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
package/dist/cjs/index.node.js
CHANGED
|
@@ -158,6 +158,7 @@ __export(index_exports, {
|
|
|
158
158
|
createMessageComposerStateCompositionMiddleware: () => createMessageComposerStateCompositionMiddleware,
|
|
159
159
|
createPollComposerStateMiddleware: () => createPollComposerStateMiddleware,
|
|
160
160
|
createPostUploadAttachmentEnrichmentMiddleware: () => createPostUploadAttachmentEnrichmentMiddleware,
|
|
161
|
+
createSendWithPendingUploadsAttachmentsMiddleware: () => createSendWithPendingUploadsAttachmentsMiddleware,
|
|
161
162
|
createSharedLocationCompositionMiddleware: () => createSharedLocationCompositionMiddleware,
|
|
162
163
|
createTextComposerCompositionMiddleware: () => createTextComposerCompositionMiddleware,
|
|
163
164
|
createTextComposerPreValidationMiddleware: () => createTextComposerPreValidationMiddleware,
|
|
@@ -186,6 +187,7 @@ __export(index_exports, {
|
|
|
186
187
|
getTokenizedSuggestionDisplayName: () => getTokenizedSuggestionDisplayName,
|
|
187
188
|
getTriggerCharWithToken: () => getTriggerCharWithToken,
|
|
188
189
|
gunzipPayload: () => gunzipPayload,
|
|
190
|
+
hasPending: () => hasPending,
|
|
189
191
|
insertItemWithTrigger: () => insertItemWithTrigger,
|
|
190
192
|
isAudioAttachment: () => isAudioAttachment,
|
|
191
193
|
isBlobButNotFile: () => isBlobButNotFile,
|
|
@@ -193,6 +195,7 @@ __export(index_exports, {
|
|
|
193
195
|
isFileAttachment: () => isFileAttachment,
|
|
194
196
|
isFileList: () => isFileList,
|
|
195
197
|
isFileReference: () => isFileReference,
|
|
198
|
+
isFinishedUpload: () => isFinishedUpload,
|
|
196
199
|
isGiphyAttachment: () => isGiphyAttachment,
|
|
197
200
|
isImageAttachment: () => isImageAttachment,
|
|
198
201
|
isImageFile: () => isImageFile,
|
|
@@ -205,9 +208,11 @@ __export(index_exports, {
|
|
|
205
208
|
isLocalVoiceRecordingAttachment: () => isLocalVoiceRecordingAttachment,
|
|
206
209
|
isOwnUser: () => isOwnUser,
|
|
207
210
|
isPatch: () => isPatch,
|
|
211
|
+
isPendingUpload: () => isPendingUpload,
|
|
208
212
|
isScrapedContent: () => isScrapedContent,
|
|
209
213
|
isSharedLocationResponse: () => isSharedLocationResponse,
|
|
210
214
|
isTargetedOptionTextUpdate: () => isTargetedOptionTextUpdate,
|
|
215
|
+
isUploadCancellation: () => isUploadCancellation,
|
|
211
216
|
isUploadedAttachment: () => isUploadedAttachment,
|
|
212
217
|
isVideoAttachment: () => isVideoAttachment,
|
|
213
218
|
isVoiceRecordingAttachment: () => isVoiceRecordingAttachment,
|
|
@@ -227,12 +232,15 @@ __export(index_exports, {
|
|
|
227
232
|
readFileAsArrayBuffer: () => readFileAsArrayBuffer,
|
|
228
233
|
removeDiacritics: () => removeDiacritics,
|
|
229
234
|
replaceWordWithEntity: () => replaceWordWithEntity,
|
|
235
|
+
settled: () => settled,
|
|
230
236
|
stripCommandFromText: () => stripCommandFromText,
|
|
231
237
|
stripMentionTokens: () => stripMentionTokens,
|
|
232
238
|
textIsEmpty: () => textIsEmpty,
|
|
233
239
|
timeLeftMs: () => timeLeftMs,
|
|
234
240
|
verifyAndParseWebhook: () => verifyAndParseWebhook,
|
|
235
|
-
verifySignature: () => verifySignature
|
|
241
|
+
verifySignature: () => verifySignature,
|
|
242
|
+
withCancellation: () => withCancellation,
|
|
243
|
+
withoutConcurrency: () => withoutConcurrency
|
|
236
244
|
});
|
|
237
245
|
module.exports = __toCommonJS(index_exports);
|
|
238
246
|
|
|
@@ -499,7 +507,7 @@ var ChannelBatchUpdater = class {
|
|
|
499
507
|
};
|
|
500
508
|
|
|
501
509
|
// src/client.ts
|
|
502
|
-
var
|
|
510
|
+
var import_axios4 = __toESM(require("axios"));
|
|
503
511
|
var import_https = __toESM(require("https"));
|
|
504
512
|
|
|
505
513
|
// src/utils.ts
|
|
@@ -759,6 +767,38 @@ function unformatMessage(message) {
|
|
|
759
767
|
quoted_message: toMessageResponseBase(message.quoted_message)
|
|
760
768
|
};
|
|
761
769
|
}
|
|
770
|
+
var isRemoteUrl = (url) => !!url && /^https?:\/\//i.test(url.trim());
|
|
771
|
+
var sanitizeOutgoingAttachments = ({
|
|
772
|
+
client,
|
|
773
|
+
message
|
|
774
|
+
}) => {
|
|
775
|
+
const attachments = message.attachments;
|
|
776
|
+
if (!attachments?.length) return message;
|
|
777
|
+
const unresolved = [];
|
|
778
|
+
let changed = false;
|
|
779
|
+
const sanitized = attachments.reduce((acc, attachment) => {
|
|
780
|
+
const { localMetadata, ...rest } = attachment;
|
|
781
|
+
if (!localMetadata) {
|
|
782
|
+
acc.push(attachment);
|
|
783
|
+
return acc;
|
|
784
|
+
}
|
|
785
|
+
changed = true;
|
|
786
|
+
const hasRemoteSource = isRemoteUrl(rest.asset_url) || isRemoteUrl(rest.image_url) || isRemoteUrl(rest.og_scrape_url) || isRemoteUrl(rest.title_link);
|
|
787
|
+
if (hasRemoteSource) {
|
|
788
|
+
acc.push(rest);
|
|
789
|
+
} else {
|
|
790
|
+
unresolved.push(rest);
|
|
791
|
+
}
|
|
792
|
+
return acc;
|
|
793
|
+
}, []);
|
|
794
|
+
if (unresolved.length) {
|
|
795
|
+
const text = `Dropped ${unresolved.length} attachment(s) whose upload never completed. Composing with pending uploads requires awaiting them before sending.`;
|
|
796
|
+
const extraData = { attachments: unresolved, message, tags: ["attachments"] };
|
|
797
|
+
client.logger("warn", text, extraData);
|
|
798
|
+
console.warn(text, extraData);
|
|
799
|
+
}
|
|
800
|
+
return changed ? { ...message, attachments: sanitized } : message;
|
|
801
|
+
};
|
|
762
802
|
var localMessageToNewMessagePayload = (localMessage) => {
|
|
763
803
|
const {
|
|
764
804
|
// Remove all timestamp fields and client-specific fields.
|
|
@@ -2531,6 +2571,12 @@ var CooldownTimer = class extends WithSubscriptions {
|
|
|
2531
2571
|
var isScrapedContent = (attachment) => !!attachment?.og_scrape_url || !!attachment?.title_link;
|
|
2532
2572
|
var isLocalAttachment = (attachment) => !!attachment?.localMetadata?.id;
|
|
2533
2573
|
var isLocalUploadAttachment = (attachment) => !!attachment?.localMetadata?.uploadState;
|
|
2574
|
+
var PENDING_UPLOAD_STATES = [
|
|
2575
|
+
"pending",
|
|
2576
|
+
"uploading"
|
|
2577
|
+
];
|
|
2578
|
+
var isPendingUpload = (attachment) => isLocalUploadAttachment(attachment) && PENDING_UPLOAD_STATES.includes(attachment.localMetadata.uploadState);
|
|
2579
|
+
var isFinishedUpload = (attachment) => isLocalUploadAttachment(attachment) && attachment.localMetadata.uploadState === "finished";
|
|
2534
2580
|
var isFileAttachment = (attachment, supportedVideoFormat = []) => attachment.type === "file" || !!(attachment.mime_type && supportedVideoFormat.indexOf(attachment.mime_type) === -1 && attachment.type !== "video");
|
|
2535
2581
|
var isLocalFileAttachment = (attachment) => isFileAttachment(attachment) && isLocalAttachment(attachment);
|
|
2536
2582
|
var isImageAttachment = (attachment) => attachment.type === "image" && !isScrapedContent(attachment);
|
|
@@ -2606,7 +2652,7 @@ var ensureIsLocalAttachment = (attachment) => {
|
|
|
2606
2652
|
};
|
|
2607
2653
|
|
|
2608
2654
|
// src/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.ts
|
|
2609
|
-
var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
2655
|
+
var createPostUploadAttachmentEnrichmentMiddleware = (composer) => ({
|
|
2610
2656
|
id: "stream-io/attachment-manager-middleware/post-upload-enrichment",
|
|
2611
2657
|
handlers: {
|
|
2612
2658
|
postProcess: ({
|
|
@@ -2619,9 +2665,10 @@ var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
|
2619
2665
|
if (error) return forward();
|
|
2620
2666
|
if (!attachment || !response) return discard();
|
|
2621
2667
|
const enrichedAttachment = { ...attachment };
|
|
2622
|
-
const previewUri = attachment.localMetadata
|
|
2623
|
-
|
|
2624
|
-
|
|
2668
|
+
const { id, previewUri } = attachment.localMetadata;
|
|
2669
|
+
const attachmentIsStillInComposer = !composer || !!composer.attachmentManager.attachmentsById[id];
|
|
2670
|
+
if (previewUri && attachmentIsStillInComposer) {
|
|
2671
|
+
if (previewUri.startsWith("blob:")) URL.revokeObjectURL?.(previewUri);
|
|
2625
2672
|
delete enrichedAttachment.localMetadata.previewUri;
|
|
2626
2673
|
}
|
|
2627
2674
|
if (isLocalImageAttachment(attachment)) {
|
|
@@ -2644,6 +2691,12 @@ var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
|
2644
2691
|
var withoutConcurrency = createRunner(wrapWithContinuationTracking);
|
|
2645
2692
|
var withCancellation = createRunner(wrapWithCancellation);
|
|
2646
2693
|
var pendingPromises = /* @__PURE__ */ new Map();
|
|
2694
|
+
function hasPending(tag) {
|
|
2695
|
+
return pendingPromises.has(tag);
|
|
2696
|
+
}
|
|
2697
|
+
async function settled(tag) {
|
|
2698
|
+
await pendingPromises.get(tag)?.promise;
|
|
2699
|
+
}
|
|
2647
2700
|
function createRunner(wrapper) {
|
|
2648
2701
|
return function run(tag, cb) {
|
|
2649
2702
|
const { cb: wrapped, onContinued } = wrapper(tag, cb);
|
|
@@ -2686,6 +2739,16 @@ var MiddlewareExecutor = class {
|
|
|
2686
2739
|
this.middleware = [];
|
|
2687
2740
|
this.id = generateUUIDv4();
|
|
2688
2741
|
}
|
|
2742
|
+
/**
|
|
2743
|
+
* The middleware currently installed, in execution order.
|
|
2744
|
+
*
|
|
2745
|
+
* Read-only: use `use` / `insert` / `replace` / `setOrder` / `remove` to change the chain. It
|
|
2746
|
+
* exists so components can ask what the chain is capable of - a middleware may declare
|
|
2747
|
+
* behaviour its host has to account for, and the host has no other way to find out.
|
|
2748
|
+
*/
|
|
2749
|
+
get installedMiddleware() {
|
|
2750
|
+
return this.middleware;
|
|
2751
|
+
}
|
|
2689
2752
|
use(middleware) {
|
|
2690
2753
|
this.middleware = this.middleware.concat(middleware);
|
|
2691
2754
|
return this;
|
|
@@ -2789,6 +2852,142 @@ var MiddlewareExecutor = class {
|
|
|
2789
2852
|
}
|
|
2790
2853
|
};
|
|
2791
2854
|
|
|
2855
|
+
// src/uploadManager.ts
|
|
2856
|
+
var import_axios = __toESM(require("axios"));
|
|
2857
|
+
var isUploadCancellation = (error) => import_axios.default.isCancel(error) || error instanceof Error && error.name === "AbortError";
|
|
2858
|
+
var initState = () => ({ uploads: {} });
|
|
2859
|
+
var upsertById = (uploads, record) => ({
|
|
2860
|
+
...uploads,
|
|
2861
|
+
[record.id]: { ...uploads[record.id], ...record }
|
|
2862
|
+
});
|
|
2863
|
+
var updateById = (uploads, record) => {
|
|
2864
|
+
if (!(record.id in uploads)) return null;
|
|
2865
|
+
const current = uploads[record.id];
|
|
2866
|
+
return { ...uploads, [record.id]: { ...current, ...record } };
|
|
2867
|
+
};
|
|
2868
|
+
var UploadManager = class {
|
|
2869
|
+
constructor(client) {
|
|
2870
|
+
this.client = client;
|
|
2871
|
+
this.inFlightUploads = /* @__PURE__ */ new Map();
|
|
2872
|
+
this.getUpload = (id) => this.uploads[id];
|
|
2873
|
+
/**
|
|
2874
|
+
* Clears all upload records.
|
|
2875
|
+
* Invoked when the user disconnects so a later session does not inherit stale upload state.
|
|
2876
|
+
* Aborts every in-flight upload request via its `UploadRequestOptions.abortSignal`.
|
|
2877
|
+
*/
|
|
2878
|
+
this.reset = () => {
|
|
2879
|
+
for (const { abortController } of this.inFlightUploads.values()) {
|
|
2880
|
+
abortController.abort();
|
|
2881
|
+
}
|
|
2882
|
+
this.inFlightUploads.clear();
|
|
2883
|
+
this.state.next(initState());
|
|
2884
|
+
};
|
|
2885
|
+
/**
|
|
2886
|
+
* Removes the upload record for `id` if present.
|
|
2887
|
+
* If an upload is still in progress, aborts its `UploadRequestOptions.abortSignal`.
|
|
2888
|
+
*/
|
|
2889
|
+
this.deleteUploadRecord = (id) => {
|
|
2890
|
+
const flight = this.inFlightUploads.get(id);
|
|
2891
|
+
if (flight) {
|
|
2892
|
+
this.inFlightUploads.delete(id);
|
|
2893
|
+
flight.abortController.abort();
|
|
2894
|
+
}
|
|
2895
|
+
this.state.next((current) => {
|
|
2896
|
+
if (!(id in current.uploads)) return current;
|
|
2897
|
+
const uploads = { ...current.uploads };
|
|
2898
|
+
delete uploads[id];
|
|
2899
|
+
return { ...current, uploads };
|
|
2900
|
+
});
|
|
2901
|
+
};
|
|
2902
|
+
/**
|
|
2903
|
+
* Starts an upload for `id`, or returns the existing in-flight promise if one is already running.
|
|
2904
|
+
* Uses {@link StreamChat.channel}(`channelCid`) → `messageComposer.attachmentManager.doUploadRequest`.
|
|
2905
|
+
* Resolves with that result; rejects if the upload rejects (the record is removed from state either way).
|
|
2906
|
+
*/
|
|
2907
|
+
this.upload = ({
|
|
2908
|
+
id,
|
|
2909
|
+
channelCid,
|
|
2910
|
+
file
|
|
2911
|
+
}) => {
|
|
2912
|
+
const existing = this.inFlightUploads.get(id);
|
|
2913
|
+
if (existing) return existing.promise;
|
|
2914
|
+
let resolvePromise;
|
|
2915
|
+
let rejectPromise;
|
|
2916
|
+
const promise = new Promise((resolve, reject) => {
|
|
2917
|
+
resolvePromise = resolve;
|
|
2918
|
+
rejectPromise = reject;
|
|
2919
|
+
});
|
|
2920
|
+
const abortController = new AbortController();
|
|
2921
|
+
this.inFlightUploads.set(id, { promise, abortController });
|
|
2922
|
+
void (async () => {
|
|
2923
|
+
const attachmentManager = this.resolveAttachmentManager(channelCid);
|
|
2924
|
+
const trackProgress = attachmentManager.config.trackUploadProgress;
|
|
2925
|
+
try {
|
|
2926
|
+
this.upsertUpload({
|
|
2927
|
+
uploadConfirmationPending: false,
|
|
2928
|
+
id,
|
|
2929
|
+
uploadProgress: trackProgress ? 0 : void 0
|
|
2930
|
+
});
|
|
2931
|
+
const onProgress = trackProgress ? (progress) => {
|
|
2932
|
+
this.updateUpload({
|
|
2933
|
+
id,
|
|
2934
|
+
uploadProgress: progress,
|
|
2935
|
+
// Only a number says anything about the flush, so a report without one leaves
|
|
2936
|
+
// the flag alone: `undefined` means the transport cannot measure this upload,
|
|
2937
|
+
// not that bytes were un-sent. Lowering it there would drop a UI that had
|
|
2938
|
+
// already gone indeterminate back to a determinate one with nothing to show.
|
|
2939
|
+
//
|
|
2940
|
+
// The record is removed in the `finally` below, so a record that still exists
|
|
2941
|
+
// while reporting 100% can only mean "flushed, awaiting the response".
|
|
2942
|
+
...typeof progress === "number" ? { uploadConfirmationPending: progress >= 100 } : {}
|
|
2943
|
+
});
|
|
2944
|
+
} : void 0;
|
|
2945
|
+
const uploadRequestOptions = {
|
|
2946
|
+
abortSignal: abortController.signal,
|
|
2947
|
+
...onProgress ? { onProgress } : {}
|
|
2948
|
+
};
|
|
2949
|
+
const response = await attachmentManager.doUploadRequest(
|
|
2950
|
+
file,
|
|
2951
|
+
uploadRequestOptions
|
|
2952
|
+
);
|
|
2953
|
+
resolvePromise(response);
|
|
2954
|
+
} catch (error) {
|
|
2955
|
+
rejectPromise(error);
|
|
2956
|
+
} finally {
|
|
2957
|
+
this.inFlightUploads.delete(id);
|
|
2958
|
+
this.deleteUploadRecord(id);
|
|
2959
|
+
}
|
|
2960
|
+
})();
|
|
2961
|
+
return promise;
|
|
2962
|
+
};
|
|
2963
|
+
this.upsertUpload = (record) => {
|
|
2964
|
+
this.state.partialNext({
|
|
2965
|
+
uploads: upsertById(this.uploads, record)
|
|
2966
|
+
});
|
|
2967
|
+
};
|
|
2968
|
+
this.updateUpload = (record) => {
|
|
2969
|
+
this.state.next((current) => {
|
|
2970
|
+
const nextUploads = updateById(current.uploads, record);
|
|
2971
|
+
if (!nextUploads) return current;
|
|
2972
|
+
return { ...current, uploads: nextUploads };
|
|
2973
|
+
});
|
|
2974
|
+
};
|
|
2975
|
+
this.state = new StateStore(initState());
|
|
2976
|
+
}
|
|
2977
|
+
resolveAttachmentManager(channelCid) {
|
|
2978
|
+
const colon = channelCid.indexOf(":");
|
|
2979
|
+
if (colon <= 0 || colon === channelCid.length - 1) {
|
|
2980
|
+
throw new Error(`Invalid channelCid: ${channelCid}`);
|
|
2981
|
+
}
|
|
2982
|
+
const channelType = channelCid.slice(0, colon);
|
|
2983
|
+
const channelId = channelCid.slice(colon + 1);
|
|
2984
|
+
return this.client.channel(channelType, channelId).messageComposer.attachmentManager;
|
|
2985
|
+
}
|
|
2986
|
+
get uploads() {
|
|
2987
|
+
return this.state.getLatestValue().uploads;
|
|
2988
|
+
}
|
|
2989
|
+
};
|
|
2990
|
+
|
|
2792
2991
|
// src/messageComposer/middleware/attachmentManager/postUpload/uploadErrorHandler.ts
|
|
2793
2992
|
var createUploadErrorHandlerMiddleware = (composer) => ({
|
|
2794
2993
|
id: "stream-io/attachment-manager-middleware/upload-error",
|
|
@@ -2801,6 +3000,7 @@ var createUploadErrorHandlerMiddleware = (composer) => ({
|
|
|
2801
3000
|
const { attachment, error } = state;
|
|
2802
3001
|
if (!error) return forward();
|
|
2803
3002
|
if (!attachment) return discard();
|
|
3003
|
+
if (isUploadCancellation(error)) return forward();
|
|
2804
3004
|
const reason = error instanceof Error ? error.message : "unknown error";
|
|
2805
3005
|
composer.client.notifications.addError({
|
|
2806
3006
|
message: "Error uploading attachment",
|
|
@@ -2825,7 +3025,7 @@ var AttachmentPostUploadMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
|
2825
3025
|
super();
|
|
2826
3026
|
this.use([
|
|
2827
3027
|
createUploadErrorHandlerMiddleware(composer),
|
|
2828
|
-
createPostUploadAttachmentEnrichmentMiddleware()
|
|
3028
|
+
createPostUploadAttachmentEnrichmentMiddleware(composer)
|
|
2829
3029
|
]);
|
|
2830
3030
|
}
|
|
2831
3031
|
};
|
|
@@ -3273,7 +3473,7 @@ function mergeWithDiff(target, source, customizer) {
|
|
|
3273
3473
|
}
|
|
3274
3474
|
|
|
3275
3475
|
// src/messageComposer/attachmentManager.ts
|
|
3276
|
-
var
|
|
3476
|
+
var initState2 = ({
|
|
3277
3477
|
message
|
|
3278
3478
|
}) => ({
|
|
3279
3479
|
attachments: (message?.attachments ?? [])?.filter(({ og_scrape_url }) => !og_scrape_url).map((att) => {
|
|
@@ -3301,13 +3501,14 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3301
3501
|
...attachment,
|
|
3302
3502
|
localMetadata: {
|
|
3303
3503
|
...attachment.localMetadata,
|
|
3504
|
+
uploadConfirmationPending: false,
|
|
3304
3505
|
uploadProgress: void 0,
|
|
3305
3506
|
uploadState: "failed"
|
|
3306
3507
|
}
|
|
3307
3508
|
};
|
|
3308
3509
|
};
|
|
3309
3510
|
this.initState = ({ message } = {}) => {
|
|
3310
|
-
this.state.next(
|
|
3511
|
+
this.state.next(initState2({ message }));
|
|
3311
3512
|
};
|
|
3312
3513
|
this.getSnapshot = () => {
|
|
3313
3514
|
const state = this.state.getLatestValue();
|
|
@@ -3384,8 +3585,22 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3384
3585
|
this.state.partialNext({ attachments });
|
|
3385
3586
|
}
|
|
3386
3587
|
};
|
|
3588
|
+
/**
|
|
3589
|
+
* Releases a local preview URL the SDK minted, if it minted one.
|
|
3590
|
+
*
|
|
3591
|
+
* Only `blob:` URLs are ours to revoke: `toLocalUploadAttachment` puts a
|
|
3592
|
+
* `URL.createObjectURL` result in `previewUri` for a `File`, but for a React Native
|
|
3593
|
+
* `FileReference` it stores the caller's own native file URI, which must be left alone.
|
|
3594
|
+
*/
|
|
3595
|
+
this.revokePreviewUri = (attachment) => {
|
|
3596
|
+
const previewUri = attachment.localMetadata?.previewUri;
|
|
3597
|
+
if (previewUri?.startsWith("blob:")) URL.revokeObjectURL?.(previewUri);
|
|
3598
|
+
};
|
|
3387
3599
|
this.removeAttachments = (localAttachmentIds) => {
|
|
3388
3600
|
if (!localAttachmentIds.length) return;
|
|
3601
|
+
const removedAttachments = this.attachments.filter(
|
|
3602
|
+
(attachment) => localAttachmentIds.includes(attachment.localMetadata?.id)
|
|
3603
|
+
);
|
|
3389
3604
|
this.state.partialNext({
|
|
3390
3605
|
attachments: this.attachments.filter(
|
|
3391
3606
|
(attachment) => !localAttachmentIds.includes(attachment.localMetadata?.id)
|
|
@@ -3394,6 +3609,7 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3394
3609
|
for (const id of localAttachmentIds) {
|
|
3395
3610
|
this.client.uploadManager.deleteUploadRecord(id);
|
|
3396
3611
|
}
|
|
3612
|
+
removedAttachments.forEach(this.revokePreviewUri);
|
|
3397
3613
|
};
|
|
3398
3614
|
this.getUploadConfigCheck = async (fileLike) => {
|
|
3399
3615
|
const client = this.channel.getClient();
|
|
@@ -3545,21 +3761,27 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3545
3761
|
localMetadata: {
|
|
3546
3762
|
...attachment.localMetadata,
|
|
3547
3763
|
uploadState: "failed",
|
|
3548
|
-
uploadProgress: void 0
|
|
3764
|
+
uploadProgress: void 0,
|
|
3765
|
+
// `false`, not `undefined`: these updates go through `updateAttachment`, which merges
|
|
3766
|
+
// via `mergeWith` — and that skips `undefined` source values, so `undefined` would
|
|
3767
|
+
// leave a stale `true` in place.
|
|
3768
|
+
uploadConfirmationPending: false
|
|
3549
3769
|
}
|
|
3550
3770
|
};
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3771
|
+
if (!isUploadCancellation(error)) {
|
|
3772
|
+
this.client.notifications.addError({
|
|
3773
|
+
message: "Error uploading attachment",
|
|
3774
|
+
origin: {
|
|
3775
|
+
emitter: "AttachmentManager",
|
|
3776
|
+
context: { attachment, failedAttachment }
|
|
3777
|
+
},
|
|
3778
|
+
options: {
|
|
3779
|
+
type: "api:attachment:upload:failed",
|
|
3780
|
+
metadata: { reason },
|
|
3781
|
+
originalError: error instanceof Error ? error : void 0
|
|
3782
|
+
}
|
|
3783
|
+
});
|
|
3784
|
+
}
|
|
3563
3785
|
this.updateAttachment(failedAttachment);
|
|
3564
3786
|
return failedAttachment;
|
|
3565
3787
|
}
|
|
@@ -3572,7 +3794,9 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3572
3794
|
localMetadata: {
|
|
3573
3795
|
...attachment.localMetadata,
|
|
3574
3796
|
uploadState: "finished",
|
|
3575
|
-
uploadProgress: void 0
|
|
3797
|
+
uploadProgress: void 0,
|
|
3798
|
+
// See the note in the failure branch: `undefined` cannot clear through `mergeWith`.
|
|
3799
|
+
uploadConfirmationPending: false
|
|
3576
3800
|
}
|
|
3577
3801
|
};
|
|
3578
3802
|
const previewUri = uploadedAttachment.localMetadata.previewUri;
|
|
@@ -3621,7 +3845,9 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3621
3845
|
localMetadata: {
|
|
3622
3846
|
...attachment.localMetadata,
|
|
3623
3847
|
uploadState: error ? "failed" : "finished",
|
|
3624
|
-
uploadProgress: void 0
|
|
3848
|
+
uploadProgress: void 0,
|
|
3849
|
+
// See the note in `uploadAttachment`: `undefined` cannot clear through `mergeWith`.
|
|
3850
|
+
uploadConfirmationPending: false
|
|
3625
3851
|
}
|
|
3626
3852
|
},
|
|
3627
3853
|
error,
|
|
@@ -3646,7 +3872,7 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3646
3872
|
);
|
|
3647
3873
|
};
|
|
3648
3874
|
this.composer = composer;
|
|
3649
|
-
this.state = new StateStore(
|
|
3875
|
+
this.state = new StateStore(initState2({ message }));
|
|
3650
3876
|
this.attachmentsByIdGetterCache = { attachmentsById: {}, attachments: [] };
|
|
3651
3877
|
this.preUploadMiddlewareExecutor = new AttachmentPreUploadMiddlewareExecutor({
|
|
3652
3878
|
composer
|
|
@@ -3751,7 +3977,8 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3751
3977
|
localMetadata: {
|
|
3752
3978
|
...attachment.localMetadata,
|
|
3753
3979
|
uploadState: "uploading",
|
|
3754
|
-
uploadProgress: this.config.trackUploadProgress ? 0 : void 0
|
|
3980
|
+
uploadProgress: this.config.trackUploadProgress ? 0 : void 0,
|
|
3981
|
+
uploadConfirmationPending: false
|
|
3755
3982
|
}
|
|
3756
3983
|
}
|
|
3757
3984
|
]);
|
|
@@ -3764,7 +3991,8 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3764
3991
|
localMetadata: {
|
|
3765
3992
|
...attachment.localMetadata,
|
|
3766
3993
|
uploadState: "uploading",
|
|
3767
|
-
uploadProgress: nextUpload.uploadProgress
|
|
3994
|
+
uploadProgress: nextUpload.uploadProgress,
|
|
3995
|
+
uploadConfirmationPending: nextUpload.uploadConfirmationPending
|
|
3768
3996
|
}
|
|
3769
3997
|
});
|
|
3770
3998
|
}
|
|
@@ -3818,6 +4046,50 @@ var localAttachmentToAttachment = (localAttachment) => {
|
|
|
3818
4046
|
const { localMetadata, ...attachment } = localAttachment;
|
|
3819
4047
|
return attachment;
|
|
3820
4048
|
};
|
|
4049
|
+
var composeWithPendingUploads = ({
|
|
4050
|
+
composer,
|
|
4051
|
+
state
|
|
4052
|
+
}) => {
|
|
4053
|
+
const composerIsKeptAsDraft = !!composer.pollId;
|
|
4054
|
+
const relevantAttachments = composer.attachmentManager.attachments.filter(
|
|
4055
|
+
(attachment) => isFinishedUpload(attachment) || !composerIsKeptAsDraft && isPendingUpload(attachment)
|
|
4056
|
+
);
|
|
4057
|
+
const localAttachments = (state.localMessage.attachments ?? []).concat(
|
|
4058
|
+
relevantAttachments.map(
|
|
4059
|
+
(attachment) => isPendingUpload(attachment) ? attachment : localAttachmentToAttachment(attachment)
|
|
4060
|
+
)
|
|
4061
|
+
);
|
|
4062
|
+
const messageAttachments = (state.message.attachments ?? []).concat(
|
|
4063
|
+
relevantAttachments.filter(isFinishedUpload).map(localAttachmentToAttachment)
|
|
4064
|
+
);
|
|
4065
|
+
if (!localAttachments.length && !messageAttachments.length) return state;
|
|
4066
|
+
return {
|
|
4067
|
+
...state,
|
|
4068
|
+
localMessage: localAttachments.length ? {
|
|
4069
|
+
...state.localMessage,
|
|
4070
|
+
attachments: localAttachments
|
|
4071
|
+
} : state.localMessage,
|
|
4072
|
+
message: messageAttachments.length ? {
|
|
4073
|
+
...state.message,
|
|
4074
|
+
attachments: messageAttachments
|
|
4075
|
+
} : state.message
|
|
4076
|
+
};
|
|
4077
|
+
};
|
|
4078
|
+
var createSendWithPendingUploadsAttachmentsMiddleware = (composer) => ({
|
|
4079
|
+
allowsPendingUploads: true,
|
|
4080
|
+
id: "stream-io/message-composer-middleware/attachments",
|
|
4081
|
+
handlers: {
|
|
4082
|
+
compose: ({
|
|
4083
|
+
state,
|
|
4084
|
+
next,
|
|
4085
|
+
forward
|
|
4086
|
+
}) => {
|
|
4087
|
+
const { attachmentManager } = composer;
|
|
4088
|
+
if (!attachmentManager) return forward();
|
|
4089
|
+
return next(composeWithPendingUploads({ composer, state }));
|
|
4090
|
+
}
|
|
4091
|
+
}
|
|
4092
|
+
});
|
|
3821
4093
|
var createAttachmentsCompositionMiddleware = (composer) => ({
|
|
3822
4094
|
id: "stream-io/message-composer-middleware/attachments",
|
|
3823
4095
|
handlers: {
|
|
@@ -4034,7 +4306,7 @@ var getInitialMentions = (message) => {
|
|
|
4034
4306
|
};
|
|
4035
4307
|
var isSameMentionEntity = (first, second) => first.id === second.id && first.mentionType === second.mentionType;
|
|
4036
4308
|
var getMentionsFromState = (state) => state.mentions ?? state.mentionedUsers.map(userResponseToMentionEntity);
|
|
4037
|
-
var
|
|
4309
|
+
var initState3 = ({
|
|
4038
4310
|
composer,
|
|
4039
4311
|
message
|
|
4040
4312
|
}) => {
|
|
@@ -4063,7 +4335,7 @@ var initState2 = ({
|
|
|
4063
4335
|
var TextComposer = class {
|
|
4064
4336
|
constructor({ composer, message }) {
|
|
4065
4337
|
this.initState = ({ message } = {}) => {
|
|
4066
|
-
this.state.next(
|
|
4338
|
+
this.state.next(initState3({ composer: this.composer, message }));
|
|
4067
4339
|
};
|
|
4068
4340
|
this.getSnapshot = (state = this.state.getLatestValue()) => state;
|
|
4069
4341
|
this.restoreSnapshot = (snapshot) => {
|
|
@@ -4256,7 +4528,7 @@ var TextComposer = class {
|
|
|
4256
4528
|
this.commitState(output.state);
|
|
4257
4529
|
};
|
|
4258
4530
|
this.composer = composer;
|
|
4259
|
-
this.state = new StateStore(
|
|
4531
|
+
this.state = new StateStore(initState3({ composer, message }));
|
|
4260
4532
|
this.middlewareExecutor = new TextComposerMiddlewareExecutor({ composer });
|
|
4261
4533
|
}
|
|
4262
4534
|
get channel() {
|
|
@@ -5958,6 +6230,13 @@ var MessageComposerMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
|
5958
6230
|
createCompositionDataCleanupMiddleware(composer)
|
|
5959
6231
|
]);
|
|
5960
6232
|
}
|
|
6233
|
+
/**
|
|
6234
|
+
* Narrows the base accessor to the composition middleware type, so callers can read the
|
|
6235
|
+
* declarations it carries (`allowsPendingUploads`) without casting.
|
|
6236
|
+
*/
|
|
6237
|
+
get installedMiddleware() {
|
|
6238
|
+
return super.installedMiddleware;
|
|
6239
|
+
}
|
|
5961
6240
|
};
|
|
5962
6241
|
var MessageDraftComposerMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
5963
6242
|
constructor({ composer }) {
|
|
@@ -7072,7 +7351,7 @@ var DEFAULT_COMPOSER_CONFIG = {
|
|
|
7072
7351
|
};
|
|
7073
7352
|
|
|
7074
7353
|
// src/messageComposer/CustomDataManager.ts
|
|
7075
|
-
var
|
|
7354
|
+
var initState4 = (options) => {
|
|
7076
7355
|
if (!options)
|
|
7077
7356
|
return { message: {}, custom: {} };
|
|
7078
7357
|
return { message: {}, custom: {} };
|
|
@@ -7081,14 +7360,14 @@ var CustomDataManager = class {
|
|
|
7081
7360
|
constructor({ composer, message }) {
|
|
7082
7361
|
this.isMessageDataEqual = (nextState, previousState) => JSON.stringify(nextState.message) === JSON.stringify(previousState?.message);
|
|
7083
7362
|
this.initState = ({ message } = {}) => {
|
|
7084
|
-
this.state.next(
|
|
7363
|
+
this.state.next(initState4({ composer: this.composer, message }));
|
|
7085
7364
|
};
|
|
7086
7365
|
this.getSnapshot = () => this.state.getLatestValue();
|
|
7087
7366
|
this.restoreSnapshot = (snapshot) => {
|
|
7088
7367
|
this.state.next(snapshot);
|
|
7089
7368
|
};
|
|
7090
7369
|
this.composer = composer;
|
|
7091
|
-
this.state = new StateStore(
|
|
7370
|
+
this.state = new StateStore(initState4({ composer, message }));
|
|
7092
7371
|
}
|
|
7093
7372
|
get customMessageData() {
|
|
7094
7373
|
return this.state.getLatestValue().message;
|
|
@@ -7124,7 +7403,7 @@ var LinkPreviewStatus = /* @__PURE__ */ ((LinkPreviewStatus2) => {
|
|
|
7124
7403
|
return LinkPreviewStatus2;
|
|
7125
7404
|
})(LinkPreviewStatus || {});
|
|
7126
7405
|
var linkPreviewArrayToMap = (linkPreviews) => new Map(linkPreviews.map((linkPreview) => [linkPreview.og_scrape_url, linkPreview]));
|
|
7127
|
-
var
|
|
7406
|
+
var initState5 = ({
|
|
7128
7407
|
message
|
|
7129
7408
|
}) => message ? {
|
|
7130
7409
|
previews: message.attachments?.reduce((acc, attachment) => {
|
|
@@ -7143,7 +7422,7 @@ var _LinkPreviewsManager = class _LinkPreviewsManager {
|
|
|
7143
7422
|
this.shouldDiscardEnrichQueries = false;
|
|
7144
7423
|
this.initState = ({ message } = {}) => {
|
|
7145
7424
|
this.cancelURLEnrichment();
|
|
7146
|
-
this.state.next(
|
|
7425
|
+
this.state.next(initState5({ message: this.enabled ? message : void 0 }));
|
|
7147
7426
|
};
|
|
7148
7427
|
this.getSnapshot = () => this.state.getLatestValue();
|
|
7149
7428
|
this.restoreSnapshot = (snapshot) => {
|
|
@@ -7246,7 +7525,7 @@ var _LinkPreviewsManager = class _LinkPreviewsManager {
|
|
|
7246
7525
|
};
|
|
7247
7526
|
this.composer = composer;
|
|
7248
7527
|
this.state = new StateStore(
|
|
7249
|
-
|
|
7528
|
+
initState5({ message: this.enabled ? message : void 0 })
|
|
7250
7529
|
);
|
|
7251
7530
|
this.findAndEnrichUrls = debounce(
|
|
7252
7531
|
this._findAndEnrichUrls.bind(this),
|
|
@@ -7334,7 +7613,7 @@ var LinkPreviewsManager = _LinkPreviewsManager;
|
|
|
7334
7613
|
|
|
7335
7614
|
// src/messageComposer/LocationComposer.ts
|
|
7336
7615
|
var MIN_LIVE_LOCATION_SHARE_DURATION = 60 * 1e3;
|
|
7337
|
-
var
|
|
7616
|
+
var initState6 = ({
|
|
7338
7617
|
message
|
|
7339
7618
|
}) => ({
|
|
7340
7619
|
location: message?.shared_location ?? null
|
|
@@ -7342,7 +7621,7 @@ var initState5 = ({
|
|
|
7342
7621
|
var LocationComposer = class {
|
|
7343
7622
|
constructor({ composer, message }) {
|
|
7344
7623
|
this.initState = ({ message } = {}) => {
|
|
7345
|
-
this.state.next(
|
|
7624
|
+
this.state.next(initState6({ message }));
|
|
7346
7625
|
};
|
|
7347
7626
|
this.getSnapshot = () => this.state.getLatestValue();
|
|
7348
7627
|
this.restoreSnapshot = (snapshot) => {
|
|
@@ -7360,7 +7639,7 @@ var LocationComposer = class {
|
|
|
7360
7639
|
});
|
|
7361
7640
|
};
|
|
7362
7641
|
this.composer = composer;
|
|
7363
|
-
this.state = new StateStore(
|
|
7642
|
+
this.state = new StateStore(initState6({ message }));
|
|
7364
7643
|
this._deviceId = this.config.getDeviceId();
|
|
7365
7644
|
}
|
|
7366
7645
|
get config() {
|
|
@@ -8081,7 +8360,7 @@ var initEditingAuditState = (composition) => {
|
|
|
8081
8360
|
}
|
|
8082
8361
|
};
|
|
8083
8362
|
};
|
|
8084
|
-
var
|
|
8363
|
+
var initState7 = (composition) => {
|
|
8085
8364
|
if (!composition) {
|
|
8086
8365
|
return {
|
|
8087
8366
|
draftId: null,
|
|
@@ -8168,7 +8447,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8168
8447
|
this.textComposer.initState({ message });
|
|
8169
8448
|
this.pollComposer.initState();
|
|
8170
8449
|
this.customDataManager.initState({ message });
|
|
8171
|
-
this.state.next(
|
|
8450
|
+
this.state.next(initState7(composition));
|
|
8172
8451
|
};
|
|
8173
8452
|
this.initStateFromChannelResponse = (channelApiResponse) => {
|
|
8174
8453
|
if (this.channel.cid !== channelApiResponse.channel.cid) {
|
|
@@ -8634,7 +8913,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8634
8913
|
this.editingAuditState = new StateStore(
|
|
8635
8914
|
this.initEditingAuditState(composition)
|
|
8636
8915
|
);
|
|
8637
|
-
this.state = new StateStore(
|
|
8916
|
+
this.state = new StateStore(initState7(composition));
|
|
8638
8917
|
this.compositionMiddlewareExecutor = new MessageComposerMiddlewareExecutor({
|
|
8639
8918
|
composer: this
|
|
8640
8919
|
});
|
|
@@ -8713,8 +8992,32 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8713
8992
|
const currentCommand = this.textComposer.command;
|
|
8714
8993
|
return !currentCommand || this.validateCommandSendability(currentCommand).ready;
|
|
8715
8994
|
}
|
|
8995
|
+
/**
|
|
8996
|
+
* Whether the installed composition middleware composes messages whose uploads are still in
|
|
8997
|
+
* flight — see `MessageCompositionMiddleware.allowsPendingUploads`.
|
|
8998
|
+
*
|
|
8999
|
+
* Derived from the chain rather than from config, so there is exactly one switch: the UI SDK
|
|
9000
|
+
* that implements the rest of the flow installs the middleware, and everything that has to
|
|
9001
|
+
* follow from that (starting with {@link hasSendableData}) follows on its own.
|
|
9002
|
+
*
|
|
9003
|
+
* **Temporary API.** In v10 sending with pending uploads becomes part of the composer
|
|
9004
|
+
* configuration (`MessageComposerConfig`, set through `updateConfig`), and this getter,
|
|
9005
|
+
* together with the middleware declaration it reads, is replaced by that config field.
|
|
9006
|
+
*/
|
|
9007
|
+
get allowsPendingUploads() {
|
|
9008
|
+
return this.compositionMiddlewareExecutor.installedMiddleware.some(
|
|
9009
|
+
(middleware) => middleware.allowsPendingUploads
|
|
9010
|
+
);
|
|
9011
|
+
}
|
|
8716
9012
|
get hasSendableData() {
|
|
8717
|
-
|
|
9013
|
+
if (!this.isCommandSendable) return false;
|
|
9014
|
+
if (this.allowsPendingUploads) {
|
|
9015
|
+
const hasSendableAttachment = this.attachmentManager.attachments.some(
|
|
9016
|
+
(attachment) => isFinishedUpload(attachment) || isPendingUpload(attachment)
|
|
9017
|
+
);
|
|
9018
|
+
return !!(!this.textComposer.textIsEmpty || hasSendableAttachment || this.pollId || this.locationComposer.validLocation);
|
|
9019
|
+
}
|
|
9020
|
+
return !!(!this.attachmentManager.uploadsInProgressCount && (!this.textComposer.textIsEmpty || this.attachmentManager.successfulUploadsCount > 0) || this.pollId || !!this.locationComposer.validLocation);
|
|
8718
9021
|
}
|
|
8719
9022
|
get compositionIsEmpty() {
|
|
8720
9023
|
return !this.quotedMessage && this.contentIsEmpty;
|
|
@@ -9341,14 +9644,16 @@ var Channel = class {
|
|
|
9341
9644
|
*
|
|
9342
9645
|
* @return {Promise<SendMessageAPIResponse>} The Server Response
|
|
9343
9646
|
*/
|
|
9344
|
-
async _sendMessage(
|
|
9345
|
-
|
|
9346
|
-
|
|
9347
|
-
|
|
9348
|
-
|
|
9349
|
-
|
|
9350
|
-
|
|
9351
|
-
|
|
9647
|
+
async _sendMessage(rawMessage, options) {
|
|
9648
|
+
const client = this.getClient();
|
|
9649
|
+
const message = sanitizeOutgoingAttachments({
|
|
9650
|
+
client,
|
|
9651
|
+
message: rawMessage
|
|
9652
|
+
});
|
|
9653
|
+
return await client.post(this._channelURL() + "/message", {
|
|
9654
|
+
message,
|
|
9655
|
+
...options
|
|
9656
|
+
});
|
|
9352
9657
|
}
|
|
9353
9658
|
async sendMessage(message, options) {
|
|
9354
9659
|
try {
|
|
@@ -10799,6 +11104,7 @@ var Channel = class {
|
|
|
10799
11104
|
// delivery-report network sync below is skipped for it.
|
|
10800
11105
|
case "message.read_locally":
|
|
10801
11106
|
case "message.read":
|
|
11107
|
+
if (event.thread) break;
|
|
10802
11108
|
if (event.user?.id && event.created_at) {
|
|
10803
11109
|
const previousReadState = channelState.read[event.user.id];
|
|
10804
11110
|
channelState.read[event.user.id] = {
|
|
@@ -11248,7 +11554,7 @@ var ClientState = class {
|
|
|
11248
11554
|
var import_isomorphic_ws = __toESM(require("isomorphic-ws"));
|
|
11249
11555
|
|
|
11250
11556
|
// src/insights.ts
|
|
11251
|
-
var
|
|
11557
|
+
var import_axios2 = __toESM(require("axios"));
|
|
11252
11558
|
var InsightMetrics = class {
|
|
11253
11559
|
constructor() {
|
|
11254
11560
|
this.connectionStartTimestamp = null;
|
|
@@ -11261,7 +11567,7 @@ var postInsights = async (insightType, insights) => {
|
|
|
11261
11567
|
const maxAttempts = 3;
|
|
11262
11568
|
for (let i = 0; i < maxAttempts; i++) {
|
|
11263
11569
|
try {
|
|
11264
|
-
await
|
|
11570
|
+
await import_axios2.default.post(
|
|
11265
11571
|
`https://chat-insights.getstream.io/insights/${insightType}`,
|
|
11266
11572
|
insights
|
|
11267
11573
|
);
|
|
@@ -11769,131 +12075,6 @@ var StableWSConnection = class {
|
|
|
11769
12075
|
}
|
|
11770
12076
|
};
|
|
11771
12077
|
|
|
11772
|
-
// src/uploadManager.ts
|
|
11773
|
-
var initState7 = () => ({ uploads: {} });
|
|
11774
|
-
var upsertById = (uploads, record) => ({
|
|
11775
|
-
...uploads,
|
|
11776
|
-
[record.id]: { ...uploads[record.id], ...record }
|
|
11777
|
-
});
|
|
11778
|
-
var updateById = (uploads, record) => {
|
|
11779
|
-
if (!(record.id in uploads)) return null;
|
|
11780
|
-
const current = uploads[record.id];
|
|
11781
|
-
return { ...uploads, [record.id]: { ...current, ...record } };
|
|
11782
|
-
};
|
|
11783
|
-
var UploadManager = class {
|
|
11784
|
-
constructor(client) {
|
|
11785
|
-
this.client = client;
|
|
11786
|
-
this.inFlightUploads = /* @__PURE__ */ new Map();
|
|
11787
|
-
this.getUpload = (id) => this.uploads[id];
|
|
11788
|
-
/**
|
|
11789
|
-
* Clears all upload records.
|
|
11790
|
-
* Invoked when the user disconnects so a later session does not inherit stale upload state.
|
|
11791
|
-
* Aborts every in-flight upload request via its `UploadRequestOptions.abortSignal`.
|
|
11792
|
-
*/
|
|
11793
|
-
this.reset = () => {
|
|
11794
|
-
for (const { abortController } of this.inFlightUploads.values()) {
|
|
11795
|
-
abortController.abort();
|
|
11796
|
-
}
|
|
11797
|
-
this.inFlightUploads.clear();
|
|
11798
|
-
this.state.next(initState7());
|
|
11799
|
-
};
|
|
11800
|
-
/**
|
|
11801
|
-
* Removes the upload record for `id` if present.
|
|
11802
|
-
* If an upload is still in progress, aborts its `UploadRequestOptions.abortSignal`.
|
|
11803
|
-
*/
|
|
11804
|
-
this.deleteUploadRecord = (id) => {
|
|
11805
|
-
const flight = this.inFlightUploads.get(id);
|
|
11806
|
-
if (flight) {
|
|
11807
|
-
this.inFlightUploads.delete(id);
|
|
11808
|
-
flight.abortController.abort();
|
|
11809
|
-
}
|
|
11810
|
-
this.state.next((current) => {
|
|
11811
|
-
if (!(id in current.uploads)) return current;
|
|
11812
|
-
const uploads = { ...current.uploads };
|
|
11813
|
-
delete uploads[id];
|
|
11814
|
-
return { ...current, uploads };
|
|
11815
|
-
});
|
|
11816
|
-
};
|
|
11817
|
-
/**
|
|
11818
|
-
* Starts an upload for `id`, or returns the existing in-flight promise if one is already running.
|
|
11819
|
-
* Uses {@link StreamChat.channel}(`channelCid`) → `messageComposer.attachmentManager.doUploadRequest`.
|
|
11820
|
-
* Resolves with that result; rejects if the upload rejects (the record is removed from state either way).
|
|
11821
|
-
*/
|
|
11822
|
-
this.upload = ({
|
|
11823
|
-
id,
|
|
11824
|
-
channelCid,
|
|
11825
|
-
file
|
|
11826
|
-
}) => {
|
|
11827
|
-
const existing = this.inFlightUploads.get(id);
|
|
11828
|
-
if (existing) return existing.promise;
|
|
11829
|
-
let resolvePromise;
|
|
11830
|
-
let rejectPromise;
|
|
11831
|
-
const promise = new Promise((resolve, reject) => {
|
|
11832
|
-
resolvePromise = resolve;
|
|
11833
|
-
rejectPromise = reject;
|
|
11834
|
-
});
|
|
11835
|
-
const abortController = new AbortController();
|
|
11836
|
-
this.inFlightUploads.set(id, { promise, abortController });
|
|
11837
|
-
void (async () => {
|
|
11838
|
-
const attachmentManager = this.resolveAttachmentManager(channelCid);
|
|
11839
|
-
const trackProgress = attachmentManager.config.trackUploadProgress;
|
|
11840
|
-
try {
|
|
11841
|
-
this.upsertUpload({
|
|
11842
|
-
id,
|
|
11843
|
-
uploadProgress: trackProgress ? 0 : void 0
|
|
11844
|
-
});
|
|
11845
|
-
const onProgress = trackProgress ? (progress) => {
|
|
11846
|
-
this.updateUpload({
|
|
11847
|
-
id,
|
|
11848
|
-
uploadProgress: progress
|
|
11849
|
-
});
|
|
11850
|
-
} : void 0;
|
|
11851
|
-
const uploadRequestOptions = {
|
|
11852
|
-
abortSignal: abortController.signal,
|
|
11853
|
-
...onProgress ? { onProgress } : {}
|
|
11854
|
-
};
|
|
11855
|
-
const response = await attachmentManager.doUploadRequest(
|
|
11856
|
-
file,
|
|
11857
|
-
uploadRequestOptions
|
|
11858
|
-
);
|
|
11859
|
-
resolvePromise(response);
|
|
11860
|
-
} catch (error) {
|
|
11861
|
-
rejectPromise(error);
|
|
11862
|
-
} finally {
|
|
11863
|
-
this.inFlightUploads.delete(id);
|
|
11864
|
-
this.deleteUploadRecord(id);
|
|
11865
|
-
}
|
|
11866
|
-
})();
|
|
11867
|
-
return promise;
|
|
11868
|
-
};
|
|
11869
|
-
this.upsertUpload = (record) => {
|
|
11870
|
-
this.state.partialNext({
|
|
11871
|
-
uploads: upsertById(this.uploads, record)
|
|
11872
|
-
});
|
|
11873
|
-
};
|
|
11874
|
-
this.updateUpload = (record) => {
|
|
11875
|
-
this.state.next((current) => {
|
|
11876
|
-
const nextUploads = updateById(current.uploads, record);
|
|
11877
|
-
if (!nextUploads) return current;
|
|
11878
|
-
return { ...current, uploads: nextUploads };
|
|
11879
|
-
});
|
|
11880
|
-
};
|
|
11881
|
-
this.state = new StateStore(initState7());
|
|
11882
|
-
}
|
|
11883
|
-
resolveAttachmentManager(channelCid) {
|
|
11884
|
-
const colon = channelCid.indexOf(":");
|
|
11885
|
-
if (colon <= 0 || colon === channelCid.length - 1) {
|
|
11886
|
-
throw new Error(`Invalid channelCid: ${channelCid}`);
|
|
11887
|
-
}
|
|
11888
|
-
const channelType = channelCid.slice(0, colon);
|
|
11889
|
-
const channelId = channelCid.slice(colon + 1);
|
|
11890
|
-
return this.client.channel(channelType, channelId).messageComposer.attachmentManager;
|
|
11891
|
-
}
|
|
11892
|
-
get uploads() {
|
|
11893
|
-
return this.state.getLatestValue().uploads;
|
|
11894
|
-
}
|
|
11895
|
-
};
|
|
11896
|
-
|
|
11897
12078
|
// src/signing.ts
|
|
11898
12079
|
var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
|
|
11899
12080
|
var import_crypto = __toESM(require("crypto"));
|
|
@@ -12152,7 +12333,7 @@ var TokenManager = class {
|
|
|
12152
12333
|
};
|
|
12153
12334
|
|
|
12154
12335
|
// src/connection_fallback.ts
|
|
12155
|
-
var
|
|
12336
|
+
var import_axios3 = __toESM(require("axios"));
|
|
12156
12337
|
var WSConnectionFallback = class {
|
|
12157
12338
|
constructor({ client }) {
|
|
12158
12339
|
/** @private */
|
|
@@ -12171,7 +12352,7 @@ var WSConnectionFallback = class {
|
|
|
12171
12352
|
/** @private */
|
|
12172
12353
|
this._req = async (params, config, retry) => {
|
|
12173
12354
|
if (!this.cancelToken && !params.close) {
|
|
12174
|
-
this.cancelToken =
|
|
12355
|
+
this.cancelToken = import_axios3.default.CancelToken.source();
|
|
12175
12356
|
}
|
|
12176
12357
|
try {
|
|
12177
12358
|
const res = await this.client.doAxiosRequest(
|
|
@@ -12207,7 +12388,7 @@ var WSConnectionFallback = class {
|
|
|
12207
12388
|
}
|
|
12208
12389
|
}
|
|
12209
12390
|
} catch (error) {
|
|
12210
|
-
if (
|
|
12391
|
+
if (import_axios3.default.isCancel(error)) {
|
|
12211
12392
|
this._log(`_poll() - axios canceled request`);
|
|
12212
12393
|
return;
|
|
12213
12394
|
}
|
|
@@ -14630,7 +14811,7 @@ var StreamChat = class _StreamChat {
|
|
|
14630
14811
|
return this.handleResponse(response);
|
|
14631
14812
|
} catch (e) {
|
|
14632
14813
|
e.client_request_id = requestConfig.headers?.["x-client-request-id"];
|
|
14633
|
-
if (
|
|
14814
|
+
if (import_axios4.default.isCancel(e)) throw e;
|
|
14634
14815
|
this._logApiError(type, url, e);
|
|
14635
14816
|
this.consecutiveFailures += 1;
|
|
14636
14817
|
if (e.response) {
|
|
@@ -14942,7 +15123,7 @@ var StreamChat = class _StreamChat {
|
|
|
14942
15123
|
return this.userAgent;
|
|
14943
15124
|
}
|
|
14944
15125
|
if (!this.cachedUserAgent) {
|
|
14945
|
-
const version = "9.
|
|
15126
|
+
const version = "9.52.0";
|
|
14946
15127
|
const { name: sdkName, version: sdkVersion } = this.sdkIdentifier ?? {};
|
|
14947
15128
|
const { name: appName, version: appVersion } = this.appIdentifier ?? {};
|
|
14948
15129
|
const { os, model: deviceModel } = this.deviceIdentifier ?? {};
|
|
@@ -15010,7 +15191,7 @@ var StreamChat = class _StreamChat {
|
|
|
15010
15191
|
keepAliveMsecs: 3e3
|
|
15011
15192
|
});
|
|
15012
15193
|
}
|
|
15013
|
-
this.axiosInstance =
|
|
15194
|
+
this.axiosInstance = import_axios4.default.create(this.options);
|
|
15014
15195
|
this.setBaseURL(this.options.baseURL || "https://chat.stream-io-api.com");
|
|
15015
15196
|
if (typeof process !== "undefined" && "env" in process && process.env.STREAM_LOCAL_TEST_RUN) {
|
|
15016
15197
|
this.setBaseURL("http://localhost:3030");
|
|
@@ -16362,6 +16543,11 @@ var StreamChat = class _StreamChat {
|
|
|
16362
16543
|
}
|
|
16363
16544
|
/**
|
|
16364
16545
|
* unflagMessage - unflag a message
|
|
16546
|
+
*
|
|
16547
|
+
* @deprecated The `/moderation/unflag` endpoint is deprecated and is a no-op on
|
|
16548
|
+
* the backend - calling this resolves successfully but does not remove the flag.
|
|
16549
|
+
* Use `client.moderation.submitAction()` against the review queue item instead.
|
|
16550
|
+
*
|
|
16365
16551
|
* @param {string} targetMessageID
|
|
16366
16552
|
* @param {string} [options.user_id] currentUserID, only used with serverside auth
|
|
16367
16553
|
* @returns {Promise<APIResponse>}
|
|
@@ -16374,6 +16560,11 @@ var StreamChat = class _StreamChat {
|
|
|
16374
16560
|
}
|
|
16375
16561
|
/**
|
|
16376
16562
|
* unflagUser - unflag a user
|
|
16563
|
+
*
|
|
16564
|
+
* @deprecated The `/moderation/unflag` endpoint is deprecated and is a no-op on
|
|
16565
|
+
* the backend - calling this resolves successfully but does not remove the flag.
|
|
16566
|
+
* Use `client.moderation.submitAction()` against the review queue item instead.
|
|
16567
|
+
*
|
|
16377
16568
|
* @param {string} targetID
|
|
16378
16569
|
* @param {string} [options.user_id] currentUserID, only used with serverside auth
|
|
16379
16570
|
* @returns {Promise<APIResponse>}
|
|
@@ -16658,7 +16849,10 @@ var StreamChat = class _StreamChat {
|
|
|
16658
16849
|
if (!message.id) {
|
|
16659
16850
|
throw Error("Please specify the message.id when calling updateMessage");
|
|
16660
16851
|
}
|
|
16661
|
-
const payload =
|
|
16852
|
+
const payload = sanitizeOutgoingAttachments({
|
|
16853
|
+
client: this,
|
|
16854
|
+
message: toUpdatedMessagePayload(message)
|
|
16855
|
+
});
|
|
16662
16856
|
if (typeof partialUserOrUserId === "string") {
|
|
16663
16857
|
payload.user_id = partialUserOrUserId;
|
|
16664
16858
|
} else if (typeof partialUserOrUserId?.id === "string") {
|
|
@@ -18474,7 +18668,7 @@ var OfflineError = class extends Error {
|
|
|
18474
18668
|
};
|
|
18475
18669
|
|
|
18476
18670
|
// src/offline-support/offline_sync_manager.ts
|
|
18477
|
-
var
|
|
18671
|
+
var import_axios5 = require("axios");
|
|
18478
18672
|
var OfflineDBSyncManager = class {
|
|
18479
18673
|
constructor({
|
|
18480
18674
|
client,
|
|
@@ -18622,7 +18816,7 @@ var OfflineDBSyncManager = class {
|
|
|
18622
18816
|
});
|
|
18623
18817
|
} catch (e) {
|
|
18624
18818
|
console.log("An error has occurred while syncing the DB.", e);
|
|
18625
|
-
if ((0,
|
|
18819
|
+
if ((0, import_axios5.isAxiosError)(e) && e.code === "ECONNABORTED") {
|
|
18626
18820
|
return;
|
|
18627
18821
|
}
|
|
18628
18822
|
const error = e;
|
|
@@ -19131,6 +19325,7 @@ var AbstractOfflineDB = class {
|
|
|
19131
19325
|
return this.handleMessageUpdatedEvent({ event, execute });
|
|
19132
19326
|
}
|
|
19133
19327
|
if (type === "message.read" || type === "notification.mark_read") {
|
|
19328
|
+
if (event.thread) return [];
|
|
19134
19329
|
return this.handleRead({ event, unreadMessages: 0, execute });
|
|
19135
19330
|
}
|
|
19136
19331
|
if (type === "message.read_locally") {
|
|
@@ -19698,6 +19893,7 @@ var LiveLocationManager = _LiveLocationManager;
|
|
|
19698
19893
|
createMessageComposerStateCompositionMiddleware,
|
|
19699
19894
|
createPollComposerStateMiddleware,
|
|
19700
19895
|
createPostUploadAttachmentEnrichmentMiddleware,
|
|
19896
|
+
createSendWithPendingUploadsAttachmentsMiddleware,
|
|
19701
19897
|
createSharedLocationCompositionMiddleware,
|
|
19702
19898
|
createTextComposerCompositionMiddleware,
|
|
19703
19899
|
createTextComposerPreValidationMiddleware,
|
|
@@ -19726,6 +19922,7 @@ var LiveLocationManager = _LiveLocationManager;
|
|
|
19726
19922
|
getTokenizedSuggestionDisplayName,
|
|
19727
19923
|
getTriggerCharWithToken,
|
|
19728
19924
|
gunzipPayload,
|
|
19925
|
+
hasPending,
|
|
19729
19926
|
insertItemWithTrigger,
|
|
19730
19927
|
isAudioAttachment,
|
|
19731
19928
|
isBlobButNotFile,
|
|
@@ -19733,6 +19930,7 @@ var LiveLocationManager = _LiveLocationManager;
|
|
|
19733
19930
|
isFileAttachment,
|
|
19734
19931
|
isFileList,
|
|
19735
19932
|
isFileReference,
|
|
19933
|
+
isFinishedUpload,
|
|
19736
19934
|
isGiphyAttachment,
|
|
19737
19935
|
isImageAttachment,
|
|
19738
19936
|
isImageFile,
|
|
@@ -19745,9 +19943,11 @@ var LiveLocationManager = _LiveLocationManager;
|
|
|
19745
19943
|
isLocalVoiceRecordingAttachment,
|
|
19746
19944
|
isOwnUser,
|
|
19747
19945
|
isPatch,
|
|
19946
|
+
isPendingUpload,
|
|
19748
19947
|
isScrapedContent,
|
|
19749
19948
|
isSharedLocationResponse,
|
|
19750
19949
|
isTargetedOptionTextUpdate,
|
|
19950
|
+
isUploadCancellation,
|
|
19751
19951
|
isUploadedAttachment,
|
|
19752
19952
|
isVideoAttachment,
|
|
19753
19953
|
isVoiceRecordingAttachment,
|
|
@@ -19767,11 +19967,14 @@ var LiveLocationManager = _LiveLocationManager;
|
|
|
19767
19967
|
readFileAsArrayBuffer,
|
|
19768
19968
|
removeDiacritics,
|
|
19769
19969
|
replaceWordWithEntity,
|
|
19970
|
+
settled,
|
|
19770
19971
|
stripCommandFromText,
|
|
19771
19972
|
stripMentionTokens,
|
|
19772
19973
|
textIsEmpty,
|
|
19773
19974
|
timeLeftMs,
|
|
19774
19975
|
verifyAndParseWebhook,
|
|
19775
|
-
verifySignature
|
|
19976
|
+
verifySignature,
|
|
19977
|
+
withCancellation,
|
|
19978
|
+
withoutConcurrency
|
|
19776
19979
|
});
|
|
19777
19980
|
//# sourceMappingURL=index.node.js.map
|