@lastbrain/app 2.0.24 → 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 (81) 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 +3 -1
  8. package/dist/components/LanguageSwitcher.d.ts.map +1 -1
  9. package/dist/components/LanguageSwitcher.js +134 -21
  10. package/dist/config/version.d.ts.map +1 -1
  11. package/dist/config/version.js +30 -19
  12. package/dist/i18n/server-lang.d.ts +1 -1
  13. package/dist/i18n/server-lang.d.ts.map +1 -1
  14. package/dist/i18n/types.d.ts +1 -1
  15. package/dist/i18n/types.d.ts.map +1 -1
  16. package/dist/i18n/useLink.d.ts.map +1 -1
  17. package/dist/i18n/useLink.js +15 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +4 -0
  21. package/dist/layouts/AdminLayoutWithSidebar.d.ts +3 -1
  22. package/dist/layouts/AdminLayoutWithSidebar.d.ts.map +1 -1
  23. package/dist/layouts/AdminLayoutWithSidebar.js +2 -2
  24. package/dist/layouts/AppProviders.d.ts +9 -1
  25. package/dist/layouts/AppProviders.d.ts.map +1 -1
  26. package/dist/layouts/AppProviders.js +24 -3
  27. package/dist/layouts/AuthLayout.js +1 -1
  28. package/dist/layouts/PublicLayout.js +1 -1
  29. package/dist/layouts/RootLayout.d.ts.map +1 -1
  30. package/dist/scripts/init-app.d.ts.map +1 -1
  31. package/dist/scripts/init-app.js +343 -138
  32. package/dist/scripts/module-build.d.ts.map +1 -1
  33. package/dist/scripts/module-build.js +784 -59
  34. package/dist/scripts/module-create.d.ts.map +1 -1
  35. package/dist/scripts/module-create.js +227 -10
  36. package/dist/scripts/sitemap-flat-generator.d.ts +39 -0
  37. package/dist/scripts/sitemap-flat-generator.d.ts.map +1 -0
  38. package/dist/scripts/sitemap-flat-generator.js +231 -0
  39. package/dist/scripts/sitemap-manifest-generator.d.ts +59 -0
  40. package/dist/scripts/sitemap-manifest-generator.d.ts.map +1 -0
  41. package/dist/scripts/sitemap-manifest-generator.js +290 -0
  42. package/dist/sitemap/manifest.d.ts +8 -0
  43. package/dist/sitemap/manifest.d.ts.map +1 -0
  44. package/dist/sitemap/manifest.js +6 -0
  45. package/dist/styles.css +2 -2
  46. package/dist/templates/AuthGuidePage.js +2 -0
  47. package/dist/templates/DefaultDoc.d.ts.map +1 -1
  48. package/dist/templates/DefaultDoc.js +9 -5
  49. package/dist/templates/DocPage.d.ts.map +1 -1
  50. package/dist/templates/DocPage.js +40 -0
  51. package/dist/templates/MigrationsGuidePage.js +2 -0
  52. package/dist/templates/ModuleGuidePage.d.ts.map +1 -1
  53. package/dist/templates/ModuleGuidePage.js +4 -1
  54. package/dist/templates/SimpleHomePage.js +2 -0
  55. package/package.json +31 -26
  56. package/src/analytics/registry.ts +14 -0
  57. package/src/auth/useAuthSession.ts +91 -1
  58. package/src/cli.ts +19 -3
  59. package/src/components/LanguageSwitcher.tsx +183 -60
  60. package/src/config/version.ts +30 -19
  61. package/src/i18n/server-lang.ts +2 -1
  62. package/src/i18n/types.ts +2 -1
  63. package/src/i18n/useLink.ts +15 -0
  64. package/src/index.ts +17 -0
  65. package/src/layouts/AdminLayoutWithSidebar.tsx +4 -0
  66. package/src/layouts/AppProviders.tsx +74 -9
  67. package/src/layouts/AuthLayout.tsx +1 -1
  68. package/src/layouts/PublicLayout.tsx +1 -1
  69. package/src/layouts/RootLayout.tsx +0 -1
  70. package/src/scripts/init-app.ts +418 -149
  71. package/src/scripts/module-build.ts +923 -63
  72. package/src/scripts/module-create.ts +260 -10
  73. package/src/scripts/sitemap-flat-generator.ts +313 -0
  74. package/src/scripts/sitemap-manifest-generator.ts +476 -0
  75. package/src/sitemap/manifest.ts +17 -0
  76. package/src/templates/AuthGuidePage.tsx +1 -1
  77. package/src/templates/DefaultDoc.tsx +397 -6
  78. package/src/templates/DocPage.tsx +40 -0
  79. package/src/templates/MigrationsGuidePage.tsx +1 -1
  80. package/src/templates/ModuleGuidePage.tsx +3 -2
  81. package/src/templates/SimpleHomePage.tsx +1 -1
