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.
Files changed (229) hide show
  1. package/dist/cjs/index.browser.js +18869 -13986
  2. package/dist/cjs/index.browser.js.map +4 -4
  3. package/dist/cjs/index.node.js +18888 -13992
  4. package/dist/cjs/index.node.js.map +4 -4
  5. package/dist/esm/index.mjs +18866 -13983
  6. package/dist/esm/index.mjs.map +4 -4
  7. package/dist/types/ChannelPaginatorsOrchestrator.d.ts +130 -0
  8. package/dist/types/EventHandlerPipeline.d.ts +104 -0
  9. package/dist/types/api-client.d.ts +26 -0
  10. package/dist/types/campaign.d.ts +0 -44
  11. package/dist/types/channel.d.ts +436 -480
  12. package/dist/types/channel_batch_updater.d.ts +0 -93
  13. package/dist/types/channel_manager.d.ts +8 -10
  14. package/dist/types/channel_state.d.ts +53 -201
  15. package/dist/types/client.d.ts +440 -1910
  16. package/dist/types/client_state.d.ts +4 -4
  17. package/dist/types/configuration/InstanceConfigurationService.d.ts +26 -0
  18. package/dist/types/configuration/index.d.ts +1 -0
  19. package/dist/types/configuration/types.d.ts +53 -0
  20. package/dist/types/connection.d.ts +49 -41
  21. package/dist/types/connection_fallback.d.ts +6 -4
  22. package/dist/types/constants.d.ts +0 -4
  23. package/dist/types/custom_types.d.ts +2 -0
  24. package/dist/types/errors.d.ts +2 -2
  25. package/dist/types/gen/chat/ChannelApi.d.ts +45 -0
  26. package/dist/types/gen/chat/ChatApi.d.ts +334 -0
  27. package/dist/types/gen/model-decoders/decoders.d.ts +3 -0
  28. package/dist/types/gen/model-decoders/event-decoder-mapping.d.ts +6 -0
  29. package/dist/types/gen/models/index.d.ts +8836 -0
  30. package/dist/types/gen/moderation/ModerationApi.d.ts +50 -0
  31. package/dist/types/gen-imports.d.ts +3 -0
  32. package/dist/types/index.d.ts +5 -5
  33. package/dist/types/insights.d.ts +7 -6
  34. package/dist/types/logger.d.ts +9 -0
  35. package/dist/types/messageComposer/LocationComposer.d.ts +7 -4
  36. package/dist/types/messageComposer/attachmentIdentity.d.ts +2 -2
  37. package/dist/types/messageComposer/attachmentManager.d.ts +8 -4
  38. package/dist/types/messageComposer/configuration/types.d.ts +11 -11
  39. package/dist/types/messageComposer/linkPreviewsManager.d.ts +25 -13
  40. package/dist/types/messageComposer/messageComposer.d.ts +10 -10
  41. package/dist/types/messageComposer/middleware/messageComposer/types.d.ts +3 -3
  42. package/dist/types/messageComposer/middleware/pollComposer/types.d.ts +4 -7
  43. package/dist/types/messageComposer/middleware/textComposer/commandUtils.d.ts +3 -3
  44. package/dist/types/messageComposer/middleware/textComposer/commands.d.ts +7 -7
  45. package/dist/types/messageComposer/middleware/textComposer/mentions.d.ts +218 -4
  46. package/dist/types/messageComposer/middleware/textComposer/types.d.ts +9 -4
  47. package/dist/types/messageComposer/pollComposer.d.ts +5 -4
  48. package/dist/types/messageComposer/textComposer.d.ts +8 -3
  49. package/dist/types/messageComposer/types.d.ts +6 -28
  50. package/dist/types/messageDelivery/MessageDeliveryReporter.d.ts +40 -25
  51. package/dist/types/messageDelivery/MessageReceiptsTracker.d.ts +53 -12
  52. package/dist/types/messageOperations/MessageOperationStatePolicy.d.ts +19 -0
  53. package/dist/types/messageOperations/MessageOperations.d.ts +17 -0
  54. package/dist/types/messageOperations/index.d.ts +3 -0
  55. package/dist/types/messageOperations/types.d.ts +49 -0
  56. package/dist/types/moderation.d.ts +21 -203
  57. package/dist/types/notifications/types.d.ts +8 -7
  58. package/dist/types/offline-support/offline_support_api.d.ts +110 -87
  59. package/dist/types/offline-support/types.d.ts +19 -23
  60. package/dist/types/offline-support/util.d.ts +4 -2
  61. package/dist/types/pagination/FilterBuilder.d.ts +1 -1
  62. package/dist/types/pagination/ItemIndex.d.ts +82 -0
  63. package/dist/types/pagination/cursorDerivation/createdAtAroundPaginationFlags.d.ts +9 -0
  64. package/dist/types/pagination/cursorDerivation/idAroundPaginationFlags.d.ts +6 -0
  65. package/dist/types/pagination/cursorDerivation/index.d.ts +1 -0
  66. package/dist/types/pagination/cursorDerivation/linearPaginationFlags.d.ts +6 -0
  67. package/dist/types/pagination/filterCompiler.d.ts +7 -0
  68. package/dist/types/pagination/index.d.ts +1 -3
  69. package/dist/types/pagination/paginators/BasePaginator.d.ts +709 -0
  70. package/dist/types/pagination/paginators/ChannelPaginator.d.ts +58 -0
  71. package/dist/types/pagination/paginators/MessageIntervalPaginator.d.ts +260 -0
  72. package/dist/types/pagination/paginators/MessagePaginator.d.ts +208 -0
  73. package/dist/types/pagination/paginators/PinnedMessagePaginator.d.ts +39 -0
  74. package/dist/types/pagination/paginators/ReminderPaginator.d.ts +19 -0
  75. package/dist/types/pagination/paginators/UserGroupPaginator.d.ts +24 -0
  76. package/dist/types/pagination/paginators/index.d.ts +7 -0
  77. package/dist/types/pagination/sortCompiler.d.ts +49 -0
  78. package/dist/types/pagination/types.normalization.d.ts +11 -0
  79. package/dist/types/pagination/utility.normalization.d.ts +18 -0
  80. package/dist/types/pagination/utility.queryChannel.d.ts +26 -0
  81. package/dist/types/pagination/utility.search.d.ts +13 -0
  82. package/dist/types/permissions.d.ts +1 -1
  83. package/dist/types/poll.d.ts +29 -32
  84. package/dist/types/poll_manager.d.ts +2 -2
  85. package/dist/types/reminders/Reminder.d.ts +2 -5
  86. package/dist/types/reminders/ReminderManager.d.ts +2 -9
  87. package/dist/types/search/MessageSearchSource.d.ts +4 -4
  88. package/dist/types/search/UserSearchSource.d.ts +1 -1
  89. package/dist/types/search/types.d.ts +3 -3
  90. package/dist/types/segment.d.ts +0 -34
  91. package/dist/types/signing.d.ts +105 -65
  92. package/dist/types/store.d.ts +1 -0
  93. package/dist/types/thread.d.ts +51 -34
  94. package/dist/types/thread_manager.d.ts +3 -3
  95. package/dist/types/token_manager.d.ts +15 -10
  96. package/dist/types/types.d.ts +196 -3384
  97. package/dist/types/utils/FixedSizeQueueCache.d.ts +12 -6
  98. package/dist/types/utils/WithSubscriptions.d.ts +2 -1
  99. package/dist/types/utils/concurrency.d.ts +4 -4
  100. package/dist/types/utils/mergeWith/mergeWith.d.ts +3 -3
  101. package/dist/types/utils/mergeWith/mergeWithCore.d.ts +8 -3
  102. package/dist/types/utils/retryable.d.ts +34 -0
  103. package/dist/types/utils.d.ts +104 -137
  104. package/package.json +7 -3
  105. package/src/ChannelPaginatorsOrchestrator.ts +545 -0
  106. package/src/CooldownTimer.ts +2 -2
  107. package/src/EventHandlerPipeline.ts +228 -0
  108. package/src/LiveLocationManager.ts +12 -11
  109. package/src/api-client.ts +275 -0
  110. package/src/campaign.ts +1 -77
  111. package/src/channel.ts +1262 -1277
  112. package/src/channel_batch_updater.ts +1 -211
  113. package/src/channel_manager.ts +92 -88
  114. package/src/channel_state.ts +144 -1013
  115. package/src/client.ts +888 -3944
  116. package/src/client_state.ts +4 -4
  117. package/src/configuration/InstanceConfigurationService.ts +73 -0
  118. package/src/configuration/index.ts +1 -0
  119. package/src/configuration/types.ts +81 -0
  120. package/src/connection.ts +145 -94
  121. package/src/connection_fallback.ts +29 -27
  122. package/src/constants.ts +1 -5
  123. package/src/custom_types.ts +4 -1
  124. package/src/errors.ts +2 -2
  125. package/src/gen/chat/ChannelApi.ts +275 -0
  126. package/src/gen/chat/ChatApi.ts +2554 -0
  127. package/src/gen/model-decoders/decoders.ts +2680 -0
  128. package/src/gen/model-decoders/event-decoder-mapping.ts +198 -0
  129. package/src/gen/models/index.ts +12673 -0
  130. package/src/gen/moderation/ModerationApi.ts +607 -0
  131. package/src/gen-imports.ts +3 -0
  132. package/src/index.ts +5 -10
  133. package/src/insights.ts +6 -5
  134. package/src/logger.ts +28 -0
  135. package/src/messageComposer/LocationComposer.ts +9 -5
  136. package/src/messageComposer/MessageComposerEffectHandlers.ts +1 -0
  137. package/src/messageComposer/attachmentIdentity.ts +16 -9
  138. package/src/messageComposer/attachmentManager.ts +13 -8
  139. package/src/messageComposer/configuration/types.ts +11 -11
  140. package/src/messageComposer/linkPreviewsManager.ts +9 -10
  141. package/src/messageComposer/messageComposer.ts +57 -53
  142. package/src/messageComposer/middleware/messageComposer/attachments.ts +1 -2
  143. package/src/messageComposer/middleware/messageComposer/cleanData.ts +1 -1
  144. package/src/messageComposer/middleware/messageComposer/compositionValidation.ts +2 -2
  145. package/src/messageComposer/middleware/messageComposer/messageComposerState.ts +2 -2
  146. package/src/messageComposer/middleware/messageComposer/sharedLocation.ts +4 -3
  147. package/src/messageComposer/middleware/messageComposer/textComposer.ts +2 -2
  148. package/src/messageComposer/middleware/messageComposer/types.ts +3 -4
  149. package/src/messageComposer/middleware/messageComposer/userDataInjection.ts +9 -5
  150. package/src/messageComposer/middleware/pollComposer/state.ts +0 -2
  151. package/src/messageComposer/middleware/pollComposer/types.ts +4 -7
  152. package/src/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.ts +10 -1
  153. package/src/messageComposer/middleware/textComposer/commandEffects.ts +4 -4
  154. package/src/messageComposer/middleware/textComposer/commandUtils.ts +3 -6
  155. package/src/messageComposer/middleware/textComposer/commands.ts +3 -3
  156. package/src/messageComposer/middleware/textComposer/mentionUtils.ts +1 -1
  157. package/src/messageComposer/middleware/textComposer/mentions.ts +31 -15
  158. package/src/messageComposer/middleware/textComposer/types.ts +9 -4
  159. package/src/messageComposer/pollComposer.ts +6 -8
  160. package/src/messageComposer/textComposer.ts +27 -2
  161. package/src/messageComposer/types.ts +6 -28
  162. package/src/messageDelivery/MessageDeliveryReporter.ts +101 -45
  163. package/src/messageDelivery/MessageReceiptsTracker.ts +294 -21
  164. package/src/messageOperations/MessageOperationStatePolicy.ts +77 -0
  165. package/src/messageOperations/MessageOperations.ts +212 -0
  166. package/src/messageOperations/index.ts +10 -0
  167. package/src/messageOperations/types.ts +64 -0
  168. package/src/moderation.ts +38 -431
  169. package/src/notifications/types.ts +8 -7
  170. package/src/offline-support/offline_support_api.ts +198 -132
  171. package/src/offline-support/offline_sync_manager.ts +17 -7
  172. package/src/offline-support/types.ts +23 -26
  173. package/src/offline-support/util.ts +5 -4
  174. package/src/pagination/FilterBuilder.ts +4 -1
  175. package/src/pagination/ItemIndex.ts +112 -0
  176. package/src/pagination/cursorDerivation/createdAtAroundPaginationFlags.ts +73 -0
  177. package/src/pagination/cursorDerivation/idAroundPaginationFlags.ts +53 -0
  178. package/src/pagination/cursorDerivation/index.ts +1 -0
  179. package/src/pagination/cursorDerivation/linearPaginationFlags.ts +86 -0
  180. package/src/pagination/filterCompiler.ts +196 -0
  181. package/src/pagination/index.ts +1 -3
  182. package/src/pagination/paginators/BasePaginator.ts +2393 -0
  183. package/src/pagination/paginators/ChannelPaginator.ts +427 -0
  184. package/src/pagination/paginators/MessageIntervalPaginator.ts +1073 -0
  185. package/src/pagination/paginators/MessagePaginator.ts +496 -0
  186. package/src/pagination/paginators/PinnedMessagePaginator.ts +105 -0
  187. package/src/pagination/paginators/ReminderPaginator.ts +105 -0
  188. package/src/pagination/paginators/UserGroupPaginator.ts +125 -0
  189. package/src/pagination/paginators/index.ts +7 -0
  190. package/src/pagination/sortCompiler.ts +178 -0
  191. package/src/pagination/types.normalization.ts +14 -0
  192. package/src/pagination/utility.normalization.ts +106 -0
  193. package/src/pagination/utility.queryChannel.ts +84 -0
  194. package/src/pagination/utility.search.ts +80 -0
  195. package/src/permissions.ts +7 -8
  196. package/src/poll.ts +101 -110
  197. package/src/poll_manager.ts +14 -8
  198. package/src/reminders/Reminder.ts +2 -5
  199. package/src/reminders/ReminderManager.ts +19 -21
  200. package/src/search/BaseSearchSource.ts +0 -3
  201. package/src/search/ChannelMemberSearchSource.ts +7 -1
  202. package/src/search/ChannelSearchSource.ts +10 -3
  203. package/src/search/MessageSearchSource.ts +29 -30
  204. package/src/search/UserSearchSource.ts +12 -8
  205. package/src/search/types.ts +3 -4
  206. package/src/segment.ts +1 -95
  207. package/src/signing.ts +107 -67
  208. package/src/store.ts +2 -1
  209. package/src/thread.ts +439 -236
  210. package/src/thread_manager.ts +36 -15
  211. package/src/token_manager.ts +21 -10
  212. package/src/types.ts +375 -4524
  213. package/src/uploadManager.ts +8 -0
  214. package/src/utils/FixedSizeQueueCache.ts +12 -6
  215. package/src/utils/WithSubscriptions.ts +2 -1
  216. package/src/utils/concurrency.ts +4 -4
  217. package/src/utils/mergeWith/mergeWith.ts +3 -3
  218. package/src/utils/mergeWith/mergeWithCore.ts +140 -164
  219. package/src/utils/mergeWith/mergeWithDiff.ts +3 -3
  220. package/src/utils/retryable.ts +117 -0
  221. package/src/utils.ts +133 -524
  222. package/dist/types/events.d.ts +0 -72
  223. package/dist/types/pagination/BasePaginator.d.ts +0 -69
  224. package/dist/types/pagination/ReminderPaginator.d.ts +0 -16
  225. package/dist/types/pagination/UserGroupPaginator.d.ts +0 -21
  226. package/src/events.ts +0 -75
  227. package/src/pagination/BasePaginator.ts +0 -184
  228. package/src/pagination/ReminderPaginator.ts +0 -56
  229. package/src/pagination/UserGroupPaginator.ts +0 -93
