nestjs-slightly-better-auth 1.10.0 → 1.12.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/README.md CHANGED
@@ -983,20 +983,34 @@ runConformance(
983
983
  );
984
984
  ```
985
985
 
986
- | Kit | Unit | Covers |
987
- | ---------------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
988
- | `httpPlatformConformance` | `HttpPlatform` | Mounting (including a dynamic `allowedHosts` base URL), byte-exact bodies, limits with host CORS, URL and header facts, client IP (production-mode per-IP rate-limit buckets, Better Auth `trustedProxies`), HTTP/2, write-back, request accessors, error delivery, lifecycle (no adapter, including microservices, late adapter, reused `TestingModule`, double `forRoot`, hooks kept after `close()`), diagnostics (404 hints, `W_PROXY_UNTRUSTED`) and log hygiene |
989
- | `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 and inherited forwarding fields, `@SkipOriginCheck()` and `disableCSRFCheck` opt-outs and direct caller-session calls, WebSocket handshake origins on every message and at connection time (untrusted, missing and forwarded origins, junk tokens, dynamic base URLs, function-valued `trustedOrigins`), subscription credentials and origins, error shapes and logging, the exact coverage report of the transport's claims, metadata canaries, `globalScope: false`, readings with and without the scope interceptor, public handlers in unclaimed contexts, inherited handlers, dynamic base URLs, stale GraphQL contexts, mixed-kind session reads, nested and federation readings, lazy scope construction and fail-closed extraction |
990
- | `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, dynamic base URLs (direct and behind a trusted proxy), credential redaction in logs and raw causes; for API-key sources the verification results, outage and write-outage probes and organization-owned keys; for session-backed sources short-circuited session reads and the cookie bridge (third-party sign-up, foreign credentials); for sources of the `jwt` plugin the issuer and audience claims and key-set outages |
991
- | `policyConformance` | `AuthorizationPolicy` | Deny values, storage outages with the cookie cache off and warm, APIError mapping and re-classification, sessions lost before the policy's call, delegation scope, unnamed-kind gating, per-invocation decisions with shared I/O, request-scoped class policies, class policies' `requires` fields, plugin prerequisites, and the admin, organization and API-key rows below; requirements name policy objects (construct a DI policy with its dependencies) |
986
+ | Kit | Unit | Covers |
987
+ | ---------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
988
+ | `httpPlatformConformance` | `HttpPlatform` | Mounting (including a dynamic `allowedHosts` base URL), byte-exact bodies, limits with host CORS, URL and header facts, client IP (production-mode per-IP rate-limit buckets, Better Auth `trustedProxies`), HTTP/2, write-back, request accessors, error delivery, lifecycle (no adapter, including microservices, late adapter, reused `TestingModule`, double `forRoot`, hooks kept after `close()`), diagnostics (404 hints, `W_PROXY_UNTRUSTED`) and log hygiene |
989
+ | `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 and inherited forwarding fields, `@SkipOriginCheck()` and `disableCSRFCheck` opt-outs, application-route checks under Better Auth's boolean origin skip, direct caller-session calls, WebSocket handshake origins on every message and at connection time (untrusted, missing and forwarded origins, junk tokens, dynamic base URLs, function-valued `trustedOrigins`), subscription credentials and origins, error shapes, logging (one ERROR entry per request and distinct reader configuration error across GraphQL list items), the exact coverage report of the transport's claims, metadata canaries, `globalScope: false` and its boot summary line, readings with and without the scope interceptor, public handlers in unclaimed contexts, inherited handlers, dynamic base URLs, stale GraphQL contexts, mixed-kind session reads, nested and federation readings, lazy scope construction and fail-closed extraction |
990
+ | `principalSourceConformance` | `PrincipalSource` | Rejection without throwing, storage outages (resolved directly and through a guarded HTTP route), delivery of every own-credential `Set-Cookie` exactly once (to the cookie sink and to an HTTP client, without other headers of those calls), refresh suppression, clean absence, principal shape, declared credential headers, `sessionBacked` and `delegates` declarations, dynamic base URLs (direct and behind a trusted proxy), credential redaction in logs and raw causes; for API-key sources the verification results, outage and write-outage probes and organization-owned keys; for session-backed sources short-circuited session reads and the cookie bridge (third-party sign-up, foreign credentials); for sources of the `jwt` plugin the issuer and audience claims and key-set outages |
991
+ | `policyConformance` | `AuthorizationPolicy` | Deny values, storage outages with the cookie cache off and warm, APIError mapping and re-classification, sessions lost before the policy's call, delegation scope, unnamed-kind gating, per-invocation decisions with shared I/O, request-scoped class policies, class policies' `requires` fields, plugin prerequisites, and the admin, organization and API-key rows below; requirements name policy objects (construct a DI policy with its dependencies) |
992
992
 
993
- The principal-source kit passes each credential factory the instance the case runs against: `credentials.valid(auth)` receives `auth`, or for `S-dynamic-base-url` a variant with a dynamic `baseURL` (allowed hosts `localhost:3000` and `public.example`, no fallback) that `variant(overrides)` builds. The default variant is `createConformanceAuth()` with the plugins of `auth`; a call that creates a credential on the variant passes a `host` header. `credentials.apiKey(auth, fields)` creates the keys of the `S-apikey-*` cases (default: `auth.api.createApiKey` for a new user), `credentials.organizationKey(auth)` enables `S-apikey-org-key`, and `http: { platform, createHttpAdapter }` enables the `S-bridge-*` routes. Each case boots its own module, so register a source that keeps state across requests, such as the API-key outage probe or a JWT key cache, as a `defineExtension()` factory.
993
+ The principal-source kit passes each credential factory the instance the case runs against: `credentials.valid(auth)` receives `auth`, or for `S-dynamic-base-url` a variant with a dynamic `baseURL` (allowed hosts `localhost:3000` and `public.example`, no fallback) that `variant(overrides)` builds. The default variant is `createConformanceAuth()` with the plugins of `auth`; a call that creates a credential on the variant passes a `host` header. `credentials.apiKey(auth, fields)` creates the keys of the `S-apikey-*` cases (default: `auth.api.createApiKey` for a new user), `credentials.organizationKey(auth)` enables `S-apikey-org-key`, and `http: { platform, createHttpAdapter }` enables the guarded route of the HTTP-route rows of `S-cookie-forwarded` and `S-infra-throws` and the `S-bridge-*` routes. Each case boots its own module, so register a source that keeps state across requests, such as the API-key outage probe or a JWT key cache, as a `defineExtension()` factory.
994
994
 
995
- 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 (`advanced.disableOriginCheck: false` and `advanced.disableCSRFCheck: false`), 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, with the organization plugin and the organizations its `org` fixture names, 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`, `forwardDirectCalls`, `fieldResolverEnhancers`, `fieldResolverCoverage`, `federation` and `graphqlContext` settings of each boot. Apply every fixture decorator, including the kit's `SetMetadata()` marker, which maps the transport's claims to fixtures, and the class decorators of `inherited.subclasses` and `graph.classDecorators`. On a connection-shaped browser leg, the kit's cookie credential carries the instance's base URL, `http://localhost:3000`, as `Origin`, as a browser page of that origin does; the `T-ws-origin-*` cases pass their own `Origin`, `Host` and forwarding headers, which the harness sends in the handshake.
995
+ 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 (`advanced.disableOriginCheck: false` and `advanced.disableCSRFCheck: false`), whatever `options` says. Its second argument, `ConformanceAuthSettings`, sets those two flags explicitly: `createConformanceAuth(options, { disableOriginCheck: true, disableCSRFCheck: false })` builds the instance of the `T-csrf-http-unsafe` row in which Better Auth skips origin checks on its own routes while application routes stay checked. 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, with the organization plugin and the organizations its `org` fixture names, 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`, `forwardDirectCalls`, `logSummary`, `fieldResolverEnhancers` (including `'filters'`), `fieldResolverCoverage`, `federation` and `graphqlContext` settings of each boot. GraphQL harnesses serve `graph.roots.items`, when given, as a list of `FixtureNode`, and the `organizationReader` and `serviceSession` fields as `String` fields. Apply every fixture decorator, including the kit's `SetMetadata()` marker, which maps the transport's claims to fixtures, and the class decorators of `inherited.subclasses` and `graph.classDecorators`. On a connection-shaped browser leg, the kit's cookie credential carries the instance's base URL, `http://localhost:3000`, as `Origin`, as a browser page of that origin does; the `T-ws-origin-*` cases pass their own `Origin`, `Host` and forwarding headers, which the harness sends in the handshake.
996
996
 
997
- The policy kit judges principals through the real evaluator, and cases that need route planning, acceptance or principal resolution send in-process requests through the real `BetterAuthGuard`. Pass the sources of the requirement's other principal kinds in `sources` (for example `apiKeyPrincipal()`). Unit-specific cases run when the requirement contains the built-in admin policy (`Z-admin-*`), an organization policy (`Z-org-ref-types` and the organization row of `Z-apikey-quota-per-request`) or the API-key permission policy (its `Z-apikey-quota-per-request` row), and skip with the reason otherwise. They use the instance's configuration where it matters: `session.cookieCache.enabled` for the warm-cache rows and `apiKey({ enableSessionForAPIKeys: true })` for the API-key session and quota rows. The kit builds the instances that need another configuration (`customSession` role shapes, `adminUserIds`, a dynamic `baseURL`) with `createConformanceAuth()`.
997
+ The policy kit judges principals through the real evaluator, and cases that need route planning, acceptance or principal resolution send in-process requests through the real `BetterAuthGuard`. Pass the sources of the requirement's other principal kinds in `sources` (for example `apiKeyPrincipal()`). Unit-specific cases run when the requirement contains the built-in admin policy (`Z-admin-*`), an organization policy (`Z-org-ref-types` and the organization row of `Z-apikey-quota-per-request`) or the API-key permission policy (its `Z-apikey-quota-per-request` row), and skip with the reason otherwise. They use the instance's configuration where it matters: `session.cookieCache.enabled` for the warm-cache rows and `apiKey({ enableSessionForAPIKeys: true })` for the API-key session and quota rows. The kit builds the instances that need another configuration (`customSession` role shapes, `adminUserIds`, a dynamic `baseURL`, an instance without `apiKey()`) with `variant(overrides)`, which defaults to `createConformanceAuth(overrides)`. A storage job passes a variant that builds the same instance on its own database: add what `createConformanceAuth()` adds (`testUtils()`, `bearer()`, `conformanceProbePlugin()`, `nestjs()` last, `session.updateAge: 0` and `advanced.disableOriginCheck: false`), and migrate the schema before returning it.
998
998
 
