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:
parent
20a51e7dce
commit
8e10f5cb03
|
|
@ -16,6 +16,7 @@ export {
|
||||||
registerPasskey,
|
registerPasskey,
|
||||||
authenticatePasskey,
|
authenticatePasskey,
|
||||||
startConditionalUI,
|
startConditionalUI,
|
||||||
|
abortConditionalUI,
|
||||||
isConditionalMediationAvailable,
|
isConditionalMediationAvailable,
|
||||||
detectCapabilities,
|
detectCapabilities,
|
||||||
bufferToBase64url,
|
bufferToBase64url,
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,21 @@ const DEFAULT_CONFIG: EncryptIDConfig = {
|
||||||
timeout: 60000,
|
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
|
// UTILITY FUNCTIONS
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
@ -108,6 +123,9 @@ export async function registerPasskey(
|
||||||
displayName: string,
|
displayName: string,
|
||||||
config: Partial<EncryptIDConfig> = {}
|
config: Partial<EncryptIDConfig> = {}
|
||||||
): Promise<EncryptIDCredential> {
|
): Promise<EncryptIDCredential> {
|
||||||
|
// Abort any pending conditional UI to prevent "request already pending" error
|
||||||
|
abortConditionalUI();
|
||||||
|
|
||||||
const cfg = { ...DEFAULT_CONFIG, ...config };
|
const cfg = { ...DEFAULT_CONFIG, ...config };
|
||||||
|
|
||||||
// Check WebAuthn support
|
// Check WebAuthn support
|
||||||
|
|
@ -237,6 +255,9 @@ export async function authenticatePasskey(
|
||||||
credentialId?: string, // Optional: specify credential, or let user choose
|
credentialId?: string, // Optional: specify credential, or let user choose
|
||||||
config: Partial<EncryptIDConfig> = {}
|
config: Partial<EncryptIDConfig> = {}
|
||||||
): Promise<AuthenticationResult> {
|
): Promise<AuthenticationResult> {
|
||||||
|
// Abort any pending conditional UI to prevent "request already pending" error
|
||||||
|
abortConditionalUI();
|
||||||
|
|
||||||
const cfg = { ...DEFAULT_CONFIG, ...config };
|
const cfg = { ...DEFAULT_CONFIG, ...config };
|
||||||
|
|
||||||
// Check WebAuthn support
|
// Check WebAuthn support
|
||||||
|
|
@ -358,6 +379,12 @@ export async function startConditionalUI(
|
||||||
return null;
|
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 cfg = { ...DEFAULT_CONFIG, ...config };
|
||||||
const challenge = generateChallenge();
|
const challenge = generateChallenge();
|
||||||
const prfSalt = await generatePRFSalt('master-key');
|
const prfSalt = await generatePRFSalt('master-key');
|
||||||
|
|
@ -380,8 +407,12 @@ export async function startConditionalUI(
|
||||||
},
|
},
|
||||||
// @ts-ignore - conditional mediation
|
// @ts-ignore - conditional mediation
|
||||||
mediation: 'conditional',
|
mediation: 'conditional',
|
||||||
|
signal: conditionalUIAbortController.signal,
|
||||||
}) as PublicKeyCredential;
|
}) as PublicKeyCredential;
|
||||||
|
|
||||||
|
// Clear abort controller on success
|
||||||
|
conditionalUIAbortController = null;
|
||||||
|
|
||||||
if (!credential) {
|
if (!credential) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue