@lastbrain/app 0.1.24 → 0.1.26

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.
Files changed (87) hide show
  1. package/dist/__tests__/module-registry.test.d.ts +2 -0
  2. package/dist/__tests__/module-registry.test.d.ts.map +1 -0
  3. package/dist/__tests__/module-registry.test.js +64 -0
  4. package/dist/app-shell/(admin)/layout.d.ts +3 -2
  5. package/dist/app-shell/(admin)/layout.d.ts.map +1 -1
  6. package/dist/app-shell/(admin)/layout.js +1 -1
  7. package/dist/app-shell/(auth)/layout.d.ts +3 -2
  8. package/dist/app-shell/(auth)/layout.d.ts.map +1 -1
  9. package/dist/app-shell/(auth)/layout.js +1 -1
  10. package/dist/app-shell/(public)/page.d.ts.map +1 -1
  11. package/dist/cli.js +50 -0
  12. package/dist/index.d.ts +4 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +4 -0
  15. package/dist/layouts/AdminLayout.d.ts +3 -2
  16. package/dist/layouts/AdminLayout.d.ts.map +1 -1
  17. package/dist/layouts/AdminLayoutWithSidebar.d.ts +8 -0
  18. package/dist/layouts/AdminLayoutWithSidebar.d.ts.map +1 -0
  19. package/dist/layouts/AdminLayoutWithSidebar.js +9 -0
  20. package/dist/layouts/AppProviders.d.ts +3 -2
  21. package/dist/layouts/AppProviders.d.ts.map +1 -1
  22. package/dist/layouts/AuthLayout.d.ts +3 -2
  23. package/dist/layouts/AuthLayout.d.ts.map +1 -1
  24. package/dist/layouts/AuthLayoutWithSidebar.d.ts +8 -0
  25. package/dist/layouts/AuthLayoutWithSidebar.d.ts.map +1 -0
  26. package/dist/layouts/AuthLayoutWithSidebar.js +9 -0
  27. package/dist/layouts/PublicLayout.d.ts +3 -2
  28. package/dist/layouts/PublicLayout.d.ts.map +1 -1
  29. package/dist/layouts/RootLayout.d.ts +3 -2
  30. package/dist/layouts/RootLayout.d.ts.map +1 -1
  31. package/dist/scripts/db-init.js +2 -2
  32. package/dist/scripts/db-migrations-sync.js +5 -5
  33. package/dist/scripts/dev-sync.js +21 -10
  34. package/dist/scripts/init-app.d.ts.map +1 -1
  35. package/dist/scripts/init-app.js +126 -21
  36. package/dist/scripts/module-add.d.ts.map +1 -1
  37. package/dist/scripts/module-add.js +20 -7
  38. package/dist/scripts/module-build.d.ts.map +1 -1
  39. package/dist/scripts/module-build.js +285 -30
  40. package/dist/scripts/module-create.d.ts.map +1 -1
  41. package/dist/scripts/module-create.js +25 -15
  42. package/dist/scripts/module-remove.d.ts.map +1 -1
  43. package/dist/scripts/module-remove.js +24 -11
  44. package/dist/scripts/script-runner.d.ts +5 -0
  45. package/dist/scripts/script-runner.d.ts.map +1 -0
  46. package/dist/scripts/script-runner.js +25 -0
  47. package/dist/styles.css +1 -1
  48. package/dist/templates/DefaultDoc.js +1 -7
  49. package/dist/templates/DocPage.d.ts.map +1 -1
  50. package/dist/templates/DocPage.js +14 -14
  51. package/dist/templates/components/AppAside.d.ts +6 -0
  52. package/dist/templates/components/AppAside.d.ts.map +1 -0
  53. package/dist/templates/components/AppAside.js +9 -0
  54. package/dist/templates/layouts/admin-layout.d.ts +4 -0
  55. package/dist/templates/layouts/admin-layout.d.ts.map +1 -0
  56. package/dist/templates/layouts/admin-layout.js +6 -0
  57. package/dist/templates/layouts/auth-layout.d.ts +4 -0
  58. package/dist/templates/layouts/auth-layout.d.ts.map +1 -0
  59. package/dist/templates/layouts/auth-layout.js +6 -0
  60. package/package.json +2 -1
  61. package/src/__tests__/module-registry.test.ts +74 -0
  62. package/src/app-shell/(admin)/layout.tsx +5 -3
  63. package/src/app-shell/(auth)/layout.tsx +5 -3
  64. package/src/app-shell/(public)/page.tsx +6 -2
  65. package/src/auth/useAuthSession.ts +1 -1
  66. package/src/cli.ts +51 -1
  67. package/src/index.ts +6 -0
  68. package/src/layouts/AdminLayout.tsx +1 -3
  69. package/src/layouts/AdminLayoutWithSidebar.tsx +35 -0
  70. package/src/layouts/AppProviders.tsx +3 -5
  71. package/src/layouts/AuthLayout.tsx +1 -3
  72. package/src/layouts/AuthLayoutWithSidebar.tsx +35 -0
  73. package/src/layouts/PublicLayout.tsx +1 -3
  74. package/src/layouts/RootLayout.tsx +1 -2
  75. package/src/scripts/db-init.ts +13 -8
  76. package/src/scripts/db-migrations-sync.ts +4 -4
  77. package/src/scripts/dev-sync.ts +49 -18
  78. package/src/scripts/init-app.ts +246 -73
  79. package/src/scripts/module-add.ts +49 -23
  80. package/src/scripts/module-build.ts +393 -88
  81. package/src/scripts/module-create.ts +85 -49
  82. package/src/scripts/module-remove.ts +116 -57
  83. package/src/scripts/readme-build.ts +2 -2
  84. package/src/scripts/script-runner.ts +28 -0
  85. package/src/templates/AuthGuidePage.tsx +1 -1
  86. package/src/templates/DefaultDoc.tsx +7 -7
  87. package/src/templates/DocPage.tsx +74 -46
