auth/role_grant_offer_notifications.ts

Role grant offer WebSocket notification specs, builders, and the narrow NotificationSender interface that decouples offer/revoke send sites from BackendWebsocketTransport.

Six RemoteNotificationActionSpecs cover the consentful-role-grants lifecycle events the server pushes to affected accounts:

- role_grant_offer_received → recipient's sockets when an offer is created - role_grant_offer_retracted → recipient's sockets when a grantor retracts - role_grant_offer_accepted → grantor's sockets when the recipient accepts - role_grant_offer_declined → grantor's sockets when the recipient declines - role_grant_offer_supersede → grantor's sockets when a sibling accept, a revoke of the resulting role_grant, or destruction of the parent scope row obsoletes their pending offer - role_grant_revoke → revokee's sockets when one of their active role_grants is revoked (companion to the role_grant_revoke audit event)

Payloads are flat and normalized — RoleGrantOfferJson for the offer-lifecycle notifications (decline reason rides on offer.decline_reason, not a sibling field), and {role_grant_id, role, scope_id, reason?} for role_grant_revoke. The revokee/grantor/recipient account id travels via the send target (the NotificationSender.send_to_account argument), not in the payload.

The specs surface as EventSpecs via create_action_event_spec — callers append role_grant_offer_notification_specs to their event_specs on create_app_server so the surface reflects them and DEV-mode broadcast validation catches payload drift.

Declarations
#

26 declarations

view source

build_role_grant_offer_accepted_notification
#

auth/role_grant_offer_notifications.ts view source

(params: { offer: { id: string & $brand<"Uuid">; from_actor_id: string & $brand<"Uuid">; to_account_id: string & $brand<"Uuid">; to_actor_id: (string & $brand<"Uuid">) | null; ... 11 more ...; resulting_role_grant_id: (string & $brand<...>) | null; }; }): { ...; }

params

type { offer: { id: string & $brand<"Uuid">; from_actor_id: string & $brand<"Uuid">; to_account_id: string & $brand<"Uuid">; to_actor_id: (string & $brand<"Uuid">) | null; ... 11 more ...; resulting_role_grant_id: (string & $brand<...>) | null; }; }

returns

{ [x: string]: unknown; jsonrpc: "2.0"; method: string; params?: { [x: string]: unknown; } | undefined; }

build_role_grant_offer_declined_notification
#

auth/role_grant_offer_notifications.ts view source

(params: { offer: { id: string & $brand<"Uuid">; from_actor_id: string & $brand<"Uuid">; to_account_id: string & $brand<"Uuid">; to_actor_id: (string & $brand<"Uuid">) | null; ... 11 more ...; resulting_role_grant_id: (string & $brand<...>) | null; }; }): { ...; }

params

type { offer: { id: string & $brand<"Uuid">; from_actor_id: string & $brand<"Uuid">; to_account_id: string & $brand<"Uuid">; to_actor_id: (string & $brand<"Uuid">) | null; ... 11 more ...; resulting_role_grant_id: (string & $brand<...>) | null; }; }

returns

{ [x: string]: unknown; jsonrpc: "2.0"; method: string; params?: { [x: string]: unknown; } | undefined; }

build_role_grant_offer_received_notification
#

auth/role_grant_offer_notifications.ts view source

(params: { offer: { id: string & $brand<"Uuid">; from_actor_id: string & $brand<"Uuid">; to_account_id: string & $brand<"Uuid">; to_actor_id: (string & $brand<"Uuid">) | null; ... 11 more ...; resulting_role_grant_id: (string & $brand<...>) | null; }; }): { ...; }

params

type { offer: { id: string & $brand<"Uuid">; from_actor_id: string & $brand<"Uuid">; to_account_id: string & $brand<"Uuid">; to_actor_id: (string & $brand<"Uuid">) | null; ... 11 more ...; resulting_role_grant_id: (string & $brand<...>) | null; }; }

returns

{ [x: string]: unknown; jsonrpc: "2.0"; method: string; params?: { [x: string]: unknown; } | undefined; }

build_role_grant_offer_retracted_notification
#

auth/role_grant_offer_notifications.ts view source

(params: { offer: { id: string & $brand<"Uuid">; from_actor_id: string & $brand<"Uuid">; to_account_id: string & $brand<"Uuid">; to_actor_id: (string & $brand<"Uuid">) | null; ... 11 more ...; resulting_role_grant_id: (string & $brand<...>) | null; }; }): { ...; }

params

type { offer: { id: string & $brand<"Uuid">; from_actor_id: string & $brand<"Uuid">; to_account_id: string & $brand<"Uuid">; to_actor_id: (string & $brand<"Uuid">) | null; ... 11 more ...; resulting_role_grant_id: (string & $brand<...>) | null; }; }

