fix: Add abort mechanism for conditional UI to prevent pending request errors

- Add global AbortController for conditional UI requests
- Call abortConditionalUI() at start of registerPasskey and authenticatePasskey
- Export abortConditionalUI from index for manual use if needed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-02-05 19:14:56 +00:00
parent 20a51e7dce
commit 8e10f5cb03
2 changed files with 32 additions and 0 deletions

View File

@ -16,6 +16,7 @@ export {
registerPasskey,
authenticatePasskey,
startConditionalUI,
abortConditionalUI,
isConditionalMediationAvailable,
detectCapabilities,
bufferToBase64url,

View File

@ -44,6 +44,21 @@ const DEFAULT_CONFIG: EncryptIDConfig = {
timeout: 60000,
};
// Global abort controller for conditional UI
let conditionalUIAbortController: AbortController | null = null;
/**
* Abort any pending conditional UI request
* Call this before starting registration or authentication
*/
export function abortConditionalUI(): void {
if (conditionalUIAbortController) {
conditionalUIAbortController.abort();
conditionalUIAbortController = null;
console.log('EncryptID: Conditional UI aborted');
}
}
// ============================================================================
// UTILITY FUNCTIONS
// ============================================================================
@ -108,6 +123,9 @@ export async function registerPasskey(
displayName: string,
config: Partial<EncryptIDConfig> = {}
): Promise<EncryptIDCredential> {
// Abort any pending conditional UI to prevent "request already pending" error
abortConditionalUI();
const cfg = { ...DEFAULT_CONFIG, ...config };
// Check WebAuthn support
@ -237,6 +255,9 @@ export async function authenticatePasskey(
credentialId?: string, // Optional: specify credential, or let user choose
config: Partial<EncryptIDConfig> = {}
): Promise<AuthenticationResult> {
// Abort any pending conditional UI to prevent "request already pending" error
abortConditionalUI();
const cfg = { ...DEFAULT_CONFIG, ...config };
// Check WebAuthn support
@ -358,6 +379,12 @@ export async function startConditionalUI(
return null;
}
// Abort any existing conditional UI request
abortConditionalUI();
// Create new abort controller for this request
conditionalUIAbortController = new AbortController();
const cfg = { ...DEFAULT_CONFIG, ...config };
const challenge = generateChallenge();
const prfSalt = await generatePRFSalt('master-key');
@ -380,8 +407,12 @@ export async function startConditionalUI(
},
// @ts-ignore - conditional mediation
mediation: 'conditional',
signal: conditionalUIAbortController.signal,
}) as PublicKeyCredential;
// Clear abort controller on success
conditionalUIAbortController = null;
if (!credential) {
return null;
}