@dloizides/auth-web 1.14.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/dist/index.js CHANGED
@@ -308,6 +308,29 @@ var DEFAULT_RESET_PASSWORD_LABELS = {
308
308
  errorNetwork: "Something went wrong. Please try again."
309
309
  };
310
310
 
311
+ // src/components/labels/accountSettingsLabels.ts
312
+ var DEFAULT_ACCOUNT_SETTINGS_LABELS = {
313
+ heading: "Account settings",
314
+ changePasswordTitle: "Change password",
315
+ changePasswordDescription: "Update the password you use to sign in.",
316
+ currentPasswordLabel: "Current password",
317
+ currentPasswordPlaceholder: "Enter your current password",
318
+ newPasswordLabel: "New password",
319
+ newPasswordPlaceholder: "Enter a new password",
320
+ confirmPasswordLabel: "Confirm new password",
321
+ confirmPasswordPlaceholder: "Re-enter your new password",
322
+ submit: "Change password",
323
+ submitting: "Changing password...",
324
+ submitHint: "Submit the form to change your password",
325
+ success: "Your password has been changed.",
326
+ errorWeakNewPassword: "Your new password must be at least 8 characters and include an uppercase letter, a lowercase letter and a number.",
327
+ errorMismatch: "The new password and its confirmation do not match.",
328
+ errorCurrentRequired: "Enter your current password.",
329
+ errorInvalidCurrent: "Your current password is incorrect, or the new password does not meet the policy.",
330
+ errorUnauthorized: "Your session has expired. Sign in again to change your password.",
331
+ errorFailed: "Could not change your password. Try again later."
332
+ };
333
+
311
334
  // src/components/testIds.ts
312
335
  var AuthTestIds = {
313
336
  loginForm: "auth-login-form",
@@ -381,6 +404,15 @@ var AuthTestIds = {
381
404
  preferredMethodSettingsError: "auth-preferred-method-settings-error",
382
405
  // Preferred-method login-screen hint
383
406
  preferredMethodHint: "auth-preferred-method-hint",
407
+ // Account-settings screen shell + in-app change-password form
408
+ accountSettings: "auth-account-settings",
409
+ accountSettingsChangePassword: "auth-account-settings-change-password",
410
+ changePasswordCurrentInput: "auth-change-password-current",
411
+ changePasswordNewInput: "auth-change-password-new",
412
+ changePasswordConfirmInput: "auth-change-password-confirm",
413
+ changePasswordSubmit: "auth-change-password-submit",
414
+ changePasswordError: "auth-change-password-error",
415
+ changePasswordSuccess: "auth-change-password-success",
384
416
  // Public-demo credentials panel
385
417
  demoCredentialsHint: "auth-demo-credentials-hint",
386
418
  demoCredentialsUsername: "auth-demo-credentials-username",
@@ -3202,6 +3234,307 @@ function PreferredMethodSettingsCard({
3202
3234
  }
3203
3235
  );
3204
3236
  }
3237
+
3238
+ // src/password/ChangePasswordErrorKey.ts
3239
+ var ChangePasswordErrorKey = /* @__PURE__ */ ((ChangePasswordErrorKey2) => {
3240
+ ChangePasswordErrorKey2["WeakNewPassword"] = "weak_new_password";
3241
+ ChangePasswordErrorKey2["Mismatch"] = "mismatch";
3242
+ ChangePasswordErrorKey2["CurrentRequired"] = "current_required";
3243
+ ChangePasswordErrorKey2["InvalidCurrent"] = "invalid_current";
3244
+ ChangePasswordErrorKey2["Unauthorized"] = "unauthorized";
3245
+ ChangePasswordErrorKey2["Failed"] = "failed";
3246
+ return ChangePasswordErrorKey2;
3247
+ })(ChangePasswordErrorKey || {});
3248
+ function errorKeyForStatus(status) {
3249
+ if (status === "invalidCurrent") {
3250
+ return "invalid_current" /* InvalidCurrent */;
3251
+ }
3252
+ if (status === "unauthorized") {
3253
+ return "unauthorized" /* Unauthorized */;
3254
+ }
3255
+ return "failed" /* Failed */;
3256
+ }
3257
+ function useChangePassword({
3258
+ client,
3259
+ onChanged
3260
+ }) {
3261
+ const [currentPassword, setCurrentValue] = react.useState("");
3262
+ const [newPassword, setNewValue] = react.useState("");
3263
+ const [confirmPassword, setConfirmValue] = react.useState("");
3264
+ const [submitting, setSubmitting] = react.useState(false);
3265
+ const [succeeded, setSucceeded] = react.useState(false);
3266
+ const [errorKey, setErrorKey] = react.useState(null);
3267
+ const clearStatus = react.useCallback(() => {
3268
+ setErrorKey(null);
3269
+ setSucceeded(false);
3270
+ }, []);
3271
+ const setCurrentPassword = react.useCallback((value) => {
3272
+ setCurrentValue(value);
3273
+ clearStatus();
3274
+ }, [clearStatus]);
3275
+ const setNewPassword = react.useCallback((value) => {
3276
+ setNewValue(value);
3277
+ clearStatus();
3278
+ }, [clearStatus]);
3279
+ const setConfirmPassword = react.useCallback((value) => {
3280
+ setConfirmValue(value);
3281
+ clearStatus();
3282
+ }, [clearStatus]);
3283
+ const reset = react.useCallback(() => {
3284
+ setCurrentValue("");
3285
+ setNewValue("");
3286
+ setConfirmValue("");
3287
+ setSubmitting(false);
3288
+ setSucceeded(false);
3289
+ setErrorKey(null);
3290
+ }, []);
3291
+ const submit = react.useCallback(() => {
3292
+ if (currentPassword === "") {
3293
+ setErrorKey("current_required" /* CurrentRequired */);
3294
+ return;
3295
+ }
3296
+ if (newPassword !== confirmPassword) {
3297
+ setErrorKey("mismatch" /* Mismatch */);
3298
+ return;
3299
+ }
3300
+ if (!isPasswordValid(newPassword)) {
3301
+ setErrorKey("weak_new_password" /* WeakNewPassword */);
3302
+ return;
3303
+ }
3304
+ setErrorKey(null);
3305
+ setSucceeded(false);
3306
+ setSubmitting(true);
3307
+ client.changePassword({ currentPassword, newPassword }).then((result) => {
3308
+ if (result.status === "success") {
3309
+ setCurrentValue("");
3310
+ setNewValue("");
3311
+ setConfirmValue("");
3312
+ setSucceeded(true);
3313
+ onChanged?.();
3314
+ return;
3315
+ }
3316
+ setErrorKey(errorKeyForStatus(result.status));
3317
+ }).catch(() => {
3318
+ setErrorKey("failed" /* Failed */);
3319
+ }).finally(() => {
3320
+ setSubmitting(false);
3321
+ });
3322
+ }, [client, currentPassword, newPassword, confirmPassword, onChanged]);
3323
+ return {
3324
+ currentPassword,
3325
+ newPassword,
3326
+ confirmPassword,
3327
+ setCurrentPassword,
3328
+ setNewPassword,
3329
+ setConfirmPassword,
3330
+ submitting,
3331
+ succeeded,
3332
+ errorKey,
3333
+ submit,
3334
+ reset
3335
+ };
3336
+ }
3337
+ function errorMessage2(errorKey, labels) {
3338
+ switch (errorKey) {
3339
+ case "weak_new_password" /* WeakNewPassword */:
3340
+ return labels.errorWeakNewPassword;
3341
+ case "mismatch" /* Mismatch */:
3342
+ return labels.errorMismatch;
3343
+ case "current_required" /* CurrentRequired */:
3344
+ return labels.errorCurrentRequired;
3345
+ case "invalid_current" /* InvalidCurrent */:
3346
+ return labels.errorInvalidCurrent;
3347
+ case "unauthorized" /* Unauthorized */:
3348
+ return labels.errorUnauthorized;
3349
+ case "failed" /* Failed */:
3350
+ return labels.errorFailed;
3351
+ default:
3352
+ return null;
3353
+ }
3354
+ }
3355
+ function ChangePasswordCard({
3356
+ client,
3357
+ theme: themeProp,
3358
+ labels: labelsProp,
3359
+ testIdPrefix,
3360
+ onChanged
3361
+ }) {
3362
+ const theme = useAuthTheme(themeProp);
3363
+ const styles3 = useAuthStyles(theme);
3364
+ const labels = react.useMemo(
3365
+ () => ({ ...DEFAULT_ACCOUNT_SETTINGS_LABELS, ...labelsProp }),
3366
+ [labelsProp]
3367
+ );
3368
+ const form = useChangePassword({ client, onChanged });
3369
+ const message = errorMessage2(form.errorKey, labels);
3370
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3371
+ reactNative.View,
3372
+ {
3373
+ style: styles3.card,
3374
+ testID: withTestIdPrefix(AuthTestIds.accountSettingsChangePassword, testIdPrefix),
3375
+ children: [
3376
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.changePasswordTitle }),
3377
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.changePasswordDescription }),
3378
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
3379
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.currentPasswordLabel }),
3380
+ /* @__PURE__ */ jsxRuntime.jsx(
3381
+ reactNative.TextInput,
3382
+ {
3383
+ accessibilityLabel: labels.currentPasswordLabel,
3384
+ autoComplete: "current-password",
3385
+ placeholder: labels.currentPasswordPlaceholder,
3386
+ placeholderTextColor: theme.colors.textSecondary,
3387
+ secureTextEntry: true,
3388
+ style: styles3.input,
3389
+ testID: withTestIdPrefix(AuthTestIds.changePasswordCurrentInput, testIdPrefix),
3390
+ value: form.currentPassword,
3391
+ onChangeText: form.setCurrentPassword
3392
+ }
3393
+ )
3394
+ ] }),
3395
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
3396
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.newPasswordLabel }),
3397
+ /* @__PURE__ */ jsxRuntime.jsx(
3398
+ reactNative.TextInput,
3399
+ {
3400
+ accessibilityLabel: labels.newPasswordLabel,
3401
+ autoComplete: "new-password",
3402
+ placeholder: labels.newPasswordPlaceholder,
3403
+ placeholderTextColor: theme.colors.textSecondary,
3404
+ secureTextEntry: true,
3405
+ style: styles3.input,
3406
+ testID: withTestIdPrefix(AuthTestIds.changePasswordNewInput, testIdPrefix),
3407
+ value: form.newPassword,
3408
+ onChangeText: form.setNewPassword
3409
+ }
3410
+ )
3411
+ ] }),
3412
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
3413
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.confirmPasswordLabel }),
3414
+ /* @__PURE__ */ jsxRuntime.jsx(
3415
+ reactNative.TextInput,
3416
+ {
3417
+ accessibilityLabel: labels.confirmPasswordLabel,
3418
+ autoComplete: "new-password",
3419
+ placeholder: labels.confirmPasswordPlaceholder,
3420
+ placeholderTextColor: theme.colors.textSecondary,
3421
+ secureTextEntry: true,
3422
+ style: styles3.input,
3423
+ testID: withTestIdPrefix(AuthTestIds.changePasswordConfirmInput, testIdPrefix),
3424
+ value: form.confirmPassword,
3425
+ onChangeText: form.setConfirmPassword
3426
+ }
3427
+ )
3428
+ ] }),
3429
+ message !== null ? /* @__PURE__ */ jsxRuntime.jsx(
3430
+ reactNative.Text,
3431
+ {
3432
+ style: styles3.errorText,
3433
+ testID: withTestIdPrefix(AuthTestIds.changePasswordError, testIdPrefix),
3434
+ children: message
3435
+ }
3436
+ ) : null,
3437
+ form.succeeded ? /* @__PURE__ */ jsxRuntime.jsx(
3438
+ reactNative.Text,
3439
+ {
3440
+ style: styles3.successText,
3441
+ testID: withTestIdPrefix(AuthTestIds.changePasswordSuccess, testIdPrefix),
3442
+ children: labels.success
3443
+ }
3444
+ ) : null,
3445
+ /* @__PURE__ */ jsxRuntime.jsx(
3446
+ reactNative.TouchableOpacity,
3447
+ {
3448
+ accessibilityHint: labels.submitHint,
3449
+ accessibilityLabel: form.submitting ? labels.submitting : labels.submit,
3450
+ accessibilityRole: "button",
3451
+ disabled: form.submitting,
3452
+ style: form.submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton,
3453
+ testID: withTestIdPrefix(AuthTestIds.changePasswordSubmit, testIdPrefix),
3454
+ onPress: form.submit,
3455
+ children: form.submitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
3456
+ }
3457
+ )
3458
+ ]
3459
+ }
3460
+ );
3461
+ }
3462
+ var GAP = 16;
3463
+ var layout = reactNative.StyleSheet.create({
3464
+ content: {
3465
+ width: "100%",
3466
+ alignItems: "center",
3467
+ rowGap: GAP
3468
+ }
3469
+ });
3470
+ function AccountSettingsScreen({
3471
+ changePassword,
3472
+ devicePin,
3473
+ passkeys,
3474
+ preferredMethod,
3475
+ theme: themeProp,
3476
+ labels: labelsProp,
3477
+ testIdPrefix
3478
+ }) {
3479
+ const theme = useAuthTheme(themeProp);
3480
+ const styles3 = useAuthStyles(theme);
3481
+ const labels = react.useMemo(
3482
+ () => ({ ...DEFAULT_ACCOUNT_SETTINGS_LABELS, ...labelsProp }),
3483
+ [labelsProp]
3484
+ );
3485
+ return /* @__PURE__ */ jsxRuntime.jsx(
3486
+ reactNative.ScrollView,
3487
+ {
3488
+ contentContainerStyle: styles3.screen,
3489
+ testID: withTestIdPrefix(AuthTestIds.accountSettings, testIdPrefix),
3490
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: layout.content, children: [
3491
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.heading }),
3492
+ /* @__PURE__ */ jsxRuntime.jsx(
3493
+ ChangePasswordCard,
3494
+ {
3495
+ client: changePassword.client,
3496
+ labels: labelsProp,
3497
+ testIdPrefix,
3498
+ theme,
3499
+ onChanged: changePassword.onChanged
3500
+ }
3501
+ ),
3502
+ devicePin !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
3503
+ DevicePinSettingsCard,
3504
+ {
3505
+ client: devicePin.client,
3506
+ enrollLabels: devicePin.enrollLabels,
3507
+ initialHasPin: devicePin.initialHasPin,
3508
+ labels: devicePin.labels,
3509
+ testIdPrefix,
3510
+ theme,
3511
+ onChanged: devicePin.onChanged
3512
+ }
3513
+ ) : null,
3514
+ passkeys !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
3515
+ PasskeySettingsCard,
3516
+ {
3517
+ labels: passkeys.labels,
3518
+ returnUrl: passkeys.returnUrl,
3519
+ testIdPrefix,
3520
+ theme
3521
+ }
3522
+ ) : null,
3523
+ preferredMethod !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
3524
+ PreferredMethodSettingsCard,
3525
+ {
3526
+ availableMethods: preferredMethod.availableMethods,
3527
+ client: preferredMethod.client,
3528
+ labels: preferredMethod.labels,
3529
+ testIdPrefix,
3530
+ theme,
3531
+ onChanged: preferredMethod.onChanged
3532
+ }
3533
+ ) : null
3534
+ ] })
3535
+ }
3536
+ );
3537
+ }
3205
3538
  function hintFor(method, labels) {
3206
3539
  if (method === "password") {
3207
3540
  return labels.password;
@@ -3718,6 +4051,56 @@ async function performBffLogout(options) {
3718
4051
  }
3719
4052
  runGuarded(onRedirect, onError);
3720
4053
  }
4054
+ var CHANGE_PASSWORD_ENDPOINT = "/bff/account/change-password";
4055
+ var CSRF_HEADER2 = "X-BFF-Csrf";
4056
+ var CSRF_HEADER_VALUE2 = "1";
4057
+ var JSON_CONTENT_TYPE2 = "application/json";
4058
+ var HTTP_NO_CONTENT = 204;
4059
+ var HTTP_OK = 200;
4060
+ var HTTP_BAD_REQUEST2 = 400;
4061
+ var HTTP_UNAUTHORIZED = 401;
4062
+ async function lazyFetchHttpClient2(request) {
4063
+ const fetchImpl = typeof fetch === "function" ? fetch.bind(globalThis) : void 0;
4064
+ if (fetchImpl === void 0) {
4065
+ throw new Error("createBffChangePasswordClient: fetch is not available in this environment");
4066
+ }
4067
+ return authClient.createFetchHttpClient(fetchImpl)(request);
4068
+ }
4069
+ function resultFromStatus(status) {
4070
+ if (status === HTTP_NO_CONTENT || status === HTTP_OK) {
4071
+ return { status: "success" };
4072
+ }
4073
+ if (status === HTTP_BAD_REQUEST2) {
4074
+ return { status: "invalidCurrent" };
4075
+ }
4076
+ if (status === HTTP_UNAUTHORIZED) {
4077
+ return { status: "unauthorized" };
4078
+ }
4079
+ return { status: "error" };
4080
+ }
4081
+ function createBffChangePasswordClient(options = {}) {
4082
+ const http = options.http ?? lazyFetchHttpClient2;
4083
+ const baseUrl = options.baseUrl ?? "";
4084
+ const url = `${baseUrl}${CHANGE_PASSWORD_ENDPOINT}`;
4085
+ return {
4086
+ changePassword: async (request) => {
4087
+ try {
4088
+ const response = await http({
4089
+ url,
4090
+ method: "POST",
4091
+ headers: { "Content-Type": JSON_CONTENT_TYPE2, [CSRF_HEADER2]: CSRF_HEADER_VALUE2 },
4092
+ body: JSON.stringify({
4093
+ currentPassword: request.currentPassword,
4094
+ newPassword: request.newPassword
4095
+ })
4096
+ });
4097
+ return resultFromStatus(response.status);
4098
+ } catch {
4099
+ return { status: "error" };
4100
+ }
4101
+ }
4102
+ };
4103
+ }
3721
4104
 
3722
4105
  Object.defineProperty(exports, "BffAuthClient", {
3723
4106
  enumerable: true,
@@ -3727,10 +4110,15 @@ Object.defineProperty(exports, "createFetchHttpClient", {
3727
4110
  enumerable: true,
3728
4111
  get: function () { return authClient.createFetchHttpClient; }
3729
4112
  });
4113
+ exports.AccountSettingsScreen = AccountSettingsScreen;
3730
4114
  exports.AuthScreen = AuthScreen;
3731
4115
  exports.AuthTestIds = AuthTestIds;
3732
4116
  exports.AuthThemeProvider = AuthThemeProvider;
3733
4117
  exports.BffAuthStatus = BffAuthStatus;
4118
+ exports.CHANGE_PASSWORD_ENDPOINT = CHANGE_PASSWORD_ENDPOINT;
4119
+ exports.ChangePasswordCard = ChangePasswordCard;
4120
+ exports.ChangePasswordErrorKey = ChangePasswordErrorKey;
4121
+ exports.DEFAULT_ACCOUNT_SETTINGS_LABELS = DEFAULT_ACCOUNT_SETTINGS_LABELS;
3734
4122
  exports.DEFAULT_AUTH_CARD_MAX_WIDTH = DEFAULT_AUTH_CARD_MAX_WIDTH;
3735
4123
  exports.DEFAULT_DEMO_CREDENTIALS_HINT_LABELS = DEFAULT_DEMO_CREDENTIALS_HINT_LABELS;
3736
4124
  exports.DEFAULT_DEVICE_PIN_ENROLL_LABELS = DEFAULT_DEVICE_PIN_ENROLL_LABELS;
@@ -3780,6 +4168,7 @@ exports.cachePreferredMethod = cachePreferredMethod;
3780
4168
  exports.clearCachedPreferredMethod = clearCachedPreferredMethod;
3781
4169
  exports.collectUserRoles = collectUserRoles;
3782
4170
  exports.createBffAuthClient = createBffAuthClient;
4171
+ exports.createBffChangePasswordClient = createBffChangePasswordClient;
3783
4172
  exports.createPreferencesClient = createPreferencesClient;
3784
4173
  exports.defaultAuthTheme = defaultAuthTheme;
3785
4174
  exports.isAllowedPinDigits = isAllowedPinDigits;
@@ -3800,6 +4189,7 @@ exports.useBffAuth = useBffAuth;
3800
4189
  exports.useBffForgotPassword = useBffForgotPassword;
3801
4190
  exports.useBffLoginConfig = useBffLoginConfig;
3802
4191
  exports.useBffResetPassword = useBffResetPassword;
4192
+ exports.useChangePassword = useChangePassword;
3803
4193
  exports.useDemoCredentials = useDemoCredentials;
3804
4194
  exports.useDevicePinDisable = useDevicePinDisable;
3805
4195
  exports.useDevicePinEnroll = useDevicePinEnroll;