@lifi/perps-sdk 19.0.0 → 20.1.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.
Files changed (209) hide show
  1. package/README.md +35 -5
  2. package/dist/cjs/client/PerpsClient.d.ts +1 -1
  3. package/dist/cjs/client/PerpsClient.d.ts.map +1 -1
  4. package/dist/cjs/client/PerpsClient.js +4 -1
  5. package/dist/cjs/client/PerpsClient.js.map +1 -1
  6. package/dist/cjs/client/createPerpsClient.d.ts +1 -6
  7. package/dist/cjs/client/createPerpsClient.d.ts.map +1 -1
  8. package/dist/cjs/client/createPerpsClient.js +1 -14
  9. package/dist/cjs/client/createPerpsClient.js.map +1 -1
  10. package/dist/cjs/index.d.ts +6 -3
  11. package/dist/cjs/index.d.ts.map +1 -1
  12. package/dist/cjs/index.js +15 -3
  13. package/dist/cjs/index.js.map +1 -1
  14. package/dist/cjs/registry/assetRegistry.d.ts +2 -1
  15. package/dist/cjs/registry/assetRegistry.d.ts.map +1 -1
  16. package/dist/cjs/registry/assetRegistry.js +4 -2
  17. package/dist/cjs/registry/assetRegistry.js.map +1 -1
  18. package/dist/cjs/registry/marketRegistry.d.ts +2 -1
  19. package/dist/cjs/registry/marketRegistry.d.ts.map +1 -1
  20. package/dist/cjs/registry/marketRegistry.js +4 -2
  21. package/dist/cjs/registry/marketRegistry.js.map +1 -1
  22. package/dist/cjs/registry/referenceDataRegistry.d.ts +5 -1
  23. package/dist/cjs/registry/referenceDataRegistry.d.ts.map +1 -1
  24. package/dist/cjs/registry/referenceDataRegistry.js +65 -5
  25. package/dist/cjs/registry/referenceDataRegistry.js.map +1 -1
  26. package/dist/cjs/services/getOhlcv.d.ts.map +1 -1
  27. package/dist/cjs/services/getOhlcv.js.map +1 -1
  28. package/dist/cjs/transport/request.d.ts +1 -0
  29. package/dist/cjs/transport/request.d.ts.map +1 -1
  30. package/dist/cjs/transport/request.js +6 -2
  31. package/dist/cjs/transport/request.js.map +1 -1
  32. package/dist/cjs/types/api.d.ts +3 -4
  33. package/dist/cjs/types/api.d.ts.map +1 -1
  34. package/dist/cjs/types/config.d.ts +0 -9
  35. package/dist/cjs/types/config.d.ts.map +1 -1
  36. package/dist/cjs/types/provider.d.ts +1 -1
  37. package/dist/cjs/types/provider.d.ts.map +1 -1
  38. package/dist/cjs/types/withdrawal.d.ts +4 -2
  39. package/dist/cjs/types/withdrawal.d.ts.map +1 -1
  40. package/dist/cjs/utils/calculations.d.ts.map +1 -1
  41. package/dist/cjs/utils/calculations.js +107 -38
  42. package/dist/cjs/utils/calculations.js.map +1 -1
  43. package/dist/cjs/utils/decimal.d.ts +5 -0
  44. package/dist/cjs/utils/decimal.d.ts.map +1 -0
  45. package/dist/cjs/utils/decimal.js +17 -0
  46. package/dist/cjs/utils/decimal.js.map +1 -0
  47. package/dist/cjs/utils/math.d.ts +4 -0
  48. package/dist/cjs/utils/math.d.ts.map +1 -0
  49. package/dist/cjs/utils/math.js +8 -0
  50. package/dist/cjs/utils/math.js.map +1 -0
  51. package/dist/cjs/utils/orderEntry.d.ts +6 -0
  52. package/dist/cjs/utils/orderEntry.d.ts.map +1 -0
  53. package/dist/cjs/utils/orderEntry.js +20 -0
  54. package/dist/cjs/utils/orderEntry.js.map +1 -0
  55. package/dist/cjs/utils/parse.d.ts +1 -0
  56. package/dist/cjs/utils/parse.d.ts.map +1 -1
  57. package/dist/cjs/utils/parse.js +15 -0
  58. package/dist/cjs/utils/parse.js.map +1 -1
  59. package/dist/cjs/utils/positionMath.d.ts +5 -0
  60. package/dist/cjs/utils/positionMath.d.ts.map +1 -1
  61. package/dist/cjs/utils/positionMath.js +53 -6
  62. package/dist/cjs/utils/positionMath.js.map +1 -1
  63. package/dist/cjs/version.d.ts +1 -1
  64. package/dist/cjs/version.js +1 -1
  65. package/dist/cjs/websocket/PerpsWsClient.d.ts +0 -1
  66. package/dist/cjs/websocket/PerpsWsClient.d.ts.map +1 -1
  67. package/dist/cjs/websocket/PerpsWsClient.js +0 -7
  68. package/dist/cjs/websocket/PerpsWsClient.js.map +1 -1
  69. package/dist/cjs/websocket/WsProviderBase.d.ts.map +1 -1
  70. package/dist/cjs/websocket/WsProviderBase.js +11 -3
  71. package/dist/cjs/websocket/WsProviderBase.js.map +1 -1
  72. package/dist/esm/client/PerpsClient.d.ts +8 -7
  73. package/dist/esm/client/PerpsClient.d.ts.map +1 -1
  74. package/dist/esm/client/PerpsClient.js +11 -7
  75. package/dist/esm/client/PerpsClient.js.map +1 -1
  76. package/dist/esm/client/createPerpsClient.d.ts +1 -12
  77. package/dist/esm/client/createPerpsClient.d.ts.map +1 -1
  78. package/dist/esm/client/createPerpsClient.js +1 -19
  79. package/dist/esm/client/createPerpsClient.js.map +1 -1
  80. package/dist/esm/client/requireProvider.d.ts +1 -1
  81. package/dist/esm/client/requireProvider.js +1 -1
  82. package/dist/esm/index.d.ts +6 -3
  83. package/dist/esm/index.d.ts.map +1 -1
  84. package/dist/esm/index.js +5 -2
  85. package/dist/esm/index.js.map +1 -1
  86. package/dist/esm/registry/assetRegistry.d.ts +2 -1
  87. package/dist/esm/registry/assetRegistry.d.ts.map +1 -1
  88. package/dist/esm/registry/assetRegistry.js +4 -2
  89. package/dist/esm/registry/assetRegistry.js.map +1 -1
  90. package/dist/esm/registry/marketRegistry.d.ts +2 -1
  91. package/dist/esm/registry/marketRegistry.d.ts.map +1 -1
  92. package/dist/esm/registry/marketRegistry.js +4 -2
  93. package/dist/esm/registry/marketRegistry.js.map +1 -1
  94. package/dist/esm/registry/referenceDataRegistry.d.ts +6 -6
  95. package/dist/esm/registry/referenceDataRegistry.d.ts.map +1 -1
  96. package/dist/esm/registry/referenceDataRegistry.js +68 -10
  97. package/dist/esm/registry/referenceDataRegistry.js.map +1 -1
  98. package/dist/esm/services/getOhlcv.d.ts +1 -0
  99. package/dist/esm/services/getOhlcv.d.ts.map +1 -1
  100. package/dist/esm/services/getOhlcv.js.map +1 -1
  101. package/dist/esm/transport/request.d.ts +2 -0
  102. package/dist/esm/transport/request.d.ts.map +1 -1
  103. package/dist/esm/transport/request.js +6 -2
  104. package/dist/esm/transport/request.js.map +1 -1
  105. package/dist/esm/types/api.d.ts +8 -22
  106. package/dist/esm/types/api.d.ts.map +1 -1
  107. package/dist/esm/types/config.d.ts +0 -27
  108. package/dist/esm/types/config.d.ts.map +1 -1
  109. package/dist/esm/types/provider.d.ts +7 -6
  110. package/dist/esm/types/provider.d.ts.map +1 -1
  111. package/dist/esm/types/withdrawal.d.ts +24 -15
  112. package/dist/esm/types/withdrawal.d.ts.map +1 -1
  113. package/dist/esm/utils/calculations.d.ts +3 -2
  114. package/dist/esm/utils/calculations.d.ts.map +1 -1
  115. package/dist/esm/utils/calculations.js +109 -39
  116. package/dist/esm/utils/calculations.js.map +1 -1
  117. package/dist/esm/utils/decimal.d.ts +14 -0
  118. package/dist/esm/utils/decimal.d.ts.map +1 -0
  119. package/dist/esm/utils/decimal.js +19 -0
  120. package/dist/esm/utils/decimal.js.map +1 -0
  121. package/dist/esm/utils/math.d.ts +6 -0
  122. package/dist/esm/utils/math.d.ts.map +1 -0
  123. package/dist/esm/utils/math.js +5 -0
  124. package/dist/esm/utils/math.js.map +1 -0
  125. package/dist/esm/utils/orderEntry.d.ts +26 -0
  126. package/dist/esm/utils/orderEntry.d.ts.map +1 -0
  127. package/dist/esm/utils/orderEntry.js +34 -0
  128. package/dist/esm/utils/orderEntry.js.map +1 -0
  129. package/dist/esm/utils/parse.d.ts +7 -0
  130. package/dist/esm/utils/parse.d.ts.map +1 -1
  131. package/dist/esm/utils/parse.js +20 -0
  132. package/dist/esm/utils/parse.js.map +1 -1
  133. package/dist/esm/utils/positionMath.d.ts +13 -0
  134. package/dist/esm/utils/positionMath.d.ts.map +1 -1
  135. package/dist/esm/utils/positionMath.js +60 -6
  136. package/dist/esm/utils/positionMath.js.map +1 -1
  137. package/dist/esm/version.d.ts +1 -1
  138. package/dist/esm/version.js +1 -1
  139. package/dist/esm/websocket/PerpsWsClient.d.ts +0 -7
  140. package/dist/esm/websocket/PerpsWsClient.d.ts.map +1 -1
  141. package/dist/esm/websocket/PerpsWsClient.js +0 -7
  142. package/dist/esm/websocket/PerpsWsClient.js.map +1 -1
  143. package/dist/esm/websocket/WsProviderBase.d.ts.map +1 -1
  144. package/dist/esm/websocket/WsProviderBase.js +11 -3
  145. package/dist/esm/websocket/WsProviderBase.js.map +1 -1
  146. package/dist/types/client/PerpsClient.d.ts +8 -7
  147. package/dist/types/client/PerpsClient.d.ts.map +1 -1
  148. package/dist/types/client/createPerpsClient.d.ts +1 -12
  149. package/dist/types/client/createPerpsClient.d.ts.map +1 -1
  150. package/dist/types/client/requireProvider.d.ts +1 -1
  151. package/dist/types/index.d.ts +6 -3
  152. package/dist/types/index.d.ts.map +1 -1
  153. package/dist/types/registry/assetRegistry.d.ts +2 -1
  154. package/dist/types/registry/assetRegistry.d.ts.map +1 -1
  155. package/dist/types/registry/marketRegistry.d.ts +2 -1
  156. package/dist/types/registry/marketRegistry.d.ts.map +1 -1
  157. package/dist/types/registry/referenceDataRegistry.d.ts +6 -6
  158. package/dist/types/registry/referenceDataRegistry.d.ts.map +1 -1
  159. package/dist/types/services/getOhlcv.d.ts +1 -0
  160. package/dist/types/services/getOhlcv.d.ts.map +1 -1
  161. package/dist/types/transport/request.d.ts +2 -0
  162. package/dist/types/transport/request.d.ts.map +1 -1
  163. package/dist/types/types/api.d.ts +8 -22
  164. package/dist/types/types/api.d.ts.map +1 -1
  165. package/dist/types/types/config.d.ts +0 -27
  166. package/dist/types/types/config.d.ts.map +1 -1
  167. package/dist/types/types/provider.d.ts +7 -6
  168. package/dist/types/types/provider.d.ts.map +1 -1
  169. package/dist/types/types/withdrawal.d.ts +24 -15
  170. package/dist/types/types/withdrawal.d.ts.map +1 -1
  171. package/dist/types/utils/calculations.d.ts +3 -2
  172. package/dist/types/utils/calculations.d.ts.map +1 -1
  173. package/dist/types/utils/decimal.d.ts +14 -0
  174. package/dist/types/utils/decimal.d.ts.map +1 -0
  175. package/dist/types/utils/math.d.ts +6 -0
  176. package/dist/types/utils/math.d.ts.map +1 -0
  177. package/dist/types/utils/orderEntry.d.ts +26 -0
  178. package/dist/types/utils/orderEntry.d.ts.map +1 -0
  179. package/dist/types/utils/parse.d.ts +7 -0
  180. package/dist/types/utils/parse.d.ts.map +1 -1
  181. package/dist/types/utils/positionMath.d.ts +13 -0
  182. package/dist/types/utils/positionMath.d.ts.map +1 -1
  183. package/dist/types/version.d.ts +1 -1
  184. package/dist/types/websocket/PerpsWsClient.d.ts +0 -7
  185. package/dist/types/websocket/PerpsWsClient.d.ts.map +1 -1
  186. package/dist/types/websocket/WsProviderBase.d.ts.map +1 -1
  187. package/package.json +2 -2
  188. package/src/client/PerpsClient.ts +12 -8
  189. package/src/client/createPerpsClient.ts +4 -32
  190. package/src/client/requireProvider.ts +1 -1
  191. package/src/index.ts +10 -4
  192. package/src/registry/assetRegistry.ts +7 -5
  193. package/src/registry/marketRegistry.ts +7 -5
  194. package/src/registry/referenceDataRegistry.ts +89 -11
  195. package/src/services/getOhlcv.ts +1 -0
  196. package/src/transport/request.ts +12 -2
  197. package/src/types/api.ts +8 -26
  198. package/src/types/config.ts +0 -30
  199. package/src/types/provider.ts +8 -7
  200. package/src/types/withdrawal.ts +24 -15
  201. package/src/utils/calculations.ts +114 -43
  202. package/src/utils/decimal.ts +21 -0
  203. package/src/utils/math.ts +7 -0
  204. package/src/utils/orderEntry.ts +38 -0
  205. package/src/utils/parse.ts +25 -0
  206. package/src/utils/positionMath.ts +66 -6
  207. package/src/version.ts +1 -1
  208. package/src/websocket/PerpsWsClient.ts +0 -19
  209. package/src/websocket/WsProviderBase.ts +11 -3
