@lastbrain/ai-ui-core 1.0.28 → 1.0.29

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,69 @@
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 pour Next.js App Router
20
+ *
21
+ * Usage:
22
+ * ```typescript
23
+ * // app/api/lb/[...path]/route.ts
24
+ * import { createLBProxyHandler } from "@lastbrain/ai-ui-core";
25
+ *
26
+ * const { GET, POST, PUT, DELETE } = createLBProxyHandler({
27
+ * baseUrl: process.env.LB_BASE_URL,
28
+ * apiKey: process.env.LB_API_KEY,
29
+ * });
30
+ *
31
+ * export { GET, POST, PUT, DELETE };
32
+ * ```
33
+ */
34
+ export declare function createLBProxyHandler(config?: LBProxyConfig): {
35
+ GET: (request: NextRequest, { params }: {
36
+ params: Promise<{
37
+ path: string[];
38
+ }>;
39
+ }) => Promise<NextResponse>;
40
+ POST: (request: NextRequest, { params }: {
41
+ params: Promise<{
42
+ path: string[];
43
+ }>;
44
+ }) => Promise<NextResponse>;
45
+ PUT: (request: NextRequest, { params }: {
46
+ params: Promise<{
47
+ path: string[];
48
+ }>;
49
+ }) => Promise<NextResponse>;
50
+ DELETE: (request: NextRequest, { params }: {
51
+ params: Promise<{
52
+ path: string[];
53
+ }>;
54
+ }) => Promise<NextResponse>;
55
+ PATCH: (request: NextRequest, { params }: {
56
+ params: Promise<{
57
+ path: string[];
58
+ }>;
59
+ }) => Promise<NextResponse>;
60
+ };
61
+ /**
62
+ * Helper pour définir un cookie de session HttpOnly
63
+ */
64
+ export declare function setLBSessionCookie(response: NextResponse, sessionToken: string, expiresIn?: number): NextResponse;
65
+ /**
66
+ * Helper pour supprimer le cookie de session
67
+ */
68
+ export declare function clearLBSessionCookie(response: NextResponse): NextResponse;
69
+ //# 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;AAGxD;;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;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,aAAkB;mBAalD,WAAW,cACR;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,IAAI,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE,KAClD,OAAO,CAAC,YAAY,CAAC;oBAFb,WAAW,cACR;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,IAAI,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE,KAClD,OAAO,CAAC,YAAY,CAAC;mBAFb,WAAW,cACR;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,IAAI,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE,KAClD,OAAO,CAAC,YAAY,CAAC;sBAFb,WAAW,cACR;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,IAAI,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE,KAClD,OAAO,CAAC,YAAY,CAAC;qBAFb,WAAW,cACR;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,IAAI,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAA;KAAE,KAClD,OAAO,CAAC,YAAY,CAAC;EA+DzB;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,104 @@
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
+ import { createLBClient } from "../../client/lb-client";
8
+ /**
9
+ * Crée un handler de proxy pour Next.js App Router
10
+ *
11
+ * Usage:
12
+ * ```typescript
13
+ * // app/api/lb/[...path]/route.ts
14
+ * import { createLBProxyHandler } from "@lastbrain/ai-ui-core";
15
+ *
16
+ * const { GET, POST, PUT, DELETE } = createLBProxyHandler({
17
+ * baseUrl: process.env.LB_BASE_URL,
18
+ * apiKey: process.env.LB_API_KEY,
19
+ * });
20
+ *
21
+ * export { GET, POST, PUT, DELETE };
22
+ * ```
23
+ */
24
+ export function createLBProxyHandler(config = {}) {
25
+ const { baseUrl = process.env.LB_BASE_URL || "https://prompt.lastbrain.io", apiKey = process.env.LB_API_KEY, sessionCookieName = "lb_session", } = config;
26
+ const client = createLBClient({ baseUrl, apiKey });
27
+ /**
28
+ * Handler générique pour toutes les méthodes HTTP
29
+ */
30
+ async function handleRequest(request, { params }) {
31
+ try {
32
+ const resolvedParams = await params;
33
+ const path = resolvedParams.path?.join("/") || "";
34
+ const endpoint = `/${path}`;
35
+ // Lire le cookie de session si présent
36
+ const sessionToken = request.cookies.get(sessionCookieName)?.value;
37
+ // Préparer les headers
38
+ const headers = {
39
+ "Content-Type": "application/json",
40
+ };
41
+ // Authentification : LB_API_KEY ou session
42
+ if (apiKey) {
43
+ headers.Authorization = `Bearer ${apiKey}`;
44
+ }
45
+ else if (sessionToken) {
46
+ headers.Authorization = `Bearer ${sessionToken}`;
47
+ }
48
+ else {
49
+ return NextResponse.json({ error: "No authentication provided. Set LB_API_KEY or login." }, { status: 401 });
50
+ }
51
+ // Lire le body si c'est POST/PUT/PATCH
52
+ let body = undefined;
53
+ if (["POST", "PUT", "PATCH"].includes(request.method)) {
54
+ body = await request.json().catch(() => ({}));
55
+ }
56
+ // Faire la requête au backend LastBrain
57
+ const response = await fetch(`${baseUrl}${endpoint}`, {
58
+ method: request.method,
59
+ headers,
60
+ body: body ? JSON.stringify(body) : undefined,
61
+ });
62
+ const data = await response.json().catch(() => ({}));
63
+ if (!response.ok) {
64
+ return NextResponse.json(data, { status: response.status });
65
+ }
66
+ return NextResponse.json(data);
67
+ }
68
+ catch (error) {
69
+ console.error("[LB Proxy] Error:", error);
70
+ return NextResponse.json({ error: error instanceof Error ? error.message : "Proxy error" }, { status: 500 });
71
+ }
72
+ }
73
+ // Retourner les handlers pour Next.js
74
+ return {
75
+ GET: handleRequest,
76
+ POST: handleRequest,
77
+ PUT: handleRequest,
78
+ DELETE: handleRequest,
79
+ PATCH: handleRequest,
80
+ };
81
+ }
82
+ /**
83
+ * Helper pour définir un cookie de session HttpOnly
84
+ */
85
+ export function setLBSessionCookie(response, sessionToken, expiresIn = 259200 // 72h en secondes
86
+ ) {
87
+ response.cookies.set({
88
+ name: "lb_session",
89
+ value: sessionToken,
90
+ httpOnly: true,
91
+ secure: process.env.NODE_ENV === "production",
92
+ sameSite: "lax",
93
+ path: "/",
94
+ maxAge: expiresIn,
95
+ });
96
+ return response;
97
+ }
98
+ /**
99
+ * Helper pour supprimer le cookie de session
100
+ */
101
+ export function clearLBSessionCookie(response) {
102
+ response.cookies.delete("lb_session");
103
+ return response;
104
+ }
@@ -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.29",
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,145 @@
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
+ import { createLBClient } from "../../client/lb-client";
9
+
10
+ /**
11
+ * Configuration du proxy LastBrain
12
+ */
13
+ export interface LBProxyConfig {
14
+ /** URL de base de l'API LastBrain */
15
+ baseUrl?: string;
16
+ /** Clé API LastBrain (optionnel, peut utiliser env) */
17
+ apiKey?: string;
18
+ /** Nom du cookie de session */
19
+ sessionCookieName?: string;
20
+ }
21
+
22
+ /**
23
+ * Crée un handler de proxy pour Next.js App Router
24
+ *
25
+ * Usage:
26
+ * ```typescript
27
+ * // app/api/lb/[...path]/route.ts
28
+ * import { createLBProxyHandler } from "@lastbrain/ai-ui-core";
29
+ *
30
+ * const { GET, POST, PUT, DELETE } = createLBProxyHandler({
31
+ * baseUrl: process.env.LB_BASE_URL,
32
+ * apiKey: process.env.LB_API_KEY,
33
+ * });
34
+ *
35
+ * export { GET, POST, PUT, DELETE };
36
+ * ```
37
+ */
38
+ export function createLBProxyHandler(config: LBProxyConfig = {}) {
39
+ const {
40
+ baseUrl = process.env.LB_BASE_URL || "https://prompt.lastbrain.io",
41
+ apiKey = process.env.LB_API_KEY,
42
+ sessionCookieName = "lb_session",
43
+ } = config;
44
+
45
+ const client = createLBClient({ baseUrl, apiKey });
46
+
47
+ /**
48
+ * Handler générique pour toutes les méthodes HTTP
49
+ */
50
+ async function handleRequest(
51
+ request: NextRequest,
52
+ { params }: { params: Promise<{ path: string[] }> }
53
+ ): Promise<NextResponse> {
54
+ try {
55
+ const resolvedParams = await params;
56
+ const path = resolvedParams.path?.join("/") || "";
57
+ const endpoint = `/${path}`;
58
+
59
+ // Lire le cookie de session si présent
60
+ const sessionToken = request.cookies.get(sessionCookieName)?.value;
61
+
62
+ // Préparer les headers
63
+ const headers: Record<string, string> = {
64
+ "Content-Type": "application/json",
65
+ };
66
+
67
+ // Authentification : LB_API_KEY ou session
68
+ if (apiKey) {
69
+ headers.Authorization = `Bearer ${apiKey}`;
70
+ } else if (sessionToken) {
71
+ headers.Authorization = `Bearer ${sessionToken}`;
72
+ } else {
73
+ return NextResponse.json(
74
+ { error: "No authentication provided. Set LB_API_KEY or login." },
75
+ { status: 401 }
76
+ );
77
+ }
78
+
79
+ // Lire le body si c'est POST/PUT/PATCH
80
+ let body: any = undefined;
81
+ if (["POST", "PUT", "PATCH"].includes(request.method)) {
82
+ body = await request.json().catch(() => ({}));
83
+ }
84
+
85
+ // Faire la requête au backend LastBrain
86
+ const response = await fetch(`${baseUrl}${endpoint}`, {
87
+ method: request.method,
88
+ headers,
89
+ body: body ? JSON.stringify(body) : undefined,
90
+ });
91
+
92
+ const data = await response.json().catch(() => ({}));
93
+
94
+ if (!response.ok) {
95
+ return NextResponse.json(data, { status: response.status });
96
+ }
97
+
98
+ return NextResponse.json(data);
99
+ } catch (error) {
100
+ console.error("[LB Proxy] Error:", error);
101
+ return NextResponse.json(
102
+ { error: error instanceof Error ? error.message : "Proxy error" },
103
+ { status: 500 }
104
+ );
105
+ }
106
+ }
107
+
108
+ // Retourner les handlers pour Next.js
109
+ return {
110
+ GET: handleRequest,
111
+ POST: handleRequest,
112
+ PUT: handleRequest,
113
+ DELETE: handleRequest,
114
+ PATCH: handleRequest,
115
+ };
116
+ }
117
+
118
+ /**
119
+ * Helper pour définir un cookie de session HttpOnly
120
+ */
121
+ export function setLBSessionCookie(
122
+ response: NextResponse,
123
+ sessionToken: string,
124
+ expiresIn: number = 259200 // 72h en secondes
125
+ ): NextResponse {
126
+ response.cookies.set({
127
+ name: "lb_session",
128
+ value: sessionToken,
129
+ httpOnly: true,
130
+ secure: process.env.NODE_ENV === "production",
131
+ sameSite: "lax",
132
+ path: "/",
133
+ maxAge: expiresIn,
134
+ });
135
+
136
+ return response;
137
+ }
138
+
139
+ /**
140
+ * Helper pour supprimer le cookie de session
141
+ */
142
+ export function clearLBSessionCookie(response: NextResponse): NextResponse {
143
+ response.cookies.delete("lb_session");
144
+ return response;
145
+ }
@@ -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
+ }