@superatomai/sdk-node 0.0.29 → 0.0.30

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/index.mjs CHANGED
@@ -9737,6 +9737,7 @@ init_logger();
9737
9737
  var SDK_VERSION = "0.0.8";
9738
9738
  var DEFAULT_WS_URL = "wss://ws.superatom.ai/websocket";
9739
9739
  var SuperatomSDK = class {
9740
+ // 3.5 minutes (PING_INTERVAL + 30s grace)
9740
9741
  constructor(config) {
9741
9742
  this.ws = null;
9742
9743
  this.messageHandlers = /* @__PURE__ */ new Map();
@@ -9747,6 +9748,12 @@ var SuperatomSDK = class {
9747
9748
  this.collections = {};
9748
9749
  this.components = [];
9749
9750
  this.tools = [];
9751
+ // Heartbeat properties for keeping WebSocket connection alive
9752
+ this.pingInterval = null;
9753
+ this.lastPong = Date.now();
9754
+ this.PING_INTERVAL_MS = 18e4;
9755
+ // 3 minutes
9756
+ this.PONG_TIMEOUT_MS = 21e4;
9750
9757
  if (config.logLevel) {
9751
9758
  logger.setLogLevel(config.logLevel);
9752
9759
  }
@@ -9860,6 +9867,7 @@ var SuperatomSDK = class {
9860
9867
  this.connected = true;
9861
9868
  this.reconnectAttempts = 0;
9862
9869
  logger.info("WebSocket connected successfully");
9870
+ this.startHeartbeat();
9863
9871
  resolve();
9864
9872
  });
9865
9873
  this.ws.addEventListener("message", (event) => {
@@ -9888,6 +9896,9 @@ var SuperatomSDK = class {
9888
9896
  const message = IncomingMessageSchema.parse(parsed);
9889
9897
  logger.debug("Received message:", message.type);
9890
9898
  switch (message.type) {
9899
+ case "PONG":
9900
+ this.handlePong();
9901
+ break;
9891
9902
  case "DATA_REQ":
9892
9903
  handleDataRequest(parsed, this.collections, (msg) => this.send(msg)).catch((error) => {
9893
9904
  logger.error("Failed to handle data request:", error);
@@ -10010,6 +10021,7 @@ var SuperatomSDK = class {
10010
10021
  * Disconnect from the WebSocket service
10011
10022
  */
10012
10023
  disconnect() {
10024
+ this.stopHeartbeat();
10013
10025
  if (this.ws) {
10014
10026
  this.ws.close();
10015
10027
  this.ws = null;
@@ -10020,6 +10032,7 @@ var SuperatomSDK = class {
10020
10032
  * Cleanup and disconnect - stops reconnection attempts and closes the connection
10021
10033
  */
10022
10034
  async destroy() {
10035
+ this.stopHeartbeat();
10023
10036
  this.maxReconnectAttempts = 0;
10024
10037
  this.reconnectAttempts = 0;
10025
10038
  this.messageHandlers.clear();
@@ -10061,6 +10074,59 @@ var SuperatomSDK = class {
10061
10074
  logger.error("Max reconnection attempts reached");
10062
10075
  }
10063
10076
  }
10077
+ /**
10078
+ * Start heartbeat to keep WebSocket connection alive
10079
+ * Sends PING every 3 minutes to prevent idle timeout from cloud infrastructure
10080
+ */
10081
+ startHeartbeat() {
10082
+ this.stopHeartbeat();
10083
+ this.lastPong = Date.now();
10084
+ this.pingInterval = setInterval(() => {
10085
+ if (!this.ws || this.ws.readyState !== this.ws.OPEN) {
10086
+ logger.warn("WebSocket not open during heartbeat check, stopping heartbeat");
10087
+ this.stopHeartbeat();
10088
+ return;
10089
+ }
10090
+ const timeSinceLastPong = Date.now() - this.lastPong;
10091
+ if (timeSinceLastPong > this.PONG_TIMEOUT_MS) {
10092
+ logger.warn(`No PONG received for ${timeSinceLastPong}ms, connection may be dead. Reconnecting...`);
10093
+ this.stopHeartbeat();
10094
+ this.ws.close();
10095
+ return;
10096
+ }
10097
+ try {
10098
+ const pingMessage = {
10099
+ type: "PING",
10100
+ from: { type: this.type },
10101
+ payload: { timestamp: Date.now() }
10102
+ };
10103
+ this.ws.send(JSON.stringify(pingMessage));
10104
+ logger.debug("Heartbeat PING sent");
10105
+ } catch (error) {
10106
+ logger.error("Failed to send PING:", error);
10107
+ this.stopHeartbeat();
10108
+ this.ws.close();
10109
+ }
10110
+ }, this.PING_INTERVAL_MS);
10111
+ logger.info(`Heartbeat started (PING every ${this.PING_INTERVAL_MS / 1e3}s)`);
10112
+ }
10113
+ /**
10114
+ * Stop the heartbeat interval
10115
+ */
10116
+ stopHeartbeat() {
10117
+ if (this.pingInterval) {
10118
+ clearInterval(this.pingInterval);
10119
+ this.pingInterval = null;
10120
+ logger.debug("Heartbeat stopped");
10121
+ }
10122
+ }
10123
+ /**
10124
+ * Handle PONG response from server
10125
+ */
10126
+ handlePong() {
10127
+ this.lastPong = Date.now();
10128
+ logger.debug("Heartbeat PONG received");
10129
+ }
10064
10130
  storeComponents(components) {
10065
10131
  this.components = components;
10066
10132
  }