@shipload/sdk 1.0.0-next.0 → 1.0.0-next.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.
package/lib/shipload.m.js CHANGED
@@ -9095,9 +9095,15 @@ class WebSocketConnection {
9095
9095
  this._state = 'disconnected';
9096
9096
  this.shouldReconnect = true;
9097
9097
  this.sendQueue = [];
9098
+ this.pingTimer = null;
9099
+ this.staleTimer = null;
9098
9100
  this.url = options.url;
9099
9101
  this.onMessage = options.onMessage;
9100
9102
  this.onStateChange = options.onStateChange;
9103
+ this.minReconnectDelay =
9104
+ options.minReconnectDelay ?? WebSocketConnection.DEFAULT_MIN_RECONNECT_DELAY;
9105
+ this.pingIntervalMs = options.pingIntervalMs ?? WebSocketConnection.DEFAULT_PING_INTERVAL_MS;
9106
+ this.pongTimeoutMs = options.pongTimeoutMs ?? WebSocketConnection.DEFAULT_PONG_TIMEOUT_MS;
9101
9107
  }
9102
9108
  get state() {
9103
9109
  return this._state;
@@ -9126,8 +9132,10 @@ class WebSocketConnection {
9126
9132
  this.ws.readyState === WebSocket.OPEN) {
9127
9133
  this.ws.send(this.sendQueue.shift());
9128
9134
  }
9135
+ this.startHeartbeat();
9129
9136
  };
