tunio-live-chat
v0.1.4
Published
Tunio live broadcast chat: protocol client, React hooks and components
Readme
tunio-live-chat
Live broadcast chat for Tunio: a WebSocket protocol client, React hooks and unstyled-but-structured components shared by the listener app and LiveStudio.
Install
pnpm add tunio-live-chatimport "tunio-live-chat/styles.css"Live chat
import { ChatComposer, ChatMessages, useLiveChat } from "tunio-live-chat"
const chat = useLiveChat({
wsUrl: "wss://app.tunio.ai/api/live/main/chat/ws",
token: async () => fetchShortLivedToken(),
enabled: stationIsLive
})
<ChatMessages
messages={chat.messages}
hostLabel="Host"
newMessagesLabel={count => `${count} new`}
emptyLabel="No messages yet"
/>
{chat.canWrite && <ChatComposer onSend={chat.send} placeholder="Message" sendLabel="Send" />}useLiveChat returns { connected, live, canWrite, isHost, viewerName, messages, pending, unread, markRead, send, remove, error }.
token may be a string or a function; a function is called again before every reconnect, so short-lived tickets work.
Replay
import { ChatMessages, useChatReplay } from "tunio-live-chat"
const visible = useChatReplay({ items, positionMs })items carry offset_ms from the start of the recording; the hook returns everything said up to the playhead and follows seeks in both directions.
Low-level client
const client = createLiveChatClient({ url, token })
client.on("message", message => {})
client.connect()
client.send("hello")The client reconnects with exponential backoff and jitter, pings every 25 s, drops a socket that went silent, and keeps unsent messages in a queue keyed by client_id. A message stays queued until the server echoes it back with the same client_id, and the queue is resent after every reconnect, so the server must treat client_id as an idempotency key.
Protocol
Server to client: hello, message, deleted, live, error, pong. Client to server: send, delete, ping. See src/types.ts.
Theming
The default stylesheet uses CSS custom properties on .tlc-messages and .tlc-composer: --tlc-fg, --tlc-muted, --tlc-author, --tlc-border, --tlc-surface, --tlc-bg, --tlc-radius, --tlc-font-size. All visible text comes from props.
Releasing
Publishing uses npm Trusted Publishing (OIDC), so no npm token is stored in the repository. .github/workflows/publish.yml is the only workflow that runs npm publish:
- every push to
mainbumps the patch version, builds, publishes, then pushes thechore(release): v<version>commit and thev<version>tag (commits starting withchore(release):do not trigger another release); - pushing a
v*tag by hand publishes that exact version, which must matchpackage.json.
One-time setup (owner)
npm only lets a trusted publisher be configured for a package that already exists, so the first version goes out by hand:
- Check out
mainat the commit wherepackage.jsonsays0.1.0, then runpnpm install && pnpm build. npm loginwith an account that may publishtunio-live-chat.npm publish --access public.- On npmjs.com open the package, Settings, Trusted Publisher, and add GitHub Actions with organization
tunioai, repositorytunio-live-chatand workflowpublish.yml, with no environment. - Optionally, in the same settings, require two-factor authentication and disallow tokens for publishing.
Until step 4 is done, the workflow's publish step fails and nothing is pushed, so no tag ever points at an unpublished version.
