@opensaas/stack-auth 0.21.0 → 0.23.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 (45) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +92 -0
  3. package/CLAUDE.md +98 -0
  4. package/README.md +33 -0
  5. package/dist/config/adopt-better-auth-tables.d.ts +107 -0
  6. package/dist/config/adopt-better-auth-tables.d.ts.map +1 -0
  7. package/dist/config/adopt-better-auth-tables.js +70 -0
  8. package/dist/config/adopt-better-auth-tables.js.map +1 -0
  9. package/dist/config/derive-auth-lists.d.ts +50 -0
  10. package/dist/config/derive-auth-lists.d.ts.map +1 -0
  11. package/dist/config/derive-auth-lists.js +274 -0
  12. package/dist/config/derive-auth-lists.js.map +1 -0
  13. package/dist/config/index.d.ts.map +1 -1
  14. package/dist/config/index.js +43 -0
  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 +52 -9
  18. package/dist/config/plugin.js.map +1 -1
  19. package/dist/config/types.d.ts +130 -3
  20. package/dist/config/types.d.ts.map +1 -1
  21. package/dist/index.d.ts +4 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +6 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/lists/index.d.ts +17 -11
  26. package/dist/lists/index.d.ts.map +1 -1
  27. package/dist/lists/index.js +34 -208
  28. package/dist/lists/index.js.map +1 -1
  29. package/dist/server/index.d.ts.map +1 -1
  30. package/dist/server/index.js +28 -7
  31. package/dist/server/index.js.map +1 -1
  32. package/package.json +2 -2
  33. package/src/config/adopt-better-auth-tables.ts +146 -0
  34. package/src/config/derive-auth-lists.ts +323 -0
  35. package/src/config/index.ts +58 -0
  36. package/src/config/plugin.ts +66 -9
  37. package/src/config/types.ts +146 -3
  38. package/src/index.ts +13 -0
  39. package/src/lists/index.ts +42 -202
  40. package/src/server/index.ts +31 -9
  41. package/tests/adopt-better-auth-tables.test.ts +183 -0
  42. package/tests/derive-auth-lists.test.ts +232 -0
  43. package/tests/plugin-derived-keys.test.ts +138 -0
  44. package/tests/plugin-schema-placement.test.ts +121 -0
  45. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,274 @@
