---
sidebar_position: 11
---

# JavaScript reference

Three scripts, each loaded only by the pages that need it:

| Global | Script | Loaded by |
|---|---|---|
| `wordplusRealtimeClient` | the page script, which every WordPlus plugin shares | `wordplus_realtime()->script()` |
| `wordplusRealtimeCalls` | calls and group calls | `wordplus_realtime()->calls_script()` |
| `wordplusRealtimeCallScreen` | the drop-in call screen | `wordplus_realtime()->call_screen()` |

The page's settings are `window.wordplusRealtimeConfig`, unset on a site without its credentials.

## `wordplusRealtimeClient.channels( config )` → `Channels`

| Member | |
|---|---|
| `subscribe( name )` | → `Subscription`, the same one for the same name |
| `channel( name )` | → the `Subscription`, or `undefined` |
| `unsubscribe( name )` | leaves it |
| `close()` | leaves every channel |
| `connected` | whether the connection is up |
| `tab` | this tab's name on the connection, for a publish's `except` |
| `site` | the site key |
| `users( ids )` | → `Promise<{ [id]: { user_id, name, avatar, url, … } }>`: the site's users from its directory, opened; rejects with `no_identity` on a page whose user the site doesn't know ([encryption](encryption.md#the-sites-users)) |
| `keyring` | the page's keys (`Keyring`, below) |
| `on( event, fn )`, `off( event, fn? )` | `connected`, `disconnected` (reason), `error` (`{ code }`: the connection refused), `moved` (to another server, without a drop) |

`config` may also carry `authorize: ( channels ) => Promise<{ token, exp, keys, denied }>` to sign in place of the site's route.

## `wordplusRealtimeClient.keyring()` → `Keyring`

The page's keys, shared by every plugin on it ([encryption](encryption.md)). The channels open what they carry with it by themselves.

| Member | |
|---|---|
| `open( value )` | → the text a sealed value holds, `null` when no key held opens it; anything not sealed as it is |
| `openJson( value )` | → its data parsed; `undefined` when it doesn't open |
| `seal( text, label )`, `sealJson( data, label )` | → sealed with a key held, or `null` |
| `missing( value )` | → the labels of the sealed values in a payload whose keys the page lacks |
| `ensure( labels )` | → `Promise`: asks the site for those keys, once for those asked together |
| `has( label )`, `newest( prefix )`, `dayLabel()` | a key held; the newest held of one thing (`ch:private-a:`); today's |
| `onAdded( fn )` | `fn( entries, source )` for each key the page gets; returns a function that stops it |

`wordplusRealtimeClient.labelOf( value )` names the key a sealed value needs.

### `Subscription`

| Member | |
|---|---|
| `name`, `kind` | the channel, and `public`, `private` or `presence` |
| `state` | `pending`, `subscribed`, `failed`, `ended` |
| `error` | why it failed |
| `on( event, fn )`, `once( event, fn )`, `off( event?, fn? )` | a channel's event, `fn( data, { user_id } )`, opened, or the page's own: `realtime:subscribed`, `realtime:error`, `realtime:member_added`, `realtime:member_removed`, `realtime:unopened` |
| `trigger( event, data )` | → `Promise`: a `client-…` event to the channel's others ([client events](client-events.md)) |
| `members()`, `memberCount` | a presence channel's members, `[ { id, info } ]`, and how many |
| `unsubscribe()` | leaves it |

## `wordplusRealtimeCalls`

| Member | |
|---|---|
| `page()` | → `{ rt, calls }`: the page's channels and calls, made once from `wordplusRealtimeConfig`; `null` without it |
| `calls( rt, options )` | → `Calls` on a `Channels` of your own; `page()` is the one to share |
| `supportsP2P()` | whether this browser can hold a direct call |

### `Calls`

| Member | |
|---|---|
| `start( name, { to, type } )` | → `Promise<Call>`: rings `to`; rejects with `code` |
| `room( name, { type } )` | → `Promise<Room>`: joins a group call; rejects with `code` |
| `incoming()` | → the `Incoming` ringing now |
| `stopRinging()` | this page holds the user's line no more |
| `on( event, fn )`, `off( event, fn? )` | `incoming` (`Incoming`), `error` (`{ code, what }`) |

Options (in `wordplusRealtimeConfig`, or to `calls()`): `calls` (the calls route, `{ endpoint, headers }`), `authorize( request )` in its place, `rooms` (the media client's script), `api` (the server for a closing page's leave), `ring` (`false`: hold no line).

### `Incoming`

| Member | |
|---|---|
| `id`, `call`, `from`, `info`, `type` | the attempt, the call's name, the caller's id, what the site said about them, `video` or `audio` |
| `state`, `reason` | `ringing`, `answered`, `declined` or `over`, and why it's over |
| `accept()` | → `Promise<Call>` |
| `decline( reason? )` | `declined` (default) or `busy` |
| `on( 'over', fn )` | it stopped ringing: `fn( reason )` |

### `Call`

| Member | |
|---|---|
| `id`, `name`, `type`, `role`, `peer` | the attempt, the call's name, `video` or `audio`, `caller` or `callee`, `{ user, info }` |
| `state` | `ringing`, `connecting`, `connected`, `reconnecting`, `ended` |
| `path` | `direct`, `relay`, `room`, or `null` before it connects |
| `remote` | `{ camera, microphone, screen, screenAudio, media, quality }` |
| `endReason` | why it ended ([calls](calls.md#why-a-call-ended)) |
| `setTrack( source, track )` | `camera`, `microphone`, `screen_share`, `screen_share_audio`; `null` stops |
| `end()` | hangs up, or `cancelled` while ringing |
| `on( event, fn )`, `off( event, fn? )` | `state`, `path`, `remote`, `waiting`, `reacquire`, `autoplay_blocked`, `ended` |

### `Room`

| Member | |
|---|---|
| `state` | `connecting`, `waiting`, `connected`, `reconnecting`, `ended` |
| `people()` | → `Person[]`: everyone else |
| `setTrack( source, track )` | → `Promise`: what this page sends |
| `leave()` | |
| `livekit` | the media client's own room |
| `on( event, fn )`, `off( event, fn? )` | `state`, `waiting` (`{ until, reason }`), `person`, `person_left`, `speakers`, `ended` |

A `Person` is `{ identity, user, info, camera, microphone, screen, screenAudio, speaking }`.

### Remote tracks

Every track another person sends has `mediaStreamTrack`, `attach( element )`, which plays it in an `<audio>` or `<video>` element, and `detach( element? )`.

## `wordplusRealtimeCallScreen`

| Member | |
|---|---|
| `place( call, to, type, { name, avatar } )` | what `<wordplus-call>` does |
| `join( room, type, title )` | what `<wordplus-room>` does |
| `start()` | starts the screen now, which it does by itself once the page has loaded |
| `setStrings( strings )` | its words |
