jsgar 4.9.0 → 4.9.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 (3) hide show
  1. package/dist/gar.umd.js +27 -13
  2. package/gar.js +27 -13
  3. package/package.json +1 -1
package/dist/gar.umd.js CHANGED
@@ -1101,9 +1101,18 @@
1101
1101
  this.log('INFO', 'Received Logoff from server');
1102
1102
  this.stop();
1103
1103
  } else if (msgType === 'Error') {
1104
- this.log('ERROR', `GAR ${message.value.message}`);
1105
- this.exitCode = 1;
1106
- this.stop();
1104
+ // proto.gar's `error` struct carries `recoverable: bool`. Recoverable errors mean
1105
+ // the server processed the failing message (e.g. a publish that violated some
1106
+ // server-side check), logged it, and kept the connection alive. We dispatch the
1107
+ // message to the user's error handler but don't tear down the client. Non-recoverable
1108
+ // errors are followed by a server disconnect; we set exit_code + stop() so callers
1109
+ // (CLI tools, the html_view UI) see the failure.
1110
+ const recoverable = !!message.value.recoverable;
1111
+ this.log(recoverable ? 'WARNING' : 'ERROR', `GAR ${message.value.message}`);
1112
+ if (!recoverable) {
1113
+ this.exitCode = 1;
1114
+ this.stop();
1115
+ }
1107
1116
  }
1108
1117
 
1109
1118
  this.checkHeartbeat();
@@ -1387,28 +1396,25 @@
1387
1396
  }
1388
1397
 
1389
1398
  /**
1390
- * Introduce a new key if not already known and return local key ID.
1399
+ * Introduce a new key if not already known and return local key ID. className is required;
1400
+ * a bare introduction with no class_list can't be routed by upstream proxies.
1391
1401
  * @param {string} name - Key name
1392
- * @param {string|Array<string>|null} [className=null] - Class name(s)
1402
+ * @param {string|Array<string>} className - Class name(s)
1393
1403
  * @returns {number} Local key ID
1394
1404
  */
