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.
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.
6 declarations
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.
realtime/audit_log_sse.ts view source
EventSpec[] type EventSpec[]
import {audit_log_event_specs} from '@fuzdev/fuz_app/realtime/audit_log_sse.js'; SSE event specs for audit log events.
One spec per AUDIT_EVENT_TYPES entry, all sharing the AuditLogEventJson params schema.
Pass to create_app_server's event_specs for surface generation and DEV validation.
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.
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.
registryThe 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>
logLogger — pass as part of stream option to create_audit_log_route_specs.
type Logger
on_audit_eventBroadcasts 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
eventvoidrequired_roleThe 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
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.
optionsfactory options
{ role?: string | undefined; log: Logger; connection_closer: RealtimeCloser | null; max_per_scope?: number | null | undefined; keep_alive_ms?: number | null | undefined; }AuditLogSse audit log SSE setup (stream options + on_audit_event + registry)
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,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.
registrythe registry to close streams on
SseRegistry<T>required_rolethe role every stream of registry was gated on,
or null when they are not role-gated (a role target then closes
nothing)
string | nullConnectionCloser create_sse_connection_closer<T>T