Data
tinylib.data saves the user's data for your app as keys with JSON values. Every call is synchronous and works offline, and Tinylib syncs the data across the user's devices.
A set or remove changes the device's copy at once, and Tinylib sends the write to its servers moments later. Offline, the write waits on the device until there's a connection. Nothing tells your client when a write has reached the servers.
When two devices change the same key, the write that reaches Tinylib's servers last wins, whenever it was made. A remove is a write like any other. If the user ticks off a to-do on their phone while offline, then removes it on their laptop, the to-do comes back when the phone reconnects. The device whose write lost gets the winning value, and onChange tells its client.
In npx tinylib-sdk dev, choose the same user at the top of both panes to watch a change reach another device. To make a conflict, turn one pane's Online switch off, change the same key in both panes, then turn it back on.
A guest, a user without a Tinylib account, has data like anyone, and it reaches no other device until they sign in.
A value is private to the user unless it's saved with audience: 'friends'. A later save without audience keeps the value's audience, and a save with audience: 'me' makes it private again.
For data that several people change together, like a shopping list a couple shares, use a room.
The user can delete their data in your app from Tinylib. That deletes everything saved for them in your app, takes them out of its rooms, and closes your app without warning if it's open. If they come back, they start as a new user with a new id.
set saves a value under a string key, get reads it, and remove deletes it:
set stores the value as JSON.stringify writes it, so a Date comes back as a string. A value JSON can't hold, like undefined, throws a TypeError. get returns a new copy each time, so changing what it returns changes nothing until you set it.
To read related keys together, give them a common prefix. keys, values, and entries return the keys that start with it, sorted by key, so dates written as YYYY-MM-DD come back in date order:
There's no query call. The whole store is in memory, so filter what entries returns.
A write replaces a key's whole value, and conflicts are settled key by key. Give each item in a list its own key, so edits to two items on two devices both survive:
To list them in order, keep each item's creation time in its value and sort by it:
Tinylib has no transaction across keys, though, so keep values that must change together in one key, like a puzzle's grid and its move count. Two devices that edit that key conflict over all of it.
Your client opens on the device's copy of the data, and what changed elsewhere arrives just after. To redraw when the user's data changes on another device, in another tab, or in your rules, pass a function to onChange. It gets the keys that changed, and it isn't called for this client's own writes:
onChange also reports a write that failed after set returned, for example because writes from another device took the data past 1 MB. Then error is set and those keys go back to what Tinylib's servers have, so the user's change is gone from the device. Keep what the user typed on screen so they can try again. onChange lists each error.code.
A set that would grow the data your client writes for the user past 1 MB throws a TinylibError with the code limit and saves nothing. A set that makes the data smaller still works, and so does remove:
A user can make their own client save anything. For a value other users should trust, like a count of wins, declare its key in rulesKeys in tinylib.json, and only your rules can write it. A name ending in / declares every key under it:
Your rules write a declared key for a room member with ctx.data(id). Use add, min, or max rather than get then set: if two rooms finish at the same moment, add counts both, while get then set drops one.
Your client reads a declared key like any other, but its set and remove throw a TypeError for one.
A key stays declared for the app's life: no later version can drop it from rulesKeys. A new version also can't declare a key that already holds a value your client wrote for any user.
In TypeScript, declare your keys on Register in a .d.ts file:
get and set then check each key's type, while entries and values still return unknown. Tinylib checks nothing at runtime, and values an earlier version wrote may have another shape.