How to consume a surface outside SolidJS
The .use() hooks are SolidJS. A CLI or TUI has no reactive runtime, so it reads
the surface directly off the typed client. The trick that keeps a CLI small is to
hold one transport-blind connection so every command is written once,
whether it runs against a local unix socket or a remote box over ssh.
Hold one connection shape
Model the connection as { client, dispose } and dial it once. Local and remote
differ only in which link you build; the commands downstream never branch.
type Connection = {
client: ContractRouterClient<typeof surface.contract>;
dispose: () => void;
};
// local: dial the daemon's unix socket
const { client, dispose } = await unixSocketLink<typeof surface.contract>({
socketPath,
});
Call procedures with a plain await
Procedures are ordinary async calls off the client. No hooks, no subscription.
await client.surface.proc.kill({ pid });
const keys = await firstFrameOrThrow(
await client.surface.processes.keys({}),
"processes keys yielded no snapshot frame — link failure",
);
Iterate a stream
A cell, collection, or stream read is an async iterable — snapshot first, then deltas. Loop it and act on each frame.
for await (const frame of await client.surface.nodeLog.get({ nodeId })) {
process.stdout.write(frame.text);
}
For a raw (non-descriptor) stream, reach for unenrolledStreamCall
(@kolu/surface/client) rather than calling the procedure bare — it carries the
STREAM_RETRY reconnect context, so a dropped transport re-subscribes
transparently instead of ending the loop.
const frames = await unenrolledStreamCall(
client.surface.nodeLog.get,
{ nodeId },
{ signal, onRetry: () => resetView() },
);
for await (const frame of frames) render(frame);
Drive a live board with mirrorRemoteSurface
When the CLI is a live dashboard rather than a one-shot query, fold the surface
into plain callbacks with mirrorRemoteSurface (@kolu/surface/mirror) — the
consume-side dual of implementSurface. You supply a sink of collection and
stream callbacks; it keeps them current and hands back the procedures plus a
done promise.
const { procedures, done } = mirrorRemoteSurface(
surface,
client,
{
collections: {
processes: {
upsert: (pid, proc) => board.set(pid, proc),
remove: (pid) => board.delete(pid),
},
},
streams: { nodeLog: { input: nodeId, onFrame: (f) => board.appendLog(f) } },
},
{ signal },
);
await procedures.proc.kill({ pid }); // same typed procedures, mirrored
await done;