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| Requirement | Detail |
|---|---|
| Auth | Session cookie (comicarr_session). API keys are not accepted |
| Content type | text/event-stream |
| Keepalive | Server pings ~every 15s; client should reconnect on drop |
curl -N -b cookies.txt \
-H "Accept: text/event-stream" \
http://localhost:8090/api/events/streamEach 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.
| Field | Notes |
|---|---|
event_id | Row id |
created_at | ISO-8601 UTC |
activity | search, grab, download, import, refresh, add, tag |
status | started, succeeded, no_match, cancelled, failed, blocked, needs_attention |
subject_type | issue, annual, series, arc, run |
subject_id / subject_label | What the event is about, and how to display it |
reason_code / reason_detail | Why, for non-succeeded outcomes |
provider | Provider name, when one was involved |
run_id | Search run this belongs to, when applicable |
release_key | Pipeline journal key, required for download and import |
parent_series_id | Set for issue- and annual-scoped events |
scope_type / scope_id | Optional 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.
| Field | Notes |
|---|---|
feature_type | Feature key |
action | Description |
success | Boolean |
latency_ms | Optional |
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.
| Field | Notes |
|---|---|
message | Human-readable |
shutdown
The server is going away and is not expected back. The client drops the backoff ladder and stops retrying.
| Field | Notes |
|---|---|
message | Human-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. activityis 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, andshutdownare published directly viaEventBus.publish_sync(event_type, payload).- The pre-EventBus
GLOBAL_MESSAGESbus and itsaddbyid/scheduler_message/config_check/check_update/search_progress/search_complete/storyarc_addedevent 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.
Related
- Authentication for session cookies
- REST API for non-streaming routes
- AI Features for the AI activity feed in the UI