@lastbrain/app 0.1.44 → 0.1.46

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.
@@ -19,6 +19,7 @@ interface InitAppOptions {
19
19
  useHeroUI: boolean;
20
20
  withAuth?: boolean;
21
21
  interactive?: boolean;
22
+ isMonorepoProject?: boolean;
22
23
  }
23
24
 
24
25
  export async function initApp(options: InitAppOptions) {
@@ -29,7 +30,7 @@ export async function initApp(options: InitAppOptions) {
29
30
  useHeroUI,
30
31
  interactive = true,
31
32
  } = options;
32
- let { withAuth = false } = options;
33
+ let { withAuth = false, isMonorepoProject = false } = options;
33
34
 
34
35
  console.log(chalk.blue("\n🚀 LastBrain App Init\n"));
35
36
  console.log(chalk.gray(`📁 Dossier cible: ${targetDir}`));
@@ -55,20 +56,56 @@ export async function initApp(options: InitAppOptions) {
55
56
  checked: false,
56
57
  })),
57
58
  },
59
+ {
60
+ type: "rawlist",
61
+ name: "projectType",
62
+ message: "Type de projet ?",
63
+ choices: [
64
+ {
65
+ name: "📦 Indépendant (créer une nouvelle BDD Supabase)",
66
+ value: "independent",
67
+ },
68
+ {
69
+ name: "🏢 Monorepo (utiliser la BDD existante)",
70
+ value: "monorepo",
71
+ },
72
+ ],
73
+ default: "independent",
74
+ },
58
75
  ]);
59
76
 
60
77
  selectedModules.push(...answers.modules);
61
78
  withAuth = selectedModules.includes("auth");
79
+ isMonorepoProject = answers.projectType === "monorepo";
80
+
81
+ if (isMonorepoProject) {
82
+ console.log(
83
+ chalk.cyan("\n💡 Mode monorepo activé:"),
84
+ chalk.gray(
85
+ "Votre app utilisera la base de données centralisée du monorepo."
86
+ )
87
+ );
88
+ console.log(
89
+ chalk.gray(" Aucune configuration Supabase locale ne sera créée.\n")
90
+ );
91
+ } else {
92
+ console.log(
93
+ chalk.cyan("\n💡 Mode projet indépendant activé:"),
94
+ chalk.gray("Votre app aura sa propre instance Supabase locale.")
95
+ );
96
+ console.log(chalk.gray(" Configuration complète sera créée.\n"));
97
+ }
62
98
 
63
99
  console.log();
64
100
  } else if (!interactive) {
65
101
  // En mode non-interactif, installer auth et ai par défaut
66
102
  selectedModules.push("auth", "ai");
67
103
  withAuth = true;
104
+ isMonorepoProject = false;
68
105
  console.log(
69
106
  chalk.blue(
70
- "📦 Modules installés par défaut : Authentication, AI Generation\n",
71
- ),
107
+ "📦 Modules installés par défaut : Authentication, AI Generation\n"
108
+ )
72
109
  );
73
110
  }
74
111
 
