jsgar 4.10.0 → 4.13.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 +132 -47
- package/gar.js +131 -47
- package/package.json +3 -1
package/dist/gar.umd.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.GARClient = {}));
|
|
5
5
|
})(this, (function (exports) { 'use strict';
|
|
6
6
|
|
|
7
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
7
8
|
/**
|
|
8
9
|
* A client implementation for the Generic Active Records (GAR) protocol using WebSockets.
|
|
9
10
|
* See trsgar.js for example usage.
|
|
@@ -805,25 +806,27 @@
|
|
|
805
806
|
|
|
806
807
|
async _ensureWebSocketCtor() {
|
|
807
808
|
// Return a WebSocket constructor for current environment.
|
|
808
|
-
//
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
// Node.js: resolve 'ws' at runtime
|
|
809
|
+
// In Node, always prefer the 'ws' package over globalThis.WebSocket.
|
|
810
|
+
// Node ≥21 ships a browser-spec WebSocket on globalThis that ignores the
|
|
811
|
+
// third-arg options object (rejectUnauthorized, headers, agent, etc.),
|
|
812
|
+
// which breaks self-signed certs and custom TLS configuration.
|
|
813
813
|
const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
|
|
814
814
|
if (isNode) {
|
|
815
815
|
try {
|
|
816
|
-
//
|
|
816
|
+
// Anchor resolution at this module so ws is found regardless of cwd.
|
|
817
817
|
const { createRequire } = await import('node:module');
|
|
818
|
-
const req = createRequire(
|
|
818
|
+
const req = createRequire((typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('gar.umd.js', document.baseURI).href)));
|
|
819
819
|
const mod = req('ws');
|
|
820
820
|
const WS = mod.default || mod.WebSocket || mod;
|
|
821
|
-
globalThis.WebSocket = WS;
|
|
822
821
|
return WS;
|
|
823
822
|
} catch {
|
|
824
823
|
throw new Error("'ws' module is required in Node.js environment. Please install it: npm install ws");
|
|
825
824
|
}
|
|
826
825
|
}
|
|
826
|
+
// Browser: use the platform WebSocket.
|
|
827
|
+
if (typeof globalThis !== 'undefined' && globalThis.WebSocket) {
|
|
828
|
+
return globalThis.WebSocket;
|
|
829
|
+
}
|
|
827
830
|
throw new Error('WebSocket constructor not found in this environment');
|
|
828
831
|
}
|
|
829
832
|
|
|
@@ -849,6 +852,31 @@
|
|
|
849
852
|
*/
|
|
850
853
|
sendMessage(message) {
|
|
851
854
|
this.messageQueue.push(message);
|
|
855
|
+
// Drain synchronously when possible: background tabs throttle timers — the polling
|
|
856
|
+
// drain loop (and any setInterval sender) can stretch from 100ms to minutes — but
|
|
857
|
+
// synchronous sends from an event or enqueue are never throttled.
|
|
858
|
+
this._flushQueue();
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* Synchronously send everything sendable. Safe alongside the polling loop (same JS
|
|
863
|
+
* thread); leaves the null shutdown sentinel for the loop's exit handling.
|
|
864
|
+
*/
|
|
865
|
+
_flushQueue() {
|
|
866
|
+
while (this.connected && this.messageQueue.length > 0 && this._isSocketOpen()) {
|
|
867
|
+
if (this.messageQueue[0] === null) return;
|
|
868
|
+
const message = this.messageQueue.shift();
|
|
869
|
+
try {
|
|
870
|
+
this.websocket.send(JSON.stringify(message));
|
|
871
|
+
if (this.logEveryMessage) {
|
|
872
|
+
this.log('INFO', `Sent: ${JSON.stringify(message)}`);
|
|
873
|
+
}
|
|
874
|
+
} catch (e) {
|
|
875
|
+
this.log('WARNING', `Error sending message: ${e.message}`);
|
|
876
|
+
this.halt();
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
852
880
|
}
|
|
853
881
|
|
|
854
882
|
/**
|
|
@@ -976,6 +1004,13 @@
|
|
|
976
1004
|
this.invalidatedKeyIds.add(message.value.client_introduced_key_id);
|
|
977
1005
|
} else if (msgType === 'Heartbeat') {
|
|
978
1006
|
this.lastHeartbeatTime = Date.now() / 1000;
|
|
1007
|
+
// Echo our own heartbeat on the server's cadence. A hidden tab's throttled timers
|
|
1008
|
+
// can silence the periodic sender far past the server's timeout while this
|
|
1009
|
+
// (unthrottled) receive path keeps delivering — the server then rightly declares
|
|
1010
|
+
// us dead. Event-driven liveness: receive -> reply, flushed synchronously above.
|
|
1011
|
+
if (this.running) {
|
|
1012
|
+
this.sendMessage({ message_type: 'Heartbeat', value: { u_milliseconds: Date.now() } });
|
|
1013
|
+
}
|
|
979
1014
|
if (this._initialGracePeriod) {
|
|
980
1015
|
// Resolve first-heartbeat waiters and end the initial grace window
|
|
981
1016
|
if (this._firstHeartbeatResolve) {
|
|
@@ -1092,13 +1127,8 @@
|
|
|
1092
1127
|
}
|
|
1093
1128
|
}
|
|
1094
1129
|
|
|
1095
|
-
// If there is a batch handler
|
|
1096
|
-
|
|
1097
|
-
const batchHandler = this.messageHandlers.get(batchHandlerKey);
|
|
1098
|
-
if (batchHandler) {
|
|
1099
|
-
batchHandler(message);
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1130
|
+
// If there is a batch handler the generic dispatch at the bottom of this method will
|
|
1131
|
+
// invoke it — do not call it explicitly here (would double-dispatch).
|
|
1102
1132
|
} else if (msgType === "ActiveSubscription") {
|
|
1103
1133
|
this.activeSubscriptionGroup = message["value"]["subscription_group"];
|
|
1104
1134
|
} else if (msgType === 'Logoff') {
|
|
@@ -1140,9 +1170,15 @@
|
|
|
1140
1170
|
}
|
|
1141
1171
|
|
|
1142
1172
|
/**
|
|
1143
|
-
* Send a subscription request
|
|
1144
|
-
*
|
|
1145
|
-
*
|
|
1173
|
+
* Send a subscription request from a named-options object — the canonical entry point.
|
|
1174
|
+
* Options are passed by name, so adding a new field can never positionally misalign an
|
|
1175
|
+
* existing caller (the failure mode of the positional `subscribe()` shim below). Owns the
|
|
1176
|
+
* convenience layer: mutual-exclusion assertions, string→single-element-list coercion, and
|
|
1177
|
+
* keyName/topicName/className resolution into the wire `key_id_list`/`topic_id_list`/
|
|
1178
|
+
* `class_list`. Produces a `g::proto::subscribe` value dict and hands it to subscribeFormatted.
|
|
1179
|
+
* @param {Object} opts - Named subscription options (fields below).
|
|
1180
|
+
* @param {string} opts.name - Subscription name
|
|
1181
|
+
* @param {string} [opts.subscriptionMode='Streaming'] - Subscription mode
|
|
1146
1182
|
* @param {string|Array<string>|null} [keyName=null] - Key name(s)
|
|
1147
1183
|
* @param {string|Array<string>|null} [topicName=null] - Topic name(s)
|
|
1148
1184
|
* @param {string|Array<string>|null} [className=null] - Class name(s)
|
|
@@ -1153,6 +1189,7 @@
|
|
|
1153
1189
|
* @param {string|null} [maxHistory] - Maximum history to include
|
|
1154
1190
|
* @param {boolean} [excludeDerived=false] - Exclude derived topics (derived topics are included by default)
|
|
1155
1191
|
* @param {boolean} [includeHeavy=false] - Include heavy derived topics (comprehensions, array-typed, heavy functions)
|
|
1192
|
+
* @param {boolean} [includeExplicit=false] - Include explicit-only topics (the `explicit` attribute, defaulted on for once-gated topics; excluded by default like includeHeavy)
|
|
1156
1193
|
* @param {boolean} [trimDefaultValues=false] - Trim records containing default values from the snapshot
|
|
1157
1194
|
* @param {string|null} [workingNamespace] - Namespace for matching relative paths
|
|
1158
1195
|
* @param {string|Array<string>|null} [restrictNamespace] - Restricts topics and keys to children of these namespaces (union). Defaults to the working namespace. Use ["::"] for root / no restriction.
|
|
@@ -1165,7 +1202,7 @@
|
|
|
1165
1202
|
* @param {number} [limit=0] - Limits records in initial snapshot (0 = all)
|
|
1166
1203
|
* @param {string|Array<string>|null} [referencingClassList=null] - Referencing class name(s); if provided, include referencing keys and records per proto.gar subscribe.referencing_class_list
|
|
1167
1204
|
*/
|
|
1168
|
-
|
|
1205
|
+
subscribeOptions({
|
|
1169
1206
|
name,
|
|
1170
1207
|
subscriptionMode = 'Streaming',
|
|
1171
1208
|
keyName = null,
|
|
@@ -1178,6 +1215,7 @@
|
|
|
1178
1215
|
maxHistory = null,
|
|
1179
1216
|
excludeDerived = false,
|
|
1180
1217
|
includeHeavy = false,
|
|
1218
|
+
includeExplicit = false,
|
|
1181
1219
|
trimDefaultValues = false,
|
|
1182
1220
|
workingNamespace = null,
|
|
1183
1221
|
restrictNamespace = null,
|
|
@@ -1189,7 +1227,7 @@
|
|
|
1189
1227
|
nagleInterval = 0,
|
|
1190
1228
|
limit = 0,
|
|
1191
1229
|
referencingClassList = null
|
|
1192
|
-
) {
|
|
1230
|
+
} = {}) {
|
|
1193
1231
|
// Validate mutually exclusive parameters
|
|
1194
1232
|
if (keyName && (keyFilter || excludeKeyFilter)) {
|
|
1195
1233
|
throw new Error('keyName cannot be used with keyFilter or excludeKeyFilter');
|
|
@@ -1271,6 +1309,9 @@
|
|
|
1271
1309
|
if (includeHeavy) {
|
|
1272
1310
|
valueDict.include_heavy = includeHeavy;
|
|
1273
1311
|
}
|
|
1312
|
+
if (includeExplicit) {
|
|
1313
|
+
valueDict.include_explicit = includeExplicit;
|
|
1314
|
+
}
|
|
1274
1315
|
if (restrictNamespace) {
|
|
1275
1316
|
valueDict.restrict_namespace = typeof restrictNamespace === 'string' ? [restrictNamespace] : restrictNamespace;
|
|
1276
1317
|
}
|
|
@@ -1314,6 +1355,47 @@
|
|
|
1314
1355
|
this.subscribeFormatted(valueDict);
|
|
1315
1356
|
}
|
|
1316
1357
|
|
|
1358
|
+
/**
|
|
1359
|
+
* Positional compatibility shim — packs its arguments by name and delegates to
|
|
1360
|
+
* subscribeOptions(). Prefer subscribeOptions({ ... }) in new code: its named signature makes
|
|
1361
|
+
* the positional-argument misalignment trap impossible. The parameter order here is frozen for
|
|
1362
|
+
* existing callers — never insert a new parameter mid-list; add new options to subscribeOptions.
|
|
1363
|
+
*/
|
|
1364
|
+
subscribe(
|
|
1365
|
+
name,
|
|
1366
|
+
subscriptionMode = 'Streaming',
|
|
1367
|
+
keyName = null,
|
|
1368
|
+
topicName = null,
|
|
1369
|
+
className = null,
|
|
1370
|
+
keyFilter = null,
|
|
1371
|
+
topicFilter = null,
|
|
1372
|
+
excludeKeyFilter = null,
|
|
1373
|
+
excludeTopicFilter = null,
|
|
1374
|
+
maxHistory = null,
|
|
1375
|
+
excludeDerived = false,
|
|
1376
|
+
includeHeavy = false,
|
|
1377
|
+
includeExplicit = false,
|
|
1378
|
+
trimDefaultValues = false,
|
|
1379
|
+
workingNamespace = null,
|
|
1380
|
+
restrictNamespace = null,
|
|
1381
|
+
excludeNamespace = null,
|
|
1382
|
+
density = null,
|
|
1383
|
+
subscriptionGroup = 0,
|
|
1384
|
+
subscriptionSet = null,
|
|
1385
|
+
snapshotSizeLimit = 0,
|
|
1386
|
+
nagleInterval = 0,
|
|
1387
|
+
limit = 0,
|
|
1388
|
+
referencingClassList = null
|
|
1389
|
+
) {
|
|
1390
|
+
this.subscribeOptions({
|
|
1391
|
+
name, subscriptionMode, keyName, topicName, className, keyFilter, topicFilter,
|
|
1392
|
+
excludeKeyFilter, excludeTopicFilter, maxHistory, excludeDerived, includeHeavy,
|
|
1393
|
+
includeExplicit, trimDefaultValues, workingNamespace, restrictNamespace, excludeNamespace,
|
|
1394
|
+
density, subscriptionGroup, subscriptionSet, snapshotSizeLimit, nagleInterval, limit,
|
|
1395
|
+
referencingClassList,
|
|
1396
|
+
});
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1317
1399
|
/**
|
|
1318
1400
|
* Wrapper to `subscribe` with a smaller set of arguments.
|
|
1319
1401
|
* @param {string} name - Subscription name
|
|
@@ -1351,16 +1433,17 @@
|
|
|
1351
1433
|
topicFilter,
|
|
1352
1434
|
excludeKeyFilter,
|
|
1353
1435
|
excludeTopicFilter,
|
|
1354
|
-
null,
|
|
1355
|
-
false,
|
|
1356
|
-
false,
|
|
1357
|
-
false,
|
|
1358
|
-
|
|
1359
|
-
null,
|
|
1360
|
-
null,
|
|
1361
|
-
null,
|
|
1436
|
+
null, // maxHistory
|
|
1437
|
+
false, // excludeDerived
|
|
1438
|
+
false, // includeHeavy
|
|
1439
|
+
false, // includeExplicit
|
|
1440
|
+
false, // trimDefaultValues
|
|
1441
|
+
null, // workingNamespace
|
|
1442
|
+
null, // restrictNamespace
|
|
1443
|
+
null, // excludeNamespace
|
|
1444
|
+
null, // density
|
|
1362
1445
|
subscriptionGroup,
|
|
1363
|
-
null,
|
|
1446
|
+
null, // subscriptionSet
|
|
1364
1447
|
snapshotSizeLimit
|
|
1365
1448
|
);
|
|
1366
1449
|
}
|
|
@@ -1692,15 +1775,16 @@
|
|
|
1692
1775
|
null,
|
|
1693
1776
|
null,
|
|
1694
1777
|
null,
|
|
1695
|
-
null,
|
|
1696
|
-
false,
|
|
1697
|
-
false,
|
|
1698
|
-
false,
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
null,
|
|
1702
|
-
null,
|
|
1703
|
-
|
|
1778
|
+
null, // maxHistory
|
|
1779
|
+
false, // excludeDerived
|
|
1780
|
+
false, // includeHeavy
|
|
1781
|
+
false, // includeExplicit
|
|
1782
|
+
false, // trimDefaultValues
|
|
1783
|
+
'g::deployment::Server', // workingNamespace
|
|
1784
|
+
null, // restrictNamespace
|
|
1785
|
+
null, // excludeNamespace
|
|
1786
|
+
null, // density
|
|
1787
|
+
subscriptionGroupServerRecords, // subscriptionGroup
|
|
1704
1788
|
);
|
|
1705
1789
|
};
|
|
1706
1790
|
|
|
@@ -1742,15 +1826,16 @@
|
|
|
1742
1826
|
null,
|
|
1743
1827
|
null,
|
|
1744
1828
|
null,
|
|
1745
|
-
null,
|
|
1746
|
-
false,
|
|
1747
|
-
false,
|
|
1748
|
-
false,
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
null,
|
|
1752
|
-
null,
|
|
1753
|
-
|
|
1829
|
+
null, // maxHistory
|
|
1830
|
+
false, // excludeDerived
|
|
1831
|
+
false, // includeHeavy
|
|
1832
|
+
false, // includeExplicit
|
|
1833
|
+
false, // trimDefaultValues
|
|
1834
|
+
'g::deployment::RecordFilter', // workingNamespace
|
|
1835
|
+
null, // restrictNamespace
|
|
1836
|
+
null, // excludeNamespace
|
|
1837
|
+
null, // density
|
|
1838
|
+
subscriptionGroupServerKeys, // subscriptionGroup
|
|
1754
1839
|
);
|
|
1755
1840
|
|
|
1756
1841
|
// Timeout handling
|
package/gar.js
CHANGED
|
@@ -799,25 +799,27 @@ class GARClient {
|
|
|
799
799
|
|
|
800
800
|
async _ensureWebSocketCtor() {
|
|
801
801
|
// Return a WebSocket constructor for current environment.
|
|
802
|
-
//
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
// Node.js: resolve 'ws' at runtime
|
|
802
|
+
// In Node, always prefer the 'ws' package over globalThis.WebSocket.
|
|
803
|
+
// Node ≥21 ships a browser-spec WebSocket on globalThis that ignores the
|
|
804
|
+
// third-arg options object (rejectUnauthorized, headers, agent, etc.),
|
|
805
|
+
// which breaks self-signed certs and custom TLS configuration.
|
|
807
806
|
const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
|
|
808
807
|
if (isNode) {
|
|
809
808
|
try {
|
|
810
|
-
//
|
|
809
|
+
// Anchor resolution at this module so ws is found regardless of cwd.
|
|
811
810
|
const { createRequire } = await import('node:module');
|
|
812
|
-
const req = createRequire(
|
|
811
|
+
const req = createRequire(import.meta.url);
|
|
813
812
|
const mod = req('ws');
|
|
814
813
|
const WS = mod.default || mod.WebSocket || mod;
|
|
815
|
-
globalThis.WebSocket = WS;
|
|
816
814
|
return WS;
|
|
817
815
|
} catch {
|
|
818
816
|
throw new Error("'ws' module is required in Node.js environment. Please install it: npm install ws");
|
|
819
817
|
}
|
|
820
818
|
}
|
|
819
|
+
// Browser: use the platform WebSocket.
|
|
820
|
+
if (typeof globalThis !== 'undefined' && globalThis.WebSocket) {
|
|
821
|
+
return globalThis.WebSocket;
|
|
822
|
+
}
|
|
821
823
|
throw new Error('WebSocket constructor not found in this environment');
|
|
822
824
|
}
|
|
823
825
|
|
|
@@ -843,6 +845,31 @@ class GARClient {
|
|
|
843
845
|
*/
|
|
844
846
|
sendMessage(message) {
|
|
845
847
|
this.messageQueue.push(message);
|
|
848
|
+
// Drain synchronously when possible: background tabs throttle timers — the polling
|
|
849
|
+
// drain loop (and any setInterval sender) can stretch from 100ms to minutes — but
|
|
850
|
+
// synchronous sends from an event or enqueue are never throttled.
|
|
851
|
+
this._flushQueue();
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
/**
|
|
855
|
+
* Synchronously send everything sendable. Safe alongside the polling loop (same JS
|
|
856
|
+
* thread); leaves the null shutdown sentinel for the loop's exit handling.
|
|
857
|
+
*/
|
|
858
|
+
_flushQueue() {
|
|
859
|
+
while (this.connected && this.messageQueue.length > 0 && this._isSocketOpen()) {
|
|
860
|
+
if (this.messageQueue[0] === null) return;
|
|
861
|
+
const message = this.messageQueue.shift();
|
|
862
|
+
try {
|
|
863
|
+
this.websocket.send(JSON.stringify(message));
|
|
864
|
+
if (this.logEveryMessage) {
|
|
865
|
+
this.log('INFO', `Sent: ${JSON.stringify(message)}`);
|
|
866
|
+
}
|
|
867
|
+
} catch (e) {
|
|
868
|
+
this.log('WARNING', `Error sending message: ${e.message}`);
|
|
869
|
+
this.halt();
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
846
873
|
}
|
|
847
874
|
|
|
848
875
|
/**
|
|
@@ -970,6 +997,13 @@ class GARClient {
|
|
|
970
997
|
this.invalidatedKeyIds.add(message.value.client_introduced_key_id);
|
|
971
998
|
} else if (msgType === 'Heartbeat') {
|
|
972
999
|
this.lastHeartbeatTime = Date.now() / 1000;
|
|
1000
|
+
// Echo our own heartbeat on the server's cadence. A hidden tab's throttled timers
|
|
1001
|
+
// can silence the periodic sender far past the server's timeout while this
|
|
1002
|
+
// (unthrottled) receive path keeps delivering — the server then rightly declares
|
|
1003
|
+
// us dead. Event-driven liveness: receive -> reply, flushed synchronously above.
|
|
1004
|
+
if (this.running) {
|
|
1005
|
+
this.sendMessage({ message_type: 'Heartbeat', value: { u_milliseconds: Date.now() } });
|
|
1006
|
+
}
|
|
973
1007
|
if (this._initialGracePeriod) {
|
|
974
1008
|
// Resolve first-heartbeat waiters and end the initial grace window
|
|
975
1009
|
if (this._firstHeartbeatResolve) {
|
|
@@ -1086,13 +1120,8 @@ class GARClient {
|
|
|
1086
1120
|
}
|
|
1087
1121
|
}
|
|
1088
1122
|
|
|
1089
|
-
// If there is a batch handler
|
|
1090
|
-
|
|
1091
|
-
const batchHandler = this.messageHandlers.get(batchHandlerKey);
|
|
1092
|
-
if (batchHandler) {
|
|
1093
|
-
batchHandler(message);
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1123
|
+
// If there is a batch handler the generic dispatch at the bottom of this method will
|
|
1124
|
+
// invoke it — do not call it explicitly here (would double-dispatch).
|
|
1096
1125
|
} else if (msgType === "ActiveSubscription") {
|
|
1097
1126
|
this.activeSubscriptionGroup = message["value"]["subscription_group"]
|
|
1098
1127
|
} else if (msgType === 'Logoff') {
|
|
@@ -1134,9 +1163,15 @@ class GARClient {
|
|
|
1134
1163
|
}
|
|
1135
1164
|
|
|
1136
1165
|
/**
|
|
1137
|
-
* Send a subscription request
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
1166
|
+
* Send a subscription request from a named-options object — the canonical entry point.
|
|
1167
|
+
* Options are passed by name, so adding a new field can never positionally misalign an
|
|
1168
|
+
* existing caller (the failure mode of the positional `subscribe()` shim below). Owns the
|
|
1169
|
+
* convenience layer: mutual-exclusion assertions, string→single-element-list coercion, and
|
|
1170
|
+
* keyName/topicName/className resolution into the wire `key_id_list`/`topic_id_list`/
|
|
1171
|
+
* `class_list`. Produces a `g::proto::subscribe` value dict and hands it to subscribeFormatted.
|
|
1172
|
+
* @param {Object} opts - Named subscription options (fields below).
|
|
1173
|
+
* @param {string} opts.name - Subscription name
|
|
1174
|
+
* @param {string} [opts.subscriptionMode='Streaming'] - Subscription mode
|
|
1140
1175
|
* @param {string|Array<string>|null} [keyName=null] - Key name(s)
|
|
1141
1176
|
* @param {string|Array<string>|null} [topicName=null] - Topic name(s)
|
|
1142
1177
|
* @param {string|Array<string>|null} [className=null] - Class name(s)
|
|
@@ -1147,6 +1182,7 @@ class GARClient {
|
|
|
1147
1182
|
* @param {string|null} [maxHistory] - Maximum history to include
|
|
1148
1183
|
* @param {boolean} [excludeDerived=false] - Exclude derived topics (derived topics are included by default)
|
|
1149
1184
|
* @param {boolean} [includeHeavy=false] - Include heavy derived topics (comprehensions, array-typed, heavy functions)
|
|
1185
|
+
* @param {boolean} [includeExplicit=false] - Include explicit-only topics (the `explicit` attribute, defaulted on for once-gated topics; excluded by default like includeHeavy)
|
|
1150
1186
|
* @param {boolean} [trimDefaultValues=false] - Trim records containing default values from the snapshot
|
|
1151
1187
|
* @param {string|null} [workingNamespace] - Namespace for matching relative paths
|
|
1152
1188
|
* @param {string|Array<string>|null} [restrictNamespace] - Restricts topics and keys to children of these namespaces (union). Defaults to the working namespace. Use ["::"] for root / no restriction.
|
|
@@ -1159,7 +1195,7 @@ class GARClient {
|
|
|
1159
1195
|
* @param {number} [limit=0] - Limits records in initial snapshot (0 = all)
|
|
1160
1196
|
* @param {string|Array<string>|null} [referencingClassList=null] - Referencing class name(s); if provided, include referencing keys and records per proto.gar subscribe.referencing_class_list
|
|
1161
1197
|
*/
|
|
1162
|
-
|
|
1198
|
+
subscribeOptions({
|
|
1163
1199
|
name,
|
|
1164
1200
|
subscriptionMode = 'Streaming',
|
|
1165
1201
|
keyName = null,
|
|
@@ -1172,6 +1208,7 @@ class GARClient {
|
|
|
1172
1208
|
maxHistory = null,
|
|
1173
1209
|
excludeDerived = false,
|
|
1174
1210
|
includeHeavy = false,
|
|
1211
|
+
includeExplicit = false,
|
|
1175
1212
|
trimDefaultValues = false,
|
|
1176
1213
|
workingNamespace = null,
|
|
1177
1214
|
restrictNamespace = null,
|
|
@@ -1183,7 +1220,7 @@ class GARClient {
|
|
|
1183
1220
|
nagleInterval = 0,
|
|
1184
1221
|
limit = 0,
|
|
1185
1222
|
referencingClassList = null
|
|
1186
|
-
) {
|
|
1223
|
+
} = {}) {
|
|
1187
1224
|
// Validate mutually exclusive parameters
|
|
1188
1225
|
if (keyName && (keyFilter || excludeKeyFilter)) {
|
|
1189
1226
|
throw new Error('keyName cannot be used with keyFilter or excludeKeyFilter');
|
|
@@ -1265,6 +1302,9 @@ class GARClient {
|
|
|
1265
1302
|
if (includeHeavy) {
|
|
1266
1303
|
valueDict.include_heavy = includeHeavy;
|
|
1267
1304
|
}
|
|
1305
|
+
if (includeExplicit) {
|
|
1306
|
+
valueDict.include_explicit = includeExplicit;
|
|
1307
|
+
}
|
|
1268
1308
|
if (restrictNamespace) {
|
|
1269
1309
|
valueDict.restrict_namespace = typeof restrictNamespace === 'string' ? [restrictNamespace] : restrictNamespace;
|
|
1270
1310
|
}
|
|
@@ -1308,6 +1348,47 @@ class GARClient {
|
|
|
1308
1348
|
this.subscribeFormatted(valueDict);
|
|
1309
1349
|
}
|
|
1310
1350
|
|
|
1351
|
+
/**
|
|
1352
|
+
* Positional compatibility shim — packs its arguments by name and delegates to
|
|
1353
|
+
* subscribeOptions(). Prefer subscribeOptions({ ... }) in new code: its named signature makes
|
|
1354
|
+
* the positional-argument misalignment trap impossible. The parameter order here is frozen for
|
|
1355
|
+
* existing callers — never insert a new parameter mid-list; add new options to subscribeOptions.
|
|
1356
|
+
*/
|
|
1357
|
+
subscribe(
|
|
1358
|
+
name,
|
|
1359
|
+
subscriptionMode = 'Streaming',
|
|
1360
|
+
keyName = null,
|
|
1361
|
+
topicName = null,
|
|
1362
|
+
className = null,
|
|
1363
|
+
keyFilter = null,
|
|
1364
|
+
topicFilter = null,
|
|
1365
|
+
excludeKeyFilter = null,
|
|
1366
|
+
excludeTopicFilter = null,
|
|
1367
|
+
maxHistory = null,
|
|
1368
|
+
excludeDerived = false,
|
|
1369
|
+
includeHeavy = false,
|
|
1370
|
+
includeExplicit = false,
|
|
1371
|
+
trimDefaultValues = false,
|
|
1372
|
+
workingNamespace = null,
|
|
1373
|
+
restrictNamespace = null,
|
|
1374
|
+
excludeNamespace = null,
|
|
1375
|
+
density = null,
|
|
1376
|
+
subscriptionGroup = 0,
|
|
1377
|
+
subscriptionSet = null,
|
|
1378
|
+
snapshotSizeLimit = 0,
|
|
1379
|
+
nagleInterval = 0,
|
|
1380
|
+
limit = 0,
|
|
1381
|
+
referencingClassList = null
|
|
1382
|
+
) {
|
|
1383
|
+
this.subscribeOptions({
|
|
1384
|
+
name, subscriptionMode, keyName, topicName, className, keyFilter, topicFilter,
|
|
1385
|
+
excludeKeyFilter, excludeTopicFilter, maxHistory, excludeDerived, includeHeavy,
|
|
1386
|
+
includeExplicit, trimDefaultValues, workingNamespace, restrictNamespace, excludeNamespace,
|
|
1387
|
+
density, subscriptionGroup, subscriptionSet, snapshotSizeLimit, nagleInterval, limit,
|
|
1388
|
+
referencingClassList,
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1311
1392
|
/**
|
|
1312
1393
|
* Wrapper to `subscribe` with a smaller set of arguments.
|
|
1313
1394
|
* @param {string} name - Subscription name
|
|
@@ -1345,16 +1426,17 @@ class GARClient {
|
|
|
1345
1426
|
topicFilter,
|
|
1346
1427
|
excludeKeyFilter,
|
|
1347
1428
|
excludeTopicFilter,
|
|
1348
|
-
null,
|
|
1349
|
-
false,
|
|
1350
|
-
false,
|
|
1351
|
-
false,
|
|
1352
|
-
|
|
1353
|
-
null,
|
|
1354
|
-
null,
|
|
1355
|
-
null,
|
|
1429
|
+
null, // maxHistory
|
|
1430
|
+
false, // excludeDerived
|
|
1431
|
+
false, // includeHeavy
|
|
1432
|
+
false, // includeExplicit
|
|
1433
|
+
false, // trimDefaultValues
|
|
1434
|
+
null, // workingNamespace
|
|
1435
|
+
null, // restrictNamespace
|
|
1436
|
+
null, // excludeNamespace
|
|
1437
|
+
null, // density
|
|
1356
1438
|
subscriptionGroup,
|
|
1357
|
-
null,
|
|
1439
|
+
null, // subscriptionSet
|
|
1358
1440
|
snapshotSizeLimit
|
|
1359
1441
|
);
|
|
1360
1442
|
}
|
|
@@ -1686,15 +1768,16 @@ class GARClient {
|
|
|
1686
1768
|
null,
|
|
1687
1769
|
null,
|
|
1688
1770
|
null,
|
|
1689
|
-
null,
|
|
1690
|
-
false,
|
|
1691
|
-
false,
|
|
1692
|
-
false,
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
null,
|
|
1696
|
-
null,
|
|
1697
|
-
|
|
1771
|
+
null, // maxHistory
|
|
1772
|
+
false, // excludeDerived
|
|
1773
|
+
false, // includeHeavy
|
|
1774
|
+
false, // includeExplicit
|
|
1775
|
+
false, // trimDefaultValues
|
|
1776
|
+
'g::deployment::Server', // workingNamespace
|
|
1777
|
+
null, // restrictNamespace
|
|
1778
|
+
null, // excludeNamespace
|
|
1779
|
+
null, // density
|
|
1780
|
+
subscriptionGroupServerRecords, // subscriptionGroup
|
|
1698
1781
|
);
|
|
1699
1782
|
};
|
|
1700
1783
|
|
|
@@ -1736,15 +1819,16 @@ class GARClient {
|
|
|
1736
1819
|
null,
|
|
1737
1820
|
null,
|
|
1738
1821
|
null,
|
|
1739
|
-
null,
|
|
1740
|
-
false,
|
|
1741
|
-
false,
|
|
1742
|
-
false,
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
null,
|
|
1746
|
-
null,
|
|
1747
|
-
|
|
1822
|
+
null, // maxHistory
|
|
1823
|
+
false, // excludeDerived
|
|
1824
|
+
false, // includeHeavy
|
|
1825
|
+
false, // includeExplicit
|
|
1826
|
+
false, // trimDefaultValues
|
|
1827
|
+
'g::deployment::RecordFilter', // workingNamespace
|
|
1828
|
+
null, // restrictNamespace
|
|
1829
|
+
null, // excludeNamespace
|
|
1830
|
+
null, // density
|
|
1831
|
+
subscriptionGroupServerKeys, // subscriptionGroup
|
|
1748
1832
|
);
|
|
1749
1833
|
|
|
1750
1834
|
// Timeout handling
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jsgar",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.13.2",
|
|
4
4
|
"description": "A Javascript client for the GAR protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/gar.umd.js",
|
|
@@ -36,6 +36,8 @@
|
|
|
36
36
|
"@eslint/json": "^0.13.2",
|
|
37
37
|
"@rollup/plugin-commonjs": "^24.0.0",
|
|
38
38
|
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
39
|
+
"@xterm/addon-fit": "^0.10.0",
|
|
40
|
+
"@xterm/xterm": "^5.5.0",
|
|
39
41
|
"ag-grid-community": "^34.1.1",
|
|
40
42
|
"ag-grid-enterprise": "^34.1.1",
|
|
41
43
|
"eslint": "^9.39.4",
|