@@ -0,0 +1,7 @@
1
+ import type Big from 'big.js'
2
+
3
+ /** The larger of two Big values, as `Math.max` for numbers. */
4
+ export const maxOf = (a: Big, b: Big): Big => (a.gt(b) ? a : b)
5
+
6
+ /** The smaller of two Big values, as `Math.min` for numbers. */
7
+ export const minOf = (a: Big, b: Big): Big => (a.lt(b) ? a : b)
@@ -0,0 +1,38 @@
1
+ import type Big from 'big.js'
2
+ import { TruncBig } from './decimal.js'
3
+
4
+ /**
5
+ * Base size the given margin buys at `leverage`: size = margin × leverage ÷ price.
6
+ * Truncates, so `size × price` never exceeds `margin × leverage`.
7
+ * @public
8
+ */
9
+ export function sizeFromMargin(margin: Big, leverage: number, price: Big): Big {
10
+ return new TruncBig(margin).times(leverage).div(price)
11
+ }
12
+
13
+ /**
14
+ * Margin that holds the given base size at `leverage`: margin = size × price ÷ leverage.
15
+ * Truncates, so `margin × leverage` never exceeds `size × price`.
16
+ * @public
17
+ */
18
+ export function marginFromSize(size: Big, leverage: number, price: Big): Big {
19
+ return new TruncBig(size).times(price).div(leverage)
20
+ }
21
+
22
+ /**
23
+ * Base size for a notional: size = notional ÷ price.
24
+ * Truncates, so `size × price` never exceeds the notional.
25
+ * @public
26
+ */
27
+ export function sizeFromNotional(notionalUsd: Big, price: Big): Big {
28
+ return new TruncBig(notionalUsd).div(price)
29
+ }
30
+
31
+ /**
32
+ * Margin for a notional at `leverage`: margin = notional ÷ leverage.
33
+ * Truncates, so `margin × leverage` never exceeds the notional.
34
+ * @public
35
+ */
36
+ export function marginFromNotional(notionalUsd: Big, leverage: number): Big {
37
+ return new TruncBig(notionalUsd).div(leverage)
38
+ }
@@ -27,3 +27,28 @@ export function stringToFloat(value: string): number {
27
27
  }
