jsgar 4.9.0 → 4.9.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/dist/gar.umd.js +35 -17
- package/gar.js +35 -17
- package/package.json +1 -1
package/dist/gar.umd.js
CHANGED
|
@@ -1040,10 +1040,14 @@
|
|
|
1040
1040
|
const keyId = keyUpdate.key_id;
|
|
1041
1041
|
const keyName = keyUpdate.name;
|
|
1042
1042
|
|
|
1043
|
-
// Handle key introduction if name is provided
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1043
|
+
// Handle key introduction if name is provided. De-dup only the
|
|
1044
|
+
// serverKey*ToName/Id maps; always invoke the registered handler
|
|
1045
|
+
// so callers see every BatchUpdate-carried key event.
|
|
1046
|
+
if (keyName) {
|
|
1047
|
+
if (!this.serverKeyIdToName.has(keyId)) {
|
|
1048
|
+
this.serverKeyIdToName.set(keyId, keyName);
|
|
1049
|
+
this.serverKeyNameToId.set(keyName, keyId);
|
|
1050
|
+
}
|
|
1047
1051
|
|
|
1048
1052
|
// If no batch handler but key handler exists, call KeyIntroduction handler
|
|
1049
1053
|
if (!hasBatchHandler && keyHandler) {
|
|
@@ -1101,9 +1105,18 @@
|
|
|
1101
1105
|
this.log('INFO', 'Received Logoff from server');
|
|
1102
1106
|
this.stop();
|
|
1103
1107
|
} else if (msgType === 'Error') {
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1108
|
+
// proto.gar's `error` struct carries `recoverable: bool`. Recoverable errors mean
|
|
1109
|
+
// the server processed the failing message (e.g. a publish that violated some
|
|
1110
|
+
// server-side check), logged it, and kept the connection alive. We dispatch the
|
|
1111
|
+
// message to the user's error handler but don't tear down the client. Non-recoverable
|
|
1112
|
+
// errors are followed by a server disconnect; we set exit_code + stop() so callers
|
|
1113
|
+
// (CLI tools, the html_view UI) see the failure.
|
|
1114
|
+
const recoverable = !!message.value.recoverable;
|
|
1115
|
+
this.log(recoverable ? 'WARNING' : 'ERROR', `GAR ${message.value.message}`);
|
|
1116
|
+
if (!recoverable) {
|
|
1117
|
+
this.exitCode = 1;
|
|
1118
|
+
this.stop();
|
|
1119
|
+
}
|
|
1107
1120
|
}
|
|
1108
1121
|
|
|
1109
1122
|
this.checkHeartbeat();
|
|
@@ -1387,28 +1400,25 @@
|
|
|
1387
1400
|
}
|
|
1388
1401
|
|
|
1389
1402
|
/**
|
|
1390
|
-
* Introduce a new key if not already known and return local key ID.
|
|
1403
|
+
* Introduce a new key if not already known and return local key ID. className is required;
|
|
1404
|
+
* a bare introduction with no class_list can't be routed by upstream proxies.
|
|
1391
1405
|
* @param {string} name - Key name
|
|
1392
|
-
* @param {string|Array<string
|
|
1406
|
+
* @param {string|Array<string>} className - Class name(s)
|
|
1393
1407
|
* @returns {number} Local key ID
|
|
1394
1408
|
*/
|
|
1395
|
-
getAndPossiblyIntroduceKeyId(name, className
|
|
1409
|
+
getAndPossiblyIntroduceKeyId(name, className) {
|
|
1396
1410
|
const existingId = this.localKeyMap.get(name);
|
|
1397
1411
|
if (existingId !== undefined && this.invalidatedKeyIds.has(existingId)) {
|
|
1398
1412
|
this.invalidatedKeyIds.delete(existingId);
|
|
1399
1413
|
this.localKeyMap.delete(name);
|
|
1400
1414
|
}
|
|
1401
1415
|
if (!this.localKeyMap.has(name)) {
|
|
1416
|
+
if (!className) throw new Error(`getAndPossiblyIntroduceKeyId: className required to introduce key "${name}"`);
|
|
1402
1417
|
const keyId = this.localKeyCounter++;
|
|
1403
1418
|
this.localKeyMap.set(name, keyId);
|
|
1404
1419
|
const value = { key_id: keyId, name };
|
|
1405
|
-
if (className)
|
|
1406
|
-
|
|
1407
|
-
value.class_list = className.split(/\s+/).filter(Boolean);
|
|
1408
|
-
} else if (Array.isArray(className)) {
|
|
1409
|
-
value.class_list = className;
|
|
1410
|
-
}
|
|
1411
|
-
}
|
|
1420
|
+
if (typeof className === 'string') value.class_list = className.split(/\s+/).filter(Boolean);
|
|
1421
|
+
else if (Array.isArray(className)) value.class_list = className;
|
|
1412
1422
|
this.sendMessage({ message_type: 'KeyIntroduction', value });
|
|
1413
1423
|
}
|
|
1414
1424
|
return this.localKeyMap.get(name);
|
|
@@ -1511,6 +1521,10 @@
|
|
|
1511
1521
|
* @param {any} value - JSON-serializable value
|
|
1512
1522
|
*/
|
|
1513
1523
|
publishRecordWithIds(keyId, topicId, value) {
|
|
1524
|
+
if (value === undefined) {
|
|
1525
|
+
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"`);
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1514
1528
|
const updateMsg = {
|
|
1515
1529
|
message_type: 'JSONRecordUpdate',
|
|
1516
1530
|
value: {
|
|
@@ -1529,6 +1543,10 @@
|
|
|
1529
1543
|
* @param {string|null} [className=null] - Class name
|
|
1530
1544
|
*/
|
|
1531
1545
|
publishRecord(keyName, topicName, value, className = null) {
|
|
1546
|
+
if (value === undefined) {
|
|
1547
|
+
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"`);
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1532
1550
|
const keyId = this.getAndPossiblyIntroduceKeyId(keyName, className);
|
|
1533
1551
|
const topicId = this.getAndPossiblyIntroduceTopicId(topicName);
|
|
1534
1552
|
this.publishRecordWithIds(keyId, topicId, value);
|
package/gar.js
CHANGED
|
@@ -1034,10 +1034,14 @@ class GARClient {
|
|
|
1034
1034
|
const keyId = keyUpdate.key_id;
|
|
1035
1035
|
const keyName = keyUpdate.name;
|
|
1036
1036
|
|
|
1037
|
-
// Handle key introduction if name is provided
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1037
|
+
// Handle key introduction if name is provided. De-dup only the
|
|
1038
|
+
// serverKey*ToName/Id maps; always invoke the registered handler
|
|
1039
|
+
// so callers see every BatchUpdate-carried key event.
|
|
1040
|
+
if (keyName) {
|
|
1041
|
+
if (!this.serverKeyIdToName.has(keyId)) {
|
|
1042
|
+
this.serverKeyIdToName.set(keyId, keyName);
|
|
1043
|
+
this.serverKeyNameToId.set(keyName, keyId);
|
|
1044
|
+
}
|
|
1041
1045
|
|
|
1042
1046
|
// If no batch handler but key handler exists, call KeyIntroduction handler
|
|
1043
1047
|
if (!hasBatchHandler && keyHandler) {
|
|
@@ -1095,9 +1099,18 @@ class GARClient {
|
|
|
1095
1099
|
this.log('INFO', 'Received Logoff from server');
|
|
1096
1100
|
this.stop();
|
|
1097
1101
|
} else if (msgType === 'Error') {
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1102
|
+
// proto.gar's `error` struct carries `recoverable: bool`. Recoverable errors mean
|
|
1103
|
+
// the server processed the failing message (e.g. a publish that violated some
|
|
1104
|
+
// server-side check), logged it, and kept the connection alive. We dispatch the
|
|
1105
|
+
// message to the user's error handler but don't tear down the client. Non-recoverable
|
|
1106
|
+
// errors are followed by a server disconnect; we set exit_code + stop() so callers
|
|
1107
|
+
// (CLI tools, the html_view UI) see the failure.
|
|
1108
|
+
const recoverable = !!message.value.recoverable;
|
|
1109
|
+
this.log(recoverable ? 'WARNING' : 'ERROR', `GAR ${message.value.message}`);
|
|
1110
|
+
if (!recoverable) {
|
|
1111
|
+
this.exitCode = 1;
|
|
1112
|
+
this.stop();
|
|
1113
|
+
}
|
|
1101
1114
|
}
|
|
1102
1115
|
|
|
1103
1116
|
this.checkHeartbeat();
|
|
@@ -1381,28 +1394,25 @@ class GARClient {
|
|
|
1381
1394
|
}
|
|
1382
1395
|
|
|
1383
1396
|
/**
|
|
1384
|
-
* Introduce a new key if not already known and return local key ID.
|
|
1397
|
+
* Introduce a new key if not already known and return local key ID. className is required;
|
|
1398
|
+
* a bare introduction with no class_list can't be routed by upstream proxies.
|
|
1385
1399
|
* @param {string} name - Key name
|
|
1386
|
-
* @param {string|Array<string
|
|
1400
|
+
* @param {string|Array<string>} className - Class name(s)
|
|
1387
1401
|
* @returns {number} Local key ID
|
|
1388
1402
|
*/
|
|
1389
|
-
getAndPossiblyIntroduceKeyId(name, className
|
|
1403
|
+
getAndPossiblyIntroduceKeyId(name, className) {
|
|
1390
1404
|
const existingId = this.localKeyMap.get(name);
|
|
1391
1405
|
if (existingId !== undefined && this.invalidatedKeyIds.has(existingId)) {
|
|
1392
1406
|
this.invalidatedKeyIds.delete(existingId);
|
|
1393
1407
|
this.localKeyMap.delete(name);
|
|
1394
1408
|
}
|
|
1395
1409
|
if (!this.localKeyMap.has(name)) {
|
|
1410
|
+
if (!className) throw new Error(`getAndPossiblyIntroduceKeyId: className required to introduce key "${name}"`);
|
|
1396
1411
|
const keyId = this.localKeyCounter++;
|
|
1397
1412
|
this.localKeyMap.set(name, keyId);
|
|
1398
1413
|
const value = { key_id: keyId, name };
|
|
1399
|
-
if (className)
|
|
1400
|
-
|
|
1401
|
-
value.class_list = className.split(/\s+/).filter(Boolean);
|
|
1402
|
-
} else if (Array.isArray(className)) {
|
|
1403
|
-
value.class_list = className;
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1414
|
+
if (typeof className === 'string') value.class_list = className.split(/\s+/).filter(Boolean);
|
|
1415
|
+
else if (Array.isArray(className)) value.class_list = className;
|
|
1406
1416
|
this.sendMessage({ message_type: 'KeyIntroduction', value });
|
|
1407
1417
|
}
|
|
1408
1418
|
return this.localKeyMap.get(name);
|
|
@@ -1505,6 +1515,10 @@ class GARClient {
|
|
|
1505
1515
|
* @param {any} value - JSON-serializable value
|
|
1506
1516
|
*/
|
|
1507
1517
|
publishRecordWithIds(keyId, topicId, value) {
|
|
1518
|
+
if (value === undefined) {
|
|
1519
|
+
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"`);
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1508
1522
|
const updateMsg = {
|
|
1509
1523
|
message_type: 'JSONRecordUpdate',
|
|
1510
1524
|
value: {
|
|
@@ -1523,6 +1537,10 @@ class GARClient {
|
|
|
1523
1537
|
* @param {string|null} [className=null] - Class name
|
|
1524
1538
|
*/
|
|
1525
1539
|
publishRecord(keyName, topicName, value, className = null) {
|
|
1540
|
+
if (value === undefined) {
|
|
1541
|
+
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"`);
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1526
1544
|
const keyId = this.getAndPossiblyIntroduceKeyId(keyName, className);
|
|
1527
1545
|
const topicId = this.getAndPossiblyIntroduceTopicId(topicName);
|
|
1528
1546
|
this.publishRecordWithIds(keyId, topicId, value);
|