stream-chat 9.50.2 → 10.0.0-rc.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.js +18869 -13986
- package/dist/cjs/index.browser.js.map +4 -4
- package/dist/cjs/index.node.js +18888 -13992
- package/dist/cjs/index.node.js.map +4 -4
- package/dist/esm/index.mjs +18866 -13983
- package/dist/esm/index.mjs.map +4 -4
- package/dist/types/ChannelPaginatorsOrchestrator.d.ts +130 -0
- package/dist/types/EventHandlerPipeline.d.ts +104 -0
- package/dist/types/api-client.d.ts +26 -0
- package/dist/types/campaign.d.ts +0 -44
- package/dist/types/channel.d.ts +436 -480
- package/dist/types/channel_batch_updater.d.ts +0 -93
- package/dist/types/channel_manager.d.ts +8 -10
- package/dist/types/channel_state.d.ts +53 -201
- package/dist/types/client.d.ts +440 -1910
- package/dist/types/client_state.d.ts +4 -4
- package/dist/types/configuration/InstanceConfigurationService.d.ts +26 -0
- package/dist/types/configuration/index.d.ts +1 -0
- package/dist/types/configuration/types.d.ts +53 -0
- package/dist/types/connection.d.ts +49 -41
- package/dist/types/connection_fallback.d.ts +6 -4
- package/dist/types/constants.d.ts +0 -4
- package/dist/types/custom_types.d.ts +2 -0
- package/dist/types/errors.d.ts +2 -2
- package/dist/types/gen/chat/ChannelApi.d.ts +45 -0
- package/dist/types/gen/chat/ChatApi.d.ts +334 -0
- package/dist/types/gen/model-decoders/decoders.d.ts +3 -0
- package/dist/types/gen/model-decoders/event-decoder-mapping.d.ts +6 -0
- package/dist/types/gen/models/index.d.ts +8836 -0
- package/dist/types/gen/moderation/ModerationApi.d.ts +50 -0
- package/dist/types/gen-imports.d.ts +3 -0
- package/dist/types/index.d.ts +5 -5
- package/dist/types/insights.d.ts +7 -6
- package/dist/types/logger.d.ts +9 -0
- package/dist/types/messageComposer/LocationComposer.d.ts +7 -4
- package/dist/types/messageComposer/attachmentIdentity.d.ts +2 -2
- package/dist/types/messageComposer/attachmentManager.d.ts +8 -4
- package/dist/types/messageComposer/configuration/types.d.ts +11 -11
- package/dist/types/messageComposer/linkPreviewsManager.d.ts +25 -13
- package/dist/types/messageComposer/messageComposer.d.ts +10 -10
- package/dist/types/messageComposer/middleware/messageComposer/types.d.ts +3 -3
- package/dist/types/messageComposer/middleware/pollComposer/types.d.ts +4 -7
- package/dist/types/messageComposer/middleware/textComposer/commandUtils.d.ts +3 -3
- package/dist/types/messageComposer/middleware/textComposer/commands.d.ts +7 -7
- package/dist/types/messageComposer/middleware/textComposer/mentions.d.ts +218 -4
- package/dist/types/messageComposer/middleware/textComposer/types.d.ts +9 -4
- package/dist/types/messageComposer/pollComposer.d.ts +5 -4
- package/dist/types/messageComposer/textComposer.d.ts +8 -3
- package/dist/types/messageComposer/types.d.ts +6 -28
- package/dist/types/messageDelivery/MessageDeliveryReporter.d.ts +40 -25
- package/dist/types/messageDelivery/MessageReceiptsTracker.d.ts +53 -12
- package/dist/types/messageOperations/MessageOperationStatePolicy.d.ts +19 -0
- package/dist/types/messageOperations/MessageOperations.d.ts +17 -0
- package/dist/types/messageOperations/index.d.ts +3 -0
- package/dist/types/messageOperations/types.d.ts +49 -0
- package/dist/types/moderation.d.ts +21 -203
- package/dist/types/notifications/types.d.ts +8 -7
- package/dist/types/offline-support/offline_support_api.d.ts +110 -87
- package/dist/types/offline-support/types.d.ts +19 -23
- package/dist/types/offline-support/util.d.ts +4 -2
- package/dist/types/pagination/FilterBuilder.d.ts +1 -1
- package/dist/types/pagination/ItemIndex.d.ts +82 -0
- package/dist/types/pagination/cursorDerivation/createdAtAroundPaginationFlags.d.ts +9 -0
- package/dist/types/pagination/cursorDerivation/idAroundPaginationFlags.d.ts +6 -0
- package/dist/types/pagination/cursorDerivation/index.d.ts +1 -0
- package/dist/types/pagination/cursorDerivation/linearPaginationFlags.d.ts +6 -0
- package/dist/types/pagination/filterCompiler.d.ts +7 -0
- package/dist/types/pagination/index.d.ts +1 -3
- package/dist/types/pagination/paginators/BasePaginator.d.ts +709 -0
- package/dist/types/pagination/paginators/ChannelPaginator.d.ts +58 -0
- package/dist/types/pagination/paginators/MessageIntervalPaginator.d.ts +260 -0
- package/dist/types/pagination/paginators/MessagePaginator.d.ts +208 -0
- package/dist/types/pagination/paginators/PinnedMessagePaginator.d.ts +39 -0
- package/dist/types/pagination/paginators/ReminderPaginator.d.ts +19 -0
- package/dist/types/pagination/paginators/UserGroupPaginator.d.ts +24 -0
- package/dist/types/pagination/paginators/index.d.ts +7 -0
- package/dist/types/pagination/sortCompiler.d.ts +49 -0
- package/dist/types/pagination/types.normalization.d.ts +11 -0
- package/dist/types/pagination/utility.normalization.d.ts +18 -0
- package/dist/types/pagination/utility.queryChannel.d.ts +26 -0
- package/dist/types/pagination/utility.search.d.ts +13 -0
- package/dist/types/permissions.d.ts +1 -1
- package/dist/types/poll.d.ts +29 -32
- package/dist/types/poll_manager.d.ts +2 -2
- package/dist/types/reminders/Reminder.d.ts +2 -5
- package/dist/types/reminders/ReminderManager.d.ts +2 -9
- package/dist/types/search/MessageSearchSource.d.ts +4 -4
- package/dist/types/search/UserSearchSource.d.ts +1 -1
- package/dist/types/search/types.d.ts +3 -3
- package/dist/types/segment.d.ts +0 -34
- package/dist/types/signing.d.ts +105 -65
- package/dist/types/store.d.ts +1 -0
- package/dist/types/thread.d.ts +51 -34
- package/dist/types/thread_manager.d.ts +3 -3
- package/dist/types/token_manager.d.ts +15 -10
- package/dist/types/types.d.ts +196 -3384
- package/dist/types/utils/FixedSizeQueueCache.d.ts +12 -6
- package/dist/types/utils/WithSubscriptions.d.ts +2 -1
- package/dist/types/utils/concurrency.d.ts +4 -4
- package/dist/types/utils/mergeWith/mergeWith.d.ts +3 -3
- package/dist/types/utils/mergeWith/mergeWithCore.d.ts +8 -3
- package/dist/types/utils/retryable.d.ts +34 -0
- package/dist/types/utils.d.ts +104 -137
- package/package.json +7 -3
- package/src/ChannelPaginatorsOrchestrator.ts +545 -0
- package/src/CooldownTimer.ts +2 -2
- package/src/EventHandlerPipeline.ts +228 -0
- package/src/LiveLocationManager.ts +12 -11
- package/src/api-client.ts +275 -0
- package/src/campaign.ts +1 -77
- package/src/channel.ts +1262 -1277
- package/src/channel_batch_updater.ts +1 -211
- package/src/channel_manager.ts +92 -88
- package/src/channel_state.ts +144 -1013
- package/src/client.ts +888 -3944
- package/src/client_state.ts +4 -4
- package/src/configuration/InstanceConfigurationService.ts +73 -0
- package/src/configuration/index.ts +1 -0
- package/src/configuration/types.ts +81 -0
- package/src/connection.ts +145 -94
- package/src/connection_fallback.ts +29 -27
- package/src/constants.ts +1 -5
- package/src/custom_types.ts +4 -1
- package/src/errors.ts +2 -2
- package/src/gen/chat/ChannelApi.ts +275 -0
- package/src/gen/chat/ChatApi.ts +2554 -0
- package/src/gen/model-decoders/decoders.ts +2680 -0
- package/src/gen/model-decoders/event-decoder-mapping.ts +198 -0
- package/src/gen/models/index.ts +12673 -0
- package/src/gen/moderation/ModerationApi.ts +607 -0
- package/src/gen-imports.ts +3 -0
- package/src/index.ts +5 -10
- package/src/insights.ts +6 -5
- package/src/logger.ts +28 -0
- package/src/messageComposer/LocationComposer.ts +9 -5
- package/src/messageComposer/MessageComposerEffectHandlers.ts +1 -0
- package/src/messageComposer/attachmentIdentity.ts +16 -9
- package/src/messageComposer/attachmentManager.ts +13 -8
- package/src/messageComposer/configuration/types.ts +11 -11
- package/src/messageComposer/linkPreviewsManager.ts +9 -10
- package/src/messageComposer/messageComposer.ts +57 -53
- package/src/messageComposer/middleware/messageComposer/attachments.ts +1 -2
- package/src/messageComposer/middleware/messageComposer/cleanData.ts +1 -1
- package/src/messageComposer/middleware/messageComposer/compositionValidation.ts +2 -2
- package/src/messageComposer/middleware/messageComposer/messageComposerState.ts +2 -2
- package/src/messageComposer/middleware/messageComposer/sharedLocation.ts +4 -3
- package/src/messageComposer/middleware/messageComposer/textComposer.ts +2 -2
- package/src/messageComposer/middleware/messageComposer/types.ts +3 -4
- package/src/messageComposer/middleware/messageComposer/userDataInjection.ts +9 -5
- package/src/messageComposer/middleware/pollComposer/state.ts +0 -2
- package/src/messageComposer/middleware/pollComposer/types.ts +4 -7
- package/src/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.ts +10 -1
- package/src/messageComposer/middleware/textComposer/commandEffects.ts +4 -4
- package/src/messageComposer/middleware/textComposer/commandUtils.ts +3 -6
- package/src/messageComposer/middleware/textComposer/commands.ts +3 -3
- package/src/messageComposer/middleware/textComposer/mentionUtils.ts +1 -1
- package/src/messageComposer/middleware/textComposer/mentions.ts +31 -15
- package/src/messageComposer/middleware/textComposer/types.ts +9 -4
- package/src/messageComposer/pollComposer.ts +6 -8
- package/src/messageComposer/textComposer.ts +27 -2
- package/src/messageComposer/types.ts +6 -28
- package/src/messageDelivery/MessageDeliveryReporter.ts +101 -45
- package/src/messageDelivery/MessageReceiptsTracker.ts +294 -21
- package/src/messageOperations/MessageOperationStatePolicy.ts +77 -0
- package/src/messageOperations/MessageOperations.ts +212 -0
- package/src/messageOperations/index.ts +10 -0
- package/src/messageOperations/types.ts +64 -0
- package/src/moderation.ts +38 -431
- package/src/notifications/types.ts +8 -7
- package/src/offline-support/offline_support_api.ts +198 -132
- package/src/offline-support/offline_sync_manager.ts +17 -7
- package/src/offline-support/types.ts +23 -26
- package/src/offline-support/util.ts +5 -4
- package/src/pagination/FilterBuilder.ts +4 -1
- package/src/pagination/ItemIndex.ts +112 -0
- package/src/pagination/cursorDerivation/createdAtAroundPaginationFlags.ts +73 -0
- package/src/pagination/cursorDerivation/idAroundPaginationFlags.ts +53 -0
- package/src/pagination/cursorDerivation/index.ts +1 -0
- package/src/pagination/cursorDerivation/linearPaginationFlags.ts +86 -0
- package/src/pagination/filterCompiler.ts +196 -0
- package/src/pagination/index.ts +1 -3
- package/src/pagination/paginators/BasePaginator.ts +2393 -0
- package/src/pagination/paginators/ChannelPaginator.ts +427 -0
- package/src/pagination/paginators/MessageIntervalPaginator.ts +1073 -0
- package/src/pagination/paginators/MessagePaginator.ts +496 -0
- package/src/pagination/paginators/PinnedMessagePaginator.ts +105 -0
- package/src/pagination/paginators/ReminderPaginator.ts +105 -0
- package/src/pagination/paginators/UserGroupPaginator.ts +125 -0
- package/src/pagination/paginators/index.ts +7 -0
- package/src/pagination/sortCompiler.ts +178 -0
- package/src/pagination/types.normalization.ts +14 -0
- package/src/pagination/utility.normalization.ts +106 -0
- package/src/pagination/utility.queryChannel.ts +84 -0
- package/src/pagination/utility.search.ts +80 -0
- package/src/permissions.ts +7 -8
- package/src/poll.ts +101 -110
- package/src/poll_manager.ts +14 -8
- package/src/reminders/Reminder.ts +2 -5
- package/src/reminders/ReminderManager.ts +19 -21
- package/src/search/BaseSearchSource.ts +0 -3
- package/src/search/ChannelMemberSearchSource.ts +7 -1
- package/src/search/ChannelSearchSource.ts +10 -3
- package/src/search/MessageSearchSource.ts +29 -30
- package/src/search/UserSearchSource.ts +12 -8
- package/src/search/types.ts +3 -4
- package/src/segment.ts +1 -95
- package/src/signing.ts +107 -67
- package/src/store.ts +2 -1
- package/src/thread.ts +439 -236
- package/src/thread_manager.ts +36 -15
- package/src/token_manager.ts +21 -10
- package/src/types.ts +375 -4524
- package/src/uploadManager.ts +8 -0
- package/src/utils/FixedSizeQueueCache.ts +12 -6
- package/src/utils/WithSubscriptions.ts +2 -1
- package/src/utils/concurrency.ts +4 -4
- package/src/utils/mergeWith/mergeWith.ts +3 -3
- package/src/utils/mergeWith/mergeWithCore.ts +140 -164
- package/src/utils/mergeWith/mergeWithDiff.ts +3 -3
- package/src/utils/retryable.ts +117 -0
- package/src/utils.ts +133 -524
- package/dist/types/events.d.ts +0 -72
- package/dist/types/pagination/BasePaginator.d.ts +0 -69
- package/dist/types/pagination/ReminderPaginator.d.ts +0 -16
- package/dist/types/pagination/UserGroupPaginator.d.ts +0 -21
- package/src/events.ts +0 -75
- package/src/pagination/BasePaginator.ts +0 -184
- package/src/pagination/ReminderPaginator.ts +0 -56
- package/src/pagination/UserGroupPaginator.ts +0 -93
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
2
|
+
APIError,
|
|
3
3
|
ChannelResponse,
|
|
4
4
|
Event,
|
|
5
|
+
EventPayload,
|
|
6
|
+
EventType,
|
|
5
7
|
LocalMessage,
|
|
6
|
-
|
|
8
|
+
MessageRequest,
|
|
7
9
|
MessageResponse,
|
|
10
|
+
OwnUserResponse,
|
|
11
|
+
RequireLiteral,
|
|
8
12
|
} from '../types';
|
|
9
13
|
|
|
10
14
|
import type {
|
|
@@ -17,15 +21,20 @@ import { OfflineError } from './types';
|
|
|
17
21
|
import type { StreamChat } from '../client';
|
|
18
22
|
import type { AxiosError } from 'axios';
|
|
19
23
|
import { OfflineDBSyncManager } from './offline_sync_manager';
|
|
24
|
+
import { chatLoggerSystem } from '../logger';
|
|
20
25
|
import { StateStore } from '../store';
|
|
21
26
|
import {
|
|
22
27
|
channelHasReadEvents,
|
|
23
28
|
channelTracksReadLocally,
|
|
29
|
+
formatMessage,
|
|
24
30
|
localMessageToNewMessagePayload,
|
|
25
31
|
runDetached,
|
|
26
32
|
} from '../utils';
|
|
27
33
|
import { isMessageUpdateReplayable } from './util';
|
|
28
34
|
|
|
35
|
+
const logger = chatLoggerSystem.getLogger('offline-db');
|
|
36
|
+
import type { WSEvent } from '../gen/models';
|
|
37
|
+
|
|
29
38
|
/**
|
|
30
39
|
* Abstract base class for an offline database implementation used with StreamChat.
|
|
31
40
|
*
|
|
@@ -45,12 +54,11 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
45
54
|
this.syncManager = new OfflineDBSyncManager({ client, offlineDb: this });
|
|
46
55
|
this.state = new StateStore<OfflineDBState>({
|
|
47
56
|
initialized: false,
|
|
48
|
-
userId: this.client.
|
|
57
|
+
userId: this.client.userId,
|
|
49
58
|
});
|
|
50
59
|
}
|
|
51
60
|
|
|
52
61
|
/**
|
|
53
|
-
* @abstract
|
|
54
62
|
* Inserts a reaction into the DB.
|
|
55
63
|
* Will write to:
|
|
56
64
|
* - The reactions table with the new reaction
|
|
@@ -58,24 +66,24 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
58
66
|
* - The users table with any users associated
|
|
59
67
|
* Will return the prepared queries for delayed execution (even if they are
|
|
60
68
|
* already executed).
|
|
69
|
+
*
|
|
61
70
|
* @param {DBInsertReactionType} options
|
|
62
71
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
63
72
|
*/
|
|
64
73
|
abstract insertReaction: OfflineDBApi['insertReaction'];
|
|
65
74
|
|
|
66
75
|
/**
|
|
67
|
-
* @abstract
|
|
68
76
|
* Upserts the list of CIDs for a filter + sort query hash.
|
|
69
77
|
* Will write to only the table containing the cids.
|
|
70
78
|
* Will return the prepared queries for delayed execution (even if they are
|
|
71
79
|
* already executed).
|
|
80
|
+
*
|
|
72
81
|
* @param {DBUpsertCidsForQueryType} options
|
|
73
82
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
74
83
|
*/
|
|
75
84
|
abstract upsertCidsForQuery: OfflineDBApi['upsertCidsForQuery'];
|
|
76
85
|
|
|
77
86
|
/**
|
|
78
|
-
* @abstract
|
|
79
87
|
* Upserts the channels passed as an argument within the DB. Relies on
|
|
80
88
|
* writing the properties we need from a ChannelResponse into the adequate
|
|
81
89
|
* tables.
|
|
@@ -89,72 +97,72 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
89
97
|
* - The reads table for each user
|
|
90
98
|
* Will return the prepared queries for delayed execution (even if they are
|
|
91
99
|
* already executed).
|
|
100
|
+
*
|
|
92
101
|
* @param {DBUpsertChannelsType} options
|
|
93
102
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
94
103
|
*/
|
|
95
104
|
abstract upsertChannels: OfflineDBApi['upsertChannels'];
|
|
96
105
|
|
|
97
106
|
/**
|
|
98
|
-
* @abstract
|
|
99
107
|
* Upserts the current active user's sync status.
|
|
100
108
|
* Will only write to the sync status table.
|
|
101
109
|
* Will return the prepared queries for delayed execution (even if they are
|
|
102
110
|
* already executed).
|
|
111
|
+
*
|
|
103
112
|
* @param {DBUpsertUserSyncStatusType} options
|
|
104
113
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
105
114
|
*/
|
|
106
115
|
abstract upsertUserSyncStatus: OfflineDBApi['upsertUserSyncStatus'];
|
|
107
116
|
|
|
108
117
|
/**
|
|
109
|
-
* @abstract
|
|
110
118
|
* Upserts the app settings for the current Stream App into the DB. It
|
|
111
119
|
* is only intended to be run once per lifecycle of the app.
|
|
112
120
|
* Will only write to the respective app settings table.
|
|
113
121
|
* Will return the prepared queries for delayed execution (even if they are
|
|
114
122
|
* already executed).
|
|
123
|
+
*
|
|
115
124
|
* @param {DBUpsertAppSettingsType} options
|
|
116
125
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
117
126
|
*/
|
|
118
127
|
abstract upsertAppSettings: OfflineDBApi['upsertAppSettings'];
|
|
119
128
|
|
|
120
129
|
/**
|
|
121
|
-
* @abstract
|
|
122
130
|
* Upserts a poll fully in the DB.
|
|
123
131
|
* Will write to the polls table. It should not update the message
|
|
124
132
|
* associated due to how the poll state works.
|
|
125
133
|
* Will return the prepared queries for delayed execution (even if they are
|
|
126
134
|
* already executed).
|
|
135
|
+
*
|
|
127
136
|
* @param {DBUpsertPollType} options
|
|
128
137
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
129
138
|
*/
|
|
130
139
|
abstract upsertPoll: OfflineDBApi['upsertPoll'];
|
|
131
140
|
|
|
132
141
|
/**
|
|
133
|
-
* @abstract
|
|
134
142
|
* Upserts only the channel.data for the provided channels in the DB.
|
|
135
143
|
* Will only write to the channels table.
|
|
136
144
|
* Will return the prepared queries for delayed execution (even if they are
|
|
137
145
|
* already executed).
|
|
146
|
+
*
|
|
138
147
|
* @param {DBUpsertChannelDataType} options
|
|
139
148
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
140
149
|
*/
|
|
141
150
|
abstract upsertChannelData: OfflineDBApi['upsertChannelData'];
|
|
142
151
|
|
|
143
152
|
/**
|
|
144
|
-
* @abstract
|
|
145
153
|
* Upserts the provided reads in the DB.
|
|
146
154
|
* Will write to:
|
|
147
155
|
* - The reads table
|
|
148
156
|
* - The users table for each user associated with a read
|
|
149
157
|
* Will return the prepared queries for delayed execution (even if they are
|
|
150
158
|
* already executed).
|
|
159
|
+
*
|
|
151
160
|
* @param {DBUpsertReadsType} options
|
|
152
161
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
153
162
|
*/
|
|
154
163
|
abstract upsertReads: OfflineDBApi['upsertReads'];
|
|
155
164
|
|
|
156
165
|
/**
|
|
157
|
-
* @abstract
|
|
158
166
|
* Upserts the messages in the DB.
|
|
159
167
|
* Will write to:
|
|
160
168
|
* - The messages table
|
|
@@ -164,287 +172,288 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
164
172
|
* - The users table
|
|
165
173
|
* Will return the prepared queries for delayed execution (even if they are
|
|
166
174
|
* already executed).
|
|
175
|
+
*
|
|
167
176
|
* @param {DBUpsertMessagesType} options
|
|
168
177
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
169
178
|
*/
|
|
170
179
|
abstract upsertMessages: OfflineDBApi['upsertMessages'];
|
|
171
180
|
|
|
172
181
|
/**
|
|
173
|
-
* @abstract
|
|
174
182
|
* Upserts the members in the DB.
|
|
175
183
|
* Will write to:
|
|
176
184
|
* - The users table (for each user associated with a member)
|
|
177
185
|
* - The members table
|
|
178
186
|
* Will return the prepared queries for delayed execution (even if they are
|
|
179
187
|
* already executed).
|
|
188
|
+
*
|
|
180
189
|
* @param {DBUpsertMembersType} options
|
|
181
190
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
182
191
|
*/
|
|
183
192
|
abstract upsertMembers: OfflineDBApi['upsertMembers'];
|
|
184
193
|
|
|
185
194
|
/**
|
|
186
|
-
* @abstract
|
|
187
195
|
* Updates a reaction in the DB. Will update the DB the same way
|
|
188
196
|
* a reaction.updated event would (it assumes enforce_unique is true
|
|
189
197
|
* and removes all other reactions associated with the user.
|
|
190
198
|
* Will write to the reactions table.
|
|
191
199
|
* Will return the prepared queries for delayed execution (even if they are
|
|
192
200
|
* already executed).
|
|
201
|
+
*
|
|
193
202
|
* @param {DBUpdateReactionType} options
|
|
194
203
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
195
204
|
*/
|
|
196
205
|
abstract updateReaction: OfflineDBApi['updateReaction'];
|
|
197
206
|
|
|
198
207
|
/**
|
|
199
|
-
* @abstract
|
|
200
208
|
* Updates a single message in the DB. This is used as a faster
|
|
201
209
|
* alternative to upsertMessages with more optimized queries.
|
|
202
210
|
* Will write to the messages table.
|
|
203
211
|
* Will return the prepared queries for delayed execution (even if they are
|
|
204
212
|
* already executed).
|
|
213
|
+
*
|
|
205
214
|
* @param {DBUpdateMessageType} options
|
|
206
215
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
207
216
|
*/
|
|
208
217
|
abstract updateMessage: OfflineDBApi['updateMessage'];
|
|
209
218
|
|
|
210
219
|
/**
|
|
211
|
-
* @abstract
|
|
212
220
|
* Fetches the provided draft from the DB. Should return as close to
|
|
213
221
|
* the server side DraftResponse as possible.
|
|
222
|
+
*
|
|
214
223
|
* @param {DBGetDraftType} options
|
|
215
224
|
* @returns {Promise<DraftResponse | null>}
|
|
216
225
|
*/
|
|
217
226
|
abstract getDraft: OfflineDBApi['getDraft'];
|
|
218
227
|
/**
|
|
219
|
-
* @abstract
|
|
220
228
|
* Upserts a draft in the DB.
|
|
221
229
|
* Will write to the draft table upserting the draft.
|
|
222
230
|
* Will return the prepared queries for delayed execution (even if they are
|
|
223
231
|
* already executed).
|
|
232
|
+
*
|
|
224
233
|
* @param {DBUpsertDraftType} options
|
|
225
234
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
226
235
|
*/
|
|
227
236
|
abstract upsertDraft: OfflineDBApi['upsertDraft'];
|
|
228
237
|
/**
|
|
229
|
-
* @abstract
|
|
230
238
|
* Deletes a draft from the DB.
|
|
231
239
|
* Will write to the draft table removing the draft.
|
|
232
240
|
* Will return the prepared queries for delayed execution (even if they are
|
|
233
241
|
* already executed).
|
|
242
|
+
*
|
|
234
243
|
* @param {DBDeleteDraftType} options
|
|
235
244
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
236
245
|
*/
|
|
237
246
|
abstract deleteDraft: OfflineDBApi['deleteDraft'];
|
|
238
247
|
|
|
239
248
|
/**
|
|
240
|
-
* @abstract
|
|
241
249
|
* Fetches the provided channels from the DB and aggregates all data associated
|
|
242
|
-
* with them in a single
|
|
250
|
+
* with them in a single ChannelStateResponseFields. The implementation itself is responsible
|
|
243
251
|
* for aggregating and serialization of all of the data. Should return as close to
|
|
244
|
-
* the server side
|
|
252
|
+
* the server side ChannelStateResponseFields as possible.
|
|
253
|
+
*
|
|
245
254
|
* @param {DBGetChannelsType} options
|
|
246
|
-
* @returns {Promise<Omit<
|
|
255
|
+
* @returns {Promise<Omit<ChannelStateResponseFields, 'duration'>[] | null>}
|
|
247
256
|
*/
|
|
248
257
|
abstract getChannels: OfflineDBApi['getChannels'];
|
|
249
258
|
|
|
250
259
|
/**
|
|
251
|
-
* @abstract
|
|
252
260
|
* Fetches the channels from the DB that were the last known response to a filters & sort
|
|
253
|
-
* hash as a query and aggregates all data associated with them in a single
|
|
261
|
+
* hash as a query and aggregates all data associated with them in a single ChannelStateResponseFields.
|
|
254
262
|
* The implementation itself is responsible for aggregating and serialization of all of the data.
|
|
255
|
-
* Should return as close to the server side
|
|
263
|
+
* Should return as close to the server side ChannelStateResponseFields as possible.
|
|
264
|
+
*
|
|
256
265
|
* @param {DBGetChannelsForQueryType} options
|
|
257
|
-
* @returns {Promise<Omit<
|
|
266
|
+
* @returns {Promise<Omit<ChannelStateResponseFields, 'duration'>[] | null>}
|
|
258
267
|
*/
|
|
259
268
|
abstract getChannelsForQuery: OfflineDBApi['getChannelsForQuery'];
|
|
260
269
|
|
|
261
270
|
/**
|
|
262
|
-
* @abstract
|
|
263
271
|
* Will return a list of all available CIDs in the DB. The same can be achieved
|
|
264
272
|
* by fetching all channels, however this is meant to be much faster as a query.
|
|
273
|
+
*
|
|
265
274
|
* @returns {Promise<string[]>}
|
|
266
275
|
*/
|
|
267
276
|
abstract getAllChannelCids: OfflineDBApi['getAllChannelCids'];
|
|
268
277
|
|
|
269
278
|
/**
|
|
270
|
-
* @abstract
|
|
271
279
|
* Fetches the timestamp of the last sync of the DB.
|
|
280
|
+
*
|
|
272
281
|
* @param {DBGetLastSyncedAtType} options
|
|
273
282
|
* @returns {Promise<string | undefined>}
|
|
274
283
|
*/
|
|
275
284
|
abstract getLastSyncedAt: OfflineDBApi['getLastSyncedAt'];
|
|
276
285
|
|
|
277
286
|
/**
|
|
278
|
-
* @abstract
|
|
279
287
|
* Fetches all pending tasks from the DB. It will return them in an
|
|
280
288
|
* ordered fashion by the time they were created.
|
|
289
|
+
*
|
|
281
290
|
* @param {DBGetPendingTasksType} [conditions]
|
|
282
291
|
* @returns {Promise<PendingTask[]>}
|
|
283
292
|
*/
|
|
284
293
|
abstract getPendingTasks: OfflineDBApi['getPendingTasks'];
|
|
285
294
|
|
|
286
295
|
/**
|
|
287
|
-
* @abstract
|
|
288
296
|
* Fetches the app settings stored in the DB. Is mainly meant to be used
|
|
289
297
|
* only while offline and opening the application, as we only update the
|
|
290
298
|
* app settings whenever they are fetched again so it has the potential to
|
|
291
299
|
* be stale.
|
|
300
|
+
*
|
|
292
301
|
* @param {DBGetAppSettingsType} options
|
|
293
|
-
* @returns {Promise<
|
|
302
|
+
* @returns {Promise<GetApplicationResponse | null>}
|
|
294
303
|
*/
|
|
295
304
|
abstract getAppSettings: OfflineDBApi['getAppSettings'];
|
|
296
305
|
|
|
297
306
|
/**
|
|
298
|
-
* @abstract
|
|
299
307
|
* Fetches reactions from the DB for a given filter & sort hash and
|
|
300
308
|
* for a given message ID.
|
|
309
|
+
*
|
|
301
310
|
* @param {DBGetReactionsType} options
|
|
302
311
|
* @returns {Promise<ReactionResponse[] | null>}
|
|
303
312
|
*/
|
|
304
313
|
abstract getReactions: OfflineDBApi['getReactions'];
|
|
305
314
|
|
|
306
315
|
/**
|
|
307
|
-
* @abstract
|
|
308
316
|
* Executes multiple queries in a batched fashion. It will also be done
|
|
309
317
|
* within a transaction.
|
|
318
|
+
*
|
|
310
319
|
* @param {ExecuteBatchDBQueriesType} queries
|
|
311
320
|
* @returns {Promise<unknown>}
|
|
312
321
|
*/
|
|
313
322
|
abstract executeSqlBatch: OfflineDBApi['executeSqlBatch'];
|
|
314
323
|
|
|
315
324
|
/**
|
|
316
|
-
* @abstract
|
|
317
325
|
* Adds a pending task to the pending tasks table. Can only be one of the
|
|
318
326
|
* supported types of pending tasks, otherwise its execution will throw.
|
|
319
327
|
* Will return the prepared queries for delayed execution (even if they are
|
|
320
328
|
* already executed).
|
|
329
|
+
*
|
|
321
330
|
* @param {PendingTask} task
|
|
322
331
|
* @returns {Promise<() => Promise<void>>}
|
|
323
332
|
*/
|
|
324
333
|
abstract addPendingTask: OfflineDBApi['addPendingTask'];
|
|
325
334
|
|
|
326
335
|
/**
|
|
327
|
-
* @abstract
|
|
328
336
|
* Updates a pending task in the DB, given its ID.
|
|
329
337
|
* Will return the prepared queries for delayed execution (even if they are
|
|
330
338
|
* already executed).
|
|
339
|
+
*
|
|
331
340
|
* @param {DBUpdatePendingTaskType} options
|
|
332
341
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
333
342
|
*/
|
|
334
343
|
abstract updatePendingTask: OfflineDBApi['updatePendingTask'];
|
|
335
344
|
|
|
336
345
|
/**
|
|
337
|
-
* @abstract
|
|
338
346
|
* Deletes a pending task from the DB, given its ID.
|
|
339
347
|
* Will return the prepared queries for delayed execution (even if they are
|
|
340
348
|
* already executed).
|
|
349
|
+
*
|
|
341
350
|
* @param {DBDeletePendingTaskType} options
|
|
342
351
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
343
352
|
*/
|
|
344
353
|
abstract deletePendingTask: OfflineDBApi['deletePendingTask'];
|
|
345
354
|
|
|
346
355
|
/**
|
|
347
|
-
* @abstract
|
|
348
356
|
* Deletes a reaction from the DB.
|
|
349
357
|
* Will write to the reactions table removing the reaction.
|
|
350
358
|
* Will return the prepared queries for delayed execution (even if they are
|
|
351
359
|
* already executed).
|
|
360
|
+
*
|
|
352
361
|
* @param {DBDeleteReactionType} options
|
|
353
362
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
354
363
|
*/
|
|
355
364
|
abstract deleteReaction: OfflineDBApi['deleteReaction'];
|
|
356
365
|
|
|
357
366
|
/**
|
|
358
|
-
* @abstract
|
|
359
367
|
* Deletes a member from the DB.
|
|
360
368
|
* Will only write to the members table.
|
|
361
369
|
* Will return the prepared queries for delayed execution (even if they are
|
|
362
370
|
* already executed).
|
|
371
|
+
*
|
|
363
372
|
* @param {DBDeleteMemberType} options
|
|
364
373
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
365
374
|
*/
|
|
366
375
|
abstract deleteMember: OfflineDBApi['deleteMember'];
|
|
367
376
|
|
|
368
377
|
/**
|
|
369
|
-
* @abstract
|
|
370
378
|
* Deletes a channel from the DB.
|
|
371
379
|
* It will also delete all other entities associated with the channel in
|
|
372
380
|
* a cascading fashion (messages, reactions, members etc.).
|
|
373
381
|
* Will return the prepared queries for delayed execution (even if they are
|
|
374
382
|
* already executed).
|
|
383
|
+
*
|
|
375
384
|
* @param {DBDeleteChannelType} options
|
|
376
385
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
377
386
|
*/
|
|
378
387
|
abstract deleteChannel: OfflineDBApi['deleteChannel'];
|
|
379
388
|
|
|
380
389
|
/**
|
|
381
|
-
* @abstract
|
|
382
390
|
* Deletes multiple messages for a given channel. Works as `channel.truncated` would.
|
|
383
391
|
* Should remove entities primarily from the messages table and then from all associated
|
|
384
392
|
* tables in a cascading fashion (reactions, polls etc.).
|
|
385
393
|
* Will return the prepared queries for delayed execution (even if they are
|
|
386
394
|
* already executed).
|
|
395
|
+
*
|
|
387
396
|
* @param {DBDeleteMessagesForChannelType} options
|
|
388
397
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
389
398
|
*/
|
|
390
399
|
abstract deleteMessagesForChannel: OfflineDBApi['deleteMessagesForChannel'];
|
|
391
400
|
|
|
392
401
|
/**
|
|
393
|
-
* @abstract
|
|
394
402
|
* Deletes all pending tasks from the DB.
|
|
395
403
|
* Will only update the pending tasks table.
|
|
396
404
|
* Will return the prepared queries for delayed execution (even if they are
|
|
397
405
|
* already executed).
|
|
406
|
+
*
|
|
398
407
|
* @param {DBDropPendingTasksType} options
|
|
399
408
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
400
409
|
*/
|
|
401
410
|
abstract dropPendingTasks: OfflineDBApi['dropPendingTasks'];
|
|
402
411
|
|
|
403
412
|
/**
|
|
404
|
-
* @abstract
|
|
405
413
|
* Deletes a message from the DB.
|
|
406
414
|
* All other entities associated with the message will also be deleted
|
|
407
415
|
* in a cascading fashion (reactions, polls etc.).
|
|
408
416
|
* Will return the prepared queries for delayed execution (even if they are
|
|
409
417
|
* already executed).
|
|
418
|
+
*
|
|
410
419
|
* @param {DBDeleteMessageType} options
|
|
411
420
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
412
421
|
*/
|
|
413
422
|
abstract hardDeleteMessage: OfflineDBApi['hardDeleteMessage'];
|
|
414
423
|
|
|
415
424
|
/**
|
|
416
|
-
* @abstract
|
|
417
425
|
* Updates a message with a deleted_at value in the DB.
|
|
418
426
|
* Will only update the messages table, as the message is simply marked
|
|
419
427
|
* as deleted and not removed from the DB.
|
|
420
428
|
* Will return the prepared queries for delayed execution (even if they are
|
|
421
429
|
* already executed).
|
|
430
|
+
*
|
|
422
431
|
* @param {DBDeleteMessageType} options
|
|
423
432
|
* @returns {Promise<ExecuteBatchDBQueriesType>}
|
|
424
433
|
*/
|
|
425
434
|
abstract softDeleteMessage: OfflineDBApi['softDeleteMessage'];
|
|
426
435
|
|
|
427
436
|
/**
|
|
428
|
-
* @abstract
|
|
429
437
|
* Drops all tables and reinitializes the connection to the DB.
|
|
438
|
+
*
|
|
430
439
|
* @returns {Promise<unknown>}
|
|
431
440
|
*/
|
|
432
441
|
abstract resetDB: OfflineDBApi['resetDB'];
|
|
433
442
|
|
|
434
443
|
/**
|
|
435
|
-
* @abstract
|
|
436
444
|
* A utility query that checks whether a specific channel exists in the DB.
|
|
437
445
|
* Technically the same as actually fetching that channel through other queries,
|
|
438
446
|
* but much faster.
|
|
447
|
+
*
|
|
439
448
|
* @param {DBChannelExistsType} options
|
|
440
449
|
* @returns {Promise<boolean>}
|
|
441
450
|
*/
|
|
442
451
|
abstract channelExists: OfflineDBApi['channelExists'];
|
|
443
452
|
|
|
444
453
|
/**
|
|
445
|
-
* @abstract
|
|
446
454
|
* Initializes the DB (typically creating a simple file handle as a connection pointer for
|
|
447
455
|
* SQLite and likely similar for other DBs).
|
|
456
|
+
*
|
|
448
457
|
* @returns {Promise<boolean>}
|
|
449
458
|
*/
|
|
450
459
|
abstract initializeDB: OfflineDBApi['initializeDB'];
|
|
@@ -452,6 +461,7 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
452
461
|
/**
|
|
453
462
|
* Initializes the DB as well as its syncManager for a given userId.
|
|
454
463
|
* It will update the DBs reactive state with initialization values.
|
|
464
|
+
*
|
|
455
465
|
* @param userId - the user ID for which we want to initialize
|
|
456
466
|
*/
|
|
457
467
|
public init = async (userId: string) => {
|
|
@@ -469,13 +479,16 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
469
479
|
}
|
|
470
480
|
} catch (error) {
|
|
471
481
|
this.state.partialNext({ initialized: false, userId: undefined });
|
|
472
|
-
|
|
482
|
+
logger
|
|
483
|
+
.withExtraTags('init')
|
|
484
|
+
.error('Failed to initialize the offline database.', { error });
|
|
473
485
|
}
|
|
474
486
|
};
|
|
475
487
|
|
|
476
488
|
/**
|
|
477
489
|
* Checks whether the DB should be initialized or if it has been initialized already.
|
|
478
|
-
*
|
|
490
|
+
*
|
|
491
|
+
* @param userId - the user ID for which we want to check initialization
|
|
479
492
|
*/
|
|
480
493
|
public shouldInitialize(userId: string): boolean {
|
|
481
494
|
const { userId: userIdFromState, initialized } = this.state.getLatestValue();
|
|
@@ -487,6 +500,7 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
487
500
|
* passed uses a reference to the DB itself and will handle errors gracefully
|
|
488
501
|
* and silently. Only really meant to be used for write queries that need to
|
|
489
502
|
* be run in synchronous functions.
|
|
503
|
+
*
|
|
490
504
|
* @param queryCallback - a callback wrapping all query logic that is to be executed
|
|
491
505
|
* @param method - a utility parameter used for proper logging (will make sure the method
|
|
492
506
|
* is logged on failure)
|
|
@@ -515,21 +529,29 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
515
529
|
* If both fail, it will not execute the query as it would result in a foreign key constraint
|
|
516
530
|
* error.
|
|
517
531
|
*
|
|
518
|
-
* @param event -
|
|
519
|
-
* @param execute -
|
|
520
|
-
* @param forceUpdate -
|
|
521
|
-
* @param createQueries -
|
|
532
|
+
* @param event - The WS event we are trying to process.
|
|
533
|
+
* @param event.execute - Whether to immediately execute the operation (optional, defaults to `true`).
|
|
534
|
+
* @param event.forceUpdate - Whether to upsert the channel data anyway (optional, defaults to `false`).
|
|
535
|
+
* @param createQueries - A callback that creates the queries to execute.
|
|
536
|
+
* @returns The list of prepared queries (executed when `execute` is `true`).
|
|
522
537
|
*/
|
|
523
538
|
public queriesWithChannelGuard = async (
|
|
524
539
|
{
|
|
525
540
|
event,
|
|
526
541
|
execute = true,
|
|
527
542
|
forceUpdate = false,
|
|
528
|
-
}: {
|
|
543
|
+
}: {
|
|
544
|
+
event: Extract<
|
|
545
|
+
Event,
|
|
546
|
+
{ channel?: any; cid?: any; channel_type?: any; channel_id?: any }
|
|
547
|
+
>;
|
|
548
|
+
execute?: boolean;
|
|
549
|
+
forceUpdate?: boolean;
|
|
550
|
+
},
|
|
529
551
|
createQueries: (executeOverride?: boolean) => Promise<PrepareBatchDBQueries[]>,
|
|
530
552
|
) => {
|
|
531
|
-
const channelFromEvent = event.channel;
|
|
532
|
-
const cid = event.cid || channelFromEvent?.cid;
|
|
553
|
+
const channelFromEvent = (event as Extract<WSEvent, { channel?: any }>).channel;
|
|
554
|
+
const cid = (event as Extract<WSEvent, { cid?: any }>).cid || channelFromEvent?.cid;
|
|
533
555
|
const type = event.type;
|
|
534
556
|
|
|
535
557
|
if (!cid) {
|
|
@@ -542,11 +564,13 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
542
564
|
// This can happen for example when a message.new event is received for a channel that is not in the db due to a channel being hidden.
|
|
543
565
|
const shouldUpsertChannelData = forceUpdate || !(await this.channelExists({ cid }));
|
|
544
566
|
if (shouldUpsertChannelData) {
|
|
567
|
+
const event_ = event as Extract<WSEvent, { channel_type?: any }>;
|
|
568
|
+
|
|
545
569
|
let channelData = channelFromEvent;
|
|
546
|
-
if (!channelData &&
|
|
570
|
+
if (!channelData && event_.channel_type && event_.channel_id) {
|
|
547
571
|
const channelFromState = this.client.channel(
|
|
548
|
-
|
|
549
|
-
|
|
572
|
+
event_.channel_type,
|
|
573
|
+
event_.channel_id,
|
|
550
574
|
);
|
|
551
575
|
if (channelFromState.initialized && !channelFromState.disconnected) {
|
|
552
576
|
channelData = channelFromState.data as unknown as ChannelResponse;
|
|
@@ -565,17 +589,21 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
565
589
|
}
|
|
566
590
|
return newQueries;
|
|
567
591
|
} else {
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
592
|
+
logger
|
|
593
|
+
.withExtraTags('queriesWithChannelGuard')
|
|
594
|
+
.warn(
|
|
595
|
+
`Could not create channel queries on a "${type}" event for an initialized channel that is not in the database. Skipping the event.`,
|
|
596
|
+
{ event },
|
|
597
|
+
);
|
|
572
598
|
return [];
|
|
573
599
|
}
|
|
574
600
|
} else {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
601
|
+
logger
|
|
602
|
+
.withExtraTags('queriesWithChannelGuard')
|
|
603
|
+
.warn(
|
|
604
|
+
`Received a "${type}" event for a non-initialized channel that is not in the database. Skipping the event.`,
|
|
605
|
+
{ event },
|
|
606
|
+
);
|
|
579
607
|
return [];
|
|
580
608
|
}
|
|
581
609
|
}
|
|
@@ -587,14 +615,15 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
587
615
|
* and it is going to make sure that both messages and reads are upserted. It will not
|
|
588
616
|
* try to fetch the reads from the DB first and it will rely on channel.state to handle
|
|
589
617
|
* the number of unreads.
|
|
590
|
-
*
|
|
591
|
-
* @param
|
|
618
|
+
*
|
|
619
|
+
* @param payload.event - the WS event we are trying to process
|
|
620
|
+
* @param payload.execute - Whether to immediately execute the operation (optional, defaults to `true`).
|
|
592
621
|
*/
|
|
593
622
|
public handleNewMessage = async ({
|
|
594
623
|
event,
|
|
595
624
|
execute = true,
|
|
596
625
|
}: {
|
|
597
|
-
event:
|
|
626
|
+
event: EventPayload<'message.new'>;
|
|
598
627
|
execute?: boolean;
|
|
599
628
|
}) => {
|
|
600
629
|
const client = this.client;
|
|
@@ -628,10 +657,13 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
628
657
|
execute: false,
|
|
629
658
|
reads: [
|
|
630
659
|
{
|
|
631
|
-
last_read:
|
|
660
|
+
last_read: ownReads?.last_read ?? new Date(0),
|
|
632
661
|
last_read_message_id: ownReads?.last_read_message_id,
|
|
633
662
|
unread_messages: unreadCount,
|
|
634
|
-
user: client.user
|
|
663
|
+
user: client.user as RequireLiteral<
|
|
664
|
+
OwnUserResponse,
|
|
665
|
+
'blocked_user_ids'
|
|
666
|
+
>, // TODO: drop RequireLiteral once the oapi spec is adjusted
|
|
635
667
|
},
|
|
636
668
|
],
|
|
637
669
|
});
|
|
@@ -652,14 +684,15 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
652
684
|
/**
|
|
653
685
|
* A handler for message deletion. It provides a channel guard and determines whether
|
|
654
686
|
* it should hard delete or soft delete the message.
|
|
655
|
-
*
|
|
656
|
-
* @param
|
|
687
|
+
*
|
|
688
|
+
* @param payload.event - the WS event we are trying to process
|
|
689
|
+
* @param payload.execute - Whether to immediately execute the operation (optional, defaults to `true`).
|
|
657
690
|
*/
|
|
658
691
|
public handleDeleteMessage = async ({
|
|
659
692
|
event,
|
|
660
693
|
execute = true,
|
|
661
694
|
}: {
|
|
662
|
-
event:
|
|
695
|
+
event: EventPayload<'message.deleted'>;
|
|
663
696
|
execute?: boolean;
|
|
664
697
|
}) => {
|
|
665
698
|
const { message, deleted_for_me, hard_delete = false } = event;
|
|
@@ -684,8 +717,9 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
684
717
|
* A utility method used for removing a message that has already failed from the
|
|
685
718
|
* state as well as the DB. We want to drop all pending tasks and finally hard
|
|
686
719
|
* delete the message from the DB.
|
|
687
|
-
*
|
|
688
|
-
* @param
|
|
720
|
+
*
|
|
721
|
+
* @param payload.messageId - The ID of the message we want to remove.
|
|
722
|
+
* @param payload.execute - Whether to immediately execute the operation (optional, defaults to `true`).
|
|
689
723
|
*/
|
|
690
724
|
public handleRemoveMessage = async ({
|
|
691
725
|
messageId,
|
|
@@ -717,22 +751,29 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
717
751
|
* The unreadMessages argument is useful for cases where we know the exact number of unreads
|
|
718
752
|
* (for example reading an entire channel), but `unread_messages` might not necessarily exist
|
|
719
753
|
* in the event (or it exists with a stale value if we know what we want to ultimately update to).
|
|
720
|
-
*
|
|
721
|
-
* @param
|
|
722
|
-
* @param
|
|
754
|
+
*
|
|
755
|
+
* @param payload.event - The WS event we are trying to process.
|
|
756
|
+
* @param payload.unreadMessages - An override of `unread_messages` that will be preferred when upserting reads.
|
|
757
|
+
* @param payload.execute - Whether to immediately execute the operation (optional, defaults to `true`).
|
|
723
758
|
*/
|
|
724
759
|
public handleRead = async ({
|
|
725
760
|
event,
|
|
726
761
|
unreadMessages,
|
|
727
762
|
execute = true,
|
|
728
763
|
}: {
|
|
729
|
-
event:
|
|
764
|
+
event: EventPayload<
|
|
765
|
+
| 'message.read'
|
|
766
|
+
| 'message.read_locally'
|
|
767
|
+
| 'notification.mark_read'
|
|
768
|
+
| 'notification.mark_unread'
|
|
769
|
+
>;
|
|
730
770
|
unreadMessages?: number;
|
|
731
771
|
execute?: boolean;
|
|
732
772
|
}) => {
|
|
733
773
|
const {
|
|
734
|
-
received_at: last_read,
|
|
774
|
+
received_at: last_read = new Date(),
|
|
735
775
|
last_read_message_id,
|
|
776
|
+
// @ts-expect-error property missing
|
|
736
777
|
unread_messages = 0,
|
|
737
778
|
user,
|
|
738
779
|
cid,
|
|
@@ -747,7 +788,7 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
747
788
|
execute: executeOverride,
|
|
748
789
|
reads: [
|
|
749
790
|
{
|
|
750
|
-
last_read
|
|
791
|
+
last_read,
|
|
751
792
|
last_read_message_id,
|
|
752
793
|
unread_messages: overriddenUnreadMessages,
|
|
753
794
|
user,
|
|
@@ -764,14 +805,15 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
764
805
|
* A utility method used to handle member events. It guards the processing
|
|
765
806
|
* of each event with a channel guard and also forces an update of member_count
|
|
766
807
|
* for the respective channel if applicable.
|
|
767
|
-
*
|
|
768
|
-
* @param
|
|
808
|
+
*
|
|
809
|
+
* @param payload.event - the WS event we are trying to process
|
|
810
|
+
* @param payload.execute - Whether to immediately execute the operation (optional, defaults to `true`).
|
|
769
811
|
*/
|
|
770
812
|
public handleMemberEvent = async ({
|
|
771
813
|
event,
|
|
772
814
|
execute = true,
|
|
773
815
|
}: {
|
|
774
|
-
event:
|
|
816
|
+
event: EventPayload<`member.${string}`>;
|
|
775
817
|
execute?: boolean;
|
|
776
818
|
}) => {
|
|
777
819
|
const { member, cid, type } = event;
|
|
@@ -802,14 +844,15 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
802
844
|
/**
|
|
803
845
|
* A utility method used to handle message.updated events. It guards each
|
|
804
846
|
* event handler within a channel guard.
|
|
805
|
-
*
|
|
806
|
-
* @param
|
|
847
|
+
*
|
|
848
|
+
* @param payload.event - the WS event we are trying to process
|
|
849
|
+
* @param payload.execute - Whether to immediately execute the operation (optional, defaults to `true`).
|
|
807
850
|
*/
|
|
808
851
|
public handleMessageUpdatedEvent = async ({
|
|
809
852
|
event,
|
|
810
853
|
execute = true,
|
|
811
854
|
}: {
|
|
812
|
-
event:
|
|
855
|
+
event: EventPayload<'message.updated' | 'message.undeleted'>;
|
|
813
856
|
execute?: boolean;
|
|
814
857
|
}) => {
|
|
815
858
|
const { message } = event;
|
|
@@ -831,14 +874,15 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
831
874
|
* simple upsertion is not enough.
|
|
832
875
|
* It will update the hidden property of a channel to true if handling the `channel.hidden`
|
|
833
876
|
* event and to false if handling `channel.visible`.
|
|
834
|
-
*
|
|
835
|
-
* @param
|
|
877
|
+
*
|
|
878
|
+
* @param payload. - the WS event we are trying to process
|
|
879
|
+
* @param payload.execute - Whether to immediately execute the operation (optional, defaults to `true`).
|
|
836
880
|
*/
|
|
837
881
|
public handleChannelVisibilityEvent = async ({
|
|
838
882
|
event,
|
|
839
883
|
execute = true,
|
|
840
884
|
}: {
|
|
841
|
-
event:
|
|
885
|
+
event: EventPayload<'channel.visible' | 'channel.hidden'>;
|
|
842
886
|
execute?: boolean;
|
|
843
887
|
}) => {
|
|
844
888
|
const { type, channel } = event;
|
|
@@ -858,14 +902,15 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
858
902
|
* A utility handler used to handle channel.truncated events. It handles both
|
|
859
903
|
* removing all messages and relying on truncated_at as well. It will also upsert
|
|
860
904
|
* reads adequately (and calculate the correct unread messages when truncating).
|
|
861
|
-
*
|
|
862
|
-
* @param
|
|
905
|
+
*
|
|
906
|
+
* @param payload.event - the WS event we are trying to process
|
|
907
|
+
* @param payload.execute - Whether to immediately execute the operation (optional, defaults to `true`).
|
|
863
908
|
*/
|
|
864
909
|
public handleChannelTruncatedEvent = async ({
|
|
865
910
|
event,
|
|
866
911
|
execute = true,
|
|
867
912
|
}: {
|
|
868
|
-
event:
|
|
913
|
+
event: EventPayload<'channel.truncated'>;
|
|
869
914
|
execute?: boolean;
|
|
870
915
|
}) => {
|
|
871
916
|
const { channel } = event;
|
|
@@ -900,10 +945,10 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
900
945
|
execute: false,
|
|
901
946
|
reads: [
|
|
902
947
|
{
|
|
903
|
-
last_read:
|
|
948
|
+
last_read: ownReads?.last_read ?? new Date(0),
|
|
904
949
|
last_read_message_id: ownReads?.last_read_message_id,
|
|
905
950
|
unread_messages: unreadCount,
|
|
906
|
-
user: ownUser,
|
|
951
|
+
user: ownUser as RequireLiteral<OwnUserResponse, 'blocked_user_ids'>, // TODO: drop RequireLiteral once the oapi spec is adjusted
|
|
907
952
|
},
|
|
908
953
|
],
|
|
909
954
|
});
|
|
@@ -926,14 +971,15 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
926
971
|
* - reaction.new -> insertReaction
|
|
927
972
|
* - reaction.updated -> updateReaction
|
|
928
973
|
* - reaction.deleted -> deleteReaction
|
|
929
|
-
*
|
|
930
|
-
* @param
|
|
974
|
+
*
|
|
975
|
+
* @param payload.event - the WS event we are trying to process
|
|
976
|
+
* @param payload.execute - Whether to immediately execute the operation (optional, defaults to `true`).
|
|
931
977
|
*/
|
|
932
978
|
public handleReactionEvent = async ({
|
|
933
979
|
event,
|
|
934
980
|
execute = true,
|
|
935
981
|
}: {
|
|
936
|
-
event:
|
|
982
|
+
event: EventPayload<`reaction.${string}`>;
|
|
937
983
|
execute?: boolean;
|
|
938
984
|
}) => {
|
|
939
985
|
const { type, message, reaction } = event;
|
|
@@ -942,7 +988,7 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
942
988
|
return [];
|
|
943
989
|
}
|
|
944
990
|
|
|
945
|
-
const getReactionMethod = (type:
|
|
991
|
+
const getReactionMethod = (type: EventType) => {
|
|
946
992
|
switch (type) {
|
|
947
993
|
case 'reaction.new':
|
|
948
994
|
return this.insertReaction;
|
|
@@ -968,14 +1014,15 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
968
1014
|
* A utility handler for all draft events:
|
|
969
1015
|
* - draft.updated -> updateDraft
|
|
970
1016
|
* - draft.deleted -> deleteDraft
|
|
971
|
-
*
|
|
972
|
-
* @param
|
|
1017
|
+
*
|
|
1018
|
+
* @param payload.event - the WS event we are trying to process
|
|
1019
|
+
* @param payload.execute - Whether to immediately execute the operation (optional, defaults to `true`).
|
|
973
1020
|
*/
|
|
974
1021
|
handleDraftEvent = async ({
|
|
975
1022
|
event,
|
|
976
1023
|
execute = true,
|
|
977
1024
|
}: {
|
|
978
|
-
event:
|
|
1025
|
+
event: EventPayload<`draft.${string}`>;
|
|
979
1026
|
execute?: boolean;
|
|
980
1027
|
}) => {
|
|
981
1028
|
const { cid, draft, type } = event;
|
|
@@ -1006,8 +1053,9 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1006
1053
|
* A generic event handler that decides which DB API to invoke based on
|
|
1007
1054
|
* event.type for all events we are currently handling. It is used to both
|
|
1008
1055
|
* react on WS events as well as process the sync API events.
|
|
1009
|
-
*
|
|
1010
|
-
* @param
|
|
1056
|
+
*
|
|
1057
|
+
* @param payload.event - the WS event we are trying to process
|
|
1058
|
+
* @param payload.execute - Whether to immediately execute the operation (optional, defaults to `true`).
|
|
1011
1059
|
*/
|
|
1012
1060
|
public handleEvent = async ({
|
|
1013
1061
|
event,
|
|
@@ -1016,10 +1064,13 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1016
1064
|
event: Event;
|
|
1017
1065
|
execute?: boolean;
|
|
1018
1066
|
}) => {
|
|
1019
|
-
const { type
|
|
1067
|
+
const { type } = event;
|
|
1020
1068
|
|
|
1021
1069
|
if (type.startsWith('reaction')) {
|
|
1022
|
-
return await this.handleReactionEvent({
|
|
1070
|
+
return await this.handleReactionEvent({
|
|
1071
|
+
event: event as EventPayload<`reaction.${string}`>,
|
|
1072
|
+
execute,
|
|
1073
|
+
});
|
|
1023
1074
|
}
|
|
1024
1075
|
|
|
1025
1076
|
if (type === 'message.new') {
|
|
@@ -1055,7 +1106,10 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1055
1106
|
}
|
|
1056
1107
|
|
|
1057
1108
|
if (type.startsWith('member.')) {
|
|
1058
|
-
return await this.handleMemberEvent({
|
|
1109
|
+
return await this.handleMemberEvent({
|
|
1110
|
+
event: event as EventPayload<`member.${string}`>,
|
|
1111
|
+
execute,
|
|
1112
|
+
});
|
|
1059
1113
|
}
|
|
1060
1114
|
|
|
1061
1115
|
if (type === 'channel.hidden' || type === 'channel.visible') {
|
|
@@ -1077,18 +1131,18 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1077
1131
|
(type === 'channel.updated' ||
|
|
1078
1132
|
type === 'notification.message_new' ||
|
|
1079
1133
|
type === 'notification.added_to_channel') &&
|
|
1080
|
-
channel
|
|
1134
|
+
event.channel
|
|
1081
1135
|
) {
|
|
1082
|
-
return await this.upsertChannelData({ channel, execute });
|
|
1136
|
+
return await this.upsertChannelData({ channel: event.channel, execute });
|
|
1083
1137
|
}
|
|
1084
1138
|
|
|
1085
1139
|
if (
|
|
1086
1140
|
(type === 'channel.deleted' ||
|
|
1087
1141
|
type === 'notification.channel_deleted' ||
|
|
1088
1142
|
type === 'notification.removed_from_channel') &&
|
|
1089
|
-
channel
|
|
1143
|
+
event.channel
|
|
1090
1144
|
) {
|
|
1091
|
-
return await this.deleteChannel({ cid: channel.cid, execute });
|
|
1145
|
+
return await this.deleteChannel({ cid: event.channel.cid, execute });
|
|
1092
1146
|
}
|
|
1093
1147
|
|
|
1094
1148
|
if (type === 'channel.truncated') {
|
|
@@ -1107,6 +1161,7 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1107
1161
|
* 3. If it is, it will insert the task in the pending tasks table
|
|
1108
1162
|
*
|
|
1109
1163
|
* It will return the response from the execution if it succeeded.
|
|
1164
|
+
*
|
|
1110
1165
|
* @param task - the pending task we want to execute
|
|
1111
1166
|
*/
|
|
1112
1167
|
public queueTask = async <T>({ task }: { task: PendingTask }): Promise<T> => {
|
|
@@ -1122,7 +1177,7 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1122
1177
|
try {
|
|
1123
1178
|
return await attemptTaskExecution();
|
|
1124
1179
|
} catch (e) {
|
|
1125
|
-
if (!this.shouldSkipQueueingTask(e as AxiosError<
|
|
1180
|
+
if (!this.shouldSkipQueueingTask(e as AxiosError<APIError>)) {
|
|
1126
1181
|
await this.handleAddPendingTask({ task });
|
|
1127
1182
|
}
|
|
1128
1183
|
throw e;
|
|
@@ -1130,13 +1185,14 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1130
1185
|
};
|
|
1131
1186
|
|
|
1132
1187
|
/**
|
|
1133
|
-
* A utility method that determines if a failed task should be added to the
|
|
1134
|
-
*
|
|
1135
|
-
*
|
|
1136
|
-
*
|
|
1137
|
-
* @param error
|
|
1188
|
+
* A utility method that determines if a failed task should be added to the queue based on its
|
|
1189
|
+
* error. Error code 4 — bad request data. Error code 17 — missing `own_capabilities` to execute
|
|
1190
|
+
* the task.
|
|
1191
|
+
*
|
|
1192
|
+
* @param error - The failed task's Axios error.
|
|
1193
|
+
* @returns `true` when the task should not be re-queued.
|
|
1138
1194
|
*/
|
|
1139
|
-
private shouldSkipQueueingTask = (error: AxiosError<
|
|
1195
|
+
private shouldSkipQueueingTask = (error: AxiosError<APIError>) =>
|
|
1140
1196
|
error?.response?.data?.code === 4 || error?.response?.data?.code === 17;
|
|
1141
1197
|
|
|
1142
1198
|
private mergeFailedMessageUpdateIntoPendingSendMessage = ({
|
|
@@ -1144,13 +1200,13 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1144
1200
|
pendingMessage,
|
|
1145
1201
|
}: {
|
|
1146
1202
|
editedMessage: LocalMessage | Partial<MessageResponse>;
|
|
1147
|
-
pendingMessage:
|
|
1203
|
+
pendingMessage: MessageRequest;
|
|
1148
1204
|
}) => {
|
|
1149
1205
|
const normalizedEditedMessageSource = {
|
|
1150
1206
|
...editedMessage,
|
|
1151
1207
|
} as LocalMessage & { message_text_updated_at?: string };
|
|
1152
1208
|
|
|
1153
|
-
if (editedMessage.status === 'failed') {
|
|
1209
|
+
if ((editedMessage as LocalMessage).status === 'failed') {
|
|
1154
1210
|
delete normalizedEditedMessageSource.message_text_updated_at;
|
|
1155
1211
|
}
|
|
1156
1212
|
|
|
@@ -1165,7 +1221,7 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1165
1221
|
...(typeof pendingMessageStatus !== 'undefined'
|
|
1166
1222
|
? { status: pendingMessageStatus }
|
|
1167
1223
|
: {}),
|
|
1168
|
-
} as
|
|
1224
|
+
} as MessageRequest;
|
|
1169
1225
|
};
|
|
1170
1226
|
|
|
1171
1227
|
private isPendingSendMessageTask = (
|
|
@@ -1176,12 +1232,12 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1176
1232
|
private handleOfflineFailedUpdateMessagePendingTask = async (
|
|
1177
1233
|
task: Extract<PendingTask, { type: 'update-message' }>,
|
|
1178
1234
|
) => {
|
|
1179
|
-
const [message] = task.payload;
|
|
1180
|
-
if (!
|
|
1235
|
+
const [{ id, message }] = task.payload;
|
|
1236
|
+
if (!id) {
|
|
1181
1237
|
return;
|
|
1182
1238
|
}
|
|
1183
1239
|
|
|
1184
|
-
const pendingTasks = await this.getPendingTasks({ messageId:
|
|
1240
|
+
const pendingTasks = await this.getPendingTasks({ messageId: id });
|
|
1185
1241
|
const pendingSendMessageTask = pendingTasks.find(this.isPendingSendMessageTask);
|
|
1186
1242
|
|
|
1187
1243
|
if (!pendingSendMessageTask) {
|
|
@@ -1190,14 +1246,20 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1190
1246
|
|
|
1191
1247
|
const updatedPendingSendMessage = this.mergeFailedMessageUpdateIntoPendingSendMessage(
|
|
1192
1248
|
{
|
|
1193
|
-
|
|
1194
|
-
|
|
1249
|
+
// TODO: this is not good, we have too many message types, should probably only have two (request, response)
|
|
1250
|
+
editedMessage: message as unknown as LocalMessage,
|
|
1251
|
+
pendingMessage: pendingSendMessageTask.payload[0].message as MessageRequest,
|
|
1195
1252
|
},
|
|
1196
1253
|
);
|
|
1197
1254
|
|
|
1198
1255
|
const updatedPendingTask: Extract<PendingTask, { type: 'send-message' }> = {
|
|
1199
1256
|
...pendingSendMessageTask,
|
|
1200
|
-
payload: [
|
|
1257
|
+
payload: [
|
|
1258
|
+
{
|
|
1259
|
+
...pendingSendMessageTask.payload[0],
|
|
1260
|
+
message: updatedPendingSendMessage,
|
|
1261
|
+
},
|
|
1262
|
+
],
|
|
1201
1263
|
};
|
|
1202
1264
|
|
|
1203
1265
|
if (pendingSendMessageTask.id) {
|
|
@@ -1219,14 +1281,17 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1219
1281
|
* or rewrites an existing pending `send-message` task for offline edits of failed messages.
|
|
1220
1282
|
*/
|
|
1221
1283
|
public handleAddPendingTask = async ({ task }: { task: PendingTask }) => {
|
|
1222
|
-
if (
|
|
1284
|
+
if (
|
|
1285
|
+
task.type === 'update-message' &&
|
|
1286
|
+
!isMessageUpdateReplayable(task.payload[0].message ?? {})
|
|
1287
|
+
) {
|
|
1223
1288
|
return;
|
|
1224
1289
|
}
|
|
1225
1290
|
|
|
1226
1291
|
if (
|
|
1227
1292
|
task.type === 'update-message' &&
|
|
1228
1293
|
!this.client.wsConnection?.isHealthy &&
|
|
1229
|
-
task.payload[0].status === 'failed'
|
|
1294
|
+
(task.payload[0].message as { status?: string } | undefined)?.status === 'failed'
|
|
1230
1295
|
) {
|
|
1231
1296
|
await this.handleOfflineFailedUpdateMessagePendingTask(task);
|
|
1232
1297
|
return;
|
|
@@ -1246,6 +1311,7 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1246
1311
|
* - Creating a draft
|
|
1247
1312
|
* - Deleting a draft
|
|
1248
1313
|
* It will throw if we try to execute a pending task that is not supported.
|
|
1314
|
+
*
|
|
1249
1315
|
* @param task - The task we want to execute
|
|
1250
1316
|
* @param isPendingTask - a control value telling us if it's an actual pending task being executed
|
|
1251
1317
|
* or delayed execution
|
|
@@ -1293,7 +1359,7 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1293
1359
|
timestampChanged: true,
|
|
1294
1360
|
});
|
|
1295
1361
|
}
|
|
1296
|
-
channel.
|
|
1362
|
+
channel.messagePaginator.trackLastMessage(formatMessage(newMessage));
|
|
1297
1363
|
}
|
|
1298
1364
|
return newMessageResponse;
|
|
1299
1365
|
}
|
|
@@ -1325,7 +1391,7 @@ export abstract class AbstractOfflineDB implements OfflineDBApi {
|
|
|
1325
1391
|
true,
|
|
1326
1392
|
);
|
|
1327
1393
|
} catch (e) {
|
|
1328
|
-
const error = e as AxiosError<
|
|
1394
|
+
const error = e as AxiosError<APIError>;
|
|
1329
1395
|
if (!this.shouldSkipQueueingTask(error)) {
|
|
1330
1396
|
// executing the pending task has failed, so keep it in the queue
|
|
1331
1397
|
continue;
|