@velajs/better-auth 0.6.0 → 1.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/README.md +19 -14
  3. package/dist/better-auth.service-BMkyFX-w.js +63 -0
  4. package/dist/better-auth.service-BMkyFX-w.js.map +1 -0
  5. package/dist/index.d.ts +280 -12
  6. package/dist/index.js +581 -15
  7. package/dist/index.js.map +1 -0
  8. package/dist/testing/index.d.ts +50 -2
  9. package/dist/testing/index.js +60 -3
  10. package/dist/testing/index.js.map +1 -0
  11. package/package.json +62 -42
  12. package/dist/better-auth.controller.d.ts +0 -21
  13. package/dist/better-auth.controller.js +0 -68
  14. package/dist/better-auth.module.d.ts +0 -52
  15. package/dist/better-auth.module.js +0 -138
  16. package/dist/better-auth.service.d.ts +0 -42
  17. package/dist/better-auth.service.js +0 -51
  18. package/dist/better-auth.tokens.d.ts +0 -5
  19. package/dist/better-auth.tokens.js +0 -4
  20. package/dist/better-auth.types.d.ts +0 -11
  21. package/dist/better-auth.types.js +0 -1
  22. package/dist/decorators/current-session.decorator.d.ts +0 -1
  23. package/dist/decorators/current-session.decorator.js +0 -7
  24. package/dist/decorators/current-user.decorator.d.ts +0 -1
  25. package/dist/decorators/current-user.decorator.js +0 -7
  26. package/dist/decorators/optional-auth.decorator.d.ts +0 -2
  27. package/dist/decorators/optional-auth.decorator.js +0 -5
  28. package/dist/decorators/public.decorator.d.ts +0 -2
  29. package/dist/decorators/public.decorator.js +0 -5
  30. package/dist/decorators/roles.decorator.d.ts +0 -2
  31. package/dist/decorators/roles.decorator.js +0 -5
  32. package/dist/guards/auth.guard.d.ts +0 -10
  33. package/dist/guards/auth.guard.js +0 -68
  34. package/dist/guards/roles.guard.d.ts +0 -5
  35. package/dist/guards/roles.guard.js +0 -36
  36. package/dist/testing/acting-as.d.ts +0 -46
  37. package/dist/testing/acting-as.js +0 -70
package/CHANGELOG.md CHANGED
@@ -1,10 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - a468b57: Run guards before ordinary identity parameters, install authentication globally and deny application routes by default, remove the insecure `defaultPolicy: 'allow'` mode and implicit auth-path bypass, enforce canonical auth mount paths, reject ambiguous authorization engines, and key module instances by the actual auth/factory reference. Anonymous routes must now use explicit `@Public()` or `@OptionalAuth()` metadata. Verified sessions now publish Vela's framework-owned principal identity and, when present, the Better Auth organization plugin's `activeOrganizationId` so downstream throttling can partition by principal and tenant before IP fallback.
8
+
9
+ ## 0.6.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 89f5473: Modernize the package build, validation, and release toolchain.
14
+
3
15
  ## 0.4.0 (2026-07-04)
4
16
 
5
17
  - Rebuilt on vela 1.11 `defineModule` + `lazyProvider` + `provideGlobal` (lazy auth-builder deferral preserved; public API unchanged). Requires `@velajs/vela >=1.11.0`.
6
18
 
7
-
8
19
  All notable changes to `@velajs/better-auth` are documented here. The format
9
20
  follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
10
21
 
package/README.md CHANGED
@@ -8,13 +8,13 @@ pnpm add @velajs/better-auth better-auth
8
8
 
9
9
  ## Quick start
10
10
 
11
- Construct your better-auth instance once, hand it to `BetterAuthModule.forRoot`, then use `AuthGuard` + `@CurrentUser()` like any other vela primitive.
11
+ Construct your better-auth instance once and hand it to `BetterAuthModule.forRoot`. The module installs `AuthGuard` application-wide by default; use `@CurrentUser()` on authenticated routes and mark the small anonymous surface explicitly.
12
12
 
