stream-chat 9.11.0 → 9.13.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 (40) hide show
  1. package/dist/cjs/index.browser.cjs +437 -23
  2. package/dist/cjs/index.browser.cjs.map +4 -4
  3. package/dist/cjs/index.node.cjs +451 -30
  4. package/dist/cjs/index.node.cjs.map +4 -4
  5. package/dist/esm/index.js +437 -23
  6. package/dist/esm/index.js.map +4 -4
  7. package/dist/types/LiveLocationManager.d.ts +54 -0
  8. package/dist/types/channel.d.ts +3 -1
  9. package/dist/types/channel_manager.d.ts +5 -1
  10. package/dist/types/client.d.ts +14 -6
  11. package/dist/types/events.d.ts +2 -0
  12. package/dist/types/index.d.ts +1 -0
  13. package/dist/types/messageComposer/LocationComposer.d.ts +34 -0
  14. package/dist/types/messageComposer/attachmentIdentity.d.ts +2 -1
  15. package/dist/types/messageComposer/configuration/configuration.d.ts +2 -1
  16. package/dist/types/messageComposer/configuration/types.d.ts +11 -0
  17. package/dist/types/messageComposer/index.d.ts +1 -0
  18. package/dist/types/messageComposer/messageComposer.d.ts +7 -2
  19. package/dist/types/messageComposer/middleware/messageComposer/index.d.ts +1 -0
  20. package/dist/types/messageComposer/middleware/messageComposer/sharedLocation.d.ts +3 -0
  21. package/dist/types/types.d.ts +58 -5
  22. package/package.json +1 -1
  23. package/src/LiveLocationManager.ts +297 -0
  24. package/src/channel.ts +34 -0
  25. package/src/channel_manager.ts +33 -4
  26. package/src/client.ts +27 -5
  27. package/src/events.ts +2 -0
  28. package/src/index.ts +1 -0
  29. package/src/messageComposer/LocationComposer.ts +94 -0
  30. package/src/messageComposer/attachmentIdentity.ts +8 -1
  31. package/src/messageComposer/configuration/configuration.ts +8 -0
  32. package/src/messageComposer/configuration/types.ts +14 -0
  33. package/src/messageComposer/index.ts +1 -0
  34. package/src/messageComposer/messageComposer.ts +81 -9
  35. package/src/messageComposer/middleware/messageComposer/MessageComposerMiddlewareExecutor.ts +2 -0
  36. package/src/messageComposer/middleware/messageComposer/compositionValidation.ts +1 -5
  37. package/src/messageComposer/middleware/messageComposer/index.ts +1 -0
  38. package/src/messageComposer/middleware/messageComposer/sharedLocation.ts +42 -0
  39. package/src/offline-support/offline_sync_manager.ts +16 -0
  40. package/src/types.ts +63 -5