1395
- getAndPossiblyIntroduceKeyId(name, className = null) {
1405
+ getAndPossiblyIntroduceKeyId(name, className) {
1396
1406
  const existingId = this.localKeyMap.get(name);
1397
1407
  if (existingId !== undefined && this.invalidatedKeyIds.has(existingId)) {
1398
1408
  this.invalidatedKeyIds.delete(existingId);
1399
1409
  this.localKeyMap.delete(name);
1400
1410
  }
1401
1411
  if (!this.localKeyMap.has(name)) {
1412
+ if (!className) throw new Error(`getAndPossiblyIntroduceKeyId: className required to introduce key "${name}"`);
1402
1413
  const keyId = this.localKeyCounter++;
1403
1414
  this.localKeyMap.set(name, keyId);
1404
1415
  const value = { key_id: keyId, name };
1405
- if (className) {
1406
- if (typeof className === 'string') {
1407
- value.class_list = className.split(/\s+/).filter(Boolean);
1408
- } else if (Array.isArray(className)) {
1409
- value.class_list = className;
1410
- }
1411
- }
1416
+ if (typeof className === 'string') value.class_list = className.split(/\s+/).filter(Boolean);
1417
+ else if (Array.isArray(className)) value.class_list = className;
1412
1418
  this.sendMessage({ message_type: 'KeyIntroduction', value });
1413
1419
  }
1414
1420
  return this.localKeyMap.get(name);
@@ -1511,6 +1517,10 @@
1511
1517
  * @param {any} value - JSON-serializable value
1512
1518
  */
1513
1519
  publishRecordWithIds(keyId, topicId, value) {
1520
+ if (value === undefined) {
1521
+ this.log('ERROR', `publishRecordWithIds(${keyId}, ${topicId}): refusing to publish undefined — JSON.stringify would drop the "value" field and the server would reject with "Missing record 'value' field"`);
1522
+ return;
1523
+ }
1514
1524
  const updateMsg = {
1515
1525
  message_type: 'JSONRecordUpdate',
1516
1526
  value: {
@@ -1529,6 +1539,10 @@
1529
1539
  * @param {string|null} [className=null] - Class name
1530
1540
  */
1531
1541
  publishRecord(keyName, topicName, value, className = null) {
1542
+ if (value === undefined) {
1543
+ this.log('ERROR', `publishRecord(${keyName}, ${topicName}): refusing to publish undefined — JSON.stringify would drop the "value" field and the server would reject with "Missing record 'value' field"`);
1544
+ return;
1545
+ }
1532
1546
  const keyId = this.getAndPossiblyIntroduceKeyId(keyName, className);
1533
1547
  const topicId = this.getAndPossiblyIntroduceTopicId(topicName);
1534
1548
  this.publishRecordWithIds(keyId, topicId, value);
package/gar.js CHANGED
@@ -1095,9 +1095,18 @@ class GARClient {
1095
1095
  this.log('INFO', 'Received Logoff from server');
1096
1096
  this.stop();
1097
1097
  } else if (msgType === 'Error') {
1098
- this.log('ERROR', `GAR ${message.value.message}`);
1099
- this.exitCode = 1;
1100
- this.stop();
1098
+ // proto.gar's `error` struct carries `recoverable: bool`. Recoverable errors mean
1099
+ // the server processed the failing message (e.g. a publish that violated some
1100
+ // server-side check), logged it, and kept the connection alive. We dispatch the
1101
+ // message to the user's error handler but don't tear down the client. Non-recoverable
1102
+ // errors are followed by a server disconnect; we set exit_code + stop() so callers
1103
+ // (CLI tools, the html_view UI) see the failure.
1104
+ const recoverable = !!message.value.recoverable;
1105
+ this.log(recoverable ? 'WARNING' : 'ERROR', `GAR ${message.value.message}`);
1106
+ if (!recoverable) {
1107
+ this.exitCode = 1;
1108
+ this.stop();
1109
+ }
1101
1110
  }
1102
1111
 
1103
1112
  this.checkHeartbeat();
@@ -1381,28 +1390,25 @@ class GARClient {
1381
1390
  }
1382
1391
 
1383
1392
  /**
1384
- * Introduce a new key if not already known and return local key ID.
1393
+ * Introduce a new key if not already known and return local key ID. className is required;
1394
+ * a bare introduction with no class_list can't be routed by upstream proxies.
1385
1395
  * @param {string} name - Key name
1386
- * @param {string|Array<string>|null} [className=null] - Class name(s)
1396
+ * @param {string|Array<string>} className - Class name(s)
1387
1397
  * @returns {number} Local key ID
1388
1398
  */
1389
- getAndPossiblyIntroduceKeyId(name, className = null) {
1399
+ getAndPossiblyIntroduceKeyId(name, className) {
1390
1400
  const existingId = this.localKeyMap.get(name);
1391
1401
  if (existingId !== undefined && this.invalidatedKeyIds.has(existingId)) {
1392
1402
  this.invalidatedKeyIds.delete(existingId);
1393
1403
  this.localKeyMap.delete(name);
1394
1404
  }
1395
1405
  if (!this.localKeyMap.has(name)) {
1406
+ if (!className) throw new Error(`getAndPossiblyIntroduceKeyId: className required to introduce key "${name}"`);
1396
1407
  const keyId = this.localKeyCounter++;
1397
1408
  this.localKeyMap.set(name, keyId);
1398
1409
  const value = { key_id: keyId, name };
1399
- if (className) {
1400
- if (typeof className === 'string') {
1401
- value.class_list = className.split(/\s+/).filter(Boolean);
1402
- } else if (Array.isArray(className)) {
1403
- value.class_list = className;
1404
- }
1405
- }
1410
+ if (typeof className === 'string') value.class_list = className.split(/\s+/).filter(Boolean);
1411
+ else if (Array.isArray(className)) value.class_list = className;
1406
1412
  this.sendMessage({ message_type: 'KeyIntroduction', value });
1407
1413
  }
1408
1414
  return this.localKeyMap.get(name);
@@ -1505,6 +1511,10 @@ class GARClient {
1505
1511
  * @param {any} value - JSON-serializable value
1506
1512
  */
1507
1513
  publishRecordWithIds(keyId, topicId, value) {
1514
+ if (value === undefined) {
1515
+ this.log('ERROR', `publishRecordWithIds(${keyId}, ${topicId}): refusing to publish undefined — JSON.stringify would drop the "value" field and the server would reject with "Missing record 'value' field"`);
1516
+ return;
1517
+ }
1508
1518
  const updateMsg = {
1509
1519
  message_type: 'JSONRecordUpdate',
1510
1520
  value: {
@@ -1523,6 +1533,10 @@ class GARClient {
1523
1533
  * @param {string|null} [className=null] - Class name
1524
1534
  */
1525
1535
  publishRecord(keyName, topicName, value, className = null) {
1536
+ if (value === undefined) {
1537
+ this.log('ERROR', `publishRecord(${keyName}, ${topicName}): refusing to publish undefined — JSON.stringify would drop the "value" field and the server would reject with "Missing record 'value' field"`);
1538
+ return;
1539
+ }
1526
1540
  const keyId = this.getAndPossiblyIntroduceKeyId(keyName, className);
1527
1541
  const topicId = this.getAndPossiblyIntroduceTopicId(topicName);
1528
1542
  this.publishRecordWithIds(keyId, topicId, value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsgar",
3
- "version": "4.9.0",
3
+ "version": "4.9.1",
4
4
  "description": "A Javascript client for the GAR protocol",
5
5
  "type": "module",
6
6
  "main": "dist/gar.umd.js",