@burtson-labs/bandit-engine 2.0.165 → 2.0.166

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.
Files changed (56) hide show
  1. package/README.md +4 -1
  2. package/dist/aiProviderStore-HY5G4QAK.mjs +8 -0
  3. package/dist/chat-RCMZYACB.mjs +15 -0
  4. package/dist/chat-provider.js +175 -109
  5. package/dist/chat-provider.js.map +1 -1
  6. package/dist/chat-provider.mjs +6 -7
  7. package/dist/{chunk-FEIDGXVR.mjs → chunk-33OSALGS.mjs} +24 -6
  8. package/dist/{chunk-FEIDGXVR.mjs.map → chunk-33OSALGS.mjs.map} +1 -1
  9. package/dist/{chunk-LKGBO5OP.mjs → chunk-6KRAPGXE.mjs} +12 -84
  10. package/dist/chunk-6KRAPGXE.mjs.map +1 -0
  11. package/dist/{chunk-6VDL4SLX.mjs → chunk-75OBTJPN.mjs} +5 -5
  12. package/dist/{chunk-QHGGV4KJ.mjs → chunk-A6W6XIDD.mjs} +6 -6
  13. package/dist/{chunk-J6LSSK3G.mjs → chunk-GRPTCHFN.mjs} +149 -41
  14. package/dist/chunk-GRPTCHFN.mjs.map +1 -0
  15. package/dist/{chunk-ASWUEAWM.mjs → chunk-IB2LPSQQ.mjs} +2 -2
  16. package/dist/{chunk-RNCASZ2Y.mjs → chunk-M4DWPNZZ.mjs} +10 -10
  17. package/dist/{chunk-NGGTQVGX.mjs → chunk-MM3NRLVR.mjs} +3 -3
  18. package/dist/{chunk-RLW4RBIR.mjs → chunk-Q2DINRIU.mjs} +4 -4
  19. package/dist/{chunk-WSUUW7T2.mjs → chunk-WSZE3DDJ.mjs} +7 -7
  20. package/dist/{chunk-2EM4ATKI.mjs → chunk-YH5YWK4K.mjs} +2 -2
  21. package/dist/index.d.mts +92 -1
  22. package/dist/index.d.ts +92 -1
  23. package/dist/index.js +188 -130
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.mjs +21 -20
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/management/management.js +159 -120
  28. package/dist/management/management.js.map +1 -1
  29. package/dist/management/management.mjs +9 -10
  30. package/dist/{memoryUtils-2FVXDSS6.mjs → memoryUtils-HGCYEUCD.mjs} +1 -3
  31. package/dist/{memoryUtils-2FVXDSS6.mjs.map → memoryUtils-HGCYEUCD.mjs.map} +1 -1
  32. package/dist/modals/chat-modal/chat-modal.js +149 -30
  33. package/dist/modals/chat-modal/chat-modal.js.map +1 -1
  34. package/dist/modals/chat-modal/chat-modal.mjs +5 -6
  35. package/dist/modelStore-F6JQUXGG.mjs +8 -0
  36. package/dist/shared/custom-element.mjs +0 -1
  37. package/docs/03_provider_integration.md +5 -2
  38. package/package.json +1 -1
  39. package/dist/aiProviderStore-M4BVEKUB.mjs +0 -9
  40. package/dist/chat-EMKHB23B.mjs +0 -16
  41. package/dist/chunk-BJTO5JO5.mjs +0 -11
  42. package/dist/chunk-J6LSSK3G.mjs.map +0 -1
  43. package/dist/chunk-LKGBO5OP.mjs.map +0 -1
  44. package/dist/modelStore-7YYELPF6.mjs +0 -9
  45. package/dist/modelStore-7YYELPF6.mjs.map +0 -1
  46. /package/dist/{aiProviderStore-M4BVEKUB.mjs.map → aiProviderStore-HY5G4QAK.mjs.map} +0 -0
  47. /package/dist/{chat-EMKHB23B.mjs.map → chat-RCMZYACB.mjs.map} +0 -0
  48. /package/dist/{chunk-6VDL4SLX.mjs.map → chunk-75OBTJPN.mjs.map} +0 -0
  49. /package/dist/{chunk-QHGGV4KJ.mjs.map → chunk-A6W6XIDD.mjs.map} +0 -0
  50. /package/dist/{chunk-ASWUEAWM.mjs.map → chunk-IB2LPSQQ.mjs.map} +0 -0
  51. /package/dist/{chunk-RNCASZ2Y.mjs.map → chunk-M4DWPNZZ.mjs.map} +0 -0
  52. /package/dist/{chunk-NGGTQVGX.mjs.map → chunk-MM3NRLVR.mjs.map} +0 -0
  53. /package/dist/{chunk-RLW4RBIR.mjs.map → chunk-Q2DINRIU.mjs.map} +0 -0
  54. /package/dist/{chunk-WSUUW7T2.mjs.map → chunk-WSZE3DDJ.mjs.map} +0 -0
  55. /package/dist/{chunk-2EM4ATKI.mjs.map → chunk-YH5YWK4K.mjs.map} +0 -0
  56. /package/dist/{chunk-BJTO5JO5.mjs.map → modelStore-F6JQUXGG.mjs.map} +0 -0
