@volr/react-ui 0.1.120 → 0.1.122
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.cjs +183 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +183 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -61,6 +61,7 @@ declare const VolrUIProvider: React$1.FC<VolrUIProviderProps>;
|
|
|
61
61
|
/**
|
|
62
62
|
* Passkey Enrollment View Component
|
|
63
63
|
* Modern passkey setup with device-specific biometric icons
|
|
64
|
+
* Includes cross-domain migration detection and guidance
|
|
64
65
|
*/
|
|
65
66
|
interface PasskeyEnrollViewProps {
|
|
66
67
|
onComplete: () => void;
|
|
@@ -194,6 +195,19 @@ declare const en: {
|
|
|
194
195
|
readonly default: "Please use this device's biometric.";
|
|
195
196
|
readonly note: "Using other devices or apps may not work.";
|
|
196
197
|
};
|
|
198
|
+
readonly migration: {
|
|
199
|
+
readonly title: "Set up passkey for this site";
|
|
200
|
+
readonly description: "Your wallet was created on {{sourceDomain}}. To use it here, you need to set up a new passkey for this site.";
|
|
201
|
+
readonly descriptionGeneric: "Your wallet was created on a different site. To use it here, you need to set up a new passkey for this site.";
|
|
202
|
+
readonly currentDomain: "Current site";
|
|
203
|
+
readonly sourceDomain: "Original site";
|
|
204
|
+
readonly benefits: "Your wallet address and balance will remain the same.";
|
|
205
|
+
readonly cta: "Set up passkey";
|
|
206
|
+
readonly later: "Do it later";
|
|
207
|
+
readonly inProgress: "Setting up...";
|
|
208
|
+
readonly success: "Passkey set up successfully!";
|
|
209
|
+
readonly error: "Failed to set up passkey. Please try again.";
|
|
210
|
+
};
|
|
197
211
|
};
|
|
198
212
|
readonly success: {
|
|
199
213
|
readonly title: "Success!";
|
package/dist/index.d.ts
CHANGED
|
@@ -61,6 +61,7 @@ declare const VolrUIProvider: React$1.FC<VolrUIProviderProps>;
|
|
|
61
61
|
/**
|
|
62
62
|
* Passkey Enrollment View Component
|
|
63
63
|
* Modern passkey setup with device-specific biometric icons
|
|
64
|
+
* Includes cross-domain migration detection and guidance
|
|
64
65
|
*/
|
|
65
66
|
interface PasskeyEnrollViewProps {
|
|
66
67
|
onComplete: () => void;
|
|
@@ -194,6 +195,19 @@ declare const en: {
|
|
|
194
195
|
readonly default: "Please use this device's biometric.";
|
|
195
196
|
readonly note: "Using other devices or apps may not work.";
|
|
196
197
|
};
|
|
198
|
+
readonly migration: {
|
|
199
|
+
readonly title: "Set up passkey for this site";
|
|
200
|
+
readonly description: "Your wallet was created on {{sourceDomain}}. To use it here, you need to set up a new passkey for this site.";
|
|
201
|
+
readonly descriptionGeneric: "Your wallet was created on a different site. To use it here, you need to set up a new passkey for this site.";
|
|
202
|
+
readonly currentDomain: "Current site";
|
|
203
|
+
readonly sourceDomain: "Original site";
|
|
204
|
+
readonly benefits: "Your wallet address and balance will remain the same.";
|
|
205
|
+
readonly cta: "Set up passkey";
|
|
206
|
+
readonly later: "Do it later";
|
|
207
|
+
readonly inProgress: "Setting up...";
|
|
208
|
+
readonly success: "Passkey set up successfully!";
|
|
209
|
+
readonly error: "Failed to set up passkey. Please try again.";
|
|
210
|
+
};
|
|
197
211
|
};
|
|
198
212
|
readonly success: {
|
|
199
213
|
readonly title: "Success!";
|
package/dist/index.js
CHANGED
|
@@ -570,6 +570,19 @@ var en = {
|
|
|
570
570
|
windows: "Please use your phone via QR code. (Windows Hello is not supported)",
|
|
571
571
|
default: "Please use this device's biometric.",
|
|
572
572
|
note: "Using other devices or apps may not work."
|
|
573
|
+
},
|
|
574
|
+
migration: {
|
|
575
|
+
title: "Set up passkey for this site",
|
|
576
|
+
description: "Your wallet was created on {{sourceDomain}}. To use it here, you need to set up a new passkey for this site.",
|
|
577
|
+
descriptionGeneric: "Your wallet was created on a different site. To use it here, you need to set up a new passkey for this site.",
|
|
578
|
+
currentDomain: "Current site",
|
|
579
|
+
sourceDomain: "Original site",
|
|
580
|
+
benefits: "Your wallet address and balance will remain the same.",
|
|
581
|
+
cta: "Set up passkey",
|
|
582
|
+
later: "Do it later",
|
|
583
|
+
inProgress: "Setting up...",
|
|
584
|
+
success: "Passkey set up successfully!",
|
|
585
|
+
error: "Failed to set up passkey. Please try again."
|
|
573
586
|
}
|
|
574
587
|
},
|
|
575
588
|
success: {
|
|
@@ -799,6 +812,19 @@ var ko = {
|
|
|
799
812
|
windows: "QR \uCF54\uB4DC\uB85C \uD734\uB300\uD3F0\uC744 \uC0AC\uC6A9\uD574\uC8FC\uC138\uC694. (Windows Hello\uB294 \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4)",
|
|
800
813
|
default: "\uC774 \uAE30\uAE30\uC758 \uC0DD\uCCB4 \uC778\uC99D\uC744 \uC0AC\uC6A9\uD574\uC8FC\uC138\uC694.",
|
|
801
814
|
note: "\uB2E4\uB978 \uAE30\uAE30\uB098 \uC571 \uC0AC\uC6A9 \uC2DC \uB3D9\uC791\uD558\uC9C0 \uC54A\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4."
|
|
815
|
+
},
|
|
816
|
+
migration: {
|
|
817
|
+
title: "\uC774 \uC0AC\uC774\uD2B8\uC6A9 \uD328\uC2A4\uD0A4 \uC124\uC815",
|
|
818
|
+
description: "\uC9C0\uAC11\uC774 {{sourceDomain}}\uC5D0\uC11C \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC774 \uC0AC\uC774\uD2B8\uC5D0\uC11C \uC0AC\uC6A9\uD558\uB824\uBA74 \uC0C8 \uD328\uC2A4\uD0A4\uB97C \uC124\uC815\uD574\uC57C \uD569\uB2C8\uB2E4.",
|
|
819
|
+
descriptionGeneric: "\uC9C0\uAC11\uC774 \uB2E4\uB978 \uC0AC\uC774\uD2B8\uC5D0\uC11C \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC774 \uC0AC\uC774\uD2B8\uC5D0\uC11C \uC0AC\uC6A9\uD558\uB824\uBA74 \uC0C8 \uD328\uC2A4\uD0A4\uB97C \uC124\uC815\uD574\uC57C \uD569\uB2C8\uB2E4.",
|
|
820
|
+
currentDomain: "\uD604\uC7AC \uC0AC\uC774\uD2B8",
|
|
821
|
+
sourceDomain: "\uC6D0\uBCF8 \uC0AC\uC774\uD2B8",
|
|
822
|
+
benefits: "\uC9C0\uAC11 \uC8FC\uC18C\uC640 \uC794\uC561\uC740 \uADF8\uB300\uB85C \uC720\uC9C0\uB429\uB2C8\uB2E4.",
|
|
823
|
+
cta: "\uD328\uC2A4\uD0A4 \uC124\uC815\uD558\uAE30",
|
|
824
|
+
later: "\uB098\uC911\uC5D0 \uD558\uAE30",
|
|
825
|
+
inProgress: "\uC124\uC815 \uC911...",
|
|
826
|
+
success: "\uD328\uC2A4\uD0A4 \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!",
|
|
827
|
+
error: "\uD328\uC2A4\uD0A4 \uC124\uC815\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694."
|
|
802
828
|
}
|
|
803
829
|
},
|
|
804
830
|
success: {
|
|
@@ -1858,6 +1884,84 @@ function PasskeyCompatibilityScreen({
|
|
|
1858
1884
|
] })
|
|
1859
1885
|
] });
|
|
1860
1886
|
}
|
|
1887
|
+
function PasskeyMigrationView({
|
|
1888
|
+
sourcePasskey,
|
|
1889
|
+
currentDomain,
|
|
1890
|
+
onMigrate,
|
|
1891
|
+
onSkip,
|
|
1892
|
+
onError,
|
|
1893
|
+
isOpen = true,
|
|
1894
|
+
wrapInModal = true
|
|
1895
|
+
}) {
|
|
1896
|
+
const { t } = useI18n();
|
|
1897
|
+
const [isMigrating, setIsMigrating] = useState(false);
|
|
1898
|
+
const [error, setError] = useState(null);
|
|
1899
|
+
const biometricType = getBiometricType();
|
|
1900
|
+
const handleMigrate = async () => {
|
|
1901
|
+
try {
|
|
1902
|
+
setIsMigrating(true);
|
|
1903
|
+
setError(null);
|
|
1904
|
+
await onMigrate();
|
|
1905
|
+
} catch (err) {
|
|
1906
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1907
|
+
setError(t("passkey.migration.error"));
|
|
1908
|
+
if (onError) {
|
|
1909
|
+
onError(err instanceof Error ? err : new Error(errorMessage));
|
|
1910
|
+
}
|
|
1911
|
+
} finally {
|
|
1912
|
+
setIsMigrating(false);
|
|
1913
|
+
}
|
|
1914
|
+
};
|
|
1915
|
+
const content = /* @__PURE__ */ jsxs("div", { children: [
|
|
1916
|
+
/* @__PURE__ */ jsx("p", { className: "volr:text-xl volr:font-semibold volr:mb-4", children: t("passkey.migration.title") }),
|
|
1917
|
+
/* @__PURE__ */ jsx("div", { className: "volr:my-6 volr:flex volr:justify-center", children: /* @__PURE__ */ jsx(BiometricIcon, { type: biometricType, size: 48 }) }),
|
|
1918
|
+
/* @__PURE__ */ jsx("p", { className: "volr:text-sm volr:mb-4 volr:text-center volr-text-secondary", children: sourcePasskey.rpId ? t("passkey.migration.description").replace(
|
|
1919
|
+
"{{sourceDomain}}",
|
|
1920
|
+
sourcePasskey.rpId
|
|
1921
|
+
) : t("passkey.migration.descriptionGeneric") }),
|
|
1922
|
+
/* @__PURE__ */ jsxs("div", { className: "volr:mb-4 volr:p-3 volr:rounded-lg volr:border volr:border-slate-200 volr:bg-slate-50", children: [
|
|
1923
|
+
/* @__PURE__ */ jsxs("div", { className: "volr:flex volr:justify-between volr:items-center volr:text-sm volr:mb-2", children: [
|
|
1924
|
+
/* @__PURE__ */ jsx("span", { className: "volr-text-secondary", children: t("passkey.migration.sourceDomain") }),
|
|
1925
|
+
/* @__PURE__ */ jsx("span", { className: "volr:font-mono volr:text-xs", children: sourcePasskey.rpId })
|
|
1926
|
+
] }),
|
|
1927
|
+
/* @__PURE__ */ jsxs("div", { className: "volr:flex volr:justify-between volr:items-center volr:text-sm", children: [
|
|
1928
|
+
/* @__PURE__ */ jsx("span", { className: "volr-text-secondary", children: t("passkey.migration.currentDomain") }),
|
|
1929
|
+
/* @__PURE__ */ jsx("span", { className: "volr:font-mono volr:text-xs", children: currentDomain })
|
|
1930
|
+
] })
|
|
1931
|
+
] }),
|
|
1932
|
+
/* @__PURE__ */ jsx("div", { className: "volr:mb-6 volr:p-3 volr:rounded-lg volr-hint", children: /* @__PURE__ */ jsxs("p", { className: "volr:text-sm volr:flex volr:items-start volr:gap-2", children: [
|
|
1933
|
+
/* @__PURE__ */ jsx("span", { className: "volr:text-base", children: "\u2713" }),
|
|
1934
|
+
/* @__PURE__ */ jsx("span", { children: t("passkey.migration.benefits") })
|
|
1935
|
+
] }) }),
|
|
1936
|
+
error && /* @__PURE__ */ jsx("div", { className: "volr:mb-4 volr:p-3 volr:rounded-lg volr:border volr:text-sm volr:text-left volr-error", children: /* @__PURE__ */ jsx("span", { children: error }) }),
|
|
1937
|
+
/* @__PURE__ */ jsxs("div", { className: "volr:flex volr:flex-col volr:gap-3", children: [
|
|
1938
|
+
/* @__PURE__ */ jsx(
|
|
1939
|
+
Button,
|
|
1940
|
+
{
|
|
1941
|
+
variant: "primary",
|
|
1942
|
+
fullWidth: true,
|
|
1943
|
+
onClick: handleMigrate,
|
|
1944
|
+
disabled: isMigrating,
|
|
1945
|
+
children: isMigrating ? t("passkey.migration.inProgress") : t("passkey.migration.cta")
|
|
1946
|
+
}
|
|
1947
|
+
),
|
|
1948
|
+
onSkip && /* @__PURE__ */ jsx(
|
|
1949
|
+
Button,
|
|
1950
|
+
{
|
|
1951
|
+
variant: "ghost",
|
|
1952
|
+
fullWidth: true,
|
|
1953
|
+
onClick: onSkip,
|
|
1954
|
+
disabled: isMigrating,
|
|
1955
|
+
children: t("passkey.migration.later")
|
|
1956
|
+
}
|
|
1957
|
+
)
|
|
1958
|
+
] })
|
|
1959
|
+
] });
|
|
1960
|
+
if (!wrapInModal) {
|
|
1961
|
+
return content;
|
|
1962
|
+
}
|
|
1963
|
+
return /* @__PURE__ */ jsx(Modal, { open: isOpen, onOpenChange: (open) => !open && onSkip?.(), children: content });
|
|
1964
|
+
}
|
|
1861
1965
|
function PasskeyEnrollView({
|
|
1862
1966
|
onComplete,
|
|
1863
1967
|
onError,
|
|
@@ -1886,14 +1990,34 @@ function PasskeyEnrollView({
|
|
|
1886
1990
|
[compatibility.platform]
|
|
1887
1991
|
);
|
|
1888
1992
|
const hasPasskey = user?.keyStorageType === "passkey";
|
|
1993
|
+
const currentDomain = useMemo(() => {
|
|
1994
|
+
if (typeof window === "undefined") return "localhost";
|
|
1995
|
+
return window.location.hostname;
|
|
1996
|
+
}, []);
|
|
1997
|
+
const migrationInfo = useMemo(() => {
|
|
1998
|
+
if (!user?.registeredPasskeys || user.registeredPasskeys.length === 0) {
|
|
1999
|
+
return { needsMigration: false, sourcePasskey: null };
|
|
2000
|
+
}
|
|
2001
|
+
const hasPasskeyOnCurrentDomain = user.registeredPasskeys.some(
|
|
2002
|
+
(pk) => pk.rpId === currentDomain
|
|
2003
|
+
);
|
|
2004
|
+
if (hasPasskeyOnCurrentDomain) {
|
|
2005
|
+
return { needsMigration: false, sourcePasskey: null };
|
|
2006
|
+
}
|
|
2007
|
+
const sourcePasskey = user.registeredPasskeys[0];
|
|
2008
|
+
return { needsMigration: true, sourcePasskey };
|
|
2009
|
+
}, [user?.registeredPasskeys, currentDomain]);
|
|
1889
2010
|
useEffect(() => {
|
|
1890
2011
|
console.log("[PasskeyEnrollView] User state:", {
|
|
1891
2012
|
user,
|
|
1892
2013
|
keyStorageType: user?.keyStorageType,
|
|
1893
2014
|
evmAddress: user?.evmAddress,
|
|
1894
|
-
hasPasskey
|
|
2015
|
+
hasPasskey,
|
|
2016
|
+
registeredPasskeys: user?.registeredPasskeys,
|
|
2017
|
+
currentDomain,
|
|
2018
|
+
migrationInfo
|
|
1895
2019
|
});
|
|
1896
|
-
}, [user, hasPasskey]);
|
|
2020
|
+
}, [user, hasPasskey, currentDomain, migrationInfo]);
|
|
1897
2021
|
useEffect(() => {
|
|
1898
2022
|
if (hasPasskey && !user?.evmAddress && !isRefreshing) {
|
|
1899
2023
|
const refreshUserData = async () => {
|
|
@@ -2031,6 +2155,23 @@ function PasskeyEnrollView({
|
|
|
2031
2155
|
}
|
|
2032
2156
|
return /* @__PURE__ */ jsx(Modal, { open: isOpen, onOpenChange: (open) => !open && onLogout?.(), children: compatibilityContent });
|
|
2033
2157
|
}
|
|
2158
|
+
if (migrationInfo.needsMigration && migrationInfo.sourcePasskey) {
|
|
2159
|
+
const handleMigration = async () => {
|
|
2160
|
+
await handleEnroll();
|
|
2161
|
+
};
|
|
2162
|
+
return /* @__PURE__ */ jsx(
|
|
2163
|
+
PasskeyMigrationView,
|
|
2164
|
+
{
|
|
2165
|
+
sourcePasskey: migrationInfo.sourcePasskey,
|
|
2166
|
+
currentDomain,
|
|
2167
|
+
onMigrate: handleMigration,
|
|
2168
|
+
onSkip: handleLogout,
|
|
2169
|
+
onError,
|
|
2170
|
+
isOpen,
|
|
2171
|
+
wrapInModal
|
|
2172
|
+
}
|
|
2173
|
+
);
|
|
2174
|
+
}
|
|
2034
2175
|
if (hasPasskey) {
|
|
2035
2176
|
const handleClose = () => {
|
|
2036
2177
|
if (onClose) {
|
|
@@ -2944,6 +3085,7 @@ function SiweLoginScreen({
|
|
|
2944
3085
|
}
|
|
2945
3086
|
function SigninModal({ isOpen, onClose, onError }) {
|
|
2946
3087
|
const { logout, user } = useVolrContext();
|
|
3088
|
+
const { client } = useInternalAuth();
|
|
2947
3089
|
const { appName, branding } = useVolrUI();
|
|
2948
3090
|
const { requestEmailCode, verifyEmailCode, handleSocialLogin } = useVolrLogin();
|
|
2949
3091
|
const [currentScreen, setCurrentScreen] = useState("method-select");
|
|
@@ -2976,13 +3118,43 @@ function SigninModal({ isOpen, onClose, onError }) {
|
|
|
2976
3118
|
const handleCodeSubmit = async (code) => {
|
|
2977
3119
|
const result = await verifyEmailCode(email, code);
|
|
2978
3120
|
if (result.keyStorageType) {
|
|
3121
|
+
try {
|
|
3122
|
+
const refreshed = await client.post(
|
|
3123
|
+
"/auth/refresh",
|
|
3124
|
+
{}
|
|
3125
|
+
);
|
|
3126
|
+
const currentRpId = typeof window !== "undefined" ? window.location.hostname : "localhost";
|
|
3127
|
+
const passkeys = refreshed.user?.registeredPasskeys ?? [];
|
|
3128
|
+
const hasCurrent = passkeys.some((p) => p.rpId === currentRpId);
|
|
3129
|
+
const needsMigration = passkeys.length > 0 && !hasCurrent;
|
|
3130
|
+
if (result.keyStorageType === "passkey" && needsMigration) {
|
|
3131
|
+
setCurrentScreen("passkey-setup");
|
|
3132
|
+
return;
|
|
3133
|
+
}
|
|
3134
|
+
} catch {
|
|
3135
|
+
}
|
|
2979
3136
|
onClose();
|
|
2980
3137
|
return;
|
|
2981
3138
|
}
|
|
2982
3139
|
setCurrentScreen("passkey-setup");
|
|
2983
3140
|
};
|
|
2984
|
-
const handleSiweSuccess = (data) => {
|
|
3141
|
+
const handleSiweSuccess = async (data) => {
|
|
2985
3142
|
if (data.keyStorageType) {
|
|
3143
|
+
try {
|
|
3144
|
+
const refreshed = await client.post(
|
|
3145
|
+
"/auth/refresh",
|
|
3146
|
+
{}
|
|
3147
|
+
);
|
|
3148
|
+
const currentRpId = typeof window !== "undefined" ? window.location.hostname : "localhost";
|
|
3149
|
+
const passkeys = refreshed.user?.registeredPasskeys ?? [];
|
|
3150
|
+
const hasCurrent = passkeys.some((p) => p.rpId === currentRpId);
|
|
3151
|
+
const needsMigration = passkeys.length > 0 && !hasCurrent;
|
|
3152
|
+
if (data.keyStorageType === "passkey" && needsMigration) {
|
|
3153
|
+
setCurrentScreen("passkey-setup");
|
|
3154
|
+
return;
|
|
3155
|
+
}
|
|
3156
|
+
} catch {
|
|
3157
|
+
}
|
|
2986
3158
|
onClose();
|
|
2987
3159
|
return;
|
|
2988
3160
|
}
|
|
@@ -6820,8 +6992,16 @@ function OAuthCallbackHandler({
|
|
|
6820
6992
|
const { isLoading, error } = useVolrAuthCallback({
|
|
6821
6993
|
onSuccess: (resultUser) => {
|
|
6822
6994
|
console.log("[OAuthCallbackHandler] Login successful:", resultUser.email);
|
|
6995
|
+
const currentRpId = typeof window !== "undefined" ? window.location.hostname : "localhost";
|
|
6996
|
+
const passkeys = resultUser.registeredPasskeys ?? [];
|
|
6997
|
+
const hasCurrent = passkeys.some((p) => p.rpId === currentRpId);
|
|
6998
|
+
const needsMigration = passkeys.length > 0 && !hasCurrent;
|
|
6823
6999
|
if (!resultUser.keyStorageType) {
|
|
6824
7000
|
onShowOnboarding();
|
|
7001
|
+
return;
|
|
7002
|
+
}
|
|
7003
|
+
if (resultUser.keyStorageType === "passkey" && needsMigration) {
|
|
7004
|
+
onShowOnboarding();
|
|
6825
7005
|
}
|
|
6826
7006
|
},
|
|
6827
7007
|
onError: (err) => {
|