@lastbrain/ai-ui-react 1.0.63 → 1.0.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.
@@ -4,7 +4,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
4
4
  * Provider d'authentification LastBrain
5
5
  * Gère l'état de connexion, la session et les appels IA
6
6
  */
7
- import { createContext, useContext, useEffect, useCallback, useState, } from "react";
7
+ import { createContext, useContext, useEffect, useCallback, useMemo, useState, } from "react";
8
+ import { createLBClient } from "@lastbrain/ai-ui-core";
8
9
  const LBContext = createContext(undefined);
9
10
  export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", proxyUrl = "/api/lastbrain", onStatusChange, onAuthChange, }) {
10
11
  const [state, setState] = useState({
@@ -18,61 +19,70 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
18
19
  const [isLoadingStatus, setIsLoadingStatus] = useState(false);
19
20
  const [isLoadingStorage, setIsLoadingStorage] = useState(false);
20
21
  const [storageLastFetch, setStorageLastFetch] = useState(0);
22
+ const lbClient = useMemo(() => createLBClient({
23
+ baseUrl: proxyUrl,
24
+ mode: process.env.LB_API_KEY ? "env-key" : "auto",
25
+ selectedApiKeyId: state.selectedKey?.id,
26
+ }), [proxyUrl, state.selectedKey?.id]);
21
27
  /**
22
28
  * Vérifie si une session existe au chargement
23
29
  */
24
30
  const checkSession = useCallback(async () => {
25
31
  try {
26
- const response = await fetch(`${proxyUrl}/auth/session/verify`, {
27
- credentials: "include",
28
- });
29
- if (response.ok) {
30
- const session = await response.json();
31
- // Récupérer les infos utilisateur depuis /auth/status
32
- try {
33
- const statusResponse = await fetch(`${proxyUrl}/auth/status`, {
34
- credentials: "include",
35
- });
36
- if (statusResponse.ok) {
37
- const statusData = await statusResponse.json();
38
- setState({
39
- status: "ready",
40
- session,
41
- user: {
42
- id: session.userId,
43
- email: statusData.user?.email || "",
44
- },
45
- });
46
- }
47
- else {
48
- // Fallback sans email
49
- setState({
50
- status: "ready",
51
- session,
52
- user: {
53
- id: session.userId,
54
- email: "",
55
- },
56
- });
32
+ const session = await lbClient.verifySession();
33
+ if (session) {
34
+ const userData = await lbClient.getUser().catch(() => null);
35
+ const activeKey = userData?.apiKeyActive
36
+ ? {
37
+ id: userData.apiKeyActive.id,
38
+ name: userData.apiKeyActive.name,
39
+ keyPrefix: userData.apiKeyActive.prefix,
40
+ scopes: userData.apiKeyActive.scopes || [],
41
+ isActive: true,
42
+ createdAt: "",
57
43
  }
58
- }
59
- catch (statusError) {
60
- console.error("[LBProvider] Failed to fetch status:", statusError);
61
- // Fallback sans email
44
+ : undefined;
45
+ setApiKeys(userData?.apiKeys || []);
46
+ setState({
47
+ status: "ready",
48
+ session,
49
+ user: {
50
+ id: session.userId,
51
+ email: userData?.user?.email || "",
52
+ },
53
+ selectedKey: activeKey,
54
+ });
55
+ onStatusChange?.("ready");
56
+ }
57
+ else {
58
+ // Supabase session mode (no lb_session cookie): try user endpoint directly
59
+ const userData = await lbClient.getUser().catch(() => null);
60
+ if (userData?.user?.id) {
61
+ const activeKey = userData?.apiKeyActive
62
+ ? {
63
+ id: userData.apiKeyActive.id,
64
+ name: userData.apiKeyActive.name,
65
+ keyPrefix: userData.apiKeyActive.prefix,
66
+ scopes: userData.apiKeyActive.scopes || [],
67
+ isActive: true,
68
+ createdAt: "",
69
+ }
70
+ : undefined;
71
+ setApiKeys(userData.apiKeys || []);
62
72
  setState({
63
73
  status: "ready",
64
- session,
65
74
  user: {
66
- id: session.userId,
67
- email: "",
75
+ id: userData.user.id,
76
+ email: userData.user.email || "",
68
77
  },
78
+ selectedKey: activeKey,
69
79
  });
80
+ onStatusChange?.("ready");
81
+ }
82
+ else {
83
+ setState({ status: "needs_auth" });
84
+ onStatusChange?.("needs_auth");
70
85
  }
71
- onStatusChange?.("ready");
72
- }
73
- else {
74
- setState({ status: "needs_auth" });
75
- onStatusChange?.("needs_auth");
76
86
  }
77
87
  }
78
88
  catch (error) {
@@ -80,7 +90,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
80
90
  setState({ status: "needs_auth" });
81
91
  onStatusChange?.("needs_auth");
82
92
  }
83
- }, [proxyUrl, onStatusChange]);
93
+ }, [lbClient, onStatusChange]);
84
94
  useEffect(() => {
85
95
  checkSession();
86
96
  }, [checkSession]);
@@ -89,23 +99,8 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
89
99
  */
90
100
  const fetchApiKeys = useCallback(async (token) => {
91
101
  try {
92
- console.log("[LBProvider] Fetching API keys with token:", token.substring(0, 20) + "...");
93
- const response = await fetch(`${proxyUrl}/public/user/api-keys`, {
94
- headers: {
95
- Authorization: `Bearer ${token}`,
96
- "Content-Type": "application/json",
97
- },
98
- credentials: "include",
99
- });
100
- console.log("[LBProvider] API keys response status:", response.status);
101
- if (!response.ok) {
102
- const errorData = await response.json().catch(() => ({}));
103
- console.error("[LBProvider] Failed to fetch API keys:", errorData);
104
- throw new Error(errorData.message || "Failed to fetch API keys");
105
- }
106
- const data = await response.json();
107
- console.log("[LBProvider] API keys received:", data);
108
- const keys = data.apiKeys || data;
102
+ const data = await lbClient.getUser(token);
103
+ const keys = data.apiKeys || [];
109
104
  setApiKeys(keys);
110
105
  return keys;
111
106
  }
@@ -113,7 +108,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
113
108
  console.error("[LBProvider] Failed to fetch API keys:", error);
114
109
  throw error;
115
110
  }
116
- }, [proxyUrl]);
111
+ }, [lbClient]);
117
112
  /**
118
113
  * Sélectionne une clé API et crée une session
119
114
  */
