@lifi/perps-sdk 0.0.0-preview-2edcdb1 → 0.0.0-preview-5111896
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/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/cjs/services/resolveSubscribeQuote.js +33 -19
- package/dist/cjs/services/resolveSubscribeQuote.js.map +1 -1
- package/dist/cjs/transport/fetchWithRetry.d.ts +0 -1
- package/dist/cjs/transport/fetchWithRetry.d.ts.map +1 -1
- package/dist/cjs/transport/fetchWithRetry.js +1 -8
- package/dist/cjs/transport/fetchWithRetry.js.map +1 -1
- package/dist/cjs/transport/request.d.ts.map +1 -1
- package/dist/cjs/transport/request.js +0 -3
- package/dist/cjs/transport/request.js.map +1 -1
- package/dist/cjs/utils/sleep.d.ts +1 -1
- package/dist/cjs/utils/sleep.d.ts.map +1 -1
- package/dist/cjs/utils/sleep.js +1 -16
- package/dist/cjs/utils/sleep.js.map +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/websocket/PerpsWsClient.d.ts +2 -0
- package/dist/cjs/websocket/PerpsWsClient.d.ts.map +1 -1
- package/dist/cjs/websocket/PerpsWsClient.js +9 -0
- package/dist/cjs/websocket/PerpsWsClient.js.map +1 -1
- package/dist/cjs/websocket/WsProviderBase.d.ts.map +1 -1
- package/dist/cjs/websocket/WsProviderBase.js +4 -1
- package/dist/cjs/websocket/WsProviderBase.js.map +1 -1
- package/dist/esm/services/resolveSubscribeQuote.d.ts +9 -8
- package/dist/esm/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/esm/services/resolveSubscribeQuote.js +44 -27
- package/dist/esm/services/resolveSubscribeQuote.js.map +1 -1
- package/dist/esm/transport/fetchWithRetry.d.ts +1 -11
- package/dist/esm/transport/fetchWithRetry.d.ts.map +1 -1
- package/dist/esm/transport/fetchWithRetry.js +2 -17
- package/dist/esm/transport/fetchWithRetry.js.map +1 -1
- package/dist/esm/transport/request.d.ts.map +1 -1
- package/dist/esm/transport/request.js +1 -4
- package/dist/esm/transport/request.js.map +1 -1
- package/dist/esm/utils/sleep.d.ts +2 -3
- package/dist/esm/utils/sleep.d.ts.map +1 -1
- package/dist/esm/utils/sleep.js +2 -18
- package/dist/esm/utils/sleep.js.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/websocket/PerpsWsClient.d.ts +5 -0
- package/dist/esm/websocket/PerpsWsClient.d.ts.map +1 -1
- package/dist/esm/websocket/PerpsWsClient.js +12 -0
- package/dist/esm/websocket/PerpsWsClient.js.map +1 -1
- package/dist/esm/websocket/WsProviderBase.d.ts.map +1 -1
- package/dist/esm/websocket/WsProviderBase.js +9 -1
- package/dist/esm/websocket/WsProviderBase.js.map +1 -1
- package/dist/types/services/resolveSubscribeQuote.d.ts +9 -8
- package/dist/types/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/types/transport/fetchWithRetry.d.ts +1 -11
- package/dist/types/transport/fetchWithRetry.d.ts.map +1 -1
- package/dist/types/transport/request.d.ts.map +1 -1
- package/dist/types/utils/sleep.d.ts +2 -3
- package/dist/types/utils/sleep.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/websocket/PerpsWsClient.d.ts +5 -0
- package/dist/types/websocket/PerpsWsClient.d.ts.map +1 -1
- package/dist/types/websocket/WsProviderBase.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/services/resolveSubscribeQuote.ts +56 -28
- package/src/transport/fetchWithRetry.ts +2 -18
- package/src/transport/request.ts +1 -5
- package/src/utils/sleep.ts +3 -19
- package/src/version.ts +1 -1
- package/src/websocket/PerpsWsClient.ts +17 -0
- package/src/websocket/WsProviderBase.ts +9 -1
|
@@ -12,25 +12,12 @@ export interface FetchWithRetryOptions {
|
|
|
12
12
|
signal?: AbortSignal
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* True when `error` is an `AbortSignal` cancellation (the native `fetch` abort
|
|
17
|
-
* rejection) rather than a genuine network failure. An abort is a deliberate
|
|
18
|
-
* caller action, so it is rethrown untouched instead of being retried.
|
|
19
|
-
*
|
|
20
|
-
* @internal
|
|
21
|
-
*/
|
|
22
|
-
export function isAbortError(error: unknown): boolean {
|
|
23
|
-
return error instanceof Error && error.name === 'AbortError'
|
|
24
|
-
}
|
|
25
|
-
|
|
26
15
|
/**
|
|
27
16
|
* Wrap `fetch` with policy-driven retry. Honors `Retry-After` (when present
|
|
28
17
|
* and `respectRetryAfter` is true), otherwise falls back to exponential
|
|
29
18
|
* backoff with full jitter, capped by `maxDelayMs`. Network errors (thrown
|
|
30
19
|
* `fetch` rejections) are treated as `retry-network` — same retry budget as
|
|
31
|
-
* 5xx.
|
|
32
|
-
* that fires during a between-retries backoff) reject with the abort reason
|
|
33
|
-
* without any further attempt.
|
|
20
|
+
* 5xx. An aborted signal short-circuits without further attempts.
|
|
34
21
|
*
|
|
35
22
|
* @public
|
|
36
23
|
*/
|
|
@@ -53,9 +40,6 @@ export async function fetchWithRetry(
|
|
|
53
40
|
try {
|
|
54
41
|
response = await fetchImpl(input, mergedInit)
|
|
55
42
|
} catch (error) {
|
|
56
|
-
if (isAbortError(error)) {
|
|
57
|
-
throw error
|
|
58
|
-
}
|
|
59
43
|
networkError = error
|
|
60
44
|
}
|
|
61
45
|
|
|
@@ -94,7 +78,7 @@ export async function fetchWithRetry(
|
|
|
94
78
|
|
|
95
79
|
const delayMs = computeDelay(policy, attempt, response)
|
|
96
80
|
if (delayMs > 0) {
|
|
97
|
-
await sleep(delayMs
|
|
81
|
+
await sleep(delayMs)
|
|
98
82
|
}
|
|
99
83
|
attempt++
|
|
100
84
|
}
|
package/src/transport/request.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { PerpsErrorCode } from '@lifi/perps-types'
|
|
|
3
3
|
import { PerpsError } from '../errors/PerpsError.js'
|
|
4
4
|
import type { PerpsBaseConfig, SDKRequestOptions } from '../types/config.js'
|
|
5
5
|
import { version } from '../version.js'
|
|
6
|
-
import { fetchWithRetry
|
|
6
|
+
import { fetchWithRetry } from './fetchWithRetry.js'
|
|
7
7
|
import {
|
|
8
8
|
LIFI_REQUEST_KEY,
|
|
9
9
|
LIFI_RETRY_DEFAULTS,
|
|
@@ -94,10 +94,6 @@ export async function request<T>(
|
|
|
94
94
|
throw error
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
if (isAbortError(error)) {
|
|
98
|
-
throw error
|
|
99
|
-
}
|
|
100
|
-
|
|
101
97
|
throw new PerpsError(
|
|
102
98
|
PerpsErrorCode.ServerError,
|
|
103
99
|
error instanceof Error ? error.message : 'Request failed'
|
package/src/utils/sleep.ts
CHANGED
|
@@ -1,23 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Resolve after `ms` milliseconds
|
|
3
|
-
* `signal` aborts first. Without a `signal` it always resolves.
|
|
2
|
+
* Resolve after `ms` milliseconds.
|
|
4
3
|
*
|
|
5
4
|
* @internal
|
|
6
5
|
*/
|
|
7
|
-
export const sleep = (ms: number
|
|
8
|
-
new Promise((resolve
|
|
9
|
-
if (signal?.aborted) {
|
|
10
|
-
reject(signal.reason ?? new DOMException('Aborted', 'AbortError'))
|
|
11
|
-
return
|
|
12
|
-
}
|
|
13
|
-
let timer: ReturnType<typeof setTimeout>
|
|
14
|
-
const onAbort = () => {
|
|
15
|
-
clearTimeout(timer)
|
|
16
|
-
reject(signal?.reason ?? new DOMException('Aborted', 'AbortError'))
|
|
17
|
-
}
|
|
18
|
-
timer = setTimeout(() => {
|
|
19
|
-
signal?.removeEventListener('abort', onAbort)
|
|
20
|
-
resolve()
|
|
21
|
-
}, ms)
|
|
22
|
-
signal?.addEventListener('abort', onAbort, { once: true })
|
|
23
|
-
})
|
|
6
|
+
export const sleep = (ms: number): Promise<void> =>
|
|
7
|
+
new Promise((resolve) => setTimeout(resolve, ms))
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const name = '@lifi/perps-sdk'
|
|
2
|
-
export const version = '0.0.0-preview-
|
|
2
|
+
export const version = '0.0.0-preview-5111896'
|
|
@@ -65,6 +65,7 @@ export class PerpsWsClient {
|
|
|
65
65
|
private readonly options: PerpsWsClientOptions
|
|
66
66
|
private providers = new Map<string, WsProvider>()
|
|
67
67
|
private initPromises = new Map<string, Promise<WsProvider>>()
|
|
68
|
+
private closed = false
|
|
68
69
|
|
|
69
70
|
constructor(client: PerpsSDKClient, options: PerpsWsClientOptions = {}) {
|
|
70
71
|
this.client = client
|
|
@@ -124,10 +125,14 @@ export class PerpsWsClient {
|
|
|
124
125
|
|
|
125
126
|
/**
|
|
126
127
|
* Close every open provider WS connection and drop all cached providers.
|
|
128
|
+
* Terminal: after `close()` the client is dead — `subscribe` and
|
|
129
|
+
* `subscribeQuote` reject, and any provider init still suspended mid-flight
|
|
130
|
+
* aborts without opening a socket. Create a new instance to subscribe again.
|
|
127
131
|
*
|
|
128
132
|
* @public
|
|
129
133
|
*/
|
|
130
134
|
close() {
|
|
135
|
+
this.closed = true
|
|
131
136
|
for (const p of this.providers.values()) {
|
|
132
137
|
p.close()
|
|
133
138
|
}
|
|
@@ -145,7 +150,18 @@ export class PerpsWsClient {
|
|
|
145
150
|
this.providers.get(provider)?.reconnect()
|
|
146
151
|
}
|
|
147
152
|
|
|
153
|
+
private assertOpen(): void {
|
|
154
|
+
if (this.closed) {
|
|
155
|
+
throw new PerpsError(
|
|
156
|
+
PerpsErrorCode.SDKError,
|
|
157
|
+
'PerpsWsClient is closed. Create a new instance to subscribe again.'
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
148
162
|
private async getOrCreateProvider(provider: string): Promise<WsProvider> {
|
|
163
|
+
this.assertOpen()
|
|
164
|
+
|
|
149
165
|
const existing = this.providers.get(provider)
|
|
150
166
|
if (existing) {
|
|
151
167
|
return existing
|
|
@@ -175,6 +191,7 @@ export class PerpsWsClient {
|
|
|
175
191
|
}
|
|
176
192
|
|
|
177
193
|
const { providers } = await getProviders(this.client)
|
|
194
|
+
this.assertOpen()
|
|
178
195
|
|
|
179
196
|
const providerInfo = providers.find((d) => d.key === provider)
|
|
180
197
|
if (!providerInfo?.wsUrl) {
|
|
@@ -188,7 +188,15 @@ export abstract class WsProviderBase<TSub = unknown> implements WsProvider {
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
private async replaySubs(): Promise<void> {
|
|
191
|
-
|
|
191
|
+
// Snapshot at replay start, and re-check the live registry before each
|
|
192
|
+
// send. An async sendSubscribe (e.g. Lighter's auth-token fetch) suspends
|
|
193
|
+
// the loop; status is already 'connected' while open listeners run, so a
|
|
194
|
+
// subscribe landing mid-replay is sent inline by registerSub — it must not
|
|
195
|
+
// be revisited here, and an entry unregistered mid-replay must be skipped.
|
|
196
|
+
for (const [key, state] of [...this.wireSubs]) {
|
|
197
|
+
if (this.wireSubs.get(key) !== state) {
|
|
198
|
+
continue
|
|
199
|
+
}
|
|
192
200
|
// Isolate each resubscribe: a send can reject (e.g. an auth-token fetch
|
|
193
201
|
// after reconnect), and one sub's failure must not abort the rest of
|
|
194
202
|
// the loop or escape as an unhandled rejection.
|