@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
@@ -1,19 +1,21 @@
1
1
  import {
2
2
  indexedDBService_default,
3
3
  usePackageSettingsStore
4
- } from "./chunk-2EM4ATKI.mjs";
4
+ } from "./chunk-YH5YWK4K.mjs";
5
5
  import {
6
6
  authenticationService,
7
7
  useAIProviderStore
8
- } from "./chunk-J6LSSK3G.mjs";
8
+ } from "./chunk-GRPTCHFN.mjs";
9
9
  import {
10
10
  debugLogger
11
11
  } from "./chunk-HNXPDIWC.mjs";
12
- import {
13
- __require
14
- } from "./chunk-BJTO5JO5.mjs";
15
12
 
16
13
  // src/services/ai-provider-init.service.ts
14
+ var sessionTokenFactory = (label) => () => {
15
+ const token = authenticationService.getToken();
16
+ debugLogger.info(`AIProviderInit: ${label}`, { hasToken: !!token });
17
+ return token;
18
+ };
17
19
  var AIProviderInitService = class _AIProviderInitService {
18
20
  static instance;
19
21
  constructor() {
@@ -93,25 +95,7 @@ var AIProviderInitService = class _AIProviderInitService {
93
95
  providerConfig = {
94
96
  type: "ollama" /* OLLAMA */,
95
97
  baseUrl: settings.ollamaUrl,
96
- tokenFactory: () => {
97
- let token = authenticationService.getToken();
98
- if (!token) {
99
- token = localStorage.getItem("authToken");
100
- }
101
- if (!token) {
102
- try {
103
- const { useAuthenticationStore } = __require("../../store/authenticationStore");
104
- const authStore = useAuthenticationStore.getState();
105
- token = authStore.token;
106
- } catch (e) {
107
- }
108
- }
109
- debugLogger.info("AIProviderInit: Token factory called", {
110
- hasToken: !!token,
111
- localStorage: !!localStorage.getItem("authToken")
112
- });
113
- return token;
114
- }
98
+ tokenFactory: sessionTokenFactory("Token factory called")
115
99
  };
116
100
  debugLogger.info("Using legacy Ollama config", providerConfig);
117
101
  }
@@ -134,25 +118,7 @@ var AIProviderInitService = class _AIProviderInitService {
134
118
  const fallbackConfig = {
135
119
  type: "ollama" /* OLLAMA */,
136
120
  baseUrl: settings.ollamaUrl || "http://localhost:11434",
137
- tokenFactory: () => {
138
- let token = authenticationService.getToken();
139
- if (!token) {
140
- token = localStorage.getItem("authToken");
141
- }
142
- if (!token) {
143
- try {
144
- const { useAuthenticationStore } = __require("../../store/authenticationStore");
145
- const authStore = useAuthenticationStore.getState();
146
- token = authStore.token;
147
- } catch (e) {
148
- }
149
- }
150
- debugLogger.info("AIProviderInit: Fallback tokenFactory", {
151
- hasToken: !!token,
152
- localStorage: !!localStorage.getItem("authToken")
153
- });
154
- return token;
155
- }
121
+ tokenFactory: sessionTokenFactory("Fallback tokenFactory")
156
122
  };
157
123
  const { createProvider } = useAIProviderStore.getState();
158
124
  createProvider(fallbackConfig);
@@ -165,25 +131,7 @@ var AIProviderInitService = class _AIProviderInitService {
165
131
  const localFallbackConfig = {
166
132
  type: "ollama" /* OLLAMA */,
167
133
  baseUrl: "http://localhost:11434",
168
- tokenFactory: () => {
169
- let token = authenticationService.getToken();
170
- if (!token) {
171
- token = localStorage.getItem("authToken");
172
- }
173
- if (!token) {
174
- try {
175
- const { useAuthenticationStore } = __require("../../store/authenticationStore");
176
- const authStore = useAuthenticationStore.getState();
177
- token = authStore.token;
178
- } catch (e) {
179
- }
180
- }
181
- debugLogger.info("AIProviderInit: Local fallback tokenFactory", {
182
- hasToken: !!token,
183
- localStorage: !!localStorage.getItem("authToken")
184
- });
185
- return token;
186
- }
134
+ tokenFactory: sessionTokenFactory("Local fallback tokenFactory")
187
135
  };
188
136
  const { createProvider } = useAIProviderStore.getState();
189
137
  createProvider(localFallbackConfig);
@@ -255,27 +203,7 @@ var AIProviderInitService = class _AIProviderInitService {
255
203
  });
256
204
  return config;
257
205
  }
258
- config.tokenFactory = () => {
259
- let token = authenticationService.getToken();
260
- if (!token && typeof localStorage !== "undefined") {
261
- try {
262
- token = localStorage.getItem("authToken");
263
- } catch {
264
- }
265
- }
266
- if (!token) {
267
- try {
268
- const { useAuthenticationStore } = __require("../../store/authenticationStore");
269
- const authStore = useAuthenticationStore.getState();
270
- token = authStore.token;
271
- } catch {
272
- }
273
- }
274
- debugLogger.info("AIProviderInit: Token factory resolved auth token", {
275
- hasToken: !!token
276
- });
277
- return token;
278
- };
206
+ config.tokenFactory = sessionTokenFactory("Token factory resolved auth token");
279
207
  }
280
208
  return config;
281
209
  }
