@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.
Files changed (47) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +146 -0
  3. package/CLAUDE.md +153 -9
  4. package/README.md +18 -7
  5. package/dist/config/adopt-better-auth-tables.d.ts +47 -0
  6. package/dist/config/adopt-better-auth-tables.d.ts.map +1 -1
  7. package/dist/config/adopt-better-auth-tables.js +29 -1
  8. package/dist/config/adopt-better-auth-tables.js.map +1 -1
  9. package/dist/config/derive-auth-lists.d.ts +7 -5
  10. package/dist/config/derive-auth-lists.d.ts.map +1 -1
  11. package/dist/config/derive-auth-lists.js +33 -34
  12. package/dist/config/derive-auth-lists.js.map +1 -1
  13. package/dist/config/index.d.ts.map +1 -1
  14. package/dist/config/index.js +41 -11
  15. package/dist/config/index.js.map +1 -1
  16. package/dist/config/plugin.d.ts.map +1 -1
  17. package/dist/config/plugin.js +39 -27
  18. package/dist/config/plugin.js.map +1 -1
  19. package/dist/config/types.d.ts +143 -28
  20. package/dist/config/types.d.ts.map +1 -1
  21. package/dist/server/build-better-auth-options.test.d.ts +2 -0
  22. package/dist/server/build-better-auth-options.test.d.ts.map +1 -0
  23. package/dist/server/build-better-auth-options.test.js +29 -0
  24. package/dist/server/build-better-auth-options.test.js.map +1 -0
  25. package/dist/server/index.d.ts +112 -8
  26. package/dist/server/index.d.ts.map +1 -1
  27. package/dist/server/index.js +284 -96
  28. package/dist/server/index.js.map +1 -1
  29. package/dist/server/schema-converter.d.ts +3 -3
  30. package/dist/server/schema-converter.d.ts.map +1 -1
  31. package/package.json +5 -5
  32. package/src/config/adopt-better-auth-tables.ts +70 -1
  33. package/src/config/derive-auth-lists.ts +37 -38
  34. package/src/config/index.ts +47 -12
  35. package/src/config/plugin.ts +40 -28
  36. package/src/config/types.ts +144 -27
  37. package/src/server/build-better-auth-options.test.ts +59 -0
  38. package/src/server/index.ts +470 -106
  39. package/src/server/schema-converter.ts +3 -3
  40. package/tests/adopt-better-auth-tables.test.ts +99 -0
  41. package/tests/config.test.ts +66 -8
  42. package/tests/derive-auth-lists.test.ts +79 -5
  43. package/tests/generated-fk-shape.test.ts +65 -0
  44. package/tests/plugin-derived-keys.test.ts +48 -0
  45. package/tests/server.test.ts +723 -0
  46. package/tsconfig.tsbuildinfo +1 -1
  47. package/vitest.config.ts +7 -1
@@ -1,6 +1,28 @@
1
1
  import { betterAuth } from 'better-auth';
2
2
  import { prismaAdapter } from 'better-auth/adapters/prisma';
3
3
  import { nextCookies } from 'better-auth/next-js';
4
+ /**
5
+ * Guard against the supplied plugin tuple silently drifting from the plugin
6
+ * array actually resolved from `authPlugin({ betterAuthPlugins })` — the
7
+ * supplied tuple exists for typing only, so if it isn't the exact same
8
+ * instances in the exact same order, the type it produces would be a lie
9
+ * about what `betterAuth()` is actually constructed with.
10
+ */
11
+ function assertPluginTupleMatchesResolved(supplied, resolved) {
12
+ if (supplied.length !== resolved.length) {
13
+ throw new Error('[@opensaas/stack-auth] The plugin tuple passed to `buildBetterAuthOptions()` / `createAuth()` ' +
14
+ `has ${supplied.length} plugin(s), but the plugin array resolved from \`authPlugin({ ` +
15
+ `betterAuthPlugins })\` has ${resolved.length}. Pass the exact same array (without ` +
16
+ '`nextCookies()` — the stack appends that itself).');
17
+ }
18
+ const mismatchIndex = supplied.findIndex((plugin, index) => plugin !== resolved[index]);
19
+ if (mismatchIndex !== -1) {
20
+ throw new Error('[@opensaas/stack-auth] The plugin tuple passed to `buildBetterAuthOptions()` / `createAuth()` ' +
21
+ `does not match the plugin array resolved from \`authPlugin({ betterAuthPlugins })\` at index ` +
22
+ `${mismatchIndex} (got plugin "${supplied[mismatchIndex]?.id}", expected the same instance as ` +
23
+ `"${resolved[mismatchIndex]?.id}"). Pass the exact same array — same instances, same order.`);
24
+ }
25
+ }
4
26
  /**
5
27
  * Get better-auth database configuration from OpenSaas config
6
28
  */
