stream-chat 9.15.0 → 9.17.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.cjs +382 -229
- package/dist/cjs/index.browser.cjs.map +4 -4
- package/dist/cjs/index.node.cjs +383 -229
- package/dist/cjs/index.node.cjs.map +4 -4
- package/dist/esm/index.js +421 -274
- package/dist/esm/index.js.map +4 -4
- package/dist/types/channel_state.d.ts +1 -1
- package/dist/types/client.d.ts +1 -1
- package/dist/types/events.d.ts +1 -0
- package/dist/types/pagination/FilterBuilder.d.ts +41 -0
- package/dist/types/pagination/index.d.ts +1 -0
- package/dist/types/search/BaseSearchSource.d.ts +1 -1
- package/dist/types/search/ChannelSearchSource.d.ts +11 -3
- package/dist/types/search/MessageSearchSource.d.ts +30 -2
- package/dist/types/search/UserSearchSource.d.ts +10 -3
- package/dist/types/search/index.d.ts +3 -3
- package/dist/types/types.d.ts +4 -0
- package/dist/types/utils.d.ts +86 -1
- package/package.json +2 -2
- package/src/channel.ts +9 -0
- package/src/channel_state.ts +24 -48
- package/src/client.ts +19 -3
- package/src/events.ts +1 -0
- package/src/pagination/FilterBuilder.ts +104 -0
- package/src/pagination/index.ts +1 -0
- package/src/search/BaseSearchSource.ts +1 -1
- package/src/search/ChannelSearchSource.ts +47 -8
- package/src/search/MessageSearchSource.ts +139 -21
- package/src/search/UserSearchSource.ts +47 -10
- package/src/search/index.ts +3 -3
- package/src/types.ts +4 -0
- package/src/utils.ts +75 -0
|
@@ -1,27 +1,66 @@
|
|
|
1
1
|
import { BaseSearchSource } from './BaseSearchSource';
|
|
2
|
+
import type { FilterBuilderOptions } from '../pagination';
|
|
3
|
+
import { FilterBuilder } from '../pagination';
|
|
2
4
|
import type { Channel } from '../channel';
|
|
3
5
|
import type { StreamChat } from '../client';
|
|
4
6
|
import type { ChannelFilters, ChannelOptions, ChannelSort } from '../types';
|
|
5
7
|
import type { SearchSourceOptions } from './types';
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
type CustomContext = Record<string, unknown>;
|
|
10
|
+
|
|
11
|
+
export type ChannelSearchSourceFilterBuilderContext<
|
|
12
|
+
C extends CustomContext = CustomContext,
|
|
13
|
+
> = { searchQuery?: string } & C;
|
|
14
|
+
|
|
15
|
+
export class ChannelSearchSource<
|
|
16
|
+
TFilterContext extends CustomContext = CustomContext,
|
|
17
|
+
> extends BaseSearchSource<Channel> {
|
|
8
18
|
readonly type = 'channels';
|
|
9
|
-
|
|
19
|
+
client: StreamChat;
|
|
10
20
|
filters: ChannelFilters | undefined;
|
|
11
21
|
sort: ChannelSort | undefined;
|
|
12
22
|
searchOptions: Omit<ChannelOptions, 'limit' | 'offset'> | undefined;
|
|
23
|
+
filterBuilder: FilterBuilder<
|
|
24
|
+
ChannelFilters,
|
|
25
|
+
ChannelSearchSourceFilterBuilderContext<TFilterContext>
|
|
26
|
+
>;
|
|
13
27
|
|
|
14
|
-
constructor(
|
|
28
|
+
constructor(
|
|
29
|
+
client: StreamChat,
|
|
30
|
+
options?: SearchSourceOptions,
|
|
31
|
+
filterBuilderOptions: FilterBuilderOptions<
|
|
32
|
+
ChannelFilters,
|
|
33
|
+
ChannelSearchSourceFilterBuilderContext<TFilterContext>
|
|
34
|
+
> = {},
|
|
35
|
+
) {
|
|
15
36
|
super(options);
|
|
16
37
|
this.client = client;
|
|
38
|
+
this.filterBuilder = new FilterBuilder<
|
|
39
|
+
ChannelFilters,
|
|
40
|
+
ChannelSearchSourceFilterBuilderContext<TFilterContext>
|
|
41
|
+
>({
|
|
42
|
+
...filterBuilderOptions,
|
|
43
|
+
initialFilterConfig: {
|
|
44
|
+
name: {
|
|
45
|
+
enabled: true,
|
|
46
|
+
generate: ({ searchQuery }) =>
|
|
47
|
+
searchQuery ? { name: { $autocomplete: searchQuery } } : null,
|
|
48
|
+
},
|
|
49
|
+
...filterBuilderOptions.initialFilterConfig,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
17
52
|
}
|
|
18
53
|
|
|
19
54
|
protected async query(searchQuery: string) {
|
|
20
|
-
const filters = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
55
|
+
const filters = this.filterBuilder.buildFilters({
|
|
56
|
+
baseFilters: {
|
|
57
|
+
...(this.client.userID ? { members: { $in: [this.client.userID] } } : {}),
|
|
58
|
+
...this.filters,
|
|
59
|
+
},
|
|
60
|
+
context: { searchQuery } as Partial<
|
|
61
|
+
ChannelSearchSourceFilterBuilderContext<TFilterContext>
|
|
62
|
+
>,
|
|
63
|
+
});
|
|
25
64
|
const sort = this.sort ?? {};
|
|
26
65
|
const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };
|
|
27
66
|
const items = await this.client.queryChannels(filters, sort, options);
|
|
@@ -10,46 +10,161 @@ import type {
|
|
|
10
10
|
} from '../types';
|
|
11
11
|
import type { StreamChat } from '../client';
|
|
12
12
|
import type { SearchSourceOptions } from './types';
|
|
13
|
+
import { FilterBuilder, type FilterBuilderOptions } from '../pagination';
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
type CustomContext = Record<string, unknown>;
|
|
16
|
+
|
|
17
|
+
// Built-in contexts per builder
|
|
18
|
+
type BuiltInContexts = {
|
|
19
|
+
messageSearchChannel: { searchQuery?: string };
|
|
20
|
+
messageSearch: { searchQuery?: string };
|
|
21
|
+
channelQuery: { cids?: string[] };
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Merge Built-in with user-provided Custom context
|
|
25
|
+
type MergeContext<
|
|
26
|
+
B extends Record<string, unknown>,
|
|
27
|
+
C extends CustomContext | undefined,
|
|
28
|
+
> = B & (C extends object ? C : {});
|
|
29
|
+
|
|
30
|
+
// User can provide custom context for each builder
|
|
31
|
+
type MessageSearchSourceContexts = Partial<{
|
|
32
|
+
messageSearchChannelContext: Record<string, unknown>;
|
|
33
|
+
messageSearchContext: Record<string, unknown>;
|
|
34
|
+
channelQueryContext: Record<string, unknown>;
|
|
35
|
+
}>;
|
|
36
|
+
|
|
37
|
+
export type MessageSearchSourceFilterBuilderOptions<
|
|
38
|
+
TContexts extends MessageSearchSourceContexts = {},
|
|
39
|
+
> = Partial<{
|
|
40
|
+
messageSearchChannel: FilterBuilderOptions<
|
|
41
|
+
ChannelFilters,
|
|
42
|
+
MergeContext<
|
|
43
|
+
BuiltInContexts['messageSearchChannel'],
|
|
44
|
+
TContexts['messageSearchChannelContext']
|
|
45
|
+
>
|
|
46
|
+
>;
|
|
47
|
+
messageSearch: FilterBuilderOptions<
|
|
48
|
+
MessageFilters,
|
|
49
|
+
MergeContext<BuiltInContexts['messageSearch'], TContexts['messageSearchContext']>
|
|
50
|
+
>;
|
|
51
|
+
channelQuery: FilterBuilderOptions<
|
|
52
|
+
ChannelFilters,
|
|
53
|
+
MergeContext<BuiltInContexts['channelQuery'], TContexts['channelQueryContext']>
|
|
54
|
+
>;
|
|
55
|
+
}>;
|
|
56
|
+
|
|
57
|
+
export class MessageSearchSource<
|
|
58
|
+
TContexts extends MessageSearchSourceContexts = {},
|
|
59
|
+
> extends BaseSearchSource<MessageResponse> {
|
|
15
60
|
readonly type = 'messages';
|
|
16
61
|
private client: StreamChat;
|
|
62
|
+
|
|
17
63
|
messageSearchChannelFilters: ChannelFilters | undefined;
|
|
18
64
|
messageSearchFilters: MessageFilters | undefined;
|
|
19
65
|
messageSearchSort: SearchMessageSort | undefined;
|
|
66
|
+
|
|
20
67
|
channelQueryFilters: ChannelFilters | undefined;
|
|
21
68
|
channelQuerySort: ChannelSort | undefined;
|
|
22
69
|
channelQueryOptions: Omit<ChannelOptions, 'limit' | 'offset'> | undefined;
|
|
23
70
|
|
|
24
|
-
|
|
71
|
+
messageSearchChannelFilterBuilder: FilterBuilder<
|
|
72
|
+
ChannelFilters,
|
|
73
|
+
MergeContext<
|
|
74
|
+
BuiltInContexts['messageSearchChannel'],
|
|
75
|
+
TContexts['messageSearchChannelContext']
|
|
76
|
+
>
|
|
77
|
+
>;
|
|
78
|
+
messageSearchFilterBuilder: FilterBuilder<
|
|
79
|
+
MessageFilters,
|
|
80
|
+
MergeContext<BuiltInContexts['messageSearch'], TContexts['messageSearchContext']>
|
|
81
|
+
>;
|
|
82
|
+
channelQueryFilterBuilder: FilterBuilder<
|
|
83
|
+
ChannelFilters,
|
|
84
|
+
MergeContext<BuiltInContexts['channelQuery'], TContexts['channelQueryContext']>
|
|
85
|
+
>;
|
|
86
|
+
|
|
87
|
+
constructor(
|
|
88
|
+
client: StreamChat,
|
|
89
|
+
options?: SearchSourceOptions,
|
|
90
|
+
filterBuilderOptions?: MessageSearchSourceFilterBuilderOptions<TContexts>,
|
|
91
|
+
) {
|
|
25
92
|
super(options);
|
|
26
93
|
this.client = client;
|
|
94
|
+
|
|
95
|
+
this.messageSearchChannelFilterBuilder = new FilterBuilder<
|
|
96
|
+
ChannelFilters,
|
|
97
|
+
MergeContext<
|
|
98
|
+
BuiltInContexts['messageSearchChannel'],
|
|
99
|
+
TContexts['messageSearchChannelContext']
|
|
100
|
+
>
|
|
101
|
+
>(filterBuilderOptions?.messageSearchChannel);
|
|
102
|
+
|
|
103
|
+
this.messageSearchFilterBuilder = new FilterBuilder<
|
|
104
|
+
MessageFilters,
|
|
105
|
+
MergeContext<BuiltInContexts['messageSearch'], TContexts['messageSearchContext']>
|
|
106
|
+
>({
|
|
107
|
+
...filterBuilderOptions?.messageSearch,
|
|
108
|
+
initialFilterConfig: {
|
|
109
|
+
text: {
|
|
110
|
+
enabled: true,
|
|
111
|
+
generate: ({ searchQuery }) => (searchQuery ? { text: searchQuery } : null),
|
|
112
|
+
},
|
|
113
|
+
...filterBuilderOptions?.messageSearch?.initialFilterConfig,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
this.channelQueryFilterBuilder = new FilterBuilder<
|
|
118
|
+
ChannelFilters,
|
|
119
|
+
MergeContext<BuiltInContexts['channelQuery'], TContexts['channelQueryContext']>
|
|
120
|
+
>({
|
|
121
|
+
...filterBuilderOptions?.channelQuery,
|
|
122
|
+
initialFilterConfig: {
|
|
123
|
+
cid: {
|
|
124
|
+
enabled: true,
|
|
125
|
+
generate: ({ cids }) => (cids ? { cid: { $in: cids } } : null),
|
|
126
|
+
},
|
|
127
|
+
...filterBuilderOptions?.channelQuery?.initialFilterConfig,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
27
130
|
}
|
|
28
131
|
|
|
29
132
|
protected async query(searchQuery: string) {
|
|
30
|
-
if (!this.client.userID) return { items: [] };
|
|
133
|
+
if (!this.client.userID || !searchQuery || this.next === null) return { items: [] };
|
|
31
134
|
|
|
32
|
-
const channelFilters
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
135
|
+
const channelFilters = this.messageSearchChannelFilterBuilder.buildFilters({
|
|
136
|
+
baseFilters: {
|
|
137
|
+
...(this.client.userID ? { members: { $in: [this.client.userID] } } : {}),
|
|
138
|
+
...this.messageSearchChannelFilters,
|
|
139
|
+
},
|
|
140
|
+
context: { searchQuery } as Partial<
|
|
141
|
+
MergeContext<
|
|
142
|
+
BuiltInContexts['messageSearchChannel'],
|
|
143
|
+
TContexts['messageSearchChannelContext']
|
|
144
|
+
>
|
|
145
|
+
>,
|
|
146
|
+
});
|
|
36
147
|
|
|
37
|
-
const messageFilters: MessageFilters = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
148
|
+
const messageFilters: MessageFilters = this.messageSearchFilterBuilder.buildFilters({
|
|
149
|
+
baseFilters: {
|
|
150
|
+
type: 'regular',
|
|
151
|
+
...this.messageSearchFilters,
|
|
152
|
+
},
|
|
153
|
+
context: { searchQuery } as Partial<
|
|
154
|
+
MergeContext<BuiltInContexts['messageSearch'], TContexts['messageSearchContext']>
|
|
155
|
+
>,
|
|
156
|
+
});
|
|
42
157
|
|
|
43
158
|
const sort: SearchMessageSort = {
|
|
44
159
|
created_at: -1,
|
|
45
160
|
...this.messageSearchSort,
|
|
46
161
|
};
|
|
47
162
|
|
|
48
|
-
const options = {
|
|
163
|
+
const options: SearchOptions = {
|
|
49
164
|
limit: this.pageSize,
|
|
50
165
|
next: this.next,
|
|
51
166
|
sort,
|
|
52
|
-
}
|
|
167
|
+
};
|
|
53
168
|
|
|
54
169
|
const { next, results } = await this.client.search(
|
|
55
170
|
channelFilters,
|
|
@@ -62,15 +177,18 @@ export class MessageSearchSource extends BaseSearchSource<MessageResponse> {
|
|
|
62
177
|
items.reduce((acc, message) => {
|
|
63
178
|
if (message.cid && !this.client.activeChannels[message.cid]) acc.add(message.cid);
|
|
64
179
|
return acc;
|
|
65
|
-
}, new Set<string>()),
|
|
180
|
+
}, new Set<string>()),
|
|
66
181
|
);
|
|
67
|
-
|
|
68
|
-
if (
|
|
182
|
+
|
|
183
|
+
if (cids.length > 0) {
|
|
184
|
+
const channelQueryFilters = this.channelQueryFilterBuilder.buildFilters({
|
|
185
|
+
baseFilters: this.channelQueryFilters,
|
|
186
|
+
context: { cids } as Partial<
|
|
187
|
+
MergeContext<BuiltInContexts['channelQuery'], TContexts['channelQueryContext']>
|
|
188
|
+
>,
|
|
189
|
+
});
|
|
69
190
|
await this.client.queryChannels(
|
|
70
|
-
|
|
71
|
-
cid: { $in: cids },
|
|
72
|
-
...this.channelQueryFilters,
|
|
73
|
-
} as ChannelFilters,
|
|
191
|
+
channelQueryFilters,
|
|
74
192
|
{
|
|
75
193
|
last_message_at: -1,
|
|
76
194
|
...this.channelQuerySort,
|
|
@@ -1,28 +1,65 @@
|
|
|
1
1
|
import { BaseSearchSource } from './BaseSearchSource';
|
|
2
|
+
import { FilterBuilder, type FilterBuilderOptions } from '../pagination';
|
|
2
3
|
import type { StreamChat } from '../client';
|
|
3
4
|
import type { UserFilters, UserOptions, UserResponse, UserSort } from '../types';
|
|
4
5
|
import type { SearchSourceOptions } from './types';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
type CustomContext = Record<string, unknown>;
|
|
8
|
+
|
|
9
|
+
export type UserSearchSourceFilterBuilderContext<
|
|
10
|
+
C extends CustomContext = CustomContext,
|
|
11
|
+
> = { searchQuery?: string } & C;
|
|
12
|
+
|
|
13
|
+
export class UserSearchSource<
|
|
14
|
+
TFilterContext extends CustomContext = CustomContext,
|
|
15
|
+
> extends BaseSearchSource<UserResponse> {
|
|
7
16
|
readonly type = 'users';
|
|
8
|
-
|
|
17
|
+
client: StreamChat;
|
|
9
18
|
filters: UserFilters | undefined;
|
|
10
19
|
sort: UserSort | undefined;
|
|
11
20
|
searchOptions: Omit<UserOptions, 'limit' | 'offset'> | undefined;
|
|
21
|
+
filterBuilder: FilterBuilder<
|
|
22
|
+
UserFilters,
|
|
23
|
+
UserSearchSourceFilterBuilderContext<TFilterContext>
|
|
24
|
+
>;
|
|
12
25
|
|
|
13
|
-
constructor(
|
|
26
|
+
constructor(
|
|
27
|
+
client: StreamChat,
|
|
28
|
+
options?: SearchSourceOptions,
|
|
29
|
+
filterBuilderOptions: FilterBuilderOptions<
|
|
30
|
+
UserFilters,
|
|
31
|
+
UserSearchSourceFilterBuilderContext<TFilterContext>
|
|
32
|
+
> = {},
|
|
33
|
+
) {
|
|
14
34
|
super(options);
|
|
15
35
|
this.client = client;
|
|
36
|
+
this.filterBuilder = new FilterBuilder<
|
|
37
|
+
UserFilters,
|
|
38
|
+
UserSearchSourceFilterBuilderContext<TFilterContext>
|
|
39
|
+
>({
|
|
40
|
+
initialFilterConfig: {
|
|
41
|
+
$or: {
|
|
42
|
+
enabled: true,
|
|
43
|
+
generate: ({ searchQuery }) =>
|
|
44
|
+
searchQuery
|
|
45
|
+
? {
|
|
46
|
+
$or: [
|
|
47
|
+
{ id: { $autocomplete: searchQuery } },
|
|
48
|
+
{ name: { $autocomplete: searchQuery } },
|
|
49
|
+
],
|
|
50
|
+
}
|
|
51
|
+
: null,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
...filterBuilderOptions,
|
|
55
|
+
});
|
|
16
56
|
}
|
|
17
57
|
|
|
18
58
|
protected async query(searchQuery: string) {
|
|
19
|
-
const filters = {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
],
|
|
24
|
-
...this.filters,
|
|
25
|
-
} as UserFilters;
|
|
59
|
+
const filters = this.filterBuilder.buildFilters({
|
|
60
|
+
baseFilters: this.filters,
|
|
61
|
+
context: { searchQuery } as UserSearchSourceFilterBuilderContext<TFilterContext>,
|
|
62
|
+
});
|
|
26
63
|
const sort = { id: 1, ...this.sort } as UserSort;
|
|
27
64
|
const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };
|
|
28
65
|
const { users } = await this.client.queryUsers(filters, sort, options);
|
package/src/search/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from './BaseSearchSource';
|
|
2
2
|
export * from './SearchController';
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
3
|
+
export * from './UserSearchSource';
|
|
4
|
+
export * from './ChannelSearchSource';
|
|
5
|
+
export * from './MessageSearchSource';
|
|
6
6
|
export * from './types';
|
package/src/types.ts
CHANGED
|
@@ -287,6 +287,7 @@ export type ChannelResponse = CustomChannelData & {
|
|
|
287
287
|
last_message_at?: string;
|
|
288
288
|
member_count?: number;
|
|
289
289
|
members?: ChannelMemberResponse[];
|
|
290
|
+
message_count?: number;
|
|
290
291
|
muted?: boolean;
|
|
291
292
|
mute_expires_at?: string;
|
|
292
293
|
own_capabilities?: string[];
|
|
@@ -1445,6 +1446,8 @@ export type Event = CustomEventData & {
|
|
|
1445
1446
|
ai_message?: string;
|
|
1446
1447
|
ai_state?: AIState;
|
|
1447
1448
|
channel?: ChannelResponse;
|
|
1449
|
+
channel_custom?: CustomChannelData;
|
|
1450
|
+
channel_member_count?: number;
|
|
1448
1451
|
channel_id?: string;
|
|
1449
1452
|
channel_type?: string;
|
|
1450
1453
|
cid?: string;
|
|
@@ -2365,6 +2368,7 @@ export type ChannelConfigFields = {
|
|
|
2365
2368
|
replies?: boolean;
|
|
2366
2369
|
search?: boolean;
|
|
2367
2370
|
shared_locations?: boolean;
|
|
2371
|
+
count_messages?: boolean; // Feature flag for message count
|
|
2368
2372
|
typing_events?: boolean;
|
|
2369
2373
|
uploads?: boolean;
|
|
2370
2374
|
url_enrichment?: boolean;
|
package/src/utils.ts
CHANGED
|
@@ -416,6 +416,81 @@ export const toUpdatedMessagePayload = (
|
|
|
416
416
|
};
|
|
417
417
|
};
|
|
418
418
|
|
|
419
|
+
export const toDeletedMessage = ({
|
|
420
|
+
message,
|
|
421
|
+
deletedAt,
|
|
422
|
+
hardDelete = false,
|
|
423
|
+
}: {
|
|
424
|
+
message: LocalMessage | LocalMessageBase;
|
|
425
|
+
deletedAt: LocalMessage['deleted_at'];
|
|
426
|
+
hardDelete: boolean;
|
|
427
|
+
}) => {
|
|
428
|
+
if (hardDelete) {
|
|
429
|
+
/**
|
|
430
|
+
* In case of hard delete, we need to strip down all text, html, attachments and all the custom properties on message
|
|
431
|
+
* The hard-deleted message is kept in the UI until the messages are re-queried
|
|
432
|
+
* FIXME: we are returning an object that does not match LocalMessage | LocalMessageBase
|
|
433
|
+
*/
|
|
434
|
+
return {
|
|
435
|
+
attachments: [],
|
|
436
|
+
cid: message.cid,
|
|
437
|
+
created_at: message.created_at,
|
|
438
|
+
deleted_at: deletedAt,
|
|
439
|
+
id: message.id,
|
|
440
|
+
latest_reactions: [],
|
|
441
|
+
mentioned_users: [],
|
|
442
|
+
own_reactions: [],
|
|
443
|
+
parent_id: message.parent_id,
|
|
444
|
+
reply_count: message.reply_count,
|
|
445
|
+
status: message.status,
|
|
446
|
+
thread_participants: message.thread_participants,
|
|
447
|
+
type: 'deleted' as const,
|
|
448
|
+
updated_at: message.updated_at,
|
|
449
|
+
user: message.user,
|
|
450
|
+
};
|
|
451
|
+
} else {
|
|
452
|
+
return {
|
|
453
|
+
...message,
|
|
454
|
+
attachments: [],
|
|
455
|
+
type: 'deleted',
|
|
456
|
+
deleted_at: deletedAt,
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
export const deleteUserMessages = ({
|
|
462
|
+
messages,
|
|
463
|
+
user,
|
|
464
|
+
hardDelete = false,
|
|
465
|
+
deletedAt,
|
|
466
|
+
}: {
|
|
467
|
+
messages: Array<LocalMessage>;
|
|
468
|
+
user: UserResponse;
|
|
469
|
+
hardDelete: boolean;
|
|
470
|
+
deletedAt: LocalMessage['deleted_at'];
|
|
471
|
+
}) => {
|
|
472
|
+
for (let i = 0; i < messages.length; i++) {
|
|
473
|
+
const message = messages[i];
|
|
474
|
+
if (message.user?.id === user.id) {
|
|
475
|
+
messages[i] =
|
|
476
|
+
message.type === 'deleted'
|
|
477
|
+
? message
|
|
478
|
+
: (toDeletedMessage({ message, hardDelete, deletedAt }) as LocalMessage);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (message.quoted_message?.user?.id === user.id) {
|
|
482
|
+
messages[i].quoted_message =
|
|
483
|
+
message.quoted_message.type === 'deleted'
|
|
484
|
+
? message.quoted_message
|
|
485
|
+
: (toDeletedMessage({
|
|
486
|
+
message: messages[i].quoted_message as LocalMessageBase,
|
|
487
|
+
hardDelete,
|
|
488
|
+
deletedAt,
|
|
489
|
+
}) as LocalMessage);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
|
|
419
494
|
export const findIndexInSortedArray = <T, L>({
|
|
420
495
|
needle,
|
|
421
496
|
sortedArray,
|