Skip to content

Commit 2224635

Browse files
committed
refactor: Restructuring the utils functions
1 parent 3b4b16b commit 2224635

12 files changed

Lines changed: 145 additions & 142 deletions

File tree

packages/payload-authjs/src/authjs/PayloadAdapter.ts

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import type {
66
VerificationToken as AdapterVerificationToken,
77
} from "next-auth/adapters";
88
import { type CollectionSlug, getPayload, type Payload, type SanitizedConfig } from "payload";
9-
import type { Account, Session, User, VerificationToken } from "../payload/types";
10-
import { isDate } from "../utils/authjs";
9+
import type { Account, Session, User, VerificationToken } from "./types";
10+
import { transformObject } from "./utils/transformObject";
1111

1212
export interface PayloadAdapterOptions {
1313
/**
@@ -453,30 +453,3 @@ function toAdapterVerificationToken(
453453
...transformObject<VerificationToken, Omit<AdapterVerificationToken, "identifier">>(token),
454454
};
455455
}
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-
}

packages/payload-authjs/src/authjs/types.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,41 @@
1+
export interface User {
2+
id: string;
3+
email: string;
4+
name?: string | null;
5+
image?: string | null;
6+
emailVerified?: string | null;
7+
accounts?: Account[] | null;
8+
sessions?: Session[] | null;
9+
verificationTokens?: VerificationToken[] | null;
10+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
11+
[key: string]: any;
12+
}
13+
14+
export interface Account {
15+
id?: string | null;
16+
provider: string;
17+
providerAccountId: string;
18+
type: string;
19+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
20+
[key: string]: any;
21+
}
22+
23+
export interface Session {
24+
id?: string | null;
25+
sessionToken: string;
26+
expires: string;
27+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
28+
[key: string]: any;
29+
}
30+
31+
export interface VerificationToken {
32+
id?: string | null;
33+
token: string;
34+
expires: string;
35+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
36+
[key: string]: any;
37+
}
38+
139
/**
240
* Helper type to extract the user type from the collection user type.
341
*
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { NextAuthConfig } from "next-auth";
2+
3+
/**
4+
* Check if an email provider is available in the authjs config
5+
*/
6+
export const isEmailProviderAvailable = (authjsConfig: NextAuthConfig) => {
7+
return authjsConfig.providers?.some(
8+
provider => (typeof provider === "function" ? provider().type : provider.type) === "email",
9+
);
10+
};
11+
12+
/**
13+
* Check if the authjs session strategy is database
14+
*/
15+
export const isSessionStrategyDatabase = (authjsConfig: NextAuthConfig) => {
16+
return authjsConfig.session?.strategy === "database";
17+
};
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// https://github.com/honeinc/is-iso-date/blob/8831e79b5b5ee615920dcb350a355ffc5cbf7aed/index.js#L5
2+
const isoDateRE =
3+
// eslint-disable-next-line regexp/no-unused-capturing-group
4+
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/;
5+
6+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
7+
const isDate = (val: any): val is ConstructorParameters<typeof Date>[0] =>
8+
!!(val && isoDateRE.test(val) && !isNaN(Date.parse(val)));
9+
10+
/**
11+
* Transform an object to an object that can be used by the adapter
12+
*
13+
* @param object Object to transform
14+
* @param exclude List of keys to remove from the object
15+
* @returns The transformed object
16+
*
17+
* @see https://authjs.dev/guides/creating-a-database-adapter#official-adapter-guidelines
18+
*/
19+
export const transformObject = <T extends Record<string, unknown>, AdapterObject extends object>(
20+
object: T,
21+
exclude?: (keyof T)[],
22+
): AdapterObject => {
23+
const adapterObject: Record<string, unknown> = {};
24+
for (const [key, value] of Object.entries(object)) {
25+
if (exclude?.includes(key)) {
26+
continue;
27+
}
28+
if (isDate(value)) {
29+
adapterObject[key] = new Date(value);
30+
} else {
31+
adapterObject[key] = value;
32+
}
33+
}
34+
return adapterObject as AdapterObject;
35+
};

packages/payload-authjs/src/payload/AuthjsAuthStrategy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import NextAuth from "next-auth";
22
import type { AuthStrategy, CollectionConfig, User as PayloadUser } from "payload";
33
import { withPayload } from "../authjs/withPayload";
4-
import { getUserAttributes } from "../utils/authjs";
5-
import { getAllVirtualFields } from "../utils/payload";
64
import type { AuthjsPluginConfig } from "./plugin";
5+
import { getAllVirtualFields } from "./utils/getAllVirtualFields";
6+
import { getUserAttributes } from "./utils/getUserAttributes";
77

88
/**
99
* Auth.js Authentication Strategy for Payload CMS

packages/payload-authjs/src/payload/collection/hooks/me.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import NextAuth from "next-auth";
22
import type { CollectionConfig, CollectionMeHook } from "payload";
33
import { withPayload } from "../../../authjs/withPayload";
4-
import { getUserAttributes } from "../../../utils/authjs";
5-
import { getAllVirtualFields } from "../../../utils/payload";
64
import type { AuthjsPluginConfig } from "../../plugin";
5+
import { getAllVirtualFields } from "../../utils/getAllVirtualFields";
6+
import { getUserAttributes } from "../../utils/getUserAttributes";
77

88
/**
99
* Add me hook to override the me endpoint to include virtual fields

packages/payload-authjs/src/payload/collection/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type { CollectionConfig, TabsField } from "payload";
2-
import { isEmailProviderAvailable, isSessionStrategyDatabase } from "../../utils/authjs";
3-
import { mergeFields } from "../../utils/payload";
2+
import { isEmailProviderAvailable, isSessionStrategyDatabase } from "../../authjs/utils/config";
43
import { AuthjsAuthStrategy } from "../AuthjsAuthStrategy";
54
import type { AuthjsPluginConfig } from "../plugin";
5+
import { mergeFields } from "../utils/mergeFields";
66
import { defaultAccess } from "./access";
77
import { logoutEndpoint } from "./endpoints/logout";
88
import { accountsField } from "./fields/accounts";

packages/payload-authjs/src/payload/types.ts

Lines changed: 0 additions & 37 deletions
This file was deleted.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { type Field } from "payload";
2+
import { fieldAffectsData, fieldIsVirtual } from "payload/shared";
3+
4+
/**
5+
* Get all virtual fields from a list of fields (including subfields and tabs)
6+
*
7+
* @param fields The fields list
8+
* @returns The virtual fields
9+
*/
10+
export const getAllVirtualFields = (fields: Field[]): Field[] => {
11+
return fields.reduce((acc, field) => {
12+
if ("fields" in field && !fieldAffectsData(field)) {
13+
// Get virtual fields from subfields if field not affecting data (e.g. row)
14+
acc.push(...getAllVirtualFields(field.fields));
15+
} else if (field.type === "tabs") {
16+
// For each tab, get the virtual fields
17+
for (const tab of field.tabs) {
18+
acc.push(...getAllVirtualFields(tab.fields));
19+
}
20+
} else if (fieldIsVirtual(field)) {
21+
// Add virtual field
22+
acc.push(field);
23+
}
24+
return acc;
25+
}, [] as Field[]);
26+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { User as AuthjsUser } from "next-auth";
2+
import type { Field } from "payload";
3+
4+
/**
5+
* Get user attributes from a user object based on the fields
6+
*
7+
* @param user User object
8+
* @param fields Fields to get from the user object
9+
* @returns Object with specified fields from the user object
10+
*/
11+
export const getUserAttributes = (user: AuthjsUser, fields: Field[]) => {
12+
return fields.reduce((acc: Partial<AuthjsUser>, field) => {
13+
if ("name" in field) {
14+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
15+
const val = user[field.name as keyof AuthjsUser] as any;
16+
acc[field.name as keyof AuthjsUser] = val;
17+
}
18+
return acc;
19+
}, {});
20+
};

0 commit comments

Comments
 (0)