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
package/dist/esm/index.js CHANGED
@@ -3854,6 +3854,7 @@ var isLocalVoiceRecordingAttachment = (attachment) => isVoiceRecordingAttachment
3854
3854
  var isVideoAttachment = (attachment, supportedVideoFormat = []) => attachment.type === "video" || !!(attachment.mime_type && supportedVideoFormat.indexOf(attachment.mime_type) !== -1);
3855
3855
  var isLocalVideoAttachment = (attachment) => isVideoAttachment(attachment) && isLocalAttachment(attachment);
3856
3856
  var isUploadedAttachment = (attachment) => isAudioAttachment(attachment) || isFileAttachment(attachment) || isImageAttachment(attachment) || isVideoAttachment(attachment) || isVoiceRecordingAttachment(attachment);
3857
+ var isSharedLocationResponse = (location) => !!location.latitude && !!location.longitude && !!location.channel_cid;
3857
3858
 
3858
3859
  // src/messageComposer/fileUtils.ts
3859
3860
  var isFile2 = (fileLike) => !!fileLike.lastModified && !("uri" in fileLike);
@@ -6025,10 +6026,15 @@ var DEFAULT_TEXT_COMPOSER_CONFIG = {
6025
6026
  enabled: true,
6026
6027
  publishTypingEvents: true
6027
6028
  };
6029
+ var DEFAULT_LOCATION_COMPOSER_CONFIG = {
6030
+ enabled: true,
6031
+ getDeviceId: () => generateUUIDv4()
6032
+ };
6028
6033
  var DEFAULT_COMPOSER_CONFIG = {
6029
6034
  attachments: DEFAULT_ATTACHMENT_MANAGER_CONFIG,
6030
6035
  drafts: { enabled: false },
6031
6036
  linkPreviews: DEFAULT_LINK_PREVIEW_MANAGER_CONFIG,
6037
+ location: DEFAULT_LOCATION_COMPOSER_CONFIG,
6032
6038
  text: DEFAULT_TEXT_COMPOSER_CONFIG
6033
6039
  };
6034
6040
 
@@ -6284,6 +6290,54 @@ _LinkPreviewsManager.getPreviewData = (preview) => {
6284
6290
  };
6285
6291
  var LinkPreviewsManager = _LinkPreviewsManager;
6286
6292
 
6293
+ // src/messageComposer/LocationComposer.ts
6294
+ var MIN_LIVE_LOCATION_SHARE_DURATION = 60 * 1e3;
6295
+ var initState4 = ({
6296
+ message
6297
+ }) => ({
6298
+ location: message?.shared_location ?? null
6299
+ });
6300
+ var LocationComposer = class {
6301
+ constructor({ composer, message }) {
6302
+ this.initState = ({ message } = {}) => {
6303
+ this.state.next(initState4({ message }));
6304
+ };
6305
+ this.setData = (data) => {
6306
+ if (!this.config.enabled) return;
6307
+ if (!data.latitude || !data.longitude) return;
6308
+ this.state.partialNext({
6309
+ location: {
6310
+ ...data,
6311
+ message_id: this.composer.id,
6312
+ created_by_device_id: this.deviceId
6313
+ }
6314
+ });
6315
+ };
6316
+ this.composer = composer;
6317
+ this.state = new StateStore(initState4({ message }));
6318
+ this._deviceId = this.config.getDeviceId();
6319
+ }
6320
+ get config() {
6321
+ return this.composer.config.location;
6322
+ }
6323
+ get deviceId() {
6324
+ return this._deviceId;
6325
+ }
6326
+ get location() {
6327
+ return this.state.getLatestValue().location;
6328
+ }
6329
+ get validLocation() {
6330
+ const { durationMs, ...location } = this.location ?? {};
6331
+ if (!!location?.created_by_device_id && location.message_id && location.latitude && location.longitude && (typeof durationMs === "undefined" || durationMs >= MIN_LIVE_LOCATION_SHARE_DURATION)) {
6332
+ return {
6333
+ ...location,
6334
+ end_at: durationMs && new Date(Date.now() + durationMs).toISOString()
6335
+ };
6336
+ }
6337
+ return null;
6338
+ }
6339
+ };
6340
+
6287
6341
  // src/utils/concurrency.ts
