@lastbrain/app 0.1.23 → 0.1.25

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 (51) hide show
  1. package/dist/__tests__/module-registry.test.d.ts +2 -0
  2. package/dist/__tests__/module-registry.test.d.ts.map +1 -0
  3. package/dist/__tests__/module-registry.test.js +64 -0
  4. package/dist/app-shell/(admin)/layout.d.ts +3 -2
  5. package/dist/app-shell/(admin)/layout.d.ts.map +1 -1
  6. package/dist/app-shell/(admin)/layout.js +1 -1
  7. package/dist/app-shell/(auth)/layout.d.ts +3 -2
  8. package/dist/app-shell/(auth)/layout.d.ts.map +1 -1
  9. package/dist/app-shell/(auth)/layout.js +1 -1
  10. package/dist/cli.js +50 -0
  11. package/dist/layouts/AdminLayout.d.ts +3 -2
  12. package/dist/layouts/AdminLayout.d.ts.map +1 -1
  13. package/dist/layouts/AppProviders.d.ts +3 -2
  14. package/dist/layouts/AppProviders.d.ts.map +1 -1
  15. package/dist/layouts/AuthLayout.d.ts +3 -2
  16. package/dist/layouts/AuthLayout.d.ts.map +1 -1
  17. package/dist/layouts/PublicLayout.d.ts +3 -2
  18. package/dist/layouts/PublicLayout.d.ts.map +1 -1
  19. package/dist/layouts/RootLayout.d.ts +3 -2
  20. package/dist/layouts/RootLayout.d.ts.map +1 -1
  21. package/dist/scripts/db-init.js +1 -1
  22. package/dist/scripts/db-migrations-sync.js +5 -5
  23. package/dist/scripts/init-app.d.ts.map +1 -1
  24. package/dist/scripts/init-app.js +355 -23
  25. package/dist/scripts/module-add.d.ts.map +1 -1
  26. package/dist/scripts/module-add.js +1 -1
  27. package/dist/scripts/script-runner.d.ts +5 -0
  28. package/dist/scripts/script-runner.d.ts.map +1 -0
  29. package/dist/scripts/script-runner.js +25 -0
  30. package/dist/styles.css +1 -1
  31. package/dist/templates/DefaultDoc.d.ts.map +1 -1
  32. package/dist/templates/DefaultDoc.js +16 -1
  33. package/dist/templates/DocPage.d.ts.map +1 -1
  34. package/dist/templates/DocPage.js +23 -17
  35. package/package.json +19 -20
  36. package/src/__tests__/module-registry.test.ts +74 -0
  37. package/src/app-shell/(admin)/layout.tsx +5 -3
  38. package/src/app-shell/(auth)/layout.tsx +5 -3
  39. package/src/cli.ts +50 -0
  40. package/src/layouts/AdminLayout.tsx +1 -3
  41. package/src/layouts/AppProviders.tsx +2 -4
  42. package/src/layouts/AuthLayout.tsx +1 -3
  43. package/src/layouts/PublicLayout.tsx +1 -3
  44. package/src/layouts/RootLayout.tsx +1 -2
  45. package/src/scripts/db-init.ts +2 -2
  46. package/src/scripts/db-migrations-sync.ts +1 -1
  47. package/src/scripts/init-app.ts +366 -23
  48. package/src/scripts/module-add.ts +1 -3
  49. package/src/scripts/script-runner.ts +28 -0
  50. package/src/templates/DefaultDoc.tsx +127 -0
  51. package/src/templates/DocPage.tsx +83 -49
