stream-chat 9.50.3 → 9.52.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 +601 -275
- package/dist/cjs/index.browser.js.map +4 -4
- package/dist/cjs/index.node.js +610 -276
- package/dist/cjs/index.node.js.map +4 -4
- package/dist/esm/index.mjs +599 -273
- package/dist/esm/index.mjs.map +4 -4
- package/dist/types/channel.d.ts +4 -3
- package/dist/types/client.d.ts +23 -9
- package/dist/types/index.d.ts +7 -0
- package/dist/types/messageComposer/attachmentIdentity.d.ts +4 -0
- package/dist/types/messageComposer/attachmentManager.d.ts +8 -0
- package/dist/types/messageComposer/messageComposer.d.ts +13 -0
- package/dist/types/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.d.ts +20 -1
- package/dist/types/messageComposer/middleware/messageComposer/MessageComposerMiddlewareExecutor.d.ts +6 -1
- package/dist/types/messageComposer/middleware/messageComposer/attachments.d.ts +24 -0
- package/dist/types/messageComposer/middleware/messageComposer/types.d.ts +22 -1
- package/dist/types/messageComposer/middleware/textComposer/mentions.d.ts +15 -9
- package/dist/types/messageComposer/types.d.ts +5 -0
- package/dist/types/middleware.d.ts +8 -0
- package/dist/types/offline-support/offline_support_api.d.ts +7 -1
- package/dist/types/offline-support/offline_sync_manager.d.ts +12 -1
- package/dist/types/search/BaseSearchSource.d.ts +42 -24
- package/dist/types/search/ChannelMemberSearchSource.d.ts +9 -4
- package/dist/types/search/ChannelSearchSource.d.ts +9 -3
- package/dist/types/search/MessageSearchSource.d.ts +14 -3
- package/dist/types/search/UserSearchSource.d.ts +9 -3
- package/dist/types/search/types.d.ts +14 -1
- package/dist/types/types.d.ts +12 -1
- package/dist/types/uploadManager.d.ts +30 -0
- package/dist/types/utils.d.ts +21 -2
- package/package.json +7 -7
- package/src/channel.ts +20 -8
- package/src/client.ts +71 -13
- package/src/index.ts +12 -0
- package/src/messageComposer/attachmentIdentity.ts +27 -0
- package/src/messageComposer/attachmentManager.ts +61 -12
- package/src/messageComposer/messageComposer.ts +43 -8
- package/src/messageComposer/middleware/attachmentManager/postUpload/AttachmentPostUploadMiddlewareExecutor.ts +1 -1
- package/src/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.ts +58 -33
- package/src/messageComposer/middleware/attachmentManager/postUpload/uploadErrorHandler.ts +4 -0
- package/src/messageComposer/middleware/messageComposer/MessageComposerMiddlewareExecutor.ts +9 -0
- package/src/messageComposer/middleware/messageComposer/attachments.ts +109 -0
- package/src/messageComposer/middleware/messageComposer/types.ts +22 -1
- package/src/messageComposer/middleware/textComposer/mentions.ts +75 -23
- package/src/messageComposer/types.ts +5 -0
- package/src/middleware.ts +11 -0
- package/src/offline-support/offline_support_api.ts +21 -2
- package/src/offline-support/offline_sync_manager.ts +36 -8
- package/src/search/BaseSearchSource.ts +123 -39
- package/src/search/ChannelMemberSearchSource.ts +22 -11
- package/src/search/ChannelSearchSource.ts +16 -5
- package/src/search/MessageSearchSource.ts +36 -4
- package/src/search/UserSearchSource.ts +16 -5
- package/src/search/types.ts +14 -1
- package/src/types.ts +13 -1
- package/src/uploadManager.ts +45 -0
- package/src/utils.ts +78 -3
|
@@ -189,6 +189,7 @@ __export(index_exports, {
|
|
|
189
189
|
createMessageComposerStateCompositionMiddleware: () => createMessageComposerStateCompositionMiddleware,
|
|
190
190
|
createPollComposerStateMiddleware: () => createPollComposerStateMiddleware,
|
|
191
191
|
createPostUploadAttachmentEnrichmentMiddleware: () => createPostUploadAttachmentEnrichmentMiddleware,
|
|
192
|
+
createSendWithPendingUploadsAttachmentsMiddleware: () => createSendWithPendingUploadsAttachmentsMiddleware,
|
|
192
193
|
createSharedLocationCompositionMiddleware: () => createSharedLocationCompositionMiddleware,
|
|
193
194
|
createTextComposerCompositionMiddleware: () => createTextComposerCompositionMiddleware,
|
|
194
195
|
createTextComposerPreValidationMiddleware: () => createTextComposerPreValidationMiddleware,
|
|
@@ -217,6 +218,7 @@ __export(index_exports, {
|
|
|
217
218
|
getTokenizedSuggestionDisplayName: () => getTokenizedSuggestionDisplayName,
|
|
218
219
|
getTriggerCharWithToken: () => getTriggerCharWithToken,
|
|
219
220
|
gunzipPayload: () => gunzipPayload,
|
|
221
|
+
hasPending: () => hasPending,
|
|
220
222
|
insertItemWithTrigger: () => insertItemWithTrigger,
|
|
221
223
|
isAudioAttachment: () => isAudioAttachment,
|
|
222
224
|
isBlobButNotFile: () => isBlobButNotFile,
|
|
@@ -224,6 +226,7 @@ __export(index_exports, {
|
|
|
224
226
|
isFileAttachment: () => isFileAttachment,
|
|
225
227
|
isFileList: () => isFileList,
|
|
226
228
|
isFileReference: () => isFileReference,
|
|
229
|
+
isFinishedUpload: () => isFinishedUpload,
|
|
227
230
|
isGiphyAttachment: () => isGiphyAttachment,
|
|
228
231
|
isImageAttachment: () => isImageAttachment,
|
|
229
232
|
isImageFile: () => isImageFile,
|
|
@@ -236,9 +239,11 @@ __export(index_exports, {
|
|
|
236
239
|
isLocalVoiceRecordingAttachment: () => isLocalVoiceRecordingAttachment,
|
|
237
240
|
isOwnUser: () => isOwnUser,
|
|
238
241
|
isPatch: () => isPatch,
|
|
242
|
+
isPendingUpload: () => isPendingUpload,
|
|
239
243
|
isScrapedContent: () => isScrapedContent,
|
|
240
244
|
isSharedLocationResponse: () => isSharedLocationResponse,
|
|
241
245
|
isTargetedOptionTextUpdate: () => isTargetedOptionTextUpdate,
|
|
246
|
+
isUploadCancellation: () => isUploadCancellation,
|
|
242
247
|
isUploadedAttachment: () => isUploadedAttachment,
|
|
243
248
|
isVideoAttachment: () => isVideoAttachment,
|
|
244
249
|
isVoiceRecordingAttachment: () => isVoiceRecordingAttachment,
|
|
@@ -258,12 +263,15 @@ __export(index_exports, {
|
|
|
258
263
|
readFileAsArrayBuffer: () => readFileAsArrayBuffer,
|
|
259
264
|
removeDiacritics: () => removeDiacritics,
|
|
260
265
|
replaceWordWithEntity: () => replaceWordWithEntity,
|
|
266
|
+
settled: () => settled,
|
|
261
267
|
stripCommandFromText: () => stripCommandFromText,
|
|
262
268
|
stripMentionTokens: () => stripMentionTokens,
|
|
263
269
|
textIsEmpty: () => textIsEmpty,
|
|
264
270
|
timeLeftMs: () => timeLeftMs,
|
|
265
271
|
verifyAndParseWebhook: () => verifyAndParseWebhook,
|
|
266
|
-
verifySignature: () => verifySignature
|
|
272
|
+
verifySignature: () => verifySignature,
|
|
273
|
+
withCancellation: () => withCancellation,
|
|
274
|
+
withoutConcurrency: () => withoutConcurrency
|
|
267
275
|
});
|
|
268
276
|
module.exports = __toCommonJS(index_exports);
|
|
269
277
|
|
|
@@ -530,7 +538,7 @@ var ChannelBatchUpdater = class {
|
|
|
530
538
|
};
|
|
531
539
|
|
|
532
540
|
// src/client.ts
|
|
533
|
-
var
|
|
541
|
+
var import_axios4 = __toESM(require("axios"));
|
|
534
542
|
var import_https = __toESM(require_https());
|
|
535
543
|
|
|
536
544
|
// src/utils.ts
|
|
@@ -790,6 +798,38 @@ function unformatMessage(message) {
|
|
|
790
798
|
quoted_message: toMessageResponseBase(message.quoted_message)
|
|
791
799
|
};
|
|
792
800
|
}
|
|
801
|
+
var isRemoteUrl = (url) => !!url && /^https?:\/\//i.test(url.trim());
|
|
802
|
+
var sanitizeOutgoingAttachments = ({
|
|
803
|
+
client,
|
|
804
|
+
message
|
|
805
|
+
}) => {
|
|
806
|
+
const attachments = message.attachments;
|
|
807
|
+
if (!attachments?.length) return message;
|
|
808
|
+
const unresolved = [];
|
|
809
|
+
let changed = false;
|
|
810
|
+
const sanitized = attachments.reduce((acc, attachment) => {
|
|
811
|
+
const { localMetadata, ...rest } = attachment;
|
|
812
|
+
if (!localMetadata) {
|
|
813
|
+
acc.push(attachment);
|
|
814
|
+
return acc;
|
|
815
|
+
}
|
|
816
|
+
changed = true;
|
|
817
|
+
const hasRemoteSource = isRemoteUrl(rest.asset_url) || isRemoteUrl(rest.image_url) || isRemoteUrl(rest.og_scrape_url) || isRemoteUrl(rest.title_link);
|
|
818
|
+
if (hasRemoteSource) {
|
|
819
|
+
acc.push(rest);
|
|
820
|
+
} else {
|
|
821
|
+
unresolved.push(rest);
|
|
822
|
+
}
|
|
823
|
+
return acc;
|
|
824
|
+
}, []);
|
|
825
|
+
if (unresolved.length) {
|
|
826
|
+
const text = `Dropped ${unresolved.length} attachment(s) whose upload never completed. Composing with pending uploads requires awaiting them before sending.`;
|
|
827
|
+
const extraData = { attachments: unresolved, message, tags: ["attachments"] };
|
|
828
|
+
client.logger("warn", text, extraData);
|
|
829
|
+
console.warn(text, extraData);
|
|
830
|
+
}
|
|
831
|
+
return changed ? { ...message, attachments: sanitized } : message;
|
|
832
|
+
};
|
|
793
833
|
var localMessageToNewMessagePayload = (localMessage) => {
|
|
794
834
|
const {
|
|
795
835
|
// Remove all timestamp fields and client-specific fields.
|
|
@@ -998,7 +1038,8 @@ var debounce = (fn, timeout = 0, { leading = false, trailing = true } = {}) => {
|
|
|
998
1038
|
}
|
|
999
1039
|
runningTimeout = null;
|
|
1000
1040
|
};
|
|
1001
|
-
|
|
1041
|
+
const delay = typeof timeout === "function" ? timeout(...args) : timeout;
|
|
1042
|
+
runningTimeout = setTimeout(timeoutHandler, delay);
|
|
1002
1043
|
return lastResult;
|
|
1003
1044
|
};
|
|
1004
1045
|
debouncedFn.cancel = () => {
|
|
@@ -2561,6 +2602,12 @@ var CooldownTimer = class extends WithSubscriptions {
|
|
|
2561
2602
|
var isScrapedContent = (attachment) => !!attachment?.og_scrape_url || !!attachment?.title_link;
|
|
2562
2603
|
var isLocalAttachment = (attachment) => !!attachment?.localMetadata?.id;
|
|
2563
2604
|
var isLocalUploadAttachment = (attachment) => !!attachment?.localMetadata?.uploadState;
|
|
2605
|
+
var PENDING_UPLOAD_STATES = [
|
|
2606
|
+
"pending",
|
|
2607
|
+
"uploading"
|
|
2608
|
+
];
|
|
2609
|
+
var isPendingUpload = (attachment) => isLocalUploadAttachment(attachment) && PENDING_UPLOAD_STATES.includes(attachment.localMetadata.uploadState);
|
|
2610
|
+
var isFinishedUpload = (attachment) => isLocalUploadAttachment(attachment) && attachment.localMetadata.uploadState === "finished";
|
|
2564
2611
|
var isFileAttachment = (attachment, supportedVideoFormat = []) => attachment.type === "file" || !!(attachment.mime_type && supportedVideoFormat.indexOf(attachment.mime_type) === -1 && attachment.type !== "video");
|
|
2565
2612
|
var isLocalFileAttachment = (attachment) => isFileAttachment(attachment) && isLocalAttachment(attachment);
|
|
2566
2613
|
var isImageAttachment = (attachment) => attachment.type === "image" && !isScrapedContent(attachment);
|
|
@@ -2636,7 +2683,7 @@ var ensureIsLocalAttachment = (attachment) => {
|
|
|
2636
2683
|
};
|
|
2637
2684
|
|
|
2638
2685
|
// src/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.ts
|
|
2639
|
-
var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
2686
|
+
var createPostUploadAttachmentEnrichmentMiddleware = (composer) => ({
|
|
2640
2687
|
id: "stream-io/attachment-manager-middleware/post-upload-enrichment",
|
|
2641
2688
|
handlers: {
|
|
2642
2689
|
postProcess: ({
|
|
@@ -2649,9 +2696,10 @@ var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
|
2649
2696
|
if (error) return forward();
|
|
2650
2697
|
if (!attachment || !response) return discard();
|
|
2651
2698
|
const enrichedAttachment = { ...attachment };
|
|
2652
|
-
const previewUri = attachment.localMetadata
|
|
2653
|
-
|
|
2654
|
-
|
|
2699
|
+
const { id, previewUri } = attachment.localMetadata;
|
|
2700
|
+
const attachmentIsStillInComposer = !composer || !!composer.attachmentManager.attachmentsById[id];
|
|
2701
|
+
if (previewUri && attachmentIsStillInComposer) {
|
|
2702
|
+
if (previewUri.startsWith("blob:")) URL.revokeObjectURL?.(previewUri);
|
|
2655
2703
|
delete enrichedAttachment.localMetadata.previewUri;
|
|
2656
2704
|
}
|
|
2657
2705
|
if (isLocalImageAttachment(attachment)) {
|
|
@@ -2674,6 +2722,12 @@ var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
|
2674
2722
|
var withoutConcurrency = createRunner(wrapWithContinuationTracking);
|
|
2675
2723
|
var withCancellation = createRunner(wrapWithCancellation);
|
|
2676
2724
|
var pendingPromises = /* @__PURE__ */ new Map();
|
|
2725
|
+
function hasPending(tag) {
|
|
2726
|
+
return pendingPromises.has(tag);
|
|
2727
|
+
}
|
|
2728
|
+
async function settled(tag) {
|
|
2729
|
+
await pendingPromises.get(tag)?.promise;
|
|
2730
|
+
}
|
|
2677
2731
|
function createRunner(wrapper) {
|
|
2678
2732
|
return function run(tag, cb) {
|
|
2679
2733
|
const { cb: wrapped, onContinued } = wrapper(tag, cb);
|
|
@@ -2716,6 +2770,16 @@ var MiddlewareExecutor = class {
|
|
|
2716
2770
|
this.middleware = [];
|
|
2717
2771
|
this.id = generateUUIDv4();
|
|
2718
2772
|
}
|
|
2773
|
+
/**
|
|
2774
|
+
* The middleware currently installed, in execution order.
|
|
2775
|
+
*
|
|
2776
|
+
* Read-only: use `use` / `insert` / `replace` / `setOrder` / `remove` to change the chain. It
|
|
2777
|
+
* exists so components can ask what the chain is capable of - a middleware may declare
|
|
2778
|
+
* behaviour its host has to account for, and the host has no other way to find out.
|
|
2779
|
+
*/
|
|
2780
|
+
get installedMiddleware() {
|
|
2781
|
+
return this.middleware;
|
|
2782
|
+
}
|
|
2719
2783
|
use(middleware) {
|
|
2720
2784
|
this.middleware = this.middleware.concat(middleware);
|
|
2721
2785
|
return this;
|
|
@@ -2819,6 +2883,142 @@ var MiddlewareExecutor = class {
|
|
|
2819
2883
|
}
|
|
2820
2884
|
};
|
|
2821
2885
|
|
|
2886
|
+
// src/uploadManager.ts
|
|
2887
|
+
var import_axios = __toESM(require("axios"));
|
|
2888
|
+
var isUploadCancellation = (error) => import_axios.default.isCancel(error) || error instanceof Error && error.name === "AbortError";
|
|
2889
|
+
var initState = () => ({ uploads: {} });
|
|
2890
|
+
var upsertById = (uploads, record) => ({
|
|
2891
|
+
...uploads,
|
|
2892
|
+
[record.id]: { ...uploads[record.id], ...record }
|
|
2893
|
+
});
|
|
2894
|
+
var updateById = (uploads, record) => {
|
|
2895
|
+
if (!(record.id in uploads)) return null;
|
|
2896
|
+
const current = uploads[record.id];
|
|
2897
|
+
return { ...uploads, [record.id]: { ...current, ...record } };
|
|
2898
|
+
};
|
|
2899
|
+
var UploadManager = class {
|
|
2900
|
+
constructor(client) {
|
|
2901
|
+
this.client = client;
|
|
2902
|
+
this.inFlightUploads = /* @__PURE__ */ new Map();
|
|
2903
|
+
this.getUpload = (id) => this.uploads[id];
|
|
2904
|
+
/**
|
|
2905
|
+
* Clears all upload records.
|
|
2906
|
+
* Invoked when the user disconnects so a later session does not inherit stale upload state.
|
|
2907
|
+
* Aborts every in-flight upload request via its `UploadRequestOptions.abortSignal`.
|
|
2908
|
+
*/
|
|
2909
|
+
this.reset = () => {
|
|
2910
|
+
for (const { abortController } of this.inFlightUploads.values()) {
|
|
2911
|
+
abortController.abort();
|
|
2912
|
+
}
|
|
2913
|
+
this.inFlightUploads.clear();
|
|
2914
|
+
this.state.next(initState());
|
|
2915
|
+
};
|
|
2916
|
+
/**
|
|
2917
|
+
* Removes the upload record for `id` if present.
|
|
2918
|
+
* If an upload is still in progress, aborts its `UploadRequestOptions.abortSignal`.
|
|
2919
|
+
*/
|
|
2920
|
+
this.deleteUploadRecord = (id) => {
|
|
2921
|
+
const flight = this.inFlightUploads.get(id);
|
|
2922
|
+
if (flight) {
|
|
2923
|
+
this.inFlightUploads.delete(id);
|
|
2924
|
+
flight.abortController.abort();
|
|
2925
|
+
}
|
|
2926
|
+
this.state.next((current) => {
|
|
2927
|
+
if (!(id in current.uploads)) return current;
|
|
2928
|
+
const uploads = { ...current.uploads };
|
|
2929
|
+
delete uploads[id];
|
|
2930
|
+
return { ...current, uploads };
|
|
2931
|
+
});
|
|
2932
|
+
};
|
|
2933
|
+
/**
|
|
2934
|
+
* Starts an upload for `id`, or returns the existing in-flight promise if one is already running.
|
|
2935
|
+
* Uses {@link StreamChat.channel}(`channelCid`) → `messageComposer.attachmentManager.doUploadRequest`.
|
|
2936
|
+
* Resolves with that result; rejects if the upload rejects (the record is removed from state either way).
|
|
2937
|
+
*/
|
|
2938
|
+
this.upload = ({
|
|
2939
|
+
id,
|
|
2940
|
+
channelCid,
|
|
2941
|
+
file
|
|
2942
|
+
}) => {
|
|
2943
|
+
const existing = this.inFlightUploads.get(id);
|
|
2944
|
+
if (existing) return existing.promise;
|
|
2945
|
+
let resolvePromise;
|
|
2946
|
+
let rejectPromise;
|
|
2947
|
+
const promise = new Promise((resolve, reject) => {
|
|
2948
|
+
resolvePromise = resolve;
|
|
2949
|
+
rejectPromise = reject;
|
|
2950
|
+
});
|
|
2951
|
+
const abortController = new AbortController();
|
|
2952
|
+
this.inFlightUploads.set(id, { promise, abortController });
|
|
2953
|
+
void (async () => {
|
|
2954
|
+
const attachmentManager = this.resolveAttachmentManager(channelCid);
|
|
2955
|
+
const trackProgress = attachmentManager.config.trackUploadProgress;
|
|
2956
|
+
try {
|
|
2957
|
+
this.upsertUpload({
|
|
2958
|
+
uploadConfirmationPending: false,
|
|
2959
|
+
id,
|
|
2960
|
+
uploadProgress: trackProgress ? 0 : void 0
|
|
2961
|
+
});
|
|
2962
|
+
const onProgress = trackProgress ? (progress) => {
|
|
2963
|
+
this.updateUpload({
|
|
2964
|
+
id,
|
|
2965
|
+
uploadProgress: progress,
|
|
2966
|
+
// Only a number says anything about the flush, so a report without one leaves
|
|
2967
|
+
// the flag alone: `undefined` means the transport cannot measure this upload,
|
|
2968
|
+
// not that bytes were un-sent. Lowering it there would drop a UI that had
|
|
2969
|
+
// already gone indeterminate back to a determinate one with nothing to show.
|
|
2970
|
+
//
|
|
2971
|
+
// The record is removed in the `finally` below, so a record that still exists
|
|
2972
|
+
// while reporting 100% can only mean "flushed, awaiting the response".
|
|
2973
|
+
...typeof progress === "number" ? { uploadConfirmationPending: progress >= 100 } : {}
|
|
2974
|
+
});
|
|
2975
|
+
} : void 0;
|
|
2976
|
+
const uploadRequestOptions = {
|
|
2977
|
+
abortSignal: abortController.signal,
|
|
2978
|
+
...onProgress ? { onProgress } : {}
|
|
2979
|
+
};
|
|
2980
|
+
const response = await attachmentManager.doUploadRequest(
|
|
2981
|
+
file,
|
|
2982
|
+
uploadRequestOptions
|
|
2983
|
+
);
|
|
2984
|
+
resolvePromise(response);
|
|
2985
|
+
} catch (error) {
|
|
2986
|
+
rejectPromise(error);
|
|
2987
|
+
} finally {
|
|
2988
|
+
this.inFlightUploads.delete(id);
|
|
2989
|
+
this.deleteUploadRecord(id);
|
|
2990
|
+
}
|
|
2991
|
+
})();
|
|
2992
|
+
return promise;
|
|
2993
|
+
};
|
|
2994
|
+
this.upsertUpload = (record) => {
|
|
2995
|
+
this.state.partialNext({
|
|
2996
|
+
uploads: upsertById(this.uploads, record)
|
|
2997
|
+
});
|
|
2998
|
+
};
|
|
2999
|
+
this.updateUpload = (record) => {
|
|
3000
|
+
this.state.next((current) => {
|
|
3001
|
+
const nextUploads = updateById(current.uploads, record);
|
|
3002
|
+
if (!nextUploads) return current;
|
|
3003
|
+
return { ...current, uploads: nextUploads };
|
|
3004
|
+
});
|
|
3005
|
+
};
|
|
3006
|
+
this.state = new StateStore(initState());
|
|
3007
|
+
}
|
|
3008
|
+
resolveAttachmentManager(channelCid) {
|
|
3009
|
+
const colon = channelCid.indexOf(":");
|
|
3010
|
+
if (colon <= 0 || colon === channelCid.length - 1) {
|
|
3011
|
+
throw new Error(`Invalid channelCid: ${channelCid}`);
|
|
3012
|
+
}
|
|
3013
|
+
const channelType = channelCid.slice(0, colon);
|
|
3014
|
+
const channelId = channelCid.slice(colon + 1);
|
|
3015
|
+
return this.client.channel(channelType, channelId).messageComposer.attachmentManager;
|
|
3016
|
+
}
|
|
3017
|
+
get uploads() {
|
|
3018
|
+
return this.state.getLatestValue().uploads;
|
|
3019
|
+
}
|
|
3020
|
+
};
|
|
3021
|
+
|
|
2822
3022
|
// src/messageComposer/middleware/attachmentManager/postUpload/uploadErrorHandler.ts
|
|
2823
3023
|
var createUploadErrorHandlerMiddleware = (composer) => ({
|
|
2824
3024
|
id: "stream-io/attachment-manager-middleware/upload-error",
|
|
@@ -2831,6 +3031,7 @@ var createUploadErrorHandlerMiddleware = (composer) => ({
|
|
|
2831
3031
|
const { attachment, error } = state;
|
|
2832
3032
|
if (!error) return forward();
|
|
2833
3033
|
if (!attachment) return discard();
|
|
3034
|
+
if (isUploadCancellation(error)) return forward();
|
|
2834
3035
|
const reason = error instanceof Error ? error.message : "unknown error";
|
|
2835
3036
|
composer.client.notifications.addError({
|
|
2836
3037
|
message: "Error uploading attachment",
|
|
@@ -2855,7 +3056,7 @@ var AttachmentPostUploadMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
|
2855
3056
|
super();
|
|
2856
3057
|
this.use([
|
|
2857
3058
|
createUploadErrorHandlerMiddleware(composer),
|
|
2858
|
-
createPostUploadAttachmentEnrichmentMiddleware()
|
|
3059
|
+
createPostUploadAttachmentEnrichmentMiddleware(composer)
|
|
2859
3060
|
]);
|
|
2860
3061
|
}
|
|
2861
3062
|
};
|
|
@@ -3303,7 +3504,7 @@ function mergeWithDiff(target, source, customizer) {
|
|
|
3303
3504
|
}
|
|
3304
3505
|
|
|
3305
3506
|
// src/messageComposer/attachmentManager.ts
|
|
3306
|
-
var
|
|
3507
|
+
var initState2 = ({
|
|
3307
3508
|
message
|
|
3308
3509
|
}) => ({
|
|
3309
3510
|
attachments: (message?.attachments ?? [])?.filter(({ og_scrape_url }) => !og_scrape_url).map((att) => {
|
|
@@ -3331,13 +3532,14 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3331
3532
|
...attachment,
|
|
3332
3533
|
localMetadata: {
|
|
3333
3534
|
...attachment.localMetadata,
|
|
3535
|
+
uploadConfirmationPending: false,
|
|
3334
3536
|
uploadProgress: void 0,
|
|
3335
3537
|
uploadState: "failed"
|
|
3336
3538
|
}
|
|
3337
3539
|
};
|
|
3338
3540
|
};
|
|
3339
3541
|
this.initState = ({ message } = {}) => {
|
|
3340
|
-
this.state.next(
|
|
3542
|
+
this.state.next(initState2({ message }));
|
|
3341
3543
|
};
|
|
3342
3544
|
this.getSnapshot = () => {
|
|
3343
3545
|
const state = this.state.getLatestValue();
|
|
@@ -3414,8 +3616,22 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3414
3616
|
this.state.partialNext({ attachments });
|
|
3415
3617
|
}
|
|
3416
3618
|
};
|
|
3619
|
+
/**
|
|
3620
|
+
* Releases a local preview URL the SDK minted, if it minted one.
|
|
3621
|
+
*
|
|
3622
|
+
* Only `blob:` URLs are ours to revoke: `toLocalUploadAttachment` puts a
|
|
3623
|
+
* `URL.createObjectURL` result in `previewUri` for a `File`, but for a React Native
|
|
3624
|
+
* `FileReference` it stores the caller's own native file URI, which must be left alone.
|
|
3625
|
+
*/
|
|
3626
|
+
this.revokePreviewUri = (attachment) => {
|
|
3627
|
+
const previewUri = attachment.localMetadata?.previewUri;
|
|
3628
|
+
if (previewUri?.startsWith("blob:")) URL.revokeObjectURL?.(previewUri);
|
|
3629
|
+
};
|
|
3417
3630
|
this.removeAttachments = (localAttachmentIds) => {
|
|
3418
3631
|
if (!localAttachmentIds.length) return;
|
|
3632
|
+
const removedAttachments = this.attachments.filter(
|
|
3633
|
+
(attachment) => localAttachmentIds.includes(attachment.localMetadata?.id)
|
|
3634
|
+
);
|
|
3419
3635
|
this.state.partialNext({
|
|
3420
3636
|
attachments: this.attachments.filter(
|
|
3421
3637
|
(attachment) => !localAttachmentIds.includes(attachment.localMetadata?.id)
|
|
@@ -3424,6 +3640,7 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3424
3640
|
for (const id of localAttachmentIds) {
|
|
3425
3641
|
this.client.uploadManager.deleteUploadRecord(id);
|
|
3426
3642
|
}
|
|
3643
|
+
removedAttachments.forEach(this.revokePreviewUri);
|
|
3427
3644
|
};
|
|
3428
3645
|
this.getUploadConfigCheck = async (fileLike) => {
|
|
3429
3646
|
const client = this.channel.getClient();
|
|
@@ -3575,21 +3792,27 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3575
3792
|
localMetadata: {
|
|
3576
3793
|
...attachment.localMetadata,
|
|
3577
3794
|
uploadState: "failed",
|
|
3578
|
-
uploadProgress: void 0
|
|
3795
|
+
uploadProgress: void 0,
|
|
3796
|
+
// `false`, not `undefined`: these updates go through `updateAttachment`, which merges
|
|
3797
|
+
// via `mergeWith` — and that skips `undefined` source values, so `undefined` would
|
|
3798
|
+
// leave a stale `true` in place.
|
|
3799
|
+
uploadConfirmationPending: false
|
|
3579
3800
|
}
|
|
3580
3801
|
};
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3802
|
+
if (!isUploadCancellation(error)) {
|
|
3803
|
+
this.client.notifications.addError({
|
|
3804
|
+
message: "Error uploading attachment",
|
|
3805
|
+
origin: {
|
|
3806
|
+
emitter: "AttachmentManager",
|
|
3807
|
+
context: { attachment, failedAttachment }
|
|
3808
|
+
},
|
|
3809
|
+
options: {
|
|
3810
|
+
type: "api:attachment:upload:failed",
|
|
3811
|
+
metadata: { reason },
|
|
3812
|
+
originalError: error instanceof Error ? error : void 0
|
|
3813
|
+
}
|
|
3814
|
+
});
|
|
3815
|
+
}
|
|
3593
3816
|
this.updateAttachment(failedAttachment);
|
|
3594
3817
|
return failedAttachment;
|
|
3595
3818
|
}
|
|
@@ -3602,7 +3825,9 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3602
3825
|
localMetadata: {
|
|
3603
3826
|
...attachment.localMetadata,
|
|
3604
3827
|
uploadState: "finished",
|
|
3605
|
-
uploadProgress: void 0
|
|
3828
|
+
uploadProgress: void 0,
|
|
3829
|
+
// See the note in the failure branch: `undefined` cannot clear through `mergeWith`.
|
|
3830
|
+
uploadConfirmationPending: false
|
|
3606
3831
|
}
|
|
3607
3832
|
};
|
|
3608
3833
|
const previewUri = uploadedAttachment.localMetadata.previewUri;
|
|
@@ -3651,7 +3876,9 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3651
3876
|
localMetadata: {
|
|
3652
3877
|
...attachment.localMetadata,
|
|
3653
3878
|
uploadState: error ? "failed" : "finished",
|
|
3654
|
-
uploadProgress: void 0
|
|
3879
|
+
uploadProgress: void 0,
|
|
3880
|
+
// See the note in `uploadAttachment`: `undefined` cannot clear through `mergeWith`.
|
|
3881
|
+
uploadConfirmationPending: false
|
|
3655
3882
|
}
|
|
3656
3883
|
},
|
|
3657
3884
|
error,
|
|
@@ -3676,7 +3903,7 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3676
3903
|
);
|
|
3677
3904
|
};
|
|
3678
3905
|
this.composer = composer;
|
|
3679
|
-
this.state = new StateStore(
|
|
3906
|
+
this.state = new StateStore(initState2({ message }));
|
|
3680
3907
|
this.attachmentsByIdGetterCache = { attachmentsById: {}, attachments: [] };
|
|
3681
3908
|
this.preUploadMiddlewareExecutor = new AttachmentPreUploadMiddlewareExecutor({
|
|
3682
3909
|
composer
|
|
@@ -3781,7 +4008,8 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3781
4008
|
localMetadata: {
|
|
3782
4009
|
...attachment.localMetadata,
|
|
3783
4010
|
uploadState: "uploading",
|
|
3784
|
-
uploadProgress: this.config.trackUploadProgress ? 0 : void 0
|
|
4011
|
+
uploadProgress: this.config.trackUploadProgress ? 0 : void 0,
|
|
4012
|
+
uploadConfirmationPending: false
|
|
3785
4013
|
}
|
|
3786
4014
|
}
|
|
3787
4015
|
]);
|
|
@@ -3794,7 +4022,8 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3794
4022
|
localMetadata: {
|
|
3795
4023
|
...attachment.localMetadata,
|
|
3796
4024
|
uploadState: "uploading",
|
|
3797
|
-
uploadProgress: nextUpload.uploadProgress
|
|
4025
|
+
uploadProgress: nextUpload.uploadProgress,
|
|
4026
|
+
uploadConfirmationPending: nextUpload.uploadConfirmationPending
|
|
3798
4027
|
}
|
|
3799
4028
|
});
|
|
3800
4029
|
}
|
|
@@ -3848,6 +4077,50 @@ var localAttachmentToAttachment = (localAttachment) => {
|
|
|
3848
4077
|
const { localMetadata, ...attachment } = localAttachment;
|
|
3849
4078
|
return attachment;
|
|
3850
4079
|
};
|
|
4080
|
+
var composeWithPendingUploads = ({
|
|
4081
|
+
composer,
|
|
4082
|
+
state
|
|
4083
|
+
}) => {
|
|
4084
|
+
const composerIsKeptAsDraft = !!composer.pollId;
|
|
4085
|
+
const relevantAttachments = composer.attachmentManager.attachments.filter(
|
|
4086
|
+
(attachment) => isFinishedUpload(attachment) || !composerIsKeptAsDraft && isPendingUpload(attachment)
|
|
4087
|
+
);
|
|
4088
|
+
const localAttachments = (state.localMessage.attachments ?? []).concat(
|
|
4089
|
+
relevantAttachments.map(
|
|
4090
|
+
(attachment) => isPendingUpload(attachment) ? attachment : localAttachmentToAttachment(attachment)
|
|
4091
|
+
)
|
|
4092
|
+
);
|
|
4093
|
+
const messageAttachments = (state.message.attachments ?? []).concat(
|
|
4094
|
+
relevantAttachments.filter(isFinishedUpload).map(localAttachmentToAttachment)
|
|
4095
|
+
);
|
|
4096
|
+
if (!localAttachments.length && !messageAttachments.length) return state;
|
|
4097
|
+
return {
|
|
4098
|
+
...state,
|
|
4099
|
+
localMessage: localAttachments.length ? {
|
|
4100
|
+
...state.localMessage,
|
|
4101
|
+
attachments: localAttachments
|
|
4102
|
+
} : state.localMessage,
|
|
4103
|
+
message: messageAttachments.length ? {
|
|
4104
|
+
...state.message,
|
|
4105
|
+
attachments: messageAttachments
|
|
4106
|
+
} : state.message
|
|
4107
|
+
};
|
|
4108
|
+
};
|
|
4109
|
+
var createSendWithPendingUploadsAttachmentsMiddleware = (composer) => ({
|
|
4110
|
+
allowsPendingUploads: true,
|
|
4111
|
+
id: "stream-io/message-composer-middleware/attachments",
|
|
4112
|
+
handlers: {
|
|
4113
|
+
compose: ({
|
|
4114
|
+
state,
|
|
4115
|
+
next,
|
|
4116
|
+
forward
|
|
4117
|
+
}) => {
|
|
4118
|
+
const { attachmentManager } = composer;
|
|
4119
|
+
if (!attachmentManager) return forward();
|
|
4120
|
+
return next(composeWithPendingUploads({ composer, state }));
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
});
|
|
3851
4124
|
var createAttachmentsCompositionMiddleware = (composer) => ({
|
|
3852
4125
|
id: "stream-io/message-composer-middleware/attachments",
|
|
3853
4126
|
handlers: {
|
|
@@ -4064,7 +4337,7 @@ var getInitialMentions = (message) => {
|
|
|
4064
4337
|
};
|
|
4065
4338
|
var isSameMentionEntity = (first, second) => first.id === second.id && first.mentionType === second.mentionType;
|
|
4066
4339
|
var getMentionsFromState = (state) => state.mentions ?? state.mentionedUsers.map(userResponseToMentionEntity);
|
|
4067
|
-
var
|
|
4340
|
+
var initState3 = ({
|
|
4068
4341
|
composer,
|
|
4069
4342
|
message
|
|
4070
4343
|
}) => {
|
|
@@ -4093,7 +4366,7 @@ var initState2 = ({
|
|
|
4093
4366
|
var TextComposer = class {
|
|
4094
4367
|
constructor({ composer, message }) {
|
|
4095
4368
|
this.initState = ({ message } = {}) => {
|
|
4096
|
-
this.state.next(
|
|
4369
|
+
this.state.next(initState3({ composer: this.composer, message }));
|
|
4097
4370
|
};
|
|
4098
4371
|
this.getSnapshot = (state = this.state.getLatestValue()) => state;
|
|
4099
4372
|
this.restoreSnapshot = (snapshot) => {
|
|
@@ -4286,7 +4559,7 @@ var TextComposer = class {
|
|
|
4286
4559
|
this.commitState(output.state);
|
|
4287
4560
|
};
|
|
4288
4561
|
this.composer = composer;
|
|
4289
|
-
this.state = new StateStore(
|
|
4562
|
+
this.state = new StateStore(initState3({ composer, message }));
|
|
4290
4563
|
this.middlewareExecutor = new TextComposerMiddlewareExecutor({ composer });
|
|
4291
4564
|
}
|
|
4292
4565
|
get channel() {
|
|
@@ -4436,13 +4709,41 @@ function isErrorResponse(res) {
|
|
|
4436
4709
|
|
|
4437
4710
|
// src/search/BaseSearchSource.ts
|
|
4438
4711
|
var DEFAULT_SEARCH_SOURCE_OPTIONS = {
|
|
4439
|
-
debounceMs: 300,
|
|
4440
4712
|
pageSize: 10,
|
|
4441
4713
|
allowEmptySearchString: false,
|
|
4442
4714
|
resetOnNewSearchQuery: true
|
|
4443
4715
|
};
|
|
4716
|
+
var resolveDebounceOptions = ({
|
|
4717
|
+
debounceMs,
|
|
4718
|
+
shortQueryDebounceMs,
|
|
4719
|
+
longQueryDebounceMs,
|
|
4720
|
+
shortQueryMaxLength
|
|
4721
|
+
}) => ({
|
|
4722
|
+
shortQueryDebounceMs: shortQueryDebounceMs ?? debounceMs ?? 500,
|
|
4723
|
+
longQueryDebounceMs: longQueryDebounceMs ?? debounceMs ?? 300,
|
|
4724
|
+
shortQueryMaxLength: shortQueryMaxLength ?? 2
|
|
4725
|
+
});
|
|
4444
4726
|
var BaseSearchSourceBase = class {
|
|
4445
4727
|
constructor(options) {
|
|
4728
|
+
this.setDebounceOptions = (options = {}) => {
|
|
4729
|
+
const resolved = resolveDebounceOptions(options);
|
|
4730
|
+
this.shortQueryDebounceMs = resolved.shortQueryDebounceMs;
|
|
4731
|
+
this.longQueryDebounceMs = resolved.longQueryDebounceMs;
|
|
4732
|
+
this.shortQueryMaxLength = resolved.shortQueryMaxLength;
|
|
4733
|
+
this.searchDebounced = debounce(
|
|
4734
|
+
this.executeQuery.bind(this),
|
|
4735
|
+
(searchString) => this.getDebounceMs(searchString)
|
|
4736
|
+
);
|
|
4737
|
+
};
|
|
4738
|
+
/**
|
|
4739
|
+
* Short queries match too much and are slow server-side, so they get a longer debounce.
|
|
4740
|
+
* Resolved per call, which is what lets the interval switch as the user keeps typing.
|
|
4741
|
+
*/
|
|
4742
|
+
this.getDebounceMs = (searchString) => {
|
|
4743
|
+
const { length } = searchString ?? this.searchQuery;
|
|
4744
|
+
return length <= this.shortQueryMaxLength ? this.shortQueryDebounceMs : this.longQueryDebounceMs;
|
|
4745
|
+
};
|
|
4746
|
+
this.search = (searchQuery) => this.searchDebounced(searchQuery);
|
|
4446
4747
|
this.activate = () => {
|
|
4447
4748
|
if (this.isActive) return;
|
|
4448
4749
|
this.state.partialNext({ isActive: true });
|
|
@@ -4454,7 +4755,7 @@ var BaseSearchSourceBase = class {
|
|
|
4454
4755
|
this.canExecuteQuery = (newSearchString) => {
|
|
4455
4756
|
const hasNewSearchQuery = typeof newSearchString !== "undefined";
|
|
4456
4757
|
const searchString = newSearchString ?? this.searchQuery;
|
|
4457
|
-
return !!(this.isActive &&
|
|
4758
|
+
return !!(this.isActive && this.canDispatchQuery(hasNewSearchQuery) && (this.allowEmptySearchString || searchString));
|
|
4458
4759
|
};
|
|
4459
4760
|
const { pageSize, allowEmptySearchString, resetOnNewSearchQuery } = {
|
|
4460
4761
|
...DEFAULT_SEARCH_SOURCE_OPTIONS,
|
|
@@ -4464,6 +4765,14 @@ var BaseSearchSourceBase = class {
|
|
|
4464
4765
|
this.allowEmptySearchString = allowEmptySearchString;
|
|
4465
4766
|
this.resetOnNewSearchQuery = resetOnNewSearchQuery;
|
|
4466
4767
|
this.state = new StateStore(this.initialState);
|
|
4768
|
+
this.setDebounceOptions(options ?? {});
|
|
4769
|
+
}
|
|
4770
|
+
/**
|
|
4771
|
+
* A new search query preempts an in-flight one; pagination waits for it to finish
|
|
4772
|
+
* and needs a next page to fetch.
|
|
4773
|
+
*/
|
|
4774
|
+
canDispatchQuery(hasNewSearchQuery) {
|
|
4775
|
+
return hasNewSearchQuery || !this.isLoading && this.hasNext;
|
|
4467
4776
|
}
|
|
4468
4777
|
get lastQueryError() {
|
|
4469
4778
|
return this.state.getLatestValue().lastQueryError;
|
|
@@ -4558,21 +4867,30 @@ var BaseSearchSourceBase = class {
|
|
|
4558
4867
|
}
|
|
4559
4868
|
};
|
|
4560
4869
|
var BaseSearchSource = class extends BaseSearchSourceBase {
|
|
4561
|
-
constructor(
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
this.
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
this.
|
|
4870
|
+
constructor() {
|
|
4871
|
+
super(...arguments);
|
|
4872
|
+
/** Aborts the in-flight request, if any, once a newer query is dispatched. */
|
|
4873
|
+
this.queryAbortController = null;
|
|
4874
|
+
}
|
|
4875
|
+
/** Aborts the in-flight request, if any. Returns true when one was aborted. */
|
|
4876
|
+
abortInFlightQuery() {
|
|
4877
|
+
if (!this.queryAbortController) return false;
|
|
4878
|
+
this.queryAbortController.abort();
|
|
4879
|
+
this.queryAbortController = null;
|
|
4880
|
+
return true;
|
|
4881
|
+
}
|
|
4882
|
+
resetState() {
|
|
4883
|
+
this.abortInFlightQuery();
|
|
4884
|
+
super.resetState();
|
|
4569
4885
|
}
|
|
4570
4886
|
async executeQuery(newSearchString) {
|
|
4571
4887
|
if (!this.canExecuteQuery(newSearchString)) return;
|
|
4888
|
+
this.abortInFlightQuery();
|
|
4889
|
+
const { signal } = this.queryAbortController = new AbortController();
|
|
4572
4890
|
const { hasNewSearchQuery, searchString } = this.prepareStateForQuery(newSearchString);
|
|
4573
4891
|
let stateUpdate = {};
|
|
4574
4892
|
try {
|
|
4575
|
-
const results = await this.query(searchString);
|
|
4893
|
+
const results = await this.query(searchString, { signal });
|
|
4576
4894
|
if (!results) return;
|
|
4577
4895
|
const { items } = results;
|
|
4578
4896
|
stateUpdate = this.updatePaginationStateFromQuery(results);
|
|
@@ -4583,23 +4901,19 @@ var BaseSearchSource = class extends BaseSearchSourceBase {
|
|
|
4583
4901
|
stateUpdate.hasNext = false;
|
|
4584
4902
|
}
|
|
4585
4903
|
} finally {
|
|
4586
|
-
|
|
4904
|
+
if (!signal.aborted) {
|
|
4905
|
+
this.state.next(this.getStateAfterQuery(stateUpdate, hasNewSearchQuery));
|
|
4906
|
+
}
|
|
4587
4907
|
}
|
|
4588
4908
|
}
|
|
4589
4909
|
cancelScheduledQuery() {
|
|
4590
4910
|
this.searchDebounced.cancel();
|
|
4911
|
+
if (this.abortInFlightQuery() && this.isLoading) {
|
|
4912
|
+
this.state.partialNext({ isLoading: false });
|
|
4913
|
+
}
|
|
4591
4914
|
}
|
|
4592
4915
|
};
|
|
4593
4916
|
var BaseSearchSourceSync = class extends BaseSearchSourceBase {
|
|
4594
|
-
constructor(options) {
|
|
4595
|
-
const { debounceMs } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
|
|
4596
|
-
super(options);
|
|
4597
|
-
this.setDebounceOptions = ({ debounceMs }) => {
|
|
4598
|
-
this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);
|
|
4599
|
-
};
|
|
4600
|
-
this.search = (searchQuery) => this.searchDebounced(searchQuery);
|
|
4601
|
-
this.setDebounceOptions({ debounceMs });
|
|
4602
|
-
}
|
|
4603
4917
|
executeQuery(newSearchString) {
|
|
4604
4918
|
if (!this.canExecuteQuery(newSearchString)) return;
|
|
4605
4919
|
const { hasNewSearchQuery, searchString } = this.prepareStateForQuery(newSearchString);
|
|
@@ -4895,13 +5209,13 @@ var UserGroupPaginator = class extends BasePaginator {
|
|
|
4895
5209
|
// src/search/ChannelMemberSearchSource.ts
|
|
4896
5210
|
var ChannelMemberSearchSource = class extends BaseSearchSource {
|
|
4897
5211
|
constructor(channel, options, filterBuilderOptions = {}) {
|
|
4898
|
-
|
|
5212
|
+
const { filters, sort, searchOptions, ...restOptions } = options || {};
|
|
5213
|
+
super({ ...restOptions, allowEmptySearchString: true });
|
|
4899
5214
|
this.type = "members";
|
|
4900
|
-
this.canExecuteQuery = (newSearchString) => {
|
|
4901
|
-
const hasNewSearchQuery = typeof newSearchString !== "undefined";
|
|
4902
|
-
return this.isActive && !this.isLoading && (this.hasNext || hasNewSearchQuery);
|
|
4903
|
-
};
|
|
4904
5215
|
this.channel = channel;
|
|
5216
|
+
this.filters = filters;
|
|
5217
|
+
this.sort = sort;
|
|
5218
|
+
this.searchOptions = searchOptions;
|
|
4905
5219
|
this.filterBuilder = new FilterBuilder({
|
|
4906
5220
|
initialFilterConfig: {
|
|
4907
5221
|
default: {
|
|
@@ -4917,7 +5231,7 @@ var ChannelMemberSearchSource = class extends BaseSearchSource {
|
|
|
4917
5231
|
...filterBuilderOptions
|
|
4918
5232
|
});
|
|
4919
5233
|
}
|
|
4920
|
-
async query(searchQuery) {
|
|
5234
|
+
async query(searchQuery, queryOptions = {}) {
|
|
4921
5235
|
const filters = this.filterBuilder.buildFilters({
|
|
4922
5236
|
baseFilters: this.filters,
|
|
4923
5237
|
context: {
|
|
@@ -4926,7 +5240,12 @@ var ChannelMemberSearchSource = class extends BaseSearchSource {
|
|
|
4926
5240
|
});
|
|
4927
5241
|
const sort = this.sort ?? [];
|
|
4928
5242
|
const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };
|
|
4929
|
-
const { members } = await this.channel.queryMembers(
|
|
5243
|
+
const { members } = await this.channel.queryMembers(
|
|
5244
|
+
filters ?? {},
|
|
5245
|
+
sort,
|
|
5246
|
+
options,
|
|
5247
|
+
queryOptions
|
|
5248
|
+
);
|
|
4930
5249
|
return { items: members };
|
|
4931
5250
|
}
|
|
4932
5251
|
filterQueryResults(items) {
|
|
@@ -5041,9 +5360,13 @@ var SearchController = class {
|
|
|
5041
5360
|
// src/search/UserSearchSource.ts
|
|
5042
5361
|
var UserSearchSource = class extends BaseSearchSource {
|
|
5043
5362
|
constructor(client, options, filterBuilderOptions = {}) {
|
|
5044
|
-
|
|
5363
|
+
const { filters, sort, searchOptions, ...restOptions } = options || {};
|
|
5364
|
+
super(restOptions);
|
|
5045
5365
|
this.type = "users";
|
|
5046
5366
|
this.client = client;
|
|
5367
|
+
this.filters = filters;
|
|
5368
|
+
this.sort = sort;
|
|
5369
|
+
this.searchOptions = searchOptions;
|
|
5047
5370
|
this.filterBuilder = new FilterBuilder({
|
|
5048
5371
|
initialFilterConfig: {
|
|
5049
5372
|
$or: {
|
|
@@ -5059,7 +5382,7 @@ var UserSearchSource = class extends BaseSearchSource {
|
|
|
5059
5382
|
...filterBuilderOptions
|
|
5060
5383
|
});
|
|
5061
5384
|
}
|
|
5062
|
-
async query(searchQuery) {
|
|
5385
|
+
async query(searchQuery, queryOptions = {}) {
|
|
5063
5386
|
const filters = this.filterBuilder.buildFilters({
|
|
5064
5387
|
baseFilters: this.filters,
|
|
5065
5388
|
context: { searchQuery }
|
|
@@ -5072,7 +5395,7 @@ var UserSearchSource = class extends BaseSearchSource {
|
|
|
5072
5395
|
sort = { id: 1, ...this.sort };
|
|
5073
5396
|
}
|
|
5074
5397
|
const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };
|
|
5075
|
-
const { users } = await this.client.queryUsers(filters, sort, options);
|
|
5398
|
+
const { users } = await this.client.queryUsers(filters, sort, options, queryOptions);
|
|
5076
5399
|
return { items: users };
|
|
5077
5400
|
}
|
|
5078
5401
|
filterQueryResults(items) {
|
|
@@ -5083,9 +5406,13 @@ var UserSearchSource = class extends BaseSearchSource {
|
|
|
5083
5406
|
// src/search/ChannelSearchSource.ts
|
|
5084
5407
|
var ChannelSearchSource = class extends BaseSearchSource {
|
|
5085
5408
|
constructor(client, options, filterBuilderOptions = {}) {
|
|
5086
|
-
|
|
5409
|
+
const { filters, sort, searchOptions, ...restOptions } = options || {};
|
|
5410
|
+
super(restOptions);
|
|
5087
5411
|
this.type = "channels";
|
|
5088
5412
|
this.client = client;
|
|
5413
|
+
this.filters = filters;
|
|
5414
|
+
this.sort = sort;
|
|
5415
|
+
this.searchOptions = searchOptions;
|
|
5089
5416
|
this.filterBuilder = new FilterBuilder({
|
|
5090
5417
|
...filterBuilderOptions,
|
|
5091
5418
|
initialFilterConfig: {
|
|
@@ -5097,7 +5424,7 @@ var ChannelSearchSource = class extends BaseSearchSource {
|
|
|
5097
5424
|
}
|
|
5098
5425
|
});
|
|
5099
5426
|
}
|
|
5100
|
-
async query(searchQuery) {
|
|
5427
|
+
async query(searchQuery, queryOptions = {}) {
|
|
5101
5428
|
const filters = this.filterBuilder.buildFilters({
|
|
5102
5429
|
baseFilters: {
|
|
5103
5430
|
...this.client.userID ? { members: { $in: [this.client.userID] } } : {},
|
|
@@ -5107,7 +5434,7 @@ var ChannelSearchSource = class extends BaseSearchSource {
|
|
|
5107
5434
|
});
|
|
5108
5435
|
const sort = this.sort ?? {};
|
|
5109
5436
|
const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };
|
|
5110
|
-
const items = await this.client.queryChannels(filters, sort, options);
|
|
5437
|
+
const items = await this.client.queryChannels(filters, sort, options, queryOptions);
|
|
5111
5438
|
return { items };
|
|
5112
5439
|
}
|
|
5113
5440
|
filterQueryResults(items) {
|
|
@@ -5118,9 +5445,24 @@ var ChannelSearchSource = class extends BaseSearchSource {
|
|
|
5118
5445
|
// src/search/MessageSearchSource.ts
|
|
5119
5446
|
var MessageSearchSource = class extends BaseSearchSource {
|
|
5120
5447
|
constructor(client, options, filterBuilderOptions) {
|
|
5121
|
-
|
|
5448
|
+
const {
|
|
5449
|
+
messageSearchChannelFilters,
|
|
5450
|
+
messageSearchFilters,
|
|
5451
|
+
messageSearchSort,
|
|
5452
|
+
channelQueryFilters,
|
|
5453
|
+
channelQuerySort,
|
|
5454
|
+
channelQueryOptions,
|
|
5455
|
+
...restOptions
|
|
5456
|
+
} = options || {};
|
|
5457
|
+
super(restOptions);
|
|
5122
5458
|
this.type = "messages";
|
|
5123
5459
|
this.client = client;
|
|
5460
|
+
this.messageSearchChannelFilters = messageSearchChannelFilters;
|
|
5461
|
+
this.messageSearchFilters = messageSearchFilters;
|
|
5462
|
+
this.messageSearchSort = messageSearchSort;
|
|
5463
|
+
this.channelQueryFilters = channelQueryFilters;
|
|
5464
|
+
this.channelQuerySort = channelQuerySort;
|
|
5465
|
+
this.channelQueryOptions = channelQueryOptions;
|
|
5124
5466
|
this.messageSearchChannelFilterBuilder = new FilterBuilder(filterBuilderOptions?.messageSearchChannel);
|
|
5125
5467
|
this.messageSearchFilterBuilder = new FilterBuilder({
|
|
5126
5468
|
...filterBuilderOptions?.messageSearch,
|
|
@@ -5143,7 +5485,7 @@ var MessageSearchSource = class extends BaseSearchSource {
|
|
|
5143
5485
|
}
|
|
5144
5486
|
});
|
|
5145
5487
|
}
|
|
5146
|
-
async query(searchQuery) {
|
|
5488
|
+
async query(searchQuery, queryOptions = {}) {
|
|
5147
5489
|
if (!this.client.userID || this.next === null) return { items: [] };
|
|
5148
5490
|
const channelFilters = this.messageSearchChannelFilterBuilder.buildFilters({
|
|
5149
5491
|
baseFilters: {
|
|
@@ -5171,9 +5513,11 @@ var MessageSearchSource = class extends BaseSearchSource {
|
|
|
5171
5513
|
const { next, results } = await this.client.search(
|
|
5172
5514
|
channelFilters,
|
|
5173
5515
|
messageFilters,
|
|
5174
|
-
options
|
|
5516
|
+
options,
|
|
5517
|
+
queryOptions
|
|
5175
5518
|
);
|
|
5176
5519
|
const items = results.map(({ message }) => message);
|
|
5520
|
+
if (queryOptions.signal?.aborted) return { items, next };
|
|
5177
5521
|
const cids = Array.from(
|
|
5178
5522
|
items.reduce((acc, message) => {
|
|
5179
5523
|
if (message.cid && !this.client.activeChannels[message.cid]) acc.add(message.cid);
|
|
@@ -5191,7 +5535,8 @@ var MessageSearchSource = class extends BaseSearchSource {
|
|
|
5191
5535
|
last_message_at: -1,
|
|
5192
5536
|
...this.channelQuerySort
|
|
5193
5537
|
},
|
|
5194
|
-
this.channelQueryOptions
|
|
5538
|
+
this.channelQueryOptions,
|
|
5539
|
+
queryOptions
|
|
5195
5540
|
);
|
|
5196
5541
|
}
|
|
5197
5542
|
return { items, next };
|
|
@@ -5916,6 +6261,13 @@ var MessageComposerMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
|
5916
6261
|
createCompositionDataCleanupMiddleware(composer)
|
|
5917
6262
|
]);
|
|
5918
6263
|
}
|
|
6264
|
+
/**
|
|
6265
|
+
* Narrows the base accessor to the composition middleware type, so callers can read the
|
|
6266
|
+
* declarations it carries (`allowsPendingUploads`) without casting.
|
|
6267
|
+
*/
|
|
6268
|
+
get installedMiddleware() {
|
|
6269
|
+
return super.installedMiddleware;
|
|
6270
|
+
}
|
|
5919
6271
|
};
|
|
5920
6272
|
var MessageDraftComposerMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
5921
6273
|
constructor({ composer }) {
|
|
@@ -6485,13 +6837,18 @@ var MentionsSearchSource = class extends BaseSearchSource {
|
|
|
6485
6837
|
constructor(channel, options) {
|
|
6486
6838
|
const {
|
|
6487
6839
|
mentionAllAppUsers,
|
|
6840
|
+
memberFilters,
|
|
6841
|
+
memberSort,
|
|
6842
|
+
searchOptions,
|
|
6488
6843
|
suggestionFactoryMappers,
|
|
6489
6844
|
textComposerText,
|
|
6490
6845
|
transliterate,
|
|
6491
6846
|
trigger,
|
|
6847
|
+
userFilters,
|
|
6848
|
+
userSort,
|
|
6492
6849
|
...restOptions
|
|
6493
6850
|
} = options || {};
|
|
6494
|
-
super(restOptions);
|
|
6851
|
+
super({ ...restOptions, allowEmptySearchString: true });
|
|
6495
6852
|
this.type = "mentions";
|
|
6496
6853
|
this.normalizeSearchValue = (value) => this.transliterate(removeDiacritics(value)).toLowerCase();
|
|
6497
6854
|
this.matchesSearchQuery = (value, searchQuery) => {
|
|
@@ -6529,10 +6886,6 @@ var MentionsSearchSource = class extends BaseSearchSource {
|
|
|
6529
6886
|
this.toHereMentionSuggestion = (searchToken = this.searchQuery) => this.mapMentionSuggestion("here", "here", searchToken);
|
|
6530
6887
|
this.toRoleMentionSuggestion = (role, searchToken = this.searchQuery) => this.mapMentionSuggestion("role", role, searchToken);
|
|
6531
6888
|
this.toUserGroupMentionSuggestion = (userGroup, searchToken = this.searchQuery) => this.mapMentionSuggestion("user_group", userGroup, searchToken);
|
|
6532
|
-
this.canExecuteQuery = (newSearchString) => {
|
|
6533
|
-
const hasNewSearchQuery = typeof newSearchString !== "undefined";
|
|
6534
|
-
return this.isActive && !this.isLoading && (hasNewSearchQuery || this.hasNext);
|
|
6535
|
-
};
|
|
6536
6889
|
this.transliterate = (text) => text;
|
|
6537
6890
|
this.getMembersAndWatchers = () => {
|
|
6538
6891
|
const memberUsers = Object.values(this.channel.state.members ?? {}).map(
|
|
@@ -6552,10 +6905,10 @@ var MentionsSearchSource = class extends BaseSearchSource {
|
|
|
6552
6905
|
...this.isMentionTypeAllowed("channel") ? [this.toChannelMentionSuggestion(searchQuery)] : [],
|
|
6553
6906
|
...this.isMentionTypeAllowed("here") ? [this.toHereMentionSuggestion(searchQuery)] : []
|
|
6554
6907
|
].filter(({ name }) => this.matchesPrefixSearchQuery(name, searchQuery));
|
|
6555
|
-
this.getRoleMentionSuggestions = async (query) => {
|
|
6908
|
+
this.getRoleMentionSuggestions = async (query, queryOptions = {}) => {
|
|
6556
6909
|
if (!this.isMentionTypeAllowed("role")) return [];
|
|
6557
6910
|
if (!query) return [];
|
|
6558
|
-
const { roles } = await this.client.searchRoles({ query });
|
|
6911
|
+
const { roles } = await this.client.searchRoles({ query }, queryOptions);
|
|
6559
6912
|
return [...roles?.map((role) => role.name) ?? []].sort((left, right) => left.localeCompare(right)).map((role) => this.toRoleMentionSuggestion(role, query));
|
|
6560
6913
|
};
|
|
6561
6914
|
this.searchMembersLocally = (searchQuery) => {
|
|
@@ -6617,20 +6970,25 @@ var MentionsSearchSource = class extends BaseSearchSource {
|
|
|
6617
6970
|
options: { ...this.searchOptions, limit: this.pageSize, offset }
|
|
6618
6971
|
};
|
|
6619
6972
|
};
|
|
6620
|
-
this.queryUsers = async (searchQuery, offset = 0) => {
|
|
6973
|
+
this.queryUsers = async (searchQuery, offset = 0, queryOptions = {}) => {
|
|
6621
6974
|
const { filters, sort, options } = this.prepareQueryUsersParams(searchQuery, offset);
|
|
6622
|
-
const { users } = await this.client.queryUsers(filters, sort, options);
|
|
6975
|
+
const { users } = await this.client.queryUsers(filters, sort, options, queryOptions);
|
|
6623
6976
|
return users;
|
|
6624
6977
|
};
|
|
6625
|
-
this.queryMembers = async (searchQuery, offset = 0) => {
|
|
6978
|
+
this.queryMembers = async (searchQuery, offset = 0, queryOptions = {}) => {
|
|
6626
6979
|
const { filters, sort, options } = this.prepareQueryMembersParams(
|
|
6627
6980
|
searchQuery,
|
|
6628
6981
|
offset
|
|
6629
6982
|
);
|
|
6630
|
-
const response = await this.channel.queryMembers(
|
|
6983
|
+
const response = await this.channel.queryMembers(
|
|
6984
|
+
filters,
|
|
6985
|
+
sort,
|
|
6986
|
+
options,
|
|
6987
|
+
queryOptions
|
|
6988
|
+
);
|
|
6631
6989
|
return response.members.map((member) => member.user);
|
|
6632
6990
|
};
|
|
6633
|
-
this.getUserSuggestionsPage = async (searchQuery, userOffset = 0) => {
|
|
6991
|
+
this.getUserSuggestionsPage = async (searchQuery, userOffset = 0, queryOptions = {}) => {
|
|
6634
6992
|
if (!this.isMentionTypeAllowed("user")) {
|
|
6635
6993
|
return {
|
|
6636
6994
|
items: [],
|
|
@@ -6640,7 +6998,7 @@ var MentionsSearchSource = class extends BaseSearchSource {
|
|
|
6640
6998
|
let users;
|
|
6641
6999
|
const shouldSearchLocally = this.allMembersLoadedWithInitialChannelQuery || !searchQuery;
|
|
6642
7000
|
if (this.config.mentionAllAppUsers) {
|
|
6643
|
-
users = await this.queryUsers(searchQuery, userOffset);
|
|
7001
|
+
users = await this.queryUsers(searchQuery, userOffset, queryOptions);
|
|
6644
7002
|
} else if (shouldSearchLocally) {
|
|
6645
7003
|
const localUsers = this.searchMembersLocally(searchQuery);
|
|
6646
7004
|
const items2 = localUsers.slice(userOffset, userOffset + this.pageSize).map((user) => this.toUserSuggestion(user, searchQuery));
|
|
@@ -6649,7 +7007,7 @@ var MentionsSearchSource = class extends BaseSearchSource {
|
|
|
6649
7007
|
nextOffset: localUsers.length > userOffset + this.pageSize ? userOffset + items2.length : void 0
|
|
6650
7008
|
};
|
|
6651
7009
|
} else {
|
|
6652
|
-
users = await this.queryMembers(searchQuery, userOffset);
|
|
7010
|
+
users = await this.queryMembers(searchQuery, userOffset, queryOptions);
|
|
6653
7011
|
}
|
|
6654
7012
|
const items = users.map((user) => this.toUserSuggestion(user, searchQuery));
|
|
6655
7013
|
return {
|
|
@@ -6666,7 +7024,7 @@ var MentionsSearchSource = class extends BaseSearchSource {
|
|
|
6666
7024
|
name_gt: lastItem.name
|
|
6667
7025
|
});
|
|
6668
7026
|
};
|
|
6669
|
-
this.getUserGroupSuggestionsPage = async (searchQuery, cursor) => {
|
|
7027
|
+
this.getUserGroupSuggestionsPage = async (searchQuery, cursor, queryOptions = {}) => {
|
|
6670
7028
|
if (!this.isMentionTypeAllowed("user_group")) {
|
|
6671
7029
|
return {
|
|
6672
7030
|
items: [],
|
|
@@ -6688,7 +7046,7 @@ var MentionsSearchSource = class extends BaseSearchSource {
|
|
|
6688
7046
|
...userGroupCursor?.id_gt ? { id_gt: userGroupCursor.id_gt } : {},
|
|
6689
7047
|
...userGroupCursor?.name_gt ? { name_gt: userGroupCursor.name_gt } : {}
|
|
6690
7048
|
};
|
|
6691
|
-
const { user_groups } = await this.client.searchUserGroups(options);
|
|
7049
|
+
const { user_groups } = await this.client.searchUserGroups(options, queryOptions);
|
|
6692
7050
|
return {
|
|
6693
7051
|
items: user_groups.map(
|
|
6694
7052
|
(userGroup) => this.toUserGroupMentionSuggestion(userGroup, searchQuery)
|
|
@@ -6698,6 +7056,11 @@ var MentionsSearchSource = class extends BaseSearchSource {
|
|
|
6698
7056
|
};
|
|
6699
7057
|
this.client = channel.getClient();
|
|
6700
7058
|
this.channel = channel;
|
|
7059
|
+
this.userFilters = userFilters;
|
|
7060
|
+
this.userSort = userSort;
|
|
7061
|
+
this.memberFilters = memberFilters;
|
|
7062
|
+
this.memberSort = memberSort;
|
|
7063
|
+
this.searchOptions = searchOptions;
|
|
6701
7064
|
this.config = {
|
|
6702
7065
|
mentionAllAppUsers,
|
|
6703
7066
|
suggestionFactoryMappers,
|
|
@@ -6730,16 +7093,21 @@ var MentionsSearchSource = class extends BaseSearchSource {
|
|
|
6730
7093
|
offset: (this.offset ?? 0) + userPaginationState.itemCount
|
|
6731
7094
|
};
|
|
6732
7095
|
}
|
|
6733
|
-
async query(searchQuery) {
|
|
7096
|
+
async query(searchQuery, queryOptions = {}) {
|
|
6734
7097
|
const userOffset = this.offset ?? 0;
|
|
6735
7098
|
const isFirstPage = userOffset === 0 && typeof this.userGroupCursor === "undefined";
|
|
6736
7099
|
const previousUserPaginationState = this.latestUserPaginationState;
|
|
6737
7100
|
const previousUserGroupCursor = this.userGroupCursor;
|
|
6738
7101
|
const [userResultsState, userGroupResultsState, roleSuggestionsState] = await Promise.allSettled([
|
|
6739
|
-
this.getUserSuggestionsPage(searchQuery, userOffset),
|
|
6740
|
-
this.getUserGroupSuggestionsPage(
|
|
6741
|
-
|
|
7102
|
+
this.getUserSuggestionsPage(searchQuery, userOffset, queryOptions),
|
|
7103
|
+
this.getUserGroupSuggestionsPage(
|
|
7104
|
+
searchQuery,
|
|
7105
|
+
previousUserGroupCursor,
|
|
7106
|
+
queryOptions
|
|
7107
|
+
),
|
|
7108
|
+
isFirstPage ? this.getRoleMentionSuggestions(searchQuery, queryOptions) : Promise.resolve([])
|
|
6742
7109
|
]);
|
|
7110
|
+
if (queryOptions.signal?.aborted) return { items: [] };
|
|
6743
7111
|
const userResults = userResultsState.status === "fulfilled" ? userResultsState.value : {
|
|
6744
7112
|
items: [],
|
|
6745
7113
|
nextOffset: isFirstPage ? void 0 : previousUserPaginationState?.nextOffset
|
|
@@ -7014,7 +7382,7 @@ var DEFAULT_COMPOSER_CONFIG = {
|
|
|
7014
7382
|
};
|
|
7015
7383
|
|
|
7016
7384
|
// src/messageComposer/CustomDataManager.ts
|
|
7017
|
-
var
|
|
7385
|
+
var initState4 = (options) => {
|
|
7018
7386
|
if (!options)
|
|
7019
7387
|
return { message: {}, custom: {} };
|
|
7020
7388
|
return { message: {}, custom: {} };
|
|
@@ -7023,14 +7391,14 @@ var CustomDataManager = class {
|
|
|
7023
7391
|
constructor({ composer, message }) {
|
|
7024
7392
|
this.isMessageDataEqual = (nextState, previousState) => JSON.stringify(nextState.message) === JSON.stringify(previousState?.message);
|
|
7025
7393
|
this.initState = ({ message } = {}) => {
|
|
7026
|
-
this.state.next(
|
|
7394
|
+
this.state.next(initState4({ composer: this.composer, message }));
|
|
7027
7395
|
};
|
|
7028
7396
|
this.getSnapshot = () => this.state.getLatestValue();
|
|
7029
7397
|
this.restoreSnapshot = (snapshot) => {
|
|
7030
7398
|
this.state.next(snapshot);
|
|
7031
7399
|
};
|
|
7032
7400
|
this.composer = composer;
|
|
7033
|
-
this.state = new StateStore(
|
|
7401
|
+
this.state = new StateStore(initState4({ composer, message }));
|
|
7034
7402
|
}
|
|
7035
7403
|
get customMessageData() {
|
|
7036
7404
|
return this.state.getLatestValue().message;
|
|
@@ -7066,7 +7434,7 @@ var LinkPreviewStatus = /* @__PURE__ */ ((LinkPreviewStatus2) => {
|
|
|
7066
7434
|
return LinkPreviewStatus2;
|
|
7067
7435
|
})(LinkPreviewStatus || {});
|
|
7068
7436
|
var linkPreviewArrayToMap = (linkPreviews) => new Map(linkPreviews.map((linkPreview) => [linkPreview.og_scrape_url, linkPreview]));
|
|
7069
|
-
var
|
|
7437
|
+
var initState5 = ({
|
|
7070
7438
|
message
|
|
7071
7439
|
}) => message ? {
|
|
7072
7440
|
previews: message.attachments?.reduce((acc, attachment) => {
|
|
@@ -7085,7 +7453,7 @@ var _LinkPreviewsManager = class _LinkPreviewsManager {
|
|
|
7085
7453
|
this.shouldDiscardEnrichQueries = false;
|
|
7086
7454
|
this.initState = ({ message } = {}) => {
|
|
7087
7455
|
this.cancelURLEnrichment();
|
|
7088
|
-
this.state.next(
|
|
7456
|
+
this.state.next(initState5({ message: this.enabled ? message : void 0 }));
|
|
7089
7457
|
};
|
|
7090
7458
|
this.getSnapshot = () => this.state.getLatestValue();
|
|
7091
7459
|
this.restoreSnapshot = (snapshot) => {
|
|
@@ -7188,7 +7556,7 @@ var _LinkPreviewsManager = class _LinkPreviewsManager {
|
|
|
7188
7556
|
};
|
|
7189
7557
|
this.composer = composer;
|
|
7190
7558
|
this.state = new StateStore(
|
|
7191
|
-
|
|
7559
|
+
initState5({ message: this.enabled ? message : void 0 })
|
|
7192
7560
|
);
|
|
7193
7561
|
this.findAndEnrichUrls = debounce(
|
|
7194
7562
|
this._findAndEnrichUrls.bind(this),
|
|
@@ -7276,7 +7644,7 @@ var LinkPreviewsManager = _LinkPreviewsManager;
|
|
|
7276
7644
|
|
|
7277
7645
|
// src/messageComposer/LocationComposer.ts
|
|
7278
7646
|
var MIN_LIVE_LOCATION_SHARE_DURATION = 60 * 1e3;
|
|
7279
|
-
var
|
|
7647
|
+
var initState6 = ({
|
|
7280
7648
|
message
|
|
7281
7649
|
}) => ({
|
|
7282
7650
|
location: message?.shared_location ?? null
|
|
@@ -7284,7 +7652,7 @@ var initState5 = ({
|
|
|
7284
7652
|
var LocationComposer = class {
|
|
7285
7653
|
constructor({ composer, message }) {
|
|
7286
7654
|
this.initState = ({ message } = {}) => {
|
|
7287
|
-
this.state.next(
|
|
7655
|
+
this.state.next(initState6({ message }));
|
|
7288
7656
|
};
|
|
7289
7657
|
this.getSnapshot = () => this.state.getLatestValue();
|
|
7290
7658
|
this.restoreSnapshot = (snapshot) => {
|
|
@@ -7302,7 +7670,7 @@ var LocationComposer = class {
|
|
|
7302
7670
|
});
|
|
7303
7671
|
};
|
|
7304
7672
|
this.composer = composer;
|
|
7305
|
-
this.state = new StateStore(
|
|
7673
|
+
this.state = new StateStore(initState6({ message }));
|
|
7306
7674
|
this._deviceId = this.config.getDeviceId();
|
|
7307
7675
|
}
|
|
7308
7676
|
get config() {
|
|
@@ -8023,7 +8391,7 @@ var initEditingAuditState = (composition) => {
|
|
|
8023
8391
|
}
|
|
8024
8392
|
};
|
|
8025
8393
|
};
|
|
8026
|
-
var
|
|
8394
|
+
var initState7 = (composition) => {
|
|
8027
8395
|
if (!composition) {
|
|
8028
8396
|
return {
|
|
8029
8397
|
draftId: null,
|
|
@@ -8110,7 +8478,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8110
8478
|
this.textComposer.initState({ message });
|
|
8111
8479
|
this.pollComposer.initState();
|
|
8112
8480
|
this.customDataManager.initState({ message });
|
|
8113
|
-
this.state.next(
|
|
8481
|
+
this.state.next(initState7(composition));
|
|
8114
8482
|
};
|
|
8115
8483
|
this.initStateFromChannelResponse = (channelApiResponse) => {
|
|
8116
8484
|
if (this.channel.cid !== channelApiResponse.channel.cid) {
|
|
@@ -8576,7 +8944,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8576
8944
|
this.editingAuditState = new StateStore(
|
|
8577
8945
|
this.initEditingAuditState(composition)
|
|
8578
8946
|
);
|
|
8579
|
-
this.state = new StateStore(
|
|
8947
|
+
this.state = new StateStore(initState7(composition));
|
|
8580
8948
|
this.compositionMiddlewareExecutor = new MessageComposerMiddlewareExecutor({
|
|
8581
8949
|
composer: this
|
|
8582
8950
|
});
|
|
@@ -8655,8 +9023,32 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8655
9023
|
const currentCommand = this.textComposer.command;
|
|
8656
9024
|
return !currentCommand || this.validateCommandSendability(currentCommand).ready;
|
|
8657
9025
|
}
|
|
9026
|
+
/**
|
|
9027
|
+
* Whether the installed composition middleware composes messages whose uploads are still in
|
|
9028
|
+
* flight — see `MessageCompositionMiddleware.allowsPendingUploads`.
|
|
9029
|
+
*
|
|
9030
|
+
* Derived from the chain rather than from config, so there is exactly one switch: the UI SDK
|
|
9031
|
+
* that implements the rest of the flow installs the middleware, and everything that has to
|
|
9032
|
+
* follow from that (starting with {@link hasSendableData}) follows on its own.
|
|
9033
|
+
*
|
|
9034
|
+
* **Temporary API.** In v10 sending with pending uploads becomes part of the composer
|
|
9035
|
+
* configuration (`MessageComposerConfig`, set through `updateConfig`), and this getter,
|
|
9036
|
+
* together with the middleware declaration it reads, is replaced by that config field.
|
|
9037
|
+
*/
|
|
9038
|
+
get allowsPendingUploads() {
|
|
9039
|
+
return this.compositionMiddlewareExecutor.installedMiddleware.some(
|
|
9040
|
+
(middleware) => middleware.allowsPendingUploads
|
|
9041
|
+
);
|
|
9042
|
+
}
|
|
8658
9043
|
get hasSendableData() {
|
|
8659
|
-
|
|
9044
|
+
if (!this.isCommandSendable) return false;
|
|
9045
|
+
if (this.allowsPendingUploads) {
|
|
9046
|
+
const hasSendableAttachment = this.attachmentManager.attachments.some(
|
|
9047
|
+
(attachment) => isFinishedUpload(attachment) || isPendingUpload(attachment)
|
|
9048
|
+
);
|
|
9049
|
+
return !!(!this.textComposer.textIsEmpty || hasSendableAttachment || this.pollId || this.locationComposer.validLocation);
|
|
9050
|
+
}
|
|
9051
|
+
return !!(!this.attachmentManager.uploadsInProgressCount && (!this.textComposer.textIsEmpty || this.attachmentManager.successfulUploadsCount > 0) || this.pollId || !!this.locationComposer.validLocation);
|
|
8660
9052
|
}
|
|
8661
9053
|
get compositionIsEmpty() {
|
|
8662
9054
|
return !this.quotedMessage && this.contentIsEmpty;
|
|
@@ -9283,14 +9675,16 @@ var Channel = class {
|
|
|
9283
9675
|
*
|
|
9284
9676
|
* @return {Promise<SendMessageAPIResponse>} The Server Response
|
|
9285
9677
|
*/
|
|
9286
|
-
async _sendMessage(
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
|
|
9292
|
-
|
|
9293
|
-
|
|
9678
|
+
async _sendMessage(rawMessage, options) {
|
|
9679
|
+
const client = this.getClient();
|
|
9680
|
+
const message = sanitizeOutgoingAttachments({
|
|
9681
|
+
client,
|
|
9682
|
+
message: rawMessage
|
|
9683
|
+
});
|
|
9684
|
+
return await client.post(this._channelURL() + "/message", {
|
|
9685
|
+
message,
|
|
9686
|
+
...options
|
|
9687
|
+
});
|
|
9294
9688
|
}
|
|
9295
9689
|
async sendMessage(message, options) {
|
|
9296
9690
|
try {
|
|
@@ -9415,10 +9809,11 @@ var Channel = class {
|
|
|
9415
9809
|
* @param {MemberSort} [sort] Sort options, for instance [{created_at: -1}].
|
|
9416
9810
|
* When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{name: -1}, {created_at: 1}]
|
|
9417
9811
|
* @param {{ limit?: number; offset?: number }} [options] Option object, {limit: 10, offset:10}
|
|
9812
|
+
* @param {RequestOptions} [requestOptions] Carries an abort signal. Not sent in the request.
|
|
9418
9813
|
*
|
|
9419
9814
|
* @return {Promise<ChannelMemberAPIResponse>} Query Members response
|
|
9420
9815
|
*/
|
|
9421
|
-
async queryMembers(filterConditions, sort = [], options = {}) {
|
|
9816
|
+
async queryMembers(filterConditions, sort = [], options = {}, requestOptions = {}) {
|
|
9422
9817
|
let id;
|
|
9423
9818
|
const type = this.type;
|
|
9424
9819
|
let members;
|
|
@@ -9438,7 +9833,8 @@ var Channel = class {
|
|
|
9438
9833
|
filter_conditions: filterConditions,
|
|
9439
9834
|
...options
|
|
9440
9835
|
}
|
|
9441
|
-
}
|
|
9836
|
+
},
|
|
9837
|
+
requestOptions
|
|
9442
9838
|
);
|
|
9443
9839
|
}
|
|
9444
9840
|
/**
|
|
@@ -10739,6 +11135,7 @@ var Channel = class {
|
|
|
10739
11135
|
// delivery-report network sync below is skipped for it.
|
|
10740
11136
|
case "message.read_locally":
|
|
10741
11137
|
case "message.read":
|
|
11138
|
+
if (event.thread) break;
|
|
10742
11139
|
if (event.user?.id && event.created_at) {
|
|
10743
11140
|
const previousReadState = channelState.read[event.user.id];
|
|
10744
11141
|
channelState.read[event.user.id] = {
|
|
@@ -11188,7 +11585,7 @@ var ClientState = class {
|
|
|
11188
11585
|
var import_isomorphic_ws = __toESM(require("isomorphic-ws"));
|
|
11189
11586
|
|
|
11190
11587
|
// src/insights.ts
|
|
11191
|
-
var
|
|
11588
|
+
var import_axios2 = __toESM(require("axios"));
|
|
11192
11589
|
var InsightMetrics = class {
|
|
11193
11590
|
constructor() {
|
|
11194
11591
|
this.connectionStartTimestamp = null;
|
|
@@ -11201,7 +11598,7 @@ var postInsights = async (insightType, insights) => {
|
|
|
11201
11598
|
const maxAttempts = 3;
|
|
11202
11599
|
for (let i = 0; i < maxAttempts; i++) {
|
|
11203
11600
|
try {
|
|
11204
|
-
await
|
|
11601
|
+
await import_axios2.default.post(
|
|
11205
11602
|
`https://chat-insights.getstream.io/insights/${insightType}`,
|
|
11206
11603
|
insights
|
|
11207
11604
|
);
|
|
@@ -11709,131 +12106,6 @@ var StableWSConnection = class {
|
|
|
11709
12106
|
}
|
|
11710
12107
|
};
|
|
11711
12108
|
|
|
11712
|
-
// src/uploadManager.ts
|
|
11713
|
-
var initState7 = () => ({ uploads: {} });
|
|
11714
|
-
var upsertById = (uploads, record) => ({
|
|
11715
|
-
...uploads,
|
|
11716
|
-
[record.id]: { ...uploads[record.id], ...record }
|
|
11717
|
-
});
|
|
11718
|
-
var updateById = (uploads, record) => {
|
|
11719
|
-
if (!(record.id in uploads)) return null;
|
|
11720
|
-
const current = uploads[record.id];
|
|
11721
|
-
return { ...uploads, [record.id]: { ...current, ...record } };
|
|
11722
|
-
};
|
|
11723
|
-
var UploadManager = class {
|
|
11724
|
-
constructor(client) {
|
|
11725
|
-
this.client = client;
|
|
11726
|
-
this.inFlightUploads = /* @__PURE__ */ new Map();
|
|
11727
|
-
this.getUpload = (id) => this.uploads[id];
|
|
11728
|
-
/**
|
|
11729
|
-
* Clears all upload records.
|
|
11730
|
-
* Invoked when the user disconnects so a later session does not inherit stale upload state.
|
|
11731
|
-
* Aborts every in-flight upload request via its `UploadRequestOptions.abortSignal`.
|
|
11732
|
-
*/
|
|
11733
|
-
this.reset = () => {
|
|
11734
|
-
for (const { abortController } of this.inFlightUploads.values()) {
|
|
11735
|
-
abortController.abort();
|
|
11736
|
-
}
|
|
11737
|
-
this.inFlightUploads.clear();
|
|
11738
|
-
this.state.next(initState7());
|
|
11739
|
-
};
|
|
11740
|
-
/**
|
|
11741
|
-
* Removes the upload record for `id` if present.
|
|
11742
|
-
* If an upload is still in progress, aborts its `UploadRequestOptions.abortSignal`.
|
|
11743
|
-
*/
|
|
11744
|
-
this.deleteUploadRecord = (id) => {
|
|
11745
|
-
const flight = this.inFlightUploads.get(id);
|
|
11746
|
-
if (flight) {
|
|
11747
|
-
this.inFlightUploads.delete(id);
|
|
11748
|
-
flight.abortController.abort();
|
|
11749
|
-
}
|
|
11750
|
-
this.state.next((current) => {
|
|
11751
|
-
if (!(id in current.uploads)) return current;
|
|
11752
|
-
const uploads = { ...current.uploads };
|
|
11753
|
-
delete uploads[id];
|
|
11754
|
-
return { ...current, uploads };
|
|
11755
|
-
});
|
|
11756
|
-
};
|
|
11757
|
-
/**
|
|
11758
|
-
* Starts an upload for `id`, or returns the existing in-flight promise if one is already running.
|
|
11759
|
-
* Uses {@link StreamChat.channel}(`channelCid`) → `messageComposer.attachmentManager.doUploadRequest`.
|
|
11760
|
-
* Resolves with that result; rejects if the upload rejects (the record is removed from state either way).
|
|
11761
|
-
*/
|
|
11762
|
-
this.upload = ({
|
|
11763
|
-
id,
|
|
11764
|
-
channelCid,
|
|
11765
|
-
file
|
|
11766
|
-
}) => {
|
|
11767
|
-
const existing = this.inFlightUploads.get(id);
|
|
11768
|
-
if (existing) return existing.promise;
|
|
11769
|
-
let resolvePromise;
|
|
11770
|
-
let rejectPromise;
|
|
11771
|
-
const promise = new Promise((resolve, reject) => {
|
|
11772
|
-
resolvePromise = resolve;
|
|
11773
|
-
rejectPromise = reject;
|
|
11774
|
-
});
|
|
11775
|
-
const abortController = new AbortController();
|
|
11776
|
-
this.inFlightUploads.set(id, { promise, abortController });
|
|
11777
|
-
void (async () => {
|
|
11778
|
-
const attachmentManager = this.resolveAttachmentManager(channelCid);
|
|
11779
|
-
const trackProgress = attachmentManager.config.trackUploadProgress;
|
|
11780
|
-
try {
|
|
11781
|
-
this.upsertUpload({
|
|
11782
|
-
id,
|
|
11783
|
-
uploadProgress: trackProgress ? 0 : void 0
|
|
11784
|
-
});
|
|
11785
|
-
const onProgress = trackProgress ? (progress) => {
|
|
11786
|
-
this.updateUpload({
|
|
11787
|
-
id,
|
|
11788
|
-
uploadProgress: progress
|
|
11789
|
-
});
|
|
11790
|
-
} : void 0;
|
|
11791
|
-
const uploadRequestOptions = {
|
|
11792
|
-
abortSignal: abortController.signal,
|
|
11793
|
-
...onProgress ? { onProgress } : {}
|
|
11794
|
-
};
|
|
11795
|
-
const response = await attachmentManager.doUploadRequest(
|
|
11796
|
-
file,
|
|
11797
|
-
uploadRequestOptions
|
|
11798
|
-
);
|
|
11799
|
-
resolvePromise(response);
|
|
11800
|
-
} catch (error) {
|
|
11801
|
-
rejectPromise(error);
|
|
11802
|
-
} finally {
|
|
11803
|
-
this.inFlightUploads.delete(id);
|
|
11804
|
-
this.deleteUploadRecord(id);
|
|
11805
|
-
}
|
|
11806
|
-
})();
|
|
11807
|
-
return promise;
|
|
11808
|
-
};
|
|
11809
|
-
this.upsertUpload = (record) => {
|
|
11810
|
-
this.state.partialNext({
|
|
11811
|
-
uploads: upsertById(this.uploads, record)
|
|
11812
|
-
});
|
|
11813
|
-
};
|
|
11814
|
-
this.updateUpload = (record) => {
|
|
11815
|
-
this.state.next((current) => {
|
|
11816
|
-
const nextUploads = updateById(current.uploads, record);
|
|
11817
|
-
if (!nextUploads) return current;
|
|
11818
|
-
return { ...current, uploads: nextUploads };
|
|
11819
|
-
});
|
|
11820
|
-
};
|
|
11821
|
-
this.state = new StateStore(initState7());
|
|
11822
|
-
}
|
|
11823
|
-
resolveAttachmentManager(channelCid) {
|
|
11824
|
-
const colon = channelCid.indexOf(":");
|
|
11825
|
-
if (colon <= 0 || colon === channelCid.length - 1) {
|
|
11826
|
-
throw new Error(`Invalid channelCid: ${channelCid}`);
|
|
11827
|
-
}
|
|
11828
|
-
const channelType = channelCid.slice(0, colon);
|
|
11829
|
-
const channelId = channelCid.slice(colon + 1);
|
|
11830
|
-
return this.client.channel(channelType, channelId).messageComposer.attachmentManager;
|
|
11831
|
-
}
|
|
11832
|
-
get uploads() {
|
|
11833
|
-
return this.state.getLatestValue().uploads;
|
|
11834
|
-
}
|
|
11835
|
-
};
|
|
11836
|
-
|
|
11837
12109
|
// src/signing.ts
|
|
11838
12110
|
var import_jsonwebtoken = __toESM(require_jsonwebtoken());
|
|
11839
12111
|
var import_crypto = __toESM(require_crypto());
|
|
@@ -12092,7 +12364,7 @@ var TokenManager = class {
|
|
|
12092
12364
|
};
|
|
12093
12365
|
|
|
12094
12366
|
// src/connection_fallback.ts
|
|
12095
|
-
var
|
|
12367
|
+
var import_axios3 = __toESM(require("axios"));
|
|
12096
12368
|
var WSConnectionFallback = class {
|
|
12097
12369
|
constructor({ client }) {
|
|
12098
12370
|
/** @private */
|
|
@@ -12111,7 +12383,7 @@ var WSConnectionFallback = class {
|
|
|
12111
12383
|
/** @private */
|
|
12112
12384
|
this._req = async (params, config, retry) => {
|
|
12113
12385
|
if (!this.cancelToken && !params.close) {
|
|
12114
|
-
this.cancelToken =
|
|
12386
|
+
this.cancelToken = import_axios3.default.CancelToken.source();
|
|
12115
12387
|
}
|
|
12116
12388
|
try {
|
|
12117
12389
|
const res = await this.client.doAxiosRequest(
|
|
@@ -12147,7 +12419,7 @@ var WSConnectionFallback = class {
|
|
|
12147
12419
|
}
|
|
12148
12420
|
}
|
|
12149
12421
|
} catch (error) {
|
|
12150
|
-
if (
|
|
12422
|
+
if (import_axios3.default.isCancel(error)) {
|
|
12151
12423
|
this._log(`_poll() - axios canceled request`);
|
|
12152
12424
|
return;
|
|
12153
12425
|
}
|
|
@@ -14570,6 +14842,7 @@ var StreamChat = class _StreamChat {
|
|
|
14570
14842
|
return this.handleResponse(response);
|
|
14571
14843
|
} catch (e) {
|
|
14572
14844
|
e.client_request_id = requestConfig.headers?.["x-client-request-id"];
|
|
14845
|
+
if (import_axios4.default.isCancel(e)) throw e;
|
|
14573
14846
|
this._logApiError(type, url, e);
|
|
14574
14847
|
this.consecutiveFailures += 1;
|
|
14575
14848
|
if (e.response) {
|
|
@@ -14881,7 +15154,7 @@ var StreamChat = class _StreamChat {
|
|
|
14881
15154
|
return this.userAgent;
|
|
14882
15155
|
}
|
|
14883
15156
|
if (!this.cachedUserAgent) {
|
|
14884
|
-
const version = "9.
|
|
15157
|
+
const version = "9.52.0";
|
|
14885
15158
|
const { name: sdkName, version: sdkVersion } = this.sdkIdentifier ?? {};
|
|
14886
15159
|
const { name: appName, version: appVersion } = this.appIdentifier ?? {};
|
|
14887
15160
|
const { os, model: deviceModel } = this.deviceIdentifier ?? {};
|
|
@@ -14949,7 +15222,7 @@ var StreamChat = class _StreamChat {
|
|
|
14949
15222
|
keepAliveMsecs: 3e3
|
|
14950
15223
|
});
|
|
14951
15224
|
}
|
|
14952
|
-
this.axiosInstance =
|
|
15225
|
+
this.axiosInstance = import_axios4.default.create(this.options);
|
|
14953
15226
|
this.setBaseURL(this.options.baseURL || "https://chat.stream-io-api.com");
|
|
14954
15227
|
if (typeof process !== "undefined" && "env" in process && process.env.STREAM_LOCAL_TEST_RUN) {
|
|
14955
15228
|
this.setBaseURL("http://localhost:3030");
|
|
@@ -15257,14 +15530,14 @@ var StreamChat = class _StreamChat {
|
|
|
15257
15530
|
error
|
|
15258
15531
|
});
|
|
15259
15532
|
}
|
|
15260
|
-
get(url, params) {
|
|
15261
|
-
return this.doAxiosRequest("get", url, null, { params });
|
|
15533
|
+
get(url, params, config) {
|
|
15534
|
+
return this.doAxiosRequest("get", url, null, { params, config });
|
|
15262
15535
|
}
|
|
15263
15536
|
put(url, data) {
|
|
15264
15537
|
return this.doAxiosRequest("put", url, data);
|
|
15265
15538
|
}
|
|
15266
|
-
post(url, data) {
|
|
15267
|
-
return this.doAxiosRequest("post", url, data);
|
|
15539
|
+
post(url, data, config) {
|
|
15540
|
+
return this.doAxiosRequest("post", url, data, { config });
|
|
15268
15541
|
}
|
|
15269
15542
|
patch(url, data) {
|
|
15270
15543
|
return this.doAxiosRequest("patch", url, data);
|
|
@@ -15459,10 +15732,11 @@ var StreamChat = class _StreamChat {
|
|
|
15459
15732
|
* @param {UserSort} sort Sort options, for instance [{last_active: -1}].
|
|
15460
15733
|
* When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_active: -1}, {created_at: 1}]
|
|
15461
15734
|
* @param {UserOptions} options Option object, {presence: true}
|
|
15735
|
+
* @param {RequestOptions} [requestOptions] Carries an abort signal. Not sent in the request.
|
|
15462
15736
|
*
|
|
15463
15737
|
* @return {Promise<{ users: Array<UserResponse> }>} User Query Response
|
|
15464
15738
|
*/
|
|
15465
|
-
async queryUsers(filterConditions, sort = [], options = {}) {
|
|
15739
|
+
async queryUsers(filterConditions, sort = [], options = {}, requestOptions = {}) {
|
|
15466
15740
|
const defaultOptions = {
|
|
15467
15741
|
presence: false
|
|
15468
15742
|
};
|
|
@@ -15479,7 +15753,8 @@ var StreamChat = class _StreamChat {
|
|
|
15479
15753
|
...defaultOptions,
|
|
15480
15754
|
...options
|
|
15481
15755
|
}
|
|
15482
|
-
}
|
|
15756
|
+
},
|
|
15757
|
+
requestOptions
|
|
15483
15758
|
);
|
|
15484
15759
|
this.state.updateUsers(data.users);
|
|
15485
15760
|
return data;
|
|
@@ -15525,13 +15800,14 @@ var StreamChat = class _StreamChat {
|
|
|
15525
15800
|
* searchUserGroups - Search user groups by prefix for autocomplete
|
|
15526
15801
|
*
|
|
15527
15802
|
* @param {SearchUserGroupsOptions} options The search options
|
|
15528
|
-
*
|
|
15803
|
+
* @param {RequestOptions} [requestOptions] Carries an abort signal. Not sent in the request.
|
|
15529
15804
|
* @return {Promise<SearchUserGroupsResponse>} User Group Search Response
|
|
15530
15805
|
*/
|
|
15531
|
-
async searchUserGroups(options) {
|
|
15806
|
+
async searchUserGroups(options, requestOptions = {}) {
|
|
15532
15807
|
return await this.get(
|
|
15533
15808
|
this.baseURL + "/usergroups/search",
|
|
15534
|
-
options
|
|
15809
|
+
options,
|
|
15810
|
+
requestOptions
|
|
15535
15811
|
);
|
|
15536
15812
|
}
|
|
15537
15813
|
/**
|
|
@@ -15651,10 +15927,11 @@ var StreamChat = class _StreamChat {
|
|
|
15651
15927
|
* @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.
|
|
15652
15928
|
* When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_updated: -1}, {created_at: 1}]
|
|
15653
15929
|
* @param {ChannelOptions} [options] Options object. Can include predefined_filter, filter_values, and sort_values for using predefined filters.
|
|
15930
|
+
* @param {RequestOptions} [requestOptions] Carries an abort signal. Not sent in the request.
|
|
15654
15931
|
*
|
|
15655
15932
|
* @return {Promise<QueryChannelsAPIResponse>} full search channels response
|
|
15656
15933
|
*/
|
|
15657
|
-
async queryChannelsRequestWithResponse(filterConditions, sort = [], options = {}) {
|
|
15934
|
+
async queryChannelsRequestWithResponse(filterConditions, sort = [], options = {}, requestOptions = {}) {
|
|
15658
15935
|
const defaultOptions = {
|
|
15659
15936
|
state: true,
|
|
15660
15937
|
watch: true,
|
|
@@ -15679,7 +15956,11 @@ var StreamChat = class _StreamChat {
|
|
|
15679
15956
|
...defaultOptions,
|
|
15680
15957
|
...restOptions
|
|
15681
15958
|
};
|
|
15682
|
-
return await this.post(
|
|
15959
|
+
return await this.post(
|
|
15960
|
+
this.baseURL + "/channels",
|
|
15961
|
+
payload,
|
|
15962
|
+
requestOptions
|
|
15963
|
+
);
|
|
15683
15964
|
}
|
|
15684
15965
|
/**
|
|
15685
15966
|
* queryChannelsRequest - Queries channels and returns the raw channel response list.
|
|
@@ -15708,7 +15989,9 @@ var StreamChat = class _StreamChat {
|
|
|
15708
15989
|
const queryChannelsResponse = await this.queryChannelsRequestWithResponse(
|
|
15709
15990
|
filterConditions,
|
|
15710
15991
|
sort,
|
|
15711
|
-
options
|
|
15992
|
+
options,
|
|
15993
|
+
// stateOptions is never serialized, so it carries the abort signal
|
|
15994
|
+
{ signal: stateOptions.signal }
|
|
15712
15995
|
);
|
|
15713
15996
|
const channels = queryChannelsResponse.channels;
|
|
15714
15997
|
this.dispatchEvent({
|
|
@@ -15825,10 +16108,11 @@ var StreamChat = class _StreamChat {
|
|
|
15825
16108
|
* @param {ChannelFilters} filterConditions MongoDB style filter conditions
|
|
15826
16109
|
* @param {MessageFilters | string} query search query or object MongoDB style filters
|
|
15827
16110
|
* @param {SearchOptions} [options] Option object, {user_id: 'tommaso'}
|
|
16111
|
+
* @param {RequestOptions} [requestOptions] Carries an abort signal. Not sent in the request.
|
|
15828
16112
|
*
|
|
15829
16113
|
* @return {Promise<SearchAPIResponse>} search messages response
|
|
15830
16114
|
*/
|
|
15831
|
-
async search(filterConditions, query, options = {}) {
|
|
16115
|
+
async search(filterConditions, query, options = {}, requestOptions = {}) {
|
|
15832
16116
|
if (options.offset && options.next) {
|
|
15833
16117
|
throw Error(`Cannot specify offset with next`);
|
|
15834
16118
|
}
|
|
@@ -15845,7 +16129,11 @@ var StreamChat = class _StreamChat {
|
|
|
15845
16129
|
throw Error(`Invalid type ${typeof query} for query parameter`);
|
|
15846
16130
|
}
|
|
15847
16131
|
await this.wsPromise;
|
|
15848
|
-
return await this.get(
|
|
16132
|
+
return await this.get(
|
|
16133
|
+
this.baseURL + "/search",
|
|
16134
|
+
{ payload },
|
|
16135
|
+
requestOptions
|
|
16136
|
+
);
|
|
15849
16137
|
}
|
|
15850
16138
|
/**
|
|
15851
16139
|
* setLocalDevice - Set the device info for the current client(device) that will be sent via WS connection automatically
|
|
@@ -16286,6 +16574,11 @@ var StreamChat = class _StreamChat {
|
|
|
16286
16574
|
}
|
|
16287
16575
|
/**
|
|
16288
16576
|
* unflagMessage - unflag a message
|
|
16577
|
+
*
|
|
16578
|
+
* @deprecated The `/moderation/unflag` endpoint is deprecated and is a no-op on
|
|
16579
|
+
* the backend - calling this resolves successfully but does not remove the flag.
|
|
16580
|
+
* Use `client.moderation.submitAction()` against the review queue item instead.
|
|
16581
|
+
*
|
|
16289
16582
|
* @param {string} targetMessageID
|
|
16290
16583
|
* @param {string} [options.user_id] currentUserID, only used with serverside auth
|
|
16291
16584
|
* @returns {Promise<APIResponse>}
|
|
@@ -16298,6 +16591,11 @@ var StreamChat = class _StreamChat {
|
|
|
16298
16591
|
}
|
|
16299
16592
|
/**
|
|
16300
16593
|
* unflagUser - unflag a user
|
|
16594
|
+
*
|
|
16595
|
+
* @deprecated The `/moderation/unflag` endpoint is deprecated and is a no-op on
|
|
16596
|
+
* the backend - calling this resolves successfully but does not remove the flag.
|
|
16597
|
+
* Use `client.moderation.submitAction()` against the review queue item instead.
|
|
16598
|
+
*
|
|
16301
16599
|
* @param {string} targetID
|
|
16302
16600
|
* @param {string} [options.user_id] currentUserID, only used with serverside auth
|
|
16303
16601
|
* @returns {Promise<APIResponse>}
|
|
@@ -16582,7 +16880,10 @@ var StreamChat = class _StreamChat {
|
|
|
16582
16880
|
if (!message.id) {
|
|
16583
16881
|
throw Error("Please specify the message.id when calling updateMessage");
|
|
16584
16882
|
}
|
|
16585
|
-
const payload =
|
|
16883
|
+
const payload = sanitizeOutgoingAttachments({
|
|
16884
|
+
client: this,
|
|
16885
|
+
message: toUpdatedMessagePayload(message)
|
|
16886
|
+
});
|
|
16586
16887
|
if (typeof partialUserOrUserId === "string") {
|
|
16587
16888
|
payload.user_id = partialUserOrUserId;
|
|
16588
16889
|
} else if (typeof partialUserOrUserId?.id === "string") {
|
|
@@ -16882,6 +17183,7 @@ var StreamChat = class _StreamChat {
|
|
|
16882
17183
|
headers: axiosRequestConfigHeaders,
|
|
16883
17184
|
...axiosRequestConfigRest
|
|
16884
17185
|
} = this.options.axiosRequestConfig || {};
|
|
17186
|
+
const resolvedSignal = options.config?.signal ?? axiosRequestConfigRest.signal ?? signal;
|
|
16885
17187
|
return {
|
|
16886
17188
|
params: {
|
|
16887
17189
|
user_id: this.userID,
|
|
@@ -16897,9 +17199,9 @@ var StreamChat = class _StreamChat {
|
|
|
16897
17199
|
...options.headers,
|
|
16898
17200
|
...axiosRequestConfigHeaders || {}
|
|
16899
17201
|
},
|
|
16900
|
-
...signal ? { signal } : {},
|
|
16901
17202
|
...options.config,
|
|
16902
|
-
...axiosRequestConfigRest
|
|
17203
|
+
...axiosRequestConfigRest,
|
|
17204
|
+
...resolvedSignal ? { signal: resolvedSignal } : {}
|
|
16903
17205
|
};
|
|
16904
17206
|
}
|
|
16905
17207
|
_getToken() {
|
|
@@ -17039,8 +17341,12 @@ var StreamChat = class _StreamChat {
|
|
|
17039
17341
|
*
|
|
17040
17342
|
* @returns {Promise<APIResponse>}
|
|
17041
17343
|
*/
|
|
17042
|
-
searchRoles(options) {
|
|
17043
|
-
return this.get(
|
|
17344
|
+
searchRoles(options, requestOptions = {}) {
|
|
17345
|
+
return this.get(
|
|
17346
|
+
`${this.baseURL}/roles/search`,
|
|
17347
|
+
options,
|
|
17348
|
+
requestOptions
|
|
17349
|
+
);
|
|
17044
17350
|
}
|
|
17045
17351
|
/** deleteRole - deletes a custom role
|
|
17046
17352
|
*
|
|
@@ -18393,11 +18699,12 @@ var OfflineError = class extends Error {
|
|
|
18393
18699
|
};
|
|
18394
18700
|
|
|
18395
18701
|
// src/offline-support/offline_sync_manager.ts
|
|
18396
|
-
var
|
|
18702
|
+
var import_axios5 = require("axios");
|
|
18397
18703
|
var OfflineDBSyncManager = class {
|
|
18398
18704
|
constructor({
|
|
18399
18705
|
client,
|
|
18400
|
-
offlineDb
|
|
18706
|
+
offlineDb,
|
|
18707
|
+
syncMaxEventCount
|
|
18401
18708
|
}) {
|
|
18402
18709
|
this.syncStatus = false;
|
|
18403
18710
|
this.connectionChangedListener = null;
|
|
@@ -18514,13 +18821,23 @@ var OfflineDBSyncManager = class {
|
|
|
18514
18821
|
await this.offlineDb.resetDB();
|
|
18515
18822
|
} else {
|
|
18516
18823
|
const result = await this.client.sync(cids, lastSyncedAtDate.toISOString());
|
|
18517
|
-
const
|
|
18518
|
-
|
|
18519
|
-
)
|
|
18520
|
-
|
|
18521
|
-
|
|
18522
|
-
|
|
18523
|
-
|
|
18824
|
+
const { syncMaxEventCount } = this;
|
|
18825
|
+
const exceedsLimit = typeof syncMaxEventCount === "number" && syncMaxEventCount > 0 && result.events.length > syncMaxEventCount;
|
|
18826
|
+
if (exceedsLimit) {
|
|
18827
|
+
this.client.logger(
|
|
18828
|
+
"warn",
|
|
18829
|
+
`Skipping sync event replay: received ${result.events.length} events, which exceeds the configured limit of ${syncMaxEventCount}. Visible channels are refreshed on reconnect instead.`,
|
|
18830
|
+
{ tags: ["sync", "offline"] }
|
|
18831
|
+
);
|
|
18832
|
+
} else {
|
|
18833
|
+
const queryPromises = result.events.map(
|
|
18834
|
+
(event) => this.offlineDb.handleEvent({ event, execute: false })
|
|
18835
|
+
);
|
|
18836
|
+
const queriesArray = await Promise.all(queryPromises);
|
|
18837
|
+
const queries = queriesArray.flat();
|
|
18838
|
+
if (queries.length) {
|
|
18839
|
+
await this.offlineDb.executeSqlBatch(queries);
|
|
18840
|
+
}
|
|
18524
18841
|
}
|
|
18525
18842
|
}
|
|
18526
18843
|
}
|
|
@@ -18530,7 +18847,7 @@ var OfflineDBSyncManager = class {
|
|
|
18530
18847
|
});
|
|
18531
18848
|
} catch (e) {
|
|
18532
18849
|
console.log("An error has occurred while syncing the DB.", e);
|
|
18533
|
-
if ((0,
|
|
18850
|
+
if ((0, import_axios5.isAxiosError)(e) && e.code === "ECONNABORTED") {
|
|
18534
18851
|
return;
|
|
18535
18852
|
}
|
|
18536
18853
|
const error = e;
|
|
@@ -18564,12 +18881,16 @@ var OfflineDBSyncManager = class {
|
|
|
18564
18881
|
};
|
|
18565
18882
|
this.client = client;
|
|
18566
18883
|
this.offlineDb = offlineDb;
|
|
18884
|
+
this.syncMaxEventCount = syncMaxEventCount;
|
|
18567
18885
|
}
|
|
18568
18886
|
};
|
|
18569
18887
|
|
|
18570
18888
|
// src/offline-support/offline_support_api.ts
|
|
18571
18889
|
var AbstractOfflineDB = class {
|
|
18572
|
-
constructor({
|
|
18890
|
+
constructor({
|
|
18891
|
+
client,
|
|
18892
|
+
syncMaxEventCount
|
|
18893
|
+
}) {
|
|
18573
18894
|
/**
|
|
18574
18895
|
* Initializes the DB as well as its syncManager for a given userId.
|
|
18575
18896
|
* It will update the DBs reactive state with initialization values.
|
|
@@ -19035,6 +19356,7 @@ var AbstractOfflineDB = class {
|
|
|
19035
19356
|
return this.handleMessageUpdatedEvent({ event, execute });
|
|
19036
19357
|
}
|
|
19037
19358
|
if (type === "message.read" || type === "notification.mark_read") {
|
|
19359
|
+
if (event.thread) return [];
|
|
19038
19360
|
return this.handleRead({ event, unreadMessages: 0, execute });
|
|
19039
19361
|
}
|
|
19040
19362
|
if (type === "message.read_locally") {
|
|
@@ -19259,7 +19581,11 @@ var AbstractOfflineDB = class {
|
|
|
19259
19581
|
}
|
|
19260
19582
|
};
|
|
19261
19583
|
this.client = client;
|
|
19262
|
-
this.syncManager = new OfflineDBSyncManager({
|
|
19584
|
+
this.syncManager = new OfflineDBSyncManager({
|
|
19585
|
+
client,
|
|
19586
|
+
offlineDb: this,
|
|
19587
|
+
syncMaxEventCount
|
|
19588
|
+
});
|
|
19263
19589
|
this.state = new StateStore({
|
|
19264
19590
|
initialized: false,
|
|
19265
19591
|
userId: this.client.userID
|