stream-chat 9.42.3 → 9.43.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 (45) hide show
  1. package/dist/cjs/index.browser.js +1457 -1178
  2. package/dist/cjs/index.browser.js.map +3 -3
  3. package/dist/cjs/index.node.js +1458 -1180
  4. package/dist/cjs/index.node.js.map +3 -3
  5. package/dist/esm/index.mjs +1457 -1178
  6. package/dist/esm/index.mjs.map +3 -3
  7. package/dist/types/client.d.ts +4 -2
  8. package/dist/types/messageComposer/CustomDataManager.d.ts +3 -0
  9. package/dist/types/messageComposer/LocationComposer.d.ts +3 -0
  10. package/dist/types/messageComposer/MessageComposerEffectHandlers.d.ts +17 -0
  11. package/dist/types/messageComposer/attachmentManager.d.ts +7 -0
  12. package/dist/types/messageComposer/linkPreviewsManager.d.ts +4 -1
  13. package/dist/types/messageComposer/messageComposer.d.ts +39 -1
  14. package/dist/types/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.d.ts +2 -1
  15. package/dist/types/messageComposer/middleware/textComposer/commandEffects.d.ts +5 -0
  16. package/dist/types/messageComposer/middleware/textComposer/commandUtils.d.ts +7 -0
  17. package/dist/types/messageComposer/middleware/textComposer/commands.d.ts +2 -0
  18. package/dist/types/messageComposer/middleware/textComposer/index.d.ts +1 -0
  19. package/dist/types/messageComposer/middleware/textComposer/textMiddlewareUtils.d.ts +0 -34
  20. package/dist/types/messageComposer/middleware/textComposer/types.d.ts +13 -0
  21. package/dist/types/messageComposer/pollComposer.d.ts +3 -0
  22. package/dist/types/messageComposer/textComposer.d.ts +5 -1
  23. package/dist/types/types.d.ts +19 -4
  24. package/dist/types/utils.d.ts +4 -2
  25. package/package.json +1 -1
  26. package/src/client.ts +0 -8
  27. package/src/connection.ts +5 -4
  28. package/src/messageComposer/CustomDataManager.ts +8 -0
  29. package/src/messageComposer/LocationComposer.ts +8 -0
  30. package/src/messageComposer/MessageComposerEffectHandlers.ts +89 -0
  31. package/src/messageComposer/attachmentManager.ts +54 -0
  32. package/src/messageComposer/linkPreviewsManager.ts +12 -3
  33. package/src/messageComposer/messageComposer.ts +107 -0
  34. package/src/messageComposer/middleware/messageComposer/compositionValidation.ts +58 -18
  35. package/src/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.ts +7 -1
  36. package/src/messageComposer/middleware/textComposer/commandEffects.ts +51 -0
  37. package/src/messageComposer/middleware/textComposer/commandStringExtraction.ts +1 -4
  38. package/src/messageComposer/middleware/textComposer/commandUtils.ts +48 -0
  39. package/src/messageComposer/middleware/textComposer/commands.ts +15 -7
  40. package/src/messageComposer/middleware/textComposer/index.ts +1 -0
  41. package/src/messageComposer/middleware/textComposer/textMiddlewareUtils.ts +3 -46
  42. package/src/messageComposer/middleware/textComposer/types.ts +20 -0
  43. package/src/messageComposer/pollComposer.ts +8 -0
  44. package/src/messageComposer/textComposer.ts +54 -6
  45. package/src/types.ts +27 -4
