@pear-protocol/hyperliquid-sdk 0.1.13-beta.2 → 0.1.14

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.
@@ -1,4 +1,4 @@
1
- import type { ApiResponse, GetEIP712MessageResponse, AuthenticateRequest, AuthenticateResponse, RefreshTokenResponse, LogoutResponse } from "../types";
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
  /**
@@ -1,4 +1,4 @@
1
- import type { GetEIP712MessageResponse } from '../types';
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 setAddress: (address: string | null) => void;
14
- readonly clearSession: () => void;
15
13
  };
package/dist/index.d.ts CHANGED
@@ -283,6 +283,7 @@ interface PositionAssetDetailDto {
283
283
  unrealizedPnl: number;
284
284
  liquidationPrice: number;
285
285
  initialWeight: number;
286
+ currentWeight: number;
286
287
  fundingPaid?: number;
287
288
  metadata?: TokenMetadata | null;
288
289
  }
@@ -1429,8 +1430,6 @@ declare function useAuth(): {
1429
1430
  readonly loginWithPrivyToken: (address: string, appId: string, privyAccessToken: string) => Promise<void>;
1430
1431
  readonly refreshTokens: () => Promise<RefreshTokenResponse>;
1431
1432
  readonly logout: () => Promise<void>;
1432
- readonly setAddress: (address: string | null) => void;
1433
- readonly clearSession: () => void;
1434
1433
  };
1435
1434
 
1436
1435
  interface MarginRequiredPerCollateral {
package/dist/index.js CHANGED
@@ -65,29 +65,18 @@ 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
- setIsReady: (value) => set({ isReady: value }),
74
- setAddress: (address) => set((state) => {
75
- // If address changed, clear user-specific data to prevent stale balances
76
- const addressChanged = state.address !== null && state.address !== address;
77
- if (addressChanged) {
78
- return {
79
- address,
80
- // Clear user-specific data when address changes
81
- spotState: null,
82
- tradeHistories: null,
83
- rawOpenPositions: null,
84
- openOrders: null,
85
- accountSummary: null,
86
- twapDetails: null,
87
- notifications: null,
88
- userExtraAgents: null,
89
- userAbstractionMode: null,
90
- };
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
+ }
91
80
  }
92
81
  return { address };
93
82
  }),
@@ -99,6 +88,10 @@ const useUserData = create((set) => ({
99
88
  setNotifications: (value) => set({ notifications: value }),
100
89
  setSpotState: (value) => set({ spotState: value }),
101
90
  clean: () => set({
91
+ accessToken: null,
92
+ refreshToken: null,
93
+ isAuthenticated: false,
94
+ address: null,
102
95
  tradeHistories: null,
103
96
  rawOpenPositions: null,
104
97
  openOrders: null,
@@ -558,7 +551,7 @@ const useHyperliquidData = create((set) => ({
558
551
  tokenMetadata: refreshTokenMetadata(state, { allMids: value }),
559
552
  })),
560
553
  setActiveAssetData: (value) => set((state) => {
561
- const activeAssetData = typeof value === "function" ? value(state.activeAssetData) : value;
554
+ const activeAssetData = typeof value === 'function' ? value(state.activeAssetData) : value;
562
555
  return {
563
556
  activeAssetData,
564
557
  tokenMetadata: refreshTokenMetadata(state, { activeAssetData }),
@@ -598,10 +591,7 @@ const useHyperliquidData = create((set) => ({
598
591
  setCandleData: (value) => set({ candleData: value }),
599
592
  upsertActiveAssetData: (key, value) => set((state) => {
600
593
  var _a;
601
- const activeAssetData = {
602
- ...((_a = state.activeAssetData) !== null && _a !== void 0 ? _a : {}),
603
- [key]: value,
604
- };
594
+ const activeAssetData = { ...((_a = state.activeAssetData) !== null && _a !== void 0 ? _a : {}), [key]: value };
605
595
  return {
606
596
  activeAssetData,
607
597
  tokenMetadata: refreshTokenMetadata(state, { activeAssetData }, { symbols: [key] }),
@@ -636,11 +626,6 @@ const useHyperliquidData = create((set) => ({
636
626
  perpMetasByDex: state.perpMetasByDex,
637
627
  }),
638
628
  })),
639
- // Clear user-specific data (called when wallet address changes)
640
- clearUserData: () => set({
641
- aggregatedClearingHouseState: null,
642
- rawClearinghouseStates: null,
643
- }),
644
629
  }));
645
630
 
646
631
  /**
@@ -932,9 +917,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
932
917
  try {
933
918
  const message = JSON.parse(event.data);
934
919
  // Handle subscription responses
935
- if ("success" in message || "error" in message) {
920
+ if ('success' in message || 'error' in message) {
936
921
  if (message.error) {
937
- console.error("[HyperLiquid WS] Subscription error:", message.error);
922
+ console.error('[HyperLiquid WS] Subscription error:', message.error);
938
923
  setLastError(message.error);
939
924
  }
940
925
  else {
@@ -943,44 +928,44 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
943
928
  return;
944
929
  }
945
930
  // Handle channel data messages
946
- if ("channel" in message && "data" in message) {
931
+ if ('channel' in message && 'data' in message) {
947
932
  const response = message;
948
933
  switch (response.channel) {
949
- case "userFills":
934
+ case 'userFills':
950
935
  {
951
936
  const maybePromise = (_a = onUserFillsRef.current) === null || _a === void 0 ? void 0 : _a.call(onUserFillsRef);
952
937
  if (maybePromise instanceof Promise) {
953
- maybePromise.catch((err) => console.error("[HyperLiquid WS] userFills callback error", err));
938
+ maybePromise.catch((err) => console.error('[HyperLiquid WS] userFills callback error', err));
954
939
  }
955
940
  }
956
941
  break;
957
- case "webData3":
942
+ case 'webData3':
958
943
  const webData3 = response.data;
959
944
  // finalAssetContexts now sourced from allDexsAssetCtxs channel
960
945
  const finalAtOICaps = webData3.perpDexStates.flatMap((dex) => dex.perpsAtOpenInterestCap);
961
946
  setFinalAtOICaps(finalAtOICaps);
962
947
  setUserAbstractionMode(webData3.userState.abstraction || null);
963
948
  break;
964
- case "allDexsAssetCtxs":
949
+ case 'allDexsAssetCtxs':
965
950
  {
966
951
  const data = response.data;
967
952
  // Store by DEX name, mapping '' to 'HYPERLIQUID'
968
953
  const assetContextsByDex = new Map();
969
954
  data.ctxs.forEach(([dexKey, ctxs]) => {
970
- const dexName = dexKey === "" ? "HYPERLIQUID" : dexKey;
955
+ const dexName = dexKey === '' ? 'HYPERLIQUID' : dexKey;
971
956
  assetContextsByDex.set(dexName, ctxs || []);
972
957
  });
973
958
  setAssetContextsByDex(assetContextsByDex);
974
959
  }
975
960
  break;
976
- case "allDexsClearinghouseState":
961
+ case 'allDexsClearinghouseState':
977
962
  {
978
963
  const data = response.data;
979
964
  const states = (data.clearinghouseStates || [])
980
965
  .map(([, s]) => s)
981
966
  .filter(Boolean);
982
- const sum = (values) => values.reduce((acc, v) => acc + (parseFloat(v || "0") || 0), 0);
983
- const toStr = (n) => Number.isFinite(n) ? n.toString() : "0";
967
+ const sum = (values) => values.reduce((acc, v) => acc + (parseFloat(v || '0') || 0), 0);
968
+ const toStr = (n) => Number.isFinite(n) ? n.toString() : '0';
984
969
  const assetPositions = states.flatMap((s) => s.assetPositions || []);
985
970
  const crossMaintenanceMarginUsed = toStr(sum(states.map((s) => s.crossMaintenanceMarginUsed)));
986
971
  const crossMarginSummary = {
@@ -1010,26 +995,26 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1010
995
  setClearinghouseStateReceived(true);
1011
996
  }
1012
997
  break;
1013
- case "allMids":
998
+ case 'allMids':
1014
999
  {
1015
1000
  const data = response.data;
1016
1001
  setAllMids(data);
1017
1002
  }
1018
1003
  break;
1019
- case "activeAssetData":
1004
+ case 'activeAssetData':
1020
1005
  {
1021
1006
  const assetData = response.data;
1022
1007
  upsertActiveAssetData(assetData.coin, assetData);
1023
1008
  }
1024
1009
  break;
1025
- case "candle":
1010
+ case 'candle':
1026
1011
  {
1027
1012
  const candleDataItem = response.data;
1028
- const symbol = candleDataItem.s || "";
1013
+ const symbol = candleDataItem.s || '';
1029
1014
  addCandleData(symbol, candleDataItem);
1030
1015
  }
1031
1016
  break;
1032
- case "spotState":
1017
+ case 'spotState':
1033
1018
  {
1034
1019
  const spotStateData = response.data;
1035
1020
  if (spotStateData === null || spotStateData === void 0 ? void 0 : spotStateData.spotState) {
@@ -1044,7 +1029,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1044
1029
  }
1045
1030
  catch (error) {
1046
1031
  const errorMessage = `Failed to parse message: ${error instanceof Error ? error.message : String(error)}`;
1047
- console.error("[HyperLiquid WS] Parse error:", errorMessage, "Raw message:", event.data);
1032
+ console.error('[HyperLiquid WS] Parse error:', errorMessage, 'Raw message:', event.data);
1048
1033
  setLastError(errorMessage);
1049
1034
  }
1050
1035
  }, [
@@ -1058,7 +1043,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1058
1043
  setSpotState,
1059
1044
  ]);
1060
1045
  const connect = useCallback(() => {
1061
- console.log("[HyperLiquid WS] connect() called, enabled:", enabled);
1046
+ console.log('[HyperLiquid WS] connect() called, enabled:', enabled);
1062
1047
  if (!enabled)
1063
1048
  return;
1064
1049
  // Clear any pending reconnect timeout
@@ -1074,10 +1059,10 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1074
1059
  console.log('[HyperLiquid WS] connect() returning early - socket already exists, readyState:', wsRef.current.readyState);
1075
1060
  return;
1076
1061
  }
1077
- console.log("[HyperLiquid WS] Creating new WebSocket connection");
1062
+ console.log('[HyperLiquid WS] Creating new WebSocket connection');
1078
1063
  manualCloseRef.current = false;
1079
1064
  setReadyState(ReadyState.CONNECTING);
1080
- const ws = new WebSocket("wss://api.hyperliquid.xyz/ws");
1065
+ const ws = new WebSocket('wss://api.hyperliquid.xyz/ws');
1081
1066
  wsRef.current = ws;
1082
1067
  ws.onopen = () => {
1083
1068
  reconnectAttemptsRef.current = 0;
@@ -1086,8 +1071,8 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1086
1071
  };
1087
1072
  ws.onmessage = handleMessage;
1088
1073
  ws.onerror = (event) => {
1089
- console.error("[HyperLiquid WS] Connection error:", event);
1090
- setLastError("WebSocket error");
1074
+ console.error('[HyperLiquid WS] Connection error:', event);
1075
+ setLastError('WebSocket error');
1091
1076
  };
1092
1077
  ws.onclose = () => {
1093
1078
  setReadyState(ReadyState.CLOSED);
@@ -1179,7 +1164,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1179
1164
  if (isConnected) {
1180
1165
  // Send ping every 30 seconds
1181
1166
  pingIntervalRef.current = setInterval(() => {
1182
- sendJsonMessage({ method: "ping" });
1167
+ sendJsonMessage({ method: 'ping' });
1183
1168
  }, 30000);
1184
1169
  }
1185
1170
  else {
@@ -1197,27 +1182,27 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1197
1182
  }, [isConnected, sendJsonMessage]);
1198
1183
  // Handle address subscription changes
1199
1184
  useEffect(() => {
1200
- const DEFAULT_ADDRESS = "0x0000000000000000000000000000000000000000";
1185
+ const DEFAULT_ADDRESS = '0x0000000000000000000000000000000000000000';
1201
1186
  const userAddress = (address || DEFAULT_ADDRESS).toLowerCase();
1202
1187
  const normalizedSubscribedAddress = (subscribedAddress === null || subscribedAddress === void 0 ? void 0 : subscribedAddress.toLowerCase()) || null;
1203
- console.log("[HyperLiquid WS] Address subscription effect running");
1204
- console.log("[HyperLiquid WS] address:", address, "userAddress:", userAddress, "subscribedAddress:", subscribedAddress, "normalizedSubscribedAddress:", normalizedSubscribedAddress);
1205
- console.log("[HyperLiquid WS] isConnected:", isConnected);
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);
1206
1191
  if (normalizedSubscribedAddress === userAddress) {
1207
- console.log("[HyperLiquid WS] Address unchanged, skipping subscription update");
1192
+ console.log('[HyperLiquid WS] Address unchanged, skipping subscription update');
1208
1193
  return;
1209
1194
  }
1210
1195
  if (!isConnected) {
1211
- console.log("[HyperLiquid WS] Not connected, skipping subscription update");
1196
+ console.log('[HyperLiquid WS] Not connected, skipping subscription update');
1212
1197
  return;
1213
1198
  }
1214
1199
  // Unsubscribe from previous address if exists
1215
1200
  if (subscribedAddress) {
1216
- console.log("[HyperLiquid WS] Unsubscribing from previous address:", subscribedAddress);
1201
+ console.log('[HyperLiquid WS] Unsubscribing from previous address:', subscribedAddress);
1217
1202
  const unsubscribeMessage = {
1218
- method: "unsubscribe",
1203
+ method: 'unsubscribe',
1219
1204
  subscription: {
1220
- type: "webData3",
1205
+ type: 'webData3',
1221
1206
  user: subscribedAddress,
1222
1207
  },
1223
1208
  };
@@ -1225,54 +1210,54 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1225
1210
  // Unsubscribe from spotState for previous address
1226
1211
  if (subscribedAddress !== DEFAULT_ADDRESS) {
1227
1212
  const unsubscribeSpotState = {
1228
- method: "unsubscribe",
1213
+ method: 'unsubscribe',
1229
1214
  subscription: {
1230
- type: "spotState",
1215
+ type: 'spotState',
1231
1216
  user: subscribedAddress,
1232
1217
  },
1233
1218
  };
1234
1219
  sendJsonMessage(unsubscribeSpotState);
1235
1220
  }
1236
1221
  const unsubscribeAllDexsClearinghouseState = {
1237
- method: "unsubscribe",
1222
+ method: 'unsubscribe',
1238
1223
  subscription: {
1239
- type: "allDexsClearinghouseState",
1224
+ type: 'allDexsClearinghouseState',
1240
1225
  user: subscribedAddress,
1241
1226
  },
1242
1227
  };
1243
1228
  sendJsonMessage(unsubscribeAllDexsClearinghouseState);
1244
1229
  const unsubscribeUserFills = {
1245
- method: "unsubscribe",
1230
+ method: 'unsubscribe',
1246
1231
  subscription: {
1247
- type: "userFills",
1232
+ type: 'userFills',
1248
1233
  user: subscribedAddress,
1249
1234
  },
1250
1235
  };
1251
1236
  sendJsonMessage(unsubscribeUserFills);
1252
1237
  }
1253
1238
  const subscribeWebData3 = {
1254
- method: "subscribe",
1239
+ method: 'subscribe',
1255
1240
  subscription: {
1256
- type: "webData3",
1241
+ type: 'webData3',
1257
1242
  user: userAddress,
1258
1243
  },
1259
1244
  };
1260
1245
  // Subscribe to allMids
1261
1246
  const subscribeAllMids = {
1262
- method: "subscribe",
1247
+ method: 'subscribe',
1263
1248
  subscription: {
1264
- type: "allMids",
1265
- dex: "ALL_DEXS",
1249
+ type: 'allMids',
1250
+ dex: 'ALL_DEXS',
1266
1251
  },
1267
1252
  };
1268
1253
  // Subscribe to allDexsAssetCtxs (no payload params, global feed)
1269
1254
  const subscribeAllDexsAssetCtxs = {
1270
- method: "subscribe",
1255
+ method: 'subscribe',
1271
1256
  subscription: {
1272
- type: "allDexsAssetCtxs",
1257
+ type: 'allDexsAssetCtxs',
1273
1258
  },
1274
1259
  };
1275
- console.log("[HyperLiquid WS] Subscribing to new address:", userAddress);
1260
+ console.log('[HyperLiquid WS] Subscribing to new address:', userAddress);
1276
1261
  sendJsonMessage(subscribeWebData3);
1277
1262
  sendJsonMessage(subscribeAllMids);
1278
1263
  sendJsonMessage(subscribeAllDexsAssetCtxs);
@@ -1280,9 +1265,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1280
1265
  // Only subscribe if we have a real user address (not the default)
1281
1266
  if (userAddress !== DEFAULT_ADDRESS.toLowerCase()) {
1282
1267
  const subscribeSpotState = {
1283
- method: "subscribe",
1268
+ method: 'subscribe',
1284
1269
  subscription: {
1285
- type: "spotState",
1270
+ type: 'spotState',
1286
1271
  user: userAddress,
1287
1272
  },
1288
1273
  };
@@ -1292,9 +1277,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1292
1277
  // Only subscribe if we have a real user address (not the default)
1293
1278
  if (userAddress !== DEFAULT_ADDRESS.toLowerCase()) {
1294
1279
  const subscribeAllDexsClearinghouseState = {
1295
- method: "subscribe",
1280
+ method: 'subscribe',
1296
1281
  subscription: {
1297
- type: "allDexsClearinghouseState",
1282
+ type: 'allDexsClearinghouseState',
1298
1283
  user: userAddress,
1299
1284
  },
1300
1285
  };
@@ -1328,9 +1313,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1328
1313
  !userSummary)
1329
1314
  return;
1330
1315
  const subscribeUserFills = {
1331
- method: "subscribe",
1316
+ method: 'subscribe',
1332
1317
  subscription: {
1333
- type: "userFills",
1318
+ type: 'userFills',
1334
1319
  user: subscribedAddress,
1335
1320
  },
1336
1321
  };
@@ -1352,9 +1337,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1352
1337
  // Unsubscribe from tokens no longer in the list
1353
1338
  tokensToUnsubscribe.forEach((token) => {
1354
1339
  const unsubscribeMessage = {
1355
- method: "unsubscribe",
1340
+ method: 'unsubscribe',
1356
1341
  subscription: {
1357
- type: "activeAssetData",
1342
+ type: 'activeAssetData',
1358
1343
  user: address,
1359
1344
  coin: token,
1360
1345
  },
@@ -1364,9 +1349,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1364
1349
  // Subscribe to new tokens
1365
1350
  tokensToSubscribe.forEach((token) => {
1366
1351
  const subscribeMessage = {
1367
- method: "subscribe",
1352
+ method: 'subscribe',
1368
1353
  subscription: {
1369
- type: "activeAssetData",
1354
+ type: 'activeAssetData',
1370
1355
  user: address,
1371
1356
  coin: token,
1372
1357
  },
@@ -1395,9 +1380,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1395
1380
  if (prevInterval && prevInterval !== candleInterval) {
1396
1381
  subscribedCandleTokens.forEach((token) => {
1397
1382
  const unsubscribeMessage = {
1398
- method: "unsubscribe",
1383
+ method: 'unsubscribe',
1399
1384
  subscription: {
1400
- type: "candle",
1385
+ type: 'candle',
1401
1386
  coin: token,
1402
1387
  interval: prevInterval,
1403
1388
  },
@@ -1412,9 +1397,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1412
1397
  // Unsubscribe from tokens no longer in the list
1413
1398
  tokensToUnsubscribe.forEach((token) => {
1414
1399
  const unsubscribeMessage = {
1415
- method: "unsubscribe",
1400
+ method: 'unsubscribe',
1416
1401
  subscription: {
1417
- type: "candle",
1402
+ type: 'candle',
1418
1403
  coin: token,
1419
1404
  interval: candleInterval,
1420
1405
  },
@@ -1424,9 +1409,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1424
1409
  // Subscribe to new tokens
1425
1410
  tokensToSubscribe.forEach((token) => {
1426
1411
  const subscribeMessage = {
1427
- method: "subscribe",
1412
+ method: 'subscribe',
1428
1413
  subscription: {
1429
- type: "candle",
1414
+ type: 'candle',
1430
1415
  coin: token,
1431
1416
  interval: candleInterval,
1432
1417
  },
@@ -5941,10 +5926,10 @@ function toApiError(error) {
5941
5926
  var _a;
5942
5927
  const axiosError = error;
5943
5928
  const payload = (axiosError && axiosError.response ? axiosError.response.data : undefined);
5944
- const message = typeof payload === "object" && payload && "message" in payload
5929
+ const message = typeof payload === 'object' && payload && 'message' in payload
5945
5930
  ? String(payload.message)
5946
- : (axiosError === null || axiosError === void 0 ? void 0 : axiosError.message) || "Request failed";
5947
- const errField = typeof payload === "object" && payload && "error" in payload
5931
+ : (axiosError === null || axiosError === void 0 ? void 0 : axiosError.message) || 'Request failed';
5932
+ const errField = typeof payload === 'object' && payload && 'error' in payload
5948
5933
  ? String(payload.error)
5949
5934
  : undefined;
5950
5935
  return {
@@ -5954,8 +5939,8 @@ function toApiError(error) {
5954
5939
  };
5955
5940
  }
5956
5941
  function joinUrl(baseUrl, path) {
5957
- const cleanBase = baseUrl.replace(/\/$/, "");
5958
- const cleanPath = path.startsWith("/") ? path : `/${path}`;
5942
+ const cleanBase = baseUrl.replace(/\/$/, '');
5943
+ const cleanPath = path.startsWith('/') ? path : `/${path}`;
5959
5944
  return `${cleanBase}${cleanPath}`;
5960
5945
  }
5961
5946
  /**
@@ -5984,7 +5969,7 @@ function addAuthInterceptors(params) {
5984
5969
  pendingRequests = [];
5985
5970
  }
5986
5971
  const isOurApiUrl = (url) => Boolean(url && url.startsWith(apiBaseUrl));
5987
- const isRefreshUrl = (url) => Boolean(url && url.startsWith(joinUrl(apiBaseUrl, "/auth/refresh")));
5972
+ const isRefreshUrl = (url) => Boolean(url && url.startsWith(joinUrl(apiBaseUrl, '/auth/refresh')));
5988
5973
  const reqId = apiClient.interceptors.request.use((config) => {
5989
5974
  var _a;
5990
5975
  try {
@@ -5992,12 +5977,11 @@ function addAuthInterceptors(params) {
5992
5977
  const token = getAccessToken();
5993
5978
  if (token) {
5994
5979
  config.headers = (_a = config.headers) !== null && _a !== void 0 ? _a : {};
5995
- config.headers["Authorization"] = `Bearer ${token}`;
5980
+ (config.headers)['Authorization'] = `Bearer ${token}`;
5996
5981
  }
5997
5982
  }
5998
5983
  }
5999
- catch (err) {
6000
- console.error("[Auth Interceptor] Request interceptor error:", err);
5984
+ catch (_b) {
6001
5985
  }
6002
5986
  return config;
6003
5987
  });
@@ -6008,36 +5992,22 @@ function addAuthInterceptors(params) {
6008
5992
  const url = originalRequest === null || originalRequest === void 0 ? void 0 : originalRequest.url;
6009
5993
  // If not our API or not 401, just reject
6010
5994
  if (!status || status !== 401 || !isOurApiUrl(url)) {
6011
- if (status === 401) {
6012
- console.warn("[Auth Interceptor] 401 received but URL check failed:", {
6013
- url,
6014
- apiBaseUrl,
6015
- isOurApiUrl: isOurApiUrl(url),
6016
- });
6017
- }
6018
5995
  return Promise.reject(error);
6019
5996
  }
6020
- console.log("[Auth Interceptor] 401 detected, attempting token refresh for URL:", url);
6021
5997
  // If the 401 is from refresh endpoint itself -> force logout
6022
5998
  if (isRefreshUrl(url)) {
6023
- console.warn("[Auth Interceptor] Refresh endpoint returned 401, logging out");
6024
5999
  try {
6025
6000
  await logout();
6026
6001
  }
6027
- catch (err) {
6028
- console.error("[Auth Interceptor] Logout failed:", err);
6029
- }
6002
+ catch (_d) { }
6030
6003
  return Promise.reject(error);
6031
6004
  }
6032
6005
  // Prevent infinite loop
6033
6006
  if (originalRequest && originalRequest._retry) {
6034
- console.warn("[Auth Interceptor] Request already retried, logging out");
6035
6007
  try {
6036
6008
  await logout();
6037
6009
  }
6038
- catch (err) {
6039
- console.error("[Auth Interceptor] Logout failed:", err);
6040
- }
6010
+ catch (_e) { }
6041
6011
  return Promise.reject(error);
6042
6012
  }
6043
6013
  // Mark so we don't retry twice
@@ -6051,45 +6021,31 @@ function addAuthInterceptors(params) {
6051
6021
  if (!newToken || !originalRequest)
6052
6022
  return reject(error);
6053
6023
  originalRequest.headers = (_a = originalRequest.headers) !== null && _a !== void 0 ? _a : {};
6054
- originalRequest.headers["Authorization"] =
6055
- `Bearer ${newToken}`;
6024
+ originalRequest.headers['Authorization'] = `Bearer ${newToken}`;
6056
6025
  resolve(apiClient.request(originalRequest));
6057
6026
  });
6058
6027
  });
6059
6028
  }
6060
6029
  isRefreshing = true;
6061
6030
  try {
6062
- console.log("[Auth Interceptor] Refreshing tokens...");
6063
6031
  const refreshed = await refreshTokens();
6064
- const newAccessToken = (_b = (refreshed &&
6065
- (refreshed.accessToken || ((_a = refreshed.data) === null || _a === void 0 ? void 0 : _a.accessToken)))) !== null && _b !== void 0 ? _b : null;
6066
- if (!newAccessToken) {
6067
- console.error("[Auth Interceptor] Token refresh succeeded but no access token in response:", refreshed);
6068
- }
6069
- else {
6070
- console.log("[Auth Interceptor] Token refresh successful");
6071
- }
6032
+ const newAccessToken = (_b = (refreshed && (refreshed.accessToken || ((_a = refreshed.data) === null || _a === void 0 ? void 0 : _a.accessToken)))) !== null && _b !== void 0 ? _b : null;
6072
6033
  resolvePendingRequests(newAccessToken);
6073
6034
  if (originalRequest) {
6074
6035
  originalRequest.headers = (_c = originalRequest.headers) !== null && _c !== void 0 ? _c : {};
6075
6036
  if (newAccessToken)
6076
- originalRequest.headers["Authorization"] =
6077
- `Bearer ${newAccessToken}`;
6078
- console.log("[Auth Interceptor] Retrying original request with new token");
6037
+ (originalRequest.headers)['Authorization'] = `Bearer ${newAccessToken}`;
6079
6038
  const resp = await apiClient.request(originalRequest);
6080
6039
  return resp;
6081
6040
  }
6082
6041
  return Promise.reject(error);
6083
6042
  }
6084
6043
  catch (refreshErr) {
6085
- console.error("[Auth Interceptor] Token refresh failed:", refreshErr);
6086
6044
  resolvePendingRequests(null);
6087
6045
  try {
6088
6046
  await logout();
6089
6047
  }
6090
- catch (err) {
6091
- console.error("[Auth Interceptor] Logout failed:", err);
6092
- }
6048
+ catch (_f) { }
6093
6049
  return Promise.reject(refreshErr);
6094
6050
  }
6095
6051
  finally {
@@ -6100,15 +6056,11 @@ function addAuthInterceptors(params) {
6100
6056
  try {
6101
6057
  apiClient.interceptors.request.eject(reqId);
6102
6058
  }
6103
- catch (err) {
6104
- console.error("[Auth Interceptor] Failed to eject request interceptor:", err);
6105
- }
6059
+ catch (_a) { }
6106
6060
  try {
6107
6061
  apiClient.interceptors.response.eject(resId);
6108
6062
  }
6109
- catch (err) {
6110
- console.error("[Auth Interceptor] Failed to eject response interceptor:", err);
6111
- }
6063
+ catch (_b) { }
6112
6064
  };
6113
6065
  }
6114
6066
 
@@ -7012,7 +6964,7 @@ async function updateLeverage(baseUrl, positionId, payload) {
7012
6964
  }
7013
6965
  }
7014
6966
 
7015
- const calculatePositionAsset = (asset, currentPrice, totalInitialPositionSize, leverage, metadata, isLong = true) => {
6967
+ const calculatePositionAsset = (asset, currentPrice, totalInitialPositionSize, totalCurrentPositionSize, leverage, metadata, isLong = true) => {
7016
6968
  var _a;
7017
6969
  const entryNotional = asset.entryPrice * asset.size;
7018
6970
  const currentNotional = currentPrice * asset.size;
@@ -7033,6 +6985,7 @@ const calculatePositionAsset = (asset, currentPrice, totalInitialPositionSize, l
7033
6985
  unrealizedPnl: unrealizedPnl,
7034
6986
  entryPositionValue: entryNotional,
7035
6987
  initialWeight: totalInitialPositionSize > 0 ? entryNotional / totalInitialPositionSize : 0,
6988
+ currentWeight: totalCurrentPositionSize > 0 ? currentNotional / totalCurrentPositionSize : 0,
7036
6989
  fundingPaid: (_a = asset.fundingPaid) !== null && _a !== void 0 ? _a : 0,
7037
6990
  metadata,
7038
6991
  };
@@ -7057,13 +7010,23 @@ const buildPositionValue = (rawPositions, clearinghouseState, getAssetByName) =>
7057
7010
  let entryMarginUsed = 0;
7058
7011
  const totalInitialPositionSize = position.longAssets.reduce((acc, asset) => acc + asset.entryPrice * asset.size, 0) +
7059
7012
  position.shortAssets.reduce((acc, asset) => acc + asset.entryPrice * asset.size, 0);
7013
+ const totalCurrentPositionSize = position.longAssets.reduce((acc, asset) => {
7014
+ var _a, _b;
7015
+ const currentPrice = (_b = (_a = getAssetByName(asset.coin)) === null || _a === void 0 ? void 0 : _a.currentPrice) !== null && _b !== void 0 ? _b : 0;
7016
+ return acc + currentPrice * asset.size;
7017
+ }, 0) +
7018
+ position.shortAssets.reduce((acc, asset) => {
7019
+ var _a, _b;
7020
+ const currentPrice = (_b = (_a = getAssetByName(asset.coin)) === null || _a === void 0 ? void 0 : _a.currentPrice) !== null && _b !== void 0 ? _b : 0;
7021
+ return acc + currentPrice * asset.size;
7022
+ }, 0);
7060
7023
  mappedPosition.longAssets = position.longAssets.map((longAsset) => {
7061
7024
  var _a, _b, _c, _d;
7062
7025
  const metadata = getAssetByName(longAsset.coin);
7063
7026
  const currentPrice = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.currentPrice) !== null && _a !== void 0 ? _a : 0;
7064
7027
  const assetState = (_b = clearinghouseState.assetPositions.find((ap) => ap.position.coin === longAsset.coin)) === null || _b === void 0 ? void 0 : _b.position;
7065
7028
  const leverage = (_d = (_c = assetState === null || assetState === void 0 ? void 0 : assetState.leverage) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : longAsset.leverage;
7066
- const mappedPositionAssets = calculatePositionAsset(longAsset, currentPrice, totalInitialPositionSize, leverage, metadata, true);
7029
+ const mappedPositionAssets = calculatePositionAsset(longAsset, currentPrice, totalInitialPositionSize, totalCurrentPositionSize, leverage, metadata, true);
7067
7030
  mappedPosition.entryPositionValue +=
7068
7031
  mappedPositionAssets.entryPositionValue;
7069
7032
  mappedPosition.unrealizedPnl += mappedPositionAssets.unrealizedPnl;
@@ -7071,7 +7034,7 @@ const buildPositionValue = (rawPositions, clearinghouseState, getAssetByName) =>
7071
7034
  mappedPosition.marginUsed += mappedPositionAssets.marginUsed;
7072
7035
  entryMarginUsed += mappedPositionAssets.entryMarginUsed;
7073
7036
  mappedPosition.entryRatio *= Math.pow(longAsset.entryPrice, mappedPositionAssets.initialWeight);
7074
- mappedPosition.markRatio *= Math.pow(currentPrice, mappedPositionAssets.initialWeight);
7037
+ mappedPosition.markRatio *= Math.pow(currentPrice, mappedPositionAssets.currentWeight);
7075
7038
  return mappedPositionAssets;
7076
7039
  });
7077
7040
  mappedPosition.shortAssets = position.shortAssets.map((shortAsset) => {
@@ -7080,7 +7043,7 @@ const buildPositionValue = (rawPositions, clearinghouseState, getAssetByName) =>
7080
7043
  const currentPrice = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.currentPrice) !== null && _a !== void 0 ? _a : 0;
7081
7044
  const assetState = (_b = clearinghouseState.assetPositions.find((ap) => ap.position.coin === shortAsset.coin)) === null || _b === void 0 ? void 0 : _b.position;
7082
7045
  const leverage = (_d = (_c = assetState === null || assetState === void 0 ? void 0 : assetState.leverage) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : shortAsset.leverage;
7083
- const mappedPositionAssets = calculatePositionAsset(shortAsset, currentPrice, totalInitialPositionSize, leverage, metadata, false);
7046
+ const mappedPositionAssets = calculatePositionAsset(shortAsset, currentPrice, totalInitialPositionSize, totalCurrentPositionSize, leverage, metadata, false);
7084
7047
  mappedPosition.entryPositionValue +=
7085
7048
  mappedPositionAssets.entryPositionValue;
7086
7049
  mappedPosition.unrealizedPnl += mappedPositionAssets.unrealizedPnl;
@@ -7088,7 +7051,7 @@ const buildPositionValue = (rawPositions, clearinghouseState, getAssetByName) =>
7088
7051
  mappedPosition.marginUsed += mappedPositionAssets.marginUsed;
7089
7052
  entryMarginUsed += mappedPositionAssets.entryMarginUsed;
7090
7053
  mappedPosition.entryRatio *= Math.pow(shortAsset.entryPrice, -mappedPositionAssets.initialWeight);
7091
- mappedPosition.markRatio *= Math.pow(currentPrice, -mappedPositionAssets.initialWeight);
7054
+ mappedPosition.markRatio *= Math.pow(currentPrice, -mappedPositionAssets.currentWeight);
7092
7055
  return mappedPositionAssets;
7093
7056
  });
7094
7057
  mappedPosition.positionValue =
@@ -7614,34 +7577,20 @@ function usePortfolio() {
7614
7577
  }
7615
7578
 
7616
7579
  async function getEIP712Message(baseUrl, address, clientId) {
7617
- const url = joinUrl(baseUrl, "/auth/eip712-message");
7580
+ const url = joinUrl(baseUrl, '/auth/eip712-message');
7618
7581
  try {
7619
- const resp = await apiClient.get(url, {
7620
- params: { address, clientId },
7621
- timeout: 30000,
7622
- });
7623
- return {
7624
- data: resp.data,
7625
- status: resp.status,
7626
- headers: resp.headers,
7627
- };
7582
+ const resp = await axios$1.get(url, { params: { address, clientId }, timeout: 30000 });
7583
+ return { data: resp.data, status: resp.status, headers: resp.headers };
7628
7584
  }
7629
7585
  catch (error) {
7630
7586
  throw toApiError(error);
7631
7587
  }
7632
7588
  }
7633
7589
  async function authenticate(baseUrl, body) {
7634
- const url = joinUrl(baseUrl, "/auth/login");
7590
+ const url = joinUrl(baseUrl, '/auth/login');
7635
7591
  try {
7636
- const resp = await apiClient.post(url, body, {
7637
- headers: { "Content-Type": "application/json" },
7638
- timeout: 30000,
7639
- });
7640
- return {
7641
- data: resp.data,
7642
- status: resp.status,
7643
- headers: resp.headers,
7644
- };
7592
+ const resp = await axios$1.post(url, body, { headers: { 'Content-Type': 'application/json' }, timeout: 30000 });
7593
+ return { data: resp.data, status: resp.status, headers: resp.headers };
7645
7594
  }
7646
7595
  catch (error) {
7647
7596
  throw toApiError(error);
@@ -7652,7 +7601,7 @@ async function authenticate(baseUrl, body) {
7652
7601
  */
