@lastbrain/ai-ui-core 1.0.27 → 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.
- package/dist/client/lb-client.d.ts +67 -0
- package/dist/client/lb-client.d.ts.map +1 -0
- package/dist/client/lb-client.js +168 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/route-handlers/nextjs/lb-proxy.d.ts +69 -0
- package/dist/route-handlers/nextjs/lb-proxy.d.ts.map +1 -0
- package/dist/route-handlers/nextjs/lb-proxy.js +104 -0
- package/dist/types/auth.d.ts +108 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +5 -0
- package/package.json +1 -1
- package/src/client/lb-client.ts +220 -0
- package/src/index.ts +3 -0
- package/src/route-handlers/nextjs/lb-proxy.ts +145 -0
- package/src/types/auth.ts +116 -0
|
@@ -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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/package.json
CHANGED
|
@@ -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
|
+
}
|