stream-chat 8.37.0 → 8.38.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.
package/src/client.ts CHANGED
@@ -206,6 +206,7 @@ import {
206
206
  } from './types';
207
207
  import { InsightMetrics, postInsights } from './insights';
208
208
  import { Thread } from './thread';
209
+ import { Moderation } from './moderation';
209
210
 
210
211
  function isString(x: unknown): x is string {
211
212
  return typeof x === 'string' || x instanceof String;
@@ -239,6 +240,7 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
239
240
  * manually calling queryChannels endpoint.
240
241
  */
241
242
  recoverStateOnReconnect?: boolean;
243
+ moderation: Moderation<StreamChatGenerics>;
242
244
  mutedChannels: ChannelMute<StreamChatGenerics>[];
243
245
  mutedUsers: Mute<StreamChatGenerics>[];
244
246
  node: boolean;
@@ -290,6 +292,8 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
290
292
  this.mutedChannels = [];
291
293
  this.mutedUsers = [];
292
294
 
295
+ this.moderation = new Moderation(this);
296
+
293
297
  // set the secret
294
298
  if (secretOrOptions && isString(secretOrOptions)) {
295
299
  this.secret = secretOrOptions;
@@ -320,11 +324,11 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
320
324
 
321
325
  this.setBaseURL(this.options.baseURL || 'https://chat.stream-io-api.com');
322
326
 
323
- if (typeof process !== 'undefined' && process.env.STREAM_LOCAL_TEST_RUN) {
327
+ if (typeof process !== 'undefined' && 'env' in process && process.env.STREAM_LOCAL_TEST_RUN) {
324
328
  this.setBaseURL('http://localhost:3030');
325
329
  }
326
330
 
327
- if (typeof process !== 'undefined' && process.env.STREAM_LOCAL_TEST_HOST) {
331
+ if (typeof process !== 'undefined' && 'env' in process && process.env.STREAM_LOCAL_TEST_HOST) {
328
332
  this.setBaseURL('http://' + process.env.STREAM_LOCAL_TEST_HOST);
329
333
  }
330
334
 
@@ -2258,7 +2262,7 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
2258
2262
  * @param {string} [options.user_id] currentUserID, only used with serverside auth
2259
2263
  * @returns {Promise<APIResponse>}
2260
2264
  */
2261
- async flagMessage(targetMessageID: string, options: { user_id?: string } = {}) {
2265
+ async flagMessage(targetMessageID: string, options: { reason?: string; user_id?: string } = {}) {
2262
2266
  return await this.post<FlagMessageResponse<StreamChatGenerics>>(this.baseURL + '/moderation/flag', {
2263
2267
  target_message_id: targetMessageID,
2264
2268
  ...options,
@@ -2271,7 +2275,7 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
2271
2275
  * @param {string} [options.user_id] currentUserID, only used with serverside auth
2272
2276
  * @returns {Promise<APIResponse>}
2273
2277
  */
2274
- async flagUser(targetID: string, options: { user_id?: string } = {}) {
2278
+ async flagUser(targetID: string, options: { reason?: string; user_id?: string } = {}) {
2275
2279
  return await this.post<FlagUserResponse<StreamChatGenerics>>(this.baseURL + '/moderation/flag', {
2276
2280
  target_user_id: targetID,
2277
2281
  ...options,
@@ -3488,44 +3492,58 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
3488
3492
  /**
3489
3493
  * Creates a poll
3490
3494
  * @param params PollData The poll that will be created
3495
+ * @param userId string The user id (only serverside)
3491
3496
  * @returns {APIResponse & CreatePollAPIResponse} The poll
3492
3497
  */
3493
- async createPoll(poll: PollData) {
3494
- return await this.post<APIResponse & CreatePollAPIResponse>(this.baseURL + `/polls`, poll);
3498
+ async createPoll(poll: PollData, userId?: string) {
3499
+ return await this.post<APIResponse & CreatePollAPIResponse>(this.baseURL + `/polls`, {
3500
+ ...poll,
3501
+ ...(userId ? { user_id: userId } : {}),
3502
+ });
3495
3503
  }
3496
3504
 
3497
3505
  /**
3498
3506
  * Retrieves a poll
3499
3507
  * @param id string The poll id
3508
+ * @param userId string The user id (only serverside)
3500
3509
  * @returns {APIResponse & GetPollAPIResponse} The poll
3501
3510
  */
3502
3511
  async getPoll(id: string, userId?: string): Promise<APIResponse & GetPollAPIResponse> {
3503
- return await this.get<APIResponse & GetPollAPIResponse>(this.baseURL + `/polls/${id}`, {
3504
- ...(userId ? { user_id: userId } : {}),
3505
- });
3512
+ return await this.get<APIResponse & GetPollAPIResponse>(this.baseURL + `/polls/${id}`,
3513
+ userId ? { user_id: userId } : {}
3514
+ );
3506
3515
  }
3507
3516
 
3508
3517
  /**
3509
3518
  * Updates a poll
3510
3519
  * @param poll PollData The poll that will be updated
3520
+ * @param userId string The user id (only serverside)
3511
3521
  * @returns {APIResponse & PollResponse} The poll
3512
3522
  */
3513
- async updatePoll(poll: PollData) {
3514
- return await this.put<APIResponse & UpdatePollAPIResponse>(this.baseURL + `/polls`, poll);
3523
+ async updatePoll(poll: PollData, userId?: string) {
3524
+ return await this.put<APIResponse & UpdatePollAPIResponse>(this.baseURL + `/polls`, {
3525
+ ...poll,
3526
+ ...(userId ? { user_id: userId } : {})
3527
+ });
3515
3528
  }
3516
3529
 
3517
3530
  /**
3518
3531
  * Partially updates a poll
3519
3532
  * @param id string The poll id
3520
3533
  * @param {PartialPollUpdate<StreamChatGenerics>} partialPollObject which should contain id and any of "set" or "unset" params;
3534
+ * @param userId string The user id (only serverside)
3521
3535
  * example: {id: "44f26af5-f2be-4fa7-9dac-71cf893781de", set:{field: value}, unset:["field2"]}
3522
3536
  * @returns {APIResponse & UpdatePollAPIResponse} The poll
3523
3537
  */
3524
3538
  async partialUpdatePoll(
3525
3539
  id: string,
3526
3540
  partialPollObject: PartialPollUpdate,
3541
+ userId?: string
3527
3542
  ): Promise<APIResponse & UpdatePollAPIResponse> {
3528
- return await this.patch<APIResponse & UpdatePollAPIResponse>(this.baseURL + `/polls/${id}`, partialPollObject);
3543
+ return await this.patch<APIResponse & UpdatePollAPIResponse>(this.baseURL + `/polls/${id}`, {
3544
+ ...partialPollObject,
3545
+ ...(userId ? { user_id: userId } : {})
3546
+ });
3529
3547
  }
3530
3548
 
3531
3549
  /**
@@ -3543,13 +3561,15 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
3543
3561
  /**
3544
3562
  * Close a poll
3545
3563
  * @param id string The poll id
3564
+ * @param userId string The user id (only serverside)
3546
3565
  * @returns {APIResponse & UpdatePollAPIResponse} The poll
3547
3566
  */
3548
- async closePoll(id: string): Promise<APIResponse & UpdatePollAPIResponse> {
3567
+ async closePoll(id: string, userId?: string): Promise<APIResponse & UpdatePollAPIResponse> {
3549
3568
  return this.partialUpdatePoll(id, {
3550
3569
  set: {
3551
3570
  is_closed: true,
3552
3571
  },
3572
+ ...(userId ? { user_id: userId } : {})
3553
3573
  });
3554
3574
  }
3555
3575
 
@@ -3557,45 +3577,52 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
3557
3577
  * Creates a poll option
3558
3578
  * @param pollId string The poll id
3559
3579
  * @param option PollOptionData The poll option that will be created
3580
+ * @param userId string The user id (only serverside)
3560
3581
  * @returns {APIResponse & PollOptionResponse} The poll option
3561
3582
  */
3562
- async createPollOption(pollId: string, option: PollOptionData) {
3583
+ async createPollOption(pollId: string, option: PollOptionData, userId?: string) {
3563
3584
  return await this.post<APIResponse & CreatePollOptionAPIResponse>(
3564
- this.baseURL + `/polls/${pollId}/options`,
3565
- option,
3566
- );
3585
+ this.baseURL + `/polls/${pollId}/options`, {
3586
+ ...option,
3587
+ ...(userId ? { user_id: userId } : {})
3588
+ });
3567
3589
  }
3568
3590
 
3569
3591
  /**
3570
3592
  * Retrieves a poll option
3571
3593
  * @param pollId string The poll id
3572
3594
  * @param optionId string The poll option id
3595
+ * @param userId string The user id (only serverside)
3573
3596
  * @returns {APIResponse & PollOptionResponse} The poll option
3574
3597
  */
3575
- async getPollOption(pollId: string, optionId: string) {
3598
+ async getPollOption(pollId: string, optionId: string, userId?: string) {
3576
3599
  return await this.get<APIResponse & GetPollOptionAPIResponse>(
3577
- this.baseURL + `/polls/${pollId}/options/${optionId}`,
3578
- );
3600
+ this.baseURL + `/polls/${pollId}/options/${optionId}`, userId ? { user_id: userId } : {});
3579
3601
  }
3580
3602
 
3581
3603
  /**
3582
3604
  * Updates a poll option
3583
3605
  * @param pollId string The poll id
3584
3606
  * @param option PollOptionData The poll option that will be updated
3607
+ * @param userId string The user id (only serverside)
3585
3608
  * @returns
3586
3609
  */
3587
- async updatePollOption(pollId: string, option: PollOptionData) {
3588
- return await this.put<APIResponse & UpdatePollOptionAPIResponse>(this.baseURL + `/polls/${pollId}/options`, option);
3610
+ async updatePollOption(pollId: string, option: PollOptionData, userId?: string) {
3611
+ return await this.put<APIResponse & UpdatePollOptionAPIResponse>(this.baseURL + `/polls/${pollId}/options`, {
3612
+ ...option,
3613
+ ...(userId ? { user_id: userId } : {}),
3614
+ });
3589
3615
  }
3590
3616
 
3591
3617
  /**
3592
3618
  * Delete a poll option
3593
3619
  * @param pollId string The poll id
3594
3620
  * @param optionId string The poll option id
3621
+ * @param userId string The user id (only serverside)
3595
3622
  * @returns {APIResponse} The poll option
3596
3623
  */
3597
- async deletePollOption(pollId: string, optionId: string) {
3598
- return await this.delete<APIResponse>(this.baseURL + `/polls/${pollId}/options/${optionId}`);
3624
+ async deletePollOption(pollId: string, optionId: string, userId?: string) {
3625
+ return await this.delete<APIResponse>(this.baseURL + `/polls/${pollId}/options/${optionId}`, userId ? { user_id: userId } : {});
3599
3626
  }
3600
3627
 
3601
3628
  /**
@@ -3603,12 +3630,15 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
3603
3630
  * @param messageId string The message id
3604
3631
  * @param pollId string The poll id
3605
3632
  * @param vote PollVoteData The vote that will be casted
3633
+ * @param userId string The user id (only serverside)
3606
3634
  * @returns {APIResponse & CastVoteAPIResponse} The poll vote
3607
3635
  */
3608
- async castPollVote(messageId: string, pollId: string, vote: PollVoteData, options = {}) {
3636
+ async castPollVote(messageId: string, pollId: string, vote: PollVoteData, userId?: string) {
3609
3637
  return await this.post<APIResponse & CastVoteAPIResponse>(
3610
- this.baseURL + `/messages/${messageId}/polls/${pollId}/vote`,
3611
- { vote, ...options },
3638
+ this.baseURL + `/messages/${messageId}/polls/${pollId}/vote`, {
3639
+ vote,
3640
+ ...(userId ? { user_id: userId } : {}),
3641
+ },
3612
3642
  );
3613
3643
  }
3614
3644
 
@@ -3617,17 +3647,19 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
3617
3647
  * @param messageId string The message id
3618
3648
  * @param pollId string The poll id
3619
3649
  * @param answerText string The answer text
3650
+ * @param userId string The user id (only serverside)
3620
3651
  */
3621
- async addPollAnswer(messageId: string, pollId: string, answerText: string) {
3652
+ async addPollAnswer(messageId: string, pollId: string, answerText: string, userId?: string) {
3622
3653
  return this.castPollVote(messageId, pollId, {
3623
3654
  answer_text: answerText,
3624
- });
3655
+ }, userId);
3625
3656
  }
3626
3657
 
3627
- async removePollVote(messageId: string, pollId: string, voteId: string) {
3658
+ async removePollVote(messageId: string, pollId: string, voteId: string, userId?: string) {
3628
3659
  return await this.delete<APIResponse & { vote: PollVote }>(
3629
- this.baseURL + `/messages/${messageId}/polls/${pollId}/vote/${voteId}`,
3630
- );
3660
+ this.baseURL + `/messages/${messageId}/polls/${pollId}/vote/${voteId}`, {
3661
+ ...(userId ? { user_id: userId } : {}),
3662
+ });
3631
3663
  }
3632
3664
 
3633
3665
  /**
@@ -3635,14 +3667,17 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
3635
3667
  * @param filter
3636
3668
  * @param sort
3637
3669
  * @param options Option object, {limit: 10, offset:0}
3670
+ * @param userId string The user id (only serverside)
3638
3671
  * @returns {APIResponse & QueryPollsResponse} The polls
3639
3672
  */
3640
3673
  async queryPolls(
3641
3674
  filter: QueryPollsFilters = {},
3642
3675
  sort: PollSort = [],
3643
3676
  options: QueryPollsOptions = {},
3677
+ userId?: string
3644
3678
  ): Promise<APIResponse & QueryPollsResponse> {
3645
- return await this.post<APIResponse & QueryPollsResponse>(this.baseURL + '/polls/query', {
3679
+ const q = userId ? `?user_id=${userId}` : '';
3680
+ return await this.post<APIResponse & QueryPollsResponse>(this.baseURL + `/polls/query${q}`, {
3646
3681
  filter,
3647
3682
  sort: normalizeQuerySort(sort),
3648
3683
  ...options,
@@ -3655,7 +3690,7 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
3655
3690
  * @param filter
3656
3691
  * @param sort
3657
3692
  * @param options Option object, {limit: 10, offset:0}
3658
-
3693
+ * @param userId string The user id (only serverside)
3659
3694
  * @returns {APIResponse & PollVotesAPIResponse} The poll votes
3660
3695
  */
3661
3696
  async queryPollVotes(
@@ -3663,8 +3698,10 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
3663
3698
  filter: QueryVotesFilters = {},
3664
3699
  sort: VoteSort = [],
3665
3700
  options: QueryVotesOptions = {},
3701
+ userId?: string
3666
3702
  ): Promise<APIResponse & PollVotesAPIResponse> {
3667
- return await this.post<APIResponse & PollVotesAPIResponse>(this.baseURL + `/polls/${pollId}/votes`, {
3703
+ const q = userId ? `?user_id=${userId}` : '';
3704
+ return await this.post<APIResponse & PollVotesAPIResponse>(this.baseURL + `/polls/${pollId}/votes${q}`, {
3668
3705
  filter,
3669
3706
  sort: normalizeQuerySort(sort),
3670
3707
  ...options,
@@ -3672,7 +3709,7 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
3672
3709
  }
3673
3710
 
3674
3711
  /**
3675
- * Queries message histories
3712
+ * Query message history
3676
3713
  * @param filter
3677
3714
  * @param sort
3678
3715
  * @param options Option object, {limit: 10}
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@ export * from './channel_state';
6
6
  export * from './thread';
7
7
  export * from './connection';
8
8
  export * from './events';
9
+ export * from './moderation';
9
10
  export * from './permissions';
10
11
  export * from './signing';
11
12
  export * from './token_manager';
@@ -0,0 +1,194 @@
1
+ import {
2
+ APIResponse,
3
+ ModerationConfig,
4
+ DefaultGenerics,
5
+ ExtendableGenerics,
6
+ GetConfigResponse,
7
+ GetUserModerationReportResponse,
8
+ MuteUserResponse,
9
+ ReviewQueueFilters,
10
+ ReviewQueuePaginationOptions,
11
+ ReviewQueueResponse,
12
+ ReviewQueueSort,
13
+ UpsertConfigResponse,
14
+ ModerationFlagOptions,
15
+ ModerationMuteOptions,
16
+ GetUserModerationReportOptions,
17
+ SubmitActionOptions,
18
+ } from './types';
19
+ import { StreamChat } from './client';
20
+ import { normalizeQuerySort } from './utils';
21
+
22
+ export const MODERATION_ENTITY_TYPES = {
23
+ user: 'stream:user',
24
+ message: 'stream:chat:v1:message',
25
+ };
26
+
27
+ // Moderation class provides all the endpoints related to moderation v2.
28
+ export class Moderation<StreamChatGenerics extends ExtendableGenerics = DefaultGenerics> {
29
+ client: StreamChat<StreamChatGenerics>;
30
+
31
+ constructor(client: StreamChat<StreamChatGenerics>) {
32
+ this.client = client;
33
+ }
34
+
35
+ /**
36
+ * Flag a user
37
+ *
38
+ * @param {string} flaggedUserID User ID to be flagged
39
+ * @param {string} reason Reason for flagging the user
40
+ * @param {Object} options Additional options for flagging the user
41
+ * @param {string} options.user_id (For server side usage) User ID of the user who is flagging the target user
42
+ * @param {Object} options.custom Additional data to be stored with the flag
43
+ * @returns
44
+ */
45
+ async flagUser(flaggedUserID: string, reason: string, options: ModerationFlagOptions = {}) {
46
+ return this.flag(MODERATION_ENTITY_TYPES.user, flaggedUserID, '', reason, options);
47
+ }
48
+
49
+ /**
50
+ * Flag a message
51
+ *
52
+ * @param {string} messageID Message ID to be flagged
53
+ * @param {string} reason Reason for flagging the message
54
+ * @param {Object} options Additional options for flagging the message
55
+ * @param {string} options.user_id (For server side usage) User ID of the user who is flagging the target message
56
+ * @param {Object} options.custom Additional data to be stored with the flag
57
+ * @returns
58
+ */
59
+ async flagMessage(messageID: string, reason: string, options: ModerationFlagOptions = {}) {
60
+ return this.flag(MODERATION_ENTITY_TYPES.message, messageID, '', reason, options);
61
+ }
62
+
63
+ /**
64
+ * Flag a user
65
+ *
66
+ * @param {string} entityType Entity type to be flagged
67
+ * @param {string} entityId Entity ID to be flagged
68
+ * @param {string} entityCreatorID User ID of the entity creator
69
+ * @param {string} reason Reason for flagging the entity
70
+ * @param {Object} options Additional options for flagging the entity
71
+ * @param {string} options.user_id (For server side usage) User ID of the user who is flagging the target entity
72
+ * @param {Object} options.moderation_payload Content to be flagged e.g., { texts: ['text1', 'text2'], images: ['image1', 'image2']}
73
+ * @param {Object} options.custom Additional data to be stored with the flag
74
+ * @returns
75
+ */
76
+ async flag(
77
+ entityType: string,
78
+ entityId: string,
79
+ entityCreatorID: string,
80
+ reason: string,
81
+ options: ModerationFlagOptions = {},
82
+ ) {
83
+ return await this.client.post<{ item_id: string } & APIResponse>(this.client.baseURL + '/api/v2/moderation/flag', {
84
+ entity_type: entityType,
85
+ entity_id: entityId,
86
+ entity_creator_id: entityCreatorID,
87
+ reason,
88
+ ...options,
89
+ });
90
+ }
91
+
92
+ /**
93
+ * Mute a user
94
+ * @param {string} targetID User ID to be muted
95
+ * @param {Object} options Additional options for muting the user
96
+ * @param {string} options.user_id (For server side usage) User ID of the user who is muting the target user
97
+ * @param {number} options.timeout Timeout for the mute in minutes
98
+ * @returns
99
+ */
100
+ async muteUser(targetID: string, options: ModerationMuteOptions = {}) {
101
+ return await this.client.post<MuteUserResponse<StreamChatGenerics> & APIResponse>(
102
+ this.client.baseURL + '/api/v2/moderation/mute',
103
+ {
104
+ target_ids: [targetID],
105
+ ...options,
106
+ },
107
+ );
108
+ }
109
+
110
+ /**
111
+ * Unmute a user
112
+ * @param {string} targetID User ID to be unmuted
113
+ * @param {Object} options Additional options for unmuting the user
114
+ * @param {string} options.user_id (For server side usage) User ID of the user who is unmuting the target user
115
+ * @returns
116
+ */
117
+ async unmuteUser(
118
+ targetID: string,
119
+ options: {
120
+ user_id?: string;
121
+ },
122
+ ) {
123
+ return await this.client.post<{ item_id: string } & APIResponse>(
124
+ this.client.baseURL + '/api/v2/moderation/unmute',
125
+ {
126
+ target_ids: [targetID],
127
+ ...options,
128
+ },
129
+ );
130
+ }
131
+
132
+ /**
133
+ * Get moderation report for a user
134
+ * @param {string} userID User ID for which moderation report is to be fetched
135
+ * @param {Object} options Additional options for fetching the moderation report
136
+ * @param {boolean} options.create_user_if_not_exists Create user if not exists
137
+ * @param {boolean} options.include_user_blocks Include user blocks
138
+ * @param {boolean} options.include_user_mutes Include user mutes
139
+ */
140
+ async getUserModerationReport(userID: string, options: GetUserModerationReportOptions = {}) {
141
+ return await this.client.get<GetUserModerationReportResponse<StreamChatGenerics>>(
142
+ this.client.baseURL + `/api/v2/moderation/user_report`,
143
+ {
144
+ user_id: userID,
145
+ ...options,
146
+ },
147
+ );
148
+ }
149
+
150
+ /**
151
+ * Query review queue
152
+ * @param {Object} filterConditions Filter conditions for querying review queue
153
+ * @param {Object} sort Sort conditions for querying review queue
154
+ * @param {Object} options Pagination options for querying review queue
155
+ */
156
+ async queryReviewQueue(
157
+ filterConditions: ReviewQueueFilters = {},
158
+ sort: ReviewQueueSort = [],
159
+ options: ReviewQueuePaginationOptions = {},
160
+ ) {
161
+ return await this.client.post<ReviewQueueResponse>(this.client.baseURL + '/api/v2/moderation/review_queue', {
162
+ filter: filterConditions,
163
+ sort: normalizeQuerySort(sort),
164
+ ...options,
165
+ });
166
+ }
167
+
168
+ /**
169
+ * Upsert moderation config
170
+ * @param {Object} config Moderation config to be upserted
171
+ */
172
+ async upsertConfig(config: ModerationConfig = {}) {
173
+ return await this.client.post<UpsertConfigResponse>(this.client.baseURL + '/api/v2/moderation/config', config);
174
+ }
175
+
176
+ /**
177
+ * Get moderation config
178
+ * @param {string} key Key for which moderation config is to be fetched
179
+ */
180
+ async getConfig(key: string) {
181
+ return await this.client.get<GetConfigResponse>(this.client.baseURL + '/api/v2/moderation/config/' + key);
182
+ }
183
+
184
+ async submitAction(actionType: string, itemID: string, options: SubmitActionOptions = {}) {
185
+ return await this.client.post<{ item_id: string } & APIResponse>(
186
+ this.client.baseURL + '/api/v2/moderation/submit_action',
187
+ {
188
+ action_type: actionType,
189
+ item_id: itemID,
190
+ ...options,
191
+ },
192
+ );
193
+ }
194
+ }