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. true means success; response holds the reply.
  • response: the typed reply payload (the Response in the method's signature). only present when ok.
  • 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 when kind is 'domain', a WireError when '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>

asset 4 methods
client.asset

Daemon-side asset events.

audio 12 methods
client.audio

Daemon -> webapp audio events: TTS lifecycle notifications and volume/mute changes.

bluetooth 11 methods
client.bluetooth

Daemon -> webapp bluetooth surface: connection status/events, in-flight pairing feedback, and the reply to bluetooth.list.

capabilities 2 methods
client.capabilities

Daemon -> webapp capabilities surface.

config 3 methods
client.config

Daemon -> webapp config replies and events.

doc 5 methods
client.doc

Daemon -> webapp doc replies and events.

forward 3 methods
client.forward
geo 4 methods
client.geo

Daemon -> webapp location surface: the Position stream a watch produces, plus replies to geo.watch and geo.getOnce.

hardware 5 methods
client.hardware

Daemon -> webapp hardware surface: ambient-light and backlight change events, plus the reply to hardware.stateGet.

library 10 methods
client.library

Daemon -> webapp replies and events for the library surface.

lyrics 1 methods
client.lyrics
net 13 methods
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.

notifications 5 methods
client.notifications

Daemon -> webapp notification mirror.

peer 1 methods
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.

phone 17 methods
client.phone

Daemon -> webapp telephony surface.

player 20 methods
client.player

Daemon -> webapp player surface.

store 3 methods
client.store
system 14 methods
client.system

Daemon -> webapp system events and replies.

time 2 methods
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.

voice 7 methods
client.voice

Daemon -> webapp voice/NLU surface: mic state-change events, resolved display intents, and the reply to voice.stateGet.

webapp 7 methods
client.webapp

Daemon -> webapp replies and events for the webapp-management surface.