13
13
  ```ts
14
14
  import { betterAuth } from 'better-auth';
15
- import { Module, Controller, Get, UseGuards, VelaFactory } from '@velajs/vela';
15
+ import { Module, Controller, Get, VelaFactory } from '@velajs/vela';
16
16
  import {
17
- BetterAuthModule, AuthGuard, CurrentUser, Public,
17
+ BetterAuthModule, CurrentUser, Public,
18
18
  } from '@velajs/better-auth';
19
19
 
20
20
  const auth = betterAuth({
@@ -24,7 +24,6 @@ const auth = betterAuth({
24
24
  });
25
25
 
26
26
  @Controller('/me')
27
- @UseGuards(AuthGuard)
28
27
  class MeController {
29
28
  @Get() me(@CurrentUser() user: { id: string; email: string }) {
30
29
  return { id: user.id, email: user.email };
@@ -35,7 +34,7 @@ class MeController {
35
34
  }
36
35
 
37
36
  @Module({
38
- imports: [BetterAuthModule.forRoot({ auth, isGlobal: true })],
37
+ imports: [BetterAuthModule.forRoot({ auth })],
39
38
  controllers: [MeController],
40
39
  })
41
40
  class AppModule {}
@@ -51,13 +50,15 @@ export default app; // edge-compatible (.fetch)
51
50
  ```ts
52
51
  BetterAuthModule.forRoot({
53
52
  auth, // pre-constructed betterAuth({ ... }) instance
53
+ issuer: 'my-app:better-auth', // stable namespace paired with user ids
54
54
  basePath: '/api/auth', // default — must match your better-auth config
55
- isGlobal: false, // register AuthGuard as APP_GUARD (deny-by-default)
56
- defaultPolicy: 'deny', // 'deny' | 'allow' for unauthenticated requests
55
+ isGlobal: true, // default — register AuthGuard as APP_GUARD
57
56
  mountHandler: true, // mount /api/auth/* catch-all controller
58
57
  });
59
58
  ```
60
59
 
60
+ Authentication has no allow-by-default compatibility mode. Use `@Public(true)` for routes that intentionally skip authentication, or `@OptionalAuth(true)` when the route accepts an anonymous identity. `isGlobal: false` is intended only for applications that install an equivalent global authentication guard themselves.
61
+
61
62
  ## Three composition patterns
62
63
 
63
64
  ### Pattern A — inline (simplest)
@@ -170,26 +171,30 @@ Under `forRootAsync`, the underlying `betterAuth({...})` instance is constructed
170
171
 
171
172
  | Decorator | Purpose |
172
173
  | ------------------- | ------------------------------------------------------------------------ |
173
- | `@CurrentUser()` | Lazy parameter — better-auth `User` from the request (read by AuthGuard) |
174
- | `@CurrentSession()` | Lazy parameter — better-auth `Session` |
174
+ | `@CurrentUser()` | Better-auth `User` from the request after guards run |
175
+ | `@CurrentSession()` | Better-auth `Session` after guards run |
175
176
  | `@Public(true)` | Class or method — bypass AuthGuard entirely |
176
177
  | `@OptionalAuth(true)` | Class or method — populate user if present, never throw 401 |
177
178
  | `@Roles(['admin'])` | Method — read by `RolesGuard`. Compares against `user.role`. |
178
179
 
179
- `@CurrentUser()` returns a lazy proxy. It's always object-truthy (because it's a proxy). When auth is optional, probe a property instead of `!!user`:
180
+ Optional identities are ordinary values: an anonymous caller receives the actual `undefined`, so normal truthiness checks are safe.
180
181
 
181
182
  ```ts
182
183
  handle(@CurrentUser() user: User | undefined) {
183
- return { hasUser: user?.id != null }; // ✓ correct
184
+ return { hasUser: Boolean(user) };
184
185
  }
