@drift-labs/sdk 2.146.0-beta.1 → 2.146.0-beta.2
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/VERSION +1 -1
- package/lib/browser/accounts/webSocketProgramAccountSubscriberV2.d.ts +99 -7
- package/lib/browser/accounts/webSocketProgramAccountSubscriberV2.js +435 -144
- package/lib/browser/driftClient.js +19 -17
- package/lib/browser/driftClientConfig.d.ts +7 -2
- package/lib/browser/index.d.ts +4 -0
- package/lib/browser/index.js +9 -1
- package/lib/node/accounts/webSocketProgramAccountSubscriberV2.d.ts +99 -7
- package/lib/node/accounts/webSocketProgramAccountSubscriberV2.d.ts.map +1 -1
- package/lib/node/accounts/webSocketProgramAccountSubscriberV2.js +435 -144
- package/lib/node/driftClient.d.ts.map +1 -1
- package/lib/node/driftClient.js +19 -17
- package/lib/node/driftClientConfig.d.ts +7 -2
- package/lib/node/driftClientConfig.d.ts.map +1 -1
- package/lib/node/index.d.ts +4 -0
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +9 -1
- package/package.json +1 -1
- package/src/accounts/webSocketProgramAccountSubscriberV2.ts +566 -167
- package/src/driftClient.ts +7 -4
- package/src/driftClientConfig.ts +15 -8
- package/src/index.ts +4 -0
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.146.0-beta.
|
|
1
|
+
2.146.0-beta.2
|
|
@@ -3,17 +3,75 @@
|
|
|
3
3
|
import { BufferAndSlot, ProgramAccountSubscriber, ResubOpts } from './types';
|
|
4
4
|
import { Program } from '@coral-xyz/anchor';
|
|
5
5
|
import { Commitment, Context, MemcmpFilter, PublicKey } from '@solana/web3.js';
|
|
6
|
-
import { AccountInfoBase, AccountInfoWithBase58EncodedData, AccountInfoWithBase64EncodedData } from 'gill';
|
|
7
|
-
|
|
6
|
+
import { AccountInfoBase, AccountInfoWithBase58EncodedData, AccountInfoWithBase64EncodedData, Address } from 'gill';
|
|
7
|
+
/**
|
|
8
|
+
* WebSocketProgramAccountsSubscriberV2
|
|
9
|
+
*
|
|
10
|
+
* High-level overview
|
|
11
|
+
* - WebSocket-first subscriber for Solana program accounts that also layers in
|
|
12
|
+
* targeted polling to detect missed updates reliably.
|
|
13
|
+
* - Emits decoded account updates via the provided `onChange` callback.
|
|
14
|
+
* - Designed to focus extra work on the specific accounts the consumer cares
|
|
15
|
+
* about ("monitored accounts") while keeping baseline WS behavior for the
|
|
16
|
+
* full program subscription.
|
|
17
|
+
*
|
|
18
|
+
* Why polling if this is a WebSocket subscriber?
|
|
19
|
+
* - WS infra can stall, drop, or reorder notifications under network stress or
|
|
20
|
+
* provider hiccups. When that happens, critical account changes can be missed.
|
|
21
|
+
* - To mitigate this, the class accepts a set of accounts (provided via constructor) to monitor
|
|
22
|
+
* and uses light polling to verify whether a WS change was missed.
|
|
23
|
+
* - If polling detects a newer slot with different data than the last seen
|
|
24
|
+
* buffer, a centralized resubscription is triggered to restore a clean stream.
|
|
25
|
+
*
|
|
26
|
+
* Initial fetch (on subscribe)
|
|
27
|
+
* - On `subscribe()`, we first perform a single batched fetch of all monitored
|
|
28
|
+
* accounts ("initial monitor fetch").
|
|
29
|
+
* - Purpose: seed the internal `bufferAndSlotMap` and emit the latest state so
|
|
30
|
+
* consumers have up-to-date data immediately, even before WS events arrive.
|
|
31
|
+
* - This step does not decide resubscription; it only establishes ground truth.
|
|
32
|
+
*
|
|
33
|
+
* Continuous polling (only for monitored accounts)
|
|
34
|
+
* - After seeding, each monitored account is put into a monitoring cycle:
|
|
35
|
+
* 1) If no WS notification for an account is observed for `pollingIntervalMs`,
|
|
36
|
+
* we enqueue it for a batched fetch (buffered for a short window).
|
|
37
|
+
* 2) Once an account enters the "currently polling" set, a shared batch poll
|
|
38
|
+
* runs every `pollingIntervalMs` across all such accounts.
|
|
39
|
+
* 3) If WS notifications resume for an account, that account is removed from
|
|
40
|
+
* the polling set and returns to passive monitoring.
|
|
41
|
+
* - Polling compares the newly fetched buffer with the last stored buffer at a
|
|
42
|
+
* later slot. A difference indicates a missed update; we schedule a single
|
|
43
|
+
* resubscription (coalesced across accounts) to re-sync.
|
|
44
|
+
*
|
|
45
|
+
* Accounts the consumer cares about
|
|
46
|
+
* - Provide accounts up-front via the constructor `accountsToMonitor`, or add
|
|
47
|
+
* them dynamically with `addAccountToMonitor()` and remove with
|
|
48
|
+
* `removeAccountFromMonitor()`.
|
|
49
|
+
* - Only these accounts incur additional polling safeguards; other accounts are
|
|
50
|
+
* still processed from the WS stream normally.
|
|
51
|
+
*
|
|
52
|
+
* Resubscription strategy
|
|
53
|
+
* - Missed updates from any monitored account are coalesced and trigger a single
|
|
54
|
+
* resubscription after a short delay. This avoids rapid churn.
|
|
55
|
+
* - If `resubOpts.resubTimeoutMs` is set, an inactivity timer also performs a
|
|
56
|
+
* batch check of monitored accounts. If a missed update is found, the same
|
|
57
|
+
* centralized resubscription flow is used.
|
|
58
|
+
*
|
|
59
|
+
* Tuning knobs
|
|
60
|
+
* - `setPollingInterval(ms)`: adjust how often monitoring/polling runs
|
|
61
|
+
* (default 30s). Shorter = faster detection, higher RPC load.
|
|
62
|
+
* - Debounced immediate poll (~100ms): batches accounts added to polling right after inactivity.
|
|
63
|
+
* - Batch size for `getMultipleAccounts` is limited to 100, requests are chunked
|
|
64
|
+
* and processed concurrently.
|
|
65
|
+
*/
|
|
66
|
+
export declare class WebSocketProgramAccountsSubscriberV2<T> implements ProgramAccountSubscriber<T> {
|
|
8
67
|
subscriptionName: string;
|
|
9
68
|
accountDiscriminator: string;
|
|
10
|
-
bufferAndSlot?: BufferAndSlot;
|
|
11
69
|
bufferAndSlotMap: Map<string, BufferAndSlot>;
|
|
12
70
|
program: Program;
|
|
13
71
|
decodeBuffer: (accountName: string, ix: Buffer) => T;
|
|
14
72
|
onChange: (accountId: PublicKey, data: T, context: Context, buffer: Buffer) => void;
|
|
15
73
|
listenerId?: number;
|
|
16
|
-
resubOpts
|
|
74
|
+
resubOpts: ResubOpts;
|
|
17
75
|
isUnsubscribing: boolean;
|
|
18
76
|
timeoutId?: ReturnType<typeof setTimeout>;
|
|
19
77
|
options: {
|
|
@@ -30,24 +88,58 @@ export declare class WebSocketProgramAccountSubscriberV2<T> implements ProgramAc
|
|
|
30
88
|
private lastWsNotificationTime;
|
|
31
89
|
private accountsCurrentlyPolling;
|
|
32
90
|
private batchPollingTimeout?;
|
|
91
|
+
private debouncedImmediatePollTimeout?;
|
|
92
|
+
private debouncedImmediatePollMs;
|
|
93
|
+
private missedChangeDetected;
|
|
94
|
+
private resubscriptionTimeout?;
|
|
95
|
+
private accountsWithMissedUpdates;
|
|
33
96
|
constructor(subscriptionName: string, accountDiscriminator: string, program: Program, decodeBufferFn: (accountName: string, ix: Buffer) => T, options?: {
|
|
34
97
|
filters: MemcmpFilter[];
|
|
35
98
|
commitment?: Commitment;
|
|
36
99
|
}, resubOpts?: ResubOpts, accountsToMonitor?: PublicKey[]);
|
|
100
|
+
private handleNotificationLoop;
|
|
37
101
|
subscribe(onChange: (accountId: PublicKey, data: T, context: Context, buffer: Buffer) => void): Promise<void>;
|
|
38
102
|
protected setTimeout(): void;
|
|
39
103
|
handleRpcResponse(context: {
|
|
40
104
|
slot: bigint;
|
|
41
|
-
}, accountInfo?: AccountInfoBase & (AccountInfoWithBase58EncodedData | AccountInfoWithBase64EncodedData)): void;
|
|
105
|
+
}, accountId: Address, accountInfo?: AccountInfoBase & (AccountInfoWithBase58EncodedData | AccountInfoWithBase64EncodedData)['data']): void;
|
|
42
106
|
private startMonitoringForAccounts;
|
|
43
107
|
private startMonitoringForAccount;
|
|
44
|
-
private
|
|
108
|
+
private scheduleDebouncedImmediatePoll;
|
|
45
109
|
private startBatchPolling;
|
|
46
110
|
private pollAllAccounts;
|
|
47
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Fetches and populates all monitored accounts data without checking for missed changes
|
|
113
|
+
* This is used during initial subscription to populate data
|
|
114
|
+
*/
|
|
115
|
+
private fetchAndPopulateAllMonitoredAccounts;
|
|
116
|
+
/**
|
|
117
|
+
* Fetches all monitored accounts and checks for missed changes
|
|
118
|
+
* Returns true if a missed change was detected and resubscription is needed
|
|
119
|
+
*/
|
|
120
|
+
private fetchAllMonitoredAccounts;
|
|
121
|
+
private fetchAccountsBatch;
|
|
48
122
|
private clearPollingTimeouts;
|
|
123
|
+
/**
|
|
124
|
+
* Centralized resubscription handler that only resubscribes once after checking all accounts
|
|
125
|
+
*/
|
|
126
|
+
private handleResubscription;
|
|
127
|
+
/**
|
|
128
|
+
* Signal that a missed change was detected and schedule resubscription
|
|
129
|
+
*/
|
|
130
|
+
private signalMissedChange;
|
|
49
131
|
unsubscribe(onResub?: boolean): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Add an account to the monitored set.
|
|
134
|
+
* - Monitored accounts are subject to initial fetch and periodic batch polls
|
|
135
|
+
* if WS notifications are not observed within `pollingIntervalMs`.
|
|
136
|
+
*/
|
|
50
137
|
addAccountToMonitor(accountId: PublicKey): void;
|
|
51
138
|
removeAccountFromMonitor(accountId: PublicKey): void;
|
|
139
|
+
/**
|
|
140
|
+
* Set the monitoring/polling interval for monitored accounts.
|
|
141
|
+
* Shorter intervals detect missed updates sooner but increase RPC load.
|
|
142
|
+
*/
|
|
52
143
|
setPollingInterval(intervalMs: number): void;
|
|
144
|
+
private updateBufferAndHandleChange;
|
|
53
145
|
}
|