@pythnetwork/pyth-lazer-sdk 6.2.1 → 6.2.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.
|
@@ -84,46 +84,68 @@ class ResilientWebSocket {
|
|
|
84
84
|
this.logger.info("WebSocket client already started.");
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
|
-
if (this.wsFailedAttempts
|
|
87
|
+
if (this.wsFailedAttempts === 0) {
|
|
88
88
|
this.logger.info(`Creating Web Socket client`);
|
|
89
89
|
}
|
|
90
90
|
if (this.retryTimeout !== undefined) {
|
|
91
91
|
clearTimeout(this.retryTimeout);
|
|
92
92
|
this.retryTimeout = undefined;
|
|
93
93
|
}
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
this.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
this.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.
|
|
94
|
+
// we wrap the new WebSocket() construction in a try / catch because,
|
|
95
|
+
// if one of our instances legitimately goes down or there's some network
|
|
96
|
+
// error that impacts connectivity, the WebSocket constructor will throw
|
|
97
|
+
// an uncaught DOMException in the browser (or equivalent in Node, Bun or Deno)
|
|
98
|
+
// and potentially blow up the process (if running in Node, Bun or Deno)
|
|
99
|
+
try {
|
|
100
|
+
// browser constructor supports a different 2nd argument for the constructor,
|
|
101
|
+
// so we need to ensure it's not included if we're running in that environment:
|
|
102
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket#protocols
|
|
103
|
+
this.wsClient = new _isomorphicws.default(this.endpoint, (0, _envutil.envIsBrowserOrWorker)() ? undefined : this.wsOptions);
|
|
104
|
+
this.wsClient.addEventListener("open", ()=>{
|
|
105
|
+
this.logger.info("WebSocket connection established");
|
|
106
|
+
this.wsFailedAttempts = 0;
|
|
107
|
+
this._isReconnecting = false;
|
|
108
|
+
this.resetHeartbeat();
|
|
109
|
+
try {
|
|
110
|
+
this.onReconnect();
|
|
111
|
+
} catch (error) {
|
|
112
|
+
this.logger.error("Error in onReconnect callback:", error);
|
|
111
113
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
this.wsClient.
|
|
124
|
-
|
|
114
|
+
});
|
|
115
|
+
this.wsClient.addEventListener("close", (e)=>{
|
|
116
|
+
if (this.wsUserClosed) {
|
|
117
|
+
this.logger.info(`WebSocket connection to ${this.endpoint} closed by user`);
|
|
118
|
+
} else {
|
|
119
|
+
if (this.shouldLogRetry()) {
|
|
120
|
+
this.logger.warn(`WebSocket connection to ${this.endpoint} closed unexpectedly: Code: ${e.code.toString()}`);
|
|
121
|
+
}
|
|
122
|
+
this.handleReconnect();
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
this.wsClient.addEventListener("error", (event)=>{
|
|
126
|
+
try {
|
|
127
|
+
this.onError(event);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
this.logger.error("Error in onError callback:", error);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
this.wsClient.addEventListener("message", (event)=>{
|
|
125
133
|
this.resetHeartbeat();
|
|
134
|
+
try {
|
|
135
|
+
this.onMessage(event.data);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
this.logger.error("Error in onMessage callback:", error);
|
|
138
|
+
}
|
|
126
139
|
});
|
|
140
|
+
if (typeof this.wsClient?.on === "function") {
|
|
141
|
+
this.wsClient.on("ping", ()=>{
|
|
142
|
+
this.logger.debug("Ping received");
|
|
143
|
+
this.resetHeartbeat();
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
} catch (error) {
|
|
147
|
+
this.logger.error("Failed to create WebSocket client:", error);
|
|
148
|
+
this.handleReconnect();
|
|
127
149
|
}
|
|
128
150
|
}
|
|
129
151
|
resetHeartbeat() {
|
|
@@ -133,7 +155,11 @@ class ResilientWebSocket {
|
|
|
133
155
|
this.heartbeatTimeout = setTimeout(()=>{
|
|
134
156
|
const warnMsg = "Connection timed out. Reconnecting...";
|
|
135
157
|
this.logger.warn(warnMsg);
|
|
136
|
-
|
|
158
|
+
try {
|
|
159
|
+
this.onTimeout();
|
|
160
|
+
} catch (error) {
|
|
161
|
+
this.logger.error("Error in onTimeout callback:", error);
|
|
162
|
+
}
|
|
137
163
|
if (this.wsClient) {
|
|
138
164
|
if (typeof this.wsClient.terminate === "function") {
|
|
139
165
|
this.wsClient.terminate();
|
|
@@ -144,7 +170,8 @@ class ResilientWebSocket {
|
|
|
144
170
|
this.wsClient.close(_protocol.CustomSocketClosureCodes.CLIENT_TIMEOUT_BUT_RECONNECTING, warnMsg);
|
|
145
171
|
}
|
|
146
172
|
}
|
|
147
|
-
|
|
173
|
+
// No direct call to handleReconnect() here
|
|
174
|
+
// terminate/close will trigger the 'close' event, which will call it.
|
|
148
175
|
}, this.heartbeatTimeoutDurationMs);
|
|
149
176
|
}
|
|
150
177
|
handleReconnect() {
|
|
@@ -169,11 +196,12 @@ class ResilientWebSocket {
|
|
|
169
196
|
}, this.retryDelayMs());
|
|
170
197
|
}
|
|
171
198
|
closeWebSocket() {
|
|
172
|
-
|
|
199
|
+
// immediately block duplicate calls to this function
|
|
200
|
+
this.wsUserClosed = true;
|
|
201
|
+
if (typeof this.wsClient?.close === "function") {
|
|
173
202
|
this.wsClient.close();
|
|
174
203
|
this.wsClient = undefined;
|
|
175
204
|
}
|
|
176
|
-
this.wsUserClosed = true;
|
|
177
205
|
}
|
|
178
206
|
/**
|
|
179
207
|
* Calculates the delay in milliseconds for exponential backoff based on the number of failed attempts.
|
|
@@ -8,17 +8,12 @@ Object.defineProperty(exports, "WebSocketPool", {
|
|
|
8
8
|
return WebSocketPool;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
-
const _ttlcache =
|
|
11
|
+
const _ttlcache = require("@isaacs/ttlcache");
|
|
12
12
|
const _tslog = require("ts-log");
|
|
13
13
|
const _constants = require("../constants.cjs");
|
|
14
14
|
const _index = require("../emitter/index.cjs");
|
|
15
15
|
const _index1 = require("../util/index.cjs");
|
|
16
16
|
const _resilientwebsocket = require("./resilient-websocket.cjs");
|
|
17
|
-
function _interop_require_default(obj) {
|
|
18
|
-
return obj && obj.__esModule ? obj : {
|
|
19
|
-
default: obj
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
17
|
const DEFAULT_NUM_CONNECTIONS = 4;
|
|
23
18
|
class WebSocketPool extends _index.IsomorphicEventEmitter {
|
|
24
19
|
logger;
|
|
@@ -36,7 +31,7 @@ class WebSocketPool extends _index.IsomorphicEventEmitter {
|
|
|
36
31
|
constructor(logger){
|
|
37
32
|
super(), this.logger = logger;
|
|
38
33
|
this.rwsPool = [];
|
|
39
|
-
this.cache = new _ttlcache.
|
|
34
|
+
this.cache = new _ttlcache.TTLCache({
|
|
40
35
|
ttl: 1000 * 10
|
|
41
36
|
}); // TTL of 10 seconds
|
|
42
37
|
this.subscriptions = new Map();
|
|
@@ -69,46 +69,68 @@ export class ResilientWebSocket {
|
|
|
69
69
|
this.logger.info("WebSocket client already started.");
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
|
-
if (this.wsFailedAttempts
|
|
72
|
+
if (this.wsFailedAttempts === 0) {
|
|
73
73
|
this.logger.info(`Creating Web Socket client`);
|
|
74
74
|
}
|
|
75
75
|
if (this.retryTimeout !== undefined) {
|
|
76
76
|
clearTimeout(this.retryTimeout);
|
|
77
77
|
this.retryTimeout = undefined;
|
|
78
78
|
}
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
this.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
this.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
this.
|
|
79
|
+
// we wrap the new WebSocket() construction in a try / catch because,
|
|
80
|
+
// if one of our instances legitimately goes down or there's some network
|
|
81
|
+
// error that impacts connectivity, the WebSocket constructor will throw
|
|
82
|
+
// an uncaught DOMException in the browser (or equivalent in Node, Bun or Deno)
|
|
83
|
+
// and potentially blow up the process (if running in Node, Bun or Deno)
|
|
84
|
+
try {
|
|
85
|
+
// browser constructor supports a different 2nd argument for the constructor,
|
|
86
|
+
// so we need to ensure it's not included if we're running in that environment:
|
|
87
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket#protocols
|
|
88
|
+
this.wsClient = new WebSocket(this.endpoint, envIsBrowserOrWorker() ? undefined : this.wsOptions);
|
|
89
|
+
this.wsClient.addEventListener("open", ()=>{
|
|
90
|
+
this.logger.info("WebSocket connection established");
|
|
91
|
+
this.wsFailedAttempts = 0;
|
|
92
|
+
this._isReconnecting = false;
|
|
93
|
+
this.resetHeartbeat();
|
|
94
|
+
try {
|
|
95
|
+
this.onReconnect();
|
|
96
|
+
} catch (error) {
|
|
97
|
+
this.logger.error("Error in onReconnect callback:", error);
|
|
96
98
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
this.wsClient.
|
|
109
|
-
|
|
99
|
+
});
|
|
100
|
+
this.wsClient.addEventListener("close", (e)=>{
|
|
101
|
+
if (this.wsUserClosed) {
|
|
102
|
+
this.logger.info(`WebSocket connection to ${this.endpoint} closed by user`);
|
|
103
|
+
} else {
|
|
104
|
+
if (this.shouldLogRetry()) {
|
|
105
|
+
this.logger.warn(`WebSocket connection to ${this.endpoint} closed unexpectedly: Code: ${e.code.toString()}`);
|
|
106
|
+
}
|
|
107
|
+
this.handleReconnect();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
this.wsClient.addEventListener("error", (event)=>{
|
|
111
|
+
try {
|
|
112
|
+
this.onError(event);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
this.logger.error("Error in onError callback:", error);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
this.wsClient.addEventListener("message", (event)=>{
|
|
110
118
|
this.resetHeartbeat();
|
|
119
|
+
try {
|
|
120
|
+
this.onMessage(event.data);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
this.logger.error("Error in onMessage callback:", error);
|
|
123
|
+
}
|
|
111
124
|
});
|
|
125
|
+
if (typeof this.wsClient?.on === "function") {
|
|
126
|
+
this.wsClient.on("ping", ()=>{
|
|
127
|
+
this.logger.debug("Ping received");
|
|
128
|
+
this.resetHeartbeat();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
this.logger.error("Failed to create WebSocket client:", error);
|
|
133
|
+
this.handleReconnect();
|
|
112
134
|
}
|
|
113
135
|
}
|
|
114
136
|
resetHeartbeat() {
|
|
@@ -118,7 +140,11 @@ export class ResilientWebSocket {
|
|
|
118
140
|
this.heartbeatTimeout = setTimeout(()=>{
|
|
119
141
|
const warnMsg = "Connection timed out. Reconnecting...";
|
|
120
142
|
this.logger.warn(warnMsg);
|
|
121
|
-
|
|
143
|
+
try {
|
|
144
|
+
this.onTimeout();
|
|
145
|
+
} catch (error) {
|
|
146
|
+
this.logger.error("Error in onTimeout callback:", error);
|
|
147
|
+
}
|
|
122
148
|
if (this.wsClient) {
|
|
123
149
|
if (typeof this.wsClient.terminate === "function") {
|
|
124
150
|
this.wsClient.terminate();
|
|
@@ -129,7 +155,8 @@ export class ResilientWebSocket {
|
|
|
129
155
|
this.wsClient.close(CustomSocketClosureCodes.CLIENT_TIMEOUT_BUT_RECONNECTING, warnMsg);
|
|
130
156
|
}
|
|
131
157
|
}
|
|
132
|
-
|
|
158
|
+
// No direct call to handleReconnect() here
|
|
159
|
+
// terminate/close will trigger the 'close' event, which will call it.
|
|
133
160
|
}, this.heartbeatTimeoutDurationMs);
|
|
134
161
|
}
|
|
135
162
|
handleReconnect() {
|
|
@@ -154,11 +181,12 @@ export class ResilientWebSocket {
|
|
|
154
181
|
}, this.retryDelayMs());
|
|
155
182
|
}
|
|
156
183
|
closeWebSocket() {
|
|
157
|
-
|
|
184
|
+
// immediately block duplicate calls to this function
|
|
185
|
+
this.wsUserClosed = true;
|
|
186
|
+
if (typeof this.wsClient?.close === "function") {
|
|
158
187
|
this.wsClient.close();
|
|
159
188
|
this.wsClient = undefined;
|
|
160
189
|
}
|
|
161
|
-
this.wsUserClosed = true;
|
|
162
190
|
}
|
|
163
191
|
/**
|
|
164
192
|
* Calculates the delay in milliseconds for exponential backoff based on the number of failed attempts.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import TTLCache from "@isaacs/ttlcache";
|
|
1
|
+
import { TTLCache } from "@isaacs/ttlcache";
|
|
2
2
|
import { dummyLogger } from "ts-log";
|
|
3
3
|
import { DEFAULT_STREAM_SERVICE_0_URL, DEFAULT_STREAM_SERVICE_1_URL } from "../constants.mjs";
|
|
4
4
|
import { IsomorphicEventEmitter } from "../emitter/index.mjs";
|
package/package.json
CHANGED
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
"url": "https://github.com/pyth-network/pyth-crosschain/issues"
|
|
4
4
|
},
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@isaacs/ttlcache": "^1.4
|
|
6
|
+
"@isaacs/ttlcache": "^2.1.4",
|
|
7
7
|
"buffer": "^6.0.3",
|
|
8
8
|
"isomorphic-ws": "^5.0.0",
|
|
9
9
|
"ts-log": "^2.2.7",
|
|
10
|
-
"ws": "^8.
|
|
10
|
+
"ws": "^8.20.0"
|
|
11
11
|
},
|
|
12
12
|
"description": "Pyth Lazer SDK",
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@cprussin/tsconfig": "^4.0.2",
|
|
15
15
|
"@types/node": "^24.10.1",
|
|
16
16
|
"@types/ws": "^8.18.1",
|
|
17
|
-
"typedoc": "^0.28.
|
|
17
|
+
"typedoc": "^0.28.18"
|
|
18
18
|
},
|
|
19
19
|
"engines": {
|
|
20
20
|
"node": "^24.0.0"
|
|
@@ -164,5 +164,5 @@
|
|
|
164
164
|
},
|
|
165
165
|
"type": "module",
|
|
166
166
|
"types": "./dist/cjs/index.d.ts",
|
|
167
|
-
"version": "6.2.
|
|
167
|
+
"version": "6.2.2"
|
|
168
168
|
}
|