@lifi/perps-sdk-provider-hyperliquid 15.0.0 → 17.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/HyperliquidProvider.d.ts.map +1 -1
- package/dist/cjs/HyperliquidProvider.js +5 -1
- package/dist/cjs/HyperliquidProvider.js.map +1 -1
- package/dist/cjs/accountSummary.d.ts.map +1 -1
- package/dist/cjs/accountSummary.js +34 -7
- package/dist/cjs/accountSummary.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/services/activeAssetData.d.ts +6 -0
- package/dist/cjs/services/activeAssetData.d.ts.map +1 -0
- package/dist/cjs/services/activeAssetData.js +7 -0
- package/dist/cjs/services/activeAssetData.js.map +1 -0
- package/dist/cjs/services/getAccount.d.ts.map +1 -1
- package/dist/cjs/services/getAccount.js +23 -35
- package/dist/cjs/services/getAccount.js.map +1 -1
- package/dist/cjs/services/getAvailableToTrade.d.ts +10 -0
- package/dist/cjs/services/getAvailableToTrade.d.ts.map +1 -0
- package/dist/cjs/services/getAvailableToTrade.js +32 -0
- package/dist/cjs/services/getAvailableToTrade.js.map +1 -0
- package/dist/cjs/services/getMarketSettings.d.ts +1 -1
- package/dist/cjs/services/getMarketSettings.d.ts.map +1 -1
- package/dist/cjs/services/getMarketSettings.js +3 -7
- package/dist/cjs/services/getMarketSettings.js.map +1 -1
- package/dist/cjs/services/getOrder.d.ts.map +1 -1
- package/dist/cjs/services/getOrder.js +7 -3
- package/dist/cjs/services/getOrder.js.map +1 -1
- package/dist/cjs/services/getOrders.d.ts.map +1 -1
- package/dist/cjs/services/getOrders.js +4 -23
- package/dist/cjs/services/getOrders.js.map +1 -1
- package/dist/cjs/services/getWithdrawableBalances.d.ts +5 -0
- package/dist/cjs/services/getWithdrawableBalances.d.ts.map +1 -0
- package/dist/cjs/services/getWithdrawableBalances.js +29 -0
- package/dist/cjs/services/getWithdrawableBalances.js.map +1 -0
- package/dist/cjs/types/account.d.ts +11 -8
- package/dist/cjs/types/account.d.ts.map +1 -1
- package/dist/cjs/types/account.js.map +1 -1
- package/dist/cjs/types/ws.d.ts +3 -4
- package/dist/cjs/types/ws.d.ts.map +1 -1
- package/dist/cjs/utils/abstractionMode.d.ts +1 -1
- package/dist/cjs/utils/abstractionMode.d.ts.map +1 -1
- package/dist/cjs/utils/abstractionMode.js.map +1 -1
- package/dist/cjs/utils/explorer.d.ts +2 -1
- package/dist/cjs/utils/explorer.d.ts.map +1 -1
- package/dist/cjs/utils/explorer.js +24 -1
- package/dist/cjs/utils/explorer.js.map +1 -1
- package/dist/cjs/utils/index.d.ts +3 -1
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +7 -2
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/mapPosition.d.ts.map +1 -1
- package/dist/cjs/utils/mapPosition.js +1 -4
- package/dist/cjs/utils/mapPosition.js.map +1 -1
- package/dist/cjs/utils/spotCollateral.d.ts +1 -1
- package/dist/cjs/utils/spotCollateral.d.ts.map +1 -1
- package/dist/cjs/utils/spotCollateral.js +1 -12
- package/dist/cjs/utils/spotCollateral.js.map +1 -1
- package/dist/cjs/utils/transferMargin.d.ts +2 -2
- package/dist/cjs/utils/transferMargin.d.ts.map +1 -1
- package/dist/cjs/utils/transferMargin.js +20 -12
- package/dist/cjs/utils/transferMargin.js.map +1 -1
- package/dist/cjs/utils/venueTotals.d.ts +11 -0
- package/dist/cjs/utils/venueTotals.d.ts.map +1 -0
- package/dist/cjs/utils/venueTotals.js +24 -0
- package/dist/cjs/utils/venueTotals.js.map +1 -0
- package/dist/cjs/utils/withdrawableBalances.d.ts +4 -0
- package/dist/cjs/utils/withdrawableBalances.d.ts.map +1 -0
- package/dist/cjs/utils/withdrawableBalances.js +42 -0
- package/dist/cjs/utils/withdrawableBalances.js.map +1 -0
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts +3 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.js +102 -36
- package/dist/cjs/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/esm/HyperliquidProvider.d.ts.map +1 -1
- package/dist/esm/HyperliquidProvider.js +6 -2
- package/dist/esm/HyperliquidProvider.js.map +1 -1
- package/dist/esm/accountSummary.d.ts +4 -3
- package/dist/esm/accountSummary.d.ts.map +1 -1
- package/dist/esm/accountSummary.js +36 -18
- package/dist/esm/accountSummary.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/services/activeAssetData.d.ts +13 -0
- package/dist/esm/services/activeAssetData.d.ts.map +1 -0
- package/dist/esm/services/activeAssetData.js +10 -0
- package/dist/esm/services/activeAssetData.js.map +1 -0
- package/dist/esm/services/getAccount.d.ts.map +1 -1
- package/dist/esm/services/getAccount.js +19 -29
- package/dist/esm/services/getAccount.js.map +1 -1
- package/dist/esm/services/getAvailableToTrade.d.ts +26 -0
- package/dist/esm/services/getAvailableToTrade.d.ts.map +1 -0
- package/dist/esm/services/getAvailableToTrade.js +42 -0
- package/dist/esm/services/getAvailableToTrade.js.map +1 -0
- package/dist/esm/services/getMarketSettings.d.ts +1 -1
- package/dist/esm/services/getMarketSettings.d.ts.map +1 -1
- package/dist/esm/services/getMarketSettings.js +3 -7
- package/dist/esm/services/getMarketSettings.js.map +1 -1
- package/dist/esm/services/getOrder.d.ts.map +1 -1
- package/dist/esm/services/getOrder.js +7 -3
- package/dist/esm/services/getOrder.js.map +1 -1
- package/dist/esm/services/getOrders.d.ts.map +1 -1
- package/dist/esm/services/getOrders.js +6 -34
- package/dist/esm/services/getOrders.js.map +1 -1
- package/dist/esm/services/getWithdrawableBalances.d.ts +24 -0
- package/dist/esm/services/getWithdrawableBalances.d.ts.map +1 -0
- package/dist/esm/services/getWithdrawableBalances.js +39 -0
- package/dist/esm/services/getWithdrawableBalances.js.map +1 -0
- package/dist/esm/types/account.d.ts +21 -8
- package/dist/esm/types/account.d.ts.map +1 -1
- package/dist/esm/types/account.js.map +1 -1
- package/dist/esm/types/ws.d.ts +10 -4
- package/dist/esm/types/ws.d.ts.map +1 -1
- package/dist/esm/utils/abstractionMode.d.ts +1 -1
- package/dist/esm/utils/abstractionMode.d.ts.map +1 -1
- package/dist/esm/utils/abstractionMode.js.map +1 -1
- package/dist/esm/utils/explorer.d.ts +9 -1
- package/dist/esm/utils/explorer.d.ts.map +1 -1
- package/dist/esm/utils/explorer.js +34 -1
- package/dist/esm/utils/explorer.js.map +1 -1
- package/dist/esm/utils/index.d.ts +3 -1
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/index.js +3 -1
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/mapPosition.d.ts.map +1 -1
- package/dist/esm/utils/mapPosition.js +1 -4
- package/dist/esm/utils/mapPosition.js.map +1 -1
- package/dist/esm/utils/spotCollateral.d.ts +4 -4
- package/dist/esm/utils/spotCollateral.d.ts.map +1 -1
- package/dist/esm/utils/spotCollateral.js +4 -23
- package/dist/esm/utils/spotCollateral.js.map +1 -1
- package/dist/esm/utils/transferMargin.d.ts +12 -8
- package/dist/esm/utils/transferMargin.d.ts.map +1 -1
- package/dist/esm/utils/transferMargin.js +30 -18
- package/dist/esm/utils/transferMargin.js.map +1 -1
- package/dist/esm/utils/venueTotals.d.ts +26 -0
- package/dist/esm/utils/venueTotals.d.ts.map +1 -0
- package/dist/esm/utils/venueTotals.js +26 -0
- package/dist/esm/utils/venueTotals.js.map +1 -0
- package/dist/esm/utils/withdrawableBalances.d.ts +16 -0
- package/dist/esm/utils/withdrawableBalances.d.ts.map +1 -0
- package/dist/esm/utils/withdrawableBalances.js +50 -0
- package/dist/esm/utils/withdrawableBalances.js.map +1 -0
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts +4 -1
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/esm/websocket/HyperliquidWsProvider.js +101 -35
- package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/types/HyperliquidProvider.d.ts.map +1 -1
- package/dist/types/accountSummary.d.ts +4 -3
- package/dist/types/accountSummary.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/services/activeAssetData.d.ts +13 -0
- package/dist/types/services/activeAssetData.d.ts.map +1 -0
- package/dist/types/services/getAccount.d.ts.map +1 -1
- package/dist/types/services/getAvailableToTrade.d.ts +26 -0
- package/dist/types/services/getAvailableToTrade.d.ts.map +1 -0
- package/dist/types/services/getMarketSettings.d.ts +1 -1
- package/dist/types/services/getMarketSettings.d.ts.map +1 -1
- package/dist/types/services/getOrder.d.ts.map +1 -1
- package/dist/types/services/getOrders.d.ts.map +1 -1
- package/dist/types/services/getWithdrawableBalances.d.ts +24 -0
- package/dist/types/services/getWithdrawableBalances.d.ts.map +1 -0
- package/dist/types/types/account.d.ts +21 -8
- package/dist/types/types/account.d.ts.map +1 -1
- package/dist/types/types/ws.d.ts +10 -4
- package/dist/types/types/ws.d.ts.map +1 -1
- package/dist/types/utils/abstractionMode.d.ts +1 -1
- package/dist/types/utils/abstractionMode.d.ts.map +1 -1
- package/dist/types/utils/explorer.d.ts +9 -1
- package/dist/types/utils/explorer.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +3 -1
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/mapPosition.d.ts.map +1 -1
- package/dist/types/utils/spotCollateral.d.ts +4 -4
- package/dist/types/utils/spotCollateral.d.ts.map +1 -1
- package/dist/types/utils/transferMargin.d.ts +12 -8
- package/dist/types/utils/transferMargin.d.ts.map +1 -1
- package/dist/types/utils/venueTotals.d.ts +26 -0
- package/dist/types/utils/venueTotals.d.ts.map +1 -0
- package/dist/types/utils/withdrawableBalances.d.ts +16 -0
- package/dist/types/utils/withdrawableBalances.d.ts.map +1 -0
- package/dist/types/websocket/HyperliquidWsProvider.d.ts +4 -1
- package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/HyperliquidProvider.ts +28 -2
- package/src/accountSummary.ts +64 -19
- package/src/index.ts +2 -0
- package/src/services/activeAssetData.ts +24 -0
- package/src/services/getAccount.ts +37 -52
- package/src/services/getAvailableToTrade.ts +72 -0
- package/src/services/getMarketSettings.ts +7 -11
- package/src/services/getOrder.ts +10 -3
- package/src/services/getOrders.ts +5 -56
- package/src/services/getWithdrawableBalances.ts +94 -0
- package/src/types/account.ts +22 -8
- package/src/types/ws.ts +18 -5
- package/src/utils/abstractionMode.ts +1 -1
- package/src/utils/explorer.ts +51 -2
- package/src/utils/index.ts +7 -1
- package/src/utils/mapPosition.ts +1 -5
- package/src/utils/spotCollateral.ts +4 -25
- package/src/utils/transferMargin.ts +31 -20
- package/src/utils/venueTotals.ts +48 -0
- package/src/utils/withdrawableBalances.ts +69 -0
- package/src/websocket/HyperliquidWsProvider.ts +149 -42
- package/dist/cjs/websocket/decodeChain.d.ts +0 -11
- package/dist/cjs/websocket/decodeChain.d.ts.map +0 -1
- package/dist/cjs/websocket/decodeChain.js +0 -37
- package/dist/cjs/websocket/decodeChain.js.map +0 -1
- package/dist/esm/websocket/decodeChain.d.ts +0 -30
- package/dist/esm/websocket/decodeChain.d.ts.map +0 -1
- package/dist/esm/websocket/decodeChain.js +0 -44
- package/dist/esm/websocket/decodeChain.js.map +0 -1
- package/dist/types/websocket/decodeChain.d.ts +0 -30
- package/dist/types/websocket/decodeChain.d.ts.map +0 -1
- package/src/websocket/decodeChain.ts +0 -54
|
@@ -1,19 +1,6 @@
|
|
|
1
1
|
import type { Balance } from '@lifi/perps-types'
|
|
2
2
|
import { toWireBig } from './decimal.js'
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Portfolio-margin collateral beyond the category quote assets, keyed by spot
|
|
6
|
-
* display symbol with its loan-to-value weight. Hyperliquid credits these
|
|
7
|
-
* toward buying power at the given fraction (0.5 for both today). Quote assets
|
|
8
|
-
* (USDC/USDT) are already full-value collateral via the category model, so
|
|
9
|
-
* they are not listed here.
|
|
10
|
-
* https://hyperliquid.gitbook.io/hyperliquid-docs/trading/portfolio-margin
|
|
11
|
-
*/
|
|
12
|
-
const PORTFOLIO_MARGIN_LTV: Readonly<Record<string, number>> = {
|
|
13
|
-
HYPE: 0.5,
|
|
14
|
-
UBTC: 0.5,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
4
|
/**
|
|
18
5
|
* Result of {@link partitionSpotBalances}: balances that count toward
|
|
19
6
|
* collateral and balances treated as ordinary holdings.
|
|
@@ -25,15 +12,14 @@ export interface SpotPartition {
|
|
|
25
12
|
}
|
|
26
13
|
|
|
27
14
|
/**
|
|
28
|
-
* Partition spot balances into collateral and ordinary holdings.
|
|
29
|
-
* are
|
|
30
|
-
*
|
|
15
|
+
* Partition spot balances into collateral and ordinary holdings. Category
|
|
16
|
+
* quote assets are collateral; every other token is an ordinary holding.
|
|
17
|
+
* Zero-unit rows are dropped from both lists.
|
|
31
18
|
* @public
|
|
32
19
|
*/
|
|
33
20
|
export const partitionSpotBalances = (
|
|
34
21
|
spotBalances: readonly Balance[],
|
|
35
|
-
quoteAssetIds: ReadonlySet<string
|
|
36
|
-
portfolioMargin: boolean
|
|
22
|
+
quoteAssetIds: ReadonlySet<string>
|
|
37
23
|
): SpotPartition => {
|
|
38
24
|
const collateralBalances: Balance[] = []
|
|
39
25
|
const balances: Balance[] = []
|
|
@@ -43,13 +29,6 @@ export const partitionSpotBalances = (
|
|
|
43
29
|
}
|
|
44
30
|
if (quoteAssetIds.has(balance.asset.id)) {
|
|
45
31
|
collateralBalances.push(balance)
|
|
46
|
-
continue
|
|
47
|
-
}
|
|
48
|
-
const ltv = portfolioMargin
|
|
49
|
-
? PORTFOLIO_MARGIN_LTV[balance.asset.displaySymbol]
|
|
50
|
-
: undefined
|
|
51
|
-
if (ltv !== undefined) {
|
|
52
|
-
collateralBalances.push({ ...balance, collateralWeight: ltv })
|
|
53
32
|
} else {
|
|
54
33
|
balances.push(balance)
|
|
55
34
|
}
|
|
@@ -2,24 +2,27 @@ import { PerpsError } from '@lifi/perps-sdk'
|
|
|
2
2
|
import {
|
|
3
3
|
PerpsErrorCode,
|
|
4
4
|
type Position,
|
|
5
|
-
type PositionMarginConstraints,
|
|
6
5
|
positionSupportsMarginAdjustment,
|
|
6
|
+
positionSupportsMarginRemoval,
|
|
7
7
|
} from '@lifi/perps-types'
|
|
8
8
|
import Big from 'big.js'
|
|
9
9
|
|
|
10
10
|
const NOTIONAL_FLOOR_RATIO = '0.1'
|
|
11
|
-
const
|
|
11
|
+
const AMOUNT_DECIMALS = 6
|
|
12
12
|
|
|
13
|
-
function
|
|
14
|
-
let amount: Big
|
|
13
|
+
function positionAmount(value: string, field: string): Big {
|
|
15
14
|
try {
|
|
16
|
-
|
|
15
|
+
return new Big(value)
|
|
17
16
|
} catch {
|
|
18
17
|
throw new PerpsError(
|
|
19
18
|
PerpsErrorCode.ValidationError,
|
|
20
19
|
`Invalid decimal string on Position.${field}: '${value}'`
|
|
21
20
|
)
|
|
22
21
|
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function positivePositionAmount(value: string, field: string): Big {
|
|
25
|
+
const amount = positionAmount(value, field)
|
|
23
26
|
if (amount.lte(0)) {
|
|
24
27
|
throw new PerpsError(
|
|
25
28
|
PerpsErrorCode.ValidationError,
|
|
@@ -30,36 +33,44 @@ function positivePositionAmount(value: string, field: string): Big {
|
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
/**
|
|
33
|
-
* Hyperliquid
|
|
34
|
-
* `max(initial_margin_required, 0.1
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* markets without individual margin adjustment return `undefined`.
|
|
36
|
+
* Hyperliquid removable isolated margin:
|
|
37
|
+
* `marginUsed − max(initial_margin_required, 0.1 × total_position_value)`.
|
|
38
|
+
* Hyperliquid isolated `marginUsed` already includes the unrealized PnL of
|
|
39
|
+
* the position, so the PnL is not added again, and it can reach zero or less
|
|
40
|
+
* before liquidation.
|
|
39
41
|
*
|
|
42
|
+
* @returns `undefined` for cross positions and markets without individual
|
|
43
|
+
* margin adjustment; `'0'` for add-only strict-isolated markets and when
|
|
44
|
+
* nothing is removable.
|
|
45
|
+
* @throws {PerpsError} `ValidationError` when a required `Position` decimal
|
|
46
|
+
* is malformed, or when a size, price or requirement is not positive.
|
|
40
47
|
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/trading/margining
|
|
41
48
|
* @public
|
|
42
49
|
*/
|
|
43
|
-
export function
|
|
50
|
+
export function positionRemovableMargin(
|
|
44
51
|
position: Position
|
|
45
|
-
):
|
|
52
|
+
): string | undefined {
|
|
46
53
|
if (!positionSupportsMarginAdjustment(position)) {
|
|
47
54
|
return undefined
|
|
48
55
|
}
|
|
56
|
+
if (!positionSupportsMarginRemoval(position)) {
|
|
57
|
+
return '0'
|
|
58
|
+
}
|
|
59
|
+
const marginUsed = positionAmount(position.marginUsed, 'marginUsed')
|
|
49
60
|
const initialMargin = positivePositionAmount(
|
|
50
61
|
position.initialMarginRequirement,
|
|
51
62
|
'initialMarginRequirement'
|
|
52
63
|
)
|
|
53
|
-
const
|
|
54
|
-
positivePositionAmount(position.markPrice, 'markPrice')
|
|
55
|
-
|
|
56
|
-
const notionalFloor = notional.times(NOTIONAL_FLOOR_RATIO)
|
|
64
|
+
const notionalFloor = positivePositionAmount(position.size, 'size')
|
|
65
|
+
.times(positivePositionAmount(position.markPrice, 'markPrice'))
|
|
66
|
+
.times(NOTIONAL_FLOOR_RATIO)
|
|
57
67
|
const minimumMargin = initialMargin.gt(notionalFloor)
|
|
58
68
|
? initialMargin
|
|
59
69
|
: notionalFloor
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
71
|
+
const removable = marginUsed.minus(minimumMargin)
|
|
72
|
+
if (removable.lte(0)) {
|
|
73
|
+
return '0'
|
|
64
74
|
}
|
|
75
|
+
return removable.round(AMOUNT_DECIMALS, Big.roundDown).toFixed()
|
|
65
76
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { HyperliquidMarginSummary, Position } from '@lifi/perps-types'
|
|
2
|
+
import Big from 'big.js'
|
|
3
|
+
import { toWireBig } from './decimal.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* One perps sub-dex entry {@link perpsTotals} reads. The REST response always
|
|
7
|
+
* carries `marginSummary`; a WebSocket frame may omit it.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export interface DexMarginSummary {
|
|
11
|
+
marginSummary?: HyperliquidMarginSummary
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Sum the venue `marginSummary` totals over every perps sub-dex of an
|
|
16
|
+
* account. `accountValue` is total equity, so it already carries locked
|
|
17
|
+
* margin and unrealized PnL. An entry without a `marginSummary` adds nothing.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
export const perpsTotals = (
|
|
21
|
+
dexStates: readonly DexMarginSummary[]
|
|
22
|
+
): { accountValue: Big; marginUsed: Big } => {
|
|
23
|
+
let accountValue = new Big(0)
|
|
24
|
+
let marginUsed = new Big(0)
|
|
25
|
+
for (const { marginSummary } of dexStates) {
|
|
26
|
+
if (marginSummary === undefined) {
|
|
27
|
+
continue
|
|
28
|
+
}
|
|
29
|
+
accountValue = accountValue.plus(
|
|
30
|
+
toWireBig(marginSummary.accountValue, 'marginSummary.accountValue')
|
|
31
|
+
)
|
|
32
|
+
marginUsed = marginUsed.plus(
|
|
33
|
+
toWireBig(marginSummary.totalMarginUsed, 'marginSummary.totalMarginUsed')
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
return { accountValue, marginUsed }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Sum the unrealized PnL of every position, in quote-asset units.
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
export const sumUnrealizedPnl = (positions: readonly Position[]): Big =>
|
|
44
|
+
positions.reduce(
|
|
45
|
+
(sum, position) =>
|
|
46
|
+
sum.plus(toWireBig(position.unrealizedPnl, 'position.unrealizedPnl')),
|
|
47
|
+
new Big(0)
|
|
48
|
+
)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ProviderWithdrawableBalance } from '@lifi/perps-sdk'
|
|
2
|
+
import type {
|
|
3
|
+
HlAbstractionMode,
|
|
4
|
+
HlClearinghouseState,
|
|
5
|
+
HlSpotClearinghouseState,
|
|
6
|
+
} from '../types/index.js'
|
|
7
|
+
import { isUnifiedAbstraction } from './abstractionMode.js'
|
|
8
|
+
import { assetIsOutcome } from './assetId.js'
|
|
9
|
+
import { toWireBig } from './decimal.js'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Split a Hyperliquid account's venue figures into the routes a withdrawal
|
|
13
|
+
* draws on. A unified or portfolio-margin account holds its collateral in spot,
|
|
14
|
+
* so each spot token adds the part of `total` that no order or margin holds. A
|
|
15
|
+
* route with nothing left to draw carries no row, and the caller applies the
|
|
16
|
+
* per-asset venue minimum.
|
|
17
|
+
*
|
|
18
|
+
* @param quoteAssetId - `Asset.id` the perps-route row is keyed by.
|
|
19
|
+
* @param withdrawalFee - Flat venue fee in quote-asset units, set on every
|
|
20
|
+
* quote-asset row. Absent leaves every row without a fee.
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export const hyperliquidWithdrawableBalances = (
|
|
24
|
+
abstraction: HlAbstractionMode | null,
|
|
25
|
+
state: HlClearinghouseState,
|
|
26
|
+
spotState: HlSpotClearinghouseState,
|
|
27
|
+
quoteAssetId: string,
|
|
28
|
+
withdrawalFee?: string
|
|
29
|
+
): ProviderWithdrawableBalance[] => {
|
|
30
|
+
const rows: ProviderWithdrawableBalance[] = []
|
|
31
|
+
const fee =
|
|
32
|
+
withdrawalFee === undefined
|
|
33
|
+
? undefined
|
|
34
|
+
: toWireBig(withdrawalFee, 'providers.withdrawalFeeUsd').toFixed()
|
|
35
|
+
const feeFor = (assetId: string) =>
|
|
36
|
+
fee === undefined || assetId !== quoteAssetId ? {} : { withdrawalFee: fee }
|
|
37
|
+
|
|
38
|
+
if (isUnifiedAbstraction(abstraction)) {
|
|
39
|
+
for (const balance of spotState.balances) {
|
|
40
|
+
if (assetIsOutcome(balance.coin)) {
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
const spot = toWireBig(balance.total, 'spotBalance.total').minus(
|
|
44
|
+
toWireBig(balance.hold, 'spotBalance.hold')
|
|
45
|
+
)
|
|
46
|
+
if (spot.gt(0)) {
|
|
47
|
+
const assetId = String(balance.token)
|
|
48
|
+
rows.push({
|
|
49
|
+
assetId,
|
|
50
|
+
route: 'spot',
|
|
51
|
+
available: spot.toFixed(),
|
|
52
|
+
...feeFor(assetId),
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const perps = toWireBig(state.withdrawable, 'clearinghouseState.withdrawable')
|
|
59
|
+
if (perps.gt(0)) {
|
|
60
|
+
rows.push({
|
|
61
|
+
assetId: quoteAssetId,
|
|
62
|
+
route: 'perps',
|
|
63
|
+
available: perps.toFixed(),
|
|
64
|
+
...feeFor(quoteAssetId),
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return rows
|
|
69
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
DecodeChain,
|
|
2
3
|
getMarketRegistry,
|
|
3
4
|
isActiveMarket,
|
|
4
5
|
isActiveOrderStatus,
|
|
@@ -10,7 +11,7 @@ import {
|
|
|
10
11
|
ReconnectingWebSocket,
|
|
11
12
|
resolveSubscribeQuote,
|
|
12
13
|
type SubscriptionListener,
|
|
13
|
-
|
|
14
|
+
toAssetDisplay,
|
|
14
15
|
toPerpsMarketDisplay,
|
|
15
16
|
WsProviderBase,
|
|
16
17
|
type WsProviderFactory,
|
|
@@ -19,7 +20,6 @@ import {
|
|
|
19
20
|
wsLog,
|
|
20
21
|
} from '@lifi/perps-sdk'
|
|
21
22
|
import type {
|
|
22
|
-
AccountResponse,
|
|
23
23
|
Balance,
|
|
24
24
|
MarketContext,
|
|
25
25
|
Order,
|
|
@@ -37,9 +37,11 @@ import {
|
|
|
37
37
|
SPOT_MARKET_ID,
|
|
38
38
|
} from '../constants.js'
|
|
39
39
|
import type {
|
|
40
|
+
HlActiveAssetData,
|
|
40
41
|
HlAssetPosition,
|
|
41
42
|
HlOrderDetail,
|
|
42
43
|
HlOrderStatusResponse,
|
|
44
|
+
HlSpotClearinghouseState,
|
|
43
45
|
HlUserFill,
|
|
44
46
|
HlWsActiveAssetCtxData,
|
|
45
47
|
HlWsActiveSpotAssetCtxData,
|
|
@@ -75,12 +77,13 @@ import {
|
|
|
75
77
|
mapOrder,
|
|
76
78
|
mapPosition,
|
|
77
79
|
partitionSpotBalances,
|
|
80
|
+
perpsTotals,
|
|
78
81
|
priceStepToAggregation,
|
|
79
82
|
spotAssetFromToken,
|
|
80
83
|
spotBalance,
|
|
81
84
|
spotPriceById,
|
|
85
|
+
sumUnrealizedPnl,
|
|
82
86
|
} from '../utils/index.js'
|
|
83
|
-
import { DecodeChain } from './decodeChain.js'
|
|
84
87
|
|
|
85
88
|
/** HL's compact `l2` snapshot carries 20 levels per side. */
|
|
86
89
|
const HL_L2_BOOK_MAX_LEVELS_PER_SIDE = 20
|
|
@@ -88,6 +91,15 @@ const HL_L2_BOOK_MAX_LEVELS_PER_SIDE = 20
|
|
|
88
91
|
const normalizeHlAddress = (address: string): string =>
|
|
89
92
|
isAddress(address, { strict: false }) ? address.toLowerCase() : address
|
|
90
93
|
|
|
94
|
+
/** Venue buying power for the asset the main perps dex settles in. */
|
|
95
|
+
const availableAfterMaintenance = (
|
|
96
|
+
spotState: { tokenToAvailableAfterMaintenance?: readonly [number, string][] },
|
|
97
|
+
quoteAssetId: string | undefined
|
|
98
|
+
): string | undefined =>
|
|
99
|
+
spotState.tokenToAvailableAfterMaintenance?.find(
|
|
100
|
+
([token]) => String(token) === quoteAssetId
|
|
101
|
+
)?.[1]
|
|
102
|
+
|
|
91
103
|
/**
|
|
92
104
|
* `WsProviderFactory` constructor for Hyperliquid — pass to
|
|
93
105
|
* `new PerpsWsClient(client, { wsProviders: { hyperliquid: hyperliquidWsProvider() } })`.
|
|
@@ -147,11 +159,16 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
147
159
|
{
|
|
148
160
|
releaseSpot: Promise<() => void>
|
|
149
161
|
spot?: { collateralBalances: Balance[]; balances: Balance[] }
|
|
162
|
+
availableMargin?: string
|
|
163
|
+
availableMarginPending?: boolean
|
|
150
164
|
}
|
|
151
165
|
>()
|
|
152
166
|
// Kept outside the pipeline entry: the first clearinghouse frame lands
|
|
153
167
|
// while the mode read is still pending, before the pipeline exists.
|
|
154
|
-
private readonly
|
|
168
|
+
private readonly latestPerpsByUser = new Map<
|
|
169
|
+
string,
|
|
170
|
+
{ positions: Position[]; marginUsed: string }
|
|
171
|
+
>()
|
|
155
172
|
private readonly heldSummaryByUser = new Map<
|
|
156
173
|
string,
|
|
157
174
|
{
|
|
@@ -273,7 +290,8 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
273
290
|
(sub.channel === 'marketContext' ||
|
|
274
291
|
sub.channel === 'orderbook' ||
|
|
275
292
|
sub.channel === 'candle' ||
|
|
276
|
-
sub.channel === 'trades'
|
|
293
|
+
sub.channel === 'trades' ||
|
|
294
|
+
sub.channel === 'availableToTrade')
|
|
277
295
|
) {
|
|
278
296
|
this.registry.requireActive(sub.marketId)
|
|
279
297
|
}
|
|
@@ -331,7 +349,7 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
331
349
|
// subscription so a resubscribe reflects an account-mode change.
|
|
332
350
|
this.abstractionByUser.delete(user)
|
|
333
351
|
this.heldSummaryByUser.delete(user)
|
|
334
|
-
this.
|
|
352
|
+
this.latestPerpsByUser.delete(user)
|
|
335
353
|
this.syncUnifiedPipeline(user, user, null)
|
|
336
354
|
this.unregisterSub(wireKey)
|
|
337
355
|
this.rws.send(
|
|
@@ -506,6 +524,8 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
506
524
|
return `accountSummary:${sub.address.toLowerCase()}`
|
|
507
525
|
case 'spotBalances':
|
|
508
526
|
return `spotState:${sub.address.toLowerCase()}`
|
|
527
|
+
case 'availableToTrade':
|
|
528
|
+
return `activeAssetData:${sub.address.toLowerCase()}:${sub.marketId}`
|
|
509
529
|
}
|
|
510
530
|
}
|
|
511
531
|
|
|
@@ -581,6 +601,12 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
581
601
|
}
|
|
582
602
|
case 'spotBalances':
|
|
583
603
|
return { type: 'spotState', user: normalizeHlAddress(sub.address) }
|
|
604
|
+
case 'availableToTrade':
|
|
605
|
+
return {
|
|
606
|
+
type: 'activeAssetData',
|
|
607
|
+
user: normalizeHlAddress(sub.address),
|
|
608
|
+
coin: sub.marketId,
|
|
609
|
+
}
|
|
584
610
|
}
|
|
585
611
|
}
|
|
586
612
|
|
|
@@ -656,6 +682,9 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
656
682
|
case 'spotState':
|
|
657
683
|
this.handleSpotState(msg.data as HlWsSpotStateData)
|
|
658
684
|
break
|
|
685
|
+
case 'activeAssetData':
|
|
686
|
+
this.handleActiveAssetData(msg.data as HlActiveAssetData)
|
|
687
|
+
break
|
|
659
688
|
}
|
|
660
689
|
} catch (error) {
|
|
661
690
|
wsLog.handlerFailure(this.providerKey, error)
|
|
@@ -1130,30 +1159,26 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
1130
1159
|
data: positions,
|
|
1131
1160
|
})
|
|
1132
1161
|
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
let accountValue = 0
|
|
1137
|
-
let marginUsed = 0
|
|
1138
|
-
for (const [, state] of data.clearinghouseStates) {
|
|
1139
|
-
accountValue +=
|
|
1140
|
-
Number.parseFloat(state.marginSummary?.accountValue ?? '') || 0
|
|
1141
|
-
marginUsed +=
|
|
1142
|
-
Number.parseFloat(state.marginSummary?.totalMarginUsed ?? '') || 0
|
|
1143
|
-
}
|
|
1144
|
-
const unrealizedPnl = positions.reduce(
|
|
1145
|
-
(sum, p) => sum + (Number.parseFloat(p.unrealizedPnl) || 0),
|
|
1146
|
-
0
|
|
1162
|
+
const { accountValue, marginUsed } = perpsTotals(
|
|
1163
|
+
data.clearinghouseStates.map(([, state]) => state)
|
|
1147
1164
|
)
|
|
1165
|
+
|
|
1166
|
+
const key = data.user.toLowerCase()
|
|
1167
|
+
this.latestPerpsByUser.set(key, {
|
|
1168
|
+
positions,
|
|
1169
|
+
marginUsed: marginUsed.toFixed(),
|
|
1170
|
+
})
|
|
1171
|
+
this.emitUnifiedSummary(key)
|
|
1172
|
+
|
|
1148
1173
|
// Equity semantics, matching the REST summary: `accountValue` already
|
|
1149
1174
|
// carries locked margin and unrealized PnL. Spot balances stream apart,
|
|
1150
1175
|
// so this portfolio value covers perps equity only — which is why the
|
|
1151
1176
|
// frame is gated on the abstraction mode below.
|
|
1152
1177
|
this.emitSummaryIfModeAllows(data.user, {
|
|
1153
|
-
portfolioValue: accountValue.
|
|
1154
|
-
availableMargin: (
|
|
1155
|
-
marginUsed: marginUsed.
|
|
1156
|
-
unrealizedPnl:
|
|
1178
|
+
portfolioValue: accountValue.toFixed(),
|
|
1179
|
+
availableMargin: accountValue.minus(marginUsed).toFixed(),
|
|
1180
|
+
marginUsed: marginUsed.toFixed(),
|
|
1181
|
+
unrealizedPnl: sumUnrealizedPnl(positions).toFixed(),
|
|
1157
1182
|
})
|
|
1158
1183
|
}
|
|
1159
1184
|
|
|
@@ -1219,24 +1244,32 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
1219
1244
|
|
|
1220
1245
|
private emitUnifiedSummary(key: string) {
|
|
1221
1246
|
const pipeline = this.unifiedSummaryByUser.get(key)
|
|
1222
|
-
const
|
|
1247
|
+
const perps = this.latestPerpsByUser.get(key)
|
|
1223
1248
|
// Both envelopes must have arrived: a spot-only summary would report
|
|
1224
1249
|
// zero margin used against real positions.
|
|
1225
|
-
if (
|
|
1250
|
+
if (
|
|
1251
|
+
pipeline?.spot === undefined ||
|
|
1252
|
+
pipeline.availableMargin === undefined ||
|
|
1253
|
+
perps === undefined
|
|
1254
|
+
) {
|
|
1226
1255
|
return
|
|
1227
1256
|
}
|
|
1228
|
-
const
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
'gross'
|
|
1257
|
+
const portfolioValue = [
|
|
1258
|
+
...pipeline.spot.collateralBalances,
|
|
1259
|
+
...pipeline.spot.balances,
|
|
1260
|
+
].reduce(
|
|
1261
|
+
(sum, balance) =>
|
|
1262
|
+
sum.plus(toWireBig(balance.valueUsd, 'spotBalance.valueUsd')),
|
|
1263
|
+
new Big(0)
|
|
1236
1264
|
)
|
|
1237
1265
|
this.emit(`accountSummary:${key}`, {
|
|
1238
1266
|
channel: 'accountSummary',
|
|
1239
|
-
data:
|
|
1267
|
+
data: {
|
|
1268
|
+
portfolioValue: portfolioValue.toFixed(),
|
|
1269
|
+
availableMargin: pipeline.availableMargin,
|
|
1270
|
+
marginUsed: perps.marginUsed,
|
|
1271
|
+
unrealizedPnl: sumUnrealizedPnl(perps.positions).toFixed(),
|
|
1272
|
+
},
|
|
1240
1273
|
})
|
|
1241
1274
|
}
|
|
1242
1275
|
|
|
@@ -1334,6 +1367,27 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
1334
1367
|
)
|
|
1335
1368
|
}
|
|
1336
1369
|
|
|
1370
|
+
private handleActiveAssetData(data: HlActiveAssetData) {
|
|
1371
|
+
const market = this.registry?.get(data.coin)
|
|
1372
|
+
if (market === undefined) {
|
|
1373
|
+
throw new PerpsError(
|
|
1374
|
+
PerpsErrorCode.ValidationError,
|
|
1375
|
+
`[${this.providerKey}] activeAssetData frame names unknown market '${data.coin}'.`
|
|
1376
|
+
)
|
|
1377
|
+
}
|
|
1378
|
+
const [buy, sell] = data.availableToTrade
|
|
1379
|
+
this.emit(`activeAssetData:${data.user.toLowerCase()}:${data.coin}`, {
|
|
1380
|
+
channel: 'availableToTrade',
|
|
1381
|
+
data: {
|
|
1382
|
+
providerId: market.providerId,
|
|
1383
|
+
marketId: market.id,
|
|
1384
|
+
asset: toAssetDisplay(market.quoteAsset),
|
|
1385
|
+
buy,
|
|
1386
|
+
sell,
|
|
1387
|
+
},
|
|
1388
|
+
})
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1337
1391
|
private handleSpotState(data: HlWsSpotStateData) {
|
|
1338
1392
|
const user = data.user.toLowerCase()
|
|
1339
1393
|
const markets = this.registry?.activeMarkets ?? []
|
|
@@ -1360,20 +1414,66 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
1360
1414
|
const pipeline = this.unifiedSummaryByUser.get(user)
|
|
1361
1415
|
if (pipeline !== undefined) {
|
|
1362
1416
|
const quoteAssetIds = new Set(markets.map((m) => m.quoteAsset.id))
|
|
1363
|
-
const entry = this.abstractionByUser.get(user)
|
|
1364
|
-
const portfolioMargin =
|
|
1365
|
-
entry !== undefined &&
|
|
1366
|
-
entry !== 'pending' &&
|
|
1367
|
-
entry.mode === HlAbstractionMode.PORTFOLIO_MARGIN
|
|
1368
1417
|
// Same partition as getAccount so REST and WS agree on collateral.
|
|
1369
1418
|
pipeline.spot = partitionSpotBalances(
|
|
1370
1419
|
rows.map(({ balance }) => balance),
|
|
1371
|
-
quoteAssetIds
|
|
1372
|
-
portfolioMargin
|
|
1420
|
+
quoteAssetIds
|
|
1373
1421
|
)
|
|
1422
|
+
const settlementAssetId = markets.find(
|
|
1423
|
+
(m) => m.categoryId === this.providerKey
|
|
1424
|
+
)?.quoteAsset.id
|
|
1425
|
+
const available = availableAfterMaintenance(
|
|
1426
|
+
data.spotState,
|
|
1427
|
+
settlementAssetId
|
|
1428
|
+
)
|
|
1429
|
+
if (available === undefined) {
|
|
1430
|
+
this.fetchAvailableAfterMaintenance(user, data.user, settlementAssetId)
|
|
1431
|
+
} else {
|
|
1432
|
+
pipeline.availableMargin = available
|
|
1433
|
+
}
|
|
1374
1434
|
this.emitUnifiedSummary(user)
|
|
1375
1435
|
}
|
|
1376
1436
|
}
|
|
1437
|
+
|
|
1438
|
+
/** Read the venue buying power over REST when the spot frame omits it. */
|
|
1439
|
+
private fetchAvailableAfterMaintenance(
|
|
1440
|
+
key: string,
|
|
1441
|
+
user: string,
|
|
1442
|
+
quoteAssetId: string | undefined
|
|
1443
|
+
) {
|
|
1444
|
+
const client = this.client
|
|
1445
|
+
const pipeline = this.unifiedSummaryByUser.get(key)
|
|
1446
|
+
if (
|
|
1447
|
+
client === undefined ||
|
|
1448
|
+
pipeline === undefined ||
|
|
1449
|
+
pipeline.availableMarginPending
|
|
1450
|
+
) {
|
|
1451
|
+
return
|
|
1452
|
+
}
|
|
1453
|
+
pipeline.availableMarginPending = true
|
|
1454
|
+
infoRequest<HlSpotClearinghouseState>(
|
|
1455
|
+
DEFAULT_HYPERLIQUID_API_URL,
|
|
1456
|
+
{ type: 'spotClearinghouseState', user },
|
|
1457
|
+
hlInfoOptions(client)
|
|
1458
|
+
).then(
|
|
1459
|
+
(state) => {
|
|
1460
|
+
const current = this.unifiedSummaryByUser.get(key)
|
|
1461
|
+
if (current === undefined) {
|
|
1462
|
+
return
|
|
1463
|
+
}
|
|
1464
|
+
current.availableMarginPending = false
|
|
1465
|
+
current.availableMargin = availableAfterMaintenance(state, quoteAssetId)
|
|
1466
|
+
this.emitUnifiedSummary(key)
|
|
1467
|
+
},
|
|
1468
|
+
(error) => {
|
|
1469
|
+
const current = this.unifiedSummaryByUser.get(key)
|
|
1470
|
+
if (current !== undefined) {
|
|
1471
|
+
current.availableMarginPending = false
|
|
1472
|
+
}
|
|
1473
|
+
wsLog.handlerFailure(this.providerKey, error)
|
|
1474
|
+
}
|
|
1475
|
+
)
|
|
1476
|
+
}
|
|
1377
1477
|
}
|
|
1378
1478
|
|
|
1379
1479
|
const isObject = (v: unknown): v is Record<string, unknown> =>
|
|
@@ -1599,6 +1699,13 @@ function isValidHlFrame(channel: string, data: unknown): boolean {
|
|
|
1599
1699
|
isObject(data.spotState) &&
|
|
1600
1700
|
Array.isArray(data.spotState.balances)
|
|
1601
1701
|
)
|
|
1702
|
+
case 'activeAssetData':
|
|
1703
|
+
return (
|
|
1704
|
+
typeof data.user === 'string' &&
|
|
1705
|
+
typeof data.coin === 'string' &&
|
|
1706
|
+
Array.isArray(data.availableToTrade) &&
|
|
1707
|
+
data.availableToTrade.length === 2
|
|
1708
|
+
)
|
|
1602
1709
|
default:
|
|
1603
1710
|
return true
|
|
1604
1711
|
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export type DecodeChainMode = 'every' | 'latest';
|
|
2
|
-
export declare class DecodeChain {
|
|
3
|
-
private readonly mode;
|
|
4
|
-
private readonly onError;
|
|
5
|
-
private tail;
|
|
6
|
-
private queued;
|
|
7
|
-
constructor(mode: DecodeChainMode, onError: (error: unknown) => void);
|
|
8
|
-
push(decode: () => Promise<void>): void;
|
|
9
|
-
reset(): void;
|
|
10
|
-
}
|
|
11
|
-
//# sourceMappingURL=decodeChain.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"decodeChain.d.ts","sourceRoot":"","sources":["../../../src/websocket/decodeChain.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,QAAQ,CAAA;AAQhD,qBAAa,WAAW;IAKpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAL1B,OAAO,CAAC,IAAI,CAAmC;IAC/C,OAAO,CAAC,MAAM,CAAmC;gBAG9B,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI;IAGpD,IAAI,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAwBvC,KAAK,IAAI,IAAI;CAId"}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DecodeChain = void 0;
|
|
4
|
-
class DecodeChain {
|
|
5
|
-
mode;
|
|
6
|
-
onError;
|
|
7
|
-
tail = Promise.resolve();
|
|
8
|
-
queued;
|
|
9
|
-
constructor(mode, onError) {
|
|
10
|
-
this.mode = mode;
|
|
11
|
-
this.onError = onError;
|
|
12
|
-
}
|
|
13
|
-
push(decode) {
|
|
14
|
-
if (this.mode === 'every') {
|
|
15
|
-
this.tail = this.tail.then(decode).catch(this.onError);
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
const drainScheduled = this.queued !== undefined;
|
|
19
|
-
this.queued = decode;
|
|
20
|
-
if (drainScheduled) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
this.tail = this.tail
|
|
24
|
-
.then(() => {
|
|
25
|
-
const next = this.queued;
|
|
26
|
-
this.queued = undefined;
|
|
27
|
-
return next?.();
|
|
28
|
-
})
|
|
29
|
-
.catch(this.onError);
|
|
30
|
-
}
|
|
31
|
-
reset() {
|
|
32
|
-
this.tail = Promise.resolve();
|
|
33
|
-
this.queued = undefined;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
exports.DecodeChain = DecodeChain;
|
|
37
|
-
//# sourceMappingURL=decodeChain.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"decodeChain.js","sourceRoot":"","sources":["../../../src/websocket/decodeChain.ts"],"names":[],"mappings":";;;AAgBA,MAAa,WAAW;IAKH;IACA;IALX,IAAI,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAA;IACvC,MAAM,CAAmC;IAEjD,YACmB,IAAqB,EACrB,OAAiC;QADjC,SAAI,GAAJ,IAAI,CAAiB;QACrB,YAAO,GAAP,OAAO,CAA0B;IACjD,CAAC;IAEJ,IAAI,CAAC,MAA2B;QAC9B,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACtD,OAAM;QACR,CAAC;QACD,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,KAAK,SAAS,CAAA;QAChD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,cAAc,EAAE,CAAC;YACnB,OAAM;QACR,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI;aAClB,IAAI,CAAC,GAAG,EAAE;YACT,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAA;YACxB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAA;YACvB,OAAO,IAAI,EAAE,EAAE,CAAA;QACjB,CAAC,CAAC;aACD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACxB,CAAC;IAOD,KAAK;QACH,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAA;QAC7B,IAAI,CAAC,MAAM,GAAG,SAAS,CAAA;IACzB,CAAC;CACF;AArCD,kCAqCC"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Frame semantics of a {@link DecodeChain}:
|
|
3
|
-
* - `'every'`: every frame decodes and applies in arrival order — required for
|
|
4
|
-
* delta-carrying channels, where dropping a frame corrupts downstream state.
|
|
5
|
-
* - `'latest'`: frames queued behind an in-flight decode coalesce to the
|
|
6
|
-
* newest — for snapshot-like channels, where a newer frame supersedes
|
|
7
|
-
* anything still waiting.
|
|
8
|
-
*/
|
|
9
|
-
export type DecodeChainMode = 'every' | 'latest';
|
|
10
|
-
/**
|
|
11
|
-
* Serializes async WS frame decodes so results apply in arrival order.
|
|
12
|
-
* In `'latest'` mode a backlog (e.g. queued behind a main-thread stall)
|
|
13
|
-
* collapses to its newest frame instead of replaying every stale decode.
|
|
14
|
-
* Decode failures are reported to `onError` and never break the chain.
|
|
15
|
-
*/
|
|
16
|
-
export declare class DecodeChain {
|
|
17
|
-
private readonly mode;
|
|
18
|
-
private readonly onError;
|
|
19
|
-
private tail;
|
|
20
|
-
private queued;
|
|
21
|
-
constructor(mode: DecodeChainMode, onError: (error: unknown) => void);
|
|
22
|
-
push(decode: () => Promise<void>): void;
|
|
23
|
-
/**
|
|
24
|
-
* Detach on connection teardown: drops the queued latest-mode decode and
|
|
25
|
-
* starts subsequent pushes on a fresh chain. A decode already in flight
|
|
26
|
-
* still settles.
|
|
27
|
-
*/
|
|
28
|
-
reset(): void;
|
|
29
|
-
}
|
|
30
|
-
//# sourceMappingURL=decodeChain.d.ts.map
|