@@ -285,4 +213,4 @@ var aiProviderInitService = AIProviderInitService.getInstance();
285
213
  export {
286
214
  aiProviderInitService
287
215
  };
288
- //# sourceMappingURL=chunk-LKGBO5OP.mjs.map
216
+ //# sourceMappingURL=chunk-6KRAPGXE.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/ai-provider-init.service.ts"],"sourcesContent":["/*\n * Copyright (c) 2025 Burtson Labs LLC.\n * SPDX-License-Identifier: BUSL-1.1\n * See LICENSE for the applicable terms.\n */\n\n\nimport { useAIProviderStore } from \"../store/aiProviderStore\";\nimport { usePackageSettingsStore } from \"../store/packageSettingsStore\";\nimport { AIProviderConfig, AIProviderType } from \"./ai-provider/types/common.types\";\nimport { authenticationService } from \"./auth/authenticationService\";\nimport { debugLogger } from \"./logging/debugLogger\";\nimport indexedDBService from \"./indexedDB/indexedDBService\";\n\ntype StoredAIProviderConfig = AIProviderConfig & { id?: string };\n\n/**\n * The signed-in user's access token for provider calls. authenticationService\n * is the single source of truth: depending on the host it reads localStorage,\n * the in-memory session (HttpOnly-cookie web sessions) or the token restored\n * from native secure storage. Nothing here reads Web Storage directly — in\n * memory mode a token must never be looked for there.\n */\nconst sessionTokenFactory = (label: string) => (): string | null => {\n const token = authenticationService.getToken();\n debugLogger.info(`AIProviderInit: ${label}`, { hasToken: !!token });\n return token;\n};\n\n/**\n * Service to initialize AI providers based on package settings\n */\nexport class AIProviderInitService {\n private static instance: AIProviderInitService;\n\n private constructor() {}\n\n static getInstance(): AIProviderInitService {\n if (!AIProviderInitService.instance) {\n AIProviderInitService.instance = new AIProviderInitService();\n }\n return AIProviderInitService.instance;\n }\n\n /**\n * Initialize AI provider from package settings\n * Provides backward compatibility with existing Ollama settings\n */\n async initializeFromSettings(): Promise<void> {\n const settings = usePackageSettingsStore.getState().settings;\n if (!settings) {\n debugLogger.warn(\"No package settings found, cannot initialize AI provider\");\n return;\n }\n\n let providerConfig: AIProviderConfig;\n\n debugLogger.info(\"AI Provider Init: Starting initialization\", { \n hasSettings: !!settings,\n hasAiProvider: !!settings.aiProvider,\n ollamaUrl: settings.ollamaUrl\n });\n\n const isPlaygroundEnvironment =\n settings.playgroundMode === true ||\n settings.aiProvider?.type === AIProviderType.PLAYGROUND ||\n (settings.gatewayApiUrl?.toLowerCase()?.startsWith(\"playground://\") ?? false) ||\n (typeof window !== \"undefined\" && window.location.pathname.includes(\"/playground\"));\n\n // First, try to load provider configuration from IndexedDB\n if (isPlaygroundEnvironment) {\n debugLogger.info(\"AI Provider Init: Playground environment detected, bypassing saved provider config\");\n } else {\n try {\n const savedConfig = await indexedDBService.get<StoredAIProviderConfig>(\n 'banditConfig', \n 1, \n 'config', \n 'aiProvider',\n [{ name: 'config', keyPath: 'id' }]\n );\n \n if (savedConfig) {\n debugLogger.info('AI Provider Init: Found saved config in IndexedDB', { type: savedConfig.type });\n \n // Filter out the 'id' property that was added for IndexedDB storage\n const { id: _id, ...configWithoutId } = savedConfig;\n providerConfig = { ...configWithoutId };\n if (providerConfig.type === AIProviderType.ANTHROPIC) {\n providerConfig = this.convertAnthropicConfig(providerConfig, settings?.gatewayApiUrl);\n }\n\n // Ensure tokenFactory is present for providers that need it\n providerConfig = this.ensureTokenFactory(providerConfig);\n \n // Initialize the provider with saved config\n try {\n const { createProvider } = useAIProviderStore.getState();\n createProvider(providerConfig);\n \n const provider = useAIProviderStore.getState().provider;\n if (provider) {\n try {\n await provider.validateServiceAvailability({ timeoutMs: 5000 });\n debugLogger.info(`AI Provider initialized and validated from IndexedDB: ${providerConfig.type}`);\n } catch (validationError) {\n debugLogger.warn(`AI Provider created but validation failed`, { error: validationError });\n }\n }\n return; // Successfully initialized from IndexedDB\n } catch (error) {\n debugLogger.error(\"Failed to initialize saved provider config, falling back to package settings\", { error });\n }\n }\n \n debugLogger.info('AI Provider Init: No saved config found, using package settings');\n } catch (error) {\n debugLogger.warn('AI Provider Init: Failed to load from IndexedDB, using package settings', { error });\n }\n }\n\n // Fallback to package settings if no saved config found\n if (settings.aiProvider) {\n providerConfig = { ...settings.aiProvider };\n if (providerConfig.type === AIProviderType.ANTHROPIC) {\n providerConfig = this.convertAnthropicConfig(providerConfig, settings.gatewayApiUrl);\n }\n \n providerConfig = this.ensureTokenFactory(providerConfig);\n \n debugLogger.info(\"Using explicit AI provider config\", providerConfig);\n } else {\n // Fall back to legacy Ollama settings for backward compatibility\n providerConfig = {\n type: AIProviderType.OLLAMA,\n baseUrl: settings.ollamaUrl,\n tokenFactory: sessionTokenFactory(\"Token factory called\")\n };\n debugLogger.info(\"Using legacy Ollama config\", providerConfig);\n }\n\n try {\n // First validate if the service is available\n const { createProvider } = useAIProviderStore.getState();\n \n // Try to create and validate the provider\n createProvider(providerConfig);\n \n // Test provider availability\n const provider = useAIProviderStore.getState().provider;\n if (provider) {\n try {\n await provider.validateServiceAvailability({ timeoutMs: 5000 });\n debugLogger.info(`AI Provider initialized and validated: ${providerConfig.type}`);\n } catch (validationError) {\n debugLogger.warn(`AI Provider created but validation failed:`, { error: validationError });\n // Provider is created but may not be fully available - this is ok for offline scenarios\n }\n }\n } catch (error) {\n debugLogger.error(\"Failed to initialize AI provider:\", { error });\n \n // Try to fall back to default Ollama if initial provider fails\n if (providerConfig.type !== AIProviderType.OLLAMA) {\n try {\n const fallbackConfig: AIProviderConfig = {\n type: AIProviderType.OLLAMA,\n baseUrl: settings.ollamaUrl || 'http://localhost:11434',\n tokenFactory: sessionTokenFactory(\"Fallback tokenFactory\")\n };\n const { createProvider } = useAIProviderStore.getState();\n createProvider(fallbackConfig);\n debugLogger.info(\"Fallback to Ollama provider successful\");\n } catch (fallbackError) {\n debugLogger.error(\"Failed to initialize fallback Ollama provider:\", { error: fallbackError });\n }\n } else {\n // If Ollama provider fails, try localhost as ultimate fallback\n try {\n const localFallbackConfig: AIProviderConfig = {\n type: AIProviderType.OLLAMA,\n baseUrl: 'http://localhost:11434',\n tokenFactory: sessionTokenFactory(\"Local fallback tokenFactory\")\n };\n const { createProvider } = useAIProviderStore.getState();\n createProvider(localFallbackConfig);\n debugLogger.info(\"Fallback to localhost Ollama provider successful\");\n } catch (localFallbackError) {\n debugLogger.error(\"All provider initialization attempts failed:\", { error: localFallbackError });\n }\n }\n }\n }\n\n /**\n * Switch to a different AI provider\n */\n switchProvider(config: AIProviderConfig): void {\n try {\n const normalizedConfig = this.ensureTokenFactory({ ...config });\n const { switchProvider } = useAIProviderStore.getState();\n switchProvider(normalizedConfig);\n debugLogger.info(`Switched to AI provider: ${normalizedConfig.type}`);\n } catch (error) {\n debugLogger.error(\"Failed to switch AI provider:\", { error });\n throw error;\n }\n }\n\n /**\n * Get the current provider type\n */\n getCurrentProviderType(): string | null {\n const provider = useAIProviderStore.getState().provider;\n return provider ? provider.getProviderType() : null;\n }\n\n /**\n * Check if a provider is initialized\n */\n isProviderInitialized(): boolean {\n return useAIProviderStore.getState().provider !== null;\n }\n\n private convertAnthropicConfig(config: AIProviderConfig, gatewayUrl?: string | null): AIProviderConfig {\n if (config.type !== AIProviderType.ANTHROPIC) {\n return config;\n }\n\n const defaultModel = typeof config.defaultModel === 'string' && config.defaultModel.trim()\n ? config.defaultModel.trim()\n : 'claude-3-5-sonnet-latest';\n\n const normalized: AIProviderConfig = {\n type: AIProviderType.GATEWAY,\n gatewayUrl: gatewayUrl || config.gatewayUrl || '',\n provider: 'anthropic',\n defaultModel,\n tokenFactory: config.tokenFactory\n };\n\n debugLogger.info('AI Provider Init: Converted direct Anthropic provider to gateway configuration');\n return normalized;\n }\n\n /**\n * Ensure providers that require auth have a token factory configured.\n * Handles both UI auth tokens and API key scenarios.\n */\n private ensureTokenFactory(config: AIProviderConfig): AIProviderConfig {\n if (config.type === AIProviderType.OLLAMA || config.type === AIProviderType.GATEWAY) {\n const existingFactory = config.tokenFactory;\n if (existingFactory) {\n return config;\n }\n\n // Prefer explicit API key if provided\n if (typeof config.apiKey === 'string' && config.apiKey.trim() !== '') {\n const key = config.apiKey.trim();\n config.tokenFactory = () => key;\n debugLogger.info(\"AIProviderInit: Using API key for token factory\", {\n type: config.type,\n hasKey: true\n });\n return config;\n }\n\n // Fallback to the signed-in session (UI sessions)\n config.tokenFactory = sessionTokenFactory(\"Token factory resolved auth token\");\n }\n\n return config;\n }\n}\n\nexport const aiProviderInitService = AIProviderInitService.getInstance();\n"],"mappings":"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","names":[]}
@@ -24,23 +24,23 @@ import {
24
24
  useNotificationService,
25
25
  useTTS,
26
26
  useVoiceStore
27
- } from "./chunk-RLW4RBIR.mjs";
27
+ } from "./chunk-Q2DINRIU.mjs";
28
28
  import {
29
29
  brandingService_default,
30
30
  toTitleCase,
31
31
  useAIQueryStore,
32
32
  useConversationStore,
33
33
  useMemoryStore
34
- } from "./chunk-FEIDGXVR.mjs";
34
+ } from "./chunk-33OSALGS.mjs";
35
35
  import {
36
36
  indexedDBService_default,
37
37
  useModelStore,
38
38
  usePackageSettingsStore,
39
39
  usePreferencesStore
40
- } from "./chunk-2EM4ATKI.mjs";
40
+ } from "./chunk-YH5YWK4K.mjs";
41
41
  import {
42
42
  useAIProviderStore
43
- } from "./chunk-J6LSSK3G.mjs";
43
+ } from "./chunk-GRPTCHFN.mjs";
44
44
  import {
45
45
  debugLogger
46
46
  } from "./chunk-HNXPDIWC.mjs";
