@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.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { KeyStorageType as KeyStorageType$1, WalletProviderPort, PrecheckInput, PrecheckQuote, RelayInput, RelayResult, Call, PasskeyProviderPort } from '@volr/sdk-core';
3
+ import { KeyStorageType as KeyStorageType$1, WalletProviderPort, PrecheckInput, PrecheckQuote, RelayInput, RelayResult, Call, TypedDataInput, PasskeyProviderPort } from '@volr/sdk-core';
4
4
  export { AuthorizationTuple, Call, MpcTransport, PrecheckInput, PrecheckQuote, PrfInput, RelayInput, RelayMode, RelayResult, SessionAuth, UploadBlobOptions, createMasterKeyProvider, createMpcProvider, createPasskeyProvider, deriveEvmKey, deriveWrapKey, sealMasterSeed, uploadBlob } from '@volr/sdk-core';
5
5
  import { Address, Abi, PublicClient } from 'viem';
6
6
 
@@ -434,6 +434,39 @@ type EvmClient = {
434
434
  * Send a batch of transactions
435
435
  */
436
436
  sendBatch: SendBatchOverloads;
437
+ /**
438
+ * Sign a message (EIP-191 personal_sign)
439
+ * @param message - String or bytes to sign
440
+ * @returns Signature hex string
441
+ * @example
442
+ * ```ts
443
+ * const signature = await evm(1).signMessage('Hello, World!');
444
+ * // or with raw bytes
445
+ * const signature = await evm(1).signMessage(new Uint8Array([1, 2, 3]));
446
+ * ```
447
+ */
448
+ signMessage: (message: string | Uint8Array) => Promise<`0x${string}`>;
449
+ /**
450
+ * Sign EIP-712 typed data
451
+ * @param typedData - Typed data with domain, types, and message
452
+ * @returns Signature hex string
453
+ * @example
454
+ * ```ts
455
+ * const signature = await evm(1).signTypedData({
456
+ * domain: {
457
+ * name: 'MyApp',
458
+ * version: '1',
459
+ * chainId: 1,
460
+ * verifyingContract: '0x...',
461
+ * },
462
+ * types: {
463
+ * Message: [{ name: 'content', type: 'string' }],
464
+ * },
465
+ * message: { content: 'Hello' },
466
+ * });
467
+ * ```
468
+ */
469
+ signTypedData: (typedData: TypedDataInput) => Promise<`0x${string}`>;
437
470
  };
438
471
  /**
439
472
  * Volr client interface
@@ -526,15 +559,52 @@ interface UseVolrLoginReturn {
526
559
  declare function useVolrLogin(): UseVolrLoginReturn;
527
560
 
528
561
  interface UseVolrAuthCallbackOptions {
562
+ /**
563
+ * Called when OAuth authentication is successful
564
+ */
529
565
  onSuccess?: (user: VolrUser) => void;
566
+ /**
567
+ * Called when OAuth authentication fails
568
+ */
530
569
  onError?: (error: string) => void;
570
+ /**
571
+ * If true, automatically clears the URL query params after processing
572
+ * @default true
573
+ */
574
+ clearUrlParams?: boolean;
531
575
  }
532
576
  interface UseVolrAuthCallbackReturn {
577
+ /** Whether the callback is being processed */
533
578
  isLoading: boolean;
579
+ /** Error message if authentication failed */
534
580
  error: string | null;
581
+ /** Whether this is a new user (first time sign in) */
535
582
  isNewUser: boolean;
583
+ /** The authenticated user object */
536
584
  user: VolrUser | null;
537
585
  }
586
+ /**
587
+ * Hook to handle OAuth callback after social login redirect.
588
+ *
589
+ * Usage:
590
+ * ```tsx
591
+ * // In your /auth/callback page
592
+ * function AuthCallbackPage() {
593
+ * const { isLoading, error, user, isNewUser } = useVolrAuthCallback({
594
+ * onSuccess: (user) => {
595
+ * navigate('/dashboard');
596
+ * },
597
+ * onError: (error) => {
598
+ * navigate('/login?error=' + encodeURIComponent(error));
599
+ * },
600
+ * });
601
+ *
602
+ * if (isLoading) return <LoadingSpinner />;
603
+ * if (error) return <ErrorMessage message={error} />;
604
+ * return null;
605
+ * }
606
+ * ```
607
+ */
538
608
  declare function useVolrAuthCallback(options?: UseVolrAuthCallbackOptions): UseVolrAuthCallbackReturn;
