Client
Client
The client is the typed surface every app, automation, and remote uses to read, write, and invoke. It is imported from $bolt/client and generated by bolt sync, so every call is type-checked against your collections.
One client, one surface per concern
The client exposes everything your workspace can do:
| Surface | Use it for |
|---|---|
client.db | reads — live findMany/findFirst prefixes and one-shot count/findGrouped/findNearest |
client.collection | writes — the declared create/createMany/update/updateMany/delete/deleteMany, each returning an optimistic row and a settlement handle that reports accepted, rebased, rejected, or quarantined |
client.collection_history | history — every revision of one record, or the record at a chosen revision, instant, or before an approval request |
client.approvals | approval decisions — process a request (APPROVED, REJECTED, REQUEST_FOR_CHANGE, SUPERSEDED) or withdraw it |
client.records | public system collections — records.findMany(collectionName, query) for tables outside the typed tenant registry |
client.collections | the read-only catalog — each collection’s declared fields and relationships, for building generic surfaces |
client.invoke | remote functions — typed query and command handlers discovered from src/functions/ |
client.automations | — start a declared automation in the background and watch its durable run |
client.device | device — location, share, copy, haptics, and online state, each answering a value or a typed DeviceRefusal instead of throwing |
The client in action
The same client powers every app — reads, writes, and invokes all flow through it:
import { client } from '$bolt/client';
import { Effect } from 'effect';
// Live read — registered with the server; its current answer is held in memory
// and commits that change the answer arrive as SSE apply frames
const sites = client.db.sites.findMany({
where: { status: { eq: 'active' } },
orderBy: { name: 'asc' },
limit: 25
});
// Collection write — queued in this tab's memory and pushed to the authority;
// the server allocates the id
const write = await client.collection.site_visits.create({
site_id: siteId,
visited_at: new Date()
});
write.row; // optimistic row projected immediately
await write.settlement.settled; // accepted, rebased, rejected, or quarantined
// History — every revision of one record, one-shot, never live.
// A create's authoritative id arrives with the live read; the optimistic row carries none.
const revisions = await client.collection_history.site_visits.revisions(visitId);
// Remote function — typed query or command handler
const forecast = await client.invoke.holiday_feed({ year: 2026 });
// Device — the platform seam for location, share, copy, and haptics;
// every call answers a value or a typed DeviceRefusal, never throws
const fix = await Effect.runPromise(client.device.location({ highAccuracy: true })); Live data
Reads are live queries registered and answered by the server; browser writes use each collection’s declared operations under client.collection.<name>, which return an optimistic result with memory durability and a settlement handle. Reads and writes are separate surfaces: client.db never writes.
AI
Model access flows through the ai facility — the host binds the provider, and tenant code never sees credentials.
Boundaries
- The client never talks to server-side cache APIs.
- Apps cannot reach private runtime facilities.
- The generated client is the only sanctioned data path into a workspace.