@@ -24,25 +46,177 @@ function toBetterAuthModelOptions(model) {
24
46
  options.fields = model.fields;
25
47
  return Object.keys(options).length > 0 ? options : undefined;
26
48
  }
49
+ const MODELS_WITH_NO_ADDITIONAL_FIELDS_PASSTHROUGH = [
50
+ 'user',
51
+ 'session',
52
+ 'account',
53
+ 'verification',
54
+ ];
27
55
  /**
28
- * Create a better-auth instance from OpenSaas config
29
- * This should be called once at app startup
30
- *
31
- * @example
32
- * ```typescript
33
- * // lib/auth.ts
34
- * import { createAuth } from '@opensaas/stack-auth/server'
35
- * import config from '../opensaas.config'
36
- * import { rawOpensaasContext } from '@/.opensaas/context'
37
- *
38
- * export const auth = createAuth(config, rawOpensaasContext)
39
- * ```
56
+ * Reject `betterAuthOptions` keys that already have a dedicated, non-passthrough
57
+ * seam accepting them here would create two unranked ways to set the same
58
+ * thing, or (for `additionalFields`) silently diverge from the generated
59
+ * Prisma schema. See the `betterAuthOptions` doc comment on `AuthConfig`.
60
+ */
61
+ function assertNoUnsupportedPassthroughKeys(betterAuthOptions) {
62
+ if ('database' in betterAuthOptions) {
63
+ throw new Error('[@opensaas/stack-auth] `betterAuthOptions.database` is not supported — the stack ' +
64
+ 'derives the database adapter from your `db` config and the running context. ' +
65
+ 'Configure the database through `db` in `opensaas.config.ts` instead.');
66
+ }
67
+ if ('plugins' in betterAuthOptions) {
68
+ throw new Error('[@opensaas/stack-auth] `betterAuthOptions.plugins` is not supported — better-auth ' +
69
+ 'plugins are added through `authPlugin({ betterAuthPlugins: [...] })`, which the stack ' +
70
+ 'appends `nextCookies()` after. Use `betterAuthPlugins` instead.');
71
+ }
72
+ for (const model of MODELS_WITH_NO_ADDITIONAL_FIELDS_PASSTHROUGH) {
73
+ const modelOptions = betterAuthOptions[model];
74
+ if (modelOptions &&
75
+ typeof modelOptions === 'object' &&
76
+ !Array.isArray(modelOptions) &&
77
+ 'additionalFields' in modelOptions) {
78
+ throw new Error(`[@opensaas/stack-auth] \`betterAuthOptions.${model}.additionalFields\` is not ` +
79
+ 'supported — it adds columns that would not be reflected in the generated Prisma ' +
80
+ 'schema. Add fields to the derived list instead: ' +
81
+ (model === 'user'
82
+ ? '`extendUserList`, or declare the list yourself in your own `lists` config.'
83
+ : 'declare the derived list yourself in your own `lists` config (the auth plugin ' +
84
+ 'merges in field additions for the models it derives).'));
85
+ }
86
+ }
87
+ }
88
+ function isPlainObject(value) {
89
+ return (typeof value === 'object' &&
90
+ value !== null &&
91
+ !Array.isArray(value) &&
92
+ Object.getPrototypeOf(value) === Object.prototype);
93
+ }
94
+ /**
95
+ * Deep-merge `overrides` onto `base`, recursing into plain-object values so a
96
+ * nested addition (one database hook, one session sub-option) merges
97
+ * alongside sibling keys the stack already set there rather than replacing
98
+ * the whole branch. Arrays and any other value type replace outright.
99
+ * `overrides` wins on every key collision.
40
100
  */