539
609
 
540
610
  type Erc20Token = {
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { KeyStorageType as KeyStorageType$1, WalletProviderPort, PrecheckInput, PrecheckQuote, RelayInput, RelayResult, Call, PasskeyProviderPort } from '@volr/sdk-core';
3
+ import { KeyStorageType as KeyStorageType$1, WalletProviderPort, PrecheckInput, PrecheckQuote, RelayInput, RelayResult, Call, TypedDataInput, PasskeyProviderPort } from '@volr/sdk-core';
4
4
  export { AuthorizationTuple, Call, MpcTransport, PrecheckInput, PrecheckQuote, PrfInput, RelayInput, RelayMode, RelayResult, SessionAuth, UploadBlobOptions, createMasterKeyProvider, createMpcProvider, createPasskeyProvider, deriveEvmKey, deriveWrapKey, sealMasterSeed, uploadBlob } from '@volr/sdk-core';
5
5
  import { Address, Abi, PublicClient } from 'viem';
6
6
 
@@ -434,6 +434,39 @@ type EvmClient = {
434
434
  * Send a batch of transactions
435
435
  */
436
436
  sendBatch: SendBatchOverloads;
437
+ /**
438
+ * Sign a message (EIP-191 personal_sign)
439
+ * @param message - String or bytes to sign
440
+ * @returns Signature hex string
441
+ * @example
442
+ * ```ts
443
+ * const signature = await evm(1).signMessage('Hello, World!');
444
+ * // or with raw bytes
445
+ * const signature = await evm(1).signMessage(new Uint8Array([1, 2, 3]));
446
+ * ```
447
+ */
448
+ signMessage: (message: string | Uint8Array) => Promise<`0x${string}`>;
449
+ /**
450
+ * Sign EIP-712 typed data
451
+ * @param typedData - Typed data with domain, types, and message
452
+ * @returns Signature hex string
453
+ * @example
454
+ * ```ts
455
+ * const signature = await evm(1).signTypedData({
456
+ * domain: {
457
+ * name: 'MyApp',
458
+ * version: '1',
459
+ * chainId: 1,
460
+ * verifyingContract: '0x...',
461
+ * },
462
+ * types: {
463
+ * Message: [{ name: 'content', type: 'string' }],
464
+ * },
465
+ * message: { content: 'Hello' },
466
+ * });
467
+ * ```
468
+ */
469
+ signTypedData: (typedData: TypedDataInput) => Promise<`0x${string}`>;
437
470
  };
438
471
  /**
439
472
  * Volr client interface
@@ -526,15 +559,52 @@ interface UseVolrLoginReturn {
526
559
  declare function useVolrLogin(): UseVolrLoginReturn;
527
560
 
528
561
  interface UseVolrAuthCallbackOptions {
562
+ /**
563
+ * Called when OAuth authentication is successful
564
+ */
529
565
  onSuccess?: (user: VolrUser) => void;
566
+ /**
567
+ * Called when OAuth authentication fails
568
+ */
530
569
  onError?: (error: string) => void;
570
+ /**
571
+ * If true, automatically clears the URL query params after processing
572
+ * @default true
573
+ */
574
+ clearUrlParams?: boolean;
531
575
  }
532
576
  interface UseVolrAuthCallbackReturn {
577
+ /** Whether the callback is being processed */
533
578
  isLoading: boolean;
579
+ /** Error message if authentication failed */
534
580
  error: string | null;
581
+ /** Whether this is a new user (first time sign in) */
535
582
  isNewUser: boolean;
583
+ /** The authenticated user object */
536
584
  user: VolrUser | null;
537
585
  }
