Files
TanTan fa9c73363d
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
SnowLuma v2.4.2 source snapshot
2026-11-13 09:02:00 +08:00

4.2 KiB

OneBot HTTP event streams

An HTTP server can serve actions and Server-Sent Events on the same listener. Enable SSE in the WebUI's HTTP API adapter, or set enableSse: true on an entry in networks.httpServers. The default is false; existing HTTP and WebSocket configurations keep their behavior. SSE and enableWebSocket may both be enabled.

{
  "name": "web-client",
  "host": "127.0.0.1",
  "port": 3000,
  "path": "/api",
  "enableSse": true,
  "accessToken": "replace-with-your-token",
  "messageFormat": "array",
  "reportSelfMessage": false
}

GET /api/_events?access_token=<token> opens the event stream. Actions continue to use POST /api/<action> with a JSON parameter object. HTTP requests accept Authorization: Bearer <token>, Authorization: <token> (for Stapxs QQ Lite), or the access_token query parameter. The configured token and bind address still apply. Empty tokens retain the existing unauthenticated HTTP behavior.

const events = new EventSource(`api/_events?access_token=${encodeURIComponent(token)}`);
events.onmessage = ({ data }) => console.log(JSON.parse(data));
events.onerror = () =>
  console.error('Event connection interrupted; check connection and authentication');

const response = await fetch('api/get_status', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', Authorization: token },
  body: JSON.stringify({}),
});
if (!response.ok) throw new Error(`Action failed: HTTP ${response.status}`);
console.log(await response.json());
// Close the stream when the owning page/component is disposed.
// events.close();

Configure Stapxs's SSE event address as api/_events and HTTP address as api when both are exposed under that same-origin proxy prefix. Forward the request path, query string, authorization and Last-Event-ID headers unchanged. SnowLuma does not add cross-origin access grants. TLS and any additional proxy authentication remain the proxy's responsibility.

Responses use text/event-stream, Cache-Control: no-cache, no-transform, and X-Accel-Buffering: no. Events are ordinary unnamed data: frames containing OneBot JSON. Connection lifecycle and current heartbeat events bootstrap each subscription. Transport comments (: ping) are sent every 15 seconds; they are not OneBot events. The browser's reconnect delay is 3 seconds.

Reconnect and resource limits

Every broadcast event has an opaque id. A reconnect with Last-Event-ID replays events after that cursor, in order, before connection bootstrap events and subsequent live events. Native EventSource sends this header automatically when reconnecting the same object. A new subscription without the header starts at the present and does not receive old messages.

Each adapter retains at most 256 events and 8 MiB in memory, including while no client is connected. This is a short reconnect window, not durable message history. Accounts and adapter instances have independent histories. Event IDs are invalidated on restart, shutdown, token rotation, report-policy changes or disabling SSE. Neither replay nor live delivery bypasses messageFormat or reportSelfMessage.

An invalid cursor returns HTTP 400. An expired, future or foreign cursor returns HTTP 409 with wording explaining that replay is unavailable. There is no silent fallback to live-only delivery. After reconciling the application's state/history, close and recreate EventSource to subscribe without the old cursor. EventSource's error callback does not expose the HTTP error body; fetch-based consumers can inspect it directly. Bootstrap events can share the latest broadcast cursor and must not be treated as newly persisted message events.

Each client's pending output is limited to 8 MiB. Slow readers are disconnected with a warning instead of retaining unbounded events or blocking other clients. A single frame exceeding this limit also disconnects that client. Reconnection is subject to the same replay limits. Disconnect, hot reload and shutdown release connections and heartbeat timers; rotating the token revokes existing streams.

Tests: pnpm --filter @snowluma/onebot exec vitest run tests/http-server-sse.test.ts tests/http-sse-backpressure.test.ts tests/http-server-websocket-config.test.ts.