1
+ /**
2
+ * Pure `better-auth config → Auth lists` derivation.
3
+ *
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 produces the four
7
+ * OpenSaaS Auth lists (user/session/account/verification) with:
8
+ *
9
+ * - list keys taken from each model's `modelName`
10
+ * - a table `@@map` (list-level `db.map`) when the key differs from the
11
+ * default better-auth model name
12
+ * - field-level `@map` (`db.map`) for any better-auth field → column override
13
+ * - relationship refs between the auth lists wired to the *derived* keys
14
+ * (e.g. `Session.user → AuthUser.sessions`)
15
+ *
16
+ * When the developer supplies no `modelName`/`fields` overrides, the output is
17
+ * byte-for-byte the historical default set keyed `User`/`Session`/`Account`/
18
+ * `Verification` with the original field shapes — see the unit tests.
19
+ *
20
+ * `getAuthLists`/`convertBetterAuthSchema` (and the runtime user-key
21
+ * resolution) consume this module so derivation lives in exactly one place.
22
+ */
23
+ import { list } from '@opensaas/stack-core';
24
+ import { text, timestamp, checkbox, relationship } from '@opensaas/stack-core/fields';
25
+ /**
26
+ * Default better-auth model names — used to decide whether a `@@map` is needed
27
+ * (only when the configured `modelName` differs from the default).
28
+ */
29
+ const DEFAULT_MODEL_NAMES = {
30
+ user: 'User',
31
+ session: 'Session',
32
+ account: 'Account',
33
+ verification: 'Verification',
34
+ };
35
+ /**
36
+ * Build the list-level `db` config (`timestamps` + `@@map` + `@@schema`) for a
37
+ * derived list.
38
+ *
39
+ * Always opts the list into auto-timestamps (`timestamps: true`). better-auth's
40
+ * adapter writes `createdAt`/`updatedAt` on every auth row and the schema
41
+ * converter returns `null` for those columns (it assumes the generator injects
42
+ * them). Now that auto-timestamps are OFF by default (ADR-0004), each derived
43
+ * Auth list must opt back in so the generated models keep those columns and
44
+ * better-auth keeps working.
45
+ *
46
+ * When the developer renames the model (e.g. `modelName: 'AuthUser'`), we also
47
+ * pin the physical table name to that model name via `@@map("AuthUser")` so the
48
+ * generated list adopts the developer's live table exactly. When a `schema` is
49
+ * configured (plugin-level or per-model), the list is placed in that Postgres
50
+ * schema via `@@schema(...)`.
51
+ *
52
+ * With no `modelName`/`schema` overrides we emit only `timestamps: true`,
53
+ * leaving the default `User`/`Session`/... table/schema output unchanged.
54
+ */
55
+ function listDb(model, defaultModelName) {
56
+ const map = model.modelName !== defaultModelName ? model.modelName : undefined;
57
+ const schema = model.schema;
58
+ return {
59
+ timestamps: true,
60
+ ...(map !== undefined ? { map } : {}),
61
+ ...(schema !== undefined ? { schema } : {}),
62
+ };
63
+ }
64
+ /**
65
+ * Resolve the `db.map` (`@map` column override) for a better-auth field, or
66
+ * `undefined` when there is no override (so default output is unchanged).
67
+ *
68
+ * The field builders capture `options.db` in a closure when generating Prisma
69
+ * types, so the column map MUST be passed through the builder's `db` option
70
+ * rather than patched onto the returned field object.
71
+ */
72
+ function fieldDb(fieldName, fields) {
73
+ const column = fields[fieldName];
74
+ return column ? { map: column } : undefined;
75
+ }
76
+ /**
77
+ * Build the foreign-key `db` config for a `user` relationship, honouring a
78
+ * `userId` column override from the better-auth `fields` map.
79
+ */
80
+ function userForeignKeyDb(fields) {
81
+ const column = fields.userId;
82
+ return column ? { foreignKey: { map: column } } : undefined;
83
+ }
84
+ /**
85
+ * Create the Auth user list, applying derived field column maps + table map and
86
+ * wiring the session/account relationships to the derived keys.
87
+ */
88
+ function createUserList(model, keys, userConfig) {
89
+ const f = model.fields;
90
+ return list({
91
+ fields: {
92
+ name: text({ validation: { isRequired: true }, db: fieldDb('name', f) }),
93
+ email: text({
94
+ validation: { isRequired: true },
95
+ isIndexed: 'unique',
96
+ db: fieldDb('email', f),
97
+ }),
98
+ emailVerified: checkbox({ defaultValue: false, db: fieldDb('emailVerified', f) }),
99
+ image: text({ db: fieldDb('image', f) }),
100
+ // Relationships to the other auth lists — refs follow the derived keys.
101
+ sessions: relationship({ ref: `${keys.session}.user`, many: true }),
102
+ accounts: relationship({ ref: `${keys.account}.user`, many: true }),
103
+ // Custom fields from user config
104
+ ...(userConfig.fields || {}),
105
+ },
106
+ db: listDb(model, DEFAULT_MODEL_NAMES.user),
107
+ access: userConfig.access || {
108
+ operation: {
109
+ query: () => true,
110
+ create: () => true,
111
+ update: ({ session, item }) => {
112
+ if (!session)
113
+ return false;
114
+ const userId = session.userId;
115
+ const itemId = item?.id;
116
+ return userId === itemId;
117
+ },
118
+ delete: ({ session, item }) => {
119
+ if (!session)
120
+ return false;
121
+ const userId = session.userId;
122
+ const itemId = item?.id;
123
+ return userId === itemId;
124
+ },
125
+ },
126
+ },
127
+ hooks: userConfig.hooks,
128
+ });
129
+ }
130
+ /**
131
+ * Create the Auth session list.
132
+ */
133
+ function createSessionList(model, keys) {
134
+ const f = model.fields;
135
+ return list({
136
+ fields: {
137
+ token: text({
138
+ validation: { isRequired: true },
139
+ isIndexed: 'unique',
140
+ db: fieldDb('token', f),
141
+ }),
142
+ expiresAt: timestamp({ db: fieldDb('expiresAt', f) }),
143
+ ipAddress: text({ db: fieldDb('ipAddress', f) }),
144
+ userAgent: text({ db: fieldDb('userAgent', f) }),
145
+ user: relationship({
146
+ ref: `${keys.user}.sessions`,
147
+ db: userForeignKeyDb(f),
148
+ }),
149
+ },
150
+ db: listDb(model, DEFAULT_MODEL_NAMES.session),
151
+ access: {
152
+ operation: {
153
+ query: ({ session }) => {
154
+ if (!session)
155
+ return false;
156
+ const userId = session.userId;
157
+ if (!userId)
158
+ return false;
159
+ return {
160
+ user: { id: { equals: userId } },
161
+ };
162
+ },
163
+ create: () => true,
164
+ update: () => false,
165
+ delete: ({ session, item }) => {
166
+ if (!session)
167
+ return false;
168
+ const userId = session.userId;
169
+ const itemUserId = item?.user?.id;
170
+ return userId === itemUserId;
171
+ },
172
+ },
173
+ },
174
+ });
175
+ }
176
+ /**
177
+ * Create the Auth account list.
178
+ */
179
+ function createAccountList(model, keys) {
180
+ const f = model.fields;
181
+ return list({
182
+ fields: {
183
+ accountId: text({ validation: { isRequired: true }, db: fieldDb('accountId', f) }),
184
+ providerId: text({ validation: { isRequired: true }, db: fieldDb('providerId', f) }),
185
+ user: relationship({
186
+ ref: `${keys.user}.accounts`,
187
+ db: userForeignKeyDb(f),
188
+ }),
189
+ accessToken: text({ db: fieldDb('accessToken', f) }),
190
+ refreshToken: text({ db: fieldDb('refreshToken', f) }),
191
+ accessTokenExpiresAt: timestamp({ db: fieldDb('accessTokenExpiresAt', f) }),
192
+ refreshTokenExpiresAt: timestamp({ db: fieldDb('refreshTokenExpiresAt', f) }),
193
+ scope: text({ db: fieldDb('scope', f) }),
194
+ idToken: text({ db: fieldDb('idToken', f) }),
195
+ password: text({ db: fieldDb('password', f) }),
196
+ },
197
+ db: listDb(model, DEFAULT_MODEL_NAMES.account),
198
+ access: {
199
+ operation: {
200
+ query: ({ session }) => {
201
+ if (!session)
202
+ return false;
203
+ const userId = session.userId;
204
+ if (!userId)
205
+ return false;
206
+ return {
207
+ user: { id: { equals: userId } },
208
+ };
209
+ },
210
+ create: () => true,
211
+ update: ({ session, item }) => {
212
+ if (!session)
213
+ return false;
214
+ const userId = session.userId;
215
+ const itemUserId = item?.user?.id;
216
+ return userId === itemUserId;
217
+ },
218
+ delete: ({ session, item }) => {
219
+ if (!session)
220
+ return false;
221
+ const userId = session.userId;
222
+ const itemUserId = item?.user?.id;
223
+ return userId === itemUserId;
224
+ },
225
+ },
226
+ },
227
+ });
228
+ }
229
+ /**
230
+ * Create the Auth verification list.
231
+ */
232
+ function createVerificationList(model) {
233
+ const f = model.fields;
234
+ return list({
235
+ fields: {
236
+ identifier: text({ validation: { isRequired: true }, db: fieldDb('identifier', f) }),
237
+ value: text({ validation: { isRequired: true }, db: fieldDb('value', f) }),
238
+ expiresAt: timestamp({ db: fieldDb('expiresAt', f) }),
239
+ },
240
+ db: listDb(model, DEFAULT_MODEL_NAMES.verification),
241
+ access: {
242
+ operation: {
243
+ query: () => false,
244
+ create: () => true,
245
+ update: () => false,
246
+ delete: () => true,
247
+ },
248
+ },
249
+ });
250
+ }
251
+ /**
252
+ * Derive the OpenSaaS Auth lists from the resolved better-auth model config.
253
+ *
254
+ * @param models - Resolved better-auth per-model config (modelName + field column maps)
255
+ * @param userConfig - Extra User-list fields/access/hooks supplied via `extendUserList`
256
+ * @returns The derived list keys and the four Auth list configs keyed by those keys
257
+ */
258
+ export function deriveAuthLists(models, userConfig = {}) {
259
+ const keys = {
260
+ user: models.user.modelName,
261
+ session: models.session.modelName,
262
+ account: models.account.modelName,
263
+ verification: models.verification.modelName,
264
+ };
265
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ListConfig must accept any TypeInfo
266
+ const lists = {
267
+ [keys.user]: createUserList(models.user, keys, userConfig),
268
+ [keys.session]: createSessionList(models.session, keys),
269
+ [keys.account]: createAccountList(models.account, keys),
270
+ [keys.verification]: createVerificationList(models.verification),
271
+ };
272
+ return { keys, lists };
273
+ }
274
+ //# sourceMappingURL=derive-auth-lists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive-auth-lists.js","sourceRoot":"","sources":["../../src/config/derive-auth-lists.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EAIrB,MAAM,YAAY,CAAA;AAEnB;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,oBAAoB,CAyD5E;AAED,YAAY,EAAE,UAAU,EAAE,oBAAoB,EAAE,CAAA;AAChD,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EAEV,oBAAoB,EAMrB,MAAM,YAAY,CAAA;AAmDnB;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,oBAAoB,CA+D5E;AAED,YAAY,EAAE,UAAU,EAAE,oBAAoB,EAAE,CAAA;AAChD,cAAc,YAAY,CAAA"}
@@ -1,3 +1,41 @@
1
+ /**
2
+ * Default better-auth model names. Used when the developer does not override
3
+ * `modelName`, preserving the historical `User`/`Session`/`Account`/`Verification`
4
+ * keys exactly.
5
+ */
6
+ const DEFAULT_MODEL_NAMES = {
7
+ user: 'User',
8
+ session: 'Session',
9
+ account: 'Account',
10
+ verification: 'Verification',
11
+ };
12
+ /**
13
+ * Resolve a single better-auth model config block into its normalized form,
14
+ * falling back to the better-auth default model name and an empty column map.
15
+ * The model's Postgres schema is the per-model `schema` override when present,
16
+ * otherwise the plugin-level `schema` default (or `undefined` for `public`).
17
+ */
18
+ function normalizeModelConfig(config, defaultModelName, defaultSchema) {
19
+ return {
20
+ modelName: config?.modelName || defaultModelName,
21
+ fields: config?.fields || {},
22
+ schema: config?.schema ?? defaultSchema,
23
+ };
24
+ }
25
+ /**
26
+ * Resolve the better-auth model config for all four auth models.
27
+ * `defaultSchema` is the plugin-level `schema` applied to every model unless a
28
+ * per-model `schema` override is given.
29
+ */
30
+ function normalizeAuthModels(config) {
31
+ const defaultSchema = config.schema;
32
+ return {
33
+ user: normalizeModelConfig(config.user, DEFAULT_MODEL_NAMES.user, defaultSchema),
34
+ session: normalizeModelConfig(config.session, DEFAULT_MODEL_NAMES.session, defaultSchema),
35
+ account: normalizeModelConfig(config.account, DEFAULT_MODEL_NAMES.account, defaultSchema),
36
+ verification: normalizeModelConfig(config.verification, DEFAULT_MODEL_NAMES.verification, defaultSchema),
37
+ };
38
+ }
1
39
  /**
2
40
  * Normalize auth configuration with defaults
3
41
  */
