@dloizides/auth-web 1.13.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,114 @@
1
1
  # Changelog
2
2
 
3
- ## 1.13.0 (2026-07-19)
3
+ ## 1.16.0
4
+
5
+ **New shared `AccountSettingsScreen` — one authenticated account surface for all
6
+ seven portals, plus a first-class in-app change-password form.**
7
+
8
+ Adds `AccountSettingsScreen`: a self-contained, theme-driven surface that stacks
9
+ the account-management cards each portal was otherwise wiring by hand. Sections
10
+ are config-driven — a card renders only when its config is passed:
11
+
12
+ - **Change password (always):** a new `ChangePasswordCard` — a real in-app form
13
+ (current / new / confirm) with client-side validation (new === confirm + the
14
+ shared password policy) that submits `POST /bff/account/change-password`
15
+ (204 → success; 400 → "current password incorrect or fails the policy";
16
+ 401 → session expired). The signed-in user changes their OWN password in the
17
+ app — no Keycloak-console detour. This package never stores, logs or inspects
18
+ the password values; it forwards them to the app's own BFF over the session
19
+ cookie and reads back only a status.
20
+ - **Device PIN (optional):** the existing `DevicePinSettingsCard`.
21
+ - **Passkeys (optional):** the existing `PasskeySettingsCard`.
22
+ - **Preferred sign-in method (optional):** the existing `PreferredMethodSettingsCard`.
23
+
24
+ New public API:
25
+
26
+ - `AccountSettingsScreen` + `AccountSettingsScreenProps` and the per-section
27
+ config types (`AccountSettingsChangePasswordConfig`, `AccountSettingsDevicePinConfig`,
28
+ `AccountSettingsPasskeysConfig`, `AccountSettingsPreferredMethodConfig`).
29
+ - `ChangePasswordCard` + `ChangePasswordCardProps`.
30
+ - `useChangePassword` (react-query-free form state + validation + submit),
31
+ `ChangePasswordErrorKey`, `ChangePasswordResult`.
32
+ - `createBffChangePasswordClient` (ready same-origin BFF client, CSRF marker
33
+ header attached) + `ChangePasswordCapableClient` / `ChangePasswordRequest` /
34
+ `CHANGE_PASSWORD_ENDPOINT` / `CreateBffChangePasswordClientOptions`.
35
+ - `AccountSettingsLabels` + `DEFAULT_ACCOUNT_SETTINGS_LABELS`.
36
+
37
+ Backend contract required by adopters: `POST /bff/account/change-password`,
38
+ body `{ currentPassword, newPassword }` → `204` on success, `400` on
39
+ wrong-current/policy-fail, `401` when unauthenticated.
40
+
41
+ ## 1.14.0 (2026-07-19)
42
+
43
+ Three defects found by measuring the DEPLOYED portals rather than reading the
44
+ source. All three had passing tests over them.
45
+
46
+ ### Fixed
47
+
48
+ - **The auth card no longer vertically centres, so expanding anything stops
49
+ moving the inputs.** Measured on `app.zygos.dloizides.com/login` at 1.13.0:
50
+ expanding the demo disclosure grew the card 445.6 → 589.6px and pulled the
51
+ username input from `y=275.2` to `y=203.2` and the password from `y=368.8` to
52
+ `y=296.8` — **72px UP each**, mid-interaction. `<DemoCredentialsHint>` was
53
+ deliberately mounted BELOW the form to avoid exactly this; centring defeated
54
+ the placement, because a centred card re-centres as it grows and drags
55
+ everything above the growth upward.
56
+
57
+ `useAuthScreenStyles.screen` and `useAuthStyles.screen` are now top-anchored
58
+ (`justifyContent: 'flex-start'` + a 64dp `paddingTop`) instead of centred.
59
+ ⚠️ **This is a visible change on every portal**: the login card now sits below
60
+ a fixed gap rather than floating in the middle of tall viewports.
61
+
62
+ Chosen over the alternatives because the defect is not specific to the
63
+ disclosure — ANY growth shifted the fields (a validation error under an input,
64
+ a passkey button arriving after the config fetch, an OTP tab swap), and only
65
+ top-anchoring fixes the whole class. Reserving the disclosure's height would
66
+ have left ~144px of permanent dead space on every login; absolutely
67
+ positioning the expanded panel would have removed it from the scrollable area,
68
+ making the credentials unreachable on a short viewport. Top-anchoring is also
69
+ strictly safer at small viewports than what it replaces: overflow now runs
70
+ downward only, where centring pushed the top of the card past the top edge
71
+ where no scroll could reach it.
72
+
73
+ - **Selection and expansion states are now announced on the web.** Three
74
+ components declared `accessibilityState` and announced nothing:
75
+ `<DemoCredentialsHint>` (`expanded`), `<DevicePinLengthPicker>` (`selected`)
76
+ and `<PreferredMethodSettingsCard>` (`selected`). Each now passes the ARIA
77
+ attribute **explicitly** (`aria-expanded` / `aria-checked`) alongside the RN
78
+ prop, which is kept for native.
79
+
80
+ Root cause is systemic, not a typo. Measured against react-native-web 0.21.2:
81
+ a `<TouchableOpacity>` given `accessibilityLabel`, `accessibilityRole`,
82
+ `accessibilityHint` and `accessibilityState={{ expanded: true, selected: true }}`
83
+ renders `<button role="button" aria-label="…">` — **no `aria-expanded`, no
84
+ `aria-selected`, and no trace of the hint at all**. `accessibilityState` is not
85
+ read by react-native-web; `accessibilityHint` produces zero DOM output.
86
+
87
+ For `<DevicePinLengthPicker>` the practical effect was WCAG 1.4.1: the chosen
88
+ PIN length was distinguishable only by the pill's fill colour. Its options also
89
+ move from `accessibilityRole="button"` to `"radio"` inside a `radiogroup`,
90
+ since `aria-checked` is only meaningful on a checkable role.
91
+
92
+ - **Field labels now speak the shared contract's `field` voice — 13/600, not
93
+ 14/600.** The forms contract (mirrored in `@dloizides/ui-forms`'
94
+ `labelVariants.ts`) defines exactly two label voices: `field` (13/600, sentence
95
+ case) and `control` (11/700, uppercase). `defaultAuthTheme.typography.label`
96
+ was 14, which is neither — drift, inherited uniformly by every portal, since
97
+ they all reuse `defaultAuthTheme.typography` verbatim. It read against the 13px
98
+ `Field` labels those same apps use on every non-auth form.
99
+
100
+ ### Tests
101
+
102
+ - **New DOM-level guards** (`*.dom.test.tsx`), rendered through the real
103
+ `react-native-web` in a `jsdom` environment, asserting the rendered
104
+ **attribute** rather than the React prop. This is the point: the pre-existing
105
+ suite mocked `react-native` down to host strings and asserted
106
+ `props.accessibilityState` — so it passed, unchanged, against a button that
107
+ announced nothing in every browser. A prop assertion cannot catch this class of
108
+ bug, and did not.
109
+ - `authVisualContract.test.ts` guards the two visual contracts by naming the
110
+ defect they forbid (`justifyContent` must NOT be `'center'`; labels must be
111
+ 13/600 written as a literal, not read back from the token under test).
4
112
 
