@delmaredigital/payload-better-auth 0.3.7 → 0.3.9

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 (119) hide show
  1. package/README.md +12 -1
  2. package/dist/adapter/collections.d.ts.map +1 -1
  3. package/dist/adapter/collections.js +126 -88
  4. package/dist/adapter/collections.js.map +1 -1
  5. package/dist/adapter/index.js +197 -150
  6. package/dist/adapter/index.js.map +1 -1
  7. package/dist/components/BeforeLogin.d.ts +1 -1
  8. package/dist/components/BeforeLogin.d.ts.map +1 -1
  9. package/dist/components/BeforeLogin.js +15 -7
  10. package/dist/components/BeforeLogin.js.map +1 -1
  11. package/dist/components/LoginView.d.ts +2 -2
  12. package/dist/components/LoginView.d.ts.map +1 -1
  13. package/dist/components/LoginView.js +660 -218
  14. package/dist/components/LoginView.js.map +1 -1
  15. package/dist/components/LoginViewWrapper.d.ts +1 -1
  16. package/dist/components/LoginViewWrapper.d.ts.map +1 -1
  17. package/dist/components/LoginViewWrapper.js +14 -4
  18. package/dist/components/LoginViewWrapper.js.map +1 -1
  19. package/dist/components/LogoutButton.d.ts +1 -1
  20. package/dist/components/LogoutButton.d.ts.map +1 -1
  21. package/dist/components/LogoutButton.js +19 -11
  22. package/dist/components/LogoutButton.js.map +1 -1
  23. package/dist/components/PasskeyRegisterButton.d.ts +2 -2
  24. package/dist/components/PasskeyRegisterButton.d.ts.map +1 -1
  25. package/dist/components/PasskeyRegisterButton.js +20 -16
  26. package/dist/components/PasskeyRegisterButton.js.map +1 -1
  27. package/dist/components/PasskeySignInButton.d.ts +2 -2
  28. package/dist/components/PasskeySignInButton.d.ts.map +1 -1
  29. package/dist/components/PasskeySignInButton.js +14 -12
  30. package/dist/components/PasskeySignInButton.js.map +1 -1
  31. package/dist/components/auth/ForgotPasswordView.d.ts +1 -1
  32. package/dist/components/auth/ForgotPasswordView.d.ts.map +1 -1
  33. package/dist/components/auth/ForgotPasswordView.js +133 -43
  34. package/dist/components/auth/ForgotPasswordView.js.map +1 -1
  35. package/dist/components/auth/ResetPasswordView.d.ts +1 -1
  36. package/dist/components/auth/ResetPasswordView.d.ts.map +1 -1
  37. package/dist/components/auth/ResetPasswordView.js +154 -50
  38. package/dist/components/auth/ResetPasswordView.js.map +1 -1
  39. package/dist/components/auth/index.js +2 -2
  40. package/dist/components/auth/index.js.map +1 -1
  41. package/dist/components/management/ApiKeysManagementClient.d.ts +2 -2
  42. package/dist/components/management/ApiKeysManagementClient.d.ts.map +1 -1
  43. package/dist/components/management/ApiKeysManagementClient.js +539 -222
  44. package/dist/components/management/ApiKeysManagementClient.js.map +1 -1
  45. package/dist/components/management/PasskeysManagementClient.d.ts +2 -2
  46. package/dist/components/management/PasskeysManagementClient.d.ts.map +1 -1
  47. package/dist/components/management/PasskeysManagementClient.js +215 -92
  48. package/dist/components/management/PasskeysManagementClient.js.map +1 -1
  49. package/dist/components/management/SecurityNavLinks.d.ts +1 -1
  50. package/dist/components/management/SecurityNavLinks.d.ts.map +1 -1
  51. package/dist/components/management/SecurityNavLinks.js +51 -24
  52. package/dist/components/management/SecurityNavLinks.js.map +1 -1
  53. package/dist/components/management/TwoFactorManagementClient.d.ts +2 -2
  54. package/dist/components/management/TwoFactorManagementClient.d.ts.map +1 -1
  55. package/dist/components/management/TwoFactorManagementClient.js +270 -111
  56. package/dist/components/management/TwoFactorManagementClient.js.map +1 -1
  57. package/dist/components/management/index.js +2 -2
  58. package/dist/components/management/index.js.map +1 -1
  59. package/dist/components/management/views/ApiKeysView.d.ts +1 -1
  60. package/dist/components/management/views/ApiKeysView.d.ts.map +1 -1
  61. package/dist/components/management/views/ApiKeysView.js +19 -4
  62. package/dist/components/management/views/ApiKeysView.js.map +1 -1
  63. package/dist/components/management/views/PasskeysView.d.ts +1 -1
  64. package/dist/components/management/views/PasskeysView.d.ts.map +1 -1
  65. package/dist/components/management/views/PasskeysView.js +16 -4
  66. package/dist/components/management/views/PasskeysView.js.map +1 -1
  67. package/dist/components/management/views/TwoFactorView.d.ts +1 -1
  68. package/dist/components/management/views/TwoFactorView.d.ts.map +1 -1
  69. package/dist/components/management/views/TwoFactorView.js +16 -4
  70. package/dist/components/management/views/TwoFactorView.js.map +1 -1
  71. package/dist/components/management/views/index.js +2 -2
  72. package/dist/components/management/views/index.js.map +1 -1
  73. package/dist/components/twoFactor/TwoFactorSetupView.d.ts +1 -1
  74. package/dist/components/twoFactor/TwoFactorSetupView.d.ts.map +1 -1
  75. package/dist/components/twoFactor/TwoFactorSetupView.js +240 -87
  76. package/dist/components/twoFactor/TwoFactorSetupView.js.map +1 -1
  77. package/dist/components/twoFactor/TwoFactorVerifyView.d.ts +1 -1
  78. package/dist/components/twoFactor/TwoFactorVerifyView.d.ts.map +1 -1
  79. package/dist/components/twoFactor/TwoFactorVerifyView.js +108 -45
  80. package/dist/components/twoFactor/TwoFactorVerifyView.js.map +1 -1
  81. package/dist/components/twoFactor/index.js +2 -2
  82. package/dist/components/twoFactor/index.js.map +1 -1
  83. package/dist/exports/client.js +9 -10
  84. package/dist/exports/client.js.map +1 -1
  85. package/dist/exports/components.js +2 -2
  86. package/dist/exports/components.js.map +1 -1
  87. package/dist/exports/management.js +3 -3
  88. package/dist/exports/management.js.map +1 -1
  89. package/dist/exports/rsc.js +2 -2
  90. package/dist/exports/rsc.js.map +1 -1
  91. package/dist/generated-types.js +4 -2
  92. package/dist/generated-types.js.map +1 -1
  93. package/dist/index.js +6 -6
  94. package/dist/index.js.map +1 -1
  95. package/dist/plugin/index.js +198 -162
  96. package/dist/plugin/index.js.map +1 -1
  97. package/dist/scripts/generate-types.js +66 -50
  98. package/dist/scripts/generate-types.js.map +1 -1
  99. package/dist/types/apiKey.js +7 -2
  100. package/dist/types/apiKey.js.map +1 -1
  101. package/dist/types/betterAuth.js +23 -2
  102. package/dist/types/betterAuth.js.map +1 -1
  103. package/dist/utils/access.js +78 -81
  104. package/dist/utils/access.js.map +1 -1
  105. package/dist/utils/apiKeyAccess.js +65 -72
  106. package/dist/utils/apiKeyAccess.js.map +1 -1
  107. package/dist/utils/betterAuthDefaults.js +8 -8
  108. package/dist/utils/betterAuthDefaults.js.map +1 -1
  109. package/dist/utils/detectAuthConfig.js +8 -11
  110. package/dist/utils/detectAuthConfig.js.map +1 -1
  111. package/dist/utils/detectEnabledPlugins.js +6 -7
  112. package/dist/utils/detectEnabledPlugins.js.map +1 -1
  113. package/dist/utils/firstUserAdmin.js +18 -20
  114. package/dist/utils/firstUserAdmin.js.map +1 -1
  115. package/dist/utils/generateScopes.js +40 -41
  116. package/dist/utils/generateScopes.js.map +1 -1
  117. package/dist/utils/session.js +8 -9
  118. package/dist/utils/session.js.map +1 -1
  119. package/package.json +27 -13
