import { Client, type DidString } from '@atproto/lex'; import type { SessionData } from '@atproto/lex-password-session'; import { com } from '@pds-moover/lexicons'; type AccountStatus = com.atproto.server.checkAccountStatus.$OutputBody; /** Rate-limit summary surfaced to the UI when a 429 stopped the import. */ export interface MissingBlobsRateLimited { uploaded: number; remaining: number; resetAt?: Date; } /** * Class to help find missing blobs from the did's previous PDS and import them into the current PDS */ declare class MissingBlobs { /** * Client for the user's current PDS */ currentPdsClient: Client | null; /** * Client for the user's old PDS */ oldPdsClient: Client | null; /** * the user's did */ did: DidString | null; /** * The user's current PDS url */ currentPdsUrl: string | null; /** * The user's old PDS url. Set once the old side is known: either resolved/passed in by * oldAgentLogin() or rebuilt by restoreSessions() from the persisted old session. */ oldPdsUrl: string | null; /** * A list of the missing cids blobs from the old PDS. In this case if a retry upload fails it gets put in this array for the ui */ missingBlobs: string[]; /** * Called whenever the current ('current') or old ('old') login session is created or * refreshed (with its serializable SessionData), or deleted/invalidated (with null). Lets * the caller persist the session so a mid-flow page refresh can be resumed via * restoreSessions(). When null (the default), no persistence happens. */ onSessionUpdate: ((side: 'current' | 'old', data: SessionData | null) => void) | null; /** * Logs the user into the current PDS and gets the account status */ currentAgentLogin(handle: string, password: string, twoFactorCode?: string | null): Promise<{ accountStatus: AccountStatus; missingBlobsCount: number; }>; /** * Checks the current PDS account status and how many blobs are still missing (capped at 10). * Split out from currentAgentLogin so a resumed session can re-run the check without logging * in again. Throws if the current PDS client has not been set up (login or restoreSessions). */ checkMissingBlobs(): Promise<{ accountStatus: AccountStatus; missingBlobsCount: number; }>; /** * Finds the user's old PDS by walking their PLC audit log newest-first for the most recent * endpoint that isn't their current one. Split out of oldAgentLogin() so a resumed session can * name the old PDS before asking for its password. Throws when no other endpoint is in the log. */ resolveOldPds(): Promise; /** * Logs into the old PDS and gets the account status. * Does not need a handle * since it is assumed the user has already logged in with the current PDS and we are using their did * @param password * @param twoFactorCode * @param pdsUrl - If you know the url of the old PDS you can pass it in here. If not it will be guessed at from plc ops */ oldAgentLogin(password: string, twoFactorCode?: string | null, pdsUrl?: string | null): Promise; /** * Rebuilds the current and (when provided) old sessions from previously persisted SessionData * (see onSessionUpdate) so a mid-flow page refresh can be resumed without re-entering * credentials or triggering another 2FA email. Each session is refreshed via * PasswordSession.resume(), which throws only when the tokens are definitively invalid — the * caller should clear its cache and fall back to the login form in that case. The current * session is resumed first and is enough on its own (the old-PDS password step follows); pass * oldData to also rebuild the old-PDS client so migrateMissingBlobs() can run straight away. */ restoreSessions(currentData: SessionData, oldData?: SessionData): Promise; /** * Gets the missing blobs from the old PDS and uploads them to the current PDS * * A rate-limited transfer returns as soon as transferBlobs stops, without the closing * checkAccountStatus/listMissingBlobs round-trips: those go to the PDS that is currently * rate limiting us, so they stall the UI right when it has a result to show. The reported * counts are instead derived from the status fetched just before the transfer plus what the * transfer uploaded, which is the same trick Migrator.handleBlobRateLimit uses. This also * matters for the headroom stop, where spending the last requests here would defeat the * point of holding quota back for the user's own app. * * @param statusUpdateHandler - A function to update the status of the migration. This is useful for showing the user the progress of the migration */ migrateMissingBlobs(statusUpdateHandler: (status: string) => void): Promise<{ accountStatus: AccountStatus; missingBlobsCount: number; rateLimited?: MissingBlobsRateLimited; }>; } export { MissingBlobs }; //# sourceMappingURL=missingBlobs.d.ts.map