@velajs/better-auth 2.0.0 → 3.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 CHANGED
@@ -1,5 +1,98 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - Publish module-based Workers on the unused 3.x stable release line. Earlier experimental 2.0.0 registry versions are immutable and do not contain this release. Upgrade the framework and integrations together; see docs/module-workers.md for queue bootstrap, native delivery, RPC modules and async root migration details.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @velajs/authz@3.0.0
13
+ - @velajs/vela@3.0.0
14
+
15
+ ## 2.0.0
16
+
17
+ ### Major Changes
18
+
19
+ - a2d2692: Require the Vela 2 module/runtime peer line. Packages that raise their framework or adapter peer requirement ship a major version so existing 1.x installations are not offered an incompatible patch release. Upgrade the related framework integrations together; native queue/bootstrap migration is documented in docs/module-workers.md.
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [a2d2692]
24
+ - Updated dependencies [b99d71a]
25
+ - @velajs/authz@2.0.0
26
+ - @velajs/vela@2.0.0
27
+
28
+ ## 1.22.2
29
+
30
+ ### Patch Changes
31
+
32
+ - c5a3cb0: Preserve authentication payload through verified tenant admission while retaining
33
+ invalidation on expiry, clear and reauthentication. Add explicit HTTP-backed
34
+ execution-context identity binding for custom dispatchers, and add a redacting
35
+ Secret value with runtime-private signing
36
+ credentials. Existing authentication and signing entrypoints remain compatible.
37
+ - Updated dependencies [c6a43a6]
38
+ - Updated dependencies [bbe62d4]
39
+ - Updated dependencies [a6ef933]
40
+ - Updated dependencies [dae3654]
41
+ - Updated dependencies [77cca9e]
42
+ - Updated dependencies [b9f75f5]
43
+ - Updated dependencies [df47ea8]
44
+ - Updated dependencies [af019bf]
45
+ - Updated dependencies [6df1059]
46
+ - Updated dependencies [bdd90a1]
47
+ - Updated dependencies [8a3923f]
48
+ - Updated dependencies [c7d108b]
49
+ - Updated dependencies [1c7f635]
50
+ - Updated dependencies [636ffbc]
51
+ - Updated dependencies [54f8864]
52
+ - Updated dependencies [f49db45]
53
+ - Updated dependencies [4fde903]
54
+ - Updated dependencies [6a1b5b3]
55
+ - Updated dependencies [a95951a]
56
+ - Updated dependencies [9e82187]
57
+ - Updated dependencies [c5a3cb0]
58
+ - Updated dependencies [68c26a3]
59
+ - Updated dependencies [363fb71]
60
+ - Updated dependencies [de4e57e]
61
+ - Updated dependencies [0765aaa]
62
+ - Updated dependencies [6b7cf23]
63
+ - Updated dependencies [5205e58]
64
+ - Updated dependencies [ae45689]
65
+ - @velajs/vela@1.25.0
66
+ - @velajs/authz@1.23.0
67
+
68
+ ## 1.22.1
69
+
70
+ ### Patch Changes
71
+
72
+ - Publish from the public velajs/vela repository through GitHub Actions OIDC with required signed npm provenance. Attestations identify the source commit and release workflow for each package.
73
+ - Updated dependencies
74
+ - @velajs/authz@1.22.1
75
+ - @velajs/vela@1.22.1
76
+
77
+ ## 1.22.0
78
+
79
+ ### Minor Changes
80
+
81
+ - Continue the coordinated framework release on the 1.x line with the current checked provider, endpoint, identity, CRUD, live, and Studio APIs. Breaking API changes are accepted during this development phase; maintained applications use the current contracts.
82
+ - Publish from the pnpm packages workspace with TypeScript 7 and GitHub OIDC. Obsolete standalone examples have been removed; runnable applications live in apps/.
83
+ - Updated workspace dependencies
84
+ - @velajs/authz@1.22.0
85
+ - @velajs/vela@1.22.0
86
+
87
+ ## 2.0.1
88
+
89
+ ### Patch Changes
90
+
91
+ - Publish from the unified packages workspace with corrected repository paths, shared native tooling, TypeScript 7 checks, and npm OIDC releases. Runnable examples now live in apps/.
92
+ - Updated dependencies
93
+ - @velajs/vela@2.0.1
94
+ - @velajs/authz@2.0.1
95
+
3
96
  ## 2.0.0
4
97
 
5
98
  Native environment configuration and one immutable verified identity shared with provider-independent authorization.
package/README.md CHANGED
@@ -189,17 +189,17 @@ When using `ThrottlerModule`, import Better Auth first. Vela then rate-limits by
189
189
  the verified issuer, subject, principal type, and active organization before it
190
190
  falls back to a platform-attested client address.
191
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.
192
+ `BETTER_AUTH_OPTIONS` contains runtime configuration; read the auth instance from `BetterAuthService`. Use `createBetterAuthCatchallController()` for a manually mounted catch-all.
193
193
 
194
194
  ## Trusted identity and typing
195
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.
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 cannot grant roles or permissions.
197
197
 
198
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
199
 
200
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
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.
202
+ Use validated parameter decorators or core's trusted identity reader for authentication state. Import shared permission guards and decorators from `@velajs/authz/vela`.
203
203
 
204
204
  ## Edge-safe DB adapters
205
205
 
@@ -238,3 +238,7 @@ Pass `basePath: '/auth'` to `BetterAuthModule.forRoot` to mount the generated co
238
238
  ## License
239
239
 
240
240
  MIT
241
+
242
+ ## Authentication composition
243
+
244
+ TenantGuard can run after AuthGuard without losing CurrentUser or CurrentSession. Provider payload survives tenant enrichment, but expires or disappears on clearing or reauthentication. Read the admitted tenant from core identity or CurrentTenant. HTTP-backed custom dispatchers must bind their execution context with bindTrustedRequestContext and authenticate at the outer boundary; AuthGuard then reads existing authentication without a second session lookup.
@@ -49,8 +49,7 @@ type Session$1 = Session;
49
49
  * application code inject the same way: `@Inject(BetterAuthService)`.
50
50
  */
