@lastbrain/app 0.1.24 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/module-registry.test.d.ts +2 -0
- package/dist/__tests__/module-registry.test.d.ts.map +1 -0
- package/dist/__tests__/module-registry.test.js +64 -0
- package/dist/app-shell/(admin)/layout.d.ts +3 -2
- package/dist/app-shell/(admin)/layout.d.ts.map +1 -1
- package/dist/app-shell/(admin)/layout.js +1 -1
- package/dist/app-shell/(auth)/layout.d.ts +3 -2
- package/dist/app-shell/(auth)/layout.d.ts.map +1 -1
- package/dist/app-shell/(auth)/layout.js +1 -1
- package/dist/app-shell/(public)/page.d.ts.map +1 -1
- package/dist/cli.js +50 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/layouts/AdminLayout.d.ts +3 -2
- package/dist/layouts/AdminLayout.d.ts.map +1 -1
- package/dist/layouts/AdminLayoutWithSidebar.d.ts +8 -0
- package/dist/layouts/AdminLayoutWithSidebar.d.ts.map +1 -0
- package/dist/layouts/AdminLayoutWithSidebar.js +9 -0
- package/dist/layouts/AppProviders.d.ts +3 -2
- package/dist/layouts/AppProviders.d.ts.map +1 -1
- package/dist/layouts/AuthLayout.d.ts +3 -2
- package/dist/layouts/AuthLayout.d.ts.map +1 -1
- package/dist/layouts/AuthLayoutWithSidebar.d.ts +8 -0
- package/dist/layouts/AuthLayoutWithSidebar.d.ts.map +1 -0
- package/dist/layouts/AuthLayoutWithSidebar.js +9 -0
- package/dist/layouts/PublicLayout.d.ts +3 -2
- package/dist/layouts/PublicLayout.d.ts.map +1 -1
- package/dist/layouts/RootLayout.d.ts +3 -2
- package/dist/layouts/RootLayout.d.ts.map +1 -1
- package/dist/scripts/db-init.js +2 -2
- package/dist/scripts/db-migrations-sync.js +5 -5
- package/dist/scripts/dev-sync.js +21 -10
- package/dist/scripts/init-app.d.ts.map +1 -1
- package/dist/scripts/init-app.js +126 -21
- package/dist/scripts/module-add.d.ts.map +1 -1
- package/dist/scripts/module-add.js +20 -7
- package/dist/scripts/module-build.d.ts.map +1 -1
- package/dist/scripts/module-build.js +285 -30
- package/dist/scripts/module-create.d.ts.map +1 -1
- package/dist/scripts/module-create.js +25 -15
- package/dist/scripts/module-remove.d.ts.map +1 -1
- package/dist/scripts/module-remove.js +24 -11
- package/dist/scripts/script-runner.d.ts +5 -0
- package/dist/scripts/script-runner.d.ts.map +1 -0
- package/dist/scripts/script-runner.js +25 -0
- package/dist/styles.css +1 -1
- package/dist/templates/DefaultDoc.js +1 -7
- package/dist/templates/DocPage.d.ts.map +1 -1
- package/dist/templates/DocPage.js +14 -14
- package/dist/templates/components/AppAside.d.ts +6 -0
- package/dist/templates/components/AppAside.d.ts.map +1 -0
- package/dist/templates/components/AppAside.js +9 -0
- package/dist/templates/layouts/admin-layout.d.ts +4 -0
- package/dist/templates/layouts/admin-layout.d.ts.map +1 -0
- package/dist/templates/layouts/admin-layout.js +6 -0
- package/dist/templates/layouts/auth-layout.d.ts +4 -0
- package/dist/templates/layouts/auth-layout.d.ts.map +1 -0
- package/dist/templates/layouts/auth-layout.js +6 -0
- package/package.json +2 -1
- package/src/__tests__/module-registry.test.ts +74 -0
- package/src/app-shell/(admin)/layout.tsx +5 -3
- package/src/app-shell/(auth)/layout.tsx +5 -3
- package/src/app-shell/(public)/page.tsx +6 -2
- package/src/auth/useAuthSession.ts +1 -1
- package/src/cli.ts +51 -1
- package/src/index.ts +6 -0
- package/src/layouts/AdminLayout.tsx +1 -3
- package/src/layouts/AdminLayoutWithSidebar.tsx +35 -0
- package/src/layouts/AppProviders.tsx +3 -5
- package/src/layouts/AuthLayout.tsx +1 -3
- package/src/layouts/AuthLayoutWithSidebar.tsx +35 -0
- package/src/layouts/PublicLayout.tsx +1 -3
- package/src/layouts/RootLayout.tsx +1 -2
- package/src/scripts/db-init.ts +13 -8
- package/src/scripts/db-migrations-sync.ts +4 -4
- package/src/scripts/dev-sync.ts +49 -18
- package/src/scripts/init-app.ts +246 -73
- package/src/scripts/module-add.ts +49 -23
- package/src/scripts/module-build.ts +393 -88
- package/src/scripts/module-create.ts +85 -49
- package/src/scripts/module-remove.ts +116 -57
- package/src/scripts/readme-build.ts +2 -2
- package/src/scripts/script-runner.ts +28 -0
- package/src/templates/AuthGuidePage.tsx +1 -1
- package/src/templates/DefaultDoc.tsx +7 -7
- package/src/templates/DocPage.tsx +74 -46
package/src/cli.ts
CHANGED
|
@@ -23,7 +23,7 @@ program
|
|
|
23
23
|
.option("--with-auth", "Inclure le module d'authentification")
|
|
24
24
|
.option(
|
|
25
25
|
"--no-interactive",
|
|
26
|
-
"Mode non-interactif (skip la sélection des modules)"
|
|
26
|
+
"Mode non-interactif (skip la sélection des modules)",
|
|
27
27
|
)
|
|
28
28
|
.action(async (directory: string | undefined, options) => {
|
|
29
29
|
try {
|
|
@@ -93,4 +93,54 @@ program
|
|
|
93
93
|
}
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
+
// Commandes de build et maintenance
|
|
97
|
+
program
|
|
98
|
+
.command("module:build")
|
|
99
|
+
.description("Build les configurations de modules")
|
|
100
|
+
.action(async () => {
|
|
101
|
+
try {
|
|
102
|
+
const { runModuleBuild } = await import("./scripts/module-build.js");
|
|
103
|
+
await runModuleBuild();
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error("❌ Erreur lors du build des modules:", error);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
program
|
|
111
|
+
.command("db:init")
|
|
112
|
+
.description("Initialise la base de données Supabase")
|
|
113
|
+
.action(async () => {
|
|
114
|
+
try {
|
|
115
|
+
await import("./scripts/db-init.js");
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error("❌ Erreur lors de l'initialisation de la DB:", error);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
program
|
|
123
|
+
.command("db:migrations:sync")
|
|
124
|
+
.description("Synchronise les migrations de modules")
|
|
125
|
+
.action(async () => {
|
|
126
|
+
try {
|
|
127
|
+
await import("./scripts/db-migrations-sync.js");
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error("❌ Erreur lors de la sync des migrations:", error);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
program
|
|
135
|
+
.command("readme:create")
|
|
136
|
+
.description("Génère le fichier README")
|
|
137
|
+
.action(async () => {
|
|
138
|
+
try {
|
|
139
|
+
await import("./scripts/readme-build.js");
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error("❌ Erreur lors de la création du README:", error);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
96
146
|
program.parse();
|
package/src/index.ts
CHANGED
|
@@ -9,8 +9,14 @@ export { signOut, signIn } from "./auth/authHelpers.js";
|
|
|
9
9
|
export { RootLayout } from "./layouts/RootLayout.js";
|
|
10
10
|
export { PublicLayout } from "./layouts/PublicLayout.js";
|
|
11
11
|
export { AuthLayout } from "./layouts/AuthLayout.js";
|
|
12
|
+
export { AuthLayoutWithSidebar } from "./layouts/AuthLayoutWithSidebar.js";
|
|
12
13
|
export { AdminLayout } from "./layouts/AdminLayout.js";
|
|
14
|
+
export { AdminLayoutWithSidebar } from "./layouts/AdminLayoutWithSidebar.js";
|
|
13
15
|
export { getModuleConfigs } from "./modules/module-loader.js";
|
|
16
|
+
|
|
17
|
+
// Components
|
|
18
|
+
export { AppAside } from "@lastbrain/ui";
|
|
19
|
+
export type { AppAsideMenuItem, AppAsideMenuConfig } from "@lastbrain/ui";
|
|
14
20
|
// Templates de pages (starter + docs)
|
|
15
21
|
|
|
16
22
|
export { SimpleHomePage } from "./templates/SimpleHomePage.js";
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export function AdminLayout({ children }: PropsWithChildren<{}>) {
|
|
3
|
+
export function AdminLayout({ children }: { children: React.ReactNode }) {
|
|
6
4
|
return <div className="pt-18 px-2 md:px-5">{children}</div>;
|
|
7
5
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { AdminLayout } from "./AdminLayout.js";
|
|
4
|
+
import { AppAside } from "@lastbrain/ui";
|
|
5
|
+
import { useAuthSession } from "../auth/useAuthSession.js";
|
|
6
|
+
|
|
7
|
+
interface AdminLayoutWithSidebarProps {
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
menuConfig?: any;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function AdminLayoutWithSidebar({
|
|
14
|
+
children,
|
|
15
|
+
menuConfig,
|
|
16
|
+
className = "",
|
|
17
|
+
}: AdminLayoutWithSidebarProps) {
|
|
18
|
+
const { isSuperAdmin } = useAuthSession();
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div className="flex min-h-screen">
|
|
22
|
+
{menuConfig && (
|
|
23
|
+
<AppAside
|
|
24
|
+
menuConfig={menuConfig}
|
|
25
|
+
isSuperAdmin={isSuperAdmin}
|
|
26
|
+
className={className}
|
|
27
|
+
/>
|
|
28
|
+
)}
|
|
29
|
+
{/* Contenu principal avec marge pour la sidebar */}
|
|
30
|
+
<div className={`flex-1 ${menuConfig ? "lg:ml-72" : ""}`}>
|
|
31
|
+
<AdminLayout>{children}</AdminLayout>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import type { PropsWithChildren } from "react";
|
|
4
3
|
import { createContext, useContext, useMemo } from "react";
|
|
5
4
|
import { getModuleConfigs } from "../modules/module-loader.js";
|
|
6
|
-
import {
|
|
5
|
+
import { ToastProvider } from "@lastbrain/ui";
|
|
7
6
|
import { useAuthSession } from "../auth/useAuthSession.js";
|
|
8
7
|
import type { User } from "@supabase/supabase-js";
|
|
9
|
-
import { useRouter } from "next/navigation.js";
|
|
10
8
|
|
|
11
9
|
const ModuleContext = createContext(getModuleConfigs());
|
|
12
10
|
const NotificationContext = createContext({ messages: [] as string[] });
|
|
@@ -32,14 +30,14 @@ export function useAuth() {
|
|
|
32
30
|
return useContext(AuthContext);
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
export function AppProviders({ children }:
|
|
33
|
+
export function AppProviders({ children }: { children: React.ReactNode }) {
|
|
36
34
|
const modules = useMemo(() => getModuleConfigs(), []);
|
|
37
35
|
const notifications = useMemo(() => ({ messages: [] as string[] }), []);
|
|
38
36
|
const { user, loading, isSuperAdmin } = useAuthSession();
|
|
39
37
|
// const router = useRouter();
|
|
40
38
|
const authValue = useMemo(
|
|
41
39
|
() => ({ user, loading, isSuperAdmin }),
|
|
42
|
-
[user, loading, isSuperAdmin]
|
|
40
|
+
[user, loading, isSuperAdmin],
|
|
43
41
|
);
|
|
44
42
|
|
|
45
43
|
// const handleLogout = async () => {
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export function AuthLayout({ children }: PropsWithChildren<{}>) {
|
|
3
|
+
export function AuthLayout({ children }: { children: React.ReactNode }) {
|
|
6
4
|
return <div className="pt-18 px-2 md:px-5 ">{children}</div>;
|
|
7
5
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { AuthLayout } from "./AuthLayout.js";
|
|
4
|
+
import { AppAside } from "@lastbrain/ui";
|
|
5
|
+
import { useAuthSession } from "../auth/useAuthSession.js";
|
|
6
|
+
|
|
7
|
+
interface AuthLayoutWithSidebarProps {
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
menuConfig?: any;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function AuthLayoutWithSidebar({
|
|
14
|
+
children,
|
|
15
|
+
menuConfig,
|
|
16
|
+
className = "",
|
|
17
|
+
}: AuthLayoutWithSidebarProps) {
|
|
18
|
+
const { isSuperAdmin } = useAuthSession();
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div className="flex min-h-screen">
|
|
22
|
+
{menuConfig && (
|
|
23
|
+
<AppAside
|
|
24
|
+
menuConfig={menuConfig}
|
|
25
|
+
isSuperAdmin={isSuperAdmin}
|
|
26
|
+
className={className}
|
|
27
|
+
/>
|
|
28
|
+
)}
|
|
29
|
+
{/* Contenu principal avec marge pour la sidebar */}
|
|
30
|
+
<div className={`flex-1 ${menuConfig ? "lg:ml-72" : ""}`}>
|
|
31
|
+
<AuthLayout>{children}</AuthLayout>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export function PublicLayout({ children }: PropsWithChildren<{}>) {
|
|
3
|
+
export function PublicLayout({ children }: { children: React.ReactNode }) {
|
|
6
4
|
return <section className=" px-4 ">{children}</section>;
|
|
7
5
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import type { PropsWithChildren } from "react";
|
|
4
3
|
import { ThemeProvider } from "next-themes";
|
|
5
4
|
import { AppProviders } from "./AppProviders.js";
|
|
6
5
|
|
|
7
6
|
// Note: L'app Next.js doit importer son propre globals.css dans son layout
|
|
8
|
-
export function RootLayout({ children }:
|
|
7
|
+
export function RootLayout({ children }: { children: React.ReactNode }) {
|
|
9
8
|
return (
|
|
10
9
|
<html lang="fr" suppressHydrationWarning>
|
|
11
10
|
<body className="min-h-screen">
|
package/src/scripts/db-init.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
spawn,
|
|
3
|
+
spawnSync,
|
|
4
|
+
execSync as _execSync,
|
|
5
|
+
execFileSync as _execFileSync,
|
|
6
|
+
} from "node:child_process";
|
|
2
7
|
import fs from "node:fs";
|
|
3
8
|
import path from "node:path";
|
|
4
9
|
import { fileURLToPath } from "node:url";
|
|
@@ -15,7 +20,7 @@ const packageAppDir = path
|
|
|
15
20
|
.replace(/dist\/scripts$/, "src");
|
|
16
21
|
const envExampleTemplate = path.join(
|
|
17
22
|
packageAppDir,
|
|
18
|
-
"templates/env.example/.env.example"
|
|
23
|
+
"templates/env.example/.env.example",
|
|
19
24
|
);
|
|
20
25
|
|
|
21
26
|
function ensureDirectory(dir: string) {
|
|
@@ -73,7 +78,7 @@ function runSupabase(...args: any[]): Buffer | null {
|
|
|
73
78
|
// Si le processus s'est terminé avec un code de sortie non nul, propager l'erreur
|
|
74
79
|
if (result.status !== 0) {
|
|
75
80
|
const error: any = new Error(
|
|
76
|
-
`Command failed with exit code ${result.status}
|
|
81
|
+
`Command failed with exit code ${result.status}`,
|
|
77
82
|
);
|
|
78
83
|
error.status = result.status;
|
|
79
84
|
throw error;
|
|
@@ -84,7 +89,7 @@ function runSupabase(...args: any[]): Buffer | null {
|
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
throw new Error(
|
|
87
|
-
"Unable to locate Supabase CLI (install it globally or via pnpm)."
|
|
92
|
+
"Unable to locate Supabase CLI (install it globally or via pnpm).",
|
|
88
93
|
);
|
|
89
94
|
}
|
|
90
95
|
|
|
@@ -105,7 +110,7 @@ function parseEnvFile(filePath: string) {
|
|
|
105
110
|
.map((line) => {
|
|
106
111
|
const [key, ...value] = line.split("=");
|
|
107
112
|
return [key, value.join("=")];
|
|
108
|
-
})
|
|
113
|
+
}),
|
|
109
114
|
) as Record<string, string>;
|
|
110
115
|
}
|
|
111
116
|
|
|
@@ -272,7 +277,7 @@ async function main() {
|
|
|
272
277
|
stdio: "inherit",
|
|
273
278
|
env: { ...process.env, PATH: enhancedPath },
|
|
274
279
|
shell: true,
|
|
275
|
-
}
|
|
280
|
+
},
|
|
276
281
|
);
|
|
277
282
|
|
|
278
283
|
if (migrationResult.error || migrationResult.status !== 0) {
|
|
@@ -282,7 +287,7 @@ async function main() {
|
|
|
282
287
|
console.log("⚙️ Starting Supabase...");
|
|
283
288
|
try {
|
|
284
289
|
runSupabase("start");
|
|
285
|
-
} catch (
|
|
290
|
+
} catch (_error) {
|
|
286
291
|
console.warn("⚠️ Supabase start had issues, continuing...");
|
|
287
292
|
}
|
|
288
293
|
|
|
@@ -310,7 +315,7 @@ async function main() {
|
|
|
310
315
|
console.log("ℹ️ Copied .env.example into .env.local as fallback.");
|
|
311
316
|
}
|
|
312
317
|
console.warn(
|
|
313
|
-
"⚠️ Impossible de récupérer automatiquement les accès Supabase."
|
|
318
|
+
"⚠️ Impossible de récupérer automatiquement les accès Supabase.",
|
|
314
319
|
);
|
|
315
320
|
}
|
|
316
321
|
|
|
@@ -13,7 +13,7 @@ function ensureDirectory(dir: string) {
|
|
|
13
13
|
fs.mkdirSync(dir, { recursive: true });
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
enum
|
|
16
|
+
enum _CopyStrategy {
|
|
17
17
|
overwrite,
|
|
18
18
|
skip,
|
|
19
19
|
}
|
|
@@ -32,7 +32,7 @@ function copyMigration(
|
|
|
32
32
|
moduleConfig: ModuleBuildConfig,
|
|
33
33
|
migration: ModuleMigrationEntry,
|
|
34
34
|
file: string,
|
|
35
|
-
index: number
|
|
35
|
+
index: number,
|
|
36
36
|
) {
|
|
37
37
|
const moduleDir = getModulePackageDir(moduleConfig.moduleName);
|
|
38
38
|
const migrationsPath = migration.path ?? "supabase/migrations";
|
|
@@ -48,7 +48,7 @@ function copyMigration(
|
|
|
48
48
|
const moduleSlug = moduleConfig.moduleName.replace("@lastbrain/", "module-");
|
|
49
49
|
const prefix = String((migration.priority ?? 0) * 10 + index + 1).padStart(
|
|
50
50
|
3,
|
|
51
|
-
"0"
|
|
51
|
+
"0",
|
|
52
52
|
);
|
|
53
53
|
const fileName = `${prefix}_${moduleSlug}_${file}`;
|
|
54
54
|
const targetFile = path.join(migrationsDir, fileName);
|
|
@@ -67,7 +67,7 @@ function syncModuleMigrations() {
|
|
|
67
67
|
|
|
68
68
|
const moduleMigrationPath = path.join(
|
|
69
69
|
getModulePackageDir(moduleConfig.moduleName),
|
|
70
|
-
migrationBlock.path ?? "supabase/migrations"
|
|
70
|
+
migrationBlock.path ?? "supabase/migrations",
|
|
71
71
|
);
|
|
72
72
|
let files = migrationBlock.files;
|
|
73
73
|
if (!files?.length && fs.existsSync(moduleMigrationPath)) {
|
package/src/scripts/dev-sync.ts
CHANGED
|
@@ -17,18 +17,24 @@ const scriptsToEnsure = {
|
|
|
17
17
|
"build:modules": "pnpm --filter @lastbrain/app module:build",
|
|
18
18
|
"db:migrations:sync": "pnpm --filter @lastbrain/app db:migrations:sync",
|
|
19
19
|
"db:init": "pnpm --filter @lastbrain/app db:init",
|
|
20
|
-
"readme:create": "pnpm --filter @lastbrain/app readme:create"
|
|
20
|
+
"readme:create": "pnpm --filter @lastbrain/app readme:create",
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
const dependenciesToEnsure = {
|
|
24
24
|
"@lastbrain/app": "workspace:*",
|
|
25
25
|
"@lastbrain/core": "workspace:*",
|
|
26
|
-
"@lastbrain/ui": "workspace:*"
|
|
26
|
+
"@lastbrain/ui": "workspace:*",
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
const gitignoreTemplate = path.join(
|
|
29
|
+
const gitignoreTemplate = path.join(
|
|
30
|
+
projectRoot,
|
|
31
|
+
"packages/app/src/templates/gitignore/.gitignore",
|
|
32
|
+
);
|
|
30
33
|
const consumerGitignore = path.join(projectRoot, "apps/web/.gitignore");
|
|
31
|
-
const envTemplate = path.join(
|
|
34
|
+
const envTemplate = path.join(
|
|
35
|
+
projectRoot,
|
|
36
|
+
"packages/app/src/templates/env.example/.env.example",
|
|
37
|
+
);
|
|
32
38
|
const consumerEnvExample = path.join(projectRoot, "apps/web/.env.example");
|
|
33
39
|
const consumerEnvLocal = path.join(projectRoot, "apps/web/.env.local");
|
|
34
40
|
|
|
@@ -37,7 +43,9 @@ function ensureDirectory(dir: string) {
|
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
function normalizeContent(data: string) {
|
|
40
|
-
const trimmed = data.startsWith(GENERATED_HEADER)
|
|
46
|
+
const trimmed = data.startsWith(GENERATED_HEADER)
|
|
47
|
+
? data.slice(GENERATED_HEADER.length)
|
|
48
|
+
: data;
|
|
41
49
|
const sanitized = trimmed.trimStart();
|
|
42
50
|
return `${GENERATED_HEADER}\n${sanitized}`;
|
|
43
51
|
}
|
|
@@ -64,7 +72,10 @@ function copyDirectory(srcDir: string, destDir: string) {
|
|
|
64
72
|
ensureDirectory(destDir);
|
|
65
73
|
const entries = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
66
74
|
for (const entry of entries) {
|
|
67
|
-
copyDirectory(
|
|
75
|
+
copyDirectory(
|
|
76
|
+
path.join(srcDir, entry.name),
|
|
77
|
+
path.join(destDir, entry.name),
|
|
78
|
+
);
|
|
68
79
|
}
|
|
69
80
|
} else if (stats.isFile()) {
|
|
70
81
|
syncFile(srcDir, destDir);
|
|
@@ -98,7 +109,7 @@ function syncAppShell() {
|
|
|
98
109
|
function cleanupStaleGroupFiles() {
|
|
99
110
|
const staleFiles = [
|
|
100
111
|
path.join(destAppShell, "(auth)", "page.tsx"),
|
|
101
|
-
path.join(destAppShell, "(admin)", "page.tsx")
|
|
112
|
+
path.join(destAppShell, "(admin)", "page.tsx"),
|
|
102
113
|
];
|
|
103
114
|
|
|
104
115
|
staleFiles.forEach((file) => {
|
|
@@ -109,7 +120,7 @@ function cleanupStaleGroupFiles() {
|
|
|
109
120
|
|
|
110
121
|
const staleDirs = [
|
|
111
122
|
path.join(destAppShell, "(auth)", "dashboard"),
|
|
112
|
-
path.join(destAppShell, "(admin)", "dashboard")
|
|
123
|
+
path.join(destAppShell, "(admin)", "dashboard"),
|
|
113
124
|
];
|
|
114
125
|
|
|
115
126
|
staleDirs.forEach((dir) => {
|
|
@@ -119,7 +130,10 @@ function cleanupStaleGroupFiles() {
|
|
|
119
130
|
});
|
|
120
131
|
}
|
|
121
132
|
|
|
122
|
-
function mergeScripts(
|
|
133
|
+
function mergeScripts(
|
|
134
|
+
base: Record<string, string>,
|
|
135
|
+
additions: Record<string, string>,
|
|
136
|
+
) {
|
|
123
137
|
return { ...base, ...additions };
|
|
124
138
|
}
|
|
125
139
|
|
|
@@ -129,15 +143,20 @@ function syncPackageJson() {
|
|
|
129
143
|
name: "web",
|
|
130
144
|
private: true,
|
|
131
145
|
version: "0.1.0",
|
|
132
|
-
type: "module"
|
|
146
|
+
type: "module",
|
|
133
147
|
};
|
|
134
148
|
|
|
135
|
-
const pkg = fs.existsSync(webPackage)
|
|
149
|
+
const pkg = fs.existsSync(webPackage)
|
|
150
|
+
? JSON.parse(fs.readFileSync(webPackage, "utf-8"))
|
|
151
|
+
: defaultPkg;
|
|
136
152
|
pkg.scripts = mergeScripts(pkg.scripts ?? {}, scriptsToEnsure);
|
|
137
153
|
pkg.dependencies = { ...(pkg.dependencies ?? {}), ...dependenciesToEnsure };
|
|
138
154
|
|
|
139
155
|
fs.writeFileSync(webPackage, JSON.stringify(pkg, null, 2) + "\n");
|
|
140
|
-
return {
|
|
156
|
+
return {
|
|
157
|
+
scripts: Object.keys(scriptsToEnsure),
|
|
158
|
+
dependencies: Object.keys(dependenciesToEnsure),
|
|
159
|
+
};
|
|
141
160
|
}
|
|
142
161
|
|
|
143
162
|
function syncEnvExample() {
|
|
@@ -147,7 +166,9 @@ function syncEnvExample() {
|
|
|
147
166
|
|
|
148
167
|
const shouldOverwrite =
|
|
149
168
|
!fs.existsSync(consumerEnvExample) ||
|
|
150
|
-
fs
|
|
169
|
+
fs
|
|
170
|
+
.readFileSync(consumerEnvExample, "utf-8")
|
|
171
|
+
.includes("GENERATED BY LASTBRAIN");
|
|
151
172
|
|
|
152
173
|
if (!shouldOverwrite) {
|
|
153
174
|
return null;
|
|
@@ -177,7 +198,9 @@ function syncGitignore() {
|
|
|
177
198
|
|
|
178
199
|
const shouldOverwrite =
|
|
179
200
|
!fs.existsSync(consumerGitignore) ||
|
|
180
|
-
fs
|
|
201
|
+
fs
|
|
202
|
+
.readFileSync(consumerGitignore, "utf-8")
|
|
203
|
+
.includes("GENERATED BY LASTBRAIN");
|
|
181
204
|
|
|
182
205
|
if (!shouldOverwrite) {
|
|
183
206
|
return null;
|
|
@@ -199,19 +222,27 @@ function main() {
|
|
|
199
222
|
|
|
200
223
|
console.log("✅ apps/web synced with @lastbrain/app");
|
|
201
224
|
console.log(`Copied or updated files (${copiedFiles.length}):`);
|
|
202
|
-
copiedFiles.forEach((file) =>
|
|
225
|
+
copiedFiles.forEach((file) =>
|
|
226
|
+
console.log(` • ${path.relative(projectRoot, file)}`),
|
|
227
|
+
);
|
|
203
228
|
console.log("Scripts ensured in apps/web/package.json:");
|
|
204
229
|
changes.scripts.forEach((script) => console.log(` • ${script}`));
|
|
205
230
|
console.log("Dependencies ensured in apps/web/package.json:");
|
|
206
231
|
changes.dependencies.forEach((dep) => console.log(` • ${dep}`));
|
|
207
232
|
if (gitignoreSynced) {
|
|
208
|
-
console.log(
|
|
233
|
+
console.log(
|
|
234
|
+
`.gitignore ensured at ${path.relative(projectRoot, gitignoreSynced)}`,
|
|
235
|
+
);
|
|
209
236
|
}
|
|
210
237
|
if (envExampleSynced) {
|
|
211
|
-
console.log(
|
|
238
|
+
console.log(
|
|
239
|
+
`.env.example ensured at ${path.relative(projectRoot, envExampleSynced)}`,
|
|
240
|
+
);
|
|
212
241
|
}
|
|
213
242
|
if (envLocalCreated) {
|
|
214
|
-
console.log(
|
|
243
|
+
console.log(
|
|
244
|
+
`.env.local ensured at ${path.relative(projectRoot, envLocalCreated)}`,
|
|
245
|
+
);
|
|
215
246
|
}
|
|
216
247
|
}
|
|
217
248
|
|