@dloizides/auth-web 1.4.0 → 1.5.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.d.mts +211 -2
- package/dist/index.d.ts +211 -2
- package/dist/index.js +317 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +308 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -139,6 +139,21 @@ var DEFAULT_PASSKEY_SETTINGS_LABELS = {
|
|
|
139
139
|
addHint: "Start setting up a passkey for this account",
|
|
140
140
|
registeredSuccess: "Your passkey was added. You can now use it to sign in."
|
|
141
141
|
};
|
|
142
|
+
var DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS = {
|
|
143
|
+
title: "Preferred sign-in method",
|
|
144
|
+
description: "Pick how you usually sign in. We will show this method first on your devices.",
|
|
145
|
+
noPreference: "No preference",
|
|
146
|
+
methodPassword: "Password",
|
|
147
|
+
methodPin: "Quick PIN",
|
|
148
|
+
methodPasskey: "Passkey",
|
|
149
|
+
saving: "Saving...",
|
|
150
|
+
saveFailed: "Could not save your preference. Try again later."
|
|
151
|
+
};
|
|
152
|
+
var DEFAULT_PREFERRED_METHOD_HINT_LABELS = {
|
|
153
|
+
password: "You usually sign in with your password.",
|
|
154
|
+
pin: "You usually sign in with your quick PIN on this account.",
|
|
155
|
+
passkey: "You usually sign in with a passkey."
|
|
156
|
+
};
|
|
142
157
|
var DEFAULT_RESET_PASSWORD_LABELS = {
|
|
143
158
|
title: "Reset password",
|
|
144
159
|
description: "Choose a new password for your account.",
|
|
@@ -219,7 +234,14 @@ var AuthTestIds = {
|
|
|
219
234
|
// Passkey settings card
|
|
220
235
|
passkeySettings: "auth-passkey-settings",
|
|
221
236
|
passkeySettingsAdd: "auth-passkey-settings-add",
|
|
222
|
-
passkeySettingsSuccess: "auth-passkey-settings-success"
|
|
237
|
+
passkeySettingsSuccess: "auth-passkey-settings-success",
|
|
238
|
+
// Preferred-method settings card (cross-device default-method picker).
|
|
239
|
+
// Each option row appends `-${method}` to `preferredMethodSettingsOption`.
|
|
240
|
+
preferredMethodSettings: "auth-preferred-method-settings",
|
|
241
|
+
preferredMethodSettingsOption: "auth-preferred-method-settings-option",
|
|
242
|
+
preferredMethodSettingsError: "auth-preferred-method-settings-error",
|
|
243
|
+
// Preferred-method login-screen hint
|
|
244
|
+
preferredMethodHint: "auth-preferred-method-hint"
|
|
223
245
|
};
|
|
224
246
|
function withTestIdPrefix(baseId, prefix) {
|
|
225
247
|
return prefix === void 0 || prefix === "" ? baseId : `${prefix}-${baseId}`;
|
|
@@ -2526,6 +2548,217 @@ function PasskeySettingsCard({
|
|
|
2526
2548
|
}
|
|
2527
2549
|
);
|
|
2528
2550
|
}
|
|
2551
|
+
|
|
2552
|
+
// src/preferences/preferredMethodCache.ts
|
|
2553
|
+
var CACHE_KEY = "dloizides.auth.preferredLoginMethod";
|
|
2554
|
+
function safeStorage() {
|
|
2555
|
+
try {
|
|
2556
|
+
if (typeof localStorage === "undefined") {
|
|
2557
|
+
return null;
|
|
2558
|
+
}
|
|
2559
|
+
return localStorage;
|
|
2560
|
+
} catch {
|
|
2561
|
+
return null;
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
function readCachedPreferredMethod() {
|
|
2565
|
+
const store = safeStorage();
|
|
2566
|
+
if (store === null) {
|
|
2567
|
+
return null;
|
|
2568
|
+
}
|
|
2569
|
+
try {
|
|
2570
|
+
const value = store.getItem(CACHE_KEY);
|
|
2571
|
+
return value === null || value === "" ? null : value;
|
|
2572
|
+
} catch {
|
|
2573
|
+
return null;
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
function cachePreferredMethod(method) {
|
|
2577
|
+
const store = safeStorage();
|
|
2578
|
+
if (store === null) {
|
|
2579
|
+
return;
|
|
2580
|
+
}
|
|
2581
|
+
try {
|
|
2582
|
+
if (method === null || method === "") {
|
|
2583
|
+
store.removeItem(CACHE_KEY);
|
|
2584
|
+
return;
|
|
2585
|
+
}
|
|
2586
|
+
store.setItem(CACHE_KEY, method);
|
|
2587
|
+
} catch {
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
function clearCachedPreferredMethod() {
|
|
2591
|
+
cachePreferredMethod(null);
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
// src/preferences/usePreferredMethodSetting.ts
|
|
2595
|
+
function usePreferredMethodSetting({
|
|
2596
|
+
client,
|
|
2597
|
+
onChanged
|
|
2598
|
+
}) {
|
|
2599
|
+
const [loading, setLoading] = useState(true);
|
|
2600
|
+
const [saving, setSaving] = useState(false);
|
|
2601
|
+
const [failed, setFailed] = useState(false);
|
|
2602
|
+
const [selected, setSelected] = useState(null);
|
|
2603
|
+
useEffect(() => {
|
|
2604
|
+
let active = true;
|
|
2605
|
+
client.getPreferredLoginMethod().then((method) => {
|
|
2606
|
+
if (active) {
|
|
2607
|
+
setSelected(method);
|
|
2608
|
+
}
|
|
2609
|
+
}).catch(() => {
|
|
2610
|
+
}).finally(() => {
|
|
2611
|
+
if (active) {
|
|
2612
|
+
setLoading(false);
|
|
2613
|
+
}
|
|
2614
|
+
});
|
|
2615
|
+
return () => {
|
|
2616
|
+
active = false;
|
|
2617
|
+
};
|
|
2618
|
+
}, [client]);
|
|
2619
|
+
const select = useCallback(
|
|
2620
|
+
(method) => {
|
|
2621
|
+
const previous = selected;
|
|
2622
|
+
if (method === previous) {
|
|
2623
|
+
return;
|
|
2624
|
+
}
|
|
2625
|
+
setFailed(false);
|
|
2626
|
+
setSaving(true);
|
|
2627
|
+
setSelected(method);
|
|
2628
|
+
client.setPreferredLoginMethod(method).then((ok) => {
|
|
2629
|
+
if (ok) {
|
|
2630
|
+
cachePreferredMethod(method);
|
|
2631
|
+
onChanged?.(method);
|
|
2632
|
+
return;
|
|
2633
|
+
}
|
|
2634
|
+
setSelected(previous);
|
|
2635
|
+
setFailed(true);
|
|
2636
|
+
}).catch(() => {
|
|
2637
|
+
setSelected(previous);
|
|
2638
|
+
setFailed(true);
|
|
2639
|
+
}).finally(() => {
|
|
2640
|
+
setSaving(false);
|
|
2641
|
+
});
|
|
2642
|
+
},
|
|
2643
|
+
[client, selected, onChanged]
|
|
2644
|
+
);
|
|
2645
|
+
return { loading, saving, failed, selected, select };
|
|
2646
|
+
}
|
|
2647
|
+
var NO_PREFERENCE = "__none__";
|
|
2648
|
+
function methodDisplayName(method, labels) {
|
|
2649
|
+
if (method === "password") {
|
|
2650
|
+
return labels.methodPassword;
|
|
2651
|
+
}
|
|
2652
|
+
if (method === "pin") {
|
|
2653
|
+
return labels.methodPin;
|
|
2654
|
+
}
|
|
2655
|
+
if (method === "passkey") {
|
|
2656
|
+
return labels.methodPasskey;
|
|
2657
|
+
}
|
|
2658
|
+
return method;
|
|
2659
|
+
}
|
|
2660
|
+
function PreferredMethodSettingsCard({
|
|
2661
|
+
client,
|
|
2662
|
+
availableMethods,
|
|
2663
|
+
theme: themeProp,
|
|
2664
|
+
labels: labelsProp,
|
|
2665
|
+
testIdPrefix,
|
|
2666
|
+
onChanged
|
|
2667
|
+
}) {
|
|
2668
|
+
const theme = useAuthTheme(themeProp);
|
|
2669
|
+
const styles3 = useAuthStyles(theme);
|
|
2670
|
+
const labels = useMemo(
|
|
2671
|
+
() => ({ ...DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, ...labelsProp }),
|
|
2672
|
+
[labelsProp]
|
|
2673
|
+
);
|
|
2674
|
+
const { loading, saving, failed, selected, select } = usePreferredMethodSetting({
|
|
2675
|
+
client,
|
|
2676
|
+
onChanged
|
|
2677
|
+
});
|
|
2678
|
+
const options = useMemo(
|
|
2679
|
+
() => [
|
|
2680
|
+
{ value: null, key: NO_PREFERENCE, label: labels.noPreference },
|
|
2681
|
+
...availableMethods.map((method) => ({
|
|
2682
|
+
value: method,
|
|
2683
|
+
key: method,
|
|
2684
|
+
label: methodDisplayName(method, labels)
|
|
2685
|
+
}))
|
|
2686
|
+
],
|
|
2687
|
+
[availableMethods, labels]
|
|
2688
|
+
);
|
|
2689
|
+
return /* @__PURE__ */ jsxs(
|
|
2690
|
+
View,
|
|
2691
|
+
{
|
|
2692
|
+
style: styles3.card,
|
|
2693
|
+
testID: withTestIdPrefix(AuthTestIds.preferredMethodSettings, testIdPrefix),
|
|
2694
|
+
children: [
|
|
2695
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
|
|
2696
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
|
|
2697
|
+
loading ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.primary, size: "small" }) : options.map((option) => {
|
|
2698
|
+
const isSelected = option.value === selected;
|
|
2699
|
+
const optionTestId = `${withTestIdPrefix(
|
|
2700
|
+
AuthTestIds.preferredMethodSettingsOption,
|
|
2701
|
+
testIdPrefix
|
|
2702
|
+
)}-${option.key}`;
|
|
2703
|
+
return /* @__PURE__ */ jsx(
|
|
2704
|
+
TouchableOpacity,
|
|
2705
|
+
{
|
|
2706
|
+
accessibilityHint: labels.description,
|
|
2707
|
+
accessibilityLabel: option.label,
|
|
2708
|
+
accessibilityRole: "radio",
|
|
2709
|
+
accessibilityState: { selected: isSelected },
|
|
2710
|
+
disabled: saving,
|
|
2711
|
+
style: isSelected ? styles3.secondaryButton : styles3.escapeLink,
|
|
2712
|
+
testID: optionTestId,
|
|
2713
|
+
onPress: () => select(option.value),
|
|
2714
|
+
children: /* @__PURE__ */ jsx(Text, { style: isSelected ? styles3.secondaryButtonText : styles3.linkText, children: isSelected ? `\u2713 ${option.label}` : option.label })
|
|
2715
|
+
},
|
|
2716
|
+
option.key
|
|
2717
|
+
);
|
|
2718
|
+
}),
|
|
2719
|
+
saving ? /* @__PURE__ */ jsx(Text, { style: styles3.helperText, children: labels.saving }) : null,
|
|
2720
|
+
failed ? /* @__PURE__ */ jsx(
|
|
2721
|
+
Text,
|
|
2722
|
+
{
|
|
2723
|
+
style: styles3.errorText,
|
|
2724
|
+
testID: withTestIdPrefix(AuthTestIds.preferredMethodSettingsError, testIdPrefix),
|
|
2725
|
+
children: labels.saveFailed
|
|
2726
|
+
}
|
|
2727
|
+
) : null
|
|
2728
|
+
]
|
|
2729
|
+
}
|
|
2730
|
+
);
|
|
2731
|
+
}
|
|
2732
|
+
function hintFor(method, labels) {
|
|
2733
|
+
if (method === "password") {
|
|
2734
|
+
return labels.password;
|
|
2735
|
+
}
|
|
2736
|
+
if (method === "pin") {
|
|
2737
|
+
return labels.pin;
|
|
2738
|
+
}
|
|
2739
|
+
if (method === "passkey") {
|
|
2740
|
+
return labels.passkey;
|
|
2741
|
+
}
|
|
2742
|
+
return null;
|
|
2743
|
+
}
|
|
2744
|
+
function PreferredMethodHint({
|
|
2745
|
+
method,
|
|
2746
|
+
theme: themeProp,
|
|
2747
|
+
labels: labelsProp,
|
|
2748
|
+
testIdPrefix
|
|
2749
|
+
}) {
|
|
2750
|
+
const theme = useAuthTheme(themeProp);
|
|
2751
|
+
const styles3 = useAuthStyles(theme);
|
|
2752
|
+
const labels = useMemo(
|
|
2753
|
+
() => ({ ...DEFAULT_PREFERRED_METHOD_HINT_LABELS, ...labelsProp }),
|
|
2754
|
+
[labelsProp]
|
|
2755
|
+
);
|
|
2756
|
+
const text = hintFor(method, labels);
|
|
2757
|
+
if (text === null) {
|
|
2758
|
+
return null;
|
|
2759
|
+
}
|
|
2760
|
+
return /* @__PURE__ */ jsx(View, { testID: withTestIdPrefix(AuthTestIds.preferredMethodHint, testIdPrefix), children: /* @__PURE__ */ jsx(Text, { style: styles3.helperText, children: text }) });
|
|
2761
|
+
}
|
|
2529
2762
|
var EMPTY_CONFIG = {
|
|
2530
2763
|
methods: [],
|
|
2531
2764
|
registrationEnabled: false,
|
|
@@ -2560,6 +2793,77 @@ function useBffLoginConfig(client) {
|
|
|
2560
2793
|
}, [client]);
|
|
2561
2794
|
return { config, loading };
|
|
2562
2795
|
}
|
|
2796
|
+
|
|
2797
|
+
// src/preferences/preferencesClient.ts
|
|
2798
|
+
var CSRF_HEADER = "X-BFF-Csrf";
|
|
2799
|
+
var CSRF_HEADER_VALUE = "1";
|
|
2800
|
+
var JSON_CONTENT_TYPE = "application/json";
|
|
2801
|
+
var DEFAULT_TENANTS_SEGMENT = "tenants";
|
|
2802
|
+
var PREFERENCES_PATH = "api/v1/me/preferences";
|
|
2803
|
+
var LOGIN_METHOD_PREFERENCE_PATH = "api/v1/me/login-method-preference";
|
|
2804
|
+
function isRecord(value) {
|
|
2805
|
+
return typeof value === "object" && value !== null;
|
|
2806
|
+
}
|
|
2807
|
+
function readOptionalString(record, key) {
|
|
2808
|
+
const value = record[key];
|
|
2809
|
+
if (typeof value !== "string" || value === "") {
|
|
2810
|
+
return null;
|
|
2811
|
+
}
|
|
2812
|
+
return value;
|
|
2813
|
+
}
|
|
2814
|
+
function createPreferencesClient(options) {
|
|
2815
|
+
const http = options.http;
|
|
2816
|
+
const baseUrl = (options.baseUrl ?? "").replace(/\/$/, "");
|
|
2817
|
+
const segment = options.tenantsSegment ?? DEFAULT_TENANTS_SEGMENT;
|
|
2818
|
+
const proxyBase = `${baseUrl}/bff/api/${segment}`;
|
|
2819
|
+
return {
|
|
2820
|
+
async getPreferredLoginMethod() {
|
|
2821
|
+
try {
|
|
2822
|
+
const response = await http({
|
|
2823
|
+
url: `${proxyBase}/${PREFERENCES_PATH}`,
|
|
2824
|
+
method: "GET",
|
|
2825
|
+
headers: { Accept: JSON_CONTENT_TYPE },
|
|
2826
|
+
credentials: "include"
|
|
2827
|
+
});
|
|
2828
|
+
if (!response.ok || !isRecord(response.data)) {
|
|
2829
|
+
return null;
|
|
2830
|
+
}
|
|
2831
|
+
return readOptionalString(response.data, "preferredLoginMethod");
|
|
2832
|
+
} catch {
|
|
2833
|
+
return null;
|
|
2834
|
+
}
|
|
2835
|
+
},
|
|
2836
|
+
async setPreferredLoginMethod(method) {
|
|
2837
|
+
try {
|
|
2838
|
+
const response = await http({
|
|
2839
|
+
url: `${proxyBase}/${LOGIN_METHOD_PREFERENCE_PATH}`,
|
|
2840
|
+
method: "PUT",
|
|
2841
|
+
headers: {
|
|
2842
|
+
"Content-Type": JSON_CONTENT_TYPE,
|
|
2843
|
+
Accept: JSON_CONTENT_TYPE,
|
|
2844
|
+
[CSRF_HEADER]: CSRF_HEADER_VALUE
|
|
2845
|
+
},
|
|
2846
|
+
body: JSON.stringify({ method }),
|
|
2847
|
+
credentials: "include"
|
|
2848
|
+
});
|
|
2849
|
+
return response.ok;
|
|
2850
|
+
} catch {
|
|
2851
|
+
return false;
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
};
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2857
|
+
// src/preferences/syncPreferredMethodCache.ts
|
|
2858
|
+
async function syncPreferredMethodFromServer(client) {
|
|
2859
|
+
try {
|
|
2860
|
+
const method = await client.getPreferredLoginMethod();
|
|
2861
|
+
cachePreferredMethod(method);
|
|
2862
|
+
return method;
|
|
2863
|
+
} catch {
|
|
2864
|
+
return null;
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2563
2867
|
async function lazyFetchHttpClient(request) {
|
|
2564
2868
|
const fetchImpl = typeof fetch === "function" ? fetch.bind(globalThis) : void 0;
|
|
2565
2869
|
if (fetchImpl === void 0) {
|
|
@@ -2575,11 +2879,11 @@ function createBffAuthClient(options = {}) {
|
|
|
2575
2879
|
}
|
|
2576
2880
|
|
|
2577
2881
|
// src/router/resolvePostLoginRoute.ts
|
|
2578
|
-
function
|
|
2882
|
+
function isRecord2(value) {
|
|
2579
2883
|
return typeof value === "object" && value !== null;
|
|
2580
2884
|
}
|
|
2581
2885
|
function readRealmAccessRoles(realmAccess) {
|
|
2582
|
-
if (!
|
|
2886
|
+
if (!isRecord2(realmAccess)) {
|
|
2583
2887
|
return [];
|
|
2584
2888
|
}
|
|
2585
2889
|
const roles = realmAccess.roles;
|
|
@@ -2603,6 +2907,6 @@ function resolvePostLoginRoute(user, table) {
|
|
|
2603
2907
|
return table.fallback ?? null;
|
|
2604
2908
|
}
|
|
2605
2909
|
|
|
2606
|
-
export { AuthTestIds, AuthThemeProvider, BffAuthStatus, 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_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, PasskeyLoginButton, PasskeySettingsCard, PasswordPolicyError, PinForm, ResetPasswordError, ResetPasswordForm, collectUserRoles, createBffAuthClient, defaultAuthTheme, isAllowedPinDigits, isPasswordValid, isValidForgotPasswordEmail, readPasskeyError, readPasskeyRegistered, resolvePostLoginRoute, startPasskeyLogin, startPasskeyRegistration, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePinLogin, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
|
|
2910
|
+
export { AuthTestIds, AuthThemeProvider, BffAuthStatus, 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, PasskeyLoginButton, PasskeySettingsCard, PasswordPolicyError, PinForm, PreferredMethodHint, PreferredMethodSettingsCard, ResetPasswordError, ResetPasswordForm, cachePreferredMethod, clearCachedPreferredMethod, collectUserRoles, createBffAuthClient, createPreferencesClient, defaultAuthTheme, isAllowedPinDigits, isPasswordValid, isValidForgotPasswordEmail, readCachedPreferredMethod, readPasskeyError, readPasskeyRegistered, resolvePostLoginRoute, startPasskeyLogin, startPasskeyRegistration, syncPreferredMethodFromServer, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePinLogin, usePreferredMethodSetting, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
|
|
2607
2911
|
//# sourceMappingURL=index.mjs.map
|
|
2608
2912
|
//# sourceMappingURL=index.mjs.map
|