28
28
  return parseFloat(cleaned)
29
29
  }
30
+
31
+ const FORMATTED_NUMBER =
32
+ /^(?:[+-]\s*)?(?:\$\s*)?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?(?:\s*(?:%|USD))?$/i
33
+
34
+ /**
35
+ * Parse an optional decimal field, with the same formatting tolerance as {@link stringToFloat}.
36
+ * Gives back `undefined` for a missing, malformed or non-finite value, and `0` for an empty string.
37
+ *
38
+ * @public
39
+ */
40
+ export function parseDecimal(
41
+ value: string | null | undefined
42
+ ): number | undefined {
43
+ if (value == null) {
44
+ return undefined
45
+ }
46
+ if (value.trim() === '') {
47
+ return stringToFloat(value)
48
+ }
49
+ if (!FORMATTED_NUMBER.test(value.trim())) {
50
+ return undefined
51
+ }
52
+ const parsed = stringToFloat(value)
53
+ return Number.isFinite(parsed) ? parsed : undefined
54
+ }
@@ -6,6 +6,8 @@
6
6
  * always non-negative magnitudes; direction is carried by `isLong`.
7
7
  */
8
8
 
9
+ import { areFinite, DivBig } from './decimal.js'
10
+
9
11
  /**
10
12
  * Direction sign for a position.
11
13
  *
@@ -50,8 +52,39 @@ export function estimateIsolatedLiquidationPrice(params: {
50
52
  if (denominator === 0) {
51
53
  return undefined
52
54
  }
53
- const marginAvailable = entryPrice * (1 / leverage - maintenanceMarginRate)
54
- return entryPrice - (side * marginAvailable) / denominator
55
+ if (!areFinite(entryPrice, leverage, maintenanceMarginRate)) {
56
+ return Number.NaN
57
+ }
58
+ const mmr = new DivBig(maintenanceMarginRate)
59
+ const marginAvailable = new DivBig(1)
60
+ .div(leverage)
61
+ .minus(mmr)
62
+ .times(entryPrice)
63
+ return new DivBig(entryPrice)
64
+ .minus(marginAvailable.times(side).div(mmr.times(-side).plus(1)))
65
+ .toNumber()
66
+ }
67
+
68
+ /**
69
+ * Whether an isolated position with this liquidation price is already past
70
+ * liquidation at `currentPrice`: a long liquidates when the price falls to its
71
+ * liquidation level, a short when it rises to it. A non-positive price on
72
+ * either side counts as unknown, so the result is `false`.
73
+ *
74
+ * @public
75
+ */
76
+ export function wouldImmediatelyLiquidate(params: {
77
+ liquidationPrice: number
78
+ currentPrice: number
79
+ isLong: boolean
80
+ }): boolean {
81
+ const { liquidationPrice, currentPrice, isLong } = params
82
+ if (currentPrice <= 0 || liquidationPrice <= 0) {
83
+ return false
84
+ }
85
+ return isLong
86
+ ? liquidationPrice >= currentPrice
87
+ : liquidationPrice <= currentPrice
55
88
  }