package/README.md CHANGED
@@ -367,12 +367,23 @@ betterAuthCollections({
367
367
  | `betterAuthOptions` | `BetterAuthOptions` | Your Better Auth options |
368
368
  | `skipCollections` | `string[]` | Collections to skip generating (default: `['user']`) |
369
369
  | `adminGroup` | `string` | Admin panel group name (default: `'Auth'`) |
370
- | `access` | `CollectionConfig['access']` | Custom access control for generated collections |
370
+ | `access` | `CollectionConfig['access']` | Custom access control for generated collections. **Note**: Replaces default access entirely (see caution below). |
371
371
  | `usePlural` | `boolean` | Pluralize collection slugs (default: `true`) |
372
372
  | `configureSaveToJWT` | `boolean` | Auto-configure `saveToJWT` for session-critical fields (default: `true`) |
373
373
  | `firstUserAdmin` | `boolean \| FirstUserAdminOptions` | Make first registered user an admin (default: `true`) |
374
374
  | `customizeCollection` | `(modelKey, collection) => CollectionConfig` | Customize generated collections |
375
375
 
376
+ > **⚠️ Caution on Custom Access:**
377
+ > When providing the `access` option, it **completely replaces** the default access object for all auto-generated collections. It does not merge with or override individual properties.
378
+ >
379
+ > By default, the plugin sets:
380
+ > - `read`: `isAdmin()`
381
+ > - `delete`: `isAdmin()`
382
+ > - `create`: `() => false` (Manual creation disabled - Better Auth manages these)
383
+ > - `update`: `() => false` (Manual update disabled - Better Auth manages these)
384
+ >
385
+ > You must explicitly handle all access types to ensure your collections remain secure and functional.
386
+
376
387
  **First User Admin:**
377
388
 
378
389
  By default, the first user to register is automatically assigned the admin role. This provides a better out-of-the-box experience - no need to manually update the database to create your first admin.
@@ -1 +1 @@
1
- {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../src/adapter/collections.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAU,gBAAgB,EAAS,MAAM,EAA8B,MAAM,SAAS,CAAA;AAClG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEpD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAEvE,YAAY,EAAE,qBAAqB,EAAE,CAAA;AAErC,MAAM,MAAM,4BAA4B,GAAG;IACzC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IAErC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAE1B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;OAGG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IAEnC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAE5B;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,qBAAqB,CAAA;IAEhD;;;;;;;;;;;;;;;;;;OAkBG;IACH,mBAAmB,CAAC,EAAE,CACpB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,gBAAgB,KACzB,gBAAgB,CAAA;CACtB,CAAA;AA2XD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,4BAAiC,GACzC,MAAM,CAuGR"}
1
+ {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../src/adapter/collections.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAU,gBAAgB,EAAS,MAAM,EAA8B,MAAM,SAAS,CAAA;AAClG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEpD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAGvE,YAAY,EAAE,qBAAqB,EAAE,CAAA;AAErC,MAAM,MAAM,4BAA4B,GAAG;IACzC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IAErC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAE1B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;OAGG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IAEnC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAE5B;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,qBAAqB,CAAA;IAEhD;;;;;;;;;;;;;;;;;;OAkBG;IACH,mBAAmB,CAAC,EAAE,CACpB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,gBAAgB,KACzB,gBAAgB,CAAA;CACtB,CAAA;AA2XD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,4BAAiC,GACzC,MAAM,CAuGR"}
@@ -2,69 +2,82 @@
2
2
  * Auto-generate Payload collections from Better Auth schema
3
3
  *
4
4
  * @packageDocumentation
5
- */
6
- import { getAuthTables } from 'better-auth/db';
5
+ */ import { getAuthTables } from 'better-auth/db';
6
+ import { isAdmin } from '../utils/access.js';
7
7
  /**
8
8
  * Creates a beforeChange hook that makes the first user an admin.
9
- */
10
- function createFirstUserAdminHook(options, usersSlug) {
11
- const { adminRole = 'admin', defaultRole = 'user', roleField = 'role', } = options;
12
- return async ({ data, operation, req }) => {
9
+ */ function createFirstUserAdminHook(options, usersSlug) {
10
+ const { adminRole = 'admin', defaultRole = 'user', roleField = 'role' } = options;
11
+ return async ({ data, operation, req })=>{
13
12
  if (operation !== 'create') {
14
13
  return data;
15
14
  }
16
15
  try {
17
16
  const { totalDocs } = await req.payload.count({
18
17
  collection: usersSlug,
19
- overrideAccess: true,
18
+ overrideAccess: true
20
19
  });
21
20
  if (totalDocs === 0) {
22
21
  // First user becomes admin
23
22
  return {
24
23
  ...data,
25
- [roleField]: adminRole,
24
+ [roleField]: adminRole
26
25
  };
27
26
  }
28
27
  // Subsequent users get default role if not already set
29
28
  return {
30
29
  ...data,
31
- [roleField]: data[roleField] ?? defaultRole,
30
+ [roleField]: data[roleField] ?? defaultRole
32
31
  };
33
- }
34
- catch (error) {
32
+ } catch (error) {
35
33
  // On error, don't block user creation - just use provided or default role
36
34
  console.warn('[betterAuthCollections] Failed to check user count:', error);
37
35
  return {
38
36
  ...data,
39
- [roleField]: data[roleField] ?? defaultRole,
37
+ [roleField]: data[roleField] ?? defaultRole
40
38
  };
41
39
  }
42
40
  };
43
41
  }
44
42
  /**
45
43
  * Inject the first-user-admin hook into a collection's hooks.
46
- */
47
- function injectFirstUserAdminHook(collection, options, usersSlug) {
44
+ */ function injectFirstUserAdminHook(collection, options, usersSlug) {
48
45
  const hook = createFirstUserAdminHook(options, usersSlug);
49
46
  const existingHooks = collection.hooks?.beforeChange ?? [];
50
47
  return {
51
48
  ...collection,
52
49
  hooks: {
53
50
  ...collection.hooks,
54
- beforeChange: [hook, ...(Array.isArray(existingHooks) ? existingHooks : [existingHooks])],
55
- },
51
+ beforeChange: [
52
+ hook,
53
+ ...Array.isArray(existingHooks) ? existingHooks : [
54
+ existingHooks
55
+ ]
56
+ ]
57
+ }
56
58
  };
57
59
  }
58
60
  /**
59
61
  * Determine if a field should be saved to JWT.
60
62
  * Session-critical fields are included, large data fields are excluded.
61
- */
62
- function getSaveToJWT(modelKey, fieldName) {
63
+ */ function getSaveToJWT(modelKey, fieldName) {
63
64
  // Session fields - include core session data
64
65
  if (modelKey === 'session') {
65
- const includeFields = ['token', 'expiresAt', 'user', 'userId', 'ipAddress', 'userAgent', 'activeOrganizationId', 'activeTeamId'];
66
- const excludeFields = ['createdAt', 'updatedAt'];
67
- if (includeFields.some(f => fieldName === f || fieldName.endsWith(f.charAt(0).toUpperCase() + f.slice(1)))) {
66
+ const includeFields = [
67
+ 'token',
68
+ 'expiresAt',
69
+ 'user',
70
+ 'userId',
71
+ 'ipAddress',
72
+ 'userAgent',
73
+ 'activeOrganizationId',
74
+ 'activeTeamId'
75
+ ];
76
+ const excludeFields = [
77
+ 'createdAt',
78
+ 'updatedAt'
79
+ ];
80
+ if (includeFields.some((f)=>fieldName === f || fieldName.endsWith(f.charAt(0).toUpperCase() + f.slice(1)))) {
68
81
  return true;
69
82
  }
70
83
  if (excludeFields.includes(fieldName)) {
@@ -73,8 +86,19 @@ function getSaveToJWT(modelKey, fieldName) {
73
86
  }
74
87
  // User fields - include essential auth data
75
88
  if (modelKey === 'user') {
76
- const includeFields = ['role', 'email', 'emailVerified', 'name', 'twoFactorEnabled', 'banned'];
77
- const excludeFields = ['image', 'password', 'banReason'];
89
+ const includeFields = [
90
+ 'role',
91
+ 'email',
92
+ 'emailVerified',
93
+ 'name',
94
+ 'twoFactorEnabled',
95
+ 'banned'
96
+ ];
97
+ const excludeFields = [
98
+ 'image',
99
+ 'password',
100
+ 'banReason'
101
+ ];
78
102
  if (includeFields.includes(fieldName)) {
79
103
  return true;
80
104
  }
@@ -95,17 +119,15 @@ function getSaveToJWT(modelKey, fieldName) {
95
119
  }
96
120
  /**
97
121
  * Simple pluralization (add 's' suffix)
98
- */
99
- function pluralize(name) {
100
- if (name.endsWith('s'))
101
- return name;
122
+ */ function pluralize(name) {
123
+ if (name.endsWith('s')) return name;
102
124
  return `${name}s`;
103
125
  }
104
126
  function mapFieldType(type, fieldName, hasReferences) {
105
127
  if (hasReferences) {
106
128
  return 'relationship';
107
129
  }
108
- switch (type) {
130
+ switch(type){
109
131
  case 'boolean':
110
132
  return 'checkbox';
111
133
  case 'number':
@@ -113,15 +135,15 @@ function mapFieldType(type, fieldName, hasReferences) {
113
135
  case 'date':
114
136
  return 'date';
115
137
  case 'string':
116
- if (fieldName === 'email')
117
- return 'email';
138
+ if (fieldName === 'email') return 'email';
118
139
  return 'text';
119
140
  case 'json':
120
141
  case 'object':
121
142
  return 'json';
122
143
  case 'string[]':
123
144
  case 'array':
124
- return 'json'; // Payload doesn't have native string array, use JSON
145
+ return 'json' // Payload doesn't have native string array, use JSON
146
+ ;
125
147
  default:
126
148
  return 'text';
127
149
  }
@@ -135,8 +157,12 @@ function generateCollection(modelKey, table, usePlural, adminGroup, customAccess
135
157
  const baseName = table.modelName ?? modelKey;
136
158
  const slug = usePlural ? pluralize(baseName) : baseName;
137
159
  const fields = [];
138
- for (const [fieldKey, fieldDef] of Object.entries(table.fields)) {
139
- if (['id', 'createdAt', 'updatedAt'].includes(fieldKey)) {
160
+ for (const [fieldKey, fieldDef] of Object.entries(table.fields)){
161
+ if ([
162
+ 'id',
163
+ 'createdAt',
164
+ 'updatedAt'
165
+ ].includes(fieldKey)) {
140
166
  continue;
141
167
  }
142
168
  const fieldName = fieldDef.fieldName ?? fieldKey;
@@ -147,8 +173,7 @@ function generateCollection(modelKey, table, usePlural, adminGroup, customAccess
147
173
  let relationTo;
148
174
  if (fieldDef.references?.model) {
149
175
  relationTo = usePlural ? pluralize(fieldDef.references.model) : fieldDef.references.model;
150
- }
151
- else {
176
+ } else {
152
177
  relationTo = extractRelationTarget(fieldKey, usePlural);
153
178
  }
154
179
  const relFieldName = fieldName.replace(/(_id|Id)$/, '');
@@ -159,7 +184,9 @@ function generateCollection(modelKey, table, usePlural, adminGroup, customAccess
159
184
  relationTo,
160
185
  required: fieldDef.required ?? false,
161
186
  index: true,
162
- ...(saveToJWT !== undefined && { saveToJWT }),
187
+ ...saveToJWT !== undefined && {
188
+ saveToJWT
189
+ }
163
190
  });
164
191
  continue;
165
192
  }
@@ -167,10 +194,11 @@ function generateCollection(modelKey, table, usePlural, adminGroup, customAccess
167
194
  const field = {
168
195
  name: fieldName,
169
196
  type: fieldType,
170
- ...(saveToJWT !== undefined && { saveToJWT }),
197
+ ...saveToJWT !== undefined && {
198
+ saveToJWT
199
+ }
171
200
  };
172
- if (fieldDef.required)
173
- field.required = true;
201
+ if (fieldDef.required) field.required = true;
174
202
  if (fieldDef.unique) {
175
203
  field.unique = true;
176
204
  field.index = true;
@@ -180,8 +208,7 @@ function generateCollection(modelKey, table, usePlural, adminGroup, customAccess
180
208
  if (typeof defaultValue === 'function') {
181
209
  try {
182
210
  defaultValue = defaultValue();
183
- }
184
- catch {
211
+ } catch {
185
212
  defaultValue = undefined;
186
213
  }
187
214
  }
@@ -191,33 +218,37 @@ function generateCollection(modelKey, table, usePlural, adminGroup, customAccess
191
218
  }
192
219
  fields.push(field);
193
220
  }
194
- const titleField = ['name', 'email', 'title', 'identifier'].find((f) => fields.some((field) => 'name' in field && field.name === f));
221
+ const titleField = [
222
+ 'name',
223
+ 'email',
224
+ 'title',
225
+ 'identifier'
226
+ ].find((f)=>fields.some((field)=>'name' in field && field.name === f));
195
227
  // Default access: admin-only read/delete, disabled manual create/update via admin UI
196
228
  // The adapter uses overrideAccess: true for programmatic operations from Better Auth
197
229
  const defaultAccess = {
198
- read: ({ req }) => req.user?.role === 'admin',
199
- create: () => false, // Manual creation disabled - Better Auth manages these
200
- update: () => false, // Manual update disabled - Better Auth manages these
201
- delete: ({ req }) => req.user?.role === 'admin',
230
+ read: isAdmin(),
231
+ create: ()=>false,
232
+ update: ()=>false,
233
+ delete: isAdmin()
202
234
  };
203
235
  return {
204
236
  slug,
205
237
  admin: {
206
238
  useAsTitle: titleField ?? 'id',
207
239
  group: adminGroup,
208
- description: `Auto-generated from Better Auth schema (${modelKey})`,
240
+ description: `Auto-generated from Better Auth schema (${modelKey})`
209
241
  },
210
242
  access: customAccess ?? defaultAccess,
211
243
  fields,
212
- timestamps: true,
244
+ timestamps: true
213
245
  };
214
246
  }
215
247
  /**
216
248
  * Get existing field names from a collection, handling nested field structures.
217
- */
218
- function getExistingFieldNames(fields) {
249
+ */ function getExistingFieldNames(fields) {
219
250
  const names = new Set();
220
- for (const field of fields) {
251
+ for (const field of fields){
221
252
  if ('name' in field && field.name) {
222
253
  names.add(field.name);
223
254
  }
@@ -227,21 +258,22 @@ function getExistingFieldNames(fields) {
227
258
  /**
228
259
  * Augment an existing collection with missing fields from Better Auth schema.
229
260
  * This ensures user-defined collections (like 'users') get plugin fields automatically.
230
- */
231
- function augmentCollectionWithMissingFields(collection, table, usePlural, modelKey, configureSaveToJWT = true) {
261
+ */ function augmentCollectionWithMissingFields(collection, table, usePlural, modelKey, configureSaveToJWT = true) {
232
262
  const existingFieldNames = getExistingFieldNames(collection.fields);
233
263
  const missingFields = [];
234
- for (const [fieldKey, fieldDef] of Object.entries(table.fields)) {
264
+ for (const [fieldKey, fieldDef] of Object.entries(table.fields)){
235
265
  // Skip standard fields that Payload handles
236
- if (['id', 'createdAt', 'updatedAt'].includes(fieldKey)) {
266
+ if ([
267
+ 'id',
268
+ 'createdAt',
269
+ 'updatedAt'
270
+ ].includes(fieldKey)) {
237
271
  continue;
238
272
  }
239
273
  const fieldName = fieldDef.fieldName ?? fieldKey;
240
274
  const hasReferences = fieldDef.references !== undefined;
241
275
  // For reference fields, check the name without Id suffix
242
- const payloadFieldName = hasReferences
243
- ? fieldName.replace(/(_id|Id)$/, '')
244
- : fieldName;
276
+ const payloadFieldName = hasReferences ? fieldName.replace(/(_id|Id)$/, '') : fieldName;
245
277
  // Skip if field already exists
246
278
  if (existingFieldNames.has(payloadFieldName)) {
247
279
  continue;
@@ -252,8 +284,7 @@ function augmentCollectionWithMissingFields(collection, table, usePlural, modelK
252
284
  let relationTo;
253
285
  if (fieldDef.references?.model) {
254
286
  relationTo = usePlural ? pluralize(fieldDef.references.model) : fieldDef.references.model;
255
- }
256
- else {
287
+ } else {
257
288
  relationTo = extractRelationTarget(fieldKey, usePlural);
258
289
  }
259
290
  const saveToJWT = configureSaveToJWT ? getSaveToJWT(modelKey, payloadFieldName) : undefined;
@@ -264,23 +295,25 @@ function augmentCollectionWithMissingFields(collection, table, usePlural, modelK
264
295
  required: fieldDef.required ?? false,
265
296
  index: true,
266
297
  admin: {
267
- description: `Auto-added by Better Auth (${fieldKey})`,
298
+ description: `Auto-added by Better Auth (${fieldKey})`
268
299
  },
269
- ...(saveToJWT !== undefined && { saveToJWT }),
300
+ ...saveToJWT !== undefined && {
301
+ saveToJWT
302
+ }
270
303
  });
271
- }
272
- else {
304
+ } else {
273
305
  const saveToJWT = configureSaveToJWT ? getSaveToJWT(modelKey, payloadFieldName) : undefined;
274
306
  const field = {
275
307
  name: payloadFieldName,
276
308
  type: fieldType,
277
309
  admin: {
278
- description: `Auto-added by Better Auth (${fieldKey})`,
310
+ description: `Auto-added by Better Auth (${fieldKey})`
279
311
  },
280
- ...(saveToJWT !== undefined && { saveToJWT }),
312
+ ...saveToJWT !== undefined && {
313
+ saveToJWT
314
+ }
281
315
  };
282
- if (fieldDef.required)
283
- field.required = true;
316
+ if (fieldDef.required) field.required = true;
284
317
  if (fieldDef.unique) {
285
318
  field.unique = true;
286
319
  field.index = true;
@@ -290,8 +323,7 @@ function augmentCollectionWithMissingFields(collection, table, usePlural, modelK
290
323
  if (typeof defaultValue === 'function') {
291
324
  try {
292
325
  defaultValue = defaultValue();
293
- }
294
- catch {
326
+ } catch {
295
327
  defaultValue = undefined;
296
328
  }
297
329
  }
@@ -309,7 +341,10 @@ function augmentCollectionWithMissingFields(collection, table, usePlural, modelK
309
341
  // Return augmented collection
310
342
  return {
311
343
  ...collection,
312
- fields: [...collection.fields, ...missingFields],
344
+ fields: [
345
+ ...collection.fields,
346
+ ...missingFields
347
+ ]
313
348
  };
314
349
  }
315
350
  /**
@@ -344,26 +379,25 @@ function augmentCollectionWithMissingFields(collection, table, usePlural, modelK
344
379
  * },
345
380
  * })
346
381
  * ```
347
- */
348
- export function betterAuthCollections(options = {}) {
349
- const { betterAuthOptions = {}, skipCollections = ['user'], adminGroup = 'Auth', access, usePlural = true, configureSaveToJWT = true, firstUserAdmin, customizeCollection, } = options;
382
+ */ export function betterAuthCollections(options = {}) {
383
+ const { betterAuthOptions = {}, skipCollections = [
384
+ 'user'
385
+ ], adminGroup = 'Auth', access, usePlural = true, configureSaveToJWT = true, firstUserAdmin, customizeCollection } = options;
350
386
  // Parse firstUserAdmin option (defaults to true)
351
- const firstUserAdminOptions = firstUserAdmin === false
352
- ? null
353
- : typeof firstUserAdmin === 'object'
354
- ? firstUserAdmin
355
- : {}; // true or undefined = enabled with defaults
356
- return (incomingConfig) => {
357
- const existingCollections = new Map((incomingConfig.collections ?? []).map((c) => [c.slug, c]));
387
+ const firstUserAdminOptions = firstUserAdmin === false ? null : typeof firstUserAdmin === 'object' ? firstUserAdmin : {} // true or undefined = enabled with defaults
388
+ ;
389
+ return (incomingConfig)=>{
390
+ const existingCollections = new Map((incomingConfig.collections ?? []).map((c)=>[
391
+ c.slug,
392
+ c
393
+ ]));
358
394
  const tables = getAuthTables(betterAuthOptions);
359
395
  const generatedCollections = [];
360
396
  const augmentedCollections = [];
361
397
  // Calculate users collection slug for firstUserAdmin hook
362
398
  const userTable = tables['user'];
363
- const usersSlug = usePlural
364
- ? pluralize(userTable?.modelName ?? 'user')
365
- : (userTable?.modelName ?? 'user');
366
- for (const [modelKey, table] of Object.entries(tables)) {
399
+ const usersSlug = usePlural ? pluralize(userTable?.modelName ?? 'user') : userTable?.modelName ?? 'user';
400
+ for (const [modelKey, table] of Object.entries(tables)){
367
401
  // Calculate slug
368
402
  const baseName = table.modelName ?? modelKey;
369
403
  const slug = usePlural ? pluralize(baseName) : baseName;
@@ -398,14 +432,18 @@ export function betterAuthCollections(options = {}) {
398
432
  generatedCollections.push(collection);
399
433
  }
400
434
  // Merge: replace augmented collections, add new ones
401
- const finalCollections = (incomingConfig.collections ?? []).map((c) => {
402
- const augmented = augmentedCollections.find((a) => a.slug === c.slug);
435
+ const finalCollections = (incomingConfig.collections ?? []).map((c)=>{
436
+ const augmented = augmentedCollections.find((a)=>a.slug === c.slug);
403
437
  return augmented ?? c;
404
438
  });
405
439
  return {
406
440
  ...incomingConfig,
407
- collections: [...finalCollections, ...generatedCollections],
441
+ collections: [
442
+ ...finalCollections,
443
+ ...generatedCollections
444
+ ]
408
445
  };
409
446
  };
410
447
  }
448
+
411
449
  //# sourceMappingURL=collections.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"collections.js","sourceRoot":"","sources":["../../src/adapter/collections.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/adapter/collections.ts"],"sourcesContent":["/**\n * Auto-generate Payload collections from Better Auth schema\n *\n * @packageDocumentation\n */\n\nimport type { Config, CollectionConfig, Field, Plugin, CollectionBeforeChangeHook } from 'payload'\nimport type { BetterAuthOptions } from 'better-auth'\nimport { getAuthTables } from 'better-auth/db'\nimport type { FirstUserAdminOptions } from '../utils/firstUserAdmin.js'\nimport { isAdmin } from '../utils/access.js'\n\nexport type { FirstUserAdminOptions }\n\nexport type BetterAuthCollectionsOptions = {\n /**\n * Better Auth options. Pass the same options you use for betterAuth().\n * The plugin reads the schema to generate collections.\n */\n betterAuthOptions?: BetterAuthOptions\n\n /**\n * Collections to skip (they already exist in your config)\n * Default: ['user'] - assumes you have a Users collection\n */\n skipCollections?: string[]\n\n /**\n * Admin group name for generated collections\n * Default: 'Auth'\n */\n adminGroup?: string\n\n /**\n * Custom access control for generated collections.\n * By default, only admins can read/delete, and create/update are disabled.\n */\n access?: CollectionConfig['access']\n\n /**\n * Whether to pluralize collection slugs (add 's' suffix).\n * Should match your adapter's usePlural setting.\n * Default: true (matches Payload conventions)\n */\n usePlural?: boolean\n\n /**\n * Configure saveToJWT for session-related fields.\n * This controls which fields are included in JWT tokens.\n * Default: true\n */\n configureSaveToJWT?: boolean\n\n /**\n * Automatically make the first registered user an admin.\n * Enabled by default. Set to `false` to disable, or provide options to customize.\n *\n * @default true\n *\n * @example Disable\n * ```ts\n * betterAuthCollections({\n * betterAuthOptions: authOptions,\n * firstUserAdmin: false,\n * })\n * ```\n *\n * @example Custom roles\n * ```ts\n * betterAuthCollections({\n * betterAuthOptions: authOptions,\n * firstUserAdmin: {\n * adminRole: 'super-admin',\n * defaultRole: 'member',\n * },\n * })\n * ```\n */\n firstUserAdmin?: boolean | FirstUserAdminOptions\n\n /**\n * Customize a generated collection before it's added to config.\n * Use this to add hooks, modify fields, or adjust any collection setting.\n *\n * @example\n * ```ts\n * customizeCollection: (modelKey, collection) => {\n * if (modelKey === 'session') {\n * return {\n * ...collection,\n * hooks: {\n * afterDelete: [myCleanupHook],\n * },\n * }\n * }\n * return collection\n * }\n * ```\n */\n customizeCollection?: (\n modelKey: string,\n collection: CollectionConfig\n ) => CollectionConfig\n}\n\n/**\n * Creates a beforeChange hook that makes the first user an admin.\n */\nfunction createFirstUserAdminHook(\n options: FirstUserAdminOptions,\n usersSlug: string\n): CollectionBeforeChangeHook {\n const {\n adminRole = 'admin',\n defaultRole = 'user',\n roleField = 'role',\n } = options\n\n return async ({ data, operation, req }) => {\n if (operation !== 'create') {\n return data\n }\n\n try {\n const { totalDocs } = await req.payload.count({\n collection: usersSlug,\n overrideAccess: true,\n })\n\n if (totalDocs === 0) {\n // First user becomes admin\n return {\n ...data,\n [roleField]: adminRole,\n }\n }\n\n // Subsequent users get default role if not already set\n return {\n ...data,\n [roleField]: data[roleField] ?? defaultRole,\n }\n } catch (error) {\n // On error, don't block user creation - just use provided or default role\n console.warn('[betterAuthCollections] Failed to check user count:', error)\n return {\n ...data,\n [roleField]: data[roleField] ?? defaultRole,\n }\n }\n }\n}\n\n/**\n * Inject the first-user-admin hook into a collection's hooks.\n */\nfunction injectFirstUserAdminHook(\n collection: CollectionConfig,\n options: FirstUserAdminOptions,\n usersSlug: string\n): CollectionConfig {\n const hook = createFirstUserAdminHook(options, usersSlug)\n const existingHooks = collection.hooks?.beforeChange ?? []\n\n return {\n ...collection,\n hooks: {\n ...collection.hooks,\n beforeChange: [hook, ...(Array.isArray(existingHooks) ? existingHooks : [existingHooks])],\n },\n }\n}\n\n/**\n * Determine if a field should be saved to JWT.\n * Session-critical fields are included, large data fields are excluded.\n */\nfunction getSaveToJWT(modelKey: string, fieldName: string): boolean | undefined {\n // Session fields - include core session data\n if (modelKey === 'session') {\n const includeFields = ['token', 'expiresAt', 'user', 'userId', 'ipAddress', 'userAgent', 'activeOrganizationId', 'activeTeamId']\n const excludeFields = ['createdAt', 'updatedAt']\n\n if (includeFields.some(f => fieldName === f || fieldName.endsWith(f.charAt(0).toUpperCase() + f.slice(1)))) {\n return true\n }\n if (excludeFields.includes(fieldName)) {\n return false\n }\n }\n\n // User fields - include essential auth data\n if (modelKey === 'user') {\n const includeFields = ['role', 'email', 'emailVerified', 'name', 'twoFactorEnabled', 'banned']\n const excludeFields = ['image', 'password', 'banReason']\n\n if (includeFields.includes(fieldName)) {\n return true\n }\n if (excludeFields.includes(fieldName)) {\n return false\n }\n }\n\n // Account fields - generally not in JWT\n if (modelKey === 'account') {\n return false\n }\n\n // Verification fields - not in JWT\n if (modelKey === 'verification') {\n return false\n }\n\n // Default: don't set (let Payload decide)\n return undefined\n}\n\n/**\n * Simple pluralization (add 's' suffix)\n */\nfunction pluralize(name: string): string {\n if (name.endsWith('s')) return name\n return `${name}s`\n}\n\nfunction mapFieldType(\n type: string,\n fieldName: string,\n hasReferences: boolean\n): Field['type'] {\n if (hasReferences) {\n return 'relationship'\n }\n\n switch (type) {\n case 'boolean':\n return 'checkbox'\n case 'number':\n return 'number'\n case 'date':\n return 'date'\n case 'string':\n if (fieldName === 'email') return 'email'\n return 'text'\n case 'json':\n case 'object':\n return 'json'\n case 'string[]':\n case 'array':\n return 'json' // Payload doesn't have native string array, use JSON\n default:\n return 'text'\n }\n}\n\nfunction extractRelationTarget(\n fieldName: string,\n usePlural: boolean\n): string {\n const base = fieldName.replace(/(_id|Id)$/, '')\n return usePlural ? pluralize(base) : base\n}\n\nfunction generateCollection(\n modelKey: string,\n table: ReturnType<typeof getAuthTables>[string],\n usePlural: boolean,\n adminGroup: string,\n customAccess?: BetterAuthCollectionsOptions['access'],\n configureSaveToJWT = true\n): CollectionConfig {\n // Use modelName from schema if set, otherwise apply pluralization to modelKey\n const baseName = table.modelName ?? modelKey\n const slug = usePlural ? pluralize(baseName) : baseName\n const fields: Field[] = []\n\n for (const [fieldKey, fieldDef] of Object.entries(table.fields)) {\n if (['id', 'createdAt', 'updatedAt'].includes(fieldKey)) {\n continue\n }\n\n const fieldName = fieldDef.fieldName ?? fieldKey\n const hasReferences = fieldDef.references !== undefined\n const fieldType = mapFieldType(fieldDef.type as string, fieldKey, hasReferences)\n\n if (fieldType === 'relationship') {\n // Use schema reference if available, otherwise infer from field name\n let relationTo: string\n if (fieldDef.references?.model) {\n relationTo = usePlural ? pluralize(fieldDef.references.model) : fieldDef.references.model\n } else {\n relationTo = extractRelationTarget(fieldKey, usePlural)\n }\n\n const relFieldName = fieldName.replace(/(_id|Id)$/, '')\n const saveToJWT = configureSaveToJWT ? getSaveToJWT(modelKey, relFieldName) : undefined\n\n fields.push({\n name: relFieldName,\n type: 'relationship',\n relationTo,\n required: fieldDef.required ?? false,\n index: true,\n ...(saveToJWT !== undefined && { saveToJWT }),\n } as Field)\n continue\n }\n\n const saveToJWT = configureSaveToJWT ? getSaveToJWT(modelKey, fieldName) : undefined\n const field: Record<string, unknown> = {\n name: fieldName,\n type: fieldType,\n ...(saveToJWT !== undefined && { saveToJWT }),\n }\n\n if (fieldDef.required) field.required = true\n if (fieldDef.unique) {\n field.unique = true\n field.index = true\n }\n\n if (fieldDef.defaultValue !== undefined) {\n let defaultValue: unknown = fieldDef.defaultValue\n if (typeof defaultValue === 'function') {\n try {\n defaultValue = (defaultValue as () => unknown)()\n } catch {\n defaultValue = undefined\n }\n }\n if (defaultValue !== undefined && defaultValue !== null) {\n field.defaultValue = defaultValue\n }\n }\n\n fields.push(field as Field)\n }\n\n const titleField = ['name', 'email', 'title', 'identifier'].find((f) =>\n fields.some((field) => 'name' in field && field.name === f)\n )\n\n // Default access: admin-only read/delete, disabled manual create/update via admin UI\n // The adapter uses overrideAccess: true for programmatic operations from Better Auth\n const defaultAccess: CollectionConfig['access'] = {\n read: isAdmin(),\n create: () => false, // Manual creation disabled - Better Auth manages these\n update: () => false, // Manual update disabled - Better Auth manages these\n delete: isAdmin(),\n }\n\n return {\n slug,\n admin: {\n useAsTitle: titleField ?? 'id',\n group: adminGroup,\n description: `Auto-generated from Better Auth schema (${modelKey})`,\n },\n access: customAccess ?? defaultAccess,\n fields,\n timestamps: true,\n }\n}\n\n/**\n * Get existing field names from a collection, handling nested field structures.\n */\nfunction getExistingFieldNames(fields: Field[]): Set<string> {\n const names = new Set<string>()\n for (const field of fields) {\n if ('name' in field && field.name) {\n names.add(field.name)\n }\n }\n return names\n}\n\n/**\n * Augment an existing collection with missing fields from Better Auth schema.\n * This ensures user-defined collections (like 'users') get plugin fields automatically.\n */\nfunction augmentCollectionWithMissingFields(\n collection: CollectionConfig,\n table: ReturnType<typeof getAuthTables>[string],\n usePlural: boolean,\n modelKey: string,\n configureSaveToJWT = true\n): CollectionConfig {\n const existingFieldNames = getExistingFieldNames(collection.fields)\n const missingFields: Field[] = []\n\n for (const [fieldKey, fieldDef] of Object.entries(table.fields)) {\n // Skip standard fields that Payload handles\n if (['id', 'createdAt', 'updatedAt'].includes(fieldKey)) {\n continue\n }\n\n const fieldName = fieldDef.fieldName ?? fieldKey\n const hasReferences = fieldDef.references !== undefined\n\n // For reference fields, check the name without Id suffix\n const payloadFieldName = hasReferences\n ? fieldName.replace(/(_id|Id)$/, '')\n : fieldName\n\n // Skip if field already exists\n if (existingFieldNames.has(payloadFieldName)) {\n continue\n }\n\n // Generate the missing field\n const fieldType = mapFieldType(fieldDef.type as string, fieldKey, hasReferences)\n\n if (fieldType === 'relationship') {\n let relationTo: string\n if (fieldDef.references?.model) {\n relationTo = usePlural ? pluralize(fieldDef.references.model) : fieldDef.references.model\n } else {\n relationTo = extractRelationTarget(fieldKey, usePlural)\n }\n\n const saveToJWT = configureSaveToJWT ? getSaveToJWT(modelKey, payloadFieldName) : undefined\n\n missingFields.push({\n name: payloadFieldName,\n type: 'relationship',\n relationTo,\n required: fieldDef.required ?? false,\n index: true,\n admin: {\n description: `Auto-added by Better Auth (${fieldKey})`,\n },\n ...(saveToJWT !== undefined && { saveToJWT }),\n } as Field)\n } else {\n const saveToJWT = configureSaveToJWT ? getSaveToJWT(modelKey, payloadFieldName) : undefined\n const field: Record<string, unknown> = {\n name: payloadFieldName,\n type: fieldType,\n admin: {\n description: `Auto-added by Better Auth (${fieldKey})`,\n },\n ...(saveToJWT !== undefined && { saveToJWT }),\n }\n\n if (fieldDef.required) field.required = true\n if (fieldDef.unique) {\n field.unique = true\n field.index = true\n }\n\n if (fieldDef.defaultValue !== undefined) {\n let defaultValue: unknown = fieldDef.defaultValue\n if (typeof defaultValue === 'function') {\n try {\n defaultValue = (defaultValue as () => unknown)()\n } catch {\n defaultValue = undefined\n }\n }\n if (defaultValue !== undefined && defaultValue !== null) {\n field.defaultValue = defaultValue\n }\n }\n\n missingFields.push(field as Field)\n }\n }\n\n // Return original if no fields to add\n if (missingFields.length === 0) {\n return collection\n }\n\n // Return augmented collection\n return {\n ...collection,\n fields: [...collection.fields, ...missingFields],\n }\n}\n\n/**\n * Payload plugin that auto-generates collections from Better Auth schema.\n *\n * @example Basic usage\n * ```ts\n * import { betterAuthCollections } from '@delmaredigital/payload-better-auth'\n *\n * export default buildConfig({\n * plugins: [\n * betterAuthCollections({\n * betterAuthOptions: { ... },\n * skipCollections: ['user'], // Define Users yourself\n * }),\n * ],\n * })\n * ```\n *\n * @example With customization callback\n * ```ts\n * betterAuthCollections({\n * betterAuthOptions: authOptions,\n * customizeCollection: (modelKey, collection) => {\n * if (modelKey === 'session') {\n * return {\n * ...collection,\n * hooks: { afterDelete: [cleanupHook] },\n * }\n * }\n * return collection\n * },\n * })\n * ```\n */\nexport function betterAuthCollections(\n options: BetterAuthCollectionsOptions = {}\n): Plugin {\n const {\n betterAuthOptions = {},\n skipCollections = ['user'],\n adminGroup = 'Auth',\n access,\n usePlural = true,\n configureSaveToJWT = true,\n firstUserAdmin,\n customizeCollection,\n } = options\n\n // Parse firstUserAdmin option (defaults to true)\n const firstUserAdminOptions: FirstUserAdminOptions | null =\n firstUserAdmin === false\n ? null\n : typeof firstUserAdmin === 'object'\n ? firstUserAdmin\n : {} // true or undefined = enabled with defaults\n\n return (incomingConfig: Config): Config => {\n const existingCollections = new Map(\n (incomingConfig.collections ?? []).map((c) => [c.slug, c])\n )\n\n const tables = getAuthTables(betterAuthOptions)\n const generatedCollections: CollectionConfig[] = []\n const augmentedCollections: CollectionConfig[] = []\n\n // Calculate users collection slug for firstUserAdmin hook\n const userTable = tables['user']\n const usersSlug = usePlural\n ? pluralize(userTable?.modelName ?? 'user')\n : (userTable?.modelName ?? 'user')\n\n for (const [modelKey, table] of Object.entries(tables)) {\n // Calculate slug\n const baseName = table.modelName ?? modelKey\n const slug = usePlural ? pluralize(baseName) : baseName\n\n // Check if this collection already exists\n const existingCollection = existingCollections.get(slug)\n\n if (existingCollection) {\n // Augment existing collection with missing fields from Better Auth schema\n let augmented = augmentCollectionWithMissingFields(\n existingCollection,\n table,\n usePlural,\n modelKey,\n configureSaveToJWT\n )\n\n // Inject first-user-admin hook for user collection\n if (modelKey === 'user' && firstUserAdminOptions) {\n augmented = injectFirstUserAdminHook(augmented, firstUserAdminOptions, usersSlug)\n }\n\n if (augmented !== existingCollection) {\n augmentedCollections.push(augmented)\n existingCollections.set(slug, augmented)\n }\n continue\n }\n\n // Skip if explicitly told to (but still augment if exists above)\n if (skipCollections.includes(modelKey)) {\n continue\n }\n\n let collection = generateCollection(\n modelKey,\n table,\n usePlural,\n adminGroup,\n access,\n configureSaveToJWT\n )\n\n // Inject first-user-admin hook for user collection\n if (modelKey === 'user' && firstUserAdminOptions) {\n collection = injectFirstUserAdminHook(collection, firstUserAdminOptions, usersSlug)\n }\n\n // Apply customization callback if provided\n if (customizeCollection) {\n collection = customizeCollection(modelKey, collection)\n }\n\n generatedCollections.push(collection)\n }\n\n // Merge: replace augmented collections, add new ones\n const finalCollections = (incomingConfig.collections ?? []).map((c) => {\n const augmented = augmentedCollections.find((a) => a.slug === c.slug)\n return augmented ?? c\n })\n\n return {\n ...incomingConfig,\n collections: [...finalCollections, ...generatedCollections],\n }\n }\n}\n"],"names":["getAuthTables","isAdmin","createFirstUserAdminHook","options","usersSlug","adminRole","defaultRole","roleField","data","operation","req","totalDocs","payload","count","collection","overrideAccess","error","console","warn","injectFirstUserAdminHook","hook","existingHooks","hooks","beforeChange","Array","isArray","getSaveToJWT","modelKey","fieldName","includeFields","excludeFields","some","f","endsWith","charAt","toUpperCase","slice","includes","undefined","pluralize","name","mapFieldType","type","hasReferences","extractRelationTarget","usePlural","base","replace","generateCollection","table","adminGroup","customAccess","configureSaveToJWT","baseName","modelName","slug","fields","fieldKey","fieldDef","Object","entries","references","fieldType","relationTo","model","relFieldName","saveToJWT","push","required","index","field","unique","defaultValue","titleField","find","defaultAccess","read","create","update","delete","admin","useAsTitle","group","description","access","timestamps","getExistingFieldNames","names","Set","add","augmentCollectionWithMissingFields","existingFieldNames","missingFields","payloadFieldName","has","length","betterAuthCollections","betterAuthOptions","skipCollections","firstUserAdmin","customizeCollection","firstUserAdminOptions","incomingConfig","existingCollections","Map","collections","map","c","tables","generatedCollections","augmentedCollections","userTable","existingCollection","get","augmented","set","finalCollections","a"],"mappings":"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"}