authhero 9.9.1 → 9.10.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 (53) hide show
  1. package/dist/assets/u/widget/index.esm.js +1 -1
  2. package/dist/authhero.cjs +146 -146
  3. package/dist/authhero.d.ts +313 -140
  4. package/dist/authhero.mjs +14974 -14666
  5. package/dist/tsconfig.types.tsbuildinfo +1 -1
  6. package/dist/types/authentication-flows/authorization-code.d.ts +2 -1
  7. package/dist/types/authentication-flows/client-credentials.d.ts +2 -1
  8. package/dist/types/authentication-flows/passwordless.d.ts +6 -5
  9. package/dist/types/authentication-flows/refresh-token.d.ts +2 -1
  10. package/dist/types/authentication-flows/token-exchange.d.ts +2 -1
  11. package/dist/types/helpers/client-assertion-replay.d.ts +21 -0
  12. package/dist/types/helpers/client-assertion.d.ts +24 -2
  13. package/dist/types/helpers/default-destinations.d.ts +7 -1
  14. package/dist/types/helpers/outbox-destinations/index.d.ts +1 -0
  15. package/dist/types/helpers/outbox-destinations/pipeline.d.ts +63 -0
  16. package/dist/types/helpers/outbox-relay.d.ts +3 -0
  17. package/dist/types/helpers/reserved-claims.d.ts +64 -0
  18. package/dist/types/helpers/run-outbox-relay.d.ts +8 -0
  19. package/dist/types/index.d.ts +150 -137
  20. package/dist/types/routes/auth-api/index.d.ts +44 -44
  21. package/dist/types/routes/auth-api/passwordless.d.ts +14 -14
  22. package/dist/types/routes/auth-api/register/index.d.ts +2 -2
  23. package/dist/types/routes/auth-api/token.d.ts +24 -24
  24. package/dist/types/routes/management-api/action-triggers.d.ts +0 -2
  25. package/dist/types/routes/management-api/actions.d.ts +0 -7
  26. package/dist/types/routes/management-api/authentication-methods.d.ts +1 -1
  27. package/dist/types/routes/management-api/branding.d.ts +9 -9
  28. package/dist/types/routes/management-api/clients.d.ts +8 -8
  29. package/dist/types/routes/management-api/connections.d.ts +1 -1
  30. package/dist/types/routes/management-api/email-templates.d.ts +18 -18
  31. package/dist/types/routes/management-api/failed-events.d.ts +21 -1
  32. package/dist/types/routes/management-api/guardian.d.ts +5 -5
  33. package/dist/types/routes/management-api/helpers.d.ts +1 -1
  34. package/dist/types/routes/management-api/index.d.ts +122 -111
  35. package/dist/types/routes/management-api/keys.d.ts +16 -16
  36. package/dist/types/routes/management-api/logs.d.ts +4 -4
  37. package/dist/types/routes/management-api/migration-sources.d.ts +6 -6
  38. package/dist/types/routes/management-api/organizations.d.ts +3 -3
  39. package/dist/types/routes/management-api/prompts.d.ts +4 -4
  40. package/dist/types/routes/management-api/roles.d.ts +1 -1
  41. package/dist/types/routes/management-api/tenants.d.ts +11 -11
  42. package/dist/types/routes/management-api/users.d.ts +24 -24
  43. package/dist/types/routes/universal-login/common.d.ts +2 -2
  44. package/dist/types/routes/universal-login/flow-api.d.ts +8 -8
  45. package/dist/types/routes/universal-login/identifier.d.ts +2 -2
  46. package/dist/types/routes/universal-login/index.d.ts +2 -2
  47. package/dist/types/routes/universal-login/u2-index.d.ts +5 -5
  48. package/dist/types/routes/universal-login/u2-routes.d.ts +5 -5
  49. package/dist/types/types/AuthHeroConfig.d.ts +27 -0
  50. package/dist/types/types/Bindings.d.ts +12 -0
  51. package/dist/types/types/OutboxMetrics.d.ts +47 -0
  52. package/dist/types/types/index.d.ts +1 -0
  53. package/package.json +6 -6
