@lastbrain/module-auth 0.1.1 → 0.1.3

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 (41) hide show
  1. package/README.md +504 -0
  2. package/dist/api/admin/users.d.ts +36 -0
  3. package/dist/api/admin/users.d.ts.map +1 -0
  4. package/dist/api/admin/users.js +90 -0
  5. package/dist/api/auth/me.d.ts +17 -0
  6. package/dist/api/auth/me.d.ts.map +1 -0
  7. package/dist/api/auth/me.js +34 -0
  8. package/dist/api/auth/profile.d.ts +32 -0
  9. package/dist/api/auth/profile.d.ts.map +1 -0
  10. package/dist/api/auth/profile.js +108 -0
  11. package/dist/api/storage.d.ts +13 -0
  12. package/dist/api/storage.d.ts.map +1 -0
  13. package/dist/api/storage.js +47 -0
  14. package/dist/auth.build.config.d.ts.map +1 -1
  15. package/dist/auth.build.config.js +21 -0
  16. package/dist/web/admin/users.d.ts.map +1 -1
  17. package/dist/web/admin/users.js +87 -2
  18. package/dist/web/auth/dashboard.d.ts +1 -1
  19. package/dist/web/auth/dashboard.d.ts.map +1 -1
  20. package/dist/web/auth/dashboard.js +42 -2
  21. package/dist/web/auth/profile.d.ts.map +1 -1
  22. package/dist/web/auth/profile.js +152 -2
  23. package/dist/web/auth/reglage.d.ts.map +1 -1
  24. package/dist/web/auth/reglage.js +98 -2
  25. package/package.json +5 -4
  26. package/src/api/admin/users.ts +124 -0
  27. package/src/api/auth/me.ts +48 -0
  28. package/src/api/auth/profile.ts +156 -0
  29. package/src/api/public/signin.ts +31 -0
  30. package/src/api/storage.ts +63 -0
  31. package/src/auth.build.config.ts +137 -0
  32. package/src/components/Doc.tsx +310 -0
  33. package/src/index.ts +12 -0
  34. package/src/server.ts +2 -0
  35. package/src/web/admin/users.tsx +266 -0
  36. package/src/web/auth/dashboard.tsx +202 -0
  37. package/src/web/auth/profile.tsx +381 -0
  38. package/src/web/auth/reglage.tsx +304 -0
  39. package/src/web/public/ResetPassword.tsx +3 -0
  40. package/src/web/public/SignInPage.tsx +255 -0
  41. package/src/web/public/SignUpPage.tsx +293 -0
