@dloizides/auth-web 1.10.0 → 1.12.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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { StyleSheet, View, Text, TextInput, TouchableOpacity, ActivityIndicator, Pressable } from 'react-native';
1
+ import { StyleSheet, Platform, View, Text, TextInput, TouchableOpacity, ActivityIndicator, Pressable } from 'react-native';
2
2
  import { createContext, useContext, useMemo, useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { useMutation } from '@tanstack/react-query';
@@ -261,6 +261,14 @@ var DEFAULT_PREFERRED_METHOD_HINT_LABELS = {
261
261
  pin: "You usually sign in with your quick PIN on this account.",
262
262
  passkey: "You usually sign in with a passkey."
263
263
  };
264
+ var DEFAULT_DEMO_CREDENTIALS_HINT_LABELS = {
265
+ title: "Demo access",
266
+ description: "Explore the full product with our shared demo account.",
267
+ usernameLabel: "Username",
268
+ passwordLabel: "Password",
269
+ useCredentials: "Use these credentials",
270
+ useCredentialsHint: "Fill the sign-in form with the demo username and password"
271
+ };
264
272
  var DEFAULT_RESET_PASSWORD_LABELS = {
265
273
  title: "Reset password",
266
274
  description: "Choose a new password for your account.",
@@ -349,7 +357,12 @@ var AuthTestIds = {
349
357
  preferredMethodSettingsOption: "auth-preferred-method-settings-option",
350
358
  preferredMethodSettingsError: "auth-preferred-method-settings-error",
351
359
  // Preferred-method login-screen hint
352
- preferredMethodHint: "auth-preferred-method-hint"
360
+ preferredMethodHint: "auth-preferred-method-hint",
361
+ // Public-demo credentials panel
362
+ demoCredentialsHint: "auth-demo-credentials-hint",
363
+ demoCredentialsUsername: "auth-demo-credentials-username",
364
+ demoCredentialsPassword: "auth-demo-credentials-password",
365
+ demoCredentialsUseButton: "auth-demo-credentials-use"
353
366
  };
354
367
  function withTestIdPrefix(baseId, prefix) {
355
368
  return prefix === void 0 || prefix === "" ? baseId : `${prefix}-${baseId}`;
@@ -480,6 +493,35 @@ function useAuthStyles(theme) {
480
493
  });
481
494
  }, [theme]);
482
495
  }
496
+
497
+ // src/components/PrefillIntent.ts
498
+ var PrefillIntent = /* @__PURE__ */ ((PrefillIntent2) => {
499
+ PrefillIntent2["Explicit"] = "explicit";
500
+ PrefillIntent2["Opportunistic"] = "opportunistic";
501
+ return PrefillIntent2;
502
+ })(PrefillIntent || {});
503
+
504
+ // src/components/useLoginPrefill.ts
505
+ function useLoginPrefill({
506
+ initialUsername,
507
+ initialPassword,
508
+ prefillNonce,
509
+ prefillIntent
510
+ }) {
511
+ const [username, setUsername] = useState(initialUsername ?? "");
512
+ const [password, setPassword] = useState(initialPassword ?? "");
513
+ const [appliedNonce, setAppliedNonce] = useState(prefillNonce);
514
+ if (prefillNonce !== appliedNonce) {
515
+ setAppliedNonce(prefillNonce);
516
+ const isPristine = username.length === 0 && password.length === 0;
517
+ const mayApply = prefillIntent !== "opportunistic" /* Opportunistic */ || isPristine;
518
+ if (mayApply) {
519
+ setUsername(initialUsername ?? "");
520
+ setPassword(initialPassword ?? "");
521
+ }
522
+ }
523
+ return { username, password, setUsername, setPassword };
524
+ }
483
525
  var BffAuthStatus = /* @__PURE__ */ ((BffAuthStatus2) => {
484
526
  BffAuthStatus2["Loading"] = "loading";
485
527
  BffAuthStatus2["Authenticated"] = "authenticated";
@@ -591,7 +633,11 @@ function LoginForm({
591
633
  onForgotPassword,
592
634
  onSignUp,
593
635
  testIdPrefix,
594
- chromeless = false
636
+ chromeless = false,
637
+ initialUsername,
638
+ initialPassword,
639
+ prefillNonce,
640
+ prefillIntent
595
641
  }) {
596
642
  const theme = useAuthTheme(themeProp);
597
643
  const styles3 = useAuthStyles(theme);
@@ -600,8 +646,12 @@ function LoginForm({
600
646
  [labelsProp]
601
647
  );
602
648
  const { login, isSubmitting } = useBffAuth({ client, probeOnMount: false });
603
- const [username, setUsername] = useState("");
604
- const [password, setPassword] = useState("");
649
+ const { username, password, setUsername, setPassword } = useLoginPrefill({
650
+ initialUsername,
651
+ initialPassword,
652
+ prefillNonce,
653
+ prefillIntent
654
+ });
605
655
  const [errorText, setErrorText] = useState(null);
606
656
  const runLogin = useCallback(async () => {
607
657
  setErrorText(null);
@@ -3131,6 +3181,156 @@ function PreferredMethodHint({
3131
3181
  }
3132
3182
  return /* @__PURE__ */ jsx(View, { testID: withTestIdPrefix(AuthTestIds.preferredMethodHint, testIdPrefix), children: /* @__PURE__ */ jsx(Text, { style: styles3.helperText, children: text }) });
3133
3183
  }
3184
+ var PANEL_BORDER_WIDTH = 1;
3185
+ var ACCENT_RAIL_WIDTH = 3;
3186
+ var TITLE_LETTER_SPACING = 0.8;
3187
+ var DESCRIPTION_LINE_HEIGHT_RATIO = 1.45;
3188
+ var HALF = 2;
3189
+ var MONOSPACE_FONT = Platform.select({
3190
+ ios: "Menlo",
3191
+ android: "monospace",
3192
+ default: "monospace"
3193
+ });
3194
+ function useDemoCredentialsStyles(theme) {
3195
+ return useMemo(() => {
3196
+ const { colors, radii, spacing, typography } = theme;
3197
+ return StyleSheet.create({
3198
+ panel: {
3199
+ borderWidth: PANEL_BORDER_WIDTH,
3200
+ borderLeftWidth: ACCENT_RAIL_WIDTH,
3201
+ borderRadius: radii.card,
3202
+ borderColor: colors.border,
3203
+ borderLeftColor: colors.primary,
3204
+ padding: spacing.md,
3205
+ marginBottom: spacing.md,
3206
+ backgroundColor: colors.background
3207
+ },
3208
+ title: {
3209
+ fontSize: typography.caption,
3210
+ fontWeight: "700",
3211
+ letterSpacing: TITLE_LETTER_SPACING,
3212
+ textTransform: "uppercase",
3213
+ color: colors.primary
3214
+ },
3215
+ description: {
3216
+ fontSize: typography.caption,
3217
+ lineHeight: typography.caption * DESCRIPTION_LINE_HEIGHT_RATIO,
3218
+ marginTop: spacing.xs / HALF,
3219
+ marginBottom: spacing.sm,
3220
+ color: colors.textSecondary
3221
+ },
3222
+ row: {
3223
+ flexDirection: "row",
3224
+ alignItems: "center",
3225
+ justifyContent: "space-between",
3226
+ marginTop: spacing.xs / HALF
3227
+ },
3228
+ rowLabel: {
3229
+ fontSize: typography.caption,
3230
+ color: colors.textSecondary
3231
+ },
3232
+ rowValue: {
3233
+ fontFamily: MONOSPACE_FONT,
3234
+ fontSize: typography.caption,
3235
+ fontWeight: "600",
3236
+ borderWidth: PANEL_BORDER_WIDTH,
3237
+ borderRadius: radii.input,
3238
+ borderColor: colors.border,
3239
+ paddingVertical: spacing.xs / HALF,
3240
+ paddingHorizontal: spacing.xs,
3241
+ // Never let a long password squeeze the label off the row.
3242
+ flexShrink: 1,
3243
+ backgroundColor: colors.surface,
3244
+ color: colors.text
3245
+ }
3246
+ });
3247
+ }, [theme]);
3248
+ }
3249
+
3250
+ // src/demo/resolveDemoCredentials.ts
3251
+ function resolveDemoCredentials(credentials) {
3252
+ if (credentials === void 0 || credentials === null) {
3253
+ return null;
3254
+ }
3255
+ const username = typeof credentials.username === "string" ? credentials.username.trim() : "";
3256
+ const password = typeof credentials.password === "string" ? credentials.password : "";
3257
+ const isUnusable = username.length === 0 || password.length === 0;
3258
+ if (isUnusable) {
3259
+ return null;
3260
+ }
3261
+ return { username, password };
3262
+ }
3263
+ function DemoCredentialsHint({
3264
+ credentials,
3265
+ theme: themeProp,
3266
+ labels: labelsProp,
3267
+ testIdPrefix,
3268
+ onUse
3269
+ }) {
3270
+ const theme = useAuthTheme(themeProp);
3271
+ const authStyles = useAuthStyles(theme);
3272
+ const styles3 = useDemoCredentialsStyles(theme);
3273
+ const labels = useMemo(
3274
+ () => ({ ...DEFAULT_DEMO_CREDENTIALS_HINT_LABELS, ...labelsProp }),
3275
+ [labelsProp]
3276
+ );
3277
+ const resolved = useMemo(() => resolveDemoCredentials(credentials), [credentials]);
3278
+ const handleUse = useCallback(() => {
3279
+ if (resolved !== null && onUse !== void 0) {
3280
+ onUse(resolved);
3281
+ }
3282
+ }, [resolved, onUse]);
3283
+ if (resolved === null) {
3284
+ return null;
3285
+ }
3286
+ return /* @__PURE__ */ jsxs(
3287
+ View,
3288
+ {
3289
+ style: styles3.panel,
3290
+ testID: withTestIdPrefix(AuthTestIds.demoCredentialsHint, testIdPrefix),
3291
+ children: [
3292
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
3293
+ /* @__PURE__ */ jsx(Text, { style: styles3.description, children: labels.description }),
3294
+ /* @__PURE__ */ jsxs(View, { style: styles3.row, children: [
3295
+ /* @__PURE__ */ jsx(Text, { style: styles3.rowLabel, children: labels.usernameLabel }),
3296
+ /* @__PURE__ */ jsx(
3297
+ Text,
3298
+ {
3299
+ selectable: true,
3300
+ style: styles3.rowValue,
3301
+ testID: withTestIdPrefix(AuthTestIds.demoCredentialsUsername, testIdPrefix),
3302
+ children: resolved.username
3303
+ }
3304
+ )
3305
+ ] }),
3306
+ /* @__PURE__ */ jsxs(View, { style: styles3.row, children: [
3307
+ /* @__PURE__ */ jsx(Text, { style: styles3.rowLabel, children: labels.passwordLabel }),
3308
+ /* @__PURE__ */ jsx(
3309
+ Text,
3310
+ {
3311
+ selectable: true,
3312
+ style: styles3.rowValue,
3313
+ testID: withTestIdPrefix(AuthTestIds.demoCredentialsPassword, testIdPrefix),
3314
+ children: resolved.password
3315
+ }
3316
+ )
3317
+ ] }),
3318
+ onUse !== void 0 ? /* @__PURE__ */ jsx(
3319
+ TouchableOpacity,
3320
+ {
3321
+ accessibilityHint: labels.useCredentialsHint,
3322
+ accessibilityLabel: labels.useCredentials,
3323
+ accessibilityRole: "button",
3324
+ style: authStyles.secondaryButton,
3325
+ testID: withTestIdPrefix(AuthTestIds.demoCredentialsUseButton, testIdPrefix),
3326
+ onPress: handleUse,
3327
+ children: /* @__PURE__ */ jsx(Text, { style: authStyles.secondaryButtonText, children: labels.useCredentials })
3328
+ }
3329
+ ) : null
3330
+ ]
3331
+ }
3332
+ );
3333
+ }
3134
3334
  var EMPTY_CONFIG = {
3135
3335
  methods: [],
3136
3336
  registrationEnabled: false,
@@ -3139,7 +3339,8 @@ var EMPTY_CONFIG = {
3139
3339
  hasPin: false,
3140
3340
  pinDigits: null,
3141
3341
  preferredMethod: null
3142
- }
3342
+ },
3343
+ demo: null
3143
3344
  };
3144
3345
  function useBffLoginConfig(client) {
3145
3346
  const [config, setConfig] = useState(EMPTY_CONFIG);
@@ -3236,6 +3437,55 @@ async function syncPreferredMethodFromServer(client) {
3236
3437
  return null;
3237
3438
  }
3238
3439
  }
3440
+ function isSamePair(a, b) {
3441
+ if (a === null || b === null) {
3442
+ return a === b;
3443
+ }
3444
+ return a.username === b.username && a.password === b.password;
3445
+ }
3446
+ function useDemoCredentials({
3447
+ credentials,
3448
+ prefillOnMount = false
3449
+ } = {}) {
3450
+ const resolved = useMemo(() => resolveDemoCredentials(credentials), [credentials]);
3451
+ const [filled, setFilled] = useState(
3452
+ prefillOnMount ? resolved : null
3453
+ );
3454
+ const [prefillNonce, setPrefillNonce] = useState(0);
3455
+ const [prefillIntent, setPrefillIntent] = useState(
3456
+ "opportunistic" /* Opportunistic */
3457
+ );
3458
+ const [autoSeeded, setAutoSeeded] = useState(
3459
+ prefillOnMount ? resolved : null
3460
+ );
3461
+ const shouldAutoSeed = prefillOnMount && resolved !== null && !isSamePair(resolved, autoSeeded);
3462
+ if (shouldAutoSeed) {
3463
+ setAutoSeeded(resolved);
3464
+ setFilled(resolved);
3465
+ setPrefillNonce((current) => current + 1);
3466
+ setPrefillIntent("opportunistic" /* Opportunistic */);
3467
+ }
3468
+ const handleUse = useCallback((next) => {
3469
+ setFilled(next);
3470
+ setPrefillNonce((current) => current + 1);
3471
+ setPrefillIntent("explicit" /* Explicit */);
3472
+ }, []);
3473
+ return useMemo(
3474
+ () => ({
3475
+ loginFormProps: {
3476
+ initialUsername: filled?.username,
3477
+ initialPassword: filled?.password,
3478
+ prefillNonce,
3479
+ prefillIntent
3480
+ },
3481
+ // `credentials` is passed through unresolved on purpose: the hint applies
3482
+ // `resolveDemoCredentials` itself, so it fails closed even when it is used
3483
+ // standalone, without this hook.
3484
+ hintProps: { credentials, onUse: handleUse }
3485
+ }),
3486
+ [filled, prefillNonce, prefillIntent, credentials, handleUse]
3487
+ );
3488
+ }
3239
3489
  async function lazyFetchHttpClient(request) {
3240
3490
  const fetchImpl = typeof fetch === "function" ? fetch.bind(globalThis) : void 0;
3241
3491
  if (fetchImpl === void 0) {
@@ -3322,6 +3572,6 @@ async function performBffLogout(options) {
3322
3572
  runGuarded(onRedirect, onError);
3323
3573
  }
3324
3574
 
3325
- export { AuthScreen, AuthTestIds, AuthThemeProvider, BffAuthStatus, DEFAULT_AUTH_CARD_MAX_WIDTH, 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, DevicePinEnrollErrorKey, DevicePinEnrollForm, DevicePinErrorKey, DevicePinInput, DevicePinLengthPicker, DevicePinOffer, DevicePinSettingsCard, DevicePinUnlockScreen, ForgotPasswordFields, ForgotPasswordForm, LoginForm, OtpForm, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyCeremonyMode, PasskeyCeremonyStatus, PasskeyLoginButton, PasskeySettingsCard, PasswordPolicyError, PinForm, PreferredMethodHint, PreferredMethodSettingsCard, ResetPasswordError, ResetPasswordForm, cachePreferredMethod, clearCachedPreferredMethod, collectUserRoles, createBffAuthClient, createPreferencesClient, defaultAuthTheme, isAllowedPinDigits, isPasswordValid, isValidForgotPasswordEmail, performBffLogout, readCachedPreferredMethod, readPasskeyError, readPasskeyRegistered, resolveAccessibleRoutes, resolvePostLoginRoute, startPasskeyLogin, startPasskeyRegistration, syncPreferredMethodFromServer, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePasskeyCeremony, usePinLogin, usePreferredMethodSetting, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
3575
+ export { AuthScreen, AuthTestIds, AuthThemeProvider, BffAuthStatus, 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, DevicePinEnrollErrorKey, DevicePinEnrollForm, DevicePinErrorKey, DevicePinInput, DevicePinLengthPicker, DevicePinOffer, DevicePinSettingsCard, DevicePinUnlockScreen, ForgotPasswordFields, ForgotPasswordForm, LoginForm, OtpForm, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyCeremonyMode, PasskeyCeremonyStatus, PasskeyLoginButton, PasskeySettingsCard, PasswordPolicyError, PinForm, PreferredMethodHint, PreferredMethodSettingsCard, PrefillIntent, ResetPasswordError, ResetPasswordForm, 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 };
3326
3576
  //# sourceMappingURL=index.mjs.map
3327
3577
  //# sourceMappingURL=index.mjs.map