@lastbrain/app 0.1.40 → 0.1.43

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.
@@ -3,6 +3,7 @@ export interface UserNotification {
3
3
  id: string;
4
4
  owner_id: string;
5
5
  title: string;
6
+ message: string;
6
7
  body?: string;
7
8
  type: string;
8
9
  read: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"useNotifications.d.ts","sourceRoot":"","sources":["../../src/hooks/useNotifications.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAElD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI;;;;;iCAwExB,MAAM;;yCAiEN,MAAM;;;;;EAwDhC"}
1
+ {"version":3,"file":"useNotifications.d.ts","sourceRoot":"","sources":["../../src/hooks/useNotifications.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAElD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI;;;;;iCAwExB,MAAM;;yCAiEN,MAAM;;;;;EAwDhC"}
@@ -1 +1 @@
1
- {"version":3,"file":"AdminLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/AdminLayout.tsx"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAEtE"}
1
+ {"version":3,"file":"AdminLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/AdminLayout.tsx"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAEtE"}
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  import { jsx as _jsx } from "react/jsx-runtime";
3
2
  export function AdminLayout({ children }) {
4
3
  return _jsx("div", { className: "pt-18 px-2 md:px-5", children: children });
@@ -1 +1 @@
1
- {"version":3,"file":"AuthLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/AuthLayout.tsx"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAErE"}
1
+ {"version":3,"file":"AuthLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/AuthLayout.tsx"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAErE"}
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  import { jsx as _jsx } from "react/jsx-runtime";
3
2
  export function AuthLayout({ children }) {
4
3
  return _jsx("div", { className: "pt-18 px-2 md:px-5 ", children: children });
@@ -1,4 +1,7 @@
1
- export declare function PublicLayout({ children }: {
1
+ interface PublicLayoutProps {
2
2
  children: React.ReactNode;
3
- }): import("react/jsx-runtime").JSX.Element;
3
+ footerConfig?: any;
4
+ }
5
+ export declare function PublicLayout({ children, footerConfig }: PublicLayoutProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
4
7
  //# sourceMappingURL=PublicLayout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PublicLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/PublicLayout.tsx"],"names":[],"mappings":"AAEA,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAEvE"}
1
+ {"version":3,"file":"PublicLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/PublicLayout.tsx"],"names":[],"mappings":"AAIA,UAAU,iBAAiB;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,YAAY,CAAC,EAAE,GAAG,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,iBAAiB,2CAOzE"}
@@ -1,5 +1,6 @@
1
1
  "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- export function PublicLayout({ children }) {
4
- return _jsx("section", { className: "pt-16 px-2 md:px-0 ", children: children });
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Footer } from "@lastbrain/ui";
4
+ export function PublicLayout({ children, footerConfig }) {
5
+ return (_jsxs(_Fragment, { children: [_jsx("section", { className: "pt-16 min-h-[calc(100vh)]", children: children }), footerConfig && _jsx(Footer, { config: footerConfig })] }));
5
6
  }
@@ -53,7 +53,7 @@ export async function initApp(options) {
53
53
  // 3. Créer la structure Next.js
54
54
  await createNextStructure(targetDir, force, useHeroUI, withAuth);
55
55
  // 4. Créer les fichiers de configuration
56
- await createConfigFiles(targetDir, force, useHeroUI);
56
+ await createConfigFiles(targetDir, force, useHeroUI, projectName);
57
57
  // 5. Créer le système de proxy storage
58
58
  await createStorageProxy(targetDir, force);
59
59
  // 6. Créer .gitignore et .env.local.example
@@ -359,41 +359,19 @@ async function createNextStructure(targetDir, force, useHeroUI, withAuth) {
359
359
  if (!fs.existsSync(layoutDest) || force) {
360
360
  let layoutContent = "";
361
361
  if (useHeroUI) {
362
- // Layout avec HeroUI
362
+ // Layout avec HeroUI - Server Component
363
363
  layoutContent = `// GENERATED BY LASTBRAIN APP-SHELL
364
-
365
- "use client";
364
+ // Server Component pour permettre le SSR des pages enfants
366
365
 
367
366
  import "../styles/globals.css";
368
- import { HeroUIProvider } from "@heroui/system";
369
-
370
- import { ThemeProvider } from "next-themes";
371
- import { useRouter } from "next/navigation";
372
- import { AppProviders } from "../components/AppProviders";
367
+ import { ClientLayout } from "../components/ClientLayout";
373
368
  import type { PropsWithChildren } from "react";
374
- import { AppHeader } from "../components/AppHeader";
375
369
 
376
370
  export default function RootLayout({ children }: PropsWithChildren<{}>) {
377
- const router = useRouter();
378
-
379
371
  return (
380
372
  <html lang="fr" suppressHydrationWarning>
381
373
  <body className="min-h-screen">
382
- <HeroUIProvider navigate={router.push}>
383
- <ThemeProvider
384
- attribute="class"
385
- defaultTheme="dark"
386
- enableSystem={false}
387
- storageKey="lastbrain-theme"
388
- >
389
- <AppProviders>
390
- <AppHeader />
391
- <div className="min-h-screen text-foreground bg-background">
392
- {children}
393
- </div>
394
- </AppProviders>
395
- </ThemeProvider>
396
- </HeroUIProvider>
374
+ <ClientLayout>{children}</ClientLayout>
397
375
  </body>
398
376
  </html>
399
377
  );
@@ -401,34 +379,19 @@ export default function RootLayout({ children }: PropsWithChildren<{}>) {
401
379
  `;
402
380
  }
403
381
  else {
404
- // Layout Tailwind CSS uniquement
382
+ // Layout Tailwind CSS uniquement - Server Component
405
383
  layoutContent = `// GENERATED BY LASTBRAIN APP-SHELL
406
-
407
- "use client";
384
+ // Server Component pour permettre le SSR des pages enfants
408
385
 
409
386
  import "../styles/globals.css";
410
- import { ThemeProvider } from "next-themes";
411
- import { AppProviders } from "../components/AppProviders";
387
+ import { ClientLayout } from "../components/ClientLayout";
412
388
  import type { PropsWithChildren } from "react";
413
- import { AppHeader } from "../components/AppHeader";
414
389
 
415
390
  export default function RootLayout({ children }: PropsWithChildren<{}>) {
416
391
  return (
417
392
  <html lang="fr" suppressHydrationWarning>
418
393
  <body className="min-h-screen">
419
- <ThemeProvider
420
- attribute="class"
421
- defaultTheme="light"
422
- enableSystem={false}
423
- storageKey="lastbrain-theme"
424
- >
425
- <AppProviders>
426
- <AppHeader />
427
- <div className="min-h-screen bg-slate-50 text-slate-900 dark:bg-slate-950 dark:text-white">
428
- {children}
429
- </div>
430
- </AppProviders>
431
- </ThemeProvider>
394
+ <ClientLayout>{children}</ClientLayout>
432
395
  </body>
433
396
  </html>
434
397
  );
@@ -457,9 +420,16 @@ export default function RootLayout({ children }: PropsWithChildren<{}>) {
457
420
  const homePageContent = `// GENERATED BY LASTBRAIN APP-SHELL
458
421
 
459
422
  import { SimpleHomePage } from "@lastbrain/app";
423
+ import { Footer } from "@lastbrain/ui";
424
+ import { footerConfig } from "../config/footer";
460
425
 
461
426
  export default function RootPage() {
462
- return <SimpleHomePage showAuth={${withAuth}} />;
427
+ return (
428
+ <>
429
+ <SimpleHomePage showAuth={${withAuth}} />
430
+ <Footer config={footerConfig} />
431
+ </>
432
+ );
463
433
  }
464
434
  `;
465
435
  await fs.writeFile(homePagePath, homePageContent);
@@ -504,6 +474,8 @@ export default function NotFound() {
504
474
  await createRoute(appDir, "admin", "admin", force);
505
475
  await createRoute(appDir, "auth", "auth", force);
506
476
  await createRoute(appDir, "docs", "public", force);
477
+ // Créer le composant ClientLayout (wrapper client avec providers)
478
+ await createClientLayout(targetDir, force, useHeroUI);
507
479
  // Créer le composant AppHeader
508
480
  await createAppHeader(targetDir, force);
509
481
  // Créer le composant AppAside
@@ -511,6 +483,81 @@ export default function NotFound() {
511
483
  // Créer le wrapper AppProviders avec configuration realtime
512
484
  await createAppProvidersWrapper(targetDir, force);
513
485
  }
486
+ async function createClientLayout(targetDir, force, useHeroUI) {
487
+ const componentsDir = path.join(targetDir, "components");
488
+ await fs.ensureDir(componentsDir);
489
+ const clientLayoutPath = path.join(componentsDir, "ClientLayout.tsx");
490
+ if (!fs.existsSync(clientLayoutPath) || force) {
491
+ let clientLayoutContent = "";
492
+ if (useHeroUI) {
493
+ // ClientLayout avec HeroUI
494
+ clientLayoutContent = `"use client";
495
+
496
+ import { HeroUIProvider } from "@heroui/system";
497
+ import { ThemeProvider } from "next-themes";
498
+ import { useRouter } from "next/navigation";
499
+ import { AppProviders } from "./AppProviders";
500
+ import { AppHeader } from "./AppHeader";
501
+ import type { ReactNode } from "react";
502
+
503
+ export function ClientLayout({ children }: { children: ReactNode }) {
504
+ const router = useRouter();
505
+
506
+ return (
507
+ <HeroUIProvider navigate={router.push}>
508
+ <ThemeProvider
509
+ attribute="class"
510
+ defaultTheme="dark"
511
+ enableSystem={false}
512
+ storageKey="lastbrain-theme"
513
+ >
514
+ <AppProviders>
515
+ <AppHeader />
516
+ <div className="min-h-screen text-foreground bg-background">
517
+ {children}
518
+ </div>
519
+ </AppProviders>
520
+ </ThemeProvider>
521
+ </HeroUIProvider>
522
+ );
523
+ }
524
+ `;
525
+ }
526
+ else {
527
+ // ClientLayout Tailwind CSS uniquement
528
+ clientLayoutContent = `"use client";
529
+
530
+ import { ThemeProvider } from "next-themes";
531
+ import { AppProviders } from "./AppProviders";
532
+ import { AppHeader } from "./AppHeader";
533
+ import type { ReactNode } from "react";
534
+
535
+ export function ClientLayout({ children }: { children: ReactNode }) {
536
+ return (
537
+ <ThemeProvider
538
+ attribute="class"
539
+ defaultTheme="light"
540
+ enableSystem={false}
541
+ storageKey="lastbrain-theme"
542
+ >
543
+ <AppProviders>
544
+ <AppHeader />
545
+ <div className="min-h-screen bg-slate-50 text-slate-900 dark:bg-slate-950 dark:text-white">
546
+ {children}
547
+ </div>
548
+ </AppProviders>
549
+ </ThemeProvider>
550
+ );
551
+ }
552
+ `;
553
+ }
554
+ await fs.writeFile(clientLayoutPath, clientLayoutContent);
555
+ console.log(chalk.green("✓ components/ClientLayout.tsx créé"));
556
+ }
557
+ else {
558
+ console.log(chalk.gray(" components/ClientLayout.tsx existe déjà (utilisez --force pour écraser)"));
559
+ }
560
+ }
514
561
  async function createRoute(appDir, routeName, layoutType, force) {
515
562
  const routeDir = path.join(appDir, routeName);
516
563
  await fs.ensureDir(routeDir);
@@ -553,11 +600,26 @@ export default function AuthLayout({
553
600
  }`;
554
601
  }
555
602
  else {
556
- // Layout standard pour les autres routes
603
+ // Layout standard pour les autres routes (ex: docs = public)
557
604
  const layoutComponent = layoutType.charAt(0).toUpperCase() + layoutType.slice(1) + "Layout";
558
- layoutContent = `import { ${layoutComponent} } from "@lastbrain/app";
605
+ if (routeName === "docs") {
606
+ // Layout docs avec footer
607
+ layoutContent = `import { ${layoutComponent} } from "@lastbrain/app";
608
+ import { footerConfig } from "../../config/footer";
609
+
610
+ export default function DocsLayout({
611
+ children,
612
+ }: {
613
+ children: React.ReactNode;
614
+ }) {
615
+ return <${layoutComponent} footerConfig={footerConfig}>{children}</${layoutComponent}>;
616
+ }`;
617
+ }
618
+ else {
619
+ layoutContent = `import { ${layoutComponent} } from "@lastbrain/app";
559
620
 
560
621
  export default ${layoutComponent};`;
622
+ }
561
623
  }
562
624
  await fs.writeFile(layoutPath, layoutContent);
563
625
  console.log(chalk.green(`✓ app/${routeName}/layout.tsx créé`));
@@ -721,7 +783,7 @@ export function AppProviders({ children }: { children: ReactNode }) {
721
783
  console.log(chalk.gray(" components/AppProviders.tsx existe déjà (utilisez --force pour écraser)"));
722
784
  }
723
785
  }
724
- async function createConfigFiles(targetDir, force, useHeroUI) {
786
+ async function createConfigFiles(targetDir, force, useHeroUI, projectName) {
725
787
  console.log(chalk.yellow("\n⚙️ Création des fichiers de configuration..."));
726
788
  // middleware.ts - Protection des routes /auth/*, /admin/* et /api/admin/*
727
789
  const middlewarePath = path.join(targetDir, "middleware.ts");
@@ -983,6 +1045,25 @@ export const menuConfig: MenuConfig = {
983
1045
  await fs.writeFile(menuConfigPath, menuConfig);
984
1046
  console.log(chalk.green("✓ config/menu.ts créé"));
985
1047
  }
1048
+ // config/footer.ts
1049
+ const footerConfigPath = path.join(configDir, "footer.ts");
1050
+ if (!fs.existsSync(footerConfigPath) || force) {
1051
+ const footerConfig = `// Auto-generated footer configuration
1052
+ // Run "node ../../scripts/generate-footer-config.js ./apps/[your-app]" to regenerate
1053
+ "use client";
1054
+
1055
+ import type { FooterConfig } from "@lastbrain/ui";
1056
+
1057
+ export const footerConfig: FooterConfig = {
1058
+ companyName: "${projectName}",
1059
+ companyDescription: "Application LastBrain",
1060
+ links: [],
1061
+ social: [],
1062
+ };
1063
+ `;
1064
+ await fs.writeFile(footerConfigPath, footerConfig);
1065
+ console.log(chalk.green("✓ config/footer.ts créé"));
1066
+ }
986
1067
  // Créer les hooks
987
1068
  await createHooksDirectory(targetDir, force);
988
1069
  }
@@ -1 +1 @@
1
- {"version":3,"file":"module-add.d.ts","sourceRoot":"","sources":["../../src/scripts/module-add.ts"],"names":[],"mappings":"AAiCA,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,iBA6VpE"}
1
+ {"version":3,"file":"module-add.d.ts","sourceRoot":"","sources":["../../src/scripts/module-add.ts"],"names":[],"mappings":"AAiCA,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,iBA+SpE"}
@@ -145,62 +145,32 @@ export async function addModule(moduleName, targetDir) {
145
145
  }
146
146
  else if (migrationAction === "push") {
147
147
  console.log(chalk.yellow("\n⬆️ Application des nouvelles migrations..."));
148
- try {
149
- // Essayer en capturant la sortie pour diagnostiquer les erreurs fréquentes
150
- execSync("supabase migration up --local", {
151
- cwd: targetDir,
152
- stdio: "pipe",
153
- });
154
- console.log(chalk.green("✓ Migrations appliquées"));
148
+ // Appliquer directement avec psql au lieu de supabase migration up
149
+ const migrationsDir = path.join(targetDir, "supabase", "migrations");
150
+ const migrationFiles = fs
151
+ .readdirSync(migrationsDir)
152
+ .filter((f) => f.endsWith(".sql"))
153
+ .filter((f) => copiedMigrationFiles.includes(f))
154
+ .sort();
155
+ if (migrationFiles.length === 0) {
156
+ console.log(chalk.yellow("⚠️ Aucune nouvelle migration à appliquer"));
155
157
  }
156
- catch (error) {
157
- const output = String(error?.stderr || error?.stdout || error?.message || "");
158
- const mismatch = output.includes("Remote migration versions not found in local migrations directory");
159
- if (mismatch) {
160
- console.warn(chalk.yellow("⚠️ Historique des migrations désynchronisé."));
161
- // Extraire TOUTES les dates de migration depuis le message d'erreur
162
- const repairMatch = output.match(/supabase migration repair --status reverted ([\s\S]+?)\n/);
163
- let migrationDates = [];
164
- if (repairMatch && repairMatch[1]) {
165
- // Extraire toutes les dates de la commande suggérée
166
- migrationDates = repairMatch[1].trim().split(/\s+/);
167
- }
168
- else {
169
- // Fallback: chercher toutes les dates dans le message
170
- const allDates = output.match(/20\d{6,14}/g);
171
- migrationDates = allDates ? [...new Set(allDates)] : [];
172
- }
173
- if (migrationDates.length === 0) {
174
- console.error(chalk.red("❌ Impossible d'extraire les dates de migration"));
175
- console.log(chalk.gray("\nFaites un reset complet:\n supabase db reset\n"));
176
- }
177
- else {
178
- // Réparation automatique de l'historique
179
- const datesStr = migrationDates.join(" ");
180
- console.log(chalk.yellow(`\n🔧 Réparation automatique de l'historique...`));
181
- console.log(chalk.gray(` Dates: ${datesStr}`));
182
- try {
183
- execSync(`supabase migration repair --status reverted ${datesStr} --local`, {
184
- cwd: targetDir,
185
- stdio: "inherit",
186
- });
187
- console.log(chalk.green("✓ Historique réparé"));
188
- console.log(chalk.yellow("\n⬆️ Application des nouvelles migrations..."));
189
- execSync("supabase migration up --local", {
190
- cwd: targetDir,
191
- stdio: "inherit",
192
- });
193
- console.log(chalk.green("✓ Migrations appliquées"));
194
- }
195
- catch (e) {
196
- console.error(chalk.red("❌ Échec de la réparation automatique"));
197
- console.log(chalk.gray(`\nVous pouvez essayer manuellement:\n supabase migration repair --status reverted ${datesStr} --local\n supabase migration up --local`));
198
- console.log(chalk.gray(`\nOu faire un reset complet:\n supabase db reset\n`));
199
- }
158
+ else {
159
+ try {
160
+ const dbUrl = "postgresql://postgres:postgres@127.0.0.1:54322/postgres";
161
+ for (const file of migrationFiles) {
162
+ const filePath = path.join(migrationsDir, file);
163
+ console.log(chalk.gray(` Exécution de ${file}...`));
164
+ execSync(`psql "${dbUrl}" -f "${filePath}"`, {
165
+ cwd: targetDir,
166
+ stdio: "pipe",
167
+ });
200
168
  }
169
+ console.log(chalk.green(`✓ ${migrationFiles.length} migration(s) appliquée(s)`));
201
170
  }
202
- else {
171
+ catch (error) {
203
172
  console.error(chalk.red("❌ Erreur lors de l'application des migrations"));
173
+ console.log(chalk.gray("\nVous pouvez essayer manuellement:\n supabase db reset\n"));
204
174
  }
205
175
  }
206
176
  }
@@ -1 +1 @@
1
- {"version":3,"file":"module-build.d.ts","sourceRoot":"","sources":["../../src/scripts/module-build.ts"],"names":[],"mappings":"AA69BA,wBAAsB,cAAc,kBA6EnC"}
1
+ {"version":3,"file":"module-build.d.ts","sourceRoot":"","sources":["../../src/scripts/module-build.ts"],"names":[],"mappings":"AA63CA,wBAAsB,cAAc,kBA+FnC"}