1
1
import type {
2
2
Adapter ,
3
+ AdapterAccount ,
3
4
AdapterSession ,
4
5
AdapterUser ,
5
6
VerificationToken as AdapterVerificationToken ,
6
7
} from "next-auth/adapters" ;
7
8
import { type CollectionSlug , getPayload , type Payload , type SanitizedConfig } from "payload" ;
8
- import type { Session , User , VerificationToken } from "../payload/types" ;
9
+ import type { Account , Session , User , VerificationToken } from "../payload/types" ;
10
+ import { isDate } from "../utils/authjs" ;
9
11
10
12
export interface PayloadAdapterOptions {
11
13
/**
@@ -28,6 +30,7 @@ export interface PayloadAdapterOptions {
28
30
}
29
31
/**
30
32
* Auth.js Database Adapter for Payload CMS
33
+ *
31
34
* @see https://authjs.dev/guides/creating-a-database-adapter
32
35
*/
33
36
export function PayloadAdapter ( {
@@ -162,7 +165,11 @@ export function PayloadAdapter({
162
165
} satisfies Partial < User > ,
163
166
} ) ) as User ;
164
167
165
- return account ;
168
+ const createdAccount = payloadUser . accounts ?. find (
169
+ a => a . provider === account . provider && a . providerAccountId === account . providerAccountId ,
170
+ ) ;
171
+
172
+ return createdAccount ? toAdapterAccount ( createdAccount ) : account ;
166
173
} ,
167
174
async unlinkAccount ( { provider, providerAccountId } ) {
168
175
/* console.log(
@@ -198,7 +205,7 @@ export function PayloadAdapter({
198
205
data : {
199
206
accounts : payloadUser . accounts ?. filter (
200
207
account =>
201
- account . provider !== provider || account . providerAccountId !== providerAccountId ,
208
+ ! ( account . provider === provider && account . providerAccountId === providerAccountId ) ,
202
209
) ,
203
210
} ,
204
211
} ) ) as User ;
@@ -229,7 +236,11 @@ export function PayloadAdapter({
229
236
} ,
230
237
} ) ) as User ;
231
238
232
- return session ;
239
+ const createdSession = payloadUser . sessions ?. find (
240
+ s => s . sessionToken === session . sessionToken ,
241
+ ) ;
242
+
243
+ return createdSession ? toAdapterSession ( payloadUser , createdSession ) : session ;
233
244
} ,
234
245
async getSessionAndUser ( sessionToken ) {
235
246
/* console.log(`[PayloadAdapter] Getting session and user by session token '${sessionToken}'`); */
@@ -294,6 +305,7 @@ export function PayloadAdapter({
294
305
const updatedSession = payloadUser . sessions ?. find (
295
306
s => s . sessionToken === session . sessionToken ,
296
307
) ;
308
+
297
309
return updatedSession ? toAdapterSession ( payloadUser , updatedSession ) : null ;
298
310
} ,
299
311
async deleteSession ( sessionToken ) {
@@ -366,10 +378,14 @@ export function PayloadAdapter({
366
378
} ) ) as User ;
367
379
}
368
380
369
- return {
370
- identifier : email ,
371
- ...token ,
372
- } ;
381
+ const createdToken = payloadUser . verificationTokens ?. find ( t => t . token === token . token ) ;
382
+
383
+ return createdToken
384
+ ? toAdapterVerificationToken ( payloadUser . email , createdToken )
385
+ : {
386
+ identifier : email ,
387
+ ...token ,
388
+ } ;
373
389
} ,
374
390
async useVerificationToken ( { identifier : email , token } ) {
375
391
/* console.log(`[PayloadAdapter] Using verification token for email '${email}'`, token); */
@@ -405,37 +421,62 @@ export function PayloadAdapter({
405
421
} ,
406
422
} ) ) as User ;
407
423
408
- return verificationToken ? toAdapterVerificationToken ( payloadUser , verificationToken ) : null ;
424
+ return verificationToken
425
+ ? toAdapterVerificationToken ( payloadUser . email , verificationToken )
426
+ : null ;
409
427
} ,
410
428
// #endregion
411
429
} ;
412
430
}
413
431
414
432
function toAdapterUser ( user : User ) : AdapterUser {
415
- return {
416
- id : user . id ,
417
- name : user . name ,
418
- email : user . email ,
419
- image : user . image ,
420
- emailVerified : user . emailVerified ? new Date ( user . emailVerified ) : null ,
421
- } ;
433
+ return transformObject ( user , [ "accounts" , "sessions" , "verificationTokens" ] ) ;
434
+ }
435
+
436
+ function toAdapterAccount ( account : Account ) : AdapterAccount {
437
+ return transformObject ( account ) ;
422
438
}
423
439
424
440
function toAdapterSession ( user : User , session : Session ) : AdapterSession {
425
441
return {
442
+ ...transformObject < Session , Omit < AdapterSession , "userId" > > ( session ) ,
426
443
userId : user . id ,
427
- sessionToken : session . sessionToken ,
428
- expires : new Date ( session . expires ) ,
429
444
} ;
430
445
}
431
446
432
447
function toAdapterVerificationToken (
433
- user : User ,
448
+ email : string ,
434
449
token : VerificationToken ,
435
450
) : AdapterVerificationToken {
436
451
return {
437
- identifier : user . email ,
438
- token : token . token ,
439
- expires : new Date ( token . expires ) ,
452
+ identifier : email ,
453
+ ...transformObject < VerificationToken , Omit < AdapterVerificationToken , "identifier" > > ( token ) ,
440
454
} ;
441
455
}
456
+
457
+ /**
458
+ * Transform an object to an object that can be used by the adapter
459
+ *
460
+ * @param object Object to transform
461
+ * @param exclude List of keys to remove from the object
462
+ * @returns The transformed object
463
+ *
464
+ * @see https://authjs.dev/guides/creating-a-database-adapter#official-adapter-guidelines
465
+ */
466
+ function transformObject < T extends Record < string , unknown > , AdapterObject extends object > (
467
+ object : T ,
468
+ exclude ?: ( keyof T ) [ ] ,
469
+ ) : AdapterObject {
470
+ const adapterObject : Record < string , unknown > = { } ;
471
+ for ( const [ key , value ] of Object . entries ( object ) ) {
472
+ if ( exclude ?. includes ( key ) ) {
473
+ continue ;
474
+ }
475
+ if ( isDate ( value ) ) {
476
+ adapterObject [ key ] = new Date ( value ) ;
477
+ } else {
478
+ adapterObject [ key ] = value ;
479
+ }
480
+ }
481
+ return adapterObject as AdapterObject ;
482
+ }
0 commit comments