@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.
Files changed (74) hide show
  1. package/dist/analytics/registry.d.ts +7 -0
  2. package/dist/analytics/registry.d.ts.map +1 -0
  3. package/dist/analytics/registry.js +11 -0
  4. package/dist/auth/useAuthSession.d.ts.map +1 -1
  5. package/dist/auth/useAuthSession.js +85 -1
  6. package/dist/cli.js +19 -3
  7. package/dist/components/LanguageSwitcher.d.ts.map +1 -1
  8. package/dist/components/LanguageSwitcher.js +89 -5
  9. package/dist/config/version.d.ts.map +1 -1
  10. package/dist/config/version.js +30 -19
  11. package/dist/i18n/useLink.d.ts.map +1 -1
  12. package/dist/i18n/useLink.js +15 -0
  13. package/dist/index.d.ts +3 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +4 -0
  16. package/dist/layouts/AdminLayoutWithSidebar.d.ts +3 -1
  17. package/dist/layouts/AdminLayoutWithSidebar.d.ts.map +1 -1
  18. package/dist/layouts/AdminLayoutWithSidebar.js +2 -2
  19. package/dist/layouts/AppProviders.d.ts +7 -1
  20. package/dist/layouts/AppProviders.d.ts.map +1 -1
  21. package/dist/layouts/AppProviders.js +24 -3
  22. package/dist/layouts/AuthLayout.js +1 -1
  23. package/dist/layouts/PublicLayout.js +1 -1
  24. package/dist/layouts/RootLayout.d.ts.map +1 -1
  25. package/dist/scripts/init-app.d.ts.map +1 -1
  26. package/dist/scripts/init-app.js +301 -138
  27. package/dist/scripts/module-build.d.ts.map +1 -1
  28. package/dist/scripts/module-build.js +402 -67
  29. package/dist/scripts/module-create.d.ts.map +1 -1
  30. package/dist/scripts/module-create.js +227 -10
  31. package/dist/scripts/sitemap-flat-generator.d.ts +39 -0
  32. package/dist/scripts/sitemap-flat-generator.d.ts.map +1 -0
  33. package/dist/scripts/sitemap-flat-generator.js +231 -0
  34. package/dist/scripts/sitemap-manifest-generator.d.ts +59 -0
  35. package/dist/scripts/sitemap-manifest-generator.d.ts.map +1 -0
  36. package/dist/scripts/sitemap-manifest-generator.js +290 -0
  37. package/dist/sitemap/manifest.d.ts +8 -0
  38. package/dist/sitemap/manifest.d.ts.map +1 -0
  39. package/dist/sitemap/manifest.js +6 -0
  40. package/dist/styles.css +2 -2
  41. package/dist/templates/AuthGuidePage.js +2 -0
  42. package/dist/templates/DefaultDoc.d.ts.map +1 -1
  43. package/dist/templates/DefaultDoc.js +9 -5
  44. package/dist/templates/DocPage.d.ts.map +1 -1
  45. package/dist/templates/DocPage.js +40 -0
  46. package/dist/templates/MigrationsGuidePage.js +2 -0
  47. package/dist/templates/ModuleGuidePage.d.ts.map +1 -1
  48. package/dist/templates/ModuleGuidePage.js +4 -1
  49. package/dist/templates/SimpleHomePage.js +2 -0
  50. package/package.json +11 -4
  51. package/src/analytics/registry.ts +14 -0
  52. package/src/auth/useAuthSession.ts +91 -1
  53. package/src/cli.ts +19 -3
  54. package/src/components/LanguageSwitcher.tsx +113 -23
  55. package/src/config/version.ts +30 -19
  56. package/src/i18n/useLink.ts +15 -0
  57. package/src/index.ts +17 -0
  58. package/src/layouts/AdminLayoutWithSidebar.tsx +4 -0
  59. package/src/layouts/AppProviders.tsx +66 -8
  60. package/src/layouts/AuthLayout.tsx +1 -1
  61. package/src/layouts/PublicLayout.tsx +1 -1
  62. package/src/layouts/RootLayout.tsx +0 -1
  63. package/src/scripts/init-app.ts +360 -149
  64. package/src/scripts/module-build.ts +458 -72
  65. package/src/scripts/module-create.ts +260 -10
  66. package/src/scripts/sitemap-flat-generator.ts +313 -0
  67. package/src/scripts/sitemap-manifest-generator.ts +476 -0
  68. package/src/sitemap/manifest.ts +17 -0
  69. package/src/templates/AuthGuidePage.tsx +1 -1
  70. package/src/templates/DefaultDoc.tsx +397 -6
  71. package/src/templates/DocPage.tsx +40 -0
  72. package/src/templates/MigrationsGuidePage.tsx +1 -1
  73. package/src/templates/ModuleGuidePage.tsx +3 -2
  74. package/src/templates/SimpleHomePage.tsx +1 -1
@@ -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.local.example
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. pnpm dev:local (ou pnpm dev:prod)\n"));
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:prod - Lance avec .env.prod"));
211
- console.log(chalk.white(" • pnpm dev - Lance avec .env actuel\n"));
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
- // Utiliser les vraies versions au lieu de "latest"
291
- if (moduleInfo.package === "@lastbrain/module-ai") {
292
- requiredDeps[moduleInfo.package] = versions.moduleAi;
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
- // Pour les futurs modules, utiliser "latest" en attendant
296
- requiredDeps[moduleInfo.package] = "latest";
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 (racine)
427
- const homePagePath = path.join(appDir, "[lang]", "page.tsx");
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
- import { Footer } from "@lastbrain/ui";
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
- <Footer config={footerConfig} />
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 { createServerClient, type CookieOptions } from "@supabase/ssr";
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] : "en";
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", detectedLang);
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.local.example");
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.local.example..."));
1783
+ console.log(chalk.yellow("\n🔐 Création de .env.example..."));
1685
1784
  const envContent = `# Supabase Configuration
1686
- # Exécutez 'pnpm db:init' pour initialiser Supabase local et générer le vrai .env.local
1785
+ # Copiez ce fichier vers .env.local, .env.development ou .env.production selon vos besoins
1687
1786
 
1688
- # Supabase Local (par défaut)
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
- # OpenAI Configuration (clé factice pour éviter les erreurs de build)
1729
- OPENAI_API_KEY=sk-fake-openai-key-for-development-replace-with-real-key
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
- await fs.writeFile(envLocalPath, envContent);
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:local": "env-cmd -f .env.local next dev",
1802
- "dev:prod": "env-cmd -f .env.prod next 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 \\"**/*.{js,jsx,ts,tsx,json,md}\\"`,
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": "Utensils",
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": "Utensils",
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":"AA0uEA,wBAAsB,cAAc,kBAgInC"}
1
+ {"version":3,"file":"module-build.d.ts","sourceRoot":"","sources":["../../src/scripts/module-build.ts"],"names":[],"mappings":"AAwlFA,wBAAsB,cAAc,kBAoJnC"}