Friends
tinylib.friends lists the user's friends who use your app and reads what they save for friends. It also opens Tinylib's send sheet, where the user picks friends to send your app to.
Friendships are mutual, and people make them in Tinylib, outside your app. Your app can't add or remove a friend.
Add "friends" to uses in tinylib.json:
The first time a user opens your app, Tinylib's onboarding tells them your app can share data with their friends. There's no separate permission to ask for.
For a guest, a user without a Tinylib account, every friends call rejects with refused. A call made as the user taps, such as friends.sendApp() behind a Send to a friend button, first opens Tinylib's offer of an account, so such a button can stay for a guest; a list or leaderboard of friends can't be filled for one, so check tinylib.user.guest before reading it. In npx tinylib-sdk dev, the simulated users are all friends with each other.
To let the user's friends read a value, save it with audience: 'friends':
A later save without audience keeps it shared, and audience: 'me' makes it private again. Keep a score friends should trust in a key only the rules write, which the rules share the same way.
tinylib.friends.list() resolves with the user's friends who use your app, sorted by name, each as { id, name }. tinylib.friends.data.get(key) resolves with a Map from each friend's id to { value, changedAt }, for each friend who shared a value under key. Neither includes the user, so add their own row from tinylib.data:
Every friends call rejects with offline without a connection. Nothing tells your client when a friend's value changes, so read it again each time you show it. changedAt is on the same clock as tinylib.now(), so you can leave out old scores.
tinylib.friends.data.of(id) has the read methods of tinylib.data for what one friend shared. Each returns a promise, and each value comes as { value, changedAt }:
For anyone who isn't the user's friend in your app, it's empty.
tinylib.friends.sendApp() opens Tinylib's send sheet. It resolves when the sheet closes, and your app never learns who the user picked. An empty leaderboard is a good place to offer it:
Tinylib has no call that turns a user id into a name. Take each name from the list its id came from:
These lists have current names, and leave out blocked users and users whose data in your app was deleted. When an id is missing from its list, drop its row rather than show it without a name.
If your app shows people to each other, the Developer Terms require it to let them block and report each other through Tinylib. tinylib.block(id) and tinylib.report(id) open Tinylib's own sheets. Each resolves true if the user went through with it and false if they backed out, and rejects with offline without a connection:
Blocking someone ends the friendship, and the user who blocked leaves every room they share with that person.