185
186
  ```
186
187
 
187
188
  ## Guards
188
189
 
189
- - **`AuthGuard`** — singleton. Reads `Authorization` header / cookies via `auth.api.getSession`, populates `REQUEST_CONTEXT`. Honors `@Public()` and `@OptionalAuth()` overrides. Always lets requests under `basePath` through (so the catch-all controller can run unauthenticated).
190
+ - **`AuthGuard`** — singleton. Reads `Authorization` header / cookies via `auth.api.getSession`, populates `REQUEST_CONTEXT`, and publishes Vela's trusted principal/tenant identity 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.
190
191
  - **`RolesGuard`** — singleton. Reads `@Roles([...])` metadata, compares against `user.role`. Use with `@UseGuards(AuthGuard, RolesGuard)` — order matters.
191
192
 
192
- Global registration: pass `isGlobal: true` to `forRoot` (binds AuthGuard to `APP_GUARD`). Routes are deny-by-default; mark public ones with `@Public(true)`.
193
+ 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
+
195
+ When using `ThrottlerModule`, import Better Auth first. Vela then rate-limits by
196
+ the verified issuer, subject, principal type, and active organization before it
197
+ falls back to a platform-attested client address.
193
198
 
194
199
  ## Edge-safe DB adapters
195
200
 
@@ -223,7 +228,7 @@ class CustomCatchallController {
223
228
  }
224
229
  ```
225
230
 
226
- Pass `basePath: '/auth'` to `BetterAuthModule.forRoot` so `AuthGuard` skips the right paths, and keep your `betterAuth({ basePath: '/auth' })` config in sync.
231
+ Pass `basePath: '/auth'` to `BetterAuthModule.forRoot` to mount the generated controller there, and keep your `betterAuth({ basePath: '/auth' })` config in sync. A custom catch-all must carry `@Public(true)` itself. Base paths must be canonical absolute paths: no root mount, trailing slash, wildcards, query/fragment, backslashes, or dot segments.
227
232
 
228
233
  ## License
229
234
 