@@ -121,22 +116,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
121
116
  try {
122
117
  console.log("[LBProvider] Selecting API key:", apiKeyId);
123
118
  setState((prev) => ({ ...prev, status: "loading" }));
124
- const response = await fetch(`${proxyUrl}/auth/session`, {
125
- method: "POST",
126
- headers: {
127
- "Content-Type": "application/json",
128
- Authorization: `Bearer ${token}`,
129
- },
130
- body: JSON.stringify({ api_key_id: apiKeyId }),
131
- credentials: "include",
132
- });
133
- console.log("[LBProvider] Session response status:", response.status);
134
- if (!response.ok) {
135
- const errorData = await response.json().catch(() => ({}));
136
- console.error("[LBProvider] Failed to create session:", errorData);
137
- throw new Error(errorData.message || "Failed to create session");
138
- }
139
- const sessionResult = await response.json();
119
+ const sessionResult = await lbClient.selectApiKey(apiKeyId, token);
140
120
  console.log("[LBProvider] Session created successfully:", sessionResult);
141
121
  setState({
142
122
  status: "ready",
@@ -162,7 +142,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
162
142
  });
163
143
  throw error;
164
144
  }
165
- }, [proxyUrl, state.user, onStatusChange, onAuthChange]);
145
+ }, [lbClient, state.user, onStatusChange, onAuthChange]);
166
146
  /**
167
147
  * Connexion utilisateur (étape 1 : login)
168
148
  * Retourne le token et les clés API sans créer de session
@@ -171,24 +151,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
171
151
  try {
172
152
  console.log("[LBProvider] Login attempt:", email);
173
153
  setState((prev) => ({ ...prev, status: "loading" }));
174
- const response = await fetch(`${proxyUrl}/auth/login`, {
175
- method: "POST",
176
- headers: { "Content-Type": "application/json" },
177
- body: JSON.stringify({ email, password }),
178
- credentials: "include",
179
- });
180
- console.log("[LBProvider] Login response status:", response.status);
181
- if (!response.ok) {
182
- const error = await response.json();
183
- const errorMessage = error.message || "Login failed";
184
- console.error("[LBProvider] Login failed:", errorMessage);
185
- setState({
186
- status: "needs_auth",
187
- error: errorMessage,
188
- });
189
- return { success: false, error: errorMessage };
190
- }
191
- const result = await response.json();
154
+ const result = await lbClient.login(email, password);
192
155
  console.log("[LBProvider] Login successful:", result.user?.email);
193
156
  console.log("[LBProvider] Access token received:", result.accessToken ? "YES" : "NO");
194
157
  console.log("[LBProvider] Token length:", result.accessToken?.length || 0);
@@ -259,7 +222,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
259
222
  });
260
223
  return { success: false, error: message };
261
224
  }
262
- }, [proxyUrl, fetchApiKeys, selectApiKey]);
225
+ }, [lbClient, fetchApiKeys, selectApiKey]);
263
226
  /**
264
227
  * Récupère le status API basique (balance, API key info) - RAPIDE
265
228
  */
