AGPL-3.0-or-later · forever.

remote preview · SSE

Reconnect without inventing events.

Consume the discriminated SSE union with idle detection, bounded reconnects and Last-Event-Id continuity.

A dropped TCP connection is not a terminal workflow result. The stream reconnects from the last event id and only settles normally after completed, failed or cancelled.

Stream from a persisted job id.

The AsyncIterable yields the typed event union. Terminal events end iteration; transport loss without one is an error.

for await (const event of nika.jobs.stream(job_id)) {
  switch (event.type) {
    case 'task_start':
      ui.start(event.task_id, event.verb)
      break
    case 'task_complete':
      ui.complete(event.task_id, event.duration_ms)
      break
  }
}

Bound the quiet and reconnect windows.

Set the idle timeout from the longest legitimate silence, then cap reconnect attempts so an outage cannot pin a worker forever.

nika.jobs.stream(job_id, {
  idleTimeout: 120_000,
  maxReconnects: 5,
  reconnectDelay: 2_000,
  signal: request.signal,
})

Design for an additive union.

Handle the events the interface needs and keep an exhaustive telemetry branch. A newer service may add an event without changing existing meanings.

id: 41  task_complete
       │
       × connection drops
       │
Last-Event-Id: 41
       ▼
id: 42  artifact_written