@@ -1,10 +1,14 @@
1
1
  import type {
2
- APIErrorResponse,
2
+ APIError,
3
3
  ChannelResponse,
4
4
  Event,
5
+ EventPayload,
6
+ EventType,
5
7
  LocalMessage,
6
- Message,
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.userID,
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 ChannelAPIResponse. The implementation itself is responsible
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 ChannelAPIResponse as possible.
252
+ * the server side ChannelStateResponseFields as possible.
253
+ *
245
254
  * @param {DBGetChannelsType} options
246
- * @returns {Promise<Omit<ChannelAPIResponse, 'duration'>[] | null>}
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 ChannelAPIResponse.
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 ChannelAPIResponse as possible.
263
+ * Should return as close to the server side ChannelStateResponseFields as possible.
264
+ *
256
265
  * @param {DBGetChannelsForQueryType} options
257
- * @returns {Promise<Omit<ChannelAPIResponse, 'duration'>[] | null>}
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<AppSettingsAPIResponse | null>}
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
- console.log('Error Initializing DB:', error);
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
- * @param {string} userId - the user ID for which we want to check initialization
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 - the WS event we are trying to process
519
- * @param execute - whether to immediately execute the operation.
520
- * @param forceUpdate - whether to upsert the channel data anyway
521
- * @param createQueries - a callback function to creation of the queries that we want to execute
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
- }: { event: Event; execute?: boolean; forceUpdate?: boolean },
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 && event.channel_type && event.channel_id) {
570
+ if (!channelData && event_.channel_type && event_.channel_id) {
547
571
  const channelFromState = this.client.channel(
548
- event.channel_type,
549
- event.channel_id,
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
- console.warn(
569
- `Couldn't create channel queries on ${type} event for an initialized channel that is not in DB, skipping event`,
570
- { event },
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
- console.warn(
576
- `Received ${type} event for a non initialized channel that is not in DB, skipping event`,
577
- { event },
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
- * @param event - the WS event we are trying to process
591
- * @param execute - whether to immediately execute the operation.
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: 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: (ownReads?.last_read ?? new Date(0)).toISOString() as string,
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
- * @param event - the WS event we are trying to process
656
- * @param execute - whether to immediately execute the operation.
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: 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
- * @param messageId - the message id of the message we want to remove
688
- * @param execute - whether to immediately execute the operation.
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
- * @param event - the WS event we are trying to process
721
- * @param unreadMessages - an override of unread_messages that will be preferred when upserting reads
722
- * @param execute - whether to immediately execute the operation.
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: 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: last_read as string,
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
- * @param event - the WS event we are trying to process
768
- * @param execute - whether to immediately execute the operation.
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: 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
- * @param event - the WS event we are trying to process
806
- * @param execute - whether to immediately execute the operation.
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: 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
- * @param event - the WS event we are trying to process
835
- * @param execute - whether to immediately execute the operation.
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: 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
- * @param event - the WS event we are trying to process
862
- * @param execute - whether to immediately execute the operation.
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: 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: (ownReads?.last_read ?? new Date(0)).toString() as string,
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
- * @param event - the WS event we are trying to process
930
- * @param execute - whether to immediately execute the operation.
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: 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: Event['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
- * @param event - the WS event we are trying to process
972
- * @param execute - whether to immediately execute the operation.
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: 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
- * @param event - the WS event we are trying to process
1010
- * @param execute - whether to immediately execute the operation.
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, channel } = event;
1067
+ const { type } = event;
1020
1068
 
1021
1069
  if (type.startsWith('reaction')) {
1022
- return await this.handleReactionEvent({ event, execute });
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({ event, execute });
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<APIErrorResponse>)) {
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
- * queue based on its error.
1135
- * Error code 4 - bad request data
1136
- * Error code 17 - missing own_capabilities to execute the task
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<APIErrorResponse>) =>
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: Message;
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 Message;
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 (!message.id) {
1235
+ const [{ id, message }] = task.payload;
1236
+ if (!id) {
1181
1237
  return;
1182
1238
  }
1183
1239
 
1184
- const pendingTasks = await this.getPendingTasks({ messageId: message.id });
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
- editedMessage: message,
1194
- pendingMessage: pendingSendMessageTask.payload[0],
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: [updatedPendingSendMessage, pendingSendMessageTask.payload[1]],
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 (task.type === 'update-message' && !isMessageUpdateReplayable(task.payload[0])) {
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.state.addMessageSorted(newMessage, true);
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<APIErrorResponse>;
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;