@volr/react 0.1.1 → 0.1.3
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/README.md +32 -0
- package/dist/index.cjs +112 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -8
- package/dist/index.d.ts +13 -8
- package/dist/index.js +112 -20
- package/dist/index.js.map +1 -1
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -88,6 +88,38 @@ function AdvancedComponent() {
|
|
|
88
88
|
- **SSR Safe**: Works with Next.js and other SSR frameworks
|
|
89
89
|
- **Call Builders**: `buildCall()` and `buildCalls()` utilities for easy transaction building
|
|
90
90
|
|
|
91
|
+
## OAuth Handling
|
|
92
|
+
|
|
93
|
+
The SDK provides a dedicated hook `useVolrAuthCallback` to simplify handling OAuth redirects. This is useful for custom login flows where you need to process the callback from social providers (Google, Twitter, Apple).
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import { useVolrAuthCallback } from '@volr/react';
|
|
97
|
+
|
|
98
|
+
function AuthCallback() {
|
|
99
|
+
const { isLoading, error, isNewUser, user } = useVolrAuthCallback({
|
|
100
|
+
onSuccess: (user) => {
|
|
101
|
+
console.log('Logged in:', user);
|
|
102
|
+
// Navigate to dashboard or home
|
|
103
|
+
},
|
|
104
|
+
onError: (err) => {
|
|
105
|
+
console.error('Login failed:', err);
|
|
106
|
+
// Show error message or redirect to login
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
if (isLoading) return <div>Processing authentication...</div>;
|
|
111
|
+
if (error) return <div>Error: {error}</div>;
|
|
112
|
+
|
|
113
|
+
return <div>Redirecting...</div>;
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This hook automatically:
|
|
118
|
+
1. Parses URL parameters (`success`, `userId`, `isNewUser`, `error`)
|
|
119
|
+
2. Refreshes the session to establish the authentication cookie
|
|
120
|
+
3. Fetches the full user profile
|
|
121
|
+
4. Updates the global `VolrProvider` context state
|
|
122
|
+
|
|
91
123
|
## Failure Semantics
|
|
92
124
|
|
|
93
125
|
- Relay enforces strict failure-by-default:
|
package/dist/index.cjs
CHANGED
|
@@ -74,7 +74,7 @@ var safeStorage = {
|
|
|
74
74
|
}
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
-
//
|
|
77
|
+
// ../shared/src/constants/storage.ts
|
|
78
78
|
var STORAGE_KEYS = {
|
|
79
79
|
accessToken: "volr:accessToken",
|
|
80
80
|
user: "volr:user",
|
|
@@ -350,6 +350,17 @@ var SessionSync = class {
|
|
|
350
350
|
}
|
|
351
351
|
};
|
|
352
352
|
|
|
353
|
+
// src/config/backend.ts
|
|
354
|
+
var DEFAULT_API_BASE_URL = "https://api.volr.io";
|
|
355
|
+
function resolveApiBaseUrl(config) {
|
|
356
|
+
const anyConfig = config;
|
|
357
|
+
const override = anyConfig.apiBaseUrl;
|
|
358
|
+
if (override && typeof override === "string") {
|
|
359
|
+
return override.replace(/\/+$/, "");
|
|
360
|
+
}
|
|
361
|
+
return DEFAULT_API_BASE_URL;
|
|
362
|
+
}
|
|
363
|
+
|
|
353
364
|
// src/config/webauthn.ts
|
|
354
365
|
var AUTHENTICATOR_SELECTION = {
|
|
355
366
|
authenticatorAttachment: "platform",
|
|
@@ -649,18 +660,18 @@ function VolrProvider({ config, children }) {
|
|
|
649
660
|
providerCountRef.current--;
|
|
650
661
|
};
|
|
651
662
|
}, []);
|
|
663
|
+
const apiBaseUrl = resolveApiBaseUrl(config);
|
|
652
664
|
const client = react.useMemo(() => {
|
|
653
665
|
if (!config.projectApiKey) {
|
|
654
666
|
throw new Error(
|
|
655
667
|
"VolrProvider requires config.projectApiKey. Please set VITE_PROJECT_API_KEY environment variable or provide projectApiKey in config."
|
|
656
668
|
);
|
|
657
669
|
}
|
|
658
|
-
const baseUrl = config.__devApiBaseUrl || config.apiBaseUrl;
|
|
659
670
|
return new APIClient({
|
|
660
|
-
baseUrl,
|
|
671
|
+
baseUrl: apiBaseUrl,
|
|
661
672
|
apiKey: config.projectApiKey
|
|
662
673
|
});
|
|
663
|
-
}, [
|
|
674
|
+
}, [apiBaseUrl, config.projectApiKey]);
|
|
664
675
|
const [user, setUser] = react.useState(() => {
|
|
665
676
|
if (typeof window === "undefined") return null;
|
|
666
677
|
const userStr = safeStorage.getItem(STORAGE_KEYS.user);
|
|
@@ -1865,9 +1876,10 @@ function useVolrLogin() {
|
|
|
1865
1876
|
credentialId: u.credentialId ?? void 0
|
|
1866
1877
|
};
|
|
1867
1878
|
}, []);
|
|
1879
|
+
const apiBaseUrl = resolveApiBaseUrl(config);
|
|
1868
1880
|
const api = react.useMemo(
|
|
1869
|
-
() => createAxiosInstance(
|
|
1870
|
-
[
|
|
1881
|
+
() => createAxiosInstance(apiBaseUrl, config.projectApiKey),
|
|
1882
|
+
[apiBaseUrl, config.projectApiKey]
|
|
1871
1883
|
);
|
|
1872
1884
|
const requestEmailCode = react.useCallback(
|
|
1873
1885
|
async (email) => {
|
|
@@ -1935,11 +1947,11 @@ function useVolrLogin() {
|
|
|
1935
1947
|
const handleSocialLogin = react.useCallback(
|
|
1936
1948
|
async (provider) => {
|
|
1937
1949
|
if (typeof window !== "undefined") {
|
|
1938
|
-
const baseUrl =
|
|
1950
|
+
const baseUrl = apiBaseUrl.replace(/\/+$/, "");
|
|
1939
1951
|
window.location.href = `${baseUrl}/auth/${provider}`;
|
|
1940
1952
|
}
|
|
1941
1953
|
},
|
|
1942
|
-
[
|
|
1954
|
+
[apiBaseUrl]
|
|
1943
1955
|
);
|
|
1944
1956
|
const requestSiweNonce = react.useCallback(async () => {
|
|
1945
1957
|
const response = await api.get("/auth/siwe/nonce");
|
|
@@ -2011,6 +2023,91 @@ function useVolrLogin() {
|
|
|
2011
2023
|
handlePasskeyComplete
|
|
2012
2024
|
};
|
|
2013
2025
|
}
|
|
2026
|
+
function useVolrAuthCallback(options = {}) {
|
|
2027
|
+
const { config, setUser } = useVolr();
|
|
2028
|
+
const { refreshAccessToken, setAccessToken } = useInternalAuth();
|
|
2029
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
2030
|
+
const [error, setError] = react.useState(null);
|
|
2031
|
+
const [isNewUser, setIsNewUser] = react.useState(false);
|
|
2032
|
+
const [user, setLocalUser] = react.useState(null);
|
|
2033
|
+
const toVolrUser = react.useCallback((u) => {
|
|
2034
|
+
return {
|
|
2035
|
+
id: u.id,
|
|
2036
|
+
email: u.email,
|
|
2037
|
+
accountId: u.accountId ?? void 0,
|
|
2038
|
+
evmAddress: u.evmAddress,
|
|
2039
|
+
keyStorageType: u.keyStorageType ?? void 0,
|
|
2040
|
+
signerType: u.signerType ?? void 0,
|
|
2041
|
+
walletConnector: u.walletConnector ?? void 0,
|
|
2042
|
+
lastWalletChainId: u.lastWalletChainId ?? void 0,
|
|
2043
|
+
blobUrl: u.blobUrl ?? void 0,
|
|
2044
|
+
prfInput: u.prfInput ?? void 0,
|
|
2045
|
+
credentialId: u.credentialId ?? void 0
|
|
2046
|
+
};
|
|
2047
|
+
}, []);
|
|
2048
|
+
const apiBaseUrl = resolveApiBaseUrl(config);
|
|
2049
|
+
react.useEffect(() => {
|
|
2050
|
+
const handleCallback = async () => {
|
|
2051
|
+
if (typeof window === "undefined") return;
|
|
2052
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
2053
|
+
const success = searchParams.get("success");
|
|
2054
|
+
const errorParam = searchParams.get("error");
|
|
2055
|
+
const userId = searchParams.get("userId");
|
|
2056
|
+
const isNew = searchParams.get("isNewUser") === "true";
|
|
2057
|
+
if (errorParam) {
|
|
2058
|
+
const errorMsg = `Authentication failed: ${errorParam}`;
|
|
2059
|
+
setError(errorMsg);
|
|
2060
|
+
setIsLoading(false);
|
|
2061
|
+
options.onError?.(errorMsg);
|
|
2062
|
+
return;
|
|
2063
|
+
}
|
|
2064
|
+
if (success !== "true" || !userId) {
|
|
2065
|
+
const errorMsg = "Invalid callback parameters";
|
|
2066
|
+
setError(errorMsg);
|
|
2067
|
+
setIsLoading(false);
|
|
2068
|
+
options.onError?.(errorMsg);
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
try {
|
|
2072
|
+
setIsNewUser(isNew);
|
|
2073
|
+
await refreshAccessToken();
|
|
2074
|
+
const api = createAxiosInstance(
|
|
2075
|
+
apiBaseUrl,
|
|
2076
|
+
config.projectApiKey
|
|
2077
|
+
);
|
|
2078
|
+
const userRes = await api.get(`/auth/onboarding/${userId}`);
|
|
2079
|
+
if (!userRes.data?.ok) {
|
|
2080
|
+
throw new Error("Failed to fetch user details");
|
|
2081
|
+
}
|
|
2082
|
+
const refreshRes = await api.post("/auth/refresh");
|
|
2083
|
+
if (!refreshRes.data?.ok) {
|
|
2084
|
+
throw new Error("Failed to refresh session");
|
|
2085
|
+
}
|
|
2086
|
+
const userData = refreshRes.data.data.user;
|
|
2087
|
+
const accessToken = refreshRes.data.data.accessToken;
|
|
2088
|
+
setAccessToken(accessToken);
|
|
2089
|
+
const volrUser = toVolrUser(userData);
|
|
2090
|
+
setUser(volrUser);
|
|
2091
|
+
setLocalUser(volrUser);
|
|
2092
|
+
setIsLoading(false);
|
|
2093
|
+
options.onSuccess?.(volrUser);
|
|
2094
|
+
} catch (err) {
|
|
2095
|
+
console.error("Callback error:", err);
|
|
2096
|
+
const errorMsg = err.message || "Failed to complete authentication";
|
|
2097
|
+
setError(errorMsg);
|
|
2098
|
+
setIsLoading(false);
|
|
2099
|
+
options.onError?.(errorMsg);
|
|
2100
|
+
}
|
|
2101
|
+
};
|
|
2102
|
+
handleCallback();
|
|
2103
|
+
}, [apiBaseUrl, config.projectApiKey, refreshAccessToken, setAccessToken, setUser, toVolrUser]);
|
|
2104
|
+
return {
|
|
2105
|
+
isLoading,
|
|
2106
|
+
error,
|
|
2107
|
+
isNewUser,
|
|
2108
|
+
user
|
|
2109
|
+
};
|
|
2110
|
+
}
|
|
2014
2111
|
async function jsonRpc(rpcUrl, method, params) {
|
|
2015
2112
|
const payload = {
|
|
2016
2113
|
jsonrpc: "2.0",
|
|
@@ -2304,6 +2401,7 @@ function usePasskeyEnrollment() {
|
|
|
2304
2401
|
const [isEnrolling, setIsEnrolling] = react.useState(false);
|
|
2305
2402
|
const [error, setError] = react.useState(null);
|
|
2306
2403
|
const isEnrollingRef = react.useRef(false);
|
|
2404
|
+
const apiBaseUrl = resolveApiBaseUrl(config);
|
|
2307
2405
|
const enroll = react.useCallback(async () => {
|
|
2308
2406
|
if (isEnrollingRef.current || isEnrolling) return;
|
|
2309
2407
|
isEnrollingRef.current = true;
|
|
@@ -2319,13 +2417,15 @@ function usePasskeyEnrollment() {
|
|
|
2319
2417
|
}
|
|
2320
2418
|
const accessToken = client.getAccessToken();
|
|
2321
2419
|
if (!accessToken) {
|
|
2322
|
-
throw new Error(
|
|
2420
|
+
throw new Error(
|
|
2421
|
+
"Access token is required for passkey enrollment. Please login first."
|
|
2422
|
+
);
|
|
2323
2423
|
}
|
|
2324
2424
|
const projectId = user.id;
|
|
2325
2425
|
setStep("encrypting");
|
|
2326
2426
|
const result = await enrollPasskey({
|
|
2327
2427
|
client,
|
|
2328
|
-
baseUrl:
|
|
2428
|
+
baseUrl: apiBaseUrl,
|
|
2329
2429
|
apiKey: config.projectApiKey,
|
|
2330
2430
|
userId: user.id,
|
|
2331
2431
|
userEmail: user.email,
|
|
@@ -2370,15 +2470,7 @@ function usePasskeyEnrollment() {
|
|
|
2370
2470
|
setIsEnrolling(false);
|
|
2371
2471
|
isEnrollingRef.current = false;
|
|
2372
2472
|
}
|
|
2373
|
-
}, [
|
|
2374
|
-
client,
|
|
2375
|
-
config.apiBaseUrl,
|
|
2376
|
-
config.projectApiKey,
|
|
2377
|
-
user,
|
|
2378
|
-
setProvider,
|
|
2379
|
-
setUser,
|
|
2380
|
-
isEnrolling
|
|
2381
|
-
]);
|
|
2473
|
+
}, [apiBaseUrl, client, config.projectApiKey, user, setProvider, setUser, isEnrolling]);
|
|
2382
2474
|
return {
|
|
2383
2475
|
enroll,
|
|
2384
2476
|
step,
|
|
@@ -2605,6 +2697,7 @@ exports.usePasskeyEnrollment = usePasskeyEnrollment;
|
|
|
2605
2697
|
exports.usePrecheck = usePrecheck;
|
|
2606
2698
|
exports.useRelay = useRelay;
|
|
2607
2699
|
exports.useVolr = useVolr;
|
|
2700
|
+
exports.useVolrAuthCallback = useVolrAuthCallback;
|
|
2608
2701
|
exports.useVolrLogin = useVolrLogin;
|
|
2609
2702
|
exports.useVolrWallet = useVolrWallet;
|
|
2610
2703
|
//# sourceMappingURL=index.cjs.map
|