@wireapp/core 46.30.2 → 46.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Account.d.ts +47 -27
- package/lib/Account.d.ts.map +1 -1
- package/lib/Account.js +175 -106
- package/lib/Account.test.js +10 -5
- package/lib/notification/NotificationService.d.ts +11 -1
- package/lib/notification/NotificationService.d.ts.map +1 -1
- package/lib/notification/NotificationService.js +11 -1
- package/package.json +4 -4
package/lib/Account.d.ts
CHANGED
|
@@ -27,13 +27,13 @@ import { UserService } from './user/';
|
|
|
27
27
|
import { RecurringTaskScheduler } from './util/RecurringTaskScheduler';
|
|
28
28
|
export type ProcessedEventPayload = HandledEventPayload;
|
|
29
29
|
export declare enum ConnectionState {
|
|
30
|
-
/** The
|
|
30
|
+
/** The WebSocket is closed and no notifications are being processed */
|
|
31
31
|
CLOSED = "closed",
|
|
32
|
-
/** The
|
|
32
|
+
/** The WebSocket is being opened or reconnected */
|
|
33
33
|
CONNECTING = "connecting",
|
|
34
34
|
/** The websocket is open but locked and notifications stream is being processed */
|
|
35
35
|
PROCESSING_NOTIFICATIONS = "processing_notifications",
|
|
36
|
-
/** The
|
|
36
|
+
/** The WebSocket is open and new messages are processed live in real time */
|
|
37
37
|
LIVE = "live"
|
|
38
38
|
}
|
|
39
39
|
export type CreateStoreFn = (storeName: string, key: Uint8Array) => undefined | Promise<CRUDEngine | undefined>;
|
|
@@ -83,9 +83,8 @@ export declare class Account extends TypedEventEmitter<Events> {
|
|
|
83
83
|
private db?;
|
|
84
84
|
private encryptedDb?;
|
|
85
85
|
private coreCallbacks?;
|
|
86
|
-
private totalPendingNotifications;
|
|
87
|
-
private remainingNotifications;
|
|
88
86
|
private connectionState;
|
|
87
|
+
private notificationProcessingQueue;
|
|
89
88
|
service?: {
|
|
90
89
|
mls?: MLSService;
|
|
91
90
|
e2eIdentity?: E2EIServiceExternal;
|
|
@@ -123,9 +122,9 @@ export declare class Account extends TypedEventEmitter<Events> {
|
|
|
123
122
|
* - useVersion(0, 1, true) > version 1 is used
|
|
124
123
|
* @return The highest version that is both supported by client and backend
|
|
125
124
|
*/
|
|
126
|
-
useAPIVersion(min: number, max: number, allowDev?: boolean)
|
|
125
|
+
useAPIVersion: (min: number, max: number, allowDev?: boolean) => Promise<BackendFeatures>;
|
|
127
126
|
private persistCookie;
|
|
128
|
-
enrollE2EI({ displayName, handle, teamId, discoveryUrl, getOAuthToken, getAllConversations, certificateTtl, }: {
|
|
127
|
+
enrollE2EI: ({ displayName, handle, teamId, discoveryUrl, getOAuthToken, getAllConversations, certificateTtl, }: {
|
|
129
128
|
/** display name of the user (should match the identity provider) */
|
|
130
129
|
displayName: string;
|
|
131
130
|
/** handle of the user (should match the identity provider) */
|
|
@@ -139,7 +138,7 @@ export declare class Account extends TypedEventEmitter<Events> {
|
|
|
139
138
|
getAllConversations: getAllConversationsCallback;
|
|
140
139
|
/** number of seconds the certificate should be valid (default 90 days) */
|
|
141
140
|
certificateTtl?: number;
|
|
142
|
-
})
|
|
141
|
+
}) => Promise<void>;
|
|
143
142
|
get clientId(): string;
|
|
144
143
|
get userId(): string;
|
|
145
144
|
/**
|
|
@@ -148,33 +147,31 @@ export declare class Account extends TypedEventEmitter<Events> {
|
|
|
148
147
|
* @param registration The user's data
|
|
149
148
|
* @param clientType Type of client to create (temporary or permanent)
|
|
150
149
|
*/
|
|
151
|
-
register(registration: RegisterData, clientType: ClientType)
|
|
150
|
+
register: (registration: RegisterData, clientType: ClientType) => Promise<Context>;
|
|
152
151
|
/**
|
|
153
152
|
* Will init the core with an already logged in user
|
|
154
153
|
*
|
|
155
154
|
* @param clientType The type of client the user is using (temporary or permanent)
|
|
156
155
|
*/
|
|
157
|
-
init(clientType: ClientType, { cookie }?: InitOptions)
|
|
156
|
+
init: (clientType: ClientType, { cookie }?: InitOptions) => Promise<Context>;
|
|
158
157
|
/**
|
|
159
158
|
* Will log the user in with the given credential.
|
|
160
159
|
*
|
|
161
160
|
* @param loginData The credentials of the user
|
|
162
161
|
* @param clientInfo Info about the client to create (name, type...)
|
|
163
162
|
*/
|
|
164
|
-
login(loginData: LoginData)
|
|
163
|
+
login: (loginData: LoginData) => Promise<Context>;
|
|
165
164
|
/**
|
|
166
165
|
* Will register a new client for the current user
|
|
167
166
|
*/
|
|
168
|
-
|
|
169
|
-
/** will add extra manual entropy to the client's identity being created */
|
|
170
|
-
entropyData?: Uint8Array): Promise<RegisteredClient>;
|
|
167
|
+
regsterClient: (loginData: LoginData, clientInfo?: ClientInfo, entropyData?: Uint8Array) => Promise<RegisteredClient>;
|
|
171
168
|
getLocalClient(): Promise<import("./client/ClientService").MetaClient | undefined> | undefined;
|
|
172
169
|
/**
|
|
173
170
|
* Will initiate all the cryptographic material of the given registered device and setup all the background tasks.
|
|
174
171
|
*
|
|
175
172
|
* @returns The local existing client or undefined if the client does not exist or is not valid (non existing on backend)
|
|
176
173
|
*/
|
|
177
|
-
initClient(client: RegisteredClient, mlsConfig?: InitClientOptions)
|
|
174
|
+
initClient: (client: RegisteredClient, mlsConfig?: InitClientOptions) => Promise<RegisteredClient>;
|
|
178
175
|
private buildCryptoClient;
|
|
179
176
|
/**
|
|
180
177
|
* In order to be able to send MLS messages, the core needs a few information from the consumer.
|
|
@@ -183,17 +180,17 @@ export declare class Account extends TypedEventEmitter<Events> {
|
|
|
183
180
|
* - what is the groupId of a conversation
|
|
184
181
|
* @param coreCallbacks
|
|
185
182
|
*/
|
|
186
|
-
configureCoreCallbacks(coreCallbacks: CoreCallbacks)
|
|
183
|
+
configureCoreCallbacks: (coreCallbacks: CoreCallbacks) => void;
|
|
187
184
|
private initServices;
|
|
188
185
|
private resetContext;
|
|
189
186
|
/**
|
|
190
187
|
* Will logout the current user
|
|
191
188
|
* @param clearData if set to `true` will completely wipe any database that was created by the Account
|
|
192
189
|
*/
|
|
193
|
-
logout(data?: {
|
|
190
|
+
logout: (data?: {
|
|
194
191
|
clearAllData?: boolean;
|
|
195
192
|
clearCryptoData?: boolean;
|
|
196
|
-
})
|
|
193
|
+
}) => Promise<void>;
|
|
197
194
|
private wipeCommonData;
|
|
198
195
|
/**
|
|
199
196
|
* Will delete the identity and history of the current user
|
|
@@ -215,7 +212,7 @@ export declare class Account extends TypedEventEmitter<Events> {
|
|
|
215
212
|
* @param callbacks callbacks that will be called to handle different events
|
|
216
213
|
* @returns close a function that will disconnect from the websocket
|
|
217
214
|
*/
|
|
218
|
-
listen({ onEvent, onConnectionStateChanged: onConnectionStateChangedCallBack, onNotificationStreamProgress, onMissedNotifications, dryRun, }?: {
|
|
215
|
+
listen: ({ onEvent, onConnectionStateChanged: onConnectionStateChangedCallBack, onNotificationStreamProgress, onMissedNotifications, dryRun, }?: {
|
|
219
216
|
/**
|
|
220
217
|
* Called when a new event arrives from backend
|
|
221
218
|
* @param payload the payload of the event. Contains the raw event received and the decrypted data (if event was encrypted)
|
|
@@ -225,10 +222,7 @@ export declare class Account extends TypedEventEmitter<Events> {
|
|
|
225
222
|
/**
|
|
226
223
|
* During the notification stream processing, this function will be called whenever a new notification has been processed
|
|
227
224
|
*/
|
|
228
|
-
onNotificationStreamProgress?: (
|
|
229
|
-
done: number;
|
|
230
|
-
total: number;
|
|
231
|
-
}) => void;
|
|
225
|
+
onNotificationStreamProgress?: (currentProcessingNotificationTimestamp: string) => void;
|
|
232
226
|
/**
|
|
233
227
|
* called when the connection state with the backend has changed
|
|
234
228
|
*/
|
|
@@ -245,7 +239,7 @@ export declare class Account extends TypedEventEmitter<Events> {
|
|
|
245
239
|
* When set will not decrypt and not store the last notification ID. This is useful if you only want to subscribe to unencrypted backend events
|
|
246
240
|
*/
|
|
247
241
|
dryRun?: boolean;
|
|
248
|
-
})
|
|
242
|
+
}) => Promise<() => void>;
|
|
249
243
|
private createConnectionStateChangedHandler;
|
|
250
244
|
/**
|
|
251
245
|
* Creates the event handler that is invoked for each decrypted event from the backend.
|
|
@@ -253,12 +247,27 @@ export declare class Account extends TypedEventEmitter<Events> {
|
|
|
253
247
|
* forwarding the event to the consumer via the `onEvent` callback.
|
|
254
248
|
*/
|
|
255
249
|
private createEventHandler;
|
|
250
|
+
/**
|
|
251
|
+
* @deprecated This method is used to handle legacy notifications from the backend.
|
|
252
|
+
* It processes notifications from the legacy system, decrypts them, and emits events.
|
|
253
|
+
* It can be replaced with the new notification handling system using `ConsumableNotification`
|
|
254
|
+
* when all clients are capable of handling consumable notifications.
|
|
255
|
+
*/
|
|
256
256
|
private createLegacyNotificationHandler;
|
|
257
257
|
private createNotificationHandler;
|
|
258
|
+
private handleNotificationQueueError;
|
|
259
|
+
private acknowledgeSynchronizationNotification;
|
|
260
|
+
private handleSynchronizationNotification;
|
|
261
|
+
private decryptAckEmitNotification;
|
|
262
|
+
getNotificationEventTime: (backendEvent: Events.BackendEvent) => string | null;
|
|
258
263
|
/**
|
|
259
264
|
* Returns a function to handle missed notifications — i.e., when the backend indicates
|
|
260
265
|
* that some notifications were lost due to age (typically >28 days).
|
|
261
266
|
* Also handles MLS-specific epoch mismatch recovery by triggering a conversation rejoin.
|
|
267
|
+
*
|
|
268
|
+
* @deprecated This is used to handle legacy missed notifications.
|
|
269
|
+
* It should be replaced with the new notification handling system using `ConsumableNotification`.
|
|
270
|
+
* when all clients are capable of handling consumable notifications.
|
|
262
271
|
*/
|
|
263
272
|
private createLegacyMissedNotificationsHandler;
|
|
264
273
|
/**
|
|
@@ -266,9 +275,20 @@ export declare class Account extends TypedEventEmitter<Events> {
|
|
|
266
275
|
* It pauses message sending and MLS rejoining during stream handling to prevent race conditions,
|
|
267
276
|
* then resumes normal operations after sync is complete.
|
|
268
277
|
*
|
|
278
|
+
* @deprecated This is used to do a final sync of the legacy notification stream
|
|
279
|
+
* before switching to the new notification handling system using `ConsumableNotification`.
|
|
280
|
+
* It should be replaced with the new notification handling system when all clients are capable of handling consumable notifications.
|
|
281
|
+
*
|
|
269
282
|
* @param handlers Various logic handlers wired to notification callbacks
|
|
270
283
|
*/
|
|
271
284
|
private createLegacyNotificationStreamProcessor;
|
|
285
|
+
/**
|
|
286
|
+
* In case of a closed connection, we flush the notification processing queue.
|
|
287
|
+
* As we are not acknowledging them before decryption is done
|
|
288
|
+
* they will be resent next time the connection is opened
|
|
289
|
+
* this is to avoid duplicate decryption of notifications
|
|
290
|
+
*/
|
|
291
|
+
private pauseAndFlushNotificationQueue;
|
|
272
292
|
/**
|
|
273
293
|
* Sets up WebSocket event listeners for:
|
|
274
294
|
* - Incoming backend messages
|
|
@@ -299,14 +319,14 @@ export declare class Account extends TypedEventEmitter<Events> {
|
|
|
299
319
|
* then we remove the flag.
|
|
300
320
|
*/
|
|
301
321
|
private reactToMissedNotification;
|
|
302
|
-
getClientCapabilities()
|
|
303
|
-
checkIsConsumable(notification: Notification | ConsumableNotification)
|
|
322
|
+
getClientCapabilities: () => ClientCapability[];
|
|
323
|
+
checkIsConsumable: (notification: Notification | ConsumableNotification) => notification is ConsumableNotification;
|
|
304
324
|
private generateDbName;
|
|
305
325
|
private generateCoreDbName;
|
|
306
326
|
private generateEncryptedDbName;
|
|
307
327
|
private initEngine;
|
|
308
328
|
private groupIdFromConversationId;
|
|
309
|
-
isMLSActiveForClient()
|
|
329
|
+
isMLSActiveForClient: () => Promise<boolean>;
|
|
310
330
|
}
|
|
311
331
|
export {};
|
|
312
332
|
//# sourceMappingURL=Account.d.ts.map
|
package/lib/Account.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Account.d.ts","sourceRoot":"","sources":["../src/Account.ts"],"names":[],"mappings":"AAmBA,OAAO,EACL,YAAY,EAGZ,OAAO,EACP,MAAM,EAEN,SAAS,EAEV,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAC,gBAAgB,EAAwB,UAAU,EAAE,gBAAgB,EAAC,MAAM,iCAAiC,CAAC;AAErH,OAAO,KAAK,MAAM,MAAM,+BAA+B,CAAC;AAExD,OAAO,EAAC,YAAY,EAAC,MAAM,uCAAuC,CAAC;AACnE,OAAO,
|
|
1
|
+
{"version":3,"file":"Account.d.ts","sourceRoot":"","sources":["../src/Account.ts"],"names":[],"mappings":"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"}
|
package/lib/Account.js
CHANGED
|
@@ -52,6 +52,7 @@ const team_1 = require("@wireapp/api-client/lib/team");
|
|
|
52
52
|
const TimeUtil_1 = require("@wireapp/commons/lib/util/TimeUtil");
|
|
53
53
|
const api_client_1 = require("@wireapp/api-client");
|
|
54
54
|
const commons_1 = require("@wireapp/commons");
|
|
55
|
+
const promise_queue_1 = require("@wireapp/promise-queue");
|
|
55
56
|
const store_engine_1 = require("@wireapp/store-engine");
|
|
56
57
|
const account_1 = require("./account/");
|
|
57
58
|
const auth_2 = require("./auth/");
|
|
@@ -81,13 +82,13 @@ const LocalStorageStore_1 = require("./util/LocalStorageStore");
|
|
|
81
82
|
const RecurringTaskScheduler_1 = require("./util/RecurringTaskScheduler");
|
|
82
83
|
var ConnectionState;
|
|
83
84
|
(function (ConnectionState) {
|
|
84
|
-
/** The
|
|
85
|
+
/** The WebSocket is closed and no notifications are being processed */
|
|
85
86
|
ConnectionState["CLOSED"] = "closed";
|
|
86
|
-
/** The
|
|
87
|
+
/** The WebSocket is being opened or reconnected */
|
|
87
88
|
ConnectionState["CONNECTING"] = "connecting";
|
|
88
89
|
/** The websocket is open but locked and notifications stream is being processed */
|
|
89
90
|
ConnectionState["PROCESSING_NOTIFICATIONS"] = "processing_notifications";
|
|
90
|
-
/** The
|
|
91
|
+
/** The WebSocket is open and new messages are processed live in real time */
|
|
91
92
|
ConnectionState["LIVE"] = "live";
|
|
92
93
|
})(ConnectionState || (exports.ConnectionState = ConnectionState = {}));
|
|
93
94
|
const coreDefaultClient = {
|
|
@@ -114,9 +115,8 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
114
115
|
db;
|
|
115
116
|
encryptedDb;
|
|
116
117
|
coreCallbacks;
|
|
117
|
-
totalPendingNotifications = 0;
|
|
118
|
-
remainingNotifications = 0;
|
|
119
118
|
connectionState = ConnectionState.CLOSED;
|
|
119
|
+
notificationProcessingQueue = new promise_queue_1.PromiseQueue({ name: 'notification-processing-queue', paused: true });
|
|
120
120
|
service;
|
|
121
121
|
backendFeatures;
|
|
122
122
|
recurringTaskScheduler;
|
|
@@ -165,16 +165,16 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
165
165
|
* - useVersion(0, 1, true) > version 1 is used
|
|
166
166
|
* @return The highest version that is both supported by client and backend
|
|
167
167
|
*/
|
|
168
|
-
async
|
|
168
|
+
useAPIVersion = async (min, max, allowDev) => {
|
|
169
169
|
const features = await this.apiClient.useVersion(min, max, allowDev);
|
|
170
170
|
this.backendFeatures = features;
|
|
171
171
|
return features;
|
|
172
|
-
}
|
|
173
|
-
persistCookie(storeEngine, cookie) {
|
|
172
|
+
};
|
|
173
|
+
persistCookie = (storeEngine, cookie) => {
|
|
174
174
|
const entity = { expiration: cookie.expiration, zuid: cookie.zuid };
|
|
175
175
|
return storeEngine.updateOrCreate(auth_1.AUTH_TABLE_NAME, auth_1.AUTH_COOKIE_KEY, entity);
|
|
176
|
-
}
|
|
177
|
-
async
|
|
176
|
+
};
|
|
177
|
+
enrollE2EI = async ({ displayName, handle, teamId, discoveryUrl, getOAuthToken, getAllConversations, certificateTtl = 90 * (TimeUtil_1.TimeInMillis.DAY / 1000), }) => {
|
|
178
178
|
const context = this.apiClient.context;
|
|
179
179
|
const domain = context?.domain ?? '';
|
|
180
180
|
if (!this.currentClient) {
|
|
@@ -191,7 +191,7 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
191
191
|
id: this.userId,
|
|
192
192
|
};
|
|
193
193
|
return this.service.mls.enrollE2EI(discoveryUrl, user, this.currentClient, this.options.nbPrekeys, certificateTtl, getOAuthToken, getAllConversations);
|
|
194
|
-
}
|
|
194
|
+
};
|
|
195
195
|
get clientId() {
|
|
196
196
|
return this.apiClient.validatedClientId;
|
|
197
197
|
}
|
|
@@ -204,40 +204,40 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
204
204
|
* @param registration The user's data
|
|
205
205
|
* @param clientType Type of client to create (temporary or permanent)
|
|
206
206
|
*/
|
|
207
|
-
async
|
|
207
|
+
register = async (registration, clientType) => {
|
|
208
208
|
const context = await this.apiClient.register(registration, clientType);
|
|
209
209
|
await this.initServices(context);
|
|
210
210
|
return context;
|
|
211
|
-
}
|
|
211
|
+
};
|
|
212
212
|
/**
|
|
213
213
|
* Will init the core with an already logged in user
|
|
214
214
|
*
|
|
215
215
|
* @param clientType The type of client the user is using (temporary or permanent)
|
|
216
216
|
*/
|
|
217
|
-
async
|
|
217
|
+
init = async (clientType, { cookie } = {}) => {
|
|
218
218
|
const context = await this.apiClient.init(clientType, cookie);
|
|
219
219
|
await this.initServices(context);
|
|
220
220
|
return context;
|
|
221
|
-
}
|
|
221
|
+
};
|
|
222
222
|
/**
|
|
223
223
|
* Will log the user in with the given credential.
|
|
224
224
|
*
|
|
225
225
|
* @param loginData The credentials of the user
|
|
226
226
|
* @param clientInfo Info about the client to create (name, type...)
|
|
227
227
|
*/
|
|
228
|
-
async
|
|
228
|
+
login = async (loginData) => {
|
|
229
229
|
this.resetContext();
|
|
230
230
|
auth_2.LoginSanitizer.removeNonPrintableCharacters(loginData);
|
|
231
231
|
const context = await this.apiClient.login(loginData);
|
|
232
232
|
await this.initServices(context);
|
|
233
233
|
return context;
|
|
234
|
-
}
|
|
234
|
+
};
|
|
235
235
|
/**
|
|
236
236
|
* Will register a new client for the current user
|
|
237
237
|
*/
|
|
238
|
-
async
|
|
238
|
+
regsterClient = async (loginData, clientInfo = coreDefaultClient,
|
|
239
239
|
/** will add extra manual entropy to the client's identity being created */
|
|
240
|
-
entropyData) {
|
|
240
|
+
entropyData) => {
|
|
241
241
|
if (!this.service || !this.apiClient.context || !this.storeEngine) {
|
|
242
242
|
throw new Error('Services are not set or context not initialized.');
|
|
243
243
|
}
|
|
@@ -249,7 +249,7 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
249
249
|
await this.service.notification.initializeNotificationStream(clientId);
|
|
250
250
|
await this.service.client.synchronizeClients(clientId);
|
|
251
251
|
return client;
|
|
252
|
-
}
|
|
252
|
+
};
|
|
253
253
|
getLocalClient() {
|
|
254
254
|
return this.service?.client.loadClient();
|
|
255
255
|
}
|
|
@@ -258,7 +258,7 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
258
258
|
*
|
|
259
259
|
* @returns The local existing client or undefined if the client does not exist or is not valid (non existing on backend)
|
|
260
260
|
*/
|
|
261
|
-
async
|
|
261
|
+
initClient = async (client, mlsConfig) => {
|
|
262
262
|
if (!this.service || !this.apiClient.context || !this.storeEngine) {
|
|
263
263
|
throw new Error('Services are not set.');
|
|
264
264
|
}
|
|
@@ -278,8 +278,8 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
278
278
|
}
|
|
279
279
|
this.currentClient = client;
|
|
280
280
|
return client;
|
|
281
|
-
}
|
|
282
|
-
async
|
|
281
|
+
};
|
|
282
|
+
buildCryptoClient = async (context, storeEngine, encryptedStore) => {
|
|
283
283
|
const baseConfig = {
|
|
284
284
|
nbPrekeys: this.options.nbPrekeys,
|
|
285
285
|
onNewPrekeys: async (prekeys) => {
|
|
@@ -299,7 +299,7 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
299
299
|
const { buildClient } = await Promise.resolve().then(() => __importStar(require('./messagingProtocols/proteus/ProteusService/CryptoClient/CryptoboxWrapper')));
|
|
300
300
|
const client = buildClient(storeEngine, baseConfig);
|
|
301
301
|
return [CryptoClient_1.CryptoClientType.CRYPTOBOX, client];
|
|
302
|
-
}
|
|
302
|
+
};
|
|
303
303
|
/**
|
|
304
304
|
* In order to be able to send MLS messages, the core needs a few information from the consumer.
|
|
305
305
|
* Namely:
|
|
@@ -307,10 +307,10 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
307
307
|
* - what is the groupId of a conversation
|
|
308
308
|
* @param coreCallbacks
|
|
309
309
|
*/
|
|
310
|
-
configureCoreCallbacks(coreCallbacks) {
|
|
310
|
+
configureCoreCallbacks = (coreCallbacks) => {
|
|
311
311
|
this.coreCallbacks = coreCallbacks;
|
|
312
|
-
}
|
|
313
|
-
async
|
|
312
|
+
};
|
|
313
|
+
initServices = async (context) => {
|
|
314
314
|
const encryptedStoreName = this.generateEncryptedDbName(context);
|
|
315
315
|
this.encryptedDb = this.options.systemCrypto
|
|
316
316
|
? await (0, encryptedStore_1.createCustomEncryptedStore)(encryptedStoreName, this.options.systemCrypto)
|
|
@@ -360,17 +360,17 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
360
360
|
team: teamService,
|
|
361
361
|
user: userService,
|
|
362
362
|
};
|
|
363
|
-
}
|
|
364
|
-
resetContext() {
|
|
363
|
+
};
|
|
364
|
+
resetContext = () => {
|
|
365
365
|
this.currentClient = undefined;
|
|
366
366
|
delete this.apiClient.context;
|
|
367
367
|
delete this.service;
|
|
368
|
-
}
|
|
368
|
+
};
|
|
369
369
|
/**
|
|
370
370
|
* Will logout the current user
|
|
371
371
|
* @param clearData if set to `true` will completely wipe any database that was created by the Account
|
|
372
372
|
*/
|
|
373
|
-
async
|
|
373
|
+
logout = async (data) => {
|
|
374
374
|
this.db?.close();
|
|
375
375
|
this.encryptedDb?.close();
|
|
376
376
|
if (data?.clearAllData) {
|
|
@@ -381,19 +381,19 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
381
381
|
}
|
|
382
382
|
await this.apiClient.logout();
|
|
383
383
|
this.resetContext();
|
|
384
|
-
}
|
|
385
|
-
async
|
|
384
|
+
};
|
|
385
|
+
wipeCommonData = async () => {
|
|
386
386
|
await this.service?.client.deleteLocalClient();
|
|
387
387
|
if (this.storeEngine) {
|
|
388
388
|
await (0, CoreCryptoWrapper_1.wipeCoreCryptoDb)(this.storeEngine);
|
|
389
389
|
}
|
|
390
390
|
// needs to be wiped last
|
|
391
391
|
await this.encryptedDb?.wipe();
|
|
392
|
-
}
|
|
392
|
+
};
|
|
393
393
|
/**
|
|
394
394
|
* Will delete the identity and history of the current user
|
|
395
395
|
*/
|
|
396
|
-
async
|
|
396
|
+
wipeAllData = async () => {
|
|
397
397
|
if (this.storeEngine) {
|
|
398
398
|
await (0, identityClearer_1.deleteIdentity)(this.storeEngine, false);
|
|
399
399
|
}
|
|
@@ -401,17 +401,17 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
401
401
|
await (0, CoreDB_1.deleteDB)(this.db);
|
|
402
402
|
}
|
|
403
403
|
await this.wipeCommonData();
|
|
404
|
-
}
|
|
404
|
+
};
|
|
405
405
|
/**
|
|
406
406
|
* Will delete the cryptography and client of the current user
|
|
407
407
|
* Will keep the history intact
|
|
408
408
|
*/
|
|
409
|
-
async
|
|
409
|
+
wipeCryptoData = async () => {
|
|
410
410
|
if (this.storeEngine) {
|
|
411
411
|
await (0, identityClearer_1.deleteIdentity)(this.storeEngine, true);
|
|
412
412
|
}
|
|
413
413
|
await this.wipeCommonData();
|
|
414
|
-
}
|
|
414
|
+
};
|
|
415
415
|
/**
|
|
416
416
|
* return true if the current user has a MLS device that is initialized and ready to use
|
|
417
417
|
*/
|
|
@@ -425,7 +425,7 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
425
425
|
* @param callbacks callbacks that will be called to handle different events
|
|
426
426
|
* @returns close a function that will disconnect from the websocket
|
|
427
427
|
*/
|
|
428
|
-
async
|
|
428
|
+
listen = async ({ onEvent = () => { }, onConnectionStateChanged: onConnectionStateChangedCallBack = () => { }, onNotificationStreamProgress = () => { }, onMissedNotifications = () => { }, dryRun = false, } = {}) => {
|
|
429
429
|
if (!this.currentClient) {
|
|
430
430
|
throw new Error('Client has not been initialized - please login first');
|
|
431
431
|
}
|
|
@@ -453,6 +453,8 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
453
453
|
*
|
|
454
454
|
* These two systems are separate, and the transition timing
|
|
455
455
|
* is important to avoid missing any messages during the switch.
|
|
456
|
+
*
|
|
457
|
+
* @todo This can be removed when all clients are capable of consumable notifications.
|
|
456
458
|
*/
|
|
457
459
|
if (!isClientCapableOfConsumableNotifications) {
|
|
458
460
|
// let the backend now client is capable of consumable notifications
|
|
@@ -462,26 +464,37 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
462
464
|
// do a quick legacy sync without connecting to any websockets
|
|
463
465
|
await processNotificationStream();
|
|
464
466
|
}
|
|
465
|
-
this.apiClient.connect()
|
|
467
|
+
this.apiClient.connect(() => {
|
|
468
|
+
(0, messageSender_1.pauseMessageSending)(); // pause message sending while processing notifications, it will be resumed once the processing is done and we have the marker token
|
|
469
|
+
/**
|
|
470
|
+
* unpause the notification processing queue
|
|
471
|
+
* it will start processing notifications immediately and pause if web socket connection drops
|
|
472
|
+
* we should start decryption and therefore acknowledging the notifications in order for the backend to
|
|
473
|
+
* send us the next batch of notifications, currently total size of notifications coming from web socket is limited to 500
|
|
474
|
+
* so we need to acknowledge the notifications to let the backend know we are ready for the next batch
|
|
475
|
+
*/
|
|
476
|
+
this.notificationProcessingQueue.pause(false);
|
|
477
|
+
});
|
|
466
478
|
return () => {
|
|
479
|
+
this.pauseAndFlushNotificationQueue();
|
|
467
480
|
this.apiClient.disconnect();
|
|
468
481
|
onConnectionStateChanged(ConnectionState.CLOSED);
|
|
469
482
|
this.apiClient.transport.ws.removeAllListeners();
|
|
470
483
|
};
|
|
471
|
-
}
|
|
472
|
-
createConnectionStateChangedHandler(onConnectionStateChanged) {
|
|
484
|
+
};
|
|
485
|
+
createConnectionStateChangedHandler = (onConnectionStateChanged) => {
|
|
473
486
|
return (state) => {
|
|
474
487
|
this.connectionState = state;
|
|
475
488
|
onConnectionStateChanged(state);
|
|
476
489
|
this.logger.info(`Connection state changed to: ${state}`);
|
|
477
490
|
};
|
|
478
|
-
}
|
|
491
|
+
};
|
|
479
492
|
/**
|
|
480
493
|
* Creates the event handler that is invoked for each decrypted event from the backend.
|
|
481
494
|
* Responsible for handling specific event types like `MESSAGE_TIMER_UPDATE`, and then
|
|
482
495
|
* forwarding the event to the consumer via the `onEvent` callback.
|
|
483
496
|
*/
|
|
484
|
-
createEventHandler(onEvent) {
|
|
497
|
+
createEventHandler = (onEvent) => {
|
|
485
498
|
return async (payload, source) => {
|
|
486
499
|
const { event } = payload;
|
|
487
500
|
switch (event?.type) {
|
|
@@ -495,8 +508,14 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
495
508
|
// Always forward the event to the consumer
|
|
496
509
|
onEvent(payload, source);
|
|
497
510
|
};
|
|
498
|
-
}
|
|
499
|
-
|
|
511
|
+
};
|
|
512
|
+
/**
|
|
513
|
+
* @deprecated This method is used to handle legacy notifications from the backend.
|
|
514
|
+
* It processes notifications from the legacy system, decrypts them, and emits events.
|
|
515
|
+
* It can be replaced with the new notification handling system using `ConsumableNotification`
|
|
516
|
+
* when all clients are capable of handling consumable notifications.
|
|
517
|
+
*/
|
|
518
|
+
createLegacyNotificationHandler = (handleEvent, dryRun) => {
|
|
500
519
|
return async (notification, source) => {
|
|
501
520
|
try {
|
|
502
521
|
const messages = this.service.notification.handleNotification(notification, source, dryRun);
|
|
@@ -508,83 +527,119 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
508
527
|
this.logger.error(`Failed to handle legacy notification "${notification.id}": ${error.message}`, error);
|
|
509
528
|
}
|
|
510
529
|
};
|
|
511
|
-
}
|
|
512
|
-
createNotificationHandler(handleEvent, onNotificationStreamProgress, onConnectionStateChanged, dryRun) {
|
|
530
|
+
};
|
|
531
|
+
createNotificationHandler = (handleEvent, onNotificationStreamProgress, onConnectionStateChanged, dryRun) => {
|
|
513
532
|
return async (notification, source) => {
|
|
514
533
|
try {
|
|
515
534
|
if (notification.type === ConsumableNotification_1.ConsumableEvent.MISSED) {
|
|
516
535
|
this.reactToMissedNotification();
|
|
517
536
|
return;
|
|
518
537
|
}
|
|
519
|
-
if (notification.type === ConsumableNotification_1.ConsumableEvent.
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
this.apiClient.transport.ws.acknowledgeMessageCountNotification();
|
|
524
|
-
(0, messageSender_1.pauseMessageSending)();
|
|
525
|
-
onConnectionStateChanged(ConnectionState.PROCESSING_NOTIFICATIONS);
|
|
526
|
-
if (count === 0) {
|
|
527
|
-
(0, messageSender_1.resumeMessageSending)();
|
|
528
|
-
onConnectionStateChanged(ConnectionState.LIVE);
|
|
529
|
-
}
|
|
530
|
-
else {
|
|
531
|
-
onNotificationStreamProgress({ total: count, done: 0 });
|
|
532
|
-
}
|
|
538
|
+
if (notification.type === ConsumableNotification_1.ConsumableEvent.SYNCHRONIZATION) {
|
|
539
|
+
void this.notificationProcessingQueue
|
|
540
|
+
.push(() => this.handleSynchronizationNotification(notification, onConnectionStateChanged))
|
|
541
|
+
.catch(this.handleNotificationQueueError);
|
|
533
542
|
return;
|
|
534
543
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
this.remainingNotifications++;
|
|
539
|
-
onNotificationStreamProgress({
|
|
540
|
-
done: this.remainingNotifications,
|
|
541
|
-
total: this.totalPendingNotifications,
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
this.apiClient.transport.ws.acknowledgeNotification(notification);
|
|
545
|
-
for await (const message of messages) {
|
|
546
|
-
await handleEvent(message, source);
|
|
547
|
-
}
|
|
548
|
-
if (this.totalPendingNotifications >= this.remainingNotifications &&
|
|
549
|
-
this.connectionState !== ConnectionState.LIVE) {
|
|
550
|
-
(0, messageSender_1.resumeMessageSending)();
|
|
551
|
-
onConnectionStateChanged(ConnectionState.LIVE);
|
|
552
|
-
}
|
|
544
|
+
void this.notificationProcessingQueue
|
|
545
|
+
.push(() => this.decryptAckEmitNotification(notification, handleEvent, source, onNotificationStreamProgress, dryRun))
|
|
546
|
+
.catch(this.handleNotificationQueueError);
|
|
553
547
|
}
|
|
554
548
|
catch (error) {
|
|
555
|
-
this.logger.error(`Failed to handle
|
|
549
|
+
this.logger.error(`Failed to handle notification "${notification.type}": ${error.message}`, error);
|
|
556
550
|
}
|
|
557
551
|
};
|
|
558
|
-
}
|
|
552
|
+
};
|
|
553
|
+
handleNotificationQueueError = (error) => {
|
|
554
|
+
if (error instanceof Error && error.message.includes('Queue was flushed')) {
|
|
555
|
+
// queue is flushed manually so we ignore the error
|
|
556
|
+
this.logger.info('Notification processing queue was flushed, ignoring error', error);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
throw error;
|
|
560
|
+
};
|
|
561
|
+
acknowledgeSynchronizationNotification = (notification) => {
|
|
562
|
+
this.apiClient.transport.ws.acknowledgeConsumableNotificationSynchronization(notification);
|
|
563
|
+
};
|
|
564
|
+
handleSynchronizationNotification = async (notification, onConnectionStateChanged) => {
|
|
565
|
+
this.acknowledgeSynchronizationNotification(notification);
|
|
566
|
+
const markerId = notification.data.marker_id;
|
|
567
|
+
const currentMarkerId = this.apiClient.transport.http.accessTokenStore.markerToken;
|
|
568
|
+
/**
|
|
569
|
+
* There is a chance that there might be multiple synchronization notifications (markers)
|
|
570
|
+
* in the queue in case websocket connection drops a few times
|
|
571
|
+
* Hence we only want to resume message sending and set the connection state to LIVE
|
|
572
|
+
* if the marker ID matches the current marker ID.
|
|
573
|
+
*/
|
|
574
|
+
if (markerId === currentMarkerId) {
|
|
575
|
+
(0, messageSender_1.resumeMessageSending)();
|
|
576
|
+
onConnectionStateChanged(ConnectionState.LIVE);
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
decryptAckEmitNotification = async (notification, handleEvent, source, onNotificationStreamProgress, dryRun) => {
|
|
580
|
+
try {
|
|
581
|
+
const payloads = this.service.notification.handleNotification(notification.data.event, source, dryRun);
|
|
582
|
+
const notificationTime = this.getNotificationEventTime(notification.data.event.payload[0]);
|
|
583
|
+
if (this.connectionState !== ConnectionState.LIVE && notificationTime) {
|
|
584
|
+
onNotificationStreamProgress(notificationTime);
|
|
585
|
+
}
|
|
586
|
+
if (!dryRun) {
|
|
587
|
+
this.apiClient.transport.ws.acknowledgeNotification(notification);
|
|
588
|
+
}
|
|
589
|
+
for await (const payload of payloads ?? []) {
|
|
590
|
+
await handleEvent(payload, source);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
catch (err) {
|
|
594
|
+
this.logger.error(`Failed to process notification ${notification.data.delivery_tag}`, err);
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
getNotificationEventTime = (backendEvent) => {
|
|
598
|
+
if ('time' in backendEvent && typeof backendEvent.time === 'string') {
|
|
599
|
+
return backendEvent.time;
|
|
600
|
+
}
|
|
601
|
+
return null;
|
|
602
|
+
};
|
|
559
603
|
/**
|
|
560
604
|
* Returns a function to handle missed notifications — i.e., when the backend indicates
|
|
561
605
|
* that some notifications were lost due to age (typically >28 days).
|
|
562
606
|
* Also handles MLS-specific epoch mismatch recovery by triggering a conversation rejoin.
|
|
607
|
+
*
|
|
608
|
+
* @deprecated This is used to handle legacy missed notifications.
|
|
609
|
+
* It should be replaced with the new notification handling system using `ConsumableNotification`.
|
|
610
|
+
* when all clients are capable of handling consumable notifications.
|
|
563
611
|
*/
|
|
564
|
-
createLegacyMissedNotificationsHandler(onMissedNotifications) {
|
|
612
|
+
createLegacyMissedNotificationsHandler = (onMissedNotifications) => {
|
|
565
613
|
return async (notificationId) => {
|
|
566
614
|
if (this.hasMLSDevice) {
|
|
567
615
|
(0, conversationRejoinQueue_1.queueConversationRejoin)('all-conversations', () => this.service.conversation.handleConversationsEpochMismatch());
|
|
568
616
|
}
|
|
569
617
|
return onMissedNotifications(notificationId);
|
|
570
618
|
};
|
|
571
|
-
}
|
|
619
|
+
};
|
|
572
620
|
/**
|
|
573
621
|
* Returns a processor function for the notification stream (legacy sync).
|
|
574
622
|
* It pauses message sending and MLS rejoining during stream handling to prevent race conditions,
|
|
575
623
|
* then resumes normal operations after sync is complete.
|
|
576
624
|
*
|
|
625
|
+
* @deprecated This is used to do a final sync of the legacy notification stream
|
|
626
|
+
* before switching to the new notification handling system using `ConsumableNotification`.
|
|
627
|
+
* It should be replaced with the new notification handling system when all clients are capable of handling consumable notifications.
|
|
628
|
+
*
|
|
577
629
|
* @param handlers Various logic handlers wired to notification callbacks
|
|
578
630
|
*/
|
|
579
|
-
createLegacyNotificationStreamProcessor({ handleLegacyNotification, handleMissedNotifications, onNotificationStreamProgress, onConnectionStateChanged, }) {
|
|
631
|
+
createLegacyNotificationStreamProcessor = ({ handleLegacyNotification, handleMissedNotifications, onNotificationStreamProgress, onConnectionStateChanged, }) => {
|
|
580
632
|
return async () => {
|
|
581
633
|
(0, messageSender_1.pauseMessageSending)();
|
|
582
634
|
// We want to avoid triggering rejoins of out-of-sync MLS conversations while we are processing the notification stream
|
|
583
635
|
(0, conversationRejoinQueue_1.pauseRejoiningMLSConversations)();
|
|
584
636
|
onConnectionStateChanged(ConnectionState.PROCESSING_NOTIFICATIONS);
|
|
585
|
-
const results = await this.service.notification.
|
|
637
|
+
const results = await this.service.notification.legacyProcessNotificationStream(async (notification, source) => {
|
|
586
638
|
await handleLegacyNotification(notification, source);
|
|
587
|
-
|
|
639
|
+
const notificationTime = this.getNotificationEventTime(notification.payload[0]);
|
|
640
|
+
if (notificationTime) {
|
|
641
|
+
onNotificationStreamProgress(notificationTime);
|
|
642
|
+
}
|
|
588
643
|
}, handleMissedNotifications);
|
|
589
644
|
this.logger.info('Finished processing notifications from the legacy endpoint', results);
|
|
590
645
|
// We need to wait for the notification stream to be fully handled before releasing the message sending queue.
|
|
@@ -594,7 +649,18 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
594
649
|
(0, conversationRejoinQueue_1.resumeRejoiningMLSConversations)();
|
|
595
650
|
onConnectionStateChanged(ConnectionState.LIVE);
|
|
596
651
|
};
|
|
597
|
-
}
|
|
652
|
+
};
|
|
653
|
+
/**
|
|
654
|
+
* In case of a closed connection, we flush the notification processing queue.
|
|
655
|
+
* As we are not acknowledging them before decryption is done
|
|
656
|
+
* they will be resent next time the connection is opened
|
|
657
|
+
* this is to avoid duplicate decryption of notifications
|
|
658
|
+
*/
|
|
659
|
+
pauseAndFlushNotificationQueue = () => {
|
|
660
|
+
this.notificationProcessingQueue.pause();
|
|
661
|
+
this.notificationProcessingQueue.flush();
|
|
662
|
+
this.logger.info('Notification processing queue paused and flushed');
|
|
663
|
+
};
|
|
598
664
|
/**
|
|
599
665
|
* Sets up WebSocket event listeners for:
|
|
600
666
|
* - Incoming backend messages
|
|
@@ -602,7 +668,7 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
602
668
|
* On each new backend message, we pass it to the notification handler.
|
|
603
669
|
* On state changes, we map raw socket states to public connection states and emit them.
|
|
604
670
|
*/
|
|
605
|
-
setupWebSocketListeners(handleNotification, onConnectionStateChanged) {
|
|
671
|
+
setupWebSocketListeners = (handleNotification, onConnectionStateChanged) => {
|
|
606
672
|
this.apiClient.transport.ws.removeAllListeners(tcp_1.WebSocketClient.TOPIC.ON_MESSAGE);
|
|
607
673
|
this.apiClient.transport.ws.on(tcp_1.WebSocketClient.TOPIC.ON_MESSAGE, notification => handleNotification(notification, notification_1.NotificationSource.WEBSOCKET));
|
|
608
674
|
this.apiClient.transport.ws.on(tcp_1.WebSocketClient.TOPIC.ON_STATE_CHANGE, wsState => {
|
|
@@ -611,11 +677,14 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
611
677
|
[ReconnectingWebsocket_1.WEBSOCKET_STATE.CONNECTING]: ConnectionState.CONNECTING,
|
|
612
678
|
};
|
|
613
679
|
const connectionState = mapping[wsState];
|
|
680
|
+
if (connectionState === ConnectionState.CLOSED) {
|
|
681
|
+
this.pauseAndFlushNotificationQueue();
|
|
682
|
+
}
|
|
614
683
|
if (connectionState) {
|
|
615
684
|
onConnectionStateChanged(connectionState);
|
|
616
685
|
}
|
|
617
686
|
});
|
|
618
|
-
}
|
|
687
|
+
};
|
|
619
688
|
/**
|
|
620
689
|
* Handles logic for reacting to a missed notification event.
|
|
621
690
|
*
|
|
@@ -637,7 +706,7 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
637
706
|
* the WebSocket transport, unblocking the backend so it resumes sending updates
|
|
638
707
|
* then we remove the flag.
|
|
639
708
|
*/
|
|
640
|
-
reactToMissedNotification() {
|
|
709
|
+
reactToMissedNotification = () => {
|
|
641
710
|
const localStorageKey = 'has_missing_notification';
|
|
642
711
|
// First-time handling: set flag and reload to trigger full re-fetch of state.
|
|
643
712
|
if (!exports.AccountLocalStorageStore.has(localStorageKey)) {
|
|
@@ -648,24 +717,24 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
648
717
|
// After reload: acknowledge the missed notification so backend resumes notifications.
|
|
649
718
|
this.apiClient.transport.ws.acknowledgeMissedNotification();
|
|
650
719
|
exports.AccountLocalStorageStore.remove(localStorageKey);
|
|
651
|
-
}
|
|
652
|
-
getClientCapabilities() {
|
|
720
|
+
};
|
|
721
|
+
getClientCapabilities = () => {
|
|
653
722
|
return this.currentClient?.capabilities || [];
|
|
654
|
-
}
|
|
655
|
-
checkIsConsumable(notification) {
|
|
723
|
+
};
|
|
724
|
+
checkIsConsumable = (notification) => {
|
|
656
725
|
return 'type' in notification;
|
|
657
|
-
}
|
|
658
|
-
generateDbName(context) {
|
|
726
|
+
};
|
|
727
|
+
generateDbName = (context) => {
|
|
659
728
|
const clientType = context.clientType === client_1.ClientType.NONE ? '' : `@${context.clientType}`;
|
|
660
729
|
return `wire@${this.apiClient.config.urls.name}@${context.userId}${clientType}`;
|
|
661
|
-
}
|
|
662
|
-
generateCoreDbName(context) {
|
|
730
|
+
};
|
|
731
|
+
generateCoreDbName = (context) => {
|
|
663
732
|
return `core-${this.generateDbName(context)}`;
|
|
664
|
-
}
|
|
665
|
-
generateEncryptedDbName(context) {
|
|
733
|
+
};
|
|
734
|
+
generateEncryptedDbName = (context) => {
|
|
666
735
|
return `secrets-${this.generateDbName(context)}`;
|
|
667
|
-
}
|
|
668
|
-
async
|
|
736
|
+
};
|
|
737
|
+
initEngine = async (context, encryptedStore) => {
|
|
669
738
|
const dbName = this.generateDbName(context);
|
|
670
739
|
this.logger.debug(`Initialising store with name "${dbName}"...`);
|
|
671
740
|
const openDb = async () => {
|
|
@@ -686,14 +755,14 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
686
755
|
await this.persistCookie(storeEngine, cookie);
|
|
687
756
|
}
|
|
688
757
|
return storeEngine;
|
|
689
|
-
}
|
|
758
|
+
};
|
|
690
759
|
groupIdFromConversationId = async (conversationId, subconversationId) => {
|
|
691
760
|
if (!subconversationId) {
|
|
692
761
|
return this.coreCallbacks?.groupIdFromConversationId(conversationId);
|
|
693
762
|
}
|
|
694
763
|
return this.service?.subconversation.getSubconversationGroupId(conversationId, subconversationId);
|
|
695
764
|
};
|
|
696
|
-
async
|
|
765
|
+
isMLSActiveForClient = async () => {
|
|
697
766
|
// Check for CoreCrypto library, it is required for MLS
|
|
698
767
|
if (!this.options.coreCryptoConfig?.enabled) {
|
|
699
768
|
return false;
|
|
@@ -705,6 +774,6 @@ class Account extends commons_1.TypedEventEmitter {
|
|
|
705
774
|
// Check if MLS is enabled for the public via backend feature flag
|
|
706
775
|
const commonConfig = (await this.service?.team.getCommonFeatureConfig()) ?? {};
|
|
707
776
|
return commonConfig[team_1.FEATURE_KEY.MLS]?.status === team_1.FeatureStatus.ENABLED;
|
|
708
|
-
}
|
|
777
|
+
};
|
|
709
778
|
}
|
|
710
779
|
exports.Account = Account;
|
package/lib/Account.test.js
CHANGED
|
@@ -43,6 +43,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
43
43
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
44
|
const auth_1 = require("@wireapp/api-client/lib/auth");
|
|
45
45
|
const client_1 = require("@wireapp/api-client/lib/client");
|
|
46
|
+
const Config_1 = require("@wireapp/api-client/lib/Config");
|
|
46
47
|
const conversation_1 = require("@wireapp/api-client/lib/conversation");
|
|
47
48
|
const http_1 = require("@wireapp/api-client/lib/http");
|
|
48
49
|
const notification_1 = require("@wireapp/api-client/lib/notification");
|
|
@@ -104,8 +105,8 @@ describe('Account', () => {
|
|
|
104
105
|
token_type: 'Bearer',
|
|
105
106
|
user: 'aaf9a833-ef30-4c22-86a0-9adc8a15b3b4',
|
|
106
107
|
};
|
|
107
|
-
const
|
|
108
|
-
const websocketServerAddress = `${MOCK_BACKEND.ws}/v${
|
|
108
|
+
const markerId = '90da5591-0a26-45f8-bbb2-6c0fc4a2df19';
|
|
109
|
+
const websocketServerAddress = `${MOCK_BACKEND.ws}/v${Config_1.MINIMUM_API_VERSION}/events?access_token=${accessTokenData.access_token}&marker=${markerId}`;
|
|
109
110
|
beforeEach(() => {
|
|
110
111
|
(0, nock_1.default)(MOCK_BACKEND.rest)
|
|
111
112
|
.post(auth_1.AuthAPI.URL.LOGIN, body => body.email && body.password)
|
|
@@ -138,9 +139,9 @@ describe('Account', () => {
|
|
|
138
139
|
(0, nock_1.default)(MOCK_BACKEND.rest)
|
|
139
140
|
.get(`/api-version`)
|
|
140
141
|
.reply(http_status_codes_1.StatusCodes.OK, {
|
|
141
|
-
supported: [
|
|
142
|
+
supported: [Config_1.MINIMUM_API_VERSION],
|
|
142
143
|
federation: false,
|
|
143
|
-
development: [
|
|
144
|
+
development: [Config_1.MINIMUM_API_VERSION + 1],
|
|
144
145
|
domain: 'zinfra.io',
|
|
145
146
|
});
|
|
146
147
|
(0, nock_1.default)(MOCK_BACKEND.rest)
|
|
@@ -276,7 +277,11 @@ describe('Account', () => {
|
|
|
276
277
|
jest
|
|
277
278
|
.spyOn(dependencies.account.service.notification['database'], 'getLastNotificationId')
|
|
278
279
|
.mockResolvedValue('0');
|
|
279
|
-
await account.useAPIVersion(
|
|
280
|
+
await account.useAPIVersion(Config_1.MINIMUM_API_VERSION, Config_1.MINIMUM_API_VERSION);
|
|
281
|
+
jest
|
|
282
|
+
.spyOn(dependencies.apiClient.transport.ws, 'buildWebSocketUrl')
|
|
283
|
+
.mockResolvedValue(websocketServerAddress);
|
|
284
|
+
jest.spyOn(dependencies.account, 'getNotificationEventTime').mockReturnValue('2025-10-01T00:00:00Z');
|
|
280
285
|
});
|
|
281
286
|
afterEach(() => {
|
|
282
287
|
server.close(); // ensure server shutdown
|
|
@@ -55,7 +55,17 @@ export declare class NotificationService extends TypedEventEmitter<Events> {
|
|
|
55
55
|
getNotificationEventList(): Promise<BackendEvent[]>;
|
|
56
56
|
setLastEventDate(eventDate: Date): Promise<Date>;
|
|
57
57
|
private setLastNotificationId;
|
|
58
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Processes the notification stream and calls the provided handler for each notification.
|
|
60
|
+
* If there are missed notifications, it will call the onMissedNotifications callback with the missed notification ID.
|
|
61
|
+
*
|
|
62
|
+
* @param notificationHandler - The handler to process each notification.
|
|
63
|
+
* @param onMissedNotifications - Callback to handle missed notifications.
|
|
64
|
+
* @returns An object containing the total number of notifications processed, number of errors, and successes.
|
|
65
|
+
*
|
|
66
|
+
* @deprecated When all client are migrated to the consumable/async notification stream, this method must be removed.
|
|
67
|
+
*/
|
|
68
|
+
legacyProcessNotificationStream(notificationHandler: NotificationHandler, onMissedNotifications: (notificationId: string) => void): Promise<{
|
|
59
69
|
total: number;
|
|
60
70
|
error: number;
|
|
61
71
|
success: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationService.d.ts","sourceRoot":"","sources":["../../src/notification/NotificationService.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,YAAY,EAAC,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAC,YAAY,EAAC,MAAM,uCAAuC,CAAC;AAEnE,OAAO,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAa,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAC,cAAc,EAAC,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAC,UAAU,EAA4B,MAAM,uBAAuB,CAAC;AAI5E,OAAO,EAAC,kBAAkB,EAAC,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAC,mBAAmB,EAAC,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAY,iBAAiB,EAAC,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAC,eAAe,EAAC,MAAM,2BAA2B,CAAC;AAE1D,MAAM,MAAM,mBAAmB,GAAG;IAChC,0CAA0C;IAC1C,KAAK,EAAE,YAAY,CAAC;IACpB,kEAAkE;IAClE,aAAa,CAAC,EAAE,cAAc,CAAC;IAC/B,8FAA8F;IAC9F,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAC,MAAM,EAAE,WAAW,CAAA;CAAC,GACrB;IAAC,MAAM,EAAE,SAAS,CAAA;CAAC,GACnB;IAAC,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAA;CAAC,CAAC;AAE7D,aAAK,KAAK;IACR,kBAAkB,iDAAiD;CACpE;AAED,MAAM,MAAM,mBAAmB,GAAG,CAChC,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,KACpC,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,KAAK,MAAM,GAAG;IACZ,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,iBAAiB,CAAC;CAC/C,CAAC;AAEF,qBAAa,mBAAoB,SAAQ,iBAAiB,CAAC,MAAM,CAAC;IAU9D,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IATtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAC1D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6D;IACpF,gBAAuB,KAAK,eAAS;gBAGnC,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,UAAU,EACN,mBAAmB,EAAE,mBAAmB;YAQ7C,mBAAmB;IAKjC,0DAA0D;IAC7C,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAM/D,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAKpC,wBAAwB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAI7C,gBAAgB,CAAC,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;YAsB/C,qBAAqB;
|
|
1
|
+
{"version":3,"file":"NotificationService.d.ts","sourceRoot":"","sources":["../../src/notification/NotificationService.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,YAAY,EAAC,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAC,YAAY,EAAC,MAAM,uCAAuC,CAAC;AAEnE,OAAO,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAa,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAC,cAAc,EAAC,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAC,UAAU,EAA4B,MAAM,uBAAuB,CAAC;AAI5E,OAAO,EAAC,kBAAkB,EAAC,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAC,mBAAmB,EAAC,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAY,iBAAiB,EAAC,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAC,eAAe,EAAC,MAAM,2BAA2B,CAAC;AAE1D,MAAM,MAAM,mBAAmB,GAAG;IAChC,0CAA0C;IAC1C,KAAK,EAAE,YAAY,CAAC;IACpB,kEAAkE;IAClE,aAAa,CAAC,EAAE,cAAc,CAAC;IAC/B,8FAA8F;IAC9F,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAC,MAAM,EAAE,WAAW,CAAA;CAAC,GACrB;IAAC,MAAM,EAAE,SAAS,CAAA;CAAC,GACnB;IAAC,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAA;CAAC,CAAC;AAE7D,aAAK,KAAK;IACR,kBAAkB,iDAAiD;CACpE;AAED,MAAM,MAAM,mBAAmB,GAAG,CAChC,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,KACpC,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,KAAK,MAAM,GAAG;IACZ,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,iBAAiB,CAAC;CAC/C,CAAC;AAEF,qBAAa,mBAAoB,SAAQ,iBAAiB,CAAC,MAAM,CAAC;IAU9D,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IATtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAC1D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6D;IACpF,gBAAuB,KAAK,eAAS;gBAGnC,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,UAAU,EACN,mBAAmB,EAAE,mBAAmB;YAQ7C,mBAAmB;IAKjC,0DAA0D;IAC7C,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAM/D,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAKpC,wBAAwB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAI7C,gBAAgB,CAAC,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;YAsB/C,qBAAqB;IAInC;;;;;;;;;OASG;IACU,+BAA+B,CAC1C,mBAAmB,EAAE,mBAAmB,EACxC,qBAAqB,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,GACtD,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;IA6B3D;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAYT,kBAAkB,CAC9B,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,GAAE,OAAe,GACtB,cAAc,CAAC,mBAAmB,CAAC;IAmCtC;;;;;OAKG;YACW,WAAW;CAc1B"}
|
|
@@ -80,7 +80,17 @@ class NotificationService extends commons_1.TypedEventEmitter {
|
|
|
80
80
|
async setLastNotificationId(lastNotification) {
|
|
81
81
|
return this.database.updateLastNotificationId(lastNotification);
|
|
82
82
|
}
|
|
83
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Processes the notification stream and calls the provided handler for each notification.
|
|
85
|
+
* If there are missed notifications, it will call the onMissedNotifications callback with the missed notification ID.
|
|
86
|
+
*
|
|
87
|
+
* @param notificationHandler - The handler to process each notification.
|
|
88
|
+
* @param onMissedNotifications - Callback to handle missed notifications.
|
|
89
|
+
* @returns An object containing the total number of notifications processed, number of errors, and successes.
|
|
90
|
+
*
|
|
91
|
+
* @deprecated When all client are migrated to the consumable/async notification stream, this method must be removed.
|
|
92
|
+
*/
|
|
93
|
+
async legacyProcessNotificationStream(notificationHandler, onMissedNotifications) {
|
|
84
94
|
const lastNotificationId = await this.database.getLastNotificationId();
|
|
85
95
|
const { notifications, missedNotification } = await this.getAllNotifications(lastNotificationId);
|
|
86
96
|
if (missedNotification) {
|
package/package.json
CHANGED
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
"./lib/cryptography/AssetCryptography/crypto.node": "./lib/cryptography/AssetCryptography/crypto.browser.js"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@wireapp/api-client": "^27.
|
|
14
|
+
"@wireapp/api-client": "^27.68.0",
|
|
15
15
|
"@wireapp/commons": "^5.4.2",
|
|
16
16
|
"@wireapp/core-crypto": "7.0.1",
|
|
17
17
|
"@wireapp/cryptobox": "12.8.0",
|
|
18
18
|
"@wireapp/priority-queue": "^2.1.11",
|
|
19
|
-
"@wireapp/promise-queue": "^2.
|
|
19
|
+
"@wireapp/promise-queue": "^2.4.0",
|
|
20
20
|
"@wireapp/protocol-messaging": "1.52.0",
|
|
21
21
|
"@wireapp/store-engine": "^5.1.11",
|
|
22
22
|
"axios": "1.7.9",
|
|
@@ -61,6 +61,6 @@
|
|
|
61
61
|
"test:coverage": "jest --coverage",
|
|
62
62
|
"watch": "tsc --watch"
|
|
63
63
|
},
|
|
64
|
-
"version": "46.
|
|
65
|
-
"gitHead": "
|
|
64
|
+
"version": "46.31.1",
|
|
65
|
+
"gitHead": "06e058b2059471dda5adf3371b145c064986a72d"
|
|
66
66
|
}
|