999
- This repository runs the platform kit against Express and Fastify, including the Fastify HTTP/2 adapter for the HTTP/2 rows; the transport kit against the built-in HTTP transport, an in-process reference transport, Socket.IO and `ws` (each with and without a principal TTL), the RPC transport over TCP (standalone and hybrid), gRPC, NATS, RabbitMQ, MQTT, Redis and Kafka, and the Apollo (Express and Fastify) and Mercurius transports over HTTP and over graphql-ws (with and without a subscription principal TTL; Mercurius also without `mercuriusSubscriptionContext()`), with federation 2 subgraphs and a federation 1 run of `T-reference-resolver`; the principal-source kit against the session source (its `S-bridge-*` rows on Express and Fastify), the API-key source with user-owned and organization-owned keys, and the design's JWT source sketch with derived and explicit claims; and the policy kit against the admin, organization (also with `customSession`), API-key and fresh-session policies. gRPC skips `T-error-shape`, because it delivers only a status and a message. The kit reads each call's browser leg while its invocation runs, because the GraphQL transports reject a completed request. Mutation tests confirm that each of these defects fails the intended case: a platform merging `Set-Cookie`, handing Better Auth no client IP, ignoring its proxy trust, dropping the request host or stripping forwarding headers, a kernel that unbinds hooks on `close()`, reports taking over a closed binding or keeps a microservice's binding open, 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 WebSocket transport that enforces its handshake like a safe read, exempts handshakes that carry a token, builds its leg URL from the bare handshake path or from forwarded headers, or answers internal errors with their cause, a GraphQL transport whose aliases share one invocation, whose lineage gives every field of an operation one position, whose field resolvers do not inherit their root's access, or that serves reference resolvers without field guards, a GraphQL harness that omits `invokeGraph`, `invokeEntities` or `invokeConnection`, a transport that claims every context type, runs no metadata canary, claims classes without handlers or drops the `Host` header without declaring hostless calls, a planner that caches plans by handler function, ignores `@SkipOriginCheck()` or skips the origin check of safe operations, an HTTP transport whose invocation is not the handler's request (Fastify), a WebSocket transport whose messages on one socket share their invocation, a GraphQL transport that treats a completed request as live, ignores `connectionParams` credentials, treats socket operations as safe reads, exempts `connectionParams` tokens, serves inherited forwarding fields without field guards, omits `W_FIELD_RESOLVER_INHERITS` or `I_CLASS_METADATA_OPERATIONS_ONLY`, a planner that applies class-level acceptance to field resolvers or records a reading on a form-mode nested public field, a source throwing its denial, a source dropping its refresh cookie, a source turning a storage outage into a 401, API-key sources that report every failure as an invalid key, verify once per call, run without the outage probe or latency signal, probe on every invalid key, touch key rows, or map organization keys to users, a session source that trusts hook answers on authoritative routes, a source that wraps errors without the request's credentials, JWT sources that expect the basePath URL as issuer or deny a key-set outage, sources that drop the host or forwarded headers, a route planner that forwards every handler's direct calls, a `forwardForeignCookies()` without a declaration check or without forwarding, a policy widening delegated principals, a policy turning a lost session or a storage outage into a denial, an organization policy coercing non-string inputs or repeating its Better Auth call, admin policies that admit API keys by default, lack fresh identity or hostless calls, ignore a key owner's ban, judge the session's role or trust the stored user row, and boot validation or route planning that ignore request-scoped dependencies or a class policy's `requires` field.
999
+ `deliveries` also sends the transport-specific rows through real transports. A `PolicyDelivery` has these members:
1000
+
1001
+ - `name` names the delivery in case titles.
1002
+ - `createApp(handlers, auth, { principals, logger })` boots an app with `globalGuard` that exposes each kit handler (a `FixtureHandler`, as in `transportConformance`) under its name: a gateway message with explicit coverage, a message pattern or a GraphQL query field. The kit's only named input, `orgId`, keeps its JSON type; a GraphQL harness declares it as a JSON scalar argument.
1003
+ - `invoke(app, handler, headers, input)` sends one logical request.
1004
+ - Connection transports add `connect(app, headers)`, which opens one connection whose `invoke()` sends one message, or one subscription operation for GraphQL, after the previous one answered. They also add `connectionPrincipalTtlMs`, the transport's `principalTtlMs` or `subscriptionPrincipalTtlMs`.
1005
+
1006
+ The kit sends the probe plugin's trusted `Origin` with every delivered request. For each delivery it adds these cases, titled `<name>: …`:
1007
+
1008
+ - `Z-admin-rejects-api-key-session`
1009
+ - `Z-org-ref-types`, with junk `orgId` values in the transport's payload
1010
+ - `Z-apikey-quota-per-request`, the API-key session setup
1011
+ - `Z-admin-banned` on one connection. It runs when `connect` and a positive `connectionPrincipalTtlMs` are present, and first checks that a default-freshness handler reuses the connection's principal after sign-out.
1012
+
1013
+ This repository runs the platform kit against Express and Fastify, including the Fastify HTTP/2 adapter for the HTTP/2 rows; the transport kit against the built-in HTTP transport, an in-process reference transport, Socket.IO and `ws` (each with and without a principal TTL), the RPC transport over TCP (standalone and hybrid), gRPC, NATS, RabbitMQ, MQTT, Redis and Kafka, and the Apollo (Express and Fastify) and Mercurius transports over HTTP and over graphql-ws (with and without a subscription principal TTL; Mercurius also without `mercuriusSubscriptionContext()`), with federation 2 subgraphs and a federation 1 run of `T-reference-resolver`; the principal-source kit against the session source (its HTTP-route and `S-bridge-*` rows on Express and Fastify), the API-key source with user-owned and organization-owned keys, and the design's JWT source sketch with derived and explicit claims; and the policy kit against the admin, organization (also with `customSession`), API-key and fresh-session policies. The policy kit's delivery rows run over Socket.IO and `ws` with a 300 s principal TTL, over RPC over TCP (standalone and hybrid), and over the Apollo (Express and Fastify) and Mercurius transports over HTTP and over graphql-ws with a 300 s subscription principal TTL. `Z-admin-null-role` also runs on PGlite with Better Auth's Kysely adapter and migrations. gRPC skips `T-error-shape`, because it delivers only a status and a message. The kit reads each call's browser leg while its invocation runs, because the GraphQL transports reject a completed request. Mutation tests confirm that each of these defects fails the intended case: a platform merging `Set-Cookie`, handing Better Auth no client IP, ignoring its proxy trust, dropping the request host or stripping forwarding headers, a kernel that unbinds hooks on `close()`, reports taking over a closed binding or keeps a microservice's binding open, 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 WebSocket transport that enforces its handshake like a safe read, exempts handshakes that carry a token, builds its leg URL from the bare handshake path or from forwarded headers, or answers internal errors with their cause, a GraphQL transport whose aliases share one invocation, whose lineage gives every field of an operation one position, whose field resolvers do not inherit their root's access, or that serves reference resolvers without field guards, a GraphQL harness that omits `invokeGraph`, `invokeEntities` or `invokeConnection`, a transport that claims every context type, runs no metadata canary, claims classes without handlers or drops the `Host` header without declaring hostless calls, a planner that caches plans by handler function, ignores `@SkipOriginCheck()` or skips the origin check of safe operations, a kernel that treats Better Auth's boolean origin skip as its own, a harness that boots without the summary `T-coverage-claims` asks for, an HTTP transport whose invocation is not the handler's request (Fastify), a WebSocket transport whose messages on one socket share their invocation, a GraphQL transport that treats a completed request as live, ignores `connectionParams` credentials, treats socket operations as safe reads, exempts `connectionParams` tokens, serves inherited forwarding fields without field guards, omits `W_FIELD_RESOLVER_INHERITS` or `I_CLASS_METADATA_OPERATIONS_ONLY`, a planner that applies class-level acceptance to field resolvers or records a reading on a form-mode nested public field, a source throwing its denial, a source dropping its refresh cookie, a source turning a storage outage into a 401, API-key sources that report every failure as an invalid key, verify once per call, run without the outage probe or latency signal, probe on every invalid key, touch key rows, or map organization keys to users, a session source that trusts hook answers on authoritative routes, a source that wraps errors without the request's credentials, JWT sources that expect the basePath URL as issuer or deny a key-set outage, sources that drop the host or forwarded headers, a route planner that forwards every handler's direct calls, a `forwardForeignCookies()` without a declaration check or without forwarding, a policy widening delegated principals, a policy turning a lost session or a storage outage into a denial, an organization policy coercing non-string inputs (also over `ws`) or repeating its Better Auth call, admin policies that admit API keys by default, lack fresh identity (also over RPC) or hostless calls, ignore a key owner's ban, judge the session's role or trust the stored user row (also on PGlite), a request scope that reuses a connection's principal for authoritative handlers (Socket.IO, graphql-ws), a WebSocket transport that declares a principal TTL it does not apply, a graphql-ws delivery that opens a new socket for each operation, and boot validation or route planning that ignore request-scoped dependencies or a class policy's `requires` field.
1000
1014
 
1001
1015
  ## Develop in this monorepo
1002
1016