Skip to content

Commit efc12ec

Browse files
Release - 4.22.0
1 parent d24a24f commit efc12ec

44 files changed

Lines changed: 290 additions & 59 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,97 @@
11
# Changelog
22

3-
## v4.21.4 (Mar 12, 2026)
3+
## v4.22.0 (Mar 26, 2026)
4+
### Features
5+
6+
#### Weekly Do-Not-Disturb Schedule
7+
8+
Added support for per-day weekly DND scheduling. You can now configure different DND time windows for each day of the week, replacing the previous single-time window DND setting.
9+
10+
**New methods:**
11+
- `setWeeklyDoNotDisturb(weeklyDndSchedules, timezone?)` — Sets a weekly DND schedule
12+
- `getWeeklyDoNotDisturb()` — Gets the current weekly DND schedule
13+
- `clearWeeklyDoNotDisturb()` — Clears the weekly DND schedule
14+
15+
**New types:**
16+
- `DndSchedule` — Model class for managing per-day DND time windows
17+
- `DndSchedules``Partial<Record<DayOfWeek, DndTimeWindow[]>>`
18+
- `DndTimeWindow``{ startHour, startMin, endHour, endMin }`
19+
- `DndSchedulePreference``{ doNotDisturbOn, dndSchedules?, timezone? }`
20+
- `DayOfWeek` — Enum (`sunday` | `monday` | ... | `saturday`)
21+
22+
### Deprecated
23+
- `setDoNotDisturb()` — Use `setWeeklyDoNotDisturb()` instead.
24+
- `getDoNotDisturb()` — Use `getWeeklyDoNotDisturb()` instead.
25+
- `DoNotDisturbPreference` — Use `DndSchedulePreference` instead.
26+
27+
### Usage Examples
28+
29+
**Set a weekly DND schedule**
30+
31+
```typescript
32+
import { DndSchedule, DayOfWeek } from '@sendbird/chat';
33+
34+
const dndSchedule = new DndSchedule();
35+
36+
// Set weekdays to 22:00 ~ 23:59
37+
dndSchedule.setWeekdays([
38+
{ startHour: 22, startMin: 0, endHour: 23, endMin: 59 },
39+
]);
40+
41+
// Set weekends to full-day DND
42+
dndSchedule.setFullDay([DayOfWeek.SATURDAY, DayOfWeek.SUNDAY]);
43+
44+
const preference = await sb.setWeeklyDoNotDisturb(dndSchedule, 'Asia/Seoul');
45+
```
46+
47+
**Get current weekly DND schedule**
48+
49+
```typescript
50+
const preference = await sb.getWeeklyDoNotDisturb();
51+
52+
console.log(preference.doNotDisturbOn); // true
53+
console.log(preference.timezone); // 'Asia/Seoul'
54+
console.log(preference.dndSchedules);
55+
// DndSchedule {
56+
// monday: [{ startHour: 22, startMin: 0, endHour: 23, endMin: 59 }],
57+
// tuesday: [{ startHour: 22, startMin: 0, endHour: 23, endMin: 59 }],
58+
// wednesday: [{ startHour: 22, startMin: 0, endHour: 23, endMin: 59 }],
59+
// thursday: [{ startHour: 22, startMin: 0, endHour: 23, endMin: 59 }],
60+
// friday: [{ startHour: 22, startMin: 0, endHour: 23, endMin: 59 }],
61+
// saturday: [{ startHour: 0, startMin: 0, endHour: 23, endMin: 59 }],
62+
// sunday: [{ startHour: 0, startMin: 0, endHour: 23, endMin: 59 }],
63+
// }
64+
```
65+
66+
**Clear weekly DND schedule**
67+
68+
```typescript
69+
await sb.clearWeeklyDoNotDisturb();
70+
```
71+
72+
**Migration from deprecated DND**
73+
74+
```typescript
75+
// Before (deprecated)
76+
await sb.setDoNotDisturb(true, 22, 0, 8, 0, 'Asia/Seoul');
77+
78+
// After
79+
const dndSchedule = new DndSchedule();
80+
dndSchedule.setWeekdays([
81+
{ starHour: 0, startMin: 0, endHour: 8, endMin: 0 },
82+
{ startHour: 22, startMin: 0, endHour: 23, endMin: 59 },
83+
]);
84+
await sb.setWeeklyDoNotDisturb(dndSchedule, 'Asia/Seoul');
85+
```
86+
87+
### Migration Notes
88+
89+
> **Important:** When you call `setWeeklyDoNotDisturb`, any existing DND schedule configured via the deprecated `setDoNotDisturb` will be reset and replaced by the new weekly schedule. The two settings are mutually exclusive — once the weekly DND schedule is set, the previous DND configuration will no longer be in effect.
90+
91+
### Improvements
92+
- Added `joinedAt` to `Member`
93+
- Fixed a bug where `MMKV` data was not trimmed after deletion
94+
- Fixed a bug where `loadMore()` pagination missed channels when an empty channel exists in the channel list## v4.21.4 (Mar 12, 2026)
495
### Improvements
596
- Fixed a bug Where messages received during `MessageCollection.initialize()` could be lost
697
- Add `cancelStewardTask` API to `AIAgentModule` for canceling steward tasks by message ID

