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
package/dist/esm/index.mjs
CHANGED
|
@@ -406,6 +406,12 @@ function isOwnUserBaseProperty(property) {
|
|
|
406
406
|
};
|
|
407
407
|
return ownUserBaseProperties[property];
|
|
408
408
|
}
|
|
409
|
+
var channelHasReadEvents = (channel) => {
|
|
410
|
+
const ownCapabilities = channel?.data?.own_capabilities;
|
|
411
|
+
return !(Array.isArray(ownCapabilities) && !ownCapabilities.includes("read-events"));
|
|
412
|
+
};
|
|
413
|
+
var channelTracksReadLocally = (channel) => !channelHasReadEvents(channel) && !!channel?.getClient().options.isLocalUnreadCountEnabled;
|
|
414
|
+
var userHasReadReceipts = (client) => client.user?.privacy_settings?.read_receipts?.enabled ?? true;
|
|
409
415
|
function addFileToFormData(uri, name, contentType) {
|
|
410
416
|
const data = new FormData();
|
|
411
417
|
if (isReadableStream(uri) || isBuffer(uri) || isFileWebAPI(uri) || isBlobWebAPI(uri)) {
|
|
@@ -8567,6 +8573,7 @@ var MessageDeliveryReporter = class _MessageDeliveryReporter {
|
|
|
8567
8573
|
* @param options
|
|
8568
8574
|
*/
|
|
8569
8575
|
this.markRead = async (collection, options) => {
|
|
8576
|
+
if (!userHasReadReceipts(this.client)) return null;
|
|
8570
8577
|
let result = null;
|
|
8571
8578
|
if (isChannel(collection)) {
|
|
8572
8579
|
result = await collection.markAsReadRequest(options);
|
|
@@ -9911,6 +9918,33 @@ var Channel = class {
|
|
|
9911
9918
|
...data
|
|
9912
9919
|
});
|
|
9913
9920
|
}
|
|
9921
|
+
/**
|
|
9922
|
+
* markReadLocally - Resets this user's unread count locally, without any backend call. Intended for
|
|
9923
|
+
* channels that have read events disabled (e.g. livestreams) when the client is created with the
|
|
9924
|
+
* `isLocalUnreadCountEnabled` option. Dispatches a dedicated, client-only `message.read_locally` event
|
|
9925
|
+
* that runs through the same `_handleChannelEvent` read logic as a real `message.read` (minus the
|
|
9926
|
+
* delivery-report network sync), so the read-state update lives in one place. When offline support
|
|
9927
|
+
* is enabled, the offline DB persists the reset for read-events-disabled channels, so the local
|
|
9928
|
+
* count stays consistent across app restarts.
|
|
9929
|
+
*
|
|
9930
|
+
* @return {Event | undefined} The dispatched `message.read_locally` event, or `undefined` if there is no connected user.
|
|
9931
|
+
*/
|
|
9932
|
+
markReadLocally() {
|
|
9933
|
+
const client = this.getClient();
|
|
9934
|
+
if (!client.userID) return;
|
|
9935
|
+
const event = {
|
|
9936
|
+
channel_id: this.id,
|
|
9937
|
+
channel_type: this.type,
|
|
9938
|
+
cid: this.cid,
|
|
9939
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9940
|
+
last_read_message_id: this.lastMessage()?.id,
|
|
9941
|
+
team: this.data?.team,
|
|
9942
|
+
type: "message.read_locally",
|
|
9943
|
+
user: client.user
|
|
9944
|
+
};
|
|
9945
|
+
client.dispatchEvent(event);
|
|
9946
|
+
return event;
|
|
9947
|
+
}
|
|
9914
9948
|
/**
|
|
9915
9949
|
* clean - Cleans the channel state and fires stop typing if needed
|
|
9916
9950
|
*/
|
|
@@ -10066,7 +10100,7 @@ var Channel = class {
|
|
|
10066
10100
|
if (message.user?.id === this.getClient().userID) return false;
|
|
10067
10101
|
if (message.user?.id && this.getClient().userMuteStatus(message.user.id))
|
|
10068
10102
|
return false;
|
|
10069
|
-
if (
|
|
10103
|
+
if (!this.getClient().options.isLocalUnreadCountEnabled && !channelHasReadEvents(this)) {
|
|
10070
10104
|
return false;
|
|
10071
10105
|
}
|
|
10072
10106
|
if (this.getClient()._muteStatus(this.cid).muted) return false;
|
|
@@ -10477,6 +10511,11 @@ var Channel = class {
|
|
|
10477
10511
|
delete channelState.typing[event.user.id];
|
|
10478
10512
|
}
|
|
10479
10513
|
break;
|
|
10514
|
+
// `message.read_locally` is the client-only event dispatched by `markReadLocally()` when read
|
|
10515
|
+
// events are disabled (e.g. livestreams with `isLocalUnreadCountEnabled`). It reuses the exact
|
|
10516
|
+
// `message.read` state logic so the read-state update lives in one place — only the
|
|
10517
|
+
// delivery-report network sync below is skipped for it.
|
|
10518
|
+
case "message.read_locally":
|
|
10480
10519
|
case "message.read":
|
|
10481
10520
|
if (event.user?.id && event.created_at) {
|
|
10482
10521
|
const previousReadState = channelState.read[event.user.id];
|
|
@@ -10497,7 +10536,9 @@ var Channel = class {
|
|
|
10497
10536
|
const isOwnEvent = event.user?.id === client.user?.id;
|
|
10498
10537
|
if (isOwnEvent) {
|
|
10499
10538
|
channelState.unreadCount = 0;
|
|
10500
|
-
|
|
10539
|
+
if (event.type === "message.read") {
|
|
10540
|
+
client.syncDeliveredCandidates([this]);
|
|
10541
|
+
}
|
|
10501
10542
|
}
|
|
10502
10543
|
}
|
|
10503
10544
|
break;
|
|
@@ -14612,6 +14653,31 @@ var StreamChat = class _StreamChat {
|
|
|
14612
14653
|
* @return {Promise<APIResponse>}
|
|
14613
14654
|
*/
|
|
14614
14655
|
this.markAllRead = this.markChannelsRead;
|
|
14656
|
+
this.getUserAgent = () => {
|
|
14657
|
+
if (this.userAgent) {
|
|
14658
|
+
return this.userAgent;
|
|
14659
|
+
}
|
|
14660
|
+
if (!this.cachedUserAgent) {
|
|
14661
|
+
const version = "9.50.0";
|
|
14662
|
+
const { name: sdkName, version: sdkVersion } = this.sdkIdentifier ?? {};
|
|
14663
|
+
const { name: appName, version: appVersion } = this.appIdentifier ?? {};
|
|
14664
|
+
const { os, model: deviceModel } = this.deviceIdentifier ?? {};
|
|
14665
|
+
const head = sdkName ? `stream-chat-${sdkName}-v${sdkVersion}-llc-v${version}` : `stream-chat-js-v${version}-${this.node ? "node" : "browser"}`;
|
|
14666
|
+
this.cachedUserAgent = [
|
|
14667
|
+
head,
|
|
14668
|
+
// reports the host app, the device OS, the device model, and the picked
|
|
14669
|
+
// exports bundle, each only when a value is present
|
|
14670
|
+
...Object.entries({
|
|
14671
|
+
app: appName,
|
|
14672
|
+
app_version: appVersion,
|
|
14673
|
+
os,
|
|
14674
|
+
device_model: deviceModel,
|
|
14675
|
+
client_bundle: "browser-esm"
|
|
14676
|
+
}).filter(([, value]) => value && value.length > 0).map(([key, value]) => `${key}=${value}`)
|
|
14677
|
+
].join("|");
|
|
14678
|
+
}
|
|
14679
|
+
return this.cachedUserAgent;
|
|
14680
|
+
};
|
|
14615
14681
|
/**
|
|
14616
14682
|
* _isUsingServerAuth - Returns true if we're using server side auth
|
|
14617
14683
|
*/
|
|
@@ -14650,6 +14716,7 @@ var StreamChat = class _StreamChat {
|
|
|
14650
14716
|
warmUp: false,
|
|
14651
14717
|
recoverStateOnReconnect: true,
|
|
14652
14718
|
disableCache: false,
|
|
14719
|
+
isLocalUnreadCountEnabled: false,
|
|
14653
14720
|
wsUrlParams: new URLSearchParams({}),
|
|
14654
14721
|
...inputOptions
|
|
14655
14722
|
};
|
|
@@ -15064,6 +15131,13 @@ var StreamChat = class _StreamChat {
|
|
|
15064
15131
|
delete this.activeChannels[cid];
|
|
15065
15132
|
});
|
|
15066
15133
|
}
|
|
15134
|
+
if (event.type === "notification.removed_from_channel" && event.cid) {
|
|
15135
|
+
const { cid } = event;
|
|
15136
|
+
this.activeChannels[cid]?._disconnect();
|
|
15137
|
+
postListenerCallbacks.push(() => {
|
|
15138
|
+
delete this.activeChannels[cid];
|
|
15139
|
+
});
|
|
15140
|
+
}
|
|
15067
15141
|
return postListenerCallbacks;
|
|
15068
15142
|
}
|
|
15069
15143
|
_muteStatus(cid) {
|
|
@@ -16555,31 +16629,6 @@ var StreamChat = class _StreamChat {
|
|
|
16555
16629
|
partialThreadObject
|
|
16556
16630
|
);
|
|
16557
16631
|
}
|
|
16558
|
-
getUserAgent() {
|
|
16559
|
-
if (this.userAgent) {
|
|
16560
|
-
return this.userAgent;
|
|
16561
|
-
}
|
|
16562
|
-
const version = "9.48.0";
|
|
16563
|
-
const clientBundle = "browser-esm";
|
|
16564
|
-
let userAgentString = "";
|
|
16565
|
-
if (this.sdkIdentifier) {
|
|
16566
|
-
userAgentString = `stream-chat-${this.sdkIdentifier.name}-v${this.sdkIdentifier.version}-llc-v${version}`;
|
|
16567
|
-
} else {
|
|
16568
|
-
userAgentString = `stream-chat-js-v${version}-${this.node ? "node" : "browser"}`;
|
|
16569
|
-
}
|
|
16570
|
-
const { os, model } = this.deviceIdentifier ?? {};
|
|
16571
|
-
return [
|
|
16572
|
-
// reports the device OS, if provided
|
|
16573
|
-
["os", os],
|
|
16574
|
-
// reports the device model, if provided
|
|
16575
|
-
["device_model", model],
|
|
16576
|
-
// reports which bundle is being picked from the exports
|
|
16577
|
-
["client_bundle", clientBundle]
|
|
16578
|
-
].reduce(
|
|
16579
|
-
(withArguments, [key, value]) => value && value.length > 0 ? withArguments.concat(`|${key}=${value}`) : withArguments,
|
|
16580
|
-
userAgentString
|
|
16581
|
-
);
|
|
16582
|
-
}
|
|
16583
16632
|
/**
|
|
16584
16633
|
* @deprecated use sdkIdentifier instead
|
|
16585
16634
|
* @param userAgent
|
|
@@ -18021,6 +18070,7 @@ var EVENT_MAP = {
|
|
|
18021
18070
|
"ai_indicator.stop": true,
|
|
18022
18071
|
"ai_indicator.clear": true,
|
|
18023
18072
|
// local events
|
|
18073
|
+
"message.read_locally": true,
|
|
18024
18074
|
"channels.queried": true,
|
|
18025
18075
|
"offline_reactions.queried": true,
|
|
18026
18076
|
"connection.changed": true,
|
|
@@ -18404,7 +18454,8 @@ var AbstractOfflineDB = class {
|
|
|
18404
18454
|
if (cid && client.user && client.user.id !== user?.id) {
|
|
18405
18455
|
const userId = client.user.id;
|
|
18406
18456
|
const channel = client.activeChannels[cid];
|
|
18407
|
-
|
|
18457
|
+
const tracksReadLocally = channelTracksReadLocally(channel);
|
|
18458
|
+
if (channel && (channelHasReadEvents(channel) || tracksReadLocally)) {
|
|
18408
18459
|
const ownReads = channel.state.read[userId];
|
|
18409
18460
|
const unreadCount = channel.countUnread();
|
|
18410
18461
|
const upsertReadsQueries = await this.upsertReads({
|
|
@@ -18412,8 +18463,8 @@ var AbstractOfflineDB = class {
|
|
|
18412
18463
|
execute: false,
|
|
18413
18464
|
reads: [
|
|
18414
18465
|
{
|
|
18415
|
-
last_read: ownReads
|
|
18416
|
-
last_read_message_id: ownReads
|
|
18466
|
+
last_read: (ownReads?.last_read ?? /* @__PURE__ */ new Date(0)).toISOString(),
|
|
18467
|
+
last_read_message_id: ownReads?.last_read_message_id,
|
|
18417
18468
|
unread_messages: unreadCount,
|
|
18418
18469
|
user: client.user
|
|
18419
18470
|
}
|
|
@@ -18612,27 +18663,30 @@ var AbstractOfflineDB = class {
|
|
|
18612
18663
|
truncated_at,
|
|
18613
18664
|
execute: false
|
|
18614
18665
|
});
|
|
18666
|
+
let finalQueries = [...truncateQueries];
|
|
18615
18667
|
const userId = ownUser.id;
|
|
18616
18668
|
const activeChannel = this.client.activeChannels[cid];
|
|
18617
|
-
const
|
|
18618
|
-
|
|
18619
|
-
|
|
18620
|
-
|
|
18621
|
-
|
|
18669
|
+
const tracksReadLocally = channelTracksReadLocally(activeChannel);
|
|
18670
|
+
if (activeChannel && (channelHasReadEvents(activeChannel) || tracksReadLocally)) {
|
|
18671
|
+
const ownReads = activeChannel.state.read[userId];
|
|
18672
|
+
let unreadCount = 0;
|
|
18673
|
+
if (truncated_at) {
|
|
18674
|
+
unreadCount = activeChannel.countUnread(new Date(truncated_at));
|
|
18675
|
+
}
|
|
18676
|
+
const upsertReadQueries = await this.upsertReads({
|
|
18677
|
+
cid,
|
|
18678
|
+
execute: false,
|
|
18679
|
+
reads: [
|
|
18680
|
+
{
|
|
18681
|
+
last_read: (ownReads?.last_read ?? /* @__PURE__ */ new Date(0)).toString(),
|
|
18682
|
+
last_read_message_id: ownReads?.last_read_message_id,
|
|
18683
|
+
unread_messages: unreadCount,
|
|
18684
|
+
user: ownUser
|
|
18685
|
+
}
|
|
18686
|
+
]
|
|
18687
|
+
});
|
|
18688
|
+
finalQueries = [...finalQueries, ...upsertReadQueries];
|
|
18622
18689
|
}
|
|
18623
|
-
const upsertReadQueries = await this.upsertReads({
|
|
18624
|
-
cid,
|
|
18625
|
-
execute: false,
|
|
18626
|
-
reads: [
|
|
18627
|
-
{
|
|
18628
|
-
last_read: ownReads.last_read.toString(),
|
|
18629
|
-
last_read_message_id: ownReads.last_read_message_id,
|
|
18630
|
-
unread_messages: unreadCount,
|
|
18631
|
-
user: ownUser
|
|
18632
|
-
}
|
|
18633
|
-
]
|
|
18634
|
-
});
|
|
18635
|
-
const finalQueries = [...truncateQueries, ...upsertReadQueries];
|
|
18636
18690
|
if (execute) {
|
|
18637
18691
|
await this.executeSqlBatch(finalQueries);
|
|
18638
18692
|
}
|
|
@@ -18733,6 +18787,13 @@ var AbstractOfflineDB = class {
|
|
|
18733
18787
|
if (type === "message.read" || type === "notification.mark_read") {
|
|
18734
18788
|
return this.handleRead({ event, unreadMessages: 0, execute });
|
|
18735
18789
|
}
|
|
18790
|
+
if (type === "message.read_locally") {
|
|
18791
|
+
const localChannel = event.cid ? this.client.activeChannels[event.cid] : void 0;
|
|
18792
|
+
if (channelTracksReadLocally(localChannel)) {
|
|
18793
|
+
return this.handleRead({ event, unreadMessages: 0, execute });
|
|
18794
|
+
}
|
|
18795
|
+
return [];
|
|
18796
|
+
}
|
|
18736
18797
|
if (type === "notification.mark_unread") {
|
|
18737
18798
|
return this.handleRead({ event, execute });
|
|
18738
18799
|
}
|