@@ -539,6 +539,133 @@ where email = 'votre@email.com';`}
539
539
  </CardBody>
540
540
  </Card>
541
541
 
542
+ <Card id="section-storage" className="scroll-mt-32">
543
+ <CardHeader>
544
+ <h2 className="text-2xl font-semibold flex items-center gap-2">
545
+ <Database size={24} />
546
+ Système de Proxy Storage
547
+ </h2>
548
+ </CardHeader>
549
+ <CardBody className="space-y-4">
550
+ <p className="text-slate-600 dark:text-slate-400">
551
+ LastBrain intègre un système de proxy pour les fichiers Supabase
552
+ Storage qui permet d'utiliser des URLs propres avec contrôle d'accès
553
+ granulaire.
554
+ </p>
555
+
556
+ <div>
557
+ <h3 className="text-lg font-semibold mb-2">
558
+ URLs Proxy vs URLs Supabase
559
+ </h3>
560
+ <div className="space-y-3">
561
+ <div className="bg-red-50 dark:bg-red-950 p-3 rounded-lg">
562
+ <p className="text-sm font-medium text-red-700 dark:text-red-300 mb-1">
563
+ ❌ URL Supabase classique (longue)
564
+ </p>
565
+ <code className="text-xs text-red-600 dark:text-red-400 break-all">
566
+ https://xxx.supabase.co/storage/v1/object/public/avatar/user_128_123456.webp
567
+ </code>
568
+ </div>
569
+ <div className="bg-green-50 dark:bg-green-950 p-3 rounded-lg">
570
+ <p className="text-sm font-medium text-green-700 dark:text-green-300 mb-1">
571
+ ✅ URL Proxy (propre)
572
+ </p>
573
+ <code className="text-xs text-green-600 dark:text-green-400">
574
+ /api/storage/avatar/user_128_123456.webp
575
+ </code>
576
+ </div>
577
+ </div>
578
+ </div>
579
+
580
+ <div>
581
+ <h3 className="text-lg font-semibold mb-2">
582
+ Configuration des Buckets
583
+ </h3>
584
+ <div className="space-y-3">
585
+ <div className="border-l-4 border-green-500 pl-4">
586
+ <h4 className="font-semibold text-green-600 dark:text-green-400">
587
+ 📂 avatar (Public)
588
+ </h4>
589
+ <p className="text-sm text-slate-600 dark:text-slate-400">
590
+ Photos de profil et avatars • 10MB max • Types: JPEG, PNG,
591
+ WebP, GIF
592
+ </p>
593
+ <code className="text-xs bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
594
+ /api/storage/avatar/user_128_123456.webp
595
+ </code>
596
+ </div>
597
+
598
+ <div className="border-l-4 border-blue-500 pl-4">
599
+ <h4 className="font-semibold text-blue-600 dark:text-blue-400">
600
+ 🔒 app (Privé)
601
+ </h4>
602
+ <p className="text-sm text-slate-600 dark:text-slate-400">
603
+ Fichiers privés des utilisateurs • 100MB max •
604
+ Authentification requise
605
+ </p>
606
+ <code className="text-xs bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
607
+ /api/storage/app/user-id/documents/file.pdf
608
+ </code>
609
+ </div>
610
+ </div>
611
+ </div>
612
+
613
+ <div>
614
+ <h3 className="text-lg font-semibold mb-2">
615
+ Utilisation dans le code
616
+ </h3>
617
+ <div className="bg-slate-50 dark:bg-slate-900 p-4 rounded-lg text-sm font-mono overflow-x-auto">
618
+ <pre>{`// Upload d'un fichier
619
+ import { uploadFile } from "@/api/storage";
620
+
621
+ const proxyUrl = await uploadFile(
622
+ "avatar",
623
+ "user_128_123456.webp",
624
+ file,
625
+ "image/webp"
626
+ );
627
+ // Retourne: "/api/storage/avatar/user_128_123456.webp"
628
+
629
+ // Conversion de chemin storage
630
+ import { storagePathToProxyUrl } from "@/lib/storage";
631
+
632
+ const proxyUrl = storagePathToProxyUrl("avatar/user_128_123456.webp");
633
+ // Retourne: "/api/storage/avatar/user_128_123456.webp"`}</pre>
634
+ </div>
635
+ </div>
636
+
637
+ <div>
638
+ <h3 className="text-lg font-semibold mb-2">Avantages du système</h3>
639
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
640
+ <div className="flex items-start gap-2">
641
+ <span className="text-green-600">✅</span>
642
+ <span>URLs plus courtes et lisibles</span>
643
+ </div>
644
+ <div className="flex items-start gap-2">
645
+ <span className="text-green-600">✅</span>
646
+ <span>Contrôle d'accès granulaire</span>
647
+ </div>
648
+ <div className="flex items-start gap-2">
649
+ <span className="text-green-600">✅</span>
650
+ <span>Cache optimisé (1 an)</span>
651
+ </div>
652
+ <div className="flex items-start gap-2">
653
+ <span className="text-green-600">✅</span>
654
+ <span>Sécurité améliorée</span>
655
+ </div>
656
+ <div className="flex items-start gap-2">
657
+ <span className="text-green-600">✅</span>
658
+ <span>Détection auto des types MIME</span>
659
+ </div>
660
+ <div className="flex items-start gap-2">
661
+ <span className="text-green-600">✅</span>
662
+ <span>Extensible facilement</span>
663
+ </div>
664
+ </div>
665
+ </div>
666
+ </CardBody>
667
+ </Card>
668
+
542
669
  <Card id="section-module-docs" className="scroll-mt-32">
