stream-chat 9.13.0 → 9.15.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.
Files changed (39) hide show
  1. package/dist/cjs/index.browser.cjs +427 -189
  2. package/dist/cjs/index.browser.cjs.map +4 -4
  3. package/dist/cjs/index.node.cjs +1647 -232
  4. package/dist/cjs/index.node.cjs.map +4 -4
  5. package/dist/esm/index.js +427 -189
  6. package/dist/esm/index.js.map +4 -4
  7. package/dist/types/messageComposer/attachmentManager.d.ts +11 -3
  8. package/dist/types/messageComposer/configuration/types.d.ts +1 -1
  9. package/dist/types/messageComposer/middleware/attachmentManager/index.d.ts +3 -0
  10. package/dist/types/messageComposer/middleware/attachmentManager/postUpload/AttachmentPostUploadMiddlewareExecutor.d.ts +5 -0
  11. package/dist/types/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.d.ts +2 -0
  12. package/dist/types/messageComposer/middleware/attachmentManager/postUpload/index.d.ts +3 -0
  13. package/dist/types/messageComposer/middleware/attachmentManager/postUpload/uploadErrorHandler.d.ts +3 -0
  14. package/dist/types/messageComposer/middleware/attachmentManager/preUpload/AttachmentPreUploadMiddlewareExecutor.d.ts +5 -0
  15. package/dist/types/messageComposer/middleware/attachmentManager/preUpload/blockedUploadNotification.d.ts +3 -0
  16. package/dist/types/messageComposer/middleware/attachmentManager/preUpload/index.d.ts +3 -0
  17. package/dist/types/messageComposer/middleware/attachmentManager/preUpload/serverUploadConfigCheck.d.ts +3 -0
  18. package/dist/types/messageComposer/middleware/attachmentManager/types.d.ts +20 -0
  19. package/dist/types/messageComposer/types.d.ts +1 -0
  20. package/dist/types/middleware.d.ts +4 -2
  21. package/dist/types/poll.d.ts +1 -1
  22. package/package.json +2 -2
  23. package/src/messageComposer/attachmentManager.ts +116 -25
  24. package/src/messageComposer/configuration/types.ts +3 -2
  25. package/src/messageComposer/messageComposer.ts +1 -1
  26. package/src/messageComposer/middleware/attachmentManager/index.ts +3 -0
  27. package/src/messageComposer/middleware/attachmentManager/postUpload/AttachmentPostUploadMiddlewareExecutor.ts +20 -0
  28. package/src/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.ts +43 -0
  29. package/src/messageComposer/middleware/attachmentManager/postUpload/index.ts +3 -0
  30. package/src/messageComposer/middleware/attachmentManager/postUpload/uploadErrorHandler.ts +39 -0
  31. package/src/messageComposer/middleware/attachmentManager/preUpload/AttachmentPreUploadMiddlewareExecutor.ts +20 -0
  32. package/src/messageComposer/middleware/attachmentManager/preUpload/blockedUploadNotification.ts +38 -0
  33. package/src/messageComposer/middleware/attachmentManager/preUpload/index.ts +3 -0
  34. package/src/messageComposer/middleware/attachmentManager/preUpload/serverUploadConfigCheck.ts +40 -0
  35. package/src/messageComposer/middleware/attachmentManager/types.ts +32 -0
  36. package/src/messageComposer/types.ts +6 -0
  37. package/src/middleware.ts +31 -10
  38. package/src/poll.ts +11 -14
  39. package/src/utils.ts +5 -1
