export interface PiProviderAuthRecoveryOptions { accountId: string; operation: (attempt: 0 | 1) => Promise; isAuthenticationError: (error: unknown) => boolean; refreshCredential: () => Promise; reopenWorker: () => Promise; } export class PiProviderRefreshCoordinator { private readonly refreshes = new Map>(); get pendingAccountCount(): number { return this.refreshes.size; } async refreshAccount(accountId: string, refresh: () => Promise): Promise { const normalizedAccountId = accountId.trim(); if (!normalizedAccountId) throw new Error('Provider account id is required'); let pending = this.refreshes.get(normalizedAccountId); if (!pending) { pending = Promise.resolve() .then(refresh) .finally(() => { if (this.refreshes.get(normalizedAccountId) === pending) { this.refreshes.delete(normalizedAccountId); } }); this.refreshes.set(normalizedAccountId, pending); } await pending; } async withSingleAuthRecovery(options: PiProviderAuthRecoveryOptions): Promise { try { return await options.operation(0); } catch (error) { if (!options.isAuthenticationError(error)) throw error; } await this.refreshAccount(options.accountId, options.refreshCredential); await options.reopenWorker(); return await options.operation(1); } }