PRODUCTS

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
2const db = await PrefsDB.getkey("my-app", words);
3 
4// localStorage-like setValue
5await db.setValue("theme", "dark");
6 
7// theme == 'dark' on any device
8const value = await db.getValue("theme");
1// mint a key from a phrase only your user knows
2const db = await PrefsDB.getkey("my-app", words);
3 
4// plain values are stored as text
5await db.key("theme").write("dark");
6 
7// objects are stored as JSON, and read back as objects
8await db.key("settings").write({ volume: 80, muted: false });
1const db = await PrefsDB.getkey("my-app", words);
2 
3const res = await db.key("theme").read();
4console.log(res.value); // "dark"
5 
6// no matching row: count is 0, not an error
7const miss = await db.key("nope").read();
8console.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
1const db = await PrefsDB.getkey("my-app", words);
2 
3// lists are append-only -- duplicates are fine
4await db.list("todos").add("buy milk");
5await db.list("todos").add("walk the dog");
1const db = await PrefsDB.getkey("my-app", words);
2 
3const res = await db.list("todos").readAll();
4// res.values: [{ "": "walk the dog", ... },
5// { "": "buy milk", ... }]
6 
7// remove just the matching entry
8await 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 time
  • readAll() returns every entry, no scope fields required
  • delete() with no key removes the whole map
1const db = await PrefsDB.getkey("my-app", words);
2 
3// put() overwrites an existing entry in the map
4await db.map("inventory").put("apples", 12);
5await db.map("inventory").put("pears", 5);
6await db.map("inventory").put("apples", 8); // now 8, not 12
7 
8const apples = await db.map("inventory").get("apples");
9console.log(apples.value); // 8
10 
11const all = await db.map("inventory").readAll();
12// all.values: [{ pears: 5, ... }, { apples: 8, ... }]
13 
14await 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 SQL LIKE
  • Works on lists, maps, and plain keys alike
  • Matched against the stored value, not the key name
1const db = await PrefsDB.getkey("my-app", words);
2 
3// .match() is a SQL LIKE pattern against the stored value
4const res = await db.list("todos").match("%milk%").read();
5console.log(res.values); // only entries containing "milk"
6 
7// works on delete() too -- clears just the matches
8await 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
1const db = await PrefsDB.getkey("my-app", words);
2 
3// resolves immediately, before the server confirms
4const res = await db.key("likes").write(count + 1, { optimistic: true });
5console.log(res.optimistic); // true
6 
7// a read while it's in flight sees the local value
8const r = await db.key("likes").read();
9console.log(r.value, r.pending); // count + 1, true
1// subscribe once, globally -- not per call
2PrefsDB.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});