package/dist/esm/index.js CHANGED
@@ -134,7 +134,8 @@ var require_https = __commonJS({
134
134
  // node_modules/form-data/lib/browser.js
135
135
  var require_browser = __commonJS({
136
136
  "node_modules/form-data/lib/browser.js"(exports, module) {
137
- module.exports = typeof self == "object" ? self.FormData : window.FormData;
137
+ "use strict";
138
+ module.exports = typeof self === "object" ? self.FormData : window.FormData;
138
139
  }
139
140
  });
140
141
 
@@ -2979,7 +2980,8 @@ var messagePaginationLinear = ({
2979
2980
  return newPagination;
2980
2981
  };
2981
2982
  var messageSetPagination = (params) => {
2982
- if (params.parentSet.messages.length < params.returnedPage.length) {
2983
+ const messagesFilteredLocally = params.returnedPage.filter(({ shadowed }) => shadowed);
2984
+ if (params.parentSet.messages.length + messagesFilteredLocally.length < params.returnedPage.length) {
2983
2985
  params.logger?.(
2984
2986
  "error",
2985
2987
  "Corrupted message set state: parent set size < returned page size"
@@ -3916,6 +3918,300 @@ var ensureIsLocalAttachment = (attachment) => {
3916
3918
  };
3917
3919
  };
3918
3920
 
3921
+ // src/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.ts
3922
+ var createPostUploadAttachmentEnrichmentMiddleware = () => ({
3923
+ id: "stream-io/attachment-manager-middleware/post-upload-enrichment",
3924
+ handlers: {
3925
+ postProcess: ({
3926
+ state,
3927
+ discard,
3928
+ forward,
3929
+ next
3930
+ }) => {
3931
+ const { attachment, error, response } = state;
3932
+ if (error) return forward();
3933
+ if (!attachment || !response) return discard();
3934
+ const enrichedAttachment = { ...attachment };
3935
+ if (isLocalImageAttachment(attachment)) {
3936
+ if (attachment.localMetadata.previewUri) {
3937
+ URL.revokeObjectURL(attachment.localMetadata.previewUri);
3938
+ delete enrichedAttachment.localMetadata.previewUri;
3939
+ }
3940
+ enrichedAttachment.image_url = response.file;
3941
+ } else {
3942
+ enrichedAttachment.asset_url = response.file;
3943
+ }
3944
+ if (response.thumb_url) {
3945
+ enrichedAttachment.thumb_url = response.thumb_url;
3946
+ }
3947
+ return next({
3948
+ ...state,
3949
+ attachment: enrichedAttachment
3950
+ });
3951
+ }
3952
+ }
3953
+ });
3954
+
3955
+ // src/utils/concurrency.ts
3956
+ var withoutConcurrency = createRunner(wrapWithContinuationTracking);
3957
+ var withCancellation = createRunner(wrapWithCancellation);
3958
+ var pendingPromises = /* @__PURE__ */ new Map();
3959
+ function createRunner(wrapper) {
3960
+ return function run2(tag, cb) {
3961
+ const { cb: wrapped, onContinued } = wrapper(tag, cb);
3962
+ const pending = pendingPromises.get(tag);
3963
+ pending?.onContinued();
3964
+ const promise = pending ? pending.promise.then(wrapped, wrapped) : wrapped();
3965
+ pendingPromises.set(tag, { promise, onContinued });
3966
+ return promise;
3967
+ };
3968
+ }
3969
+ function wrapWithContinuationTracking(tag, cb) {
3970
+ let hasContinuation = false;
3971
+ const wrapped = () => cb().finally(() => {
3972
+ if (!hasContinuation) {
3973
+ pendingPromises.delete(tag);
3974
+ }
3975
+ });
3976
+ const onContinued = () => hasContinuation = true;
3977
+ return { cb: wrapped, onContinued };
3978
+ }
3979
+ function wrapWithCancellation(tag, cb) {
3980
+ const ac = new AbortController();
3981
+ const wrapped = () => {
3982
+ if (ac.signal.aborted) {
3983
+ return Promise.resolve("canceled");
3984
+ }
3985
+ return cb(ac.signal).finally(() => {
3986
+ if (!ac.signal.aborted) {
3987
+ pendingPromises.delete(tag);
3988
+ }
3989
+ });
3990
+ };
3991
+ const onContinued = () => ac.abort();
3992
+ return { cb: wrapped, onContinued };
3993
+ }
3994
+
3995
+ // src/middleware.ts
3996
+ var MiddlewareExecutor = class {
3997
+ constructor() {
3998
+ this.middleware = [];
3999
+ this.id = generateUUIDv4();
4000
+ }
4001
+ use(middleware) {
4002
+ this.middleware = this.middleware.concat(middleware);
4003
+ return this;
4004
+ }
4005
+ // todo: document how to re-arrange the order of middleware using replace
4006
+ replace(middleware) {
4007
+ const newMiddleware = [...this.middleware];
4008
+ middleware.forEach((upserted) => {
4009
+ const existingIndex = this.middleware.findIndex(
4010
+ (existing) => existing.id === upserted.id
4011
+ );
4012
+ if (existingIndex >= 0) {
4013
+ newMiddleware.splice(existingIndex, 1, upserted);
4014
+ } else {
4015
+ newMiddleware.push(upserted);
4016
+ }
4017
+ });
4018
+ this.middleware = newMiddleware;
4019
+ return this;
4020
+ }
4021
+ insert({
4022
+ middleware,
4023
+ position,
4024
+ unique
4025
+ }) {
4026
+ if (unique) {
4027
+ middleware.forEach((md) => {
4028
+ const existingMiddlewareIndex = this.middleware.findIndex((m) => m.id === md.id);
4029
+ if (existingMiddlewareIndex >= 0) {
4030
+ this.middleware.splice(existingMiddlewareIndex, 1);
4031
+ }
4032
+ });
4033
+ }
4034
+ const targetId = position.after || position.before;
4035
+ const targetIndex = this.middleware.findIndex((m) => m.id === targetId);
4036
+ const insertionIndex = position.after ? targetIndex + 1 : targetIndex;
4037
+ this.middleware.splice(insertionIndex, 0, ...middleware);
4038
+ return this;
4039
+ }
4040
+ setOrder(order) {
4041
+ this.middleware = order.map((id) => this.middleware.find((middleware) => middleware.id === id)).filter(Boolean);
4042
+ }
4043
+ remove(middlewareIds) {
4044
+ if (!middlewareIds && !middlewareIds.length) return;
4045
+ this.middleware = this.middleware.filter(
4046
+ (md) => typeof middlewareIds === "string" ? middlewareIds !== md.id : !middlewareIds.includes(md.id)
4047
+ );
4048
+ }
4049
+ async executeMiddlewareChain({
4050
+ eventName,
4051
+ initialValue,
4052
+ mode = "cancelable"
4053
+ }) {
4054
+ let index = -1;
4055
+ const execute = async (i, state, status) => {
4056
+ if (i <= index) {
4057
+ throw new Error("next() called multiple times");
4058
+ }
4059
+ index = i;
4060
+ const returnFromChain = i === this.middleware.length || status && ["complete", "discard"].includes(status);
4061
+ if (returnFromChain) return { state, status };
4062
+ const middleware = this.middleware[i];
4063
+ const handler = middleware.handlers[eventName];
4064
+ if (!handler) {
4065
+ return execute(i + 1, state, status);
4066
+ }
4067
+ const next = (adjustedState) => execute(i + 1, adjustedState);
4068
+ const complete = (adjustedState) => execute(i + 1, adjustedState, "complete");
4069
+ const discard = () => execute(i + 1, state, "discard");
4070
+ const forward = () => execute(i + 1, state);
4071
+ return await handler({
4072
+ state,
4073
+ next,
4074
+ complete,
4075
+ discard,
4076
+ forward
4077
+ });
4078
+ };
4079
+ const result = mode === "cancelable" ? await withCancellation(
4080
+ `middleware-execution-${this.id}-${eventName}`,
4081
+ async (abortSignal) => {
4082
+ const result2 = await execute(0, initialValue);
4083
+ if (abortSignal.aborted) {
4084
+ return "canceled";
4085
+ }
4086
+ return result2;
4087
+ }
4088
+ ) : await execute(0, initialValue);
4089
+ return result === "canceled" ? { state: initialValue, status: "discard" } : result;
4090
+ }
4091
+ async execute({
4092
+ eventName,
4093
+ initialValue: initialState,
4094
+ mode
4095
+ }) {
4096
+ return await this.executeMiddlewareChain({
4097
+ eventName,
4098
+ initialValue: initialState,
4099
+ mode
4100
+ });
4101
+ }
4102
+ };
4103
+
4104
+ // src/messageComposer/middleware/attachmentManager/postUpload/uploadErrorHandler.ts
4105
+ var createUploadErrorHandlerMiddleware = (composer) => ({
4106
+ id: "stream-io/attachment-manager-middleware/upload-error",
4107
+ handlers: {
4108
+ postProcess: ({
4109
+ state,
4110
+ discard,
4111
+ forward
4112
+ }) => {
4113
+ const { attachment, error } = state;
4114
+ if (!error) return forward();
4115
+ if (!attachment) return discard();
4116
+ const reason = error instanceof Error ? error.message : "unknown error";
4117
+ composer.client.notifications.addError({
4118
+ message: "Error uploading attachment",
4119
+ origin: {
4120
+ emitter: "AttachmentManager",
4121
+ context: { attachment }
4122
+ },
4123
+ options: {
4124
+ type: "api:attachment:upload:failed",
4125
+ metadata: { reason },
4126
+ originalError: error
4127
+ }
4128
+ });
4129
+ return forward();
4130
+ }
4131
+ }
4132
+ });
4133
+
4134
+ // src/messageComposer/middleware/attachmentManager/postUpload/AttachmentPostUploadMiddlewareExecutor.ts
4135
+ var AttachmentPostUploadMiddlewareExecutor = class extends MiddlewareExecutor {
4136
+ constructor({ composer }) {
4137
+ super();
4138
+ this.use([
4139
+ createUploadErrorHandlerMiddleware(composer),
4140
+ createPostUploadAttachmentEnrichmentMiddleware()
4141
+ ]);
4142
+ }
4143
+ };
4144
+
4145
+ // src/messageComposer/middleware/attachmentManager/preUpload/serverUploadConfigCheck.ts
4146
+ var createUploadConfigCheckMiddleware = (composer) => ({
4147
+ id: "stream-io/attachment-manager-middleware/file-upload-config-check",
4148
+ handlers: {
4149
+ prepare: async ({
4150
+ state,
4151
+ next,
4152
+ discard
4153
+ }) => {
4154
+ const { attachmentManager } = composer;
4155
+ if (!attachmentManager || !state.attachment) return discard();
4156
+ const uploadPermissionCheck = await attachmentManager.getUploadConfigCheck(
4157
+ state.attachment.localMetadata.file
4158
+ );
4159
+ const attachment = {
4160
+ ...state.attachment,
4161
+ localMetadata: {
4162
+ ...state.attachment.localMetadata,
4163
+ uploadPermissionCheck,
4164
+ uploadState: uploadPermissionCheck.uploadBlocked ? "blocked" : "pending"
4165
+ }
4166
+ };
4167
+ return next({
4168
+ ...state,
4169
+ attachment
4170
+ });
4171
+ }
4172
+ }
4173
+ });
4174
+
4175
+ // src/messageComposer/middleware/attachmentManager/preUpload/blockedUploadNotification.ts
4176
+ var createBlockedAttachmentUploadNotificationMiddleware = (composer) => ({
4177
+ id: "stream-io/attachment-manager-middleware/blocked-upload-notification",
4178
+ handlers: {
4179
+ prepare: ({
4180
+ state: { attachment },
4181
+ forward
4182
+ }) => {
4183
+ if (!attachment) return forward();
4184
+ if (attachment.localMetadata.uploadPermissionCheck?.uploadBlocked) {
4185
+ composer.client.notifications.addError({
4186
+ message: `The attachment upload was blocked`,
4187
+ origin: {
4188
+ emitter: "AttachmentManager",
4189
+ context: { blockedAttachment: attachment }
4190
+ },
4191
+ options: {
4192
+ type: "validation:attachment:upload:blocked",
4193
+ metadata: {
4194
+ reason: attachment.localMetadata.uploadPermissionCheck?.reason
4195
+ }
4196
+ }
4197
+ });
4198
+ }
4199
+ return forward();
4200
+ }
4201
+ }
4202
+ });
4203
+
4204
+ // src/messageComposer/middleware/attachmentManager/preUpload/AttachmentPreUploadMiddlewareExecutor.ts
4205
+ var AttachmentPreUploadMiddlewareExecutor = class extends MiddlewareExecutor {
4206
+ constructor({ composer }) {
4207
+ super();
4208
+ this.use([
4209
+ createUploadConfigCheckMiddleware(composer),
4210
+ createBlockedAttachmentUploadNotificationMiddleware(composer)
4211
+ ]);
4212
+ }
4213
+ };
4214
+
3919
4215
  // src/store.ts
3920
4216
  var isPatch = (value) => typeof value === "function";
3921
4217
  var noop2 = () => {
@@ -4507,7 +4803,7 @@ var initState = ({
4507
4803
  };
4508
4804
  })
4509
4805
  });
4510
- var AttachmentManager = class {
4806
+ var _AttachmentManager = class _AttachmentManager {
4511
4807
  constructor({ composer, message }) {
4512
4808
  this.setCustomUploadFn = (doUploadRequest) => {
4513
4809
  this.composer.updateConfig({ attachments: { doUploadRequest } });
@@ -4614,42 +4910,18 @@ var AttachmentManager = class {
4614
4910
  }
4615
4911
  return { uploadBlocked: false };
4616
4912
  };
4913
+ // @deprecated use AttachmentManager.toLocalUploadAttachment(file)
4617
4914
  this.fileToLocalUploadAttachment = async (fileLike) => {
4618
- const file = isFileReference(fileLike) || isFile2(fileLike) ? fileLike : createFileFromBlobs({
4619
- blobsArray: [fileLike],
4620
- fileName: generateFileName(fileLike.type),
4621
- mimeType: fileLike.type
4622
- });
4623
- const uploadPermissionCheck = await this.getUploadConfigCheck(file);
4624
- const localAttachment = {
4625
- file_size: file.size,
4626
- mime_type: file.type,
4627
- localMetadata: {
4628
- file,
4629
- id: generateUUIDv4(),
4630
- uploadPermissionCheck,
4631
- uploadState: uploadPermissionCheck.uploadBlocked ? "blocked" : "pending"
4632
- },
4633
- type: getAttachmentTypeFromMimeType(file.type)
4634
- };
4635
- localAttachment[isImageFile(file) ? "fallback" : "title"] = file.name;
4636
- if (isImageFile(file)) {
4637
- localAttachment.localMetadata.previewUri = isFileReference(fileLike) ? fileLike.uri : URL.createObjectURL?.(fileLike);
4638
- if (isFileReference(fileLike) && fileLike.height && fileLike.width) {
4639
- localAttachment.original_height = fileLike.height;
4640
- localAttachment.original_width = fileLike.width;
4641
- }
4642
- }
4643
- if (isFileReference(fileLike) && fileLike.thumb_url) {
4644
- localAttachment.thumb_url = fileLike.thumb_url;
4645
- }
4646
- if (isFileReference(fileLike) && fileLike.duration) {
4647
- localAttachment.duration = fileLike.duration;
4648
- }
4915
+ const localAttachment = _AttachmentManager.toLocalUploadAttachment(fileLike);
4916
+ const uploadPermissionCheck = await this.getUploadConfigCheck(
4917
+ localAttachment.localMetadata.file
4918
+ );
4919
+ localAttachment.localMetadata.uploadPermissionCheck = uploadPermissionCheck;
4920
+ localAttachment.localMetadata.uploadState = uploadPermissionCheck.uploadBlocked ? "blocked" : "pending";
4649
4921
  return localAttachment;
4650
4922
  };
4651
4923
  this.ensureLocalUploadAttachment = async (attachment) => {
4652
- if (!attachment.localMetadata?.file || !attachment.localMetadata.id) {
4924
+ if (!attachment.localMetadata?.file) {
4653
4925
  this.client.notifications.addError({
4654
4926
  message: "File is required for upload attachment",
4655
4927
  origin: { emitter: "AttachmentManager", context: { attachment } },
@@ -4657,6 +4929,14 @@ var AttachmentManager = class {
4657
4929
  });
4658
4930
  return;
4659
4931
  }
4932
+ if (!attachment.localMetadata.id) {
4933
+ this.client.notifications.addError({
4934
+ message: "Local upload attachment missing local id",
4935
+ origin: { emitter: "AttachmentManager", context: { attachment } },
4936
+ options: { type: "validation:attachment:id:missing" }
4937
+ });
4938
+ return;
4939
+ }
4660
4940
  if (!this.fileUploadFilter(attachment)) return;
4661
4941
  const newAttachment = await this.fileToLocalUploadAttachment(
4662
4942
  attachment.localMetadata.file
@@ -4696,6 +4976,7 @@ var AttachmentManager = class {
4696
4976
  }
4697
4977
  return this.doDefaultUploadRequest(fileLike);
4698
4978
  };
4979
+ // @deprecated use attachmentManager.uploadFile(file)
4699
4980
  this.uploadAttachment = async (attachment) => {
4700
4981
  if (!this.isUploadEnabled) return;
4701
4982
  const localAttachment = await this.ensureLocalUploadAttachment(attachment);
@@ -4779,19 +5060,75 @@ var AttachmentManager = class {
4779
5060
  this.updateAttachment(uploadedAttachment);
4780
5061
  return uploadedAttachment;
4781
5062
  };
5063
+ this.uploadFile = async (file) => {
5064
+ const preUpload = await this.preUploadMiddlewareExecutor.execute({
5065
+ eventName: "prepare",
5066
+ initialValue: {
5067
+ attachment: _AttachmentManager.toLocalUploadAttachment(file)
5068
+ },
5069
+ mode: "concurrent"
5070
+ });
5071
+ let attachment = preUpload.state.attachment;
5072
+ if (preUpload.status === "discard") return attachment;
5073
+ if (!this.fileUploadFilter(attachment)) return attachment;
5074
+ if (attachment.localMetadata.uploadState === "blocked") {
5075
+ this.upsertAttachments([attachment]);
5076
+ return preUpload.state.attachment;
5077
+ }
5078
+ attachment = {
5079
+ ...attachment,
5080
+ localMetadata: {
5081
+ ...attachment.localMetadata,
5082
+ uploadState: "uploading"
5083
+ }
5084
+ };
5085
+ this.upsertAttachments([attachment]);
5086
+ let response;
5087
+ let error;
5088
+ try {
5089
+ response = await this.doUploadRequest(file);
5090
+ } catch (err) {
5091
+ error = err instanceof Error ? err : void 0;
5092
+ }
5093
+ const postUpload = await this.postUploadMiddlewareExecutor.execute({
5094
+ eventName: "postProcess",
5095
+ initialValue: {
5096
+ attachment: {
5097
+ ...attachment,
5098
+ localMetadata: {
5099
+ ...attachment.localMetadata,
5100
+ uploadState: error ? "failed" : "finished"
5101
+ }
5102
+ },
5103
+ error,
5104
+ response
5105
+ },
5106
+ mode: "concurrent"
5107
+ });
5108
+ attachment = postUpload.state.attachment;
5109
+ if (postUpload.status === "discard") {
5110
+ this.removeAttachments([attachment.localMetadata.id]);
5111
+ return attachment;
5112
+ }
5113
+ this.updateAttachment(attachment);
5114
+ return attachment;
5115
+ };
4782
5116
  this.uploadFiles = async (files) => {
4783
5117
  if (!this.isUploadEnabled) return;
4784
5118
  const iterableFiles = isFileList2(files) ? Array.from(files) : files;
4785
- const attachments = await Promise.all(
4786
- iterableFiles.map(this.fileToLocalUploadAttachment)
4787
- );
4788
- return Promise.all(
4789
- attachments.filter(this.fileUploadFilter).slice(0, this.availableUploadSlots).map(this.uploadAttachment)
5119
+ return await Promise.all(
5120
+ iterableFiles.slice(0, this.availableUploadSlots).map(this.uploadFile)
4790
5121
  );
4791
5122
  };
4792
5123
  this.composer = composer;
4793
5124
  this.state = new StateStore(initState({ message }));
4794
5125
  this.attachmentsByIdGetterCache = { attachmentsById: {}, attachments: [] };
5126
+ this.preUploadMiddlewareExecutor = new AttachmentPreUploadMiddlewareExecutor({
5127
+ composer
5128
+ });
5129
+ this.postUploadMiddlewareExecutor = new AttachmentPostUploadMiddlewareExecutor({
5130
+ composer
5131
+ });
4795
5132
  }
4796
5133
  get attachmentsById() {
4797
5134
  const { attachments } = this.state.getLatestValue();
@@ -4821,9 +5158,15 @@ var AttachmentManager = class {
4821
5158
  set acceptedFiles(acceptedFiles) {
4822
5159
  this.composer.updateConfig({ attachments: { acceptedFiles } });
4823
5160
  }
5161
+ /*
5162
+ @deprecated attachments can be filtered using injecting pre-upload middleware
5163
+ */
4824
5164
  get fileUploadFilter() {
4825
5165
  return this.config.fileUploadFilter;
4826
5166
  }
5167
+ /*
5168
+ @deprecated attachments can be filtered using injecting pre-upload middleware
5169
+ */
4827
5170
  set fileUploadFilter(fileUploadFilter) {
4828
5171
  this.composer.updateConfig({ attachments: { fileUploadFilter } });
4829
5172
  }
@@ -4870,6 +5213,39 @@ var AttachmentManager = class {
4870
5213
  );
4871
5214
  }
4872
5215
  };
5216
+ _AttachmentManager.toLocalUploadAttachment = (fileLike) => {
5217
+ const file = isFileReference(fileLike) || isFile2(fileLike) ? fileLike : createFileFromBlobs({
5218
+ blobsArray: [fileLike],
5219
+ fileName: generateFileName(fileLike.type),
5220
+ mimeType: fileLike.type
5221
+ });
5222
+ const localAttachment = {
5223
+ file_size: file.size,
5224
+ mime_type: file.type,
5225
+ localMetadata: {
5226
+ file,
5227
+ id: generateUUIDv4(),
5228
+ uploadState: "pending"
5229
+ },
5230
+ type: getAttachmentTypeFromMimeType(file.type)
5231
+ };
5232
+ localAttachment[isImageFile(file) ? "fallback" : "title"] = file.name;
5233
+ if (isImageFile(file)) {
5234
+ localAttachment.localMetadata.previewUri = isFileReference(fileLike) ? fileLike.uri : URL.createObjectURL?.(fileLike);
5235
+ if (isFileReference(fileLike) && fileLike.height && fileLike.width) {
5236
+ localAttachment.original_height = fileLike.height;
5237
+ localAttachment.original_width = fileLike.width;
5238
+ }
5239
+ }
5240
+ if (isFileReference(fileLike) && fileLike.thumb_url) {
5241
+ localAttachment.thumb_url = fileLike.thumb_url;
5242
+ }
5243
+ if (isFileReference(fileLike) && fileLike.duration) {
5244
+ localAttachment.duration = fileLike.duration;
5245
+ }
5246
+ return localAttachment;
5247
+ };
5248
+ var AttachmentManager = _AttachmentManager;
4873
5249
 
4874
5250
  // node_modules/linkifyjs/dist/linkify.es.js
4875
5251
  var encodedTlds = "aaa1rp3bb0ott3vie4c1le2ogado5udhabi7c0ademy5centure6ountant0s9o1tor4d0s1ult4e0g1ro2tna4f0l1rica5g0akhan5ency5i0g1rbus3force5tel5kdn3l0ibaba4pay4lfinanz6state5y2sace3tom5m0azon4ericanexpress7family11x2fam3ica3sterdam8nalytics7droid5quan4z2o0l2partments8p0le4q0uarelle8r0ab1mco4chi3my2pa2t0e3s0da2ia2sociates9t0hleta5torney7u0ction5di0ble3o3spost5thor3o0s4w0s2x0a2z0ure5ba0by2idu3namex4d1k2r0celona5laycard4s5efoot5gains6seball5ketball8uhaus5yern5b0c1t1va3cg1n2d1e0ats2uty4er2ntley5rlin4st0buy5t2f1g1h0arti5i0ble3d1ke2ng0o3o1z2j1lack0friday9ockbuster8g1omberg7ue3m0s1w2n0pparibas9o0ats3ehringer8fa2m1nd2o0k0ing5sch2tik2on4t1utique6x2r0adesco6idgestone9oadway5ker3ther5ussels7s1t1uild0ers6siness6y1zz3v1w1y1z0h3ca0b1fe2l0l1vinklein9m0era3p2non3petown5ital0one8r0avan4ds2e0er0s4s2sa1e1h1ino4t0ering5holic7ba1n1re3c1d1enter4o1rn3f0a1d2g1h0anel2nel4rity4se2t2eap3intai5ristmas6ome4urch5i0priani6rcle4sco3tadel4i0c2y3k1l0aims4eaning6ick2nic1que6othing5ud3ub0med6m1n1o0ach3des3ffee4llege4ogne5m0mbank4unity6pany2re3uter5sec4ndos3struction8ulting7tact3ractors9oking4l1p2rsica5untry4pon0s4rses6pa2r0edit0card4union9icket5own3s1uise0s6u0isinella9v1w1x1y0mru3ou3z2dad1nce3ta1e1ing3sun4y2clk3ds2e0al0er2s3gree4livery5l1oitte5ta3mocrat6ntal2ist5si0gn4v2hl2iamonds6et2gital5rect0ory7scount3ver5h2y2j1k1m1np2o0cs1tor4g1mains5t1wnload7rive4tv2ubai3nlop4pont4rban5vag2r2z2earth3t2c0o2deka3u0cation8e1g1mail3erck5nergy4gineer0ing9terprises10pson4quipment8r0icsson6ni3s0q1tate5t1u0rovision8s2vents5xchange6pert3osed4ress5traspace10fage2il1rwinds6th3mily4n0s2rm0ers5shion4t3edex3edback6rrari3ero6i0delity5o2lm2nal1nce1ial7re0stone6mdale6sh0ing5t0ness6j1k1lickr3ghts4r2orist4wers5y2m1o0o0d1tball6rd1ex2sale4um3undation8x2r0ee1senius7l1ogans4ntier7tr2ujitsu5n0d2rniture7tbol5yi3ga0l0lery3o1up4me0s3p1rden4y2b0iz3d0n2e0a1nt0ing5orge5f1g0ee3h1i0ft0s3ves2ing5l0ass3e1obal2o4m0ail3bh2o1x2n1odaddy5ld0point6f2o0dyear5g0le4p1t1v2p1q1r0ainger5phics5tis4een3ipe3ocery4up4s1t1u0cci3ge2ide2tars5ru3w1y2hair2mburg5ngout5us3bo2dfc0bank7ealth0care8lp1sinki6re1mes5iphop4samitsu7tachi5v2k0t2m1n1ockey4ldings5iday5medepot5goods5s0ense7nda3rse3spital5t0ing5t0els3mail5use3w2r1sbc3t1u0ghes5yatt3undai7ibm2cbc2e1u2d1e0ee3fm2kano4l1m0amat4db2mo0bilien9n0c1dustries8finiti5o2g1k1stitute6urance4e4t0ernational10uit4vestments10o1piranga7q1r0ish4s0maili5t0anbul7t0au2v3jaguar4va3cb2e0ep2tzt3welry6io2ll2m0p2nj2o0bs1urg4t1y2p0morgan6rs3uegos4niper7kaufen5ddi3e0rryhotels6logistics9properties14fh2g1h1i0a1ds2m1ndle4tchen5wi3m1n1oeln3matsu5sher5p0mg2n2r0d1ed3uokgroup8w1y0oto4z2la0caixa5mborghini8er3ncaster6d0rover6xess5salle5t0ino3robe5w0yer5b1c1ds2ease3clerc5frak4gal2o2xus4gbt3i0dl2fe0insurance9style7ghting6ke2lly3mited4o2ncoln4k2psy3ve1ing5k1lc1p2oan0s3cker3us3l1ndon4tte1o3ve3pl0financial11r1s1t0d0a3u0ndbeck6xe1ury5v1y2ma0drid4if1son4keup4n0agement7go3p1rket0ing3s4riott5shalls7ttel5ba2c0kinsey7d1e0d0ia3et2lbourne7me1orial6n0u2rckmsd7g1h1iami3crosoft7l1ni1t2t0subishi9k1l0b1s2m0a2n1o0bi0le4da2e1i1m1nash3ey2ster5rmon3tgage6scow4to0rcycles9v0ie4p1q1r1s0d2t0n1r2u0seum3ic4v1w1x1y1z2na0b1goya4me2vy3ba2c1e0c1t0bank4flix4work5ustar5w0s2xt0direct7us4f0l2g0o2hk2i0co2ke1on3nja3ssan1y5l1o0kia3rton4w0ruz3tv4p1r0a1w2tt2u1yc2z2obi1server7ffice5kinawa6layan0group9lo3m0ega4ne1g1l0ine5oo2pen3racle3nge4g0anic5igins6saka4tsuka4t2vh3pa0ge2nasonic7ris2s1tners4s1y3y2ccw3e0t2f0izer5g1h0armacy6d1ilips5one2to0graphy6s4ysio5ics1tet2ures6d1n0g1k2oneer5zza4k1l0ace2y0station9umbing5s3m1n0c2ohl2ker3litie5rn2st3r0america6xi3ess3ime3o0d0uctions8f1gressive8mo2perties3y5tection8u0dential9s1t1ub2w0c2y2qa1pon3uebec3st5racing4dio4e0ad1lestate6tor2y4cipes5d0stone5umbrella9hab3ise0n3t2liance6n0t0als5pair3ort3ublican8st0aurant8view0s5xroth6ich0ardli6oh3l1o1p2o0cks3deo3gers4om3s0vp3u0gby3hr2n2w0e2yukyu6sa0arland6fe0ty4kura4le1on3msclub4ung5ndvik0coromant12ofi4p1rl2s1ve2xo3b0i1s2c0b1haeffler7midt4olarships8ol3ule3warz5ience5ot3d1e0arch3t2cure1ity6ek2lect4ner3rvices6ven3w1x0y3fr2g1h0angrila6rp3ell3ia1ksha5oes2p0ping5uji3w3i0lk2na1gles5te3j1k0i0n2y0pe4l0ing4m0art3ile4n0cf3o0ccer3ial4ftbank4ware6hu2lar2utions7ng1y2y2pa0ce3ort2t3r0l2s1t0ada2ples4r1tebank4farm7c0group6ockholm6rage3e3ream4udio2y3yle4u0cks3pplies3y2ort5rf1gery5zuki5v1watch4iss4x1y0dney4stems6z2tab1ipei4lk2obao4rget4tamotors6r2too4x0i3c0i2d0k2eam2ch0nology8l1masek5nnis4va3f1g1h0d1eater2re6iaa2ckets5enda4ps2res2ol4j0maxx4x2k0maxx5l1m0all4n1o0day3kyo3ols3p1ray3shiba5tal3urs3wn2yota3s3r0ade1ing4ining5vel0ers0insurance16ust3v2t1ube2i1nes3shu4v0s2w1z2ua1bank3s2g1k1nicom3versity8o2ol2ps2s1y1z2va0cations7na1guard7c1e0gas3ntures6risign5m\xF6gensberater2ung14sicherung10t2g1i0ajes4deo3g1king4llas4n1p1rgin4sa1ion4va1o3laanderen9n1odka3lvo3te1ing3o2yage5u2wales2mart4ter4ng0gou5tch0es6eather0channel12bcam3er2site5d0ding5ibo2r3f1hoswho6ien2ki2lliamhill9n0dows4e1ners6me2olterskluwer11odside6rk0s2ld3w2s1tc1f3xbox3erox4ihuan4n2xx2yz3yachts4hoo3maxun5ndex5e1odobashi7ga2kohama6u0tube6t1un3za0ppos4ra3ero3ip2m1one3uerich6w2";
@@ -6338,146 +6714,6 @@ var LocationComposer = class {
6338
6714
  }
6339
6715
  };
6340
6716
 
6341
- // src/utils/concurrency.ts
6342
- var withoutConcurrency = createRunner(wrapWithContinuationTracking);
6343
- var withCancellation = createRunner(wrapWithCancellation);
6344
- var pendingPromises = /* @__PURE__ */ new Map();
6345
- function createRunner(wrapper) {
6346
- return function run2(tag, cb) {
6347
- const { cb: wrapped, onContinued } = wrapper(tag, cb);
6348
- const pending = pendingPromises.get(tag);
6349
- pending?.onContinued();
6350
- const promise = pending ? pending.promise.then(wrapped, wrapped) : wrapped();
6351
- pendingPromises.set(tag, { promise, onContinued });
6352
- return promise;
6353
- };
6354
- }
6355
- function wrapWithContinuationTracking(tag, cb) {
6356
- let hasContinuation = false;
6357
- const wrapped = () => cb().finally(() => {
6358
- if (!hasContinuation) {
6359
- pendingPromises.delete(tag);
6360
- }
6361
- });
6362
- const onContinued = () => hasContinuation = true;
6363
- return { cb: wrapped, onContinued };
6364
- }
6365
- function wrapWithCancellation(tag, cb) {
6366
- const ac = new AbortController();
6367
- const wrapped = () => {
6368
- if (ac.signal.aborted) {
6369
- return Promise.resolve("canceled");
6370
- }
6371
- return cb(ac.signal).finally(() => {
6372
- if (!ac.signal.aborted) {
6373
- pendingPromises.delete(tag);
6374
- }
6375
- });
6376
- };
6377
- const onContinued = () => ac.abort();
6378
- return { cb: wrapped, onContinued };
6379
- }
6380
-
6381
- // src/middleware.ts
6382
- var MiddlewareExecutor = class {
6383
- constructor() {
6384
- this.middleware = [];
6385
- this.id = generateUUIDv4();
6386
- }
6387
- use(middleware) {
6388
- this.middleware = this.middleware.concat(middleware);
6389
- return this;
6390
- }
6391
- // todo: document how to re-arrange the order of middleware using replace
6392
- replace(middleware) {
6393
- const newMiddleware = [...this.middleware];
6394
- middleware.forEach((upserted) => {
6395
- const existingIndex = this.middleware.findIndex(
6396
- (existing) => existing.id === upserted.id
6397
- );
6398
- if (existingIndex >= 0) {
6399
- newMiddleware.splice(existingIndex, 1, upserted);
6400
- } else {
6401
- newMiddleware.push(upserted);
6402
- }
6403
- });
6404
- this.middleware = newMiddleware;
6405
- return this;
6406
- }
6407
- insert({
6408
- middleware,
6409
- position,
6410
- unique
6411
- }) {
6412
- if (unique) {
6413
- middleware.forEach((md) => {
6414
- const existingMiddlewareIndex = this.middleware.findIndex((m) => m.id === md.id);
6415
- if (existingMiddlewareIndex >= 0) {
6416
- this.middleware.splice(existingMiddlewareIndex, 1);
6417
- }
6418
- });
6419
- }
6420
- const targetId = position.after || position.before;
6421
- const targetIndex = this.middleware.findIndex((m) => m.id === targetId);
6422
- const insertionIndex = position.after ? targetIndex + 1 : targetIndex;
6423
- this.middleware.splice(insertionIndex, 0, ...middleware);
6424
- return this;
6425
- }
6426
- setOrder(order) {
6427
- this.middleware = order.map((id) => this.middleware.find((middleware) => middleware.id === id)).filter(Boolean);
6428
- }
6429
- async executeMiddlewareChain({
6430
- eventName,
6431
- initialValue
6432
- }) {
6433
- let index = -1;
6434
- const execute = async (i, state, status) => {
6435
- if (i <= index) {
6436
- throw new Error("next() called multiple times");
6437
- }
6438
- index = i;
6439
- const returnFromChain = i === this.middleware.length || status && ["complete", "discard"].includes(status);
6440
- if (returnFromChain) return { state, status };
6441
- const middleware = this.middleware[i];
6442
- const handler = middleware.handlers[eventName];
6443
- if (!handler) {
6444
- return execute(i + 1, state, status);
6445
- }
6446
- const next = (adjustedState) => execute(i + 1, adjustedState);
6447
- const complete = (adjustedState) => execute(i + 1, adjustedState, "complete");
6448
- const discard = () => execute(i + 1, state, "discard");
6449
- const forward = () => execute(i + 1, state);
6450
- return await handler({
6451
- state,
6452
- next,
6453
- complete,
6454
- discard,
6455
- forward
6456
- });
6457
- };
6458
- const result = await withCancellation(
6459
- `middleware-execution-${this.id}-${eventName}`,
6460
- async (abortSignal) => {
6461
- const result2 = await execute(0, initialValue);
6462
- if (abortSignal.aborted) {
6463
- return "canceled";
6464
- }
6465
- return result2;
6466
- }
6467
- );
6468
- return result === "canceled" ? { state: initialValue, status: "discard" } : result;
6469
- }
6470
- async execute({
6471
- eventName,
6472
- initialValue: initialState
6473
- }) {
6474
- return await this.executeMiddlewareChain({
6475
- eventName,
6476
- initialValue: initialState
6477
- });
6478
- }
6479
- };
6480
-
6481
6717
  // src/messageComposer/middleware/pollComposer/state.ts
6482
6718
  var VALID_MAX_VOTES_VALUE_REGEX = /^([2-9]|10)$/;
6483
6719
  var MAX_POLL_OPTIONS = 100;
@@ -9412,7 +9648,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
9412
9648
  id: this.id,
9413
9649
  mentioned_users: [],
9414
9650
  parent_id: this.threadId ?? void 0,
9415
- pinned_at: null,
9651
+ pinned_at: this.editedMessage?.pinned_at || null,
9416
9652
  reaction_groups: null,
9417
9653
  status: this.editedMessage ? this.editedMessage.status : "sending",
9418
9654
  text,
@@ -13240,15 +13476,17 @@ var Poll = class {
13240
13476
  const { max_votes_allowed, ownVotesByOptionId } = this.data;
13241
13477
  const reachedVoteLimit = max_votes_allowed && max_votes_allowed === Object.keys(ownVotesByOptionId).length;
13242
13478
  if (reachedVoteLimit) {
13243
- let oldestVote = Object.values(ownVotesByOptionId)[0];
13244
- Object.values(ownVotesByOptionId).slice(1).forEach((vote) => {
13245
- if (!oldestVote?.created_at || new Date(vote.created_at) < new Date(oldestVote.created_at)) {
13246
- oldestVote = vote;
13479
+ this.client.notifications.addInfo({
13480
+ message: "Reached the vote limit. Remove an existing vote first.",
13481
+ origin: {
13482
+ emitter: "Poll",
13483
+ context: { messageId, optionId }
13484
+ },
13485
+ options: {
13486
+ type: "validation:poll:castVote:limit"
13247
13487
  }
13248
13488
  });
13249
- if (oldestVote?.id) {
13250
- await this.removeVote(oldestVote.id, messageId);
13251
- }
13489
+ return;
13252
13490
  }
13253
13491
  return await this.client.castPollVote(messageId, this.id, {
13254
13492
  option_id: optionId
@@ -16731,7 +16969,7 @@ var StreamChat = class _StreamChat {
16731
16969
  if (this.userAgent) {
16732
16970
  return this.userAgent;
16733
16971
  }
16734
- const version = "9.13.0";
16972
+ const version = "9.15.0";
16735
16973
  const clientBundle = "browser-esm";
16736
16974
  let userAgentString = "";
16737
16975
  if (this.sdkIdentifier) {