SSE bridge
The Nuxt module ships an opt-in Server-Sent Events endpoint that exposes the in-process default stream over HTTP. Anything that speaks SSE — a browser tab, a Tauri app, a CLI using fetch, a curl one-liner — can subscribe to live wide events.
pnpm dev, on a Node / Bun / Deno container, on a long-lived VM, or on Fly / Railway-style instances.Enable
In a Nuxt project the bridge is auto-enabled in dev — start pnpm dev and the stream URL is printed at startup:
[evlog] Stream available at http://localhost:3000/api/_evlog/stream
No config needed. To override the default, pick the shape that matches your intent:
export default defineNuxtConfig({
modules: ['evlog/nuxt'],
evlog: {
transport: {
// Auto-on in dev, off in production builds (current default — no config needed).
// stream: undefined,
// Boolean shorthand — force-enable in BOTH dev and prod.
stream: true,
// Explicit off — overrides the dev-mode auto-enable.
// stream: false,
// Full configuration.
// stream: {
// enabled: true,
// endpoint: '/api/_evlog/stream',
// token: process.env.EVLOG_STREAM_TOKEN,
// heartbeatMs: 15_000,
// buffer: 500,
// },
},
},
})
The four accepted shapes:
| Value | Dev | Production |
|---|---|---|
undefined (default) | enabled | disabled |
true | enabled | enabled |
false | disabled | disabled |
{ enabled: true, ... } | enabled (with config) | enabled (with config) |
The Nitro plugin auto-hooks the default in-process stream into evlog:drain, so every wide event also flows into any subscriber connected to the SSE route.
Try it in the playground
apps/playground ships a live demo. Run:
pnpm dev
# open http://localhost:3000/stream
You get a live event table with filters, a JSON inspector for each event, and buttons to fire demo requests. Useful to read the page source (apps/playground/app/pages/stream.vue) — it's ~25 lines of EventSource glue.
Endpoint
GET /api/_evlog/stream
| Header | Note |
|---|---|
Authorization: Bearer <token> | Required when token is configured |
Accept: text/event-stream | Set automatically by the browser EventSource |
Query parameters:
?since=<iso>— replay buffered events withevent.timestamp >= sincebefore switching to live mode
Response:
Content-Type: text/event-stream; charset=utf-8X-Evlog-Version: <package version>
Wire format
Every SSE data: line is a versioned JSON envelope:
data: {"evlog":"1","type":"hello","data":{"evlogVersion":"2.16.0","bufferSize":500,"heartbeatMs":15000}}
data: {"evlog":"1","type":"replay","data":{...wide event...}}
data: {"evlog":"1","type":"event","data":{...wide event...}}
event: ping
data: {"evlog":"1","type":"ping","data":{"t":1730000000000}}
| Type | When |
|---|---|
hello | First frame — server version + stream config |
replay | Each buffered event flushed when the client passed ?since= |
event | Each new event drained after the connection opened |
ping | Heartbeat every heartbeatMs (default 15s), sent with event: ping |
The evlog: "1" discriminant is the protocol version; future incompatible changes will bump it.
Security
| Mode | Behavior |
|---|---|
token set | Authorization: Bearer <token> is required |
token unset, host is localhost | Connection allowed (dev convenience) |
token unset, host is non-localhost | Origin must match Host (mirrors the ingest endpoint policy) |
The endpoint always returns 404 when the stream is disabled (production builds without an explicit override) so it's a no-op in environments where you don't want it.
Minimal browser consumer
const es = new EventSource('/api/_evlog/stream')
es.onmessage = (e) => {
const envelope = JSON.parse(e.data)
if (envelope.evlog !== '1') return
if (envelope.type === 'event' || envelope.type === 'replay') {
handle(envelope.data)
}
}
es.addEventListener('ping', () => {
// heartbeat — connection alive
})
That's it — no SDK needed, the browser ships EventSource. For Node / Bun consumers, use fetch with streaming response and parse the same envelope.
Going further
- Recipes — concrete patterns: build your own devtool, curl + jq inspection, replay-then-live, consumer-side analytics. See Recipes.
- Playground demo —
apps/playground/app/pages/stream.vueis a ~30-lineEventSourceconsumer with a live table, JSON inspector, and code samples per runtime. Runpnpm devand visit/stream.