@remelondb/core
v0.3.1
Published
remelonDB core: reactive offline-first database over a pluggable SQLite driver — queries as data, schema/migrations, observation, sync engine
Maintainers
Readme
@remelondb/core
The platform-independent whole of remelonDB: an offline-first data layer with multi-device sync — reactive SQLite, typed schemas inferred from one definition, and a model-checked sync protocol — rebuilt from WatermelonDB's best ideas on one engine: SQLite everywhere.
This package contains everything except the platform driver: the Q query
DSL and its SQL compiler, schema and migrations, the Database/Collection/
Model layer, reactive observation, and the sync engine. It talks to SQLite
through a ~7-method SqliteDriver interface; pick the driver for your
platform:
| Platform | Driver package |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Node | @remelondb/driver-node (better-sqlite3) |
| Browser | @remelondb/driver-web (SQLite-WASM + OPFS in a Worker) |
| React Native with Expo SQLite | @remelondb/driver-rn (expo-sqlite adapter) |
| React Native with bundled SQLite | @remelondb/driver-rn-cpp (C++ TurboModule; native build required) |
Because every driver is real SQLite and passes the same
conformance suite (@remelondb/core/conformance),
code written against core behaves identically on all of them.
Companions: the @remelondb/core/zod subpath
derives tables and sync wire validators from shared Zod schemas;
@remelondb/server
implements the sync backend over a storage seam, proven by
its @remelondb/server/conformance suite.
Example
import {
appSchema,
column as c,
table,
Database,
ModelFor,
Q,
synchronize,
} from '@remelondb/core';
import { NodeSqliteDriver } from '@remelondb/driver-node';
const tasks = table('tasks', {
name: c.string(),
position: c.number().indexed(),
is_done: c.boolean(),
});
const schema = appSchema({ version: 1, tables: [tasks] });
class Task extends ModelFor(tasks) {
// no field declarations: name/position/is_done are typed from the
// table definition; accessors are schema-generated
}
const db = await Database.open({
driver: new NodeSqliteDriver(),
schema,
modelClasses: [Task],
name: 'app.db',
});
const task = await db.write(() =>
db.get(Task).create({ name: 'try it', position: 1 }),
);
await db.write(() =>
task.update(() => {
task.is_done = true;
}),
);
const unsubscribe = db
.get(Task)
.query(Q.where('is_done', false), Q.sortBy('position'))
.observe((open) => console.log('open tasks:', open.length));
await synchronize({ database: db, pullChanges, pushChanges }); // your backendApp bootstraps should wrap this in createDatabaseManager (see the
root README): shared init, retryable failure, takeover handling, and a
React hook via @remelondb/core/react.
Nothing schedules that call: the library has no timer and holds no
connection. Sync on app start, on foreground, on online, and after
local writes — see
when to sync.
Documentation
- Tutorial: a flashcard app's data layer, end to end
- Reference: database & observation · models · queries · sync · when to sync · schema & migrations · records · the driver contract
- Design: layers · queries as data, one engine · sync protocol
License and credits
MIT. The design owes its best ideas (queries as data, reactive observation, the offline-first sync protocol) to WatermelonDB by Nozbe and contributors (MIT); the code is written from scratch.