@@ -93,10 +130,21 @@ export async function initApp(options: InitAppOptions) {
93
130
  // 6. Créer .gitignore et .env.local.example
94
131
  await createGitIgnore(targetDir, force);
95
132
  await createEnvExample(targetDir, force);
96
- await createEnvLocal(targetDir, force);
133
+ await createEnvLocal(targetDir, force, isMonorepoProject);
97
134
 
98
- // 7. Créer la structure Supabase avec migrations
99
- await createSupabaseStructure(targetDir, force);
135
+ // 7. Créer la structure Supabase avec migrations (seulement pour projets indépendants)
136
+ if (!isMonorepoProject) {
137
+ console.log(
138
+ chalk.blue("🗄️ Création de la structure Supabase locale...\n")
139
+ );
140
+ await createSupabaseStructure(targetDir, force);
141
+ } else {
142
+ console.log(
143
+ chalk.yellow(
144
+ "⏭️ Projet monorepo détecté - pas de configuration Supabase locale requise\n"
145
+ )
146
+ );
147
+ }
100
148
 
101
149
  // 8. Ajouter les scripts NPM
102
150
  await addScriptsToPackageJson(targetDir);
@@ -111,7 +159,7 @@ export async function initApp(options: InitAppOptions) {
111
159
  }
112
160
 
113
161
  console.log(
114
- chalk.green("\n✅ Application LastBrain initialisée avec succès!\n"),
162
+ chalk.green("\n✅ Application LastBrain initialisée avec succès!\n")
115
163
  );
116
164
 
117
165
  const relativePath = path.relative(process.cwd(), targetDir);
@@ -139,7 +187,7 @@ export async function initApp(options: InitAppOptions) {
139
187
  console.log(chalk.green("\n✓ Routes des modules générées\n"));
140
188
 
141
189
  console.log(
142
- chalk.yellow("📜 Synchronisation des migrations des modules...\n"),
190
+ chalk.yellow("📜 Synchronisation des migrations des modules...\n")
143
191
  );
144
192
  try {
145
193
  execSync("pnpm db:migrations:sync", {
@@ -149,7 +197,7 @@ export async function initApp(options: InitAppOptions) {
149
197
  console.log(chalk.green("\n✓ Migrations synchronisées\n"));
150
198
  } catch (error) {
151
199
  console.log(
152
- chalk.yellow("\n⚠️ Erreur de synchronisation des migrations\n"),
200
+ chalk.yellow("\n⚠️ Erreur de synchronisation des migrations\n")
153
201
  );
154
202
  }
155
203
 
@@ -160,8 +208,8 @@ export async function initApp(options: InitAppOptions) {
160
208
  } catch {
161
209
  console.log(
162
210
  chalk.yellow(
163
- "\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n",
164
- ),
211
+ "\n⚠️ Erreur d'initialisation de la DB (normal si Supabase pas configuré)\n"
212
+ )
165
213
  );
166
214
  }
167
215
 
@@ -170,19 +218,19 @@ export async function initApp(options: InitAppOptions) {
170
218
  const url = `http://127.0.0.1:${port}`;
171
219
 
172
220
  console.log(
173
- chalk.yellow("🚀 Lancement du serveur de développement...\n"),
221
+ chalk.yellow("🚀 Lancement du serveur de développement...\n")
174
222
  );
175
223
  console.log(chalk.cyan(`📱 Ouvrez votre navigateur sur : ${url}\n`));
176
224
 
177
225
  console.log(chalk.blue("\n📋 Prochaines étapes après le démarrage :"));
178
226
  console.log(
179
- chalk.white(" 1. Cliquez sur 'Get Started' sur la page d'accueil"),
227
+ chalk.white(" 1. Cliquez sur 'Get Started' sur la page d'accueil")
180
228
  );
181
229
  console.log(chalk.white(" 2. Lancez Docker Desktop"));
182
230
  console.log(
183
231
  chalk.white(
184
- " 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase",
185
- ),
232
+ " 3. Installez Supabase CLI si nécessaire : brew install supabase/tap/supabase"
233
+ )
186
234
  );
187
235
  console.log(chalk.white(" 4. Exécutez : pnpm db:init"));
188
236
  console.log(chalk.white(" 5. Rechargez la page\n"));
@@ -219,20 +267,20 @@ export async function initApp(options: InitAppOptions) {
219
267
  console.log(chalk.white(" 1. cd " + relativePath));
220
268
  console.log(chalk.white(" 2. pnpm install (installer les dépendances)"));
221
269
  console.log(
222
- chalk.white(" 3. pnpm build:modules (générer les routes des modules)"),
270
+ chalk.white(" 3. pnpm build:modules (générer les routes des modules)")
223
271
  );
224
272
  console.log(
225
- chalk.white(" 4. pnpm db:migrations:sync (synchroniser les migrations)"),
273
+ chalk.white(" 4. pnpm db:migrations:sync (synchroniser les migrations)")
226
274
  );
227
275
  console.log(
228
- chalk.white(" 5. pnpm db:init (initialiser la base de données)"),
276
+ chalk.white(" 5. pnpm db:init (initialiser la base de données)")
229
277
  );
230
278
  console.log(chalk.white(" 6. pnpm dev (lancer le serveur)\n"));
231
279
 
232
280
  console.log(chalk.gray("Prérequis pour Supabase :"));
233
281
  console.log(chalk.white(" - Docker Desktop installé et lancé"));
234
282
  console.log(
235
- chalk.white(" - Supabase CLI : brew install supabase/tap/supabase\n"),
283
+ chalk.white(" - Supabase CLI : brew install supabase/tap/supabase\n")
236
284
  );
237
285
 
238
286
  // Afficher la commande cd pour faciliter la copie
@@ -276,7 +324,7 @@ function getLastBrainVersions(targetDir: string): {
276
324
  } {
277
325
  const targetIsInMonorepo =
278
326
  fs.existsSync(
279
- path.join(targetDir, "../../../packages/core/package.json"),
327
+ path.join(targetDir, "../../../packages/core/package.json")
280
328
  ) ||
281
329
  fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
282
330
 
@@ -304,11 +352,11 @@ function getLastBrainVersions(targetDir: string): {
304
352
  const monorepoRoot = path.join(__dirname, "../../../../");
305
353
  const moduleAuthPkgPath = path.join(
306
354
  monorepoRoot,
307
- "packages/module-auth/package.json",
355
+ "packages/module-auth/package.json"
308
356
  );
309
357
  const moduleAiPkgPath = path.join(
310
358
  monorepoRoot,
311
- "packages/module-ai/package.json",
359
+ "packages/module-ai/package.json"
312
360
  );
313
361
  const corePkgPath = path.join(monorepoRoot, "packages/core/package.json");
314
362
  const uiPkgPath = path.join(monorepoRoot, "packages/ui/package.json");
@@ -321,7 +369,7 @@ function getLastBrainVersions(targetDir: string): {
321
369
  // Lire les vraies versions depuis les package.json du monorepo
322
370
  if (fs.existsSync(moduleAuthPkgPath)) {
323
371
  const moduleAuthPkg = JSON.parse(
324
- fs.readFileSync(moduleAuthPkgPath, "utf-8"),
372
+ fs.readFileSync(moduleAuthPkgPath, "utf-8")
325
373
  );
326
374
  moduleAuthVersion = `^${moduleAuthPkg.version}`;
327
375
  } else {
@@ -331,7 +379,7 @@ function getLastBrainVersions(targetDir: string): {
331
379
 
332
380
  if (fs.existsSync(moduleAiPkgPath)) {
333
381
  const moduleAiPkg = JSON.parse(
334
- fs.readFileSync(moduleAiPkgPath, "utf-8"),
382
+ fs.readFileSync(moduleAiPkgPath, "utf-8")
335
383
  );
336
384
  moduleAiVersion = `^${moduleAiPkg.version}`;
337
385
  } else {
@@ -360,8 +408,8 @@ function getLastBrainVersions(targetDir: string): {
360
408
  } catch (error) {
361
409
  console.warn(
362
410
  chalk.yellow(
363
- `⚠️ Impossible de lire les versions locales (${error}), utilisation de 'latest'`,
364
- ),
411
+ `⚠️ Impossible de lire les versions locales (${error}), utilisation de 'latest'`
412
+ )
365
413
  );
366
414
  }
367
415
 
@@ -379,7 +427,7 @@ async function addDependencies(
379
427
  targetDir: string,
380
428
  useHeroUI: boolean,
381
429
  withAuth: boolean,
382
- selectedModules: string[] = [],
430
+ selectedModules: string[] = []
383
431
  ) {
384
432
  const pkgPath = path.join(targetDir, "package.json");
385
433
  const pkg = await fs.readJson(pkgPath);
@@ -490,7 +538,7 @@ async function createNextStructure(
490
538
  targetDir: string,
491
539
  force: boolean,
492
540
  useHeroUI: boolean,
493
- withAuth: boolean,
541
+ withAuth: boolean
494
542
  ) {
495
543
  console.log(chalk.yellow("\n📁 Création de la structure Next.js..."));
496
544
 
@@ -550,9 +598,7 @@ export default function RootLayout({ children }: PropsWithChildren<{}>) {
550
598
  console.log(chalk.green("✓ app/layout.tsx créé"));
551
599
  } else {
552
600
  console.log(
553
- chalk.gray(
554
- " app/layout.tsx existe déjà (utilisez --force pour écraser)",
555
- ),
601
+ chalk.gray(" app/layout.tsx existe déjà (utilisez --force pour écraser)")
556
602
  );
557
603
  }
558
604
 
@@ -646,7 +692,7 @@ export default function NotFound() {
646
692
  async function createClientLayout(
647
693
  targetDir: string,
648
694
  force: boolean,
649
- useHeroUI: boolean,
695
+ useHeroUI: boolean
650
696
  ) {
651
697
  const componentsDir = path.join(targetDir, "components");
652
698
  await fs.ensureDir(componentsDir);
@@ -723,8 +769,8 @@ export function ClientLayout({ children }: { children: ReactNode }) {
723
769
  } else {
724
770
  console.log(
725
771
  chalk.gray(
726
- " components/ClientLayout.tsx existe déjà (utilisez --force pour écraser)",
727
- ),
772
+ " components/ClientLayout.tsx existe déjà (utilisez --force pour écraser)"
773
+ )
728
774
  );
729
775
  }
730
776
  }
@@ -733,7 +779,7 @@ async function createRoute(
733
779
  appDir: string,
734
780
  routeName: string,
735
781
  layoutType: string,
736
- force: boolean,
782
+ force: boolean
737
783
  ) {
738
784
  const routeDir = path.join(appDir, routeName);
739
785
  await fs.ensureDir(routeDir);
@@ -780,9 +826,8 @@ export default function AuthLayout({
780
826
  const layoutComponent =
781
827
  layoutType.charAt(0).toUpperCase() + layoutType.slice(1) + "Layout";
782
828
 
783
- if (routeName === "docs") {
784
- // Layout docs avec footer
785
- layoutContent = `import { ${layoutComponent} } from "@lastbrain/app";
829
+ // Layout docs avec footer
830
+ layoutContent = `import { ${layoutComponent} } from "@lastbrain/app";
786
831
  import { footerConfig } from "../../config/footer";
787
832
 
788
833
  export default function DocsLayout({
@@ -792,11 +837,6 @@ export default function DocsLayout({
792
837
  }) {
793
838
  return <${layoutComponent} footerConfig={footerConfig}>{children}</${layoutComponent}>;
794
839
  }`;
795
- } else {
796
- layoutContent = `import { ${layoutComponent} } from "@lastbrain/app";
797
-
798
- export default ${layoutComponent};`;
799
- }
800
840
  }
801
841
 
802
842
  await fs.writeFile(layoutPath, layoutContent);
@@ -893,6 +933,7 @@ export function AppHeader() {
893
933
  user={user}
894
934
  onLogout={handleLogout}
895
935
  menuConfig={menuConfig}
936
+ accountMenu={menuConfig.account}
896
937
  brandName="LastBrain App"
897
938
  brandHref="/"
898
939
  isSuperAdmin={isSuperAdmin}
@@ -911,8 +952,8 @@ export function AppHeader() {
911
952
  } else {
912
953
  console.log(
913
954
  chalk.gray(
914
- " components/AppHeader.tsx existe déjà (utilisez --force pour écraser)",
915
- ),
955
+ " components/AppHeader.tsx existe déjà (utilisez --force pour écraser)"
956
+ )
916
957
  );
917
958
  }
918
959
  }
@@ -951,8 +992,8 @@ export function AppAside({ className = "", isVisible = true }: AppAsideProps) {
951
992
  } else {
952
993
  console.log(
953
994
  chalk.gray(
954
- " components/AppAside.tsx existe déjà (utilisez --force pour écraser)",
955
- ),
995
+ " components/AppAside.tsx existe déjà (utilisez --force pour écraser)"
996
+ )
956
997
  );
957
998
  }
958
999
  }
@@ -981,8 +1022,8 @@ export function AppProviders({ children }: { children: ReactNode }) {
981
1022
  } else {
982
1023
  console.log(
983
1024
  chalk.gray(
984
- " components/AppProviders.tsx existe déjà (utilisez --force pour écraser)",
985
- ),
1025
+ " components/AppProviders.tsx existe déjà (utilisez --force pour écraser)"
1026
+ )
986
1027
  );
987
1028
  }
988
1029
  }
@@ -991,7 +1032,7 @@ async function createConfigFiles(
991
1032
  targetDir: string,
992
1033
  force: boolean,
993
1034
  useHeroUI: boolean,
994
- projectName?: string,
1035
+ projectName?: string
995
1036
  ) {
996
1037
  console.log(chalk.yellow("\n⚙️ Création des fichiers de configuration..."));
997
1038
 
@@ -1014,6 +1055,11 @@ export async function middleware(request: NextRequest) {
1014
1055
  "/callback",
1015
1056
  ];
1016
1057
 
1058
+ if(process.env.MAINTENANCE_MODE === "true" && !pathname.startsWith("/maintenance")) {
1059
+ const redirectUrl = new URL("/maintenance", request.url);
1060
+ return NextResponse.redirect(redirectUrl);
1061
+ }
1062
+
1017
1063
  const isPublicAuthPage = publicAuthPages.some((page) =>
1018
1064
  pathname.startsWith(page)
1019
1065
  );
@@ -1131,8 +1177,8 @@ export const config = {
1131
1177
  await fs.writeFile(middlewarePath, middleware);
1132
1178
  console.log(
1133
1179
  chalk.green(
1134
- "✓ middleware.ts créé (protection /auth/*, /admin/* et /api/admin/*)",
1135
- ),
1180
+ "✓ middleware.ts créé (protection /auth/*, /admin/* et /api/admin/*)"
1181
+ )
1136
1182
  );
1137
1183
  }
1138
1184
 
@@ -1418,7 +1464,7 @@ async function createGitIgnore(targetDir: string, force: boolean) {
1418
1464
  // Copier le fichier .gitignore depuis le template
1419
1465
  const templateGitignorePath = path.join(
1420
1466
  __dirname,
1421
- "../templates/gitignore/.gitignore",
1467
+ "../templates/gitignore/.gitignore"
1422
1468
  );
1423
1469
 
1424
1470
  if (fs.existsSync(templateGitignorePath)) {
@@ -1516,13 +1562,31 @@ SUPABASE_SERVICE_ROLE_KEY=YOUR_LOCAL_SERVICE_ROLE_KEY
1516
1562
  }
1517
1563
  }
1518
1564
 
1519
- async function createEnvLocal(targetDir: string, force: boolean) {
1565
+ async function createEnvLocal(
1566
+ targetDir: string,
1567
+ force: boolean,
1568
+ isMonorepoProject: boolean = false
1569
+ ) {
1520
1570
  const envLocalPath = path.join(targetDir, ".env.local");
1521
1571
 
1522
1572
  if (!fs.existsSync(envLocalPath) || force) {
1523
1573
  console.log(chalk.yellow("\n🔐 Création de .env.local..."));
1524
1574
 
1525
- const envContent = `# Supabase Configuration
1575
+ let envContent: string;
1576
+
1577
+ if (isMonorepoProject) {
1578
+ // Pour les projets monorepo, utiliser les variables du monorepo
1579
+ envContent = `# Supabase Configuration (Monorepo - Centralisé)
1580
+ # Les variables Supabase sont gérées au niveau du monorepo
1581
+
1582
+ # OpenAI Configuration (clé factice pour éviter les erreurs de build)
1583
+ OPENAI_API_KEY=sk-fake-openai-key-for-development-replace-with-real-key
1584
+
1585
+ # Note: Les variables Supabase sont fournies par le monorepo parent
1586
+ `;
1587
+ } else {
1588
+ // Pour les projets indépendants
1589
+ envContent = `# Supabase Configuration
1526
1590
  # Valeurs par défaut pour le développement local
1527
1591
 
1528
1592
  # Supabase Local (par défaut)
@@ -1533,6 +1597,8 @@ SUPABASE_SERVICE_ROLE_KEY=eyJhbGc...
1533
1597
  # OpenAI Configuration (clé factice pour éviter les erreurs de build)
1534
1598
  OPENAI_API_KEY=sk-fake-openai-key-for-development-replace-with-real-key
1535
1599
  `;
1600
+ }
1601
+
1536
1602
  await fs.writeFile(envLocalPath, envContent);
1537
1603
  console.log(chalk.green("✓ .env.local créé"));
1538
1604
  }
@@ -1548,11 +1614,11 @@ async function createSupabaseStructure(targetDir: string, force: boolean) {
1548
1614
  // Copier le fichier de migration initial depuis le template
1549
1615
  const templateMigrationPath = path.join(
1550
1616
  __dirname,
1551
- "../templates/migrations/20201010100000_app_base.sql",
1617
+ "../templates/migrations/20201010100000_app_base.sql"
1552
1618
  );
1553
1619
  const migrationDestPath = path.join(
1554
1620
  migrationsDir,
1555
- "20201010100000_app_base.sql",
1621
+ "20201010100000_app_base.sql"
1556
1622
  );
1557
1623
 
1558
1624
  if (!fs.existsSync(migrationDestPath) || force) {
@@ -1560,35 +1626,35 @@ async function createSupabaseStructure(targetDir: string, force: boolean) {
1560
1626
  if (fs.existsSync(templateMigrationPath)) {
1561
1627
  await fs.copy(templateMigrationPath, migrationDestPath);
1562
1628
  console.log(
1563
- chalk.green("✓ supabase/migrations/20201010100000_app_base.sql créé"),
1629
+ chalk.green("✓ supabase/migrations/20201010100000_app_base.sql créé")
1564
1630
  );
1565
1631
  } else {
1566
1632
  console.log(
1567
1633
  chalk.yellow(
1568
- "⚠ Template de migration introuvable, création d'un fichier vide",
1569
- ),
1634
+ "⚠ Template de migration introuvable, création d'un fichier vide"
1635
+ )
1570
1636
  );
1571
1637
  await fs.writeFile(
1572
1638
  migrationDestPath,
1573
- "-- Initial migration\n-- Add your database schema here\n",
1639
+ "-- Initial migration\n-- Add your database schema here\n"
1574
1640
  );
1575
1641
  console.log(
1576
1642
  chalk.green(
1577
- "✓ supabase/migrations/20201010100000_app_base.sql créé (vide)",
1578
- ),
1643
+ "✓ supabase/migrations/20201010100000_app_base.sql créé (vide)"
1644
+ )
1579
1645
  );
1580
1646
  }
1581
1647
  } catch (error) {
1582
1648
  console.error(
1583
1649
  chalk.red("✗ Erreur lors de la création de la migration:"),
1584
- error,
1650
+ error
1585
1651
  );
1586
1652
  }
1587
1653
  } else {
1588
1654
  console.log(
1589
1655
  chalk.gray(
1590
- " supabase/migrations/20201010100000_app_base.sql existe déjà",
1591
- ),
1656
+ " supabase/migrations/20201010100000_app_base.sql existe déjà"
1657
+ )
1592
1658
  );
1593
1659
  }
1594
1660
  }
@@ -1602,7 +1668,7 @@ async function addScriptsToPackageJson(targetDir: string) {
1602
1668
  // Détecter si le projet cible est dans un workspace
1603
1669
  const targetIsInMonorepo =
1604
1670
  fs.existsSync(
1605
- path.join(targetDir, "../../../packages/core/package.json"),
1671
+ path.join(targetDir, "../../../packages/core/package.json")
1606
1672
  ) ||
1607
1673
  fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
1608
1674
 
@@ -1639,7 +1705,7 @@ async function addScriptsToPackageJson(targetDir: string) {
1639
1705
  async function saveModulesConfig(
1640
1706
  targetDir: string,
1641
1707
  selectedModules: string[],
1642
- withAuth: boolean,
1708
+ withAuth: boolean
1643
1709
  ) {
1644
1710
  const modulesConfigPath = path.join(targetDir, ".lastbrain", "modules.json");
1645
1711
  await fs.ensureDir(path.dirname(modulesConfigPath));
@@ -1660,7 +1726,7 @@ async function saveModulesConfig(
1660
1726
  const modulePath = path.join(
1661
1727
  targetDir,
1662
1728
  "node_modules",
1663
- ...availableModule.package.split("/"),
1729
+ ...availableModule.package.split("/")
1664
1730
  );
1665
1731
  const migrationsDir = path.join(modulePath, "supabase", "migrations");
1666
1732
 
@@ -1918,7 +1984,7 @@ export function isPrivateBucket(bucket: string): boolean {
1918
1984
  "api",
1919
1985
  "storage",
1920
1986
  "[bucket]",
1921
- "[...path]",
1987
+ "[...path]"
1922
1988
  );
1923
1989
  await fs.ensureDir(apiStorageDir);
1924
1990
 
@@ -2045,7 +2111,7 @@ export async function GET(
2045
2111
 
2046
2112
  await fs.writeFile(routePath, routeContent);
2047
2113
  console.log(
2048
- chalk.green("✓ app/api/storage/[bucket]/[...path]/route.ts créé"),
2114
+ chalk.green("✓ app/api/storage/[bucket]/[...path]/route.ts créé")
2049
2115
  );
2050
2116
  }
2051
2117