6288
6342
  var withoutConcurrency = createRunner(wrapWithContinuationTracking);
6289
6343
  var withCancellation = createRunner(wrapWithCancellation);
@@ -6967,9 +7021,8 @@ var createCompositionValidationMiddleware = (composer) => ({
6967
7021
  }) => {
6968
7022
  const { maxLengthOnSend } = composer.config.text ?? {};
6969
7023
  const inputText = state.message.text ?? "";
6970
- const isEmptyMessage = textIsEmpty(inputText) && !state.message.attachments?.length && !state.message.poll_id;
6971
7024
  const hasExceededMaxLength = typeof maxLengthOnSend === "number" && inputText.length > maxLengthOnSend;
6972
- if (isEmptyMessage || hasExceededMaxLength) {
7025
+ if (composer.compositionIsEmpty || hasExceededMaxLength) {
6973
7026
  return await discard();
6974
7027
  }
6975
7028
  return await forward();
@@ -7249,6 +7302,40 @@ var createPollOnlyCompositionMiddleware = (composer) => ({
7249
7302
  }
7250
7303
  });
7251
7304
 
7305
+ // src/messageComposer/middleware/messageComposer/sharedLocation.ts
7306
+ var createSharedLocationCompositionMiddleware = (composer) => ({
7307
+ id: "stream-io/message-composer-middleware/shared-location",
7308
+ handlers: {
7309
+ compose: ({
7310
+ state,
7311
+ next,
7312
+ forward
7313
+ }) => {
7314
+ const { locationComposer } = composer;
7315
+ const location = locationComposer.validLocation;
7316
+ if (!locationComposer || !location || !composer.client.user) return forward();
7317
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
7318
+ return next({
7319
+ ...state,
7320
+ localMessage: {
7321
+ ...state.localMessage,
7322
+ shared_location: {
7323
+ ...location,
7324
+ channel_cid: composer.channel.cid,
7325
+ created_at: timestamp,
7326
+ updated_at: timestamp,
7327
+ user_id: composer.client.user.id
7328
+ }
7329
+ },
7330
+ message: {
7331
+ ...state.message,
7332
+ shared_location: location
7333
+ }
7334
+ });
7335
+ }
7336
+ }
7337
+ });
7338
+
7252
7339
  // src/messageComposer/middleware/messageComposer/MessageComposerMiddlewareExecutor.ts
7253
7340
  var MessageComposerMiddlewareExecutor = class extends MiddlewareExecutor {
7254
7341
  constructor({ composer }) {
@@ -7259,6 +7346,7 @@ var MessageComposerMiddlewareExecutor = class extends MiddlewareExecutor {
7259
7346
  createTextComposerCompositionMiddleware(composer),
7260
7347
  createAttachmentsCompositionMiddleware(composer),
7261
7348
  createLinkPreviewsCompositionMiddleware(composer),
7349
+ createSharedLocationCompositionMiddleware(composer),
7262
7350
  createMessageComposerStateCompositionMiddleware(composer),
7263
7351
  createCustomDataCompositionMiddleware(composer),
7264
7352
  createCompositionValidationMiddleware(composer),
@@ -8300,7 +8388,7 @@ var textIsEmpty = (text) => {
8300
8388
  const trimmedText = text.trim();
8301
8389
  return trimmedText === "" || trimmedText === ">" || trimmedText === "``````" || trimmedText === "``" || trimmedText === "**" || trimmedText === "____" || trimmedText === "__" || trimmedText === "****";
8302
8390
  };
8303
- var initState4 = ({
8391
+ var initState5 = ({
8304
8392
  composer,
8305
8393
  message
8306
8394
  }) => {
@@ -8325,7 +8413,7 @@ var initState4 = ({
8325
8413
  var TextComposer = class {
8326
8414
  constructor({ composer, message }) {
8327
8415
  this.initState = ({ message } = {}) => {
8328
- this.state.next(initState4({ composer: this.composer, message }));
8416
+ this.state.next(initState5({ composer: this.composer, message }));
8329
8417
  };
8330
8418
  this.upsertMentionedUser = (user) => {
8331
8419
  const mentionedUsers = [...this.mentionedUsers];
@@ -8453,7 +8541,7 @@ var TextComposer = class {
8453
8541
  this.state.next(output.state);
8454
8542
  };
8455
8543
  this.composer = composer;
8456
- this.state = new StateStore(initState4({ composer, message }));
8544
+ this.state = new StateStore(initState5({ composer, message }));
8457
8545
  this.middlewareExecutor = new TextComposerMiddlewareExecutor({ composer });
8458
8546
  }
8459
8547
  get channel() {
@@ -9026,7 +9114,7 @@ var initEditingAuditState = (composition) => {
9026
9114
  }
9027
9115
  };
9028
9116
  };
9029
- var initState5 = (composition) => {
9117
+ var initState6 = (composition) => {
9030
9118
  if (!composition) {
9031
9119
  return {
9032
9120
  draftId: null,
@@ -9064,6 +9152,9 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
9064
9152
  client
9065
9153
  }) {
9066
9154
  super();
9155
+ this.refreshId = () => {
9156
+ this.state.partialNext({ id: _MessageComposer.generateId() });
9157
+ };
9067
9158
  this.initState = ({
9068
9159
  composition
9069
9160
  } = {}) => {
@@ -9071,10 +9162,11 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
9071
9162
  const message = typeof composition === "undefined" ? composition : compositionIsDraftResponse(composition) ? composition.message : formatMessage(composition);
9072
9163
  this.attachmentManager.initState({ message });
9073
9164
  this.linkPreviewsManager.initState({ message });
9165
+ this.locationComposer.initState({ message });
9074
9166
  this.textComposer.initState({ message });
9075
9167
  this.pollComposer.initState();
9076
9168
  this.customDataManager.initState({ message });
9077
- this.state.next(initState5(composition));
9169
+ this.state.next(initState6(composition));
9078
9170
  if (composition && !compositionIsDraftResponse(composition) && message && isLocalMessage(message)) {
9079
9171
  this.editedMessage = message;
9080
9172
  }
@@ -9114,6 +9206,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
9114
9206
  this.addUnsubscribeFunction(this.subscribeTextComposerStateChanged());
9115
9207
  this.addUnsubscribeFunction(this.subscribeAttachmentManagerStateChanged());
9116
9208
  this.addUnsubscribeFunction(this.subscribeLinkPreviewsManagerStateChanged());
9209
+ this.addUnsubscribeFunction(this.subscribeLocationComposerStateChanged());
9117
9210
  this.addUnsubscribeFunction(this.subscribePollComposerStateChanged());
9118
9211
  this.addUnsubscribeFunction(this.subscribeCustomDataManagerStateChanged());
9119
9212
  this.addUnsubscribeFunction(this.subscribeMessageComposerStateChanged());
@@ -9210,6 +9303,14 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
9210
9303
  return;
9211
9304
  }
9212
9305
  });
9306
+ this.subscribeLocationComposerStateChanged = () => this.locationComposer.state.subscribe((_, previousValue) => {
9307
+ if (typeof previousValue === "undefined") return;
9308
+ this.logStateUpdateTimestamp();
9309
+ if (this.compositionIsEmpty) {
9310
+ this.deleteDraft();
9311
+ return;
9312
+ }
9313
+ });
9213
9314
  this.subscribeLinkPreviewsManagerStateChanged = () => this.linkPreviewsManager.state.subscribe((_, previousValue) => {
9214
9315
  if (typeof previousValue === "undefined") return;
9215
9316
  this.logStateUpdateTimestamp();
@@ -9430,10 +9531,32 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
9430
9531
  throw error;
9431
9532
  }
9432
9533
  };
9534
+ this.sendLocation = async () => {
9535
+ const location = this.locationComposer.validLocation;
9536
+ if (this.threadId || !location) return;
9537
+ try {
9538
+ await this.channel.sendSharedLocation(location);
9539
+ this.refreshId();
9540
+ this.locationComposer.initState();
9541
+ } catch (error) {
9542
+ this.client.notifications.addError({
9543
+ message: "Failed to share the location",
9544
+ origin: {
9545
+ emitter: "MessageComposer",
9546
+ context: { composer: this }
9547
+ },
9548
+ options: {
9549
+ type: "api:location:create:failed",
9550
+ metadata: {
9551
+ reason: error.message
9552
+ },
9553
+ originalError: error instanceof Error ? error : void 0
9554
+ }
9555
+ });
9556
+ throw error;
9557
+ }
9558
+ };
9433
9559
  this.compositionContext = compositionContext;
9434
- this.configState = new StateStore(
9435
- mergeWith(DEFAULT_COMPOSER_CONFIG, config ?? {})
9436
- );
9437
9560
  if (compositionContext instanceof Channel) {
9438
9561
  this.channel = compositionContext;
9439
9562
  } else if (compositionContext instanceof Thread) {
@@ -9446,6 +9569,21 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
9446
9569
  "MessageComposer requires composition context pointing to channel (channel or context.cid)"
9447
9570
  );
9448
9571
  }
9572
+ const mergeChannelConfigCustomizer = (originalVal, channelConfigVal, key) => typeof originalVal === "object" ? void 0 : originalVal === false && key === "enabled" ? false : ["string", "number", "bigint", "boolean", "symbol"].includes(
9573
+ // prevent enabling features that are disabled server-side
9574
+ typeof channelConfigVal
9575
+ ) ? channelConfigVal : originalVal;
9576
+ this.configState = new StateStore(
9577
+ mergeWith(
9578
+ mergeWith(DEFAULT_COMPOSER_CONFIG, config ?? {}),
9579
+ {
9580
+ location: {
9581
+ enabled: this.channel.getConfig()?.shared_locations
9582
+ }
9583
+ },
9584
+ mergeChannelConfigCustomizer
9585
+ )
9586
+ );
9449
9587
  let message = void 0;
9450
9588
  if (compositionIsDraftResponse(composition)) {
9451
9589
  message = composition.message;
@@ -9455,13 +9593,14 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
9455
9593
  }
9456
9594
  this.attachmentManager = new AttachmentManager({ composer: this, message });
9457
9595
  this.linkPreviewsManager = new LinkPreviewsManager({ composer: this, message });
9596
+ this.locationComposer = new LocationComposer({ composer: this, message });
9458
9597
  this.textComposer = new TextComposer({ composer: this, message });
9459
9598
  this.pollComposer = new PollComposer({ composer: this });
9460
9599
  this.customDataManager = new CustomDataManager({ composer: this, message });
9461
9600
  this.editingAuditState = new StateStore(
9462
9601
  this.initEditingAuditState(composition)
9463
9602
  );
9464
- this.state = new StateStore(initState5(composition));
9603
+ this.state = new StateStore(initState6(composition));
9465
9604
  this.compositionMiddlewareExecutor = new MessageComposerMiddlewareExecutor({
9466
9605
  composer: this
9467
9606
  });
@@ -9536,10 +9675,10 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
9536
9675
  if (this.client.offlineDb) {
9537
9676
  return !this.compositionIsEmpty;
9538
9677
  }
9539
- return !!(!this.attachmentManager.uploadsInProgressCount && (!this.textComposer.textIsEmpty || this.attachmentManager.successfulUploadsCount > 0) || this.pollId);
9678
+ return !!(!this.attachmentManager.uploadsInProgressCount && (!this.textComposer.textIsEmpty || this.attachmentManager.successfulUploadsCount > 0) || this.pollId || !!this.locationComposer.validLocation);
9540
9679
  }
9541
9680
  get compositionIsEmpty() {
9542
- return !this.quotedMessage && this.textComposer.textIsEmpty && !this.attachmentManager.attachments.length && !this.pollId;
9681
+ return !this.quotedMessage && this.textComposer.textIsEmpty && !this.attachmentManager.attachments.length && !this.pollId && !this.locationComposer.validLocation;
9543
9682
  }
9544
9683
  get lastChangeOriginIsLocal() {
9545
9684
  const initiatedWithoutDraft = this.lastChange.draftUpdate === null;
@@ -10066,6 +10205,30 @@ var Channel = class {
10066
10205
  this.data = data.channel;
10067
10206
  return data;
10068
10207
  }
10208
+ async sendSharedLocation(location, userId) {
10209
+ const result = await this.sendMessage({
10210
+ id: location.message_id,
10211
+ shared_location: location,
10212
+ user: userId ? { id: userId } : void 0
10213
+ });
10214
+ if (location.end_at) {
10215
+ this.getClient().dispatchEvent({
10216
+ message: result.message,
10217
+ type: "live_location_sharing.started"
10218
+ });
10219
+ }
10220
+ return result;
10221
+ }
10222
+ async stopLiveLocationSharing(payload) {
10223
+ const location = await this.getClient().updateLocation({
10224
+ ...payload,
10225
+ end_at: (/* @__PURE__ */ new Date()).toISOString()
10226
+ });
10227
+ this.getClient().dispatchEvent({
10228
+ live_location: location,
10229
+ type: "live_location_sharing.stopped"
10230
+ });
10231
+ }
10069
10232
  /**
10070
10233
  * delete - Delete the channel. Messages are permanently removed.
10071
10234
  *
@@ -13312,7 +13475,8 @@ var ChannelManager = class extends WithSubscriptions {
13312
13475
  constructor({
13313
13476
  client,
13314
13477
  eventHandlerOverrides = {},
13315
- options = {}
13478
+ options = {},
13479
+ queryChannelsOverride
13316
13480
  }) {
13317
13481
  super();
13318
13482
  this.eventHandlers = /* @__PURE__ */ new Map();
@@ -13352,6 +13516,9 @@ var ChannelManager = class extends WithSubscriptions {
13352
13516
  Object.entries(truthyEventHandlerOverrides)
13353
13517
  );
13354
13518
  };
13519
+ this.setQueryChannelsRequest = (queryChannelsRequest) => {
13520
+ this.queryChannelsRequest = queryChannelsRequest;
13521
+ };
13355
13522
  this.setOptions = (options = {}) => {
13356
13523
  this.options = { ...DEFAULT_CHANNEL_MANAGER_OPTIONS, ...options };
13357
13524
  };
@@ -13362,7 +13529,7 @@ var ChannelManager = class extends WithSubscriptions {
13362
13529
  ...options
13363
13530
  };
13364
13531
  try {
13365
- const channels = await this.client.queryChannels(
13532
+ const channels = await this.queryChannelsRequest(
13366
13533
  filters,
13367
13534
  sort,
13368
13535
  options,
@@ -13478,7 +13645,7 @@ var ChannelManager = class extends WithSubscriptions {
13478
13645
  this.state.partialNext({
13479
13646
  pagination: { ...pagination, isLoading: false, isLoadingNext: true }
13480
13647
  });
13481
- const nextChannels = await this.client.queryChannels(
13648
+ const nextChannels = await this.queryChannelsRequest(
13482
13649
  filters,
13483
13650
  sort,
13484
13651
  options,
@@ -13721,6 +13888,7 @@ var ChannelManager = class extends WithSubscriptions {
13721
13888
  });
13722
13889
  this.setEventHandlerOverrides(eventHandlerOverrides);
13723
13890
  this.setOptions(options);
13891
+ this.queryChannelsRequest = queryChannelsOverride ?? ((...params) => this.client.queryChannels(...params));
13724
13892
  this.eventHandlers = new Map(
13725
13893
  Object.entries({
13726
13894
  channelDeletedHandler: this.channelDeletedHandler,
@@ -14422,8 +14590,14 @@ var StreamChat = class _StreamChat {
14422
14590
  */
14423
14591
  this.createChannelManager = ({
14424
14592
  eventHandlerOverrides = {},
14425
- options = {}
14426
- }) => new ChannelManager({ client: this, eventHandlerOverrides, options });
14593
+ options = {},
14594
+ queryChannelsOverride
14595
+ }) => new ChannelManager({
14596
+ client: this,
14597
+ eventHandlerOverrides,
14598
+ options,
14599
+ queryChannelsOverride
14600
+ });
14427
14601
  /**
14428
14602
  * Creates a new WebSocket connection with the current user. Returns empty promise, if there is an active connection
14429
14603
  */
@@ -16527,7 +16701,7 @@ var StreamChat = class _StreamChat {
16527
16701
  if (this.userAgent) {
16528
16702
  return this.userAgent;
16529
16703
  }
16530
- const version = "9.11.0";
16704
+ const version = "9.12.0";
16531
16705
  const clientBundle = "browser-esm";
16532
16706
  let userAgentString = "";
16533
16707
  if (this.sdkIdentifier) {
@@ -17619,9 +17793,9 @@ var StreamChat = class _StreamChat {
17619
17793
  /**
17620
17794
  * updateLocation - Updates a location
17621
17795
  *
17622
- * @param location UserLocation the location data to update
17796
+ * @param location SharedLocationRequest the location data to update
17623
17797
  *
17624
- * @returns {Promise<APIResponse>} The server response
17798
+ * @returns {Promise<SharedLocationResponse>} The server response
17625
17799
  */
17626
17800
  async updateLocation(location) {
17627
17801
  return await this.put(
@@ -17742,6 +17916,8 @@ var EVENT_MAP = {
17742
17916
  "connection.recovered": true,
17743
17917
  "transport.changed": true,
17744
17918
  "capabilities.changed": true,
17919
+ "live_location_sharing.started": true,
17920
+ "live_location_sharing.stopped": true,
17745
17921
  // Reminder events
17746
17922
  "reminder.created": true,
17747
17923
  "reminder.updated": true,
@@ -18597,6 +18773,200 @@ var AbstractOfflineDB = class {
18597
18773
  }
18598
18774
  };
18599
18775
 
18776
+ // src/LiveLocationManager.ts
18777
+ var isExpiredLocation = (location) => {
18778
+ const endTimeTimestamp = new Date(location.end_at).getTime();
18779
+ return endTimeTimestamp < Date.now();
18780
+ };
18781
+ function isValidLiveLocationMessage(message) {
18782
+ if (!message || message.type === "deleted" || !message.shared_location?.end_at)
18783
+ return false;
18784
+ return !isExpiredLocation(message.shared_location);
18785
+ }
18786
+ var UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT = 3e3;
18787
+ var _LiveLocationManager = class _LiveLocationManager extends WithSubscriptions {
18788
+ constructor({
18789
+ client,
18790
+ getDeviceId,
18791
+ watchLocation
18792
+ }) {
18793
+ if (!client.userID) {
18794
+ throw new Error("Live-location sharing is reserved for client-side use only");
18795
+ }
18796
+ super();
18797
+ this.registerSubscriptions = () => {
18798
+ this.incrementRefCount();
18799
+ if (this.hasSubscriptions) return;
18800
+ this.addUnsubscribeFunction(this.subscribeLiveLocationSharingUpdates());
18801
+ this.addUnsubscribeFunction(this.subscribeTargetMessagesChange());
18802
+ };
18803
+ this.unregisterSubscriptions = () => super.unregisterSubscriptions();
18804
+ this.client = client;
18805
+ this.state = new StateStore({
18806
+ messages: /* @__PURE__ */ new Map(),
18807
+ ready: false
18808
+ });
18809
+ this._deviceId = getDeviceId();
18810
+ this.getDeviceId = getDeviceId;
18811
+ this.watchLocation = watchLocation;
18812
+ }
18813
+ async init() {
18814
+ await this.assureStateInit();
18815
+ this.registerSubscriptions();
18816
+ }
18817
+ get messages() {
18818
+ return this.state.getLatestValue().messages;
18819
+ }
18820
+ get stateIsReady() {
18821
+ return this.state.getLatestValue().ready;
18822
+ }
18823
+ get deviceId() {
18824
+ if (!this._deviceId) {
18825
+ this._deviceId = this.getDeviceId();
18826
+ }
18827
+ return this._deviceId;
18828
+ }
18829
+ async assureStateInit() {
18830
+ if (this.stateIsReady) return;
18831
+ const { active_live_locations } = await this.client.getSharedLocations();
18832
+ this.state.next({
18833
+ messages: new Map(
18834
+ active_live_locations.filter((location) => !isExpiredLocation(location)).map((location) => [
18835
+ location.message_id,
18836
+ {
18837
+ ...location,
18838
+ stopSharingTimeout: setTimeout(
18839
+ () => {
18840
+ this.unregisterMessages([location.message_id]);
18841
+ },
18842
+ new Date(location.end_at).getTime() - Date.now()
18843
+ )
18844
+ }
18845
+ ])
18846
+ ),
18847
+ ready: true
18848
+ });
18849
+ }
18850
+ subscribeTargetMessagesChange() {
18851
+ let unsubscribeWatchLocation = null;
18852
+ const unsubscribe = this.state.subscribeWithSelector(
18853
+ ({ messages }) => ({ messages }),
18854
+ ({ messages }) => {
18855
+ if (!messages.size) {
18856
+ unsubscribeWatchLocation?.();
18857
+ unsubscribeWatchLocation = null;
18858
+ } else if (messages.size && !unsubscribeWatchLocation) {
18859
+ unsubscribeWatchLocation = this.subscribeWatchLocation();
18860
+ }
18861
+ }
18862
+ );
18863
+ return () => {
18864
+ unsubscribe();
18865
+ unsubscribeWatchLocation?.();
18866
+ };
18867
+ }
18868
+ subscribeWatchLocation() {
18869
+ let nextAllowedUpdateCallTimestamp = Date.now();
18870
+ const unsubscribe = this.watchLocation(({ latitude, longitude }) => {
18871
+ if (Date.now() < nextAllowedUpdateCallTimestamp) return;
18872
+ nextAllowedUpdateCallTimestamp = Date.now() + UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT;
18873
+ withCancellation(_LiveLocationManager.symbol, async () => {
18874
+ const promises = [];
18875
+ await this.assureStateInit();
18876
+ const expiredLocations = [];
18877
+ for (const [messageId, location] of this.messages) {
18878
+ if (isExpiredLocation(location)) {
18879
+ expiredLocations.push(location.message_id);
18880
+ continue;
18881
+ }
18882
+ if (location.latitude === latitude && location.longitude === longitude)
18883
+ continue;
18884
+ const promise = this.client.updateLocation({
18885
+ created_by_device_id: location.created_by_device_id,
18886
+ message_id: messageId,
18887
+ latitude,
18888
+ longitude
18889
+ });
18890
+ promises.push(promise);
18891
+ }
18892
+ this.unregisterMessages(expiredLocations);
18893
+ if (promises.length > 0) {
18894
+ await Promise.allSettled(promises);
18895
+ }
18896
+ });
18897
+ });
18898
+ return unsubscribe;
18899
+ }
18900
+ subscribeLiveLocationSharingUpdates() {
18901
+ const subscriptions = [
18902
+ ...[
18903
+ "live_location_sharing.started",
18904
+ "message.updated",
18905
+ "message.deleted"
18906
+ ].map(
18907
+ (eventType) => this.client.on(eventType, (event) => {
18908
+ if (!event.message) return;
18909
+ if (event.type === "live_location_sharing.started") {
18910
+ this.registerMessage(event.message);
18911
+ } else if (event.type === "message.updated") {
18912
+ const isRegistered = this.messages.has(event.message.id);
18913
+ if (isRegistered && !isValidLiveLocationMessage(event.message)) {
18914
+ this.unregisterMessages([event.message.id]);
18915
+ }
18916
+ this.registerMessage(event.message);
18917
+ } else {
18918
+ this.unregisterMessages([event.message.id]);
18919
+ }
18920
+ })
18921
+ ),
18922
+ this.client.on("live_location_sharing.stopped", (event) => {
18923
+ if (!event.live_location) return;
18924
+ this.unregisterMessages([event.live_location?.message_id]);
18925
+ })
18926
+ ];
18927
+ return () => subscriptions.forEach((subscription) => subscription.unsubscribe());
18928
+ }
18929
+ registerMessage(message) {
18930
+ if (!this.client.userID || message?.user?.id !== this.client.userID || !isValidLiveLocationMessage(message))
18931
+ return;
18932
+ this.state.next((currentValue) => {
18933
+ const messages = new Map(currentValue.messages);
18934
+ messages.set(message.id, {
18935
+ ...message.shared_location,
18936
+ stopSharingTimeout: setTimeout(
18937
+ () => {
18938
+ this.unregisterMessages([message.id]);
18939
+ },
18940
+ new Date(message.shared_location.end_at).getTime() - Date.now()
18941
+ )
18942
+ });
18943
+ return {
18944
+ ...currentValue,
18945
+ messages
18946
+ };
18947
+ });
18948
+ }
18949
+ unregisterMessages(messageIds) {
18950
+ const messages = this.messages;
18951
+ const removedMessages = new Set(messageIds);
18952
+ const newMessages = new Map(
18953
+ Array.from(messages).filter(([messageId, location]) => {
18954
+ if (removedMessages.has(messageId) && location.stopSharingTimeout) {
18955
+ clearTimeout(location.stopSharingTimeout);
18956
+ location.stopSharingTimeout = null;
18957
+ }
18958
+ return !removedMessages.has(messageId);
18959
+ })
18960
+ );
18961
+ if (newMessages.size === messages.size) return;
18962
+ this.state.partialNext({
18963
+ messages: newMessages
18964
+ });
18965
+ }
18966
+ };
18967
+ _LiveLocationManager.symbol = Symbol(_LiveLocationManager.name);
18968
+ var LiveLocationManager = _LiveLocationManager;
18969
+
18600
18970
  // src/utils/FixedSizeQueueCache.ts
18601
18971
  var FixedSizeQueueCache = class {
18602
18972
  constructor(size, options) {
@@ -18675,6 +19045,7 @@ export {
18675
19045
  DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS,
18676
19046
  DEFAULT_COMPOSER_CONFIG,
18677
19047
  DEFAULT_LINK_PREVIEW_MANAGER_CONFIG,
19048
+ DEFAULT_LOCATION_COMPOSER_CONFIG,
18678
19049
  DEFAULT_PAGINATION_OPTIONS,
18679
19050
  DEFAULT_REMINDER_MANAGER_CONFIG,
18680
19051
  DEFAULT_STOP_REFRESH_BOUNDARY_MS,
@@ -18690,6 +19061,8 @@ export {
18690
19061
  JWTUserToken,
18691
19062
  LinkPreviewStatus,
18692
19063
  LinkPreviewsManager,
19064
+ LiveLocationManager,
19065
+ LocationComposer,
18693
19066
  MAX_POLL_OPTIONS,
18694
19067
  MODERATION_ENTITY_TYPES,
18695
19068
  MaxPriority,
@@ -18726,6 +19099,7 @@ export {
18726
19099
  Thread,
18727
19100
  ThreadManager,
18728
19101
  TokenManager,
19102
+ UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT,
18729
19103
  UserFromToken,
18730
19104
  UserSearchSource,
18731
19105
  VALID_MAX_VOTES_VALUE_REGEX,
@@ -18756,6 +19130,7 @@ export {
18756
19130
  createMentionsMiddleware,
18757
19131
  createMessageComposerStateCompositionMiddleware,
18758
19132
  createPollComposerStateMiddleware,
19133
+ createSharedLocationCompositionMiddleware,
18759
19134
  createTextComposerCompositionMiddleware,
18760
19135
  createTextComposerPreValidationMiddleware,
18761
19136
  decodeBase64,
@@ -18792,6 +19167,7 @@ export {
18792
19167
  isOwnUser,
18793
19168
  isPatch,
18794
19169
  isScrapedContent,
19170
+ isSharedLocationResponse,
18795
19171
  isTargetedOptionTextUpdate,
18796
19172
  isUploadedAttachment,
18797
19173
  isVideoAttachment,