@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.js
CHANGED
|
@@ -9750,10 +9750,42 @@ function useSessionSync({
|
|
|
9750
9750
|
}
|
|
9751
9751
|
|
|
9752
9752
|
// src/config/webauthn.ts
|
|
9753
|
+
function isWindows() {
|
|
9754
|
+
if (typeof navigator === "undefined") return false;
|
|
9755
|
+
const platform = navigator.platform || "";
|
|
9756
|
+
return /Win/.test(platform);
|
|
9757
|
+
}
|
|
9758
|
+
function isLinux() {
|
|
9759
|
+
if (typeof navigator === "undefined") return false;
|
|
9760
|
+
const platform = navigator.platform || "";
|
|
9761
|
+
const ua = navigator.userAgent;
|
|
9762
|
+
return /Linux/.test(platform) && !/CrOS/.test(ua) && !/Android/.test(ua);
|
|
9763
|
+
}
|
|
9764
|
+
function shouldForceCrossDevice() {
|
|
9765
|
+
return isWindows() || isLinux();
|
|
9766
|
+
}
|
|
9753
9767
|
var AUTHENTICATOR_SELECTION = {
|
|
9754
9768
|
userVerification: "required",
|
|
9755
9769
|
residentKey: "required"
|
|
9756
9770
|
};
|
|
9771
|
+
var AUTHENTICATOR_SELECTION_CROSS_DEVICE = {
|
|
9772
|
+
userVerification: "required",
|
|
9773
|
+
residentKey: "required",
|
|
9774
|
+
authenticatorAttachment: "cross-platform"
|
|
9775
|
+
};
|
|
9776
|
+
function getAuthenticatorSelection() {
|
|
9777
|
+
if (shouldForceCrossDevice()) {
|
|
9778
|
+
return AUTHENTICATOR_SELECTION_CROSS_DEVICE;
|
|
9779
|
+
}
|
|
9780
|
+
return AUTHENTICATOR_SELECTION;
|
|
9781
|
+
}
|
|
9782
|
+
function getWebAuthnHints() {
|
|
9783
|
+
if (shouldForceCrossDevice()) {
|
|
9784
|
+
return ["hybrid"];
|
|
9785
|
+
}
|
|
9786
|
+
return void 0;
|
|
9787
|
+
}
|
|
9788
|
+
var AUTHENTICATOR_TRANSPORTS = ["internal", "hybrid"];
|
|
9757
9789
|
var CREDENTIAL_MEDIATION = "required";
|
|
9758
9790
|
var USER_VERIFICATION = "required";
|
|
9759
9791
|
var WEBAUTHN_TIMEOUT = 6e4;
|
|
@@ -9921,50 +9953,51 @@ function createPasskeyAdapter(options = {}) {
|
|
|
9921
9953
|
return { r, s };
|
|
9922
9954
|
},
|
|
9923
9955
|
async authenticate(prfInput) {
|
|
9924
|
-
|
|
9925
|
-
|
|
9926
|
-
|
|
9927
|
-
)
|
|
9928
|
-
|
|
9929
|
-
|
|
9930
|
-
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
|
|
9937
|
-
);
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
9941
|
-
|
|
9942
|
-
|
|
9943
|
-
|
|
9944
|
-
|
|
9945
|
-
}
|
|
9946
|
-
const credIdBytes = new Uint8Array(
|
|
9947
|
-
hexPairs.map((byte) => parseInt(byte, 16))
|
|
9948
|
-
);
|
|
9949
|
-
const reconvertedHex = Array.from(credIdBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
9950
|
-
if (reconvertedHex.toLowerCase() !== normalizedHex.toLowerCase()) {
|
|
9951
|
-
throw new Error(
|
|
9952
|
-
`[PasskeyAdapter] credentialId conversion failed. Original: ${normalizedHex}, Reconverted: ${reconvertedHex}`
|
|
9956
|
+
const allowCredentials = [];
|
|
9957
|
+
if (prfInput.credentialId) {
|
|
9958
|
+
const hexString = prfInput.credentialId.startsWith("0x") ? prfInput.credentialId.slice(2) : prfInput.credentialId;
|
|
9959
|
+
if (!/^[0-9a-fA-F]+$/.test(hexString)) {
|
|
9960
|
+
console.error(
|
|
9961
|
+
"[PasskeyAdapter] Invalid credentialId format (not hex):",
|
|
9962
|
+
prfInput.credentialId
|
|
9963
|
+
);
|
|
9964
|
+
throw new Error(
|
|
9965
|
+
`[PasskeyAdapter] Invalid credentialId format. Expected hex string, got: ${prfInput.credentialId}`
|
|
9966
|
+
);
|
|
9967
|
+
}
|
|
9968
|
+
const normalizedHex = hexString.length % 2 === 0 ? hexString : "0" + hexString;
|
|
9969
|
+
const hexPairs = normalizedHex.match(/.{1,2}/g);
|
|
9970
|
+
if (!hexPairs) {
|
|
9971
|
+
throw new Error(
|
|
9972
|
+
`[PasskeyAdapter] Failed to parse hex string: ${normalizedHex}`
|
|
9973
|
+
);
|
|
9974
|
+
}
|
|
9975
|
+
const credIdBytes = new Uint8Array(
|
|
9976
|
+
hexPairs.map((byte) => parseInt(byte, 16))
|
|
9953
9977
|
);
|
|
9954
|
-
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
|
|
9958
|
-
|
|
9978
|
+
const reconvertedHex = Array.from(credIdBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
9979
|
+
if (reconvertedHex.toLowerCase() !== normalizedHex.toLowerCase()) {
|
|
9980
|
+
throw new Error(
|
|
9981
|
+
`[PasskeyAdapter] credentialId conversion failed. Original: ${normalizedHex}, Reconverted: ${reconvertedHex}`
|
|
9982
|
+
);
|
|
9959
9983
|
}
|
|
9960
|
-
|
|
9984
|
+
const transports = shouldForceCrossDevice() ? ["hybrid"] : AUTHENTICATOR_TRANSPORTS;
|
|
9985
|
+
allowCredentials.push({
|
|
9986
|
+
id: credIdBytes,
|
|
9987
|
+
type: "public-key",
|
|
9988
|
+
transports
|
|
9989
|
+
});
|
|
9990
|
+
}
|
|
9991
|
+
const hints = getWebAuthnHints();
|
|
9961
9992
|
return withWebAuthnLock(async () => {
|
|
9962
9993
|
let credential = null;
|
|
9963
9994
|
try {
|
|
9964
|
-
|
|
9995
|
+
const requestOptions = {
|
|
9965
9996
|
publicKey: {
|
|
9966
9997
|
challenge: crypto.getRandomValues(new Uint8Array(32)),
|
|
9967
9998
|
rpId,
|
|
9999
|
+
// If allowCredentials is empty, the browser will use discoverable credentials.
|
|
10000
|
+
// This enables the account chooser and cross-device (hybrid) QR flows.
|
|
9968
10001
|
allowCredentials,
|
|
9969
10002
|
userVerification: USER_VERIFICATION,
|
|
9970
10003
|
// Shared constant
|
|
@@ -9974,11 +10007,15 @@ function createPasskeyAdapter(options = {}) {
|
|
|
9974
10007
|
first: prfInput.salt.buffer
|
|
9975
10008
|
}
|
|
9976
10009
|
}
|
|
9977
|
-
}
|
|
10010
|
+
},
|
|
10011
|
+
// Chrome 128+ supports hints to prioritize certain authenticator types
|
|
10012
|
+
// On Windows/Linux, this prioritizes QR code over USB security key prompt
|
|
10013
|
+
...hints && { hints }
|
|
9978
10014
|
},
|
|
9979
10015
|
mediation: CREDENTIAL_MEDIATION
|
|
9980
10016
|
// Use shared constant
|
|
9981
|
-
}
|
|
10017
|
+
};
|
|
10018
|
+
credential = await navigator.credentials.get(requestOptions);
|
|
9982
10019
|
} catch (error) {
|
|
9983
10020
|
console.error("[PasskeyAdapter] WebAuthn get() failed:", error);
|
|
9984
10021
|
console.error("[PasskeyAdapter] Error name:", error?.name);
|
|
@@ -10364,6 +10401,10 @@ function VolrProvider({ config, children }) {
|
|
|
10364
10401
|
const [isLoading, setIsLoading] = useState(true);
|
|
10365
10402
|
const [error, setError] = useState(null);
|
|
10366
10403
|
const [chainId] = useState(config.defaultChainId);
|
|
10404
|
+
const userRef = useRef(null);
|
|
10405
|
+
useEffect(() => {
|
|
10406
|
+
userRef.current = user;
|
|
10407
|
+
}, [user]);
|
|
10367
10408
|
const [accessToken, setAccessTokenState] = useState(() => {
|
|
10368
10409
|
return client.getAccessToken();
|
|
10369
10410
|
});
|
|
@@ -10384,10 +10425,11 @@ function VolrProvider({ config, children }) {
|
|
|
10384
10425
|
setError(null);
|
|
10385
10426
|
const keyStorageType = newProvider.keyStorageType;
|
|
10386
10427
|
setProviderState(newProvider);
|
|
10387
|
-
const
|
|
10428
|
+
const currentUser = userRef.current;
|
|
10429
|
+
const userHasCompleteData = currentUser?.keyStorageType === "passkey" && currentUser?.blobUrl && currentUser?.prfInput && currentUser?.id;
|
|
10388
10430
|
if (userHasCompleteData) {
|
|
10389
10431
|
console.log("[Provider] setProvider: User data already complete, skipping refresh");
|
|
10390
|
-
if (
|
|
10432
|
+
if (currentUser?.keyStorageType !== keyStorageType) {
|
|
10391
10433
|
setUser((prev) => ({ ...prev, keyStorageType }));
|
|
10392
10434
|
}
|
|
10393
10435
|
} else {
|
|
@@ -10419,7 +10461,7 @@ function VolrProvider({ config, children }) {
|
|
|
10419
10461
|
throw error2;
|
|
10420
10462
|
}
|
|
10421
10463
|
},
|
|
10422
|
-
[client,
|
|
10464
|
+
[client, syncRef]
|
|
10423
10465
|
);
|
|
10424
10466
|
useAutoRecover({
|
|
10425
10467
|
client,
|
|
@@ -18479,26 +18521,28 @@ function createGetRpcUrl(deps) {
|
|
|
18479
18521
|
};
|
|
18480
18522
|
}
|
|
18481
18523
|
function createGetNetworkInfo(deps) {
|
|
18482
|
-
const { client } = deps;
|
|
18524
|
+
const { client, rpcOverrides } = deps;
|
|
18483
18525
|
return async function getNetworkInfo(chainId, includeRpcUrl = false) {
|
|
18526
|
+
const overrideUrl = rpcOverrides?.[chainId.toString()];
|
|
18484
18527
|
const cached = networkCache.get(chainId);
|
|
18485
18528
|
if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
|
|
18486
18529
|
return {
|
|
18487
18530
|
name: cached.name || `Chain ${chainId}`,
|
|
18488
|
-
rpcUrl: includeRpcUrl ? cached.rpcUrl : void 0,
|
|
18531
|
+
rpcUrl: includeRpcUrl ? overrideUrl ?? cached.rpcUrl : void 0,
|
|
18489
18532
|
invokerAddress: cached.invokerAddress
|
|
18490
18533
|
};
|
|
18491
18534
|
}
|
|
18492
18535
|
const response = await client.get(`/networks/${chainId}${includeRpcUrl ? "?includeRpcUrl=true" : ""}`);
|
|
18493
18536
|
networkCache.set(chainId, {
|
|
18494
18537
|
name: response.name,
|
|
18495
|
-
rpcUrl
|
|
18538
|
+
// If an override exists, cache it as the effective rpcUrl for this chainId
|
|
18539
|
+
rpcUrl: overrideUrl ?? response.rpcUrl,
|
|
18496
18540
|
invokerAddress: response.invokerAddress,
|
|
18497
18541
|
timestamp: Date.now()
|
|
18498
18542
|
});
|
|
18499
18543
|
return {
|
|
18500
18544
|
name: response.name,
|
|
18501
|
-
rpcUrl: includeRpcUrl ? response.rpcUrl : void 0,
|
|
18545
|
+
rpcUrl: includeRpcUrl ? overrideUrl ?? response.rpcUrl : void 0,
|
|
18502
18546
|
invokerAddress: response.invokerAddress
|
|
18503
18547
|
};
|
|
18504
18548
|
};
|
|
@@ -18537,7 +18581,7 @@ function validateCalls2(calls) {
|
|
|
18537
18581
|
|
|
18538
18582
|
// src/wallet/normalize.ts
|
|
18539
18583
|
function normalizeCall(call2) {
|
|
18540
|
-
const normalizedTarget = getAddress(call2.target);
|
|
18584
|
+
const normalizedTarget = normalizeHex(getAddress(call2.target));
|
|
18541
18585
|
const normalizedData = normalizeHex(call2.data);
|
|
18542
18586
|
const value = call2.value ?? 0n;
|
|
18543
18587
|
const gasLimit = call2.gasLimit ?? 0n;
|
|
@@ -18773,7 +18817,7 @@ async function sendCalls(args) {
|
|
|
18773
18817
|
if (chainId === 0) {
|
|
18774
18818
|
throw new Error("chainId cannot be 0");
|
|
18775
18819
|
}
|
|
18776
|
-
const normalizedFrom = from14;
|
|
18820
|
+
const normalizedFrom = normalizeHex(from14);
|
|
18777
18821
|
const normalizedCalls = normalizeCalls(calls);
|
|
18778
18822
|
validateCalls2(normalizedCalls);
|
|
18779
18823
|
if (!deps.provider && deps.user?.keyStorageType !== "passkey") {
|
|
@@ -18837,7 +18881,7 @@ async function sendCalls(args) {
|
|
|
18837
18881
|
if (!quotePolicyId) {
|
|
18838
18882
|
throw new Error("Backend did not return policyId in precheck response");
|
|
18839
18883
|
}
|
|
18840
|
-
const projectPolicyId = quotePolicyId;
|
|
18884
|
+
const projectPolicyId = normalizeHex(quotePolicyId);
|
|
18841
18885
|
validatePolicyId2(projectPolicyId);
|
|
18842
18886
|
const tempAuth = buildTempAuth({
|
|
18843
18887
|
chainId,
|
|
@@ -19652,6 +19696,8 @@ async function enrollPasskey(params) {
|
|
|
19652
19696
|
};
|
|
19653
19697
|
const prfSalt = deriveWrapKey(tempPrfInput);
|
|
19654
19698
|
const displayName = buildDisplayName(userEmail, userEvmAddress, userId);
|
|
19699
|
+
const authenticatorSelection = getAuthenticatorSelection();
|
|
19700
|
+
const hints = getWebAuthnHints();
|
|
19655
19701
|
const publicKeyCredentialCreationOptions = {
|
|
19656
19702
|
challenge: challenge2,
|
|
19657
19703
|
rp: {
|
|
@@ -19664,7 +19710,7 @@ async function enrollPasskey(params) {
|
|
|
19664
19710
|
displayName
|
|
19665
19711
|
},
|
|
19666
19712
|
pubKeyCredParams: PUBKEY_CRED_PARAMS,
|
|
19667
|
-
authenticatorSelection
|
|
19713
|
+
authenticatorSelection,
|
|
19668
19714
|
timeout: WEBAUTHN_TIMEOUT,
|
|
19669
19715
|
attestation: ATTESTATION,
|
|
19670
19716
|
extensions: {
|
|
@@ -19673,7 +19719,10 @@ async function enrollPasskey(params) {
|
|
|
19673
19719
|
first: prfSalt.buffer
|
|
19674
19720
|
}
|
|
19675
19721
|
}
|
|
19676
|
-
}
|
|
19722
|
+
},
|
|
19723
|
+
// Chrome 128+ supports hints to prioritize certain authenticator types
|
|
19724
|
+
// On Windows/Linux, this prioritizes QR code over USB security key prompt
|
|
19725
|
+
...hints && { hints }
|
|
19677
19726
|
};
|
|
19678
19727
|
const credential = await navigator.credentials.create({
|
|
19679
19728
|
publicKey: publicKeyCredentialCreationOptions
|
|
@@ -20867,7 +20916,12 @@ function getPlatformHint(platform) {
|
|
|
20867
20916
|
case "Windows":
|
|
20868
20917
|
return {
|
|
20869
20918
|
hintKey: "passkey.hint.windows",
|
|
20870
|
-
noteKey: "passkey.hint.
|
|
20919
|
+
noteKey: "passkey.hint.windowsNote"
|
|
20920
|
+
};
|
|
20921
|
+
case "Linux":
|
|
20922
|
+
return {
|
|
20923
|
+
hintKey: "passkey.hint.linux",
|
|
20924
|
+
noteKey: "passkey.hint.windowsNote"
|
|
20871
20925
|
};
|
|
20872
20926
|
default:
|
|
20873
20927
|
return {
|
|
@@ -21061,6 +21115,8 @@ async function completeMigration(params) {
|
|
|
21061
21115
|
credentialId: tempCredentialId
|
|
21062
21116
|
};
|
|
21063
21117
|
const prfSalt = deriveWrapKey(tempPrfInput);
|
|
21118
|
+
const authenticatorSelection = getAuthenticatorSelection();
|
|
21119
|
+
const hints = getWebAuthnHints();
|
|
21064
21120
|
const publicKeyCredentialCreationOptions = {
|
|
21065
21121
|
challenge: challenge2,
|
|
21066
21122
|
rp: {
|
|
@@ -21073,7 +21129,7 @@ async function completeMigration(params) {
|
|
|
21073
21129
|
displayName
|
|
21074
21130
|
},
|
|
21075
21131
|
pubKeyCredParams: PUBKEY_CRED_PARAMS,
|
|
21076
|
-
authenticatorSelection
|
|
21132
|
+
authenticatorSelection,
|
|
21077
21133
|
timeout: WEBAUTHN_TIMEOUT,
|
|
21078
21134
|
attestation: ATTESTATION,
|
|
21079
21135
|
extensions: {
|
|
@@ -21082,7 +21138,10 @@ async function completeMigration(params) {
|
|
|
21082
21138
|
first: prfSalt.buffer
|
|
21083
21139
|
}
|
|
21084
21140
|
}
|
|
21085
|
-
}
|
|
21141
|
+
},
|
|
21142
|
+
// Chrome 128+ supports hints to prioritize certain authenticator types
|
|
21143
|
+
// On Windows/Linux, this prioritizes QR code over USB security key prompt
|
|
21144
|
+
...hints && { hints }
|
|
21086
21145
|
};
|
|
21087
21146
|
const credential = await navigator.credentials.create({
|
|
21088
21147
|
publicKey: publicKeyCredentialCreationOptions
|