stream-chat 9.4.0 → 9.5.1

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 (53) hide show
  1. package/dist/cjs/index.browser.cjs +663 -135
  2. package/dist/cjs/index.browser.cjs.map +4 -4
  3. package/dist/cjs/index.node.cjs +673 -136
  4. package/dist/cjs/index.node.cjs.map +4 -4
  5. package/dist/esm/index.js +663 -135
  6. package/dist/esm/index.js.map +4 -4
  7. package/dist/types/client.d.ts +53 -20
  8. package/dist/types/events.d.ts +4 -0
  9. package/dist/types/index.d.ts +3 -1
  10. package/dist/types/messageComposer/middleware/textComposer/commands.d.ts +2 -2
  11. package/dist/types/messageComposer/middleware/textComposer/mentions.d.ts +2 -2
  12. package/dist/types/messageComposer/middleware/textComposer/types.d.ts +1 -1
  13. package/dist/types/pagination/BasePaginator.d.ts +69 -0
  14. package/dist/types/pagination/ReminderPaginator.d.ts +12 -0
  15. package/dist/types/pagination/index.d.ts +2 -0
  16. package/dist/types/reminders/Reminder.d.ts +37 -0
  17. package/dist/types/reminders/ReminderManager.d.ts +65 -0
  18. package/dist/types/reminders/ReminderTimer.d.ts +17 -0
  19. package/dist/types/reminders/index.d.ts +3 -0
  20. package/dist/types/search/BaseSearchSource.d.ts +87 -0
  21. package/dist/types/search/ChannelSearchSource.d.ts +17 -0
  22. package/dist/types/search/MessageSearchSource.d.ts +23 -0
  23. package/dist/types/search/SearchController.d.ts +44 -0
  24. package/dist/types/search/UserSearchSource.d.ts +16 -0
  25. package/dist/types/search/index.d.ts +5 -0
  26. package/dist/types/types.d.ts +43 -0
  27. package/package.json +1 -1
  28. package/src/channel.ts +2 -1
  29. package/src/client.ts +109 -40
  30. package/src/events.ts +6 -0
  31. package/src/index.ts +3 -1
  32. package/src/messageComposer/middleware/pollComposer/state.ts +4 -5
  33. package/src/messageComposer/middleware/textComposer/commands.ts +2 -2
  34. package/src/messageComposer/middleware/textComposer/mentions.ts +2 -2
  35. package/src/messageComposer/middleware/textComposer/types.ts +1 -1
  36. package/src/messageComposer/pollComposer.ts +3 -2
  37. package/src/pagination/BasePaginator.ts +184 -0
  38. package/src/pagination/ReminderPaginator.ts +38 -0
  39. package/src/pagination/index.ts +2 -0
  40. package/src/reminders/Reminder.ts +89 -0
  41. package/src/reminders/ReminderManager.ts +284 -0
  42. package/src/reminders/ReminderTimer.ts +86 -0
  43. package/src/reminders/index.ts +3 -0
  44. package/src/search/BaseSearchSource.ts +227 -0
  45. package/src/search/ChannelSearchSource.ts +34 -0
  46. package/src/search/MessageSearchSource.ts +88 -0
  47. package/src/search/SearchController.ts +154 -0
  48. package/src/search/UserSearchSource.ts +35 -0
  49. package/src/search/index.ts +5 -0
  50. package/src/token_manager.ts +3 -1
  51. package/src/types.ts +88 -0
  52. package/dist/types/search_controller.d.ts +0 -174
  53. package/src/search_controller.ts +0 -523
