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/esm/index.mjs
CHANGED
|
@@ -316,7 +316,7 @@ var ChannelBatchUpdater = class {
|
|
|
316
316
|
|
|
317
317
|
// src/client.ts
|
|
318
318
|
var import_https = __toESM(require_https());
|
|
319
|
-
import
|
|
319
|
+
import axios4 from "axios";
|
|
320
320
|
|
|
321
321
|
// src/utils.ts
|
|
322
322
|
import FormData from "form-data";
|
|
@@ -575,6 +575,38 @@ function unformatMessage(message) {
|
|
|
575
575
|
quoted_message: toMessageResponseBase(message.quoted_message)
|
|
576
576
|
};
|
|
577
577
|
}
|
|
578
|
+
var isRemoteUrl = (url) => !!url && /^https?:\/\//i.test(url.trim());
|
|
579
|
+
var sanitizeOutgoingAttachments = ({
|
|
580
|
+
client,
|
|
581
|
+
message
|
|
582
|
+
}) => {
|
|
583
|
+
const attachments = message.attachments;
|
|
584
|
+
if (!attachments?.length) return message;
|
|
585
|
+
const unresolved = [];
|
|
586
|
+
let changed = false;
|
|
587
|
+
const sanitized = attachments.reduce((acc, attachment) => {
|
|
588
|
+
const { localMetadata, ...rest } = attachment;
|
|
589
|
+
if (!localMetadata) {
|
|
590
|
+
acc.push(attachment);
|
|
591
|
+
return acc;
|
|
592
|
+
}
|
|
593
|
+
changed = true;
|
|
594
|
+
const hasRemoteSource = isRemoteUrl(rest.asset_url) || isRemoteUrl(rest.image_url) || isRemoteUrl(rest.og_scrape_url) || isRemoteUrl(rest.title_link);
|
|
595
|
+
if (hasRemoteSource) {
|
|
596
|
+
acc.push(rest);
|
|
597
|
+
} else {
|
|
598
|
+
unresolved.push(rest);
|
|
599
|
+
}
|
|
600
|
+
return acc;
|
|
601
|
+
}, []);
|
|
602
|
+
if (unresolved.length) {
|
|
603
|
+
const text = `Dropped ${unresolved.length} attachment(s) whose upload never completed. Composing with pending uploads requires awaiting them before sending.`;
|
|
604
|
+
const extraData = { attachments: unresolved, message, tags: ["attachments"] };
|
|
605
|
+
client.logger("warn", text, extraData);
|
|
606
|
+
console.warn(text, extraData);
|
|
607
|
+
}
|
|
608
|
+
return changed ? { ...message, attachments: sanitized } : message;
|
|
609
|
+
};
|
|
578
610
|
var localMessageToNewMessagePayload = (localMessage) => {
|
|
579
611
|
const {
|
|
580
612
|
// Remove all timestamp fields and client-specific fields.
|
|
@@ -2347,6 +2379,12 @@ var CooldownTimer = class extends WithSubscriptions {
|
|
|
2347
2379
|
var isScrapedContent = (attachment) => !!attachment?.og_scrape_url || !!attachment?.title_link;
|
|
2348
2380
|
var isLocalAttachment = (attachment) => !!attachment?.localMetadata?.id;
|
|
2349
2381
|
var isLocalUploadAttachment = (attachment) => !!attachment?.localMetadata?.uploadState;
|
|
2382
|
+
var PENDING_UPLOAD_STATES = [
|
|
2383
|
+
"pending",
|
|
2384
|
+
"uploading"
|
|
2385
|
+
];
|
|
2386
|
+
var isPendingUpload = (attachment) => isLocalUploadAttachment(attachment) && PENDING_UPLOAD_STATES.includes(attachment.localMetadata.uploadState);
|
|
2387
|
+
var isFinishedUpload = (attachment) => isLocalUploadAttachment(attachment) && attachment.localMetadata.uploadState === "finished";
|
|
2350
2388
|
var isFileAttachment = (attachment, supportedVideoFormat = []) => attachment.type === "file" || !!(attachment.mime_type && supportedVideoFormat.indexOf(attachment.mime_type) === -1 && attachment.type !== "video");
|
|
2351
2389
|
var isLocalFileAttachment = (attachment) => isFileAttachment(attachment) && isLocalAttachment(attachment);
|
|
2352
2390
|
var isImageAttachment = (attachment) => attachment.type === "image" && !isScrapedContent(attachment);
|
|
@@ -2422,7 +2460,7 @@ var ensureIsLocalAttachment = (attachment) => {
|
|
|
2422
2460
|
};
|
|
2423
2461
|
|
|
2424
2462
|
// src/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.ts
|
|
2425
|
-
var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
2463
|
+
var createPostUploadAttachmentEnrichmentMiddleware = (composer) => ({
|
|
2426
2464
|
id: "stream-io/attachment-manager-middleware/post-upload-enrichment",
|
|
2427
2465
|
handlers: {
|
|
2428
2466
|
postProcess: ({
|
|
@@ -2435,9 +2473,10 @@ var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
|
2435
2473
|
if (error) return forward();
|
|
2436
2474
|
if (!attachment || !response) return discard();
|
|
2437
2475
|
const enrichedAttachment = { ...attachment };
|
|
2438
|
-
const previewUri = attachment.localMetadata
|
|
2439
|
-
|
|
2440
|
-
|
|
2476
|
+
const { id, previewUri } = attachment.localMetadata;
|
|
2477
|
+
const attachmentIsStillInComposer = !composer || !!composer.attachmentManager.attachmentsById[id];
|
|
2478
|
+
if (previewUri && attachmentIsStillInComposer) {
|
|
2479
|
+
if (previewUri.startsWith("blob:")) URL.revokeObjectURL?.(previewUri);
|
|
2441
2480
|
delete enrichedAttachment.localMetadata.previewUri;
|
|
2442
2481
|
}
|
|
2443
2482
|
if (isLocalImageAttachment(attachment)) {
|
|
@@ -2460,6 +2499,12 @@ var createPostUploadAttachmentEnrichmentMiddleware = () => ({
|
|
|
2460
2499
|
var withoutConcurrency = createRunner(wrapWithContinuationTracking);
|
|
2461
2500
|
var withCancellation = createRunner(wrapWithCancellation);
|
|
2462
2501
|
var pendingPromises = /* @__PURE__ */ new Map();
|
|
2502
|
+
function hasPending(tag) {
|
|
2503
|
+
return pendingPromises.has(tag);
|
|
2504
|
+
}
|
|
2505
|
+
async function settled(tag) {
|
|
2506
|
+
await pendingPromises.get(tag)?.promise;
|
|
2507
|
+
}
|
|
2463
2508
|
function createRunner(wrapper) {
|
|
2464
2509
|
return function run(tag, cb) {
|
|
2465
2510
|
const { cb: wrapped, onContinued } = wrapper(tag, cb);
|
|
@@ -2502,6 +2547,16 @@ var MiddlewareExecutor = class {
|
|
|
2502
2547
|
this.middleware = [];
|
|
2503
2548
|
this.id = generateUUIDv4();
|
|
2504
2549
|
}
|
|
2550
|
+
/**
|
|
2551
|
+
* The middleware currently installed, in execution order.
|
|
2552
|
+
*
|
|
2553
|
+
* Read-only: use `use` / `insert` / `replace` / `setOrder` / `remove` to change the chain. It
|
|
2554
|
+
* exists so components can ask what the chain is capable of - a middleware may declare
|
|
2555
|
+
* behaviour its host has to account for, and the host has no other way to find out.
|
|
2556
|
+
*/
|
|
2557
|
+
get installedMiddleware() {
|
|
2558
|
+
return this.middleware;
|
|
2559
|
+
}
|
|
2505
2560
|
use(middleware) {
|
|
2506
2561
|
this.middleware = this.middleware.concat(middleware);
|
|
2507
2562
|
return this;
|
|
@@ -2605,6 +2660,142 @@ var MiddlewareExecutor = class {
|
|
|
2605
2660
|
}
|
|
2606
2661
|
};
|
|
2607
2662
|
|
|
2663
|
+
// src/uploadManager.ts
|
|
2664
|
+
import axios from "axios";
|
|
2665
|
+
var isUploadCancellation = (error) => axios.isCancel(error) || error instanceof Error && error.name === "AbortError";
|
|
2666
|
+
var initState = () => ({ uploads: {} });
|
|
2667
|
+
var upsertById = (uploads, record) => ({
|
|
2668
|
+
...uploads,
|
|
2669
|
+
[record.id]: { ...uploads[record.id], ...record }
|
|
2670
|
+
});
|
|
2671
|
+
var updateById = (uploads, record) => {
|
|
2672
|
+
if (!(record.id in uploads)) return null;
|
|
2673
|
+
const current = uploads[record.id];
|
|
2674
|
+
return { ...uploads, [record.id]: { ...current, ...record } };
|
|
2675
|
+
};
|
|
2676
|
+
var UploadManager = class {
|
|
2677
|
+
constructor(client) {
|
|
2678
|
+
this.client = client;
|
|
2679
|
+
this.inFlightUploads = /* @__PURE__ */ new Map();
|
|
2680
|
+
this.getUpload = (id) => this.uploads[id];
|
|
2681
|
+
/**
|
|
2682
|
+
* Clears all upload records.
|
|
2683
|
+
* Invoked when the user disconnects so a later session does not inherit stale upload state.
|
|
2684
|
+
* Aborts every in-flight upload request via its `UploadRequestOptions.abortSignal`.
|
|
2685
|
+
*/
|
|
2686
|
+
this.reset = () => {
|
|
2687
|
+
for (const { abortController } of this.inFlightUploads.values()) {
|
|
2688
|
+
abortController.abort();
|
|
2689
|
+
}
|
|
2690
|
+
this.inFlightUploads.clear();
|
|
2691
|
+
this.state.next(initState());
|
|
2692
|
+
};
|
|
2693
|
+
/**
|
|
2694
|
+
* Removes the upload record for `id` if present.
|
|
2695
|
+
* If an upload is still in progress, aborts its `UploadRequestOptions.abortSignal`.
|
|
2696
|
+
*/
|
|
2697
|
+
this.deleteUploadRecord = (id) => {
|
|
2698
|
+
const flight = this.inFlightUploads.get(id);
|
|
2699
|
+
if (flight) {
|
|
2700
|
+
this.inFlightUploads.delete(id);
|
|
2701
|
+
flight.abortController.abort();
|
|
2702
|
+
}
|
|
2703
|
+
this.state.next((current) => {
|
|
2704
|
+
if (!(id in current.uploads)) return current;
|
|
2705
|
+
const uploads = { ...current.uploads };
|
|
2706
|
+
delete uploads[id];
|
|
2707
|
+
return { ...current, uploads };
|
|
2708
|
+
});
|
|
2709
|
+
};
|
|
2710
|
+
/**
|
|
2711
|
+
* Starts an upload for `id`, or returns the existing in-flight promise if one is already running.
|
|
2712
|
+
* Uses {@link StreamChat.channel}(`channelCid`) → `messageComposer.attachmentManager.doUploadRequest`.
|
|
2713
|
+
* Resolves with that result; rejects if the upload rejects (the record is removed from state either way).
|
|
2714
|
+
*/
|
|
2715
|
+
this.upload = ({
|
|
2716
|
+
id,
|
|
2717
|
+
channelCid,
|
|
2718
|
+
file
|
|
2719
|
+
}) => {
|
|
2720
|
+
const existing = this.inFlightUploads.get(id);
|
|
2721
|
+
if (existing) return existing.promise;
|
|
2722
|
+
let resolvePromise;
|
|
2723
|
+
let rejectPromise;
|
|
2724
|
+
const promise = new Promise((resolve, reject) => {
|
|
2725
|
+
resolvePromise = resolve;
|
|
2726
|
+
rejectPromise = reject;
|
|
2727
|
+
});
|
|
2728
|
+
const abortController = new AbortController();
|
|
2729
|
+
this.inFlightUploads.set(id, { promise, abortController });
|
|
2730
|
+
void (async () => {
|
|
2731
|
+
const attachmentManager = this.resolveAttachmentManager(channelCid);
|
|
2732
|
+
const trackProgress = attachmentManager.config.trackUploadProgress;
|
|
2733
|
+
try {
|
|
2734
|
+
this.upsertUpload({
|
|
2735
|
+
uploadConfirmationPending: false,
|
|
2736
|
+
id,
|
|
2737
|
+
uploadProgress: trackProgress ? 0 : void 0
|
|
2738
|
+
});
|
|
2739
|
+
const onProgress = trackProgress ? (progress) => {
|
|
2740
|
+
this.updateUpload({
|
|
2741
|
+
id,
|
|
2742
|
+
uploadProgress: progress,
|
|
2743
|
+
// Only a number says anything about the flush, so a report without one leaves
|
|
2744
|
+
// the flag alone: `undefined` means the transport cannot measure this upload,
|
|
2745
|
+
// not that bytes were un-sent. Lowering it there would drop a UI that had
|
|
2746
|
+
// already gone indeterminate back to a determinate one with nothing to show.
|
|
2747
|
+
//
|
|
2748
|
+
// The record is removed in the `finally` below, so a record that still exists
|
|
2749
|
+
// while reporting 100% can only mean "flushed, awaiting the response".
|
|
2750
|
+
...typeof progress === "number" ? { uploadConfirmationPending: progress >= 100 } : {}
|
|
2751
|
+
});
|
|
2752
|
+
} : void 0;
|
|
2753
|
+
const uploadRequestOptions = {
|
|
2754
|
+
abortSignal: abortController.signal,
|
|
2755
|
+
...onProgress ? { onProgress } : {}
|
|
2756
|
+
};
|
|
2757
|
+
const response = await attachmentManager.doUploadRequest(
|
|
2758
|
+
file,
|
|
2759
|
+
uploadRequestOptions
|
|
2760
|
+
);
|
|
2761
|
+
resolvePromise(response);
|
|
2762
|
+
} catch (error) {
|
|
2763
|
+
rejectPromise(error);
|
|
2764
|
+
} finally {
|
|
2765
|
+
this.inFlightUploads.delete(id);
|
|
2766
|
+
this.deleteUploadRecord(id);
|
|
2767
|
+
}
|
|
2768
|
+
})();
|
|
2769
|
+
return promise;
|
|
2770
|
+
};
|
|
2771
|
+
this.upsertUpload = (record) => {
|
|
2772
|
+
this.state.partialNext({
|
|
2773
|
+
uploads: upsertById(this.uploads, record)
|
|
2774
|
+
});
|
|
2775
|
+
};
|
|
2776
|
+
this.updateUpload = (record) => {
|
|
2777
|
+
this.state.next((current) => {
|
|
2778
|
+
const nextUploads = updateById(current.uploads, record);
|
|
2779
|
+
if (!nextUploads) return current;
|
|
2780
|
+
return { ...current, uploads: nextUploads };
|
|
2781
|
+
});
|
|
2782
|
+
};
|
|
2783
|
+
this.state = new StateStore(initState());
|
|
2784
|
+
}
|
|
2785
|
+
resolveAttachmentManager(channelCid) {
|
|
2786
|
+
const colon = channelCid.indexOf(":");
|
|
2787
|
+
if (colon <= 0 || colon === channelCid.length - 1) {
|
|
2788
|
+
throw new Error(`Invalid channelCid: ${channelCid}`);
|
|
2789
|
+
}
|
|
2790
|
+
const channelType = channelCid.slice(0, colon);
|
|
2791
|
+
const channelId = channelCid.slice(colon + 1);
|
|
2792
|
+
return this.client.channel(channelType, channelId).messageComposer.attachmentManager;
|
|
2793
|
+
}
|
|
2794
|
+
get uploads() {
|
|
2795
|
+
return this.state.getLatestValue().uploads;
|
|
2796
|
+
}
|
|
2797
|
+
};
|
|
2798
|
+
|
|
2608
2799
|
// src/messageComposer/middleware/attachmentManager/postUpload/uploadErrorHandler.ts
|
|
2609
2800
|
var createUploadErrorHandlerMiddleware = (composer) => ({
|
|
2610
2801
|
id: "stream-io/attachment-manager-middleware/upload-error",
|
|
@@ -2617,6 +2808,7 @@ var createUploadErrorHandlerMiddleware = (composer) => ({
|
|
|
2617
2808
|
const { attachment, error } = state;
|
|
2618
2809
|
if (!error) return forward();
|
|
2619
2810
|
if (!attachment) return discard();
|
|
2811
|
+
if (isUploadCancellation(error)) return forward();
|
|
2620
2812
|
const reason = error instanceof Error ? error.message : "unknown error";
|
|
2621
2813
|
composer.client.notifications.addError({
|
|
2622
2814
|
message: "Error uploading attachment",
|
|
@@ -2641,7 +2833,7 @@ var AttachmentPostUploadMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
|
2641
2833
|
super();
|
|
2642
2834
|
this.use([
|
|
2643
2835
|
createUploadErrorHandlerMiddleware(composer),
|
|
2644
|
-
createPostUploadAttachmentEnrichmentMiddleware()
|
|
2836
|
+
createPostUploadAttachmentEnrichmentMiddleware(composer)
|
|
2645
2837
|
]);
|
|
2646
2838
|
}
|
|
2647
2839
|
};
|
|
@@ -3089,7 +3281,7 @@ function mergeWithDiff(target, source, customizer) {
|
|
|
3089
3281
|
}
|
|
3090
3282
|
|
|
3091
3283
|
// src/messageComposer/attachmentManager.ts
|
|
3092
|
-
var
|
|
3284
|
+
var initState2 = ({
|
|
3093
3285
|
message
|
|
3094
3286
|
}) => ({
|
|
3095
3287
|
attachments: (message?.attachments ?? [])?.filter(({ og_scrape_url }) => !og_scrape_url).map((att) => {
|
|
@@ -3117,13 +3309,14 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3117
3309
|
...attachment,
|
|
3118
3310
|
localMetadata: {
|
|
3119
3311
|
...attachment.localMetadata,
|
|
3312
|
+
uploadConfirmationPending: false,
|
|
3120
3313
|
uploadProgress: void 0,
|
|
3121
3314
|
uploadState: "failed"
|
|
3122
3315
|
}
|
|
3123
3316
|
};
|
|
3124
3317
|
};
|
|
3125
3318
|
this.initState = ({ message } = {}) => {
|
|
3126
|
-
this.state.next(
|
|
3319
|
+
this.state.next(initState2({ message }));
|
|
3127
3320
|
};
|
|
3128
3321
|
this.getSnapshot = () => {
|
|
3129
3322
|
const state = this.state.getLatestValue();
|
|
@@ -3200,8 +3393,22 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3200
3393
|
this.state.partialNext({ attachments });
|
|
3201
3394
|
}
|
|
3202
3395
|
};
|
|
3396
|
+
/**
|
|
3397
|
+
* Releases a local preview URL the SDK minted, if it minted one.
|
|
3398
|
+
*
|
|
3399
|
+
* Only `blob:` URLs are ours to revoke: `toLocalUploadAttachment` puts a
|
|
3400
|
+
* `URL.createObjectURL` result in `previewUri` for a `File`, but for a React Native
|
|
3401
|
+
* `FileReference` it stores the caller's own native file URI, which must be left alone.
|
|
3402
|
+
*/
|
|
3403
|
+
this.revokePreviewUri = (attachment) => {
|
|
3404
|
+
const previewUri = attachment.localMetadata?.previewUri;
|
|
3405
|
+
if (previewUri?.startsWith("blob:")) URL.revokeObjectURL?.(previewUri);
|
|
3406
|
+
};
|
|
3203
3407
|
this.removeAttachments = (localAttachmentIds) => {
|
|
3204
3408
|
if (!localAttachmentIds.length) return;
|
|
3409
|
+
const removedAttachments = this.attachments.filter(
|
|
3410
|
+
(attachment) => localAttachmentIds.includes(attachment.localMetadata?.id)
|
|
3411
|
+
);
|
|
3205
3412
|
this.state.partialNext({
|
|
3206
3413
|
attachments: this.attachments.filter(
|
|
3207
3414
|
(attachment) => !localAttachmentIds.includes(attachment.localMetadata?.id)
|
|
@@ -3210,6 +3417,7 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3210
3417
|
for (const id of localAttachmentIds) {
|
|
3211
3418
|
this.client.uploadManager.deleteUploadRecord(id);
|
|
3212
3419
|
}
|
|
3420
|
+
removedAttachments.forEach(this.revokePreviewUri);
|
|
3213
3421
|
};
|
|
3214
3422
|
this.getUploadConfigCheck = async (fileLike) => {
|
|
3215
3423
|
const client = this.channel.getClient();
|
|
@@ -3361,21 +3569,27 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3361
3569
|
localMetadata: {
|
|
3362
3570
|
...attachment.localMetadata,
|
|
3363
3571
|
uploadState: "failed",
|
|
3364
|
-
uploadProgress: void 0
|
|
3572
|
+
uploadProgress: void 0,
|
|
3573
|
+
// `false`, not `undefined`: these updates go through `updateAttachment`, which merges
|
|
3574
|
+
// via `mergeWith` — and that skips `undefined` source values, so `undefined` would
|
|
3575
|
+
// leave a stale `true` in place.
|
|
3576
|
+
uploadConfirmationPending: false
|
|
3365
3577
|
}
|
|
3366
3578
|
};
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3579
|
+
if (!isUploadCancellation(error)) {
|
|
3580
|
+
this.client.notifications.addError({
|
|
3581
|
+
message: "Error uploading attachment",
|
|
3582
|
+
origin: {
|
|
3583
|
+
emitter: "AttachmentManager",
|
|
3584
|
+
context: { attachment, failedAttachment }
|
|
3585
|
+
},
|
|
3586
|
+
options: {
|
|
3587
|
+
type: "api:attachment:upload:failed",
|
|
3588
|
+
metadata: { reason },
|
|
3589
|
+
originalError: error instanceof Error ? error : void 0
|
|
3590
|
+
}
|
|
3591
|
+
});
|
|
3592
|
+
}
|
|
3379
3593
|
this.updateAttachment(failedAttachment);
|
|
3380
3594
|
return failedAttachment;
|
|
3381
3595
|
}
|
|
@@ -3388,7 +3602,9 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3388
3602
|
localMetadata: {
|
|
3389
3603
|
...attachment.localMetadata,
|
|
3390
3604
|
uploadState: "finished",
|
|
3391
|
-
uploadProgress: void 0
|
|
3605
|
+
uploadProgress: void 0,
|
|
3606
|
+
// See the note in the failure branch: `undefined` cannot clear through `mergeWith`.
|
|
3607
|
+
uploadConfirmationPending: false
|
|
3392
3608
|
}
|
|
3393
3609
|
};
|
|
3394
3610
|
const previewUri = uploadedAttachment.localMetadata.previewUri;
|
|
@@ -3437,7 +3653,9 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3437
3653
|
localMetadata: {
|
|
3438
3654
|
...attachment.localMetadata,
|
|
3439
3655
|
uploadState: error ? "failed" : "finished",
|
|
3440
|
-
uploadProgress: void 0
|
|
3656
|
+
uploadProgress: void 0,
|
|
3657
|
+
// See the note in `uploadAttachment`: `undefined` cannot clear through `mergeWith`.
|
|
3658
|
+
uploadConfirmationPending: false
|
|
3441
3659
|
}
|
|
3442
3660
|
},
|
|
3443
3661
|
error,
|
|
@@ -3462,7 +3680,7 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3462
3680
|
);
|
|
3463
3681
|
};
|
|
3464
3682
|
this.composer = composer;
|
|
3465
|
-
this.state = new StateStore(
|
|
3683
|
+
this.state = new StateStore(initState2({ message }));
|
|
3466
3684
|
this.attachmentsByIdGetterCache = { attachmentsById: {}, attachments: [] };
|
|
3467
3685
|
this.preUploadMiddlewareExecutor = new AttachmentPreUploadMiddlewareExecutor({
|
|
3468
3686
|
composer
|
|
@@ -3567,7 +3785,8 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3567
3785
|
localMetadata: {
|
|
3568
3786
|
...attachment.localMetadata,
|
|
3569
3787
|
uploadState: "uploading",
|
|
3570
|
-
uploadProgress: this.config.trackUploadProgress ? 0 : void 0
|
|
3788
|
+
uploadProgress: this.config.trackUploadProgress ? 0 : void 0,
|
|
3789
|
+
uploadConfirmationPending: false
|
|
3571
3790
|
}
|
|
3572
3791
|
}
|
|
3573
3792
|
]);
|
|
@@ -3580,7 +3799,8 @@ var _AttachmentManager = class _AttachmentManager {
|
|
|
3580
3799
|
localMetadata: {
|
|
3581
3800
|
...attachment.localMetadata,
|
|
3582
3801
|
uploadState: "uploading",
|
|
3583
|
-
uploadProgress: nextUpload.uploadProgress
|
|
3802
|
+
uploadProgress: nextUpload.uploadProgress,
|
|
3803
|
+
uploadConfirmationPending: nextUpload.uploadConfirmationPending
|
|
3584
3804
|
}
|
|
3585
3805
|
});
|
|
3586
3806
|
}
|
|
@@ -3634,6 +3854,50 @@ var localAttachmentToAttachment = (localAttachment) => {
|
|
|
3634
3854
|
const { localMetadata, ...attachment } = localAttachment;
|
|
3635
3855
|
return attachment;
|
|
3636
3856
|
};
|
|
3857
|
+
var composeWithPendingUploads = ({
|
|
3858
|
+
composer,
|
|
3859
|
+
state
|
|
3860
|
+
}) => {
|
|
3861
|
+
const composerIsKeptAsDraft = !!composer.pollId;
|
|
3862
|
+
const relevantAttachments = composer.attachmentManager.attachments.filter(
|
|
3863
|
+
(attachment) => isFinishedUpload(attachment) || !composerIsKeptAsDraft && isPendingUpload(attachment)
|
|
3864
|
+
);
|
|
3865
|
+
const localAttachments = (state.localMessage.attachments ?? []).concat(
|
|
3866
|
+
relevantAttachments.map(
|
|
3867
|
+
(attachment) => isPendingUpload(attachment) ? attachment : localAttachmentToAttachment(attachment)
|
|
3868
|
+
)
|
|
3869
|
+
);
|
|
3870
|
+
const messageAttachments = (state.message.attachments ?? []).concat(
|
|
3871
|
+
relevantAttachments.filter(isFinishedUpload).map(localAttachmentToAttachment)
|
|
3872
|
+
);
|
|
3873
|
+
if (!localAttachments.length && !messageAttachments.length) return state;
|
|
3874
|
+
return {
|
|
3875
|
+
...state,
|
|
3876
|
+
localMessage: localAttachments.length ? {
|
|
3877
|
+
...state.localMessage,
|
|
3878
|
+
attachments: localAttachments
|
|
3879
|
+
} : state.localMessage,
|
|
3880
|
+
message: messageAttachments.length ? {
|
|
3881
|
+
...state.message,
|
|
3882
|
+
attachments: messageAttachments
|
|
3883
|
+
} : state.message
|
|
3884
|
+
};
|
|
3885
|
+
};
|
|
3886
|
+
var createSendWithPendingUploadsAttachmentsMiddleware = (composer) => ({
|
|
3887
|
+
allowsPendingUploads: true,
|
|
3888
|
+
id: "stream-io/message-composer-middleware/attachments",
|
|
3889
|
+
handlers: {
|
|
3890
|
+
compose: ({
|
|
3891
|
+
state,
|
|
3892
|
+
next,
|
|
3893
|
+
forward
|
|
3894
|
+
}) => {
|
|
3895
|
+
const { attachmentManager } = composer;
|
|
3896
|
+
if (!attachmentManager) return forward();
|
|
3897
|
+
return next(composeWithPendingUploads({ composer, state }));
|
|
3898
|
+
}
|
|
3899
|
+
}
|
|
3900
|
+
});
|
|
3637
3901
|
var createAttachmentsCompositionMiddleware = (composer) => ({
|
|
3638
3902
|
id: "stream-io/message-composer-middleware/attachments",
|
|
3639
3903
|
handlers: {
|
|
@@ -3850,7 +4114,7 @@ var getInitialMentions = (message) => {
|
|
|
3850
4114
|
};
|
|
3851
4115
|
var isSameMentionEntity = (first, second) => first.id === second.id && first.mentionType === second.mentionType;
|
|
3852
4116
|
var getMentionsFromState = (state) => state.mentions ?? state.mentionedUsers.map(userResponseToMentionEntity);
|
|
3853
|
-
var
|
|
4117
|
+
var initState3 = ({
|
|
3854
4118
|
composer,
|
|
3855
4119
|
message
|
|
3856
4120
|
}) => {
|
|
@@ -3879,7 +4143,7 @@ var initState2 = ({
|
|
|
3879
4143
|
var TextComposer = class {
|
|
3880
4144
|
constructor({ composer, message }) {
|
|
3881
4145
|
this.initState = ({ message } = {}) => {
|
|
3882
|
-
this.state.next(
|
|
4146
|
+
this.state.next(initState3({ composer: this.composer, message }));
|
|
3883
4147
|
};
|
|
3884
4148
|
this.getSnapshot = (state = this.state.getLatestValue()) => state;
|
|
3885
4149
|
this.restoreSnapshot = (snapshot) => {
|
|
@@ -4072,7 +4336,7 @@ var TextComposer = class {
|
|
|
4072
4336
|
this.commitState(output.state);
|
|
4073
4337
|
};
|
|
4074
4338
|
this.composer = composer;
|
|
4075
|
-
this.state = new StateStore(
|
|
4339
|
+
this.state = new StateStore(initState3({ composer, message }));
|
|
4076
4340
|
this.middlewareExecutor = new TextComposerMiddlewareExecutor({ composer });
|
|
4077
4341
|
}
|
|
4078
4342
|
get channel() {
|
|
@@ -5774,6 +6038,13 @@ var MessageComposerMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
|
5774
6038
|
createCompositionDataCleanupMiddleware(composer)
|
|
5775
6039
|
]);
|
|
5776
6040
|
}
|
|
6041
|
+
/**
|
|
6042
|
+
* Narrows the base accessor to the composition middleware type, so callers can read the
|
|
6043
|
+
* declarations it carries (`allowsPendingUploads`) without casting.
|
|
6044
|
+
*/
|
|
6045
|
+
get installedMiddleware() {
|
|
6046
|
+
return super.installedMiddleware;
|
|
6047
|
+
}
|
|
5777
6048
|
};
|
|
5778
6049
|
var MessageDraftComposerMiddlewareExecutor = class extends MiddlewareExecutor {
|
|
5779
6050
|
constructor({ composer }) {
|
|
@@ -6888,7 +7159,7 @@ var DEFAULT_COMPOSER_CONFIG = {
|
|
|
6888
7159
|
};
|
|
6889
7160
|
|
|
6890
7161
|
// src/messageComposer/CustomDataManager.ts
|
|
6891
|
-
var
|
|
7162
|
+
var initState4 = (options) => {
|
|
6892
7163
|
if (!options)
|
|
6893
7164
|
return { message: {}, custom: {} };
|
|
6894
7165
|
return { message: {}, custom: {} };
|
|
@@ -6897,14 +7168,14 @@ var CustomDataManager = class {
|
|
|
6897
7168
|
constructor({ composer, message }) {
|
|
6898
7169
|
this.isMessageDataEqual = (nextState, previousState) => JSON.stringify(nextState.message) === JSON.stringify(previousState?.message);
|
|
6899
7170
|
this.initState = ({ message } = {}) => {
|
|
6900
|
-
this.state.next(
|
|
7171
|
+
this.state.next(initState4({ composer: this.composer, message }));
|
|
6901
7172
|
};
|
|
6902
7173
|
this.getSnapshot = () => this.state.getLatestValue();
|
|
6903
7174
|
this.restoreSnapshot = (snapshot) => {
|
|
6904
7175
|
this.state.next(snapshot);
|
|
6905
7176
|
};
|
|
6906
7177
|
this.composer = composer;
|
|
6907
|
-
this.state = new StateStore(
|
|
7178
|
+
this.state = new StateStore(initState4({ composer, message }));
|
|
6908
7179
|
}
|
|
6909
7180
|
get customMessageData() {
|
|
6910
7181
|
return this.state.getLatestValue().message;
|
|
@@ -6940,7 +7211,7 @@ var LinkPreviewStatus = /* @__PURE__ */ ((LinkPreviewStatus2) => {
|
|
|
6940
7211
|
return LinkPreviewStatus2;
|
|
6941
7212
|
})(LinkPreviewStatus || {});
|
|
6942
7213
|
var linkPreviewArrayToMap = (linkPreviews) => new Map(linkPreviews.map((linkPreview) => [linkPreview.og_scrape_url, linkPreview]));
|
|
6943
|
-
var
|
|
7214
|
+
var initState5 = ({
|
|
6944
7215
|
message
|
|
6945
7216
|
}) => message ? {
|
|
6946
7217
|
previews: message.attachments?.reduce((acc, attachment) => {
|
|
@@ -6959,7 +7230,7 @@ var _LinkPreviewsManager = class _LinkPreviewsManager {
|
|
|
6959
7230
|
this.shouldDiscardEnrichQueries = false;
|
|
6960
7231
|
this.initState = ({ message } = {}) => {
|
|
6961
7232
|
this.cancelURLEnrichment();
|
|
6962
|
-
this.state.next(
|
|
7233
|
+
this.state.next(initState5({ message: this.enabled ? message : void 0 }));
|
|
6963
7234
|
};
|
|
6964
7235
|
this.getSnapshot = () => this.state.getLatestValue();
|
|
6965
7236
|
this.restoreSnapshot = (snapshot) => {
|
|
@@ -7062,7 +7333,7 @@ var _LinkPreviewsManager = class _LinkPreviewsManager {
|
|
|
7062
7333
|
};
|
|
7063
7334
|
this.composer = composer;
|
|
7064
7335
|
this.state = new StateStore(
|
|
7065
|
-
|
|
7336
|
+
initState5({ message: this.enabled ? message : void 0 })
|
|
7066
7337
|
);
|
|
7067
7338
|
this.findAndEnrichUrls = debounce(
|
|
7068
7339
|
this._findAndEnrichUrls.bind(this),
|
|
@@ -7150,7 +7421,7 @@ var LinkPreviewsManager = _LinkPreviewsManager;
|
|
|
7150
7421
|
|
|
7151
7422
|
// src/messageComposer/LocationComposer.ts
|
|
7152
7423
|
var MIN_LIVE_LOCATION_SHARE_DURATION = 60 * 1e3;
|
|
7153
|
-
var
|
|
7424
|
+
var initState6 = ({
|
|
7154
7425
|
message
|
|
7155
7426
|
}) => ({
|
|
7156
7427
|
location: message?.shared_location ?? null
|
|
@@ -7158,7 +7429,7 @@ var initState5 = ({
|
|
|
7158
7429
|
var LocationComposer = class {
|
|
7159
7430
|
constructor({ composer, message }) {
|
|
7160
7431
|
this.initState = ({ message } = {}) => {
|
|
7161
|
-
this.state.next(
|
|
7432
|
+
this.state.next(initState6({ message }));
|
|
7162
7433
|
};
|
|
7163
7434
|
this.getSnapshot = () => this.state.getLatestValue();
|
|
7164
7435
|
this.restoreSnapshot = (snapshot) => {
|
|
@@ -7176,7 +7447,7 @@ var LocationComposer = class {
|
|
|
7176
7447
|
});
|
|
7177
7448
|
};
|
|
7178
7449
|
this.composer = composer;
|
|
7179
|
-
this.state = new StateStore(
|
|
7450
|
+
this.state = new StateStore(initState6({ message }));
|
|
7180
7451
|
this._deviceId = this.config.getDeviceId();
|
|
7181
7452
|
}
|
|
7182
7453
|
get config() {
|
|
@@ -7897,7 +8168,7 @@ var initEditingAuditState = (composition) => {
|
|
|
7897
8168
|
}
|
|
7898
8169
|
};
|
|
7899
8170
|
};
|
|
7900
|
-
var
|
|
8171
|
+
var initState7 = (composition) => {
|
|
7901
8172
|
if (!composition) {
|
|
7902
8173
|
return {
|
|
7903
8174
|
draftId: null,
|
|
@@ -7984,7 +8255,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
7984
8255
|
this.textComposer.initState({ message });
|
|
7985
8256
|
this.pollComposer.initState();
|
|
7986
8257
|
this.customDataManager.initState({ message });
|
|
7987
|
-
this.state.next(
|
|
8258
|
+
this.state.next(initState7(composition));
|
|
7988
8259
|
};
|
|
7989
8260
|
this.initStateFromChannelResponse = (channelApiResponse) => {
|
|
7990
8261
|
if (this.channel.cid !== channelApiResponse.channel.cid) {
|
|
@@ -8450,7 +8721,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8450
8721
|
this.editingAuditState = new StateStore(
|
|
8451
8722
|
this.initEditingAuditState(composition)
|
|
8452
8723
|
);
|
|
8453
|
-
this.state = new StateStore(
|
|
8724
|
+
this.state = new StateStore(initState7(composition));
|
|
8454
8725
|
this.compositionMiddlewareExecutor = new MessageComposerMiddlewareExecutor({
|
|
8455
8726
|
composer: this
|
|
8456
8727
|
});
|
|
@@ -8529,8 +8800,32 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
8529
8800
|
const currentCommand = this.textComposer.command;
|
|
8530
8801
|
return !currentCommand || this.validateCommandSendability(currentCommand).ready;
|
|
8531
8802
|
}
|
|
8803
|
+
/**
|
|
8804
|
+
* Whether the installed composition middleware composes messages whose uploads are still in
|
|
8805
|
+
* flight — see `MessageCompositionMiddleware.allowsPendingUploads`.
|
|
8806
|
+
*
|
|
8807
|
+
* Derived from the chain rather than from config, so there is exactly one switch: the UI SDK
|
|
8808
|
+
* that implements the rest of the flow installs the middleware, and everything that has to
|
|
8809
|
+
* follow from that (starting with {@link hasSendableData}) follows on its own.
|
|
8810
|
+
*
|
|
8811
|
+
* **Temporary API.** In v10 sending with pending uploads becomes part of the composer
|
|
8812
|
+
* configuration (`MessageComposerConfig`, set through `updateConfig`), and this getter,
|
|
8813
|
+
* together with the middleware declaration it reads, is replaced by that config field.
|
|
8814
|
+
*/
|
|
8815
|
+
get allowsPendingUploads() {
|
|
8816
|
+
return this.compositionMiddlewareExecutor.installedMiddleware.some(
|
|
8817
|
+
(middleware) => middleware.allowsPendingUploads
|
|
8818
|
+
);
|
|
8819
|
+
}
|
|
8532
8820
|
get hasSendableData() {
|
|
8533
|
-
|
|
8821
|
+
if (!this.isCommandSendable) return false;
|
|
8822
|
+
if (this.allowsPendingUploads) {
|
|
8823
|
+
const hasSendableAttachment = this.attachmentManager.attachments.some(
|
|
8824
|
+
(attachment) => isFinishedUpload(attachment) || isPendingUpload(attachment)
|
|
8825
|
+
);
|
|
8826
|
+
return !!(!this.textComposer.textIsEmpty || hasSendableAttachment || this.pollId || this.locationComposer.validLocation);
|
|
8827
|
+
}
|
|
8828
|
+
return !!(!this.attachmentManager.uploadsInProgressCount && (!this.textComposer.textIsEmpty || this.attachmentManager.successfulUploadsCount > 0) || this.pollId || !!this.locationComposer.validLocation);
|
|
8534
8829
|
}
|
|
8535
8830
|
get compositionIsEmpty() {
|
|
8536
8831
|
return !this.quotedMessage && this.contentIsEmpty;
|
|
@@ -9157,14 +9452,16 @@ var Channel = class {
|
|
|
9157
9452
|
*
|
|
9158
9453
|
* @return {Promise<SendMessageAPIResponse>} The Server Response
|
|
9159
9454
|
*/
|
|
9160
|
-
async _sendMessage(
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9164
|
-
|
|
9165
|
-
|
|
9166
|
-
|
|
9167
|
-
|
|
9455
|
+
async _sendMessage(rawMessage, options) {
|
|
9456
|
+
const client = this.getClient();
|
|
9457
|
+
const message = sanitizeOutgoingAttachments({
|
|
9458
|
+
client,
|
|
9459
|
+
message: rawMessage
|
|
9460
|
+
});
|
|
9461
|
+
return await client.post(this._channelURL() + "/message", {
|
|
9462
|
+
message,
|
|
9463
|
+
...options
|
|
9464
|
+
});
|
|
9168
9465
|
}
|
|
9169
9466
|
async sendMessage(message, options) {
|
|
9170
9467
|
try {
|
|
@@ -10615,6 +10912,7 @@ var Channel = class {
|
|
|
10615
10912
|
// delivery-report network sync below is skipped for it.
|
|
10616
10913
|
case "message.read_locally":
|
|
10617
10914
|
case "message.read":
|
|
10915
|
+
if (event.thread) break;
|
|
10618
10916
|
if (event.user?.id && event.created_at) {
|
|
10619
10917
|
const previousReadState = channelState.read[event.user.id];
|
|
10620
10918
|
channelState.read[event.user.id] = {
|
|
@@ -11064,7 +11362,7 @@ var ClientState = class {
|
|
|
11064
11362
|
import WebSocket from "isomorphic-ws";
|
|
11065
11363
|
|
|
11066
11364
|
// src/insights.ts
|
|
11067
|
-
import
|
|
11365
|
+
import axios2 from "axios";
|
|
11068
11366
|
var InsightMetrics = class {
|
|
11069
11367
|
constructor() {
|
|
11070
11368
|
this.connectionStartTimestamp = null;
|
|
@@ -11077,7 +11375,7 @@ var postInsights = async (insightType, insights) => {
|
|
|
11077
11375
|
const maxAttempts = 3;
|
|
11078
11376
|
for (let i = 0; i < maxAttempts; i++) {
|
|
11079
11377
|
try {
|
|
11080
|
-
await
|
|
11378
|
+
await axios2.post(
|
|
11081
11379
|
`https://chat-insights.getstream.io/insights/${insightType}`,
|
|
11082
11380
|
insights
|
|
11083
11381
|
);
|
|
@@ -11585,131 +11883,6 @@ var StableWSConnection = class {
|
|
|
11585
11883
|
}
|
|
11586
11884
|
};
|
|
11587
11885
|
|
|
11588
|
-
// src/uploadManager.ts
|
|
11589
|
-
var initState7 = () => ({ uploads: {} });
|
|
11590
|
-
var upsertById = (uploads, record) => ({
|
|
11591
|
-
...uploads,
|
|
11592
|
-
[record.id]: { ...uploads[record.id], ...record }
|
|
11593
|
-
});
|
|
11594
|
-
var updateById = (uploads, record) => {
|
|
11595
|
-
if (!(record.id in uploads)) return null;
|
|
11596
|
-
const current = uploads[record.id];
|
|
11597
|
-
return { ...uploads, [record.id]: { ...current, ...record } };
|
|
11598
|
-
};
|
|
11599
|
-
var UploadManager = class {
|
|
11600
|
-
constructor(client) {
|
|
11601
|
-
this.client = client;
|
|
11602
|
-
this.inFlightUploads = /* @__PURE__ */ new Map();
|
|
11603
|
-
this.getUpload = (id) => this.uploads[id];
|
|
11604
|
-
/**
|
|
11605
|
-
* Clears all upload records.
|
|
11606
|
-
* Invoked when the user disconnects so a later session does not inherit stale upload state.
|
|
11607
|
-
* Aborts every in-flight upload request via its `UploadRequestOptions.abortSignal`.
|
|
11608
|
-
*/
|
|
11609
|
-
this.reset = () => {
|
|
11610
|
-
for (const { abortController } of this.inFlightUploads.values()) {
|
|
11611
|
-
abortController.abort();
|
|
11612
|
-
}
|
|
11613
|
-
this.inFlightUploads.clear();
|
|
11614
|
-
this.state.next(initState7());
|
|
11615
|
-
};
|
|
11616
|
-
/**
|
|
11617
|
-
* Removes the upload record for `id` if present.
|
|
11618
|
-
* If an upload is still in progress, aborts its `UploadRequestOptions.abortSignal`.
|
|
11619
|
-
*/
|
|
11620
|
-
this.deleteUploadRecord = (id) => {
|
|
11621
|
-
const flight = this.inFlightUploads.get(id);
|
|
11622
|
-
if (flight) {
|
|
11623
|
-
this.inFlightUploads.delete(id);
|
|
11624
|
-
flight.abortController.abort();
|
|
11625
|
-
}
|
|
11626
|
-
this.state.next((current) => {
|
|
11627
|
-
if (!(id in current.uploads)) return current;
|
|
11628
|
-
const uploads = { ...current.uploads };
|
|
11629
|
-
delete uploads[id];
|
|
11630
|
-
return { ...current, uploads };
|
|
11631
|
-
});
|
|
11632
|
-
};
|
|
11633
|
-
/**
|
|
11634
|
-
* Starts an upload for `id`, or returns the existing in-flight promise if one is already running.
|
|
11635
|
-
* Uses {@link StreamChat.channel}(`channelCid`) → `messageComposer.attachmentManager.doUploadRequest`.
|
|
11636
|
-
* Resolves with that result; rejects if the upload rejects (the record is removed from state either way).
|
|
11637
|
-
*/
|
|
11638
|
-
this.upload = ({
|
|
11639
|
-
id,
|
|
11640
|
-
channelCid,
|
|
11641
|
-
file
|
|
11642
|
-
}) => {
|
|
11643
|
-
const existing = this.inFlightUploads.get(id);
|
|
11644
|
-
if (existing) return existing.promise;
|
|
11645
|
-
let resolvePromise;
|
|
11646
|
-
let rejectPromise;
|
|
11647
|
-
const promise = new Promise((resolve, reject) => {
|
|
11648
|
-
resolvePromise = resolve;
|
|
11649
|
-
rejectPromise = reject;
|
|
11650
|
-
});
|
|
11651
|
-
const abortController = new AbortController();
|
|
11652
|
-
this.inFlightUploads.set(id, { promise, abortController });
|
|
11653
|
-
void (async () => {
|
|
11654
|
-
const attachmentManager = this.resolveAttachmentManager(channelCid);
|
|
11655
|
-
const trackProgress = attachmentManager.config.trackUploadProgress;
|
|
11656
|
-
try {
|
|
11657
|
-
this.upsertUpload({
|
|
11658
|
-
id,
|
|
11659
|
-
uploadProgress: trackProgress ? 0 : void 0
|
|
11660
|
-
});
|
|
11661
|
-
const onProgress = trackProgress ? (progress) => {
|
|
11662
|
-
this.updateUpload({
|
|
11663
|
-
id,
|
|
11664
|
-
uploadProgress: progress
|
|
11665
|
-
});
|
|
11666
|
-
} : void 0;
|
|
11667
|
-
const uploadRequestOptions = {
|
|
11668
|
-
abortSignal: abortController.signal,
|
|
11669
|
-
...onProgress ? { onProgress } : {}
|
|
11670
|
-
};
|
|
11671
|
-
const response = await attachmentManager.doUploadRequest(
|
|
11672
|
-
file,
|
|
11673
|
-
uploadRequestOptions
|
|
11674
|
-
);
|
|
11675
|
-
resolvePromise(response);
|
|
11676
|
-
} catch (error) {
|
|
11677
|
-
rejectPromise(error);
|
|
11678
|
-
} finally {
|
|
11679
|
-
this.inFlightUploads.delete(id);
|
|
11680
|
-
this.deleteUploadRecord(id);
|
|
11681
|
-
}
|
|
11682
|
-
})();
|
|
11683
|
-
return promise;
|
|
11684
|
-
};
|
|
11685
|
-
this.upsertUpload = (record) => {
|
|
11686
|
-
this.state.partialNext({
|
|
11687
|
-
uploads: upsertById(this.uploads, record)
|
|
11688
|
-
});
|
|
11689
|
-
};
|
|
11690
|
-
this.updateUpload = (record) => {
|
|
11691
|
-
this.state.next((current) => {
|
|
11692
|
-
const nextUploads = updateById(current.uploads, record);
|
|
11693
|
-
if (!nextUploads) return current;
|
|
11694
|
-
return { ...current, uploads: nextUploads };
|
|
11695
|
-
});
|
|
11696
|
-
};
|
|
11697
|
-
this.state = new StateStore(initState7());
|
|
11698
|
-
}
|
|
11699
|
-
resolveAttachmentManager(channelCid) {
|
|
11700
|
-
const colon = channelCid.indexOf(":");
|
|
11701
|
-
if (colon <= 0 || colon === channelCid.length - 1) {
|
|
11702
|
-
throw new Error(`Invalid channelCid: ${channelCid}`);
|
|
11703
|
-
}
|
|
11704
|
-
const channelType = channelCid.slice(0, colon);
|
|
11705
|
-
const channelId = channelCid.slice(colon + 1);
|
|
11706
|
-
return this.client.channel(channelType, channelId).messageComposer.attachmentManager;
|
|
11707
|
-
}
|
|
11708
|
-
get uploads() {
|
|
11709
|
-
return this.state.getLatestValue().uploads;
|
|
11710
|
-
}
|
|
11711
|
-
};
|
|
11712
|
-
|
|
11713
11886
|
// src/signing.ts
|
|
11714
11887
|
var import_jsonwebtoken = __toESM(require_jsonwebtoken());
|
|
11715
11888
|
var import_crypto = __toESM(require_crypto());
|
|
@@ -11968,7 +12141,7 @@ var TokenManager = class {
|
|
|
11968
12141
|
};
|
|
11969
12142
|
|
|
11970
12143
|
// src/connection_fallback.ts
|
|
11971
|
-
import
|
|
12144
|
+
import axios3 from "axios";
|
|
11972
12145
|
var WSConnectionFallback = class {
|
|
11973
12146
|
constructor({ client }) {
|
|
11974
12147
|
/** @private */
|
|
@@ -11987,7 +12160,7 @@ var WSConnectionFallback = class {
|
|
|
11987
12160
|
/** @private */
|
|
11988
12161
|
this._req = async (params, config, retry) => {
|
|
11989
12162
|
if (!this.cancelToken && !params.close) {
|
|
11990
|
-
this.cancelToken =
|
|
12163
|
+
this.cancelToken = axios3.CancelToken.source();
|
|
11991
12164
|
}
|
|
11992
12165
|
try {
|
|
11993
12166
|
const res = await this.client.doAxiosRequest(
|
|
@@ -12023,7 +12196,7 @@ var WSConnectionFallback = class {
|
|
|
12023
12196
|
}
|
|
12024
12197
|
}
|
|
12025
12198
|
} catch (error) {
|
|
12026
|
-
if (
|
|
12199
|
+
if (axios3.isCancel(error)) {
|
|
12027
12200
|
this._log(`_poll() - axios canceled request`);
|
|
12028
12201
|
return;
|
|
12029
12202
|
}
|
|
@@ -14446,7 +14619,7 @@ var StreamChat = class _StreamChat {
|
|
|
14446
14619
|
return this.handleResponse(response);
|
|
14447
14620
|
} catch (e) {
|
|
14448
14621
|
e.client_request_id = requestConfig.headers?.["x-client-request-id"];
|
|
14449
|
-
if (
|
|
14622
|
+
if (axios4.isCancel(e)) throw e;
|
|
14450
14623
|
this._logApiError(type, url, e);
|
|
14451
14624
|
this.consecutiveFailures += 1;
|
|
14452
14625
|
if (e.response) {
|
|
@@ -14758,7 +14931,7 @@ var StreamChat = class _StreamChat {
|
|
|
14758
14931
|
return this.userAgent;
|
|
14759
14932
|
}
|
|
14760
14933
|
if (!this.cachedUserAgent) {
|
|
14761
|
-
const version = "9.
|
|
14934
|
+
const version = "9.52.0";
|
|
14762
14935
|
const { name: sdkName, version: sdkVersion } = this.sdkIdentifier ?? {};
|
|
14763
14936
|
const { name: appName, version: appVersion } = this.appIdentifier ?? {};
|
|
14764
14937
|
const { os, model: deviceModel } = this.deviceIdentifier ?? {};
|
|
@@ -14826,7 +14999,7 @@ var StreamChat = class _StreamChat {
|
|
|
14826
14999
|
keepAliveMsecs: 3e3
|
|
14827
15000
|
});
|
|
14828
15001
|
}
|
|
14829
|
-
this.axiosInstance =
|
|
15002
|
+
this.axiosInstance = axios4.create(this.options);
|
|
14830
15003
|
this.setBaseURL(this.options.baseURL || "https://chat.stream-io-api.com");
|
|
14831
15004
|
if (typeof process !== "undefined" && "env" in process && process.env.STREAM_LOCAL_TEST_RUN) {
|
|
14832
15005
|
this.setBaseURL("http://localhost:3030");
|
|
@@ -16178,6 +16351,11 @@ var StreamChat = class _StreamChat {
|
|
|
16178
16351
|
}
|
|
16179
16352
|
/**
|
|
16180
16353
|
* unflagMessage - unflag a message
|
|
16354
|
+
*
|
|
16355
|
+
* @deprecated The `/moderation/unflag` endpoint is deprecated and is a no-op on
|
|
16356
|
+
* the backend - calling this resolves successfully but does not remove the flag.
|
|
16357
|
+
* Use `client.moderation.submitAction()` against the review queue item instead.
|
|
16358
|
+
*
|
|
16181
16359
|
* @param {string} targetMessageID
|
|
16182
16360
|
* @param {string} [options.user_id] currentUserID, only used with serverside auth
|
|
16183
16361
|
* @returns {Promise<APIResponse>}
|
|
@@ -16190,6 +16368,11 @@ var StreamChat = class _StreamChat {
|
|
|
16190
16368
|
}
|
|
16191
16369
|
/**
|
|
16192
16370
|
* unflagUser - unflag a user
|
|
16371
|
+
*
|
|
16372
|
+
* @deprecated The `/moderation/unflag` endpoint is deprecated and is a no-op on
|
|
16373
|
+
* the backend - calling this resolves successfully but does not remove the flag.
|
|
16374
|
+
* Use `client.moderation.submitAction()` against the review queue item instead.
|
|
16375
|
+
*
|
|
16193
16376
|
* @param {string} targetID
|
|
16194
16377
|
* @param {string} [options.user_id] currentUserID, only used with serverside auth
|
|
16195
16378
|
* @returns {Promise<APIResponse>}
|
|
@@ -16474,7 +16657,10 @@ var StreamChat = class _StreamChat {
|
|
|
16474
16657
|
if (!message.id) {
|
|
16475
16658
|
throw Error("Please specify the message.id when calling updateMessage");
|
|
16476
16659
|
}
|
|
16477
|
-
const payload =
|
|
16660
|
+
const payload = sanitizeOutgoingAttachments({
|
|
16661
|
+
client: this,
|
|
16662
|
+
message: toUpdatedMessagePayload(message)
|
|
16663
|
+
});
|
|
16478
16664
|
if (typeof partialUserOrUserId === "string") {
|
|
16479
16665
|
payload.user_id = partialUserOrUserId;
|
|
16480
16666
|
} else if (typeof partialUserOrUserId?.id === "string") {
|
|
@@ -18947,6 +19133,7 @@ var AbstractOfflineDB = class {
|
|
|
18947
19133
|
return this.handleMessageUpdatedEvent({ event, execute });
|
|
18948
19134
|
}
|
|
18949
19135
|
if (type === "message.read" || type === "notification.mark_read") {
|
|
19136
|
+
if (event.thread) return [];
|
|
18950
19137
|
return this.handleRead({ event, unreadMessages: 0, execute });
|
|
18951
19138
|
}
|
|
18952
19139
|
if (type === "message.read_locally") {
|
|
@@ -19513,6 +19700,7 @@ export {
|
|
|
19513
19700
|
createMessageComposerStateCompositionMiddleware,
|
|
19514
19701
|
createPollComposerStateMiddleware,
|
|
19515
19702
|
createPostUploadAttachmentEnrichmentMiddleware,
|
|
19703
|
+
createSendWithPendingUploadsAttachmentsMiddleware,
|
|
19516
19704
|
createSharedLocationCompositionMiddleware,
|
|
19517
19705
|
createTextComposerCompositionMiddleware,
|
|
19518
19706
|
createTextComposerPreValidationMiddleware,
|
|
@@ -19541,6 +19729,7 @@ export {
|
|
|
19541
19729
|
getTokenizedSuggestionDisplayName,
|
|
19542
19730
|
getTriggerCharWithToken,
|
|
19543
19731
|
gunzipPayload,
|
|
19732
|
+
hasPending,
|
|
19544
19733
|
insertItemWithTrigger,
|
|
19545
19734
|
isAudioAttachment,
|
|
19546
19735
|
isBlobButNotFile,
|
|
@@ -19548,6 +19737,7 @@ export {
|
|
|
19548
19737
|
isFileAttachment,
|
|
19549
19738
|
isFileList,
|
|
19550
19739
|
isFileReference,
|
|
19740
|
+
isFinishedUpload,
|
|
19551
19741
|
isGiphyAttachment,
|
|
19552
19742
|
isImageAttachment,
|
|
19553
19743
|
isImageFile,
|
|
@@ -19560,9 +19750,11 @@ export {
|
|
|
19560
19750
|
isLocalVoiceRecordingAttachment,
|
|
19561
19751
|
isOwnUser,
|
|
19562
19752
|
isPatch,
|
|
19753
|
+
isPendingUpload,
|
|
19563
19754
|
isScrapedContent,
|
|
19564
19755
|
isSharedLocationResponse,
|
|
19565
19756
|
isTargetedOptionTextUpdate,
|
|
19757
|
+
isUploadCancellation,
|
|
19566
19758
|
isUploadedAttachment,
|
|
19567
19759
|
isVideoAttachment,
|
|
19568
19760
|
isVoiceRecordingAttachment,
|
|
@@ -19582,11 +19774,14 @@ export {
|
|
|
19582
19774
|
readFileAsArrayBuffer,
|
|
19583
19775
|
removeDiacritics,
|
|
19584
19776
|
replaceWordWithEntity,
|
|
19777
|
+
settled,
|
|
19585
19778
|
stripCommandFromText,
|
|
19586
19779
|
stripMentionTokens,
|
|
19587
19780
|
textIsEmpty,
|
|
19588
19781
|
timeLeftMs,
|
|
19589
19782
|
verifyAndParseWebhook,
|
|
19590
|
-
verifySignature
|
|
19783
|
+
verifySignature,
|
|
19784
|
+
withCancellation,
|
|
19785
|
+
withoutConcurrency
|
|
19591
19786
|
};
|
|
19592
19787
|
//# sourceMappingURL=index.mjs.map
|