@pythnetwork/pyth-lazer-sdk 5.0.0 → 5.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.
Files changed (41) hide show
  1. package/dist/cjs/{client.js → client.cjs} +93 -98
  2. package/dist/cjs/constants.cjs +36 -0
  3. package/dist/cjs/emitter/index.cjs +53 -0
  4. package/dist/cjs/emitter/index.d.ts +29 -0
  5. package/dist/cjs/index.cjs +20 -0
  6. package/dist/cjs/package.json +1 -1
  7. package/dist/cjs/protocol.cjs +33 -0
  8. package/dist/cjs/protocol.d.ts +1 -1
  9. package/dist/cjs/socket/{resilient-websocket.js → resilient-websocket.cjs} +47 -48
  10. package/dist/cjs/socket/websocket-pool.cjs +253 -0
  11. package/dist/cjs/socket/websocket-pool.d.ts +37 -3
  12. package/dist/cjs/util/{buffer-util.js → buffer-util.cjs} +14 -14
  13. package/dist/cjs/util/env-util.cjs +33 -0
  14. package/dist/cjs/util/index.cjs +20 -0
  15. package/dist/cjs/util/url-util.cjs +17 -0
  16. package/dist/esm/{client.js → client.mjs} +76 -88
  17. package/dist/esm/emitter/index.d.ts +29 -0
  18. package/dist/esm/emitter/index.mjs +43 -0
  19. package/dist/esm/index.mjs +3 -0
  20. package/dist/esm/package.json +1 -1
  21. package/dist/esm/protocol.d.ts +1 -1
  22. package/dist/esm/{protocol.js → protocol.mjs} +4 -4
  23. package/dist/esm/socket/{resilient-websocket.js → resilient-websocket.mjs} +27 -36
  24. package/dist/esm/socket/websocket-pool.d.ts +37 -3
  25. package/dist/esm/socket/websocket-pool.mjs +238 -0
  26. package/dist/esm/util/{buffer-util.js → buffer-util.mjs} +3 -6
  27. package/dist/esm/util/{env-util.js → env-util.mjs} +4 -8
  28. package/dist/esm/util/index.mjs +3 -0
  29. package/dist/esm/util/{url-util.js → url-util.mjs} +2 -4
  30. package/package.json +119 -15
  31. package/dist/cjs/constants.js +0 -9
  32. package/dist/cjs/index.js +0 -19
  33. package/dist/cjs/protocol.js +0 -15
  34. package/dist/cjs/socket/websocket-pool.js +0 -201
  35. package/dist/cjs/util/env-util.js +0 -32
  36. package/dist/cjs/util/index.js +0 -19
  37. package/dist/cjs/util/url-util.js +0 -18
  38. package/dist/esm/index.js +0 -3
  39. package/dist/esm/socket/websocket-pool.js +0 -195
  40. package/dist/esm/util/index.js +0 -3
  41. /package/dist/esm/{constants.js → constants.mjs} +0 -0
