@volr/react 0.1.130 → 0.1.132
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 +112 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +112 -53
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -9774,10 +9774,42 @@ function useSessionSync({
|
|
|
9774
9774
|
}
|
|
9775
9775
|
|
|
9776
9776
|
// src/config/webauthn.ts
|
|
9777
|
+
function isWindows() {
|
|
9778
|
+
if (typeof navigator === "undefined") return false;
|
|
9779
|
+
const platform = navigator.platform || "";
|
|
9780
|
+
return /Win/.test(platform);
|
|
9781
|
+
}
|
|
9782
|
+
function isLinux() {
|
|
9783
|
+
if (typeof navigator === "undefined") return false;
|
|
9784
|
+
const platform = navigator.platform || "";
|
|
9785
|
+
const ua = navigator.userAgent;
|
|
9786
|
+
return /Linux/.test(platform) && !/CrOS/.test(ua) && !/Android/.test(ua);
|
|
9787
|
+
}
|
|
9788
|
+
function shouldForceCrossDevice() {
|
|
9789
|
+
return isWindows() || isLinux();
|
|
9790
|
+
}
|
|
9777
9791
|
var AUTHENTICATOR_SELECTION = {
|
|
9778
9792
|
userVerification: "required",
|
|
9779
9793
|
residentKey: "required"
|
|
9780
9794
|
};
|
|
9795
|
+
var AUTHENTICATOR_SELECTION_CROSS_DEVICE = {
|
|
9796
|
+
userVerification: "required",
|
|
9797
|
+
residentKey: "required",
|
|
9798
|
+
authenticatorAttachment: "cross-platform"
|
|
9799
|
+
};
|
|
9800
|
+
function getAuthenticatorSelection() {
|
|
9801
|
+
if (shouldForceCrossDevice()) {
|
|
9802
|
+
return AUTHENTICATOR_SELECTION_CROSS_DEVICE;
|
|
9803
|
+
}
|
|
9804
|
+
return AUTHENTICATOR_SELECTION;
|
|
9805
|
+
}
|
|
9806
|
+
function getWebAuthnHints() {
|
|
9807
|
+
if (shouldForceCrossDevice()) {
|
|
9808
|
+
return ["hybrid"];
|
|
9809
|
+
}
|
|
9810
|
+
return void 0;
|
|
9811
|
+
}
|
|
9812
|
+
var AUTHENTICATOR_TRANSPORTS = ["internal", "hybrid"];
|
|
9781
9813
|
var CREDENTIAL_MEDIATION = "required";
|
|
9782
9814
|
var USER_VERIFICATION = "required";
|
|
9783
9815
|
var WEBAUTHN_TIMEOUT = 6e4;
|
|
@@ -9945,50 +9977,51 @@ function createPasskeyAdapter(options = {}) {
|
|
|
9945
9977
|
return { r, s };
|
|
9946
9978
|
},
|
|
9947
9979
|
async authenticate(prfInput) {
|
|
9948
|
-
|
|
9949
|
-
|
|
9950
|
-
|
|
9951
|
-
)
|
|
9952
|
-
|
|
9953
|
-
|
|
9954
|
-
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
|
|
9958
|
-
|
|
9959
|
-
|
|
9960
|
-
|
|
9961
|
-
);
|
|
9962
|
-
|
|
9963
|
-
|
|
9964
|
-
|
|
9965
|
-
|
|
9966
|
-
|
|
9967
|
-
|
|
9968
|
-
|
|
9969
|
-
}
|
|
9970
|
-
const credIdBytes = new Uint8Array(
|
|
9971
|
-
hexPairs.map((byte) => parseInt(byte, 16))
|
|
9972
|
-
);
|
|
9973
|
-
const reconvertedHex = Array.from(credIdBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
9974
|
-
if (reconvertedHex.toLowerCase() !== normalizedHex.toLowerCase()) {
|
|
9975
|
-
throw new Error(
|
|
9976
|
-
`[PasskeyAdapter] credentialId conversion failed. Original: ${normalizedHex}, Reconverted: ${reconvertedHex}`
|
|
9980
|
+
const allowCredentials = [];
|
|
9981
|
+
if (prfInput.credentialId) {
|
|
9982
|
+
const hexString = prfInput.credentialId.startsWith("0x") ? prfInput.credentialId.slice(2) : prfInput.credentialId;
|
|
9983
|
+
if (!/^[0-9a-fA-F]+$/.test(hexString)) {
|
|
9984
|
+
console.error(
|
|
9985
|
+
"[PasskeyAdapter] Invalid credentialId format (not hex):",
|
|
9986
|
+
prfInput.credentialId
|
|
9987
|
+
);
|
|
9988
|
+
throw new Error(
|
|
9989
|
+
`[PasskeyAdapter] Invalid credentialId format. Expected hex string, got: ${prfInput.credentialId}`
|
|
9990
|
+
);
|
|
9991
|
+
}
|
|
9992
|
+
const normalizedHex = hexString.length % 2 === 0 ? hexString : "0" + hexString;
|
|
9993
|
+
const hexPairs = normalizedHex.match(/.{1,2}/g);
|
|
9994
|
+
if (!hexPairs) {
|
|
9995
|
+
throw new Error(
|
|
9996
|
+
`[PasskeyAdapter] Failed to parse hex string: ${normalizedHex}`
|
|
9997
|
+
);
|
|
9998
|
+
}
|
|
9999
|
+
const credIdBytes = new Uint8Array(
|
|
10000
|
+
hexPairs.map((byte) => parseInt(byte, 16))
|
|
9977
10001
|
);
|
|
9978
|
-
|
|
9979
|
-
|
|
9980
|
-
|
|
9981
|
-
|
|
9982
|
-
|
|
10002
|
+
const reconvertedHex = Array.from(credIdBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
10003
|
+
if (reconvertedHex.toLowerCase() !== normalizedHex.toLowerCase()) {
|
|
10004
|
+
throw new Error(
|
|
10005
|
+
`[PasskeyAdapter] credentialId conversion failed. Original: ${normalizedHex}, Reconverted: ${reconvertedHex}`
|
|
10006
|
+
);
|
|
9983
10007
|
}
|
|
9984
|
-
|
|
10008
|
+
const transports = shouldForceCrossDevice() ? ["hybrid"] : AUTHENTICATOR_TRANSPORTS;
|
|
10009
|
+
allowCredentials.push({
|
|
10010
|
+
id: credIdBytes,
|
|
10011
|
+
type: "public-key",
|
|
10012
|
+
transports
|
|
10013
|
+
});
|
|
10014
|
+
}
|
|
10015
|
+
const hints = getWebAuthnHints();
|
|
9985
10016
|
return withWebAuthnLock(async () => {
|
|
9986
10017
|
let credential = null;
|
|
9987
10018
|
try {
|
|
9988
|
-
|
|
10019
|
+
const requestOptions = {
|
|
9989
10020
|
publicKey: {
|
|
9990
10021
|
challenge: crypto.getRandomValues(new Uint8Array(32)),
|
|
9991
10022
|
rpId,
|
|
10023
|
+
// If allowCredentials is empty, the browser will use discoverable credentials.
|
|
10024
|
+
// This enables the account chooser and cross-device (hybrid) QR flows.
|
|
9992
10025
|
allowCredentials,
|
|
9993
10026
|
userVerification: USER_VERIFICATION,
|
|
9994
10027
|
// Shared constant
|
|
@@ -9998,11 +10031,15 @@ function createPasskeyAdapter(options = {}) {
|
|
|
9998
10031
|
first: prfInput.salt.buffer
|
|
9999
10032
|
}
|
|
10000
10033
|
}
|
|
10001
|
-
}
|
|
10034
|
+
},
|
|
10035
|
+
// Chrome 128+ supports hints to prioritize certain authenticator types
|
|
10036
|
+
// On Windows/Linux, this prioritizes QR code over USB security key prompt
|
|
10037
|
+
...hints && { hints }
|
|
10002
10038
|
},
|
|
10003
10039
|
mediation: CREDENTIAL_MEDIATION
|
|
10004
10040
|
// Use shared constant
|
|
10005
|
-
}
|
|
10041
|
+
};
|
|
10042
|
+
credential = await navigator.credentials.get(requestOptions);
|
|
10006
10043
|
} catch (error) {
|
|
10007
10044
|
console.error("[PasskeyAdapter] WebAuthn get() failed:", error);
|
|
10008
10045
|
console.error("[PasskeyAdapter] Error name:", error?.name);
|
|
@@ -10388,6 +10425,10 @@ function VolrProvider({ config, children }) {
|
|
|
10388
10425
|
const [isLoading, setIsLoading] = react.useState(true);
|
|
10389
10426
|
const [error, setError] = react.useState(null);
|
|
10390
10427
|
const [chainId] = react.useState(config.defaultChainId);
|
|
10428
|
+
const userRef = react.useRef(null);
|
|
10429
|
+
react.useEffect(() => {
|
|
10430
|
+
userRef.current = user;
|
|
10431
|
+
}, [user]);
|
|
10391
10432
|
const [accessToken, setAccessTokenState] = react.useState(() => {
|
|
10392
10433
|
return client.getAccessToken();
|
|
10393
10434
|
});
|
|
@@ -10408,10 +10449,11 @@ function VolrProvider({ config, children }) {
|
|
|
10408
10449
|
setError(null);
|
|
10409
10450
|
const keyStorageType = newProvider.keyStorageType;
|
|
10410
10451
|
setProviderState(newProvider);
|
|
10411
|
-
const
|
|
10452
|
+
const currentUser = userRef.current;
|
|
10453
|
+
const userHasCompleteData = currentUser?.keyStorageType === "passkey" && currentUser?.blobUrl && currentUser?.prfInput && currentUser?.id;
|
|
10412
10454
|
if (userHasCompleteData) {
|
|
10413
10455
|
console.log("[Provider] setProvider: User data already complete, skipping refresh");
|
|
10414
|
-
if (
|
|
10456
|
+
if (currentUser?.keyStorageType !== keyStorageType) {
|
|
10415
10457
|
setUser((prev) => ({ ...prev, keyStorageType }));
|
|
10416
10458
|
}
|
|
10417
10459
|
} else {
|
|
@@ -10443,7 +10485,7 @@ function VolrProvider({ config, children }) {
|
|
|
10443
10485
|
throw error2;
|
|
10444
10486
|
}
|
|
10445
10487
|
},
|
|
10446
|
-
[client,
|
|
10488
|
+
[client, syncRef]
|
|
10447
10489
|
);
|
|
10448
10490
|
useAutoRecover({
|
|
10449
10491
|
client,
|
|
@@ -18503,26 +18545,28 @@ function createGetRpcUrl(deps) {
|
|
|
18503
18545
|
};
|
|
18504
18546
|
}
|
|
18505
18547
|
function createGetNetworkInfo(deps) {
|
|
18506
|
-
const { client } = deps;
|
|
18548
|
+
const { client, rpcOverrides } = deps;
|
|
18507
18549
|
return async function getNetworkInfo(chainId, includeRpcUrl = false) {
|
|
18550
|
+
const overrideUrl = rpcOverrides?.[chainId.toString()];
|
|
18508
18551
|
const cached = networkCache.get(chainId);
|
|
18509
18552
|
if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
|
|
18510
18553
|
return {
|
|
18511
18554
|
name: cached.name || `Chain ${chainId}`,
|
|
18512
|
-
rpcUrl: includeRpcUrl ? cached.rpcUrl : void 0,
|
|
18555
|
+
rpcUrl: includeRpcUrl ? overrideUrl ?? cached.rpcUrl : void 0,
|
|
18513
18556
|
invokerAddress: cached.invokerAddress
|
|
18514
18557
|
};
|
|
18515
18558
|
}
|
|
18516
18559
|
const response = await client.get(`/networks/${chainId}${includeRpcUrl ? "?includeRpcUrl=true" : ""}`);
|
|
18517
18560
|
networkCache.set(chainId, {
|
|
18518
18561
|
name: response.name,
|
|
18519
|
-
rpcUrl
|
|
18562
|
+
// If an override exists, cache it as the effective rpcUrl for this chainId
|
|
18563
|
+
rpcUrl: overrideUrl ?? response.rpcUrl,
|
|
18520
18564
|
invokerAddress: response.invokerAddress,
|
|
18521
18565
|
timestamp: Date.now()
|
|
18522
18566
|
});
|
|
18523
18567
|
return {
|
|
18524
18568
|
name: response.name,
|
|
18525
|
-
rpcUrl: includeRpcUrl ? response.rpcUrl : void 0,
|
|
18569
|
+
rpcUrl: includeRpcUrl ? overrideUrl ?? response.rpcUrl : void 0,
|
|
18526
18570
|
invokerAddress: response.invokerAddress
|
|
18527
18571
|
};
|
|
18528
18572
|
};
|
|
@@ -18561,7 +18605,7 @@ function validateCalls2(calls) {
|
|
|
18561
18605
|
|
|
18562
18606
|
// src/wallet/normalize.ts
|
|
18563
18607
|
function normalizeCall(call2) {
|
|
18564
|
-
const normalizedTarget = getAddress(call2.target);
|
|
18608
|
+
const normalizedTarget = normalizeHex(getAddress(call2.target));
|
|
18565
18609
|
const normalizedData = normalizeHex(call2.data);
|
|
18566
18610
|
const value = call2.value ?? 0n;
|
|
18567
18611
|
const gasLimit = call2.gasLimit ?? 0n;
|
|
@@ -18797,7 +18841,7 @@ async function sendCalls(args) {
|
|
|
18797
18841
|
if (chainId === 0) {
|
|
18798
18842
|
throw new Error("chainId cannot be 0");
|
|
18799
18843
|
}
|
|
18800
|
-
const normalizedFrom = from14;
|
|
18844
|
+
const normalizedFrom = normalizeHex(from14);
|
|
18801
18845
|
const normalizedCalls = normalizeCalls(calls);
|
|
18802
18846
|
validateCalls2(normalizedCalls);
|
|
18803
18847
|
if (!deps.provider && deps.user?.keyStorageType !== "passkey") {
|
|
@@ -18861,7 +18905,7 @@ async function sendCalls(args) {
|
|
|
18861
18905
|
if (!quotePolicyId) {
|
|
18862
18906
|
throw new Error("Backend did not return policyId in precheck response");
|
|
18863
18907
|
}
|
|
18864
|
-
const projectPolicyId = quotePolicyId;
|
|
18908
|
+
const projectPolicyId = normalizeHex(quotePolicyId);
|
|
18865
18909
|
validatePolicyId2(projectPolicyId);
|
|
18866
18910
|
const tempAuth = buildTempAuth({
|
|
18867
18911
|
chainId,
|
|
@@ -19676,6 +19720,8 @@ async function enrollPasskey(params) {
|
|
|
19676
19720
|
};
|
|
19677
19721
|
const prfSalt = sdkCore.deriveWrapKey(tempPrfInput);
|
|
19678
19722
|
const displayName = buildDisplayName(userEmail, userEvmAddress, userId);
|
|
19723
|
+
const authenticatorSelection = getAuthenticatorSelection();
|
|
19724
|
+
const hints = getWebAuthnHints();
|
|
19679
19725
|
const publicKeyCredentialCreationOptions = {
|
|
19680
19726
|
challenge: challenge2,
|
|
19681
19727
|
rp: {
|
|
@@ -19688,7 +19734,7 @@ async function enrollPasskey(params) {
|
|
|
19688
19734
|
displayName
|
|
19689
19735
|
},
|
|
19690
19736
|
pubKeyCredParams: PUBKEY_CRED_PARAMS,
|
|
19691
|
-
authenticatorSelection
|
|
19737
|
+
authenticatorSelection,
|
|
19692
19738
|
timeout: WEBAUTHN_TIMEOUT,
|
|
19693
19739
|
attestation: ATTESTATION,
|
|
19694
19740
|
extensions: {
|
|
@@ -19697,7 +19743,10 @@ async function enrollPasskey(params) {
|
|
|
19697
19743
|
first: prfSalt.buffer
|
|
19698
19744
|
}
|
|
19699
19745
|
}
|
|
19700
|
-
}
|
|
19746
|
+
},
|
|
19747
|
+
// Chrome 128+ supports hints to prioritize certain authenticator types
|
|
19748
|
+
// On Windows/Linux, this prioritizes QR code over USB security key prompt
|
|
19749
|
+
...hints && { hints }
|
|
19701
19750
|
};
|
|
19702
19751
|
const credential = await navigator.credentials.create({
|
|
19703
19752
|
publicKey: publicKeyCredentialCreationOptions
|
|
@@ -20891,7 +20940,12 @@ function getPlatformHint(platform) {
|
|
|
20891
20940
|
case "Windows":
|
|
20892
20941
|
return {
|
|
20893
20942
|
hintKey: "passkey.hint.windows",
|
|
20894
|
-
noteKey: "passkey.hint.
|
|
20943
|
+
noteKey: "passkey.hint.windowsNote"
|
|
20944
|
+
};
|
|
20945
|
+
case "Linux":
|
|
20946
|
+
return {
|
|
20947
|
+
hintKey: "passkey.hint.linux",
|
|
20948
|
+
noteKey: "passkey.hint.windowsNote"
|
|
20895
20949
|
};
|
|
20896
20950
|
default:
|
|
20897
20951
|
return {
|
|
@@ -21085,6 +21139,8 @@ async function completeMigration(params) {
|
|
|
21085
21139
|
credentialId: tempCredentialId
|
|
21086
21140
|
};
|
|
21087
21141
|
const prfSalt = sdkCore.deriveWrapKey(tempPrfInput);
|
|
21142
|
+
const authenticatorSelection = getAuthenticatorSelection();
|
|
21143
|
+
const hints = getWebAuthnHints();
|
|
21088
21144
|
const publicKeyCredentialCreationOptions = {
|
|
21089
21145
|
challenge: challenge2,
|
|
21090
21146
|
rp: {
|
|
@@ -21097,7 +21153,7 @@ async function completeMigration(params) {
|
|
|
21097
21153
|
displayName
|
|
21098
21154
|
},
|
|
21099
21155
|
pubKeyCredParams: PUBKEY_CRED_PARAMS,
|
|
21100
|
-
authenticatorSelection
|
|
21156
|
+
authenticatorSelection,
|
|
21101
21157
|
timeout: WEBAUTHN_TIMEOUT,
|
|
21102
21158
|
attestation: ATTESTATION,
|
|
21103
21159
|
extensions: {
|
|
@@ -21106,7 +21162,10 @@ async function completeMigration(params) {
|
|
|
21106
21162
|
first: prfSalt.buffer
|
|
21107
21163
|
}
|
|
21108
21164
|
}
|
|
21109
|
-
}
|
|
21165
|
+
},
|
|
21166
|
+
// Chrome 128+ supports hints to prioritize certain authenticator types
|
|
21167
|
+
// On Windows/Linux, this prioritizes QR code over USB security key prompt
|
|
21168
|
+
...hints && { hints }
|
|
21110
21169
|
};
|
|
21111
21170
|
const credential = await navigator.credentials.create({
|
|
21112
21171
|
publicKey: publicKeyCredentialCreationOptions
|