index ↓

doc

client.doc

Daemon -> webapp doc replies and events. Changed broadcasts whenever the companion writes or deletes a doc value for the active webapp.

requests

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

get(DocGet): Promise<TypedRequestResult<DocGetReply, never>>

push form: onGet (subscribe instead of awaiting)

Webapp request: read one doc value for the currently active webapp.

const res = await client.doc.get({ key: '...' });
if (res.ok) {
  console.log(res.response.key);
}

list(): Promise<TypedRequestResult<DocListReply, never>>

push form: onList (subscribe instead of awaiting)

Marker request: read every doc entry for the currently active webapp.

const res = await client.doc.list();
if (res.ok) {
  console.log(res.response.entries);
}

set(DocSet): Promise<TypedRequestResult<DocAck, WebappError>>

push form: onAck (subscribe instead of awaiting)

Webapp request: write a doc value. Last write wins against companion writes on the same key; the companion hears the change as a gateway webapp.docChanged event.

const res = await client.doc.set({ key: '...', value: '...' });
if (res.ok) {
  console.log(res.response.key);
} else {
  console.warn(res.kind, res.error);
}

delete(DocDelete): Promise<TypedRequestResult<DocAck, never>>

push form: onAck (subscribe instead of awaiting)

Webapp request: delete the doc entry at key.

const res = await client.doc.delete({ key: '...' });
if (res.ok) {
  console.log(res.response.key);
}

events

the daemon pushes these unprompted. subscribing returns an unsubscribe function

onChanged(handler: (DocChanged) => void): () => void

const off = client.doc.onChanged((docChanged) => {
  console.log(docChanged.key);
});
// call off() to unsubscribe

types

shapes referenced above, as the sdk types them

Broadcast when the COMPANION writes the active webapp's doc namespace. Webapp-origin writes are not echoed back (the writer already holds the ack).

type DocChanged = {
  key: string;
  value?: string; // `None` means the entry was deleted.
};

Webapp request: read one doc value for the currently active webapp.

type DocGet = {
  key: string;
};

Reply to DocGet.

type DocGetReply = {
  key: string;
  value?: string; // `None` when the key has never been written.
};

Reply to DocList.

type DocListReply = {
  entries: DocEntry[];
};

Webapp request: write a doc value. Last write wins against companion writes on the same key; the companion hears the change as a gateway webapp.docChanged event.

type DocSet = {
  key: string;
  value: string;
};

Ack for DocSet / DocDelete; echoes what's now stored.

type DocAck = {
  key: string;
  value?: string;
};

Domain errors emitted by any webapp surface (gateway- or client-side). Single catalog: both protocols speak the same variant set.

type WebappError =
  | 'webappNotFound' // No installed webapp matches this id (uninstall / activate / icon / config target).
  | 'cannotUninstallBuiltin' // Built-in webapps cannot be uninstalled.
  | 'idReserved' // Install rejected: the manifest's id is in the reserved-uuid set (stock, hub, launcher, etc).
  | 'extractedTooLarge' // Extracted bundle exceeds the 1 GiB disk-protection cap.
  | 'provenanceTooLong' // Install carried a provenance string over `WEBAPP_PROVENANCE_MAX_LEN`.
  | 'zipMalformed' // Zip extraction failed: corrupt archive, unsafe entry names, etc.
  | 'missingIndexHtml' // Bundle has no index.html at its root.
  | 'invalidManifest' // manifest.json missing, unparseable, or failed schema validation.
  | 'resourceNotAvailable' // The requested resource (icon / settings page / overlay) isn't declared by the webapp's manifest or its file is missing on disk.
  | 'notALauncher' // Launcher slot rejected: the bundle does not declare `role: launcher`.
  | 'noOverlay' // Overlay slot rejected: the bundle declares no overlay entry.
  | 'unknownConfigKey' // Config key is not declared in the webapp's manifest schema.
  | 'invalidConfigValue' // Value failed schema validation (out of range, regex mismatch, not in enum).
  | 'invalidDocValue' // Doc value rejected (oversized).
  | 'internal' // Catch-all for genuinely-unexpected failures (io errors, daemon-side bugs). Reason is human-readable; not a stable wire contract.;

Webapp request: delete the doc entry at key.

type DocDelete = {
  key: string;
};

One key/value pair from a webapp's doc namespace: shared structured state writable from both the companion (gateway) and the webapp itself, last write wins. Values are strings; apps encode JSON as needed.

type DocEntry = {
  key: string;
  value: string;
};