Skip to content

Data-source writes and reconciliation

View as Markdown

WriteCapability is implemented by the source and consumed by the runtime:

type WriteCapability = {
setCell(rowKey: RowKey, colId: ColId, value: unknown): void;
applyChanges(changes: readonly CellChange[]): void;
createNode(node: TreeNode, atIndex?: number): Promise<CreateNodeResult>;
removeNode(rowKey: RowKey): void | Promise<void>;
onReconcile(listener: (event: ReconcileEvent) => void): () => void;
canAppendRow?: () => boolean;
};

Application code writes through the level runtime:

const level = runtime.root;
const rowId = makeRowId(level.path, "project-1");
level.writeCell({ rowId, colId: "status" }, "done");
level.applyChanges([{ rowKey: "project-1", colId: "status", value: "done" }]);
await level.createRow({
rowKey: "project-2",
levelName: level.schema.name,
columns: { name: "Migration" },
});
await level.removeRow("project-2");

These commands validate the current level registration, require a writable source, and emit runtime mutation events.

type ReconcileEvent =
| { kind: "agreed"; rowKey: RowKey; colId: ColId; value: unknown }
| {
kind: "diverged";
rowKey: RowKey;
colId: ColId;
optimisticValue: unknown;
authoritativeValue: unknown;
priorValue: unknown;
}
| {
kind: "rejected";
rowKey: RowKey;
colId: ColId;
optimisticValue: unknown;
reason: string;
priorValue: unknown;
};
const unsubscribe = runtime.root.data.onReconcile((event) => {
if (event.kind === "rejected") showSaveError(event.reason);
});