@opensaas/stack-auth 0.36.0 → 0.38.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 +146 -0
- package/CLAUDE.md +153 -9
- 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 +143 -28
- package/dist/config/types.d.ts.map +1 -1
- package/dist/server/build-better-auth-options.test.d.ts +2 -0
- package/dist/server/build-better-auth-options.test.d.ts.map +1 -0
- package/dist/server/build-better-auth-options.test.js +29 -0
- package/dist/server/build-better-auth-options.test.js.map +1 -0
- package/dist/server/index.d.ts +112 -8
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +284 -96
- package/dist/server/index.js.map +1 -1
- package/dist/server/schema-converter.d.ts +3 -3
- package/dist/server/schema-converter.d.ts.map +1 -1
- package/package.json +5 -5
- 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 +40 -28
- package/src/config/types.ts +144 -27
- package/src/server/build-better-auth-options.test.ts +59 -0
- package/src/server/index.ts +470 -106
- package/src/server/schema-converter.ts +3 -3
- 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 +723 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +7 -1
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,151 @@
|
|
|
1
1
|
# @opensaas/stack-auth
|
|
2
2
|
|
|
3
|
+
## 0.38.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#888](https://github.com/OpenSaasAU/stack/pull/888) [`8183827`](https://github.com/OpenSaasAU/stack/commit/8183827ec65d6cfd7153028f84057ab65dfdc7dd) Thanks [@borisno2](https://github.com/borisno2)! - `buildBetterAuthOptions()` and `createAuth()` now accept an optional third argument — your app's `betterAuthPlugins` array, the same array passed to `authPlugin({ betterAuthPlugins })` — so the returned options/`Auth` type carries the literal plugin tuple instead of the widened `BetterAuthOptions`/`Auth<BetterAuthOptions>`. Without this, `betterAuth()` constructed from the widened return loses plugin-derived `auth.api.*` endpoints (e.g. `emailOTP()`'s `signInEmailOTP`) and a `customSession()` plugin's replaced session shape.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
export const appBetterAuthPlugins = [emailOTP({ sendVerificationOTP })] // same array passed to authPlugin({ betterAuthPlugins })
|
|
11
|
+
|
|
12
|
+
export const auth = betterAuth({
|
|
13
|
+
...(await buildBetterAuthOptions(config, rawOpensaasContext, appBetterAuthPlugins)),
|
|
14
|
+
})
|
|
15
|
+
// auth.api.signInEmailOTP is now typed, and auth.api.getSession() returns your customSession() shape.
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The supplied tuple is for typing only — the plugin array used at runtime is always the one resolved from `authPlugin({ betterAuthPlugins })`. Passing a tuple that isn't the same plugin instances in the same order throws, naming the mismatch, so the two can't silently drift apart. Calling either function with no third argument is unchanged — same widened return type, same runtime options, fully backwards compatible.
|
|
19
|
+
|
|
20
|
+
Also, `AuthConfig`/`NormalizedAuthConfig`'s `betterAuthPlugins` field is now typed as better-auth's own `BetterAuthPlugin[]` instead of `any[]`.
|
|
21
|
+
|
|
22
|
+
- [#889](https://github.com/OpenSaasAU/stack/pull/889) [`b9b9357`](https://github.com/OpenSaasAU/stack/commit/b9b935719774b01a81cfd2082387b76806c1a484) Thanks [@borisno2](https://github.com/borisno2)! - Fix `getSessionFromAuth` to project `sessionFields` from the _resolved_ better-auth session instead of only its `user` sub-object. A `customSession` plugin's replaced shape with no `user` key is now correctly treated as a signed-in session (never misreported as anonymous), and a session-only field (e.g. the admin plugin's `impersonatedBy`) is now resolvable. Errors from the underlying session lookup now propagate instead of silently becoming `null`, and a `sessionFields` entry that can't be resolved is omitted and logs a warning (once per field, per process) instead of vanishing silently.
|
|
23
|
+
|
|
24
|
+
The scaffolded `getSession()` — the CLI feature generator's `lib/auth.ts` template, and `examples/starter-auth`/`examples/auth-demo` — now call this single shared helper, reading `sessionFields` from the resolved config at runtime instead of baking a field list in at generation time. `examples/auth-demo`'s `getSession()` also now correctly returns `null` for an anonymous visitor (previously returned a truthy object of `undefined` values).
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
authPlugin({ sessionFields: ['userId', 'email', 'name', 'role'] })
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// lib/auth.ts
|
|
32
|
+
export async function getSession() {
|
|
33
|
+
const resolvedConfig = await config
|
|
34
|
+
const authConfig = resolvedConfig._pluginData?.auth as NormalizedAuthConfig | undefined
|
|
35
|
+
const sessionFields = authConfig?.sessionFields ?? ['userId', 'email', 'name']
|
|
36
|
+
return getSessionFromAuth(auth, sessionFields, await headers())
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 0.37.0
|
|
41
|
+
|
|
42
|
+
### Minor Changes
|
|
43
|
+
|
|
44
|
+
- [#872](https://github.com/OpenSaasAU/stack/pull/872) [`17acf04`](https://github.com/OpenSaasAU/stack/commit/17acf046b494da184c2b77434a7b4d3400ca32f2) Thanks [@borisno2](https://github.com/borisno2)! - `createAuth()` now forwards `AuthConfig` options it previously normalized but silently dropped: `emailAndPassword.minPasswordLength`, `passwordReset.enabled`/`tokenExpiration` (wired to better-auth's `sendResetPassword`), and `emailVerification.enabled`/`sendOnSignUp`/`tokenExpiration` (wired to `sendVerificationEmail`).
|
|
45
|
+
|
|
46
|
+
The stack does not wrap these email callbacks in any way — `emailAndPassword.sendResetPassword` and `emailVerification.sendVerificationEmail` are better-auth's own option shape, forwarded straight through, so an app configures them exactly as it would when calling `betterAuth()` directly:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
authPlugin({
|
|
50
|
+
emailAndPassword: {
|
|
51
|
+
enabled: true,
|
|
52
|
+
sendResetPassword: async ({ user, url }) => {
|
|
53
|
+
await resend.emails.send({
|
|
54
|
+
to: user.email,
|
|
55
|
+
subject: 'Reset your password',
|
|
56
|
+
html: `<a href="${url}">Reset your password</a>`,
|
|
57
|
+
})
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
emailVerification: {
|
|
61
|
+
enabled: true,
|
|
62
|
+
sendVerificationEmail: async ({ user, url }) => {
|
|
63
|
+
await resend.emails.send({
|
|
64
|
+
to: user.email,
|
|
65
|
+
subject: 'Verify your email',
|
|
66
|
+
html: `<a href="${url}">Verify your email</a>`,
|
|
67
|
+
})
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
If not provided, reset/verification emails are logged to console instead of sent — apps relying on the previous no-op behavior (verification/reset emails silently not sending) will start sending real emails once `emailVerification`/`passwordReset` are enabled and these callbacks are configured.
|
|
74
|
+
|
|
75
|
+
Two related fixes, both changing existing behavior:
|
|
76
|
+
|
|
77
|
+
- `session.updateAge` is retyped from `boolean` to `number | false` — the number of seconds between session refreshes, passed straight through to better-auth's own `session.updateAge` instead of being computed as `expiresIn / 10`. The default changes from `true` to `86400` (1 day), matching better-auth's own default. Update any `updateAge: true` config to a duration in seconds (e.g. `86400`). `updateAge: false` now correctly maps to better-auth's `disableSessionRefresh: true` (previously it mapped to `updateAge: 0`, which better-auth treats as "refresh on every request" — the opposite of disabling refresh).
|
|
78
|
+
- `getSessionFromAuth(auth, sessionFields, headers)` gains a required third `headers: Headers` parameter. Previously it always called `auth.api.getSession({ headers: new Headers() })`, an empty header set that could never resolve a session cookie, so the function always returned `null`. Callers must now pass the request's real headers (e.g. Next.js `await headers()`).
|
|
79
|
+
|
|
80
|
+
Setting `emailAndPassword.requireConfirmation` (while `emailAndPassword.enabled` is true) now logs a `console.warn` — it has no better-auth server-side equivalent (it's a UI-only "confirm password" concern). Pass `requirePasswordConfirmation` directly to `<SignUpForm>`/`<ResetPasswordForm>` instead. Similarly, `passwordReset.enabled` now warns if `emailAndPassword.enabled` is false, since password reset has no effect without a password-based account.
|
|
81
|
+
|
|
82
|
+
- [#871](https://github.com/OpenSaasAU/stack/pull/871) [`06375ca`](https://github.com/OpenSaasAU/stack/commit/06375cad571677e92bfe84c35ff55240f3546a1f) Thanks [@{](https://github.com/{)! - Add a per-model `tableName` option, independent of `modelName`, so a renamed Auth list key can still adopt a differently-named live table — most commonly better-auth's own default lowercase table names (`user`, `session`, `account`, `verification`).
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
authPlugin({
|
|
86
|
+
modelName: 'AuthUser', tableName: 'user' },
|
|
87
|
+
session: { modelName: 'AuthSession', tableName: 'session' },
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`adoptBetterAuthTables()` gains matching `useBetterAuthTableNames` and `tableNames` options:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
adoptBetterAuthTables({ useBetterAuthTableNames: true })
|
|
95
|
+
// or explicitly:
|
|
96
|
+
adoptBetterAuthTables({ tableNames: { user: 'user', session: 'session' } })
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
With no `tableName` set, behaviour is unchanged: the table name still follows `modelName` when it differs from the better-auth default, otherwise no `@@map` is emitted.
|
|
100
|
+
|
|
101
|
+
- [#874](https://github.com/OpenSaasAU/stack/pull/874) [`7ef9dbc`](https://github.com/OpenSaasAU/stack/commit/7ef9dbc2f94cc4e7ab831ecafb3ef65159a3c55e) Thanks [@borisno2](https://github.com/borisno2)! - Add a `betterAuthOptions` escape hatch on `AuthConfig` for better-auth options the stack doesn't model, plus an exported `buildBetterAuthOptions()` builder for apps that still need to hand-wire their own `betterAuth()` instance.
|
|
102
|
+
|
|
103
|
+
`betterAuthOptions` is deep-merged onto the options `createAuth()` builds, applied last — a plain-object value merges recursively alongside sibling keys the stack already set (e.g. `session: { cookieCache }` doesn't clobber `session.expiresIn`), and wins on any genuine key collision:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
authPlugin({
|
|
107
|
+
betterAuthOptions: {
|
|
108
|
+
databaseHooks: { user: { create: { after: syncDomainUser } } },
|
|
109
|
+
session: { cookieCache: { enabled: true, maxAge: 300 } },
|
|
110
|
+
verification: { storeIdentifier: 'hashed' },
|
|
111
|
+
baseURL: process.env.BETTER_AUTH_URL,
|
|
112
|
+
},
|
|
113
|
+
})
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`database`, `plugins`, and `additionalFields` under `user`/`session`/`account`/`verification` are rejected — they already have dedicated seams (`db` config, `betterAuthPlugins`), or have schema consequences a passthrough can't also apply to the generated Prisma schema.
|
|
117
|
+
|
|
118
|
+
`buildBetterAuthOptions(config, context)` returns the exact same options object `createAuth()` uses, for apps that need a resolved `betterAuth()` instance rather than `createAuth()`'s lazy proxy:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { betterAuth } from 'better-auth'
|
|
122
|
+
import { buildBetterAuthOptions } from '@opensaas/stack-auth/server'
|
|
123
|
+
|
|
124
|
+
export const auth = betterAuth({
|
|
125
|
+
...(await buildBetterAuthOptions(config, rawOpensaasContext)),
|
|
126
|
+
databaseHooks: { user: { create: { after: syncDomainUser } } },
|
|
127
|
+
})
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
- [#870](https://github.com/OpenSaasAU/stack/pull/870) [`7b6189f`](https://github.com/OpenSaasAU/stack/commit/7b6189fa60119a45082ba62dd71d915d93de529c) Thanks [@relationship({](https://github.com/relationship({)! - A relationship field's foreign key can now be declared non-nullable via `db.isNullable: false` — the generated FK column and its relation field lose their `?` together. Omitting the option leaves every existing relationship unchanged (still nullable by default).
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
|
|
134
|
+
ref: 'User.sessions',
|
|
135
|
+
db: { isNullable: false },
|
|
136
|
+
})
|
|
137
|
+
// Generates: userId String (was String?)
|
|
138
|
+
// user User @relation(...) (was User?)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`@opensaas/stack-auth`'s derived Auth lists now use this to match better-auth's own Prisma schema: `Session.expiresAt`, `Verification.expiresAt`, and the `Session.user`/`Account.user` foreign keys generate as required instead of nullable.
|
|
142
|
+
|
|
143
|
+
**Migration note:** this changes the generated schema for existing greenfield apps. Running `opensaas generate` followed by `prisma db push`/`prisma migrate dev` will produce a migration that adds `NOT NULL` to `Session.expiresAt`, `Verification.expiresAt`, `Session.userId`, and `Account.userId`. Since better-auth's own adapter always writes these columns, no existing row should violate the new constraint — but back up production data before applying, as with any schema migration.
|
|
144
|
+
|
|
145
|
+
### Patch Changes
|
|
146
|
+
|
|
147
|
+
- [#867](https://github.com/OpenSaasAU/stack/pull/867) [`43b4d17`](https://github.com/OpenSaasAU/stack/commit/43b4d1738340f05b1cf8bec3315927b3004816dd) Thanks [@borisno2](https://github.com/borisno2)! - Fix a better-auth plugin's schema extension of a base model (`user`/`session`/`account`/`verification`) silently dropping the derived Auth list's `db` (`map`/`schema`/`timestamps`) and `access` config.
|
|
148
|
+
|
|
3
149
|
## 0.36.0
|
|
4
150
|
|
|
5
151
|
## 0.35.0
|
package/CLAUDE.md
CHANGED
|
@@ -28,7 +28,8 @@ Auto-generated lists:
|
|
|
28
28
|
|
|
29
29
|
### Server (`src/server/index.ts`)
|
|
30
30
|
|
|
31
|
-
- `createAuth(config, rawContext?)` - Creates Better-auth instance with MCP plugin support
|
|
31
|
+
- `createAuth(config, rawContext?, betterAuthPlugins?)` - Creates Better-auth instance with MCP plugin support
|
|
32
|
+
- `buildBetterAuthOptions(config, rawContext?, betterAuthPlugins?)` - Returns the same `BetterAuthOptions` `createAuth()` builds, without constructing an instance — for apps that need to hand-wire their own `betterAuth()`. The optional third argument (the app's own `betterAuthPlugins` array) makes the return type carry that literal plugin tuple instead of the widened array type — see "Typed `auth.api.*` reads" below.
|
|
32
33
|
- Returns `{ handler, signIn, signOut, ... }` - Better-auth methods
|
|
33
34
|
|
|
34
35
|
### Client (`src/client/index.ts`)
|
|
@@ -71,13 +72,16 @@ developer writes — not hardcoded. The pure derivation lives in
|
|
|
71
72
|
`src/config/derive-auth-lists.ts` (`deriveAuthLists`), which `getAuthLists`
|
|
72
73
|
and the plugin's add-vs-extend logic consume:
|
|
73
74
|
|
|
74
|
-
- per-model `modelName` → list key
|
|
75
|
+
- per-model `modelName` → list key (and Prisma model name)
|
|
76
|
+
- per-model `tableName` → table `@@map`, **independent of `modelName`**
|
|
77
|
+
(defaults to `modelName` when it differs from the better-auth default,
|
|
78
|
+
otherwise unset — i.e. unchanged output when `tableName` isn't set)
|
|
75
79
|
- per-model `fields` (better-auth field → column) → field-level `@map`
|
|
76
80
|
- the `userId` column override → the `user` relationship foreign-key `@map`
|
|
77
81
|
- relationship refs between the Auth lists follow the derived keys
|
|
78
82
|
(e.g. `Session.user → AuthUser.sessions`)
|
|
79
83
|
|
|
80
|
-
With no `modelName`/`fields` overrides the output is unchanged
|
|
84
|
+
With no `modelName`/`tableName`/`fields` overrides the output is unchanged
|
|
81
85
|
(`User`/`Session`/`Account`/`Verification`, original field shapes, no `@@map`).
|
|
82
86
|
|
|
83
87
|
```typescript
|
|
@@ -89,6 +93,15 @@ authPlugin({
|
|
|
89
93
|
// Adds AuthUser/AuthSession/... and leaves an app's own `User` untouched.
|
|
90
94
|
```
|
|
91
95
|
|
|
96
|
+
```typescript
|
|
97
|
+
// modelName sets the list key; tableName independently pins the live table —
|
|
98
|
+
// e.g. a prefixed list key adopting better-auth's own default lowercase table.
|
|
99
|
+
authPlugin({
|
|
100
|
+
user: { modelName: 'AuthUser', tableName: 'user' },
|
|
101
|
+
session: { modelName: 'AuthSession', tableName: 'session' },
|
|
102
|
+
})
|
|
103
|
+
```
|
|
104
|
+
|
|
92
105
|
Because the plugin only ever adds/extends its **derived** keys, an app's own
|
|
93
106
|
domain `User` (a different model from the better-auth user) is never extended
|
|
94
107
|
or overwritten when the user model is renamed. The runtime `getUser`/
|
|
@@ -164,10 +177,10 @@ How it wires up (Postgres multi-schema):
|
|
|
164
177
|
|
|
165
178
|
`adoptBetterAuthTables()` (`src/config/adopt-better-auth-tables.ts`) is a thin
|
|
166
179
|
recipe that returns the `AuthConfig` adoption knobs — the plugin-level `schema`
|
|
167
|
-
plus a per-model `modelName` (and optional column `fields` maps) —
|
|
168
|
-
conventions of a standard separate-schema better-auth install. It
|
|
169
|
-
the keys/field derivation and schema placement so a migrator
|
|
170
|
-
config by hand. Spread it into `authPlugin`:
|
|
180
|
+
plus a per-model `modelName` (and optional column `fields`/`tableName` maps) —
|
|
181
|
+
preset to the conventions of a standard separate-schema better-auth install. It
|
|
182
|
+
ties together the keys/field derivation and schema placement so a migrator
|
|
183
|
+
doesn't rebuild the config by hand. Spread it into `authPlugin`:
|
|
171
184
|
|
|
172
185
|
```typescript
|
|
173
186
|
import { authPlugin, adoptBetterAuthTables } from '@opensaas/stack-auth'
|
|
@@ -176,7 +189,23 @@ authPlugin({
|
|
|
176
189
|
...adoptBetterAuthTables(), // schema: 'auth', AuthUser/AuthSession/AuthAccount/AuthVerification
|
|
177
190
|
emailAndPassword: { enabled: true },
|
|
178
191
|
})
|
|
179
|
-
// Options: adoptBetterAuthTables({ schema, modelNamePrefix, fields })
|
|
192
|
+
// Options: adoptBetterAuthTables({ schema, modelNamePrefix, fields, useBetterAuthTableNames, tableNames })
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The most common adoption shape is a project that ran better-auth **before**
|
|
196
|
+
Stack, so its live tables are still better-auth's own default lowercase names
|
|
197
|
+
(`user`/`session`/`account`/`verification`) even though the derived list keys
|
|
198
|
+
need an `Auth` prefix to avoid colliding with the app's own domain `User`.
|
|
199
|
+
`useBetterAuthTableNames: true` sets every model's `tableName` to that
|
|
200
|
+
default; the per-model `tableNames` map is the escape hatch for a mix (it
|
|
201
|
+
wins over `useBetterAuthTableNames` for any model it names):
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
authPlugin({
|
|
205
|
+
...adoptBetterAuthTables({ useBetterAuthTableNames: true }),
|
|
206
|
+
// → AuthUser/AuthSession/AuthAccount/AuthVerification list keys,
|
|
207
|
+
// @@map("user")/@@map("session")/@@map("account")/@@map("verification")
|
|
208
|
+
})
|
|
180
209
|
```
|
|
181
210
|
|
|
182
211
|
It is pure config (no side effects): everything it sets can also be written
|
|
@@ -206,7 +235,8 @@ const context = createContext(config, prisma, session)
|
|
|
206
235
|
|
|
207
236
|
### Session Fields Configuration
|
|
208
237
|
|
|
209
|
-
|
|
238
|
+
`sessionFields` describes a **flattened projection** of the resolved better-auth session, not
|
|
239
|
+
the session's own shape:
|
|
210
240
|
|
|
211
241
|
```typescript
|
|
212
242
|
authPlugin({ sessionFields: ['userId', 'email', 'name', 'role'] })
|
|
@@ -218,6 +248,15 @@ access: {
|
|
|
218
248
|
}
|
|
219
249
|
```
|
|
220
250
|
|
|
251
|
+
`getSessionFromAuth()` (`@opensaas/stack-auth/server`) is the single implementation of this
|
|
252
|
+
projection — the scaffolded `getSession()` calls it with `sessionFields` read from the resolved
|
|
253
|
+
config at runtime. Each name resolves against a fixed precedence (a top-level key on the
|
|
254
|
+
resolved session, then `user`, then `session`), with `userId` special-cased to the user's `id`.
|
|
255
|
+
A `customSession` better-auth plugin fully replaces the resolved shape and can nest fields
|
|
256
|
+
anywhere; reconciling that against `sessionFields` is the app's job — an unresolvable name is
|
|
257
|
+
omitted and warns once (per field, per process) rather than silently becoming `undefined`. See
|
|
258
|
+
the `sessionFields` reference (`docs/content/reference/auth.md`) for the full contract.
|
|
259
|
+
|
|
221
260
|
### Session Type Safety
|
|
222
261
|
|
|
223
262
|
To get autocomplete and type safety for session fields, use module augmentation:
|
|
@@ -294,6 +333,111 @@ authPlugin({
|
|
|
294
333
|
})
|
|
295
334
|
```
|
|
296
335
|
|
|
336
|
+
### Escape hatch for unmodelled better-auth options (`betterAuthOptions`)
|
|
337
|
+
|
|
338
|
+
`AuthConfig` models a deliberately closed set of better-auth options. For
|
|
339
|
+
anything the stack doesn't model — database hooks, `session.cookieCache`,
|
|
340
|
+
`baseURL`, `verification.storeIdentifier`, and so on — pass it through
|
|
341
|
+
`betterAuthOptions`, typed as better-auth's own `BetterAuthOptions` so it
|
|
342
|
+
tracks better-auth's surface without the stack re-declaring it:
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
authPlugin({
|
|
346
|
+
betterAuthOptions: {
|
|
347
|
+
databaseHooks: { user: { create: { after: syncDomainUser } } },
|
|
348
|
+
session: { cookieCache: { enabled: true, maxAge: 300 } },
|
|
349
|
+
verification: { storeIdentifier: 'hashed' },
|
|
350
|
+
baseURL: process.env.BETTER_AUTH_URL,
|
|
351
|
+
},
|
|
352
|
+
})
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
`createAuth()` (`src/server/index.ts`) deep-merges `betterAuthOptions` onto
|
|
356
|
+
the options it builds from the rest of `AuthConfig`, applied **last**:
|
|
357
|
+
plain-object values merge recursively per key (so `session: { cookieCache }`
|
|
358
|
+
lands alongside the stack's own `session.expiresIn`/`updateAge` instead of
|
|
359
|
+
replacing the whole `session` block), arrays and other value types replace
|
|
360
|
+
outright, and `betterAuthOptions` wins on any genuine key collision. The
|
|
361
|
+
merge and the option-building it merges onto both live in
|
|
362
|
+
`buildBetterAuthOptions()`, the single place `createAuth()` and the exported
|
|
363
|
+
builder share — they cannot drift from each other because `createAuth()`
|
|
364
|
+
calls it directly rather than reimplementing it.
|
|
365
|
+
|
|
366
|
+
`database` and `plugins` are rejected outright (`assertNoUnsupportedPassthroughKeys`
|
|
367
|
+
in `src/server/index.ts`): they already have dedicated seams (`db` in the
|
|
368
|
+
stack config, and `betterAuthPlugins` respectively), and accepting them here
|
|
369
|
+
would create two unranked ways to set the same thing — worse for `plugins`,
|
|
370
|
+
since the stack must append `nextCookies()` last (see "Auth forms submit
|
|
371
|
+
through server actions" below). `additionalFields` under `user`/`session`/
|
|
372
|
+
`account`/`verification` is rejected too — it adds columns with no
|
|
373
|
+
corresponding change to the generated Prisma schema, which is exactly the
|
|
374
|
+
silent-divergence failure mode this passthrough exists to avoid elsewhere.
|
|
375
|
+
Add fields to the derived list instead: `extendUserList` for the user model,
|
|
376
|
+
or declare the list yourself in your own `lists` config for the others (the
|
|
377
|
+
auth plugin's `addList`-vs-`extendList` logic — see "Deriving Auth lists from
|
|
378
|
+
better-auth config" above — merges in field additions for any list matching
|
|
379
|
+
one of its derived keys).
|
|
380
|
+
|
|
381
|
+
### Hand-wiring `betterAuth()` from the stack config (`buildBetterAuthOptions`)
|
|
382
|
+
|
|
383
|
+
An app that needs a resolved `betterAuth()` instance at module-init time
|
|
384
|
+
(rather than `createAuth()`'s lazy proxy) can derive its options from the
|
|
385
|
+
stack config instead of duplicating them:
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
import { betterAuth } from 'better-auth'
|
|
389
|
+
import { buildBetterAuthOptions } from '@opensaas/stack-auth/server'
|
|
390
|
+
|
|
391
|
+
export const auth = betterAuth({
|
|
392
|
+
...(await buildBetterAuthOptions(config, rawOpensaasContext)),
|
|
393
|
+
databaseHooks: { user: { create: { after: syncDomainUser } } }, // not yet in betterAuthOptions
|
|
394
|
+
})
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
This is the same async-resolve-then-construct step `createAuth()` performs
|
|
398
|
+
internally, exported standalone — see ADR-0014 and root `CLAUDE.md`'s
|
|
399
|
+
"Getting the ORM client outside a request" for why `createAuth()` itself
|
|
400
|
+
can't be synchronous. It gives an incremental path onto `createAuth()`: adopt
|
|
401
|
+
the builder first, then fold options into `betterAuthOptions` above as the
|
|
402
|
+
stack grows first-class config for them.
|
|
403
|
+
|
|
404
|
+
**Typed `auth.api.*` reads.** Called with just `(config, context)`, both
|
|
405
|
+
`buildBetterAuthOptions()` and `createAuth()` return the widened
|
|
406
|
+
`BetterAuthOptions` / `Auth<BetterAuthOptions>` — better-auth infers plugin
|
|
407
|
+
endpoints and a `customSession()`'s replaced session shape from the _literal_
|
|
408
|
+
options type, so the widened form erases them (an `emailOTP()` plugin loses
|
|
409
|
+
`auth.api.signInEmailOTP`; `auth.api.getSession()` falls back to `{ user,
|
|
410
|
+
session }` instead of a `customSession()` shape). Both functions take the
|
|
411
|
+
app's `betterAuthPlugins` array — the exact same array passed to
|
|
412
|
+
`authPlugin({ betterAuthPlugins })` — as an optional third argument, and their
|
|
413
|
+
return type then carries that literal tuple (plus the `nextCookies()` the
|
|
414
|
+
stack always appends last) instead of the widened array type:
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
export const appBetterAuthPlugins = [emailOTP({ sendVerificationOTP })] // same array passed to authPlugin({ betterAuthPlugins })
|
|
418
|
+
|
|
419
|
+
export const auth = betterAuth({
|
|
420
|
+
...(await buildBetterAuthOptions(config, rawOpensaasContext, appBetterAuthPlugins)),
|
|
421
|
+
})
|
|
422
|
+
// auth.api.signInEmailOTP is now typed.
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
The supplied tuple is for typing only — the plugin array used at runtime is
|
|
426
|
+
always the one resolved from `authPlugin({ betterAuthPlugins })` — so both
|
|
427
|
+
functions verify the supplied tuple is the same plugin instances in the same
|
|
428
|
+
order as the resolved array, throwing a prefixed error naming the mismatch if
|
|
429
|
+
not (`assertPluginTupleMatchesResolved` in `src/server/index.ts`). This is
|
|
430
|
+
what closes the drift hole a hand-rolled re-pass of the plugin array would
|
|
431
|
+
otherwise open.
|
|
432
|
+
|
|
433
|
+
`createAuth()`'s lazy `Proxy` does not behave identically to a real `Auth`
|
|
434
|
+
instance for every property regardless of which form you use — every access,
|
|
435
|
+
including a non-function property, is surfaced through an `async` wrapper (so
|
|
436
|
+
`auth.options` reads back as a `Promise`, not the plain object a real
|
|
437
|
+
instance returns synchronously). Reach for `buildBetterAuthOptions()` plus
|
|
438
|
+
`betterAuth()` instead when the app reads `auth.api.*` in typed code — it
|
|
439
|
+
constructs a real instance and does not have this gap.
|
|
440
|
+
|
|
297
441
|
## Integration Points
|
|
298
442
|
|
|
299
443
|
### With @opensaas/stack-core
|
package/README.md
CHANGED
|
@@ -164,7 +164,15 @@ authPlugin({
|
|
|
164
164
|
emailAndPassword: {
|
|
165
165
|
enabled: true,
|
|
166
166
|
minPasswordLength: 8,
|
|
167
|
-
requireConfirmation: true,
|
|
167
|
+
requireConfirmation: true, // UI-only — pass to <SignUpForm>/<ResetPasswordForm> directly
|
|
168
|
+
// Passed straight through to better-auth's own `emailAndPassword.sendResetPassword`
|
|
169
|
+
sendResetPassword: async ({ user, url }) => {
|
|
170
|
+
await yourEmailService.send({
|
|
171
|
+
to: user.email,
|
|
172
|
+
subject: 'Reset your password',
|
|
173
|
+
html: `<a href="${url}">Reset your password</a>`,
|
|
174
|
+
})
|
|
175
|
+
},
|
|
168
176
|
},
|
|
169
177
|
|
|
170
178
|
// Email verification
|
|
@@ -172,6 +180,14 @@ authPlugin({
|
|
|
172
180
|
enabled: true,
|
|
173
181
|
sendOnSignUp: true,
|
|
174
182
|
tokenExpiration: 86400, // 24 hours in seconds
|
|
183
|
+
// Passed straight through to better-auth's own `emailVerification.sendVerificationEmail`
|
|
184
|
+
sendVerificationEmail: async ({ user, url }) => {
|
|
185
|
+
await yourEmailService.send({
|
|
186
|
+
to: user.email,
|
|
187
|
+
subject: 'Verify your email',
|
|
188
|
+
html: `<a href="${url}">Verify your email</a>`,
|
|
189
|
+
})
|
|
190
|
+
},
|
|
175
191
|
},
|
|
176
192
|
|
|
177
193
|
// Password reset
|
|
@@ -195,7 +211,7 @@ authPlugin({
|
|
|
195
211
|
// Session configuration
|
|
196
212
|
session: {
|
|
197
213
|
expiresIn: 604800, // 7 days in seconds
|
|
198
|
-
updateAge:
|
|
214
|
+
updateAge: 86400, // seconds between session refreshes; set `false` to disable
|
|
199
215
|
},
|
|
200
216
|
|
|
201
217
|
// Fields to include in session object
|
|
@@ -208,11 +224,6 @@ authPlugin({
|
|
|
208
224
|
company: text(),
|
|
209
225
|
},
|
|
210
226
|
},
|
|
211
|
-
|
|
212
|
-
// Custom email sending function
|
|
213
|
-
sendEmail: async ({ to, subject, html }) => {
|
|
214
|
-
await yourEmailService.send({ to, subject, html })
|
|
215
|
-
},
|
|
216
227
|
})
|
|
217
228
|
```
|
|
218
229
|
|
|
@@ -28,6 +28,22 @@
|
|
|
28
28
|
* auth migration. The recipe never touches the application's own domain `User`:
|
|
29
29
|
* its model names are `Auth`-prefixed by default and the plugin only ever
|
|
30
30
|
* adds/extends its *derived* keys.
|
|
31
|
+
*
|
|
32
|
+
* The single most common adoption shape is a project that ran better-auth
|
|
33
|
+
* *before* adding Stack: its live tables are still better-auth's own default
|
|
34
|
+
* lowercase names (`user`/`session`/`account`/`verification`), even though the
|
|
35
|
+
* derived list keys need the `Auth` prefix to avoid colliding with the app's
|
|
36
|
+
* own domain `User`. Pass `useBetterAuthTableNames: true` to point every
|
|
37
|
+
* model's physical table at that default while keeping the prefixed list keys
|
|
38
|
+
* (or `tableNames` for an explicit per-model override):
|
|
39
|
+
*
|
|
40
|
+
* ```typescript
|
|
41
|
+
* authPlugin({
|
|
42
|
+
* ...adoptBetterAuthTables({ useBetterAuthTableNames: true }),
|
|
43
|
+
* // AuthUser/AuthSession/AuthAccount/AuthVerification list keys,
|
|
44
|
+
* // @@map("user")/@@map("session")/@@map("account")/@@map("verification")
|
|
45
|
+
* })
|
|
46
|
+
* ```
|
|
31
47
|
*/
|
|
32
48
|
import type { AuthConfig } from './types.js';
|
|
33
49
|
/**
|
|
@@ -85,6 +101,37 @@ export type AdoptBetterAuthTablesOptions = {
|
|
|
85
101
|
account?: Record<string, string>;
|
|
86
102
|
verification?: Record<string, string>;
|
|
87
103
|
};
|
|
104
|
+
/**
|
|
105
|
+
* Set every model's physical table name to better-auth's own default
|
|
106
|
+
* lowercase table name (`user`, `session`, `account`, `verification`) —
|
|
107
|
+
* independent of the prefixed list key/`modelName`.
|
|
108
|
+
*
|
|
109
|
+
* This is the single most common adoption shape: a project that ran
|
|
110
|
+
* better-auth before adding the stack has exactly these tables, and the
|
|
111
|
+
* default `modelNamePrefix: 'Auth'` alone would otherwise pin the table
|
|
112
|
+
* name to the prefixed model name (`AuthUser`, ...), which `prisma migrate
|
|
113
|
+
* diff` reads as a rename against the live `user` table.
|
|
114
|
+
*
|
|
115
|
+
* Ignored for a model with an explicit entry in {@link tableNames}.
|
|
116
|
+
*
|
|
117
|
+
* @default false
|
|
118
|
+
*/
|
|
119
|
+
useBetterAuthTableNames?: boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Per-model explicit table name overrides, keyed by model. Takes
|
|
122
|
+
* precedence over `useBetterAuthTableNames` for that model.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* adoptBetterAuthTables({ tableNames: { user: 'users' } })
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
tableNames?: {
|
|
130
|
+
user?: string;
|
|
131
|
+
session?: string;
|
|
132
|
+
account?: string;
|
|
133
|
+
verification?: string;
|
|
134
|
+
};
|
|
88
135
|
};
|
|
89
136
|
/**
|
|
90
137
|
* The adoption-relevant slice of {@link AuthConfig}: the plugin-level `schema`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adopt-better-auth-tables.d.ts","sourceRoot":"","sources":["../../src/config/adopt-better-auth-tables.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"adopt-better-auth-tables.d.ts","sourceRoot":"","sources":["../../src/config/adopt-better-auth-tables.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,YAAY,CAAA;AAE7D;;;;;;GAMG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IAExB;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAChC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KACtC,CAAA;IAED;;;;;;;;;;;;;;OAcG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAA;IAEjC;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE;QACX,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,CAAA;CACF,CAAA;AAkBD;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,GAAG,IAAI,CAC5C,UAAU,EACV,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,cAAc,CAC3D,CAAA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,4BAAiC,GACzC,2BAA2B,CAiC7B"}
|
|
@@ -28,6 +28,22 @@
|
|
|
28
28
|
* auth migration. The recipe never touches the application's own domain `User`:
|
|
29
29
|
* its model names are `Auth`-prefixed by default and the plugin only ever
|
|
30
30
|
* adds/extends its *derived* keys.
|
|
31
|
+
*
|
|
32
|
+
* The single most common adoption shape is a project that ran better-auth
|
|
33
|
+
* *before* adding Stack: its live tables are still better-auth's own default
|
|
34
|
+
* lowercase names (`user`/`session`/`account`/`verification`), even though the
|
|
35
|
+
* derived list keys need the `Auth` prefix to avoid colliding with the app's
|
|
36
|
+
* own domain `User`. Pass `useBetterAuthTableNames: true` to point every
|
|
37
|
+
* model's physical table at that default while keeping the prefixed list keys
|
|
38
|
+
* (or `tableNames` for an explicit per-model override):
|
|
39
|
+
*
|
|
40
|
+
* ```typescript
|
|
41
|
+
* authPlugin({
|
|
42
|
+
* ...adoptBetterAuthTables({ useBetterAuthTableNames: true }),
|
|
43
|
+
* // AuthUser/AuthSession/AuthAccount/AuthVerification list keys,
|
|
44
|
+
* // @@map("user")/@@map("session")/@@map("account")/@@map("verification")
|
|
45
|
+
* })
|
|
46
|
+
* ```
|
|
31
47
|
*/
|
|
32
48
|
/** The four better-auth models and their default (unprefixed) model names. */
|
|
33
49
|
const MODEL_DEFAULT_NAMES = {
|
|
@@ -36,6 +52,13 @@ const MODEL_DEFAULT_NAMES = {
|
|
|
36
52
|
account: 'Account',
|
|
37
53
|
verification: 'Verification',
|
|
38
54
|
};
|
|
55
|
+
/** better-auth's own default lowercase table names, per model. */
|
|
56
|
+
const BETTER_AUTH_DEFAULT_TABLE_NAMES = {
|
|
57
|
+
user: 'user',
|
|
58
|
+
session: 'session',
|
|
59
|
+
account: 'account',
|
|
60
|
+
verification: 'verification',
|
|
61
|
+
};
|
|
39
62
|
/**
|
|
40
63
|
* Build the adoption {@link AuthConfig} fragment for a pre-existing better-auth
|
|
41
64
|
* installation.
|
|
@@ -48,11 +71,16 @@ const MODEL_DEFAULT_NAMES = {
|
|
|
48
71
|
* (and any field column maps) set to match the live tables
|
|
49
72
|
*/
|
|
50
73
|
export function adoptBetterAuthTables(options = {}) {
|
|
51
|
-
const { schema = 'auth', modelNamePrefix = 'Auth', fields = {} } = options;
|
|
74
|
+
const { schema = 'auth', modelNamePrefix = 'Auth', fields = {}, useBetterAuthTableNames = false, tableNames = {}, } = options;
|
|
52
75
|
const buildModel = (model) => {
|
|
53
76
|
const config = {
|
|
54
77
|
modelName: `${modelNamePrefix}${MODEL_DEFAULT_NAMES[model]}`,
|
|
55
78
|
};
|
|
79
|
+
const tableName = tableNames[model] ??
|
|
80
|
+
(useBetterAuthTableNames ? BETTER_AUTH_DEFAULT_TABLE_NAMES[model] : undefined);
|
|
81
|
+
if (tableName !== undefined) {
|
|
82
|
+
config.tableName = tableName;
|
|
83
|
+
}
|
|
56
84
|
const fieldMap = fields[model];
|
|
57
85
|
if (fieldMap && Object.keys(fieldMap).length > 0) {
|
|
58
86
|
config.fields = fieldMap;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adopt-better-auth-tables.js","sourceRoot":"","sources":["../../src/config/adopt-better-auth-tables.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"adopt-better-auth-tables.js","sourceRoot":"","sources":["../../src/config/adopt-better-auth-tables.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAgGH,8EAA8E;AAC9E,MAAM,mBAAmB,GAAG;IAC1B,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,YAAY,EAAE,cAAc;CACpB,CAAA;AAEV,kEAAkE;AAClE,MAAM,+BAA+B,GAAG;IACtC,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,YAAY,EAAE,cAAc;CACpB,CAAA;AAYV;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAO,GAAiC,EAAE;IAE1C,MAAM,EACJ,MAAM,GAAG,MAAM,EACf,eAAe,GAAG,MAAM,EACxB,MAAM,GAAG,EAAE,EACX,uBAAuB,GAAG,KAAK,EAC/B,UAAU,GAAG,EAAE,GAChB,GAAG,OAAO,CAAA;IAEX,MAAM,UAAU,GAAG,CAAC,KAAuC,EAAmB,EAAE;QAC9E,MAAM,MAAM,GAAoB;YAC9B,SAAS,EAAE,GAAG,eAAe,GAAG,mBAAmB,CAAC,KAAK,CAAC,EAAE;SAC7D,CAAA;QACD,MAAM,SAAS,GACb,UAAU,CAAC,KAAK,CAAC;YACjB,CAAC,uBAAuB,CAAC,CAAC,CAAC,+BAA+B,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QAChF,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,CAAC,SAAS,GAAG,SAAS,CAAA;QAC9B,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;QAC9B,IAAI,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjD,MAAM,CAAC,MAAM,GAAG,QAAQ,CAAA;QAC1B,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;IAED,OAAO;QACL,MAAM;QACN,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC;QACxB,OAAO,EAAE,UAAU,CAAC,SAAS,CAAC;QAC9B,OAAO,EAAE,UAAU,CAAC,SAAS,CAAC;QAC9B,YAAY,EAAE,UAAU,CAAC,cAAc,CAAC;KACzC,CAAA;AACH,CAAC"}
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
* Pure `better-auth config → Auth lists` derivation.
|
|
3
3
|
*
|
|
4
4
|
* This module is intentionally free of side effects and plugin/runtime
|
|
5
|
-
* concerns: given the resolved better-auth model config (per-model `modelName
|
|
6
|
-
* and `fields` column maps) plus any custom User fields, it
|
|
7
|
-
* OpenSaaS Auth lists (user/session/account/verification)
|
|
5
|
+
* concerns: given the resolved better-auth model config (per-model `modelName`,
|
|
6
|
+
* `tableName`, and `fields` column maps) plus any custom User fields, it
|
|
7
|
+
* produces the four OpenSaaS Auth lists (user/session/account/verification)
|
|
8
|
+
* with:
|
|
8
9
|
*
|
|
9
10
|
* - list keys taken from each model's `modelName`
|
|
10
|
-
* - a table `@@map` (list-level `db.map`)
|
|
11
|
-
*
|
|
11
|
+
* - a table `@@map` (list-level `db.map`) taken from each model's resolved
|
|
12
|
+
* `tableName` — independent of `modelName`, so a renamed list key can still
|
|
13
|
+
* adopt a differently-named live table
|
|
12
14
|
* - field-level `@map` (`db.map`) for any better-auth field → column override
|
|
13
15
|
* - relationship refs between the auth lists wired to the *derived* keys
|
|
14
16
|
* (e.g. `Session.user → AuthUser.sessions`)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-auth-lists.d.ts","sourceRoot":"","sources":["../../src/config/derive-auth-lists.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"derive-auth-lists.d.ts","sourceRoot":"","sources":["../../src/config/derive-auth-lists.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAEtD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAA6B,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEnG;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,oDAAoD;IACpD,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;QACf,YAAY,EAAE,MAAM,CAAA;KACrB,CAAA;IACD,kEAAkE;IAElE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;CACvC,CAAA;AAiND;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,oBAAoB,EAC5B,UAAU,GAAE,oBAAyB,EACrC,YAAY,GAAE,gBAAqB,GAClC,gBAAgB,CAiBlB"}
|