9130
9137
  this.ws.onmessage = (event) => {
9138
+ this.resetStaleTimer();
9131
9139
  try {
9132
9140
  const message = JSON.parse(event.data);
9133
9141
  this.onMessage(message);
@@ -9137,6 +9145,7 @@ class WebSocketConnection {
9137
9145
  }
9138
9146
  };
9139
9147
  this.ws.onclose = () => {
9148
+ this.stopHeartbeat();
9140
9149
  this.ws = null;
9141
9150
  this.sendQueue.length = 0;
9142
9151
  if (this.shouldReconnect) {
@@ -9161,7 +9170,7 @@ class WebSocketConnection {
9161
9170
  if (this.reconnectTimeout) {
9162
9171
  return;
9163
9172
  }
9164
- const delay = Math.min(WebSocketConnection.MIN_RECONNECT_DELAY *
9173
+ const delay = Math.min(this.minReconnectDelay *
9165
9174
  WebSocketConnection.RECONNECT_MULTIPLIER ** this.reconnectAttempts, WebSocketConnection.MAX_RECONNECT_DELAY);
9166
9175
  debug(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts + 1})`);
9167
9176
  this.reconnectTimeout = setTimeout(() => {
@@ -9176,6 +9185,7 @@ class WebSocketConnection {
9176
9185
  clearTimeout(this.reconnectTimeout);
9177
9186
  this.reconnectTimeout = null;
9178
9187
  }
9188
+ this.stopHeartbeat();
9179
9189
  if (this.ws) {
9180
9190
  this.ws.close();
9181
9191
  this.ws = null;
@@ -9183,6 +9193,34 @@ class WebSocketConnection {
9183
9193
  this.sendQueue.length = 0;
9184
9194
  this.setState('disconnected');
9185
9195
  }
9196
+ startHeartbeat() {
9197
+ this.stopHeartbeat();
9198
+ this.resetStaleTimer();
9199
+ this.pingTimer = setInterval(() => {
9200
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
9201
+ this.ws.send(JSON.stringify({ type: 'ping' }));
9202
+ }
9203
+ }, this.pingIntervalMs);
9204
+ }
9205
+ stopHeartbeat() {
9206
+ if (this.pingTimer) {
9207
+ clearInterval(this.pingTimer);
9208
+ this.pingTimer = null;
9209
+ }
9210
+ if (this.staleTimer) {
9211
+ clearTimeout(this.staleTimer);
9212
+ this.staleTimer = null;
9213
+ }
9214
+ }
9215
+ resetStaleTimer() {
9216
+ if (this.staleTimer)
9217
+ clearTimeout(this.staleTimer);
9218
+ this.staleTimer = setTimeout(() => {
9219
+ debug('No frames within ping interval + pong timeout — forcing reconnect');
9220
+ if (this.ws)
9221
+ this.ws.close();
9222
+ }, this.pingIntervalMs + this.pongTimeoutMs);
9223
+ }
9186
9224
  close() {
9187
9225
  this.disconnect();
9188
9226
  }
@@ -9198,9 +9236,11 @@ class WebSocketConnection {
9198
9236
  return this._state === 'connected';
9199
9237
  }
9200
9238
  }
9201
- WebSocketConnection.MIN_RECONNECT_DELAY = 1000;
9239
+ WebSocketConnection.DEFAULT_MIN_RECONNECT_DELAY = 1000;
9202
9240
  WebSocketConnection.MAX_RECONNECT_DELAY = 30000;
9203
9241
  WebSocketConnection.RECONNECT_MULTIPLIER = 2;
9242
+ WebSocketConnection.DEFAULT_PING_INTERVAL_MS = 25000;
9243
+ WebSocketConnection.DEFAULT_PONG_TIMEOUT_MS = 10000;
9204
9244
 
9205
9245
  function mapEntity(ei) {
9206
9246
  if (ei.type.equals('ship'))
@@ -9229,9 +9269,14 @@ class SubscriptionsManager {
9229
9269
  this.entitySubs = new Map();
9230
9270
  this.boundsSubs = new Map();
9231
9271
  this.subCounter = 0;
9272
+ this.hasConnected = false;
9232
9273
  this.conn = new WebSocketConnection({
9233
9274
  url: opts.url,
9234
9275
  onMessage: (m) => this.onMessage(m),
9276
+ onStateChange: (s) => this.onStateChange(s),
9277
+ minReconnectDelay: opts.minReconnectDelay,
9278
+ pingIntervalMs: opts.pingIntervalMs,
9279
+ pongTimeoutMs: opts.pongTimeoutMs,
9235
9280
  });
9236
9281
  this.conn.connect();
9237
9282
  }
@@ -9288,6 +9333,9 @@ class SubscriptionsManager {
9288
9333
  current: new Map(),
9289
9334
  };
9290
9335
  this.boundsSubs.set(subId, {
9336
+ bounds,
9337
+ owner: handlers.owner,
9338
+ prioritizeOwner: handlers.prioritizeOwner,
9291
9339
  onSnapshot: handlers.onSnapshot,
9292
9340
  onUpdate: handlers.onUpdate,
9293
9341
  onBoundsDelta: handlers.onBoundsDelta,
@@ -9301,9 +9349,39 @@ class SubscriptionsManager {
9301
9349
  this.sendMessage({ type: 'unsubscribe', sub_id: subId });
9302
9350
  }
9303
9351
  updateBounds(subId, bounds) {
9352
+ const entry = this.boundsSubs.get(subId);
9353
+ if (entry)
9354
+ entry.bounds = bounds;
9304
9355
  const msg = { type: 'update_bounds', sub_id: subId, bounds };
9305
9356
  this.sendMessage(msg);
9306
9357
  }
9358
+ onStateChange(state) {
9359
+ if (state !== 'connected')
9360
+ return;
9361
+ if (!this.hasConnected) {
9362
+ this.hasConnected = true;
9363
+ return;
9364
+ }
9365
+ for (const [subId, entry] of this.entitySubs) {
9366
+ const msg = {
9367
+ type: 'subscribe_entity',
9368
+ sub_id: subId,
9369
+ entity_type: entry.type,
9370
+ entity_id: entry.id,
9371
+ };
9372
+ this.sendMessage(msg);
9373
+ }
9374
+ for (const [subId, entry] of this.boundsSubs) {
9375
+ const msg = {
9376
+ type: 'subscribe',
9377
+ sub_id: subId,
9378
+ bounds: entry.bounds,
9379
+ owner: entry.owner,
9380
+ prioritize_owner: entry.prioritizeOwner,
9381
+ };
9382
+ this.sendMessage(msg);
9383
+ }
9384
+ }
9307
9385
  onMessage(msg) {
9308
9386
  switch (msg.type) {
9309
9387
  case 'snapshot':