@lastbrain/ai-ui-core 1.0.29 → 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.
@@ -16,50 +16,47 @@ export interface LBProxyConfig {
16
16
  sessionCookieName?: string;
17
17
  }
18
18
  /**
19
- * Crée un handler de proxy pour Next.js App Router
19
+ * Crée un handler de proxy unifié pour Next.js App Router
20
20
  *
21
21
  * Usage:
22
22
  * ```typescript
23
- * // app/api/lb/[...path]/route.ts
23
+ * // app/api/lastbrain/[...path]/route.ts
24
24
  * import { createLBProxyHandler } from "@lastbrain/ai-ui-core";
25
25
  *
26
- * const { GET, POST, PUT, DELETE } = createLBProxyHandler({
26
+ * export const { GET, POST, PUT, DELETE, PATCH } = createLBProxyHandler({
27
27
  * baseUrl: process.env.LB_BASE_URL,
28
- * apiKey: process.env.LB_API_KEY,
29
28
  * });
30
- *
31
- * export { GET, POST, PUT, DELETE };
32
29
  * ```
33
30
  */
34
31
  export declare function createLBProxyHandler(config?: LBProxyConfig): {
35
- GET: (request: NextRequest, { params }: {
32
+ GET: (request: NextRequest, context?: {
36
33
  params: Promise<{
37
- path: string[];
34
+ path?: string[];
38
35
  }>;
39
36
  }) => Promise<NextResponse>;
40
- POST: (request: NextRequest, { params }: {
37
+ POST: (request: NextRequest, context?: {
41
38
  params: Promise<{
42
- path: string[];
39
+ path?: string[];
43
40
  }>;
44
41
  }) => Promise<NextResponse>;
45
- PUT: (request: NextRequest, { params }: {
42
+ PUT: (request: NextRequest, context?: {
46
43
  params: Promise<{
47
- path: string[];
44
+ path?: string[];
48
45
  }>;
49
46
  }) => Promise<NextResponse>;
50
- DELETE: (request: NextRequest, { params }: {
47
+ DELETE: (request: NextRequest, context?: {
51
48
  params: Promise<{
52
- path: string[];
49
+ path?: string[];
53
50
  }>;
54
51
  }) => Promise<NextResponse>;
55
- PATCH: (request: NextRequest, { params }: {
52
+ PATCH: (request: NextRequest, context?: {
56
53
  params: Promise<{
57
- path: string[];
54
+ path?: string[];
58
55
  }>;
59
56
  }) => Promise<NextResponse>;
60
57
  };
61
58
  /**
62
- * Helper pour définir un cookie de session HttpOnly
59
+ * Helper pour ajouter ou mettre à jour le cookie de session
63
60
  */
64
61
  export declare function setLBSessionCookie(response: NextResponse, sessionToken: string, expiresIn?: number): NextResponse;
65
62
  /**
@@ -1 +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"}
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"}
@@ -4,83 +4,126 @@
4
4
  * avec support de LB_API_KEY ou session cookie
5
5
  */
6
6
  import { NextResponse } from "next/server";
7
- import { createLBClient } from "../../client/lb-client";
8
7
  /**
9
- * Crée un handler de proxy pour Next.js App Router
8
+ * Crée un handler de proxy unifié pour Next.js App Router
10
9
  *
11
10
  * Usage:
12
11
  * ```typescript
13
- * // app/api/lb/[...path]/route.ts
12
+ * // app/api/lastbrain/[...path]/route.ts
14
13
  * import { createLBProxyHandler } from "@lastbrain/ai-ui-core";
15
14
  *
16
- * const { GET, POST, PUT, DELETE } = createLBProxyHandler({
15
+ * export const { GET, POST, PUT, DELETE, PATCH } = createLBProxyHandler({
17
16
  * baseUrl: process.env.LB_BASE_URL,
18
- * apiKey: process.env.LB_API_KEY,
19
17
  * });
20
- *
21
- * export { GET, POST, PUT, DELETE };
22
18
  * ```
23
19
  */
24
20
  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 });
21
+ const { baseUrl = process.env.LB_BASE_URL || "https://lastbrain.io", apiKey = process.env.LB_API_KEY, sessionCookieName = "lb_session", } = config;
27
22
  /**
28
- * Handler générique pour toutes les méthodes HTTP
23
+ * Handler unique pour toutes les méthodes HTTP et tous les paths
29
24
  */
30
- async function handleRequest(request, { params }) {
25
+ async function handler(request, context) {
31
26
  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;
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}`;
37
48
  // 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}`;
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;
44
54
  }
45
- else if (sessionToken) {
46
- headers.Authorization = `Bearer ${sessionToken}`;
55
+ const authorization = request.headers.get("authorization");
56
+ if (authorization) {
57
+ headers["Authorization"] = authorization;
47
58
  }
48
- else {
49
- return NextResponse.json({ error: "No authentication provided. Set LB_API_KEY or login." }, { status: 401 });
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
+ }
50
78
  }
51
79
  // Lire le body si c'est POST/PUT/PATCH
52
80
  let body = undefined;
53
81
  if (["POST", "PUT", "PATCH"].includes(request.method)) {
54
- body = await request.json().catch(() => ({}));
82
+ const text = await request.text();
83
+ if (text) {
84
+ body = text;
85
+ }
55
86
  }
56
87
  // Faire la requête au backend LastBrain
57
- const response = await fetch(`${baseUrl}${endpoint}`, {
88
+ const response = await fetch(targetUrl, {
58
89
  method: request.method,
59
90
  headers,
60
- body: body ? JSON.stringify(body) : undefined,
91
+ body,
61
92
  });
62
- const data = await response.json().catch(() => ({}));
63
- if (!response.ok) {
64
- return NextResponse.json(data, { status: response.status });
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);
65
108
  }
66
- return NextResponse.json(data);
109
+ return nextResponse;
67
110
  }
68
111
  catch (error) {
69
112
  console.error("[LB Proxy] Error:", error);
70
113
  return NextResponse.json({ error: error instanceof Error ? error.message : "Proxy error" }, { status: 500 });
71
114
  }
72
115
  }
73
- // Retourner les handlers pour Next.js
116
+ // Retourner un objet avec les handlers pour chaque méthode HTTP
74
117
  return {
75
- GET: handleRequest,
76
- POST: handleRequest,
77
- PUT: handleRequest,
78
- DELETE: handleRequest,
79
- PATCH: handleRequest,
118
+ GET: handler,
119
+ POST: handler,
120
+ PUT: handler,
121
+ DELETE: handler,
122
+ PATCH: handler,
80
123
  };
81
124
  }
82
125
  /**
83
- * Helper pour définir un cookie de session HttpOnly
126
+ * Helper pour ajouter ou mettre à jour le cookie de session
84
127
  */
85
128
  export function setLBSessionCookie(response, sessionToken, expiresIn = 259200 // 72h en secondes
86
129
  ) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lastbrain/ai-ui-core",
3
- "version": "1.0.29",
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",
@@ -5,7 +5,6 @@
5
5
  */
6
6
 
7
7
  import { NextRequest, NextResponse } from "next/server";
8
- import { createLBClient } from "../../client/lb-client";
9
8
 
10
9
  /**
11
10
  * Configuration du proxy LastBrain
@@ -20,82 +19,127 @@ export interface LBProxyConfig {
20
19
  }
21
20
 
22
21
  /**
23
- * Crée un handler de proxy pour Next.js App Router
22
+ * Crée un handler de proxy unifié pour Next.js App Router
24
23
  *
25
24
  * Usage:
26
25
  * ```typescript
27
- * // app/api/lb/[...path]/route.ts
26
+ * // app/api/lastbrain/[...path]/route.ts
28
27
  * import { createLBProxyHandler } from "@lastbrain/ai-ui-core";
29
28
  *
30
- * const { GET, POST, PUT, DELETE } = createLBProxyHandler({
29
+ * export const { GET, POST, PUT, DELETE, PATCH } = createLBProxyHandler({
31
30
  * baseUrl: process.env.LB_BASE_URL,
32
- * apiKey: process.env.LB_API_KEY,
33
31
  * });
34
- *
35
- * export { GET, POST, PUT, DELETE };
36
32
  * ```
37
33
  */
38
34
  export function createLBProxyHandler(config: LBProxyConfig = {}) {
39
35
  const {
40
- baseUrl = process.env.LB_BASE_URL || "https://prompt.lastbrain.io",
36
+ baseUrl = process.env.LB_BASE_URL || "https://lastbrain.io",
41
37
  apiKey = process.env.LB_API_KEY,
42
38
  sessionCookieName = "lb_session",
43
39
  } = config;
44
40
 
45
- const client = createLBClient({ baseUrl, apiKey });
46
-
47
41
  /**
48
- * Handler générique pour toutes les méthodes HTTP
42
+ * Handler unique pour toutes les méthodes HTTP et tous les paths
49
43
  */
50
- async function handleRequest(
44
+ async function handler(
51
45
  request: NextRequest,
52
- { params }: { params: Promise<{ path: string[] }> }
46
+ context?: { params: Promise<{ path?: string[] }> }
53
47
  ): Promise<NextResponse> {
54
48
  try {
55
- const resolvedParams = await params;
56
- const path = resolvedParams.path?.join("/") || "";
57
- const endpoint = `/${path}`;
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
+ }
58
60
 
59
- // Lire le cookie de session si présent
60
- const sessionToken = request.cookies.get(sessionCookieName)?.value;
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}`;
61
71
 
62
72
  // 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
- );
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
+ }
77
106
  }
78
107
 
79
108
  // Lire le body si c'est POST/PUT/PATCH
80
- let body: any = undefined;
109
+ let body: string | undefined = undefined;
81
110
  if (["POST", "PUT", "PATCH"].includes(request.method)) {
82
- body = await request.json().catch(() => ({}));
111
+ const text = await request.text();
112
+ if (text) {
113
+ body = text;
114
+ }
83
115
  }
84
116
 
85
117
  // Faire la requête au backend LastBrain
86
- const response = await fetch(`${baseUrl}${endpoint}`, {
118
+ const response = await fetch(targetUrl, {
87
119
  method: request.method,
88
120
  headers,
89
- body: body ? JSON.stringify(body) : undefined,
121
+ body,
90
122
  });
91
123
 
92
- const data = await response.json().catch(() => ({}));
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 });
93
135
 
94
- if (!response.ok) {
95
- return NextResponse.json(data, { status: response.status });
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);
96
140
  }
97
141
 
98
- return NextResponse.json(data);
142
+ return nextResponse;
99
143
  } catch (error) {
100
144
  console.error("[LB Proxy] Error:", error);
101
145
  return NextResponse.json(
@@ -105,18 +149,18 @@ export function createLBProxyHandler(config: LBProxyConfig = {}) {
105
149
  }
106
150
  }
107
151
 
108
- // Retourner les handlers pour Next.js
152
+ // Retourner un objet avec les handlers pour chaque méthode HTTP
109
153
  return {
110
- GET: handleRequest,
111
- POST: handleRequest,
112
- PUT: handleRequest,
113
- DELETE: handleRequest,
114
- PATCH: handleRequest,
154
+ GET: handler,
155
+ POST: handler,
156
+ PUT: handler,
157
+ DELETE: handler,
158
+ PATCH: handler,
115
159
  };
116
160
  }
117
161
 
118
162
  /**
119
- * Helper pour définir un cookie de session HttpOnly
163
+ * Helper pour ajouter ou mettre à jour le cookie de session
120
164
  */
121
165
  export function setLBSessionCookie(
122
166
  response: NextResponse,