@@ -32,12 +70,17 @@ export function normalizeAuthConfig(config) {
32
70
  };
33
71
  // Session fields defaults
34
72
  const sessionFields = config.sessionFields || ['userId', 'email', 'name'];
73
+ // Resolve better-auth per-model config (modelName + field column maps).
74
+ // Defaults preserve the historical User/Session/Account/Verification keys.
75
+ const models = normalizeAuthModels(config);
35
76
  return {
36
77
  emailAndPassword,
37
78
  emailVerification,
38
79
  passwordReset,
39
80
  socialProviders: config.socialProviders || {},
40
81
  session,
82
+ models,
83
+ schema: config.schema,
41
84
  sessionFields,
42
85
  extendUserList: config.extendUserList || {},
43
86
  sendEmail: config.sendEmail ||
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAkB;IACpD,8BAA8B;IAC9B,MAAM,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,EAAE,OAAO;QACvD,CAAC,CAAC;YACE,OAAO,EAAE,IAAa;YACtB,iBAAiB,EAAG,MAAM,CAAC,gBAAwC,CAAC,iBAAiB,IAAI,CAAC;YAC1F,mBAAmB,EAChB,MAAM,CAAC,gBAAwC,CAAC,mBAAmB,IAAI,IAAI;SAC/E;QACH,CAAC,CAAC,EAAE,OAAO,EAAE,KAAc,EAAE,iBAAiB,EAAE,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAA;IAEhF,8BAA8B;IAC9B,MAAM,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,EAAE,OAAO;QACzD,CAAC,CAAC;YACE,OAAO,EAAE,IAAa;YACtB,YAAY,EAAG,MAAM,CAAC,iBAA6C,CAAC,YAAY,IAAI,IAAI;YACxF,eAAe,EACZ,MAAM,CAAC,iBAA6C,CAAC,eAAe,IAAI,KAAK;SACjF;QACH,CAAC,CAAC,EAAE,OAAO,EAAE,KAAc,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,CAAA;IAE3E,0BAA0B;IAC1B,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,EAAE,OAAO;QACjD,CAAC,CAAC;YACE,OAAO,EAAE,IAAa;YACtB,eAAe,EAAG,MAAM,CAAC,aAAqC,CAAC,eAAe,IAAI,IAAI;SACvF;QACH,CAAC,CAAC,EAAE,OAAO,EAAE,KAAc,EAAE,eAAe,EAAE,IAAI,EAAE,CAAA;IAEtD,mBAAmB;IACnB,MAAM,OAAO,GAAG;QACd,SAAS,EAAE,MAAM,CAAC,OAAO,EAAE,SAAS,IAAI,MAAM,EAAE,SAAS;QACzD,SAAS,EAAE,MAAM,CAAC,OAAO,EAAE,SAAS,IAAI,IAAI;KAC7C,CAAA;IAED,0BAA0B;IAC1B,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;IAEzE,OAAO;QACL,gBAAgB;QAChB,iBAAiB;QACjB,aAAa;QACb,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,EAAE;QAC7C,OAAO;QACP,aAAa;QACb,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,EAAE;QAC3C,SAAS,EACP,MAAM,CAAC,SAAS;YAChB,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;gBAC/B,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAA;gBAC/D,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;gBACxB,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,EAAE,CAAC,CAAA;gBAClC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAA;YAC9B,CAAC,CAAC;QACJ,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,EAAE;QACjD,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAA;AACH,CAAC;AAGD,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/config/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAA;AACzD,OAAO,KAAK,EAAE,UAAU,EAAwB,MAAM,YAAY,CAAA;AAKlE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA6FrD"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/config/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAA;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAwB,MAAM,YAAY,CAAA;AAKlE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAqJrD"}
@@ -1,3 +1,4 @@
1
+ import { getDbKey } from '@opensaas/stack-core';
1
2
  import { normalizeAuthConfig } from './index.js';
