浏览代码

chore(lazer-sdk-js): fixed formatting

benduran 1 月之前
父节点
当前提交
b0d6e55e1c

+ 49 - 49
lazer/sdk/js/README.md

@@ -7,56 +7,56 @@ See [contributing.md](docs/contributing/contributing.md) for information on how
 ## How to use
 
 ```javascript
-import { PythLazerClient } from '@pythnetwork/pyth-lazer-sdk';
+import { PythLazerClient } from "@pythnetwork/pyth-lazer-sdk";
 
 const c = await PythLazerClient.create({
-    token: 'YOUR-AUTH-TOKEN-HERE',
-    logger: console, // Optionally log operations (to the console in this case.)
-    webSocketPoolConfig: {
-      numConnections: 4, // Optionally specify number of parallel redundant connections to reduce the chance of dropped messages. The connections will round-robin across the provided URLs. Default is 4.
-      onError: error => {
-        console.error('⛔️ WebSocket error:', error.message);
-      },
-      // Optional configuration for resilient WebSocket connections
-      rwsConfig: {
-        heartbeatTimeoutDurationMs: 5000, // Optional heartbeat timeout duration in milliseconds
-        maxRetryDelayMs: 1000, // Optional maximum retry delay in milliseconds
-        logAfterRetryCount: 10, // Optional log after how many retries
-      },
+  token: "YOUR-AUTH-TOKEN-HERE",
+  logger: console, // Optionally log operations (to the console in this case.)
+  webSocketPoolConfig: {
+    numConnections: 4, // Optionally specify number of parallel redundant connections to reduce the chance of dropped messages. The connections will round-robin across the provided URLs. Default is 4.
+    onError: (error) => {
+      console.error("⛔️ WebSocket error:", error.message);
     },
-  });
-
-  c.addMessageListener(message => {
-    console.info('received the following from the Lazer stream:', message);
-  });
-
-  // Monitor for all connections in the pool being down simultaneously (e.g. if the internet goes down)
-  // The connections may still try to reconnect in the background. To shut down the client completely, call shutdown().
-  c.addAllConnectionsDownListener(() => {
-    console.error('All connections are down!');
-  });
-
-  // Create and remove one or more subscriptions on the fly
-  c.subscribe({
-    type: 'subscribe',
-    subscriptionId: 1,
-    priceFeedIds: [1, 2],
-    properties: ['price'],
-    formats: ['solana'],
-    deliveryFormat: 'binary',
-    channel: 'fixed_rate@200ms',
-    parsed: false,
-    jsonBinaryEncoding: 'base64',
-  });
-  c.subscribe({
-    type: 'subscribe',
-    subscriptionId: 2,
-    priceFeedIds: [1, 2, 3, 4, 5],
-    properties: ['price', 'exponent', 'publisherCount', 'confidence'],
-    formats: ['evm'],
-    deliveryFormat: 'json',
-    channel: 'fixed_rate@200ms',
-    parsed: true,
-    jsonBinaryEncoding: 'hex',
-  });
+    // Optional configuration for resilient WebSocket connections
+    rwsConfig: {
+      heartbeatTimeoutDurationMs: 5000, // Optional heartbeat timeout duration in milliseconds
+      maxRetryDelayMs: 1000, // Optional maximum retry delay in milliseconds
+      logAfterRetryCount: 10, // Optional log after how many retries
+    },
+  },
+});
+
+c.addMessageListener((message) => {
+  console.info("received the following from the Lazer stream:", message);
+});
+
+// Monitor for all connections in the pool being down simultaneously (e.g. if the internet goes down)
+// The connections may still try to reconnect in the background. To shut down the client completely, call shutdown().
+c.addAllConnectionsDownListener(() => {
+  console.error("All connections are down!");
+});
+
+// Create and remove one or more subscriptions on the fly
+c.subscribe({
+  type: "subscribe",
+  subscriptionId: 1,
+  priceFeedIds: [1, 2],
+  properties: ["price"],
+  formats: ["solana"],
+  deliveryFormat: "binary",
+  channel: "fixed_rate@200ms",
+  parsed: false,
+  jsonBinaryEncoding: "base64",
+});
+c.subscribe({
+  type: "subscribe",
+  subscriptionId: 2,
+  priceFeedIds: [1, 2, 3, 4, 5],
+  properties: ["price", "exponent", "publisherCount", "confidence"],
+  formats: ["evm"],
+  deliveryFormat: "json",
+  channel: "fixed_rate@200ms",
+  parsed: true,
+  jsonBinaryEncoding: "hex",
+});
 ```

+ 10 - 6
lazer/sdk/js/src/client.ts

@@ -31,9 +31,9 @@ export type BinaryResponse = {
 };
 export type JsonOrBinaryResponse =
   | {
-    type: "json";
-    value: Response;
-  }
+      type: "json";
+      value: Response;
+    }
   | { type: "binary"; value: BinaryResponse };
 
 const UINT16_NUM_BYTES = 2;