returns

{ [x: string]: unknown; jsonrpc: "2.0"; method: string; params?: { [x: string]: unknown; } | undefined; }

build_role_grant_offer_supersede_notification
#

auth/role_grant_offer_notifications.ts view source

(params: { offer: { id: string & $brand<"Uuid">; from_actor_id: string & $brand<"Uuid">; to_account_id: string & $brand<"Uuid">; to_actor_id: (string & $brand<"Uuid">) | null; ... 11 more ...; resulting_role_grant_id: (string & $brand<...>) | null; }; reason: "sibling_accepted" | ... 1 more ... | "scope_destroyed"; cause_id: string & $brand<...>; }): { ...; }

params

type { offer: { id: string & $brand<"Uuid">; from_actor_id: string & $brand<"Uuid">; to_account_id: string & $brand<"Uuid">; to_actor_id: (string & $brand<"Uuid">) | null; ... 11 more ...; resulting_role_grant_id: (string & $brand<...>) | null; }; reason: "sibling_accepted" | ... 1 more ... | "scope_destroyed"; cause_id:...

returns

{ [x: string]: unknown; jsonrpc: "2.0"; method: string; params?: { [x: string]: unknown; } | undefined; }

build_role_grant_revoke_notification
#

auth/role_grant_offer_notifications.ts view source

(params: { role_grant_id: string & $brand<"Uuid">; role: string; scope_id: (string & $brand<"Uuid">) | null; reason: string | null; }): { [x: string]: unknown; jsonrpc: "2.0"; method: string; params?: { ...; } | undefined; }

params

type { role_grant_id: string & $brand<"Uuid">; role: string; scope_id: (string & $brand<"Uuid">) | null; reason: string | null; }

returns

{ [x: string]: unknown; jsonrpc: "2.0"; method: string; params?: { [x: string]: unknown; } | undefined; }

NotificationSender
#

auth/role_grant_offer_notifications.ts view source

NotificationSender

Narrow structural capability for sending a JSON-RPC notification to every socket bound to an account.

BackendWebsocketTransport satisfies this interface — its send_to_account(account_id, message) signature accepts the broader JsonrpcMessageFromServerToClient type, which is contravariantly compatible with JsonrpcNotification here. The interface stays local so handlers don't couple to the concrete transport, and tests can inject a capturing stub with no WS machinery.

Returns the number of sockets the notification was sent to — callers typically ignore it (used by telemetry / tests).

send_to_account

type (account_id: Uuid, message: JsonrpcNotification) => number

ROLE_GRANT_OFFER_ACCEPTED_NOTIFICATION_METHOD
#

role_grant_offer_accepted_notification_spec
#

auth/role_grant_offer_notifications.ts view source

{ method: string; kind: "remote_notification"; initiator: "backend"; auth: null; side_effects: true; input: ZodObject<{ offer: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; from_actor_id: $ZodBranded<...>; ... 13 more ...; resulting_role_grant_id: ZodNullable<...>; }, $strict>; }, $strict>; output: ZodVoid; a...

ROLE_GRANT_OFFER_DECLINED_NOTIFICATION_METHOD
#

role_grant_offer_declined_notification_spec
#

auth/role_grant_offer_notifications.ts view source

{ method: string; kind: "remote_notification"; initiator: "backend"; auth: null; side_effects: true; input: ZodObject<{ offer: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; from_actor_id: $ZodBranded<...>; ... 13 more ...; resulting_role_grant_id: ZodNullable<...>; }, $strict>; }, $strict>; output: ZodVoid; a...

role_grant_offer_notification_specs
#

ROLE_GRANT_OFFER_RECEIVED_NOTIFICATION_METHOD
#

role_grant_offer_received_notification_spec
#

auth/role_grant_offer_notifications.ts view source

{ method: string; kind: "remote_notification"; initiator: "backend"; auth: null; side_effects: true; input: ZodObject<{ offer: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; from_actor_id: $ZodBranded<...>; ... 13 more ...; resulting_role_grant_id: ZodNullable<...>; }, $strict>; }, $strict>; output: ZodVoid; a...

ROLE_GRANT_OFFER_RETRACTED_NOTIFICATION_METHOD
#

role_grant_offer_retracted_notification_spec
#

auth/role_grant_offer_notifications.ts view source

{ method: string; kind: "remote_notification"; initiator: "backend"; auth: null; side_effects: true; input: ZodObject<{ offer: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; from_actor_id: $ZodBranded<...>; ... 13 more ...; resulting_role_grant_id: ZodNullable<...>; }, $strict>; }, $strict>; output: ZodVoid; a...

ROLE_GRANT_OFFER_SUPERSEDE_NOTIFICATION_METHOD
#

role_grant_offer_supersede_notification_spec
#

auth/role_grant_offer_notifications.ts view source

{ method: string; kind: "remote_notification"; initiator: "backend"; auth: null; side_effects: true; input: ZodObject<{ offer: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; from_actor_id: $ZodBranded<...>; ... 13 more ...; resulting_role_grant_id: ZodNullable<...>; }, $strict>; reason: ZodEnum<...>; cause_id:...

ROLE_GRANT_REVOKE_NOTIFICATION_METHOD
#

role_grant_revoke_notification_spec
#

auth/role_grant_offer_notifications.ts view source

{ method: string; kind: "remote_notification"; initiator: "backend"; auth: null; side_effects: true; input: ZodObject<{ role_grant_id: $ZodBranded<ZodUUID, "Uuid", "out">; role: ZodString; scope_id: ZodNullable<...>; reason: ZodNullable<...>; }, $strict>; output: ZodVoid; async: true; description: string; }

RoleGrantOfferAcceptedParams
#

auth/role_grant_offer_notifications.ts view source

ZodObject<{ offer: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; from_actor_id: $ZodBranded<ZodUUID, "Uuid", "out">; to_account_id: $ZodBranded<ZodUUID, "Uuid", "out">; ... 12 more ...; resulting_role_grant_id: ZodNullable<...>; }, $strict>; }, $strict>

Params for role_grant_offer_accepted — recipient accepted the offer.

RoleGrantOfferDeclinedParams
#

auth/role_grant_offer_notifications.ts view source

ZodObject<{ offer: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; from_actor_id: $ZodBranded<ZodUUID, "Uuid", "out">; to_account_id: $ZodBranded<ZodUUID, "Uuid", "out">; ... 12 more ...; resulting_role_grant_id: ZodNullable<...>; }, $strict>; }, $strict>

