@pear-protocol/hyperliquid-sdk 0.1.11 → 0.1.13-beta.1

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 { AvailableToTrades, SpotBalances, CollateralToken } from '../types';
1
+ import { AvailableToTrades, SpotBalances, CollateralToken, UserAbstraction } from '../types';
2
2
  export interface MarginRequiredPerCollateral {
3
3
  collateral: CollateralToken;
4
4
  marginRequired: number;
@@ -16,6 +16,7 @@ interface AllUserBalancesResult {
16
16
  spotBalances: SpotBalances;
17
17
  availableToTrades: AvailableToTrades;
18
18
  isLoading: boolean;
19
+ abstractionMode: UserAbstraction | null;
19
20
  getMarginRequired: (assetsLeverage: Record<string, number>, size: number) => MarginRequiredResult;
20
21
  getMaxSize: (assetsLeverage: Record<string, number>) => number;
21
22
  }
@@ -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,4 +10,6 @@ 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;
13
15
  };
package/dist/index.d.ts CHANGED
@@ -591,6 +591,7 @@ interface HLChannelDataMap {
591
591
  allDexsAssetCtxs: AllDexsAssetCtxsData;
592
592
  userFills: any;
593
593
  }
594
+ type UserAbstraction = 'dexAbstraction' | 'disabled' | 'unifiedAccount';
594
595
  interface WebData3UserState {
595
596
  agentAddress?: string;
596
597
  agentValidUntil?: number;
@@ -599,6 +600,7 @@ interface WebData3UserState {
599
600
  isVault: boolean;
600
601
  user: string;
601
602
  dexAbstractionEnabled?: boolean;
603
+ abstraction: UserAbstraction;
602
604
  }
603
605
  interface WebData3AssetCtx {
604
606
  funding: string;
@@ -1427,6 +1429,8 @@ declare function useAuth(): {
1427
1429
  readonly loginWithPrivyToken: (address: string, appId: string, privyAccessToken: string) => Promise<void>;
1428
1430
  readonly refreshTokens: () => Promise<RefreshTokenResponse>;
1429
1431
  readonly logout: () => Promise<void>;
1432
+ readonly clearSession: () => void;
1433
+ readonly setAddress: (address: string | null) => void;
1430
1434
  };
1431
1435
 
1432
1436
  interface MarginRequiredPerCollateral {
@@ -1446,6 +1450,7 @@ interface AllUserBalancesResult {
1446
1450
  spotBalances: SpotBalances;
1447
1451
  availableToTrades: AvailableToTrades;
1448
1452
  isLoading: boolean;
1453
+ abstractionMode: UserAbstraction | null;
1449
1454
  getMarginRequired: (assetsLeverage: Record<string, number>, size: number) => MarginRequiredResult;
1450
1455
  getMaxSize: (assetsLeverage: Record<string, number>) => number;
1451
1456
  }
@@ -1743,4 +1748,4 @@ interface MarketDataState {
1743
1748
  declare const useMarketData: zustand.UseBoundStore<zustand.StoreApi<MarketDataState>>;
1744
1749
 
1745
1750
  export { ConflictDetector, MAX_ASSETS_PER_LEG, MINIMUM_ASSET_USD_VALUE, MaxAssetsPerLegError, MinimumPositionSizeError, PearHyperliquidProvider, ReadyState, adjustAdvancePosition, adjustOrder, adjustPosition, calculateMinimumPositionValue, calculateWeightedRatio, cancelOrder, cancelTwap, cancelTwapOrder, closeAllPositions, closePosition, computeBasketCandles, createCandleLookups, createPosition, executeSpotOrder, getCompleteTimestamps, getKalshiMarkets, getOrderDirection, getOrderLadderConfig, getOrderLeverage, getOrderReduceOnly, getOrderTpSlTriggerType, getOrderTrailingInfo, getOrderTriggerType, getOrderTriggerValue, getOrderTwapDuration, getOrderUsdValue, getPortfolio, isBtcDomOrder, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, markNotificationReadById, markNotificationsRead, toggleWatchlist, updateLeverage, updateRiskParameters, useAccountSummary, useAgentWallet, useAllUserBalances, useAuth, useBasketCandles, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidUserFills, useMarket, useMarketData, useMarketDataHook, useNotifications, useOpenOrders, useOrders, usePearHyperliquid, usePerformanceOverlays, usePortfolio, usePosition, useSpotOrder, useTokenSelectionMetadata, useTradeHistories, useTwap, useUserSelection, useWatchlist, validateMaxAssetsPerLeg, validateMinimumAssetSize, validatePositionSize };
1746
- export type { AccountSummaryResponseDto, ActiveAssetData, ActiveAssetGroupItem, ActiveAssetsAllResponse, ActiveAssetsResponse, AddressState, AdjustAdvanceAssetInput, AdjustAdvanceItemInput, AdjustAdvanceResponseDto, AdjustExecutionType, AdjustOrderRequestInput, AdjustOrderResponseDto, AdjustPositionRequestInput, AdjustPositionResponseDto, AgentWalletDto, AgentWalletState, AgentWalletStatus, AllDexsAssetCtxsData, AllDexsClearinghouseStateData, AllPerpMetasItem, AllPerpMetasResponse, ApiErrorResponse, ApiResponse, AssetCtx, AssetInformationDetail, AssetMarketData, AssetPosition, AuthenticateRequest, AuthenticateResponse, AvailableToTrades, BalanceSummaryDto, BaseTriggerOrderNotificationParams, BtcDomTriggerParams, CancelOrderResponseDto, CancelTwapResponseDto, CandleChartData, CandleData, CandleInterval, CandleSnapshotRequest, ChunkFillDto, ClearinghouseState, CloseAllPositionsResponseDto, CloseAllPositionsResultDto, CloseExecutionType, ClosePositionRequestInput, ClosePositionResponseDto, CollateralToken, CreateAgentWalletResponseDto, CreatePositionRequestInput, CreatePositionResponseDto, CrossAssetPriceTriggerParams, CrossMarginSummaryDto, CumFundingDto, EIP712AuthDetails, ExecutionType, ExternalFillDto, ExternalLiquidationDto, ExtraAgent, GetAgentWalletResponseDto, GetEIP712MessageResponse, GetKalshiMarketsParams, HLChannel, HLChannelDataMap, HLWebSocketResponse, HistoricalRange, KalshiMarket, KalshiMarketsResponse, KalshiMveLeg, KalshiPriceRange, LadderConfigInput, LadderOrderParameters, LeverageInfo, LogoutRequest, LogoutResponse, MarginRequiredPerCollateral, MarginRequiredResult, MarginSummaryDto, MarginTableDef, MarginTablesEntry, MarginTier, MarketOrderParameters, NotificationCategory, NotificationDto, OpenLimitOrderDto, OpenPositionDto, OrderAssetDto, OrderDirection, OrderParameters, OrderStatus, OrderType, PairAssetDto, PairAssetInput, PerformanceOverlay, PerpDex, PerpDexsResponse, PerpMetaAsset, PlatformAccountSummaryResponseDto, PortfolioBucketDto, PortfolioInterval, PortfolioIntervalsDto, PortfolioOverallDto, PortfolioResponseDto, PositionAdjustmentType, PositionAssetDetailDto, PredictionMarketOutcomeTriggerParams, PriceRatioTriggerParams, PriceTriggerParams, PrivyAuthDetails, RawAssetDto, RawPositionDto, RealtimeBar, RealtimeBarsCallback, RefreshTokenRequest, RefreshTokenResponse, SpotBalance, SpotBalances, SpotOrderFilledStatus, SpotOrderHyperliquidData, SpotOrderHyperliquidResult, SpotOrderRequestInput, SpotOrderResponseDto, SpotState, SyncFillsRequestDto, SyncFillsResponseDto, ToggleWatchlistResponseDto, TokenConflict, TokenEntry, TokenHistoricalPriceData, TokenMetadata, TokenSelection, TokenSelectorConfig, TpSlOrderParameters, TpSlThreshold, TpSlThresholdInput, TpSlThresholdType, TpSlTriggerType, TradeHistoryAssetDataDto, TradeHistoryDataDto, TriggerOrderNotificationAsset, TriggerOrderNotificationParams, TriggerOrderNotificationType, TriggerOrderParameters, TriggerType, TwapChunkStatus, TwapChunkStatusDto, TwapMonitoringDto, TwapOrderOverallStatus, TwapOrderParameters, TwapSliceFillResponseItem, UniverseAsset, UpdateLeverageRequestInput, UpdateLeverageResponseDto, UpdateRiskParametersRequestInput, UpdateRiskParametersResponseDto, UseAuthOptions, UseBasketCandlesReturn, UseHistoricalPriceDataReturn, UseHyperliquidUserFillsOptions, UseHyperliquidUserFillsState, UseNotificationsResult, UsePerformanceOverlaysReturn, UsePortfolioResult, UseSpotOrderResult, UseTokenSelectionMetadataReturn, UserProfile, UserSelectionState, WatchlistAssetDto, WatchlistItemDto, WebData3AssetCtx, WebData3PerpDexState, WebData3Response, WebData3UserState, WebSocketAckResponse, WebSocketChannel, WebSocketConnectionState, WebSocketDataMessage, WebSocketMessage, WebSocketSubscribeMessage, WsAllMidsData };
1751
+ export type { AccountSummaryResponseDto, ActiveAssetData, ActiveAssetGroupItem, ActiveAssetsAllResponse, ActiveAssetsResponse, AddressState, AdjustAdvanceAssetInput, AdjustAdvanceItemInput, AdjustAdvanceResponseDto, AdjustExecutionType, AdjustOrderRequestInput, AdjustOrderResponseDto, AdjustPositionRequestInput, AdjustPositionResponseDto, AgentWalletDto, AgentWalletState, AgentWalletStatus, AllDexsAssetCtxsData, AllDexsClearinghouseStateData, AllPerpMetasItem, AllPerpMetasResponse, ApiErrorResponse, ApiResponse, AssetCtx, AssetInformationDetail, AssetMarketData, AssetPosition, AuthenticateRequest, AuthenticateResponse, AvailableToTrades, BalanceSummaryDto, BaseTriggerOrderNotificationParams, BtcDomTriggerParams, CancelOrderResponseDto, CancelTwapResponseDto, CandleChartData, CandleData, CandleInterval, CandleSnapshotRequest, ChunkFillDto, ClearinghouseState, CloseAllPositionsResponseDto, CloseAllPositionsResultDto, CloseExecutionType, ClosePositionRequestInput, ClosePositionResponseDto, CollateralToken, CreateAgentWalletResponseDto, CreatePositionRequestInput, CreatePositionResponseDto, CrossAssetPriceTriggerParams, CrossMarginSummaryDto, CumFundingDto, EIP712AuthDetails, ExecutionType, ExternalFillDto, ExternalLiquidationDto, ExtraAgent, GetAgentWalletResponseDto, GetEIP712MessageResponse, GetKalshiMarketsParams, HLChannel, HLChannelDataMap, HLWebSocketResponse, HistoricalRange, KalshiMarket, KalshiMarketsResponse, KalshiMveLeg, KalshiPriceRange, LadderConfigInput, LadderOrderParameters, LeverageInfo, LogoutRequest, LogoutResponse, MarginRequiredPerCollateral, MarginRequiredResult, MarginSummaryDto, MarginTableDef, MarginTablesEntry, MarginTier, MarketOrderParameters, NotificationCategory, NotificationDto, OpenLimitOrderDto, OpenPositionDto, OrderAssetDto, OrderDirection, OrderParameters, OrderStatus, OrderType, PairAssetDto, PairAssetInput, PerformanceOverlay, PerpDex, PerpDexsResponse, PerpMetaAsset, PlatformAccountSummaryResponseDto, PortfolioBucketDto, PortfolioInterval, PortfolioIntervalsDto, PortfolioOverallDto, PortfolioResponseDto, PositionAdjustmentType, PositionAssetDetailDto, PredictionMarketOutcomeTriggerParams, PriceRatioTriggerParams, PriceTriggerParams, PrivyAuthDetails, RawAssetDto, RawPositionDto, RealtimeBar, RealtimeBarsCallback, RefreshTokenRequest, RefreshTokenResponse, SpotBalance, SpotBalances, SpotOrderFilledStatus, SpotOrderHyperliquidData, SpotOrderHyperliquidResult, SpotOrderRequestInput, SpotOrderResponseDto, SpotState, SyncFillsRequestDto, SyncFillsResponseDto, ToggleWatchlistResponseDto, TokenConflict, TokenEntry, TokenHistoricalPriceData, TokenMetadata, TokenSelection, TokenSelectorConfig, TpSlOrderParameters, TpSlThreshold, TpSlThresholdInput, TpSlThresholdType, TpSlTriggerType, TradeHistoryAssetDataDto, TradeHistoryDataDto, TriggerOrderNotificationAsset, TriggerOrderNotificationParams, TriggerOrderNotificationType, TriggerOrderParameters, TriggerType, TwapChunkStatus, TwapChunkStatusDto, TwapMonitoringDto, TwapOrderOverallStatus, TwapOrderParameters, TwapSliceFillResponseItem, UniverseAsset, UpdateLeverageRequestInput, UpdateLeverageResponseDto, UpdateRiskParametersRequestInput, UpdateRiskParametersResponseDto, UseAuthOptions, UseBasketCandlesReturn, UseHistoricalPriceDataReturn, UseHyperliquidUserFillsOptions, UseHyperliquidUserFillsState, UseNotificationsResult, UsePerformanceOverlaysReturn, UsePortfolioResult, UseSpotOrderResult, UseTokenSelectionMetadataReturn, UserAbstraction, UserProfile, UserSelectionState, WatchlistAssetDto, WatchlistItemDto, WebData3AssetCtx, WebData3PerpDexState, WebData3Response, WebData3UserState, WebSocketAckResponse, WebSocketChannel, WebSocketConnectionState, WebSocketDataMessage, WebSocketMessage, WebSocketSubscribeMessage, WsAllMidsData };
package/dist/index.js CHANGED
@@ -64,20 +64,16 @@ const useUserData = create((set) => ({
64
64
  notifications: null,
65
65
  userExtraAgents: null,
66
66
  spotState: null,
67
+ userAbstractionMode: null,
68
+ isReady: false,
69
+ setUserAbstractionMode: (value) => set({ userAbstractionMode: value }),
67
70
  setAccessToken: (token) => set({ accessToken: token }),
68
71
  setRefreshToken: (token) => set({ refreshToken: token }),
69
72
  setIsAuthenticated: (value) => set({ isAuthenticated: value }),
70
- setAddress: (address) => set(() => {
71
- if (typeof window !== 'undefined') {
72
- if (address) {
73
- window.localStorage.setItem('address', address);
74
- }
75
- else {
76
- window.localStorage.removeItem('address');
77
- }
78
- }
79
- return { address };
80
- }),
73
+ setIsReady: (value) => set({ isReady: value }),
74
+ setAddress: (address) => {
75
+ set({ address });
76
+ },
81
77
  setTradeHistories: (value) => set({ tradeHistories: value }),
82
78
  setRawOpenPositions: (value) => set({ rawOpenPositions: value }),
83
79
  setOpenOrders: (value) => set({ openOrders: value }),
@@ -86,10 +82,11 @@ const useUserData = create((set) => ({
86
82
  setNotifications: (value) => set({ notifications: value }),
87
83
  setSpotState: (value) => set({ spotState: value }),
88
84
  clean: () => set({
89
- accessToken: null,
90
- refreshToken: null,
91
- isAuthenticated: false,
92
- address: null,
85
+ // accessToken: null,
86
+ // refreshToken: null,
87
+ // isAuthenticated: false,
88
+ // isReady: false,
89
+ // address: null,
93
90
  tradeHistories: null,
94
91
  rawOpenPositions: null,
95
92
  openOrders: null,
@@ -382,19 +379,19 @@ class TokenMetadataExtractor {
382
379
  if (!assetCtx) {
383
380
  return null;
384
381
  }
385
- // Get current price - prefer assetCtx.midPx as it's already index-matched,
386
- // fall back to allMids lookup if midPx is null
382
+ // Get current price - prefer allMids (real-time WebSocket data),
383
+ // fall back to assetCtx.midPx if not available
387
384
  const actualSymbol = foundAsset.name;
388
385
  let currentPrice = 0;
389
- // Fallback: assetCtx.midPx (already properly indexed)
390
- if (!currentPrice || isNaN(currentPrice)) {
391
- const currentPriceStr = allMids.mids[actualSymbol] || allMids.mids[symbol];
392
- currentPrice = currentPriceStr ? parseFloat(currentPriceStr) : 0;
393
- }
394
- // Primary source: allMids lookup
386
+ // Fallback: assetCtx.midPx (from REST API, less frequent)
395
387
  if (assetCtx.midPx) {
396
388
  currentPrice = parseFloat(assetCtx.midPx);
397
389
  }
390
+ // Primary source: allMids (real-time WebSocket data)
391
+ const currentPriceStr = allMids.mids[actualSymbol] || allMids.mids[symbol];
392
+ if (currentPriceStr) {
393
+ currentPrice = parseFloat(currentPriceStr);
394
+ }
398
395
  // Get previous day price
399
396
  const prevDayPrice = parseFloat(assetCtx.prevDayPx);
400
397
  // Calculate 24h price change
@@ -549,7 +546,7 @@ const useHyperliquidData = create((set) => ({
549
546
  tokenMetadata: refreshTokenMetadata(state, { allMids: value }),
550
547
  })),
551
548
  setActiveAssetData: (value) => set((state) => {
552
- const activeAssetData = typeof value === 'function' ? value(state.activeAssetData) : value;
549
+ const activeAssetData = typeof value === "function" ? value(state.activeAssetData) : value;
553
550
  return {
554
551
  activeAssetData,
555
552
  tokenMetadata: refreshTokenMetadata(state, { activeAssetData }),
@@ -589,7 +586,10 @@ const useHyperliquidData = create((set) => ({
589
586
  setCandleData: (value) => set({ candleData: value }),
590
587
  upsertActiveAssetData: (key, value) => set((state) => {
591
588
  var _a;
592
- const activeAssetData = { ...((_a = state.activeAssetData) !== null && _a !== void 0 ? _a : {}), [key]: value };
589
+ const activeAssetData = {
590
+ ...((_a = state.activeAssetData) !== null && _a !== void 0 ? _a : {}),
591
+ [key]: value,
592
+ };
593
593
  return {
594
594
  activeAssetData,
595
595
  tokenMetadata: refreshTokenMetadata(state, { activeAssetData }, { symbols: [key] }),
@@ -887,7 +887,7 @@ const useUserSelection$1 = create((set, get) => ({
887
887
 
888
888
  const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }) => {
889
889
  const { setAllMids, setActiveAssetData, upsertActiveAssetData, setCandleData, deleteCandleSymbol, deleteActiveAssetData, addCandleData, setFinalAtOICaps, setAggregatedClearingHouseState, setRawClearinghouseStates, setAssetContextsByDex, } = useHyperliquidData();
890
- const { setSpotState } = useUserData();
890
+ const { setSpotState, setUserAbstractionMode } = useUserData();
891
891
  const { candleInterval } = useUserSelection$1();
892
892
  const userSummary = useUserData((state) => state.accountSummary);
893
893
  const longTokens = useUserSelection$1((s) => s.longTokens);
@@ -904,6 +904,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
904
904
  const reconnectAttemptsRef = useRef(0);
905
905
  const manualCloseRef = useRef(false);
906
906
  const onUserFillsRef = useRef(onUserFills);
907
+ const reconnectTimeoutRef = useRef(null);
907
908
  const [readyState, setReadyState] = useState(ReadyState.CONNECTING);
908
909
  // Keep the ref updated with the latest callback
909
910
  useEffect(() => {
@@ -914,9 +915,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
914
915
  try {
915
916
  const message = JSON.parse(event.data);
916
917
  // Handle subscription responses
917
- if ('success' in message || 'error' in message) {
918
+ if ("success" in message || "error" in message) {
918
919
  if (message.error) {
919
- console.error('[HyperLiquid WS] Subscription error:', message.error);
920
+ console.error("[HyperLiquid WS] Subscription error:", message.error);
920
921
  setLastError(message.error);
921
922
  }
922
923
  else {
@@ -925,43 +926,44 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
925
926
  return;
926
927
  }
927
928
  // Handle channel data messages
928
- if ('channel' in message && 'data' in message) {
929
+ if ("channel" in message && "data" in message) {
929
930
  const response = message;
930
931
  switch (response.channel) {
931
- case 'userFills':
932
+ case "userFills":
932
933
  {
933
934
  const maybePromise = (_a = onUserFillsRef.current) === null || _a === void 0 ? void 0 : _a.call(onUserFillsRef);
934
935
  if (maybePromise instanceof Promise) {
935
- maybePromise.catch((err) => console.error('[HyperLiquid WS] userFills callback error', err));
936
+ maybePromise.catch((err) => console.error("[HyperLiquid WS] userFills callback error", err));
936
937
  }
937
938
  }
938
939
  break;
939
- case 'webData3':
940
+ case "webData3":
940
941
  const webData3 = response.data;
941
942
  // finalAssetContexts now sourced from allDexsAssetCtxs channel
942
943
  const finalAtOICaps = webData3.perpDexStates.flatMap((dex) => dex.perpsAtOpenInterestCap);
943
944
  setFinalAtOICaps(finalAtOICaps);
945
+ setUserAbstractionMode(webData3.userState.abstraction || null);
944
946
  break;
945
- case 'allDexsAssetCtxs':
947
+ case "allDexsAssetCtxs":
946
948
  {
947
949
  const data = response.data;
948
950
  // Store by DEX name, mapping '' to 'HYPERLIQUID'
949
951
  const assetContextsByDex = new Map();
950
952
  data.ctxs.forEach(([dexKey, ctxs]) => {
951
- const dexName = dexKey === '' ? 'HYPERLIQUID' : dexKey;
953
+ const dexName = dexKey === "" ? "HYPERLIQUID" : dexKey;
952
954
  assetContextsByDex.set(dexName, ctxs || []);
953
955
  });
954
956
  setAssetContextsByDex(assetContextsByDex);
955
957
  }
956
958
  break;
957
- case 'allDexsClearinghouseState':
959
+ case "allDexsClearinghouseState":
958
960
  {
959
961
  const data = response.data;
960
962
  const states = (data.clearinghouseStates || [])
961
963
  .map(([, s]) => s)
962
964
  .filter(Boolean);
963
- const sum = (values) => values.reduce((acc, v) => acc + (parseFloat(v || '0') || 0), 0);
964
- const toStr = (n) => Number.isFinite(n) ? n.toString() : '0';
965
+ const sum = (values) => values.reduce((acc, v) => acc + (parseFloat(v || "0") || 0), 0);
966
+ const toStr = (n) => Number.isFinite(n) ? n.toString() : "0";
965
967
  const assetPositions = states.flatMap((s) => s.assetPositions || []);
966
968
  const crossMaintenanceMarginUsed = toStr(sum(states.map((s) => s.crossMaintenanceMarginUsed)));
967
969
  const crossMarginSummary = {
@@ -991,26 +993,26 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
991
993
  setClearinghouseStateReceived(true);
992
994
  }
993
995
  break;
994
- case 'allMids':
996
+ case "allMids":
995
997
  {
996
998
  const data = response.data;
997
999
  setAllMids(data);
998
1000
  }
999
1001
  break;
1000
- case 'activeAssetData':
1002
+ case "activeAssetData":
1001
1003
  {
1002
1004
  const assetData = response.data;
1003
1005
  upsertActiveAssetData(assetData.coin, assetData);
1004
1006
  }
1005
1007
  break;
1006
- case 'candle':
1008
+ case "candle":
1007
1009
  {
1008
1010
  const candleDataItem = response.data;
1009
- const symbol = candleDataItem.s || '';
1011
+ const symbol = candleDataItem.s || "";
1010
1012
  addCandleData(symbol, candleDataItem);
1011
1013
  }
1012
1014
  break;
1013
- case 'spotState':
1015
+ case "spotState":
1014
1016
  {
1015
1017
  const spotStateData = response.data;
1016
1018
  if (spotStateData === null || spotStateData === void 0 ? void 0 : spotStateData.spotState) {
@@ -1025,7 +1027,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1025
1027
  }
1026
1028
  catch (error) {
1027
1029
  const errorMessage = `Failed to parse message: ${error instanceof Error ? error.message : String(error)}`;
1028
- console.error('[HyperLiquid WS] Parse error:', errorMessage, 'Raw message:', event.data);
1030
+ console.error("[HyperLiquid WS] Parse error:", errorMessage, "Raw message:", event.data);
1029
1031
  setLastError(errorMessage);
1030
1032
  }
1031
1033
  }, [
@@ -1039,9 +1041,14 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1039
1041
  setSpotState,
1040
1042
  ]);
1041
1043
  const connect = useCallback(() => {
1042
- console.log('[HyperLiquid WS] connect() called, enabled:', enabled);
1044
+ console.log("[HyperLiquid WS] connect() called, enabled:", enabled);
1043
1045
  if (!enabled)
1044
1046
  return;
1047
+ // Clear any pending reconnect timeout
1048
+ if (reconnectTimeoutRef.current) {
1049
+ clearTimeout(reconnectTimeoutRef.current);
1050
+ reconnectTimeoutRef.current = null;
1051
+ }
1045
1052
  try {
1046
1053
  // Avoid opening multiple sockets if one is already active or connecting
1047
1054
  if (wsRef.current &&
@@ -1050,10 +1057,10 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1050
1057
  console.log('[HyperLiquid WS] connect() returning early - socket already exists, readyState:', wsRef.current.readyState);
1051
1058
  return;
1052
1059
  }
1053
- console.log('[HyperLiquid WS] Creating new WebSocket connection');
1060
+ console.log("[HyperLiquid WS] Creating new WebSocket connection");
1054
1061
  manualCloseRef.current = false;
1055
1062
  setReadyState(ReadyState.CONNECTING);
1056
- const ws = new WebSocket('wss://api.hyperliquid.xyz/ws');
1063
+ const ws = new WebSocket("wss://api.hyperliquid.xyz/ws");
1057
1064
  wsRef.current = ws;
1058
1065
  ws.onopen = () => {
1059
1066
  reconnectAttemptsRef.current = 0;
@@ -1062,17 +1069,22 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1062
1069
  };
1063
1070
  ws.onmessage = handleMessage;
1064
1071
  ws.onerror = (event) => {
1065
- console.error('[HyperLiquid WS] Connection error:', event);
1066
- setLastError('WebSocket error');
1072
+ console.error("[HyperLiquid WS] Connection error:", event);
1073
+ setLastError("WebSocket error");
1067
1074
  };
1068
1075
  ws.onclose = () => {
1069
1076
  setReadyState(ReadyState.CLOSED);
1070
- if (!manualCloseRef.current && reconnectAttemptsRef.current < 5) {
1077
+ // Reset subscription state so effects will resubscribe on reconnect
1078
+ setSubscribedAddress(null);
1079
+ setSubscribedTokens([]);
1080
+ setSubscribedCandleTokens([]);
1081
+ setClearinghouseStateReceived(false);
1082
+ if (!manualCloseRef.current) {
1071
1083
  reconnectAttemptsRef.current += 1;
1072
- if (reconnectAttemptsRef.current === 5) {
1073
- console.error('[HyperLiquid WS] Reconnection stopped after 5 attempts');
1074
- }
1075
- setTimeout(() => connect(), 3000);
1084
+ // Exponential backoff: 1s, 2s, 4s, 8s, 16s, 30s (max), then stay at 30s
1085
+ const delay = Math.min(1000 * Math.pow(2, reconnectAttemptsRef.current - 1), 30000);
1086
+ console.log(`[HyperLiquid WS] Reconnecting in ${delay}ms (attempt ${reconnectAttemptsRef.current})`);
1087
+ reconnectTimeoutRef.current = setTimeout(() => connect(), delay);
1076
1088
  }
1077
1089
  };
1078
1090
  }
@@ -1083,9 +1095,53 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1083
1095
  useEffect(() => {
1084
1096
  console.log('[HyperLiquid WS] Connection effect running - calling connect()');
1085
1097
  connect();
1098
+ // Handle online/offline events to reconnect when internet is restored
1099
+ const handleOnline = () => {
1100
+ console.log('[HyperLiquid WS] Browser went online, attempting reconnect');
1101
+ // Reset reconnect attempts when internet comes back
1102
+ reconnectAttemptsRef.current = 0;
1103
+ // Clear any pending reconnect timeout
1104
+ if (reconnectTimeoutRef.current) {
1105
+ clearTimeout(reconnectTimeoutRef.current);
1106
+ reconnectTimeoutRef.current = null;
1107
+ }
1108
+ // Reset subscription state so effects will resubscribe on reconnect
1109
+ setSubscribedAddress(null);
1110
+ setSubscribedTokens([]);
1111
+ setSubscribedCandleTokens([]);
1112
+ setClearinghouseStateReceived(false);
1113
+ // Close existing socket if in a bad state
1114
+ if (wsRef.current &&
1115
+ wsRef.current.readyState !== WebSocket.OPEN &&
1116
+ wsRef.current.readyState !== WebSocket.CONNECTING) {
1117
+ try {
1118
+ wsRef.current.close();
1119
+ }
1120
+ catch (_a) { }
1121
+ wsRef.current = null;
1122
+ }
1123
+ // Attempt to reconnect
1124
+ connect();
1125
+ };
1126
+ const handleOffline = () => {
1127
+ console.log('[HyperLiquid WS] Browser went offline');
1128
+ // Clear pending reconnect timeout since we're offline
1129
+ if (reconnectTimeoutRef.current) {
1130
+ clearTimeout(reconnectTimeoutRef.current);
1131
+ reconnectTimeoutRef.current = null;
1132
+ }
1133
+ };
1134
+ window.addEventListener('online', handleOnline);
1135
+ window.addEventListener('offline', handleOffline);
1086
1136
  return () => {
1087
1137
  console.log('[HyperLiquid WS] Connection effect cleanup - closing existing connection');
1138
+ window.removeEventListener('online', handleOnline);
1139
+ window.removeEventListener('offline', handleOffline);
1088
1140
  manualCloseRef.current = true;
1141
+ if (reconnectTimeoutRef.current) {
1142
+ clearTimeout(reconnectTimeoutRef.current);
1143
+ reconnectTimeoutRef.current = null;
1144
+ }
1089
1145
  if (wsRef.current) {
1090
1146
  try {
1091
1147
  wsRef.current.close();
@@ -1106,7 +1162,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1106
1162
  if (isConnected) {
1107
1163
  // Send ping every 30 seconds
1108
1164
  pingIntervalRef.current = setInterval(() => {
1109
- sendJsonMessage({ method: 'ping' });
1165
+ sendJsonMessage({ method: "ping" });
1110
1166
  }, 30000);
1111
1167
  }
1112
1168
  else {
@@ -1124,27 +1180,27 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1124
1180
  }, [isConnected, sendJsonMessage]);
1125
1181
  // Handle address subscription changes
1126
1182
  useEffect(() => {
1127
- const DEFAULT_ADDRESS = '0x0000000000000000000000000000000000000000';
1183
+ const DEFAULT_ADDRESS = "0x0000000000000000000000000000000000000000";
1128
1184
  const userAddress = (address || DEFAULT_ADDRESS).toLowerCase();
1129
1185
  const normalizedSubscribedAddress = (subscribedAddress === null || subscribedAddress === void 0 ? void 0 : subscribedAddress.toLowerCase()) || null;
1130
- console.log('[HyperLiquid WS] Address subscription effect running');
1131
- console.log('[HyperLiquid WS] address:', address, 'userAddress:', userAddress, 'subscribedAddress:', subscribedAddress, 'normalizedSubscribedAddress:', normalizedSubscribedAddress);
1132
- console.log('[HyperLiquid WS] isConnected:', isConnected);
1186
+ console.log("[HyperLiquid WS] Address subscription effect running");
1187
+ console.log("[HyperLiquid WS] address:", address, "userAddress:", userAddress, "subscribedAddress:", subscribedAddress, "normalizedSubscribedAddress:", normalizedSubscribedAddress);
1188
+ console.log("[HyperLiquid WS] isConnected:", isConnected);
1133
1189
  if (normalizedSubscribedAddress === userAddress) {
1134
- console.log('[HyperLiquid WS] Address unchanged, skipping subscription update');
1190
+ console.log("[HyperLiquid WS] Address unchanged, skipping subscription update");
1135
1191
  return;
1136
1192
  }
1137
1193
  if (!isConnected) {
1138
- console.log('[HyperLiquid WS] Not connected, skipping subscription update');
1194
+ console.log("[HyperLiquid WS] Not connected, skipping subscription update");
1139
1195
  return;
1140
1196
  }
1141
1197
  // Unsubscribe from previous address if exists
1142
1198
  if (subscribedAddress) {
1143
- console.log('[HyperLiquid WS] Unsubscribing from previous address:', subscribedAddress);
1199
+ console.log("[HyperLiquid WS] Unsubscribing from previous address:", subscribedAddress);
1144
1200
  const unsubscribeMessage = {
1145
- method: 'unsubscribe',
1201
+ method: "unsubscribe",
1146
1202
  subscription: {
1147
- type: 'webData3',
1203
+ type: "webData3",
1148
1204
  user: subscribedAddress,
1149
1205
  },
1150
1206
  };
@@ -1152,54 +1208,54 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1152
1208
  // Unsubscribe from spotState for previous address
1153
1209
  if (subscribedAddress !== DEFAULT_ADDRESS) {
1154
1210
  const unsubscribeSpotState = {
1155
- method: 'unsubscribe',
1211
+ method: "unsubscribe",
1156
1212
  subscription: {
1157
- type: 'spotState',
1213
+ type: "spotState",
1158
1214
  user: subscribedAddress,
1159
1215
  },
1160
1216
  };
1161
1217
  sendJsonMessage(unsubscribeSpotState);
1162
1218
  }
1163
1219
  const unsubscribeAllDexsClearinghouseState = {
1164
- method: 'unsubscribe',
1220
+ method: "unsubscribe",
1165
1221
  subscription: {
1166
- type: 'allDexsClearinghouseState',
1222
+ type: "allDexsClearinghouseState",
1167
1223
  user: subscribedAddress,
1168
1224
  },
1169
1225
  };
1170
1226
  sendJsonMessage(unsubscribeAllDexsClearinghouseState);
1171
1227
  const unsubscribeUserFills = {
1172
- method: 'unsubscribe',
1228
+ method: "unsubscribe",
1173
1229
  subscription: {
1174
- type: 'userFills',
1230
+ type: "userFills",
1175
1231
  user: subscribedAddress,
1176
1232
  },
1177
1233
  };
1178
1234
  sendJsonMessage(unsubscribeUserFills);
1179
1235
  }
1180
1236
  const subscribeWebData3 = {
1181
- method: 'subscribe',
1237
+ method: "subscribe",
1182
1238
  subscription: {
1183
- type: 'webData3',
1239
+ type: "webData3",
1184
1240
  user: userAddress,
1185
1241
  },
1186
1242
  };
1187
1243
  // Subscribe to allMids
1188
1244
  const subscribeAllMids = {
1189
- method: 'subscribe',
1245
+ method: "subscribe",
1190
1246
  subscription: {
1191
- type: 'allMids',
1192
- dex: 'ALL_DEXS',
1247
+ type: "allMids",
1248
+ dex: "ALL_DEXS",
1193
1249
  },
1194
1250
  };
1195
1251
  // Subscribe to allDexsAssetCtxs (no payload params, global feed)
1196
1252
  const subscribeAllDexsAssetCtxs = {
1197
- method: 'subscribe',
1253
+ method: "subscribe",
1198
1254
  subscription: {
1199
- type: 'allDexsAssetCtxs',
1255
+ type: "allDexsAssetCtxs",
1200
1256
  },
1201
1257
  };
1202
- console.log('[HyperLiquid WS] Subscribing to new address:', userAddress);
1258
+ console.log("[HyperLiquid WS] Subscribing to new address:", userAddress);
1203
1259
  sendJsonMessage(subscribeWebData3);
1204
1260
  sendJsonMessage(subscribeAllMids);
1205
1261
  sendJsonMessage(subscribeAllDexsAssetCtxs);
@@ -1207,9 +1263,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1207
1263
  // Only subscribe if we have a real user address (not the default)
1208
1264
  if (userAddress !== DEFAULT_ADDRESS.toLowerCase()) {
1209
1265
  const subscribeSpotState = {
1210
- method: 'subscribe',
1266
+ method: "subscribe",
1211
1267
  subscription: {
1212
- type: 'spotState',
1268
+ type: "spotState",
1213
1269
  user: userAddress,
1214
1270
  },
1215
1271
  };
@@ -1219,9 +1275,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1219
1275
  // Only subscribe if we have a real user address (not the default)
1220
1276
  if (userAddress !== DEFAULT_ADDRESS.toLowerCase()) {
1221
1277
  const subscribeAllDexsClearinghouseState = {
1222
- method: 'subscribe',
1278
+ method: "subscribe",
1223
1279
  subscription: {
1224
- type: 'allDexsClearinghouseState',
1280
+ type: "allDexsClearinghouseState",
1225
1281
  user: userAddress,
1226
1282
  },
1227
1283
  };
@@ -1255,9 +1311,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1255
1311
  !userSummary)
1256
1312
  return;
1257
1313
  const subscribeUserFills = {
1258
- method: 'subscribe',
1314
+ method: "subscribe",
1259
1315
  subscription: {
1260
- type: 'userFills',
1316
+ type: "userFills",
1261
1317
  user: subscribedAddress,
1262
1318
  },
1263
1319
  };
@@ -1279,9 +1335,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1279
1335
  // Unsubscribe from tokens no longer in the list
1280
1336
  tokensToUnsubscribe.forEach((token) => {
1281
1337
  const unsubscribeMessage = {
1282
- method: 'unsubscribe',
1338
+ method: "unsubscribe",
1283
1339
  subscription: {
1284
- type: 'activeAssetData',
1340
+ type: "activeAssetData",
1285
1341
  user: address,
1286
1342
  coin: token,
1287
1343
  },
@@ -1291,9 +1347,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1291
1347
  // Subscribe to new tokens
1292
1348
  tokensToSubscribe.forEach((token) => {
1293
1349
  const subscribeMessage = {
1294
- method: 'subscribe',
1350
+ method: "subscribe",
1295
1351
  subscription: {
1296
- type: 'activeAssetData',
1352
+ type: "activeAssetData",
1297
1353
  user: address,
1298
1354
  coin: token,
1299
1355
  },
@@ -1322,9 +1378,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1322
1378
  if (prevInterval && prevInterval !== candleInterval) {
1323
1379
  subscribedCandleTokens.forEach((token) => {
1324
1380
  const unsubscribeMessage = {
1325
- method: 'unsubscribe',
1381
+ method: "unsubscribe",
1326
1382
  subscription: {
1327
- type: 'candle',
1383
+ type: "candle",
1328
1384
  coin: token,
1329
1385
  interval: prevInterval,
1330
1386
  },
@@ -1339,9 +1395,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1339
1395
  // Unsubscribe from tokens no longer in the list
1340
1396
  tokensToUnsubscribe.forEach((token) => {
1341
1397
  const unsubscribeMessage = {
1342
- method: 'unsubscribe',
1398
+ method: "unsubscribe",
1343
1399
  subscription: {
1344
- type: 'candle',
1400
+ type: "candle",
1345
1401
  coin: token,
1346
1402
  interval: candleInterval,
1347
1403
  },
@@ -1351,9 +1407,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
1351
1407
  // Subscribe to new tokens
1352
1408
  tokensToSubscribe.forEach((token) => {
1353
1409
  const subscribeMessage = {
1354
- method: 'subscribe',
1410
+ method: "subscribe",
1355
1411
  subscription: {
1356
- type: 'candle',
1412
+ type: "candle",
1357
1413
  coin: token,
1358
1414
  interval: candleInterval,
1359
1415
  },
@@ -5868,10 +5924,10 @@ function toApiError(error) {
5868
5924
  var _a;
5869
5925
  const axiosError = error;
5870
5926
  const payload = (axiosError && axiosError.response ? axiosError.response.data : undefined);
5871
- const message = typeof payload === 'object' && payload && 'message' in payload
5927
+ const message = typeof payload === "object" && payload && "message" in payload
5872
5928
  ? String(payload.message)
5873
- : (axiosError === null || axiosError === void 0 ? void 0 : axiosError.message) || 'Request failed';
5874
- const errField = typeof payload === 'object' && payload && 'error' in payload
5929
+ : (axiosError === null || axiosError === void 0 ? void 0 : axiosError.message) || "Request failed";
5930
+ const errField = typeof payload === "object" && payload && "error" in payload
5875
5931
  ? String(payload.error)
5876
5932
  : undefined;
5877
5933
  return {
@@ -5881,8 +5937,8 @@ function toApiError(error) {
5881
5937
  };
5882
5938
  }
5883
5939
  function joinUrl(baseUrl, path) {
5884
- const cleanBase = baseUrl.replace(/\/$/, '');
5885
- const cleanPath = path.startsWith('/') ? path : `/${path}`;
5940
+ const cleanBase = baseUrl.replace(/\/$/, "");
5941
+ const cleanPath = path.startsWith("/") ? path : `/${path}`;
5886
5942
  return `${cleanBase}${cleanPath}`;
5887
5943
  }
5888
5944
  /**
@@ -5911,7 +5967,7 @@ function addAuthInterceptors(params) {
5911
5967
  pendingRequests = [];
5912
5968
  }
5913
5969
  const isOurApiUrl = (url) => Boolean(url && url.startsWith(apiBaseUrl));
5914
- const isRefreshUrl = (url) => Boolean(url && url.startsWith(joinUrl(apiBaseUrl, '/auth/refresh')));
5970
+ const isRefreshUrl = (url) => Boolean(url && url.startsWith(joinUrl(apiBaseUrl, "/auth/refresh")));
5915
5971
  const reqId = apiClient.interceptors.request.use((config) => {
5916
5972
  var _a;
5917
5973
  try {
@@ -5919,11 +5975,12 @@ function addAuthInterceptors(params) {
5919
5975
  const token = getAccessToken();
5920
5976
  if (token) {
5921
5977
  config.headers = (_a = config.headers) !== null && _a !== void 0 ? _a : {};
5922
- (config.headers)['Authorization'] = `Bearer ${token}`;
5978
+ config.headers["Authorization"] = `Bearer ${token}`;
5923
5979
  }
5924
5980
  }
5925
5981
  }
5926
- catch (_b) {
5982
+ catch (err) {
5983
+ console.error("[Auth Interceptor] Request interceptor error:", err);
5927
5984
  }
5928
5985
  return config;
5929
5986
  });
@@ -5934,22 +5991,36 @@ function addAuthInterceptors(params) {
5934
5991
  const url = originalRequest === null || originalRequest === void 0 ? void 0 : originalRequest.url;
5935
5992
  // If not our API or not 401, just reject
5936
5993
  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
+ }
5937
6001
  return Promise.reject(error);
5938
6002
  }
6003
+ console.log("[Auth Interceptor] 401 detected, attempting token refresh for URL:", url);
5939
6004
  // If the 401 is from refresh endpoint itself -> force logout
5940
6005
  if (isRefreshUrl(url)) {
6006
+ console.warn("[Auth Interceptor] Refresh endpoint returned 401, logging out");
5941
6007
  try {
5942
6008
  await logout();
5943
6009
  }
5944
- catch (_d) { }
6010
+ catch (err) {
6011
+ console.error("[Auth Interceptor] Logout failed:", err);
6012
+ }
5945
6013
  return Promise.reject(error);
5946
6014
  }
5947
6015
  // Prevent infinite loop
5948
6016
  if (originalRequest && originalRequest._retry) {
6017
+ console.warn("[Auth Interceptor] Request already retried, logging out");
5949
6018
  try {
5950
6019
  await logout();
5951
6020
  }
5952
- catch (_e) { }
6021
+ catch (err) {
6022
+ console.error("[Auth Interceptor] Logout failed:", err);
6023
+ }
5953
6024
  return Promise.reject(error);
5954
6025
  }
5955
6026
  // Mark so we don't retry twice
@@ -5963,31 +6034,45 @@ function addAuthInterceptors(params) {
5963
6034
  if (!newToken || !originalRequest)
5964
6035
  return reject(error);
5965
6036
  originalRequest.headers = (_a = originalRequest.headers) !== null && _a !== void 0 ? _a : {};
5966
- originalRequest.headers['Authorization'] = `Bearer ${newToken}`;
6037
+ originalRequest.headers["Authorization"] =
6038
+ `Bearer ${newToken}`;
5967
6039
  resolve(apiClient.request(originalRequest));
5968
6040
  });
5969
6041
  });
5970
6042
  }
5971
6043
  isRefreshing = true;
5972
6044
  try {
6045
+ console.log("[Auth Interceptor] Refreshing tokens...");
5973
6046
  const refreshed = await refreshTokens();
5974
- const newAccessToken = (_b = (refreshed && (refreshed.accessToken || ((_a = refreshed.data) === null || _a === void 0 ? void 0 : _a.accessToken)))) !== null && _b !== void 0 ? _b : null;
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
+ }
5975
6055
  resolvePendingRequests(newAccessToken);
5976
6056
  if (originalRequest) {
5977
6057
  originalRequest.headers = (_c = originalRequest.headers) !== null && _c !== void 0 ? _c : {};
5978
6058
  if (newAccessToken)
5979
- (originalRequest.headers)['Authorization'] = `Bearer ${newAccessToken}`;
6059
+ originalRequest.headers["Authorization"] =
6060
+ `Bearer ${newAccessToken}`;
6061
+ console.log("[Auth Interceptor] Retrying original request with new token");
5980
6062
  const resp = await apiClient.request(originalRequest);
5981
6063
  return resp;
5982
6064
  }
5983
6065
  return Promise.reject(error);
5984
6066
  }
5985
6067
  catch (refreshErr) {
6068
+ console.error("[Auth Interceptor] Token refresh failed:", refreshErr);
5986
6069
  resolvePendingRequests(null);
5987
6070
  try {
5988
6071
  await logout();
5989
6072
  }
5990
- catch (_f) { }
6073
+ catch (err) {
6074
+ console.error("[Auth Interceptor] Logout failed:", err);
6075
+ }
5991
6076
  return Promise.reject(refreshErr);
5992
6077
  }
5993
6078
  finally {
@@ -5998,11 +6083,15 @@ function addAuthInterceptors(params) {
5998
6083
  try {
5999
6084
  apiClient.interceptors.request.eject(reqId);
6000
6085
  }
6001
- catch (_a) { }
6086
+ catch (err) {
6087
+ console.error("[Auth Interceptor] Failed to eject request interceptor:", err);
6088
+ }
6002
6089
  try {
6003
6090
  apiClient.interceptors.response.eject(resId);
6004
6091
  }
6005
- catch (_b) { }
6092
+ catch (err) {
6093
+ console.error("[Auth Interceptor] Failed to eject response interceptor:", err);
6094
+ }
6006
6095
  };
6007
6096
  }
6008
6097
 
@@ -7508,20 +7597,34 @@ function usePortfolio() {
7508
7597
  }
7509
7598
 
7510
7599
  async function getEIP712Message(baseUrl, address, clientId) {
7511
- const url = joinUrl(baseUrl, '/auth/eip712-message');
7600
+ const url = joinUrl(baseUrl, "/auth/eip712-message");
7512
7601
  try {
7513
- const resp = await axios$1.get(url, { params: { address, clientId }, timeout: 30000 });
7514
- return { data: resp.data, status: resp.status, headers: resp.headers };
7602
+ const resp = await apiClient.get(url, {
7603
+ params: { address, clientId },
7604
+ timeout: 30000,
7605
+ });
7606
+ return {
7607
+ data: resp.data,
7608
+ status: resp.status,
7609
+ headers: resp.headers,
7610
+ };
7515
7611
  }
7516
7612
  catch (error) {
7517
7613
  throw toApiError(error);
7518
7614
  }
7519
7615
  }
7520
7616
  async function authenticate(baseUrl, body) {
7521
- const url = joinUrl(baseUrl, '/auth/login');
7617
+ const url = joinUrl(baseUrl, "/auth/login");
7522
7618
  try {
7523
- const resp = await axios$1.post(url, body, { headers: { 'Content-Type': 'application/json' }, timeout: 30000 });
7524
- return { data: resp.data, status: resp.status, headers: resp.headers };
7619
+ const resp = await apiClient.post(url, body, {
7620
+ headers: { "Content-Type": "application/json" },
7621
+ timeout: 30000,
7622
+ });
7623
+ return {
7624
+ data: resp.data,
7625
+ status: resp.status,
7626
+ headers: resp.headers,
7627
+ };
7525
7628
  }
7526
7629
  catch (error) {
7527
7630
  throw toApiError(error);
@@ -7532,7 +7635,7 @@ async function authenticate(baseUrl, body) {
7532
7635
  */
7533
7636
  async function authenticateWithPrivy(baseUrl, params) {
7534
7637
  const body = {
7535
- method: 'privy_access_token',
7638
+ method: "privy_access_token",
7536
7639
  address: params.address,
7537
7640
  clientId: params.clientId,
7538
7641
  details: { appId: params.appId, accessToken: params.accessToken },
@@ -7540,62 +7643,124 @@ async function authenticateWithPrivy(baseUrl, params) {
7540
7643
  return authenticate(baseUrl, body);
7541
7644
  }
7542
7645
  async function refreshToken(baseUrl, refreshTokenVal) {
7543
- const url = joinUrl(baseUrl, '/auth/refresh');
7646
+ const url = joinUrl(baseUrl, "/auth/refresh");
7544
7647
  try {
7545
- const resp = await axios$1.post(url, { refreshToken: refreshTokenVal }, { headers: { 'Content-Type': 'application/json' }, timeout: 30000 });
7546
- return { data: resp.data, status: resp.status, headers: resp.headers };
7648
+ const resp = await apiClient.post(url, { refreshToken: refreshTokenVal }, { headers: { "Content-Type": "application/json" }, timeout: 30000 });
7649
+ return {
7650
+ data: resp.data,
7651
+ status: resp.status,
7652
+ headers: resp.headers,
7653
+ };
7547
7654
  }
7548
7655
  catch (error) {
7549
7656
  throw toApiError(error);
7550
7657
  }
7551
7658
  }
7552
7659
  async function logout(baseUrl, refreshTokenVal) {
7553
- const url = joinUrl(baseUrl, '/auth/logout');
7660
+ const url = joinUrl(baseUrl, "/auth/logout");
7554
7661
  try {
7555
- const resp = await axios$1.post(url, { refreshToken: refreshTokenVal }, { headers: { 'Content-Type': 'application/json' }, timeout: 30000 });
7556
- return { data: resp.data, status: resp.status, headers: resp.headers };
7662
+ const resp = await apiClient.post(url, { refreshToken: refreshTokenVal }, { headers: { "Content-Type": "application/json" }, timeout: 30000 });
7663
+ return {
7664
+ data: resp.data,
7665
+ status: resp.status,
7666
+ headers: resp.headers,
7667
+ };
7557
7668
  }
7558
7669
  catch (error) {
7559
7670
  throw toApiError(error);
7560
7671
  }
7561
7672
  }
7562
7673
 
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
+ }
7563
7683
  function useAuth() {
7564
7684
  const context = useContext(PearHyperliquidContext);
7565
7685
  if (!context) {
7566
- throw new Error("usePortfolio must be used within a PearHyperliquidProvider");
7686
+ throw new Error('useAuth must be used within a PearHyperliquidProvider');
7567
7687
  }
7568
7688
  const { apiBaseUrl, clientId } = context;
7569
- const [isReady, setIsReady] = useState(false);
7570
7689
  const accessToken = useUserData((s) => s.accessToken);
7571
7690
  const refreshToken$1 = useUserData((s) => s.refreshToken);
7691
+ const isReady = useUserData((s) => s.isReady);
7692
+ const isAuthenticated = useUserData((s) => s.isAuthenticated);
7572
7693
  const setAccessToken = useUserData((s) => s.setAccessToken);
7573
7694
  const setRefreshToken = useUserData((s) => s.setRefreshToken);
7574
- const isAuthenticated = useUserData((s) => s.isAuthenticated);
7695
+ const setIsReady = useUserData((s) => s.setIsReady);
7575
7696
  const setIsAuthenticated = useUserData((s) => s.setIsAuthenticated);
7576
7697
  const address = useUserData((s) => s.address);
7577
7698
  const setAddress = useUserData((s) => s.setAddress);
7699
+ // Ref to prevent concurrent refresh attempts
7700
+ const isRefreshingRef = useRef(false);
7578
7701
  useEffect(() => {
7579
- if (typeof window == "undefined") {
7702
+ if (typeof window == 'undefined') {
7580
7703
  return;
7581
7704
  }
7582
- const access = localStorage.getItem("accessToken");
7583
- const refresh = localStorage.getItem("refreshToken");
7584
- const addr = localStorage.getItem("address");
7585
- setAccessToken(access);
7586
- setRefreshToken(refresh);
7587
- setAddress(addr);
7588
- const authed = Boolean(access && addr);
7589
- setIsAuthenticated(authed);
7590
- setIsReady(true);
7591
- }, [setAccessToken, setRefreshToken, setIsAuthenticated, setAddress]);
7705
+ if (address) {
7706
+ const accessTokenKey = `${address}_accessToken`;
7707
+ const refreshTokenKey = `${address}_refreshToken`;
7708
+ const accessTokenExpiresAtKey = `${address}_accessTokenExpiresAt`;
7709
+ const refreshTokenExpiresAtKey = `${address}_refreshTokenExpiresAt`;
7710
+ const storedAccessToken = localStorage.getItem(accessTokenKey);
7711
+ const storedRefreshToken = localStorage.getItem(refreshTokenKey);
7712
+ const accessExpRaw = localStorage.getItem(accessTokenExpiresAtKey);
7713
+ const refreshExpRaw = localStorage.getItem(refreshTokenExpiresAtKey);
7714
+ const accessExp = accessExpRaw ? Number(accessExpRaw) : 0;
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]);
7592
7756
  useEffect(() => {
7593
7757
  const cleanup = addAuthInterceptors({
7594
7758
  apiBaseUrl,
7595
7759
  getAccessToken: () => {
7596
- return typeof window !== "undefined"
7597
- ? window.localStorage.getItem("accessToken")
7598
- : null;
7760
+ if (typeof window === 'undefined')
7761
+ return null;
7762
+ // Read from Zustand state as single source of truth
7763
+ return useUserData.getState().accessToken;
7599
7764
  },
7600
7765
  refreshTokens: async () => {
7601
7766
  const data = await refreshTokens();
@@ -7609,6 +7774,55 @@ function useAuth() {
7609
7774
  cleanup();
7610
7775
  };
7611
7776
  }, [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]);
7612
7826
  async function getEip712(address) {
7613
7827
  const { data } = await getEIP712Message(apiBaseUrl, address, clientId);
7614
7828
  return data;
@@ -7616,17 +7830,21 @@ function useAuth() {
7616
7830
  async function loginWithSignedMessage(address, signature, timestamp) {
7617
7831
  try {
7618
7832
  const { data } = await authenticate(apiBaseUrl, {
7619
- method: "eip712",
7833
+ method: 'eip712',
7620
7834
  address,
7621
7835
  clientId,
7622
7836
  details: { signature, timestamp },
7623
7837
  });
7624
- window.localStorage.setItem("accessToken", data.accessToken);
7625
- window.localStorage.setItem("refreshToken", data.refreshToken);
7626
- window.localStorage.setItem("address", address);
7838
+ const accessTokenKey = `${address}_accessToken`;
7839
+ const refreshTokenKey = `${address}_refreshToken`;
7840
+ const accessTokenExpiresAtKey = `${address}_accessTokenExpiresAt`;
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));
7627
7846
  setAccessToken(data.accessToken);
7628
7847
  setRefreshToken(data.refreshToken);
7629
- setAddress(address);
7630
7848
  setIsAuthenticated(true);
7631
7849
  }
7632
7850
  catch (e) {
@@ -7641,12 +7859,16 @@ function useAuth() {
7641
7859
  appId,
7642
7860
  accessToken: privyAccessToken,
7643
7861
  });
7644
- window.localStorage.setItem("accessToken", data.accessToken);
7645
- window.localStorage.setItem("refreshToken", data.refreshToken);
7646
- window.localStorage.setItem("address", address);
7862
+ const accessTokenKey = `${address}_accessToken`;
7863
+ const refreshTokenKey = `${address}_refreshToken`;
7864
+ const accessTokenExpiresAtKey = `${address}_accessTokenExpiresAt`;
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));
7647
7870
  setAccessToken(data.accessToken);
7648
7871
  setRefreshToken(data.refreshToken);
7649
- setAddress(address);
7650
7872
  setIsAuthenticated(true);
7651
7873
  }
7652
7874
  catch (e) {
@@ -7654,35 +7876,56 @@ function useAuth() {
7654
7876
  }
7655
7877
  }
7656
7878
  async function refreshTokens() {
7657
- const refresh = window.localStorage.getItem("refreshToken");
7658
- if (!refresh)
7659
- throw new Error("No refresh token");
7660
- const { data } = await refreshToken(apiBaseUrl, refresh);
7661
- window.localStorage.setItem("accessToken", data.accessToken);
7662
- window.localStorage.setItem("refreshToken", data.refreshToken);
7879
+ const currentAddress = address;
7880
+ const currentRefresh = refreshToken$1;
7881
+ if (!currentRefresh || !currentAddress)
7882
+ throw new Error('No refresh token');
7883
+ const { data } = await refreshToken(apiBaseUrl, currentRefresh);
7884
+ // Update tokens in localStorage
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));
7663
7893
  setAccessToken(data.accessToken);
7664
7894
  setRefreshToken(data.refreshToken);
7665
7895
  setIsAuthenticated(true);
7666
7896
  return data;
7667
7897
  }
7668
7898
  async function logout$1() {
7669
- const refresh = window.localStorage.getItem("refreshToken");
7670
- if (refresh) {
7899
+ const currentAddress = address;
7900
+ const currentRefresh = refreshToken$1;
7901
+ if (currentRefresh) {
7671
7902
  try {
7672
- await logout(apiBaseUrl, refresh);
7903
+ await logout(apiBaseUrl, currentRefresh);
7673
7904
  }
7674
7905
  catch (_a) {
7675
7906
  /* ignore */
7676
7907
  }
7677
7908
  }
7678
- window.localStorage.removeItem("accessToken");
7679
- window.localStorage.removeItem("refreshToken");
7680
- window.localStorage.removeItem("address");
7909
+ if (currentAddress) {
7910
+ const accessTokenKey = `${currentAddress}_accessToken`;
7911
+ const refreshTokenKey = `${currentAddress}_refreshToken`;
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
+ }
7681
7919
  setAccessToken(null);
7682
7920
  setRefreshToken(null);
7683
7921
  setAddress(null);
7684
7922
  setIsAuthenticated(false);
7685
7923
  }
7924
+ function clearSession() {
7925
+ setAccessToken(null);
7926
+ setRefreshToken(null);
7927
+ setIsAuthenticated(false);
7928
+ }
7686
7929
  return {
7687
7930
  isReady,
7688
7931
  isAuthenticated,
@@ -7694,6 +7937,8 @@ function useAuth() {
7694
7937
  loginWithPrivyToken,
7695
7938
  refreshTokens,
7696
7939
  logout: logout$1,
7940
+ clearSession,
7941
+ setAddress,
7697
7942
  };
7698
7943
  }
7699
7944
 
@@ -7861,6 +8106,7 @@ const useAllUserBalances = () => {
7861
8106
  availableToTrades,
7862
8107
  ]);
7863
8108
  return {
8109
+ abstractionMode: useUserData((state) => state.userAbstractionMode),
7864
8110
  spotBalances,
7865
8111
  availableToTrades,
7866
8112
  isLoading,
@@ -8005,9 +8251,8 @@ const PearHyperliquidContext = createContext(undefined);
8005
8251
  /**
8006
8252
  * React Provider for PearHyperliquidClient
8007
8253
  */
8008
- const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-ui.pearprotocol.io', clientId = 'PEARPROTOCOLUI', wsUrl = 'wss://hl-ui.pearprotocol.io/ws', }) => {
8254
+ const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-ui.pearprotocol.io", clientId = "PEARPROTOCOLUI", wsUrl = "wss://hl-ui.pearprotocol.io/ws", }) => {
8009
8255
  const address = useUserData((s) => s.address);
8010
- const setAddress = useUserData((s) => s.setAddress);
8011
8256
  const perpMetasByDex = useHyperliquidData((state) => state.perpMetasByDex);
8012
8257
  const setPerpDexs = useHyperliquidData((state) => state.setPerpDexs);
8013
8258
  const setPerpMetasByDex = useHyperliquidData((state) => state.setPerpMetasByDex);
@@ -8038,20 +8283,20 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-ui.pearpro
8038
8283
  perpMetas.forEach((item, perpIndex) => {
8039
8284
  var _a, _b;
8040
8285
  const dexName = perpIndex === 0
8041
- ? 'HYPERLIQUID'
8286
+ ? "HYPERLIQUID"
8042
8287
  : ((_b = (_a = perpDexs[perpIndex]) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : `DEX_${perpIndex}`);
8043
8288
  var collateralToken;
8044
8289
  if (item.collateralToken === 360) {
8045
- collateralToken = 'USDH';
8290
+ collateralToken = "USDH";
8046
8291
  }
8047
8292
  if (item.collateralToken === 0) {
8048
- collateralToken = 'USDC';
8293
+ collateralToken = "USDC";
8049
8294
  }
8050
8295
  if (item.collateralToken === 235) {
8051
- collateralToken = 'USDE';
8296
+ collateralToken = "USDE";
8052
8297
  }
8053
8298
  if (item.collateralToken === 268) {
8054
- collateralToken = 'USDT0';
8299
+ collateralToken = "USDT0";
8055
8300
  }
8056
8301
  const universeAssets = item.universe.map((asset) => ({
8057
8302
  ...asset,
@@ -8079,8 +8324,6 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-ui.pearpro
8079
8324
  }), [
8080
8325
  apiBaseUrl,
8081
8326
  wsUrl,
8082
- address,
8083
- setAddress,
8084
8327
  isConnected,
8085
8328
  lastError,
8086
8329
  nativeIsConnected,
@@ -8095,7 +8338,7 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-ui.pearpro
8095
8338
  function usePearHyperliquid() {
8096
8339
  const ctx = useContext(PearHyperliquidContext);
8097
8340
  if (!ctx)
8098
- throw new Error('usePearHyperliquid must be used within a PearHyperliquidProvider');
8341
+ throw new Error("usePearHyperliquid must be used within a PearHyperliquidProvider");
8099
8342
  return ctx;
8100
8343
  }
8101
8344
 
@@ -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;
@@ -1,8 +1,9 @@
1
- import { PlatformAccountSummaryResponseDto, OpenLimitOrderDto, RawPositionDto, TradeHistoryDataDto, TwapMonitoringDto, NotificationDto, ExtraAgent, SpotState } from "../types";
1
+ import { PlatformAccountSummaryResponseDto, OpenLimitOrderDto, RawPositionDto, TradeHistoryDataDto, TwapMonitoringDto, NotificationDto, ExtraAgent, SpotState, UserAbstraction } from "../types";
2
2
  interface UserDataState {
3
3
  accessToken: string | null;
4
4
  refreshToken: string | null;
5
5
  isAuthenticated: boolean;
6
+ isReady: boolean;
6
7
  address: string | null;
7
8
  tradeHistories: TradeHistoryDataDto[] | null;
8
9
  rawOpenPositions: RawPositionDto[] | null;
@@ -12,6 +13,7 @@ interface UserDataState {
12
13
  notifications: NotificationDto[] | null;
13
14
  userExtraAgents: ExtraAgent[] | null;
14
15
  spotState: SpotState | null;
16
+ userAbstractionMode: UserAbstraction | null;
15
17
  setAccessToken: (token: string | null) => void;
16
18
  setRefreshToken: (token: string | null) => void;
17
19
  setIsAuthenticated: (value: boolean) => void;
@@ -24,6 +26,8 @@ interface UserDataState {
24
26
  setTwapDetails: (value: TwapMonitoringDto[] | null) => void;
25
27
  setNotifications: (value: NotificationDto[] | null) => void;
26
28
  setSpotState: (value: SpotState | null) => void;
29
+ setUserAbstractionMode: (value: UserAbstraction | null) => void;
30
+ setIsReady: (value: boolean) => void;
27
31
  clean: () => void;
28
32
  }
29
33
  export declare const useUserData: import("zustand").UseBoundStore<import("zustand").StoreApi<UserDataState>>;
package/dist/types.d.ts CHANGED
@@ -563,6 +563,7 @@ export interface HLChannelDataMap {
563
563
  allDexsAssetCtxs: AllDexsAssetCtxsData;
564
564
  userFills: any;
565
565
  }
566
+ export type UserAbstraction = 'dexAbstraction' | 'disabled' | 'unifiedAccount';
566
567
  export interface WebData3UserState {
567
568
  agentAddress?: string;
568
569
  agentValidUntil?: number;
@@ -571,6 +572,7 @@ export interface WebData3UserState {
571
572
  isVault: boolean;
572
573
  user: string;
573
574
  dexAbstractionEnabled?: boolean;
575
+ abstraction: UserAbstraction;
574
576
  }
575
577
  export interface WebData3AssetCtx {
576
578
  funding: string;
@@ -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.11",
3
+ "version": "0.1.13-beta.1",
4
4
  "description": "React SDK for Pear Protocol Hyperliquid API integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",