Skip to content

Redraw when rows arrive

A shared document changes under the application when the other copy's rows arrive — from a file or link somebody opened, or in the background. The application finds out from one event, and nowhere else.

SHARED-REDRAW-ON-MERGE

Redraw when the other copy's rows arrive

Listen for the dai:merged event on window and redraw everything drawn from shared tables when it fires: window.addEventListener("dai:merged", (event) => { redraw(); }). event.detail carries applied, duplicate, rejected, newReplicas, conflicts and via — "carrier" when a file or link was opened, "mailbox" when rows arrived in the background. If the page uses the kit's reading elements, call window.daiKit.refresh() in the listener. A redraw must never discard what the person is in the middle of — text typed into a field, an editor that is open, a selection: rows arrive whenever the other copy's changes do, including mid-sentence. Keep work in progress outside what the redraw rebuilds — in a form written once in the HTML rather than recreated on every draw, or in a local drafts table the redraw reads back — or leave the element being edited untouched until it is saved or cancelled. The same failure arriving at start-up rather than mid-edit is NO-INPUT-LOST-WHILE-OPENING.

Why. Nothing else tells the application that another copy's rows landed. Without it the application draws once and redraws only after its own writes, so a two-person document looks broken in exactly the case it exists for. And a redraw that rebuilds an open editor from the stored wording throws away what was being typed, silently — found by running a blind candidate over the mailbox, where a background merge landed while a term was being edited.

Applies to passable, session · checked by the lint (shared-no-merge-listener) · SHARED-REDRAW-ON-MERGE in Constraints

Carrier or mailbox

event.detail.via says where the rows came from. "carrier" means a person opened a file or a link — a deliberate act, and in a session document the one moment to take an open seat. "mailbox" means rows arrived in the background, and must never make a copy join anything.

SESSION-JOIN-ON-OPEN

Take the open seat when an invite is opened

When this copy opens an invite, bind its open seat with window.dai.replicated.session.join(session, seat): once at start-up, and again in the dai:merged listener only when event.detail.via === "carrier" — never for "mailbox". Join only if this copy is not already a member and an open seat exists: the open seat is a _dai_seat_current row for the session whose seat no _dai_binding_current row binds. Join the session the invite was sent for. An invite carries only that session and none of the sender's local rows (SESSION-INVITE), so it is a session with an open seat that this copy did not create and is not a member of — in a fresh copy made from an invite there is exactly one. That includes a copy whose seat was contested or replaced: opening the creator's fresh invite is how it gets back in, and excluding copies that were ever seated would lock it out for good. Prefer the item that is showing when it is joinable (a copy that arrived as a whole document carries the sender's local rows, including which item was showing), otherwise take the newest joinable one, and make it the item showing.

Why. Membership comes from opening an invite, not from rows arriving. A copy that joined on every background merge would re-take a seat it had lost, and a copy that joined twice would contest its own seat.

Applies to session · not checked by anything · SESSION-JOIN-ON-OPEN in Constraints

With the kit

The kit's <dai-rows> and <dai-value> redraw after the kit's own writes, not after a merge. Call window.daiKit.refresh() from the listener.

SHARED-KIT-READS

The kit reads shared tables; it does not write them

The kit's write controls — data-run, <dai-form run=…>, <dai-attach run=…> — run plain SQL, so they are for local tables only. On a shared table they fail (SHARED-WRITE-SURFACE), and the kit neither catches the error nor shows it. The kit's reading elements, <dai-rows> and <dai-value>, work over t_current views; redraw them on a merge with window.daiKit.refresh() (SHARED-REDRAW-ON-MERGE). Write shared rows in JavaScript through window.dai.replicated.

Why. Run against the rewrite: a kit INSERT into a replicated table fails with SQLite's NOT NULL error, and an UPDATE or DELETE with REPLICATED_TABLE_IMMUTABLE — uncaught, so the person sees nothing happen.

Applies to passable, session · checked by the lint (shared-raw-write) · SHARED-KIT-READS in Constraints

Released under the MIT License. Dynamic Application Interface standard.