payload-better-auth 1.0.1 → 1.0.3

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 (31) hide show
  1. package/README.md +1 -1
  2. package/dist/better-auth/helpers.d.ts +8 -0
  3. package/dist/better-auth/helpers.js +3 -0
  4. package/dist/better-auth/helpers.js.map +1 -0
  5. package/dist/better-auth/plugin.js +45 -5
  6. package/dist/better-auth/plugin.js.map +1 -1
  7. package/dist/components/BetterAuthLoginServer.d.ts +12 -1
  8. package/dist/components/BetterAuthLoginServer.js +36 -13
  9. package/dist/components/BetterAuthLoginServer.js.map +1 -1
  10. package/dist/components/EmailPasswordFormClient.d.ts +4 -1
  11. package/dist/components/EmailPasswordFormClient.js +53 -21
  12. package/dist/components/EmailPasswordFormClient.js.map +1 -1
  13. package/dist/components/VerifyEmailInfoViewClient.d.ts +1 -0
  14. package/dist/components/VerifyEmailInfoViewClient.js +63 -0
  15. package/dist/components/VerifyEmailInfoViewClient.js.map +1 -0
  16. package/dist/exports/client.d.ts +1 -1
  17. package/dist/exports/client.js +1 -1
  18. package/dist/exports/client.js.map +1 -1
  19. package/dist/payload/plugin.d.ts +1 -0
  20. package/dist/payload/plugin.js +10 -3
  21. package/dist/payload/plugin.js.map +1 -1
  22. package/dist/utils/payload-reconcile.js +1 -0
  23. package/dist/utils/payload-reconcile.js.map +1 -1
  24. package/package.json +7 -2
  25. package/dist/components/BeforeDashboardClient.d.ts +0 -2
  26. package/dist/components/BeforeDashboardClient.js +0 -36
  27. package/dist/components/BeforeDashboardClient.js.map +0 -1
  28. package/dist/components/BeforeDashboardServer.d.ts +0 -3
  29. package/dist/components/BeforeDashboardServer.js +0 -22
  30. package/dist/components/BeforeDashboardServer.js.map +0 -1
  31. package/dist/components/BeforeDashboardServer.module.css +0 -5
package/README.md CHANGED
@@ -13,7 +13,7 @@ To build your own Payload plugin, all you need is:
13
13
 
14
14
  1. Install: `pnpm i`
15
15
  2. Generate import map for payload: `cd packages/plugins/dev && pnpx payload generate:importmap`
16
- 3. Initialize / migrate the better-auth database: `pnpx @better-auth/cli migrate --yes` (Also from `dev` directory)
16
+ 3. Initialize / migrate the better-auth database: `cd ../ && pnpx @better-auth/cli migrate --yes --config ./dev/lib/auth.ts` (Run from `dev` directory)
17
17
  4. Run dev: `pnpm dev`
18
18
 
19
19
  ## Background
@@ -0,0 +1,8 @@
1
+ export type AuthMethod = {
2
+ method: 'emailAndPassword';
3
+ options: {
4
+ minPasswordLength: number;
5
+ };
6
+ } | {
7
+ method: 'magicLink';
8
+ };
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/better-auth/helpers.ts"],"sourcesContent":["export type AuthMethod =\n | { method: 'emailAndPassword'; options: { minPasswordLength: number } }\n | { method: 'magicLink' }\n"],"names":[],"mappings":"AAAA,WAE2B"}
@@ -1,5 +1,6 @@
1
1
  // src/plugins/reconcile-queue-plugin.ts
2
- import { APIError, createAuthEndpoint } from 'better-auth/api';
2
+ import { APIError } from 'better-auth/api';
3
+ import { createAuthEndpoint, createAuthMiddleware } from 'better-auth/plugins';
3
4
  import { createDatabaseHooks } from './databaseHooks.js';
4
5
  import { Queue } from './reconcile-queue.js';
5
6
  import { createDeleteUserFromPayload, createListPayloadUsersPage, createSyncUserToPayload } from './sources.js';
@@ -40,11 +41,19 @@ export const payloadBetterAuthPlugin = (opts)=>{
40
41
  const authMethods = [];
41
42
  // Check if emailAndPassword is enabled, or if present at all (not present defaults to false)
42
43
  if (context.options.emailAndPassword?.enabled) {
43
- authMethods.push('emailAndPassword');
44
+ authMethods.push({
45
+ method: 'emailAndPassword',
46
+ options: {
47
+ minPasswordLength: context.options.emailAndPassword.minPasswordLength ?? 0
48
+ }
49
+ });
44
50
  }
45
- return await json({
46
- authMethods
47
- });
51
+ if (context.options.plugins?.some((p)=>p.id === 'magic-link')) {
52
+ authMethods.push({
53
+ method: 'magicLink'
54
+ });
55
+ }
56
+ return await json(authMethods);
48
57
  }),
49
58
  deleteNow: createAuthEndpoint('/reconcile/delete', {
50
59
  method: 'POST'
@@ -89,6 +98,37 @@ export const payloadBetterAuthPlugin = (opts)=>{
89
98
  });
90
99
  })
91
100
  },
101
+ hooks: {
102
+ before: [
103
+ {
104
+ handler: createAuthMiddleware(async (ctx)=>{
105
+ const locale = ctx.getHeader('User-Locale');
106
+ return Promise.resolve({
107
+ context: {
108
+ ...ctx,
109
+ body: {
110
+ ...ctx.body,
111
+ locale: locale ?? undefined
112
+ }
113
+ }
114
+ });
115
+ }),
116
+ matcher: (context)=>{
117
+ return context.path === '/sign-up/email';
118
+ }
119
+ }
120
+ ]
121
+ },
122
+ schema: {
123
+ user: {
124
+ fields: {
125
+ locale: {
126
+ type: 'string',
127
+ required: false
128
+ }
129
+ }
130
+ }
131
+ },
92
132
  // TODO: the queue must be destroyed on better auth instance destruction, as it utilizes timers.
