stream-chat 9.50.3 → 10.0.0-rc.2

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