@lastbrain/ai-ui-core 1.0.28 → 1.0.30

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.
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Client LastBrain intelligent
3
+ * Supporte deux modes d'authentification :
4
+ * - env-key : utilise LB_API_KEY (côté serveur)
5
+ * - session : utilise cookie lb_session (user authentifié)
6
+ */
7
+ import type { LBAuthConfig, LBSession, LBLoginResult, LBApiKey, LBSessionResult } from "../types/auth";
8
+ export declare class LBClient {
9
+ private config;
10
+ constructor(config?: LBAuthConfig);
11
+ /**
12
+ * Détecte le mode d'authentification à utiliser
13
+ */
14
+ private getAuthMode;
15
+ /**
16
+ * Construit les headers d'authentification
17
+ */
18
+ private getAuthHeaders;
19
+ /**
20
+ * Fait une requête à l'API LastBrain
21
+ */
22
+ private request;
23
+ /**
24
+ * Login utilisateur (email + password)
25
+ * Retourne un access_token temporaire pour récupérer les clés API
26
+ */
27
+ login(email: string, password: string): Promise<LBLoginResult>;
28
+ /**
29
+ * Récupère les clés API de l'utilisateur
30
+ */
31
+ getUserApiKeys(accessToken: string): Promise<LBApiKey[]>;
32
+ /**
33
+ * Crée une session (72h) avec une clé API sélectionnée
34
+ */
35
+ createSession(accessToken: string, apiKeyId: string): Promise<LBSessionResult>;
36
+ /**
37
+ * Vérifie si une session est valide
38
+ */
39
+ verifySession(sessionToken: string): Promise<LBSession | null>;
40
+ /**
41
+ * Déconnexion (invalide la session)
42
+ */
43
+ logout(sessionToken: string): Promise<void>;
44
+ /**
45
+ * Fait un appel IA (génération de texte)
46
+ */
47
+ generateText(params: {
48
+ prompt: string;
49
+ model?: string;
50
+ sessionToken?: string;
51
+ [key: string]: any;
52
+ }): Promise<any>;
53
+ /**
54
+ * Fait un appel IA (génération d'image)
55
+ */
56
+ generateImage(params: {
57
+ prompt: string;
58
+ model?: string;
59
+ sessionToken?: string;
60
+ [key: string]: any;
61
+ }): Promise<any>;
62
+ }
63
+ /**
64
+ * Factory pour créer un client LastBrain
65
+ */
66
+ export declare function createLBClient(config?: LBAuthConfig): LBClient;
67
+ //# sourceMappingURL=lb-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lb-client.d.ts","sourceRoot":"","sources":["../../src/client/lb-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EAET,aAAa,EACb,QAAQ,EACR,eAAe,EAChB,MAAM,eAAe,CAAC;AAEvB,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAyB;gBAE3B,MAAM,GAAE,YAAiB;IAWrC;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;YACW,cAAc;IAsB5B;;OAEG;YACW,OAAO;IAyCrB;;;OAGG;IACG,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAOpE;;OAEG;IACG,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAQ9D;;OAEG;IACG,aAAa,CACjB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,CAAC;IAU3B;;OAEG;IACG,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAYpE;;OAEG;IACG,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASjD;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE;QACzB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,GAAG,OAAO,CAAC,GAAG,CAAC;IAWhB;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE;QAC1B,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,GAAG,OAAO,CAAC,GAAG,CAAC;CAUjB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,QAAQ,CAE9D"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Client LastBrain intelligent
3
+ * Supporte deux modes d'authentification :
4
+ * - env-key : utilise LB_API_KEY (côté serveur)
5
+ * - session : utilise cookie lb_session (user authentifié)
6
+ */
7
+ export class LBClient {
8
+ config;
9
+ constructor(config = {}) {
10
+ this.config = {
11
+ baseUrl: config.baseUrl ||
12
+ process.env.LB_BASE_URL ||
13
+ "https://prompt.lastbrain.io",
14
+ apiKey: config.apiKey || process.env.LB_API_KEY || "",
15
+ mode: config.mode || "auto",
16
+ };
17
+ }
18
+ /**
19
+ * Détecte le mode d'authentification à utiliser
20
+ */
21
+ getAuthMode() {
22
+ if (this.config.mode === "env-key")
23
+ return "env-key";
24
+ if (this.config.mode === "session")
25
+ return "session";
26
+ // Mode auto : préfère env-key si disponible
27
+ return this.config.apiKey ? "env-key" : "session";
28
+ }
29
+ /**
30
+ * Construit les headers d'authentification
31
+ */
32
+ async getAuthHeaders(sessionToken) {
33
+ const mode = this.getAuthMode();
34
+ if (mode === "env-key" && this.config.apiKey) {
35
+ return {
36
+ Authorization: `Bearer ${this.config.apiKey}`,
37
+ };
38
+ }
39
+ // Mode session : utilise le token fourni ou tente de lire le cookie
40
+ if (sessionToken) {
41
+ return {
42
+ Authorization: `Bearer ${sessionToken}`,
43
+ };
44
+ }
45
+ // Si aucun token fourni, la requête échouera (attendu pour déclencher auth)
46
+ return {};
47
+ }
48
+ /**
49
+ * Fait une requête à l'API LastBrain
50
+ */
51
+ async request(endpoint, options = {}) {
52
+ const { baseUrl, headers: customHeaders, timeout, ...fetchOptions } = options;
53
+ const url = `${baseUrl || this.config.baseUrl}${endpoint}`;
54
+ const authHeaders = await this.getAuthHeaders();
55
+ const controller = new AbortController();
56
+ const timeoutId = timeout
57
+ ? setTimeout(() => controller.abort(), timeout)
58
+ : undefined;
59
+ try {
60
+ const response = await fetch(url, {
61
+ ...fetchOptions,
62
+ headers: {
63
+ "Content-Type": "application/json",
64
+ ...authHeaders,
65
+ ...customHeaders,
66
+ },
67
+ signal: controller.signal,
68
+ });
69
+ if (!response.ok) {
70
+ const error = await response.json().catch(() => ({}));
71
+ throw new Error(error.message || `HTTP ${response.status}`);
72
+ }
73
+ return await response.json();
74
+ }
75
+ finally {
76
+ if (timeoutId)
77
+ clearTimeout(timeoutId);
78
+ }
79
+ }
80
+ /**
81
+ * Login utilisateur (email + password)
82
+ * Retourne un access_token temporaire pour récupérer les clés API
83
+ */
84
+ async login(email, password) {
85
+ return this.request("/auth/login", {
86
+ method: "POST",
87
+ body: JSON.stringify({ email, password }),
88
+ });
89
+ }
90
+ /**
91
+ * Récupère les clés API de l'utilisateur
92
+ */
93
+ async getUserApiKeys(accessToken) {
94
+ return this.request("/user/api-keys", {
95
+ headers: {
96
+ Authorization: `Bearer ${accessToken}`,
97
+ },
98
+ });
99
+ }
100
+ /**
101
+ * Crée une session (72h) avec une clé API sélectionnée
102
+ */
103
+ async createSession(accessToken, apiKeyId) {
104
+ return this.request("/auth/session", {
105
+ method: "POST",
106
+ headers: {
107
+ Authorization: `Bearer ${accessToken}`,
108
+ },
109
+ body: JSON.stringify({ api_key_id: apiKeyId }),
110
+ });
111
+ }
112
+ /**
113
+ * Vérifie si une session est valide
114
+ */
115
+ async verifySession(sessionToken) {
116
+ try {
117
+ return await this.request("/auth/session/verify", {
118
+ headers: {
119
+ Authorization: `Bearer ${sessionToken}`,
120
+ },
121
+ });
122
+ }
123
+ catch {
124
+ return null;
125
+ }
126
+ }
127
+ /**
128
+ * Déconnexion (invalide la session)
129
+ */
130
+ async logout(sessionToken) {
131
+ await this.request("/auth/session/logout", {
132
+ method: "POST",
133
+ headers: {
134
+ Authorization: `Bearer ${sessionToken}`,
135
+ },
136
+ });
137
+ }
138
+ /**
139
+ * Fait un appel IA (génération de texte)
140
+ */
141
+ async generateText(params) {
142
+ const { sessionToken, ...body } = params;
143
+ const headers = await this.getAuthHeaders(sessionToken);
144
+ return this.request("/ai/generate-text", {
145
+ method: "POST",
146
+ headers,
147
+ body: JSON.stringify(body),
148
+ });
149
+ }
150
+ /**
151
+ * Fait un appel IA (génération d'image)
152
+ */
153
+ async generateImage(params) {
154
+ const { sessionToken, ...body } = params;
155
+ const headers = await this.getAuthHeaders(sessionToken);
156
+ return this.request("/ai/generate-image", {
157
+ method: "POST",
158
+ headers,
159
+ body: JSON.stringify(body),
160
+ });
161
+ }
162
+ }
163
+ /**
164
+ * Factory pour créer un client LastBrain
165
+ */
166
+ export function createLBClient(config) {
167
+ return new LBClient(config);
168
+ }
package/dist/index.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  export * from "./types";
2
+ export * from "./types/auth";
2
3
  export * from "./errors/errorCodes";
