@lobehub/chat 1.122.4 → 1.122.5

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.122.5](https://github.com/lobehub/lobe-chat/compare/v1.122.4...v1.122.5)
6
+
7
+ <sup>Released on **2025-09-04**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: Make LobeNextAuthDBAdapter Edge Compatible.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Code refactoring
19
+
20
+ - **misc**: Make LobeNextAuthDBAdapter Edge Compatible, closes [#8188](https://github.com/lobehub/lobe-chat/issues/8188) ([f456e91](https://github.com/lobehub/lobe-chat/commit/f456e91))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
5
30
  ### [Version 1.122.4](https://github.com/lobehub/lobe-chat/compare/v1.122.3...v1.122.4)
6
31
 
7
32
  <sup>Released on **2025-09-04**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "improvements": [
5
+ "Make LobeNextAuthDBAdapter Edge Compatible."
6
+ ]
7
+ },
8
+ "date": "2025-09-04",
9
+ "version": "1.122.5"
10
+ },
2
11
  {
3
12
  "children": {
4
13
  "improvements": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.122.4",
3
+ "version": "1.122.5",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -28,7 +28,7 @@ vi.mock('@/libs/clerk-auth', () => ({
28
28
  },
29
29
  }));
30
30
 
31
- vi.mock('@/libs/next-auth/edge', () => ({
31
+ vi.mock('@/libs/next-auth', () => ({
32
32
  default: {
33
33
  auth: vi.fn().mockResolvedValue({
34
34
  user: {
@@ -12,9 +12,9 @@ export const getUserAuth = async () => {
12
12
  }
13
13
 
14
14
  if (enableNextAuth) {
15
- const { default: NextAuthEdge } = await import('@/libs/next-auth/edge');
15
+ const { default: NextAuth } = await import('@/libs/next-auth');
16
16
 
17
- const session = await NextAuthEdge.auth();
17
+ const session = await NextAuth.auth();
18
18
 
19
19
  const userId = session?.user.id;
20
20
 
@@ -0,0 +1,137 @@
1
+ import debug from 'debug';
2
+ import { NextRequest, NextResponse } from 'next/server';
3
+
4
+ import { serverDBEnv } from '@/config/db';
5
+ import { serverDB } from '@/database/server';
6
+ import { dateKeys } from '@/libs/next-auth/adapter';
7
+ import { NextAuthUserService } from '@/server/services/nextAuthUser';
8
+
9
+ const log = debug('lobe-next-auth:api:auth:adapter');
10
+
11
+ /**
12
+ * @description Process the db query for the NextAuth adapter.
13
+ * Returns the db query result directly and let NextAuth handle the raw results.
14
+ * @returns {
15
+ * success: boolean; // Only return false if the database query fails or the action is invalid.
16
+ * data?: any;
17
+ * error?: string;
18
+ * }
19
+ */
20
+ export async function POST(req: NextRequest) {
21
+ try {
22
+ // try validate the request
23
+ if (
24
+ !req.headers.get('Authorization') ||
25
+ req.headers.get('Authorization')?.trim() !== `Bearer ${serverDBEnv.KEY_VAULTS_SECRET}`
26
+ ) {
27
+ log('Unauthorized request, missing or invalid Authorization header');
28
+ return NextResponse.json({ error: 'Unauthorized', success: false }, { status: 401 });
29
+ }
30
+
31
+ // Parse the request body
32
+ const data = await req.json();
33
+ log('Received request data:', data);
34
+ // Preprocess
35
+ if (data?.data) {
36
+ for (const key of dateKeys) {
37
+ if (data?.data && data.data[key]) {
38
+ data.data[key] = new Date(data.data[key]);
39
+ continue;
40
+ }
41
+ }
42
+ }
43
+ const service = new NextAuthUserService(serverDB);
44
+ let result;
45
+ switch (data.action) {
46
+ case 'createAuthenticator': {
47
+ result = await service.createAuthenticator(data.data);
48
+ break;
49
+ }
50
+ case 'createSession': {
51
+ result = await service.createSession(data.data);
52
+ break;
53
+ }
54
+ case 'createUser': {
55
+ result = await service.createUser(data.data);
56
+ break;
57
+ }
58
+ case 'createVerificationToken': {
59
+ result = await service.createVerificationToken(data.data);
60
+ break;
61
+ }
62
+ case 'deleteSession': {
63
+ result = await service.deleteSession(data.data);
64
+ break;
65
+ }
66
+ case 'deleteUser': {
67
+ result = await service.deleteUser(data.data);
68
+ break;
69
+ }
70
+ case 'getAccount': {
71
+ result = await service.getAccount(data.data.providerAccountId, data.data.provider);
72
+ break;
73
+ }
74
+ case 'getAuthenticator': {
75
+ result = await service.getAuthenticator(data.data);
76
+ break;
77
+ }
78
+ case 'getSessionAndUser': {
79
+ result = await service.getSessionAndUser(data.data);
80
+ break;
81
+ }
82
+ case 'getUser': {
83
+ result = await service.getUser(data.data);
84
+ break;
85
+ }
86
+ case 'getUserByAccount': {
87
+ result = await service.getUserByAccount(data.data);
88
+ break;
89
+ }
90
+ case 'getUserByEmail': {
91
+ result = await service.getUserByEmail(data.data);
92
+ break;
93
+ }
94
+ case 'linkAccount': {
95
+ result = await service.linkAccount(data.data);
96
+ break;
97
+ }
98
+ case 'listAuthenticatorsByUserId': {
99
+ result = await service.listAuthenticatorsByUserId(data.data);
100
+ break;
101
+ }
102
+ case 'unlinkAccount': {
103
+ result = await service.unlinkAccount(data.data);
104
+ break;
105
+ }
106
+ case 'updateAuthenticatorCounter': {
107
+ result = await service.updateAuthenticatorCounter(
108
+ data.data.credentialID,
109
+ data.data.counter,
110
+ );
111
+ break;
112
+ }
113
+ case 'updateSession': {
114
+ result = await service.updateSession(data.data);
115
+ break;
116
+ }
117
+ case 'updateUser': {
118
+ result = await service.updateUser(data.data);
119
+ break;
120
+ }
121
+ case 'useVerificationToken': {
122
+ result = await service.useVerificationToken(data.data);
123
+ break;
124
+ }
125
+ default: {
126
+ return NextResponse.json({ error: 'Invalid action', success: false }, { status: 400 });
127
+ }
128
+ }
129
+ return NextResponse.json({ data: result, success: true });
130
+ } catch (error) {
131
+ log('Error processing request:');
132
+ log(error);
133
+ return NextResponse.json({ error, success: false }, { status: 400 });
134
+ }
135
+ }
136
+
137
+ export const runtime = 'nodejs';
@@ -36,6 +36,15 @@ export const POST = async (req: Request): Promise<NextResponse> => {
36
36
  },
37
37
  );
38
38
  }
39
+ case 'User.SuspensionStatus.Updated': {
40
+ if (data.isSuspended) {
41
+ return nextAuthUserService.safeSignOutUser({
42
+ provider: 'logto',
43
+ providerAccountId: data.id,
44
+ });
45
+ }
46
+ return NextResponse.json({ message: 'user reactivated', success: true }, { status: 200 });
47
+ }
39
48
 
40
49
  default: {
41
50
  pino.warn(
@@ -18,6 +18,8 @@ declare global {
18
18
 
19
19
  NEXT_AUTH_DEBUG?: string;
20
20
 
21
+ NEXT_AUTH_SSO_SESSION_STRATEGY?: string;
22
+
21
23
  AUTH0_CLIENT_ID?: string;
22
24
  AUTH0_CLIENT_SECRET?: string;
23
25
  AUTH0_ISSUER?: string;
@@ -159,6 +161,7 @@ export const getAuthConfig = () => {
159
161
  NEXT_AUTH_SECRET: z.string().optional(),
160
162
  NEXT_AUTH_SSO_PROVIDERS: z.string().optional().default('auth0'),
161
163
  NEXT_AUTH_DEBUG: z.boolean().optional().default(false),
164
+ NEXT_AUTH_SSO_SESSION_STRATEGY: z.enum(['jwt', 'database']).optional().default('jwt'),
162
165
 
163
166
  // Auth0
164
167
  AUTH0_CLIENT_ID: z.string().optional(),
@@ -221,6 +224,7 @@ export const getAuthConfig = () => {
221
224
  NEXT_AUTH_SSO_PROVIDERS: process.env.NEXT_AUTH_SSO_PROVIDERS,
222
225
  NEXT_AUTH_SECRET: process.env.NEXT_AUTH_SECRET,
223
226
  NEXT_AUTH_DEBUG: !!process.env.NEXT_AUTH_DEBUG,
227
+ NEXT_AUTH_SSO_SESSION_STRATEGY: process.env.NEXT_AUTH_SSO_SESSION_STRATEGY || 'jwt',
224
228
 
225
229
  // Auth0
226
230
  AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID,
@@ -4,273 +4,175 @@ import type {
4
4
  AdapterUser,
5
5
  VerificationToken,
6
6
  } from '@auth/core/adapters';
7
- import { and, eq } from 'drizzle-orm';
8
- import type { NeonDatabase } from 'drizzle-orm/neon-serverless';
7
+ import debug from 'debug';
9
8
  import { Adapter, AdapterAccount } from 'next-auth/adapters';
9
+ import urlJoin from 'url-join';
10
10
 
11
- import { UserModel } from '@/database/models/user';
12
- import * as schema from '@/database/schemas';
13
- import { AgentService } from '@/server/services/agent';
14
- import { merge } from '@/utils/merge';
11
+ import { serverDBEnv } from '@/config/db';
12
+ import { appEnv } from '@/envs/app';
15
13
 
16
- import {
17
- mapAdapterUserToLobeUser,
18
- mapAuthenticatorQueryResutlToAdapterAuthenticator,
19
- mapLobeUserToAdapterUser,
20
- partialMapAdapterUserToLobeUser,
21
- } from './utils';
14
+ const log = debug('lobe-next-auth:adapter');
22
15
 
23
- const {
24
- nextauthAccounts,
25
- nextauthAuthenticators,
26
- nextauthSessions,
27
- nextauthVerificationTokens,
28
- users,
29
- } = schema;
16
+ interface BackendAdapterResponse {
17
+ data?: any;
18
+ error?: string;
19
+ success: boolean;
20
+ }
21
+
22
+ // Due to use direct HTTP Post, the date string cannot parse automatically
23
+ export const dateKeys = ['expires', 'emailVerified'];
30
24
 
31
25
  /**
32
26
  * @description LobeNextAuthDbAdapter is implemented to handle the database operations
33
27
  * for NextAuth, this function do the same things as `src/app/api/webhooks/clerk/route.ts`
34
28
  * @returns {Adapter}
35
29
  */
36
- export function LobeNextAuthDbAdapter(serverDB: NeonDatabase<typeof schema>): Adapter {
30
+ export function LobeNextAuthDbAdapter(): Adapter {
31
+ const baseUrl = appEnv.APP_URL;
32
+
33
+ // Ensure the baseUrl is set, otherwise throw an error
34
+ if (!baseUrl) {
35
+ throw new Error('LobeNextAuthDbAdapter: APP_URL is not set in environment variables');
36
+ }
37
+ const interactionUrl = urlJoin(baseUrl, '/api/auth/adapter');
38
+ log(`LobeNextAuthDbAdapter initialized with url: ${interactionUrl}`);
39
+
40
+ // Ensure serverDBEnv.KEY_VAULTS_SECRET is set, otherwise throw an error
41
+ if (!serverDBEnv.KEY_VAULTS_SECRET) {
42
+ throw new Error('LobeNextAuthDbAdapter: KEY_VAULTS_SECRET is not set in environment variables');
43
+ }
44
+
45
+ const fetcher = (action: string, data: any) =>
46
+ fetch(interactionUrl, {
47
+ body: JSON.stringify({ action, data }),
48
+ headers: {
49
+ 'Authorization': `Bearer ${serverDBEnv.KEY_VAULTS_SECRET}`,
50
+ 'Content-Type': 'application/json',
51
+ },
52
+ method: 'POST',
53
+ });
54
+ const postProcessor = async (res: Response) => {
55
+ const data = (await res.json()) as BackendAdapterResponse;
56
+ log('LobeNextAuthDbAdapter: postProcessor called with data:', data);
57
+ if (!data.success) {
58
+ log('LobeNextAuthDbAdapter: Error in postProcessor:');
59
+ log(data);
60
+ throw new Error(`LobeNextAuthDbAdapter: ${data.error}`);
61
+ }
62
+ if (data?.data) {
63
+ for (const key of dateKeys) {
64
+ if (data.data[key]) {
65
+ data.data[key] = new Date(data.data[key]);
66
+ continue;
67
+ }
68
+ }
69
+ }
70
+ return data.data;
71
+ };
72
+
37
73
  return {
38
74
  async createAuthenticator(authenticator): Promise<AdapterAuthenticator> {
39
- const result = await serverDB
40
- .insert(nextauthAuthenticators)
41
- .values(authenticator)
42
- .returning()
43
- .then((res) => res[0] ?? undefined);
44
- if (!result) throw new Error('LobeNextAuthDbAdapter: Failed to create authenticator');
45
- return mapAuthenticatorQueryResutlToAdapterAuthenticator(result);
75
+ const data = await fetcher('createAuthenticator', authenticator);
76
+ return await postProcessor(data);
46
77
  },
47
- async createSession(data): Promise<AdapterSession> {
48
- return serverDB
49
- .insert(nextauthSessions)
50
- .values(data)
51
- .returning()
52
- .then((res) => res[0]);
78
+ async createSession(session): Promise<AdapterSession> {
79
+ const data = await fetcher('createSession', session);
80
+ return await postProcessor(data);
53
81
  },
54
82
  async createUser(user): Promise<AdapterUser> {
55
- const { id, name, email, emailVerified, image, providerAccountId } = user;
56
- // return the user if it already exists
57
- let existingUser =
58
- email && typeof email === 'string' && email.trim()
59
- ? await UserModel.findByEmail(serverDB, email)
60
- : undefined;
61
- // If the user is not found by email, try to find by providerAccountId
62
- if (!existingUser && providerAccountId) {
63
- existingUser = await UserModel.findById(serverDB, providerAccountId);
64
- }
65
- if (existingUser) {
66
- const adapterUser = mapLobeUserToAdapterUser(existingUser);
67
- return adapterUser;
68
- }
69
-
70
- // create a new user if it does not exist
71
- // Use id from provider if it exists, otherwise use id assigned by next-auth
72
- // ref: https://github.com/lobehub/lobe-chat/pull/2935
73
- const uid = providerAccountId ?? id;
74
- await UserModel.createUser(
75
- serverDB,
76
- mapAdapterUserToLobeUser({
77
- email,
78
- emailVerified,
79
- // Use providerAccountId as userid to identify if the user exists in a SSO provider
80
- id: uid,
81
- image,
82
- name,
83
- }),
84
- );
85
-
86
- // 3. Create an inbox session for the user
87
- const agentService = new AgentService(serverDB, uid);
88
- await agentService.createInbox();
89
-
90
- return { ...user, id: uid };
83
+ const data = await fetcher('createUser', user);
84
+ return await postProcessor(data);
91
85
  },
92
86
  async createVerificationToken(data): Promise<VerificationToken | null | undefined> {
93
- return serverDB
94
- .insert(nextauthVerificationTokens)
95
- .values(data)
96
- .returning()
97
- .then((res) => res[0]);
87
+ const result = await fetcher('createVerificationToken', data);
88
+ return await postProcessor(result);
98
89
  },
99
90
  async deleteSession(sessionToken): Promise<AdapterSession | null | undefined> {
100
- await serverDB
101
- .delete(nextauthSessions)
102
- .where(eq(nextauthSessions.sessionToken, sessionToken));
91
+ const result = await fetcher('deleteSession', sessionToken);
92
+ await postProcessor(result);
103
93
  return;
104
94
  },
105
95
  async deleteUser(id): Promise<AdapterUser | null | undefined> {
106
- const user = await UserModel.findById(serverDB, id);
107
- if (!user) throw new Error('NextAuth: Delete User not found');
108
-
109
- await UserModel.deleteUser(serverDB, id);
96
+ const result = await fetcher('deleteUser', id);
97
+ await postProcessor(result);
110
98
  return;
111
99
  },
112
100
 
113
101
  async getAccount(providerAccountId, provider): Promise<AdapterAccount | null> {
114
- return serverDB
115
- .select()
116
- .from(nextauthAccounts)
117
- .where(
118
- and(
119
- eq(nextauthAccounts.provider, provider),
120
- eq(nextauthAccounts.providerAccountId, providerAccountId),
121
- ),
122
- )
123
- .then((res) => res[0] ?? null) as Promise<AdapterAccount | null>;
102
+ const data = await fetcher('getAccount', {
103
+ provider,
104
+ providerAccountId,
105
+ });
106
+ return await postProcessor(data);
124
107
  },
125
108
 
126
109
  async getAuthenticator(credentialID): Promise<AdapterAuthenticator | null> {
127
- const result = await serverDB
128
- .select()
129
- .from(nextauthAuthenticators)
130
- .where(eq(nextauthAuthenticators.credentialID, credentialID))
131
- .then((res) => res[0] ?? null);
132
- if (!result) throw new Error('LobeNextAuthDbAdapter: Failed to get authenticator');
133
- return mapAuthenticatorQueryResutlToAdapterAuthenticator(result);
110
+ const result = await fetcher('getAuthenticator', credentialID);
111
+ return await postProcessor(result);
134
112
  },
135
113
 
136
114
  async getSessionAndUser(sessionToken): Promise<{
137
115
  session: AdapterSession;
138
116
  user: AdapterUser;
139
117
  } | null> {
140
- const result = await serverDB
141
- .select({
142
- session: nextauthSessions,
143
- user: users,
144
- })
145
- .from(nextauthSessions)
146
- .where(eq(nextauthSessions.sessionToken, sessionToken))
147
- .innerJoin(users, eq(users.id, nextauthSessions.userId))
148
- .then((res) => (res.length > 0 ? res[0] : null));
149
-
150
- if (!result) return null;
151
- const adapterUser = mapLobeUserToAdapterUser(result.user);
152
- if (!adapterUser) return null;
153
- return {
154
- session: result.session,
155
- user: adapterUser,
156
- };
118
+ const result = await fetcher('getSessionAndUser', sessionToken);
119
+ return await postProcessor(result);
157
120
  },
158
121
 
159
122
  async getUser(id): Promise<AdapterUser | null> {
160
- const lobeUser = await UserModel.findById(serverDB, id);
161
- if (!lobeUser) return null;
162
- return mapLobeUserToAdapterUser(lobeUser);
123
+ log('getUser called with id:', id);
124
+ const result = await fetcher('getUser', id);
125
+ return await postProcessor(result);
163
126
  },
164
127
 
165
128
  async getUserByAccount(account): Promise<AdapterUser | null> {
166
- const result = await serverDB
167
- .select({
168
- account: nextauthAccounts,
169
- users,
170
- })
171
- .from(nextauthAccounts)
172
- .innerJoin(users, eq(nextauthAccounts.userId, users.id))
173
- .where(
174
- and(
175
- eq(nextauthAccounts.provider, account.provider),
176
- eq(nextauthAccounts.providerAccountId, account.providerAccountId),
177
- ),
178
- )
179
- .then((res) => res[0]);
180
-
181
- return result?.users ? mapLobeUserToAdapterUser(result.users) : null;
129
+ const data = await fetcher('getUserByAccount', account);
130
+ return await postProcessor(data);
182
131
  },
183
132
 
184
133
  async getUserByEmail(email): Promise<AdapterUser | null> {
185
- const lobeUser =
186
- email && typeof email === 'string' && email.trim()
187
- ? await UserModel.findByEmail(serverDB, email)
188
- : undefined;
189
- return lobeUser ? mapLobeUserToAdapterUser(lobeUser) : null;
134
+ const data = await fetcher('getUserByEmail', email);
135
+ return await postProcessor(data);
190
136
  },
191
137
 
192
138
  async linkAccount(data): Promise<AdapterAccount | null | undefined> {
193
- const [account] = await serverDB
194
- .insert(nextauthAccounts)
195
- .values(data as any)
196
- .returning();
197
- if (!account) throw new Error('NextAuthAccountModel: Failed to create account');
198
- // TODO Update type annotation
199
- return account as any;
139
+ const result = await fetcher('linkAccount', data);
140
+ return await postProcessor(result);
200
141
  },
201
142
 
202
143
  async listAuthenticatorsByUserId(userId): Promise<AdapterAuthenticator[]> {
203
- const result = await serverDB
204
- .select()
205
- .from(nextauthAuthenticators)
206
- .where(eq(nextauthAuthenticators.userId, userId))
207
- .then((res) => res);
208
- if (result.length === 0)
209
- throw new Error('LobeNextAuthDbAdapter: Failed to get authenticator list');
210
- return result.map((r) => mapAuthenticatorQueryResutlToAdapterAuthenticator(r));
144
+ const result = await fetcher('listAuthenticatorsByUserId', userId);
145
+ return await postProcessor(result);
211
146
  },
212
147
 
213
148
  // @ts-ignore: The return type is {Promise<void> | Awaitable<AdapterAccount | undefined>}
214
149
  async unlinkAccount(account): Promise<void | AdapterAccount | undefined> {
215
- await serverDB
216
- .delete(nextauthAccounts)
217
- .where(
218
- and(
219
- eq(nextauthAccounts.provider, account.provider),
220
- eq(nextauthAccounts.providerAccountId, account.providerAccountId),
221
- ),
222
- );
150
+ const result = await fetcher('unlinkAccount', account);
151
+ await postProcessor(result);
152
+ return;
223
153
  },
224
154
 
225
155
  async updateAuthenticatorCounter(credentialID, counter): Promise<AdapterAuthenticator> {
226
- const result = await serverDB
227
- .update(nextauthAuthenticators)
228
- .set({ counter })
229
- .where(eq(nextauthAuthenticators.credentialID, credentialID))
230
- .returning()
231
- .then((res) => res[0]);
232
- if (!result) throw new Error('LobeNextAuthDbAdapter: Failed to update authenticator counter');
233
- return mapAuthenticatorQueryResutlToAdapterAuthenticator(result);
156
+ const result = await fetcher('updateAuthenticatorCounter', {
157
+ counter,
158
+ credentialID,
159
+ });
160
+ return await postProcessor(result);
234
161
  },
235
162
 
236
163
  async updateSession(data): Promise<AdapterSession | null | undefined> {
237
- const res = await serverDB
238
- .update(nextauthSessions)
239
- .set(data)
240
- .where(eq(nextauthSessions.sessionToken, data.sessionToken))
241
- .returning();
242
- return res[0];
164
+ const result = await fetcher('updateSession', data);
165
+ return await postProcessor(result);
243
166
  },
244
167
 
245
168
  async updateUser(user): Promise<AdapterUser> {
246
- const lobeUser = await UserModel.findById(serverDB, user?.id);
247
- if (!lobeUser) throw new Error('NextAuth: User not found');
248
- const userModel = new UserModel(serverDB, user.id);
249
-
250
- const updatedUser = await userModel.updateUser({
251
- ...partialMapAdapterUserToLobeUser(user),
252
- });
253
- if (!updatedUser) throw new Error('NextAuth: Failed to update user');
254
-
255
- // merge new user data with old user data
256
- const newAdapterUser = mapLobeUserToAdapterUser(lobeUser);
257
- if (!newAdapterUser) {
258
- throw new Error('NextAuth: Failed to map user data to adapter user');
259
- }
260
- return merge(newAdapterUser, user);
169
+ const result = await fetcher('updateUser', user);
170
+ return await postProcessor(result);
261
171
  },
262
172
 
263
173
  async useVerificationToken(identifier_token): Promise<VerificationToken | null> {
264
- return serverDB
265
- .delete(nextauthVerificationTokens)
266
- .where(
267
- and(
268
- eq(nextauthVerificationTokens.identifier, identifier_token.identifier),
269
- eq(nextauthVerificationTokens.token, identifier_token.token),
270
- ),
271
- )
272
- .returning()
273
- .then((res) => (res.length > 0 ? res[0] : null));
174
+ const result = await fetcher('useVerificationToken', identifier_token);
175
+ return await postProcessor(result);
274
176
  },
275
177
  };
276
178
  }