@opensaas/stack-auth 0.29.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 +14 -0
- package/README.md +1 -1
- package/dist/mcp/better-auth.d.ts +2 -3
- package/dist/mcp/better-auth.d.ts.map +1 -1
- package/dist/mcp/better-auth.js +2 -3
- package/dist/mcp/better-auth.js.map +1 -1
- package/package.json +3 -2
- package/src/mcp/better-auth.ts +2 -3
- 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,19 @@
|
|
|
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
|
+
|
|
9
|
+
## 0.30.0
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#741](https://github.com/OpenSaasAU/stack/pull/741) [`afa865f`](https://github.com/OpenSaasAU/stack/commit/afa865f62ed7968b494a87e0621cf71bacd36f39) Thanks [@borisno2](https://github.com/borisno2)! - Update documentation links to the restructured docs site URLs (Diátaxis layout)
|
|
14
|
+
|
|
15
|
+
- [#744](https://github.com/OpenSaasAU/stack/pull/744) [`5e135ef`](https://github.com/OpenSaasAU/stack/commit/5e135ef635dd7cd97ab106f46fbf808250aa079e) Thanks [@borisno2](https://github.com/borisno2)! - Fix stale `withMcpAuth` JSDoc example that imported a nonexistent generated module
|
|
16
|
+
|
|
3
17
|
## 0.29.0
|
|
4
18
|
|
|
5
19
|
## 0.28.0
|
package/README.md
CHANGED
|
@@ -233,7 +233,7 @@ better-auth user, e.g. `AuthUser`). It does not assume that list is your app's
|
|
|
233
233
|
own domain `User` — when the keys differ, your `User` is never extended or
|
|
234
234
|
overwritten. **Linking your domain `User` to the Auth identity is your app's
|
|
235
235
|
concern** (declare a `relationship({ ref: 'AuthUser' })` on your `User`). See the
|
|
236
|
-
[Authentication guide](https://stack.opensaas.au/docs/
|
|
236
|
+
[Authentication guide](https://stack.opensaas.au/docs/how-to/authentication) for
|
|
237
237
|
the full migrator walkthrough and a Schema-parity (clean-diff) check.
|
|
238
238
|
|
|
239
239
|
## UI Components
|
|
@@ -41,11 +41,10 @@ export declare function createBetterAuthMcpAdapter(auth: BetterAuthInstance): Mc
|
|
|
41
41
|
* ```typescript
|
|
42
42
|
* import { withMcpAuth } from '@opensaas/stack-auth/mcp'
|
|
43
43
|
* import { auth } from '@/lib/auth'
|
|
44
|
-
* import { createMcpServer } from '@/.opensaas/mcp/server'
|
|
45
44
|
*
|
|
46
45
|
* const handler = withMcpAuth(auth, async (req, session) => {
|
|
47
|
-
*
|
|
48
|
-
* return
|
|
46
|
+
* // session.userId is authenticated — handle the MCP request
|
|
47
|
+
* return new Response(JSON.stringify({ ok: true }))
|
|
49
48
|
* })
|
|
50
49
|
*
|
|
51
50
|
* export { handler as GET, handler as POST, handler as DELETE }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"better-auth.d.ts","sourceRoot":"","sources":["../../src/mcp/better-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAE9E;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAE/B,GAAG,EAAE,GAAG,CAAA;IAER,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,kBAAkB,GAAG,kBAAkB,CAIvF;AAED
|
|
1
|
+
{"version":3,"file":"better-auth.d.ts","sourceRoot":"","sources":["../../src/mcp/better-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAE9E;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAE/B,GAAG,EAAE,GAAG,CAAA;IAER,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,kBAAkB,GAAG,kBAAkB,CAIvF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,GAC3E,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAoBrC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,UAAU,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAIrF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,CAGhF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAG7D;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,kBAAkB,SAChD,OAAO,uBAS3B;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CAAC,KAAK,EAAE,kBAAkB,SACxD,OAAO,uBAS3B"}
|
package/dist/mcp/better-auth.js
CHANGED
|
@@ -36,11 +36,10 @@ export function createBetterAuthMcpAdapter(auth) {
|
|
|
36
36
|
* ```typescript
|
|
37
37
|
* import { withMcpAuth } from '@opensaas/stack-auth/mcp'
|
|
38
38
|
* import { auth } from '@/lib/auth'
|
|
39
|
-
* import { createMcpServer } from '@/.opensaas/mcp/server'
|
|
40
39
|
*
|
|
41
40
|
* const handler = withMcpAuth(auth, async (req, session) => {
|
|
42
|
-
*
|
|
43
|
-
* return
|
|
41
|
+
* // session.userId is authenticated — handle the MCP request
|
|
42
|
+
* return new Response(JSON.stringify({ ok: true }))
|
|
44
43
|
* })
|
|
45
44
|
*
|
|
46
45
|
* export { handler as GET, handler as POST, handler as DELETE }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"better-auth.js","sourceRoot":"","sources":["../../src/mcp/better-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAAwB;IACjE,OAAO,KAAK,EAAE,OAAgB,EAA8B,EAAE;QAC5D,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC,CAAA;IAClD,CAAC,CAAA;AACH,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"better-auth.js","sourceRoot":"","sources":["../../src/mcp/better-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAAwB;IACjE,OAAO,KAAK,EAAE,OAAgB,EAA8B,EAAE;QAC5D,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC,CAAA;IAClD,CAAC,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,WAAW,CACzB,IAAwB,EACxB,OAA4E;IAE5E,OAAO,KAAK,EAAE,GAAY,EAAE,EAAE;QAC5B,uCAAuC;QACvC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC;YAC3C,OAAO,EAAE,GAAG,CAAC,OAAO;SACrB,CAAC,CAAA;QAEF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,4DAA4D;YAC5D,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;gBACxB,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE;oBACP,kBAAkB,EAAE,2CAA2C;iBAChE;aACF,CAAC,CAAA;QACJ,CAAC;QAED,0CAA0C;QAC1C,OAAO,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IAC9B,CAAC,CAAA;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,0BAA0B,CAAC,UAAsB;IAC/D,OAAO;QACL,MAAM,EAAE,UAAU,CAAC,MAAM;KAC1B,CAAA;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,SAAS,CAAC,OAAmB,EAAE,cAAwB;IACrE,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IACjC,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,MAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;AACzE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAmB;IAClD,IAAI,CAAC,OAAO,CAAC,SAAS;QAAE,OAAO,KAAK,CAAA;IACpC,OAAO,IAAI,IAAI,EAAE,GAAG,OAAO,CAAC,SAAS,CAAA;AACvC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CAAC,KAAyB;IACnE,OAAO,KAAK,EAAE,GAAY,EAAE,EAAE;QAC5B,6CAA6C;QAC7C,MAAM,QAAQ,GAAG,kDAAkD,CAAA;QACnE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,CAAA;QAE1C,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE;YAC/B,OAAO,EAAE,GAAG,CAAC,OAAO;SACrB,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mCAAmC,CAAC,KAAyB;IAC3E,OAAO,KAAK,EAAE,GAAY,EAAE,EAAE;QAC5B,6CAA6C;QAC7C,MAAM,QAAQ,GAAG,gDAAgD,CAAA;QACjE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,CAAA;QAE1C,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE;YAC/B,OAAO,EAAE,GAAG,CAAC,OAAO;SACrB,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC"}
|
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",
|
package/src/mcp/better-auth.ts
CHANGED
|
@@ -51,11 +51,10 @@ export function createBetterAuthMcpAdapter(auth: BetterAuthInstance): McpSession
|
|
|
51
51
|
* ```typescript
|
|
52
52
|
* import { withMcpAuth } from '@opensaas/stack-auth/mcp'
|
|
53
53
|
* import { auth } from '@/lib/auth'
|
|
54
|
-
* import { createMcpServer } from '@/.opensaas/mcp/server'
|
|
55
54
|
*
|
|
56
55
|
* const handler = withMcpAuth(auth, async (req, session) => {
|
|
57
|
-
*
|
|
58
|
-
* return
|
|
56
|
+
* // session.userId is authenticated — handle the MCP request
|
|
57
|
+
* return new Response(JSON.stringify({ ok: true }))
|
|
59
58
|
* })
|
|
60
59
|
*
|
|
61
60
|
* export { handler as GET, handler as POST, handler as DELETE }
|
|
@@ -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
|
+
})
|