@lastbrain/ai-ui-react 1.0.78 → 1.0.80
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/AiContextButton.d.ts.map +1 -1
- package/dist/components/AiContextButton.js +12 -6
- package/dist/components/AiImageButton.d.ts.map +1 -1
- package/dist/components/AiImageButton.js +11 -5
- package/dist/components/AiInput.js +4 -4
- package/dist/components/AiPromptPanel.d.ts +2 -0
- package/dist/components/AiPromptPanel.d.ts.map +1 -1
- package/dist/components/AiPromptPanel.js +138 -5
- package/dist/components/AiSelect.js +4 -4
- package/dist/components/AiStatusButton.js +3 -3
- package/dist/components/AiTextarea.d.ts.map +1 -1
- package/dist/components/AiTextarea.js +15 -4
- package/dist/components/LBApiKeySelector.d.ts.map +1 -1
- package/dist/components/LBApiKeySelector.js +12 -2
- package/dist/components/UsageToast.js +1 -1
- package/dist/context/LBAuthProvider.d.ts +3 -1
- package/dist/context/LBAuthProvider.d.ts.map +1 -1
- package/dist/context/LBAuthProvider.js +65 -29
- package/dist/styles.css +6 -4
- package/package.json +1 -1
- package/src/components/AiContextButton.tsx +14 -6
- package/src/components/AiImageButton.tsx +12 -6
- package/src/components/AiInput.tsx +4 -4
- package/src/components/AiPromptPanel.tsx +279 -12
- package/src/components/AiSelect.tsx +4 -4
- package/src/components/AiStatusButton.tsx +3 -3
- package/src/components/AiTextarea.tsx +16 -5
- package/src/components/LBApiKeySelector.tsx +14 -2
- package/src/components/UsageToast.tsx +1 -1
- package/src/context/LBAuthProvider.tsx +84 -30
- package/src/styles.css +6 -4
|
@@ -7,6 +7,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
7
7
|
import { createContext, useContext, useEffect, useCallback, useMemo, useRef, useState, } from "react";
|
|
8
8
|
import { createLBClient } from "@lastbrain/ai-ui-core";
|
|
9
9
|
import { I18nProvider } from "./I18nContext";
|
|
10
|
+
function hasServerSelectedApiKeyCookie(userData) {
|
|
11
|
+
if (!userData || typeof userData !== "object")
|
|
12
|
+
return false;
|
|
13
|
+
const value = userData.hasApiKeySelectedCookie;
|
|
14
|
+
return value === true;
|
|
15
|
+
}
|
|
10
16
|
const LBContext = createContext(undefined);
|
|
11
17
|
// Export pour usage dans d'autres composants
|
|
12
18
|
export { LBContext };
|
|
@@ -24,15 +30,6 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
24
30
|
const [storageLastFetch, setStorageLastFetch] = useState(0);
|
|
25
31
|
const [hasSelectedApiKeyCookie, setHasSelectedApiKeyCookie] = useState(false);
|
|
26
32
|
const previousStatusRef = useRef("loading");
|
|
27
|
-
const syncSelectedApiKeyCookie = useCallback(() => {
|
|
28
|
-
if (typeof document === "undefined")
|
|
29
|
-
return;
|
|
30
|
-
const hasCookie = document.cookie
|
|
31
|
-
.split(";")
|
|
32
|
-
.map((part) => part.trim())
|
|
33
|
-
.some((part) => part.startsWith("api_key_selected=") && part.length > 17);
|
|
34
|
-
setHasSelectedApiKeyCookie(hasCookie);
|
|
35
|
-
}, []);
|
|
36
33
|
const lbClient = useMemo(() => createLBClient({
|
|
37
34
|
baseUrl: proxyUrl,
|
|
38
35
|
mode: process.env.LB_API_KEY ? "env-key" : "auto",
|
|
@@ -46,6 +43,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
46
43
|
const session = await lbClient.verifySession();
|
|
47
44
|
if (session) {
|
|
48
45
|
const userData = await lbClient.getUser().catch(() => null);
|
|
46
|
+
const hasCookie = hasServerSelectedApiKeyCookie(userData);
|
|
49
47
|
const activeKey = userData?.apiKeyActive
|
|
50
48
|
? {
|
|
51
49
|
id: userData.apiKeyActive.id,
|
|
@@ -64,14 +62,16 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
64
62
|
id: session.userId,
|
|
65
63
|
email: userData?.user?.email || "",
|
|
66
64
|
},
|
|
67
|
-
selectedKey: activeKey,
|
|
65
|
+
selectedKey: hasCookie ? activeKey : undefined,
|
|
68
66
|
});
|
|
67
|
+
setHasSelectedApiKeyCookie(hasCookie);
|
|
69
68
|
onStatusChange?.("ready");
|
|
70
69
|
}
|
|
71
70
|
else {
|
|
72
71
|
// Supabase session mode (no lb_session cookie): try user endpoint directly
|
|
73
72
|
const userData = await lbClient.getUser().catch(() => null);
|
|
74
73
|
if (userData?.user?.id) {
|
|
74
|
+
const hasCookie = hasServerSelectedApiKeyCookie(userData);
|
|
75
75
|
const activeKey = userData?.apiKeyActive
|
|
76
76
|
? {
|
|
77
77
|
id: userData.apiKeyActive.id,
|
|
@@ -89,12 +89,14 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
89
89
|
id: userData.user.id,
|
|
90
90
|
email: userData.user.email || "",
|
|
91
91
|
},
|
|
92
|
-
selectedKey: activeKey,
|
|
92
|
+
selectedKey: hasCookie ? activeKey : undefined,
|
|
93
93
|
});
|
|
94
|
+
setHasSelectedApiKeyCookie(hasCookie);
|
|
94
95
|
onStatusChange?.("ready");
|
|
95
96
|
}
|
|
96
97
|
else {
|
|
97
98
|
setState({ status: "needs_auth" });
|
|
99
|
+
setHasSelectedApiKeyCookie(false);
|
|
98
100
|
onStatusChange?.("needs_auth");
|
|
99
101
|
}
|
|
100
102
|
}
|
|
@@ -102,19 +104,42 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
102
104
|
catch (error) {
|
|
103
105
|
console.error("[LBProvider] Session check failed:", error);
|
|
104
106
|
setState({ status: "needs_auth" });
|
|
107
|
+
setHasSelectedApiKeyCookie(false);
|
|
105
108
|
onStatusChange?.("needs_auth");
|
|
106
109
|
}
|
|
107
110
|
}, [lbClient, onStatusChange]);
|
|
108
111
|
useEffect(() => {
|
|
109
112
|
checkSession();
|
|
110
113
|
}, [checkSession]);
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
const fetchWalletSummary = useCallback(async () => {
|
|
115
|
+
const headers = lbClient.getAuthHeaders(state.session?.sessionToken);
|
|
116
|
+
const walletUrls = Array.from(new Set([
|
|
117
|
+
`${proxyUrl}/auth/wallet`,
|
|
118
|
+
`${proxyUrl.replace("/api/lastbrain", "/api/ai")}/auth/wallet`,
|
|
119
|
+
]));
|
|
120
|
+
for (const url of walletUrls) {
|
|
121
|
+
try {
|
|
122
|
+
const response = await fetch(url, {
|
|
123
|
+
method: "GET",
|
|
124
|
+
credentials: "include",
|
|
125
|
+
headers,
|
|
126
|
+
});
|
|
127
|
+
if (!response.ok)
|
|
128
|
+
continue;
|
|
129
|
+
const data = (await response.json());
|
|
130
|
+
return {
|
|
131
|
+
used: Number(data.totalUsed || 0),
|
|
132
|
+
total: Number(data.totalAdded || 0),
|
|
133
|
+
percentage: Number(data.percentUsed ?? data.percentage ?? 0),
|
|
134
|
+
remaining: Number(data.walletSellValueUsd || 0),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// try next endpoint
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}, [lbClient, proxyUrl, state.session?.sessionToken]);
|
|
118
143
|
/**
|
|
119
144
|
* Récupère les clés API de l'utilisateur
|
|
120
145
|
*/
|
|
@@ -153,7 +178,6 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
153
178
|
setAccessToken(undefined); // Nettoyer l'access token temporaire
|
|
154
179
|
setApiKeys([]); // Nettoyer les clés API temporaires
|
|
155
180
|
setHasSelectedApiKeyCookie(true);
|
|
156
|
-
setTimeout(() => syncSelectedApiKeyCookie(), 100);
|
|
157
181
|
onStatusChange?.("ready");
|
|
158
182
|
onAuthChange?.(); // Refresh provider after signin
|
|
159
183
|
}
|
|
@@ -165,7 +189,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
165
189
|
});
|
|
166
190
|
throw error;
|
|
167
191
|
}
|
|
168
|
-
}, [lbClient, onAuthChange, onStatusChange, state.user
|
|
192
|
+
}, [lbClient, onAuthChange, onStatusChange, state.user]);
|
|
169
193
|
/**
|
|
170
194
|
* Connexion utilisateur (étape 1 : login)
|
|
171
195
|
* Retourne le token et les clés API sans créer de session
|
|
@@ -273,16 +297,20 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
273
297
|
used: 0,
|
|
274
298
|
total: userData.balance?.sellValueUsd || 0,
|
|
275
299
|
percentage: 0,
|
|
300
|
+
remaining: userData.balance?.sellValueUsd || 0,
|
|
276
301
|
},
|
|
277
302
|
};
|
|
278
303
|
}
|
|
304
|
+
const userData = await lbClient.getUser().catch(() => null);
|
|
305
|
+
setHasSelectedApiKeyCookie(hasServerSelectedApiKeyCookie(userData));
|
|
306
|
+
const walletSummary = await fetchWalletSummary().catch(() => null);
|
|
279
307
|
const normalizedStatus = {
|
|
280
308
|
...data,
|
|
281
309
|
authType: data?.authType,
|
|
282
|
-
user: data?.user,
|
|
283
|
-
apiKey: data?.apiKey || data?.api_key,
|
|
284
|
-
api_key: data?.api_key || data?.apiKey,
|
|
285
|
-
balance: data?.balance || {
|
|
310
|
+
user: data?.user || userData?.user,
|
|
311
|
+
apiKey: data?.apiKey || data?.api_key || userData?.apiKeyActive,
|
|
312
|
+
api_key: data?.api_key || data?.apiKey || userData?.apiKeyActive,
|
|
313
|
+
balance: walletSummary || data?.balance || {
|
|
286
314
|
used: 0,
|
|
287
315
|
total: 0,
|
|
288
316
|
percentage: 0,
|
|
@@ -302,7 +330,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
302
330
|
finally {
|
|
303
331
|
setIsLoadingStatus(false);
|
|
304
332
|
}
|
|
305
|
-
}, [lbClient, state.status, storageStatus]);
|
|
333
|
+
}, [fetchWalletSummary, lbClient, state.status, storageStatus]);
|
|
306
334
|
/**
|
|
307
335
|
* Récupère le storage - LENT avec cache (5 minutes)
|
|
308
336
|
*/
|
|
@@ -380,9 +408,11 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
380
408
|
}));
|
|
381
409
|
}
|
|
382
410
|
setHasSelectedApiKeyCookie(true);
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
setTimeout(() =>
|
|
411
|
+
// Ne pas bloquer la validation UI de sélection sur des requêtes status/wallet/storage.
|
|
412
|
+
void refreshBasicStatus();
|
|
413
|
+
setTimeout(() => {
|
|
414
|
+
void refreshStorageStatus();
|
|
415
|
+
}, 100);
|
|
386
416
|
}
|
|
387
417
|
else {
|
|
388
418
|
throw new Error("No valid authentication method available");
|
|
@@ -395,7 +425,6 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
395
425
|
lbClient,
|
|
396
426
|
refreshBasicStatus,
|
|
397
427
|
refreshStorageStatus,
|
|
398
|
-
syncSelectedApiKeyCookie,
|
|
399
428
|
]);
|
|
400
429
|
/**
|
|
401
430
|
* Déconnexion
|
|
@@ -444,6 +473,13 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
444
473
|
setApiKeys([]);
|
|
445
474
|
}
|
|
446
475
|
}, [lbClient, state.status]);
|
|
476
|
+
useEffect(() => {
|
|
477
|
+
if (state.status !== "ready" || !state.session)
|
|
478
|
+
return;
|
|
479
|
+
if (hasSelectedApiKeyCookie)
|
|
480
|
+
return;
|
|
481
|
+
setState((prev) => ({ ...prev, selectedKey: undefined }));
|
|
482
|
+
}, [hasSelectedApiKeyCookie, state.session, state.status]);
|
|
447
483
|
// Refresh status uniquement lors de la transition vers "ready"
|
|
448
484
|
// (évite les boucles status/user causées par des callbacks recréés)
|
|
449
485
|
useEffect(() => {
|
package/dist/styles.css
CHANGED
|
@@ -310,7 +310,7 @@
|
|
|
310
310
|
min-height: 96px;
|
|
311
311
|
resize: none;
|
|
312
312
|
overflow: hidden;
|
|
313
|
-
padding: 6px 2px
|
|
313
|
+
padding: 6px 2px 32px;
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
.ai-control[aria-invalid="true"],
|
|
@@ -641,7 +641,7 @@
|
|
|
641
641
|
|
|
642
642
|
.ai-status-tooltip {
|
|
643
643
|
width: min(370px, calc(100vw - 16px));
|
|
644
|
-
z-index:
|
|
644
|
+
z-index: 2147483646;
|
|
645
645
|
}
|
|
646
646
|
|
|
647
647
|
.ai-status-actions {
|
|
@@ -685,7 +685,7 @@
|
|
|
685
685
|
white-space: nowrap;
|
|
686
686
|
opacity: 0;
|
|
687
687
|
pointer-events: none;
|
|
688
|
-
z-index:
|
|
688
|
+
z-index: 2147483646;
|
|
689
689
|
padding: 4px 8px;
|
|
690
690
|
border-radius: 8px;
|
|
691
691
|
border: 1px solid var(--ai-border);
|
|
@@ -772,7 +772,7 @@
|
|
|
772
772
|
[data-ai-settings-panel] {
|
|
773
773
|
position: fixed;
|
|
774
774
|
inset: 0;
|
|
775
|
-
z-index:
|
|
775
|
+
z-index: 2147483647;
|
|
776
776
|
display: flex;
|
|
777
777
|
align-items: center;
|
|
778
778
|
justify-content: center;
|
|
@@ -1109,6 +1109,8 @@
|
|
|
1109
1109
|
|
|
1110
1110
|
.ai-key-modal-panel {
|
|
1111
1111
|
max-width: 520px;
|
|
1112
|
+
position: relative;
|
|
1113
|
+
z-index: 2147483647;
|
|
1112
1114
|
}
|
|
1113
1115
|
|
|
1114
1116
|
.ai-key-radio {
|
package/package.json
CHANGED
|
@@ -84,20 +84,19 @@ export function AiContextButton({
|
|
|
84
84
|
|
|
85
85
|
let lbStatus: string | undefined;
|
|
86
86
|
let lbHasSession = false;
|
|
87
|
-
let lbHasSelectedKey = false;
|
|
88
87
|
let lbHasSelectedApiKeyCookie = false;
|
|
88
|
+
let lbHasSelectedKey = false;
|
|
89
89
|
let hasLBProvider = false;
|
|
90
90
|
try {
|
|
91
91
|
const lbContext = useLB();
|
|
92
92
|
lbStatus = lbContext.status;
|
|
93
93
|
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
94
|
-
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
95
94
|
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
95
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
96
96
|
hasLBProvider = true;
|
|
97
97
|
} catch {
|
|
98
98
|
lbStatus = undefined;
|
|
99
99
|
lbHasSession = false;
|
|
100
|
-
lbHasSelectedKey = false;
|
|
101
100
|
hasLBProvider = false;
|
|
102
101
|
}
|
|
103
102
|
|
|
@@ -114,7 +113,8 @@ export function AiContextButton({
|
|
|
114
113
|
hasLBProvider &&
|
|
115
114
|
lbStatus === "ready" &&
|
|
116
115
|
lbHasSession &&
|
|
117
|
-
|
|
116
|
+
!lbHasSelectedApiKeyCookie &&
|
|
117
|
+
!lbHasSelectedKey;
|
|
118
118
|
const isAuthReady =
|
|
119
119
|
!needsApiKeySelection &&
|
|
120
120
|
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
@@ -250,8 +250,14 @@ export function AiContextButton({
|
|
|
250
250
|
<div className="relative inline-block ai-glow">
|
|
251
251
|
<button
|
|
252
252
|
{...buttonProps}
|
|
253
|
-
onClick={
|
|
254
|
-
|
|
253
|
+
onClick={() => {
|
|
254
|
+
if (!isAuthReady) {
|
|
255
|
+
setShowAuthModal(true);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
handleOpenPanel();
|
|
259
|
+
}}
|
|
260
|
+
disabled={disabled || loading}
|
|
255
261
|
className={`ai-btn ai-context-btn ${variantClass} ${sizeClass} ${radiusClass} ${className || ""}`}
|
|
256
262
|
title={
|
|
257
263
|
!isAuthReady
|
|
@@ -292,6 +298,8 @@ export function AiContextButton({
|
|
|
292
298
|
modelCategory="text"
|
|
293
299
|
baseUrl={baseUrl}
|
|
294
300
|
apiKey={apiKeyId}
|
|
301
|
+
contextPreview={formatContextData(contextData)}
|
|
302
|
+
contextPreviewTitle={resolvedContextDescription}
|
|
295
303
|
/>
|
|
296
304
|
) : null}
|
|
297
305
|
</div>
|
|
@@ -80,21 +80,20 @@ export function AiImageButton({
|
|
|
80
80
|
// Rendre l'authentification optionnelle
|
|
81
81
|
let lbStatus: string | undefined;
|
|
82
82
|
let lbHasSession = false;
|
|
83
|
-
let lbHasSelectedKey = false;
|
|
84
83
|
let lbHasSelectedApiKeyCookie = false;
|
|
84
|
+
let lbHasSelectedKey = false;
|
|
85
85
|
let hasLBProvider = false;
|
|
86
86
|
try {
|
|
87
87
|
const lbContext = useLB();
|
|
88
88
|
lbStatus = lbContext.status;
|
|
89
89
|
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
90
|
-
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
91
90
|
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
91
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
92
92
|
hasLBProvider = true;
|
|
93
93
|
} catch {
|
|
94
94
|
// LBProvider n'est pas disponible, ignorer
|
|
95
95
|
lbStatus = undefined;
|
|
96
96
|
lbHasSession = false;
|
|
97
|
-
lbHasSelectedKey = false;
|
|
98
97
|
hasLBProvider = false;
|
|
99
98
|
}
|
|
100
99
|
|
|
@@ -110,7 +109,8 @@ export function AiImageButton({
|
|
|
110
109
|
hasLBProvider &&
|
|
111
110
|
lbStatus === "ready" &&
|
|
112
111
|
lbHasSession &&
|
|
113
|
-
|
|
112
|
+
!lbHasSelectedApiKeyCookie &&
|
|
113
|
+
!lbHasSelectedKey;
|
|
114
114
|
const isAuthReady =
|
|
115
115
|
!needsApiKeySelection &&
|
|
116
116
|
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|
|
@@ -229,8 +229,14 @@ export function AiImageButton({
|
|
|
229
229
|
<div className="relative inline-block ai-glow">
|
|
230
230
|
<button
|
|
231
231
|
{...buttonProps}
|
|
232
|
-
onClick={
|
|
233
|
-
|
|
232
|
+
onClick={() => {
|
|
233
|
+
if (!isAuthReady) {
|
|
234
|
+
setShowAuthModal(true);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
handleOpenPanel();
|
|
238
|
+
}}
|
|
239
|
+
disabled={disabled || loading}
|
|
234
240
|
className={`ai-btn ai-image-btn ${variantClass} ${sizeClass} ${radiusClass} ${className || ""}`}
|
|
235
241
|
style={buttonProps.style}
|
|
236
242
|
data-ai-image-button
|
|
@@ -61,21 +61,20 @@ export function AiInput({
|
|
|
61
61
|
// Rendre l'authentification optionnelle
|
|
62
62
|
let lbStatus: string | undefined;
|
|
63
63
|
let lbHasSession = false;
|
|
64
|
-
let lbHasSelectedKey = false;
|
|
65
64
|
let lbHasSelectedApiKeyCookie = false;
|
|
65
|
+
let lbHasSelectedKey = false;
|
|
66
66
|
let hasLBProvider = false;
|
|
67
67
|
try {
|
|
68
68
|
const lbContext = useLB();
|
|
69
69
|
lbStatus = lbContext.status;
|
|
70
70
|
lbHasSession = Boolean(lbContext.session?.sessionToken);
|
|
71
|
-
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
72
71
|
lbHasSelectedApiKeyCookie = lbContext.hasSelectedApiKeyCookie;
|
|
72
|
+
lbHasSelectedKey = Boolean(lbContext.selectedKey?.id);
|
|
73
73
|
hasLBProvider = true;
|
|
74
74
|
} catch {
|
|
75
75
|
// LBProvider n'est pas disponible, ignorer
|
|
76
76
|
lbStatus = undefined;
|
|
77
77
|
lbHasSession = false;
|
|
78
|
-
lbHasSelectedKey = false;
|
|
79
78
|
hasLBProvider = false;
|
|
80
79
|
}
|
|
81
80
|
|
|
@@ -106,7 +105,8 @@ export function AiInput({
|
|
|
106
105
|
hasLBProvider &&
|
|
107
106
|
lbStatus === "ready" &&
|
|
108
107
|
lbHasSession &&
|
|
109
|
-
|
|
108
|
+
!lbHasSelectedApiKeyCookie &&
|
|
109
|
+
!lbHasSelectedKey;
|
|
110
110
|
const isAuthReady =
|
|
111
111
|
!needsApiKeySelection &&
|
|
112
112
|
(lbStatus === "ready" || Boolean(process.env.LB_API_KEY));
|