@lastbrain/module-auth 2.0.27 → 2.0.31

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 (179) hide show
  1. package/README.md +55 -7
  2. package/dist/api/admin/signup-stats.d.ts.map +1 -1
  3. package/dist/api/admin/signup-stats.js +2 -1
  4. package/dist/api/admin/storage/usage.d.ts +18 -0
  5. package/dist/api/admin/storage/usage.d.ts.map +1 -0
  6. package/dist/api/admin/storage/usage.js +100 -0
  7. package/dist/api/admin/users/[id]/notifications.d.ts.map +1 -1
  8. package/dist/api/admin/users/[id]/notifications.js +3 -2
  9. package/dist/api/admin/users/[id].d.ts.map +1 -1
  10. package/dist/api/admin/users/[id].js +3 -2
  11. package/dist/api/admin/users/reactivate/[id].d.ts +16 -0
  12. package/dist/api/admin/users/reactivate/[id].d.ts.map +1 -0
  13. package/dist/api/admin/users/reactivate/[id].js +59 -0
  14. package/dist/api/admin/users/suspend/[id].d.ts +16 -0
  15. package/dist/api/admin/users/suspend/[id].d.ts.map +1 -0
  16. package/dist/api/admin/users/suspend/[id].js +59 -0
  17. package/dist/api/admin/users-by-source.d.ts.map +1 -1
  18. package/dist/api/admin/users-by-source.js +2 -1
  19. package/dist/api/admin/users.d.ts.map +1 -1
  20. package/dist/api/admin/users.js +53 -2
  21. package/dist/api/auth/account/email-change.d.ts +7 -0
  22. package/dist/api/auth/account/email-change.d.ts.map +1 -0
  23. package/dist/api/auth/account/email-change.js +39 -0
  24. package/dist/api/auth/account/reset-password.d.ts +7 -0
  25. package/dist/api/auth/account/reset-password.d.ts.map +1 -0
  26. package/dist/api/auth/account/reset-password.js +36 -0
  27. package/dist/api/auth/check-username.d.ts +9 -0
  28. package/dist/api/auth/check-username.d.ts.map +1 -0
  29. package/dist/api/auth/check-username.js +35 -0
  30. package/dist/api/auth/establish-session.d.ts +2 -0
  31. package/dist/api/auth/establish-session.d.ts.map +1 -0
  32. package/dist/api/auth/establish-session.js +23 -0
  33. package/dist/api/auth/me.d.ts +4 -4
  34. package/dist/api/auth/me.d.ts.map +1 -1
  35. package/dist/api/auth/me.js +28 -6
  36. package/dist/api/auth/profile.d.ts.map +1 -1
  37. package/dist/api/auth/profile.js +6 -3
  38. package/dist/api/auth/storage/recalculate.d.ts +15 -0
  39. package/dist/api/auth/storage/recalculate.d.ts.map +1 -0
  40. package/dist/api/auth/storage/recalculate.js +68 -0
  41. package/dist/api/auth/storage/usage.d.ts +10 -0
  42. package/dist/api/auth/storage/usage.d.ts.map +1 -0
  43. package/dist/api/auth/storage/usage.js +86 -0
  44. package/dist/api/public/add-welcome-bonus.d.ts +16 -0
  45. package/dist/api/public/add-welcome-bonus.d.ts.map +1 -0
  46. package/dist/api/public/add-welcome-bonus.js +177 -0
  47. package/dist/api/public/callback.d.ts +3 -0
  48. package/dist/api/public/callback.d.ts.map +1 -0
  49. package/dist/api/public/callback.js +197 -0
  50. package/dist/api/public/reset-password.d.ts +3 -0
  51. package/dist/api/public/reset-password.d.ts.map +1 -0
  52. package/dist/api/public/reset-password.js +43 -0
  53. package/dist/api/public/set-session.d.ts +7 -0
  54. package/dist/api/public/set-session.d.ts.map +1 -0
  55. package/dist/api/public/set-session.js +55 -0
  56. package/dist/api/public/signin.d.ts.map +1 -1
  57. package/dist/api/public/signin.js +31 -0
  58. package/dist/api/public/signup.d.ts.map +1 -1
  59. package/dist/api/public/signup.js +38 -27
  60. package/dist/api/public/webhook/storage-addon.d.ts +9 -0
  61. package/dist/api/public/webhook/storage-addon.d.ts.map +1 -0
  62. package/dist/api/public/webhook/storage-addon.js +155 -0
  63. package/dist/api/storage.js +2 -2
  64. package/dist/auth.build.config.d.ts.map +1 -1
  65. package/dist/auth.build.config.js +126 -11
  66. package/dist/components/AccountButton.d.ts.map +1 -1
  67. package/dist/components/AccountButton.js +54 -28
  68. package/dist/components/Doc.d.ts.map +1 -1
  69. package/dist/components/Doc.js +1 -1
  70. package/dist/components/HasProfil.d.ts +4 -0
  71. package/dist/components/HasProfil.d.ts.map +1 -0
  72. package/dist/components/HasProfil.js +39 -0
  73. package/dist/components/auth/dashboard.d.ts +1 -1
  74. package/dist/components/auth/dashboard.d.ts.map +1 -1
  75. package/dist/components/auth/dashboard.js +34 -7
  76. package/dist/index.d.ts +2 -0
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +2 -0
  79. package/dist/lib/app-branding-data.d.ts +22 -0
  80. package/dist/lib/app-branding-data.d.ts.map +1 -0
  81. package/dist/lib/app-branding-data.js +49 -0
  82. package/dist/lib/auth-email-service.d.ts +57 -0
  83. package/dist/lib/auth-email-service.d.ts.map +1 -0
  84. package/dist/lib/auth-email-service.js +382 -0
  85. package/dist/lib/auth-email-templates.d.ts +2 -0
  86. package/dist/lib/auth-email-templates.d.ts.map +1 -0
  87. package/dist/lib/auth-email-templates.js +1 -0
  88. package/dist/lib/site-url.d.ts +3 -0
  89. package/dist/lib/site-url.d.ts.map +1 -0
  90. package/dist/lib/site-url.js +11 -0
  91. package/dist/sitemap/manifest.d.ts +9 -0
  92. package/dist/sitemap/manifest.d.ts.map +1 -0
  93. package/dist/sitemap/manifest.js +14 -0
  94. package/dist/web/admin/signup-stats.js +3 -3
  95. package/dist/web/admin/user-detail.d.ts.map +1 -1
  96. package/dist/web/admin/user-detail.js +135 -14
  97. package/dist/web/admin/users-by-signup-source.js +2 -2
  98. package/dist/web/admin/users.d.ts.map +1 -1
  99. package/dist/web/admin/users.js +26 -7
  100. package/dist/web/auth/folder.d.ts.map +1 -1
  101. package/dist/web/auth/folder.js +4 -3
  102. package/dist/web/auth/profile.d.ts.map +1 -1
  103. package/dist/web/auth/profile.js +132 -13
  104. package/dist/web/auth/reglage.d.ts.map +1 -1
  105. package/dist/web/auth/reglage.js +15 -8
  106. package/dist/web/public/ResetPassword.d.ts.map +1 -1
  107. package/dist/web/public/ResetPassword.js +172 -2
  108. package/dist/web/public/SignInPage.d.ts.map +1 -1
  109. package/dist/web/public/SignInPage.js +39 -3
  110. package/dist/web/public/SignUpPage.d.ts.map +1 -1
  111. package/dist/web/public/SignUpPage.js +7 -2
  112. package/dist/web/public/auth-code-error.d.ts +2 -0
  113. package/dist/web/public/auth-code-error.d.ts.map +1 -0
  114. package/dist/web/public/auth-code-error.js +14 -0
  115. package/dist/web/public/confirm.d.ts +2 -0
  116. package/dist/web/public/confirm.d.ts.map +1 -0
  117. package/dist/web/public/confirm.js +157 -0
  118. package/package.json +10 -5
  119. package/src/api/admin/signup-stats.ts +2 -1
  120. package/src/api/admin/storage/usage.ts +141 -0
  121. package/src/api/admin/users/[id]/notifications.ts +3 -2
  122. package/src/api/admin/users/[id].ts +3 -2
  123. package/src/api/admin/users/reactivate/[id].ts +88 -0
  124. package/src/api/admin/users/suspend/[id].ts +85 -0
  125. package/src/api/admin/users-by-source.ts +2 -1
  126. package/src/api/admin/users.ts +59 -2
  127. package/src/api/auth/account/email-change.ts +54 -0
  128. package/src/api/auth/account/reset-password.ts +47 -0
  129. package/src/api/auth/check-username.ts +52 -0
  130. package/src/api/auth/establish-session.ts +32 -0
  131. package/src/api/auth/me.ts +29 -7
  132. package/src/api/auth/profile.ts +6 -2
  133. package/src/api/auth/storage/recalculate.ts +108 -0
  134. package/src/api/auth/storage/usage.ts +113 -0
  135. package/src/api/public/add-welcome-bonus.ts +229 -0
  136. package/src/api/public/callback.ts +307 -0
  137. package/src/api/public/reset-password.ts +52 -0
  138. package/src/api/public/set-session.ts +73 -0
  139. package/src/api/public/signin.ts +36 -0
  140. package/src/api/public/signup.ts +44 -37
  141. package/src/api/public/webhook/storage-addon.ts +267 -0
  142. package/src/api/storage.ts +2 -2
  143. package/src/auth.build.config.ts +126 -11
  144. package/src/components/AccountButton.tsx +114 -90
  145. package/src/components/Doc.tsx +47 -9
  146. package/src/components/HasProfil.tsx +63 -0
  147. package/src/components/auth/dashboard.tsx +54 -13
  148. package/src/i18n/en.json +76 -8
  149. package/src/i18n/es.json +330 -0
  150. package/src/i18n/fr.json +74 -8
  151. package/src/index.ts +2 -0
  152. package/src/lib/app-branding-data.ts +90 -0
  153. package/src/lib/auth-email-service.ts +508 -0
  154. package/src/lib/auth-email-templates.ts +5 -0
  155. package/src/lib/site-url.ts +17 -0
  156. package/src/sitemap/manifest.ts +26 -0
  157. package/src/web/admin/signup-stats.tsx +3 -3
  158. package/src/web/admin/user-detail.tsx +314 -15
  159. package/src/web/admin/users-by-signup-source.tsx +2 -2
  160. package/src/web/admin/users.tsx +50 -14
  161. package/src/web/auth/folder.tsx +23 -5
  162. package/src/web/auth/profile.tsx +227 -13
  163. package/src/web/auth/reglage.tsx +55 -24
  164. package/src/web/public/ResetPassword.tsx +301 -1
  165. package/src/web/public/SignInPage.tsx +43 -3
  166. package/src/web/public/SignUpPage.tsx +14 -5
  167. package/src/web/public/auth-code-error.tsx +49 -0
  168. package/src/web/public/confirm.tsx +195 -0
  169. package/supabase/migrations/20251112000001_auto_profile_and_admin_view.sql +3 -1
  170. package/supabase/migrations/20251127100000_rename_body_to_message.sql +8 -3
  171. package/supabase/migrations/20260120150001_add_user_storage.sql +105 -0
  172. package/supabase/migrations/20260122131200_add_global_addons_system.sql +305 -0
  173. package/supabase/migrations/20260123100000_enable_vector_extension.sql +9 -0
  174. package/supabase/migrations/20260123140000_module_auth_fix_get_user_limits_null.sql +93 -0
  175. package/supabase/migrations/20260123145000_module_auth_fix_circular_storage_base.sql +89 -0
  176. package/supabase/migrations/20260129400000_add_username_to_user_profil.sql +33 -0
  177. package/dist/web/auth/dashboard.d.ts +0 -2
  178. package/dist/web/auth/dashboard.d.ts.map +0 -1
  179. package/dist/web/auth/dashboard.js +0 -48
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 📦 Module auth
2
2
 
