Runtime API
Everything an application is given, and nothing else. Each call is checked against the runtime that defines it by tests/rules.spec.ts.
Every application
await window.dai.openDatabase()— Opens the database inside this file. In a shared document it waits for the host's write rules first.db.exec(sql)— Runs one or more statements.db.exec({ sql, bind })— Runs a statement with bound parameters. Omit bind when there are none: an empty array throws.db.selectObjects(sql, bind?)— Returns rows as plain objects. bind is an array for ? or an object for :name.db.selectValue(sql, bind?)— The first column of the first row — a count, a setting, a total.window.dai.autosaves— True under a host: every write is saved as it happens, and nothing needs pressing.await window.dai.saveDatabase(db)— Saves now. Needed only where there is no host (a file opened straight in a browser). Returns { saved, method }.window.dai.exportDatabase(db)— The database as bytes, without saving.window.dai.documentUuid— This document's identity.window.dai.signature— "valid", "unsigned" or "invalid" for this container.window.dai.onAppModeChange(fn)— Called when the container enters or leaves full-screen App Mode.window.dai.requestShare(session?)— Opens the host's own share sheet — the same one behind its menu. Does not share anything itself: the person still sees the card, still chooses whether to include their data, and still presses Send. In a session document, pass the session id to make it an invite into that one session: the copy that travels holds only that session's rows, and none of the other sessions or of this copy's local tables. Without one, the whole document is offered.window.daiKit.refresh()— Re-runs every kit query on the page. Call it in the dai:merged listener when the page uses <dai-rows> or <dai-value>.
Shared tables (passable and session)
await window.dai.openDatabase()— Opens the database inside this file. In a shared document it waits for the host's write rules first.db.exec(sql)— Runs one or more statements.db.exec({ sql, bind })— Runs a statement with bound parameters. Omit bind when there are none: an empty array throws.db.selectObjects(sql, bind?)— Returns rows as plain objects. bind is an array for ? or an object for :name.db.selectValue(sql, bind?)— The first column of the first row — a count, a setting, a total.window.dai.autosaves— True under a host: every write is saved as it happens, and nothing needs pressing.await window.dai.saveDatabase(db)— Saves now. Needed only where there is no host (a file opened straight in a browser). Returns { saved, method }.window.dai.exportDatabase(db)— The database as bytes, without saving.window.dai.documentUuid— This document's identity.window.dai.signature— "valid", "unsigned" or "invalid" for this container.window.dai.onAppModeChange(fn)— Called when the container enters or leaves full-screen App Mode.window.dai.requestShare(session?)— Opens the host's own share sheet — the same one behind its menu. Does not share anything itself: the person still sees the card, still chooses whether to include their data, and still presses Send. In a session document, pass the session id to make it an invite into that one session: the copy that travels holds only that session's rows, and none of the other sessions or of this copy's local tables. Without one, the whole document is offered.window.dai.replicated.insert(table, values, session?)— Creates a shared row and returns its entity (32 hex characters). values is an object of your own columns. In a session document, session (hex) is required.window.dai.replicated.change(table, entity, values)— Writes a new version of a shared row, naming every current version as its parent — which is also how a conflict is resolved. values carries every one of your columns. Returns the entity.window.dai.replicated.remove(table, entity)— Deletes a shared row by writing a tombstone. The row leaves t_current. Returns the entity.window.addEventListener("dai:merged", fn)— Fired when another copy's rows arrive. event.detail: { applied, duplicate, rejected, newReplicas, conflicts, via } — via is "carrier" (a file or link was opened) or "mailbox" (rows arrived in the background).window.daiKit.refresh()— Re-runs every kit query on the page. Call it in the dai:merged listener when the page uses <dai-rows> or <dai-value>.
Sessions
window.dai.replicated.session.create()— Starts a session: seats this copy and leaves one open seat. Returns { session, seat } as hex.window.dai.replicated.session.join(session, seat)— Binds this copy to an open seat. Call it when this copy opens an invite (SESSION-JOIN-ON-OPEN).window.dai.replicated.session.close(session)— Closes a session at what this copy has seen. Throws CLOSE_NOT_PERMITTED for a non-creator under close=creator.window.dai.replicated.session.reseat(session)— The creator's repair for a contested seat: replaces the open seat so a fresh invite can be taken. Throws NOT_SEAT_CREATOR for anyone else and CANNOT_RESEAT when no seat is contested.
Custom properties
The host sets these on the application's root so it can paint to the edge of a phone's screen and keep content clear of what covers it (EDGE-TO-EDGE). Zero on a screen with nothing in the way.
--dai-safe-top— How much of the top edge a status bar covers.--dai-safe-right— How much of the right edge is covered.--dai-safe-bottom— How much of the bottom edge a home indicator covers.--dai-safe-left— How much of the left edge is covered.