@lastbrain/ai-ui-core 1.0.29 → 1.0.31

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;mBAiBlD,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;EAkHzB;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,132 @@
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;
22
+ // Déterminer le chemin de base API
23
+ // Si baseUrl contient déjà /api/public/v1, l'utiliser tel quel
24
+ // Sinon, pour les nouvelles routes d'auth, utiliser /api/ai
25
+ const isLegacyBaseUrl = baseUrl.includes("/api/public/v1");
26
+ const apiBasePath = isLegacyBaseUrl ? "" : "/api/ai";
27
27
  /**
28
- * Handler générique pour toutes les méthodes HTTP
28
+ * Handler unique pour toutes les méthodes HTTP et tous les paths
29
29
  */
30
- async function handleRequest(request, { params }) {
30
+ async function handler(request, context) {
31
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;
32
+ // Extraire le path depuis l'URL ou les params
33
+ let path = "";
34
+ if (context?.params) {
35
+ const resolvedParams = await context.params;
36
+ path = resolvedParams.path?.join("/") || "";
37
+ }
38
+ else {
39
+ // Fallback: extraire depuis l'URL
40
+ const url = new URL(request.url);
41
+ const pathMatch = url.pathname.match(/\/api\/lastbrain\/(.*)/);
42
+ path = pathMatch ? pathMatch[1] : "";
43
+ }
44
+ // Routes publiques qui ne nécessitent pas d'authentification
45
+ const publicPaths = [
46
+ "auth/login",
47
+ "auth/session/create",
48
+ "public/user/api-keys",
49
+ ];
50
+ const isPublicPath = publicPaths.some((p) => path.startsWith(p));
51
+ // Construire l'URL complète vers LastBrain
52
+ // Si legacy baseUrl (avec /api/public/v1), ne pas ajouter apiBasePath
53
+ const targetUrl = `${baseUrl}${apiBasePath}/${path}`;
37
54
  // 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}`;
55
+ const headers = {};
56
+ // Copier les headers pertinents de la requête originale
57
+ const contentType = request.headers.get("content-type");
58
+ if (contentType) {
59
+ headers["Content-Type"] = contentType;
44
60
  }
45
- else if (sessionToken) {
46
- headers.Authorization = `Bearer ${sessionToken}`;
61
+ const authorization = request.headers.get("authorization");
62
+ if (authorization) {
63
+ headers["Authorization"] = authorization;
47
64
  }
48
- else {
49
- return NextResponse.json({ error: "No authentication provided. Set LB_API_KEY or login." }, { status: 401 });
65
+ // Authentification : LB_API_KEY ou session cookie
66
+ if (!authorization) {
67
+ if (apiKey) {
68
+ headers["Authorization"] = `Bearer ${apiKey}`;
69
+ }
70
+ else {
71
+ // Lire le cookie de session
72
+ const sessionToken = request.cookies.get(sessionCookieName)?.value;
73
+ if (sessionToken) {
74
+ headers["Authorization"] = `Bearer ${sessionToken}`;
75
+ }
76
+ else if (!isPublicPath) {
77
+ // Pas d'auth disponible et route protégée
78
+ return NextResponse.json({
79
+ error: "No authentication provided",
80
+ hint: "Set LB_API_KEY env variable or login via /api/lastbrain/auth/login",
81
+ }, { status: 401 });
82
+ }
83
+ }
50
84
  }
51
85
  // Lire le body si c'est POST/PUT/PATCH
52
86
  let body = undefined;
53
87
  if (["POST", "PUT", "PATCH"].includes(request.method)) {
54
- body = await request.json().catch(() => ({}));
88
+ const text = await request.text();
89
+ if (text) {
90
+ body = text;
91
+ }
55
92
  }
56
93
  // Faire la requête au backend LastBrain
57
- const response = await fetch(`${baseUrl}${endpoint}`, {
94
+ const response = await fetch(targetUrl, {
58
95
  method: request.method,
59
96
  headers,
60
- body: body ? JSON.stringify(body) : undefined,
97
+ body,
61
98
  });
62
- const data = await response.json().catch(() => ({}));
63
- if (!response.ok) {
64
- return NextResponse.json(data, { status: response.status });
99
+ // Lire la réponse
100
+ const responseText = await response.text();
101
+ let data;
102
+ try {
103
+ data = responseText ? JSON.parse(responseText) : {};
104
+ }
105
+ catch {
106
+ data = { error: "Invalid JSON response", raw: responseText };
107
+ }
108
+ // Créer la réponse Next.js
109
+ const nextResponse = NextResponse.json(data, { status: response.status });
110
+ // Copier les cookies de la réponse (notamment lb_session)
111
+ const setCookie = response.headers.get("set-cookie");
112
+ if (setCookie) {
113
+ nextResponse.headers.set("set-cookie", setCookie);
65
114
  }
66
- return NextResponse.json(data);
115
+ return nextResponse;
67
116
  }
68
117
  catch (error) {
69
118
  console.error("[LB Proxy] Error:", error);
70
119
  return NextResponse.json({ error: error instanceof Error ? error.message : "Proxy error" }, { status: 500 });
71
120
  }
72
121
  }
73
- // Retourner les handlers pour Next.js
122
+ // Retourner un objet avec les handlers pour chaque méthode HTTP
74
123
  return {
75
- GET: handleRequest,
76
- POST: handleRequest,
77
- PUT: handleRequest,
78
- DELETE: handleRequest,
79
- PATCH: handleRequest,
124
+ GET: handler,
125
+ POST: handler,
126
+ PUT: handler,
127
+ DELETE: handler,
128
+ PATCH: handler,
80
129
  };
81
130
  }
82
131
  /**
83
- * Helper pour définir un cookie de session HttpOnly
132
+ * Helper pour ajouter ou mettre à jour le cookie de session
84
133
  */
85
134
  export function setLBSessionCookie(response, sessionToken, expiresIn = 259200 // 72h en secondes
86
135
  ) {
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.31",
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,134 @@ 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 });
41
+ // Déterminer le chemin de base API
42
+ // Si baseUrl contient déjà /api/public/v1, l'utiliser tel quel
43
+ // Sinon, pour les nouvelles routes d'auth, utiliser /api/ai
44
+ const isLegacyBaseUrl = baseUrl.includes("/api/public/v1");
45
+ const apiBasePath = isLegacyBaseUrl ? "" : "/api/ai";
46
46
 
47
47
  /**
48
- * Handler générique pour toutes les méthodes HTTP
48
+ * Handler unique pour toutes les méthodes HTTP et tous les paths
49
49
  */
50
- async function handleRequest(
50
+ async function handler(
51
51
  request: NextRequest,
52
- { params }: { params: Promise<{ path: string[] }> }
52
+ context?: { params: Promise<{ path?: string[] }> }
53
53
  ): Promise<NextResponse> {
54
54
  try {
55
- const resolvedParams = await params;
56
- const path = resolvedParams.path?.join("/") || "";
57
- const endpoint = `/${path}`;
55
+ // Extraire le path depuis l'URL ou les params
56
+ let path = "";
57
+ if (context?.params) {
58
+ const resolvedParams = await context.params;
59
+ path = resolvedParams.path?.join("/") || "";
60
+ } else {
61
+ // Fallback: extraire depuis l'URL
62
+ const url = new URL(request.url);
63
+ const pathMatch = url.pathname.match(/\/api\/lastbrain\/(.*)/);
64
+ path = pathMatch ? pathMatch[1] : "";
65
+ }
58
66
 
59
- // Lire le cookie de session si présent
60
- const sessionToken = request.cookies.get(sessionCookieName)?.value;
67
+ // Routes publiques qui ne nécessitent pas d'authentification
68
+ const publicPaths = [
69
+ "auth/login",
70
+ "auth/session/create",
71
+ "public/user/api-keys",
72
+ ];
73
+ const isPublicPath = publicPaths.some((p) => path.startsWith(p));
74
+
75
+ // Construire l'URL complète vers LastBrain
76
+ // Si legacy baseUrl (avec /api/public/v1), ne pas ajouter apiBasePath
77
+ const targetUrl = `${baseUrl}${apiBasePath}/${path}`;
61
78
 
62
79
  // 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
- );
80
+ const headers: Record<string, string> = {};
81
+
82
+ // Copier les headers pertinents de la requête originale
83
+ const contentType = request.headers.get("content-type");
84
+ if (contentType) {
85
+ headers["Content-Type"] = contentType;
86
+ }
87
+
88
+ const authorization = request.headers.get("authorization");
89
+ if (authorization) {
90
+ headers["Authorization"] = authorization;
91
+ }
92
+
93
+ // Authentification : LB_API_KEY ou session cookie
94
+ if (!authorization) {
95
+ if (apiKey) {
96
+ headers["Authorization"] = `Bearer ${apiKey}`;
97
+ } else {
98
+ // Lire le cookie de session
99
+ const sessionToken = request.cookies.get(sessionCookieName)?.value;
100
+ if (sessionToken) {
101
+ headers["Authorization"] = `Bearer ${sessionToken}`;
102
+ } else if (!isPublicPath) {
103
+ // Pas d'auth disponible et route protégée
104
+ return NextResponse.json(
105
+ {
106
+ error: "No authentication provided",
107
+ hint: "Set LB_API_KEY env variable or login via /api/lastbrain/auth/login",
108
+ },
109
+ { status: 401 }
110
+ );
111
+ }
112
+ }
77
113
  }
78
114
 
79
115
  // Lire le body si c'est POST/PUT/PATCH
80
- let body: any = undefined;
116
+ let body: string | undefined = undefined;
81
117
  if (["POST", "PUT", "PATCH"].includes(request.method)) {
82
- body = await request.json().catch(() => ({}));
118
+ const text = await request.text();
119
+ if (text) {
120
+ body = text;
121
+ }
83
122
  }
84
123
 
85
124
  // Faire la requête au backend LastBrain
86
- const response = await fetch(`${baseUrl}${endpoint}`, {
125
+ const response = await fetch(targetUrl, {
87
126
  method: request.method,
88
127
  headers,
89
- body: body ? JSON.stringify(body) : undefined,
128
+ body,
90
129
  });
91
130
 
92
- const data = await response.json().catch(() => ({}));
131
+ // Lire la réponse
132
+ const responseText = await response.text();
133
+ let data: any;
134
+ try {
135
+ data = responseText ? JSON.parse(responseText) : {};
136
+ } catch {
137
+ data = { error: "Invalid JSON response", raw: responseText };
138
+ }
139
+
140
+ // Créer la réponse Next.js
141
+ const nextResponse = NextResponse.json(data, { status: response.status });
93
142
 
94
- if (!response.ok) {
95
- return NextResponse.json(data, { status: response.status });
143
+ // Copier les cookies de la réponse (notamment lb_session)
144
+ const setCookie = response.headers.get("set-cookie");
145
+ if (setCookie) {
146
+ nextResponse.headers.set("set-cookie", setCookie);
96
147
  }
97
148
 
98
- return NextResponse.json(data);
149
+ return nextResponse;
99
150
  } catch (error) {
100
151
  console.error("[LB Proxy] Error:", error);
101
152
  return NextResponse.json(
@@ -105,18 +156,18 @@ export function createLBProxyHandler(config: LBProxyConfig = {}) {
105
156
  }
106
157
  }
107
158
 
108
- // Retourner les handlers pour Next.js
159
+ // Retourner un objet avec les handlers pour chaque méthode HTTP
109
160
  return {
110
- GET: handleRequest,
111
- POST: handleRequest,
112
- PUT: handleRequest,
113
- DELETE: handleRequest,
114
- PATCH: handleRequest,
161
+ GET: handler,
162
+ POST: handler,
163
+ PUT: handler,
164
+ DELETE: handler,
165
+ PATCH: handler,
115
166
  };
116
167
  }
117
168
 
118
169
  /**
119
- * Helper pour définir un cookie de session HttpOnly
170
+ * Helper pour ajouter ou mettre à jour le cookie de session
120
171
  */
121
172
  export function setLBSessionCookie(
122
173
  response: NextResponse,