41
- export function createAuth(opensaasConfig, context) {
101
+ function mergeBetterAuthOptions(base, overrides) {
102
+ const result = { ...base };
103
+ for (const [key, value] of Object.entries(overrides)) {
104
+ const baseValue = result[key];
105
+ result[key] =
106
+ isPlainObject(baseValue) && isPlainObject(value)
107
+ ? mergeBetterAuthOptions(baseValue, value)
108
+ : value;
109
+ }
110
+ return result;
111
+ }
112
+ export async function buildBetterAuthOptions(opensaasConfig, context, plugins) {
113
+ const resolvedConfig = await Promise.resolve(opensaasConfig);
114
+ const resolvedContext = await Promise.resolve(context);
115
+ // Extract auth config from plugin data
116
+ const authConfig = resolvedConfig._pluginData?.auth;
117
+ if (!authConfig) {
118
+ throw new Error('Auth config not found. Make sure to use authPlugin() in your opensaas.config.ts');
119
+ }
120
+ // `requireConfirmation` has no better-auth equivalent — it's a UI-only
121
+ // concern the pre-built forms already take as their own
122
+ // `requirePasswordConfirmation` prop. Warn rather than silently drop it,
123
+ // since setting it here looks like it should do something.
124
+ if (authConfig.emailAndPassword.enabled &&
125
+ authConfig.emailAndPassword.requireConfirmation !== true) {
126
+ console.warn('[@opensaas/stack-auth] `emailAndPassword.requireConfirmation` has no effect here — ' +
127
+ 'createAuth() has no better-auth option to forward it to. Pass ' +
128
+ '`requirePasswordConfirmation` directly to <SignUpForm> / <ResetPasswordForm> instead.');
129
+ }
130
+ // `passwordReset` is wired through better-auth's `emailAndPassword` config
131
+ // (there's no password to reset without a password-based account), so it
132
+ // silently has no effect if email/password auth itself isn't enabled.
133
+ if (authConfig.passwordReset.enabled && !authConfig.emailAndPassword.enabled) {
134
+ console.warn('[@opensaas/stack-auth] `passwordReset.enabled` has no effect here — ' +
135
+ '`emailAndPassword.enabled` is false, so there is no password-based account to reset.');
136
+ }
137
+ assertNoUnsupportedPassthroughKeys(authConfig.betterAuthOptions);
138
+ const resolvedPlugins = authConfig.betterAuthPlugins || [];
139
+ if (plugins) {
140
+ assertPluginTupleMatchesResolved(plugins, resolvedPlugins);
141
+ }
142
+ // Build better-auth configuration
143
+ const betterAuthConfig = {
144
+ database: getDatabaseConfig(resolvedConfig.db, resolvedContext),
145
+ // Mirror the per-model config (modelName + field column maps) back to
146
+ // better-auth so the running auth instance reads/writes the same
147
+ // tables/columns the OpenSaaS Auth lists were derived from.
148
+ user: toBetterAuthModelOptions(authConfig.models.user),
149
+ session: {
150
+ ...toBetterAuthModelOptions(authConfig.models.session),
151
+ expiresIn: authConfig.session.expiresIn || 604800,
152
+ // better-auth treats `updateAge: 0` as "refresh on every request", not
153
+ // "never refresh" — disabling refresh entirely requires its separate
154
+ // `disableSessionRefresh` flag regardless of `updateAge`.
155
+ ...(authConfig.session.updateAge === false
156
+ ? { disableSessionRefresh: true }
157
+ : { updateAge: authConfig.session.updateAge }),
158
+ },
159
+ account: toBetterAuthModelOptions(authConfig.models.account),
160
+ verification: toBetterAuthModelOptions(authConfig.models.verification),
161
+ // Enable email and password if configured
162
+ emailAndPassword: authConfig.emailAndPassword.enabled
163
+ ? {
164
+ enabled: true,
165
+ requireEmailVerification: authConfig.emailVerification.enabled,
166
+ minPasswordLength: authConfig.emailAndPassword.minPasswordLength,
167
+ ...(authConfig.passwordReset.enabled
168
+ ? {
169
+ sendResetPassword: authConfig.emailAndPassword.sendResetPassword,
170
+ resetPasswordTokenExpiresIn: authConfig.passwordReset.tokenExpiration,
171
+ }
172
+ : {}),
173
+ }
174
+ : undefined,
175
+ // Email verification (independent of emailAndPassword — also covers
176
+ // e.g. a social-provider account whose email isn't yet verified)
177
+ emailVerification: authConfig.emailVerification.enabled
178
+ ? {
179
+ sendVerificationEmail: authConfig.emailVerification.sendVerificationEmail,
180
+ sendOnSignUp: authConfig.emailVerification.sendOnSignUp,
181
+ expiresIn: authConfig.emailVerification.tokenExpiration,
182
+ }
183
+ : undefined,
184
+ // Trust host (required for production)
185
+ trustedOrigins: process.env.BETTER_AUTH_TRUSTED_ORIGINS?.split(',') || [],
186
+ // Social providers
187
+ socialProviders: Object.entries(authConfig.socialProviders)
188
+ .filter(([_, config]) => config?.enabled !== false)
189
+ .reduce((acc, [provider, config]) => {
190
+ if (config) {
191
+ acc[provider] = {
192
+ clientId: config.clientId,
193
+ clientSecret: config.clientSecret,
194
+ };
195
+ }
196
+ return acc;
197
+ }, {}),
198
+ // Rate limiting configuration
199
+ rateLimit: authConfig.rateLimit
200
+ ? {
201
+ enabled: authConfig.rateLimit.enabled,
202
+ window: authConfig.rateLimit.window,
203
+ max: authConfig.rateLimit.max,
204
+ }
205
+ : undefined,
206
+ // Pass through any additional Better Auth plugins, then append
207
+ // nextCookies LAST so it can write the Set-Cookie headers produced by
208
+ // any auth.api.* call made inside a Next.js server action into Next's
209
+ // cookie store. This is what makes the server-action auth forms (which
210
+ // call auth.api.signInEmail/signUpEmail/etc. server-side) actually
211
+ // persist a session. It must be the final plugin in the array.
212
+ plugins: [...resolvedPlugins, nextCookies()],
213
+ };
214
+ return mergeBetterAuthOptions(betterAuthConfig, authConfig.betterAuthOptions);
215
+ }
216
+ export function createAuth(opensaasConfig, context, plugins) {
42
217
  // Resolve config and context asynchronously
43
218
  const configPromise = Promise.resolve(opensaasConfig);
44
219
  const contextPromise = Promise.resolve(context);
45
- // Create auth instance lazily when needed
46
220
  let authInstance = null;
47
221
  let authPromise = null;
48
222
  async function getAuthInstance() {
@@ -50,66 +224,9 @@ export function createAuth(opensaasConfig, context) {
50
224
  return authInstance;
51
225
  if (!authPromise) {
52
226
  authPromise = (async () => {
53
- const resolvedConfig = await configPromise;
54
- const resolvedContext = await contextPromise;
55
- // Extract auth config from plugin data
56
- const authConfig = resolvedConfig._pluginData?.auth;
57
- if (!authConfig) {
58
- throw new Error('Auth config not found. Make sure to use authPlugin() in your opensaas.config.ts');
59
- }
60
- // Build better-auth configuration
61
- const betterAuthConfig = {
62
- database: getDatabaseConfig(resolvedConfig.db, resolvedContext),
63
- // Mirror the per-model config (modelName + field column maps) back to
64
- // better-auth so the running auth instance reads/writes the same
65
- // tables/columns the OpenSaaS Auth lists were derived from.
66
- user: toBetterAuthModelOptions(authConfig.models.user),
67
- session: {
68
- ...toBetterAuthModelOptions(authConfig.models.session),
69
- expiresIn: authConfig.session.expiresIn || 604800,
70
- updateAge: authConfig.session.updateAge
71
- ? (authConfig.session.expiresIn || 604800) / 10
72
- : 0,
73
- },
74
- account: toBetterAuthModelOptions(authConfig.models.account),
75
- verification: toBetterAuthModelOptions(authConfig.models.verification),
76
- // Enable email and password if configured
77
- emailAndPassword: authConfig.emailAndPassword.enabled
78
- ? {
79
- enabled: true,
80
- requireEmailVerification: authConfig.emailVerification.enabled,
81
- }
82
- : undefined,
83
- // Trust host (required for production)
84
- trustedOrigins: process.env.BETTER_AUTH_TRUSTED_ORIGINS?.split(',') || [],
85
- // Social providers
86
- socialProviders: Object.entries(authConfig.socialProviders)
87
- .filter(([_, config]) => config?.enabled !== false)
88
- .reduce((acc, [provider, config]) => {
89
- if (config) {
90
- acc[provider] = {
91
- clientId: config.clientId,
92
- clientSecret: config.clientSecret,
93
- };
94
- }
95
- return acc;
96
- }, {}),
97
- // Rate limiting configuration
98
- rateLimit: authConfig.rateLimit
99
- ? {
100
- enabled: authConfig.rateLimit.enabled,
101
- window: authConfig.rateLimit.window,
102
- max: authConfig.rateLimit.max,
103
- }
104
- : undefined,
105
- // Pass through any additional Better Auth plugins, then append
106
- // nextCookies LAST so it can write the Set-Cookie headers produced by
107
- // any auth.api.* call made inside a Next.js server action into Next's
108
- // cookie store. This is what makes the server-action auth forms (which
109
- // call auth.api.signInEmail/signUpEmail/etc. server-side) actually
110
- // persist a session. It must be the final plugin in the array.
111
- plugins: [...(authConfig.betterAuthPlugins || []), nextCookies()],
112
- };
227
+ const betterAuthConfig = plugins
228
+ ? await buildBetterAuthOptions(configPromise, contextPromise, plugins)
229
+ : await buildBetterAuthOptions(configPromise, contextPromise);
113
230
  authInstance = betterAuth(betterAuthConfig);
114
231
  return authInstance;
115
232
  })();
@@ -158,31 +275,102 @@ export function createAuth(opensaasConfig, context) {
158
275
  });
159
276
  }
160
277
  /**
161
- * Get session from better-auth and transform it to OpenSaas session format
162
- * This is used internally by the generated context
278
+ * Field names already warned about failing to resolve against a session, so a
279
+ * given field warns at most once per process rather than once per request.
163
280
  */
164
- export async function getSessionFromAuth(auth, sessionFields) {
165
- try {
166
- const session = await auth.api.getSession({
167
- headers: new Headers(),
168
- });
169
- if (!session?.user) {
170
- return null;
171
- }
172
- // Build session object with requested fields
173
- const result = {};
174
- for (const field of sessionFields) {
175
- if (field === 'userId') {
176
- result.userId = session.user.id;
177
- }
178
- else if (field in session.user) {
179
- result[field] = session.user[field];
180
- }
181
- }
182
- return result;
281
+ const unresolvedSessionFieldWarnings = new Set();
282
+ /**
283
+ * Warn (once per field, per process) that a `sessionFields` entry could not
284
+ * be resolved from the session shape `auth.api.getSession()` actually
285
+ * returned — naming the field and what keys were available to check, so the
286
+ * gap is visible here instead of surfacing later as an access-control
287
+ * function silently reading `undefined`.
288
+ */
289
+ function warnUnresolvedSessionField(field, resolvedSession) {
290
+ if (unresolvedSessionFieldWarnings.has(field))
291
+ return;
292
+ unresolvedSessionFieldWarnings.add(field);
293
+ const user = isPlainObject(resolvedSession.user) ? resolvedSession.user : undefined;
294
+ const sessionRow = isPlainObject(resolvedSession.session) ? resolvedSession.session : undefined;
295
+ console.warn(`[@opensaas/stack-auth] sessionFields: "${field}" was not found on the resolved session. ` +
296
+ `Checked its top-level keys (${Object.keys(resolvedSession).join(', ') || 'none'}), ` +
297
+ `its "user" object (${user ? Object.keys(user).join(', ') || 'none' : 'not present'}), ` +
298
+ `and its "session" object (${sessionRow ? Object.keys(sessionRow).join(', ') || 'none' : 'not present'}). ` +
299
+ `The field is omitted from the projected session. A \`customSession\` plugin that nests this ` +
300
+ `value elsewhere is the app's own to reconcile — see the \`sessionFields\` reference. ` +
301
+ `This warning will not repeat for "${field}".`);
302
+ }
303
+ /**
304
+ * Resolve a single `sessionFields` entry off the resolved better-auth
305
+ * session (whatever `auth.api.getSession()` returned — the default `{
306
+ * session, user }` shape, or a `customSession` plugin's replaced shape).
307
+ *
308
+ * `userId` is special-cased to the authenticated user's `id` — the
309
+ * documented default apps depend on. Every other name resolves against a
310
+ * fixed precedence so a collision between sources is predictable rather
311
+ * than incidental: a top-level key on the resolved session object, then the
312
+ * `user` object, then the `session` sub-object.
313
+ */
314
+ function resolveSessionField(field, resolvedSession) {
315
+ const user = isPlainObject(resolvedSession.user) ? resolvedSession.user : undefined;
316
+ if (field === 'userId') {
317
+ return user && 'id' in user ? { found: true, value: user.id } : { found: false };
318
+ }
319
+ if (field in resolvedSession) {
320
+ return { found: true, value: resolvedSession[field] };
321
+ }
322
+ if (user && field in user) {
323
+ return { found: true, value: user[field] };
183
324
  }
184
- catch {
325
+ const sessionRow = isPlainObject(resolvedSession.session) ? resolvedSession.session : undefined;
326
+ if (sessionRow && field in sessionRow) {
327
+ return { found: true, value: sessionRow[field] };
328
+ }
329
+ return { found: false };
330
+ }
331
+ /**
332
+ * Get session from better-auth and transform it to OpenSaas session format —
333
+ * a flattened projection of `sessionFields` off the *resolved* session
334
+ * object, not just its `user` sub-object. This is what makes a
335
+ * `customSession` plugin's fields (added at the top level, or a
336
+ * session-only field like the admin plugin's `impersonatedBy`) reachable.
337
+ * See the `sessionFields` reference for the resolution precedence.
338
+ *
339
+ * Returns `null` only when there is genuinely no session — a resolved
340
+ * session with no `user` key (a `customSession` plugin that dropped it) is
341
+ * still a session and still gets projected, never misreported as anonymous.
342
+ * A listed field that can't be resolved from the session shape is omitted
343
+ * and warns once per field per process (see `warnUnresolvedSessionField`)
344
+ * instead of silently vanishing into an access-control function reading
345
+ * `undefined`.
346
+ *
347
+ * Errors from the underlying `auth.api.getSession()` call propagate rather
348
+ * than becoming `null` — collapsing a lookup failure (e.g. a session-store
349
+ * outage) into "anonymous" is indistinguishable from a mass sign-out under
350
+ * fail-closed access control, so the caller must see it.
351
+ *
352
+ * Not called by any generated code before this helper existed — apps used to
353
+ * hand-roll this same transform against `auth.api.getSession({ headers:
354
+ * await headers() })`. Exported as the single reusable implementation; pass
355
+ * the caller's request headers (e.g. Next.js `await headers()` in a Server
356
+ * Component/action) so a session cookie can actually be resolved.
357
+ */
358
+ export async function getSessionFromAuth(auth, sessionFields, headers) {
359
+ const resolvedSession = await auth.api.getSession({ headers });
360
+ if (!resolvedSession) {
185
361
  return null;
186
362
  }
363
+ const resolvedSessionRecord = resolvedSession;
364
+ const result = {};
365
+ for (const field of sessionFields) {
366
+ const resolved = resolveSessionField(field, resolvedSessionRecord);
367
+ if (resolved.found) {
368
+ result[field] = resolved.value;
369
+ }
370
+ else {
371
+ warnUnresolvedSessionField(field, resolvedSessionRecord);
372
+ }
373
+ }
374
+ return result;
187
375
  }
188
376
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
@@ -8,13 +8,13 @@ import type { ListConfig } from '@opensaas/stack-core';
8
8
  * Inferred from better-auth internal types
9
9
  */
10
10
  type BetterAuthFieldAttribute = {
11
- type: string;
11
+ type: string | string[];
12
12
  required?: boolean;
13
13
  unique?: boolean;
14
14
  references?: {
15
15
  model: string;
16
16
  field: string;
17
- onDelete?: 'cascade' | 'set null' | 'restrict';
17
+ onDelete?: 'no action' | 'restrict' | 'cascade' | 'set null' | 'set default';
18
18
  };
19
19
  defaultValue?: unknown;
20
20
  returned?: boolean;
@@ -24,7 +24,7 @@ type BetterAuthFieldAttribute = {
24
24
  * Better Auth table schema structure
25
25
  */
26
26
  type BetterAuthTableSchema = {
27
- modelName: string;
27
+ modelName?: string;
28
28
  fields: Record<string, BetterAuthFieldAttribute>;
29
29
  };
30
30
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"schema-converter.d.ts","sourceRoot":"","sources":["../../src/server/schema-converter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,sBAAsB,CAAA;AAEnE;;;GAGG;AACH,KAAK,wBAAwB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,UAAU,CAAC,EAAE;QACX,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,CAAA;KAC/C,CAAA;IACD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAED;;GAEG;AACH,KAAK,qBAAqB,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAA;CACjD,CAAA;AA2DD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,qBAAqB,GAEjC,UAAU,CAAC,GAAG,CAAC,CA4BjB;AAED;;;GAGG;AACH,KAAK,gBAAgB,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,cAAc,CAAA;AAEvE;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAA;AA0BzE;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,EAC7C,aAAa,GAAE,iBAAsB,GAEpC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAejC"}
1
+ {"version":3,"file":"schema-converter.d.ts","sourceRoot":"","sources":["../../src/server/schema-converter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,sBAAsB,CAAA;AAEnE;;;GAGG;AACH,KAAK,wBAAwB,GAAG;IAC9B,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,UAAU,CAAC,EAAE;QACX,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa,CAAA;KAC7E,CAAA;IACD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAED;;GAEG;AACH,KAAK,qBAAqB,GAAG;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAA;CACjD,CAAA;AA2DD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,qBAAqB,GAEjC,UAAU,CAAC,GAAG,CAAC,CA4BjB;AAED;;;GAGG;AACH,KAAK,gBAAgB,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,cAAc,CAAA;AAEvE;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAA;AA0BzE;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,EAC7C,aAAa,GAAE,iBAAsB,GAEpC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAejC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opensaas/stack-auth",
3
- "version": "0.36.0",
3
+ "version": "0.38.0",
4
4
  "description": "Better-auth integration for OpenSaas Stack",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,13 +60,13 @@
60
60
  "@typescript/native": "npm:typescript@^7.0.2",
61
61
  "@vitest/coverage-v8": "^4.1.10",
62
62
  "@vitest/ui": "^4.1.10",
63
- "better-auth": "^1.5.5",
63
+ "better-auth": "^1.6.25",
64
64
  "next": "^16.2.10",
65
- "react": "^19.2.4",
65
+ "react": "^19.2.8",
66
66
  "typescript": "npm:@typescript/typescript6@^6.0.2",
67
67
  "vitest": "^4.1.10",
68
- "@opensaas/stack-cli": "0.36.0",
69
- "@opensaas/stack-core": "0.36.0"
68
+ "@opensaas/stack-cli": "0.38.0",
69
+ "@opensaas/stack-core": "0.38.0"
70
70
  },
71
71
  "scripts": {
72
72
  "build": "tsc",
@@ -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
 
33
49
  import type { AuthConfig, AuthModelConfig } from './types.js'
@@ -89,6 +105,39 @@ export type AdoptBetterAuthTablesOptions = {
89
105
  account?: Record<string, string>
90
106
  verification?: Record<string, string>
91
107
  }
108
+
109
+ /**
110
+ * Set every model's physical table name to better-auth's own default
111
+ * lowercase table name (`user`, `session`, `account`, `verification`) —
112
+ * independent of the prefixed list key/`modelName`.
113
+ *
114
+ * This is the single most common adoption shape: a project that ran
115
+ * better-auth before adding the stack has exactly these tables, and the
116
+ * default `modelNamePrefix: 'Auth'` alone would otherwise pin the table
117
+ * name to the prefixed model name (`AuthUser`, ...), which `prisma migrate
118
+ * diff` reads as a rename against the live `user` table.
119
+ *
120
+ * Ignored for a model with an explicit entry in {@link tableNames}.
121
+ *
122
+ * @default false
123
+ */
124
+ useBetterAuthTableNames?: boolean
125
+
126
+ /**
127
+ * Per-model explicit table name overrides, keyed by model. Takes
128
+ * precedence over `useBetterAuthTableNames` for that model.
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * adoptBetterAuthTables({ tableNames: { user: 'users' } })
133
+ * ```
134
+ */
135
+ tableNames?: {
136
+ user?: string
137
+ session?: string
138
+ account?: string
139
+ verification?: string
140
+ }
92
141
  }
93
142
 
94
143
  /** The four better-auth models and their default (unprefixed) model names. */
@@ -99,6 +148,14 @@ const MODEL_DEFAULT_NAMES = {
99
148
  verification: 'Verification',
100
149
  } as const
101
150
 
151
+ /** better-auth's own default lowercase table names, per model. */
152
+ const BETTER_AUTH_DEFAULT_TABLE_NAMES = {
153
+ user: 'user',
154
+ session: 'session',
155
+ account: 'account',
156
+ verification: 'verification',
157
+ } as const
158
+
102
159
  /**
103
160
  * The adoption-relevant slice of {@link AuthConfig}: the plugin-level `schema`
104
161
  * and the per-model `modelName`/`fields`. Returned (not the full `AuthConfig`)
@@ -123,12 +180,24 @@ export type AdoptBetterAuthTablesConfig = Pick<
123
180
  export function adoptBetterAuthTables(
124
181
  options: AdoptBetterAuthTablesOptions = {},
125
182
  ): AdoptBetterAuthTablesConfig {
126
- const { schema = 'auth', modelNamePrefix = 'Auth', fields = {} } = options
183
+ const {
184
+ schema = 'auth',
185
+ modelNamePrefix = 'Auth',
186
+ fields = {},
187
+ useBetterAuthTableNames = false,
188
+ tableNames = {},
189
+ } = options
127
190
 
128
191
  const buildModel = (model: keyof typeof MODEL_DEFAULT_NAMES): AuthModelConfig => {
129
192
  const config: AuthModelConfig = {
130
193
  modelName: `${modelNamePrefix}${MODEL_DEFAULT_NAMES[model]}`,
131
194
  }
195
+ const tableName =
196
+ tableNames[model] ??
197
+ (useBetterAuthTableNames ? BETTER_AUTH_DEFAULT_TABLE_NAMES[model] : undefined)
198
+ if (tableName !== undefined) {
199
+ config.tableName = tableName
200
+ }
132
201
  const fieldMap = fields[model]
133
202
  if (fieldMap && Object.keys(fieldMap).length > 0) {
134
203
  config.fields = fieldMap