@volr/react 0.1.129 → 0.1.131

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
@@ -1,6 +1,6 @@
1
1
  import * as nc from 'crypto';
2
2
  import { createContext, useRef, useEffect, useMemo, useState, useCallback, useContext } from 'react';
3
- import { createPasskeyProvider, createMpcProvider, deriveWrapKey, unsealMasterSeed, sealMasterSeed, signSession, getAuthNonce, signAuthorization, createMasterKeyProvider, deriveEvmKey, ZERO_HASH, selectSigner, VolrError } from '@volr/sdk-core';
3
+ import { signSession, getAuthNonce, signAuthorization, createPasskeyProvider, createMpcProvider, deriveWrapKey, unsealMasterSeed, sealMasterSeed, createMasterKeyProvider, deriveEvmKey, ZERO_HASH, selectSigner, VolrError } from '@volr/sdk-core';
4
4
  export { createMasterKeyProvider, createMpcProvider, createPasskeyProvider, deriveEvmKey, deriveWrapKey, sealMasterSeed, uploadBlob } from '@volr/sdk-core';
5
5
  import axios from 'axios';
6
6
  import { jsx } from 'react/jsx-runtime';
@@ -9269,12 +9269,13 @@ var APIClient = class {
9269
9269
  headers: {
9270
9270
  "Content-Type": "application/json"
9271
9271
  },
9272
+ // Transform BigInt to string before JSON serialization
9272
9273
  transformRequest: [
9273
9274
  (data) => {
9274
9275
  if (data && typeof data === "object") {
9275
9276
  return JSON.stringify(
9276
9277
  data,
9277
- (_, value) => typeof value === "bigint" ? value.toString() : value
9278
+ (_key, value) => typeof value === "bigint" ? value.toString() : value
9278
9279
  );
9279
9280
  }
9280
9281
  return data;
@@ -9298,6 +9299,9 @@ var APIClient = class {
9298
9299
  this.api.interceptors.response.use(
9299
9300
  (response) => response,
9300
9301
  async (error) => {
9302
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "test") {
9303
+ sanitizeAxiosErrorForTest(error);
9304
+ }
9301
9305
  const originalRequest = error.config;
9302
9306
  const requestUrl = originalRequest?.url || "";
9303
9307
  const responseData = error.response?.data;
@@ -9334,7 +9338,14 @@ var APIClient = class {
9334
9338
  }
9335
9339
  return this.api(originalRequest);
9336
9340
  } catch (refreshError) {
9337
- console.error("[APIClient] Token refresh failed:", refreshError);
9341
+ const anyErr = refreshError;
9342
+ const status = anyErr?.response?.status;
9343
+ const backendCode = anyErr?.response?.data?.error?.code;
9344
+ const backendMessage = anyErr?.response?.data?.error?.message;
9345
+ const message = backendMessage || anyErr?.message || "Unknown error";
9346
+ console.error(
9347
+ `[APIClient] Token refresh failed${typeof status === "number" ? ` (${status})` : ""}: ${backendCode ? `${backendCode}: ` : ""}${message}`
9348
+ );
9338
9349
  return Promise.reject(refreshError);
9339
9350
  }
9340
9351
  }
@@ -9415,17 +9426,11 @@ var APIClient = class {
9415
9426
  if (!this.refreshToken) {
9416
9427
  throw new Error("No refresh token available. Please log in again.");
9417
9428
  }
9418
- const timeoutPromise = new Promise(
9419
- (_, reject) => setTimeout(
9420
- () => reject(new Error("Session refresh timeout. Please check your network connection.")),
9421
- timeoutMs
9422
- )
9423
- );
9424
- const refreshPromise = this.api.post(
9429
+ const response = await this.api.post(
9425
9430
  "/auth/refresh",
9426
- { refreshToken: this.refreshToken }
9431
+ { refreshToken: this.refreshToken },
9432
+ { timeout: timeoutMs }
9427
9433
  );
9428
- const response = await Promise.race([refreshPromise, timeoutPromise]);
9429
9434
  const data = response.data;
9430
9435
  if (isErrorResponse(data)) {
9431
9436
  this.setAccessToken(null);
@@ -9453,23 +9458,27 @@ var APIClient = class {
9453
9458
  }
9454
9459
  this.refreshPromise = (async () => {
9455
9460
  try {
9456
- const response = await this.api.post(
9457
- "/auth/refresh",
9458
- { refreshToken: this.refreshToken }
9459
- );
9460
- const data = response.data;
9461
- if (isErrorResponse(data)) {
9461
+ try {
9462
+ const response = await this.api.post("/auth/refresh", { refreshToken: this.refreshToken });
9463
+ const data = response.data;
9464
+ if (isErrorResponse(data)) {
9465
+ this.setAccessToken(null);
9466
+ this.setRefreshToken(null);
9467
+ safeStorage.removeItem(STORAGE_KEYS.user);
9468
+ throw new Error(data.error.message);
9469
+ }
9470
+ this.setAccessToken(data.data.accessToken);
9471
+ if (data.data.refreshToken) {
9472
+ this.setRefreshToken(data.data.refreshToken);
9473
+ }
9474
+ if (data.data.user) {
9475
+ safeStorage.setItem(STORAGE_KEYS.user, JSON.stringify(data.data.user));
9476
+ }
9477
+ } catch (err) {
9462
9478
  this.setAccessToken(null);
9463
9479
  this.setRefreshToken(null);
9464
9480
  safeStorage.removeItem(STORAGE_KEYS.user);
9465
- throw new Error(data.error.message);
9466
- }
9467
- this.setAccessToken(data.data.accessToken);
9468
- if (data.data.refreshToken) {
9469
- this.setRefreshToken(data.data.refreshToken);
9470
- }
9471
- if (data.data.user) {
9472
- safeStorage.setItem(STORAGE_KEYS.user, JSON.stringify(data.data.user));
9481
+ throw err;
9473
9482
  }
9474
9483
  } finally {
9475
9484
  this.refreshPromise = null;
@@ -9517,7 +9526,14 @@ var APIClient = class {
9517
9526
  const response = await this.api.request(config);
9518
9527
  return unwrapResponse(response.data);
9519
9528
  } catch (error) {
9520
- console.error(`[APIClient] POST ${normalizedEndpoint} error:`, error);
9529
+ const anyErr = error;
9530
+ const status = anyErr?.response?.status;
9531
+ const backendCode = anyErr?.response?.data?.error?.code;
9532
+ const backendMessage = anyErr?.response?.data?.error?.message;
9533
+ const message = backendMessage || anyErr?.message || "Unknown error";
9534
+ console.error(
9535
+ `[APIClient] POST ${normalizedEndpoint} error${typeof status === "number" ? ` (${status})` : ""}: ${backendCode ? `${backendCode}: ` : ""}${message}`
9536
+ );
9521
9537
  throw error;
9522
9538
  }
9523
9539
  }
@@ -9554,7 +9570,36 @@ var APIClient = class {
9554
9570
  const response = await this.api.get(normalizedEndpoint);
9555
9571
  return unwrapResponse(response.data);
9556
9572
  }
9573
+ /**
9574
+ * Internal helper to sanitize Axios errors in test environment so that Vitest
9575
+ * can safely structured-clone them between workers.
9576
+ *
9577
+ * NOTE: This function is exported only for tests. It is a no-op in production
9578
+ * builds where NODE_ENV !== 'test'.
9579
+ */
9580
+ static sanitizeAxiosErrorForTest(error) {
9581
+ sanitizeAxiosErrorForTest(error);
9582
+ }
9557
9583
  };
9584
+ function sanitizeAxiosErrorForTest(error) {
9585
+ if (!error || typeof error !== "object") return;
9586
+ try {
9587
+ const anyErr = error;
9588
+ const cfg = anyErr.config;
9589
+ if (cfg && typeof cfg === "object") {
9590
+ if ("transformRequest" in cfg) cfg.transformRequest = void 0;
9591
+ if ("transformResponse" in cfg) cfg.transformResponse = void 0;
9592
+ if ("adapter" in cfg) cfg.adapter = void 0;
9593
+ }
9594
+ if (anyErr.request) {
9595
+ anyErr.request = void 0;
9596
+ }
9597
+ if (anyErr.response && anyErr.response.request) {
9598
+ anyErr.response.request = void 0;
9599
+ }
9600
+ } catch {
9601
+ }
9602
+ }
9558
9603
 
9559
9604
  // src/config/backend.ts
9560
9605
  var DEFAULT_API_BASE_URL = "https://api.volr.io";
@@ -9627,7 +9672,9 @@ var SessionSync = class {
9627
9672
  try {
9628
9673
  listener(event);
9629
9674
  } catch (error) {
9630
- console.error("SessionSync listener error:", error);
9675
+ console.error(
9676
+ `SessionSync listener error: ${error instanceof Error ? error.message : String(error)}`
9677
+ );
9631
9678
  }
9632
9679
  }
9633
9680
  }
@@ -9703,10 +9750,41 @@ function useSessionSync({
9703
9750
  }
9704
9751
 
9705
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
+ }
9706
9767
  var AUTHENTICATOR_SELECTION = {
9707
9768
  userVerification: "required",
9708
9769
  residentKey: "required"
9709
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
+ }
9710
9788
  var CREDENTIAL_MEDIATION = "required";
9711
9789
  var USER_VERIFICATION = "required";
9712
9790
  var WEBAUTHN_TIMEOUT = 6e4;
@@ -9747,6 +9825,17 @@ var PrfNotSupportedError = class _PrfNotSupportedError extends Error {
9747
9825
  Object.setPrototypeOf(this, _PrfNotSupportedError.prototype);
9748
9826
  }
9749
9827
  };
9828
+ var WebAuthnBusyError = class _WebAuthnBusyError extends Error {
9829
+ constructor(message) {
9830
+ super(
9831
+ message || "Another passkey authentication is in progress. Please wait a moment and try again."
9832
+ );
9833
+ this.code = "WEBAUTHN_BUSY";
9834
+ this.isRetryable = true;
9835
+ this.name = "WebAuthnBusyError";
9836
+ Object.setPrototypeOf(this, _WebAuthnBusyError.prototype);
9837
+ }
9838
+ };
9750
9839
  function isUserCancelledError(error) {
9751
9840
  if (error instanceof UserCancelledError) {
9752
9841
  return true;
@@ -9764,8 +9853,40 @@ function isUserCancelledError(error) {
9764
9853
  }
9765
9854
  return false;
9766
9855
  }
9856
+ function isWebAuthnBusyError(error) {
9857
+ if (error instanceof WebAuthnBusyError) {
9858
+ return true;
9859
+ }
9860
+ if (error instanceof Error) {
9861
+ const msg = error.message.toLowerCase();
9862
+ if (msg.includes("already in progress") || msg.includes("already pending") || msg.includes("\uC774\uBBF8 \uC694\uCCAD\uC774 \uB300\uAE30 \uC911") || // Korean locale
9863
+ msg.includes("authentication is already in progress") || msg.includes("operation already in progress") || msg.includes("request is already in progress")) {
9864
+ return true;
9865
+ }
9866
+ }
9867
+ return false;
9868
+ }
9767
9869
 
9768
9870
  // src/adapters/passkey.ts
9871
+ var pendingWebAuthnPromise = null;
9872
+ async function withWebAuthnLock(fn) {
9873
+ if (pendingWebAuthnPromise) {
9874
+ try {
9875
+ await pendingWebAuthnPromise;
9876
+ } catch {
9877
+ }
9878
+ }
9879
+ const promise = fn();
9880
+ pendingWebAuthnPromise = promise;
9881
+ try {
9882
+ const result = await promise;
9883
+ return result;
9884
+ } finally {
9885
+ if (pendingWebAuthnPromise === promise) {
9886
+ pendingWebAuthnPromise = null;
9887
+ }
9888
+ }
9889
+ }
9769
9890
  function createPasskeyAdapter(options = {}) {
9770
9891
  const rpId = options.rpId || (typeof window !== "undefined" ? window.location.hostname : "localhost");
9771
9892
  return {
@@ -9868,72 +9989,88 @@ function createPasskeyAdapter(options = {}) {
9868
9989
  type: "public-key"
9869
9990
  }
9870
9991
  ];
9871
- let credential = null;
9872
- try {
9873
- credential = await navigator.credentials.get({
9874
- publicKey: {
9875
- challenge: crypto.getRandomValues(new Uint8Array(32)),
9876
- rpId,
9877
- allowCredentials,
9878
- userVerification: USER_VERIFICATION,
9879
- // Shared constant
9880
- extensions: {
9881
- prf: {
9882
- eval: {
9883
- first: prfInput.salt.buffer
9992
+ const hints = getWebAuthnHints();
9993
+ return withWebAuthnLock(async () => {
9994
+ let credential = null;
9995
+ try {
9996
+ const requestOptions = {
9997
+ publicKey: {
9998
+ challenge: crypto.getRandomValues(new Uint8Array(32)),
9999
+ rpId,
10000
+ allowCredentials,
10001
+ userVerification: USER_VERIFICATION,
10002
+ // Shared constant
10003
+ extensions: {
10004
+ prf: {
10005
+ eval: {
10006
+ first: prfInput.salt.buffer
10007
+ }
9884
10008
  }
9885
- }
9886
- }
9887
- },
9888
- mediation: CREDENTIAL_MEDIATION
9889
- // Use shared constant
9890
- });
9891
- } catch (error) {
9892
- console.error("[PasskeyAdapter] WebAuthn get() failed:", error);
9893
- console.error("[PasskeyAdapter] Error name:", error?.name);
9894
- console.error("[PasskeyAdapter] Error message:", error?.message);
9895
- if (error?.name === "NotAllowedError") {
9896
- throw new UserCancelledError(
9897
- "User cancelled the passkey prompt or authentication was denied."
10009
+ },
10010
+ // Chrome 128+ supports hints to prioritize certain authenticator types
10011
+ // On Windows/Linux, this prioritizes QR code over USB security key prompt
10012
+ ...hints && { hints }
10013
+ },
10014
+ mediation: CREDENTIAL_MEDIATION
10015
+ // Use shared constant
10016
+ };
10017
+ credential = await navigator.credentials.get(requestOptions);
10018
+ } catch (error) {
10019
+ console.error("[PasskeyAdapter] WebAuthn get() failed:", error);
10020
+ console.error("[PasskeyAdapter] Error name:", error?.name);
10021
+ console.error("[PasskeyAdapter] Error message:", error?.message);
10022
+ const msg = (error?.message || "").toLowerCase();
10023
+ if (msg.includes("already in progress") || msg.includes("already pending") || msg.includes("\uC774\uBBF8 \uC694\uCCAD\uC774 \uB300\uAE30 \uC911") || // Korean
10024
+ msg.includes("operation already in progress") || msg.includes("request is already in progress")) {
10025
+ throw new WebAuthnBusyError(
10026
+ "Another passkey authentication is in progress. Please wait a moment and try again."
10027
+ );
10028
+ }
10029
+ if (error?.name === "NotAllowedError") {
10030
+ throw new UserCancelledError(
10031
+ "User cancelled the passkey prompt or authentication was denied."
10032
+ );
10033
+ }
10034
+ if (error?.name === "NotFoundError" || error?.name === "InvalidStateError") {
10035
+ throw new PasskeyNotFoundError(
10036
+ "No passkey found matching the provided credentialId. This may happen if the passkey was deleted or the credentialId is incorrect."
10037
+ );
10038
+ }
10039
+ if (error?.name === "NotSupportedError") {
10040
+ throw new PrfNotSupportedError(
10041
+ "WebAuthn PRF extension is not supported by this browser or device. Please use a browser that supports WebAuthn PRF extension (Chrome 108+, Edge 108+, Safari 16.4+)."
10042
+ );
10043
+ }
10044
+ throw new Error(
10045
+ `[PasskeyAdapter] WebAuthn authentication failed: ${error?.message || "Unknown error"}`
9898
10046
  );
9899
10047
  }
9900
- if (error?.name === "NotFoundError" || error?.name === "InvalidStateError") {
9901
- throw new PasskeyNotFoundError(
9902
- "No passkey found matching the provided credentialId. This may happen if the passkey was deleted or the credentialId is incorrect."
10048
+ if (!credential || !credential.response) {
10049
+ console.error(
10050
+ "[PasskeyAdapter] credential is null or missing response"
10051
+ );
10052
+ throw new Error(
10053
+ "[PasskeyAdapter] Failed to get passkey credential for PRF. The passkey prompt may have been cancelled or no matching credential was found."
9903
10054
  );
9904
10055
  }
9905
- if (error?.name === "NotSupportedError") {
9906
- throw new PrfNotSupportedError(
9907
- "WebAuthn PRF extension is not supported by this browser or device. Please use a browser that supports WebAuthn PRF extension (Chrome 108+, Edge 108+, Safari 16.4+)."
10056
+ const extensionResults = credential.getClientExtensionResults();
10057
+ if (!extensionResults.prf || !extensionResults.prf.results || !extensionResults.prf.results.first) {
10058
+ throw new Error(
10059
+ "[PasskeyAdapter] PRF extension not supported or PRF output missing"
9908
10060
  );
9909
10061
  }
9910
- throw new Error(
9911
- `[PasskeyAdapter] WebAuthn authentication failed: ${error?.message || "Unknown error"}`
9912
- );
9913
- }
9914
- if (!credential || !credential.response) {
9915
- console.error(
9916
- "[PasskeyAdapter] credential is null or missing response"
9917
- );
9918
- throw new Error(
9919
- "[PasskeyAdapter] Failed to get passkey credential for PRF. The passkey prompt may have been cancelled or no matching credential was found."
9920
- );
9921
- }
9922
- const extensionResults = credential.getClientExtensionResults();
9923
- if (!extensionResults.prf || !extensionResults.prf.results || !extensionResults.prf.results.first) {
9924
- throw new Error(
9925
- "[PasskeyAdapter] PRF extension not supported or PRF output missing"
9926
- );
9927
- }
9928
- const prfOutputBuffer = extensionResults.prf.results.first;
9929
- const prfOutput = new Uint8Array(prfOutputBuffer);
9930
- const credentialIdBytes = new Uint8Array(credential.rawId);
9931
- const credentialIdBase64 = btoa(String.fromCharCode(...credentialIdBytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
9932
- console.log("[PasskeyAdapter] WebAuthn prompt completed successfully");
9933
- return {
9934
- prfOutput,
9935
- credentialId: credentialIdBase64
9936
- };
10062
+ const prfOutputBuffer = extensionResults.prf.results.first;
10063
+ const prfOutput = new Uint8Array(prfOutputBuffer);
10064
+ const credentialIdBytes = new Uint8Array(credential.rawId);
10065
+ const credentialIdBase64 = btoa(
10066
+ String.fromCharCode(...credentialIdBytes)
10067
+ ).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
10068
+ console.log("[PasskeyAdapter] WebAuthn prompt completed successfully");
10069
+ return {
10070
+ prfOutput,
10071
+ credentialId: credentialIdBase64
10072
+ };
10073
+ });
9937
10074
  }
9938
10075
  };
9939
10076
  }
@@ -10299,7 +10436,9 @@ function VolrProvider({ config, children }) {
10299
10436
  setUser((prev) => ({ ...prev, keyStorageType }));
10300
10437
  }
10301
10438
  } catch (error2) {
10302
- console.warn("[Provider] setProvider: Failed to refresh user data:", error2);
10439
+ console.warn(
10440
+ `[Provider] setProvider: Failed to refresh user data: ${error2 instanceof Error ? error2.message : String(error2)}`
10441
+ );
10303
10442
  setUser((prev) => ({ ...prev, keyStorageType }));
10304
10443
  }
10305
10444
  }
@@ -18650,7 +18789,9 @@ async function pollTransactionStatus(txId, client, maxAttempts = 60) {
18650
18789
  const intervalMs = getPollingInterval(attempt);
18651
18790
  await new Promise((resolve) => setTimeout(resolve, intervalMs));
18652
18791
  } catch (error) {
18653
- console.error(`[pollTransactionStatus] Error polling transaction ${txId}:`, error);
18792
+ console.error(
18793
+ `[pollTransactionStatus] Error polling transaction ${txId}: ${error instanceof Error ? error.message : String(error)}`
18794
+ );
18654
18795
  const intervalMs = getPollingInterval(attempt);
18655
18796
  await new Promise((resolve) => setTimeout(resolve, intervalMs));
18656
18797
  }
@@ -18671,6 +18812,11 @@ async function sendCalls(args) {
18671
18812
  const normalizedFrom = from14;
18672
18813
  const normalizedCalls = normalizeCalls(calls);
18673
18814
  validateCalls2(normalizedCalls);
18815
+ if (!deps.provider && deps.user?.keyStorageType !== "passkey") {
18816
+ throw new Error(
18817
+ "No wallet provider configured. Please set up a Passkey provider to sign transactions. SIWE is authentication-only."
18818
+ );
18819
+ }
18674
18820
  let currentUser = deps.user;
18675
18821
  if (deps.user?.keyStorageType === "passkey" && !deps.provider) {
18676
18822
  try {
@@ -18679,7 +18825,9 @@ async function sendCalls(args) {
18679
18825
  currentUser = refreshedUser;
18680
18826
  }
18681
18827
  } catch (error) {
18682
- console.error("[sendCalls] Failed to refresh session:", error);
18828
+ console.error(
18829
+ `[sendCalls] Failed to refresh session: ${error instanceof Error ? error.message : String(error)}`
18830
+ );
18683
18831
  throw new Error(
18684
18832
  `Failed to refresh session before transaction. ${error instanceof Error ? error.message : "Unknown error"}. Please try logging in again.`
18685
18833
  );
@@ -18699,7 +18847,9 @@ async function sendCalls(args) {
18699
18847
  calls: normalizedCalls
18700
18848
  });
18701
18849
  } catch (err) {
18702
- console.error("[sendCalls] First precheck failed:", err);
18850
+ console.error(
18851
+ `[sendCalls] First precheck failed: ${err instanceof Error ? err.message : String(err)}`
18852
+ );
18703
18853
  throw err instanceof Error ? err : new Error(String(err));
18704
18854
  }
18705
18855
  if (precheckQuote.simulationSuccess === false && precheckQuote.simulationErrors?.length) {
@@ -19289,7 +19439,9 @@ function useVolrAuthCallback(options = {}) {
19289
19439
  setIsLoading(false);
19290
19440
  options.onSuccess?.(volrUser);
19291
19441
  } catch (err) {
19292
- console.error("[useVolrAuthCallback] Token exchange error:", err);
19442
+ console.error(
19443
+ `[useVolrAuthCallback] Token exchange error: ${err instanceof Error ? err.message : String(err)}`
19444
+ );
19293
19445
  let errorMsg = "Failed to complete authentication";
19294
19446
  if (err instanceof Error) {
19295
19447
  if (err.message.includes("AUTH_CODE_EXPIRED")) {
@@ -19393,7 +19545,9 @@ function useDepositListener(input) {
19393
19545
  if (cancelled) return;
19394
19546
  setStatus({ state: "listening", balance: initial });
19395
19547
  } catch (e) {
19396
- console.error("[DepositListener] Error:", e);
19548
+ console.error(
19549
+ `[DepositListener] Error: ${e instanceof Error ? e.message : String(e)}`
19550
+ );
19397
19551
  if (cancelled) return;
19398
19552
  setStatus({ state: "error", message: e.message || String(e) });
19399
19553
  return;
@@ -19429,7 +19583,9 @@ function useDepositListener(input) {
19429
19583
  return prev;
19430
19584
  });
19431
19585
  } catch (err) {
19432
- console.error("[DepositListener] Polling error:", err);
19586
+ console.error(
19587
+ `[DepositListener] Polling error: ${err instanceof Error ? err.message : String(err)}`
19588
+ );
19433
19589
  if (cancelled) return;
19434
19590
  setStatus({ state: "error", message: err.message || String(err) });
19435
19591
  }
@@ -19532,6 +19688,8 @@ async function enrollPasskey(params) {
19532
19688
  };
19533
19689
  const prfSalt = deriveWrapKey(tempPrfInput);
19534
19690
  const displayName = buildDisplayName(userEmail, userEvmAddress, userId);
19691
+ const authenticatorSelection = getAuthenticatorSelection();
19692
+ const hints = getWebAuthnHints();
19535
19693
  const publicKeyCredentialCreationOptions = {
19536
19694
  challenge: challenge2,
19537
19695
  rp: {
@@ -19544,7 +19702,7 @@ async function enrollPasskey(params) {
19544
19702
  displayName
19545
19703
  },
19546
19704
  pubKeyCredParams: PUBKEY_CRED_PARAMS,
19547
- authenticatorSelection: AUTHENTICATOR_SELECTION,
19705
+ authenticatorSelection,
19548
19706
  timeout: WEBAUTHN_TIMEOUT,
19549
19707
  attestation: ATTESTATION,
19550
19708
  extensions: {
@@ -19553,7 +19711,10 @@ async function enrollPasskey(params) {
19553
19711
  first: prfSalt.buffer
19554
19712
  }
19555
19713
  }
19556
- }
19714
+ },
19715
+ // Chrome 128+ supports hints to prioritize certain authenticator types
19716
+ // On Windows/Linux, this prioritizes QR code over USB security key prompt
19717
+ ...hints && { hints }
19557
19718
  };
19558
19719
  const credential = await navigator.credentials.create({
19559
19720
  publicKey: publicKeyCredentialCreationOptions
@@ -20062,7 +20223,9 @@ function useUserBalances() {
20062
20223
  });
20063
20224
  setBalances(initialBalances);
20064
20225
  }).catch((err) => {
20065
- console.error("[useUserBalances] Failed to fetch branding:", err);
20226
+ console.error(
20227
+ `[useUserBalances] Failed to fetch branding: ${err instanceof Error ? err.message : String(err)}`
20228
+ );
20066
20229
  setError(err instanceof Error ? err : new Error("Failed to fetch branding"));
20067
20230
  }).finally(() => {
20068
20231
  setIsLoadingBranding(false);
@@ -20103,7 +20266,9 @@ function useUserBalances() {
20103
20266
  error: void 0
20104
20267
  };
20105
20268
  } catch (err) {
20106
- console.error(`[useUserBalances] Failed to fetch balance for ${id}:`, err);
20269
+ console.error(
20270
+ `[useUserBalances] Failed to fetch balance for ${id}: ${err instanceof Error ? err.message : String(err)}`
20271
+ );
20107
20272
  return {
20108
20273
  id,
20109
20274
  balanceRaw: 0n,
@@ -20743,7 +20908,12 @@ function getPlatformHint(platform) {
20743
20908
  case "Windows":
20744
20909
  return {
20745
20910
  hintKey: "passkey.hint.windows",
20746
- noteKey: "passkey.hint.note"
20911
+ noteKey: "passkey.hint.windowsNote"
20912
+ };
20913
+ case "Linux":
20914
+ return {
20915
+ hintKey: "passkey.hint.linux",
20916
+ noteKey: "passkey.hint.windowsNote"
20747
20917
  };
20748
20918
  default:
20749
20919
  return {
@@ -20937,6 +21107,8 @@ async function completeMigration(params) {
20937
21107
  credentialId: tempCredentialId
20938
21108
  };
20939
21109
  const prfSalt = deriveWrapKey(tempPrfInput);
21110
+ const authenticatorSelection = getAuthenticatorSelection();
21111
+ const hints = getWebAuthnHints();
20940
21112
  const publicKeyCredentialCreationOptions = {
20941
21113
  challenge: challenge2,
20942
21114
  rp: {
@@ -20949,7 +21121,7 @@ async function completeMigration(params) {
20949
21121
  displayName
20950
21122
  },
20951
21123
  pubKeyCredParams: PUBKEY_CRED_PARAMS,
20952
- authenticatorSelection: AUTHENTICATOR_SELECTION,
21124
+ authenticatorSelection,
20953
21125
  timeout: WEBAUTHN_TIMEOUT,
20954
21126
  attestation: ATTESTATION,
20955
21127
  extensions: {
@@ -20958,7 +21130,10 @@ async function completeMigration(params) {
20958
21130
  first: prfSalt.buffer
20959
21131
  }
20960
21132
  }
20961
- }
21133
+ },
21134
+ // Chrome 128+ supports hints to prioritize certain authenticator types
21135
+ // On Windows/Linux, this prioritizes QR code over USB security key prompt
21136
+ ...hints && { hints }
20962
21137
  };
20963
21138
  const credential = await navigator.credentials.create({
20964
21139
  publicKey: publicKeyCredentialCreationOptions
@@ -21126,6 +21301,6 @@ function detectWalletConnector(provider, providerInfo) {
21126
21301
  (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
21127
21302
  */
21128
21303
 
21129
- export { DEFAULT_EXPIRES_IN_SEC, DEFAULT_MODE, PasskeyNotFoundError, PrfNotSupportedError, UserCancelledError, VolrProvider, analyzeContractForEIP7702, buildCall, buildCalls, checkPrfCompatibility, checkPrfExtensionAvailable, checkPrfSupport, compareERC20Balances, compareWalletStates, completeMigration, createGetNetworkInfo, createPasskeyAdapter, debugTransactionFailure, decryptEntropyForMigration, defaultIdempotencyKey, detectWalletConnector, diagnoseTransactionFailure, getBrowserVersion, getERC20Balance, getIOSVersion, getPasskeyAuthGuidance, getPlatformHint, getUserCredentials, getWalletState, isEIP7702Delegated, isInAppBrowser, isUserCancelledError, listenForSeedRequests, normalizeHex, normalizeHexArray, openMigrationPopup, requestMigration, requestSeedFromOpener, sendSeedToPopup, uploadBlobViaPresign, useDepositListener, useEIP6963, useInternalAuth, useMpcConnection, usePasskeyEnrollment, useUserBalances, useVolr, useVolrAuthCallback, useVolrContext, useVolrLogin, useVolrPaymentApi, useWithdraw };
21304
+ export { DEFAULT_EXPIRES_IN_SEC, DEFAULT_MODE, PasskeyNotFoundError, PrfNotSupportedError, UserCancelledError, VolrProvider, WebAuthnBusyError, analyzeContractForEIP7702, buildCall, buildCalls, checkPrfCompatibility, checkPrfExtensionAvailable, checkPrfSupport, compareERC20Balances, compareWalletStates, completeMigration, createGetNetworkInfo, createPasskeyAdapter, debugTransactionFailure, decryptEntropyForMigration, defaultIdempotencyKey, detectWalletConnector, diagnoseTransactionFailure, getBrowserVersion, getERC20Balance, getIOSVersion, getPasskeyAuthGuidance, getPlatformHint, getUserCredentials, getWalletState, isEIP7702Delegated, isInAppBrowser, isUserCancelledError, isWebAuthnBusyError, listenForSeedRequests, normalizeHex, normalizeHexArray, openMigrationPopup, requestMigration, requestSeedFromOpener, sendSeedToPopup, uploadBlobViaPresign, useDepositListener, useEIP6963, useInternalAuth, useMpcConnection, usePasskeyEnrollment, usePrecheck, useRelay, useUserBalances, useVolr, useVolrAuthCallback, useVolrContext, useVolrLogin, useVolrPaymentApi, useWithdraw };
21130
21305
  //# sourceMappingURL=index.js.map
21131
21306
  //# sourceMappingURL=index.js.map