3
4
  export * from "./errors/normalizeError";
4
5
  export * from "./client/createClient";
6
+ export * from "./client/lb-client";
5
7
  export * from "./route-handlers/nextjs/gateway";
6
8
  export { GET as EnhancedGET, POST as EnhancedPOST, PUT as EnhancedPUT, } from "./route-handlers/nextjs/enhanced-gateway";
7
9
  export * as enhancedGateway from "./route-handlers/nextjs/enhanced-gateway";
10
+ export * from "./route-handlers/nextjs/lb-proxy";
8
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,iCAAiC,CAAC;AAChD,OAAO,EACL,GAAG,IAAI,WAAW,EAClB,IAAI,IAAI,YAAY,EACpB,GAAG,IAAI,WAAW,GACnB,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,eAAe,MAAM,0CAA0C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,iCAAiC,CAAC;AAChD,OAAO,EACL,GAAG,IAAI,WAAW,EAClB,IAAI,IAAI,YAAY,EACpB,GAAG,IAAI,WAAW,GACnB,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,eAAe,MAAM,0CAA0C,CAAC;AAC5E,cAAc,kCAAkC,CAAC"}
package/dist/index.js CHANGED
@@ -1,8 +1,11 @@
1
1
  export * from "./types";
2
+ export * from "./types/auth";
2
3
  export * from "./errors/errorCodes";
3
4
  export * from "./errors/normalizeError";
4
5
  export * from "./client/createClient";
6
+ export * from "./client/lb-client";
5
7
  // Route handlers
