Database
Key/value pairs, lists, and maps easy to use like local storage but persist across devices and browsers — with no backend to run, no user accounts to manage, and no localStorage-sized limitations.
- No schema to define up front
- A miss is just
count: 0, not an error - Scope with
domain()/subdomain()/project()when one key name isn't enough
| 1 | // mint a key from a phrase only your user knows |
| 2 | const db = await PrefsDB.getkey("my-app", words); |
| 3 | |
| 4 | // localStorage-like setValue |
| 5 | await db.setValue("theme", "dark"); |
| 6 | |
| 7 | // theme == 'dark' on any device |
| 8 | const value = await db.getValue("theme"); |
| 1 | // mint a key from a phrase only your user knows |
| 2 | const db = await PrefsDB.getkey("my-app", words); |
| 3 | |
| 4 | // plain values are stored as text |
| 5 | await db.key("theme").write("dark"); |
| 6 | |
| 7 | // objects are stored as JSON, and read back as objects |
| 8 | await db.key("settings").write({ volume: 80, muted: false }); |
| 1 | const db = await PrefsDB.getkey("my-app", words); |
| 2 | |
| 3 | const res = await db.key("theme").read(); |
| 4 | console.log(res.value); // "dark" |
| 5 | |
| 6 | // no matching row: count is 0, not an error |
| 7 | const miss = await db.key("nope").read(); |
| 8 | console.log(miss.count); // 0 |
Lists
An append-only collection: duplicate values are fine, and every add() creates a new row instead of overwriting one. Good for logs, timelines, and to-do items.
- Newest entries first on
readAll() - Nest lists under
domain()/project()like any other key - Combine with
.match()to delete just the matching entries
| 1 | const db = await PrefsDB.getkey("my-app", words); |
| 2 | |
| 3 | // lists are append-only -- duplicates are fine |
| 4 | await db.list("todos").add("buy milk"); |
| 5 | await db.list("todos").add("walk the dog"); |
| 1 | const db = await PrefsDB.getkey("my-app", words); |
| 2 | |
| 3 | const res = await db.list("todos").readAll(); |
| 4 | // res.values: [{ "": "walk the dog", ... }, |
| 5 | // { "": "buy milk", ... }] |
| 6 | |
| 7 | // remove just the matching entry |
| 8 | await db.list("todos").match("buy milk").delete(); |
Maps
A named key/value collection: unlike a list, put() overwrites an existing entry instead of appending a duplicate. Good for anything shaped like a record -- an inventory, a settings bag, per-item counters.
put()/get()/remove()address one entry at a timereadAll()returns every entry, no scope fields requireddelete()with no key removes the whole map
| 1 | const db = await PrefsDB.getkey("my-app", words); |
| 2 | |
| 3 | // put() overwrites an existing entry in the map |
| 4 | await db.map("inventory").put("apples", 12); |
| 5 | await db.map("inventory").put("pears", 5); |
| 6 | await db.map("inventory").put("apples", 8); // now 8, not 12 |
| 7 | |
| 8 | const apples = await db.map("inventory").get("apples"); |
| 9 | console.log(apples.value); // 8 |
| 10 | |
| 11 | const all = await db.map("inventory").readAll(); |
| 12 | // all.values: [{ pears: 5, ... }, { apples: 8, ... }] |
| 13 | |
| 14 | await db.map("inventory").remove("apples"); // just that entry |
Filtering with .match()
Narrow a read() -- or a delete() -- to rows whose stored value matches a SQL LIKE pattern, without pulling everything back to filter client-side.
%/_wildcards, same as SQLLIKE- Works on lists, maps, and plain keys alike
- Matched against the stored value, not the key name
| 1 | const db = await PrefsDB.getkey("my-app", words); |
| 2 | |
| 3 | // .match() is a SQL LIKE pattern against the stored value |
| 4 | const res = await db.list("todos").match("%milk%").read(); |
| 5 | console.log(res.values); // only entries containing "milk" |
| 6 | |
| 7 | // works on delete() too -- clears just the matches |
| 8 | await db.list("todos").match("%milk%").delete(); |
Optimistic updates
Pass { optimistic: true } to apply a write locally and resolve immediately, instead of waiting on the network round trip -- while still finding out whether the server actually agreed.
- A same-key
read()sees the pending value right away - Listen for
onSyncEvent()to catch a rollback - Also works on
write()/add()for a list
| 1 | const db = await PrefsDB.getkey("my-app", words); |
| 2 | |
| 3 | // resolves immediately, before the server confirms |
| 4 | const res = await db.key("likes").write(count + 1, { optimistic: true }); |
| 5 | console.log(res.optimistic); // true |
| 6 | |
| 7 | // a read while it's in flight sees the local value |
| 8 | const r = await db.key("likes").read(); |
| 9 | console.log(r.value, r.pending); // count + 1, true |
| 1 | // subscribe once, globally -- not per call |
| 2 | PrefsDB.onSyncEvent((evt) => { |
| 3 | if (evt.phase === "confirmed") { |
| 4 | // the server agreed -- evt.result is its response |
| 5 | } |
| 6 | if (evt.phase === "optimistic-rollback") { |
| 7 | // it didn't stick -- evt.result says why |
| 8 | } |
| 9 | }); |