@opensaas/stack-auth 0.20.1 → 0.22.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 +122 -0
- package/CLAUDE.md +115 -17
- package/INTEGRATION_SUMMARY.md +21 -20
- package/README.md +82 -48
- package/dist/config/adopt-better-auth-tables.d.ts +107 -0
- package/dist/config/adopt-better-auth-tables.d.ts.map +1 -0
- package/dist/config/adopt-better-auth-tables.js +70 -0
- package/dist/config/adopt-better-auth-tables.js.map +1 -0
- package/dist/config/derive-auth-lists.d.ts +50 -0
- package/dist/config/derive-auth-lists.d.ts.map +1 -0
- package/dist/config/derive-auth-lists.js +274 -0
- package/dist/config/derive-auth-lists.js.map +1 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +43 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/plugin.d.ts +1 -1
- package/dist/config/plugin.d.ts.map +1 -1
- package/dist/config/plugin.js +52 -9
- package/dist/config/plugin.js.map +1 -1
- package/dist/config/types.d.ts +130 -3
- package/dist/config/types.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/lists/index.d.ts +17 -11
- package/dist/lists/index.d.ts.map +1 -1
- package/dist/lists/index.js +34 -208
- package/dist/lists/index.js.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +28 -7
- package/dist/server/index.js.map +1 -1
- package/dist/server/schema-converter.d.ts +1 -1
- package/dist/server/schema-converter.js +1 -1
- package/package.json +3 -3
- package/src/config/adopt-better-auth-tables.ts +146 -0
- package/src/config/derive-auth-lists.ts +323 -0
- package/src/config/index.ts +58 -0
- package/src/config/plugin.ts +67 -10
- package/src/config/types.ts +146 -3
- package/src/index.ts +13 -0
- package/src/lists/index.ts +42 -202
- package/src/server/index.ts +33 -10
- package/src/server/schema-converter.ts +1 -1
- package/tests/adopt-better-auth-tables.test.ts +183 -0
- package/tests/derive-auth-lists.test.ts +232 -0
- package/tests/plugin-derived-keys.test.ts +138 -0
- package/tests/plugin-schema-placement.test.ts +121 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { config, list } from '@opensaas/stack-core'
|
|
3
|
+
import { text } from '@opensaas/stack-core/fields'
|
|
4
|
+
import type { OpenSaasConfig } from '@opensaas/stack-core'
|
|
5
|
+
import type { Plugin } from '@opensaas/stack-core/extend'
|
|
6
|
+
import { authPlugin } from '../src/config/plugin.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Run a config through plugin `init` (via `config()`) and then the auth
|
|
10
|
+
* plugin's `beforeGenerate` hook — mirroring the CLI generate pipeline — to
|
|
11
|
+
* observe the final config the generator would consume.
|
|
12
|
+
*/
|
|
13
|
+
async function generationConfig(userConfig: OpenSaasConfig): Promise<OpenSaasConfig> {
|
|
14
|
+
const resolved = await config(userConfig)
|
|
15
|
+
let current = resolved
|
|
16
|
+
const plugins: Plugin[] = resolved.plugins ?? []
|
|
17
|
+
for (const plugin of plugins) {
|
|
18
|
+
if (plugin.beforeGenerate) {
|
|
19
|
+
current = await plugin.beforeGenerate(current)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return current
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe('authPlugin - schema placement (greenfield default)', () => {
|
|
26
|
+
it('places Auth lists in no schema and leaves the datasource untouched when no schema option is set', async () => {
|
|
27
|
+
const result = await generationConfig({
|
|
28
|
+
db: { provider: 'postgresql' },
|
|
29
|
+
plugins: [authPlugin({})],
|
|
30
|
+
lists: {},
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
// Default keys, no @@schema, no @@map. Auth lists still opt into
|
|
34
|
+
// auto-timestamps (ADR-0004), so db carries only `timestamps: true`.
|
|
35
|
+
expect(result.lists.User.db).toEqual({ timestamps: true })
|
|
36
|
+
expect(result.lists.User.db?.schema).toBeUndefined()
|
|
37
|
+
expect(result.lists.User.db?.map).toBeUndefined()
|
|
38
|
+
expect(result.lists.Session.db?.schema).toBeUndefined()
|
|
39
|
+
expect(result.lists.Account.db?.schema).toBeUndefined()
|
|
40
|
+
expect(result.lists.Verification.db?.schema).toBeUndefined()
|
|
41
|
+
|
|
42
|
+
// Datasource is NOT switched to multi-schema
|
|
43
|
+
expect(result.db.schemas).toBeUndefined()
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
describe('authPlugin - schema placement (adopt existing auth-schema install)', () => {
|
|
48
|
+
it('places all Auth lists in the configured schema with @@schema + @@map and wires the datasource', async () => {
|
|
49
|
+
const result = await generationConfig({
|
|
50
|
+
db: { provider: 'postgresql' },
|
|
51
|
+
plugins: [
|
|
52
|
+
authPlugin({
|
|
53
|
+
schema: 'auth',
|
|
54
|
+
user: { modelName: 'AuthUser' },
|
|
55
|
+
session: { modelName: 'AuthSession' },
|
|
56
|
+
account: { modelName: 'AuthAccount' },
|
|
57
|
+
verification: { modelName: 'AuthVerification' },
|
|
58
|
+
}),
|
|
59
|
+
],
|
|
60
|
+
// The app keeps its own domain User in the default schema
|
|
61
|
+
lists: {
|
|
62
|
+
User: list({
|
|
63
|
+
fields: { subjectId: text({ validation: { isRequired: true } }) },
|
|
64
|
+
}),
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// Auth lists land in the `auth` schema, pinned to their live table names.
|
|
69
|
+
// Auto-timestamps stay enabled (ADR-0004) alongside the @@map + @@schema.
|
|
70
|
+
expect(result.lists.AuthUser.db).toEqual({ timestamps: true, map: 'AuthUser', schema: 'auth' })
|
|
71
|
+
expect(result.lists.AuthSession.db).toEqual({
|
|
72
|
+
timestamps: true,
|
|
73
|
+
map: 'AuthSession',
|
|
74
|
+
schema: 'auth',
|
|
75
|
+
})
|
|
76
|
+
expect(result.lists.AuthAccount.db).toEqual({
|
|
77
|
+
timestamps: true,
|
|
78
|
+
map: 'AuthAccount',
|
|
79
|
+
schema: 'auth',
|
|
80
|
+
})
|
|
81
|
+
expect(result.lists.AuthVerification.db).toEqual({
|
|
82
|
+
timestamps: true,
|
|
83
|
+
map: 'AuthVerification',
|
|
84
|
+
schema: 'auth',
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// The app's own User is left in `public` (not extended/overwritten, not in `auth`)
|
|
88
|
+
expect(result.lists.User.fields).toHaveProperty('subjectId')
|
|
89
|
+
expect(result.lists.User.fields).not.toHaveProperty('email')
|
|
90
|
+
expect(result.lists.User.db?.schema).toBe('public')
|
|
91
|
+
|
|
92
|
+
// Datasource gains both schemas (public always included) so the multi-schema
|
|
93
|
+
// Prisma schema is valid
|
|
94
|
+
expect(result.db.schemas).toEqual(['public', 'auth'])
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('honours a per-list schema override on a single Auth list', async () => {
|
|
98
|
+
const result = await generationConfig({
|
|
99
|
+
db: { provider: 'postgresql' },
|
|
100
|
+
plugins: [
|
|
101
|
+
authPlugin({
|
|
102
|
+
schema: 'auth',
|
|
103
|
+
user: { modelName: 'AuthUser' },
|
|
104
|
+
session: { modelName: 'AuthSession' },
|
|
105
|
+
account: { modelName: 'AuthAccount' },
|
|
106
|
+
// Override: verification lives in a different schema
|
|
107
|
+
verification: { modelName: 'AuthVerification', schema: 'auth_internal' },
|
|
108
|
+
}),
|
|
109
|
+
],
|
|
110
|
+
lists: {},
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
expect(result.lists.AuthUser.db?.schema).toBe('auth')
|
|
114
|
+
expect(result.lists.AuthVerification.db?.schema).toBe('auth_internal')
|
|
115
|
+
|
|
116
|
+
// All used schemas are listed on the datasource (order: public, then discovered)
|
|
117
|
+
expect(result.db.schemas).toContain('public')
|
|
118
|
+
expect(result.db.schemas).toContain('auth')
|
|
119
|
+
expect(result.db.schemas).toContain('auth_internal')
|
|
120
|
+
})
|
|
121
|
+
})
|