543
670
  <CardHeader>
544
671
  <h2 className="text-2xl font-semibold flex items-center gap-2">
@@ -27,9 +27,72 @@ import {
27
27
  BookOpen,
28
28
  Link,
29
29
  Blocks,
30
+ HardDrive,
30
31
  } from "lucide-react";
31
32
  import { DefaultDocumentation } from "./DefaultDoc.js";
32
33
 
34
+ // Composant NavigationListbox séparé pour éviter la recréation
35
+ interface NavigationListboxProps {
36
+ navigationItems: Array<{
37
+ id: string;
38
+ name: string;
39
+ description: string;
40
+ icon: any;
41
+ color?: string;
42
+ number?: number;
43
+ }>;
44
+ selectedModule: string;
45
+ scrollToSection: (id: string) => void;
46
+ setSelectedModule: (id: string) => void;
47
+ }
48
+
49
+ const NavigationListbox: React.FC<NavigationListboxProps> = ({
50
+ navigationItems,
51
+ selectedModule,
52
+ scrollToSection,
53
+ setSelectedModule,
54
+ }) => (
55
+ <Listbox
56
+ aria-label="Navigation"
57
+ selectionMode="single"
58
+ selectedKeys={selectedModule ? [selectedModule] : []}
59
+ onSelectionChange={(keys) => {
60
+ const key = Array.from(keys)[0] as string;
61
+ if (key) {
62
+ scrollToSection(key);
63
+ } else {
64
+ setSelectedModule("");
65
+ window.scrollTo({ top: 0, behavior: "smooth" });
66
+ }
67
+ }}
68
+ items={navigationItems}
69
+ >
70
+ {(item: any) => {
71
+ const IconComponent = item.icon;
72
+ return (
73
+ <ListboxItem
74
+ key={item.id}
75
+ textValue={item.name}
76
+ description={item.description}
77
+ color={item.color}
78
+ variant="solid"
79
+ endContent={
80
+ item.number && (
81
+ <Chip size="sm" color="primary">
82
+ {item.number ?? 0}
83
+ </Chip>
84
+ )
85
+ }
86
+ className={`${selectedModule === item.id ? "bg-default-200/40" : ""}`}
87
+ startContent={<IconComponent size={18} className="shrink-0" />}
88
+ >
89
+ {item.name}
90
+ </ListboxItem>
91
+ );
92
+ }}
93
+ </Listbox>
94
+ );
95
+
33
96
  interface ModuleDocConfig {
34
97
  id: string;
35
98
  name: string;
@@ -66,14 +129,13 @@ export function DocPage({ modules = [], defaultContent }: DocPageProps) {
66
129
  "section-architecture",
67
130
  "section-create-module",
68
131
  "section-database",
132
+ "section-storage",
69
133
  "section-ui",
70
134
  "section-module-docs",
71
135
  "section-links",
72
136
  ...(modules.length > 0 ? ["section-modules"] : []),
73
137
  ...modules.map((m) => `module-${m.id}`),
74
- ];
75
-
76
- // Trouver la section actuellement visible
138
+ ]; // Trouver la section actuellement visible
77
139
  let currentSection = "default";