2
3
  import { getAuthLists } from '../lists/index.js';
3
4
  import { convertBetterAuthSchema } from '../server/schema-converter.js';
@@ -32,8 +33,12 @@ export function authPlugin(config) {
32
33
  typeName: 'AuthRuntimeServices',
33
34
  },
34
35
  init: async (context) => {
35
- // Get auth lists from base Better Auth schema
36
- const authLists = getAuthLists(normalized.extendUserList);
36
+ // Derive the auth lists from the better-auth model config (modelName +
37
+ // field column maps). With no overrides this yields the historical
38
+ // User/Session/Account/Verification keys; with overrides (e.g.
39
+ // user.modelName: 'AuthUser') the lists are keyed and column-mapped to
40
+ // match the developer's live better-auth tables.
41
+ const authLists = getAuthLists(normalized.extendUserList, normalized.models);
37
42
  // Extract additional lists from Better Auth plugins
38
43
  for (const plugin of normalized.betterAuthPlugins) {
39
44
  if (plugin && typeof plugin === 'object' && 'schema' in plugin) {
@@ -58,10 +63,18 @@ export function authPlugin(config) {
58
63
  }
59
64
  }
60
65
  }
61
- // Add all auth lists
66
+ // Add all auth lists.
67
+ //
68
+ // The plugin only ever touches its OWN derived keys. When a developer
69
+ // renames the auth user model (e.g. user.modelName: 'AuthUser'), the
70
+ // derived key is 'AuthUser' and an app's separate 'User' list is left
71
+ // untouched — the plugin never extends/overwrites a list it didn't
72
+ // derive. Extending only kicks in when an existing list shares the
73
+ // derived key (e.g. the default 'User'), which is the intended
74
+ // "merge auth fields into my User" behaviour.
62
75
  for (const [listName, listConfig] of Object.entries(authLists)) {
63
76
  if (context.config.lists[listName]) {
64
- // If user defined a User list, extend it with auth fields
77
+ // A list already exists under this derived key merge auth fields in.
65
78
  context.extendList(listName, {
66
79
  fields: listConfig.fields,
67
80
  hooks: listConfig.hooks,
@@ -78,7 +91,40 @@ export function authPlugin(config) {
78
91
  // Access at runtime via: config._pluginData.auth
79
92
  context.setPluginData('auth', normalized);
80
93
  },
94
+ beforeGenerate: (generationConfig) => {
95
+ // Collect every schema the Auth lists are placed in (per-model schema,
96
+ // else the plugin-level schema). When none is configured the Auth lists
97
+ // stay in the default `public` schema and we leave the config untouched —
98
+ // the greenfield default Prisma schema is unchanged (no `schemas`, no
99
+ // `previewFeatures`, no `@@schema`).
100
+ const authSchemas = Array.from(new Set(Object.values(normalized.models)
101
+ .map((model) => model.schema)
102
+ .filter((schema) => Boolean(schema))));
103
+ if (authSchemas.length === 0) {
104
+ return generationConfig;
105
+ }
106
+ // Multi-schema Prisma requires the datasource to list every schema in use
107
+ // AND every model to carry an `@@schema`. Merge the auth schema(s) into the
108
+ // datasource `schemas` array (always including `public` for the app's own
109
+ // lists), and default any list without an explicit `db.schema` to `public`
110
+ // so the generated multi-schema schema is coherent and valid.
111
+ const schemas = Array.from(new Set(['public', ...(generationConfig.db.schemas ?? []), ...authSchemas]));
112
+ const lists = Object.fromEntries(Object.entries(generationConfig.lists).map(([listKey, listConfig]) => {
113
+ if (listConfig.db?.schema) {
114
+ return [listKey, listConfig];
115
+ }
116
+ return [listKey, { ...listConfig, db: { ...listConfig.db, schema: 'public' } }];
117
+ }));
118
+ return {
119
+ ...generationConfig,
120
+ db: { ...generationConfig.db, schemas },
121
+ lists,
122
+ };
123
+ },
81
124
  runtime: (context) => {
125
+ // Resolve the user list's context.db key from the configured user model.
126
+ // context.db is keyed camelCase, so 'User' -> 'user', 'AuthUser' -> 'authUser'.
127
+ const userDbKey = getDbKey(normalized.models.user.modelName);
82
128
  // Provide auth-related utilities at runtime
83
129
  return {
84
130
  /**
@@ -86,9 +132,7 @@ export function authPlugin(config) {
86
132
  * Uses the access-controlled context to fetch user data
87
133
  */
88
134
  getUser: async (userId) => {
89
- // Use 'authUser' if custom User list name was provided, otherwise 'user'
90
- const userListKey = 'user'; // TODO: Make this configurable based on list name
91
- return await context.db[userListKey].findUnique({
135
+ return await context.db[userDbKey].findUnique({
92
136
  where: { id: userId },
93
137
  });
94
138
  },
@@ -100,8 +144,7 @@ export function authPlugin(config) {
100
144
  if (!context.session?.userId) {
101
145
  return null;
102
146
  }
103
- const userListKey = 'user';
104
- return await context.db[userListKey].findUnique({
147
+ return await context.db[userDbKey].findUnique({
105
148
  where: { id: context.session.userId },
106
149
  });
107
150
  },
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/config/plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/config/plugin.ts"],"names":[],"mappings":"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"}
@@ -75,6 +75,54 @@ export type SessionConfig = {
75
75
  */
76
76
  updateAge?: boolean;
77
77
  };
78
+ /**
79
+ * Per-model better-auth configuration block.
80
+ *
81
+ * Mirrors better-auth's own `BetterAuthDBOptions` (the `user`/`session`/
82
+ * `account`/`verification` config a developer already writes): `modelName`
83
+ * renames the table/list and `fields` maps individual better-auth field names
84
+ * to database column names. The auth plugin derives its Auth lists from this
85
+ * config so the generated lists carry the same keys and column maps as the
86
+ * developer's live better-auth tables.
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * authPlugin({
91
+ * user: { modelName: 'AuthUser', fields: { name: 'full_name' } },
92
+ * session: { modelName: 'AuthSession' },
93
+ * })
94
+ * ```
95
+ */
96
+ export type AuthModelConfig = {
97
+ /**
98
+ * The table/list name for this model.
99
+ * Becomes the OpenSaaS list key (and Prisma model name) and the table `@@map`.
100
+ * @default the default better-auth model name (e.g. 'User', 'Session')
101
+ */
102
+ modelName?: string;
103
+ /**
104
+ * Map better-auth field names to database column names.
105
+ * Each entry generates a `@map("column")` on the derived field.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * fields: { name: 'full_name', emailVerified: 'email_verified' }
110
+ * ```
111
+ */
112
+ fields?: Record<string, string>;
113
+ /**
114
+ * Database schema (Postgres) for this auth model.
115
+ * Generates a `@@schema("...")` on the derived list, overriding the
116
+ * plugin-level {@link AuthConfig.schema} for this one model.
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * // Place the verification table in a different schema from the rest
121
+ * verification: { schema: 'auth_internal' }
122
+ * ```
123
+ */
124
+ schema?: string;
125
+ };
78
126
  /**
79
127
  * Auth configuration options
80
128
  */
@@ -102,9 +150,56 @@ export type AuthConfig = {
102
150
  */
103
151
  socialProviders?: SocialProvidersConfig;
104
152
  /**
105
- * Session configuration
153
+ * Session configuration.
154
+ *
155
+ * Carries session expiry settings as well as the better-auth `session` model
156
+ * config (`modelName` + field column `fields` maps) used to derive the Auth
157
+ * session list.
158
+ */
159
+ session?: SessionConfig & AuthModelConfig;
160
+ /**
161
+ * better-auth `user` model configuration (modelName + field column maps).
162
+ * Used to derive the Auth user list's key, table `@@map`, and field `@map`s.
163
+ *
164
+ * Custom fields beyond the better-auth basics are added via `extendUserList`.
106
165
  */
107
- session?: SessionConfig;
166
+ user?: AuthModelConfig;
167
+ /**
168
+ * better-auth `account` model configuration (modelName + field column maps).
169
+ */
170
+ account?: AuthModelConfig;
171
+ /**
172
+ * better-auth `verification` model configuration (modelName + field column maps).
173
+ */
174
+ verification?: AuthModelConfig;
175
+ /**
176
+ * Database schema (Postgres) for the generated Auth lists.
177
+ *
178
+ * When set, all four Auth lists (user/session/account/verification) are placed
179
+ * in this schema via `@@schema(...)`, and the stack's multi-schema support is
180
+ * wired automatically: the datasource `schemas` array gains this schema (plus
181
+ * `public`) and the `multiSchema` preview feature is enabled. A per-model
182
+ * {@link AuthModelConfig.schema} overrides this for an individual list.
183
+ *
184
+ * Useful for adopting an existing separate-schema better-auth installation
185
+ * (e.g. an `auth` Postgres schema) so the generated lists diff clean against
186
+ * the live tables. When unset, the Auth lists stay in the default `public`
187
+ * schema and no `@@schema` is emitted (greenfield default unchanged).
188
+ *
189
+ * Only applies to the `postgresql` provider.
190
+ *
191
+ * @example Adopt an `auth`-schema better-auth install
192
+ * ```typescript
193
+ * authPlugin({
194
+ * schema: 'auth',
195
+ * user: { modelName: 'AuthUser' },
196
+ * session: { modelName: 'AuthSession' },
197
+ * account: { modelName: 'AuthAccount' },
198
+ * verification: { modelName: 'AuthVerification' },
199
+ * })
200
+ * ```
201
+ */
202
+ schema?: string;
108
203
  /**
109
204
  * Which fields to include in the session object
110
205
  * This determines what data is available in access control functions
@@ -194,14 +289,46 @@ export type AuthConfig = {
194
289
  max?: number;
195
290
  };
196
291
  };
292
+ /**
293
+ * Resolved per-model auth configuration after normalization.
294
+ * Always carries a concrete `modelName` (the developer's override or the
295
+ * better-auth default) and a (possibly empty) `fields` column map. `schema`
296
+ * carries the resolved Postgres schema for the model (per-model override, else
297
+ * the plugin-level schema, else `undefined` for the default `public` schema).
298
+ */
299
+ export type NormalizedAuthModelConfig = {
300
+ modelName: string;
301
+ fields: Record<string, string>;
302
+ schema?: string;
303
+ };
304
+ /**
305
+ * Resolved auth model configuration for all four better-auth models.
306
+ * Consumed by the Auth-list derivation and the runtime user-key resolution.
307
+ */
308
+ export type NormalizedAuthModels = {
309
+ user: NormalizedAuthModelConfig;
310
+ session: NormalizedAuthModelConfig;
311
+ account: NormalizedAuthModelConfig;
312
+ verification: NormalizedAuthModelConfig;
313
+ };
197
314
  /**
198
315
  * Internal normalized auth configuration
199
316
  * Used after parsing user config
200
317
  */
201
- export type NormalizedAuthConfig = Required<Omit<AuthConfig, 'emailAndPassword' | 'emailVerification' | 'passwordReset' | 'betterAuthPlugins' | 'rateLimit'>> & {
318
+ export type NormalizedAuthConfig = Required<Omit<AuthConfig, 'emailAndPassword' | 'emailVerification' | 'passwordReset' | 'betterAuthPlugins' | 'rateLimit' | 'session' | 'user' | 'account' | 'verification' | 'schema'>> & {
202
319
  emailAndPassword: Required<EmailPasswordConfig>;
203
320
  emailVerification: Required<EmailVerificationConfig>;
204
321
  passwordReset: Required<PasswordResetConfig>;
322
+ /** Resolved session expiry settings (model config lives under `models.session`). */
323
+ session: Required<SessionConfig>;
324
+ /** Resolved better-auth model config (modelName + field column maps + schema) for all auth models. */
325
+ models: NormalizedAuthModels;
326
+ /**
327
+ * Plugin-level Postgres schema for the Auth lists, if any. Resolved per-model
328
+ * schemas live on `models.<model>.schema`; this is the unresolved plugin-level
329
+ * default (used to wire the datasource `schemas` array during generation).
330
+ */
331
+ schema?: string;
205
332
  betterAuthPlugins: any[];
206
333
  rateLimit?: {
207
334
  enabled: boolean;