56
89
 
57
90
  /**
@@ -84,7 +117,14 @@ export function predictAverageEntryPrice(params: {
84
117
  if (!Number.isFinite(currentEntry) || !Number.isFinite(fillPrice)) {
85
118
  return undefined
86
119
  }
87
- return (currentSize * currentEntry + addSize * fillPrice) / totalSize
120
+ if (!areFinite(currentSize, addSize)) {
121
+ return Number.NaN
122
+ }
123
+ return new DivBig(currentSize)
124
+ .times(currentEntry)
125
+ .plus(new DivBig(addSize).times(fillPrice))
126
+ .div(new DivBig(currentSize).plus(addSize))
127
+ .toNumber()
88
128
  }
89
129
 
90
130
  /**
@@ -109,7 +149,13 @@ export function predictNewLeverage(params: {
109
149
  if (totalMargin <= 0) {
110
150
  return undefined
111
151
  }
112
- return (currentNotional + addNotional) / totalMargin
152
+ if (!areFinite(currentNotional, currentMargin, addNotional, addMargin)) {
153
+ return Number.NaN
154
+ }
155
+ return new DivBig(currentNotional)
156
+ .plus(addNotional)
157
+ .div(new DivBig(currentMargin).plus(addMargin))
158
+ .toNumber()
113
159
  }
114
160
 
115
161
  /**
@@ -127,7 +173,14 @@ export function predictUnrealizedPnl(params: {
127
173
  isLong: boolean
128
174
  }): number {
129
175
  const { entryPrice, markPrice, size, isLong } = params
130
- return (markPrice - entryPrice) * size * directionSign(isLong)
176
+ if (!areFinite(entryPrice, markPrice, size)) {
177
+ return Number.NaN
178
+ }
179
+ return new DivBig(markPrice)
180
+ .minus(entryPrice)
181
+ .times(size)
182
+ .times(directionSign(isLong))
183
+ .toNumber()
131
184
  }
132
185
 
133
186
  /**
@@ -145,5 +198,12 @@ export function realizedPnlOnClose(params: {
145
198
  isLong: boolean
146
199
  }): number {
147
200
  const { entryPrice, closePrice, closeSize, isLong } = params
148
- return (closePrice - entryPrice) * closeSize * directionSign(isLong)
201
+ if (!areFinite(entryPrice, closePrice, closeSize)) {
202
+ return Number.NaN
203
+ }
204
+ return new DivBig(closePrice)
205
+ .minus(entryPrice)
206
+ .times(closeSize)
207
+ .times(directionSign(isLong))
208
+ .toNumber()
149
209
  }
package/src/version.ts CHANGED
@@ -10,4 +10,4 @@ export const name = '@lifi/perps-sdk'
10
10
  *
11
11
  * @public
12
12
  */
