From 70ed3f5f1e34cce67f41f30200bdf28f8db7ffbe Mon Sep 17 00:00:00 2001 From: Amit Singh Date: Thu, 2 Apr 2026 12:47:20 +0530 Subject: [PATCH] feat: enhance abortPasskeyEnrollment method to accept doNotShowAgain option --- .../auth0-acul-js/interfaces/common/index.ts | 8 ++++++++ .../auth0-acul-js/interfaces/export/common.ts | 2 +- .../auth0-acul-js/interfaces/export/options.ts | 1 - .../screens/passkey-enrollment-local.ts | 7 +------ .../interfaces/screens/passkey-enrollment.ts | 4 ++-- .../screens/passkey-enrollment-local/index.ts | 5 ++--- .../src/screens/passkey-enrollment/index.ts | 16 +++++++++++----- .../passkey-enrollment-local/index.test.ts | 3 +-- .../screens/passkey-enrollment/index.test.ts | 18 +++++++++++++++++- .../src/screens/passkey-enrollment.tsx | 3 ++- 10 files changed, 45 insertions(+), 22 deletions(-) diff --git a/packages/auth0-acul-js/interfaces/common/index.ts b/packages/auth0-acul-js/interfaces/common/index.ts index ede617949..436e58266 100644 --- a/packages/auth0-acul-js/interfaces/common/index.ts +++ b/packages/auth0-acul-js/interfaces/common/index.ts @@ -3,6 +3,14 @@ export interface CustomOptions { [key: string]: string | number | boolean | undefined; } +/** + * Options for aborting passkey enrollment. + */ +export interface AbortEnrollmentOptions { + doNotShowAgain?: boolean; + [key: string]: string | number | boolean | undefined; +} + /** * Details of a WebAuthn browser error. */ diff --git a/packages/auth0-acul-js/interfaces/export/common.ts b/packages/auth0-acul-js/interfaces/export/common.ts index 3c66a752f..16615bccc 100644 --- a/packages/auth0-acul-js/interfaces/export/common.ts +++ b/packages/auth0-acul-js/interfaces/export/common.ts @@ -1,7 +1,7 @@ export type { CaptchaContext, PhonePrefix, PasskeyCreate, Scope, AuthorizationDetail, AllowCredential, AuthenticatorTransport } from '../models/screen'; export type { Connection, EnterpriseConnection, PasswordPolicy, PasswordComplexityPolicy, UsernamePolicy, Error, Error as ULError, PasswordComplexityRule } from '../models/transaction'; export type { BrandingSettings, BrandingThemes } from '../models/branding'; -export type { CustomOptions, WebAuthnErrorDetails, CurrentScreenOptions, FlattenedTheme, LanguageChangeOptions } from '../common/index'; +export type { CustomOptions, AbortEnrollmentOptions, WebAuthnErrorDetails, CurrentScreenOptions, FlattenedTheme, LanguageChangeOptions } from '../common/index'; export type { OnStatusChangeCallback, StartResendOptions, ResendControl } from '../utils/resend-control'; export type { EnrolledEmail, EnrolledPhoneNumber, EnrolledDevice } from '../models/user'; export type { IdentifierType } from '../../src/constants'; diff --git a/packages/auth0-acul-js/interfaces/export/options.ts b/packages/auth0-acul-js/interfaces/export/options.ts index 2e8d62214..ec889c7b6 100644 --- a/packages/auth0-acul-js/interfaces/export/options.ts +++ b/packages/auth0-acul-js/interfaces/export/options.ts @@ -3,7 +3,6 @@ export type { LoginPasswordOptions, FederatedLoginOptions as FederatedLoginPassw export type { SubmitCodeOptions, SwitchConnectionOptions as SwitchConnectionOptionsEmailCode } from '../screens/login-passwordless-email-code'; export type { SubmitOTPOptions, SwitchConnectionOptions as SwitchConnectionOptionsSmsOtp } from '../screens/login-passwordless-sms-otp'; export type { SubmitCaptchaOptions } from '../screens/interstitial-captcha'; -export type { AbortEnrollmentOptions } from '../screens/passkey-enrollment-local'; export type { EmailChallengeOptions } from '../screens/email-identifier-challenge'; export type { PhoneChallengeOptions } from '../screens/phone-identifier-challenge'; export type { PhoneEnrollmentOptions } from '../screens/phone-identifier-enrollment'; diff --git a/packages/auth0-acul-js/interfaces/screens/passkey-enrollment-local.ts b/packages/auth0-acul-js/interfaces/screens/passkey-enrollment-local.ts index a646e950e..b33940bf5 100644 --- a/packages/auth0-acul-js/interfaces/screens/passkey-enrollment-local.ts +++ b/packages/auth0-acul-js/interfaces/screens/passkey-enrollment-local.ts @@ -1,4 +1,4 @@ -import type { CustomOptions } from '../common'; +import type { CustomOptions, AbortEnrollmentOptions } from '../common'; import type { BaseContext, BaseMembers } from '../models/base-context'; import type { ScreenContext, PasskeyCreate, ScreenMembers } from '../models/screen'; @@ -16,11 +16,6 @@ export interface PasskeyEnrollmentLocal extends BaseContext { screen: ExtendedScreenContext; } -export interface AbortEnrollmentOptions { - doNotShowAgain?: boolean; - [key: string]: string | number | boolean | undefined; -} - export interface ScreenMembersOnPasskeyEnrollmentLocal extends ScreenMembers { publicKey: PasskeyCreate['public_key'] | null; } diff --git a/packages/auth0-acul-js/interfaces/screens/passkey-enrollment.ts b/packages/auth0-acul-js/interfaces/screens/passkey-enrollment.ts index 53f345210..8e2d5cfd4 100644 --- a/packages/auth0-acul-js/interfaces/screens/passkey-enrollment.ts +++ b/packages/auth0-acul-js/interfaces/screens/passkey-enrollment.ts @@ -1,4 +1,4 @@ -import type { CustomOptions } from '../common'; +import type { CustomOptions, AbortEnrollmentOptions } from '../common'; import type { BaseContext, BaseMembers } from '../models/base-context'; import type { ScreenContext, PasskeyCreate, ScreenMembers } from '../models/screen'; @@ -25,5 +25,5 @@ export interface ScreenMembersOnPasskeyEnrollment extends ScreenMembers { export interface PasskeyEnrollmentMembers extends BaseMembers { screen: ScreenMembersOnPasskeyEnrollment; continuePasskeyEnrollment(payload?: CustomOptions): Promise; - abortPasskeyEnrollment(payload?: CustomOptions): Promise; + abortPasskeyEnrollment(payload?: AbortEnrollmentOptions): Promise; } diff --git a/packages/auth0-acul-js/src/screens/passkey-enrollment-local/index.ts b/packages/auth0-acul-js/src/screens/passkey-enrollment-local/index.ts index 878a95c28..573d06c33 100644 --- a/packages/auth0-acul-js/src/screens/passkey-enrollment-local/index.ts +++ b/packages/auth0-acul-js/src/screens/passkey-enrollment-local/index.ts @@ -5,12 +5,11 @@ import { createPasskeyCredentials } from '../../utils/passkeys'; import { ScreenOverride } from './screen-override'; -import type { CustomOptions } from '../../../interfaces/common'; +import type { CustomOptions, AbortEnrollmentOptions } from '../../../interfaces/common'; import type { ScreenContext } from '../../../interfaces/models/screen'; import type { PasskeyEnrollmentLocalMembers, ScreenMembersOnPasskeyEnrollmentLocal as ScreenOptions, - AbortEnrollmentOptions, } from '../../../interfaces/screens/passkey-enrollment-local'; import type { FormOptions } from '../../../interfaces/utils/form-handler'; @@ -61,7 +60,7 @@ export default class PasskeyEnrollmentLocal extends BaseContext implements Passk }; const userActions: { [key: string]: string } = {}; - if (payload['doNotShowAgain'] === true) { + if (payload && payload.doNotShowAgain === true) { userActions['dontShowAgain'] = 'on'; } await new FormHandler(options).submitData({ ...payload, action: FormActions.ABORT_PASSKEY_ENROLLMENT, ...userActions }); diff --git a/packages/auth0-acul-js/src/screens/passkey-enrollment/index.ts b/packages/auth0-acul-js/src/screens/passkey-enrollment/index.ts index 5755d3381..f26f39e9b 100644 --- a/packages/auth0-acul-js/src/screens/passkey-enrollment/index.ts +++ b/packages/auth0-acul-js/src/screens/passkey-enrollment/index.ts @@ -5,7 +5,7 @@ import { createPasskeyCredentials } from '../../utils/passkeys'; import { ScreenOverride } from './screen-override'; -import type { CustomOptions } from '../../../interfaces/common'; +import type { CustomOptions, AbortEnrollmentOptions } from '../../../interfaces/common'; import type { ScreenContext } from '../../../interfaces/models/screen'; import type { PasskeyEnrollmentMembers, ScreenMembersOnPasskeyEnrollment as ScreenOptions } from '../../../interfaces/screens/passkey-enrollment'; import type { FormOptions } from '../../../interfaces/utils/form-handler'; @@ -46,18 +46,24 @@ export default class PasskeyEnrollment extends BaseContext implements PasskeyEnr * import PasskeyEnrollment from '@auth0/auth0-acul-js/passkey-enrollment'; * * const passkeyEnrollment = new PasskeyEnrollment(); - * passkeyEnrollment.abortPasskeyEnrollment(); + * passkeyEnrollment.abortPasskeyEnrollment({ + * doNotShowAgain: + * }); */ - async abortPasskeyEnrollment(payload?: CustomOptions): Promise { + async abortPasskeyEnrollment(payload?: AbortEnrollmentOptions): Promise { const options: FormOptions = { state: this.transaction.state, telemetry: [PasskeyEnrollment.screenIdentifier, 'abortPasskeyEnrollment'], }; - await new FormHandler(options).submitData({ ...payload, action: FormActions.ABORT_PASSKEY_ENROLLMENT }); + const userActions: { [key: string]: string } = {}; + if (payload && payload.doNotShowAgain === true) { + userActions['dontShowAgain'] = 'on'; + } + await new FormHandler(options).submitData({ ...payload, action: FormActions.ABORT_PASSKEY_ENROLLMENT, ...userActions }); } } -export { PasskeyEnrollmentMembers, ScreenOptions as ScreenMembersOnPasskeyEnrollment }; +export { PasskeyEnrollmentMembers, AbortEnrollmentOptions, ScreenOptions as ScreenMembersOnPasskeyEnrollment }; export * from '../../../interfaces/export/common'; export * from '../../../interfaces/export/base-properties'; diff --git a/packages/auth0-acul-js/tests/unit/screens/passkey-enrollment-local/index.test.ts b/packages/auth0-acul-js/tests/unit/screens/passkey-enrollment-local/index.test.ts index 72b90f4a5..5de095244 100644 --- a/packages/auth0-acul-js/tests/unit/screens/passkey-enrollment-local/index.test.ts +++ b/packages/auth0-acul-js/tests/unit/screens/passkey-enrollment-local/index.test.ts @@ -6,8 +6,7 @@ import { FormHandler } from '../../../../src/utils/form-handler'; import { createPasskeyCredentials } from '../../../../src/utils/passkeys'; import { baseContextData } from '../../../data/test-data'; -import type { CustomOptions } from 'interfaces/common'; -import type { AbortEnrollmentOptions } from 'interfaces/screens/passkey-enrollment-local'; +import type { CustomOptions, AbortEnrollmentOptions } from 'interfaces/common'; jest.mock('../../../../src/utils/form-handler'); jest.mock('../../../../src/utils/passkeys'); diff --git a/packages/auth0-acul-js/tests/unit/screens/passkey-enrollment/index.test.ts b/packages/auth0-acul-js/tests/unit/screens/passkey-enrollment/index.test.ts index 54f8b6afd..41e86a07b 100644 --- a/packages/auth0-acul-js/tests/unit/screens/passkey-enrollment/index.test.ts +++ b/packages/auth0-acul-js/tests/unit/screens/passkey-enrollment/index.test.ts @@ -6,7 +6,7 @@ import { FormHandler } from '../../../../src/utils/form-handler'; import { createPasskeyCredentials } from '../../../../src/utils/passkeys'; import { baseContextData } from '../../../data/test-data'; -import type { CustomOptions } from 'interfaces/common'; +import type { CustomOptions, AbortEnrollmentOptions } from 'interfaces/common'; jest.mock('../../../../src/utils/form-handler'); jest.mock('../../../../src/utils/passkeys'); @@ -126,6 +126,22 @@ describe('PasskeyEnrollment', () => { ); }); + it('should handle abortPasskeyEnrollment with doNotShowAgain set to true', async () => { + const payload: AbortEnrollmentOptions = { + doNotShowAgain: true, + }; + await passkeyEnrollment.abortPasskeyEnrollment(payload); + + expect(mockFormHandler.submitData).toHaveBeenCalledTimes(1); + expect(mockFormHandler.submitData).toHaveBeenCalledWith( + expect.objectContaining({ + ...payload, + action: FormActions.ABORT_PASSKEY_ENROLLMENT, + dontShowAgain: 'on', + }) + ); + }); + it('should throw error when promise is rejected', async () => { mockFormHandler.submitData.mockRejectedValue(new Error('Mocked reject')); const payload: CustomOptions = { diff --git a/packages/auth0-acul-react/src/screens/passkey-enrollment.tsx b/packages/auth0-acul-react/src/screens/passkey-enrollment.tsx index a89c9f3b2..cc7fabb51 100644 --- a/packages/auth0-acul-react/src/screens/passkey-enrollment.tsx +++ b/packages/auth0-acul-react/src/screens/passkey-enrollment.tsx @@ -8,6 +8,7 @@ import { registerScreen } from '../state/instance-store'; import type { PasskeyEnrollmentMembers, CustomOptions, + AbortEnrollmentOptions, } from '@auth0/auth0-acul-js/passkey-enrollment'; // Register the singleton instance of PasskeyEnrollment @@ -33,7 +34,7 @@ export const { // Submit functions export const continuePasskeyEnrollment = (payload?: CustomOptions) => withError(instance.continuePasskeyEnrollment(payload)); -export const abortPasskeyEnrollment = (payload?: CustomOptions) => +export const abortPasskeyEnrollment = (payload?: AbortEnrollmentOptions) => withError(instance.abortPasskeyEnrollment(payload)); // Common hooks