@volr/react 0.1.70 → 0.1.72

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
@@ -18540,7 +18540,37 @@ function useVolr() {
18540
18540
  setProvider
18541
18541
  }
18542
18542
  });
18543
- })
18543
+ }),
18544
+ signMessage: async (message) => {
18545
+ if (!provider) {
18546
+ throw new Error(
18547
+ "No wallet provider available. Please log in with a Passkey or MPC wallet to sign messages."
18548
+ );
18549
+ }
18550
+ await provider.ensureSession({ interactive: true });
18551
+ const messageHash = hashMessage(
18552
+ typeof message === "string" ? message : { raw: message }
18553
+ );
18554
+ const hashBytes = new Uint8Array(32);
18555
+ const hex = messageHash.slice(2);
18556
+ for (let i = 0; i < 32; i++) {
18557
+ hashBytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
18558
+ }
18559
+ const sig = await provider.signMessage(hashBytes);
18560
+ const v = sig.yParity + 27;
18561
+ const rHex = Array.from(sig.r).map((b) => b.toString(16).padStart(2, "0")).join("");
18562
+ const sHex = Array.from(sig.s).map((b) => b.toString(16).padStart(2, "0")).join("");
18563
+ const vHex = v.toString(16).padStart(2, "0");
18564
+ return `0x${rHex}${sHex}${vHex}`;
18565
+ },
18566
+ signTypedData: async (typedData) => {
18567
+ if (!provider) {
18568
+ throw new Error(
18569
+ "No wallet provider available. Please log in with a Passkey or MPC wallet to sign typed data."
18570
+ );
18571
+ }
18572
+ return provider.signTypedData(typedData);
18573
+ }
18544
18574
  };
18545
18575
  },
18546
18576
  [user, config, provider, precheck, relay, getRpcUrl, setProvider, client]
@@ -18633,7 +18663,12 @@ function useVolrLogin() {
18633
18663
  async (provider) => {
18634
18664
  if (typeof window !== "undefined") {
18635
18665
  const baseUrl = apiBaseUrl.replace(/\/+$/, "");
18636
- window.location.href = `${baseUrl}/auth/${provider}?projectApiKey=${encodeURIComponent(config.projectApiKey)}`;
18666
+ const params = new URLSearchParams({
18667
+ projectApiKey: config.projectApiKey,
18668
+ callbackUrl: window.location.href
18669
+ // Return to current page after login
18670
+ });
18671
+ window.location.href = `${baseUrl}/auth/${provider}?${params.toString()}`;
18637
18672
  }
18638
18673
  },
18639
18674
  [apiBaseUrl, config.projectApiKey]
@@ -18691,45 +18726,15 @@ function useVolrLogin() {
18691
18726
  handlePasskeyComplete
18692
18727
  };
18693
18728
  }
