stream-chat 9.0.0 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1064,12 +1064,12 @@ export declare class StreamChat {
1064
1064
  * updateMessage - Update the given message
1065
1065
  *
1066
1066
  * @param {Omit<MessageResponse, 'mentioned_users'> & { mentioned_users?: string[] }} message object, id needs to be specified
1067
- * @param {string | { id: string }} [userId]
1067
+ * @param {string | { id: string }} [partialUserOrUserId]
1068
1068
  * @param {boolean} [options.skip_enrich_url] Do not try to enrich the URLs within message
1069
1069
  *
1070
1070
  * @return {{ message: LocalMessage | MessageResponse }} Response that includes the message
1071
1071
  */
1072
- updateMessage(message: LocalMessage | Partial<MessageResponse>, userId?: string | {
1072
+ updateMessage(message: LocalMessage | Partial<MessageResponse>, partialUserOrUserId?: string | {
1073
1073
  id: string;
1074
1074
  }, options?: UpdateMessageOptions): Promise<UpdateMessageAPIResponse>;
1075
1075
  /**
@@ -1085,7 +1085,7 @@ export declare class StreamChat {
1085
1085
  *
1086
1086
  * @return {{ message: MessageResponse }} Response that includes the updated message
1087
1087
  */
1088
- partialUpdateMessage(id: string, partialMessageObject: PartialMessageUpdate, userId?: string | {
1088
+ partialUpdateMessage(id: string, partialMessageObject: PartialMessageUpdate, partialUserOrUserId?: string | {
1089
1089
  id: string;
1090
1090
  }, options?: UpdateMessageOptions): Promise<UpdateMessageAPIResponse>;
1091
1091
  deleteMessage(messageID: string, hardDelete?: boolean): Promise<APIResponse & {
@@ -1,4 +1,3 @@
1
- import type { ReservedUpdatedMessageFields } from './types';
2
1
  export declare const DEFAULT_QUERY_CHANNELS_MESSAGE_LIST_PAGE_SIZE = 25;
3
2
  export declare const DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE = 100;
4
3
  export declare const DEFAULT_MESSAGE_SET_PAGINATION: {
@@ -8,5 +7,24 @@ export declare const DEFAULT_MESSAGE_SET_PAGINATION: {
8
7
  export declare const DEFAULT_UPLOAD_SIZE_LIMIT_BYTES: number;
9
8
  export declare const API_MAX_FILES_ALLOWED_PER_MESSAGE = 10;
10
9
  export declare const MAX_CHANNEL_MEMBER_COUNT_IN_CHANNEL_QUERY = 100;
11
- export declare const RESERVED_UPDATED_MESSAGE_FIELDS: Array<ReservedUpdatedMessageFields>;
12
- export declare const LOCAL_MESSAGE_FIELDS: readonly ["error"];
10
+ export declare const RESERVED_UPDATED_MESSAGE_FIELDS: {
11
+ readonly created_at: true;
12
+ readonly deleted_at: true;
13
+ readonly pinned_at: true;
14
+ readonly updated_at: true;
15
+ readonly command: true;
16
+ readonly mentioned_users: true;
17
+ readonly quoted_message: true;
18
+ readonly latest_reactions: true;
19
+ readonly own_reactions: true;
20
+ readonly reaction_counts: true;
21
+ readonly reply_count: true;
22
+ readonly i18n: true;
23
+ readonly type: true;
24
+ readonly html: true;
25
+ readonly __html: true;
26
+ readonly user: true;
27
+ };
28
+ export declare const LOCAL_MESSAGE_FIELDS: {
29
+ readonly error: true;
30
+ };
@@ -0,0 +1,3 @@
1
+ import type { MessageCompositionMiddleware } from './types';
2
+ import type { MessageComposer } from '../../messageComposer';
3
+ export declare const createPollOnlyCompositionMiddleware: (composer: MessageComposer) => MessageCompositionMiddleware;
@@ -43,6 +43,7 @@ export type PollComposerStateChangeMiddlewareValue = {
43
43
  targetFields: Partial<{
44
44
  [K in keyof PollComposerState['data']]: K extends 'options' ? PollComposerOptionUpdate : PollComposerState['data'][K];
45
45
  }>;
46
+ injectedFieldErrors?: PollComposerFieldErrors;
46
47
  };
47
48
  export type PollComposerStateMiddlewareValue = MiddlewareExecutionResult<PollComposerStateChangeMiddlewareValue>;
48
49
  export {};
@@ -1,5 +1,5 @@
1
- import type { ExecuteParams, MiddlewareExecutionResult, MiddlewareHandler } from '../../../middleware';
2
1
  import { MiddlewareExecutor } from '../../../middleware';
2
+ import type { ExecuteParams, MiddlewareExecutionResult, MiddlewareHandler } from '../../../middleware';
3
3
  import type { Suggestion, TextComposerMiddlewareExecutorOptions, TextComposerState } from './types';
4
4
  export type TextComposerMiddlewareExecutorState<T extends Suggestion = Suggestion> = TextComposerState<T> & {
5
5
  change?: {
@@ -2,7 +2,7 @@ import { PollComposerCompositionMiddlewareExecutor, PollComposerStateMiddlewareE
2
2
  import { StateStore } from '../store';
3
3
  import { VotingVisibility } from '../types';
4
4
  import type { MessageComposer } from './messageComposer';
5
- import type { PollComposerState, UpdateFieldsData } from './middleware/pollComposer';
5
+ import type { PollComposerFieldErrors, PollComposerState, UpdateFieldsData } from './middleware/pollComposer';
6
6
  export type PollComposerOptions = {
7
7
  composer: MessageComposer;
8
8
  };
@@ -25,7 +25,12 @@ export declare class PollComposer {
25
25
  get voting_visibility(): VotingVisibility | undefined;
26
26
  get canCreatePoll(): boolean;
27
27
  initState: () => void;
28
- updateFields: (data: UpdateFieldsData) => Promise<void>;
28
+ /**
29
+ * Updates specified fields and generates relevant errors
30
+ * @param data
31
+ * @param injectedFieldErrors - errors produced externally that will take precedence over the errors generated in the middleware chaing
32
+ */
33
+ updateFields: (data: UpdateFieldsData, injectedFieldErrors?: PollComposerFieldErrors) => Promise<void>;
29
34
  handleFieldBlur: (field: keyof PollComposerState["data"]) => Promise<void>;
30
35
  compose: () => Promise<import("..").PollComposerCompositionMiddlewareValueState | undefined>;
31
36
  }
@@ -5,6 +5,7 @@ import type { StableWSConnection } from './connection';
5
5
  import type { Role } from './permissions';
6
6
  import type { CustomAttachmentData, CustomChannelData, CustomCommandData, CustomEventData, CustomMemberData, CustomMessageData, CustomPollData, CustomPollOptionData, CustomReactionData, CustomThreadData, CustomUserData } from './custom_types';
7
7
  import type { NotificationManager } from './notifications';
8
+ import type { RESERVED_UPDATED_MESSAGE_FIELDS } from './constants';
8
9
  /**
9
10
  * Utility Types
10
11
  */
@@ -2122,7 +2123,7 @@ export type TokenOrProvider = null | string | TokenProvider | undefined;
2122
2123
  export type TokenProvider = () => Promise<string>;
2123
2124
  export type TranslationLanguages = 'af' | 'am' | 'ar' | 'az' | 'bg' | 'bn' | 'bs' | 'cs' | 'da' | 'de' | 'el' | 'en' | 'es' | 'es-MX' | 'et' | 'fa' | 'fa-AF' | 'fi' | 'fr' | 'fr-CA' | 'ha' | 'he' | 'hi' | 'hr' | 'hu' | 'id' | 'it' | 'ja' | 'ka' | 'ko' | 'lt' | 'lv' | 'ms' | 'nl' | 'no' | 'pl' | 'ps' | 'pt' | 'ro' | 'ru' | 'sk' | 'sl' | 'so' | 'sq' | 'sr' | 'sv' | 'sw' | 'ta' | 'th' | 'tl' | 'tr' | 'uk' | 'ur' | 'vi' | 'zh' | 'zh-TW' | (string & {});
2124
2125
  export type TypingStartEvent = Event;
2125
- export type ReservedUpdatedMessageFields = 'command' | 'created_at' | 'deleted_at' | 'html' | 'i18n' | 'latest_reactions' | 'mentioned_users' | 'own_reactions' | 'pinned_at' | 'quoted_message' | 'reaction_counts' | 'reply_count' | 'type' | 'updated_at' | '__html';
2126
+ export type ReservedUpdatedMessageFields = keyof typeof RESERVED_UPDATED_MESSAGE_FIELDS;
2126
2127
  export type UpdatedMessage = Omit<MessageResponse, ReservedUpdatedMessageFields> & {
2127
2128
  mentioned_users?: string[];
2128
2129
  type?: MessageLabel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stream-chat",
3
- "version": "9.0.0",
3
+ "version": "9.1.0",
4
4
  "description": "JS SDK for the Stream Chat API",
5
5
  "homepage": "https://getstream.io/chat/",
6
6
  "author": {
package/src/client.ts CHANGED
@@ -2860,28 +2860,28 @@ export class StreamChat {
2860
2860
  * updateMessage - Update the given message
2861
2861
  *
2862
2862
  * @param {Omit<MessageResponse, 'mentioned_users'> & { mentioned_users?: string[] }} message object, id needs to be specified
2863
- * @param {string | { id: string }} [userId]
2863
+ * @param {string | { id: string }} [partialUserOrUserId]
2864
2864
  * @param {boolean} [options.skip_enrich_url] Do not try to enrich the URLs within message
2865
2865
  *
2866
2866
  * @return {{ message: LocalMessage | MessageResponse }} Response that includes the message
2867
2867
  */
2868
2868
  async updateMessage(
2869
2869
  message: LocalMessage | Partial<MessageResponse>,
2870
- userId?: string | { id: string },
2870
+ partialUserOrUserId?: string | { id: string },
2871
2871
  options?: UpdateMessageOptions,
2872
2872
  ) {
2873
2873
  if (!message.id) {
2874
- throw Error('Please specify the message id when calling updateMessage');
2874
+ throw Error('Please specify the message.id when calling updateMessage');
2875
2875
  }
2876
+
2877
+ // should not include user object
2876
2878
  const payload = toUpdatedMessagePayload(message);
2877
- if (userId != null) {
2878
- if (isString(userId)) {
2879
- payload.user_id = userId;
2880
- } else {
2881
- payload.user = {
2882
- id: userId.id,
2883
- };
2884
- }
2879
+
2880
+ // add user_id (if exists)
2881
+ if (typeof partialUserOrUserId === 'string') {
2882
+ payload.user_id = partialUserOrUserId;
2883
+ } else if (typeof partialUserOrUserId?.id === 'string') {
2884
+ payload.user_id = partialUserOrUserId.id;
2885
2885
  }
2886
2886
 
2887
2887
  return await this.post<UpdateMessageAPIResponse>(
@@ -2909,16 +2909,21 @@ export class StreamChat {
2909
2909
  async partialUpdateMessage(
2910
2910
  id: string,
2911
2911
  partialMessageObject: PartialMessageUpdate,
2912
- userId?: string | { id: string },
2912
+ partialUserOrUserId?: string | { id: string },
2913
2913
  options?: UpdateMessageOptions,
2914
2914
  ) {
2915
2915
  if (!id) {
2916
- throw Error('Please specify the message id when calling partialUpdateMessage');
2916
+ throw Error('Please specify the message.id when calling partialUpdateMessage');
2917
2917
  }
2918
- let user = userId;
2919
- if (userId != null && isString(userId)) {
2920
- user = { id: userId };
2918
+
2919
+ let user: { id: string } | undefined = undefined;
2920
+
2921
+ if (typeof partialUserOrUserId === 'string') {
2922
+ user = { id: partialUserOrUserId };
2923
+ } else if (typeof partialUserOrUserId?.id === 'string') {
2924
+ user = { id: partialUserOrUserId.id };
2921
2925
  }
2926
+
2922
2927
  return await this.put<UpdateMessageAPIResponse>(
2923
2928
  this.baseURL + `/messages/${encodeURIComponent(id)}`,
2924
2929
  {
package/src/constants.ts CHANGED
@@ -1,31 +1,30 @@
1
- import type { ReservedUpdatedMessageFields } from './types';
2
-
3
1
  export const DEFAULT_QUERY_CHANNELS_MESSAGE_LIST_PAGE_SIZE = 25;
4
2
  export const DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE = 100;
5
3
  export const DEFAULT_MESSAGE_SET_PAGINATION = { hasNext: false, hasPrev: false };
6
4
  export const DEFAULT_UPLOAD_SIZE_LIMIT_BYTES = 100 * 1024 * 1024; // 100 MB
7
5
  export const API_MAX_FILES_ALLOWED_PER_MESSAGE = 10;
8
6
  export const MAX_CHANNEL_MEMBER_COUNT_IN_CHANNEL_QUERY = 100;
9
- export const RESERVED_UPDATED_MESSAGE_FIELDS: Array<ReservedUpdatedMessageFields> = [
7
+ export const RESERVED_UPDATED_MESSAGE_FIELDS = {
10
8
  // Dates should not be converted back to ISO strings as JS looses precision on them (milliseconds)
11
- 'created_at',
12
- 'deleted_at',
13
- 'pinned_at',
14
- 'updated_at',
15
- 'command',
9
+ created_at: true,
10
+ deleted_at: true,
11
+ pinned_at: true,
12
+ updated_at: true,
13
+ command: true,
16
14
  // Back-end enriches these fields
17
- 'mentioned_users',
18
- 'quoted_message',
15
+ mentioned_users: true,
16
+ quoted_message: true,
19
17
  // Client-specific fields
20
- 'latest_reactions',
21
- 'own_reactions',
22
- 'reaction_counts',
23
- 'reply_count',
18
+ latest_reactions: true,
19
+ own_reactions: true,
20
+ reaction_counts: true,
21
+ reply_count: true,
24
22
  // Message text related fields that shouldn't be in update
25
- 'i18n',
26
- 'type',
27
- 'html',
28
- '__html',
29
- ] as const;
23
+ i18n: true,
24
+ type: true,
25
+ html: true,
26
+ __html: true,
27
+ user: true,
28
+ } as const;
30
29
 
31
- export const LOCAL_MESSAGE_FIELDS = ['error'] as const;
30
+ export const LOCAL_MESSAGE_FIELDS = { error: true } as const;
@@ -88,16 +88,18 @@ const initState = (
88
88
  const quotedMessage = composition.quoted_message;
89
89
  let message;
90
90
  let draftId = null;
91
+ let id = MessageComposer.generateId(); // do not use draft id for messsage id
91
92
  if (compositionIsDraftResponse(composition)) {
92
93
  message = composition.message;
93
94
  draftId = composition.message.id;
94
95
  } else {
95
96
  message = composition;
97
+ id = composition.id;
96
98
  }
97
99
 
98
100
  return {
99
101
  draftId,
100
- id: message.id,
102
+ id,
101
103
  quotedMessage: quotedMessage
102
104
  ? formatMessage(quotedMessage as MessageResponseBase)
103
105
  : null,
@@ -318,6 +320,7 @@ export class MessageComposer {
318
320
  this.attachmentManager.initState({ message });
319
321
  this.linkPreviewsManager.initState({ message });
320
322
  this.textComposer.initState({ message });
323
+ this.pollComposer.initState();
321
324
  this.customDataManager.initState({ message });
322
325
  this.state.next(initState(composition));
323
326
  if (
@@ -543,11 +546,6 @@ export class MessageComposer {
543
546
  };
544
547
 
545
548
  clear = () => {
546
- this.attachmentManager.initState();
547
- this.linkPreviewsManager.initState();
548
- this.textComposer.initState();
549
- this.pollComposer.initState();
550
- this.customDataManager.initState();
551
549
  this.initState();
552
550
  };
553
551
 
@@ -630,6 +628,7 @@ export class MessageComposer {
630
628
  try {
631
629
  const { poll } = await this.client.createPoll(composition.data);
632
630
  this.state.partialNext({ pollId: poll.id });
631
+ this.pollComposer.initState();
633
632
  } catch (error) {
634
633
  this.client.notifications.add({
635
634
  message: 'Failed to create the poll',
@@ -30,6 +30,7 @@ import {
30
30
  createCustomDataCompositionMiddleware,
31
31
  createDraftCustomDataCompositionMiddleware,
32
32
  } from './customData';
33
+ import { createPollOnlyCompositionMiddleware } from './pollOnly';
33
34
 
34
35
  export class MessageComposerMiddlewareExecutor extends MiddlewareExecutor<
35
36
  MessageComposerMiddlewareState,
@@ -40,6 +41,7 @@ export class MessageComposerMiddlewareExecutor extends MiddlewareExecutor<
40
41
  // todo: document how to add custom data to a composed message using middleware
41
42
  // or adding custom composer components (apart from AttachmentsManager, TextComposer etc.)
42
43
  this.use([
44
+ createPollOnlyCompositionMiddleware(composer),
43
45
  createTextComposerCompositionMiddleware(composer),
44
46
  createAttachmentsCompositionMiddleware(composer),
45
47
  createLinkPreviewsCompositionMiddleware(composer),
@@ -0,0 +1,49 @@
1
+ import type {
2
+ MessageComposerMiddlewareState,
3
+ MessageCompositionMiddleware,
4
+ } from './types';
5
+ import type { MessageComposer } from '../../messageComposer';
6
+ import type { MiddlewareHandlerParams } from '../../../middleware';
7
+ import type { LocalMessage } from '../../../types';
8
+
9
+ const pollLocalMessageNullifiedFields: Pick<
10
+ LocalMessage,
11
+ 'attachments' | 'mentioned_users' | 'parent_id' | 'quoted_message' | 'text'
12
+ > = {
13
+ attachments: [],
14
+ mentioned_users: [],
15
+ parent_id: undefined,
16
+ quoted_message: undefined,
17
+ text: '',
18
+ };
19
+
20
+ export const createPollOnlyCompositionMiddleware = (
21
+ composer: MessageComposer,
22
+ ): MessageCompositionMiddleware => ({
23
+ id: 'stream-io/message-composer-middleware/poll-only',
24
+ handlers: {
25
+ compose: ({
26
+ state,
27
+ complete,
28
+ forward,
29
+ }: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {
30
+ const pollId = composer.pollId;
31
+ const isEditingMessage = !!composer.editedMessage;
32
+ const isComposingThreadReply = !!composer.threadId;
33
+ if (!pollId || isComposingThreadReply || isEditingMessage) return forward();
34
+
35
+ return complete({
36
+ ...state,
37
+ localMessage: {
38
+ ...state.localMessage,
39
+ ...pollLocalMessageNullifiedFields,
40
+ poll_id: pollId,
41
+ },
42
+ message: {
43
+ id: state.localMessage.id,
44
+ poll_id: pollId,
45
+ },
46
+ });
47
+ },
48
+ },
49
+ });
@@ -31,6 +31,10 @@ export const pollStateChangeValidators: Partial<
31
31
  max_votes_allowed: ({ data, value }) => {
32
32
  if (data.enforce_unique_vote && value)
33
33
  return { max_votes_allowed: 'Enforce unique vote is enabled' };
34
+ const numericMatch = value.match(/^[0-9]+$/);
35
+ if (!numericMatch && value) {
36
+ return { max_votes_allowed: 'Only numbers are allowed' };
37
+ }
34
38
  if (value?.length > 1 && !value.match(VALID_MAX_VOTES_VALUE_REGEX))
35
39
  return { max_votes_allowed: 'Type a number from 2 to 10' };
36
40
  return { max_votes_allowed: undefined };
@@ -225,7 +229,7 @@ export const createPollComposerStateMiddleware = ({
225
229
  forward,
226
230
  }: MiddlewareHandlerParams<PollComposerStateChangeMiddlewareValue>) => {
227
231
  if (!state.targetFields) return forward();
228
- const { previousState } = state;
232
+ const { previousState, injectedFieldErrors } = state;
229
233
  const finalValidators = {
230
234
  ...pollStateChangeValidators,
231
235
  ...defaultPollFieldChangeEventValidators,
@@ -247,7 +251,7 @@ export const createPollComposerStateMiddleware = ({
247
251
  nextState: {
248
252
  ...previousState,
249
253
  data: { ...previousState.data, ...newData },
250
- errors: { ...previousState.errors, ...newErrors },
254
+ errors: { ...previousState.errors, ...newErrors, ...injectedFieldErrors },
251
255
  },
252
256
  });
253
257
  },
@@ -275,7 +279,11 @@ export const createPollComposerStateMiddleware = ({
275
279
  nextState: {
276
280
  ...previousState,
277
281
  data: { ...previousState.data, ...newData },
278
- errors: { ...previousState.errors, ...newErrors },
282
+ errors: {
283
+ ...previousState.errors,
284
+ ...newErrors,
285
+ ...state.injectedFieldErrors,
286
+ },
279
287
  },
280
288
  });
281
289
  },
@@ -60,6 +60,7 @@ export type PollComposerStateChangeMiddlewareValue = {
60
60
  ? PollComposerOptionUpdate
61
61
  : PollComposerState['data'][K];
62
62
  }>;
63
+ injectedFieldErrors?: PollComposerFieldErrors;
63
64
  };
64
65
 
65
66
  export type PollComposerStateMiddlewareValue =
@@ -1,15 +1,15 @@
1
1
  import { createCommandsMiddleware } from './commands';
2
2
  import { createMentionsMiddleware } from './mentions';
3
3
  import { createTextComposerPreValidationMiddleware } from './validation';
4
+ import { MiddlewareExecutor } from '../../../middleware';
4
5
  import type {
5
6
  ExecuteParams,
6
7
  MiddlewareExecutionResult,
7
8
  MiddlewareHandler,
8
9
  } from '../../../middleware';
9
- import { MiddlewareExecutor } from '../../../middleware';
10
- import { withCancellation } from '../../../utils/concurrency';
11
10
  import type {
12
11
  Suggestion,
12
+ Suggestions,
13
13
  TextComposerMiddlewareExecutorOptions,
14
14
  TextComposerState,
15
15
  } from './types';
@@ -58,28 +58,14 @@ export class TextComposerMiddlewareExecutor<
58
58
  initialValue: initialState,
59
59
  });
60
60
 
61
- if (result && result.state.suggestions) {
62
- try {
63
- const searchResult = await withCancellation(
64
- 'textComposer-suggestions-search',
65
- async () => {
66
- await result.state.suggestions?.searchSource.search(
67
- result.state.suggestions?.query,
68
- );
69
- },
70
- );
71
- if (searchResult === 'canceled') return { ...result, status: 'discard' };
72
- } catch (error) {
73
- // Clear suggestions on search error
74
- return {
75
- ...result,
76
- state: {
77
- ...result.state,
78
- suggestions: undefined,
79
- },
80
- };
81
- }
82
- }
61
+ const { query, searchSource } = result.state.suggestions ?? ({} as Suggestions);
62
+ /**
63
+ * Catching error just for sanity purposes.
64
+ * The BaseSearchSource.search() method returns debounced result.
65
+ * That means the result of the previous search call as the debounced call result is unknown at the moment.
66
+ * Custom search source implementation should handle errors meaningfully internally.
67
+ */
68
+ searchSource?.search(query)?.catch(console.error);
83
69
 
84
70
  return result;
85
71
  }
@@ -7,7 +7,11 @@ import { StateStore } from '../store';
7
7
  import { VotingVisibility } from '../types';
8
8
  import { generateUUIDv4 } from '../utils';
9
9
  import type { MessageComposer } from './messageComposer';
10
- import type { PollComposerState, UpdateFieldsData } from './middleware/pollComposer';
10
+ import type {
11
+ PollComposerFieldErrors,
12
+ PollComposerState,
13
+ UpdateFieldsData,
14
+ } from './middleware/pollComposer';
11
15
 
12
16
  export type PollComposerOptions = {
13
17
  composer: MessageComposer;
@@ -102,13 +106,23 @@ export class PollComposer {
102
106
  this.state.next(this.initialState);
103
107
  };
104
108
 
105
- updateFields = async (data: UpdateFieldsData) => {
109
+ /**
110
+ * Updates specified fields and generates relevant errors
111
+ * @param data
112
+ * @param injectedFieldErrors - errors produced externally that will take precedence over the errors generated in the middleware chaing
113
+ */
114
+ // FIXME: change method params to a single object with the next major release
115
+ updateFields = async (
116
+ data: UpdateFieldsData,
117
+ injectedFieldErrors?: PollComposerFieldErrors,
118
+ ) => {
106
119
  const { state, status } = await this.stateMiddlewareExecutor.execute({
107
120
  eventName: 'handleFieldChange',
108
121
  initialValue: {
109
122
  nextState: { ...this.state.getLatestValue() },
110
123
  previousState: { ...this.state.getLatestValue() },
111
124
  targetFields: data,
125
+ injectedFieldErrors,
112
126
  },
113
127
  });
114
128
 
package/src/types.ts CHANGED
@@ -17,6 +17,7 @@ import type {
17
17
  CustomUserData,
18
18
  } from './custom_types';
19
19
  import type { NotificationManager } from './notifications';
20
+ import type { RESERVED_UPDATED_MESSAGE_FIELDS } from './constants';
20
21
 
21
22
  /**
22
23
  * Utility Types
@@ -2945,23 +2946,7 @@ export type TranslationLanguages =
2945
2946
 
2946
2947
  export type TypingStartEvent = Event;
2947
2948
 
2948
- export type ReservedUpdatedMessageFields =
2949
- | 'command'
2950
- | 'created_at'
2951
- | 'deleted_at'
2952
- | 'html'
2953
- | 'i18n'
2954
- | 'latest_reactions'
2955
- // the the original array of UserResponse object is converted to array of user ids and re-inserted before sending the update request
2956
- | 'mentioned_users'
2957
- | 'own_reactions'
2958
- | 'pinned_at'
2959
- | 'quoted_message'
2960
- | 'reaction_counts'
2961
- | 'reply_count'
2962
- | 'type'
2963
- | 'updated_at'
2964
- | '__html';
2949
+ export type ReservedUpdatedMessageFields = keyof typeof RESERVED_UPDATED_MESSAGE_FIELDS;
2965
2950
 
2966
2951
  export type UpdatedMessage = Omit<MessageResponse, ReservedUpdatedMessageFields> & {
2967
2952
  mentioned_users?: string[];
package/src/utils.ts CHANGED
@@ -367,14 +367,14 @@ export const localMessageToNewMessagePayload = (localMessage: LocalMessage): Mes
367
367
  export const toUpdatedMessagePayload = (
368
368
  message: LocalMessage | Partial<MessageResponse>,
369
369
  ): UpdatedMessage => {
370
+ const reservedKeys = {
371
+ ...RESERVED_UPDATED_MESSAGE_FIELDS,
372
+ ...LOCAL_MESSAGE_FIELDS,
373
+ } as const;
374
+
370
375
  const messageFields = Object.fromEntries(
371
376
  Object.entries(message).filter(
372
- ([key]) =>
373
- ![...RESERVED_UPDATED_MESSAGE_FIELDS, ...LOCAL_MESSAGE_FIELDS].includes(
374
- key as
375
- | (typeof RESERVED_UPDATED_MESSAGE_FIELDS)[number]
376
- | (typeof LOCAL_MESSAGE_FIELDS)[number],
377
- ),
377
+ ([key]) => !reservedKeys[key as keyof typeof reservedKeys],
378
378
  ),
379
379
  ) as UpdatedMessage;
380
380
 
@@ -384,7 +384,6 @@ export const toUpdatedMessagePayload = (
384
384
  mentioned_users: message.mentioned_users?.map((user) =>
385
385
  typeof user === 'string' ? user : user.id,
386
386
  ),
387
- user_id: message.user?.id ?? message.user_id,
388
387
  };
389
388
  };
390
389