@@ -2942,4 +2942,4 @@ export {
2942
2942
  MAX_WINDOWED_HEIGHT,
2943
2943
  chat_modal_default
2944
2944
  };
2945
- //# sourceMappingURL=chunk-6VDL4SLX.mjs.map
2945
+ //# sourceMappingURL=chunk-75OBTJPN.mjs.map
@@ -3,10 +3,10 @@ import {
3
3
  } from "./chunk-ONQMRE2G.mjs";
4
4
  import {
5
5
  aiProviderInitService
6
- } from "./chunk-LKGBO5OP.mjs";
6
+ } from "./chunk-6KRAPGXE.mjs";
7
7
  import {
8
8
  useMCPToolsStore
9
- } from "./chunk-NGGTQVGX.mjs";
9
+ } from "./chunk-MM3NRLVR.mjs";
10
10
  import {
11
11
  FeatureFlagProvider,
12
12
  NotificationProvider,
@@ -19,17 +19,17 @@ import {
19
19
  useKnowledgeStore2,
20
20
  useMemoryStore,
21
21
  useProjectStore
22
- } from "./chunk-FEIDGXVR.mjs";
22
+ } from "./chunk-33OSALGS.mjs";
23
23
  import {
24
24
  indexedDBService_default,
25
25
  useModelStore,
26
26
  usePackageSettingsStore,
27
27
  usePreferencesStore
28
- } from "./chunk-2EM4ATKI.mjs";
28
+ } from "./chunk-YH5YWK4K.mjs";
29
29
  import {
30
30
  AUTH_TOKEN_CHANGED_EVENT,
31
31
  authenticationService
32
- } from "./chunk-J6LSSK3G.mjs";
32
+ } from "./chunk-GRPTCHFN.mjs";
33
33
  import {
34
34
  debugLogger
35
35
  } from "./chunk-HNXPDIWC.mjs";
