Server-Sent Events

Real-time event stream types used by the Comicarr UI.

Comicarr pushes live updates to the browser over Server-Sent Events (SSE).

Endpoint

GET /api/events/stream
RequirementDetail
AuthSession cookie (comicarr_session). API keys are not accepted
Content typetext/event-stream
KeepaliveServer pings ~every 15s; client should reconnect on drop
curl -N -b cookies.txt \
  -H "Accept: text/event-stream" \
  http://localhost:8090/api/events/stream

Each event has an SSE event: name and a JSON data: payload. Sequence id: values may be present for client tracking.

Event catalog

There are exactly four event names, and the web UI (useServerEvents) listens for all four. Per-feature event types are deliberately not added: everything narrative travels on activity.

activity

The single narrative channel. One event is published per durable activity row, after the row commits, so an event you receive always corresponds to something that actually happened.

FieldNotes
event_idRow id
created_atISO-8601 UTC
activitysearch, grab, download, import, refresh, add, tag
statusstarted, succeeded, no_match, cancelled, failed, blocked, needs_attention
subject_typeissue, annual, series, arc, run
subject_id / subject_labelWhat the event is about, and how to display it
reason_code / reason_detailWhy, for non-succeeded outcomes
providerProvider name, when one was involved
run_idSearch run this belongs to, when applicable
release_keyPipeline journal key, required for download and import
parent_series_idSet for issue- and annual-scoped events
scope_type / scope_idOptional narrowing scope

Not every combination is legal. The (activity, status, subject_type) triple is validated against a fixed table before the row is written. search brackets a run with started / succeeded at subject_type: run and only reports per-issue trouble. download has no started, because in-flight state is live instead of narrated. An illegal combination is rejected at write time and never reaches the stream.

Severity is derived, never sent. failed, blocked, and needs_attention are action-required; everything else is normal. Compute it from status; there is no severity field to read.

Do not accumulate the stream

The Comicarr client treats each event as an invalidation signal. It re-reads the affected queries and does not build a list out of the stream. Integrators should do the same. The stream is lossy under load by design, since per-subscriber queues drop oldest at 256 events, so a client that treats it as the record of what happened will silently miss entries. Read /api/activity/timeline for history.

ai_activity

AI feature completed a logged action.

FieldNotes
feature_typeFeature key
actionDescription
successBoolean
latency_msOptional

UI: invalidates AI activity/status and dashboard queries. Published via the EventBus from the AI activity logger.

restart

The server is coming back. The client keeps its normal reconnect backoff and rides it home.

FieldNotes
messageHuman-readable

shutdown

The server is going away and is not expected back. The client drops the backoff ladder and stops retrying.

FieldNotes
messageHuman-readable

Delivery model

  • The backend EventBus (comicarr.app.core.events) fans out to each SSE subscriber queue, capped at 256 events per subscriber with the oldest dropped under overflow.
  • activity is published by one facade, comicarr.app.activity.events.record_activity, and only after the durable row commits. Nothing else publishes on that channel.
  • ai_activity, restart, and shutdown are published directly via EventBus.publish_sync(event_type, payload).
  • The pre-EventBus GLOBAL_MESSAGES bus and its addbyid / scheduler_message / config_check / check_update / search_progress / search_complete / storyarc_added event names are retired. If you are integrating against an older description of this API, those names no longer appear on the stream.

Client reconnect

The React client opens exactly one EventSource per tab and reconnects with capped exponential backoff if the stream drops. Integrators should do the same. A second concurrent stream per session is not supported.

On this page