@lastbrain/module-auth 0.1.20 → 0.1.22

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.
@@ -1 +1 @@
1
- {"version":3,"file":"AccountButton.d.ts","sourceRoot":"","sources":["../../src/components/AccountButton.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAGlD,UAAU,kBAAkB;IAC1B,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AASD,eAAO,MAAM,aAAa,GAAI,kCAI3B,kBAAkB,4CAoHpB,CAAC"}
1
+ {"version":3,"file":"AccountButton.d.ts","sourceRoot":"","sources":["../../src/components/AccountButton.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAGlD,UAAU,kBAAkB;IAC1B,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AASD,eAAO,MAAM,aAAa,GAAI,kCAI3B,kBAAkB,4CA8HpB,CAAC"}
@@ -14,10 +14,12 @@ const getIcon = (iconName) => {
14
14
  export const AccountButton = ({ user, accountMenu = [], onLogout, }) => {
15
15
  if (!user)
16
16
  return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "block md:hidden", children: [_jsx(Button, { as: Link, href: "/signin", radius: "full", isIconOnly: true, variant: "light", color: "primary", children: _jsx(LucideIcons.LogIn, { size: 16 }) }), _jsx(Button, { as: Link, href: "/signup", radius: "full", isIconOnly: true, variant: "flat", className: "ml-2", color: "secondary", children: _jsx(LucideIcons.UserPlus2, { size: 16 }) })] }), _jsxs("div", { className: "hidden md:block", children: [_jsx(Button, { as: Link, href: "/signin", startContent: _jsx(LucideIcons.LogIn, { size: 16 }), variant: "light", color: "primary", children: "Se connecter" }), _jsx(Button, { as: Link, href: "/signup", variant: "flat", className: "ml-2", color: "secondary", startContent: _jsx(LucideIcons.UserPlus2, { size: 16 }), children: "S'inscrire" })] })] }));
