import { RegisterData, Context, Cookie, LoginData } from '@wireapp/api-client/lib/auth'; import { ClientCapability, ClientType, RegisteredClient } from '@wireapp/api-client/lib/client/'; import * as Events from '@wireapp/api-client/lib/event'; import { Notification } from '@wireapp/api-client/lib/notification/'; import { ConsumableNotification } from '@wireapp/api-client/lib/notification/ConsumableNotification'; import { APIClient, BackendFeatures } from '@wireapp/api-client'; import { TypedEventEmitter } from '@wireapp/commons'; import type { CoreCryptoLogLevel } from '@wireapp/core-crypto'; import { CRUDEngine } from '@wireapp/store-engine'; import { AccountService } from './account/'; import { BroadcastService } from './broadcast/'; import { ClientInfo, ClientService } from './client/'; import { ConnectionService } from './connection/'; import { AssetService, ConversationService } from './conversation/'; import { SubconversationService } from './conversation/SubconversationService/SubconversationService'; import { GiphyService } from './giphy/'; import { LinkPreviewService } from './linkPreview'; import { CoreCryptoConfig } from './messagingProtocols/common.types'; import { InitClientOptions, MLSService } from './messagingProtocols/mls'; import { E2EIServiceExternal } from './messagingProtocols/mls/E2EIdentityService'; import { getAllConversationsCallback, getTokenCallback } from './messagingProtocols/mls/E2EIdentityService/E2EIServiceInternal'; import { CoreCallbacks, SecretCrypto } from './messagingProtocols/mls/types'; import { NewClient, ProteusService } from './messagingProtocols/proteus'; import { HandledEventPayload, NotificationService, NotificationSource } from './notification/'; import { SelfService } from './self/'; import { TeamService } from './team/'; import { UserService } from './user/'; import { RecurringTaskScheduler } from './util/RecurringTaskScheduler'; export type ProcessedEventPayload = HandledEventPayload; export declare enum ConnectionState { /** The WebSocket is closed and no notifications are being processed */ CLOSED = "closed", /** The WebSocket is being opened or reconnected */ CONNECTING = "connecting", /** The websocket is open but locked and notifications stream is being processed */ PROCESSING_NOTIFICATIONS = "processing_notifications", /** The WebSocket is open and new messages are processed live in real time */ LIVE = "live" } export type CreateStoreFn = (storeName: string, key: Uint8Array) => undefined | Promise; interface AccountOptions { /** Used to store info in the database (will create a inMemory engine if returns undefined) */ createStore?: CreateStoreFn; systemCrypto?: SecretCrypto; coreCryptoConfig?: CoreCryptoConfig; /** Number of prekeys to generate when creating a new device (defaults to 2) * Prekeys are Diffie-Hellmann public keys which allow offline initiation of a secure Proteus session between two devices. * Having a high value will: * - make creating a new device consuming more CPU resources * - make it less likely that all prekeys get consumed while the device is offline and the last resort prekey will not be used to create new session * Having a low value will: * - make creating a new device fast * - make it likely that all prekeys get consumed while the device is offline and the last resort prekey will be used to create new session */ nbPrekeys: number; } type InitOptions = { /** cookie used to identify the current user. Will use the browser cookie if not defined */ cookie?: Cookie; }; export declare enum EVENTS { /** * event triggered when a message from an unknown client is received. * An unknown client is a client we don't yet have a session with */ NEW_SESSION = "new_session" } type Events = { [EVENTS.NEW_SESSION]: NewClient; }; export declare const AccountLocalStorageStore: { get: (key: string) => string | undefined; add: (key: string, value: string) => void; remove: (key: string) => void; has: (key: string) => boolean; }; export declare class Account extends TypedEventEmitter { private readonly options; private readonly apiClient; private readonly logger; /** this is the client the consumer is currently using. Will be set as soon as `initClient` is called and will be rest upon logout */ private currentClient?; private storeEngine?; private db?; private encryptedDb?; private coreCallbacks?; private connectionState; private readonly notificationProcessingQueue; setMaxCoreCryptoLogLevel: (level: CoreCryptoLogLevel) => void; service?: { mls?: MLSService; e2eIdentity?: E2EIServiceExternal; proteus: ProteusService; account: AccountService; asset: AssetService; broadcast: BroadcastService; client: ClientService; connection: ConnectionService; conversation: ConversationService; subconversation: SubconversationService; giphy: GiphyService; linkPreview: LinkPreviewService; notification: NotificationService; self: SelfService; team: TeamService; user: UserService; }; backendFeatures: BackendFeatures; recurringTaskScheduler: RecurringTaskScheduler; /** * @param apiClient The apiClient instance to use in the core (will create a new new one if undefined) * @param accountOptions */ constructor(apiClient?: APIClient, options?: AccountOptions); /** * Will set the APIClient to use a specific version of the API (by default uses version 0) * It will fetch the API Config and use the highest possible version * @param min mininum version to use * @param max maximum version to use * @param allowDev allow the api-client to use development version of the api (if present). The dev version also need to be listed on the supportedVersions given as parameters * If we have version 2 that is a dev version, this is going to be the output of those calls * - useVersion(0, 2, true) > version 2 is used * - useVersion(0, 2) > version 1 is used * - useVersion(0, 1, true) > version 1 is used * @return The highest version that is both supported by client and backend */ useAPIVersion: (min: number, max: number, allowDev?: boolean) => Promise; private readonly persistCookie; enrollE2EI: ({ displayName, handle, teamId, discoveryUrl, getOAuthToken, getAllConversations, certificateTtl, }: { /** display name of the user (should match the identity provider) */ displayName: string; /** handle of the user (should match the identity provider) */ handle: string; /** team of the user */ teamId: string; discoveryUrl: string; /** function called to get the oauth token */ getOAuthToken: getTokenCallback; /** function called to get all conversations */ getAllConversations: getAllConversationsCallback; /** number of seconds the certificate should be valid (default 90 days) */ certificateTtl?: number; }) => Promise; get clientId(): string; get userId(): string; /** * Will register a new user to the backend * * @param registration The user's data * @param clientType Type of client to create (temporary or permanent) */ register: (registration: RegisterData, clientType: ClientType) => Promise; /** * Will init the core with an already logged in user * * @param clientType The type of client the user is using (temporary or permanent) */ init: (clientType: ClientType, { cookie }?: InitOptions) => Promise; /** * Will log the user in with the given credential. * * @param loginData The credentials of the user * @param clientInfo Info about the client to create (name, type...) */ login: (loginData: LoginData) => Promise; /** * Will register a new client for the current user */ registerClient: (loginData: LoginData, useLegacyNotificationStream: boolean, entropyData?: Uint8Array, clientInfo?: ClientInfo) => Promise; getLocalClient(): Promise | undefined; /** * Will initiate all the cryptographic material of the given registered device and setup all the background tasks. * * @returns The local existing client or undefined if the client does not exist or is not valid (non existing on backend) */ initClient: (client: RegisteredClient, mlsConfig?: InitClientOptions) => Promise; private readonly buildCryptoClient; /** * In order to be able to send MLS messages, the core needs a few information from the consumer. * Namely: * - is the current user allowed to administrate a specific conversation * - what is the groupId of a conversation * @param coreCallbacks */ configureCoreCallbacks: (coreCallbacks: CoreCallbacks) => void; private readonly initServices; private readonly resetContext; /** * Will logout the current user * @param clearData if set to `true` will completely wipe any database that was created by the Account */ logout: (data?: { clearAllData?: boolean; clearCryptoData?: boolean; }) => Promise; private readonly wipeCommonData; /** * Will delete the identity and history of the current user */ private readonly wipeAllData; /** * Will delete the cryptography and client of the current user * Will keep the history intact */ private readonly wipeCryptoData; /** * return true if the current user has a MLS device that is initialized and ready to use */ get hasMLSDevice(): boolean; /** * Will download and handle the notification stream since last stored notification id. * Once the notification stream has been handled from backend, will then connect to the websocket and start listening to incoming events * * @param callbacks callbacks that will be called to handle different events * @returns close a function that will disconnect from the websocket */ listen: ({ useLegacy, onEvent, onConnectionStateChanged: onConnectionStateChangedCallBack, onNotificationStreamProgress, onMissedNotifications, }?: { /** * Called when a new event arrives from backend * @param payload the payload of the event. Contains the raw event received and the decrypted data (if event was encrypted) * @param source where the message comes from (either websocket or notification stream) */ onEvent?: (payload: HandledEventPayload, source: NotificationSource) => Promise; /** * During the notification stream processing, this function will be called whenever a new notification has been processed */ onNotificationStreamProgress?: (currentProcessingNotificationTimestamp: string) => void; /** * called when the connection state with the backend has changed */ onConnectionStateChanged?: (state: ConnectionState) => void; /** * called when we detect lost notification from backend. * When a client doesn't log in for a while (28 days, as of now) notifications that are older than 28 days will be deleted from backend. * If the client query the backend for the notifications since a particular notification ID and this ID doesn't exist anymore on the backend, we deduce that some messages were not sync before they were removed from backend. * We can then detect that something was wrong and warn the consumer that there might be some missing old messages * @param {string} notificationId */ onMissedNotifications?: (notificationId: string) => void; /** * When set to true, will use the legacy notification stream instead of the new async notifications. */ useLegacy?: boolean; /** * 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 * @deprecated Core doesn't support dryRun mode anymore and this parameter will be removed in future versions */ dryRun?: boolean; }) => Promise<() => void>; private readonly createConnectionStateChangedHandler; /** * Creates the event handler that is invoked for each decrypted event from the backend. * Responsible for handling specific event types like `MESSAGE_TIMER_UPDATE`, and then * forwarding the event to the consumer via the `onEvent` callback. */ private readonly createEventHandler; /** * @deprecated This method is used to handle legacy notifications from the backend. * It processes notifications from the legacy system, decrypts them, and emits events. * It can be replaced with the new notification handling system using `ConsumableNotification` * when all clients are capable of handling consumable notifications. */ private readonly createLegacyNotificationHandler; private readonly createNotificationHandler; private readonly handleNotificationQueueError; private readonly acknowledgeSynchronizationNotification; private readonly handleSynchronizationNotification; private readonly decryptAckEmitNotification; getNotificationEventTime: (backendEvent: Events.BackendEvent) => string | null; /** * Returns a function to handle missed notifications — i.e., when the backend indicates * that some notifications were lost due to age (typically >28 days). * Also handles MLS-specific epoch mismatch recovery by triggering a conversation rejoin. * * @deprecated This is used to handle legacy missed notifications. * It should be replaced with the new notification handling system using `ConsumableNotification`. * when all clients are capable of handling consumable notifications. */ private readonly createLegacyMissedNotificationsHandler; /** * Returns a processor function for the notification stream (legacy sync). * It pauses message sending and MLS rejoining during stream handling to prevent race conditions, * then resumes normal operations after sync is complete. * * @deprecated This is used to do a final sync of the legacy notification stream * before switching to the new notification handling system using `ConsumableNotification`. * It should be replaced with the new notification handling system when all clients are capable of handling consumable notifications. * * @param handlers Various logic handlers wired to notification callbacks */ private readonly createLegacyNotificationStreamProcessor; /** * In case of a closed connection, we flush the notification processing queue. * As we are not acknowledging them before decryption is done * they will be resent next time the connection is opened * this is to avoid duplicate decryption of notifications */ private readonly pauseAndFlushNotificationQueue; readonly pauseNotificationQueue: () => void; readonly resumeNotificationQueue: () => void; /** * Sets up WebSocket event listeners for: * - Incoming backend messages * - WebSocket state changes * On each new backend message, we pass it to the notification handler. * On state changes, we map raw socket states to public connection states and emit them. */ private readonly setupWebSocketListeners; /** * Handles logic for reacting to a missed notification event. * * The backend sends a special "missed notification" signal if it detects * that the client has missed one or more notifications. Once this signal is sent, * the backend will **stop sending all further notifications** until the client * acknowledges the missed state. * * Because our app currently lacks functionality to perform a full real-time sync * while running, we must reload the application to re-fetch the entire state. * * On first detection of the missed notification: * - We set a local storage flag (`has_missing_notification`) to mark that we've * entered this state. * - We reload the application so the state can be re-fetched from scratch. * * On the next load: * - If the flag is already present, we acknowledge the missed notification via * the WebSocket transport, unblocking the backend so it resumes sending updates * then we remove the flag. */ private readonly reactToMissedNotification; getClientCapabilities: () => ClientCapability[]; static checkIsConsumable: (notification: Notification | ConsumableNotification) => notification is ConsumableNotification; static checkIsLegacyNotification: (notification: Notification | ConsumableNotification) => notification is Notification; private readonly generateDbName; private readonly generateCoreDbName; private readonly generateEncryptedDbName; private readonly initEngine; private readonly groupIdFromConversationId; isMLSActiveForClient: () => Promise; private readonly isMLSConversationRecoveryEnabled; /** * Checks the health of the WebSocket connection by sending a ping and waiting for a pong response. * This is a non-disruptive check that does not close or reconnect the socket. * @returns A promise that resolves to true if the socket responds with a pong within the timeout, false otherwise. * * @example * const healthy = await account.isWebsocketHealthy(); * if (!healthy) { * // handle unhealthy websocket * } */ isWebsocketHealthy: () => Promise; } export {}; //# sourceMappingURL=Account.d.ts.map