jsgar 3.7.1 → 3.7.8

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 (2) hide show
  1. package/dist/gar.umd.js +74 -29
  2. package/package.json +1 -1
package/dist/gar.umd.js CHANGED
@@ -47,7 +47,11 @@
47
47
  this.reconnectDelay = 5000; // Milliseconds
48
48
  this.user = user;
49
49
  this.working_namespace = working_namespace;
50
- this.heartbeatTimeoutInterval = heartbeatTimeoutInterval;
50
+ this.timeoutScale = (typeof process !== 'undefined' && process.env && process.env.TRS_TIMEOUT_SCALE) ? parseFloat(process.env.TRS_TIMEOUT_SCALE) : 1.0;
51
+ this.scaledHeartbeatTimeoutInterval = heartbeatTimeoutInterval;
52
+ if (this.timeoutScale !== 1.0) {
53
+ this.scaledHeartbeatTimeoutInterval *= this.timeoutScale;
54
+ }
51
55
  this.version = 650707;
52
56
 
53
57
  if (typeof window !== 'undefined' && window.location) {
@@ -70,7 +74,6 @@
70
74
  this.heartbeatIntervalId = null;
71
75
  this.messageHandlers = new Map();
72
76
  this.lastHeartbeatTime = Date.now() / 1000;
73
- this.heartbeatTimeout = 3; // Seconds
74
77
 
75
78
  this.heartbeatTimeoutCallback = null;
76
79
  this.stoppedCallback = null;
@@ -145,42 +148,72 @@
145
148
 
146
149
  /**
147
150
  * Establish WebSocket connection with reconnection logic.
151
+ * @param {number} [openTimeout=20] - Connection timeout in seconds
148
152
  */
149
- /**
150
- * Establish WebSocket connection with reconnection logic.
151
- */
152
- async connect() {
153
+ async connect(openTimeout = 20) {
153
154
  // Before attempting a new connection, clear any previous state
154
155
  this.clearConnectionState();
155
156
 
157
+ let scaledOpenTimeout = openTimeout * this.timeoutScale;
158
+
156
159
  while (this.running && !this.connected) {
157
160
  try {
158
161
  const WS = await this._ensureWebSocketCtor();
159
162
  const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
160
- if (this.allowSelfSignedCertificate && isNode) {
161
- // Node.js 'ws' supports options for TLS; browsers do not.
162
- this.websocket = new WS(this.wsEndpoint, ['gar-protocol'], { rejectUnauthorized: false });
163
- } else {
164
- this.websocket = new WS(this.wsEndpoint, ['gar-protocol']);
165
- }
166
- this.websocket.onopen = () => {
167
- this.connected = true;
168
- this.log('INFO', `Connected to WebSocket server at ${this.wsEndpoint} using gar-protocol`);
169
- this._sendMessages();
170
- this._receiveMessages();
171
- };
163
+
164
+ this.log('INFO', `Connecting to WebSocket server at ${this.wsEndpoint}`);
165
+
166
+ const connectionPromise = new Promise((resolve, reject) => {
167
+ let websocket;
168
+ if (this.allowSelfSignedCertificate && isNode) {
169
+ // Node.js 'ws' supports options for TLS; browsers do not.
170
+ websocket = new WS(this.wsEndpoint, ['gar-protocol'], { rejectUnauthorized: false });
171
+ } else {
172
+ websocket = new WS(this.wsEndpoint, ['gar-protocol']);
173
+ }
174
+
175
+ const timeoutId = setTimeout(() => {
176
+ websocket.onopen = null;
177
+ websocket.onclose = null;
178
+ websocket.onerror = null;
179
+ if (websocket.terminate) websocket.terminate();
180
+ else if (websocket.close) websocket.close();
181
+ reject(new Error(`Connection timed out after ${scaledOpenTimeout}s`));
182
+ }, scaledOpenTimeout * 1000);
183
+
184
+ websocket.onopen = () => {
185
+ clearTimeout(timeoutId);
186
+ resolve(websocket);
187
+ };
188
+ websocket.onerror = (error) => {
189
+ clearTimeout(timeoutId);
190
+ reject(new Error(error.message || 'Unknown WebSocket error'));
191
+ };
192
+ websocket.onclose = () => {
193
+ clearTimeout(timeoutId);
194
+ reject(new Error('WebSocket closed during connection attempt'));
195
+ };
196
+ });
197
+
198
+ this.websocket = await connectionPromise;
199
+ this.connected = true;
200
+ this.log('INFO', `Connected to WebSocket server at ${this.wsEndpoint} using gar-protocol`);
201
+
172
202
  this.websocket.onclose = () => {
173
203
  this.log('WARNING', 'WebSocket connection closed.');
174
204
  this.connected = false;
175
205
  this.websocket = null;
206
+ this._reconnect();
176
207
  };
177
208
  this.websocket.onerror = (error) => {
178
209
  this.log('ERROR', `WebSocket error: ${error.message || 'Unknown error'}`);
179
210
  this.connected = false;
180
211
  this.websocket = null;
181
212
  };
182
- // Wait indefinitely until connection succeeds or fails
183
- await new Promise(resolve => setTimeout(resolve, 5000));
213
+
214
+ this._sendMessages();
215
+ this._receiveMessages();
216
+
184
217
  } catch (e) {
185
218
  this.log('ERROR', `WebSocket connection failed: ${e.message}. Reconnecting in ${this.reconnectDelay / 1000} seconds...`);
186
219
  this.connected = false;
@@ -457,13 +490,13 @@
457
490
  message_type: 'Introduction',
458
491
  value: {
459
492
  version: this.version,
460
- heartbeat_timeout_interval: this.heartbeatTimeoutInterval,
493
+ heartbeat_timeout_interval: Math.floor(this.scaledHeartbeatTimeoutInterval),
461
494
  user: this.user,
462
495
  working_namespace: this.working_namespace
463
496
  }
464
497
  };
465
498
  this.sendMessage(introMsg);
466
- this.heartbeatIntervalId = setInterval(() => this._heartbeatLoop(), this.heartbeatTimeoutInterval / 2);
499
+ this.heartbeatIntervalId = setInterval(() => this._heartbeatLoop(), this.scaledHeartbeatTimeoutInterval / 2);
467
500
  this.connect();
468
501
  }
469
502
 
@@ -590,7 +623,7 @@
590
623
  */
591
624
  checkHeartbeat() {
592
625
  const now = Date.now() / 1000;
593
- const cutoff = this._initialGracePeriod ? this._initialGraceDeadline : this.lastHeartbeatTime + this.heartbeatTimeout;
626
+ const cutoff = this._initialGracePeriod ? this._initialGraceDeadline : this.lastHeartbeatTime + (this.scaledHeartbeatTimeoutInterval / 1000.0);
594
627
  if (now > cutoff) {
595
628
  this.log('WARNING', `Heartbeat failed; previous heartbeat: ${this.lastHeartbeatTime.toFixed(3)}s`);
596
629
  this.exitCode = 1;
@@ -678,10 +711,14 @@
678
711
  this.serverKeyIdToName.clear();
679
712
  this.serverKeyNameToId.clear();
680
713
  this.recordMap.clear();
681
- this.heartbeatTimeout = Math.max(this.heartbeatTimeout, value.heartbeat_timeout_interval / 1000);
714
+ let newInterval = value.heartbeat_timeout_interval;
715
+ if (this.timeoutScale !== 1.0) {
716
+ newInterval *= this.timeoutScale;
717
+ }
718
+ this.scaledHeartbeatTimeoutInterval = Math.max(this.scaledHeartbeatTimeoutInterval, newInterval);
682
719
  this.lastHeartbeatTime = Date.now() / 1000;
683
720
  this._initialGracePeriod = true;
684
- this._initialGraceDeadline = this.lastHeartbeatTime + this.heartbeatTimeout * 10;
721
+ this._initialGraceDeadline = this.lastHeartbeatTime + (this.scaledHeartbeatTimeoutInterval / 1000.0) * 10;
685
722
  // New Introduction: do not reset the first-heartbeat promise to avoid racing
686
723
  // with consumers already awaiting it. The existing promise will resolve on
687
724
  // the first Heartbeat observed during the grace period above.
@@ -1075,6 +1112,17 @@
1075
1112
  this.sendMessage(msg);
1076
1113
  }
1077
1114
 
1115
+ /**
1116
+ * Delete a key by name if it exists in the localKeyMap. Safe to call multiple times.
1117
+ * @param {string} keyName - Key name
1118
+ */
1119
+ deleteKey(keyName) {
1120
+ const keyId = this.localKeyMap.get(keyName);
1121
+ if (keyId) {
1122
+ this.publishDeleteKey(keyId);
1123
+ }
1124
+ }
1125
+
1078
1126
  /**
1079
1127
  * Publish a DeleteRecord message using local key and topic IDs.
1080
1128
  * @param {number} keyId - Key ID
@@ -1199,10 +1247,7 @@
1199
1247
  const resultContainer = { };
1200
1248
 
1201
1249
  const cleanup = () => {
1202
- const keyId = this.localKeyMap.get(queryKey);
1203
- if (keyId) {
1204
- this.publishDeleteKey(keyId);
1205
- }
1250
+ this.deleteKey(queryKey);
1206
1251
  };
1207
1252
 
1208
1253
  return new Promise((resolve) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsgar",
3
- "version": "3.7.1",
3
+ "version": "3.7.8",
4
4
  "description": "A Javascript client for the GAR protocol",
5
5
  "type": "module",
6
6
  "main": "dist/gar.umd.js",