stream-chat 9.44.1 → 9.45.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/dist/cjs/index.browser.js +3546 -2681
- package/dist/cjs/index.browser.js.map +4 -4
- package/dist/cjs/index.node.js +3555 -2681
- package/dist/cjs/index.node.js.map +4 -4
- package/dist/esm/index.mjs +3546 -2681
- package/dist/esm/index.mjs.map +4 -4
- package/dist/types/channel_manager.d.ts +5 -2
- package/dist/types/channel_state.d.ts +1 -1
- package/dist/types/client.d.ts +112 -5
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/messageComposer/LocationComposer.d.ts +1 -1
- package/dist/types/messageComposer/configuration/commands.configuration.d.ts +6 -0
- package/dist/types/messageComposer/configuration/configuration.d.ts +1 -2
- package/dist/types/messageComposer/configuration/index.d.ts +4 -0
- package/dist/types/messageComposer/configuration/types.d.ts +21 -0
- package/dist/types/messageComposer/fileUtils.d.ts +1 -1
- package/dist/types/messageComposer/messageComposer.d.ts +6 -4
- package/dist/types/messageComposer/middleware/messageComposer/compositionValidation.d.ts +2 -1
- package/dist/types/messageComposer/middleware/messageComposer/textComposer.d.ts +1 -1
- package/dist/types/messageComposer/middleware/textComposer/commandUtils.d.ts +10 -1
- package/dist/types/messageComposer/middleware/textComposer/mentionUtils.d.ts +8 -0
- package/dist/types/messageComposer/middleware/textComposer/mentions.d.ts +77 -15
- package/dist/types/messageComposer/middleware/textComposer/types.d.ts +51 -2
- package/dist/types/messageComposer/pollComposer.d.ts +2 -2
- package/dist/types/messageComposer/textComposer.d.ts +17 -3
- package/dist/types/pagination/UserGroupPaginator.d.ts +21 -0
- package/dist/types/pagination/index.d.ts +1 -0
- package/dist/types/types.d.ts +132 -2
- package/dist/types/utils.d.ts +2 -0
- package/package.json +38 -31
- package/src/channel_manager.ts +88 -13
- package/src/client.ts +217 -12
- package/src/constants.ts +1 -0
- package/src/messageComposer/MessageComposerEffectHandlers.ts +1 -0
- package/src/messageComposer/configuration/commands.configuration.ts +55 -0
- package/src/messageComposer/configuration/configuration.ts +3 -1
- package/src/messageComposer/configuration/index.ts +4 -0
- package/src/messageComposer/configuration/types.ts +27 -0
- package/src/messageComposer/messageComposer.ts +73 -22
- package/src/messageComposer/middleware/messageComposer/compositionValidation.ts +23 -15
- package/src/messageComposer/middleware/messageComposer/textComposer.ts +151 -31
- package/src/messageComposer/middleware/textComposer/commandUtils.ts +68 -1
- package/src/messageComposer/middleware/textComposer/commands.ts +6 -2
- package/src/messageComposer/middleware/textComposer/mentionUtils.ts +33 -0
- package/src/messageComposer/middleware/textComposer/mentions.ts +596 -66
- package/src/messageComposer/middleware/textComposer/types.ts +70 -2
- package/src/messageComposer/textComposer.ts +154 -10
- package/src/pagination/UserGroupPaginator.ts +93 -0
- package/src/pagination/index.ts +1 -0
- package/src/permissions.ts +1 -0
- package/src/types.ts +161 -2
- package/src/utils.ts +1 -0
package/src/client.ts
CHANGED
|
@@ -42,6 +42,8 @@ import {
|
|
|
42
42
|
|
|
43
43
|
import type {
|
|
44
44
|
ActiveLiveLocationsAPIResponse,
|
|
45
|
+
AddUserGroupMembersOptions,
|
|
46
|
+
AddUserGroupMembersResponse,
|
|
45
47
|
APIErrorResponse,
|
|
46
48
|
APIResponse,
|
|
47
49
|
AppSettings,
|
|
@@ -86,12 +88,16 @@ import type {
|
|
|
86
88
|
CreatePollOptionAPIResponse,
|
|
87
89
|
CreatePredefinedFilterOptions,
|
|
88
90
|
CreateReminderOptions,
|
|
91
|
+
CreateRoleAPIResponse,
|
|
92
|
+
CreateUserGroupOptions,
|
|
93
|
+
CreateUserGroupResponse,
|
|
89
94
|
CustomPermissionOptions,
|
|
90
95
|
DeactivateUsersOptions,
|
|
91
96
|
DeleteChannelsResponse,
|
|
92
97
|
DeleteCommandResponse,
|
|
93
98
|
DeleteMessageOptions,
|
|
94
99
|
DeleteRetentionPolicyResponse,
|
|
100
|
+
DeleteUserGroupOptions,
|
|
95
101
|
DeleteUserOptions,
|
|
96
102
|
Device,
|
|
97
103
|
DeviceIdentifier,
|
|
@@ -134,12 +140,15 @@ import type {
|
|
|
134
140
|
GetThreadOptions,
|
|
135
141
|
GetUnreadCountAPIResponse,
|
|
136
142
|
GetUnreadCountBatchAPIResponse,
|
|
143
|
+
GetUserGroupOptions,
|
|
144
|
+
GetUserGroupResponse,
|
|
137
145
|
ListChannelResponse,
|
|
138
146
|
ListCommandsResponse,
|
|
139
147
|
ListImportsPaginationOptions,
|
|
140
148
|
ListImportsResponse,
|
|
141
149
|
ListPredefinedFiltersOptions,
|
|
142
150
|
ListPredefinedFiltersResponse,
|
|
151
|
+
ListRolesAPIResponse,
|
|
143
152
|
LocalMessage,
|
|
144
153
|
Logger,
|
|
145
154
|
MarkChannelsReadOptions,
|
|
@@ -197,6 +206,8 @@ import type {
|
|
|
197
206
|
QueryTeamUsageStatsResponse,
|
|
198
207
|
QueryThreadsAPIResponse,
|
|
199
208
|
QueryThreadsOptions,
|
|
209
|
+
QueryUserGroupsOptions,
|
|
210
|
+
QueryUserGroupsResponse,
|
|
200
211
|
QueryVotesFilters,
|
|
201
212
|
QueryVotesOptions,
|
|
202
213
|
ReactionFilters,
|
|
@@ -205,6 +216,8 @@ import type {
|
|
|
205
216
|
ReactivateUserOptions,
|
|
206
217
|
ReactivateUsersOptions,
|
|
207
218
|
ReminderAPIResponse,
|
|
219
|
+
RemoveUserGroupMembersOptions,
|
|
220
|
+
RemoveUserGroupMembersResponse,
|
|
208
221
|
ReviewFlagReportOptions,
|
|
209
222
|
ReviewFlagReportResponse,
|
|
210
223
|
SdkIdentifier,
|
|
@@ -212,6 +225,10 @@ import type {
|
|
|
212
225
|
SearchMessageSortBase,
|
|
213
226
|
SearchOptions,
|
|
214
227
|
SearchPayload,
|
|
228
|
+
SearchRolesAPIResponse,
|
|
229
|
+
SearchRolesOptions,
|
|
230
|
+
SearchUserGroupsOptions,
|
|
231
|
+
SearchUserGroupsResponse,
|
|
215
232
|
SegmentData,
|
|
216
233
|
SegmentResponse,
|
|
217
234
|
SegmentTargetsResponse,
|
|
@@ -245,6 +262,8 @@ import type {
|
|
|
245
262
|
UpdatePredefinedFilterOptions,
|
|
246
263
|
UpdateReminderOptions,
|
|
247
264
|
UpdateSegmentData,
|
|
265
|
+
UpdateUserGroupOptions,
|
|
266
|
+
UpdateUserGroupResponse,
|
|
248
267
|
UpdateUsersAPIResponse,
|
|
249
268
|
UpsertPushPreferencesResponse,
|
|
250
269
|
UserCustomEvent,
|
|
@@ -281,6 +300,13 @@ function isString(x: unknown): x is string {
|
|
|
281
300
|
|
|
282
301
|
type MessageComposerTearDownFunction = () => void;
|
|
283
302
|
|
|
303
|
+
export type QueryChannelsResponseWithChannels = Omit<
|
|
304
|
+
QueryChannelsAPIResponse,
|
|
305
|
+
'channels'
|
|
306
|
+
> & {
|
|
307
|
+
channels: Channel[];
|
|
308
|
+
};
|
|
309
|
+
|
|
284
310
|
type MessageComposerSetupFunction = ({
|
|
285
311
|
composer,
|
|
286
312
|
}: {
|
|
@@ -1827,6 +1853,120 @@ export class StreamChat {
|
|
|
1827
1853
|
return data;
|
|
1828
1854
|
}
|
|
1829
1855
|
|
|
1856
|
+
/**
|
|
1857
|
+
* queryUserGroups - List user groups with cursor-based pagination.
|
|
1858
|
+
*
|
|
1859
|
+
* @param {QueryUserGroupsOptions} options The query options
|
|
1860
|
+
*
|
|
1861
|
+
* @return {Promise<QueryUserGroupsResponse>} User Group Query Response
|
|
1862
|
+
*/
|
|
1863
|
+
async queryUserGroups(options: QueryUserGroupsOptions = {}) {
|
|
1864
|
+
return await this.get<QueryUserGroupsResponse>(this.baseURL + '/usergroups', options);
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
/**
|
|
1868
|
+
* createUserGroup - Create a user group
|
|
1869
|
+
*
|
|
1870
|
+
* @param {CreateUserGroupOptions} options The create options
|
|
1871
|
+
*
|
|
1872
|
+
* @return {Promise<CreateUserGroupResponse>} User Group Create Response
|
|
1873
|
+
*/
|
|
1874
|
+
async createUserGroup(options: CreateUserGroupOptions) {
|
|
1875
|
+
return await this.post<CreateUserGroupResponse>(
|
|
1876
|
+
this.baseURL + '/usergroups',
|
|
1877
|
+
options,
|
|
1878
|
+
);
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
/**
|
|
1882
|
+
* getUserGroup - Get a user group by ID
|
|
1883
|
+
*
|
|
1884
|
+
* @param {string} id The user group ID
|
|
1885
|
+
* @param {GetUserGroupOptions} options Optional query options
|
|
1886
|
+
*
|
|
1887
|
+
* @return {Promise<GetUserGroupResponse>} User Group Get Response
|
|
1888
|
+
*/
|
|
1889
|
+
async getUserGroup(id: string, options: GetUserGroupOptions = {}) {
|
|
1890
|
+
return await this.get<GetUserGroupResponse>(
|
|
1891
|
+
`${this.baseURL}/usergroups/${encodeURIComponent(id)}`,
|
|
1892
|
+
options,
|
|
1893
|
+
);
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
/**
|
|
1897
|
+
* searchUserGroups - Search user groups by prefix for autocomplete
|
|
1898
|
+
*
|
|
1899
|
+
* @param {SearchUserGroupsOptions} options The search options
|
|
1900
|
+
*
|
|
1901
|
+
* @return {Promise<SearchUserGroupsResponse>} User Group Search Response
|
|
1902
|
+
*/
|
|
1903
|
+
async searchUserGroups(options: SearchUserGroupsOptions) {
|
|
1904
|
+
return await this.get<SearchUserGroupsResponse>(
|
|
1905
|
+
this.baseURL + '/usergroups/search',
|
|
1906
|
+
options,
|
|
1907
|
+
);
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
/**
|
|
1911
|
+
* updateUserGroup - Update a user group by ID
|
|
1912
|
+
*
|
|
1913
|
+
* @param {string} id The user group ID
|
|
1914
|
+
* @param {UpdateUserGroupOptions} options The update options
|
|
1915
|
+
*
|
|
1916
|
+
* @return {Promise<UpdateUserGroupResponse>} User Group Update Response
|
|
1917
|
+
*/
|
|
1918
|
+
async updateUserGroup(id: string, options: UpdateUserGroupOptions) {
|
|
1919
|
+
return await this.put<UpdateUserGroupResponse>(
|
|
1920
|
+
`${this.baseURL}/usergroups/${encodeURIComponent(id)}`,
|
|
1921
|
+
options,
|
|
1922
|
+
);
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
/**
|
|
1926
|
+
* deleteUserGroup - Delete a user group by ID
|
|
1927
|
+
*
|
|
1928
|
+
* @param {string} id The user group ID
|
|
1929
|
+
* @param {DeleteUserGroupOptions} options Optional query options
|
|
1930
|
+
*
|
|
1931
|
+
* @return {Promise<APIResponse>} User Group Delete Response
|
|
1932
|
+
*/
|
|
1933
|
+
async deleteUserGroup(id: string, options: DeleteUserGroupOptions = {}) {
|
|
1934
|
+
return await this.delete<APIResponse>(
|
|
1935
|
+
`${this.baseURL}/usergroups/${encodeURIComponent(id)}`,
|
|
1936
|
+
options,
|
|
1937
|
+
);
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
/**
|
|
1941
|
+
* addUserGroupMembers - Add members to a user group
|
|
1942
|
+
*
|
|
1943
|
+
* @param {string} id The user group ID
|
|
1944
|
+
* @param {AddUserGroupMembersOptions} options The add-members options
|
|
1945
|
+
*
|
|
1946
|
+
* @return {Promise<AddUserGroupMembersResponse>} User Group Add Members Response
|
|
1947
|
+
*/
|
|
1948
|
+
async addUserGroupMembers(id: string, options: AddUserGroupMembersOptions) {
|
|
1949
|
+
return await this.post<AddUserGroupMembersResponse>(
|
|
1950
|
+
`${this.baseURL}/usergroups/${encodeURIComponent(id)}/members`,
|
|
1951
|
+
options,
|
|
1952
|
+
);
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
/**
|
|
1956
|
+
* removeUserGroupMembers - Remove members from a user group
|
|
1957
|
+
*
|
|
1958
|
+
* @param {string} id The user group ID
|
|
1959
|
+
* @param {RemoveUserGroupMembersOptions} options The remove-members options
|
|
1960
|
+
*
|
|
1961
|
+
* @return {Promise<RemoveUserGroupMembersResponse>} User Group Remove Members Response
|
|
1962
|
+
*/
|
|
1963
|
+
async removeUserGroupMembers(id: string, options: RemoveUserGroupMembersOptions) {
|
|
1964
|
+
return await this.post<RemoveUserGroupMembersResponse>(
|
|
1965
|
+
`${this.baseURL}/usergroups/${encodeURIComponent(id)}/members/delete`,
|
|
1966
|
+
options,
|
|
1967
|
+
);
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1830
1970
|
/**
|
|
1831
1971
|
* queryBannedUsers - Query user bans
|
|
1832
1972
|
*
|
|
@@ -1888,20 +2028,26 @@ export class StreamChat {
|
|
|
1888
2028
|
}
|
|
1889
2029
|
|
|
1890
2030
|
/**
|
|
1891
|
-
*
|
|
2031
|
+
* queryChannelsRequestWithResponse - Queries channels and returns the full API response
|
|
2032
|
+
* including top-level metadata such as `predefined_filter`.
|
|
2033
|
+
*
|
|
2034
|
+
* This exists as a compatibility bridge, as changing `queryChannelsRequest()` to return
|
|
2035
|
+
* `QueryChannelsAPIResponse` would be a breaking change because it currently returns
|
|
2036
|
+
* only the channel list. In the next major release, the request/response APIs should
|
|
2037
|
+
* be consolidated so callers can access the full response through the primary API.
|
|
1892
2038
|
*
|
|
1893
2039
|
* @param {ChannelFilters} filterConditions object MongoDB style filters. Can be empty object when using predefined_filter in options.
|
|
1894
2040
|
* @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.
|
|
1895
2041
|
* When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_updated: -1}, {created_at: 1}]
|
|
1896
2042
|
* @param {ChannelOptions} [options] Options object. Can include predefined_filter, filter_values, and sort_values for using predefined filters.
|
|
1897
2043
|
*
|
|
1898
|
-
* @return {Promise<
|
|
2044
|
+
* @return {Promise<QueryChannelsAPIResponse>} full search channels response
|
|
1899
2045
|
*/
|
|
1900
|
-
async
|
|
2046
|
+
async queryChannelsRequestWithResponse(
|
|
1901
2047
|
filterConditions: ChannelFilters,
|
|
1902
2048
|
sort: ChannelSort = [],
|
|
1903
2049
|
options: ChannelOptions = {},
|
|
1904
|
-
) {
|
|
2050
|
+
): Promise<QueryChannelsAPIResponse> {
|
|
1905
2051
|
const defaultOptions: ChannelOptions = {
|
|
1906
2052
|
state: true,
|
|
1907
2053
|
watch: true,
|
|
@@ -1934,9 +2080,33 @@ export class StreamChat {
|
|
|
1934
2080
|
...restOptions,
|
|
1935
2081
|
};
|
|
1936
2082
|
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
2083
|
+
return await this.post<QueryChannelsAPIResponse>(this.baseURL + '/channels', payload);
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
/**
|
|
2087
|
+
* queryChannelsRequest - Queries channels and returns the raw channel response list.
|
|
2088
|
+
*
|
|
2089
|
+
* This preserves the historical return shape for backwards compatibility. Use
|
|
2090
|
+
* `queryChannelsRequestWithResponse()` when response level metadata such as
|
|
2091
|
+
* `predefined_filter` is needed. In the next major release these APIs should be
|
|
2092
|
+
* consolidated into a single full-response API.
|
|
2093
|
+
*
|
|
2094
|
+
* @param {ChannelFilters} filterConditions object MongoDB style filters. Can be empty object when using predefined_filter in options.
|
|
2095
|
+
* @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.
|
|
2096
|
+
* When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_updated: -1}, {created_at: 1}]
|
|
2097
|
+
* @param {ChannelOptions} [options] Options object. Can include predefined_filter, filter_values, and sort_values for using predefined filters.
|
|
2098
|
+
*
|
|
2099
|
+
* @return {Promise<Array<ChannelAPIResponse>>} search channels response
|
|
2100
|
+
*/
|
|
2101
|
+
async queryChannelsRequest(
|
|
2102
|
+
filterConditions: ChannelFilters,
|
|
2103
|
+
sort: ChannelSort = [],
|
|
2104
|
+
options: ChannelOptions = {},
|
|
2105
|
+
) {
|
|
2106
|
+
const data = await this.queryChannelsRequestWithResponse(
|
|
2107
|
+
filterConditions,
|
|
2108
|
+
sort,
|
|
2109
|
+
options,
|
|
1940
2110
|
);
|
|
1941
2111
|
|
|
1942
2112
|
// FIXME: In the next major release, return the full QueryChannelsAPIResponse
|
|
@@ -1955,16 +2125,34 @@ export class StreamChat {
|
|
|
1955
2125
|
* @param {ChannelStateOptions} [stateOptions] State options object. These options will only be used for state management and won't be sent in the request.
|
|
1956
2126
|
* - stateOptions.skipInitialization - Skips the initialization of the state for the channels matching the ids in the list.
|
|
1957
2127
|
* - stateOptions.skipHydration - Skips returning the channels as instances of the Channel class and rather returns the raw query response.
|
|
2128
|
+
* - stateOptions.withResponse - Returns the full query response with hydrated channels. This is a compatibility bridge for internal callers that need response-level metadata while the default return value remains `Channel[]`.
|
|
1958
2129
|
*
|
|
1959
2130
|
* @return {Promise<Array<Channel>>} search channels response
|
|
1960
2131
|
*/
|
|
2132
|
+
async queryChannels(
|
|
2133
|
+
filterConditions: ChannelFilters,
|
|
2134
|
+
sort: ChannelSort,
|
|
2135
|
+
options: ChannelOptions,
|
|
2136
|
+
stateOptions: ChannelStateOptions & { withResponse: true },
|
|
2137
|
+
): Promise<QueryChannelsResponseWithChannels>;
|
|
2138
|
+
async queryChannels(
|
|
2139
|
+
filterConditions?: ChannelFilters,
|
|
2140
|
+
sort?: ChannelSort,
|
|
2141
|
+
options?: ChannelOptions,
|
|
2142
|
+
stateOptions?: ChannelStateOptions,
|
|
2143
|
+
): Promise<Channel[]>;
|
|
1961
2144
|
async queryChannels(
|
|
1962
2145
|
filterConditions: ChannelFilters,
|
|
1963
2146
|
sort: ChannelSort = [],
|
|
1964
2147
|
options: ChannelOptions = {},
|
|
1965
2148
|
stateOptions: ChannelStateOptions = {},
|
|
1966
|
-
) {
|
|
1967
|
-
const
|
|
2149
|
+
): Promise<Channel[] | QueryChannelsResponseWithChannels> {
|
|
2150
|
+
const queryChannelsResponse = await this.queryChannelsRequestWithResponse(
|
|
2151
|
+
filterConditions,
|
|
2152
|
+
sort,
|
|
2153
|
+
options,
|
|
2154
|
+
);
|
|
2155
|
+
const channels = queryChannelsResponse.channels;
|
|
1968
2156
|
|
|
1969
2157
|
this.dispatchEvent({
|
|
1970
2158
|
type: 'channels.queried',
|
|
@@ -1980,7 +2168,16 @@ export class StreamChat {
|
|
|
1980
2168
|
});
|
|
1981
2169
|
}
|
|
1982
2170
|
|
|
1983
|
-
|
|
2171
|
+
const hydratedChannels = this.hydrateActiveChannels(channels, stateOptions, options);
|
|
2172
|
+
|
|
2173
|
+
if (stateOptions.withResponse) {
|
|
2174
|
+
return {
|
|
2175
|
+
...queryChannelsResponse,
|
|
2176
|
+
channels: hydratedChannels,
|
|
2177
|
+
};
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
return hydratedChannels;
|
|
1984
2181
|
}
|
|
1985
2182
|
|
|
1986
2183
|
/**
|
|
@@ -3758,7 +3955,7 @@ export class StreamChat {
|
|
|
3758
3955
|
* @returns {Promise<APIResponse>}
|
|
3759
3956
|
*/
|
|
3760
3957
|
createRole(name: string) {
|
|
3761
|
-
return this.post<
|
|
3958
|
+
return this.post<CreateRoleAPIResponse>(`${this.baseURL}/roles`, { name });
|
|
3762
3959
|
}
|
|
3763
3960
|
|
|
3764
3961
|
/** listRoles - returns the list of all roles for this application
|
|
@@ -3766,7 +3963,15 @@ export class StreamChat {
|
|
|
3766
3963
|
* @returns {Promise<APIResponse>}
|
|
3767
3964
|
*/
|
|
3768
3965
|
listRoles() {
|
|
3769
|
-
return this.get<
|
|
3966
|
+
return this.get<ListRolesAPIResponse>(`${this.baseURL}/roles`);
|
|
3967
|
+
}
|
|
3968
|
+
|
|
3969
|
+
/** listRoles - returns the list of all roles for this application
|
|
3970
|
+
*
|
|
3971
|
+
* @returns {Promise<APIResponse>}
|
|
3972
|
+
*/
|
|
3973
|
+
searchRoles(options: SearchRolesOptions) {
|
|
3974
|
+
return this.get<SearchRolesAPIResponse>(`${this.baseURL}/roles/search`, options);
|
|
3770
3975
|
}
|
|
3771
3976
|
|
|
3772
3977
|
/** deleteRole - deletes a custom role
|
package/src/constants.ts
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CommandsConfig,
|
|
3
|
+
CommandSendValidator,
|
|
4
|
+
MessageComposerConfig,
|
|
5
|
+
} from './types';
|
|
6
|
+
import type { DeepPartial } from '../../types.utility';
|
|
7
|
+
import { stripMentionTokens } from '../middleware';
|
|
8
|
+
|
|
9
|
+
export const MENTION_ONLY_COMMANDS = new Set(['mute', 'unmute', 'unban']);
|
|
10
|
+
export const defaultCommandSendabilityValidator: CommandSendValidator = ({
|
|
11
|
+
command,
|
|
12
|
+
commandArgsText,
|
|
13
|
+
mentionedUsersInText,
|
|
14
|
+
}) => {
|
|
15
|
+
if (command.name !== 'ban' && !MENTION_ONLY_COMMANDS.has(command.name ?? '')) return;
|
|
16
|
+
|
|
17
|
+
if (mentionedUsersInText.length === 0) {
|
|
18
|
+
return { command, ready: false, reason: 'missing-mention' };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (command.name !== 'ban') {
|
|
22
|
+
return { command, ready: true };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const banReason = stripMentionTokens(commandArgsText, mentionedUsersInText);
|
|
26
|
+
|
|
27
|
+
if (!banReason.length) {
|
|
28
|
+
return { command, ready: false, reason: 'missing-ban-reason' };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return { command, ready: true };
|
|
32
|
+
};
|
|
33
|
+
export const DEFAULT_COMMANDS_CONFIG: CommandsConfig = {
|
|
34
|
+
sendValidator: defaultCommandSendabilityValidator,
|
|
35
|
+
};
|
|
36
|
+
export const applyCommandValidatorOverride = (
|
|
37
|
+
targetConfig: MessageComposerConfig,
|
|
38
|
+
sourceConfig?: DeepPartial<MessageComposerConfig>,
|
|
39
|
+
) => {
|
|
40
|
+
const overrideValidator = sourceConfig?.commands?.sendValidator as
|
|
41
|
+
| CommandSendValidator
|
|
42
|
+
| undefined;
|
|
43
|
+
|
|
44
|
+
if (typeof overrideValidator === 'undefined') {
|
|
45
|
+
return targetConfig;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
...targetConfig,
|
|
50
|
+
commands: {
|
|
51
|
+
...targetConfig.commands,
|
|
52
|
+
sendValidator: overrideValidator,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
};
|
|
@@ -5,9 +5,10 @@ import type {
|
|
|
5
5
|
LinkPreviewsManagerConfig,
|
|
6
6
|
LocationComposerConfig,
|
|
7
7
|
MessageComposerConfig,
|
|
8
|
+
TextComposerConfig,
|
|
8
9
|
} from './types';
|
|
9
|
-
import type { TextComposerConfig } from './types';
|
|
10
10
|
import { generateUUIDv4 } from '../../utils';
|
|
11
|
+
import { DEFAULT_COMMANDS_CONFIG } from './commands.configuration';
|
|
11
12
|
|
|
12
13
|
export const DEFAULT_LINK_PREVIEW_MANAGER_CONFIG: LinkPreviewsManagerConfig = {
|
|
13
14
|
debounceURLEnrichmentMs: 1500,
|
|
@@ -46,6 +47,7 @@ export const DEFAULT_LOCATION_COMPOSER_CONFIG: LocationComposerConfig = {
|
|
|
46
47
|
|
|
47
48
|
export const DEFAULT_COMPOSER_CONFIG: MessageComposerConfig = {
|
|
48
49
|
attachments: DEFAULT_ATTACHMENT_MANAGER_CONFIG,
|
|
50
|
+
commands: DEFAULT_COMMANDS_CONFIG,
|
|
49
51
|
drafts: { enabled: false },
|
|
50
52
|
linkPreviews: DEFAULT_LINK_PREVIEW_MANAGER_CONFIG,
|
|
51
53
|
location: DEFAULT_LOCATION_COMPOSER_CONFIG,
|
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
export * from './configuration';
|
|
2
2
|
export * from './types';
|
|
3
|
+
export { applyCommandValidatorOverride } from './commands.configuration';
|
|
4
|
+
export { DEFAULT_COMMANDS_CONFIG } from './commands.configuration';
|
|
5
|
+
export { defaultCommandSendabilityValidator } from './commands.configuration';
|
|
6
|
+
export { MENTION_ONLY_COMMANDS } from './commands.configuration';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { LinkPreview } from '../linkPreviewsManager';
|
|
2
2
|
import type { FileUploadFilter } from '../attachmentManager';
|
|
3
|
+
import type { MessageComposer } from '../messageComposer';
|
|
3
4
|
import type { FileLike, FileReference } from '../types';
|
|
5
|
+
import type { CommandResponse, UserResponse } from '../../types';
|
|
4
6
|
|
|
5
7
|
export type MinimumUploadRequestResult = { file: string; thumb_url?: string } & Partial<
|
|
6
8
|
Record<string, unknown>
|
|
@@ -38,6 +40,29 @@ export type TextComposerConfig = {
|
|
|
38
40
|
maxLengthOnSend?: number;
|
|
39
41
|
};
|
|
40
42
|
|
|
43
|
+
export type CommandSendability = {
|
|
44
|
+
command: CommandResponse;
|
|
45
|
+
ready: boolean;
|
|
46
|
+
reason?: string & {};
|
|
47
|
+
metadata?: Record<string, unknown>;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type CommandSendValidationContext = {
|
|
51
|
+
command: CommandResponse;
|
|
52
|
+
composer: MessageComposer;
|
|
53
|
+
commandArgsText: string;
|
|
54
|
+
mentionedUsersInText: UserResponse[];
|
|
55
|
+
rawText: string;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export type CommandSendValidator = (
|
|
59
|
+
context: CommandSendValidationContext,
|
|
60
|
+
) => CommandSendability | undefined;
|
|
61
|
+
|
|
62
|
+
export type CommandsConfig = {
|
|
63
|
+
sendValidator: CommandSendValidator;
|
|
64
|
+
};
|
|
65
|
+
|
|
41
66
|
export type AttachmentManagerConfig = {
|
|
42
67
|
// todo: document removal of noFiles prop showing how to achieve the same with custom fileUploadFilter function
|
|
43
68
|
/**
|
|
@@ -86,6 +111,8 @@ export type LocationComposerConfig = {
|
|
|
86
111
|
export type MessageComposerConfig = {
|
|
87
112
|
/** If true, enables creating drafts on the server */
|
|
88
113
|
drafts: DraftsConfiguration;
|
|
114
|
+
/** Configuration for command sendability validation */
|
|
115
|
+
commands: CommandsConfig;
|
|
89
116
|
/** Configuration for the attachment manager */
|
|
90
117
|
attachments: AttachmentManagerConfig;
|
|
91
118
|
/** Configuration for the link previews manager */
|
|
@@ -5,7 +5,7 @@ import { LocationComposer } from './LocationComposer';
|
|
|
5
5
|
import { MessageComposerEffectHandlers } from './MessageComposerEffectHandlers';
|
|
6
6
|
import { PollComposer } from './pollComposer';
|
|
7
7
|
import { TextComposer } from './textComposer';
|
|
8
|
-
import { DEFAULT_COMPOSER_CONFIG } from './configuration';
|
|
8
|
+
import { applyCommandValidatorOverride, DEFAULT_COMPOSER_CONFIG } from './configuration';
|
|
9
9
|
import type { MessageComposerMiddlewareValue } from './middleware';
|
|
10
10
|
import {
|
|
11
11
|
MessageComposerMiddlewareExecutor,
|
|
@@ -30,7 +30,7 @@ import type {
|
|
|
30
30
|
} from '../types';
|
|
31
31
|
import { WithSubscriptions } from '../utils/WithSubscriptions';
|
|
32
32
|
import type { StreamChat } from '../client';
|
|
33
|
-
import type { MessageComposerConfig } from './configuration/types';
|
|
33
|
+
import type { CommandSendability, MessageComposerConfig } from './configuration/types';
|
|
34
34
|
import type {
|
|
35
35
|
CommandSuggestionDisabledReason,
|
|
36
36
|
TextComposerCommandActivationEffect,
|
|
@@ -44,6 +44,10 @@ import type { PollComposerSnapshot } from './pollComposer';
|
|
|
44
44
|
import type { TextComposerSnapshot } from './textComposer';
|
|
45
45
|
import type { DeepPartial } from '../types.utility';
|
|
46
46
|
import type { MergeWithCustomizer } from '../utils/mergeWith/mergeWithCore';
|
|
47
|
+
import {
|
|
48
|
+
getMentionedUsersInText,
|
|
49
|
+
stripCommandFromText,
|
|
50
|
+
} from './middleware/textComposer/commandUtils';
|
|
47
51
|
|
|
48
52
|
type UnregisterSubscriptions = Unsubscribe;
|
|
49
53
|
|
|
@@ -208,7 +212,16 @@ export class MessageComposer extends WithSubscriptions {
|
|
|
208
212
|
);
|
|
209
213
|
}
|
|
210
214
|
|
|
211
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Customizes config merges for the composer constructor.
|
|
217
|
+
*
|
|
218
|
+
* It catches two scalar override cases that should not use the default deep merge:
|
|
219
|
+
* - client-disabled `enabled` flags stay disabled even if the channel config tries to re-enable them
|
|
220
|
+
* - scalar channel-config values replace client defaults for matching config keys
|
|
221
|
+
*
|
|
222
|
+
* All other values fall back to the normal `mergeWith` behavior.
|
|
223
|
+
*/
|
|
224
|
+
const mergeMessageComposerConfigCustomizer: MergeWithCustomizer<
|
|
212
225
|
DeepPartial<MessageComposerConfig>
|
|
213
226
|
> = (originalVal, channelConfigVal, key) =>
|
|
214
227
|
typeof originalVal === 'object'
|
|
@@ -223,14 +236,17 @@ export class MessageComposer extends WithSubscriptions {
|
|
|
223
236
|
: originalVal;
|
|
224
237
|
|
|
225
238
|
this.configState = new StateStore<MessageComposerConfig>(
|
|
226
|
-
|
|
227
|
-
mergeWith(
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
239
|
+
applyCommandValidatorOverride(
|
|
240
|
+
mergeWith(
|
|
241
|
+
mergeWith(DEFAULT_COMPOSER_CONFIG, config ?? {}),
|
|
242
|
+
{
|
|
243
|
+
location: {
|
|
244
|
+
enabled: this.channel.getConfig()?.shared_locations,
|
|
245
|
+
},
|
|
231
246
|
},
|
|
232
|
-
|
|
233
|
-
|
|
247
|
+
mergeMessageComposerConfigCustomizer,
|
|
248
|
+
),
|
|
249
|
+
config,
|
|
234
250
|
),
|
|
235
251
|
);
|
|
236
252
|
|
|
@@ -360,6 +376,14 @@ export class MessageComposer extends WithSubscriptions {
|
|
|
360
376
|
return this.state.getLatestValue().quotedMessage;
|
|
361
377
|
}
|
|
362
378
|
|
|
379
|
+
get pollId() {
|
|
380
|
+
return this.state.getLatestValue().pollId;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
get showReplyInChannel() {
|
|
384
|
+
return this.state.getLatestValue().showReplyInChannel;
|
|
385
|
+
}
|
|
386
|
+
|
|
363
387
|
getCommandDisabledReason = (
|
|
364
388
|
command: CommandResponse,
|
|
365
389
|
): CommandSuggestionDisabledReason | undefined => {
|
|
@@ -378,21 +402,46 @@ export class MessageComposer extends WithSubscriptions {
|
|
|
378
402
|
isCommandDisabled = (command: CommandResponse) =>
|
|
379
403
|
!!this.getCommandDisabledReason(command);
|
|
380
404
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
405
|
+
validateCommandSendability = (
|
|
406
|
+
command: CommandResponse,
|
|
407
|
+
text = this.textComposer.text,
|
|
408
|
+
): CommandSendability => {
|
|
409
|
+
const currentMentionedUsers = this.textComposer.mentionedUsers;
|
|
410
|
+
const mentionedUsersInText = getMentionedUsersInText(text, currentMentionedUsers);
|
|
411
|
+
|
|
412
|
+
const validationContext = {
|
|
413
|
+
command,
|
|
414
|
+
commandArgsText: command.name
|
|
415
|
+
? stripCommandFromText(text, command.name).trim()
|
|
416
|
+
: text.trim(),
|
|
417
|
+
composer: this,
|
|
418
|
+
mentionedUsersInText,
|
|
419
|
+
rawText: text,
|
|
420
|
+
};
|
|
384
421
|
|
|
385
|
-
|
|
386
|
-
|
|
422
|
+
const result = this.config.commands.sendValidator(validationContext);
|
|
423
|
+
if (result && !result.ready) {
|
|
424
|
+
return result;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return { command, ready: true };
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
get isCommandSendable() {
|
|
431
|
+
const currentCommand = this.textComposer.command;
|
|
432
|
+
return !currentCommand || this.validateCommandSendability(currentCommand).ready;
|
|
387
433
|
}
|
|
388
434
|
|
|
389
435
|
get hasSendableData() {
|
|
390
|
-
return
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
436
|
+
return (
|
|
437
|
+
this.isCommandSendable &&
|
|
438
|
+
!!(
|
|
439
|
+
(!this.attachmentManager.uploadsInProgressCount &&
|
|
440
|
+
(!this.textComposer.textIsEmpty ||
|
|
441
|
+
this.attachmentManager.successfulUploadsCount > 0)) ||
|
|
442
|
+
this.pollId ||
|
|
443
|
+
!!this.locationComposer.validLocation
|
|
444
|
+
)
|
|
396
445
|
);
|
|
397
446
|
}
|
|
398
447
|
|
|
@@ -426,7 +475,9 @@ export class MessageComposer extends WithSubscriptions {
|
|
|
426
475
|
}
|
|
427
476
|
|
|
428
477
|
updateConfig(config: DeepPartial<MessageComposerConfig>) {
|
|
429
|
-
this.configState.partialNext(
|
|
478
|
+
this.configState.partialNext(
|
|
479
|
+
applyCommandValidatorOverride(mergeWith(this.config, config), config),
|
|
480
|
+
);
|
|
430
481
|
}
|
|
431
482
|
|
|
432
483
|
refreshId = () => {
|