7653
7602
  async function authenticateWithPrivy(baseUrl, params) {
7654
7603
  const body = {
7655
- method: "privy_access_token",
7604
+ method: 'privy_access_token',
7656
7605
  address: params.address,
7657
7606
  clientId: params.clientId,
7658
7607
  details: { appId: params.appId, accessToken: params.accessToken },
@@ -7660,124 +7609,62 @@ async function authenticateWithPrivy(baseUrl, params) {
7660
7609
  return authenticate(baseUrl, body);
7661
7610
  }
7662
7611
  async function refreshToken(baseUrl, refreshTokenVal) {
7663
- const url = joinUrl(baseUrl, "/auth/refresh");
7612
+ const url = joinUrl(baseUrl, '/auth/refresh');
7664
7613
  try {
7665
- const resp = await apiClient.post(url, { refreshToken: refreshTokenVal }, { headers: { "Content-Type": "application/json" }, timeout: 30000 });
7666
- return {
7667
- data: resp.data,
7668
- status: resp.status,
7669
- headers: resp.headers,
7670
- };
7614
+ const resp = await axios$1.post(url, { refreshToken: refreshTokenVal }, { headers: { 'Content-Type': 'application/json' }, timeout: 30000 });
7615
+ return { data: resp.data, status: resp.status, headers: resp.headers };
7671
7616
  }
7672
7617
  catch (error) {
7673
7618
  throw toApiError(error);
7674
7619
  }
7675
7620
  }
7676
7621
  async function logout(baseUrl, refreshTokenVal) {
7677
- const url = joinUrl(baseUrl, "/auth/logout");
7622
+ const url = joinUrl(baseUrl, '/auth/logout');
7678
7623
  try {
7679
- const resp = await apiClient.post(url, { refreshToken: refreshTokenVal }, { headers: { "Content-Type": "application/json" }, timeout: 30000 });
7680
- return {
7681
- data: resp.data,
7682
- status: resp.status,
7683
- headers: resp.headers,
7684
- };
7624
+ const resp = await axios$1.post(url, { refreshToken: refreshTokenVal }, { headers: { 'Content-Type': 'application/json' }, timeout: 30000 });
7625
+ return { data: resp.data, status: resp.status, headers: resp.headers };
7685
7626
  }
7686
7627
  catch (error) {
7687
7628
  throw toApiError(error);
7688
7629
  }
7689
7630
  }
7690
7631
 
7691
- // Token expiration constants
7692
- const ACCESS_TOKEN_BUFFER_MS = 5 * 60 * 1000; // Refresh 5 min before expiry
7693
- const REFRESH_TOKEN_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days fallback
7694
- function nowMs() {
7695
- return Date.now();
7696
- }
7697
- function calcExpiresAt(expiresInSeconds) {
7698
- return nowMs() + expiresInSeconds * 1000;
7699
- }
7700
7632
  function useAuth() {
7701
7633
  const context = useContext(PearHyperliquidContext);
7702
7634
  if (!context) {
7703
- throw new Error('useAuth must be used within a PearHyperliquidProvider');
7635
+ throw new Error("usePortfolio must be used within a PearHyperliquidProvider");
7704
7636
  }
7705
7637
  const { apiBaseUrl, clientId } = context;
7638
+ const [isReady, setIsReady] = useState(false);
7706
7639
  const accessToken = useUserData((s) => s.accessToken);
7707
7640
  const refreshToken$1 = useUserData((s) => s.refreshToken);
7708
- const isReady = useUserData((s) => s.isReady);
7709
- const isAuthenticated = useUserData((s) => s.isAuthenticated);
7710
7641
  const setAccessToken = useUserData((s) => s.setAccessToken);
7711
7642
  const setRefreshToken = useUserData((s) => s.setRefreshToken);
7712
- const setIsReady = useUserData((s) => s.setIsReady);
7643
+ const isAuthenticated = useUserData((s) => s.isAuthenticated);
7713
7644
  const setIsAuthenticated = useUserData((s) => s.setIsAuthenticated);
7714
7645
  const address = useUserData((s) => s.address);
7715
7646
  const setAddress = useUserData((s) => s.setAddress);
7716
- // Ref to prevent concurrent refresh attempts
7717
- const isRefreshingRef = useRef(false);
7718
7647
  useEffect(() => {
7719
- if (typeof window == 'undefined') {
7648
+ if (typeof window == "undefined") {
7720
7649
  return;
7721
7650
  }
7722
- if (address) {
7723
- const accessTokenKey = `${address}_accessToken`;
7724
- const refreshTokenKey = `${address}_refreshToken`;
7725
- const accessTokenExpiresAtKey = `${address}_accessTokenExpiresAt`;
7726
- const refreshTokenExpiresAtKey = `${address}_refreshTokenExpiresAt`;
7727
- const storedAccessToken = localStorage.getItem(accessTokenKey);
7728
- const storedRefreshToken = localStorage.getItem(refreshTokenKey);
7729
- const accessExpRaw = localStorage.getItem(accessTokenExpiresAtKey);
7730
- const refreshExpRaw = localStorage.getItem(refreshTokenExpiresAtKey);
7731
- const accessExp = accessExpRaw ? Number(accessExpRaw) : 0;
7732
- const refreshExp = refreshExpRaw ? Number(refreshExpRaw) : 0;
7733
- const now = nowMs();
7734
- const accessValid = !!storedAccessToken && accessExp > now;
7735
- const refreshValid = !!storedRefreshToken && refreshExp > now;
7736
- if (accessValid && refreshValid) {
7737
- // Both tokens are valid
7738
- setAccessToken(storedAccessToken);
7739
- setRefreshToken(storedRefreshToken);
7740
- setIsAuthenticated(true);
7741
- setIsReady(true);
7742
- }
7743
- else if (refreshValid) {
7744
- // Access token expired but refresh still valid → refresh immediately
7745
- setAccessToken(storedAccessToken);
7746
- setRefreshToken(storedRefreshToken);
7747
- (async () => {
7748
- try {
7749
- await refreshTokens();
7750
- }
7751
- catch (_a) {
7752
- // Refresh failed → clear tokens
7753
- setAccessToken(null);
7754
- setRefreshToken(null);
7755
- setIsAuthenticated(false);
7756
- }
7757
- setIsReady(true);
7758
- })();
7759
- return; // setIsReady will be called in the async block
7760
- }
7761
- else {
7762
- // Refresh expired or no tokens → clear
7763
- setAccessToken(null);
7764
- setRefreshToken(null);
7765
- setIsAuthenticated(false);
7766
- setIsReady(true);
7767
- }
7768
- }
7769
- else {
7770
- setIsReady(true);
7771
- }
7772
- }, [address]);
7651
+ const access = localStorage.getItem("accessToken");
7652
+ const refresh = localStorage.getItem("refreshToken");
7653
+ const addr = localStorage.getItem("address");
7654
+ setAccessToken(access);
7655
+ setRefreshToken(refresh);
7656
+ setAddress(addr);
7657
+ const authed = Boolean(access && addr);
7658
+ setIsAuthenticated(authed);
7659
+ setIsReady(true);
7660
+ }, [setAccessToken, setRefreshToken, setIsAuthenticated, setAddress]);
7773
7661
  useEffect(() => {
7774
7662
  const cleanup = addAuthInterceptors({
7775
7663
  apiBaseUrl,
7776
7664
  getAccessToken: () => {
7777
- if (typeof window === 'undefined')
7778
- return null;
7779
- // Read from Zustand state as single source of truth
7780
- return useUserData.getState().accessToken;
7665
+ return typeof window !== "undefined"
7666
+ ? window.localStorage.getItem("accessToken")
7667
+ : null;
7781
7668
  },
7782
7669
  refreshTokens: async () => {
7783
7670
  const data = await refreshTokens();
@@ -7791,55 +7678,6 @@ function useAuth() {
7791
7678
  cleanup();
7792
7679
  };
7793
7680
  }, [apiBaseUrl]);
7794
- // Proactive refresh effect: refresh when app regains focus or timer fires
7795
- useEffect(() => {
7796
- if (typeof window === 'undefined' || !address || !refreshToken$1)
7797
- return;
7798
- const refreshIfNeeded = async () => {
7799
- // Prevent concurrent refresh attempts
7800
- if (isRefreshingRef.current)
7801
- return;
7802
- // Read fresh expiration values from localStorage (not stale closure)
7803
- const accessExpRaw = localStorage.getItem(`${address}_accessTokenExpiresAt`);
7804
- const refreshExpRaw = localStorage.getItem(`${address}_refreshTokenExpiresAt`);
7805
- const accessExp = accessExpRaw ? Number(accessExpRaw) : 0;
7806
- const refreshExp = refreshExpRaw ? Number(refreshExpRaw) : 0;
7807
- const now = nowMs();
7808
- // If refresh token is already expired, do nothing
7809
- if (refreshExp <= now)
7810
- return;
7811
- // If access token is within buffer window, refresh
7812
- if (accessExp - now <= ACCESS_TOKEN_BUFFER_MS) {
7813
- isRefreshingRef.current = true;
7814
- try {
7815
- await refreshTokens();
7816
- }
7817
- catch (_a) {
7818
- // Refresh failed, interceptor will handle logout on next API call
7819
- }
7820
- finally {
7821
- isRefreshingRef.current = false;
7822
- }
7823
- }
7824
- };
7825
- const onVisibilityChange = () => {
7826
- if (document.visibilityState === 'visible') {
7827
- refreshIfNeeded();
7828
- }
7829
- };
7830
- document.addEventListener('visibilitychange', onVisibilityChange);
7831
- // Schedule timer for (accessExp - buffer)
7832
- const accessExpRaw = localStorage.getItem(`${address}_accessTokenExpiresAt`);
7833
- const accessExp = accessExpRaw ? Number(accessExpRaw) : 0;
7834
- const delay = Math.max(0, accessExp - nowMs() - ACCESS_TOKEN_BUFFER_MS);
7835
- const timer = window.setTimeout(() => {
7836
- refreshIfNeeded();
7837
- }, delay);
7838
- return () => {
7839
- document.removeEventListener('visibilitychange', onVisibilityChange);
7840
- clearTimeout(timer);
7841
- };
7842
- }, [address, refreshToken$1]);
7843
7681
  async function getEip712(address) {
7844
7682
  const { data } = await getEIP712Message(apiBaseUrl, address, clientId);
7845
7683
  return data;
@@ -7847,21 +7685,17 @@ function useAuth() {
7847
7685
  async function loginWithSignedMessage(address, signature, timestamp) {
7848
7686
  try {
7849
7687
  const { data } = await authenticate(apiBaseUrl, {
7850
- method: 'eip712',
7688
+ method: "eip712",
7851
7689
  address,
7852
7690
  clientId,
7853
7691
  details: { signature, timestamp },
7854
7692
  });
7855
- const accessTokenKey = `${address}_accessToken`;
7856
- const refreshTokenKey = `${address}_refreshToken`;
7857
- const accessTokenExpiresAtKey = `${address}_accessTokenExpiresAt`;
7858
- const refreshTokenExpiresAtKey = `${address}_refreshTokenExpiresAt`;
7859
- window.localStorage.setItem(accessTokenKey, data.accessToken);
7860
- window.localStorage.setItem(refreshTokenKey, data.refreshToken);
7861
- window.localStorage.setItem(accessTokenExpiresAtKey, String(calcExpiresAt(data.expiresIn)));
7862
- window.localStorage.setItem(refreshTokenExpiresAtKey, String(nowMs() + REFRESH_TOKEN_TTL_MS));
7693
+ window.localStorage.setItem("accessToken", data.accessToken);
7694
+ window.localStorage.setItem("refreshToken", data.refreshToken);
7695
+ window.localStorage.setItem("address", address);
7863
7696
  setAccessToken(data.accessToken);
7864
7697
  setRefreshToken(data.refreshToken);
7698
+ setAddress(address);
7865
7699
  setIsAuthenticated(true);
7866
7700
  }
7867
7701
  catch (e) {
@@ -7876,16 +7710,12 @@ function useAuth() {
7876
7710
  appId,
7877
7711
  accessToken: privyAccessToken,
7878
7712
  });
7879
- const accessTokenKey = `${address}_accessToken`;
7880
- const refreshTokenKey = `${address}_refreshToken`;
7881
- const accessTokenExpiresAtKey = `${address}_accessTokenExpiresAt`;
7882
- const refreshTokenExpiresAtKey = `${address}_refreshTokenExpiresAt`;
7883
- window.localStorage.setItem(accessTokenKey, data.accessToken);
7884
- window.localStorage.setItem(refreshTokenKey, data.refreshToken);
7885
- window.localStorage.setItem(accessTokenExpiresAtKey, String(calcExpiresAt(data.expiresIn)));
7886
- window.localStorage.setItem(refreshTokenExpiresAtKey, String(nowMs() + REFRESH_TOKEN_TTL_MS));
7713
+ window.localStorage.setItem("accessToken", data.accessToken);
7714
+ window.localStorage.setItem("refreshToken", data.refreshToken);
7715
+ window.localStorage.setItem("address", address);
7887
7716
  setAccessToken(data.accessToken);
7888
7717
  setRefreshToken(data.refreshToken);
7718
+ setAddress(address);
7889
7719
  setIsAuthenticated(true);
7890
7720
  }
7891
7721
  catch (e) {
@@ -7893,61 +7723,35 @@ function useAuth() {
7893
7723
  }
7894
7724
  }
7895
7725
  async function refreshTokens() {
7896
- const currentAddress = address;
7897
- const currentRefresh = refreshToken$1;
7898
- if (!currentRefresh || !currentAddress)
7899
- throw new Error('No refresh token');
7900
- const { data } = await refreshToken(apiBaseUrl, currentRefresh);
7901
- // Update tokens in localStorage
7902
- const accessTokenKey = `${currentAddress}_accessToken`;
7903
- const refreshTokenKey = `${currentAddress}_refreshToken`;
7904
- const accessTokenExpiresAtKey = `${currentAddress}_accessTokenExpiresAt`;
7905
- const refreshTokenExpiresAtKey = `${currentAddress}_refreshTokenExpiresAt`;
7906
- window.localStorage.setItem(accessTokenKey, data.accessToken);
7907
- window.localStorage.setItem(refreshTokenKey, data.refreshToken);
7908
- window.localStorage.setItem(accessTokenExpiresAtKey, String(calcExpiresAt(data.expiresIn)));
7909
- window.localStorage.setItem(refreshTokenExpiresAtKey, String(nowMs() + REFRESH_TOKEN_TTL_MS));
7726
+ const refresh = window.localStorage.getItem("refreshToken");
7727
+ if (!refresh)
7728
+ throw new Error("No refresh token");
7729
+ const { data } = await refreshToken(apiBaseUrl, refresh);
7730
+ window.localStorage.setItem("accessToken", data.accessToken);
7731
+ window.localStorage.setItem("refreshToken", data.refreshToken);
7910
7732
  setAccessToken(data.accessToken);
7911
7733
  setRefreshToken(data.refreshToken);
7912
7734
  setIsAuthenticated(true);
7913
7735
  return data;
7914
7736
  }
7915
7737
  async function logout$1() {
7916
- const currentAddress = address;
7917
- const currentRefresh = refreshToken$1;
7918
- if (currentRefresh) {
7738
+ const refresh = window.localStorage.getItem("refreshToken");
7739
+ if (refresh) {
7919
7740
  try {
7920
- await logout(apiBaseUrl, currentRefresh);
7741
+ await logout(apiBaseUrl, refresh);
7921
7742
  }
7922
7743
  catch (_a) {
7923
7744
  /* ignore */
7924
7745
  }
7925
7746
  }
7926
- if (currentAddress) {
7927
- const accessTokenKey = `${currentAddress}_accessToken`;
7928
- const refreshTokenKey = `${currentAddress}_refreshToken`;
7929
- const accessTokenExpiresAtKey = `${currentAddress}_accessTokenExpiresAt`;
7930
- const refreshTokenExpiresAtKey = `${currentAddress}_refreshTokenExpiresAt`;
7931
- window.localStorage.removeItem(accessTokenKey);
7932
- window.localStorage.removeItem(refreshTokenKey);
7933
- window.localStorage.removeItem(accessTokenExpiresAtKey);
7934
- window.localStorage.removeItem(refreshTokenExpiresAtKey);
7935
- }
7747
+ window.localStorage.removeItem("accessToken");
7748
+ window.localStorage.removeItem("refreshToken");
7749
+ window.localStorage.removeItem("address");
7936
7750
  setAccessToken(null);
7937
7751
  setRefreshToken(null);
7938
7752
  setAddress(null);
7939
7753
  setIsAuthenticated(false);
7940
7754
  }
7941
- /**
7942
- * Clear the current session without logging out from the API.
7943
- * Useful when switching wallets to clear stale in-memory auth state.
7944
- * Note: setAddress will clear user-specific data (spotState, etc.) when called
7945
- */
7946
- function clearSession() {
7947
- setAccessToken(null);
7948
- setRefreshToken(null);
7949
- setIsAuthenticated(false);
7950
- }
7951
7755
  return {
7952
7756
  isReady,
7953
7757
  isAuthenticated,
@@ -7959,8 +7763,6 @@ function useAuth() {
7959
7763
  loginWithPrivyToken,
7960
7764
  refreshTokens,
7961
7765
  logout: logout$1,
7962
- setAddress,
7963
- clearSession,
7964
7766
  };
7965
7767
  }
7966
7768
 
@@ -8273,17 +8075,9 @@ const PearHyperliquidContext = createContext(undefined);
8273
8075
  /**
8274
8076
  * React Provider for PearHyperliquidClient
8275
8077
  */
8276
- const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-ui.pearprotocol.io", clientId = "PEARPROTOCOLUI", wsUrl = "wss://hl-ui.pearprotocol.io/ws", }) => {
8078
+ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-ui.pearprotocol.io', clientId = 'PEARPROTOCOLUI', wsUrl = 'wss://hl-ui.pearprotocol.io/ws', }) => {
8277
8079
  const address = useUserData((s) => s.address);
8278
- const clearHyperliquidUserData = useHyperliquidData((state) => state.clearUserData);
8279
- const prevAddressRef = useRef(null);
8280
- // Clear user-specific data when address changes
8281
- useEffect(() => {
8282
- if (prevAddressRef.current !== null && prevAddressRef.current !== address) {
8283
- clearHyperliquidUserData();
8284
- }
8285
- prevAddressRef.current = address;
8286
- }, [address, clearHyperliquidUserData]);
8080
+ const setAddress = useUserData((s) => s.setAddress);
8287
8081
  const perpMetasByDex = useHyperliquidData((state) => state.perpMetasByDex);
8288
8082
  const setPerpDexs = useHyperliquidData((state) => state.setPerpDexs);
8289
8083
  const setPerpMetasByDex = useHyperliquidData((state) => state.setPerpMetasByDex);
@@ -8314,20 +8108,20 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-ui.pearpro
8314
8108
  perpMetas.forEach((item, perpIndex) => {
8315
8109
  var _a, _b;
8316
8110
  const dexName = perpIndex === 0
8317
- ? "HYPERLIQUID"
8111
+ ? 'HYPERLIQUID'
8318
8112
  : ((_b = (_a = perpDexs[perpIndex]) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : `DEX_${perpIndex}`);
8319
8113
  var collateralToken;
8320
8114
  if (item.collateralToken === 360) {
8321
- collateralToken = "USDH";
8115
+ collateralToken = 'USDH';
8322
8116
  }
8323
8117
  if (item.collateralToken === 0) {
8324
- collateralToken = "USDC";
8118
+ collateralToken = 'USDC';
8325
8119
  }
8326
8120
  if (item.collateralToken === 235) {
8327
- collateralToken = "USDE";
8121
+ collateralToken = 'USDE';
8328
8122
  }
8329
8123
  if (item.collateralToken === 268) {
8330
- collateralToken = "USDT0";
8124
+ collateralToken = 'USDT0';
8331
8125
  }
8332
8126
  const universeAssets = item.universe.map((asset) => ({
8333
8127
  ...asset,
@@ -8355,6 +8149,8 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-ui.pearpro
8355
8149
  }), [
8356
8150
  apiBaseUrl,
8357
8151
  wsUrl,
8152
+ address,
8153
+ setAddress,
8358
8154
  isConnected,
8359
8155
  lastError,
8360
8156
  nativeIsConnected,
@@ -8369,7 +8165,7 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-ui.pearpro
8369
8165
  function usePearHyperliquid() {
8370
8166
  const ctx = useContext(PearHyperliquidContext);
8371
8167
  if (!ctx)
8372
- throw new Error("usePearHyperliquid must be used within a PearHyperliquidProvider");
8168
+ throw new Error('usePearHyperliquid must be used within a PearHyperliquidProvider');
8373
8169
  return ctx;
8374
8170
  }
8375
8171
 
@@ -1,4 +1,4 @@
1
- import React, { ReactNode } from "react";
1
+ import React, { ReactNode } from 'react';
2
2
  export interface PearHyperliquidContextType {
3
3
  clientId: string;
4
4
  apiBaseUrl: string;
@@ -1,5 +1,5 @@
1
- import { ActiveAssetData, CandleChartData, CandleData, ClearinghouseState, UniverseAsset, WebData3AssetCtx, WsAllMidsData, PerpDexsResponse } from "../types";
2
- import { TokenMetadataBySymbol } from "../utils/token-metadata-extractor";
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;
@@ -28,7 +28,6 @@ interface HyperliquidDataState {
28
28
  setPerpDexs: (value: PerpDexsResponse | null) => void;
29
29
  setPerpMetasByDex: (value: Map<string, UniverseAsset[]> | null) => void;
30
30
  setAssetContextsByDex: (value: Map<string, WebData3AssetCtx[]> | null) => void;
31
- clearUserData: () => void;
32
31
  }
33
32
  export declare const useHyperliquidData: import("zustand").UseBoundStore<import("zustand").StoreApi<HyperliquidDataState>>;
34
33
  export {};
@@ -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/types.d.ts CHANGED
@@ -255,6 +255,7 @@ export interface PositionAssetDetailDto {
255
255
  unrealizedPnl: number;
256
256
  liquidationPrice: number;
257
257
  initialWeight: number;
258
+ currentWeight: number;
258
259
  fundingPaid?: number;
259
260
  metadata?: TokenMetadata | null;
260
261
  }
@@ -1,5 +1,5 @@
1
- import type { AxiosInstance } from "axios";
2
- import { ApiErrorResponse } from "../types";
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
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pear-protocol/hyperliquid-sdk",
3
- "version": "0.1.13-beta.2",
3
+ "version": "0.1.14",
4
4
  "description": "React SDK for Pear Protocol Hyperliquid API integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",