Robutler

host.documents

host.documents saves an app's state as a user-owned document: a top-level, shareable item in the user's library with version history. It is the surface behind "Save to my files" and "Open a file". Where host.content stores raw bytes scoped to one app instance, a document is a first-class, named, versioned artifact the user owns and can reopen, share, and roll back.

For a collab-enabled app, save also seeds the document's <id>:MAIN Yjs room so collaborators load the same starting state. See host.collab for how a room is then joined live.

API

interface DocumentsNamespace {
  save(opts: DocumentsSaveOpts): Promise<{ id: string }>;
  revisions(docId: string): Promise<DocumentRevision[]>;
  getRevision(docId: string, version: number): Promise<{ version: number; snapshot: string; createdAt: string }>;
  restore(docId: string, version: number): Promise<{ version: number }>;
  info(docId: string): Promise<{ isDocument: boolean; name?: string; mime?: string; owned?: boolean }>;
}

interface DocumentsSaveOpts {
  snapshot: string;       // JSON snapshot: the document body for previews / non-collab readers
  yjsState: string;       // base64 Yjs state: seeds the <id>:MAIN collab room
  yjsStateVector: string; // base64 Yjs state vector
  mime: string;           // document format mime, e.g. application/vnd.robutler.board+json
  name?: string;          // display name
  docId?: string;         // when set, CHECKPOINT this existing owned document instead of creating a new one
}

interface DocumentRevision {
  version: number;
  size: number;
  command: string | null;
  createdAt: string;
}
MethodReturnsWhat it does
save(opts){ id }No docId: create a new document. With docId: checkpoint an existing owned one.
revisions(docId)DocumentRevision[]List version-history checkpoints, newest first.
getRevision(docId, version){ version, snapshot, createdAt }Fetch one revision's snapshot body.
restore(docId, version){ version }Restore to a past revision (records a restore checkpoint).
info(docId){ isDocument, name?, mime?, owned? }Whether the caller opened a document, plus its name and owned flag.

Save and checkpoint

save without a docId creates a new top-level document and returns its content id. save with a docId checkpoints that existing owned document, appending a version to its history. Both take a JSON snapshot (the preview body, read by non-collab viewers) and the base64 Yjs state that seeds the collab room.

await host.ready();

// Create on first save.
let { id: docId } = await host.documents.save({
  name: 'Untitled board',
  mime: 'application/vnd.robutler.board+json',
  snapshot: JSON.stringify(boardSnapshot()),
  yjsState: encodeBase64(Y.encodeStateAsUpdate(ydoc)),
  yjsStateVector: encodeBase64(Y.encodeStateVector(ydoc)),
});

// Later: checkpoint the same document. Debounce this; do not call per edit.
await host.documents.save({
  docId,
  mime: 'application/vnd.robutler.board+json',
  snapshot: JSON.stringify(boardSnapshot()),
  yjsState: encodeBase64(Y.encodeStateAsUpdate(ydoc)),
  yjsStateVector: encodeBase64(Y.encodeStateVector(ydoc)),
});

Checkpoint on a debounced timer (for example every few seconds of idle, or on explicit Save), not on every keystroke. Live collaboration flows through the host.collab room; the document is the durable, versioned record.

Version history

const history = await host.documents.revisions(docId);
// → [{ version: 7, size, command, createdAt }, { version: 6, ... }]

const past = await host.documents.getRevision(docId, 3);
preview(JSON.parse(past.snapshot));

await host.documents.restore(docId, 3); // restores; records a new checkpoint

DocumentRevision.command records the command that produced the checkpoint when one drove the edit (see agent command interface), or null for a plain save.

Open detection

When an app mounts on a content row, use info to tell whether it was opened as a real saved document (and whether the viewer owns it) versus a fresh scratch instance:

const meta = await host.documents.info(host.workspace.itemId ?? '');
if (meta.isDocument) {
  setTitle(meta.name);
  showOwnerControls(meta.owned === true);
}

Relationship to other namespaces

  • host.content stores instance-scoped bytes. host.documents stores user-owned, versioned, shareable documents.
  • host.collab joins the live Yjs room a saved document seeds (<id>:MAIN). A collab-enabled app saves once with host.documents, then every collaborator co-edits the room.
  • The mime you choose is your document's format identity, surfaced when the user reopens the file.

On this page