@@ -178,6 +178,7 @@ __export(index_exports, {
178
178
  DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS: () => DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS,
179
179
  DEFAULT_COMPOSER_CONFIG: () => DEFAULT_COMPOSER_CONFIG,
180
180
  DEFAULT_LINK_PREVIEW_MANAGER_CONFIG: () => DEFAULT_LINK_PREVIEW_MANAGER_CONFIG,
181
+ DEFAULT_LOCATION_COMPOSER_CONFIG: () => DEFAULT_LOCATION_COMPOSER_CONFIG,
181
182
  DEFAULT_PAGINATION_OPTIONS: () => DEFAULT_PAGINATION_OPTIONS,
182
183
  DEFAULT_REMINDER_MANAGER_CONFIG: () => DEFAULT_REMINDER_MANAGER_CONFIG,
183
184
  DEFAULT_STOP_REFRESH_BOUNDARY_MS: () => DEFAULT_STOP_REFRESH_BOUNDARY_MS,
@@ -193,6 +194,8 @@ __export(index_exports, {
193
194
  JWTUserToken: () => JWTUserToken,
194
195
  LinkPreviewStatus: () => LinkPreviewStatus,
195
196
  LinkPreviewsManager: () => LinkPreviewsManager,
197
+ LiveLocationManager: () => LiveLocationManager,
198
+ LocationComposer: () => LocationComposer,
196
199
  MAX_POLL_OPTIONS: () => MAX_POLL_OPTIONS,
197
200
  MODERATION_ENTITY_TYPES: () => MODERATION_ENTITY_TYPES,
198
201
  MaxPriority: () => MaxPriority,
@@ -214,6 +217,7 @@ __export(index_exports, {
214
217
  PollComposerCompositionMiddlewareExecutor: () => PollComposerCompositionMiddlewareExecutor,
215
218
  PollComposerStateMiddlewareExecutor: () => PollComposerStateMiddlewareExecutor,
216
219
  PollManager: () => PollManager,
220
+ Product: () => Product,
217
221
  Reminder: () => Reminder,
218
222
  ReminderManager: () => ReminderManager,
219
223
  ReminderPaginator: () => ReminderPaginator,
@@ -229,6 +233,7 @@ __export(index_exports, {
229
233
  Thread: () => Thread,
230
234
  ThreadManager: () => ThreadManager,
231
235
  TokenManager: () => TokenManager,
236
+ UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT: () => UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT,
232
237
  UserFromToken: () => UserFromToken,
233
238
  UserSearchSource: () => UserSearchSource,
234
239
  VALID_MAX_VOTES_VALUE_REGEX: () => VALID_MAX_VOTES_VALUE_REGEX,
@@ -259,6 +264,7 @@ __export(index_exports, {
259
264
  createMentionsMiddleware: () => createMentionsMiddleware,
260
265
  createMessageComposerStateCompositionMiddleware: () => createMessageComposerStateCompositionMiddleware,
261
266
  createPollComposerStateMiddleware: () => createPollComposerStateMiddleware,
267
+ createSharedLocationCompositionMiddleware: () => createSharedLocationCompositionMiddleware,
262
268
  createTextComposerCompositionMiddleware: () => createTextComposerCompositionMiddleware,
263
269
  createTextComposerPreValidationMiddleware: () => createTextComposerPreValidationMiddleware,
264
270
  decodeBase64: () => decodeBase64,
@@ -295,6 +301,7 @@ __export(index_exports, {
295
301
  isOwnUser: () => isOwnUser,
296
302
  isPatch: () => isPatch,
297
303
  isScrapedContent: () => isScrapedContent,
304
+ isSharedLocationResponse: () => isSharedLocationResponse,
298
305
  isTargetedOptionTextUpdate: () => isTargetedOptionTextUpdate,
299
306
  isUploadedAttachment: () => isUploadedAttachment,
300
307
  isVideoAttachment: () => isVideoAttachment,
@@ -4019,6 +4026,7 @@ var isLocalVoiceRecordingAttachment = (attachment) => isVoiceRecordingAttachment
4019
4026
  var isVideoAttachment = (attachment, supportedVideoFormat = []) => attachment.type === "video" || !!(attachment.mime_type && supportedVideoFormat.indexOf(attachment.mime_type) !== -1);
4020
4027
  var isLocalVideoAttachment = (attachment) => isVideoAttachment(attachment) && isLocalAttachment(attachment);
4021
4028
  var isUploadedAttachment = (attachment) => isAudioAttachment(attachment) || isFileAttachment(attachment) || isImageAttachment(attachment) || isVideoAttachment(attachment) || isVoiceRecordingAttachment(attachment);
4029
+ var isSharedLocationResponse = (location) => !!location.latitude && !!location.longitude && !!location.channel_cid;
4022
4030
 
4023
4031
  // src/messageComposer/fileUtils.ts
4024
4032
  var isFile2 = (fileLike) => !!fileLike.lastModified && !("uri" in fileLike);
@@ -5061,10 +5069,15 @@ var DEFAULT_TEXT_COMPOSER_CONFIG = {
5061
5069
  enabled: true,
5062
5070
  publishTypingEvents: true
5063
5071
  };
5072
+ var DEFAULT_LOCATION_COMPOSER_CONFIG = {
5073
+ enabled: true,
5074
+ getDeviceId: () => generateUUIDv4()
5075
+ };
5064
5076
  var DEFAULT_COMPOSER_CONFIG = {
5065
5077
  attachments: DEFAULT_ATTACHMENT_MANAGER_CONFIG,
5066
5078
  drafts: { enabled: false },
5067
5079
  linkPreviews: DEFAULT_LINK_PREVIEW_MANAGER_CONFIG,
5080
+ location: DEFAULT_LOCATION_COMPOSER_CONFIG,
5068
5081
  text: DEFAULT_TEXT_COMPOSER_CONFIG
5069
5082
  };
5070
5083
 
@@ -5320,6 +5333,54 @@ _LinkPreviewsManager.getPreviewData = (preview) => {
5320
5333
  };
5321
5334
  var LinkPreviewsManager = _LinkPreviewsManager;
5322
5335
 
5336
+ // src/messageComposer/LocationComposer.ts
5337
+ var MIN_LIVE_LOCATION_SHARE_DURATION = 60 * 1e3;
5338
+ var initState4 = ({
5339
+ message
5340
+ }) => ({
5341
+ location: message?.shared_location ?? null
5342
+ });
5343
+ var LocationComposer = class {
5344
+ constructor({ composer, message }) {
5345
+ this.initState = ({ message } = {}) => {
5346
+ this.state.next(initState4({ message }));
5347
+ };
5348
+ this.setData = (data) => {
5349
+ if (!this.config.enabled) return;
5350
+ if (!data.latitude || !data.longitude) return;
5351
+ this.state.partialNext({
5352
+ location: {
5353
+ ...data,
5354
+ message_id: this.composer.id,
5355
+ created_by_device_id: this.deviceId
5356
+ }
5357
+ });
5358
+ };
5359
+ this.composer = composer;
5360
+ this.state = new StateStore(initState4({ message }));
5361
+ this._deviceId = this.config.getDeviceId();
5362
+ }
5363
+ get config() {
5364
+ return this.composer.config.location;
5365
+ }
5366
+ get deviceId() {
5367
+ return this._deviceId;
5368
+ }
5369
+ get location() {
5370
+ return this.state.getLatestValue().location;
5371
+ }
5372
+ get validLocation() {
5373
+ const { durationMs, ...location } = this.location ?? {};
5374
+ if (!!location?.created_by_device_id && location.message_id && location.latitude && location.longitude && (typeof durationMs === "undefined" || durationMs >= MIN_LIVE_LOCATION_SHARE_DURATION)) {
5375
+ return {
5376
+ ...location,
5377
+ end_at: durationMs && new Date(Date.now() + durationMs).toISOString()
5378
+ };
5379
+ }
5380
+ return null;
5381
+ }
5382
+ };
5383
+
5323
5384
  // src/utils/concurrency.ts
5324
5385
  var withoutConcurrency = createRunner(wrapWithContinuationTracking);
5325
5386
  var withCancellation = createRunner(wrapWithCancellation);
@@ -5688,6 +5749,13 @@ var PollComposerStateMiddlewareExecutor = class extends MiddlewareExecutor {
5688
5749
  };
5689
5750
 
5690
5751
  // src/types.ts
5752
+ var Product = /* @__PURE__ */ ((Product2) => {
5753
+ Product2["Chat"] = "chat";
5754
+ Product2["Video"] = "video";
5755
+ Product2["Moderation"] = "moderation";
5756
+ Product2["Feeds"] = "feeds";
5757
+ return Product2;
5758
+ })(Product || {});
5691
5759
  var ErrorFromResponse = class extends Error {
5692
5760
  constructor(message, {
5693
5761
  code,
@@ -6003,9 +6071,8 @@ var createCompositionValidationMiddleware = (composer) => ({
6003
6071
  }) => {
6004
6072
  const { maxLengthOnSend } = composer.config.text ?? {};
6005
6073
  const inputText = state.message.text ?? "";
6006
- const isEmptyMessage = textIsEmpty(inputText) && !state.message.attachments?.length && !state.message.poll_id;
6007
6074
  const hasExceededMaxLength = typeof maxLengthOnSend === "number" && inputText.length > maxLengthOnSend;
6008
- if (isEmptyMessage || hasExceededMaxLength) {
6075
+ if (composer.compositionIsEmpty || hasExceededMaxLength) {
6009
6076
  return await discard();
6010
6077
  }
6011
6078
  return await forward();
@@ -6285,6 +6352,40 @@ var createPollOnlyCompositionMiddleware = (composer) => ({
6285
6352
  }
6286
6353
  });
6287
6354
 
6355
+ // src/messageComposer/middleware/messageComposer/sharedLocation.ts
6356
+ var createSharedLocationCompositionMiddleware = (composer) => ({
6357
+ id: "stream-io/message-composer-middleware/shared-location",
6358
+ handlers: {
6359
+ compose: ({
6360
+ state,
6361
+ next,
6362
+ forward
6363
+ }) => {
6364
+ const { locationComposer } = composer;
6365
+ const location = locationComposer.validLocation;
6366
+ if (!locationComposer || !location || !composer.client.user) return forward();
6367
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
6368
+ return next({
6369
+ ...state,
6370
+ localMessage: {
6371
+ ...state.localMessage,
6372
+ shared_location: {
6373
+ ...location,
6374
+ channel_cid: composer.channel.cid,
6375
+ created_at: timestamp,
6376
+ updated_at: timestamp,
6377
+ user_id: composer.client.user.id
6378
+ }
6379
+ },
6380
+ message: {
6381
+ ...state.message,
6382
+ shared_location: location
6383
+ }
6384
+ });
6385
+ }
6386
+ }
6387
+ });
6388
+
6288
6389
  // src/messageComposer/middleware/messageComposer/MessageComposerMiddlewareExecutor.ts
6289
6390
  var MessageComposerMiddlewareExecutor = class extends MiddlewareExecutor {
6290
6391
  constructor({ composer }) {
@@ -6295,6 +6396,7 @@ var MessageComposerMiddlewareExecutor = class extends MiddlewareExecutor {
6295
6396
  createTextComposerCompositionMiddleware(composer),
6296
6397
  createAttachmentsCompositionMiddleware(composer),
6297
6398
  createLinkPreviewsCompositionMiddleware(composer),
6399
+ createSharedLocationCompositionMiddleware(composer),
6298
6400
  createMessageComposerStateCompositionMiddleware(composer),
6299
6401
  createCustomDataCompositionMiddleware(composer),
6300
6402
  createCompositionValidationMiddleware(composer),
@@ -7336,7 +7438,7 @@ var textIsEmpty = (text) => {
7336
7438
  const trimmedText = text.trim();
7337
7439
  return trimmedText === "" || trimmedText === ">" || trimmedText === "``````" || trimmedText === "``" || trimmedText === "**" || trimmedText === "____" || trimmedText === "__" || trimmedText === "****";
7338
7440
  };
7339
- var initState4 = ({
7441
+ var initState5 = ({
7340
7442
  composer,
7341
7443
  message
7342
7444
  }) => {
@@ -7361,7 +7463,7 @@ var initState4 = ({
7361
7463
  var TextComposer = class {
7362
7464
  constructor({ composer, message }) {
7363
7465
  this.initState = ({ message } = {}) => {
7364
- this.state.next(initState4({ composer: this.composer, message }));
7466
+ this.state.next(initState5({ composer: this.composer, message }));
7365
7467
  };
7366
7468
  this.upsertMentionedUser = (user) => {
7367
7469
  const mentionedUsers = [...this.mentionedUsers];
@@ -7489,7 +7591,7 @@ var TextComposer = class {
7489
7591
  this.state.next(output.state);
7490
7592
  };
7491
7593
  this.composer = composer;
7492
- this.state = new StateStore(initState4({ composer, message }));
7594
+ this.state = new StateStore(initState5({ composer, message }));
7493
7595
  this.middlewareExecutor = new TextComposerMiddlewareExecutor({ composer });
7494
7596
  }
7495
7597
  get channel() {
@@ -8062,7 +8164,7 @@ var initEditingAuditState = (composition) => {
8062
8164
  }
8063
8165
  };
8064
8166
  };
8065
- var initState5 = (composition) => {
8167
+ var initState6 = (composition) => {
8066
8168
  if (!composition) {
8067
8169
  return {
8068
8170
  draftId: null,
@@ -8100,6 +8202,9 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8100
8202
  client
8101
8203
  }) {
8102
8204
  super();
8205
+ this.refreshId = () => {
8206
+ this.state.partialNext({ id: _MessageComposer.generateId() });
8207
+ };
8103
8208
  this.initState = ({
8104
8209
  composition
8105
8210
  } = {}) => {
@@ -8107,10 +8212,11 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8107
8212
  const message = typeof composition === "undefined" ? composition : compositionIsDraftResponse(composition) ? composition.message : formatMessage(composition);
8108
8213
  this.attachmentManager.initState({ message });
8109
8214
  this.linkPreviewsManager.initState({ message });
8215
+ this.locationComposer.initState({ message });
8110
8216
  this.textComposer.initState({ message });
8111
8217
  this.pollComposer.initState();
8112
8218
  this.customDataManager.initState({ message });
8113
- this.state.next(initState5(composition));
8219
+ this.state.next(initState6(composition));
8114
8220
  if (composition && !compositionIsDraftResponse(composition) && message && isLocalMessage(message)) {
8115
8221
  this.editedMessage = message;
8116
8222
  }
@@ -8150,6 +8256,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8150
8256
  this.addUnsubscribeFunction(this.subscribeTextComposerStateChanged());
8151
8257
  this.addUnsubscribeFunction(this.subscribeAttachmentManagerStateChanged());
8152
8258
  this.addUnsubscribeFunction(this.subscribeLinkPreviewsManagerStateChanged());
8259
+ this.addUnsubscribeFunction(this.subscribeLocationComposerStateChanged());
8153
8260
  this.addUnsubscribeFunction(this.subscribePollComposerStateChanged());
8154
8261
  this.addUnsubscribeFunction(this.subscribeCustomDataManagerStateChanged());
8155
8262
  this.addUnsubscribeFunction(this.subscribeMessageComposerStateChanged());
@@ -8246,6 +8353,14 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8246
8353
  return;
8247
8354
  }
8248
8355
  });
8356
+ this.subscribeLocationComposerStateChanged = () => this.locationComposer.state.subscribe((_, previousValue) => {
8357
+ if (typeof previousValue === "undefined") return;
8358
+ this.logStateUpdateTimestamp();
8359
+ if (this.compositionIsEmpty) {
8360
+ this.deleteDraft();
8361
+ return;
8362
+ }
8363
+ });
8249
8364
  this.subscribeLinkPreviewsManagerStateChanged = () => this.linkPreviewsManager.state.subscribe((_, previousValue) => {
8250
8365
  if (typeof previousValue === "undefined") return;
8251
8366
  this.logStateUpdateTimestamp();
@@ -8466,10 +8581,32 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8466
8581
  throw error;
8467
8582
  }
8468
8583
  };
8584
+ this.sendLocation = async () => {
8585
+ const location = this.locationComposer.validLocation;
8586
+ if (this.threadId || !location) return;
8587
+ try {
8588
+ await this.channel.sendSharedLocation(location);
8589
+ this.refreshId();
8590
+ this.locationComposer.initState();
8591
+ } catch (error) {
8592
+ this.client.notifications.addError({
8593
+ message: "Failed to share the location",
8594
+ origin: {
8595
+ emitter: "MessageComposer",
8596
+ context: { composer: this }
8597
+ },
8598
+ options: {
8599
+ type: "api:location:create:failed",
8600
+ metadata: {
8601
+ reason: error.message
8602
+ },
8603
+ originalError: error instanceof Error ? error : void 0
8604
+ }
8605
+ });
8606
+ throw error;
8607
+ }
8608
+ };
8469
8609
  this.compositionContext = compositionContext;
8470
- this.configState = new StateStore(
8471
- mergeWith(DEFAULT_COMPOSER_CONFIG, config ?? {})
8472
- );
8473
8610
  if (compositionContext instanceof Channel) {
8474
8611
  this.channel = compositionContext;
8475
8612
  } else if (compositionContext instanceof Thread) {
@@ -8482,6 +8619,21 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8482
8619
  "MessageComposer requires composition context pointing to channel (channel or context.cid)"
8483
8620
  );
8484
8621
  }
8622
+ const mergeChannelConfigCustomizer = (originalVal, channelConfigVal, key) => typeof originalVal === "object" ? void 0 : originalVal === false && key === "enabled" ? false : ["string", "number", "bigint", "boolean", "symbol"].includes(
8623
+ // prevent enabling features that are disabled server-side
8624
+ typeof channelConfigVal
8625
+ ) ? channelConfigVal : originalVal;
8626
+ this.configState = new StateStore(
8627
+ mergeWith(
8628
+ mergeWith(DEFAULT_COMPOSER_CONFIG, config ?? {}),
8629
+ {
8630
+ location: {
8631
+ enabled: this.channel.getConfig()?.shared_locations
8632
+ }
8633
+ },
8634
+ mergeChannelConfigCustomizer
8635
+ )
8636
+ );
8485
8637
  let message = void 0;
8486
8638
  if (compositionIsDraftResponse(composition)) {
8487
8639
  message = composition.message;
@@ -8491,13 +8643,14 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8491
8643
  }
8492
8644
  this.attachmentManager = new AttachmentManager({ composer: this, message });
8493
8645
  this.linkPreviewsManager = new LinkPreviewsManager({ composer: this, message });
8646
+ this.locationComposer = new LocationComposer({ composer: this, message });
8494
8647
  this.textComposer = new TextComposer({ composer: this, message });
8495
8648
  this.pollComposer = new PollComposer({ composer: this });
8496
8649
  this.customDataManager = new CustomDataManager({ composer: this, message });
8497
8650
  this.editingAuditState = new StateStore(
8498
8651
  this.initEditingAuditState(composition)
8499
8652
  );
8500
- this.state = new StateStore(initState5(composition));
8653
+ this.state = new StateStore(initState6(composition));
8501
8654
  this.compositionMiddlewareExecutor = new MessageComposerMiddlewareExecutor({
8502
8655
  composer: this
8503
8656
  });
@@ -8572,10 +8725,10 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8572
8725
  if (this.client.offlineDb) {
8573
8726
  return !this.compositionIsEmpty;
8574
8727
  }
8575
- return !!(!this.attachmentManager.uploadsInProgressCount && (!this.textComposer.textIsEmpty || this.attachmentManager.successfulUploadsCount > 0) || this.pollId);
8728
+ return !!(!this.attachmentManager.uploadsInProgressCount && (!this.textComposer.textIsEmpty || this.attachmentManager.successfulUploadsCount > 0) || this.pollId || !!this.locationComposer.validLocation);
8576
8729
  }
8577
8730
  get compositionIsEmpty() {
8578
- return !this.quotedMessage && this.textComposer.textIsEmpty && !this.attachmentManager.attachments.length && !this.pollId;
8731
+ return !this.quotedMessage && this.textComposer.textIsEmpty && !this.attachmentManager.attachments.length && !this.pollId && !this.locationComposer.validLocation;
8579
8732
  }
8580
8733
  get lastChangeOriginIsLocal() {
8581
8734
  const initiatedWithoutDraft = this.lastChange.draftUpdate === null;
@@ -9102,6 +9255,30 @@ var Channel = class {
9102
9255
  this.data = data.channel;
9103
9256
  return data;
9104
9257
  }
9258
+ async sendSharedLocation(location, userId) {
9259
+ const result = await this.sendMessage({
9260
+ id: location.message_id,
9261
+ shared_location: location,
9262
+ user: userId ? { id: userId } : void 0
9263
+ });
9264
+ if (location.end_at) {
9265
+ this.getClient().dispatchEvent({
9266
+ message: result.message,
9267
+ type: "live_location_sharing.started"
9268
+ });
9269
+ }
9270
+ return result;
9271
+ }
9272
+ async stopLiveLocationSharing(payload) {
9273
+ const location = await this.getClient().updateLocation({
9274
+ ...payload,
9275
+ end_at: (/* @__PURE__ */ new Date()).toISOString()
9276
+ });
9277
+ this.getClient().dispatchEvent({
9278
+ live_location: location,
9279
+ type: "live_location_sharing.stopped"
9280
+ });
9281
+ }
9105
9282
  /**
9106
9283
  * delete - Delete the channel. Messages are permanently removed.
9107
9284
  *
@@ -12348,7 +12525,8 @@ var ChannelManager = class extends WithSubscriptions {
12348
12525
  constructor({
12349
12526
  client,
12350
12527
  eventHandlerOverrides = {},
12351
- options = {}
12528
+ options = {},
12529
+ queryChannelsOverride
12352
12530
  }) {
12353
12531
  super();
12354
12532
  this.eventHandlers = /* @__PURE__ */ new Map();
@@ -12388,6 +12566,9 @@ var ChannelManager = class extends WithSubscriptions {
12388
12566
  Object.entries(truthyEventHandlerOverrides)
12389
12567
  );
12390
12568
  };
12569
+ this.setQueryChannelsRequest = (queryChannelsRequest) => {
12570
+ this.queryChannelsRequest = queryChannelsRequest;
12571
+ };
12391
12572
  this.setOptions = (options = {}) => {
12392
12573
  this.options = { ...DEFAULT_CHANNEL_MANAGER_OPTIONS, ...options };
12393
12574
  };
@@ -12398,7 +12579,7 @@ var ChannelManager = class extends WithSubscriptions {
12398
12579
  ...options
12399
12580
  };
12400
12581
  try {
12401
- const channels = await this.client.queryChannels(
12582
+ const channels = await this.queryChannelsRequest(
12402
12583
  filters,
12403
12584
  sort,
12404
12585
  options,
@@ -12432,7 +12613,16 @@ var ChannelManager = class extends WithSubscriptions {
12432
12613
  const wrappedError = new Error(
12433
12614
  `Maximum number of retries reached in queryChannels. Last error message is: ${err}`
12434
12615
  );
12435
- this.state.partialNext({ error: wrappedError });
12616
+ const state = this.state.getLatestValue();
12617
+ const isOfflineSupportEnabledWithChannels = this.client.offlineDb && state.channels.length > 0;
12618
+ this.state.partialNext({
12619
+ error: isOfflineSupportEnabledWithChannels ? void 0 : wrappedError,
12620
+ pagination: {
12621
+ ...state.pagination,
12622
+ isLoading: false,
12623
+ isLoadingNext: false
12624
+ }
12625
+ });
12436
12626
  return;
12437
12627
  }
12438
12628
  await sleep(DEFAULT_QUERY_CHANNELS_MS_BETWEEN_RETRIES);
@@ -12514,7 +12704,7 @@ var ChannelManager = class extends WithSubscriptions {
12514
12704
  this.state.partialNext({
12515
12705
  pagination: { ...pagination, isLoading: false, isLoadingNext: true }
12516
12706
  });
12517
- const nextChannels = await this.client.queryChannels(
12707
+ const nextChannels = await this.queryChannelsRequest(
12518
12708
  filters,
12519
12709
  sort,
12520
12710
  options,
@@ -12537,7 +12727,11 @@ var ChannelManager = class extends WithSubscriptions {
12537
12727
  this.client.logger("error", error.message);
12538
12728
  this.state.next((currentState) => ({
12539
12729
  ...currentState,
12540
- pagination: { ...currentState.pagination, isLoadingNext: false }
12730
+ pagination: {
12731
+ ...currentState.pagination,
12732
+ isLoadingNext: false,
12733
+ isLoading: false
12734
+ }
12541
12735
  }));
12542
12736
  throw error;
12543
12737
  }
@@ -12757,6 +12951,7 @@ var ChannelManager = class extends WithSubscriptions {
12757
12951
  });
12758
12952
  this.setEventHandlerOverrides(eventHandlerOverrides);
12759
12953
  this.setOptions(options);
12954
+ this.queryChannelsRequest = queryChannelsOverride ?? ((...params) => this.client.queryChannels(...params));
12760
12955
  this.eventHandlers = new Map(
12761
12956
  Object.entries({
12762
12957
  channelDeletedHandler: this.channelDeletedHandler,
@@ -13458,8 +13653,14 @@ var StreamChat = class _StreamChat {
13458
13653
  */
13459
13654
  this.createChannelManager = ({
13460
13655
  eventHandlerOverrides = {},
13461
- options = {}
13462
- }) => new ChannelManager({ client: this, eventHandlerOverrides, options });
13656
+ options = {},
13657
+ queryChannelsOverride
13658
+ }) => new ChannelManager({
13659
+ client: this,
13660
+ eventHandlerOverrides,
13661
+ options,
13662
+ queryChannelsOverride
13663
+ });
13463
13664
  /**
13464
13665
  * Creates a new WebSocket connection with the current user. Returns empty promise, if there is an active connection
13465
13666
  */
@@ -14782,6 +14983,16 @@ var StreamChat = class _StreamChat {
14782
14983
  endpoints: endpoints ? endpoints.join(",") : void 0
14783
14984
  });
14784
14985
  }
14986
+ /**
14987
+ * getHookEvents - Get available events for hooks (webhook, SQS, and SNS)
14988
+ *
14989
+ * @param {Product[]} [products] Optional array of products to filter events by (e.g., [Product.Chat, Product.Video])
14990
+ * @returns {Promise<GetHookEventsResponse>} Response containing available hook events
14991
+ */
14992
+ async getHookEvents(products) {
14993
+ const params = products && products.length > 0 ? { product: products.join(",") } : {};
14994
+ return await this.get(this.baseURL + "/hook/events", params);
14995
+ }
14785
14996
  _addChannelConfig({ cid, config }) {
14786
14997
  if (this._cacheEnabled()) {
14787
14998
  this.configs[cid] = config;
@@ -15563,7 +15774,7 @@ var StreamChat = class _StreamChat {
15563
15774
  if (this.userAgent) {
15564
15775
  return this.userAgent;
15565
15776
  }
15566
- const version = "9.11.0";
15777
+ const version = "9.13.0";
15567
15778
  const clientBundle = "browser-cjs";
15568
15779
  let userAgentString = "";
15569
15780
  if (this.sdkIdentifier) {
@@ -16655,9 +16866,9 @@ var StreamChat = class _StreamChat {
16655
16866
  /**
16656
16867
  * updateLocation - Updates a location
16657
16868
  *
16658
- * @param location UserLocation the location data to update
16869
+ * @param location SharedLocationRequest the location data to update
16659
16870
  *
16660
- * @returns {Promise<APIResponse>} The server response
16871
+ * @returns {Promise<SharedLocationResponse>} The server response
16661
16872
  */
16662
16873
  async updateLocation(location) {
16663
16874
  return await this.put(
@@ -16778,6 +16989,8 @@ var EVENT_MAP = {
16778
16989
  "connection.recovered": true,
16779
16990
  "transport.changed": true,
16780
16991
  "capabilities.changed": true,
16992
+ "live_location_sharing.started": true,
16993
+ "live_location_sharing.stopped": true,
16781
16994
  // Reminder events
16782
16995
  "reminder.created": true,
16783
16996
  "reminder.updated": true,
@@ -16998,6 +17211,13 @@ var OfflineDBSyncManager = class {
16998
17211
  });
16999
17212
  } catch (e) {
17000
17213
  console.log("An error has occurred while syncing the DB.", e);
17214
+ if (isAxiosError2(e) && e.code === "ECONNABORTED") {
17215
+ return;
17216
+ }
17217
+ const error = e;
17218
+ if (error.response?.data?.code === 23) {
17219
+ return;
17220
+ }
17001
17221
  await this.offlineDb.resetDB();
17002
17222
  }
17003
17223
  };
@@ -17633,6 +17853,200 @@ var AbstractOfflineDB = class {
17633
17853
  }
17634
17854
  };
17635
17855
 
17856
+ // src/LiveLocationManager.ts
17857
+ var isExpiredLocation = (location) => {
17858
+ const endTimeTimestamp = new Date(location.end_at).getTime();
17859
+ return endTimeTimestamp < Date.now();
17860
+ };
17861
+ function isValidLiveLocationMessage(message) {
17862
+ if (!message || message.type === "deleted" || !message.shared_location?.end_at)
17863
+ return false;
17864
+ return !isExpiredLocation(message.shared_location);
17865
+ }
17866
+ var UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT = 3e3;
17867
+ var _LiveLocationManager = class _LiveLocationManager extends WithSubscriptions {
17868
+ constructor({
17869
+ client,
17870
+ getDeviceId,
17871
+ watchLocation
17872
+ }) {
17873
+ if (!client.userID) {
17874
+ throw new Error("Live-location sharing is reserved for client-side use only");
17875
+ }
17876
+ super();
17877
+ this.registerSubscriptions = () => {
17878
+ this.incrementRefCount();
17879
+ if (this.hasSubscriptions) return;
17880
+ this.addUnsubscribeFunction(this.subscribeLiveLocationSharingUpdates());
17881
+ this.addUnsubscribeFunction(this.subscribeTargetMessagesChange());
17882
+ };
17883
+ this.unregisterSubscriptions = () => super.unregisterSubscriptions();
17884
+ this.client = client;
17885
+ this.state = new StateStore({
17886
+ messages: /* @__PURE__ */ new Map(),
17887
+ ready: false
17888
+ });
17889
+ this._deviceId = getDeviceId();
17890
+ this.getDeviceId = getDeviceId;
17891
+ this.watchLocation = watchLocation;
17892
+ }
17893
+ async init() {
17894
+ await this.assureStateInit();
17895
+ this.registerSubscriptions();
17896
+ }
17897
+ get messages() {
17898
+ return this.state.getLatestValue().messages;
17899
+ }
17900
+ get stateIsReady() {
17901
+ return this.state.getLatestValue().ready;
17902
+ }
17903
+ get deviceId() {
17904
+ if (!this._deviceId) {
17905
+ this._deviceId = this.getDeviceId();
17906
+ }
17907
+ return this._deviceId;
17908
+ }
17909
+ async assureStateInit() {
17910
+ if (this.stateIsReady) return;
17911
+ const { active_live_locations } = await this.client.getSharedLocations();
17912
+ this.state.next({
17913
+ messages: new Map(
17914
+ active_live_locations.filter((location) => !isExpiredLocation(location)).map((location) => [
17915
+ location.message_id,
17916
+ {
17917
+ ...location,
17918
+ stopSharingTimeout: setTimeout(
17919
+ () => {
17920
+ this.unregisterMessages([location.message_id]);
17921
+ },
17922
+ new Date(location.end_at).getTime() - Date.now()
17923
+ )
17924
+ }
17925
+ ])
17926
+ ),
17927
+ ready: true
17928
+ });
17929
+ }
17930
+ subscribeTargetMessagesChange() {
17931
+ let unsubscribeWatchLocation = null;
17932
+ const unsubscribe = this.state.subscribeWithSelector(
17933
+ ({ messages }) => ({ messages }),
17934
+ ({ messages }) => {
17935
+ if (!messages.size) {
17936
+ unsubscribeWatchLocation?.();
17937
+ unsubscribeWatchLocation = null;
17938
+ } else if (messages.size && !unsubscribeWatchLocation) {
17939
+ unsubscribeWatchLocation = this.subscribeWatchLocation();
17940
+ }
17941
+ }
17942
+ );
17943
+ return () => {
17944
+ unsubscribe();
17945
+ unsubscribeWatchLocation?.();
17946
+ };
17947
+ }
17948
+ subscribeWatchLocation() {
17949
+ let nextAllowedUpdateCallTimestamp = Date.now();
17950
+ const unsubscribe = this.watchLocation(({ latitude, longitude }) => {
17951
+ if (Date.now() < nextAllowedUpdateCallTimestamp) return;
17952
+ nextAllowedUpdateCallTimestamp = Date.now() + UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT;
17953
+ withCancellation(_LiveLocationManager.symbol, async () => {
17954
+ const promises = [];
17955
+ await this.assureStateInit();
17956
+ const expiredLocations = [];
17957
+ for (const [messageId, location] of this.messages) {
17958
+ if (isExpiredLocation(location)) {
17959
+ expiredLocations.push(location.message_id);
17960
+ continue;
17961
+ }
17962
+ if (location.latitude === latitude && location.longitude === longitude)
17963
+ continue;
17964
+ const promise = this.client.updateLocation({
17965
+ created_by_device_id: location.created_by_device_id,
17966
+ message_id: messageId,
17967
+ latitude,
17968
+ longitude
17969
+ });
17970
+ promises.push(promise);
17971
+ }
17972
+ this.unregisterMessages(expiredLocations);
17973
+ if (promises.length > 0) {
17974
+ await Promise.allSettled(promises);
17975
+ }
17976
+ });
17977
+ });
17978
+ return unsubscribe;
17979
+ }
17980
+ subscribeLiveLocationSharingUpdates() {
17981
+ const subscriptions = [
17982
+ ...[
17983
+ "live_location_sharing.started",
17984
+ "message.updated",
17985
+ "message.deleted"
17986
+ ].map(
17987
+ (eventType) => this.client.on(eventType, (event) => {
17988
+ if (!event.message) return;
17989
+ if (event.type === "live_location_sharing.started") {
17990
+ this.registerMessage(event.message);
17991
+ } else if (event.type === "message.updated") {
17992
+ const isRegistered = this.messages.has(event.message.id);
17993
+ if (isRegistered && !isValidLiveLocationMessage(event.message)) {
17994
+ this.unregisterMessages([event.message.id]);
17995
+ }
17996
+ this.registerMessage(event.message);
17997
+ } else {
17998
+ this.unregisterMessages([event.message.id]);
17999
+ }
18000
+ })
18001
+ ),
18002
+ this.client.on("live_location_sharing.stopped", (event) => {
18003
+ if (!event.live_location) return;
18004
+ this.unregisterMessages([event.live_location?.message_id]);
18005
+ })
18006
+ ];
18007
+ return () => subscriptions.forEach((subscription) => subscription.unsubscribe());
18008
+ }
18009
+ registerMessage(message) {
18010
+ if (!this.client.userID || message?.user?.id !== this.client.userID || !isValidLiveLocationMessage(message))
18011
+ return;
18012
+ this.state.next((currentValue) => {
18013
+ const messages = new Map(currentValue.messages);
18014
+ messages.set(message.id, {
18015
+ ...message.shared_location,
18016
+ stopSharingTimeout: setTimeout(
18017
+ () => {
18018
+ this.unregisterMessages([message.id]);
18019
+ },
18020
+ new Date(message.shared_location.end_at).getTime() - Date.now()
18021
+ )
18022
+ });
18023
+ return {
18024
+ ...currentValue,
18025
+ messages
18026
+ };
18027
+ });
18028
+ }
18029
+ unregisterMessages(messageIds) {
18030
+ const messages = this.messages;
18031
+ const removedMessages = new Set(messageIds);
18032
+ const newMessages = new Map(
18033
+ Array.from(messages).filter(([messageId, location]) => {
18034
+ if (removedMessages.has(messageId) && location.stopSharingTimeout) {
18035
+ clearTimeout(location.stopSharingTimeout);
18036
+ location.stopSharingTimeout = null;
18037
+ }
18038
+ return !removedMessages.has(messageId);
18039
+ })
18040
+ );
18041
+ if (newMessages.size === messages.size) return;
18042
+ this.state.partialNext({
18043
+ messages: newMessages
18044
+ });
18045
+ }
18046
+ };
18047
+ _LiveLocationManager.symbol = Symbol(_LiveLocationManager.name);
18048
+ var LiveLocationManager = _LiveLocationManager;
18049
+
17636
18050
  // src/utils/FixedSizeQueueCache.ts
17637
18051
  var FixedSizeQueueCache = class {
17638
18052
  constructor(size, options) {