11import type {
22 Adapter ,
3+ AdapterAccount ,
34 AdapterSession ,
45 AdapterUser ,
56 VerificationToken as AdapterVerificationToken ,
67} from "next-auth/adapters" ;
78import { 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" ;
911
1012export interface PayloadAdapterOptions {
1113 /**
@@ -28,6 +30,7 @@ export interface PayloadAdapterOptions {
2830}
2931/**
3032 * Auth.js Database Adapter for Payload CMS
33+ *
3134 * @see https://authjs.dev/guides/creating-a-database-adapter
3235 */
3336export function PayloadAdapter ( {
@@ -162,7 +165,11 @@ export function PayloadAdapter({
162165 } satisfies Partial < User > ,
163166 } ) ) as User ;
164167
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 ;
166173 } ,
167174 async unlinkAccount ( { provider, providerAccountId } ) {
168175 /* console.log(
@@ -198,7 +205,7 @@ export function PayloadAdapter({
198205 data : {
199206 accounts : payloadUser . accounts ?. filter (
200207 account =>
201- account . provider !== provider || account . providerAccountId !== providerAccountId ,
208+ ! ( account . provider === provider && account . providerAccountId === providerAccountId ) ,
202209 ) ,
203210 } ,
204211 } ) ) as User ;
@@ -229,7 +236,11 @@ export function PayloadAdapter({
229236 } ,
230237 } ) ) as User ;
231238
232- return session ;
239+ const createdSession = payloadUser . sessions ?. find (
240+ s => s . sessionToken === session . sessionToken ,
241+ ) ;
242+
243+ return createdSession ? toAdapterSession ( payloadUser , createdSession ) : session ;
233244 } ,
234245 async getSessionAndUser ( sessionToken ) {
235246 /* console.log(`[PayloadAdapter] Getting session and user by session token '${sessionToken}'`); */
@@ -294,6 +305,7 @@ export function PayloadAdapter({
294305 const updatedSession = payloadUser . sessions ?. find (
295306 s => s . sessionToken === session . sessionToken ,
296307 ) ;
308+
297309 return updatedSession ? toAdapterSession ( payloadUser , updatedSession ) : null ;
298310 } ,
299311 async deleteSession ( sessionToken ) {
@@ -366,10 +378,14 @@ export function PayloadAdapter({
366378 } ) ) as User ;
367379 }
368380
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+ } ;
373389 } ,
374390 async useVerificationToken ( { identifier : email , token } ) {
375391 /* console.log(`[PayloadAdapter] Using verification token for email '${email}'`, token); */
@@ -405,37 +421,62 @@ export function PayloadAdapter({
405421 } ,
406422 } ) ) as User ;
407423
408- return verificationToken ? toAdapterVerificationToken ( payloadUser , verificationToken ) : null ;
424+ return verificationToken
425+ ? toAdapterVerificationToken ( payloadUser . email , verificationToken )
426+ : null ;
409427 } ,
410428 // #endregion
411429 } ;
412430}
413431
414432function 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 ) ;
422438}
423439
424440function toAdapterSession ( user : User , session : Session ) : AdapterSession {
425441 return {
442+ ...transformObject < Session , Omit < AdapterSession , "userId" > > ( session ) ,
426443 userId : user . id ,
427- sessionToken : session . sessionToken ,
428- expires : new Date ( session . expires ) ,
429444 } ;
430445}
431446
432447function toAdapterVerificationToken (
433- user : User ,
448+ email : string ,
434449 token : VerificationToken ,
435450) : AdapterVerificationToken {
436451 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 ) ,
440454 } ;
441455}
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