@lastbrain/app 2.0.31 → 2.0.35
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/analytics/registry.d.ts +7 -0
- package/dist/analytics/registry.d.ts.map +1 -0
- package/dist/analytics/registry.js +11 -0
- package/dist/auth/useAuthSession.d.ts.map +1 -1
- package/dist/auth/useAuthSession.js +85 -1
- package/dist/cli.js +19 -3
- package/dist/components/LanguageSwitcher.d.ts.map +1 -1
- package/dist/components/LanguageSwitcher.js +89 -5
- package/dist/config/version.d.ts.map +1 -1
- package/dist/config/version.js +30 -19
- package/dist/i18n/useLink.d.ts.map +1 -1
- package/dist/i18n/useLink.js +15 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/layouts/AdminLayoutWithSidebar.d.ts +3 -1
- package/dist/layouts/AdminLayoutWithSidebar.d.ts.map +1 -1
- package/dist/layouts/AdminLayoutWithSidebar.js +2 -2
- package/dist/layouts/AppProviders.d.ts +7 -1
- package/dist/layouts/AppProviders.d.ts.map +1 -1
- package/dist/layouts/AppProviders.js +24 -3
- package/dist/layouts/AuthLayout.js +1 -1
- package/dist/layouts/PublicLayout.js +1 -1
- package/dist/layouts/RootLayout.d.ts.map +1 -1
- package/dist/scripts/init-app.d.ts.map +1 -1
- package/dist/scripts/init-app.js +301 -138
- package/dist/scripts/module-build.d.ts.map +1 -1
- package/dist/scripts/module-build.js +402 -67
- package/dist/scripts/module-create.d.ts.map +1 -1
- package/dist/scripts/module-create.js +227 -10
- package/dist/scripts/sitemap-flat-generator.d.ts +39 -0
- package/dist/scripts/sitemap-flat-generator.d.ts.map +1 -0
- package/dist/scripts/sitemap-flat-generator.js +231 -0
- package/dist/scripts/sitemap-manifest-generator.d.ts +59 -0
- package/dist/scripts/sitemap-manifest-generator.d.ts.map +1 -0
- package/dist/scripts/sitemap-manifest-generator.js +290 -0
- package/dist/sitemap/manifest.d.ts +8 -0
- package/dist/sitemap/manifest.d.ts.map +1 -0
- package/dist/sitemap/manifest.js +6 -0
- package/dist/styles.css +2 -2
- package/dist/templates/AuthGuidePage.js +2 -0
- package/dist/templates/DefaultDoc.d.ts.map +1 -1
- package/dist/templates/DefaultDoc.js +9 -5
- package/dist/templates/DocPage.d.ts.map +1 -1
- package/dist/templates/DocPage.js +40 -0
- package/dist/templates/MigrationsGuidePage.js +2 -0
- package/dist/templates/ModuleGuidePage.d.ts.map +1 -1
- package/dist/templates/ModuleGuidePage.js +4 -1
- package/dist/templates/SimpleHomePage.js +2 -0
- package/package.json +11 -4
- package/src/analytics/registry.ts +14 -0
- package/src/auth/useAuthSession.ts +91 -1
- package/src/cli.ts +19 -3
- package/src/components/LanguageSwitcher.tsx +113 -23
- package/src/config/version.ts +30 -19
- package/src/i18n/useLink.ts +15 -0
- package/src/index.ts +17 -0
- package/src/layouts/AdminLayoutWithSidebar.tsx +4 -0
- package/src/layouts/AppProviders.tsx +66 -8
- package/src/layouts/AuthLayout.tsx +1 -1
- package/src/layouts/PublicLayout.tsx +1 -1
- package/src/layouts/RootLayout.tsx +0 -1
- package/src/scripts/init-app.ts +360 -149
- package/src/scripts/module-build.ts +458 -72
- package/src/scripts/module-create.ts +260 -10
- package/src/scripts/sitemap-flat-generator.ts +313 -0
- package/src/scripts/sitemap-manifest-generator.ts +476 -0
- package/src/sitemap/manifest.ts +17 -0
- package/src/templates/AuthGuidePage.tsx +1 -1
- package/src/templates/DefaultDoc.tsx +397 -6
- package/src/templates/DocPage.tsx +40 -0
- package/src/templates/MigrationsGuidePage.tsx +1 -1
- package/src/templates/ModuleGuidePage.tsx +3 -2
- package/src/templates/SimpleHomePage.tsx +1 -1
package/dist/scripts/init-app.js
CHANGED
|
@@ -83,11 +83,10 @@ export async function initApp(options) {
|
|
|
83
83
|
await createConfigFiles(targetDir, force, useHeroUI, projectName);
|
|
84
84
|
// 5. Créer le système de proxy storage
|
|
85
85
|
await createStorageProxy(targetDir, force);
|
|
86
|
-
// 6. Créer .gitignore et .env.
|
|
86
|
+
// 6. Créer .gitignore, vercel.json et .env.example
|
|
87
87
|
await createGitIgnore(targetDir, force);
|
|
88
|
+
await createVercelJson(targetDir, projectName, force);
|
|
88
89
|
await createEnvExample(targetDir, force);
|
|
89
|
-
await createEnvLocal(targetDir, force, isMonorepoProject);
|
|
90
|
-
await createEnvProd(targetDir, force);
|
|
91
90
|
// 6b. Créer les fichiers i18n/default pour les traductions personnalisées
|
|
92
91
|
await createI18nDefaults(targetDir, force, projectName);
|
|
93
92
|
// 7. Créer la structure Supabase avec migrations (seulement pour projets indépendants)
|
|
@@ -194,7 +193,7 @@ export async function initApp(options) {
|
|
|
194
193
|
if (!isMonorepoProject) {
|
|
195
194
|
console.log(chalk.white(" pnpm db:init"));
|
|
196
195
|
}
|
|
197
|
-
console.log(chalk.white(" pnpm dev:local (ou pnpm dev:prod)\n"));
|
|
196
|
+
console.log(chalk.white(" pnpm dev:local (ou pnpm dev:dev / dev:prod)\n"));
|
|
198
197
|
}
|
|
199
198
|
}
|
|
200
199
|
else {
|
|
@@ -204,11 +203,13 @@ export async function initApp(options) {
|
|
|
204
203
|
console.log(chalk.white(" 3. pnpm build:modules (générer les routes des modules)"));
|
|
205
204
|
console.log(chalk.white(" 4. pnpm db:migrations:sync (synchroniser les migrations)"));
|
|
206
205
|
console.log(chalk.white(" 5. pnpm db:init (initialiser la base de données)"));
|
|
207
|
-
console.log(chalk.white(" 6.
|
|
206
|
+
console.log(chalk.white(" 6. Copier .env.example vers .env.local/.env.development/.env.production"));
|
|
207
|
+
console.log(chalk.white(" 7. pnpm dev:local (ou pnpm dev:dev / dev:prod)\n"));
|
|
208
208
|
console.log(chalk.cyan("\n💡 Scripts disponibles:"));
|
|
209
|
-
console.log(chalk.white(" • pnpm dev:local - Lance avec .env.local"));
|
|
210
|
-
console.log(chalk.white(" • pnpm dev:
|
|
211
|
-
console.log(chalk.white(" • pnpm dev
|
|
209
|
+
console.log(chalk.white(" • pnpm dev:local - Lance avec NODE_ENV=local (utilise .env.local)"));
|
|
210
|
+
console.log(chalk.white(" • pnpm dev:dev - Lance avec NODE_ENV=development (utilise .env.development)"));
|
|
211
|
+
console.log(chalk.white(" • pnpm dev:prod - Lance avec NODE_ENV=production (utilise .env.production)"));
|
|
212
|
+
console.log(chalk.white(" • pnpm dev - Lance avec Next.js (utilise .env par défaut)\n"));
|
|
212
213
|
console.log(chalk.gray("Prérequis pour Supabase :"));
|
|
213
214
|
console.log(chalk.white(" - Docker Desktop installé et lancé"));
|
|
214
215
|
console.log(chalk.white(" - Supabase CLI : brew install supabase/tap/supabase\n"));
|
|
@@ -287,13 +288,20 @@ async function addDependencies(targetDir, useHeroUI, withAuth, selectedModules =
|
|
|
287
288
|
for (const moduleName of selectedModules) {
|
|
288
289
|
const moduleInfo = AVAILABLE_MODULES.find((m) => m.name === moduleName);
|
|
289
290
|
if (moduleInfo && moduleInfo.package !== "@lastbrain/module-auth") {
|
|
290
|
-
//
|
|
291
|
-
|
|
292
|
-
|
|
291
|
+
// Dans un monorepo, utiliser workspace:*
|
|
292
|
+
const targetIsInMonorepo = fs.existsSync(path.join(targetDir, "../../../packages/core/package.json")) ||
|
|
293
|
+
fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
|
|
294
|
+
if (targetIsInMonorepo) {
|
|
295
|
+
requiredDeps[moduleInfo.package] = "workspace:*";
|
|
293
296
|
}
|
|
294
297
|
else {
|
|
295
|
-
//
|
|
296
|
-
|
|
298
|
+
// Hors monorepo, utiliser les versions publiées
|
|
299
|
+
if (moduleInfo.package === "@lastbrain/module-ai") {
|
|
300
|
+
requiredDeps[moduleInfo.package] = versions.moduleAi;
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
requiredDeps[moduleInfo.package] = "latest";
|
|
304
|
+
}
|
|
297
305
|
}
|
|
298
306
|
}
|
|
299
307
|
}
|
|
@@ -423,26 +431,30 @@ export default function RootLayout({ children }: PropsWithChildren<{}>) {
|
|
|
423
431
|
await fs.writeFile(globalsPath, globalsContent);
|
|
424
432
|
console.log(chalk.green("✓ styles/globals.css créé"));
|
|
425
433
|
}
|
|
426
|
-
// Créer la page d'accueil publique (
|
|
427
|
-
const
|
|
434
|
+
// Créer la page d'accueil publique dans (public)
|
|
435
|
+
const langDir = path.join(appDir, "[lang]");
|
|
436
|
+
await fs.ensureDir(langDir);
|
|
437
|
+
const publicDir = path.join(langDir, "(public)");
|
|
438
|
+
await fs.ensureDir(publicDir);
|
|
439
|
+
const homePagePath = path.join(publicDir, "page.tsx");
|
|
428
440
|
if (!fs.existsSync(homePagePath) || force) {
|
|
429
441
|
const homePageContent = `// GENERATED BY LASTBRAIN APP-SHELL
|
|
442
|
+
"use client";
|
|
430
443
|
|
|
431
444
|
import { SimpleHomePage } from "@lastbrain/app";
|
|
432
|
-
|
|
433
|
-
import { footerConfig } from "../config/footer";
|
|
445
|
+
|
|
434
446
|
|
|
435
447
|
export default function RootPage() {
|
|
436
448
|
return (
|
|
437
449
|
<>
|
|
438
450
|
<SimpleHomePage showAuth={${withAuth}} />
|
|
439
|
-
|
|
451
|
+
|
|
440
452
|
</>
|
|
441
453
|
);
|
|
442
454
|
}
|
|
443
455
|
`;
|
|
444
456
|
await fs.writeFile(homePagePath, homePageContent);
|
|
445
|
-
console.log(chalk.green("✓ app/page.tsx créé"));
|
|
457
|
+
console.log(chalk.green("✓ app/[lang]/(public)/page.tsx créé"));
|
|
446
458
|
}
|
|
447
459
|
// Créer la page not-found.tsx
|
|
448
460
|
const notFoundPath = path.join(appDir, "not-found.tsx");
|
|
@@ -836,74 +848,47 @@ async function createConfigFiles(targetDir, force, useHeroUI, projectName) {
|
|
|
836
848
|
const middlewarePath = path.join(targetDir, "middleware.ts");
|
|
837
849
|
if (!fs.existsSync(middlewarePath) || force) {
|
|
838
850
|
const middleware = `import { type NextRequest, NextResponse } from "next/server";
|
|
839
|
-
import {
|
|
840
|
-
|
|
841
|
-
/**
|
|
842
|
-
* Crée un client Supabase pour le middleware
|
|
843
|
-
*/
|
|
844
|
-
function createMiddlewareClient(request: NextRequest) {
|
|
845
|
-
let response = NextResponse.next({
|
|
846
|
-
request: {
|
|
847
|
-
headers: request.headers,
|
|
848
|
-
},
|
|
849
|
-
});
|
|
850
|
-
|
|
851
|
-
const supabase = createServerClient(
|
|
852
|
-
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
853
|
-
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
|
854
|
-
{
|
|
855
|
-
cookies: {
|
|
856
|
-
get(name: string) {
|
|
857
|
-
return request.cookies.get(name)?.value;
|
|
858
|
-
},
|
|
859
|
-
set(name: string, value: string, options: CookieOptions) {
|
|
860
|
-
request.cookies.set({
|
|
861
|
-
name,
|
|
862
|
-
value,
|
|
863
|
-
...options,
|
|
864
|
-
});
|
|
865
|
-
response = NextResponse.next({
|
|
866
|
-
request: {
|
|
867
|
-
headers: request.headers,
|
|
868
|
-
},
|
|
869
|
-
});
|
|
870
|
-
response.cookies.set({
|
|
871
|
-
name,
|
|
872
|
-
value,
|
|
873
|
-
...options,
|
|
874
|
-
});
|
|
875
|
-
},
|
|
876
|
-
remove(name: string, options: CookieOptions) {
|
|
877
|
-
request.cookies.delete(name);
|
|
878
|
-
response = NextResponse.next({
|
|
879
|
-
request: {
|
|
880
|
-
headers: request.headers,
|
|
881
|
-
},
|
|
882
|
-
});
|
|
883
|
-
response.cookies.delete(name);
|
|
884
|
-
},
|
|
885
|
-
},
|
|
886
|
-
}
|
|
887
|
-
);
|
|
888
|
-
|
|
889
|
-
return { supabase, response };
|
|
890
|
-
}
|
|
851
|
+
import { createMiddlewareClient } from "@lastbrain/core/server";
|
|
852
|
+
import { logger } from "@lastbrain/core";
|
|
891
853
|
|
|
892
854
|
export async function middleware(request: NextRequest) {
|
|
893
855
|
const { pathname } = request.nextUrl;
|
|
894
856
|
const isApi = pathname.startsWith("/api/");
|
|
895
857
|
|
|
858
|
+
// Liste des locales supportées
|
|
859
|
+
const supportedLocales = ["fr", "en", "es"];
|
|
860
|
+
const defaultLocale = "fr";
|
|
861
|
+
|
|
862
|
+
// Special case: root path — redirect to default locale for better SEO
|
|
863
|
+
if (pathname === "/") {
|
|
864
|
+
const redirectUrl = new URL(\`/\${defaultLocale}\`, request.url);
|
|
865
|
+
// preserve search params
|
|
866
|
+
redirectUrl.search = request.nextUrl.search;
|
|
867
|
+
return NextResponse.redirect(redirectUrl);
|
|
868
|
+
}
|
|
869
|
+
|
|
896
870
|
// Détecter la langue depuis l'URL (ex: /fr/... ou /es/...)
|
|
897
871
|
const langMatch = pathname.match(/^\\/([a-z]{2})(\\/|$)/);
|
|
898
|
-
const detectedLang = langMatch ? langMatch[1] :
|
|
872
|
+
const detectedLang = langMatch ? langMatch[1] : null;
|
|
873
|
+
|
|
874
|
+
// Utiliser la langue détectée ou la langue par défaut
|
|
875
|
+
const currentLang =
|
|
876
|
+
detectedLang && supportedLocales.includes(detectedLang)
|
|
877
|
+
? detectedLang
|
|
878
|
+
: defaultLocale;
|
|
899
879
|
|
|
900
880
|
// Créer la réponse de base avec les headers de langue
|
|
901
881
|
const createResponseWithLang = (response: NextResponse) => {
|
|
902
|
-
response.headers.set("x-locale",
|
|
882
|
+
response.headers.set("x-locale", currentLang);
|
|
903
883
|
response.headers.set("x-pathname", pathname);
|
|
904
884
|
return response;
|
|
905
885
|
};
|
|
906
886
|
|
|
887
|
+
// Extraire le chemin sans le préfixe de langue pour les vérifications
|
|
888
|
+
const pathnameWithoutLang = detectedLang
|
|
889
|
+
? pathname.replace(\`/\${detectedLang}\`, "") || "/"
|
|
890
|
+
: pathname;
|
|
891
|
+
|
|
907
892
|
// Pages publiques d'authentification (ne pas protéger)
|
|
908
893
|
const publicAuthPages = [
|
|
909
894
|
"/signin",
|
|
@@ -911,6 +896,8 @@ export async function middleware(request: NextRequest) {
|
|
|
911
896
|
"/reset-password",
|
|
912
897
|
"/forgot-password",
|
|
913
898
|
"/callback",
|
|
899
|
+
"/confirm",
|
|
900
|
+
"/auth-code-error",
|
|
914
901
|
];
|
|
915
902
|
|
|
916
903
|
if(process.env.MAINTENANCE_MODE === "true" && !pathname.startsWith("/maintenance")) {
|
|
@@ -1387,6 +1374,21 @@ export default config;
|
|
|
1387
1374
|
await fs.writeJson(tsconfigPath, tsconfig, { spaces: 2 });
|
|
1388
1375
|
console.log(chalk.green("✓ tsconfig.json créé"));
|
|
1389
1376
|
}
|
|
1377
|
+
// locale-helpers.ts - Re-export locale helpers from config
|
|
1378
|
+
const localeHelpersPath = path.join(targetDir, "locale-helpers.ts");
|
|
1379
|
+
if (!fs.existsSync(localeHelpersPath) || force) {
|
|
1380
|
+
const localeHelpers = `// Re-export locale helpers from config for easy import in packages
|
|
1381
|
+
export {
|
|
1382
|
+
langToLocale,
|
|
1383
|
+
getAlternateLocales,
|
|
1384
|
+
getLocaleMap,
|
|
1385
|
+
LOCALE_CONFIG,
|
|
1386
|
+
} from "./config/locales.generated";
|
|
1387
|
+
export type { LocaleConfig } from "./config/locales.generated";
|
|
1388
|
+
`;
|
|
1389
|
+
await fs.writeFile(localeHelpersPath, localeHelpers);
|
|
1390
|
+
console.log(chalk.green("✓ locale-helpers.ts créé"));
|
|
1391
|
+
}
|
|
1390
1392
|
// config/menu.ts
|
|
1391
1393
|
const configDir = path.join(targetDir, "config");
|
|
1392
1394
|
await fs.ensureDir(configDir);
|
|
@@ -1609,6 +1611,83 @@ export default realtimeConfig;
|
|
|
1609
1611
|
await fs.writeFile(realtimePath, realtimeContent);
|
|
1610
1612
|
console.log(chalk.green("✓ config/realtime.ts placeholder créé"));
|
|
1611
1613
|
}
|
|
1614
|
+
// Créer un placeholder pour locales.generated.ts qui sera généré par build:modules
|
|
1615
|
+
const localesGeneratedPath = path.join(targetDir, "config", "locales.generated.ts");
|
|
1616
|
+
if (!fs.existsSync(localesGeneratedPath) || force) {
|
|
1617
|
+
const localesContent = `// GENERATED FILE - DO NOT EDIT MANUALLY
|
|
1618
|
+
// Ce fichier sera automatiquement généré lors du build:modules
|
|
1619
|
+
// Exécutez "pnpm build:modules" pour créer la configuration des locales
|
|
1620
|
+
|
|
1621
|
+
export const LOCALE_MAP: Record<string, string> = {
|
|
1622
|
+
fr: "Français",
|
|
1623
|
+
en: "English",
|
|
1624
|
+
es: "Español",
|
|
1625
|
+
de: "Deutsch",
|
|
1626
|
+
it: "Italiano",
|
|
1627
|
+
pt: "Português",
|
|
1628
|
+
nl: "Nederlands",
|
|
1629
|
+
ru: "Русский",
|
|
1630
|
+
ja: "日本語",
|
|
1631
|
+
zh: "中文",
|
|
1632
|
+
ar: "العربية",
|
|
1633
|
+
hi: "हिन्दी",
|
|
1634
|
+
};
|
|
1635
|
+
|
|
1636
|
+
export interface LocaleConfig {
|
|
1637
|
+
code: string;
|
|
1638
|
+
name: string;
|
|
1639
|
+
flag: string;
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
export const LOCALE_CONFIG: LocaleConfig[] = Object.entries(LOCALE_MAP).map(
|
|
1643
|
+
([code, name]) => ({
|
|
1644
|
+
code,
|
|
1645
|
+
name,
|
|
1646
|
+
flag: code.toUpperCase(),
|
|
1647
|
+
})
|
|
1648
|
+
);
|
|
1649
|
+
|
|
1650
|
+
export function langToLocale(lang: string): string {
|
|
1651
|
+
return lang;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
export function getAlternateLocales(currentLang: string): string[] {
|
|
1655
|
+
return Object.keys(LOCALE_MAP).filter((lang) => lang !== currentLang);
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
export function getLocaleMap(): Record<string, string> {
|
|
1659
|
+
return LOCALE_MAP;
|
|
1660
|
+
}
|
|
1661
|
+
`;
|
|
1662
|
+
await fs.writeFile(localesGeneratedPath, localesContent);
|
|
1663
|
+
console.log(chalk.green("✓ config/locales.generated.ts placeholder créé"));
|
|
1664
|
+
}
|
|
1665
|
+
// Créer un placeholder pour auth-dashboard.ts qui sera généré par build:modules
|
|
1666
|
+
const authDashboardPath = path.join(targetDir, "config", "auth-dashboard.ts");
|
|
1667
|
+
if (!fs.existsSync(authDashboardPath) || force) {
|
|
1668
|
+
const authDashboardContent = `// GENERATED FILE - DO NOT EDIT MANUALLY
|
|
1669
|
+
// Ce fichier sera automatiquement généré lors du build:modules
|
|
1670
|
+
// Exécutez "pnpm build:modules" pour créer la configuration auth dashboard
|
|
1671
|
+
|
|
1672
|
+
"use client";
|
|
1673
|
+
|
|
1674
|
+
import type React from "react";
|
|
1675
|
+
|
|
1676
|
+
export interface ModuleAuthDashboard {
|
|
1677
|
+
key: string;
|
|
1678
|
+
title: string;
|
|
1679
|
+
icon?: string;
|
|
1680
|
+
order?: number;
|
|
1681
|
+
component: React.ComponentType<Record<string, never>>;
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
export const moduleAuthDashboards: ModuleAuthDashboard[] = [];
|
|
1685
|
+
|
|
1686
|
+
export default moduleAuthDashboards;
|
|
1687
|
+
`;
|
|
1688
|
+
await fs.writeFile(authDashboardPath, authDashboardContent);
|
|
1689
|
+
console.log(chalk.green("✓ config/auth-dashboard.ts placeholder créé"));
|
|
1690
|
+
}
|
|
1612
1691
|
}
|
|
1613
1692
|
async function createGitIgnore(targetDir, force) {
|
|
1614
1693
|
const gitignorePath = path.join(targetDir, ".gitignore");
|
|
@@ -1678,14 +1757,34 @@ coverage/
|
|
|
1678
1757
|
console.log(chalk.green("✓ .gitignore créé"));
|
|
1679
1758
|
}
|
|
1680
1759
|
}
|
|
1760
|
+
async function createVercelJson(targetDir, projectName, force) {
|
|
1761
|
+
const vercelJsonPath = path.join(targetDir, "vercel.json");
|
|
1762
|
+
if (!fs.existsSync(vercelJsonPath) || force) {
|
|
1763
|
+
console.log(chalk.yellow("\n📝 Création de vercel.json..."));
|
|
1764
|
+
const vercelConfig = {
|
|
1765
|
+
buildCommand: `cd ../.. && pnpm install && turbo run build --filter=${projectName}`,
|
|
1766
|
+
framework: "nextjs",
|
|
1767
|
+
functions: {
|
|
1768
|
+
"app/api/public/convert-pdf/route.ts": {
|
|
1769
|
+
maxDuration: 60,
|
|
1770
|
+
},
|
|
1771
|
+
"app/api/audits/convert-pdf/route.ts": {
|
|
1772
|
+
maxDuration: 60,
|
|
1773
|
+
},
|
|
1774
|
+
},
|
|
1775
|
+
};
|
|
1776
|
+
await fs.writeFile(vercelJsonPath, JSON.stringify(vercelConfig, null, 2), "utf-8");
|
|
1777
|
+
console.log(chalk.green("✓ vercel.json créé"));
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1681
1780
|
async function createEnvExample(targetDir, force) {
|
|
1682
|
-
const envExamplePath = path.join(targetDir, ".env.
|
|
1781
|
+
const envExamplePath = path.join(targetDir, ".env.example");
|
|
1683
1782
|
if (!fs.existsSync(envExamplePath) || force) {
|
|
1684
|
-
console.log(chalk.yellow("\n🔐 Création de .env.
|
|
1783
|
+
console.log(chalk.yellow("\n🔐 Création de .env.example..."));
|
|
1685
1784
|
const envContent = `# Supabase Configuration
|
|
1686
|
-
#
|
|
1785
|
+
# Copiez ce fichier vers .env.local, .env.development ou .env.production selon vos besoins
|
|
1687
1786
|
|
|
1688
|
-
# Supabase Local (
|
|
1787
|
+
# Supabase Local (pour développement)
|
|
1689
1788
|
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
|
|
1690
1789
|
NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_LOCAL_ANON_KEY
|
|
1691
1790
|
SUPABASE_SERVICE_ROLE_KEY=YOUR_LOCAL_SERVICE_ROLE_KEY
|
|
@@ -1694,64 +1793,13 @@ SUPABASE_SERVICE_ROLE_KEY=YOUR_LOCAL_SERVICE_ROLE_KEY
|
|
|
1694
1793
|
# NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
|
|
1695
1794
|
# NEXT_PUBLIC_SUPABASE_ANON_KEY=your_production_anon_key
|
|
1696
1795
|
# SUPABASE_SERVICE_ROLE_KEY=your_production_service_role_key
|
|
1697
|
-
`;
|
|
1698
|
-
await fs.writeFile(envExamplePath, envContent);
|
|
1699
|
-
console.log(chalk.green("✓ .env.local.example créé"));
|
|
1700
|
-
}
|
|
1701
|
-
}
|
|
1702
|
-
async function createEnvLocal(targetDir, force, isMonorepoProject = false) {
|
|
1703
|
-
const envLocalPath = path.join(targetDir, ".env.local");
|
|
1704
|
-
if (!fs.existsSync(envLocalPath) || force) {
|
|
1705
|
-
console.log(chalk.yellow("\n🔐 Création de .env.local..."));
|
|
1706
|
-
let envContent;
|
|
1707
|
-
if (isMonorepoProject) {
|
|
1708
|
-
// Pour les projets monorepo, utiliser les variables du monorepo
|
|
1709
|
-
envContent = `# Supabase Configuration (Monorepo - Centralisé)
|
|
1710
|
-
# Les variables Supabase sont gérées au niveau du monorepo
|
|
1711
|
-
|
|
1712
|
-
# OpenAI Configuration (clé factice pour éviter les erreurs de build)
|
|
1713
|
-
OPENAI_API_KEY=sk-fake-openai-key-for-development-replace-with-real-key
|
|
1714
|
-
|
|
1715
|
-
# Note: Les variables Supabase sont fournies par le monorepo parent
|
|
1716
|
-
`;
|
|
1717
|
-
}
|
|
1718
|
-
else {
|
|
1719
|
-
// Pour les projets indépendants
|
|
1720
|
-
envContent = `# Supabase Configuration
|
|
1721
|
-
# Valeurs par défaut pour le développement local
|
|
1722
|
-
|
|
1723
|
-
# Supabase Local (par défaut)
|
|
1724
|
-
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
|
|
1725
|
-
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGc...
|
|
1726
|
-
SUPABASE_SERVICE_ROLE_KEY=eyJhbGc...
|
|
1727
1796
|
|
|
1728
|
-
#
|
|
1729
|
-
|
|
1797
|
+
# AI Gateway API Key (recommandé) ou OpenAI direct
|
|
1798
|
+
AI_GATEWAY_API_KEY=your-ai-gateway-key
|
|
1799
|
+
# OPENAI_API_KEY=sk-proj-your-openai-key
|
|
1730
1800
|
`;
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
console.log(chalk.green("✓ .env.local créé"));
|
|
1734
|
-
}
|
|
1735
|
-
}
|
|
1736
|
-
async function createEnvProd(targetDir, force) {
|
|
1737
|
-
const envProdPath = path.join(targetDir, ".env.prod");
|
|
1738
|
-
if (!fs.existsSync(envProdPath) || force) {
|
|
1739
|
-
console.log(chalk.yellow("\n🔐 Création de .env.prod..."));
|
|
1740
|
-
const envContent = `# Production Environment Configuration
|
|
1741
|
-
# Copy your production values here
|
|
1742
|
-
|
|
1743
|
-
# Supabase Production
|
|
1744
|
-
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
|
|
1745
|
-
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-prod-anon-key
|
|
1746
|
-
SUPABASE_SERVICE_ROLE_KEY=your-prod-service-role-key
|
|
1747
|
-
|
|
1748
|
-
# OpenAI Production
|
|
1749
|
-
OPENAI_API_KEY=sk-proj-your-prod-api-key
|
|
1750
|
-
|
|
1751
|
-
# Note: Update these values with your actual production credentials
|
|
1752
|
-
`;
|
|
1753
|
-
await fs.writeFile(envProdPath, envContent);
|
|
1754
|
-
console.log(chalk.green("✓ .env.prod créé"));
|
|
1801
|
+
await fs.writeFile(envExamplePath, envContent);
|
|
1802
|
+
console.log(chalk.green("✓ .env.example créé"));
|
|
1755
1803
|
}
|
|
1756
1804
|
}
|
|
1757
1805
|
async function createSupabaseStructure(targetDir, force) {
|
|
@@ -1798,13 +1846,14 @@ async function addScriptsToPackageJson(targetDir) {
|
|
|
1798
1846
|
? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/app build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
|
|
1799
1847
|
: "echo 'No prebuild needed'",
|
|
1800
1848
|
dev: "next dev",
|
|
1801
|
-
"dev:
|
|
1802
|
-
"dev:
|
|
1849
|
+
"dev:dev": "NODE_ENV=development next dev --turbopack",
|
|
1850
|
+
"dev:local": "NODE_ENV=local next dev --turbopack",
|
|
1851
|
+
"dev:prod": "NODE_ENV=production next dev --turbopack",
|
|
1803
1852
|
build: "next build",
|
|
1804
1853
|
start: "next start",
|
|
1805
1854
|
lint: "next lint",
|
|
1806
1855
|
lastbrain: scriptsPrefix,
|
|
1807
|
-
"build:modules": `${scriptsPrefix} module:build && prettier --write
|
|
1856
|
+
"build:modules": `${scriptsPrefix} module:build && prettier --write "**/*.{js,jsx,ts,tsx,json,md}"`,
|
|
1808
1857
|
"db:migrations:sync": `${scriptsPrefix} db:migrations:sync`,
|
|
1809
1858
|
"db:init": `${scriptsPrefix} db:init`,
|
|
1810
1859
|
"readme:create": `${scriptsPrefix} readme:create`,
|
|
@@ -2194,7 +2243,64 @@ async function createI18nDefaults(targetDir, force, projectName) {
|
|
|
2194
2243
|
"app.name": projectName,
|
|
2195
2244
|
"app.description": `Bienvenue dans ${projectName}`,
|
|
2196
2245
|
"app.tagline": "Votre plateforme de gestion",
|
|
2197
|
-
"app.icon": "
|
|
2246
|
+
"app.icon": "Sparkles",
|
|
2247
|
+
"app.twitter_creator": "@YourTwitter",
|
|
2248
|
+
"app.twitter_site": "@YourTwitter",
|
|
2249
|
+
"app.email.contact": "contact@example.com",
|
|
2250
|
+
"app.email.color.primary": "#3b82f6",
|
|
2251
|
+
"app.email.color.secondary": "#8b5cf6",
|
|
2252
|
+
// Navigation
|
|
2253
|
+
"nav.home": "Accueil",
|
|
2254
|
+
"nav.dashboard": "Tableau de bord",
|
|
2255
|
+
"nav.profile": "Profil",
|
|
2256
|
+
"nav.settings": "Paramètres",
|
|
2257
|
+
"nav.admin": "Administration",
|
|
2258
|
+
"nav.logout": "Déconnexion",
|
|
2259
|
+
"nav.login": "Connexion",
|
|
2260
|
+
"nav.signup": "S'inscrire",
|
|
2261
|
+
// Actions communes
|
|
2262
|
+
"action.save": "Enregistrer",
|
|
2263
|
+
"action.cancel": "Annuler",
|
|
2264
|
+
"action.delete": "Supprimer",
|
|
2265
|
+
"action.edit": "Modifier",
|
|
2266
|
+
"action.create": "Créer",
|
|
2267
|
+
"action.search": "Rechercher",
|
|
2268
|
+
"action.filter": "Filtrer",
|
|
2269
|
+
"action.export": "Exporter",
|
|
2270
|
+
"action.import": "Importer",
|
|
2271
|
+
"action.close": "Fermer",
|
|
2272
|
+
"action.confirm": "Confirmer",
|
|
2273
|
+
"action.back": "Retour",
|
|
2274
|
+
"action.next": "Suivant",
|
|
2275
|
+
"action.previous": "Précédent",
|
|
2276
|
+
"action.submit": "Soumettre",
|
|
2277
|
+
"action.reset": "Réinitialiser",
|
|
2278
|
+
// Messages communs
|
|
2279
|
+
"message.loading": "Chargement...",
|
|
2280
|
+
"message.saving": "Enregistrement...",
|
|
2281
|
+
"message.success": "Opération réussie",
|
|
2282
|
+
"message.error": "Une erreur est survenue",
|
|
2283
|
+
"message.no_data": "Aucune donnée disponible",
|
|
2284
|
+
"message.confirm_delete": "Êtes-vous sûr de vouloir supprimer cet élément ?",
|
|
2285
|
+
"message.unsaved_changes": "Vous avez des modifications non enregistrées",
|
|
2286
|
+
// Formulaires
|
|
2287
|
+
"form.required": "Ce champ est requis",
|
|
2288
|
+
"form.invalid_email": "Email invalide",
|
|
2289
|
+
"form.password_too_short": "Le mot de passe est trop court",
|
|
2290
|
+
"form.passwords_no_match": "Les mots de passe ne correspondent pas",
|
|
2291
|
+
// Contact
|
|
2292
|
+
"contact.page.title": "Contactez-nous",
|
|
2293
|
+
"contact.page.subtitle": "Nous sommes à votre écoute",
|
|
2294
|
+
"contact.form.name": "Nom",
|
|
2295
|
+
"contact.form.name_placeholder": "Votre nom",
|
|
2296
|
+
"contact.form.email": "Email",
|
|
2297
|
+
"contact.form.email_placeholder": "votre@email.fr",
|
|
2298
|
+
"contact.form.subject": "Sujet",
|
|
2299
|
+
"contact.form.message": "Message",
|
|
2300
|
+
"contact.form.message_placeholder": "Votre message...",
|
|
2301
|
+
"contact.form.submit": "Envoyer",
|
|
2302
|
+
"contact.success.title": "Message envoyé !",
|
|
2303
|
+
"contact.success.description": "Nous vous répondrons dans les plus brefs délais",
|
|
2198
2304
|
};
|
|
2199
2305
|
if (!fs.existsSync(frPath) || force) {
|
|
2200
2306
|
await fs.writeJson(frPath, frContent, { spaces: 2 });
|
|
@@ -2206,7 +2312,64 @@ async function createI18nDefaults(targetDir, force, projectName) {
|
|
|
2206
2312
|
"app.name": projectName,
|
|
2207
2313
|
"app.description": `Welcome to ${projectName}`,
|
|
2208
2314
|
"app.tagline": "Your management platform",
|
|
2209
|
-
"app.icon": "
|
|
2315
|
+
"app.icon": "Sparkles",
|
|
2316
|
+
"app.twitter_creator": "@YourTwitter",
|
|
2317
|
+
"app.twitter_site": "@YourTwitter",
|
|
2318
|
+
"app.email.contact": "contact@example.com",
|
|
2319
|
+
"app.email.color.primary": "#3b82f6",
|
|
2320
|
+
"app.email.color.secondary": "#8b5cf6",
|
|
2321
|
+
// Navigation
|
|
2322
|
+
"nav.home": "Home",
|
|
2323
|
+
"nav.dashboard": "Dashboard",
|
|
2324
|
+
"nav.profile": "Profile",
|
|
2325
|
+
"nav.settings": "Settings",
|
|
2326
|
+
"nav.admin": "Administration",
|
|
2327
|
+
"nav.logout": "Logout",
|
|
2328
|
+
"nav.login": "Login",
|
|
2329
|
+
"nav.signup": "Sign up",
|
|
2330
|
+
// Common actions
|
|
2331
|
+
"action.save": "Save",
|
|
2332
|
+
"action.cancel": "Cancel",
|
|
2333
|
+
"action.delete": "Delete",
|
|
2334
|
+
"action.edit": "Edit",
|
|
2335
|
+
"action.create": "Create",
|
|
2336
|
+
"action.search": "Search",
|
|
2337
|
+
"action.filter": "Filter",
|
|
2338
|
+
"action.export": "Export",
|
|
2339
|
+
"action.import": "Import",
|
|
2340
|
+
"action.close": "Close",
|
|
2341
|
+
"action.confirm": "Confirm",
|
|
2342
|
+
"action.back": "Back",
|
|
2343
|
+
"action.next": "Next",
|
|
2344
|
+
"action.previous": "Previous",
|
|
2345
|
+
"action.submit": "Submit",
|
|
2346
|
+
"action.reset": "Reset",
|
|
2347
|
+
// Common messages
|
|
2348
|
+
"message.loading": "Loading...",
|
|
2349
|
+
"message.saving": "Saving...",
|
|
2350
|
+
"message.success": "Operation successful",
|
|
2351
|
+
"message.error": "An error occurred",
|
|
2352
|
+
"message.no_data": "No data available",
|
|
2353
|
+
"message.confirm_delete": "Are you sure you want to delete this item?",
|
|
2354
|
+
"message.unsaved_changes": "You have unsaved changes",
|
|
2355
|
+
// Forms
|
|
2356
|
+
"form.required": "This field is required",
|
|
2357
|
+
"form.invalid_email": "Invalid email",
|
|
2358
|
+
"form.password_too_short": "Password is too short",
|
|
2359
|
+
"form.passwords_no_match": "Passwords do not match",
|
|
2360
|
+
// Contact
|
|
2361
|
+
"contact.page.title": "Contact Us",
|
|
2362
|
+
"contact.page.subtitle": "We're here to help",
|
|
2363
|
+
"contact.form.name": "Name",
|
|
2364
|
+
"contact.form.name_placeholder": "Your name",
|
|
2365
|
+
"contact.form.email": "Email",
|
|
2366
|
+
"contact.form.email_placeholder": "your@email.com",
|
|
2367
|
+
"contact.form.subject": "Subject",
|
|
2368
|
+
"contact.form.message": "Message",
|
|
2369
|
+
"contact.form.message_placeholder": "Your message...",
|
|
2370
|
+
"contact.form.submit": "Send",
|
|
2371
|
+
"contact.success.title": "Message sent!",
|
|
2372
|
+
"contact.success.description": "We will get back to you as soon as possible",
|
|
2210
2373
|
};
|
|
2211
2374
|
if (!fs.existsSync(enPath) || force) {
|
|
2212
2375
|
await fs.writeJson(enPath, enContent, { spaces: 2 });
|
|
@@ -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":"AAwlFA,wBAAsB,cAAc,kBAoJnC"}
|