Surfaces ↓
Net
client.net Daemon -> webapp network surface: replies to fetch and ws.open,
WebSocket frame/close/error events, and the Stream* event trio
driven by net.stream.open.
Requests
you ask, the daemon answers; await the tagged result and check .ok
fetch(NetFetch): Promise<TypedRequestResult<NetFetchReply, NetFetchErrorReply>>
push form: onFetchReply (subscribe instead of awaiting)
Payload for net.fetch: a single proxied HTTP request/response
round-trip through the connected companion's network stack.
const res = await client.net.fetch({ request: { /* NetFetchRequest */ } });
if (res.ok) {
console.log(res.response.response);
} else {
console.warn(res.kind, res.error);
} type Result =
| { ok: true; response: NetFetchReply }
| { ok: false; kind: 'domain'; error: NetFetchErrorReply }
| { ok: false; kind: 'protocol'; error: WireError }; wsOpen(NetWsOpen): Promise<TypedRequestResult<NetWsOpenReply, NetWsErrorReply>>
push form: onWsOpenReply (subscribe instead of awaiting)
const res = await client.net.wsOpen({ connectionId: '...', url: '...' });
if (res.ok) {
console.log(res.response.acceptedProtocol);
} else {
console.warn(res.kind, res.error);
} type Result =
| { ok: true; response: NetWsOpenReply }
| { ok: false; kind: 'domain'; error: NetWsErrorReply }
| { ok: false; kind: 'protocol'; error: WireError }; Commands
fire-and-forget; the promise resolves once the daemon has taken the message
wsClose(NetWsClose): Promise<void>
await client.net.wsClose({ connectionId: '...' }); wsSend(NetWsSend): Promise<void>
await client.net.wsSend({ connectionId: '...', frame: { /* WsFrame */ } }); streamOpen(NetStreamOpen): Promise<void>
await client.net.streamOpen({ streamId: '...', request: { /* NetFetchRequest */ } }); streamCancel(NetStreamCancel): Promise<void>
await client.net.streamCancel({ streamId: '...' }); Events
the daemon pushes these unprompted; subscribing returns an unsubscribe function
onWsMessage(handler: (NetWsMessage) => void): () => void
const off = client.net.onWsMessage((netWsMessage) => {
console.log(netWsMessage.connectionId);
});
// call off() to unsubscribe onWsClosed(handler: (NetWsClosed) => void): () => void
const off = client.net.onWsClosed((netWsClosed) => {
console.log(netWsClosed.connectionId);
});
// call off() to unsubscribe onWsErrorEvent(handler: (NetWsErrorEvent) => void): () => void
const off = client.net.onWsErrorEvent((event) => {
console.log(event.connectionId);
});
// call off() to unsubscribe onStreamBegin(handler: (StreamBegin) => void): () => void
const off = client.net.onStreamBegin((streamBegin) => {
console.log(streamBegin.streamId);
});
// call off() to unsubscribe onStreamChunk(handler: (StreamChunk) => void): () => void
const off = client.net.onStreamChunk((streamChunk) => {
console.log(streamChunk.streamId);
});
// call off() to unsubscribe onStreamEnd(handler: (StreamEnd) => void): () => void
const off = client.net.onStreamEnd((streamEnd) => {
console.log(streamEnd.streamId);
});
// call off() to unsubscribe onStreamError(handler: (StreamError) => void): () => void
const off = client.net.onStreamError((streamError) => {
console.log(streamError.streamId);
});
// call off() to unsubscribe Types
shapes referenced above, as the SDK types them
type NetWsMessage = {
connectionId: string;
frame: WsFrame;
}; type NetWsClosed = {
connectionId: string;
code: number;
reason: string;
}; type NetWsErrorEvent = {
connectionId: string;
error: WsError;
}; First event of an open stream. Carries the response status, headers,
and (when known) total payload size so the consumer can preallocate
or display progress. Subsequent StreamChunk and StreamEnd events
for the same stream_id follow.
type StreamBegin = {
streamId: string;
status: number;
headers: HttpHeader[];
totalSize?: number;
}; One body chunk. Chunks arrive in order; offset is the byte
position of bytes[0] within the full body.
type StreamChunk = {
streamId: string;
offset: number;
bytes: number[];
}; Terminates a stream. After End no further chunks for stream_id
are valid and the daemon clears its routing entry.
type StreamEnd = {
streamId: string;
}; Stream failed mid-flight (or before the first byte). Terminal - the
daemon clears its routing entry. The error shape is shared with
fetch since the failure modes are identical.
type StreamError = {
streamId: string;
error: NetError;
}; Payload for net.fetch: a single proxied HTTP request/response
round-trip through the connected companion's network stack.
type NetFetch = {
request: NetFetchRequest;
}; type NetFetchReply = {
response: NetFetchResponse;
}; type NetFetchErrorReply = {
error: NetError;
}; type NetWsOpen = {
connectionId: string;
url: string;
protocols?: string[];
headers?: HttpHeader[];
}; type NetWsOpenReply = {
acceptedProtocol?: string;
}; type NetWsErrorReply = {
error: WsError;
}; type NetWsClose = {
connectionId: string;
code?: number;
reason?: string;
}; type NetWsSend = {
connectionId: string;
frame: WsFrame;
}; type NetStreamOpen = {
streamId: string;
request: NetFetchRequest;
}; type NetStreamCancel = {
streamId: string;
}; type WsFrame =
| { type: 'text'; data: string }
| { type: 'binary'; data: Uint8Array }; type WsError =
| 'connectFailed'
| 'frameTooLarge'
| 'gatewayDisconnected'
| 'protocolError'; One header on an HTTP request or response. Key order is preserved across serialize/deserialize.
type HttpHeader = {
name: string;
value: string;
}; type NetError = 'requestFailed' | 'timeout' | 'unavailable' | 'noGateway'; type NetFetchRequest = {
url: string;
method: HttpMethod;
headers: HttpHeader[];
body?: number[];
timeoutMs?: number;
redirect: RedirectPolicy;
}; type NetFetchResponse = {
status: number;
headers: HttpHeader[];
body: number[];
}; type HttpMethod =
| 'get'
| 'head'
| 'post'
| 'put'
| 'patch'
| 'delete'
| 'options'; type RedirectPolicy =
| 'follow' // Follow up to a gateway-defined cap (typically 5).
| 'manual' // Surface the redirect status to the caller; do not follow.
| 'error' // Treat any 3xx as an error.;