@@ -271,22 +234,43 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
271
234
  }
272
235
  setIsLoadingStatus(true);
273
236
  try {
274
- const response = await fetch(`${proxyUrl}/auth/status?fast=true`, {
275
- credentials: "include",
276
- });
277
- if (response.ok) {
278
- const data = await response.json();
279
- setBasicStatus(data);
280
- // Combiner avec le storage existant si disponible
281
- const combinedStatus = {
282
- ...data,
283
- storage: storageStatus?.storage || data.storage,
284
- };
285
- setApiStatus(combinedStatus);
237
+ let data;
238
+ try {
239
+ data = await lbClient.getStatus();
286
240
  }
287
- else {
288
- setBasicStatus(null);
241
+ catch {
242
+ // Backward compatibility: older backends may not expose /auth/status
243
+ const userData = await lbClient.getUser();
244
+ data = {
245
+ authType: userData.authType,
246
+ user: userData.user,
247
+ apiKey: userData.apiKeyActive,
248
+ api_key: userData.apiKeyActive,
249
+ balance: {
250
+ used: 0,
251
+ total: userData.balance?.sellValueUsd || 0,
252
+ percentage: 0,
253
+ },
254
+ };
289
255
  }
256
+ const normalizedStatus = {
257
+ ...data,
258
+ authType: data?.authType,
259
+ user: data?.user,
260
+ apiKey: data?.apiKey || data?.api_key,
261
+ api_key: data?.api_key || data?.apiKey,
262
+ balance: data?.balance || {
263
+ used: 0,
264
+ total: 0,
265
+ percentage: 0,
266
+ },
267
+ };
268
+ setBasicStatus(normalizedStatus);
269
+ const combinedStatus = {
270
+ ...normalizedStatus,
271
+ storage: storageStatus?.storage,
272
+ };
273
+ setApiStatus(combinedStatus);
290
274
  }
291
275
  catch (error) {
292
276
  console.error("[LBProvider] Failed to fetch basic status:", error);
@@ -295,7 +279,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
295
279
  finally {
296
280
  setIsLoadingStatus(false);
297
281
  }
298
- }, [proxyUrl, state.status, storageStatus]);
282
+ }, [lbClient, state.status, storageStatus]);
299
283
  /**
300
284
  * Récupère le storage - LENT avec cache (5 minutes)
301
285
  */
@@ -315,35 +299,16 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
315
299
  }
316
300
  setIsLoadingStorage(true);