586
+ /**
587
+ * Hook to handle OAuth callback after social login redirect.
588
+ *
589
+ * Usage:
590
+ * ```tsx
591
+ * // In your /auth/callback page
592
+ * function AuthCallbackPage() {
593
+ * const { isLoading, error, user, isNewUser } = useVolrAuthCallback({
594
+ * onSuccess: (user) => {
595
+ * navigate('/dashboard');
596
+ * },
597
+ * onError: (error) => {
598
+ * navigate('/login?error=' + encodeURIComponent(error));
599
+ * },
600
+ * });
601
+ *
602
+ * if (isLoading) return <LoadingSpinner />;
603
+ * if (error) return <ErrorMessage message={error} />;
604
+ * return null;
605
+ * }
606
+ * ```
607
+ */
538
608
  declare function useVolrAuthCallback(options?: UseVolrAuthCallbackOptions): UseVolrAuthCallbackReturn;
539
609
 
540
610
  type Erc20Token = {
package/dist/index.js CHANGED
@@ -18516,7 +18516,37 @@ function useVolr() {
18516
18516
  setProvider
18517
18517
  }
18518
18518
  });
18519
- })
18519
+ }),
18520
+ signMessage: async (message) => {
18521
+ if (!provider) {
18522
+ throw new Error(
18523
+ "No wallet provider available. Please log in with a Passkey or MPC wallet to sign messages."
18524
+ );
18525
+ }
18526
+ await provider.ensureSession({ interactive: true });
18527
+ const messageHash = hashMessage(
18528
+ typeof message === "string" ? message : { raw: message }
18529
+ );
18530
+ const hashBytes = new Uint8Array(32);
18531
+ const hex = messageHash.slice(2);
18532
+ for (let i = 0; i < 32; i++) {
18533
+ hashBytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
18534
+ }
18535
+ const sig = await provider.signMessage(hashBytes);
18536
+ const v = sig.yParity + 27;
18537
+ const rHex = Array.from(sig.r).map((b) => b.toString(16).padStart(2, "0")).join("");
18538
+ const sHex = Array.from(sig.s).map((b) => b.toString(16).padStart(2, "0")).join("");
18539
+ const vHex = v.toString(16).padStart(2, "0");
18540
+ return `0x${rHex}${sHex}${vHex}`;
18541
+ },
18542
+ signTypedData: async (typedData) => {
18543
+ if (!provider) {
18544
+ throw new Error(
18545
+ "No wallet provider available. Please log in with a Passkey or MPC wallet to sign typed data."
18546
+ );
18547
+ }
18548
+ return provider.signTypedData(typedData);
18549
+ }
18520
18550
  };
18521
18551
  },
18522
18552
  [user, config, provider, precheck, relay, getRpcUrl, setProvider, client]
@@ -18609,7 +18639,12 @@ function useVolrLogin() {
18609
18639
  async (provider) => {
18610
18640
  if (typeof window !== "undefined") {
18611
18641
  const baseUrl = apiBaseUrl.replace(/\/+$/, "");
18612
- window.location.href = `${baseUrl}/auth/${provider}?projectApiKey=${encodeURIComponent(config.projectApiKey)}`;
18642
+ const params = new URLSearchParams({
18643
+ projectApiKey: config.projectApiKey,
18644
+ callbackUrl: window.location.href
18645
+ // Return to current page after login
18646
+ });
18647
+ window.location.href = `${baseUrl}/auth/${provider}?${params.toString()}`;
18613
18648
  }
18614
18649
  },
18615
18650
  [apiBaseUrl, config.projectApiKey]
@@ -18667,45 +18702,15 @@ function useVolrLogin() {
18667
18702
  handlePasskeyComplete
18668
18703
  };
18669
18704
  }