@@ -58,6 +58,11 @@ export async function initApp(options: InitAppOptions) {
58
58
  withAuth = selectedModules.includes("auth");
59
59
 
60
60
  console.log();
61
+ } else if (!interactive) {
62
+ // En mode non-interactif, installer auth et ai par défaut
63
+ selectedModules.push("auth", "ai");
64
+ withAuth = true;
65
+ console.log(chalk.blue("📦 Modules installés par défaut : Authentication, AI Generation\n"));
61
66
  }
62
67
 
63
68
  // Créer le dossier s'il n'existe pas
@@ -89,29 +94,34 @@ export async function initApp(options: InitAppOptions) {
89
94
  await addScriptsToPackageJson(targetDir);
90
95
 
91
96
  // 9. Enregistrer les modules sélectionnés
92
- if (withAuth || selectedModules.length > 0) {
97
+ if (withAuth && !selectedModules.includes("auth")) {
98
+ selectedModules.push("auth");
99
+ }
100
+
101
+ if (selectedModules.length > 0) {
93
102
  await saveModulesConfig(targetDir, selectedModules, withAuth);
94
103
  }
95
104
 
96
105
  console.log(
97
- chalk.green("\n✅ Application LastBrain initialisée avec succès!\n")
106
+ chalk.green("\n✅ Application LastBrain initialisée avec succès!\n"),
98
107
  );
99
-
108
+
100
109
  const relativePath = path.relative(process.cwd(), targetDir);
101
-
110
+
102
111
  // Demander si l'utilisateur veut lancer l'installation et le dev server
103
112
  const { launchNow } = await inquirer.prompt([
104
113
  {
105
114
  type: "confirm",
106
115
  name: "launchNow",
107
- message: "Voulez-vous installer les dépendances et lancer le serveur de développement maintenant ?",
116
+ message:
117
+ "Voulez-vous installer les dépendances et lancer le serveur de développement maintenant ?",
108
118
  default: true,
109
119
  },
110
120
  ]);
111
121
 
112
122
  if (launchNow) {
113
123
  console.log(chalk.yellow("\n📦 Installation des dépendances...\n"));
114
-
124
+
115
125
  try {
116
126
  execSync("pnpm install", { cwd: targetDir, stdio: "inherit" });
117
127
  console.log(chalk.green("\n✓ Dépendances installées\n"));
@@ -120,52 +130,82 @@ export async function initApp(options: InitAppOptions) {
120
130
  execSync("pnpm build:modules", { cwd: targetDir, stdio: "inherit" });
121
131
  console.log(chalk.green("\n✓ Routes des modules générées\n"));
122
132
 
133
+ console.log(chalk.yellow("🗄️ Initialisation de la base de données...\n"));
134
+ try {
135
+ execSync("pnpm db:init", { cwd: targetDir, stdio: "inherit" });
136
+ console.log(chalk.green("\n✓ Base de données initialisée\n"));
137
+ } catch (dbError) {
138
+ console.log(chalk.yellow("\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"));
139
+ }
140
+
123
141
  // Détecter le port (par défaut 3000 pour Next.js)
124
142
  const port = 3000;
125
143
  const url = `http://127.0.0.1:${port}`;
126
144
 
127
- console.log(chalk.yellow("🚀 Lancement du serveur de développement...\n"));
145
+ console.log(
146
+ chalk.yellow("🚀 Lancement du serveur de développement...\n"),
147
+ );
128
148
  console.log(chalk.cyan(`📱 Ouvrez votre navigateur sur : ${url}\n`));
129
-
149
+
130
150
  console.log(chalk.blue("\n📋 Prochaines étapes après le démarrage :"));
131
- console.log(chalk.white(" 1. Cliquez sur 'Get Started' sur la page d'accueil"));
151
+ console.log(
152
+ chalk.white(" 1. Cliquez sur 'Get Started' sur la page d'accueil"),
153
+ );
132
154
  console.log(chalk.white(" 2. Lancez Docker Desktop"));
133
- console.log(chalk.white(" 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase"));
155
+ console.log(
156
+ chalk.white(
157
+ " 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase",
158
+ ),
159
+ );
134
160
  console.log(chalk.white(" 4. Exécutez : pnpm db:init"));
135
161
  console.log(chalk.white(" 5. Rechargez la page\n"));
136
162
 
137
163
  // Ouvrir le navigateur
138
- const openCommand = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
164
+ const openCommand =
165
+ process.platform === "darwin"
166
+ ? "open"
167
+ : process.platform === "win32"
168
+ ? "start"
169
+ : "xdg-open";
139
170
  setTimeout(() => {
140
171
  try {
141
172
  execSync(`${openCommand} ${url}`, { stdio: "ignore" });
142
- } catch (error) {
173
+ } catch {
143
174
  // Ignorer les erreurs d'ouverture du navigateur
144
175
  }
145
176
  }, 2000);
146
177
 
147
178
  // Lancer pnpm dev
148
179
  execSync("pnpm dev", { cwd: targetDir, stdio: "inherit" });
149
- } catch (error) {
180
+ } catch {
150
181
  console.error(chalk.red("\n❌ Erreur lors du lancement\n"));
151
182
  console.log(chalk.cyan("\nVous pouvez lancer manuellement avec :"));
152
183
  console.log(chalk.white(` cd ${relativePath}`));
153
184
  console.log(chalk.white(" pnpm install"));
154
185
  console.log(chalk.white(" pnpm build:modules"));
186
+ console.log(chalk.white(" pnpm db:init"));
155
187
  console.log(chalk.white(" pnpm dev\n"));
156
188
  }
157
189
  } else {
158
190
  console.log(chalk.cyan("\n📋 Prochaines étapes:"));
159
191
  console.log(chalk.white(" 1. cd " + relativePath));
160
192
  console.log(chalk.white(" 2. pnpm install (installer les dépendances)"));
161
- console.log(chalk.white(" 3. pnpm build:modules (générer les routes des modules)"));
193
+ console.log(
194
+ chalk.white(" 3. pnpm build:modules (générer les routes des modules)"),
195
+ );
196
+ console.log(
197
+ chalk.white(" 4. pnpm db:init (initialiser la base de données)"),
198
+ );
199
+ console.log(chalk.white(" 5. pnpm dev (lancer le serveur)"));
162
200
  console.log(chalk.white(" 4. pnpm db:init (initialiser Supabase)"));
163
201
  console.log(chalk.white(" 5. pnpm dev (démarrer le serveur)\n"));
164
-
202
+
165
203
  console.log(chalk.gray("Prérequis pour Supabase :"));
166
204
  console.log(chalk.white(" - Docker Desktop installé et lancé"));
167
- console.log(chalk.white(" - Supabase CLI : brew install supabase/tap/supabase\n"));
168
-
205
+ console.log(
206
+ chalk.white(" - Supabase CLI : brew install supabase/tap/supabase\n"),
207
+ );
208
+
169
209
  // Afficher la commande cd pour faciliter la copie
170
210
  console.log(chalk.gray("Pour vous déplacer dans le projet :"));
171
211
  console.log(chalk.cyan(` cd ${relativePath}\n`));
@@ -204,8 +244,11 @@ function getLastBrainVersions(targetDir: string): {
204
244
  ui: string;
205
245
  moduleAuth: string;
206
246
  } {
207
- const targetIsInMonorepo = fs.existsSync(path.join(targetDir, "../../../packages/core/package.json")) ||
208
- fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
247
+ const targetIsInMonorepo =
248
+ fs.existsSync(
249
+ path.join(targetDir, "../../../packages/core/package.json"),
250
+ ) ||
251
+ fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
209
252
 
210
253
  if (targetIsInMonorepo) {
211
254
  // Dans le monorepo, utiliser workspace:*
@@ -221,16 +264,16 @@ function getLastBrainVersions(targetDir: string): {
221
264
  try {
222
265
  // Essayer de lire depuis node_modules/@lastbrain (si init-app a été installé)
223
266
  const appPkgPath = path.join(__dirname, "../../package.json");
224
-
267
+
225
268
  if (fs.existsSync(appPkgPath)) {
226
269
  const appPkg = JSON.parse(fs.readFileSync(appPkgPath, "utf-8"));
227
270
  const appVersion = `^${appPkg.version}`;
228
-
271
+
229
272
  // Lire les versions des dépendances de @lastbrain/app
230
273
  const coreDep = appPkg.dependencies?.["@lastbrain/core"];
231
274
  const uiDep = appPkg.dependencies?.["@lastbrain/ui"];
232
275
  const authDep = appPkg.dependencies?.["@lastbrain/module-auth"];
233
-
276
+
234
277
  return {
235
278
  app: appVersion,
236
279
  core: coreDep || appVersion,
@@ -238,8 +281,12 @@ function getLastBrainVersions(targetDir: string): {
238
281
  moduleAuth: authDep || appVersion,
239
282
  };
240
283
  }
241
- } catch (error) {
242
- console.warn(chalk.yellow("⚠️ Impossible de lire les versions locales, utilisation de 'latest'"));
284
+ } catch {
285
+ console.warn(
286
+ chalk.yellow(
287
+ "⚠️ Impossible de lire les versions locales, utilisation de 'latest'",
288
+ ),
289
+ );
243
290
  }
244
291
 
245
292
  // Fallback: utiliser "latest"
@@ -255,7 +302,7 @@ async function addDependencies(
255
302
  targetDir: string,
256
303
  useHeroUI: boolean,
257
304
  withAuth: boolean,
258
- selectedModules: string[] = []
305
+ selectedModules: string[] = [],
259
306
  ) {
260
307
  const pkgPath = path.join(targetDir, "package.json");
261
308
  const pkg = await fs.readJson(pkgPath);
@@ -263,7 +310,7 @@ async function addDependencies(
263
310
  console.log(chalk.yellow("\n📦 Configuration des dépendances..."));
264
311
 
265
312
  const versions = getLastBrainVersions(targetDir);
266
-
313
+
267
314
  // Dependencies
268
315
  const requiredDeps: Record<string, string> = {
269
316
  next: "^15.0.3",
@@ -282,7 +329,7 @@ async function addDependencies(
282
329
 
283
330
  // Ajouter les autres modules sélectionnés
284
331
  for (const moduleName of selectedModules) {
285
- const moduleInfo = AVAILABLE_MODULES.find(m => m.name === moduleName);
332
+ const moduleInfo = AVAILABLE_MODULES.find((m) => m.name === moduleName);
286
333
  if (moduleInfo && moduleInfo.package !== "@lastbrain/module-auth") {
287
334
  // Pour les autres modules, utiliser "latest" ou la version depuis le package
288
335
  requiredDeps[moduleInfo.package] = versions.app; // Utiliser la même version que app
@@ -292,6 +339,7 @@ async function addDependencies(
292
339
  // Ajouter les dépendances HeroUI si nécessaire
293
340
  if (useHeroUI) {
294
341
  // Tous les packages HeroUI nécessaires (car @lastbrain/ui les ré-exporte)
342
+ requiredDeps["@heroui/system"] = "^2.4.23";
295
343
  requiredDeps["@heroui/theme"] = "^2.4.23";
296
344
  requiredDeps["@heroui/accordion"] = "^2.2.24";
297
345
  requiredDeps["@heroui/alert"] = "^2.2.27";
@@ -326,7 +374,6 @@ async function addDependencies(
326
374
  requiredDeps["@heroui/switch"] = "^2.2.24";
327
375
  requiredDeps["@heroui/table"] = "^2.2.27";
328
376
  requiredDeps["@heroui/tabs"] = "^2.2.24";
329
- requiredDeps["@heroui/system"] = "^2.4.23"; // Ajout pour HeroUIProvider
330
377
  requiredDeps["@heroui/toast"] = "^2.0.17";
331
378
  requiredDeps["@heroui/tooltip"] = "^2.2.24";
332
379
  requiredDeps["@heroui/user"] = "^2.2.22";
@@ -359,7 +406,7 @@ async function createNextStructure(
359
406
  targetDir: string,
360
407
  force: boolean,
361
408
  useHeroUI: boolean,
362
- withAuth: boolean
409
+ withAuth: boolean,
363
410
  ) {
364
411
  console.log(chalk.yellow("\n📁 Création de la structure Next.js..."));
365
412
 
@@ -456,7 +503,9 @@ export default function RootLayout({ children }: PropsWithChildren<{}>) {
456
503
  console.log(chalk.green("✓ app/layout.tsx créé"));
457
504
  } else {
458
505
  console.log(
459
- chalk.gray(" app/layout.tsx existe déjà (utilisez --force pour écraser)")
506
+ chalk.gray(
507
+ " app/layout.tsx existe déjà (utilisez --force pour écraser)",
508
+ ),
460
509
  );
461
510
  }
462
511
 
@@ -524,17 +573,21 @@ export default function NotFound() {
524
573
 
525
574
  // Créer les routes avec leurs layouts
526
575
  await createRoute(appDir, "admin", "admin", force);
576
+ await createRoute(appDir, "auth", "auth", force);
527
577
  await createRoute(appDir, "docs", "public", force);
528
578
 
529
579
  // Créer le composant AppHeader
530
580
  await createAppHeader(targetDir, force);
581
+
582
+ // Créer le composant AppAside
583
+ await createAppAside(targetDir, force);
531
584
  }
532
585
 
533
586
  async function createRoute(
534
587
  appDir: string,
535
588
  routeName: string,
536
589
  layoutType: string,
537
- force: boolean
590
+ force: boolean,
538
591
  ) {
539
592
  const routeDir = path.join(appDir, routeName);
540
593
  await fs.ensureDir(routeDir);
@@ -542,13 +595,49 @@ async function createRoute(
542
595
  // Layout pour la route
543
596
  const layoutPath = path.join(routeDir, "layout.tsx");
544
597
  if (!fs.existsSync(layoutPath) || force) {
545
- const layoutComponent =
546
- layoutType.charAt(0).toUpperCase() + layoutType.slice(1) + "Layout";
598
+ let layoutContent = "";
599
+
600
+ if (routeName === "admin") {
601
+ // Layout admin avec sidebar
602
+ layoutContent = `import { AdminLayoutWithSidebar } from "@lastbrain/app";
603
+ import { menuConfig } from "../../config/menu";
604
+
605
+ export default function AdminLayout({
606
+ children,
607
+ }: {
608
+ children: React.ReactNode;
609
+ }) {
610
+ return (
611
+ <AdminLayoutWithSidebar menuConfig={menuConfig}>
612
+ {children}
613
+ </AdminLayoutWithSidebar>
614
+ );
615
+ }`;
616
+ } else if (routeName === "auth") {
617
+ // Layout auth avec sidebar
618
+ layoutContent = `import { AuthLayoutWithSidebar } from "@lastbrain/app";
619
+ import { menuConfig } from "../../config/menu";
620
+
621
+ export default function AuthLayout({
622
+ children,
623
+ }: {
624
+ children: React.ReactNode;
625
+ }) {
626
+ return (
627
+ <AuthLayoutWithSidebar menuConfig={menuConfig}>
628
+ {children}
629
+ </AuthLayoutWithSidebar>
630
+ );
631
+ }`;
632
+ } else {
633
+ // Layout standard pour les autres routes
634
+ const layoutComponent =
635
+ layoutType.charAt(0).toUpperCase() + layoutType.slice(1) + "Layout";
636
+ layoutContent = `import { ${layoutComponent} } from "@lastbrain/app";
547
637
 
548
- const layoutContent = `import { ${layoutComponent} } from "@lastbrain/app";
638
+ export default ${layoutComponent};`;
639
+ }
549
640
 
550
- export default ${layoutComponent};
551
- `;
552
641
  await fs.writeFile(layoutPath, layoutContent);
553
642
  console.log(chalk.green(`✓ app/${routeName}/layout.tsx créé`));
554
643
  }
@@ -616,7 +705,7 @@ async function createAppHeader(targetDir: string, force: boolean) {
616
705
  await fs.ensureDir(componentsDir);
617
706
 
618
707
  const headerPath = path.join(componentsDir, "AppHeader.tsx");
619
-
708
+
620
709
  if (!fs.existsSync(headerPath) || force) {
621
710
  const headerContent = `"use client";
622
711
 
@@ -652,7 +741,49 @@ export function AppHeader() {
652
741
  console.log(chalk.green("✓ components/AppHeader.tsx créé"));
653
742
  } else {
654
743
  console.log(
655
- chalk.gray(" components/AppHeader.tsx existe déjà (utilisez --force pour écraser)")
744
+ chalk.gray(
745
+ " components/AppHeader.tsx existe déjà (utilisez --force pour écraser)",
746
+ ),
747
+ );
748
+ }
749
+ }
750
+
751
+ async function createAppAside(targetDir: string, force: boolean) {
752
+ const componentsDir = path.join(targetDir, "components");
753
+ await fs.ensureDir(componentsDir);
754
+
755
+ const asidePath = path.join(componentsDir, "AppAside.tsx");
756
+ if (!fs.existsSync(asidePath) || force) {
757
+ const asideContent = `"use client";
758
+
759
+ import { AppAside as UIAppAside } from "@lastbrain/app";
760
+ import { useAuthSession } from "@lastbrain/app";
761
+ import { menuConfig } from "../config/menu";
762
+
763
+ interface AppAsideProps {
764
+ className?: string;
765
+ isVisible?: boolean;
766
+ }
767
+
768
+ export function AppAside({ className = "", isVisible = true }: AppAsideProps) {
769
+ const { isSuperAdmin } = useAuthSession();
770
+
771
+ return (
772
+ <UIAppAside
773
+ className={className}
774
+ menuConfig={menuConfig}
775
+ isSuperAdmin={isSuperAdmin}
776
+ isVisible={isVisible}
777
+ />
778
+ );
779
+ }`;
780
+ await fs.writeFile(asidePath, asideContent);
781
+ console.log(chalk.green("✓ components/AppAside.tsx créé"));
782
+ } else {
783
+ console.log(
784
+ chalk.gray(
785
+ " components/AppAside.tsx existe déjà (utilisez --force pour écraser)",
786
+ ),
656
787
  );
657
788
  }
658
789
  }
@@ -660,7 +791,7 @@ export function AppHeader() {
660
791
  async function createConfigFiles(
661
792
  targetDir: string,
662
793
  force: boolean,
663
- useHeroUI: boolean
794
+ useHeroUI: boolean,
664
795
  ) {
665
796
  console.log(chalk.yellow("\n⚙️ Création des fichiers de configuration..."));
666
797
 
@@ -745,7 +876,9 @@ export const config = {
745
876
  };
746
877
  `;
747
878
  await fs.writeFile(middlewarePath, middleware);
748
- console.log(chalk.green("✓ middleware.ts créé (protection /auth/* et /admin/*)"));
879
+ console.log(
880
+ chalk.green("✓ middleware.ts créé (protection /auth/* et /admin/*)"),
881
+ );
749
882
  }
750
883
 
751
884
  // next.config.mjs
@@ -904,7 +1037,7 @@ async function createGitIgnore(targetDir: string, force: boolean) {
904
1037
  // Copier le fichier .gitignore depuis le template
905
1038
  const templateGitignorePath = path.join(
906
1039
  __dirname,
907
- "../templates/gitignore/.gitignore"
1040
+ "../templates/gitignore/.gitignore",
908
1041
  );
909
1042
 
910
1043
  if (fs.existsSync(templateGitignorePath)) {
@@ -1012,35 +1145,48 @@ async function createSupabaseStructure(targetDir: string, force: boolean) {
1012
1145
  // Copier le fichier de migration initial depuis le template
1013
1146
  const templateMigrationPath = path.join(
1014
1147
  __dirname,
1015
- "../templates/migrations/20201010100000_app_base.sql"
1148
+ "../templates/migrations/20201010100000_app_base.sql",
1016
1149
  );
1017
1150
  const migrationDestPath = path.join(
1018
1151
  migrationsDir,
1019
- "20201010100000_app_base.sql"
1152
+ "20201010100000_app_base.sql",
1020
1153
  );
1021
1154
 
1022
1155
  if (!fs.existsSync(migrationDestPath) || force) {
1023
1156
  try {
1024
1157
  if (fs.existsSync(templateMigrationPath)) {
1025
1158
  await fs.copy(templateMigrationPath, migrationDestPath);
1026
- console.log(chalk.green("✓ supabase/migrations/20201010100000_app_base.sql créé"));
1159
+ console.log(
1160
+ chalk.green("✓ supabase/migrations/20201010100000_app_base.sql créé"),
1161
+ );
1027
1162
  } else {
1028
1163
  console.log(
1029
1164
  chalk.yellow(
1030
- "⚠ Template de migration introuvable, création d'un fichier vide"
1031
- )
1165
+ "⚠ Template de migration introuvable, création d'un fichier vide",
1166
+ ),
1032
1167
  );
1033
1168
  await fs.writeFile(
1034
1169
  migrationDestPath,
1035
- "-- Initial migration\n-- Add your database schema here\n"
1170
+ "-- Initial migration\n-- Add your database schema here\n",
1171
+ );
1172
+ console.log(
1173
+ chalk.green(
1174
+ "✓ supabase/migrations/20201010100000_app_base.sql créé (vide)",
1175
+ ),
1036
1176
  );
1037
- console.log(chalk.green("✓ supabase/migrations/20201010100000_app_base.sql créé (vide)"));
1038
1177
  }
1039
1178
  } catch (error) {
1040
- console.error(chalk.red("✗ Erreur lors de la création de la migration:"), error);
1179
+ console.error(
1180
+ chalk.red("✗ Erreur lors de la création de la migration:"),
1181
+ error,
1182
+ );
1041
1183
  }
1042
1184
  } else {
1043
- console.log(chalk.gray(" supabase/migrations/20201010100000_app_base.sql existe déjà"));
1185
+ console.log(
1186
+ chalk.gray(
1187
+ " supabase/migrations/20201010100000_app_base.sql existe déjà",
1188
+ ),
1189
+ );
1044
1190
  }
1045
1191
  }
1046
1192
 
@@ -1051,26 +1197,34 @@ async function addScriptsToPackageJson(targetDir: string) {
1051
1197
  const pkg = await fs.readJson(pkgPath);
1052
1198
 
1053
1199
  // Détecter si le projet cible est dans un workspace
1054
- const targetIsInMonorepo = fs.existsSync(path.join(targetDir, "../../../packages/core/package.json")) ||
1055
- fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
1200
+ const targetIsInMonorepo =
1201
+ fs.existsSync(
1202
+ path.join(targetDir, "../../../packages/core/package.json"),
1203
+ ) ||
1204
+ fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
1056
1205
 
1057
- let scriptsPrefix = "node node_modules/@lastbrain/app/dist/scripts/";
1058
-
1059
- if (targetIsInMonorepo) {
1060
- // Dans un monorepo, utiliser pnpm exec pour résoudre correctement les workspace packages
1061
- scriptsPrefix = "pnpm exec lastbrain ";
1206
+ let scriptsPrefix = "lastbrain";
1207
+
1208
+ if (!targetIsInMonorepo) {
1209
+ // Hors monorepo, utiliser le chemin direct vers le CLI
1210
+ scriptsPrefix = "node node_modules/@lastbrain/app/dist/cli.js";
1062
1211
  }
1063
1212
 
1064
1213
  const scripts = {
1214
+ predev: targetIsInMonorepo
1215
+ ? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
1216
+ : "echo 'No prebuild needed outside monorepo'",
1065
1217
  dev: "next dev",
1066
1218
  build: "next build",
1067
1219
  start: "next start",
1068
1220
  lint: "next lint",
1069
- lastbrain: "node node_modules/@lastbrain/app/dist/cli.js",
1070
- "build:modules": "node node_modules/@lastbrain/app/dist/scripts/module-build.js",
1071
- "db:migrations:sync": "node node_modules/@lastbrain/app/dist/scripts/db-migrations-sync.js",
1072
- "db:init": "node node_modules/@lastbrain/app/dist/scripts/db-init.js",
1073
- "readme:create": "node node_modules/@lastbrain/app/dist/scripts/readme-build.js",
1221
+ lastbrain: targetIsInMonorepo
1222
+ ? "lastbrain"
1223
+ : "node node_modules/@lastbrain/app/dist/cli.js",
1224
+ "build:modules": `${scriptsPrefix} module:build`,
1225
+ "db:migrations:sync": `${scriptsPrefix} db:migrations:sync`,
1226
+ "db:init": `${scriptsPrefix} db:init`,
1227
+ "readme:create": `${scriptsPrefix} readme:create`,
1074
1228
  };
1075
1229
 
1076
1230
  pkg.scripts = { ...pkg.scripts, ...scripts };
@@ -1082,26 +1236,36 @@ async function addScriptsToPackageJson(targetDir: string) {
1082
1236
  async function saveModulesConfig(
1083
1237
  targetDir: string,
1084
1238
  selectedModules: string[],
1085
- withAuth: boolean
1239
+ withAuth: boolean,
1086
1240
  ) {
1087
1241
  const modulesConfigPath = path.join(targetDir, ".lastbrain", "modules.json");
1088
1242
  await fs.ensureDir(path.dirname(modulesConfigPath));
1089
1243
 
1090
- const modules: Array<{ package: string; active: boolean; migrations?: string[] }> = [];
1244
+ const modules: Array<{
1245
+ package: string;
1246
+ active: boolean;
1247
+ migrations?: string[];
1248
+ }> = [];
1091
1249
 
1092
1250
  // Ajouter TOUS les modules disponibles
1093
1251
  for (const availableModule of AVAILABLE_MODULES) {
1094
- const isSelected = selectedModules.includes(availableModule.name) || (withAuth && availableModule.name === 'auth');
1095
-
1252
+ const isSelected =
1253
+ selectedModules.includes(availableModule.name) ||
1254
+ (withAuth && availableModule.name === "auth");
1255
+
1096
1256
  // Vérifier si le module a des migrations
1097
1257
  const modulePath = path.join(
1098
1258
  targetDir,
1099
1259
  "node_modules",
1100
- ...availableModule.package.split("/")
1260
+ ...availableModule.package.split("/"),
1101
1261
  );
1102
1262
  const migrationsDir = path.join(modulePath, "supabase", "migrations");
1103
-
1104
- const moduleConfig: { package: string; active: boolean; migrations?: string[] } = {
1263
+
1264
+ const moduleConfig: {
1265
+ package: string;
1266
+ active: boolean;
1267
+ migrations?: string[];
1268
+ } = {
1105
1269
  package: availableModule.package,
1106
1270
  active: isSelected,
1107
1271
  };
@@ -1110,7 +1274,7 @@ async function saveModulesConfig(
1110
1274
  const migrationFiles = fs
1111
1275
  .readdirSync(migrationsDir)
1112
1276
  .filter((f) => f.endsWith(".sql"));
1113
-
1277
+
1114
1278
  if (migrationFiles.length > 0) {
1115
1279
  moduleConfig.migrations = isSelected ? migrationFiles : [];
1116
1280
  }
@@ -1338,9 +1502,16 @@ export function isPrivateBucket(bucket: string): boolean {
1338
1502
  }
1339
1503
 
1340
1504
  // 3. Créer app/api/storage/[bucket]/[...path]/route.ts
1341
- const apiStorageDir = path.join(targetDir, "app", "api", "storage", "[bucket]", "[...path]");
1505
+ const apiStorageDir = path.join(
1506
+ targetDir,
1507
+ "app",
1508
+ "api",
1509
+ "storage",
1510
+ "[bucket]",
1511
+ "[...path]",
1512
+ );
1342
1513
  await fs.ensureDir(apiStorageDir);
1343
-
1514
+
1344
1515
  const routePath = path.join(apiStorageDir, "route.ts");
1345
1516
  if (!fs.existsSync(routePath) || force) {
1346
1517
  const routeContent = `import { NextRequest, NextResponse } from "next/server";
@@ -1463,7 +1634,9 @@ export async function GET(
1463
1634
  }`;
1464
1635
 
1465
1636
  await fs.writeFile(routePath, routeContent);
1466
- console.log(chalk.green("✓ app/api/storage/[bucket]/[...path]/route.ts créé"));
1637
+ console.log(
1638
+ chalk.green("✓ app/api/storage/[bucket]/[...path]/route.ts créé"),
1639
+ );
1467
1640
  }
1468
1641
 
1469
1642
  console.log(chalk.green("✓ Système de proxy storage configuré"));