@velajs/better-auth 1.0.0 → 2.0.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/CHANGELOG.md +6 -0
- package/README.md +24 -19
- package/dist/{better-auth.service-BMkyFX-w.js → better-auth.service-DurQ4JQf.js} +4 -4
- package/dist/better-auth.service-DurQ4JQf.js.map +1 -0
- package/dist/better-auth.service-NOlWXxd4.d.ts +68 -0
- package/dist/index.d.ts +29 -158
- package/dist/index.js +198 -390
- package/dist/index.js.map +1 -1
- package/dist/testing/index.d.ts +4 -3
- package/dist/testing/index.js +3 -2
- package/dist/testing/index.js.map +1 -1
- package/package.json +24 -25
- package/dist/better-auth.service-BMkyFX-w.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.0.0
|
|
4
|
+
|
|
5
|
+
Native environment configuration and one immutable verified identity shared with provider-independent authorization.
|
|
6
|
+
|
|
7
|
+
Requires the coordinated Vela 2.0 package set. See the workspace migration guide.
|
|
8
|
+
|
|
3
9
|
## 1.0.0
|
|
4
10
|
|
|
5
11
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -74,22 +74,19 @@ imports: [
|
|
|
74
74
|
|
|
75
75
|
### Pattern B — DI'd plugin construction
|
|
76
76
|
|
|
77
|
-
`forRootAsync` lets
|
|
77
|
+
`forRootAsync` requires an explicit `inject` tuple (use `inject: []` when there are no dependencies), so factory parameter types always have matching runtime tokens. It lets Vela services participate in your Better Auth configuration. On Workers, declare `WORKER_ENV = new InjectionToken<WorkerEnv>('app.Env')` and pass that token to `createCloudflareWorker(AppModule, { envToken: WORKER_ENV })`; the native event environment is available before DI factories run.
|
|
78
78
|
|
|
79
79
|
```ts
|
|
80
80
|
imports: [
|
|
81
|
-
D1Module.forRoot({ binding: 'DB' }),
|
|
82
81
|
BetterAuthModule.forRootAsync({
|
|
83
|
-
inject: [
|
|
84
|
-
useFactory: (
|
|
85
|
-
|
|
86
|
-
database: drizzleAdapter(drizzle(d1.binding), { provider: 'sqlite' }),
|
|
82
|
+
inject: [WORKER_ENV, EmailService],
|
|
83
|
+
useFactory: (env, email) => betterAuth({
|
|
84
|
+
database: drizzleAdapter(drizzle(env.DB), { provider: 'sqlite' }),
|
|
87
85
|
plugins: [
|
|
88
86
|
magicLink({ sendMagicLink: (data) => email.send(data) }), // DI'd EmailService
|
|
89
87
|
apiKey(),
|
|
90
88
|
twoFactor(),
|
|
91
89
|
],
|
|
92
|
-
}),
|
|
93
90
|
}),
|
|
94
91
|
isGlobal: true,
|
|
95
92
|
}),
|
|
@@ -102,7 +99,7 @@ Each feature ships a self-contained vela module that exports a plugin token. App
|
|
|
102
99
|
|
|
103
100
|
```ts
|
|
104
101
|
// magic-link-auth.module.ts
|
|
105
|
-
import { Module, InjectionToken } from '@velajs/vela';
|
|
102
|
+
import { Module, InjectionToken, defineProvider } from '@velajs/vela';
|
|
106
103
|
import { magicLink } from 'better-auth/plugins';
|
|
107
104
|
import { EmailService } from './email.service';
|
|
108
105
|
|
|
@@ -113,12 +110,11 @@ export const MAGIC_LINK_PLUGIN = new InjectionToken<ReturnType<typeof magicLink>
|
|
|
113
110
|
@Module({
|
|
114
111
|
providers: [
|
|
115
112
|
EmailService,
|
|
116
|
-
{
|
|
117
|
-
provide: MAGIC_LINK_PLUGIN,
|
|
113
|
+
defineProvider(MAGIC_LINK_PLUGIN, {
|
|
118
114
|
inject: [EmailService],
|
|
119
115
|
useFactory: (email: EmailService) =>
|
|
120
116
|
magicLink({ sendMagicLink: (d) => email.send({ to: d.email, link: d.url }) }),
|
|
121
|
-
},
|
|
117
|
+
}),
|
|
122
118
|
],
|
|
123
119
|
exports: [MAGIC_LINK_PLUGIN],
|
|
124
120
|
})
|
|
@@ -134,9 +130,7 @@ export class MagicLinkAuthModule {}
|
|
|
134
130
|
BetterAuthModule.forRootAsync({
|
|
135
131
|
imports: [MagicLinkAuthModule, OAuthAuthModule],
|
|
136
132
|
inject: [MAGIC_LINK_PLUGIN, OAUTH_PLUGIN],
|
|
137
|
-
useFactory: (magicLink, oauth) => ({
|
|
138
|
-
auth: betterAuth({ database, plugins: [magicLink, oauth] }),
|
|
139
|
-
}),
|
|
133
|
+
useFactory: (magicLink, oauth) => betterAuth({ database, plugins: [magicLink, oauth] }),
|
|
140
134
|
isGlobal: true,
|
|
141
135
|
}),
|
|
142
136
|
],
|
|
@@ -154,7 +148,7 @@ import { BetterAuthService } from '@velajs/better-auth';
|
|
|
154
148
|
|
|
155
149
|
@Injectable()
|
|
156
150
|
class AdminUserService {
|
|
157
|
-
constructor(@Inject(BetterAuthService) private readonly auth: BetterAuthService) {}
|
|
151
|
+
constructor(@Inject(BetterAuthService) private readonly auth: BetterAuthService<typeof auth>) {}
|
|
158
152
|
|
|
159
153
|
listSessions(userId: string) {
|
|
160
154
|
return this.auth.api.listUserSessions({ userId });
|
|
@@ -165,7 +159,7 @@ class AdminUserService {
|
|
|
165
159
|
}
|
|
166
160
|
```
|
|
167
161
|
|
|
168
|
-
Under `forRootAsync`, the underlying `betterAuth({...})` instance is constructed
|
|
162
|
+
Under `forRootAsync`, the underlying `betterAuth({...})` instance is constructed lazily on first `.auth` / `.api` / `.handler` access. The Workers adapter supplies the typed environment before DI and owns a separate application for each environment, so a cached auth instance never crosses environments.
|
|
169
163
|
|
|
170
164
|
## Decorators
|
|
171
165
|
|
|
@@ -175,7 +169,6 @@ Under `forRootAsync`, the underlying `betterAuth({...})` instance is constructed
|
|
|
175
169
|
| `@CurrentSession()` | Better-auth `Session` after guards run |
|
|
176
170
|
| `@Public(true)` | Class or method — bypass AuthGuard entirely |
|
|
177
171
|
| `@OptionalAuth(true)` | Class or method — populate user if present, never throw 401 |
|
|
178
|
-
| `@Roles(['admin'])` | Method — read by `RolesGuard`. Compares against `user.role`. |
|
|
179
172
|
|
|
180
173
|
Optional identities are ordinary values: an anonymous caller receives the actual `undefined`, so normal truthiness checks are safe.
|
|
181
174
|
|
|
@@ -187,8 +180,8 @@ handle(@CurrentUser() user: User | undefined) {
|
|
|
187
180
|
|
|
188
181
|
## Guards
|
|
189
182
|
|
|
190
|
-
- **`AuthGuard`** — singleton. Reads `Authorization` header / cookies via `auth.api.getSession`,
|
|
191
|
-
|
|
183
|
+
- **`AuthGuard`** — singleton. Reads `Authorization` header / cookies via `auth.api.getSession`, validates the full base user/session models, and publishes Vela's trusted principal, tenant, roles, and session expiry for downstream security components. The Better Auth organization plugin's verified `activeOrganizationId` becomes the tenant partition when present. The guard honors only explicit `@Public()` / `@OptionalAuth()` metadata. The generated Better Auth catch-all controller is explicitly public; sharing its URL prefix never makes an application controller public.
|
|
184
|
+
Permission and role guards live in `@velajs/authz/vela`: import `PermissionGuard`, `RequirePermission`, `RolesGuard`, and `Roles` there. They read the same trusted identity for Better Auth and Cloudflare Access. Run authentication before authorization.
|
|
192
185
|
|
|
193
186
|
Global registration is the default: installing the module binds `AuthGuard` to `APP_GUARD`. Routes are deny-by-default; mark public ones with `@Public(true)`. The generated Better Auth controller is already marked public.
|
|
194
187
|
|
|
@@ -196,6 +189,18 @@ When using `ThrottlerModule`, import Better Auth first. Vela then rate-limits by
|
|
|
196
189
|
the verified issuer, subject, principal type, and active organization before it
|
|
197
190
|
falls back to a platform-attested client address.
|
|
198
191
|
|
|
192
|
+
`BETTER_AUTH_OPTIONS` now contains only runtime configuration; read the auth instance from `BetterAuthService`. The obsolete `defaultPolicy` option and default-path controller constant were removed. Use `createBetterAuthCatchallController()` for a manually mounted catch-all.
|
|
193
|
+
|
|
194
|
+
## Trusted identity and typing
|
|
195
|
+
|
|
196
|
+
`@CurrentUser()` and `@CurrentSession()` expose only validated Better Auth data tied to the exact current trusted identity. Public routes, missing/rejected sessions, logout, expiry, and another provider replacing the identity invalidate those values. Hono user variables and removed compatibility symbols cannot grant roles or permissions.
|
|
197
|
+
|
|
198
|
+
Core `getTrustedRequestIdentity(request)` and authz `@CurrentIdentity()` return the verified issuer/subject/type, optional tenant, explicit roles, and credential expiry. WebSocket guards consume only the normalized server connection attachment and do not consult HTTP cookies or arbitrary socket role metadata.
|
|
199
|
+
|
|
200
|
+
The integration accepts the minimal `BetterAuthInstance` contract instead of `Auth<any>`. `new BetterAuthService(() => auth)` infers the concrete instance and retains plugin API/result types. For an injected service, annotate `BetterAuthService<typeof auth>` with the same configured instance type. The unparameterized service intentionally exposes only the operations the framework itself requires.
|
|
201
|
+
|
|
202
|
+
Migration: identity symbols (`AUTH_USER_KEY`, `AUTH_SESSION_KEY`, issuer/type keys) were removed. Use validated parameter decorators or core's trusted identity reader. Authorization imports moved to `@velajs/authz/vela`; the module no longer registers duplicate provider-specific permission guards.
|
|
203
|
+
|
|
199
204
|
## Edge-safe DB adapters
|
|
200
205
|
|
|
201
206
|
`@velajs/better-auth` itself is `node:`-clean. Edge-safety of your runtime depends on your better-auth DB adapter:
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { Inject, Injectable, InjectionToken } from "@velajs/vela";
|
|
2
|
-
//#region \0@oxc-project+runtime@0.
|
|
2
|
+
//#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorateMetadata.js
|
|
3
3
|
function __decorateMetadata(k, v) {
|
|
4
4
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
5
5
|
}
|
|
6
6
|
//#endregion
|
|
7
|
-
//#region \0@oxc-project+runtime@0.
|
|
7
|
+
//#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorateParam.js
|
|
8
8
|
function __decorateParam(paramIndex, decorator) {
|
|
9
9
|
return function(target, key) {
|
|
10
10
|
decorator(target, key, paramIndex);
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
13
|
//#endregion
|
|
14
|
-
//#region \0@oxc-project+runtime@0.
|
|
14
|
+
//#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorate.js
|
|
15
15
|
function __decorate(decorators, target, key, desc) {
|
|
16
16
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
17
17
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -60,4 +60,4 @@ BetterAuthService = __decorate([
|
|
|
60
60
|
//#endregion
|
|
61
61
|
export { __decorateMetadata as a, __decorateParam as i, BetterAuthService as n, __decorate as r, BETTER_AUTH_BUILDER as t };
|
|
62
62
|
|
|
63
|
-
//# sourceMappingURL=better-auth.service-
|
|
63
|
+
//# sourceMappingURL=better-auth.service-DurQ4JQf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"better-auth.service-DurQ4JQf.js","names":[],"sources":["../src/better-auth.service.ts"],"sourcesContent":["import { Inject, Injectable, InjectionToken } from '@velajs/vela';\nimport type { BetterAuthInstance } from './better-auth.types';\n\n/**\n * Internal token holding the auth-construction closure with its inject deps\n * closed over. Resolves cheaply at module load (just captures references);\n * the inner call happens lazily on first auth use (see `BetterAuthService`).\n *\n * Not exported from the public surface — only the service consumes it.\n */\nexport const BETTER_AUTH_BUILDER = new InjectionToken<() => BetterAuthInstance>(\n 'vela.better-auth.Builder',\n);\n\n/**\n * The single injectable consumers reach for to interact with better-auth.\n * Wraps the underlying `betterAuth({...})` instance with lazy construction:\n *\n * - `forRoot({ auth })` — the builder returns the eagerly-provided instance,\n * so the first `.auth` / `.api` / `.handler` access is effectively a\n * read-and-cache.\n * - `forRootAsync({ inject, useFactory })` — the builder wraps the user's\n * factory + inject deps. First access triggers `useFactory(...deps)`. This\n * is what makes Cloudflare D1/KV bindings work: at module load the factory\n * doesn't run; on first request (when AuthGuard or the catch-all calls\n * `service.api` / `service.handler`), the native environment is registered and the\n * factory can read them safely.\n *\n * Used directly by AuthGuard and the catch-all controller. Consumers in\n * application code inject the same way: `@Inject(BetterAuthService)`.\n */\n@Injectable()\nexport class BetterAuthService<TAuth extends BetterAuthInstance = BetterAuthInstance> {\n private cached: TAuth | undefined;\n\n constructor(@Inject(BETTER_AUTH_BUILDER) private readonly build: () => TAuth) {}\n\n /**\n * The underlying better-auth instance. Constructed once on first access.\n * Safe to call from any request-time code path (guards, controllers,\n * services invoked from handlers).\n */\n get auth(): TAuth {\n if (!this.cached) this.cached = this.build();\n return this.cached;\n }\n\n /** Convenience accessor — equivalent to `service.auth.api`. */\n get api(): TAuth['api'] {\n return this.auth.api;\n }\n\n /** Convenience accessor — equivalent to `service.auth.handler`. */\n get handler(): TAuth['handler'] {\n return this.auth.handler;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,MAAa,sBAAsB,IAAI,eACrC,0BACF;AAoBO,IAAM,oBAAN,MAAM,kBAAyE;CAG1B;CAF1D;CAEA,YAAY,OAAkE;EAApB,KAAA,QAAA;CAAqB;;;;;;CAO/E,IAAI,OAAc;EAChB,IAAI,CAAC,KAAK,QAAQ,KAAK,SAAS,KAAK,MAAM;EAC3C,OAAO,KAAK;CACd;;CAGA,IAAI,MAAoB;EACtB,OAAO,KAAK,KAAK;CACnB;;CAGA,IAAI,UAA4B;EAC9B,OAAO,KAAK,KAAK;CACnB;AACF;;CAzBC,WAAW;CAIG,gBAAA,GAAA,OAAO,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { InjectionToken } from "@velajs/vela";
|
|
2
|
+
import { Auth, Session, User } from "better-auth";
|
|
3
|
+
//#region src/better-auth.types.d.ts
|
|
4
|
+
/** The runtime surface required by the integration; concrete instances retain their generics. */
|
|
5
|
+
interface BetterAuthInstance {
|
|
6
|
+
readonly api: {
|
|
7
|
+
getSession(input: {
|
|
8
|
+
headers: Headers;
|
|
9
|
+
}): Promise<unknown>;
|
|
10
|
+
};
|
|
11
|
+
readonly handler: (request: Request) => Promise<Response>;
|
|
12
|
+
/** Used only by the real-session testing helper. */
|
|
13
|
+
readonly $context?: Promise<Pick<Awaited<Auth['$context']>, 'internalAdapter' | 'authCookies' | 'secret'>>;
|
|
14
|
+
}
|
|
15
|
+
interface BetterAuthModuleOptions<TAuth extends BetterAuthInstance = BetterAuthInstance> extends BetterAuthRuntimeOptions {
|
|
16
|
+
auth: TAuth;
|
|
17
|
+
}
|
|
18
|
+
/** Provider configuration, separate from the lazily constructed auth instance. */
|
|
19
|
+
interface BetterAuthRuntimeOptions {
|
|
20
|
+
/** Stable namespace paired with user ids in authorization identities. */
|
|
21
|
+
issuer?: string;
|
|
22
|
+
basePath?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Register AuthGuard application-wide. Defaults to `true`; opt out only when
|
|
25
|
+
* the application installs an equivalent global authentication guard itself.
|
|
26
|
+
*/
|
|
27
|
+
isGlobal?: boolean;
|
|
28
|
+
mountHandler?: boolean;
|
|
29
|
+
}
|
|
30
|
+
type User$1 = User;
|
|
31
|
+
type Session$1 = Session;
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/better-auth.service.d.ts
|
|
34
|
+
/**
|
|
35
|
+
* The single injectable consumers reach for to interact with better-auth.
|
|
36
|
+
* Wraps the underlying `betterAuth({...})` instance with lazy construction:
|
|
37
|
+
*
|
|
38
|
+
* - `forRoot({ auth })` — the builder returns the eagerly-provided instance,
|
|
39
|
+
* so the first `.auth` / `.api` / `.handler` access is effectively a
|
|
40
|
+
* read-and-cache.
|
|
41
|
+
* - `forRootAsync({ inject, useFactory })` — the builder wraps the user's
|
|
42
|
+
* factory + inject deps. First access triggers `useFactory(...deps)`. This
|
|
43
|
+
* is what makes Cloudflare D1/KV bindings work: at module load the factory
|
|
44
|
+
* doesn't run; on first request (when AuthGuard or the catch-all calls
|
|
45
|
+
* `service.api` / `service.handler`), the native environment is registered and the
|
|
46
|
+
* factory can read them safely.
|
|
47
|
+
*
|
|
48
|
+
* Used directly by AuthGuard and the catch-all controller. Consumers in
|
|
49
|
+
* application code inject the same way: `@Inject(BetterAuthService)`.
|
|
50
|
+
*/
|
|
51
|
+
declare class BetterAuthService<TAuth extends BetterAuthInstance = BetterAuthInstance> {
|
|
52
|
+
private readonly build;
|
|
53
|
+
private cached;
|
|
54
|
+
constructor(build: () => TAuth);
|
|
55
|
+
/**
|
|
56
|
+
* The underlying better-auth instance. Constructed once on first access.
|
|
57
|
+
* Safe to call from any request-time code path (guards, controllers,
|
|
58
|
+
* services invoked from handlers).
|
|
59
|
+
*/
|
|
60
|
+
get auth(): TAuth;
|
|
61
|
+
/** Convenience accessor — equivalent to `service.auth.api`. */
|
|
62
|
+
get api(): TAuth['api'];
|
|
63
|
+
/** Convenience accessor — equivalent to `service.auth.handler`. */
|
|
64
|
+
get handler(): TAuth['handler'];
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { Session$1 as a, BetterAuthRuntimeOptions as i, BetterAuthInstance as n, User$1 as o, BetterAuthModuleOptions as r, BetterAuthService as t };
|
|
68
|
+
//# sourceMappingURL=better-auth.service-NOlWXxd4.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,25 +1,6 @@
|
|
|
1
|
+
import { a as Session, i as BetterAuthRuntimeOptions, n as BetterAuthInstance, o as User, r as BetterAuthModuleOptions, t as BetterAuthService } from "./better-auth.service-NOlWXxd4.js";
|
|
1
2
|
import { CanActivate, DynamicModule, ExecutionContext, InferTokens, InjectionToken, Token, Type } from "@velajs/vela";
|
|
2
|
-
import { Auth, Session as Session$1, User as User$1 } from "better-auth";
|
|
3
3
|
import { Identity, PermissionResolver } from "@velajs/authz";
|
|
4
|
-
//#region src/better-auth.types.d.ts
|
|
5
|
-
type BetterAuthInstance = Auth<any>;
|
|
6
|
-
interface BetterAuthModuleOptions {
|
|
7
|
-
auth: BetterAuthInstance;
|
|
8
|
-
/** Stable namespace paired with user ids in authorization identities. */
|
|
9
|
-
issuer?: string;
|
|
10
|
-
basePath?: string;
|
|
11
|
-
/**
|
|
12
|
-
* Register AuthGuard application-wide. Defaults to `true`; opt out only when
|
|
13
|
-
* the application installs an equivalent global authentication guard itself.
|
|
14
|
-
*/
|
|
15
|
-
isGlobal?: boolean;
|
|
16
|
-
/** @deprecated Authentication is deny-by-default. Only `'deny'` is accepted. */
|
|
17
|
-
defaultPolicy?: 'deny';
|
|
18
|
-
mountHandler?: boolean;
|
|
19
|
-
}
|
|
20
|
-
type User = User$1;
|
|
21
|
-
type Session = Session$1;
|
|
22
|
-
//#endregion
|
|
23
4
|
//#region src/better-auth.module.d.ts
|
|
24
5
|
/**
|
|
25
6
|
* Options for {@link BetterAuthModule.forRootAsync}.
|
|
@@ -30,25 +11,23 @@ type Session = Session$1;
|
|
|
30
11
|
*
|
|
31
12
|
* ```ts
|
|
32
13
|
* BetterAuthModule.forRootAsync({
|
|
33
|
-
* inject: [
|
|
34
|
-
* useFactory: (
|
|
35
|
-
* betterAuth({ database: drizzleAdapter(drizzle(
|
|
14
|
+
* inject: [WORKER_ENV, ConfigService], // captured as readonly tuple
|
|
15
|
+
* useFactory: (env, config) => // inferred from the tokens
|
|
16
|
+
* betterAuth({ database: drizzleAdapter(drizzle(env.DB), ...) }),
|
|
36
17
|
* });
|
|
37
18
|
* ```
|
|
38
19
|
*/
|
|
39
|
-
interface ForRootAsyncOptions<Inject extends readonly Token
|
|
40
|
-
inject
|
|
20
|
+
interface ForRootAsyncOptions<Inject extends readonly Token[] = readonly Token[]> {
|
|
21
|
+
inject: Inject;
|
|
41
22
|
imports?: DynamicModule['imports'];
|
|
42
23
|
useFactory: (...deps: InferTokens<Inject>) => BetterAuthInstance;
|
|
43
24
|
isGlobal?: boolean;
|
|
44
25
|
mountHandler?: boolean;
|
|
45
26
|
basePath?: string;
|
|
46
27
|
issuer?: string;
|
|
47
|
-
/** @deprecated Authentication is deny-by-default. Only `'deny'` is accepted. */
|
|
48
|
-
defaultPolicy?: 'deny';
|
|
49
28
|
key?: string;
|
|
50
29
|
}
|
|
51
|
-
declare class BetterAuthModule {
|
|
30
|
+
export declare class BetterAuthModule {
|
|
52
31
|
/**
|
|
53
32
|
* Synchronous registration. The auth instance is constructed by the consumer
|
|
54
33
|
* at module-load time and passed in directly. Use this when the inputs to
|
|
@@ -64,47 +43,11 @@ declare class BetterAuthModule {
|
|
|
64
43
|
* first time anything reads `BetterAuthService.auth` (or `.api` / `.handler`).
|
|
65
44
|
* In normal request handling that's `AuthGuard.canActivate` or the catch-all
|
|
66
45
|
* controller's `.handle`. At module load the factory does NOT run — it's only
|
|
67
|
-
* captured
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* the service. Inject deps resolve at module load (cheap BindingRef wrappers);
|
|
71
|
-
* their *values* are read at first auth use, inside your factory body.
|
|
72
|
-
*/
|
|
73
|
-
static forRootAsync<const Inject extends readonly Token<unknown>[] = readonly Token<unknown>[]>(options: ForRootAsyncOptions<Inject>): DynamicModule;
|
|
74
|
-
}
|
|
75
|
-
//#endregion
|
|
76
|
-
//#region src/better-auth.service.d.ts
|
|
77
|
-
/**
|
|
78
|
-
* The single injectable consumers reach for to interact with better-auth.
|
|
79
|
-
* Wraps the underlying `betterAuth({...})` instance with lazy construction:
|
|
80
|
-
*
|
|
81
|
-
* - `forRoot({ auth })` — the builder returns the eagerly-provided instance,
|
|
82
|
-
* so the first `.auth` / `.api` / `.handler` access is effectively a
|
|
83
|
-
* read-and-cache.
|
|
84
|
-
* - `forRootAsync({ inject, useFactory })` — the builder wraps the user's
|
|
85
|
-
* factory + inject deps. First access triggers `useFactory(...deps)`. This
|
|
86
|
-
* is what makes Cloudflare D1/KV bindings work: at module load the factory
|
|
87
|
-
* doesn't run; on first request (when AuthGuard or the catch-all calls
|
|
88
|
-
* `service.api` / `service.handler`), the bindings are populated and the
|
|
89
|
-
* factory can read them safely.
|
|
90
|
-
*
|
|
91
|
-
* Used directly by AuthGuard and the catch-all controller. Consumers in
|
|
92
|
-
* application code inject the same way: `@Inject(BetterAuthService)`.
|
|
93
|
-
*/
|
|
94
|
-
declare class BetterAuthService {
|
|
95
|
-
private readonly build;
|
|
96
|
-
private cached;
|
|
97
|
-
constructor(build: () => BetterAuthInstance);
|
|
98
|
-
/**
|
|
99
|
-
* The underlying better-auth instance. Constructed once on first access.
|
|
100
|
-
* Safe to call from any request-time code path (guards, controllers,
|
|
101
|
-
* services invoked from handlers).
|
|
46
|
+
* captured in the checked builder provider. The Workers adapter supplies its
|
|
47
|
+
* native environment before DI; the lazily constructed auth instance belongs
|
|
48
|
+
* to that environment's application and never captures another app's bindings.
|
|
102
49
|
*/
|
|
103
|
-
|
|
104
|
-
/** Convenience accessor — equivalent to `service.auth.api`. */
|
|
105
|
-
get api(): BetterAuthInstance['api'];
|
|
106
|
-
/** Convenience accessor — equivalent to `service.auth.handler`. */
|
|
107
|
-
get handler(): BetterAuthInstance['handler'];
|
|
50
|
+
static forRootAsync<const Inject extends readonly Token[] = readonly Token[]>(options: ForRootAsyncOptions<Inject>): DynamicModule;
|
|
108
51
|
}
|
|
109
52
|
//#endregion
|
|
110
53
|
//#region src/better-auth.controller.d.ts
|
|
@@ -121,106 +64,33 @@ declare class BetterAuthService {
|
|
|
121
64
|
*
|
|
122
65
|
* Both default to `/api/auth`, so the no-prefix / no-config case just works.
|
|
123
66
|
*/
|
|
124
|
-
declare function createBetterAuthCatchallController(basePath?: string): Type;
|
|
125
|
-
/**
|
|
126
|
-
* Default-path (`/api/auth`) catch-all controller. Retained for back-compat;
|
|
127
|
-
* `BetterAuthModule` now mounts {@link createBetterAuthCatchallController} with
|
|
128
|
-
* the configured `basePath`. Prefer the factory for a custom base path.
|
|
129
|
-
*/
|
|
130
|
-
declare const BetterAuthCatchallController: Type;
|
|
67
|
+
export declare function createBetterAuthCatchallController(basePath?: string): Type;
|
|
131
68
|
//#endregion
|
|
132
69
|
//#region src/better-auth.tokens.d.ts
|
|
133
|
-
declare const BETTER_AUTH_OPTIONS: InjectionToken<
|
|
134
|
-
declare const AUTH_USER_KEY: unique symbol;
|
|
135
|
-
declare const AUTH_SESSION_KEY: unique symbol;
|
|
136
|
-
declare const AUTH_ISSUER_KEY: unique symbol;
|
|
137
|
-
declare const AUTH_PRINCIPAL_TYPE_KEY: unique symbol;
|
|
70
|
+
export declare const BETTER_AUTH_OPTIONS: InjectionToken<BetterAuthRuntimeOptions>;
|
|
138
71
|
//#endregion
|
|
139
72
|
//#region src/guards/auth.guard.d.ts
|
|
140
|
-
declare class AuthGuard implements CanActivate {
|
|
73
|
+
export declare class AuthGuard implements CanActivate {
|
|
141
74
|
private readonly auth;
|
|
142
75
|
private readonly opts;
|
|
143
76
|
private readonly reflector;
|
|
144
|
-
constructor(auth: BetterAuthService, opts:
|
|
145
|
-
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
146
|
-
}
|
|
147
|
-
//#endregion
|
|
148
|
-
//#region src/guards/roles.guard.d.ts
|
|
149
|
-
declare class RolesGuard implements CanActivate {
|
|
150
|
-
private readonly reflector;
|
|
151
|
-
canActivate(context: ExecutionContext): boolean;
|
|
152
|
-
}
|
|
153
|
-
//#endregion
|
|
154
|
-
//#region src/guards/permission.guard.d.ts
|
|
155
|
-
/**
|
|
156
|
-
* Enforces the `@RequirePermission(...)` metadata against the `@velajs/authz`
|
|
157
|
-
* engine. For each required permission it calls `authz.can(identity, perm)`,
|
|
158
|
-
* requiring **all** of them (AND semantics — contrast {@link RolesGuard}, which
|
|
159
|
-
* is OR over roles). The caller's `Identity` is derived from the better-auth
|
|
160
|
-
* user that {@link AuthGuard} placed in canonical request-local auth state, so this guard must
|
|
161
|
-
* run *after* `AuthGuard` (e.g. `@UseGuards(AuthGuard, PermissionGuard)`).
|
|
162
|
-
*
|
|
163
|
-
* `AUTHZ` is resolved at request time from the per-request container. Exactly
|
|
164
|
-
* one reachable engine is required; zero or multiple registrations deny rather
|
|
165
|
-
* than selecting one by import order.
|
|
166
|
-
*
|
|
167
|
-
* Fail-closed on every abnormal path — no branch grants access on missing
|
|
168
|
-
* wiring or a missing caller:
|
|
169
|
-
* - no required permissions → allow (nothing to enforce);
|
|
170
|
-
* - `AUTHZ` unresolvable (`AuthzModule` not registered) → deny (`ForbiddenException`);
|
|
171
|
-
* - no authenticated user in request-local auth state → deny;
|
|
172
|
-
* - any single required permission not granted → deny.
|
|
173
|
-
*
|
|
174
|
-
* The guard is stateless (no injected dependencies), so it is safe to register
|
|
175
|
-
* as a plain provided guard.
|
|
176
|
-
*/
|
|
177
|
-
declare class PermissionGuard implements CanActivate {
|
|
178
|
-
private readonly reflector;
|
|
77
|
+
constructor(auth: BetterAuthService, opts: BetterAuthRuntimeOptions);
|
|
179
78
|
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
180
79
|
}
|
|
181
80
|
//#endregion
|
|
182
81
|
//#region src/decorators/current-user.decorator.d.ts
|
|
183
|
-
declare const CurrentUser: (data?: unknown, ...pipes: import("@velajs/vela").PipeType[]) => ParameterDecorator;
|
|
82
|
+
export declare const CurrentUser: (data?: unknown, ...pipes: import("@velajs/vela").PipeType[]) => ParameterDecorator;
|
|
184
83
|
//#endregion
|
|
185
84
|
//#region src/decorators/current-session.decorator.d.ts
|
|
186
|
-
declare const CurrentSession: (data?: unknown, ...pipes: import("@velajs/vela").PipeType[]) => ParameterDecorator;
|
|
85
|
+
export declare const CurrentSession: (data?: unknown, ...pipes: import("@velajs/vela").PipeType[]) => ParameterDecorator;
|
|
187
86
|
//#endregion
|
|
188
87
|
//#region src/decorators/public.decorator.d.ts
|
|
189
|
-
declare const Public: import("@velajs/vela").ReflectableDecorator<boolean>;
|
|
190
|
-
declare const PUBLIC_KEY: string;
|
|
88
|
+
export declare const Public: import("@velajs/vela").ReflectableDecorator<boolean>;
|
|
89
|
+
export declare const PUBLIC_KEY: string;
|
|
191
90
|
//#endregion
|
|
192
91
|
//#region src/decorators/optional-auth.decorator.d.ts
|
|
193
|
-
declare const OptionalAuth: import("@velajs/vela").ReflectableDecorator<boolean>;
|
|
194
|
-
declare const OPTIONAL_AUTH_KEY: string;
|
|
195
|
-
//#endregion
|
|
196
|
-
//#region src/decorators/roles.decorator.d.ts
|
|
197
|
-
declare const Roles: import("@velajs/vela").ReflectableDecorator<string[]>;
|
|
198
|
-
declare const ROLES_KEY: string;
|
|
199
|
-
//#endregion
|
|
200
|
-
//#region src/decorators/require-permission.decorator.d.ts
|
|
201
|
-
/**
|
|
202
|
-
* Declares the `@velajs/authz` permission(s) required to reach a controller or
|
|
203
|
-
* route handler. Read via `Reflector` in an authorization guard, then checked
|
|
204
|
-
* against the caller's `Identity` with `authz.can(...)`.
|
|
205
|
-
*
|
|
206
|
-
* ```ts
|
|
207
|
-
* @RequirePermission(['posts:write'])
|
|
208
|
-
* @Post()
|
|
209
|
-
* create() { ... }
|
|
210
|
-
* ```
|
|
211
|
-
*
|
|
212
|
-
* The metadata is a plain `string[]` of permission strings in the granted-side
|
|
213
|
-
* format `@velajs/authz` matches (`resource:action`, or wildcards like
|
|
214
|
-
* `posts:*`). Handler-level metadata overrides class-level (standard
|
|
215
|
-
* `Reflector.getAllAndOverride` precedence).
|
|
216
|
-
*
|
|
217
|
-
* Semantics are **require-ALL** (AND): every listed permission must be granted
|
|
218
|
-
* for access — the `PermissionGuard` denies if any one is missing. This
|
|
219
|
-
* contrasts with `@Roles`, which is **OR** (any one of the listed roles
|
|
220
|
-
* suffices).
|
|
221
|
-
*/
|
|
222
|
-
declare const RequirePermission: import("@velajs/vela").ReflectableDecorator<string[]>;
|
|
223
|
-
declare const REQUIRE_PERMISSION_KEY: string;
|
|
92
|
+
export declare const OptionalAuth: import("@velajs/vela").ReflectableDecorator<boolean>;
|
|
93
|
+
export declare const OPTIONAL_AUTH_KEY: string;
|
|
224
94
|
//#endregion
|
|
225
95
|
//#region src/authz-bridge.d.ts
|
|
226
96
|
/**
|
|
@@ -228,13 +98,14 @@ declare const REQUIRE_PERMISSION_KEY: string;
|
|
|
228
98
|
* admin plugin. `role` may be a single role, a comma-separated list, or an
|
|
229
99
|
* array — {@link identityFromUser} normalizes all three.
|
|
230
100
|
*/
|
|
231
|
-
type AuthUser = User & {
|
|
101
|
+
type AuthUser = Pick<User, 'id'> & {
|
|
232
102
|
role?: string | string[] | null;
|
|
233
103
|
};
|
|
234
104
|
/** Stable issuer namespace used for better-auth session principals. */
|
|
235
|
-
declare const BETTER_AUTH_ISSUER = "better-auth";
|
|
105
|
+
export declare const BETTER_AUTH_ISSUER = "better-auth";
|
|
236
106
|
/**
|
|
237
|
-
*
|
|
107
|
+
* Pure authorization projection; this does not authenticate or publish trusted state.
|
|
108
|
+
* Adapts an already verified better-auth user into a stable `@velajs/authz` {@link Identity}.
|
|
238
109
|
* The issuer scopes `user.id` as both `subject` and the compatibility `userId`;
|
|
239
110
|
* the admin-plugin `role` field supplies local roles.
|
|
240
111
|
*
|
|
@@ -242,7 +113,7 @@ declare const BETTER_AUTH_ISSUER = "better-auth";
|
|
|
242
113
|
* request) maps to the zero-privilege identity `{ roles: [] }`, so downstream
|
|
243
114
|
* `can()` checks grant nothing.
|
|
244
115
|
*/
|
|
245
|
-
declare const identityFromUser: (user: AuthUser | null | undefined, issuer?: string, principalType?: 'user' | 'service') => Identity;
|
|
116
|
+
export declare const identityFromUser: (user: AuthUser | null | undefined, issuer?: string, principalType?: 'user' | 'service') => Identity;
|
|
246
117
|
/**
|
|
247
118
|
* The minimal slice of a better-auth access-control role consumed here. Both
|
|
248
119
|
* `createAccessControl(...).newRole(...)` and the standalone `role(...)` return
|
|
@@ -258,7 +129,7 @@ interface BetterAuthAcRole {
|
|
|
258
129
|
* permission strings — the granted-side format `@velajs/authz` matches
|
|
259
130
|
* (wildcards included).
|
|
260
131
|
*/
|
|
261
|
-
declare const permissionsFromAcRole: (role: BetterAuthAcRole) => string[];
|
|
132
|
+
export declare const permissionsFromAcRole: (role: BetterAuthAcRole) => string[];
|
|
262
133
|
/**
|
|
263
134
|
* Builds a fail-closed `@velajs/authz` {@link PermissionResolver} from a
|
|
264
135
|
* better-auth access-control role table (`{ roleName: acRole }` — the same map
|
|
@@ -274,7 +145,7 @@ declare const permissionsFromAcRole: (role: BetterAuthAcRole) => string[];
|
|
|
274
145
|
* await authz.can(identityFromUser(user), 'posts:write');
|
|
275
146
|
* ```
|
|
276
147
|
*/
|
|
277
|
-
declare const betterAuthAcResolver: (roles: Readonly<Record<string, BetterAuthAcRole>>) => PermissionResolver;
|
|
148
|
+
export declare const betterAuthAcResolver: (roles: Readonly<Record<string, BetterAuthAcRole>>) => PermissionResolver;
|
|
278
149
|
//#endregion
|
|
279
|
-
export {
|
|
150
|
+
export { type AuthUser, type BetterAuthAcRole, type BetterAuthInstance, type BetterAuthModuleOptions, type BetterAuthRuntimeOptions, BetterAuthService, type Session, type User };
|
|
280
151
|
//# sourceMappingURL=index.d.ts.map
|