The JavaScript SDK is in pre-release and not on npm yet. Install it from source.
FolkwaysDocs

Typed events

Type each event's data with an event map, and share topic definitions between your apps with defineTopic.

Event maps

Give client.topic() a map from event names to data types. TypeScript then checks what you publish and narrows msg.data by msg.name:

type ChatEvents = {
  message: { text: string };
  edited: { uid: string; text: string };
};

const room = client.topic<ChatEvents>('chat/lobby');

await room.publish('message', { text: 'hi' });   // ✓
// room.publish('message', { body: 'hi' });       // ✗ type error

room.subscribe((msg) => {
  if (msg.name === 'message') addMessage(msg.data.text);           // data: { text: string }
  if (msg.name === 'edited') editMessage(msg.data.uid, msg.data.text);
});

Types are not sent to the node; they only help your code.

Shared topic definitions

defineTopic describes a topic once: its name pattern, its events and each event's delivery type. Put it in a shared file and use it from your web app, mobile app and backend, so event names and types can't drift apart.

topics.ts
import { defineTopic } from '@folkways/realtime';

type RideEvents = {
  location: { lat: number; lng: number };
  status: { state: 'waiting' | 'on-the-way' | 'arrived' };
};

export const rideLocation = defineTopic<RideEvents>()('rides/{ride}/location', {
  events: {
    location: { delivery: 'kv', ttlMs: 30_000 },
    status: 'kv',
  },
});

Open it with the topic's parameters. publish() then fills in each event's delivery type (and kv lifetime), so you can't forget { delivery: 'kv' }:

const ride = rideLocation.open(client, { ride: '42' }); // topic rides/42/location

await ride.publish('location', { lat: 59.43, lng: 24.75 }); // sent as kv, expires after 30 s
// ride.publish('pickup', …)                               // ✗ not in the definition: refused locally
MemberMeaning
patternThe pattern as written, e.g. rides/{ride}/location
topic(params)The concrete name, e.g. rideLocation.topic({ ride: '42' }) → 'rides/42/location'
open(client, params)The typed topic handle, with each event's delivery filled in
eventsEach event's delivery type and options

Each {param} must be one topic level: a value containing / throws InvalidTopic.

Event options in a definition:

OptionMeaning
delivery'stream', 'kv' or 'signal'; a plain string is short for { delivery }
ttlMskv only: default lifetime of values

Each event's delivery type must match the topic's rule in the dashboard, which today allows one type per rule. Definitions also accept keyIsPublisher, access and presence, for rules and features that are coming soon; leave them out for now.

On this page