@@ -152,6 +152,7 @@ __export(index_exports, {
152
152
  createActiveCommandGuardMiddleware: () => createActiveCommandGuardMiddleware,
153
153
  createAttachmentsCompositionMiddleware: () => createAttachmentsCompositionMiddleware,
154
154
  createBlockedAttachmentUploadNotificationMiddleware: () => createBlockedAttachmentUploadNotificationMiddleware,
155
+ createCommandEffectsMiddleware: () => createCommandEffectsMiddleware,
155
156
  createCommandInjectionMiddleware: () => createCommandInjectionMiddleware,
156
157
  createCommandStringExtractionMiddleware: () => createCommandStringExtractionMiddleware,
157
158
  createCommandsMiddleware: () => createCommandsMiddleware,
@@ -181,13 +182,11 @@ __export(index_exports, {
181
182
  defaultPollFieldChangeEventValidators: () => defaultPollFieldChangeEventValidators,
182
183
  encodeBase64: () => encodeBase64,
183
184
  ensureIsLocalAttachment: () => ensureIsLocalAttachment,
184
- escapeRegExp: () => escapeRegExp,
185
185
  extractPollData: () => extractPollData,
186
186
  extractPollEnrichedData: () => extractPollEnrichedData,
187
187
  formatMessage: () => formatMessage,
188
188
  generateFileName: () => generateFileName,
189
189
  getAttachmentTypeFromMimeType: () => getAttachmentTypeFromMimeType,
190
- getCompleteCommandInString: () => getCompleteCommandInString,
191
190
  getExtensionFromMimeType: () => getExtensionFromMimeType,
192
191
  getTokenizedSuggestionDisplayName: () => getTokenizedSuggestionDisplayName,
193
192
  getTriggerCharWithToken: () => getTriggerCharWithToken,
@@ -3276,9 +3275,51 @@ var _AttachmentManager = class _AttachmentManager {
3276
3275
  this.setCustomUploadFn = (doUploadRequest) => {
3277
3276
  this.composer.updateConfig({ attachments: { doUploadRequest } });
3278
3277
  };
3278
+ this.cancelAttachmentUploads = (attachments = this.attachments) => {
3279
+ for (const { localMetadata } of attachments) {
3280
+ this.client.uploadManager.deleteUploadRecord(localMetadata.id);
3281
+ }
3282
+ };
3283
+ this.normalizeSnapshotAttachment = (attachment) => {
3284
+ if (attachment.localMetadata.uploadState !== "uploading") return attachment;
3285
+ this.client.uploadManager.deleteUploadRecord(attachment.localMetadata.id);
3286
+ return {
3287
+ ...attachment,
3288
+ localMetadata: {
3289
+ ...attachment.localMetadata,
3290
+ uploadProgress: void 0,
3291
+ uploadState: "failed"
3292
+ }
3293
+ };
3294
+ };
3279
3295
  this.initState = ({ message } = {}) => {
3280
3296
  this.state.next(initState({ message }));
3281
3297
  };
3298
+ this.getSnapshot = () => {
3299
+ const state = this.state.getLatestValue();
3300
+ let hasUpdates = false;
3301
+ const attachments = state.attachments.map(this.normalizeSnapshotAttachment);
3302
+ for (let i = 0; i < attachments.length; i++) {
3303
+ if (attachments[i] !== state.attachments[i]) {
3304
+ hasUpdates = true;
3305
+ break;
3306
+ }
3307
+ }
3308
+ return hasUpdates ? { ...state, attachments } : state;
3309
+ };
3310
+ this.restoreSnapshot = (snapshot) => {
3311
+ this.cancelAttachmentUploads(this.attachments);
3312
+ this.state.next(snapshot);
3313
+ };
3314
+ this.setAttachments = (attachments) => {
3315
+ this.state.partialNext({ attachments });
3316
+ };
3317
+ this.clearAttachments = () => {
3318
+ if (!this.attachments.length) return;
3319
+ this.removeAttachments(
3320
+ this.attachments.map((attachment) => attachment.localMetadata.id)
3321
+ );
3322
+ };
3282
3323
  this.getAttachmentIndex = (localId) => {
3283
3324
  const attachmentsById = this.attachmentsById;
3284
3325
  return this.attachments.indexOf(attachmentsById[localId]);
@@ -3799,6 +3840,10 @@ var CustomDataManager = class {
3799
3840
  this.initState = ({ message } = {}) => {
3800
3841
  this.state.next(initState2({ composer: this.composer, message }));
3801
3842
  };
3843
+ this.getSnapshot = () => this.state.getLatestValue();
3844
+ this.restoreSnapshot = (snapshot) => {
3845
+ this.state.next(snapshot);
3846
+ };
3802
3847
  this.composer = composer;
3803
3848
  this.state = new StateStore(initState2({ composer, message }));
3804
3849
  }
@@ -3854,8 +3899,13 @@ var _LinkPreviewsManager = class _LinkPreviewsManager {
3854
3899
  constructor({ composer, message }) {
3855
3900
  this.shouldDiscardEnrichQueries = false;
3856
3901
  this.initState = ({ message } = {}) => {
3902
+ this.cancelURLEnrichment();
3857
3903
  this.state.next(initState3({ message: this.enabled ? message : void 0 }));
3858
3904
  };
3905
+ this.getSnapshot = () => this.state.getLatestValue();
3906
+ this.restoreSnapshot = (snapshot) => {
3907
+ this.state.next(snapshot);
3908
+ };
3859
3909
  this._findAndEnrichUrls = async (text) => {
3860
3910
  if (!this.enabled) return;
3861
3911
  const urls = this.config.findURLFn(text);
@@ -3908,8 +3958,8 @@ var _LinkPreviewsManager = class _LinkPreviewsManager {
3908
3958
  );
3909
3959
  };
3910
3960
  this.cancelURLEnrichment = () => {
3911
- this.findAndEnrichUrls.cancel();
3912
- this.findAndEnrichUrls.flush();
3961
+ this.findAndEnrichUrls.cancel?.();
3962
+ this.findAndEnrichUrls.flush?.();
3913
3963
  };
3914
3964
  /**
3915
3965
  * Clears all non-dismissed previews when the text composer is cleared.
@@ -4051,6 +4101,10 @@ var LocationComposer = class {
4051
4101
  this.initState = ({ message } = {}) => {
4052
4102
  this.state.next(initState4({ message }));
4053
4103
  };
4104
+ this.getSnapshot = () => this.state.getLatestValue();
4105
+ this.restoreSnapshot = (snapshot) => {
4106
+ this.state.next(snapshot);
4107
+ };
4054
4108
  this.setData = (data) => {
4055
4109
  if (!this.config.enabled) return;
4056
4110
  if (!data.latitude || !data.longitude) return;
@@ -4087,6 +4141,65 @@ var LocationComposer = class {
4087
4141
  }
4088
4142
  };
4089
4143
 
4144
+ // src/messageComposer/MessageComposerEffectHandlers.ts
4145
+ var applyCommandActivationEffect = (effect, composer) => {
4146
+ const snapshot = composer.getSnapshot();
4147
+ if (effect.stateToRestore) {
4148
+ snapshot.textComposer = {
4149
+ ...snapshot.textComposer,
4150
+ ...effect.stateToRestore,
4151
+ command: null
4152
+ };
4153
+ }
4154
+ composer.captureSnapshot(snapshot);
4155
+ composer.textComposer.state.next({
4156
+ command: effect.command,
4157
+ mentionedUsers: [],
4158
+ suggestions: void 0,
4159
+ selection: { start: 0, end: 0 },
4160
+ text: ""
4161
+ });
4162
+ const attachmentsToCancel = composer.attachmentManager.attachments;
4163
+ composer.attachmentManager.initState();
4164
+ composer.attachmentManager.cancelAttachmentUploads(attachmentsToCancel);
4165
+ composer.linkPreviewsManager.initState();
4166
+ composer.locationComposer.initState();
4167
+ composer.pollComposer.initState();
4168
+ composer.customDataManager.initState();
4169
+ };
4170
+ var applyCommandClearEffect = (_, composer) => {
4171
+ const snapshot = composer.popSnapshot();
4172
+ if (!snapshot) return;
4173
+ composer.restoreSnapshot(snapshot);
4174
+ };
4175
+ var MessageComposerEffectHandlers = class {
4176
+ constructor(options) {
4177
+ this.options = options;
4178
+ this.handlers = /* @__PURE__ */ new Map();
4179
+ this.registerDefaultHandlers = () => {
4180
+ this.registerEffectHandler(
4181
+ "command.activate",
4182
+ applyCommandActivationEffect
4183
+ );
4184
+ this.registerEffectHandler(
4185
+ "command.clear",
4186
+ applyCommandClearEffect
4187
+ );
4188
+ };
4189
+ this.registerEffectHandler = (type, handler) => {
4190
+ this.handlers.set(type, handler);
4191
+ };
4192
+ this.applyEffects = (effects = []) => {
4193
+ effects.forEach((effect) => this.applyEffect(effect));
4194
+ };
4195
+ this.applyEffect = (effect) => {
4196
+ const handler = this.handlers.get(effect.type);
4197
+ handler?.(effect, this.options.composer);
4198
+ };
4199
+ this.registerDefaultHandlers();
4200
+ }
4201
+ };
4202
+
4090
4203
  // src/messageComposer/middleware/pollComposer/state.ts
4091
4204
  var VALID_MAX_VOTES_VALUE_REGEX = /^([2-9]|10)$/;
4092
4205
  var MAX_POLL_OPTIONS = 100;
@@ -4377,6 +4490,10 @@ var PollComposer = class {
4377
4490
  this.initState = () => {
4378
4491
  this.state.next(this.initialState);
4379
4492
  };
4493
+ this.getSnapshot = () => this.state.getLatestValue();
4494
+ this.restoreSnapshot = (snapshot) => {
4495
+ this.state.next(snapshot);
4496
+ };
4380
4497
  /**
4381
4498
  * Updates specified fields and generates relevant errors
4382
4499
  * @param data
@@ -4639,667 +4756,239 @@ var createDraftCustomDataCompositionMiddleware = (composer) => ({
4639
4756
  }
4640
4757
  });
4641
4758
 
4642
- // src/messageComposer/middleware/messageComposer/compositionValidation.ts
4643
- var createCompositionValidationMiddleware = (composer) => ({
4644
- id: "stream-io/message-composer-middleware/data-validation",
4645
- handlers: {
4646
- compose: async ({
4647
- state,
4648
- discard,
4649
- forward
4650
- }) => {
4651
- const { maxLengthOnSend } = composer.config.text ?? {};
4652
- const inputText = state.message.text ?? "";
4653
- const hasExceededMaxLength = typeof maxLengthOnSend === "number" && inputText.length > maxLengthOnSend;
4654
- if (composer.compositionIsEmpty || hasExceededMaxLength) {
4655
- return await discard();
4656
- }
4657
- return await forward();
4658
- }
4759
+ // src/errors.ts
4760
+ var APIErrorCodes = {
4761
+ "-1": { name: "InternalSystemError", retryable: true },
4762
+ "2": { name: "AccessKeyError", retryable: false },
4763
+ "3": { name: "AuthenticationFailedError", retryable: true },
4764
+ "4": { name: "InputError", retryable: false },
4765
+ "6": { name: "DuplicateUsernameError", retryable: false },
4766
+ "9": { name: "RateLimitError", retryable: true },
4767
+ "16": { name: "DoesNotExistError", retryable: false },
4768
+ "17": { name: "NotAllowedError", retryable: false },
4769
+ "18": { name: "EventNotSupportedError", retryable: false },
4770
+ "19": { name: "ChannelFeatureNotSupportedError", retryable: false },
4771
+ "20": { name: "MessageTooLongError", retryable: false },
4772
+ "21": { name: "MultipleNestingLevelError", retryable: false },
4773
+ "22": { name: "PayloadTooBigError", retryable: false },
4774
+ "23": { name: "RequestTimeoutError", retryable: true },
4775
+ "24": { name: "MaxHeaderSizeExceededError", retryable: false },
4776
+ "40": { name: "AuthErrorTokenExpired", retryable: false },
4777
+ "41": { name: "AuthErrorTokenNotValidYet", retryable: false },
4778
+ "42": { name: "AuthErrorTokenUsedBeforeIssuedAt", retryable: false },
4779
+ "43": { name: "AuthErrorTokenSignatureInvalid", retryable: false },
4780
+ "44": { name: "CustomCommandEndpointMissingError", retryable: false },
4781
+ "45": { name: "CustomCommandEndpointCallError", retryable: true },
4782
+ "46": { name: "ConnectionIDNotFoundError", retryable: false },
4783
+ "60": { name: "CoolDownError", retryable: true },
4784
+ "69": { name: "ErrWrongRegion", retryable: false },
4785
+ "70": { name: "ErrQueryChannelPermissions", retryable: false },
4786
+ "71": { name: "ErrTooManyConnections", retryable: true },
4787
+ "99": { name: "AppSuspendedError", retryable: false }
4788
+ };
4789
+ function isAPIError(error) {
4790
+ return error.code !== void 0;
4791
+ }
4792
+ function isErrorRetryable(error) {
4793
+ if (!error.code) return false;
4794
+ const err = APIErrorCodes[`${error.code}`];
4795
+ if (!err) return false;
4796
+ return err.retryable;
4797
+ }
4798
+ function isConnectionIDError(error) {
4799
+ return error.code === 46;
4800
+ }
4801
+ function isWSFailure(err) {
4802
+ if (typeof err.isWSFailure === "boolean") {
4803
+ return err.isWSFailure;
4659
4804
  }
4660
- });
4661
- var createDraftCompositionValidationMiddleware = (composer) => ({
4662
- id: "stream-io/message-composer-middleware/draft-data-validation",
4663
- handlers: {
4664
- compose: async ({
4665
- state,
4666
- discard,
4667
- forward
4668
- }) => {
4669
- const hasData = !textIsEmpty(state.draft.text ?? "") || state.draft.attachments?.length || state.draft.poll_id || state.draft.quoted_message_id;
4670
- const shouldCreateDraft = composer.lastChangeOriginIsLocal && hasData;
4671
- if (!shouldCreateDraft) {
4672
- return await discard();
4673
- }
4674
- return await forward();
4675
- }
4805
+ try {
4806
+ return JSON.parse(err.message).isWSFailure;
4807
+ } catch (_) {
4808
+ return false;
4676
4809
  }
4677
- });
4810
+ }
4811
+ function isErrorResponse(res) {
4812
+ return !res.status || res.status < 200 || 300 <= res.status;
4813
+ }
4678
4814
 
4679
- // src/messageComposer/middleware/messageComposer/linkPreviews.ts
4680
- var createLinkPreviewsCompositionMiddleware = (composer) => ({
4681
- id: "stream-io/message-composer-middleware/link-previews",
4682
- handlers: {
4683
- compose: ({
4684
- state,
4685
- next,
4686
- forward
4687
- }) => {
4688
- const { linkPreviewsManager } = composer;
4689
- if (!linkPreviewsManager) return forward();
4690
- linkPreviewsManager.cancelURLEnrichment();
4691
- const someLinkPreviewsLoading = linkPreviewsManager.loadingPreviews.length > 0;
4692
- const someLinkPreviewsDismissed = linkPreviewsManager.dismissedPreviews.length > 0;
4693
- const linkPreviews = linkPreviewsManager.loadingPreviews.length > 0 ? [] : linkPreviewsManager.loadedPreviews.map(
4694
- (preview) => LinkPreviewsManager.getPreviewData(preview)
4695
- );
4696
- const attachments = (state.message.attachments ?? []).concat(
4697
- linkPreviews
4698
- );
4699
- if (!attachments.length) return forward();
4700
- const sendOptions = { ...state.sendOptions };
4701
- const skip_enrich_url = !someLinkPreviewsLoading && linkPreviews.length > 0 || someLinkPreviewsDismissed;
4702
- if (skip_enrich_url) {
4703
- sendOptions.skip_enrich_url = true;
4704
- }
4705
- return next({
4706
- ...state,
4707
- message: {
4708
- ...state.message,
4709
- attachments
4710
- },
4711
- localMessage: {
4712
- ...state.localMessage,
4713
- attachments
4714
- },
4715
- sendOptions
4716
- });
4717
- }
4815
+ // src/search/BaseSearchSource.ts
4816
+ var DEFAULT_SEARCH_SOURCE_OPTIONS = {
4817
+ debounceMs: 300,
4818
+ pageSize: 10
4819
+ };
4820
+ var BaseSearchSourceBase = class {
4821
+ constructor(options) {
4822
+ this.activate = () => {
4823
+ if (this.isActive) return;
4824
+ this.state.partialNext({ isActive: true });
4825
+ };
4826
+ this.deactivate = () => {
4827
+ if (!this.isActive) return;
4828
+ this.state.partialNext({ isActive: false });
4829
+ };
4830
+ this.canExecuteQuery = (newSearchString) => {
4831
+ const hasNewSearchQuery = typeof newSearchString !== "undefined";
4832
+ const searchString = newSearchString ?? this.searchQuery;
4833
+ return !!(this.isActive && !this.isLoading && (this.hasNext || hasNewSearchQuery) && searchString);
4834
+ };
4835
+ const { pageSize } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
4836
+ this.pageSize = pageSize;
4837
+ this.state = new StateStore(this.initialState);
4718
4838
  }
4719
- });
4720
- var createDraftLinkPreviewsCompositionMiddleware = (composer) => ({
4721
- id: "stream-io/message-composer-middleware/draft-link-previews",
4722
- handlers: {
4723
- compose: ({
4724
- state,
4725
- next,
4726
- forward
4727
- }) => {
4728
- const { linkPreviewsManager } = composer;
4729
- if (!linkPreviewsManager) return forward();
4730
- linkPreviewsManager.cancelURLEnrichment();
4731
- const linkPreviews = linkPreviewsManager.loadedPreviews.map(
4732
- (preview) => LinkPreviewsManager.getPreviewData(preview)
4733
- );
4734
- if (!linkPreviews.length) return forward();
4735
- return next({
4736
- ...state,
4737
- draft: {
4738
- ...state.draft,
4739
- attachments: (state.draft.attachments ?? []).concat(linkPreviews)
4740
- }
4741
- });
4742
- }
4839
+ get lastQueryError() {
4840
+ return this.state.getLatestValue().lastQueryError;
4743
4841
  }
4744
- });
4745
-
4746
- // src/messageComposer/middleware/messageComposer/textComposer.ts
4747
- var createTextComposerCompositionMiddleware = (composer) => ({
4748
- id: "stream-io/message-composer-middleware/text-composition",
4749
- handlers: {
4750
- compose: ({
4751
- state,
4752
- next,
4753
- forward
4754
- }) => {
4755
- if (!composer.textComposer) return forward();
4756
- const { mentionedUsers, text } = composer.textComposer;
4757
- const mentioned_users = Array.from(
4758
- new Set(
4759
- mentionedUsers.filter(
4760
- ({ id, name }) => text.includes(`@${id}`) || text.includes(`@${name}`)
4761
- )
4762
- )
4763
- );
4764
- if (!text && mentioned_users.length === 0) return forward();
4765
- return next({
4766
- ...state,
4767
- localMessage: {
4768
- ...state.localMessage,
4769
- mentioned_users,
4770
- text
4771
- },
4772
- message: {
4773
- ...state.message,
4774
- mentioned_users: mentioned_users.map((u) => u.id),
4775
- text
4776
- }
4777
- });
4778
- }
4842
+ get hasNext() {
4843
+ return this.state.getLatestValue().hasNext;
4779
4844
  }
4780
- });
4781
- var createDraftTextComposerCompositionMiddleware = (composer) => ({
4782
- id: "stream-io/message-composer-middleware/draft-text-composition",
4783
- handlers: {
4784
- compose: ({
4785
- state,
4786
- next,
4787
- forward
4788
- }) => {
4789
- if (!composer.textComposer) return forward();
4790
- const { maxLengthOnSend } = composer.config.text ?? {};
4791
- const { mentionedUsers, text: inputText } = composer.textComposer;
4792
- const mentioned_users = mentionedUsers.length ? Array.from(
4793
- new Set(
4794
- mentionedUsers.filter(
4795
- ({ id, name }) => inputText.includes(`@${id}`) || inputText.includes(`@${name}`)
4796
- )
4797
- )
4798
- ) : void 0;
4799
- const text = typeof maxLengthOnSend === "number" && inputText.length > maxLengthOnSend ? inputText.slice(0, maxLengthOnSend) : inputText;
4800
- return next({
4801
- ...state,
4802
- draft: {
4803
- ...state.draft,
4804
- mentioned_users: mentioned_users?.map((u) => u.id),
4805
- text
4806
- }
4807
- });
4845
+ get hasResults() {
4846
+ return Array.isArray(this.state.getLatestValue().items);
4847
+ }
4848
+ get isActive() {
4849
+ return this.state.getLatestValue().isActive;
4850
+ }
4851
+ get isLoading() {
4852
+ return this.state.getLatestValue().isLoading;
4853
+ }
4854
+ get initialState() {
4855
+ return {
4856
+ hasNext: true,
4857
+ isActive: false,
4858
+ isLoading: false,
4859
+ items: void 0,
4860
+ lastQueryError: void 0,
4861
+ next: void 0,
4862
+ offset: 0,
4863
+ searchQuery: ""
4864
+ };
4865
+ }
4866
+ get items() {
4867
+ return this.state.getLatestValue().items;
4868
+ }
4869
+ get next() {
4870
+ return this.state.getLatestValue().next;
4871
+ }
4872
+ get offset() {
4873
+ return this.state.getLatestValue().offset;
4874
+ }
4875
+ get searchQuery() {
4876
+ return this.state.getLatestValue().searchQuery;
4877
+ }
4878
+ getStateBeforeFirstQuery(newSearchString) {
4879
+ return {
4880
+ ...this.initialState,
4881
+ isActive: this.isActive,
4882
+ isLoading: true,
4883
+ searchQuery: newSearchString
4884
+ };
4885
+ }
4886
+ getStateAfterQuery(stateUpdate, isFirstPage) {
4887
+ const current = this.state.getLatestValue();
4888
+ return {
4889
+ ...current,
4890
+ lastQueryError: void 0,
4891
+ // reset lastQueryError that can be overridden by the stateUpdate
4892
+ ...stateUpdate,
4893
+ isLoading: false,
4894
+ items: isFirstPage ? stateUpdate.items : [...this.items ?? [], ...stateUpdate.items || []]
4895
+ };
4896
+ }
4897
+ prepareStateForQuery(newSearchString) {
4898
+ const hasNewSearchQuery = typeof newSearchString !== "undefined";
4899
+ const searchString = newSearchString ?? this.searchQuery;
4900
+ if (hasNewSearchQuery) {
4901
+ this.state.next(this.getStateBeforeFirstQuery(newSearchString ?? ""));
4902
+ } else {
4903
+ this.state.partialNext({ isLoading: true });
4808
4904
  }
4905
+ return { searchString, hasNewSearchQuery };
4809
4906
  }
4810
- });
4811
-
4812
- // src/messageComposer/middleware/messageComposer/messageComposerState.ts
4813
- var createMessageComposerStateCompositionMiddleware = (composer) => ({
4814
- id: "stream-io/message-composer-middleware/own-state",
4815
- handlers: {
4816
- compose: ({
4817
- state,
4818
- next
4819
- }) => {
4820
- const payload = {};
4821
- if (composer.quotedMessage) {
4822
- payload.quoted_message_id = composer.quotedMessage.id;
4823
- }
4824
- if (composer.pollId) {
4825
- payload.poll_id = composer.pollId;
4826
- }
4827
- if (composer.showReplyInChannel) {
4828
- payload.show_in_channel = true;
4829
- }
4830
- return next({
4831
- ...state,
4832
- localMessage: {
4833
- ...state.localMessage,
4834
- ...payload,
4835
- quoted_message: composer.quotedMessage ?? void 0
4836
- },
4837
- message: {
4838
- ...state.message,
4839
- ...payload
4840
- }
4841
- });
4907
+ updatePaginationStateFromQuery(result) {
4908
+ const { items, next } = result;
4909
+ const stateUpdate = {};
4910
+ if (Object.prototype.hasOwnProperty.call(result, "next")) {
4911
+ stateUpdate.next = next;
4912
+ stateUpdate.hasNext = !!next;
4913
+ } else {
4914
+ stateUpdate.offset = (this.offset ?? 0) + items.length;
4915
+ stateUpdate.hasNext = items.length === this.pageSize;
4842
4916
  }
4917
+ return stateUpdate;
4843
4918
  }
4844
- });
4845
- var createDraftMessageComposerStateCompositionMiddleware = (composer) => ({
4846
- id: "stream-io/message-composer-middleware/draft-own-state",
4847
- handlers: {
4848
- compose: ({
4849
- state,
4850
- next
4851
- }) => {
4852
- const payload = {};
4853
- if (composer.quotedMessage) {
4854
- payload.quoted_message_id = composer.quotedMessage.id;
4855
- }
4856
- if (composer.pollId) {
4857
- payload.poll_id = composer.pollId;
4858
- }
4859
- if (composer.showReplyInChannel) {
4860
- payload.show_in_channel = true;
4919
+ resetState() {
4920
+ this.state.next(this.initialState);
4921
+ }
4922
+ resetStateAndActivate() {
4923
+ this.resetState();
4924
+ this.activate();
4925
+ }
4926
+ };
4927
+ var BaseSearchSource = class extends BaseSearchSourceBase {
4928
+ constructor(options) {
4929
+ const { debounceMs } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
4930
+ super(options);
4931
+ this.setDebounceOptions = ({ debounceMs }) => {
4932
+ this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);
4933
+ };
4934
+ this.search = (searchQuery) => this.searchDebounced(searchQuery);
4935
+ this.setDebounceOptions({ debounceMs });
4936
+ }
4937
+ async executeQuery(newSearchString) {
4938
+ if (!this.canExecuteQuery(newSearchString)) return;
4939
+ const { hasNewSearchQuery, searchString } = this.prepareStateForQuery(newSearchString);
4940
+ let stateUpdate = {};
4941
+ try {
4942
+ const results = await this.query(searchString);
4943
+ if (!results) return;
4944
+ const { items } = results;
4945
+ stateUpdate = this.updatePaginationStateFromQuery(results);
4946
+ stateUpdate.items = await this.filterQueryResults(items);
4947
+ } catch (e) {
4948
+ stateUpdate.lastQueryError = e;
4949
+ if (isAPIError(e) && !isErrorRetryable(e)) {
4950
+ stateUpdate.hasNext = false;
4861
4951
  }
4862
- return next({
4863
- ...state,
4864
- draft: {
4865
- ...state.draft,
4866
- ...payload
4867
- }
4868
- });
4952
+ } finally {
4953
+ this.state.next(this.getStateAfterQuery(stateUpdate, hasNewSearchQuery));
4869
4954
  }
4870
4955
  }
4871
- });
4872
-
4873
- // src/messageComposer/middleware/messageComposer/userDataInjection.ts
4874
- var createUserDataInjectionMiddleware = (composer) => ({
4875
- id: "stream-io/message-composer-middleware/user-data-injection",
4876
- handlers: {
4877
- compose: ({
4878
- state,
4879
- next,
4880
- forward
4881
- }) => {
4882
- if (!composer.client.user) {
4883
- return forward();
4956
+ cancelScheduledQuery() {
4957
+ this.searchDebounced.cancel();
4958
+ }
4959
+ };
4960
+ var BaseSearchSourceSync = class extends BaseSearchSourceBase {
4961
+ constructor(options) {
4962
+ const { debounceMs } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
4963
+ super(options);
4964
+ this.setDebounceOptions = ({ debounceMs }) => {
4965
+ this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);
4966
+ };
4967
+ this.search = (searchQuery) => this.searchDebounced(searchQuery);
4968
+ this.setDebounceOptions({ debounceMs });
4969
+ }
4970
+ executeQuery(newSearchString) {
4971
+ if (!this.canExecuteQuery(newSearchString)) return;
4972
+ const { hasNewSearchQuery, searchString } = this.prepareStateForQuery(newSearchString);
4973
+ let stateUpdate = {};
4974
+ try {
4975
+ const results = this.query(searchString);
4976
+ if (!results) return;
4977
+ const { items } = results;
4978
+ stateUpdate = this.updatePaginationStateFromQuery(results);
4979
+ stateUpdate.items = this.filterQueryResults(items);
4980
+ } catch (e) {
4981
+ stateUpdate.lastQueryError = e;
4982
+ if (isAPIError(e) && !isErrorRetryable(e)) {
4983
+ stateUpdate.hasNext = false;
4884
4984
  }
4885
- const { channel_mutes, devices, mutes, ...messageUser } = composer.client.user;
4886
- return next({
4887
- ...state,
4888
- localMessage: {
4889
- ...state.localMessage,
4890
- user: messageUser,
4891
- user_id: messageUser.id
4892
- }
4893
- });
4985
+ } finally {
4986
+ this.state.next(this.getStateAfterQuery(stateUpdate, hasNewSearchQuery));
4894
4987
  }
4895
4988
  }
4896
- });
4897
-
4898
- // src/messageComposer/middleware/messageComposer/pollOnly.ts
4899
- var pollLocalMessageNullifiedFields = {
4900
- attachments: [],
4901
- mentioned_users: [],
4902
- parent_id: void 0,
4903
- quoted_message: void 0,
4904
- text: ""
4905
- };
4906
- var createPollOnlyCompositionMiddleware = (composer) => ({
4907
- id: "stream-io/message-composer-middleware/poll-only",
4908
- handlers: {
4909
- compose: ({
4910
- state,
4911
- complete,
4912
- forward
4913
- }) => {
4914
- const pollId = composer.pollId;
4915
- const isEditingMessage = !!composer.editedMessage;
4916
- const isComposingThreadReply = !!composer.threadId;
4917
- if (!pollId || isComposingThreadReply || isEditingMessage) return forward();
4918
- return complete({
4919
- ...state,
4920
- localMessage: {
4921
- ...state.localMessage,
4922
- ...pollLocalMessageNullifiedFields,
4923
- poll_id: pollId
4924
- },
4925
- message: {
4926
- id: state.localMessage.id,
4927
- poll_id: pollId
4928
- }
4929
- });
4930
- }
4931
- }
4932
- });
4933
-
4934
- // src/messageComposer/middleware/messageComposer/sharedLocation.ts
4935
- var createSharedLocationCompositionMiddleware = (composer) => ({
4936
- id: "stream-io/message-composer-middleware/shared-location",
4937
- handlers: {
4938
- compose: ({
4939
- state,
4940
- next,
4941
- forward
4942
- }) => {
4943
- const { locationComposer } = composer;
4944
- const location = locationComposer.validLocation;
4945
- if (!locationComposer || !location || !composer.client.user) return forward();
4946
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
4947
- return next({
4948
- ...state,
4949
- localMessage: {
4950
- ...state.localMessage,
4951
- shared_location: {
4952
- ...location,
4953
- channel_cid: composer.channel.cid,
4954
- created_at: timestamp,
4955
- updated_at: timestamp,
4956
- user_id: composer.client.user.id
4957
- }
4958
- },
4959
- message: {
4960
- ...state.message,
4961
- shared_location: location
4962
- }
4963
- });
4964
- }
4965
- }
4966
- });
4967
-
4968
- // src/messageComposer/middleware/messageComposer/MessageComposerMiddlewareExecutor.ts
4969
- var MessageComposerMiddlewareExecutor = class extends MiddlewareExecutor {
4970
- constructor({ composer }) {
4971
- super();
4972
- this.use([
4973
- createUserDataInjectionMiddleware(composer),
4974
- createPollOnlyCompositionMiddleware(composer),
4975
- createTextComposerCompositionMiddleware(composer),
4976
- createAttachmentsCompositionMiddleware(composer),
4977
- createLinkPreviewsCompositionMiddleware(composer),
4978
- createSharedLocationCompositionMiddleware(composer),
4979
- createMessageComposerStateCompositionMiddleware(composer),
4980
- createCustomDataCompositionMiddleware(composer),
4981
- createCompositionValidationMiddleware(composer),
4982
- createCompositionDataCleanupMiddleware(composer)
4983
- ]);
4984
- }
4985
- };
4986
- var MessageDraftComposerMiddlewareExecutor = class extends MiddlewareExecutor {
4987
- constructor({ composer }) {
4988
- super();
4989
- this.use([
4990
- createDraftTextComposerCompositionMiddleware(composer),
4991
- createDraftAttachmentsCompositionMiddleware(composer),
4992
- createDraftLinkPreviewsCompositionMiddleware(composer),
4993
- createDraftMessageComposerStateCompositionMiddleware(composer),
4994
- createDraftCustomDataCompositionMiddleware(composer),
4995
- createDraftCompositionValidationMiddleware(composer)
4996
- ]);
4997
- }
4998
- };
4999
-
5000
- // src/messageComposer/middleware/messageComposer/commandInjection.ts
5001
- var createCommandInjectionMiddleware = (composer) => ({
5002
- handlers: {
5003
- compose: ({
5004
- forward,
5005
- next,
5006
- state
5007
- }) => {
5008
- const command = composer.textComposer.command;
5009
- if (!command) {
5010
- return forward();
5011
- }
5012
- const { text } = state.localMessage;
5013
- const injection = `/${command?.name}`;
5014
- const enrichedText = `${injection} ${text}`;
5015
- return next({
5016
- ...state,
5017
- localMessage: {
5018
- ...state.localMessage,
5019
- text: enrichedText
5020
- },
5021
- message: {
5022
- ...state.message,
5023
- text: enrichedText
5024
- }
5025
- });
5026
- }
5027
- },
5028
- id: "stream-io/message-composer-middleware/command-string-injection"
5029
- });
5030
- var createDraftCommandInjectionMiddleware = (composer) => ({
5031
- handlers: {
5032
- compose: ({
5033
- forward,
5034
- next,
5035
- state
5036
- }) => {
5037
- const command = composer.textComposer.command;
5038
- if (!command) {
5039
- return forward();
5040
- }
5041
- const { text } = state.draft;
5042
- const injection = `/${command?.name}`;
5043
- const enrichedText = `${injection} ${text}`;
5044
- return next({
5045
- ...state,
5046
- draft: {
5047
- ...state.draft,
5048
- text: enrichedText
5049
- }
5050
- });
5051
- }
5052
- },
5053
- id: "stream-io/message-composer-middleware/draft-command-string-injection"
5054
- });
5055
-
5056
- // src/messageComposer/middleware/textComposer/activeCommandGuard.ts
5057
- var createActiveCommandGuardMiddleware = () => ({
5058
- handlers: {
5059
- onChange: ({ complete, forward, state }) => {
5060
- if (state.command) {
5061
- return complete(state);
5062
- }
5063
- return forward();
5064
- },
5065
- onSuggestionItemSelect: ({ forward }) => forward()
5066
- },
5067
- id: "stream-io/text-composer/active-command-guard"
5068
- });
5069
-
5070
- // src/errors.ts
5071
- var APIErrorCodes = {
5072
- "-1": { name: "InternalSystemError", retryable: true },
5073
- "2": { name: "AccessKeyError", retryable: false },
5074
- "3": { name: "AuthenticationFailedError", retryable: true },
5075
- "4": { name: "InputError", retryable: false },
5076
- "6": { name: "DuplicateUsernameError", retryable: false },
5077
- "9": { name: "RateLimitError", retryable: true },
5078
- "16": { name: "DoesNotExistError", retryable: false },
5079
- "17": { name: "NotAllowedError", retryable: false },
5080
- "18": { name: "EventNotSupportedError", retryable: false },
5081
- "19": { name: "ChannelFeatureNotSupportedError", retryable: false },
5082
- "20": { name: "MessageTooLongError", retryable: false },
5083
- "21": { name: "MultipleNestingLevelError", retryable: false },
5084
- "22": { name: "PayloadTooBigError", retryable: false },
5085
- "23": { name: "RequestTimeoutError", retryable: true },
5086
- "24": { name: "MaxHeaderSizeExceededError", retryable: false },
5087
- "40": { name: "AuthErrorTokenExpired", retryable: false },
5088
- "41": { name: "AuthErrorTokenNotValidYet", retryable: false },
5089
- "42": { name: "AuthErrorTokenUsedBeforeIssuedAt", retryable: false },
5090
- "43": { name: "AuthErrorTokenSignatureInvalid", retryable: false },
5091
- "44": { name: "CustomCommandEndpointMissingError", retryable: false },
5092
- "45": { name: "CustomCommandEndpointCallError", retryable: true },
5093
- "46": { name: "ConnectionIDNotFoundError", retryable: false },
5094
- "60": { name: "CoolDownError", retryable: true },
5095
- "69": { name: "ErrWrongRegion", retryable: false },
5096
- "70": { name: "ErrQueryChannelPermissions", retryable: false },
5097
- "71": { name: "ErrTooManyConnections", retryable: true },
5098
- "99": { name: "AppSuspendedError", retryable: false }
5099
- };
5100
- function isAPIError(error) {
5101
- return error.code !== void 0;
5102
- }
5103
- function isErrorRetryable(error) {
5104
- if (!error.code) return false;
5105
- const err = APIErrorCodes[`${error.code}`];
5106
- if (!err) return false;
5107
- return err.retryable;
5108
- }
5109
- function isConnectionIDError(error) {
5110
- return error.code === 46;
5111
- }
5112
- function isWSFailure(err) {
5113
- if (typeof err.isWSFailure === "boolean") {
5114
- return err.isWSFailure;
5115
- }
5116
- try {
5117
- return JSON.parse(err.message).isWSFailure;
5118
- } catch (_) {
5119
- return false;
5120
- }
5121
- }
5122
- function isErrorResponse(res) {
5123
- return !res.status || res.status < 200 || 300 <= res.status;
5124
- }
5125
-
5126
- // src/search/BaseSearchSource.ts
5127
- var DEFAULT_SEARCH_SOURCE_OPTIONS = {
5128
- debounceMs: 300,
5129
- pageSize: 10
5130
- };
5131
- var BaseSearchSourceBase = class {
5132
- constructor(options) {
5133
- this.activate = () => {
5134
- if (this.isActive) return;
5135
- this.state.partialNext({ isActive: true });
5136
- };
5137
- this.deactivate = () => {
5138
- if (!this.isActive) return;
5139
- this.state.partialNext({ isActive: false });
5140
- };
5141
- this.canExecuteQuery = (newSearchString) => {
5142
- const hasNewSearchQuery = typeof newSearchString !== "undefined";
5143
- const searchString = newSearchString ?? this.searchQuery;
5144
- return !!(this.isActive && !this.isLoading && (this.hasNext || hasNewSearchQuery) && searchString);
5145
- };
5146
- const { pageSize } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
5147
- this.pageSize = pageSize;
5148
- this.state = new StateStore(this.initialState);
5149
- }
5150
- get lastQueryError() {
5151
- return this.state.getLatestValue().lastQueryError;
5152
- }
5153
- get hasNext() {
5154
- return this.state.getLatestValue().hasNext;
5155
- }
5156
- get hasResults() {
5157
- return Array.isArray(this.state.getLatestValue().items);
5158
- }
5159
- get isActive() {
5160
- return this.state.getLatestValue().isActive;
5161
- }
5162
- get isLoading() {
5163
- return this.state.getLatestValue().isLoading;
5164
- }
5165
- get initialState() {
5166
- return {
5167
- hasNext: true,
5168
- isActive: false,
5169
- isLoading: false,
5170
- items: void 0,
5171
- lastQueryError: void 0,
5172
- next: void 0,
5173
- offset: 0,
5174
- searchQuery: ""
5175
- };
5176
- }
5177
- get items() {
5178
- return this.state.getLatestValue().items;
5179
- }
5180
- get next() {
5181
- return this.state.getLatestValue().next;
5182
- }
5183
- get offset() {
5184
- return this.state.getLatestValue().offset;
5185
- }
5186
- get searchQuery() {
5187
- return this.state.getLatestValue().searchQuery;
5188
- }
5189
- getStateBeforeFirstQuery(newSearchString) {
5190
- return {
5191
- ...this.initialState,
5192
- isActive: this.isActive,
5193
- isLoading: true,
5194
- searchQuery: newSearchString
5195
- };
5196
- }
5197
- getStateAfterQuery(stateUpdate, isFirstPage) {
5198
- const current = this.state.getLatestValue();
5199
- return {
5200
- ...current,
5201
- lastQueryError: void 0,
5202
- // reset lastQueryError that can be overridden by the stateUpdate
5203
- ...stateUpdate,
5204
- isLoading: false,
5205
- items: isFirstPage ? stateUpdate.items : [...this.items ?? [], ...stateUpdate.items || []]
5206
- };
5207
- }
5208
- prepareStateForQuery(newSearchString) {
5209
- const hasNewSearchQuery = typeof newSearchString !== "undefined";
5210
- const searchString = newSearchString ?? this.searchQuery;
5211
- if (hasNewSearchQuery) {
5212
- this.state.next(this.getStateBeforeFirstQuery(newSearchString ?? ""));
5213
- } else {
5214
- this.state.partialNext({ isLoading: true });
5215
- }
5216
- return { searchString, hasNewSearchQuery };
5217
- }
5218
- updatePaginationStateFromQuery(result) {
5219
- const { items, next } = result;
5220
- const stateUpdate = {};
5221
- if (Object.prototype.hasOwnProperty.call(result, "next")) {
5222
- stateUpdate.next = next;
5223
- stateUpdate.hasNext = !!next;
5224
- } else {
5225
- stateUpdate.offset = (this.offset ?? 0) + items.length;
5226
- stateUpdate.hasNext = items.length === this.pageSize;
5227
- }
5228
- return stateUpdate;
5229
- }
5230
- resetState() {
5231
- this.state.next(this.initialState);
5232
- }
5233
- resetStateAndActivate() {
5234
- this.resetState();
5235
- this.activate();
5236
- }
5237
- };
5238
- var BaseSearchSource = class extends BaseSearchSourceBase {
5239
- constructor(options) {
5240
- const { debounceMs } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
5241
- super(options);
5242
- this.setDebounceOptions = ({ debounceMs }) => {
5243
- this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);
5244
- };
5245
- this.search = (searchQuery) => this.searchDebounced(searchQuery);
5246
- this.setDebounceOptions({ debounceMs });
5247
- }
5248
- async executeQuery(newSearchString) {
5249
- if (!this.canExecuteQuery(newSearchString)) return;
5250
- const { hasNewSearchQuery, searchString } = this.prepareStateForQuery(newSearchString);
5251
- let stateUpdate = {};
5252
- try {
5253
- const results = await this.query(searchString);
5254
- if (!results) return;
5255
- const { items } = results;
5256
- stateUpdate = this.updatePaginationStateFromQuery(results);
5257
- stateUpdate.items = await this.filterQueryResults(items);
5258
- } catch (e) {
5259
- stateUpdate.lastQueryError = e;
5260
- if (isAPIError(e) && !isErrorRetryable(e)) {
5261
- stateUpdate.hasNext = false;
5262
- }
5263
- } finally {
5264
- this.state.next(this.getStateAfterQuery(stateUpdate, hasNewSearchQuery));
5265
- }
5266
- }
5267
- cancelScheduledQuery() {
5268
- this.searchDebounced.cancel();
5269
- }
5270
- };
5271
- var BaseSearchSourceSync = class extends BaseSearchSourceBase {
5272
- constructor(options) {
5273
- const { debounceMs } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };
5274
- super(options);
5275
- this.setDebounceOptions = ({ debounceMs }) => {
5276
- this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);
5277
- };
5278
- this.search = (searchQuery) => this.searchDebounced(searchQuery);
5279
- this.setDebounceOptions({ debounceMs });
5280
- }
5281
- executeQuery(newSearchString) {
5282
- if (!this.canExecuteQuery(newSearchString)) return;
5283
- const { hasNewSearchQuery, searchString } = this.prepareStateForQuery(newSearchString);
5284
- let stateUpdate = {};
5285
- try {
5286
- const results = this.query(searchString);
5287
- if (!results) return;
5288
- const { items } = results;
5289
- stateUpdate = this.updatePaginationStateFromQuery(results);
5290
- stateUpdate.items = this.filterQueryResults(items);
5291
- } catch (e) {
5292
- stateUpdate.lastQueryError = e;
5293
- if (isAPIError(e) && !isErrorRetryable(e)) {
5294
- stateUpdate.hasNext = false;
5295
- }
5296
- } finally {
5297
- this.state.next(this.getStateAfterQuery(stateUpdate, hasNewSearchQuery));
5298
- }
5299
- }
5300
- cancelScheduledQuery() {
5301
- this.searchDebounced.cancel();
5302
- }
4989
+ cancelScheduledQuery() {
4990
+ this.searchDebounced.cancel();
4991
+ }
5303
4992
  };
5304
4993
 
5305
4994
  // src/search/SearchController.ts
@@ -5395,586 +5084,1095 @@ var SearchController = class {
5395
5084
  get activeSources() {
5396
5085
  return this.state.getLatestValue().sources.filter((s) => s.isActive);
5397
5086
  }
5398
- get isActive() {
5399
- return this.state.getLatestValue().isActive;
5087
+ get isActive() {
5088
+ return this.state.getLatestValue().isActive;
5089
+ }
5090
+ get searchQuery() {
5091
+ return this.state.getLatestValue().searchQuery;
5092
+ }
5093
+ get searchSourceTypes() {
5094
+ return this.sources.map((s) => s.type);
5095
+ }
5096
+ };
5097
+
5098
+ // src/pagination/BasePaginator.ts
5099
+ var DEFAULT_PAGINATION_OPTIONS = {
5100
+ debounceMs: 300,
5101
+ pageSize: 10
5102
+ };
5103
+ var BasePaginator = class {
5104
+ constructor(options) {
5105
+ this._isCursorPagination = false;
5106
+ this.setDebounceOptions = ({ debounceMs }) => {
5107
+ this._executeQueryDebounced = debounce(this.executeQuery.bind(this), debounceMs);
5108
+ };
5109
+ this.canExecuteQuery = (direction) => !this.isLoading && direction === "next" && this.hasNext || direction === "prev" && this.hasPrev;
5110
+ this.next = () => this.executeQuery({ direction: "next" });
5111
+ this.prev = () => this.executeQuery({ direction: "prev" });
5112
+ this.nextDebounced = () => {
5113
+ this._executeQueryDebounced({ direction: "next" });
5114
+ };
5115
+ this.prevDebounced = () => {
5116
+ this._executeQueryDebounced({ direction: "prev" });
5117
+ };
5118
+ const { debounceMs, pageSize } = { ...DEFAULT_PAGINATION_OPTIONS, ...options };
5119
+ this.pageSize = pageSize;
5120
+ this.state = new StateStore(this.initialState);
5121
+ this.setDebounceOptions({ debounceMs });
5122
+ }
5123
+ get lastQueryError() {
5124
+ return this.state.getLatestValue().lastQueryError;
5125
+ }
5126
+ get hasNext() {
5127
+ return this.state.getLatestValue().hasNext;
5128
+ }
5129
+ get hasPrev() {
5130
+ return this.state.getLatestValue().hasPrev;
5131
+ }
5132
+ get hasResults() {
5133
+ return Array.isArray(this.state.getLatestValue().items);
5134
+ }
5135
+ get isLoading() {
5136
+ return this.state.getLatestValue().isLoading;
5137
+ }
5138
+ get initialState() {
5139
+ return {
5140
+ hasNext: true,
5141
+ hasPrev: true,
5142
+ //todo: check if optimistic value does not cause problems in UI
5143
+ isLoading: false,
5144
+ items: void 0,
5145
+ lastQueryError: void 0,
5146
+ cursor: void 0,
5147
+ offset: 0
5148
+ };
5149
+ }
5150
+ get items() {
5151
+ return this.state.getLatestValue().items;
5152
+ }
5153
+ get cursor() {
5154
+ return this.state.getLatestValue().cursor;
5155
+ }
5156
+ get offset() {
5157
+ return this.state.getLatestValue().offset;
5158
+ }
5159
+ getStateBeforeFirstQuery() {
5160
+ return {
5161
+ ...this.initialState,
5162
+ isLoading: true
5163
+ };
5164
+ }
5165
+ getStateAfterQuery(stateUpdate, isFirstPage) {
5166
+ const current = this.state.getLatestValue();
5167
+ return {
5168
+ ...current,
5169
+ lastQueryError: void 0,
5170
+ // reset lastQueryError that can be overridden by the stateUpdate
5171
+ ...stateUpdate,
5172
+ isLoading: false,
5173
+ items: isFirstPage ? stateUpdate.items : [...this.items ?? [], ...stateUpdate.items || []]
5174
+ };
5175
+ }
5176
+ async executeQuery({ direction }) {
5177
+ if (!this.canExecuteQuery(direction)) return;
5178
+ const isFirstPage = typeof this.items === "undefined";
5179
+ if (isFirstPage) {
5180
+ this.state.next(this.getStateBeforeFirstQuery());
5181
+ } else {
5182
+ this.state.partialNext({ isLoading: true });
5183
+ }
5184
+ const stateUpdate = {};
5185
+ try {
5186
+ const results = await this.query({ direction });
5187
+ if (!results) return;
5188
+ const { items, next, prev } = results;
5189
+ if (isFirstPage && (next || prev)) {
5190
+ this._isCursorPagination = true;
5191
+ }
5192
+ if (this._isCursorPagination) {
5193
+ stateUpdate.cursor = { next: next || null, prev: prev || null };
5194
+ stateUpdate.hasNext = !!next;
5195
+ stateUpdate.hasPrev = !!prev;
5196
+ } else {
5197
+ stateUpdate.offset = (this.offset ?? 0) + items.length;
5198
+ stateUpdate.hasNext = items.length === this.pageSize;
5199
+ }
5200
+ stateUpdate.items = await this.filterQueryResults(items);
5201
+ } catch (e) {
5202
+ stateUpdate.lastQueryError = e;
5203
+ } finally {
5204
+ this.state.next(this.getStateAfterQuery(stateUpdate, isFirstPage));
5205
+ }
5206
+ }
5207
+ cancelScheduledQuery() {
5208
+ this._executeQueryDebounced.cancel();
5209
+ }
5210
+ resetState() {
5211
+ this.state.next(this.initialState);
5212
+ }
5213
+ };
5214
+
5215
+ // src/pagination/FilterBuilder.ts
5216
+ var FilterBuilder = class {
5217
+ constructor(params) {
5218
+ this.context = new StateStore(params?.initialContext ?? {});
5219
+ this.filterConfig = new StateStore(
5220
+ params?.initialFilterConfig ?? {}
5221
+ );
5222
+ }
5223
+ updateFilterConfig(config) {
5224
+ this.filterConfig.partialNext(config);
5225
+ }
5226
+ enableFilter(filterKey) {
5227
+ const config = this.filterConfig.getLatestValue();
5228
+ if (config[filterKey]) {
5229
+ this.filterConfig.partialNext({
5230
+ [filterKey]: {
5231
+ ...config[filterKey],
5232
+ enabled: true
5233
+ }
5234
+ });
5235
+ }
5236
+ }
5237
+ disableFilter(filterKey) {
5238
+ const config = this.filterConfig.getLatestValue();
5239
+ if (config[filterKey]) {
5240
+ this.filterConfig.partialNext({
5241
+ [filterKey]: {
5242
+ ...config[filterKey],
5243
+ enabled: false
5244
+ }
5245
+ });
5246
+ }
5247
+ }
5248
+ updateContext(newContext) {
5249
+ this.context.partialNext(newContext);
5250
+ }
5251
+ buildFilters(params) {
5252
+ const filters = {
5253
+ ...params?.baseFilters ?? {}
5254
+ };
5255
+ const filterConfig = this.filterConfig.getLatestValue();
5256
+ for (const key in filterConfig) {
5257
+ const configItem = filterConfig[key];
5258
+ if (!configItem?.enabled) continue;
5259
+ const generated = configItem.generate({
5260
+ ...this.context.getLatestValue(),
5261
+ ...params?.context ?? {}
5262
+ });
5263
+ if (generated) Object.assign(filters, generated);
5264
+ }
5265
+ return filters;
5266
+ }
5267
+ };
5268
+
5269
+ // src/pagination/ReminderPaginator.ts
5270
+ var ReminderPaginator = class extends BasePaginator {
5271
+ constructor(client, options) {
5272
+ super(options);
5273
+ this.query = async ({
5274
+ direction
5275
+ }) => {
5276
+ const cursor = this.cursor?.[direction];
5277
+ const {
5278
+ reminders: items,
5279
+ next,
5280
+ prev
5281
+ } = await this.client.queryReminders({
5282
+ filter: this.filters,
5283
+ sort: this.sort,
5284
+ limit: this.pageSize,
5285
+ [direction]: cursor
5286
+ });
5287
+ return { items, next, prev };
5288
+ };
5289
+ this.filterQueryResults = (items) => items;
5290
+ this.client = client;
5291
+ }
5292
+ get filters() {
5293
+ return this._filters;
5294
+ }
5295
+ get sort() {
5296
+ return this._sort;
5400
5297
  }
5401
- get searchQuery() {
5402
- return this.state.getLatestValue().searchQuery;
5298
+ set filters(filters) {
5299
+ this._filters = filters;
5300
+ this.resetState();
5403
5301
  }
5404
- get searchSourceTypes() {
5405
- return this.sources.map((s) => s.type);
5302
+ set sort(sort) {
5303
+ this._sort = sort;
5304
+ this.resetState();
5406
5305
  }
5407
5306
  };
5408
5307
 
5409
- // src/pagination/BasePaginator.ts
5410
- var DEFAULT_PAGINATION_OPTIONS = {
5411
- debounceMs: 300,
5412
- pageSize: 10
5413
- };
5414
- var BasePaginator = class {
5415
- constructor(options) {
5416
- this._isCursorPagination = false;
5417
- this.setDebounceOptions = ({ debounceMs }) => {
5418
- this._executeQueryDebounced = debounce(this.executeQuery.bind(this), debounceMs);
5419
- };
5420
- this.canExecuteQuery = (direction) => !this.isLoading && direction === "next" && this.hasNext || direction === "prev" && this.hasPrev;
5421
- this.next = () => this.executeQuery({ direction: "next" });
5422
- this.prev = () => this.executeQuery({ direction: "prev" });
5423
- this.nextDebounced = () => {
5424
- this._executeQueryDebounced({ direction: "next" });
5425
- };
5426
- this.prevDebounced = () => {
5427
- this._executeQueryDebounced({ direction: "prev" });
5428
- };
5429
- const { debounceMs, pageSize } = { ...DEFAULT_PAGINATION_OPTIONS, ...options };
5430
- this.pageSize = pageSize;
5431
- this.state = new StateStore(this.initialState);
5432
- this.setDebounceOptions({ debounceMs });
5308
+ // src/search/UserSearchSource.ts
5309
+ var UserSearchSource = class extends BaseSearchSource {
5310
+ constructor(client, options, filterBuilderOptions = {}) {
5311
+ super(options);
5312
+ this.type = "users";
5313
+ this.client = client;
5314
+ this.filterBuilder = new FilterBuilder({
5315
+ initialFilterConfig: {
5316
+ $or: {
5317
+ enabled: true,
5318
+ generate: ({ searchQuery }) => searchQuery ? {
5319
+ $or: [
5320
+ { id: { $autocomplete: searchQuery } },
5321
+ { name: { $autocomplete: searchQuery } }
5322
+ ]
5323
+ } : null
5324
+ }
5325
+ },
5326
+ ...filterBuilderOptions
5327
+ });
5433
5328
  }
5434
- get lastQueryError() {
5435
- return this.state.getLatestValue().lastQueryError;
5329
+ async query(searchQuery) {
5330
+ const filters = this.filterBuilder.buildFilters({
5331
+ baseFilters: this.filters,
5332
+ context: { searchQuery }
5333
+ });
5334
+ const sort = { id: 1, ...this.sort };
5335
+ const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };
5336
+ const { users } = await this.client.queryUsers(filters, sort, options);
5337
+ return { items: users };
5436
5338
  }
5437
- get hasNext() {
5438
- return this.state.getLatestValue().hasNext;
5339
+ filterQueryResults(items) {
5340
+ return items.filter((u) => u.id !== this.client.user?.id);
5439
5341
  }
5440
- get hasPrev() {
5441
- return this.state.getLatestValue().hasPrev;
5342
+ };
5343
+
5344
+ // src/search/ChannelSearchSource.ts
5345
+ var ChannelSearchSource = class extends BaseSearchSource {
5346
+ constructor(client, options, filterBuilderOptions = {}) {
5347
+ super(options);
5348
+ this.type = "channels";
5349
+ this.client = client;
5350
+ this.filterBuilder = new FilterBuilder({
5351
+ ...filterBuilderOptions,
5352
+ initialFilterConfig: {
5353
+ name: {
5354
+ enabled: true,
5355
+ generate: ({ searchQuery }) => searchQuery ? { name: { $autocomplete: searchQuery } } : null
5356
+ },
5357
+ ...filterBuilderOptions.initialFilterConfig
5358
+ }
5359
+ });
5442
5360
  }
5443
- get hasResults() {
5444
- return Array.isArray(this.state.getLatestValue().items);
5361
+ async query(searchQuery) {
5362
+ const filters = this.filterBuilder.buildFilters({
5363
+ baseFilters: {
5364
+ ...this.client.userID ? { members: { $in: [this.client.userID] } } : {},
5365
+ ...this.filters
5366
+ },
5367
+ context: { searchQuery }
5368
+ });
5369
+ const sort = this.sort ?? {};
5370
+ const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };
5371
+ const items = await this.client.queryChannels(filters, sort, options);
5372
+ return { items };
5445
5373
  }
5446
- get isLoading() {
5447
- return this.state.getLatestValue().isLoading;
5374
+ filterQueryResults(items) {
5375
+ return items;
5448
5376
  }
5449
- get initialState() {
5450
- return {
5451
- hasNext: true,
5452
- hasPrev: true,
5453
- //todo: check if optimistic value does not cause problems in UI
5454
- isLoading: false,
5455
- items: void 0,
5456
- lastQueryError: void 0,
5457
- cursor: void 0,
5458
- offset: 0
5459
- };
5377
+ };
5378
+
5379
+ // src/search/MessageSearchSource.ts
5380
+ var MessageSearchSource = class extends BaseSearchSource {
5381
+ constructor(client, options, filterBuilderOptions) {
5382
+ super(options);
5383
+ this.type = "messages";
5384
+ this.client = client;
5385
+ this.messageSearchChannelFilterBuilder = new FilterBuilder(filterBuilderOptions?.messageSearchChannel);
5386
+ this.messageSearchFilterBuilder = new FilterBuilder({
5387
+ ...filterBuilderOptions?.messageSearch,
5388
+ initialFilterConfig: {
5389
+ text: {
5390
+ enabled: true,
5391
+ generate: ({ searchQuery }) => searchQuery ? { text: searchQuery } : null
5392
+ },
5393
+ ...filterBuilderOptions?.messageSearch?.initialFilterConfig
5394
+ }
5395
+ });
5396
+ this.channelQueryFilterBuilder = new FilterBuilder({
5397
+ ...filterBuilderOptions?.channelQuery,
5398
+ initialFilterConfig: {
5399
+ cid: {
5400
+ enabled: true,
5401
+ generate: ({ cids }) => cids ? { cid: { $in: cids } } : null
5402
+ },
5403
+ ...filterBuilderOptions?.channelQuery?.initialFilterConfig
5404
+ }
5405
+ });
5460
5406
  }
5461
- get items() {
5462
- return this.state.getLatestValue().items;
5407
+ async query(searchQuery) {
5408
+ if (!this.client.userID || !searchQuery || this.next === null) return { items: [] };
5409
+ const channelFilters = this.messageSearchChannelFilterBuilder.buildFilters({
5410
+ baseFilters: {
5411
+ ...this.client.userID ? { members: { $in: [this.client.userID] } } : {},
5412
+ ...this.messageSearchChannelFilters
5413
+ },
5414
+ context: { searchQuery }
5415
+ });
5416
+ const messageFilters = this.messageSearchFilterBuilder.buildFilters({
5417
+ baseFilters: {
5418
+ type: "regular",
5419
+ ...this.messageSearchFilters
5420
+ },
5421
+ context: { searchQuery }
5422
+ });
5423
+ const sort = {
5424
+ created_at: -1,
5425
+ ...this.messageSearchSort
5426
+ };
5427
+ const options = {
5428
+ limit: this.pageSize,
5429
+ next: this.next,
5430
+ sort
5431
+ };
5432
+ const { next, results } = await this.client.search(
5433
+ channelFilters,
5434
+ messageFilters,
5435
+ options
5436
+ );
5437
+ const items = results.map(({ message }) => message);
5438
+ const cids = Array.from(
5439
+ items.reduce((acc, message) => {
5440
+ if (message.cid && !this.client.activeChannels[message.cid]) acc.add(message.cid);
5441
+ return acc;
5442
+ }, /* @__PURE__ */ new Set())
5443
+ );
5444
+ if (cids.length > 0) {
5445
+ const channelQueryFilters = this.channelQueryFilterBuilder.buildFilters({
5446
+ baseFilters: this.channelQueryFilters,
5447
+ context: { cids }
5448
+ });
5449
+ await this.client.queryChannels(
5450
+ channelQueryFilters,
5451
+ {
5452
+ last_message_at: -1,
5453
+ ...this.channelQuerySort
5454
+ },
5455
+ this.channelQueryOptions
5456
+ );
5457
+ }
5458
+ return { items, next };
5463
5459
  }
5464
- get cursor() {
5465
- return this.state.getLatestValue().cursor;
5460
+ filterQueryResults(items) {
5461
+ return items;
5466
5462
  }
5467
- get offset() {
5468
- return this.state.getLatestValue().offset;
5463
+ };
5464
+
5465
+ // src/messageComposer/middleware/textComposer/commandUtils.ts
5466
+ function escapeCommandRegExp(text) {
5467
+ return text.replace(/[-[\]{}()*+?.,/\\^$|#]/g, "\\$&");
5468
+ }
5469
+ var getRawCommandName = (text) => text?.match(/^\/(\S+)(?:\s.*)?$/)?.[1];
5470
+ var getCompleteCommandInString = (text) => {
5471
+ const match = text.match(/^\/(\S+)\s+.*/);
5472
+ const commandName = match && match[1];
5473
+ return commandName;
5474
+ };
5475
+ var stripCommandFromText = (text, commandName) => text.replace(new RegExp(`^${escapeCommandRegExp(`/${commandName}`)}\\s*`), "");
5476
+ var notifyCommandDisabled = (composer, command) => {
5477
+ const disabledReason = composer.getCommandDisabledReason(command);
5478
+ if (!disabledReason) return;
5479
+ composer.client.notifications.addWarning({
5480
+ message: disabledReason === "editing" ? "Command not available while editing" : "Command not available while replying",
5481
+ origin: {
5482
+ emitter: "MessageComposer",
5483
+ context: { command, composer }
5484
+ },
5485
+ options: {
5486
+ type: "validation:command:disabled",
5487
+ metadata: {
5488
+ command: command.name,
5489
+ reason: disabledReason
5490
+ }
5491
+ }
5492
+ });
5493
+ return true;
5494
+ };
5495
+
5496
+ // src/messageComposer/middleware/textComposer/textMiddlewareUtils.ts
5497
+ var getTriggerCharWithToken = ({
5498
+ trigger,
5499
+ text,
5500
+ isCommand = false,
5501
+ acceptTrailingSpaces = true
5502
+ }) => {
5503
+ const escapedTrigger = escapeCommandRegExp(trigger);
5504
+ const triggerNorWhitespace = `[^\\s${escapedTrigger}]*`;
5505
+ const match = text.match(
5506
+ new RegExp(
5507
+ isCommand ? `^[${escapedTrigger}]${triggerNorWhitespace}$` : acceptTrailingSpaces ? `(?!^|\\W)?[${escapedTrigger}]${triggerNorWhitespace}\\s?${triggerNorWhitespace}$` : `(?!^|\\W)?[${escapedTrigger}]${triggerNorWhitespace}$`,
5508
+ "g"
5509
+ )
5510
+ );
5511
+ return match && match[match.length - 1].trim();
5512
+ };
5513
+ var insertItemWithTrigger = ({
5514
+ insertText,
5515
+ selection,
5516
+ text,
5517
+ trigger
5518
+ }) => {
5519
+ const beforeCursor = text.slice(0, selection.end);
5520
+ const afterCursor = text.slice(selection.end);
5521
+ const lastIndex = beforeCursor.lastIndexOf(trigger);
5522
+ const newText = beforeCursor.slice(0, lastIndex) + insertText + afterCursor;
5523
+ return {
5524
+ text: newText,
5525
+ selection: {
5526
+ start: lastIndex + insertText.length,
5527
+ end: lastIndex + insertText.length
5528
+ }
5529
+ };
5530
+ };
5531
+ var replaceWordWithEntity = async ({
5532
+ caretPosition,
5533
+ getEntityString,
5534
+ text
5535
+ }) => {
5536
+ const lastWordRegex = /([^\s]+)(\s*)$/;
5537
+ const match = lastWordRegex.exec(text.slice(0, caretPosition));
5538
+ if (!match) return text;
5539
+ const lastWord = match[1];
5540
+ if (!lastWord) return text;
5541
+ const spaces = match[2];
5542
+ const newWord = await getEntityString(lastWord);
5543
+ if (newWord == null) return text;
5544
+ const textBeforeWord = text.slice(0, caretPosition - match[0].length);
5545
+ const textAfterCaret = text.slice(caretPosition, -1);
5546
+ return textBeforeWord + newWord + spaces + textAfterCaret;
5547
+ };
5548
+ var getTokenizedSuggestionDisplayName = ({
5549
+ displayName,
5550
+ searchToken
5551
+ }) => ({
5552
+ tokenizedDisplayName: {
5553
+ token: searchToken,
5554
+ parts: searchToken ? displayName.split(new RegExp(`(${escapeCommandRegExp(searchToken)})`, "gi")).filter(Boolean) : [displayName]
5469
5555
  }
5470
- getStateBeforeFirstQuery() {
5471
- return {
5472
- ...this.initialState,
5473
- isLoading: true
5556
+ });
5557
+
5558
+ // src/messageComposer/middleware/textComposer/commands.ts
5559
+ var CommandSearchSource = class extends BaseSearchSourceSync {
5560
+ constructor(channel, options) {
5561
+ super(options);
5562
+ this.type = "commands";
5563
+ this.canExecuteQuery = (newSearchString) => {
5564
+ const hasNewSearchQuery = typeof newSearchString !== "undefined";
5565
+ return this.isActive && !this.isLoading && (this.hasNext || hasNewSearchQuery);
5474
5566
  };
5567
+ this.channel = channel;
5475
5568
  }
5476
- getStateAfterQuery(stateUpdate, isFirstPage) {
5477
- const current = this.state.getLatestValue();
5569
+ getStateBeforeFirstQuery(newSearchString) {
5570
+ const newState = super.getStateBeforeFirstQuery(newSearchString);
5571
+ const { items } = this.state.getLatestValue();
5478
5572
  return {
5479
- ...current,
5480
- lastQueryError: void 0,
5481
- // reset lastQueryError that can be overridden by the stateUpdate
5482
- ...stateUpdate,
5483
- isLoading: false,
5484
- items: isFirstPage ? stateUpdate.items : [...this.items ?? [], ...stateUpdate.items || []]
5573
+ ...newState,
5574
+ items
5575
+ // preserve items to avoid flickering
5485
5576
  };
5486
5577
  }
5487
- async executeQuery({ direction }) {
5488
- if (!this.canExecuteQuery(direction)) return;
5489
- const isFirstPage = typeof this.items === "undefined";
5490
- if (isFirstPage) {
5491
- this.state.next(this.getStateBeforeFirstQuery());
5492
- } else {
5493
- this.state.partialNext({ isLoading: true });
5494
- }
5495
- const stateUpdate = {};
5496
- try {
5497
- const results = await this.query({ direction });
5498
- if (!results) return;
5499
- const { items, next, prev } = results;
5500
- if (isFirstPage && (next || prev)) {
5501
- this._isCursorPagination = true;
5578
+ query(searchQuery) {
5579
+ const channelConfig = this.channel.getConfig();
5580
+ const commands = channelConfig?.commands || [];
5581
+ const selectedCommands = commands.filter(
5582
+ (command) => !!(command.name && command.name.toLowerCase().indexOf(searchQuery.toLowerCase()) !== -1)
5583
+ );
5584
+ selectedCommands.sort((a, b) => {
5585
+ let nameA = a.name?.toLowerCase();
5586
+ let nameB = b.name?.toLowerCase();
5587
+ if (nameA?.indexOf(searchQuery) === 0) {
5588
+ nameA = `0${nameA}`;
5502
5589
  }
5503
- if (this._isCursorPagination) {
5504
- stateUpdate.cursor = { next: next || null, prev: prev || null };
5505
- stateUpdate.hasNext = !!next;
5506
- stateUpdate.hasPrev = !!prev;
5507
- } else {
5508
- stateUpdate.offset = (this.offset ?? 0) + items.length;
5509
- stateUpdate.hasNext = items.length === this.pageSize;
5590
+ if (nameB?.indexOf(searchQuery) === 0) {
5591
+ nameB = `0${nameB}`;
5510
5592
  }
5511
- stateUpdate.items = await this.filterQueryResults(items);
5512
- } catch (e) {
5513
- stateUpdate.lastQueryError = e;
5514
- } finally {
5515
- this.state.next(this.getStateAfterQuery(stateUpdate, isFirstPage));
5516
- }
5593
+ if (nameA != null && nameB != null) {
5594
+ if (nameA < nameB) {
5595
+ return -1;
5596
+ }
5597
+ if (nameA > nameB) {
5598
+ return 1;
5599
+ }
5600
+ }
5601
+ return 0;
5602
+ });
5603
+ return {
5604
+ items: selectedCommands.map((command) => ({
5605
+ ...command,
5606
+ id: command.name
5607
+ })),
5608
+ next: null
5609
+ };
5517
5610
  }
5518
- cancelScheduledQuery() {
5519
- this._executeQueryDebounced.cancel();
5611
+ filterQueryResults(items) {
5612
+ return items;
5520
5613
  }
5521
- resetState() {
5522
- this.state.next(this.initialState);
5614
+ };
5615
+ var DEFAULT_OPTIONS = { minChars: 1, trigger: "/" };
5616
+ var createCommandsMiddleware = (channel, options) => {
5617
+ const finalOptions = mergeWith(DEFAULT_OPTIONS, options ?? {});
5618
+ let searchSource = new CommandSearchSource(channel);
5619
+ if (options?.searchSource) {
5620
+ searchSource = options.searchSource;
5621
+ searchSource.resetState();
5523
5622
  }
5623
+ searchSource.activate();
5624
+ return {
5625
+ id: "stream-io/text-composer/commands-middleware",
5626
+ handlers: {
5627
+ onChange: ({ state, next, complete, forward }) => {
5628
+ if (!state.selection) return forward();
5629
+ const finalText = state.text.slice(0, state.selection.end);
5630
+ const commandName = getCompleteCommandInString(finalText);
5631
+ if (commandName) {
5632
+ const command = searchSource?.query(commandName).items[0];
5633
+ const composer = options?.composer;
5634
+ if (command && !composer?.isCommandDisabled(command)) {
5635
+ return next({
5636
+ ...state,
5637
+ command,
5638
+ suggestions: void 0
5639
+ });
5640
+ }
5641
+ }
5642
+ const triggerWithToken = getTriggerCharWithToken({
5643
+ trigger: finalOptions.trigger,
5644
+ text: finalText,
5645
+ acceptTrailingSpaces: false,
5646
+ isCommand: true
5647
+ });
5648
+ const newSearchTriggerred = triggerWithToken && triggerWithToken.length === finalOptions.minChars;
5649
+ if (newSearchTriggerred) {
5650
+ searchSource.resetStateAndActivate();
5651
+ }
5652
+ const triggerWasRemoved = !triggerWithToken || triggerWithToken.length < finalOptions.minChars;
5653
+ if (triggerWasRemoved) {
5654
+ const hasStaleSuggestions = state.suggestions?.trigger === finalOptions.trigger;
5655
+ const newState = { ...state };
5656
+ if (hasStaleSuggestions) {
5657
+ delete newState.suggestions;
5658
+ }
5659
+ return next(newState);
5660
+ }
5661
+ return complete({
5662
+ ...state,
5663
+ command: null,
5664
+ suggestions: {
5665
+ query: triggerWithToken.slice(1),
5666
+ searchSource,
5667
+ trigger: finalOptions.trigger
5668
+ }
5669
+ });
5670
+ },
5671
+ onSuggestionItemSelect: ({ state, next, forward }) => {
5672
+ const { selectedSuggestion } = state.change ?? {};
5673
+ if (!selectedSuggestion || state.suggestions?.trigger !== finalOptions.trigger)
5674
+ return forward();
5675
+ const composer = options?.composer;
5676
+ if (composer && notifyCommandDisabled(composer, selectedSuggestion)) {
5677
+ return forward();
5678
+ }
5679
+ searchSource.resetStateAndActivate();
5680
+ return next({
5681
+ ...state,
5682
+ ...insertItemWithTrigger({
5683
+ insertText: `/${selectedSuggestion.name} `,
5684
+ selection: state.selection,
5685
+ text: state.text,
5686
+ trigger: finalOptions.trigger
5687
+ }),
5688
+ command: selectedSuggestion,
5689
+ suggestions: void 0
5690
+ });
5691
+ }
5692
+ }
5693
+ };
5524
5694
  };
5525
5695
 
5526
- // src/pagination/FilterBuilder.ts
5527
- var FilterBuilder = class {
5528
- constructor(params) {
5529
- this.context = new StateStore(params?.initialContext ?? {});
5530
- this.filterConfig = new StateStore(
5531
- params?.initialFilterConfig ?? {}
5532
- );
5533
- }
5534
- updateFilterConfig(config) {
5535
- this.filterConfig.partialNext(config);
5696
+ // src/messageComposer/middleware/messageComposer/compositionValidation.ts
5697
+ var getCommandByName = (searchSource, commandName) => {
5698
+ if (!commandName) return;
5699
+ const normalizedCommandName = commandName.toLowerCase();
5700
+ return searchSource.query(normalizedCommandName).items.find((command) => command.name?.toLowerCase() === normalizedCommandName);
5701
+ };
5702
+ var getDisabledRawCommand = (composer, searchSource, text) => {
5703
+ const rawCommand = getCommandByName(searchSource, getRawCommandName(text));
5704
+ if (rawCommand && composer.isCommandDisabled(rawCommand)) {
5705
+ return rawCommand;
5536
5706
  }
5537
- enableFilter(filterKey) {
5538
- const config = this.filterConfig.getLatestValue();
5539
- if (config[filterKey]) {
5540
- this.filterConfig.partialNext({
5541
- [filterKey]: {
5542
- ...config[filterKey],
5543
- enabled: true
5707
+ };
5708
+ var createCompositionValidationMiddleware = (composer) => {
5709
+ const commandSearchSource = new CommandSearchSource(composer.channel);
5710
+ return {
5711
+ id: "stream-io/message-composer-middleware/data-validation",
5712
+ handlers: {
5713
+ compose: async ({
5714
+ state,
5715
+ discard,
5716
+ forward
5717
+ }) => {
5718
+ const { maxLengthOnSend } = composer.config.text ?? {};
5719
+ const inputText = state.message.text ?? "";
5720
+ const disabledRawCommand = getDisabledRawCommand(
5721
+ composer,
5722
+ commandSearchSource,
5723
+ inputText
5724
+ );
5725
+ if (disabledRawCommand) {
5726
+ notifyCommandDisabled(composer, disabledRawCommand);
5727
+ return await discard();
5544
5728
  }
5729
+ const hasExceededMaxLength = typeof maxLengthOnSend === "number" && inputText.length > maxLengthOnSend;
5730
+ if (composer.compositionIsEmpty || hasExceededMaxLength) {
5731
+ return await discard();
5732
+ }
5733
+ return await forward();
5734
+ }
5735
+ }
5736
+ };
5737
+ };
5738
+ var createDraftCompositionValidationMiddleware = (composer) => ({
5739
+ id: "stream-io/message-composer-middleware/draft-data-validation",
5740
+ handlers: {
5741
+ compose: async ({
5742
+ state,
5743
+ discard,
5744
+ forward
5745
+ }) => {
5746
+ const hasData = !textIsEmpty(state.draft.text ?? "") || state.draft.attachments?.length || state.draft.poll_id || state.draft.quoted_message_id;
5747
+ const shouldCreateDraft = composer.lastChangeOriginIsLocal && hasData;
5748
+ if (!shouldCreateDraft) {
5749
+ return await discard();
5750
+ }
5751
+ return await forward();
5752
+ }
5753
+ }
5754
+ });
5755
+
5756
+ // src/messageComposer/middleware/messageComposer/linkPreviews.ts
5757
+ var createLinkPreviewsCompositionMiddleware = (composer) => ({
5758
+ id: "stream-io/message-composer-middleware/link-previews",
5759
+ handlers: {
5760
+ compose: ({
5761
+ state,
5762
+ next,
5763
+ forward
5764
+ }) => {
5765
+ const { linkPreviewsManager } = composer;
5766
+ if (!linkPreviewsManager) return forward();
5767
+ linkPreviewsManager.cancelURLEnrichment();
5768
+ const someLinkPreviewsLoading = linkPreviewsManager.loadingPreviews.length > 0;
5769
+ const someLinkPreviewsDismissed = linkPreviewsManager.dismissedPreviews.length > 0;
5770
+ const linkPreviews = linkPreviewsManager.loadingPreviews.length > 0 ? [] : linkPreviewsManager.loadedPreviews.map(
5771
+ (preview) => LinkPreviewsManager.getPreviewData(preview)
5772
+ );
5773
+ const attachments = (state.message.attachments ?? []).concat(
5774
+ linkPreviews
5775
+ );
5776
+ if (!attachments.length) return forward();
5777
+ const sendOptions = { ...state.sendOptions };
5778
+ const skip_enrich_url = !someLinkPreviewsLoading && linkPreviews.length > 0 || someLinkPreviewsDismissed;
5779
+ if (skip_enrich_url) {
5780
+ sendOptions.skip_enrich_url = true;
5781
+ }
5782
+ return next({
5783
+ ...state,
5784
+ message: {
5785
+ ...state.message,
5786
+ attachments
5787
+ },
5788
+ localMessage: {
5789
+ ...state.localMessage,
5790
+ attachments
5791
+ },
5792
+ sendOptions
5545
5793
  });
5546
5794
  }
5547
5795
  }
5548
- disableFilter(filterKey) {
5549
- const config = this.filterConfig.getLatestValue();
5550
- if (config[filterKey]) {
5551
- this.filterConfig.partialNext({
5552
- [filterKey]: {
5553
- ...config[filterKey],
5554
- enabled: false
5796
+ });
5797
+ var createDraftLinkPreviewsCompositionMiddleware = (composer) => ({
5798
+ id: "stream-io/message-composer-middleware/draft-link-previews",
5799
+ handlers: {
5800
+ compose: ({
5801
+ state,
5802
+ next,
5803
+ forward
5804
+ }) => {
5805
+ const { linkPreviewsManager } = composer;
5806
+ if (!linkPreviewsManager) return forward();
5807
+ linkPreviewsManager.cancelURLEnrichment();
5808
+ const linkPreviews = linkPreviewsManager.loadedPreviews.map(
5809
+ (preview) => LinkPreviewsManager.getPreviewData(preview)
5810
+ );
5811
+ if (!linkPreviews.length) return forward();
5812
+ return next({
5813
+ ...state,
5814
+ draft: {
5815
+ ...state.draft,
5816
+ attachments: (state.draft.attachments ?? []).concat(linkPreviews)
5555
5817
  }
5556
5818
  });
5557
5819
  }
5558
5820
  }
5559
- updateContext(newContext) {
5560
- this.context.partialNext(newContext);
5561
- }
5562
- buildFilters(params) {
5563
- const filters = {
5564
- ...params?.baseFilters ?? {}
5565
- };
5566
- const filterConfig = this.filterConfig.getLatestValue();
5567
- for (const key in filterConfig) {
5568
- const configItem = filterConfig[key];
5569
- if (!configItem?.enabled) continue;
5570
- const generated = configItem.generate({
5571
- ...this.context.getLatestValue(),
5572
- ...params?.context ?? {}
5573
- });
5574
- if (generated) Object.assign(filters, generated);
5575
- }
5576
- return filters;
5577
- }
5578
- };
5821
+ });
5579
5822
 
5580
- // src/pagination/ReminderPaginator.ts
5581
- var ReminderPaginator = class extends BasePaginator {
5582
- constructor(client, options) {
5583
- super(options);
5584
- this.query = async ({
5585
- direction
5823
+ // src/messageComposer/middleware/messageComposer/textComposer.ts
5824
+ var createTextComposerCompositionMiddleware = (composer) => ({
5825
+ id: "stream-io/message-composer-middleware/text-composition",
5826
+ handlers: {
5827
+ compose: ({
5828
+ state,
5829
+ next,
5830
+ forward
5586
5831
  }) => {
5587
- const cursor = this.cursor?.[direction];
5588
- const {
5589
- reminders: items,
5590
- next,
5591
- prev
5592
- } = await this.client.queryReminders({
5593
- filter: this.filters,
5594
- sort: this.sort,
5595
- limit: this.pageSize,
5596
- [direction]: cursor
5832
+ if (!composer.textComposer) return forward();
5833
+ const { mentionedUsers, text } = composer.textComposer;
5834
+ const mentioned_users = Array.from(
5835
+ new Set(
5836
+ mentionedUsers.filter(
5837
+ ({ id, name }) => text.includes(`@${id}`) || text.includes(`@${name}`)
5838
+ )
5839
+ )
5840
+ );
5841
+ if (!text && mentioned_users.length === 0) return forward();
5842
+ return next({
5843
+ ...state,
5844
+ localMessage: {
5845
+ ...state.localMessage,
5846
+ mentioned_users,
5847
+ text
5848
+ },
5849
+ message: {
5850
+ ...state.message,
5851
+ mentioned_users: mentioned_users.map((u) => u.id),
5852
+ text
5853
+ }
5597
5854
  });
5598
- return { items, next, prev };
5599
- };
5600
- this.filterQueryResults = (items) => items;
5601
- this.client = client;
5602
- }
5603
- get filters() {
5604
- return this._filters;
5605
- }
5606
- get sort() {
5607
- return this._sort;
5608
- }
5609
- set filters(filters) {
5610
- this._filters = filters;
5611
- this.resetState();
5612
- }
5613
- set sort(sort) {
5614
- this._sort = sort;
5615
- this.resetState();
5855
+ }
5616
5856
  }
5617
- };
5618
-
5619
- // src/search/UserSearchSource.ts
5620
- var UserSearchSource = class extends BaseSearchSource {
5621
- constructor(client, options, filterBuilderOptions = {}) {
5622
- super(options);
5623
- this.type = "users";
5624
- this.client = client;
5625
- this.filterBuilder = new FilterBuilder({
5626
- initialFilterConfig: {
5627
- $or: {
5628
- enabled: true,
5629
- generate: ({ searchQuery }) => searchQuery ? {
5630
- $or: [
5631
- { id: { $autocomplete: searchQuery } },
5632
- { name: { $autocomplete: searchQuery } }
5633
- ]
5634
- } : null
5857
+ });
5858
+ var createDraftTextComposerCompositionMiddleware = (composer) => ({
5859
+ id: "stream-io/message-composer-middleware/draft-text-composition",
5860
+ handlers: {
5861
+ compose: ({
5862
+ state,
5863
+ next,
5864
+ forward
5865
+ }) => {
5866
+ if (!composer.textComposer) return forward();
5867
+ const { maxLengthOnSend } = composer.config.text ?? {};
5868
+ const { mentionedUsers, text: inputText } = composer.textComposer;
5869
+ const mentioned_users = mentionedUsers.length ? Array.from(
5870
+ new Set(
5871
+ mentionedUsers.filter(
5872
+ ({ id, name }) => inputText.includes(`@${id}`) || inputText.includes(`@${name}`)
5873
+ )
5874
+ )
5875
+ ) : void 0;
5876
+ const text = typeof maxLengthOnSend === "number" && inputText.length > maxLengthOnSend ? inputText.slice(0, maxLengthOnSend) : inputText;
5877
+ return next({
5878
+ ...state,
5879
+ draft: {
5880
+ ...state.draft,
5881
+ mentioned_users: mentioned_users?.map((u) => u.id),
5882
+ text
5635
5883
  }
5636
- },
5637
- ...filterBuilderOptions
5638
- });
5639
- }
5640
- async query(searchQuery) {
5641
- const filters = this.filterBuilder.buildFilters({
5642
- baseFilters: this.filters,
5643
- context: { searchQuery }
5644
- });
5645
- const sort = { id: 1, ...this.sort };
5646
- const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };
5647
- const { users } = await this.client.queryUsers(filters, sort, options);
5648
- return { items: users };
5649
- }
5650
- filterQueryResults(items) {
5651
- return items.filter((u) => u.id !== this.client.user?.id);
5652
- }
5653
- };
5654
-
5655
- // src/search/ChannelSearchSource.ts
5656
- var ChannelSearchSource = class extends BaseSearchSource {
5657
- constructor(client, options, filterBuilderOptions = {}) {
5658
- super(options);
5659
- this.type = "channels";
5660
- this.client = client;
5661
- this.filterBuilder = new FilterBuilder({
5662
- ...filterBuilderOptions,
5663
- initialFilterConfig: {
5664
- name: {
5665
- enabled: true,
5666
- generate: ({ searchQuery }) => searchQuery ? { name: { $autocomplete: searchQuery } } : null
5667
- },
5668
- ...filterBuilderOptions.initialFilterConfig
5669
- }
5670
- });
5671
- }
5672
- async query(searchQuery) {
5673
- const filters = this.filterBuilder.buildFilters({
5674
- baseFilters: {
5675
- ...this.client.userID ? { members: { $in: [this.client.userID] } } : {},
5676
- ...this.filters
5677
- },
5678
- context: { searchQuery }
5679
- });
5680
- const sort = this.sort ?? {};
5681
- const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };
5682
- const items = await this.client.queryChannels(filters, sort, options);
5683
- return { items };
5684
- }
5685
- filterQueryResults(items) {
5686
- return items;
5884
+ });
5885
+ }
5687
5886
  }
5688
- };
5887
+ });
5689
5888
 
5690
- // src/search/MessageSearchSource.ts
5691
- var MessageSearchSource = class extends BaseSearchSource {
5692
- constructor(client, options, filterBuilderOptions) {
5693
- super(options);
5694
- this.type = "messages";
5695
- this.client = client;
5696
- this.messageSearchChannelFilterBuilder = new FilterBuilder(filterBuilderOptions?.messageSearchChannel);
5697
- this.messageSearchFilterBuilder = new FilterBuilder({
5698
- ...filterBuilderOptions?.messageSearch,
5699
- initialFilterConfig: {
5700
- text: {
5701
- enabled: true,
5702
- generate: ({ searchQuery }) => searchQuery ? { text: searchQuery } : null
5703
- },
5704
- ...filterBuilderOptions?.messageSearch?.initialFilterConfig
5889
+ // src/messageComposer/middleware/messageComposer/messageComposerState.ts
5890
+ var createMessageComposerStateCompositionMiddleware = (composer) => ({
5891
+ id: "stream-io/message-composer-middleware/own-state",
5892
+ handlers: {
5893
+ compose: ({
5894
+ state,
5895
+ next
5896
+ }) => {
5897
+ const payload = {};
5898
+ if (composer.quotedMessage) {
5899
+ payload.quoted_message_id = composer.quotedMessage.id;
5705
5900
  }
5706
- });
5707
- this.channelQueryFilterBuilder = new FilterBuilder({
5708
- ...filterBuilderOptions?.channelQuery,
5709
- initialFilterConfig: {
5710
- cid: {
5711
- enabled: true,
5712
- generate: ({ cids }) => cids ? { cid: { $in: cids } } : null
5713
- },
5714
- ...filterBuilderOptions?.channelQuery?.initialFilterConfig
5901
+ if (composer.pollId) {
5902
+ payload.poll_id = composer.pollId;
5715
5903
  }
5716
- });
5904
+ if (composer.showReplyInChannel) {
5905
+ payload.show_in_channel = true;
5906
+ }
5907
+ return next({
5908
+ ...state,
5909
+ localMessage: {
5910
+ ...state.localMessage,
5911
+ ...payload,
5912
+ quoted_message: composer.quotedMessage ?? void 0
5913
+ },
5914
+ message: {
5915
+ ...state.message,
5916
+ ...payload
5917
+ }
5918
+ });
5919
+ }
5717
5920
  }
5718
- async query(searchQuery) {
5719
- if (!this.client.userID || !searchQuery || this.next === null) return { items: [] };
5720
- const channelFilters = this.messageSearchChannelFilterBuilder.buildFilters({
5721
- baseFilters: {
5722
- ...this.client.userID ? { members: { $in: [this.client.userID] } } : {},
5723
- ...this.messageSearchChannelFilters
5724
- },
5725
- context: { searchQuery }
5726
- });
5727
- const messageFilters = this.messageSearchFilterBuilder.buildFilters({
5728
- baseFilters: {
5729
- type: "regular",
5730
- ...this.messageSearchFilters
5731
- },
5732
- context: { searchQuery }
5733
- });
5734
- const sort = {
5735
- created_at: -1,
5736
- ...this.messageSearchSort
5737
- };
5738
- const options = {
5739
- limit: this.pageSize,
5740
- next: this.next,
5741
- sort
5742
- };
5743
- const { next, results } = await this.client.search(
5744
- channelFilters,
5745
- messageFilters,
5746
- options
5747
- );
5748
- const items = results.map(({ message }) => message);
5749
- const cids = Array.from(
5750
- items.reduce((acc, message) => {
5751
- if (message.cid && !this.client.activeChannels[message.cid]) acc.add(message.cid);
5752
- return acc;
5753
- }, /* @__PURE__ */ new Set())
5754
- );
5755
- if (cids.length > 0) {
5756
- const channelQueryFilters = this.channelQueryFilterBuilder.buildFilters({
5757
- baseFilters: this.channelQueryFilters,
5758
- context: { cids }
5921
+ });
5922
+ var createDraftMessageComposerStateCompositionMiddleware = (composer) => ({
5923
+ id: "stream-io/message-composer-middleware/draft-own-state",
5924
+ handlers: {
5925
+ compose: ({
5926
+ state,
5927
+ next
5928
+ }) => {
5929
+ const payload = {};
5930
+ if (composer.quotedMessage) {
5931
+ payload.quoted_message_id = composer.quotedMessage.id;
5932
+ }
5933
+ if (composer.pollId) {
5934
+ payload.poll_id = composer.pollId;
5935
+ }
5936
+ if (composer.showReplyInChannel) {
5937
+ payload.show_in_channel = true;
5938
+ }
5939
+ return next({
5940
+ ...state,
5941
+ draft: {
5942
+ ...state.draft,
5943
+ ...payload
5944
+ }
5759
5945
  });
5760
- await this.client.queryChannels(
5761
- channelQueryFilters,
5762
- {
5763
- last_message_at: -1,
5764
- ...this.channelQuerySort
5765
- },
5766
- this.channelQueryOptions
5767
- );
5768
5946
  }
5769
- return { items, next };
5770
5947
  }
5771
- filterQueryResults(items) {
5772
- return items;
5948
+ });
5949
+
5950
+ // src/messageComposer/middleware/messageComposer/userDataInjection.ts
5951
+ var createUserDataInjectionMiddleware = (composer) => ({
5952
+ id: "stream-io/message-composer-middleware/user-data-injection",
5953
+ handlers: {
5954
+ compose: ({
5955
+ state,
5956
+ next,
5957
+ forward
5958
+ }) => {
5959
+ if (!composer.client.user) {
5960
+ return forward();
5961
+ }
5962
+ const { channel_mutes, devices, mutes, ...messageUser } = composer.client.user;
5963
+ return next({
5964
+ ...state,
5965
+ localMessage: {
5966
+ ...state.localMessage,
5967
+ user: messageUser,
5968
+ user_id: messageUser.id
5969
+ }
5970
+ });
5971
+ }
5773
5972
  }
5774
- };
5973
+ });
5775
5974
 
5776
- // src/messageComposer/middleware/textComposer/textMiddlewareUtils.ts
5777
- var getTriggerCharWithToken = ({
5778
- trigger,
5779
- text,
5780
- isCommand = false,
5781
- acceptTrailingSpaces = true
5782
- }) => {
5783
- const escapedTrigger = escapeRegExp(trigger);
5784
- const triggerNorWhitespace = `[^\\s${escapedTrigger}]*`;
5785
- const match = text.match(
5786
- new RegExp(
5787
- isCommand ? `^[${escapedTrigger}]${triggerNorWhitespace}$` : acceptTrailingSpaces ? `(?!^|\\W)?[${escapedTrigger}]${triggerNorWhitespace}\\s?${triggerNorWhitespace}$` : `(?!^|\\W)?[${escapedTrigger}]${triggerNorWhitespace}$`,
5788
- "g"
5789
- )
5790
- );
5791
- return match && match[match.length - 1].trim();
5792
- };
5793
- var getCompleteCommandInString = (text) => {
5794
- const match = text.match(/^\/(\S+)\s+.*/);
5795
- const commandName = match && match[1];
5796
- return commandName;
5975
+ // src/messageComposer/middleware/messageComposer/pollOnly.ts
5976
+ var pollLocalMessageNullifiedFields = {
5977
+ attachments: [],
5978
+ mentioned_users: [],
5979
+ parent_id: void 0,
5980
+ quoted_message: void 0,
5981
+ text: ""
5797
5982
  };
5798
- var insertItemWithTrigger = ({
5799
- insertText,
5800
- selection,
5801
- text,
5802
- trigger
5803
- }) => {
5804
- const beforeCursor = text.slice(0, selection.end);
5805
- const afterCursor = text.slice(selection.end);
5806
- const lastIndex = beforeCursor.lastIndexOf(trigger);
5807
- const newText = beforeCursor.slice(0, lastIndex) + insertText + afterCursor;
5808
- return {
5809
- text: newText,
5810
- selection: {
5811
- start: lastIndex + insertText.length,
5812
- end: lastIndex + insertText.length
5983
+ var createPollOnlyCompositionMiddleware = (composer) => ({
5984
+ id: "stream-io/message-composer-middleware/poll-only",
5985
+ handlers: {
5986
+ compose: ({
5987
+ state,
5988
+ complete,
5989
+ forward
5990
+ }) => {
5991
+ const pollId = composer.pollId;
5992
+ const isEditingMessage = !!composer.editedMessage;
5993
+ const isComposingThreadReply = !!composer.threadId;
5994
+ if (!pollId || isComposingThreadReply || isEditingMessage) return forward();
5995
+ return complete({
5996
+ ...state,
5997
+ localMessage: {
5998
+ ...state.localMessage,
5999
+ ...pollLocalMessageNullifiedFields,
6000
+ poll_id: pollId
6001
+ },
6002
+ message: {
6003
+ id: state.localMessage.id,
6004
+ poll_id: pollId
6005
+ }
6006
+ });
6007
+ }
6008
+ }
6009
+ });
6010
+
6011
+ // src/messageComposer/middleware/messageComposer/sharedLocation.ts
6012
+ var createSharedLocationCompositionMiddleware = (composer) => ({
6013
+ id: "stream-io/message-composer-middleware/shared-location",
6014
+ handlers: {
6015
+ compose: ({
6016
+ state,
6017
+ next,
6018
+ forward
6019
+ }) => {
6020
+ const { locationComposer } = composer;
6021
+ const location = locationComposer.validLocation;
6022
+ if (!locationComposer || !location || !composer.client.user) return forward();
6023
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
6024
+ return next({
6025
+ ...state,
6026
+ localMessage: {
6027
+ ...state.localMessage,
6028
+ shared_location: {
6029
+ ...location,
6030
+ channel_cid: composer.channel.cid,
6031
+ created_at: timestamp,
6032
+ updated_at: timestamp,
6033
+ user_id: composer.client.user.id
6034
+ }
6035
+ },
6036
+ message: {
6037
+ ...state.message,
6038
+ shared_location: location
6039
+ }
6040
+ });
5813
6041
  }
5814
- };
5815
- };
5816
- var replaceWordWithEntity = async ({
5817
- caretPosition,
5818
- getEntityString,
5819
- text
5820
- }) => {
5821
- const lastWordRegex = /([^\s]+)(\s*)$/;
5822
- const match = lastWordRegex.exec(text.slice(0, caretPosition));
5823
- if (!match) return text;
5824
- const lastWord = match[1];
5825
- if (!lastWord) return text;
5826
- const spaces = match[2];
5827
- const newWord = await getEntityString(lastWord);
5828
- if (newWord == null) return text;
5829
- const textBeforeWord = text.slice(0, caretPosition - match[0].length);
5830
- const textAfterCaret = text.slice(caretPosition, -1);
5831
- return textBeforeWord + newWord + spaces + textAfterCaret;
5832
- };
5833
- function escapeRegExp(text) {
5834
- return text.replace(/[-[\]{}()*+?.,/\\^$|#]/g, "\\$&");
5835
- }
5836
- var getTokenizedSuggestionDisplayName = ({
5837
- displayName,
5838
- searchToken
5839
- }) => ({
5840
- tokenizedDisplayName: {
5841
- token: searchToken,
5842
- parts: searchToken ? displayName.split(new RegExp(`(${escapeRegExp(searchToken)})`, "gi")).filter(Boolean) : [displayName]
5843
6042
  }
5844
6043
  });
5845
6044
 
5846
- // src/messageComposer/middleware/textComposer/commands.ts
5847
- var CommandSearchSource = class extends BaseSearchSourceSync {
5848
- constructor(channel, options) {
5849
- super(options);
5850
- this.type = "commands";
5851
- this.canExecuteQuery = (newSearchString) => {
5852
- const hasNewSearchQuery = typeof newSearchString !== "undefined";
5853
- return this.isActive && !this.isLoading && (this.hasNext || hasNewSearchQuery);
5854
- };
5855
- this.channel = channel;
6045
+ // src/messageComposer/middleware/messageComposer/MessageComposerMiddlewareExecutor.ts
6046
+ var MessageComposerMiddlewareExecutor = class extends MiddlewareExecutor {
6047
+ constructor({ composer }) {
6048
+ super();
6049
+ this.use([
6050
+ createUserDataInjectionMiddleware(composer),
6051
+ createPollOnlyCompositionMiddleware(composer),
6052
+ createTextComposerCompositionMiddleware(composer),
6053
+ createAttachmentsCompositionMiddleware(composer),
6054
+ createLinkPreviewsCompositionMiddleware(composer),
6055
+ createSharedLocationCompositionMiddleware(composer),
6056
+ createMessageComposerStateCompositionMiddleware(composer),
6057
+ createCustomDataCompositionMiddleware(composer),
6058
+ createCompositionValidationMiddleware(composer),
6059
+ createCompositionDataCleanupMiddleware(composer)
6060
+ ]);
5856
6061
  }
5857
- getStateBeforeFirstQuery(newSearchString) {
5858
- const newState = super.getStateBeforeFirstQuery(newSearchString);
5859
- const { items } = this.state.getLatestValue();
5860
- return {
5861
- ...newState,
5862
- items
5863
- // preserve items to avoid flickering
5864
- };
6062
+ };
6063
+ var MessageDraftComposerMiddlewareExecutor = class extends MiddlewareExecutor {
6064
+ constructor({ composer }) {
6065
+ super();
6066
+ this.use([
6067
+ createDraftTextComposerCompositionMiddleware(composer),
6068
+ createDraftAttachmentsCompositionMiddleware(composer),
6069
+ createDraftLinkPreviewsCompositionMiddleware(composer),
6070
+ createDraftMessageComposerStateCompositionMiddleware(composer),
6071
+ createDraftCustomDataCompositionMiddleware(composer),
6072
+ createDraftCompositionValidationMiddleware(composer)
6073
+ ]);
5865
6074
  }
5866
- query(searchQuery) {
5867
- const channelConfig = this.channel.getConfig();
5868
- const commands = channelConfig?.commands || [];
5869
- const selectedCommands = commands.filter(
5870
- (command) => !!(command.name && command.name.toLowerCase().indexOf(searchQuery.toLowerCase()) !== -1)
5871
- );
5872
- selectedCommands.sort((a, b) => {
5873
- let nameA = a.name?.toLowerCase();
5874
- let nameB = b.name?.toLowerCase();
5875
- if (nameA?.indexOf(searchQuery) === 0) {
5876
- nameA = `0${nameA}`;
5877
- }
5878
- if (nameB?.indexOf(searchQuery) === 0) {
5879
- nameB = `0${nameB}`;
6075
+ };
6076
+
6077
+ // src/messageComposer/middleware/messageComposer/commandInjection.ts
6078
+ var createCommandInjectionMiddleware = (composer) => ({
6079
+ handlers: {
6080
+ compose: ({
6081
+ forward,
6082
+ next,
6083
+ state
6084
+ }) => {
6085
+ const command = composer.textComposer.command;
6086
+ if (!command) {
6087
+ return forward();
5880
6088
  }
5881
- if (nameA != null && nameB != null) {
5882
- if (nameA < nameB) {
5883
- return -1;
6089
+ const { text } = state.localMessage;
6090
+ const injection = `/${command?.name}`;
6091
+ const enrichedText = `${injection} ${text}`;
6092
+ return next({
6093
+ ...state,
6094
+ localMessage: {
6095
+ ...state.localMessage,
6096
+ text: enrichedText
6097
+ },
6098
+ message: {
6099
+ ...state.message,
6100
+ text: enrichedText
5884
6101
  }
5885
- if (nameA > nameB) {
5886
- return 1;
6102
+ });
6103
+ }
6104
+ },
6105
+ id: "stream-io/message-composer-middleware/command-string-injection"
6106
+ });
6107
+ var createDraftCommandInjectionMiddleware = (composer) => ({
6108
+ handlers: {
6109
+ compose: ({
6110
+ forward,
6111
+ next,
6112
+ state
6113
+ }) => {
6114
+ const command = composer.textComposer.command;
6115
+ if (!command) {
6116
+ return forward();
6117
+ }
6118
+ const { text } = state.draft;
6119
+ const injection = `/${command?.name}`;
6120
+ const enrichedText = `${injection} ${text}`;
6121
+ return next({
6122
+ ...state,
6123
+ draft: {
6124
+ ...state.draft,
6125
+ text: enrichedText
5887
6126
  }
6127
+ });
6128
+ }
6129
+ },
6130
+ id: "stream-io/message-composer-middleware/draft-command-string-injection"
6131
+ });
6132
+
6133
+ // src/messageComposer/middleware/textComposer/activeCommandGuard.ts
6134
+ var createActiveCommandGuardMiddleware = () => ({
6135
+ handlers: {
6136
+ onChange: ({ complete, forward, state }) => {
6137
+ if (state.command) {
6138
+ return complete(state);
5888
6139
  }
5889
- return 0;
5890
- });
5891
- return {
5892
- items: selectedCommands.map((c) => ({ ...c, id: c.name })),
5893
- next: null
5894
- };
5895
- }
5896
- filterQueryResults(items) {
5897
- return items;
5898
- }
6140
+ return forward();
6141
+ },
6142
+ onSuggestionItemSelect: ({ forward }) => forward()
6143
+ },
6144
+ id: "stream-io/text-composer/active-command-guard"
6145
+ });
6146
+
6147
+ // src/messageComposer/middleware/textComposer/commandEffects.ts
6148
+ var emptyCommandStateToRestore = {
6149
+ selection: { start: 0, end: 0 },
6150
+ text: ""
5899
6151
  };
5900
- var DEFAULT_OPTIONS = { minChars: 1, trigger: "/" };
5901
- var createCommandsMiddleware = (channel, options) => {
5902
- const finalOptions = mergeWith(DEFAULT_OPTIONS, options ?? {});
5903
- let searchSource = new CommandSearchSource(channel);
5904
- if (options?.searchSource) {
5905
- searchSource = options.searchSource;
5906
- searchSource.resetState();
5907
- }
5908
- searchSource.activate();
5909
- return {
5910
- id: "stream-io/text-composer/commands-middleware",
5911
- handlers: {
5912
- onChange: ({ state, next, complete, forward }) => {
5913
- if (!state.selection) return forward();
5914
- const finalText = state.text.slice(0, state.selection.end);
5915
- const commandName = getCompleteCommandInString(finalText);
5916
- if (commandName) {
5917
- const command = searchSource?.query(commandName).items[0];
5918
- if (command) {
5919
- return next({
5920
- ...state,
5921
- command,
5922
- suggestions: void 0
5923
- });
5924
- }
5925
- }
5926
- const triggerWithToken = getTriggerCharWithToken({
5927
- trigger: finalOptions.trigger,
5928
- text: finalText,
5929
- acceptTrailingSpaces: false,
5930
- isCommand: true
5931
- });
5932
- const newSearchTriggerred = triggerWithToken && triggerWithToken.length === finalOptions.minChars;
5933
- if (newSearchTriggerred) {
5934
- searchSource.resetStateAndActivate();
5935
- }
5936
- const triggerWasRemoved = !triggerWithToken || triggerWithToken.length < finalOptions.minChars;
5937
- if (triggerWasRemoved) {
5938
- const hasStaleSuggestions = state.suggestions?.trigger === finalOptions.trigger;
5939
- const newState = { ...state };
5940
- if (hasStaleSuggestions) {
5941
- delete newState.suggestions;
5942
- }
5943
- return next(newState);
5944
- }
5945
- return complete({
5946
- ...state,
5947
- command: null,
5948
- suggestions: {
5949
- query: triggerWithToken.slice(1),
5950
- searchSource,
5951
- trigger: finalOptions.trigger
5952
- }
5953
- });
5954
- },
5955
- onSuggestionItemSelect: ({ state, next, forward }) => {
5956
- const { selectedSuggestion } = state.change ?? {};
5957
- if (!selectedSuggestion || state.suggestions?.trigger !== finalOptions.trigger)
5958
- return forward();
5959
- searchSource.resetStateAndActivate();
5960
- return next({
5961
- ...state,
5962
- ...insertItemWithTrigger({
5963
- insertText: `/${selectedSuggestion.name} `,
5964
- selection: state.selection,
5965
- text: state.text,
5966
- trigger: finalOptions.trigger
5967
- }),
5968
- command: selectedSuggestion,
5969
- suggestions: void 0
5970
- });
6152
+ var createCommandActivationEffect = (command) => ({
6153
+ command,
6154
+ stateToRestore: emptyCommandStateToRestore,
6155
+ type: "command.activate"
6156
+ });
6157
+ var isCommandResponse = (suggestion) => typeof suggestion?.name === "string";
6158
+ var createCommandEffectsMiddleware = () => ({
6159
+ handlers: {
6160
+ onChange: ({ forward }) => forward(),
6161
+ onSuggestionItemSelect: ({ state, next, forward }) => {
6162
+ const { selectedSuggestion } = state.change ?? {};
6163
+ if (!isCommandResponse(selectedSuggestion) || !state.command || state.command.name !== selectedSuggestion.name) {
6164
+ return forward();
5971
6165
  }
6166
+ return next({
6167
+ ...state,
6168
+ effects: [...state.effects ?? [], createCommandActivationEffect(state.command)]
6169
+ });
5972
6170
  }
5973
- };
5974
- };
6171
+ },
6172
+ id: "stream-io/text-composer/command-effects-middleware"
6173
+ });
5975
6174
 
5976
6175
  // src/messageComposer/middleware/textComposer/commandStringExtraction.ts
5977
- var stripCommandFromText = (text, commandName) => text.replace(new RegExp(`^${escapeRegExp(`/${commandName}`)}\\s*`), "");
5978
6176
  var createCommandStringExtractionMiddleware = () => ({
5979
6177
  handlers: {
5980
6178
  onChange: ({ complete, forward, state }) => {
@@ -6314,7 +6512,10 @@ var TextComposerMiddlewareExecutor = class extends MiddlewareExecutor {
6314
6512
  this.use([
6315
6513
  createTextComposerPreValidationMiddleware(composer),
6316
6514
  createMentionsMiddleware(composer.channel),
6317
- createCommandsMiddleware(composer.channel)
6515
+ createCommandsMiddleware(composer.channel, {
6516
+ composer
6517
+ }),
6518
+ createCommandEffectsMiddleware()
6318
6519
  ]);
6319
6520
  }
6320
6521
  async execute({
@@ -6363,6 +6564,10 @@ var TextComposer = class {
6363
6564
  this.initState = ({ message } = {}) => {
6364
6565
  this.state.next(initState5({ composer: this.composer, message }));
6365
6566
  };
6567
+ this.getSnapshot = (state = this.state.getLatestValue()) => state;
6568
+ this.restoreSnapshot = (snapshot) => {
6569
+ this.state.next(snapshot);
6570
+ };
6366
6571
  this.upsertMentionedUser = (user) => {
6367
6572
  const mentionedUsers = [...this.mentionedUsers];
6368
6573
  const existingUserIndex = mentionedUsers.findIndex((u) => u.id === user.id);
@@ -6383,8 +6588,27 @@ var TextComposer = class {
6383
6588
  this.state.partialNext({ mentionedUsers });
6384
6589
  };
6385
6590
  this.setCommand = (command) => {
6386
- if (command?.name === this.command?.name) return;
6387
- this.state.partialNext({ command });
6591
+ if (!command) {
6592
+ this.clearCommand();
6593
+ return;
6594
+ }
6595
+ if (command.name === this.command?.name) return;
6596
+ if (this.composer.isCommandDisabled(command)) return;
6597
+ const stateToRestore = {
6598
+ command: null
6599
+ };
6600
+ this.commitState({
6601
+ ...this.state.getLatestValue(),
6602
+ command,
6603
+ effects: [
6604
+ {
6605
+ command,
6606
+ stateToRestore,
6607
+ type: "command.activate"
6608
+ }
6609
+ ],
6610
+ suggestions: void 0
6611
+ });
6388
6612
  };
6389
6613
  this.setText = (text) => {
6390
6614
  if (!this.enabled || text === this.text) return;
@@ -6451,6 +6675,12 @@ var TextComposer = class {
6451
6675
  this.state.partialNext({ suggestions: void 0 });
6452
6676
  };
6453
6677
  // --- END STATE API ---
6678
+ this.commitState = (state) => {
6679
+ const { change, effects, ...nextState } = state;
6680
+ void change;
6681
+ this.state.next(nextState);
6682
+ this.composer.applyEffects(effects);
6683
+ };
6454
6684
  // --- START TEXT PROCESSING ----
6455
6685
  this.handleChange = async ({
6456
6686
  text,
@@ -6466,7 +6696,7 @@ var TextComposer = class {
6466
6696
  }
6467
6697
  });
6468
6698
  if (output.status === "discard") return;
6469
- this.state.next(output.state);
6699
+ this.commitState(output.state);
6470
6700
  if (this.config.publishTypingEvents && text) {
6471
6701
  logChatPromiseExecution(
6472
6702
  this.channel.keystroke(this.composer.threadId ?? void 0),
@@ -6487,7 +6717,7 @@ var TextComposer = class {
6487
6717
  }
6488
6718
  });
6489
6719
  if (output?.status === "discard") return;
6490
- this.state.next(output.state);
6720
+ this.commitState(output.state);
6491
6721
  };
6492
6722
  this.composer = composer;
6493
6723
  this.state = new StateStore(initState5({ composer, message }));
@@ -6557,7 +6787,12 @@ var TextComposer = class {
6557
6787
  this.state.partialNext({ mentionedUsers: users });
6558
6788
  }
6559
6789
  clearCommand() {
6560
- this.state.partialNext({ command: null });
6790
+ if (!this.command) return;
6791
+ this.commitState({
6792
+ ...this.state.getLatestValue(),
6793
+ command: null,
6794
+ effects: [{ type: "command.clear" }]
6795
+ });
6561
6796
  }
6562
6797
  // --- END TEXT PROCESSING ----
6563
6798
  };
@@ -7048,15 +7283,28 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
7048
7283
  client
7049
7284
  }) {
7050
7285
  super();
7286
+ this.snapshots = [];
7051
7287
  this.setEditedMessage = (editedMessage) => {
7052
7288
  this.state.partialNext({ editedMessage: editedMessage ?? null });
7289
+ if (editedMessage) {
7290
+ this.textComposer.clearCommand();
7291
+ }
7292
+ };
7293
+ this.getCommandDisabledReason = (command) => {
7294
+ if (this.editedMessage) return "editing";
7295
+ if (this.quotedMessage && (command.set === "moderation_set" || command.name === "moderation_set")) {
7296
+ return "quoted_message";
7297
+ }
7298
+ return void 0;
7053
7299
  };
7300
+ this.isCommandDisabled = (command) => !!this.getCommandDisabledReason(command);
7054
7301
  this.refreshId = () => {
7055
7302
  this.state.partialNext({ id: _MessageComposer.generateId() });
7056
7303
  };
7057
7304
  this.initState = ({
7058
7305
  composition
7059
7306
  } = {}) => {
7307
+ this.clearSnapshots();
7060
7308
  this.editingAuditState.partialNext(this.initEditingAuditState(composition));
7061
7309
  const message = typeof composition === "undefined" ? composition : compositionIsDraftResponse(composition) ? composition.message : formatMessage(composition);
7062
7310
  this.attachmentManager.initState({ message });
@@ -7086,6 +7334,36 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
7086
7334
  }
7087
7335
  };
7088
7336
  this.initEditingAuditState = (composition) => initEditingAuditState(composition);
7337
+ this.clearSnapshots = () => {
7338
+ this.snapshots = [];
7339
+ };
7340
+ this.getSnapshot = () => ({
7341
+ attachmentManager: this.attachmentManager.getSnapshot(),
7342
+ customDataManager: this.customDataManager.getSnapshot(),
7343
+ linkPreviewsManager: this.linkPreviewsManager.getSnapshot(),
7344
+ locationComposer: this.locationComposer.getSnapshot(),
7345
+ pollComposer: this.pollComposer.getSnapshot(),
7346
+ textComposer: this.textComposer.getSnapshot()
7347
+ });
7348
+ this.restoreSnapshot = (snapshot) => {
7349
+ this.attachmentManager.restoreSnapshot(snapshot.attachmentManager);
7350
+ this.linkPreviewsManager.restoreSnapshot(snapshot.linkPreviewsManager);
7351
+ this.locationComposer.restoreSnapshot(snapshot.locationComposer);
7352
+ this.pollComposer.restoreSnapshot(snapshot.pollComposer);
7353
+ this.customDataManager.restoreSnapshot(snapshot.customDataManager);
7354
+ this.textComposer.restoreSnapshot(snapshot.textComposer);
7355
+ };
7356
+ this.captureSnapshot = (snapshot = this.getSnapshot()) => {
7357
+ if (this.snapshots.length) return;
7358
+ this.snapshots.push(snapshot);
7359
+ };
7360
+ this.popSnapshot = () => this.snapshots.pop();
7361
+ this.registerEffectHandler = (type, handler) => {
7362
+ this.effectHandlers.registerEffectHandler(type, handler);
7363
+ };
7364
+ this.applyEffects = (effects = []) => {
7365
+ this.effectHandlers.applyEffects(effects);
7366
+ };
7089
7367
  this.registerDraftEventSubscriptions = () => {
7090
7368
  const unsubscribeDraftUpdated = this.subscribeDraftUpdated();
7091
7369
  const unsubscribeDraftDeleted = this.subscribeDraftDeleted();
@@ -7265,6 +7543,10 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
7265
7543
  };
7266
7544
  this.setQuotedMessage = (quotedMessage) => {
7267
7545
  this.state.partialNext({ quotedMessage });
7546
+ const activeCommand = this.textComposer.command;
7547
+ if (quotedMessage && activeCommand && this.isCommandDisabled(activeCommand)) {
7548
+ this.textComposer.clearCommand();
7549
+ }
7268
7550
  };
7269
7551
  this.toggleShowReplyInChannel = () => {
7270
7552
  this.state.partialNext({ showReplyInChannel: !this.showReplyInChannel });
@@ -7499,6 +7781,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
7499
7781
  this.draftCompositionMiddlewareExecutor = new MessageDraftComposerMiddlewareExecutor({
7500
7782
  composer: this
7501
7783
  });
7784
+ this.effectHandlers = new MessageComposerEffectHandlers({ composer: this });
7502
7785
  }
7503
7786
  static evaluateContextType(compositionContext) {
7504
7787
  if (compositionContext instanceof Channel) {
@@ -10173,8 +10456,9 @@ var StableWSConnection = class {
10173
10456
  this.onmessage = (wsID, event) => {
10174
10457
  if (this.wsID !== wsID) return;
10175
10458
  this._log("onmessage() - onmessage callback", { event, wsID });
10176
- const data = typeof event.data === "string" ? JSON.parse(event.data) : null;
10177
- if (!this.isResolved && data) {
10459
+ if (typeof event.data !== "string") return;
10460
+ const data = JSON.parse(event.data);
10461
+ if (!this.isResolved) {
10178
10462
  this.isResolved = true;
10179
10463
  if (data.error) {
10180
10464
  this.rejectPromise?.(this._errorFromWSEvent(data, false));
@@ -10184,10 +10468,10 @@ var StableWSConnection = class {
10184
10468
  this._setHealth(true);
10185
10469
  }
10186
10470
  this.lastEvent = /* @__PURE__ */ new Date();
10187
- if (data && data.type === "health.check") {
10471
+ if (data.type === "health.check") {
10188
10472
  this.scheduleNextPing();
10189
10473
  }
10190
- this.client.handleEvent(event);
10474
+ this.client.dispatchEvent(data);
10191
10475
  this.scheduleConnectionCheck();
10192
10476
  };
10193
10477
  this.onclose = (wsID, event) => {
@@ -13290,11 +13574,6 @@ var StreamChat = class _StreamChat {
13290
13574
  method: `handleEvent;${event.type}`
13291
13575
  });
13292
13576
  };
13293
- this.handleEvent = (messageEvent) => {
13294
- const jsonString = messageEvent.data;
13295
- const event = JSON.parse(jsonString);
13296
- this.dispatchEvent(event);
13297
- };
13298
13577
  /**
13299
13578
  * Updates the members, watchers and read references of the currently active channels that contain this user
13300
13579
  *
@@ -15382,7 +15661,7 @@ var StreamChat = class _StreamChat {
15382
15661
  if (this.userAgent) {
15383
15662
  return this.userAgent;
15384
15663
  }
15385
- const version = "9.42.3";
15664
+ const version = "9.43.1";
15386
15665
  const clientBundle = "browser-cjs";
15387
15666
  let userAgentString = "";
15388
15667
  if (this.sdkIdentifier) {