51
51
  declare class BetterAuthService<TAuth extends BetterAuthInstance = BetterAuthInstance> {
52
- private readonly build;
53
- private cached;
52
+ #private;
54
53
  constructor(build: () => TAuth);
55
54
  /**
56
55
  * The underlying better-auth instance. Constructed once on first access.
@@ -65,4 +64,4 @@ declare class BetterAuthService<TAuth extends BetterAuthInstance = BetterAuthIns
65
64
  }
66
65
  //#endregion
67
66
  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
67
+ //# sourceMappingURL=better-auth.service-CvmboUID.d.ts.map
@@ -29,10 +29,10 @@ function __decorate(decorators, target, key, desc) {
29
29
  */
30
30
  const BETTER_AUTH_BUILDER = new InjectionToken("vela.better-auth.Builder");
31
31
  let BetterAuthService = class BetterAuthService {
32
- build;
33
- cached;
32
+ #cached;
33
+ #build;
34
34
  constructor(build) {
35
- this.build = build;
35
+ this.#build = build;
36
36
  }
37
37
  /**
38
38
  * The underlying better-auth instance. Constructed once on first access.
@@ -40,8 +40,8 @@ let BetterAuthService = class BetterAuthService {
40
40
  * services invoked from handlers).
41
41
  */
42
42
  get auth() {
43
- if (!this.cached) this.cached = this.build();
44
- return this.cached;
43
+ if (!this.#cached) this.#cached = this.#build();
44
+ return this.#cached;
45
45
  }
46
46
  /** Convenience accessor — equivalent to `service.auth.api`. */
47
47
  get api() {
@@ -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-DurQ4JQf.js.map
63
+ //# sourceMappingURL=better-auth.service-SNg1YFTK.js.map
@@ -1 +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"}
1
+ {"version":3,"file":"better-auth.service-SNg1YFTK.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 #cached: TAuth | undefined;\n\n readonly #build: () => TAuth;\n\n constructor(@Inject(BETTER_AUTH_BUILDER) build: () => TAuth) {\n this.#build = build;\n }\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;CACpF;CAEA;CAEA,YAAY,OAAiD;EAC3D,KAAK,SAAS;CAChB;;;;;;CAOA,IAAI,OAAc;EAChB,IAAI,CAAC,KAAK,SAAS,KAAK,UAAU,KAAK,OAAO;EAC9C,OAAO,KAAK;CACd;;CAGA,IAAI,MAAoB;EACtB,OAAO,KAAK,KAAK;CACnB;;CAGA,IAAI,UAA4B;EAC9B,OAAO,KAAK,KAAK;CACnB;AACF;;CA7BC,WAAW;CAMG,gBAAA,GAAA,OAAO,mBAAmB,CAAA"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
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
+ import { a as Session, i as BetterAuthRuntimeOptions, n as BetterAuthInstance, o as User, r as BetterAuthModuleOptions, t as BetterAuthService } from "./better-auth.service-CvmboUID.js";
2
2
  import { CanActivate, DynamicModule, ExecutionContext, InferTokens, InjectionToken, Token, Type } from "@velajs/vela";
3
3
  import { Identity, PermissionResolver } from "@velajs/authz";
4
4
  //#region src/better-auth.module.d.ts
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { a as __decorateMetadata, i as __decorateParam, n as BetterAuthService, r as __decorate, t as BETTER_AUTH_BUILDER } from "./better-auth.service-DurQ4JQf.js";
2
- import { All, Controller, Inject, Injectable, InjectionToken, Reflector, Req, UnauthorizedException, clearTrustedRequestIdentity, createParamDecorator, defineProvider, getTrustedRequestIdentity, provideGlobal, setTrustedRequestIdentity, stableHash } from "@velajs/vela";
1
+ import { a as __decorateMetadata, i as __decorateParam, n as BetterAuthService, r as __decorate, t as BETTER_AUTH_BUILDER } from "./better-auth.service-SNg1YFTK.js";
2
+ import { All, Controller, Inject, Injectable, InjectionToken, Reflector, Req, UnauthorizedException, clearTrustedRequestIdentity, createParamDecorator, createTrustedRequestIdentityStore, defineProvider, getTrustedContextRequest, provideGlobal, setTrustedRequestIdentity, stableHash } from "@velajs/vela";
3
3
  import { getContextIdentity } from "@velajs/authz/vela";
4
4
  //#region src/decorators/public.decorator.ts
5
5
  const Public = Reflector.createDecorator({ key: "vela.auth.public" });
@@ -64,7 +64,7 @@ function createBetterAuthCatchallController(basePath = "/api/auth") {
64
64
  const BETTER_AUTH_OPTIONS = new InjectionToken("vela.BetterAuthOptions");
65
65
  //#endregion
66
66
  //#region src/auth-request-state.ts
67
- const sessions = /* @__PURE__ */ new WeakMap();
67
+ const sessions = createTrustedRequestIdentityStore();
68
68
  function beginAuthRequest(context) {
69
69
  clearTrustedRequestIdentity(context.getRequest());
70
70
  }
@@ -80,13 +80,11 @@ function authenticateRequest(context, data, issuer) {
80
80
  roles: data.roles,
81
81
  ...data.tenantId === void 0 ? {} : { tenantId: data.tenantId }
82
82
  });
83
- const identity = getTrustedRequestIdentity(request);
84
- if (identity) sessions.set(identity, data);
83
+ sessions.set(request, data);
85
84
  }
86
85
  function getAuthRequestState(context) {
87
- if (context.getType() !== "http") return void 0;
88
- const identity = getTrustedRequestIdentity(context.getRequest());
89
- return identity && sessions.get(identity);
86
+ const request = getTrustedContextRequest(context);
87
+ return request ? sessions.get(request) : void 0;
90
88
  }
91
89
  //#endregion
92
90
  //#region src/session-data.ts
@@ -186,6 +184,10 @@ let AuthGuard = class AuthGuard {
186
184
  if (getContextIdentity(context)) return true;
187
185
  throw new UnauthorizedException("Authentication required");
188
186
  }
187
+ if (context.getType() !== "http") {
188
+ if (getTrustedContextRequest(context) && (getAuthRequestState(context) || this.reflector.getAllAndOverride(Public, context) || this.reflector.getAllAndOverride(OptionalAuth, context))) return true;
189
+ throw new UnauthorizedException("Authentication required");
190
+ }
189
191
  beginAuthRequest(context);
190
192
  if (this.reflector.getAllAndOverride(Public, context)) return true;
191
193
  const data = validateSessionData(await this.auth.api.getSession({ headers: context.getRequest().headers }));
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/decorators/public.decorator.ts","../src/base-path.ts","../src/better-auth.controller.ts","../src/better-auth.tokens.ts","../src/auth-request-state.ts","../src/session-data.ts","../src/decorators/optional-auth.decorator.ts","../src/guards/auth.guard.ts","../src/better-auth.module.ts","../src/decorators/current-user.decorator.ts","../src/decorators/current-session.decorator.ts","../src/authz-bridge.ts"],"sourcesContent":["import { Reflector } from '@velajs/vela';\n\nexport const Public = Reflector.createDecorator<boolean>({ key: 'vela.auth.public' });\nexport const PUBLIC_KEY = Public.KEY;\n","export const DEFAULT_BETTER_AUTH_BASE_PATH = '/api/auth';\n\n/** Validate and canonicalize the route prefix used by the public auth controller. */\nexport function normalizeBetterAuthBasePath(value?: string): string {\n const basePath = value ?? DEFAULT_BETTER_AUTH_BASE_PATH;\n if (\n basePath.length === 0 ||\n basePath !== basePath.trim() ||\n !basePath.startsWith('/') ||\n basePath.startsWith('//') ||\n basePath === '/' ||\n basePath.endsWith('/') ||\n /[\\\\?#*]/u.test(basePath) ||\n /%(?:2e|2f|5c)/iu.test(basePath)\n ) {\n throw new Error(\n '@velajs/better-auth: basePath must be a canonical absolute path such as \"/api/auth\"',\n );\n }\n\n let decoded: string;\n try {\n decoded = decodeURIComponent(basePath);\n } catch {\n throw new Error('@velajs/better-auth: basePath contains invalid percent encoding');\n }\n if (decoded.split('/').some((segment) => segment === '.' || segment === '..')) {\n throw new Error('@velajs/better-auth: basePath must not contain dot segments');\n }\n return basePath;\n}\n","import { All, Controller, Inject, Injectable, Req, type Type } from '@velajs/vela';\nimport type { Context } from 'hono';\nimport { BetterAuthService } from './better-auth.service';\nimport { Public } from './decorators/public.decorator';\nimport { normalizeBetterAuthBasePath } from './base-path';\n\n/**\n * Build a catch-all controller that mounts better-auth's handler at `basePath`\n * (default `/api/auth`). This is a factory because vela reads a controller's\n * route off the class at decoration time, so a custom base path needs its own\n * decorated class — the path can't be parametrized on a single shared class.\n *\n * Two base paths to keep consistent:\n * - this `basePath` is RELATIVE to vela's `globalPrefix` (always prepended);\n * - better-auth routes against its OWN absolute `basePath` (the one you pass to\n * `betterAuth({ basePath })`), which must equal `globalPrefix + basePath`.\n *\n * Both default to `/api/auth`, so the no-prefix / no-config case just works.\n */\nexport function createBetterAuthCatchallController(basePath: string = '/api/auth'): Type {\n const normalizedBasePath = normalizeBetterAuthBasePath(basePath);\n @Public(true)\n @Controller(normalizedBasePath)\n @Injectable()\n class BetterAuthCatchallController {\n // Inject the service — its `.handler` getter triggers lazy construction\n // of the underlying betterAuth() instance on first access, AFTER any\n // runtime adapter middleware (Cloudflare env capture) has run.\n constructor(@Inject(BetterAuthService) private readonly auth: BetterAuthService) {}\n\n @All('/*')\n async handle(@Req() c: Context): Promise<Response> {\n return this.auth.handler(c.req.raw);\n }\n }\n return BetterAuthCatchallController;\n}\n","import { InjectionToken } from '@velajs/vela';\nimport type { BetterAuthRuntimeOptions } from './better-auth.types';\n\nexport const BETTER_AUTH_OPTIONS = new InjectionToken<BetterAuthRuntimeOptions>(\n 'vela.BetterAuthOptions',\n);\n","import {\n clearTrustedRequestIdentity,\n getTrustedRequestIdentity,\n setTrustedRequestIdentity,\n type ExecutionContext,\n type TrustedRequestIdentity,\n} from '@velajs/vela';\nimport type { SessionData } from './session-data';\n\n// This map stores provider payload, never a second authentication authority.\n// A clear, expiry, or identity replacement makes the payload unreachable.\nconst sessions = new WeakMap<TrustedRequestIdentity, SessionData>();\n\nexport function beginAuthRequest(context: ExecutionContext): void {\n clearTrustedRequestIdentity(context.getRequest());\n}\n\nexport function authenticateRequest(\n context: ExecutionContext,\n data: SessionData,\n issuer: string,\n): void {\n const request = context.getRequest();\n setTrustedRequestIdentity(request, {\n principal: { issuer, subject: data.user.id, principalType: 'user' },\n expiresAtMs: data.session.expiresAt.getTime(),\n roles: data.roles,\n ...(data.tenantId === undefined ? {} : { tenantId: data.tenantId }),\n });\n const identity = getTrustedRequestIdentity(request);\n if (identity) sessions.set(identity, data);\n}\n\nexport function getAuthRequestState(context: ExecutionContext): SessionData | undefined {\n if (context.getType() !== 'http') return undefined;\n const identity = getTrustedRequestIdentity(context.getRequest());\n return identity && sessions.get(identity);\n}\n","import type { Session, User } from './better-auth.types';\n\nexport interface SessionData {\n readonly user: User;\n readonly session: Session;\n readonly roles: readonly string[];\n readonly tenantId?: string;\n}\n\nfunction own(value: unknown, key: string): unknown {\n if (typeof value !== 'object' || value === null) return undefined;\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n return descriptor && 'value' in descriptor ? descriptor.value : undefined;\n}\n\nfunction requiredString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\nfunction date(value: unknown): Date | undefined {\n return value instanceof Date && Number.isFinite(value.getTime()) ? new Date(value) : undefined;\n}\n\nfunction optionalString(value: unknown): value is string | null | undefined {\n return value === undefined || value === null || typeof value === 'string';\n}\n\n/** Keep plugin data opaque; base model fields below are validated individually. */\nfunction dataProperties(value: object): Record<string, unknown> {\n return Object.fromEntries(Object.keys(value).map((key) => [key, own(value, key)]));\n}\n\n/** Validate the full Better Auth base models, not merely ids masquerading as them. */\nexport function validateSessionData(value: unknown): SessionData | undefined {\n try {\n const user = own(value, 'user');\n const session = own(value, 'session');\n if (\n typeof user !== 'object' ||\n user === null ||\n typeof session !== 'object' ||\n session === null\n ) {\n return undefined;\n }\n const id = own(user, 'id');\n const email = own(user, 'email');\n const name = own(user, 'name');\n const emailVerified = own(user, 'emailVerified');\n const image = own(user, 'image');\n const createdAt = date(own(user, 'createdAt'));\n const updatedAt = date(own(user, 'updatedAt'));\n const sessionId = own(session, 'id');\n const userId = own(session, 'userId');\n const token = own(session, 'token');\n const sessionCreatedAt = date(own(session, 'createdAt'));\n const sessionUpdatedAt = date(own(session, 'updatedAt'));\n const expiresAt = date(own(session, 'expiresAt'));\n const ipAddress = own(session, 'ipAddress');\n const userAgent = own(session, 'userAgent');\n const organization = own(session, 'activeOrganizationId');\n const role = own(user, 'role');\n let roles: string[] = [];\n if (role !== undefined && role !== null) {\n if (typeof role === 'string')\n roles = role\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean);\n else if (\n Array.isArray(role) &&\n role.every((entry: unknown): entry is string => typeof entry === 'string')\n ) {\n roles = role.map((entry: string) => entry.trim()).filter(Boolean);\n } else return undefined;\n }\n if (\n !requiredString(id) ||\n !requiredString(email) ||\n typeof name !== 'string' ||\n typeof emailVerified !== 'boolean' ||\n !optionalString(image) ||\n !createdAt ||\n !updatedAt ||\n !requiredString(sessionId) ||\n userId !== id ||\n !requiredString(token) ||\n !sessionCreatedAt ||\n !sessionUpdatedAt ||\n !expiresAt ||\n expiresAt.getTime() <= Date.now() ||\n !optionalString(ipAddress) ||\n !optionalString(userAgent) ||\n (organization !== undefined && organization !== null && !requiredString(organization))\n )\n return undefined;\n return {\n user: Object.freeze({\n ...dataProperties(user),\n id,\n email,\n name,\n emailVerified,\n createdAt,\n updatedAt,\n image,\n }),\n session: Object.freeze({\n ...dataProperties(session),\n id: sessionId,\n userId: id,\n token,\n createdAt: sessionCreatedAt,\n updatedAt: sessionUpdatedAt,\n expiresAt,\n ipAddress,\n userAgent,\n }),\n roles: Object.freeze(roles),\n ...(typeof organization === 'string' ? { tenantId: organization } : {}),\n };\n } catch {\n return undefined;\n }\n}\n","import { Reflector } from '@velajs/vela';\n\nexport const OptionalAuth = Reflector.createDecorator<boolean>({ key: 'vela.auth.optional' });\nexport const OPTIONAL_AUTH_KEY = OptionalAuth.KEY;\n","import {\n Inject,\n Injectable,\n Reflector,\n UnauthorizedException,\n type CanActivate,\n type ExecutionContext,\n} from '@velajs/vela';\nimport { getContextIdentity } from '@velajs/authz/vela';\nimport { BETTER_AUTH_OPTIONS } from '../better-auth.tokens';\nimport { BetterAuthService } from '../better-auth.service';\nimport type { BetterAuthRuntimeOptions } from '../better-auth.types';\nimport { authenticateRequest, beginAuthRequest } from '../auth-request-state';\nimport { validateSessionData } from '../session-data';\nimport { OptionalAuth } from '../decorators/optional-auth.decorator';\nimport { Public } from '../decorators/public.decorator';\n\n@Injectable()\nexport class AuthGuard implements CanActivate {\n private readonly reflector = new Reflector();\n\n constructor(\n @Inject(BetterAuthService) private readonly auth: BetterAuthService,\n @Inject(BETTER_AUTH_OPTIONS) private readonly opts: BetterAuthRuntimeOptions,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n // Frames trust only the authenticated connection attachment; HTTP cookies\n // and request payload never become ambient WebSocket authentication.\n if (context.getType() === 'ws') {\n if (getContextIdentity(context)) return true;\n throw new UnauthorizedException('Authentication required');\n }\n beginAuthRequest(context);\n if (this.reflector.getAllAndOverride(Public, context)) return true;\n\n const raw = await this.auth.api.getSession({ headers: context.getRequest().headers });\n const data = validateSessionData(raw);\n if (data) {\n authenticateRequest(context, data, this.opts.issuer ?? 'better-auth');\n return true;\n }\n if (this.reflector.getAllAndOverride(OptionalAuth, context)) return true;\n throw new UnauthorizedException('Authentication required');\n }\n}\n","import {\n defineProvider,\n provideGlobal,\n stableHash,\n type DynamicModule,\n type InferTokens,\n type Token,\n type Type,\n} from '@velajs/vela';\nimport { createBetterAuthCatchallController } from './better-auth.controller';\nimport { BetterAuthService, BETTER_AUTH_BUILDER } from './better-auth.service';\nimport { BETTER_AUTH_OPTIONS } from './better-auth.tokens';\nimport type {\n BetterAuthInstance,\n BetterAuthModuleOptions,\n BetterAuthRuntimeOptions,\n} from './better-auth.types';\nimport { AuthGuard } from './guards/auth.guard';\nimport { normalizeBetterAuthBasePath } from './base-path';\n\nconst referenceIds = new WeakMap<object, number>();\nconst explicitKeyClaims = new Map<\n string,\n { readonly kind: 'auth' | 'factory'; readonly reference: object; readonly shape: string }\n>();\nlet nextReferenceId = 1;\n\nfunction referenceId(reference: object): number {\n const existing = referenceIds.get(reference);\n if (existing !== undefined) return existing;\n const id = nextReferenceId++;\n referenceIds.set(reference, id);\n return id;\n}\n\nfunction claimExplicitKey(\n key: string,\n kind: 'auth' | 'factory',\n reference: object,\n shape: string,\n): string {\n if (key.length === 0 || key !== key.trim()) {\n throw new Error('@velajs/better-auth: an explicit module key must be a non-empty string');\n }\n const existing = explicitKeyClaims.get(key);\n if (\n existing !== undefined &&\n (existing.kind !== kind || existing.reference !== reference || existing.shape !== shape)\n ) {\n throw new Error(\n `@velajs/better-auth: explicit module key \"${key}\" is already bound to a different auth registration`,\n );\n }\n explicitKeyClaims.set(key, { kind, reference, shape });\n return `explicit:${key}:ref:${referenceId(reference)}`;\n}\n\n/** Structural options with defaults applied (everything but the auth instance). */\ninterface NormalizedOptions {\n basePath: string;\n issuer: string;\n isGlobal: boolean;\n mountHandler: boolean;\n}\n\nfunction normalize(options: BetterAuthRuntimeOptions): NormalizedOptions {\n const basePath = normalizeBetterAuthBasePath(options.basePath);\n const issuer = options.issuer ?? `better-auth:${basePath}`;\n if (issuer.length === 0 || issuer !== issuer.trim()) {\n throw new Error('@velajs/better-auth: issuer must be a non-empty stable namespace');\n }\n return {\n basePath,\n issuer,\n isGlobal: options.isGlobal ?? true,\n mountHandler: options.mountHandler ?? true,\n };\n}\n\n/** Providers, controllers, and exports shared by both entry points. */\nfunction commonContributions(n: NormalizedOptions): {\n providers: NonNullable<DynamicModule['providers']>;\n controllers: Type[];\n exports: DynamicModule['exports'];\n} {\n return {\n providers: [BetterAuthService, AuthGuard],\n controllers: n.mountHandler ? [createBetterAuthCatchallController(n.basePath)] : [],\n exports: [BetterAuthService, BETTER_AUTH_OPTIONS, AuthGuard],\n };\n}\n\n/**\n * Options for {@link BetterAuthModule.forRootAsync}.\n *\n * The `Inject` type parameter captures the literal `inject` tuple at the call\n * site (via `const` inference) so `useFactory` parameters are typed from the\n * inject array, position-by-position — no `as const`, no `(...deps: any[])`:\n *\n * ```ts\n * BetterAuthModule.forRootAsync({\n * inject: [WORKER_ENV, ConfigService], // captured as readonly tuple\n * useFactory: (env, config) => // inferred from the tokens\n * betterAuth({ database: drizzleAdapter(drizzle(env.DB), ...) }),\n * });\n * ```\n */\ninterface ForRootAsyncOptions<Inject extends readonly Token[] = readonly Token[]> {\n inject: Inject;\n imports?: DynamicModule['imports'];\n useFactory: (...deps: InferTokens<Inject>) => BetterAuthInstance;\n isGlobal?: boolean;\n mountHandler?: boolean;\n basePath?: string;\n issuer?: string;\n key?: string;\n}\n\nexport class BetterAuthModule {\n /**\n * Synchronous registration. The auth instance is constructed by the consumer\n * at module-load time and passed in directly. Use this when the inputs to\n * `betterAuth({...})` are available at startup (Node apps with a static DB\n * connection, in-memory adapters, etc.).\n */\n static forRoot(\n options: BetterAuthModuleOptions & { isGlobal?: boolean; key?: string },\n ): DynamicModule {\n const normalized = normalize(options);\n const shape = stableHash(normalized);\n const key =\n options.key === undefined\n ? `${shape}:auth:${referenceId(options.auth)}`\n : claimExplicitKey(options.key, 'auth', options.auth, shape);\n const common = commonContributions(normalized);\n return {\n module: BetterAuthModule,\n key,\n providers: [\n defineProvider(BETTER_AUTH_OPTIONS, { useValue: normalized }),\n defineProvider(BETTER_AUTH_BUILDER, { useValue: () => options.auth }),\n ...common.providers,\n ...(normalized.isGlobal ? provideGlobal('guard', AuthGuard) : []),\n ],\n controllers: common.controllers,\n exports: common.exports,\n };\n }\n\n /**\n * Deferred / DI-driven registration. The user factory runs **lazily**, on the\n * first time anything reads `BetterAuthService.auth` (or `.api` / `.handler`).\n * In normal request handling that's `AuthGuard.canActivate` or the catch-all\n * controller's `.handle`. At module load the factory does NOT run — it's only\n * captured in the checked builder provider. The Workers adapter supplies its\n * native environment before DI; the lazily constructed auth instance belongs\n * to that environment's application and never captures another app's bindings.\n */\n static forRootAsync<const Inject extends readonly Token[] = readonly Token[]>(\n options: ForRootAsyncOptions<Inject>,\n ): DynamicModule {\n const n = normalize(options);\n const common = commonContributions(n);\n const shape = stableHash({ ...n, inject: options.inject });\n const key =\n options.key === undefined\n ? `${shape}:factory:${referenceId(options.useFactory)}`\n : claimExplicitKey(options.key, 'factory', options.useFactory, shape);\n return {\n module: BetterAuthModule,\n key,\n imports: options.imports ?? [],\n providers: [\n defineProvider(BETTER_AUTH_OPTIONS, { useValue: n }),\n defineProvider(BETTER_AUTH_BUILDER, {\n inject: options.inject,\n useFactory:\n (...deps: InferTokens<Inject>) =>\n () =>\n options.useFactory(...deps),\n }),\n ...common.providers,\n ...(n.isGlobal ? provideGlobal('guard', AuthGuard) : []),\n ],\n controllers: common.controllers,\n exports: common.exports,\n };\n }\n}\n","import { createParamDecorator, type ExecutionContext } from '@velajs/vela';\nimport { getAuthRequestState } from '../auth-request-state';\nimport type { User } from '../better-auth.types';\n\nexport const CurrentUser = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext): User | undefined => {\n const state = getAuthRequestState(ctx);\n return state?.user;\n },\n);\n","import { createParamDecorator, type ExecutionContext } from '@velajs/vela';\nimport { getAuthRequestState } from '../auth-request-state';\nimport type { Session } from '../better-auth.types';\n\nexport const CurrentSession = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext): Session | undefined => {\n const state = getAuthRequestState(ctx);\n return state?.session;\n },\n);\n","import type { Identity, PermissionResolver } from '@velajs/authz';\nimport type { User } from './better-auth.types';\n\n/**\n * A better-auth user carrying the optional `role` field contributed by the\n * admin plugin. `role` may be a single role, a comma-separated list, or an\n * array — {@link identityFromUser} normalizes all three.\n */\nexport type AuthUser = Pick<User, 'id'> & { role?: string | string[] | null };\n\n/** Stable issuer namespace used for better-auth session principals. */\nexport const BETTER_AUTH_ISSUER = 'better-auth';\n\nconst normalizeRoles = (role: string | string[] | null | undefined): string[] => {\n if (!role) return [];\n // Strip empty entries and return a fresh array (never alias the caller's\n // input), matching the comma-string path below.\n if (Array.isArray(role)) return role.filter(Boolean);\n return role\n .split(',')\n .map((r) => r.trim())\n .filter(Boolean);\n};\n\n/**\n * Pure authorization projection; this does not authenticate or publish trusted state.\n * Adapts an already verified better-auth user into a stable `@velajs/authz` {@link Identity}.\n * The issuer scopes `user.id` as both `subject` and the compatibility `userId`;\n * the admin-plugin `role` field supplies local roles.\n *\n * Fail-closed: a missing user (`null`/`undefined`, i.e. an unauthenticated\n * request) maps to the zero-privilege identity `{ roles: [] }`, so downstream\n * `can()` checks grant nothing.\n */\nexport const identityFromUser = (\n user: AuthUser | null | undefined,\n issuer: string = BETTER_AUTH_ISSUER,\n principalType: 'user' | 'service' = 'user',\n): Identity => {\n if (!user || typeof user.id !== 'string' || user.id.length === 0) return { roles: [] };\n if (issuer.length === 0)\n throw new Error('@velajs/better-auth: identity issuer must be non-empty');\n return {\n issuer,\n subject: user.id,\n principalType,\n userId: user.id,\n roles: normalizeRoles(user.role),\n };\n};\n\n/**\n * The minimal slice of a better-auth access-control role consumed here. Both\n * `createAccessControl(...).newRole(...)` and the standalone `role(...)` return\n * `{ authorize, statements }`; `statements` is the `{ resource: actions[] }`\n * grant map for that role — the only accessor {@link betterAuthAcResolver}\n * reads.\n */\nexport interface BetterAuthAcRole {\n readonly statements: Readonly<Record<string, readonly string[]>>;\n}\n\n/**\n * Flattens a better-auth AC role's `statements` into `resource:action`\n * permission strings — the granted-side format `@velajs/authz` matches\n * (wildcards included).\n */\nexport const permissionsFromAcRole = (role: BetterAuthAcRole): string[] => {\n const permissions: string[] = [];\n for (const [resource, actions] of Object.entries(role.statements ?? {})) {\n for (const action of actions ?? []) permissions.push(`${resource}:${action}`);\n }\n return permissions;\n};\n\n/**\n * Builds a fail-closed `@velajs/authz` {@link PermissionResolver} from a\n * better-auth access-control role table (`{ roleName: acRole }` — the same map\n * shape passed to better-auth's admin/organization plugins). An identity's\n * `roles` are unioned into their granted permission strings; unknown roles\n * contribute nothing.\n *\n * ```ts\n * const ac = createAccessControl({ posts: ['read', 'write'] });\n * const authz = createAuthz({\n * resolver: betterAuthAcResolver({ editor: ac.newRole({ posts: ['write'] }) }),\n * });\n * await authz.can(identityFromUser(user), 'posts:write');\n * ```\n */\nexport const betterAuthAcResolver = (\n roles: Readonly<Record<string, BetterAuthAcRole>>,\n): PermissionResolver => {\n const grantsByRole = new Map<string, string[]>();\n for (const [name, role] of Object.entries(roles)) {\n grantsByRole.set(name, permissionsFromAcRole(role));\n }\n return {\n grants(identity: Identity): Set<string> {\n const out = new Set<string>();\n for (const name of identity.roles ?? []) {\n for (const permission of grantsByRole.get(name) ?? []) out.add(permission);\n }\n return out;\n },\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/decorators/public.decorator.ts","../src/base-path.ts","../src/better-auth.controller.ts","../src/better-auth.tokens.ts","../src/auth-request-state.ts","../src/session-data.ts","../src/decorators/optional-auth.decorator.ts","../src/guards/auth.guard.ts","../src/better-auth.module.ts","../src/decorators/current-user.decorator.ts","../src/decorators/current-session.decorator.ts","../src/authz-bridge.ts"],"sourcesContent":["import { Reflector } from '@velajs/vela';\n\nexport const Public = Reflector.createDecorator<boolean>({ key: 'vela.auth.public' });\nexport const PUBLIC_KEY = Public.KEY;\n","export const DEFAULT_BETTER_AUTH_BASE_PATH = '/api/auth';\n\n/** Validate and canonicalize the route prefix used by the public auth controller. */\nexport function normalizeBetterAuthBasePath(value?: string): string {\n const basePath = value ?? DEFAULT_BETTER_AUTH_BASE_PATH;\n if (\n basePath.length === 0 ||\n basePath !== basePath.trim() ||\n !basePath.startsWith('/') ||\n basePath.startsWith('//') ||\n basePath === '/' ||\n basePath.endsWith('/') ||\n /[\\\\?#*]/u.test(basePath) ||\n /%(?:2e|2f|5c)/iu.test(basePath)\n ) {\n throw new Error(\n '@velajs/better-auth: basePath must be a canonical absolute path such as \"/api/auth\"',\n );\n }\n\n let decoded: string;\n try {\n decoded = decodeURIComponent(basePath);\n } catch {\n throw new Error('@velajs/better-auth: basePath contains invalid percent encoding');\n }\n if (decoded.split('/').some((segment) => segment === '.' || segment === '..')) {\n throw new Error('@velajs/better-auth: basePath must not contain dot segments');\n }\n return basePath;\n}\n","import { All, Controller, Inject, Injectable, Req, type Type } from '@velajs/vela';\nimport type { Context } from 'hono';\nimport { BetterAuthService } from './better-auth.service';\nimport { Public } from './decorators/public.decorator';\nimport { normalizeBetterAuthBasePath } from './base-path';\n\n/**\n * Build a catch-all controller that mounts better-auth's handler at `basePath`\n * (default `/api/auth`). This is a factory because vela reads a controller's\n * route off the class at decoration time, so a custom base path needs its own\n * decorated class — the path can't be parametrized on a single shared class.\n *\n * Two base paths to keep consistent:\n * - this `basePath` is RELATIVE to vela's `globalPrefix` (always prepended);\n * - better-auth routes against its OWN absolute `basePath` (the one you pass to\n * `betterAuth({ basePath })`), which must equal `globalPrefix + basePath`.\n *\n * Both default to `/api/auth`, so the no-prefix / no-config case just works.\n */\nexport function createBetterAuthCatchallController(basePath: string = '/api/auth'): Type {\n const normalizedBasePath = normalizeBetterAuthBasePath(basePath);\n @Public(true)\n @Controller(normalizedBasePath)\n @Injectable()\n class BetterAuthCatchallController {\n // Inject the service — its `.handler` getter triggers lazy construction\n // of the underlying betterAuth() instance on first access, AFTER any\n // runtime adapter middleware (Cloudflare env capture) has run.\n constructor(@Inject(BetterAuthService) private readonly auth: BetterAuthService) {}\n\n @All('/*')\n async handle(@Req() c: Context): Promise<Response> {\n return this.auth.handler(c.req.raw);\n }\n }\n return BetterAuthCatchallController;\n}\n","import { InjectionToken } from '@velajs/vela';\nimport type { BetterAuthRuntimeOptions } from './better-auth.types';\n\nexport const BETTER_AUTH_OPTIONS = new InjectionToken<BetterAuthRuntimeOptions>(\n 'vela.BetterAuthOptions',\n);\n","import {\n clearTrustedRequestIdentity,\n createTrustedRequestIdentityStore,\n getTrustedContextRequest,\n setTrustedRequestIdentity,\n type ExecutionContext,\n} from '@velajs/vela';\nimport type { SessionData } from './session-data';\n\n// This map stores provider payload, never a second authentication authority.\n// A clear, expiry, or identity replacement makes the payload unreachable.\nconst sessions = createTrustedRequestIdentityStore<SessionData>();\n\nexport function beginAuthRequest(context: ExecutionContext): void {\n clearTrustedRequestIdentity(context.getRequest());\n}\n\nexport function authenticateRequest(\n context: ExecutionContext,\n data: SessionData,\n issuer: string,\n): void {\n const request = context.getRequest();\n setTrustedRequestIdentity(request, {\n principal: { issuer, subject: data.user.id, principalType: 'user' },\n expiresAtMs: data.session.expiresAt.getTime(),\n roles: data.roles,\n ...(data.tenantId === undefined ? {} : { tenantId: data.tenantId }),\n });\n sessions.set(request, data);\n}\n\nexport function getAuthRequestState(context: ExecutionContext): SessionData | undefined {\n const request = getTrustedContextRequest(context);\n return request ? sessions.get(request) : undefined;\n}\n","import type { Session, User } from './better-auth.types';\n\nexport interface SessionData {\n readonly user: User;\n readonly session: Session;\n readonly roles: readonly string[];\n readonly tenantId?: string;\n}\n\nfunction own(value: unknown, key: string): unknown {\n if (typeof value !== 'object' || value === null) return undefined;\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n return descriptor && 'value' in descriptor ? descriptor.value : undefined;\n}\n\nfunction requiredString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\nfunction date(value: unknown): Date | undefined {\n return value instanceof Date && Number.isFinite(value.getTime()) ? new Date(value) : undefined;\n}\n\nfunction optionalString(value: unknown): value is string | null | undefined {\n return value === undefined || value === null || typeof value === 'string';\n}\n\n/** Keep plugin data opaque; base model fields below are validated individually. */\nfunction dataProperties(value: object): Record<string, unknown> {\n return Object.fromEntries(Object.keys(value).map((key) => [key, own(value, key)]));\n}\n\n/** Validate the full Better Auth base models, not merely ids masquerading as them. */\nexport function validateSessionData(value: unknown): SessionData | undefined {\n try {\n const user = own(value, 'user');\n const session = own(value, 'session');\n if (\n typeof user !== 'object' ||\n user === null ||\n typeof session !== 'object' ||\n session === null\n ) {\n return undefined;\n }\n const id = own(user, 'id');\n const email = own(user, 'email');\n const name = own(user, 'name');\n const emailVerified = own(user, 'emailVerified');\n const image = own(user, 'image');\n const createdAt = date(own(user, 'createdAt'));\n const updatedAt = date(own(user, 'updatedAt'));\n const sessionId = own(session, 'id');\n const userId = own(session, 'userId');\n const token = own(session, 'token');\n const sessionCreatedAt = date(own(session, 'createdAt'));\n const sessionUpdatedAt = date(own(session, 'updatedAt'));\n const expiresAt = date(own(session, 'expiresAt'));\n const ipAddress = own(session, 'ipAddress');\n const userAgent = own(session, 'userAgent');\n const organization = own(session, 'activeOrganizationId');\n const role = own(user, 'role');\n let roles: string[] = [];\n if (role !== undefined && role !== null) {\n if (typeof role === 'string')\n roles = role\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean);\n else if (\n Array.isArray(role) &&\n role.every((entry: unknown): entry is string => typeof entry === 'string')\n ) {\n roles = role.map((entry: string) => entry.trim()).filter(Boolean);\n } else return undefined;\n }\n if (\n !requiredString(id) ||\n !requiredString(email) ||\n typeof name !== 'string' ||\n typeof emailVerified !== 'boolean' ||\n !optionalString(image) ||\n !createdAt ||\n !updatedAt ||\n !requiredString(sessionId) ||\n userId !== id ||\n !requiredString(token) ||\n !sessionCreatedAt ||\n !sessionUpdatedAt ||\n !expiresAt ||\n expiresAt.getTime() <= Date.now() ||\n !optionalString(ipAddress) ||\n !optionalString(userAgent) ||\n (organization !== undefined && organization !== null && !requiredString(organization))\n )\n return undefined;\n return {\n user: Object.freeze({\n ...dataProperties(user),\n id,\n email,\n name,\n emailVerified,\n createdAt,\n updatedAt,\n image,\n }),\n session: Object.freeze({\n ...dataProperties(session),\n id: sessionId,\n userId: id,\n token,\n createdAt: sessionCreatedAt,\n updatedAt: sessionUpdatedAt,\n expiresAt,\n ipAddress,\n userAgent,\n }),\n roles: Object.freeze(roles),\n ...(typeof organization === 'string' ? { tenantId: organization } : {}),\n };\n } catch {\n return undefined;\n }\n}\n","import { Reflector } from '@velajs/vela';\n\nexport const OptionalAuth = Reflector.createDecorator<boolean>({ key: 'vela.auth.optional' });\nexport const OPTIONAL_AUTH_KEY = OptionalAuth.KEY;\n","import {\n Inject,\n Injectable,\n Reflector,\n UnauthorizedException,\n getTrustedContextRequest,\n type CanActivate,\n type ExecutionContext,\n} from '@velajs/vela';\nimport { getContextIdentity } from '@velajs/authz/vela';\nimport { BETTER_AUTH_OPTIONS } from '../better-auth.tokens';\nimport { BetterAuthService } from '../better-auth.service';\nimport type { BetterAuthRuntimeOptions } from '../better-auth.types';\nimport { authenticateRequest, beginAuthRequest, getAuthRequestState } from '../auth-request-state';\nimport { validateSessionData } from '../session-data';\nimport { OptionalAuth } from '../decorators/optional-auth.decorator';\nimport { Public } from '../decorators/public.decorator';\n\n@Injectable()\nexport class AuthGuard implements CanActivate {\n private readonly reflector = new Reflector();\n\n constructor(\n @Inject(BetterAuthService) private readonly auth: BetterAuthService,\n @Inject(BETTER_AUTH_OPTIONS) private readonly opts: BetterAuthRuntimeOptions,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n // Frames trust only the authenticated connection attachment; HTTP cookies\n // and request payload never become ambient WebSocket authentication.\n if (context.getType() === 'ws') {\n if (getContextIdentity(context)) return true;\n throw new UnauthorizedException('Authentication required');\n }\n // Custom HTTP-backed dispatchers authenticate once at the outer boundary.\n // Never re-read credentials or clear shared authority across sibling fields.\n if (context.getType() !== 'http') {\n if (\n getTrustedContextRequest(context) &&\n (getAuthRequestState(context) ||\n this.reflector.getAllAndOverride(Public, context) ||\n this.reflector.getAllAndOverride(OptionalAuth, context))\n )\n return true;\n throw new UnauthorizedException('Authentication required');\n }\n beginAuthRequest(context);\n if (this.reflector.getAllAndOverride(Public, context)) return true;\n\n const raw = await this.auth.api.getSession({ headers: context.getRequest().headers });\n const data = validateSessionData(raw);\n if (data) {\n authenticateRequest(context, data, this.opts.issuer ?? 'better-auth');\n return true;\n }\n if (this.reflector.getAllAndOverride(OptionalAuth, context)) return true;\n throw new UnauthorizedException('Authentication required');\n }\n}\n","import {\n defineProvider,\n provideGlobal,\n stableHash,\n type DynamicModule,\n type InferTokens,\n type Token,\n type Type,\n} from '@velajs/vela';\nimport { createBetterAuthCatchallController } from './better-auth.controller';\nimport { BetterAuthService, BETTER_AUTH_BUILDER } from './better-auth.service';\nimport { BETTER_AUTH_OPTIONS } from './better-auth.tokens';\nimport type {\n BetterAuthInstance,\n BetterAuthModuleOptions,\n BetterAuthRuntimeOptions,\n} from './better-auth.types';\nimport { AuthGuard } from './guards/auth.guard';\nimport { normalizeBetterAuthBasePath } from './base-path';\n\nconst referenceIds = new WeakMap<object, number>();\nconst explicitKeyClaims = new Map<\n string,\n { readonly kind: 'auth' | 'factory'; readonly reference: object; readonly shape: string }\n>();\nlet nextReferenceId = 1;\n\nfunction referenceId(reference: object): number {\n const existing = referenceIds.get(reference);\n if (existing !== undefined) return existing;\n const id = nextReferenceId++;\n referenceIds.set(reference, id);\n return id;\n}\n\nfunction claimExplicitKey(\n key: string,\n kind: 'auth' | 'factory',\n reference: object,\n shape: string,\n): string {\n if (key.length === 0 || key !== key.trim()) {\n throw new Error('@velajs/better-auth: an explicit module key must be a non-empty string');\n }\n const existing = explicitKeyClaims.get(key);\n if (\n existing !== undefined &&\n (existing.kind !== kind || existing.reference !== reference || existing.shape !== shape)\n ) {\n throw new Error(\n `@velajs/better-auth: explicit module key \"${key}\" is already bound to a different auth registration`,\n );\n }\n explicitKeyClaims.set(key, { kind, reference, shape });\n return `explicit:${key}:ref:${referenceId(reference)}`;\n}\n\n/** Structural options with defaults applied (everything but the auth instance). */\ninterface NormalizedOptions {\n basePath: string;\n issuer: string;\n isGlobal: boolean;\n mountHandler: boolean;\n}\n\nfunction normalize(options: BetterAuthRuntimeOptions): NormalizedOptions {\n const basePath = normalizeBetterAuthBasePath(options.basePath);\n const issuer = options.issuer ?? `better-auth:${basePath}`;\n if (issuer.length === 0 || issuer !== issuer.trim()) {\n throw new Error('@velajs/better-auth: issuer must be a non-empty stable namespace');\n }\n return {\n basePath,\n issuer,\n isGlobal: options.isGlobal ?? true,\n mountHandler: options.mountHandler ?? true,\n };\n}\n\n/** Providers, controllers, and exports shared by both entry points. */\nfunction commonContributions(n: NormalizedOptions): {\n providers: NonNullable<DynamicModule['providers']>;\n controllers: Type[];\n exports: DynamicModule['exports'];\n} {\n return {\n providers: [BetterAuthService, AuthGuard],\n controllers: n.mountHandler ? [createBetterAuthCatchallController(n.basePath)] : [],\n exports: [BetterAuthService, BETTER_AUTH_OPTIONS, AuthGuard],\n };\n}\n\n/**\n * Options for {@link BetterAuthModule.forRootAsync}.\n *\n * The `Inject` type parameter captures the literal `inject` tuple at the call\n * site (via `const` inference) so `useFactory` parameters are typed from the\n * inject array, position-by-position — no `as const`, no `(...deps: any[])`:\n *\n * ```ts\n * BetterAuthModule.forRootAsync({\n * inject: [WORKER_ENV, ConfigService], // captured as readonly tuple\n * useFactory: (env, config) => // inferred from the tokens\n * betterAuth({ database: drizzleAdapter(drizzle(env.DB), ...) }),\n * });\n * ```\n */\ninterface ForRootAsyncOptions<Inject extends readonly Token[] = readonly Token[]> {\n inject: Inject;\n imports?: DynamicModule['imports'];\n useFactory: (...deps: InferTokens<Inject>) => BetterAuthInstance;\n isGlobal?: boolean;\n mountHandler?: boolean;\n basePath?: string;\n issuer?: string;\n key?: string;\n}\n\nexport class BetterAuthModule {\n /**\n * Synchronous registration. The auth instance is constructed by the consumer\n * at module-load time and passed in directly. Use this when the inputs to\n * `betterAuth({...})` are available at startup (Node apps with a static DB\n * connection, in-memory adapters, etc.).\n */\n static forRoot(\n options: BetterAuthModuleOptions & { isGlobal?: boolean; key?: string },\n ): DynamicModule {\n const normalized = normalize(options);\n const shape = stableHash(normalized);\n const key =\n options.key === undefined\n ? `${shape}:auth:${referenceId(options.auth)}`\n : claimExplicitKey(options.key, 'auth', options.auth, shape);\n const common = commonContributions(normalized);\n return {\n module: BetterAuthModule,\n key,\n providers: [\n defineProvider(BETTER_AUTH_OPTIONS, { useValue: normalized }),\n defineProvider(BETTER_AUTH_BUILDER, { useValue: () => options.auth }),\n ...common.providers,\n ...(normalized.isGlobal ? provideGlobal('guard', AuthGuard) : []),\n ],\n controllers: common.controllers,\n exports: common.exports,\n };\n }\n\n /**\n * Deferred / DI-driven registration. The user factory runs **lazily**, on the\n * first time anything reads `BetterAuthService.auth` (or `.api` / `.handler`).\n * In normal request handling that's `AuthGuard.canActivate` or the catch-all\n * controller's `.handle`. At module load the factory does NOT run — it's only\n * captured in the checked builder provider. The Workers adapter supplies its\n * native environment before DI; the lazily constructed auth instance belongs\n * to that environment's application and never captures another app's bindings.\n */\n static forRootAsync<const Inject extends readonly Token[] = readonly Token[]>(\n options: ForRootAsyncOptions<Inject>,\n ): DynamicModule {\n const n = normalize(options);\n const common = commonContributions(n);\n const shape = stableHash({ ...n, inject: options.inject });\n const key =\n options.key === undefined\n ? `${shape}:factory:${referenceId(options.useFactory)}`\n : claimExplicitKey(options.key, 'factory', options.useFactory, shape);\n return {\n module: BetterAuthModule,\n key,\n imports: options.imports ?? [],\n providers: [\n defineProvider(BETTER_AUTH_OPTIONS, { useValue: n }),\n defineProvider(BETTER_AUTH_BUILDER, {\n inject: options.inject,\n useFactory:\n (...deps: InferTokens<Inject>) =>\n () =>\n options.useFactory(...deps),\n }),\n ...common.providers,\n ...(n.isGlobal ? provideGlobal('guard', AuthGuard) : []),\n ],\n controllers: common.controllers,\n exports: common.exports,\n };\n }\n}\n","import { createParamDecorator, type ExecutionContext } from '@velajs/vela';\nimport { getAuthRequestState } from '../auth-request-state';\nimport type { User } from '../better-auth.types';\n\nexport const CurrentUser = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext): User | undefined => {\n const state = getAuthRequestState(ctx);\n return state?.user;\n },\n);\n","import { createParamDecorator, type ExecutionContext } from '@velajs/vela';\nimport { getAuthRequestState } from '../auth-request-state';\nimport type { Session } from '../better-auth.types';\n\nexport const CurrentSession = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext): Session | undefined => {\n const state = getAuthRequestState(ctx);\n return state?.session;\n },\n);\n","import type { Identity, PermissionResolver } from '@velajs/authz';\nimport type { User } from './better-auth.types';\n\n/**\n * A better-auth user carrying the optional `role` field contributed by the\n * admin plugin. `role` may be a single role, a comma-separated list, or an\n * array — {@link identityFromUser} normalizes all three.\n */\nexport type AuthUser = Pick<User, 'id'> & { role?: string | string[] | null };\n\n/** Stable issuer namespace used for better-auth session principals. */\nexport const BETTER_AUTH_ISSUER = 'better-auth';\n\nconst normalizeRoles = (role: string | string[] | null | undefined): string[] => {\n if (!role) return [];\n // Strip empty entries and return a fresh array (never alias the caller's\n // input), matching the comma-string path below.\n if (Array.isArray(role)) return role.filter(Boolean);\n return role\n .split(',')\n .map((r) => r.trim())\n .filter(Boolean);\n};\n\n/**\n * Pure authorization projection; this does not authenticate or publish trusted state.\n * Adapts an already verified better-auth user into a stable `@velajs/authz` {@link Identity}.\n * The issuer scopes `user.id` as both `subject` and the compatibility `userId`;\n * the admin-plugin `role` field supplies local roles.\n *\n * Fail-closed: a missing user (`null`/`undefined`, i.e. an unauthenticated\n * request) maps to the zero-privilege identity `{ roles: [] }`, so downstream\n * `can()` checks grant nothing.\n */\nexport const identityFromUser = (\n user: AuthUser | null | undefined,\n issuer: string = BETTER_AUTH_ISSUER,\n principalType: 'user' | 'service' = 'user',\n): Identity => {\n if (!user || typeof user.id !== 'string' || user.id.length === 0) return { roles: [] };\n if (issuer.length === 0)\n throw new Error('@velajs/better-auth: identity issuer must be non-empty');\n return {\n issuer,\n subject: user.id,\n principalType,\n userId: user.id,\n roles: normalizeRoles(user.role),\n };\n};\n\n/**\n * The minimal slice of a better-auth access-control role consumed here. Both\n * `createAccessControl(...).newRole(...)` and the standalone `role(...)` return\n * `{ authorize, statements }`; `statements` is the `{ resource: actions[] }`\n * grant map for that role — the only accessor {@link betterAuthAcResolver}\n * reads.\n */\nexport interface BetterAuthAcRole {\n readonly statements: Readonly<Record<string, readonly string[]>>;\n}\n\n/**\n * Flattens a better-auth AC role's `statements` into `resource:action`\n * permission strings — the granted-side format `@velajs/authz` matches\n * (wildcards included).\n */\nexport const permissionsFromAcRole = (role: BetterAuthAcRole): string[] => {\n const permissions: string[] = [];\n for (const [resource, actions] of Object.entries(role.statements ?? {})) {\n for (const action of actions ?? []) permissions.push(`${resource}:${action}`);\n }\n return permissions;\n};\n\n/**\n * Builds a fail-closed `@velajs/authz` {@link PermissionResolver} from a\n * better-auth access-control role table (`{ roleName: acRole }` — the same map\n * shape passed to better-auth's admin/organization plugins). An identity's\n * `roles` are unioned into their granted permission strings; unknown roles\n * contribute nothing.\n *\n * ```ts\n * const ac = createAccessControl({ posts: ['read', 'write'] });\n * const authz = createAuthz({\n * resolver: betterAuthAcResolver({ editor: ac.newRole({ posts: ['write'] }) }),\n * });\n * await authz.can(identityFromUser(user), 'posts:write');\n * ```\n */\nexport const betterAuthAcResolver = (\n roles: Readonly<Record<string, BetterAuthAcRole>>,\n): PermissionResolver => {\n const grantsByRole = new Map<string, string[]>();\n for (const [name, role] of Object.entries(roles)) {\n grantsByRole.set(name, permissionsFromAcRole(role));\n }\n return {\n grants(identity: Identity): Set<string> {\n const out = new Set<string>();\n for (const name of identity.roles ?? []) {\n for (const permission of grantsByRole.get(name) ?? []) out.add(permission);\n }\n return out;\n },\n };\n};\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { t as BetterAuthService } from "../better-auth.service-NOlWXxd4.js";
1
+ import { t as BetterAuthService } from "../better-auth.service-CvmboUID.js";
2
2
  //#region src/testing/acting-as.d.ts
3
3
  /**
4
4
  * The slice of `@velajs/testing`'s `TestingModule` this resolver depends on.
@@ -1,4 +1,4 @@
1
- import { n as BetterAuthService } from "../better-auth.service-DurQ4JQf.js";
1
+ import { n as BetterAuthService } from "../better-auth.service-SNg1YFTK.js";
2
2
  import { makeSignature } from "better-auth/crypto";
3
3
  //#region src/testing/acting-as.ts
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velajs/better-auth",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "better-auth integration for the Vela framework",
5
5
  "keywords": [
6
6
  "auth",
@@ -12,7 +12,7 @@
12
12
  "session",
13
13
  "vela"
14
14
  ],
15
- "homepage": "https://github.com/velajs/vela/tree/main/auth#readme",
15
+ "homepage": "https://github.com/velajs/vela/tree/main/packages/better-auth#readme",
16
16
  "bugs": {
17
17
  "url": "https://github.com/velajs/vela/issues"
18
18
  },
@@ -21,7 +21,7 @@
21
21
  "repository": {
22
22
  "type": "git",
23
23
  "url": "git+https://github.com/velajs/vela.git",
24
- "directory": "auth"
24
+ "directory": "packages/better-auth"
25
25
  },
26
26
  "files": [
27
27
  "dist",
@@ -43,12 +43,15 @@
43
43
  "import": "./dist/testing/index.js"
44
44
  }
45
45
  },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
46
49
  "dependencies": {
47
- "@velajs/authz": "2.0.0"
50
+ "@velajs/authz": "3.0.0"
48
51
  },
49
52
  "devDependencies": {
50
53
  "@arethetypeswrong/cli": "0.18.5",
51
- "@changesets/cli": "2.31.0",
54
+ "@changesets/cli": "3.0.1",
52
55
  "@swc/core": "1.15.43",
53
56
  "better-auth": "^1.6.20",
54
57
  "hono": "4.13.8",
@@ -60,20 +63,18 @@
60
63
  "unplugin-swc": "1.5.9",
61
64
  "vite": "^8.0.16",
62
65
  "vitest": "4.1.10",
63
- "@velajs/vela": "2.0.0",
64
- "@velajs/testing": "2.0.0"
66
+ "@velajs/tenant": "3.0.0",
67
+ "@velajs/vela": "3.0.0",
68
+ "@velajs/testing": "3.0.0"
65
69
  },
66
70
  "peerDependencies": {
67
71
  "better-auth": ">=1.2.0",
68
72
  "hono": ">=4",
69
- "@velajs/vela": "^2.0.0"
73
+ "@velajs/vela": "^3.0.0"
70
74
  },
71
75
  "engines": {
72
76
  "node": ">=24"
73
77
  },
74
- "publishConfig": {
75
- "access": "public"
76
- },
77
78
  "scripts": {
78
79
  "build": "tsdown",
79
80
  "test": "vitest run",