@@ -1556,31 +1556,42 @@ var init_anthropic_provider = __esm({
1556
1556
  });
1557
1557
 
1558
1558
  // src/store/authenticationStore.ts
1559
- var import_zustand2, TOKEN_KEY, validToken, user, rawToken, useAuthenticationStore, readPersistedToken;
1559
+ var import_zustand2, TOKEN_KEY, decodeClaims, validOrNull, readLegacyStorage, validToken, user, rawToken, useAuthenticationStore, readPersistedToken;
1560
1560
  var init_authenticationStore = __esm({
1561
1561
  "src/store/authenticationStore.ts"() {
1562
1562
  "use strict";
1563
1563
  import_zustand2 = require("zustand");
1564
1564
  TOKEN_KEY = "authToken";
1565
- validToken = null;
1566
- user = null;
1567
- rawToken = localStorage.getItem(TOKEN_KEY);
1568
- if (rawToken) {
1565
+ decodeClaims = (token) => {
1569
1566
  try {
1570
- const base64Url = rawToken.split(".")[1];
1567
+ const base64Url = token.split(".")[1];
1571
1568
  const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
1572
1569
  const jsonPayload = decodeURIComponent(
1573
1570
  atob(base64).split("").map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join("")
1574
1571
  );
1575
- const decoded = JSON.parse(jsonPayload);
1576
- if (decoded.exp * 1e3 > Date.now()) {
1577
- validToken = rawToken;
1578
- user = decoded;
1579
- }
1572
+ return JSON.parse(jsonPayload);
1580
1573
  } catch {
1581
- validToken = null;
1582
- user = null;
1574
+ return null;
1583
1575
  }
1576
+ };
1577
+ validOrNull = (raw) => {
1578
+ if (!raw) return null;
1579
+ const decoded = decodeClaims(raw);
1580
+ return decoded && decoded.exp * 1e3 > Date.now() ? raw : null;
1581
+ };
1582
+ readLegacyStorage = () => {
1583
+ try {
1584
+ return typeof localStorage === "undefined" ? null : localStorage.getItem(TOKEN_KEY);
1585
+ } catch {
1586
+ return null;
1587
+ }
1588
+ };
1589
+ validToken = null;
1590
+ user = null;
1591
+ rawToken = readLegacyStorage();
1592
+ if (rawToken) {
1593
+ validToken = validOrNull(rawToken);
1594
+ user = validToken ? decodeClaims(validToken) : null;
1584
1595
  }
1585
1596
  useAuthenticationStore = (0, import_zustand2.create)((set) => ({
1586
1597
  token: validToken,
@@ -1588,16 +1599,10 @@ var init_authenticationStore = __esm({
1588
1599
  authError: null,
1589
1600
  setToken: (token) => {
1590
1601
  if (token) {
1591
- try {
1592
- const base64Url = token.split(".")[1];
1593
- const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
1594
- const jsonPayload = decodeURIComponent(
1595
- atob(base64).split("").map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join("")
1596
- );
1597
- const user2 = JSON.parse(jsonPayload);
1598
- localStorage.setItem(TOKEN_KEY, token);
1599
- set({ token, authError: null, user: user2 });
1600
- } catch {
1602
+ const decoded = decodeClaims(token);
1603
+ if (decoded) {
1604
+ set({ token, authError: null, user: decoded });
1605
+ } else {
1601
1606
  set({ token: null, authError: "Invalid token", user: null });
1602
1607
  }
1603
1608
  } else {
@@ -1605,23 +1610,11 @@ var init_authenticationStore = __esm({
1605
1610
  }
1606
1611
  },
1607
1612
  clearToken: () => {
1608
- localStorage.removeItem(TOKEN_KEY);
1609
1613
  set({ token: null, authError: null, user: null });
1610
1614
  }
1611
1615
  }));
1612
1616
  readPersistedToken = () => {
1613
- try {
1614
- const raw = localStorage.getItem(TOKEN_KEY);
1615
- if (!raw) return null;
1616
- const base64 = raw.split(".")[1].replace(/-/g, "+").replace(/_/g, "/");
1617
- const json2 = decodeURIComponent(
1618
- atob(base64).split("").map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join("")
1619
- );
1620
- const decoded = JSON.parse(json2);
1621
- return decoded.exp * 1e3 > Date.now() ? raw : null;
1622
- } catch {
1623
- return null;
1624
- }
1617
+ return validOrNull(readLegacyStorage()) ?? validOrNull(useAuthenticationStore.getState().token);
1625
1618
  };
1626
1619
  }
1627
1620
  });
@@ -1635,7 +1628,7 @@ function emitAuthTokenChanged(token) {
1635
1628
  detail: { token }
1636
1629
  }));
1637
1630
  }
1638
- var TOKEN_KEY2, AUTH_TOKEN_CHANGED_EVENT, AuthenticationService, authenticationService;
1631
+ var TOKEN_KEY2, AUTH_TOKEN_CHANGED_EVENT, readLocalStorage, writeLocalStorage, AuthenticationService, authenticationService;
1639
1632
  var init_authenticationService = __esm({
1640
1633
  "src/services/auth/authenticationService.ts"() {
1641
1634
  "use strict";
@@ -1643,21 +1636,103 @@ var init_authenticationService = __esm({
1643
1636
  init_debugLogger();
1644
1637
  TOKEN_KEY2 = "authToken";
1645
1638
  AUTH_TOKEN_CHANGED_EVENT = "bandit:auth-token-changed";
1639
+ readLocalStorage = () => {
1640
+ try {
1641
+ return typeof localStorage === "undefined" ? null : localStorage.getItem(TOKEN_KEY2);
1642
+ } catch {
1643
+ return null;
1644
+ }
1645
+ };
1646
+ writeLocalStorage = (token) => {
1647
+ try {
1648
+ if (typeof localStorage === "undefined") return;
1649
+ if (token) localStorage.setItem(TOKEN_KEY2, token);
1650
+ else localStorage.removeItem(TOKEN_KEY2);
1651
+ } catch {
1652
+ }
1653
+ };
1646
1654
  AuthenticationService = class {
1655
+ storageMode = "localStorage";
1656
+ persistence = null;
1657
+ handlers = {};
1658
+ /** Bumped on every setToken/clearToken; async flows compare it to detect a superseded session. */
1659
+ revision = 0;
1660
+ refreshInFlight = null;
1661
+ lastPersist = Promise.resolve();
1662
+ /**
1663
+ * Pick the storage contract for this host. Call once at boot, before the
1664
+ * first `setToken`. Switching modes never moves a token by itself: the
1665
+ * host migrates (e.g. reads the legacy localStorage value, then clears it).
1666
+ */
1667
+ configureSession(config) {
1668
+ this.storageMode = config.storage;
1669
+ this.persistence = config.persistence ?? null;
1670
+ this.handlers = config.handlers ?? {};
1671
+ }
1672
+ getStorageMode() {
1673
+ return this.storageMode;
1674
+ }
1675
+ getSessionRevision() {
1676
+ return this.revision;
1677
+ }
1647
1678
  getToken() {
1648
- const token = localStorage.getItem(TOKEN_KEY2);
1649
- return token;
1679
+ if (this.storageMode === "memory") {
1680
+ return useAuthenticationStore.getState().token;
1681
+ }
1682
+ return readLocalStorage();
1650
1683
  }
1651
1684
  setToken(token) {
1652
- localStorage.setItem(TOKEN_KEY2, token);
1685
+ this.revision += 1;
1686
+ if (this.storageMode === "localStorage") {
1687
+ writeLocalStorage(token);
1688
+ } else {
1689
+ writeLocalStorage(null);
1690
+ }
1653
1691
  useAuthenticationStore.getState().setToken(token);
1692
+ this.mirror(() => this.persistence?.write(token));
1654
1693
  emitAuthTokenChanged(token);
1655
1694
  }
1656
1695
  clearToken() {
1657
- localStorage.removeItem(TOKEN_KEY2);
1696
+ this.revision += 1;
1697
+ const current = this.getToken() ?? useAuthenticationStore.getState().token;
1698
+ try {
1699
+ this.handlers.beforeClear?.(current);
1700
+ } catch (error) {
1701
+ debugLogger.warn("Auth beforeClear handler failed", { error });
1702
+ }
1703
+ writeLocalStorage(null);
1658
1704
  useAuthenticationStore.getState().clearToken();
1705
+ this.mirror(() => this.persistence?.clear());
1659
1706
  emitAuthTokenChanged(null);
1660
1707
  }
1708
+ /** True when the host registered a silent refresh path. */
1709
+ canRefresh() {
1710
+ return typeof this.handlers.refresh === "function";
1711
+ }
1712
+ /**
1713
+ * Ask the host for a fresh token. Concurrent callers share one attempt.
1714
+ * Resolves false when no refresh path exists or it did not produce a token.
1715
+ */
1716
+ tryRefresh() {
1717
+ const refresh = this.handlers.refresh;
1718
+ if (!refresh) return Promise.resolve(false);
1719
+ if (this.refreshInFlight) return this.refreshInFlight;
1720
+ this.refreshInFlight = (async () => {
1721
+ try {
1722
+ return await refresh();
1723
+ } catch (error) {
1724
+ debugLogger.warn("Auth refresh handler failed", { error });
1725
+ return false;
1726
+ } finally {
1727
+ this.refreshInFlight = null;
1728
+ }
1729
+ })();
1730
+ return this.refreshInFlight;
1731
+ }
1732
+ /** Resolves once the most recent persistence write/clear has settled. */
1733
+ whenPersisted() {
1734
+ return this.lastPersist;
1735
+ }
1661
1736
  isAuthenticated() {
1662
1737
  const token = useAuthenticationStore.getState().token;
1663
1738
  return !!token && !this.isTokenExpired(token);
@@ -1687,6 +1762,16 @@ var init_authenticationService = __esm({
1687
1762
  return null;
1688
1763
  }
1689
1764
  }
1765
+ mirror(run) {
1766
+ const attempt = (async () => {
1767
+ try {
1768
+ await run();
1769
+ } catch (error) {
1770
+ debugLogger.warn("Auth token persistence failed", { error });
1771
+ }
1772
+ })();
1773
+ this.lastPersist = attempt;
1774
+ }
1690
1775
  };
1691
1776
  authenticationService = new AuthenticationService();
1692
1777
  }
@@ -1742,13 +1827,35 @@ var init_gateway_service = __esm({
1742
1827
  });
1743
1828
  instance.interceptors.response.use(
1744
1829
  (response) => response,
1745
- (error) => {
1830
+ async (error) => {
1831
+ const retried = await this._retryAfterRefresh(instance, error);
1832
+ if (retried) return retried;
1746
1833
  this._handleAuthFailure(error);
1747
1834
  return Promise.reject(this._normalizeAxiosError(error));
1748
1835
  }
1749
1836
  );
1750
1837
  return instance;
1751
1838
  }
1839
+ /**
1840
+ * A bare 401 on a host with a silent refresh path (HttpOnly refresh cookie,
1841
+ * native device token) usually means the access token aged out mid-session.
1842
+ * Refresh once and replay the request with the new token instead of
1843
+ * signing the user out; a failed refresh falls through to the sign-out path.
1844
+ */
1845
+ async _retryAfterRefresh(instance, error) {
1846
+ const config = error.config;
1847
+ if (!config || config._banditAuthRetried || error.response?.status !== 401) return null;
1848
+ if (!authenticationService.canRefresh()) return null;
1849
+ const data = error.response?.data;
1850
+ if (data?.code && data.code !== "TOKEN_EXPIRED") return null;
1851
+ try {
1852
+ if (!await authenticationService.tryRefresh()) return null;
1853
+ } catch {
1854
+ return null;
1855
+ }
1856
+ config._banditAuthRetried = true;
1857
+ return instance.request(config);
1858
+ }
1752
1859
  _normalizeAxiosError(error) {
1753
1860
  if (error.response) {
1754
1861
  return this._createHttpError(
@@ -6437,6 +6544,7 @@ var init_FeatureFlagContext = __esm({
6437
6544
  import_react = require("react");
6438
6545
  init_featureFlags();
6439
6546
  init_debugLogger();
6547
+ init_authenticationService();
6440
6548
  import_jsx_runtime = require("react/jsx-runtime");
6441
6549
  FeatureFlagContext = (0, import_react.createContext)(void 0);
6442
6550
  useFeatureFlag = () => {
@@ -40941,6 +41049,11 @@ init_common_types();
40941
41049
  init_authenticationService();
40942
41050
  init_debugLogger();
40943
41051
  init_indexedDBService();
41052
+ var sessionTokenFactory = (label) => () => {
41053
+ const token = authenticationService.getToken();
41054
+ debugLogger.info(`AIProviderInit: ${label}`, { hasToken: !!token });
41055
+ return token;
41056
+ };
40944
41057
  var AIProviderInitService = class _AIProviderInitService {
40945
41058
  static instance;
40946
41059
  constructor() {
@@ -41020,25 +41133,7 @@ var AIProviderInitService = class _AIProviderInitService {
41020
41133
  providerConfig = {
41021
41134
  type: "ollama" /* OLLAMA */,
41022
41135
  baseUrl: settings.ollamaUrl,
41023
- tokenFactory: () => {
41024
- let token = authenticationService.getToken();
41025
- if (!token) {
41026
- token = localStorage.getItem("authToken");
41027
- }
41028
- if (!token) {
41029
- try {
41030
- const { useAuthenticationStore: useAuthenticationStore2 } = require("../../store/authenticationStore");
41031
- const authStore = useAuthenticationStore2.getState();
41032
- token = authStore.token;
41033
- } catch (e) {
41034
- }
41035
- }
41036
- debugLogger.info("AIProviderInit: Token factory called", {
41037
- hasToken: !!token,
41038
- localStorage: !!localStorage.getItem("authToken")
41039
- });
41040
- return token;
41041
- }
41136
+ tokenFactory: sessionTokenFactory("Token factory called")
41042
41137
  };
41043
41138
  debugLogger.info("Using legacy Ollama config", providerConfig);
41044
41139
  }
@@ -41061,25 +41156,7 @@ var AIProviderInitService = class _AIProviderInitService {
41061
41156
  const fallbackConfig = {
41062
41157
  type: "ollama" /* OLLAMA */,
41063
41158
  baseUrl: settings.ollamaUrl || "http://localhost:11434",
41064
- tokenFactory: () => {
41065
- let token = authenticationService.getToken();
41066
- if (!token) {
41067
- token = localStorage.getItem("authToken");
41068
- }
41069
- if (!token) {
41070
- try {
41071
- const { useAuthenticationStore: useAuthenticationStore2 } = require("../../store/authenticationStore");
41072
- const authStore = useAuthenticationStore2.getState();
41073
- token = authStore.token;
41074
- } catch (e) {
41075
- }
41076
- }
41077
- debugLogger.info("AIProviderInit: Fallback tokenFactory", {
41078
- hasToken: !!token,
41079
- localStorage: !!localStorage.getItem("authToken")
41080
- });
41081
- return token;
41082
- }
41159
+ tokenFactory: sessionTokenFactory("Fallback tokenFactory")
41083
41160
  };
41084
41161
  const { createProvider } = useAIProviderStore.getState();
41085
41162
  createProvider(fallbackConfig);
@@ -41092,25 +41169,7 @@ var AIProviderInitService = class _AIProviderInitService {
41092
41169
  const localFallbackConfig = {
41093
41170
  type: "ollama" /* OLLAMA */,
41094
41171
  baseUrl: "http://localhost:11434",
41095
- tokenFactory: () => {
41096
- let token = authenticationService.getToken();
41097
- if (!token) {
41098
- token = localStorage.getItem("authToken");
41099
- }
41100
- if (!token) {
41101
- try {
41102
- const { useAuthenticationStore: useAuthenticationStore2 } = require("../../store/authenticationStore");
41103
- const authStore = useAuthenticationStore2.getState();
41104
- token = authStore.token;
41105
- } catch (e) {
41106
- }
41107
- }
41108
- debugLogger.info("AIProviderInit: Local fallback tokenFactory", {
41109
- hasToken: !!token,
41110
- localStorage: !!localStorage.getItem("authToken")
41111
- });
41112
- return token;
41113
- }
41172
+ tokenFactory: sessionTokenFactory("Local fallback tokenFactory")
41114
41173
  };
41115
41174
  const { createProvider } = useAIProviderStore.getState();
41116
41175
  createProvider(localFallbackConfig);
@@ -41182,27 +41241,7 @@ var AIProviderInitService = class _AIProviderInitService {
41182
41241
  });
41183
41242
  return config;
41184
41243
  }
41185
- config.tokenFactory = () => {
41186
- let token = authenticationService.getToken();
41187
- if (!token && typeof localStorage !== "undefined") {
41188
- try {
41189
- token = localStorage.getItem("authToken");
41190
- } catch {
41191
- }
41192
- }
41193
- if (!token) {
41194
- try {
41195
- const { useAuthenticationStore: useAuthenticationStore2 } = require("../../store/authenticationStore");
41196
- const authStore = useAuthenticationStore2.getState();
41197
- token = authStore.token;
41198
- } catch {
41199
- }
41200
- }
41201
- debugLogger.info("AIProviderInit: Token factory resolved auth token", {
41202
- hasToken: !!token
41203
- });
41204
- return token;
41205
- };
41244
+ config.tokenFactory = sessionTokenFactory("Token factory resolved auth token");
41206
41245
  }
41207
41246
  return config;
41208
41247
  }