@@ -191,4 +191,4 @@ export {
191
191
  ChatProvider,
192
192
  chat_provider_default
193
193
  };
194
- //# sourceMappingURL=chunk-QHGGV4KJ.mjs.map
194
+ //# sourceMappingURL=chunk-A6W6XIDD.mjs.map
@@ -1060,25 +1060,36 @@ import { catchError as catchError2, from as from5, lastValueFrom as lastValueFro
1060
1060
  // src/store/authenticationStore.ts
1061
1061
  import { create } from "zustand";
1062
1062
  var TOKEN_KEY = "authToken";
1063
- var validToken = null;
1064
- var user = null;
1065
- var rawToken = localStorage.getItem(TOKEN_KEY);
1066
- if (rawToken) {
1063
+ var decodeClaims = (token) => {
1067
1064
  try {
1068
- const base64Url = rawToken.split(".")[1];
1065
+ const base64Url = token.split(".")[1];
1069
1066
  const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
1070
1067
  const jsonPayload = decodeURIComponent(
1071
1068
  atob(base64).split("").map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join("")
1072
1069
  );
1073
- const decoded = JSON.parse(jsonPayload);
1074
- if (decoded.exp * 1e3 > Date.now()) {
1075
- validToken = rawToken;
1076
- user = decoded;
1077
- }
1070
+ return JSON.parse(jsonPayload);
1078
1071
  } catch {
1079
- validToken = null;
1080
- user = null;
1072
+ return null;
1081
1073
  }
1074
+ };
1075
+ var validOrNull = (raw) => {
1076
+ if (!raw) return null;
1077
+ const decoded = decodeClaims(raw);
1078
+ return decoded && decoded.exp * 1e3 > Date.now() ? raw : null;
1079
+ };
1080
+ var readLegacyStorage = () => {
1081
+ try {
1082
+ return typeof localStorage === "undefined" ? null : localStorage.getItem(TOKEN_KEY);
1083
+ } catch {
1084
+ return null;
1085
+ }
1086
+ };
1087
+ var validToken = null;
1088
+ var user = null;
1089
+ var rawToken = readLegacyStorage();
1090
+ if (rawToken) {
1091
+ validToken = validOrNull(rawToken);
1092
+ user = validToken ? decodeClaims(validToken) : null;
1082
1093
  }
1083
1094
  var useAuthenticationStore = create((set) => ({
1084
1095
  token: validToken,
@@ -1086,16 +1097,10 @@ var useAuthenticationStore = create((set) => ({
1086
1097
  authError: null,
1087
1098
  setToken: (token) => {
1088
1099
  if (token) {
1089
- try {
1090
- const base64Url = token.split(".")[1];
1091
- const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
1092
- const jsonPayload = decodeURIComponent(
1093
- atob(base64).split("").map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join("")
1094
- );
1095
- const user2 = JSON.parse(jsonPayload);
1096
- localStorage.setItem(TOKEN_KEY, token);
1097
- set({ token, authError: null, user: user2 });
1098
- } catch {
1100
+ const decoded = decodeClaims(token);
1101
+ if (decoded) {
1102
+ set({ token, authError: null, user: decoded });
1103
+ } else {
1099
1104
  set({ token: null, authError: "Invalid token", user: null });
1100
1105
  }
1101
1106
  } else {
@@ -1103,23 +1108,11 @@ var useAuthenticationStore = create((set) => ({
1103
1108
  }
1104
1109
  },
1105
1110
  clearToken: () => {
1106
- localStorage.removeItem(TOKEN_KEY);
1107
1111
  set({ token: null, authError: null, user: null });
1108
1112
  }
1109
1113
  }));
1110
1114
  var readPersistedToken = () => {
1111
- try {
1112
- const raw = localStorage.getItem(TOKEN_KEY);
1113
- if (!raw) return null;
1114
- const base64 = raw.split(".")[1].replace(/-/g, "+").replace(/_/g, "/");
1115
- const json = decodeURIComponent(
1116
- atob(base64).split("").map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join("")
1117
- );
1118
- const decoded = JSON.parse(json);
1119
- return decoded.exp * 1e3 > Date.now() ? raw : null;
1120
- } catch {
1121
- return null;
1122
- }
1115
+ return validOrNull(readLegacyStorage()) ?? validOrNull(useAuthenticationStore.getState().token);
1123
1116
  };
1124
1117
 
1125
1118
  // src/services/auth/authenticationService.ts
@@ -1133,21 +1126,103 @@ function emitAuthTokenChanged(token) {
1133
1126
  detail: { token }
1134
1127
  }));
1135
1128
  }
1129
+ var readLocalStorage = () => {
1130
+ try {
1131
+ return typeof localStorage === "undefined" ? null : localStorage.getItem(TOKEN_KEY2);
1132
+ } catch {
1133
+ return null;
1134
+ }
1135
+ };
1136
+ var writeLocalStorage = (token) => {
1137
+ try {
1138
+ if (typeof localStorage === "undefined") return;
1139
+ if (token) localStorage.setItem(TOKEN_KEY2, token);
1140
+ else localStorage.removeItem(TOKEN_KEY2);
1141
+ } catch {
1142
+ }
1143
+ };
1136
1144
  var AuthenticationService = class {
1145
+ storageMode = "localStorage";
1146
+ persistence = null;
1147
+ handlers = {};
1148
+ /** Bumped on every setToken/clearToken; async flows compare it to detect a superseded session. */
1149
+ revision = 0;
1150
+ refreshInFlight = null;
1151
+ lastPersist = Promise.resolve();
1152
+ /**
1153
+ * Pick the storage contract for this host. Call once at boot, before the
1154
+ * first `setToken`. Switching modes never moves a token by itself: the
1155
+ * host migrates (e.g. reads the legacy localStorage value, then clears it).
1156
+ */
1157
+ configureSession(config) {
1158
+ this.storageMode = config.storage;
1159
+ this.persistence = config.persistence ?? null;
1160
+ this.handlers = config.handlers ?? {};
1161
+ }
1162
+ getStorageMode() {
1163
+ return this.storageMode;
1164
+ }
1165
+ getSessionRevision() {
1166
+ return this.revision;
1167
+ }
1137
1168
  getToken() {
1138
- const token = localStorage.getItem(TOKEN_KEY2);
1139
- return token;
1169
+ if (this.storageMode === "memory") {
1170
+ return useAuthenticationStore.getState().token;
1171
+ }
1172
+ return readLocalStorage();
1140
1173
  }
1141
1174
  setToken(token) {
1142
- localStorage.setItem(TOKEN_KEY2, token);
1175
+ this.revision += 1;
1176
+ if (this.storageMode === "localStorage") {
1177
+ writeLocalStorage(token);
1178
+ } else {
1179
+ writeLocalStorage(null);
1180
+ }
1143
1181
  useAuthenticationStore.getState().setToken(token);
1182
+ this.mirror(() => this.persistence?.write(token));
1144
1183
  emitAuthTokenChanged(token);
1145
1184
  }
1146
1185
  clearToken() {
1147
- localStorage.removeItem(TOKEN_KEY2);
1186
+ this.revision += 1;
1187
+ const current = this.getToken() ?? useAuthenticationStore.getState().token;
1188
+ try {
1189
+ this.handlers.beforeClear?.(current);
1190
+ } catch (error) {
1191
+ debugLogger.warn("Auth beforeClear handler failed", { error });
1192
+ }
1193
+ writeLocalStorage(null);
1148
1194
  useAuthenticationStore.getState().clearToken();
1195
+ this.mirror(() => this.persistence?.clear());
1149
1196
  emitAuthTokenChanged(null);
1150
1197
  }
1198
+ /** True when the host registered a silent refresh path. */
1199
+ canRefresh() {
1200
+ return typeof this.handlers.refresh === "function";
1201
+ }
1202
+ /**
1203
+ * Ask the host for a fresh token. Concurrent callers share one attempt.
1204
+ * Resolves false when no refresh path exists or it did not produce a token.
1205
+ */
1206
+ tryRefresh() {
1207
+ const refresh = this.handlers.refresh;
1208
+ if (!refresh) return Promise.resolve(false);
1209
+ if (this.refreshInFlight) return this.refreshInFlight;
1210
+ this.refreshInFlight = (async () => {
1211
+ try {
1212
+ return await refresh();
1213
+ } catch (error) {
1214
+ debugLogger.warn("Auth refresh handler failed", { error });
1215
+ return false;
1216
+ } finally {
1217
+ this.refreshInFlight = null;
1218
+ }
1219
+ })();
1220
+ return this.refreshInFlight;
1221
+ }
1222
+ /** Resolves once the most recent persistence write/clear has settled. */
1223
+ whenPersisted() {
1224
+ return this.lastPersist;
1225
+ }
1151
1226
  isAuthenticated() {
1152
1227
  const token = useAuthenticationStore.getState().token;
1153
1228
  return !!token && !this.isTokenExpired(token);
@@ -1177,6 +1252,16 @@ var AuthenticationService = class {
1177
1252
  return null;
1178
1253
  }
1179
1254
  }
1255
+ mirror(run) {
1256
+ const attempt = (async () => {
1257
+ try {
1258
+ await run();
1259
+ } catch (error) {
1260
+ debugLogger.warn("Auth token persistence failed", { error });
1261
+ }
1262
+ })();
1263
+ this.lastPersist = attempt;
1264
+ }
1180
1265
  };
1181
1266
  var authenticationService = new AuthenticationService();
1182
1267
 
@@ -1221,13 +1306,35 @@ var GatewayService = class {
1221
1306
  });
1222
1307
  instance.interceptors.response.use(
1223
1308
  (response) => response,
1224
- (error) => {
1309
+ async (error) => {
1310
+ const retried = await this._retryAfterRefresh(instance, error);
1311
+ if (retried) return retried;
1225
1312
  this._handleAuthFailure(error);
1226
1313
  return Promise.reject(this._normalizeAxiosError(error));
1227
1314
  }
1228
1315
  );
1229
1316
  return instance;
1230
1317
  }
1318
+ /**
1319
+ * A bare 401 on a host with a silent refresh path (HttpOnly refresh cookie,
1320
+ * native device token) usually means the access token aged out mid-session.
1321
+ * Refresh once and replay the request with the new token instead of
1322
+ * signing the user out; a failed refresh falls through to the sign-out path.
1323
+ */
1324
+ async _retryAfterRefresh(instance, error) {
1325
+ const config = error.config;
1326
+ if (!config || config._banditAuthRetried || error.response?.status !== 401) return null;
1327
+ if (!authenticationService.canRefresh()) return null;
1328
+ const data = error.response?.data;
1329
+ if (data?.code && data.code !== "TOKEN_EXPIRED") return null;
1330
+ try {
1331
+ if (!await authenticationService.tryRefresh()) return null;
1332
+ } catch {
1333
+ return null;
1334
+ }
1335
+ config._banditAuthRetried = true;
1336
+ return instance.request(config);
1337
+ }
1231
1338
  _normalizeAxiosError(error) {
1232
1339
  if (error.response) {
1233
1340
  return this._createHttpError(
@@ -3148,10 +3255,11 @@ var useAIProviderStore = create2((set, get) => ({
3148
3255
  export {
3149
3256
  useAuthenticationStore,
3150
3257
  readPersistedToken,
3258
+ TOKEN_KEY2 as TOKEN_KEY,
3151
3259
  AUTH_TOKEN_CHANGED_EVENT,
3152
3260
  authenticationService,
3153
3261
  GatewayService,
3154
3262
  AIProviderFactory,
3155
3263
  useAIProviderStore
3156
3264
  };
3157
- //# sourceMappingURL=chunk-J6LSSK3G.mjs.map
3265
+ //# sourceMappingURL=chunk-GRPTCHFN.mjs.map