@@ -1,4 +1,100 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { Card, CardBody, CardHeader, Switch, Button, Spinner, Divider, Select, SelectItem, addToast, } from "@lastbrain/ui";
5
+ import { Settings, Save } from "lucide-react";
2
6
  export function ReglagePage() {
3
- return _jsx("div", { className: "pt-12", children: "Welcome to your Reglage!" });
7
+ const [preferences, setPreferences] = useState({
8
+ email_notifications: true,
9
+ push_notifications: false,
10
+ marketing_emails: false,
11
+ theme: "system",
12
+ language: "en",
13
+ timezone: "UTC",
14
+ });
15
+ const [isLoading, setIsLoading] = useState(true);
16
+ const [isSaving, setIsSaving] = useState(false);
17
+ useEffect(() => {
18
+ fetchSettings();
19
+ }, []);
20
+ const fetchSettings = async () => {
21
+ try {
22
+ setIsLoading(true);
23
+ const response = await fetch("/api/auth/profile");
24
+ if (!response.ok) {
25
+ throw new Error("Failed to fetch settings");
26
+ }
27
+ const result = await response.json();
28
+ if (result.data) {
29
+ const profile = result.data;
30
+ setPreferences((prev) => ({
31
+ ...prev,
32
+ language: profile.language || prev.language,
33
+ timezone: profile.timezone || prev.timezone,
34
+ ...(profile.preferences || {}),
35
+ }));
36
+ }
37
+ }
38
+ catch (err) {
39
+ console.error("Error loading settings:", err);
40
+ addToast({
41
+ title: "Error",
42
+ description: "Failed to load settings",
43
+ color: "danger",
44
+ });
45
+ }
46
+ finally {
47
+ setIsLoading(false);
48
+ }
49
+ };
50
+ const handleSave = async () => {
51
+ setIsSaving(true);
52
+ try {
53
+ const response = await fetch("/api/auth/profile", {
54
+ method: "PUT",
55
+ headers: {
56
+ "Content-Type": "application/json",
57
+ },
58
+ body: JSON.stringify({
59
+ language: preferences.language,
60
+ timezone: preferences.timezone,
61
+ preferences: {
62
+ email_notifications: preferences.email_notifications,
63
+ push_notifications: preferences.push_notifications,
64
+ marketing_emails: preferences.marketing_emails,
65
+ theme: preferences.theme,
66
+ },
67
+ }),
68
+ });
69
+ if (!response.ok) {
70
+ throw new Error("Failed to update settings");
71
+ }
72
+ addToast({
73
+ title: "Success",
74
+ description: "Settings updated successfully",
75
+ color: "success",
76
+ });
77
+ }
78
+ catch (err) {
79
+ console.error("Error updating settings:", err);
80
+ addToast({
81
+ title: "Error",
82
+ description: "Failed to update settings",
83
+ color: "danger",
84
+ });
85
+ }
86
+ finally {
87
+ setIsSaving(false);
88
+ }
89
+ };
90
+ const handleToggle = (key, value) => {
91
+ setPreferences((prev) => ({ ...prev, [key]: value }));
92
+ };
93
+ const handleSelect = (key, value) => {
94
+ setPreferences((prev) => ({ ...prev, [key]: value }));
95
+ };
96
+ if (isLoading) {
97
+ return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsx(Spinner, { size: "lg", label: "Loading settings..." }) }));
98
+ }
99
+ return (_jsxs("div", { className: "pt-12 pb-12 max-w-4xl mx-auto px-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(Settings, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: "Account Settings" })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Notifications" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Email Notifications" }), _jsx("p", { className: "text-small text-default-500", children: "Receive email notifications for important updates" })] }), _jsx(Switch, { isSelected: preferences.email_notifications, onValueChange: (value) => handleToggle("email_notifications", value) })] }), _jsx(Divider, {}), _jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Push Notifications" }), _jsx("p", { className: "text-small text-default-500", children: "Receive push notifications in your browser" })] }), _jsx(Switch, { isSelected: preferences.push_notifications, onValueChange: (value) => handleToggle("push_notifications", value) })] }), _jsx(Divider, {}), _jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Marketing Emails" }), _jsx("p", { className: "text-small text-default-500", children: "Receive emails about new features and updates" })] }), _jsx(Switch, { isSelected: preferences.marketing_emails, onValueChange: (value) => handleToggle("marketing_emails", value) })] })] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Appearance" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs(Select, { label: "Theme", placeholder: "Select a theme", selectedKeys: preferences.theme ? [preferences.theme] : [], onChange: (e) => handleSelect("theme", e.target.value), children: [_jsx(SelectItem, { children: "Light" }, "light"), _jsx(SelectItem, { children: "Dark" }, "dark"), _jsx(SelectItem, { children: "System" }, "system")] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Language & Region" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs(Select, { label: "Language", placeholder: "Select a language", selectedKeys: preferences.language ? [preferences.language] : [], onChange: (e) => handleSelect("language", e.target.value), children: [_jsx(SelectItem, { children: "English" }, "en"), _jsx(SelectItem, { children: "Fran\u00E7ais" }, "fr"), _jsx(SelectItem, { children: "Espa\u00F1ol" }, "es"), _jsx(SelectItem, { children: "Deutsch" }, "de")] }), _jsxs(Select, { label: "Timezone", placeholder: "Select a timezone", selectedKeys: preferences.timezone ? [preferences.timezone] : [], onChange: (e) => handleSelect("timezone", e.target.value), children: [_jsx(SelectItem, { children: "UTC" }, "UTC"), _jsx(SelectItem, { children: "Europe/Paris" }, "Europe/Paris"), _jsx(SelectItem, { children: "America/New_York" }, "America/New_York"), _jsx(SelectItem, { children: "America/Los_Angeles" }, "America/Los_Angeles"), _jsx(SelectItem, { children: "Asia/Tokyo" }, "Asia/Tokyo")] })] }) })] }), _jsxs("div", { className: "flex justify-end gap-3", children: [_jsx(Button, { type: "button", variant: "flat", onPress: () => fetchSettings(), isDisabled: isSaving, children: "Reset" }), _jsx(Button, { type: "button", color: "primary", isLoading: isSaving, onPress: handleSave, startContent: !isSaving && _jsx(Save, { className: "w-4 h-4" }), children: isSaving ? "Saving..." : "Save Settings" })] })] })] }));
4
100
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lastbrain/module-auth",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Module d'authentification complet pour LastBrain avec Supabase",
5
5
  "private": false,
6
6
  "type": "module",
@@ -25,14 +25,15 @@
25
25
  },
26
26
  "files": [
27
27
  "dist",
28
+ "src",
28
29
  "supabase"
29
30
  ],
30
31
  "dependencies": {
32
+ "@lastbrain/core": "^0.1.0",
33
+ "@lastbrain/ui": "^0.1.4",
31
34
  "lucide-react": "^0.554.0",
32
35
  "react": "^19.0.0",
33
- "react-dom": "^19.0.0",
34
- "@lastbrain/core": "0.1.0",
35
- "@lastbrain/ui": "0.1.3"
36
+ "react-dom": "^19.0.0"
36
37
  },
37
38
  "peerDependencies": {
38
39
  "next": ">=15.0.0"
@@ -0,0 +1,124 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ import { getSupabaseServerClient } from "@lastbrain/core/server";
3
+
4
+ /**
5
+ * GET /api/admin/users
6
+ * Returns all users (superadmin only)
7
+ * Supports pagination via query params: page, per_page
8
+ * Supports search via query param: search (email)
9
+ */
10
+ export async function GET(request: NextRequest) {
11
+ try {
12
+ const supabase = await getSupabaseServerClient();
13
+
14
+ // Check authentication
15
+ const {
16
+ data: { user },
17
+ error: authError,
18
+ } = await supabase.auth.getUser();
19
+
20
+ if (authError || !user) {
21
+ return NextResponse.json(
22
+ { error: "Unauthorized", message: "User not authenticated" },
23
+ { status: 401 }
24
+ );
25
+ }
26
+
27
+ // Check if user is superadmin
28
+ const { data: isSuperAdmin } = await supabase.rpc("is_superadmin", {
29
+ user_id: user.id,
30
+ });
31
+
32
+ if (!isSuperAdmin) {
33
+ return NextResponse.json(
34
+ { error: "Forbidden", message: "Superadmin access required" },
35
+ { status: 403 }
36
+ );
37
+ }
38
+
39
+ // Get query parameters
40
+ const searchParams = request.nextUrl.searchParams;
41
+ const page = parseInt(searchParams.get("page") || "1");
42
+ const perPage = parseInt(searchParams.get("per_page") || "20");
43
+ const search = searchParams.get("search") || "";
44
+
45
+ // Note: We can only get public user data from auth.users via RPC or service role
46
+ // For now, we'll query user_profil which has owner_id references
47
+ let query = supabase
48
+ .from("user_profil")
49
+ .select("*, owner_id", { count: "exact" })
50
+ .order("created_at", { ascending: false });
51
+
52
+ // Add search filter if provided - using Supabase's built-in parameterized query
53
+ if (search) {
54
+ // Using .ilike with % wildcards - Supabase handles escaping
55
+ query = query.or(
56
+ `first_name.ilike.%${search}%,last_name.ilike.%${search}%`
57
+ );
58
+ }
59
+
60
+ // Apply pagination
61
+ const start = (page - 1) * perPage;
62
+ query = query.range(start, start + perPage - 1);
63
+
64
+ const { data: profiles, error: profileError, count } = await query;
65
+
66
+ if (profileError) {
67
+ console.error("Error fetching users:", profileError);
68
+ return NextResponse.json(
69
+ { error: "Database Error", message: profileError.message },
70
+ { status: 500 }
71
+ );
72
+ }
73
+
74
+ // Get auth users data in batch - more efficient than individual calls
75
+ // Note: auth.admin methods require service role, so results may be limited
76
+ // In production, consider creating a database view or RPC function to join
77
+ // user_profil with auth.users for better performance
78
+ const users = await Promise.all(
79
+ (profiles || []).map(async (profile) => {
80
+ // Get basic auth info - this is limited to what's available
81
+ const { data: authData } = await supabase.auth.admin.getUserById(
82
+ profile.owner_id
83
+ );
84
+
85
+ return {
86
+ id: profile.owner_id,
87
+ email: authData?.user?.email || "N/A",
88
+ created_at: authData?.user?.created_at || profile.created_at,
89
+ profile: {
90
+ first_name: profile.first_name,
91
+ last_name: profile.last_name,
92
+ avatar_url: profile.avatar_url,
93
+ bio: profile.bio,
94
+ phone: profile.phone,
95
+ company: profile.company,
96
+ website: profile.website,
97
+ location: profile.location,
98
+ language: profile.language,
99
+ timezone: profile.timezone,
100
+ },
101
+ };
102
+ })
103
+ );
104
+
105
+ return NextResponse.json({
106
+ data: users,
107
+ pagination: {
108
+ page,
109
+ per_page: perPage,
110
+ total: count || 0,
111
+ total_pages: Math.ceil((count || 0) / perPage),
112
+ },
113
+ });
114
+ } catch (error) {
115
+ console.error("Error in admin users endpoint:", error);
116
+ return NextResponse.json(
117
+ {
118
+ error: "Internal Server Error",
119
+ message: "Failed to fetch users",
120
+ },
121
+ { status: 500 }
122
+ );
123
+ }
124
+ }
@@ -0,0 +1,48 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getSupabaseServerClient } from "@lastbrain/core/server";
3
+
4
+ /**
5
+ * GET /api/auth/me
6
+ * Returns the current authenticated user and their profile
7
+ */
8
+ export async function GET() {
9
+ try {
10
+ const supabase = await getSupabaseServerClient();
11
+
12
+ // Get the authenticated user
13
+ const {
14
+ data: { user },
15
+ error: authError,
16
+ } = await supabase.auth.getUser();
17
+
18
+ if (authError || !user) {
19
+ return NextResponse.json(
20
+ { error: "Unauthorized", message: "User not authenticated" },
21
+ { status: 401 }
22
+ );
23
+ }
24
+
25
+ // Get user profile
26
+ const { data: profile, error: profileError } = await supabase
27
+ .from("user_profil")
28
+ .select("*")
29
+ .eq("owner_id", user.id)
30
+ .single();
31
+
32
+ // Profile might not exist yet, that's OK
33
+ const userData = {
34
+ id: user.id,
35
+ email: user.email,
36
+ created_at: user.created_at,
37
+ profile: profile || null,
38
+ };
39
+
40
+ return NextResponse.json({ data: userData });
41
+ } catch (error) {
42
+ console.error("Error fetching user:", error);
43
+ return NextResponse.json(
44
+ { error: "Internal Server Error", message: "Failed to fetch user data" },
45
+ { status: 500 }
46
+ );
47
+ }
48
+ }
@@ -0,0 +1,156 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ import { getSupabaseServerClient } from "@lastbrain/core/server";
3
+
4
+ /**
5
+ * GET /api/auth/profile
6
+ * Returns the user's profile
7
+ */
8
+ export async function GET() {
9
+ try {
10
+ const supabase = await getSupabaseServerClient();
11
+
12
+ const {
13
+ data: { user },
14
+ error: authError,
15
+ } = await supabase.auth.getUser();
16
+
17
+ if (authError || !user) {
18
+ return NextResponse.json(
19
+ { error: "Unauthorized", message: "User not authenticated" },
20
+ { status: 401 }
21
+ );
22
+ }
23
+
24
+ const { data: profile, error: profileError } = await supabase
25
+ .from("user_profil")
26
+ .select("*")
27
+ .eq("owner_id", user.id)
28
+ .single();
29
+
30
+ if (profileError && profileError.code !== "PGRST116") {
31
+ // PGRST116 = no rows returned, which is OK
32
+ return NextResponse.json(
33
+ { error: "Database Error", message: profileError.message },
34
+ { status: 500 }
35
+ );
36
+ }
37
+
38
+ return NextResponse.json({ data: profile || null });
39
+ } catch (error) {
40
+ console.error("Error fetching profile:", error);
41
+ return NextResponse.json(
42
+ { error: "Internal Server Error", message: "Failed to fetch profile" },
43
+ { status: 500 }
44
+ );
45
+ }
46
+ }
47
+
48
+ /**
49
+ * PUT /api/auth/profile
50
+ * Updates the user's profile
51
+ */
52
+ export async function PUT(request: NextRequest) {
53
+ try {
54
+ const supabase = await getSupabaseServerClient();
55
+
56
+ const {
57
+ data: { user },
58
+ error: authError,
59
+ } = await supabase.auth.getUser();
60
+
61
+ if (authError || !user) {
62
+ return NextResponse.json(
63
+ { error: "Unauthorized", message: "User not authenticated" },
64
+ { status: 401 }
65
+ );
66
+ }
67
+
68
+ const body = await request.json();
69
+ const {
70
+ first_name,
71
+ last_name,
72
+ avatar_url,
73
+ bio,
74
+ phone,
75
+ company,
76
+ website,
77
+ location,
78
+ language,
79
+ timezone,
80
+ preferences,
81
+ } = body;
82
+
83
+ // Check if profile exists
84
+ const { data: existingProfile } = await supabase
85
+ .from("user_profil")
86
+ .select("id")
87
+ .eq("owner_id", user.id)
88
+ .single();
89
+
90
+ let result;
91
+ if (existingProfile) {
92
+ // Update existing profile
93
+ result = await supabase
94
+ .from("user_profil")
95
+ .update({
96
+ first_name,
97
+ last_name,
98
+ avatar_url,
99
+ bio,
100
+ phone,
101
+ company,
102
+ website,
103
+ location,
104
+ language,
105
+ timezone,
106
+ preferences,
107
+ })
108
+ .eq("owner_id", user.id)
109
+ .select()
110
+ .single();
111
+ } else {
112
+ // Create new profile
113
+ result = await supabase
114
+ .from("user_profil")
115
+ .insert({
116
+ owner_id: user.id,
117
+ first_name,
118
+ last_name,
119
+ avatar_url,
120
+ bio,
121
+ phone,
122
+ company,
123
+ website,
124
+ location,
125
+ language,
126
+ timezone,
127
+ preferences,
128
+ })
129
+ .select()
130
+ .single();
131
+ }
132
+
133
+ if (result.error) {
134
+ return NextResponse.json(
135
+ { error: "Database Error", message: result.error.message },
136
+ { status: 500 }
137
+ );
138
+ }
139
+
140
+ return NextResponse.json({ data: result.data });
141
+ } catch (error) {
142
+ console.error("Error updating profile:", error);
143
+ return NextResponse.json(
144
+ { error: "Internal Server Error", message: "Failed to update profile" },
145
+ { status: 500 }
146
+ );
147
+ }
148
+ }
149
+
150
+ /**
151
+ * PATCH /api/auth/profile
152
+ * Partially updates the user's profile
153
+ */
154
+ export async function PATCH(request: NextRequest) {
155
+ return PUT(request);
156
+ }
@@ -0,0 +1,31 @@
1
+ import { getSupabaseServerClient } from "@lastbrain/core/server";
2
+
3
+ const jsonResponse = (payload: unknown, status = 200) => {
4
+ return new Response(JSON.stringify(payload), {
5
+ headers: {
6
+ "content-type": "application/json"
7
+ },
8
+ status
9
+ });
10
+ };
11
+
12
+ export async function POST(request: Request) {
13
+ const supabase = await getSupabaseServerClient();
14
+ const body = await request.json();
15
+ const { email, password } = body;
16
+
17
+ if (!email || !password) {
18
+ return jsonResponse({ error: "Email et mot de passe requis." }, 400);
19
+ }
20
+
21
+ const { error, data } = await supabase.auth.signInWithPassword({
22
+ email,
23
+ password
24
+ });
25
+
26
+ if (error) {
27
+ return jsonResponse({ error: error.message }, 400);
28
+ }
29
+
30
+ return jsonResponse({ data });
31
+ }
@@ -0,0 +1,63 @@
1
+ import { supabaseBrowserClient } from "@lastbrain/core";
2
+
3
+ /**
4
+ * Upload a file to Supabase Storage and return proxy URL
5
+ */
6
+ export async function uploadFile(
7
+ bucket: string,
8
+ path: string,
9
+ file: Blob,
10
+ contentType: string
11
+ ): Promise<string> {
12
+ const { data, error } = await supabaseBrowserClient.storage
13
+ .from(bucket)
14
+ .upload(path, file, {
15
+ contentType,
16
+ upsert: true,
17
+ });
18
+
19
+ if (error) {
20
+ throw new Error(`Upload failed: ${error.message}`);
21
+ }
22
+
23
+ // Return proxy URL instead of Supabase public URL
24
+ return `/api/storage/${bucket}/${data.path}`;
25
+ }
26
+
27
+ /**
28
+ * Delete files from Supabase Storage
29
+ */
30
+ export async function deleteFiles(bucket: string, paths: string[]): Promise<void> {
31
+ const { error } = await supabaseBrowserClient.storage
32
+ .from(bucket)
33
+ .remove(paths);
34
+
35
+ if (error) {
36
+ throw new Error(`Delete failed: ${error.message}`);
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Delete files starting with a specific prefix (like user ID)
42
+ */
43
+ export async function deleteFilesWithPrefix(
44
+ bucket: string,
45
+ prefix: string
46
+ ): Promise<void> {
47
+ // List files with the prefix
48
+ const { data: files, error: listError } = await supabaseBrowserClient.storage
49
+ .from(bucket)
50
+ .list("", {
51
+ search: prefix,
52
+ });
53
+
54
+ if (listError) {
55
+ console.warn("Failed to list files for deletion:", listError);
56
+ return;
57
+ }
58
+
59
+ if (files && files.length > 0) {
60
+ const filePaths = files.map(file => file.name);
61
+ await deleteFiles(bucket, filePaths);
62
+ }
63
+ }
@@ -0,0 +1,137 @@
1
+ import type { ModuleBuildConfig } from "@lastbrain/core";
2
+
3
+ const authBuildConfig: ModuleBuildConfig = {
4
+ moduleName: "@lastbrain/module-auth",
5
+ pages: [
6
+ {
7
+ section: "public",
8
+ path: "/signin",
9
+ componentExport: "SignInPage",
10
+ },
11
+ {
12
+ section: "public",
13
+ path: "/signup",
14
+ componentExport: "SignUpPage",
15
+ },
16
+ {
17
+ section: "public",
18
+ path: "/reset-password",
19
+ componentExport: "ResetPassword",
20
+ },
21
+ {
22
+ section: "auth",
23
+ path: "/dashboard",
24
+ componentExport: "DashboardPage",
25
+ },
26
+ {
27
+ section: "auth",
28
+ path: "/reglage",
29
+ componentExport: "ReglagePage",
30
+ },
31
+ {
32
+ section: "auth",
33
+ path: "/profile",
34
+ componentExport: "ProfilePage",
35
+ },
36
+ {
37
+ section: "admin",
38
+ path: "/users",
39
+ componentExport: "AdminUsersPage",
40
+ },
41
+ ],
42
+ apis: [
43
+ {
44
+ method: "POST",
45
+ path: "/api/auth/signin",
46
+ handlerExport: "POST",
47
+ entryPoint: "api/public/signin",
48
+ authRequired: false,
49
+ },
50
+ {
51
+ method: "GET",
52
+ path: "/api/auth/profile",
53
+ handlerExport: "GET",
54
+ entryPoint: "api/auth/profile",
55
+ authRequired: true,
56
+ },
57
+ {
58
+ method: "PUT",
59
+ path: "/api/auth/profile",
60
+ handlerExport: "PUT",
61
+ entryPoint: "api/auth/profile",
62
+ authRequired: true,
63
+ },
64
+ {
65
+ method: "PATCH",
66
+ path: "/api/auth/profile",
67
+ handlerExport: "PATCH",
68
+ entryPoint: "api/auth/profile",
69
+ authRequired: true,
70
+ },
71
+ ],
72
+ migrations: {
73
+ enabled: true,
74
+ priority: 20,
75
+ path: "supabase/migrations",
76
+ files: ["001_auth_base.sql"],
77
+ },
78
+ menu: {
79
+ public: [
80
+ {
81
+ title: "Connexion",
82
+ description: "Connectez-vous à votre compte",
83
+ icon: "LogIn",
84
+ path: "/signin",
85
+ order: 1,
86
+ },
87
+ {
88
+ title: "Inscription",
89
+ description: "Créez votre compte",
90
+ icon: "UserPlus2",
91
+ path: "/signup",
92
+ order: 2,
93
+ },
94
+ ],
95
+ admin: [
96
+ {
97
+ title: "Gestion des utilisateurs",
98
+ description: "Gérez les utilisateurs de la plateforme",
99
+ icon: "Users2",
100
+ path: "/admin/users",
101
+ order: 1,
102
+ },
103
+ ],
104
+ account: [
105
+ {
106
+ title: "Tableau de bord",
107
+ description: "Accédez à votre tableau de bord",
108
+ icon: "LayoutDashboard",
109
+ path: "/auth/dashboard",
110
+ order: 1,
111
+ },
112
+ {
113
+ title: "Mon profil",
114
+ description: "Gérez vos informations personnelles",
115
+ icon: "User2",
116
+ path: "/auth/profile",
117
+ order: 1,
118
+ },
119
+ {
120
+ title: "Paramètres",
121
+ description: "Configurez votre compte",
122
+ icon: "Settings",
123
+ path: "/auth/reglage",
124
+ order: 2,
125
+ },
126
+ {
127
+ title: "Déconnexion",
128
+ description: "Se déconnecter",
129
+ icon: "LogOut",
130
+ path: "/signout",
131
+ order: 99,
132
+ },
133
+ ],
134
+ },
135
+ };
136
+
137
+ export default authBuildConfig;