stream-chat 9.0.1 → 9.1.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.
- package/dist/cjs/index.browser.cjs +87 -40
- package/dist/cjs/index.browser.cjs.map +3 -3
- package/dist/cjs/index.node.cjs +87 -40
- package/dist/cjs/index.node.cjs.map +3 -3
- package/dist/esm/index.js +87 -40
- package/dist/esm/index.js.map +3 -3
- package/dist/types/client.d.ts +13 -1
- package/dist/types/messageComposer/middleware/messageComposer/pollOnly.d.ts +3 -0
- package/dist/types/messageComposer/middleware/pollComposer/types.d.ts +1 -0
- package/dist/types/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.d.ts +1 -1
- package/dist/types/messageComposer/pollComposer.d.ts +7 -2
- package/dist/types/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/client.ts +29 -8
- package/src/messageComposer/messageComposer.ts +5 -6
- package/src/messageComposer/middleware/messageComposer/MessageComposerMiddlewareExecutor.ts +2 -0
- package/src/messageComposer/middleware/messageComposer/pollOnly.ts +49 -0
- package/src/messageComposer/middleware/pollComposer/state.ts +11 -3
- package/src/messageComposer/middleware/pollComposer/types.ts +1 -0
- package/src/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.ts +10 -24
- package/src/messageComposer/pollComposer.ts +16 -2
- package/src/types.ts +1 -0
package/dist/types/client.d.ts
CHANGED
|
@@ -474,6 +474,17 @@ export declare class StreamChat {
|
|
|
474
474
|
* @return {Promise<MessageFlagsResponse>} Message Flags Response
|
|
475
475
|
*/
|
|
476
476
|
queryMessageFlags(filterConditions?: MessageFlagsFilters, options?: MessageFlagsPaginationOptions): Promise<MessageFlagsResponse>;
|
|
477
|
+
/**
|
|
478
|
+
* queryChannelsRequest - Queries channels and returns the raw response
|
|
479
|
+
*
|
|
480
|
+
* @param {ChannelFilters} filterConditions object MongoDB style filters
|
|
481
|
+
* @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.
|
|
482
|
+
* When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_updated: -1}, {created_at: 1}]
|
|
483
|
+
* @param {ChannelOptions} [options] Options object
|
|
484
|
+
*
|
|
485
|
+
* @return {Promise<Array<ChannelAPIResponse>>} search channels response
|
|
486
|
+
*/
|
|
487
|
+
queryChannelsRequest(filterConditions: ChannelFilters, sort?: ChannelSort, options?: ChannelOptions): Promise<Omit<ChannelAPIResponse, "duration">[]>;
|
|
477
488
|
/**
|
|
478
489
|
* queryChannels - Query channels
|
|
479
490
|
*
|
|
@@ -483,8 +494,9 @@ export declare class StreamChat {
|
|
|
483
494
|
* @param {ChannelOptions} [options] Options object
|
|
484
495
|
* @param {ChannelStateOptions} [stateOptions] State options object. These options will only be used for state management and won't be sent in the request.
|
|
485
496
|
* - stateOptions.skipInitialization - Skips the initialization of the state for the channels matching the ids in the list.
|
|
497
|
+
* - stateOptions.skipHydration - Skips returning the channels as instances of the Channel class and rather returns the raw query response.
|
|
486
498
|
*
|
|
487
|
-
* @return {Promise<
|
|
499
|
+
* @return {Promise<Array<Channel>>} search channels response
|
|
488
500
|
*/
|
|
489
501
|
queryChannels(filterConditions: ChannelFilters, sort?: ChannelSort, options?: ChannelOptions, stateOptions?: ChannelStateOptions): Promise<Channel[]>;
|
|
490
502
|
/**
|
|
@@ -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 {};
|
package/dist/types/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
}
|
package/dist/types/types.d.ts
CHANGED
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -1735,22 +1735,19 @@ export class StreamChat {
|
|
|
1735
1735
|
}
|
|
1736
1736
|
|
|
1737
1737
|
/**
|
|
1738
|
-
*
|
|
1738
|
+
* queryChannelsRequest - Queries channels and returns the raw response
|
|
1739
1739
|
*
|
|
1740
1740
|
* @param {ChannelFilters} filterConditions object MongoDB style filters
|
|
1741
1741
|
* @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.
|
|
1742
1742
|
* When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_updated: -1}, {created_at: 1}]
|
|
1743
1743
|
* @param {ChannelOptions} [options] Options object
|
|
1744
|
-
* @param {ChannelStateOptions} [stateOptions] State options object. These options will only be used for state management and won't be sent in the request.
|
|
1745
|
-
* - stateOptions.skipInitialization - Skips the initialization of the state for the channels matching the ids in the list.
|
|
1746
1744
|
*
|
|
1747
|
-
* @return {Promise<
|
|
1745
|
+
* @return {Promise<Array<ChannelAPIResponse>>} search channels response
|
|
1748
1746
|
*/
|
|
1749
|
-
async
|
|
1747
|
+
async queryChannelsRequest(
|
|
1750
1748
|
filterConditions: ChannelFilters,
|
|
1751
1749
|
sort: ChannelSort = [],
|
|
1752
1750
|
options: ChannelOptions = {},
|
|
1753
|
-
stateOptions: ChannelStateOptions = {},
|
|
1754
1751
|
) {
|
|
1755
1752
|
const defaultOptions: ChannelOptions = {
|
|
1756
1753
|
state: true,
|
|
@@ -1777,15 +1774,39 @@ export class StreamChat {
|
|
|
1777
1774
|
payload,
|
|
1778
1775
|
);
|
|
1779
1776
|
|
|
1777
|
+
return data.channels;
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
/**
|
|
1781
|
+
* queryChannels - Query channels
|
|
1782
|
+
*
|
|
1783
|
+
* @param {ChannelFilters} filterConditions object MongoDB style filters
|
|
1784
|
+
* @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.
|
|
1785
|
+
* When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_updated: -1}, {created_at: 1}]
|
|
1786
|
+
* @param {ChannelOptions} [options] Options object
|
|
1787
|
+
* @param {ChannelStateOptions} [stateOptions] State options object. These options will only be used for state management and won't be sent in the request.
|
|
1788
|
+
* - stateOptions.skipInitialization - Skips the initialization of the state for the channels matching the ids in the list.
|
|
1789
|
+
* - stateOptions.skipHydration - Skips returning the channels as instances of the Channel class and rather returns the raw query response.
|
|
1790
|
+
*
|
|
1791
|
+
* @return {Promise<Array<Channel>>} search channels response
|
|
1792
|
+
*/
|
|
1793
|
+
async queryChannels(
|
|
1794
|
+
filterConditions: ChannelFilters,
|
|
1795
|
+
sort: ChannelSort = [],
|
|
1796
|
+
options: ChannelOptions = {},
|
|
1797
|
+
stateOptions: ChannelStateOptions = {},
|
|
1798
|
+
) {
|
|
1799
|
+
const channels = await this.queryChannelsRequest(filterConditions, sort, options);
|
|
1800
|
+
|
|
1780
1801
|
this.dispatchEvent({
|
|
1781
1802
|
type: 'channels.queried',
|
|
1782
1803
|
queriedChannels: {
|
|
1783
|
-
channels
|
|
1804
|
+
channels,
|
|
1784
1805
|
isLatestMessageSet: true,
|
|
1785
1806
|
},
|
|
1786
1807
|
});
|
|
1787
1808
|
|
|
1788
|
-
return this.hydrateActiveChannels(
|
|
1809
|
+
return this.hydrateActiveChannels(channels, stateOptions, options);
|
|
1789
1810
|
}
|
|
1790
1811
|
|
|
1791
1812
|
/**
|
|
@@ -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
|
|
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: {
|
|
282
|
+
errors: {
|
|
283
|
+
...previousState.errors,
|
|
284
|
+
...newErrors,
|
|
285
|
+
...state.injectedFieldErrors,
|
|
286
|
+
},
|
|
279
287
|
},
|
|
280
288
|
});
|
|
281
289
|
},
|
|
@@ -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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
|