@@ -0,0 +1,63 @@
1
+ import { Inject, Injectable, InjectionToken } from "@velajs/vela";
2
+ //#region \0@oxc-project+runtime@0.139.0/helpers/esm/decorateMetadata.js
3
+ function __decorateMetadata(k, v) {
4
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
5
+ }
6
+ //#endregion
7
+ //#region \0@oxc-project+runtime@0.139.0/helpers/esm/decorateParam.js
8
+ function __decorateParam(paramIndex, decorator) {
9
+ return function(target, key) {
10
+ decorator(target, key, paramIndex);
11
+ };
12
+ }
13
+ //#endregion
14
+ //#region \0@oxc-project+runtime@0.139.0/helpers/esm/decorate.js
15
+ function __decorate(decorators, target, key, desc) {
16
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
17
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
18
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
19
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
20
+ }
21
+ //#endregion
22
+ //#region src/better-auth.service.ts
23
+ /**
24
+ * Internal token holding the auth-construction closure with its inject deps
25
+ * closed over. Resolves cheaply at module load (just captures references);
26
+ * the inner call happens lazily on first auth use (see `BetterAuthService`).
27
+ *
28
+ * Not exported from the public surface — only the service consumes it.
29
+ */
30
+ const BETTER_AUTH_BUILDER = new InjectionToken("vela.better-auth.Builder");
31
+ let BetterAuthService = class BetterAuthService {
32
+ build;
33
+ cached;
34
+ constructor(build) {
35
+ this.build = build;
36
+ }
37
+ /**
38
+ * The underlying better-auth instance. Constructed once on first access.
39
+ * Safe to call from any request-time code path (guards, controllers,
40
+ * services invoked from handlers).
41
+ */
42
+ get auth() {
43
+ if (!this.cached) this.cached = this.build();
44
+ return this.cached;
45
+ }
46
+ /** Convenience accessor — equivalent to `service.auth.api`. */
47
+ get api() {
48
+ return this.auth.api;
49
+ }
50
+ /** Convenience accessor — equivalent to `service.auth.handler`. */
51
+ get handler() {
52
+ return this.auth.handler;
53
+ }
54
+ };
55
+ BetterAuthService = __decorate([
56
+ Injectable(),
57
+ __decorateParam(0, Inject(BETTER_AUTH_BUILDER)),
58
+ __decorateMetadata("design:paramtypes", [Function])
59
+ ], BetterAuthService);
60
+ //#endregion
61
+ export { __decorateMetadata as a, __decorateParam as i, BetterAuthService as n, __decorate as r, BETTER_AUTH_BUILDER as t };
62
+
63
+ //# sourceMappingURL=better-auth.service-BMkyFX-w.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"better-auth.service-BMkyFX-w.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 bindings are populated 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 {\n private cached: BetterAuthInstance | undefined;\n\n constructor(@Inject(BETTER_AUTH_BUILDER) private readonly build: () => BetterAuthInstance) {}\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(): BetterAuthInstance {\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(): BetterAuthInstance['api'] {\n return this.auth.api;\n }\n\n /** Convenience accessor — equivalent to `service.auth.handler`. */\n get handler(): BetterAuthInstance['handler'] {\n return this.auth.handler;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,MAAa,sBAAsB,IAAI,eACrC,0BACF;AAoBO,IAAA,oBAAA,MAAM,kBAAkB;CAG6B;CAF1D;CAEA,YAAY,OAA+E;EAAjC,KAAA,QAAA;CAAkC;;;;;;CAO5F,IAAI,OAA2B;EAC7B,IAAI,CAAC,KAAK,QAAQ,KAAK,SAAS,KAAK,MAAM;EAC3C,OAAO,KAAK;CACd;;CAGA,IAAI,MAAiC;EACnC,OAAO,KAAK,KAAK;CACnB;;CAGA,IAAI,UAAyC;EAC3C,OAAO,KAAK,KAAK;CACnB;AACF;;CAzBC,WAAW;oBAIG,OAAO,mBAAmB,CAAA"}
package/dist/index.d.ts CHANGED
@@ -1,12 +1,280 @@
1
- export { BetterAuthModule } from './better-auth.module';
2
- export { BetterAuthService } from './better-auth.service';
3
- export { BetterAuthCatchallController, createBetterAuthCatchallController, } from './better-auth.controller';
4
- export { BETTER_AUTH_OPTIONS, AUTH_USER_KEY, AUTH_SESSION_KEY, } from './better-auth.tokens';
5
- export { AuthGuard } from './guards/auth.guard';
6
- export { RolesGuard } from './guards/roles.guard';
7
- export { CurrentUser } from './decorators/current-user.decorator';
8
- export { CurrentSession } from './decorators/current-session.decorator';
9
- export { Public, PUBLIC_KEY } from './decorators/public.decorator';
10
- export { OptionalAuth, OPTIONAL_AUTH_KEY } from './decorators/optional-auth.decorator';
11
- export { Roles, ROLES_KEY } from './decorators/roles.decorator';
12
- export type { BetterAuthInstance, BetterAuthModuleOptions, Session, User, } from './better-auth.types';
1
+ 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
+ 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
+ //#region src/better-auth.module.d.ts
24
+ /**
25
+ * Options for {@link BetterAuthModule.forRootAsync}.
26
+ *
27
+ * The `Inject` type parameter captures the literal `inject` tuple at the call
28
+ * site (via `const` inference) so `useFactory` parameters are typed from the
29
+ * inject array, position-by-position — no `as const`, no `(...deps: any[])`:
30
+ *
31
+ * ```ts
32
+ * BetterAuthModule.forRootAsync({
33
+ * inject: [D1Service, ConfigService], // captured as readonly tuple
34
+ * useFactory: (d1, config) => // d1: D1Service, config: ConfigService
35
+ * betterAuth({ database: drizzleAdapter(drizzle(d1.database), ...) }),
36
+ * });
37
+ * ```
38
+ */
39
+ interface ForRootAsyncOptions<Inject extends readonly Token<unknown>[] = readonly Token<unknown>[]> {
40
+ inject?: Inject;
41
+ imports?: DynamicModule['imports'];
42
+ useFactory: (...deps: InferTokens<Inject>) => BetterAuthInstance;
43
+ isGlobal?: boolean;
44
+ mountHandler?: boolean;
45
+ basePath?: string;
46
+ issuer?: string;
47
+ /** @deprecated Authentication is deny-by-default. Only `'deny'` is accepted. */
48
+ defaultPolicy?: 'deny';
49
+ key?: string;
50
+ }
51
+ declare class BetterAuthModule {
52
+ /**
53
+ * Synchronous registration. The auth instance is constructed by the consumer
54
+ * at module-load time and passed in directly. Use this when the inputs to
55
+ * `betterAuth({...})` are available at startup (Node apps with a static DB
56
+ * connection, in-memory adapters, etc.).
57
+ */
58
+ static forRoot(options: BetterAuthModuleOptions & {
59
+ isGlobal?: boolean;
60
+ key?: string;
61
+ }): DynamicModule;
62
+ /**
63
+ * Deferred / DI-driven registration. The user factory runs **lazily**, on the
64
+ * first time anything reads `BetterAuthService.auth` (or `.api` / `.handler`).
65
+ * In normal request handling that's `AuthGuard.canActivate` or the catch-all
66
+ * controller's `.handle`. At module load the factory does NOT run — it's only
67
+ * captured behind {@link lazyProvider}'s memoized thunk. This is what makes
68
+ * Cloudflare bindings (D1, KV, R2) work: the binding isn't ready at boot, but
69
+ * it IS by the time a request flows through and the guard / catch-all reads
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).
102
+ */
103
+ get auth(): BetterAuthInstance;
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'];
108
+ }
109
+ //#endregion
110
+ //#region src/better-auth.controller.d.ts
111
+ /**
112
+ * Build a catch-all controller that mounts better-auth's handler at `basePath`
113
+ * (default `/api/auth`). This is a factory because vela reads a controller's
114
+ * route off the class at decoration time, so a custom base path needs its own
115
+ * decorated class — the path can't be parametrized on a single shared class.
116
+ *
117
+ * Two base paths to keep consistent:
118
+ * - this `basePath` is RELATIVE to vela's `globalPrefix` (always prepended);
119
+ * - better-auth routes against its OWN absolute `basePath` (the one you pass to
120
+ * `betterAuth({ basePath })`), which must equal `globalPrefix + basePath`.
121
+ *
122
+ * Both default to `/api/auth`, so the no-prefix / no-config case just works.
123
+ */
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;
131
+ //#endregion
132
+ //#region src/better-auth.tokens.d.ts
133
+ declare const BETTER_AUTH_OPTIONS: InjectionToken<BetterAuthModuleOptions>;
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;
138
+ //#endregion
139
+ //#region src/guards/auth.guard.d.ts
140
+ declare class AuthGuard implements CanActivate {
141
+ private readonly auth;
142
+ private readonly opts;
143
+ private readonly reflector;
144
+ constructor(auth: BetterAuthService, opts: BetterAuthModuleOptions);
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;
179
+ canActivate(context: ExecutionContext): Promise<boolean>;
180
+ }
181
+ //#endregion
182
+ //#region src/decorators/current-user.decorator.d.ts
183
+ declare const CurrentUser: (data?: unknown, ...pipes: import("@velajs/vela").PipeType[]) => ParameterDecorator;
184
+ //#endregion
185
+ //#region src/decorators/current-session.decorator.d.ts
186
+ declare const CurrentSession: (data?: unknown, ...pipes: import("@velajs/vela").PipeType[]) => ParameterDecorator;
187
+ //#endregion
188
+ //#region src/decorators/public.decorator.d.ts
189
+ declare const Public: import("@velajs/vela").ReflectableDecorator<boolean>;
190
+ declare const PUBLIC_KEY: string;
191
+ //#endregion
192
+ //#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;
224
+ //#endregion
225
+ //#region src/authz-bridge.d.ts
226
+ /**
227
+ * A better-auth user carrying the optional `role` field contributed by the
228
+ * admin plugin. `role` may be a single role, a comma-separated list, or an
229
+ * array — {@link identityFromUser} normalizes all three.
230
+ */
231
+ type AuthUser = User & {
232
+ role?: string | string[] | null;
233
+ };
234
+ /** Stable issuer namespace used for better-auth session principals. */
235
+ declare const BETTER_AUTH_ISSUER = "better-auth";
236
+ /**
237
+ * Adapts a better-auth user into a stable `@velajs/authz` {@link Identity}.
238
+ * The issuer scopes `user.id` as both `subject` and the compatibility `userId`;
239
+ * the admin-plugin `role` field supplies local roles.
240
+ *
241
+ * Fail-closed: a missing user (`null`/`undefined`, i.e. an unauthenticated
242
+ * request) maps to the zero-privilege identity `{ roles: [] }`, so downstream
243
+ * `can()` checks grant nothing.
244
+ */
245
+ declare const identityFromUser: (user: AuthUser | null | undefined, issuer?: string, principalType?: 'user' | 'service') => Identity;
246
+ /**
247
+ * The minimal slice of a better-auth access-control role consumed here. Both
248
+ * `createAccessControl(...).newRole(...)` and the standalone `role(...)` return
249
+ * `{ authorize, statements }`; `statements` is the `{ resource: actions[] }`
250
+ * grant map for that role — the only accessor {@link betterAuthAcResolver}
251
+ * reads.
252
+ */
253
+ interface BetterAuthAcRole {
254
+ readonly statements: Readonly<Record<string, readonly string[]>>;
255
+ }
256
+ /**
257
+ * Flattens a better-auth AC role's `statements` into `resource:action`
258
+ * permission strings — the granted-side format `@velajs/authz` matches
259
+ * (wildcards included).
260
+ */
261
+ declare const permissionsFromAcRole: (role: BetterAuthAcRole) => string[];
262
+ /**
263
+ * Builds a fail-closed `@velajs/authz` {@link PermissionResolver} from a
264
+ * better-auth access-control role table (`{ roleName: acRole }` — the same map
265
+ * shape passed to better-auth's admin/organization plugins). An identity's
266
+ * `roles` are unioned into their granted permission strings; unknown roles
267
+ * contribute nothing.
268
+ *
269
+ * ```ts
270
+ * const ac = createAccessControl({ posts: ['read', 'write'] });
271
+ * const authz = createAuthz({
272
+ * resolver: betterAuthAcResolver({ editor: ac.newRole({ posts: ['write'] }) }),
273
+ * });
274
+ * await authz.can(identityFromUser(user), 'posts:write');
275
+ * ```
276
+ */
277
+ declare const betterAuthAcResolver: (roles: Readonly<Record<string, BetterAuthAcRole>>) => PermissionResolver;
278
+ //#endregion
279
+ export { AUTH_ISSUER_KEY, AUTH_PRINCIPAL_TYPE_KEY, AUTH_SESSION_KEY, AUTH_USER_KEY, AuthGuard, type AuthUser, BETTER_AUTH_ISSUER, BETTER_AUTH_OPTIONS, type BetterAuthAcRole, BetterAuthCatchallController, type BetterAuthInstance, BetterAuthModule, type BetterAuthModuleOptions, BetterAuthService, CurrentSession, CurrentUser, OPTIONAL_AUTH_KEY, OptionalAuth, PUBLIC_KEY, PermissionGuard, Public, REQUIRE_PERMISSION_KEY, ROLES_KEY, RequirePermission, Roles, RolesGuard, type Session, type User, betterAuthAcResolver, createBetterAuthCatchallController, identityFromUser, permissionsFromAcRole };
280
+ //# sourceMappingURL=index.d.ts.map