3
- > @lastbrain/module-auth
3
+ > Module @lastbrain/module-auth
4
4
 
5
5
  ## 📋 Informations
6
6
 
@@ -15,10 +15,11 @@
15
15
  - **GET** `/signin` - SignInPage
16
16
  - **GET** `/signup` - SignUpPage
17
17
  - **GET** `/reset-password` - ResetPassword
18
+ - **GET** `/confirm` - ConfirmPage
19
+ - **GET** `/auth-code-error` - AuthCodeErrorPage
18
20
 
19
21
  ### Pages Protégées (Auth)
20
22
 
21
- - **GET** `/dashboard` - DashboardPage
22
23
  - **GET** `/folder` - FolderPage
23
24
  - **GET** `/reglage` - ReglagePage
24
25
  - **GET** `/profile` - ProfilePage
@@ -31,23 +32,47 @@
31
32
 
32
33
  ### `/api/auth/signin`
33
34
 
34
- **Méthodes supportées**: GET, POST, PUT, DELETE
35
+ **Méthodes supportées**: POST
35
36
 
36
37
  ### `/api/auth/signup`
37
38
 
38
- **Méthodes supportées**: GET, POST, PUT, DELETE
39
+ **Méthodes supportées**: POST
40
+
41
+ ### `/api/public/set-session`
42
+
43
+ **Méthodes supportées**: POST
44
+
45
+ ### `/api/public/add-welcome-bonus`
46
+
47
+ **Méthodes supportées**: POST
48
+
49
+ ### `/api/public/reset-password`
50
+
51
+ **Méthodes supportées**: POST
52
+
53
+ ### `/api/public/callback`
54
+
55
+ **Méthodes supportées**: GET
39
56
 
