@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.cjs CHANGED
@@ -9293,12 +9293,13 @@ var APIClient = class {
9293
9293
  headers: {
9294
9294
  "Content-Type": "application/json"
9295
9295
  },
9296
+ // Transform BigInt to string before JSON serialization
9296
9297
  transformRequest: [
9297
9298
  (data) => {
9298
9299
  if (data && typeof data === "object") {
9299
9300
  return JSON.stringify(
9300
9301
  data,
9301
- (_, value) => typeof value === "bigint" ? value.toString() : value
9302
+ (_key, value) => typeof value === "bigint" ? value.toString() : value
9302
9303
  );
9303
9304
  }
9304
9305
  return data;
@@ -9322,6 +9323,9 @@ var APIClient = class {
9322
9323
  this.api.interceptors.response.use(
9323
9324
  (response) => response,
9324
9325
  async (error) => {
9326
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "test") {
9327
+ sanitizeAxiosErrorForTest(error);
9328
+ }
9325
9329
  const originalRequest = error.config;
9326
9330
  const requestUrl = originalRequest?.url || "";
9327
9331
  const responseData = error.response?.data;
@@ -9358,7 +9362,14 @@ var APIClient = class {
9358
9362
  }
9359
9363
  return this.api(originalRequest);
9360
9364
  } catch (refreshError) {
9361
- console.error("[APIClient] Token refresh failed:", refreshError);
9365
+ const anyErr = refreshError;
9366
+ const status = anyErr?.response?.status;
9367
+ const backendCode = anyErr?.response?.data?.error?.code;
9368
+ const backendMessage = anyErr?.response?.data?.error?.message;
9369
+ const message = backendMessage || anyErr?.message || "Unknown error";
9370
+ console.error(
9371
+ `[APIClient] Token refresh failed${typeof status === "number" ? ` (${status})` : ""}: ${backendCode ? `${backendCode}: ` : ""}${message}`
9372
+ );
9362
9373
  return Promise.reject(refreshError);
9363
9374
  }
9364
9375
  }
@@ -9439,17 +9450,11 @@ var APIClient = class {
9439
9450
  if (!this.refreshToken) {
9440
9451
  throw new Error("No refresh token available. Please log in again.");
9441
9452
  }
9442
- const timeoutPromise = new Promise(
9443
- (_, reject) => setTimeout(
9444
- () => reject(new Error("Session refresh timeout. Please check your network connection.")),
9445
- timeoutMs
9446
- )
9447
- );
9448
- const refreshPromise = this.api.post(
9453
+ const response = await this.api.post(
9449
9454
  "/auth/refresh",
9450
- { refreshToken: this.refreshToken }
9455
+ { refreshToken: this.refreshToken },
9456
+ { timeout: timeoutMs }
9451
9457
  );
9452
- const response = await Promise.race([refreshPromise, timeoutPromise]);
9453
9458
  const data = response.data;
9454
9459
  if (isErrorResponse(data)) {
9455
9460
  this.setAccessToken(null);
@@ -9477,23 +9482,27 @@ var APIClient = class {
9477
9482
  }
9478
9483
  this.refreshPromise = (async () => {
9479
9484
  try {
9480
- const response = await this.api.post(
9481
- "/auth/refresh",
9482
- { refreshToken: this.refreshToken }
9483
- );
9484
- const data = response.data;
9485
- if (isErrorResponse(data)) {
9485
+ try {
9486
+ const response = await this.api.post("/auth/refresh", { refreshToken: this.refreshToken });
9487
+ const data = response.data;
9488
+ if (isErrorResponse(data)) {
9489
+ this.setAccessToken(null);
9490
+ this.setRefreshToken(null);
9491
+ safeStorage.removeItem(STORAGE_KEYS.user);
9492
+ throw new Error(data.error.message);
9493
+ }
9494
+ this.setAccessToken(data.data.accessToken);
9495
+ if (data.data.refreshToken) {
9496
+ this.setRefreshToken(data.data.refreshToken);
9497
+ }
9498
+ if (data.data.user) {
9499
+ safeStorage.setItem(STORAGE_KEYS.user, JSON.stringify(data.data.user));
9500
+ }
9501
+ } catch (err) {
9486
9502
  this.setAccessToken(null);
9487
9503
  this.setRefreshToken(null);
9488
9504
  safeStorage.removeItem(STORAGE_KEYS.user);
9489
- throw new Error(data.error.message);
9490
- }
9491
- this.setAccessToken(data.data.accessToken);
9492
- if (data.data.refreshToken) {
9493
- this.setRefreshToken(data.data.refreshToken);
9494
- }
9495
- if (data.data.user) {
9496
- safeStorage.setItem(STORAGE_KEYS.user, JSON.stringify(data.data.user));
9505
+ throw err;
9497
9506
  }
9498
9507
  } finally {
9499
9508
  this.refreshPromise = null;
@@ -9541,7 +9550,14 @@ var APIClient = class {
9541
9550
  const response = await this.api.request(config);
9542
9551
  return unwrapResponse(response.data);
9543
9552
  } catch (error) {
9544
- console.error(`[APIClient] POST ${normalizedEndpoint} error:`, error);
9553
+ const anyErr = error;
9554
+ const status = anyErr?.response?.status;
9555
+ const backendCode = anyErr?.response?.data?.error?.code;
9556
+ const backendMessage = anyErr?.response?.data?.error?.message;
9557
+ const message = backendMessage || anyErr?.message || "Unknown error";
9558
+ console.error(
9559
+ `[APIClient] POST ${normalizedEndpoint} error${typeof status === "number" ? ` (${status})` : ""}: ${backendCode ? `${backendCode}: ` : ""}${message}`
9560
+ );
9545
9561
  throw error;
9546
9562
  }
9547
9563
  }
@@ -9578,7 +9594,36 @@ var APIClient = class {
9578
9594
  const response = await this.api.get(normalizedEndpoint);
9579
9595
  return unwrapResponse(response.data);
9580
9596
  }
9597
+ /**
9598
+ * Internal helper to sanitize Axios errors in test environment so that Vitest
9599
+ * can safely structured-clone them between workers.
9600
+ *
9601
+ * NOTE: This function is exported only for tests. It is a no-op in production
9602
+ * builds where NODE_ENV !== 'test'.
9603
+ */
9604
+ static sanitizeAxiosErrorForTest(error) {
9605
+ sanitizeAxiosErrorForTest(error);
9606
+ }
9581
9607
  };
9608
+ function sanitizeAxiosErrorForTest(error) {
9609
+ if (!error || typeof error !== "object") return;
9610
+ try {
9611
+ const anyErr = error;
9612
+ const cfg = anyErr.config;
9613
+ if (cfg && typeof cfg === "object") {
9614
+ if ("transformRequest" in cfg) cfg.transformRequest = void 0;
9615
+ if ("transformResponse" in cfg) cfg.transformResponse = void 0;
9616
+ if ("adapter" in cfg) cfg.adapter = void 0;
9617
+ }
9618
+ if (anyErr.request) {
9619
+ anyErr.request = void 0;
9620
+ }
9621
+ if (anyErr.response && anyErr.response.request) {
9622
+ anyErr.response.request = void 0;
9623
+ }
9624
+ } catch {
9625
+ }
9626
+ }
9582
9627
 
9583
9628
  // src/config/backend.ts
9584
9629
  var DEFAULT_API_BASE_URL = "https://api.volr.io";
@@ -9651,7 +9696,9 @@ var SessionSync = class {
9651
9696
  try {
9652
9697
  listener(event);
9653
9698
  } catch (error) {
9654
- console.error("SessionSync listener error:", error);
9699
+ console.error(
9700
+ `SessionSync listener error: ${error instanceof Error ? error.message : String(error)}`
9701
+ );
9655
9702
  }
9656
9703
  }
9657
9704
  }
@@ -9727,10 +9774,41 @@ function useSessionSync({
9727
9774
  }
9728
9775
 
9729
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
+ }
9730
9791
  var AUTHENTICATOR_SELECTION = {
9731
9792
  userVerification: "required",
9732
9793
  residentKey: "required"
9733
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
+ }
9734
9812
  var CREDENTIAL_MEDIATION = "required";
9735
9813
  var USER_VERIFICATION = "required";
9736
9814
  var WEBAUTHN_TIMEOUT = 6e4;
@@ -9771,6 +9849,17 @@ var PrfNotSupportedError = class _PrfNotSupportedError extends Error {
9771
9849
  Object.setPrototypeOf(this, _PrfNotSupportedError.prototype);
9772
9850
  }
9773
9851
  };
9852
+ var WebAuthnBusyError = class _WebAuthnBusyError extends Error {
9853
+ constructor(message) {
9854
+ super(
9855
+ message || "Another passkey authentication is in progress. Please wait a moment and try again."
9856
+ );
9857
+ this.code = "WEBAUTHN_BUSY";
9858
+ this.isRetryable = true;
9859
+ this.name = "WebAuthnBusyError";
9860
+ Object.setPrototypeOf(this, _WebAuthnBusyError.prototype);
9861
+ }
9862
+ };
9774
9863
  function isUserCancelledError(error) {
9775
9864
  if (error instanceof UserCancelledError) {
9776
9865
  return true;
@@ -9788,8 +9877,40 @@ function isUserCancelledError(error) {
9788
9877
  }
9789
9878
  return false;
9790
9879
  }
9880
+ function isWebAuthnBusyError(error) {
9881
+ if (error instanceof WebAuthnBusyError) {
9882
+ return true;
9883
+ }
9884
+ if (error instanceof Error) {
9885
+ const msg = error.message.toLowerCase();
9886
+ if (msg.includes("already in progress") || msg.includes("already pending") || msg.includes("\uC774\uBBF8 \uC694\uCCAD\uC774 \uB300\uAE30 \uC911") || // Korean locale
9887
+ msg.includes("authentication is already in progress") || msg.includes("operation already in progress") || msg.includes("request is already in progress")) {
9888
+ return true;
9889
+ }
9890
+ }
9891
+ return false;
9892
+ }
9791
9893
 
9792
9894
  // src/adapters/passkey.ts
9895
+ var pendingWebAuthnPromise = null;
9896
+ async function withWebAuthnLock(fn) {
9897
+ if (pendingWebAuthnPromise) {
9898
+ try {
9899
+ await pendingWebAuthnPromise;
9900
+ } catch {
9901
+ }
9902
+ }
9903
+ const promise = fn();
9904
+ pendingWebAuthnPromise = promise;
9905
+ try {
9906
+ const result = await promise;
9907
+ return result;
9908
+ } finally {
9909
+ if (pendingWebAuthnPromise === promise) {
9910
+ pendingWebAuthnPromise = null;
9911
+ }
9912
+ }
9913
+ }
9793
9914
  function createPasskeyAdapter(options = {}) {
9794
9915
  const rpId = options.rpId || (typeof window !== "undefined" ? window.location.hostname : "localhost");
9795
9916
  return {
@@ -9892,72 +10013,88 @@ function createPasskeyAdapter(options = {}) {
9892
10013
  type: "public-key"
9893
10014
  }
9894
10015
  ];
9895
- let credential = null;
9896
- try {
9897
- credential = await navigator.credentials.get({
9898
- publicKey: {
9899
- challenge: crypto.getRandomValues(new Uint8Array(32)),
9900
- rpId,
9901
- allowCredentials,
9902
- userVerification: USER_VERIFICATION,
9903
- // Shared constant
9904
- extensions: {
9905
- prf: {
9906
- eval: {
9907
- first: prfInput.salt.buffer
10016
+ const hints = getWebAuthnHints();
10017
+ return withWebAuthnLock(async () => {
10018
+ let credential = null;
10019
+ try {
10020
+ const requestOptions = {
10021
+ publicKey: {
10022
+ challenge: crypto.getRandomValues(new Uint8Array(32)),
10023
+ rpId,
10024
+ allowCredentials,
10025
+ userVerification: USER_VERIFICATION,
10026
+ // Shared constant
10027
+ extensions: {
10028
+ prf: {
10029
+ eval: {
10030
+ first: prfInput.salt.buffer
10031
+ }
9908
10032
  }
9909
- }
9910
- }
9911
- },
9912
- mediation: CREDENTIAL_MEDIATION
9913
- // Use shared constant
9914
- });
9915
- } catch (error) {
9916
- console.error("[PasskeyAdapter] WebAuthn get() failed:", error);
9917
- console.error("[PasskeyAdapter] Error name:", error?.name);
9918
- console.error("[PasskeyAdapter] Error message:", error?.message);
9919
- if (error?.name === "NotAllowedError") {
9920
- throw new UserCancelledError(
9921
- "User cancelled the passkey prompt or authentication was denied."
10033
+ },
10034
+ // Chrome 128+ supports hints to prioritize certain authenticator types
10035
+ // On Windows/Linux, this prioritizes QR code over USB security key prompt
10036
+ ...hints && { hints }
10037
+ },
10038
+ mediation: CREDENTIAL_MEDIATION
10039
+ // Use shared constant
10040
+ };
10041
+ credential = await navigator.credentials.get(requestOptions);
10042
+ } catch (error) {
10043
+ console.error("[PasskeyAdapter] WebAuthn get() failed:", error);
10044
+ console.error("[PasskeyAdapter] Error name:", error?.name);
10045
+ console.error("[PasskeyAdapter] Error message:", error?.message);
10046
+ const msg = (error?.message || "").toLowerCase();
10047
+ if (msg.includes("already in progress") || msg.includes("already pending") || msg.includes("\uC774\uBBF8 \uC694\uCCAD\uC774 \uB300\uAE30 \uC911") || // Korean
10048
+ msg.includes("operation already in progress") || msg.includes("request is already in progress")) {
10049
+ throw new WebAuthnBusyError(
10050
+ "Another passkey authentication is in progress. Please wait a moment and try again."
10051
+ );
10052
+ }
10053
+ if (error?.name === "NotAllowedError") {
10054
+ throw new UserCancelledError(
10055
+ "User cancelled the passkey prompt or authentication was denied."
10056
+ );
10057
+ }
10058
+ if (error?.name === "NotFoundError" || error?.name === "InvalidStateError") {
10059
+ throw new PasskeyNotFoundError(
10060
+ "No passkey found matching the provided credentialId. This may happen if the passkey was deleted or the credentialId is incorrect."
10061
+ );
10062
+ }
10063
+ if (error?.name === "NotSupportedError") {
10064
+ throw new PrfNotSupportedError(
10065
+ "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+)."
10066
+ );
10067
+ }
10068
+ throw new Error(
10069
+ `[PasskeyAdapter] WebAuthn authentication failed: ${error?.message || "Unknown error"}`
9922
10070
  );
9923
10071
  }
9924
- if (error?.name === "NotFoundError" || error?.name === "InvalidStateError") {
9925
- throw new PasskeyNotFoundError(
9926
- "No passkey found matching the provided credentialId. This may happen if the passkey was deleted or the credentialId is incorrect."
10072
+ if (!credential || !credential.response) {
10073
+ console.error(
10074
+ "[PasskeyAdapter] credential is null or missing response"
10075
+ );
10076
+ throw new Error(
10077
+ "[PasskeyAdapter] Failed to get passkey credential for PRF. The passkey prompt may have been cancelled or no matching credential was found."
9927
10078
  );
9928
10079
  }
9929
- if (error?.name === "NotSupportedError") {
9930
- throw new PrfNotSupportedError(
9931
- "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+)."
10080
+ const extensionResults = credential.getClientExtensionResults();
10081
+ if (!extensionResults.prf || !extensionResults.prf.results || !extensionResults.prf.results.first) {
10082
+ throw new Error(
10083
+ "[PasskeyAdapter] PRF extension not supported or PRF output missing"
9932
10084
  );
9933
10085
  }
9934
- throw new Error(
9935
- `[PasskeyAdapter] WebAuthn authentication failed: ${error?.message || "Unknown error"}`
9936
- );
9937
- }
9938
- if (!credential || !credential.response) {
9939
- console.error(
9940
- "[PasskeyAdapter] credential is null or missing response"
9941
- );
9942
- throw new Error(
9943
- "[PasskeyAdapter] Failed to get passkey credential for PRF. The passkey prompt may have been cancelled or no matching credential was found."
9944
- );
9945
- }
9946
- const extensionResults = credential.getClientExtensionResults();
9947
- if (!extensionResults.prf || !extensionResults.prf.results || !extensionResults.prf.results.first) {
9948
- throw new Error(
9949
- "[PasskeyAdapter] PRF extension not supported or PRF output missing"
9950
- );
9951
- }
9952
- const prfOutputBuffer = extensionResults.prf.results.first;
9953
- const prfOutput = new Uint8Array(prfOutputBuffer);
9954
- const credentialIdBytes = new Uint8Array(credential.rawId);
9955
- const credentialIdBase64 = btoa(String.fromCharCode(...credentialIdBytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
9956
- console.log("[PasskeyAdapter] WebAuthn prompt completed successfully");
9957
- return {
9958
- prfOutput,
9959
- credentialId: credentialIdBase64
9960
- };
10086
+ const prfOutputBuffer = extensionResults.prf.results.first;
10087
+ const prfOutput = new Uint8Array(prfOutputBuffer);
10088
+ const credentialIdBytes = new Uint8Array(credential.rawId);
10089
+ const credentialIdBase64 = btoa(
10090
+ String.fromCharCode(...credentialIdBytes)
10091
+ ).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
10092
+ console.log("[PasskeyAdapter] WebAuthn prompt completed successfully");
10093
+ return {
10094
+ prfOutput,
10095
+ credentialId: credentialIdBase64
10096
+ };
10097
+ });
9961
10098
  }
9962
10099
  };
9963
10100
  }
@@ -10323,7 +10460,9 @@ function VolrProvider({ config, children }) {
10323
10460
  setUser((prev) => ({ ...prev, keyStorageType }));
10324
10461
  }
10325
10462
  } catch (error2) {
10326
- console.warn("[Provider] setProvider: Failed to refresh user data:", error2);
10463
+ console.warn(
10464
+ `[Provider] setProvider: Failed to refresh user data: ${error2 instanceof Error ? error2.message : String(error2)}`
10465
+ );
10327
10466
  setUser((prev) => ({ ...prev, keyStorageType }));
10328
10467
  }
10329
10468
  }
@@ -18674,7 +18813,9 @@ async function pollTransactionStatus(txId, client, maxAttempts = 60) {
18674
18813
  const intervalMs = getPollingInterval(attempt);
18675
18814
  await new Promise((resolve) => setTimeout(resolve, intervalMs));
18676
18815
  } catch (error) {
18677
- console.error(`[pollTransactionStatus] Error polling transaction ${txId}:`, error);
18816
+ console.error(
18817
+ `[pollTransactionStatus] Error polling transaction ${txId}: ${error instanceof Error ? error.message : String(error)}`
18818
+ );
18678
18819
  const intervalMs = getPollingInterval(attempt);
18679
18820
  await new Promise((resolve) => setTimeout(resolve, intervalMs));
18680
18821
  }
@@ -18695,6 +18836,11 @@ async function sendCalls(args) {
18695
18836
  const normalizedFrom = from14;
18696
18837
  const normalizedCalls = normalizeCalls(calls);
18697
18838
  validateCalls2(normalizedCalls);
18839
+ if (!deps.provider && deps.user?.keyStorageType !== "passkey") {
18840
+ throw new Error(
18841
+ "No wallet provider configured. Please set up a Passkey provider to sign transactions. SIWE is authentication-only."
18842
+ );
18843
+ }
18698
18844
  let currentUser = deps.user;
18699
18845
  if (deps.user?.keyStorageType === "passkey" && !deps.provider) {
18700
18846
  try {
@@ -18703,7 +18849,9 @@ async function sendCalls(args) {
18703
18849
  currentUser = refreshedUser;
18704
18850
  }
18705
18851
  } catch (error) {
18706
- console.error("[sendCalls] Failed to refresh session:", error);
18852
+ console.error(
18853
+ `[sendCalls] Failed to refresh session: ${error instanceof Error ? error.message : String(error)}`
18854
+ );
18707
18855
  throw new Error(
18708
18856
  `Failed to refresh session before transaction. ${error instanceof Error ? error.message : "Unknown error"}. Please try logging in again.`
18709
18857
  );
@@ -18723,7 +18871,9 @@ async function sendCalls(args) {
18723
18871
  calls: normalizedCalls
18724
18872
  });
18725
18873
  } catch (err) {
18726
- console.error("[sendCalls] First precheck failed:", err);
18874
+ console.error(
18875
+ `[sendCalls] First precheck failed: ${err instanceof Error ? err.message : String(err)}`
18876
+ );
18727
18877
  throw err instanceof Error ? err : new Error(String(err));
18728
18878
  }
18729
18879
  if (precheckQuote.simulationSuccess === false && precheckQuote.simulationErrors?.length) {
@@ -19313,7 +19463,9 @@ function useVolrAuthCallback(options = {}) {
19313
19463
  setIsLoading(false);
19314
19464
  options.onSuccess?.(volrUser);
19315
19465
  } catch (err) {
19316
- console.error("[useVolrAuthCallback] Token exchange error:", err);
19466
+ console.error(
19467
+ `[useVolrAuthCallback] Token exchange error: ${err instanceof Error ? err.message : String(err)}`
19468
+ );
19317
19469
  let errorMsg = "Failed to complete authentication";
19318
19470
  if (err instanceof Error) {
19319
19471
  if (err.message.includes("AUTH_CODE_EXPIRED")) {
@@ -19417,7 +19569,9 @@ function useDepositListener(input) {
19417
19569
  if (cancelled) return;
19418
19570
  setStatus({ state: "listening", balance: initial });
19419
19571
  } catch (e) {
19420
- console.error("[DepositListener] Error:", e);
19572
+ console.error(
19573
+ `[DepositListener] Error: ${e instanceof Error ? e.message : String(e)}`
19574
+ );
19421
19575
  if (cancelled) return;
19422
19576
  setStatus({ state: "error", message: e.message || String(e) });
19423
19577
  return;
@@ -19453,7 +19607,9 @@ function useDepositListener(input) {
19453
19607
  return prev;
19454
19608
  });
19455
19609
  } catch (err) {
19456
- console.error("[DepositListener] Polling error:", err);
19610
+ console.error(
19611
+ `[DepositListener] Polling error: ${err instanceof Error ? err.message : String(err)}`
19612
+ );
19457
19613
  if (cancelled) return;
19458
19614
  setStatus({ state: "error", message: err.message || String(err) });
19459
19615
  }
@@ -19556,6 +19712,8 @@ async function enrollPasskey(params) {
19556
19712
  };
19557
19713
  const prfSalt = sdkCore.deriveWrapKey(tempPrfInput);
19558
19714
  const displayName = buildDisplayName(userEmail, userEvmAddress, userId);
19715
+ const authenticatorSelection = getAuthenticatorSelection();
19716
+ const hints = getWebAuthnHints();
19559
19717
  const publicKeyCredentialCreationOptions = {
19560
19718
  challenge: challenge2,
19561
19719
  rp: {
@@ -19568,7 +19726,7 @@ async function enrollPasskey(params) {
19568
19726
  displayName
19569
19727
  },
19570
19728
  pubKeyCredParams: PUBKEY_CRED_PARAMS,
19571
- authenticatorSelection: AUTHENTICATOR_SELECTION,
19729
+ authenticatorSelection,
19572
19730
  timeout: WEBAUTHN_TIMEOUT,
19573
19731
  attestation: ATTESTATION,
19574
19732
  extensions: {
@@ -19577,7 +19735,10 @@ async function enrollPasskey(params) {
19577
19735
  first: prfSalt.buffer
19578
19736
  }
19579
19737
  }
19580
- }
19738
+ },
19739
+ // Chrome 128+ supports hints to prioritize certain authenticator types
19740
+ // On Windows/Linux, this prioritizes QR code over USB security key prompt
19741
+ ...hints && { hints }
19581
19742
  };
19582
19743
  const credential = await navigator.credentials.create({
19583
19744
  publicKey: publicKeyCredentialCreationOptions
@@ -20086,7 +20247,9 @@ function useUserBalances() {
20086
20247
  });
20087
20248
  setBalances(initialBalances);
20088
20249
  }).catch((err) => {
20089
- console.error("[useUserBalances] Failed to fetch branding:", err);
20250
+ console.error(
20251
+ `[useUserBalances] Failed to fetch branding: ${err instanceof Error ? err.message : String(err)}`
20252
+ );
20090
20253
  setError(err instanceof Error ? err : new Error("Failed to fetch branding"));
20091
20254
  }).finally(() => {
20092
20255
  setIsLoadingBranding(false);
@@ -20127,7 +20290,9 @@ function useUserBalances() {
20127
20290
  error: void 0
20128
20291
  };
20129
20292
  } catch (err) {
20130
- console.error(`[useUserBalances] Failed to fetch balance for ${id}:`, err);
20293
+ console.error(
20294
+ `[useUserBalances] Failed to fetch balance for ${id}: ${err instanceof Error ? err.message : String(err)}`
20295
+ );
20131
20296
  return {
20132
20297
  id,
20133
20298
  balanceRaw: 0n,
@@ -20767,7 +20932,12 @@ function getPlatformHint(platform) {
20767
20932
  case "Windows":
20768
20933
  return {
20769
20934
  hintKey: "passkey.hint.windows",
20770
- noteKey: "passkey.hint.note"
20935
+ noteKey: "passkey.hint.windowsNote"
20936
+ };
20937
+ case "Linux":
20938
+ return {
20939
+ hintKey: "passkey.hint.linux",
20940
+ noteKey: "passkey.hint.windowsNote"
20771
20941
  };
20772
20942
  default:
20773
20943
  return {
@@ -20961,6 +21131,8 @@ async function completeMigration(params) {
20961
21131
  credentialId: tempCredentialId
20962
21132
  };
20963
21133
  const prfSalt = sdkCore.deriveWrapKey(tempPrfInput);
21134
+ const authenticatorSelection = getAuthenticatorSelection();
21135
+ const hints = getWebAuthnHints();
20964
21136
  const publicKeyCredentialCreationOptions = {
20965
21137
  challenge: challenge2,
20966
21138
  rp: {
@@ -20973,7 +21145,7 @@ async function completeMigration(params) {
20973
21145
  displayName
20974
21146
  },
20975
21147
  pubKeyCredParams: PUBKEY_CRED_PARAMS,
20976
- authenticatorSelection: AUTHENTICATOR_SELECTION,
21148
+ authenticatorSelection,
20977
21149
  timeout: WEBAUTHN_TIMEOUT,
20978
21150
  attestation: ATTESTATION,
20979
21151
  extensions: {
@@ -20982,7 +21154,10 @@ async function completeMigration(params) {
20982
21154
  first: prfSalt.buffer
20983
21155
  }
20984
21156
  }
20985
- }
21157
+ },
21158
+ // Chrome 128+ supports hints to prioritize certain authenticator types
21159
+ // On Windows/Linux, this prioritizes QR code over USB security key prompt
21160
+ ...hints && { hints }
20986
21161
  };
20987
21162
  const credential = await navigator.credentials.create({
20988
21163
  publicKey: publicKeyCredentialCreationOptions
@@ -21184,6 +21359,7 @@ exports.PasskeyNotFoundError = PasskeyNotFoundError;
21184
21359
  exports.PrfNotSupportedError = PrfNotSupportedError;
21185
21360
  exports.UserCancelledError = UserCancelledError;
21186
21361
  exports.VolrProvider = VolrProvider;
21362
+ exports.WebAuthnBusyError = WebAuthnBusyError;
21187
21363
  exports.analyzeContractForEIP7702 = analyzeContractForEIP7702;
21188
21364
  exports.buildCall = buildCall;
21189
21365
  exports.buildCalls = buildCalls;
@@ -21210,6 +21386,7 @@ exports.getWalletState = getWalletState;
21210
21386
  exports.isEIP7702Delegated = isEIP7702Delegated;
21211
21387
  exports.isInAppBrowser = isInAppBrowser;
21212
21388
  exports.isUserCancelledError = isUserCancelledError;
21389
+ exports.isWebAuthnBusyError = isWebAuthnBusyError;
21213
21390
  exports.listenForSeedRequests = listenForSeedRequests;
21214
21391
  exports.normalizeHex = normalizeHex;
21215
21392
  exports.normalizeHexArray = normalizeHexArray;
@@ -21223,6 +21400,8 @@ exports.useEIP6963 = useEIP6963;
21223
21400
  exports.useInternalAuth = useInternalAuth;
21224
21401
  exports.useMpcConnection = useMpcConnection;
21225
21402
  exports.usePasskeyEnrollment = usePasskeyEnrollment;
21403
+ exports.usePrecheck = usePrecheck;
21404
+ exports.useRelay = useRelay;
21226
21405
  exports.useUserBalances = useUserBalances;
21227
21406
  exports.useVolr = useVolr;
21228
21407
  exports.useVolrAuthCallback = useVolrAuthCallback;