stream-chat 9.51.0 → 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 +382 -187
- package/dist/cjs/index.browser.js.map +4 -4
- package/dist/cjs/index.node.js +391 -188
- package/dist/cjs/index.node.js.map +4 -4
- package/dist/esm/index.mjs +380 -185
- package/dist/esm/index.mjs.map +4 -4
- package/dist/types/channel.d.ts +1 -1
- package/dist/types/client.d.ts +10 -0
- 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/types.d.ts +5 -0
- package/dist/types/middleware.d.ts +8 -0
- package/dist/types/uploadManager.d.ts +30 -0
- package/dist/types/utils.d.ts +20 -1
- package/package.json +1 -1
- package/src/channel.ts +16 -8
- package/src/client.ts +17 -1
- 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/types.ts +5 -0
- package/src/middleware.ts +11 -0
- package/src/offline-support/offline_support_api.ts +4 -0
- package/src/uploadManager.ts +45 -0
- package/src/utils.ts +72 -0
|
@@ -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.
|
|
@@ -2562,6 +2602,12 @@ var CooldownTimer = class extends WithSubscriptions {
|
|
|
2562
2602
|
var isScrapedContent = (attachment) => !!attachment?.og_scrape_url || !!attachment?.title_link;
|
|
2563
2603
|
var isLocalAttachment = (attachment) => !!attachment?.localMetadata?.id;
|
|
2564
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";
|
|
2565
2611
|
var isFileAttachment = (attachment, supportedVideoFormat = []) => attachment.type === "file" || !!(attachment.mime_type && supportedVideoFormat.indexOf(attachment.mime_type) === -1 && attachment.type !== "video");
|
|
2566
2612
|
var isLocalFileAttachment = (attachment) => isFileAttachment(attachment) && isLocalAttachment(attachment);
|
|
2567
2613
|
var isImageAttachment = (attachment) => attachment.type === "image" && !isScrapedContent(attachment);
|
|
@@ -2637,7 +2683,7 @@ var ensureIsLocalAttachment = (attachment) => {
|
|
|
2637
2683
|
};
|
|
2638
2684
|
|
|
2639
2685
|
// src/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.ts
|
|
2640
|
-
var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
2686
|
+
var createPostUploadAttachmentEnrichmentMiddleware = (composer) => ({
|
|
2641
2687
|
id: "stream-io/attachment-manager-middleware/post-upload-enrichment",
|
|
2642
2688
|
handlers: {
|
|
2643
2689
|
postProcess: ({
|
|
@@ -2650,9 +2696,10 @@ var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
|
2650
2696
|
if (error) return forward();
|
|
2651
2697
|
if (!attachment || !response) return discard();
|
|
2652
2698
|
const enrichedAttachment = { ...attachment };
|
|
2653
|
-
const previewUri = attachment.localMetadata
|
|
2654
|
-
|
|
2655
|
-
|
|
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);
|
|
2656
2703
|
delete enrichedAttachment.localMetadata.previewUri;
|
|
2657
2704
|
}
|
|
2658
2705
|
if (isLocalImageAttachment(attachment)) {
|
|
@@ -2675,6 +2722,12 @@ var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
|
2675
2722
|
var withoutConcurrency = createRunner(wrapWithContinuationTracking);
|
|
2676
2723
|
var withCancellation = createRunner(wrapWithCancellation);
|
|
2677
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
|
+
}
|
|
2678
2731
|
function createRunner(wrapper) {
|
|
2679
2732
|
return function run(tag, cb) {
|
|
2680
2733
|
const { cb: wrapped, onContinued } = wrapper(tag, cb);
|
|
@@ -2717,6 +2770,16 @@ var MiddlewareExecutor = class {
|
|
|
2717
2770
|
this.middleware = [];
|
|
2718
2771
|
this.id = generateUUIDv4();
|
|
2719
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
|
+
}
|
|
2720
2783
|
use(middleware) {
|
|
2721
2784
|
this.middleware = this.middleware.concat(middleware);
|
|
2722
2785
|
return this;
|
|
@@ -2820,6 +2883,142 @@ var MiddlewareExecutor = class {
|
|
|
2820
2883
|
}
|
|
2821
2884
|
};
|
|
2822
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
|
+
|
|
2823
3022
|
// src/messageComposer/middleware/attachmentManager/postUpload/uploadErrorHandler.ts
|
|
2824
3023
|
var createUploadErrorHandlerMiddleware = (composer) => ({
|
|
2825
3024
|
id: "stream-io/attachment-manager-middleware/upload-error",
|
|
@@ -2832,6 +3031,7 @@ var createUploadErrorHandlerMiddleware = (composer) => ({
|
|
|
2832
3031
|
const { attachment, error } = state;
|
|
2833
3032
|
if (!error) return forward();
|
|
2834
3033
|
if (!attachment) return discard();
|
|
3034
|
+
if (isUploadCancellation(error)) return forward();
|
|
2835
3035
|
const reason = error instanceof Error ? error.message : "unknown error";
|
|
2836
3036
|
composer.client.notifications.addError({
|
|
2837
3037
|
message: "Error uploading attachment",
|
|
@@ -2856,7 +3056,7 @@ var AttachmentPostUploadMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
|
2856
3056
|
super();
|
|
2857
3057
|
this.use([
|
|
2858
3058
|
createUploadErrorHandlerMiddleware(composer),
|
|
2859
|
-
createPostUploadAttachmentEnrichmentMiddleware()
|
|
3059
|
+
createPostUploadAttachmentEnrichmentMiddleware(composer)
|
|
2860
3060
|
]);
|
|
2861
3061
|
}
|
|
2862
3062
|
};
|
|
@@ -3304,7 +3504,7 @@ function mergeWithDiff(target, source, customizer) {
|
|
|
3304
3504
|
}
|
|
3305
3505
|
|
|
3306
3506
|
// src/messageComposer/attachmentManager.ts
|
|
3307
|
-
var
|
|
3507
|
+
var initState2 = ({
|
|
3308
3508
|
message
|
|
3309
3509
|
}) => ({
|
|
3310
3510
|
attachments: (message?.attachments ?? [])?.filter(({ og_scrape_url }) => !og_scrape_url).map((att) => {
|
|
@@ -3332,13 +3532,14 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3332
3532
|
...attachment,
|
|
3333
3533
|
localMetadata: {
|
|
3334
3534
|
...attachment.localMetadata,
|
|
3535
|
+
uploadConfirmationPending: false,
|
|
3335
3536
|
uploadProgress: void 0,
|
|
3336
3537
|
uploadState: "failed"
|
|
3337
3538
|
}
|
|
3338
3539
|
};
|
|
3339
3540
|
};
|
|
3340
3541
|
this.initState = ({ message } = {}) => {
|
|
3341
|
-
this.state.next(
|
|
3542
|
+
this.state.next(initState2({ message }));
|
|
3342
3543
|
};
|
|
3343
3544
|
this.getSnapshot = () => {
|
|
3344
3545
|
const state = this.state.getLatestValue();
|
|
@@ -3415,8 +3616,22 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3415
3616
|
this.state.partialNext({ attachments });
|
|
3416
3617
|
}
|
|
3417
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
|
+
};
|
|
3418
3630
|
this.removeAttachments = (localAttachmentIds) => {
|
|
3419
3631
|
if (!localAttachmentIds.length) return;
|
|
3632
|
+
const removedAttachments = this.attachments.filter(
|
|
3633
|
+
(attachment) => localAttachmentIds.includes(attachment.localMetadata?.id)
|
|
3634
|
+
);
|
|
3420
3635
|
this.state.partialNext({
|
|
3421
3636
|
attachments: this.attachments.filter(
|
|
3422
3637
|
(attachment) => !localAttachmentIds.includes(attachment.localMetadata?.id)
|
|
@@ -3425,6 +3640,7 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3425
3640
|
for (const id of localAttachmentIds) {
|
|
3426
3641
|
this.client.uploadManager.deleteUploadRecord(id);
|
|
3427
3642
|
}
|
|
3643
|
+
removedAttachments.forEach(this.revokePreviewUri);
|
|
3428
3644
|
};
|
|
3429
3645
|
this.getUploadConfigCheck = async (fileLike) => {
|
|
3430
3646
|
const client = this.channel.getClient();
|
|
@@ -3576,21 +3792,27 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3576
3792
|
localMetadata: {
|
|
3577
3793
|
...attachment.localMetadata,
|
|
3578
3794
|
uploadState: "failed",
|
|
3579
|
-
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
|
|
3580
3800
|
}
|
|
3581
3801
|
};
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
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
|
+
}
|
|
3594
3816
|
this.updateAttachment(failedAttachment);
|
|
3595
3817
|
return failedAttachment;
|
|
3596
3818
|
}
|
|
@@ -3603,7 +3825,9 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3603
3825
|
localMetadata: {
|
|
3604
3826
|
...attachment.localMetadata,
|
|
3605
3827
|
uploadState: "finished",
|
|
3606
|
-
uploadProgress: void 0
|
|
3828
|
+
uploadProgress: void 0,
|
|
3829
|
+
// See the note in the failure branch: `undefined` cannot clear through `mergeWith`.
|
|
3830
|
+
uploadConfirmationPending: false
|
|
3607
3831
|
}
|
|
3608
3832
|
};
|
|
3609
3833
|
const previewUri = uploadedAttachment.localMetadata.previewUri;
|
|
@@ -3652,7 +3876,9 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3652
3876
|
localMetadata: {
|
|
3653
3877
|
...attachment.localMetadata,
|
|
3654
3878
|
uploadState: error ? "failed" : "finished",
|
|
3655
|
-
uploadProgress: void 0
|
|
3879
|
+
uploadProgress: void 0,
|
|
3880
|
+
// See the note in `uploadAttachment`: `undefined` cannot clear through `mergeWith`.
|
|
3881
|
+
uploadConfirmationPending: false
|
|
3656
3882
|
}
|
|
3657
3883
|
},
|
|
3658
3884
|
error,
|
|
@@ -3677,7 +3903,7 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3677
3903
|
);
|
|
3678
3904
|
};
|
|
3679
3905
|
this.composer = composer;
|
|
3680
|
-
this.state = new StateStore(
|
|
3906
|
+
this.state = new StateStore(initState2({ message }));
|
|
3681
3907
|
this.attachmentsByIdGetterCache = { attachmentsById: {}, attachments: [] };
|
|
3682
3908
|
this.preUploadMiddlewareExecutor = new AttachmentPreUploadMiddlewareExecutor({
|
|
3683
3909
|
composer
|
|
@@ -3782,7 +4008,8 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3782
4008
|
localMetadata: {
|
|
3783
4009
|
...attachment.localMetadata,
|
|
3784
4010
|
uploadState: "uploading",
|
|
3785
|
-
uploadProgress: this.config.trackUploadProgress ? 0 : void 0
|
|
4011
|
+
uploadProgress: this.config.trackUploadProgress ? 0 : void 0,
|
|
4012
|
+
uploadConfirmationPending: false
|
|
3786
4013
|
}
|
|
3787
4014
|
}
|
|
3788
4015
|
]);
|
|
@@ -3795,7 +4022,8 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3795
4022
|
localMetadata: {
|
|
3796
4023
|
...attachment.localMetadata,
|
|
3797
4024
|
uploadState: "uploading",
|
|
3798
|
-
uploadProgress: nextUpload.uploadProgress
|
|
4025
|
+
uploadProgress: nextUpload.uploadProgress,
|
|
4026
|
+
uploadConfirmationPending: nextUpload.uploadConfirmationPending
|
|
3799
4027
|
}
|
|
3800
4028
|
});
|
|
3801
4029
|
}
|
|
@@ -3849,6 +4077,50 @@ var localAttachmentToAttachment = (localAttachment) => {
|
|
|
3849
4077
|
const { localMetadata, ...attachment } = localAttachment;
|
|
3850
4078
|
return attachment;
|
|
3851
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
|
+
});
|
|
3852
4124
|
var createAttachmentsCompositionMiddleware = (composer) => ({
|
|
3853
4125
|
id: "stream-io/message-composer-middleware/attachments",
|
|
3854
4126
|
handlers: {
|
|
@@ -4065,7 +4337,7 @@ var getInitialMentions = (message) => {
|
|
|
4065
4337
|
};
|
|
4066
4338
|
var isSameMentionEntity = (first, second) => first.id === second.id && first.mentionType === second.mentionType;
|
|
4067
4339
|
var getMentionsFromState = (state) => state.mentions ?? state.mentionedUsers.map(userResponseToMentionEntity);
|
|
4068
|
-
var
|
|
4340
|
+
var initState3 = ({
|
|
4069
4341
|
composer,
|
|
4070
4342
|
message
|
|
4071
4343
|
}) => {
|
|
@@ -4094,7 +4366,7 @@ var initState2 = ({
|
|
|
4094
4366
|
var TextComposer = class {
|
|
4095
4367
|
constructor({ composer, message }) {
|
|
4096
4368
|
this.initState = ({ message } = {}) => {
|
|
4097
|
-
this.state.next(
|
|
4369
|
+
this.state.next(initState3({ composer: this.composer, message }));
|
|
4098
4370
|
};
|
|
4099
4371
|
this.getSnapshot = (state = this.state.getLatestValue()) => state;
|
|
4100
4372
|
this.restoreSnapshot = (snapshot) => {
|
|
@@ -4287,7 +4559,7 @@ var TextComposer = class {
|
|
|
4287
4559
|
this.commitState(output.state);
|
|
4288
4560
|
};
|
|
4289
4561
|
this.composer = composer;
|
|
4290
|
-
this.state = new StateStore(
|
|
4562
|
+
this.state = new StateStore(initState3({ composer, message }));
|
|
4291
4563
|
this.middlewareExecutor = new TextComposerMiddlewareExecutor({ composer });
|
|
4292
4564
|
}
|
|
4293
4565
|
get channel() {
|
|
@@ -5989,6 +6261,13 @@ var MessageComposerMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
|
5989
6261
|
createCompositionDataCleanupMiddleware(composer)
|
|
5990
6262
|
]);
|
|
5991
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
|
+
}
|
|
5992
6271
|
};
|
|
5993
6272
|
var MessageDraftComposerMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
5994
6273
|
constructor({ composer }) {
|
|
@@ -7103,7 +7382,7 @@ var DEFAULT_COMPOSER_CONFIG = {
|
|
|
7103
7382
|
};
|
|
7104
7383
|
|
|
7105
7384
|
// src/messageComposer/CustomDataManager.ts
|
|
7106
|
-
var
|
|
7385
|
+
var initState4 = (options) => {
|
|
7107
7386
|
if (!options)
|
|
7108
7387
|
return { message: {}, custom: {} };
|
|
7109
7388
|
return { message: {}, custom: {} };
|
|
@@ -7112,14 +7391,14 @@ var CustomDataManager = class {
|
|
|
7112
7391
|
constructor({ composer, message }) {
|
|
7113
7392
|
this.isMessageDataEqual = (nextState, previousState) => JSON.stringify(nextState.message) === JSON.stringify(previousState?.message);
|
|
7114
7393
|
this.initState = ({ message } = {}) => {
|
|
7115
|
-
this.state.next(
|
|
7394
|
+
this.state.next(initState4({ composer: this.composer, message }));
|
|
7116
7395
|
};
|
|
7117
7396
|
this.getSnapshot = () => this.state.getLatestValue();
|
|
7118
7397
|
this.restoreSnapshot = (snapshot) => {
|
|
7119
7398
|
this.state.next(snapshot);
|
|
7120
7399
|
};
|
|
7121
7400
|
this.composer = composer;
|
|
7122
|
-
this.state = new StateStore(
|
|
7401
|
+
this.state = new StateStore(initState4({ composer, message }));
|
|
7123
7402
|
}
|
|
7124
7403
|
get customMessageData() {
|
|
7125
7404
|
return this.state.getLatestValue().message;
|
|
@@ -7155,7 +7434,7 @@ var LinkPreviewStatus = /* @__PURE__ */ ((LinkPreviewStatus2) => {
|
|
|
7155
7434
|
return LinkPreviewStatus2;
|
|
7156
7435
|
})(LinkPreviewStatus || {});
|
|
7157
7436
|
var linkPreviewArrayToMap = (linkPreviews) => new Map(linkPreviews.map((linkPreview) => [linkPreview.og_scrape_url, linkPreview]));
|
|
7158
|
-
var
|
|
7437
|
+
var initState5 = ({
|
|
7159
7438
|
message
|
|
7160
7439
|
}) => message ? {
|
|
7161
7440
|
previews: message.attachments?.reduce((acc, attachment) => {
|
|
@@ -7174,7 +7453,7 @@ var _LinkPreviewsManager = class _LinkPreviewsManager {
|
|
|
7174
7453
|
this.shouldDiscardEnrichQueries = false;
|
|
7175
7454
|
this.initState = ({ message } = {}) => {
|
|
7176
7455
|
this.cancelURLEnrichment();
|
|
7177
|
-
this.state.next(
|
|
7456
|
+
this.state.next(initState5({ message: this.enabled ? message : void 0 }));
|
|
7178
7457
|
};
|
|
7179
7458
|
this.getSnapshot = () => this.state.getLatestValue();
|
|
7180
7459
|
this.restoreSnapshot = (snapshot) => {
|
|
@@ -7277,7 +7556,7 @@ var _LinkPreviewsManager = class _LinkPreviewsManager {
|
|
|
7277
7556
|
};
|
|
7278
7557
|
this.composer = composer;
|
|
7279
7558
|
this.state = new StateStore(
|
|
7280
|
-
|
|
7559
|
+
initState5({ message: this.enabled ? message : void 0 })
|
|
7281
7560
|
);
|
|
7282
7561
|
this.findAndEnrichUrls = debounce(
|
|
7283
7562
|
this._findAndEnrichUrls.bind(this),
|
|
@@ -7365,7 +7644,7 @@ var LinkPreviewsManager = _LinkPreviewsManager;
|
|
|
7365
7644
|
|
|
7366
7645
|
// src/messageComposer/LocationComposer.ts
|
|
7367
7646
|
var MIN_LIVE_LOCATION_SHARE_DURATION = 60 * 1e3;
|
|
7368
|
-
var
|
|
7647
|
+
var initState6 = ({
|
|
7369
7648
|
message
|
|
7370
7649
|
}) => ({
|
|
7371
7650
|
location: message?.shared_location ?? null
|
|
@@ -7373,7 +7652,7 @@ var initState5 = ({
|
|
|
7373
7652
|
var LocationComposer = class {
|
|
7374
7653
|
constructor({ composer, message }) {
|
|
7375
7654
|
this.initState = ({ message } = {}) => {
|
|
7376
|
-
this.state.next(
|
|
7655
|
+
this.state.next(initState6({ message }));
|
|
7377
7656
|
};
|
|
7378
7657
|
this.getSnapshot = () => this.state.getLatestValue();
|
|
7379
7658
|
this.restoreSnapshot = (snapshot) => {
|
|
@@ -7391,7 +7670,7 @@ var LocationComposer = class {
|
|
|
7391
7670
|
});
|
|
7392
7671
|
};
|
|
7393
7672
|
this.composer = composer;
|
|
7394
|
-
this.state = new StateStore(
|
|
7673
|
+
this.state = new StateStore(initState6({ message }));
|
|
7395
7674
|
this._deviceId = this.config.getDeviceId();
|
|
7396
7675
|
}
|
|
7397
7676
|
get config() {
|
|
@@ -8112,7 +8391,7 @@ var initEditingAuditState = (composition) => {
|
|
|
8112
8391
|
}
|
|
8113
8392
|
};
|
|
8114
8393
|
};
|
|
8115
|
-
var
|
|
8394
|
+
var initState7 = (composition) => {
|
|
8116
8395
|
if (!composition) {
|
|
8117
8396
|
return {
|
|
8118
8397
|
draftId: null,
|
|
@@ -8199,7 +8478,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8199
8478
|
this.textComposer.initState({ message });
|
|
8200
8479
|
this.pollComposer.initState();
|
|
8201
8480
|
this.customDataManager.initState({ message });
|
|
8202
|
-
this.state.next(
|
|
8481
|
+
this.state.next(initState7(composition));
|
|
8203
8482
|
};
|
|
8204
8483
|
this.initStateFromChannelResponse = (channelApiResponse) => {
|
|
8205
8484
|
if (this.channel.cid !== channelApiResponse.channel.cid) {
|
|
@@ -8665,7 +8944,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8665
8944
|
this.editingAuditState = new StateStore(
|
|
8666
8945
|
this.initEditingAuditState(composition)
|
|
8667
8946
|
);
|
|
8668
|
-
this.state = new StateStore(
|
|
8947
|
+
this.state = new StateStore(initState7(composition));
|
|
8669
8948
|
this.compositionMiddlewareExecutor = new MessageComposerMiddlewareExecutor({
|
|
8670
8949
|
composer: this
|
|
8671
8950
|
});
|
|
@@ -8744,8 +9023,32 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8744
9023
|
const currentCommand = this.textComposer.command;
|
|
8745
9024
|
return !currentCommand || this.validateCommandSendability(currentCommand).ready;
|
|
8746
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
|
+
}
|
|
8747
9043
|
get hasSendableData() {
|
|
8748
|
-
|
|
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);
|
|
8749
9052
|
}
|
|
8750
9053
|
get compositionIsEmpty() {
|
|
8751
9054
|
return !this.quotedMessage && this.contentIsEmpty;
|
|
@@ -9372,14 +9675,16 @@ var Channel = class {
|
|
|
9372
9675
|
*
|
|
9373
9676
|
* @return {Promise<SendMessageAPIResponse>} The Server Response
|
|
9374
9677
|
*/
|
|
9375
|
-
async _sendMessage(
|
|
9376
|
-
|
|
9377
|
-
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
|
|
9382
|
-
|
|
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
|
+
});
|
|
9383
9688
|
}
|
|
9384
9689
|
async sendMessage(message, options) {
|
|
9385
9690
|
try {
|
|
@@ -10830,6 +11135,7 @@ var Channel = class {
|
|
|
10830
11135
|
// delivery-report network sync below is skipped for it.
|
|
10831
11136
|
case "message.read_locally":
|
|
10832
11137
|
case "message.read":
|
|
11138
|
+
if (event.thread) break;
|
|
10833
11139
|
if (event.user?.id && event.created_at) {
|
|
10834
11140
|
const previousReadState = channelState.read[event.user.id];
|
|
10835
11141
|
channelState.read[event.user.id] = {
|
|
@@ -11279,7 +11585,7 @@ var ClientState = class {
|
|
|
11279
11585
|
var import_isomorphic_ws = __toESM(require("isomorphic-ws"));
|
|
11280
11586
|
|
|
11281
11587
|
// src/insights.ts
|
|
11282
|
-
var
|
|
11588
|
+
var import_axios2 = __toESM(require("axios"));
|
|
11283
11589
|
var InsightMetrics = class {
|
|
11284
11590
|
constructor() {
|
|
11285
11591
|
this.connectionStartTimestamp = null;
|
|
@@ -11292,7 +11598,7 @@ var postInsights = async (insightType, insights) => {
|
|
|
11292
11598
|
const maxAttempts = 3;
|
|
11293
11599
|
for (let i = 0; i < maxAttempts; i++) {
|
|
11294
11600
|
try {
|
|
11295
|
-
await
|
|
11601
|
+
await import_axios2.default.post(
|
|
11296
11602
|
`https://chat-insights.getstream.io/insights/${insightType}`,
|
|
11297
11603
|
insights
|
|
11298
11604
|
);
|
|
@@ -11800,131 +12106,6 @@ var StableWSConnection = class {
|
|
|
11800
12106
|
}
|
|
11801
12107
|
};
|
|
11802
12108
|
|
|
11803
|
-
// src/uploadManager.ts
|
|
11804
|
-
var initState7 = () => ({ uploads: {} });
|
|
11805
|
-
var upsertById = (uploads, record) => ({
|
|
11806
|
-
...uploads,
|
|
11807
|
-
[record.id]: { ...uploads[record.id], ...record }
|
|
11808
|
-
});
|
|
11809
|
-
var updateById = (uploads, record) => {
|
|
11810
|
-
if (!(record.id in uploads)) return null;
|
|
11811
|
-
const current = uploads[record.id];
|
|
11812
|
-
return { ...uploads, [record.id]: { ...current, ...record } };
|
|
11813
|
-
};
|
|
11814
|
-
var UploadManager = class {
|
|
11815
|
-
constructor(client) {
|
|
11816
|
-
this.client = client;
|
|
11817
|
-
this.inFlightUploads = /* @__PURE__ */ new Map();
|
|
11818
|
-
this.getUpload = (id) => this.uploads[id];
|
|
11819
|
-
/**
|
|
11820
|
-
* Clears all upload records.
|
|
11821
|
-
* Invoked when the user disconnects so a later session does not inherit stale upload state.
|
|
11822
|
-
* Aborts every in-flight upload request via its `UploadRequestOptions.abortSignal`.
|
|
11823
|
-
*/
|
|
11824
|
-
this.reset = () => {
|
|
11825
|
-
for (const { abortController } of this.inFlightUploads.values()) {
|
|
11826
|
-
abortController.abort();
|
|
11827
|
-
}
|
|
11828
|
-
this.inFlightUploads.clear();
|
|
11829
|
-
this.state.next(initState7());
|
|
11830
|
-
};
|
|
11831
|
-
/**
|
|
11832
|
-
* Removes the upload record for `id` if present.
|
|
11833
|
-
* If an upload is still in progress, aborts its `UploadRequestOptions.abortSignal`.
|
|
11834
|
-
*/
|
|
11835
|
-
this.deleteUploadRecord = (id) => {
|
|
11836
|
-
const flight = this.inFlightUploads.get(id);
|
|
11837
|
-
if (flight) {
|
|
11838
|
-
this.inFlightUploads.delete(id);
|
|
11839
|
-
flight.abortController.abort();
|
|
11840
|
-
}
|
|
11841
|
-
this.state.next((current) => {
|
|
11842
|
-
if (!(id in current.uploads)) return current;
|
|
11843
|
-
const uploads = { ...current.uploads };
|
|
11844
|
-
delete uploads[id];
|
|
11845
|
-
return { ...current, uploads };
|
|
11846
|
-
});
|
|
11847
|
-
};
|
|
11848
|
-
/**
|
|
11849
|
-
* Starts an upload for `id`, or returns the existing in-flight promise if one is already running.
|
|
11850
|
-
* Uses {@link StreamChat.channel}(`channelCid`) → `messageComposer.attachmentManager.doUploadRequest`.
|
|
11851
|
-
* Resolves with that result; rejects if the upload rejects (the record is removed from state either way).
|
|
11852
|
-
*/
|
|
11853
|
-
this.upload = ({
|
|
11854
|
-
id,
|
|
11855
|
-
channelCid,
|
|
11856
|
-
file
|
|
11857
|
-
}) => {
|
|
11858
|
-
const existing = this.inFlightUploads.get(id);
|
|
11859
|
-
if (existing) return existing.promise;
|
|
11860
|
-
let resolvePromise;
|
|
11861
|
-
let rejectPromise;
|
|
11862
|
-
const promise = new Promise((resolve, reject) => {
|
|
11863
|
-
resolvePromise = resolve;
|
|
11864
|
-
rejectPromise = reject;
|
|
11865
|
-
});
|
|
11866
|
-
const abortController = new AbortController();
|
|
11867
|
-
this.inFlightUploads.set(id, { promise, abortController });
|
|
11868
|
-
void (async () => {
|
|
11869
|
-
const attachmentManager = this.resolveAttachmentManager(channelCid);
|
|
11870
|
-
const trackProgress = attachmentManager.config.trackUploadProgress;
|
|
11871
|
-
try {
|
|
11872
|
-
this.upsertUpload({
|
|
11873
|
-
id,
|
|
11874
|
-
uploadProgress: trackProgress ? 0 : void 0
|
|
11875
|
-
});
|
|
11876
|
-
const onProgress = trackProgress ? (progress) => {
|
|
11877
|
-
this.updateUpload({
|
|
11878
|
-
id,
|
|
11879
|
-
uploadProgress: progress
|
|
11880
|
-
});
|
|
11881
|
-
} : void 0;
|
|
11882
|
-
const uploadRequestOptions = {
|
|
11883
|
-
abortSignal: abortController.signal,
|
|
11884
|
-
...onProgress ? { onProgress } : {}
|
|
11885
|
-
};
|
|
11886
|
-
const response = await attachmentManager.doUploadRequest(
|
|
11887
|
-
file,
|
|
11888
|
-
uploadRequestOptions
|
|
11889
|
-
);
|
|
11890
|
-
resolvePromise(response);
|
|
11891
|
-
} catch (error) {
|
|
11892
|
-
rejectPromise(error);
|
|
11893
|
-
} finally {
|
|
11894
|
-
this.inFlightUploads.delete(id);
|
|
11895
|
-
this.deleteUploadRecord(id);
|
|
11896
|
-
}
|
|
11897
|
-
})();
|
|
11898
|
-
return promise;
|
|
11899
|
-
};
|
|
11900
|
-
this.upsertUpload = (record) => {
|
|
11901
|
-
this.state.partialNext({
|
|
11902
|
-
uploads: upsertById(this.uploads, record)
|
|
11903
|
-
});
|
|
11904
|
-
};
|
|
11905
|
-
this.updateUpload = (record) => {
|
|
11906
|
-
this.state.next((current) => {
|
|
11907
|
-
const nextUploads = updateById(current.uploads, record);
|
|
11908
|
-
if (!nextUploads) return current;
|
|
11909
|
-
return { ...current, uploads: nextUploads };
|
|
11910
|
-
});
|
|
11911
|
-
};
|
|
11912
|
-
this.state = new StateStore(initState7());
|
|
11913
|
-
}
|
|
11914
|
-
resolveAttachmentManager(channelCid) {
|
|
11915
|
-
const colon = channelCid.indexOf(":");
|
|
11916
|
-
if (colon <= 0 || colon === channelCid.length - 1) {
|
|
11917
|
-
throw new Error(`Invalid channelCid: ${channelCid}`);
|
|
11918
|
-
}
|
|
11919
|
-
const channelType = channelCid.slice(0, colon);
|
|
11920
|
-
const channelId = channelCid.slice(colon + 1);
|
|
11921
|
-
return this.client.channel(channelType, channelId).messageComposer.attachmentManager;
|
|
11922
|
-
}
|
|
11923
|
-
get uploads() {
|
|
11924
|
-
return this.state.getLatestValue().uploads;
|
|
11925
|
-
}
|
|
11926
|
-
};
|
|
11927
|
-
|
|
11928
12109
|
// src/signing.ts
|
|
11929
12110
|
var import_jsonwebtoken = __toESM(require_jsonwebtoken());
|
|
11930
12111
|
var import_crypto = __toESM(require_crypto());
|
|
@@ -12183,7 +12364,7 @@ var TokenManager = class {
|
|
|
12183
12364
|
};
|
|
12184
12365
|
|
|
12185
12366
|
// src/connection_fallback.ts
|
|
12186
|
-
var
|
|
12367
|
+
var import_axios3 = __toESM(require("axios"));
|
|
12187
12368
|
var WSConnectionFallback = class {
|
|
12188
12369
|
constructor({ client }) {
|
|
12189
12370
|
/** @private */
|
|
@@ -12202,7 +12383,7 @@ var WSConnectionFallback = class {
|
|
|
12202
12383
|
/** @private */
|
|
12203
12384
|
this._req = async (params, config, retry) => {
|
|
12204
12385
|
if (!this.cancelToken && !params.close) {
|
|
12205
|
-
this.cancelToken =
|
|
12386
|
+
this.cancelToken = import_axios3.default.CancelToken.source();
|
|
12206
12387
|
}
|
|
12207
12388
|
try {
|
|
12208
12389
|
const res = await this.client.doAxiosRequest(
|
|
@@ -12238,7 +12419,7 @@ var WSConnectionFallback = class {
|
|
|
12238
12419
|
}
|
|
12239
12420
|
}
|
|
12240
12421
|
} catch (error) {
|
|
12241
|
-
if (
|
|
12422
|
+
if (import_axios3.default.isCancel(error)) {
|
|
12242
12423
|
this._log(`_poll() - axios canceled request`);
|
|
12243
12424
|
return;
|
|
12244
12425
|
}
|
|
@@ -14661,7 +14842,7 @@ var StreamChat = class _StreamChat {
|
|
|
14661
14842
|
return this.handleResponse(response);
|
|
14662
14843
|
} catch (e) {
|
|
14663
14844
|
e.client_request_id = requestConfig.headers?.["x-client-request-id"];
|
|
14664
|
-
if (
|
|
14845
|
+
if (import_axios4.default.isCancel(e)) throw e;
|
|
14665
14846
|
this._logApiError(type, url, e);
|
|
14666
14847
|
this.consecutiveFailures += 1;
|
|
14667
14848
|
if (e.response) {
|
|
@@ -14973,7 +15154,7 @@ var StreamChat = class _StreamChat {
|
|
|
14973
15154
|
return this.userAgent;
|
|
14974
15155
|
}
|
|
14975
15156
|
if (!this.cachedUserAgent) {
|
|
14976
|
-
const version = "9.
|
|
15157
|
+
const version = "9.52.0";
|
|
14977
15158
|
const { name: sdkName, version: sdkVersion } = this.sdkIdentifier ?? {};
|
|
14978
15159
|
const { name: appName, version: appVersion } = this.appIdentifier ?? {};
|
|
14979
15160
|
const { os, model: deviceModel } = this.deviceIdentifier ?? {};
|
|
@@ -15041,7 +15222,7 @@ var StreamChat = class _StreamChat {
|
|
|
15041
15222
|
keepAliveMsecs: 3e3
|
|
15042
15223
|
});
|
|
15043
15224
|
}
|
|
15044
|
-
this.axiosInstance =
|
|
15225
|
+
this.axiosInstance = import_axios4.default.create(this.options);
|
|
15045
15226
|
this.setBaseURL(this.options.baseURL || "https://chat.stream-io-api.com");
|
|
15046
15227
|
if (typeof process !== "undefined" && "env" in process && process.env.STREAM_LOCAL_TEST_RUN) {
|
|
15047
15228
|
this.setBaseURL("http://localhost:3030");
|
|
@@ -16393,6 +16574,11 @@ var StreamChat = class _StreamChat {
|
|
|
16393
16574
|
}
|
|
16394
16575
|
/**
|
|
16395
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
|
+
*
|
|
16396
16582
|
* @param {string} targetMessageID
|
|
16397
16583
|
* @param {string} [options.user_id] currentUserID, only used with serverside auth
|
|
16398
16584
|
* @returns {Promise<APIResponse>}
|
|
@@ -16405,6 +16591,11 @@ var StreamChat = class _StreamChat {
|
|
|
16405
16591
|
}
|
|
16406
16592
|
/**
|
|
16407
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
|
+
*
|
|
16408
16599
|
* @param {string} targetID
|
|
16409
16600
|
* @param {string} [options.user_id] currentUserID, only used with serverside auth
|
|
16410
16601
|
* @returns {Promise<APIResponse>}
|
|
@@ -16689,7 +16880,10 @@ var StreamChat = class _StreamChat {
|
|
|
16689
16880
|
if (!message.id) {
|
|
16690
16881
|
throw Error("Please specify the message.id when calling updateMessage");
|
|
16691
16882
|
}
|
|
16692
|
-
const payload =
|
|
16883
|
+
const payload = sanitizeOutgoingAttachments({
|
|
16884
|
+
client: this,
|
|
16885
|
+
message: toUpdatedMessagePayload(message)
|
|
16886
|
+
});
|
|
16693
16887
|
if (typeof partialUserOrUserId === "string") {
|
|
16694
16888
|
payload.user_id = partialUserOrUserId;
|
|
16695
16889
|
} else if (typeof partialUserOrUserId?.id === "string") {
|
|
@@ -18505,7 +18699,7 @@ var OfflineError = class extends Error {
|
|
|
18505
18699
|
};
|
|
18506
18700
|
|
|
18507
18701
|
// src/offline-support/offline_sync_manager.ts
|
|
18508
|
-
var
|
|
18702
|
+
var import_axios5 = require("axios");
|
|
18509
18703
|
var OfflineDBSyncManager = class {
|
|
18510
18704
|
constructor({
|
|
18511
18705
|
client,
|
|
@@ -18653,7 +18847,7 @@ var OfflineDBSyncManager = class {
|
|
|
18653
18847
|
});
|
|
18654
18848
|
} catch (e) {
|
|
18655
18849
|
console.log("An error has occurred while syncing the DB.", e);
|
|
18656
|
-
if ((0,
|
|
18850
|
+
if ((0, import_axios5.isAxiosError)(e) && e.code === "ECONNABORTED") {
|
|
18657
18851
|
return;
|
|
18658
18852
|
}
|
|
18659
18853
|
const error = e;
|
|
@@ -19162,6 +19356,7 @@ var AbstractOfflineDB = class {
|
|
|
19162
19356
|
return this.handleMessageUpdatedEvent({ event, execute });
|
|
19163
19357
|
}
|
|
19164
19358
|
if (type === "message.read" || type === "notification.mark_read") {
|
|
19359
|
+
if (event.thread) return [];
|
|
19165
19360
|
return this.handleRead({ event, unreadMessages: 0, execute });
|
|
19166
19361
|
}
|
|
19167
19362
|
if (type === "message.read_locally") {
|