6
8
  export * from "./route-handlers/nextjs/gateway";
7
9
  export { GET as EnhancedGET, POST as EnhancedPOST, PUT as EnhancedPUT, } from "./route-handlers/nextjs/enhanced-gateway";
8
10
  export * as enhancedGateway from "./route-handlers/nextjs/enhanced-gateway";
11
+ export * from "./route-handlers/nextjs/lb-proxy";
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Proxy handler pour Next.js App Router
3
+ * Permet de faire des appels IA LastBrain depuis le serveur
4
+ * avec support de LB_API_KEY ou session cookie
5
+ */
6
+ import { NextRequest, NextResponse } from "next/server";
7
+ /**
8
+ * Configuration du proxy LastBrain
9
+ */
10
+ export interface LBProxyConfig {
11
+ /** URL de base de l'API LastBrain */
12
+ baseUrl?: string;
13
+ /** Clé API LastBrain (optionnel, peut utiliser env) */
14
+ apiKey?: string;
15
+ /** Nom du cookie de session */
16
+ sessionCookieName?: string;
17
+ }
18
+ /**
19
+ * Crée un handler de proxy unifié pour Next.js App Router
20
+ *
21
+ * Usage:
22
+ * ```typescript
23
+ * // app/api/lastbrain/[...path]/route.ts
24
+ * import { createLBProxyHandler } from "@lastbrain/ai-ui-core";
25
+ *
26
+ * export const { GET, POST, PUT, DELETE, PATCH } = createLBProxyHandler({
27
+ * baseUrl: process.env.LB_BASE_URL,
28
+ * });
29
+ * ```
30
+ */
31
+ export declare function createLBProxyHandler(config?: LBProxyConfig): {
32
+ GET: (request: NextRequest, context?: {
33
+ params: Promise<{
34
+ path?: string[];
35
+ }>;
36
+ }) => Promise<NextResponse>;
37
+ POST: (request: NextRequest, context?: {
38
+ params: Promise<{
39
+ path?: string[];
40
+ }>;
41
+ }) => Promise<NextResponse>;
42
+ PUT: (request: NextRequest, context?: {
43
+ params: Promise<{
44
+ path?: string[];
45
+ }>;
46
+ }) => Promise<NextResponse>;
47
+ DELETE: (request: NextRequest, context?: {
48
+ params: Promise<{
49
+ path?: string[];
50
+ }>;
51
+ }) => Promise<NextResponse>;
52
+ PATCH: (request: NextRequest, context?: {
53
+ params: Promise<{
54
+ path?: string[];
55
+ }>;
56
+ }) => Promise<NextResponse>;
57
+ };
58
+ /**
59
+ * Helper pour ajouter ou mettre à jour le cookie de session
60
+ */
61
+ export declare function setLBSessionCookie(response: NextResponse, sessionToken: string, expiresIn?: number): NextResponse;
62
+ /**
63
+ * Helper pour supprimer le cookie de session
64
+ */
65
+ export declare function clearLBSessionCookie(response: NextResponse): NextResponse;
66
+ //# sourceMappingURL=lb-proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lb-proxy.d.ts","sourceRoot":"","sources":["../../../src/route-handlers/nextjs/lb-proxy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,aAAkB;mBAWlD,WAAW,YACV;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE,KACjD,OAAO,CAAC,YAAY,CAAC;oBAFb,WAAW,YACV;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE,KACjD,OAAO,CAAC,YAAY,CAAC;mBAFb,WAAW,YACV;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE,KACjD,OAAO,CAAC,YAAY,CAAC;sBAFb,WAAW,YACV;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE,KACjD,OAAO,CAAC,YAAY,CAAC;qBAFb,WAAW,YACV;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE,KACjD,OAAO,CAAC,YAAY,CAAC;EAiHzB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,YAAY,EACtB,YAAY,EAAE,MAAM,EACpB,SAAS,GAAE,MAAe,GACzB,YAAY,CAYd;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,YAAY,GAAG,YAAY,CAGzE"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Proxy handler pour Next.js App Router
3
+ * Permet de faire des appels IA LastBrain depuis le serveur
4
+ * avec support de LB_API_KEY ou session cookie
5
+ */
6
+ import { NextResponse } from "next/server";
7
+ /**
8
+ * Crée un handler de proxy unifié pour Next.js App Router
9
+ *
10
+ * Usage:
11
+ * ```typescript
12
+ * // app/api/lastbrain/[...path]/route.ts
13
+ * import { createLBProxyHandler } from "@lastbrain/ai-ui-core";
14
+ *
15
+ * export const { GET, POST, PUT, DELETE, PATCH } = createLBProxyHandler({
16
+ * baseUrl: process.env.LB_BASE_URL,
17
+ * });
18
+ * ```
19
+ */
20
+ export function createLBProxyHandler(config = {}) {
21
+ const { baseUrl = process.env.LB_BASE_URL || "https://lastbrain.io", apiKey = process.env.LB_API_KEY, sessionCookieName = "lb_session", } = config;
22
+ /**
23
+ * Handler unique pour toutes les méthodes HTTP et tous les paths
24
+ */
25
+ async function handler(request, context) {
26
+ try {
27
+ // Extraire le path depuis l'URL ou les params
28
+ let path = "";
29
+ if (context?.params) {
30
+ const resolvedParams = await context.params;
31
+ path = resolvedParams.path?.join("/") || "";
32
+ }
33
+ else {
34
+ // Fallback: extraire depuis l'URL
35
+ const url = new URL(request.url);
36
+ const pathMatch = url.pathname.match(/\/api\/lastbrain\/(.*)/);
37
+ path = pathMatch ? pathMatch[1] : "";
38
+ }
39
+ // Routes publiques qui ne nécessitent pas d'authentification
40
+ const publicPaths = [
41
+ "auth/login",
42
+ "auth/session/create",
43
+ "public/user/api-keys",
44
+ ];
45
+ const isPublicPath = publicPaths.some((p) => path.startsWith(p));
46
+ // Construire l'URL complète vers LastBrain
47
+ const targetUrl = `${baseUrl}/api/ai/${path}`;
48
+ // Préparer les headers
49
+ const headers = {};
50
+ // Copier les headers pertinents de la requête originale
51
+ const contentType = request.headers.get("content-type");
52
+ if (contentType) {
53
+ headers["Content-Type"] = contentType;
54
+ }
55
+ const authorization = request.headers.get("authorization");
56
+ if (authorization) {
57
+ headers["Authorization"] = authorization;
58
+ }
59
+ // Authentification : LB_API_KEY ou session cookie
60
+ if (!authorization) {
61
+ if (apiKey) {
62
+ headers["Authorization"] = `Bearer ${apiKey}`;
63
+ }
64
+ else {
65
+ // Lire le cookie de session
66
+ const sessionToken = request.cookies.get(sessionCookieName)?.value;
67
+ if (sessionToken) {
68
+ headers["Authorization"] = `Bearer ${sessionToken}`;
69
+ }
70
+ else if (!isPublicPath) {
71
+ // Pas d'auth disponible et route protégée
72
+ return NextResponse.json({
73
+ error: "No authentication provided",
74
+ hint: "Set LB_API_KEY env variable or login via /api/lastbrain/auth/login",
75
+ }, { status: 401 });
76
+ }
77
+ }
78
+ }
79
+ // Lire le body si c'est POST/PUT/PATCH
80
+ let body = undefined;
81
+ if (["POST", "PUT", "PATCH"].includes(request.method)) {
82
+ const text = await request.text();
83
+ if (text) {
84
+ body = text;
85
+ }
86
+ }
87
+ // Faire la requête au backend LastBrain
88
+ const response = await fetch(targetUrl, {
89
+ method: request.method,
90
+ headers,
91
+ body,
92
+ });
93
+ // Lire la réponse
94
+ const responseText = await response.text();
95
+ let data;
96
+ try {
97
+ data = responseText ? JSON.parse(responseText) : {};
98
+ }
99
+ catch {
100
+ data = { error: "Invalid JSON response", raw: responseText };
101
+ }
102
+ // Créer la réponse Next.js
103
+ const nextResponse = NextResponse.json(data, { status: response.status });
104
+ // Copier les cookies de la réponse (notamment lb_session)
105
+ const setCookie = response.headers.get("set-cookie");
106
+ if (setCookie) {
107
+ nextResponse.headers.set("set-cookie", setCookie);
108
+ }
109
+ return nextResponse;
110
+ }
111
+ catch (error) {
112
+ console.error("[LB Proxy] Error:", error);
113
+ return NextResponse.json({ error: error instanceof Error ? error.message : "Proxy error" }, { status: 500 });
114
+ }
115
+ }
116
+ // Retourner un objet avec les handlers pour chaque méthode HTTP
117
+ return {
118
+ GET: handler,
119
+ POST: handler,
120
+ PUT: handler,
121
+ DELETE: handler,
122
+ PATCH: handler,
123
+ };
124
+ }
125
+ /**
126
+ * Helper pour ajouter ou mettre à jour le cookie de session
127
+ */
128
+ export function setLBSessionCookie(response, sessionToken, expiresIn = 259200 // 72h en secondes
129
+ ) {
130
+ response.cookies.set({
131
+ name: "lb_session",
132
+ value: sessionToken,
133
+ httpOnly: true,
134
+ secure: process.env.NODE_ENV === "production",
135
+ sameSite: "lax",
136
+ path: "/",
137
+ maxAge: expiresIn,
138
+ });
139
+ return response;
140
+ }
141
+ /**
142
+ * Helper pour supprimer le cookie de session
143
+ */
144
+ export function clearLBSessionCookie(response) {
145
+ response.cookies.delete("lb_session");
146
+ return response;
147
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Types pour le système d'authentification LastBrain
3
+ * Permet l'utilisation des services IA avec LB_API_KEY ou session utilisateur
4
+ */
5
+ /**
6
+ * Configuration du client LastBrain
7
+ */
8
+ export interface LBAuthConfig {
9
+ /** URL de base de l'API LastBrain (ex: https://api.lastbrain.io) */
10
+ baseUrl?: string;
11
+ /** Clé API LastBrain (côté serveur uniquement) */
12
+ apiKey?: string;
13
+ /** Mode d'authentification */
14
+ mode?: "env-key" | "session" | "auto";
15
+ }
16
+ /**
17
+ * Session utilisateur LastBrain (stockée dans cookie HttpOnly)
18
+ */
19
+ export interface LBSession {
20
+ /** Token de session opaque signé côté serveur */
21
+ sessionToken: string;
22
+ /** ID utilisateur associé */
23
+ userId: string;
24
+ /** ID de la clé API sélectionnée */
25
+ apiKeyId: string;
26
+ /** Timestamp d'expiration (72h après création) */
27
+ expiresAt: number;
28
+ /** Scopes/permissions accordés */
29
+ scopes?: string[];
30
+ /** Quotas restants (optionnel) */
31
+ quotas?: {
32
+ tokens?: number;
33
+ requests?: number;
34
+ };
35
+ }
36
+ /**
37
+ * Informations utilisateur LastBrain
38
+ */
39
+ export interface LBUser {
40
+ id: string;
41
+ email: string;
42
+ name?: string;
43
+ avatar?: string;
44
+ }
45
+ /**
46
+ * Clé API LastBrain de l'utilisateur
47
+ */
48
+ export interface LBApiKey {
49
+ id: string;
50
+ name: string;
51
+ /** Préfixe visible de la clé (ex: "lb_live_abc...") */
52
+ keyPrefix: string;
53
+ scopes: string[];
54
+ isActive: boolean;
55
+ createdAt: string;
56
+ lastUsedAt?: string;
57
+ }
58
+ /**
59
+ * Résultat de connexion
60
+ */
61
+ export interface LBLoginResult {
62
+ /** Token d'accès temporaire pour récupérer les clés API */
63
+ accessToken: string;
64
+ /** Informations utilisateur */
65
+ user: LBUser;
66
+ }
67
+ /**
68
+ * Résultat de création de session
69
+ */
70
+ export interface LBSessionResult {
71
+ /** Token de session opaque (72h) */
72
+ sessionToken: string;
73
+ /** Durée de validité en secondes (259200 = 72h) */
74
+ expiresIn: number;
75
+ /** Clé API sélectionnée */
76
+ apiKey: LBApiKey;
77
+ }
78
+ /**
79
+ * Statut d'authentification
80
+ */
81
+ export type LBAuthStatus = "ready" | "needs_auth" | "loading" | "error";
82
+ /**
83
+ * État d'authentification complet
84
+ */
85
+ export interface LBAuthState {
86
+ /** Statut actuel */
87
+ status: LBAuthStatus;
88
+ /** Utilisateur connecté (si session active) */
89
+ user?: LBUser;
90
+ /** Clé API sélectionnée (si session active) */
91
+ selectedKey?: LBApiKey;
92
+ /** Session active */
93
+ session?: LBSession;
94
+ /** Erreur éventuelle */
95
+ error?: string;
96
+ }
97
+ /**
98
+ * Options pour les requêtes IA
99
+ */
100
+ export interface LBRequestOptions {
101
+ /** URL de base (override config) */
102
+ baseUrl?: string;
103
+ /** Headers supplémentaires */
104
+ headers?: Record<string, string>;
105
+ /** Timeout en ms */
106
+ timeout?: number;
107
+ }
108
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/types/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,kCAAkC;IAClC,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,MAAM,EAAE,QAAQ,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,oBAAoB;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,qBAAqB;IACrB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Types pour le système d'authentification LastBrain
3
+ * Permet l'utilisation des services IA avec LB_API_KEY ou session utilisateur
4
+ */
5
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lastbrain/ai-ui-core",
3
- "version": "1.0.28",
3
+ "version": "1.0.30",
4
4
  "description": "Framework-agnostic core library for LastBrain AI UI Kit",
5
5
  "private": false,
6
6
  "type": "module",
@@ -0,0 +1,220 @@
1
+ /**
2
+ * Client LastBrain intelligent
3
+ * Supporte deux modes d'authentification :
4
+ * - env-key : utilise LB_API_KEY (côté serveur)
5
+ * - session : utilise cookie lb_session (user authentifié)
6
+ */
7
+
8
+ import type {
9
+ LBAuthConfig,
10
+ LBSession,
11
+ LBRequestOptions,
12
+ LBLoginResult,
13
+ LBApiKey,
14
+ LBSessionResult,
15
+ } from "../types/auth";
16
+
17
+ export class LBClient {
18
+ private config: Required<LBAuthConfig>;
19
+
20
+ constructor(config: LBAuthConfig = {}) {
21
+ this.config = {
22
+ baseUrl:
23
+ config.baseUrl ||
24
+ process.env.LB_BASE_URL ||
25
+ "https://prompt.lastbrain.io",
26
+ apiKey: config.apiKey || process.env.LB_API_KEY || "",
27
+ mode: config.mode || "auto",
28
+ };
29
+ }
30
+
31
+ /**
32
+ * Détecte le mode d'authentification à utiliser
33
+ */
34
+ private getAuthMode(): "env-key" | "session" {
35
+ if (this.config.mode === "env-key") return "env-key";
36
+ if (this.config.mode === "session") return "session";
37
+
38
+ // Mode auto : préfère env-key si disponible
39
+ return this.config.apiKey ? "env-key" : "session";
40
+ }
41
+
42
+ /**
43
+ * Construit les headers d'authentification
44
+ */
45
+ private async getAuthHeaders(
46
+ sessionToken?: string
47
+ ): Promise<Record<string, string>> {
48
+ const mode = this.getAuthMode();
49
+
50
+ if (mode === "env-key" && this.config.apiKey) {
51
+ return {
52
+ Authorization: `Bearer ${this.config.apiKey}`,
53
+ };
54
+ }
55
+
56
+ // Mode session : utilise le token fourni ou tente de lire le cookie
57
+ if (sessionToken) {
58
+ return {
59
+ Authorization: `Bearer ${sessionToken}`,
60
+ };
61
+ }
62
+
63
+ // Si aucun token fourni, la requête échouera (attendu pour déclencher auth)
64
+ return {};
65
+ }
66
+
67
+ /**
68
+ * Fait une requête à l'API LastBrain
69
+ */
70
+ private async request<T>(
71
+ endpoint: string,
72
+ options: RequestInit & LBRequestOptions = {}
73
+ ): Promise<T> {
74
+ const {
75
+ baseUrl,
76
+ headers: customHeaders,
77
+ timeout,
78
+ ...fetchOptions
79
+ } = options;
80
+
81
+ const url = `${baseUrl || this.config.baseUrl}${endpoint}`;
82
+ const authHeaders = await this.getAuthHeaders();
83
+
84
+ const controller = new AbortController();
85
+ const timeoutId = timeout
86
+ ? setTimeout(() => controller.abort(), timeout)
87
+ : undefined;
88
+
89
+ try {
90
+ const response = await fetch(url, {
91
+ ...fetchOptions,
92
+ headers: {
93
+ "Content-Type": "application/json",
94
+ ...authHeaders,
95
+ ...customHeaders,
96
+ },
97
+ signal: controller.signal,
98
+ });
99
+
100
+ if (!response.ok) {
101
+ const error = await response.json().catch(() => ({}));
102
+ throw new Error(error.message || `HTTP ${response.status}`);
103
+ }
104
+
105
+ return await response.json();
106
+ } finally {
107
+ if (timeoutId) clearTimeout(timeoutId);
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Login utilisateur (email + password)
113
+ * Retourne un access_token temporaire pour récupérer les clés API
114
+ */
115
+ async login(email: string, password: string): Promise<LBLoginResult> {
116
+ return this.request<LBLoginResult>("/auth/login", {
117
+ method: "POST",
118
+ body: JSON.stringify({ email, password }),
119
+ });
120
+ }
121
+
122
+ /**
123
+ * Récupère les clés API de l'utilisateur
124
+ */
125
+ async getUserApiKeys(accessToken: string): Promise<LBApiKey[]> {
126
+ return this.request<LBApiKey[]>("/user/api-keys", {
127
+ headers: {
128
+ Authorization: `Bearer ${accessToken}`,
129
+ },
130
+ });
131
+ }
132
+
133
+ /**
134
+ * Crée une session (72h) avec une clé API sélectionnée
135
+ */
136
+ async createSession(
137
+ accessToken: string,
138
+ apiKeyId: string
139
+ ): Promise<LBSessionResult> {
140
+ return this.request<LBSessionResult>("/auth/session", {
141
+ method: "POST",
142
+ headers: {
143
+ Authorization: `Bearer ${accessToken}`,
144
+ },
145
+ body: JSON.stringify({ api_key_id: apiKeyId }),
146
+ });
147
+ }
148
+
149
+ /**
150
+ * Vérifie si une session est valide
151
+ */
152
+ async verifySession(sessionToken: string): Promise<LBSession | null> {
153
+ try {
154
+ return await this.request<LBSession>("/auth/session/verify", {
155
+ headers: {
156
+ Authorization: `Bearer ${sessionToken}`,
157
+ },
158
+ });
159
+ } catch {
160
+ return null;
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Déconnexion (invalide la session)
166
+ */
167
+ async logout(sessionToken: string): Promise<void> {
168
+ await this.request("/auth/session/logout", {
169
+ method: "POST",
170
+ headers: {
171
+ Authorization: `Bearer ${sessionToken}`,
172
+ },
173
+ });
174
+ }
175
+
176
+ /**
177
+ * Fait un appel IA (génération de texte)
178
+ */
179
+ async generateText(params: {
180
+ prompt: string;
181
+ model?: string;
182
+ sessionToken?: string;
183
+ [key: string]: any;
184
+ }): Promise<any> {
185
+ const { sessionToken, ...body } = params;
186
+ const headers = await this.getAuthHeaders(sessionToken);
187
+
188
+ return this.request("/ai/generate-text", {
189
+ method: "POST",
190
+ headers,
191
+ body: JSON.stringify(body),
192
+ });
193
+ }
194
+
195
+ /**
196
+ * Fait un appel IA (génération d'image)
197
+ */
198
+ async generateImage(params: {
199
+ prompt: string;
200
+ model?: string;
201
+ sessionToken?: string;
202
+ [key: string]: any;
203
+ }): Promise<any> {
204
+ const { sessionToken, ...body } = params;
205
+ const headers = await this.getAuthHeaders(sessionToken);
206
+
207
+ return this.request("/ai/generate-image", {
208
+ method: "POST",
209
+ headers,
210
+ body: JSON.stringify(body),
211
+ });
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Factory pour créer un client LastBrain
217
+ */
218
+ export function createLBClient(config?: LBAuthConfig): LBClient {
219
+ return new LBClient(config);
220
+ }
package/src/index.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  export * from "./types";
2
+ export * from "./types/auth";
2
3
  export * from "./errors/errorCodes";
3
4
  export * from "./errors/normalizeError";
4
5
  export * from "./client/createClient";
6
+ export * from "./client/lb-client";
5
7
 
6
8
  // Route handlers
7
9
  export * from "./route-handlers/nextjs/gateway";
@@ -11,3 +13,4 @@ export {
11
13
  PUT as EnhancedPUT,
12
14
  } from "./route-handlers/nextjs/enhanced-gateway";
13
15
  export * as enhancedGateway from "./route-handlers/nextjs/enhanced-gateway";
16
+ export * from "./route-handlers/nextjs/lb-proxy";
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Proxy handler pour Next.js App Router
3
+ * Permet de faire des appels IA LastBrain depuis le serveur
4
+ * avec support de LB_API_KEY ou session cookie
5
+ */
6
+
7
+ import { NextRequest, NextResponse } from "next/server";
8
+
9
+ /**
10
+ * Configuration du proxy LastBrain
11
+ */
12
+ export interface LBProxyConfig {
13
+ /** URL de base de l'API LastBrain */
14
+ baseUrl?: string;
15
+ /** Clé API LastBrain (optionnel, peut utiliser env) */
16
+ apiKey?: string;
17
+ /** Nom du cookie de session */
18
+ sessionCookieName?: string;
19
+ }
20
+
21
+ /**
22
+ * Crée un handler de proxy unifié pour Next.js App Router
23
+ *
24
+ * Usage:
25
+ * ```typescript
26
+ * // app/api/lastbrain/[...path]/route.ts
27
+ * import { createLBProxyHandler } from "@lastbrain/ai-ui-core";
28
+ *
29
+ * export const { GET, POST, PUT, DELETE, PATCH } = createLBProxyHandler({
30
+ * baseUrl: process.env.LB_BASE_URL,
31
+ * });
32
+ * ```
33
+ */
34
+ export function createLBProxyHandler(config: LBProxyConfig = {}) {
35
+ const {
36
+ baseUrl = process.env.LB_BASE_URL || "https://lastbrain.io",
37
+ apiKey = process.env.LB_API_KEY,
38
+ sessionCookieName = "lb_session",
39
+ } = config;
40
+
41
+ /**
42
+ * Handler unique pour toutes les méthodes HTTP et tous les paths
43
+ */
44
+ async function handler(
45
+ request: NextRequest,
46
+ context?: { params: Promise<{ path?: string[] }> }
47
+ ): Promise<NextResponse> {
48
+ try {
49
+ // Extraire le path depuis l'URL ou les params
50
+ let path = "";
51
+ if (context?.params) {
52
+ const resolvedParams = await context.params;
53
+ path = resolvedParams.path?.join("/") || "";
54
+ } else {
55
+ // Fallback: extraire depuis l'URL
56
+ const url = new URL(request.url);
57
+ const pathMatch = url.pathname.match(/\/api\/lastbrain\/(.*)/);
58
+ path = pathMatch ? pathMatch[1] : "";
59
+ }
60
+
61
+ // Routes publiques qui ne nécessitent pas d'authentification
62
+ const publicPaths = [
63
+ "auth/login",
64
+ "auth/session/create",
65
+ "public/user/api-keys",
66
+ ];
67
+ const isPublicPath = publicPaths.some((p) => path.startsWith(p));
68
+
69
+ // Construire l'URL complète vers LastBrain
70
+ const targetUrl = `${baseUrl}/api/ai/${path}`;
71
+
72
+ // Préparer les headers
73
+ const headers: Record<string, string> = {};
74
+
75
+ // Copier les headers pertinents de la requête originale
76
+ const contentType = request.headers.get("content-type");
77
+ if (contentType) {
78
+ headers["Content-Type"] = contentType;
79
+ }
80
+
81
+ const authorization = request.headers.get("authorization");
82
+ if (authorization) {
83
+ headers["Authorization"] = authorization;
84
+ }
85
+
86
+ // Authentification : LB_API_KEY ou session cookie
87
+ if (!authorization) {
88
+ if (apiKey) {
89
+ headers["Authorization"] = `Bearer ${apiKey}`;
90
+ } else {
91
+ // Lire le cookie de session
92
+ const sessionToken = request.cookies.get(sessionCookieName)?.value;
93
+ if (sessionToken) {
94
+ headers["Authorization"] = `Bearer ${sessionToken}`;
95
+ } else if (!isPublicPath) {
96
+ // Pas d'auth disponible et route protégée
97
+ return NextResponse.json(
98
+ {
99
+ error: "No authentication provided",
100
+ hint: "Set LB_API_KEY env variable or login via /api/lastbrain/auth/login",
101
+ },
102
+ { status: 401 }
103
+ );
104
+ }
105
+ }
106
+ }
107
+
108
+ // Lire le body si c'est POST/PUT/PATCH
109
+ let body: string | undefined = undefined;
110
+ if (["POST", "PUT", "PATCH"].includes(request.method)) {
111
+ const text = await request.text();
112
+ if (text) {
113
+ body = text;
114
+ }
115
+ }
116
+
117
+ // Faire la requête au backend LastBrain
118
+ const response = await fetch(targetUrl, {
119
+ method: request.method,
120
+ headers,
121
+ body,
122
+ });
123
+
124
+ // Lire la réponse
125
+ const responseText = await response.text();
126
+ let data: any;
127
+ try {
128
+ data = responseText ? JSON.parse(responseText) : {};
129
+ } catch {
130
+ data = { error: "Invalid JSON response", raw: responseText };
131
+ }
132
+
133
+ // Créer la réponse Next.js
134
+ const nextResponse = NextResponse.json(data, { status: response.status });
135
+
136
+ // Copier les cookies de la réponse (notamment lb_session)
137
+ const setCookie = response.headers.get("set-cookie");
138
+ if (setCookie) {
139
+ nextResponse.headers.set("set-cookie", setCookie);
140
+ }
141
+
142
+ return nextResponse;
143
+ } catch (error) {
144
+ console.error("[LB Proxy] Error:", error);
145
+ return NextResponse.json(
146
+ { error: error instanceof Error ? error.message : "Proxy error" },
147
+ { status: 500 }
148
+ );
149
+ }
150
+ }
151
+
152
+ // Retourner un objet avec les handlers pour chaque méthode HTTP
153
+ return {
154
+ GET: handler,
155
+ POST: handler,
156
+ PUT: handler,
157
+ DELETE: handler,
158
+ PATCH: handler,
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Helper pour ajouter ou mettre à jour le cookie de session
164
+ */
165
+ export function setLBSessionCookie(
166
+ response: NextResponse,
167
+ sessionToken: string,
168
+ expiresIn: number = 259200 // 72h en secondes
169
+ ): NextResponse {
170
+ response.cookies.set({
171
+ name: "lb_session",
172
+ value: sessionToken,
173
+ httpOnly: true,
174
+ secure: process.env.NODE_ENV === "production",
175
+ sameSite: "lax",
176
+ path: "/",
177
+ maxAge: expiresIn,
178
+ });
179
+
180
+ return response;
181
+ }
182
+
183
+ /**
184
+ * Helper pour supprimer le cookie de session
185
+ */
186
+ export function clearLBSessionCookie(response: NextResponse): NextResponse {
187
+ response.cookies.delete("lb_session");
188
+ return response;
189
+ }
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Types pour le système d'authentification LastBrain
3
+ * Permet l'utilisation des services IA avec LB_API_KEY ou session utilisateur
4
+ */
5
+
6
+ /**
7
+ * Configuration du client LastBrain
8
+ */
9
+ export interface LBAuthConfig {
10
+ /** URL de base de l'API LastBrain (ex: https://api.lastbrain.io) */
11
+ baseUrl?: string;
12
+ /** Clé API LastBrain (côté serveur uniquement) */
13
+ apiKey?: string;
14
+ /** Mode d'authentification */
15
+ mode?: "env-key" | "session" | "auto";
16
+ }
17
+
18
+ /**
19
+ * Session utilisateur LastBrain (stockée dans cookie HttpOnly)
20
+ */
21
+ export interface LBSession {
22
+ /** Token de session opaque signé côté serveur */
23
+ sessionToken: string;
24
+ /** ID utilisateur associé */
25
+ userId: string;
26
+ /** ID de la clé API sélectionnée */
27
+ apiKeyId: string;
28
+ /** Timestamp d'expiration (72h après création) */
29
+ expiresAt: number;
30
+ /** Scopes/permissions accordés */
31
+ scopes?: string[];
32
+ /** Quotas restants (optionnel) */
33
+ quotas?: {
34
+ tokens?: number;
35
+ requests?: number;
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Informations utilisateur LastBrain
41
+ */
42
+ export interface LBUser {
43
+ id: string;
44
+ email: string;
45
+ name?: string;
46
+ avatar?: string;
47
+ }
48
+
49
+ /**
50
+ * Clé API LastBrain de l'utilisateur
51
+ */
52
+ export interface LBApiKey {
53
+ id: string;
54
+ name: string;
55
+ /** Préfixe visible de la clé (ex: "lb_live_abc...") */
56
+ keyPrefix: string;
57
+ scopes: string[];
58
+ isActive: boolean;
59
+ createdAt: string;
60
+ lastUsedAt?: string;
61
+ }
62
+
63
+ /**
64
+ * Résultat de connexion
65
+ */
66
+ export interface LBLoginResult {
67
+ /** Token d'accès temporaire pour récupérer les clés API */
68
+ accessToken: string;
69
+ /** Informations utilisateur */
70
+ user: LBUser;
71
+ }
72
+
73
+ /**
74
+ * Résultat de création de session
75
+ */
76
+ export interface LBSessionResult {
77
+ /** Token de session opaque (72h) */
78
+ sessionToken: string;
79
+ /** Durée de validité en secondes (259200 = 72h) */
80
+ expiresIn: number;
81
+ /** Clé API sélectionnée */
82
+ apiKey: LBApiKey;
83
+ }
84
+
85
+ /**
86
+ * Statut d'authentification
87
+ */
88
+ export type LBAuthStatus = "ready" | "needs_auth" | "loading" | "error";
89
+
90
+ /**
91
+ * État d'authentification complet
92
+ */
93
+ export interface LBAuthState {
94
+ /** Statut actuel */
95
+ status: LBAuthStatus;
96
+ /** Utilisateur connecté (si session active) */
97
+ user?: LBUser;
98
+ /** Clé API sélectionnée (si session active) */
99
+ selectedKey?: LBApiKey;
100
+ /** Session active */
101
+ session?: LBSession;
102
+ /** Erreur éventuelle */
103
+ error?: string;
104
+ }
105
+
106
+ /**
107
+ * Options pour les requêtes IA
108
+ */
109
+ export interface LBRequestOptions {
110
+ /** URL de base (override config) */
111
+ baseUrl?: string;
112
+ /** Headers supplémentaires */
113
+ headers?: Record<string, string>;
114
+ /** Timeout en ms */
115
+ timeout?: number;
116
+ }