@volr/react 0.1.131 → 0.1.133

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.js CHANGED
@@ -9773,8 +9773,8 @@ var AUTHENTICATOR_SELECTION_CROSS_DEVICE = {
9773
9773
  residentKey: "required",
9774
9774
  authenticatorAttachment: "cross-platform"
9775
9775
  };
9776
- function getAuthenticatorSelection() {
9777
- if (shouldForceCrossDevice()) {
9776
+ function getAuthenticatorSelection(options) {
9777
+ if (shouldForceCrossDevice() && !options?.allowPlatform) {
9778
9778
  return AUTHENTICATOR_SELECTION_CROSS_DEVICE;
9779
9779
  }
9780
9780
  return AUTHENTICATOR_SELECTION;
@@ -9785,6 +9785,7 @@ function getWebAuthnHints() {
9785
9785
  }
9786
9786
  return void 0;
9787
9787
  }
9788
+ var AUTHENTICATOR_TRANSPORTS = ["internal", "hybrid"];
9788
9789
  var CREDENTIAL_MEDIATION = "required";
9789
9790
  var USER_VERIFICATION = "required";
9790
9791
  var WEBAUTHN_TIMEOUT = 6e4;
@@ -9952,43 +9953,41 @@ function createPasskeyAdapter(options = {}) {
9952
9953
  return { r, s };
9953
9954
  },
9954
9955
  async authenticate(prfInput) {
9955
- if (!prfInput.credentialId) {
9956
- throw new Error(
9957
- "[PasskeyAdapter] credentialId is required for authentication. This usually means the passkey was not properly registered or user data is incomplete. Please re-enroll your passkey."
9958
- );
9959
- }
9960
- const hexString = prfInput.credentialId.startsWith("0x") ? prfInput.credentialId.slice(2) : prfInput.credentialId;
9961
- if (!/^[0-9a-fA-F]+$/.test(hexString)) {
9962
- console.error(
9963
- "[PasskeyAdapter] Invalid credentialId format (not hex):",
9964
- prfInput.credentialId
9965
- );
9966
- throw new Error(
9967
- `[PasskeyAdapter] Invalid credentialId format. Expected hex string, got: ${prfInput.credentialId}`
9968
- );
9969
- }
9970
- const normalizedHex = hexString.length % 2 === 0 ? hexString : "0" + hexString;
9971
- const hexPairs = normalizedHex.match(/.{1,2}/g);
9972
- if (!hexPairs) {
9973
- throw new Error(
9974
- `[PasskeyAdapter] Failed to parse hex string: ${normalizedHex}`
9975
- );
9976
- }
9977
- const credIdBytes = new Uint8Array(
9978
- hexPairs.map((byte) => parseInt(byte, 16))
9979
- );
9980
- const reconvertedHex = Array.from(credIdBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
9981
- if (reconvertedHex.toLowerCase() !== normalizedHex.toLowerCase()) {
9982
- throw new Error(
9983
- `[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))
9984
9977
  );
9985
- }
9986
- const allowCredentials = [
9987
- {
9988
- id: credIdBytes,
9989
- type: "public-key"
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
+ );
9990
9983
  }
9991
- ];
9984
+ const transports = shouldForceCrossDevice() ? ["hybrid"] : AUTHENTICATOR_TRANSPORTS;
9985
+ allowCredentials.push({
9986
+ id: credIdBytes,
9987
+ type: "public-key",
9988
+ transports
9989
+ });
9990
+ }
9992
9991
  const hints = getWebAuthnHints();
9993
9992
  return withWebAuthnLock(async () => {
9994
9993
  let credential = null;
@@ -9997,6 +9996,8 @@ function createPasskeyAdapter(options = {}) {
9997
9996
  publicKey: {
9998
9997
  challenge: crypto.getRandomValues(new Uint8Array(32)),
9999
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.
10000
10001
  allowCredentials,
10001
10002
  userVerification: USER_VERIFICATION,
10002
10003
  // Shared constant
@@ -10400,6 +10401,10 @@ function VolrProvider({ config, children }) {
10400
10401
  const [isLoading, setIsLoading] = useState(true);
10401
10402
  const [error, setError] = useState(null);
10402
10403
  const [chainId] = useState(config.defaultChainId);
10404
+ const userRef = useRef(null);
10405
+ useEffect(() => {
10406
+ userRef.current = user;
10407
+ }, [user]);
10403
10408
  const [accessToken, setAccessTokenState] = useState(() => {
10404
10409
  return client.getAccessToken();
10405
10410
  });
@@ -10420,10 +10425,11 @@ function VolrProvider({ config, children }) {
10420
10425
  setError(null);
10421
10426
  const keyStorageType = newProvider.keyStorageType;
10422
10427
  setProviderState(newProvider);
10423
- const userHasCompleteData = user?.keyStorageType === "passkey" && user?.blobUrl && user?.prfInput && user?.id;
10428
+ const currentUser = userRef.current;
10429
+ const userHasCompleteData = currentUser?.keyStorageType === "passkey" && currentUser?.blobUrl && currentUser?.prfInput && currentUser?.id;
10424
10430
  if (userHasCompleteData) {
10425
10431
  console.log("[Provider] setProvider: User data already complete, skipping refresh");
10426
- if (user.keyStorageType !== keyStorageType) {
10432
+ if (currentUser?.keyStorageType !== keyStorageType) {
10427
10433
  setUser((prev) => ({ ...prev, keyStorageType }));
10428
10434
  }
10429
10435
  } else {
@@ -10455,7 +10461,7 @@ function VolrProvider({ config, children }) {
10455
10461
  throw error2;
10456
10462
  }
10457
10463
  },
10458
- [client, user, syncRef]
10464
+ [client, syncRef]
10459
10465
  );
10460
10466
  useAutoRecover({
10461
10467
  client,
@@ -18515,26 +18521,28 @@ function createGetRpcUrl(deps) {
18515
18521
  };
18516
18522
  }
18517
18523
  function createGetNetworkInfo(deps) {
18518
- const { client } = deps;
18524
+ const { client, rpcOverrides } = deps;
18519
18525
  return async function getNetworkInfo(chainId, includeRpcUrl = false) {
18526
+ const overrideUrl = rpcOverrides?.[chainId.toString()];
18520
18527
  const cached = networkCache.get(chainId);
18521
18528
  if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
18522
18529
  return {
18523
18530
  name: cached.name || `Chain ${chainId}`,
18524
- rpcUrl: includeRpcUrl ? cached.rpcUrl : void 0,
18531
+ rpcUrl: includeRpcUrl ? overrideUrl ?? cached.rpcUrl : void 0,
18525
18532
  invokerAddress: cached.invokerAddress
18526
18533
  };
18527
18534
  }
18528
18535
  const response = await client.get(`/networks/${chainId}${includeRpcUrl ? "?includeRpcUrl=true" : ""}`);
18529
18536
  networkCache.set(chainId, {
18530
18537
  name: response.name,
18531
- rpcUrl: response.rpcUrl,
18538
+ // If an override exists, cache it as the effective rpcUrl for this chainId
18539
+ rpcUrl: overrideUrl ?? response.rpcUrl,
18532
18540
  invokerAddress: response.invokerAddress,
18533
18541
  timestamp: Date.now()
18534
18542
  });
18535
18543
  return {
18536
18544
  name: response.name,
18537
- rpcUrl: includeRpcUrl ? response.rpcUrl : void 0,
18545
+ rpcUrl: includeRpcUrl ? overrideUrl ?? response.rpcUrl : void 0,
18538
18546
  invokerAddress: response.invokerAddress
18539
18547
  };
18540
18548
  };
@@ -18573,7 +18581,7 @@ function validateCalls2(calls) {
18573
18581
 
18574
18582
  // src/wallet/normalize.ts
18575
18583
  function normalizeCall(call2) {
18576
- const normalizedTarget = getAddress(call2.target);
18584
+ const normalizedTarget = normalizeHex(getAddress(call2.target));
18577
18585
  const normalizedData = normalizeHex(call2.data);
18578
18586
  const value = call2.value ?? 0n;
18579
18587
  const gasLimit = call2.gasLimit ?? 0n;
@@ -18809,7 +18817,7 @@ async function sendCalls(args) {
18809
18817
  if (chainId === 0) {
18810
18818
  throw new Error("chainId cannot be 0");
18811
18819
  }
18812
- const normalizedFrom = from14;
18820
+ const normalizedFrom = normalizeHex(from14);
18813
18821
  const normalizedCalls = normalizeCalls(calls);
18814
18822
  validateCalls2(normalizedCalls);
18815
18823
  if (!deps.provider && deps.user?.keyStorageType !== "passkey") {
@@ -18873,7 +18881,7 @@ async function sendCalls(args) {
18873
18881
  if (!quotePolicyId) {
18874
18882
  throw new Error("Backend did not return policyId in precheck response");
18875
18883
  }
18876
- const projectPolicyId = quotePolicyId;
18884
+ const projectPolicyId = normalizeHex(quotePolicyId);
18877
18885
  validatePolicyId2(projectPolicyId);
18878
18886
  const tempAuth = buildTempAuth({
18879
18887
  chainId,
@@ -19688,7 +19696,7 @@ async function enrollPasskey(params) {
19688
19696
  };
19689
19697
  const prfSalt = deriveWrapKey(tempPrfInput);
19690
19698
  const displayName = buildDisplayName(userEmail, userEvmAddress, userId);
19691
- const authenticatorSelection = getAuthenticatorSelection();
19699
+ const authenticatorSelection = getAuthenticatorSelection({ allowPlatform: true });
19692
19700
  const hints = getWebAuthnHints();
19693
19701
  const publicKeyCredentialCreationOptions = {
19694
19702
  challenge: challenge2,
@@ -21107,7 +21115,7 @@ async function completeMigration(params) {
21107
21115
  credentialId: tempCredentialId
21108
21116
  };
21109
21117
  const prfSalt = deriveWrapKey(tempPrfInput);
21110
- const authenticatorSelection = getAuthenticatorSelection();
21118
+ const authenticatorSelection = getAuthenticatorSelection({ allowPlatform: true });
21111
21119
  const hints = getWebAuthnHints();
21112
21120
  const publicKeyCredentialCreationOptions = {
21113
21121
  challenge: challenge2,