@opensaas/stack-auth 0.30.0 → 0.31.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 +6 -0
- package/package.json +3 -2
- package/tests/generated-fk-shape.test.ts +81 -0
- package/tsconfig.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @opensaas/stack-auth
|
|
2
2
|
|
|
3
|
+
## 0.31.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#772](https://github.com/OpenSaasAU/stack/pull/772) [`be5772b`](https://github.com/OpenSaasAU/stack/commit/be5772be231d5be6a77d80c4f7eff5adc15da2fa) Thanks [@borisno2](https://github.com/borisno2)! - Add a regression test locking the generated Session/Account user FK shape (no `@@index([userId])`, `onDelete: Cascade`) so future drift from better-auth parity is caught.
|
|
8
|
+
|
|
3
9
|
## 0.30.0
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opensaas/stack-auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"description": "Better-auth integration for OpenSaas Stack",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -65,7 +65,8 @@
|
|
|
65
65
|
"react": "^19.2.4",
|
|
66
66
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
67
67
|
"vitest": "^4.1.10",
|
|
68
|
-
"@opensaas/stack-
|
|
68
|
+
"@opensaas/stack-cli": "0.31.0",
|
|
69
|
+
"@opensaas/stack-core": "0.31.0"
|
|
69
70
|
},
|
|
70
71
|
"scripts": {
|
|
71
72
|
"build": "tsc",
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { config, list } from '@opensaas/stack-core'
|
|
3
|
+
import { text, relationship } from '@opensaas/stack-core/fields'
|
|
4
|
+
import type { OpenSaasConfig } from '@opensaas/stack-core'
|
|
5
|
+
import type { Plugin } from '@opensaas/stack-core/extend'
|
|
6
|
+
import { generatePrismaSchema } from '@opensaas/stack-cli/generator/prisma'
|
|
7
|
+
import { authPlugin } from '../src/config/plugin.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Resolve a config through plugin `init` (via `config()`) and each plugin's
|
|
11
|
+
* `beforeGenerate` hook — the same sequence the CLI generate pipeline runs —
|
|
12
|
+
* then hand the result to the Prisma generator. Unlike the config-level
|
|
13
|
+
* assertions in `derive-auth-lists.test.ts` and `plugin-schema-placement.test.ts`,
|
|
14
|
+
* this exercises the *assembled generated schema text* so the auth FK shape is
|
|
15
|
+
* locked end-to-end (issue #753).
|
|
16
|
+
*/
|
|
17
|
+
async function generateSchema(userConfig: OpenSaasConfig): Promise<string> {
|
|
18
|
+
let current = await config(userConfig)
|
|
19
|
+
const plugins: Plugin[] = current.plugins ?? []
|
|
20
|
+
for (const plugin of plugins) {
|
|
21
|
+
if (plugin.beforeGenerate) {
|
|
22
|
+
current = await plugin.beforeGenerate(current)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return generatePrismaSchema(current)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Slice out a single `model X { ... }` block from generated schema text. */
|
|
29
|
+
function modelBlock(schema: string, modelName: string): string {
|
|
30
|
+
const start = schema.indexOf(`model ${modelName} {`)
|
|
31
|
+
if (start === -1) throw new Error(`model ${modelName} not found in generated schema`)
|
|
32
|
+
const end = schema.indexOf('\n}', start)
|
|
33
|
+
return schema.slice(start, end === -1 ? undefined : end + 2)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe('generated auth schema — Session/Account user FK mirrors better-auth (issue #679/#753)', () => {
|
|
37
|
+
it('emits onDelete: Cascade and omits @@index on Session.user and Account.user', async () => {
|
|
38
|
+
const schema = await generateSchema({
|
|
39
|
+
db: { provider: 'sqlite' },
|
|
40
|
+
plugins: [authPlugin({ emailAndPassword: { enabled: true } })],
|
|
41
|
+
lists: {},
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
for (const model of ['Session', 'Account']) {
|
|
45
|
+
const block = modelBlock(schema, model)
|
|
46
|
+
|
|
47
|
+
// (a) The user relation carries the cascade referential action. Match on
|
|
48
|
+
// the whitespace-stable attribute substring rather than the padded line,
|
|
49
|
+
// since raw generator output and prisma-formatted output differ only in
|
|
50
|
+
// column alignment.
|
|
51
|
+
expect(block).toContain('@relation(onDelete: Cascade, fields: [userId], references: [id])')
|
|
52
|
+
|
|
53
|
+
// (b) No separate FK index is emitted — parity with better-auth, which
|
|
54
|
+
// ships no @@index([userId]). This is deliberate (ADR-0007), not a
|
|
55
|
+
// regression; catching a re-introduced index here flags drift.
|
|
56
|
+
expect(block).not.toContain('@@index([userId])')
|
|
57
|
+
expect(block).not.toContain('@@index([user])')
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('still emits the default @@index for a non-auth relationship FK', async () => {
|
|
62
|
+
// Contrast case: the generic FK-index path is untouched. Only the auth
|
|
63
|
+
// user relations opt out (via isIndexed: false); an ordinary app
|
|
64
|
+
// relationship keeps the default Keystone-parity @@index.
|
|
65
|
+
const schema = await generateSchema({
|
|
66
|
+
db: { provider: 'sqlite' },
|
|
67
|
+
plugins: [authPlugin({ emailAndPassword: { enabled: true } })],
|
|
68
|
+
lists: {
|
|
69
|
+
Widget: list({
|
|
70
|
+
fields: {
|
|
71
|
+
title: text({ validation: { isRequired: true } }),
|
|
72
|
+
owner: relationship({ ref: 'User' }),
|
|
73
|
+
},
|
|
74
|
+
}),
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
const widget = modelBlock(schema, 'Widget')
|
|
79
|
+
expect(widget).toContain('@@index([ownerId])')
|
|
80
|
+
})
|
|
81
|
+
})
|