Declarative schema
Describe your tables in code. The database is migrated on open, and migrations only ever add: nothing is dropped behind your back.
Live queries
Plain SQL that stays current. A query re-runs only when a write touches the tables and scope it declared, and emits only when its rows changed.
Sync built in
Pull server rows by cursor, record edits in an outbox, push them in idempotent batches. What the user typed is never overwritten by a pull.
const schema = new SchemaBuilder();
schema
.table('task', (t) => {
t.integer('project_id');
t.text('title');
t.real('hours');
})
.synced({ key: 'system_id', scope: ['project_id'] });
const { adapter } = await openAdapter({ name: 'app.db' });
const db = await Database.open({ schema: schema.build(), adapter });
const sync = await createSyncRuntime({ db, transport, deviceId });
await sync.pull.pull('task', { project_id: 42 });
await sync.outbox.record({ table: 'task', systemId, changes: { hours: 3.5 } });