Event schema¶
uvscope exposes several bounded, sequenced event streams. The HTTP API reads them with
?after=<seq>&limit=<n>; long-lived WebSocket terminals stream output separately. This page is the
1.x compatibility contract for those payloads.
Compatibility policy¶
- Within 1.x, event fields may be added; existing field names, types and meanings do not change without a major release.
- Consumers must ignore unknown fields and unknown
typevalues. seqis monotonic per stream and starts at 1. It is the cursor forafter. Gaps mean the bounded buffer dropped older entries, not that the event was lost silently: the stream'sfirstSeq/nextSeq(where exposed) describe the retained window.- Timestamps are ISO-8601 UTC strings. Proxy logs use
time; other streams useat. - Payloads are truncated at a fixed byte budget. Truncation is always explicit in the payload
(
truncated: true) and never changes the event type. - No stream includes credentials, private keys or complete request/response bodies by default.
Common envelope¶
Every stream event carries:
{
"seq": 12,
"at": "2026-10-25T09:30:00Z",
"type": "connected"
}
Supervisor events add id (service id), name and an optional message. Proxy logs add
method, path, status and optional rule, action, latencyMs, error, message.
Service supervisor¶
GET /api/supervisor/events?after=&limit= returns:
type |
Meaning | Extra fields |
|---|---|---|
registered |
A service was added to the watchdog | message describes desired state |
unregistered |
A service was removed (delete, module disable, reset) | — |
enabled / disabled |
desired changed |
— |
restart-requested |
POST /api/supervisor/:id/restart |
— |
fail-runtime |
POST /api/supervisor/:id/stop-runtime |
— |
restart |
The watchdog started a desired service that was down | message |
Snapshot rows (GET /api/supervisor) contain id, kind (proxy, listener, socks5,
terminal), name, desired, running, restarts, lastError and updatedAt.
Persistent TCP sessions¶
GET /api/tcp/sessions/:id/events?after=&limit=:
type |
Extra fields |
|---|---|
connected |
— |
recv |
payload (see below) |
send |
payload |
closed |
reason |
peer-closed |
fin |
error |
error |
Payload objects¶
Binary-safe payloads use one shape in TCP/UDP/listener events:
{
"length": 12,
"truncated": false,
"hex": "68 65 6c 6c 6f 0a ...",
"encoding": "utf8",
"text": "hello"
}
encoding is utf8 or base64 (binary payloads use base64 instead of text). length is the
original byte count; truncated means the retained sample is shorter than length.
TCP / UDP listeners¶
GET /api/transport/listeners/:id/events?after=&limit=:
type |
Extra fields |
|---|---|
started |
— |
stopped |
— |
error |
error |
accepted |
sessionId, peer |
session-closed |
sessionId (see the per-session closed/error event for the reason) |
datagram |
peer, partial, payload |
Per-session events (.../sessions/:sid/events) use the same envelope:
type |
Extra fields |
|---|---|
accepted |
peer |
recv |
payload |
send |
payload |
closed |
reason |
peer-closed |
fin |
error |
error |
peer is "host:port". UDP datagrams also report partial when the datagram was clipped at the
receive buffer size.
SOCKS5 servers¶
GET /api/socks5/servers/:id/events?after=&limit=:
type |
Extra fields |
|---|---|
started |
port (actual bound port) |
stopped |
— |
error |
error |
session-end |
sessionId, command, target, peer, endStatus, durationMs, bytesClientToTarget, bytesTargetToClient, udpDatagrams, udpBytes |
Session records (.../sessions) use the same fields plus state, endedAt,
bytesAvailable and error when the session failed.
Reverse proxy logs¶
GET /api/proxies/:id/logs?after=&limit= returns entries with seq, time, method, path,
status and, when relevant, rule, action, latencyMs, error or message. method is
SYSTEM for lifecycle entries (started, stopped, hot reload, supervisor restart) and the request
method for traffic. A WebSocket upgrade is logged with status: 101 and action: "upgrade".
Backend WebSocket sessions¶
GET /api/ws/sessions/:id/events?after=&limit=:
type |
Extra fields |
|---|---|
connecting |
url |
open |
— |
error |
error, optional detail, closeCode |
sent |
opcode (text, binary, ping, pong), size |
text |
text or base64 + encoding, size, truncated |
binary |
base64, size, truncated |
frame |
opcode, opcodeId, fin, rsv1, masked, length, truncated and a body field |
closing |
code, reason |
close |
code, reason, clean |
Virtual terminal output¶
Terminal output is not an event log; it is a sequenced chunk stream exposed by both
GET /api/terminal/sessions/:id/output?after=&limit= and the terminal WebSocket:
{
"ok": true,
"session": { "id": "...", "state": "running", "nextSeq": 42 },
"chunks": [{ "seq": 41, "data": "base64-bytes" }],
"firstSeq": 40,
"nextSeq": 42,
"truncated": false,
"missed": false
}
missed: true means the client cursor is ahead of or older than the retained window; reset the
cursor to 0 (the WebSocket sends {"type":"reset"} and the UI clears xterm). A supervised
restart resets the sequence numbers because the new child starts a fresh stream.
Terminal WebSocket control frames¶
| Direction | Message |
|---|---|
| Server → client | {"type":"attached","id":"..."} |
| Server → client | {"type":"reset"} |
| Server → client | {"type":"exit","state":"exited","code":0} |
| Server → client | {"type":"error","error":"..."} |
| Client → server | {"type":"input","data":"...","encoding":"text\|hex\|base64"} |
| Client → server | {"type":"resize","cols":100,"rows":30} |
| Client → server | {"type":"ping"} (server replies {"type":"pong"}) |
Output is sent as binary WebSocket frames; terminal input may also be sent as raw binary frames.