@lastbrain/app 0.1.26 → 0.1.28
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 +4 -4
- 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/dist/templates/SimpleHomePage.js +1 -1
- 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 +17 -9
- 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/src/templates/SimpleHomePage.tsx +1 -1
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)
|
|
@@ -240,8 +240,8 @@ async function addDependencies(targetDir, useHeroUI, withAuth, selectedModules =
|
|
|
240
240
|
for (const moduleName of selectedModules) {
|
|
241
241
|
const moduleInfo = AVAILABLE_MODULES.find((m) => m.name === moduleName);
|
|
242
242
|
if (moduleInfo && moduleInfo.package !== "@lastbrain/module-auth") {
|
|
243
|
-
// Pour les autres modules, utiliser "latest"
|
|
244
|
-
requiredDeps[moduleInfo.package] =
|
|
243
|
+
// Pour les autres modules, utiliser "latest" pour éviter les problèmes de versions
|
|
244
|
+
requiredDeps[moduleInfo.package] = "latest";
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
// Ajouter les dépendances HeroUI si nécessaire
|
|
@@ -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"));
|
|
@@ -3,5 +3,5 @@ import NextLink from "next/link";
|
|
|
3
3
|
import { Button, Card, CardBody, CardHeader, Chip, Snippet, } from "@lastbrain/ui";
|
|
4
4
|
import { Rocket, Package, Database, Code, Zap, Shield, ArrowRight, BookOpen, } from "lucide-react";
|
|
5
5
|
export function SimpleHomePage({ showAuth }) {
|
|
6
|
-
return (_jsxs("div", { className: "min-h-screen", children: [_jsxs("section", { className: "relative overflow-hidden bg-gradient-to-br from-blue-50 via-purple-50 to-pink-50 dark:from-slate-900 dark:via-purple-900/20 dark:to-blue-900/20", children: [_jsx("div", { className: "absolute inset-0 bg-grid-slate-200/50 dark:bg-grid-slate-700/25 mask-[radial-gradient(ellipse_at_center,transparent_20%,black)]" }), _jsx("div", { className: "relative container mx-auto px-4 py-24 md:py-32", children: _jsxs("div", { className: "max-w-4xl mx-auto text-center", children: [_jsxs("div", { className: "inline-flex items-center gap-2 px-4 py-2 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 mb-8", children: [_jsx(Zap, { size: 16 }), _jsx("span", { className: "text-sm font-medium", children: "Framework modulaire Next.js" })] }), _jsx("h1", { className: "text-5xl md:text-7xl font-bold mb-6 bg-gradient-to-r from-blue-600 via-purple-600 to-pink-600 bg-clip-text text-transparent", children: "Bienvenue sur LastBrain" }), _jsx("p", { className: "text-xl md:text-2xl text-slate-600 dark:text-slate-300 mb-12 max-w-2xl mx-auto", children: "Cr\u00E9ez des applications modernes avec une architecture modulaire, puissante et \u00E9volutive." }), _jsxs("div", { className: "flex flex-col sm:flex-row gap-4 justify-center", children: [_jsx(NextLink, { href: "/docs", children: _jsx(Button, { size: "lg", color: "primary", endContent: _jsx(ArrowRight, { size: 20 }), className: "text-base font-medium", children: "Voir la documentation" }) }), showAuth && (_jsx(NextLink, { href: "/signup", children: _jsx(Button, { size: "lg", variant: "bordered", className: "text-base font-medium", children: "Cr\u00E9er un compte" }) }))] })] }) })] }), _jsx("section", { className: "py-20 bg-white dark:bg-slate-950", children: _jsx("div", { className: "container mx-auto px-4", children: _jsxs("div", { className: "max-w-6xl mx-auto", children: [_jsxs("div", { className: "text-center mb-16", children: [_jsx("h2", { className: "text-3xl md:text-4xl font-bold mb-4", children: "Tout ce dont vous avez besoin" }), _jsx("p", { className: "text-lg text-slate-600 dark:text-slate-400", children: "Une stack moderne pour d\u00E9marrer rapidement" })] }), _jsxs("div", { className: "grid gap-6 md:grid-cols-2 lg:grid-cols-3", children: [_jsxs(Card, { className: "hover:shadow-xl transition-shadow", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-blue-100 dark:bg-blue-900/30", children: _jsx(Package, { className: "text-blue-600 dark:text-blue-400", size: 24 }) }), _jsx("h3", { className: "text-xl font-semibold", children: "Modulaire" })] }) }), _jsx(CardBody, { className: "pt-2", children: _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "Architecture bas\u00E9e sur des modules r\u00E9utilisables. Ajoutez ou retirez des fonctionnalit\u00E9s en une commande." }) })] }), _jsxs(Card, { className: "hover:shadow-xl transition-shadow", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-purple-100 dark:bg-purple-900/30", children: _jsx(Database, { className: "text-purple-600 dark:text-purple-400", size: 24 }) }), _jsx("h3", { className: "text-xl font-semibold", children: "Supabase" })] }) }), _jsx(CardBody, { className: "pt-2", children: _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "Base de donn\u00E9es PostgreSQL, authentification et migrations automatiques. Tout en local pour le d\u00E9veloppement." }) })] }), _jsxs(Card, { className: "hover:shadow-xl transition-shadow", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-green-100 dark:bg-green-900/30", children: _jsx(Zap, { className: "text-green-600 dark:text-green-400", size: 24 }) }), _jsx("h3", { className: "text-xl font-semibold", children: "Rapide" })] }) }), _jsx(CardBody, { className: "pt-2", children: _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "Next.js 15, React 19, Tailwind CSS v4. Hot reload et g\u00E9n\u00E9ration automatique des routes." }) })] }), _jsxs(Card, { className: "hover:shadow-xl transition-shadow", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-orange-100 dark:bg-orange-900/30", children: _jsx(Code, { className: "text-orange-600 dark:text-orange-400", size: 24 }) }), _jsx("h3", { className: "text-xl font-semibold", children: "TypeScript" })] }) }), _jsx(CardBody, { className: "pt-2", children: _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "100% TypeScript avec types partag\u00E9s entre frontend et backend. Monorepo pnpm pour une gestion optimale." }) })] }), _jsxs(Card, { className: "hover:shadow-xl transition-shadow", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-pink-100 dark:bg-pink-900/30", children: _jsx(Shield, { className: "text-pink-600 dark:text-pink-400", size: 24 }) }), _jsx("h3", { className: "text-xl font-semibold", children: "S\u00E9curis\u00E9" })] }) }), _jsx(CardBody, { className: "pt-2", children: _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "Middleware d'authentification automatique. Routes prot\u00E9g\u00E9es pour /auth et /admin configur\u00E9es par d\u00E9faut." }) })] }), _jsxs(Card, { className: "hover:shadow-xl transition-shadow", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-cyan-100 dark:bg-cyan-900/30", children: _jsx(BookOpen, { className: "text-cyan-600 dark:text-cyan-400", size: 24 }) }), _jsx("h3", { className: "text-xl font-semibold", children: "Document\u00E9" })] }) }), _jsx(CardBody, { className: "pt-2", children: _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "Documentation compl\u00E8te et interactive. Chaque module documente automatiquement ses pages et APIs." }) })] })] })] }) }) }), _jsx("section", { className: "py-20 bg-slate-50 dark:bg-slate-900/50", children: _jsx("div", { className: "container mx-auto px-4", children: _jsxs("div", { className: "max-w-4xl mx-auto", children: [_jsxs("div", { className: "text-center mb-12", children: [_jsxs("div", { className: "inline-flex items-center gap-2 mb-4", children: [_jsx(Rocket, { size: 24, className: "text-blue-600" }), _jsx("h2", { className: "text-3xl md:text-4xl font-bold", children: "D\u00E9marrez en 4 \u00E9tapes" })] }), _jsx("p", { className: "text-lg text-slate-600 dark:text-slate-400", children: "Votre application pr\u00EAte en quelques minutes" })] }), _jsxs("div", { className: "space-y-6", children: [_jsx(Card, { className: "border-l-4 border-l-blue-500", children: _jsx(CardBody, { children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "shrink-0 w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center font-bold text-blue-600 dark:text-blue-400", children: "1" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Cr\u00E9ez votre application" }), _jsx(Snippet, { className: "w-full", children: "pnpx @lastbrain/create-app mon-app" }), _jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400 mt-2", children: "L'assistant interactif vous guidera pour :" }), _jsxs("ul", { className: "text-sm text-slate-600 dark:text-slate-400 mt-2 ml-4 space-y-1", children: [_jsx("li", { children: "\u2022 Choisir les modules \u00E0 installer (auth, ai...)" }), _jsx("li", { children: "\u2022 Cr\u00E9er la structure compl\u00E8te du projet" }), _jsx("li", { children: "\u2022 Installer automatiquement les d\u00E9pendances" }), _jsx("li", { children: "\u2022 G\u00E9n\u00E9rer les routes des modules" })] })] })] }) }) }), _jsx(Card, { className: "border-l-4 border-l-purple-500", children: _jsx(CardBody, { children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "shrink-0 w-8 h-8 rounded-full bg-purple-100 dark:bg-purple-900/30 flex items-center justify-center font-bold text-purple-600 dark:text-purple-400", children: "2" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Acc\u00E9dez au dossier" }), _jsx(Snippet, { className: "w-full", children: "cd mon-app" }), _jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400 mt-2", children: "Entrez dans le dossier de votre nouvelle application" })] })] }) }) }), _jsx(Card, { className: "border-l-4 border-l-orange-500", children: _jsx(CardBody, { children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "shrink-0 w-8 h-8 rounded-full bg-orange-100 dark:bg-orange-900/30 flex items-center justify-center font-bold text-orange-600 dark:text-orange-400", children: "3" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Initialisez Supabase" }), _jsx(Snippet, { className: "w-full", children: "pnpm db:init" }), _jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400 mt-2", children: "D\u00E9marre Supabase en local et applique toutes les migrations (base + modules)" })] })] }) }) }), _jsx(Card, { className: "border-l-4 border-l-green-500", children: _jsx(CardBody, { children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "shrink-0 w-8 h-8 rounded-full bg-green-100 dark:bg-green-900/30 flex items-center justify-center font-bold text-green-600 dark:text-green-400", children: "4" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Lancez le serveur" }), _jsx(Snippet, { className: "w-full", children: "pnpm dev" }), _jsxs("p", { className: "text-sm text-slate-600 dark:text-slate-400 mt-2", children: ["Ouvre l'application sur", " ", _jsx("strong", { children: "http://localhost:3000" })] })] })] }) }) }), _jsx(Card, { className: "bg-blue-50 dark:bg-blue-950/30 border-blue-200 dark:border-blue-800", children: _jsx(CardBody, { children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-blue-100 dark:bg-blue-900/30 shrink-0", children: _jsx(Package, { className: "text-blue-600 dark:text-blue-400", size: 20 }) }), _jsxs("div", { children: [_jsx("h4", { className: "font-semibold mb-2 text-blue-900 dark:text-blue-100", children: "Ajouter des modules plus tard" }), _jsxs("div", { className: "space-y-2", children: [_jsx(Snippet, { className: "w-full", size: "sm", children: "pnpm lastbrain add-module auth" }), _jsx(Snippet, { className: "w-full", size: "sm", children: "pnpm build:modules" })] }), _jsxs("div", { className: "text-sm text-blue-700 dark:text-blue-300 mt-2", children: ["Modules disponibles :", " ", _jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "auth" }), " ", _jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "ai" })] })] })] }) }) })] })] }) }) }), _jsx("section", { className: "py-20 bg-gradient-to-r from-blue-600 to-purple-600 text-white", children: _jsx("div", { className: "container mx-auto px-4", children: _jsxs("div", { className: "max-w-3xl mx-auto text-center", children: [_jsx("h2", { className: "text-3xl md:text-4xl font-bold mb-4", children: "Pr\u00EAt \u00E0 commencer ?" }), _jsx("p", { className: "text-lg text-blue-100 mb-8", children: "Explorez la documentation compl\u00E8te pour d\u00E9couvrir toutes les fonctionnalit\u00E9s" }), _jsx(NextLink, { href: "/docs", children: _jsx(Button, { size: "lg", className: "bg-white text-blue-600 hover:bg-blue-50 font-medium", endContent: _jsx(BookOpen, { size: 20 }), children: "Consulter la documentation" }) })] }) }) })] }));
|
|
6
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsxs("section", { className: "relative overflow-hidden bg-gradient-to-br from-blue-50 via-purple-50 to-pink-50 dark:from-slate-900 dark:via-purple-900/20 dark:to-blue-900/20", children: [_jsx("div", { className: "absolute inset-0 bg-grid-slate-200/50 dark:bg-grid-slate-700/25 mask-[radial-gradient(ellipse_at_center,transparent_20%,black)]" }), _jsx("div", { className: "relative container mx-auto px-4 py-24 md:py-32", children: _jsxs("div", { className: "max-w-4xl mx-auto text-center", children: [_jsxs("div", { className: "inline-flex items-center gap-2 px-4 py-2 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 mb-8", children: [_jsx(Zap, { size: 16 }), _jsx("span", { className: "text-sm font-medium", children: "Framework modulaire Next.js" })] }), _jsx("h1", { className: "text-5xl md:text-7xl font-bold mb-6 bg-gradient-to-r from-blue-600 via-purple-600 to-pink-600 bg-clip-text text-transparent", children: "Bienvenue sur LastBrain" }), _jsx("p", { className: "text-xl md:text-2xl text-slate-600 dark:text-slate-300 mb-12 max-w-2xl mx-auto", children: "Cr\u00E9ez des applications modernes avec une architecture modulaire, puissante et \u00E9volutive." }), _jsxs("div", { className: "flex flex-col sm:flex-row gap-4 justify-center", children: [_jsx(NextLink, { href: "/docs", children: _jsx(Button, { size: "lg", color: "primary", endContent: _jsx(ArrowRight, { size: 20 }), className: "text-base font-medium", children: "Voir la documentation" }) }), showAuth && (_jsx(NextLink, { href: "/signup", children: _jsx(Button, { size: "lg", variant: "bordered", className: "text-base font-medium", children: "Cr\u00E9er un compte" }) }))] })] }) })] }), _jsx("section", { className: "py-20 bg-white dark:bg-slate-950", children: _jsx("div", { className: "container mx-auto px-4", children: _jsxs("div", { className: "max-w-6xl mx-auto", children: [_jsxs("div", { className: "text-center mb-16", children: [_jsx("h2", { className: "text-3xl md:text-4xl font-bold mb-4", children: "Tout ce dont vous avez besoin" }), _jsx("p", { className: "text-lg text-slate-600 dark:text-slate-400", children: "Une stack moderne pour d\u00E9marrer rapidement" })] }), _jsxs("div", { className: "grid gap-6 md:grid-cols-2 lg:grid-cols-3", children: [_jsxs(Card, { className: "hover:shadow-xl transition-shadow", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-blue-100 dark:bg-blue-900/30", children: _jsx(Package, { className: "text-blue-600 dark:text-blue-400", size: 24 }) }), _jsx("h3", { className: "text-xl font-semibold", children: "Modulaire" })] }) }), _jsx(CardBody, { className: "pt-2", children: _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "Architecture bas\u00E9e sur des modules r\u00E9utilisables. Ajoutez ou retirez des fonctionnalit\u00E9s en une commande." }) })] }), _jsxs(Card, { className: "hover:shadow-xl transition-shadow", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-purple-100 dark:bg-purple-900/30", children: _jsx(Database, { className: "text-purple-600 dark:text-purple-400", size: 24 }) }), _jsx("h3", { className: "text-xl font-semibold", children: "Supabase" })] }) }), _jsx(CardBody, { className: "pt-2", children: _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "Base de donn\u00E9es PostgreSQL, authentification et migrations automatiques. Tout en local pour le d\u00E9veloppement." }) })] }), _jsxs(Card, { className: "hover:shadow-xl transition-shadow", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-green-100 dark:bg-green-900/30", children: _jsx(Zap, { className: "text-green-600 dark:text-green-400", size: 24 }) }), _jsx("h3", { className: "text-xl font-semibold", children: "Rapide" })] }) }), _jsx(CardBody, { className: "pt-2", children: _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "Next.js 15, React 19, Tailwind CSS v4. Hot reload et g\u00E9n\u00E9ration automatique des routes." }) })] }), _jsxs(Card, { className: "hover:shadow-xl transition-shadow", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-orange-100 dark:bg-orange-900/30", children: _jsx(Code, { className: "text-orange-600 dark:text-orange-400", size: 24 }) }), _jsx("h3", { className: "text-xl font-semibold", children: "TypeScript" })] }) }), _jsx(CardBody, { className: "pt-2", children: _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "100% TypeScript avec types partag\u00E9s entre frontend et backend. Monorepo pnpm pour une gestion optimale." }) })] }), _jsxs(Card, { className: "hover:shadow-xl transition-shadow", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-pink-100 dark:bg-pink-900/30", children: _jsx(Shield, { className: "text-pink-600 dark:text-pink-400", size: 24 }) }), _jsx("h3", { className: "text-xl font-semibold", children: "S\u00E9curis\u00E9" })] }) }), _jsx(CardBody, { className: "pt-2", children: _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "Middleware d'authentification automatique. Routes prot\u00E9g\u00E9es pour /auth et /admin configur\u00E9es par d\u00E9faut." }) })] }), _jsxs(Card, { className: "hover:shadow-xl transition-shadow", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-cyan-100 dark:bg-cyan-900/30", children: _jsx(BookOpen, { className: "text-cyan-600 dark:text-cyan-400", size: 24 }) }), _jsx("h3", { className: "text-xl font-semibold", children: "Document\u00E9" })] }) }), _jsx(CardBody, { className: "pt-2", children: _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "Documentation compl\u00E8te et interactive. Chaque module documente automatiquement ses pages et APIs." }) })] })] })] }) }) }), _jsx("section", { className: "py-20 bg-slate-50 dark:bg-slate-900/50", children: _jsx("div", { className: "container mx-auto px-4", children: _jsxs("div", { className: "max-w-4xl mx-auto", children: [_jsxs("div", { className: "text-center mb-12", children: [_jsxs("div", { className: "inline-flex items-center gap-2 mb-4", children: [_jsx(Rocket, { size: 24, className: "text-blue-600" }), _jsx("h2", { className: "text-3xl md:text-4xl font-bold", children: "D\u00E9marrez en 4 \u00E9tapes" })] }), _jsx("p", { className: "text-lg text-slate-600 dark:text-slate-400", children: "Votre application pr\u00EAte en quelques minutes" })] }), _jsxs("div", { className: "space-y-6", children: [_jsx(Card, { className: "border-l-4 border-l-blue-500", children: _jsx(CardBody, { children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "shrink-0 w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center font-bold text-blue-600 dark:text-blue-400", children: "1" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Cr\u00E9ez votre application" }), _jsx(Snippet, { className: "w-full", children: "pnpx @lastbrain/app init mon-app" }), _jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400 mt-2", children: "L'assistant interactif vous guidera pour :" }), _jsxs("ul", { className: "text-sm text-slate-600 dark:text-slate-400 mt-2 ml-4 space-y-1", children: [_jsx("li", { children: "\u2022 Choisir les modules \u00E0 installer (auth, ai...)" }), _jsx("li", { children: "\u2022 Cr\u00E9er la structure compl\u00E8te du projet" }), _jsx("li", { children: "\u2022 Installer automatiquement les d\u00E9pendances" }), _jsx("li", { children: "\u2022 G\u00E9n\u00E9rer les routes des modules" })] })] })] }) }) }), _jsx(Card, { className: "border-l-4 border-l-purple-500", children: _jsx(CardBody, { children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "shrink-0 w-8 h-8 rounded-full bg-purple-100 dark:bg-purple-900/30 flex items-center justify-center font-bold text-purple-600 dark:text-purple-400", children: "2" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Acc\u00E9dez au dossier" }), _jsx(Snippet, { className: "w-full", children: "cd mon-app" }), _jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400 mt-2", children: "Entrez dans le dossier de votre nouvelle application" })] })] }) }) }), _jsx(Card, { className: "border-l-4 border-l-orange-500", children: _jsx(CardBody, { children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "shrink-0 w-8 h-8 rounded-full bg-orange-100 dark:bg-orange-900/30 flex items-center justify-center font-bold text-orange-600 dark:text-orange-400", children: "3" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Initialisez Supabase" }), _jsx(Snippet, { className: "w-full", children: "pnpm db:init" }), _jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400 mt-2", children: "D\u00E9marre Supabase en local et applique toutes les migrations (base + modules)" })] })] }) }) }), _jsx(Card, { className: "border-l-4 border-l-green-500", children: _jsx(CardBody, { children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "shrink-0 w-8 h-8 rounded-full bg-green-100 dark:bg-green-900/30 flex items-center justify-center font-bold text-green-600 dark:text-green-400", children: "4" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Lancez le serveur" }), _jsx(Snippet, { className: "w-full", children: "pnpm dev" }), _jsxs("p", { className: "text-sm text-slate-600 dark:text-slate-400 mt-2", children: ["Ouvre l'application sur", " ", _jsx("strong", { children: "http://localhost:3000" })] })] })] }) }) }), _jsx(Card, { className: "bg-blue-50 dark:bg-blue-950/30 border-blue-200 dark:border-blue-800", children: _jsx(CardBody, { children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "p-2 rounded-lg bg-blue-100 dark:bg-blue-900/30 shrink-0", children: _jsx(Package, { className: "text-blue-600 dark:text-blue-400", size: 20 }) }), _jsxs("div", { children: [_jsx("h4", { className: "font-semibold mb-2 text-blue-900 dark:text-blue-100", children: "Ajouter des modules plus tard" }), _jsxs("div", { className: "space-y-2", children: [_jsx(Snippet, { className: "w-full", size: "sm", children: "pnpm lastbrain add-module auth" }), _jsx(Snippet, { className: "w-full", size: "sm", children: "pnpm build:modules" })] }), _jsxs("div", { className: "text-sm text-blue-700 dark:text-blue-300 mt-2", children: ["Modules disponibles :", " ", _jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "auth" }), " ", _jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "ai" })] })] })] }) }) })] })] }) }) }), _jsx("section", { className: "py-20 bg-gradient-to-r from-blue-600 to-purple-600 text-white", children: _jsx("div", { className: "container mx-auto px-4", children: _jsxs("div", { className: "max-w-3xl mx-auto text-center", children: [_jsx("h2", { className: "text-3xl md:text-4xl font-bold mb-4", children: "Pr\u00EAt \u00E0 commencer ?" }), _jsx("p", { className: "text-lg text-blue-100 mb-8", children: "Explorez la documentation compl\u00E8te pour d\u00E9couvrir toutes les fonctionnalit\u00E9s" }), _jsx(NextLink, { href: "/docs", children: _jsx(Button, { size: "lg", className: "bg-white text-blue-600 hover:bg-blue-50 font-medium", endContent: _jsx(BookOpen, { size: 20 }), children: "Consulter la documentation" }) })] }) }) })] }));
|
|
7
7
|
}
|
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)
|
|
@@ -331,8 +339,8 @@ async function addDependencies(
|
|
|
331
339
|
for (const moduleName of selectedModules) {
|
|
332
340
|
const moduleInfo = AVAILABLE_MODULES.find((m) => m.name === moduleName);
|
|
333
341
|
if (moduleInfo && moduleInfo.package !== "@lastbrain/module-auth") {
|
|
334
|
-
// Pour les autres modules, utiliser "latest"
|
|
335
|
-
requiredDeps[moduleInfo.package] =
|
|
342
|
+
// Pour les autres modules, utiliser "latest" pour éviter les problèmes de versions
|
|
343
|
+
requiredDeps[moduleInfo.package] = "latest";
|
|
336
344
|
}
|
|
337
345
|
}
|
|
338
346
|
|
|
@@ -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
|
|
|
@@ -242,7 +242,7 @@ export function SimpleHomePage({ showAuth }: HomePageProps) {
|
|
|
242
242
|
Créez votre application
|
|
243
243
|
</h3>
|
|
244
244
|
<Snippet className="w-full">
|
|
245
|
-
pnpx @lastbrain/
|
|
245
|
+
pnpx @lastbrain/app init mon-app
|
|
246
246
|
</Snippet>
|
|
247
247
|
<p className="text-sm text-slate-600 dark:text-slate-400 mt-2">
|
|
248
248
|
L'assistant interactif vous guidera pour :
|