18694
- function createAxiosInstance(baseUrl, apiKey) {
18695
- const instance = axios__default.default.create({
18696
- baseURL: baseUrl.replace(/\/+$/, ""),
18697
- // Remove trailing slashes
18698
- withCredentials: true,
18699
- // Include cookies
18700
- headers: {
18701
- "Content-Type": "application/json"
18702
- }
18703
- });
18704
- instance.interceptors.request.use((config) => {
18705
- if (apiKey) {
18706
- config.headers["X-API-Key"] = apiKey;
18707
- }
18708
- return config;
18709
- });
18710
- instance.interceptors.response.use(
18711
- (response) => response,
18712
- (error) => {
18713
- if (error.response?.data) {
18714
- const errorData = error.response.data;
18715
- if (errorData.error?.message) {
18716
- error.message = errorData.error.message;
18717
- }
18718
- }
18719
- return Promise.reject(error);
18720
- }
18721
- );
18722
- return instance;
18723
- }
18724
-
18725
- // src/hooks/useVolrAuthCallback.ts
18726
18729
  function useVolrAuthCallback(options = {}) {
18727
- const { config, setUser } = useVolrContext();
18728
- const { refreshAccessToken, setAccessToken, setRefreshToken, client } = useInternalAuth();
18730
+ const { clearUrlParams = true } = options;
18731
+ const { setUser } = useVolrContext();
18732
+ const { setAccessToken, setRefreshToken, client } = useInternalAuth();
18729
18733
  const [isLoading, setIsLoading] = react.useState(true);
18730
18734
  const [error, setError] = react.useState(null);
18731
18735
  const [isNewUser, setIsNewUser] = react.useState(false);
18732
18736
  const [user, setLocalUser] = react.useState(null);
18737
+ const hasProcessed = react.useRef(false);
18733
18738
  const toVolrUser = react.useCallback((u) => {
18734
18739
  return {
18735
18740
  id: u.id,
@@ -18745,24 +18750,35 @@ function useVolrAuthCallback(options = {}) {
18745
18750
  credentialId: u.credentialId ?? void 0
18746
18751
  };
18747
18752
  }, []);
18748
- const apiBaseUrl = resolveApiBaseUrl(config);
18749
18753
  react.useEffect(() => {
18750
18754
  const handleCallback = async () => {
18751
18755
  if (typeof window === "undefined") return;
18756
+ if (hasProcessed.current) return;
18757
+ hasProcessed.current = true;
18752
18758
  const searchParams = new URLSearchParams(window.location.search);
18753
- const success = searchParams.get("success");
18759
+ const authCode = searchParams.get("code");
18754
18760
  const errorParam = searchParams.get("error");
18755
- const userId = searchParams.get("userId");
18756
18761
  const isNew = searchParams.get("isNewUser") === "true";
18762
+ const warning = searchParams.get("warning");
18763
+ if (warning) {
18764
+ console.warn(`[Volr] ${warning}`);
18765
+ }
18757
18766
  if (errorParam) {
18758
- const errorMsg = `Authentication failed: ${errorParam}`;
18767
+ const errorMsg = `Authentication failed: ${errorParam.replace(/_/g, " ")}`;
18759
18768
  setError(errorMsg);
18760
18769
  setIsLoading(false);
18761
18770
  options.onError?.(errorMsg);
18762
18771
  return;
18763
18772
  }
18764
- if (success !== "true" || !userId) {
18765
- const errorMsg = "Invalid callback parameters";
18773
+ if (!authCode) {
18774
+ const errorMsg = "No authorization code found. Please try logging in again.";
18775
+ setError(errorMsg);
18776
+ setIsLoading(false);
18777
+ options.onError?.(errorMsg);
18778
+ return;
18779
+ }
18780
+ if (!authCode.startsWith("volr_auth_")) {
18781
+ const errorMsg = "Invalid authorization code format";
18766
18782
  setError(errorMsg);
18767
18783
  setIsLoading(false);
18768
18784
  options.onError?.(errorMsg);
@@ -18770,45 +18786,44 @@ function useVolrAuthCallback(options = {}) {
18770
18786
  }
18771
18787
  try {
18772
18788
  setIsNewUser(isNew);
18773
- await refreshAccessToken();
18774
- const api = createAxiosInstance(
18775
- apiBaseUrl,
18776
- config.projectApiKey
18777
- );
18778
- const userRes = await api.get(`/auth/onboarding/${userId}`);
18779
- if (!userRes.data?.ok) {
18780
- throw new Error("Failed to fetch user details");
18781
- }
18782
- const currentRefreshToken = client.getRefreshToken();
18783
- if (!currentRefreshToken) {
18784
- throw new Error("No refresh token available. Please log in again.");
18785
- }
18786
- const refreshRes = await api.post("/auth/refresh", { refreshToken: currentRefreshToken });
18787
- if (!refreshRes.data?.ok) {
18788
- throw new Error("Failed to refresh session");
18789
+ const response = await client.post("/auth/token/exchange", { code: authCode });
18790
+ const { user: userData, accessToken, refreshToken } = response;
18791
+ if (!accessToken) {
18792
+ throw new Error("No access token received from server");
18789
18793
  }
18790
- const userData = refreshRes.data.data.user;
18791
- const accessToken = refreshRes.data.data.accessToken;
18792
- const newRefreshToken = refreshRes.data.data.refreshToken;
18793
18794
  setAccessToken(accessToken);
18794
- if (newRefreshToken) {
18795
- setRefreshToken(newRefreshToken);
18795
+ if (refreshToken) {
18796
+ setRefreshToken(refreshToken);
18796
18797
  }
18797
18798
  const volrUser = toVolrUser(userData);
18798
18799
  setUser(volrUser);
18799
18800
  setLocalUser(volrUser);
18801
+ if (clearUrlParams && typeof window !== "undefined") {
18802
+ const url = new URL(window.location.href);
18803
+ url.search = "";
18804
+ window.history.replaceState({}, "", url.toString());
18805
+ }
18800
18806
  setIsLoading(false);
18801
18807
  options.onSuccess?.(volrUser);
18802
18808
  } catch (err) {
18803
- console.error("Callback error:", err);
18804
- const errorMsg = err.message || "Failed to complete authentication";
18809
+ console.error("[useVolrAuthCallback] Token exchange error:", err);
18810
+ let errorMsg = "Failed to complete authentication";
18811
+ if (err instanceof Error) {
18812
+ if (err.message.includes("AUTH_CODE_EXPIRED")) {
18813
+ errorMsg = "Login link has expired. Please try again.";
18814
+ } else if (err.message.includes("AUTH_INVALID_CODE")) {
18815
+ errorMsg = "Invalid login link. Please try again.";
18816
+ } else {
18817
+ errorMsg = err.message;
18818
+ }
18819
+ }
18805
18820
  setError(errorMsg);
18806
18821
  setIsLoading(false);
18807
18822
  options.onError?.(errorMsg);
18808
18823
  }
18809
18824
  };
18810
18825
  handleCallback();
18811
- }, [apiBaseUrl, config.projectApiKey, refreshAccessToken, setAccessToken, setRefreshToken, setUser, toVolrUser, client]);
18826
+ }, []);
18812
18827
  return {
18813
18828
  isLoading,
18814
18829
  error,
@@ -19358,6 +19373,36 @@ function useMpcConnection() {
19358
19373
  error
19359
19374
  };
19360
19375
  }
19376
+ function createAxiosInstance(baseUrl, apiKey) {
19377
+ const instance = axios__default.default.create({
19378
+ baseURL: baseUrl.replace(/\/+$/, ""),
19379
+ // Remove trailing slashes
19380
+ withCredentials: true,
19381
+ // Include cookies
19382
+ headers: {
19383
+ "Content-Type": "application/json"
19384
+ }
19385
+ });
19386
+ instance.interceptors.request.use((config) => {
19387
+ if (apiKey) {
19388
+ config.headers["X-API-Key"] = apiKey;
19389
+ }
19390
+ return config;
19391
+ });
19392
+ instance.interceptors.response.use(
19393
+ (response) => response,
19394
+ (error) => {
19395
+ if (error.response?.data) {
19396
+ const errorData = error.response.data;
19397
+ if (errorData.error?.message) {
19398
+ error.message = errorData.error.message;
19399
+ }
19400
+ }
19401
+ return Promise.reject(error);
19402
+ }
19403
+ );
19404
+ return instance;
19405
+ }
19361
19406
 
19362
19407
  // src/headless/blobs.ts
19363
19408
  async function uploadBlobViaPresign(params) {