@@ -3,6 +3,16 @@
3
3
  import { useLanguage } from "./LanguageProvider";
4
4
  import type { Language } from "./types";
5
5
 
6
+ /**
7
+ * Détecte si un chemin commence par un code de langue ISO 639-1 (2 lettres)
8
+ * Ex: /fr/auth/billing -> true, /auth/billing -> false
9
+ */
10
+ function startsWithLocale(href: string): boolean {
11
+ // Pattern: /XX/ ou /XX où XX est un code langue de 2 lettres minuscules
12
+ const localePattern = /^\/[a-z]{2}(\/|$)/;
13
+ return localePattern.test(href);
14
+ }
15
+
6
16
  /**
7
17
  * Helper pour transformer un URL avec le paramètre [lang]
8
18
  * Utile pour les transformations statiques avant le rendu React
@@ -17,11 +27,16 @@ export function langHref(href: string, lang: Language): string {
17
27
  const normalizedHref = String(href);
18
28
  const isAbsolute = normalizedHref.startsWith("http");
19
29
  const hasLangPrefix = normalizedHref.startsWith(`/${lang}/`);
30
+ const hasAnyLangPrefix = startsWithLocale(normalizedHref);
20
31
 
21
32
  if (isAbsolute) {
22
33
  return normalizedHref;
23
34
  } else if (hasLangPrefix) {
35
+ // Déjà préfixé avec la bonne langue
24
36
  return normalizedHref;
37
+ } else if (hasAnyLangPrefix) {
38
+ // Préfixé avec une autre langue - remplacer par la langue courante
39
+ return `/${lang}${normalizedHref.slice(3)}`;
25
40
  } else if (normalizedHref === "/") {
26
41
  return `/${lang}`;
27
42
  } else if (normalizedHref.startsWith("/api/")) {
package/src/index.ts CHANGED
@@ -22,6 +22,9 @@ export { AdminLayout } from "./layouts/AdminLayout";
22
22
  export { AdminLayoutWithSidebar } from "./layouts/AdminLayoutWithSidebar";
23
23
  export { getModuleConfigs } from "./modules/module-loader";
24
24
 
25
+ // Analytics
26
+ export { registerAnalyticsComponent } from "./analytics/registry";
27
+
25
28
  // i18n
26
29
  export {
27
30
  LanguageProvider,
@@ -42,6 +45,17 @@ export type {
42
45
  ModuleTranslations,
43
46
  } from "./i18n/types";
44
47
 
48
+ // Re-export types from core for scripts
49
+ export type {
50
+ ModuleBuildConfig,
51
+ ModuleApiConfig,
52
+ ModuleMenuItemConfig,
53
+ ModulePageConfig,
54
+ ModuleSection,
55
+ ModuleRealtimeConfig,
56
+ ModuleSitemapConfig,
57
+ } from "@lastbrain/core";
58
+
45
59
  // Components
46
60
  export { AppAside } from "@lastbrain/ui";
47
61
  export type { AppAsideMenuItem, AppAsideMenuConfig } from "@lastbrain/ui";
@@ -53,3 +67,6 @@ export { SimpleDocPage } from "./templates/SimpleDocPage";
53
67
  export { ModuleGuidePage } from "./templates/ModuleGuidePage";
54
68
  export { AuthGuidePage } from "./templates/AuthGuidePage";
55
69
  export { MigrationsGuidePage } from "./templates/MigrationsGuidePage";
70
+
71
+ // Sitemap manifest
72
+ export { sitemapManifest } from "./sitemap/manifest";
@@ -10,12 +10,14 @@ import {
10
10
  import { useAuthSession } from "../auth/useAuthSession";
11
11
  import { usePathname } from "next/navigation";
12
12
  import { useEffect, useState } from "react";
13
+ import type { MenuIgnored } from "../types/menu";
13
14
 
14
15
  interface AdminLayoutWithSidebarProps {
15
16
  children: React.ReactNode;
16
17
  menuConfig?: MenuConfig;
17
18
  className?: string;
18
19
  menuCustom?: MenuItem[];
20
+ menuIgnored?: MenuIgnored;
19
21
  }
20
22
 
21
23
  export function AdminLayoutWithSidebar({
@@ -23,6 +25,7 @@ export function AdminLayoutWithSidebar({
23
25
  menuConfig,
24
26
  className = "",
25
27
  menuCustom,
28
+ menuIgnored,
26
29
  }: AdminLayoutWithSidebarProps) {
27
30
  const { isSuperAdmin, loading, user } = useAuthSession();
28
31
  const pathname = usePathname();
@@ -109,6 +112,7 @@ export function AdminLayoutWithSidebar({
109
112
  isSuperAdmin={isSuperAdmin}
110
113
  isAuthenticated={!!user}
111
114
  className={className}
115
+ {...(menuIgnored ? { menuIgnored } : {})}
112
116
  {...(menuCustom ? { menuCustom } : {})}
113
117
  />
114
118
  )}
@@ -11,6 +11,36 @@ import type { User } from "@supabase/supabase-js";
11
11
  import type { ModuleRealtimeConfig } from "@lastbrain/core";
12
12
  import type { NotificationsData } from "../hooks/useNotifications";
13
13
 
14
+ // Wrapper for optional EntitlementsProvider passed via props
15
+ function OptionalEntitlementsWrapper({
16
+ children,
17
+ EntitlementsProviderComponent,
18
+ }: {
19
+ children: React.ReactNode;
20
+ EntitlementsProviderComponent?: React.ComponentType<{
21
+ children: React.ReactNode;
22
+ }>;
23
+ }) {
24
+ if (EntitlementsProviderComponent) {
25
+ return (
26
+ <EntitlementsProviderComponent>{children}</EntitlementsProviderComponent>
27
+ );
28
+ }
29
+ return <>{children}</>;
30
+ }
31
+
32
+ // Wrapper for optional AnalyticsListener
33
+ function OptionalAnalyticsListener({
34
+ AnalyticsListenerComponent,
35
+ }: {
36
+ AnalyticsListenerComponent?: React.ComponentType;
37
+ }) {
38
+ if (AnalyticsListenerComponent) {
39
+ return <AnalyticsListenerComponent />;
40
+ }
41
+ return null;
42
+ }
43
+
14
44
  const ModuleContext = createContext(getModuleConfigs());
15
45
  const NotificationContext = createContext<{
16
46
  data: NotificationsData;
@@ -65,11 +95,22 @@ export function AppProviders({
65
95
  realtimeConfig = [],
66
96
  lang = "fr",
67
97
  translations = {},
98
+ availableLanguages = ["fr", "en"],
99
+ EntitlementsProviderComponent,
100
+ AnalyticsListenerComponent,
68
101
  }: {
69
102
  children: React.ReactNode;
70
103
  realtimeConfig?: ModuleRealtimeConfig[];
71
104
  lang?: Language;
72
105
  translations?: Record<string, string>;
106
+ /** Liste des langues disponibles depuis locales.generated.ts */
107
+ availableLanguages?: string[];
108
+ /** Provider optionnel pour les entitlements (billing) */
109
+ EntitlementsProviderComponent?: React.ComponentType<{
110
+ children: React.ReactNode;
111
+ }>;
112
+ /** Composant optionnel pour le tracking analytics */
113
+ AnalyticsListenerComponent?: React.ComponentType;
73
114
  }) {
74
115
  const modules = useMemo(() => getModuleConfigs(), []);
75
116
  const { user, loading: authLoading, isSuperAdmin } = useAuthSession();
@@ -97,17 +138,41 @@ export function AppProviders({
97
138
  }, [translations]);
98
139
 
99
140
  return (
100
- <LanguageProvider initialLang={lang} translations={memoizedTranslations}>
141
+ <LanguageProvider
142
+ initialLang={lang}
143
+ translations={memoizedTranslations}
144
+ availableLanguages={availableLanguages}
145
+ >
101
146
  <AppLinkProvider lang={lang || "fr"}>
102
147
  <AuthContext.Provider value={authValue}>
103
- <ModuleContext.Provider value={modules}>
104
- <NotificationContext.Provider value={notificationsData}>
105
- <RealtimeProvider userId={user?.id} config={realtimeConfig}>
106
- {children}
107
- <ToastProvider placement="bottom-right" toastOffset={5} />
108
- </RealtimeProvider>
109
- </NotificationContext.Provider>
110
- </ModuleContext.Provider>
148
+ <OptionalEntitlementsWrapper
149
+ EntitlementsProviderComponent={EntitlementsProviderComponent}
150
+ >
151
+ <ModuleContext.Provider value={modules}>
152
+ <NotificationContext.Provider value={notificationsData}>
153
+ <RealtimeProvider userId={user?.id} config={realtimeConfig}>
154
+ <OptionalAnalyticsListener
155
+ AnalyticsListenerComponent={AnalyticsListenerComponent}
156
+ />
157
+
158
+ {children}
159
+ <ToastProvider
160
+ toastProps={{
161
+ variant: "flat",
162
+ timeout: 5000,
163
+ shouldShowTimeoutProgress: true,
164
+ classNames: {
165
+ closeButton:
166
+ "opacity-100 absolute right-4 top-1/2 -translate-y-1/2",
167
+ },
168
+ }}
169
+ placement="bottom-right"
170
+ toastOffset={5}
171
+ />
172
+ </RealtimeProvider>
173
+ </NotificationContext.Provider>
174
+ </ModuleContext.Provider>
175
+ </OptionalEntitlementsWrapper>
111
176
  </AuthContext.Provider>
112
177
  </AppLinkProvider>
113
178
  </LanguageProvider>
@@ -1,3 +1,3 @@
1
1
  export function AuthLayout({ children }: { children: React.ReactNode }) {
2
- return <div className="pt-4 px-2 md:px-5 max-w-screen">{children}</div>;
2
+ return <div className="pt-16 px-2 md:px-5 max-w-screen">{children}</div>;
3
3
  }
@@ -10,7 +10,7 @@ interface PublicLayoutProps {
10
10
  export function PublicLayout({ children, footerConfig }: PublicLayoutProps) {
11
11
  return (
12
12
  <>
13
- <section className="pt-16 min-h-[calc(100vh)] max-w-screen">
13
+ <section className=" min-h-[calc(100vh)] max-w-screen">
14
14
  {children}
15
15
  </section>
16
16
  {footerConfig && <Footer config={footerConfig} />}
@@ -4,7 +4,6 @@ import { ThemeProvider } from "next-themes";
4
4
  import { AppProviders } from "./AppProviders";
5
5
  import type { ModuleRealtimeConfig } from "@lastbrain/core";
6
6
  import type { Language } from "../i18n/LanguageProvider";
7
-
8
7
  // Note: L'app Next.js doit importer son propre globals.css dans son layout
9
8
  // Note: La configuration realtime doit être fournie par l'app qui utilise ce layout
10
9
  export function RootLayout({