317
301
  try {
318
- // Essayer l'endpoint spécialisé storage d'abord
319
- let response = await fetch(`${proxyUrl}/auth/status/storage`, {
320
- credentials: "include",
321
- });
322
- // Si 404, faire un fallback vers l'endpoint normal (backward compatibility)
323
- if (!response.ok && response.status === 404) {
324
- console.log("[LBProvider] Storage endpoint not available, using fallback");
325
- response = await fetch(`${proxyUrl}/auth/status`, {
326
- credentials: "include",
327
- });
328
- }
329
- if (response.ok) {
330
- const data = await response.json();
331
- // Si c'est la réponse complète (fallback), extraire juste le storage
332
- const storageData = data.storage ? { storage: data.storage } : data;
333
- setStorageStatus(storageData);
334
- setStorageLastFetch(now);
335
- // Combiner avec le basic status
336
- const combinedStatus = {
337
- ...basicStatus,
338
- storage: storageData.storage,
339
- };
340
- setApiStatus(combinedStatus);
341
- }
342
- else {
343
- console.warn("[LBProvider] Failed to fetch storage status:", response.status);
344
- // Arrêter les tentatives répétées si échec persistant
345
- setStorageLastFetch(now); // Marquer comme essayé pour éviter la boucle
346
- }
302
+ const data = await lbClient.getStorageStatus();
303
+ const storageData = data?.storage ? { storage: data.storage } : data;
304
+ setStorageStatus(storageData);
305
+ setStorageLastFetch(now);
306
+ // Combiner avec le basic status
307
+ const combinedStatus = {
308
+ ...basicStatus,
309
+ storage: storageData?.storage,
310
+ };
311
+ setApiStatus(combinedStatus);
347
312
  }
348
313
  catch (error) {
349
314
  console.error("[LBProvider] Failed to fetch storage status:", error);
@@ -353,7 +318,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
353
318
  finally {
354
319
  setIsLoadingStorage(false);
355
320
  }
356
- }, [proxyUrl, state.status, basicStatus, storageLastFetch]);
321
+ }, [lbClient, state.status, basicStatus, storageLastFetch]);
357
322
  /**
358
323
  * Sélectionne une clé API avec le token déjà stocké (après login)
359
324
  */
@@ -367,35 +332,40 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
367
332
  * Change l'API key active - utilise la bonne méthode selon le contexte
368
333
  */