@@ -55,7 +55,7 @@ export class PythLazerClient {
     private readonly priceServiceUrl: string,
     private readonly logger: Logger,
     private readonly wsp?: WebSocketPool,
-  ) { }
+  ) {}
 
   /**
    * Gets the WebSocket pool. If the WebSocket pool is not configured, an error is thrown.
@@ -123,7 +123,9 @@ export class PythLazerClient {
       }
       const buffData = await IsomorphicBuffer.fromWebsocketData(data);
       let pos = 0;
-      const magic = buffData.subarray(pos, pos + UINT32_NUM_BYTES).readUint32LE();
+      const magic = buffData
+        .subarray(pos, pos + UINT32_NUM_BYTES)
+        .readUint32LE();
       pos += UINT32_NUM_BYTES;
       if (magic != BINARY_UPDATE_FORMAT_MAGIC_LE) {
         throw new Error("binary update format magic mismatch");
@@ -136,7 +138,9 @@ export class PythLazerClient {
 
       const value: BinaryResponse = { subscriptionId };
       while (pos < buffData.length) {
-        const len = buffData.subarray(pos, pos + UINT16_NUM_BYTES).readUint16BE();
+        const len = buffData
+          .subarray(pos, pos + UINT16_NUM_BYTES)
+          .readUint16BE();
         pos += UINT16_NUM_BYTES;
         const magic = buffData
           .subarray(pos, pos + UINT32_NUM_BYTES)

+ 19 - 5
lazer/sdk/js/src/socket/resilient-websocket.ts

@@ -28,7 +28,9 @@ export class ResilientWebSocket {
   private maxRetryDelayMs: number;
   private logAfterRetryCount: number;
 
-  wsClient: undefined | WebSocket;
+  wsClient:
+    | undefined
+    | (Omit<WebSocket, "terminate"> & Partial<Pick<WebSocket, "terminate">>);
   wsUserClosed = false;
   private wsFailedAttempts: number;
   private heartbeatTimeout?: NodeJS.Timeout | undefined;
@@ -111,7 +113,10 @@ export class ResilientWebSocket {
     // browser constructor supports a different 2nd argument for the constructor,
     // so we need to ensure it's not included if we're running in that environment:
     // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket#protocols
-    this.wsClient = new WebSocket(this.endpoint, envIsServiceOrWebWorker() ? undefined : this.wsOptions);
+    this.wsClient = new WebSocket(
+      this.endpoint,
+      envIsServiceOrWebWorker() ? undefined : this.wsOptions,
+    );
 
     this.wsClient.addEventListener("open", () => {
       this.logger.info("WebSocket connection established");
@@ -160,7 +165,16 @@ export class ResilientWebSocket {
 
     this.heartbeatTimeout = setTimeout(() => {
       this.logger.warn("Connection timed out. Reconnecting...");
-      this.wsClient?.terminate();
+      if (this.wsClient) {
+        if (typeof this.wsClient.terminate === "function") {
+          this.wsClient.terminate();
+        } else {
+          // terminate is an implementation detail of the node-friendly
+          // https://www.npmjs.com/package/ws package, but is not a native WebSocket API,
+          // so we have to use the close method
+          this.wsClient.close();
+        }
+      }
       this.handleReconnect();
     }, this.heartbeatTimeoutDurationMs);
   }
@@ -189,8 +203,8 @@ export class ResilientWebSocket {
     if (this.shouldLogRetry()) {
       this.logger.error(
         "Connection closed unexpectedly or because of timeout. Reconnecting after " +
-        String(this.retryDelayMs()) +
-        "ms.",
+          String(this.retryDelayMs()) +
+          "ms.",
       );
     }
 

+ 10 - 9
lazer/sdk/js/src/socket/websocket-pool.ts

@@ -15,7 +15,9 @@ import { envIsBrowserOrWorker, IsomorphicBuffer } from "../util/index.js";
 
 const DEFAULT_NUM_CONNECTIONS = 4;
 
-type WebSocketOnMessageCallback = (data: WebSocket.Data) => void | Promise<void>;
+type WebSocketOnMessageCallback = (
+  data: WebSocket.Data,
+) => void | Promise<void>;
 
 export type WebSocketPoolConfig = {
   urls?: string[];
@@ -72,7 +74,7 @@ export class WebSocketPool {
       if (!url) {
         throw new Error(`URLs must not be null or empty`);
       }
-      const wsOptions: ResilientWebSocketConfig['wsOptions'] = {
+      const wsOptions: ResilientWebSocketConfig["wsOptions"] = {
         ...config.rwsConfig?.wsOptions,
       };
 
@@ -81,7 +83,7 @@ export class WebSocketPool {
         // doesn't support sending headers in the initial upgrade request,
         // so we add the token as a query param, which the server already supports
         const parsedUrl = new URL(url);
-        parsedUrl.searchParams.set('ACCESS_TOKEN', token);
+        parsedUrl.searchParams.set("ACCESS_TOKEN", token);
         url = parsedUrl.toString();
       } else {
         // we are in a server-side javascript runtime context
@@ -119,7 +121,7 @@ export class WebSocketPool {
         rws.onError = config.onError;
       }
       // Handle all client messages ourselves. Dedupe before sending to registered message handlers.
-      rws.onMessage = data => {
+      rws.onMessage = (data) => {
         void pool.dedupeHandler(data);
       };
       pool.rwsPool.push(rws);
@@ -162,12 +164,12 @@ export class WebSocketPool {
    * multiple connections before forwarding to registered handlers
    */
   dedupeHandler = async (data: WebSocket.Data): Promise<void> => {
-    let cacheKey = '';
-    if (typeof data === 'string') {
+    let cacheKey = "";
+    if (typeof data === "string") {
       cacheKey = data;
     } else {
       const buff = await IsomorphicBuffer.fromWebsocketData(data);
-      cacheKey = buff.toString('hex');
+      cacheKey = buff.toString("hex");
     }
 
     if (this.cache.has(cacheKey)) {
@@ -181,8 +183,7 @@ export class WebSocketPool {
       this.handleErrorMessages(data);
     }
 
-    await Promise.all(this.messageListeners.map(handler => handler(data)));
-
+    await Promise.all(this.messageListeners.map((handler) => handler(data)));
   };
 
   sendRequest(request: Request) {

+ 13 - 9
lazer/sdk/js/src/util/buffer-util.ts

@@ -2,22 +2,24 @@
 // a global, top-level import. we disable this rule because we need this
 // imported from our installed dependency
 // eslint-disable-next-line unicorn/prefer-node-protocol
-import { Buffer as BrowserBuffer } from 'buffer';
+import { Buffer as BrowserBuffer } from "buffer";
 
-import type { Data } from 'isomorphic-ws';
+import type { Data } from "isomorphic-ws";
 
-const { Buffer: PossibleBuiltInBuffer } = globalThis as Partial<{ Buffer: typeof Buffer }>;
+const { Buffer: PossibleBuiltInBuffer } = globalThis as Partial<{
+  Buffer: typeof Buffer;
+}>;
 
 const BufferClassToUse = PossibleBuiltInBuffer ?? BrowserBuffer;
 
 export class IsomorphicBuffer extends BufferClassToUse {
   /**
- * given a relatively unknown websocket frame data object,
- * returns a valid Buffer instance that is safe to use
- * isomorphically in any JS runtime environment
- */
+   * given a relatively unknown websocket frame data object,
+   * returns a valid Buffer instance that is safe to use
+   * isomorphically in any JS runtime environment
+   */
   static async fromWebsocketData(data: Data) {
-    if (typeof data === 'string') {
+    if (typeof data === "string") {
       return BufferClassToUse.from(new TextEncoder().encode(data).buffer);
     }
     if (data instanceof Blob) {
@@ -33,6 +35,8 @@ export class IsomorphicBuffer extends BufferClassToUse {
       }
       return BufferClassToUse.from(arrBuffer);
     }
-    throw new TypeError("unexpected event data type found when IsomorphicBuffer.fromWebsocketData() called");
+    throw new TypeError(
+      "unexpected event data type found when IsomorphicBuffer.fromWebsocketData() called",
+    );
   }
 }

+ 7 - 3
lazer/sdk/js/src/util/env-util.ts

@@ -1,13 +1,17 @@
 // we create this local-only type, which has assertions made to indicate
 // that we do not know and cannot guarantee which JS environment we are in
-const g = globalThis as Partial<{ self: typeof globalThis.self; window: typeof globalThis.window }>
+const g = globalThis as Partial<{
+  self: typeof globalThis.self;
+  window: typeof globalThis.window;
+}>;
 
 /**
  * Detects if this code is running within any Service or WebWorker context.
  * @returns true if in a worker of some kind, false if otherwise
  */
 export function envIsServiceOrWebWorker() {
-  const possiblyInAWorker = typeof WorkerGlobalScope !== 'undefined' && g.self !== undefined;
+  const possiblyInAWorker =
+    typeof WorkerGlobalScope !== "undefined" && g.self !== undefined;
   return possiblyInAWorker && g.self instanceof WorkerGlobalScope;
 }
 
@@ -22,7 +26,7 @@ export function envIsBrowser() {
 /**
  * a convenience method that returns whether or not
  * this code is executing in some type of browser-centric environment
- * 
+ *
  * @returns true if in the browser's main UI thread or in a worker, false if otherwise
  */
 export function envIsBrowserOrWorker() {