JavaScript Chat SDK 1.0.0 migration guide
The 1.0.0 release of the JavaScript Chat SDK introduces a set of API improvements that make real-time subscriptions more discoverable, event payloads strongly typed, and membership management more expressive. The core change is the shift from generic listener methods to entity-owned callbacks: instead of calling chat.listenForEvents() or passing a callback to channel.connect(), you now attach callbacks directly to entity objects (channel.onMessageReceived, user.onMentioned, etc.).
This guide is for developers who use JavaScript Chat SDK 0.x.x in existing applications.
If your application uses 0.x.x, it will not compile against 1.0.0 without changes to join(), Message.reactions, and GetCurrentUserMentionsResult. This guide summarizes the differences between the versions and shows how to migrate to JavaScript Chat SDK 1.0.0.
Most notable changes include:
join()signature change: The callback parameter is removed andjoin()no longer subscribes to messages automatically. CallonMessageReceived()separately after joining to start message delivery.join()now returnsPromise<Membership>directly instead of aJoinResultwrapper.- Entity-first callbacks: All streaming methods gain entity-owned alternatives.
connect()→onMessageReceived(),getTyping()→onTypingChanged(),streamPresence()→onPresenceChanged(),streamUpdates()→onUpdated()+onDeleted(). The old methods are deprecated but still compile. - Typed event payloads: Events that previously required manual
EventContentparsing now deliver purpose-built types.onMentioned()deliversMention,onInvited()deliversInvite,onRestrictionChanged()delivers a restriction object, andonReadReceiptReceived()deliversReadReceipt. Message.reactionstype change:Message.reactionschanged from an object of reaction lists toMessageReaction[]. EachMessageReactionexposesvalue,isMine, anduserIds.GetCurrentUserMentionsResult.mentions: TheenhancedMentionsDatafield is deprecated (still available) and a newmentionsfield is added. Its element type changes to a unifiedUserMentiontype with fieldsmessage(aMessageobject),userId,channelId, andparentChannelId?.sendText()renamed: The old multi-parametersendText()overload is renamed tosendTextLegacy(). Use the newsendText(text, options?: SendTextParams)form.MessageDraftis now the primary draft class: What wasMessageDraftV2is nowMessageDraft. The oldMessageDraftclass is renamed toMessageDraftV1and deprecated. Usechannel.createMessageDraft()— it now returns the newMessageDraft.- New read receipt capabilities:
channel.fetchReadReceipts()returns a paginated snapshot of read positions. A newemitReadReceiptEventsconfiguration option controls which channel types emit read receipt signals. - New membership methods:
channel.hasMember(),channel.getMember(),user.isMemberOf(), anduser.getMembership()let you check and retrieve a specific membership without fetching the full list.
Differences between 0.x.x and 1.0.0
| Feature/Method | 0.x.x | 1.0.0 |
|---|---|---|
join() return type | Promise<JoinResult> (includes disconnect) | Promise<Membership> |
join() signature | join(custom?, callback?) | join(params?: { status?, type?, custom? }) |
JoinResult | Available | Removed |
Message delivery after join() | Automatic (via callback) | Requires explicit onMessageReceived() call |
| Disconnect from message delivery | joinResult.disconnect() (function) | disconnect() returned by onMessageReceived() |
connect() | Primary method for message delivery | Deprecated — use channel.onMessageReceived() |
getTyping() | Typing indicator streaming | Deprecated — use channel.onTypingChanged() |
streamPresence() | Presence streaming | Deprecated — use channel.onPresenceChanged() |
streamUpdates() on entity | Update streaming (single entity) | Deprecated — use onUpdated() |
streamUpdatesOn() on entity | Update streaming (multiple entities) | Still supported |
| Deletion events | Part of streamUpdates() callback | Separate onDeleted() event |
streamReadReceipts() | { [timetoken: string]: string[] } callback | Deprecated — use channel.onReadReceiptReceived() with typed ReadReceipt |
streamMessageReports() | Raw event callback | Deprecated — use channel.onMessageReported() |
Message.reactions type | Object of reaction lists | MessageReaction[] |
Message.actions | Available | Deprecated |
| Mention events | chat.listenForEvents({ type: "mention" }) | user.onMentioned(Mention) |
| Invite events | chat.listenForEvents({ type: "invite" }) | user.onInvited(Invite) |
| Moderation events | chat.listenForEvents({ type: "moderation" }) | user.onRestrictionChanged({ userId, channelId, ban, mute, reason? }) |
| Custom events (emit) | chat.emitEvent() | Deprecated — use channel.emitCustomEvent() |
| Custom events (listen) | chat.listenForEvents({ type: "custom" }) | Deprecated — use channel.onCustomEvent() |
EventContent.* types | Available | Deprecated |
Old sendText() overload | sendText(text, options) with legacy params | Renamed to sendTextLegacy() |
New sendText() overload | Not available | sendText(text, options?: SendTextParams) |
| Primary draft class | MessageDraftV2 (via createMessageDraftV2()) | MessageDraft (via createMessageDraft()) |
| Old draft class | MessageDraft (via createMessageDraft()) | MessageDraftV1 (via createMessageDraftV1()), deprecated |
| Read receipts snapshot | Not available | channel.fetchReadReceipts() → ReadReceiptsResponse |
| Read receipt timetokens | N/A | string (not number) |
emitReadReceiptEvents config | Not available | Available in ChatConfig |
GetCurrentUserMentionsResult field | enhancedMentionsData | mentions: UserMention[] |
| Membership existence check | getMembers() then filter | channel.hasMember(userId), channel.getMember(userId) |
| User membership check | getMemberships() then filter | user.isMemberOf(channelId), user.getMembership(channelId) |
removeThread() return | Composite object | Promise<boolean> |
createThread() | No arguments, returns ThreadChannel | Required text parameter, returns CreateThreadResult |
Channel.delete() / User.delete() | Accepts soft parameter | soft parameter removed; returns Promise<true> |
Membership.update() signature | update({ custom }) | update({ status?, type?, custom? }) |
join() and onMessageReceived()
Important change
This change affects any code that calls join() and then listens for messages. Update it before releasing to users.
In 0.x.x, calling join() on a channel both created the membership server-side and subscribed to message delivery automatically — messages arrived via the callback you passed to join(), and the returned disconnect function stopped the subscription. In 1.0.0, join() creates the membership only. Call onMessageReceived() separately to start receiving messages.
The JoinResult type is removed. join() now returns Promise<Membership> directly. The disconnect function is returned by onMessageReceived().
- 0.x.x
- 1.0.0
1// join() both created the membership and started message delivery
2const { membership, disconnect } = await channel.join(
3 (message) => {
4 console.log("New message:", message.text);
5 },
6 { role: "member" }
7);
8
9// Stop message delivery:
10disconnect();
11await channel.leave();
1// join() creates the membership — messages are not delivered automatically
2const membership = await channel.join({
3 status: "active",
4 custom: { role: "member" },
5});
6
7// Subscribe to messages separately
8const disconnect = channel.onMessageReceived((message) => {
9 console.log("New message:", message.text);
10});
11
12// Stop message delivery and leave:
13disconnect();
14await channel.leave();
Entity-first callbacks
In 0.x.x, streaming subscriptions were created by calling methods on the Chat or Channel object and passing a callback as a parameter. In 1.0.0, entity objects expose dedicated callback methods. Pass a handler function and receive a disconnect function in return — call it to stop the subscription.
The old instance methods (connect(), getTyping(), streamPresence(), streamUpdates()) are deprecated but still compile. The static streamUpdatesOn() helper remains supported. Migrate to the new names at your own pace.
- 0.x.x
- 1.0.0
1// Channel — message delivery
2const stopMessages = channel.connect((message) => {
3 console.log("Message:", message.text);
4});
5
6// Channel — typing indicator
7const stopTyping = channel.getTyping((typingUserIds) => {
8 console.log("Typing:", typingUserIds);
9});
10
11// Channel — presence
12const stopPresence = channel.streamPresence((presence) => {
13 console.log("Present:", presence.occupants);
14});
15
show all 29 lines1// Channel — message delivery
2const stopMessages = channel.onMessageReceived((message) => {
3 console.log("Message:", message.text);
4});
5
6// Channel — typing indicator
7const stopTyping = channel.onTypingChanged((typingUserIds) => {
8 console.log("Typing:", typingUserIds);
9});
10
11// Channel — presence
12const stopPresence = channel.onPresenceChanged((userIds) => {
13 console.log("Present:", userIds);
14});
15
show all 41 linesThe same pattern applies to message.onUpdated() for individual message update subscriptions.
Typed event payloads
In 0.x.x, invite, mention, and moderation events required calling chat.listenForEvents() with a type string and reading fields from the raw event payload. In 1.0.0, these events are exposed as dedicated entity callbacks with purpose-built types. The chat.listenForEvents() method and all EventContent types are deprecated.
- 0.x.x
- 1.0.0
1// Mention events — raw event with untyped payload
2const stopMentions = chat.listenForEvents({
3 channel: currentUser.id,
4 type: "mention",
5 callback: (event) => {
6 console.log("Mentioned in:", event.payload.channelId);
7 },
8});
9
10// Invite events
11const stopInvites = chat.listenForEvents({
12 channel: currentUser.id,
13 type: "invite",
14 callback: (event) => {
15 console.log("Invited to:", event.payload.channelId);
show all 31 lines1// Mention events — typed Mention
2const stopMentions = user.onMentioned((mention: Mention) => {
3 console.log("Mentioned in:", mention.channelId);
4 console.log("By:", mention.mentionedByUserId);
5 console.log("Message timetoken:", mention.messageTimetoken);
6});
7
8// Invite events — typed Invite
9const stopInvites = user.onInvited((invite: Invite) => {
10 console.log("Invited to:", invite.channelId, "(", invite.channelType, ")");
11 console.log("By:", invite.invitedByUserId, "at:", invite.invitationTimetoken);
12});
13
14// Moderation events — restriction object { userId, channelId, ban, mute, reason? }
15const stopModeration = user.onRestrictionChanged((restriction) => {
show all 24 linesRead receipts
The read receipts API gains two new capabilities in 1.0.0: a typed real-time callback (onReadReceiptReceived()) and an on-demand snapshot (fetchReadReceipts()). The old streamReadReceipts() method is deprecated.
In 0.x.x, streamReadReceipts() delivered an object on every event, where keys were timetokens and values were arrays of user IDs who had read up to that point.
In 1.0.0, onReadReceiptReceived() fires once per incoming receipt signal and delivers a single ReadReceipt value containing the user ID and their last-read timetoken as a string. fetchReadReceipts() provides a paginated snapshot of the current read state for all channel members.
note
Read receipt timetokens are string values in the JavaScript SDK, unlike the Long type in Kotlin.
- 0.x.x
- 1.0.0
1const stop = channel.streamReadReceipts((receipts) => {
2 // receipts: { [timetoken: string]: string[] } — timetoken to user IDs
3 Object.entries(receipts).forEach(([timetoken, userIds]) => {
4 console.log(`Timetoken ${timetoken} read by`, userIds);
5 });
6});
1// Real-time updates — one event per user receipt
2const stop = channel.onReadReceiptReceived((receipt: ReadReceipt) => {
3 // lastReadTimetoken is a string in the JS SDK
4 console.log(`User ${receipt.userId} read up to ${receipt.lastReadTimetoken}`);
5});
6
7// On-demand snapshot of all current read positions
8const response = await channel.fetchReadReceipts();
9response.receipts.forEach((receipt: ReadReceipt) => {
10 console.log(`${receipt.userId}: ${receipt.lastReadTimetoken}`);
11});
Controlling which channel types emit read receipts
A new emitReadReceiptEvents option in ChatConfig controls which channel types produce read receipt signals. By default, public channels do not emit read receipts.
1const chat = await Chat.init({
2 publishKey: "...",
3 subscribeKey: "...",
4 userId: "...",
5 // Default: public = false, group = true, direct = true
6 // To restore the old behavior (always emit), set all to true:
7 emitReadReceiptEvents: {
8 public: true,
9 group: true,
10 direct: true,
11 },
12});
Behavioral change
In 1.0.0, setLastReadMessage(), setLastReadMessageTimetoken(), and markAllMessagesAsRead() now emit receipt events by default on direct and group channels. If your app previously relied on these methods not emitting events, you may see unexpected receipt signals and additional network traffic after upgrading. Set emitReadReceiptEvents to { direct: false, group: false } to restore the old behavior.
Message reactions
Important change
This change affects any code that reads Message.reactions. Update it before releasing to users.
In 0.x.x, Message.reactions returned a raw object of reaction lists. Grouping reactions by value, counting them, or checking whether the current user had reacted required manual processing.
In 1.0.0, Message.reactions returns MessageReaction[]. Each MessageReaction aggregates reactions of the same value and exposes isMine (whether the current user is among them) and userIds (array of reacting user IDs). The Message.actions property is deprecated.
- 0.x.x
- 1.0.0
1// Raw object — manual grouping required
2const rawReactions = message.reactions;
3Object.entries(rawReactions).forEach(([type, actions]) => {
4 console.log(`${type}: ${actions.length} reaction(s)`);
5 const isMine = actions.some((a) => a.uuid === chat.currentUser.id);
6 console.log("Mine:", isMine);
7});
1// MessageReaction[] — aggregated by reaction value
2const reactions: MessageReaction[] = message.reactions;
3reactions.forEach((reaction) => {
4 console.log(`${reaction.value}: ${reaction.userIds.length} reaction(s), mine: ${reaction.isMine}`);
5 console.log("Reacted by:", reaction.userIds);
6});
Sending messages in 1.0.0
1.0.0 separates message sending into two distinct paths: a lightweight API for plain text and a composition API for rich content.
| Use case | API |
|---|---|
Send plain text with delivery options (meta, ttl, storeInHistory, and so on) | channel.sendText(text, options?: SendTextParams) |
| Build messages with mentions, channel references, links, files, or quoted messages | channel.createMessageDraft() → draft.send() |
Migrate existing code that passed quotedMessage or files to the old sendText() | channel.sendTextLegacy() — migration only, do not use for new code |
SendTextParams covers lightweight delivery options only: meta, storeInHistory, sendByPost, ttl, and customPushData. It does not accept rich-content parameters.
For rich composition, channel.createMessageDraft() returns the MessageDraft class (previously MessageDraftV2 in 0.x.x). Use it whenever your UI has a text composer that handles mentions, channel references, links, files, or quoted messages.
Deprecated overload
The previous sendText() overload accepting SendTextOptionParams (which included quotedMessage and files as top-level options) was renamed to sendTextLegacy().
sendTextLegacy() is kept only to ease migration from 0.x.x. Do not use it for new integrations — use sendText() for plain text or createMessageDraft() for rich content.
Simple send
1const channel = await chat.getChannel("support")
2await channel.sendText("Hi everyone!", {
3 meta: { priority: "high" },
4 storeInHistory: true,
5 ttl: 15,
6})
Rich send with MessageDraft
1const channel = await chat.getChannel("support")
2if (!channel) throw new Error("Channel not found")
3
4const draft = channel.createMessageDraft({
5 userSuggestionSource: "channel",
6 isTypingIndicatorTriggered: true,
7 userLimit: 10,
8 channelLimit: 10,
9})
10
11draft.addChangeListener(async (state) => {
12 const elements = state.messageElements
13 const suggestions = await state.suggestedMentions
14 renderComposer(elements)
15 renderSuggestions(suggestions)
show all 27 linesMigrating from 0.x.x
- 0.x.x
- 1.0.0
1await channel.sendText("See you there!", {
2 quotedMessage: someMessage,
3 mentionedUsers: { 8: mentionedUser },
4 files: [myFile],
5});
1// Plain text with delivery options
2const params: SendTextParams = {
3 meta: { priority: "high" },
4 storeInHistory: true,
5 ttl: 24,
6};
7await channel.sendText("See you there!", params);
8
9// Rich content — use MessageDraft
10// sendTextLegacy() is available only for migration from 0.x.x and will be removed in a future release
removeThread() return type
In 0.x.x, removeThread() returned a composite object. In 1.0.0, it returns Promise<boolean>.
- 0.x.x
- 1.0.0
1const { threadChannel, parentMessage } = await message.removeThread()
2console.log("Thread removed from:", threadChannel.id)
1const success = await message.removeThread()
2console.log("Thread removed:", success)
createThread() now requires text
In 0.x.x, createThread() took no arguments and created an empty thread channel. In 1.0.0, createThread(text, options?) requires the first reply text, sends it as the initial thread message, and returns CreateThreadResult containing both threadChannel and parentMessage.
- 0.x.x
- 1.0.0
1const threadChannel = await message.createThread()
2await threadChannel.sendText("First reply")
1const { threadChannel, parentMessage } = await message.createThread("First reply")
2console.log("Thread created:", threadChannel.id)
3console.log("Parent has thread:", parentMessage.hasThread) // true
Soft-delete removed from entity deletion
In 0.x.x, Channel.delete(), ThreadChannel.delete(), User.delete(), Chat.deleteChannel(), and Chat.deleteUser() accepted a soft parameter for soft-deletion. In 1.0.0, the soft parameter is removed — all deletions are permanent. Return types are simplified to Promise<true>.
- 0.x.x
- 1.0.0
1await channel.delete({ soft: true })
1const deleted = await channel.delete()
2console.log("Channel deleted:", deleted)
note
Message soft-delete (Message.delete({ soft: true })) is unaffected by this change.
Membership.update() signature expanded
In 0.x.x, Membership.update() accepted only custom. In 1.0.0, it also accepts status and type.
- 0.x.x
- 1.0.0
1await membership.update({ custom: { role: "admin" } })
1await membership.update({
2 status: "active",
3 type: "admin",
4 custom: { role: "admin" },
5})
MessageDraft class rename
What was MessageDraftV2 is now MessageDraft. What was MessageDraft is now MessageDraftV1 (deprecated). The channel.createMessageDraft() method now returns a MessageDraft (the new class). To access the old draft class during a transition period, use channel.createMessageDraftV1().
- 0.x.x
- 1.0.0
1// Old primary draft
2const draft = channel.createMessageDraft();
3// draft is MessageDraft (old class)
4
5// New draft
6const draftV2 = channel.createMessageDraftV2();
7// draftV2 is MessageDraftV2
1// createMessageDraft() now returns the new MessageDraft class
2const draft = channel.createMessageDraft();
3// draft is MessageDraft (previously MessageDraftV2)
4
5// Old draft is now deprecated
6const oldDraft = channel.createMessageDraftV1();
7// oldDraft is MessageDraftV1 (previously MessageDraft), deprecated
Additional MessageDraft changes
Beyond the class rename, several MessageDraft types changed in 1.0.0:
MessageDraft.send()— The options parameter type changed fromMessageDraftOptionstoSendTextParams.MessageDraft.addMention()— The mention type parameter changed fromTextTypestoMentionType.SuggestedMention.type— Changed fromTextTypestoMentionType.
Update any code that references these types directly.
Custom events
chat.emitEvent() and chat.listenForEvents() are deprecated. Use channel.emitCustomEvent() to emit a custom event and channel.onCustomEvent() to listen for one.
Note that the JavaScript emitCustomEvent() and onCustomEvent() methods accept an options object rather than positional parameters.
- 0.x.x
- 1.0.0
1// Emit
2await chat.emitEvent({
3 channel: "my-channel",
4 type: "custom",
5 payload: { action: "ping" },
6});
7
8// Listen
9const stop = chat.listenForEvents({
10 channel: "my-channel",
11 type: "custom",
12 callback: (event) => {
13 console.log("Custom event:", event.payload);
14 },
15});
1// Emit — options object
2await channel.emitCustomEvent({ action: "ping" }, {
3 storeInHistory: true,
4});
5
6// Listen — callback first, options second
7const stop = channel.onCustomEvent(
8 (event) => {
9 console.log("Custom event:", event.payload);
10 },
11 { /* CustomEventListenOptions */ }
12);
GetCurrentUserMentionsResult
Important change
This change affects any code that reads GetCurrentUserMentionsResult. Update it before releasing to users.
The enhancedMentionsData field on GetCurrentUserMentionsResult is renamed to mentions. Its element type changes to a unified UserMention type.
- 0.x.x
- 1.0.0
1const result = await chat.getCurrentUserMentions();
2result.enhancedMentionsData.forEach((mentionData) => {
3 // mentionData could be UserMentionData, ChannelMentionData, or ThreadMentionData
4 console.log("Channel:", mentionData.channelId);
5});
1const result = await chat.getCurrentUserMentions();
2result.mentions.forEach((userMention: UserMention) => {
3 console.log("Channel:", userMention.channelId);
4 console.log("By:", userMention.userId);
5 console.log("Message:", userMention.message.timetoken);
6 if (userMention.parentChannelId) {
7 console.log("Thread in:", userMention.parentChannelId);
8 }
9});
New capabilities in 1.0.0
The following features are new in 1.0.0 and have no counterpart in 0.x.x.
| Feature | Description |
|---|---|
channel.fetchReadReceipts() | Returns a ReadReceiptsResponse with the last-read timetoken (string) for each channel member. Use for initial load or on-demand checks. |
channel.hasMember(userId) | Returns Promise<boolean> — checks whether a user is a member of the channel without fetching the full membership list. |
channel.getMember(userId) | Returns Promise<Membership | null> — retrieves a specific member's membership object directly from the channel. |
user.isMemberOf(channelId) | Returns Promise<boolean> — checks whether the user is a member of the given channel. |
user.getMembership(channelId) | Returns Promise<Membership | null> — retrieves the user's membership for a specific channel. |
membership.onUpdated() | Fires when membership metadata changes. Returns () => void. |
membership.onDeleted() | Fires when the membership is deleted. Returns () => void. |
channel.emitCustomEvent() | Emits a custom event directly on the channel. Accepts (payload, options?: CustomEventEmitOptions). Replaces chat.emitEvent(). |
channel.onCustomEvent() | Subscribes to custom events on the channel. Accepts (callback, options?: CustomEventListenOptions). Replaces chat.listenForEvents({ type: "custom" }). |
user.onMentioned() | Subscribes to mention events for the user. Delivers typed Mention objects. |
user.onInvited() | Subscribes to invite events for the user. Delivers typed Invite objects. |
user.onRestrictionChanged() | Subscribes to moderation events for the user. Delivers restriction objects with shape { userId, channelId, ban, mute, reason? }. |
emitReadReceiptEvents config | ChatConfig.emitReadReceiptEvents ({ public?: boolean; group?: boolean; direct?: boolean }) controls which channel types emit read receipt signals. |
ChannelGroup.onMessageReceived() | Subscribes to incoming messages on all channels in the group. |
ChannelGroup.onPresenceChanged() | Subscribes to presence events across all channels in the group. |
membership.delete() | Removes the membership. Returns Promise<boolean>. |
channel.getInvitees() | Returns a list of users invited to the channel. |
threadChannel.onThreadMessageReceived() | Subscribes to new messages in a thread. Returns () => void. |
threadChannel.onThreadChannelUpdated() | Fires when thread channel metadata changes. Returns () => void. |
threadMessage.onThreadMessageUpdated() | Fires when a thread message or its reactions change. Returns () => void. |
Custom interface implementations
If your application implements or extends Chat SDK interfaces (such as Channel, User, Message, or Membership), 1.0.0 adds new required methods to these interfaces. Compilation will fail until you implement the new methods.
Key additions include entity-owned callback methods (onUpdated(), onDeleted(), onMessageReceived(), etc.) and new membership/presence methods (hasMember(), getMember(), isMemberOf(), getMembership()).
Review the entity documentation for each interface your code extends to identify the new required members:
Migration steps
To migrate from JavaScript Chat SDK 0.x.x to 1.0.0:
- Replace every
channel.join(callback, custom?)call. Remove the callback argument fromjoin(). Addchannel.onMessageReceived(callback)after a successful join to restore message delivery. Update your code to useMembershipdirectly from thejoin()result —JoinResultno longer exists. - Rename streaming methods on
Channel:connect()→onMessageReceived(),getTyping()→onTypingChanged(),streamPresence()→onPresenceChanged(). Update all disconnect calls: previouslyjoinResult.disconnect(), now the return value ofonMessageReceived(). - Replace
channel.streamUpdates()withchannel.onUpdated(). Addchannel.onDeleted()wherever you previously detected deletion through thestreamUpdates()callback. Note:streamUpdatesOn()is still supported and does not need to be replaced. - Apply the same
onUpdated()/onDeleted()pattern toUser,Membership, andMessage. - Replace
channel.streamReadReceipts()withchannel.onReadReceiptReceived(). Update the handler to useReadReceipt(fields:userId,lastReadTimetoken: string) instead of the old dictionary type. - Replace
channel.streamMessageReports()withchannel.onMessageReported()and update the handler to use the typedMessageReporttype. - Replace
chat.listenForEvents({ type: "mention" })withuser.onMentioned()and update the handler to use theMentiontype. - Replace
chat.listenForEvents({ type: "invite" })withuser.onInvited()and update the handler to use theInvitetype. - Replace
chat.listenForEvents({ type: "moderation" })withuser.onRestrictionChanged()and update the handler to use the restriction object shape{ userId, channelId, ban, mute, reason? }. - Update all code that reads
Message.reactions. Replace raw object iteration withMessageReaction[]iteration. Accessreaction.value,reaction.isMine, andreaction.userIdsdirectly. Remove any references toMessage.actions. - Migrate any calls to the old
sendText()multi-parameter overload withquotedMessage,mentionedUsers, andfilestochannel.createMessageDraft()for new integrations. For plain text sends, use the newsendText(text, options?: SendTextParams)form.sendTextLegacy()exists only to ease short-term migration from0.x.xand will be removed in a future release — do not use it as the primary path for new code. - Replace
channel.createMessageDraftV2()calls withchannel.createMessageDraft(). Rename anyMessageDraftV2type references toMessageDraft. If you need the old draft during a transitional period, usechannel.createMessageDraftV1()and theMessageDraftV1type. - Replace
chat.emitEvent()calls withchannel.emitCustomEvent(payload, options?). Replacechat.listenForEvents({ type: "custom" })calls withchannel.onCustomEvent(callback, options?). Remove all references toEventContenttypes. - Replace
result.enhancedMentionsDatawithresult.mentionsin any code that callschat.getCurrentUserMentions(). Update element handling to useUserMention(fields:message,userId,channelId,parentChannelId). Note thatmessageis aMessageobject, not a timetoken.enhancedMentionsDatais deprecated but still available. - Review
Chat.init()configuration and addemitReadReceiptEventsif you need non-default read receipt emission behavior. - Remove the
softparameter from allChannel.delete(),User.delete(),Chat.deleteChannel(), andChat.deleteUser()calls. Update return-type handling toPromise<true>. - Update
Membership.update()calls to use the expanded signature (status,type,custom). - Update any code that destructures
Message.removeThread()results — the method now returnsPromise<boolean>. - Replace
message.createThread()(no arguments) withmessage.createThread(text, options?). Handle theCreateThreadResultreturn value containingthreadChannelandparentMessage. - Update
MessageDraft.send()options to useSendTextParams. ReplaceTextTypeswithMentionTypeinaddMention()andSuggestedMention.type. - If you implement Chat SDK interfaces, add the new required methods to your implementations.
- If you use
streamUpdates()callbacks, be aware that they may now receivenullfor deletion events. Splitting into separateonUpdated()andonDeleted()handlers avoids this ambiguity.
If you encounter issues during migration, contact PubNub Support.