index ↓
webapp sdk
a bridgething webapp is a single-page ui. it runs full-screen in the car thing's chromium kiosk. it reaches the on-device daemon through one typed client, @bridgething/client. this reference is generated from the daemon's wire types.
d1 - start a project
scaffold a webapp. react, vite, tailwind, and this client come preinstalled.
bun create bridgething my-app source and issues on github.
d2 - settings pages
apps can ship a companion-side settings ui. it is one self-contained html page rendered in the phone app, with its own tiny bridge sdk for config and shared state. see settings pages, including the network caveat.
d3 - connect
construct the client once and reuse it. the daemon is the sole peer. you never open sockets or address anything (unless you are using the web proxy feature).
import { BridgethingClient } from '@bridgething/client';
const client = new BridgethingClient(); // auto-connects, auto-reconnects d4 - the three call shapes
every surface method is one of three shapes. learn these and the whole sdk reads the same way.
events
the daemon pushes, you subscribe. onXxx returns an unsubscribe function.
const off = client.player.onSnapshot(r => render(r.state));
off(); // stop listening requests
you ask, the daemon answers. returns a tagged result.
const res = await client.player.stateGet();
if (res.ok) render(res.response.state); commands
fire-and-forget. resolves once the daemon has taken the message.
await client.player.skipNext(); d5 - request results
a request never returns its payload directly and never throws. it resolves to a tagged result. narrow it on
ok. this is the TypedRequestResult<Response, Error> in every request's signature:
type TypedRequestResult<Response, Error> =
| { ok: true; response: Response }
| { ok: false; kind: 'domain'; error: Error }
| { ok: false; kind: 'protocol'; error: WireError }; -
ok: the discriminant.truemeans success;responseholds the reply. -
response: the typed reply payload (theResponsein the method's signature). only present whenok. -
kind: on failure,'domain'(an expected, operation-specific failure, e.g. an asset that isn't found) or'protocol'(the request could not be reached or dispatched). -
error: the failure detail. your operation's error type whenkindis'domain', aWireErrorwhen'protocol'.
every request also accepts an optional second argument { timeoutMs }.
the 'protocol' failure carries a WireError: the request was malformed, unsupported, or
the handler threw.
type WireError =
| { type: 'unsupported' }
| { type: 'unimplemented' }
| { type: 'malformed'; data: { reason: string } }
| { type: 'handlerFailed'; data: { reason: string } }; d6 - surfaces
21 surfaces on client.<name>
client.asset Daemon-side asset events.
client.audio Daemon -> webapp audio events: TTS lifecycle notifications and volume/mute changes.
client.bluetooth Daemon -> webapp bluetooth surface: connection status/events, in-flight pairing feedback, and the reply to bluetooth.list.
client.capabilities Daemon -> webapp capabilities surface.
client.config Daemon -> webapp config replies and events.
client.doc Daemon -> webapp doc replies and events.
client.forward client.geo Daemon -> webapp location surface: the Position stream a watch produces, plus replies to geo.watch and geo.getOnce.
client.hardware Daemon -> webapp hardware surface: ambient-light and backlight change events, plus the reply to hardware.stateGet.
client.library Daemon -> webapp replies and events for the library surface.
client.lyrics 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.
client.notifications Daemon -> webapp notification mirror.
client.peer Daemon -> webapp peer surface: a full snapshot of every known peer (paired, iAP2, and companion-gateway state), re-sent whenever any peer changes.
client.phone Daemon -> webapp telephony surface.
client.player Daemon -> webapp player surface.
client.store client.system Daemon -> webapp system events and replies.
client.time Daemon -> webapp wall-clock surface: an initial snapshot at announce, Changed events on tz/locale/clock updates, and the reply to time.get.
client.voice Daemon -> webapp voice/NLU surface: mic state-change events, resolved display intents, and the reply to voice.stateGet.
client.webapp Daemon -> webapp replies and events for the webapp-management surface.