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

Topics and subscriptions

Reference for Topic, publish and subscribe options, Subscription, Message, PublishReceipt and topic sets.

Topic

client.topic(name) or client.topic<Events>(name).

MemberReturnsMeaning
namestringThe topic's name
publish(event, data, options?)Promise<PublishReceipt>, or Promise<void> for signalsPublishes one event. See PublishOptions
subscribe(handler?, options?) / subscribe(options)SubscriptionSubscribes. See SubscribeOptions
messagesLiveView<TopicMessage[]>The latest 100 stream events, plus your own sends, while a subscription on this topic is active
values(event?)ValuesViewCurrent kv values by key, or signals by sender, for one event name. Without a name: every value, keyed name/key

publish parameters

ParameterTypeMeaning
eventstringThe event's name, e.g. 'message'. Non-empty, at most 64 bytes
dataany JSON value, string, Uint8Array, ArrayBuffer or typed arrayThe payload. Objects are sent as JSON, strings as text, bytes as bytes
optionsPublishOptionsOptional, below

PublishOptions

OptionTypeDefaultMeaning
delivery'stream' | 'kv' | 'signal''stream', or the topic definition's typeHow the event is delivered. Must match the topic's rule
keystringyour identitykv: which key to set or remove
ttlMsnumbernonekv: how long the value lives, in ms
removebooleanfalsekv: remove the key; data is ignored
headersRecord<string, string>noneUp to limits.maxHeaders (16) string headers, passed to subscribers
contentType'json' | 'text' | 'bytes' | 'flatbuffers' | 'protobuf' | 'msgpack' | 'cbor' | numberfrom dataLabels the payload. With an explicit type other than json or text, data must be bytes
idempotencyKeystringgenerated32 hex digits or a UUID. The node applies a key at most once within 10 minutes
clientTimenumberDate.now()Your clock for the event, Unix ms
signalAbortSignalnoneStop waiting for the receipt. The event may still be published

key, ttlMs and remove with a delivery other than kv throw InvalidArgument.

PublishReceipt

What a stream or kv publish resolves with.

FieldTypeMeaning
topicstringThe topic
delivery'stream' | 'kv' | 'signal'The delivery type used
idstringThe same as Message.id of the delivered event
uidstring (optional)The event's permanent id
cursorCursor (optional)Its position in the topic, for stream events
level'accepted' | 'committed'How durably it was stored. Today always 'accepted'
duplicatebooleantrue if the node had already stored this idempotency key. Still a success
serverTimenumberWhen the node accepted it, Unix ms

SubscribeOptions

OptionTypeDefaultMeaning
from'latest' | 'oldest' | { last: number } | { after: Cursor | string }'latest'Where stream events start when there is no saved position
onGap'from-oldest' | 'from-latest' | 'fail''from-oldest'What to do when the requested position is no longer kept
types('stream' | 'kv' | 'signal')[]allOnly receive these delivery types
eventsstring[]allOnly receive these event names

The handler, (message) => void | Promise<void>, runs for each event in order, one at a time.

Subscription

MemberTypeMeaning
topicstringThe topic
readyPromise<void>Resolves when the node confirms; rejects if it refuses
status'pending' | 'active' | 'resyncing' | 'failed' | 'ended' | 'closed'The current status
cursorCursor | undefinedThe last event this subscription finished handling
deliveries('stream' | 'kv' | 'signal')[]The delivery types the topic allows, once confirmed
unsubscribe()Promise<void>Stops this subscription
[Symbol.asyncIterator]for await (const msg of sub); ends when the subscription does

Subscription events

sub.on(event, fn) returns a function that removes the listener; once() and off() are also available.

EventArgumentsWhen
message(message)Every event, after your handler ran
snapshot(messages[])The current kv values or signals, on subscribe and after reconnects
gap(gap)Events were missed, see GapEvent
error(err)The subscription failed, or your handler threw
ended(err)The node ended it (permissions narrowed), the identity changed, or the client closed
status(status)The status changed

GapEvent

FieldTypeMeaning
topicstringThe topic
reason'expired' | 'epoch-lost' | 'slow-consumer' | 'unspecified'Why: history was trimmed, the node restarted, or the client fell too far behind
requestedCursor (optional)The position you asked to resume after
oldestCursor (optional)The oldest event still kept
latestCursor (optional)The newest event
resumedbooleanfalse when onGap: 'fail' ended the subscription

Message

Every event you receive.

FieldTypeMeaning
topicstringThe topic
namestringThe event's name
delivery'stream' | 'kv' | 'signal'Its delivery type
datayour type, or unknownThe decoded payload: JSON as a value, text as a string, anything else as a Uint8Array. undefined for a removed kv key
publisherstringThe verified identity of the sender. Trust this, not names inside data
idstringUnique within the topic; use it as a React key
uidstring (optional)Permanent id for stream and kv events. Point replies, edits and reactions at it
cursorCursor (optional)Position in the topic, for stream events
keystring (optional)kv: the key. Signals: the publisher
deletedbooleanA removed kv key
headersRecord<string, string>Headers set by the publisher
contentTypenumberThe payload's content type code
payloadUint8ArrayThe raw payload; don't modify it
serverTimenumberWhen the node accepted it, Unix ms. Informational, not for ordering
clientTimenumber (optional)The publisher's clock
replayedbooleanDelivered from history rather than live
pendingbooleanSent by this client and not yet confirmed
fromCachebooleanRead from the local store and not yet confirmed by the node

Entries of topic.messages also have:

FieldTypeMeaning
status'pending' | 'sent' | 'failed'Where your own send is; received events are 'sent'
errorRealtimeError (optional)Why a send failed
retry()() => Promise<void> (optional)Sends a failed message again, with the same idempotency key

ValuesView

topic.values(event): a read-only Map<string, Message> that is also a live value. It has get, has, size, keys(), values(), entries(), forEach() and can be iterated with for…of.

TopicSet

client.topic(['chat/a', 'chat/b']).

MemberReturnsMeaning
namesstring[]The topics in the set
add(names)thisAdds topics; active subscriptions of the set pick them up
remove(names)thisRemoves topics; active subscriptions of the set stop them
get(name)TopicThe single topic's handle
subscribe(handler?, options?)SetSubscriptionSubscribes to every topic. Takes SubscribeOptions plus strict
publish(event, data, options?)Promise<PublishReceipt[]>Publishes to every topic; one receipt per topic, in order

Set subscribe options add strict: boolean (default false): reject ready if any topic fails.

SetSubscription

MemberTypeMeaning
readyPromise<{ ok: string[]; failed: { topic, error }[] }>Settles when every topic has answered
topicsstring[]The topics currently covered
statusesMap<string, SubscriptionStatus>Each topic's status
unsubscribe()Promise<void>Stops every topic
Eventsmessage, gap, error, endedAs for a single subscription

EventFilter

The filter of client.on(filter, handler). Every field is optional and narrows the match.

FieldTypeMeaning
topicstringA topic name or pattern (* one level, trailing > one or more)
delivery'stream' | 'kv' | 'signal'Only this delivery type
eventstring | string[]Only these event names
publisherstring | string[]Only these publishers
selfbooleanfalse skips events your own identity published

On this page