@@ -3,6 +3,7 @@ import { z } from "@hono/zod-openapi";
3
3
  import { Bindings, Variables } from "../types";
4
4
  import { TokenResponse } from "@authhero/adapter-interfaces";
5
5
  import { GrantFlowUserResult } from "src/types/GrantFlowResult";
6
+ import { EnrichedClient } from "../helpers/client";
6
7
  export declare const authorizationCodeGrantParamsSchema: z.ZodObject<{
7
8
  grant_type: z.ZodLiteral<"authorization_code">;
8
9
  client_id: z.ZodString;
@@ -16,7 +17,7 @@ export type AuthorizationCodeGrantTypeParams = z.infer<typeof authorizationCodeG
16
17
  export declare function authorizationCodeGrantUser(ctx: Context<{
17
18
  Bindings: Bindings;
18
19
  Variables: Variables;
19
- }>, params: AuthorizationCodeGrantTypeParams): Promise<GrantFlowUserResult>;
20
+ }>, params: AuthorizationCodeGrantTypeParams, preloadedClient?: EnrichedClient): Promise<GrantFlowUserResult>;
20
21
  export declare function authorizationCodeGrant(ctx: Context<{
21
22
  Bindings: Bindings;
22
23
  Variables: Variables;
@@ -2,6 +2,7 @@ import { Context } from "hono";
2
2
  import { z } from "@hono/zod-openapi";
3
3
  import { Bindings, Variables } from "../types";
4
4
  import { GrantFlowResult } from "../types/GrantFlowResult";
5
+ import { EnrichedClient } from "../helpers/client";
5
6
  export declare const clientCredentialGrantParamsSchema: z.ZodObject<{
6
7
  grant_type: z.ZodLiteral<"client_credentials">;
7
8
  scope: z.ZodOptional<z.ZodString>;
@@ -13,4 +14,4 @@ export declare const clientCredentialGrantParamsSchema: z.ZodObject<{
13
14
  export declare function clientCredentialsGrant(ctx: Context<{
14
15
  Bindings: Bindings;
15
16
  Variables: Variables;
16
- }>, params: z.infer<typeof clientCredentialGrantParamsSchema>): Promise<GrantFlowResult>;
17
+ }>, params: z.infer<typeof clientCredentialGrantParamsSchema>, preloadedClient?: EnrichedClient): Promise<GrantFlowResult>;
@@ -1,6 +1,7 @@
1
1
  import { Context } from "hono";
2
2
  import { z } from "@hono/zod-openapi";
3
3
  import { Bindings, Variables } from "../types";
4
+ import { EnrichedClient } from "../helpers/client";
4
5
  import { GrantFlowUserResult } from "../types/GrantFlowResult";
5
6
  export declare const passwordlessGrantParamsSchema: z.ZodObject<{
6
7
  client_id: z.ZodString;
@@ -45,7 +46,7 @@ export declare const passwordlessGrantParamsSchema: z.ZodObject<{
45
46
  export declare function passwordlessGrantUser(ctx: Context<{
46
47
  Bindings: Bindings;
47
48
  Variables: Variables;
48
- }>, { client_id, username, otp, scope, audience, authParams, enforceIpCheck, }: z.input<typeof passwordlessGrantParamsSchema>): Promise<{
49
+ }>, { client_id, username, otp, scope, audience, authParams, enforceIpCheck, }: z.input<typeof passwordlessGrantParamsSchema>, preloadedClient?: EnrichedClient): Promise<{
49
50
  user: {
50
51
  connection: string;
51
52
  email_verified: boolean;
@@ -474,7 +475,7 @@ export declare function passwordlessGrantUser(ctx: Context<{
474
475
  custom_login_page_preview?: string | undefined;
475
476
  form_template?: string | undefined;
476
477
  addons?: Record<string, any> | undefined;
477
- token_endpoint_auth_method?: "none" | "client_secret_post" | "client_secret_basic" | "client_secret_jwt" | "private_key_jwt" | undefined;
478
+ token_endpoint_auth_method?: "client_secret_post" | "client_secret_basic" | "none" | "client_secret_jwt" | "private_key_jwt" | undefined;
478
479
  client_metadata?: Record<string, string> | undefined;
479
480
  hide_sign_up_disabled_error?: boolean | undefined;
480
481
  mobile?: Record<string, any> | undefined;
@@ -557,8 +558,8 @@ export declare function passwordlessGrantUser(ctx: Context<{
557
558
  } | undefined;
558
559
  authenticated_at?: string | undefined;
559
560
  };
560
- connectionType: "username" | "email" | "sms";
561
- authConnection: "username" | "email" | "sms";
561
+ connectionType: "email" | "username" | "sms";
562
+ authConnection: "email" | "username" | "sms";
562
563
  session_id: string | undefined;
563
564
  authParams: {
564
565
  audience?: string | undefined;
@@ -612,7 +613,7 @@ export declare function passwordlessGrantUser(ctx: Context<{
612
613
  export declare function passwordlessOtpGrant(ctx: Context<{
613
614
  Bindings: Bindings;
614
615
  Variables: Variables;
615
- }>, params: z.input<typeof passwordlessGrantParamsSchema>): Promise<GrantFlowUserResult>;
616
+ }>, params: z.input<typeof passwordlessGrantParamsSchema>, preloadedClient?: EnrichedClient): Promise<GrantFlowUserResult>;
616
617
  export declare function passwordlessGrant(ctx: Context<{
617
618
  Bindings: Bindings;
618
619
  Variables: Variables;
@@ -1,6 +1,7 @@
1
1
  import { Context } from "hono";
2
2
  import { Bindings, Variables, GrantFlowUserResult } from "../types";
3
3
  import { z } from "@hono/zod-openapi";
4
+ import { EnrichedClient } from "../helpers/client";
4
5
  export declare const refreshTokenParamsSchema: z.ZodObject<{
5
6
  grant_type: z.ZodLiteral<"refresh_token">;
6
7
  client_id: z.ZodString;
@@ -12,4 +13,4 @@ export declare const refreshTokenParamsSchema: z.ZodObject<{
12
13
  export declare function refreshTokenGrant(ctx: Context<{
13
14
  Bindings: Bindings;
14
15
  Variables: Variables;
15
- }>, params: z.infer<typeof refreshTokenParamsSchema>): Promise<GrantFlowUserResult>;
16
+ }>, params: z.infer<typeof refreshTokenParamsSchema>, preloadedClient?: EnrichedClient): Promise<GrantFlowUserResult>;
@@ -1,6 +1,7 @@
1
1
  import { Context } from "hono";
2
2
  import { z } from "@hono/zod-openapi";
3
3
  import { Bindings, Variables, GrantFlowUserResult } from "../types";
4
+ import { EnrichedClient } from "../helpers/client";
4
5
  export declare const TOKEN_EXCHANGE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange";
5
6
  export declare const tokenExchangeParamsSchema: z.ZodObject<{
6
7
  grant_type: z.ZodLiteral<"urn:ietf:params:oauth:grant-type:token-exchange">;
@@ -16,4 +17,4 @@ export type TokenExchangeParams = z.infer<typeof tokenExchangeParamsSchema>;
16
17
  export declare function tokenExchangeGrant(ctx: Context<{
17
18
  Bindings: Bindings;
18
19
  Variables: Variables;
19
- }>, params: TokenExchangeParams): Promise<GrantFlowUserResult>;
20
+ }>, params: TokenExchangeParams, preloadedClient?: EnrichedClient): Promise<GrantFlowUserResult>;
@@ -0,0 +1,21 @@
1
+ import { Context } from "hono";
2
+ import { Bindings, Variables } from "../types";
3
+ export interface ConsumeClientAssertionJtiParams {
4
+ clientId: string;
5
+ /** The assertion's `jti`. When absent there is nothing to spend. */
6
+ jti?: string;
7
+ /** The assertion's `exp`, in seconds — when the marker becomes collectable. */
8
+ exp: number;
9
+ }
10
+ /**
11
+ * Spend a client assertion's `jti`.
12
+ *
13
+ * @returns false when this assertion has already been presented (the caller
14
+ * must reject it as `invalid_client`), true otherwise. An assertion carrying
15
+ * no `jti` cannot be tracked, so it returns true — its replay window is
16
+ * bounded only by the assertion lifetime cap.
17
+ */
18
+ export declare function consumeClientAssertionJti(ctx: Context<{
19
+ Bindings: Bindings;
20
+ Variables: Variables;
21
+ }>, tenantId: string, params: ConsumeClientAssertionJtiParams): Promise<boolean>;
@@ -1,5 +1,12 @@
1
1
  import { LoadClientKeysOptions, ClientWithKeys } from "./client-keys";
2
2
  declare const ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
3
+ /**
4
+ * Default upper bound on a client assertion's lifetime. RFC 7523 gives no
5
+ * limit, so without one a client can mint an assertion valid for a year and a
6
+ * captured assertion stays usable for that whole window. 300s matches the
7
+ * usual guidance for a single-use token presented directly to the endpoint.
8
+ */
9
+ declare const DEFAULT_MAX_LIFETIME_SECONDS = 300;
3
10
  export type ClientAssertionMethod = "private_key_jwt" | "client_secret_jwt";
4
11
  export declare class ClientAssertionError extends Error {
5
12
  code: "invalid_client" | "invalid_request" | "unsupported_alg" | "missing_keys";
@@ -18,6 +25,14 @@ export interface VerifyClientAssertionOptions extends LoadClientKeysOptions {
18
25
  acceptedAudiences: string[];
19
26
  /** Clock-skew leeway in seconds. Defaults to 30. */
20
27
  leewaySeconds?: number;
28
+ /**
29
+ * Maximum accepted assertion lifetime in seconds. Rejects an assertion whose
30
+ * `exp - iat` exceeds this, and caps the absolute `exp` at `now + max` so an
31
+ * assertion that omits `iat` cannot sidestep the bound. Defaults to
32
+ * DEFAULT_MAX_LIFETIME_SECONDS (300) — the window a captured assertion stays
33
+ * replayable in is bounded by this, so keep it short.
34
+ */
35
+ maxLifetimeSeconds?: number;
21
36
  /** Override Date.now() for tests. */
22
37
  now?: () => number;
23
38
  }
@@ -26,8 +41,15 @@ export interface VerifiedClientAssertion {
26
41
  clientId: string;
27
42
  /** Which authentication method was actually used. */
28
43
  method: ClientAssertionMethod;
29
- /** Optional jti claim — useful if callers want to enforce replay protection. */
44
+ /**
45
+ * The `jti` claim, when present. `consumeClientAssertionJti`
46
+ * (helpers/client-assertion-replay.ts) spends it so an assertion cannot be
47
+ * presented twice; the token endpoint calls that after this verifier
48
+ * returns.
49
+ */
30
50
  jti?: string;
51
+ /** The `exp` claim, in seconds. Bounds how long the `jti` must be remembered. */
52
+ exp: number;
31
53
  /** The full verified payload, in case callers need other claims. */
32
54
  payload: Record<string, unknown>;
33
55
  }
@@ -46,4 +68,4 @@ export interface VerifiedClientAssertion {
46
68
  * any of the iss/sub/aud/exp checks.
47
69
  */
48
70
  export declare function verifyClientAssertion(assertion: string, client: ClientAssertionClient, opts: VerifyClientAssertionOptions): Promise<VerifiedClientAssertion>;
49
- export { ASSERTION_TYPE as CLIENT_ASSERTION_TYPE };
71
+ export { ASSERTION_TYPE as CLIENT_ASSERTION_TYPE, DEFAULT_MAX_LIFETIME_SECONDS as CLIENT_ASSERTION_DEFAULT_MAX_LIFETIME_SECONDS, };
@@ -1,7 +1,7 @@
1
1
  import { CodeExecutor, DataAdapters } from "@authhero/adapter-interfaces";
2
2
  import { EventDestination } from "./outbox-relay";
3
3
  import { type GetServiceToken } from "./outbox-destinations/webhooks";
4
- import type { WebhookInvoker } from "../types/AuthHeroConfig";
4
+ import type { OutboxPipelineConfig, WebhookInvoker } from "../types/AuthHeroConfig";
5
5
  export interface CreateDefaultDestinationsConfig {
6
6
  /**
7
7
  * Data adapter — the `logs`, `hooks`, `users`, and `logStreams` adapters are
@@ -47,6 +47,12 @@ export interface CreateDefaultDestinationsConfig {
47
47
  * failed per-request delivery would be silently skipped on retry.
48
48
  */
49
49
  codeExecutor?: CodeExecutor;
50
+ /**
51
+ * Same shape as `init({ outbox: { pipeline } })`. When set, cron-drained
52
+ * events are also archived to the Cloudflare Pipelines stream, matching the
53
+ * per-request destination list. Omit to leave the archive out entirely.
54
+ */
55
+ pipeline?: OutboxPipelineConfig;
50
56
  }
51
57
  /**
52
58
  * Build the same array of outbox destinations that authhero's per-request
@@ -1,2 +1,3 @@
1
1
  export { LogsDestination } from "./logs";
2
2
  export { LogStreamDestination } from "./log-streams";
3
+ export { PipelineDestination } from "./pipeline";
@@ -0,0 +1,63 @@
1
+ import { AuditEvent, AuditCategory } from "@authhero/adapter-interfaces";
2
+ import { EventDestination } from "../outbox-relay";
3
+ /**
4
+ * One row of the archive table. The promoted columns are the query and
5
+ * erasure keys (`actor_id` / `target_id`); `event` carries the untouched
6
+ * `AuditEvent` so nothing is lost and the promoted set can grow later
7
+ * without a backfill.
8
+ *
9
+ * `actor_id` is emitted as `null` rather than omitted when the actor is
10
+ * anonymous, so every record has the same key set — Pipelines stream
11
+ * schemas are fixed once created.
12
+ */
13
+ export interface PipelineRecord {
14
+ id: string;
15
+ timestamp: string;
16
+ tenant_id: string;
17
+ event_type: string;
18
+ log_type: string;
19
+ category: AuditCategory;
20
+ actor_id: string | null;
21
+ target_type: string;
22
+ target_id: string;
23
+ event: AuditEvent;
24
+ }
25
+ export interface PipelineDestinationOptions {
26
+ /** Stream HTTP ingest endpoint, e.g. `https://<stream-id>.ingest.cloudflare.com`. */
27
+ endpoint: string;
28
+ /** Stream ingest token, sent as `Authorization: Bearer`. */
29
+ token: string;
30
+ /** Per-request timeout (default: 10s). */
31
+ timeoutMs?: number;
32
+ /** Override for tests. */
33
+ fetchImpl?: typeof fetch;
34
+ }
35
+ /**
36
+ * Archives audit events to a Cloudflare Pipelines stream, which lands them in
37
+ * R2 as an Iceberg table. See `apps/docs/architecture/audit-archive.md`.
38
+ *
39
+ * HTTP ingest is used rather than the Worker binding so the destination works
40
+ * in every deployment (Node included) and stays symmetric with the
41
+ * log-streams destination.
42
+ *
43
+ * Duplicates are expected and by design: the relay retries per event, not per
44
+ * destination, so a failure in a later destination re-delivers this one, and
45
+ * the Iceberg sink is append-only. Consumers dedup on `id` at query time.
46
+ */
47
+ export declare class PipelineDestination implements EventDestination {
48
+ name: string;
49
+ private endpoint;
50
+ private token;
51
+ private timeoutMs;
52
+ private fetchImpl;
53
+ constructor(options: PipelineDestinationOptions);
54
+ /**
55
+ * Archives the audit trail, not the delivery plumbing: `hook.*` and
56
+ * `controlplane.sync.*` are instructions to other destinations rather than
57
+ * records of something a tenant did. Same filter as the log-streams
58
+ * destination.
59
+ */
60
+ accepts(event: AuditEvent): boolean;
61
+ transform(event: AuditEvent): PipelineRecord;
62
+ deliver(records: PipelineRecord[]): Promise<void>;
63
+ }
@@ -1,4 +1,5 @@
1
1
  import { OutboxAdapter, AuditEvent } from "@authhero/adapter-interfaces";
2
+ import type { OutboxMetricsSink } from "../types/OutboxMetrics";
2
3
  /**
3
4
  * Interface for outbox event destinations.
4
5
  * Each destination transforms audit events into its own format and delivers them.
@@ -21,6 +22,7 @@ export interface EventDestination {
21
22
  */
22
23
  export declare function processOutboxEvents(outbox: OutboxAdapter, ids: string[], destinations: EventDestination[], options?: {
23
24
  maxRetries?: number;
25
+ metrics?: OutboxMetricsSink;
24
26
  }): Promise<void>;
25
27
  /**
26
28
  * Drain unprocessed events from the outbox and deliver to all destinations.
@@ -31,4 +33,5 @@ export declare function drainOutbox(outbox: OutboxAdapter, destinations: EventDe
31
33
  batchSize?: number;
32
34
  maxRetries?: number;
33
35
  retentionDays?: number;
36
+ metrics?: OutboxMetricsSink;
34
37
  }): Promise<void>;
@@ -0,0 +1,64 @@
1
+ import { Context } from "hono";
2
+ import { Bindings, Variables } from "../types";
3
+ /** RFC 9068 §2.2 + AuthHero-owned access-token claims. */
4
+ export declare const ACCESS_TOKEN_RESERVED_CLAIMS: readonly ["iss", "sub", "aud", "exp", "nbf", "iat", "jti", "client_id", "azp", "scope", "auth_time", "acr", "amr", "act", "sid", "permissions", "tenant_id", "org_id", "org_name", "requested_userinfo_claims", "gty"];
5
+ /** OIDC Core ID-token claims: the access-token set plus the ID-token-only ones. */
6
+ export declare const ID_TOKEN_RESERVED_CLAIMS: readonly ["iss", "sub", "aud", "exp", "nbf", "iat", "jti", "client_id", "azp", "scope", "auth_time", "acr", "amr", "act", "sid", "permissions", "tenant_id", "org_id", "org_name", "requested_userinfo_claims", "gty", "nonce", "at_hash", "c_hash", "s_hash"];
7
+ /**
8
+ * /userinfo response. The identity set only — the response body is otherwise
9
+ * made up of user profile claims, which hooks are expected to extend.
10
+ */
11
+ export declare const USERINFO_RESERVED_CLAIMS: readonly ["iss", "sub", "aud", "exp", "nbf", "iat", "jti"];
12
+ /**
13
+ * Internal `auth-service` mints. Same set as an access token except `azp`:
14
+ * trusted internal hook code overrides it to attribute the call to a
15
+ * vendor/tenant for downstream APIs while `sub` stays `auth-service`.
16
+ * Client-bound mints keep `azp` locked (see below).
17
+ */
18
+ export declare const SERVICE_TOKEN_RESERVED_CLAIMS: ("client_id" | "scope" | "sid" | "tenant_id" | "org_id" | "org_name" | "sub" | "permissions" | "iat" | "exp" | "iss" | "aud" | "auth_time" | "acr" | "amr" | "nbf" | "jti" | "act" | "requested_userinfo_claims" | "gty")[];
19
+ /** Client-bound mints: `azp` must stay the registered client id. */
20
+ export declare const CLIENT_SERVICE_TOKEN_RESERVED_CLAIMS: ("client_id" | "scope" | "sid" | "tenant_id" | "org_id" | "org_name" | "sub" | "permissions" | "iat" | "exp" | "iss" | "aud" | "auth_time" | "acr" | "amr" | "azp" | "nbf" | "jti" | "act" | "requested_userinfo_claims" | "gty")[];
21
+ export type AccessTokenReservedClaim = (typeof ACCESS_TOKEN_RESERVED_CLAIMS)[number];
22
+ export type IdTokenReservedClaim = (typeof ID_TOKEN_RESERVED_CLAIMS)[number];
23
+ /**
24
+ * The server-owned half of an access-token payload. Typing the payload literal
25
+ * as this makes TypeScript's excess-property check reject any claim name that
26
+ * isn't in `ACCESS_TOKEN_RESERVED_CLAIMS`, so a new server-owned claim cannot
27
+ * be added to the mint without also being reserved.
28
+ */
29
+ export type ServerOwnedAccessTokenClaims = Partial<Record<AccessTokenReservedClaim, unknown>>;
30
+ /** As `ServerOwnedAccessTokenClaims`, for the ID token. */
31
+ export type ServerOwnedIdTokenClaims = Partial<Record<IdTokenReservedClaim, unknown>>;
32
+ /** Which payload a custom claim is being written to. */
33
+ export type ClaimPayloadKind = "access_token" | "id_token" | "userinfo" | "service_token" | "client_service_token";
34
+ export declare function isReservedClaim(claim: string, kind: ClaimPayloadKind): boolean;
35
+ export interface ApplyCustomClaimOptions {
36
+ /** Which payload is being written to — selects the reserved set. */
37
+ kind: ClaimPayloadKind;
38
+ /**
39
+ * Who is writing. Used in the warning so an operator can tell which hook
40
+ * dropped a claim (e.g. `onExecuteCredentialsExchange`,
41
+ * `template-hook:add-roles`, `createServiceToken`).
42
+ */
43
+ source: string;
44
+ /** Request context, when there is one — the warning goes to the tenant log. */
45
+ ctx?: Context<{
46
+ Bindings: Bindings;
47
+ Variables: Variables;
48
+ }>;
49
+ /** Tenant to log against. Defaults to `ctx.var.tenant_id`. */
50
+ tenantId?: string;
51
+ }
52
+ /**
53
+ * Write a caller-supplied claim onto a payload unless the authorization server
54
+ * owns that claim name.
55
+ *
56
+ * @returns true when the claim was written, false when it was dropped.
57
+ */
58
+ export declare function applyCustomClaim(payload: Record<string, unknown>, claim: string, value: unknown, options: ApplyCustomClaimOptions): boolean;
59
+ /**
60
+ * Bulk variant of `applyCustomClaim`. Returns a new object holding only the
61
+ * claims that are safe to merge, so callers can keep spreading them into a
62
+ * payload literal.
63
+ */
64
+ export declare function applyCustomClaims(claims: Record<string, unknown> | undefined, options: ApplyCustomClaimOptions): Record<string, unknown> | undefined;
@@ -1,5 +1,6 @@
1
1
  import { CodeExecutor, DataAdapters } from "@authhero/adapter-interfaces";
2
2
  import type { WebhookInvoker } from "../types/AuthHeroConfig";
3
+ import type { OutboxMetricsSink } from "../types/OutboxMetrics";
3
4
  export interface RunOutboxRelayConfig {
4
5
  /** Same `DataAdapters` passed to `init()`. Must include `outbox` to drain. */
5
6
  dataAdapter: DataAdapters;
@@ -31,6 +32,13 @@ export interface RunOutboxRelayConfig {
31
32
  * silently skipped.
32
33
  */
33
34
  codeExecutor?: CodeExecutor;
35
+ /**
36
+ * Optional metrics sink — same shape as `init({ outbox: { metrics } })`.
37
+ * Receives `outbox_events_processed_total`,
38
+ * `outbox_events_dead_lettered_total` and `outbox_retry_delay_seconds` for
39
+ * the events this cron drain handles, tagged `source: "cron"`.
40
+ */
41
+ metrics?: OutboxMetricsSink;
34
42
  }
35
43
  /**
36
44
  * One-call outbox relay for cron / scheduled handlers.