@delmaredigital/payload-better-auth 0.4.1 → 0.4.2

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.
@@ -1,6 +1,9 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect } from 'react';
4
+ import { Button, Banner } from '@payloadcms/ui';
5
+ import { PlusIcon } from '@payloadcms/ui/icons/Plus';
6
+ import { XIcon } from '@payloadcms/ui/icons/X';
4
7
  import { createPayloadAuthClient } from '../../exports/client.js';
5
8
  /**
6
9
  * Client component for passkey management.
@@ -36,8 +39,7 @@ import { createPayloadAuthClient } from '../../exports/client.js';
36
39
  setLoading(false);
37
40
  }
38
41
  }
39
- async function handleRegister(e) {
40
- e.preventDefault();
42
+ async function handleRegister() {
41
43
  setRegistering(true);
42
44
  setError(null);
43
45
  setSuccess(null);
@@ -96,213 +98,131 @@ import { createPayloadAuthClient } from '../../exports/client.js';
96
98
  return d.toLocaleString();
97
99
  }
98
100
  return /*#__PURE__*/ _jsxs("div", {
99
- style: {
100
- maxWidth: '900px',
101
- margin: '0 auto',
102
- padding: 'calc(var(--base) * 2)'
103
- },
101
+ className: "field-type passkeys-management",
104
102
  children: [
103
+ error && /*#__PURE__*/ _jsx(Banner, {
104
+ type: "error",
105
+ children: error
106
+ }),
107
+ success && /*#__PURE__*/ _jsx(Banner, {
108
+ type: "success",
109
+ children: success
110
+ }),
105
111
  /*#__PURE__*/ _jsxs("div", {
106
112
  style: {
107
113
  display: 'flex',
108
114
  justifyContent: 'space-between',
109
115
  alignItems: 'center',
110
- marginBottom: 'calc(var(--base) * 2)'
116
+ marginBottom: 'var(--base)'
111
117
  },
112
118
  children: [
113
- /*#__PURE__*/ _jsxs("div", {
114
- children: [
115
- /*#__PURE__*/ _jsx("h1", {
116
- style: {
117
- color: 'var(--theme-text)',
118
- fontSize: 'var(--font-size-h2)',
119
- fontWeight: 600,
120
- margin: 0
121
- },
122
- children: title
123
- }),
124
- /*#__PURE__*/ _jsx("p", {
125
- style: {
126
- color: 'var(--theme-text)',
127
- opacity: 0.7,
128
- fontSize: 'var(--font-size-small)',
129
- margin: 'calc(var(--base) * 0.5) 0 0 0'
130
- },
131
- children: "Passkeys provide secure, passwordless sign-in using your device's biometrics or security keys."
132
- })
133
- ]
134
- }),
135
- /*#__PURE__*/ _jsx("button", {
136
- onClick: ()=>setShowRegisterForm(true),
119
+ /*#__PURE__*/ _jsx("p", {
120
+ className: "field-description",
137
121
  style: {
138
- padding: 'calc(var(--base) * 0.5) calc(var(--base) * 1)',
139
- background: 'var(--theme-elevation-800)',
140
- border: 'none',
141
- borderRadius: 'var(--style-radius-s)',
142
- color: 'var(--theme-elevation-50)',
143
- fontSize: 'var(--font-size-small)',
144
- cursor: 'pointer'
122
+ margin: 0
145
123
  },
124
+ children: "Passkeys provide secure, passwordless sign-in using your device's biometrics or security keys."
125
+ }),
126
+ !showRegisterForm && /*#__PURE__*/ _jsx(Button, {
127
+ buttonStyle: "secondary",
128
+ size: "small",
129
+ icon: /*#__PURE__*/ _jsx(PlusIcon, {}),
130
+ onClick: ()=>setShowRegisterForm(true),
146
131
  children: "Add Passkey"
147
132
  })
148
133
  ]
149
134
  }),
150
- error && /*#__PURE__*/ _jsx("div", {
151
- style: {
152
- color: 'var(--theme-error-500)',
153
- marginBottom: 'var(--base)',
154
- fontSize: 'var(--font-size-small)',
155
- padding: 'calc(var(--base) * 0.75)',
156
- background: 'var(--theme-error-50)',
157
- borderRadius: 'var(--style-radius-s)',
158
- border: '1px solid var(--theme-error-200)'
159
- },
160
- children: error
161
- }),
162
- success && /*#__PURE__*/ _jsx("div", {
163
- style: {
164
- color: 'var(--theme-success-700)',
165
- marginBottom: 'var(--base)',
166
- fontSize: 'var(--font-size-small)',
167
- padding: 'calc(var(--base) * 0.75)',
168
- background: 'var(--theme-success-50)',
169
- borderRadius: 'var(--style-radius-s)',
170
- border: '1px solid var(--theme-success-200)'
171
- },
172
- children: success
173
- }),
174
135
  showRegisterForm && /*#__PURE__*/ _jsxs("div", {
175
136
  style: {
176
- marginBottom: 'calc(var(--base) * 1.5)',
177
- padding: 'calc(var(--base) * 1.5)',
178
- background: 'var(--theme-elevation-50)',
179
- borderRadius: 'var(--style-radius-m)',
180
- border: '1px solid var(--theme-elevation-100)'
137
+ marginBottom: 'var(--base)'
181
138
  },
182
139
  children: [
183
- /*#__PURE__*/ _jsx("h2", {
140
+ /*#__PURE__*/ _jsxs("div", {
184
141
  style: {
185
- color: 'var(--theme-text)',
186
- fontSize: 'var(--font-size-h4)',
187
- fontWeight: 500,
188
- margin: '0 0 var(--base) 0'
142
+ marginBottom: 'var(--base)'
189
143
  },
190
- children: "Register New Passkey"
191
- }),
192
- /*#__PURE__*/ _jsxs("form", {
193
- onSubmit: handleRegister,
194
144
  children: [
195
- /*#__PURE__*/ _jsxs("div", {
145
+ /*#__PURE__*/ _jsx("label", {
146
+ className: "field-label",
196
147
  style: {
197
- marginBottom: 'var(--base)'
148
+ marginBottom: 'calc(var(--base) * 0.5)',
149
+ display: 'block'
198
150
  },
199
- children: [
200
- /*#__PURE__*/ _jsx("label", {
201
- style: {
202
- display: 'block',
203
- color: 'var(--theme-text)',
204
- fontSize: 'var(--font-size-small)',
205
- marginBottom: 'calc(var(--base) * 0.25)'
206
- },
207
- children: "Name (optional)"
208
- }),
209
- /*#__PURE__*/ _jsx("input", {
210
- type: "text",
211
- value: passkeyName,
212
- onChange: (e)=>setPasskeyName(e.target.value),
213
- placeholder: "e.g., MacBook Pro, iPhone",
214
- style: {
215
- width: '100%',
216
- padding: 'calc(var(--base) * 0.5)',
217
- background: 'var(--theme-input-bg)',
218
- border: '1px solid var(--theme-elevation-150)',
219
- borderRadius: 'var(--style-radius-s)',
220
- color: 'var(--theme-text)',
221
- boxSizing: 'border-box'
222
- }
223
- }),
224
- /*#__PURE__*/ _jsx("p", {
225
- style: {
226
- color: 'var(--theme-text)',
227
- opacity: 0.6,
228
- fontSize: 'var(--font-size-small)',
229
- margin: 'calc(var(--base) * 0.25) 0 0 0'
230
- },
231
- children: "Your browser will prompt you to use your device's biometrics or security key."
232
- })
233
- ]
151
+ children: "Name (optional)"
234
152
  }),
235
- /*#__PURE__*/ _jsxs("div", {
153
+ /*#__PURE__*/ _jsx("input", {
154
+ type: "text",
155
+ value: passkeyName,
156
+ onChange: (e)=>setPasskeyName(e.target.value),
157
+ onKeyDown: (e)=>{
158
+ if (e.key === 'Enter') {
159
+ e.preventDefault();
160
+ handleRegister();
161
+ }
162
+ },
163
+ placeholder: "e.g., MacBook Pro, iPhone",
164
+ style: {
165
+ width: '100%',
166
+ padding: 'var(--base)',
167
+ background: 'var(--theme-input-bg)',
168
+ border: '1px solid var(--theme-border-color)',
169
+ borderRadius: 'var(--style-radius-s)',
170
+ color: 'var(--theme-text)',
171
+ fontSize: 'var(--base-body-size)',
172
+ boxSizing: 'border-box'
173
+ }
174
+ }),
175
+ /*#__PURE__*/ _jsx("p", {
176
+ className: "field-description",
236
177
  style: {
237
- display: 'flex',
238
- gap: 'calc(var(--base) * 0.5)'
178
+ marginTop: 'calc(var(--base) * 0.25)'
239
179
  },
240
- children: [
241
- /*#__PURE__*/ _jsx("button", {
242
- type: "submit",
243
- disabled: registering,
244
- style: {
245
- padding: 'calc(var(--base) * 0.5) calc(var(--base) * 1)',
246
- background: 'var(--theme-elevation-800)',
247
- border: 'none',
248
- borderRadius: 'var(--style-radius-s)',
249
- color: 'var(--theme-elevation-50)',
250
- fontSize: 'var(--font-size-small)',
251
- cursor: registering ? 'not-allowed' : 'pointer',
252
- opacity: registering ? 0.7 : 1
253
- },
254
- children: registering ? 'Registering...' : 'Register Passkey'
255
- }),
256
- /*#__PURE__*/ _jsx("button", {
257
- type: "button",
258
- onClick: ()=>setShowRegisterForm(false),
259
- style: {
260
- padding: 'calc(var(--base) * 0.5) calc(var(--base) * 1)',
261
- background: 'transparent',
262
- border: '1px solid var(--theme-elevation-200)',
263
- borderRadius: 'var(--style-radius-s)',
264
- color: 'var(--theme-text)',
265
- fontSize: 'var(--font-size-small)',
266
- cursor: 'pointer'
267
- },
268
- children: "Cancel"
269
- })
270
- ]
180
+ children: "Your browser will prompt you to use your device's biometrics or security key."
181
+ })
182
+ ]
183
+ }),
184
+ /*#__PURE__*/ _jsxs("div", {
185
+ style: {
186
+ display: 'flex',
187
+ gap: 'calc(var(--base) * 0.5)'
188
+ },
189
+ children: [
190
+ /*#__PURE__*/ _jsx(Button, {
191
+ buttonStyle: "primary",
192
+ size: "small",
193
+ onClick: handleRegister,
194
+ disabled: registering,
195
+ children: registering ? 'Registering...' : 'Register Passkey'
196
+ }),
197
+ /*#__PURE__*/ _jsx(Button, {
198
+ buttonStyle: "secondary",
199
+ size: "small",
200
+ onClick: ()=>setShowRegisterForm(false),
201
+ children: "Cancel"
271
202
  })
272
203
  ]
273
204
  })
274
205
  ]
275
206
  }),
276
- loading ? /*#__PURE__*/ _jsx("div", {
277
- style: {
278
- color: 'var(--theme-text)',
279
- opacity: 0.7,
280
- textAlign: 'center',
281
- padding: 'calc(var(--base) * 3)'
282
- },
207
+ loading ? /*#__PURE__*/ _jsx("p", {
208
+ className: "field-description",
283
209
  children: "Loading passkeys..."
284
- }) : passkeys.length === 0 ? /*#__PURE__*/ _jsx("div", {
285
- style: {
286
- color: 'var(--theme-text)',
287
- opacity: 0.7,
288
- textAlign: 'center',
289
- padding: 'calc(var(--base) * 3)'
290
- },
291
- children: "No passkeys registered. Add one to enable passwordless sign-in."
210
+ }) : passkeys.length === 0 ? /*#__PURE__*/ _jsx("p", {
211
+ className: "field-description",
212
+ children: "No passkeys registered."
292
213
  }) : /*#__PURE__*/ _jsx("div", {
293
214
  style: {
294
- background: 'var(--theme-elevation-50)',
295
- borderRadius: 'var(--style-radius-m)',
296
- overflow: 'hidden',
297
- border: '1px solid var(--theme-elevation-100)'
215
+ border: '1px solid var(--theme-border-color)',
216
+ borderRadius: 'var(--style-radius-s)',
217
+ overflow: 'hidden'
298
218
  },
299
219
  children: passkeys.map((pk, index)=>/*#__PURE__*/ _jsxs("div", {
300
220
  style: {
301
221
  display: 'flex',
302
222
  justifyContent: 'space-between',
303
223
  alignItems: 'center',
304
- padding: 'calc(var(--base) * 1)',
305
- borderBottom: index < passkeys.length - 1 ? '1px solid var(--theme-elevation-100)' : 'none'
224
+ padding: 'var(--base)',
225
+ borderBottom: index < passkeys.length - 1 ? '1px solid var(--theme-border-color)' : 'none'
306
226
  },
307
227
  children: [
308
228
  /*#__PURE__*/ _jsxs("div", {
@@ -310,46 +230,29 @@ import { createPayloadAuthClient } from '../../exports/client.js';
310
230
  /*#__PURE__*/ _jsx("div", {
311
231
  style: {
312
232
  color: 'var(--theme-text)',
313
- fontWeight: 500,
314
- marginBottom: 'calc(var(--base) * 0.25)'
233
+ fontWeight: 500
315
234
  },
316
235
  children: pk.name || 'Passkey'
317
236
  }),
318
- /*#__PURE__*/ _jsxs("div", {
237
+ /*#__PURE__*/ _jsxs("p", {
238
+ className: "field-description",
319
239
  style: {
320
- color: 'var(--theme-elevation-600)',
321
- fontSize: 'var(--font-size-small)'
240
+ margin: 'calc(var(--base) * 0.25) 0 0 0'
322
241
  },
323
242
  children: [
324
- /*#__PURE__*/ _jsxs("span", {
325
- children: [
326
- "Created: ",
327
- formatDate(pk.createdAt)
328
- ]
329
- }),
330
- pk.lastUsedAt && /*#__PURE__*/ _jsxs("span", {
331
- children: [
332
- " | Last used: ",
333
- formatDate(pk.lastUsedAt)
334
- ]
335
- })
243
+ "Created: ",
244
+ formatDate(pk.createdAt),
245
+ pk.lastUsedAt && ` | Last used: ${formatDate(pk.lastUsedAt)}`
336
246
  ]
337
247
  })
338
248
  ]
339
249
  }),
340
- /*#__PURE__*/ _jsx("button", {
250
+ /*#__PURE__*/ _jsx(Button, {
251
+ buttonStyle: "error",
252
+ size: "small",
253
+ icon: /*#__PURE__*/ _jsx(XIcon, {}),
341
254
  onClick: ()=>handleDelete(pk.id),
342
255
  disabled: deleting === pk.id,
343
- style: {
344
- padding: 'calc(var(--base) * 0.5) calc(var(--base) * 0.75)',
345
- background: 'transparent',
346
- border: '1px solid var(--theme-error-300)',
347
- borderRadius: 'var(--style-radius-s)',
348
- color: 'var(--theme-error-500)',
349
- fontSize: 'var(--font-size-small)',
350
- cursor: deleting === pk.id ? 'not-allowed' : 'pointer',
351
- opacity: deleting === pk.id ? 0.7 : 1
352
- },
353
256
  children: deleting === pk.id ? 'Deleting...' : 'Delete'
354
257
  })
355
258
  ]
@@ -1,19 +1,16 @@
1
1
  export type SecurityNavLinksProps = {
2
2
  /** Base path for security views. Default: '/admin/security' */
3
3
  basePath?: string;
4
- /** Show Two-Factor Auth link. Default: true */
5
- showTwoFactor?: boolean;
6
4
  /** Show API Keys link. Default: true */
7
5
  showApiKeys?: boolean;
8
- /** Show Passkeys link. Default: true */
9
- showPasskeys?: boolean;
10
6
  };
11
7
  /**
12
8
  * Navigation links for security management features.
13
9
  * Rendered in admin sidebar via afterNavLinks injection.
14
10
  * Uses Payload's NavGroup and nav CSS classes for native styling.
15
11
  *
16
- * Links are conditionally shown based on which Better Auth plugins are enabled.
12
+ * Currently only renders API Keys link 2FA and Passkeys
13
+ * are now embedded as ui fields on the user document.
17
14
  */
18
- export declare function SecurityNavLinks({ basePath, showTwoFactor, showApiKeys, showPasskeys, }?: SecurityNavLinksProps): import("react").JSX.Element | null;
15
+ export declare function SecurityNavLinks({ basePath, showApiKeys, }?: SecurityNavLinksProps): import("react").JSX.Element | null;
19
16
  export default SecurityNavLinks;
@@ -6,40 +6,22 @@ import { NavGroup } from '@payloadcms/ui';
6
6
  * Rendered in admin sidebar via afterNavLinks injection.
7
7
  * Uses Payload's NavGroup and nav CSS classes for native styling.
8
8
  *
9
- * Links are conditionally shown based on which Better Auth plugins are enabled.
10
- */ export function SecurityNavLinks({ basePath = '/admin/security', showTwoFactor = true, showApiKeys = true, showPasskeys = true } = {}) {
11
- const links = [];
12
- if (showTwoFactor) {
13
- links.push({
14
- href: `${basePath}/two-factor`,
15
- label: 'Two-Factor Auth'
16
- });
17
- }
18
- if (showApiKeys) {
19
- links.push({
20
- href: `${basePath}/api-keys`,
21
- label: 'API Keys'
22
- });
23
- }
24
- if (showPasskeys) {
25
- links.push({
26
- href: `${basePath}/passkeys`,
27
- label: 'Passkeys'
28
- });
29
- }
30
- if (links.length === 0) {
9
+ * Currently only renders API Keys link 2FA and Passkeys
10
+ * are now embedded as ui fields on the user document.
11
+ */ export function SecurityNavLinks({ basePath = '/admin/security', showApiKeys = true } = {}) {
12
+ if (!showApiKeys) {
31
13
  return null;
32
14
  }
33
15
  return /*#__PURE__*/ _jsx(NavGroup, {
34
16
  label: "Security",
35
- children: links.map((link)=>/*#__PURE__*/ _jsx("a", {
36
- href: link.href,
37
- className: "nav__link",
38
- children: /*#__PURE__*/ _jsx("span", {
39
- className: "nav__link-label",
40
- children: link.label
41
- })
42
- }, link.href))
17
+ children: /*#__PURE__*/ _jsx("a", {
18
+ href: `${basePath}/api-keys`,
19
+ className: "nav__link",
20
+ children: /*#__PURE__*/ _jsx("span", {
21
+ className: "nav__link-label",
22
+ children: "API Keys"
23
+ })
24
+ })
43
25
  });
44
26
  }
45
27
  export default SecurityNavLinks;
@@ -4,10 +4,12 @@ export type TwoFactorManagementClientProps = {
4
4
  authClient?: PayloadAuthClient;
5
5
  /** Page title. Default: 'Two-Factor Authentication' */
6
6
  title?: string;
7
+ /** Called after 2FA is enabled or disabled. Use to refresh form state. */
8
+ onComplete?: () => void | Promise<void>;
7
9
  };
8
10
  /**
9
11
  * Client component for two-factor authentication management.
10
12
  * Shows 2FA status and allows enabling/disabling.
11
13
  */
12
- export declare function TwoFactorManagementClient({ authClient: providedClient, title, }?: TwoFactorManagementClientProps): import("react").JSX.Element;
14
+ export declare function TwoFactorManagementClient({ authClient: providedClient, title, onComplete, }?: TwoFactorManagementClientProps): import("react").JSX.Element;
13
15
  export default TwoFactorManagementClient;
@@ -1,11 +1,13 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect } from 'react';
4
+ import { Button, Banner } from '@payloadcms/ui';
5
+ import { CopyIcon } from '@payloadcms/ui/icons/Copy';
4
6
  import { createPayloadAuthClient } from '../../exports/client.js';
5
7
  /**
6
8
  * Client component for two-factor authentication management.
7
9
  * Shows 2FA status and allows enabling/disabling.
8
- */ export function TwoFactorManagementClient({ authClient: providedClient, title = 'Two-Factor Authentication' } = {}) {
10
+ */ export function TwoFactorManagementClient({ authClient: providedClient, title = 'Two-Factor Authentication', onComplete } = {}) {
9
11
  const [isEnabled, setIsEnabled] = useState(false);
10
12
  const [loading, setLoading] = useState(true);
11
13
  const [error, setError] = useState(null);
@@ -43,8 +45,7 @@ import { createPayloadAuthClient } from '../../exports/client.js';
43
45
  setPassword('');
44
46
  setError(null);
45
47
  }
46
- async function handleEnableWithPassword(e) {
47
- e.preventDefault();
48
+ async function handleEnableWithPassword() {
48
49
  setActionLoading(true);
49
50
  setError(null);
50
51
  try {
@@ -69,8 +70,7 @@ import { createPayloadAuthClient } from '../../exports/client.js';
69
70
  setActionLoading(false);
70
71
  }
71
72
  }
72
- async function handleVerify(e) {
73
- e.preventDefault();
73
+ async function handleVerify() {
74
74
  setActionLoading(true);
75
75
  setError(null);
76
76
  try {
@@ -86,6 +86,7 @@ import { createPayloadAuthClient } from '../../exports/client.js';
86
86
  } else {
87
87
  setIsEnabled(true);
88
88
  setStep('status');
89
+ onComplete?.();
89
90
  }
90
91
  }
91
92
  } catch {
@@ -109,6 +110,7 @@ import { createPayloadAuthClient } from '../../exports/client.js';
109
110
  setError(result.error.message ?? 'Failed to disable 2FA');
110
111
  } else {
111
112
  setIsEnabled(false);
113
+ onComplete?.();
112
114
  }
113
115
  } catch {
114
116
  setError('Failed to disable 2FA');
@@ -119,186 +121,92 @@ import { createPayloadAuthClient } from '../../exports/client.js';
119
121
  function handleBackupContinue() {
120
122
  setIsEnabled(true);
121
123
  setStep('status');
124
+ onComplete?.();
122
125
  }
123
126
  if (loading) {
124
- return /*#__PURE__*/ _jsx("div", {
125
- style: {
126
- display: 'flex',
127
- alignItems: 'center',
128
- justifyContent: 'center',
129
- padding: 'calc(var(--base) * 3)'
130
- },
131
- children: /*#__PURE__*/ _jsx("div", {
132
- style: {
133
- color: 'var(--theme-text)',
134
- opacity: 0.7
135
- },
136
- children: "Loading..."
137
- })
127
+ return /*#__PURE__*/ _jsx("p", {
128
+ className: "field-description",
129
+ children: "Loading..."
138
130
  });
139
131
  }
140
132
  return /*#__PURE__*/ _jsxs("div", {
141
- style: {
142
- maxWidth: '600px',
143
- margin: '0 auto',
144
- padding: 'calc(var(--base) * 2)'
145
- },
133
+ className: "field-type two-factor-management",
146
134
  children: [
147
- /*#__PURE__*/ _jsx("h1", {
148
- style: {
149
- color: 'var(--theme-text)',
150
- fontSize: 'var(--font-size-h2)',
151
- fontWeight: 600,
152
- margin: '0 0 calc(var(--base) * 2) 0'
153
- },
154
- children: title
155
- }),
156
- error && /*#__PURE__*/ _jsx("div", {
157
- style: {
158
- color: 'var(--theme-error-500)',
159
- marginBottom: 'var(--base)',
160
- fontSize: 'var(--font-size-small)',
161
- padding: 'calc(var(--base) * 0.75)',
162
- background: 'var(--theme-error-50)',
163
- borderRadius: 'var(--style-radius-s)',
164
- border: '1px solid var(--theme-error-200)'
165
- },
135
+ error && /*#__PURE__*/ _jsx(Banner, {
136
+ type: "error",
166
137
  children: error
167
138
  }),
168
- step === 'status' && /*#__PURE__*/ _jsx("div", {
139
+ step === 'status' && /*#__PURE__*/ _jsxs("div", {
169
140
  style: {
170
- background: 'var(--theme-elevation-50)',
171
- padding: 'calc(var(--base) * 1.5)',
172
- borderRadius: 'var(--style-radius-m)',
173
- border: '1px solid var(--theme-elevation-100)'
174
- },
175
- children: /*#__PURE__*/ _jsxs("div", {
176
- style: {
177
- display: 'flex',
178
- justifyContent: 'space-between',
179
- alignItems: 'center'
180
- },
181
- children: [
182
- /*#__PURE__*/ _jsxs("div", {
183
- children: [
184
- /*#__PURE__*/ _jsx("div", {
185
- style: {
186
- color: 'var(--theme-text)',
187
- fontWeight: 500,
188
- marginBottom: 'calc(var(--base) * 0.25)'
189
- },
190
- children: "Status"
191
- }),
192
- /*#__PURE__*/ _jsx("div", {
193
- style: {
194
- color: isEnabled ? 'var(--theme-success-500)' : 'var(--theme-elevation-600)',
195
- fontSize: 'var(--font-size-small)'
196
- },
197
- children: isEnabled ? '✓ Enabled' : 'Not enabled'
198
- })
199
- ]
200
- }),
201
- /*#__PURE__*/ _jsx("button", {
202
- onClick: isEnabled ? handleDisable : handleEnableClick,
203
- disabled: actionLoading,
204
- style: {
205
- padding: 'calc(var(--base) * 0.5) calc(var(--base) * 1)',
206
- background: isEnabled ? 'var(--theme-error-500)' : 'var(--theme-elevation-800)',
207
- border: 'none',
208
- borderRadius: 'var(--style-radius-s)',
209
- color: 'var(--theme-elevation-50)',
210
- fontSize: 'var(--font-size-small)',
211
- cursor: actionLoading ? 'not-allowed' : 'pointer',
212
- opacity: actionLoading ? 0.7 : 1
213
- },
214
- children: actionLoading ? 'Loading...' : isEnabled ? 'Disable' : 'Enable'
215
- })
216
- ]
217
- })
218
- }),
219
- step === 'password' && /*#__PURE__*/ _jsxs("div", {
220
- style: {
221
- background: 'var(--theme-elevation-50)',
222
- padding: 'calc(var(--base) * 2)',
223
- borderRadius: 'var(--style-radius-m)',
224
- border: '1px solid var(--theme-elevation-100)'
141
+ display: 'flex',
142
+ justifyContent: 'space-between',
143
+ alignItems: 'center'
225
144
  },
226
145
  children: [
227
- /*#__PURE__*/ _jsx("h2", {
146
+ /*#__PURE__*/ _jsx("p", {
147
+ className: "field-description",
228
148
  style: {
229
- color: 'var(--theme-text)',
230
- fontSize: 'var(--font-size-h4)',
231
- fontWeight: 500,
232
- margin: '0 0 var(--base) 0'
149
+ margin: 0
233
150
  },
234
- children: "Confirm Your Password"
151
+ children: isEnabled ? 'Two-factor authentication is enabled.' : 'Two-factor authentication is not enabled.'
235
152
  }),
153
+ /*#__PURE__*/ _jsx(Button, {
154
+ buttonStyle: isEnabled ? 'error' : 'secondary',
155
+ size: "small",
156
+ onClick: isEnabled ? handleDisable : handleEnableClick,
157
+ disabled: actionLoading,
158
+ children: actionLoading ? 'Loading...' : isEnabled ? 'Disable' : 'Enable'
159
+ })
160
+ ]
161
+ }),
162
+ step === 'password' && /*#__PURE__*/ _jsxs("div", {
163
+ children: [
236
164
  /*#__PURE__*/ _jsx("p", {
165
+ className: "field-description",
166
+ children: "Enter your password to enable two-factor authentication."
167
+ }),
168
+ /*#__PURE__*/ _jsx("input", {
169
+ type: "password",
170
+ value: password,
171
+ onChange: (e)=>setPassword(e.target.value),
172
+ onKeyDown: (e)=>{
173
+ if (e.key === 'Enter' && password) {
174
+ e.preventDefault();
175
+ handleEnableWithPassword();
176
+ }
177
+ },
178
+ placeholder: "Enter your password",
179
+ className: "field-type__wrap",
237
180
  style: {
181
+ width: '100%',
182
+ padding: 'var(--base)',
183
+ background: 'var(--theme-input-bg)',
184
+ border: '1px solid var(--theme-border-color)',
185
+ borderRadius: 'var(--style-radius-s)',
238
186
  color: 'var(--theme-text)',
239
- opacity: 0.7,
240
- fontSize: 'var(--font-size-small)',
241
- marginBottom: 'calc(var(--base) * 1.5)'
242
- },
243
- children: "Enter your password to enable two-factor authentication."
187
+ fontSize: 'var(--base-body-size)',
188
+ marginBottom: 'var(--base)',
189
+ boxSizing: 'border-box'
190
+ }
244
191
  }),
245
- /*#__PURE__*/ _jsxs("form", {
246
- onSubmit: handleEnableWithPassword,
192
+ /*#__PURE__*/ _jsxs("div", {
193
+ style: {
194
+ display: 'flex',
195
+ gap: 'calc(var(--base) * 0.5)'
196
+ },
247
197
  children: [
248
- /*#__PURE__*/ _jsx("input", {
249
- type: "password",
250
- value: password,
251
- onChange: (e)=>setPassword(e.target.value),
252
- placeholder: "Enter your password",
253
- required: true,
254
- style: {
255
- width: '100%',
256
- padding: 'calc(var(--base) * 0.75)',
257
- background: 'var(--theme-input-bg)',
258
- border: '1px solid var(--theme-elevation-150)',
259
- borderRadius: 'var(--style-radius-s)',
260
- color: 'var(--theme-text)',
261
- fontSize: 'var(--font-size-base)',
262
- marginBottom: 'var(--base)',
263
- boxSizing: 'border-box'
264
- }
198
+ /*#__PURE__*/ _jsx(Button, {
199
+ buttonStyle: "primary",
200
+ size: "small",
201
+ onClick: handleEnableWithPassword,
202
+ disabled: actionLoading || !password,
203
+ children: actionLoading ? 'Enabling...' : 'Continue'
265
204
  }),
266
- /*#__PURE__*/ _jsxs("div", {
267
- style: {
268
- display: 'flex',
269
- gap: 'calc(var(--base) * 0.5)'
270
- },
271
- children: [
272
- /*#__PURE__*/ _jsx("button", {
273
- type: "submit",
274
- disabled: actionLoading || !password,
275
- style: {
276
- padding: 'calc(var(--base) * 0.75) calc(var(--base) * 1.5)',
277
- background: 'var(--theme-elevation-800)',
278
- border: 'none',
279
- borderRadius: 'var(--style-radius-s)',
280
- color: 'var(--theme-elevation-50)',
281
- fontSize: 'var(--font-size-base)',
282
- cursor: actionLoading || !password ? 'not-allowed' : 'pointer',
283
- opacity: actionLoading || !password ? 0.7 : 1
284
- },
285
- children: actionLoading ? 'Enabling...' : 'Continue'
286
- }),
287
- /*#__PURE__*/ _jsx("button", {
288
- type: "button",
289
- onClick: ()=>setStep('status'),
290
- style: {
291
- padding: 'calc(var(--base) * 0.75) calc(var(--base) * 1.5)',
292
- background: 'transparent',
293
- border: '1px solid var(--theme-elevation-200)',
294
- borderRadius: 'var(--style-radius-s)',
295
- color: 'var(--theme-text)',
296
- fontSize: 'var(--font-size-base)',
297
- cursor: 'pointer'
298
- },
299
- children: "Cancel"
300
- })
301
- ]
205
+ /*#__PURE__*/ _jsx(Button, {
206
+ buttonStyle: "secondary",
207
+ size: "small",
208
+ onClick: ()=>setStep('status'),
209
+ children: "Cancel"
302
210
  })
303
211
  ]
304
212
  })
@@ -306,18 +214,11 @@ import { createPayloadAuthClient } from '../../exports/client.js';
306
214
  }),
307
215
  step === 'setup' && totpUri && /*#__PURE__*/ _jsxs("div", {
308
216
  style: {
309
- background: 'var(--theme-elevation-50)',
310
- padding: 'calc(var(--base) * 2)',
311
- borderRadius: 'var(--style-radius-m)',
312
217
  textAlign: 'center'
313
218
  },
314
219
  children: [
315
220
  /*#__PURE__*/ _jsx("p", {
316
- style: {
317
- color: 'var(--theme-text)',
318
- opacity: 0.7,
319
- marginBottom: 'calc(var(--base) * 1.5)'
320
- },
221
+ className: "field-description",
321
222
  children: "Scan this QR code with your authenticator app:"
322
223
  }),
323
224
  /*#__PURE__*/ _jsx("img", {
@@ -326,7 +227,7 @@ import { createPayloadAuthClient } from '../../exports/client.js';
326
227
  style: {
327
228
  width: '200px',
328
229
  height: '200px',
329
- border: '1px solid var(--theme-elevation-150)',
230
+ border: '1px solid var(--theme-border-color)',
330
231
  borderRadius: 'var(--style-radius-s)',
331
232
  marginBottom: 'var(--base)'
332
233
  }
@@ -337,10 +238,8 @@ import { createPayloadAuthClient } from '../../exports/client.js';
337
238
  },
338
239
  children: [
339
240
  /*#__PURE__*/ _jsx("p", {
241
+ className: "field-description",
340
242
  style: {
341
- color: 'var(--theme-text)',
342
- opacity: 0.7,
343
- fontSize: 'var(--font-size-small)',
344
243
  marginBottom: 'calc(var(--base) * 0.5)'
345
244
  },
346
245
  children: "Or enter manually:"
@@ -352,15 +251,14 @@ import { createPayloadAuthClient } from '../../exports/client.js';
352
251
  background: 'var(--theme-elevation-100)',
353
252
  borderRadius: 'var(--style-radius-s)',
354
253
  fontFamily: 'monospace',
355
- fontSize: 'var(--font-size-small)',
254
+ fontSize: 'var(--base-body-size)',
356
255
  color: 'var(--theme-text)'
357
256
  },
358
257
  children: secret
359
258
  })
360
259
  ]
361
260
  }),
362
- /*#__PURE__*/ _jsxs("form", {
363
- onSubmit: handleVerify,
261
+ /*#__PURE__*/ _jsxs("div", {
364
262
  children: [
365
263
  /*#__PURE__*/ _jsx("input", {
366
264
  type: "text",
@@ -368,16 +266,21 @@ import { createPayloadAuthClient } from '../../exports/client.js';
368
266
  pattern: "[0-9]*",
369
267
  value: verificationCode,
370
268
  onChange: (e)=>setVerificationCode(e.target.value.replace(/\D/g, '').slice(0, 6)),
371
- placeholder: "Enter 6-digit code",
269
+ onKeyDown: (e)=>{
270
+ if (e.key === 'Enter' && verificationCode.length === 6) {
271
+ e.preventDefault();
272
+ handleVerify();
273
+ }
274
+ },
275
+ placeholder: "000000",
372
276
  style: {
373
- width: '100%',
374
- maxWidth: '200px',
375
- padding: 'calc(var(--base) * 0.75)',
277
+ width: '200px',
278
+ padding: 'var(--base)',
376
279
  background: 'var(--theme-input-bg)',
377
- border: '1px solid var(--theme-elevation-150)',
280
+ border: '1px solid var(--theme-border-color)',
378
281
  borderRadius: 'var(--style-radius-s)',
379
282
  color: 'var(--theme-text)',
380
- fontSize: 'var(--font-size-h4)',
283
+ fontSize: '1.5rem',
381
284
  fontFamily: 'monospace',
382
285
  textAlign: 'center',
383
286
  letterSpacing: '0.5em',
@@ -386,19 +289,11 @@ import { createPayloadAuthClient } from '../../exports/client.js';
386
289
  }
387
290
  }),
388
291
  /*#__PURE__*/ _jsx("br", {}),
389
- /*#__PURE__*/ _jsx("button", {
390
- type: "submit",
292
+ /*#__PURE__*/ _jsx(Button, {
293
+ buttonStyle: "primary",
294
+ size: "small",
295
+ onClick: handleVerify,
391
296
  disabled: actionLoading || verificationCode.length !== 6,
392
- style: {
393
- padding: 'calc(var(--base) * 0.75) calc(var(--base) * 2)',
394
- background: 'var(--theme-elevation-800)',
395
- border: 'none',
396
- borderRadius: 'var(--style-radius-s)',
397
- color: 'var(--theme-elevation-50)',
398
- fontSize: 'var(--font-size-base)',
399
- cursor: actionLoading || verificationCode.length !== 6 ? 'not-allowed' : 'pointer',
400
- opacity: actionLoading || verificationCode.length !== 6 ? 0.7 : 1
401
- },
402
297
  children: actionLoading ? 'Verifying...' : 'Verify'
403
298
  })
404
299
  ]
@@ -406,37 +301,17 @@ import { createPayloadAuthClient } from '../../exports/client.js';
406
301
  ]
407
302
  }),
408
303
  step === 'backup' && /*#__PURE__*/ _jsxs("div", {
409
- style: {
410
- background: 'var(--theme-elevation-50)',
411
- padding: 'calc(var(--base) * 2)',
412
- borderRadius: 'var(--style-radius-m)'
413
- },
414
304
  children: [
415
- /*#__PURE__*/ _jsx("h2", {
416
- style: {
417
- color: 'var(--theme-text)',
418
- fontSize: 'var(--font-size-h3)',
419
- fontWeight: 600,
420
- margin: '0 0 var(--base) 0',
421
- textAlign: 'center'
422
- },
423
- children: "Save Your Backup Codes"
424
- }),
425
- /*#__PURE__*/ _jsx("p", {
426
- style: {
427
- color: 'var(--theme-text)',
428
- opacity: 0.7,
429
- fontSize: 'var(--font-size-small)',
430
- textAlign: 'center',
431
- marginBottom: 'calc(var(--base) * 1.5)'
432
- },
433
- children: "Store these codes safely. Use them if you lose your authenticator."
305
+ /*#__PURE__*/ _jsx(Banner, {
306
+ type: "info",
307
+ children: "Save these backup codes in a safe place. You can use them to sign in if you lose access to your authenticator app."
434
308
  }),
435
309
  /*#__PURE__*/ _jsx("div", {
436
310
  style: {
437
311
  background: 'var(--theme-elevation-100)',
438
312
  padding: 'var(--base)',
439
313
  borderRadius: 'var(--style-radius-s)',
314
+ marginTop: 'var(--base)',
440
315
  marginBottom: 'var(--base)',
441
316
  fontFamily: 'monospace'
442
317
  },
@@ -455,34 +330,26 @@ import { createPayloadAuthClient } from '../../exports/client.js';
455
330
  }, index))
456
331
  })
457
332
  }),
458
- /*#__PURE__*/ _jsx("button", {
459
- onClick: ()=>navigator.clipboard.writeText(backupCodes.join('\n')),
460
- style: {
461
- width: '100%',
462
- padding: 'calc(var(--base) * 0.5)',
463
- background: 'var(--theme-elevation-150)',
464
- border: 'none',
465
- borderRadius: 'var(--style-radius-s)',
466
- color: 'var(--theme-text)',
467
- fontSize: 'var(--font-size-small)',
468
- cursor: 'pointer',
469
- marginBottom: 'var(--base)'
470
- },
471
- children: "Copy to Clipboard"
472
- }),
473
- /*#__PURE__*/ _jsx("button", {
474
- onClick: handleBackupContinue,
333
+ /*#__PURE__*/ _jsxs("div", {
475
334
  style: {
476
- width: '100%',
477
- padding: 'calc(var(--base) * 0.75)',
478
- background: 'var(--theme-elevation-800)',
479
- border: 'none',
480
- borderRadius: 'var(--style-radius-s)',
481
- color: 'var(--theme-elevation-50)',
482
- fontSize: 'var(--font-size-base)',
483
- cursor: 'pointer'
335
+ display: 'flex',
336
+ gap: 'calc(var(--base) * 0.5)'
484
337
  },
485
- children: "I've Saved My Codes"
338
+ children: [
339
+ /*#__PURE__*/ _jsx(Button, {
340
+ buttonStyle: "secondary",
341
+ size: "small",
342
+ icon: /*#__PURE__*/ _jsx(CopyIcon, {}),
343
+ onClick: ()=>navigator.clipboard.writeText(backupCodes.join('\n')),
344
+ children: "Copy to Clipboard"
345
+ }),
346
+ /*#__PURE__*/ _jsx(Button, {
347
+ buttonStyle: "primary",
348
+ size: "small",
349
+ onClick: handleBackupContinue,
350
+ children: "I've Saved My Codes"
351
+ })
352
+ ]
486
353
  })
487
354
  ]
488
355
  })
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Thin wrapper around PasskeysManagementClient for use as a Payload `ui` field.
3
+ */
4
+ export declare function PasskeysField(): import("react").JSX.Element;
5
+ export default PasskeysField;
@@ -0,0 +1,9 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { PasskeysManagementClient } from '../PasskeysManagementClient.js';
4
+ /**
5
+ * Thin wrapper around PasskeysManagementClient for use as a Payload `ui` field.
6
+ */ export function PasskeysField() {
7
+ return /*#__PURE__*/ _jsx(PasskeysManagementClient, {});
8
+ }
9
+ export default PasskeysField;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Wrapper around TwoFactorManagementClient for use as a Payload `ui` field.
3
+ *
4
+ * After 2FA is enabled or disabled, triggers a Next.js router refresh so that
5
+ * the document form re-fetches from the DB and picks up the `twoFactorEnabled`
6
+ * value that Better Auth wrote. Without this, navigating away without clicking
7
+ * Save would overwrite the change.
8
+ */
9
+ export declare function TwoFactorField(): import("react").JSX.Element;
10
+ export default TwoFactorField;
@@ -0,0 +1,24 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useRouter } from 'next/navigation.js';
4
+ import { useCallback } from 'react';
5
+ import { TwoFactorManagementClient } from '../TwoFactorManagementClient.js';
6
+ /**
7
+ * Wrapper around TwoFactorManagementClient for use as a Payload `ui` field.
8
+ *
9
+ * After 2FA is enabled or disabled, triggers a Next.js router refresh so that
10
+ * the document form re-fetches from the DB and picks up the `twoFactorEnabled`
11
+ * value that Better Auth wrote. Without this, navigating away without clicking
12
+ * Save would overwrite the change.
13
+ */ export function TwoFactorField() {
14
+ const router = useRouter();
15
+ const handleComplete = useCallback(()=>{
16
+ router.refresh();
17
+ }, [
18
+ router
19
+ ]);
20
+ return /*#__PURE__*/ _jsx(TwoFactorManagementClient, {
21
+ onComplete: handleComplete
22
+ });
23
+ }
24
+ export default TwoFactorField;
@@ -21,3 +21,5 @@ export type { PasskeySignInButtonProps } from '../components/PasskeySignInButton
21
21
  export { PasskeySignInButton } from '../components/PasskeySignInButton.js';
22
22
  export type { PasskeyRegisterButtonProps } from '../components/PasskeyRegisterButton.js';
23
23
  export { PasskeyRegisterButton } from '../components/PasskeyRegisterButton.js';
24
+ export { TwoFactorField } from '../components/management/fields/TwoFactorField.js';
25
+ export { PasskeysField } from '../components/management/fields/PasskeysField.js';
@@ -12,3 +12,6 @@ export { TwoFactorSetupView } from '../components/twoFactor/TwoFactorSetupView.j
12
12
  export { TwoFactorVerifyView } from '../components/twoFactor/TwoFactorVerifyView.js';
13
13
  export { PasskeySignInButton } from '../components/PasskeySignInButton.js';
14
14
  export { PasskeyRegisterButton } from '../components/PasskeyRegisterButton.js';
15
+ // Management UI field wrappers (for Payload ui fields)
16
+ export { TwoFactorField } from '../components/management/fields/TwoFactorField.js';
17
+ export { PasskeysField } from '../components/management/fields/PasskeysField.js';
@@ -314,6 +314,9 @@ let apiKeyScopesConfig = undefined;
314
314
  }
315
315
  /**
316
316
  * Injects management UI components into the Payload config based on enabled plugins.
317
+ *
318
+ * - 2FA and Passkeys are injected as `ui` fields on the auth collection (per-user settings)
319
+ * - API Keys remain as a sidebar admin view (admin-level feature)
317
320
  */ function injectManagementComponents(config, options) {
318
321
  const adminOptions = options.admin ?? {};
319
322
  // Skip if management UI is disabled
@@ -324,55 +327,72 @@ let apiKeyScopesConfig = undefined;
324
327
  const enabledPlugins = detectEnabledPlugins(adminOptions.betterAuthOptions);
325
328
  // Get custom paths or use defaults
326
329
  const paths = {
327
- twoFactor: adminOptions.managementPaths?.twoFactor ?? '/security/two-factor',
328
- apiKeys: adminOptions.managementPaths?.apiKeys ?? '/security/api-keys',
329
- passkeys: adminOptions.managementPaths?.passkeys ?? '/security/passkeys'
330
+ apiKeys: adminOptions.managementPaths?.apiKeys ?? '/security/api-keys'
330
331
  };
331
332
  const existingComponents = config.admin?.components ?? {};
332
333
  const existingViews = existingComponents.views ?? {};
333
334
  const existingAfterNavLinks = existingComponents.afterNavLinks ?? [];
334
- // Build management views based on enabled plugins
335
- // Note: Sessions and passkeys use Payload's default collection views
335
+ // Build management views only API Keys stays as a sidebar view
336
336
  const managementViews = {};
337
- // Two-factor (if enabled)
338
- if (enabledPlugins.hasTwoFactor) {
339
- managementViews.securityTwoFactor = {
340
- Component: '@delmaredigital/payload-better-auth/rsc#TwoFactorView',
341
- path: paths.twoFactor
342
- };
343
- }
344
- // API keys (if enabled)
345
337
  if (enabledPlugins.hasApiKey) {
346
338
  managementViews.securityApiKeys = {
347
339
  Component: '@delmaredigital/payload-better-auth/rsc#ApiKeysView',
348
340
  path: paths.apiKeys
349
341
  };
350
342
  }
351
- // Passkeys (if enabled)
352
- if (enabledPlugins.hasPasskey) {
353
- managementViews.securityPasskeys = {
354
- Component: '@delmaredigital/payload-better-auth/rsc#PasskeysView',
355
- path: paths.passkeys
356
- };
357
- }
358
- // Only add nav links if at least one plugin is enabled
359
- const hasAnyPlugin = enabledPlugins.hasTwoFactor || enabledPlugins.hasApiKey || enabledPlugins.hasPasskey;
360
- // Add SecurityNavLinks to afterNavLinks with clientProps for enabled plugins
361
- const afterNavLinks = hasAnyPlugin ? [
343
+ // Only add nav links if API Keys is enabled
344
+ const afterNavLinks = enabledPlugins.hasApiKey ? [
362
345
  ...Array.isArray(existingAfterNavLinks) ? existingAfterNavLinks : [
363
346
  existingAfterNavLinks
364
347
  ],
365
348
  {
366
349
  path: '@delmaredigital/payload-better-auth/components/management#SecurityNavLinks',
367
350
  clientProps: {
368
- showTwoFactor: enabledPlugins.hasTwoFactor,
369
- showApiKeys: enabledPlugins.hasApiKey,
370
- showPasskeys: enabledPlugins.hasPasskey
351
+ showApiKeys: enabledPlugins.hasApiKey
371
352
  }
372
353
  }
373
354
  ] : existingAfterNavLinks;
355
+ // Inject 2FA and Passkeys as ui fields on the auth collection
356
+ const securityFields = [];
357
+ if (enabledPlugins.hasTwoFactor) {
358
+ securityFields.push({
359
+ type: 'ui',
360
+ name: 'twoFactorManagement',
361
+ label: 'Two-Factor Authentication',
362
+ admin: {
363
+ components: {
364
+ Field: '@delmaredigital/payload-better-auth/components#TwoFactorField'
365
+ }
366
+ }
367
+ });
368
+ }
369
+ if (enabledPlugins.hasPasskey) {
370
+ securityFields.push({
371
+ type: 'ui',
372
+ name: 'passkeysManagement',
373
+ label: 'Passkeys',
374
+ admin: {
375
+ components: {
376
+ Field: '@delmaredigital/payload-better-auth/components#PasskeysField'
377
+ }
378
+ }
379
+ });
380
+ }
381
+ // Add ui fields to the auth collection
382
+ const collections = (config.collections ?? []).map((collection)=>{
383
+ const isAuthCollection = collection.auth === true || typeof collection.auth === 'object' && collection.auth.disableLocalStrategy;
384
+ if (!isAuthCollection || securityFields.length === 0) return collection;
385
+ return {
386
+ ...collection,
387
+ fields: [
388
+ ...collection.fields ?? [],
389
+ ...securityFields
390
+ ]
391
+ };
392
+ });
374
393
  return {
375
394
  ...config,
395
+ collections,
376
396
  admin: {
377
397
  ...config.admin,
378
398
  components: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delmaredigital/payload-better-auth",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Better Auth adapter and plugins for Payload CMS",
5
5
  "type": "module",
6
6
  "license": "MIT",