13
- export const version = '19.0.0'
13
+ export const version = '20.1.0'
@@ -20,13 +20,6 @@ export interface WsProviderFactoryParams {
20
20
  provider: string
21
21
  /** WS URL discovered from `/providers`. */
22
22
  wsUrl: string
23
- /**
24
- * Markets visible to this provider via `/providers`, optionally filtered
25
- * by the consumer's `createPerpsClient({ providers: { [key]: { markets } } })`
26
- * config. Each provider interprets these its own way — Hyperliquid uses
27
- * them to decide which sub-DEXes to subscribe to; Lighter ignores them.
28
- */
29
- markets: string[]
30
23
  /**
31
24
  * The SDK client. WS providers use it to call core services (e.g.
32
25
  * `getAssets` to source the wire-id ↔ display-symbol map) without
@@ -235,21 +228,9 @@ export class PerpsWsClient {
235
228
  throw new Error(`No WebSocket URL found for provider: ${provider}`)
236
229
  }
237
230
 
238
- const allMarkets = (providerInfo.categories ?? []) as Array<{
239
- id: string
240
- }>
241
- const providerConfig = this.client.config.providers?.[provider]
242
- const configuredMarkets = providerConfig?.markets
243
- const markets = (
244
- configuredMarkets
245
- ? allMarkets.filter((m) => configuredMarkets.includes(m.id))
246
- : allMarkets
247
- ).map((m) => m.id)
248
-
249
231
  const wsProvider = factory({
250
232
  provider,
251
233
  wsUrl: providerInfo.wsUrl,
252
- markets,
253
234
  client: this.client,
254
235
  })
255
236
  this.providers.set(provider, wsProvider)
@@ -199,7 +199,9 @@ export abstract class WsProviderBase<TSub = unknown> implements WsProvider {
199
199
  try {
200
200
  await this.sendSubscribe(state)
201
201
  } catch (err) {
202
- this.wireSubs.delete(key)
202
+ if (this.wireSubs.get(key) === state) {
203
+ this.wireSubs.delete(key)
204
+ }
203
205
  throw err
204
206
  }
205
207
  }
@@ -304,7 +306,11 @@ export abstract class WsProviderBase<TSub = unknown> implements WsProvider {
304
306
  try {
305
307
  const teardown = await opening
306
308
  const current = this.channels.get(key)
307
- if (current === undefined || current.listeners.size === 0) {
309
+ if (current !== entry) {
310
+ teardown()
311
+ return
312
+ }
313
+ if (current.listeners.size === 0) {
308
314
  // Every listener released while opening — unwind immediately.
309
315
  teardown()
310
316
  this.channels.delete(key)
@@ -315,7 +321,9 @@ export abstract class WsProviderBase<TSub = unknown> implements WsProvider {
315
321
  } catch (err) {
316
322
  // Open failed: drop the channel so all (concurrent) subscribers reject
317
323
  // cleanly and a later subscribe re-opens.
318
- this.channels.delete(key)
324
+ if (this.channels.get(key) === entry) {
325
+ this.channels.delete(key)
326
+ }
319
327
  throw err
320
328
  }
321
329
  }