Params for role_grant_offer_declined. The decline reason (if any) rides along inside offer.decline_reason — the DB stamps it on the offer row during decline, so a sibling reason field would just duplicate it.

RoleGrantOfferReceivedParams
#

auth/role_grant_offer_notifications.ts view source

ZodObject<{ offer: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; from_actor_id: $ZodBranded<ZodUUID, "Uuid", "out">; to_account_id: $ZodBranded<ZodUUID, "Uuid", "out">; ... 12 more ...; resulting_role_grant_id: ZodNullable<...>; }, $strict>; }, $strict>

Params for role_grant_offer_received — offer delivered to its recipient.

RoleGrantOfferRetractedParams
#

auth/role_grant_offer_notifications.ts view source

ZodObject<{ offer: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; from_actor_id: $ZodBranded<ZodUUID, "Uuid", "out">; to_account_id: $ZodBranded<ZodUUID, "Uuid", "out">; ... 12 more ...; resulting_role_grant_id: ZodNullable<...>; }, $strict>; }, $strict>

Params for role_grant_offer_retracted — grantor-side retraction.

RoleGrantOfferSupersedeParams
#

auth/role_grant_offer_notifications.ts view source

ZodObject<{ offer: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; from_actor_id: $ZodBranded<ZodUUID, "Uuid", "out">; to_account_id: $ZodBranded<ZodUUID, "Uuid", "out">; ... 12 more ...; resulting_role_grant_id: ZodNullable<...>; }, $strict>; reason: ZodEnum<...>; cause_id: $ZodBranded<...>; }, $strict>

Params for role_grant_offer_supersede. Fires to the grantor's sockets when their pending offer is obsoleted — either by a sibling accept (reason: 'sibling_accepted'), by revoke of the resulting role_grant (reason: 'role_grant_revoked'), or by deletion of the parent scope row the offer was bound to (reason: 'scope_destroyed'). cause_id points at the accepted offer id, the revoked role_grant id, or the destroyed scope row id respectively.

RoleGrantRevokeParams
#

auth/role_grant_offer_notifications.ts view source

ZodObject<{ role_grant_id: $ZodBranded<ZodUUID, "Uuid", "out">; role: ZodString; scope_id: ZodNullable<$ZodBranded<ZodUUID, "Uuid", "out">>; reason: ZodNullable<...>; }, $strict>

Params for role_grant_revoke. Delivered to the revokee's sockets when one of their active role_grants is revoked. Flat wire shape — revoked_by is admin-UI-visible but deliberately omitted here (the revokee doesn't need to learn the admin's identity). Target account is implicit in the send target.

Depends on
#

Imported by
#