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
package/dist/esm/index.js
CHANGED
|
@@ -2598,6 +2598,23 @@ function formatMessage(message) {
|
|
|
2598
2598
|
quoted_message: toLocalMessageBase(message.quoted_message)
|
|
2599
2599
|
};
|
|
2600
2600
|
}
|
|
2601
|
+
function unformatMessage(message) {
|
|
2602
|
+
const toMessageResponseBase = (msg) => {
|
|
2603
|
+
if (!msg) return null;
|
|
2604
|
+
const newDateString = (/* @__PURE__ */ new Date()).toISOString();
|
|
2605
|
+
return {
|
|
2606
|
+
...msg,
|
|
2607
|
+
created_at: message.created_at ? message.created_at.toISOString() : newDateString,
|
|
2608
|
+
deleted_at: message.deleted_at ? message.deleted_at.toISOString() : void 0,
|
|
2609
|
+
pinned_at: message.pinned_at ? message.pinned_at.toISOString() : void 0,
|
|
2610
|
+
updated_at: message.updated_at ? message.updated_at.toISOString() : newDateString
|
|
2611
|
+
};
|
|
2612
|
+
};
|
|
2613
|
+
return {
|
|
2614
|
+
...toMessageResponseBase(message),
|
|
2615
|
+
quoted_message: toMessageResponseBase(message.quoted_message)
|
|
2616
|
+
};
|
|
2617
|
+
}
|
|
2601
2618
|
var localMessageToNewMessagePayload = (localMessage) => {
|
|
2602
2619
|
const {
|
|
2603
2620
|
// Remove all timestamp fields and client-specific fields.
|
|
@@ -7266,11 +7283,8 @@ var DEFAULT_SEARCH_SOURCE_OPTIONS = {
|
|
|
7266
7283
|
debounceMs: 300,
|
|
7267
7284
|
pageSize: 10
|
|
7268
7285
|
};
|
|
7269
|
-
var
|
|
7286
|
+
var BaseSearchSourceBase = class {
|
|
7270
7287
|
constructor(options) {
|
|
7271
|
-
this.setDebounceOptions = ({ debounceMs }) => {
|
|
7272
|
-
this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);
|
|
7273
|
-
};
|
|
7274
7288
|
this.activate = () => {
|
|
7275
7289
|
if (this.isActive) return;
|
|
7276
7290
|
this.state.partialNext({ isActive: true });
|
|
@@ -7284,11 +7298,9 @@ var BaseSearchSource = class {
|
|
|
7284
7298
|
const searchString = newSearchString ?? this.searchQuery;
|
|
7285
7299
|
return !!(this.isActive && !this.isLoading && (this.hasNext || hasNewSearchQuery) && searchString);
|
|
7286
7300
|
};
|
|
7287
|
-
|
|
7288
|
-
const { debounceMs, pageSize } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
|
|
7301
|
+
const { pageSize } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
|
|
7289
7302
|
this.pageSize = pageSize;
|
|
7290
7303
|
this.state = new StateStore(this.initialState);
|
|
7291
|
-
this.setDebounceOptions({ debounceMs });
|
|
7292
7304
|
}
|
|
7293
7305
|
get lastQueryError() {
|
|
7294
7306
|
return this.state.getLatestValue().lastQueryError;
|
|
@@ -7348,8 +7360,7 @@ var BaseSearchSource = class {
|
|
|
7348
7360
|
items: isFirstPage ? stateUpdate.items : [...this.items ?? [], ...stateUpdate.items || []]
|
|
7349
7361
|
};
|
|
7350
7362
|
}
|
|
7351
|
-
|
|
7352
|
-
if (!this.canExecuteQuery(newSearchString)) return;
|
|
7363
|
+
prepareStateForQuery(newSearchString) {
|
|
7353
7364
|
const hasNewSearchQuery = typeof newSearchString !== "undefined";
|
|
7354
7365
|
const searchString = newSearchString ?? this.searchQuery;
|
|
7355
7366
|
if (hasNewSearchQuery) {
|
|
@@ -7357,18 +7368,47 @@ var BaseSearchSource = class {
|
|
|
7357
7368
|
} else {
|
|
7358
7369
|
this.state.partialNext({ isLoading: true });
|
|
7359
7370
|
}
|
|
7371
|
+
return { searchString, hasNewSearchQuery };
|
|
7372
|
+
}
|
|
7373
|
+
updatePaginationStateFromQuery(result) {
|
|
7374
|
+
const { items, next } = result;
|
|
7360
7375
|
const stateUpdate = {};
|
|
7376
|
+
if (next || next === null) {
|
|
7377
|
+
stateUpdate.next = next;
|
|
7378
|
+
stateUpdate.hasNext = !!next;
|
|
7379
|
+
} else {
|
|
7380
|
+
stateUpdate.offset = (this.offset ?? 0) + items.length;
|
|
7381
|
+
stateUpdate.hasNext = items.length === this.pageSize;
|
|
7382
|
+
}
|
|
7383
|
+
return stateUpdate;
|
|
7384
|
+
}
|
|
7385
|
+
resetState() {
|
|
7386
|
+
this.state.next(this.initialState);
|
|
7387
|
+
}
|
|
7388
|
+
resetStateAndActivate() {
|
|
7389
|
+
this.resetState();
|
|
7390
|
+
this.activate();
|
|
7391
|
+
}
|
|
7392
|
+
};
|
|
7393
|
+
var BaseSearchSource = class extends BaseSearchSourceBase {
|
|
7394
|
+
constructor(options) {
|
|
7395
|
+
const { debounceMs } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
|
|
7396
|
+
super(options);
|
|
7397
|
+
this.setDebounceOptions = ({ debounceMs }) => {
|
|
7398
|
+
this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);
|
|
7399
|
+
};
|
|
7400
|
+
this.search = (searchQuery) => this.searchDebounced(searchQuery);
|
|
7401
|
+
this.setDebounceOptions({ debounceMs });
|
|
7402
|
+
}
|
|
7403
|
+
async executeQuery(newSearchString) {
|
|
7404
|
+
if (!this.canExecuteQuery(newSearchString)) return;
|
|
7405
|
+
const { hasNewSearchQuery, searchString } = this.prepareStateForQuery(newSearchString);
|
|
7406
|
+
let stateUpdate = {};
|
|
7361
7407
|
try {
|
|
7362
7408
|
const results = await this.query(searchString);
|
|
7363
7409
|
if (!results) return;
|
|
7364
|
-
const { items
|
|
7365
|
-
|
|
7366
|
-
stateUpdate.next = next;
|
|
7367
|
-
stateUpdate.hasNext = !!next;
|
|
7368
|
-
} else {
|
|
7369
|
-
stateUpdate.offset = (this.offset ?? 0) + items.length;
|
|
7370
|
-
stateUpdate.hasNext = items.length === this.pageSize;
|
|
7371
|
-
}
|
|
7410
|
+
const { items } = results;
|
|
7411
|
+
stateUpdate = this.updatePaginationStateFromQuery(results);
|
|
7372
7412
|
stateUpdate.items = await this.filterQueryResults(items);
|
|
7373
7413
|
} catch (e) {
|
|
7374
7414
|
stateUpdate.lastQueryError = e;
|
|
@@ -7379,12 +7419,35 @@ var BaseSearchSource = class {
|
|
|
7379
7419
|
cancelScheduledQuery() {
|
|
7380
7420
|
this.searchDebounced.cancel();
|
|
7381
7421
|
}
|
|
7382
|
-
|
|
7383
|
-
|
|
7422
|
+
};
|
|
7423
|
+
var BaseSearchSourceSync = class extends BaseSearchSourceBase {
|
|
7424
|
+
constructor(options) {
|
|
7425
|
+
const { debounceMs } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
|
|
7426
|
+
super(options);
|
|
7427
|
+
this.setDebounceOptions = ({ debounceMs }) => {
|
|
7428
|
+
this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);
|
|
7429
|
+
};
|
|
7430
|
+
this.search = (searchQuery) => this.searchDebounced(searchQuery);
|
|
7431
|
+
this.setDebounceOptions({ debounceMs });
|
|
7384
7432
|
}
|
|
7385
|
-
|
|
7386
|
-
this.
|
|
7387
|
-
this.
|
|
7433
|
+
executeQuery(newSearchString) {
|
|
7434
|
+
if (!this.canExecuteQuery(newSearchString)) return;
|
|
7435
|
+
const { hasNewSearchQuery, searchString } = this.prepareStateForQuery(newSearchString);
|
|
7436
|
+
let stateUpdate = {};
|
|
7437
|
+
try {
|
|
7438
|
+
const results = this.query(searchString);
|
|
7439
|
+
if (!results) return;
|
|
7440
|
+
const { items } = results;
|
|
7441
|
+
stateUpdate = this.updatePaginationStateFromQuery(results);
|
|
7442
|
+
stateUpdate.items = this.filterQueryResults(items);
|
|
7443
|
+
} catch (e) {
|
|
7444
|
+
stateUpdate.lastQueryError = e;
|
|
7445
|
+
} finally {
|
|
7446
|
+
this.state.next(this.getStateAfterQuery(stateUpdate, hasNewSearchQuery));
|
|
7447
|
+
}
|
|
7448
|
+
}
|
|
7449
|
+
cancelScheduledQuery() {
|
|
7450
|
+
this.searchDebounced.cancel();
|
|
7388
7451
|
}
|
|
7389
7452
|
};
|
|
7390
7453
|
|
|
@@ -7667,7 +7730,7 @@ var getTokenizedSuggestionDisplayName = ({
|
|
|
7667
7730
|
});
|
|
7668
7731
|
|
|
7669
7732
|
// src/messageComposer/middleware/textComposer/commands.ts
|
|
7670
|
-
var CommandSearchSource = class extends
|
|
7733
|
+
var CommandSearchSource = class extends BaseSearchSourceSync {
|
|
7671
7734
|
constructor(channel, options) {
|
|
7672
7735
|
super(options);
|
|
7673
7736
|
this.type = "commands";
|
|
@@ -7711,10 +7774,10 @@ var CommandSearchSource = class extends BaseSearchSource {
|
|
|
7711
7774
|
}
|
|
7712
7775
|
return 0;
|
|
7713
7776
|
});
|
|
7714
|
-
return
|
|
7777
|
+
return {
|
|
7715
7778
|
items: selectedCommands.map((c) => ({ ...c, id: c.name })),
|
|
7716
7779
|
next: null
|
|
7717
|
-
}
|
|
7780
|
+
};
|
|
7718
7781
|
}
|
|
7719
7782
|
filterQueryResults(items) {
|
|
7720
7783
|
return items;
|
|
@@ -8322,6 +8385,7 @@ var TextComposer = class {
|
|
|
8322
8385
|
var _WithSubscriptions = class _WithSubscriptions {
|
|
8323
8386
|
constructor() {
|
|
8324
8387
|
this.unsubscribeFunctions = /* @__PURE__ */ new Set();
|
|
8388
|
+
this.refCount = 0;
|
|
8325
8389
|
}
|
|
8326
8390
|
/**
|
|
8327
8391
|
* Returns a boolean, provides information of whether `registerSubscriptions`
|
|
@@ -8333,6 +8397,12 @@ var _WithSubscriptions = class _WithSubscriptions {
|
|
|
8333
8397
|
addUnsubscribeFunction(unsubscribeFunction) {
|
|
8334
8398
|
this.unsubscribeFunctions.add(unsubscribeFunction);
|
|
8335
8399
|
}
|
|
8400
|
+
/**
|
|
8401
|
+
* Increments `refCount` by one and returns new value.
|
|
8402
|
+
*/
|
|
8403
|
+
incrementRefCount() {
|
|
8404
|
+
return ++this.refCount;
|
|
8405
|
+
}
|
|
8336
8406
|
/**
|
|
8337
8407
|
* If you re-declare `unregisterSubscriptions` method within your class
|
|
8338
8408
|
* make sure to run the original too.
|
|
@@ -8349,8 +8419,13 @@ var _WithSubscriptions = class _WithSubscriptions {
|
|
|
8349
8419
|
* ```
|
|
8350
8420
|
*/
|
|
8351
8421
|
unregisterSubscriptions() {
|
|
8422
|
+
if (this.refCount > 1) {
|
|
8423
|
+
this.refCount--;
|
|
8424
|
+
return _WithSubscriptions.symbol;
|
|
8425
|
+
}
|
|
8352
8426
|
this.unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());
|
|
8353
8427
|
this.unsubscribeFunctions.clear();
|
|
8428
|
+
this.refCount = 0;
|
|
8354
8429
|
return _WithSubscriptions.symbol;
|
|
8355
8430
|
}
|
|
8356
8431
|
};
|
|
@@ -8836,7 +8911,6 @@ var initState5 = (composition) => {
|
|
|
8836
8911
|
showReplyInChannel: false
|
|
8837
8912
|
};
|
|
8838
8913
|
};
|
|
8839
|
-
var noop4 = () => void 0;
|
|
8840
8914
|
var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
8841
8915
|
// todo: mediaRecorder: MediaRecorderController;
|
|
8842
8916
|
constructor({
|
|
@@ -8861,22 +8935,48 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8861
8935
|
this.editedMessage = message;
|
|
8862
8936
|
}
|
|
8863
8937
|
};
|
|
8938
|
+
this.initStateFromChannelResponse = (channelApiResponse) => {
|
|
8939
|
+
if (this.channel.cid !== channelApiResponse.channel.cid) {
|
|
8940
|
+
return;
|
|
8941
|
+
}
|
|
8942
|
+
if (channelApiResponse.draft) {
|
|
8943
|
+
this.initState({ composition: channelApiResponse.draft });
|
|
8944
|
+
} else if (this.state.getLatestValue().draftId) {
|
|
8945
|
+
this.clear();
|
|
8946
|
+
this.client.offlineDb?.executeQuerySafely(
|
|
8947
|
+
(db) => db.deleteDraft({
|
|
8948
|
+
cid: this.channel.cid,
|
|
8949
|
+
parent_id: void 0
|
|
8950
|
+
// makes sure that we don't delete thread drafts while upserting channels
|
|
8951
|
+
}),
|
|
8952
|
+
{ method: "deleteDraft" }
|
|
8953
|
+
);
|
|
8954
|
+
}
|
|
8955
|
+
};
|
|
8864
8956
|
this.initEditingAuditState = (composition) => initEditingAuditState(composition);
|
|
8957
|
+
this.registerDraftEventSubscriptions = () => {
|
|
8958
|
+
const unsubscribeDraftUpdated = this.subscribeDraftUpdated();
|
|
8959
|
+
const unsubscribeDraftDeleted = this.subscribeDraftDeleted();
|
|
8960
|
+
return () => {
|
|
8961
|
+
unsubscribeDraftUpdated();
|
|
8962
|
+
unsubscribeDraftDeleted();
|
|
8963
|
+
};
|
|
8964
|
+
};
|
|
8865
8965
|
this.registerSubscriptions = () => {
|
|
8866
|
-
if (this.hasSubscriptions) {
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
8872
|
-
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
this.
|
|
8879
|
-
return this.unregisterSubscriptions
|
|
8966
|
+
if (!this.hasSubscriptions) {
|
|
8967
|
+
this.addUnsubscribeFunction(this.subscribeMessageComposerSetupStateChange());
|
|
8968
|
+
this.addUnsubscribeFunction(this.subscribeMessageUpdated());
|
|
8969
|
+
this.addUnsubscribeFunction(this.subscribeMessageDeleted());
|
|
8970
|
+
this.addUnsubscribeFunction(this.subscribeTextComposerStateChanged());
|
|
8971
|
+
this.addUnsubscribeFunction(this.subscribeAttachmentManagerStateChanged());
|
|
8972
|
+
this.addUnsubscribeFunction(this.subscribeLinkPreviewsManagerStateChanged());
|
|
8973
|
+
this.addUnsubscribeFunction(this.subscribePollComposerStateChanged());
|
|
8974
|
+
this.addUnsubscribeFunction(this.subscribeCustomDataManagerStateChanged());
|
|
8975
|
+
this.addUnsubscribeFunction(this.subscribeMessageComposerStateChanged());
|
|
8976
|
+
this.addUnsubscribeFunction(this.subscribeMessageComposerConfigStateChanged());
|
|
8977
|
+
}
|
|
8978
|
+
this.incrementRefCount();
|
|
8979
|
+
return () => this.unregisterSubscriptions();
|
|
8880
8980
|
};
|
|
8881
8981
|
this.subscribeMessageUpdated = () => {
|
|
8882
8982
|
const eventTypes = [
|
|
@@ -8926,13 +9026,13 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8926
9026
|
}).unsubscribe;
|
|
8927
9027
|
this.subscribeDraftUpdated = () => this.client.on("draft.updated", (event) => {
|
|
8928
9028
|
const draft = event.draft;
|
|
8929
|
-
if (!draft ||
|
|
9029
|
+
if (!draft || (draft.parent_id ?? null) !== (this.threadId ?? null) || draft.channel_cid !== this.channel.cid)
|
|
8930
9030
|
return;
|
|
8931
9031
|
this.initState({ composition: draft });
|
|
8932
9032
|
}).unsubscribe;
|
|
8933
9033
|
this.subscribeDraftDeleted = () => this.client.on("draft.deleted", (event) => {
|
|
8934
9034
|
const draft = event.draft;
|
|
8935
|
-
if (!draft ||
|
|
9035
|
+
if (!draft || (draft.parent_id ?? null) !== (this.threadId ?? null) || draft.channel_cid !== this.channel.cid) {
|
|
8936
9036
|
return;
|
|
8937
9037
|
}
|
|
8938
9038
|
this.logDraftUpdateTimestamp();
|
|
@@ -8996,7 +9096,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8996
9096
|
}
|
|
8997
9097
|
});
|
|
8998
9098
|
this.subscribeMessageComposerConfigStateChanged = () => {
|
|
8999
|
-
let
|
|
9099
|
+
let draftUnsubscribeFunction;
|
|
9000
9100
|
const unsubscribe = this.configState.subscribeWithSelector(
|
|
9001
9101
|
(currentValue) => ({
|
|
9002
9102
|
textDefaultValue: currentValue.text.defaultValue,
|
|
@@ -9009,19 +9109,16 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
9009
9109
|
selection: { start: 0, end: 0 }
|
|
9010
9110
|
});
|
|
9011
9111
|
}
|
|
9012
|
-
if (draftsEnabled && !
|
|
9013
|
-
|
|
9014
|
-
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
} else if (!draftsEnabled && draftUnsubscribeFunctions) {
|
|
9018
|
-
draftUnsubscribeFunctions.forEach((fn) => fn());
|
|
9019
|
-
draftUnsubscribeFunctions = null;
|
|
9112
|
+
if (draftsEnabled && !draftUnsubscribeFunction) {
|
|
9113
|
+
draftUnsubscribeFunction = this.registerDraftEventSubscriptions();
|
|
9114
|
+
} else if (!draftsEnabled && draftUnsubscribeFunction) {
|
|
9115
|
+
draftUnsubscribeFunction();
|
|
9116
|
+
draftUnsubscribeFunction = null;
|
|
9020
9117
|
}
|
|
9021
9118
|
}
|
|
9022
9119
|
);
|
|
9023
9120
|
return () => {
|
|
9024
|
-
|
|
9121
|
+
draftUnsubscribeFunction?.();
|
|
9025
9122
|
unsubscribe();
|
|
9026
9123
|
};
|
|
9027
9124
|
};
|
|
@@ -9091,14 +9188,78 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
9091
9188
|
if (!composition) return;
|
|
9092
9189
|
const { draft } = composition;
|
|
9093
9190
|
this.state.partialNext({ draftId: draft.id });
|
|
9191
|
+
if (this.client.offlineDb) {
|
|
9192
|
+
try {
|
|
9193
|
+
const optimisticDraftResponse = {
|
|
9194
|
+
channel_cid: this.channel.cid,
|
|
9195
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9196
|
+
message: draft,
|
|
9197
|
+
parent_id: draft.parent_id,
|
|
9198
|
+
quoted_message: this.quotedMessage ? unformatMessage(this.quotedMessage) : void 0
|
|
9199
|
+
};
|
|
9200
|
+
await this.client.offlineDb.upsertDraft({ draft: optimisticDraftResponse });
|
|
9201
|
+
} catch (error) {
|
|
9202
|
+
this.client.logger("error", `offlineDb:upsertDraft`, {
|
|
9203
|
+
tags: ["channel", "offlineDb"],
|
|
9204
|
+
error
|
|
9205
|
+
});
|
|
9206
|
+
}
|
|
9207
|
+
}
|
|
9094
9208
|
this.logDraftUpdateTimestamp();
|
|
9095
9209
|
await this.channel.createDraft(draft);
|
|
9096
9210
|
};
|
|
9097
9211
|
this.deleteDraft = async () => {
|
|
9098
9212
|
if (this.editedMessage || !this.config.drafts.enabled || !this.draftId) return;
|
|
9099
9213
|
this.state.partialNext({ draftId: null });
|
|
9214
|
+
const parentId = this.threadId ?? void 0;
|
|
9215
|
+
if (this.client.offlineDb) {
|
|
9216
|
+
try {
|
|
9217
|
+
await this.client.offlineDb.deleteDraft({
|
|
9218
|
+
cid: this.channel.cid,
|
|
9219
|
+
parent_id: parentId
|
|
9220
|
+
});
|
|
9221
|
+
} catch (error) {
|
|
9222
|
+
this.client.logger("error", `offlineDb:deleteDraft`, {
|
|
9223
|
+
tags: ["channel", "offlineDb"],
|
|
9224
|
+
error
|
|
9225
|
+
});
|
|
9226
|
+
}
|
|
9227
|
+
}
|
|
9100
9228
|
this.logDraftUpdateTimestamp();
|
|
9101
|
-
await this.channel.deleteDraft({ parent_id:
|
|
9229
|
+
await this.channel.deleteDraft({ parent_id: parentId });
|
|
9230
|
+
};
|
|
9231
|
+
this.getDraft = async () => {
|
|
9232
|
+
if (this.editedMessage || !this.config.drafts.enabled || !this.client.userID) return;
|
|
9233
|
+
const draftFromOfflineDB = await this.client.offlineDb?.getDraft({
|
|
9234
|
+
cid: this.channel.cid,
|
|
9235
|
+
userId: this.client.userID,
|
|
9236
|
+
parent_id: this.threadId ?? void 0
|
|
9237
|
+
});
|
|
9238
|
+
if (draftFromOfflineDB) {
|
|
9239
|
+
this.initState({ composition: draftFromOfflineDB });
|
|
9240
|
+
}
|
|
9241
|
+
try {
|
|
9242
|
+
const response = await this.channel.getDraft({
|
|
9243
|
+
parent_id: this.threadId ?? void 0
|
|
9244
|
+
});
|
|
9245
|
+
const { draft } = response;
|
|
9246
|
+
if (!draft) return;
|
|
9247
|
+
this.client.offlineDb?.executeQuerySafely(
|
|
9248
|
+
(db) => db.upsertDraft({
|
|
9249
|
+
draft
|
|
9250
|
+
}),
|
|
9251
|
+
{ method: "upsertDraft" }
|
|
9252
|
+
);
|
|
9253
|
+
this.initState({ composition: draft });
|
|
9254
|
+
} catch (error) {
|
|
9255
|
+
this.client.notifications.add({
|
|
9256
|
+
message: "Failed to get the draft",
|
|
9257
|
+
origin: {
|
|
9258
|
+
emitter: "MessageComposer",
|
|
9259
|
+
context: { composer: this }
|
|
9260
|
+
}
|
|
9261
|
+
});
|
|
9262
|
+
}
|
|
9102
9263
|
};
|
|
9103
9264
|
this.createPoll = async () => {
|
|
9104
9265
|
const composition = await this.pollComposer.compose();
|
|
@@ -9227,6 +9388,9 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
9227
9388
|
return this.state.getLatestValue().showReplyInChannel;
|
|
9228
9389
|
}
|
|
9229
9390
|
get hasSendableData() {
|
|
9391
|
+
if (this.client.offlineDb) {
|
|
9392
|
+
return !this.compositionIsEmpty;
|
|
9393
|
+
}
|
|
9230
9394
|
return !!(!this.attachmentManager.uploadsInProgressCount && (!this.textComposer.textIsEmpty || this.attachmentManager.successfulUploadsCount > 0) || this.pollId);
|
|
9231
9395
|
}
|
|
9232
9396
|
get compositionIsEmpty() {
|
|
@@ -9542,6 +9706,17 @@ var Channel = class {
|
|
|
9542
9706
|
updates
|
|
9543
9707
|
);
|
|
9544
9708
|
}
|
|
9709
|
+
/**
|
|
9710
|
+
* sendReaction - Sends a reaction to a message. If offline support is enabled, it will make sure
|
|
9711
|
+
* that sending the reaction is queued up if it fails due to bad internet conditions and executed
|
|
9712
|
+
* later.
|
|
9713
|
+
*
|
|
9714
|
+
* @param {string} messageID the message id
|
|
9715
|
+
* @param {Reaction} reaction the reaction object for instance {type: 'love'}
|
|
9716
|
+
* @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
|
|
9717
|
+
*
|
|
9718
|
+
* @return {Promise<ReactionAPIResponse>} The Server Response
|
|
9719
|
+
*/
|
|
9545
9720
|
async sendReaction(messageID, reaction, options) {
|
|
9546
9721
|
if (!messageID) {
|
|
9547
9722
|
throw Error(`Message id is missing`);
|
|
@@ -10394,9 +10569,7 @@ var Channel = class {
|
|
|
10394
10569
|
};
|
|
10395
10570
|
this.getClient().polls.hydratePollCache(state.messages, true);
|
|
10396
10571
|
this.getClient().reminders.hydrateState(state.messages);
|
|
10397
|
-
|
|
10398
|
-
this.messageComposer.initState({ composition: state.draft });
|
|
10399
|
-
}
|
|
10572
|
+
this.messageComposer.initStateFromChannelResponse(state);
|
|
10400
10573
|
const areCapabilitiesChanged = [...state.channel.own_capabilities || []].sort().join() !== [
|
|
10401
10574
|
...this.data && Array.isArray(this.data?.own_capabilities) ? this.data.own_capabilities : []
|
|
10402
10575
|
].sort().join();
|
|
@@ -10523,13 +10696,11 @@ var Channel = class {
|
|
|
10523
10696
|
/**
|
|
10524
10697
|
* createDraft - Creates or updates a draft message in a channel
|
|
10525
10698
|
*
|
|
10526
|
-
* @param {string} channelType The channel type
|
|
10527
|
-
* @param {string} channelID The channel ID
|
|
10528
10699
|
* @param {DraftMessagePayload} message The draft message to create or update
|
|
10529
10700
|
*
|
|
10530
10701
|
* @return {Promise<CreateDraftResponse>} Response containing the created draft
|
|
10531
10702
|
*/
|
|
10532
|
-
async
|
|
10703
|
+
async _createDraft(message) {
|
|
10533
10704
|
return await this.getClient().post(
|
|
10534
10705
|
this._channelURL() + "/draft",
|
|
10535
10706
|
{
|
|
@@ -10538,18 +10709,82 @@ var Channel = class {
|
|
|
10538
10709
|
);
|
|
10539
10710
|
}
|
|
10540
10711
|
/**
|
|
10541
|
-
*
|
|
10712
|
+
* createDraft - Creates or updates a draft message in a channel. If offline support is
|
|
10713
|
+
* enabled, it will make sure that creating the draft is queued up if it fails due to
|
|
10714
|
+
* bad internet conditions and executed later.
|
|
10715
|
+
*
|
|
10716
|
+
* @param {DraftMessagePayload} message The draft message to create or update
|
|
10717
|
+
*
|
|
10718
|
+
* @return {Promise<CreateDraftResponse>} Response containing the created draft
|
|
10719
|
+
*/
|
|
10720
|
+
async createDraft(message) {
|
|
10721
|
+
try {
|
|
10722
|
+
const offlineDb = this.getClient().offlineDb;
|
|
10723
|
+
if (offlineDb) {
|
|
10724
|
+
return await offlineDb.queueTask({
|
|
10725
|
+
task: {
|
|
10726
|
+
channelId: this.id,
|
|
10727
|
+
channelType: this.type,
|
|
10728
|
+
threadId: message.parent_id,
|
|
10729
|
+
payload: [message],
|
|
10730
|
+
type: "create-draft"
|
|
10731
|
+
}
|
|
10732
|
+
});
|
|
10733
|
+
}
|
|
10734
|
+
} catch (error) {
|
|
10735
|
+
this._client.logger("error", `offlineDb:create-draft`, {
|
|
10736
|
+
tags: ["channel", "offlineDb"],
|
|
10737
|
+
error
|
|
10738
|
+
});
|
|
10739
|
+
}
|
|
10740
|
+
return this._createDraft(message);
|
|
10741
|
+
}
|
|
10742
|
+
/**
|
|
10743
|
+
* deleteDraft - Deletes a draft message from a channel or a thread.
|
|
10542
10744
|
*
|
|
10543
10745
|
* @param {Object} options
|
|
10544
10746
|
* @param {string} options.parent_id Optional parent message ID for drafts in threads
|
|
10545
10747
|
*
|
|
10546
10748
|
* @return {Promise<APIResponse>} API response
|
|
10547
10749
|
*/
|
|
10548
|
-
async
|
|
10750
|
+
async _deleteDraft({ parent_id } = {}) {
|
|
10549
10751
|
return await this.getClient().delete(this._channelURL() + "/draft", {
|
|
10550
10752
|
parent_id
|
|
10551
10753
|
});
|
|
10552
10754
|
}
|
|
10755
|
+
/**
|
|
10756
|
+
* deleteDraft - Deletes a draft message from a channel or a thread. If offline support is
|
|
10757
|
+
* enabled, it will make sure that deleting the draft is queued up if it fails due to
|
|
10758
|
+
* bad internet conditions and executed later.
|
|
10759
|
+
*
|
|
10760
|
+
* @param {Object} options
|
|
10761
|
+
* @param {string} options.parent_id Optional parent message ID for drafts in threads
|
|
10762
|
+
*
|
|
10763
|
+
* @return {Promise<APIResponse>} API response
|
|
10764
|
+
*/
|
|
10765
|
+
async deleteDraft(options = {}) {
|
|
10766
|
+
const { parent_id } = options;
|
|
10767
|
+
try {
|
|
10768
|
+
const offlineDb = this.getClient().offlineDb;
|
|
10769
|
+
if (offlineDb) {
|
|
10770
|
+
return await offlineDb.queueTask({
|
|
10771
|
+
task: {
|
|
10772
|
+
channelId: this.id,
|
|
10773
|
+
channelType: this.type,
|
|
10774
|
+
threadId: parent_id,
|
|
10775
|
+
payload: [options],
|
|
10776
|
+
type: "delete-draft"
|
|
10777
|
+
}
|
|
10778
|
+
});
|
|
10779
|
+
}
|
|
10780
|
+
} catch (error) {
|
|
10781
|
+
this._client.logger("error", `offlineDb:delete-draft`, {
|
|
10782
|
+
tags: ["channel", "offlineDb"],
|
|
10783
|
+
error
|
|
10784
|
+
});
|
|
10785
|
+
}
|
|
10786
|
+
return this._deleteDraft(options);
|
|
10787
|
+
}
|
|
10553
10788
|
/**
|
|
10554
10789
|
* getDraft - Retrieves a draft message from a channel
|
|
10555
10790
|
*
|
|
@@ -15199,9 +15434,7 @@ var StreamChat = class _StreamChat {
|
|
|
15199
15434
|
this.polls.hydratePollCache(channelState.messages, true);
|
|
15200
15435
|
this.reminders.hydrateState(channelState.messages);
|
|
15201
15436
|
}
|
|
15202
|
-
|
|
15203
|
-
c.messageComposer.initState({ composition: channelState.draft });
|
|
15204
|
-
}
|
|
15437
|
+
c.messageComposer.initStateFromChannelResponse(channelState);
|
|
15205
15438
|
channels.push(c);
|
|
15206
15439
|
}
|
|
15207
15440
|
return channels;
|
|
@@ -16118,7 +16351,7 @@ var StreamChat = class _StreamChat {
|
|
|
16118
16351
|
if (this.userAgent) {
|
|
16119
16352
|
return this.userAgent;
|
|
16120
16353
|
}
|
|
16121
|
-
const version = "9.
|
|
16354
|
+
const version = "9.7.0";
|
|
16122
16355
|
const clientBundle = "browser-esm";
|
|
16123
16356
|
let userAgentString = "";
|
|
16124
16357
|
if (this.sdkIdentifier) {
|
|
@@ -17207,6 +17440,52 @@ var StreamChat = class _StreamChat {
|
|
|
17207
17440
|
...rest
|
|
17208
17441
|
});
|
|
17209
17442
|
}
|
|
17443
|
+
/**
|
|
17444
|
+
* uploadFile - Uploads a file to the configured storage (defaults to Stream CDN)
|
|
17445
|
+
*
|
|
17446
|
+
* @param {string|NodeJS.ReadableStream|Buffer|File} uri The file to upload
|
|
17447
|
+
* @param {string} [name] The name of the file
|
|
17448
|
+
* @param {string} [contentType] The content type of the file
|
|
17449
|
+
* @param {UserResponse} [user] Optional user information
|
|
17450
|
+
*
|
|
17451
|
+
* @return {Promise<SendFileAPIResponse>} Response containing the file URL
|
|
17452
|
+
*/
|
|
17453
|
+
uploadFile(uri, name, contentType, user) {
|
|
17454
|
+
return this.sendFile(`${this.baseURL}/uploads/file`, uri, name, contentType, user);
|
|
17455
|
+
}
|
|
17456
|
+
/**
|
|
17457
|
+
* uploadImage - Uploads an image to the configured storage (defaults to Stream CDN)
|
|
17458
|
+
*
|
|
17459
|
+
* @param {string|NodeJS.ReadableStream|File} uri The image to upload
|
|
17460
|
+
* @param {string} [name] The name of the image
|
|
17461
|
+
* @param {string} [contentType] The content type of the image
|
|
17462
|
+
* @param {UserResponse} [user] Optional user information
|
|
17463
|
+
*
|
|
17464
|
+
* @return {Promise<SendFileAPIResponse>} Response containing the image URL
|
|
17465
|
+
*/
|
|
17466
|
+
uploadImage(uri, name, contentType, user) {
|
|
17467
|
+
return this.sendFile(`${this.baseURL}/uploads/image`, uri, name, contentType, user);
|
|
17468
|
+
}
|
|
17469
|
+
/**
|
|
17470
|
+
* deleteFile - Deletes a file from the configured storage
|
|
17471
|
+
*
|
|
17472
|
+
* @param {string} url The URL of the file to delete
|
|
17473
|
+
*
|
|
17474
|
+
* @return {Promise<APIResponse>} The server response
|
|
17475
|
+
*/
|
|
17476
|
+
deleteFile(url) {
|
|
17477
|
+
return this.delete(`${this.baseURL}/uploads/file`, { url });
|
|
17478
|
+
}
|
|
17479
|
+
/**
|
|
17480
|
+
* deleteImage - Deletes an image from the configured storage
|
|
17481
|
+
*
|
|
17482
|
+
* @param {string} url The URL of the image to delete
|
|
17483
|
+
*
|
|
17484
|
+
* @return {Promise<APIResponse>} The server response
|
|
17485
|
+
*/
|
|
17486
|
+
deleteImage(url) {
|
|
17487
|
+
return this.delete(`${this.baseURL}/uploads/image`, { url });
|
|
17488
|
+
}
|
|
17210
17489
|
};
|
|
17211
17490
|
|
|
17212
17491
|
// src/events.ts
|
|
@@ -17915,6 +18194,35 @@ var AbstractOfflineDB = class {
|
|
|
17915
18194
|
(executeOverride) => reactionMethod({ message, reaction, execute: executeOverride })
|
|
17916
18195
|
);
|
|
17917
18196
|
};
|
|
18197
|
+
/**
|
|
18198
|
+
* A utility handler for all draft events:
|
|
18199
|
+
* - draft.updated -> updateDraft
|
|
18200
|
+
* - draft.deleted -> deleteDraft
|
|
18201
|
+
* @param event - the WS event we are trying to process
|
|
18202
|
+
* @param execute - whether to immediately execute the operation.
|
|
18203
|
+
*/
|
|
18204
|
+
this.handleDraftEvent = async ({
|
|
18205
|
+
event,
|
|
18206
|
+
execute = true
|
|
18207
|
+
}) => {
|
|
18208
|
+
const { cid, draft, type } = event;
|
|
18209
|
+
if (!draft) return [];
|
|
18210
|
+
if (type === "draft.updated") {
|
|
18211
|
+
return await this.upsertDraft({
|
|
18212
|
+
draft,
|
|
18213
|
+
execute
|
|
18214
|
+
});
|
|
18215
|
+
}
|
|
18216
|
+
if (type === "draft.deleted") {
|
|
18217
|
+
if (!cid) return [];
|
|
18218
|
+
return await this.deleteDraft({
|
|
18219
|
+
cid,
|
|
18220
|
+
parent_id: draft.parent_id,
|
|
18221
|
+
execute
|
|
18222
|
+
});
|
|
18223
|
+
}
|
|
18224
|
+
return [];
|
|
18225
|
+
};
|
|
17918
18226
|
/**
|
|
17919
18227
|
* A generic event handler that decides which DB API to invoke based on
|
|
17920
18228
|
* event.type for all events we are currently handling. It is used to both
|
|
@@ -17951,6 +18259,9 @@ var AbstractOfflineDB = class {
|
|
|
17951
18259
|
if (type === "channel.hidden" || type === "channel.visible") {
|
|
17952
18260
|
return await this.handleChannelVisibilityEvent({ event, execute });
|
|
17953
18261
|
}
|
|
18262
|
+
if (type === "draft.updated" || type === "draft.deleted") {
|
|
18263
|
+
return await this.handleDraftEvent({ event, execute });
|
|
18264
|
+
}
|
|
17954
18265
|
if ((type === "channel.updated" || type === "notification.message_new" || type === "notification.added_to_channel") && channel) {
|
|
17955
18266
|
return await this.upsertChannelData({ channel, execute });
|
|
17956
18267
|
}
|
|
@@ -18025,6 +18336,12 @@ var AbstractOfflineDB = class {
|
|
|
18025
18336
|
if (task.type === "delete-reaction") {
|
|
18026
18337
|
return await channel._deleteReaction(...task.payload);
|
|
18027
18338
|
}
|
|
18339
|
+
if (task.type === "create-draft") {
|
|
18340
|
+
return await channel._createDraft(...task.payload);
|
|
18341
|
+
}
|
|
18342
|
+
if (task.type === "delete-draft") {
|
|
18343
|
+
return await channel._deleteDraft(...task.payload);
|
|
18344
|
+
}
|
|
18028
18345
|
if (task.type === "send-message") {
|
|
18029
18346
|
const newMessageResponse = await channel._sendMessage(...task.payload);
|
|
18030
18347
|
const newMessage = newMessageResponse?.message;
|
|
@@ -18152,6 +18469,7 @@ export {
|
|
|
18152
18469
|
AttachmentManager,
|
|
18153
18470
|
BasePaginator,
|
|
18154
18471
|
BaseSearchSource,
|
|
18472
|
+
BaseSearchSourceSync,
|
|
18155
18473
|
BuiltinPermissions,
|
|
18156
18474
|
BuiltinRoles,
|
|
18157
18475
|
Campaign,
|