369
334
  const switchApiKey = useCallback(async (apiKeyId) => {
370
- if (state.status === "ready") {
371
- // Utiliser la route de switch avec session
372
- const response = await fetch(`${proxyUrl}/auth/session/switch-api-key`, {
373
- method: "POST",
374
- credentials: "include",
375
- headers: { "Content-Type": "application/json" },
376
- body: JSON.stringify({ api_key_id: apiKeyId }),
377
- });
378
- if (!response.ok) {
379
- const errorData = await response.json().catch(() => ({}));
380
- throw new Error(errorData.error || "Failed to switch API key");
335
+ if (state.status === "ready" || accessToken) {
336
+ // lb_session / login token flow: persist selection server-side when possible.
337
+ // api_key flow may legitimately reject this route; we still support local selection
338
+ // via x-lb-api-key-selected header on subsequent requests.
339
+ if (accessToken || state.session?.sessionToken) {
340
+ await lbClient.selectApiKey(apiKeyId, accessToken);
341
+ }
342
+ else {
343
+ try {
344
+ await lbClient.selectApiKey(apiKeyId, accessToken);
345
+ }
346
+ catch (error) {
347
+ console.warn("[LBProvider] selectApiKey API call failed, applying local switch only", error);
348
+ }
349
+ }
350
+ const selectedKey = apiKeys.find((key) => key.id === apiKeyId);
351
+ if (selectedKey) {
352
+ setState((prev) => ({
353
+ ...prev,
354
+ selectedKey,
355
+ }));
381
356
  }
382
- // Refresh le status après le changement
383
357
  await refreshBasicStatus();
384
- // Refresh storage en arrière-plan
385
358
  setTimeout(() => refreshStorageStatus(), 100);
386
359
  }
387
- else if (accessToken) {
388
- // Utiliser la méthode avec access token
389
- await selectApiKey(accessToken, apiKeyId);
390
- }
391
360
  else {
392
361
  throw new Error("No valid authentication method available");
393
362
  }
394
363
  }, [
395
364
  state.status,
396
- proxyUrl,
365
+ state.session?.sessionToken,
397
366
  accessToken,
398
- selectApiKey,
367
+ apiKeys,
368
+ lbClient,
399
369
  refreshBasicStatus,
400
370
  refreshStorageStatus,
401
371
  ]);
@@ -404,10 +374,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
404
374
  */
405
375
  const logout = useCallback(async () => {
406
376
  try {
407
- await fetch(`${proxyUrl}/auth/session/logout`, {
408
- method: "POST",
409
- credentials: "include",
410
- });
377
+ await lbClient.logout();
411
378
  }
412
379
  catch (error) {
413
380
  console.error("[LBProvider] Logout failed:", error);
@@ -416,10 +383,15 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
416
383
  setState({ status: "needs_auth" });
417
384
  setApiKeys([]);
418
385
  setAccessToken(undefined);
386
+ // Reset tous les statuts après logout
387
+ setApiStatus(null);
388
+ setBasicStatus(null);
389
+ setStorageStatus(null);
390
+ setStorageLastFetch(0);
419
391
  onStatusChange?.("needs_auth");
420
392
  onAuthChange?.(); // Refresh provider after logout
421
393
  }
422
- }, [proxyUrl, onStatusChange, onAuthChange]);
394
+ }, [lbClient, onStatusChange, onAuthChange]);
423
395
  /**
424
396
  * Recharge la session
425
397
  */
@@ -435,25 +407,14 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
435
407
  return;
436
408
  }
437
409
  try {
438
- console.log("[LBProvider] Fetching API keys with session...");
439
- const response = await fetch(`${proxyUrl}/auth/api-keys`, {
440
- credentials: "include",
441
- });
442
- if (response.ok) {
443
- const data = await response.json();
444
- console.log("[LBProvider] API keys received:", data);
445
- setApiKeys(data.apiKeys || []);
446
- }
447
- else {
448
- console.warn("[LBProvider] Failed to fetch API keys:", response.status);
449
- setApiKeys([]);
450
- }
410
+ const data = await lbClient.getUser();
411
+ setApiKeys(data.apiKeys || []);
451
412
  }
452
413
  catch (error) {
453
414
  console.error("[LBProvider] Failed to fetch API keys:", error);
454
415
  setApiKeys([]);
455
416
  }
456
- }, [proxyUrl, state.status]);
417
+ }, [lbClient, state.status]);
457
418
  // Refresh status quand la session devient ready
