@opensaas/stack-auth 0.37.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +37 -0
- package/CLAUDE.md +50 -3
- package/dist/config/plugin.js +1 -1
- package/dist/config/plugin.js.map +1 -1
- package/dist/config/types.d.ts +18 -5
- package/dist/config/types.d.ts.map +1 -1
- package/dist/server/build-better-auth-options.test.d.ts +2 -0
- package/dist/server/build-better-auth-options.test.d.ts.map +1 -0
- package/dist/server/build-better-auth-options.test.js +29 -0
- package/dist/server/build-better-auth-options.test.js.map +1 -0
- package/dist/server/index.d.ts +92 -14
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +123 -62
- package/dist/server/index.js.map +1 -1
- package/dist/server/schema-converter.d.ts +3 -3
- package/dist/server/schema-converter.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/config/plugin.ts +1 -1
- package/src/config/types.ts +18 -7
- package/src/server/build-better-auth-options.test.ts +59 -0
- package/src/server/index.ts +238 -38
- package/src/server/schema-converter.ts +3 -3
- package/tests/server.test.ts +210 -4
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +7 -1
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# @opensaas/stack-auth
|
|
2
2
|
|
|
3
|
+
## 0.38.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#888](https://github.com/OpenSaasAU/stack/pull/888) [`8183827`](https://github.com/OpenSaasAU/stack/commit/8183827ec65d6cfd7153028f84057ab65dfdc7dd) Thanks [@borisno2](https://github.com/borisno2)! - `buildBetterAuthOptions()` and `createAuth()` now accept an optional third argument — your app's `betterAuthPlugins` array, the same array passed to `authPlugin({ betterAuthPlugins })` — so the returned options/`Auth` type carries the literal plugin tuple instead of the widened `BetterAuthOptions`/`Auth<BetterAuthOptions>`. Without this, `betterAuth()` constructed from the widened return loses plugin-derived `auth.api.*` endpoints (e.g. `emailOTP()`'s `signInEmailOTP`) and a `customSession()` plugin's replaced session shape.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
export const appBetterAuthPlugins = [emailOTP({ sendVerificationOTP })] // same array passed to authPlugin({ betterAuthPlugins })
|
|
11
|
+
|
|
12
|
+
export const auth = betterAuth({
|
|
13
|
+
...(await buildBetterAuthOptions(config, rawOpensaasContext, appBetterAuthPlugins)),
|
|
14
|
+
})
|
|
15
|
+
// auth.api.signInEmailOTP is now typed, and auth.api.getSession() returns your customSession() shape.
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The supplied tuple is for typing only — the plugin array used at runtime is always the one resolved from `authPlugin({ betterAuthPlugins })`. Passing a tuple that isn't the same plugin instances in the same order throws, naming the mismatch, so the two can't silently drift apart. Calling either function with no third argument is unchanged — same widened return type, same runtime options, fully backwards compatible.
|
|
19
|
+
|
|
20
|
+
Also, `AuthConfig`/`NormalizedAuthConfig`'s `betterAuthPlugins` field is now typed as better-auth's own `BetterAuthPlugin[]` instead of `any[]`.
|
|
21
|
+
|
|
22
|
+
- [#889](https://github.com/OpenSaasAU/stack/pull/889) [`b9b9357`](https://github.com/OpenSaasAU/stack/commit/b9b935719774b01a81cfd2082387b76806c1a484) Thanks [@borisno2](https://github.com/borisno2)! - Fix `getSessionFromAuth` to project `sessionFields` from the _resolved_ better-auth session instead of only its `user` sub-object. A `customSession` plugin's replaced shape with no `user` key is now correctly treated as a signed-in session (never misreported as anonymous), and a session-only field (e.g. the admin plugin's `impersonatedBy`) is now resolvable. Errors from the underlying session lookup now propagate instead of silently becoming `null`, and a `sessionFields` entry that can't be resolved is omitted and logs a warning (once per field, per process) instead of vanishing silently.
|
|
23
|
+
|
|
24
|
+
The scaffolded `getSession()` — the CLI feature generator's `lib/auth.ts` template, and `examples/starter-auth`/`examples/auth-demo` — now call this single shared helper, reading `sessionFields` from the resolved config at runtime instead of baking a field list in at generation time. `examples/auth-demo`'s `getSession()` also now correctly returns `null` for an anonymous visitor (previously returned a truthy object of `undefined` values).
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
authPlugin({ sessionFields: ['userId', 'email', 'name', 'role'] })
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// lib/auth.ts
|
|
32
|
+
export async function getSession() {
|
|
33
|
+
const resolvedConfig = await config
|
|
34
|
+
const authConfig = resolvedConfig._pluginData?.auth as NormalizedAuthConfig | undefined
|
|
35
|
+
const sessionFields = authConfig?.sessionFields ?? ['userId', 'email', 'name']
|
|
36
|
+
return getSessionFromAuth(auth, sessionFields, await headers())
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
3
40
|
## 0.37.0
|
|
4
41
|
|
|
5
42
|
### Minor Changes
|
package/CLAUDE.md
CHANGED
|
@@ -28,8 +28,8 @@ Auto-generated lists:
|
|
|
28
28
|
|
|
29
29
|
### Server (`src/server/index.ts`)
|
|
30
30
|
|
|
31
|
-
- `createAuth(config, rawContext?)` - Creates Better-auth instance with MCP plugin support
|
|
32
|
-
- `buildBetterAuthOptions(config, rawContext?)` - Returns the same `BetterAuthOptions` `createAuth()` builds, without constructing an instance — for apps that need to hand-wire their own `betterAuth()`
|
|
31
|
+
- `createAuth(config, rawContext?, betterAuthPlugins?)` - Creates Better-auth instance with MCP plugin support
|
|
32
|
+
- `buildBetterAuthOptions(config, rawContext?, betterAuthPlugins?)` - Returns the same `BetterAuthOptions` `createAuth()` builds, without constructing an instance — for apps that need to hand-wire their own `betterAuth()`. The optional third argument (the app's own `betterAuthPlugins` array) makes the return type carry that literal plugin tuple instead of the widened array type — see "Typed `auth.api.*` reads" below.
|
|
33
33
|
- Returns `{ handler, signIn, signOut, ... }` - Better-auth methods
|
|
34
34
|
|
|
35
35
|
### Client (`src/client/index.ts`)
|
|
@@ -235,7 +235,8 @@ const context = createContext(config, prisma, session)
|
|
|
235
235
|
|
|
236
236
|
### Session Fields Configuration
|
|
237
237
|
|
|
238
|
-
|
|
238
|
+
`sessionFields` describes a **flattened projection** of the resolved better-auth session, not
|
|
239
|
+
the session's own shape:
|
|
239
240
|
|
|
240
241
|
```typescript
|
|
241
242
|
authPlugin({ sessionFields: ['userId', 'email', 'name', 'role'] })
|
|
@@ -247,6 +248,15 @@ access: {
|
|
|
247
248
|
}
|
|
248
249
|
```
|
|
249
250
|
|
|
251
|
+
`getSessionFromAuth()` (`@opensaas/stack-auth/server`) is the single implementation of this
|
|
252
|
+
projection — the scaffolded `getSession()` calls it with `sessionFields` read from the resolved
|
|
253
|
+
config at runtime. Each name resolves against a fixed precedence (a top-level key on the
|
|
254
|
+
resolved session, then `user`, then `session`), with `userId` special-cased to the user's `id`.
|
|
255
|
+
A `customSession` better-auth plugin fully replaces the resolved shape and can nest fields
|
|
256
|
+
anywhere; reconciling that against `sessionFields` is the app's job — an unresolvable name is
|
|
257
|
+
omitted and warns once (per field, per process) rather than silently becoming `undefined`. See
|
|
258
|
+
the `sessionFields` reference (`docs/content/reference/auth.md`) for the full contract.
|
|
259
|
+
|
|
250
260
|
### Session Type Safety
|
|
251
261
|
|
|
252
262
|
To get autocomplete and type safety for session fields, use module augmentation:
|
|
@@ -391,6 +401,43 @@ can't be synchronous. It gives an incremental path onto `createAuth()`: adopt
|
|
|
391
401
|
the builder first, then fold options into `betterAuthOptions` above as the
|
|
392
402
|
stack grows first-class config for them.
|
|
393
403
|
|
|
404
|
+
**Typed `auth.api.*` reads.** Called with just `(config, context)`, both
|
|
405
|
+
`buildBetterAuthOptions()` and `createAuth()` return the widened
|
|
406
|
+
`BetterAuthOptions` / `Auth<BetterAuthOptions>` — better-auth infers plugin
|
|
407
|
+
endpoints and a `customSession()`'s replaced session shape from the _literal_
|
|
408
|
+
options type, so the widened form erases them (an `emailOTP()` plugin loses
|
|
409
|
+
`auth.api.signInEmailOTP`; `auth.api.getSession()` falls back to `{ user,
|
|
410
|
+
session }` instead of a `customSession()` shape). Both functions take the
|
|
411
|
+
app's `betterAuthPlugins` array — the exact same array passed to
|
|
412
|
+
`authPlugin({ betterAuthPlugins })` — as an optional third argument, and their
|
|
413
|
+
return type then carries that literal tuple (plus the `nextCookies()` the
|
|
414
|
+
stack always appends last) instead of the widened array type:
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
export const appBetterAuthPlugins = [emailOTP({ sendVerificationOTP })] // same array passed to authPlugin({ betterAuthPlugins })
|
|
418
|
+
|
|
419
|
+
export const auth = betterAuth({
|
|
420
|
+
...(await buildBetterAuthOptions(config, rawOpensaasContext, appBetterAuthPlugins)),
|
|
421
|
+
})
|
|
422
|
+
// auth.api.signInEmailOTP is now typed.
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
The supplied tuple is for typing only — the plugin array used at runtime is
|
|
426
|
+
always the one resolved from `authPlugin({ betterAuthPlugins })` — so both
|
|
427
|
+
functions verify the supplied tuple is the same plugin instances in the same
|
|
428
|
+
order as the resolved array, throwing a prefixed error naming the mismatch if
|
|
429
|
+
not (`assertPluginTupleMatchesResolved` in `src/server/index.ts`). This is
|
|
430
|
+
what closes the drift hole a hand-rolled re-pass of the plugin array would
|
|
431
|
+
otherwise open.
|
|
432
|
+
|
|
433
|
+
`createAuth()`'s lazy `Proxy` does not behave identically to a real `Auth`
|
|
434
|
+
instance for every property regardless of which form you use — every access,
|
|
435
|
+
including a non-function property, is surfaced through an `async` wrapper (so
|
|
436
|
+
`auth.options` reads back as a `Promise`, not the plain object a real
|
|
437
|
+
instance returns synchronously). Reach for `buildBetterAuthOptions()` plus
|
|
438
|
+
`betterAuth()` instead when the app reads `auth.api.*` in typed code — it
|
|
439
|
+
constructs a real instance and does not have this gap.
|
|
440
|
+
|
|
394
441
|
## Integration Points
|
|
395
442
|
|
|
396
443
|
### With @opensaas/stack-core
|
package/dist/config/plugin.js
CHANGED
|
@@ -90,7 +90,7 @@ export function authPlugin(config) {
|
|
|
90
90
|
// `oauth_application`, `passkey`) still register as new lists via
|
|
91
91
|
// `addList`, same as before.
|
|
92
92
|
for (const plugin of normalized.betterAuthPlugins) {
|
|
93
|
-
if (plugin && typeof plugin === 'object' &&
|
|
93
|
+
if (plugin && typeof plugin === 'object' && plugin.schema) {
|
|
94
94
|
// Plugin has schema property - convert to OpenSaaS lists
|
|
95
95
|
const pluginSchema = plugin.schema;
|
|
96
96
|
const pluginLists = convertBetterAuthSchema(pluginSchema, baseModelKeys);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/config/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAE/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAA;AAEvE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,UAAU,CAAC,MAAkB;IAC3C,MAAM,UAAU,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAA;IAE9C,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,OAAO;QAEhB,mBAAmB,EAAE;YACnB,MAAM,EAAE,iEAAiE;YACzE,QAAQ,EAAE,qBAAqB;SAChC;QAED,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACtB,uEAAuE;YACvE,mEAAmE;YACnE,+DAA+D;YAC/D,uEAAuE;YACvE,iDAAiD;YACjD,MAAM,SAAS,GAAG,YAAY,CAC5B,UAAU,CAAC,cAAc,EACzB,UAAU,CAAC,MAAM,EACjB,UAAU,CAAC,MAAM,CAClB,CAAA;YAED,wEAAwE;YACxE,kEAAkE;YAClE,oEAAoE;YACpE,gEAAgE;YAChE,+DAA+D;YAC/D,MAAM,aAAa,GAAG;gBACpB,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS;gBACtC,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS;gBAC5C,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS;gBAC5C,YAAY,EAAE,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS;aACvD,CAAA;YAED,iEAAiE;YACjE,wEAAwE;YACxE,mEAAmE;YACnE,qEAAqE;YACrE,mEAAmE;YACnE,2DAA2D;YAC3D,+DAA+D;YAC/D,EAAE;YACF,sEAAsE;YACtE,qEAAqE;YACrE,sEAAsE;YACtE,mEAAmE;YACnE,mEAAmE;YACnE,+DAA+D;YAC/D,8CAA8C;YAC9C,KAAK,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC/D,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACnC,mEAAmE;oBACnE,gEAAgE;oBAChE,mEAAmE;oBACnE,kCAAkC;oBAClC,OAAO,CAAC,UAAU,CAAC,QAAQ,EAAE;wBAC3B,MAAM,EAAE,UAAU,CAAC,MAAM;wBACzB,KAAK,EAAE,UAAU,CAAC,KAAK;wBACvB,GAAG,EAAE,UAAU,CAAC,GAAG;qBACpB,CAAC,CAAA;gBACJ,CAAC;qBAAM,CAAC;oBACN,+BAA+B;oBAC/B,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;gBACvC,CAAC;YACH,CAAC;YAED,sEAAsE;YACtE,mEAAmE;YACnE,sEAAsE;YACtE,sEAAsE;YACtE,gEAAgE;YAChE,kEAAkE;YAClE,6BAA6B;YAC7B,KAAK,MAAM,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAE,CAAC;gBAClD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/config/plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/config/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ListConfig } from '@opensaas/stack-core';
|
|
2
|
-
import type { BetterAuthOptions, User } from 'better-auth';
|
|
2
|
+
import type { BetterAuthOptions, BetterAuthPlugin, User } from 'better-auth';
|
|
3
3
|
import type { ExtendUserListConfig } from '../lists/index.js';
|
|
4
4
|
/**
|
|
5
5
|
* better-auth's own callback shape for `sendVerificationEmail`/
|
|
@@ -321,8 +321,21 @@ export type AuthConfig = {
|
|
|
321
321
|
*/
|
|
322
322
|
schema?: string;
|
|
323
323
|
/**
|
|
324
|
-
* Which fields to include in the session object
|
|
325
|
-
*
|
|
324
|
+
* Which fields to include in the session object passed to access control
|
|
325
|
+
* functions — a **flattened projection** of the resolved better-auth
|
|
326
|
+
* session, not the session's own shape. `getSessionFromAuth` (the
|
|
327
|
+
* implementation the scaffolded `getSession()` calls) resolves each name
|
|
328
|
+
* against a fixed precedence: a top-level key on the resolved session
|
|
329
|
+
* object, then the `user` object, then the `session` sub-object.
|
|
330
|
+
* `userId` is special-cased to the authenticated user's `id`.
|
|
331
|
+
*
|
|
332
|
+
* A `customSession` better-auth plugin fully replaces the resolved shape
|
|
333
|
+
* (it can nest fields anywhere, e.g. under its own custom key) —
|
|
334
|
+
* reconciling that shape against `sessionFields` is the application's job.
|
|
335
|
+
* A listed name that can't be resolved is omitted and warns once per
|
|
336
|
+
* field per process, naming what was checked, rather than silently
|
|
337
|
+
* becoming `undefined` in an access control function.
|
|
338
|
+
*
|
|
326
339
|
* @default ['userId', 'email', 'name']
|
|
327
340
|
*
|
|
328
341
|
* @example
|
|
@@ -375,7 +388,7 @@ export type AuthConfig = {
|
|
|
375
388
|
* ]
|
|
376
389
|
* ```
|
|
377
390
|
*/
|
|
378
|
-
betterAuthPlugins?:
|
|
391
|
+
betterAuthPlugins?: BetterAuthPlugin[];
|
|
379
392
|
/**
|
|
380
393
|
* Rate limiting configuration
|
|
381
394
|
* Controls rate limiting for authentication endpoints
|
|
@@ -489,7 +502,7 @@ export type NormalizedAuthConfig = Required<Omit<AuthConfig, 'emailAndPassword'
|
|
|
489
502
|
* default (used to wire the datasource `schemas` array during generation).
|
|
490
503
|
*/
|
|
491
504
|
schema?: string;
|
|
492
|
-
betterAuthPlugins:
|
|
505
|
+
betterAuthPlugins: BetterAuthPlugin[];
|
|
493
506
|
rateLimit?: {
|
|
494
507
|
enabled: boolean;
|
|
495
508
|
window?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-better-auth-options.test.d.ts","sourceRoot":"","sources":["../../src/server/build-better-auth-options.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, it, expectTypeOf } from 'vitest';
|
|
2
|
+
import { buildBetterAuthOptions } from './index.js';
|
|
3
|
+
// `ReturnType<typeof buildBetterAuthOptions>` on the overloaded export itself
|
|
4
|
+
// resolves against its last (generic) signature, not the call-site-selected
|
|
5
|
+
// one — wrapping each call shape in its own ordinary function and reading
|
|
6
|
+
// `ReturnType<typeof wrapper>` instead forces TS to resolve overloads exactly
|
|
7
|
+
// as a real call site would.
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- referenced only via `typeof` below
|
|
9
|
+
function callWithNoPlugins(config, context) {
|
|
10
|
+
return buildBetterAuthOptions(config, context);
|
|
11
|
+
}
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- referenced only via `typeof` below
|
|
13
|
+
function callWithPlugins(config, context, plugins) {
|
|
14
|
+
return buildBetterAuthOptions(config, context, plugins);
|
|
15
|
+
}
|
|
16
|
+
describe('buildBetterAuthOptions plugin-tuple typing', () => {
|
|
17
|
+
it('back-compat: the no-argument call still returns the widened BetterAuthOptions', () => {
|
|
18
|
+
expectTypeOf().toEqualTypeOf();
|
|
19
|
+
});
|
|
20
|
+
it('preserves plugin-derived auth.api.* endpoints and a customSession shape', () => {
|
|
21
|
+
// emailOTP() endpoints exist on the constructed Auth's `api` — erased entirely
|
|
22
|
+
// when constructed from the widened `BetterAuthOptions` (see #876).
|
|
23
|
+
expectTypeOf().not.toBeNever();
|
|
24
|
+
expectTypeOf().not.toBeNever();
|
|
25
|
+
expectTypeOf().not.toBeNever();
|
|
26
|
+
expectTypeOf().toEqualTypeOf();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=build-better-auth-options.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-better-auth-options.test.js","sourceRoot":"","sources":["../../src/server/build-better-auth-options.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAKnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAWnD,8EAA8E;AAC9E,4EAA4E;AAC5E,0EAA0E;AAC1E,8EAA8E;AAC9E,6BAA6B;AAC7B,mGAAmG;AACnG,SAAS,iBAAiB,CACxB,MAAgD,EAChD,OAA+C;IAE/C,OAAO,sBAAsB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAChD,CAAC;AAED,mGAAmG;AACnG,SAAS,eAAe,CACtB,MAAgD,EAChD,OAA+C,EAC/C,OAAoB;IAEpB,OAAO,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;AACzD,CAAC;AAMD,QAAQ,CAAC,4CAA4C,EAAE,GAAG,EAAE;IAC1D,EAAE,CAAC,+EAA+E,EAAE,GAAG,EAAE;QACvF,YAAY,EAAe,CAAC,aAAa,EAAqB,CAAA;IAChE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,+EAA+E;QAC/E,oEAAoE;QACpE,YAAY,EAA4C,CAAC,GAAG,CAAC,SAAS,EAAE,CAAA;QACxE,YAAY,EAAiD,CAAC,GAAG,CAAC,SAAS,EAAE,CAAA;QAC7E,YAAY,EAAkD,CAAC,GAAG,CAAC,SAAS,EAAE,CAAA;QAI9E,YAAY,EAAoB,CAAC,aAAa,EAAqB,CAAA;IACrE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { betterAuth } from 'better-auth';
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
2
|
+
import { nextCookies } from 'better-auth/next-js';
|
|
3
|
+
import type { Auth, BetterAuthOptions, BetterAuthPlugin } from 'better-auth';
|
|
4
|
+
import type { OpenSaasConfig, AccessContext, Session } from '@opensaas/stack-core';
|
|
5
|
+
/**
|
|
6
|
+
* The `BetterAuthOptions` shape produced when an app's own plugin tuple is
|
|
7
|
+
* passed to `buildBetterAuthOptions()`/`createAuth()` — the tuple plus the
|
|
8
|
+
* `nextCookies()` plugin the stack always appends last. Carrying the literal
|
|
9
|
+
* tuple type (rather than the widened `BetterAuthPlugin[]`) is what lets
|
|
10
|
+
* `betterAuth()` re-infer plugin endpoints (e.g. `emailOTP()`'s
|
|
11
|
+
* `api.signInEmailOTP`) and a `customSession()` plugin's replaced session
|
|
12
|
+
* shape from the resulting options object.
|
|
13
|
+
*/
|
|
14
|
+
type ResolvedBetterAuthOptions<TPlugins extends readonly BetterAuthPlugin[]> = Omit<BetterAuthOptions, 'plugins'> & {
|
|
15
|
+
plugins: [...TPlugins, ReturnType<typeof nextCookies>];
|
|
16
|
+
};
|
|
4
17
|
/**
|
|
5
18
|
* Build the `BetterAuthOptions` a better-auth instance for this OpenSaas
|
|
6
19
|
* config should be constructed with — the same options `createAuth()` uses
|
|
@@ -10,42 +23,107 @@ import type { OpenSaasConfig, AccessContext } from '@opensaas/stack-core';
|
|
|
10
23
|
* authoritative for everything it models; the app's additions on top become
|
|
11
24
|
* an explicit, reviewable diff instead of a parallel, hand-duplicated config.
|
|
12
25
|
*
|
|
13
|
-
*
|
|
26
|
+
* Called with just `(config, context)`, the return type is the widened
|
|
27
|
+
* `BetterAuthOptions` — `betterAuth()` infers its plugin/session types from
|
|
28
|
+
* the *literal* type of the options object, so constructing from this
|
|
29
|
+
* widened return erases plugin endpoints (e.g. `emailOTP()`'s
|
|
30
|
+
* `api.signInEmailOTP`) and a `customSession()` plugin's replaced session
|
|
31
|
+
* shape. **If your app reads `auth.api.*` in typed code and uses either of
|
|
32
|
+
* those, pass its plugin tuple as the third argument** — the exact same
|
|
33
|
+
* array already passed to `authPlugin({ betterAuthPlugins })` — so the
|
|
34
|
+
* return type carries the literal tuple instead:
|
|
35
|
+
*
|
|
14
36
|
* ```typescript
|
|
15
37
|
* import { betterAuth } from 'better-auth'
|
|
38
|
+
* import { emailOTP } from 'better-auth/plugins'
|
|
16
39
|
* import { buildBetterAuthOptions } from '@opensaas/stack-auth/server'
|
|
17
40
|
*
|
|
41
|
+
* export const appBetterAuthPlugins = [emailOTP()] // same array passed to authPlugin({ betterAuthPlugins })
|
|
42
|
+
*
|
|
18
43
|
* export const auth = betterAuth({
|
|
19
|
-
* ...(await buildBetterAuthOptions(config, context)),
|
|
44
|
+
* ...(await buildBetterAuthOptions(config, context, appBetterAuthPlugins)),
|
|
20
45
|
* databaseHooks: { user: { create: { after: syncDomainUser } } },
|
|
21
46
|
* })
|
|
47
|
+
* // auth.api.signInEmailOTP / auth.api.getSession()'s customSession shape are now typed.
|
|
22
48
|
* ```
|
|
49
|
+
*
|
|
50
|
+
* The supplied tuple is for typing only — the array actually used at runtime
|
|
51
|
+
* is always the one resolved from `authPlugin({ betterAuthPlugins })`, with
|
|
52
|
+
* exactly one `nextCookies()` appended last. Passing a tuple that isn't the
|
|
53
|
+
* same plugin instances in the same order throws, so the two can't silently
|
|
54
|
+
* drift apart.
|
|
55
|
+
*
|
|
56
|
+
* Note `createAuth()`'s lazy Proxy does not behave identically to a real
|
|
57
|
+
* `Auth` instance for every property (see its own doc comment) — reach for
|
|
58
|
+
* this builder plus `betterAuth()` instead when the app reads `auth.api.*`
|
|
59
|
+
* in typed code.
|
|
23
60
|
*/
|
|
24
61
|
export declare function buildBetterAuthOptions(opensaasConfig: OpenSaasConfig | Promise<OpenSaasConfig>, context: AccessContext | Promise<AccessContext>): Promise<BetterAuthOptions>;
|
|
62
|
+
export declare function buildBetterAuthOptions<const TPlugins extends readonly BetterAuthPlugin[]>(opensaasConfig: OpenSaasConfig | Promise<OpenSaasConfig>, context: AccessContext | Promise<AccessContext>, plugins: TPlugins): Promise<ResolvedBetterAuthOptions<TPlugins>>;
|
|
25
63
|
/**
|
|
26
64
|
* Create a better-auth instance from OpenSaas config
|
|
27
65
|
* This should be called once at app startup
|
|
28
66
|
*
|
|
29
|
-
*
|
|
67
|
+
* Returns a lazy `Proxy` (see the caveat below), typed as `Auth<BetterAuthOptions>`
|
|
68
|
+
* when called with just `(config, context)` — the widened type, same erasure
|
|
69
|
+
* caveat as {@link buildBetterAuthOptions}'s no-argument form. **If your app
|
|
70
|
+
* reads `auth.api.*` in typed code and relies on a plugin's endpoints (e.g.
|
|
71
|
+
* `emailOTP()`) or a `customSession()`'s replaced session shape, pass its
|
|
72
|
+
* plugin tuple as the third argument** — the exact same array already passed
|
|
73
|
+
* to `authPlugin({ betterAuthPlugins })` — so the declared type carries the
|
|
74
|
+
* literal tuple instead:
|
|
75
|
+
*
|
|
30
76
|
* ```typescript
|
|
31
77
|
* // lib/auth.ts
|
|
32
78
|
* import { createAuth } from '@opensaas/stack-auth/server'
|
|
33
79
|
* import config from '../opensaas.config'
|
|
34
80
|
* import { rawOpensaasContext } from '@/.opensaas/context'
|
|
35
81
|
*
|
|
36
|
-
* export const
|
|
82
|
+
* export const appBetterAuthPlugins = [emailOTP()] // same array passed to authPlugin({ betterAuthPlugins })
|
|
83
|
+
*
|
|
84
|
+
* export const auth = createAuth(config, rawOpensaasContext, appBetterAuthPlugins)
|
|
37
85
|
* ```
|
|
86
|
+
*
|
|
87
|
+
* As with the builder, the supplied tuple is for typing only, and a tuple
|
|
88
|
+
* that isn't the same plugin instances in the same order throws.
|
|
89
|
+
*
|
|
90
|
+
* **Proxy caveat:** the lazy `Proxy` this returns does not behave identically
|
|
91
|
+
* to a real `Auth` instance for every property — every access, including a
|
|
92
|
+
* non-function property, is surfaced through an `async` wrapper (so e.g.
|
|
93
|
+
* `auth.options` reads back as a `Promise`, not the plain object a real
|
|
94
|
+
* instance would return synchronously). The declared type does not model
|
|
95
|
+
* this difference; where it matters, reach for {@link buildBetterAuthOptions}
|
|
96
|
+
* plus `betterAuth()` instead, which constructs a real instance.
|
|
38
97
|
*/
|
|
39
|
-
export declare function createAuth(opensaasConfig: OpenSaasConfig | Promise<OpenSaasConfig>, context: AccessContext | Promise<AccessContext>):
|
|
98
|
+
export declare function createAuth(opensaasConfig: OpenSaasConfig | Promise<OpenSaasConfig>, context: AccessContext | Promise<AccessContext>): Auth<BetterAuthOptions>;
|
|
99
|
+
export declare function createAuth<const TPlugins extends readonly BetterAuthPlugin[]>(opensaasConfig: OpenSaasConfig | Promise<OpenSaasConfig>, context: AccessContext | Promise<AccessContext>, plugins: TPlugins): Auth<ResolvedBetterAuthOptions<TPlugins>>;
|
|
40
100
|
/**
|
|
41
|
-
* Get session from better-auth and transform it to OpenSaas session format
|
|
101
|
+
* Get session from better-auth and transform it to OpenSaas session format —
|
|
102
|
+
* a flattened projection of `sessionFields` off the *resolved* session
|
|
103
|
+
* object, not just its `user` sub-object. This is what makes a
|
|
104
|
+
* `customSession` plugin's fields (added at the top level, or a
|
|
105
|
+
* session-only field like the admin plugin's `impersonatedBy`) reachable.
|
|
106
|
+
* See the `sessionFields` reference for the resolution precedence.
|
|
107
|
+
*
|
|
108
|
+
* Returns `null` only when there is genuinely no session — a resolved
|
|
109
|
+
* session with no `user` key (a `customSession` plugin that dropped it) is
|
|
110
|
+
* still a session and still gets projected, never misreported as anonymous.
|
|
111
|
+
* A listed field that can't be resolved from the session shape is omitted
|
|
112
|
+
* and warns once per field per process (see `warnUnresolvedSessionField`)
|
|
113
|
+
* instead of silently vanishing into an access-control function reading
|
|
114
|
+
* `undefined`.
|
|
115
|
+
*
|
|
116
|
+
* Errors from the underlying `auth.api.getSession()` call propagate rather
|
|
117
|
+
* than becoming `null` — collapsing a lookup failure (e.g. a session-store
|
|
118
|
+
* outage) into "anonymous" is indistinguishable from a mass sign-out under
|
|
119
|
+
* fail-closed access control, so the caller must see it.
|
|
42
120
|
*
|
|
43
|
-
* Not called by any generated code
|
|
44
|
-
* transform against `auth.api.getSession({ headers:
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
121
|
+
* Not called by any generated code before this helper existed — apps used to
|
|
122
|
+
* hand-roll this same transform against `auth.api.getSession({ headers:
|
|
123
|
+
* await headers() })`. Exported as the single reusable implementation; pass
|
|
124
|
+
* the caller's request headers (e.g. Next.js `await headers()` in a Server
|
|
125
|
+
* Component/action) so a session cookie can actually be resolved.
|
|
48
126
|
*/
|
|
49
|
-
export declare function getSessionFromAuth(auth: ReturnType<typeof betterAuth>, sessionFields: string[], headers: Headers): Promise<
|
|
127
|
+
export declare function getSessionFromAuth(auth: ReturnType<typeof betterAuth>, sessionFields: string[], headers: Headers): Promise<Session | null>;
|
|
50
128
|
export type { BetterAuthOptions };
|
|
51
129
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC5E,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAIlF;;;;;;;;GAQG;AACH,KAAK,yBAAyB,CAAC,QAAQ,SAAS,SAAS,gBAAgB,EAAE,IAAI,IAAI,CACjF,iBAAiB,EACjB,SAAS,CACV,GAAG;IACF,OAAO,EAAE,CAAC,GAAG,QAAQ,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CAAA;CACvD,CAAA;AA+ID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAsB,sBAAsB,CAC1C,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,EACxD,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,GAC9C,OAAO,CAAC,iBAAiB,CAAC,CAAA;AAC7B,wBAAsB,sBAAsB,CAAC,KAAK,CAAC,QAAQ,SAAS,SAAS,gBAAgB,EAAE,EAC7F,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,EACxD,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,EAC/C,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC,CAAA;AA2I/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,UAAU,CACxB,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,EACxD,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,GAC9C,IAAI,CAAC,iBAAiB,CAAC,CAAA;AAC1B,wBAAgB,UAAU,CAAC,KAAK,CAAC,QAAQ,SAAS,SAAS,gBAAgB,EAAE,EAC3E,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,EACxD,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,EAC/C,OAAO,EAAE,QAAQ,GAChB,IAAI,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC,CAAA;AA8I5C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,EACnC,aAAa,EAAE,MAAM,EAAE,EACvB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAoBzB;AAED,YAAY,EAAE,iBAAiB,EAAE,CAAA"}
|