nestjs-slightly-better-auth 1.1.0 → 1.3.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 (92) hide show
  1. package/README.md +182 -3
  2. package/dist/admin.cjs +2 -2
  3. package/dist/admin.d.cts +1 -1
  4. package/dist/admin.d.mts +1 -1
  5. package/dist/admin.mjs +2 -2
  6. package/dist/api-key.cjs +8 -7
  7. package/dist/api-key.cjs.map +1 -1
  8. package/dist/api-key.d.cts +1 -1
  9. package/dist/api-key.d.mts +1 -1
  10. package/dist/api-key.mjs +3 -2
  11. package/dist/api-key.mjs.map +1 -1
  12. package/dist/{auth-contracts-BBA1C1gj.d.cts → auth-contracts-CL8TEt5t.d.cts} +28 -2
  13. package/dist/auth-contracts-CL8TEt5t.d.cts.map +1 -0
  14. package/dist/{auth-contracts-tqsfBZ8B.d.mts → auth-contracts-CnGaBzlg.d.mts} +29 -3
  15. package/dist/auth-contracts-CnGaBzlg.d.mts.map +1 -0
  16. package/dist/auth-decorators-BmUNYTFd.mjs +394 -0
  17. package/dist/auth-decorators-BmUNYTFd.mjs.map +1 -0
  18. package/dist/auth-decorators-CJUQDwAQ.cjs +543 -0
  19. package/dist/auth-decorators-CJUQDwAQ.cjs.map +1 -0
  20. package/dist/{auth-errors-CsERBNWI.cjs → auth-errors-1EdQ36D8.cjs} +7 -1
  21. package/dist/{auth-errors-CsERBNWI.cjs.map → auth-errors-1EdQ36D8.cjs.map} +1 -1
  22. package/dist/{auth-errors-CQjfgjaO.mjs → auth-errors-B6jLBpQu.mjs} +2 -2
  23. package/dist/{auth-errors-CQjfgjaO.mjs.map → auth-errors-B6jLBpQu.mjs.map} +1 -1
  24. package/dist/auth-module-DXSvwVXS.mjs +2555 -0
  25. package/dist/auth-module-DXSvwVXS.mjs.map +1 -0
  26. package/dist/auth-module-boCEWXr1.cjs +2656 -0
  27. package/dist/auth-module-boCEWXr1.cjs.map +1 -0
  28. package/dist/bridge-protocol-B6iB-7X8.mjs +8 -0
  29. package/dist/bridge-protocol-B6iB-7X8.mjs.map +1 -0
  30. package/dist/bridge-protocol-BTwcn95p.cjs +25 -0
  31. package/dist/bridge-protocol-BTwcn95p.cjs.map +1 -0
  32. package/dist/decorate-Bvg21vkL.cjs +303 -0
  33. package/dist/decorate-Bvg21vkL.cjs.map +1 -0
  34. package/dist/decorate-YZjmlv7t.mjs +76 -0
  35. package/dist/decorate-YZjmlv7t.mjs.map +1 -0
  36. package/dist/express.cjs +1 -1
  37. package/dist/express.d.cts +1 -1
  38. package/dist/express.d.mts +1 -1
  39. package/dist/express.mjs +1 -1
  40. package/dist/fastify.d.cts +1 -1
  41. package/dist/fastify.d.mts +1 -1
  42. package/dist/index.cjs +36 -2585
  43. package/dist/index.d.cts +1 -1
  44. package/dist/index.d.mts +1 -1
  45. package/dist/index.mjs +6 -2555
  46. package/dist/microservices.cjs +3 -24
  47. package/dist/microservices.cjs.map +1 -1
  48. package/dist/microservices.d.cts +1 -1
  49. package/dist/microservices.d.mts +1 -1
  50. package/dist/microservices.mjs +1 -1
  51. package/dist/organization.cjs +2 -2
  52. package/dist/organization.d.cts +1 -1
  53. package/dist/organization.d.mts +1 -1
  54. package/dist/organization.mjs +2 -2
  55. package/dist/principal-readings-BKeyOxwJ.mjs +413 -0
  56. package/dist/principal-readings-BKeyOxwJ.mjs.map +1 -0
  57. package/dist/principal-readings-CpF4q6b-.cjs +490 -0
  58. package/dist/principal-readings-CpF4q6b-.cjs.map +1 -0
  59. package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
  60. package/dist/testing/conformance.cjs +3153 -0
  61. package/dist/testing/conformance.cjs.map +1 -0
  62. package/dist/testing/conformance.d.cts +278 -0
  63. package/dist/testing/conformance.d.cts.map +1 -0
  64. package/dist/testing/conformance.d.mts +278 -0
  65. package/dist/testing/conformance.d.mts.map +1 -0
  66. package/dist/testing/conformance.mjs +3143 -0
  67. package/dist/testing/conformance.mjs.map +1 -0
  68. package/dist/testing.cjs +220 -0
  69. package/dist/testing.cjs.map +1 -0
  70. package/dist/testing.d.cts +63 -0
  71. package/dist/testing.d.cts.map +1 -0
  72. package/dist/testing.d.mts +63 -0
  73. package/dist/testing.d.mts.map +1 -0
  74. package/dist/testing.mjs +213 -0
  75. package/dist/testing.mjs.map +1 -0
  76. package/dist/websockets.cjs +351 -0
  77. package/dist/websockets.cjs.map +1 -0
  78. package/dist/websockets.d.cts +67 -0
  79. package/dist/websockets.d.cts.map +1 -0
  80. package/dist/websockets.d.mts +67 -0
  81. package/dist/websockets.d.mts.map +1 -0
  82. package/dist/websockets.mjs +338 -0
  83. package/dist/websockets.mjs.map +1 -0
  84. package/package.json +63 -3
  85. package/dist/auth-contracts-BBA1C1gj.d.cts.map +0 -1
  86. package/dist/auth-contracts-tqsfBZ8B.d.mts.map +0 -1
  87. package/dist/auth-decorators-CwW5JY4y.cjs +0 -1274
  88. package/dist/auth-decorators-CwW5JY4y.cjs.map +0 -1
  89. package/dist/auth-decorators-DfAJbHar.mjs +0 -849
  90. package/dist/auth-decorators-DfAJbHar.mjs.map +0 -1
  91. package/dist/index.cjs.map +0 -1
  92. package/dist/index.mjs.map +0 -1
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  A NestJS integration for [Better Auth](https://www.better-auth.com), built on an independently reviewed specification.
8
8
 
9
- > **Scope.** The package covers HTTP and RPC. HTTP support comprises the Nest authentication kernel, the Better Auth construction plugin, the Express and Fastify platforms, and the admin, organization and API-key authorization units. The `./microservices` entry authenticates Nest microservice messages. GraphQL and WebSocket transports and the conformance testing kit are not included; they arrive in later minor versions behind their own entry points. The [changelog](CHANGELOG.md) records the version that introduces each entry point.
9
+ > **Scope.** The package covers HTTP, WebSocket and RPC authentication. HTTP support comprises the Nest authentication kernel, the Better Auth construction plugin, the Express and Fastify platforms, and the admin, organization and API-key authorization units. The `./websockets` entry authenticates Socket.IO and raw `ws` gateways, and the `./microservices` entry authenticates Nest microservice messages. The `./testing` entry provides consumer testing helpers and `./testing/conformance` reusable conformance kits. The GraphQL transport is not included; it arrives in a later minor version behind its own entry point. The [changelog](CHANGELOG.md) records the version that introduces each entry point.
10
10
 
11
11
  ## Install
12
12
 
@@ -14,7 +14,14 @@ A NestJS integration for [Better Auth](https://www.better-auth.com), built on an
14
14
  pnpm add nestjs-slightly-better-auth better-auth
15
15
  ```
16
16
 
17
- Peer dependencies: `@nestjs/common` and `@nestjs/core` 12, `better-auth` 1.7.5 or newer, `reflect-metadata` and `rxjs`. Node.js 24.11 or newer.
17
+ Peer dependencies: `@nestjs/common` and `@nestjs/core` 12, `better-auth` 1.7.5 or newer, `reflect-metadata` and `rxjs`. Node.js 24.11 or newer. The `./testing` and `./testing/conformance` entries also need the optional peer `@nestjs/testing` 12; the root entry never loads it or a test runner.
18
+
19
+ The `./websockets` entry also needs the optional peer `@nestjs/websockets` 12 and the Nest adapter for your socket library:
20
+
21
+ ```sh
22
+ pnpm add @nestjs/websockets @nestjs/platform-socket.io # Socket.IO
23
+ pnpm add @nestjs/websockets @nestjs/platform-ws # raw ws
24
+ ```
18
25
 
19
26
  The `./microservices` entry also needs the optional peer `@nestjs/microservices` 12 and the client library Nest uses for your transport, for example:
20
27
 
@@ -36,10 +43,75 @@ Express preserves native controller parsing for unconditional routes that overla
36
43
 
37
44
  Fastify does not expose its configured `trustProxy` value through a public inspection API. The boot summary therefore reports proxy trust as `unknown`, and diagnostics that depend on the setting are unavailable. Client IP resolution still uses the native Fastify request. Configure proxy trust on your Nest Fastify adapter and verify it against your deployment topology.
38
45
 
39
- GraphQL and WebSocket integrations have separate implementation and end-to-end acceptance gates. They will use optional entry points so applications install only the transports they use.
46
+ The GraphQL integration has separate implementation and end-to-end acceptance gates. It will use an optional entry point so applications install only the transports they use.
40
47
 
41
48
  Start with the [design workspace](docs/design/README.md), [reviewed specification](docs/design/design-v7.md), [review ledger](docs/design/ledger.md) and [implementation plan](../../docs/superpowers/plans/2026-09-21-better-auth.md). Independent Better Auth, NestJS and security reviews approved the final v7 snapshot after resolving the round-6 and round-7 findings. The remaining entry points are tracked in [issue #534](https://github.com/thilllon/nestjs-kit/issues/534).
42
49
 
50
+ ## WebSocket gateways
51
+
52
+ The `./websockets` entry authenticates Socket.IO and raw `ws` gateways. Register `socketIoTransport()` or `wsTransport()` in the module's `transports`, and decorate every gateway with `@UseBetterAuth()` so both the guard and the invocation scope run for its message handlers. Startup fails with `GATEWAY_UNGUARDED` when a message handler lacks that coverage; `@Public()` opts a gateway or handler out, and the transports' `gatewayCoverage` option downgrades the check to `"warn"` or `"off"`. Message handlers use the same access, session and authorization decorators as controllers.
53
+
54
+ ```ts
55
+ import { Inject, Module } from "@nestjs/common";
56
+ import { SubscribeMessage, WebSocketGateway } from "@nestjs/websockets";
57
+ import type { Server } from "socket.io";
58
+ import {
59
+ BetterAuthModule,
60
+ CurrentSession,
61
+ RequireAuth,
62
+ UseBetterAuth,
63
+ } from "nestjs-slightly-better-auth";
64
+ import { expressPlatform } from "nestjs-slightly-better-auth/express";
65
+ import {
66
+ socketIoTransport,
67
+ WS_CONNECTION_AUTH,
68
+ type WsConnectionAuth,
69
+ } from "nestjs-slightly-better-auth/websockets";
70
+ import { auth } from "./auth"; // betterAuth({ plugins: [nestjs(), bearer()], ... })
71
+
72
+ @WebSocketGateway()
73
+ @UseBetterAuth()
74
+ export class EventsGateway {
75
+ constructor(
76
+ @Inject(WS_CONNECTION_AUTH)
77
+ private readonly connectionAuth: WsConnectionAuth,
78
+ ) {}
79
+
80
+ afterInit(server: Server) {
81
+ // Optional: reject unauthenticated handshakes before any message arrives.
82
+ server.use(this.connectionAuth.socketIoMiddleware({ required: true }));
83
+ }
84
+
85
+ @RequireAuth()
86
+ @SubscribeMessage("whoami")
87
+ whoami(@CurrentSession() session: { user: { email: string } }) {
88
+ return { email: session.user.email };
89
+ }
90
+ }
91
+
92
+ @Module({
93
+ imports: [
94
+ BetterAuthModule.forRoot({
95
+ auth,
96
+ platforms: [expressPlatform()],
97
+ transports: [socketIoTransport()],
98
+ }),
99
+ ],
100
+ providers: [EventsGateway],
101
+ })
102
+ export class AppModule {}
103
+ ```
104
+
105
+ Socket.IO reads credentials from the handshake headers. When the handshake has no `Authorization` header, a string `auth.token` becomes `Authorization: Bearer <token>`, which Better Auth's `bearer()` plugin accepts. Raw `ws` reads the upgrade request, so wrap Nest's adapter to record it: `app.useWebSocketAdapter(new (withUpgradeRequest(WsAdapter))(app))`. Without that record, public messages still run and protected messages fail with a 500 `WS_UPGRADE_REQUEST_MISSING` configuration error.
106
+
107
+ A `credentials(client)` option on either transport replaces the default mapping: the entries of the `HeadersInit` it returns override the handshake headers of the same name for authentication. The browser-origin check always uses the original handshake, so mapped credentials cannot bypass it. A non-string `auth.token`, or mapped credentials that are not string pairs or contain CR, LF, NUL or other invalid header characters, fail with a 401 `MALFORMED_CREDENTIALS` before any Better Auth call. Other credentials on the connection are not tried in their place, and the failure does not carry the rejected value. Errors thrown by the mapper itself are not converted into authentication failures.
108
+
109
+ Connection authentication runs the same origin check and default credential sources as messages, for the default instance or the one named by `instance`. `socketIoMiddleware({ required, instance })` rejects a Socket.IO handshake with a `connect_error` whose `data` holds `statusCode`, `code` and `reason`; `required: false` admits connections without credentials but still rejects invalid ones. Unexpected errors reach the client as a 500 `Internal server error`, and the server logs a summary that omits foreign error messages because they can quote credentials. For raw `ws`, call `authenticate(client)` in `handleConnection` and close rejected connections with `wsCloseCodeFor(result.failure)`, which maps 401, 403 and 429 failures to close codes 4401, 4403 and 4429.
110
+
111
+ Principal caching is off by default. A positive `principalTtlMs` reuses a successful authentication on the same connection and therefore delays revocation for ordinary handlers; handlers declared with `@RequireAuth({ authoritative: true })` always revalidate. Neither message nor connection authentication refreshes cookies.
112
+
113
+ Tests run real Socket.IO 4.8.3 and ws 8.21.3 clients against Nest 12.0.3, where Nest delivers raw `ws` authentication failures as native `exception` messages.
114
+
43
115
  ## RPC authentication
44
116
 
45
117
  The `./microservices` entry authenticates messages in standalone and hybrid Nest microservices. `rpcTransport()` reads credentials from the transport's native carrier: gRPC metadata, NATS headers, Kafka headers, RabbitMQ message headers and MQTT 5 user properties. TCP and Redis messages have no header carrier, so they send credentials in a payload envelope field, `auth` by default. Every message is authenticated separately.
@@ -104,6 +176,113 @@ In a hybrid application, Nest applies global guards to microservice handlers onl
104
176
 
105
177
  Failures become `RpcException` payloads with `statusCode`, `code` and, where present, `reason`. gRPC calls receive native status codes: 16 for authentication, 7 for authorization, 8 for throttling and 13 for redacted infrastructure failures. End-to-end tests run real TCP and gRPC servers and real NATS, Kafka, RabbitMQ, MQTT 5 and Redis brokers against Nest 12.0.3, including hybrid applications with both coverage modes and default plus named instances.
106
178
 
179
+ ## Testing helpers (`./testing`)
180
+
181
+ The helpers replace one collaborator at a time in a `TestingModuleBuilder`, so the rest of the pipeline stays real.
182
+
183
+ ```ts
184
+ import { Test } from "@nestjs/testing";
185
+ import { allow } from "nestjs-slightly-better-auth";
186
+ import {
187
+ initTestApp,
188
+ overrideAuthGuard,
189
+ overrideDecisions,
190
+ overridePrincipal,
191
+ stampPrincipal,
192
+ } from "nestjs-slightly-better-auth/testing";
193
+
194
+ // Fixed principal: acceptance, the origin check and policies still run; Better Auth is not called for resolution.
195
+ const builder = overridePrincipal(
196
+ Test.createTestingModule({ imports: [AppModule] }),
197
+ {
198
+ kind: "session",
199
+ source: "better-auth:session",
200
+ userId: "u1",
201
+ session,
202
+ },
203
+ );
204
+
205
+ // Stub a policy decision; returning undefined runs the real policy.
206
+ overrideDecisions(
207
+ builder,
208
+ (policyId) =>
209
+ policyId === "better-auth:organization/permission" ? allow() : undefined, // gitleaks:allow: public policy identifier
210
+ );
211
+
212
+ // Replace the guard everywhere: the global APP_GUARD and every @UseBetterAuth()/@UseGuards(BetterAuthGuard) site.
213
+ overrideAuthGuard(builder, {
214
+ canActivate(ctx) {
215
+ stampPrincipal(ctx, testUser); // publishes the principal to @CurrentPrincipal(), @CurrentSession() and the service
216
+ return true;
217
+ },
218
+ });
219
+
220
+ // Inside a Vitest test or beforeEach: onTestFinished closes this app when the test ends (node:test: t.after).
221
+ const app = await initTestApp(
222
+ (await builder.compile()).createNestApplication(),
223
+ { closeWith: onTestFinished },
224
+ );
225
+ ```
226
+
227
+ - `overridePrincipal(builder, principal, { instance })` overrides `PRINCIPAL_RESOLVER` for one instance (default `'default'`). A policy's re-classification read of a generic 401 answers absent, so organization policies deny 401 under a fixed principal; stub them with `overrideDecisions` or use real sessions from `authHeadersFor`. The admin policy judges the stored user row of the fixed `userId`.
228
+ - `overrideAuthGuard(builder, guard | { principal })` overrides `GUARD_CORE` and `SCOPE_CORE` once each. `overrideProvider(BetterAuthGuard)` and `overrideGuard(BetterAuthGuard)` cannot be combined: `TestingModuleBuilder` keeps one override per token, so one set of call sites would keep the real guard. An object with a `canActivate` method always runs as the guard, even when it also has a `principal` property. The stand-in scope reads the test stamp first; `{ principal }` stamps for the handler's instance, including named instances.
229
+ - `stampPrincipal(ctx, principal, { instance })` records the principal on the invocation's argument array and its object elements. Readers accept it from the same array (WebSocket, RPC and GraphQL guards and interceptors share it) or from another array with the same elements when at least two elements are objects (an HTTP request and its response). A lone shared element, such as a socket beside a primitive payload, never identifies an invocation, so concurrent invocations do not see each other's stamps. A stand-in that stamps nothing makes principal readers fail with the generic `NO_AUTH_RESULT` error.
230
+ - `testPrincipal(principal | (request) => principal | null, { kinds, acceptance, delegates })` is a principal source for composed test modules.
231
+ - `authHeadersFor(auth, userId)` creates real session headers through Better Auth's `testUtils()` plugin.
232
+ - `initTestApp(app, { closeWith })` runs `init()` and Fastify `ready()`. A Better Auth instance binds to one application at a time (a second bound application fails with `INSTANCE_ALREADY_BOUND`), so the helper first closes the previous application that it initialized for the same instance; a failed `init()` leaves its binding to the next application, which takes it over with `W_INSTANCE_TAKEN_OVER`. The helper makes `app.close()` idempotent and passes it to `closeWith`, a per-test cleanup such as Vitest's `onTestFinished` or node:test's `t.after`. Jest cannot register hooks while a test runs, so collect the closes and run them in a suite-level `afterEach`. Without `closeWith`, close the last application yourself. On Express, compile one `TestingModule` per application.
233
+
234
+ Better Auth treats a process with `NODE_ENV=test` or a truthy `TEST` variable (Vitest sets it; Jest sets `NODE_ENV=test`) as a test run and then skips its origin checks, and this library's origin check follows the same flags. Set `advanced.disableOriginCheck: false` on test instances that exercise origin rules.
235
+
236
+ ## Conformance kits (`./testing/conformance`)
237
+
238
+ The kits verify extension units against the invariants of the [reviewed specification](docs/design/design-v7.md) (§4 and §14.1). Each kit returns `ConformanceCase[]` (`{ id, title, skip?, run() }`) that `runConformance(cases, { describe, it })` registers with Vitest, Jest or `node:test`. Assertions use `node:assert/strict`; the kits import no test runner.
239
+
240
+ Applicability comes from the unit, not from the options a harness passes. A platform that declares `capabilities.http2` needs the `http2` option. A transport with a lineage needs `invokeTwice`, one that nests handlers (`defaultAccessFor`) needs `invokeGraph`, and one that claims the kit's federation reference resolver needs `invokeEntities`. Such a case fails when the helper is missing. A case whose optional capability is absent is skipped with the reason. The kits read these members from unit objects before running; for classes and `defineExtension()` definitions they boot once and read the resolved unit. A case known to be inapplicable registers with its reason in the test name. A case that finds out at run time resolves with `{ skipped: reason }`, which `runConformance` reports through the runner's `context.skip(reason)` (Vitest, `node:test`; Jest has no runtime skip, so the test passes).
241
+
242
+ ```ts
243
+ import { ExpressAdapter } from "@nestjs/platform-express";
244
+ import { describe, it } from "vitest";
245
+ import {
246
+ createConformanceAuth,
247
+ httpPlatformConformance,
248
+ policyConformance,
249
+ principalSourceConformance,
250
+ runConformance,
251
+ } from "nestjs-slightly-better-auth/testing/conformance";
252
+
253
+ runConformance(
254
+ httpPlatformConformance({
255
+ platform: myPlatform(),
256
+ createHttpAdapter: () => new ExpressAdapter(),
257
+ }),
258
+ { describe, it },
259
+ );
260
+
261
+ const auth = createConformanceAuth({ plugins: [myPlugin()] });
262
+ runConformance(
263
+ principalSourceConformance({
264
+ source: myTokenSource(),
265
+ auth,
266
+ credentials: {
267
+ valid: issueToken,
268
+ invalid: () => new Headers({ authorization: "Bearer invalid" }),
269
+ },
270
+ }),
271
+ { describe, it },
272
+ );
273
+ ```
274
+
275
+ | Kit | Unit | Covers |
276
+ | ---------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
277
+ | `httpPlatformConformance` | `HttpPlatform` | Mounting, byte-exact bodies, limits with host CORS, URL and header facts, client IP, HTTP/2, write-back, request accessors, error delivery, lifecycle (no adapter, late adapter, reused `TestingModule`, double `forRoot`), diagnostics and log hygiene |
278
+ | `transportConformance` | `AuthTransport` | Selection, credentials, per-request memoization, per-invocation decisions, acceptance, cookie forwarding or refresh suppression, origin and form-CSRF rules including forwarding on safe operations, error shapes and logging, the exact coverage report of the transport's claims, `globalScope: false`, mixed-kind session reads, lazy scope construction and fail-closed extraction |
279
+ | `principalSourceConformance` | `PrincipalSource` | Rejection without throwing, storage outages, delivery of every own-credential `Set-Cookie` exactly once, refresh suppression, clean absence, principal shape, declared credential headers, `sessionBacked` and `delegates` declarations |
280
+ | `policyConformance` | `AuthorizationPolicy` | Deny values, storage outages, APIError mapping and re-classification, delegation scope, unnamed-kind gating, per-invocation decisions with shared I/O and plugin prerequisites; requirements name policy objects (construct a DI policy with its dependencies) |
281
+
282
+ Every case boots real Nest applications or modules with a real Better Auth instance that includes `conformanceProbePlugin()`. The probe counts and faults every operation of the instance's database adapter, so storage outages reach endpoints that would swallow them, and records the `Set-Cookie` lines each call produces. `createConformanceAuth({ plugins })` builds such an instance: memory adapter, `testUtils()`, `bearer()`, the probe plugin, `nestjs()` last, and `session.updateAge: 0` and origin checks on, whatever `options` says. The principal-source and policy kits take that instance as `auth`; the principal-source kit rejects an instance without `session.updateAge: 0`. The transport kit creates its own instance and passes it to your `createApp` harness together with the kit's API-key source in `principals`, a `logger` to boot with, and the `globalScope`, `appEnhancers`, `fieldResolverEnhancers` and `federation` settings of each boot. Apply every fixture decorator, including the kit's `SetMetadata()` marker, which maps the transport's claims to fixtures.
283
+
284
+ This repository runs the platform kit against Express and Fastify, the transport kit against the built-in HTTP transport and an in-process reference transport, the principal-source kit against the session and API-key sources, and the policy kit against the admin, organization, API-key and fresh-session policies. Mutation tests confirm that each of these defects fails the intended case: a platform merging `Set-Cookie`, a transport sharing invocation state across aliases, a transport without a browser leg on safe operations, a `defineExtension()` transport with a lineage or nesting and no helper, a source throwing its denial, a source dropping its refresh cookie, a source turning a storage outage into a 401, and a policy widening delegated principals.
285
+
107
286
  ## Develop in this monorepo
108
287
 
109
288
  From the repository root:
package/dist/admin.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_auth_errors = require("./auth-errors-CsERBNWI.cjs");
3
- const require_auth_decorators = require("./auth-decorators-CwW5JY4y.cjs");
2
+ const require_auth_errors = require("./auth-errors-1EdQ36D8.cjs");
3
+ const require_auth_decorators = require("./auth-decorators-CJUQDwAQ.cjs");
4
4
  let better_auth_api = require("better-auth/api");
5
5
  //#region src/admin.ts
6
6
  const adminPermissionPolicy = {
package/dist/admin.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { f as AuthorizationPolicy, kt as PrincipalKind, mt as AdminPermissions, nt as Requirement, yt as AuthPrincipal } from "./auth-contracts-BBA1C1gj.cjs";
1
+ import { Ct as AuthPrincipal, Nt as PrincipalKind, f as AuthorizationPolicy, ot as Requirement, vt as AdminPermissions } from "./auth-contracts-CL8TEt5t.cjs";
2
2
  //#region src/admin.d.ts
3
3
  export interface PermissionOptions {
4
4
  principals?: readonly PrincipalKind[];
package/dist/admin.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { f as AuthorizationPolicy, kt as PrincipalKind, mt as AdminPermissions, nt as Requirement, yt as AuthPrincipal } from "./auth-contracts-tqsfBZ8B.mjs";
1
+ import { Ct as AuthPrincipal, Nt as PrincipalKind, f as AuthorizationPolicy, ot as Requirement, vt as AdminPermissions } from "./auth-contracts-CnGaBzlg.mjs";
2
2
  //#region src/admin.d.ts
3
3
  export interface PermissionOptions {
4
4
  principals?: readonly PrincipalKind[];
package/dist/admin.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { n as BetterAuthConfigurationError } from "./auth-errors-CQjfgjaO.mjs";
2
- import { u as Require } from "./auth-decorators-DfAJbHar.mjs";
1
+ import { n as BetterAuthConfigurationError } from "./auth-errors-B6jLBpQu.mjs";
2
+ import { u as Require } from "./auth-decorators-BmUNYTFd.mjs";
3
3
  import { isAPIError } from "better-auth/api";
4
4
  //#region src/admin.ts
5
5
  const adminPermissionPolicy = {
package/dist/api-key.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_auth_errors = require("./auth-errors-CsERBNWI.cjs");
3
- const require_auth_decorators = require("./auth-decorators-CwW5JY4y.cjs");
2
+ const require_auth_errors = require("./auth-errors-1EdQ36D8.cjs");
3
+ const require_principal_readings = require("./principal-readings-CpF4q6b-.cjs");
4
+ const require_auth_decorators = require("./auth-decorators-CJUQDwAQ.cjs");
4
5
  let better_auth_plugins_access = require("better-auth/plugins/access");
5
6
  //#region src/api-key.ts
6
7
  const API_KEY_PRINCIPAL_KIND = "api-key";
@@ -55,7 +56,7 @@ function apiKeyPrincipal(options = {}) {
55
56
  requires: { plugins: ["api-key"] },
56
57
  appliesTo: (request) => request.headers.has(header),
57
58
  async resolve(request) {
58
- if (!request.headers.has(header)) return require_auth_decorators.absent();
59
+ if (!request.headers.has(header)) return require_principal_readings.absent();
59
60
  return request.memo(verificationMemo, async () => {
60
61
  const key = request.headers.get(header);
61
62
  const headers = new Headers();
@@ -87,7 +88,7 @@ function apiKeyPrincipal(options = {}) {
87
88
  const references = typeof options.references === "function" ? options.references({ configId }) : options.references ?? "user";
88
89
  const permissions = verified.permissions ?? null;
89
90
  const grant = (0, better_auth_plugins_access.role)(permissions ?? {});
90
- return require_auth_decorators.authenticated({
91
+ return require_principal_readings.authenticated({
91
92
  kind: API_KEY_PRINCIPAL_KIND,
92
93
  source: "better-auth:api-key",
93
94
  keyId: verified.id,
@@ -105,7 +106,7 @@ function apiKeyPrincipal(options = {}) {
105
106
  const code = result.error?.code;
106
107
  if (code === "RATE_LIMITED" || code === "USAGE_EXCEEDED") {
107
108
  const retry = result.error?.details?.tryAgainIn;
108
- return require_auth_decorators.rejected(require_auth_errors.AuthFailures.rejected({
109
+ return require_principal_readings.rejected(require_auth_errors.AuthFailures.rejected({
109
110
  status: 429,
110
111
  reason: code,
111
112
  ...code === "RATE_LIMITED" && typeof retry === "number" ? { retryAfterSeconds: retry / 1e3 } : {}
@@ -115,7 +116,7 @@ function apiKeyPrincipal(options = {}) {
115
116
  if (slowMs !== false && performance.now() - started > slowMs) throw new require_auth_errors.BetterAuthInfrastructureError(/* @__PURE__ */ new Error("API-key verification exceeded the outage threshold"));
116
117
  await probe(request.auth);
117
118
  }
118
- if (code === "INVALID_API_KEY" || code === "KEY_NOT_FOUND" || code === "KEY_DISABLED" || code === "KEY_EXPIRED") return require_auth_decorators.rejected(require_auth_errors.AuthFailures.rejected({
119
+ if (code === "INVALID_API_KEY" || code === "KEY_NOT_FOUND" || code === "KEY_DISABLED" || code === "KEY_EXPIRED") return require_principal_readings.rejected(require_auth_errors.AuthFailures.rejected({
119
120
  status: 401,
120
121
  reason: code
121
122
  }));
@@ -123,7 +124,7 @@ function apiKeyPrincipal(options = {}) {
123
124
  } catch (error) {
124
125
  const failure = require_auth_errors.normalizeThrown(error, "source", "better-auth:api-key", [key]);
125
126
  if ("sessionLoss" in failure) throw new require_auth_errors.BetterAuthInfrastructureError(error, { secrets: [key] });
126
- return require_auth_decorators.rejected(failure);
127
+ return require_principal_readings.rejected(failure);
127
128
  }
128
129
  });
129
130
  }
@@ -1 +1 @@
1
- {"version":3,"file":"api-key.cjs","names":["BetterAuthConfigurationError","absent","BetterAuthInfrastructureError","role","authenticated","rejected","AuthFailures","normalizeThrown","Require"],"sources":["../src/api-key.ts"],"sourcesContent":["import { role } from \"better-auth/plugins/access\";\nimport type {\n AuthHandle,\n AuthPrincipalBase,\n AuthorizationPolicy,\n PrincipalDelegation,\n PrincipalSource,\n Requirement,\n} from \"./auth-contracts.js\";\nimport { Require } from \"./auth-decorators.js\";\nimport {\n AuthFailures,\n BetterAuthConfigurationError,\n BetterAuthInfrastructureError,\n normalizeThrown,\n} from \"./auth-errors.js\";\nimport { absent, authenticated, rejected } from \"./principal-resolver.js\";\n\nexport const API_KEY_PRINCIPAL_KIND = \"api-key\" as const;\nexport interface ApiKeyPrincipal extends AuthPrincipalBase {\n readonly kind: \"api-key\";\n readonly keyId: string;\n readonly configId: string | null;\n readonly referenceId: string;\n readonly userId: string | null;\n readonly organizationId: string | null;\n readonly permissions: Readonly<Record<string, readonly string[]>> | null;\n readonly delegation: PrincipalDelegation;\n}\n// The public module identity survives declaration bundling in both output formats.\ndeclare module \"nestjs-slightly-better-auth\" {\n interface PrincipalKinds {\n \"api-key\": ApiKeyPrincipal;\n }\n}\nexport interface ApiKeyPrincipalOptions {\n header?: string;\n configId?: string;\n references?:\n | \"user\"\n | \"organization\"\n | ((key: { readonly configId: string | null }) => \"user\" | \"organization\");\n /**\n * Default true: slow INVALID_API_KEY results (>500 ms) throw infrastructure errors,\n * then fast failures share one read/no-op-write probe per second per instance.\n * false disables both checks; { slowMs: false } keeps only the probe.\n * Set slowMs below pool lock/statement timeouts and above custom hashing costs.\n * Fast failures confined to one row, or secondary storage without database fallback,\n * may still look like invalid keys. A statement-level trigger can observe the zero-row write.\n */\n outageProbe?: boolean | { readonly slowMs?: number | false };\n acceptance?: \"default\" | \"explicit\";\n}\ninterface VerifiedKey {\n id: string;\n configId?: string | null;\n referenceId: string;\n permissions?: Record<string, readonly string[]> | null;\n}\ninterface Verification {\n valid: boolean;\n key?: VerifiedKey | null;\n error?: { code?: string; details?: { tryAgainIn?: number } } | null;\n}\ninterface KeyApi {\n verifyApiKey(input: {\n body: { key: string; configId?: string };\n headers: Headers;\n }): Promise<Verification>;\n}\nexport function apiKeyPrincipal(\n options: ApiKeyPrincipalOptions = {},\n): PrincipalSource<ApiKeyPrincipal> {\n const header = options.header ?? \"x-api-key\";\n const slowMs =\n typeof options.outageProbe === \"object\"\n ? (options.outageProbe.slowMs ?? 500)\n : 500;\n if (\n !header.trim() ||\n (slowMs !== false && (!Number.isFinite(slowMs) || slowMs < 0))\n ) {\n throw new BetterAuthConfigurationError(\n \"INVALID_API_KEY_OPTIONS\",\n \"API-key header must be nonempty and slowMs must be finite and nonnegative.\",\n );\n }\n const verificationMemo = Symbol(\"api-key-verification\");\n const probes = new WeakMap<\n object,\n { at: number; pending: boolean; result: Promise<void> }\n >();\n async function probe(auth: AuthHandle): Promise<void> {\n const previous = probes.get(auth.instance);\n if (previous && (previous.pending || Date.now() - previous.at < 1000)) {\n return previous.result;\n }\n const result = (async () => {\n const context = await auth.context();\n // The logical key column is string-valued for default, UUID and serial IDs.\n const where = [{ field: \"key\", value: crypto.randomUUID() }];\n await context.adapter.findOne({ model: \"apikey\", where });\n await context.adapter.updateMany({\n model: \"apikey\",\n where,\n update: { updatedAt: new Date() },\n });\n })();\n const state = { at: Date.now(), pending: true, result };\n probes.set(auth.instance, state);\n void result.then(\n () => {\n state.pending = false;\n },\n () => {\n state.pending = false;\n },\n );\n return result;\n }\n return {\n id: \"better-auth:api-key\",\n kinds: [API_KEY_PRINCIPAL_KIND],\n acceptance: options.acceptance ?? \"explicit\",\n delegates: true,\n credentialHeaders: [header],\n effects: { consumesQuota: true, writes: true },\n requires: { plugins: [\"api-key\"] },\n appliesTo: (request) => request.headers.has(header),\n async resolve(request) {\n if (!request.headers.has(header)) {\n return absent();\n }\n return request.memo(verificationMemo, async () => {\n const key = request.headers.get(header)!;\n const headers = new Headers();\n for (const name of [\"host\", \"x-forwarded-host\", \"x-forwarded-proto\"]) {\n const value = request.headers.get(name);\n if (value !== null) {\n headers.set(name, value);\n }\n }\n const started = performance.now();\n try {\n const result = await request.auth.run(\n {\n cookies: request.cookies,\n inbound: () => request.headers,\n internal: true,\n },\n () =>\n (request.auth.api as unknown as KeyApi).verifyApiKey({\n body: {\n key,\n ...(options.configId === undefined\n ? {}\n : { configId: options.configId }),\n },\n headers,\n }),\n );\n if (result.valid) {\n const verified = result.key;\n if (\n !verified ||\n typeof verified.id !== \"string\" ||\n typeof verified.referenceId !== \"string\"\n ) {\n throw new BetterAuthInfrastructureError(\n new Error(\"Malformed API-key verification result\"),\n );\n }\n const configId = verified.configId ?? null;\n const references =\n typeof options.references === \"function\"\n ? options.references({ configId })\n : (options.references ?? \"user\");\n const permissions = verified.permissions ?? null;\n const grant = role(permissions ?? {});\n return authenticated({\n kind: API_KEY_PRINCIPAL_KIND,\n source: \"better-auth:api-key\",\n keyId: verified.id,\n configId,\n referenceId: verified.referenceId,\n userId: references === \"user\" ? verified.referenceId : null,\n organizationId:\n references === \"organization\" ? verified.referenceId : null,\n permissions,\n delegation: {\n description: \"api-key permissions\",\n allows: (requested) => grant.authorize(requested).success,\n },\n });\n }\n const code = result.error?.code;\n if (code === \"RATE_LIMITED\" || code === \"USAGE_EXCEEDED\") {\n const retry = result.error?.details?.tryAgainIn;\n return rejected(\n AuthFailures.rejected({\n status: 429,\n reason: code,\n ...(code === \"RATE_LIMITED\" && typeof retry === \"number\"\n ? { retryAfterSeconds: retry / 1000 }\n : {}),\n }),\n );\n }\n if (code === \"INVALID_API_KEY\" && options.outageProbe !== false) {\n if (slowMs !== false && performance.now() - started > slowMs) {\n throw new BetterAuthInfrastructureError(\n new Error(\"API-key verification exceeded the outage threshold\"),\n );\n }\n await probe(request.auth);\n }\n if (\n code === \"INVALID_API_KEY\" ||\n code === \"KEY_NOT_FOUND\" ||\n code === \"KEY_DISABLED\" ||\n code === \"KEY_EXPIRED\"\n ) {\n return rejected(\n AuthFailures.rejected({ status: 401, reason: code }),\n );\n }\n throw new BetterAuthInfrastructureError(\n new Error(\n `Unexpected API-key verification error: ${code ?? \"missing code\"}`,\n ),\n );\n } catch (error) {\n const failure = normalizeThrown(\n error,\n \"source\",\n \"better-auth:api-key\",\n [key],\n );\n if (\"sessionLoss\" in failure) {\n throw new BetterAuthInfrastructureError(error, { secrets: [key] });\n }\n return rejected(failure);\n }\n });\n },\n };\n}\nconst apiKeyPermissionPolicy: AuthorizationPolicy<\n Record<string, string[]>,\n ApiKeyPrincipal\n> = {\n id: \"better-auth:api-key/permission\",\n requires: { plugins: [\"api-key\"], principals: [API_KEY_PRINCIPAL_KIND] },\n validate(permissions) {\n if (\n !Object.keys(permissions).length ||\n Object.values(permissions).some(\n (actions) => !Array.isArray(actions) || !actions.length,\n )\n ) {\n throw new BetterAuthConfigurationError(\n \"EMPTY_PERMISSIONS\",\n \"API-key permissions must contain a resource and actions.\",\n );\n }\n },\n evaluate(permissions, context) {\n return context.principal.delegation.allows(permissions)\n ? { effect: \"allow\" }\n : { effect: \"deny\", reason: \"MISSING_PERMISSION\" };\n },\n};\nexport function apiKeyPermission(\n permissions: Record<string, string[]>,\n): Requirement<Record<string, string[]>> {\n return { policy: apiKeyPermissionPolicy, params: permissions };\n}\nexport function RequireApiKeyPermission(\n permissions: Record<string, string[]>,\n): ClassDecorator & MethodDecorator {\n return Require(apiKeyPermission(permissions));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"api-key.cjs","names":["BetterAuthConfigurationError","absent","BetterAuthInfrastructureError","role","authenticated","rejected","AuthFailures","normalizeThrown","Require"],"sources":["../src/api-key.ts"],"sourcesContent":["import { role } from \"better-auth/plugins/access\";\nimport type {\n AuthHandle,\n AuthPrincipalBase,\n AuthorizationPolicy,\n PrincipalDelegation,\n PrincipalSource,\n Requirement,\n} from \"./auth-contracts.js\";\nimport { Require } from \"./auth-decorators.js\";\nimport {\n AuthFailures,\n BetterAuthConfigurationError,\n BetterAuthInfrastructureError,\n normalizeThrown,\n} from \"./auth-errors.js\";\nimport { absent, authenticated, rejected } from \"./principal-resolver.js\";\n\nexport const API_KEY_PRINCIPAL_KIND = \"api-key\" as const;\nexport interface ApiKeyPrincipal extends AuthPrincipalBase {\n readonly kind: \"api-key\";\n readonly keyId: string;\n readonly configId: string | null;\n readonly referenceId: string;\n readonly userId: string | null;\n readonly organizationId: string | null;\n readonly permissions: Readonly<Record<string, readonly string[]>> | null;\n readonly delegation: PrincipalDelegation;\n}\n// The public module identity survives declaration bundling in both output formats.\ndeclare module \"nestjs-slightly-better-auth\" {\n interface PrincipalKinds {\n \"api-key\": ApiKeyPrincipal;\n }\n}\nexport interface ApiKeyPrincipalOptions {\n header?: string;\n configId?: string;\n references?:\n | \"user\"\n | \"organization\"\n | ((key: { readonly configId: string | null }) => \"user\" | \"organization\");\n /**\n * Default true: slow INVALID_API_KEY results (>500 ms) throw infrastructure errors,\n * then fast failures share one read/no-op-write probe per second per instance.\n * false disables both checks; { slowMs: false } keeps only the probe.\n * Set slowMs below pool lock/statement timeouts and above custom hashing costs.\n * Fast failures confined to one row, or secondary storage without database fallback,\n * may still look like invalid keys. A statement-level trigger can observe the zero-row write.\n */\n outageProbe?: boolean | { readonly slowMs?: number | false };\n acceptance?: \"default\" | \"explicit\";\n}\ninterface VerifiedKey {\n id: string;\n configId?: string | null;\n referenceId: string;\n permissions?: Record<string, readonly string[]> | null;\n}\ninterface Verification {\n valid: boolean;\n key?: VerifiedKey | null;\n error?: { code?: string; details?: { tryAgainIn?: number } } | null;\n}\ninterface KeyApi {\n verifyApiKey(input: {\n body: { key: string; configId?: string };\n headers: Headers;\n }): Promise<Verification>;\n}\nexport function apiKeyPrincipal(\n options: ApiKeyPrincipalOptions = {},\n): PrincipalSource<ApiKeyPrincipal> {\n const header = options.header ?? \"x-api-key\";\n const slowMs =\n typeof options.outageProbe === \"object\"\n ? (options.outageProbe.slowMs ?? 500)\n : 500;\n if (\n !header.trim() ||\n (slowMs !== false && (!Number.isFinite(slowMs) || slowMs < 0))\n ) {\n throw new BetterAuthConfigurationError(\n \"INVALID_API_KEY_OPTIONS\",\n \"API-key header must be nonempty and slowMs must be finite and nonnegative.\",\n );\n }\n const verificationMemo = Symbol(\"api-key-verification\");\n const probes = new WeakMap<\n object,\n { at: number; pending: boolean; result: Promise<void> }\n >();\n async function probe(auth: AuthHandle): Promise<void> {\n const previous = probes.get(auth.instance);\n if (previous && (previous.pending || Date.now() - previous.at < 1000)) {\n return previous.result;\n }\n const result = (async () => {\n const context = await auth.context();\n // The logical key column is string-valued for default, UUID and serial IDs.\n const where = [{ field: \"key\", value: crypto.randomUUID() }];\n await context.adapter.findOne({ model: \"apikey\", where });\n await context.adapter.updateMany({\n model: \"apikey\",\n where,\n update: { updatedAt: new Date() },\n });\n })();\n const state = { at: Date.now(), pending: true, result };\n probes.set(auth.instance, state);\n void result.then(\n () => {\n state.pending = false;\n },\n () => {\n state.pending = false;\n },\n );\n return result;\n }\n return {\n id: \"better-auth:api-key\",\n kinds: [API_KEY_PRINCIPAL_KIND],\n acceptance: options.acceptance ?? \"explicit\",\n delegates: true,\n credentialHeaders: [header],\n effects: { consumesQuota: true, writes: true },\n requires: { plugins: [\"api-key\"] },\n appliesTo: (request) => request.headers.has(header),\n async resolve(request) {\n if (!request.headers.has(header)) {\n return absent();\n }\n return request.memo(verificationMemo, async () => {\n const key = request.headers.get(header)!;\n const headers = new Headers();\n for (const name of [\"host\", \"x-forwarded-host\", \"x-forwarded-proto\"]) {\n const value = request.headers.get(name);\n if (value !== null) {\n headers.set(name, value);\n }\n }\n const started = performance.now();\n try {\n const result = await request.auth.run(\n {\n cookies: request.cookies,\n inbound: () => request.headers,\n internal: true,\n },\n () =>\n (request.auth.api as unknown as KeyApi).verifyApiKey({\n body: {\n key,\n ...(options.configId === undefined\n ? {}\n : { configId: options.configId }),\n },\n headers,\n }),\n );\n if (result.valid) {\n const verified = result.key;\n if (\n !verified ||\n typeof verified.id !== \"string\" ||\n typeof verified.referenceId !== \"string\"\n ) {\n throw new BetterAuthInfrastructureError(\n new Error(\"Malformed API-key verification result\"),\n );\n }\n const configId = verified.configId ?? null;\n const references =\n typeof options.references === \"function\"\n ? options.references({ configId })\n : (options.references ?? \"user\");\n const permissions = verified.permissions ?? null;\n const grant = role(permissions ?? {});\n return authenticated({\n kind: API_KEY_PRINCIPAL_KIND,\n source: \"better-auth:api-key\",\n keyId: verified.id,\n configId,\n referenceId: verified.referenceId,\n userId: references === \"user\" ? verified.referenceId : null,\n organizationId:\n references === \"organization\" ? verified.referenceId : null,\n permissions,\n delegation: {\n description: \"api-key permissions\",\n allows: (requested) => grant.authorize(requested).success,\n },\n });\n }\n const code = result.error?.code;\n if (code === \"RATE_LIMITED\" || code === \"USAGE_EXCEEDED\") {\n const retry = result.error?.details?.tryAgainIn;\n return rejected(\n AuthFailures.rejected({\n status: 429,\n reason: code,\n ...(code === \"RATE_LIMITED\" && typeof retry === \"number\"\n ? { retryAfterSeconds: retry / 1000 }\n : {}),\n }),\n );\n }\n if (code === \"INVALID_API_KEY\" && options.outageProbe !== false) {\n if (slowMs !== false && performance.now() - started > slowMs) {\n throw new BetterAuthInfrastructureError(\n new Error(\"API-key verification exceeded the outage threshold\"),\n );\n }\n await probe(request.auth);\n }\n if (\n code === \"INVALID_API_KEY\" ||\n code === \"KEY_NOT_FOUND\" ||\n code === \"KEY_DISABLED\" ||\n code === \"KEY_EXPIRED\"\n ) {\n return rejected(\n AuthFailures.rejected({ status: 401, reason: code }),\n );\n }\n throw new BetterAuthInfrastructureError(\n new Error(\n `Unexpected API-key verification error: ${code ?? \"missing code\"}`,\n ),\n );\n } catch (error) {\n const failure = normalizeThrown(\n error,\n \"source\",\n \"better-auth:api-key\",\n [key],\n );\n if (\"sessionLoss\" in failure) {\n throw new BetterAuthInfrastructureError(error, { secrets: [key] });\n }\n return rejected(failure);\n }\n });\n },\n };\n}\nconst apiKeyPermissionPolicy: AuthorizationPolicy<\n Record<string, string[]>,\n ApiKeyPrincipal\n> = {\n id: \"better-auth:api-key/permission\",\n requires: { plugins: [\"api-key\"], principals: [API_KEY_PRINCIPAL_KIND] },\n validate(permissions) {\n if (\n !Object.keys(permissions).length ||\n Object.values(permissions).some(\n (actions) => !Array.isArray(actions) || !actions.length,\n )\n ) {\n throw new BetterAuthConfigurationError(\n \"EMPTY_PERMISSIONS\",\n \"API-key permissions must contain a resource and actions.\",\n );\n }\n },\n evaluate(permissions, context) {\n return context.principal.delegation.allows(permissions)\n ? { effect: \"allow\" }\n : { effect: \"deny\", reason: \"MISSING_PERMISSION\" };\n },\n};\nexport function apiKeyPermission(\n permissions: Record<string, string[]>,\n): Requirement<Record<string, string[]>> {\n return { policy: apiKeyPermissionPolicy, params: permissions };\n}\nexport function RequireApiKeyPermission(\n permissions: Record<string, string[]>,\n): ClassDecorator & MethodDecorator {\n return Require(apiKeyPermission(permissions));\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Y as PrincipalDelegation, et as PrincipalSource, nt as Requirement, o as AuthPrincipalBase } from "./auth-contracts-BBA1C1gj.cjs";
1
+ import { $ as PrincipalDelegation, it as PrincipalSource, o as AuthPrincipalBase, ot as Requirement } from "./auth-contracts-CL8TEt5t.cjs";
2
2
  //#region src/api-key.d.ts
3
3
  export declare const API_KEY_PRINCIPAL_KIND: "api-key";
4
4
  export interface ApiKeyPrincipal extends AuthPrincipalBase {
@@ -1,4 +1,4 @@
1
- import { Y as PrincipalDelegation, et as PrincipalSource, nt as Requirement, o as AuthPrincipalBase } from "./auth-contracts-tqsfBZ8B.mjs";
1
+ import { $ as PrincipalDelegation, it as PrincipalSource, o as AuthPrincipalBase, ot as Requirement } from "./auth-contracts-CnGaBzlg.mjs";
2
2
  //#region src/api-key.d.ts
3
3
  export declare const API_KEY_PRINCIPAL_KIND: "api-key";
4
4
  export interface ApiKeyPrincipal extends AuthPrincipalBase {
package/dist/api-key.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import { n as BetterAuthConfigurationError, r as BetterAuthInfrastructureError, t as AuthFailures, u as normalizeThrown } from "./auth-errors-CQjfgjaO.mjs";
2
- import { F as authenticated, P as absent, R as rejected, u as Require } from "./auth-decorators-DfAJbHar.mjs";
1
+ import { n as BetterAuthConfigurationError, r as BetterAuthInfrastructureError, t as AuthFailures, u as normalizeThrown } from "./auth-errors-B6jLBpQu.mjs";
2
+ import { c as absent, f as rejected, l as authenticated } from "./principal-readings-BKeyOxwJ.mjs";
3
+ import { u as Require } from "./auth-decorators-BmUNYTFd.mjs";
3
4
  import { role } from "better-auth/plugins/access";
4
5
  //#region src/api-key.ts
5
6
  const API_KEY_PRINCIPAL_KIND = "api-key";
@@ -1 +1 @@
1
- {"version":3,"file":"api-key.mjs","names":[],"sources":["../src/api-key.ts"],"sourcesContent":["import { role } from \"better-auth/plugins/access\";\nimport type {\n AuthHandle,\n AuthPrincipalBase,\n AuthorizationPolicy,\n PrincipalDelegation,\n PrincipalSource,\n Requirement,\n} from \"./auth-contracts.js\";\nimport { Require } from \"./auth-decorators.js\";\nimport {\n AuthFailures,\n BetterAuthConfigurationError,\n BetterAuthInfrastructureError,\n normalizeThrown,\n} from \"./auth-errors.js\";\nimport { absent, authenticated, rejected } from \"./principal-resolver.js\";\n\nexport const API_KEY_PRINCIPAL_KIND = \"api-key\" as const;\nexport interface ApiKeyPrincipal extends AuthPrincipalBase {\n readonly kind: \"api-key\";\n readonly keyId: string;\n readonly configId: string | null;\n readonly referenceId: string;\n readonly userId: string | null;\n readonly organizationId: string | null;\n readonly permissions: Readonly<Record<string, readonly string[]>> | null;\n readonly delegation: PrincipalDelegation;\n}\n// The public module identity survives declaration bundling in both output formats.\ndeclare module \"nestjs-slightly-better-auth\" {\n interface PrincipalKinds {\n \"api-key\": ApiKeyPrincipal;\n }\n}\nexport interface ApiKeyPrincipalOptions {\n header?: string;\n configId?: string;\n references?:\n | \"user\"\n | \"organization\"\n | ((key: { readonly configId: string | null }) => \"user\" | \"organization\");\n /**\n * Default true: slow INVALID_API_KEY results (>500 ms) throw infrastructure errors,\n * then fast failures share one read/no-op-write probe per second per instance.\n * false disables both checks; { slowMs: false } keeps only the probe.\n * Set slowMs below pool lock/statement timeouts and above custom hashing costs.\n * Fast failures confined to one row, or secondary storage without database fallback,\n * may still look like invalid keys. A statement-level trigger can observe the zero-row write.\n */\n outageProbe?: boolean | { readonly slowMs?: number | false };\n acceptance?: \"default\" | \"explicit\";\n}\ninterface VerifiedKey {\n id: string;\n configId?: string | null;\n referenceId: string;\n permissions?: Record<string, readonly string[]> | null;\n}\ninterface Verification {\n valid: boolean;\n key?: VerifiedKey | null;\n error?: { code?: string; details?: { tryAgainIn?: number } } | null;\n}\ninterface KeyApi {\n verifyApiKey(input: {\n body: { key: string; configId?: string };\n headers: Headers;\n }): Promise<Verification>;\n}\nexport function apiKeyPrincipal(\n options: ApiKeyPrincipalOptions = {},\n): PrincipalSource<ApiKeyPrincipal> {\n const header = options.header ?? \"x-api-key\";\n const slowMs =\n typeof options.outageProbe === \"object\"\n ? (options.outageProbe.slowMs ?? 500)\n : 500;\n if (\n !header.trim() ||\n (slowMs !== false && (!Number.isFinite(slowMs) || slowMs < 0))\n ) {\n throw new BetterAuthConfigurationError(\n \"INVALID_API_KEY_OPTIONS\",\n \"API-key header must be nonempty and slowMs must be finite and nonnegative.\",\n );\n }\n const verificationMemo = Symbol(\"api-key-verification\");\n const probes = new WeakMap<\n object,\n { at: number; pending: boolean; result: Promise<void> }\n >();\n async function probe(auth: AuthHandle): Promise<void> {\n const previous = probes.get(auth.instance);\n if (previous && (previous.pending || Date.now() - previous.at < 1000)) {\n return previous.result;\n }\n const result = (async () => {\n const context = await auth.context();\n // The logical key column is string-valued for default, UUID and serial IDs.\n const where = [{ field: \"key\", value: crypto.randomUUID() }];\n await context.adapter.findOne({ model: \"apikey\", where });\n await context.adapter.updateMany({\n model: \"apikey\",\n where,\n update: { updatedAt: new Date() },\n });\n })();\n const state = { at: Date.now(), pending: true, result };\n probes.set(auth.instance, state);\n void result.then(\n () => {\n state.pending = false;\n },\n () => {\n state.pending = false;\n },\n );\n return result;\n }\n return {\n id: \"better-auth:api-key\",\n kinds: [API_KEY_PRINCIPAL_KIND],\n acceptance: options.acceptance ?? \"explicit\",\n delegates: true,\n credentialHeaders: [header],\n effects: { consumesQuota: true, writes: true },\n requires: { plugins: [\"api-key\"] },\n appliesTo: (request) => request.headers.has(header),\n async resolve(request) {\n if (!request.headers.has(header)) {\n return absent();\n }\n return request.memo(verificationMemo, async () => {\n const key = request.headers.get(header)!;\n const headers = new Headers();\n for (const name of [\"host\", \"x-forwarded-host\", \"x-forwarded-proto\"]) {\n const value = request.headers.get(name);\n if (value !== null) {\n headers.set(name, value);\n }\n }\n const started = performance.now();\n try {\n const result = await request.auth.run(\n {\n cookies: request.cookies,\n inbound: () => request.headers,\n internal: true,\n },\n () =>\n (request.auth.api as unknown as KeyApi).verifyApiKey({\n body: {\n key,\n ...(options.configId === undefined\n ? {}\n : { configId: options.configId }),\n },\n headers,\n }),\n );\n if (result.valid) {\n const verified = result.key;\n if (\n !verified ||\n typeof verified.id !== \"string\" ||\n typeof verified.referenceId !== \"string\"\n ) {\n throw new BetterAuthInfrastructureError(\n new Error(\"Malformed API-key verification result\"),\n );\n }\n const configId = verified.configId ?? null;\n const references =\n typeof options.references === \"function\"\n ? options.references({ configId })\n : (options.references ?? \"user\");\n const permissions = verified.permissions ?? null;\n const grant = role(permissions ?? {});\n return authenticated({\n kind: API_KEY_PRINCIPAL_KIND,\n source: \"better-auth:api-key\",\n keyId: verified.id,\n configId,\n referenceId: verified.referenceId,\n userId: references === \"user\" ? verified.referenceId : null,\n organizationId:\n references === \"organization\" ? verified.referenceId : null,\n permissions,\n delegation: {\n description: \"api-key permissions\",\n allows: (requested) => grant.authorize(requested).success,\n },\n });\n }\n const code = result.error?.code;\n if (code === \"RATE_LIMITED\" || code === \"USAGE_EXCEEDED\") {\n const retry = result.error?.details?.tryAgainIn;\n return rejected(\n AuthFailures.rejected({\n status: 429,\n reason: code,\n ...(code === \"RATE_LIMITED\" && typeof retry === \"number\"\n ? { retryAfterSeconds: retry / 1000 }\n : {}),\n }),\n );\n }\n if (code === \"INVALID_API_KEY\" && options.outageProbe !== false) {\n if (slowMs !== false && performance.now() - started > slowMs) {\n throw new BetterAuthInfrastructureError(\n new Error(\"API-key verification exceeded the outage threshold\"),\n );\n }\n await probe(request.auth);\n }\n if (\n code === \"INVALID_API_KEY\" ||\n code === \"KEY_NOT_FOUND\" ||\n code === \"KEY_DISABLED\" ||\n code === \"KEY_EXPIRED\"\n ) {\n return rejected(\n AuthFailures.rejected({ status: 401, reason: code }),\n );\n }\n throw new BetterAuthInfrastructureError(\n new Error(\n `Unexpected API-key verification error: ${code ?? \"missing code\"}`,\n ),\n );\n } catch (error) {\n const failure = normalizeThrown(\n error,\n \"source\",\n \"better-auth:api-key\",\n [key],\n );\n if (\"sessionLoss\" in failure) {\n throw new BetterAuthInfrastructureError(error, { secrets: [key] });\n }\n return rejected(failure);\n }\n });\n },\n };\n}\nconst apiKeyPermissionPolicy: AuthorizationPolicy<\n Record<string, string[]>,\n ApiKeyPrincipal\n> = {\n id: \"better-auth:api-key/permission\",\n requires: { plugins: [\"api-key\"], principals: [API_KEY_PRINCIPAL_KIND] },\n validate(permissions) {\n if (\n !Object.keys(permissions).length ||\n Object.values(permissions).some(\n (actions) => !Array.isArray(actions) || !actions.length,\n )\n ) {\n throw new BetterAuthConfigurationError(\n \"EMPTY_PERMISSIONS\",\n \"API-key permissions must contain a resource and actions.\",\n );\n }\n },\n evaluate(permissions, context) {\n return context.principal.delegation.allows(permissions)\n ? { effect: \"allow\" }\n : { effect: \"deny\", reason: \"MISSING_PERMISSION\" };\n },\n};\nexport function apiKeyPermission(\n permissions: Record<string, string[]>,\n): Requirement<Record<string, string[]>> {\n return { policy: apiKeyPermissionPolicy, params: permissions };\n}\nexport function RequireApiKeyPermission(\n permissions: Record<string, string[]>,\n): ClassDecorator & MethodDecorator {\n return Require(apiKeyPermission(permissions));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"api-key.mjs","names":[],"sources":["../src/api-key.ts"],"sourcesContent":["import { role } from \"better-auth/plugins/access\";\nimport type {\n AuthHandle,\n AuthPrincipalBase,\n AuthorizationPolicy,\n PrincipalDelegation,\n PrincipalSource,\n Requirement,\n} from \"./auth-contracts.js\";\nimport { Require } from \"./auth-decorators.js\";\nimport {\n AuthFailures,\n BetterAuthConfigurationError,\n BetterAuthInfrastructureError,\n normalizeThrown,\n} from \"./auth-errors.js\";\nimport { absent, authenticated, rejected } from \"./principal-resolver.js\";\n\nexport const API_KEY_PRINCIPAL_KIND = \"api-key\" as const;\nexport interface ApiKeyPrincipal extends AuthPrincipalBase {\n readonly kind: \"api-key\";\n readonly keyId: string;\n readonly configId: string | null;\n readonly referenceId: string;\n readonly userId: string | null;\n readonly organizationId: string | null;\n readonly permissions: Readonly<Record<string, readonly string[]>> | null;\n readonly delegation: PrincipalDelegation;\n}\n// The public module identity survives declaration bundling in both output formats.\ndeclare module \"nestjs-slightly-better-auth\" {\n interface PrincipalKinds {\n \"api-key\": ApiKeyPrincipal;\n }\n}\nexport interface ApiKeyPrincipalOptions {\n header?: string;\n configId?: string;\n references?:\n | \"user\"\n | \"organization\"\n | ((key: { readonly configId: string | null }) => \"user\" | \"organization\");\n /**\n * Default true: slow INVALID_API_KEY results (>500 ms) throw infrastructure errors,\n * then fast failures share one read/no-op-write probe per second per instance.\n * false disables both checks; { slowMs: false } keeps only the probe.\n * Set slowMs below pool lock/statement timeouts and above custom hashing costs.\n * Fast failures confined to one row, or secondary storage without database fallback,\n * may still look like invalid keys. A statement-level trigger can observe the zero-row write.\n */\n outageProbe?: boolean | { readonly slowMs?: number | false };\n acceptance?: \"default\" | \"explicit\";\n}\ninterface VerifiedKey {\n id: string;\n configId?: string | null;\n referenceId: string;\n permissions?: Record<string, readonly string[]> | null;\n}\ninterface Verification {\n valid: boolean;\n key?: VerifiedKey | null;\n error?: { code?: string; details?: { tryAgainIn?: number } } | null;\n}\ninterface KeyApi {\n verifyApiKey(input: {\n body: { key: string; configId?: string };\n headers: Headers;\n }): Promise<Verification>;\n}\nexport function apiKeyPrincipal(\n options: ApiKeyPrincipalOptions = {},\n): PrincipalSource<ApiKeyPrincipal> {\n const header = options.header ?? \"x-api-key\";\n const slowMs =\n typeof options.outageProbe === \"object\"\n ? (options.outageProbe.slowMs ?? 500)\n : 500;\n if (\n !header.trim() ||\n (slowMs !== false && (!Number.isFinite(slowMs) || slowMs < 0))\n ) {\n throw new BetterAuthConfigurationError(\n \"INVALID_API_KEY_OPTIONS\",\n \"API-key header must be nonempty and slowMs must be finite and nonnegative.\",\n );\n }\n const verificationMemo = Symbol(\"api-key-verification\");\n const probes = new WeakMap<\n object,\n { at: number; pending: boolean; result: Promise<void> }\n >();\n async function probe(auth: AuthHandle): Promise<void> {\n const previous = probes.get(auth.instance);\n if (previous && (previous.pending || Date.now() - previous.at < 1000)) {\n return previous.result;\n }\n const result = (async () => {\n const context = await auth.context();\n // The logical key column is string-valued for default, UUID and serial IDs.\n const where = [{ field: \"key\", value: crypto.randomUUID() }];\n await context.adapter.findOne({ model: \"apikey\", where });\n await context.adapter.updateMany({\n model: \"apikey\",\n where,\n update: { updatedAt: new Date() },\n });\n })();\n const state = { at: Date.now(), pending: true, result };\n probes.set(auth.instance, state);\n void result.then(\n () => {\n state.pending = false;\n },\n () => {\n state.pending = false;\n },\n );\n return result;\n }\n return {\n id: \"better-auth:api-key\",\n kinds: [API_KEY_PRINCIPAL_KIND],\n acceptance: options.acceptance ?? \"explicit\",\n delegates: true,\n credentialHeaders: [header],\n effects: { consumesQuota: true, writes: true },\n requires: { plugins: [\"api-key\"] },\n appliesTo: (request) => request.headers.has(header),\n async resolve(request) {\n if (!request.headers.has(header)) {\n return absent();\n }\n return request.memo(verificationMemo, async () => {\n const key = request.headers.get(header)!;\n const headers = new Headers();\n for (const name of [\"host\", \"x-forwarded-host\", \"x-forwarded-proto\"]) {\n const value = request.headers.get(name);\n if (value !== null) {\n headers.set(name, value);\n }\n }\n const started = performance.now();\n try {\n const result = await request.auth.run(\n {\n cookies: request.cookies,\n inbound: () => request.headers,\n internal: true,\n },\n () =>\n (request.auth.api as unknown as KeyApi).verifyApiKey({\n body: {\n key,\n ...(options.configId === undefined\n ? {}\n : { configId: options.configId }),\n },\n headers,\n }),\n );\n if (result.valid) {\n const verified = result.key;\n if (\n !verified ||\n typeof verified.id !== \"string\" ||\n typeof verified.referenceId !== \"string\"\n ) {\n throw new BetterAuthInfrastructureError(\n new Error(\"Malformed API-key verification result\"),\n );\n }\n const configId = verified.configId ?? null;\n const references =\n typeof options.references === \"function\"\n ? options.references({ configId })\n : (options.references ?? \"user\");\n const permissions = verified.permissions ?? null;\n const grant = role(permissions ?? {});\n return authenticated({\n kind: API_KEY_PRINCIPAL_KIND,\n source: \"better-auth:api-key\",\n keyId: verified.id,\n configId,\n referenceId: verified.referenceId,\n userId: references === \"user\" ? verified.referenceId : null,\n organizationId:\n references === \"organization\" ? verified.referenceId : null,\n permissions,\n delegation: {\n description: \"api-key permissions\",\n allows: (requested) => grant.authorize(requested).success,\n },\n });\n }\n const code = result.error?.code;\n if (code === \"RATE_LIMITED\" || code === \"USAGE_EXCEEDED\") {\n const retry = result.error?.details?.tryAgainIn;\n return rejected(\n AuthFailures.rejected({\n status: 429,\n reason: code,\n ...(code === \"RATE_LIMITED\" && typeof retry === \"number\"\n ? { retryAfterSeconds: retry / 1000 }\n : {}),\n }),\n );\n }\n if (code === \"INVALID_API_KEY\" && options.outageProbe !== false) {\n if (slowMs !== false && performance.now() - started > slowMs) {\n throw new BetterAuthInfrastructureError(\n new Error(\"API-key verification exceeded the outage threshold\"),\n );\n }\n await probe(request.auth);\n }\n if (\n code === \"INVALID_API_KEY\" ||\n code === \"KEY_NOT_FOUND\" ||\n code === \"KEY_DISABLED\" ||\n code === \"KEY_EXPIRED\"\n ) {\n return rejected(\n AuthFailures.rejected({ status: 401, reason: code }),\n );\n }\n throw new BetterAuthInfrastructureError(\n new Error(\n `Unexpected API-key verification error: ${code ?? \"missing code\"}`,\n ),\n );\n } catch (error) {\n const failure = normalizeThrown(\n error,\n \"source\",\n \"better-auth:api-key\",\n [key],\n );\n if (\"sessionLoss\" in failure) {\n throw new BetterAuthInfrastructureError(error, { secrets: [key] });\n }\n return rejected(failure);\n }\n });\n },\n };\n}\nconst apiKeyPermissionPolicy: AuthorizationPolicy<\n Record<string, string[]>,\n ApiKeyPrincipal\n> = {\n id: \"better-auth:api-key/permission\",\n requires: { plugins: [\"api-key\"], principals: [API_KEY_PRINCIPAL_KIND] },\n validate(permissions) {\n if (\n !Object.keys(permissions).length ||\n Object.values(permissions).some(\n (actions) => !Array.isArray(actions) || !actions.length,\n )\n ) {\n throw new BetterAuthConfigurationError(\n \"EMPTY_PERMISSIONS\",\n \"API-key permissions must contain a resource and actions.\",\n );\n }\n },\n evaluate(permissions, context) {\n return context.principal.delegation.allows(permissions)\n ? { effect: \"allow\" }\n : { effect: \"deny\", reason: \"MISSING_PERMISSION\" };\n },\n};\nexport function apiKeyPermission(\n permissions: Record<string, string[]>,\n): Requirement<Record<string, string[]>> {\n return { policy: apiKeyPermissionPolicy, params: permissions };\n}\nexport function RequireApiKeyPermission(\n permissions: Record<string, string[]>,\n): ClassDecorator & MethodDecorator {\n return Require(apiKeyPermission(permissions));\n}\n"],"mappings":"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"}
@@ -143,6 +143,7 @@ declare class BetterAuthModule {
143
143
  //#endregion
144
144
  //#region src/bridge-protocol.d.ts
145
145
  declare const EXTENSION_DEFINITION: unique symbol;
146
+ declare const UPGRADE_REQUEST: unique symbol;
146
147
  interface BridgeHandle {
147
148
  readonly protocol: 4;
148
149
  readonly clientIpHeader: string | null;
@@ -975,6 +976,31 @@ interface FastifyPlatformOptions {
975
976
  raw: IncomingMessage;
976
977
  }) => string | null;
977
978
  }
979
+ interface ConformanceCase {
980
+ readonly id: string;
981
+ readonly title: string;
982
+ /** Why the case does not apply, when that is known before it runs. */
983
+ readonly skip?: string;
984
+ /**
985
+ * Runs the case. It resolves with a ConformanceSkip when the case finds at run time that it does not apply, for
986
+ * example because a unit registered through defineExtension() lacks an optional capability.
987
+ */
988
+ run(): Promise<ConformanceOutcome>;
989
+ }
990
+ /** A case that found at run time that it does not apply. */
991
+ interface ConformanceSkip {
992
+ readonly skipped: string;
993
+ }
994
+ /** What a case's run() resolves with: nothing when it passed, a ConformanceSkip when it does not apply. */
995
+ type ConformanceOutcome = void | ConformanceSkip;
996
+ interface ConformanceRunner {
997
+ describe(name: string, fn: () => void): void;
998
+ /**
999
+ * Registers a test. runConformance passes a function without declared parameters; when the runner hands it a test
1000
+ * context with skip(note) (Vitest, node:test), a case that skips at run time is reported as skipped.
1001
+ */
1002
+ it(name: string, fn: (context?: unknown) => Promise<void>): void;
1003
+ }
978
1004
  interface BootAdvice {
979
1005
  readonly level: "warn" | "info";
980
1006
  /** Stable code, e.g. 'W_API_KEY_SESSION_MULTIPLIER'. */
@@ -1631,5 +1657,5 @@ interface PolicyBootContext {
1631
1657
  readonly site: string;
1632
1658
  }
1633
1659
  //#endregion
1634
- export { PrincipalResult as $, AfterAuth as $t, ExpressPlatformOptions as A, POLICY_INVOKER as An, PrincipalOfKind as At, HttpRequestAccessor as B, AuthFailures as Bn, httpTransport as Bt, CookieForwardingOptions as C, allow as Cn, DatabaseHookMethod as Ct, DbHookMethodDecorator as D, EXTENSION_DEFINITION as Dn, IsRegistered as Dt, DatabaseHookTarget as E, BetterAuthService as En, GetSessionWithHeaders as Et, HookMethodDecorator as F, getBetterAuthOptionsToken as Fn, SessionPrincipal as Ft, PlatformPrepareContext as G, ErrorMappingOptions as Gn, rejected as Gt, InvocationLineage as H, AuthTransportErrorPayload as Hn, absent as Ht, HookOptions as I, getBetterAuthServiceToken as In, UnvalidatedBody as It, PolicyRef as J, isConfigurationError as Jn, RequireFreshSession as Jt, PolicyBootContext as K, getRawCause as Kn, CurrentSession as Kt, HookPredicate as L, AuthErrorBody as Ln, UserOf as Lt, ExtensionRef as M, SCOPE_CORE as Mn, RegisteredAuth as Mt, FastifyPlatformOptions as N, getBetterAuthHandleToken as Nn, RegisteredInstances as Nt, DbHookOptions as O, BetterAuthModule as On, OrgPermissions as Ot, GuardReach as P, getBetterAuthInstanceToken as Pn, SessionOf as Pt, PrincipalResolver as Q, AcceptPrincipals as Qt, HttpMountOptions as R, AuthErrorCode as Rn, WithActiveOrganization as Rt, ClaimOptions as S, BetterAuthGuard as Sn, DatabaseHookData as St, CorsOriginOptions as T, deny as Tn, EndpointPath as Tt, OriginCheckOptions as U, BetterAuthConfigurationError as Un, authenticated as Ut, InboundAuthRequest as V, AuthGraphqlExtensions as Vn, betterAuthCorsOrigin as Vt, PlatformMountContext as W, BetterAuthInfrastructureError as Wn, definePrincipalSource as Wt, PrincipalReading as X, freshSession as Xt, PrincipalDelegation as Y, isInfrastructureError as Yn, SESSION_PRINCIPAL_KIND as Yt, PrincipalRequest as Z, sessionPrincipal as Zt, BetterAuthRuntimeOptions as _, requirement as _n, AuthLike as _t, AuthHandlerInterceptor as a, OptionalAuth as an, ResolutionRequest as at, BootAdviceContext as b, defineTransport as bn, AuthSession as bt, AuthTransport as c, RequireAuth as cn, SessionOption as ct, AuthorizationLimits as d, UseAuthInstance as dn, TransportCall as dt, AfterDatabase as en, PrincipalSource as et, AuthorizationPolicy as f, UseBetterAuth as fn, TransportKit as ft, BetterAuthModuleOptions as g, definePrincipalParam as gn, AuthHookContext as gt, BetterAuthModuleAsyncOptions as h, defineInvocationParam as hn, AuthAfterHookContext as ht, AuthHandle as i, ForwardAuthCookies as in, RequirementOptions as it, ExtensionDefinition as j, PRINCIPAL_RESOLVER as jn, Register as jt, DefaultInstanceCheck as k, GUARD_CORE as kn, PrincipalKind as kt, AuthorizationContext as l, SkipDefaultRequirements as ln, SessionPrincipalOptions as lt, BetterAuthFactoryResult as m, anyOf as mn, AdminPermissions as mt, ApplicationRouteDescriptor as n, BeforeDatabase as nn, Requirement as nt, AuthPrincipalBase as o, Public as on, RoutePlan as ot, BetterAuthAppOptions as p, allOf as pn, TransportValidationContext as pt, PolicyInvoker as q, isAuthFailure as qn, CurrentUser as qt, AuthContextView as r, CurrentPrincipal as rn, RequirementExpr as rt, AuthRouteBinding as s, Require as sn, ScopeInit as st, AdvisedHandler as t, BeforeAuth as tn, ProxyTrust as tt, AuthorizationDecision as u, SkipOriginCheck as un, StaticOptionMustBePassedToForRootAsync as ut, BetterAuthStaticOptions as v, defineExtension as vn, AuthOf as vt, CookieSink as w, definePolicy as wn, DatabaseHookResult as wt, BrowserExposure as x, BetterAuthScopeInterceptor as xn, AuthUser as xt, BootAdvice as y, defineHttpPlatform as yn, AuthPrincipal as yt, HttpPlatform as z, AuthFailure as zn, PrincipalKinds as zt };
1635
- //# sourceMappingURL=auth-contracts-BBA1C1gj.d.cts.map
1660
+ export { PrincipalDelegation as $, getRawCause as $n, SESSION_PRINCIPAL_KIND as $t, DatabaseHookTarget as A, BetterAuthService as An, GetSessionWithHeaders as At, HookOptions as B, getBetterAuthHandleToken as Bn, UnvalidatedBody as Bt, ConformanceCase as C, defineHttpPlatform as Cn, AuthPrincipal as Ct, CookieForwardingOptions as D, allow as Dn, DatabaseHookMethod as Dt, ConformanceSkip as E, BetterAuthGuard as En, DatabaseHookData as Et, ExtensionDefinition as F, BetterAuthModule as Fn, Register as Ft, InboundAuthRequest as G, AuthErrorCode as Gn, betterAuthCorsOrigin as Gt, HttpMountOptions as H, getBetterAuthOptionsToken as Hn, WithActiveOrganization as Ht, ExtensionRef as I, GUARD_CORE as In, RegisteredAuth as It, PlatformMountContext as J, AuthGraphqlExtensions as Jn, definePrincipalSource as Jt, InvocationLineage as K, AuthFailure as Kn, absent as Kt, FastifyPlatformOptions as L, POLICY_INVOKER as Ln, RegisteredInstances as Lt, DbHookOptions as M, InstanceLookup as Mn, OrgPermissions as Mt, DefaultInstanceCheck as N, EXTENSION_DEFINITION as Nn, PrincipalKind as Nt, CookieSink as O, definePolicy as On, DatabaseHookResult as Ot, ExpressPlatformOptions as P, UPGRADE_REQUEST as Pn, PrincipalOfKind as Pt, PolicyRef as Q, ErrorMappingOptions as Qn, RequireFreshSession as Qt, GuardReach as R, PRINCIPAL_RESOLVER as Rn, SessionOf as Rt, ClaimOptions as S, defineExtension as Sn, AuthOf as St, ConformanceRunner as T, BetterAuthScopeInterceptor as Tn, AuthUser as Tt, HttpPlatform as U, getBetterAuthServiceToken as Un, PrincipalKinds as Ut, HookPredicate as V, getBetterAuthInstanceToken as Vn, UserOf as Vt, HttpRequestAccessor as W, AuthErrorBody as Wn, httpTransport as Wt, PolicyBootContext as X, BetterAuthConfigurationError as Xn, CurrentSession as Xt, PlatformPrepareContext as Y, AuthTransportErrorPayload as Yn, rejected as Yt, PolicyInvoker as Z, BetterAuthInfrastructureError as Zn, CurrentUser as Zt, BetterAuthRuntimeOptions as _, allOf as _n, TransportValidationContext as _t, AuthHandlerInterceptor as a, BeforeAuth as an, ProxyTrust as at, BootAdviceContext as b, definePrincipalParam as bn, AuthHookContext as bt, AuthTransport as c, ForwardAuthCookies as cn, RequirementOptions as ct, AuthorizationLimits as d, Require as dn, ScopeInit as dt, freshSession as en, isAuthFailure as er, PrincipalReading as et, AuthorizationPolicy as f, RequireAuth as fn, SessionOption as ft, BetterAuthModuleOptions as g, UseBetterAuth as gn, TransportKit as gt, BetterAuthModuleAsyncOptions as h, UseAuthInstance as hn, TransportCall as ht, AuthHandle as i, AfterDatabase as in, PrincipalSource as it, DbHookMethodDecorator as j, TransportRegistry as jn, IsRegistered as jt, CorsOriginOptions as k, deny as kn, EndpointPath as kt, AuthorizationContext as l, OptionalAuth as ln, ResolutionRequest as lt, BetterAuthFactoryResult as m, SkipOriginCheck as mn, StaticOptionMustBePassedToForRootAsync as mt, ApplicationRouteDescriptor as n, AcceptPrincipals as nn, isInfrastructureError as nr, PrincipalResolver as nt, AuthPrincipalBase as o, BeforeDatabase as on, Requirement as ot, BetterAuthAppOptions as p, SkipDefaultRequirements as pn, SessionPrincipalOptions as pt, OriginCheckOptions as q, AuthFailures as qn, authenticated as qt, AuthContextView as r, AfterAuth as rn, PrincipalResult as rt, AuthRouteBinding as s, CurrentPrincipal as sn, RequirementExpr as st, AdvisedHandler as t, sessionPrincipal as tn, isConfigurationError as tr, PrincipalRequest as tt, AuthorizationDecision as u, Public as un, RoutePlan as ut, BetterAuthStaticOptions as v, anyOf as vn, AdminPermissions as vt, ConformanceOutcome as w, defineTransport as wn, AuthSession as wt, BrowserExposure as x, requirement as xn, AuthLike as xt, BootAdvice as y, defineInvocationParam as yn, AuthAfterHookContext as yt, HookMethodDecorator as z, SCOPE_CORE as zn, SessionPrincipal as zt };
1661
+ //# sourceMappingURL=auth-contracts-CL8TEt5t.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-contracts-CL8TEt5t.d.cts","names":[],"sources":["../src/auth-errors.ts","../src/auth-tokens.ts","../src/auth-module.ts","../src/bridge-protocol.ts","../src/request-scope.ts","../src/origin-check.ts","../src/instance-registry.ts","../src/mount-coordinator.ts","../src/principal-readings.ts","../src/policy-resolver.ts","../src/transport-registry.ts","../src/route-planner.ts","../src/auth-service.ts","../src/authorization-evaluator.ts","../src/auth-guard.ts","../src/auth-scope-interceptor.ts","../src/auth-module-definition.ts","../src/auth-decorators.ts","../src/session-principal.ts","../src/principal-resolver.ts","../src/auth-exchange.ts","../src/http-transport.ts","../src/index.ts","../src/auth-types.ts","../src/auth-contracts.ts"],"mappings":"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"}