Build an engine that has not connected yet. Nothing is written until [Self::handle_connected].
config is a JS object with the same shape as [Config]. Only nick is required; every
other field has a default.
React to a message with an emoji.
Do anything, as a [Command] object.
Every command also has a method of its own, such as [Self::join]; this is the one call
that takes a command a host built itself.
Anything the engine cannot read throws, rather than going quietly missing.
Make an invitation link to a channel, or to the network when no channel is named.
Optionalchannel: stringOptionaldescription: stringWithdraw an invitation link.
Ask for older messages in a target, before the message with this id.
Mint a bearer token for one of the network's services, such as its file host.
Feed whatever the transport read. Partial lines are held until the rest arrives.
Tell the engine the transport is up. Queues the registration burst.
Tell the engine its transport died. The model survives, so a reconnect can resume from it.
Ask for the invitation links we have made.
Move our read marker in a target, at a time in milliseconds since the Unix epoch.
Everything the connection knows, as a JS value: channels, members, conversations and messages. For a host that only wants the model, not a diff of what changed.
Leave a channel, with a reason the others in it see.
Optionalreason: stringEvery event the engine has queued since the last call, as a JS array.
Draining a batch instead of one event per call is what keeps this binding cheap on every target this core is bound into: a call across the WebAssembly boundary costs the same whether it carries one event or a hundred, so paying that cost once per drain rather than once per event is what actually saves work.
for (const event of client.pollEvents()) {
switch (event.type) {
case "registered":
console.log(`registered as ${event.nick}`);
break;
case "model_changed":
if (event.change.type === "message_added") render(event.change.target);
break;
case "server_reply":
console.log(event.severity, event.code, event.text);
break;
}
}
When [Self::tick] next has something to do, as a monotonic instant, or undefined when
nothing is scheduled. A host can set one timer for exactly this instant instead of polling
on an interval.
Bytes the host should write to the transport, or undefined when there are none.
One chunk per call, unlike [Self::poll_events]: a chunk is already the smallest unit a
socket writes, so there is nothing to gain from batching it, and a growing [Event] never
has to carry it.
Leave the server, with a reason the others see.
Optionalreason: stringAsk the server to redact a message.
Optionalreason: stringRedeem an invitation code. Only before registering, which is the point of it.
Take one of our reactions back.
Rename a channel, keeping everyone in it and everything said in it.
Optionalreason: stringSend a CTCP ACTION, the third-person form.
Send a notice, which by convention must never be auto-replied to.
Send one raw protocol line, for anything this API does not name.
Send one voice signalling frame to a room.
Go away with a message, or come back by passing nothing.
Optionalmessage: stringSet one of our own metadata keys, or clear it by passing nothing.
Optionalvalue: stringChange our nick.
Set a channel's topic, or ask for the current one by passing nothing.
Optionaltopic: stringTell a target we are composing, paused, or done.
Subscribe to the metadata keys we want told about.
Advance the clock. monotonicMs drives every deadline; unixMs only stamps a message the
server did not stamp itself with server-time.
Stop watching nicks.
Watch nicks, so we hear when they come online.
Ask the server everything it will say about someone.
One connection, wrapped for JavaScript.
Every method mirrors one on [
Client]. None of them can panic: a bad argument comes back as a rejectedResult, whichwasm-bindgenturns into a thrown JS error, because a panic inside a WebAssembly module poisons it for the rest of the host's lifetime, with no way to recover.Example