17
- return (_jsxs(Dropdown, { children: [_jsx(DropdownTrigger, { children: _jsx(Avatar, { size: "sm", src: `/api/storage/${user?.user_metadata.avatar}`, title: user.email, fallback: _jsx(LucideIcons.User2, { size: 18 }), classNames: {
18
- base: "bg-white/0",
17
+ return (_jsxs(Dropdown, { children: [_jsx(DropdownTrigger, { children: user?.user_metadata.avatar ? (_jsx(Avatar, { size: "sm", src: user?.user_metadata.avatar
18
+ ? `/api/storage/${user?.user_metadata.avatar}`
19
+ : undefined, title: user.email, fallback: _jsx(LucideIcons.User2, { size: 18 }), classNames: {
20
+ base: "cursor-pointer bg-white/0",
19
21
  icon: "text-default-700",
20
- } }) }), _jsx(DropdownMenu, { items: [
22
+ } })) : (_jsx(Button, { size: "sm", variant: "flat", radius: "full", isIconOnly: true, children: _jsx(LucideIcons.User2, { size: 16 }) })) }), _jsx(DropdownMenu, { items: [
21
23
  {
22
24
  key: "hello",
23
25
  label: `Bonjour ${user?.user_metadata?.full_name || user.email}`,
@@ -1 +1 @@
1
- {"version":3,"file":"folder.d.ts","sourceRoot":"","sources":["../../../src/web/auth/folder.tsx"],"names":[],"mappings":"AA4BA,wBAAgB,UAAU,mDAwEzB"}
1
+ {"version":3,"file":"folder.d.ts","sourceRoot":"","sources":["../../../src/web/auth/folder.tsx"],"names":[],"mappings":"AAqBA,wBAAgB,UAAU,mDAqEzB"}
@@ -1,8 +1,9 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from "react";
4
- import { Card, CardBody, Spinner, } from "@lastbrain/ui";
4
+ import { Card, CardBody, Spinner } from "@lastbrain/ui";
5
5
  import { FileManager } from "@lastbrain/ui";
6
+ import { ImageGenerative } from "@lastbrain/module-ai";
6
7
  export function FolderPage() {
7
8
  const [userData, setUserData] = useState(null);
8
9
  const [isLoading, setIsLoading] = useState(true);
@@ -36,8 +37,5 @@ export function FolderPage() {
36
37
  if (!userData) {
37
38
  return null;
38
39
  }
39
- const fullName = userData.profile?.first_name && userData.profile?.last_name
40
- ? `${userData.profile.first_name} ${userData.profile.last_name}`
41
- : "User";
42
- return (_jsxs("div", { className: "pt-4 pb-12 max-w-8xl mx-auto px-4", children: [_jsx("h1", { className: "text-3xl font-bold mb-8", children: "Dossier" }), _jsx(FileManager, { bucket: "app", basePath: userData.id, allowUpload: true, allowCreateFolder: true, className: "min-h-[80vh]" })] }));
40
+ return (_jsxs("div", { className: "pt-4 pb-12 max-w-8xl mx-auto px-4", children: [_jsx("h1", { className: "text-3xl font-bold mb-8", children: "Dossier" }), _jsx(FileManager, { bucket: "app", basePath: userData.id, allowUpload: true, allowCreateFolder: true, allowAIImageGeneration: true, renderImageGenerator: (props) => _jsx(ImageGenerative, { ...props }), className: "min-h-[80vh]" })] }));
43
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lastbrain/module-auth",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "Module d'authentification complet pour LastBrain avec Supabase",
5
5
  "private": false,
6
6
  "type": "module",
@@ -34,6 +34,7 @@
34
34
  "dependencies": {
35
35
  "@lastbrain/core": "^0.1.0",
36
36
  "@lastbrain/ui": "^0.1.0",
37
+ "@lastbrain/module-ai": "^0.1.0",
37
38
  "@supabase/supabase-js": "^2.86.0",
38
39
  "lucide-react": "^0.554.0",
39
40
  "react": "^19.0.0",
@@ -7,7 +7,7 @@ import { getSupabaseServerClient } from "@lastbrain/core/server";
7
7
  */
8
8
  export async function POST(
9
9
  request: NextRequest,
10
- context: { params: Promise<{ id: string }> },
10
+ context: { params: Promise<{ id: string }> }
11
11
  ) {
12
12
  try {
13
13
  const supabase = await getSupabaseServerClient();
@@ -16,7 +16,7 @@ export async function POST(
16
16
  if (!userId) {
17
17
  return NextResponse.json(
18
18
  { error: "User ID is required" },
19
- { status: 400 },
19
+ { status: 400 }
20
20
  );
21
21
  }
22
22
 
@@ -26,7 +26,7 @@ export async function POST(
26
26
  if (!title?.trim() || !message?.trim()) {
27
27
  return NextResponse.json(
28
28
  { error: "Title and message are required" },
29
- { status: 400 },
29
+ { status: 400 }
30
30
  );
31
31
  }
32
32
 
@@ -47,7 +47,7 @@ export async function POST(
47
47
  console.error("Error creating notification:", error);
48
48
  return NextResponse.json(
49
49
  { error: "Database Error", message: error.message },
50
- { status: 500 },
50
+ { status: 500 }
51
51
  );
52
52
  }
53
53
 
@@ -62,7 +62,7 @@ export async function POST(
62
62
  error: "Internal Server Error",
63
63
  message: "Failed to send notification",
64
64
  },
65
- { status: 500 },
65
+ { status: 500 }
66
66
  );
67
67
  }
68
68
  }
@@ -7,7 +7,7 @@ import { getSupabaseServerClient } from "@lastbrain/core/server";
7
7
  */
8
8
  export async function GET(
9
9
  request: NextRequest,
10
- context: { params: Promise<{ id: string }> },
10
+ context: { params: Promise<{ id: string }> }
11
11
  ) {
12
12
  try {
13
13
  const supabase = await getSupabaseServerClient();
@@ -16,21 +16,21 @@ export async function GET(
16
16
  if (!userId) {
17
17
  return NextResponse.json(
18
18
  { error: "User ID is required" },
19
- { status: 400 },
19
+ { status: 400 }
20
20
  );
21
21
  }
22
22
 
23
23
  // Utiliser la fonction RPC pour récupérer les détails de l'utilisateur
24
24
  const { data: userDetails, error: userError } = await supabase.rpc(
25
25
  "get_admin_user_details",
26
- { user_id: userId },
26
+ { user_id: userId }
27
27
  );
28
28
 
29
29
  if (userError) {
30
30
  console.error("Error fetching user details:", userError);
31
31
  return NextResponse.json(
32
32
  { error: "Database Error", message: userError.message },
33
- { status: 500 },
33
+ { status: 500 }
34
34
  );
35
35
  }
36
36
 
@@ -46,7 +46,7 @@ export async function GET(
46
46
  error: "Internal Server Error",
47
47
  message: "Failed to fetch user details",
48
48
  },
49
- { status: 500 },
49
+ { status: 500 }
50
50
  );
51
51
  }
52
52
  }
@@ -25,14 +25,14 @@ export async function GET(request: NextRequest) {
25
25
  page_number: page,
26
26
  page_size: perPage,
27
27
  search_term: search,
28
- },
28
+ }
29
29
  );
30
30
 
31
31
  if (usersError) {
32
32
  console.error("Error fetching users:", usersError);
33
33
  return NextResponse.json(
34
34
  { error: "Database Error", message: usersError.message },
35
- { status: 500 },
35
+ { status: 500 }
36
36
  );
37
37
  }
38
38
 
@@ -41,7 +41,7 @@ export async function GET(request: NextRequest) {
41
41
  result || {
42
42
  data: [],
43
43
  pagination: { page, per_page: perPage, total: 0, total_pages: 0 },
44
- },
44
+ }
45
45
  );
46
46
  } catch (error) {
47
47
  console.error("Error in admin users endpoint:", error);
@@ -50,7 +50,7 @@ export async function GET(request: NextRequest) {
50
50
  error: "Internal Server Error",
51
51
  message: "Failed to fetch users",
52
52
  },
53
- { status: 500 },
53
+ { status: 500 }
54
54
  );
55
55
  }
56
56
  }
@@ -35,7 +35,7 @@ export async function GET() {
35
35
  console.error("Error fetching user:", error);
36
36
  return NextResponse.json(
37
37
  { error: "Internal Server Error", message: "Failed to fetch user data" },
38
- { status: 500 },
38
+ { status: 500 }
39
39
  );
40
40
  }
41
41
  }
@@ -24,7 +24,7 @@ export async function GET() {
24
24
  // PGRST116 = no rows returned, which is OK
25
25
  return NextResponse.json(
26
26
  { error: "Database Error", message: profileError.message },
27
- { status: 500 },
27
+ { status: 500 }
28
28
  );
29
29
  }
30
30
 
@@ -33,7 +33,7 @@ export async function GET() {
33
33
  console.error("Error fetching profile:", error);
34
34
  return NextResponse.json(
35
35
  { error: "Internal Server Error", message: "Failed to fetch profile" },
36
- { status: 500 },
36
+ { status: 500 }
37
37
  );
38
38
  }
39
39
  }
@@ -119,7 +119,7 @@ export async function PUT(request: NextRequest) {
119
119
  if (result.error) {
120
120
  return NextResponse.json(
121
121
  { error: "Database Error", message: result.error.message },
122
- { status: 500 },
122
+ { status: 500 }
123
123
  );
124
124
  }
125
125
 
@@ -128,7 +128,7 @@ export async function PUT(request: NextRequest) {
128
128
  console.error("Error updating profile:", error);
129
129
  return NextResponse.json(
130
130
  { error: "Internal Server Error", message: "Failed to update profile" },
131
- { status: 500 },
131
+ { status: 500 }
132
132
  );
133
133
  }
134
134
  }
@@ -7,7 +7,7 @@ export async function uploadFile(
7
7
  bucket: string,
8
8
  path: string,
9
9
  file: Blob,
10
- contentType: string,
10
+ contentType: string
11
11
  ): Promise<string> {
12
12
  const { data, error } = await supabaseBrowserClient.storage
13
13
  .from(bucket)
@@ -29,7 +29,7 @@ export async function uploadFile(
29
29
  */
30
30
  export async function deleteFiles(
31
31
  bucket: string,
32
- paths: string[],
32
+ paths: string[]
33
33
  ): Promise<void> {
34
34
  const { error } = await supabaseBrowserClient.storage
35
35
  .from(bucket)
@@ -45,7 +45,7 @@ export async function deleteFiles(
45
45
  */
46
46
  export async function deleteFilesWithPrefix(
47
47
  bucket: string,
48
- prefix: string,
48
+ prefix: string
49
49
  ): Promise<void> {
50
50
  // List files with the prefix
51
51
  const { data: files, error: listError } = await supabaseBrowserClient.storage
@@ -92,16 +92,26 @@ export const AccountButton = ({
92
92
  return (
93
93
  <Dropdown>
94
94
  <DropdownTrigger>
95
- <Avatar
96
- size="sm"
97
- src={`/api/storage/${user?.user_metadata.avatar}`}
98
- title={user.email}
99
- fallback={<LucideIcons.User2 size={18} />}
100
- classNames={{
101
- base: "bg-white/0",
102
- icon: "text-default-700",
103
- }}
104
- />
95
+ {user?.user_metadata.avatar ? (
96
+ <Avatar
97
+ size="sm"
98
+ src={
99
+ user?.user_metadata.avatar
100
+ ? `/api/storage/${user?.user_metadata.avatar}`
101
+ : undefined
102
+ }
103
+ title={user.email}
104
+ fallback={<LucideIcons.User2 size={18} />}
105
+ classNames={{
106
+ base: "cursor-pointer bg-white/0",
107
+ icon: "text-default-700",
108
+ }}
109
+ />
110
+ ) : (
111
+ <Button size="sm" variant="flat" radius="full" isIconOnly>
112
+ <LucideIcons.User2 size={16} />
113
+ </Button>
114
+ )}
105
115
  </DropdownTrigger>
106
116
 
107
117
  <DropdownMenu
@@ -414,7 +414,7 @@ export function UserDetailPage({
414
414
  <p className="font-medium mt-1">
415
415
  {userProfile.created_at
416
416
  ? new Date(
417
- userProfile.created_at,
417
+ userProfile.created_at
418
418
  ).toLocaleDateString("fr-FR", {
419
419
  year: "numeric",
420
420
  month: "long",
@@ -430,7 +430,7 @@ export function UserDetailPage({
430
430
  <p className="font-medium mt-1">
431
431
  {userProfile.last_sign_in_at
432
432
  ? new Date(
433
- userProfile.last_sign_in_at,
433
+ userProfile.last_sign_in_at
434
434
  ).toLocaleDateString("fr-FR", {
435
435
  year: "numeric",
436
436
  month: "long",
@@ -542,7 +542,7 @@ export function UserDetailPage({
542
542
  user_metadata: userProfile.raw_user_meta_data,
543
543
  },
544
544
  null,
545
- 2,
545
+ 2
546
546
  )}
547
547
  </pre>
548
548
  </div>
@@ -117,7 +117,7 @@ export function AdminUsersPage() {
117
117
  (userId: string) => {
118
118
  router.push(`/admin/auth/users/${userId}`);
119
119
  },
120
- [router],
120
+ [router]
121
121
  );
122
122
 
123
123
  const formatDate = (dateString: string) => {
@@ -196,7 +196,7 @@ export function DashboardPage() {
196
196
  <p className="text-2xl font-bold text-secondary">
197
197
  {Math.floor(
198
198
  (Date.now() - new Date(userData.created_at).getTime()) /
199
- (1000 * 60 * 60 * 24),
199
+ (1000 * 60 * 60 * 24)
200
200
  )}
201
201
  </p>
202
202
  <p className="text-small text-default-500">Days active</p>
@@ -1,16 +1,9 @@
1
1
  "use client";
2
2
 
3
3
  import { useEffect, useState } from "react";
4
- import {
5
- Card,
6
- CardBody,
7
- CardHeader,
8
- Spinner,
9
- Chip,
10
- Divider,
11
- Avatar,
12
- } from "@lastbrain/ui";
4
+ import { Card, CardBody, Spinner } from "@lastbrain/ui";
13
5
  import { FileManager } from "@lastbrain/ui";
6
+ import { ImageGenerative } from "@lastbrain/module-ai";
14
7
 
15
8
  interface UserData {
16
9
  id: string;
@@ -80,11 +73,6 @@ export function FolderPage() {
80
73
  return null;
81
74
  }
82
75
 
83
- const fullName =
84
- userData.profile?.first_name && userData.profile?.last_name
85
- ? `${userData.profile.first_name} ${userData.profile.last_name}`
86
- : "User";
87
-
88
76
  return (
89
77
  <div className="pt-4 pb-12 max-w-8xl mx-auto px-4">
90
78
  <h1 className="text-3xl font-bold mb-8">Dossier</h1>
@@ -94,6 +82,8 @@ export function FolderPage() {
94
82
  basePath={userData.id}
95
83
  allowUpload={true}
96
84
  allowCreateFolder={true}
85
+ allowAIImageGeneration={true}
86
+ renderImageGenerator={(props) => <ImageGenerative {...props} />}
97
87
  className="min-h-[80vh]"
98
88
  />
99
89
  </div>
@@ -146,19 +146,19 @@ export function ProfilePage() {
146
146
  "avatar",
147
147
  `${currentUser.id}_32_${version}.webp`,
148
148
  files.small,
149
- "image/webp",
149
+ "image/webp"
150
150
  );
151
151
  urls.medium = await uploadFile(
152
152
  "avatar",
153
153
  `${currentUser.id}_64_${version}.webp`,
154
154
  files.medium,
155
- "image/webp",
155
+ "image/webp"
156
156
  );
157
157
  urls.large = await uploadFile(
158
158
  "avatar",
159
159
  `${currentUser.id}_128_${version}.webp`,
160
160
  files.large,
161
- "image/webp",
161
+ "image/webp"
162
162
  );
163
163
 
164
164
  // Update user metadata
@@ -75,7 +75,7 @@ function SignUpForm() {
75
75
  // Si la confirmation par email est requise
76
76
  if (data.user && !data.session) {
77
77
  setSuccess(
78
- "Compte créé avec succès ! Veuillez vérifier votre email pour confirmer votre compte.",
78
+ "Compte créé avec succès ! Veuillez vérifier votre email pour confirmer votre compte."
79
79
  );
80
80
  return;
81
81
  }