@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.
- package/dist/components/AiChipLabel.d.ts.map +1 -1
- package/dist/components/AiChipLabel.js +1 -1
- package/dist/components/AiInput.d.ts +1 -1
- package/dist/components/AiInput.d.ts.map +1 -1
- package/dist/components/AiInput.js +16 -2
- package/dist/components/AiPromptPanel.d.ts +1 -0
- package/dist/components/AiPromptPanel.d.ts.map +1 -1
- package/dist/components/AiPromptPanel.js +39 -9
- package/dist/components/AiStatusButton.d.ts.map +1 -1
- package/dist/components/AiStatusButton.js +81 -12
- package/dist/components/AiTextarea.d.ts +1 -1
- package/dist/components/AiTextarea.d.ts.map +1 -1
- package/dist/components/AiTextarea.js +16 -2
- package/dist/context/LBAuthProvider.d.ts.map +1 -1
- package/dist/context/LBAuthProvider.js +143 -182
- package/dist/hooks/usePrompts.d.ts.map +1 -1
- package/dist/hooks/usePrompts.js +12 -4
- package/dist/utils/modelManagement.d.ts.map +1 -1
- package/dist/utils/modelManagement.js +23 -8
- package/package.json +2 -2
- package/src/components/AiChipLabel.tsx +2 -0
- package/src/components/AiInput.tsx +18 -2
- package/src/components/AiPromptPanel.tsx +50 -9
- package/src/components/AiStatusButton.tsx +127 -13
- package/src/components/AiTextarea.tsx +18 -2
- package/src/context/LBAuthProvider.tsx +151 -208
- package/src/hooks/usePrompts.ts +11 -4
- package/src/utils/modelManagement.ts +25 -8
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
useContext,
|
|
11
11
|
useEffect,
|
|
12
12
|
useCallback,
|
|
13
|
+
useMemo,
|
|
13
14
|
useState,
|
|
14
15
|
type ReactNode,
|
|
15
16
|
} from "react";
|
|
@@ -21,6 +22,7 @@ import type {
|
|
|
21
22
|
LBSessionResult,
|
|
22
23
|
AiStatus,
|
|
23
24
|
} from "@lastbrain/ai-ui-core";
|
|
25
|
+
import { createLBClient } from "@lastbrain/ai-ui-core";
|
|
24
26
|
|
|
25
27
|
interface LBProviderProps {
|
|
26
28
|
children: ReactNode;
|
|
@@ -100,69 +102,81 @@ export function LBProvider({
|
|
|
100
102
|
const [isLoadingStorage, setIsLoadingStorage] = useState(false);
|
|
101
103
|
const [storageLastFetch, setStorageLastFetch] = useState<number>(0);
|
|
102
104
|
|
|
105
|
+
const lbClient = useMemo(
|
|
106
|
+
() =>
|
|
107
|
+
createLBClient({
|
|
108
|
+
baseUrl: proxyUrl,
|
|
109
|
+
mode: process.env.LB_API_KEY ? "env-key" : "auto",
|
|
110
|
+
selectedApiKeyId: state.selectedKey?.id,
|
|
111
|
+
}),
|
|
112
|
+
[proxyUrl, state.selectedKey?.id]
|
|
113
|
+
);
|
|
114
|
+
|
|
103
115
|
/**
|
|
104
116
|
* Vérifie si une session existe au chargement
|
|
105
117
|
*/
|
|
106
118
|
const checkSession = useCallback(async () => {
|
|
107
119
|
try {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
120
|
+
const session = await lbClient.verifySession();
|
|
121
|
+
if (session) {
|
|
122
|
+
const userData = await lbClient.getUser().catch(() => null);
|
|
123
|
+
const activeKey = userData?.apiKeyActive
|
|
124
|
+
? {
|
|
125
|
+
id: userData.apiKeyActive.id,
|
|
126
|
+
name: userData.apiKeyActive.name,
|
|
127
|
+
keyPrefix: userData.apiKeyActive.prefix,
|
|
128
|
+
scopes: userData.apiKeyActive.scopes || [],
|
|
129
|
+
isActive: true,
|
|
130
|
+
createdAt: "",
|
|
131
|
+
}
|
|
132
|
+
: undefined;
|
|
133
|
+
setApiKeys(userData?.apiKeys || []);
|
|
134
|
+
setState({
|
|
135
|
+
status: "ready",
|
|
136
|
+
session,
|
|
137
|
+
user: {
|
|
138
|
+
id: session.userId,
|
|
139
|
+
email: userData?.user?.email || "",
|
|
140
|
+
},
|
|
141
|
+
selectedKey: activeKey,
|
|
142
|
+
});
|
|
143
|
+
onStatusChange?.("ready");
|
|
144
|
+
} else {
|
|
145
|
+
// Supabase session mode (no lb_session cookie): try user endpoint directly
|
|
146
|
+
const userData = await lbClient.getUser().catch(() => null);
|
|
147
|
+
if (userData?.user?.id) {
|
|
148
|
+
const activeKey = userData?.apiKeyActive
|
|
149
|
+
? {
|
|
150
|
+
id: userData.apiKeyActive.id,
|
|
151
|
+
name: userData.apiKeyActive.name,
|
|
152
|
+
keyPrefix: userData.apiKeyActive.prefix,
|
|
153
|
+
scopes: userData.apiKeyActive.scopes || [],
|
|
154
|
+
isActive: true,
|
|
155
|
+
createdAt: "",
|
|
156
|
+
}
|
|
157
|
+
: undefined;
|
|
158
|
+
|
|
159
|
+
setApiKeys(userData.apiKeys || []);
|
|
145
160
|
setState({
|
|
146
161
|
status: "ready",
|
|
147
|
-
session,
|
|
148
162
|
user: {
|
|
149
|
-
id:
|
|
150
|
-
email: "",
|
|
163
|
+
id: userData.user.id,
|
|
164
|
+
email: userData.user.email || "",
|
|
151
165
|
},
|
|
166
|
+
selectedKey: activeKey,
|
|
152
167
|
});
|
|
168
|
+
onStatusChange?.("ready");
|
|
169
|
+
} else {
|
|
170
|
+
setState({ status: "needs_auth" });
|
|
171
|
+
onStatusChange?.("needs_auth");
|
|
153
172
|
}
|
|
154
|
-
|
|
155
|
-
onStatusChange?.("ready");
|
|
156
|
-
} else {
|
|
157
|
-
setState({ status: "needs_auth" });
|
|
158
|
-
onStatusChange?.("needs_auth");
|
|
159
173
|
}
|
|
160
174
|
} catch (error) {
|
|
161
175
|
console.error("[LBProvider] Session check failed:", error);
|
|
162
176
|
setState({ status: "needs_auth" });
|
|
163
177
|
onStatusChange?.("needs_auth");
|
|
164
178
|
}
|
|
165
|
-
}, [
|
|
179
|
+
}, [lbClient, onStatusChange]);
|
|
166
180
|
|
|
167
181
|
useEffect(() => {
|
|
168
182
|
checkSession();
|
|
@@ -174,31 +188,8 @@ export function LBProvider({
|
|
|
174
188
|
const fetchApiKeys = useCallback(
|
|
175
189
|
async (token: string): Promise<LBApiKey[]> => {
|
|
176
190
|
try {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
token.substring(0, 20) + "..."
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
const response = await fetch(`${proxyUrl}/public/user/api-keys`, {
|
|
183
|
-
headers: {
|
|
184
|
-
Authorization: `Bearer ${token}`,
|
|
185
|
-
"Content-Type": "application/json",
|
|
186
|
-
},
|
|
187
|
-
credentials: "include",
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
console.log("[LBProvider] API keys response status:", response.status);
|
|
191
|
-
|
|
192
|
-
if (!response.ok) {
|
|
193
|
-
const errorData = await response.json().catch(() => ({}));
|
|
194
|
-
console.error("[LBProvider] Failed to fetch API keys:", errorData);
|
|
195
|
-
throw new Error(errorData.message || "Failed to fetch API keys");
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const data = await response.json();
|
|
199
|
-
console.log("[LBProvider] API keys received:", data);
|
|
200
|
-
|
|
201
|
-
const keys: LBApiKey[] = data.apiKeys || data;
|
|
191
|
+
const data = await lbClient.getUser(token);
|
|
192
|
+
const keys: LBApiKey[] = data.apiKeys || [];
|
|
202
193
|
setApiKeys(keys);
|
|
203
194
|
return keys;
|
|
204
195
|
} catch (error) {
|
|
@@ -206,7 +197,7 @@ export function LBProvider({
|
|
|
206
197
|
throw error;
|
|
207
198
|
}
|
|
208
199
|
},
|
|
209
|
-
[
|
|
200
|
+
[lbClient]
|
|
210
201
|
);
|
|
211
202
|
|
|
212
203
|
/**
|
|
@@ -217,26 +208,10 @@ export function LBProvider({
|
|
|
217
208
|
try {
|
|
218
209
|
console.log("[LBProvider] Selecting API key:", apiKeyId);
|
|
219
210
|
setState((prev: LBAuthState) => ({ ...prev, status: "loading" }));
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
"Content-Type": "application/json",
|
|
225
|
-
Authorization: `Bearer ${token}`,
|
|
226
|
-
},
|
|
227
|
-
body: JSON.stringify({ api_key_id: apiKeyId }),
|
|
228
|
-
credentials: "include",
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
console.log("[LBProvider] Session response status:", response.status);
|
|
232
|
-
|
|
233
|
-
if (!response.ok) {
|
|
234
|
-
const errorData = await response.json().catch(() => ({}));
|
|
235
|
-
console.error("[LBProvider] Failed to create session:", errorData);
|
|
236
|
-
throw new Error(errorData.message || "Failed to create session");
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const sessionResult: LBSessionResult = await response.json();
|
|
211
|
+
const sessionResult: LBSessionResult = await lbClient.selectApiKey(
|
|
212
|
+
apiKeyId,
|
|
213
|
+
token
|
|
214
|
+
);
|
|
240
215
|
console.log(
|
|
241
216
|
"[LBProvider] Session created successfully:",
|
|
242
217
|
sessionResult
|
|
@@ -268,7 +243,7 @@ export function LBProvider({
|
|
|
268
243
|
throw error;
|
|
269
244
|
}
|
|
270
245
|
},
|
|
271
|
-
[
|
|
246
|
+
[lbClient, state.user, onStatusChange, onAuthChange]
|
|
272
247
|
);
|
|
273
248
|
|
|
274
249
|
/**
|
|
@@ -289,27 +264,7 @@ export function LBProvider({
|
|
|
289
264
|
console.log("[LBProvider] Login attempt:", email);
|
|
290
265
|
setState((prev: LBAuthState) => ({ ...prev, status: "loading" }));
|
|
291
266
|
|
|
292
|
-
const
|
|
293
|
-
method: "POST",
|
|
294
|
-
headers: { "Content-Type": "application/json" },
|
|
295
|
-
body: JSON.stringify({ email, password }),
|
|
296
|
-
credentials: "include",
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
console.log("[LBProvider] Login response status:", response.status);
|
|
300
|
-
|
|
301
|
-
if (!response.ok) {
|
|
302
|
-
const error = await response.json();
|
|
303
|
-
const errorMessage = error.message || "Login failed";
|
|
304
|
-
console.error("[LBProvider] Login failed:", errorMessage);
|
|
305
|
-
setState({
|
|
306
|
-
status: "needs_auth",
|
|
307
|
-
error: errorMessage,
|
|
308
|
-
});
|
|
309
|
-
return { success: false, error: errorMessage };
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const result: LBLoginResult = await response.json();
|
|
267
|
+
const result: LBLoginResult = await lbClient.login(email, password);
|
|
313
268
|
console.log("[LBProvider] Login successful:", result.user?.email);
|
|
314
269
|
console.log(
|
|
315
270
|
"[LBProvider] Access token received:",
|
|
@@ -403,7 +358,7 @@ export function LBProvider({
|
|
|
403
358
|
return { success: false, error: message };
|
|
404
359
|
}
|
|
405
360
|
},
|
|
406
|
-
[
|
|
361
|
+
[lbClient, fetchApiKeys, selectApiKey]
|
|
407
362
|
);
|
|
408
363
|
|
|
409
364
|
/**
|
|
@@ -418,30 +373,50 @@ export function LBProvider({
|
|
|
418
373
|
|
|
419
374
|
setIsLoadingStatus(true);
|
|
420
375
|
try {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
376
|
+
let data: any;
|
|
377
|
+
try {
|
|
378
|
+
data = await lbClient.getStatus();
|
|
379
|
+
} catch {
|
|
380
|
+
// Backward compatibility: older backends may not expose /auth/status
|
|
381
|
+
const userData = await lbClient.getUser();
|
|
382
|
+
data = {
|
|
383
|
+
authType: userData.authType,
|
|
384
|
+
user: userData.user,
|
|
385
|
+
apiKey: userData.apiKeyActive,
|
|
386
|
+
api_key: userData.apiKeyActive,
|
|
387
|
+
balance: {
|
|
388
|
+
used: 0,
|
|
389
|
+
total: userData.balance?.sellValueUsd || 0,
|
|
390
|
+
percentage: 0,
|
|
391
|
+
},
|
|
433
392
|
};
|
|
434
|
-
setApiStatus(combinedStatus);
|
|
435
|
-
} else {
|
|
436
|
-
setBasicStatus(null);
|
|
437
393
|
}
|
|
394
|
+
const normalizedStatus = {
|
|
395
|
+
...data,
|
|
396
|
+
authType: data?.authType,
|
|
397
|
+
user: data?.user,
|
|
398
|
+
apiKey: data?.apiKey || data?.api_key,
|
|
399
|
+
api_key: data?.api_key || data?.apiKey,
|
|
400
|
+
balance: data?.balance || {
|
|
401
|
+
used: 0,
|
|
402
|
+
total: 0,
|
|
403
|
+
percentage: 0,
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
setBasicStatus(normalizedStatus);
|
|
407
|
+
|
|
408
|
+
const combinedStatus = {
|
|
409
|
+
...normalizedStatus,
|
|
410
|
+
storage: storageStatus?.storage,
|
|
411
|
+
};
|
|
412
|
+
setApiStatus(combinedStatus as any);
|
|
438
413
|
} catch (error) {
|
|
439
414
|
console.error("[LBProvider] Failed to fetch basic status:", error);
|
|
440
415
|
setBasicStatus(null);
|
|
441
416
|
} finally {
|
|
442
417
|
setIsLoadingStatus(false);
|
|
443
418
|
}
|
|
444
|
-
}, [
|
|
419
|
+
}, [lbClient, state.status, storageStatus]);
|
|
445
420
|
|
|
446
421
|
/**
|
|
447
422
|
* Récupère le storage - LENT avec cache (5 minutes)
|
|
@@ -467,42 +442,17 @@ export function LBProvider({
|
|
|
467
442
|
|
|
468
443
|
setIsLoadingStorage(true);
|
|
469
444
|
try {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
445
|
+
const data = await lbClient.getStorageStatus();
|
|
446
|
+
const storageData = data?.storage ? { storage: data.storage } : data;
|
|
447
|
+
setStorageStatus(storageData);
|
|
448
|
+
setStorageLastFetch(now);
|
|
474
449
|
|
|
475
|
-
//
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
if (response.ok) {
|
|
484
|
-
const data = await response.json();
|
|
485
|
-
|
|
486
|
-
// Si c'est la réponse complète (fallback), extraire juste le storage
|
|
487
|
-
const storageData = data.storage ? { storage: data.storage } : data;
|
|
488
|
-
|
|
489
|
-
setStorageStatus(storageData);
|
|
490
|
-
setStorageLastFetch(now);
|
|
491
|
-
|
|
492
|
-
// Combiner avec le basic status
|
|
493
|
-
const combinedStatus = {
|
|
494
|
-
...basicStatus,
|
|
495
|
-
storage: storageData.storage,
|
|
496
|
-
};
|
|
497
|
-
setApiStatus(combinedStatus);
|
|
498
|
-
} else {
|
|
499
|
-
console.warn(
|
|
500
|
-
"[LBProvider] Failed to fetch storage status:",
|
|
501
|
-
response.status
|
|
502
|
-
);
|
|
503
|
-
// Arrêter les tentatives répétées si échec persistant
|
|
504
|
-
setStorageLastFetch(now); // Marquer comme essayé pour éviter la boucle
|
|
505
|
-
}
|
|
450
|
+
// Combiner avec le basic status
|
|
451
|
+
const combinedStatus = {
|
|
452
|
+
...basicStatus,
|
|
453
|
+
storage: storageData?.storage,
|
|
454
|
+
};
|
|
455
|
+
setApiStatus(combinedStatus);
|
|
506
456
|
} catch (error) {
|
|
507
457
|
console.error("[LBProvider] Failed to fetch storage status:", error);
|
|
508
458
|
// Arrêter les tentatives répétées si erreur persistante
|
|
@@ -511,7 +461,7 @@ export function LBProvider({
|
|
|
511
461
|
setIsLoadingStorage(false);
|
|
512
462
|
}
|
|
513
463
|
},
|
|
514
|
-
[
|
|
464
|
+
[lbClient, state.status, basicStatus, storageLastFetch]
|
|
515
465
|
);
|
|
516
466
|
|
|
517
467
|
/**
|
|
@@ -532,39 +482,41 @@ export function LBProvider({
|
|
|
532
482
|
*/
|
|
533
483
|
const switchApiKey = useCallback(
|
|
534
484
|
async (apiKeyId: string): Promise<void> => {
|
|
535
|
-
if (state.status === "ready") {
|
|
536
|
-
//
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
485
|
+
if (state.status === "ready" || accessToken) {
|
|
486
|
+
// lb_session / login token flow: persist selection server-side when possible.
|
|
487
|
+
// api_key flow may legitimately reject this route; we still support local selection
|
|
488
|
+
// via x-lb-api-key-selected header on subsequent requests.
|
|
489
|
+
if (accessToken || state.session?.sessionToken) {
|
|
490
|
+
await lbClient.selectApiKey(apiKeyId, accessToken);
|
|
491
|
+
} else {
|
|
492
|
+
try {
|
|
493
|
+
await lbClient.selectApiKey(apiKeyId, accessToken);
|
|
494
|
+
} catch (error) {
|
|
495
|
+
console.warn(
|
|
496
|
+
"[LBProvider] selectApiKey API call failed, applying local switch only",
|
|
497
|
+
error
|
|
498
|
+
);
|
|
544
499
|
}
|
|
545
|
-
);
|
|
546
|
-
|
|
547
|
-
if (!response.ok) {
|
|
548
|
-
const errorData = await response.json().catch(() => ({}));
|
|
549
|
-
throw new Error(errorData.error || "Failed to switch API key");
|
|
550
500
|
}
|
|
551
|
-
|
|
552
|
-
|
|
501
|
+
const selectedKey = apiKeys.find((key) => key.id === apiKeyId);
|
|
502
|
+
if (selectedKey) {
|
|
503
|
+
setState((prev) => ({
|
|
504
|
+
...prev,
|
|
505
|
+
selectedKey,
|
|
506
|
+
}));
|
|
507
|
+
}
|
|
553
508
|
await refreshBasicStatus();
|
|
554
|
-
// Refresh storage en arrière-plan
|
|
555
509
|
setTimeout(() => refreshStorageStatus(), 100);
|
|
556
|
-
} else if (accessToken) {
|
|
557
|
-
// Utiliser la méthode avec access token
|
|
558
|
-
await selectApiKey(accessToken, apiKeyId);
|
|
559
510
|
} else {
|
|
560
511
|
throw new Error("No valid authentication method available");
|
|
561
512
|
}
|
|
562
513
|
},
|
|
563
514
|
[
|
|
564
515
|
state.status,
|
|
565
|
-
|
|
516
|
+
state.session?.sessionToken,
|
|
566
517
|
accessToken,
|
|
567
|
-
|
|
518
|
+
apiKeys,
|
|
519
|
+
lbClient,
|
|
568
520
|
refreshBasicStatus,
|
|
569
521
|
refreshStorageStatus,
|
|
570
522
|
]
|
|
@@ -575,20 +527,22 @@ export function LBProvider({
|
|
|
575
527
|
*/
|
|
576
528
|
const logout = useCallback(async (): Promise<void> => {
|
|
577
529
|
try {
|
|
578
|
-
await
|
|
579
|
-
method: "POST",
|
|
580
|
-
credentials: "include",
|
|
581
|
-
});
|
|
530
|
+
await lbClient.logout();
|
|
582
531
|
} catch (error) {
|
|
583
532
|
console.error("[LBProvider] Logout failed:", error);
|
|
584
533
|
} finally {
|
|
585
534
|
setState({ status: "needs_auth" });
|
|
586
535
|
setApiKeys([]);
|
|
587
536
|
setAccessToken(undefined);
|
|
537
|
+
// Reset tous les statuts après logout
|
|
538
|
+
setApiStatus(null);
|
|
539
|
+
setBasicStatus(null);
|
|
540
|
+
setStorageStatus(null);
|
|
541
|
+
setStorageLastFetch(0);
|
|
588
542
|
onStatusChange?.("needs_auth");
|
|
589
543
|
onAuthChange?.(); // Refresh provider after logout
|
|
590
544
|
}
|
|
591
|
-
}, [
|
|
545
|
+
}, [lbClient, onStatusChange, onAuthChange]);
|
|
592
546
|
|
|
593
547
|
/**
|
|
594
548
|
* Recharge la session
|
|
@@ -607,24 +561,13 @@ export function LBProvider({
|
|
|
607
561
|
}
|
|
608
562
|
|
|
609
563
|
try {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
credentials: "include",
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
if (response.ok) {
|
|
616
|
-
const data = await response.json();
|
|
617
|
-
console.log("[LBProvider] API keys received:", data);
|
|
618
|
-
setApiKeys(data.apiKeys || []);
|
|
619
|
-
} else {
|
|
620
|
-
console.warn("[LBProvider] Failed to fetch API keys:", response.status);
|
|
621
|
-
setApiKeys([]);
|
|
622
|
-
}
|
|
564
|
+
const data = await lbClient.getUser();
|
|
565
|
+
setApiKeys(data.apiKeys || []);
|
|
623
566
|
} catch (error) {
|
|
624
567
|
console.error("[LBProvider] Failed to fetch API keys:", error);
|
|
625
568
|
setApiKeys([]);
|
|
626
569
|
}
|
|
627
|
-
}, [
|
|
570
|
+
}, [lbClient, state.status]);
|
|
628
571
|
|
|
629
572
|
// Refresh status quand la session devient ready
|
|
630
573
|
useEffect(() => {
|
package/src/hooks/usePrompts.ts
CHANGED
|
@@ -59,6 +59,13 @@ export function usePrompts(): UsePromptsReturn {
|
|
|
59
59
|
const [loading, setLoading] = useState(false);
|
|
60
60
|
const [error, setError] = useState<string | null>(null);
|
|
61
61
|
|
|
62
|
+
const isAuthTokenCandidate = (value?: string): boolean => {
|
|
63
|
+
if (!value) return false;
|
|
64
|
+
const token = value.trim();
|
|
65
|
+
if (!token) return false;
|
|
66
|
+
return token.startsWith("lb_") || token.split(".").length === 3;
|
|
67
|
+
};
|
|
68
|
+
|
|
62
69
|
const fetchPrompts = useCallback(
|
|
63
70
|
async (options?: UsePromptsOptions) => {
|
|
64
71
|
try {
|
|
@@ -133,7 +140,7 @@ export function usePrompts(): UsePromptsReturn {
|
|
|
133
140
|
|
|
134
141
|
const headers: HeadersInit = {};
|
|
135
142
|
// Ajouter l'API key pour les appels publics directs (pas de proxy externe ni auth interne)
|
|
136
|
-
if (isPublicApi && apiKeyId) {
|
|
143
|
+
if (isPublicApi && isAuthTokenCandidate(apiKeyId)) {
|
|
137
144
|
headers["Authorization"] = `Bearer ${apiKeyId}`;
|
|
138
145
|
}
|
|
139
146
|
|
|
@@ -179,7 +186,7 @@ export function usePrompts(): UsePromptsReturn {
|
|
|
179
186
|
: "/api/ai/auth/prompts";
|
|
180
187
|
|
|
181
188
|
const headers: HeadersInit = { "Content-Type": "application/json" };
|
|
182
|
-
if (!isExternalProxy && apiKeyId) {
|
|
189
|
+
if (!isExternalProxy && isAuthTokenCandidate(apiKeyId)) {
|
|
183
190
|
headers["Authorization"] = `Bearer ${apiKeyId}`;
|
|
184
191
|
}
|
|
185
192
|
|
|
@@ -225,7 +232,7 @@ export function usePrompts(): UsePromptsReturn {
|
|
|
225
232
|
: "/api/ai/auth/prompts";
|
|
226
233
|
|
|
227
234
|
const headers: HeadersInit = { "Content-Type": "application/json" };
|
|
228
|
-
if (isPublicApi && apiKeyId) {
|
|
235
|
+
if (isPublicApi && isAuthTokenCandidate(apiKeyId)) {
|
|
229
236
|
headers["Authorization"] = `Bearer ${apiKeyId}`;
|
|
230
237
|
}
|
|
231
238
|
|
|
@@ -271,7 +278,7 @@ export function usePrompts(): UsePromptsReturn {
|
|
|
271
278
|
: `/api/ai/auth/prompts?id=${id}`;
|
|
272
279
|
|
|
273
280
|
const headers: HeadersInit = {};
|
|
274
|
-
if (isPublicApi && apiKeyId) {
|
|
281
|
+
if (isPublicApi && isAuthTokenCandidate(apiKeyId)) {
|
|
275
282
|
headers["Authorization"] = `Bearer ${apiKeyId}`;
|
|
276
283
|
}
|
|
277
284
|
|
|
@@ -7,6 +7,14 @@ export interface ModelToggleOptions {
|
|
|
7
7
|
baseUrl?: string; // URL de base de l'API
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
function isAuthTokenCandidate(value?: string): boolean {
|
|
11
|
+
if (!value) return false;
|
|
12
|
+
const token = value.trim();
|
|
13
|
+
if (!token) return false;
|
|
14
|
+
// Raw API key or JWT access token
|
|
15
|
+
return token.startsWith("lb_") || token.split(".").length === 3;
|
|
16
|
+
}
|
|
17
|
+
|
|
10
18
|
/**
|
|
11
19
|
* Active ou désactive un modèle pour l'utilisateur courant
|
|
12
20
|
*/
|
|
@@ -22,7 +30,7 @@ export async function toggleUserModel(
|
|
|
22
30
|
};
|
|
23
31
|
|
|
24
32
|
// Ajouter la clé API si fournie
|
|
25
|
-
if (apiKey) {
|
|
33
|
+
if (isAuthTokenCandidate(apiKey)) {
|
|
26
34
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
27
35
|
}
|
|
28
36
|
|
|
@@ -77,12 +85,12 @@ export async function getAvailableModels(
|
|
|
77
85
|
const isPublicApi = baseUrl && baseUrl.includes("/api/public/v1");
|
|
78
86
|
|
|
79
87
|
const endpoint = isExternalProxy
|
|
80
|
-
? `${baseUrl}/
|
|
88
|
+
? `${baseUrl}/auth/models` // Proxy routes to /api/ai/auth/models
|
|
81
89
|
: isPublicApi
|
|
82
|
-
? `${baseUrl}/
|
|
90
|
+
? `${baseUrl}/gateway-models` // → /api/public/v1/gateway-models
|
|
83
91
|
: baseUrl
|
|
84
|
-
? `${baseUrl}/auth/
|
|
85
|
-
: `/api/ai/auth/
|
|
92
|
+
? `${baseUrl}/auth/models` // → /api/ai/auth/models
|
|
93
|
+
: `/api/ai/auth/models`; // fallback
|
|
86
94
|
|
|
87
95
|
console.log(
|
|
88
96
|
"[getAvailableModels] isExternalProxy:",
|
|
@@ -96,7 +104,7 @@ export async function getAvailableModels(
|
|
|
96
104
|
const headers: Record<string, string> = {};
|
|
97
105
|
|
|
98
106
|
// Ajouter la clé API pour les appels publics directs
|
|
99
|
-
if (isPublicApi && apiKey) {
|
|
107
|
+
if (isPublicApi && isAuthTokenCandidate(apiKey)) {
|
|
100
108
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
101
109
|
}
|
|
102
110
|
|
|
@@ -113,7 +121,16 @@ export async function getAvailableModels(
|
|
|
113
121
|
}
|
|
114
122
|
|
|
115
123
|
const data = await response.json();
|
|
116
|
-
|
|
124
|
+
|
|
125
|
+
if (Array.isArray(data?.models)) {
|
|
126
|
+
return data.models;
|
|
127
|
+
}
|
|
128
|
+
if (Array.isArray(data?.providers)) {
|
|
129
|
+
return data.providers.flatMap((provider: any) =>
|
|
130
|
+
Array.isArray(provider.models) ? provider.models : []
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
return [];
|
|
117
134
|
}
|
|
118
135
|
|
|
119
136
|
/**
|
|
@@ -148,7 +165,7 @@ export async function getUserModels(
|
|
|
148
165
|
const headers: Record<string, string> = {};
|
|
149
166
|
|
|
150
167
|
// Ajouter la clé API pour tous les types d'appels si disponible
|
|
151
|
-
if (apiKey) {
|
|
168
|
+
if (isAuthTokenCandidate(apiKey)) {
|
|
152
169
|
if (isPublicApi) {
|
|
153
170
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
154
171
|
} else {
|