bridgething
Surfaces ↓

Capabilities

client.capabilities

Daemon -> webapp capabilities surface. Update is the broadcast event fired on connect + on every change; Snapshot is the typed reply to CapabilitiesGet. Webapps that auto-react to capability change listen on Update and don't need to call Get.

Requests

you ask, the daemon answers; await the tagged result and check .ok

get(): Promise<TypedRequestResult<CapabilitiesSnapshot, never>>

push form: onSnapshot (subscribe instead of awaiting)

One-shot query: webapp asks the daemon for the current capabilities snapshot. The daemon also broadcasts Update on every connect and on every change, so most webapps don't need this.

const res = await client.capabilities.get();
if (res.ok) {
  console.log(res.response.capabilities);
}

Events

the daemon pushes these unprompted; subscribing returns an unsubscribe function

onUpdate(handler: (CapabilitiesSnapshot) => void): () => void

const off = client.capabilities.onUpdate((snapshot) => {
  console.log(snapshot.capabilities);
});
// call off() to unsubscribe

Types

shapes referenced above, as the SDK types them

Wrapper carrying one Capabilities snapshot; reply to CapabilitiesGet and payload of the Update broadcast event.

type CapabilitiesSnapshot = {
  capabilities: Capabilities;
};

What the daemon advertises to webapps. gateway: None means no companion is connected; webapps that depend on companion-routed surfaces (Library, Net, Notifications, etc.) should branch on this. authority is the live set of scopes the companion currently claims.

type Capabilities = {
  gateway?: GatewayInfo;
  available: SurfaceAvailability;
  authority: CompanionAuthorityScope[];
  uriSchemes: string[];
  network: NetworkInfo;
  audio: AudioCapabilities;
  musicProvider: MusicProvider;
};

Identity payload describing the companion peer the daemon is talking to. Address is the BT MAC the companion advertises; on transports without a stable MAC (the network gateway's 0xfe:fe:... synthetic addrs) it is the synthetic address as a string.

type GatewayInfo = {
  address: string;
  name: string;
  osName: string;
  appName: string;
  appVersion: string;
  adapterVersion: string;
  libVersion: string;
  libbridgethingVersion: string;
};

Bool feature flags the daemon exposes to webapps. Each is true when the surface has both a backing implementation and (where applicable) a connected companion claiming to provide it. False = the surface will respond Unsupported or Unimplemented to verbs.

type SurfaceAvailability = {
  geo: boolean;
  notifications: boolean;
  netFetch: boolean;
  netWs: boolean;
  audioTts: boolean;
  lyrics: boolean;
};

One axis the companion can declare authority over. Each scope has a fallback source the daemon merges with when no claim is active or the claim has gone stale. Unknown scopes arriving at an older daemon are stored opaquely and ignored.

type CompanionAuthorityScope =
  | 'nowPlayingMetadata' // Track metadata: title, album, artist, persistent_id, artwork_id, duration, liked. Excludes playback state. Companion claims when it has rich app-specific data for the currently-playing iOS app; releases when the user switches to a non-tracked app.
  | 'nowPlayingPlayback' // Playback state: position, playing/paused, shuffle, repeat, app_bundle, app_display_name. On iOS, iAP2 is usually the better source (microsecond-fresh playhead). On Android the companion is the only source and always claims this.
  | 'volume' // Host audio output volume + mute. iAP2 has no inbound volume CSM (HID step is one-way only), so without a companion claiming this scope the daemon can't see real volume - it broadcasts a fixed placeholder (0.5, unmuted) so the kiosk doesn't render a muted state, and forwards HID Inc/Dec/Mute presses best-effort.;

What kind of network the companion's host is currently using. metered is the OS-reported metered flag; webapps should treat it as a hint (e.g. defer non-essential fetches) rather than a hard ban.

type NetworkInfo = {
  kind: NetworkKind;
  metered: boolean;
};

What the gateway-side audio backend supports. earcons are short named sounds the companion can play; voices are TTS voices.

type AudioCapabilities = {
  earcons: string[];
  voices: VoiceDescriptor[];
};

Which music service the companion is currently logged into and driving on behalf of the user. None when no glue is attached.

type MusicProvider = 'none' | 'spotify' | 'appleMusic' | 'tidal';
type NetworkKind = 'unknown' | 'wifi' | 'cellular' | 'ethernet';

One TTS voice the companion's audio backend can speak as. id is platform-opaque (Apple/Android voice id); locale is BCP-47.

type VoiceDescriptor = {
  id: string;
  name: string;
  locale: string;
};