93
133
  async init ({ internalAdapter, password }) {
94
134
  if (opts.createAdmins) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/better-auth/plugin.ts"],"sourcesContent":["// src/plugins/reconcile-queue-plugin.ts\nimport type { AuthContext, BetterAuthPlugin, DeepPartial } from 'better-auth'\nimport type { SanitizedConfig } from 'payload'\n\nimport { APIError, createAuthEndpoint } from 'better-auth/api'\n\nimport { createDatabaseHooks } from './databaseHooks.js'\nimport { type InitOptions, Queue } from './reconcile-queue.js'\nimport {\n type BAUser,\n createDeleteUserFromPayload,\n createListPayloadUsersPage,\n createSyncUserToPayload,\n} from './sources.js'\n\ntype PayloadSyncPluginContext = { payloadSyncPlugin: { queue: Queue } } & AuthContext\n\ntype CreateAdminsUser = Parameters<AuthContext['internalAdapter']['createUser']>['0']\n\nconst defaultLog = (msg: string, extra?: unknown) => {\n console.log(`[reconcile] ${msg}`, extra ? JSON.stringify(extra, null, 2) : '')\n}\n\nexport const payloadBetterAuthPlugin = (\n opts: {\n createAdmins?: { overwrite?: boolean; user: CreateAdminsUser }[]\n enableLogging?: boolean\n payloadConfig: Promise<SanitizedConfig>\n token: string // simple header token for admin endpoints,\n } & InitOptions,\n): BetterAuthPlugin => {\n return {\n id: 'reconcile-queue-plugin',\n endpoints: {\n run: createAuthEndpoint(\n '/reconcile/run',\n { method: 'POST' },\n async ({ context, json, request }) => {\n if (opts.token && request?.headers.get('x-reconcile-token') !== opts.token) {\n throw new APIError('UNAUTHORIZED', { message: 'invalid token' })\n }\n await (context as PayloadSyncPluginContext).payloadSyncPlugin.queue.seedFullReconcile()\n return json({ ok: true })\n },\n ),\n status: createAuthEndpoint(\n '/reconcile/status',\n { method: 'GET' },\n async ({ context, json, request }) => {\n if (opts.token && request?.headers.get('x-reconcile-token') !== opts.token) {\n return Promise.reject(\n new APIError('UNAUTHORIZED', { message: 'invalid token' }) as Error,\n )\n }\n return json((context as PayloadSyncPluginContext).payloadSyncPlugin.queue.status())\n },\n ),\n // convenience for tests/admin tools (optional)\n authMethods: createAuthEndpoint(\n '/auth/methods',\n { method: 'GET' },\n async ({ context, json }) => {\n const authMethods: string[] = []\n\n // Check if emailAndPassword is enabled, or if present at all (not present defaults to false)\n if (context.options.emailAndPassword?.enabled) {\n authMethods.push('emailAndPassword')\n }\n\n return await json({ authMethods })\n },\n ),\n deleteNow: createAuthEndpoint(\n '/reconcile/delete',\n { method: 'POST' },\n async ({ context, json, request }) => {\n if (opts.token && request?.headers.get('x-reconcile-token') !== opts.token) {\n throw new APIError('UNAUTHORIZED', { message: 'invalid token' })\n }\n const body = (await request?.json().catch(() => ({}))) as { baId?: string } | undefined\n const baId = body?.baId\n if (!baId) {\n throw new APIError('BAD_REQUEST', { message: 'missing baId' })\n }\n ;(context as PayloadSyncPluginContext).payloadSyncPlugin.queue.enqueueDelete(\n baId,\n true,\n 'user-operation',\n )\n return json({ ok: true })\n },\n ),\n ensureNow: createAuthEndpoint(\n '/reconcile/ensure',\n { method: 'POST' },\n async ({ context, json, request }) => {\n if (opts.token && request?.headers.get('x-reconcile-token') !== opts.token) {\n throw new APIError('UNAUTHORIZED', { message: 'invalid token' })\n }\n const body = (await request?.json().catch(() => ({}))) as { user?: BAUser } | undefined\n const user = body?.user\n if (!user?.id) {\n throw new APIError('BAD_REQUEST', { message: 'missing user' })\n }\n ;(context as PayloadSyncPluginContext).payloadSyncPlugin.queue.enqueueEnsure(\n user,\n true,\n 'user-operation',\n )\n return json({ ok: true })\n },\n ),\n },\n // TODO: the queue must be destroyed on better auth instance destruction, as it utilizes timers.\n async init({ internalAdapter, password }) {\n if (opts.createAdmins) {\n try {\n await Promise.all(\n opts.createAdmins.map(async ({ overwrite, user }) => {\n const alreadyExistingUser = await internalAdapter.findUserByEmail(user.email)\n if (alreadyExistingUser) {\n if (overwrite) {\n // clear accounts\n await internalAdapter.deleteAccounts(alreadyExistingUser.user.id)\n const createdUser = await internalAdapter.updateUser(\n alreadyExistingUser.user.id,\n {\n ...user,\n role: 'admin',\n },\n )\n // assuming this creates an account?\n await internalAdapter.linkAccount({\n accountId: createdUser.id,\n password: await password.hash(user.password),\n providerId: 'credential',\n userId: createdUser.id,\n })\n }\n }\n // if the user doesnt exist there can't be an account\n else {\n const createdUser = await internalAdapter.createUser({ ...user, role: 'admin' })\n await internalAdapter.linkAccount({\n accountId: createdUser.id,\n password: await password.hash(user.password),\n providerId: 'credential',\n userId: createdUser.id,\n })\n }\n }),\n )\n } catch (error) {\n if (opts.enableLogging) {\n defaultLog('Failed to create Admin user', error)\n }\n }\n }\n\n const queue = new Queue(\n {\n deleteUserFromPayload: createDeleteUserFromPayload(opts.payloadConfig),\n internalAdapter,\n listPayloadUsersPage: createListPayloadUsersPage(opts.payloadConfig),\n log: opts.enableLogging ? defaultLog : undefined,\n syncUserToPayload: createSyncUserToPayload(opts.payloadConfig),\n },\n opts,\n )\n return {\n context: { payloadSyncPlugin: { queue } } as DeepPartial<Omit<AuthContext, 'options'>>,\n options: {\n databaseHooks: createDatabaseHooks({ config: opts.payloadConfig }),\n user: { deleteUser: { enabled: true } },\n },\n }\n },\n }\n}\n"],"names":["APIError","createAuthEndpoint","createDatabaseHooks","Queue","createDeleteUserFromPayload","createListPayloadUsersPage","createSyncUserToPayload","defaultLog","msg","extra","console","log","JSON","stringify","payloadBetterAuthPlugin","opts","id","endpoints","run","method","context","json","request","token","headers","get","message","payloadSyncPlugin","queue","seedFullReconcile","ok","status","Promise","reject","authMethods","options","emailAndPassword","enabled","push","deleteNow","body","catch","baId","enqueueDelete","ensureNow","user","enqueueEnsure","init","internalAdapter","password","createAdmins","all","map","overwrite","alreadyExistingUser","findUserByEmail","email","deleteAccounts","createdUser","updateUser","role","linkAccount","accountId","hash","providerId","userId","createUser","error","enableLogging","deleteUserFromPayload","payloadConfig","listPayloadUsersPage","undefined","syncUserToPayload","databaseHooks","config","deleteUser"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/better-auth/plugin.ts"],"sourcesContent":["// src/plugins/reconcile-queue-plugin.ts\nimport type { AuthContext, BetterAuthPlugin, DeepPartial } from 'better-auth'\nimport type { SanitizedConfig } from 'payload'\n\nimport { APIError } from 'better-auth/api'\nimport { createAuthEndpoint, createAuthMiddleware } from 'better-auth/plugins'\n\nimport type { AuthMethod } from './helpers.js'\n\nimport { createDatabaseHooks } from './databaseHooks.js'\nimport { type InitOptions, Queue } from './reconcile-queue.js'\nimport {\n type BAUser,\n createDeleteUserFromPayload,\n createListPayloadUsersPage,\n createSyncUserToPayload,\n} from './sources.js'\n\ntype PayloadSyncPluginContext = { payloadSyncPlugin: { queue: Queue } } & AuthContext\n\ntype CreateAdminsUser = Parameters<AuthContext['internalAdapter']['createUser']>['0']\n\nconst defaultLog = (msg: string, extra?: unknown) => {\n console.log(`[reconcile] ${msg}`, extra ? JSON.stringify(extra, null, 2) : '')\n}\n\nexport const payloadBetterAuthPlugin = (\n opts: {\n createAdmins?: { overwrite?: boolean; user: CreateAdminsUser }[]\n enableLogging?: boolean\n payloadConfig: Promise<SanitizedConfig>\n token: string // simple header token for admin endpoints,\n } & InitOptions,\n): BetterAuthPlugin => {\n return {\n id: 'reconcile-queue-plugin',\n endpoints: {\n run: createAuthEndpoint(\n '/reconcile/run',\n { method: 'POST' },\n async ({ context, json, request }) => {\n if (opts.token && request?.headers.get('x-reconcile-token') !== opts.token) {\n throw new APIError('UNAUTHORIZED', { message: 'invalid token' })\n }\n await (context as PayloadSyncPluginContext).payloadSyncPlugin.queue.seedFullReconcile()\n return json({ ok: true })\n },\n ),\n status: createAuthEndpoint(\n '/reconcile/status',\n { method: 'GET' },\n async ({ context, json, request }) => {\n if (opts.token && request?.headers.get('x-reconcile-token') !== opts.token) {\n return Promise.reject(\n new APIError('UNAUTHORIZED', { message: 'invalid token' }) as Error,\n )\n }\n return json((context as PayloadSyncPluginContext).payloadSyncPlugin.queue.status())\n },\n ),\n // convenience for tests/admin tools (optional)\n authMethods: createAuthEndpoint(\n '/auth/methods',\n { method: 'GET' },\n async ({ context, json }) => {\n const authMethods: AuthMethod[] = []\n // Check if emailAndPassword is enabled, or if present at all (not present defaults to false)\n if (context.options.emailAndPassword?.enabled) {\n authMethods.push({\n method: 'emailAndPassword',\n options: {\n minPasswordLength: context.options.emailAndPassword.minPasswordLength ?? 0,\n },\n })\n }\n if (context.options.plugins?.some((p) => p.id === 'magic-link')) {\n authMethods.push({ method: 'magicLink' })\n }\n\n return await json(authMethods)\n },\n ),\n deleteNow: createAuthEndpoint(\n '/reconcile/delete',\n { method: 'POST' },\n async ({ context, json, request }) => {\n if (opts.token && request?.headers.get('x-reconcile-token') !== opts.token) {\n throw new APIError('UNAUTHORIZED', { message: 'invalid token' })\n }\n const body = (await request?.json().catch(() => ({}))) as { baId?: string } | undefined\n const baId = body?.baId\n if (!baId) {\n throw new APIError('BAD_REQUEST', { message: 'missing baId' })\n }\n ;(context as PayloadSyncPluginContext).payloadSyncPlugin.queue.enqueueDelete(\n baId,\n true,\n 'user-operation',\n )\n return json({ ok: true })\n },\n ),\n ensureNow: createAuthEndpoint(\n '/reconcile/ensure',\n { method: 'POST' },\n async ({ context, json, request }) => {\n if (opts.token && request?.headers.get('x-reconcile-token') !== opts.token) {\n throw new APIError('UNAUTHORIZED', { message: 'invalid token' })\n }\n const body = (await request?.json().catch(() => ({}))) as { user?: BAUser } | undefined\n const user = body?.user\n if (!user?.id) {\n throw new APIError('BAD_REQUEST', { message: 'missing user' })\n }\n ;(context as PayloadSyncPluginContext).payloadSyncPlugin.queue.enqueueEnsure(\n user,\n true,\n 'user-operation',\n )\n return json({ ok: true })\n },\n ),\n },\n hooks: {\n before: [\n {\n handler: createAuthMiddleware(async (ctx) => {\n const locale = ctx.getHeader('User-Locale')\n return Promise.resolve({\n context: { ...ctx, body: { ...ctx.body, locale: locale ?? undefined } },\n })\n }),\n matcher: (context) => {\n return context.path === '/sign-up/email'\n },\n },\n ],\n },\n schema: {\n user: {\n fields: {\n locale: {\n type: 'string',\n required: false,\n },\n },\n },\n },\n // TODO: the queue must be destroyed on better auth instance destruction, as it utilizes timers.\n async init({ internalAdapter, password }) {\n if (opts.createAdmins) {\n try {\n await Promise.all(\n opts.createAdmins.map(async ({ overwrite, user }) => {\n const alreadyExistingUser = await internalAdapter.findUserByEmail(user.email)\n if (alreadyExistingUser) {\n if (overwrite) {\n // clear accounts\n await internalAdapter.deleteAccounts(alreadyExistingUser.user.id)\n const createdUser = await internalAdapter.updateUser(\n alreadyExistingUser.user.id,\n {\n ...user,\n role: 'admin',\n },\n )\n // assuming this creates an account?\n await internalAdapter.linkAccount({\n accountId: createdUser.id,\n password: await password.hash(user.password),\n providerId: 'credential',\n userId: createdUser.id,\n })\n }\n }\n // if the user doesnt exist there can't be an account\n else {\n const createdUser = await internalAdapter.createUser({ ...user, role: 'admin' })\n await internalAdapter.linkAccount({\n accountId: createdUser.id,\n password: await password.hash(user.password),\n providerId: 'credential',\n userId: createdUser.id,\n })\n }\n }),\n )\n } catch (error) {\n if (opts.enableLogging) {\n defaultLog('Failed to create Admin user', error)\n }\n }\n }\n\n const queue = new Queue(\n {\n deleteUserFromPayload: createDeleteUserFromPayload(opts.payloadConfig),\n internalAdapter,\n listPayloadUsersPage: createListPayloadUsersPage(opts.payloadConfig),\n log: opts.enableLogging ? defaultLog : undefined,\n syncUserToPayload: createSyncUserToPayload(opts.payloadConfig),\n },\n opts,\n )\n return {\n context: { payloadSyncPlugin: { queue } } as DeepPartial<Omit<AuthContext, 'options'>>,\n options: {\n databaseHooks: createDatabaseHooks({ config: opts.payloadConfig }),\n user: { deleteUser: { enabled: true } },\n },\n }\n },\n }\n}\n"],"names":["APIError","createAuthEndpoint","createAuthMiddleware","createDatabaseHooks","Queue","createDeleteUserFromPayload","createListPayloadUsersPage","createSyncUserToPayload","defaultLog","msg","extra","console","log","JSON","stringify","payloadBetterAuthPlugin","opts","id","endpoints","run","method","context","json","request","token","headers","get","message","payloadSyncPlugin","queue","seedFullReconcile","ok","status","Promise","reject","authMethods","options","emailAndPassword","enabled","push","minPasswordLength","plugins","some","p","deleteNow","body","catch","baId","enqueueDelete","ensureNow","user","enqueueEnsure","hooks","before","handler","ctx","locale","getHeader","resolve","undefined","matcher","path","schema","fields","type","required","init","internalAdapter","password","createAdmins","all","map","overwrite","alreadyExistingUser","findUserByEmail","email","deleteAccounts","createdUser","updateUser","role","linkAccount","accountId","hash","providerId","userId","createUser","error","enableLogging","deleteUserFromPayload","payloadConfig","listPayloadUsersPage","syncUserToPayload","databaseHooks","config","deleteUser"],"mappings":"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"}
@@ -1,5 +1,16 @@
1
1
  import type { createAuthClient } from 'better-auth/react';
2
2
  import type React from 'react';
3
- export declare function BetterAuthLoginServer({ authClientOptions, }: {
3
+ import type { AuthMethod } from 'src/better-auth/helpers.js';
4
+ export declare function fetchAuthMethods({ baseUrl, }: {
5
+ baseUrl: string;
6
+ }): Promise<{
7
+ data: AuthMethod[];
8
+ error: null;
9
+ } | {
10
+ data: null;
11
+ error: Error;
12
+ }>;
13
+ export declare function BetterAuthLoginServer({ authClientOptions, baseUrl, }: {
4
14
  authClientOptions: Parameters<typeof createAuthClient>['0'];
15
+ baseUrl: string;
5
16
  }): Promise<React.JSX.Element>;
@@ -1,9 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { EmailPasswordFormClient } from './EmailPasswordFormClient.js';
3
- async function fetchAuthMethods() {
3
+ export async function fetchAuthMethods({ baseUrl }) {
4
4
  try {
5
- const baseURL = process.env.NEXT_PUBLIC_SERVER_URL || 'http://localhost:3000';
6
- const response = await fetch(`${baseURL}/api/auth/auth/methods`, {
5
+ const response = await fetch(`${baseUrl}/api/auth/auth/methods`, {
7
6
  headers: {
8
7
  'Content-Type': 'application/json'
9
8
  },
@@ -13,19 +12,22 @@ async function fetchAuthMethods() {
13
12
  throw new Error(`Failed to fetch auth methods: ${response.status}`);
14
13
  }
15
14
  const data = await response.json();
16
- return data;
15
+ return {
16
+ data,
17
+ error: null
18
+ };
17
19
  } catch (error) {
18
20
  console.error('Error fetching auth methods:', error);
19
- // Return default fallback
20
21
  return {
21
- authMethods: [
22
- 'emailAndPassword'
23
- ]
22
+ data: null,
23
+ error: error
24
24
  };
25
25
  }
26
26
  }
27
- export async function BetterAuthLoginServer({ authClientOptions }) {
28
- const { authMethods } = await fetchAuthMethods();
27
+ export async function BetterAuthLoginServer({ authClientOptions, baseUrl }) {
28
+ const authMethods = await fetchAuthMethods({
29
+ baseUrl
30
+ });
29
31
  return /*#__PURE__*/ _jsx("div", {
30
32
  style: {
31
33
  alignItems: 'center',
@@ -52,10 +54,12 @@ export async function BetterAuthLoginServer({ authClientOptions }) {
52
54
  },
53
55
  children: "Sign In to Admin"
54
56
  }),
55
- authMethods.includes('emailAndPassword') && /*#__PURE__*/ _jsx(EmailPasswordFormClient, {
56
- authClientOptions: authClientOptions
57
+ authMethods.data?.some((m)=>m.method === 'emailAndPassword' || m.method === 'magicLink') && /*#__PURE__*/ _jsx(EmailPasswordFormClient, {
58
+ authClientOptions: authClientOptions,
59
+ authMethods: authMethods.data,
60
+ baseUrl: baseUrl
57
61
  }),
58
- authMethods.length === 0 && /*#__PURE__*/ _jsxs("div", {
62
+ authMethods.data?.length === 0 && /*#__PURE__*/ _jsxs("div", {
59
63
  style: {
60
64
  color: '#666',
61
65
  padding: '2rem',
@@ -73,6 +77,25 @@ export async function BetterAuthLoginServer({ authClientOptions }) {
73
77
  children: "Please contact your administrator."
74
78
  })
75
79
  ]
80
+ }),
81
+ authMethods.error && /*#__PURE__*/ _jsxs("div", {
82
+ style: {
83
+ color: '#666',
84
+ padding: '2rem',
85
+ textAlign: 'center'
86
+ },
87
+ children: [
88
+ /*#__PURE__*/ _jsx("p", {
89
+ children: "Couldn't fetch authentication methods from better-auth"
90
+ }),
91
+ /*#__PURE__*/ _jsx("p", {
92
+ style: {
93
+ fontSize: '0.875rem',
94
+ marginTop: '1rem'
95
+ },
96
+ children: "Please contact your administrator."
97
+ })
98
+ ]
76
99
  })
77
100
  ]
78
101
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/BetterAuthLoginServer.tsx"],"sourcesContent":["import type { createAuthClient } from 'better-auth/react'\nimport type React from 'react'\n\nimport { EmailPasswordFormClient } from './EmailPasswordFormClient.js'\n\ninterface AuthMethods {\n authMethods: 'emailAndPassword'[]\n}\n\nasync function fetchAuthMethods(): Promise<AuthMethods> {\n try {\n const baseURL = process.env.NEXT_PUBLIC_SERVER_URL || 'http://localhost:3000'\n const response = await fetch(`${baseURL}/api/auth/auth/methods`, {\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'GET',\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch auth methods: ${response.status}`)\n }\n\n const data = await response.json()\n return data as AuthMethods\n } catch (error) {\n console.error('Error fetching auth methods:', error)\n // Return default fallback\n return { authMethods: ['emailAndPassword'] }\n }\n}\n\nexport async function BetterAuthLoginServer({\n authClientOptions,\n}: {\n authClientOptions: Parameters<typeof createAuthClient>['0']\n}) {\n const { authMethods } = await fetchAuthMethods()\n\n return (\n <div\n style={{\n alignItems: 'center',\n display: 'flex',\n justifyContent: 'center',\n }}\n >\n <div\n style={{\n background: 'white',\n borderRadius: '8px',\n boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',\n maxWidth: '400px',\n padding: '2rem',\n width: '100%',\n }}\n >\n <h2\n style={{\n color: '#333',\n fontSize: '1.5rem',\n fontWeight: '600',\n marginBottom: '2rem',\n textAlign: 'center',\n }}\n >\n Sign In to Admin\n </h2>\n\n {authMethods.includes('emailAndPassword') && (\n <EmailPasswordFormClient authClientOptions={authClientOptions} />\n )}\n {authMethods.length === 0 && (\n <div\n style={{\n color: '#666',\n padding: '2rem',\n textAlign: 'center',\n }}\n >\n <p>No authentication methods are currently available.</p>\n <p style={{ fontSize: '0.875rem', marginTop: '1rem' }}>\n Please contact your administrator.\n </p>\n </div>\n )}\n </div>\n </div>\n )\n}\n"],"names":["EmailPasswordFormClient","fetchAuthMethods","baseURL","process","env","NEXT_PUBLIC_SERVER_URL","response","fetch","headers","method","ok","Error","status","data","json","error","console","authMethods","BetterAuthLoginServer","authClientOptions","div","style","alignItems","display","justifyContent","background","borderRadius","boxShadow","maxWidth","padding","width","h2","color","fontSize","fontWeight","marginBottom","textAlign","includes","length","p","marginTop"],"mappings":";AAGA,SAASA,uBAAuB,QAAQ,+BAA8B;AAMtE,eAAeC;IACb,IAAI;QACF,MAAMC,UAAUC,QAAQC,GAAG,CAACC,sBAAsB,IAAI;QACtD,MAAMC,WAAW,MAAMC,MAAM,GAAGL,QAAQ,sBAAsB,CAAC,EAAE;YAC/DM,SAAS;gBACP,gBAAgB;YAClB;YACAC,QAAQ;QACV;QAEA,IAAI,CAACH,SAASI,EAAE,EAAE;YAChB,MAAM,IAAIC,MAAM,CAAC,8BAA8B,EAAEL,SAASM,MAAM,EAAE;QACpE;QAEA,MAAMC,OAAO,MAAMP,SAASQ,IAAI;QAChC,OAAOD;IACT,EAAE,OAAOE,OAAO;QACdC,QAAQD,KAAK,CAAC,gCAAgCA;QAC9C,0BAA0B;QAC1B,OAAO;YAAEE,aAAa;gBAAC;aAAmB;QAAC;IAC7C;AACF;AAEA,OAAO,eAAeC,sBAAsB,EAC1CC,iBAAiB,EAGlB;IACC,MAAM,EAAEF,WAAW,EAAE,GAAG,MAAMhB;IAE9B,qBACE,KAACmB;QACCC,OAAO;YACLC,YAAY;YACZC,SAAS;YACTC,gBAAgB;QAClB;kBAEA,cAAA,MAACJ;YACCC,OAAO;gBACLI,YAAY;gBACZC,cAAc;gBACdC,WAAW;gBACXC,UAAU;gBACVC,SAAS;gBACTC,OAAO;YACT;;8BAEA,KAACC;oBACCV,OAAO;wBACLW,OAAO;wBACPC,UAAU;wBACVC,YAAY;wBACZC,cAAc;wBACdC,WAAW;oBACb;8BACD;;gBAIAnB,YAAYoB,QAAQ,CAAC,qCACpB,KAACrC;oBAAwBmB,mBAAmBA;;gBAE7CF,YAAYqB,MAAM,KAAK,mBACtB,MAAClB;oBACCC,OAAO;wBACLW,OAAO;wBACPH,SAAS;wBACTO,WAAW;oBACb;;sCAEA,KAACG;sCAAE;;sCACH,KAACA;4BAAElB,OAAO;gCAAEY,UAAU;gCAAYO,WAAW;4BAAO;sCAAG;;;;;;;AAQnE"}
1
+ {"version":3,"sources":["../../src/components/BetterAuthLoginServer.tsx"],"sourcesContent":["import type { createAuthClient } from 'better-auth/react'\nimport type React from 'react'\nimport type { AuthMethod } from 'src/better-auth/helpers.js'\n\nimport { EmailPasswordFormClient } from './EmailPasswordFormClient.js'\n\nexport async function fetchAuthMethods({\n baseUrl,\n}: {\n baseUrl: string\n}): Promise<{ data: AuthMethod[]; error: null } | { data: null; error: Error }> {\n try {\n const response = await fetch(`${baseUrl}/api/auth/auth/methods`, {\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'GET',\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch auth methods: ${response.status}`)\n }\n\n const data = await response.json()\n return { data, error: null } as { data: AuthMethod[]; error: null }\n } catch (error) {\n console.error('Error fetching auth methods:', error)\n return { data: null, error: error as Error }\n }\n}\n\nexport async function BetterAuthLoginServer({\n authClientOptions,\n baseUrl,\n}: {\n authClientOptions: Parameters<typeof createAuthClient>['0']\n baseUrl: string\n}) {\n const authMethods = await fetchAuthMethods({ baseUrl })\n\n return (\n <div\n style={{\n alignItems: 'center',\n display: 'flex',\n justifyContent: 'center',\n }}\n >\n <div\n style={{\n background: 'white',\n borderRadius: '8px',\n boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',\n maxWidth: '400px',\n padding: '2rem',\n width: '100%',\n }}\n >\n <h2\n style={{\n color: '#333',\n fontSize: '1.5rem',\n fontWeight: '600',\n marginBottom: '2rem',\n textAlign: 'center',\n }}\n >\n Sign In to Admin\n </h2>\n\n {authMethods.data?.some(\n (m) => m.method === 'emailAndPassword' || m.method === 'magicLink',\n ) && (\n <EmailPasswordFormClient\n authClientOptions={authClientOptions}\n authMethods={authMethods.data}\n baseUrl={baseUrl}\n />\n )}\n {authMethods.data?.length === 0 && (\n <div\n style={{\n color: '#666',\n padding: '2rem',\n textAlign: 'center',\n }}\n >\n <p>No authentication methods are currently available.</p>\n <p style={{ fontSize: '0.875rem', marginTop: '1rem' }}>\n Please contact your administrator.\n </p>\n </div>\n )}\n {authMethods.error && (\n <div\n style={{\n color: '#666',\n padding: '2rem',\n textAlign: 'center',\n }}\n >\n <p>Couldn't fetch authentication methods from better-auth</p>\n <p style={{ fontSize: '0.875rem', marginTop: '1rem' }}>\n Please contact your administrator.\n </p>\n </div>\n )}\n </div>\n </div>\n )\n}\n"],"names":["EmailPasswordFormClient","fetchAuthMethods","baseUrl","response","fetch","headers","method","ok","Error","status","data","json","error","console","BetterAuthLoginServer","authClientOptions","authMethods","div","style","alignItems","display","justifyContent","background","borderRadius","boxShadow","maxWidth","padding","width","h2","color","fontSize","fontWeight","marginBottom","textAlign","some","m","length","p","marginTop"],"mappings":";AAIA,SAASA,uBAAuB,QAAQ,+BAA8B;AAEtE,OAAO,eAAeC,iBAAiB,EACrCC,OAAO,EAGR;IACC,IAAI;QACF,MAAMC,WAAW,MAAMC,MAAM,GAAGF,QAAQ,sBAAsB,CAAC,EAAE;YAC/DG,SAAS;gBACP,gBAAgB;YAClB;YACAC,QAAQ;QACV;QAEA,IAAI,CAACH,SAASI,EAAE,EAAE;YAChB,MAAM,IAAIC,MAAM,CAAC,8BAA8B,EAAEL,SAASM,MAAM,EAAE;QACpE;QAEA,MAAMC,OAAO,MAAMP,SAASQ,IAAI;QAChC,OAAO;YAAED;YAAME,OAAO;QAAK;IAC7B,EAAE,OAAOA,OAAO;QACdC,QAAQD,KAAK,CAAC,gCAAgCA;QAC9C,OAAO;YAAEF,MAAM;YAAME,OAAOA;QAAe;IAC7C;AACF;AAEA,OAAO,eAAeE,sBAAsB,EAC1CC,iBAAiB,EACjBb,OAAO,EAIR;IACC,MAAMc,cAAc,MAAMf,iBAAiB;QAAEC;IAAQ;IAErD,qBACE,KAACe;QACCC,OAAO;YACLC,YAAY;YACZC,SAAS;YACTC,gBAAgB;QAClB;kBAEA,cAAA,MAACJ;YACCC,OAAO;gBACLI,YAAY;gBACZC,cAAc;gBACdC,WAAW;gBACXC,UAAU;gBACVC,SAAS;gBACTC,OAAO;YACT;;8BAEA,KAACC;oBACCV,OAAO;wBACLW,OAAO;wBACPC,UAAU;wBACVC,YAAY;wBACZC,cAAc;wBACdC,WAAW;oBACb;8BACD;;gBAIAjB,YAAYN,IAAI,EAAEwB,KACjB,CAACC,IAAMA,EAAE7B,MAAM,KAAK,sBAAsB6B,EAAE7B,MAAM,KAAK,8BAEvD,KAACN;oBACCe,mBAAmBA;oBACnBC,aAAaA,YAAYN,IAAI;oBAC7BR,SAASA;;gBAGZc,YAAYN,IAAI,EAAE0B,WAAW,mBAC5B,MAACnB;oBACCC,OAAO;wBACLW,OAAO;wBACPH,SAAS;wBACTO,WAAW;oBACb;;sCAEA,KAACI;sCAAE;;sCACH,KAACA;4BAAEnB,OAAO;gCAAEY,UAAU;gCAAYQ,WAAW;4BAAO;sCAAG;;;;gBAK1DtB,YAAYJ,KAAK,kBAChB,MAACK;oBACCC,OAAO;wBACLW,OAAO;wBACPH,SAAS;wBACTO,WAAW;oBACb;;sCAEA,KAACI;sCAAE;;sCACH,KAACA;4BAAEnB,OAAO;gCAAEY,UAAU;gCAAYQ,WAAW;4BAAO;sCAAG;;;;;;;AAQnE"}
@@ -1,5 +1,8 @@
1
1
  import type { default as React } from 'react';
2
+ import type { AuthMethod } from 'src/better-auth/helpers.js';
2
3
  import { createAuthClient } from 'better-auth/react';
3
- export declare function EmailPasswordFormClient({ authClientOptions, }: {
4
+ export declare function EmailPasswordFormClient({ authClientOptions, authMethods, baseUrl, }: {
4
5
  authClientOptions: Parameters<typeof createAuthClient>['0'];
6
+ authMethods: AuthMethod[];
7
+ baseUrl: string;
5
8
  }): React.JSX.Element;
@@ -1,17 +1,29 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Button, FieldLabel, TextInput } from '@payloadcms/ui';
4
+ import { magicLinkClient } from 'better-auth/client/plugins';
4
5
  import { createAuthClient } from 'better-auth/react';
5
6
  import { useRouter } from 'next/navigation.js';
6
7
  import { useState } from 'react';
7
- export function EmailPasswordFormClient({ authClientOptions }) {
8
- const authClient = createAuthClient(authClientOptions);
8
+ export function EmailPasswordFormClient({ authClientOptions, authMethods, baseUrl }) {
9
+ const authClient = createAuthClient({
10
+ ...authClientOptions,
11
+ plugins: [
12
+ ...authClientOptions?.plugins?.filter((p)=>p.id !== 'magic-link') ?? [],
13
+ magicLinkClient()
14
+ ]
15
+ });
9
16
  const router = useRouter();
10
17
  const [errors, setErrors] = useState({});
11
18
  const [isLoading, setIsLoading] = useState(false);
12
19
  // Use useField hooks for each input to get proper setValue functions
13
20
  const [emailValue, setEmailValue] = useState('');
14
21
  const [passwordValue, setPasswordValue] = useState('');
22
+ const withEmailAndPassword = authMethods.find((m)=>m.method === 'emailAndPassword');
23
+ const withMagicLink = authMethods.find((m)=>m.method === 'magicLink');
24
+ if (!withEmailAndPassword && !withMagicLink) {
25
+ throw new Error("This Form can't render with neither email nor magicLink activated.");
26
+ }
15
27
  const handleEmailChange = (event)=>{
16
28
  setEmailValue(event.target.value);
17
29
  // Clear field-specific error when user starts typing
@@ -41,10 +53,13 @@ export function EmailPasswordFormClient({ authClientOptions }) {
41
53
  } else if (!/^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/.test(email)) {
42
54
  newErrors.email = 'Please enter a valid email address';
43
55
  }
44
- if (!password) {
45
- newErrors.password = 'Password is required';
46
- } else if (password.length < 6) {
47
- newErrors.password = 'Password must be at least 6 characters';
56
+ if (withEmailAndPassword && !withMagicLink) {
57
+ if (!password) {
58
+ newErrors.password = 'Password is required';
59
+ // TODO: verify if minPasswordLength is also set if not actively specified
60
+ } else if (password.length < withEmailAndPassword.options.minPasswordLength) {
61
+ newErrors.password = `Password must be at least ${withEmailAndPassword.options.minPasswordLength} characters`;
62
+ }
48
63
  }
49
64
  setErrors(newErrors);
50
65
  return Object.keys(newErrors).length === 0;
@@ -57,23 +72,38 @@ export function EmailPasswordFormClient({ authClientOptions }) {
57
72
  setIsLoading(true);
58
73
  setErrors({});
59
74
  try {
60
- const result = await authClient.signIn.email({
61
- email: String(emailValue || ''),
62
- password: String(passwordValue || '')
63
- });
64
- if (result.error) {
65
- setErrors({
66
- general: result.error.message || 'Sign in failed. Please check your credentials.'
75
+ if (withEmailAndPassword && passwordValue !== '') {
76
+ const result = await authClient.signIn.email({
77
+ email: String(emailValue || ''),
78
+ password: String(passwordValue || '')
79
+ });
80
+ if (result.error) {
81
+ setErrors({
82
+ general: result.error.message || 'Sign in failed. Please check your credentials.'
83
+ });
84
+ } else {
85
+ // Successful sign in - redirect to admin
86
+ router.push('/admin');
87
+ router.refresh();
88
+ }
89
+ } else if (withMagicLink && passwordValue === '') {
90
+ const result = await authClient.signIn.magicLink({
91
+ callbackURL: `${baseUrl}/admin`,
92
+ email: String(emailValue || '')
67
93
  });
68
- } else {
69
- // Successful sign in - redirect to admin
70
- router.push('/admin');
71
- router.refresh();
94
+ if (result.error) {
95
+ setErrors({
96
+ general: result.error.message || 'Sign in failed. Please check your credentials.'
97
+ });
98
+ } else {
99
+ // Successful sign in - redirect to admin
100
+ router.push('/admin/auth/verify-email');
101
+ router.refresh();
102
+ }
72
103
  }
73
104
  } catch (error) {
74
- console.error('Sign in error:', error);
75
105
  setErrors({
76
- general: 'An unexpected error occurred. Please try again.'
106
+ general: error.message
77
107
  });
78
108
  } finally{
79
109
  setIsLoading(false);
@@ -103,6 +133,7 @@ export function EmailPasswordFormClient({ authClientOptions }) {
103
133
  onChange: handleEmailChange,
104
134
  path: "email",
105
135
  readOnly: isLoading,
136
+ required: true,
106
137
  value: emailValue || ''
107
138
  }),
108
139
  errors.email && /*#__PURE__*/ _jsx("div", {
@@ -120,13 +151,14 @@ export function EmailPasswordFormClient({ authClientOptions }) {
120
151
  children: [
121
152
  /*#__PURE__*/ _jsx(FieldLabel, {
122
153
  htmlFor: "password",
123
- label: "Password",
124
- required: true
154
+ label: `Password ${withMagicLink && '(Optional)'}`,
155
+ required: !withMagicLink
125
156
  }),
126
157
  /*#__PURE__*/ _jsx(TextInput, {
127
158
  onChange: handlePasswordChange,
128
159
  path: "password",
129
160
  readOnly: isLoading,
161
+ required: !withMagicLink,
130
162
  value: passwordValue || ''
131
163
  }),
132
164
  errors.password && /*#__PURE__*/ _jsx("div", {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/EmailPasswordFormClient.tsx"],"sourcesContent":["'use client'\n\nimport type { ChangeEvent, default as React } from 'react'\n\nimport { Button, FieldLabel, TextInput } from '@payloadcms/ui'\nimport { createAuthClient } from 'better-auth/react'\nimport { useRouter } from 'next/navigation.js'\nimport { useState } from 'react'\n\ninterface FormErrors {\n email?: string\n general?: string\n password?: string\n}\n\nexport function EmailPasswordFormClient({\n authClientOptions,\n}: {\n authClientOptions: Parameters<typeof createAuthClient>['0']\n}) {\n const authClient = createAuthClient(authClientOptions)\n const router = useRouter()\n const [errors, setErrors] = useState<FormErrors>({})\n const [isLoading, setIsLoading] = useState(false)\n\n // Use useField hooks for each input to get proper setValue functions\n const [emailValue, setEmailValue] = useState('')\n const [passwordValue, setPasswordValue] = useState('')\n\n const handleEmailChange = (event: ChangeEvent<HTMLInputElement>) => {\n setEmailValue(event.target.value)\n // Clear field-specific error when user starts typing\n if (errors.email) {\n setErrors((prev) => ({ ...prev, email: undefined }))\n }\n }\n\n const handlePasswordChange = (event: ChangeEvent<HTMLInputElement>) => {\n setPasswordValue(event.target.value)\n // Clear field-specific error when user starts typing\n if (errors.password) {\n setErrors((prev) => ({ ...prev, password: undefined }))\n }\n }\n\n const validateForm = (): boolean => {\n const newErrors: FormErrors = {}\n const email = String(emailValue || '').trim()\n const password = String(passwordValue || '').trim()\n\n if (!email) {\n newErrors.email = 'Email is required'\n } else if (!/^[^\\s@]+@[^\\s@][^\\s.@]*\\.[^\\s@]+$/.test(email)) {\n newErrors.email = 'Please enter a valid email address'\n }\n\n if (!password) {\n newErrors.password = 'Password is required'\n } else if (password.length < 6) {\n newErrors.password = 'Password must be at least 6 characters'\n }\n\n setErrors(newErrors)\n return Object.keys(newErrors).length === 0\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n\n if (!validateForm()) {\n return\n }\n\n setIsLoading(true)\n setErrors({})\n\n try {\n const result = await authClient.signIn.email({\n email: String(emailValue || ''),\n password: String(passwordValue || ''),\n })\n\n if (result.error) {\n setErrors({\n general: result.error.message || 'Sign in failed. Please check your credentials.',\n })\n } else {\n // Successful sign in - redirect to admin\n router.push('/admin')\n router.refresh()\n }\n } catch (error) {\n console.error('Sign in error:', error)\n setErrors({\n general: 'An unexpected error occurred. Please try again.',\n })\n } finally {\n setIsLoading(false)\n }\n }\n\n const errorStyle = {\n color: '#dc2626',\n fontSize: '0.875rem',\n marginTop: '0.25rem',\n }\n\n return (\n <form className=\"email-password-form\" onSubmit={handleSubmit}>\n <div className=\"form-field\" style={{ marginBottom: '1.5rem' }}>\n <FieldLabel htmlFor=\"email\" label=\"Email\" required />\n <TextInput\n onChange={handleEmailChange}\n path=\"email\"\n readOnly={isLoading}\n value={emailValue || ''}\n />\n {errors.email && (\n <div className=\"field-error\" style={errorStyle}>\n {errors.email}\n </div>\n )}\n </div>\n\n <div className=\"form-field\" style={{ marginBottom: '1.5rem' }}>\n <FieldLabel htmlFor=\"password\" label=\"Password\" required />\n <TextInput\n onChange={handlePasswordChange}\n path=\"password\"\n readOnly={isLoading}\n value={passwordValue || ''}\n />\n {errors.password && (\n <div className=\"field-error\" style={errorStyle}>\n {errors.password}\n </div>\n )}\n </div>\n\n {errors.general && (\n <div\n className=\"general-error\"\n style={{\n ...errorStyle,\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: '0.375rem',\n marginBottom: '1rem',\n padding: '0.75rem',\n }}\n >\n {errors.general}\n </div>\n )}\n\n <Button buttonStyle=\"primary\" disabled={isLoading} size=\"large\" type=\"submit\">\n {isLoading ? 'Signing In...' : 'Sign In'}\n </Button>\n </form>\n )\n}\n"],"names":["Button","FieldLabel","TextInput","createAuthClient","useRouter","useState","EmailPasswordFormClient","authClientOptions","authClient","router","errors","setErrors","isLoading","setIsLoading","emailValue","setEmailValue","passwordValue","setPasswordValue","handleEmailChange","event","target","value","email","prev","undefined","handlePasswordChange","password","validateForm","newErrors","String","trim","test","length","Object","keys","handleSubmit","e","preventDefault","result","signIn","error","general","message","push","refresh","console","errorStyle","color","fontSize","marginTop","form","className","onSubmit","div","style","marginBottom","htmlFor","label","required","onChange","path","readOnly","backgroundColor","border","borderRadius","padding","buttonStyle","disabled","size","type"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/EmailPasswordFormClient.tsx"],"sourcesContent":["'use client'\n\nimport type { ChangeEvent, default as React } from 'react'\nimport type { AuthMethod } from 'src/better-auth/helpers.js'\n\nimport { Button, FieldLabel, TextInput } from '@payloadcms/ui'\nimport { magicLinkClient } from 'better-auth/client/plugins'\nimport { createAuthClient } from 'better-auth/react'\nimport { useRouter } from 'next/navigation.js'\nimport { useState } from 'react'\n\ninterface FormErrors {\n email?: string\n general?: string\n password?: string\n}\n\nexport function EmailPasswordFormClient({\n authClientOptions,\n authMethods,\n baseUrl,\n}: {\n authClientOptions: Parameters<typeof createAuthClient>['0']\n authMethods: AuthMethod[]\n baseUrl: string\n}) {\n const authClient = createAuthClient({\n ...authClientOptions,\n plugins: [\n ...(authClientOptions?.plugins?.filter((p) => p.id !== 'magic-link') ?? []),\n magicLinkClient(),\n ],\n })\n const router = useRouter()\n const [errors, setErrors] = useState<FormErrors>({})\n const [isLoading, setIsLoading] = useState(false)\n\n // Use useField hooks for each input to get proper setValue functions\n const [emailValue, setEmailValue] = useState('')\n const [passwordValue, setPasswordValue] = useState('')\n\n const withEmailAndPassword = authMethods.find((m) => m.method === 'emailAndPassword')\n const withMagicLink = authMethods.find((m) => m.method === 'magicLink')\n\n if (!withEmailAndPassword && !withMagicLink) {\n throw new Error(\"This Form can't render with neither email nor magicLink activated.\")\n }\n\n const handleEmailChange = (event: ChangeEvent<HTMLInputElement>) => {\n setEmailValue(event.target.value)\n // Clear field-specific error when user starts typing\n if (errors.email) {\n setErrors((prev) => ({ ...prev, email: undefined }))\n }\n }\n\n const handlePasswordChange = (event: ChangeEvent<HTMLInputElement>) => {\n setPasswordValue(event.target.value)\n // Clear field-specific error when user starts typing\n if (errors.password) {\n setErrors((prev) => ({ ...prev, password: undefined }))\n }\n }\n\n const validateForm = (): boolean => {\n const newErrors: FormErrors = {}\n const email = String(emailValue || '').trim()\n const password = String(passwordValue || '').trim()\n\n if (!email) {\n newErrors.email = 'Email is required'\n } else if (!/^[^\\s@]+@[^\\s@][^\\s.@]*\\.[^\\s@]+$/.test(email)) {\n newErrors.email = 'Please enter a valid email address'\n }\n\n if (withEmailAndPassword && !withMagicLink) {\n if (!password) {\n newErrors.password = 'Password is required'\n // TODO: verify if minPasswordLength is also set if not actively specified\n } else if (password.length < withEmailAndPassword.options.minPasswordLength) {\n newErrors.password = `Password must be at least ${withEmailAndPassword.options.minPasswordLength} characters`\n }\n }\n\n setErrors(newErrors)\n return Object.keys(newErrors).length === 0\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n\n if (!validateForm()) {\n return\n }\n\n setIsLoading(true)\n setErrors({})\n\n try {\n if (withEmailAndPassword && passwordValue !== '') {\n const result = await authClient.signIn.email({\n email: String(emailValue || ''),\n password: String(passwordValue || ''),\n })\n\n if (result.error) {\n setErrors({\n general: result.error.message || 'Sign in failed. Please check your credentials.',\n })\n } else {\n // Successful sign in - redirect to admin\n router.push('/admin')\n router.refresh()\n }\n } else if (withMagicLink && passwordValue === '') {\n const result = await authClient.signIn.magicLink({\n callbackURL: `${baseUrl}/admin`,\n email: String(emailValue || ''),\n })\n\n if (result.error) {\n setErrors({\n general: result.error.message || 'Sign in failed. Please check your credentials.',\n })\n } else {\n // Successful sign in - redirect to admin\n router.push('/admin/auth/verify-email')\n router.refresh()\n }\n }\n } catch (error) {\n setErrors({\n general: (error as Error).message,\n })\n } finally {\n setIsLoading(false)\n }\n }\n\n const errorStyle = {\n color: '#dc2626',\n fontSize: '0.875rem',\n marginTop: '0.25rem',\n }\n\n return (\n <form className=\"email-password-form\" onSubmit={handleSubmit}>\n <div className=\"form-field\" style={{ marginBottom: '1.5rem' }}>\n <FieldLabel htmlFor=\"email\" label=\"Email\" required />\n <TextInput\n onChange={handleEmailChange}\n path=\"email\"\n readOnly={isLoading}\n required\n value={emailValue || ''}\n />\n {errors.email && (\n <div className=\"field-error\" style={errorStyle}>\n {errors.email}\n </div>\n )}\n </div>\n\n <div className=\"form-field\" style={{ marginBottom: '1.5rem' }}>\n <FieldLabel\n htmlFor=\"password\"\n label={`Password ${withMagicLink && '(Optional)'}`}\n required={!withMagicLink}\n />\n <TextInput\n onChange={handlePasswordChange}\n path=\"password\"\n readOnly={isLoading}\n required={!withMagicLink}\n value={passwordValue || ''}\n />\n {errors.password && (\n <div className=\"field-error\" style={errorStyle}>\n {errors.password}\n </div>\n )}\n </div>\n\n {errors.general && (\n <div\n className=\"general-error\"\n style={{\n ...errorStyle,\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: '0.375rem',\n marginBottom: '1rem',\n padding: '0.75rem',\n }}\n >\n {errors.general}\n </div>\n )}\n\n <Button buttonStyle=\"primary\" disabled={isLoading} size=\"large\" type=\"submit\">\n {isLoading ? 'Signing In...' : 'Sign In'}\n </Button>\n </form>\n )\n}\n"],"names":["Button","FieldLabel","TextInput","magicLinkClient","createAuthClient","useRouter","useState","EmailPasswordFormClient","authClientOptions","authMethods","baseUrl","authClient","plugins","filter","p","id","router","errors","setErrors","isLoading","setIsLoading","emailValue","setEmailValue","passwordValue","setPasswordValue","withEmailAndPassword","find","m","method","withMagicLink","Error","handleEmailChange","event","target","value","email","prev","undefined","handlePasswordChange","password","validateForm","newErrors","String","trim","test","length","options","minPasswordLength","Object","keys","handleSubmit","e","preventDefault","result","signIn","error","general","message","push","refresh","magicLink","callbackURL","errorStyle","color","fontSize","marginTop","form","className","onSubmit","div","style","marginBottom","htmlFor","label","required","onChange","path","readOnly","backgroundColor","border","borderRadius","padding","buttonStyle","disabled","size","type"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function VerifyEmailInfoViewClient(): import("react").JSX.Element;
@@ -0,0 +1,63 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Link } from '@payloadcms/ui';
3
+ export function VerifyEmailInfoViewClient() {
4
+ return /*#__PURE__*/ _jsx("div", {
5
+ style: {
6
+ alignItems: 'center',
7
+ display: 'flex',
8
+ justifyContent: 'center',
9
+ minHeight: '100dvh',
10
+ padding: '1.5rem'
11
+ },
12
+ children: /*#__PURE__*/ _jsxs("div", {
13
+ style: {
14
+ background: 'white',
15
+ borderRadius: 8,
16
+ boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
17
+ maxWidth: 480,
18
+ padding: '2rem',
19
+ width: '100%'
20
+ },
21
+ children: [
22
+ /*#__PURE__*/ _jsx("h2", {
23
+ style: {
24
+ color: '#333',
25
+ fontSize: '1.5rem',
26
+ fontWeight: 600,
27
+ marginBottom: '0.75rem',
28
+ textAlign: 'center'
29
+ },
30
+ children: "Check your email"
31
+ }),
32
+ /*#__PURE__*/ _jsx("p", {
33
+ style: {
34
+ color: '#555',
35
+ fontSize: '0.9875rem',
36
+ lineHeight: 1.6,
37
+ marginBottom: '1.75rem',
38
+ textAlign: 'center'
39
+ },
40
+ children: "We’ve sent a magic sign-in link to your inbox. Open the email and click the link to continue. If you don’t see it, check your spam folder."
41
+ }),
42
+ /*#__PURE__*/ _jsxs("p", {
43
+ style: {
44
+ color: '#666',
45
+ fontSize: '0.9375rem',
46
+ marginTop: '1.5rem',
47
+ textAlign: 'center'
48
+ },
49
+ children: [
50
+ "Ready to try again?",
51
+ /*#__PURE__*/ _jsx(Link, {
52
+ href: "/admin/auth",
53
+ children: "Go back to sign-in"
54
+ }),
55
+ "."
56
+ ]
57
+ })
58
+ ]
59
+ })
60
+ });
61
+ }
62
+
63
+ //# sourceMappingURL=VerifyEmailInfoViewClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/VerifyEmailInfoViewClient.tsx"],"sourcesContent":["import { Link } from '@payloadcms/ui'\n\nexport function VerifyEmailInfoViewClient() {\n return (\n <div\n style={{\n alignItems: 'center',\n display: 'flex',\n justifyContent: 'center',\n minHeight: '100dvh',\n padding: '1.5rem',\n }}\n >\n <div\n style={{\n background: 'white',\n borderRadius: 8,\n boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',\n maxWidth: 480,\n padding: '2rem',\n width: '100%',\n }}\n >\n <h2\n style={{\n color: '#333',\n fontSize: '1.5rem',\n fontWeight: 600,\n marginBottom: '0.75rem',\n textAlign: 'center',\n }}\n >\n Check your email\n </h2>\n <p\n style={{\n color: '#555',\n fontSize: '0.9875rem',\n lineHeight: 1.6,\n marginBottom: '1.75rem',\n textAlign: 'center',\n }}\n >\n We’ve sent a magic sign-in link to your inbox. Open the email and click the link to\n continue. If you don’t see it, check your spam folder.\n </p>\n\n <p\n style={{\n color: '#666',\n fontSize: '0.9375rem',\n marginTop: '1.5rem',\n textAlign: 'center',\n }}\n >\n Ready to try again?\n <Link href=\"/admin/auth\">Go back to sign-in</Link>.\n </p>\n </div>\n </div>\n )\n}\n"],"names":["Link","VerifyEmailInfoViewClient","div","style","alignItems","display","justifyContent","minHeight","padding","background","borderRadius","boxShadow","maxWidth","width","h2","color","fontSize","fontWeight","marginBottom","textAlign","p","lineHeight","marginTop","href"],"mappings":";AAAA,SAASA,IAAI,QAAQ,iBAAgB;AAErC,OAAO,SAASC;IACd,qBACE,KAACC;QACCC,OAAO;YACLC,YAAY;YACZC,SAAS;YACTC,gBAAgB;YAChBC,WAAW;YACXC,SAAS;QACX;kBAEA,cAAA,MAACN;YACCC,OAAO;gBACLM,YAAY;gBACZC,cAAc;gBACdC,WAAW;gBACXC,UAAU;gBACVJ,SAAS;gBACTK,OAAO;YACT;;8BAEA,KAACC;oBACCX,OAAO;wBACLY,OAAO;wBACPC,UAAU;wBACVC,YAAY;wBACZC,cAAc;wBACdC,WAAW;oBACb;8BACD;;8BAGD,KAACC;oBACCjB,OAAO;wBACLY,OAAO;wBACPC,UAAU;wBACVK,YAAY;wBACZH,cAAc;wBACdC,WAAW;oBACb;8BACD;;8BAKD,MAACC;oBACCjB,OAAO;wBACLY,OAAO;wBACPC,UAAU;wBACVM,WAAW;wBACXH,WAAW;oBACb;;wBACD;sCAEC,KAACnB;4BAAKuB,MAAK;sCAAc;;wBAAyB;;;;;;AAK5D"}
@@ -1 +1 @@
1
- export { BeforeDashboardClient } from '../components/BeforeDashboardClient.js';
1
+ export { VerifyEmailInfoViewClient } from '../components/VerifyEmailInfoViewClient.js';
@@ -1,3 +1,3 @@
1
- export { BeforeDashboardClient } from '../components/BeforeDashboardClient.js';
1
+ export { VerifyEmailInfoViewClient } from '../components/VerifyEmailInfoViewClient.js';
2
2
 
3
3
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["export { BeforeDashboardClient } from '../components/BeforeDashboardClient.js'\n"],"names":["BeforeDashboardClient"],"mappings":"AAAA,SAASA,qBAAqB,QAAQ,yCAAwC"}
1
+ {"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["export { VerifyEmailInfoViewClient } from '../components/VerifyEmailInfoViewClient.js'\n"],"names":["VerifyEmailInfoViewClient"],"mappings":"AAAA,SAASA,yBAAyB,QAAQ,6CAA4C"}
@@ -2,6 +2,7 @@ import type { createAuthClient } from 'better-auth/react';
2
2
  import type { Config } from 'payload';
3
3
  export type BetterAuthPayloadPluginOptions = {
4
4
  authClientOptions: Parameters<typeof createAuthClient>['0'];
5
+ baseUrl: string;
5
6
  disabled?: boolean;
6
7
  };
7
8
  export declare const betterAuthPayloadPlugin: (pluginOptions: BetterAuthPayloadPluginOptions) => (config: Config) => Config;
@@ -38,9 +38,7 @@ export const betterAuthPayloadPlugin = (pluginOptions)=>(config)=>{
38
38
  }
39
39
  config.admin.components.beforeLogin.push({
40
40
  path: `payload-better-auth/rsc#BetterAuthLoginServer`,
41
- serverProps: {
42
- authClientOptions: pluginOptions.authClientOptions
43
- }
41
+ serverProps: pluginOptions
44
42
  });
45
43
  if (!config.admin.components.views) {
46
44
  config.admin.components.views = {};
@@ -54,6 +52,15 @@ export const betterAuthPayloadPlugin = (pluginOptions)=>(config)=>{
54
52
  } else {
55
53
  throw new Error('Payload-better-auth plugin: admin.components.views.login property in config already set.');
56
54
  }
55
+ if (!config.admin.components.views.verifyEmail) {
56
+ config.admin.components.views.verifyEmail = {
57
+ Component: 'payload-better-auth/client#VerifyEmailInfoViewClient',
58
+ exact: true,
59
+ path: '/auth/verify-email'
60
+ };
61
+ } else {
62
+ throw new Error('Payload-better-auth plugin: admin.components.views.verifyEmail property in config already set.');
63
+ }
57
64
  if (!config.admin.routes) {
58
65
  config.admin.routes = {};
59
66
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/payload/plugin.ts"],"sourcesContent":["import type { createAuthClient } from 'better-auth/react'\nimport type { Config } from 'payload'\n\nimport { createUsersCollection } from '../collections/Users/index.js'\nimport { triggerFullReconcile } from '../utils/payload-reconcile.js'\n\nexport type BetterAuthPayloadPluginOptions = {\n authClientOptions: Parameters<typeof createAuthClient>['0']\n disabled?: boolean\n}\n\nexport const betterAuthPayloadPlugin =\n (pluginOptions: BetterAuthPayloadPluginOptions) =>\n (config: Config): Config => {\n const Users = createUsersCollection({ authClientOptions: pluginOptions.authClientOptions })\n if (!config.collections) {\n config.collections = [Users]\n } else if (config.collections.find((col) => col.slug === 'users')) {\n throw new Error('Payload-better-auth plugin: Users collection already present')\n } else {\n config.collections.push(Users)\n }\n\n /**\n * If the plugin is disabled, we still want to keep added collections/fields so the database schema is consistent which is important for migrations.\n * If your plugin heavily modifies the database schema, you may want to remove this property.\n */\n if (pluginOptions.disabled) {\n return config\n }\n\n if (!config.endpoints) {\n config.endpoints = []\n }\n\n if (!config.admin) {\n config.admin = {}\n }\n\n if (!config.admin.user) {\n config.admin.user = Users.slug\n } else if (config.admin.user !== Users.slug) {\n throw new Error(\n 'Payload-better-auth plugin: admin.user property already set with conflicting value.',\n )\n }\n\n if (!config.admin.components) {\n config.admin.components = {}\n }\n\n if (!config.admin.components.beforeLogin) {\n config.admin.components.beforeLogin = []\n }\n\n config.admin.components.beforeLogin.push({\n path: `payload-better-auth/rsc#BetterAuthLoginServer`,\n serverProps: { authClientOptions: pluginOptions.authClientOptions },\n })\n\n if (!config.admin.components.views) {\n config.admin.components.views = {}\n }\n\n if (!config.admin.components.views.login) {\n config.admin.components.views.login = {\n Component: 'payload-better-auth/rsc#BetterAuthLoginServer', // RSC or 'use client' component\n exact: true,\n path: '/auth',\n }\n } else {\n throw new Error(\n 'Payload-better-auth plugin: admin.components.views.login property in config already set.',\n )\n }\n\n if (!config.admin.routes) {\n config.admin.routes = {}\n }\n\n if (!config.admin.routes.login) {\n config.admin.routes.login = '/auth'\n } else {\n throw new Error(\n 'Payload-better-auth plugin: admin.routes.login property in config already set.',\n )\n }\n\n const incomingOnInit = config.onInit\n\n config.onInit = async (payload) => {\n // Ensure we are executing any existing onInit functions before running our own.\n if (incomingOnInit) {\n await incomingOnInit(payload)\n }\n await triggerFullReconcile(payload)\n }\n\n return config\n }\n"],"names":["createUsersCollection","triggerFullReconcile","betterAuthPayloadPlugin","pluginOptions","config","Users","authClientOptions","collections","find","col","slug","Error","push","disabled","endpoints","admin","user","components","beforeLogin","path","serverProps","views","login","Component","exact","routes","incomingOnInit","onInit","payload"],"mappings":"AAGA,SAASA,qBAAqB,QAAQ,gCAA+B;AACrE,SAASC,oBAAoB,QAAQ,gCAA+B;AAOpE,OAAO,MAAMC,0BACX,CAACC,gBACD,CAACC;QACC,MAAMC,QAAQL,sBAAsB;YAAEM,mBAAmBH,cAAcG,iBAAiB;QAAC;QACzF,IAAI,CAACF,OAAOG,WAAW,EAAE;YACvBH,OAAOG,WAAW,GAAG;gBAACF;aAAM;QAC9B,OAAO,IAAID,OAAOG,WAAW,CAACC,IAAI,CAAC,CAACC,MAAQA,IAAIC,IAAI,KAAK,UAAU;YACjE,MAAM,IAAIC,MAAM;QAClB,OAAO;YACLP,OAAOG,WAAW,CAACK,IAAI,CAACP;QAC1B;QAEA;;;KAGC,GACD,IAAIF,cAAcU,QAAQ,EAAE;YAC1B,OAAOT;QACT;QAEA,IAAI,CAACA,OAAOU,SAAS,EAAE;YACrBV,OAAOU,SAAS,GAAG,EAAE;QACvB;QAEA,IAAI,CAACV,OAAOW,KAAK,EAAE;YACjBX,OAAOW,KAAK,GAAG,CAAC;QAClB;QAEA,IAAI,CAACX,OAAOW,KAAK,CAACC,IAAI,EAAE;YACtBZ,OAAOW,KAAK,CAACC,IAAI,GAAGX,MAAMK,IAAI;QAChC,OAAO,IAAIN,OAAOW,KAAK,CAACC,IAAI,KAAKX,MAAMK,IAAI,EAAE;YAC3C,MAAM,IAAIC,MACR;QAEJ;QAEA,IAAI,CAACP,OAAOW,KAAK,CAACE,UAAU,EAAE;YAC5Bb,OAAOW,KAAK,CAACE,UAAU,GAAG,CAAC;QAC7B;QAEA,IAAI,CAACb,OAAOW,KAAK,CAACE,UAAU,CAACC,WAAW,EAAE;YACxCd,OAAOW,KAAK,CAACE,UAAU,CAACC,WAAW,GAAG,EAAE;QAC1C;QAEAd,OAAOW,KAAK,CAACE,UAAU,CAACC,WAAW,CAACN,IAAI,CAAC;YACvCO,MAAM,CAAC,6CAA6C,CAAC;YACrDC,aAAa;gBAAEd,mBAAmBH,cAAcG,iBAAiB;YAAC;QACpE;QAEA,IAAI,CAACF,OAAOW,KAAK,CAACE,UAAU,CAACI,KAAK,EAAE;YAClCjB,OAAOW,KAAK,CAACE,UAAU,CAACI,KAAK,GAAG,CAAC;QACnC;QAEA,IAAI,CAACjB,OAAOW,KAAK,CAACE,UAAU,CAACI,KAAK,CAACC,KAAK,EAAE;YACxClB,OAAOW,KAAK,CAACE,UAAU,CAACI,KAAK,CAACC,KAAK,GAAG;gBACpCC,WAAW;gBACXC,OAAO;gBACPL,MAAM;YACR;QACF,OAAO;YACL,MAAM,IAAIR,MACR;QAEJ;QAEA,IAAI,CAACP,OAAOW,KAAK,CAACU,MAAM,EAAE;YACxBrB,OAAOW,KAAK,CAACU,MAAM,GAAG,CAAC;QACzB;QAEA,IAAI,CAACrB,OAAOW,KAAK,CAACU,MAAM,CAACH,KAAK,EAAE;YAC9BlB,OAAOW,KAAK,CAACU,MAAM,CAACH,KAAK,GAAG;QAC9B,OAAO;YACL,MAAM,IAAIX,MACR;QAEJ;QAEA,MAAMe,iBAAiBtB,OAAOuB,MAAM;QAEpCvB,OAAOuB,MAAM,GAAG,OAAOC;YACrB,gFAAgF;YAChF,IAAIF,gBAAgB;gBAClB,MAAMA,eAAeE;YACvB;YACA,MAAM3B,qBAAqB2B;QAC7B;QAEA,OAAOxB;IACT,EAAC"}
1
+ {"version":3,"sources":["../../src/payload/plugin.ts"],"sourcesContent":["import type { createAuthClient } from 'better-auth/react'\nimport type { Config } from 'payload'\n\nimport { createUsersCollection } from '../collections/Users/index.js'\nimport { triggerFullReconcile } from '../utils/payload-reconcile.js'\n\nexport type BetterAuthPayloadPluginOptions = {\n authClientOptions: Parameters<typeof createAuthClient>['0']\n baseUrl: string\n disabled?: boolean\n}\n\nexport const betterAuthPayloadPlugin =\n (pluginOptions: BetterAuthPayloadPluginOptions) =>\n (config: Config): Config => {\n const Users = createUsersCollection({ authClientOptions: pluginOptions.authClientOptions })\n if (!config.collections) {\n config.collections = [Users]\n } else if (config.collections.find((col) => col.slug === 'users')) {\n throw new Error('Payload-better-auth plugin: Users collection already present')\n } else {\n config.collections.push(Users)\n }\n\n /**\n * If the plugin is disabled, we still want to keep added collections/fields so the database schema is consistent which is important for migrations.\n * If your plugin heavily modifies the database schema, you may want to remove this property.\n */\n if (pluginOptions.disabled) {\n return config\n }\n\n if (!config.endpoints) {\n config.endpoints = []\n }\n\n if (!config.admin) {\n config.admin = {}\n }\n\n if (!config.admin.user) {\n config.admin.user = Users.slug\n } else if (config.admin.user !== Users.slug) {\n throw new Error(\n 'Payload-better-auth plugin: admin.user property already set with conflicting value.',\n )\n }\n\n if (!config.admin.components) {\n config.admin.components = {}\n }\n\n if (!config.admin.components.beforeLogin) {\n config.admin.components.beforeLogin = []\n }\n\n config.admin.components.beforeLogin.push({\n path: `payload-better-auth/rsc#BetterAuthLoginServer`,\n serverProps: pluginOptions,\n })\n\n if (!config.admin.components.views) {\n config.admin.components.views = {}\n }\n\n if (!config.admin.components.views.login) {\n config.admin.components.views.login = {\n Component: 'payload-better-auth/rsc#BetterAuthLoginServer', // RSC or 'use client' component\n exact: true,\n path: '/auth',\n }\n } else {\n throw new Error(\n 'Payload-better-auth plugin: admin.components.views.login property in config already set.',\n )\n }\n\n if (!config.admin.components.views.verifyEmail) {\n config.admin.components.views.verifyEmail = {\n Component: 'payload-better-auth/client#VerifyEmailInfoViewClient', // RSC or 'use client' component\n exact: true,\n path: '/auth/verify-email',\n }\n } else {\n throw new Error(\n 'Payload-better-auth plugin: admin.components.views.verifyEmail property in config already set.',\n )\n }\n\n if (!config.admin.routes) {\n config.admin.routes = {}\n }\n\n if (!config.admin.routes.login) {\n config.admin.routes.login = '/auth'\n } else {\n throw new Error(\n 'Payload-better-auth plugin: admin.routes.login property in config already set.',\n )\n }\n\n const incomingOnInit = config.onInit\n\n config.onInit = async (payload) => {\n // Ensure we are executing any existing onInit functions before running our own.\n if (incomingOnInit) {\n await incomingOnInit(payload)\n }\n await triggerFullReconcile(payload)\n }\n\n return config\n }\n"],"names":["createUsersCollection","triggerFullReconcile","betterAuthPayloadPlugin","pluginOptions","config","Users","authClientOptions","collections","find","col","slug","Error","push","disabled","endpoints","admin","user","components","beforeLogin","path","serverProps","views","login","Component","exact","verifyEmail","routes","incomingOnInit","onInit","payload"],"mappings":"AAGA,SAASA,qBAAqB,QAAQ,gCAA+B;AACrE,SAASC,oBAAoB,QAAQ,gCAA+B;AAQpE,OAAO,MAAMC,0BACX,CAACC,gBACD,CAACC;QACC,MAAMC,QAAQL,sBAAsB;YAAEM,mBAAmBH,cAAcG,iBAAiB;QAAC;QACzF,IAAI,CAACF,OAAOG,WAAW,EAAE;YACvBH,OAAOG,WAAW,GAAG;gBAACF;aAAM;QAC9B,OAAO,IAAID,OAAOG,WAAW,CAACC,IAAI,CAAC,CAACC,MAAQA,IAAIC,IAAI,KAAK,UAAU;YACjE,MAAM,IAAIC,MAAM;QAClB,OAAO;YACLP,OAAOG,WAAW,CAACK,IAAI,CAACP;QAC1B;QAEA;;;KAGC,GACD,IAAIF,cAAcU,QAAQ,EAAE;YAC1B,OAAOT;QACT;QAEA,IAAI,CAACA,OAAOU,SAAS,EAAE;YACrBV,OAAOU,SAAS,GAAG,EAAE;QACvB;QAEA,IAAI,CAACV,OAAOW,KAAK,EAAE;YACjBX,OAAOW,KAAK,GAAG,CAAC;QAClB;QAEA,IAAI,CAACX,OAAOW,KAAK,CAACC,IAAI,EAAE;YACtBZ,OAAOW,KAAK,CAACC,IAAI,GAAGX,MAAMK,IAAI;QAChC,OAAO,IAAIN,OAAOW,KAAK,CAACC,IAAI,KAAKX,MAAMK,IAAI,EAAE;YAC3C,MAAM,IAAIC,MACR;QAEJ;QAEA,IAAI,CAACP,OAAOW,KAAK,CAACE,UAAU,EAAE;YAC5Bb,OAAOW,KAAK,CAACE,UAAU,GAAG,CAAC;QAC7B;QAEA,IAAI,CAACb,OAAOW,KAAK,CAACE,UAAU,CAACC,WAAW,EAAE;YACxCd,OAAOW,KAAK,CAACE,UAAU,CAACC,WAAW,GAAG,EAAE;QAC1C;QAEAd,OAAOW,KAAK,CAACE,UAAU,CAACC,WAAW,CAACN,IAAI,CAAC;YACvCO,MAAM,CAAC,6CAA6C,CAAC;YACrDC,aAAajB;QACf;QAEA,IAAI,CAACC,OAAOW,KAAK,CAACE,UAAU,CAACI,KAAK,EAAE;YAClCjB,OAAOW,KAAK,CAACE,UAAU,CAACI,KAAK,GAAG,CAAC;QACnC;QAEA,IAAI,CAACjB,OAAOW,KAAK,CAACE,UAAU,CAACI,KAAK,CAACC,KAAK,EAAE;YACxClB,OAAOW,KAAK,CAACE,UAAU,CAACI,KAAK,CAACC,KAAK,GAAG;gBACpCC,WAAW;gBACXC,OAAO;gBACPL,MAAM;YACR;QACF,OAAO;YACL,MAAM,IAAIR,MACR;QAEJ;QAEA,IAAI,CAACP,OAAOW,KAAK,CAACE,UAAU,CAACI,KAAK,CAACI,WAAW,EAAE;YAC9CrB,OAAOW,KAAK,CAACE,UAAU,CAACI,KAAK,CAACI,WAAW,GAAG;gBAC1CF,WAAW;gBACXC,OAAO;gBACPL,MAAM;YACR;QACF,OAAO;YACL,MAAM,IAAIR,MACR;QAEJ;QAEA,IAAI,CAACP,OAAOW,KAAK,CAACW,MAAM,EAAE;YACxBtB,OAAOW,KAAK,CAACW,MAAM,GAAG,CAAC;QACzB;QAEA,IAAI,CAACtB,OAAOW,KAAK,CAACW,MAAM,CAACJ,KAAK,EAAE;YAC9BlB,OAAOW,KAAK,CAACW,MAAM,CAACJ,KAAK,GAAG;QAC9B,OAAO;YACL,MAAM,IAAIX,MACR;QAEJ;QAEA,MAAMgB,iBAAiBvB,OAAOwB,MAAM;QAEpCxB,OAAOwB,MAAM,GAAG,OAAOC;YACrB,gFAAgF;YAChF,IAAIF,gBAAgB;gBAClB,MAAMA,eAAeE;YACvB;YACA,MAAM5B,qBAAqB4B;QAC7B;QAEA,OAAOzB;IACT,EAAC"}
@@ -13,6 +13,7 @@
13
13
  const reconcileUrl = `${betterAuthUrl}/api/auth/reconcile/run`;
14
14
  payload.logger.info('Triggering full reconcile from Payload onInit...');
15
15
  const response = await fetch(reconcileUrl, {
16
+ body: JSON.stringify({}),
16
17
  headers: {
17
18
  'Content-Type': 'application/json',
18
19
  'x-reconcile-token': reconcileToken
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/payload-reconcile.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\n/**\n * Triggers a full reconcile operation via the Better Auth reconcile API\n * This is typically called during Payload initialization to ensure data consistency\n */\nexport async function triggerFullReconcile(payload: Payload): Promise<void> {\n try {\n const reconcileToken = process.env.RECONCILE_TOKEN\n if (!reconcileToken) {\n payload.logger.warn('RECONCILE_TOKEN not set, skipping onInit reconcile trigger')\n return\n }\n\n // Determine the better-auth server URL\n const betterAuthUrl = process.env.BETTER_AUTH_URL || 'http://localhost:3000'\n const reconcileUrl = `${betterAuthUrl}/api/auth/reconcile/run`\n\n payload.logger.info('Triggering full reconcile from Payload onInit...')\n\n const response = await fetch(reconcileUrl, {\n headers: {\n 'Content-Type': 'application/json',\n 'x-reconcile-token': reconcileToken,\n },\n method: 'POST',\n })\n\n if (!response.ok) {\n throw new Error(`Reconcile request failed: ${response.status} ${response.statusText}`)\n }\n\n const result = await response.json()\n payload.logger.info('Full reconcile triggered successfully from Payload onInit', { result })\n } catch (error) {\n payload.logger.error('Failed to trigger full reconcile from Payload onInit', { error })\n // Don't throw - we don't want to prevent Payload from starting if reconcile fails\n }\n}\n"],"names":["triggerFullReconcile","payload","reconcileToken","process","env","RECONCILE_TOKEN","logger","warn","betterAuthUrl","BETTER_AUTH_URL","reconcileUrl","info","response","fetch","headers","method","ok","Error","status","statusText","result","json","error"],"mappings":"AAEA;;;CAGC,GACD,OAAO,eAAeA,qBAAqBC,OAAgB;IACzD,IAAI;QACF,MAAMC,iBAAiBC,QAAQC,GAAG,CAACC,eAAe;QAClD,IAAI,CAACH,gBAAgB;YACnBD,QAAQK,MAAM,CAACC,IAAI,CAAC;YACpB;QACF;QAEA,uCAAuC;QACvC,MAAMC,gBAAgBL,QAAQC,GAAG,CAACK,eAAe,IAAI;QACrD,MAAMC,eAAe,GAAGF,cAAc,uBAAuB,CAAC;QAE9DP,QAAQK,MAAM,CAACK,IAAI,CAAC;QAEpB,MAAMC,WAAW,MAAMC,MAAMH,cAAc;YACzCI,SAAS;gBACP,gBAAgB;gBAChB,qBAAqBZ;YACvB;YACAa,QAAQ;QACV;QAEA,IAAI,CAACH,SAASI,EAAE,EAAE;YAChB,MAAM,IAAIC,MAAM,CAAC,0BAA0B,EAAEL,SAASM,MAAM,CAAC,CAAC,EAAEN,SAASO,UAAU,EAAE;QACvF;QAEA,MAAMC,SAAS,MAAMR,SAASS,IAAI;QAClCpB,QAAQK,MAAM,CAACK,IAAI,CAAC,6DAA6D;YAAES;QAAO;IAC5F,EAAE,OAAOE,OAAO;QACdrB,QAAQK,MAAM,CAACgB,KAAK,CAAC,wDAAwD;YAAEA;QAAM;IACrF,kFAAkF;IACpF;AACF"}
1
+ {"version":3,"sources":["../../src/utils/payload-reconcile.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\n/**\n * Triggers a full reconcile operation via the Better Auth reconcile API\n * This is typically called during Payload initialization to ensure data consistency\n */\nexport async function triggerFullReconcile(payload: Payload): Promise<void> {\n try {\n const reconcileToken = process.env.RECONCILE_TOKEN\n if (!reconcileToken) {\n payload.logger.warn('RECONCILE_TOKEN not set, skipping onInit reconcile trigger')\n return\n }\n\n // Determine the better-auth server URL\n const betterAuthUrl = process.env.BETTER_AUTH_URL || 'http://localhost:3000'\n const reconcileUrl = `${betterAuthUrl}/api/auth/reconcile/run`\n\n payload.logger.info('Triggering full reconcile from Payload onInit...')\n\n const response = await fetch(reconcileUrl, {\n body: JSON.stringify({}),\n headers: {\n 'Content-Type': 'application/json',\n 'x-reconcile-token': reconcileToken,\n },\n method: 'POST',\n })\n\n if (!response.ok) {\n throw new Error(`Reconcile request failed: ${response.status} ${response.statusText}`)\n }\n\n const result = await response.json()\n payload.logger.info('Full reconcile triggered successfully from Payload onInit', { result })\n } catch (error) {\n payload.logger.error('Failed to trigger full reconcile from Payload onInit', { error })\n // Don't throw - we don't want to prevent Payload from starting if reconcile fails\n }\n}\n"],"names":["triggerFullReconcile","payload","reconcileToken","process","env","RECONCILE_TOKEN","logger","warn","betterAuthUrl","BETTER_AUTH_URL","reconcileUrl","info","response","fetch","body","JSON","stringify","headers","method","ok","Error","status","statusText","result","json","error"],"mappings":"AAEA;;;CAGC,GACD,OAAO,eAAeA,qBAAqBC,OAAgB;IACzD,IAAI;QACF,MAAMC,iBAAiBC,QAAQC,GAAG,CAACC,eAAe;QAClD,IAAI,CAACH,gBAAgB;YACnBD,QAAQK,MAAM,CAACC,IAAI,CAAC;YACpB;QACF;QAEA,uCAAuC;QACvC,MAAMC,gBAAgBL,QAAQC,GAAG,CAACK,eAAe,IAAI;QACrD,MAAMC,eAAe,GAAGF,cAAc,uBAAuB,CAAC;QAE9DP,QAAQK,MAAM,CAACK,IAAI,CAAC;QAEpB,MAAMC,WAAW,MAAMC,MAAMH,cAAc;YACzCI,MAAMC,KAAKC,SAAS,CAAC,CAAC;YACtBC,SAAS;gBACP,gBAAgB;gBAChB,qBAAqBf;YACvB;YACAgB,QAAQ;QACV;QAEA,IAAI,CAACN,SAASO,EAAE,EAAE;YAChB,MAAM,IAAIC,MAAM,CAAC,0BAA0B,EAAER,SAASS,MAAM,CAAC,CAAC,EAAET,SAASU,UAAU,EAAE;QACvF;QAEA,MAAMC,SAAS,MAAMX,SAASY,IAAI;QAClCvB,QAAQK,MAAM,CAACK,IAAI,CAAC,6DAA6D;YAAEY;QAAO;IAC5F,EAAE,OAAOE,OAAO;QACdxB,QAAQK,MAAM,CAACmB,KAAK,CAAC,wDAAwD;YAAEA;QAAM;IACrF,kFAAkF;IACpF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payload-better-auth",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "A blank template to get started with Payload 3.0",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,6 +39,7 @@
39
39
  "@swc-node/register": "1.10.9",
40
40
  "@swc/cli": "0.6.0",
41
41
  "@types/node": "^22.18.6",
42
+ "@types/nodemailer": "^7.0.2",
42
43
  "@types/react": "19.1.8",
43
44
  "@types/react-dom": "19.1.6",
44
45
  "better-sqlite3": "^12.4.1",
@@ -50,8 +51,10 @@
50
51
  "eslint-config-next": "15.4.4",
51
52
  "execa": "^9.6.0",
52
53
  "graphql": "^16.11.0",
54
+ "maildev": "^2.2.1",
53
55
  "mongodb-memory-server": "10.1.4",
54
56
  "next": "15.4.4",
57
+ "nodemailer": "^7.0.6",
55
58
  "open": "^10.2.0",
56
59
  "payload": "^3.57.0",
57
60
  "prettier": "^3.6.2",
@@ -80,7 +83,8 @@
80
83
  "build:types": "tsc --outDir dist --rootDir ./src",
81
84
  "clean": "rimraf {dist,*.tsbuildinfo}",
82
85
  "copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
83
- "dev": "next dev dev --turbo",
86
+ "dev": "concurrently -k -n \"WEB,MAIL\" -c \"auto\" \"pnpm:dev:original\" \"pnpm:maildev\"",
87
+ "dev:original": "next dev dev --turbo",
84
88
  "dev:generate-importmap": "pnpm dev:payload generate:importmap",
85
89
  "dev:generate-types": "pnpm dev:payload generate:types",
86
90
  "dev:payload": "dotenv -e ./dev/.env -- cross-env PAYLOAD_CONFIG_PATH=./dev/payload.config.ts payload",
@@ -88,6 +92,7 @@
88
92
  "generate:types": "pnpm dev:generate-types",
89
93
  "lint": "eslint",
90
94
  "lint:fix": "eslint ./src --fix",
95
+ "maildev": "maildev --smtp=1025 --web=1080",
91
96
  "test": "pnpm test:int && pnpm test:e2e",
92
97
  "test:e2e": "playwright test",
93
98
  "test:int": "vitest",
@@ -1,2 +0,0 @@
1
- import { type default as React } from 'react';
2
- export declare const BeforeDashboardClient: () => React.JSX.Element;
@@ -1,36 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useConfig } from '@payloadcms/ui';
4
- import { useEffect, useState } from 'react';
5
- export const BeforeDashboardClient = ()=>{
6
- const { config } = useConfig();
7
- const [message, setMessage] = useState('');
8
- useEffect(()=>{
9
- const fetchMessage = async ()=>{
10
- const response = await fetch(`${config.serverURL}${config.routes.api}/my-plugin-endpoint`);
11
- const result = await response.json();
12
- setMessage(result.message);
13
- };
14
- void fetchMessage();
15
- }, [
16
- config.serverURL,
17
- config.routes.api
18
- ]);
19
- return /*#__PURE__*/ _jsxs("div", {
20
- children: [
21
- /*#__PURE__*/ _jsx("h1", {
22
- children: "Added by the plugin: Before Dashboard Client"
23
- }),
24
- /*#__PURE__*/ _jsxs("div", {
25
- children: [
26
- "Message from the endpoint:",
27
- /*#__PURE__*/ _jsx("div", {
28
- children: message || 'Loading...'
29
- })
30
- ]
31
- })
32
- ]
33
- });
34
- };
35
-
36
- //# sourceMappingURL=BeforeDashboardClient.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/components/BeforeDashboardClient.tsx"],"sourcesContent":["'use client'\nimport { useConfig } from '@payloadcms/ui'\nimport { type default as React, useEffect, useState } from 'react'\n\nexport const BeforeDashboardClient = () => {\n const { config } = useConfig()\n\n const [message, setMessage] = useState('')\n\n useEffect(() => {\n const fetchMessage = async () => {\n const response = await fetch(`${config.serverURL}${config.routes.api}/my-plugin-endpoint`)\n const result = await response.json()\n setMessage(result.message)\n }\n\n void fetchMessage()\n }, [config.serverURL, config.routes.api])\n\n return (\n <div>\n <h1>Added by the plugin: Before Dashboard Client</h1>\n <div>\n Message from the endpoint:\n <div>{message || 'Loading...'}</div>\n </div>\n </div>\n )\n}\n"],"names":["useConfig","useEffect","useState","BeforeDashboardClient","config","message","setMessage","fetchMessage","response","fetch","serverURL","routes","api","result","json","div","h1"],"mappings":"AAAA;;AACA,SAASA,SAAS,QAAQ,iBAAgB;AAC1C,SAAgCC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAElE,OAAO,MAAMC,wBAAwB;IACnC,MAAM,EAAEC,MAAM,EAAE,GAAGJ;IAEnB,MAAM,CAACK,SAASC,WAAW,GAAGJ,SAAS;IAEvCD,UAAU;QACR,MAAMM,eAAe;YACnB,MAAMC,WAAW,MAAMC,MAAM,GAAGL,OAAOM,SAAS,GAAGN,OAAOO,MAAM,CAACC,GAAG,CAAC,mBAAmB,CAAC;YACzF,MAAMC,SAAS,MAAML,SAASM,IAAI;YAClCR,WAAWO,OAAOR,OAAO;QAC3B;QAEA,KAAKE;IACP,GAAG;QAACH,OAAOM,SAAS;QAAEN,OAAOO,MAAM,CAACC,GAAG;KAAC;IAExC,qBACE,MAACG;;0BACC,KAACC;0BAAG;;0BACJ,MAACD;;oBAAI;kCAEH,KAACA;kCAAKV,WAAW;;;;;;AAIzB,EAAC"}
@@ -1,3 +0,0 @@
1
- import type { ServerComponentProps } from 'payload';
2
- import type React from 'react';
3
- export declare const BeforeDashboardServer: (props: ServerComponentProps) => Promise<React.JSX.Element>;
@@ -1,22 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import styles from './BeforeDashboardServer.module.css';
3
- export const BeforeDashboardServer = async (props)=>{
4
- const { payload } = props;
5
- const { docs } = await payload.find({
6
- collection: 'plugin-collection'
7
- });
8
- return /*#__PURE__*/ _jsxs("div", {
9
- className: styles.wrapper,
10
- children: [
11
- /*#__PURE__*/ _jsx("h1", {
12
- children: "Added by the plugin: Before Dashboard Server"
13
- }),
14
- "Docs from Local API:",
15
- docs.map((doc)=>/*#__PURE__*/ _jsx("div", {
16
- children: doc.id
17
- }, doc.id))
18
- ]
19
- });
20
- };
21
-
22
- //# sourceMappingURL=BeforeDashboardServer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/components/BeforeDashboardServer.tsx"],"sourcesContent":["import type { ServerComponentProps } from 'payload'\nimport type React from 'react'\n\nimport styles from './BeforeDashboardServer.module.css'\n\nexport const BeforeDashboardServer = async (props: ServerComponentProps) => {\n const { payload } = props\n\n const { docs } = await payload.find({ collection: 'plugin-collection' })\n\n return (\n <div className={styles.wrapper}>\n <h1>Added by the plugin: Before Dashboard Server</h1>\n Docs from Local API:\n {docs.map((doc) => (\n <div key={doc.id}>{doc.id}</div>\n ))}\n </div>\n )\n}\n"],"names":["styles","BeforeDashboardServer","props","payload","docs","find","collection","div","className","wrapper","h1","map","doc","id"],"mappings":";AAGA,OAAOA,YAAY,qCAAoC;AAEvD,OAAO,MAAMC,wBAAwB,OAAOC;IAC1C,MAAM,EAAEC,OAAO,EAAE,GAAGD;IAEpB,MAAM,EAAEE,IAAI,EAAE,GAAG,MAAMD,QAAQE,IAAI,CAAC;QAAEC,YAAY;IAAoB;IAEtE,qBACE,MAACC;QAAIC,WAAWR,OAAOS,OAAO;;0BAC5B,KAACC;0BAAG;;YAAiD;YAEpDN,KAAKO,GAAG,CAAC,CAACC,oBACT,KAACL;8BAAkBK,IAAIC,EAAE;mBAAfD,IAAIC,EAAE;;;AAIxB,EAAC"}
@@ -1,5 +0,0 @@
1
- .wrapper {
2
- display: flex;
3
- gap: 5px;
4
- flex-direction: column;
5
- }