realtime/audit_log_sse.ts

The audit log SSE stream's registry, its connection closer, and the convenience factory that wires them.

An SSE stream is authorized once, at open, and then only emits — nothing re-reads its credential or its role. create_sse_connection_closer adapts a SseRegistry to ConnectionCloser, and a registry added to the backend's deps.connection_closer is closed by every revocation: the handlers' own post-commit closes (queue_connection_close), and the one audit listener on that closer (create_revocation_guard), which repeats them.

create_audit_log_sse builds the registry and its broadcaster and adds the registry to the closer — making the secure path the easy path for consumers.

view source

Declarations
#

6 declarations

AUDIT_LOG_CHANNEL
#

realtime/audit_log_sse.ts view source

"audit_log" import {AUDIT_LOG_CHANNEL} from '@fuzdev/fuz_app/realtime/audit_log_sse.js';

SSE channel the audit-log stream route publishes on.

audit_log_event_specs
#

AUDIT_LOG_SSE_MAX_PER_SCOPE
#

realtime/audit_log_sse.ts view source

10 import {AUDIT_LOG_SSE_MAX_PER_SCOPE} from '@fuzdev/fuz_app/realtime/audit_log_sse.js';

Default max concurrent SSE subscribers per session scope for the audit log.

The audit log SSE subscribes with scope = session_hash and groups = [account_id]. Only scope is capped — so this limits tabs per session. An account's total streams across all sessions is bounded transitively by max_sessions × AUDIT_LOG_SSE_MAX_PER_SCOPE. 10 tabs per session is a comfortable ceiling for normal use; consumers raising it above ~50 should consider server-side connection limits.

AuditLogSse
#

realtime/audit_log_sse.ts view source

AuditLogSse import type {AuditLogSse} from '@fuzdev/fuz_app/realtime/audit_log_sse.js';

Convenience factory result for audit log SSE.

Satisfies AuditLogRouteOptions['stream'] and provides the on_audit_event callback that broadcasts each row to the stream.

registry

The SSE registry the audit stream route registers each stream on (two-phase: subscribe_pending then admit) — pass as part of the stream option to create_audit_log_route_specs. Also exposed for subscriber count monitoring.

type SseRegistry<SseNotification>

log

Logger — pass as part of stream option to create_audit_log_route_specs.

type Logger

on_audit_event

Broadcasts each audit row to the stream's subscribers. Wired by create_app_server's audit_log_sse option, or compose inside the consumer's audit_factory body. Closes nothing: revocations reach the streams through the registry's membership in the backend's closer.

type (event: AuditLogEvent): void

event

returns void

required_role

The role the stream requires — what a caller adapting registry passes create_sse_connection_closer, so a role revocation closes its streams.

type string

keep_alive_ms?

Each stream's keep-alive interval, read by the audit stream route (AuditLogRouteOptions['stream']); undefined keeps the default.

type number | null

create_audit_log_sse
#

realtime/audit_log_sse.ts view source

(options: { role?: string | undefined; log: Logger; connection_closer: RealtimeCloser | null; max_per_scope?: number | null | undefined; keep_alive_ms?: number | null | undefined; }): AuditLogSse import {create_audit_log_sse} from '@fuzdev/fuz_app/realtime/audit_log_sse.js';

Create a complete audit log SSE setup: the registry, its broadcaster, and its connection closer.

Builds the SseRegistry and the broadcast callback, and adds the registry to connection_closer for good — the remover add returns is dropped, so a caller that must take the registry out again passes null and adds it itself. Revocations close the streams through that closer: the handlers' post-commit closes, and the create_revocation_guard listener on it (which create_app_server registers; a hand wiring registers its own). The result satisfies AuditLogRouteOptions['stream'] and provides the on_audit_event listener for the audit emitter.

Most consumers pass audit_log_sse: true to create_app_server and never touch this directly — the factory builds an AuditLogSse, registers audit_sse.on_audit_event via backend.deps.audit.add_listener, and exposes it via AppServerContext.audit_sse. Reach for the manual path (compose inside audit_factory body, or audit.add_listener(audit_sse.on_audit_event) post-assembly) only when wiring outside create_app_server.

options

factory options

type { role?: string | undefined; log: Logger; connection_closer: RealtimeCloser | null; max_per_scope?: number | null | undefined; keep_alive_ms?: number | null | undefined; }

returns

AuditLogSse

audit log SSE setup (stream options + on_audit_event + registry)

examples

const connection_closer = create_realtime_closer(); const audit_sse = create_audit_log_sse({log, connection_closer}); // On CreateAppBackendOptions — the same closer, and the listeners inside // the audit_factory body: connection_closer, audit_factory: ({db, log}) => { const guard = create_revocation_guard(connection_closer, log); return create_audit_emitter({ db, log, on_audit_event: (event) => { audit_sse.on_audit_event(event); guard(event); }, }); }, // In create_route_specs: create_audit_log_route_specs({stream: audit_sse}); // In create_app_server options: event_specs: audit_log_event_specs,

create_sse_connection_closer
#

realtime/audit_log_sse.ts view source

<T>(registry: SseRegistry<T>, required_role: string | null): ConnectionCloser import {create_sse_connection_closer} from '@fuzdev/fuz_app/realtime/audit_log_sse.js';

Adapt an SseRegistry to ConnectionCloser, so a revocation handler's close reaches its streams.

close_connections is SseRegistry.close_by_identity on the id its target carries, so it closes the streams registered under that id as their scope or in their groups — pending registrations included. The audit stream route registers scope = session hash and groups = [account id]; a route that admits bearer tokens registers the API token id too, and a token target then reaches it. A role target closes the account's streams when its role is the one the registry's streams are gated on — the registry keeps one gating role for all its streams, not one per stream. close_all_connections is SseRegistry.close_all — every stream, for shutdown.

Twin of the Rust spine's ConnectionCloser impl on SseRegistry.

registry

the registry to close streams on

type SseRegistry<T>

required_role

the role every stream of registry was gated on, or null when they are not role-gated (a role target then closes nothing)

type string | null

returns

ConnectionCloser

generics

create_sse_connection_closer<T>
T

Depends on
#

Imported by
#