stream-chat 9.6.0 → 9.7.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.cjs +383 -65
- package/dist/cjs/index.browser.cjs.map +3 -3
- package/dist/cjs/index.node.cjs +387 -68
- package/dist/cjs/index.node.cjs.map +3 -3
- package/dist/esm/index.js +383 -65
- package/dist/esm/index.js.map +3 -3
- package/dist/types/channel.d.ts +36 -4
- package/dist/types/client.d.ts +38 -0
- package/dist/types/messageComposer/messageComposer.d.ts +4 -1
- package/dist/types/messageComposer/middleware/textComposer/commands.d.ts +5 -5
- package/dist/types/messageComposer/middleware/textComposer/mentions.d.ts +1 -2
- package/dist/types/messageComposer/middleware/textComposer/types.d.ts +2 -2
- package/dist/types/offline-support/offline_support_api.d.ts +39 -0
- package/dist/types/offline-support/types.d.ts +36 -2
- package/dist/types/search/BaseSearchSource.d.ts +37 -31
- package/dist/types/search/ChannelSearchSource.d.ts +1 -1
- package/dist/types/search/MessageSearchSource.d.ts +1 -1
- package/dist/types/search/UserSearchSource.d.ts +1 -1
- package/dist/types/search/index.d.ts +1 -0
- package/dist/types/search/types.d.ts +20 -0
- package/dist/types/types.d.ts +5 -1
- package/dist/types/utils/WithSubscriptions.d.ts +7 -2
- package/dist/types/utils.d.ts +11 -2
- package/package.json +1 -1
- package/src/channel.ts +85 -10
- package/src/client.ts +61 -3
- package/src/messageComposer/messageComposer.ts +136 -32
- package/src/messageComposer/middleware/textComposer/commands.ts +6 -7
- package/src/messageComposer/middleware/textComposer/mentions.ts +1 -2
- package/src/messageComposer/middleware/textComposer/types.ts +2 -2
- package/src/offline-support/offline_support_api.ts +79 -0
- package/src/offline-support/types.ts +41 -1
- package/src/search/BaseSearchSource.ts +123 -52
- package/src/search/ChannelSearchSource.ts +1 -1
- package/src/search/MessageSearchSource.ts +1 -1
- package/src/search/UserSearchSource.ts +1 -1
- package/src/search/index.ts +1 -0
- package/src/search/types.ts +20 -0
- package/src/types.ts +8 -1
- package/src/utils/WithSubscriptions.ts +16 -2
- package/src/utils.ts +31 -2
|
@@ -161,6 +161,7 @@ __export(index_exports, {
|
|
|
161
161
|
AttachmentManager: () => AttachmentManager,
|
|
162
162
|
BasePaginator: () => BasePaginator,
|
|
163
163
|
BaseSearchSource: () => BaseSearchSource,
|
|
164
|
+
BaseSearchSourceSync: () => BaseSearchSourceSync,
|
|
164
165
|
BuiltinPermissions: () => BuiltinPermissions,
|
|
165
166
|
BuiltinRoles: () => BuiltinRoles,
|
|
166
167
|
Campaign: () => Campaign,
|
|
@@ -2757,6 +2758,23 @@ function formatMessage(message) {
|
|
|
2757
2758
|
quoted_message: toLocalMessageBase(message.quoted_message)
|
|
2758
2759
|
};
|
|
2759
2760
|
}
|
|
2761
|
+
function unformatMessage(message) {
|
|
2762
|
+
const toMessageResponseBase = (msg) => {
|
|
2763
|
+
if (!msg) return null;
|
|
2764
|
+
const newDateString = (/* @__PURE__ */ new Date()).toISOString();
|
|
2765
|
+
return {
|
|
2766
|
+
...msg,
|
|
2767
|
+
created_at: message.created_at ? message.created_at.toISOString() : newDateString,
|
|
2768
|
+
deleted_at: message.deleted_at ? message.deleted_at.toISOString() : void 0,
|
|
2769
|
+
pinned_at: message.pinned_at ? message.pinned_at.toISOString() : void 0,
|
|
2770
|
+
updated_at: message.updated_at ? message.updated_at.toISOString() : newDateString
|
|
2771
|
+
};
|
|
2772
|
+
};
|
|
2773
|
+
return {
|
|
2774
|
+
...toMessageResponseBase(message),
|
|
2775
|
+
quoted_message: toMessageResponseBase(message.quoted_message)
|
|
2776
|
+
};
|
|
2777
|
+
}
|
|
2760
2778
|
var localMessageToNewMessagePayload = (localMessage) => {
|
|
2761
2779
|
const {
|
|
2762
2780
|
// Remove all timestamp fields and client-specific fields.
|
|
@@ -6296,11 +6314,8 @@ var DEFAULT_SEARCH_SOURCE_OPTIONS = {
|
|
|
6296
6314
|
debounceMs: 300,
|
|
6297
6315
|
pageSize: 10
|
|
6298
6316
|
};
|
|
6299
|
-
var
|
|
6317
|
+
var BaseSearchSourceBase = class {
|
|
6300
6318
|
constructor(options) {
|
|
6301
|
-
this.setDebounceOptions = ({ debounceMs }) => {
|
|
6302
|
-
this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);
|
|
6303
|
-
};
|
|
6304
6319
|
this.activate = () => {
|
|
6305
6320
|
if (this.isActive) return;
|
|
6306
6321
|
this.state.partialNext({ isActive: true });
|
|
@@ -6314,11 +6329,9 @@ var BaseSearchSource = class {
|
|
|
6314
6329
|
const searchString = newSearchString ?? this.searchQuery;
|
|
6315
6330
|
return !!(this.isActive && !this.isLoading && (this.hasNext || hasNewSearchQuery) && searchString);
|
|
6316
6331
|
};
|
|
6317
|
-
|
|
6318
|
-
const { debounceMs, pageSize } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
|
|
6332
|
+
const { pageSize } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
|
|
6319
6333
|
this.pageSize = pageSize;
|
|
6320
6334
|
this.state = new StateStore(this.initialState);
|
|
6321
|
-
this.setDebounceOptions({ debounceMs });
|
|
6322
6335
|
}
|
|
6323
6336
|
get lastQueryError() {
|
|
6324
6337
|
return this.state.getLatestValue().lastQueryError;
|
|
@@ -6378,8 +6391,7 @@ var BaseSearchSource = class {
|
|
|
6378
6391
|
items: isFirstPage ? stateUpdate.items : [...this.items ?? [], ...stateUpdate.items || []]
|
|
6379
6392
|
};
|
|
6380
6393
|
}
|
|
6381
|
-
|
|
6382
|
-
if (!this.canExecuteQuery(newSearchString)) return;
|
|
6394
|
+
prepareStateForQuery(newSearchString) {
|
|
6383
6395
|
const hasNewSearchQuery = typeof newSearchString !== "undefined";
|
|
6384
6396
|
const searchString = newSearchString ?? this.searchQuery;
|
|
6385
6397
|
if (hasNewSearchQuery) {
|
|
@@ -6387,18 +6399,47 @@ var BaseSearchSource = class {
|
|
|
6387
6399
|
} else {
|
|
6388
6400
|
this.state.partialNext({ isLoading: true });
|
|
6389
6401
|
}
|
|
6402
|
+
return { searchString, hasNewSearchQuery };
|
|
6403
|
+
}
|
|
6404
|
+
updatePaginationStateFromQuery(result) {
|
|
6405
|
+
const { items, next } = result;
|
|
6390
6406
|
const stateUpdate = {};
|
|
6407
|
+
if (next || next === null) {
|
|
6408
|
+
stateUpdate.next = next;
|
|
6409
|
+
stateUpdate.hasNext = !!next;
|
|
6410
|
+
} else {
|
|
6411
|
+
stateUpdate.offset = (this.offset ?? 0) + items.length;
|
|
6412
|
+
stateUpdate.hasNext = items.length === this.pageSize;
|
|
6413
|
+
}
|
|
6414
|
+
return stateUpdate;
|
|
6415
|
+
}
|
|
6416
|
+
resetState() {
|
|
6417
|
+
this.state.next(this.initialState);
|
|
6418
|
+
}
|
|
6419
|
+
resetStateAndActivate() {
|
|
6420
|
+
this.resetState();
|
|
6421
|
+
this.activate();
|
|
6422
|
+
}
|
|
6423
|
+
};
|
|
6424
|
+
var BaseSearchSource = class extends BaseSearchSourceBase {
|
|
6425
|
+
constructor(options) {
|
|
6426
|
+
const { debounceMs } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
|
|
6427
|
+
super(options);
|
|
6428
|
+
this.setDebounceOptions = ({ debounceMs }) => {
|
|
6429
|
+
this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);
|
|
6430
|
+
};
|
|
6431
|
+
this.search = (searchQuery) => this.searchDebounced(searchQuery);
|
|
6432
|
+
this.setDebounceOptions({ debounceMs });
|
|
6433
|
+
}
|
|
6434
|
+
async executeQuery(newSearchString) {
|
|
6435
|
+
if (!this.canExecuteQuery(newSearchString)) return;
|
|
6436
|
+
const { hasNewSearchQuery, searchString } = this.prepareStateForQuery(newSearchString);
|
|
6437
|
+
let stateUpdate = {};
|
|
6391
6438
|
try {
|
|
6392
6439
|
const results = await this.query(searchString);
|
|
6393
6440
|
if (!results) return;
|
|
6394
|
-
const { items
|
|
6395
|
-
|
|
6396
|
-
stateUpdate.next = next;
|
|
6397
|
-
stateUpdate.hasNext = !!next;
|
|
6398
|
-
} else {
|
|
6399
|
-
stateUpdate.offset = (this.offset ?? 0) + items.length;
|
|
6400
|
-
stateUpdate.hasNext = items.length === this.pageSize;
|
|
6401
|
-
}
|
|
6441
|
+
const { items } = results;
|
|
6442
|
+
stateUpdate = this.updatePaginationStateFromQuery(results);
|
|
6402
6443
|
stateUpdate.items = await this.filterQueryResults(items);
|
|
6403
6444
|
} catch (e) {
|
|
6404
6445
|
stateUpdate.lastQueryError = e;
|
|
@@ -6409,12 +6450,35 @@ var BaseSearchSource = class {
|
|
|
6409
6450
|
cancelScheduledQuery() {
|
|
6410
6451
|
this.searchDebounced.cancel();
|
|
6411
6452
|
}
|
|
6412
|
-
|
|
6413
|
-
|
|
6453
|
+
};
|
|
6454
|
+
var BaseSearchSourceSync = class extends BaseSearchSourceBase {
|
|
6455
|
+
constructor(options) {
|
|
6456
|
+
const { debounceMs } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
|
|
6457
|
+
super(options);
|
|
6458
|
+
this.setDebounceOptions = ({ debounceMs }) => {
|
|
6459
|
+
this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);
|
|
6460
|
+
};
|
|
6461
|
+
this.search = (searchQuery) => this.searchDebounced(searchQuery);
|
|
6462
|
+
this.setDebounceOptions({ debounceMs });
|
|
6414
6463
|
}
|
|
6415
|
-
|
|
6416
|
-
this.
|
|
6417
|
-
this.
|
|
6464
|
+
executeQuery(newSearchString) {
|
|
6465
|
+
if (!this.canExecuteQuery(newSearchString)) return;
|
|
6466
|
+
const { hasNewSearchQuery, searchString } = this.prepareStateForQuery(newSearchString);
|
|
6467
|
+
let stateUpdate = {};
|
|
6468
|
+
try {
|
|
6469
|
+
const results = this.query(searchString);
|
|
6470
|
+
if (!results) return;
|
|
6471
|
+
const { items } = results;
|
|
6472
|
+
stateUpdate = this.updatePaginationStateFromQuery(results);
|
|
6473
|
+
stateUpdate.items = this.filterQueryResults(items);
|
|
6474
|
+
} catch (e) {
|
|
6475
|
+
stateUpdate.lastQueryError = e;
|
|
6476
|
+
} finally {
|
|
6477
|
+
this.state.next(this.getStateAfterQuery(stateUpdate, hasNewSearchQuery));
|
|
6478
|
+
}
|
|
6479
|
+
}
|
|
6480
|
+
cancelScheduledQuery() {
|
|
6481
|
+
this.searchDebounced.cancel();
|
|
6418
6482
|
}
|
|
6419
6483
|
};
|
|
6420
6484
|
|
|
@@ -6697,7 +6761,7 @@ var getTokenizedSuggestionDisplayName = ({
|
|
|
6697
6761
|
});
|
|
6698
6762
|
|
|
6699
6763
|
// src/messageComposer/middleware/textComposer/commands.ts
|
|
6700
|
-
var CommandSearchSource = class extends
|
|
6764
|
+
var CommandSearchSource = class extends BaseSearchSourceSync {
|
|
6701
6765
|
constructor(channel, options) {
|
|
6702
6766
|
super(options);
|
|
6703
6767
|
this.type = "commands";
|
|
@@ -6741,10 +6805,10 @@ var CommandSearchSource = class extends BaseSearchSource {
|
|
|
6741
6805
|
}
|
|
6742
6806
|
return 0;
|
|
6743
6807
|
});
|
|
6744
|
-
return
|
|
6808
|
+
return {
|
|
6745
6809
|
items: selectedCommands.map((c) => ({ ...c, id: c.name })),
|
|
6746
6810
|
next: null
|
|
6747
|
-
}
|
|
6811
|
+
};
|
|
6748
6812
|
}
|
|
6749
6813
|
filterQueryResults(items) {
|
|
6750
6814
|
return items;
|
|
@@ -7352,6 +7416,7 @@ var TextComposer = class {
|
|
|
7352
7416
|
var _WithSubscriptions = class _WithSubscriptions {
|
|
7353
7417
|
constructor() {
|
|
7354
7418
|
this.unsubscribeFunctions = /* @__PURE__ */ new Set();
|
|
7419
|
+
this.refCount = 0;
|
|
7355
7420
|
}
|
|
7356
7421
|
/**
|
|
7357
7422
|
* Returns a boolean, provides information of whether `registerSubscriptions`
|
|
@@ -7363,6 +7428,12 @@ var _WithSubscriptions = class _WithSubscriptions {
|
|
|
7363
7428
|
addUnsubscribeFunction(unsubscribeFunction) {
|
|
7364
7429
|
this.unsubscribeFunctions.add(unsubscribeFunction);
|
|
7365
7430
|
}
|
|
7431
|
+
/**
|
|
7432
|
+
* Increments `refCount` by one and returns new value.
|
|
7433
|
+
*/
|
|
7434
|
+
incrementRefCount() {
|
|
7435
|
+
return ++this.refCount;
|
|
7436
|
+
}
|
|
7366
7437
|
/**
|
|
7367
7438
|
* If you re-declare `unregisterSubscriptions` method within your class
|
|
7368
7439
|
* make sure to run the original too.
|
|
@@ -7379,8 +7450,13 @@ var _WithSubscriptions = class _WithSubscriptions {
|
|
|
7379
7450
|
* ```
|
|
7380
7451
|
*/
|
|
7381
7452
|
unregisterSubscriptions() {
|
|
7453
|
+
if (this.refCount > 1) {
|
|
7454
|
+
this.refCount--;
|
|
7455
|
+
return _WithSubscriptions.symbol;
|
|
7456
|
+
}
|
|
7382
7457
|
this.unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());
|
|
7383
7458
|
this.unsubscribeFunctions.clear();
|
|
7459
|
+
this.refCount = 0;
|
|
7384
7460
|
return _WithSubscriptions.symbol;
|
|
7385
7461
|
}
|
|
7386
7462
|
};
|
|
@@ -7866,7 +7942,6 @@ var initState5 = (composition) => {
|
|
|
7866
7942
|
showReplyInChannel: false
|
|
7867
7943
|
};
|
|
7868
7944
|
};
|
|
7869
|
-
var noop3 = () => void 0;
|
|
7870
7945
|
var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
7871
7946
|
// todo: mediaRecorder: MediaRecorderController;
|
|
7872
7947
|
constructor({
|
|
@@ -7891,22 +7966,48 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
7891
7966
|
this.editedMessage = message;
|
|
7892
7967
|
}
|
|
7893
7968
|
};
|
|
7969
|
+
this.initStateFromChannelResponse = (channelApiResponse) => {
|
|
7970
|
+
if (this.channel.cid !== channelApiResponse.channel.cid) {
|
|
7971
|
+
return;
|
|
7972
|
+
}
|
|
7973
|
+
if (channelApiResponse.draft) {
|
|
7974
|
+
this.initState({ composition: channelApiResponse.draft });
|
|
7975
|
+
} else if (this.state.getLatestValue().draftId) {
|
|
7976
|
+
this.clear();
|
|
7977
|
+
this.client.offlineDb?.executeQuerySafely(
|
|
7978
|
+
(db) => db.deleteDraft({
|
|
7979
|
+
cid: this.channel.cid,
|
|
7980
|
+
parent_id: void 0
|
|
7981
|
+
// makes sure that we don't delete thread drafts while upserting channels
|
|
7982
|
+
}),
|
|
7983
|
+
{ method: "deleteDraft" }
|
|
7984
|
+
);
|
|
7985
|
+
}
|
|
7986
|
+
};
|
|
7894
7987
|
this.initEditingAuditState = (composition) => initEditingAuditState(composition);
|
|
7988
|
+
this.registerDraftEventSubscriptions = () => {
|
|
7989
|
+
const unsubscribeDraftUpdated = this.subscribeDraftUpdated();
|
|
7990
|
+
const unsubscribeDraftDeleted = this.subscribeDraftDeleted();
|
|
7991
|
+
return () => {
|
|
7992
|
+
unsubscribeDraftUpdated();
|
|
7993
|
+
unsubscribeDraftDeleted();
|
|
7994
|
+
};
|
|
7995
|
+
};
|
|
7895
7996
|
this.registerSubscriptions = () => {
|
|
7896
|
-
if (this.hasSubscriptions) {
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
|
|
7907
|
-
|
|
7908
|
-
this.
|
|
7909
|
-
return this.unregisterSubscriptions
|
|
7997
|
+
if (!this.hasSubscriptions) {
|
|
7998
|
+
this.addUnsubscribeFunction(this.subscribeMessageComposerSetupStateChange());
|
|
7999
|
+
this.addUnsubscribeFunction(this.subscribeMessageUpdated());
|
|
8000
|
+
this.addUnsubscribeFunction(this.subscribeMessageDeleted());
|
|
8001
|
+
this.addUnsubscribeFunction(this.subscribeTextComposerStateChanged());
|
|
8002
|
+
this.addUnsubscribeFunction(this.subscribeAttachmentManagerStateChanged());
|
|
8003
|
+
this.addUnsubscribeFunction(this.subscribeLinkPreviewsManagerStateChanged());
|
|
8004
|
+
this.addUnsubscribeFunction(this.subscribePollComposerStateChanged());
|
|
8005
|
+
this.addUnsubscribeFunction(this.subscribeCustomDataManagerStateChanged());
|
|
8006
|
+
this.addUnsubscribeFunction(this.subscribeMessageComposerStateChanged());
|
|
8007
|
+
this.addUnsubscribeFunction(this.subscribeMessageComposerConfigStateChanged());
|
|
8008
|
+
}
|
|
8009
|
+
this.incrementRefCount();
|
|
8010
|
+
return () => this.unregisterSubscriptions();
|
|
7910
8011
|
};
|
|
7911
8012
|
this.subscribeMessageUpdated = () => {
|
|
7912
8013
|
const eventTypes = [
|
|
@@ -7956,13 +8057,13 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
7956
8057
|
}).unsubscribe;
|
|
7957
8058
|
this.subscribeDraftUpdated = () => this.client.on("draft.updated", (event) => {
|
|
7958
8059
|
const draft = event.draft;
|
|
7959
|
-
if (!draft ||
|
|
8060
|
+
if (!draft || (draft.parent_id ?? null) !== (this.threadId ?? null) || draft.channel_cid !== this.channel.cid)
|
|
7960
8061
|
return;
|
|
7961
8062
|
this.initState({ composition: draft });
|
|
7962
8063
|
}).unsubscribe;
|
|
7963
8064
|
this.subscribeDraftDeleted = () => this.client.on("draft.deleted", (event) => {
|
|
7964
8065
|
const draft = event.draft;
|
|
7965
|
-
if (!draft ||
|
|
8066
|
+
if (!draft || (draft.parent_id ?? null) !== (this.threadId ?? null) || draft.channel_cid !== this.channel.cid) {
|
|
7966
8067
|
return;
|
|
7967
8068
|
}
|
|
7968
8069
|
this.logDraftUpdateTimestamp();
|
|
@@ -8026,7 +8127,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8026
8127
|
}
|
|
8027
8128
|
});
|
|
8028
8129
|
this.subscribeMessageComposerConfigStateChanged = () => {
|
|
8029
|
-
let
|
|
8130
|
+
let draftUnsubscribeFunction;
|
|
8030
8131
|
const unsubscribe = this.configState.subscribeWithSelector(
|
|
8031
8132
|
(currentValue) => ({
|
|
8032
8133
|
textDefaultValue: currentValue.text.defaultValue,
|
|
@@ -8039,19 +8140,16 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8039
8140
|
selection: { start: 0, end: 0 }
|
|
8040
8141
|
});
|
|
8041
8142
|
}
|
|
8042
|
-
if (draftsEnabled && !
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
} else if (!draftsEnabled && draftUnsubscribeFunctions) {
|
|
8048
|
-
draftUnsubscribeFunctions.forEach((fn) => fn());
|
|
8049
|
-
draftUnsubscribeFunctions = null;
|
|
8143
|
+
if (draftsEnabled && !draftUnsubscribeFunction) {
|
|
8144
|
+
draftUnsubscribeFunction = this.registerDraftEventSubscriptions();
|
|
8145
|
+
} else if (!draftsEnabled && draftUnsubscribeFunction) {
|
|
8146
|
+
draftUnsubscribeFunction();
|
|
8147
|
+
draftUnsubscribeFunction = null;
|
|
8050
8148
|
}
|
|
8051
8149
|
}
|
|
8052
8150
|
);
|
|
8053
8151
|
return () => {
|
|
8054
|
-
|
|
8152
|
+
draftUnsubscribeFunction?.();
|
|
8055
8153
|
unsubscribe();
|
|
8056
8154
|
};
|
|
8057
8155
|
};
|
|
@@ -8121,14 +8219,78 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8121
8219
|
if (!composition) return;
|
|
8122
8220
|
const { draft } = composition;
|
|
8123
8221
|
this.state.partialNext({ draftId: draft.id });
|
|
8222
|
+
if (this.client.offlineDb) {
|
|
8223
|
+
try {
|
|
8224
|
+
const optimisticDraftResponse = {
|
|
8225
|
+
channel_cid: this.channel.cid,
|
|
8226
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8227
|
+
message: draft,
|
|
8228
|
+
parent_id: draft.parent_id,
|
|
8229
|
+
quoted_message: this.quotedMessage ? unformatMessage(this.quotedMessage) : void 0
|
|
8230
|
+
};
|
|
8231
|
+
await this.client.offlineDb.upsertDraft({ draft: optimisticDraftResponse });
|
|
8232
|
+
} catch (error) {
|
|
8233
|
+
this.client.logger("error", `offlineDb:upsertDraft`, {
|
|
8234
|
+
tags: ["channel", "offlineDb"],
|
|
8235
|
+
error
|
|
8236
|
+
});
|
|
8237
|
+
}
|
|
8238
|
+
}
|
|
8124
8239
|
this.logDraftUpdateTimestamp();
|
|
8125
8240
|
await this.channel.createDraft(draft);
|
|
8126
8241
|
};
|
|
8127
8242
|
this.deleteDraft = async () => {
|
|
8128
8243
|
if (this.editedMessage || !this.config.drafts.enabled || !this.draftId) return;
|
|
8129
8244
|
this.state.partialNext({ draftId: null });
|
|
8245
|
+
const parentId = this.threadId ?? void 0;
|
|
8246
|
+
if (this.client.offlineDb) {
|
|
8247
|
+
try {
|
|
8248
|
+
await this.client.offlineDb.deleteDraft({
|
|
8249
|
+
cid: this.channel.cid,
|
|
8250
|
+
parent_id: parentId
|
|
8251
|
+
});
|
|
8252
|
+
} catch (error) {
|
|
8253
|
+
this.client.logger("error", `offlineDb:deleteDraft`, {
|
|
8254
|
+
tags: ["channel", "offlineDb"],
|
|
8255
|
+
error
|
|
8256
|
+
});
|
|
8257
|
+
}
|
|
8258
|
+
}
|
|
8130
8259
|
this.logDraftUpdateTimestamp();
|
|
8131
|
-
await this.channel.deleteDraft({ parent_id:
|
|
8260
|
+
await this.channel.deleteDraft({ parent_id: parentId });
|
|
8261
|
+
};
|
|
8262
|
+
this.getDraft = async () => {
|
|
8263
|
+
if (this.editedMessage || !this.config.drafts.enabled || !this.client.userID) return;
|
|
8264
|
+
const draftFromOfflineDB = await this.client.offlineDb?.getDraft({
|
|
8265
|
+
cid: this.channel.cid,
|
|
8266
|
+
userId: this.client.userID,
|
|
8267
|
+
parent_id: this.threadId ?? void 0
|
|
8268
|
+
});
|
|
8269
|
+
if (draftFromOfflineDB) {
|
|
8270
|
+
this.initState({ composition: draftFromOfflineDB });
|
|
8271
|
+
}
|
|
8272
|
+
try {
|
|
8273
|
+
const response = await this.channel.getDraft({
|
|
8274
|
+
parent_id: this.threadId ?? void 0
|
|
8275
|
+
});
|
|
8276
|
+
const { draft } = response;
|
|
8277
|
+
if (!draft) return;
|
|
8278
|
+
this.client.offlineDb?.executeQuerySafely(
|
|
8279
|
+
(db) => db.upsertDraft({
|
|
8280
|
+
draft
|
|
8281
|
+
}),
|
|
8282
|
+
{ method: "upsertDraft" }
|
|
8283
|
+
);
|
|
8284
|
+
this.initState({ composition: draft });
|
|
8285
|
+
} catch (error) {
|
|
8286
|
+
this.client.notifications.add({
|
|
8287
|
+
message: "Failed to get the draft",
|
|
8288
|
+
origin: {
|
|
8289
|
+
emitter: "MessageComposer",
|
|
8290
|
+
context: { composer: this }
|
|
8291
|
+
}
|
|
8292
|
+
});
|
|
8293
|
+
}
|
|
8132
8294
|
};
|
|
8133
8295
|
this.createPoll = async () => {
|
|
8134
8296
|
const composition = await this.pollComposer.compose();
|
|
@@ -8257,6 +8419,9 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8257
8419
|
return this.state.getLatestValue().showReplyInChannel;
|
|
8258
8420
|
}
|
|
8259
8421
|
get hasSendableData() {
|
|
8422
|
+
if (this.client.offlineDb) {
|
|
8423
|
+
return !this.compositionIsEmpty;
|
|
8424
|
+
}
|
|
8260
8425
|
return !!(!this.attachmentManager.uploadsInProgressCount && (!this.textComposer.textIsEmpty || this.attachmentManager.successfulUploadsCount > 0) || this.pollId);
|
|
8261
8426
|
}
|
|
8262
8427
|
get compositionIsEmpty() {
|
|
@@ -8572,6 +8737,17 @@ var Channel = class {
|
|
|
8572
8737
|
updates
|
|
8573
8738
|
);
|
|
8574
8739
|
}
|
|
8740
|
+
/**
|
|
8741
|
+
* sendReaction - Sends a reaction to a message. If offline support is enabled, it will make sure
|
|
8742
|
+
* that sending the reaction is queued up if it fails due to bad internet conditions and executed
|
|
8743
|
+
* later.
|
|
8744
|
+
*
|
|
8745
|
+
* @param {string} messageID the message id
|
|
8746
|
+
* @param {Reaction} reaction the reaction object for instance {type: 'love'}
|
|
8747
|
+
* @param {{ enforce_unique?: boolean, skip_push?: boolean }} [options] Option object, {enforce_unique: true, skip_push: true} to override any existing reaction or skip sending push notifications
|
|
8748
|
+
*
|
|
8749
|
+
* @return {Promise<ReactionAPIResponse>} The Server Response
|
|
8750
|
+
*/
|
|
8575
8751
|
async sendReaction(messageID, reaction, options) {
|
|
8576
8752
|
if (!messageID) {
|
|
8577
8753
|
throw Error(`Message id is missing`);
|
|
@@ -9424,9 +9600,7 @@ var Channel = class {
|
|
|
9424
9600
|
};
|
|
9425
9601
|
this.getClient().polls.hydratePollCache(state.messages, true);
|
|
9426
9602
|
this.getClient().reminders.hydrateState(state.messages);
|
|
9427
|
-
|
|
9428
|
-
this.messageComposer.initState({ composition: state.draft });
|
|
9429
|
-
}
|
|
9603
|
+
this.messageComposer.initStateFromChannelResponse(state);
|
|
9430
9604
|
const areCapabilitiesChanged = [...state.channel.own_capabilities || []].sort().join() !== [
|
|
9431
9605
|
...this.data && Array.isArray(this.data?.own_capabilities) ? this.data.own_capabilities : []
|
|
9432
9606
|
].sort().join();
|
|
@@ -9553,13 +9727,11 @@ var Channel = class {
|
|
|
9553
9727
|
/**
|
|
9554
9728
|
* createDraft - Creates or updates a draft message in a channel
|
|
9555
9729
|
*
|
|
9556
|
-
* @param {string} channelType The channel type
|
|
9557
|
-
* @param {string} channelID The channel ID
|
|
9558
9730
|
* @param {DraftMessagePayload} message The draft message to create or update
|
|
9559
9731
|
*
|
|
9560
9732
|
* @return {Promise<CreateDraftResponse>} Response containing the created draft
|
|
9561
9733
|
*/
|
|
9562
|
-
async
|
|
9734
|
+
async _createDraft(message) {
|
|
9563
9735
|
return await this.getClient().post(
|
|
9564
9736
|
this._channelURL() + "/draft",
|
|
9565
9737
|
{
|
|
@@ -9568,18 +9740,82 @@ var Channel = class {
|
|
|
9568
9740
|
);
|
|
9569
9741
|
}
|
|
9570
9742
|
/**
|
|
9571
|
-
*
|
|
9743
|
+
* createDraft - Creates or updates a draft message in a channel. If offline support is
|
|
9744
|
+
* enabled, it will make sure that creating the draft is queued up if it fails due to
|
|
9745
|
+
* bad internet conditions and executed later.
|
|
9746
|
+
*
|
|
9747
|
+
* @param {DraftMessagePayload} message The draft message to create or update
|
|
9748
|
+
*
|
|
9749
|
+
* @return {Promise<CreateDraftResponse>} Response containing the created draft
|
|
9750
|
+
*/
|
|
9751
|
+
async createDraft(message) {
|
|
9752
|
+
try {
|
|
9753
|
+
const offlineDb = this.getClient().offlineDb;
|
|
9754
|
+
if (offlineDb) {
|
|
9755
|
+
return await offlineDb.queueTask({
|
|
9756
|
+
task: {
|
|
9757
|
+
channelId: this.id,
|
|
9758
|
+
channelType: this.type,
|
|
9759
|
+
threadId: message.parent_id,
|
|
9760
|
+
payload: [message],
|
|
9761
|
+
type: "create-draft"
|
|
9762
|
+
}
|
|
9763
|
+
});
|
|
9764
|
+
}
|
|
9765
|
+
} catch (error) {
|
|
9766
|
+
this._client.logger("error", `offlineDb:create-draft`, {
|
|
9767
|
+
tags: ["channel", "offlineDb"],
|
|
9768
|
+
error
|
|
9769
|
+
});
|
|
9770
|
+
}
|
|
9771
|
+
return this._createDraft(message);
|
|
9772
|
+
}
|
|
9773
|
+
/**
|
|
9774
|
+
* deleteDraft - Deletes a draft message from a channel or a thread.
|
|
9572
9775
|
*
|
|
9573
9776
|
* @param {Object} options
|
|
9574
9777
|
* @param {string} options.parent_id Optional parent message ID for drafts in threads
|
|
9575
9778
|
*
|
|
9576
9779
|
* @return {Promise<APIResponse>} API response
|
|
9577
9780
|
*/
|
|
9578
|
-
async
|
|
9781
|
+
async _deleteDraft({ parent_id } = {}) {
|
|
9579
9782
|
return await this.getClient().delete(this._channelURL() + "/draft", {
|
|
9580
9783
|
parent_id
|
|
9581
9784
|
});
|
|
9582
9785
|
}
|
|
9786
|
+
/**
|
|
9787
|
+
* deleteDraft - Deletes a draft message from a channel or a thread. If offline support is
|
|
9788
|
+
* enabled, it will make sure that deleting the draft is queued up if it fails due to
|
|
9789
|
+
* bad internet conditions and executed later.
|
|
9790
|
+
*
|
|
9791
|
+
* @param {Object} options
|
|
9792
|
+
* @param {string} options.parent_id Optional parent message ID for drafts in threads
|
|
9793
|
+
*
|
|
9794
|
+
* @return {Promise<APIResponse>} API response
|
|
9795
|
+
*/
|
|
9796
|
+
async deleteDraft(options = {}) {
|
|
9797
|
+
const { parent_id } = options;
|
|
9798
|
+
try {
|
|
9799
|
+
const offlineDb = this.getClient().offlineDb;
|
|
9800
|
+
if (offlineDb) {
|
|
9801
|
+
return await offlineDb.queueTask({
|
|
9802
|
+
task: {
|
|
9803
|
+
channelId: this.id,
|
|
9804
|
+
channelType: this.type,
|
|
9805
|
+
threadId: parent_id,
|
|
9806
|
+
payload: [options],
|
|
9807
|
+
type: "delete-draft"
|
|
9808
|
+
}
|
|
9809
|
+
});
|
|
9810
|
+
}
|
|
9811
|
+
} catch (error) {
|
|
9812
|
+
this._client.logger("error", `offlineDb:delete-draft`, {
|
|
9813
|
+
tags: ["channel", "offlineDb"],
|
|
9814
|
+
error
|
|
9815
|
+
});
|
|
9816
|
+
}
|
|
9817
|
+
return this._deleteDraft(options);
|
|
9818
|
+
}
|
|
9583
9819
|
/**
|
|
9584
9820
|
* getDraft - Retrieves a draft message from a channel
|
|
9585
9821
|
*
|
|
@@ -14229,9 +14465,7 @@ var StreamChat = class _StreamChat {
|
|
|
14229
14465
|
this.polls.hydratePollCache(channelState.messages, true);
|
|
14230
14466
|
this.reminders.hydrateState(channelState.messages);
|
|
14231
14467
|
}
|
|
14232
|
-
|
|
14233
|
-
c.messageComposer.initState({ composition: channelState.draft });
|
|
14234
|
-
}
|
|
14468
|
+
c.messageComposer.initStateFromChannelResponse(channelState);
|
|
14235
14469
|
channels.push(c);
|
|
14236
14470
|
}
|
|
14237
14471
|
return channels;
|
|
@@ -15148,7 +15382,7 @@ var StreamChat = class _StreamChat {
|
|
|
15148
15382
|
if (this.userAgent) {
|
|
15149
15383
|
return this.userAgent;
|
|
15150
15384
|
}
|
|
15151
|
-
const version = "9.
|
|
15385
|
+
const version = "9.7.0";
|
|
15152
15386
|
const clientBundle = "browser-cjs";
|
|
15153
15387
|
let userAgentString = "";
|
|
15154
15388
|
if (this.sdkIdentifier) {
|
|
@@ -16237,6 +16471,52 @@ var StreamChat = class _StreamChat {
|
|
|
16237
16471
|
...rest
|
|
16238
16472
|
});
|
|
16239
16473
|
}
|
|
16474
|
+
/**
|
|
16475
|
+
* uploadFile - Uploads a file to the configured storage (defaults to Stream CDN)
|
|
16476
|
+
*
|
|
16477
|
+
* @param {string|NodeJS.ReadableStream|Buffer|File} uri The file to upload
|
|
16478
|
+
* @param {string} [name] The name of the file
|
|
16479
|
+
* @param {string} [contentType] The content type of the file
|
|
16480
|
+
* @param {UserResponse} [user] Optional user information
|
|
16481
|
+
*
|
|
16482
|
+
* @return {Promise<SendFileAPIResponse>} Response containing the file URL
|
|
16483
|
+
*/
|
|
16484
|
+
uploadFile(uri, name, contentType, user) {
|
|
16485
|
+
return this.sendFile(`${this.baseURL}/uploads/file`, uri, name, contentType, user);
|
|
16486
|
+
}
|
|
16487
|
+
/**
|
|
16488
|
+
* uploadImage - Uploads an image to the configured storage (defaults to Stream CDN)
|
|
16489
|
+
*
|
|
16490
|
+
* @param {string|NodeJS.ReadableStream|File} uri The image to upload
|
|
16491
|
+
* @param {string} [name] The name of the image
|
|
16492
|
+
* @param {string} [contentType] The content type of the image
|
|
16493
|
+
* @param {UserResponse} [user] Optional user information
|
|
16494
|
+
*
|
|
16495
|
+
* @return {Promise<SendFileAPIResponse>} Response containing the image URL
|
|
16496
|
+
*/
|
|
16497
|
+
uploadImage(uri, name, contentType, user) {
|
|
16498
|
+
return this.sendFile(`${this.baseURL}/uploads/image`, uri, name, contentType, user);
|
|
16499
|
+
}
|
|
16500
|
+
/**
|
|
16501
|
+
* deleteFile - Deletes a file from the configured storage
|
|
16502
|
+
*
|
|
16503
|
+
* @param {string} url The URL of the file to delete
|
|
16504
|
+
*
|
|
16505
|
+
* @return {Promise<APIResponse>} The server response
|
|
16506
|
+
*/
|
|
16507
|
+
deleteFile(url) {
|
|
16508
|
+
return this.delete(`${this.baseURL}/uploads/file`, { url });
|
|
16509
|
+
}
|
|
16510
|
+
/**
|
|
16511
|
+
* deleteImage - Deletes an image from the configured storage
|
|
16512
|
+
*
|
|
16513
|
+
* @param {string} url The URL of the image to delete
|
|
16514
|
+
*
|
|
16515
|
+
* @return {Promise<APIResponse>} The server response
|
|
16516
|
+
*/
|
|
16517
|
+
deleteImage(url) {
|
|
16518
|
+
return this.delete(`${this.baseURL}/uploads/image`, { url });
|
|
16519
|
+
}
|
|
16240
16520
|
};
|
|
16241
16521
|
|
|
16242
16522
|
// src/events.ts
|
|
@@ -16945,6 +17225,35 @@ var AbstractOfflineDB = class {
|
|
|
16945
17225
|
(executeOverride) => reactionMethod({ message, reaction, execute: executeOverride })
|
|
16946
17226
|
);
|
|
16947
17227
|
};
|
|
17228
|
+
/**
|
|
17229
|
+
* A utility handler for all draft events:
|
|
17230
|
+
* - draft.updated -> updateDraft
|
|
17231
|
+
* - draft.deleted -> deleteDraft
|
|
17232
|
+
* @param event - the WS event we are trying to process
|
|
17233
|
+
* @param execute - whether to immediately execute the operation.
|
|
17234
|
+
*/
|
|
17235
|
+
this.handleDraftEvent = async ({
|
|
17236
|
+
event,
|
|
17237
|
+
execute = true
|
|
17238
|
+
}) => {
|
|
17239
|
+
const { cid, draft, type } = event;
|
|
17240
|
+
if (!draft) return [];
|
|
17241
|
+
if (type === "draft.updated") {
|
|
17242
|
+
return await this.upsertDraft({
|
|
17243
|
+
draft,
|
|
17244
|
+
execute
|
|
17245
|
+
});
|
|
17246
|
+
}
|
|
17247
|
+
if (type === "draft.deleted") {
|
|
17248
|
+
if (!cid) return [];
|
|
17249
|
+
return await this.deleteDraft({
|
|
17250
|
+
cid,
|
|
17251
|
+
parent_id: draft.parent_id,
|
|
17252
|
+
execute
|
|
17253
|
+
});
|
|
17254
|
+
}
|
|
17255
|
+
return [];
|
|
17256
|
+
};
|
|
16948
17257
|
/**
|
|
16949
17258
|
* A generic event handler that decides which DB API to invoke based on
|
|
16950
17259
|
* event.type for all events we are currently handling. It is used to both
|
|
@@ -16981,6 +17290,9 @@ var AbstractOfflineDB = class {
|
|
|
16981
17290
|
if (type === "channel.hidden" || type === "channel.visible") {
|
|
16982
17291
|
return await this.handleChannelVisibilityEvent({ event, execute });
|
|
16983
17292
|
}
|
|
17293
|
+
if (type === "draft.updated" || type === "draft.deleted") {
|
|
17294
|
+
return await this.handleDraftEvent({ event, execute });
|
|
17295
|
+
}
|
|
16984
17296
|
if ((type === "channel.updated" || type === "notification.message_new" || type === "notification.added_to_channel") && channel) {
|
|
16985
17297
|
return await this.upsertChannelData({ channel, execute });
|
|
16986
17298
|
}
|
|
@@ -17055,6 +17367,12 @@ var AbstractOfflineDB = class {
|
|
|
17055
17367
|
if (task.type === "delete-reaction") {
|
|
17056
17368
|
return await channel._deleteReaction(...task.payload);
|
|
17057
17369
|
}
|
|
17370
|
+
if (task.type === "create-draft") {
|
|
17371
|
+
return await channel._createDraft(...task.payload);
|
|
17372
|
+
}
|
|
17373
|
+
if (task.type === "delete-draft") {
|
|
17374
|
+
return await channel._deleteDraft(...task.payload);
|
|
17375
|
+
}
|
|
17058
17376
|
if (task.type === "send-message") {
|
|
17059
17377
|
const newMessageResponse = await channel._sendMessage(...task.payload);
|
|
17060
17378
|
const newMessage = newMessageResponse?.message;
|