458
419
  useEffect(() => {
459
420
  if (state.status === "ready") {
@@ -1 +1 @@
1
- {"version":3,"file":"usePrompts.d.ts","sourceRoot":"","sources":["../../src/hooks/usePrompts.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAa,SAAQ,MAAM;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,EAAE,CAAC,OAAO,CAAC,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,YAAY,EAAE,CACZ,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,KACnD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5B,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5E,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,aAAa,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,KAClC,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED,wBAAgB,UAAU,IAAI,gBAAgB,CAgS7C"}
1
+ {"version":3,"file":"usePrompts.d.ts","sourceRoot":"","sources":["../../src/hooks/usePrompts.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAa,SAAQ,MAAM;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,EAAE,CAAC,OAAO,CAAC,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,YAAY,EAAE,CACZ,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,KACnD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5B,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5E,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,aAAa,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,KAClC,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED,wBAAgB,UAAU,IAAI,gBAAgB,CAuS7C"}
@@ -7,6 +7,14 @@ export function usePrompts() {
7
7
  const [prompts, setPrompts] = useState([]);
8
8
  const [loading, setLoading] = useState(false);
9
9
  const [error, setError] = useState(null);
10
+ const isAuthTokenCandidate = (value) => {
11
+ if (!value)
12
+ return false;
13
+ const token = value.trim();
14
+ if (!token)
15
+ return false;
16
+ return token.startsWith("lb_") || token.split(".").length === 3;
17
+ };
10
18
  const fetchPrompts = useCallback(async (options) => {
11
19
  try {
12
20
  setLoading(true);
@@ -71,7 +79,7 @@ export function usePrompts() {
71
79
  console.log("[usePrompts] Fetching prompts from:", endpoint);
72
80
  const headers = {};
73
81
  // Ajouter l'API key pour les appels publics directs (pas de proxy externe ni auth interne)
74
- if (isPublicApi && apiKeyId) {
82
+ if (isPublicApi && isAuthTokenCandidate(apiKeyId)) {
75
83
  headers["Authorization"] = `Bearer ${apiKeyId}`;
76
84
  }
77
85
  const response = await fetch(endpoint, {
@@ -110,7 +118,7 @@ export function usePrompts() {
110
118
  ? `${baseUrl}/auth/prompts` // Proxy ajoutera /api/ai/
111
119
  : "/api/ai/auth/prompts";
112
120
  const headers = { "Content-Type": "application/json" };
113
- if (!isExternalProxy && apiKeyId) {
121
+ if (!isExternalProxy && isAuthTokenCandidate(apiKeyId)) {
114
122
  headers["Authorization"] = `Bearer ${apiKeyId}`;
115
123
  }
116
124
  const response = await fetch(endpoint, {
@@ -148,7 +156,7 @@ export function usePrompts() {
148
156
  ? `${baseUrl}/auth/prompts`
149
157
  : "/api/ai/auth/prompts";
150
158
  const headers = { "Content-Type": "application/json" };
151
- if (isPublicApi && apiKeyId) {
159
+ if (isPublicApi && isAuthTokenCandidate(apiKeyId)) {
152
160
  headers["Authorization"] = `Bearer ${apiKeyId}`;
153
161
  }
154
162
  const response = await fetch(endpoint, {
@@ -186,7 +194,7 @@ export function usePrompts() {
186
194
  ? `${baseUrl}/auth/prompts?id=${id}`
187
195
  : `/api/ai/auth/prompts?id=${id}`;
188
196
  const headers = {};
189
- if (isPublicApi && apiKeyId) {
197
+ if (isPublicApi && isAuthTokenCandidate(apiKeyId)) {
190
198
  headers["Authorization"] = `Bearer ${apiKeyId}`;
191
199
  }
192
200
  const response = await fetch(endpoint, {
@@ -1 +1 @@
1
- {"version":3,"file":"modelManagement.d.ts","sourceRoot":"","sources":["../../src/utils/modelManagement.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,OAAO,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CACR,KAAK,CAAC;IACJ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CACH,CA6CA;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,MAAM,EAAE,CAAC,CAkDnB"}
1
+ {"version":3,"file":"modelManagement.d.ts","sourceRoot":"","sources":["../../src/utils/modelManagement.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAUD;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,OAAO,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CACR,KAAK,CAAC;IACJ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CACH,CAsDA;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,MAAM,EAAE,CAAC,CAkDnB"}
@@ -1,6 +1,15 @@
1
1
  /**
2
2
  * Utilitaires pour la gestion des modèles IA
3
3
  */
4
+ function isAuthTokenCandidate(value) {
5
+ if (!value)
6
+ return false;
7
+ const token = value.trim();
8
+ if (!token)
9
+ return false;
10
+ // Raw API key or JWT access token
11
+ return token.startsWith("lb_") || token.split(".").length === 3;
12
+ }
4
13
  /**
5
14
  * Active ou désactive un modèle pour l'utilisateur courant
6
15
  */
@@ -10,7 +19,7 @@ export async function toggleUserModel(modelId, isActive, options = {}) {
10
19
  "Content-Type": "application/json",
11
20
  };
12
21
  // Ajouter la clé API si fournie
13
- if (apiKey) {
22
+ if (isAuthTokenCandidate(apiKey)) {
14
23
  headers["Authorization"] = `Bearer ${apiKey}`;
15
24
  }
16
25
  const isPublicApi = baseUrl && baseUrl.includes("/api/public/v1");
@@ -45,16 +54,16 @@ export async function getAvailableModels(options = {}) {
45
54
  const isExternalProxy = baseUrl && baseUrl.includes("/api/lastbrain");
46
55
  const isPublicApi = baseUrl && baseUrl.includes("/api/public/v1");
47
56
  const endpoint = isExternalProxy
48
- ? `${baseUrl}/ai/models/available` // Proxy routes to public API
57
+ ? `${baseUrl}/auth/models` // Proxy routes to /api/ai/auth/models
49
58
  : isPublicApi
50
- ? `${baseUrl}/ai/models/available` // → /api/public/v1/ai/models/available
59
+ ? `${baseUrl}/gateway-models` // → /api/public/v1/gateway-models
51
60
  : baseUrl
52
- ? `${baseUrl}/auth/ai-models-available` // → /api/ai/auth/ai-models-available
53
- : `/api/ai/auth/ai-models-available`; // fallback
61
+ ? `${baseUrl}/auth/models` // → /api/ai/auth/models
62
+ : `/api/ai/auth/models`; // fallback
54
63
  console.log("[getAvailableModels] isExternalProxy:", isExternalProxy, "isPublicApi:", isPublicApi, "endpoint:", endpoint);
55
64
  const headers = {};
56
65
  // Ajouter la clé API pour les appels publics directs
57
- if (isPublicApi && apiKey) {
66
+ if (isPublicApi && isAuthTokenCandidate(apiKey)) {
58
67
  headers["Authorization"] = `Bearer ${apiKey}`;
59
68
  }
60
69
  const response = await fetch(endpoint, {
@@ -66,7 +75,13 @@ export async function getAvailableModels(options = {}) {
66
75
  throw new Error(`Erreur lors de la récupération des modèles: ${response.status}`);
67
76
  }
68
77
  const data = await response.json();
69
- return data.models || [];
78
+ if (Array.isArray(data?.models)) {
79
+ return data.models;
80
+ }
81
+ if (Array.isArray(data?.providers)) {
82
+ return data.providers.flatMap((provider) => Array.isArray(provider.models) ? provider.models : []);
83
+ }
84
+ return [];
70
85
  }
71
86
  /**
72
87
  * Récupère les modèles activés par l'utilisateur avec API key
@@ -86,7 +101,7 @@ export async function getUserModels(options = {}) {
86
101
  console.log("[getUserModels] isExternalProxy:", isExternalProxy, "isPublicApi:", isPublicApi, "endpoint:", endpoint);
87
102
  const headers = {};
88
103
  // Ajouter la clé API pour tous les types d'appels si disponible
89
- if (apiKey) {
104
+ if (isAuthTokenCandidate(apiKey)) {
90
105
  if (isPublicApi) {
91
106
  headers["Authorization"] = `Bearer ${apiKey}`;
92
107
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lastbrain/ai-ui-react",
3
- "version": "1.0.63",
3
+ "version": "1.0.65",
4
4
  "description": "Headless React components for LastBrain AI UI Kit",
5
5
  "private": false,
6
6
  "type": "module",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "lucide-react": "^0.257.0",
51
- "@lastbrain/ai-ui-core": "1.0.46"
51
+ "@lastbrain/ai-ui-core": "1.0.49"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/react": "^19.2.0",
@@ -296,6 +296,8 @@ Exemple de réponse attendue: javascript, react, frontend, api, development`;
296
296
  models={models || undefined}
297
297
  baseUrl={baseUrl}
298
298
  sourceText={context ? `Contexte: ${context}` : undefined}
299
+ enableModelManagement={true}
300
+ showOnlyUserModels={true}
299
301
  />
300
302
 
301
303
  {/* Modal signin pour les utilisateurs non connectés */}