Rules
Kind
A kind of room, exported from rules.js under its name.
Example
export const game = {
create(options, ctx) {
return { board: Array(9).fill(''), x: ctx.by.id, o: null }
},
on(state, input, ctx) {
if (input.type === 'join' && state.o) ctx.refuse('This game already has two players.')
},
}
Extended by
Type Parameters
| Type Parameter | Default type |
|---|---|
State | any |
Options | any |
Properties
| Property | Type | Description |
|---|---|---|
address? | string | Where Tinylib sends people who come in for a room of this kind from outside the app, such as 'game/:id'. |
Kind.create()
create(options, ctx): State;
Returns the first state, from the options tinylib.rooms.create passed. May refuse them with ctx.refuse.
Parameters
| Parameter | Type |
|---|---|
options | Options |
ctx | CreateContext |
Returns
State
Kind.on()
Input
type Input =
| {
type: "action";
from: Member;
name: string;
data?: unknown;
}
| {
type: "join";
from: Member;
via: | {
invite: Member;
}
| "link";
}
| {
type: "invite";
from: Member;
}
| {
type: "getLink";
from: Member;
}
| {
type: "deleteLink";
from: Member;
}
| {
type: "leave";
from: Member;
why: LeaveReason;
}
| {
type: "connect";
from: Member;
}
| {
type: "disconnect";
from: Member;
}
| {
type: "open";
from: Member;
}
| {
type: "timer";
name: string;
data?: unknown;
}
| {
type: "upgraded";
fromPublish: number;
};
What happens in a room, one at a time. Requests can be refused with ctx.refuse: action, join, invite,
getLink and deleteLink. The rest are facts.
action: a member'sroom.send(name, data).join: someone asks to join,viathe member who invited them or the room's link. They aren't a member until the rules accept, so they're welcomed on theirconnect, which follows at once.invite: a member is about to invite someone. The rules never learn who.getLinkanddeleteLink: a member gets the room's link, or deletes it.leave: a member left, andwhy.connectanddisconnect: a member's first device opened the room, or their last closed it.open: a page opened the room, on every open, a reload or a second device included.timer: a timerctx.setTimerset came due.upgraded: the first input under a new publish's rules.
LeaveReason
type LeaveReason =
| "left"
| "removed"
| "blocked someone"
| "data deleted"
| "account gone"
| "suspended";
Why a member left. 'blocked someone': they blocked another member, and so left.
ctx
What Tinylib hands the rules with every input, and the outputs they call. Outputs happen once on returns; when it
refuses or throws, the state and every output are thrown away.
Extended by
Properties
| Property | Type | Description |
|---|---|---|
roomId | string | - |
kind | string | The name of the kind's export. |
now | number | When the input arrived, in milliseconds on Tinylib's clock. |
publish | number | The publish that last wrote this state. |
members | RoomMember[] | The current members in the order they joined, with their current names. |
data | (personaId) => MemberValues & object | ctx.data(personaId) is a member's values under the keys tinylib.json declares in rulesKeys, for a current member or one leaving on this input. ctx.data.room is the data kept with this room. Writes happen after the input, one by one, and a failed write undoes nothing. Example ctx.data(winner).set('wins', (ctx.data(winner).get('wins') ?? 0) + 1, { audience: 'friends' }) ctx.data.room.set('result', { winner }) |
ctx.random()
random(): number;
A number from 0 up to 1 that players can't predict or rig.
Returns
number
ctx.refuse()
refuse(sentence): never;
Refuses the input: nothing changes, nothing is sent, and the member who acted gets sentence. Refusing a fact
changes nothing and tells no one.
Parameters
| Parameter | Type |
|---|---|
sentence | string |
Returns
never
Example
if (state.o) ctx.refuse('This game already has two players.')
ctx.send()
send(to, message): void;
Sends message to the open app of each of to, once. It isn't kept: a member without the room open misses it.
Parameters
| Parameter | Type |
|---|---|
to | Recipients |
message | unknown |
Returns
void
Example
ctx.send('everyone', { screen: 'vote' })
ctx.notify()
notify(
id,
title,
text?
): void;
Sends a notification with title and text to the devices of member id, unless they have the room open. Needs
"notifications" in tinylib.json's uses.
Parameters
| Parameter | Type |
|---|---|
id | string |
title | string |
text? | string |
Returns
void
Example
ctx.notify(next, 'Your move', `${input.from.name} played.`)
ctx.status()
status(
id,
text,
waiting
): void;
Sets the line Tinylib's screens show member id about this room, and whether the room waits on them. Tinylib keeps
it; the last one is the room's record when it ends.
Parameters
| Parameter | Type |
|---|---|
id | string |
text | string |
waiting | boolean |
Returns
void
Example
ctx.status(next, 'Your move', true)
ctx.name()
name(text): void;
What Tinylib calls the room outside the app: in the person's rooms list, in an invitation, and in its own sentences about the room. Until set, "this room". At most 60 characters.
Parameters
| Parameter | Type |
|---|---|
text | string |
Returns
void
Example
ctx.name(options.title)
ctx.setTimer()
setTimer(
name,
at,
data?
): void;
Wakes the room at at, on Tinylib's clock, with a timer input carrying name and data. Setting a name again
moves it.
Parameters
| Parameter | Type |
|---|---|
name | string |
at | number |
data? | unknown |
Returns
void
Example
ctx.setTimer('flag', ctx.now + 60_000)
ctx.cancelTimer()
cancelTimer(name): void;
Parameters
| Parameter | Type |
|---|---|
name | string |
Returns
void
ctx.remove()
remove(id): void;
Removes member id, which comes back as a leave input with why: 'removed'.
Parameters
| Parameter | Type |
|---|---|
id | string |
Returns
void
ctx.end()
end(): void;
Ends the room now. It takes no more input, and its members keep a record of it in their past rooms.
Returns
void
Recipients
type Recipients = "sender" | "everyone" | string | string[];
to for ctx.send: a member's id, a list of ids, everyone, or the input's sender.
MemberValues
A member's values under the keys tinylib.json declares in rulesKeys, from ctx.data(personaId).
MemberValues.get()
get(key): unknown;
The current value under key, earlier writes in this input included. Throws for a key rulesKeys doesn't declare.
Parameters
| Parameter | Type |
|---|---|
key | string |
Returns
unknown
MemberValues.keys()
keys(prefix?): string[];
The declared keys that start with prefix, sorted.
Parameters
| Parameter | Type |
|---|---|
prefix? | string |
Returns
string[]
MemberValues.set()
MemberValues.remove()
remove(key): void;
Removes the value under key after the input.
Parameters
| Parameter | Type |
|---|---|
key | string |
Returns
void
RoomData
The data kept with this room, for its members during the room and after, from ctx.data.room.
RoomData.get()
get(key): unknown;
The current value under key, earlier writes in this input included.
Parameters
| Parameter | Type |
|---|---|
key | string |
Returns
unknown
RoomData.keys()
keys(prefix?): string[];
The keys that start with prefix, sorted.
Parameters
| Parameter | Type |
|---|---|
prefix? | string |
Returns
string[]
RoomData.set()
set(key, value): void;
Writes value under key after the input.
Parameters
| Parameter | Type |
|---|---|
key | string |
value | unknown |
Returns
void
RoomData.remove()
remove(key): void;
Removes the value under key after the input.
Parameters
| Parameter | Type |
|---|---|
key | string |
Returns
void
Audience
type Audience = "me" | "friends";
Who reads a value: the persona only, or also their friends who have the app.
CreateContext
What Tinylib hands the rules with every input, and the outputs they call. Outputs happen once on returns; when it
refuses or throws, the state and every output are thrown away.
Extends
Properties
| Property | Type | Description | Inherited from |
|---|---|---|---|
roomId | string | - | Context.roomId |
kind | string | The name of the kind's export. | Context.kind |
now | number | When the input arrived, in milliseconds on Tinylib's clock. | Context.now |
publish | number | The publish that last wrote this state. | Context.publish |
members | RoomMember[] | The current members in the order they joined, with their current names. | Context.members |
data | (personaId) => MemberValues & object | ctx.data(personaId) is a member's values under the keys tinylib.json declares in rulesKeys, for a current member or one leaving on this input. ctx.data.room is the data kept with this room. Writes happen after the input, one by one, and a failed write undoes nothing. Example ctx.data(winner).set('wins', (ctx.data(winner).get('wins') ?? 0) + 1, { audience: 'friends' }) ctx.data.room.set('result', { winner }) | Context.data |
by | Member | The creator, who is the room's first member. | - |
Member
A persona: its id, and its current display name.
Extended by
Properties
| Property | Type |
|---|---|
id | string |
name | string |
RoomMember
withViews()
function withViews<State, View, Options>(kind): Kind<State, Options>;
After create, after every input the rules don't refuse, and on open, sends each member
{ view } and sets their status. A kind's end() waits until those have gone out, so the last
status becomes the room's record.
Type Parameters
| Type Parameter | Default type |
|---|---|
State | - |
View | - |
Options | any |
Parameters
| Parameter | Type |
|---|---|
kind | ViewKind<State, View, Options> |
Returns
Kind<State, Options>
Example
export const game = withViews({
create: (options, ctx) => ({ board: Array(9).fill(''), x: ctx.by.id, o: null, next: ctx.by.id }),
on(state, input, ctx) {},
view: (state, member) => ({ board: state.board, mine: state.next === member.id }),
status: (state, member) => (state.next === member.id ? { text: 'Your move', waiting: true } : { text: 'Their move', waiting: false }),
})
ViewKind
A kind of room, exported from rules.js under its name.
Example
export const game = {
create(options, ctx) {
return { board: Array(9).fill(''), x: ctx.by.id, o: null }
},
on(state, input, ctx) {
if (input.type === 'join' && state.o) ctx.refuse('This game already has two players.')
},
}
Extends
Kind<State,Options>
Type Parameters
| Type Parameter |
|---|
State |
View |
Options |
Properties
ViewKind.create()
create(options, ctx): State;
Returns the first state, from the options tinylib.rooms.create passed. May refuse them with ctx.refuse.
Parameters
| Parameter | Type |
|---|---|
options | Options |
ctx | CreateContext |
Returns
State
Inherited from
ViewKind.on()
ViewKind.view()
ViewKind.status()
Status
Properties
| Property | Type |
|---|---|
text | string |
waiting | boolean |