Live data
Live data
A read has two modes, chosen by name: await q reads once, and bolt.live(q) stays live for as long as something renders it. The host keeps each live view’s current answer and streams the changes each commit makes to it, so a page never polls and never refetches after its own writes.
Live reads
<script lang="ts">
// src/data/collection/projects/+representation.svelte (templates/construction, excerpt)
import { bolt, live } from '$bolt';
import type { RecordView } from '@norbital-ai/ui';
let { view }: { view: RecordView<'projects'> } = $props();
const record = $derived(view.mode !== 'create' ? view.record : null);
const sites = live(
() =>
record === null ? null :
bolt.live(bolt.read('site_locations', {
where: { project_id: { eq: record.id } },
select: { location_name: true, location_code: true, location_type: true },
orderBy: { location_name: 'asc' },
all: true
}))
);
</script> bolt.live(q) subscribes to the query. A subscription lasts while a reader renders it, with a 30 s grace after the last one. A query that mentions now or today has to say how often to re-evaluate with every.
Reading once
// src/kiosk/attendance/+clock.page.svelte (templates/hr-payroll, excerpt): an event's one-shot read
import { Effect } from 'effect';
import { bolt, fork } from '$bolt';
function loadHolders() {
fork(bolt.read('employment_profile', {
where: { face_enrollment_status: { eq: 'APPROVED' } },
select: { name: true, face_embedding: true },
all: true
}).pipe(Effect.tap((answer) => Effect.sync(() => { holders = [...answer.rows]; }))),
(error) => { message = error.message; });
} A cursor page and a similarity search are read once. Use await for a value a page needs at start or after a click, and a live read for anything on screen that other people can change.
Optimistic writes
A create, update or delete through bolt.act — and every Form save, Table edit and Board move — paints its change at once over the live reads it touches, and settles on the outcome: committed replaces the paint with the committed rows, pendingApproval keeps the rows as held, and refused or conflict rolls the paint back and returns the message. Actions and queries do not paint.
An update carries the revision of the row the page last read; if the row has moved since, the answer is conflict. Writes in flight are ordered only by await.
Read your writes
When act resolves, the page’s live views already include the write: the reply carries the commit’s sequence, and the client waits (at most 5 s, while the stream is open) until its stream has applied it.
What a live read sees
A live view is evaluated under the viewer’s current grants and field masks. When the viewer’s authority changes, affected views are answered again; when the release changes, the stream closes and the page picks up the new release. The Sync engine guide explains how the host routes each commit.