@@ -1,201 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.WebSocketPool = void 0;
7
- const ttlcache_1 = __importDefault(require("@isaacs/ttlcache"));
8
- const ts_log_1 = require("ts-log");
9
- const resilient_websocket_js_1 = require("./resilient-websocket.js");
10
- const constants_js_1 = require("../constants.js");
11
- const index_js_1 = require("../util/index.js");
12
- const DEFAULT_NUM_CONNECTIONS = 4;
13
- class WebSocketPool {
14
- logger;
15
- rwsPool;
16
- cache;
17
- subscriptions; // id -> subscription Request
18
- messageListeners;
19
- allConnectionsDownListeners;
20
- wasAllDown = true;
21
- checkConnectionStatesInterval;
22
- constructor(logger) {
23
- this.logger = logger;
24
- this.rwsPool = [];
25
- this.cache = new ttlcache_1.default({ ttl: 1000 * 10 }); // TTL of 10 seconds
26
- this.subscriptions = new Map();
27
- this.messageListeners = [];
28
- this.allConnectionsDownListeners = [];
29
- // Start monitoring connection states
30
- this.checkConnectionStatesInterval = setInterval(() => {
31
- this.checkConnectionStates();
32
- }, 100);
33
- }
34
- /**
35
- * Creates a new WebSocketPool instance that uses multiple redundant WebSocket connections for reliability.
36
- * Usage semantics are similar to using a regular WebSocket client.
37
- * @param urls - List of WebSocket URLs to connect to
38
- * @param token - Authentication token to use for the connections
39
- * @param numConnections - Number of parallel WebSocket connections to maintain (default: 3)
40
- * @param logger - Optional logger to get socket level logs. Compatible with most loggers such as the built-in console and `bunyan`.
41
- */
42
- static async create(config, token, logger) {
43
- const urls = config.urls ?? [
44
- constants_js_1.DEFAULT_STREAM_SERVICE_0_URL,
45
- constants_js_1.DEFAULT_STREAM_SERVICE_1_URL,
46
- ];
47
- const log = logger ?? ts_log_1.dummyLogger;
48
- const pool = new WebSocketPool(log);
49
- const numConnections = config.numConnections ?? DEFAULT_NUM_CONNECTIONS;
50
- for (let i = 0; i < numConnections; i++) {
51
- const baseUrl = urls[i % urls.length];
52
- const isBrowser = (0, index_js_1.envIsBrowserOrWorker)();
53
- const url = isBrowser
54
- ? (0, index_js_1.addAuthTokenToWebSocketUrl)(baseUrl, token)
55
- : baseUrl;
56
- if (!url) {
57
- throw new Error(`URLs must not be null or empty`);
58
- }
59
- const wsOptions = {
60
- ...config.rwsConfig?.wsOptions,
61
- headers: isBrowser ? undefined : { Authorization: `Bearer ${token}` },
62
- };
63
- const rws = new resilient_websocket_js_1.ResilientWebSocket({
64
- ...config.rwsConfig,
65
- endpoint: url,
66
- wsOptions,
67
- logger: log,
68
- });
69
- // If a websocket client unexpectedly disconnects, ResilientWebSocket will reestablish
70
- // the connection and call the onReconnect callback.
71
- rws.onReconnect = () => {
72
- if (rws.wsUserClosed) {
73
- return;
74
- }
75
- for (const [, request] of pool.subscriptions) {
76
- try {
77
- rws.send(JSON.stringify(request));
78
- }
79
- catch (error) {
80
- pool.logger.error("Failed to resend subscription on reconnect:", error);
81
- }
82
- }
83
- };
84
- if (config.onError) {
85
- rws.onError = config.onError;
86
- }
87
- // Handle all client messages ourselves. Dedupe before sending to registered message handlers.
88
- rws.onMessage = (data) => {
89
- pool.dedupeHandler(data).catch((error) => {
90
- const errMsg = `An error occurred in the WebSocket pool's dedupeHandler: ${error instanceof Error ? error.message : String(error)}`;
91
- throw new Error(errMsg);
92
- });
93
- };
94
- pool.rwsPool.push(rws);
95
- rws.startWebSocket();
96
- }
97
- pool.logger.info(`Started WebSocketPool with ${numConnections.toString()} connections. Waiting for at least one to connect...`);
98
- while (!pool.isAnyConnectionEstablished()) {
99
- await new Promise((resolve) => setTimeout(resolve, 100));
100
- }
101
- pool.logger.info(`At least one WebSocket connection is established. WebSocketPool is ready.`);
102
- return pool;
103
- }
104
- /**
105
- * Checks for error responses in JSON messages and throws appropriate errors
106
- */
107
- handleErrorMessages(data) {
108
- const message = JSON.parse(data);
109
- if (message.type === "subscriptionError") {
110
- throw new Error(`Error occurred for subscription ID ${String(message.subscriptionId)}: ${message.error}`);
111
- }
112
- else if (message.type === "error") {
113
- throw new Error(`Error: ${message.error}`);
114
- }
115
- }
116
- async constructCacheKeyFromWebsocketData(data) {
117
- if (typeof data === "string")
118
- return data;
119
- const buff = await (0, index_js_1.bufferFromWebsocketData)(data);
120
- return buff.toString("hex");
121
- }
122
- /**
123
- * Handles incoming websocket messages by deduplicating identical messages received across
124
- * multiple connections before forwarding to registered handlers
125
- */
126
- dedupeHandler = async (data) => {
127
- const cacheKey = await this.constructCacheKeyFromWebsocketData(data);
128
- if (this.cache.has(cacheKey)) {
129
- this.logger.debug("Dropping duplicate message");
130
- return;
131
- }
132
- this.cache.set(cacheKey, true);
133
- if (typeof data === "string") {
134
- this.handleErrorMessages(data);
135
- }
136
- await Promise.all(this.messageListeners.map((handler) => handler(data)));
137
- };
138
- sendRequest(request) {
139
- for (const rws of this.rwsPool) {
140
- rws.send(JSON.stringify(request));
141
- }
142
- }
143
- addSubscription(request) {
144
- if (request.type !== "subscribe") {
145
- throw new Error("Request must be a subscribe request");
146
- }
147
- this.subscriptions.set(request.subscriptionId, request);
148
- this.sendRequest(request);
149
- }
150
- removeSubscription(subscriptionId) {
151
- this.subscriptions.delete(subscriptionId);
152
- const request = {
153
- type: "unsubscribe",
154
- subscriptionId,
155
- };
156
- this.sendRequest(request);
157
- }
158
- addMessageListener(handler) {
159
- this.messageListeners.push(handler);
160
- }
161
- /**
162
- * Calls the handler if all websocket connections are currently down or in reconnecting state.
163
- * The connections may still try to reconnect in the background.
164
- */
165
- addAllConnectionsDownListener(handler) {
166
- this.allConnectionsDownListeners.push(handler);
167
- }
168
- areAllConnectionsDown() {
169
- return this.rwsPool.every((ws) => !ws.isConnected() || ws.isReconnecting());
170
- }
171
- isAnyConnectionEstablished() {
172
- return this.rwsPool.some((ws) => ws.isConnected());
173
- }
174
- checkConnectionStates() {
175
- const allDown = this.areAllConnectionsDown();
176
- // If all connections just went down
177
- if (allDown && !this.wasAllDown) {
178
- this.wasAllDown = true;
179
- this.logger.error("All WebSocket connections are down or reconnecting");
180
- // Notify all listeners
181
- for (const listener of this.allConnectionsDownListeners) {
182
- listener();
183
- }
184
- }
185
- // If at least one connection was restored
186
- if (!allDown && this.wasAllDown) {
187
- this.wasAllDown = false;
188
- }
189
- }
190
- shutdown() {
191
- for (const rws of this.rwsPool) {
192
- rws.closeWebSocket();
193
- }
194
- this.rwsPool = [];
195
- this.subscriptions.clear();
196
- this.messageListeners = [];
197
- this.allConnectionsDownListeners = [];
198
- clearInterval(this.checkConnectionStatesInterval);
199
- }
200
- }
201
- exports.WebSocketPool = WebSocketPool;
@@ -1,32 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.envIsServiceOrWebWorker = envIsServiceOrWebWorker;
4
- exports.envIsBrowser = envIsBrowser;
5
- exports.envIsBrowserOrWorker = envIsBrowserOrWorker;
6
- // we create this local-only type, which has assertions made to indicate
7
- // that we do not know and cannot guarantee which JS environment we are in
8
- const g = globalThis;
9
- /**
10
- * Detects if this code is running within any Service or WebWorker context.
11
- * @returns true if in a worker of some kind, false if otherwise
12
- */
13
- function envIsServiceOrWebWorker() {
14
- return (typeof WorkerGlobalScope !== "undefined" &&
15
- g.self instanceof WorkerGlobalScope);
16
- }
17
- /**
18
- * Detects if the code is running in a regular DOM or Web Worker context.
19
- * @returns true if running in a DOM or Web Worker context, false if running in Node.js
20
- */
21
- function envIsBrowser() {
22
- return g.window !== undefined;
23
- }
24
- /**
25
- * a convenience method that returns whether or not
26
- * this code is executing in some type of browser-centric environment
27
- *
28
- * @returns true if in the browser's main UI thread or in a worker, false if otherwise
29
- */
30
- function envIsBrowserOrWorker() {
31
- return envIsServiceOrWebWorker() || envIsBrowser();
32
- }
@@ -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("./buffer-util.js"), exports);
18
- __exportStar(require("./env-util.js"), exports);
19
- __exportStar(require("./url-util.js"), exports);
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.addAuthTokenToWebSocketUrl = addAuthTokenToWebSocketUrl;
4
- const ACCESS_TOKEN_QUERY_PARAM_KEY = "ACCESS_TOKEN";
5
- /**
6
- * Given a URL to a hosted lazer stream service and a possible auth token,
7
- * appends the auth token as a query parameter and returns the URL with the token
8
- * contained within.
9
- * If the URL provided is nullish, it is returned as-is (in the same nullish format).
10
- * If the token is nullish, the baseUrl given is returned, instead.
11
- */
12
- function addAuthTokenToWebSocketUrl(baseUrl, authToken) {
13
- if (!baseUrl || !authToken)
14
- return baseUrl;
15
- const parsedUrl = new URL(baseUrl);
16
- parsedUrl.searchParams.set(ACCESS_TOKEN_QUERY_PARAM_KEY, authToken);
17
- return parsedUrl.toString();
18
- }
package/dist/esm/index.js DELETED
@@ -1,3 +0,0 @@
1
- export * from "./client.js";
2
- export * from "./protocol.js";
3
- export * from "./constants.js";
@@ -1,195 +0,0 @@
1
- import TTLCache from "@isaacs/ttlcache";
2
- import WebSocket from "isomorphic-ws";
3
- import { dummyLogger } from "ts-log";
4
- import { ResilientWebSocket } from "./resilient-websocket.js";
5
- import { DEFAULT_STREAM_SERVICE_0_URL, DEFAULT_STREAM_SERVICE_1_URL, } from "../constants.js";
6
- import { addAuthTokenToWebSocketUrl, bufferFromWebsocketData, envIsBrowserOrWorker, } from "../util/index.js";
7
- const DEFAULT_NUM_CONNECTIONS = 4;
8
- export class WebSocketPool {
9
- logger;
10
- rwsPool;
11
- cache;
12
- subscriptions; // id -> subscription Request
13
- messageListeners;
14
- allConnectionsDownListeners;
15
- wasAllDown = true;
16
- checkConnectionStatesInterval;
17
- constructor(logger) {
18
- this.logger = logger;
19
- this.rwsPool = [];
20
- this.cache = new TTLCache({ ttl: 1000 * 10 }); // TTL of 10 seconds
21
- this.subscriptions = new Map();
22
- this.messageListeners = [];
23
- this.allConnectionsDownListeners = [];
24
- // Start monitoring connection states
25
- this.checkConnectionStatesInterval = setInterval(() => {
26
- this.checkConnectionStates();
27
- }, 100);
28
- }
29
- /**
30
- * Creates a new WebSocketPool instance that uses multiple redundant WebSocket connections for reliability.
31
- * Usage semantics are similar to using a regular WebSocket client.
32
- * @param urls - List of WebSocket URLs to connect to
33
- * @param token - Authentication token to use for the connections
34
- * @param numConnections - Number of parallel WebSocket connections to maintain (default: 3)
35
- * @param logger - Optional logger to get socket level logs. Compatible with most loggers such as the built-in console and `bunyan`.
36
- */
37
- static async create(config, token, logger) {
38
- const urls = config.urls ?? [
39
- DEFAULT_STREAM_SERVICE_0_URL,
40
- DEFAULT_STREAM_SERVICE_1_URL,
41
- ];
42
- const log = logger ?? dummyLogger;
43
- const pool = new WebSocketPool(log);
44
- const numConnections = config.numConnections ?? DEFAULT_NUM_CONNECTIONS;
45
- for (let i = 0; i < numConnections; i++) {
46
- const baseUrl = urls[i % urls.length];
47
- const isBrowser = envIsBrowserOrWorker();
48
- const url = isBrowser
49
- ? addAuthTokenToWebSocketUrl(baseUrl, token)
50
- : baseUrl;
51
- if (!url) {
52
- throw new Error(`URLs must not be null or empty`);
53
- }
54
- const wsOptions = {
55
- ...config.rwsConfig?.wsOptions,
56
- headers: isBrowser ? undefined : { Authorization: `Bearer ${token}` },
57
- };
58
- const rws = new ResilientWebSocket({
59
- ...config.rwsConfig,
60
- endpoint: url,
61
- wsOptions,
62
- logger: log,
63
- });
64
- // If a websocket client unexpectedly disconnects, ResilientWebSocket will reestablish
65
- // the connection and call the onReconnect callback.
66
- rws.onReconnect = () => {
67
- if (rws.wsUserClosed) {
68
- return;
69
- }
70
- for (const [, request] of pool.subscriptions) {
71
- try {
72
- rws.send(JSON.stringify(request));
73
- }
74
- catch (error) {
75
- pool.logger.error("Failed to resend subscription on reconnect:", error);
76
- }
77
- }
78
- };
79
- if (config.onError) {
80
- rws.onError = config.onError;
81
- }
82
- // Handle all client messages ourselves. Dedupe before sending to registered message handlers.
83
- rws.onMessage = (data) => {
84
- pool.dedupeHandler(data).catch((error) => {
85
- const errMsg = `An error occurred in the WebSocket pool's dedupeHandler: ${error instanceof Error ? error.message : String(error)}`;
86
- throw new Error(errMsg);
87
- });
88
- };
89
- pool.rwsPool.push(rws);
90
- rws.startWebSocket();
91
- }
92
- pool.logger.info(`Started WebSocketPool with ${numConnections.toString()} connections. Waiting for at least one to connect...`);
93
- while (!pool.isAnyConnectionEstablished()) {
94
- await new Promise((resolve) => setTimeout(resolve, 100));
95
- }
96
- pool.logger.info(`At least one WebSocket connection is established. WebSocketPool is ready.`);
97
- return pool;
98
- }
99
- /**
100
- * Checks for error responses in JSON messages and throws appropriate errors
101
- */
102
- handleErrorMessages(data) {
103
- const message = JSON.parse(data);
104
- if (message.type === "subscriptionError") {
105
- throw new Error(`Error occurred for subscription ID ${String(message.subscriptionId)}: ${message.error}`);
106
- }
107
- else if (message.type === "error") {
108
- throw new Error(`Error: ${message.error}`);
109
- }
110
- }
111
- async constructCacheKeyFromWebsocketData(data) {
112
- if (typeof data === "string")
113
- return data;
114
- const buff = await bufferFromWebsocketData(data);
115
- return buff.toString("hex");
116
- }
117
- /**
118
- * Handles incoming websocket messages by deduplicating identical messages received across
119
- * multiple connections before forwarding to registered handlers
120
- */
121
- dedupeHandler = async (data) => {
122
- const cacheKey = await this.constructCacheKeyFromWebsocketData(data);
123
- if (this.cache.has(cacheKey)) {
124
- this.logger.debug("Dropping duplicate message");
125
- return;
126
- }
127
- this.cache.set(cacheKey, true);
128
- if (typeof data === "string") {
129
- this.handleErrorMessages(data);
130
- }
131
- await Promise.all(this.messageListeners.map((handler) => handler(data)));
132
- };
133
- sendRequest(request) {
134
- for (const rws of this.rwsPool) {
135
- rws.send(JSON.stringify(request));
136
- }
137
- }
138
- addSubscription(request) {
139
- if (request.type !== "subscribe") {
140
- throw new Error("Request must be a subscribe request");
141
- }
142
- this.subscriptions.set(request.subscriptionId, request);
143
- this.sendRequest(request);
144
- }
145
- removeSubscription(subscriptionId) {
146
- this.subscriptions.delete(subscriptionId);
147
- const request = {
148
- type: "unsubscribe",
149
- subscriptionId,
150
- };
151
- this.sendRequest(request);
152
- }
153
- addMessageListener(handler) {
154
- this.messageListeners.push(handler);
155
- }
156
- /**
157
- * Calls the handler if all websocket connections are currently down or in reconnecting state.
158
- * The connections may still try to reconnect in the background.
159
- */
160
- addAllConnectionsDownListener(handler) {
161
- this.allConnectionsDownListeners.push(handler);
162
- }
163
- areAllConnectionsDown() {
164
- return this.rwsPool.every((ws) => !ws.isConnected() || ws.isReconnecting());
165
- }
166
- isAnyConnectionEstablished() {
167
- return this.rwsPool.some((ws) => ws.isConnected());
168
- }
169
- checkConnectionStates() {
170
- const allDown = this.areAllConnectionsDown();
171
- // If all connections just went down
172
- if (allDown && !this.wasAllDown) {
173
- this.wasAllDown = true;
174
- this.logger.error("All WebSocket connections are down or reconnecting");
175
- // Notify all listeners
176
- for (const listener of this.allConnectionsDownListeners) {
177
- listener();
178
- }
179
- }
180
- // If at least one connection was restored
181
- if (!allDown && this.wasAllDown) {
182
- this.wasAllDown = false;
183
- }
184
- }
185
- shutdown() {
186
- for (const rws of this.rwsPool) {
187
- rws.closeWebSocket();
188
- }
189
- this.rwsPool = [];
190
- this.subscriptions.clear();
191
- this.messageListeners = [];
192
- this.allConnectionsDownListeners = [];
193
- clearInterval(this.checkConnectionStatesInterval);
194
- }
195
- }
@@ -1,3 +0,0 @@
1
- export * from "./buffer-util.js";
2
- export * from "./env-util.js";
3
- export * from "./url-util.js";
File without changes