stream-chat 9.12.0 → 9.14.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 (43) hide show
  1. package/dist/cjs/index.browser.cjs +452 -184
  2. package/dist/cjs/index.browser.cjs.map +4 -4
  3. package/dist/cjs/index.node.cjs +1679 -233
  4. package/dist/cjs/index.node.cjs.map +4 -4
  5. package/dist/esm/index.js +452 -184
  6. package/dist/esm/index.js.map +4 -4
  7. package/dist/types/client.d.ts +8 -1
  8. package/dist/types/messageComposer/attachmentManager.d.ts +11 -3
  9. package/dist/types/messageComposer/configuration/types.d.ts +1 -1
  10. package/dist/types/messageComposer/middleware/attachmentManager/index.d.ts +3 -0
  11. package/dist/types/messageComposer/middleware/attachmentManager/postUpload/AttachmentPostUploadMiddlewareExecutor.d.ts +5 -0
  12. package/dist/types/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.d.ts +2 -0
  13. package/dist/types/messageComposer/middleware/attachmentManager/postUpload/index.d.ts +3 -0
  14. package/dist/types/messageComposer/middleware/attachmentManager/postUpload/uploadErrorHandler.d.ts +3 -0
  15. package/dist/types/messageComposer/middleware/attachmentManager/preUpload/AttachmentPreUploadMiddlewareExecutor.d.ts +5 -0
  16. package/dist/types/messageComposer/middleware/attachmentManager/preUpload/blockedUploadNotification.d.ts +3 -0
  17. package/dist/types/messageComposer/middleware/attachmentManager/preUpload/index.d.ts +3 -0
  18. package/dist/types/messageComposer/middleware/attachmentManager/preUpload/serverUploadConfigCheck.d.ts +3 -0
  19. package/dist/types/messageComposer/middleware/attachmentManager/types.d.ts +20 -0
  20. package/dist/types/messageComposer/types.d.ts +1 -0
  21. package/dist/types/middleware.d.ts +3 -2
  22. package/dist/types/types.d.ts +14 -0
  23. package/package.json +2 -2
  24. package/src/channel_manager.ts +18 -2
  25. package/src/client.ts +13 -0
  26. package/src/messageComposer/attachmentManager.ts +116 -25
  27. package/src/messageComposer/configuration/types.ts +3 -2
  28. package/src/messageComposer/messageComposer.ts +1 -1
  29. package/src/messageComposer/middleware/attachmentManager/index.ts +3 -0
  30. package/src/messageComposer/middleware/attachmentManager/postUpload/AttachmentPostUploadMiddlewareExecutor.ts +20 -0
  31. package/src/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.ts +43 -0
  32. package/src/messageComposer/middleware/attachmentManager/postUpload/index.ts +3 -0
  33. package/src/messageComposer/middleware/attachmentManager/postUpload/uploadErrorHandler.ts +39 -0
  34. package/src/messageComposer/middleware/attachmentManager/preUpload/AttachmentPreUploadMiddlewareExecutor.ts +20 -0
  35. package/src/messageComposer/middleware/attachmentManager/preUpload/blockedUploadNotification.ts +38 -0
  36. package/src/messageComposer/middleware/attachmentManager/preUpload/index.ts +3 -0
  37. package/src/messageComposer/middleware/attachmentManager/preUpload/serverUploadConfigCheck.ts +40 -0
  38. package/src/messageComposer/middleware/attachmentManager/types.ts +32 -0
  39. package/src/messageComposer/types.ts +6 -0
  40. package/src/middleware.ts +22 -10
  41. package/src/offline-support/offline_sync_manager.ts +16 -0
  42. package/src/types.ts +17 -0
  43. package/src/utils.ts +5 -1