40
57
  ### `/api/auth/profile`
41
58
 
42
- **Méthodes supportées**: GET, POST, PUT, DELETE
59
+ **Méthodes supportées**: GET, PUT, PATCH
43
60
 
44
61
  ### `/api/auth/me`
45
62
 
46
- **Méthodes supportées**: GET, POST, PUT, DELETE
63
+ **Méthodes supportées**: GET
64
+
65
+ ### `/api/auth/account/email-change`
66
+
67
+ **Méthodes supportées**: POST
68
+
69
+ ### `/api/auth/account/reset-password`
70
+
71
+ **Méthodes supportées**: POST
47
72
 
48
73
  ### `/api/admin/users`
49
74
 
50
- **Méthodes supportées**: GET, POST, PUT, DELETE
75
+ **Méthodes supportées**: GET
51
76
 
52
77
  ## 🗄️ Base de Données
53
78
 
@@ -83,6 +108,26 @@
83
108
  />
84
109
  ```
85
110
 
111
+ #### `global_addons`
112
+
113
+ ```tsx
114
+ <TableStructure
115
+ tableName="global_addons"
116
+ title="global_addons"
117
+ description="Table global_addons du module auth"
118
+ />
119
+ ```
120
+
121
+ #### `user_global_addons`
122
+
123
+ ```tsx
124
+ <TableStructure
125
+ tableName="user_global_addons"
126
+ title="user_global_addons"
127
+ description="Table user_global_addons du module auth"
128
+ />
129
+ ```
130
+
86
131
  ### Migrations
87
132
 
88
133
  - `20251112000000_user_init.sql`
@@ -90,6 +135,9 @@
90
135
  - `20251112000002_sync_avatars.sql`
91
136
  - `20251124000001_add_get_admin_user_details.sql`
92
137
  - `20251127100000_rename_body_to_message.sql`
138
+ - `20260120150001_add_user_storage.sql`
139
+ - `20260122131200_add_global_addons_system.sql`
140
+ - `20260123100000_enable_vector_extension.sql`
93
141
 
94
142
  ## 📦 Installation
95
143
 
@@ -1 +1 @@
1
- {"version":3,"file":"signup-stats.d.ts","sourceRoot":"","sources":["../../../src/api/admin/signup-stats.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED,wBAAsB,GAAG,CAAC,QAAQ,EAAE,WAAW;;;;IAuC9C"}
1
+ {"version":3,"file":"signup-stats.d.ts","sourceRoot":"","sources":["../../../src/api/admin/signup-stats.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED,wBAAsB,GAAG,CAAC,QAAQ,EAAE,WAAW;;;;IAuC9C"}
@@ -1,3 +1,4 @@
1
+ import { logger } from "@lastbrain/core";
1
2
  import { getSupabaseServiceClient } from "@lastbrain/core/server";
2
3
  import { NextResponse } from "next/server";
3
4
  export async function GET(_request) {
@@ -27,7 +28,7 @@ export async function GET(_request) {
27
28
  return NextResponse.json({ data: stats }, { status: 200 });
28
29
  }
29
30
  catch (error) {
30
- console.error("Error fetching signup stats:", error);
31
+ logger.error("Error fetching signup stats:", error);
31
32
  return NextResponse.json({ error: "Erreur interne du serveur" }, { status: 500 });
32
33
  }
33
34
  }
@@ -0,0 +1,18 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ import { StorageUsageData } from "@lastbrain/core";
3
+ /**
4
+ * GET /api/admin/storage/usage
5
+ * Admin route: superadmin can query any user's storage usage
6
+ * Query params:
7
+ * - ownerId: required, user ID to check
8
+ * - forceRefresh: optional, bypass cache
9
+ */
10
+ export declare function GET(request: NextRequest): Promise<NextResponse<{
11
+ success: boolean;
12
+ error: string;
13
+ }> | NextResponse<{
14
+ success: boolean;
15
+ data: StorageUsageData;
16
+ fromCache: boolean;
17
+ }>>;
18
+ //# sourceMappingURL=usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../../src/api/admin/storage/usage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAmB,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAmBpE;;;;;;GAMG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;;;;IAgH7C"}
@@ -0,0 +1,100 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getSupabaseServerClient } from "@lastbrain/core/server";
3
+ import { getStorageUsage } from "@lastbrain/core";
4
+ // Cache simple pour éviter de recalculer trop souvent
5
+ const storageCache = new Map();
6
+ const CACHE_TTL = 30 * 1000; // 30 secondes
7
+ // Nettoyer les entrées expirées du cache
8
+ function cleanExpiredCache() {
9
+ const now = Date.now();
10
+ for (const [key, value] of storageCache.entries()) {
11
+ if (now - value.timestamp > CACHE_TTL) {
12
+ storageCache.delete(key);
13
+ }
14
+ }
15
+ }
16
+ /**
17
+ * GET /api/admin/storage/usage
18
+ * Admin route: superadmin can query any user's storage usage
19
+ * Query params:
20
+ * - ownerId: required, user ID to check
21
+ * - forceRefresh: optional, bypass cache
22
+ */
23
+ export async function GET(request) {
24
+ try {
25
+ const supabase = await getSupabaseServerClient();
26
+ // Vérifier l'authentification
27
+ const { data: { user }, error: authError, } = await supabase.auth.getUser();
28
+ if (authError || !user) {
29
+ return NextResponse.json({ success: false, error: "Non authentifié" }, { status: 401 });
30
+ }
31
+ // Vérifier si l'utilisateur est superadmin
32
+ const { data: isSuperAdmin, error: adminCheckError } = await supabase.rpc("is_superadmin", { user_id: user.id });
33
+ if (adminCheckError || !isSuperAdmin) {
34
+ return NextResponse.json({
35
+ success: false,
36
+ error: "Accès non autorisé - réservé aux superadmins",
37
+ }, { status: 403 });
38
+ }
39
+ // Récupérer l'ownerId depuis les paramètres (requis pour la route admin)
40
+ const { searchParams } = new URL(request.url);
41
+ const ownerId = searchParams.get("ownerId");
42
+ const forceRefresh = searchParams.get("forceRefresh") === "true";
43
+ if (!ownerId) {
44
+ return NextResponse.json({ success: false, error: "ownerId est requis" }, { status: 400 });
45
+ }
46
+ // Nettoyer le cache avant utilisation
47
+ cleanExpiredCache();
48
+ // Vérifier si on a des données en cache (sauf si forceRefresh)
49
+ const cacheKey = `storage-${ownerId}`;
50
+ let shouldUseCache = false;
51
+ if (!forceRefresh) {
52
+ const cachedEntry = storageCache.get(cacheKey);
53
+ const now = Date.now();
54
+ if (cachedEntry && now - cachedEntry.timestamp < CACHE_TTL) {
55
+ // Vérifier d'abord si l'allocation de stockage a changé
56
+ const { data: userProfile } = await supabase
57
+ .from("user_profil")
58
+ .select("stockage")
59
+ .eq("owner_id", ownerId)
60
+ .single();
61
+ if (userProfile &&
62
+ userProfile.stockage === cachedEntry.data.allocatedGb) {
63
+ shouldUseCache = true;
64
+ }
65
+ }
66
+ }
67
+ // Utiliser le cache si valide
68
+ if (shouldUseCache) {
69
+ const cached = storageCache.get(cacheKey);
70
+ if (cached) {
71
+ return NextResponse.json({
72
+ success: true,
73
+ data: cached.data,
74
+ fromCache: true,
75
+ });
76
+ }
77
+ }
78
+ // Calculer les données de stockage
79
+ const storageData = await getStorageUsage(supabase, ownerId);
80
+ // Mettre en cache
81
+ storageCache.set(cacheKey, {
82
+ data: storageData,
83
+ timestamp: Date.now(),
84
+ });
85
+ return NextResponse.json({
86
+ success: true,
87
+ data: storageData,
88
+ fromCache: false,
89
+ });
90
+ }
91
+ catch (error) {
92
+ console.error("[Admin Storage Usage] Error:", error);
93
+ return NextResponse.json({
94
+ success: false,
95
+ error: error instanceof Error
96
+ ? error.message
97
+ : "Erreur lors du calcul du stockage",
98
+ }, { status: 500 });
99
+ }
100
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../../../../src/api/admin/users/[id]/notifications.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGxD;;;GAGG;AACH,wBAAsB,IAAI,CACxB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE;;;;;IA0D7C"}
1
+ {"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../../../../src/api/admin/users/[id]/notifications.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIxD;;;GAGG;AACH,wBAAsB,IAAI,CACxB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE;;;;;IA0D7C"}
@@ -1,5 +1,6 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { getSupabaseServerClient } from "@lastbrain/core/server";
3
+ import { logger } from "@lastbrain/core";
3
4
  /**
4
5
  * POST /api/admin/users/[id]/notifications
5
6
  * Send a notification to a specific user (superadmin only)
@@ -29,7 +30,7 @@ export async function POST(request, context) {
29
30
  .select()
30
31
  .single();
31
32
  if (error) {
32
- console.error("Error creating notification:", error);
33
+ logger.error("Error creating notification:", error);
33
34
  return NextResponse.json({ error: "Database Error", message: error.message }, { status: 500 });
34
35
  }
35
36
  return NextResponse.json({
@@ -38,7 +39,7 @@ export async function POST(request, context) {
38
39
  });
39
40
  }
40
41
  catch (error) {
41
- console.error("Error in send notification endpoint:", error);
42
+ logger.error("Error in send notification endpoint:", error);
42
43
  return NextResponse.json({
43
44
  error: "Internal Server Error",
44
45
  message: "Failed to send notification",
@@ -1 +1 @@
1
- {"version":3,"file":"[id].d.ts","sourceRoot":"","sources":["../../../../src/api/admin/users/[id].ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGxD;;;GAGG;AACH,wBAAsB,GAAG,CACvB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,8BA0C7C"}
1
+ {"version":3,"file":"[id].d.ts","sourceRoot":"","sources":["../../../../src/api/admin/users/[id].ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIxD;;;GAGG;AACH,wBAAsB,GAAG,CACvB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,8BA0C7C"}
@@ -1,5 +1,6 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { getSupabaseServerClient } from "@lastbrain/core/server";
3
+ import { logger } from "@lastbrain/core";
3
4
  /**
4
5
  * GET /api/admin/users/[id]
5
6
  * Returns user details by ID (superadmin only)
@@ -14,7 +15,7 @@ export async function GET(request, context) {
14
15
  // Utiliser la fonction RPC pour récupérer les détails de l'utilisateur
15
16
  const { data: userDetails, error: userError } = await supabase.rpc("get_admin_user_details", { user_id: userId });
16
17
  if (userError) {
17
- console.error("Error fetching user details:", userError);
18
+ logger.error("Error fetching user details:", userError);
18
19
  return NextResponse.json({ error: "Database Error", message: userError.message }, { status: 500 });
19
20
  }
20
21
  if (!userDetails) {
@@ -23,7 +24,7 @@ export async function GET(request, context) {
23
24
  return NextResponse.json(userDetails);
24
25
  }
25
26
  catch (error) {
26
- console.error("Error in admin user details endpoint:", error);
27
+ logger.error("Error in admin user details endpoint:", error);
27
28
  return NextResponse.json({
28
29
  error: "Internal Server Error",
29
30
  message: "Failed to fetch user details",
@@ -0,0 +1,16 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ /**
3
+ * POST /api/admin/users/reactivate/[id]
4
+ * Attempt to reactivate a user by clearing the suspended flag in app metadata (service role required)
5
+ */
6
+ export declare function POST(request: NextRequest, context: {
7
+ params: Promise<{
8
+ id: string;
9
+ }>;
10
+ }): Promise<NextResponse<{
11
+ error: string;
12
+ }> | NextResponse<{
13
+ success: boolean;
14
+ user: any;
15
+ }>>;
16
+ //# sourceMappingURL=%5Bid%5D.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"[id].d.ts","sourceRoot":"","sources":["../../../../../src/api/admin/users/reactivate/[id].ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIxD;;;GAGG;AACH,wBAAsB,IAAI,CACxB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE;;;;;IA6E7C"}
@@ -0,0 +1,59 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getSupabaseServiceClient } from "@lastbrain/core/server";
3
+ import { logger } from "@lastbrain/core";
4
+ /**
5
+ * POST /api/admin/users/reactivate/[id]
6
+ * Attempt to reactivate a user by clearing the suspended flag in app metadata (service role required)
7
+ */
8
+ export async function POST(request, context) {
9
+ try {
10
+ const supabase = await getSupabaseServiceClient();
11
+ const { id: userId } = await context.params;
12
+ if (!userId) {
13
+ return NextResponse.json({ error: "User ID is required" }, { status: 400 });
14
+ }
15
+ // Try using the Admin auth API if available
16
+ try {
17
+ // @ts-expect-error - supabase-js may expose auth.admin.updateUserById
18
+ if (supabase.auth?.admin?.updateUserById) {
19
+ // set app_metadata.suspended = false
20
+ const { data, error } = await supabase.auth.admin.updateUserById(userId, {
21
+ app_metadata: { suspended: false },
22
+ });
23
+ if (error) {
24
+ logger.error("Error reactivating user (admin.updateUserById):", error);
25
+ return NextResponse.json({ error: "Database Error", message: error.message }, { status: 500 });
26
+ }
27
+ return NextResponse.json({ success: true, user: data });
28
+ }
29
+ }
30
+ catch (err) {
31
+ logger.debug("auth.admin.updateUserById not available or failed:", err);
32
+ }
33
+ // Fallback: try to update auth.users via SQL (may require service role privileges)
34
+ try {
35
+ const update = {
36
+ raw_app_meta_data: { suspended: false },
37
+ };
38
+ const { data, error } = await supabase
39
+ .from("users")
40
+ .update(update)
41
+ .eq("id", userId)
42
+ .select()
43
+ .single();
44
+ if (error) {
45
+ logger.error("Fallback reactivate user failed:", error);
46
+ return NextResponse.json({ error: "Database Error", message: error.message }, { status: 500 });
47
+ }
48
+ return NextResponse.json({ success: true, user: data });
49
+ }
50
+ catch (err) {
51
+ logger.error("Final reactivate fallback error:", err);
52
+ return NextResponse.json({ error: "Internal Server Error", message: String(err) }, { status: 500 });
53
+ }
54
+ }
55
+ catch (error) {
56
+ logger.error("Error in reactivate user endpoint:", error);
57
+ return NextResponse.json({ error: "Internal Server Error", message: "Failed to reactivate user" }, { status: 500 });
58
+ }
59
+ }
@@ -0,0 +1,16 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ /**
3
+ * POST /api/admin/users/suspend/[id]
4
+ * Attempt to suspend a user by setting a suspended flag in app metadata (service role required)
5
+ */
6
+ export declare function POST(request: NextRequest, context: {
7
+ params: Promise<{
8
+ id: string;
9
+ }>;
10
+ }): Promise<NextResponse<{
11
+ error: string;
12
+ }> | NextResponse<{
13
+ success: boolean;
14
+ user: any;
15
+ }>>;
16
+ //# sourceMappingURL=%5Bid%5D.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"[id].d.ts","sourceRoot":"","sources":["../../../../../src/api/admin/users/suspend/[id].ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIxD;;;GAGG;AACH,wBAAsB,IAAI,CACxB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE;;;;;IA0E7C"}
@@ -0,0 +1,59 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getSupabaseServiceClient } from "@lastbrain/core/server";
3
+ import { logger } from "@lastbrain/core";
4
+ /**
5
+ * POST /api/admin/users/suspend/[id]
6
+ * Attempt to suspend a user by setting a suspended flag in app metadata (service role required)
7
+ */
8
+ export async function POST(request, context) {
9
+ try {
10
+ const supabase = await getSupabaseServiceClient();
11
+ const { id: userId } = await context.params;
12
+ if (!userId) {
13
+ return NextResponse.json({ error: "User ID is required" }, { status: 400 });
14
+ }
15
+ // Try using the Admin auth API if available
16
+ try {
17
+ // @ts-expect-error - supabase-js may expose auth.admin.updateUserById
18
+ if (supabase.auth?.admin?.updateUserById) {
19
+ // set app_metadata.suspended = true
20
+ const { data, error } = await supabase.auth.admin.updateUserById(userId, {
21
+ app_metadata: { suspended: true },
22
+ });
23
+ if (error) {
24
+ logger.error("Error suspending user (admin.updateUserById):", error);
25
+ return NextResponse.json({ error: "Database Error", message: error.message }, { status: 500 });
26
+ }
27
+ return NextResponse.json({ success: true, user: data });
28
+ }
29
+ }
30
+ catch (err) {
31
+ logger.debug("auth.admin.updateUserById not available or failed:", err);
32
+ }
33
+ // Fallback: try to update auth.users via SQL (may require service role privileges)
34
+ try {
35
+ const update = {
36
+ raw_app_meta_data: { suspended: true },
37
+ };
38
+ const { data, error } = await supabase
39
+ .from("users")
40
+ .update(update)
41
+ .eq("id", userId)
42
+ .select()
43
+ .single();
44
+ if (error) {
45
+ logger.error("Fallback suspend user failed:", error);
46
+ return NextResponse.json({ error: "Database Error", message: error.message }, { status: 500 });
47
+ }
48
+ return NextResponse.json({ success: true, user: data });
49
+ }
50
+ catch (err) {
51
+ logger.error("Final suspend fallback error:", err);
52
+ return NextResponse.json({ error: "Internal Server Error", message: String(err) }, { status: 500 });
53
+ }
54
+ }
55
+ catch (error) {
56
+ logger.error("Error in suspend user endpoint:", error);
57
+ return NextResponse.json({ error: "Internal Server Error", message: "Failed to suspend user" }, { status: 500 });
58
+ }
59
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"users-by-source.d.ts","sourceRoot":"","sources":["../../../src/api/admin/users-by-source.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;;;;;;;IA0E7C"}
1
+ {"version":3,"file":"users-by-source.d.ts","sourceRoot":"","sources":["../../../src/api/admin/users-by-source.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExD,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;;;;;;;IA0E7C"}
@@ -1,3 +1,4 @@
1
+ import { logger } from "@lastbrain/core";
1
2
  import { getSupabaseServiceClient } from "@lastbrain/core/server";
2
3
  import { NextResponse } from "next/server";
3
4
  export async function GET(request) {
@@ -50,7 +51,7 @@ export async function GET(request) {
50
51
  }, { status: 200 });
51
52
  }
52
53
  catch (error) {
53
- console.error("Error fetching users by signup source:", error);
54
+ logger.error("Error fetching users by signup source:", error);
54
55
  return NextResponse.json({ error: "Erreur interne du serveur" }, { status: 500 });
55
56
  }
56
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/api/admin/users.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGxD;;;;;GAKG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW,8BA8C7C"}
1
+ {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/api/admin/users.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIxD;;;;;GAKG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW,8BAsG7C"}
@@ -1,5 +1,6 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { getSupabaseServerClient } from "@lastbrain/core/server";
3
+ import { logger } from "@lastbrain/core";
3
4
  /**
4
5
  * GET /api/admin/users
5
6
  * Returns all users (superadmin only)
@@ -22,17 +23,67 @@ export async function GET(request) {
22
23
  search_term: search,
23
24
  });
24
25
  if (usersError) {
25
- console.error("Error fetching users:", usersError);
26
+ logger.error("Error fetching users:", usersError);
26
27
  return NextResponse.json({ error: "Database Error", message: usersError.message }, { status: 500 });
27
28
  }
28
29
  // The RPC function returns the complete response with data and pagination
30
+ // Ensure each user has a normalized `app_metadata` field derived from
31
+ // `raw_app_meta_data` (RPCs may differ in the exact shape returned).
32
+ if (result && Array.isArray(result.data)) {
33
+ try {
34
+ const mapped = result.data.map((u) => {
35
+ const out = { ...u };
36
+ // Try multiple possible locations for app metadata returned by different RPCs
37
+ const rawCandidate = out.raw_app_meta_data ??
38
+ out.metadata ??
39
+ out.raw_user_meta_data ??
40
+ out.app_metadata ??
41
+ null;
42
+ // rawCandidate can be an object or a JSON string
43
+ let parsedRaw = rawCandidate;
44
+ if (typeof rawCandidate === "string") {
45
+ try {
46
+ parsedRaw = JSON.parse(rawCandidate);
47
+ }
48
+ catch (e) {
49
+ parsedRaw = rawCandidate;
50
+ }
51
+ }
52
+ // If parsedRaw contains an `app_metadata` object, prefer it.
53
+ // Otherwise, if parsedRaw itself looks like metadata (contains suspended or provider keys), use it.
54
+ let derived = null;
55
+ if (parsedRaw && typeof parsedRaw === "object") {
56
+ if (parsedRaw.app_metadata &&
57
+ typeof parsedRaw.app_metadata === "object") {
58
+ derived = parsedRaw.app_metadata;
59
+ }
60
+ else {
61
+ // parsedRaw may already be the app metadata
62
+ derived = parsedRaw;
63
+ }
64
+ }
65
+ // Ensure out.app_metadata is an object when possible
66
+ if (derived && typeof derived === "object") {
67
+ out.app_metadata = { ...(out.app_metadata || {}), ...derived };
68
+ }
69
+ else if (out.app_metadata == null) {
70
+ out.app_metadata = null;
71
+ }
72
+ return out;
73
+ });
74
+ result.data = mapped;
75
+ }
76
+ catch (e) {
77
+ logger.debug("Failed to normalize app_metadata for users list:", e);
78
+ }
79
+ }
29
80
  return NextResponse.json(result || {
30
81
  data: [],
31
82
  pagination: { page, per_page: perPage, total: 0, total_pages: 0 },
32
83
  });
33
84
  }
34
85
  catch (error) {
35
- console.error("Error in admin users endpoint:", error);
86
+ logger.error("Error in admin users endpoint:", error);
36
87
  return NextResponse.json({
37
88
  error: "Internal Server Error",
38
89
  message: "Failed to fetch users",
@@ -0,0 +1,7 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ export declare function POST(request: NextRequest): Promise<NextResponse<{
3
+ error: string;
4
+ }> | NextResponse<{
5
+ message: string;
6
+ }>>;
7
+ //# sourceMappingURL=email-change.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-change.d.ts","sourceRoot":"","sources":["../../../../src/api/auth/account/email-change.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAaxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;IAwC9C"}
@@ -0,0 +1,39 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getSupabaseServerClient } from "@lastbrain/core/server";
3
+ import { sendEmailChangeConfirmation } from "../../../lib/auth-email-service";
4
+ import { logger } from "@lastbrain/core";
5
+ function extractLocale(request) {
6
+ const lang = request.headers
7
+ .get("accept-language")
8
+ ?.split(",")?.[0]
9
+ ?.split("-")?.[0];
10
+ return lang === "fr" || lang === "en" ? lang : undefined;
11
+ }
12
+ export async function POST(request) {
13
+ try {
14
+ const locale = extractLocale(request);
15
+ const supabase = await getSupabaseServerClient();
16
+ const { data: { user }, error: authError, } = await supabase.auth.getUser();
17
+ if (authError || !user) {
18
+ return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
19
+ }
20
+ const body = await request.json();
21
+ const newEmail = body?.newEmail;
22
+ if (!newEmail) {
23
+ return NextResponse.json({ error: "Nouvel email requis" }, { status: 400 });
24
+ }
25
+ await sendEmailChangeConfirmation({
26
+ email: user.email || "",
27
+ newEmail,
28
+ displayName: user.user_metadata?.full_name,
29
+ locale,
30
+ ownerId: user.id,
31
+ redirectTo: `${request.nextUrl.origin}/api/public/callback?next=/confirm`,
32
+ });
33
+ return NextResponse.json({ message: "Lien de confirmation envoyé" });
34
+ }
35
+ catch (error) {
36
+ logger.error("email-change error:", error);
37
+ return NextResponse.json({ error: "Impossible d'envoyer le lien de confirmation" }, { status: 500 });
38
+ }
39
+ }
@@ -0,0 +1,7 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ export declare function POST(request: NextRequest): Promise<NextResponse<{
3
+ error: string;
4
+ }> | NextResponse<{
5
+ message: string;
6
+ }>>;
7
+ //# sourceMappingURL=reset-password.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reset-password.d.ts","sourceRoot":"","sources":["../../../../src/api/auth/account/reset-password.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAgBxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;IA8B9C"}