stream-chat 9.11.0 → 9.12.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 +397 -21
  2. package/dist/cjs/index.browser.cjs.map +4 -4
  3. package/dist/cjs/index.node.cjs +410 -28
  4. package/dist/cjs/index.node.cjs.map +4 -4
  5. package/dist/esm/index.js +397 -21
  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 +7 -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 +44 -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 +15 -2
  26. package/src/client.ts +14 -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/types.ts +46 -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,
@@ -229,6 +232,7 @@ __export(index_exports, {
229
232
  Thread: () => Thread,
230
233
  ThreadManager: () => ThreadManager,
231
234
  TokenManager: () => TokenManager,
235
+ UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT: () => UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT,
232
236
  UserFromToken: () => UserFromToken,
233
237
  UserSearchSource: () => UserSearchSource,
234
238
  VALID_MAX_VOTES_VALUE_REGEX: () => VALID_MAX_VOTES_VALUE_REGEX,
@@ -259,6 +263,7 @@ __export(index_exports, {
259
263
  createMentionsMiddleware: () => createMentionsMiddleware,
260
264
  createMessageComposerStateCompositionMiddleware: () => createMessageComposerStateCompositionMiddleware,
261
265
  createPollComposerStateMiddleware: () => createPollComposerStateMiddleware,
266
+ createSharedLocationCompositionMiddleware: () => createSharedLocationCompositionMiddleware,
262
267
  createTextComposerCompositionMiddleware: () => createTextComposerCompositionMiddleware,
263
268
  createTextComposerPreValidationMiddleware: () => createTextComposerPreValidationMiddleware,
264
269
  decodeBase64: () => decodeBase64,
@@ -295,6 +300,7 @@ __export(index_exports, {
295
300
  isOwnUser: () => isOwnUser,
296
301
  isPatch: () => isPatch,
297
302
  isScrapedContent: () => isScrapedContent,
303
+ isSharedLocationResponse: () => isSharedLocationResponse,
298
304
  isTargetedOptionTextUpdate: () => isTargetedOptionTextUpdate,
299
305
  isUploadedAttachment: () => isUploadedAttachment,
300
306
  isVideoAttachment: () => isVideoAttachment,
@@ -4019,6 +4025,7 @@ var isLocalVoiceRecordingAttachment = (attachment) => isVoiceRecordingAttachment
4019
4025
  var isVideoAttachment = (attachment, supportedVideoFormat = []) => attachment.type === "video" || !!(attachment.mime_type && supportedVideoFormat.indexOf(attachment.mime_type) !== -1);
4020
4026
  var isLocalVideoAttachment = (attachment) => isVideoAttachment(attachment) && isLocalAttachment(attachment);
4021
4027
  var isUploadedAttachment = (attachment) => isAudioAttachment(attachment) || isFileAttachment(attachment) || isImageAttachment(attachment) || isVideoAttachment(attachment) || isVoiceRecordingAttachment(attachment);
4028
+ var isSharedLocationResponse = (location) => !!location.latitude && !!location.longitude && !!location.channel_cid;
4022
4029
 
4023
4030
  // src/messageComposer/fileUtils.ts
4024
4031
  var isFile2 = (fileLike) => !!fileLike.lastModified && !("uri" in fileLike);
@@ -5061,10 +5068,15 @@ var DEFAULT_TEXT_COMPOSER_CONFIG = {
5061
5068
  enabled: true,
5062
5069
  publishTypingEvents: true
5063
5070
  };
5071
+ var DEFAULT_LOCATION_COMPOSER_CONFIG = {
5072
+ enabled: true,
5073
+ getDeviceId: () => generateUUIDv4()
5074
+ };
5064
5075
  var DEFAULT_COMPOSER_CONFIG = {
5065
5076
  attachments: DEFAULT_ATTACHMENT_MANAGER_CONFIG,
5066
5077
  drafts: { enabled: false },
5067
5078
  linkPreviews: DEFAULT_LINK_PREVIEW_MANAGER_CONFIG,
5079
+ location: DEFAULT_LOCATION_COMPOSER_CONFIG,
5068
5080
  text: DEFAULT_TEXT_COMPOSER_CONFIG
5069
5081
  };
5070
5082
 
@@ -5320,6 +5332,54 @@ _LinkPreviewsManager.getPreviewData = (preview) => {
5320
5332
  };
5321
5333
  var LinkPreviewsManager = _LinkPreviewsManager;
5322
5334
 
5335
+ // src/messageComposer/LocationComposer.ts
5336
+ var MIN_LIVE_LOCATION_SHARE_DURATION = 60 * 1e3;
5337
+ var initState4 = ({
5338
+ message
5339
+ }) => ({
5340
+ location: message?.shared_location ?? null
5341
+ });
5342
+ var LocationComposer = class {
5343
+ constructor({ composer, message }) {
5344
+ this.initState = ({ message } = {}) => {
5345
+ this.state.next(initState4({ message }));
5346
+ };
5347
+ this.setData = (data) => {
5348
+ if (!this.config.enabled) return;
5349
+ if (!data.latitude || !data.longitude) return;
5350
+ this.state.partialNext({
5351
+ location: {
5352
+ ...data,
5353
+ message_id: this.composer.id,
5354
+ created_by_device_id: this.deviceId
5355
+ }
5356
+ });
5357
+ };
5358
+ this.composer = composer;
5359
+ this.state = new StateStore(initState4({ message }));
5360
+ this._deviceId = this.config.getDeviceId();
5361
+ }
5362
+ get config() {
5363
+ return this.composer.config.location;
5364
+ }
5365
+ get deviceId() {
5366
+ return this._deviceId;
5367
+ }
5368
+ get location() {
5369
+ return this.state.getLatestValue().location;
5370
+ }
5371
+ get validLocation() {
5372
+ const { durationMs, ...location } = this.location ?? {};
5373
+ if (!!location?.created_by_device_id && location.message_id && location.latitude && location.longitude && (typeof durationMs === "undefined" || durationMs >= MIN_LIVE_LOCATION_SHARE_DURATION)) {
5374
+ return {
5375
+ ...location,
5376
+ end_at: durationMs && new Date(Date.now() + durationMs).toISOString()
5377
+ };
5378
+ }
5379
+ return null;
5380
+ }
5381
+ };
5382
+
5323
5383
  // src/utils/concurrency.ts
5324
5384
  var withoutConcurrency = createRunner(wrapWithContinuationTracking);
5325
5385
  var withCancellation = createRunner(wrapWithCancellation);
@@ -6003,9 +6063,8 @@ var createCompositionValidationMiddleware = (composer) => ({
6003
6063
  }) => {
6004
6064
  const { maxLengthOnSend } = composer.config.text ?? {};
6005
6065
  const inputText = state.message.text ?? "";
6006
- const isEmptyMessage = textIsEmpty(inputText) && !state.message.attachments?.length && !state.message.poll_id;
6007
6066
  const hasExceededMaxLength = typeof maxLengthOnSend === "number" && inputText.length > maxLengthOnSend;
6008
- if (isEmptyMessage || hasExceededMaxLength) {
6067
+ if (composer.compositionIsEmpty || hasExceededMaxLength) {
6009
6068
  return await discard();
6010
6069
  }
6011
6070
  return await forward();
@@ -6285,6 +6344,40 @@ var createPollOnlyCompositionMiddleware = (composer) => ({
6285
6344
  }
6286
6345
  });
6287
6346
 
6347
+ // src/messageComposer/middleware/messageComposer/sharedLocation.ts
6348
+ var createSharedLocationCompositionMiddleware = (composer) => ({
6349
+ id: "stream-io/message-composer-middleware/shared-location",
6350
+ handlers: {
6351
+ compose: ({
6352
+ state,
6353
+ next,
6354
+ forward
6355
+ }) => {
6356
+ const { locationComposer } = composer;
6357
+ const location = locationComposer.validLocation;
6358
+ if (!locationComposer || !location || !composer.client.user) return forward();
6359
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
6360
+ return next({
6361
+ ...state,
6362
+ localMessage: {
6363
+ ...state.localMessage,
6364
+ shared_location: {
6365
+ ...location,
6366
+ channel_cid: composer.channel.cid,
6367
+ created_at: timestamp,
6368
+ updated_at: timestamp,
6369
+ user_id: composer.client.user.id
6370
+ }
6371
+ },
6372
+ message: {
6373
+ ...state.message,
6374
+ shared_location: location
6375
+ }
6376
+ });
6377
+ }
6378
+ }
6379
+ });
6380
+
6288
6381
  // src/messageComposer/middleware/messageComposer/MessageComposerMiddlewareExecutor.ts
6289
6382
  var MessageComposerMiddlewareExecutor = class extends MiddlewareExecutor {
6290
6383
  constructor({ composer }) {
@@ -6295,6 +6388,7 @@ var MessageComposerMiddlewareExecutor = class extends MiddlewareExecutor {
6295
6388
  createTextComposerCompositionMiddleware(composer),
6296
6389
  createAttachmentsCompositionMiddleware(composer),
6297
6390
  createLinkPreviewsCompositionMiddleware(composer),
6391
+ createSharedLocationCompositionMiddleware(composer),
6298
6392
  createMessageComposerStateCompositionMiddleware(composer),
6299
6393
  createCustomDataCompositionMiddleware(composer),
6300
6394
  createCompositionValidationMiddleware(composer),
@@ -7336,7 +7430,7 @@ var textIsEmpty = (text) => {
7336
7430
  const trimmedText = text.trim();
7337
7431
  return trimmedText === "" || trimmedText === ">" || trimmedText === "``````" || trimmedText === "``" || trimmedText === "**" || trimmedText === "____" || trimmedText === "__" || trimmedText === "****";
7338
7432
  };
7339
- var initState4 = ({
7433
+ var initState5 = ({
7340
7434
  composer,
7341
7435
  message
7342
7436
  }) => {
@@ -7361,7 +7455,7 @@ var initState4 = ({
7361
7455
  var TextComposer = class {
7362
7456
  constructor({ composer, message }) {
7363
7457
  this.initState = ({ message } = {}) => {
7364
- this.state.next(initState4({ composer: this.composer, message }));
7458
+ this.state.next(initState5({ composer: this.composer, message }));
7365
7459
  };
7366
7460
  this.upsertMentionedUser = (user) => {
7367
7461
  const mentionedUsers = [...this.mentionedUsers];
@@ -7489,7 +7583,7 @@ var TextComposer = class {
7489
7583
  this.state.next(output.state);
7490
7584
  };
7491
7585
  this.composer = composer;
7492
- this.state = new StateStore(initState4({ composer, message }));
7586
+ this.state = new StateStore(initState5({ composer, message }));
7493
7587
  this.middlewareExecutor = new TextComposerMiddlewareExecutor({ composer });
7494
7588
  }
7495
7589
  get channel() {
@@ -8062,7 +8156,7 @@ var initEditingAuditState = (composition) => {
8062
8156
  }
8063
8157
  };
8064
8158
  };
8065
- var initState5 = (composition) => {
8159
+ var initState6 = (composition) => {
8066
8160
  if (!composition) {
8067
8161
  return {
8068
8162
  draftId: null,
@@ -8100,6 +8194,9 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8100
8194
  client
8101
8195
  }) {
8102
8196
  super();
8197
+ this.refreshId = () => {
8198
+ this.state.partialNext({ id: _MessageComposer.generateId() });
8199
+ };
8103
8200
  this.initState = ({
8104
8201
  composition
8105
8202
  } = {}) => {
@@ -8107,10 +8204,11 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8107
8204
  const message = typeof composition === "undefined" ? composition : compositionIsDraftResponse(composition) ? composition.message : formatMessage(composition);
8108
8205
  this.attachmentManager.initState({ message });
8109
8206
  this.linkPreviewsManager.initState({ message });
8207
+ this.locationComposer.initState({ message });
8110
8208
  this.textComposer.initState({ message });
8111
8209
  this.pollComposer.initState();
8112
8210
  this.customDataManager.initState({ message });
8113
- this.state.next(initState5(composition));
8211
+ this.state.next(initState6(composition));
8114
8212
  if (composition && !compositionIsDraftResponse(composition) && message && isLocalMessage(message)) {
8115
8213
  this.editedMessage = message;
8116
8214
  }
@@ -8150,6 +8248,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8150
8248
  this.addUnsubscribeFunction(this.subscribeTextComposerStateChanged());
8151
8249
  this.addUnsubscribeFunction(this.subscribeAttachmentManagerStateChanged());
8152
8250
  this.addUnsubscribeFunction(this.subscribeLinkPreviewsManagerStateChanged());
8251
+ this.addUnsubscribeFunction(this.subscribeLocationComposerStateChanged());
8153
8252
  this.addUnsubscribeFunction(this.subscribePollComposerStateChanged());
8154
8253
  this.addUnsubscribeFunction(this.subscribeCustomDataManagerStateChanged());
8155
8254
  this.addUnsubscribeFunction(this.subscribeMessageComposerStateChanged());
@@ -8246,6 +8345,14 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8246
8345
  return;
8247
8346
  }
8248
8347
  });
8348
+ this.subscribeLocationComposerStateChanged = () => this.locationComposer.state.subscribe((_, previousValue) => {
8349
+ if (typeof previousValue === "undefined") return;
8350
+ this.logStateUpdateTimestamp();
8351
+ if (this.compositionIsEmpty) {
8352
+ this.deleteDraft();
8353
+ return;
8354
+ }
8355
+ });
8249
8356
  this.subscribeLinkPreviewsManagerStateChanged = () => this.linkPreviewsManager.state.subscribe((_, previousValue) => {
8250
8357
  if (typeof previousValue === "undefined") return;
8251
8358
  this.logStateUpdateTimestamp();
@@ -8466,10 +8573,32 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8466
8573
  throw error;
8467
8574
  }
8468
8575
  };
8576
+ this.sendLocation = async () => {
8577
+ const location = this.locationComposer.validLocation;
8578
+ if (this.threadId || !location) return;
8579
+ try {
8580
+ await this.channel.sendSharedLocation(location);
8581
+ this.refreshId();
8582
+ this.locationComposer.initState();
8583
+ } catch (error) {
8584
+ this.client.notifications.addError({
8585
+ message: "Failed to share the location",
8586
+ origin: {
8587
+ emitter: "MessageComposer",
8588
+ context: { composer: this }
8589
+ },
8590
+ options: {
8591
+ type: "api:location:create:failed",
8592
+ metadata: {
8593
+ reason: error.message
8594
+ },
8595
+ originalError: error instanceof Error ? error : void 0
8596
+ }
8597
+ });
8598
+ throw error;
8599
+ }
8600
+ };
8469
8601
  this.compositionContext = compositionContext;
8470
- this.configState = new StateStore(
8471
- mergeWith(DEFAULT_COMPOSER_CONFIG, config ?? {})
8472
- );
8473
8602
  if (compositionContext instanceof Channel) {
8474
8603
  this.channel = compositionContext;
8475
8604
  } else if (compositionContext instanceof Thread) {
@@ -8482,6 +8611,21 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8482
8611
  "MessageComposer requires composition context pointing to channel (channel or context.cid)"
8483
8612
  );
8484
8613
  }
8614
+ const mergeChannelConfigCustomizer = (originalVal, channelConfigVal, key) => typeof originalVal === "object" ? void 0 : originalVal === false && key === "enabled" ? false : ["string", "number", "bigint", "boolean", "symbol"].includes(
8615
+ // prevent enabling features that are disabled server-side
8616
+ typeof channelConfigVal
8617
+ ) ? channelConfigVal : originalVal;
8618
+ this.configState = new StateStore(
8619
+ mergeWith(
8620
+ mergeWith(DEFAULT_COMPOSER_CONFIG, config ?? {}),
8621
+ {
8622
+ location: {
8623
+ enabled: this.channel.getConfig()?.shared_locations
8624
+ }
8625
+ },
8626
+ mergeChannelConfigCustomizer
8627
+ )
8628
+ );
8485
8629
  let message = void 0;
8486
8630
  if (compositionIsDraftResponse(composition)) {
8487
8631
  message = composition.message;
@@ -8491,13 +8635,14 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8491
8635
  }
8492
8636
  this.attachmentManager = new AttachmentManager({ composer: this, message });
8493
8637
  this.linkPreviewsManager = new LinkPreviewsManager({ composer: this, message });
8638
+ this.locationComposer = new LocationComposer({ composer: this, message });
8494
8639
  this.textComposer = new TextComposer({ composer: this, message });
8495
8640
  this.pollComposer = new PollComposer({ composer: this });
8496
8641
  this.customDataManager = new CustomDataManager({ composer: this, message });
8497
8642
  this.editingAuditState = new StateStore(
8498
8643
  this.initEditingAuditState(composition)
8499
8644
  );
8500
- this.state = new StateStore(initState5(composition));
8645
+ this.state = new StateStore(initState6(composition));
8501
8646
  this.compositionMiddlewareExecutor = new MessageComposerMiddlewareExecutor({
8502
8647
  composer: this
8503
8648
  });
@@ -8572,10 +8717,10 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
8572
8717
  if (this.client.offlineDb) {
8573
8718
  return !this.compositionIsEmpty;
8574
8719
  }
8575
- return !!(!this.attachmentManager.uploadsInProgressCount && (!this.textComposer.textIsEmpty || this.attachmentManager.successfulUploadsCount > 0) || this.pollId);
8720
+ return !!(!this.attachmentManager.uploadsInProgressCount && (!this.textComposer.textIsEmpty || this.attachmentManager.successfulUploadsCount > 0) || this.pollId || !!this.locationComposer.validLocation);
8576
8721
  }
8577
8722
  get compositionIsEmpty() {
8578
- return !this.quotedMessage && this.textComposer.textIsEmpty && !this.attachmentManager.attachments.length && !this.pollId;
8723
+ return !this.quotedMessage && this.textComposer.textIsEmpty && !this.attachmentManager.attachments.length && !this.pollId && !this.locationComposer.validLocation;
8579
8724
  }
8580
8725
  get lastChangeOriginIsLocal() {
8581
8726
  const initiatedWithoutDraft = this.lastChange.draftUpdate === null;
@@ -9102,6 +9247,30 @@ var Channel = class {
9102
9247
  this.data = data.channel;
9103
9248
  return data;
9104
9249
  }
9250
+ async sendSharedLocation(location, userId) {
9251
+ const result = await this.sendMessage({
9252
+ id: location.message_id,
9253
+ shared_location: location,
9254
+ user: userId ? { id: userId } : void 0
9255
+ });
9256
+ if (location.end_at) {
9257
+ this.getClient().dispatchEvent({
9258
+ message: result.message,
9259
+ type: "live_location_sharing.started"
9260
+ });
9261
+ }
9262
+ return result;
9263
+ }
9264
+ async stopLiveLocationSharing(payload) {
9265
+ const location = await this.getClient().updateLocation({
9266
+ ...payload,
9267
+ end_at: (/* @__PURE__ */ new Date()).toISOString()
9268
+ });
9269
+ this.getClient().dispatchEvent({
9270
+ live_location: location,
9271
+ type: "live_location_sharing.stopped"
9272
+ });
9273
+ }
9105
9274
  /**
9106
9275
  * delete - Delete the channel. Messages are permanently removed.
9107
9276
  *
@@ -12348,7 +12517,8 @@ var ChannelManager = class extends WithSubscriptions {
12348
12517
  constructor({
12349
12518
  client,
12350
12519
  eventHandlerOverrides = {},
12351
- options = {}
12520
+ options = {},
12521
+ queryChannelsOverride
12352
12522
  }) {
12353
12523
  super();
12354
12524
  this.eventHandlers = /* @__PURE__ */ new Map();
@@ -12388,6 +12558,9 @@ var ChannelManager = class extends WithSubscriptions {
12388
12558
  Object.entries(truthyEventHandlerOverrides)
12389
12559
  );
12390
12560
  };
12561
+ this.setQueryChannelsRequest = (queryChannelsRequest) => {
12562
+ this.queryChannelsRequest = queryChannelsRequest;
12563
+ };
12391
12564
  this.setOptions = (options = {}) => {
12392
12565
  this.options = { ...DEFAULT_CHANNEL_MANAGER_OPTIONS, ...options };
12393
12566
  };
@@ -12398,7 +12571,7 @@ var ChannelManager = class extends WithSubscriptions {
12398
12571
  ...options
12399
12572
  };
12400
12573
  try {
12401
- const channels = await this.client.queryChannels(
12574
+ const channels = await this.queryChannelsRequest(
12402
12575
  filters,
12403
12576
  sort,
12404
12577
  options,
@@ -12514,7 +12687,7 @@ var ChannelManager = class extends WithSubscriptions {
12514
12687
  this.state.partialNext({
12515
12688
  pagination: { ...pagination, isLoading: false, isLoadingNext: true }
12516
12689
  });
12517
- const nextChannels = await this.client.queryChannels(
12690
+ const nextChannels = await this.queryChannelsRequest(
12518
12691
  filters,
12519
12692
  sort,
12520
12693
  options,
@@ -12757,6 +12930,7 @@ var ChannelManager = class extends WithSubscriptions {
12757
12930
  });
12758
12931
  this.setEventHandlerOverrides(eventHandlerOverrides);
12759
12932
  this.setOptions(options);
12933
+ this.queryChannelsRequest = queryChannelsOverride ?? ((...params) => this.client.queryChannels(...params));
12760
12934
  this.eventHandlers = new Map(
12761
12935
  Object.entries({
12762
12936
  channelDeletedHandler: this.channelDeletedHandler,
@@ -13458,8 +13632,14 @@ var StreamChat = class _StreamChat {
13458
13632
  */
13459
13633
  this.createChannelManager = ({
13460
13634
  eventHandlerOverrides = {},
13461
- options = {}
13462
- }) => new ChannelManager({ client: this, eventHandlerOverrides, options });
13635
+ options = {},
13636
+ queryChannelsOverride
13637
+ }) => new ChannelManager({
13638
+ client: this,
13639
+ eventHandlerOverrides,
13640
+ options,
13641
+ queryChannelsOverride
13642
+ });
13463
13643
  /**
13464
13644
  * Creates a new WebSocket connection with the current user. Returns empty promise, if there is an active connection
13465
13645
  */
@@ -15563,7 +15743,7 @@ var StreamChat = class _StreamChat {
15563
15743
  if (this.userAgent) {
15564
15744
  return this.userAgent;
15565
15745
  }
15566
- const version = "9.11.0";
15746
+ const version = "9.12.0";
15567
15747
  const clientBundle = "browser-cjs";
15568
15748
  let userAgentString = "";
15569
15749
  if (this.sdkIdentifier) {
@@ -16655,9 +16835,9 @@ var StreamChat = class _StreamChat {
16655
16835
  /**
16656
16836
  * updateLocation - Updates a location
16657
16837
  *
16658
- * @param location UserLocation the location data to update
16838
+ * @param location SharedLocationRequest the location data to update
16659
16839
  *
16660
- * @returns {Promise<APIResponse>} The server response
16840
+ * @returns {Promise<SharedLocationResponse>} The server response
16661
16841
  */
16662
16842
  async updateLocation(location) {
16663
16843
  return await this.put(
@@ -16778,6 +16958,8 @@ var EVENT_MAP = {
16778
16958
  "connection.recovered": true,
16779
16959
  "transport.changed": true,
16780
16960
  "capabilities.changed": true,
16961
+ "live_location_sharing.started": true,
16962
+ "live_location_sharing.stopped": true,
16781
16963
  // Reminder events
16782
16964
  "reminder.created": true,
16783
16965
  "reminder.updated": true,
@@ -17633,6 +17815,200 @@ var AbstractOfflineDB = class {
17633
17815
  }
17634
17816
  };
17635
17817
 
17818
+ // src/LiveLocationManager.ts
17819
+ var isExpiredLocation = (location) => {
17820
+ const endTimeTimestamp = new Date(location.end_at).getTime();
17821
+ return endTimeTimestamp < Date.now();
17822
+ };
17823
+ function isValidLiveLocationMessage(message) {
17824
+ if (!message || message.type === "deleted" || !message.shared_location?.end_at)
17825
+ return false;
17826
+ return !isExpiredLocation(message.shared_location);
17827
+ }
17828
+ var UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT = 3e3;
17829
+ var _LiveLocationManager = class _LiveLocationManager extends WithSubscriptions {
17830
+ constructor({
17831
+ client,
17832
+ getDeviceId,
17833
+ watchLocation
17834
+ }) {
17835
+ if (!client.userID) {
17836
+ throw new Error("Live-location sharing is reserved for client-side use only");
17837
+ }
17838
+ super();
17839
+ this.registerSubscriptions = () => {
17840
+ this.incrementRefCount();
17841
+ if (this.hasSubscriptions) return;
17842
+ this.addUnsubscribeFunction(this.subscribeLiveLocationSharingUpdates());
17843
+ this.addUnsubscribeFunction(this.subscribeTargetMessagesChange());
17844
+ };
17845
+ this.unregisterSubscriptions = () => super.unregisterSubscriptions();
17846
+ this.client = client;
17847
+ this.state = new StateStore({
17848
+ messages: /* @__PURE__ */ new Map(),
17849
+ ready: false
17850
+ });
17851
+ this._deviceId = getDeviceId();
17852
+ this.getDeviceId = getDeviceId;
17853
+ this.watchLocation = watchLocation;
17854
+ }
17855
+ async init() {
17856
+ await this.assureStateInit();
17857
+ this.registerSubscriptions();
17858
+ }
17859
+ get messages() {
17860
+ return this.state.getLatestValue().messages;
17861
+ }
17862
+ get stateIsReady() {
17863
+ return this.state.getLatestValue().ready;
17864
+ }
17865
+ get deviceId() {
17866
+ if (!this._deviceId) {
17867
+ this._deviceId = this.getDeviceId();
17868
+ }
17869
+ return this._deviceId;
17870
+ }
17871
+ async assureStateInit() {
17872
+ if (this.stateIsReady) return;
17873
+ const { active_live_locations } = await this.client.getSharedLocations();
17874
+ this.state.next({
17875
+ messages: new Map(
17876
+ active_live_locations.filter((location) => !isExpiredLocation(location)).map((location) => [
17877
+ location.message_id,
17878
+ {
17879
+ ...location,
17880
+ stopSharingTimeout: setTimeout(
17881
+ () => {
17882
+ this.unregisterMessages([location.message_id]);
17883
+ },
17884
+ new Date(location.end_at).getTime() - Date.now()
17885
+ )
17886
+ }
17887
+ ])
17888
+ ),
17889
+ ready: true
17890
+ });
17891
+ }
17892
+ subscribeTargetMessagesChange() {
17893
+ let unsubscribeWatchLocation = null;
17894
+ const unsubscribe = this.state.subscribeWithSelector(
17895
+ ({ messages }) => ({ messages }),
17896
+ ({ messages }) => {
17897
+ if (!messages.size) {
17898
+ unsubscribeWatchLocation?.();
17899
+ unsubscribeWatchLocation = null;
17900
+ } else if (messages.size && !unsubscribeWatchLocation) {
17901
+ unsubscribeWatchLocation = this.subscribeWatchLocation();
17902
+ }
17903
+ }
17904
+ );
17905
+ return () => {
17906
+ unsubscribe();
17907
+ unsubscribeWatchLocation?.();
17908
+ };
17909
+ }
17910
+ subscribeWatchLocation() {
17911
+ let nextAllowedUpdateCallTimestamp = Date.now();
17912
+ const unsubscribe = this.watchLocation(({ latitude, longitude }) => {
17913
+ if (Date.now() < nextAllowedUpdateCallTimestamp) return;
17914
+ nextAllowedUpdateCallTimestamp = Date.now() + UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT;
17915
+ withCancellation(_LiveLocationManager.symbol, async () => {
17916
+ const promises = [];
17917
+ await this.assureStateInit();
17918
+ const expiredLocations = [];
17919
+ for (const [messageId, location] of this.messages) {
17920
+ if (isExpiredLocation(location)) {
17921
+ expiredLocations.push(location.message_id);
17922
+ continue;
17923
+ }
17924
+ if (location.latitude === latitude && location.longitude === longitude)
17925
+ continue;
17926
+ const promise = this.client.updateLocation({
17927
+ created_by_device_id: location.created_by_device_id,
17928
+ message_id: messageId,
17929
+ latitude,
17930
+ longitude
17931
+ });
17932
+ promises.push(promise);
17933
+ }
17934
+ this.unregisterMessages(expiredLocations);
17935
+ if (promises.length > 0) {
17936
+ await Promise.allSettled(promises);
17937
+ }
17938
+ });
17939
+ });
17940
+ return unsubscribe;
17941
+ }
17942
+ subscribeLiveLocationSharingUpdates() {
17943
+ const subscriptions = [
17944
+ ...[
17945
+ "live_location_sharing.started",
17946
+ "message.updated",
17947
+ "message.deleted"
17948
+ ].map(
17949
+ (eventType) => this.client.on(eventType, (event) => {
17950
+ if (!event.message) return;
17951
+ if (event.type === "live_location_sharing.started") {
17952
+ this.registerMessage(event.message);
17953
+ } else if (event.type === "message.updated") {
17954
+ const isRegistered = this.messages.has(event.message.id);
17955
+ if (isRegistered && !isValidLiveLocationMessage(event.message)) {
17956
+ this.unregisterMessages([event.message.id]);
17957
+ }
17958
+ this.registerMessage(event.message);
17959
+ } else {
17960
+ this.unregisterMessages([event.message.id]);
17961
+ }
17962
+ })
17963
+ ),
17964
+ this.client.on("live_location_sharing.stopped", (event) => {
17965
+ if (!event.live_location) return;
17966
+ this.unregisterMessages([event.live_location?.message_id]);
17967
+ })
17968
+ ];
17969
+ return () => subscriptions.forEach((subscription) => subscription.unsubscribe());
17970
+ }
17971
+ registerMessage(message) {
17972
+ if (!this.client.userID || message?.user?.id !== this.client.userID || !isValidLiveLocationMessage(message))
17973
+ return;
17974
+ this.state.next((currentValue) => {
17975
+ const messages = new Map(currentValue.messages);
17976
+ messages.set(message.id, {
17977
+ ...message.shared_location,
17978
+ stopSharingTimeout: setTimeout(
17979
+ () => {
17980
+ this.unregisterMessages([message.id]);
17981
+ },
17982
+ new Date(message.shared_location.end_at).getTime() - Date.now()
17983
+ )
17984
+ });
17985
+ return {
17986
+ ...currentValue,
17987
+ messages
17988
+ };
17989
+ });
17990
+ }
17991
+ unregisterMessages(messageIds) {
17992
+ const messages = this.messages;
17993
+ const removedMessages = new Set(messageIds);
17994
+ const newMessages = new Map(
17995
+ Array.from(messages).filter(([messageId, location]) => {
17996
+ if (removedMessages.has(messageId) && location.stopSharingTimeout) {
17997
+ clearTimeout(location.stopSharingTimeout);
17998
+ location.stopSharingTimeout = null;
17999
+ }
18000
+ return !removedMessages.has(messageId);
18001
+ })
18002
+ );
18003
+ if (newMessages.size === messages.size) return;
18004
+ this.state.partialNext({
18005
+ messages: newMessages
18006
+ });
18007
+ }
18008
+ };
18009
+ _LiveLocationManager.symbol = Symbol(_LiveLocationManager.name);
18010
+ var LiveLocationManager = _LiveLocationManager;
18011
+
17636
18012
  // src/utils/FixedSizeQueueCache.ts
17637
18013
  var FixedSizeQueueCache = class {
17638
18014
  constructor(size, options) {