aiAgent.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cjs/aiAgent.cjs

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

cjs/feedChannel.cjs

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

cjs/groupChannel.cjs

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

cjs/index.cjs

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

cjs/index.d.cts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,13 @@ export {
2222
CollectionEventSource,
2323
ConnectionHandler,
2424
ConnectionState,
25+
DayOfWeek,
2526
DeviceOsInfo,
2627
DeviceOsPlatform,
28+
DndSchedule,
29+
DndSchedulePreference,
30+
DndSchedules,
31+
DndTimeWindow,
2732
DoNotDisturbPreference,
2833
Emoji,
2934
EmojiCategory,
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
var e,t=require("./__bundle-61616961.cjs"),s=require("./__bundle-ff507d79.cjs"),n=require("./__bundle-dae7bdf2.cjs");exports.ChannelEventCategory=void 0,(e=exports.ChannelEventCategory||(exports.ChannelEventCategory={}))[e.NONE=0]="NONE",e[e.CHANNEL_ENTER=10102]="CHANNEL_ENTER",e[e.CHANNEL_EXIT=10103]="CHANNEL_EXIT",e[e.USER_CHANNEL_MUTE=10201]="USER_CHANNEL_MUTE",e[e.USER_CHANNEL_UNMUTE=10200]="USER_CHANNEL_UNMUTE",e[e.USER_CHANNEL_BAN=10601]="USER_CHANNEL_BAN",e[e.USER_CHANNEL_UNBAN=10600]="USER_CHANNEL_UNBAN",e[e.CHANNEL_FREEZE=10701]="CHANNEL_FREEZE",e[e.CHANNEL_UNFREEZE=10700]="CHANNEL_UNFREEZE",e[e.TYPING_START=10900]="TYPING_START",e[e.TYPING_END=10901]="TYPING_END",e[e.CHANNEL_JOIN=1e4]="CHANNEL_JOIN",e[e.CHANNEL_LEAVE=10001]="CHANNEL_LEAVE",e[e.CHANNEL_OPERATOR_UPDATE=10002]="CHANNEL_OPERATOR_UPDATE",e[e.CHANNEL_INVITE=10020]="CHANNEL_INVITE",e[e.CHANNEL_ACCEPT_INVITE=10021]="CHANNEL_ACCEPT_INVITE",e[e.CHANNEL_DECLINE_INVITE=10022]="CHANNEL_DECLINE_INVITE",e[e.CHANNEL_PROP_CHANGED=11e3]="CHANNEL_PROP_CHANGED",e[e.CHANNEL_DELETED=12e3]="CHANNEL_DELETED",e[e.CHANNEL_META_DATA_CHANGED=11100]="CHANNEL_META_DATA_CHANGED",e[e.CHANNEL_META_COUNTERS_CHANGED=11200]="CHANNEL_META_COUNTERS_CHANGED",e[e.CHANNEL_HIDE=13e3]="CHANNEL_HIDE",e[e.CHANNEL_UNHIDE=13001]="CHANNEL_UNHIDE",e[e.PINNED_MESSAGE_CHANGED=11300]="PINNED_MESSAGE_CHANGED";class a{constructor(e){var t;this.channelUrl=e.channel_url,this.channelType=e.channel_type,this.category=e.cat,this.data=null!==(t=e.data)&&void 0!==t?t:{},this.ts=e.ts}get isGroupChannelEvent(){return this.channelType===t.ChannelType.GROUP}get isOpenChannelEvent(){return this.channelType===t.ChannelType.OPEN}}class o extends t.WebSocketEventCommand{constructor(e,t,s){super(e,"SYEV",s),this.event=new a(s)}}class r extends t.WebSocketEventCommand{constructor(e,t,n){var a;super(e,"SYEV",n),this.pinnedMessageIds=[],this.latestPinnedMessage=null,this.ts=0,n.data&&(this.pinnedMessageIds=null!==(a=n.data.pinned_message_ids)&&void 0!==a?a:[],this.latestPinnedMessage=n.data.latest_pinned_message?s.parseMessagePayload(e,Object.assign({},n.data.latest_pinned_message)):null),this.ts=n.ts}}class i extends t.InstancedObject{get _messageBroadcast(){return s.MessageBroadcast.of(this._iid)}constructor(e,t){super(e),this._logger=t.logger,this._sdkState=t.sdkState,this._sessionManager=t.sessionManager,this._requestQueue=t.requestQueue,this._dispatcher=t.dispatcher,this._cacheContext=t.cacheContext,this._channelType=t.channelType}subscribeMessageEvent(e,t){this._messageBroadcast.subscribe(e,t)}unsubscribeMessageEvent(e){this._messageBroadcast.unsubscribe(e)}getMessageFromCache(e){return t.__awaiter(this,void 0,void 0,(function*(){return null}))}getExactlyMatchingMessagesForTokenFromCache(e,s,n,a=!1){return t.__awaiter(this,void 0,void 0,(function*(){return[]}))}getMessagesFromCache(e,s,n,a,o,r,i=!1){return t.__awaiter(this,void 0,void 0,(function*(){return[]}))}getPollMessagesFromCache(e,s,n,a){return t.__awaiter(this,void 0,void 0,(function*(){return[]}))}getCachedMessageCountBetween(e,s,n,a){return t.__awaiter(this,void 0,void 0,(function*(){return 0}))}getUnsentMessagesFromCache(e,s){return t.__awaiter(this,void 0,void 0,(function*(){return[]}))}removeFailedMessageFromCache(e){return t.__awaiter(this,void 0,void 0,(function*(){}))}}class E extends t.WebSocketEventCommand{constructor(e,n,a){var o,r,i,E;super(e,"ADMM",a),this.message=new s.AdminMessage(e,a);const{sdkState:d}=t.Vault.of(e);this.isMentioned=t.checkIfMentioned(this.message.mentionType,null!==(i=null!==(o=this.message.mentionedUserIds)&&void 0!==o?o:null===(r=this.message.mentionedUsers)||void 0===r?void 0:r.map((e=>e.userId)))&&void 0!==i?i:[],d.userId),this.forceUpdateLastMessage=null!==(E=a.force_update_last_message)&&void 0!==E&&E}}class d extends t.WebSocketEventCommand{constructor(e,n,a){var o,r,i,E,d;super(e,"AEDI",a),this.message=new s.AdminMessage(e,a);const{sdkState:_}=t.Vault.of(e);this.mentionCountChange=t.calculateMentionCountChange({mentionType:null===(o=a.old_values)||void 0===o?void 0:o.mention_type,mentionedUserIds:null!==(i=null===(r=a.old_values)||void 0===r?void 0:r.mentioned_user_ids)&&void 0!==i?i:[]},t.undefineNullProps({mentionType:this.message.mentionType,mentionedUserIds:null!==(E=this.message.mentionedUserIds)&&void 0!==E?E:null===(d=this.message.mentionedUsers)||void 0===d?void 0:d.map((e=>e.userId))}),_.userId)}}class _ extends t.WebSocketEventCommand{constructor(e,t,n){super(e,"MRCT",n),this.channelUrl=n.channel_url,this.channelType=n.channel_type,this.event=new s.ReactionEvent(n)}}class N extends t.WebSocketEventCommand{constructor(e,t,n){super(e,"MTHD",n),this.event=new s.ThreadInfoUpdateEvent(e,n)}}class l extends t.WebSocketEventCommand{constructor(e,t,s){super(e,"MCNT",s),this.groupChannelMemberCounts=s.group_channels.map((e=>({channelUrl:e.channel_url,memberCount:e.member_count,joinedMemberCount:e.joined_member_count,updatedAt:e.ts}))),this.openChannelMemberCounts=s.open_channels.map((e=>({channelUrl:e.channel_url,participantCount:e.participant_count,updatedAt:e.ts})))}}class c extends t.WebSocketEventCommand{constructor(e,s,a){super(e,"PEDI",a),this.event=new n.PollUpdateEvent(e,a),this.status=t.parsePollStatusPayload(a.poll.status)||a.poll.status,this.channelUrl=a.channel_url,this.channelType=a.channel_type}}exports.AdminMessageEventCommand=E,exports.BaseChannelManager=i,exports.ChannelEventCommand=o,exports.MemberCountUpdateEventCommand=l,exports.OperatorUpdateEventCommand=class extends o{constructor(e,s,n){super(e,s,n);const{operators:a=[]}=n.data;this.operators=a.map((e=>new t.User(this._iid,e)))}},exports.PollUpdateEventCommand=c,exports.ReactionEventCommand=_,exports.ThreadInfoUpdateEventCommand=N,exports.UpdateAdminMessageEventCommand=d,exports.UpdatePinnedMessageEventCommand=r;
1+
var e,t=require("./__bundle-4cedcee6.cjs"),s=require("./__bundle-a38b7b19.cjs"),n=require("./__bundle-dae7bdf2.cjs");exports.ChannelEventCategory=void 0,(e=exports.ChannelEventCategory||(exports.ChannelEventCategory={}))[e.NONE=0]="NONE",e[e.CHANNEL_ENTER=10102]="CHANNEL_ENTER",e[e.CHANNEL_EXIT=10103]="CHANNEL_EXIT",e[e.USER_CHANNEL_MUTE=10201]="USER_CHANNEL_MUTE",e[e.USER_CHANNEL_UNMUTE=10200]="USER_CHANNEL_UNMUTE",e[e.USER_CHANNEL_BAN=10601]="USER_CHANNEL_BAN",e[e.USER_CHANNEL_UNBAN=10600]="USER_CHANNEL_UNBAN",e[e.CHANNEL_FREEZE=10701]="CHANNEL_FREEZE",e[e.CHANNEL_UNFREEZE=10700]="CHANNEL_UNFREEZE",e[e.TYPING_START=10900]="TYPING_START",e[e.TYPING_END=10901]="TYPING_END",e[e.CHANNEL_JOIN=1e4]="CHANNEL_JOIN",e[e.CHANNEL_LEAVE=10001]="CHANNEL_LEAVE",e[e.CHANNEL_OPERATOR_UPDATE=10002]="CHANNEL_OPERATOR_UPDATE",e[e.CHANNEL_INVITE=10020]="CHANNEL_INVITE",e[e.CHANNEL_ACCEPT_INVITE=10021]="CHANNEL_ACCEPT_INVITE",e[e.CHANNEL_DECLINE_INVITE=10022]="CHANNEL_DECLINE_INVITE",e[e.CHANNEL_PROP_CHANGED=11e3]="CHANNEL_PROP_CHANGED",e[e.CHANNEL_DELETED=12e3]="CHANNEL_DELETED",e[e.CHANNEL_META_DATA_CHANGED=11100]="CHANNEL_META_DATA_CHANGED",e[e.CHANNEL_META_COUNTERS_CHANGED=11200]="CHANNEL_META_COUNTERS_CHANGED",e[e.CHANNEL_HIDE=13e3]="CHANNEL_HIDE",e[e.CHANNEL_UNHIDE=13001]="CHANNEL_UNHIDE",e[e.PINNED_MESSAGE_CHANGED=11300]="PINNED_MESSAGE_CHANGED";class a{constructor(e){var t;this.channelUrl=e.channel_url,this.channelType=e.channel_type,this.category=e.cat,this.data=null!==(t=e.data)&&void 0!==t?t:{},this.ts=e.ts}get isGroupChannelEvent(){return this.channelType===t.ChannelType.GROUP}get isOpenChannelEvent(){return this.channelType===t.ChannelType.OPEN}}class o extends t.WebSocketEventCommand{constructor(e,t,s){super(e,"SYEV",s),this.event=new a(s)}}class r extends t.WebSocketEventCommand{constructor(e,t,n){var a;super(e,"SYEV",n),this.pinnedMessageIds=[],this.latestPinnedMessage=null,this.ts=0,n.data&&(this.pinnedMessageIds=null!==(a=n.data.pinned_message_ids)&&void 0!==a?a:[],this.latestPinnedMessage=n.data.latest_pinned_message?s.parseMessagePayload(e,Object.assign({},n.data.latest_pinned_message)):null),this.ts=n.ts}}class i extends t.InstancedObject{get _messageBroadcast(){return s.MessageBroadcast.of(this._iid)}constructor(e,t){super(e),this._logger=t.logger,this._sdkState=t.sdkState,this._sessionManager=t.sessionManager,this._requestQueue=t.requestQueue,this._dispatcher=t.dispatcher,this._cacheContext=t.cacheContext,this._channelType=t.channelType}subscribeMessageEvent(e,t){this._messageBroadcast.subscribe(e,t)}unsubscribeMessageEvent(e){this._messageBroadcast.unsubscribe(e)}getMessageFromCache(e){return t.__awaiter(this,void 0,void 0,(function*(){return null}))}getExactlyMatchingMessagesForTokenFromCache(e,s,n,a=!1){return t.__awaiter(this,void 0,void 0,(function*(){return[]}))}getMessagesFromCache(e,s,n,a,o,r,i=!1){return t.__awaiter(this,void 0,void 0,(function*(){return[]}))}getPollMessagesFromCache(e,s,n,a){return t.__awaiter(this,void 0,void 0,(function*(){return[]}))}getCachedMessageCountBetween(e,s,n,a){return t.__awaiter(this,void 0,void 0,(function*(){return 0}))}getUnsentMessagesFromCache(e,s){return t.__awaiter(this,void 0,void 0,(function*(){return[]}))}removeFailedMessageFromCache(e){return t.__awaiter(this,void 0,void 0,(function*(){}))}}class E extends t.WebSocketEventCommand{constructor(e,n,a){var o,r,i,E;super(e,"ADMM",a),this.message=new s.AdminMessage(e,a);const{sdkState:d}=t.Vault.of(e);this.isMentioned=t.checkIfMentioned(this.message.mentionType,null!==(i=null!==(o=this.message.mentionedUserIds)&&void 0!==o?o:null===(r=this.message.mentionedUsers)||void 0===r?void 0:r.map((e=>e.userId)))&&void 0!==i?i:[],d.userId),this.forceUpdateLastMessage=null!==(E=a.force_update_last_message)&&void 0!==E&&E}}class d extends t.WebSocketEventCommand{constructor(e,n,a){var o,r,i,E,d;super(e,"AEDI",a),this.message=new s.AdminMessage(e,a);const{sdkState:_}=t.Vault.of(e);this.mentionCountChange=t.calculateMentionCountChange({mentionType:null===(o=a.old_values)||void 0===o?void 0:o.mention_type,mentionedUserIds:null!==(i=null===(r=a.old_values)||void 0===r?void 0:r.mentioned_user_ids)&&void 0!==i?i:[]},t.undefineNullProps({mentionType:this.message.mentionType,mentionedUserIds:null!==(E=this.message.mentionedUserIds)&&void 0!==E?E:null===(d=this.message.mentionedUsers)||void 0===d?void 0:d.map((e=>e.userId))}),_.userId)}}class _ extends t.WebSocketEventCommand{constructor(e,t,n){super(e,"MRCT",n),this.channelUrl=n.channel_url,this.channelType=n.channel_type,this.event=new s.ReactionEvent(n)}}class N extends t.WebSocketEventCommand{constructor(e,t,n){super(e,"MTHD",n),this.event=new s.ThreadInfoUpdateEvent(e,n)}}class c extends t.WebSocketEventCommand{constructor(e,t,s){super(e,"MCNT",s),this.groupChannelMemberCounts=s.group_channels.map((e=>({channelUrl:e.channel_url,memberCount:e.member_count,joinedMemberCount:e.joined_member_count,updatedAt:e.ts}))),this.openChannelMemberCounts=s.open_channels.map((e=>({channelUrl:e.channel_url,participantCount:e.participant_count,updatedAt:e.ts})))}}class l extends t.WebSocketEventCommand{constructor(e,s,a){super(e,"PEDI",a),this.event=new n.PollUpdateEvent(e,a),this.status=t.parsePollStatusPayload(a.poll.status)||a.poll.status,this.channelUrl=a.channel_url,this.channelType=a.channel_type}}exports.AdminMessageEventCommand=E,exports.BaseChannelManager=i,exports.ChannelEventCommand=o,exports.MemberCountUpdateEventCommand=c,exports.OperatorUpdateEventCommand=class extends o{constructor(e,s,n){super(e,s,n);const{operators:a=[]}=n.data;this.operators=a.map((e=>new t.User(this._iid,e)))}},exports.PollUpdateEventCommand=l,exports.ReactionEventCommand=_,exports.ThreadInfoUpdateEventCommand=N,exports.UpdateAdminMessageEventCommand=d,exports.UpdatePinnedMessageEventCommand=r;
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
var e=require("./__bundle-61616961.cjs");class s extends e.BaseCommand{}exports.NotificationCollectionRefreshCommand=s,exports.getFeedChannelIndexBy=e=>["-lastMessageUpdatedAt","-createdAt","syncIndex"];
1+
var e=require("./__bundle-4cedcee6.cjs");class s extends e.BaseCommand{}exports.NotificationCollectionRefreshCommand=s,exports.getFeedChannelIndexBy=e=>["-lastMessageUpdatedAt","-createdAt","syncIndex"];

cjs/lib/__bundle-42042489.cjs

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)