@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.
- package/dist/__tests__/module-registry.test.d.ts +2 -0
- package/dist/__tests__/module-registry.test.d.ts.map +1 -0
- package/dist/__tests__/module-registry.test.js +64 -0
- package/dist/app-shell/(admin)/layout.d.ts +3 -2
- package/dist/app-shell/(admin)/layout.d.ts.map +1 -1
- package/dist/app-shell/(admin)/layout.js +1 -1
- package/dist/app-shell/(auth)/layout.d.ts +3 -2
- package/dist/app-shell/(auth)/layout.d.ts.map +1 -1
- package/dist/app-shell/(auth)/layout.js +1 -1
- package/dist/app-shell/(public)/page.d.ts.map +1 -1
- package/dist/cli.js +50 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/layouts/AdminLayout.d.ts +3 -2
- package/dist/layouts/AdminLayout.d.ts.map +1 -1
- package/dist/layouts/AdminLayoutWithSidebar.d.ts +8 -0
- package/dist/layouts/AdminLayoutWithSidebar.d.ts.map +1 -0
- package/dist/layouts/AdminLayoutWithSidebar.js +9 -0
- package/dist/layouts/AppProviders.d.ts +3 -2
- package/dist/layouts/AppProviders.d.ts.map +1 -1
- package/dist/layouts/AuthLayout.d.ts +3 -2
- package/dist/layouts/AuthLayout.d.ts.map +1 -1
- package/dist/layouts/AuthLayoutWithSidebar.d.ts +8 -0
- package/dist/layouts/AuthLayoutWithSidebar.d.ts.map +1 -0
- package/dist/layouts/AuthLayoutWithSidebar.js +9 -0
- package/dist/layouts/PublicLayout.d.ts +3 -2
- package/dist/layouts/PublicLayout.d.ts.map +1 -1
- package/dist/layouts/RootLayout.d.ts +3 -2
- package/dist/layouts/RootLayout.d.ts.map +1 -1
- package/dist/scripts/db-init.js +2 -2
- package/dist/scripts/db-migrations-sync.js +5 -5
- package/dist/scripts/dev-sync.js +21 -10
- package/dist/scripts/init-app.d.ts.map +1 -1
- package/dist/scripts/init-app.js +126 -21
- package/dist/scripts/module-add.d.ts.map +1 -1
- package/dist/scripts/module-add.js +20 -7
- package/dist/scripts/module-build.d.ts.map +1 -1
- package/dist/scripts/module-build.js +285 -30
- package/dist/scripts/module-create.d.ts.map +1 -1
- package/dist/scripts/module-create.js +25 -15
- package/dist/scripts/module-remove.d.ts.map +1 -1
- package/dist/scripts/module-remove.js +24 -11
- package/dist/scripts/script-runner.d.ts +5 -0
- package/dist/scripts/script-runner.d.ts.map +1 -0
- package/dist/scripts/script-runner.js +25 -0
- package/dist/styles.css +1 -1
- package/dist/templates/DefaultDoc.js +1 -7
- package/dist/templates/DocPage.d.ts.map +1 -1
- package/dist/templates/DocPage.js +14 -14
- package/dist/templates/components/AppAside.d.ts +6 -0
- package/dist/templates/components/AppAside.d.ts.map +1 -0
- package/dist/templates/components/AppAside.js +9 -0
- package/dist/templates/layouts/admin-layout.d.ts +4 -0
- package/dist/templates/layouts/admin-layout.d.ts.map +1 -0
- package/dist/templates/layouts/admin-layout.js +6 -0
- package/dist/templates/layouts/auth-layout.d.ts +4 -0
- package/dist/templates/layouts/auth-layout.d.ts.map +1 -0
- package/dist/templates/layouts/auth-layout.js +6 -0
- package/package.json +2 -1
- package/src/__tests__/module-registry.test.ts +74 -0
- package/src/app-shell/(admin)/layout.tsx +5 -3
- package/src/app-shell/(auth)/layout.tsx +5 -3
- package/src/app-shell/(public)/page.tsx +6 -2
- package/src/auth/useAuthSession.ts +1 -1
- package/src/cli.ts +51 -1
- package/src/index.ts +6 -0
- package/src/layouts/AdminLayout.tsx +1 -3
- package/src/layouts/AdminLayoutWithSidebar.tsx +35 -0
- package/src/layouts/AppProviders.tsx +3 -5
- package/src/layouts/AuthLayout.tsx +1 -3
- package/src/layouts/AuthLayoutWithSidebar.tsx +35 -0
- package/src/layouts/PublicLayout.tsx +1 -3
- package/src/layouts/RootLayout.tsx +1 -2
- package/src/scripts/db-init.ts +13 -8
- package/src/scripts/db-migrations-sync.ts +4 -4
- package/src/scripts/dev-sync.ts +49 -18
- package/src/scripts/init-app.ts +246 -73
- package/src/scripts/module-add.ts +49 -23
- package/src/scripts/module-build.ts +393 -88
- package/src/scripts/module-create.ts +85 -49
- package/src/scripts/module-remove.ts +116 -57
- package/src/scripts/readme-build.ts +2 -2
- package/src/scripts/script-runner.ts +28 -0
- package/src/templates/AuthGuidePage.tsx +1 -1
- package/src/templates/DefaultDoc.tsx +7 -7
- package/src/templates/DocPage.tsx +74 -46
package/src/scripts/init-app.ts
CHANGED
|
@@ -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
|
|
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:
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
208
|
-
|
|
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
|
|
242
|
-
console.warn(
|
|
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(
|
|
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
|
-
|
|
546
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
1055
|
-
|
|
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 = "
|
|
1058
|
-
|
|
1059
|
-
if (targetIsInMonorepo) {
|
|
1060
|
-
//
|
|
1061
|
-
scriptsPrefix = "
|
|
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:
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
"
|
|
1073
|
-
"
|
|
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<{
|
|
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 =
|
|
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: {
|
|
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(
|
|
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(
|
|
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é"));
|