@pear-protocol/hyperliquid-sdk 0.1.13-beta.1 → 0.1.13
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/clients/auth.d.ts +1 -1
- package/dist/hooks/useAuth.d.ts +1 -3
- package/dist/index.d.ts +0 -2
- package/dist/index.js +156 -340
- package/dist/provider.d.ts +1 -1
- package/dist/store/hyperliquidDataStore.d.ts +2 -2
- package/dist/store/userDataStore.d.ts +0 -2
- package/dist/utils/http.d.ts +2 -2
- package/package.json +1 -1
package/dist/clients/auth.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ApiResponse, GetEIP712MessageResponse, AuthenticateRequest, AuthenticateResponse, RefreshTokenResponse, LogoutResponse } from
|
|
1
|
+
import type { ApiResponse, GetEIP712MessageResponse, AuthenticateRequest, AuthenticateResponse, RefreshTokenResponse, LogoutResponse } from '../types';
|
|
2
2
|
export declare function getEIP712Message(baseUrl: string, address: string, clientId: string): Promise<ApiResponse<GetEIP712MessageResponse>>;
|
|
3
3
|
export declare function authenticate(baseUrl: string, body: AuthenticateRequest): Promise<ApiResponse<AuthenticateResponse>>;
|
|
4
4
|
/**
|
package/dist/hooks/useAuth.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GetEIP712MessageResponse } from
|
|
1
|
+
import type { GetEIP712MessageResponse } from "../types";
|
|
2
2
|
export declare function useAuth(): {
|
|
3
3
|
readonly isReady: boolean;
|
|
4
4
|
readonly isAuthenticated: boolean;
|
|
@@ -10,6 +10,4 @@ export declare function useAuth(): {
|
|
|
10
10
|
readonly loginWithPrivyToken: (address: string, appId: string, privyAccessToken: string) => Promise<void>;
|
|
11
11
|
readonly refreshTokens: () => Promise<import("../types").RefreshTokenResponse>;
|
|
12
12
|
readonly logout: () => Promise<void>;
|
|
13
|
-
readonly clearSession: () => void;
|
|
14
|
-
readonly setAddress: (address: string | null) => void;
|
|
15
13
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1429,8 +1429,6 @@ declare function useAuth(): {
|
|
|
1429
1429
|
readonly loginWithPrivyToken: (address: string, appId: string, privyAccessToken: string) => Promise<void>;
|
|
1430
1430
|
readonly refreshTokens: () => Promise<RefreshTokenResponse>;
|
|
1431
1431
|
readonly logout: () => Promise<void>;
|
|
1432
|
-
readonly clearSession: () => void;
|
|
1433
|
-
readonly setAddress: (address: string | null) => void;
|
|
1434
1432
|
};
|
|
1435
1433
|
|
|
1436
1434
|
interface MarginRequiredPerCollateral {
|
package/dist/index.js
CHANGED
|
@@ -65,15 +65,21 @@ const useUserData = create((set) => ({
|
|
|
65
65
|
userExtraAgents: null,
|
|
66
66
|
spotState: null,
|
|
67
67
|
userAbstractionMode: null,
|
|
68
|
-
isReady: false,
|
|
69
68
|
setUserAbstractionMode: (value) => set({ userAbstractionMode: value }),
|
|
70
69
|
setAccessToken: (token) => set({ accessToken: token }),
|
|
71
70
|
setRefreshToken: (token) => set({ refreshToken: token }),
|
|
72
71
|
setIsAuthenticated: (value) => set({ isAuthenticated: value }),
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
setAddress: (address) => set(() => {
|
|
73
|
+
if (typeof window !== 'undefined') {
|
|
74
|
+
if (address) {
|
|
75
|
+
window.localStorage.setItem('address', address);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
window.localStorage.removeItem('address');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return { address };
|
|
82
|
+
}),
|
|
77
83
|
setTradeHistories: (value) => set({ tradeHistories: value }),
|
|
78
84
|
setRawOpenPositions: (value) => set({ rawOpenPositions: value }),
|
|
79
85
|
setOpenOrders: (value) => set({ openOrders: value }),
|
|
@@ -82,11 +88,10 @@ const useUserData = create((set) => ({
|
|
|
82
88
|
setNotifications: (value) => set({ notifications: value }),
|
|
83
89
|
setSpotState: (value) => set({ spotState: value }),
|
|
84
90
|
clean: () => set({
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// address: null,
|
|
91
|
+
accessToken: null,
|
|
92
|
+
refreshToken: null,
|
|
93
|
+
isAuthenticated: false,
|
|
94
|
+
address: null,
|
|
90
95
|
tradeHistories: null,
|
|
91
96
|
rawOpenPositions: null,
|
|
92
97
|
openOrders: null,
|
|
@@ -546,7 +551,7 @@ const useHyperliquidData = create((set) => ({
|
|
|
546
551
|
tokenMetadata: refreshTokenMetadata(state, { allMids: value }),
|
|
547
552
|
})),
|
|
548
553
|
setActiveAssetData: (value) => set((state) => {
|
|
549
|
-
const activeAssetData = typeof value ===
|
|
554
|
+
const activeAssetData = typeof value === 'function' ? value(state.activeAssetData) : value;
|
|
550
555
|
return {
|
|
551
556
|
activeAssetData,
|
|
552
557
|
tokenMetadata: refreshTokenMetadata(state, { activeAssetData }),
|
|
@@ -586,10 +591,7 @@ const useHyperliquidData = create((set) => ({
|
|
|
586
591
|
setCandleData: (value) => set({ candleData: value }),
|
|
587
592
|
upsertActiveAssetData: (key, value) => set((state) => {
|
|
588
593
|
var _a;
|
|
589
|
-
const activeAssetData = {
|
|
590
|
-
...((_a = state.activeAssetData) !== null && _a !== void 0 ? _a : {}),
|
|
591
|
-
[key]: value,
|
|
592
|
-
};
|
|
594
|
+
const activeAssetData = { ...((_a = state.activeAssetData) !== null && _a !== void 0 ? _a : {}), [key]: value };
|
|
593
595
|
return {
|
|
594
596
|
activeAssetData,
|
|
595
597
|
tokenMetadata: refreshTokenMetadata(state, { activeAssetData }, { symbols: [key] }),
|
|
@@ -915,9 +917,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
915
917
|
try {
|
|
916
918
|
const message = JSON.parse(event.data);
|
|
917
919
|
// Handle subscription responses
|
|
918
|
-
if (
|
|
920
|
+
if ('success' in message || 'error' in message) {
|
|
919
921
|
if (message.error) {
|
|
920
|
-
console.error(
|
|
922
|
+
console.error('[HyperLiquid WS] Subscription error:', message.error);
|
|
921
923
|
setLastError(message.error);
|
|
922
924
|
}
|
|
923
925
|
else {
|
|
@@ -926,44 +928,44 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
926
928
|
return;
|
|
927
929
|
}
|
|
928
930
|
// Handle channel data messages
|
|
929
|
-
if (
|
|
931
|
+
if ('channel' in message && 'data' in message) {
|
|
930
932
|
const response = message;
|
|
931
933
|
switch (response.channel) {
|
|
932
|
-
case
|
|
934
|
+
case 'userFills':
|
|
933
935
|
{
|
|
934
936
|
const maybePromise = (_a = onUserFillsRef.current) === null || _a === void 0 ? void 0 : _a.call(onUserFillsRef);
|
|
935
937
|
if (maybePromise instanceof Promise) {
|
|
936
|
-
maybePromise.catch((err) => console.error(
|
|
938
|
+
maybePromise.catch((err) => console.error('[HyperLiquid WS] userFills callback error', err));
|
|
937
939
|
}
|
|
938
940
|
}
|
|
939
941
|
break;
|
|
940
|
-
case
|
|
942
|
+
case 'webData3':
|
|
941
943
|
const webData3 = response.data;
|
|
942
944
|
// finalAssetContexts now sourced from allDexsAssetCtxs channel
|
|
943
945
|
const finalAtOICaps = webData3.perpDexStates.flatMap((dex) => dex.perpsAtOpenInterestCap);
|
|
944
946
|
setFinalAtOICaps(finalAtOICaps);
|
|
945
947
|
setUserAbstractionMode(webData3.userState.abstraction || null);
|
|
946
948
|
break;
|
|
947
|
-
case
|
|
949
|
+
case 'allDexsAssetCtxs':
|
|
948
950
|
{
|
|
949
951
|
const data = response.data;
|
|
950
952
|
// Store by DEX name, mapping '' to 'HYPERLIQUID'
|
|
951
953
|
const assetContextsByDex = new Map();
|
|
952
954
|
data.ctxs.forEach(([dexKey, ctxs]) => {
|
|
953
|
-
const dexName = dexKey ===
|
|
955
|
+
const dexName = dexKey === '' ? 'HYPERLIQUID' : dexKey;
|
|
954
956
|
assetContextsByDex.set(dexName, ctxs || []);
|
|
955
957
|
});
|
|
956
958
|
setAssetContextsByDex(assetContextsByDex);
|
|
957
959
|
}
|
|
958
960
|
break;
|
|
959
|
-
case
|
|
961
|
+
case 'allDexsClearinghouseState':
|
|
960
962
|
{
|
|
961
963
|
const data = response.data;
|
|
962
964
|
const states = (data.clearinghouseStates || [])
|
|
963
965
|
.map(([, s]) => s)
|
|
964
966
|
.filter(Boolean);
|
|
965
|
-
const sum = (values) => values.reduce((acc, v) => acc + (parseFloat(v ||
|
|
966
|
-
const toStr = (n) => Number.isFinite(n) ? n.toString() :
|
|
967
|
+
const sum = (values) => values.reduce((acc, v) => acc + (parseFloat(v || '0') || 0), 0);
|
|
968
|
+
const toStr = (n) => Number.isFinite(n) ? n.toString() : '0';
|
|
967
969
|
const assetPositions = states.flatMap((s) => s.assetPositions || []);
|
|
968
970
|
const crossMaintenanceMarginUsed = toStr(sum(states.map((s) => s.crossMaintenanceMarginUsed)));
|
|
969
971
|
const crossMarginSummary = {
|
|
@@ -993,26 +995,26 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
993
995
|
setClearinghouseStateReceived(true);
|
|
994
996
|
}
|
|
995
997
|
break;
|
|
996
|
-
case
|
|
998
|
+
case 'allMids':
|
|
997
999
|
{
|
|
998
1000
|
const data = response.data;
|
|
999
1001
|
setAllMids(data);
|
|
1000
1002
|
}
|
|
1001
1003
|
break;
|
|
1002
|
-
case
|
|
1004
|
+
case 'activeAssetData':
|
|
1003
1005
|
{
|
|
1004
1006
|
const assetData = response.data;
|
|
1005
1007
|
upsertActiveAssetData(assetData.coin, assetData);
|
|
1006
1008
|
}
|
|
1007
1009
|
break;
|
|
1008
|
-
case
|
|
1010
|
+
case 'candle':
|
|
1009
1011
|
{
|
|
1010
1012
|
const candleDataItem = response.data;
|
|
1011
|
-
const symbol = candleDataItem.s ||
|
|
1013
|
+
const symbol = candleDataItem.s || '';
|
|
1012
1014
|
addCandleData(symbol, candleDataItem);
|
|
1013
1015
|
}
|
|
1014
1016
|
break;
|
|
1015
|
-
case
|
|
1017
|
+
case 'spotState':
|
|
1016
1018
|
{
|
|
1017
1019
|
const spotStateData = response.data;
|
|
1018
1020
|
if (spotStateData === null || spotStateData === void 0 ? void 0 : spotStateData.spotState) {
|
|
@@ -1027,7 +1029,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1027
1029
|
}
|
|
1028
1030
|
catch (error) {
|
|
1029
1031
|
const errorMessage = `Failed to parse message: ${error instanceof Error ? error.message : String(error)}`;
|
|
1030
|
-
console.error(
|
|
1032
|
+
console.error('[HyperLiquid WS] Parse error:', errorMessage, 'Raw message:', event.data);
|
|
1031
1033
|
setLastError(errorMessage);
|
|
1032
1034
|
}
|
|
1033
1035
|
}, [
|
|
@@ -1041,7 +1043,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1041
1043
|
setSpotState,
|
|
1042
1044
|
]);
|
|
1043
1045
|
const connect = useCallback(() => {
|
|
1044
|
-
console.log(
|
|
1046
|
+
console.log('[HyperLiquid WS] connect() called, enabled:', enabled);
|
|
1045
1047
|
if (!enabled)
|
|
1046
1048
|
return;
|
|
1047
1049
|
// Clear any pending reconnect timeout
|
|
@@ -1057,10 +1059,10 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1057
1059
|
console.log('[HyperLiquid WS] connect() returning early - socket already exists, readyState:', wsRef.current.readyState);
|
|
1058
1060
|
return;
|
|
1059
1061
|
}
|
|
1060
|
-
console.log(
|
|
1062
|
+
console.log('[HyperLiquid WS] Creating new WebSocket connection');
|
|
1061
1063
|
manualCloseRef.current = false;
|
|
1062
1064
|
setReadyState(ReadyState.CONNECTING);
|
|
1063
|
-
const ws = new WebSocket(
|
|
1065
|
+
const ws = new WebSocket('wss://api.hyperliquid.xyz/ws');
|
|
1064
1066
|
wsRef.current = ws;
|
|
1065
1067
|
ws.onopen = () => {
|
|
1066
1068
|
reconnectAttemptsRef.current = 0;
|
|
@@ -1069,8 +1071,8 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1069
1071
|
};
|
|
1070
1072
|
ws.onmessage = handleMessage;
|
|
1071
1073
|
ws.onerror = (event) => {
|
|
1072
|
-
console.error(
|
|
1073
|
-
setLastError(
|
|
1074
|
+
console.error('[HyperLiquid WS] Connection error:', event);
|
|
1075
|
+
setLastError('WebSocket error');
|
|
1074
1076
|
};
|
|
1075
1077
|
ws.onclose = () => {
|
|
1076
1078
|
setReadyState(ReadyState.CLOSED);
|
|
@@ -1162,7 +1164,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1162
1164
|
if (isConnected) {
|
|
1163
1165
|
// Send ping every 30 seconds
|
|
1164
1166
|
pingIntervalRef.current = setInterval(() => {
|
|
1165
|
-
sendJsonMessage({ method:
|
|
1167
|
+
sendJsonMessage({ method: 'ping' });
|
|
1166
1168
|
}, 30000);
|
|
1167
1169
|
}
|
|
1168
1170
|
else {
|
|
@@ -1180,27 +1182,27 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1180
1182
|
}, [isConnected, sendJsonMessage]);
|
|
1181
1183
|
// Handle address subscription changes
|
|
1182
1184
|
useEffect(() => {
|
|
1183
|
-
const DEFAULT_ADDRESS =
|
|
1185
|
+
const DEFAULT_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
1184
1186
|
const userAddress = (address || DEFAULT_ADDRESS).toLowerCase();
|
|
1185
1187
|
const normalizedSubscribedAddress = (subscribedAddress === null || subscribedAddress === void 0 ? void 0 : subscribedAddress.toLowerCase()) || null;
|
|
1186
|
-
console.log(
|
|
1187
|
-
console.log(
|
|
1188
|
-
console.log(
|
|
1188
|
+
console.log('[HyperLiquid WS] Address subscription effect running');
|
|
1189
|
+
console.log('[HyperLiquid WS] address:', address, 'userAddress:', userAddress, 'subscribedAddress:', subscribedAddress, 'normalizedSubscribedAddress:', normalizedSubscribedAddress);
|
|
1190
|
+
console.log('[HyperLiquid WS] isConnected:', isConnected);
|
|
1189
1191
|
if (normalizedSubscribedAddress === userAddress) {
|
|
1190
|
-
console.log(
|
|
1192
|
+
console.log('[HyperLiquid WS] Address unchanged, skipping subscription update');
|
|
1191
1193
|
return;
|
|
1192
1194
|
}
|
|
1193
1195
|
if (!isConnected) {
|
|
1194
|
-
console.log(
|
|
1196
|
+
console.log('[HyperLiquid WS] Not connected, skipping subscription update');
|
|
1195
1197
|
return;
|
|
1196
1198
|
}
|
|
1197
1199
|
// Unsubscribe from previous address if exists
|
|
1198
1200
|
if (subscribedAddress) {
|
|
1199
|
-
console.log(
|
|
1201
|
+
console.log('[HyperLiquid WS] Unsubscribing from previous address:', subscribedAddress);
|
|
1200
1202
|
const unsubscribeMessage = {
|
|
1201
|
-
method:
|
|
1203
|
+
method: 'unsubscribe',
|
|
1202
1204
|
subscription: {
|
|
1203
|
-
type:
|
|
1205
|
+
type: 'webData3',
|
|
1204
1206
|
user: subscribedAddress,
|
|
1205
1207
|
},
|
|
1206
1208
|
};
|
|
@@ -1208,54 +1210,54 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1208
1210
|
// Unsubscribe from spotState for previous address
|
|
1209
1211
|
if (subscribedAddress !== DEFAULT_ADDRESS) {
|
|
1210
1212
|
const unsubscribeSpotState = {
|
|
1211
|
-
method:
|
|
1213
|
+
method: 'unsubscribe',
|
|
1212
1214
|
subscription: {
|
|
1213
|
-
type:
|
|
1215
|
+
type: 'spotState',
|
|
1214
1216
|
user: subscribedAddress,
|
|
1215
1217
|
},
|
|
1216
1218
|
};
|
|
1217
1219
|
sendJsonMessage(unsubscribeSpotState);
|
|
1218
1220
|
}
|
|
1219
1221
|
const unsubscribeAllDexsClearinghouseState = {
|
|
1220
|
-
method:
|
|
1222
|
+
method: 'unsubscribe',
|
|
1221
1223
|
subscription: {
|
|
1222
|
-
type:
|
|
1224
|
+
type: 'allDexsClearinghouseState',
|
|
1223
1225
|
user: subscribedAddress,
|
|
1224
1226
|
},
|
|
1225
1227
|
};
|
|
1226
1228
|
sendJsonMessage(unsubscribeAllDexsClearinghouseState);
|
|
1227
1229
|
const unsubscribeUserFills = {
|
|
1228
|
-
method:
|
|
1230
|
+
method: 'unsubscribe',
|
|
1229
1231
|
subscription: {
|
|
1230
|
-
type:
|
|
1232
|
+
type: 'userFills',
|
|
1231
1233
|
user: subscribedAddress,
|
|
1232
1234
|
},
|
|
1233
1235
|
};
|
|
1234
1236
|
sendJsonMessage(unsubscribeUserFills);
|
|
1235
1237
|
}
|
|
1236
1238
|
const subscribeWebData3 = {
|
|
1237
|
-
method:
|
|
1239
|
+
method: 'subscribe',
|
|
1238
1240
|
subscription: {
|
|
1239
|
-
type:
|
|
1241
|
+
type: 'webData3',
|
|
1240
1242
|
user: userAddress,
|
|
1241
1243
|
},
|
|
1242
1244
|
};
|
|
1243
1245
|
// Subscribe to allMids
|
|
1244
1246
|
const subscribeAllMids = {
|
|
1245
|
-
method:
|
|
1247
|
+
method: 'subscribe',
|
|
1246
1248
|
subscription: {
|
|
1247
|
-
type:
|
|
1248
|
-
dex:
|
|
1249
|
+
type: 'allMids',
|
|
1250
|
+
dex: 'ALL_DEXS',
|
|
1249
1251
|
},
|
|
1250
1252
|
};
|
|
1251
1253
|
// Subscribe to allDexsAssetCtxs (no payload params, global feed)
|
|
1252
1254
|
const subscribeAllDexsAssetCtxs = {
|
|
1253
|
-
method:
|
|
1255
|
+
method: 'subscribe',
|
|
1254
1256
|
subscription: {
|
|
1255
|
-
type:
|
|
1257
|
+
type: 'allDexsAssetCtxs',
|
|
1256
1258
|
},
|
|
1257
1259
|
};
|
|
1258
|
-
console.log(
|
|
1260
|
+
console.log('[HyperLiquid WS] Subscribing to new address:', userAddress);
|
|
1259
1261
|
sendJsonMessage(subscribeWebData3);
|
|
1260
1262
|
sendJsonMessage(subscribeAllMids);
|
|
1261
1263
|
sendJsonMessage(subscribeAllDexsAssetCtxs);
|
|
@@ -1263,9 +1265,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1263
1265
|
// Only subscribe if we have a real user address (not the default)
|
|
1264
1266
|
if (userAddress !== DEFAULT_ADDRESS.toLowerCase()) {
|
|
1265
1267
|
const subscribeSpotState = {
|
|
1266
|
-
method:
|
|
1268
|
+
method: 'subscribe',
|
|
1267
1269
|
subscription: {
|
|
1268
|
-
type:
|
|
1270
|
+
type: 'spotState',
|
|
1269
1271
|
user: userAddress,
|
|
1270
1272
|
},
|
|
1271
1273
|
};
|
|
@@ -1275,9 +1277,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1275
1277
|
// Only subscribe if we have a real user address (not the default)
|
|
1276
1278
|
if (userAddress !== DEFAULT_ADDRESS.toLowerCase()) {
|
|
1277
1279
|
const subscribeAllDexsClearinghouseState = {
|
|
1278
|
-
method:
|
|
1280
|
+
method: 'subscribe',
|
|
1279
1281
|
subscription: {
|
|
1280
|
-
type:
|
|
1282
|
+
type: 'allDexsClearinghouseState',
|
|
1281
1283
|
user: userAddress,
|
|
1282
1284
|
},
|
|
1283
1285
|
};
|
|
@@ -1311,9 +1313,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1311
1313
|
!userSummary)
|
|
1312
1314
|
return;
|
|
1313
1315
|
const subscribeUserFills = {
|
|
1314
|
-
method:
|
|
1316
|
+
method: 'subscribe',
|
|
1315
1317
|
subscription: {
|
|
1316
|
-
type:
|
|
1318
|
+
type: 'userFills',
|
|
1317
1319
|
user: subscribedAddress,
|
|
1318
1320
|
},
|
|
1319
1321
|
};
|
|
@@ -1335,9 +1337,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1335
1337
|
// Unsubscribe from tokens no longer in the list
|
|
1336
1338
|
tokensToUnsubscribe.forEach((token) => {
|
|
1337
1339
|
const unsubscribeMessage = {
|
|
1338
|
-
method:
|
|
1340
|
+
method: 'unsubscribe',
|
|
1339
1341
|
subscription: {
|
|
1340
|
-
type:
|
|
1342
|
+
type: 'activeAssetData',
|
|
1341
1343
|
user: address,
|
|
1342
1344
|
coin: token,
|
|
1343
1345
|
},
|
|
@@ -1347,9 +1349,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1347
1349
|
// Subscribe to new tokens
|
|
1348
1350
|
tokensToSubscribe.forEach((token) => {
|
|
1349
1351
|
const subscribeMessage = {
|
|
1350
|
-
method:
|
|
1352
|
+
method: 'subscribe',
|
|
1351
1353
|
subscription: {
|
|
1352
|
-
type:
|
|
1354
|
+
type: 'activeAssetData',
|
|
1353
1355
|
user: address,
|
|
1354
1356
|
coin: token,
|
|
1355
1357
|
},
|
|
@@ -1378,9 +1380,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1378
1380
|
if (prevInterval && prevInterval !== candleInterval) {
|
|
1379
1381
|
subscribedCandleTokens.forEach((token) => {
|
|
1380
1382
|
const unsubscribeMessage = {
|
|
1381
|
-
method:
|
|
1383
|
+
method: 'unsubscribe',
|
|
1382
1384
|
subscription: {
|
|
1383
|
-
type:
|
|
1385
|
+
type: 'candle',
|
|
1384
1386
|
coin: token,
|
|
1385
1387
|
interval: prevInterval,
|
|
1386
1388
|
},
|
|
@@ -1395,9 +1397,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1395
1397
|
// Unsubscribe from tokens no longer in the list
|
|
1396
1398
|
tokensToUnsubscribe.forEach((token) => {
|
|
1397
1399
|
const unsubscribeMessage = {
|
|
1398
|
-
method:
|
|
1400
|
+
method: 'unsubscribe',
|
|
1399
1401
|
subscription: {
|
|
1400
|
-
type:
|
|
1402
|
+
type: 'candle',
|
|
1401
1403
|
coin: token,
|
|
1402
1404
|
interval: candleInterval,
|
|
1403
1405
|
},
|
|
@@ -1407,9 +1409,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
1407
1409
|
// Subscribe to new tokens
|
|
1408
1410
|
tokensToSubscribe.forEach((token) => {
|
|
1409
1411
|
const subscribeMessage = {
|
|
1410
|
-
method:
|
|
1412
|
+
method: 'subscribe',
|
|
1411
1413
|
subscription: {
|
|
1412
|
-
type:
|
|
1414
|
+
type: 'candle',
|
|
1413
1415
|
coin: token,
|
|
1414
1416
|
interval: candleInterval,
|
|
1415
1417
|
},
|
|
@@ -5924,10 +5926,10 @@ function toApiError(error) {
|
|
|
5924
5926
|
var _a;
|
|
5925
5927
|
const axiosError = error;
|
|
5926
5928
|
const payload = (axiosError && axiosError.response ? axiosError.response.data : undefined);
|
|
5927
|
-
const message = typeof payload ===
|
|
5929
|
+
const message = typeof payload === 'object' && payload && 'message' in payload
|
|
5928
5930
|
? String(payload.message)
|
|
5929
|
-
: (axiosError === null || axiosError === void 0 ? void 0 : axiosError.message) ||
|
|
5930
|
-
const errField = typeof payload ===
|
|
5931
|
+
: (axiosError === null || axiosError === void 0 ? void 0 : axiosError.message) || 'Request failed';
|
|
5932
|
+
const errField = typeof payload === 'object' && payload && 'error' in payload
|
|
5931
5933
|
? String(payload.error)
|
|
5932
5934
|
: undefined;
|
|
5933
5935
|
return {
|
|
@@ -5937,8 +5939,8 @@ function toApiError(error) {
|
|
|
5937
5939
|
};
|
|
5938
5940
|
}
|
|
5939
5941
|
function joinUrl(baseUrl, path) {
|
|
5940
|
-
const cleanBase = baseUrl.replace(/\/$/,
|
|
5941
|
-
const cleanPath = path.startsWith(
|
|
5942
|
+
const cleanBase = baseUrl.replace(/\/$/, '');
|
|
5943
|
+
const cleanPath = path.startsWith('/') ? path : `/${path}`;
|
|
5942
5944
|
return `${cleanBase}${cleanPath}`;
|
|
5943
5945
|
}
|
|
5944
5946
|
/**
|
|
@@ -5967,7 +5969,7 @@ function addAuthInterceptors(params) {
|
|
|
5967
5969
|
pendingRequests = [];
|
|
5968
5970
|
}
|
|
5969
5971
|
const isOurApiUrl = (url) => Boolean(url && url.startsWith(apiBaseUrl));
|
|
5970
|
-
const isRefreshUrl = (url) => Boolean(url && url.startsWith(joinUrl(apiBaseUrl,
|
|
5972
|
+
const isRefreshUrl = (url) => Boolean(url && url.startsWith(joinUrl(apiBaseUrl, '/auth/refresh')));
|
|
5971
5973
|
const reqId = apiClient.interceptors.request.use((config) => {
|
|
5972
5974
|
var _a;
|
|
5973
5975
|
try {
|
|
@@ -5975,12 +5977,11 @@ function addAuthInterceptors(params) {
|
|
|
5975
5977
|
const token = getAccessToken();
|
|
5976
5978
|
if (token) {
|
|
5977
5979
|
config.headers = (_a = config.headers) !== null && _a !== void 0 ? _a : {};
|
|
5978
|
-
config.headers[
|
|
5980
|
+
(config.headers)['Authorization'] = `Bearer ${token}`;
|
|
5979
5981
|
}
|
|
5980
5982
|
}
|
|
5981
5983
|
}
|
|
5982
|
-
catch (
|
|
5983
|
-
console.error("[Auth Interceptor] Request interceptor error:", err);
|
|
5984
|
+
catch (_b) {
|
|
5984
5985
|
}
|
|
5985
5986
|
return config;
|
|
5986
5987
|
});
|
|
@@ -5991,36 +5992,22 @@ function addAuthInterceptors(params) {
|
|
|
5991
5992
|
const url = originalRequest === null || originalRequest === void 0 ? void 0 : originalRequest.url;
|
|
5992
5993
|
// If not our API or not 401, just reject
|
|
5993
5994
|
if (!status || status !== 401 || !isOurApiUrl(url)) {
|
|
5994
|
-
if (status === 401) {
|
|
5995
|
-
console.warn("[Auth Interceptor] 401 received but URL check failed:", {
|
|
5996
|
-
url,
|
|
5997
|
-
apiBaseUrl,
|
|
5998
|
-
isOurApiUrl: isOurApiUrl(url),
|
|
5999
|
-
});
|
|
6000
|
-
}
|
|
6001
5995
|
return Promise.reject(error);
|
|
6002
5996
|
}
|
|
6003
|
-
console.log("[Auth Interceptor] 401 detected, attempting token refresh for URL:", url);
|
|
6004
5997
|
// If the 401 is from refresh endpoint itself -> force logout
|
|
6005
5998
|
if (isRefreshUrl(url)) {
|
|
6006
|
-
console.warn("[Auth Interceptor] Refresh endpoint returned 401, logging out");
|
|
6007
5999
|
try {
|
|
6008
6000
|
await logout();
|
|
6009
6001
|
}
|
|
6010
|
-
catch (
|
|
6011
|
-
console.error("[Auth Interceptor] Logout failed:", err);
|
|
6012
|
-
}
|
|
6002
|
+
catch (_d) { }
|
|
6013
6003
|
return Promise.reject(error);
|
|
6014
6004
|
}
|
|
6015
6005
|
// Prevent infinite loop
|
|
6016
6006
|
if (originalRequest && originalRequest._retry) {
|
|
6017
|
-
console.warn("[Auth Interceptor] Request already retried, logging out");
|
|
6018
6007
|
try {
|
|
6019
6008
|
await logout();
|
|
6020
6009
|
}
|
|
6021
|
-
catch (
|
|
6022
|
-
console.error("[Auth Interceptor] Logout failed:", err);
|
|
6023
|
-
}
|
|
6010
|
+
catch (_e) { }
|
|
6024
6011
|
return Promise.reject(error);
|
|
6025
6012
|
}
|
|
6026
6013
|
// Mark so we don't retry twice
|
|
@@ -6034,45 +6021,31 @@ function addAuthInterceptors(params) {
|
|
|
6034
6021
|
if (!newToken || !originalRequest)
|
|
6035
6022
|
return reject(error);
|
|
6036
6023
|
originalRequest.headers = (_a = originalRequest.headers) !== null && _a !== void 0 ? _a : {};
|
|
6037
|
-
originalRequest.headers[
|
|
6038
|
-
`Bearer ${newToken}`;
|
|
6024
|
+
originalRequest.headers['Authorization'] = `Bearer ${newToken}`;
|
|
6039
6025
|
resolve(apiClient.request(originalRequest));
|
|
6040
6026
|
});
|
|
6041
6027
|
});
|
|
6042
6028
|
}
|
|
6043
6029
|
isRefreshing = true;
|
|
6044
6030
|
try {
|
|
6045
|
-
console.log("[Auth Interceptor] Refreshing tokens...");
|
|
6046
6031
|
const refreshed = await refreshTokens();
|
|
6047
|
-
const newAccessToken = (_b = (refreshed &&
|
|
6048
|
-
(refreshed.accessToken || ((_a = refreshed.data) === null || _a === void 0 ? void 0 : _a.accessToken)))) !== null && _b !== void 0 ? _b : null;
|
|
6049
|
-
if (!newAccessToken) {
|
|
6050
|
-
console.error("[Auth Interceptor] Token refresh succeeded but no access token in response:", refreshed);
|
|
6051
|
-
}
|
|
6052
|
-
else {
|
|
6053
|
-
console.log("[Auth Interceptor] Token refresh successful");
|
|
6054
|
-
}
|
|
6032
|
+
const newAccessToken = (_b = (refreshed && (refreshed.accessToken || ((_a = refreshed.data) === null || _a === void 0 ? void 0 : _a.accessToken)))) !== null && _b !== void 0 ? _b : null;
|
|
6055
6033
|
resolvePendingRequests(newAccessToken);
|
|
6056
6034
|
if (originalRequest) {
|
|
6057
6035
|
originalRequest.headers = (_c = originalRequest.headers) !== null && _c !== void 0 ? _c : {};
|
|
6058
6036
|
if (newAccessToken)
|
|
6059
|
-
originalRequest.headers[
|
|
6060
|
-
`Bearer ${newAccessToken}`;
|
|
6061
|
-
console.log("[Auth Interceptor] Retrying original request with new token");
|
|
6037
|
+
(originalRequest.headers)['Authorization'] = `Bearer ${newAccessToken}`;
|
|
6062
6038
|
const resp = await apiClient.request(originalRequest);
|
|
6063
6039
|
return resp;
|
|
6064
6040
|
}
|
|
6065
6041
|
return Promise.reject(error);
|
|
6066
6042
|
}
|
|
6067
6043
|
catch (refreshErr) {
|
|
6068
|
-
console.error("[Auth Interceptor] Token refresh failed:", refreshErr);
|
|
6069
6044
|
resolvePendingRequests(null);
|
|
6070
6045
|
try {
|
|
6071
6046
|
await logout();
|
|
6072
6047
|
}
|
|
6073
|
-
catch (
|
|
6074
|
-
console.error("[Auth Interceptor] Logout failed:", err);
|
|
6075
|
-
}
|
|
6048
|
+
catch (_f) { }
|
|
6076
6049
|
return Promise.reject(refreshErr);
|
|
6077
6050
|
}
|
|
6078
6051
|
finally {
|
|
@@ -6083,15 +6056,11 @@ function addAuthInterceptors(params) {
|
|
|
6083
6056
|
try {
|
|
6084
6057
|
apiClient.interceptors.request.eject(reqId);
|
|
6085
6058
|
}
|
|
6086
|
-
catch (
|
|
6087
|
-
console.error("[Auth Interceptor] Failed to eject request interceptor:", err);
|
|
6088
|
-
}
|
|
6059
|
+
catch (_a) { }
|
|
6089
6060
|
try {
|
|
6090
6061
|
apiClient.interceptors.response.eject(resId);
|
|
6091
6062
|
}
|
|
6092
|
-
catch (
|
|
6093
|
-
console.error("[Auth Interceptor] Failed to eject response interceptor:", err);
|
|
6094
|
-
}
|
|
6063
|
+
catch (_b) { }
|
|
6095
6064
|
};
|
|
6096
6065
|
}
|
|
6097
6066
|
|
|
@@ -7597,34 +7566,20 @@ function usePortfolio() {
|
|
|
7597
7566
|
}
|
|
7598
7567
|
|
|
7599
7568
|
async function getEIP712Message(baseUrl, address, clientId) {
|
|
7600
|
-
const url = joinUrl(baseUrl,
|
|
7569
|
+
const url = joinUrl(baseUrl, '/auth/eip712-message');
|
|
7601
7570
|
try {
|
|
7602
|
-
const resp = await
|
|
7603
|
-
|
|
7604
|
-
timeout: 30000,
|
|
7605
|
-
});
|
|
7606
|
-
return {
|
|
7607
|
-
data: resp.data,
|
|
7608
|
-
status: resp.status,
|
|
7609
|
-
headers: resp.headers,
|
|
7610
|
-
};
|
|
7571
|
+
const resp = await axios$1.get(url, { params: { address, clientId }, timeout: 30000 });
|
|
7572
|
+
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
7611
7573
|
}
|
|
7612
7574
|
catch (error) {
|
|
7613
7575
|
throw toApiError(error);
|
|
7614
7576
|
}
|
|
7615
7577
|
}
|
|
7616
7578
|
async function authenticate(baseUrl, body) {
|
|
7617
|
-
const url = joinUrl(baseUrl,
|
|
7579
|
+
const url = joinUrl(baseUrl, '/auth/login');
|
|
7618
7580
|
try {
|
|
7619
|
-
const resp = await
|
|
7620
|
-
|
|
7621
|
-
timeout: 30000,
|
|
7622
|
-
});
|
|
7623
|
-
return {
|
|
7624
|
-
data: resp.data,
|
|
7625
|
-
status: resp.status,
|
|
7626
|
-
headers: resp.headers,
|
|
7627
|
-
};
|
|
7581
|
+
const resp = await axios$1.post(url, body, { headers: { 'Content-Type': 'application/json' }, timeout: 30000 });
|
|
7582
|
+
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
7628
7583
|
}
|
|
7629
7584
|
catch (error) {
|
|
7630
7585
|
throw toApiError(error);
|
|
@@ -7635,7 +7590,7 @@ async function authenticate(baseUrl, body) {
|
|
|
7635
7590
|
*/
|
|
7636
7591
|
async function authenticateWithPrivy(baseUrl, params) {
|
|
7637
7592
|
const body = {
|
|
7638
|
-
method:
|
|
7593
|
+
method: 'privy_access_token',
|
|
7639
7594
|
address: params.address,
|
|
7640
7595
|
clientId: params.clientId,
|
|
7641
7596
|
details: { appId: params.appId, accessToken: params.accessToken },
|
|
@@ -7643,124 +7598,62 @@ async function authenticateWithPrivy(baseUrl, params) {
|
|
|
7643
7598
|
return authenticate(baseUrl, body);
|
|
7644
7599
|
}
|
|
7645
7600
|
async function refreshToken(baseUrl, refreshTokenVal) {
|
|
7646
|
-
const url = joinUrl(baseUrl,
|
|
7601
|
+
const url = joinUrl(baseUrl, '/auth/refresh');
|
|
7647
7602
|
try {
|
|
7648
|
-
const resp = await
|
|
7649
|
-
return {
|
|
7650
|
-
data: resp.data,
|
|
7651
|
-
status: resp.status,
|
|
7652
|
-
headers: resp.headers,
|
|
7653
|
-
};
|
|
7603
|
+
const resp = await axios$1.post(url, { refreshToken: refreshTokenVal }, { headers: { 'Content-Type': 'application/json' }, timeout: 30000 });
|
|
7604
|
+
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
7654
7605
|
}
|
|
7655
7606
|
catch (error) {
|
|
7656
7607
|
throw toApiError(error);
|
|
7657
7608
|
}
|
|
7658
7609
|
}
|
|
7659
7610
|
async function logout(baseUrl, refreshTokenVal) {
|
|
7660
|
-
const url = joinUrl(baseUrl,
|
|
7611
|
+
const url = joinUrl(baseUrl, '/auth/logout');
|
|
7661
7612
|
try {
|
|
7662
|
-
const resp = await
|
|
7663
|
-
return {
|
|
7664
|
-
data: resp.data,
|
|
7665
|
-
status: resp.status,
|
|
7666
|
-
headers: resp.headers,
|
|
7667
|
-
};
|
|
7613
|
+
const resp = await axios$1.post(url, { refreshToken: refreshTokenVal }, { headers: { 'Content-Type': 'application/json' }, timeout: 30000 });
|
|
7614
|
+
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
7668
7615
|
}
|
|
7669
7616
|
catch (error) {
|
|
7670
7617
|
throw toApiError(error);
|
|
7671
7618
|
}
|
|
7672
7619
|
}
|
|
7673
7620
|
|
|
7674
|
-
// Token expiration constants
|
|
7675
|
-
const ACCESS_TOKEN_BUFFER_MS = 5 * 60 * 1000; // Refresh 5 min before expiry
|
|
7676
|
-
const REFRESH_TOKEN_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days fallback
|
|
7677
|
-
function nowMs() {
|
|
7678
|
-
return Date.now();
|
|
7679
|
-
}
|
|
7680
|
-
function calcExpiresAt(expiresInSeconds) {
|
|
7681
|
-
return nowMs() + expiresInSeconds * 1000;
|
|
7682
|
-
}
|
|
7683
7621
|
function useAuth() {
|
|
7684
7622
|
const context = useContext(PearHyperliquidContext);
|
|
7685
7623
|
if (!context) {
|
|
7686
|
-
throw new Error(
|
|
7624
|
+
throw new Error("usePortfolio must be used within a PearHyperliquidProvider");
|
|
7687
7625
|
}
|
|
7688
7626
|
const { apiBaseUrl, clientId } = context;
|
|
7627
|
+
const [isReady, setIsReady] = useState(false);
|
|
7689
7628
|
const accessToken = useUserData((s) => s.accessToken);
|
|
7690
7629
|
const refreshToken$1 = useUserData((s) => s.refreshToken);
|
|
7691
|
-
const isReady = useUserData((s) => s.isReady);
|
|
7692
|
-
const isAuthenticated = useUserData((s) => s.isAuthenticated);
|
|
7693
7630
|
const setAccessToken = useUserData((s) => s.setAccessToken);
|
|
7694
7631
|
const setRefreshToken = useUserData((s) => s.setRefreshToken);
|
|
7695
|
-
const
|
|
7632
|
+
const isAuthenticated = useUserData((s) => s.isAuthenticated);
|
|
7696
7633
|
const setIsAuthenticated = useUserData((s) => s.setIsAuthenticated);
|
|
7697
7634
|
const address = useUserData((s) => s.address);
|
|
7698
7635
|
const setAddress = useUserData((s) => s.setAddress);
|
|
7699
|
-
// Ref to prevent concurrent refresh attempts
|
|
7700
|
-
const isRefreshingRef = useRef(false);
|
|
7701
7636
|
useEffect(() => {
|
|
7702
|
-
if (typeof window ==
|
|
7637
|
+
if (typeof window == "undefined") {
|
|
7703
7638
|
return;
|
|
7704
7639
|
}
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
const refreshExp = refreshExpRaw ? Number(refreshExpRaw) : 0;
|
|
7716
|
-
const now = nowMs();
|
|
7717
|
-
const accessValid = !!storedAccessToken && accessExp > now;
|
|
7718
|
-
const refreshValid = !!storedRefreshToken && refreshExp > now;
|
|
7719
|
-
if (accessValid && refreshValid) {
|
|
7720
|
-
// Both tokens are valid
|
|
7721
|
-
setAccessToken(storedAccessToken);
|
|
7722
|
-
setRefreshToken(storedRefreshToken);
|
|
7723
|
-
setIsAuthenticated(true);
|
|
7724
|
-
setIsReady(true);
|
|
7725
|
-
}
|
|
7726
|
-
else if (refreshValid) {
|
|
7727
|
-
// Access token expired but refresh still valid → refresh immediately
|
|
7728
|
-
setAccessToken(storedAccessToken);
|
|
7729
|
-
setRefreshToken(storedRefreshToken);
|
|
7730
|
-
(async () => {
|
|
7731
|
-
try {
|
|
7732
|
-
await refreshTokens();
|
|
7733
|
-
}
|
|
7734
|
-
catch (_a) {
|
|
7735
|
-
// Refresh failed → clear tokens
|
|
7736
|
-
setAccessToken(null);
|
|
7737
|
-
setRefreshToken(null);
|
|
7738
|
-
setIsAuthenticated(false);
|
|
7739
|
-
}
|
|
7740
|
-
setIsReady(true);
|
|
7741
|
-
})();
|
|
7742
|
-
return; // setIsReady will be called in the async block
|
|
7743
|
-
}
|
|
7744
|
-
else {
|
|
7745
|
-
// Refresh expired or no tokens → clear
|
|
7746
|
-
setAccessToken(null);
|
|
7747
|
-
setRefreshToken(null);
|
|
7748
|
-
setIsAuthenticated(false);
|
|
7749
|
-
setIsReady(true);
|
|
7750
|
-
}
|
|
7751
|
-
}
|
|
7752
|
-
else {
|
|
7753
|
-
setIsReady(true);
|
|
7754
|
-
}
|
|
7755
|
-
}, [address]);
|
|
7640
|
+
const access = localStorage.getItem("accessToken");
|
|
7641
|
+
const refresh = localStorage.getItem("refreshToken");
|
|
7642
|
+
const addr = localStorage.getItem("address");
|
|
7643
|
+
setAccessToken(access);
|
|
7644
|
+
setRefreshToken(refresh);
|
|
7645
|
+
setAddress(addr);
|
|
7646
|
+
const authed = Boolean(access && addr);
|
|
7647
|
+
setIsAuthenticated(authed);
|
|
7648
|
+
setIsReady(true);
|
|
7649
|
+
}, [setAccessToken, setRefreshToken, setIsAuthenticated, setAddress]);
|
|
7756
7650
|
useEffect(() => {
|
|
7757
7651
|
const cleanup = addAuthInterceptors({
|
|
7758
7652
|
apiBaseUrl,
|
|
7759
7653
|
getAccessToken: () => {
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
return useUserData.getState().accessToken;
|
|
7654
|
+
return typeof window !== "undefined"
|
|
7655
|
+
? window.localStorage.getItem("accessToken")
|
|
7656
|
+
: null;
|
|
7764
7657
|
},
|
|
7765
7658
|
refreshTokens: async () => {
|
|
7766
7659
|
const data = await refreshTokens();
|
|
@@ -7774,55 +7667,6 @@ function useAuth() {
|
|
|
7774
7667
|
cleanup();
|
|
7775
7668
|
};
|
|
7776
7669
|
}, [apiBaseUrl]);
|
|
7777
|
-
// Proactive refresh effect: refresh when app regains focus or timer fires
|
|
7778
|
-
useEffect(() => {
|
|
7779
|
-
if (typeof window === 'undefined' || !address || !refreshToken$1)
|
|
7780
|
-
return;
|
|
7781
|
-
const refreshIfNeeded = async () => {
|
|
7782
|
-
// Prevent concurrent refresh attempts
|
|
7783
|
-
if (isRefreshingRef.current)
|
|
7784
|
-
return;
|
|
7785
|
-
// Read fresh expiration values from localStorage (not stale closure)
|
|
7786
|
-
const accessExpRaw = localStorage.getItem(`${address}_accessTokenExpiresAt`);
|
|
7787
|
-
const refreshExpRaw = localStorage.getItem(`${address}_refreshTokenExpiresAt`);
|
|
7788
|
-
const accessExp = accessExpRaw ? Number(accessExpRaw) : 0;
|
|
7789
|
-
const refreshExp = refreshExpRaw ? Number(refreshExpRaw) : 0;
|
|
7790
|
-
const now = nowMs();
|
|
7791
|
-
// If refresh token is already expired, do nothing
|
|
7792
|
-
if (refreshExp <= now)
|
|
7793
|
-
return;
|
|
7794
|
-
// If access token is within buffer window, refresh
|
|
7795
|
-
if (accessExp - now <= ACCESS_TOKEN_BUFFER_MS) {
|
|
7796
|
-
isRefreshingRef.current = true;
|
|
7797
|
-
try {
|
|
7798
|
-
await refreshTokens();
|
|
7799
|
-
}
|
|
7800
|
-
catch (_a) {
|
|
7801
|
-
// Refresh failed, interceptor will handle logout on next API call
|
|
7802
|
-
}
|
|
7803
|
-
finally {
|
|
7804
|
-
isRefreshingRef.current = false;
|
|
7805
|
-
}
|
|
7806
|
-
}
|
|
7807
|
-
};
|
|
7808
|
-
const onVisibilityChange = () => {
|
|
7809
|
-
if (document.visibilityState === 'visible') {
|
|
7810
|
-
refreshIfNeeded();
|
|
7811
|
-
}
|
|
7812
|
-
};
|
|
7813
|
-
document.addEventListener('visibilitychange', onVisibilityChange);
|
|
7814
|
-
// Schedule timer for (accessExp - buffer)
|
|
7815
|
-
const accessExpRaw = localStorage.getItem(`${address}_accessTokenExpiresAt`);
|
|
7816
|
-
const accessExp = accessExpRaw ? Number(accessExpRaw) : 0;
|
|
7817
|
-
const delay = Math.max(0, accessExp - nowMs() - ACCESS_TOKEN_BUFFER_MS);
|
|
7818
|
-
const timer = window.setTimeout(() => {
|
|
7819
|
-
refreshIfNeeded();
|
|
7820
|
-
}, delay);
|
|
7821
|
-
return () => {
|
|
7822
|
-
document.removeEventListener('visibilitychange', onVisibilityChange);
|
|
7823
|
-
clearTimeout(timer);
|
|
7824
|
-
};
|
|
7825
|
-
}, [address, refreshToken$1]);
|
|
7826
7670
|
async function getEip712(address) {
|
|
7827
7671
|
const { data } = await getEIP712Message(apiBaseUrl, address, clientId);
|
|
7828
7672
|
return data;
|
|
@@ -7830,21 +7674,17 @@ function useAuth() {
|
|
|
7830
7674
|
async function loginWithSignedMessage(address, signature, timestamp) {
|
|
7831
7675
|
try {
|
|
7832
7676
|
const { data } = await authenticate(apiBaseUrl, {
|
|
7833
|
-
method:
|
|
7677
|
+
method: "eip712",
|
|
7834
7678
|
address,
|
|
7835
7679
|
clientId,
|
|
7836
7680
|
details: { signature, timestamp },
|
|
7837
7681
|
});
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
const refreshTokenExpiresAtKey = `${address}_refreshTokenExpiresAt`;
|
|
7842
|
-
window.localStorage.setItem(accessTokenKey, data.accessToken);
|
|
7843
|
-
window.localStorage.setItem(refreshTokenKey, data.refreshToken);
|
|
7844
|
-
window.localStorage.setItem(accessTokenExpiresAtKey, String(calcExpiresAt(data.expiresIn)));
|
|
7845
|
-
window.localStorage.setItem(refreshTokenExpiresAtKey, String(nowMs() + REFRESH_TOKEN_TTL_MS));
|
|
7682
|
+
window.localStorage.setItem("accessToken", data.accessToken);
|
|
7683
|
+
window.localStorage.setItem("refreshToken", data.refreshToken);
|
|
7684
|
+
window.localStorage.setItem("address", address);
|
|
7846
7685
|
setAccessToken(data.accessToken);
|
|
7847
7686
|
setRefreshToken(data.refreshToken);
|
|
7687
|
+
setAddress(address);
|
|
7848
7688
|
setIsAuthenticated(true);
|
|
7849
7689
|
}
|
|
7850
7690
|
catch (e) {
|
|
@@ -7859,16 +7699,12 @@ function useAuth() {
|
|
|
7859
7699
|
appId,
|
|
7860
7700
|
accessToken: privyAccessToken,
|
|
7861
7701
|
});
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
const refreshTokenExpiresAtKey = `${address}_refreshTokenExpiresAt`;
|
|
7866
|
-
window.localStorage.setItem(accessTokenKey, data.accessToken);
|
|
7867
|
-
window.localStorage.setItem(refreshTokenKey, data.refreshToken);
|
|
7868
|
-
window.localStorage.setItem(accessTokenExpiresAtKey, String(calcExpiresAt(data.expiresIn)));
|
|
7869
|
-
window.localStorage.setItem(refreshTokenExpiresAtKey, String(nowMs() + REFRESH_TOKEN_TTL_MS));
|
|
7702
|
+
window.localStorage.setItem("accessToken", data.accessToken);
|
|
7703
|
+
window.localStorage.setItem("refreshToken", data.refreshToken);
|
|
7704
|
+
window.localStorage.setItem("address", address);
|
|
7870
7705
|
setAccessToken(data.accessToken);
|
|
7871
7706
|
setRefreshToken(data.refreshToken);
|
|
7707
|
+
setAddress(address);
|
|
7872
7708
|
setIsAuthenticated(true);
|
|
7873
7709
|
}
|
|
7874
7710
|
catch (e) {
|
|
@@ -7876,56 +7712,35 @@ function useAuth() {
|
|
|
7876
7712
|
}
|
|
7877
7713
|
}
|
|
7878
7714
|
async function refreshTokens() {
|
|
7879
|
-
const
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
const accessTokenKey = `${currentAddress}_accessToken`;
|
|
7886
|
-
const refreshTokenKey = `${currentAddress}_refreshToken`;
|
|
7887
|
-
const accessTokenExpiresAtKey = `${currentAddress}_accessTokenExpiresAt`;
|
|
7888
|
-
const refreshTokenExpiresAtKey = `${currentAddress}_refreshTokenExpiresAt`;
|
|
7889
|
-
window.localStorage.setItem(accessTokenKey, data.accessToken);
|
|
7890
|
-
window.localStorage.setItem(refreshTokenKey, data.refreshToken);
|
|
7891
|
-
window.localStorage.setItem(accessTokenExpiresAtKey, String(calcExpiresAt(data.expiresIn)));
|
|
7892
|
-
window.localStorage.setItem(refreshTokenExpiresAtKey, String(nowMs() + REFRESH_TOKEN_TTL_MS));
|
|
7715
|
+
const refresh = window.localStorage.getItem("refreshToken");
|
|
7716
|
+
if (!refresh)
|
|
7717
|
+
throw new Error("No refresh token");
|
|
7718
|
+
const { data } = await refreshToken(apiBaseUrl, refresh);
|
|
7719
|
+
window.localStorage.setItem("accessToken", data.accessToken);
|
|
7720
|
+
window.localStorage.setItem("refreshToken", data.refreshToken);
|
|
7893
7721
|
setAccessToken(data.accessToken);
|
|
7894
7722
|
setRefreshToken(data.refreshToken);
|
|
7895
7723
|
setIsAuthenticated(true);
|
|
7896
7724
|
return data;
|
|
7897
7725
|
}
|
|
7898
7726
|
async function logout$1() {
|
|
7899
|
-
const
|
|
7900
|
-
|
|
7901
|
-
if (currentRefresh) {
|
|
7727
|
+
const refresh = window.localStorage.getItem("refreshToken");
|
|
7728
|
+
if (refresh) {
|
|
7902
7729
|
try {
|
|
7903
|
-
await logout(apiBaseUrl,
|
|
7730
|
+
await logout(apiBaseUrl, refresh);
|
|
7904
7731
|
}
|
|
7905
7732
|
catch (_a) {
|
|
7906
7733
|
/* ignore */
|
|
7907
7734
|
}
|
|
7908
7735
|
}
|
|
7909
|
-
|
|
7910
|
-
|
|
7911
|
-
|
|
7912
|
-
const accessTokenExpiresAtKey = `${currentAddress}_accessTokenExpiresAt`;
|
|
7913
|
-
const refreshTokenExpiresAtKey = `${currentAddress}_refreshTokenExpiresAt`;
|
|
7914
|
-
window.localStorage.removeItem(accessTokenKey);
|
|
7915
|
-
window.localStorage.removeItem(refreshTokenKey);
|
|
7916
|
-
window.localStorage.removeItem(accessTokenExpiresAtKey);
|
|
7917
|
-
window.localStorage.removeItem(refreshTokenExpiresAtKey);
|
|
7918
|
-
}
|
|
7736
|
+
window.localStorage.removeItem("accessToken");
|
|
7737
|
+
window.localStorage.removeItem("refreshToken");
|
|
7738
|
+
window.localStorage.removeItem("address");
|
|
7919
7739
|
setAccessToken(null);
|
|
7920
7740
|
setRefreshToken(null);
|
|
7921
7741
|
setAddress(null);
|
|
7922
7742
|
setIsAuthenticated(false);
|
|
7923
7743
|
}
|
|
7924
|
-
function clearSession() {
|
|
7925
|
-
setAccessToken(null);
|
|
7926
|
-
setRefreshToken(null);
|
|
7927
|
-
setIsAuthenticated(false);
|
|
7928
|
-
}
|
|
7929
7744
|
return {
|
|
7930
7745
|
isReady,
|
|
7931
7746
|
isAuthenticated,
|
|
@@ -7937,8 +7752,6 @@ function useAuth() {
|
|
|
7937
7752
|
loginWithPrivyToken,
|
|
7938
7753
|
refreshTokens,
|
|
7939
7754
|
logout: logout$1,
|
|
7940
|
-
clearSession,
|
|
7941
|
-
setAddress,
|
|
7942
7755
|
};
|
|
7943
7756
|
}
|
|
7944
7757
|
|
|
@@ -8251,8 +8064,9 @@ const PearHyperliquidContext = createContext(undefined);
|
|
|
8251
8064
|
/**
|
|
8252
8065
|
* React Provider for PearHyperliquidClient
|
|
8253
8066
|
*/
|
|
8254
|
-
const PearHyperliquidProvider = ({ children, apiBaseUrl =
|
|
8067
|
+
const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-ui.pearprotocol.io', clientId = 'PEARPROTOCOLUI', wsUrl = 'wss://hl-ui.pearprotocol.io/ws', }) => {
|
|
8255
8068
|
const address = useUserData((s) => s.address);
|
|
8069
|
+
const setAddress = useUserData((s) => s.setAddress);
|
|
8256
8070
|
const perpMetasByDex = useHyperliquidData((state) => state.perpMetasByDex);
|
|
8257
8071
|
const setPerpDexs = useHyperliquidData((state) => state.setPerpDexs);
|
|
8258
8072
|
const setPerpMetasByDex = useHyperliquidData((state) => state.setPerpMetasByDex);
|
|
@@ -8283,20 +8097,20 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-ui.pearpro
|
|
|
8283
8097
|
perpMetas.forEach((item, perpIndex) => {
|
|
8284
8098
|
var _a, _b;
|
|
8285
8099
|
const dexName = perpIndex === 0
|
|
8286
|
-
?
|
|
8100
|
+
? 'HYPERLIQUID'
|
|
8287
8101
|
: ((_b = (_a = perpDexs[perpIndex]) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : `DEX_${perpIndex}`);
|
|
8288
8102
|
var collateralToken;
|
|
8289
8103
|
if (item.collateralToken === 360) {
|
|
8290
|
-
collateralToken =
|
|
8104
|
+
collateralToken = 'USDH';
|
|
8291
8105
|
}
|
|
8292
8106
|
if (item.collateralToken === 0) {
|
|
8293
|
-
collateralToken =
|
|
8107
|
+
collateralToken = 'USDC';
|
|
8294
8108
|
}
|
|
8295
8109
|
if (item.collateralToken === 235) {
|
|
8296
|
-
collateralToken =
|
|
8110
|
+
collateralToken = 'USDE';
|
|
8297
8111
|
}
|
|
8298
8112
|
if (item.collateralToken === 268) {
|
|
8299
|
-
collateralToken =
|
|
8113
|
+
collateralToken = 'USDT0';
|
|
8300
8114
|
}
|
|
8301
8115
|
const universeAssets = item.universe.map((asset) => ({
|
|
8302
8116
|
...asset,
|
|
@@ -8324,6 +8138,8 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-ui.pearpro
|
|
|
8324
8138
|
}), [
|
|
8325
8139
|
apiBaseUrl,
|
|
8326
8140
|
wsUrl,
|
|
8141
|
+
address,
|
|
8142
|
+
setAddress,
|
|
8327
8143
|
isConnected,
|
|
8328
8144
|
lastError,
|
|
8329
8145
|
nativeIsConnected,
|
|
@@ -8338,7 +8154,7 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-ui.pearpro
|
|
|
8338
8154
|
function usePearHyperliquid() {
|
|
8339
8155
|
const ctx = useContext(PearHyperliquidContext);
|
|
8340
8156
|
if (!ctx)
|
|
8341
|
-
throw new Error(
|
|
8157
|
+
throw new Error('usePearHyperliquid must be used within a PearHyperliquidProvider');
|
|
8342
8158
|
return ctx;
|
|
8343
8159
|
}
|
|
8344
8160
|
|
package/dist/provider.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ActiveAssetData, CandleChartData, CandleData, ClearinghouseState, UniverseAsset, WebData3AssetCtx, WsAllMidsData, PerpDexsResponse } from
|
|
2
|
-
import { TokenMetadataBySymbol } from
|
|
1
|
+
import { ActiveAssetData, CandleChartData, CandleData, ClearinghouseState, UniverseAsset, WebData3AssetCtx, WsAllMidsData, PerpDexsResponse } from '../types';
|
|
2
|
+
import { TokenMetadataBySymbol } from '../utils/token-metadata-extractor';
|
|
3
3
|
interface HyperliquidDataState {
|
|
4
4
|
allMids: WsAllMidsData | null;
|
|
5
5
|
activeAssetData: Record<string, ActiveAssetData> | null;
|
|
@@ -3,7 +3,6 @@ interface UserDataState {
|
|
|
3
3
|
accessToken: string | null;
|
|
4
4
|
refreshToken: string | null;
|
|
5
5
|
isAuthenticated: boolean;
|
|
6
|
-
isReady: boolean;
|
|
7
6
|
address: string | null;
|
|
8
7
|
tradeHistories: TradeHistoryDataDto[] | null;
|
|
9
8
|
rawOpenPositions: RawPositionDto[] | null;
|
|
@@ -27,7 +26,6 @@ interface UserDataState {
|
|
|
27
26
|
setNotifications: (value: NotificationDto[] | null) => void;
|
|
28
27
|
setSpotState: (value: SpotState | null) => void;
|
|
29
28
|
setUserAbstractionMode: (value: UserAbstraction | null) => void;
|
|
30
|
-
setIsReady: (value: boolean) => void;
|
|
31
29
|
clean: () => void;
|
|
32
30
|
}
|
|
33
31
|
export declare const useUserData: import("zustand").UseBoundStore<import("zustand").StoreApi<UserDataState>>;
|
package/dist/utils/http.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AxiosInstance } from
|
|
2
|
-
import { ApiErrorResponse } from
|
|
1
|
+
import type { AxiosInstance } from 'axios';
|
|
2
|
+
import { ApiErrorResponse } from '../types';
|
|
3
3
|
export declare function toApiError(error: unknown): ApiErrorResponse;
|
|
4
4
|
export declare function joinUrl(baseUrl: string, path: string): string;
|
|
5
5
|
/**
|