@@ -10670,6 +10670,7 @@ __export(index_exports, {
10670
10670
  AnyResource: () => AnyResource,
10671
10671
  AnyRole: () => AnyRole,
10672
10672
  AttachmentManager: () => AttachmentManager,
10673
+ BasePaginator: () => BasePaginator,
10673
10674
  BaseSearchSource: () => BaseSearchSource,
10674
10675
  BuiltinPermissions: () => BuiltinPermissions,
10675
10676
  BuiltinRoles: () => BuiltinRoles,
@@ -10687,6 +10688,9 @@ __export(index_exports, {
10687
10688
  DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS: () => DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS,
10688
10689
  DEFAULT_COMPOSER_CONFIG: () => DEFAULT_COMPOSER_CONFIG,
10689
10690
  DEFAULT_LINK_PREVIEW_MANAGER_CONFIG: () => DEFAULT_LINK_PREVIEW_MANAGER_CONFIG,
10691
+ DEFAULT_PAGINATION_OPTIONS: () => DEFAULT_PAGINATION_OPTIONS,
10692
+ DEFAULT_REMINDER_MANAGER_CONFIG: () => DEFAULT_REMINDER_MANAGER_CONFIG,
10693
+ DEFAULT_STOP_REFRESH_BOUNDARY_MS: () => DEFAULT_STOP_REFRESH_BOUNDARY_MS,
10690
10694
  DEFAULT_TEXT_COMPOSER_CONFIG: () => DEFAULT_TEXT_COMPOSER_CONFIG,
10691
10695
  Deny: () => Deny,
10692
10696
  DenyAll: () => DenyAll,
@@ -10719,6 +10723,10 @@ __export(index_exports, {
10719
10723
  PollComposerCompositionMiddlewareExecutor: () => PollComposerCompositionMiddlewareExecutor,
10720
10724
  PollComposerStateMiddlewareExecutor: () => PollComposerStateMiddlewareExecutor,
10721
10725
  PollManager: () => PollManager,
10726
+ Reminder: () => Reminder,
10727
+ ReminderManager: () => ReminderManager,
10728
+ ReminderPaginator: () => ReminderPaginator,
10729
+ ReminderTimer: () => ReminderTimer,
10722
10730
  SearchController: () => SearchController,
10723
10731
  Segment: () => Segment,
10724
10732
  StableWSConnection: () => StableWSConnection,
@@ -10806,7 +10814,8 @@ __export(index_exports, {
10806
10814
  readFileAsArrayBuffer: () => readFileAsArrayBuffer,
10807
10815
  removeDiacritics: () => removeDiacritics,
10808
10816
  replaceWordWithEntity: () => replaceWordWithEntity,
10809
- textIsEmpty: () => textIsEmpty
10817
+ textIsEmpty: () => textIsEmpty,
10818
+ timeLeftMs: () => timeLeftMs
10810
10819
  });
10811
10820
  module.exports = __toCommonJS(index_exports);
10812
10821
 
@@ -16774,15 +16783,14 @@ var pollStateChangeValidators = {
16774
16783
  return { max_votes_allowed: "Type a number from 2 to 10" };
16775
16784
  return { max_votes_allowed: void 0 };
16776
16785
  },
16777
- options: ({ value }) => {
16786
+ options: ({ value: options }) => {
16778
16787
  const errors = {};
16779
16788
  const seenOptions = /* @__PURE__ */ new Set();
16780
- value.forEach((option) => {
16781
- const trimmedText = option.text.trim();
16782
- if (seenOptions.has(trimmedText)) {
16789
+ options.forEach((option) => {
16790
+ if (seenOptions.has(option.text) && option.text.length) {
16783
16791
  errors[option.id] = "Option already exists";
16784
16792
  } else {
16785
- seenOptions.add(trimmedText);
16793
+ seenOptions.add(option.text);
16786
16794
  }
16787
16795
  });
16788
16796
  return Object.keys(errors).length > 0 ? { options: errors } : { options: void 0 };
@@ -17135,13 +17143,13 @@ var PollComposer = class {
17135
17143
  }
17136
17144
  get canCreatePoll() {
17137
17145
  const { data, errors } = this.state.getLatestValue();
17138
- const hasAtLeastOneOption = data.options.filter((o) => !!o.text).length > 0;
17146
+ const hasAtLeastOneNonEmptyOption = data.options.filter((o) => !!o.text.trim()).length > 0;
17139
17147
  const hasName = !!data.name;
17140
17148
  const maxVotesAllowedNumber = parseInt(
17141
17149
  data.max_votes_allowed?.match(VALID_MAX_VOTES_VALUE_REGEX)?.[0] || ""
17142
17150
  );
17143
17151
  const validMaxVotesAllowed = data.max_votes_allowed === "" || !!maxVotesAllowedNumber && (2 <= maxVotesAllowedNumber || maxVotesAllowedNumber <= 10);
17144
- return hasAtLeastOneOption && hasName && validMaxVotesAllowed && Object.values(errors).filter((errorText) => !!errorText).length === 0;
17152
+ return hasAtLeastOneNonEmptyOption && hasName && validMaxVotesAllowed && Object.values(errors).filter((errorText) => !!errorText).length === 0;
17145
17153
  }
17146
17154
  };
17147
17155
 
@@ -17584,7 +17592,7 @@ var MessageDraftComposerMiddlewareExecutor = class extends MiddlewareExecutor {
17584
17592
  }
17585
17593
  };
17586
17594
 
17587
- // src/search_controller.ts
17595
+ // src/search/BaseSearchSource.ts
17588
17596
  var DEFAULT_SEARCH_SOURCE_OPTIONS = {
17589
17597
  debounceMs: 300,
17590
17598
  pageSize: 10
@@ -17710,6 +17718,112 @@ var BaseSearchSource = class {
17710
17718
  this.activate();
17711
17719
  }
17712
17720
  };
17721
+
17722
+ // src/search/SearchController.ts
17723
+ var SearchController = class {
17724
+ constructor({ config, sources } = {}) {
17725
+ this.addSource = (source) => {
17726
+ this.state.partialNext({
17727
+ sources: [...this.sources, source]
17728
+ });
17729
+ };
17730
+ this.getSource = (sourceType) => this.sources.find((s) => s.type === sourceType);
17731
+ this.removeSource = (sourceType) => {
17732
+ const newSources = this.sources.filter((s) => s.type !== sourceType);
17733
+ if (newSources.length === this.sources.length) return;
17734
+ this.state.partialNext({ sources: newSources });
17735
+ };
17736
+ this.activateSource = (sourceType) => {
17737
+ const source = this.getSource(sourceType);
17738
+ if (!source || source.isActive) return;
17739
+ if (this.config.keepSingleActiveSource) {
17740
+ this.sources.forEach((s) => {
17741
+ if (s.type !== sourceType) {
17742
+ s.deactivate();
17743
+ }
17744
+ });
17745
+ }
17746
+ source.activate();
17747
+ this.state.partialNext({ sources: [...this.sources] });
17748
+ };
17749
+ this.deactivateSource = (sourceType) => {
17750
+ const source = this.getSource(sourceType);
17751
+ if (!source?.isActive) return;
17752
+ if (this.activeSources.length === 1) return;
17753
+ source.deactivate();
17754
+ this.state.partialNext({ sources: [...this.sources] });
17755
+ };
17756
+ this.activate = () => {
17757
+ if (!this.activeSources.length) {
17758
+ const sourcesToActivate = this.config.keepSingleActiveSource ? this.sources.slice(0, 1) : this.sources;
17759
+ sourcesToActivate.forEach((s) => s.activate());
17760
+ }
17761
+ if (this.isActive) return;
17762
+ this.state.partialNext({ isActive: true });
17763
+ };
17764
+ this.search = async (searchQuery) => {
17765
+ const searchedSources = this.activeSources;
17766
+ this.state.partialNext({
17767
+ searchQuery
17768
+ });
17769
+ await Promise.all(searchedSources.map((source) => source.search(searchQuery)));
17770
+ };
17771
+ this.cancelSearchQueries = () => {
17772
+ this.activeSources.forEach((s) => s.cancelScheduledQuery());
17773
+ };
17774
+ this.clear = () => {
17775
+ this.cancelSearchQueries();
17776
+ this.sources.forEach(
17777
+ (source) => source.state.next({ ...source.initialState, isActive: source.isActive })
17778
+ );
17779
+ this.state.next((current) => ({
17780
+ ...current,
17781
+ isActive: true,
17782
+ queriesInProgress: [],
17783
+ searchQuery: ""
17784
+ }));
17785
+ };
17786
+ this.exit = () => {
17787
+ this.cancelSearchQueries();
17788
+ this.sources.forEach(
17789
+ (source) => source.state.next({ ...source.initialState, isActive: source.isActive })
17790
+ );
17791
+ this.state.next((current) => ({
17792
+ ...current,
17793
+ isActive: false,
17794
+ queriesInProgress: [],
17795
+ searchQuery: ""
17796
+ }));
17797
+ };
17798
+ this.state = new StateStore({
17799
+ isActive: false,
17800
+ searchQuery: "",
17801
+ sources: sources ?? []
17802
+ });
17803
+ this._internalState = new StateStore({});
17804
+ this.config = { keepSingleActiveSource: true, ...config };
17805
+ }
17806
+ get hasNext() {
17807
+ return this.sources.some((source) => source.hasNext);
17808
+ }
17809
+ get sources() {
17810
+ return this.state.getLatestValue().sources;
17811
+ }
17812
+ get activeSources() {
17813
+ return this.state.getLatestValue().sources.filter((s) => s.isActive);
17814
+ }
17815
+ get isActive() {
17816
+ return this.state.getLatestValue().isActive;
17817
+ }
17818
+ get searchQuery() {
17819
+ return this.state.getLatestValue().searchQuery;
17820
+ }
17821
+ get searchSourceTypes() {
17822
+ return this.sources.map((s) => s.type);
17823
+ }
17824
+ };
17825
+
17826
+ // src/search/UserSearchSource.ts
17713
17827
  var UserSearchSource = class extends BaseSearchSource {
17714
17828
  constructor(client, options) {
17715
17829
  super(options);
@@ -17733,6 +17847,8 @@ var UserSearchSource = class extends BaseSearchSource {
17733
17847
  return items.filter((u) => u.id !== this.client.user?.id);
17734
17848
  }
17735
17849
  };
17850
+
17851
+ // src/search/ChannelSearchSource.ts
17736
17852
  var ChannelSearchSource = class extends BaseSearchSource {
17737
17853
  constructor(client, options) {
17738
17854
  super(options);
@@ -17754,6 +17870,8 @@ var ChannelSearchSource = class extends BaseSearchSource {
17754
17870
  return items;
17755
17871
  }
17756
17872
  };
17873
+
17874
+ // src/search/MessageSearchSource.ts
17757
17875
  var MessageSearchSource = class extends BaseSearchSource {
17758
17876
  constructor(client, options) {
17759
17877
  super(options);
@@ -17814,108 +17932,6 @@ var MessageSearchSource = class extends BaseSearchSource {
17814
17932
  return items;
17815
17933
  }
17816
17934
  };
17817
- var SearchController = class {
17818
- constructor({ config, sources } = {}) {
17819
- this.addSource = (source) => {
17820
- this.state.partialNext({
17821
- sources: [...this.sources, source]
17822
- });
17823
- };
17824
- this.getSource = (sourceType) => this.sources.find((s) => s.type === sourceType);
17825
- this.removeSource = (sourceType) => {
17826
- const newSources = this.sources.filter((s) => s.type !== sourceType);
17827
- if (newSources.length === this.sources.length) return;
17828
- this.state.partialNext({ sources: newSources });
17829
- };
17830
- this.activateSource = (sourceType) => {
17831
- const source = this.getSource(sourceType);
17832
- if (!source || source.isActive) return;
17833
- if (this.config.keepSingleActiveSource) {
17834
- this.sources.forEach((s) => {
17835
- if (s.type !== sourceType) {
17836
- s.deactivate();
17837
- }
17838
- });
17839
- }
17840
- source.activate();
17841
- this.state.partialNext({ sources: [...this.sources] });
17842
- };
17843
- this.deactivateSource = (sourceType) => {
17844
- const source = this.getSource(sourceType);
17845
- if (!source?.isActive) return;
17846
- if (this.activeSources.length === 1) return;
17847
- source.deactivate();
17848
- this.state.partialNext({ sources: [...this.sources] });
17849
- };
17850
- this.activate = () => {
17851
- if (!this.activeSources.length) {
17852
- const sourcesToActivate = this.config.keepSingleActiveSource ? this.sources.slice(0, 1) : this.sources;
17853
- sourcesToActivate.forEach((s) => s.activate());
17854
- }
17855
- if (this.isActive) return;
17856
- this.state.partialNext({ isActive: true });
17857
- };
17858
- this.search = async (searchQuery) => {
17859
- const searchedSources = this.activeSources;
17860
- this.state.partialNext({
17861
- searchQuery
17862
- });
17863
- await Promise.all(searchedSources.map((source) => source.search(searchQuery)));
17864
- };
17865
- this.cancelSearchQueries = () => {
17866
- this.activeSources.forEach((s) => s.cancelScheduledQuery());
17867
- };
17868
- this.clear = () => {
17869
- this.cancelSearchQueries();
17870
- this.sources.forEach(
17871
- (source) => source.state.next({ ...source.initialState, isActive: source.isActive })
17872
- );
17873
- this.state.next((current) => ({
17874
- ...current,
17875
- isActive: true,
17876
- queriesInProgress: [],
17877
- searchQuery: ""
17878
- }));
17879
- };
17880
- this.exit = () => {
17881
- this.cancelSearchQueries();
17882
- this.sources.forEach(
17883
- (source) => source.state.next({ ...source.initialState, isActive: source.isActive })
17884
- );
17885
- this.state.next((current) => ({
17886
- ...current,
17887
- isActive: false,
17888
- queriesInProgress: [],
17889
- searchQuery: ""
17890
- }));
17891
- };
17892
- this.state = new StateStore({
17893
- isActive: false,
17894
- searchQuery: "",
17895
- sources: sources ?? []
17896
- });
17897
- this._internalState = new StateStore({});
17898
- this.config = { keepSingleActiveSource: true, ...config };
17899
- }
17900
- get hasNext() {
17901
- return this.sources.some((source) => source.hasNext);
17902
- }
17903
- get sources() {
17904
- return this.state.getLatestValue().sources;
17905
- }
17906
- get activeSources() {
17907
- return this.state.getLatestValue().sources.filter((s) => s.isActive);
17908
- }
17909
- get isActive() {
17910
- return this.state.getLatestValue().isActive;
17911
- }
17912
- get searchQuery() {
17913
- return this.state.getLatestValue().searchQuery;
17914
- }
17915
- get searchSourceTypes() {
17916
- return this.sources.map((s) => s.type);
17917
- }
17918
- };
17919
17935
 
17920
17936
  // src/messageComposer/middleware/textComposer/textMiddlewareUtils.ts
17921
17937
  var getTriggerCharWithToken = ({
@@ -20694,6 +20710,7 @@ var Channel = class {
20694
20710
  })
20695
20711
  };
20696
20712
  this.getClient().polls.hydratePollCache(state.messages, true);
20713
+ this.getClient().reminders.hydrateState(state.messages);
20697
20714
  if (state.draft) {
20698
20715
  this.messageComposer.initState({ composition: state.draft });
20699
20716
  }
@@ -21973,7 +21990,9 @@ var TokenManager = class {
21973
21990
  try {
21974
21991
  this.token = await this.tokenProvider();
21975
21992
  } catch (e) {
21976
- return reject(new Error(`Call to tokenProvider failed with message: ${e}`));
21993
+ return reject(
21994
+ new Error(`Call to tokenProvider failed with message: ${e}`, { cause: e })
21995
+ );
21977
21996
  }
21978
21997
  resolve(this.token);
21979
21998
  }
@@ -23723,6 +23742,458 @@ var NotificationManager = class {
23723
23742
  }
23724
23743
  };
23725
23744
 
23745
+ // src/reminders/ReminderTimer.ts
23746
+ var oneMinute = 60 * 1e3;
23747
+ var oneHour = 60 * oneMinute;
23748
+ var oneDay = 24 * oneHour;
23749
+ var oneWeek = 7 * oneDay;
23750
+ var GROUP_BOUNDS = {
23751
+ minute: { lower: oneMinute, upper: oneHour },
23752
+ hour: { lower: oneHour, upper: oneDay },
23753
+ day: { lower: oneDay, upper: oneWeek }
23754
+ };
23755
+ var DEFAULT_STOP_REFRESH_BOUNDARY_MS = 2 * oneWeek;
23756
+ var ReminderTimer = class {
23757
+ constructor({
23758
+ reminder,
23759
+ config
23760
+ }) {
23761
+ this.timeout = null;
23762
+ this.stopRefreshBoundaryMs = DEFAULT_STOP_REFRESH_BOUNDARY_MS;
23763
+ this.getRefreshIntervalLength = () => {
23764
+ if (!this.reminder.remindAt) return null;
23765
+ const distanceFromDeadlineMs = Math.abs(timeLeftMs(this.reminder.remindAt.getTime()));
23766
+ let refreshInterval;
23767
+ if (distanceFromDeadlineMs === 0) {
23768
+ refreshInterval = oneMinute;
23769
+ } else if (distanceFromDeadlineMs < GROUP_BOUNDS.minute.lower) {
23770
+ refreshInterval = distanceFromDeadlineMs;
23771
+ } else if (distanceFromDeadlineMs <= GROUP_BOUNDS.minute.upper) {
23772
+ refreshInterval = oneMinute;
23773
+ } else if (distanceFromDeadlineMs <= GROUP_BOUNDS.hour.upper) {
23774
+ refreshInterval = oneHour;
23775
+ } else {
23776
+ refreshInterval = oneDay;
23777
+ }
23778
+ return refreshInterval;
23779
+ };
23780
+ this.init = () => {
23781
+ if (!this.reminder.remindAt) return null;
23782
+ const timeoutLength = this.getRefreshIntervalLength();
23783
+ if (timeoutLength === null) return null;
23784
+ const boundaryTimestamp = this.reminder.remindAt?.getTime() + this.stopRefreshBoundaryMs;
23785
+ const timeLeftToBoundary = boundaryTimestamp - Date.now();
23786
+ if (timeLeftToBoundary <= 0) {
23787
+ this.timeout = null;
23788
+ return;
23789
+ }
23790
+ if (this.timeout) clearTimeout(this.timeout);
23791
+ this.timeout = setTimeout(() => {
23792
+ this.reminder.refreshTimeLeft();
23793
+ this.init();
23794
+ }, timeoutLength);
23795
+ };
23796
+ this.clear = () => {
23797
+ if (this.timeout) {
23798
+ clearInterval(this.timeout);
23799
+ this.timeout = null;
23800
+ }
23801
+ };
23802
+ this.reminder = reminder;
23803
+ if (typeof config?.stopRefreshBoundaryMs === "number") {
23804
+ this.stopRefreshBoundaryMs = config.stopRefreshBoundaryMs;
23805
+ }
23806
+ }
23807
+ };
23808
+
23809
+ // src/reminders/Reminder.ts
23810
+ var timeLeftMs = (remindAt) => remindAt - (/* @__PURE__ */ new Date()).getTime();
23811
+ var _Reminder = class _Reminder {
23812
+ constructor({ data, config }) {
23813
+ this.setState = (data) => {
23814
+ this.state.next((current) => {
23815
+ const newState = { ...current, ..._Reminder.toStateValue(data) };
23816
+ if (newState.remind_at) {
23817
+ newState.timeLeftMs = timeLeftMs(newState.remind_at.getTime());
23818
+ }
23819
+ return newState;
23820
+ });
23821
+ if (data.remind_at) {
23822
+ this.initTimer();
23823
+ } else if (!data.remind_at) {
23824
+ this.clearTimer();
23825
+ }
23826
+ };
23827
+ this.refreshTimeLeft = () => {
23828
+ if (!this.remindAt) return;
23829
+ this.state.partialNext({ timeLeftMs: timeLeftMs(this.remindAt.getTime()) });
23830
+ };
23831
+ this.initTimer = () => {
23832
+ this.timer.init();
23833
+ };
23834
+ this.clearTimer = () => {
23835
+ this.timer.clear();
23836
+ };
23837
+ this.state = new StateStore(_Reminder.toStateValue(data));
23838
+ this.timer = new ReminderTimer({ reminder: this, config });
23839
+ this.initTimer();
23840
+ }
23841
+ get id() {
23842
+ return this.state.getLatestValue().message_id;
23843
+ }
23844
+ get remindAt() {
23845
+ return this.state.getLatestValue().remind_at;
23846
+ }
23847
+ get timeLeftMs() {
23848
+ return this.state.getLatestValue().timeLeftMs;
23849
+ }
23850
+ };
23851
+ _Reminder.toStateValue = (data) => ({
23852
+ ...data,
23853
+ created_at: new Date(data.created_at),
23854
+ message: data.message || null,
23855
+ remind_at: data.remind_at ? new Date(data.remind_at) : null,
23856
+ timeLeftMs: data.remind_at ? timeLeftMs(new Date(data.remind_at).getTime()) : null,
23857
+ updated_at: new Date(data.updated_at),
23858
+ user: data.user || null
23859
+ });
23860
+ var Reminder = _Reminder;
23861
+
23862
+ // src/pagination/BasePaginator.ts
23863
+ var DEFAULT_PAGINATION_OPTIONS = {
23864
+ debounceMs: 300,
23865
+ pageSize: 10
23866
+ };
23867
+ var BasePaginator = class {
23868
+ constructor(options) {
23869
+ this._isCursorPagination = false;
23870
+ this.setDebounceOptions = ({ debounceMs }) => {
23871
+ this._executeQueryDebounced = debounce(this.executeQuery.bind(this), debounceMs);
23872
+ };
23873
+ this.canExecuteQuery = (direction) => !this.isLoading && direction === "next" && this.hasNext || direction === "prev" && this.hasPrev;
23874
+ this.next = () => this.executeQuery({ direction: "next" });
23875
+ this.prev = () => this.executeQuery({ direction: "prev" });
23876
+ this.nextDebounced = () => {
23877
+ this._executeQueryDebounced({ direction: "next" });
23878
+ };
23879
+ this.prevDebounced = () => {
23880
+ this._executeQueryDebounced({ direction: "prev" });
23881
+ };
23882
+ const { debounceMs, pageSize } = { ...DEFAULT_PAGINATION_OPTIONS, ...options };
23883
+ this.pageSize = pageSize;
23884
+ this.state = new StateStore(this.initialState);
23885
+ this.setDebounceOptions({ debounceMs });
23886
+ }
23887
+ get lastQueryError() {
23888
+ return this.state.getLatestValue().lastQueryError;
23889
+ }
23890
+ get hasNext() {
23891
+ return this.state.getLatestValue().hasNext;
23892
+ }
23893
+ get hasPrev() {
23894
+ return this.state.getLatestValue().hasPrev;
23895
+ }
23896
+ get hasResults() {
23897
+ return Array.isArray(this.state.getLatestValue().items);
23898
+ }
23899
+ get isLoading() {
23900
+ return this.state.getLatestValue().isLoading;
23901
+ }
23902
+ get initialState() {
23903
+ return {
23904
+ hasNext: true,
23905
+ hasPrev: true,
23906
+ //todo: check if optimistic value does not cause problems in UI
23907
+ isLoading: false,
23908
+ items: void 0,
23909
+ lastQueryError: void 0,
23910
+ cursor: void 0,
23911
+ offset: 0
23912
+ };
23913
+ }
23914
+ get items() {
23915
+ return this.state.getLatestValue().items;
23916
+ }
23917
+ get cursor() {
23918
+ return this.state.getLatestValue().cursor;
23919
+ }
23920
+ get offset() {
23921
+ return this.state.getLatestValue().offset;
23922
+ }
23923
+ getStateBeforeFirstQuery() {
23924
+ return {
23925
+ ...this.initialState,
23926
+ isLoading: true
23927
+ };
23928
+ }
23929
+ getStateAfterQuery(stateUpdate, isFirstPage) {
23930
+ const current = this.state.getLatestValue();
23931
+ return {
23932
+ ...current,
23933
+ lastQueryError: void 0,
23934
+ // reset lastQueryError that can be overridden by the stateUpdate
23935
+ ...stateUpdate,
23936
+ isLoading: false,
23937
+ items: isFirstPage ? stateUpdate.items : [...this.items ?? [], ...stateUpdate.items || []]
23938
+ };
23939
+ }
23940
+ async executeQuery({ direction }) {
23941
+ if (!this.canExecuteQuery(direction)) return;
23942
+ const isFirstPage = typeof this.items === "undefined";
23943
+ if (isFirstPage) {
23944
+ this.state.next(this.getStateBeforeFirstQuery());
23945
+ } else {
23946
+ this.state.partialNext({ isLoading: true });
23947
+ }
23948
+ const stateUpdate = {};
23949
+ try {
23950
+ const results = await this.query({ direction });
23951
+ if (!results) return;
23952
+ const { items, next, prev } = results;
23953
+ if (isFirstPage && (next || prev)) {
23954
+ this._isCursorPagination = true;
23955
+ }
23956
+ if (this._isCursorPagination) {
23957
+ stateUpdate.cursor = { next: next || null, prev: prev || null };
23958
+ stateUpdate.hasNext = !!next;
23959
+ stateUpdate.hasPrev = !!prev;
23960
+ } else {
23961
+ stateUpdate.offset = (this.offset ?? 0) + items.length;
23962
+ stateUpdate.hasNext = items.length === this.pageSize;
23963
+ }
23964
+ stateUpdate.items = await this.filterQueryResults(items);
23965
+ } catch (e) {
23966
+ stateUpdate.lastQueryError = e;
23967
+ } finally {
23968
+ this.state.next(this.getStateAfterQuery(stateUpdate, isFirstPage));
23969
+ }
23970
+ }
23971
+ cancelScheduledQuery() {
23972
+ this._executeQueryDebounced.cancel();
23973
+ }
23974
+ resetState() {
23975
+ this.state.next(this.initialState);
23976
+ }
23977
+ };
23978
+
23979
+ // src/pagination/ReminderPaginator.ts
23980
+ var ReminderPaginator = class extends BasePaginator {
23981
+ constructor(client, options) {
23982
+ super(options);
23983
+ this.query = async ({
23984
+ direction
23985
+ }) => {
23986
+ const cursor = this.cursor?.[direction];
23987
+ const {
23988
+ reminders: items,
23989
+ next,
23990
+ prev
23991
+ } = await this.client.queryReminders({
23992
+ filter: this.filters,
23993
+ sort: this.sort,
23994
+ limit: this.pageSize,
23995
+ [direction]: cursor
23996
+ });
23997
+ return { items, next, prev };
23998
+ };
23999
+ this.filterQueryResults = (items) => items;
24000
+ this.client = client;
24001
+ }
24002
+ };
24003
+
24004
+ // src/reminders/ReminderManager.ts
24005
+ var oneMinute2 = 60 * 1e3;
24006
+ var oneHour2 = 60 * oneMinute2;
24007
+ var oneDay2 = 24 * oneHour2;
24008
+ var DEFAULT_REMINDER_MANAGER_CONFIG = {
24009
+ scheduledOffsetsMs: [
24010
+ 2 * oneMinute2,
24011
+ 30 * oneMinute2,
24012
+ oneHour2,
24013
+ 2 * oneHour2,
24014
+ 8 * oneHour2,
24015
+ oneDay2
24016
+ ]
24017
+ };
24018
+ var isReminderExistsError = (error) => error.message.match("already has reminder created for this message_id");
24019
+ var isReminderDoesNotExistError = (error) => error.message.match("reminder does not exist");
24020
+ var _ReminderManager = class _ReminderManager extends WithSubscriptions {
24021
+ constructor({ client, config }) {
24022
+ super();
24023
+ this.upsertToState = ({
24024
+ data,
24025
+ overwrite = true
24026
+ }) => {
24027
+ if (!this.client._cacheEnabled()) {
24028
+ return;
24029
+ }
24030
+ const cachedReminder = this.getFromState(data.message_id);
24031
+ if (!cachedReminder) {
24032
+ const reminder = new Reminder({
24033
+ data,
24034
+ config: { stopRefreshBoundaryMs: this.stopTimerRefreshBoundaryMs }
24035
+ });
24036
+ this.state.partialNext({
24037
+ reminders: new Map(this.reminders.set(data.message_id, reminder))
24038
+ });
24039
+ } else if (overwrite) {
24040
+ cachedReminder.setState(data);
24041
+ }
24042
+ return cachedReminder;
24043
+ };
24044
+ this.removeFromState = (messageId) => {
24045
+ const cachedReminder = this.getFromState(messageId);
24046
+ if (!cachedReminder) return;
24047
+ cachedReminder.clearTimer();
24048
+ const reminders = this.reminders;
24049
+ reminders.delete(messageId);
24050
+ this.state.partialNext({ reminders: new Map(reminders) });
24051
+ };
24052
+ this.hydrateState = (messages) => {
24053
+ messages.forEach(({ reminder }) => {
24054
+ if (reminder) {
24055
+ this.upsertToState({ data: reminder });
24056
+ }
24057
+ });
24058
+ };
24059
+ // State API END //
24060
+ // Timers API START //
24061
+ this.initTimers = () => {
24062
+ this.reminders.forEach((reminder) => reminder.initTimer());
24063
+ };
24064
+ this.clearTimers = () => {
24065
+ this.reminders.forEach((reminder) => reminder.clearTimer());
24066
+ };
24067
+ this.registerSubscriptions = () => {
24068
+ if (this.hasSubscriptions) return;
24069
+ this.addUnsubscribeFunction(this.subscribeReminderCreated());
24070
+ this.addUnsubscribeFunction(this.subscribeReminderUpdated());
24071
+ this.addUnsubscribeFunction(this.subscribeReminderDeleted());
24072
+ this.addUnsubscribeFunction(this.subscribeNotificationReminderDue());
24073
+ this.addUnsubscribeFunction(this.subscribeMessageDeleted());
24074
+ this.addUnsubscribeFunction(this.subscribeMessageUndeleted());
24075
+ this.addUnsubscribeFunction(this.subscribePaginatorStateUpdated());
24076
+ this.addUnsubscribeFunction(this.subscribeConfigStateUpdated());
24077
+ };
24078
+ this.subscribeReminderCreated = () => this.client.on("reminder.created", (event) => {
24079
+ if (!_ReminderManager.isReminderWsEventPayload(event)) return;
24080
+ const { reminder } = event;
24081
+ this.upsertToState({ data: reminder });
24082
+ }).unsubscribe;
24083
+ this.subscribeReminderUpdated = () => this.client.on("reminder.updated", (event) => {
24084
+ if (!_ReminderManager.isReminderWsEventPayload(event)) return;
24085
+ const { reminder } = event;
24086
+ this.upsertToState({ data: reminder });
24087
+ }).unsubscribe;
24088
+ this.subscribeReminderDeleted = () => this.client.on("reminder.deleted", (event) => {
24089
+ if (!_ReminderManager.isReminderWsEventPayload(event)) return;
24090
+ this.removeFromState(event.message_id);
24091
+ }).unsubscribe;
24092
+ this.subscribeMessageDeleted = () => this.client.on("message.deleted", (event) => {
24093
+ if (!event.message?.id) return;
24094
+ this.removeFromState(event.message.id);
24095
+ }).unsubscribe;
24096
+ this.subscribeMessageUndeleted = () => this.client.on("message.undeleted", (event) => {
24097
+ if (!event.message?.reminder) return;
24098
+ this.upsertToState({ data: event.message.reminder });
24099
+ }).unsubscribe;
24100
+ this.subscribeNotificationReminderDue = () => this.client.on("notification.reminder_due", () => null).unsubscribe;
24101
+ // todo: what should be performed on this event?
24102
+ this.subscribePaginatorStateUpdated = () => this.paginator.state.subscribeWithSelector(
24103
+ ({ items }) => [items],
24104
+ ([items]) => {
24105
+ if (!items) return;
24106
+ for (const reminder of items) {
24107
+ this.upsertToState({ data: reminder });
24108
+ }
24109
+ }
24110
+ );
24111
+ this.subscribeConfigStateUpdated = () => this.configState.subscribeWithSelector(
24112
+ ({ stopTimerRefreshBoundaryMs }) => ({ stopTimerRefreshBoundaryMs }),
24113
+ ({ stopTimerRefreshBoundaryMs }, previousValue) => {
24114
+ if (typeof stopTimerRefreshBoundaryMs === "number" && stopTimerRefreshBoundaryMs !== previousValue?.stopTimerRefreshBoundaryMs) {
24115
+ this.reminders.forEach((reminder) => {
24116
+ if (reminder.timer) {
24117
+ reminder.timer.stopRefreshBoundaryMs = stopTimerRefreshBoundaryMs;
24118
+ }
24119
+ });
24120
+ }
24121
+ }
24122
+ );
24123
+ // WS event handling END //
24124
+ // API calls START //
24125
+ this.upsertReminder = async (options) => {
24126
+ const { messageId } = options;
24127
+ if (this.getFromState(messageId)) {
24128
+ try {
24129
+ return await this.updateReminder(options);
24130
+ } catch (error) {
24131
+ if (isReminderDoesNotExistError(error)) {
24132
+ return await this.createReminder(options);
24133
+ }
24134
+ throw error;
24135
+ }
24136
+ } else {
24137
+ try {
24138
+ return await this.createReminder(options);
24139
+ } catch (error) {
24140
+ if (isReminderExistsError(error)) {
24141
+ return await this.updateReminder(options);
24142
+ }
24143
+ throw error;
24144
+ }
24145
+ }
24146
+ };
24147
+ this.createReminder = async (options) => {
24148
+ const { reminder } = await this.client.createReminder(options);
24149
+ return this.upsertToState({ data: reminder, overwrite: false });
24150
+ };
24151
+ this.updateReminder = async (options) => {
24152
+ const { reminder } = await this.client.updateReminder(options);
24153
+ return this.upsertToState({ data: reminder });
24154
+ };
24155
+ this.deleteReminder = async (messageId) => {
24156
+ await this.client.deleteReminder(messageId);
24157
+ this.removeFromState(messageId);
24158
+ };
24159
+ this.queryNextReminders = async () => {
24160
+ await this.paginator.next();
24161
+ };
24162
+ this.queryPreviousReminders = async () => {
24163
+ await this.paginator.prev();
24164
+ };
24165
+ this.client = client;
24166
+ this.configState = new StateStore({
24167
+ scheduledOffsetsMs: config?.scheduledOffsetsMs ?? DEFAULT_REMINDER_MANAGER_CONFIG.scheduledOffsetsMs
24168
+ });
24169
+ this.state = new StateStore({ reminders: /* @__PURE__ */ new Map() });
24170
+ this.paginator = new ReminderPaginator(client);
24171
+ }
24172
+ // Config API START //
24173
+ updateConfig(config) {
24174
+ this.configState.partialNext(config);
24175
+ }
24176
+ get stopTimerRefreshBoundaryMs() {
24177
+ return this.configState.getLatestValue().stopTimerRefreshBoundaryMs;
24178
+ }
24179
+ get scheduledOffsetsMs() {
24180
+ return this.configState.getLatestValue().scheduledOffsetsMs;
24181
+ }
24182
+ // Config API END //
24183
+ // State API START //
24184
+ get reminders() {
24185
+ return this.state.getLatestValue().reminders;
24186
+ }
24187
+ getFromState(messageId) {
24188
+ return this.reminders.get(messageId);
24189
+ }
24190
+ // API calls END //
24191
+ };
24192
+ // Timers API END //
24193
+ // WS event handling START //
24194
+ _ReminderManager.isReminderWsEventPayload = (event) => !!event.reminder && (event.type.startsWith("reminder.") || event.type === "notification.reminder_due");
24195
+ var ReminderManager = _ReminderManager;
24196
+
23726
24197
  // src/client.ts
23727
24198
  function isString3(x) {
23728
24199
  return typeof x === "string" || x instanceof String;
@@ -23738,6 +24209,9 @@ var StreamChat = class _StreamChat {
23738
24209
  });
23739
24210
  this._getConnectionID = () => this.wsConnection?.connectionID || this.wsFallback?.connectionID;
23740
24211
  this._hasConnectionID = () => Boolean(this._getConnectionID());
24212
+ this.setMessageComposerSetupFunction = (setupFunction) => {
24213
+ this._messageComposerSetupState.partialNext({ setupFunction });
24214
+ };
23741
24215
  /**
23742
24216
  * connectUser - Set the current user and open a WebSocket connection
23743
24217
  *
@@ -24306,9 +24780,6 @@ var StreamChat = class _StreamChat {
24306
24780
  device: this.options.device,
24307
24781
  client_request_id
24308
24782
  });
24309
- this.setMessageComposerSetupFunction = (setupFunction) => {
24310
- this._messageComposerSetupState.partialNext({ setupFunction });
24311
- };
24312
24783
  this.key = key;
24313
24784
  this.listeners = {};
24314
24785
  this.state = new ClientState({ client: this });
@@ -24363,6 +24834,7 @@ var StreamChat = class _StreamChat {
24363
24834
  this.recoverStateOnReconnect = this.options.recoverStateOnReconnect;
24364
24835
  this.threads = new ThreadManager({ client: this });
24365
24836
  this.polls = new PollManager({ client: this });
24837
+ this.reminders = new ReminderManager({ client: this });
24366
24838
  }
24367
24839
  static getInstance(key, secretOrOptions, options) {
24368
24840
  if (!_StreamChat._instance) {
@@ -24498,15 +24970,15 @@ var StreamChat = class _StreamChat {
24498
24970
  * @param {string} userID User ID. If user has no devices, it will error
24499
24971
  * @param {TestPushDataInput} [data] Overrides for push templates/message used
24500
24972
  * IE: {
24501
- messageID: 'id-of-message', // will error if message does not exist
24502
- apnTemplate: '{}', // if app doesn't have apn configured it will error
24503
- firebaseTemplate: '{}', // if app doesn't have firebase configured it will error
24504
- firebaseDataTemplate: '{}', // if app doesn't have firebase configured it will error
24505
- skipDevices: true, // skip config/device checks and sending to real devices
24506
- pushProviderName: 'staging' // one of your configured push providers
24507
- pushProviderType: 'apn' // one of supported provider types
24508
- }
24509
- */
24973
+ messageID: 'id-of-message', // will error if message does not exist
24974
+ apnTemplate: '{}', // if app doesn't have apn configured it will error
24975
+ firebaseTemplate: '{}', // if app doesn't have firebase configured it will error
24976
+ firebaseDataTemplate: '{}', // if app doesn't have firebase configured it will error
24977
+ skipDevices: true, // skip config/device checks and sending to real devices
24978
+ pushProviderName: 'staging' // one of your configured push providers
24979
+ pushProviderType: 'apn' // one of supported provider types
24980
+ }
24981
+ */
24510
24982
  async testPushSettings(userID, data = {}) {
24511
24983
  return await this.post(this.baseURL + "/check_push", {
24512
24984
  user_id: userID,
@@ -24524,10 +24996,10 @@ var StreamChat = class _StreamChat {
24524
24996
  *
24525
24997
  * @param {TestSQSDataInput} [data] Overrides SQS settings for testing if needed
24526
24998
  * IE: {
24527
- sqs_key: 'auth_key',
24528
- sqs_secret: 'auth_secret',
24529
- sqs_url: 'url_to_queue',
24530
- }
24999
+ sqs_key: 'auth_key',
25000
+ sqs_secret: 'auth_secret',
25001
+ sqs_url: 'url_to_queue',
25002
+ }
24531
25003
  */
24532
25004
  async testSQSSettings(data = {}) {
24533
25005
  return await this.post(this.baseURL + "/check_sqs", data);
@@ -24537,10 +25009,10 @@ var StreamChat = class _StreamChat {
24537
25009
  *
24538
25010
  * @param {TestSNSDataInput} [data] Overrides SNS settings for testing if needed
24539
25011
  * IE: {
24540
- sns_key: 'auth_key',
24541
- sns_secret: 'auth_secret',
24542
- sns_topic_arn: 'topic_to_publish_to',
24543
- }
25012
+ sns_key: 'auth_key',
25013
+ sns_secret: 'auth_secret',
25014
+ sns_topic_arn: 'topic_to_publish_to',
25015
+ }
24544
25016
  */
24545
25017
  async testSNSSettings(data = {}) {
24546
25018
  return await this.post(this.baseURL + "/check_sns", data);
@@ -25021,6 +25493,7 @@ var StreamChat = class _StreamChat {
25021
25493
  })
25022
25494
  };
25023
25495
  this.polls.hydratePollCache(channelState.messages, true);
25496
+ this.reminders.hydrateState(channelState.messages);
25024
25497
  }
25025
25498
  if (channelState.draft) {
25026
25499
  c.messageComposer.initState({ composition: channelState.draft });
@@ -25598,7 +26071,7 @@ var StreamChat = class _StreamChat {
25598
26071
  data
25599
26072
  );
25600
26073
  }
25601
- DBDeleteChannelType(channelType) {
26074
+ deleteChannelType(channelType) {
25602
26075
  return this.delete(
25603
26076
  this.baseURL + `/channeltypes/${encodeURIComponent(channelType)}`
25604
26077
  );
@@ -25941,7 +26414,7 @@ var StreamChat = class _StreamChat {
25941
26414
  if (this.userAgent) {
25942
26415
  return this.userAgent;
25943
26416
  }
25944
- const version = "9.4.0";
26417
+ const version = "9.5.1";
25945
26418
  const clientBundle = "node-cjs";
25946
26419
  let userAgentString = "";
25947
26420
  if (this.sdkIdentifier) {
@@ -26980,6 +27453,56 @@ var StreamChat = class _StreamChat {
26980
27453
  };
26981
27454
  return await this.post(this.baseURL + "/drafts/query", payload);
26982
27455
  }
27456
+ /**
27457
+ * createReminder - Creates a reminder for a message
27458
+ *
27459
+ * @param {CreateReminderOptions} options The options for creating the reminder
27460
+ * @returns {Promise<ReminderAPIResponse>}
27461
+ */
27462
+ async createReminder({ messageId, ...options }) {
27463
+ return await this.post(
27464
+ `${this.baseURL}/messages/${messageId}/reminders`,
27465
+ options
27466
+ );
27467
+ }
27468
+ /**
27469
+ * updateReminder - Updates an existing reminder for a message
27470
+ *
27471
+ * @param {UpdateReminderOptions} options The options for updating the reminder
27472
+ * @returns {Promise<ReminderAPIResponse>}
27473
+ */
27474
+ async updateReminder({ messageId, ...options }) {
27475
+ return await this.patch(
27476
+ `${this.baseURL}/messages/${messageId}/reminders`,
27477
+ options
27478
+ );
27479
+ }
27480
+ /**
27481
+ * deleteReminder - Deletes a reminder for a message
27482
+ *
27483
+ * @param {string} messageId The ID of the message whose reminder to delete
27484
+ * @param {string} [userId] Optional user ID, required for server-side operations
27485
+ * @returns {Promise<APIResponse>}
27486
+ */
27487
+ async deleteReminder(messageId, userId) {
27488
+ return await this.delete(
27489
+ `${this.baseURL}/messages/${messageId}/reminders`,
27490
+ userId ? { user_id: userId } : {}
27491
+ );
27492
+ }
27493
+ /**
27494
+ * queryReminders - Queries reminders based on given filters
27495
+ *
27496
+ * @param {QueryRemindersOptions} options The options for querying reminders
27497
+ * @returns {Promise<QueryRemindersResponse>}
27498
+ */
27499
+ async queryReminders({ filter: filter2, sort, ...rest } = {}) {
27500
+ return await this.post(`${this.baseURL}/reminders/query`, {
27501
+ filter_conditions: filter2,
27502
+ sort: sort && normalizeQuerySort(sort),
27503
+ ...rest
27504
+ });
27505
+ }
26983
27506
  };
26984
27507
 
26985
27508
  // src/events.ts
@@ -27046,7 +27569,12 @@ var EVENT_MAP = {
27046
27569
  "connection.changed": true,
27047
27570
  "connection.recovered": true,
27048
27571
  "transport.changed": true,
27049
- "capabilities.changed": true
27572
+ "capabilities.changed": true,
27573
+ // Reminder events
27574
+ "reminder.created": true,
27575
+ "reminder.updated": true,
27576
+ "reminder.deleted": true,
27577
+ "notification.reminder_due": true
27050
27578
  };
27051
27579
 
27052
27580
  // src/permissions.ts
@@ -27919,6 +28447,7 @@ var FixedSizeQueueCache = class {
27919
28447
  AnyResource,
27920
28448
  AnyRole,
27921
28449
  AttachmentManager,
28450
+ BasePaginator,
27922
28451
  BaseSearchSource,
27923
28452
  BuiltinPermissions,
27924
28453
  BuiltinRoles,
@@ -27936,6 +28465,9 @@ var FixedSizeQueueCache = class {
27936
28465
  DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS,
27937
28466
  DEFAULT_COMPOSER_CONFIG,
27938
28467
  DEFAULT_LINK_PREVIEW_MANAGER_CONFIG,
28468
+ DEFAULT_PAGINATION_OPTIONS,
28469
+ DEFAULT_REMINDER_MANAGER_CONFIG,
28470
+ DEFAULT_STOP_REFRESH_BOUNDARY_MS,
27939
28471
  DEFAULT_TEXT_COMPOSER_CONFIG,
27940
28472
  Deny,
27941
28473
  DenyAll,
@@ -27968,6 +28500,10 @@ var FixedSizeQueueCache = class {
27968
28500
  PollComposerCompositionMiddlewareExecutor,
27969
28501
  PollComposerStateMiddlewareExecutor,
27970
28502
  PollManager,
28503
+ Reminder,
28504
+ ReminderManager,
28505
+ ReminderPaginator,
28506
+ ReminderTimer,
27971
28507
  SearchController,
27972
28508
  Segment,
27973
28509
  StableWSConnection,
@@ -28055,7 +28591,8 @@ var FixedSizeQueueCache = class {
28055
28591
  readFileAsArrayBuffer,
28056
28592
  removeDiacritics,
28057
28593
  replaceWordWithEntity,
28058
- textIsEmpty
28594
+ textIsEmpty,
28595
+ timeLeftMs
28059
28596
  });
28060
28597
  /*! Bundled license information:
28061
28598