@jack-kernel/sdk 1.0.0 → 1.2.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.
- package/dist/cjs/index.js +125 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lifi/chain-map.js +39 -0
- package/dist/cjs/lifi/chain-map.js.map +1 -0
- package/dist/cjs/lifi/fallback.js +135 -0
- package/dist/cjs/lifi/fallback.js.map +1 -0
- package/dist/cjs/lifi/index.js +34 -0
- package/dist/cjs/lifi/index.js.map +1 -0
- package/dist/cjs/lifi/lifi-provider.js +496 -0
- package/dist/cjs/lifi/lifi-provider.js.map +1 -0
- package/dist/cjs/lifi/token-map.js +75 -0
- package/dist/cjs/lifi/token-map.js.map +1 -0
- package/dist/cjs/lifi/types.js +3 -0
- package/dist/cjs/lifi/types.js.map +1 -0
- package/dist/cjs/lifi/utils.js +45 -0
- package/dist/cjs/lifi/utils.js.map +1 -0
- package/dist/cjs/yellow/channel-state-manager.js +167 -0
- package/dist/cjs/yellow/channel-state-manager.js.map +1 -0
- package/dist/cjs/yellow/clear-node-connection.js +390 -0
- package/dist/cjs/yellow/clear-node-connection.js.map +1 -0
- package/dist/cjs/yellow/event-mapper.js +254 -0
- package/dist/cjs/yellow/event-mapper.js.map +1 -0
- package/dist/cjs/yellow/serialization.js +130 -0
- package/dist/cjs/yellow/serialization.js.map +1 -0
- package/dist/cjs/yellow/session-key-manager.js +308 -0
- package/dist/cjs/yellow/session-key-manager.js.map +1 -0
- package/dist/cjs/yellow/types.js +12 -0
- package/dist/cjs/yellow/types.js.map +1 -0
- package/dist/cjs/yellow/yellow-provider.js +1545 -0
- package/dist/cjs/yellow/yellow-provider.js.map +1 -0
- package/dist/esm/index.js +102 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lifi/chain-map.js +35 -0
- package/dist/esm/lifi/chain-map.js.map +1 -0
- package/dist/esm/lifi/fallback.js +128 -0
- package/dist/esm/lifi/fallback.js.map +1 -0
- package/dist/esm/lifi/index.js +19 -0
- package/dist/esm/lifi/index.js.map +1 -0
- package/dist/esm/lifi/lifi-provider.js +492 -0
- package/dist/esm/lifi/lifi-provider.js.map +1 -0
- package/dist/esm/lifi/token-map.js +71 -0
- package/dist/esm/lifi/token-map.js.map +1 -0
- package/dist/esm/lifi/types.js +2 -0
- package/dist/esm/lifi/types.js.map +1 -0
- package/dist/esm/lifi/utils.js +41 -0
- package/dist/esm/lifi/utils.js.map +1 -0
- package/dist/esm/yellow/channel-state-manager.js +163 -0
- package/dist/esm/yellow/channel-state-manager.js.map +1 -0
- package/dist/esm/yellow/clear-node-connection.js +385 -0
- package/dist/esm/yellow/clear-node-connection.js.map +1 -0
- package/dist/esm/yellow/event-mapper.js +248 -0
- package/dist/esm/yellow/event-mapper.js.map +1 -0
- package/dist/esm/yellow/serialization.js +125 -0
- package/dist/esm/yellow/serialization.js.map +1 -0
- package/dist/esm/yellow/session-key-manager.js +302 -0
- package/dist/esm/yellow/session-key-manager.js.map +1 -0
- package/dist/esm/yellow/types.js +11 -0
- package/dist/esm/yellow/types.js.map +1 -0
- package/dist/esm/yellow/yellow-provider.js +1538 -0
- package/dist/esm/yellow/yellow-provider.js.map +1 -0
- package/dist/types/index.d.ts +104 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lifi/chain-map.d.ts +27 -0
- package/dist/types/lifi/chain-map.d.ts.map +1 -0
- package/dist/types/lifi/fallback.d.ts +58 -0
- package/dist/types/lifi/fallback.d.ts.map +1 -0
- package/dist/types/lifi/index.d.ts +18 -0
- package/dist/types/lifi/index.d.ts.map +1 -0
- package/dist/types/lifi/lifi-provider.d.ts +133 -0
- package/dist/types/lifi/lifi-provider.d.ts.map +1 -0
- package/dist/types/lifi/token-map.d.ts +34 -0
- package/dist/types/lifi/token-map.d.ts.map +1 -0
- package/dist/types/lifi/types.d.ts +52 -0
- package/dist/types/lifi/types.d.ts.map +1 -0
- package/dist/types/lifi/utils.d.ts +29 -0
- package/dist/types/lifi/utils.d.ts.map +1 -0
- package/dist/types/yellow/channel-state-manager.d.ts +106 -0
- package/dist/types/yellow/channel-state-manager.d.ts.map +1 -0
- package/dist/types/yellow/clear-node-connection.d.ts +202 -0
- package/dist/types/yellow/clear-node-connection.d.ts.map +1 -0
- package/dist/types/yellow/event-mapper.d.ts +74 -0
- package/dist/types/yellow/event-mapper.d.ts.map +1 -0
- package/dist/types/yellow/serialization.d.ts +52 -0
- package/dist/types/yellow/serialization.d.ts.map +1 -0
- package/dist/types/yellow/session-key-manager.d.ts +179 -0
- package/dist/types/yellow/session-key-manager.d.ts.map +1 -0
- package/dist/types/yellow/types.d.ts +177 -0
- package/dist/types/yellow/types.d.ts.map +1 -0
- package/dist/types/yellow/yellow-provider.d.ts +303 -0
- package/dist/types/yellow/yellow-provider.d.ts.map +1 -0
- package/package.json +4 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Channel State Manager for Yellow Network Integration
|
|
3
|
+
*
|
|
4
|
+
* Tracks local channel state and provides on-chain query capabilities.
|
|
5
|
+
* Maintains a local cache of channel states from ClearNode messages and
|
|
6
|
+
* falls back to on-chain queries via viem PublicClient when the WebSocket
|
|
7
|
+
* is disconnected.
|
|
8
|
+
*
|
|
9
|
+
* Requirements: 7.1, 7.2, 7.3, 7.4
|
|
10
|
+
*/
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Custody Contract ABI (minimal)
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Minimal ABI for the custody contract's balance query function.
|
|
16
|
+
*
|
|
17
|
+
* The custody contract exposes a `getChannelBalances` function that returns
|
|
18
|
+
* the token balances held in a specific channel for the given token addresses.
|
|
19
|
+
*
|
|
20
|
+
* Function signature: getChannelBalances(bytes32 channelId, address[] tokens) → uint256[]
|
|
21
|
+
*/
|
|
22
|
+
const CUSTODY_BALANCE_ABI = [
|
|
23
|
+
{
|
|
24
|
+
name: 'getChannelBalances',
|
|
25
|
+
type: 'function',
|
|
26
|
+
stateMutability: 'view',
|
|
27
|
+
inputs: [
|
|
28
|
+
{ name: 'channelId', type: 'bytes32' },
|
|
29
|
+
{ name: 'tokens', type: 'address[]' },
|
|
30
|
+
],
|
|
31
|
+
outputs: [{ name: 'balances', type: 'uint256[]' }],
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// ChannelStateManager
|
|
36
|
+
// ============================================================================
|
|
37
|
+
/**
|
|
38
|
+
* Manages local channel state cache and provides on-chain query capabilities.
|
|
39
|
+
*
|
|
40
|
+
* The ChannelStateManager serves two purposes:
|
|
41
|
+
* 1. Maintains a local cache of channel states received from ClearNode messages,
|
|
42
|
+
* enabling fast lookups without network calls.
|
|
43
|
+
* 2. Provides on-chain balance queries via viem PublicClient for when the
|
|
44
|
+
* WebSocket connection is unavailable (Requirement 7.4) or when authoritative
|
|
45
|
+
* on-chain data is needed (Requirement 7.2).
|
|
46
|
+
*
|
|
47
|
+
* Requirements: 7.1, 7.2, 7.3, 7.4
|
|
48
|
+
*/
|
|
49
|
+
export class ChannelStateManager {
|
|
50
|
+
publicClient;
|
|
51
|
+
custodyAddress;
|
|
52
|
+
channels;
|
|
53
|
+
/**
|
|
54
|
+
* @param publicClient - viem PublicClient for on-chain balance queries
|
|
55
|
+
* @param custodyAddress - Address of the custody contract holding channel collateral
|
|
56
|
+
*/
|
|
57
|
+
constructor(publicClient, custodyAddress) {
|
|
58
|
+
this.publicClient = publicClient;
|
|
59
|
+
this.custodyAddress = custodyAddress;
|
|
60
|
+
this.channels = new Map();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Update the local cache with a channel state from a ClearNode response.
|
|
64
|
+
*
|
|
65
|
+
* This is called when the YellowProvider receives channel state updates
|
|
66
|
+
* from ClearNode messages (create, resize, close, or get_ledger_balances).
|
|
67
|
+
*
|
|
68
|
+
* Requirement 7.1: Maintain local channel state from ClearNode responses.
|
|
69
|
+
*
|
|
70
|
+
* @param channelId - The channel identifier
|
|
71
|
+
* @param state - The channel state to cache
|
|
72
|
+
*/
|
|
73
|
+
updateChannel(channelId, state) {
|
|
74
|
+
this.channels.set(channelId, state);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get a locally cached channel state by channel ID.
|
|
78
|
+
*
|
|
79
|
+
* Returns undefined if the channel is not in the local cache.
|
|
80
|
+
* For authoritative on-chain data, use queryOnChainBalances instead.
|
|
81
|
+
*
|
|
82
|
+
* Requirement 7.2: Query specific channel status by channel ID.
|
|
83
|
+
*
|
|
84
|
+
* @param channelId - The channel identifier
|
|
85
|
+
* @returns The cached channel state, or undefined if not found
|
|
86
|
+
*/
|
|
87
|
+
getChannel(channelId) {
|
|
88
|
+
return this.channels.get(channelId);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get all locally cached channel states.
|
|
92
|
+
*
|
|
93
|
+
* Returns a snapshot array of all channels currently in the cache.
|
|
94
|
+
* The returned array is a copy; modifications do not affect the cache.
|
|
95
|
+
*
|
|
96
|
+
* Requirement 7.1: Return list of channels with their statuses and allocations.
|
|
97
|
+
*
|
|
98
|
+
* @returns Array of all cached channel states
|
|
99
|
+
*/
|
|
100
|
+
getAllChannels() {
|
|
101
|
+
return Array.from(this.channels.values());
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Query on-chain channel balances from the custody contract.
|
|
105
|
+
*
|
|
106
|
+
* Uses viem PublicClient.readContract to call the custody contract's
|
|
107
|
+
* getChannelBalances function. This provides authoritative on-chain data
|
|
108
|
+
* and is used as a fallback when the ClearNode WebSocket is disconnected.
|
|
109
|
+
*
|
|
110
|
+
* Requirement 7.2: Query on-chain custody contract for channel balances.
|
|
111
|
+
* Requirement 7.4: Fall back to on-chain queries when WebSocket is disconnected.
|
|
112
|
+
*
|
|
113
|
+
* @param channelId - The channel identifier (bytes32 hex string)
|
|
114
|
+
* @param tokens - Array of token addresses to query balances for
|
|
115
|
+
* @returns Array of token balances as bigint values, one per token
|
|
116
|
+
* @throws Error if the on-chain query fails
|
|
117
|
+
*/
|
|
118
|
+
async queryOnChainBalances(channelId, tokens) {
|
|
119
|
+
try {
|
|
120
|
+
const balances = await this.publicClient.readContract({
|
|
121
|
+
address: this.custodyAddress,
|
|
122
|
+
abi: CUSTODY_BALANCE_ABI,
|
|
123
|
+
functionName: 'getChannelBalances',
|
|
124
|
+
args: [channelId, tokens],
|
|
125
|
+
});
|
|
126
|
+
return [...balances];
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
130
|
+
throw new Error(`Failed to query on-chain balances for channel ${channelId}: ${message}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Find an open (ACTIVE) channel for a given token address.
|
|
135
|
+
*
|
|
136
|
+
* Searches the local cache for a channel with status 'ACTIVE' that
|
|
137
|
+
* matches the specified token address. Returns the first match found.
|
|
138
|
+
*
|
|
139
|
+
* This is used by the YellowProvider to reuse existing channels
|
|
140
|
+
* when executing intents, avoiding unnecessary channel creation.
|
|
141
|
+
*
|
|
142
|
+
* @param token - The token address to find an open channel for
|
|
143
|
+
* @returns The first matching ACTIVE channel, or undefined if none found
|
|
144
|
+
*/
|
|
145
|
+
findOpenChannel(token) {
|
|
146
|
+
for (const channel of this.channels.values()) {
|
|
147
|
+
if (channel.status === 'ACTIVE' && channel.token === token) {
|
|
148
|
+
return channel;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Clear all cached channel states.
|
|
155
|
+
*
|
|
156
|
+
* This is typically called when the provider disconnects or when
|
|
157
|
+
* a full state refresh is needed.
|
|
158
|
+
*/
|
|
159
|
+
clear() {
|
|
160
|
+
this.channels.clear();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=channel-state-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-state-manager.js","sourceRoot":"","sources":["../../../src/yellow/channel-state-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,+EAA+E;AAC/E,iCAAiC;AACjC,+EAA+E;AAE/E;;;;;;;GAOG;AACH,MAAM,mBAAmB,GAAG;IAC1B;QACE,IAAI,EAAE,oBAAoB;QAC1B,IAAI,EAAE,UAAU;QAChB,eAAe,EAAE,MAAM;QACvB,MAAM,EAAE;YACN,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE;YACtC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE;SACtC;QACD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;KACnD;CACO,CAAC;AAEX,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,mBAAmB;IACb,YAAY,CAAe;IAC3B,cAAc,CAAgB;IAC9B,QAAQ,CAA4B;IAErD;;;OAGG;IACH,YAAY,YAA0B,EAAE,cAA6B;QACnE,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAC;IAClD,CAAC;IAED;;;;;;;;;;OAUG;IACH,aAAa,CAAC,SAAiB,EAAE,KAAmB;QAClD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IAED;;;;;;;;;;OAUG;IACH,UAAU,CAAC,SAAiB;QAC1B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED;;;;;;;;;OASG;IACH,cAAc;QACZ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,oBAAoB,CAAC,SAAiB,EAAE,MAAgB;QAC5D,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC;gBACpD,OAAO,EAAE,IAAI,CAAC,cAAc;gBAC5B,GAAG,EAAE,mBAAmB;gBACxB,YAAY,EAAE,oBAAoB;gBAClC,IAAI,EAAE,CAAC,SAA0B,EAAE,MAAyB,CAAC;aAC9D,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,MAAM,IAAI,KAAK,CAAC,iDAAiD,SAAS,KAAK,OAAO,EAAE,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IAED;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,KAAa;QAC3B,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;gBAC3D,OAAO,OAAO,CAAC;YACjB,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACH,KAAK;QACH,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACF"}
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClearNode WebSocket Connection Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages the WebSocket connection to Yellow Network's ClearNode relay server
|
|
5
|
+
* with reconnection logic, request-response correlation, and event emission.
|
|
6
|
+
*
|
|
7
|
+
* Key features:
|
|
8
|
+
* - Exponential backoff reconnection: delay = initialDelay * 2^(attempt-1)
|
|
9
|
+
* - Request-response correlation using method name matching
|
|
10
|
+
* - EventEmitter pattern for connected/disconnected events
|
|
11
|
+
* - Cleanup of all pending handlers on disconnect
|
|
12
|
+
*
|
|
13
|
+
* Requirements: 10.1, 10.2, 10.3, 10.4, 10.5
|
|
14
|
+
*/
|
|
15
|
+
import { EventEmitter } from 'events';
|
|
16
|
+
/** WebSocket readyState constants */
|
|
17
|
+
const WS_OPEN = 1;
|
|
18
|
+
const WS_CONNECTING = 0;
|
|
19
|
+
/**
|
|
20
|
+
* Calculate the exponential backoff delay for a given reconnection attempt.
|
|
21
|
+
*
|
|
22
|
+
* Formula: delay = initialDelay * 2^(attempt - 1)
|
|
23
|
+
*
|
|
24
|
+
* This is exported as a pure function so it can be independently tested
|
|
25
|
+
* (including via property-based tests).
|
|
26
|
+
*
|
|
27
|
+
* @param initialDelay - The base delay in milliseconds
|
|
28
|
+
* @param attempt - The attempt number (1-based)
|
|
29
|
+
* @returns The delay in milliseconds before the given attempt
|
|
30
|
+
*/
|
|
31
|
+
export function calculateBackoffDelay(initialDelay, attempt) {
|
|
32
|
+
if (attempt < 1) {
|
|
33
|
+
return initialDelay;
|
|
34
|
+
}
|
|
35
|
+
return initialDelay * Math.pow(2, attempt - 1);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Manages a WebSocket connection to Yellow Network's ClearNode.
|
|
39
|
+
*
|
|
40
|
+
* Provides:
|
|
41
|
+
* - connect/disconnect lifecycle management
|
|
42
|
+
* - send (fire-and-forget) and sendAndWait (request-response correlation)
|
|
43
|
+
* - Automatic reconnection with exponential backoff
|
|
44
|
+
* - Event emission for 'connected' and 'disconnected' events
|
|
45
|
+
* - Cleanup of pending handlers on disconnect
|
|
46
|
+
*
|
|
47
|
+
* Requirements: 10.1, 10.2, 10.3, 10.4, 10.5
|
|
48
|
+
*/
|
|
49
|
+
export class ClearNodeConnection {
|
|
50
|
+
url;
|
|
51
|
+
maxReconnectAttempts;
|
|
52
|
+
reconnectDelay;
|
|
53
|
+
messageTimeout;
|
|
54
|
+
wsFactory;
|
|
55
|
+
ws = null;
|
|
56
|
+
emitter = new EventEmitter();
|
|
57
|
+
pendingRequests = [];
|
|
58
|
+
messageHandlers = [];
|
|
59
|
+
_isConnected = false;
|
|
60
|
+
_isDisposed = false;
|
|
61
|
+
reconnectAttempt = 0;
|
|
62
|
+
reconnectTimer = null;
|
|
63
|
+
/**
|
|
64
|
+
* @param url - The ClearNode WebSocket URL
|
|
65
|
+
* @param options - Connection configuration options
|
|
66
|
+
* @param wsFactory - Optional WebSocket factory for testing. Defaults to global WebSocket.
|
|
67
|
+
*/
|
|
68
|
+
constructor(url, options, wsFactory) {
|
|
69
|
+
this.url = url;
|
|
70
|
+
this.maxReconnectAttempts = options?.maxReconnectAttempts ?? 5;
|
|
71
|
+
this.reconnectDelay = options?.reconnectDelay ?? 1000;
|
|
72
|
+
this.messageTimeout = options?.messageTimeout ?? 30000;
|
|
73
|
+
this.wsFactory = wsFactory ?? ((wsUrl) => new WebSocket(wsUrl));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Establish a WebSocket connection to ClearNode.
|
|
77
|
+
*
|
|
78
|
+
* Resolves when the connection is open and ready.
|
|
79
|
+
* Rejects if the connection fails to establish.
|
|
80
|
+
*
|
|
81
|
+
* Requirement 10.1: Emit a connected event on successful connection.
|
|
82
|
+
*/
|
|
83
|
+
async connect() {
|
|
84
|
+
if (this._isDisposed) {
|
|
85
|
+
throw new Error('ClearNodeConnection has been disposed');
|
|
86
|
+
}
|
|
87
|
+
if (this._isConnected && this.ws) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
return new Promise((resolve, reject) => {
|
|
91
|
+
let settled = false;
|
|
92
|
+
try {
|
|
93
|
+
this.ws = this.wsFactory(this.url);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
reject(new Error(`Failed to create WebSocket: ${err instanceof Error ? err.message : String(err)}`));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this.ws.onopen = () => {
|
|
100
|
+
if (settled)
|
|
101
|
+
return;
|
|
102
|
+
settled = true;
|
|
103
|
+
this._isConnected = true;
|
|
104
|
+
this.reconnectAttempt = 0;
|
|
105
|
+
this.emitter.emit('connected');
|
|
106
|
+
resolve();
|
|
107
|
+
};
|
|
108
|
+
this.ws.onerror = (event) => {
|
|
109
|
+
if (settled)
|
|
110
|
+
return;
|
|
111
|
+
settled = true;
|
|
112
|
+
const errorMessage = event && typeof event === 'object' && 'message' in event
|
|
113
|
+
? String(event.message)
|
|
114
|
+
: 'WebSocket connection failed';
|
|
115
|
+
reject(new Error(errorMessage));
|
|
116
|
+
};
|
|
117
|
+
this.ws.onclose = () => {
|
|
118
|
+
if (!settled) {
|
|
119
|
+
settled = true;
|
|
120
|
+
reject(new Error('WebSocket closed before connection was established'));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
this.handleDisconnect();
|
|
124
|
+
};
|
|
125
|
+
this.ws.onmessage = (event) => {
|
|
126
|
+
this.handleMessage(event.data);
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Close the WebSocket connection and clean up all resources.
|
|
132
|
+
*
|
|
133
|
+
* Requirement 10.4: Clean up all pending message handlers on disconnect.
|
|
134
|
+
*/
|
|
135
|
+
async disconnect() {
|
|
136
|
+
this._isDisposed = true;
|
|
137
|
+
this.cancelReconnect();
|
|
138
|
+
this.cleanupPendingRequests(new Error('Connection closed by client'));
|
|
139
|
+
this.messageHandlers = [];
|
|
140
|
+
if (this.ws) {
|
|
141
|
+
const ws = this.ws;
|
|
142
|
+
this.ws = null;
|
|
143
|
+
this._isConnected = false;
|
|
144
|
+
// Remove handlers to prevent reconnection attempts
|
|
145
|
+
ws.onopen = null;
|
|
146
|
+
ws.onclose = null;
|
|
147
|
+
ws.onerror = null;
|
|
148
|
+
ws.onmessage = null;
|
|
149
|
+
// Only close if not already closed/closing
|
|
150
|
+
if (ws.readyState === WS_OPEN || ws.readyState === WS_CONNECTING) {
|
|
151
|
+
ws.close();
|
|
152
|
+
}
|
|
153
|
+
this.emitter.emit('disconnected');
|
|
154
|
+
}
|
|
155
|
+
this._isConnected = false;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Send a message and wait for a correlated response.
|
|
159
|
+
*
|
|
160
|
+
* The response is matched by method name: when a message is received
|
|
161
|
+
* that contains a matching method field, the promise resolves with that response.
|
|
162
|
+
*
|
|
163
|
+
* Requirement 10.5: Request-response correlation using method name matching.
|
|
164
|
+
*
|
|
165
|
+
* @param message - The message string to send
|
|
166
|
+
* @param method - The method name to correlate the response with
|
|
167
|
+
* @param timeout - Optional timeout in ms (defaults to messageTimeout)
|
|
168
|
+
* @returns The parsed response data
|
|
169
|
+
* @throws Error if the connection is not open, the request times out, or the connection drops
|
|
170
|
+
*/
|
|
171
|
+
async sendAndWait(message, method, timeout) {
|
|
172
|
+
if (!this._isConnected || !this.ws || this.ws.readyState !== WS_OPEN) {
|
|
173
|
+
throw new Error('WebSocket is not connected');
|
|
174
|
+
}
|
|
175
|
+
const effectiveTimeout = timeout ?? this.messageTimeout;
|
|
176
|
+
return new Promise((resolve, reject) => {
|
|
177
|
+
const timer = setTimeout(() => {
|
|
178
|
+
this.removePendingRequest(pending);
|
|
179
|
+
reject(new Error(`Request timed out waiting for response to method: ${method}`));
|
|
180
|
+
}, effectiveTimeout);
|
|
181
|
+
const pending = {
|
|
182
|
+
method,
|
|
183
|
+
resolve: resolve,
|
|
184
|
+
reject,
|
|
185
|
+
timer,
|
|
186
|
+
};
|
|
187
|
+
this.pendingRequests.push(pending);
|
|
188
|
+
this.ws.send(message);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Send a message without waiting for a response (fire-and-forget).
|
|
193
|
+
*
|
|
194
|
+
* @param message - The message string to send
|
|
195
|
+
* @throws Error if the connection is not open
|
|
196
|
+
*/
|
|
197
|
+
send(message) {
|
|
198
|
+
if (!this._isConnected || !this.ws || this.ws.readyState !== WS_OPEN) {
|
|
199
|
+
throw new Error('WebSocket is not connected');
|
|
200
|
+
}
|
|
201
|
+
this.ws.send(message);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Register a handler for incoming messages.
|
|
205
|
+
*
|
|
206
|
+
* Handlers receive the parsed message data for all incoming messages
|
|
207
|
+
* (including those that match pending requests).
|
|
208
|
+
*
|
|
209
|
+
* @param handler - Callback invoked with the parsed message data
|
|
210
|
+
*/
|
|
211
|
+
onMessage(handler) {
|
|
212
|
+
this.messageHandlers.push(handler);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Whether the WebSocket connection is currently open and ready.
|
|
216
|
+
*/
|
|
217
|
+
get isConnected() {
|
|
218
|
+
return this._isConnected;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Register an event listener for connection lifecycle events.
|
|
222
|
+
*
|
|
223
|
+
* Supported events: 'connected', 'disconnected'
|
|
224
|
+
*/
|
|
225
|
+
on(event, handler) {
|
|
226
|
+
this.emitter.on(event, handler);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Remove an event listener.
|
|
230
|
+
*/
|
|
231
|
+
off(event, handler) {
|
|
232
|
+
this.emitter.off(event, handler);
|
|
233
|
+
}
|
|
234
|
+
// ============================================================================
|
|
235
|
+
// Private Methods
|
|
236
|
+
// ============================================================================
|
|
237
|
+
/**
|
|
238
|
+
* Handle an incoming WebSocket message.
|
|
239
|
+
*
|
|
240
|
+
* Parses the message as JSON and checks for method-based correlation
|
|
241
|
+
* with pending requests. Also dispatches to all registered message handlers.
|
|
242
|
+
*/
|
|
243
|
+
handleMessage(rawData) {
|
|
244
|
+
let data;
|
|
245
|
+
try {
|
|
246
|
+
const text = typeof rawData === 'string' ? rawData : String(rawData);
|
|
247
|
+
data = JSON.parse(text);
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
// If the message is not valid JSON, pass the raw data
|
|
251
|
+
data = rawData;
|
|
252
|
+
}
|
|
253
|
+
// Dispatch to all registered message handlers
|
|
254
|
+
for (const handler of this.messageHandlers) {
|
|
255
|
+
try {
|
|
256
|
+
handler(data);
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
// Swallow handler errors to prevent one handler from breaking others
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// Check for method-based correlation with pending requests
|
|
263
|
+
if (data && typeof data === 'object') {
|
|
264
|
+
const messageObj = data;
|
|
265
|
+
const responseMethod = this.extractMethod(messageObj);
|
|
266
|
+
if (responseMethod) {
|
|
267
|
+
const matchIndex = this.pendingRequests.findIndex((req) => req.method === responseMethod);
|
|
268
|
+
if (matchIndex !== -1) {
|
|
269
|
+
const pending = this.pendingRequests[matchIndex];
|
|
270
|
+
this.pendingRequests.splice(matchIndex, 1);
|
|
271
|
+
clearTimeout(pending.timer);
|
|
272
|
+
pending.resolve(data);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Extract the method name from a parsed message object.
|
|
279
|
+
*
|
|
280
|
+
* Supports common message formats:
|
|
281
|
+
* - { method: "..." }
|
|
282
|
+
* - { type: "..." }
|
|
283
|
+
* - Nested: { response: { method: "..." } }
|
|
284
|
+
*/
|
|
285
|
+
extractMethod(obj) {
|
|
286
|
+
// Direct method field
|
|
287
|
+
if (typeof obj.method === 'string') {
|
|
288
|
+
return obj.method;
|
|
289
|
+
}
|
|
290
|
+
// Type field as fallback
|
|
291
|
+
if (typeof obj.type === 'string') {
|
|
292
|
+
return obj.type;
|
|
293
|
+
}
|
|
294
|
+
// Nested response object
|
|
295
|
+
if (obj.response && typeof obj.response === 'object') {
|
|
296
|
+
const response = obj.response;
|
|
297
|
+
if (typeof response.method === 'string') {
|
|
298
|
+
return response.method;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Handle an unexpected WebSocket disconnection.
|
|
305
|
+
*
|
|
306
|
+
* Cleans up state and initiates reconnection with exponential backoff.
|
|
307
|
+
*
|
|
308
|
+
* Requirement 10.2: Exponential backoff reconnection.
|
|
309
|
+
* Requirement 10.3: Emit disconnected and mark unavailable when retries exhausted.
|
|
310
|
+
*/
|
|
311
|
+
handleDisconnect() {
|
|
312
|
+
const wasConnected = this._isConnected;
|
|
313
|
+
this._isConnected = false;
|
|
314
|
+
this.ws = null;
|
|
315
|
+
// If disposed, don't attempt reconnection
|
|
316
|
+
if (this._isDisposed) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
// Attempt reconnection
|
|
320
|
+
if (wasConnected) {
|
|
321
|
+
this.attemptReconnect();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Attempt to reconnect with exponential backoff.
|
|
326
|
+
*
|
|
327
|
+
* Requirement 10.2: delay = initialDelay * 2^(attempt-1)
|
|
328
|
+
* Requirement 10.3: Mark provider unavailable when all retries exhausted.
|
|
329
|
+
*/
|
|
330
|
+
attemptReconnect() {
|
|
331
|
+
this.reconnectAttempt++;
|
|
332
|
+
if (this.reconnectAttempt > this.maxReconnectAttempts) {
|
|
333
|
+
// All retries exhausted
|
|
334
|
+
this.cleanupPendingRequests(new Error('All reconnection attempts exhausted'));
|
|
335
|
+
this.emitter.emit('disconnected');
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const delay = calculateBackoffDelay(this.reconnectDelay, this.reconnectAttempt);
|
|
339
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
340
|
+
this.reconnectTimer = null;
|
|
341
|
+
if (this._isDisposed) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
try {
|
|
345
|
+
await this.connect();
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
// Connection failed, try again
|
|
349
|
+
this.attemptReconnect();
|
|
350
|
+
}
|
|
351
|
+
}, delay);
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Cancel any pending reconnection timer.
|
|
355
|
+
*/
|
|
356
|
+
cancelReconnect() {
|
|
357
|
+
if (this.reconnectTimer !== null) {
|
|
358
|
+
clearTimeout(this.reconnectTimer);
|
|
359
|
+
this.reconnectTimer = null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Reject all pending requests with the given error and clean up timers.
|
|
364
|
+
*
|
|
365
|
+
* Requirement 10.4: Clean up all pending message handlers on disconnect.
|
|
366
|
+
*/
|
|
367
|
+
cleanupPendingRequests(error) {
|
|
368
|
+
const pending = [...this.pendingRequests];
|
|
369
|
+
this.pendingRequests = [];
|
|
370
|
+
for (const req of pending) {
|
|
371
|
+
clearTimeout(req.timer);
|
|
372
|
+
req.reject(error);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Remove a specific pending request from the list.
|
|
377
|
+
*/
|
|
378
|
+
removePendingRequest(request) {
|
|
379
|
+
const index = this.pendingRequests.indexOf(request);
|
|
380
|
+
if (index !== -1) {
|
|
381
|
+
this.pendingRequests.splice(index, 1);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
//# sourceMappingURL=clear-node-connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clear-node-connection.js","sourceRoot":"","sources":["../../../src/yellow/clear-node-connection.ts"],"names":[],"mappings":"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"}
|