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
@@ -159,6 +159,7 @@ __export(index_exports, {
159
159
  AnyResource: () => AnyResource,
160
160
  AnyRole: () => AnyRole,
161
161
  AttachmentManager: () => AttachmentManager,
162
+ BasePaginator: () => BasePaginator,
162
163
  BaseSearchSource: () => BaseSearchSource,
163
164
  BuiltinPermissions: () => BuiltinPermissions,
164
165
  BuiltinRoles: () => BuiltinRoles,
@@ -176,6 +177,9 @@ __export(index_exports, {
176
177
  DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS: () => DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS,
177
178
  DEFAULT_COMPOSER_CONFIG: () => DEFAULT_COMPOSER_CONFIG,
178
179
  DEFAULT_LINK_PREVIEW_MANAGER_CONFIG: () => DEFAULT_LINK_PREVIEW_MANAGER_CONFIG,
180
+ DEFAULT_PAGINATION_OPTIONS: () => DEFAULT_PAGINATION_OPTIONS,
181
+ DEFAULT_REMINDER_MANAGER_CONFIG: () => DEFAULT_REMINDER_MANAGER_CONFIG,
182
+ DEFAULT_STOP_REFRESH_BOUNDARY_MS: () => DEFAULT_STOP_REFRESH_BOUNDARY_MS,
179
183
  DEFAULT_TEXT_COMPOSER_CONFIG: () => DEFAULT_TEXT_COMPOSER_CONFIG,
180
184
  Deny: () => Deny,
181
185
  DenyAll: () => DenyAll,
@@ -208,6 +212,10 @@ __export(index_exports, {
208
212
  PollComposerCompositionMiddlewareExecutor: () => PollComposerCompositionMiddlewareExecutor,
209
213
  PollComposerStateMiddlewareExecutor: () => PollComposerStateMiddlewareExecutor,
210
214
  PollManager: () => PollManager,
215
+ Reminder: () => Reminder,
216
+ ReminderManager: () => ReminderManager,
217
+ ReminderPaginator: () => ReminderPaginator,
218
+ ReminderTimer: () => ReminderTimer,
211
219
  SearchController: () => SearchController,
212
220
  Segment: () => Segment,
213
221
  StableWSConnection: () => StableWSConnection,
@@ -295,7 +303,8 @@ __export(index_exports, {
295
303
  readFileAsArrayBuffer: () => readFileAsArrayBuffer,
296
304
  removeDiacritics: () => removeDiacritics,
297
305
  replaceWordWithEntity: () => replaceWordWithEntity,
298
- textIsEmpty: () => textIsEmpty
306
+ textIsEmpty: () => textIsEmpty,
307
+ timeLeftMs: () => timeLeftMs
299
308
  });
300
309
  module.exports = __toCommonJS(index_exports);
301
310
 
@@ -5431,15 +5440,14 @@ var pollStateChangeValidators = {
5431
5440
  return { max_votes_allowed: "Type a number from 2 to 10" };
5432
5441
  return { max_votes_allowed: void 0 };
5433
5442
  },
5434
- options: ({ value }) => {
5443
+ options: ({ value: options }) => {
5435
5444
  const errors = {};
5436
5445
  const seenOptions = /* @__PURE__ */ new Set();
5437
- value.forEach((option) => {
5438
- const trimmedText = option.text.trim();
5439
- if (seenOptions.has(trimmedText)) {
5446
+ options.forEach((option) => {
5447
+ if (seenOptions.has(option.text) && option.text.length) {
5440
5448
  errors[option.id] = "Option already exists";
5441
5449
  } else {
5442
- seenOptions.add(trimmedText);
5450
+ seenOptions.add(option.text);
5443
5451
  }
5444
5452
  });
5445
5453
  return Object.keys(errors).length > 0 ? { options: errors } : { options: void 0 };
@@ -5792,13 +5800,13 @@ var PollComposer = class {
5792
5800
  }
5793
5801
  get canCreatePoll() {
5794
5802
  const { data, errors } = this.state.getLatestValue();
5795
- const hasAtLeastOneOption = data.options.filter((o) => !!o.text).length > 0;
5803
+ const hasAtLeastOneNonEmptyOption = data.options.filter((o) => !!o.text.trim()).length > 0;
5796
5804
  const hasName = !!data.name;
5797
5805
  const maxVotesAllowedNumber = parseInt(
5798
5806
  data.max_votes_allowed?.match(VALID_MAX_VOTES_VALUE_REGEX)?.[0] || ""
5799
5807
  );
5800
5808
  const validMaxVotesAllowed = data.max_votes_allowed === "" || !!maxVotesAllowedNumber && (2 <= maxVotesAllowedNumber || maxVotesAllowedNumber <= 10);
5801
- return hasAtLeastOneOption && hasName && validMaxVotesAllowed && Object.values(errors).filter((errorText) => !!errorText).length === 0;
5809
+ return hasAtLeastOneNonEmptyOption && hasName && validMaxVotesAllowed && Object.values(errors).filter((errorText) => !!errorText).length === 0;
5802
5810
  }
5803
5811
  };
5804
5812
 
@@ -6241,7 +6249,7 @@ var MessageDraftComposerMiddlewareExecutor = class extends MiddlewareExecutor {
6241
6249
  }
6242
6250
  };
6243
6251
 
6244
- // src/search_controller.ts
6252
+ // src/search/BaseSearchSource.ts
6245
6253
  var DEFAULT_SEARCH_SOURCE_OPTIONS = {
6246
6254
  debounceMs: 300,
6247
6255
  pageSize: 10
@@ -6367,6 +6375,112 @@ var BaseSearchSource = class {
6367
6375
  this.activate();
6368
6376
  }
6369
6377
  };
6378
+
6379
+ // src/search/SearchController.ts
6380
+ var SearchController = class {
6381
+ constructor({ config, sources } = {}) {
6382
+ this.addSource = (source) => {
6383
+ this.state.partialNext({
6384
+ sources: [...this.sources, source]
6385
+ });
6386
+ };
6387
+ this.getSource = (sourceType) => this.sources.find((s) => s.type === sourceType);
6388
+ this.removeSource = (sourceType) => {
6389
+ const newSources = this.sources.filter((s) => s.type !== sourceType);
6390
+ if (newSources.length === this.sources.length) return;
6391
+ this.state.partialNext({ sources: newSources });
6392
+ };
6393
+ this.activateSource = (sourceType) => {
6394
+ const source = this.getSource(sourceType);
6395
+ if (!source || source.isActive) return;
6396
+ if (this.config.keepSingleActiveSource) {
6397
+ this.sources.forEach((s) => {
6398
+ if (s.type !== sourceType) {
6399
+ s.deactivate();
6400
+ }
6401
+ });
6402
+ }
6403
+ source.activate();
6404
+ this.state.partialNext({ sources: [...this.sources] });
6405
+ };
6406
+ this.deactivateSource = (sourceType) => {
6407
+ const source = this.getSource(sourceType);
6408
+ if (!source?.isActive) return;
6409
+ if (this.activeSources.length === 1) return;
6410
+ source.deactivate();
6411
+ this.state.partialNext({ sources: [...this.sources] });
6412
+ };
6413
+ this.activate = () => {
6414
+ if (!this.activeSources.length) {
6415
+ const sourcesToActivate = this.config.keepSingleActiveSource ? this.sources.slice(0, 1) : this.sources;
6416
+ sourcesToActivate.forEach((s) => s.activate());
6417
+ }
6418
+ if (this.isActive) return;
6419
+ this.state.partialNext({ isActive: true });
6420
+ };
6421
+ this.search = async (searchQuery) => {
6422
+ const searchedSources = this.activeSources;
6423
+ this.state.partialNext({
6424
+ searchQuery
6425
+ });
6426
+ await Promise.all(searchedSources.map((source) => source.search(searchQuery)));
6427
+ };
6428
+ this.cancelSearchQueries = () => {
6429
+ this.activeSources.forEach((s) => s.cancelScheduledQuery());
6430
+ };
6431
+ this.clear = () => {
6432
+ this.cancelSearchQueries();
6433
+ this.sources.forEach(
6434
+ (source) => source.state.next({ ...source.initialState, isActive: source.isActive })
6435
+ );
6436
+ this.state.next((current) => ({
6437
+ ...current,
6438
+ isActive: true,
6439
+ queriesInProgress: [],
6440
+ searchQuery: ""
6441
+ }));
6442
+ };
6443
+ this.exit = () => {
6444
+ this.cancelSearchQueries();
6445
+ this.sources.forEach(
6446
+ (source) => source.state.next({ ...source.initialState, isActive: source.isActive })
6447
+ );
6448
+ this.state.next((current) => ({
6449
+ ...current,
6450
+ isActive: false,
6451
+ queriesInProgress: [],
6452
+ searchQuery: ""
6453
+ }));
6454
+ };
6455
+ this.state = new StateStore({
6456
+ isActive: false,
6457
+ searchQuery: "",
6458
+ sources: sources ?? []
6459
+ });
6460
+ this._internalState = new StateStore({});
6461
+ this.config = { keepSingleActiveSource: true, ...config };
6462
+ }
6463
+ get hasNext() {
6464
+ return this.sources.some((source) => source.hasNext);
6465
+ }
6466
+ get sources() {
6467
+ return this.state.getLatestValue().sources;
6468
+ }
6469
+ get activeSources() {
6470
+ return this.state.getLatestValue().sources.filter((s) => s.isActive);
6471
+ }
6472
+ get isActive() {
6473
+ return this.state.getLatestValue().isActive;
6474
+ }
6475
+ get searchQuery() {
6476
+ return this.state.getLatestValue().searchQuery;
6477
+ }
6478
+ get searchSourceTypes() {
6479
+ return this.sources.map((s) => s.type);
6480
+ }
6481
+ };
6482
+
6483
+ // src/search/UserSearchSource.ts
6370
6484
  var UserSearchSource = class extends BaseSearchSource {
6371
6485
  constructor(client, options) {
6372
6486
  super(options);
@@ -6390,6 +6504,8 @@ var UserSearchSource = class extends BaseSearchSource {
6390
6504
  return items.filter((u) => u.id !== this.client.user?.id);
6391
6505
  }
6392
6506
  };
6507
+
6508
+ // src/search/ChannelSearchSource.ts
6393
6509
  var ChannelSearchSource = class extends BaseSearchSource {
6394
6510
  constructor(client, options) {
6395
6511
  super(options);
@@ -6411,6 +6527,8 @@ var ChannelSearchSource = class extends BaseSearchSource {
6411
6527
  return items;
6412
6528
  }
6413
6529
  };
6530
+
6531
+ // src/search/MessageSearchSource.ts
6414
6532
  var MessageSearchSource = class extends BaseSearchSource {
6415
6533
  constructor(client, options) {
6416
6534
  super(options);
@@ -6471,108 +6589,6 @@ var MessageSearchSource = class extends BaseSearchSource {
6471
6589
  return items;
6472
6590
  }
6473
6591
  };
6474
- var SearchController = class {
6475
- constructor({ config, sources } = {}) {
6476
- this.addSource = (source) => {
6477
- this.state.partialNext({
6478
- sources: [...this.sources, source]
6479
- });
6480
- };
6481
- this.getSource = (sourceType) => this.sources.find((s) => s.type === sourceType);
6482
- this.removeSource = (sourceType) => {
6483
- const newSources = this.sources.filter((s) => s.type !== sourceType);
6484
- if (newSources.length === this.sources.length) return;
6485
- this.state.partialNext({ sources: newSources });
6486
- };
6487
- this.activateSource = (sourceType) => {
6488
- const source = this.getSource(sourceType);
6489
- if (!source || source.isActive) return;
6490
- if (this.config.keepSingleActiveSource) {
6491
- this.sources.forEach((s) => {
6492
- if (s.type !== sourceType) {
6493
- s.deactivate();
6494
- }
6495
- });
6496
- }
6497
- source.activate();
6498
- this.state.partialNext({ sources: [...this.sources] });
6499
- };
6500
- this.deactivateSource = (sourceType) => {
6501
- const source = this.getSource(sourceType);
6502
- if (!source?.isActive) return;
6503
- if (this.activeSources.length === 1) return;
6504
- source.deactivate();
6505
- this.state.partialNext({ sources: [...this.sources] });
6506
- };
6507
- this.activate = () => {
6508
- if (!this.activeSources.length) {
6509
- const sourcesToActivate = this.config.keepSingleActiveSource ? this.sources.slice(0, 1) : this.sources;
6510
- sourcesToActivate.forEach((s) => s.activate());
6511
- }
6512
- if (this.isActive) return;
6513
- this.state.partialNext({ isActive: true });
6514
- };
6515
- this.search = async (searchQuery) => {
6516
- const searchedSources = this.activeSources;
6517
- this.state.partialNext({
6518
- searchQuery
6519
- });
6520
- await Promise.all(searchedSources.map((source) => source.search(searchQuery)));
6521
- };
6522
- this.cancelSearchQueries = () => {
6523
- this.activeSources.forEach((s) => s.cancelScheduledQuery());
6524
- };
6525
- this.clear = () => {
6526
- this.cancelSearchQueries();
6527
- this.sources.forEach(
6528
- (source) => source.state.next({ ...source.initialState, isActive: source.isActive })
6529
- );
6530
- this.state.next((current) => ({
6531
- ...current,
6532
- isActive: true,
6533
- queriesInProgress: [],
6534
- searchQuery: ""
6535
- }));
6536
- };
6537
- this.exit = () => {
6538
- this.cancelSearchQueries();
6539
- this.sources.forEach(
6540
- (source) => source.state.next({ ...source.initialState, isActive: source.isActive })
6541
- );
6542
- this.state.next((current) => ({
6543
- ...current,
6544
- isActive: false,
6545
- queriesInProgress: [],
6546
- searchQuery: ""
6547
- }));
6548
- };
6549
- this.state = new StateStore({
6550
- isActive: false,
6551
- searchQuery: "",
6552
- sources: sources ?? []
6553
- });
6554
- this._internalState = new StateStore({});
6555
- this.config = { keepSingleActiveSource: true, ...config };
6556
- }
6557
- get hasNext() {
6558
- return this.sources.some((source) => source.hasNext);
6559
- }
6560
- get sources() {
6561
- return this.state.getLatestValue().sources;
6562
- }
6563
- get activeSources() {
6564
- return this.state.getLatestValue().sources.filter((s) => s.isActive);
6565
- }
6566
- get isActive() {
6567
- return this.state.getLatestValue().isActive;
6568
- }
6569
- get searchQuery() {
6570
- return this.state.getLatestValue().searchQuery;
6571
- }
6572
- get searchSourceTypes() {
6573
- return this.sources.map((s) => s.type);
6574
- }
6575
- };
6576
6592
 
6577
6593
  // src/messageComposer/middleware/textComposer/textMiddlewareUtils.ts
6578
6594
  var getTriggerCharWithToken = ({
@@ -9351,6 +9367,7 @@ var Channel = class {
9351
9367
  })
9352
9368
  };
9353
9369
  this.getClient().polls.hydratePollCache(state.messages, true);
9370
+ this.getClient().reminders.hydrateState(state.messages);
9354
9371
  if (state.draft) {
9355
9372
  this.messageComposer.initState({ composition: state.draft });
9356
9373
  }
@@ -10642,7 +10659,9 @@ var TokenManager = class {
10642
10659
  try {
10643
10660
  this.token = await this.tokenProvider();
10644
10661
  } catch (e) {
10645
- return reject(new Error(`Call to tokenProvider failed with message: ${e}`));
10662
+ return reject(
10663
+ new Error(`Call to tokenProvider failed with message: ${e}`, { cause: e })
10664
+ );
10646
10665
  }
10647
10666
  resolve(this.token);
10648
10667
  }
@@ -12392,6 +12411,458 @@ var NotificationManager = class {
12392
12411
  }
12393
12412
  };
12394
12413
 
12414
+ // src/reminders/ReminderTimer.ts
12415
+ var oneMinute = 60 * 1e3;
12416
+ var oneHour = 60 * oneMinute;
12417
+ var oneDay = 24 * oneHour;
12418
+ var oneWeek = 7 * oneDay;
12419
+ var GROUP_BOUNDS = {
12420
+ minute: { lower: oneMinute, upper: oneHour },
12421
+ hour: { lower: oneHour, upper: oneDay },
12422
+ day: { lower: oneDay, upper: oneWeek }
12423
+ };
12424
+ var DEFAULT_STOP_REFRESH_BOUNDARY_MS = 2 * oneWeek;
12425
+ var ReminderTimer = class {
12426
+ constructor({
12427
+ reminder,
12428
+ config
12429
+ }) {
12430
+ this.timeout = null;
12431
+ this.stopRefreshBoundaryMs = DEFAULT_STOP_REFRESH_BOUNDARY_MS;
12432
+ this.getRefreshIntervalLength = () => {
12433
+ if (!this.reminder.remindAt) return null;
12434
+ const distanceFromDeadlineMs = Math.abs(timeLeftMs(this.reminder.remindAt.getTime()));
12435
+ let refreshInterval;
12436
+ if (distanceFromDeadlineMs === 0) {
12437
+ refreshInterval = oneMinute;
12438
+ } else if (distanceFromDeadlineMs < GROUP_BOUNDS.minute.lower) {
12439
+ refreshInterval = distanceFromDeadlineMs;
12440
+ } else if (distanceFromDeadlineMs <= GROUP_BOUNDS.minute.upper) {
12441
+ refreshInterval = oneMinute;
12442
+ } else if (distanceFromDeadlineMs <= GROUP_BOUNDS.hour.upper) {
12443
+ refreshInterval = oneHour;
12444
+ } else {
12445
+ refreshInterval = oneDay;
12446
+ }
12447
+ return refreshInterval;
12448
+ };
12449
+ this.init = () => {
12450
+ if (!this.reminder.remindAt) return null;
12451
+ const timeoutLength = this.getRefreshIntervalLength();
12452
+ if (timeoutLength === null) return null;
12453
+ const boundaryTimestamp = this.reminder.remindAt?.getTime() + this.stopRefreshBoundaryMs;
12454
+ const timeLeftToBoundary = boundaryTimestamp - Date.now();
12455
+ if (timeLeftToBoundary <= 0) {
12456
+ this.timeout = null;
12457
+ return;
12458
+ }
12459
+ if (this.timeout) clearTimeout(this.timeout);
12460
+ this.timeout = setTimeout(() => {
12461
+ this.reminder.refreshTimeLeft();
12462
+ this.init();
12463
+ }, timeoutLength);
12464
+ };
12465
+ this.clear = () => {
12466
+ if (this.timeout) {
12467
+ clearInterval(this.timeout);
12468
+ this.timeout = null;
12469
+ }
12470
+ };
12471
+ this.reminder = reminder;
12472
+ if (typeof config?.stopRefreshBoundaryMs === "number") {
12473
+ this.stopRefreshBoundaryMs = config.stopRefreshBoundaryMs;
12474
+ }
12475
+ }
12476
+ };
12477
+
12478
+ // src/reminders/Reminder.ts
12479
+ var timeLeftMs = (remindAt) => remindAt - (/* @__PURE__ */ new Date()).getTime();
12480
+ var _Reminder = class _Reminder {
12481
+ constructor({ data, config }) {
12482
+ this.setState = (data) => {
12483
+ this.state.next((current) => {
12484
+ const newState = { ...current, ..._Reminder.toStateValue(data) };
12485
+ if (newState.remind_at) {
12486
+ newState.timeLeftMs = timeLeftMs(newState.remind_at.getTime());
12487
+ }
12488
+ return newState;
12489
+ });
12490
+ if (data.remind_at) {
12491
+ this.initTimer();
12492
+ } else if (!data.remind_at) {
12493
+ this.clearTimer();
12494
+ }
12495
+ };
12496
+ this.refreshTimeLeft = () => {
12497
+ if (!this.remindAt) return;
12498
+ this.state.partialNext({ timeLeftMs: timeLeftMs(this.remindAt.getTime()) });
12499
+ };
12500
+ this.initTimer = () => {
12501
+ this.timer.init();
12502
+ };
12503
+ this.clearTimer = () => {
12504
+ this.timer.clear();
12505
+ };
12506
+ this.state = new StateStore(_Reminder.toStateValue(data));
12507
+ this.timer = new ReminderTimer({ reminder: this, config });
12508
+ this.initTimer();
12509
+ }
12510
+ get id() {
12511
+ return this.state.getLatestValue().message_id;
12512
+ }
12513
+ get remindAt() {
12514
+ return this.state.getLatestValue().remind_at;
12515
+ }
12516
+ get timeLeftMs() {
12517
+ return this.state.getLatestValue().timeLeftMs;
12518
+ }
12519
+ };
12520
+ _Reminder.toStateValue = (data) => ({
12521
+ ...data,
12522
+ created_at: new Date(data.created_at),
12523
+ message: data.message || null,
12524
+ remind_at: data.remind_at ? new Date(data.remind_at) : null,
12525
+ timeLeftMs: data.remind_at ? timeLeftMs(new Date(data.remind_at).getTime()) : null,
12526
+ updated_at: new Date(data.updated_at),
12527
+ user: data.user || null
12528
+ });
12529
+ var Reminder = _Reminder;
12530
+
12531
+ // src/pagination/BasePaginator.ts
12532
+ var DEFAULT_PAGINATION_OPTIONS = {
12533
+ debounceMs: 300,
12534
+ pageSize: 10
12535
+ };
12536
+ var BasePaginator = class {
12537
+ constructor(options) {
12538
+ this._isCursorPagination = false;
12539
+ this.setDebounceOptions = ({ debounceMs }) => {
12540
+ this._executeQueryDebounced = debounce(this.executeQuery.bind(this), debounceMs);
12541
+ };
12542
+ this.canExecuteQuery = (direction) => !this.isLoading && direction === "next" && this.hasNext || direction === "prev" && this.hasPrev;
12543
+ this.next = () => this.executeQuery({ direction: "next" });
12544
+ this.prev = () => this.executeQuery({ direction: "prev" });
12545
+ this.nextDebounced = () => {
12546
+ this._executeQueryDebounced({ direction: "next" });
12547
+ };
12548
+ this.prevDebounced = () => {
12549
+ this._executeQueryDebounced({ direction: "prev" });
12550
+ };
12551
+ const { debounceMs, pageSize } = { ...DEFAULT_PAGINATION_OPTIONS, ...options };
12552
+ this.pageSize = pageSize;
12553
+ this.state = new StateStore(this.initialState);
12554
+ this.setDebounceOptions({ debounceMs });
12555
+ }
12556
+ get lastQueryError() {
12557
+ return this.state.getLatestValue().lastQueryError;
12558
+ }
12559
+ get hasNext() {
12560
+ return this.state.getLatestValue().hasNext;
12561
+ }
12562
+ get hasPrev() {
12563
+ return this.state.getLatestValue().hasPrev;
12564
+ }
12565
+ get hasResults() {
12566
+ return Array.isArray(this.state.getLatestValue().items);
12567
+ }
12568
+ get isLoading() {
12569
+ return this.state.getLatestValue().isLoading;
12570
+ }
12571
+ get initialState() {
12572
+ return {
12573
+ hasNext: true,
12574
+ hasPrev: true,
12575
+ //todo: check if optimistic value does not cause problems in UI
12576
+ isLoading: false,
12577
+ items: void 0,
12578
+ lastQueryError: void 0,
12579
+ cursor: void 0,
12580
+ offset: 0
12581
+ };
12582
+ }
12583
+ get items() {
12584
+ return this.state.getLatestValue().items;
12585
+ }
12586
+ get cursor() {
12587
+ return this.state.getLatestValue().cursor;
12588
+ }
12589
+ get offset() {
12590
+ return this.state.getLatestValue().offset;
12591
+ }
12592
+ getStateBeforeFirstQuery() {
12593
+ return {
12594
+ ...this.initialState,
12595
+ isLoading: true
12596
+ };
12597
+ }
12598
+ getStateAfterQuery(stateUpdate, isFirstPage) {
12599
+ const current = this.state.getLatestValue();
12600
+ return {
12601
+ ...current,
12602
+ lastQueryError: void 0,
12603
+ // reset lastQueryError that can be overridden by the stateUpdate
12604
+ ...stateUpdate,
12605
+ isLoading: false,
12606
+ items: isFirstPage ? stateUpdate.items : [...this.items ?? [], ...stateUpdate.items || []]
12607
+ };
12608
+ }
12609
+ async executeQuery({ direction }) {
12610
+ if (!this.canExecuteQuery(direction)) return;
12611
+ const isFirstPage = typeof this.items === "undefined";
12612
+ if (isFirstPage) {
12613
+ this.state.next(this.getStateBeforeFirstQuery());
12614
+ } else {
12615
+ this.state.partialNext({ isLoading: true });
12616
+ }
12617
+ const stateUpdate = {};
12618
+ try {
12619
+ const results = await this.query({ direction });
12620
+ if (!results) return;
12621
+ const { items, next, prev } = results;
12622
+ if (isFirstPage && (next || prev)) {
12623
+ this._isCursorPagination = true;
12624
+ }
12625
+ if (this._isCursorPagination) {
12626
+ stateUpdate.cursor = { next: next || null, prev: prev || null };
12627
+ stateUpdate.hasNext = !!next;
12628
+ stateUpdate.hasPrev = !!prev;
12629
+ } else {
12630
+ stateUpdate.offset = (this.offset ?? 0) + items.length;
12631
+ stateUpdate.hasNext = items.length === this.pageSize;
12632
+ }
12633
+ stateUpdate.items = await this.filterQueryResults(items);
12634
+ } catch (e) {
12635
+ stateUpdate.lastQueryError = e;
12636
+ } finally {
12637
+ this.state.next(this.getStateAfterQuery(stateUpdate, isFirstPage));
12638
+ }
12639
+ }
12640
+ cancelScheduledQuery() {
12641
+ this._executeQueryDebounced.cancel();
12642
+ }
12643
+ resetState() {
12644
+ this.state.next(this.initialState);
12645
+ }
12646
+ };
12647
+
12648
+ // src/pagination/ReminderPaginator.ts
12649
+ var ReminderPaginator = class extends BasePaginator {
12650
+ constructor(client, options) {
12651
+ super(options);
12652
+ this.query = async ({
12653
+ direction
12654
+ }) => {
12655
+ const cursor = this.cursor?.[direction];
12656
+ const {
12657
+ reminders: items,
12658
+ next,
12659
+ prev
12660
+ } = await this.client.queryReminders({
12661
+ filter: this.filters,
12662
+ sort: this.sort,
12663
+ limit: this.pageSize,
12664
+ [direction]: cursor
12665
+ });
12666
+ return { items, next, prev };
12667
+ };
12668
+ this.filterQueryResults = (items) => items;
12669
+ this.client = client;
12670
+ }
12671
+ };
12672
+
12673
+ // src/reminders/ReminderManager.ts
12674
+ var oneMinute2 = 60 * 1e3;
12675
+ var oneHour2 = 60 * oneMinute2;
12676
+ var oneDay2 = 24 * oneHour2;
12677
+ var DEFAULT_REMINDER_MANAGER_CONFIG = {
12678
+ scheduledOffsetsMs: [
12679
+ 2 * oneMinute2,
12680
+ 30 * oneMinute2,
12681
+ oneHour2,
12682
+ 2 * oneHour2,
12683
+ 8 * oneHour2,
12684
+ oneDay2
12685
+ ]
12686
+ };
12687
+ var isReminderExistsError = (error) => error.message.match("already has reminder created for this message_id");
12688
+ var isReminderDoesNotExistError = (error) => error.message.match("reminder does not exist");
12689
+ var _ReminderManager = class _ReminderManager extends WithSubscriptions {
12690
+ constructor({ client, config }) {
12691
+ super();
12692
+ this.upsertToState = ({
12693
+ data,
12694
+ overwrite = true
12695
+ }) => {
12696
+ if (!this.client._cacheEnabled()) {
12697
+ return;
12698
+ }
12699
+ const cachedReminder = this.getFromState(data.message_id);
12700
+ if (!cachedReminder) {
12701
+ const reminder = new Reminder({
12702
+ data,
12703
+ config: { stopRefreshBoundaryMs: this.stopTimerRefreshBoundaryMs }
12704
+ });
12705
+ this.state.partialNext({
12706
+ reminders: new Map(this.reminders.set(data.message_id, reminder))
12707
+ });
12708
+ } else if (overwrite) {
12709
+ cachedReminder.setState(data);
12710
+ }
12711
+ return cachedReminder;
12712
+ };
12713
+ this.removeFromState = (messageId) => {
12714
+ const cachedReminder = this.getFromState(messageId);
12715
+ if (!cachedReminder) return;
12716
+ cachedReminder.clearTimer();
12717
+ const reminders = this.reminders;
12718
+ reminders.delete(messageId);
12719
+ this.state.partialNext({ reminders: new Map(reminders) });
12720
+ };
12721
+ this.hydrateState = (messages) => {
12722
+ messages.forEach(({ reminder }) => {
12723
+ if (reminder) {
12724
+ this.upsertToState({ data: reminder });
12725
+ }
12726
+ });
12727
+ };
12728
+ // State API END //
12729
+ // Timers API START //
12730
+ this.initTimers = () => {
12731
+ this.reminders.forEach((reminder) => reminder.initTimer());
12732
+ };
12733
+ this.clearTimers = () => {
12734
+ this.reminders.forEach((reminder) => reminder.clearTimer());
12735
+ };
12736
+ this.registerSubscriptions = () => {
12737
+ if (this.hasSubscriptions) return;
12738
+ this.addUnsubscribeFunction(this.subscribeReminderCreated());
12739
+ this.addUnsubscribeFunction(this.subscribeReminderUpdated());
12740
+ this.addUnsubscribeFunction(this.subscribeReminderDeleted());
12741
+ this.addUnsubscribeFunction(this.subscribeNotificationReminderDue());
12742
+ this.addUnsubscribeFunction(this.subscribeMessageDeleted());
12743
+ this.addUnsubscribeFunction(this.subscribeMessageUndeleted());
12744
+ this.addUnsubscribeFunction(this.subscribePaginatorStateUpdated());
12745
+ this.addUnsubscribeFunction(this.subscribeConfigStateUpdated());
12746
+ };
12747
+ this.subscribeReminderCreated = () => this.client.on("reminder.created", (event) => {
12748
+ if (!_ReminderManager.isReminderWsEventPayload(event)) return;
12749
+ const { reminder } = event;
12750
+ this.upsertToState({ data: reminder });
12751
+ }).unsubscribe;
12752
+ this.subscribeReminderUpdated = () => this.client.on("reminder.updated", (event) => {
12753
+ if (!_ReminderManager.isReminderWsEventPayload(event)) return;
12754
+ const { reminder } = event;
12755
+ this.upsertToState({ data: reminder });
12756
+ }).unsubscribe;
12757
+ this.subscribeReminderDeleted = () => this.client.on("reminder.deleted", (event) => {
12758
+ if (!_ReminderManager.isReminderWsEventPayload(event)) return;
12759
+ this.removeFromState(event.message_id);
12760
+ }).unsubscribe;
12761
+ this.subscribeMessageDeleted = () => this.client.on("message.deleted", (event) => {
12762
+ if (!event.message?.id) return;
12763
+ this.removeFromState(event.message.id);
12764
+ }).unsubscribe;
12765
+ this.subscribeMessageUndeleted = () => this.client.on("message.undeleted", (event) => {
12766
+ if (!event.message?.reminder) return;
12767
+ this.upsertToState({ data: event.message.reminder });
12768
+ }).unsubscribe;
12769
+ this.subscribeNotificationReminderDue = () => this.client.on("notification.reminder_due", () => null).unsubscribe;
12770
+ // todo: what should be performed on this event?
12771
+ this.subscribePaginatorStateUpdated = () => this.paginator.state.subscribeWithSelector(
12772
+ ({ items }) => [items],
12773
+ ([items]) => {
12774
+ if (!items) return;
12775
+ for (const reminder of items) {
12776
+ this.upsertToState({ data: reminder });
12777
+ }
12778
+ }
12779
+ );
12780
+ this.subscribeConfigStateUpdated = () => this.configState.subscribeWithSelector(
12781
+ ({ stopTimerRefreshBoundaryMs }) => ({ stopTimerRefreshBoundaryMs }),
12782
+ ({ stopTimerRefreshBoundaryMs }, previousValue) => {
12783
+ if (typeof stopTimerRefreshBoundaryMs === "number" && stopTimerRefreshBoundaryMs !== previousValue?.stopTimerRefreshBoundaryMs) {
12784
+ this.reminders.forEach((reminder) => {
12785
+ if (reminder.timer) {
12786
+ reminder.timer.stopRefreshBoundaryMs = stopTimerRefreshBoundaryMs;
12787
+ }
12788
+ });
12789
+ }
12790
+ }
12791
+ );
12792
+ // WS event handling END //
12793
+ // API calls START //
12794
+ this.upsertReminder = async (options) => {
12795
+ const { messageId } = options;
12796
+ if (this.getFromState(messageId)) {
12797
+ try {
12798
+ return await this.updateReminder(options);
12799
+ } catch (error) {
12800
+ if (isReminderDoesNotExistError(error)) {
12801
+ return await this.createReminder(options);
12802
+ }
12803
+ throw error;
12804
+ }
12805
+ } else {
12806
+ try {
12807
+ return await this.createReminder(options);
12808
+ } catch (error) {
12809
+ if (isReminderExistsError(error)) {
12810
+ return await this.updateReminder(options);
12811
+ }
12812
+ throw error;
12813
+ }
12814
+ }
12815
+ };
12816
+ this.createReminder = async (options) => {
12817
+ const { reminder } = await this.client.createReminder(options);
12818
+ return this.upsertToState({ data: reminder, overwrite: false });
12819
+ };
12820
+ this.updateReminder = async (options) => {
12821
+ const { reminder } = await this.client.updateReminder(options);
12822
+ return this.upsertToState({ data: reminder });
12823
+ };
12824
+ this.deleteReminder = async (messageId) => {
12825
+ await this.client.deleteReminder(messageId);
12826
+ this.removeFromState(messageId);
12827
+ };
12828
+ this.queryNextReminders = async () => {
12829
+ await this.paginator.next();
12830
+ };
12831
+ this.queryPreviousReminders = async () => {
12832
+ await this.paginator.prev();
12833
+ };
12834
+ this.client = client;
12835
+ this.configState = new StateStore({
12836
+ scheduledOffsetsMs: config?.scheduledOffsetsMs ?? DEFAULT_REMINDER_MANAGER_CONFIG.scheduledOffsetsMs
12837
+ });
12838
+ this.state = new StateStore({ reminders: /* @__PURE__ */ new Map() });
12839
+ this.paginator = new ReminderPaginator(client);
12840
+ }
12841
+ // Config API START //
12842
+ updateConfig(config) {
12843
+ this.configState.partialNext(config);
12844
+ }
12845
+ get stopTimerRefreshBoundaryMs() {
12846
+ return this.configState.getLatestValue().stopTimerRefreshBoundaryMs;
12847
+ }
12848
+ get scheduledOffsetsMs() {
12849
+ return this.configState.getLatestValue().scheduledOffsetsMs;
12850
+ }
12851
+ // Config API END //
12852
+ // State API START //
12853
+ get reminders() {
12854
+ return this.state.getLatestValue().reminders;
12855
+ }
12856
+ getFromState(messageId) {
12857
+ return this.reminders.get(messageId);
12858
+ }
12859
+ // API calls END //
12860
+ };
12861
+ // Timers API END //
12862
+ // WS event handling START //
12863
+ _ReminderManager.isReminderWsEventPayload = (event) => !!event.reminder && (event.type.startsWith("reminder.") || event.type === "notification.reminder_due");
12864
+ var ReminderManager = _ReminderManager;
12865
+
12395
12866
  // src/client.ts
12396
12867
  function isString3(x) {
12397
12868
  return typeof x === "string" || x instanceof String;
@@ -12407,6 +12878,9 @@ var StreamChat = class _StreamChat {
12407
12878
  });
12408
12879
  this._getConnectionID = () => this.wsConnection?.connectionID || this.wsFallback?.connectionID;
12409
12880
  this._hasConnectionID = () => Boolean(this._getConnectionID());
12881
+ this.setMessageComposerSetupFunction = (setupFunction) => {
12882
+ this._messageComposerSetupState.partialNext({ setupFunction });
12883
+ };
12410
12884
  /**
12411
12885
  * connectUser - Set the current user and open a WebSocket connection
12412
12886
  *
@@ -12975,9 +13449,6 @@ var StreamChat = class _StreamChat {
12975
13449
  device: this.options.device,
12976
13450
  client_request_id
12977
13451
  });
12978
- this.setMessageComposerSetupFunction = (setupFunction) => {
12979
- this._messageComposerSetupState.partialNext({ setupFunction });
12980
- };
12981
13452
  this.key = key;
12982
13453
  this.listeners = {};
12983
13454
  this.state = new ClientState({ client: this });
@@ -13032,6 +13503,7 @@ var StreamChat = class _StreamChat {
13032
13503
  this.recoverStateOnReconnect = this.options.recoverStateOnReconnect;
13033
13504
  this.threads = new ThreadManager({ client: this });
13034
13505
  this.polls = new PollManager({ client: this });
13506
+ this.reminders = new ReminderManager({ client: this });
13035
13507
  }
13036
13508
  static getInstance(key, secretOrOptions, options) {
13037
13509
  if (!_StreamChat._instance) {
@@ -13167,15 +13639,15 @@ var StreamChat = class _StreamChat {
13167
13639
  * @param {string} userID User ID. If user has no devices, it will error
13168
13640
  * @param {TestPushDataInput} [data] Overrides for push templates/message used
13169
13641
  * IE: {
13170
- messageID: 'id-of-message', // will error if message does not exist
13171
- apnTemplate: '{}', // if app doesn't have apn configured it will error
13172
- firebaseTemplate: '{}', // if app doesn't have firebase configured it will error
13173
- firebaseDataTemplate: '{}', // if app doesn't have firebase configured it will error
13174
- skipDevices: true, // skip config/device checks and sending to real devices
13175
- pushProviderName: 'staging' // one of your configured push providers
13176
- pushProviderType: 'apn' // one of supported provider types
13177
- }
13178
- */
13642
+ messageID: 'id-of-message', // will error if message does not exist
13643
+ apnTemplate: '{}', // if app doesn't have apn configured it will error
13644
+ firebaseTemplate: '{}', // if app doesn't have firebase configured it will error
13645
+ firebaseDataTemplate: '{}', // if app doesn't have firebase configured it will error
13646
+ skipDevices: true, // skip config/device checks and sending to real devices
13647
+ pushProviderName: 'staging' // one of your configured push providers
13648
+ pushProviderType: 'apn' // one of supported provider types
13649
+ }
13650
+ */
13179
13651
  async testPushSettings(userID, data = {}) {
13180
13652
  return await this.post(this.baseURL + "/check_push", {
13181
13653
  user_id: userID,
@@ -13193,10 +13665,10 @@ var StreamChat = class _StreamChat {
13193
13665
  *
13194
13666
  * @param {TestSQSDataInput} [data] Overrides SQS settings for testing if needed
13195
13667
  * IE: {
13196
- sqs_key: 'auth_key',
13197
- sqs_secret: 'auth_secret',
13198
- sqs_url: 'url_to_queue',
13199
- }
13668
+ sqs_key: 'auth_key',
13669
+ sqs_secret: 'auth_secret',
13670
+ sqs_url: 'url_to_queue',
13671
+ }
13200
13672
  */
13201
13673
  async testSQSSettings(data = {}) {
13202
13674
  return await this.post(this.baseURL + "/check_sqs", data);
@@ -13206,10 +13678,10 @@ var StreamChat = class _StreamChat {
13206
13678
  *
13207
13679
  * @param {TestSNSDataInput} [data] Overrides SNS settings for testing if needed
13208
13680
  * IE: {
13209
- sns_key: 'auth_key',
13210
- sns_secret: 'auth_secret',
13211
- sns_topic_arn: 'topic_to_publish_to',
13212
- }
13681
+ sns_key: 'auth_key',
13682
+ sns_secret: 'auth_secret',
13683
+ sns_topic_arn: 'topic_to_publish_to',
13684
+ }
13213
13685
  */
13214
13686
  async testSNSSettings(data = {}) {
13215
13687
  return await this.post(this.baseURL + "/check_sns", data);
@@ -13690,6 +14162,7 @@ var StreamChat = class _StreamChat {
13690
14162
  })
13691
14163
  };
13692
14164
  this.polls.hydratePollCache(channelState.messages, true);
14165
+ this.reminders.hydrateState(channelState.messages);
13693
14166
  }
13694
14167
  if (channelState.draft) {
13695
14168
  c.messageComposer.initState({ composition: channelState.draft });
@@ -14267,7 +14740,7 @@ var StreamChat = class _StreamChat {
14267
14740
  data
14268
14741
  );
14269
14742
  }
14270
- DBDeleteChannelType(channelType) {
14743
+ deleteChannelType(channelType) {
14271
14744
  return this.delete(
14272
14745
  this.baseURL + `/channeltypes/${encodeURIComponent(channelType)}`
14273
14746
  );
@@ -14610,7 +15083,7 @@ var StreamChat = class _StreamChat {
14610
15083
  if (this.userAgent) {
14611
15084
  return this.userAgent;
14612
15085
  }
14613
- const version = "9.4.0";
15086
+ const version = "9.5.1";
14614
15087
  const clientBundle = "browser-cjs";
14615
15088
  let userAgentString = "";
14616
15089
  if (this.sdkIdentifier) {
@@ -15649,6 +16122,56 @@ var StreamChat = class _StreamChat {
15649
16122
  };
15650
16123
  return await this.post(this.baseURL + "/drafts/query", payload);
15651
16124
  }
16125
+ /**
16126
+ * createReminder - Creates a reminder for a message
16127
+ *
16128
+ * @param {CreateReminderOptions} options The options for creating the reminder
16129
+ * @returns {Promise<ReminderAPIResponse>}
16130
+ */
16131
+ async createReminder({ messageId, ...options }) {
16132
+ return await this.post(
16133
+ `${this.baseURL}/messages/${messageId}/reminders`,
16134
+ options
16135
+ );
16136
+ }
16137
+ /**
16138
+ * updateReminder - Updates an existing reminder for a message
16139
+ *
16140
+ * @param {UpdateReminderOptions} options The options for updating the reminder
16141
+ * @returns {Promise<ReminderAPIResponse>}
16142
+ */
16143
+ async updateReminder({ messageId, ...options }) {
16144
+ return await this.patch(
16145
+ `${this.baseURL}/messages/${messageId}/reminders`,
16146
+ options
16147
+ );
16148
+ }
16149
+ /**
16150
+ * deleteReminder - Deletes a reminder for a message
16151
+ *
16152
+ * @param {string} messageId The ID of the message whose reminder to delete
16153
+ * @param {string} [userId] Optional user ID, required for server-side operations
16154
+ * @returns {Promise<APIResponse>}
16155
+ */
16156
+ async deleteReminder(messageId, userId) {
16157
+ return await this.delete(
16158
+ `${this.baseURL}/messages/${messageId}/reminders`,
16159
+ userId ? { user_id: userId } : {}
16160
+ );
16161
+ }
16162
+ /**
16163
+ * queryReminders - Queries reminders based on given filters
16164
+ *
16165
+ * @param {QueryRemindersOptions} options The options for querying reminders
16166
+ * @returns {Promise<QueryRemindersResponse>}
16167
+ */
16168
+ async queryReminders({ filter: filter2, sort, ...rest } = {}) {
16169
+ return await this.post(`${this.baseURL}/reminders/query`, {
16170
+ filter_conditions: filter2,
16171
+ sort: sort && normalizeQuerySort(sort),
16172
+ ...rest
16173
+ });
16174
+ }
15652
16175
  };
15653
16176
 
15654
16177
  // src/events.ts
@@ -15715,7 +16238,12 @@ var EVENT_MAP = {
15715
16238
  "connection.changed": true,
15716
16239
  "connection.recovered": true,
15717
16240
  "transport.changed": true,
15718
- "capabilities.changed": true
16241
+ "capabilities.changed": true,
16242
+ // Reminder events
16243
+ "reminder.created": true,
16244
+ "reminder.updated": true,
16245
+ "reminder.deleted": true,
16246
+ "notification.reminder_due": true
15719
16247
  };
15720
16248
 
15721
16249
  // src/permissions.ts