@pythnetwork/pyth-lazer-sdk 5.0.0 → 5.2.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.
- package/dist/cjs/{client.js → client.cjs} +93 -98
- package/dist/cjs/constants.cjs +36 -0
- package/dist/cjs/index.cjs +20 -0
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/protocol.cjs +33 -0
- package/dist/cjs/protocol.d.ts +1 -1
- package/dist/cjs/socket/{resilient-websocket.js → resilient-websocket.cjs} +47 -48
- package/dist/cjs/socket/{websocket-pool.js → websocket-pool.cjs} +68 -65
- package/dist/cjs/util/{buffer-util.js → buffer-util.cjs} +14 -14
- package/dist/cjs/util/env-util.cjs +33 -0
- package/dist/cjs/util/index.cjs +20 -0
- package/dist/cjs/util/url-util.cjs +17 -0
- package/dist/esm/{client.js → client.mjs} +76 -88
- package/dist/esm/index.mjs +3 -0
- package/dist/esm/package.json +1 -1
- package/dist/esm/protocol.d.ts +1 -1
- package/dist/esm/{protocol.js → protocol.mjs} +4 -4
- package/dist/esm/socket/{resilient-websocket.js → resilient-websocket.mjs} +27 -36
- package/dist/esm/socket/{websocket-pool.js → websocket-pool.mjs} +47 -53
- package/dist/esm/util/{buffer-util.js → buffer-util.mjs} +3 -6
- package/dist/esm/util/{env-util.js → env-util.mjs} +4 -8
- package/dist/esm/util/index.mjs +3 -0
- package/dist/esm/util/{url-util.js → url-util.mjs} +2 -4
- package/package.json +108 -15
- package/dist/cjs/constants.js +0 -9
- package/dist/cjs/index.js +0 -19
- package/dist/cjs/protocol.js +0 -15
- package/dist/cjs/util/env-util.js +0 -32
- package/dist/cjs/util/index.js +0 -19
- package/dist/cjs/util/url-util.js +0 -18
- package/dist/esm/index.js +0 -3
- package/dist/esm/util/index.js +0 -3
- /package/dist/esm/{constants.js → constants.mjs} +0 -0
package/dist/esm/protocol.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type Format = "evm" | "solana" | "leEcdsa" | "leUnsigned";
|
|
2
2
|
export type DeliveryFormat = "json" | "binary";
|
|
3
3
|
export type JsonBinaryEncoding = "base64" | "hex";
|
|
4
|
-
export type PriceFeedProperty = "price" | "bestBidPrice" | "bestAskPrice" | "exponent" | "publisherCount" | "confidence";
|
|
4
|
+
export type PriceFeedProperty = "price" | "bestBidPrice" | "bestAskPrice" | "exponent" | "publisherCount" | "confidence" | "fundingRate" | "fundingTimestamp" | "fundingRateInterval";
|
|
5
5
|
export type Channel = "real_time" | "fixed_rate@50ms" | "fixed_rate@200ms";
|
|
6
6
|
export type Request = {
|
|
7
7
|
type: "subscribe";
|
|
@@ -4,9 +4,9 @@ export const FORMAT_MAGICS_LE = {
|
|
|
4
4
|
EVM: 2_593_727_018,
|
|
5
5
|
SOLANA: 2_182_742_457,
|
|
6
6
|
LE_ECDSA: 1_296_547_300,
|
|
7
|
-
LE_UNSIGNED: 1_499_680_012
|
|
7
|
+
LE_UNSIGNED: 1_499_680_012
|
|
8
8
|
};
|
|
9
|
-
export var CustomSocketClosureCodes
|
|
10
|
-
(function (CustomSocketClosureCodes) {
|
|
9
|
+
export var CustomSocketClosureCodes = /*#__PURE__*/ function(CustomSocketClosureCodes) {
|
|
11
10
|
CustomSocketClosureCodes[CustomSocketClosureCodes["CLIENT_TIMEOUT_BUT_RECONNECTING"] = 4000] = "CLIENT_TIMEOUT_BUT_RECONNECTING";
|
|
12
|
-
|
|
11
|
+
return CustomSocketClosureCodes;
|
|
12
|
+
}({});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import WebSocket from "isomorphic-ws";
|
|
2
2
|
import { dummyLogger } from "ts-log";
|
|
3
|
-
import { CustomSocketClosureCodes } from "../protocol.
|
|
4
|
-
import { envIsBrowserOrWorker } from "../util/env-util.
|
|
3
|
+
import { CustomSocketClosureCodes } from "../protocol.mjs";
|
|
4
|
+
import { envIsBrowserOrWorker } from "../util/env-util.mjs";
|
|
5
5
|
const DEFAULT_HEARTBEAT_TIMEOUT_DURATION_MS = 5000; // 5 seconds
|
|
6
6
|
const DEFAULT_MAX_RETRY_DELAY_MS = 1000; // 1 second'
|
|
7
7
|
const DEFAULT_LOG_AFTER_RETRY_COUNT = 10;
|
|
@@ -30,33 +30,29 @@ export class ResilientWebSocket {
|
|
|
30
30
|
onError;
|
|
31
31
|
onMessage;
|
|
32
32
|
onReconnect;
|
|
33
|
-
constructor(config)
|
|
33
|
+
constructor(config){
|
|
34
34
|
this.endpoint = config.endpoint;
|
|
35
35
|
this.wsOptions = config.wsOptions;
|
|
36
36
|
this.logger = config.logger ?? dummyLogger;
|
|
37
|
-
this.heartbeatTimeoutDurationMs =
|
|
38
|
-
config.heartbeatTimeoutDurationMs ??
|
|
39
|
-
DEFAULT_HEARTBEAT_TIMEOUT_DURATION_MS;
|
|
37
|
+
this.heartbeatTimeoutDurationMs = config.heartbeatTimeoutDurationMs ?? DEFAULT_HEARTBEAT_TIMEOUT_DURATION_MS;
|
|
40
38
|
this.maxRetryDelayMs = config.maxRetryDelayMs ?? DEFAULT_MAX_RETRY_DELAY_MS;
|
|
41
|
-
this.logAfterRetryCount =
|
|
42
|
-
config.logAfterRetryCount ?? DEFAULT_LOG_AFTER_RETRY_COUNT;
|
|
39
|
+
this.logAfterRetryCount = config.logAfterRetryCount ?? DEFAULT_LOG_AFTER_RETRY_COUNT;
|
|
43
40
|
this.wsFailedAttempts = 0;
|
|
44
|
-
this.onError = (error)
|
|
41
|
+
this.onError = (error)=>{
|
|
45
42
|
void error;
|
|
46
43
|
};
|
|
47
|
-
this.onMessage = (data)
|
|
44
|
+
this.onMessage = (data)=>{
|
|
48
45
|
void data;
|
|
49
46
|
};
|
|
50
|
-
this.onReconnect = ()
|
|
51
|
-
|
|
47
|
+
this.onReconnect = ()=>{
|
|
48
|
+
// Empty function, can be set by the user.
|
|
52
49
|
};
|
|
53
50
|
}
|
|
54
51
|
send(data) {
|
|
55
52
|
this.logger.debug(`Sending message`);
|
|
56
53
|
if (this.isConnected()) {
|
|
57
54
|
this.wsClient.send(data);
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
55
|
+
} else {
|
|
60
56
|
this.logger.warn(`WebSocket to ${this.endpoint} is not connected. Cannot send message.`);
|
|
61
57
|
}
|
|
62
58
|
}
|
|
@@ -80,33 +76,32 @@ export class ResilientWebSocket {
|
|
|
80
76
|
// so we need to ensure it's not included if we're running in that environment:
|
|
81
77
|
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket#protocols
|
|
82
78
|
this.wsClient = new WebSocket(this.endpoint, envIsBrowserOrWorker() ? undefined : this.wsOptions);
|
|
83
|
-
this.wsClient.addEventListener("open", ()
|
|
79
|
+
this.wsClient.addEventListener("open", ()=>{
|
|
84
80
|
this.logger.info("WebSocket connection established");
|
|
85
81
|
this.wsFailedAttempts = 0;
|
|
86
82
|
this._isReconnecting = false;
|
|
87
83
|
this.resetHeartbeat();
|
|
88
84
|
this.onReconnect();
|
|
89
85
|
});
|
|
90
|
-
this.wsClient.addEventListener("close", (e)
|
|
86
|
+
this.wsClient.addEventListener("close", (e)=>{
|
|
91
87
|
if (this.wsUserClosed) {
|
|
92
88
|
this.logger.info(`WebSocket connection to ${this.endpoint} closed by user`);
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
89
|
+
} else {
|
|
95
90
|
if (this.shouldLogRetry()) {
|
|
96
91
|
this.logger.warn(`WebSocket connection to ${this.endpoint} closed unexpectedly: Code: ${e.code.toString()}`);
|
|
97
92
|
}
|
|
98
93
|
this.handleReconnect();
|
|
99
94
|
}
|
|
100
95
|
});
|
|
101
|
-
this.wsClient.addEventListener("error", (event)
|
|
96
|
+
this.wsClient.addEventListener("error", (event)=>{
|
|
102
97
|
this.onError(event);
|
|
103
98
|
});
|
|
104
|
-
this.wsClient.addEventListener("message", (event)
|
|
99
|
+
this.wsClient.addEventListener("message", (event)=>{
|
|
105
100
|
this.resetHeartbeat();
|
|
106
101
|
this.onMessage(event.data);
|
|
107
102
|
});
|
|
108
103
|
if ("on" in this.wsClient) {
|
|
109
|
-
this.wsClient.on("ping", ()
|
|
104
|
+
this.wsClient.on("ping", ()=>{
|
|
110
105
|
this.logger.info("Ping received");
|
|
111
106
|
this.resetHeartbeat();
|
|
112
107
|
});
|
|
@@ -116,14 +111,13 @@ export class ResilientWebSocket {
|
|
|
116
111
|
if (this.heartbeatTimeout !== undefined) {
|
|
117
112
|
clearTimeout(this.heartbeatTimeout);
|
|
118
113
|
}
|
|
119
|
-
this.heartbeatTimeout = setTimeout(()
|
|
114
|
+
this.heartbeatTimeout = setTimeout(()=>{
|
|
120
115
|
const warnMsg = "Connection timed out. Reconnecting...";
|
|
121
116
|
this.logger.warn(warnMsg);
|
|
122
117
|
if (this.wsClient) {
|
|
123
118
|
if (typeof this.wsClient.terminate === "function") {
|
|
124
119
|
this.wsClient.terminate();
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
120
|
+
} else {
|
|
127
121
|
// terminate is an implementation detail of the node-friendly
|
|
128
122
|
// https://www.npmjs.com/package/ws package, but is not a native WebSocket API,
|
|
129
123
|
// so we have to use the close method
|
|
@@ -148,11 +142,9 @@ export class ResilientWebSocket {
|
|
|
148
142
|
this.wsClient = undefined;
|
|
149
143
|
this._isReconnecting = true;
|
|
150
144
|
if (this.shouldLogRetry()) {
|
|
151
|
-
this.logger.error("Connection closed unexpectedly or because of timeout. Reconnecting after " +
|
|
152
|
-
String(this.retryDelayMs()) +
|
|
153
|
-
"ms.");
|
|
145
|
+
this.logger.error("Connection closed unexpectedly or because of timeout. Reconnecting after " + String(this.retryDelayMs()) + "ms.");
|
|
154
146
|
}
|
|
155
|
-
this.retryTimeout = setTimeout(()
|
|
147
|
+
this.retryTimeout = setTimeout(()=>{
|
|
156
148
|
this.startWebSocket();
|
|
157
149
|
}, this.retryDelayMs());
|
|
158
150
|
}
|
|
@@ -164,14 +156,13 @@ export class ResilientWebSocket {
|
|
|
164
156
|
this.wsUserClosed = true;
|
|
165
157
|
}
|
|
166
158
|
/**
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
retryDelayMs() {
|
|
159
|
+
* Calculates the delay in milliseconds for exponential backoff based on the number of failed attempts.
|
|
160
|
+
*
|
|
161
|
+
* The delay increases exponentially with each attempt, starting at 20ms for the first attempt,
|
|
162
|
+
* and is capped at maxRetryDelayMs for attempts greater than or equal to 10.
|
|
163
|
+
*
|
|
164
|
+
* @returns The calculated delay in milliseconds before the next retry.
|
|
165
|
+
*/ retryDelayMs() {
|
|
175
166
|
if (this.wsFailedAttempts >= 10) {
|
|
176
167
|
return this.maxRetryDelayMs;
|
|
177
168
|
}
|
|
@@ -1,77 +1,76 @@
|
|
|
1
1
|
import TTLCache from "@isaacs/ttlcache";
|
|
2
|
-
import WebSocket from "isomorphic-ws";
|
|
3
2
|
import { dummyLogger } from "ts-log";
|
|
4
|
-
import { ResilientWebSocket } from "./resilient-websocket.
|
|
5
|
-
import { DEFAULT_STREAM_SERVICE_0_URL, DEFAULT_STREAM_SERVICE_1_URL
|
|
6
|
-
import { addAuthTokenToWebSocketUrl, bufferFromWebsocketData, envIsBrowserOrWorker
|
|
3
|
+
import { ResilientWebSocket } from "./resilient-websocket.mjs";
|
|
4
|
+
import { DEFAULT_STREAM_SERVICE_0_URL, DEFAULT_STREAM_SERVICE_1_URL } from "../constants.mjs";
|
|
5
|
+
import { addAuthTokenToWebSocketUrl, bufferFromWebsocketData, envIsBrowserOrWorker } from "../util/index.mjs";
|
|
7
6
|
const DEFAULT_NUM_CONNECTIONS = 4;
|
|
8
7
|
export class WebSocketPool {
|
|
9
8
|
logger;
|
|
10
9
|
rwsPool;
|
|
11
10
|
cache;
|
|
12
|
-
subscriptions;
|
|
11
|
+
subscriptions;
|
|
13
12
|
messageListeners;
|
|
14
13
|
allConnectionsDownListeners;
|
|
15
14
|
wasAllDown = true;
|
|
16
15
|
checkConnectionStatesInterval;
|
|
17
|
-
constructor(logger)
|
|
16
|
+
constructor(logger){
|
|
18
17
|
this.logger = logger;
|
|
19
18
|
this.rwsPool = [];
|
|
20
|
-
this.cache = new TTLCache({
|
|
19
|
+
this.cache = new TTLCache({
|
|
20
|
+
ttl: 1000 * 10
|
|
21
|
+
}); // TTL of 10 seconds
|
|
21
22
|
this.subscriptions = new Map();
|
|
22
23
|
this.messageListeners = [];
|
|
23
24
|
this.allConnectionsDownListeners = [];
|
|
24
25
|
// Start monitoring connection states
|
|
25
|
-
this.checkConnectionStatesInterval = setInterval(()
|
|
26
|
+
this.checkConnectionStatesInterval = setInterval(()=>{
|
|
26
27
|
this.checkConnectionStates();
|
|
27
28
|
}, 100);
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
static async create(config, token, logger) {
|
|
31
|
+
* Creates a new WebSocketPool instance that uses multiple redundant WebSocket connections for reliability.
|
|
32
|
+
* Usage semantics are similar to using a regular WebSocket client.
|
|
33
|
+
* @param urls - List of WebSocket URLs to connect to
|
|
34
|
+
* @param token - Authentication token to use for the connections
|
|
35
|
+
* @param numConnections - Number of parallel WebSocket connections to maintain (default: 3)
|
|
36
|
+
* @param logger - Optional logger to get socket level logs. Compatible with most loggers such as the built-in console and `bunyan`.
|
|
37
|
+
*/ static async create(config, token, logger) {
|
|
38
38
|
const urls = config.urls ?? [
|
|
39
39
|
DEFAULT_STREAM_SERVICE_0_URL,
|
|
40
|
-
DEFAULT_STREAM_SERVICE_1_URL
|
|
40
|
+
DEFAULT_STREAM_SERVICE_1_URL
|
|
41
41
|
];
|
|
42
42
|
const log = logger ?? dummyLogger;
|
|
43
43
|
const pool = new WebSocketPool(log);
|
|
44
44
|
const numConnections = config.numConnections ?? DEFAULT_NUM_CONNECTIONS;
|
|
45
|
-
for
|
|
45
|
+
for(let i = 0; i < numConnections; i++){
|
|
46
46
|
const baseUrl = urls[i % urls.length];
|
|
47
47
|
const isBrowser = envIsBrowserOrWorker();
|
|
48
|
-
const url = isBrowser
|
|
49
|
-
? addAuthTokenToWebSocketUrl(baseUrl, token)
|
|
50
|
-
: baseUrl;
|
|
48
|
+
const url = isBrowser ? addAuthTokenToWebSocketUrl(baseUrl, token) : baseUrl;
|
|
51
49
|
if (!url) {
|
|
52
50
|
throw new Error(`URLs must not be null or empty`);
|
|
53
51
|
}
|
|
54
52
|
const wsOptions = {
|
|
55
53
|
...config.rwsConfig?.wsOptions,
|
|
56
|
-
headers: isBrowser ? undefined : {
|
|
54
|
+
headers: isBrowser ? undefined : {
|
|
55
|
+
Authorization: `Bearer ${token}`
|
|
56
|
+
}
|
|
57
57
|
};
|
|
58
58
|
const rws = new ResilientWebSocket({
|
|
59
59
|
...config.rwsConfig,
|
|
60
60
|
endpoint: url,
|
|
61
61
|
wsOptions,
|
|
62
|
-
logger: log
|
|
62
|
+
logger: log
|
|
63
63
|
});
|
|
64
64
|
// If a websocket client unexpectedly disconnects, ResilientWebSocket will reestablish
|
|
65
65
|
// the connection and call the onReconnect callback.
|
|
66
|
-
rws.onReconnect = ()
|
|
66
|
+
rws.onReconnect = ()=>{
|
|
67
67
|
if (rws.wsUserClosed) {
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
|
-
for (const [, request] of pool.subscriptions)
|
|
70
|
+
for (const [, request] of pool.subscriptions){
|
|
71
71
|
try {
|
|
72
72
|
rws.send(JSON.stringify(request));
|
|
73
|
-
}
|
|
74
|
-
catch (error) {
|
|
73
|
+
} catch (error) {
|
|
75
74
|
pool.logger.error("Failed to resend subscription on reconnect:", error);
|
|
76
75
|
}
|
|
77
76
|
}
|
|
@@ -80,8 +79,8 @@ export class WebSocketPool {
|
|
|
80
79
|
rws.onError = config.onError;
|
|
81
80
|
}
|
|
82
81
|
// Handle all client messages ourselves. Dedupe before sending to registered message handlers.
|
|
83
|
-
rws.onMessage = (data)
|
|
84
|
-
pool.dedupeHandler(data).catch((error)
|
|
82
|
+
rws.onMessage = (data)=>{
|
|
83
|
+
pool.dedupeHandler(data).catch((error)=>{
|
|
85
84
|
const errMsg = `An error occurred in the WebSocket pool's dedupeHandler: ${error instanceof Error ? error.message : String(error)}`;
|
|
86
85
|
throw new Error(errMsg);
|
|
87
86
|
});
|
|
@@ -90,35 +89,31 @@ export class WebSocketPool {
|
|
|
90
89
|
rws.startWebSocket();
|
|
91
90
|
}
|
|
92
91
|
pool.logger.info(`Started WebSocketPool with ${numConnections.toString()} connections. Waiting for at least one to connect...`);
|
|
93
|
-
while
|
|
94
|
-
await new Promise((resolve)
|
|
92
|
+
while(!pool.isAnyConnectionEstablished()){
|
|
93
|
+
await new Promise((resolve)=>setTimeout(resolve, 100));
|
|
95
94
|
}
|
|
96
95
|
pool.logger.info(`At least one WebSocket connection is established. WebSocketPool is ready.`);
|
|
97
96
|
return pool;
|
|
98
97
|
}
|
|
99
98
|
/**
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
handleErrorMessages(data) {
|
|
99
|
+
* Checks for error responses in JSON messages and throws appropriate errors
|
|
100
|
+
*/ handleErrorMessages(data) {
|
|
103
101
|
const message = JSON.parse(data);
|
|
104
102
|
if (message.type === "subscriptionError") {
|
|
105
103
|
throw new Error(`Error occurred for subscription ID ${String(message.subscriptionId)}: ${message.error}`);
|
|
106
|
-
}
|
|
107
|
-
else if (message.type === "error") {
|
|
104
|
+
} else if (message.type === "error") {
|
|
108
105
|
throw new Error(`Error: ${message.error}`);
|
|
109
106
|
}
|
|
110
107
|
}
|
|
111
108
|
async constructCacheKeyFromWebsocketData(data) {
|
|
112
|
-
if (typeof data === "string")
|
|
113
|
-
return data;
|
|
109
|
+
if (typeof data === "string") return data;
|
|
114
110
|
const buff = await bufferFromWebsocketData(data);
|
|
115
111
|
return buff.toString("hex");
|
|
116
112
|
}
|
|
117
113
|
/**
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
dedupeHandler = async (data) => {
|
|
114
|
+
* Handles incoming websocket messages by deduplicating identical messages received across
|
|
115
|
+
* multiple connections before forwarding to registered handlers
|
|
116
|
+
*/ dedupeHandler = async (data)=>{
|
|
122
117
|
const cacheKey = await this.constructCacheKeyFromWebsocketData(data);
|
|
123
118
|
if (this.cache.has(cacheKey)) {
|
|
124
119
|
this.logger.debug("Dropping duplicate message");
|
|
@@ -128,10 +123,10 @@ export class WebSocketPool {
|
|
|
128
123
|
if (typeof data === "string") {
|
|
129
124
|
this.handleErrorMessages(data);
|
|
130
125
|
}
|
|
131
|
-
await Promise.all(this.messageListeners.map((handler)
|
|
126
|
+
await Promise.all(this.messageListeners.map((handler)=>handler(data)));
|
|
132
127
|
};
|
|
133
128
|
sendRequest(request) {
|
|
134
|
-
for (const rws of this.rwsPool)
|
|
129
|
+
for (const rws of this.rwsPool){
|
|
135
130
|
rws.send(JSON.stringify(request));
|
|
136
131
|
}
|
|
137
132
|
}
|
|
@@ -146,7 +141,7 @@ export class WebSocketPool {
|
|
|
146
141
|
this.subscriptions.delete(subscriptionId);
|
|
147
142
|
const request = {
|
|
148
143
|
type: "unsubscribe",
|
|
149
|
-
subscriptionId
|
|
144
|
+
subscriptionId
|
|
150
145
|
};
|
|
151
146
|
this.sendRequest(request);
|
|
152
147
|
}
|
|
@@ -154,17 +149,16 @@ export class WebSocketPool {
|
|
|
154
149
|
this.messageListeners.push(handler);
|
|
155
150
|
}
|
|
156
151
|
/**
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
addAllConnectionsDownListener(handler) {
|
|
152
|
+
* Calls the handler if all websocket connections are currently down or in reconnecting state.
|
|
153
|
+
* The connections may still try to reconnect in the background.
|
|
154
|
+
*/ addAllConnectionsDownListener(handler) {
|
|
161
155
|
this.allConnectionsDownListeners.push(handler);
|
|
162
156
|
}
|
|
163
157
|
areAllConnectionsDown() {
|
|
164
|
-
return this.rwsPool.every((ws)
|
|
158
|
+
return this.rwsPool.every((ws)=>!ws.isConnected() || ws.isReconnecting());
|
|
165
159
|
}
|
|
166
160
|
isAnyConnectionEstablished() {
|
|
167
|
-
return this.rwsPool.some((ws)
|
|
161
|
+
return this.rwsPool.some((ws)=>ws.isConnected());
|
|
168
162
|
}
|
|
169
163
|
checkConnectionStates() {
|
|
170
164
|
const allDown = this.areAllConnectionsDown();
|
|
@@ -173,7 +167,7 @@ export class WebSocketPool {
|
|
|
173
167
|
this.wasAllDown = true;
|
|
174
168
|
this.logger.error("All WebSocket connections are down or reconnecting");
|
|
175
169
|
// Notify all listeners
|
|
176
|
-
for (const listener of this.allConnectionsDownListeners)
|
|
170
|
+
for (const listener of this.allConnectionsDownListeners){
|
|
177
171
|
listener();
|
|
178
172
|
}
|
|
179
173
|
}
|
|
@@ -183,7 +177,7 @@ export class WebSocketPool {
|
|
|
183
177
|
}
|
|
184
178
|
}
|
|
185
179
|
shutdown() {
|
|
186
|
-
for (const rws of this.rwsPool)
|
|
180
|
+
for (const rws of this.rwsPool){
|
|
187
181
|
rws.closeWebSocket();
|
|
188
182
|
}
|
|
189
183
|
this.rwsPool = [];
|
|
@@ -8,19 +8,16 @@ const BufferClassToUse = "Buffer" in globalThis ? globalThis.Buffer : BrowserBuf
|
|
|
8
8
|
* given a relatively unknown websocket frame data object,
|
|
9
9
|
* returns a valid Buffer instance that is safe to use
|
|
10
10
|
* isomorphically in any JS runtime environment
|
|
11
|
-
*/
|
|
12
|
-
export async function bufferFromWebsocketData(data) {
|
|
11
|
+
*/ export async function bufferFromWebsocketData(data) {
|
|
13
12
|
if (typeof data === "string") {
|
|
14
13
|
return BufferClassToUse.from(new TextEncoder().encode(data).buffer);
|
|
15
14
|
}
|
|
16
|
-
if (data instanceof BufferClassToUse)
|
|
17
|
-
return data;
|
|
15
|
+
if (data instanceof BufferClassToUse) return data;
|
|
18
16
|
if (data instanceof Blob) {
|
|
19
17
|
// let the uncaught promise exception bubble up if there's an issue
|
|
20
18
|
return BufferClassToUse.from(await data.arrayBuffer());
|
|
21
19
|
}
|
|
22
|
-
if (data instanceof ArrayBuffer)
|
|
23
|
-
return BufferClassToUse.from(data);
|
|
20
|
+
if (data instanceof ArrayBuffer) return BufferClassToUse.from(data);
|
|
24
21
|
if (Array.isArray(data)) {
|
|
25
22
|
// an array of buffers is highly unlikely, but it is a possibility
|
|
26
23
|
// indicated by the WebSocket Data interface
|
|
@@ -4,16 +4,13 @@ const g = globalThis;
|
|
|
4
4
|
/**
|
|
5
5
|
* Detects if this code is running within any Service or WebWorker context.
|
|
6
6
|
* @returns true if in a worker of some kind, false if otherwise
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
return (typeof WorkerGlobalScope !== "undefined" &&
|
|
10
|
-
g.self instanceof WorkerGlobalScope);
|
|
7
|
+
*/ export function envIsServiceOrWebWorker() {
|
|
8
|
+
return typeof WorkerGlobalScope !== "undefined" && g.self instanceof WorkerGlobalScope;
|
|
11
9
|
}
|
|
12
10
|
/**
|
|
13
11
|
* Detects if the code is running in a regular DOM or Web Worker context.
|
|
14
12
|
* @returns true if running in a DOM or Web Worker context, false if running in Node.js
|
|
15
|
-
*/
|
|
16
|
-
export function envIsBrowser() {
|
|
13
|
+
*/ export function envIsBrowser() {
|
|
17
14
|
return g.window !== undefined;
|
|
18
15
|
}
|
|
19
16
|
/**
|
|
@@ -21,7 +18,6 @@ export function envIsBrowser() {
|
|
|
21
18
|
* this code is executing in some type of browser-centric environment
|
|
22
19
|
*
|
|
23
20
|
* @returns true if in the browser's main UI thread or in a worker, false if otherwise
|
|
24
|
-
*/
|
|
25
|
-
export function envIsBrowserOrWorker() {
|
|
21
|
+
*/ export function envIsBrowserOrWorker() {
|
|
26
22
|
return envIsServiceOrWebWorker() || envIsBrowser();
|
|
27
23
|
}
|
|
@@ -5,10 +5,8 @@ const ACCESS_TOKEN_QUERY_PARAM_KEY = "ACCESS_TOKEN";
|
|
|
5
5
|
* contained within.
|
|
6
6
|
* If the URL provided is nullish, it is returned as-is (in the same nullish format).
|
|
7
7
|
* If the token is nullish, the baseUrl given is returned, instead.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
if (!baseUrl || !authToken)
|
|
11
|
-
return baseUrl;
|
|
8
|
+
*/ export function addAuthTokenToWebSocketUrl(baseUrl, authToken) {
|
|
9
|
+
if (!baseUrl || !authToken) return baseUrl;
|
|
12
10
|
const parsedUrl = new URL(baseUrl);
|
|
13
11
|
parsedUrl.searchParams.set(ACCESS_TOKEN_QUERY_PARAM_KEY, authToken);
|
|
14
12
|
return parsedUrl.toString();
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pythnetwork/pyth-lazer-sdk",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "Pyth Lazer SDK",
|
|
5
5
|
"engines": {
|
|
6
|
-
"node": ">=22"
|
|
6
|
+
"node": ">=22.14.0"
|
|
7
7
|
},
|
|
8
8
|
"publishConfig": {
|
|
9
9
|
"access": "public"
|
|
@@ -11,17 +11,110 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
"dist/**/*"
|
|
13
13
|
],
|
|
14
|
-
"main": "./dist/cjs/index.
|
|
14
|
+
"main": "./dist/cjs/index.cjs",
|
|
15
15
|
"types": "./dist/cjs/index.d.ts",
|
|
16
16
|
"exports": {
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
17
|
+
"./client": {
|
|
18
|
+
"require": {
|
|
19
|
+
"types": "./dist/cjs/client.d.ts",
|
|
20
|
+
"default": "./dist/cjs/client.cjs"
|
|
21
|
+
},
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./dist/esm/client.d.ts",
|
|
24
|
+
"default": "./dist/esm/client.mjs"
|
|
25
|
+
}
|
|
20
26
|
},
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
"./constants": {
|
|
28
|
+
"require": {
|
|
29
|
+
"types": "./dist/cjs/constants.d.ts",
|
|
30
|
+
"default": "./dist/cjs/constants.cjs"
|
|
31
|
+
},
|
|
32
|
+
"import": {
|
|
33
|
+
"types": "./dist/esm/constants.d.ts",
|
|
34
|
+
"default": "./dist/esm/constants.mjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
".": {
|
|
38
|
+
"require": {
|
|
39
|
+
"types": "./dist/cjs/index.d.ts",
|
|
40
|
+
"default": "./dist/cjs/index.cjs"
|
|
41
|
+
},
|
|
42
|
+
"import": {
|
|
43
|
+
"types": "./dist/esm/index.d.ts",
|
|
44
|
+
"default": "./dist/esm/index.mjs"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"./protocol": {
|
|
48
|
+
"require": {
|
|
49
|
+
"types": "./dist/cjs/protocol.d.ts",
|
|
50
|
+
"default": "./dist/cjs/protocol.cjs"
|
|
51
|
+
},
|
|
52
|
+
"import": {
|
|
53
|
+
"types": "./dist/esm/protocol.d.ts",
|
|
54
|
+
"default": "./dist/esm/protocol.mjs"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"./socket/resilient-websocket": {
|
|
58
|
+
"require": {
|
|
59
|
+
"types": "./dist/cjs/socket/resilient-websocket.d.ts",
|
|
60
|
+
"default": "./dist/cjs/socket/resilient-websocket.cjs"
|
|
61
|
+
},
|
|
62
|
+
"import": {
|
|
63
|
+
"types": "./dist/esm/socket/resilient-websocket.d.ts",
|
|
64
|
+
"default": "./dist/esm/socket/resilient-websocket.mjs"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"./socket/websocket-pool": {
|
|
68
|
+
"require": {
|
|
69
|
+
"types": "./dist/cjs/socket/websocket-pool.d.ts",
|
|
70
|
+
"default": "./dist/cjs/socket/websocket-pool.cjs"
|
|
71
|
+
},
|
|
72
|
+
"import": {
|
|
73
|
+
"types": "./dist/esm/socket/websocket-pool.d.ts",
|
|
74
|
+
"default": "./dist/esm/socket/websocket-pool.mjs"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"./util/buffer-util": {
|
|
78
|
+
"require": {
|
|
79
|
+
"types": "./dist/cjs/util/buffer-util.d.ts",
|
|
80
|
+
"default": "./dist/cjs/util/buffer-util.cjs"
|
|
81
|
+
},
|
|
82
|
+
"import": {
|
|
83
|
+
"types": "./dist/esm/util/buffer-util.d.ts",
|
|
84
|
+
"default": "./dist/esm/util/buffer-util.mjs"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"./util/env-util": {
|
|
88
|
+
"require": {
|
|
89
|
+
"types": "./dist/cjs/util/env-util.d.ts",
|
|
90
|
+
"default": "./dist/cjs/util/env-util.cjs"
|
|
91
|
+
},
|
|
92
|
+
"import": {
|
|
93
|
+
"types": "./dist/esm/util/env-util.d.ts",
|
|
94
|
+
"default": "./dist/esm/util/env-util.mjs"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"./util": {
|
|
98
|
+
"require": {
|
|
99
|
+
"types": "./dist/cjs/util/index.d.ts",
|
|
100
|
+
"default": "./dist/cjs/util/index.cjs"
|
|
101
|
+
},
|
|
102
|
+
"import": {
|
|
103
|
+
"types": "./dist/esm/util/index.d.ts",
|
|
104
|
+
"default": "./dist/esm/util/index.mjs"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"./util/url-util": {
|
|
108
|
+
"require": {
|
|
109
|
+
"types": "./dist/cjs/util/url-util.d.ts",
|
|
110
|
+
"default": "./dist/cjs/util/url-util.cjs"
|
|
111
|
+
},
|
|
112
|
+
"import": {
|
|
113
|
+
"types": "./dist/esm/util/url-util.d.ts",
|
|
114
|
+
"default": "./dist/esm/util/url-util.mjs"
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"./package.json": "./package.json"
|
|
25
118
|
},
|
|
26
119
|
"devDependencies": {
|
|
27
120
|
"@cprussin/eslint-config": "^4.0.2",
|
|
@@ -31,8 +124,7 @@
|
|
|
31
124
|
"eslint": "^9.23.0",
|
|
32
125
|
"prettier": "^3.5.3",
|
|
33
126
|
"ts-node": "^10.9.2",
|
|
34
|
-
"typedoc": "^0.26.8"
|
|
35
|
-
"typescript": "^5.8.2"
|
|
127
|
+
"typedoc": "^0.26.8"
|
|
36
128
|
},
|
|
37
129
|
"bugs": {
|
|
38
130
|
"url": "https://github.com/pyth-network/pyth-crosschain/issues"
|
|
@@ -56,9 +148,9 @@
|
|
|
56
148
|
"ts-log": "^2.2.7",
|
|
57
149
|
"ws": "^8.18.0"
|
|
58
150
|
},
|
|
151
|
+
"module": "./dist/esm/index.mjs",
|
|
59
152
|
"scripts": {
|
|
60
|
-
"build
|
|
61
|
-
"build:esm": "tsc --project tsconfig.build.json --outDir ./dist/esm && echo '{\"type\":\"module\"}' > dist/esm/package.json",
|
|
153
|
+
"build": "ts-duality --clean",
|
|
62
154
|
"fix:lint": "eslint --fix . --max-warnings 0",
|
|
63
155
|
"test:lint": "eslint . --max-warnings 0",
|
|
64
156
|
"test:types": "tsc",
|
|
@@ -67,6 +159,7 @@
|
|
|
67
159
|
"example:streaming": "node --loader ts-node/esm examples/streaming.js",
|
|
68
160
|
"example:history": "node --loader ts-node/esm examples/history.js",
|
|
69
161
|
"example:symbols": "node --loader ts-node/esm examples/symbols.js",
|
|
70
|
-
"doc": "typedoc --out docs/typedoc src"
|
|
162
|
+
"doc": "typedoc --out docs/typedoc src",
|
|
163
|
+
"clean": "rm -rf ./dist"
|
|
71
164
|
}
|
|
72
165
|
}
|
package/dist/cjs/constants.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_STREAM_SERVICE_1_URL = exports.DEFAULT_STREAM_SERVICE_0_URL = exports.DEFAULT_PRICE_SERVICE_URL = exports.DEFAULT_METADATA_SERVICE_URL = exports.SOLANA_LAZER_STORAGE_ID = exports.SOLANA_LAZER_PROGRAM_ID = void 0;
|
|
4
|
-
exports.SOLANA_LAZER_PROGRAM_ID = "pytd2yyk641x7ak7mkaasSJVXh6YYZnC7wTmtgAyxPt";
|
|
5
|
-
exports.SOLANA_LAZER_STORAGE_ID = "3rdJbqfnagQ4yx9HXJViD4zc4xpiSqmFsKpPuSCQVyQL";
|
|
6
|
-
exports.DEFAULT_METADATA_SERVICE_URL = "https://history.pyth-lazer.dourolabs.app/history";
|
|
7
|
-
exports.DEFAULT_PRICE_SERVICE_URL = "https://pyth-lazer-0.dourolabs.app";
|
|
8
|
-
exports.DEFAULT_STREAM_SERVICE_0_URL = "wss://pyth-lazer-0.dourolabs.app/v1/stream";
|
|
9
|
-
exports.DEFAULT_STREAM_SERVICE_1_URL = "wss://pyth-lazer-1.dourolabs.app/v1/stream";
|
package/dist/cjs/index.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./client.js"), exports);
|
|
18
|
-
__exportStar(require("./protocol.js"), exports);
|
|
19
|
-
__exportStar(require("./constants.js"), exports);
|