@@ -140,7 +140,8 @@ var require_https = __commonJS({
140
140
  // node_modules/form-data/lib/browser.js
141
141
  var require_browser = __commonJS({
142
142
  "node_modules/form-data/lib/browser.js"(exports, module2) {
143
- module2.exports = typeof self == "object" ? self.FormData : window.FormData;
143
+ "use strict";
144
+ module2.exports = typeof self === "object" ? self.FormData : window.FormData;
144
145
  }
145
146
  });
146
147
 
@@ -217,6 +218,7 @@ __export(index_exports, {
217
218
  PollComposerCompositionMiddlewareExecutor: () => PollComposerCompositionMiddlewareExecutor,
218
219
  PollComposerStateMiddlewareExecutor: () => PollComposerStateMiddlewareExecutor,
219
220
  PollManager: () => PollManager,
221
+ Product: () => Product,
220
222
  Reminder: () => Reminder,
221
223
  ReminderManager: () => ReminderManager,
222
224
  ReminderPaginator: () => ReminderPaginator,
@@ -3150,7 +3152,8 @@ var messagePaginationLinear = ({
3150
3152
  return newPagination;
3151
3153
  };
3152
3154
  var messageSetPagination = (params) => {
3153
- if (params.parentSet.messages.length < params.returnedPage.length) {
3155
+ const messagesFilteredLocally = params.returnedPage.filter(({ shadowed }) => shadowed);
3156
+ if (params.parentSet.messages.length + messagesFilteredLocally.length < params.returnedPage.length) {
3154
3157
  params.logger?.(
3155
3158
  "error",
3156
3159
  "Corrupted message set state: parent set size < returned page size"
@@ -4087,6 +4090,294 @@ var ensureIsLocalAttachment = (attachment) => {
4087
4090
  };
4088
4091
  };
4089
4092
 
4093
+ // src/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.ts
4094
+ var createPostUploadAttachmentEnrichmentMiddleware = () => ({
4095
+ id: "stream-io/attachment-manager-middleware/post-upload-enrichment",
4096
+ handlers: {
4097
+ postProcess: ({
4098
+ state,
4099
+ discard,
4100
+ forward,
4101
+ next
4102
+ }) => {
4103
+ const { attachment, error, response } = state;
4104
+ if (error) return forward();
4105
+ if (!attachment || !response) return discard();
4106
+ const enrichedAttachment = { ...attachment };
4107
+ if (isLocalImageAttachment(attachment)) {
4108
+ if (attachment.localMetadata.previewUri) {
4109
+ URL.revokeObjectURL(attachment.localMetadata.previewUri);
4110
+ delete enrichedAttachment.localMetadata.previewUri;
4111
+ }
4112
+ enrichedAttachment.image_url = response.file;
4113
+ } else {
4114
+ enrichedAttachment.asset_url = response.file;
4115
+ }
4116
+ if (response.thumb_url) {
4117
+ enrichedAttachment.thumb_url = response.thumb_url;
4118
+ }
4119
+ return next({
4120
+ ...state,
4121
+ attachment: enrichedAttachment
4122
+ });
4123
+ }
4124
+ }
4125
+ });
4126
+
4127
+ // src/utils/concurrency.ts
4128
+ var withoutConcurrency = createRunner(wrapWithContinuationTracking);
4129
+ var withCancellation = createRunner(wrapWithCancellation);
4130
+ var pendingPromises = /* @__PURE__ */ new Map();
4131
+ function createRunner(wrapper) {
4132
+ return function run(tag, cb) {
4133
+ const { cb: wrapped, onContinued } = wrapper(tag, cb);
4134
+ const pending = pendingPromises.get(tag);
4135
+ pending?.onContinued();
4136
+ const promise = pending ? pending.promise.then(wrapped, wrapped) : wrapped();
4137
+ pendingPromises.set(tag, { promise, onContinued });
4138
+ return promise;
4139
+ };
4140
+ }
4141
+ function wrapWithContinuationTracking(tag, cb) {
4142
+ let hasContinuation = false;
4143
+ const wrapped = () => cb().finally(() => {
4144
+ if (!hasContinuation) {
4145
+ pendingPromises.delete(tag);
4146
+ }
4147
+ });
4148
+ const onContinued = () => hasContinuation = true;
4149
+ return { cb: wrapped, onContinued };
4150
+ }
4151
+ function wrapWithCancellation(tag, cb) {
4152
+ const ac = new AbortController();
4153
+ const wrapped = () => {
4154
+ if (ac.signal.aborted) {
4155
+ return Promise.resolve("canceled");
4156
+ }
4157
+ return cb(ac.signal).finally(() => {
4158
+ if (!ac.signal.aborted) {
4159
+ pendingPromises.delete(tag);
4160
+ }
4161
+ });
4162
+ };
4163
+ const onContinued = () => ac.abort();
4164
+ return { cb: wrapped, onContinued };
4165
+ }
4166
+
4167
+ // src/middleware.ts
4168
+ var MiddlewareExecutor = class {
4169
+ constructor() {
4170
+ this.middleware = [];
4171
+ this.id = generateUUIDv4();
4172
+ }
4173
+ use(middleware) {
4174
+ this.middleware = this.middleware.concat(middleware);
4175
+ return this;
4176
+ }
4177
+ // todo: document how to re-arrange the order of middleware using replace
4178
+ replace(middleware) {
4179
+ const newMiddleware = [...this.middleware];
4180
+ middleware.forEach((upserted) => {
4181
+ const existingIndex = this.middleware.findIndex(
4182
+ (existing) => existing.id === upserted.id
4183
+ );
4184
+ if (existingIndex >= 0) {
4185
+ newMiddleware.splice(existingIndex, 1, upserted);
4186
+ } else {
4187
+ newMiddleware.push(upserted);
4188
+ }
4189
+ });
4190
+ this.middleware = newMiddleware;
4191
+ return this;
4192
+ }
4193
+ insert({
4194
+ middleware,
4195
+ position,
4196
+ unique
4197
+ }) {
4198
+ if (unique) {
4199
+ middleware.forEach((md) => {
4200
+ const existingMiddlewareIndex = this.middleware.findIndex((m) => m.id === md.id);
4201
+ if (existingMiddlewareIndex >= 0) {
4202
+ this.middleware.splice(existingMiddlewareIndex, 1);
4203
+ }
4204
+ });
4205
+ }
4206
+ const targetId = position.after || position.before;
4207
+ const targetIndex = this.middleware.findIndex((m) => m.id === targetId);
4208
+ const insertionIndex = position.after ? targetIndex + 1 : targetIndex;
4209
+ this.middleware.splice(insertionIndex, 0, ...middleware);
4210
+ return this;
4211
+ }
4212
+ setOrder(order) {
4213
+ this.middleware = order.map((id) => this.middleware.find((middleware) => middleware.id === id)).filter(Boolean);
4214
+ }
4215
+ async executeMiddlewareChain({
4216
+ eventName,
4217
+ initialValue,
4218
+ mode = "cancelable"
4219
+ }) {
4220
+ let index = -1;
4221
+ const execute = async (i, state, status) => {
4222
+ if (i <= index) {
4223
+ throw new Error("next() called multiple times");
4224
+ }
4225
+ index = i;
4226
+ const returnFromChain = i === this.middleware.length || status && ["complete", "discard"].includes(status);
4227
+ if (returnFromChain) return { state, status };
4228
+ const middleware = this.middleware[i];
4229
+ const handler = middleware.handlers[eventName];
4230
+ if (!handler) {
4231
+ return execute(i + 1, state, status);
4232
+ }
4233
+ const next = (adjustedState) => execute(i + 1, adjustedState);
4234
+ const complete = (adjustedState) => execute(i + 1, adjustedState, "complete");
4235
+ const discard = () => execute(i + 1, state, "discard");
4236
+ const forward = () => execute(i + 1, state);
4237
+ return await handler({
4238
+ state,
4239
+ next,
4240
+ complete,
4241
+ discard,
4242
+ forward
4243
+ });
4244
+ };
4245
+ const result = mode === "cancelable" ? await withCancellation(
4246
+ `middleware-execution-${this.id}-${eventName}`,
4247
+ async (abortSignal) => {
4248
+ const result2 = await execute(0, initialValue);
4249
+ if (abortSignal.aborted) {
4250
+ return "canceled";
4251
+ }
4252
+ return result2;
4253
+ }
4254
+ ) : await execute(0, initialValue);
4255
+ return result === "canceled" ? { state: initialValue, status: "discard" } : result;
4256
+ }
4257
+ async execute({
4258
+ eventName,
4259
+ initialValue: initialState,
4260
+ mode
4261
+ }) {
4262
+ return await this.executeMiddlewareChain({
4263
+ eventName,
4264
+ initialValue: initialState,
4265
+ mode
4266
+ });
4267
+ }
4268
+ };
4269
+
4270
+ // src/messageComposer/middleware/attachmentManager/postUpload/uploadErrorHandler.ts
4271
+ var createUploadErrorHandlerMiddleware = (composer) => ({
4272
+ id: "stream-io/attachment-manager-middleware/upload-error",
4273
+ handlers: {
4274
+ postProcess: ({
4275
+ state,
4276
+ discard,
4277
+ forward
4278
+ }) => {
4279
+ const { attachment, error } = state;
4280
+ if (!error) return forward();
4281
+ if (!attachment) return discard();
4282
+ const reason = error instanceof Error ? error.message : "unknown error";
4283
+ composer.client.notifications.addError({
4284
+ message: "Error uploading attachment",
4285
+ origin: {
4286
+ emitter: "AttachmentManager",
4287
+ context: { attachment }
4288
+ },
4289
+ options: {
4290
+ type: "api:attachment:upload:failed",
4291
+ metadata: { reason },
4292
+ originalError: error
4293
+ }
4294
+ });
4295
+ return forward();
4296
+ }
4297
+ }
4298
+ });
4299
+
4300
+ // src/messageComposer/middleware/attachmentManager/postUpload/AttachmentPostUploadMiddlewareExecutor.ts
4301
+ var AttachmentPostUploadMiddlewareExecutor = class extends MiddlewareExecutor {
4302
+ constructor({ composer }) {
4303
+ super();
4304
+ this.use([
4305
+ createUploadErrorHandlerMiddleware(composer),
4306
+ createPostUploadAttachmentEnrichmentMiddleware()
4307
+ ]);
4308
+ }
4309
+ };
4310
+
4311
+ // src/messageComposer/middleware/attachmentManager/preUpload/serverUploadConfigCheck.ts
4312
+ var createUploadConfigCheckMiddleware = (composer) => ({
4313
+ id: "stream-io/attachment-manager-middleware/file-upload-config-check",
4314
+ handlers: {
4315
+ prepare: async ({
4316
+ state,
4317
+ next,
4318
+ discard
4319
+ }) => {
4320
+ const { attachmentManager } = composer;
4321
+ if (!attachmentManager || !state.attachment) return discard();
4322
+ const uploadPermissionCheck = await attachmentManager.getUploadConfigCheck(
4323
+ state.attachment.localMetadata.file
4324
+ );
4325
+ const attachment = {
4326
+ ...state.attachment,
4327
+ localMetadata: {
4328
+ ...state.attachment.localMetadata,
4329
+ uploadPermissionCheck,
4330
+ uploadState: uploadPermissionCheck.uploadBlocked ? "blocked" : "pending"
4331
+ }
4332
+ };
4333
+ return next({
4334
+ ...state,
4335
+ attachment
4336
+ });
4337
+ }
4338
+ }
4339
+ });
4340
+
4341
+ // src/messageComposer/middleware/attachmentManager/preUpload/blockedUploadNotification.ts
4342
+ var createBlockedAttachmentUploadNotificationMiddleware = (composer) => ({
4343
+ id: "stream-io/attachment-manager-middleware/blocked-upload-notification",
4344
+ handlers: {
4345
+ prepare: ({
4346
+ state: { attachment },
4347
+ forward
4348
+ }) => {
4349
+ if (!attachment) return forward();
4350
+ if (attachment.localMetadata.uploadPermissionCheck?.uploadBlocked) {
4351
+ composer.client.notifications.addError({
4352
+ message: `The attachment upload was blocked`,
4353
+ origin: {
4354
+ emitter: "AttachmentManager",
4355
+ context: { blockedAttachment: attachment }
4356
+ },
4357
+ options: {
4358
+ type: "validation:attachment:upload:blocked",
4359
+ metadata: {
4360
+ reason: attachment.localMetadata.uploadPermissionCheck?.reason
4361
+ }
4362
+ }
4363
+ });
4364
+ }
4365
+ return forward();
4366
+ }
4367
+ }
4368
+ });
4369
+
4370
+ // src/messageComposer/middleware/attachmentManager/preUpload/AttachmentPreUploadMiddlewareExecutor.ts
4371
+ var AttachmentPreUploadMiddlewareExecutor = class extends MiddlewareExecutor {
4372
+ constructor({ composer }) {
4373
+ super();
4374
+ this.use([
4375
+ createUploadConfigCheckMiddleware(composer),
4376
+ createBlockedAttachmentUploadNotificationMiddleware(composer)
4377
+ ]);
4378
+ }
4379
+ };
4380
+
4090
4381
  // src/store.ts
4091
4382
  var isPatch = (value) => typeof value === "function";
4092
4383
  var noop2 = () => {
@@ -4678,7 +4969,7 @@ var initState = ({
4678
4969
  };
4679
4970
  })
4680
4971
  });
4681
- var AttachmentManager = class {
4972
+ var _AttachmentManager = class _AttachmentManager {
4682
4973
  constructor({ composer, message }) {
4683
4974
  this.setCustomUploadFn = (doUploadRequest) => {
4684
4975
  this.composer.updateConfig({ attachments: { doUploadRequest } });
@@ -4785,42 +5076,18 @@ var AttachmentManager = class {
4785
5076
  }
4786
5077
  return { uploadBlocked: false };
4787
5078
  };
5079
+ // @deprecated use AttachmentManager.toLocalUploadAttachment(file)
4788
5080
  this.fileToLocalUploadAttachment = async (fileLike) => {
4789
- const file = isFileReference(fileLike) || isFile2(fileLike) ? fileLike : createFileFromBlobs({
4790
- blobsArray: [fileLike],
4791
- fileName: generateFileName(fileLike.type),
4792
- mimeType: fileLike.type
4793
- });
4794
- const uploadPermissionCheck = await this.getUploadConfigCheck(file);
4795
- const localAttachment = {
4796
- file_size: file.size,
4797
- mime_type: file.type,
4798
- localMetadata: {
4799
- file,
4800
- id: generateUUIDv4(),
4801
- uploadPermissionCheck,
4802
- uploadState: uploadPermissionCheck.uploadBlocked ? "blocked" : "pending"
4803
- },
4804
- type: getAttachmentTypeFromMimeType(file.type)
4805
- };
4806
- localAttachment[isImageFile(file) ? "fallback" : "title"] = file.name;
4807
- if (isImageFile(file)) {
4808
- localAttachment.localMetadata.previewUri = isFileReference(fileLike) ? fileLike.uri : URL.createObjectURL?.(fileLike);
4809
- if (isFileReference(fileLike) && fileLike.height && fileLike.width) {
4810
- localAttachment.original_height = fileLike.height;
4811
- localAttachment.original_width = fileLike.width;
4812
- }
4813
- }
4814
- if (isFileReference(fileLike) && fileLike.thumb_url) {
4815
- localAttachment.thumb_url = fileLike.thumb_url;
4816
- }
4817
- if (isFileReference(fileLike) && fileLike.duration) {
4818
- localAttachment.duration = fileLike.duration;
4819
- }
5081
+ const localAttachment = _AttachmentManager.toLocalUploadAttachment(fileLike);
5082
+ const uploadPermissionCheck = await this.getUploadConfigCheck(
5083
+ localAttachment.localMetadata.file
5084
+ );
5085
+ localAttachment.localMetadata.uploadPermissionCheck = uploadPermissionCheck;
5086
+ localAttachment.localMetadata.uploadState = uploadPermissionCheck.uploadBlocked ? "blocked" : "pending";
4820
5087
  return localAttachment;
4821
5088
  };
4822
5089
  this.ensureLocalUploadAttachment = async (attachment) => {
4823
- if (!attachment.localMetadata?.file || !attachment.localMetadata.id) {
5090
+ if (!attachment.localMetadata?.file) {
4824
5091
  this.client.notifications.addError({
4825
5092
  message: "File is required for upload attachment",
4826
5093
  origin: { emitter: "AttachmentManager", context: { attachment } },
@@ -4828,6 +5095,14 @@ var AttachmentManager = class {
4828
5095
  });
4829
5096
  return;
4830
5097
  }
5098
+ if (!attachment.localMetadata.id) {
5099
+ this.client.notifications.addError({
5100
+ message: "Local upload attachment missing local id",
5101
+ origin: { emitter: "AttachmentManager", context: { attachment } },
5102
+ options: { type: "validation:attachment:id:missing" }
5103
+ });
5104
+ return;
5105
+ }
4831
5106
  if (!this.fileUploadFilter(attachment)) return;
4832
5107
  const newAttachment = await this.fileToLocalUploadAttachment(
4833
5108
  attachment.localMetadata.file
@@ -4867,6 +5142,7 @@ var AttachmentManager = class {
4867
5142
  }
4868
5143
  return this.doDefaultUploadRequest(fileLike);
4869
5144
  };
5145
+ // @deprecated use attachmentManager.uploadFile(file)
4870
5146
  this.uploadAttachment = async (attachment) => {
4871
5147
  if (!this.isUploadEnabled) return;
4872
5148
  const localAttachment = await this.ensureLocalUploadAttachment(attachment);
@@ -4950,19 +5226,75 @@ var AttachmentManager = class {
4950
5226
  this.updateAttachment(uploadedAttachment);
4951
5227
  return uploadedAttachment;
4952
5228
  };
5229
+ this.uploadFile = async (file) => {
5230
+ const preUpload = await this.preUploadMiddlewareExecutor.execute({
5231
+ eventName: "prepare",
5232
+ initialValue: {
5233
+ attachment: _AttachmentManager.toLocalUploadAttachment(file)
5234
+ },
5235
+ mode: "concurrent"
5236
+ });
5237
+ let attachment = preUpload.state.attachment;
5238
+ if (preUpload.status === "discard") return attachment;
5239
+ if (!this.fileUploadFilter(attachment)) return attachment;
5240
+ if (attachment.localMetadata.uploadState === "blocked") {
5241
+ this.upsertAttachments([attachment]);
5242
+ return preUpload.state.attachment;
5243
+ }
5244
+ attachment = {
5245
+ ...attachment,
5246
+ localMetadata: {
5247
+ ...attachment.localMetadata,
5248
+ uploadState: "uploading"
5249
+ }
5250
+ };
5251
+ this.upsertAttachments([attachment]);
5252
+ let response;
5253
+ let error;
5254
+ try {
5255
+ response = await this.doUploadRequest(file);
5256
+ } catch (err) {
5257
+ error = err instanceof Error ? err : void 0;
5258
+ }
5259
+ const postUpload = await this.postUploadMiddlewareExecutor.execute({
5260
+ eventName: "postProcess",
5261
+ initialValue: {
5262
+ attachment: {
5263
+ ...attachment,
5264
+ localMetadata: {
5265
+ ...attachment.localMetadata,
5266
+ uploadState: error ? "failed" : "finished"
5267
+ }
5268
+ },
5269
+ error,
5270
+ response
5271
+ },
5272
+ mode: "concurrent"
5273
+ });
5274
+ attachment = postUpload.state.attachment;
5275
+ if (postUpload.status === "discard") {
5276
+ this.removeAttachments([attachment.localMetadata.id]);
5277
+ return attachment;
5278
+ }
5279
+ this.updateAttachment(attachment);
5280
+ return attachment;
5281
+ };
4953
5282
  this.uploadFiles = async (files) => {
4954
5283
  if (!this.isUploadEnabled) return;
4955
5284
  const iterableFiles = isFileList2(files) ? Array.from(files) : files;
4956
- const attachments = await Promise.all(
4957
- iterableFiles.map(this.fileToLocalUploadAttachment)
4958
- );
4959
- return Promise.all(
4960
- attachments.filter(this.fileUploadFilter).slice(0, this.availableUploadSlots).map(this.uploadAttachment)
5285
+ return await Promise.all(
5286
+ iterableFiles.slice(0, this.availableUploadSlots).map(this.uploadFile)
4961
5287
  );
4962
5288
  };
4963
5289
  this.composer = composer;
4964
5290
  this.state = new StateStore(initState({ message }));
4965
5291
  this.attachmentsByIdGetterCache = { attachmentsById: {}, attachments: [] };
5292
+ this.preUploadMiddlewareExecutor = new AttachmentPreUploadMiddlewareExecutor({
5293
+ composer
5294
+ });
5295
+ this.postUploadMiddlewareExecutor = new AttachmentPostUploadMiddlewareExecutor({
5296
+ composer
5297
+ });
4966
5298
  }
4967
5299
  get attachmentsById() {
4968
5300
  const { attachments } = this.state.getLatestValue();
@@ -4992,9 +5324,15 @@ var AttachmentManager = class {
4992
5324
  set acceptedFiles(acceptedFiles) {
4993
5325
  this.composer.updateConfig({ attachments: { acceptedFiles } });
4994
5326
  }
5327
+ /*
5328
+ @deprecated attachments can be filtered using injecting pre-upload middleware
5329
+ */
4995
5330
  get fileUploadFilter() {
4996
5331
  return this.config.fileUploadFilter;
4997
5332
  }
5333
+ /*
5334
+ @deprecated attachments can be filtered using injecting pre-upload middleware
5335
+ */
4998
5336
  set fileUploadFilter(fileUploadFilter) {
4999
5337
  this.composer.updateConfig({ attachments: { fileUploadFilter } });
5000
5338
  }
@@ -5041,6 +5379,39 @@ var AttachmentManager = class {
5041
5379
  );
5042
5380
  }
5043
5381
  };
5382
+ _AttachmentManager.toLocalUploadAttachment = (fileLike) => {
5383
+ const file = isFileReference(fileLike) || isFile2(fileLike) ? fileLike : createFileFromBlobs({
5384
+ blobsArray: [fileLike],
5385
+ fileName: generateFileName(fileLike.type),
5386
+ mimeType: fileLike.type
5387
+ });
5388
+ const localAttachment = {
5389
+ file_size: file.size,
5390
+ mime_type: file.type,
5391
+ localMetadata: {
5392
+ file,
5393
+ id: generateUUIDv4(),
5394
+ uploadState: "pending"
5395
+ },
5396
+ type: getAttachmentTypeFromMimeType(file.type)
5397
+ };
5398
+ localAttachment[isImageFile(file) ? "fallback" : "title"] = file.name;
5399
+ if (isImageFile(file)) {
5400
+ localAttachment.localMetadata.previewUri = isFileReference(fileLike) ? fileLike.uri : URL.createObjectURL?.(fileLike);
5401
+ if (isFileReference(fileLike) && fileLike.height && fileLike.width) {
5402
+ localAttachment.original_height = fileLike.height;
5403
+ localAttachment.original_width = fileLike.width;
5404
+ }
5405
+ }
5406
+ if (isFileReference(fileLike) && fileLike.thumb_url) {
5407
+ localAttachment.thumb_url = fileLike.thumb_url;
5408
+ }
5409
+ if (isFileReference(fileLike) && fileLike.duration) {
5410
+ localAttachment.duration = fileLike.duration;
5411
+ }
5412
+ return localAttachment;
5413
+ };
5414
+ var AttachmentManager = _AttachmentManager;
5044
5415
 
5045
5416
  // src/messageComposer/configuration/configuration.ts
5046
5417
  var import_linkifyjs = require("linkifyjs");
@@ -5380,146 +5751,6 @@ var LocationComposer = class {
5380
5751
  }
5381
5752
  };
5382
5753
 
5383
- // src/utils/concurrency.ts
5384
- var withoutConcurrency = createRunner(wrapWithContinuationTracking);
5385
- var withCancellation = createRunner(wrapWithCancellation);
5386
- var pendingPromises = /* @__PURE__ */ new Map();
5387
- function createRunner(wrapper) {
5388
- return function run(tag, cb) {
5389
- const { cb: wrapped, onContinued } = wrapper(tag, cb);
5390
- const pending = pendingPromises.get(tag);
5391
- pending?.onContinued();
5392
- const promise = pending ? pending.promise.then(wrapped, wrapped) : wrapped();
5393
- pendingPromises.set(tag, { promise, onContinued });
5394
- return promise;
5395
- };
5396
- }
5397
- function wrapWithContinuationTracking(tag, cb) {
5398
- let hasContinuation = false;
5399
- const wrapped = () => cb().finally(() => {
5400
- if (!hasContinuation) {
5401
- pendingPromises.delete(tag);
5402
- }
5403
- });
5404
- const onContinued = () => hasContinuation = true;
5405
- return { cb: wrapped, onContinued };
5406
- }
5407
- function wrapWithCancellation(tag, cb) {
5408
- const ac = new AbortController();
5409
- const wrapped = () => {
5410
- if (ac.signal.aborted) {
5411
- return Promise.resolve("canceled");
5412
- }
5413
- return cb(ac.signal).finally(() => {
5414
- if (!ac.signal.aborted) {
5415
- pendingPromises.delete(tag);
5416
- }
5417
- });
5418
- };
5419
- const onContinued = () => ac.abort();
5420
- return { cb: wrapped, onContinued };
5421
- }
5422
-
5423
- // src/middleware.ts
5424
- var MiddlewareExecutor = class {
5425
- constructor() {
5426
- this.middleware = [];
5427
- this.id = generateUUIDv4();
5428
- }
5429
- use(middleware) {
5430
- this.middleware = this.middleware.concat(middleware);
5431
- return this;
5432
- }
5433
- // todo: document how to re-arrange the order of middleware using replace
5434
- replace(middleware) {
5435
- const newMiddleware = [...this.middleware];
5436
- middleware.forEach((upserted) => {
5437
- const existingIndex = this.middleware.findIndex(
5438
- (existing) => existing.id === upserted.id
5439
- );
5440
- if (existingIndex >= 0) {
5441
- newMiddleware.splice(existingIndex, 1, upserted);
5442
- } else {
5443
- newMiddleware.push(upserted);
5444
- }
5445
- });
5446
- this.middleware = newMiddleware;
5447
- return this;
5448
- }
5449
- insert({
5450
- middleware,
5451
- position,
5452
- unique
5453
- }) {
5454
- if (unique) {
5455
- middleware.forEach((md) => {
5456
- const existingMiddlewareIndex = this.middleware.findIndex((m) => m.id === md.id);
5457
- if (existingMiddlewareIndex >= 0) {
5458
- this.middleware.splice(existingMiddlewareIndex, 1);
5459
- }
5460
- });
5461
- }
5462
- const targetId = position.after || position.before;
5463
- const targetIndex = this.middleware.findIndex((m) => m.id === targetId);
5464
- const insertionIndex = position.after ? targetIndex + 1 : targetIndex;
5465
- this.middleware.splice(insertionIndex, 0, ...middleware);
5466
- return this;
5467
- }
5468
- setOrder(order) {
5469
- this.middleware = order.map((id) => this.middleware.find((middleware) => middleware.id === id)).filter(Boolean);
5470
- }
5471
- async executeMiddlewareChain({
5472
- eventName,
5473
- initialValue
5474
- }) {
5475
- let index = -1;
5476
- const execute = async (i, state, status) => {
5477
- if (i <= index) {
5478
- throw new Error("next() called multiple times");
5479
- }
5480
- index = i;
5481
- const returnFromChain = i === this.middleware.length || status && ["complete", "discard"].includes(status);
5482
- if (returnFromChain) return { state, status };
5483
- const middleware = this.middleware[i];
5484
- const handler = middleware.handlers[eventName];
5485
- if (!handler) {
5486
- return execute(i + 1, state, status);
5487
- }
5488
- const next = (adjustedState) => execute(i + 1, adjustedState);
5489
- const complete = (adjustedState) => execute(i + 1, adjustedState, "complete");
5490
- const discard = () => execute(i + 1, state, "discard");
5491
- const forward = () => execute(i + 1, state);
5492
- return await handler({
5493
- state,
5494
- next,
5495
- complete,
5496
- discard,
5497
- forward
5498
- });
5499
- };
5500
- const result = await withCancellation(
5501
- `middleware-execution-${this.id}-${eventName}`,
5502
- async (abortSignal) => {
5503
- const result2 = await execute(0, initialValue);
5504
- if (abortSignal.aborted) {
5505
- return "canceled";
5506
- }
5507
- return result2;
5508
- }
5509
- );
5510
- return result === "canceled" ? { state: initialValue, status: "discard" } : result;
5511
- }
5512
- async execute({
5513
- eventName,
5514
- initialValue: initialState
5515
- }) {
5516
- return await this.executeMiddlewareChain({
5517
- eventName,
5518
- initialValue: initialState
5519
- });
5520
- }
5521
- };
5522
-
5523
5754
  // src/messageComposer/middleware/pollComposer/state.ts
5524
5755
  var VALID_MAX_VOTES_VALUE_REGEX = /^([2-9]|10)$/;
5525
5756
  var MAX_POLL_OPTIONS = 100;
@@ -5748,6 +5979,13 @@ var PollComposerStateMiddlewareExecutor = class extends MiddlewareExecutor {
5748
5979
  };
5749
5980
 
5750
5981
  // src/types.ts
5982
+ var Product = /* @__PURE__ */ ((Product2) => {
5983
+ Product2["Chat"] = "chat";
5984
+ Product2["Video"] = "video";
5985
+ Product2["Moderation"] = "moderation";
5986
+ Product2["Feeds"] = "feeds";
5987
+ return Product2;
5988
+ })(Product || {});
5751
5989
  var ErrorFromResponse = class extends Error {
5752
5990
  constructor(message, {
5753
5991
  code,
@@ -8447,7 +8685,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8447
8685
  id: this.id,
8448
8686
  mentioned_users: [],
8449
8687
  parent_id: this.threadId ?? void 0,
8450
- pinned_at: null,
8688
+ pinned_at: this.editedMessage?.pinned_at || null,
8451
8689
  reaction_groups: null,
8452
8690
  status: this.editedMessage ? this.editedMessage.status : "sending",
8453
8691
  text,
@@ -12605,7 +12843,16 @@ var ChannelManager = class extends WithSubscriptions {
12605
12843
  const wrappedError = new Error(
12606
12844
  `Maximum number of retries reached in queryChannels. Last error message is: ${err}`
12607
12845
  );
12608
- this.state.partialNext({ error: wrappedError });
12846
+ const state = this.state.getLatestValue();
12847
+ const isOfflineSupportEnabledWithChannels = this.client.offlineDb && state.channels.length > 0;
12848
+ this.state.partialNext({
12849
+ error: isOfflineSupportEnabledWithChannels ? void 0 : wrappedError,
12850
+ pagination: {
12851
+ ...state.pagination,
12852
+ isLoading: false,
12853
+ isLoadingNext: false
12854
+ }
12855
+ });
12609
12856
  return;
12610
12857
  }
12611
12858
  await sleep(DEFAULT_QUERY_CHANNELS_MS_BETWEEN_RETRIES);
@@ -12710,7 +12957,11 @@ var ChannelManager = class extends WithSubscriptions {
12710
12957
  this.client.logger("error", error.message);
12711
12958
  this.state.next((currentState) => ({
12712
12959
  ...currentState,
12713
- pagination: { ...currentState.pagination, isLoadingNext: false }
12960
+ pagination: {
12961
+ ...currentState.pagination,
12962
+ isLoadingNext: false,
12963
+ isLoading: false
12964
+ }
12714
12965
  }));
12715
12966
  throw error;
12716
12967
  }
@@ -14962,6 +15213,16 @@ var StreamChat = class _StreamChat {
14962
15213
  endpoints: endpoints ? endpoints.join(",") : void 0
14963
15214
  });
14964
15215
  }
15216
+ /**
15217
+ * getHookEvents - Get available events for hooks (webhook, SQS, and SNS)
15218
+ *
15219
+ * @param {Product[]} [products] Optional array of products to filter events by (e.g., [Product.Chat, Product.Video])
15220
+ * @returns {Promise<GetHookEventsResponse>} Response containing available hook events
15221
+ */
15222
+ async getHookEvents(products) {
15223
+ const params = products && products.length > 0 ? { product: products.join(",") } : {};
15224
+ return await this.get(this.baseURL + "/hook/events", params);
15225
+ }
14965
15226
  _addChannelConfig({ cid, config }) {
14966
15227
  if (this._cacheEnabled()) {
14967
15228
  this.configs[cid] = config;
@@ -15743,7 +16004,7 @@ var StreamChat = class _StreamChat {
15743
16004
  if (this.userAgent) {
15744
16005
  return this.userAgent;
15745
16006
  }
15746
- const version = "9.12.0";
16007
+ const version = "9.14.0";
15747
16008
  const clientBundle = "browser-cjs";
15748
16009
  let userAgentString = "";
15749
16010
  if (this.sdkIdentifier) {
@@ -17180,6 +17441,13 @@ var OfflineDBSyncManager = class {
17180
17441
  });
17181
17442
  } catch (e) {
17182
17443
  console.log("An error has occurred while syncing the DB.", e);
17444
+ if (isAxiosError2(e) && e.code === "ECONNABORTED") {
17445
+ return;
17446
+ }
17447
+ const error = e;
17448
+ if (error.response?.data?.code === 23) {
17449
+ return;
17450
+ }
17183
17451
  await this.offlineDb.resetDB();
17184
17452
  }
17185
17453
  };