stream-chat 9.48.0 → 9.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.browser.js +109 -48
- package/dist/cjs/index.browser.js.map +2 -2
- package/dist/cjs/index.node.js +109 -48
- package/dist/cjs/index.node.js.map +2 -2
- package/dist/esm/index.mjs +109 -48
- package/dist/esm/index.mjs.map +2 -2
- package/dist/types/channel.d.ts +12 -0
- package/dist/types/client.d.ts +4 -2
- package/dist/types/events.d.ts +1 -0
- package/dist/types/types.d.ts +16 -0
- package/dist/types/utils.d.ts +13 -0
- package/package.json +1 -1
- package/src/channel.ts +45 -4
- package/src/client.ts +47 -28
- package/src/events.ts +1 -0
- package/src/messageDelivery/MessageDeliveryReporter.ts +3 -1
- package/src/offline-support/offline_support_api.ts +53 -24
- package/src/types.ts +14 -0
- package/src/utils.ts +22 -0
|
@@ -621,6 +621,12 @@ function isOwnUserBaseProperty(property) {
|
|
|
621
621
|
};
|
|
622
622
|
return ownUserBaseProperties[property];
|
|
623
623
|
}
|
|
624
|
+
var channelHasReadEvents = (channel) => {
|
|
625
|
+
const ownCapabilities = channel?.data?.own_capabilities;
|
|
626
|
+
return !(Array.isArray(ownCapabilities) && !ownCapabilities.includes("read-events"));
|
|
627
|
+
};
|
|
628
|
+
var channelTracksReadLocally = (channel) => !channelHasReadEvents(channel) && !!channel?.getClient().options.isLocalUnreadCountEnabled;
|
|
629
|
+
var userHasReadReceipts = (client) => client.user?.privacy_settings?.read_receipts?.enabled ?? true;
|
|
624
630
|
function addFileToFormData(uri, name, contentType) {
|
|
625
631
|
const data = new import_form_data.default();
|
|
626
632
|
if (isReadableStream(uri) || isBuffer(uri) || isFileWebAPI(uri) || isBlobWebAPI(uri)) {
|
|
@@ -8782,6 +8788,7 @@ var MessageDeliveryReporter = class _MessageDeliveryReporter {
|
|
|
8782
8788
|
* @param options
|
|
8783
8789
|
*/
|
|
8784
8790
|
this.markRead = async (collection, options) => {
|
|
8791
|
+
if (!userHasReadReceipts(this.client)) return null;
|
|
8785
8792
|
let result = null;
|
|
8786
8793
|
if (isChannel(collection)) {
|
|
8787
8794
|
result = await collection.markAsReadRequest(options);
|
|
@@ -10126,6 +10133,33 @@ var Channel = class {
|
|
|
10126
10133
|
...data
|
|
10127
10134
|
});
|
|
10128
10135
|
}
|
|
10136
|
+
/**
|
|
10137
|
+
* markReadLocally - Resets this user's unread count locally, without any backend call. Intended for
|
|
10138
|
+
* channels that have read events disabled (e.g. livestreams) when the client is created with the
|
|
10139
|
+
* `isLocalUnreadCountEnabled` option. Dispatches a dedicated, client-only `message.read_locally` event
|
|
10140
|
+
* that runs through the same `_handleChannelEvent` read logic as a real `message.read` (minus the
|
|
10141
|
+
* delivery-report network sync), so the read-state update lives in one place. When offline support
|
|
10142
|
+
* is enabled, the offline DB persists the reset for read-events-disabled channels, so the local
|
|
10143
|
+
* count stays consistent across app restarts.
|
|
10144
|
+
*
|
|
10145
|
+
* @return {Event | undefined} The dispatched `message.read_locally` event, or `undefined` if there is no connected user.
|
|
10146
|
+
*/
|
|
10147
|
+
markReadLocally() {
|
|
10148
|
+
const client = this.getClient();
|
|
10149
|
+
if (!client.userID) return;
|
|
10150
|
+
const event = {
|
|
10151
|
+
channel_id: this.id,
|
|
10152
|
+
channel_type: this.type,
|
|
10153
|
+
cid: this.cid,
|
|
10154
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10155
|
+
last_read_message_id: this.lastMessage()?.id,
|
|
10156
|
+
team: this.data?.team,
|
|
10157
|
+
type: "message.read_locally",
|
|
10158
|
+
user: client.user
|
|
10159
|
+
};
|
|
10160
|
+
client.dispatchEvent(event);
|
|
10161
|
+
return event;
|
|
10162
|
+
}
|
|
10129
10163
|
/**
|
|
10130
10164
|
* clean - Cleans the channel state and fires stop typing if needed
|
|
10131
10165
|
*/
|
|
@@ -10281,7 +10315,7 @@ var Channel = class {
|
|
|
10281
10315
|
if (message.user?.id === this.getClient().userID) return false;
|
|
10282
10316
|
if (message.user?.id && this.getClient().userMuteStatus(message.user.id))
|
|
10283
10317
|
return false;
|
|
10284
|
-
if (
|
|
10318
|
+
if (!this.getClient().options.isLocalUnreadCountEnabled && !channelHasReadEvents(this)) {
|
|
10285
10319
|
return false;
|
|
10286
10320
|
}
|
|
10287
10321
|
if (this.getClient()._muteStatus(this.cid).muted) return false;
|
|
@@ -10692,6 +10726,11 @@ var Channel = class {
|
|
|
10692
10726
|
delete channelState.typing[event.user.id];
|
|
10693
10727
|
}
|
|
10694
10728
|
break;
|
|
10729
|
+
// `message.read_locally` is the client-only event dispatched by `markReadLocally()` when read
|
|
10730
|
+
// events are disabled (e.g. livestreams with `isLocalUnreadCountEnabled`). It reuses the exact
|
|
10731
|
+
// `message.read` state logic so the read-state update lives in one place — only the
|
|
10732
|
+
// delivery-report network sync below is skipped for it.
|
|
10733
|
+
case "message.read_locally":
|
|
10695
10734
|
case "message.read":
|
|
10696
10735
|
if (event.user?.id && event.created_at) {
|
|
10697
10736
|
const previousReadState = channelState.read[event.user.id];
|
|
@@ -10712,7 +10751,9 @@ var Channel = class {
|
|
|
10712
10751
|
const isOwnEvent = event.user?.id === client.user?.id;
|
|
10713
10752
|
if (isOwnEvent) {
|
|
10714
10753
|
channelState.unreadCount = 0;
|
|
10715
|
-
|
|
10754
|
+
if (event.type === "message.read") {
|
|
10755
|
+
client.syncDeliveredCandidates([this]);
|
|
10756
|
+
}
|
|
10716
10757
|
}
|
|
10717
10758
|
}
|
|
10718
10759
|
break;
|
|
@@ -14827,6 +14868,31 @@ var StreamChat = class _StreamChat {
|
|
|
14827
14868
|
* @return {Promise<APIResponse>}
|
|
14828
14869
|
*/
|
|
14829
14870
|
this.markAllRead = this.markChannelsRead;
|
|
14871
|
+
this.getUserAgent = () => {
|
|
14872
|
+
if (this.userAgent) {
|
|
14873
|
+
return this.userAgent;
|
|
14874
|
+
}
|
|
14875
|
+
if (!this.cachedUserAgent) {
|
|
14876
|
+
const version = "9.50.0";
|
|
14877
|
+
const { name: sdkName, version: sdkVersion } = this.sdkIdentifier ?? {};
|
|
14878
|
+
const { name: appName, version: appVersion } = this.appIdentifier ?? {};
|
|
14879
|
+
const { os, model: deviceModel } = this.deviceIdentifier ?? {};
|
|
14880
|
+
const head = sdkName ? `stream-chat-${sdkName}-v${sdkVersion}-llc-v${version}` : `stream-chat-js-v${version}-${this.node ? "node" : "browser"}`;
|
|
14881
|
+
this.cachedUserAgent = [
|
|
14882
|
+
head,
|
|
14883
|
+
// reports the host app, the device OS, the device model, and the picked
|
|
14884
|
+
// exports bundle, each only when a value is present
|
|
14885
|
+
...Object.entries({
|
|
14886
|
+
app: appName,
|
|
14887
|
+
app_version: appVersion,
|
|
14888
|
+
os,
|
|
14889
|
+
device_model: deviceModel,
|
|
14890
|
+
client_bundle: "browser-cjs"
|
|
14891
|
+
}).filter(([, value]) => value && value.length > 0).map(([key, value]) => `${key}=${value}`)
|
|
14892
|
+
].join("|");
|
|
14893
|
+
}
|
|
14894
|
+
return this.cachedUserAgent;
|
|
14895
|
+
};
|
|
14830
14896
|
/**
|
|
14831
14897
|
* _isUsingServerAuth - Returns true if we're using server side auth
|
|
14832
14898
|
*/
|
|
@@ -14865,6 +14931,7 @@ var StreamChat = class _StreamChat {
|
|
|
14865
14931
|
warmUp: false,
|
|
14866
14932
|
recoverStateOnReconnect: true,
|
|
14867
14933
|
disableCache: false,
|
|
14934
|
+
isLocalUnreadCountEnabled: false,
|
|
14868
14935
|
wsUrlParams: new URLSearchParams({}),
|
|
14869
14936
|
...inputOptions
|
|
14870
14937
|
};
|
|
@@ -15279,6 +15346,13 @@ var StreamChat = class _StreamChat {
|
|
|
15279
15346
|
delete this.activeChannels[cid];
|
|
15280
15347
|
});
|
|
15281
15348
|
}
|
|
15349
|
+
if (event.type === "notification.removed_from_channel" && event.cid) {
|
|
15350
|
+
const { cid } = event;
|
|
15351
|
+
this.activeChannels[cid]?._disconnect();
|
|
15352
|
+
postListenerCallbacks.push(() => {
|
|
15353
|
+
delete this.activeChannels[cid];
|
|
15354
|
+
});
|
|
15355
|
+
}
|
|
15282
15356
|
return postListenerCallbacks;
|
|
15283
15357
|
}
|
|
15284
15358
|
_muteStatus(cid) {
|
|
@@ -16770,31 +16844,6 @@ var StreamChat = class _StreamChat {
|
|
|
16770
16844
|
partialThreadObject
|
|
16771
16845
|
);
|
|
16772
16846
|
}
|
|
16773
|
-
getUserAgent() {
|
|
16774
|
-
if (this.userAgent) {
|
|
16775
|
-
return this.userAgent;
|
|
16776
|
-
}
|
|
16777
|
-
const version = "9.48.0";
|
|
16778
|
-
const clientBundle = "browser-cjs";
|
|
16779
|
-
let userAgentString = "";
|
|
16780
|
-
if (this.sdkIdentifier) {
|
|
16781
|
-
userAgentString = `stream-chat-${this.sdkIdentifier.name}-v${this.sdkIdentifier.version}-llc-v${version}`;
|
|
16782
|
-
} else {
|
|
16783
|
-
userAgentString = `stream-chat-js-v${version}-${this.node ? "node" : "browser"}`;
|
|
16784
|
-
}
|
|
16785
|
-
const { os, model } = this.deviceIdentifier ?? {};
|
|
16786
|
-
return [
|
|
16787
|
-
// reports the device OS, if provided
|
|
16788
|
-
["os", os],
|
|
16789
|
-
// reports the device model, if provided
|
|
16790
|
-
["device_model", model],
|
|
16791
|
-
// reports which bundle is being picked from the exports
|
|
16792
|
-
["client_bundle", clientBundle]
|
|
16793
|
-
].reduce(
|
|
16794
|
-
(withArguments, [key, value]) => value && value.length > 0 ? withArguments.concat(`|${key}=${value}`) : withArguments,
|
|
16795
|
-
userAgentString
|
|
16796
|
-
);
|
|
16797
|
-
}
|
|
16798
16847
|
/**
|
|
16799
16848
|
* @deprecated use sdkIdentifier instead
|
|
16800
16849
|
* @param userAgent
|
|
@@ -18236,6 +18285,7 @@ var EVENT_MAP = {
|
|
|
18236
18285
|
"ai_indicator.stop": true,
|
|
18237
18286
|
"ai_indicator.clear": true,
|
|
18238
18287
|
// local events
|
|
18288
|
+
"message.read_locally": true,
|
|
18239
18289
|
"channels.queried": true,
|
|
18240
18290
|
"offline_reactions.queried": true,
|
|
18241
18291
|
"connection.changed": true,
|
|
@@ -18619,7 +18669,8 @@ var AbstractOfflineDB = class {
|
|
|
18619
18669
|
if (cid && client.user && client.user.id !== user?.id) {
|
|
18620
18670
|
const userId = client.user.id;
|
|
18621
18671
|
const channel = client.activeChannels[cid];
|
|
18622
|
-
|
|
18672
|
+
const tracksReadLocally = channelTracksReadLocally(channel);
|
|
18673
|
+
if (channel && (channelHasReadEvents(channel) || tracksReadLocally)) {
|
|
18623
18674
|
const ownReads = channel.state.read[userId];
|
|
18624
18675
|
const unreadCount = channel.countUnread();
|
|
18625
18676
|
const upsertReadsQueries = await this.upsertReads({
|
|
@@ -18627,8 +18678,8 @@ var AbstractOfflineDB = class {
|
|
|
18627
18678
|
execute: false,
|
|
18628
18679
|
reads: [
|
|
18629
18680
|
{
|
|
18630
|
-
last_read: ownReads
|
|
18631
|
-
last_read_message_id: ownReads
|
|
18681
|
+
last_read: (ownReads?.last_read ?? /* @__PURE__ */ new Date(0)).toISOString(),
|
|
18682
|
+
last_read_message_id: ownReads?.last_read_message_id,
|
|
18632
18683
|
unread_messages: unreadCount,
|
|
18633
18684
|
user: client.user
|
|
18634
18685
|
}
|
|
@@ -18827,27 +18878,30 @@ var AbstractOfflineDB = class {
|
|
|
18827
18878
|
truncated_at,
|
|
18828
18879
|
execute: false
|
|
18829
18880
|
});
|
|
18881
|
+
let finalQueries = [...truncateQueries];
|
|
18830
18882
|
const userId = ownUser.id;
|
|
18831
18883
|
const activeChannel = this.client.activeChannels[cid];
|
|
18832
|
-
const
|
|
18833
|
-
|
|
18834
|
-
|
|
18835
|
-
|
|
18836
|
-
|
|
18884
|
+
const tracksReadLocally = channelTracksReadLocally(activeChannel);
|
|
18885
|
+
if (activeChannel && (channelHasReadEvents(activeChannel) || tracksReadLocally)) {
|
|
18886
|
+
const ownReads = activeChannel.state.read[userId];
|
|
18887
|
+
let unreadCount = 0;
|
|
18888
|
+
if (truncated_at) {
|
|
18889
|
+
unreadCount = activeChannel.countUnread(new Date(truncated_at));
|
|
18890
|
+
}
|
|
18891
|
+
const upsertReadQueries = await this.upsertReads({
|
|
18892
|
+
cid,
|
|
18893
|
+
execute: false,
|
|
18894
|
+
reads: [
|
|
18895
|
+
{
|
|
18896
|
+
last_read: (ownReads?.last_read ?? /* @__PURE__ */ new Date(0)).toString(),
|
|
18897
|
+
last_read_message_id: ownReads?.last_read_message_id,
|
|
18898
|
+
unread_messages: unreadCount,
|
|
18899
|
+
user: ownUser
|
|
18900
|
+
}
|
|
18901
|
+
]
|
|
18902
|
+
});
|
|
18903
|
+
finalQueries = [...finalQueries, ...upsertReadQueries];
|
|
18837
18904
|
}
|
|
18838
|
-
const upsertReadQueries = await this.upsertReads({
|
|
18839
|
-
cid,
|
|
18840
|
-
execute: false,
|
|
18841
|
-
reads: [
|
|
18842
|
-
{
|
|
18843
|
-
last_read: ownReads.last_read.toString(),
|
|
18844
|
-
last_read_message_id: ownReads.last_read_message_id,
|
|
18845
|
-
unread_messages: unreadCount,
|
|
18846
|
-
user: ownUser
|
|
18847
|
-
}
|
|
18848
|
-
]
|
|
18849
|
-
});
|
|
18850
|
-
const finalQueries = [...truncateQueries, ...upsertReadQueries];
|
|
18851
18905
|
if (execute) {
|
|
18852
18906
|
await this.executeSqlBatch(finalQueries);
|
|
18853
18907
|
}
|
|
@@ -18948,6 +19002,13 @@ var AbstractOfflineDB = class {
|
|
|
18948
19002
|
if (type === "message.read" || type === "notification.mark_read") {
|
|
18949
19003
|
return this.handleRead({ event, unreadMessages: 0, execute });
|
|
18950
19004
|
}
|
|
19005
|
+
if (type === "message.read_locally") {
|
|
19006
|
+
const localChannel = event.cid ? this.client.activeChannels[event.cid] : void 0;
|
|
19007
|
+
if (channelTracksReadLocally(localChannel)) {
|
|
19008
|
+
return this.handleRead({ event, unreadMessages: 0, execute });
|
|
19009
|
+
}
|
|
19010
|
+
return [];
|
|
19011
|
+
}
|
|
18951
19012
|
if (type === "notification.mark_unread") {
|
|
18952
19013
|
return this.handleRead({ event, execute });
|
|
18953
19014
|
}
|