@lastbrain/app 0.1.26 → 0.1.27
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/scripts/db-init.js +1 -1
- package/dist/scripts/dev-sync.js +2 -2
- package/dist/scripts/init-app.d.ts.map +1 -1
- package/dist/scripts/init-app.js +2 -2
- package/dist/scripts/module-add.d.ts.map +1 -1
- package/dist/scripts/module-add.js +1 -1
- package/dist/scripts/module-build.d.ts.map +1 -1
- package/dist/scripts/module-build.js +19 -16
- package/dist/scripts/module-remove.js +5 -5
- package/package.json +1 -1
- package/src/scripts/db-init.ts +1 -1
- package/src/scripts/db-migrations-sync.ts +1 -1
- package/src/scripts/dev-sync.ts +2 -2
- package/src/scripts/init-app.ts +15 -7
- package/src/scripts/module-add.ts +7 -3
- package/src/scripts/module-build.ts +65 -46
- package/src/scripts/module-remove.ts +5 -5
package/dist/scripts/db-init.js
CHANGED
package/dist/scripts/dev-sync.js
CHANGED
|
@@ -50,13 +50,13 @@ function syncFile(src, dest) {
|
|
|
50
50
|
fs.writeFileSync(dest, content);
|
|
51
51
|
return dest;
|
|
52
52
|
}
|
|
53
|
-
function
|
|
53
|
+
function _copyDirectory(srcDir, destDir) {
|
|
54
54
|
const stats = fs.statSync(srcDir);
|
|
55
55
|
if (stats.isDirectory()) {
|
|
56
56
|
ensureDirectory(destDir);
|
|
57
57
|
const entries = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
58
58
|
for (const entry of entries) {
|
|
59
|
-
|
|
59
|
+
_copyDirectory(path.join(srcDir, entry.name), path.join(destDir, entry.name));
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
else if (stats.isFile()) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-app.d.ts","sourceRoot":"","sources":["../../src/scripts/init-app.ts"],"names":[],"mappings":"AAWA,UAAU,cAAc;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"init-app.d.ts","sourceRoot":"","sources":["../../src/scripts/init-app.ts"],"names":[],"mappings":"AAWA,UAAU,cAAc;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,iBAwMpD"}
|
package/dist/scripts/init-app.js
CHANGED
|
@@ -94,7 +94,7 @@ export async function initApp(options) {
|
|
|
94
94
|
execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
|
|
95
95
|
console.log(chalk.green("\n✓ Base de données initialisée\n"));
|
|
96
96
|
}
|
|
97
|
-
catch
|
|
97
|
+
catch {
|
|
98
98
|
console.log(chalk.yellow("\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"));
|
|
99
99
|
}
|
|
100
100
|
// Détecter le port (par défaut 3000 pour Next.js)
|
|
@@ -491,7 +491,7 @@ export default function AdminLayout({
|
|
|
491
491
|
}`;
|
|
492
492
|
}
|
|
493
493
|
else if (routeName === "auth") {
|
|
494
|
-
// Layout auth avec sidebar
|
|
494
|
+
// Layout auth avec sidebar
|
|
495
495
|
layoutContent = `import { AuthLayoutWithSidebar } from "@lastbrain/app";
|
|
496
496
|
import { menuConfig } from "../../config/menu";
|
|
497
497
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-add.d.ts","sourceRoot":"","sources":["../../src/scripts/module-add.ts"],"names":[],"mappings":"AAMA,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAGD,eAAO,MAAM,iBAAiB,EAAE,gBAAgB,EAqB/C,CAAC;AAEF,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"module-add.d.ts","sourceRoot":"","sources":["../../src/scripts/module-add.ts"],"names":[],"mappings":"AAMA,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAGD,eAAO,MAAM,iBAAiB,EAAE,gBAAgB,EAqB/C,CAAC;AAEF,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,iBAuOpE"}
|
|
@@ -183,7 +183,7 @@ export async function addModule(moduleName, targetDir) {
|
|
|
183
183
|
execSync("pnpm build:modules", { cwd: targetDir, stdio: "inherit" });
|
|
184
184
|
console.log(chalk.green("✓ Routes du module générées"));
|
|
185
185
|
}
|
|
186
|
-
catch
|
|
186
|
+
catch {
|
|
187
187
|
console.error(chalk.red("❌ Erreur lors de la génération des routes"));
|
|
188
188
|
console.error(chalk.gray("Vous pouvez les générer manuellement avec: pnpm build:modules"));
|
|
189
189
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-build.d.ts","sourceRoot":"","sources":["../../src/scripts/module-build.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"module-build.d.ts","sourceRoot":"","sources":["../../src/scripts/module-build.ts"],"names":[],"mappings":"AA6wBA,wBAAsB,cAAc,kBA4CnC"}
|
|
@@ -115,13 +115,14 @@ function toPascalCase(value) {
|
|
|
115
115
|
function buildPage(moduleConfig, page) {
|
|
116
116
|
// Extraire le préfixe du module (ex: @lastbrain/module-auth -> auth)
|
|
117
117
|
const modulePrefix = moduleConfig.moduleName
|
|
118
|
-
.replace(/^@lastbrain\/module-/,
|
|
118
|
+
.replace(/^@lastbrain\/module-/, "")
|
|
119
119
|
.toLowerCase();
|
|
120
120
|
console.log(`🔄 Building page for module ${modulePrefix}: ${page.path}`);
|
|
121
|
-
// Ajouter le préfixe du module au path pour les sections admin et auth,
|
|
121
|
+
// Ajouter le préfixe du module au path pour les sections admin et auth,
|
|
122
122
|
// MAIS seulement quand la section ne correspond PAS au module lui-même
|
|
123
123
|
let effectivePath = page.path;
|
|
124
|
-
if (page.section ===
|
|
124
|
+
if (page.section === "admin" ||
|
|
125
|
+
(page.section === "auth" && modulePrefix !== "auth")) {
|
|
125
126
|
// Éviter les doublons si le préfixe est déjà présent
|
|
126
127
|
if (!page.path.startsWith(`/${modulePrefix}/`)) {
|
|
127
128
|
effectivePath = `/${modulePrefix}${page.path}`;
|
|
@@ -131,7 +132,7 @@ function buildPage(moduleConfig, page) {
|
|
|
131
132
|
console.log(`✅ Module prefix already present: ${page.path}`);
|
|
132
133
|
}
|
|
133
134
|
}
|
|
134
|
-
else if (page.section ===
|
|
135
|
+
else if (page.section === "auth" && modulePrefix === "auth") {
|
|
135
136
|
console.log(`🏠 Auth module in auth section, no prefix needed: ${page.path}`);
|
|
136
137
|
}
|
|
137
138
|
const segments = effectivePath.replace(/^\/+/, "").split("/").filter(Boolean);
|
|
@@ -457,7 +458,7 @@ function cleanGeneratedFiles() {
|
|
|
457
458
|
"middleware.ts",
|
|
458
459
|
// Dossiers de lib et config
|
|
459
460
|
"lib",
|
|
460
|
-
"config"
|
|
461
|
+
"config",
|
|
461
462
|
]);
|
|
462
463
|
// Fonction pour vérifier si un chemin est protégé
|
|
463
464
|
const isProtected = (filePath) => {
|
|
@@ -467,7 +468,8 @@ function cleanGeneratedFiles() {
|
|
|
467
468
|
return true;
|
|
468
469
|
}
|
|
469
470
|
// Protection par préfixe pour les dossiers
|
|
470
|
-
return Array.from(protectedFiles).some(protectedPath => (protectedPath.endsWith(
|
|
471
|
+
return Array.from(protectedFiles).some((protectedPath) => (protectedPath.endsWith("/") ||
|
|
472
|
+
["lib", "config", "api/storage"].includes(protectedPath)) &&
|
|
471
473
|
relativePath.startsWith(protectedPath));
|
|
472
474
|
};
|
|
473
475
|
// Fonction pour nettoyer récursivement un dossier
|
|
@@ -488,24 +490,25 @@ function cleanGeneratedFiles() {
|
|
|
488
490
|
console.log(`🗑️ Removed empty directory: ${itemPath}`);
|
|
489
491
|
}
|
|
490
492
|
}
|
|
491
|
-
catch
|
|
492
|
-
// Ignorer les erreurs de suppression de
|
|
493
|
+
catch {
|
|
494
|
+
// Ignorer les erreurs de suppression de fichiers
|
|
493
495
|
}
|
|
494
496
|
}
|
|
495
|
-
else if (item.endsWith(
|
|
497
|
+
else if (item.endsWith(".tsx") || item.endsWith(".ts")) {
|
|
496
498
|
// Vérifier si c'est un fichier généré
|
|
497
499
|
if (!isProtected(itemPath)) {
|
|
498
500
|
try {
|
|
499
|
-
const content = fs.readFileSync(itemPath,
|
|
501
|
+
const content = fs.readFileSync(itemPath, "utf-8");
|
|
500
502
|
// Supprimer les fichiers générés ou les wrapper simples de modules
|
|
501
503
|
if (content.includes(generatedComment) ||
|
|
502
504
|
content.includes('from "@lastbrain/module-') ||
|
|
503
|
-
content.includes(
|
|
505
|
+
(content.includes("export {") &&
|
|
506
|
+
content.includes('} from "@lastbrain/module-'))) {
|
|
504
507
|
fs.unlinkSync(itemPath);
|
|
505
508
|
console.log(`🗑️ Cleaned generated file: ${itemPath}`);
|
|
506
509
|
}
|
|
507
510
|
}
|
|
508
|
-
catch
|
|
511
|
+
catch {
|
|
509
512
|
// Ignorer les erreurs de lecture/suppression
|
|
510
513
|
}
|
|
511
514
|
}
|
|
@@ -516,16 +519,16 @@ function cleanGeneratedFiles() {
|
|
|
516
519
|
}
|
|
517
520
|
};
|
|
518
521
|
// Nettoyer les dossiers de sections
|
|
519
|
-
const sectionsToClean = [
|
|
520
|
-
sectionsToClean.forEach(section => {
|
|
522
|
+
const sectionsToClean = ["(public)", "auth", "admin", "api"];
|
|
523
|
+
sectionsToClean.forEach((section) => {
|
|
521
524
|
const sectionPath = path.join(appDirectory, section);
|
|
522
525
|
if (fs.existsSync(sectionPath)) {
|
|
523
526
|
cleanDirectory(sectionPath);
|
|
524
527
|
}
|
|
525
528
|
});
|
|
526
529
|
// Nettoyer les fichiers générés à la racine
|
|
527
|
-
const rootFiles = [
|
|
528
|
-
rootFiles.forEach(file => {
|
|
530
|
+
const rootFiles = ["navigation.generated.ts"];
|
|
531
|
+
rootFiles.forEach((file) => {
|
|
529
532
|
const filePath = path.join(appDirectory, file);
|
|
530
533
|
if (fs.existsSync(filePath)) {
|
|
531
534
|
fs.unlinkSync(filePath);
|
|
@@ -193,7 +193,7 @@ export async function removeModule(moduleName, targetDir) {
|
|
|
193
193
|
}
|
|
194
194
|
console.log(chalk.green(` ✓ ${downFile}`));
|
|
195
195
|
}
|
|
196
|
-
catch
|
|
196
|
+
catch {
|
|
197
197
|
console.error(chalk.red(` ❌ Erreur avec ${downFile}`));
|
|
198
198
|
}
|
|
199
199
|
}
|
|
@@ -213,7 +213,7 @@ export async function removeModule(moduleName, targetDir) {
|
|
|
213
213
|
execSync("supabase db reset", { cwd: targetDir, stdio: "inherit" });
|
|
214
214
|
console.log(chalk.green("✓ Base de données réinitialisée"));
|
|
215
215
|
}
|
|
216
|
-
catch
|
|
216
|
+
catch {
|
|
217
217
|
console.error(chalk.red("❌ Erreur lors du reset"));
|
|
218
218
|
}
|
|
219
219
|
}
|
|
@@ -268,7 +268,7 @@ export async function removeModule(moduleName, targetDir) {
|
|
|
268
268
|
fs.writeFileSync(modulesJsonPath, JSON.stringify(modulesConfig, null, 2));
|
|
269
269
|
console.log(chalk.gray("\n✓ Module marqué comme inactif dans modules.json"));
|
|
270
270
|
}
|
|
271
|
-
catch
|
|
271
|
+
catch {
|
|
272
272
|
console.error(chalk.red("❌ Erreur lors de la mise à jour de modules.json"));
|
|
273
273
|
}
|
|
274
274
|
}
|
|
@@ -277,7 +277,7 @@ export async function removeModule(moduleName, targetDir) {
|
|
|
277
277
|
try {
|
|
278
278
|
execSync("pnpm install", { cwd: targetDir, stdio: "inherit" });
|
|
279
279
|
}
|
|
280
|
-
catch
|
|
280
|
+
catch {
|
|
281
281
|
console.error(chalk.red("❌ Erreur lors du nettoyage"));
|
|
282
282
|
process.exit(1);
|
|
283
283
|
}
|
|
@@ -288,7 +288,7 @@ export async function removeModule(moduleName, targetDir) {
|
|
|
288
288
|
execSync("pnpm run build:modules", { cwd: targetDir, stdio: "inherit" });
|
|
289
289
|
console.log(chalk.green("✓ Modules mis à jour"));
|
|
290
290
|
}
|
|
291
|
-
catch
|
|
291
|
+
catch {
|
|
292
292
|
console.warn(chalk.yellow("⚠️ Erreur lors de la mise à jour des modules"));
|
|
293
293
|
}
|
|
294
294
|
console.log(chalk.gray("Le serveur de développement redémarrera automatiquement.\n"));
|
package/package.json
CHANGED
package/src/scripts/db-init.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { fileURLToPath as _fileURLToPath } from "node:url";
|
|
4
4
|
|
|
5
5
|
import { getModuleConfigs } from "../modules/module-loader.js";
|
|
6
6
|
import type { ModuleBuildConfig } from "@lastbrain/core";
|
package/src/scripts/dev-sync.ts
CHANGED
|
@@ -66,13 +66,13 @@ function syncFile(src: string, dest: string) {
|
|
|
66
66
|
return dest;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
function
|
|
69
|
+
function _copyDirectory(srcDir: string, destDir: string) {
|
|
70
70
|
const stats = fs.statSync(srcDir);
|
|
71
71
|
if (stats.isDirectory()) {
|
|
72
72
|
ensureDirectory(destDir);
|
|
73
73
|
const entries = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
74
74
|
for (const entry of entries) {
|
|
75
|
-
|
|
75
|
+
_copyDirectory(
|
|
76
76
|
path.join(srcDir, entry.name),
|
|
77
77
|
path.join(destDir, entry.name),
|
|
78
78
|
);
|
package/src/scripts/init-app.ts
CHANGED
|
@@ -62,7 +62,11 @@ export async function initApp(options: InitAppOptions) {
|
|
|
62
62
|
// En mode non-interactif, installer auth et ai par défaut
|
|
63
63
|
selectedModules.push("auth", "ai");
|
|
64
64
|
withAuth = true;
|
|
65
|
-
console.log(
|
|
65
|
+
console.log(
|
|
66
|
+
chalk.blue(
|
|
67
|
+
"📦 Modules installés par défaut : Authentication, AI Generation\n",
|
|
68
|
+
),
|
|
69
|
+
);
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
// Créer le dossier s'il n'existe pas
|
|
@@ -97,7 +101,7 @@ export async function initApp(options: InitAppOptions) {
|
|
|
97
101
|
if (withAuth && !selectedModules.includes("auth")) {
|
|
98
102
|
selectedModules.push("auth");
|
|
99
103
|
}
|
|
100
|
-
|
|
104
|
+
|
|
101
105
|
if (selectedModules.length > 0) {
|
|
102
106
|
await saveModulesConfig(targetDir, selectedModules, withAuth);
|
|
103
107
|
}
|
|
@@ -134,8 +138,12 @@ export async function initApp(options: InitAppOptions) {
|
|
|
134
138
|
try {
|
|
135
139
|
execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
|
|
136
140
|
console.log(chalk.green("\n✓ Base de données initialisée\n"));
|
|
137
|
-
} catch
|
|
138
|
-
console.log(
|
|
141
|
+
} catch {
|
|
142
|
+
console.log(
|
|
143
|
+
chalk.yellow(
|
|
144
|
+
"\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n",
|
|
145
|
+
),
|
|
146
|
+
);
|
|
139
147
|
}
|
|
140
148
|
|
|
141
149
|
// Détecter le port (par défaut 3000 pour Next.js)
|
|
@@ -578,7 +586,7 @@ export default function NotFound() {
|
|
|
578
586
|
|
|
579
587
|
// Créer le composant AppHeader
|
|
580
588
|
await createAppHeader(targetDir, force);
|
|
581
|
-
|
|
589
|
+
|
|
582
590
|
// Créer le composant AppAside
|
|
583
591
|
await createAppAside(targetDir, force);
|
|
584
592
|
}
|
|
@@ -596,7 +604,7 @@ async function createRoute(
|
|
|
596
604
|
const layoutPath = path.join(routeDir, "layout.tsx");
|
|
597
605
|
if (!fs.existsSync(layoutPath) || force) {
|
|
598
606
|
let layoutContent = "";
|
|
599
|
-
|
|
607
|
+
|
|
600
608
|
if (routeName === "admin") {
|
|
601
609
|
// Layout admin avec sidebar
|
|
602
610
|
layoutContent = `import { AdminLayoutWithSidebar } from "@lastbrain/app";
|
|
@@ -614,7 +622,7 @@ export default function AdminLayout({
|
|
|
614
622
|
);
|
|
615
623
|
}`;
|
|
616
624
|
} else if (routeName === "auth") {
|
|
617
|
-
// Layout auth avec sidebar
|
|
625
|
+
// Layout auth avec sidebar
|
|
618
626
|
layoutContent = `import { AuthLayoutWithSidebar } from "@lastbrain/app";
|
|
619
627
|
import { menuConfig } from "../../config/menu";
|
|
620
628
|
|
|
@@ -251,15 +251,19 @@ export async function addModule(moduleName: string, targetDir: string) {
|
|
|
251
251
|
console.log(
|
|
252
252
|
chalk.green(`\n✅ Module ${module.displayName} ajouté avec succès!\n`),
|
|
253
253
|
);
|
|
254
|
-
|
|
254
|
+
|
|
255
255
|
// 7. Générer automatiquement les routes du module
|
|
256
256
|
console.log(chalk.yellow("🔧 Génération des routes du module..."));
|
|
257
257
|
try {
|
|
258
258
|
execSync("pnpm build:modules", { cwd: targetDir, stdio: "inherit" });
|
|
259
259
|
console.log(chalk.green("✓ Routes du module générées"));
|
|
260
|
-
} catch
|
|
260
|
+
} catch {
|
|
261
261
|
console.error(chalk.red("❌ Erreur lors de la génération des routes"));
|
|
262
|
-
console.error(
|
|
262
|
+
console.error(
|
|
263
|
+
chalk.gray(
|
|
264
|
+
"Vous pouvez les générer manuellement avec: pnpm build:modules",
|
|
265
|
+
),
|
|
266
|
+
);
|
|
263
267
|
}
|
|
264
268
|
|
|
265
269
|
console.log(
|
|
@@ -153,15 +153,18 @@ function toPascalCase(value: string) {
|
|
|
153
153
|
function buildPage(moduleConfig: ModuleBuildConfig, page: ModulePageConfig) {
|
|
154
154
|
// Extraire le préfixe du module (ex: @lastbrain/module-auth -> auth)
|
|
155
155
|
const modulePrefix = moduleConfig.moduleName
|
|
156
|
-
.replace(/^@lastbrain\/module-/,
|
|
156
|
+
.replace(/^@lastbrain\/module-/, "")
|
|
157
157
|
.toLowerCase();
|
|
158
|
-
|
|
158
|
+
|
|
159
159
|
console.log(`🔄 Building page for module ${modulePrefix}: ${page.path}`);
|
|
160
|
-
|
|
161
|
-
// Ajouter le préfixe du module au path pour les sections admin et auth,
|
|
160
|
+
|
|
161
|
+
// Ajouter le préfixe du module au path pour les sections admin et auth,
|
|
162
162
|
// MAIS seulement quand la section ne correspond PAS au module lui-même
|
|
163
163
|
let effectivePath = page.path;
|
|
164
|
-
if (
|
|
164
|
+
if (
|
|
165
|
+
page.section === "admin" ||
|
|
166
|
+
(page.section === "auth" && modulePrefix !== "auth")
|
|
167
|
+
) {
|
|
165
168
|
// Éviter les doublons si le préfixe est déjà présent
|
|
166
169
|
if (!page.path.startsWith(`/${modulePrefix}/`)) {
|
|
167
170
|
effectivePath = `/${modulePrefix}${page.path}`;
|
|
@@ -169,10 +172,12 @@ function buildPage(moduleConfig: ModuleBuildConfig, page: ModulePageConfig) {
|
|
|
169
172
|
} else {
|
|
170
173
|
console.log(`✅ Module prefix already present: ${page.path}`);
|
|
171
174
|
}
|
|
172
|
-
} else if (page.section ===
|
|
173
|
-
console.log(
|
|
175
|
+
} else if (page.section === "auth" && modulePrefix === "auth") {
|
|
176
|
+
console.log(
|
|
177
|
+
`🏠 Auth module in auth section, no prefix needed: ${page.path}`,
|
|
178
|
+
);
|
|
174
179
|
}
|
|
175
|
-
|
|
180
|
+
|
|
176
181
|
const segments = effectivePath.replace(/^\/+/, "").split("/").filter(Boolean);
|
|
177
182
|
const sectionPath = sectionDirectoryMap[page.section] ?? ["(public)"];
|
|
178
183
|
|
|
@@ -517,16 +522,20 @@ ${moduleConfigurations.join(",\n")}
|
|
|
517
522
|
console.log(`📚 Generated docs page: ${docsPagePath}`);
|
|
518
523
|
}
|
|
519
524
|
|
|
520
|
-
function buildGroupedApi(
|
|
525
|
+
function buildGroupedApi(
|
|
526
|
+
apis: Array<{ moduleConfig: ModuleBuildConfig; api: ModuleApiConfig }>,
|
|
527
|
+
routePath: string,
|
|
528
|
+
) {
|
|
521
529
|
const segments = routePath.replace(/^\/+/, "").split("/").filter(Boolean);
|
|
522
|
-
const sanitizedSegments =
|
|
530
|
+
const sanitizedSegments =
|
|
531
|
+
segments[0] === "api" ? segments.slice(1) : segments;
|
|
523
532
|
const routeDir = path.join(appDirectory, "api", ...sanitizedSegments);
|
|
524
533
|
const filePath = path.join(routeDir, "route.ts");
|
|
525
534
|
ensureDirectory(routeDir);
|
|
526
535
|
|
|
527
536
|
// Grouper par module/entryPoint pour créer les exports
|
|
528
537
|
const exportsBySource = new Map<string, string[]>();
|
|
529
|
-
|
|
538
|
+
|
|
530
539
|
apis.forEach(({ moduleConfig, api }) => {
|
|
531
540
|
const handler = `${moduleConfig.moduleName}/${api.entryPoint}`;
|
|
532
541
|
if (!exportsBySource.has(handler)) {
|
|
@@ -542,11 +551,11 @@ function buildGroupedApi(apis: Array<{ moduleConfig: ModuleBuildConfig; api: Mod
|
|
|
542
551
|
});
|
|
543
552
|
|
|
544
553
|
const content = exportStatements.join("\n") + "\n";
|
|
545
|
-
|
|
554
|
+
|
|
546
555
|
// Ajouter le marqueur de génération au début
|
|
547
556
|
const contentWithMarker = `// GENERATED BY LASTBRAIN MODULE BUILD
|
|
548
557
|
${content}`;
|
|
549
|
-
|
|
558
|
+
|
|
550
559
|
fs.writeFileSync(filePath, contentWithMarker);
|
|
551
560
|
console.log(`🔌 Generated API route: ${filePath}`);
|
|
552
561
|
}
|
|
@@ -561,77 +570,82 @@ function getModuleDescription(moduleConfig: ModuleBuildConfig): string {
|
|
|
561
570
|
|
|
562
571
|
function cleanGeneratedFiles() {
|
|
563
572
|
const generatedComment = "// GENERATED BY LASTBRAIN MODULE BUILD";
|
|
564
|
-
|
|
573
|
+
|
|
565
574
|
// Fichiers de base à préserver (paths relatifs exacts)
|
|
566
575
|
const protectedFiles = new Set([
|
|
567
576
|
// API de base
|
|
568
577
|
"api/storage",
|
|
569
578
|
// Layouts de base
|
|
570
579
|
"layout.tsx",
|
|
571
|
-
"not-found.tsx",
|
|
572
|
-
"page.tsx",
|
|
573
|
-
"admin/page.tsx",
|
|
574
|
-
"admin/layout.tsx",
|
|
575
|
-
"docs/page.tsx",
|
|
580
|
+
"not-found.tsx",
|
|
581
|
+
"page.tsx", // Page racine seulement
|
|
582
|
+
"admin/page.tsx", // Page admin racine
|
|
583
|
+
"admin/layout.tsx", // Layout admin racine
|
|
584
|
+
"docs/page.tsx", // Page docs générée
|
|
576
585
|
// Middleware et autres fichiers core
|
|
577
586
|
"middleware.ts",
|
|
578
587
|
// Dossiers de lib et config
|
|
579
588
|
"lib",
|
|
580
|
-
"config"
|
|
589
|
+
"config",
|
|
581
590
|
]);
|
|
582
591
|
|
|
583
592
|
// Fonction pour vérifier si un chemin est protégé
|
|
584
593
|
const isProtected = (filePath: string) => {
|
|
585
594
|
const relativePath = path.relative(appDirectory, filePath);
|
|
586
|
-
|
|
595
|
+
|
|
587
596
|
// Protection exacte pour certains fichiers
|
|
588
597
|
if (protectedFiles.has(relativePath)) {
|
|
589
598
|
return true;
|
|
590
599
|
}
|
|
591
|
-
|
|
600
|
+
|
|
592
601
|
// Protection par préfixe pour les dossiers
|
|
593
|
-
return Array.from(protectedFiles).some(
|
|
594
|
-
(protectedPath
|
|
595
|
-
|
|
602
|
+
return Array.from(protectedFiles).some(
|
|
603
|
+
(protectedPath) =>
|
|
604
|
+
(protectedPath.endsWith("/") ||
|
|
605
|
+
["lib", "config", "api/storage"].includes(protectedPath)) &&
|
|
606
|
+
relativePath.startsWith(protectedPath),
|
|
596
607
|
);
|
|
597
608
|
};
|
|
598
609
|
|
|
599
610
|
// Fonction pour nettoyer récursivement un dossier
|
|
600
611
|
const cleanDirectory = (dirPath: string) => {
|
|
601
612
|
if (!fs.existsSync(dirPath)) return;
|
|
602
|
-
|
|
613
|
+
|
|
603
614
|
const items = fs.readdirSync(dirPath);
|
|
604
|
-
|
|
615
|
+
|
|
605
616
|
for (const item of items) {
|
|
606
617
|
const itemPath = path.join(dirPath, item);
|
|
607
618
|
const stat = fs.statSync(itemPath);
|
|
608
|
-
|
|
619
|
+
|
|
609
620
|
if (stat.isDirectory()) {
|
|
610
621
|
// Nettoyer récursivement le sous-dossier
|
|
611
622
|
cleanDirectory(itemPath);
|
|
612
|
-
|
|
623
|
+
|
|
613
624
|
// Supprimer le dossier s'il est vide et non protégé
|
|
614
625
|
try {
|
|
615
626
|
if (!isProtected(itemPath) && fs.readdirSync(itemPath).length === 0) {
|
|
616
627
|
fs.rmdirSync(itemPath);
|
|
617
628
|
console.log(`🗑️ Removed empty directory: ${itemPath}`);
|
|
618
629
|
}
|
|
619
|
-
} catch
|
|
620
|
-
// Ignorer les erreurs de suppression de
|
|
630
|
+
} catch {
|
|
631
|
+
// Ignorer les erreurs de suppression de fichiers
|
|
621
632
|
}
|
|
622
|
-
} else if (item.endsWith(
|
|
633
|
+
} else if (item.endsWith(".tsx") || item.endsWith(".ts")) {
|
|
623
634
|
// Vérifier si c'est un fichier généré
|
|
624
635
|
if (!isProtected(itemPath)) {
|
|
625
636
|
try {
|
|
626
|
-
const content = fs.readFileSync(itemPath,
|
|
637
|
+
const content = fs.readFileSync(itemPath, "utf-8");
|
|
627
638
|
// Supprimer les fichiers générés ou les wrapper simples de modules
|
|
628
|
-
if (
|
|
629
|
-
|
|
630
|
-
|
|
639
|
+
if (
|
|
640
|
+
content.includes(generatedComment) ||
|
|
641
|
+
content.includes('from "@lastbrain/module-') ||
|
|
642
|
+
(content.includes("export {") &&
|
|
643
|
+
content.includes('} from "@lastbrain/module-'))
|
|
644
|
+
) {
|
|
631
645
|
fs.unlinkSync(itemPath);
|
|
632
646
|
console.log(`🗑️ Cleaned generated file: ${itemPath}`);
|
|
633
647
|
}
|
|
634
|
-
} catch
|
|
648
|
+
} catch {
|
|
635
649
|
// Ignorer les erreurs de lecture/suppression
|
|
636
650
|
}
|
|
637
651
|
} else {
|
|
@@ -642,8 +656,8 @@ function cleanGeneratedFiles() {
|
|
|
642
656
|
};
|
|
643
657
|
|
|
644
658
|
// Nettoyer les dossiers de sections
|
|
645
|
-
const sectionsToClean = [
|
|
646
|
-
sectionsToClean.forEach(section => {
|
|
659
|
+
const sectionsToClean = ["(public)", "auth", "admin", "api"];
|
|
660
|
+
sectionsToClean.forEach((section) => {
|
|
647
661
|
const sectionPath = path.join(appDirectory, section);
|
|
648
662
|
if (fs.existsSync(sectionPath)) {
|
|
649
663
|
cleanDirectory(sectionPath);
|
|
@@ -651,8 +665,8 @@ function cleanGeneratedFiles() {
|
|
|
651
665
|
});
|
|
652
666
|
|
|
653
667
|
// Nettoyer les fichiers générés à la racine
|
|
654
|
-
const rootFiles = [
|
|
655
|
-
rootFiles.forEach(file => {
|
|
668
|
+
const rootFiles = ["navigation.generated.ts"];
|
|
669
|
+
rootFiles.forEach((file) => {
|
|
656
670
|
const filePath = path.join(appDirectory, file);
|
|
657
671
|
if (fs.existsSync(filePath)) {
|
|
658
672
|
fs.unlinkSync(filePath);
|
|
@@ -665,7 +679,7 @@ function cleanGeneratedFiles() {
|
|
|
665
679
|
|
|
666
680
|
function generateAppAside() {
|
|
667
681
|
const targetPath = path.join(appDirectory, "components", "AppAside.tsx");
|
|
668
|
-
|
|
682
|
+
|
|
669
683
|
// Ne pas écraser si le fichier existe déjà
|
|
670
684
|
if (fs.existsSync(targetPath)) {
|
|
671
685
|
console.log(`⏭️ AppAside already exists, skipping: ${targetPath}`);
|
|
@@ -774,16 +788,21 @@ export async function runModuleBuild() {
|
|
|
774
788
|
|
|
775
789
|
const moduleConfigs = await loadModuleConfigs();
|
|
776
790
|
console.log(`🔍 Loaded ${moduleConfigs.length} module configurations`);
|
|
777
|
-
|
|
791
|
+
|
|
778
792
|
// Générer les pages
|
|
779
793
|
moduleConfigs.forEach((moduleConfig) => {
|
|
780
|
-
console.log(
|
|
794
|
+
console.log(
|
|
795
|
+
`📦 Processing module: ${moduleConfig.moduleName} with ${moduleConfig.pages.length} pages`,
|
|
796
|
+
);
|
|
781
797
|
moduleConfig.pages.forEach((page) => buildPage(moduleConfig, page));
|
|
782
798
|
});
|
|
783
799
|
|
|
784
800
|
// Grouper les APIs par chemin pour éviter les écrasements de fichier
|
|
785
|
-
const apisByPath = new Map<
|
|
786
|
-
|
|
801
|
+
const apisByPath = new Map<
|
|
802
|
+
string,
|
|
803
|
+
Array<{ moduleConfig: ModuleBuildConfig; api: ModuleApiConfig }>
|
|
804
|
+
>();
|
|
805
|
+
|
|
787
806
|
moduleConfigs.forEach((moduleConfig) => {
|
|
788
807
|
moduleConfig.apis.forEach((api) => {
|
|
789
808
|
if (!apisByPath.has(api.path)) {
|
|
@@ -293,7 +293,7 @@ export async function removeModule(moduleName: string, targetDir: string) {
|
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
console.log(chalk.green(` ✓ ${downFile}`));
|
|
296
|
-
} catch
|
|
296
|
+
} catch {
|
|
297
297
|
console.error(chalk.red(` ❌ Erreur avec ${downFile}`));
|
|
298
298
|
}
|
|
299
299
|
}
|
|
@@ -315,7 +315,7 @@ export async function removeModule(moduleName: string, targetDir: string) {
|
|
|
315
315
|
try {
|
|
316
316
|
execSync("supabase db reset", { cwd: targetDir, stdio: "inherit" });
|
|
317
317
|
console.log(chalk.green("✓ Base de données réinitialisée"));
|
|
318
|
-
} catch
|
|
318
|
+
} catch {
|
|
319
319
|
console.error(chalk.red("❌ Erreur lors du reset"));
|
|
320
320
|
}
|
|
321
321
|
} else {
|
|
@@ -391,7 +391,7 @@ export async function removeModule(moduleName: string, targetDir: string) {
|
|
|
391
391
|
console.log(
|
|
392
392
|
chalk.gray("\n✓ Module marqué comme inactif dans modules.json"),
|
|
393
393
|
);
|
|
394
|
-
} catch
|
|
394
|
+
} catch {
|
|
395
395
|
console.error(
|
|
396
396
|
chalk.red("❌ Erreur lors de la mise à jour de modules.json"),
|
|
397
397
|
);
|
|
@@ -402,7 +402,7 @@ export async function removeModule(moduleName: string, targetDir: string) {
|
|
|
402
402
|
console.log(chalk.yellow("\n🧹 Nettoyage des dépendances..."));
|
|
403
403
|
try {
|
|
404
404
|
execSync("pnpm install", { cwd: targetDir, stdio: "inherit" });
|
|
405
|
-
} catch
|
|
405
|
+
} catch {
|
|
406
406
|
console.error(chalk.red("❌ Erreur lors du nettoyage"));
|
|
407
407
|
process.exit(1);
|
|
408
408
|
}
|
|
@@ -416,7 +416,7 @@ export async function removeModule(moduleName: string, targetDir: string) {
|
|
|
416
416
|
try {
|
|
417
417
|
execSync("pnpm run build:modules", { cwd: targetDir, stdio: "inherit" });
|
|
418
418
|
console.log(chalk.green("✓ Modules mis à jour"));
|
|
419
|
-
} catch
|
|
419
|
+
} catch {
|
|
420
420
|
console.warn(chalk.yellow("⚠️ Erreur lors de la mise à jour des modules"));
|
|
421
421
|
}
|
|
422
422
|
|