@lastbrain/app 0.1.39 → 0.1.42
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/cli.js +6 -1
- package/dist/hooks/useNotifications.d.ts +1 -0
- package/dist/hooks/useNotifications.d.ts.map +1 -1
- package/dist/layouts/PublicLayout.js +1 -1
- package/dist/scripts/init-app.js +54 -12
- package/dist/scripts/module-add.d.ts.map +1 -1
- package/dist/scripts/module-add.js +28 -10
- package/dist/scripts/module-build.d.ts.map +1 -1
- package/dist/scripts/module-build.js +432 -48
- package/dist/scripts/module-list.d.ts.map +1 -1
- package/dist/scripts/module-list.js +38 -8
- package/dist/styles.css +1 -1
- package/dist/templates/DefaultDoc.d.ts.map +1 -1
- package/dist/templates/DefaultDoc.js +2 -2
- package/package.json +2 -2
- package/src/cli.ts +6 -1
- package/src/hooks/useNotifications.ts +1 -0
- package/src/layouts/PublicLayout.tsx +1 -1
- package/src/scripts/init-app.ts +56 -12
- package/src/scripts/module-add.ts +44 -11
- package/src/scripts/module-build.ts +499 -54
- package/src/scripts/module-list.ts +45 -8
- package/src/templates/DefaultDoc.tsx +325 -12
package/src/scripts/init-app.ts
CHANGED
|
@@ -903,7 +903,7 @@ async function createConfigFiles(
|
|
|
903
903
|
) {
|
|
904
904
|
console.log(chalk.yellow("\n⚙️ Création des fichiers de configuration..."));
|
|
905
905
|
|
|
906
|
-
// middleware.ts - Protection des routes /auth/* et /admin/*
|
|
906
|
+
// middleware.ts - Protection des routes /auth/*, /admin/* et /api/admin/*
|
|
907
907
|
const middlewarePath = path.join(targetDir, "middleware.ts");
|
|
908
908
|
if (!fs.existsSync(middlewarePath) || force) {
|
|
909
909
|
const middleware = `import { type NextRequest, NextResponse } from "next/server";
|
|
@@ -911,6 +911,7 @@ import { createMiddlewareClient } from "@lastbrain/core/server";
|
|
|
911
911
|
|
|
912
912
|
export async function middleware(request: NextRequest) {
|
|
913
913
|
const { pathname } = request.nextUrl;
|
|
914
|
+
const isApi = pathname.startsWith("/api/");
|
|
914
915
|
|
|
915
916
|
// Protéger les routes /auth/* (espace membre)
|
|
916
917
|
if (pathname.startsWith("/auth")) {
|
|
@@ -920,33 +921,56 @@ export async function middleware(request: NextRequest) {
|
|
|
920
921
|
data: { session },
|
|
921
922
|
} = await supabase.auth.getSession();
|
|
922
923
|
|
|
923
|
-
// Pas de session → redirection vers /signin
|
|
924
|
+
// Pas de session → nettoyage des cookies + redirection vers /auth/signin
|
|
924
925
|
if (!session) {
|
|
925
|
-
const redirectUrl = new URL("/signin", request.url);
|
|
926
|
+
const redirectUrl = new URL("/auth/signin", request.url);
|
|
926
927
|
redirectUrl.searchParams.set("redirect", pathname);
|
|
927
|
-
|
|
928
|
+
const res = NextResponse.redirect(redirectUrl);
|
|
929
|
+
res.cookies.delete("sb-access-token");
|
|
930
|
+
res.cookies.delete("sb-refresh-token");
|
|
931
|
+
res.cookies.delete("sb:token");
|
|
932
|
+
res.cookies.delete("sb:refresh-token");
|
|
933
|
+
return res;
|
|
928
934
|
}
|
|
929
935
|
|
|
930
936
|
return response;
|
|
931
937
|
} catch (error) {
|
|
932
938
|
console.error("Middleware auth error:", error);
|
|
933
|
-
|
|
939
|
+
const res = NextResponse.redirect(new URL("/auth/signin", request.url));
|
|
940
|
+
res.cookies.delete("sb-access-token");
|
|
941
|
+
res.cookies.delete("sb-refresh-token");
|
|
942
|
+
res.cookies.delete("sb:token");
|
|
943
|
+
res.cookies.delete("sb:refresh-token");
|
|
944
|
+
return res;
|
|
934
945
|
}
|
|
935
946
|
}
|
|
936
947
|
|
|
937
|
-
// Protéger les routes /admin/* (superadmin uniquement)
|
|
938
|
-
if (pathname.startsWith("/admin")) {
|
|
948
|
+
// Protéger les routes /admin/* et /api/admin/* (superadmin uniquement)
|
|
949
|
+
if (pathname.startsWith("/admin") || pathname.startsWith("/api/admin")) {
|
|
939
950
|
try {
|
|
940
951
|
const { supabase, response } = createMiddlewareClient(request);
|
|
941
952
|
const {
|
|
942
953
|
data: { session },
|
|
943
954
|
} = await supabase.auth.getSession();
|
|
944
955
|
|
|
945
|
-
// Pas de session → redirection vers /signin
|
|
956
|
+
// Pas de session → 401 JSON pour API, sinon redirection vers /auth/signin avec nettoyage cookies
|
|
946
957
|
if (!session) {
|
|
947
|
-
|
|
958
|
+
if (isApi) {
|
|
959
|
+
const res = NextResponse.json({ error: "Non authentifié" }, { status: 401 });
|
|
960
|
+
res.cookies.delete("sb-access-token");
|
|
961
|
+
res.cookies.delete("sb-refresh-token");
|
|
962
|
+
res.cookies.delete("sb:token");
|
|
963
|
+
res.cookies.delete("sb:refresh-token");
|
|
964
|
+
return res;
|
|
965
|
+
}
|
|
966
|
+
const redirectUrl = new URL("/auth/signin", request.url);
|
|
948
967
|
redirectUrl.searchParams.set("redirect", pathname);
|
|
949
|
-
|
|
968
|
+
const res = NextResponse.redirect(redirectUrl);
|
|
969
|
+
res.cookies.delete("sb-access-token");
|
|
970
|
+
res.cookies.delete("sb-refresh-token");
|
|
971
|
+
res.cookies.delete("sb:token");
|
|
972
|
+
res.cookies.delete("sb:refresh-token");
|
|
973
|
+
return res;
|
|
950
974
|
}
|
|
951
975
|
|
|
952
976
|
// Vérifier si l'utilisateur est superadmin
|
|
@@ -957,13 +981,24 @@ export async function middleware(request: NextRequest) {
|
|
|
957
981
|
|
|
958
982
|
if (error || !isSuperAdmin) {
|
|
959
983
|
console.error("Access denied: not a superadmin", error);
|
|
984
|
+
if (isApi) {
|
|
985
|
+
return NextResponse.json({ error: "Accès refusé" }, { status: 403 });
|
|
986
|
+
}
|
|
960
987
|
return NextResponse.redirect(new URL("/", request.url));
|
|
961
988
|
}
|
|
962
989
|
|
|
963
990
|
return response;
|
|
964
991
|
} catch (error) {
|
|
965
992
|
console.error("Middleware admin error:", error);
|
|
966
|
-
|
|
993
|
+
if (isApi) {
|
|
994
|
+
return NextResponse.json({ error: "Erreur middleware" }, { status: 500 });
|
|
995
|
+
}
|
|
996
|
+
const res = NextResponse.redirect(new URL("/", request.url));
|
|
997
|
+
res.cookies.delete("sb-access-token");
|
|
998
|
+
res.cookies.delete("sb-refresh-token");
|
|
999
|
+
res.cookies.delete("sb:token");
|
|
1000
|
+
res.cookies.delete("sb:refresh-token");
|
|
1001
|
+
return res;
|
|
967
1002
|
}
|
|
968
1003
|
}
|
|
969
1004
|
|
|
@@ -985,7 +1020,9 @@ export const config = {
|
|
|
985
1020
|
`;
|
|
986
1021
|
await fs.writeFile(middlewarePath, middleware);
|
|
987
1022
|
console.log(
|
|
988
|
-
chalk.green(
|
|
1023
|
+
chalk.green(
|
|
1024
|
+
"✓ middleware.ts créé (protection /auth/*, /admin/* et /api/admin/*)",
|
|
1025
|
+
),
|
|
989
1026
|
);
|
|
990
1027
|
}
|
|
991
1028
|
|
|
@@ -1561,6 +1598,13 @@ export const BUCKET_CONFIGS: Record<string, BucketConfig> = {
|
|
|
1561
1598
|
return filePath.startsWith(\`\${userId}/\`);
|
|
1562
1599
|
},
|
|
1563
1600
|
},
|
|
1601
|
+
recipes: {
|
|
1602
|
+
name: "recipes",
|
|
1603
|
+
isPublic: true,
|
|
1604
|
+
description: "Public recipe images accessible by slug",
|
|
1605
|
+
allowedFileTypes: ["image/jpeg", "image/png", "image/webp", "image/gif"],
|
|
1606
|
+
maxFileSize: 50 * 1024 * 1024, // 50MB
|
|
1607
|
+
},
|
|
1564
1608
|
// Example for future buckets:
|
|
1565
1609
|
// public: {
|
|
1566
1610
|
// name: "public",
|
|
@@ -204,16 +204,49 @@ export async function addModule(moduleName: string, targetDir: string) {
|
|
|
204
204
|
console.log(
|
|
205
205
|
chalk.yellow("\n⬆️ Application des nouvelles migrations..."),
|
|
206
206
|
);
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
207
|
+
|
|
208
|
+
// Appliquer directement avec psql au lieu de supabase migration up
|
|
209
|
+
const migrationsDir = path.join(targetDir, "supabase", "migrations");
|
|
210
|
+
const migrationFiles = fs
|
|
211
|
+
.readdirSync(migrationsDir)
|
|
212
|
+
.filter((f) => f.endsWith(".sql"))
|
|
213
|
+
.filter((f) => copiedMigrationFiles.includes(f))
|
|
214
|
+
.sort();
|
|
215
|
+
|
|
216
|
+
if (migrationFiles.length === 0) {
|
|
217
|
+
console.log(
|
|
218
|
+
chalk.yellow("⚠️ Aucune nouvelle migration à appliquer"),
|
|
216
219
|
);
|
|
220
|
+
} else {
|
|
221
|
+
try {
|
|
222
|
+
const dbUrl =
|
|
223
|
+
"postgresql://postgres:postgres@127.0.0.1:54322/postgres";
|
|
224
|
+
|
|
225
|
+
for (const file of migrationFiles) {
|
|
226
|
+
const filePath = path.join(migrationsDir, file);
|
|
227
|
+
console.log(chalk.gray(` Exécution de ${file}...`));
|
|
228
|
+
|
|
229
|
+
execSync(`psql "${dbUrl}" -f "${filePath}"`, {
|
|
230
|
+
cwd: targetDir,
|
|
231
|
+
stdio: "pipe",
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
console.log(
|
|
236
|
+
chalk.green(
|
|
237
|
+
`✓ ${migrationFiles.length} migration(s) appliquée(s)`,
|
|
238
|
+
),
|
|
239
|
+
);
|
|
240
|
+
} catch (error: any) {
|
|
241
|
+
console.error(
|
|
242
|
+
chalk.red("❌ Erreur lors de l'application des migrations"),
|
|
243
|
+
);
|
|
244
|
+
console.log(
|
|
245
|
+
chalk.gray(
|
|
246
|
+
"\nVous pouvez essayer manuellement:\n supabase db reset\n",
|
|
247
|
+
),
|
|
248
|
+
);
|
|
249
|
+
}
|
|
217
250
|
}
|
|
218
251
|
} else {
|
|
219
252
|
console.log(
|
|
@@ -287,13 +320,13 @@ export async function addModule(moduleName: string, targetDir: string) {
|
|
|
287
320
|
// 7. Générer automatiquement les routes du module
|
|
288
321
|
console.log(chalk.yellow("🔧 Génération des routes du module..."));
|
|
289
322
|
try {
|
|
290
|
-
execSync("pnpm build:modules", { cwd: targetDir, stdio: "inherit" });
|
|
323
|
+
execSync("pnpm run build:modules", { cwd: targetDir, stdio: "inherit" });
|
|
291
324
|
console.log(chalk.green("✓ Routes du module générées"));
|
|
292
325
|
} catch {
|
|
293
326
|
console.error(chalk.red("❌ Erreur lors de la génération des routes"));
|
|
294
327
|
console.error(
|
|
295
328
|
chalk.gray(
|
|
296
|
-
"Vous pouvez les générer manuellement avec: pnpm build:modules",
|
|
329
|
+
"Vous pouvez les générer manuellement avec: cd apps/<votre-app> && pnpm run build:modules",
|
|
297
330
|
),
|
|
298
331
|
);
|
|
299
332
|
}
|