78
140
 
79
141
  // Si on est tout en haut de la page
@@ -165,6 +227,12 @@ export function DocPage({ modules = [], defaultContent }: DocPageProps) {
165
227
  description: "",
166
228
  icon: Database,
167
229
  },
230
+ {
231
+ id: "section-storage",
232
+ name: "Proxy Storage",
233
+ description: "Gestion des fichiers",
234
+ icon: HardDrive,
235
+ },
168
236
  {
169
237
  id: "section-ui",
170
238
  name: "Interface utilisateur",
@@ -201,50 +269,6 @@ export function DocPage({ modules = [], defaultContent }: DocPageProps) {
201
269
  })),
202
270
  ];
203
271
 
204
- const NavigationListbox = () => (
205
- <Listbox
206
- aria-label="Navigation"
207
- selectionMode="single"
208
- selectedKeys={selectedModule ? [selectedModule] : []}
209
- onSelectionChange={(keys) => {
210
- const key = Array.from(keys)[0] as string;
211
- if (key) {
212
- scrollToSection(key);
213
- } else {
214
- setSelectedModule("");
215
- window.scrollTo({ top: 0, behavior: "smooth" });
216
- }
217
- }}
218
- items={navigationItems}
219
- >
220
- {(item: any) => {
221
- const IconComponent = item.icon;
222
- return (
223
- <ListboxItem
224
- key={item.id}
225
- textValue={item.name}
226
- description={item.description}
227
- color={item.color}
228
- variant="solid"
229
- endContent={
230
- item.number && (
231
- <Chip size="sm" color="primary">
232
- {item.number ?? 0}
233
- </Chip>
234
- )
235
- }
236
- className={`${
237
- selectedModule === item.id ? "bg-default-200/40" : ""
238
- }`}
239
- startContent={<IconComponent size={18} className="shrink-0" />}
240
- >
241
- {item.name}
242
- </ListboxItem>
243
- );
244
- }}
245
- </Listbox>
246
- );
247
-
248
272
  return (
249
273
  <div className="w-full pt-8 md:pt-12 pb-24 lg:pb-8">
250
274
  <div className="container mx-auto md:px-4 py-8">
@@ -272,7 +296,12 @@ export function DocPage({ modules = [], defaultContent }: DocPageProps) {
272
296
  <h2 className="text-xl font-semibold">Navigation</h2>
273
297
  </DrawerHeader>
274
298
  <DrawerBody>
275
- <NavigationListbox />
299
+ <NavigationListbox
300
+ navigationItems={navigationItems}
301
+ selectedModule={selectedModule}
302
+ scrollToSection={scrollToSection}
303
+ setSelectedModule={setSelectedModule}
304
+ />
276
305
  </DrawerBody>
277
306
  </DrawerContent>
278
307
  </Drawer>
@@ -285,7 +314,12 @@ export function DocPage({ modules = [], defaultContent }: DocPageProps) {
285
314
  <h2 className="text-xl font-semibold">Navigation</h2>
286
315
  </CardHeader>
287
316
  <CardBody>
288
- <NavigationListbox />
317
+ <NavigationListbox
318
+ navigationItems={navigationItems}
319
+ selectedModule={selectedModule}
320
+ scrollToSection={scrollToSection}
321
+ setSelectedModule={setSelectedModule}
322
+ />
289
323
  </CardBody>
290
324
  </Card>
291
325
  </aside>