5
113
  `<DemoCredentialsHint>` gets a **discreet** presentation, and it is now the
6
114
  default. The demo stops competing with the sign-in form on login pages that real
package/dist/index.d.mts CHANGED
@@ -62,7 +62,21 @@ interface AuthThemeTypography {
62
62
  title: number;
63
63
  /** Form subtitle. */
64
64
  subtitle: number;
65
- /** Field labels. */
65
+ /**
66
+ * Field labels.
67
+ *
68
+ * The shared forms contract ("The TWO legitimate label voices", mirrored in
69
+ * `@dloizides/ui-forms`' `labelVariants.ts`) defines exactly two: `field` —
70
+ * 13 / 600 / sentence case, a label that is READ — and `control` — 11 / 700 /
71
+ * uppercase, a label that is SCANNED. Auth field labels are prose addressed to
72
+ * the person signing in, so they are the `field` voice: **13**.
73
+ *
74
+ * Through 1.13.0 this default was 14, which is neither voice — drift. Every
75
+ * portal that renders `<LoginForm>` inherits this token (all of them reuse
76
+ * `defaultAuthTheme.typography` verbatim), so the drift was uniform across
77
+ * zygos, agora, erevna, katalogos and ichnos, and it read against the 13px
78
+ * `Field` labels those same apps use on every non-auth form.
79
+ */
66
80
  label: number;
67
81
  /** Input text and button text. */
68
82
  body: number;
@@ -449,6 +463,50 @@ interface ResetPasswordFormLabels {
449
463
  }
450
464
  declare const DEFAULT_RESET_PASSWORD_LABELS: ResetPasswordFormLabels;
451
465
 
466
+ /**
467
+ * Strings rendered by `<AccountSettingsScreen>` and its `ChangePasswordCard`.
468
+ *
469
+ * As with every auth label bag, the consuming app supplies already-localised
470
+ * strings; the `DEFAULT_*` English constant lets the screen render with no
471
+ * `labels` prop and lets an app spread-override only the keys it cares about.
472
+ */
473
+ /** Strings for the account-settings screen shell + the in-app change-password form. */
474
+ interface AccountSettingsLabels {
475
+ /** The screen heading above the stacked settings cards. */
476
+ heading: string;
477
+ /** Card title. */
478
+ changePasswordTitle: string;
479
+ /** Card body copy above the fields. */
480
+ changePasswordDescription: string;
481
+ currentPasswordLabel: string;
482
+ currentPasswordPlaceholder: string;
483
+ newPasswordLabel: string;
484
+ newPasswordPlaceholder: string;
485
+ confirmPasswordLabel: string;
486
+ confirmPasswordPlaceholder: string;
487
+ /** Submit button. */
488
+ submit: string;
489
+ /** Shown while the submit is in flight. */
490
+ submitting: string;
491
+ /** Accessibility hint for the submit button. */
492
+ submitHint: string;
493
+ /** Shown after a successful change. */
494
+ success: string;
495
+ /** New password fails the shared policy. */
496
+ errorWeakNewPassword: string;
497
+ /** New password and confirmation do not match. */
498
+ errorMismatch: string;
499
+ /** Current password field left blank. */
500
+ errorCurrentRequired: string;
501
+ /** BFF 400 — current password wrong or new one rejected server-side. */
502
+ errorInvalidCurrent: string;
503
+ /** BFF 401 — session not authenticated. */
504
+ errorUnauthorized: string;
505
+ /** Any other failure. */
506
+ errorFailed: string;
507
+ }
508
+ declare const DEFAULT_ACCOUNT_SETTINGS_LABELS: AccountSettingsLabels;
509
+
452
510
  /**
453
511
  * Who asked for a prefill — the difference between "the user requested this" and
454
512
  * "the app offered it".
@@ -1267,6 +1325,175 @@ interface PreferredMethodSettingsCardProps {
1267
1325
  /** Themeable authenticated preferred-method picker. */
1268
1326
  declare function PreferredMethodSettingsCard({ client, availableMethods, theme: themeProp, labels: labelsProp, testIdPrefix, onChanged, }: Readonly<PreferredMethodSettingsCardProps>): ReactElement;
1269
1327
 
1328
+ /**
1329
+ * Discriminated result of an authenticated change-password attempt.
1330
+ *
1331
+ * Mirrors the device-PIN result shapes: the client never rejects for an expected
1332
+ * outcome — it resolves one of these so the form routes on the distinct causes
1333
+ * (a wrong current password / policy rejection vs. an expired session vs. an
1334
+ * unexpected error) rather than collapsing them into one opaque failure.
1335
+ */
1336
+ type ChangePasswordResult = {
1337
+ status: 'success';
1338
+ }
1339
+ /** BFF 400 — current password incorrect, or the new password failed the server policy. */
1340
+ | {
1341
+ status: 'invalidCurrent';
1342
+ }
1343
+ /** BFF 401 — the session is not / no longer authenticated. */
1344
+ | {
1345
+ status: 'unauthorized';
1346
+ }
1347
+ /** Any other status / transport failure. */
1348
+ | {
1349
+ status: 'error';
1350
+ };
1351
+
1352
+ /**
1353
+ * The client capability the authenticated change-password form depends on, plus
1354
+ * a ready-made same-origin BFF implementation.
1355
+ *
1356
+ * As with the device-PIN surfaces, the UI depends on a **structural** shape
1357
+ * ({@link ChangePasswordCapableClient}) — exactly one method — so a consuming app
1358
+ * may pass the ready-made client below or a thin hand-rolled object. The ready
1359
+ * client POSTs to the same-origin BFF and maps the response to a
1360
+ * {@link ChangePasswordResult}; it never rejects for an expected outcome.
1361
+ *
1362
+ * SECURITY: the password values live only in the request the end user's OWN
1363
+ * browser sends to their OWN app's BFF over the session cookie. This package
1364
+ * neither stores, logs, nor inspects them — it forwards `currentPassword` /
1365
+ * `newPassword` to the BFF and reads back only a status code.
1366
+ */
1367
+
1368
+ /** The request body posted to `POST /bff/account/change-password`. */
1369
+ interface ChangePasswordRequest {
1370
+ currentPassword: string;
1371
+ newPassword: string;
1372
+ }
1373
+ /** The single-method capability the change-password form needs. */
1374
+ interface ChangePasswordCapableClient {
1375
+ /** Change the signed-in user's password. Resolves a result; never rejects on an expected outcome. */
1376
+ changePassword(request: ChangePasswordRequest): Promise<ChangePasswordResult>;
1377
+ }
1378
+ /** Options for {@link createBffChangePasswordClient}. */
1379
+ interface CreateBffChangePasswordClientOptions {
1380
+ /**
1381
+ * BFF origin. Omit (the production default) for same-origin — the SPA's own
1382
+ * host is the BFF. An explicit origin is useful only for a non-same-origin BFF
1383
+ * or for tests.
1384
+ */
1385
+ baseUrl?: string;
1386
+ /**
1387
+ * Override the HTTP transport. Defaults to a lazily-resolved native `fetch`
1388
+ * (module load stays side-effect-free, so a `fetch`-less test runtime does not
1389
+ * blow up on import). Tests pass a fake `HttpClient`.
1390
+ */
1391
+ http?: HttpClient;
1392
+ }
1393
+ /** The BFF endpoint the ready client posts to. */
1394
+ declare const CHANGE_PASSWORD_ENDPOINT = "/bff/account/change-password";
1395
+ /**
1396
+ * Build a same-origin change-password client. With no arguments this is the exact
1397
+ * production wiring: same-origin, lazy `fetch`, session-cookie auth, the BFF CSRF
1398
+ * marker header attached. A thrown transport error resolves to `{ status: 'error' }`
1399
+ * so the caller never has to catch.
1400
+ */
1401
+ declare function createBffChangePasswordClient(options?: CreateBffChangePasswordClientOptions): ChangePasswordCapableClient;
1402
+
1403
+ /**
1404
+ * AccountSettingsScreen — the shared, composable authenticated account surface
1405
+ * every dloizides portal can mount to give a signed-in user one place to manage
1406
+ * their account. Self-contained and theme-driven: it stacks a set of independent,
1407
+ * individually-themed cards, each rendered only when its config is supplied.
1408
+ *
1409
+ * - **Change password** (always) — the in-app `<ChangePasswordCard>` form
1410
+ * (`POST /bff/account/change-password`). No password value is handled by this
1411
+ * package beyond forwarding it to the app's own BFF.
1412
+ * - **Device PIN** (optional) — the existing `<DevicePinSettingsCard>`, so every
1413
+ * portal gets quick-PIN enable/disable for free.
1414
+ * - **Passkeys** (optional) — the existing `<PasskeySettingsCard>`.
1415
+ * - **Preferred sign-in method** (optional) — the existing
1416
+ * `<PreferredMethodSettingsCard>`.
1417
+ *
1418
+ * Purely presentational assembly: each card owns its own behaviour + hooks (all
1419
+ * react-query-free). The screen only threads the shared `theme` / `testIdPrefix`
1420
+ * down and lays the cards out in a scrollable, centered column.
1421
+ */
1422
+
1423
+ /** Device-PIN section config — mirrors `DevicePinSettingsCard` (theme/testIdPrefix threaded by the screen). */
1424
+ interface AccountSettingsDevicePinConfig {
1425
+ client: DevicePinEnrollCapableClient & DevicePinDisableCapableClient;
1426
+ initialHasPin: boolean;
1427
+ labels?: Partial<DevicePinSettingsLabels>;
1428
+ enrollLabels?: Partial<DevicePinEnrollLabels>;
1429
+ onChanged?: (hasPin: boolean) => void;
1430
+ }
1431
+ /** Passkeys section config — mirrors `PasskeySettingsCard`. */
1432
+ interface AccountSettingsPasskeysConfig {
1433
+ returnUrl?: string;
1434
+ labels?: Partial<PasskeySettingsLabels>;
1435
+ }
1436
+ /** Preferred-method section config — mirrors `PreferredMethodSettingsCard`. */
1437
+ interface AccountSettingsPreferredMethodConfig {
1438
+ client: PreferredMethodClient;
1439
+ availableMethods: readonly string[];
1440
+ labels?: Partial<PreferredMethodSettingsLabels>;
1441
+ onChanged?: (method: string | null) => void;
1442
+ }
1443
+ /** Change-password section config. */
1444
+ interface AccountSettingsChangePasswordConfig {
1445
+ client: ChangePasswordCapableClient;
1446
+ onChanged?: () => void;
1447
+ }
1448
+ interface AccountSettingsScreenProps {
1449
+ /** Change-password form config (always rendered). */
1450
+ changePassword: AccountSettingsChangePasswordConfig;
1451
+ /** Device-PIN card config. Omit to hide the section. */
1452
+ devicePin?: AccountSettingsDevicePinConfig;
1453
+ /** Passkeys card config. Omit to hide the section. */
1454
+ passkeys?: AccountSettingsPasskeysConfig;
1455
+ /** Preferred-method card config. Omit to hide the section. */
1456
+ preferredMethod?: AccountSettingsPreferredMethodConfig;
1457
+ /** Explicit theme; overrides any `<AuthThemeProvider>`. Threaded to every card. */
1458
+ theme?: AuthTheme;
1459
+ /** Screen + change-password copy (partial; unspecified keys fall back to English). */
1460
+ labels?: Partial<AccountSettingsLabels>;
1461
+ /** Prefix applied to every `testID`, on the screen and every card. */
1462
+ testIdPrefix?: string;
1463
+ }
1464
+ /** The shared authenticated account-management surface. */
1465
+ declare function AccountSettingsScreen({ changePassword, devicePin, passkeys, preferredMethod, theme: themeProp, labels: labelsProp, testIdPrefix, }: Readonly<AccountSettingsScreenProps>): ReactElement;
1466
+
1467
+ /**
1468
+ * ChangePasswordCard — an authenticated, in-app "Change password" form.
1469
+ *
1470
+ * The signed-in user types their OWN current + new password in their OWN app;
1471
+ * that is a legitimate first-class feature (no Keycloak-console detour). The card
1472
+ * is purely presentational: all state, validation and submission live in
1473
+ * {@link useChangePassword}, which posts to `POST /bff/account/change-password`
1474
+ * through a {@link ChangePasswordCapableClient}. This package never stores, logs
1475
+ * or inspects the password values — it forwards them to the app's own BFF over
1476
+ * the session cookie and reads back only a status.
1477
+ *
1478
+ * Theme-driven and react-query-free, mirroring `DevicePinSettingsCard` /
1479
+ * `ResetPasswordForm`.
1480
+ */
1481
+
1482
+ interface ChangePasswordCardProps {
1483
+ /** The client exposing `changePassword` (see `createBffChangePasswordClient`). */
1484
+ client: ChangePasswordCapableClient;
1485
+ /** Explicit theme; overrides any `<AuthThemeProvider>`. */
1486
+ theme?: AuthTheme;
1487
+ /** Localised copy. Partial — unspecified keys fall back to English defaults. */
1488
+ labels?: Partial<AccountSettingsLabels>;
1489
+ /** Prefix applied to every `testID`. */
1490
+ testIdPrefix?: string;
1491
+ /** Called once after a successful password change. */
1492
+ onChanged?: () => void;
1493
+ }
1494
+ /** Themeable authenticated change-password form. */
1495
+ declare function ChangePasswordCard({ client, theme: themeProp, labels: labelsProp, testIdPrefix, onChanged, }: Readonly<ChangePasswordCardProps>): ReactElement;
1496
+
1270
1497
  /**
1271
1498
  * The login-screen "you usually sign in with…" hint (unified-login D5).
1272
1499
  *
@@ -1359,9 +1586,15 @@ declare const enum DemoCredentialsHintVariant {
1359
1586
  * the same AA-held token as every other piece of helper copy. Discretion is
1360
1587
  * carried by size, placement and the absence of chrome.
1361
1588
  * - **It does not hide from assistive tech.** The trigger is a real focusable
1362
- * button carrying `accessibilityState.expanded`, so a screen reader
1363
- * announces both that it exists and whether it is open. Visually quiet must
1364
- * not mean absent — a demo nobody can find is a demo nobody uses.
1589
+ * button carrying an explicit `aria-expanded` (plus `accessibilityState` for
1590
+ * native), so a screen reader announces both that it exists and whether it is
1591
+ * open. Visually quiet must not mean absent — a demo nobody can find is a demo
1592
+ * nobody uses.
1593
+ *
1594
+ * ⚠️ Through 1.13.0 this carried ONLY `accessibilityState={{ expanded }}` and
1595
+ * therefore announced nothing on web: react-native-web 0.21.2 does not read
1596
+ * `accessibilityState`, so the rendered button had no `aria-expanded` at all.
1597
+ * The old unit test asserted the React *prop*, so it passed against the bug.
1365
1598
  *
1366
1599
  * ## Layout stability
1367
1600
  *
@@ -1505,6 +1738,14 @@ declare const AuthTestIds: {
1505
1738
  readonly preferredMethodSettingsOption: "auth-preferred-method-settings-option";
1506
1739
  readonly preferredMethodSettingsError: "auth-preferred-method-settings-error";
1507
1740
  readonly preferredMethodHint: "auth-preferred-method-hint";
1741
+ readonly accountSettings: "auth-account-settings";
1742
+ readonly accountSettingsChangePassword: "auth-account-settings-change-password";
1743
+ readonly changePasswordCurrentInput: "auth-change-password-current";
1744
+ readonly changePasswordNewInput: "auth-change-password-new";
1745
+ readonly changePasswordConfirmInput: "auth-change-password-confirm";
1746
+ readonly changePasswordSubmit: "auth-change-password-submit";
1747
+ readonly changePasswordError: "auth-change-password-error";
1748
+ readonly changePasswordSuccess: "auth-change-password-success";
1508
1749
  readonly demoCredentialsHint: "auth-demo-credentials-hint";
1509
1750
  readonly demoCredentialsUsername: "auth-demo-credentials-username";
1510
1751
  readonly demoCredentialsPassword: "auth-demo-credentials-password";
@@ -2327,4 +2568,50 @@ declare function validatePasswordPolicy(password: string): PasswordPolicyError[]
2327
2568
  /** `true` when the password satisfies every policy rule. */
2328
2569
  declare function isPasswordValid(password: string): boolean;
2329
2570
 
2330
- export { AuthScreen, type AuthScreenProps, AuthTestIds, type AuthTheme, type AuthThemeColors, AuthThemeProvider, type AuthThemeProviderProps, type AuthThemeRadii, type AuthThemeSpacing, type AuthThemeTypography, BffAuthStatus, type BffDeviceState, type BffLoginConfig, type BffLogoutClient, type CreateBffAuthClientOptions, DEFAULT_AUTH_CARD_MAX_WIDTH, DEFAULT_DEMO_CREDENTIALS_HINT_LABELS, DEFAULT_DEVICE_PIN_ENROLL_LABELS, DEFAULT_DEVICE_PIN_SETTINGS_LABELS, DEFAULT_DEVICE_PIN_UNLOCK_LABELS, DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PASSKEY_LOGIN_LABELS, DEFAULT_PASSKEY_SETTINGS_LABELS, DEFAULT_PIN_LABELS, DEFAULT_PREFERRED_METHOD_HINT_LABELS, DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, DEFAULT_RESET_PASSWORD_LABELS, DEVICE_PIN_ALLOWED_DIGITS, DEVICE_PIN_DEFAULT_DIGITS, DemoCredentialsHint, type DemoCredentialsHintLabels, type DemoCredentialsHintProps, DemoCredentialsHintVariant, type DemoCredentialsHintWiring, type DemoCredentialsLoginFormProps, type DevicePinCapableClient, type DevicePinDisableCapableClient, type DevicePinEnrollCapableClient, DevicePinEnrollErrorKey, DevicePinEnrollForm, type DevicePinEnrollFormProps, type DevicePinEnrollLabels, type DevicePinEnrollResult, DevicePinErrorKey, DevicePinInput, type DevicePinInputProps, DevicePinLengthPicker, type DevicePinLengthPickerProps, DevicePinOffer, type DevicePinOfferProps, DevicePinSettingsCard, type DevicePinSettingsCardProps, type DevicePinSettingsLabels, type DevicePinUnlockCapableClient, type DevicePinUnlockLabels, type DevicePinUnlockResult, DevicePinUnlockScreen, type DevicePinUnlockScreenProps, type DevicePinUnlockedUser, ForgotPasswordFields, type ForgotPasswordFieldsLabels, type ForgotPasswordFieldsProps, ForgotPasswordForm, type ForgotPasswordFormLabels, type ForgotPasswordFormProps, type LoginConfigCapableClient, LoginForm, type LoginFormLabels, type LoginFormProps, OtpForm, type OtpFormLabels, type OtpFormProps, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyCeremonyMode, PasskeyCeremonyStatus, type PasskeyErrorCode, PasskeyLoginButton, type PasskeyLoginButtonProps, type PasskeyLoginLabels, PasskeySettingsCard, type PasskeySettingsCardProps, type PasskeySettingsLabels, PasswordPolicyError, type PerformBffLogoutOptions, PinForm, type PinFormLabels, type PinFormProps, type PreferencesClientOptions, type PreferredMethodClient, PreferredMethodHint, type PreferredMethodHintLabels, type PreferredMethodHintProps, PreferredMethodSettingsCard, type PreferredMethodSettingsCardProps, type PreferredMethodSettingsLabels, PrefillIntent, ResetPasswordError, ResetPasswordForm, type ResetPasswordFormLabels, type ResetPasswordFormProps, type RoleRoute, type RoleRouteTable, type UseBffAuthOptions, type UseBffAuthResult, type UseBffForgotPasswordOptions, type UseBffLoginConfigResult, type UseBffResetPasswordOptions, type UseDemoCredentialsOptions, type UseDemoCredentialsResult, type UseDevicePinDisableArgs, type UseDevicePinDisableResult, type UseDevicePinEnrollArgs, type UseDevicePinEnrollResult, type UseDevicePinUnlockArgs, type UseDevicePinUnlockResult, type UseForgotPasswordSubmitArgs, type UseForgotPasswordSubmitResult, type UseOtpLoginOptions, type UseOtpLoginResult, type UsePasskeyCeremonyOptions, type UsePasskeyCeremonyResult, type UsePinLoginOptions, type UsePinLoginResult, type UsePreferredMethodSettingArgs, type UsePreferredMethodSettingResult, type UseResetPasswordFormArgs, type UseResetPasswordFormResult, cachePreferredMethod, clearCachedPreferredMethod, collectUserRoles, createBffAuthClient, createPreferencesClient, defaultAuthTheme, isAllowedPinDigits, isPasswordValid, isValidForgotPasswordEmail, performBffLogout, readCachedPreferredMethod, readPasskeyError, readPasskeyRegistered, resolveAccessibleRoutes, resolveDemoCredentials, resolvePostLoginRoute, startPasskeyLogin, startPasskeyRegistration, syncPreferredMethodFromServer, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useDemoCredentials, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePasskeyCeremony, usePinLogin, usePreferredMethodSetting, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
2571
+ /**
2572
+ * The localizable failure states the authenticated "Change password" form can
2573
+ * show. Client-side validation states never hit the network; the rest map from
2574
+ * the BFF's `POST /bff/account/change-password` response.
2575
+ */
2576
+ declare const enum ChangePasswordErrorKey {
2577
+ /** New password is empty / fails the shared password policy (no network call). */
2578
+ WeakNewPassword = "weak_new_password",
2579
+ /** New password and its confirmation do not match (no network call). */
2580
+ Mismatch = "mismatch",
2581
+ /** Current password field was left blank (no network call). */
2582
+ CurrentRequired = "current_required",
2583
+ /** BFF 400 — the current password is wrong, or the new one was rejected server-side. */
2584
+ InvalidCurrent = "invalid_current",
2585
+ /** BFF 401 — the session is not (or no longer) authenticated. */
2586
+ Unauthorized = "unauthorized",
2587
+ /** Any other failure (network / unexpected). */
2588
+ Failed = "failed"
2589
+ }
2590
+
2591
+ interface UseChangePasswordArgs {
2592
+ /** The client exposing `changePassword`. */
2593
+ client: ChangePasswordCapableClient;
2594
+ /** Called once after a successful change (the form has been cleared by then). */
2595
+ onChanged?: () => void;
2596
+ }
2597
+ interface UseChangePasswordResult {
2598
+ currentPassword: string;
2599
+ newPassword: string;
2600
+ confirmPassword: string;
2601
+ setCurrentPassword: (value: string) => void;
2602
+ setNewPassword: (value: string) => void;
2603
+ setConfirmPassword: (value: string) => void;
2604
+ /** `true` while a BFF submit is in flight. */
2605
+ submitting: boolean;
2606
+ /** `true` after a successful change (until `reset` / a field edit). */
2607
+ succeeded: boolean;
2608
+ /** The current failure cause, or `null` when there is none. */
2609
+ errorKey: ChangePasswordErrorKey | null;
2610
+ /** Validate then submit. A validation failure sets `errorKey` and skips the network call. */
2611
+ submit: () => void;
2612
+ /** Clear every field + status back to a blank form. */
2613
+ reset: () => void;
2614
+ }
2615
+ declare function useChangePassword({ client, onChanged, }: UseChangePasswordArgs): UseChangePasswordResult;
2616
+
2617
+ export { type AccountSettingsChangePasswordConfig, type AccountSettingsDevicePinConfig, type AccountSettingsLabels, type AccountSettingsPasskeysConfig, type AccountSettingsPreferredMethodConfig, AccountSettingsScreen, type AccountSettingsScreenProps, AuthScreen, type AuthScreenProps, AuthTestIds, type AuthTheme, type AuthThemeColors, AuthThemeProvider, type AuthThemeProviderProps, type AuthThemeRadii, type AuthThemeSpacing, type AuthThemeTypography, BffAuthStatus, type BffDeviceState, type BffLoginConfig, type BffLogoutClient, CHANGE_PASSWORD_ENDPOINT, type ChangePasswordCapableClient, ChangePasswordCard, type ChangePasswordCardProps, ChangePasswordErrorKey, type ChangePasswordRequest, type ChangePasswordResult, type CreateBffAuthClientOptions, type CreateBffChangePasswordClientOptions, DEFAULT_ACCOUNT_SETTINGS_LABELS, DEFAULT_AUTH_CARD_MAX_WIDTH, DEFAULT_DEMO_CREDENTIALS_HINT_LABELS, DEFAULT_DEVICE_PIN_ENROLL_LABELS, DEFAULT_DEVICE_PIN_SETTINGS_LABELS, DEFAULT_DEVICE_PIN_UNLOCK_LABELS, DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PASSKEY_LOGIN_LABELS, DEFAULT_PASSKEY_SETTINGS_LABELS, DEFAULT_PIN_LABELS, DEFAULT_PREFERRED_METHOD_HINT_LABELS, DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, DEFAULT_RESET_PASSWORD_LABELS, DEVICE_PIN_ALLOWED_DIGITS, DEVICE_PIN_DEFAULT_DIGITS, DemoCredentialsHint, type DemoCredentialsHintLabels, type DemoCredentialsHintProps, DemoCredentialsHintVariant, type DemoCredentialsHintWiring, type DemoCredentialsLoginFormProps, type DevicePinCapableClient, type DevicePinDisableCapableClient, type DevicePinEnrollCapableClient, DevicePinEnrollErrorKey, DevicePinEnrollForm, type DevicePinEnrollFormProps, type DevicePinEnrollLabels, type DevicePinEnrollResult, DevicePinErrorKey, DevicePinInput, type DevicePinInputProps, DevicePinLengthPicker, type DevicePinLengthPickerProps, DevicePinOffer, type DevicePinOfferProps, DevicePinSettingsCard, type DevicePinSettingsCardProps, type DevicePinSettingsLabels, type DevicePinUnlockCapableClient, type DevicePinUnlockLabels, type DevicePinUnlockResult, DevicePinUnlockScreen, type DevicePinUnlockScreenProps, type DevicePinUnlockedUser, ForgotPasswordFields, type ForgotPasswordFieldsLabels, type ForgotPasswordFieldsProps, ForgotPasswordForm, type ForgotPasswordFormLabels, type ForgotPasswordFormProps, type LoginConfigCapableClient, LoginForm, type LoginFormLabels, type LoginFormProps, OtpForm, type OtpFormLabels, type OtpFormProps, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyCeremonyMode, PasskeyCeremonyStatus, type PasskeyErrorCode, PasskeyLoginButton, type PasskeyLoginButtonProps, type PasskeyLoginLabels, PasskeySettingsCard, type PasskeySettingsCardProps, type PasskeySettingsLabels, PasswordPolicyError, type PerformBffLogoutOptions, PinForm, type PinFormLabels, type PinFormProps, type PreferencesClientOptions, type PreferredMethodClient, PreferredMethodHint, type PreferredMethodHintLabels, type PreferredMethodHintProps, PreferredMethodSettingsCard, type PreferredMethodSettingsCardProps, type PreferredMethodSettingsLabels, PrefillIntent, ResetPasswordError, ResetPasswordForm, type ResetPasswordFormLabels, type ResetPasswordFormProps, type RoleRoute, type RoleRouteTable, type UseBffAuthOptions, type UseBffAuthResult, type UseBffForgotPasswordOptions, type UseBffLoginConfigResult, type UseBffResetPasswordOptions, type UseChangePasswordArgs, type UseChangePasswordResult, type UseDemoCredentialsOptions, type UseDemoCredentialsResult, type UseDevicePinDisableArgs, type UseDevicePinDisableResult, type UseDevicePinEnrollArgs, type UseDevicePinEnrollResult, type UseDevicePinUnlockArgs, type UseDevicePinUnlockResult, type UseForgotPasswordSubmitArgs, type UseForgotPasswordSubmitResult, type UseOtpLoginOptions, type UseOtpLoginResult, type UsePasskeyCeremonyOptions, type UsePasskeyCeremonyResult, type UsePinLoginOptions, type UsePinLoginResult, type UsePreferredMethodSettingArgs, type UsePreferredMethodSettingResult, type UseResetPasswordFormArgs, type UseResetPasswordFormResult, cachePreferredMethod, clearCachedPreferredMethod, collectUserRoles, createBffAuthClient, createBffChangePasswordClient, createPreferencesClient, defaultAuthTheme, isAllowedPinDigits, isPasswordValid, isValidForgotPasswordEmail, performBffLogout, readCachedPreferredMethod, readPasskeyError, readPasskeyRegistered, resolveAccessibleRoutes, resolveDemoCredentials, resolvePostLoginRoute, startPasskeyLogin, startPasskeyRegistration, syncPreferredMethodFromServer, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useChangePassword, useDemoCredentials, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePasskeyCeremony, usePinLogin, usePreferredMethodSetting, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };