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
@@ -1,5 +1,6 @@
1
1
  export * from './activeCommandGuard';
2
2
  export * from './commands';
3
+ export * from './commandEffects';
3
4
  export * from './commandStringExtraction';
4
5
  export * from './mentions';
5
6
  export * from './validation';
@@ -1,4 +1,5 @@
1
1
  import type { TextSelection } from './types';
2
+ import { escapeCommandRegExp } from './commandUtils';
2
3
 
3
4
  /**
4
5
  * For commands, we want to match all patterns except:
@@ -16,7 +17,7 @@ export const getTriggerCharWithToken = ({
16
17
  isCommand?: boolean;
17
18
  acceptTrailingSpaces?: boolean;
18
19
  }) => {
19
- const escapedTrigger = escapeRegExp(trigger);
20
+ const escapedTrigger = escapeCommandRegExp(trigger);
20
21
  const triggerNorWhitespace = `[^\\s${escapedTrigger}]*`;
21
22
 
22
23
  const match = text.match(
@@ -33,14 +34,6 @@ export const getTriggerCharWithToken = ({
33
34
  return match && match[match.length - 1].trim();
34
35
  };
35
36
 
36
- export const getCompleteCommandInString = (text: string) => {
37
- // starts with "/" followed by 1+ non-whitespace chars followed by 1+ white-space chars
38
- // the comand name is extracted into a separate group
39
- const match = text.match(/^\/(\S+)\s+.*/);
40
- const commandName = match && match[1];
41
- return commandName;
42
- };
43
-
44
37
  export const insertItemWithTrigger = ({
45
38
  insertText,
46
39
  selection,
@@ -93,42 +86,6 @@ export const replaceWordWithEntity = async ({
93
86
  return textBeforeWord + newWord + spaces + textAfterCaret;
94
87
  };
95
88
 
96
- /**
97
- * Escapes a string for use in a regular expression
98
- * @param text - The string to escape
99
- * @returns The escaped string
100
- * What does this regex do?
101
-
102
- The regex escapes special regex characters by adding a backslash before them. Here's what it matches:
103
- - dash
104
- [ ] square brackets
105
- { } curly braces
106
- ( ) parentheses
107
- * asterisk
108
- + plus
109
- ? question mark
110
- . period
111
- , comma
112
- / forward slash
113
- \ backslash
114
- ^ caret
115
- $ dollar sign
116
- | pipe
117
- # hash
118
-
119
- The \\$& replacement adds a backslash before any matched character.
120
- This is needed when you want to use these characters literally
121
- in a regex pattern instead of their special regex meanings.
122
- For example:
123
- escapeRegExp("hello.world") // Returns: "hello\.world"
124
- escapeRegExp("[test]") // Returns: "\[test\]"
125
-
126
- This is commonly used when building dynamic regex patterns from user input to prevent special characters from being interpreted as regex syntax.
127
- */
128
- export function escapeRegExp(text: string) {
129
- return text.replace(/[-[\]{}()*+?.,/\\^$|#]/g, '\\$&');
130
- }
131
-
132
89
  export type TokenizationPayload = {
133
90
  tokenizedDisplayName: { token: string; parts: string[] };
134
91
  };
@@ -144,7 +101,7 @@ export const getTokenizedSuggestionDisplayName = ({
144
101
  token: searchToken,
145
102
  parts: searchToken
146
103
  ? displayName
147
- .split(new RegExp(`(${escapeRegExp(searchToken)})`, 'gi'))
104
+ .split(new RegExp(`(${escapeCommandRegExp(searchToken)})`, 'gi'))
148
105
  .filter(Boolean)
149
106
  : [displayName],
150
107
  },
@@ -1,4 +1,5 @@
1
1
  import type { MessageComposer } from '../../messageComposer';
2
+ import type { MessageComposerEffect } from '../../messageComposer';
2
3
  import type { CommandResponse, UserResponse } from '../../../types';
3
4
  import type { TokenizationPayload } from './textMiddlewareUtils';
4
5
  import type { SearchSource, SearchSourceSync } from '../../../search';
@@ -12,11 +13,30 @@ export type BaseSuggestion = {
12
13
  id: string;
13
14
  };
14
15
 
16
+ export type CommandSuggestionDisabledReason = 'editing' | 'quoted_message';
17
+
15
18
  export type CommandSuggestion = BaseSuggestion & CommandResponse;
16
19
  export type UserSuggestion = BaseSuggestion & UserResponse & TokenizationPayload;
17
20
  export type CustomValidSuggestion = BaseSuggestion & CustomTextComposerSuggestion;
18
21
  export type Suggestion = CommandSuggestion | UserSuggestion | CustomValidSuggestion;
19
22
 
23
+ export type TextComposerStateSnapshot = TextComposerState;
24
+
25
+ export type TextComposerCommandActivationStateToRestore =
26
+ Partial<TextComposerStateSnapshot>;
27
+
28
+ export type TextComposerCommandActivationEffect = {
29
+ command: CommandResponse;
30
+ stateToRestore?: TextComposerCommandActivationStateToRestore;
31
+ type: 'command.activate';
32
+ };
33
+
34
+ export type TextComposerCommandClearEffect = {
35
+ type: 'command.clear';
36
+ };
37
+
38
+ export type TextComposerEffect = MessageComposerEffect;
39
+
20
40
  export type TextComposerMiddlewareOptions = {
21
41
  minChars: number;
22
42
  trigger: string;
@@ -13,6 +13,8 @@ import type {
13
13
  UpdateFieldsData,
14
14
  } from './middleware/pollComposer';
15
15
 
16
+ export type PollComposerSnapshot = PollComposerState;
17
+
16
18
  export type PollComposerOptions = {
17
19
  composer: MessageComposer;
18
20
  };
@@ -107,6 +109,12 @@ export class PollComposer {
107
109
  this.state.next(this.initialState);
108
110
  };
109
111
 
112
+ getSnapshot = (): PollComposerSnapshot => this.state.getLatestValue();
113
+
114
+ restoreSnapshot = (snapshot: PollComposerSnapshot) => {
115
+ this.state.next(snapshot);
116
+ };
117
+
110
118
  /**
111
119
  * Updates specified fields and generates relevant errors
112
120
  * @param data
@@ -1,9 +1,14 @@
1
1
  import { TextComposerMiddlewareExecutor } from './middleware';
2
2
  import { StateStore } from '../store';
3
3
  import { logChatPromiseExecution } from '../utils';
4
+ import type { TextComposerMiddlewareExecutorState } from './middleware';
4
5
  import type { TextComposerSuggestion } from './middleware/textComposer/types';
5
6
  import type { TextSelection } from './middleware/textComposer/types';
6
- import type { TextComposerState } from './middleware/textComposer/types';
7
+ import type {
8
+ TextComposerCommandActivationEffect,
9
+ TextComposerState,
10
+ TextComposerStateSnapshot,
11
+ } from './middleware/textComposer/types';
7
12
  import type { Suggestions } from './middleware/textComposer/types';
8
13
  import type { MessageComposer } from './messageComposer';
9
14
  import type { CommandResponse, DraftMessage, LocalMessage, UserResponse } from '../types';
@@ -13,6 +18,8 @@ export type TextComposerOptions = {
13
18
  message?: DraftMessage | LocalMessage;
14
19
  };
15
20
 
21
+ export type TextComposerSnapshot = TextComposerStateSnapshot;
22
+
16
23
  export const textIsEmpty = (text: string) => {
17
24
  const trimmedText = text.trim();
18
25
  return (
@@ -147,12 +154,24 @@ export class TextComposer {
147
154
  this.state.next(initState({ composer: this.composer, message }));
148
155
  };
149
156
 
157
+ getSnapshot = (state = this.state.getLatestValue()): TextComposerSnapshot => state;
158
+
159
+ restoreSnapshot = (snapshot: TextComposerSnapshot) => {
160
+ this.state.next(snapshot);
161
+ };
162
+
150
163
  setMentionedUsers(users: UserResponse[]) {
151
164
  this.state.partialNext({ mentionedUsers: users });
152
165
  }
153
166
 
154
167
  clearCommand() {
155
- this.state.partialNext({ command: null });
168
+ if (!this.command) return;
169
+
170
+ this.commitState({
171
+ ...this.state.getLatestValue(),
172
+ command: null,
173
+ effects: [{ type: 'command.clear' }],
174
+ });
156
175
  }
157
176
 
158
177
  upsertMentionedUser = (user: UserResponse) => {
@@ -179,8 +198,29 @@ export class TextComposer {
179
198
  };
180
199
 
181
200
  setCommand = (command: CommandResponse | null) => {
182
- if (command?.name === this.command?.name) return;
183
- this.state.partialNext({ command });
201
+ if (!command) {
202
+ this.clearCommand();
203
+ return;
204
+ }
205
+ if (command.name === this.command?.name) return;
206
+ if (this.composer.isCommandDisabled(command)) return;
207
+
208
+ const stateToRestore: TextComposerCommandActivationEffect['stateToRestore'] = {
209
+ command: null,
210
+ };
211
+
212
+ this.commitState({
213
+ ...this.state.getLatestValue(),
214
+ command,
215
+ effects: [
216
+ {
217
+ command,
218
+ stateToRestore,
219
+ type: 'command.activate',
220
+ },
221
+ ],
222
+ suggestions: undefined,
223
+ });
184
224
  };
185
225
 
186
226
  setText = (text: string) => {
@@ -270,6 +310,14 @@ export class TextComposer {
270
310
  };
271
311
  // --- END STATE API ---
272
312
 
313
+ private commitState = (state: TextComposerMiddlewareExecutorState) => {
314
+ const { change, effects, ...nextState } = state;
315
+ void change;
316
+
317
+ this.state.next(nextState);
318
+ this.composer.applyEffects(effects);
319
+ };
320
+
273
321
  // --- START TEXT PROCESSING ----
274
322
 
275
323
  handleChange = async ({
@@ -289,7 +337,7 @@ export class TextComposer {
289
337
  },
290
338
  });
291
339
  if (output.status === 'discard') return;
292
- this.state.next(output.state);
340
+ this.commitState(output.state);
293
341
 
294
342
  if (this.config.publishTypingEvents && text) {
295
343
  logChatPromiseExecution(
@@ -312,7 +360,7 @@ export class TextComposer {
312
360
  },
313
361
  });
314
362
  if (output?.status === 'discard') return;
315
- this.state.next(output.state);
363
+ this.commitState(output.state);
316
364
  };
317
365
  // --- END TEXT PROCESSING ----
318
366
  }
package/src/types.ts CHANGED
@@ -119,6 +119,13 @@ export type AppSettingsAPIResponse = APIResponse & {
119
119
  uploads?: boolean;
120
120
  url_enrichment?: boolean;
121
121
  user_message_reminders?: boolean;
122
+ push_level?:
123
+ | 'all'
124
+ | 'all_mentions'
125
+ | 'direct_mentions'
126
+ | 'mentions'
127
+ | 'none'
128
+ | '';
122
129
  }
123
130
  >;
124
131
  reminders_interval: number;
@@ -154,9 +161,11 @@ export type AppSettingsAPIResponse = APIResponse & {
154
161
  max_aggregated_activities_length?: number;
155
162
  moderation_bulk_submit_action_enabled?: boolean;
156
163
  moderation_dashboard_preferences?: Record<string, unknown> | null;
164
+ moderation_audio_call_moderation_enabled?: boolean;
157
165
  moderation_enabled?: boolean;
158
166
  moderation_llm_configurability_enabled?: boolean;
159
167
  moderation_multitenant_blocklist_enabled?: boolean;
168
+ moderation_video_call_moderation_enabled?: boolean;
160
169
  moderation_webhook_url?: string;
161
170
  multi_tenant_enabled?: boolean;
162
171
  name?: string;
@@ -535,8 +544,8 @@ export type LocalMessageBase = Omit<
535
544
  };
536
545
 
537
546
  export type LocalMessage = LocalMessageBase & {
538
- error?: ErrorFromResponse<APIErrorResponse>;
539
- quoted_message?: LocalMessageBase;
547
+ error?: ErrorFromResponse<APIErrorResponse> | null;
548
+ quoted_message?: LocalMessageBase | null;
540
549
  };
541
550
 
542
551
  /**
@@ -744,6 +753,8 @@ export type MessageResponseBase = MessageBase & {
744
753
  member?: ChannelMemberResponse;
745
754
  mentioned_users?: UserResponse[];
746
755
  mentioned_channel?: boolean;
756
+ mentioned_here?: boolean;
757
+ mentioned_roles?: string[];
747
758
  message_text_updated_at?: string;
748
759
  moderation?: ModerationResponse; // present only with Moderation v2
749
760
  moderation_details?: ModerationDetailsResponse; // present only with Moderation v1
@@ -770,6 +781,13 @@ export type ReactionGroupResponse = {
770
781
  sum_scores: number;
771
782
  first_reaction_at?: string;
772
783
  last_reaction_at?: string;
784
+ latest_reactions_by?: ReactionGroupUserResponse[];
785
+ };
786
+
787
+ export type ReactionGroupUserResponse = {
788
+ created_at: string;
789
+ user_id: string;
790
+ user?: UserResponse;
773
791
  };
774
792
 
775
793
  export type ModerationDetailsResponse = {
@@ -2500,6 +2518,7 @@ export type ChannelConfigFields = {
2500
2518
  uploads?: boolean;
2501
2519
  url_enrichment?: boolean;
2502
2520
  user_message_reminders?: boolean; // Feature flag for user message reminders
2521
+ push_level?: 'all' | 'all_mentions' | 'direct_mentions' | 'mentions' | 'none' | '';
2503
2522
  };
2504
2523
 
2505
2524
  export type ChannelConfigWithInfo = ChannelConfigFields &
@@ -2920,9 +2939,13 @@ export type Mute = {
2920
2939
  user: UserResponse;
2921
2940
  };
2922
2941
 
2942
+ export type PartialUpdateChannelFields = Partial<ChannelResponse> & {
2943
+ config_overrides?: Partial<ChannelConfigFields>;
2944
+ };
2945
+
2923
2946
  export type PartialUpdateChannel = {
2924
- set?: Partial<ChannelResponse>;
2925
- unset?: Array<keyof ChannelResponse>;
2947
+ set?: PartialUpdateChannelFields;
2948
+ unset?: Array<keyof PartialUpdateChannelFields>;
2926
2949
  };
2927
2950
 
2928
2951
  export type PartialUpdateMember = {