18670
- function createAxiosInstance(baseUrl, apiKey) {
18671
- const instance = axios.create({
18672
- baseURL: baseUrl.replace(/\/+$/, ""),
18673
- // Remove trailing slashes
18674
- withCredentials: true,
18675
- // Include cookies
18676
- headers: {
18677
- "Content-Type": "application/json"
18678
- }
18679
- });
18680
- instance.interceptors.request.use((config) => {
18681
- if (apiKey) {
18682
- config.headers["X-API-Key"] = apiKey;
18683
- }
18684
- return config;
18685
- });
18686
- instance.interceptors.response.use(
18687
- (response) => response,
18688
- (error) => {
18689
- if (error.response?.data) {
18690
- const errorData = error.response.data;
18691
- if (errorData.error?.message) {
18692
- error.message = errorData.error.message;
18693
- }
18694
- }
18695
- return Promise.reject(error);
18696
- }
18697
- );
18698
- return instance;
18699
- }
18700
-
18701
- // src/hooks/useVolrAuthCallback.ts
18702
18705
  function useVolrAuthCallback(options = {}) {
18703
- const { config, setUser } = useVolrContext();
18704
- const { refreshAccessToken, setAccessToken, setRefreshToken, client } = useInternalAuth();
18706
+ const { clearUrlParams = true } = options;
18707
+ const { setUser } = useVolrContext();
18708
+ const { setAccessToken, setRefreshToken, client } = useInternalAuth();
18705
18709
  const [isLoading, setIsLoading] = useState(true);
18706
18710
  const [error, setError] = useState(null);
18707
18711
  const [isNewUser, setIsNewUser] = useState(false);
18708
18712
  const [user, setLocalUser] = useState(null);
18713
+ const hasProcessed = useRef(false);
18709
18714
  const toVolrUser = useCallback((u) => {
18710
18715
  return {
18711
18716
  id: u.id,
@@ -18721,24 +18726,35 @@ function useVolrAuthCallback(options = {}) {
18721
18726
  credentialId: u.credentialId ?? void 0
18722
18727
  };
18723
18728
  }, []);
18724
- const apiBaseUrl = resolveApiBaseUrl(config);
18725
18729
  useEffect(() => {
18726
18730
  const handleCallback = async () => {
18727
18731
  if (typeof window === "undefined") return;
18732
+ if (hasProcessed.current) return;
18733
+ hasProcessed.current = true;
18728
18734
  const searchParams = new URLSearchParams(window.location.search);
18729
- const success = searchParams.get("success");
18735
+ const authCode = searchParams.get("code");
18730
18736
  const errorParam = searchParams.get("error");
18731
- const userId = searchParams.get("userId");
18732
18737
  const isNew = searchParams.get("isNewUser") === "true";
18738
+ const warning = searchParams.get("warning");
18739
+ if (warning) {
18740
+ console.warn(`[Volr] ${warning}`);
18741
+ }
18733
18742
  if (errorParam) {
18734
- const errorMsg = `Authentication failed: ${errorParam}`;
18743
+ const errorMsg = `Authentication failed: ${errorParam.replace(/_/g, " ")}`;
18735
18744
  setError(errorMsg);
18736
18745
  setIsLoading(false);
18737
18746
  options.onError?.(errorMsg);
18738
18747
  return;
18739
18748
  }
18740
- if (success !== "true" || !userId) {
18741
- const errorMsg = "Invalid callback parameters";
18749
+ if (!authCode) {
18750
+ const errorMsg = "No authorization code found. Please try logging in again.";
18751
+ setError(errorMsg);
18752
+ setIsLoading(false);
18753
+ options.onError?.(errorMsg);
18754
+ return;
18755
+ }
18756
+ if (!authCode.startsWith("volr_auth_")) {
18757
+ const errorMsg = "Invalid authorization code format";
18742
18758
  setError(errorMsg);
18743
18759
  setIsLoading(false);
18744
18760
  options.onError?.(errorMsg);
@@ -18746,45 +18762,44 @@ function useVolrAuthCallback(options = {}) {
18746
18762
  }
18747
18763
  try {
18748
18764
  setIsNewUser(isNew);
18749
- await refreshAccessToken();
18750
- const api = createAxiosInstance(
18751
- apiBaseUrl,
18752
- config.projectApiKey
18753
- );
18754
- const userRes = await api.get(`/auth/onboarding/${userId}`);
18755
- if (!userRes.data?.ok) {
18756
- throw new Error("Failed to fetch user details");
18757
- }
18758
- const currentRefreshToken = client.getRefreshToken();
18759
- if (!currentRefreshToken) {
18760
- throw new Error("No refresh token available. Please log in again.");
18761
- }
18762
- const refreshRes = await api.post("/auth/refresh", { refreshToken: currentRefreshToken });
18763
- if (!refreshRes.data?.ok) {
18764
- throw new Error("Failed to refresh session");
18765
+ const response = await client.post("/auth/token/exchange", { code: authCode });
18766
+ const { user: userData, accessToken, refreshToken } = response;
18767
+ if (!accessToken) {
18768
+ throw new Error("No access token received from server");
18765
18769
  }
18766
- const userData = refreshRes.data.data.user;
18767
- const accessToken = refreshRes.data.data.accessToken;
18768
- const newRefreshToken = refreshRes.data.data.refreshToken;
18769
18770
  setAccessToken(accessToken);
18770
- if (newRefreshToken) {
18771
- setRefreshToken(newRefreshToken);
18771
+ if (refreshToken) {
18772
+ setRefreshToken(refreshToken);
18772
18773
  }
18773
18774
  const volrUser = toVolrUser(userData);
18774
18775
  setUser(volrUser);
18775
18776
  setLocalUser(volrUser);
18777
+ if (clearUrlParams && typeof window !== "undefined") {
18778
+ const url = new URL(window.location.href);
18779
+ url.search = "";
18780
+ window.history.replaceState({}, "", url.toString());
18781
+ }
18776
18782
  setIsLoading(false);
18777
18783
  options.onSuccess?.(volrUser);
18778
18784
  } catch (err) {
18779
- console.error("Callback error:", err);
18780
- const errorMsg = err.message || "Failed to complete authentication";
18785
+ console.error("[useVolrAuthCallback] Token exchange error:", err);
18786
+ let errorMsg = "Failed to complete authentication";
18787
+ if (err instanceof Error) {
18788
+ if (err.message.includes("AUTH_CODE_EXPIRED")) {
18789
+ errorMsg = "Login link has expired. Please try again.";
18790
+ } else if (err.message.includes("AUTH_INVALID_CODE")) {
18791
+ errorMsg = "Invalid login link. Please try again.";
18792
+ } else {
18793
+ errorMsg = err.message;
18794
+ }
18795
+ }
18781
18796
  setError(errorMsg);
18782
18797
  setIsLoading(false);
18783
18798
  options.onError?.(errorMsg);
18784
18799
  }
18785
18800
  };
18786
18801
  handleCallback();
18787
- }, [apiBaseUrl, config.projectApiKey, refreshAccessToken, setAccessToken, setRefreshToken, setUser, toVolrUser, client]);
18802
+ }, []);
18788
18803
  return {
18789
18804
  isLoading,
18790
18805
  error,
@@ -19334,6 +19349,36 @@ function useMpcConnection() {
19334
19349
  error
19335
19350
  };
19336
19351
  }
19352
+ function createAxiosInstance(baseUrl, apiKey) {
19353
+ const instance = axios.create({
19354
+ baseURL: baseUrl.replace(/\/+$/, ""),
19355
+ // Remove trailing slashes
19356
+ withCredentials: true,
19357
+ // Include cookies
19358
+ headers: {
19359
+ "Content-Type": "application/json"
19360
+ }
19361
+ });
19362
+ instance.interceptors.request.use((config) => {
19363
+ if (apiKey) {
19364
+ config.headers["X-API-Key"] = apiKey;
19365
+ }
19366
+ return config;
19367
+ });
19368
+ instance.interceptors.response.use(
19369
+ (response) => response,
19370
+ (error) => {
19371
+ if (error.response?.data) {
19372
+ const errorData = error.response.data;
19373
+ if (errorData.error?.message) {
19374
+ error.message = errorData.error.message;
19375
+ }
19376
+ }
19377
+ return Promise.reject(error);
19378
+ }
19379
+ );
19380
+ return instance;
19381
+ }
19337
19382
 
19338
19383
  // src/headless/blobs.ts
19339
19384
  async function uploadBlobViaPresign(params) {