@opensaas/stack-auth 0.36.0 → 0.37.0
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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +109 -0
- package/CLAUDE.md +104 -7
- package/README.md +18 -7
- package/dist/config/adopt-better-auth-tables.d.ts +47 -0
- package/dist/config/adopt-better-auth-tables.d.ts.map +1 -1
- package/dist/config/adopt-better-auth-tables.js +29 -1
- package/dist/config/adopt-better-auth-tables.js.map +1 -1
- package/dist/config/derive-auth-lists.d.ts +7 -5
- package/dist/config/derive-auth-lists.d.ts.map +1 -1
- package/dist/config/derive-auth-lists.js +33 -34
- package/dist/config/derive-auth-lists.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +41 -11
- package/dist/config/index.js.map +1 -1
- package/dist/config/plugin.d.ts.map +1 -1
- package/dist/config/plugin.js +39 -27
- package/dist/config/plugin.js.map +1 -1
- package/dist/config/types.d.ts +126 -24
- package/dist/config/types.d.ts.map +1 -1
- package/dist/server/index.d.ts +29 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +193 -66
- package/dist/server/index.js.map +1 -1
- package/package.json +3 -3
- package/src/config/adopt-better-auth-tables.ts +70 -1
- package/src/config/derive-auth-lists.ts +37 -38
- package/src/config/index.ts +47 -12
- package/src/config/plugin.ts +39 -27
- package/src/config/types.ts +127 -21
- package/src/server/index.ts +244 -80
- package/tests/adopt-better-auth-tables.test.ts +99 -0
- package/tests/config.test.ts +66 -8
- package/tests/derive-auth-lists.test.ts +79 -5
- package/tests/generated-fk-shape.test.ts +65 -0
- package/tests/plugin-derived-keys.test.ts +48 -0
- package/tests/server.test.ts +517 -0
- package/tsconfig.tsbuildinfo +1 -1
package/src/config/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
EmailPasswordConfig,
|
|
8
8
|
EmailVerificationConfig,
|
|
9
9
|
PasswordResetConfig,
|
|
10
|
+
SendAuthEmail,
|
|
10
11
|
} from './types.js'
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -26,14 +27,24 @@ const DEFAULT_MODEL_NAMES = {
|
|
|
26
27
|
* falling back to the better-auth default model name and an empty column map.
|
|
27
28
|
* The model's Postgres schema is the per-model `schema` override when present,
|
|
28
29
|
* otherwise the plugin-level `schema` default (or `undefined` for `public`).
|
|
30
|
+
*
|
|
31
|
+
* `tableName` defaults to today's behaviour when not explicitly set: it
|
|
32
|
+
* follows `modelName` when that differs from the better-auth default (so a
|
|
33
|
+
* renamed list still pins its table via `@@map`), otherwise it stays unset.
|
|
34
|
+
* An explicit `tableName` is independent of `modelName` — it lets a renamed
|
|
35
|
+
* list key adopt a differently-named live table (e.g. better-auth's own
|
|
36
|
+
* default lowercase table names).
|
|
29
37
|
*/
|
|
30
38
|
function normalizeModelConfig(
|
|
31
39
|
config: AuthModelConfig | undefined,
|
|
32
40
|
defaultModelName: string,
|
|
33
41
|
defaultSchema: string | undefined,
|
|
34
42
|
): NormalizedAuthModelConfig {
|
|
43
|
+
const modelName = config?.modelName || defaultModelName
|
|
44
|
+
const tableName = config?.tableName ?? (modelName !== defaultModelName ? modelName : undefined)
|
|
35
45
|
return {
|
|
36
|
-
modelName
|
|
46
|
+
modelName,
|
|
47
|
+
tableName,
|
|
37
48
|
fields: config?.fields || {},
|
|
38
49
|
schema: config?.schema ?? defaultSchema,
|
|
39
50
|
}
|
|
@@ -58,6 +69,21 @@ function normalizeAuthModels(config: AuthConfig): NormalizedAuthModels {
|
|
|
58
69
|
}
|
|
59
70
|
}
|
|
60
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Default `sendResetPassword`/`sendVerificationEmail` — logs to console
|
|
74
|
+
* instead of sending, matching the pre-existing "no sendEmail configured"
|
|
75
|
+
* behavior for apps that haven't wired a real email provider yet.
|
|
76
|
+
*/
|
|
77
|
+
function defaultSendAuthEmail(kind: 'password reset' | 'verification'): SendAuthEmail {
|
|
78
|
+
return async ({ user, url }) => {
|
|
79
|
+
console.log(
|
|
80
|
+
`[Auth] ${kind[0].toUpperCase()}${kind.slice(1)} email not sent (no callback configured):`,
|
|
81
|
+
)
|
|
82
|
+
console.log(`To: ${user.email}`)
|
|
83
|
+
console.log(`URL: ${url}`)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
61
87
|
/**
|
|
62
88
|
* Normalize auth configuration with defaults
|
|
63
89
|
*/
|
|
@@ -69,8 +95,16 @@ export function normalizeAuthConfig(config: AuthConfig): NormalizedAuthConfig {
|
|
|
69
95
|
minPasswordLength: (config.emailAndPassword as EmailPasswordConfig).minPasswordLength ?? 8,
|
|
70
96
|
requireConfirmation:
|
|
71
97
|
(config.emailAndPassword as EmailPasswordConfig).requireConfirmation ?? true,
|
|
98
|
+
sendResetPassword:
|
|
99
|
+
(config.emailAndPassword as EmailPasswordConfig).sendResetPassword ??
|
|
100
|
+
defaultSendAuthEmail('password reset'),
|
|
101
|
+
}
|
|
102
|
+
: {
|
|
103
|
+
enabled: false as const,
|
|
104
|
+
minPasswordLength: 8,
|
|
105
|
+
requireConfirmation: true,
|
|
106
|
+
sendResetPassword: defaultSendAuthEmail('password reset'),
|
|
72
107
|
}
|
|
73
|
-
: { enabled: false as const, minPasswordLength: 8, requireConfirmation: true }
|
|
74
108
|
|
|
75
109
|
// Email verification defaults
|
|
76
110
|
const emailVerification = config.emailVerification?.enabled
|
|
@@ -79,8 +113,16 @@ export function normalizeAuthConfig(config: AuthConfig): NormalizedAuthConfig {
|
|
|
79
113
|
sendOnSignUp: (config.emailVerification as EmailVerificationConfig).sendOnSignUp ?? true,
|
|
80
114
|
tokenExpiration:
|
|
81
115
|
(config.emailVerification as EmailVerificationConfig).tokenExpiration ?? 86400,
|
|
116
|
+
sendVerificationEmail:
|
|
117
|
+
(config.emailVerification as EmailVerificationConfig).sendVerificationEmail ??
|
|
118
|
+
defaultSendAuthEmail('verification'),
|
|
119
|
+
}
|
|
120
|
+
: {
|
|
121
|
+
enabled: false as const,
|
|
122
|
+
sendOnSignUp: true,
|
|
123
|
+
tokenExpiration: 86400,
|
|
124
|
+
sendVerificationEmail: defaultSendAuthEmail('verification'),
|
|
82
125
|
}
|
|
83
|
-
: { enabled: false as const, sendOnSignUp: true, tokenExpiration: 86400 }
|
|
84
126
|
|
|
85
127
|
// Password reset defaults
|
|
86
128
|
const passwordReset = config.passwordReset?.enabled
|
|
@@ -93,7 +135,7 @@ export function normalizeAuthConfig(config: AuthConfig): NormalizedAuthConfig {
|
|
|
93
135
|
// Session defaults
|
|
94
136
|
const session = {
|
|
95
137
|
expiresIn: config.session?.expiresIn || 604800, // 7 days
|
|
96
|
-
updateAge: config.session?.updateAge ??
|
|
138
|
+
updateAge: config.session?.updateAge ?? 86400, // 1 day, matching better-auth's own default
|
|
97
139
|
}
|
|
98
140
|
|
|
99
141
|
// Session fields defaults
|
|
@@ -114,16 +156,9 @@ export function normalizeAuthConfig(config: AuthConfig): NormalizedAuthConfig {
|
|
|
114
156
|
sessionFields,
|
|
115
157
|
extendUserList: config.extendUserList || {},
|
|
116
158
|
access: config.access || {},
|
|
117
|
-
sendEmail:
|
|
118
|
-
config.sendEmail ||
|
|
119
|
-
(async ({ to, subject, html }) => {
|
|
120
|
-
console.log('[Auth] Email not sent (no sendEmail configured):')
|
|
121
|
-
console.log(`To: ${to}`)
|
|
122
|
-
console.log(`Subject: ${subject}`)
|
|
123
|
-
console.log(`Body: ${html}`)
|
|
124
|
-
}),
|
|
125
159
|
betterAuthPlugins: config.betterAuthPlugins || [],
|
|
126
160
|
rateLimit: config.rateLimit,
|
|
161
|
+
betterAuthOptions: config.betterAuthOptions || {},
|
|
127
162
|
}
|
|
128
163
|
}
|
|
129
164
|
|
package/src/config/plugin.ts
CHANGED
|
@@ -62,7 +62,45 @@ export function authPlugin(config: AuthConfig): Plugin {
|
|
|
62
62
|
verification: normalized.models.verification.modelName,
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
//
|
|
65
|
+
// Add all auth lists FIRST, before any better-auth plugin schema
|
|
66
|
+
// extension is processed. This must happen before the betterAuthPlugins
|
|
67
|
+
// loop below so a base-model extension (e.g. a plugin's `schema: {
|
|
68
|
+
// user: { fields: … } }`) always finds the real derived list already
|
|
69
|
+
// registered under its key and takes the merge (`extendList`) path
|
|
70
|
+
// against it — instead of pre-empting that key with a bare
|
|
71
|
+
// `list({ fields })` that carries no `db`/`access` (see #861).
|
|
72
|
+
//
|
|
73
|
+
// The plugin only ever touches its OWN derived keys. When a developer
|
|
74
|
+
// renames the auth user model (e.g. user.modelName: 'AuthUser'), the
|
|
75
|
+
// derived key is 'AuthUser' and an app's separate 'User' list is left
|
|
76
|
+
// untouched — the plugin never extends/overwrites a list it didn't
|
|
77
|
+
// derive. Extending only kicks in when an existing list shares the
|
|
78
|
+
// derived key (e.g. the default 'User'), which is the intended
|
|
79
|
+
// "merge auth fields into my User" behaviour.
|
|
80
|
+
for (const [listName, listConfig] of Object.entries(authLists)) {
|
|
81
|
+
if (context.config.lists[listName]) {
|
|
82
|
+
// A list already exists under this derived key — merge auth fields
|
|
83
|
+
// in only. Access control belongs to whoever owns the list (the
|
|
84
|
+
// application declared it first), so the plugin never forwards its
|
|
85
|
+
// own access here — see ADR-0013.
|
|
86
|
+
context.extendList(listName, {
|
|
87
|
+
fields: listConfig.fields,
|
|
88
|
+
hooks: listConfig.hooks,
|
|
89
|
+
mcp: listConfig.mcp,
|
|
90
|
+
})
|
|
91
|
+
} else {
|
|
92
|
+
// Otherwise, add the auth list
|
|
93
|
+
context.addList(listName, listConfig)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Extract additional lists from Better Auth plugins. Because the auth
|
|
98
|
+
// lists above are already registered, a schema extension of a base
|
|
99
|
+
// model (user/session/account/verification) always finds its resolved
|
|
100
|
+
// key occupied by the real derived list and merges via `extendList` —
|
|
101
|
+
// its `db`/`access` are preserved. Non-base plugin tables (e.g.
|
|
102
|
+
// `oauth_application`, `passkey`) still register as new lists via
|
|
103
|
+
// `addList`, same as before.
|
|
66
104
|
for (const plugin of normalized.betterAuthPlugins) {
|
|
67
105
|
if (plugin && typeof plugin === 'object' && 'schema' in plugin) {
|
|
68
106
|
// Plugin has schema property - convert to OpenSaaS lists
|
|
@@ -89,32 +127,6 @@ export function authPlugin(config: AuthConfig): Plugin {
|
|
|
89
127
|
}
|
|
90
128
|
}
|
|
91
129
|
|
|
92
|
-
// Add all auth lists.
|
|
93
|
-
//
|
|
94
|
-
// The plugin only ever touches its OWN derived keys. When a developer
|
|
95
|
-
// renames the auth user model (e.g. user.modelName: 'AuthUser'), the
|
|
96
|
-
// derived key is 'AuthUser' and an app's separate 'User' list is left
|
|
97
|
-
// untouched — the plugin never extends/overwrites a list it didn't
|
|
98
|
-
// derive. Extending only kicks in when an existing list shares the
|
|
99
|
-
// derived key (e.g. the default 'User'), which is the intended
|
|
100
|
-
// "merge auth fields into my User" behaviour.
|
|
101
|
-
for (const [listName, listConfig] of Object.entries(authLists)) {
|
|
102
|
-
if (context.config.lists[listName]) {
|
|
103
|
-
// A list already exists under this derived key — merge auth fields
|
|
104
|
-
// in only. Access control belongs to whoever owns the list (the
|
|
105
|
-
// application declared it first), so the plugin never forwards its
|
|
106
|
-
// own access here — see ADR-0013.
|
|
107
|
-
context.extendList(listName, {
|
|
108
|
-
fields: listConfig.fields,
|
|
109
|
-
hooks: listConfig.hooks,
|
|
110
|
-
mcp: listConfig.mcp,
|
|
111
|
-
})
|
|
112
|
-
} else {
|
|
113
|
-
// Otherwise, add the auth list
|
|
114
|
-
context.addList(listName, listConfig)
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
130
|
// Store auth config for runtime access
|
|
119
131
|
// Access at runtime via: config._pluginData.auth
|
|
120
132
|
context.setPluginData<NormalizedAuthConfig>('auth', normalized)
|
package/src/config/types.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import type { ListConfig } from '@opensaas/stack-core'
|
|
2
|
+
import type { BetterAuthOptions, User } from 'better-auth'
|
|
2
3
|
import type { ExtendUserListConfig } from '../lists/index.js'
|
|
3
4
|
|
|
5
|
+
/**
|
|
6
|
+
* better-auth's own callback shape for `sendVerificationEmail`/
|
|
7
|
+
* `sendResetPassword` — `data` is exactly what better-auth passes (no stack
|
|
8
|
+
* abstraction layered on top), and `request` is the raw request that
|
|
9
|
+
* triggered it.
|
|
10
|
+
*/
|
|
11
|
+
export type SendAuthEmail = (
|
|
12
|
+
data: { user: User; url: string; token: string },
|
|
13
|
+
request?: Request,
|
|
14
|
+
) => Promise<void>
|
|
15
|
+
|
|
4
16
|
/**
|
|
5
17
|
* OAuth provider configuration
|
|
6
18
|
*/
|
|
@@ -32,10 +44,36 @@ export type EmailPasswordConfig = {
|
|
|
32
44
|
*/
|
|
33
45
|
minPasswordLength?: number
|
|
34
46
|
/**
|
|
35
|
-
* Require password confirmation
|
|
47
|
+
* Require password confirmation (a second "confirm password" field).
|
|
48
|
+
*
|
|
49
|
+
* There is no better-auth server-side equivalent — this is purely a UI
|
|
50
|
+
* concern. `createAuth()` does not read it. Pass it directly to the
|
|
51
|
+
* pre-built forms instead: `<SignUpForm requirePasswordConfirmation={...} />`
|
|
52
|
+
* / `<ResetPasswordForm requirePasswordConfirmation={...} />` (both default
|
|
53
|
+
* to `true`). Setting it here has no effect and `createAuth()` warns if it
|
|
54
|
+
* is configured.
|
|
55
|
+
*
|
|
36
56
|
* @default true
|
|
37
57
|
*/
|
|
38
58
|
requireConfirmation?: boolean
|
|
59
|
+
/**
|
|
60
|
+
* Send a password reset email. Passed straight through to better-auth's own
|
|
61
|
+
* `emailAndPassword.sendResetPassword` — the stack does not wrap or
|
|
62
|
+
* reshape it. If not provided, reset emails are logged to console instead
|
|
63
|
+
* of sent.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* sendResetPassword: async ({ user, url }) => {
|
|
68
|
+
* await resend.emails.send({
|
|
69
|
+
* to: user.email,
|
|
70
|
+
* subject: 'Reset your password',
|
|
71
|
+
* html: `<a href="${url}">Reset your password</a>`,
|
|
72
|
+
* })
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
sendResetPassword?: SendAuthEmail
|
|
39
77
|
}
|
|
40
78
|
|
|
41
79
|
/**
|
|
@@ -53,6 +91,24 @@ export type EmailVerificationConfig = {
|
|
|
53
91
|
* @default 86400 (24 hours)
|
|
54
92
|
*/
|
|
55
93
|
tokenExpiration?: number
|
|
94
|
+
/**
|
|
95
|
+
* Send a verification email. Passed straight through to better-auth's own
|
|
96
|
+
* `emailVerification.sendVerificationEmail` — the stack does not wrap or
|
|
97
|
+
* reshape it. If not provided, verification emails are logged to console
|
|
98
|
+
* instead of sent.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* sendVerificationEmail: async ({ user, url }) => {
|
|
103
|
+
* await resend.emails.send({
|
|
104
|
+
* to: user.email,
|
|
105
|
+
* subject: 'Verify your email',
|
|
106
|
+
* html: `<a href="${url}">Verify your email</a>`,
|
|
107
|
+
* })
|
|
108
|
+
* }
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
sendVerificationEmail?: SendAuthEmail
|
|
56
112
|
}
|
|
57
113
|
|
|
58
114
|
/**
|
|
@@ -77,10 +133,12 @@ export type SessionConfig = {
|
|
|
77
133
|
*/
|
|
78
134
|
expiresIn?: number
|
|
79
135
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
136
|
+
* How often the session should be refreshed, in seconds. Passed straight
|
|
137
|
+
* through to better-auth's own `session.updateAge`. Set `false` to disable
|
|
138
|
+
* refresh entirely (the session expiry is then fixed at creation time).
|
|
139
|
+
* @default 86400 (1 day, matching better-auth's own default)
|
|
82
140
|
*/
|
|
83
|
-
updateAge?:
|
|
141
|
+
updateAge?: number | false
|
|
84
142
|
}
|
|
85
143
|
|
|
86
144
|
/**
|
|
@@ -150,10 +208,30 @@ export type AuthAccessConfig = {
|
|
|
150
208
|
export type AuthModelConfig = {
|
|
151
209
|
/**
|
|
152
210
|
* The table/list name for this model.
|
|
153
|
-
* Becomes the OpenSaaS list key
|
|
211
|
+
* Becomes the OpenSaaS list key and Prisma model name.
|
|
154
212
|
* @default the default better-auth model name (e.g. 'User', 'Session')
|
|
155
213
|
*/
|
|
156
214
|
modelName?: string
|
|
215
|
+
/**
|
|
216
|
+
* The physical database table name for this model, independent of
|
|
217
|
+
* `modelName`. Generates a `@@map("...")` on the derived list.
|
|
218
|
+
*
|
|
219
|
+
* Lets a renamed list key (e.g. `modelName: 'AuthUser'`, to avoid colliding
|
|
220
|
+
* with an app's own domain `User`) still adopt a live table under a
|
|
221
|
+
* different name — most commonly better-auth's own default lowercase
|
|
222
|
+
* table names (`user`, `session`, `account`, `verification`).
|
|
223
|
+
*
|
|
224
|
+
* @default `modelName` when it differs from the better-auth default model
|
|
225
|
+
* name, otherwise unset (no `@@map`) — i.e. today's behaviour when this
|
|
226
|
+
* option is not set.
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```typescript
|
|
230
|
+
* // List key AuthUser, but the live table is still called `user`.
|
|
231
|
+
* user: { modelName: 'AuthUser', tableName: 'user' }
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
tableName?: string
|
|
157
235
|
/**
|
|
158
236
|
* Map better-auth field names to database column names.
|
|
159
237
|
* Each entry generates a `@map("column")` on the derived field.
|
|
@@ -303,19 +381,6 @@ export type AuthConfig = {
|
|
|
303
381
|
*/
|
|
304
382
|
access?: AuthAccessConfig
|
|
305
383
|
|
|
306
|
-
/**
|
|
307
|
-
* Custom email sending function for verification and password reset
|
|
308
|
-
* If not provided, emails will be logged to console
|
|
309
|
-
*
|
|
310
|
-
* @example
|
|
311
|
-
* ```typescript
|
|
312
|
-
* sendEmail: async ({ to, subject, html }) => {
|
|
313
|
-
* await resend.emails.send({ to, subject, html })
|
|
314
|
-
* }
|
|
315
|
-
* ```
|
|
316
|
-
*/
|
|
317
|
-
sendEmail?: (params: { to: string; subject: string; html: string }) => Promise<void>
|
|
318
|
-
|
|
319
384
|
/**
|
|
320
385
|
* Additional Better Auth plugins to enable
|
|
321
386
|
* Allows integrating any Better Auth plugin (MCP, 2FA, etc.)
|
|
@@ -364,17 +429,58 @@ export type AuthConfig = {
|
|
|
364
429
|
*/
|
|
365
430
|
max?: number
|
|
366
431
|
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Escape hatch for better-auth options the stack doesn't model — typed as
|
|
435
|
+
* better-auth's own `BetterAuthOptions` so it stays in step with
|
|
436
|
+
* better-auth's surface without the stack re-declaring it. Deep-merged into
|
|
437
|
+
* the options `createAuth()` builds, applied LAST: a plain-object value at a
|
|
438
|
+
* given key merges recursively with whatever the stack already set there
|
|
439
|
+
* (so e.g. `session: { cookieCache: {...} }` adds alongside the stack's own
|
|
440
|
+
* `session.expiresIn`/`updateAge` rather than clobbering them); any other
|
|
441
|
+
* value (including arrays) replaces the stack's value outright. On a genuine
|
|
442
|
+
* key collision, this option wins.
|
|
443
|
+
*
|
|
444
|
+
* `database` and `plugins` are rejected — they're already the dedicated
|
|
445
|
+
* seams (the stack's `db` config, and `betterAuthPlugins` respectively) and
|
|
446
|
+
* accepting them here would create two unranked ways to set the same thing.
|
|
447
|
+
* So is `additionalFields` under `user`/`session`/`account`/`verification` —
|
|
448
|
+
* it has schema consequences (new columns) that a passthrough can't also
|
|
449
|
+
* apply to the generated Prisma schema; add fields to the derived list
|
|
450
|
+
* instead (`extendUserList` for the user model, or declare the list
|
|
451
|
+
* yourself for the others — see `packages/auth/CLAUDE.md`).
|
|
452
|
+
*
|
|
453
|
+
* The same options object is available standalone via
|
|
454
|
+
* `buildBetterAuthOptions()` (`@opensaas/stack-auth/server`) for apps that
|
|
455
|
+
* still need to hand-wire their own `betterAuth()` instance.
|
|
456
|
+
*
|
|
457
|
+
* @example
|
|
458
|
+
* ```typescript
|
|
459
|
+
* authPlugin({
|
|
460
|
+
* betterAuthOptions: {
|
|
461
|
+
* databaseHooks: { user: { create: { after: syncDomainUser } } },
|
|
462
|
+
* session: { cookieCache: { enabled: true, maxAge: 300 } },
|
|
463
|
+
* verification: { storeIdentifier: 'hashed' },
|
|
464
|
+
* baseURL: process.env.BETTER_AUTH_URL,
|
|
465
|
+
* },
|
|
466
|
+
* })
|
|
467
|
+
* ```
|
|
468
|
+
*/
|
|
469
|
+
betterAuthOptions?: Partial<BetterAuthOptions>
|
|
367
470
|
}
|
|
368
471
|
|
|
369
472
|
/**
|
|
370
473
|
* Resolved per-model auth configuration after normalization.
|
|
371
474
|
* Always carries a concrete `modelName` (the developer's override or the
|
|
372
|
-
* better-auth default) and a (possibly empty) `fields` column map. `
|
|
373
|
-
*
|
|
374
|
-
* the
|
|
475
|
+
* better-auth default) and a (possibly empty) `fields` column map. `tableName`
|
|
476
|
+
* is the resolved physical table name — `undefined` means no `@@map` is
|
|
477
|
+
* emitted (the list key doubles as the table name). `schema` carries the
|
|
478
|
+
* resolved Postgres schema for the model (per-model override, else the
|
|
479
|
+
* plugin-level schema, else `undefined` for the default `public` schema).
|
|
375
480
|
*/
|
|
376
481
|
export type NormalizedAuthModelConfig = {
|
|
377
482
|
modelName: string
|
|
483
|
+
tableName?: string
|
|
378
484
|
fields: Record<string, string>
|
|
379
485
|
schema?: string
|
|
380
486
|
}
|