@lastbrain/app 0.1.37 → 0.1.40

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/cli.js CHANGED
@@ -89,8 +89,13 @@ program
89
89
  program
90
90
  .command("module:build")
91
91
  .description("Build les configurations de modules")
92
- .action(async () => {
92
+ .option("--debug", "Affiche tous les logs détaillés")
93
+ .action(async (options) => {
93
94
  try {
95
+ // Passer le flag debug via process.argv pour que module-build puisse le lire
96
+ if (options.debug && !process.argv.includes("--debug")) {
97
+ process.argv.push("--debug");
98
+ }
94
99
  const { runModuleBuild } = await import("./scripts/module-build.js");
95
100
  await runModuleBuild();
96
101
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AdminLayoutWithSidebar.d.ts","sourceRoot":"","sources":["../../src/layouts/AdminLayoutWithSidebar.tsx"],"names":[],"mappings":"AAOA,UAAU,2BAA2B;IACnC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,UAAU,EACV,SAAc,GACf,EAAE,2BAA2B,2CAyC7B"}
1
+ {"version":3,"file":"AdminLayoutWithSidebar.d.ts","sourceRoot":"","sources":["../../src/layouts/AdminLayoutWithSidebar.tsx"],"names":[],"mappings":"AAQA,UAAU,2BAA2B;IACnC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,UAAU,EACV,SAAc,GACf,EAAE,2BAA2B,2CA0F7B"}
@@ -4,9 +4,44 @@ import { AdminLayout } from "./AdminLayout.js";
4
4
  import { AppAside, AppAsideSkeleton } from "@lastbrain/ui";
5
5
  import { useAuthSession } from "../auth/useAuthSession.js";
6
6
  import { usePathname } from "next/navigation";
7
+ import { useEffect, useState } from "react";
7
8
  export function AdminLayoutWithSidebar({ children, menuConfig, className = "", }) {
8
9
  const { isSuperAdmin, loading, user } = useAuthSession();
9
10
  const pathname = usePathname();
11
+ const [isCollapsed, setIsCollapsed] = useState(() => {
12
+ if (typeof window !== "undefined") {
13
+ const savedState = localStorage.getItem("aside-collapsed");
14
+ return savedState !== null ? JSON.parse(savedState) : false;
15
+ }
16
+ return false;
17
+ });
18
+ const [mounted, setMounted] = useState(false);
19
+ useEffect(() => {
20
+ // eslint-disable-next-line react-hooks/set-state-in-effect
21
+ setMounted(true);
22
+ }, []);
23
+ useEffect(() => {
24
+ if (typeof window !== "undefined") {
25
+ // Écouter les changements du localStorage depuis le même onglet
26
+ const handleStorageChange = (_e) => {
27
+ const savedState = localStorage.getItem("aside-collapsed");
28
+ if (savedState !== null) {
29
+ // Utiliser queueMicrotask pour déférer le setState
30
+ queueMicrotask(() => {
31
+ setIsCollapsed(JSON.parse(savedState));
32
+ });
33
+ }
34
+ };
35
+ // Écouter l'événement storage (changements depuis d'autres onglets)
36
+ window.addEventListener("storage", handleStorageChange);
37
+ // Écouter l'événement custom pour les changements du même onglet
38
+ window.addEventListener("localStorage-changed", handleStorageChange);
39
+ return () => {
40
+ window.removeEventListener("storage", handleStorageChange);
41
+ window.removeEventListener("localStorage-changed", handleStorageChange);
42
+ };
43
+ }
44
+ }, []);
10
45
  // Détecter si on est dans la section admin pour le skeleton
11
46
  const isAdminSection = pathname.startsWith("/admin");
12
47
  // Vérifier si menuConfig est vraiment disponible et valide
@@ -17,5 +52,5 @@ export function AdminLayoutWithSidebar({ children, menuConfig, className = "", }
17
52
  menuConfig.public?.length > 0);
18
53
  // Afficher le skeleton pendant le chargement de la session ou si pas de menuConfig valide
19
54
  const shouldShowSkeleton = loading || !hasValidMenuConfig;
20
- return (_jsxs("div", { className: "flex min-h-screen", children: [shouldShowSkeleton ? (_jsx(AppAsideSkeleton, { className: className, isAdminSection: isAdminSection })) : (_jsx(AppAside, { menuConfig: menuConfig, isSuperAdmin: isSuperAdmin, isAuthenticated: !!user, className: className })), _jsx("div", { className: "flex-1 lg:ml-72", children: _jsx(AdminLayout, { children: children }) })] }));
55
+ return (_jsxs("div", { className: "flex min-h-screen", children: [shouldShowSkeleton ? (_jsx(AppAsideSkeleton, { className: className, isAdminSection: isAdminSection })) : (_jsx(AppAside, { menuConfig: menuConfig, isSuperAdmin: isSuperAdmin, isAuthenticated: !!user, className: className })), _jsx("div", { className: `flex-1 transition-all duration-300 ${!mounted ? "lg:ml-72" : isCollapsed ? "lg:ml-20" : "lg:ml-72"}`, children: _jsx(AdminLayout, { children: children }) })] }));
21
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AuthLayoutWithSidebar.d.ts","sourceRoot":"","sources":["../../src/layouts/AuthLayoutWithSidebar.tsx"],"names":[],"mappings":"AAMA,UAAU,0BAA0B;IAClC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,qBAAqB,CAAC,EACpC,QAAQ,EACR,UAAU,EACV,SAAc,GACf,EAAE,0BAA0B,2CAuC5B"}
1
+ {"version":3,"file":"AuthLayoutWithSidebar.d.ts","sourceRoot":"","sources":["../../src/layouts/AuthLayoutWithSidebar.tsx"],"names":[],"mappings":"AAOA,UAAU,0BAA0B;IAClC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,qBAAqB,CAAC,EACpC,QAAQ,EACR,UAAU,EACV,SAAc,GACf,EAAE,0BAA0B,2CAwF5B"}
@@ -3,8 +3,43 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { AuthLayout } from "./AuthLayout.js";
4
4
  import { AppAside, AppAsideSkeleton } from "@lastbrain/ui";
5
5
  import { useAuthSession } from "../auth/useAuthSession.js";
6
+ import { useEffect, useState } from "react";
6
7
  export function AuthLayoutWithSidebar({ children, menuConfig, className = "", }) {
7
8
  const { isSuperAdmin, loading, user } = useAuthSession();
9
+ const [isCollapsed, setIsCollapsed] = useState(() => {
10
+ if (typeof window !== "undefined") {
11
+ const savedState = localStorage.getItem("aside-collapsed");
12
+ return savedState !== null ? JSON.parse(savedState) : false;
13
+ }
14
+ return false;
15
+ });
16
+ const [mounted, setMounted] = useState(false);
17
+ useEffect(() => {
18
+ // eslint-disable-next-line react-hooks/set-state-in-effect
19
+ setMounted(true);
20
+ }, []);
21
+ useEffect(() => {
22
+ if (typeof window !== "undefined") {
23
+ // Écouter les changements du localStorage depuis le même onglet
24
+ const handleStorageChange = (_e) => {
25
+ const savedState = localStorage.getItem("aside-collapsed");
26
+ if (savedState !== null) {
27
+ // Utiliser queueMicrotask pour déférer le setState
28
+ queueMicrotask(() => {
29
+ setIsCollapsed(JSON.parse(savedState));
30
+ });
31
+ }
32
+ };
33
+ // Écouter l'événement storage (changements depuis d'autres onglets)
34
+ window.addEventListener("storage", handleStorageChange);
35
+ // Écouter l'événement custom pour les changements du même onglet
36
+ window.addEventListener("localStorage-changed", handleStorageChange);
37
+ return () => {
38
+ window.removeEventListener("storage", handleStorageChange);
39
+ window.removeEventListener("localStorage-changed", handleStorageChange);
40
+ };
41
+ }
42
+ }, []);
8
43
  // Pour la section auth, isAdminSection sera false
9
44
  const isAdminSection = false;
10
45
  // Vérifier si menuConfig est vraiment disponible et valide
@@ -15,5 +50,5 @@ export function AuthLayoutWithSidebar({ children, menuConfig, className = "", })
15
50
  menuConfig.public?.length > 0);
16
51
  // Afficher le skeleton pendant le chargement de la session ou si pas de menuConfig valide
17
52
  const shouldShowSkeleton = loading || !hasValidMenuConfig;
18
- return (_jsxs("div", { className: "flex min-h-screen", children: [shouldShowSkeleton ? (_jsx(AppAsideSkeleton, { className: className, isAdminSection: isAdminSection })) : (_jsx(AppAside, { menuConfig: menuConfig, isSuperAdmin: isSuperAdmin, isAuthenticated: !!user, className: className })), _jsx("div", { className: "flex-1 lg:ml-72", children: _jsx(AuthLayout, { children: children }) })] }));
53
+ return (_jsxs("div", { className: "flex min-h-screen", children: [shouldShowSkeleton ? (_jsx(AppAsideSkeleton, { className: className, isAdminSection: isAdminSection })) : (_jsx(AppAside, { menuConfig: menuConfig, isSuperAdmin: isSuperAdmin, isAuthenticated: !!user, className: className })), _jsx("div", { className: `flex-1 transition-all duration-300 ${!mounted ? "lg:ml-72" : isCollapsed ? "lg:ml-20" : "lg:ml-72"}`, children: _jsx(AuthLayout, { children: children }) })] }));
19
54
  }
@@ -1,5 +1,5 @@
1
1
  "use client";
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  export function PublicLayout({ children }) {
4
- return _jsx("section", { className: " ", children: children });
4
+ return _jsx("section", { className: "pt-16 px-2 md:px-0 ", children: children });
5
5
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PublicLayoutWithSidebar.d.ts","sourceRoot":"","sources":["../../src/layouts/PublicLayoutWithSidebar.tsx"],"names":[],"mappings":"AAMA,UAAU,4BAA4B;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,UAAU,EACV,SAAc,GACf,EAAE,4BAA4B,2CAuC9B"}
1
+ {"version":3,"file":"PublicLayoutWithSidebar.d.ts","sourceRoot":"","sources":["../../src/layouts/PublicLayoutWithSidebar.tsx"],"names":[],"mappings":"AAOA,UAAU,4BAA4B;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,UAAU,EACV,SAAc,GACf,EAAE,4BAA4B,2CAwF9B"}
@@ -3,8 +3,43 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { PublicLayout } from "./PublicLayout.js";
4
4
  import { AppAside, AppAsideSkeleton } from "@lastbrain/ui";
5
5
  import { useAuthSession } from "../auth/useAuthSession.js";
6
+ import { useEffect, useState } from "react";
6
7
  export function PublicLayoutWithSidebar({ children, menuConfig, className = "", }) {
7
8
  const { user, loading } = useAuthSession();
9
+ const [isCollapsed, setIsCollapsed] = useState(() => {
10
+ if (typeof window !== "undefined") {
11
+ const savedState = localStorage.getItem("aside-collapsed");
12
+ return savedState !== null ? JSON.parse(savedState) : false;
13
+ }
14
+ return false;
15
+ });
16
+ const [mounted, setMounted] = useState(false);
17
+ useEffect(() => {
18
+ // eslint-disable-next-line react-hooks/set-state-in-effect
19
+ setMounted(true);
20
+ }, []);
21
+ useEffect(() => {
22
+ if (typeof window !== "undefined") {
23
+ // Écouter les changements du localStorage depuis le même onglet
24
+ const handleStorageChange = (_e) => {
25
+ const savedState = localStorage.getItem("aside-collapsed");
26
+ if (savedState !== null) {
27
+ // Utiliser queueMicrotask pour déférer le setState
28
+ queueMicrotask(() => {
29
+ setIsCollapsed(JSON.parse(savedState));
30
+ });
31
+ }
32
+ };
33
+ // Écouter l'événement storage (changements depuis d'autres onglets)
34
+ window.addEventListener("storage", handleStorageChange);
35
+ // Écouter l'événement custom pour les changements du même onglet
36
+ window.addEventListener("localStorage-changed", handleStorageChange);
37
+ return () => {
38
+ window.removeEventListener("storage", handleStorageChange);
39
+ window.removeEventListener("localStorage-changed", handleStorageChange);
40
+ };
41
+ }
42
+ }, []);
8
43
  // Pour la section public, isAdminSection sera false
9
44
  const isAdminSection = false;
10
45
  // Vérifier si menuConfig est vraiment disponible et valide
@@ -15,5 +50,5 @@ export function PublicLayoutWithSidebar({ children, menuConfig, className = "",
15
50
  menuConfig.public?.length > 0);
16
51
  // Afficher le skeleton pendant le chargement de la session ou si pas de menuConfig valide
17
52
  const shouldShowSkeleton = loading || !hasValidMenuConfig;
18
- return (_jsxs("div", { className: "flex min-h-screen", children: [shouldShowSkeleton ? (_jsx(AppAsideSkeleton, { className: className, isAdminSection: isAdminSection })) : (_jsx(AppAside, { menuConfig: menuConfig, isSuperAdmin: false, isAuthenticated: !!user, className: className })), _jsx("div", { className: "flex-1 lg:ml-72", children: _jsx(PublicLayout, { children: children }) })] }));
53
+ return (_jsxs("div", { className: "flex min-h-screen", children: [shouldShowSkeleton ? (_jsx(AppAsideSkeleton, { className: className, isAdminSection: isAdminSection })) : (_jsx(AppAside, { menuConfig: menuConfig, isSuperAdmin: false, isAuthenticated: !!user, className: className })), _jsx("div", { className: `flex-1 transition-all duration-300 ${!mounted ? "lg:ml-72" : isCollapsed ? "lg:ml-20" : "lg:ml-72"}`, children: _jsx(PublicLayout, { children: children }) })] }));
19
54
  }
@@ -723,7 +723,7 @@ export function AppProviders({ children }: { children: ReactNode }) {
723
723
  }
724
724
  async function createConfigFiles(targetDir, force, useHeroUI) {
725
725
  console.log(chalk.yellow("\n⚙️ Création des fichiers de configuration..."));
726
- // middleware.ts - Protection des routes /auth/* et /admin/*
726
+ // middleware.ts - Protection des routes /auth/*, /admin/* et /api/admin/*
727
727
  const middlewarePath = path.join(targetDir, "middleware.ts");
728
728
  if (!fs.existsSync(middlewarePath) || force) {
729
729
  const middleware = `import { type NextRequest, NextResponse } from "next/server";
@@ -731,6 +731,7 @@ import { createMiddlewareClient } from "@lastbrain/core/server";
731
731
 
732
732
  export async function middleware(request: NextRequest) {
733
733
  const { pathname } = request.nextUrl;
734
+ const isApi = pathname.startsWith("/api/");
734
735
 
735
736
  // Protéger les routes /auth/* (espace membre)
736
737
  if (pathname.startsWith("/auth")) {
@@ -740,33 +741,56 @@ export async function middleware(request: NextRequest) {
740
741
  data: { session },
741
742
  } = await supabase.auth.getSession();
742
743
 
743
- // Pas de session → redirection vers /signin
744
+ // Pas de session → nettoyage des cookies + redirection vers /auth/signin
744
745
  if (!session) {
745
- const redirectUrl = new URL("/signin", request.url);
746
+ const redirectUrl = new URL("/auth/signin", request.url);
746
747
  redirectUrl.searchParams.set("redirect", pathname);
747
- return NextResponse.redirect(redirectUrl);
748
+ const res = NextResponse.redirect(redirectUrl);
749
+ res.cookies.delete("sb-access-token");
750
+ res.cookies.delete("sb-refresh-token");
751
+ res.cookies.delete("sb:token");
752
+ res.cookies.delete("sb:refresh-token");
753
+ return res;
748
754
  }
749
755
 
750
756
  return response;
751
757
  } catch (error) {
752
758
  console.error("Middleware auth error:", error);
753
- return NextResponse.redirect(new URL("/signin", request.url));
759
+ const res = NextResponse.redirect(new URL("/auth/signin", request.url));
760
+ res.cookies.delete("sb-access-token");
761
+ res.cookies.delete("sb-refresh-token");
762
+ res.cookies.delete("sb:token");
763
+ res.cookies.delete("sb:refresh-token");
764
+ return res;
754
765
  }
755
766
  }
756
767
 
757
- // Protéger les routes /admin/* (superadmin uniquement)
758
- if (pathname.startsWith("/admin")) {
768
+ // Protéger les routes /admin/* et /api/admin/* (superadmin uniquement)
769
+ if (pathname.startsWith("/admin") || pathname.startsWith("/api/admin")) {
759
770
  try {
760
771
  const { supabase, response } = createMiddlewareClient(request);
761
772
  const {
762
773
  data: { session },
763
774
  } = await supabase.auth.getSession();
764
775
 
765
- // Pas de session → redirection vers /signin
776
+ // Pas de session → 401 JSON pour API, sinon redirection vers /auth/signin avec nettoyage cookies
766
777
  if (!session) {
767
- const redirectUrl = new URL("/signin", request.url);
778
+ if (isApi) {
779
+ const res = NextResponse.json({ error: "Non authentifié" }, { status: 401 });
780
+ res.cookies.delete("sb-access-token");
781
+ res.cookies.delete("sb-refresh-token");
782
+ res.cookies.delete("sb:token");
783
+ res.cookies.delete("sb:refresh-token");
784
+ return res;
785
+ }
786
+ const redirectUrl = new URL("/auth/signin", request.url);
768
787
  redirectUrl.searchParams.set("redirect", pathname);
769
- return NextResponse.redirect(redirectUrl);
788
+ const res = NextResponse.redirect(redirectUrl);
789
+ res.cookies.delete("sb-access-token");
790
+ res.cookies.delete("sb-refresh-token");
791
+ res.cookies.delete("sb:token");
792
+ res.cookies.delete("sb:refresh-token");
793
+ return res;
770
794
  }
771
795
 
772
796
  // Vérifier si l'utilisateur est superadmin
@@ -777,13 +801,24 @@ export async function middleware(request: NextRequest) {
777
801
 
778
802
  if (error || !isSuperAdmin) {
779
803
  console.error("Access denied: not a superadmin", error);
804
+ if (isApi) {
805
+ return NextResponse.json({ error: "Accès refusé" }, { status: 403 });
806
+ }
780
807
  return NextResponse.redirect(new URL("/", request.url));
781
808
  }
782
809
 
783
810
  return response;
784
811
  } catch (error) {
785
812
  console.error("Middleware admin error:", error);
786
- return NextResponse.redirect(new URL("/", request.url));
813
+ if (isApi) {
814
+ return NextResponse.json({ error: "Erreur middleware" }, { status: 500 });
815
+ }
816
+ const res = NextResponse.redirect(new URL("/", request.url));
817
+ res.cookies.delete("sb-access-token");
818
+ res.cookies.delete("sb-refresh-token");
819
+ res.cookies.delete("sb:token");
820
+ res.cookies.delete("sb:refresh-token");
821
+ return res;
787
822
  }
788
823
  }
789
824
 
@@ -804,7 +839,7 @@ export const config = {
804
839
  };
805
840
  `;
806
841
  await fs.writeFile(middlewarePath, middleware);
807
- console.log(chalk.green("✓ middleware.ts créé (protection /auth/* et /admin/*)"));
842
+ console.log(chalk.green("✓ middleware.ts créé (protection /auth/*, /admin/* et /api/admin/*)"));
808
843
  }
809
844
  // next.config.mjs
810
845
  const nextConfigPath = path.join(targetDir, "next.config.mjs");
@@ -1290,6 +1325,13 @@ export const BUCKET_CONFIGS: Record<string, BucketConfig> = {
1290
1325
  return filePath.startsWith(\`\${userId}/\`);
1291
1326
  },
1292
1327
  },
1328
+ recipes: {
1329
+ name: "recipes",
1330
+ isPublic: true,
1331
+ description: "Public recipe images accessible by slug",
1332
+ allowedFileTypes: ["image/jpeg", "image/png", "image/webp", "image/gif"],
1333
+ maxFileSize: 50 * 1024 * 1024, // 50MB
1334
+ },
1293
1335
  // Example for future buckets:
1294
1336
  // public: {
1295
1337
  // name: "public",
@@ -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,iBA8QpE"}
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"}
@@ -146,14 +146,62 @@ export async function addModule(moduleName, targetDir) {
146
146
  else if (migrationAction === "push") {
147
147
  console.log(chalk.yellow("\n⬆️ Application des nouvelles migrations..."));
148
148
  try {
149
- execSync("supabase migration up", {
149
+ // Essayer en capturant la sortie pour diagnostiquer les erreurs fréquentes
150
+ execSync("supabase migration up --local", {
150
151
  cwd: targetDir,
151
- stdio: "inherit",
152
+ stdio: "pipe",
152
153
  });
153
154
  console.log(chalk.green("✓ Migrations appliquées"));
154
155
  }
155
- catch {
156
- console.error(chalk.red("❌ Erreur lors de l'application des migrations"));
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
+ }
200
+ }
201
+ }
202
+ else {
203
+ console.error(chalk.red("❌ Erreur lors de l'application des migrations"));
204
+ }
157
205
  }
158
206
  }
159
207
  else {
@@ -203,12 +251,12 @@ export async function addModule(moduleName, targetDir) {
203
251
  // 7. Générer automatiquement les routes du module
204
252
  console.log(chalk.yellow("🔧 Génération des routes du module..."));
205
253
  try {
206
- execSync("pnpm build:modules", { cwd: targetDir, stdio: "inherit" });
254
+ execSync("pnpm run build:modules", { cwd: targetDir, stdio: "inherit" });
207
255
  console.log(chalk.green("✓ Routes du module générées"));
208
256
  }
209
257
  catch {
210
258
  console.error(chalk.red("❌ Erreur lors de la génération des routes"));
211
- console.error(chalk.gray("Vous pouvez les générer manuellement avec: pnpm build:modules"));
259
+ console.error(chalk.gray("Vous pouvez les générer manuellement avec: cd apps/<votre-app> && pnpm run build:modules"));
212
260
  }
213
261
  console.log(chalk.gray("\nLe serveur de développement redémarrera automatiquement.\n"));
214
262
  }
@@ -1 +1 @@
1
- {"version":3,"file":"module-build.d.ts","sourceRoot":"","sources":["../../src/scripts/module-build.ts"],"names":[],"mappings":"AAg7BA,wBAAsB,cAAc,kBAoDnC"}
1
+ {"version":3,"file":"module-build.d.ts","sourceRoot":"","sources":["../../src/scripts/module-build.ts"],"names":[],"mappings":"AA69BA,wBAAsB,cAAc,kBA6EnC"}