import { AppSyncClient } from '../appsync/appsync-client'; /** * Options for re-keying behavior. */ export interface RekeyOptions { /** * Set of deviceIds that should be force-wrapped (granted) even if * they already have an entry in `session.encryptedKeys`. Use this * when you know a specific device just re-registered — for example, * when handling an `onDeviceKeyRegistered` subscription event — so * a rotated public key gets a fresh wrapped entry. The old entry * is left intact; the new one is appended via `grantSessionKey`. * * Default: empty. The bulk diff path (catch-up after disconnect, * catch-up at session resume) does not pass this and relies on the * standard "deviceId missing from encryptedKeys" comparison. */ forceDeviceIds?: ReadonlySet; } /** * Compare the current list of registered devices for the authenticated * user against the session's encryptedKeys array, and grant the session * key to any device that is missing an entry (or that the caller has * explicitly marked as needing a fresh wrap via `forceDeviceIds`). * * Safe to call repeatedly. No-op when every registered device already * has an entry and nothing is forced. Does not modify or remove existing * entries — only appends new ones via the grantSessionKey mutation. * * @param sessionId The session to re-key. * @param sessionKey The plaintext session key (base64). The caller must * already hold this — typically from * keychainManager.getCachedSessionKey(sessionId). * @param appSyncClient Authenticated AppSyncClient. * @param options Optional behavior knobs. See RekeyOptions. * @returns The number of new grants that succeeded. */ export declare function rekeySessionForNewDevices(sessionId: string, sessionKey: string, appSyncClient: AppSyncClient, options?: RekeyOptions): Promise; /** * Options for {@link awaitOwnSessionKeyGrant}. */ export interface AwaitOwnGrantOptions { /** Poll interval in ms. Default 5000. */ pollIntervalMs?: number; /** Max poll attempts. Default 6 (30s total at 5s intervals). */ maxAttempts?: number; /** Authenticated AppSyncClient. */ appSyncClient: AppSyncClient; /** Fired on successful decrypt. Telemetry-only — never thrown. */ onSuccess?: (attemptCount: number) => void; /** Fired after maxAttempts exhausted. Telemetry-only — never thrown. */ onTimeout?: (attemptCount: number) => void; } /** * Wait for this device's deviceId to appear in `session.encryptedKeys`. * * Triggered when {@link keychainManager.getSessionKey} returned null on * resume AND at least one other device IS in encryptedKeys (so some other * device can mint a grant for us via grantSessionKey). Caller must have * already invoked {@link registerDeviceEncryptionKey} BEFORE this helper — * that's what causes mobile's DeviceKeyWatcher subscription to fire and * grant the session key to our (possibly rotated) pubKey. * * This helper deliberately bypasses {@link keychainManager.getSessionKey} * (which has a cache short-circuit) and instead: * 1. Calls {@link AppSyncClient.getSession} each poll for fresh * `encryptedKeys`. * 2. Looks for our `deviceId` in the fresh list. * 3. If found, calls {@link cryptoService.decryptSessionKey} directly. * 4. On success, populates the keychain cache (so subsequent * `getSessionKey` calls hit the cache). The cache is NEVER populated * on failure — there's no null sentinel. * * Returns the decrypted session key on success, or `null` after timeout. * Errors are swallowed inside the loop (best-effort polling); telemetry * surfaces success vs timeout via the optional callbacks. */ export declare function awaitOwnSessionKeyGrant(sessionId: string, options: AwaitOwnGrantOptions): Promise;