unetjs 3.1.5 → 3.2.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.
package/dist/cjs/unet.cjs CHANGED
@@ -1,8 +1,8 @@
1
- /* unet.js v3.1.5 2024-09-13T08:21:33.662Z */
1
+ /* unet.js v3.2.1 2025-01-31T16:55:08.539Z */
2
2
 
3
3
  'use strict';
4
4
 
5
- /* fjage.js v1.12.2 */
5
+ /* fjage.js v1.13.7 */
6
6
 
7
7
  const isBrowser =
8
8
  typeof window !== "undefined" && typeof window.document !== "undefined";
@@ -27,9 +27,7 @@ const isJsDom =
27
27
  (navigator.userAgent.includes("Node.js") ||
28
28
  navigator.userAgent.includes("jsdom")));
29
29
 
30
- typeof Deno !== "undefined" &&
31
- typeof Deno.version !== "undefined" &&
32
- typeof Deno.version.deno !== "undefined";
30
+ typeof Deno !== "undefined" && typeof Deno.core !== "undefined";
33
31
 
34
32
  const SOCKET_OPEN = 'open';
35
33
  const SOCKET_OPENING = 'opening';
@@ -41,29 +39,31 @@ var createConnection;
41
39
  * @class
42
40
  * @ignore
43
41
  */
44
- class TCPconnector {
42
+ class TCPConnector {
45
43
 
46
44
  /**
47
45
  * Create an TCPConnector to connect to a fjage master over TCP
48
46
  * @param {Object} opts
49
- * @param {string} opts.hostname - hostname/ip address of the master container to connect to
50
- * @param {string} opts.port - port number of the master container to connect to
51
- * @param {boolean} opts.keepAlive - try to reconnect if the connection is lost
47
+ * @param {string} [opts.hostname='localhost'] - hostname/ip address of the master container to connect to
48
+ * @param {number} [opts.port=1100] - port number of the master container to connect to
49
+ * @param {boolean} [opts.keepAlive=true] - try to reconnect if the connection is lost
50
+ * @param {boolean} [opts.debug=false] - debug info to be logged to console?
52
51
  * @param {number} [opts.reconnectTime=5000] - time before reconnection is attempted after an error
53
52
  */
54
53
  constructor(opts = {}) {
55
- let host = opts.hostname;
56
- let port = opts.port;
54
+ let host = opts.hostname || 'localhost';
55
+ let port = opts.port || 1100;
57
56
  this._keepAlive = opts.keepAlive;
58
57
  this._reconnectTime = opts.reconnectTime || DEFAULT_RECONNECT_TIME$1;
59
58
  this.url = new URL('tcp://localhost');
60
59
  this.url.hostname = host;
61
- this.url.port = port;
60
+ this.url.port = port.toString();
62
61
  this._buf = '';
63
62
  this._firstConn = true; // if the Gateway has managed to connect to a server before
64
63
  this._firstReConn = true; // if the Gateway has attempted to reconnect to a server before
65
64
  this.pendingOnOpen = []; // list of callbacks make as soon as gateway is open
66
65
  this.connListeners = []; // external listeners wanting to listen connection events
66
+ this.debug = false;
67
67
  this._sockInit(host, port);
68
68
  }
69
69
 
@@ -77,6 +77,7 @@ class TCPconnector {
77
77
  _sockInit(host, port){
78
78
  if (!createConnection){
79
79
  try {
80
+ // @ts-ignore
80
81
  import('net').then(module => {
81
82
  createConnection = module.createConnection;
82
83
  this._sockSetup(host, port);
@@ -160,20 +161,20 @@ class TCPconnector {
160
161
  return false;
161
162
  }
162
163
 
164
+ /**
165
+ * @callback TCPConnectorReadCallback
166
+ * @ignore
167
+ * @param {string} s - incoming message string
168
+ */
169
+
163
170
  /**
164
171
  * Set a callback for receiving incoming strings from the connector
165
- * @param {TCPConnector~ReadCallback} cb - callback that is called when the connector gets a string
172
+ * @param {TCPConnectorReadCallback} cb - callback that is called when the connector gets a string
166
173
  */
167
174
  setReadCallback(cb){
168
175
  if (cb && {}.toString.call(cb) === '[object Function]') this._onSockRx = cb;
169
176
  }
170
177
 
171
- /**
172
- * @callback TCPConnector~ReadCallback
173
- * @ignore
174
- * @param {string} s - incoming message string
175
- */
176
-
177
178
  /**
178
179
  * Add listener for connection events
179
180
  * @param {function} listener - a listener callback that is called when the connection is opened/closed
@@ -230,17 +231,20 @@ class WSConnector {
230
231
  /**
231
232
  * Create an WSConnector to connect to a fjage master over WebSockets
232
233
  * @param {Object} opts
233
- * @param {string} opts.hostname - hostname/ip address of the master container to connect to
234
- * @param {string} opts.port - port number of the master container to connect to
235
- * @param {string} opts.pathname - path of the master container to connect to
236
- * @param {boolean} opts.keepAlive - try to reconnect if the connection is lost
234
+ * @param {string} [opts.hostname='localhost'] - hostname/ip address of the master container to connect to
235
+ * @param {number} [opts.port=80] - port number of the master container to connect to
236
+ * @param {string} [opts.pathname="/"] - path of the master container to connect to
237
+ * @param {boolean} [opts.keepAlive=true] - try to reconnect if the connection is lost
238
+ * @param {boolean} [opts.debug=false] - debug info to be logged to console?
237
239
  * @param {number} [opts.reconnectTime=5000] - time before reconnection is attempted after an error
238
240
  */
239
241
  constructor(opts = {}) {
242
+ let host = opts.hostname || 'localhost';
243
+ let port = opts.port || 80;
240
244
  this.url = new URL('ws://localhost');
241
- this.url.hostname = opts.hostname;
242
- this.url.port = opts.port;
243
- this.url.pathname = opts.pathname;
245
+ this.url.hostname = host;
246
+ this.url.port = port.toString();
247
+ this.url.pathname = opts.pathname || '/';
244
248
  this._keepAlive = opts.keepAlive;
245
249
  this._reconnectTime = opts.reconnectTime || DEFAULT_RECONNECT_TIME;
246
250
  this.debug = opts.debug || false; // debug info to be logged to console?
@@ -315,19 +319,19 @@ class WSConnector {
315
319
  }
316
320
 
317
321
  /**
318
- * Set a callback for receiving incoming strings from the connector
319
- * @param {WSConnector~ReadCallback} cb - callback that is called when the connector gets a string
322
+ * @callback WSConnectorReadCallback
320
323
  * @ignore
324
+ * @param {string} s - incoming message string
321
325
  */
322
- setReadCallback(cb){
323
- if (cb && {}.toString.call(cb) === '[object Function]') this._onWebsockRx = cb;
324
- }
325
326
 
326
327
  /**
327
- * @callback WSConnector~ReadCallback
328
+ * Set a callback for receiving incoming strings from the connector
329
+ * @param {WSConnectorReadCallback} cb - callback that is called when the connector gets a string
328
330
  * @ignore
329
- * @param {string} s - incoming message string
330
331
  */
332
+ setReadCallback(cb){
333
+ if (cb && {}.toString.call(cb) === '[object Function]') this._onWebsockRx = cb;
334
+ }
331
335
 
332
336
  /**
333
337
  * Add listener for connection events
@@ -378,7 +382,7 @@ const DEFAULT_QUEUE_SIZE = 128; // max number of old unreceived messages
378
382
  /**
379
383
  * An action represented by a message. The performative actions are a subset of the
380
384
  * FIPA ACL recommendations for interagent communication.
381
- * @typedef {Object} Performative
385
+ * @enum {string}
382
386
  */
383
387
  const Performative = {
384
388
  REQUEST: 'REQUEST', // Request an action to be performed
@@ -399,13 +403,13 @@ const Performative = {
399
403
  * An identifier for an agent or a topic.
400
404
  * @class
401
405
  * @param {string} name - name of the agent
402
- * @param {boolean} topic - name of topic
403
- * @param {Gateway} owner - Gateway owner for this AgentID
406
+ * @param {boolean} [topic=false] - name of topic
407
+ * @param {Gateway} [owner] - Gateway owner for this AgentID
404
408
  */
405
409
  class AgentID {
406
410
 
407
411
 
408
- constructor(name, topic, owner) {
412
+ constructor(name, topic=false, owner) {
409
413
  this.name = name;
410
414
  this.topic = topic;
411
415
  this.owner = owner;
@@ -432,12 +436,13 @@ class AgentID {
432
436
  /**
433
437
  * Sends a message to the agent represented by this id.
434
438
  *
435
- * @param {string} msg - message to send
439
+ * @param {Message} msg - message to send
436
440
  * @returns {void}
437
441
  */
438
442
  send(msg) {
439
443
  msg.recipient = this.toJSON();
440
- this.owner.send(msg);
444
+ if (this.owner) this.owner.send(msg);
445
+ else throw new Error('Unowned AgentID cannot send messages');
441
446
  }
442
447
 
443
448
  /**
@@ -449,7 +454,8 @@ class AgentID {
449
454
  */
450
455
  async request(msg, timeout=1000) {
451
456
  msg.recipient = this.toJSON();
452
- return this.owner.request(msg, timeout);
457
+ if (this.owner) return this.owner.request(msg, timeout);
458
+ else throw new Error('Unowned AgentID cannot send messages');
453
459
  }
454
460
 
455
461
  /**
@@ -565,15 +571,27 @@ class AgentID {
565
571
  }
566
572
  }
567
573
 
574
+ // protected String msgID = UUID.randomUUID().toString();
575
+ // protected Performative perf;
576
+ // protected AgentID recipient;
577
+ // protected AgentID sender = null;
578
+ // protected String inReplyTo = null;
579
+ // protected Long sentAt = null;
580
+
568
581
  /**
569
582
  * Base class for messages transmitted by one agent to another. Creates an empty message.
570
583
  * @class
571
- * @param {Message} inReplyTo - message to which this response corresponds to
572
- * @param {Performative} - performative
584
+ * @param {string} [msgID] - unique identifier for the message
585
+ * @param {Performative} [perf=Performative.INFORM] - performative
586
+ * @param {AgentID} [recipient] - recipient of the message
587
+ * @param {AgentID} [sender] - sender of the message
588
+ * @param {string} [inReplyTo] - message to which this response corresponds to
589
+ * @param {Message} [inReplyTo] - message to which this response corresponds to
590
+ * @param {number} [sentAt] - time at which the message was sent
573
591
  */
574
592
  class Message {
575
593
 
576
- constructor(inReplyTo={msgID:null, sender:null}, perf='') {
594
+ constructor(inReplyTo={msgID:null, sender:null}, perf=Performative.INFORM) {
577
595
  this.__clazz__ = 'org.arl.fjage.Message';
578
596
  this.msgID = _guid(8);
579
597
  this.sender = null;
@@ -614,7 +632,11 @@ class Message {
614
632
  // convert a message into a JSON string
615
633
  // NOTE: we don't do any base64 encoding for TX as
616
634
  // we don't know what data type is intended
617
- /** @private */
635
+ /**
636
+ * @private
637
+ *
638
+ * @return {string} - JSON string representation of the message
639
+ */
618
640
  _serialize() {
619
641
  let clazz = this.__clazz__ || 'org.arl.fjage.Message';
620
642
  let data = JSON.stringify(this, (k,v) => {
@@ -632,26 +654,27 @@ class Message {
632
654
  }
633
655
 
634
656
  // convert a dictionary (usually from decoding JSON) into a message
635
- /** @private */
636
- static _deserialize(obj) {
637
- if (typeof obj == 'string' || obj instanceof String) {
657
+ /**
658
+ * @private
659
+ *
660
+ * @param {(string|Object)} json - JSON string or object to be converted to a message
661
+ * @returns {Message} - message created from the JSON string or object
662
+ * */
663
+ static _deserialize(json) {
664
+ let obj = null;
665
+ if (typeof json == 'string') {
638
666
  try {
639
- obj = JSON.parse(obj);
667
+ obj = JSON.parse(json);
640
668
  }catch(e){
641
669
  return null;
642
670
  }
643
- }
644
- try {
645
- let qclazz = obj.clazz;
646
- let clazz = qclazz.replace(/^.*\./, '');
647
- let rv = MessageClass[clazz] ? new MessageClass[clazz] : new Message();
648
- rv.__clazz__ = qclazz;
649
- rv._inflate(obj.data);
650
- return rv;
651
- } catch (err) {
652
- console.warn('Error trying to deserialize JSON object : ', obj, err);
653
- return null;
654
- }
671
+ } else obj = json;
672
+ let qclazz = obj.clazz;
673
+ let clazz = qclazz.replace(/^.*\./, '');
674
+ let rv = MessageClass[clazz] ? new MessageClass[clazz] : new Message();
675
+ rv.__clazz__ = qclazz;
676
+ rv._inflate(obj.data);
677
+ return rv;
655
678
  }
656
679
  }
657
680
 
@@ -662,33 +685,18 @@ class Message {
662
685
  *
663
686
  * @class
664
687
  * @param {Object} opts
665
- * @param {string} [opts.hostname="localhost"] - hostname/ip address of the master container to connect to
666
- * @param {string} [opts.port='1100'] - port number of the master container to connect to
667
- * @param {string} [opts.pathname=""] - path of the master container to connect to (for WebSockets)
668
- * @param {boolean} [opts.keepAlive=true] - try to reconnect if the connection is lost
669
- * @param {number} [opts.queueSize=128] - size of the queue of received messages that haven't been consumed yet
670
- * @param {number} [opts.timeout=1000] - timeout for fjage level messages in ms
688
+ * @param {string} [opts.hostname="localhost"] - hostname/ip address of the master container to connect to
689
+ * @param {number} [opts.port=1100] - port number of the master container to connect to
690
+ * @param {string} [opts.pathname=""] - path of the master container to connect to (for WebSockets)
691
+ * @param {string} [opts.keepAlive=true] - try to reconnect if the connection is lost
692
+ * @param {number} [opts.queueSize=128] - size of the queue of received messages that haven't been consumed yet
693
+ * @param {number} [opts.timeout=1000] - timeout for fjage level messages in ms
671
694
  * @param {boolean} [opts.returnNullOnFailedResponse=true] - return null instead of throwing an error when a parameter is not found
672
- * @param {string} [hostname="localhost"] - <strike>Deprecated : hostname/ip address of the master container to connect to</strike>
673
- * @param {number} [port=] - <strike>Deprecated : port number of the master container to connect to</strike>
674
- * @param {string} [pathname=="/ws/"] - <strike>Deprecated : path of the master container to connect to (for WebSockets)</strike>
675
- * @param {number} [timeout=1000] - <strike>Deprecated : timeout for fjage level messages in ms</strike>
676
695
  */
677
696
  class Gateway {
678
697
 
679
- constructor(opts = {}, port, pathname='/ws/', timeout=1000) {
680
- // Support for deprecated constructor
681
- if (typeof opts === 'string' || opts instanceof String){
682
- opts = {
683
- 'hostname': opts,
684
- 'port' : port,
685
- 'pathname' : pathname,
686
- 'timeout' : timeout
687
- };
688
- console.warn('Deprecated use of Gateway constructor');
689
- }
690
-
691
- // Set defaults
698
+ constructor(opts = {}) {
699
+ // Similar to Object.assign but also overwrites `undefined` and empty strings with defaults
692
700
  for (var key in GATEWAY_DEFAULTS){
693
701
  if (opts[key] == undefined || opts[key] === '') opts[key] = GATEWAY_DEFAULTS[key];
694
702
  }
@@ -707,13 +715,19 @@ class Gateway {
707
715
  this.listener = {}; // set of callbacks that want to listen to incoming messages
708
716
  this.eventListeners = {}; // external listeners wanting to listen internal events
709
717
  this.queue = []; // incoming message queue
718
+ this.connected = false; // connection status
710
719
  this.debug = false; // debug info to be logged to console?
711
- this.aid = new AgentID((isBrowser ? 'WebGW-' : 'NodeGW-')+_guid(4)); // gateway agent name
720
+ this.aid = new AgentID('gateway-'+_guid(4)); // gateway agent name
712
721
  this.connector = this._createConnector(url);
713
722
  this._addGWCache(this);
714
723
  }
715
724
 
716
- /** @private */
725
+ /**
726
+ * Sends an event to all registered listeners of the given type.
727
+ * @private
728
+ * @param {string} type - type of event
729
+ * @param {Object|Message|string} val - value to be sent to the listeners
730
+ */
717
731
  _sendEvent(type, val) {
718
732
  if (Array.isArray(this.eventListeners[type])) {
719
733
  this.eventListeners[type].forEach(l => {
@@ -728,7 +742,11 @@ class Gateway {
728
742
  }
729
743
  }
730
744
 
731
- /** @private */
745
+ /**
746
+ * @private
747
+ * @param {string} data - stringfied JSON data received from the master container to be processed
748
+ * @returns {void}
749
+ */
732
750
  _onMsgRx(data) {
733
751
  var obj;
734
752
  if (this.debug) console.log('< '+data);
@@ -745,6 +763,7 @@ class Gateway {
745
763
  delete this.pending[obj.id];
746
764
  } else if (obj.action == 'send') {
747
765
  // incoming message from master
766
+ // @ts-ignore
748
767
  let msg = Message._deserialize(obj.message);
749
768
  if (!msg) return;
750
769
  this._sendEvent('rxmsg', msg);
@@ -805,7 +824,12 @@ class Gateway {
805
824
  }
806
825
  }
807
826
 
808
- /** @private */
827
+ /**
828
+ * Sends a message out to the master container.
829
+ * @private
830
+ * @param {string|Object} s - JSON object (either stringified or not) to be sent to the master container
831
+ * @returns {boolean} - true if the message was sent successfully
832
+ */
809
833
  _msgTx(s) {
810
834
  if (typeof s != 'string' && !(s instanceof String)) s = JSON.stringify(s);
811
835
  if(this.debug) console.log('> '+s);
@@ -813,7 +837,11 @@ class Gateway {
813
837
  return this.connector.write(s);
814
838
  }
815
839
 
816
- /** @private */
840
+ /**
841
+ * @private
842
+ * @param {Object} rq - request to be sent to the master container as a JSON object
843
+ * @returns {Promise<Object>} - a promise which returns the response from the master container
844
+ */
817
845
  _msgTxRx(rq) {
818
846
  rq.id = _guid(8);
819
847
  return new Promise(resolve => {
@@ -835,25 +863,32 @@ class Gateway {
835
863
  });
836
864
  }
837
865
 
838
- /** @private */
866
+ /**
867
+ * @private
868
+ * @param {URL} url - URL object of the master container to connect to
869
+ * @returns {TCPConnector|WSConnector} - connector object to connect to the master container
870
+ */
839
871
  _createConnector(url){
840
872
  let conn;
841
873
  if (url.protocol.startsWith('ws')){
842
874
  conn = new WSConnector({
843
875
  'hostname':url.hostname,
844
- 'port':url.port,
876
+ 'port':parseInt(url.port),
845
877
  'pathname':url.pathname,
846
- 'keepAlive': this._keepAlive
878
+ 'keepAlive': this._keepAlive,
879
+ 'debug': this.debug
847
880
  });
848
881
  }else if (url.protocol.startsWith('tcp')){
849
- conn = new TCPconnector({
882
+ conn = new TCPConnector({
850
883
  'hostname':url.hostname,
851
- 'port':url.port,
852
- 'keepAlive': this._keepAlive
884
+ 'port':parseInt(url.port),
885
+ 'keepAlive': this._keepAlive,
886
+ 'debug': this.debug
853
887
  });
854
888
  } else return null;
855
889
  conn.setReadCallback(this._onMsgRx.bind(this));
856
890
  conn.addConnectionListener(state => {
891
+ this.connected = !!state;
857
892
  if (state == true){
858
893
  this.flush();
859
894
  this.connector.write('{"alive": true}');
@@ -864,7 +899,13 @@ class Gateway {
864
899
  return conn;
865
900
  }
866
901
 
867
- /** @private */
902
+ /**
903
+ * Checks if the object is a constructor.
904
+ *
905
+ * @private
906
+ * @param {Object} value - an object to be checked if it is a constructor
907
+ * @returns {boolean} - if the object is a constructor
908
+ */
868
909
  _isConstructor(value) {
869
910
  try {
870
911
  new new Proxy(value, {construct() { return {}; }});
@@ -874,7 +915,13 @@ class Gateway {
874
915
  }
875
916
  }
876
917
 
877
- /** @private */
918
+ /**
919
+ * Matches a message with a filter.
920
+ * @private
921
+ * @param {string|Object|function} filter - filter to be matched
922
+ * @param {Message} msg - message to be matched to the filter
923
+ * @returns {boolean} - true if the message matches the filter
924
+ */
878
925
  _matchMessage(filter, msg){
879
926
  if (typeof filter == 'string' || filter instanceof String) {
880
927
  return 'inReplyTo' in msg && msg.inReplyTo == filter;
@@ -894,18 +941,25 @@ class Gateway {
894
941
  }
895
942
  }
896
943
 
897
- /** @private */
944
+ /**
945
+ * Gets the next message from the queue that matches the filter.
946
+ * @private
947
+ * @param {string|Object|function} filter - filter to be matched
948
+ */
898
949
  _getMessageFromQueue(filter) {
899
950
  if (!this.queue.length) return;
900
951
  if (!filter) return this.queue.shift();
901
-
902
952
  let matchedMsg = this.queue.find( msg => this._matchMessage(filter, msg));
903
953
  if (matchedMsg) this.queue.splice(this.queue.indexOf(matchedMsg), 1);
904
-
905
954
  return matchedMsg;
906
955
  }
907
956
 
908
- /** @private */
957
+ /**
958
+ * Gets a cached gateway object for the given URL (if it exists).
959
+ * @private
960
+ * @param {URL} url - URL object of the master container to connect to
961
+ * @returns {Gateway|void} - gateway object for the given URL
962
+ */
909
963
  _getGWCache(url){
910
964
  if (!gObj.fjage || !gObj.fjage.gateways) return null;
911
965
  var f = gObj.fjage.gateways.filter(g => g.connector.url.toString() == url.toString());
@@ -913,13 +967,21 @@ class Gateway {
913
967
  return null;
914
968
  }
915
969
 
916
- /** @private */
970
+ /**
971
+ * Adds a gateway object to the cache if it doesn't already exist.
972
+ * @private
973
+ * @param {Gateway} gw - gateway object to be added to the cache
974
+ */
917
975
  _addGWCache(gw){
918
976
  if (!gObj.fjage || !gObj.fjage.gateways) return;
919
977
  gObj.fjage.gateways.push(gw);
920
978
  }
921
979
 
922
- /** @private */
980
+ /**
981
+ * Removes a gateway object from the cache if it exists.
982
+ * @private
983
+ * @param {Gateway} gw - gateway object to be removed from the cache
984
+ */
923
985
  _removeGWCache(gw){
924
986
  if (!gObj.fjage || !gObj.fjage.gateways) return;
925
987
  var index = gObj.fjage.gateways.indexOf(gw);
@@ -1007,7 +1069,7 @@ class Gateway {
1007
1069
  /**
1008
1070
  * Gets the agent ID associated with the gateway.
1009
1071
  *
1010
- * @returns {string} - agent ID
1072
+ * @returns {AgentID} - agent ID
1011
1073
  */
1012
1074
  getAgentID() {
1013
1075
  return this.aid;
@@ -1027,7 +1089,7 @@ class Gateway {
1027
1089
  * Returns an object representing the named topic.
1028
1090
  *
1029
1091
  * @param {string|AgentID} topic - name of the topic or AgentID
1030
- * @param {string} topic2 - name of the topic if the topic param is an AgentID
1092
+ * @param {string} [topic2] - name of the topic if the topic param is an AgentID
1031
1093
  * @returns {AgentID} - object representing the topic
1032
1094
  */
1033
1095
  topic(topic, topic2) {
@@ -1048,6 +1110,7 @@ class Gateway {
1048
1110
  if (!topic.isTopic()) topic = new AgentID(topic.getName() + '__ntf', true, this);
1049
1111
  this.subscriptions[topic.toJSON()] = true;
1050
1112
  this._update_watch();
1113
+ return true;
1051
1114
  }
1052
1115
 
1053
1116
  /**
@@ -1139,6 +1202,7 @@ class Gateway {
1139
1202
  }
1140
1203
  this._sendEvent('txmsg', msg);
1141
1204
  let rq = JSON.stringify({ action: 'send', relay: true, message: '###MSG###' });
1205
+ // @ts-ignore
1142
1206
  rq = rq.replace('"###MSG###"', msg._serialize());
1143
1207
  return !!this._msgTx(rq);
1144
1208
  }
@@ -1156,9 +1220,9 @@ class Gateway {
1156
1220
  * Sends a request and waits for a response. This method returns a {Promise} which resolves when a response
1157
1221
  * is received or if no response is received after the timeout.
1158
1222
  *
1159
- * @param {string} msg - message to send
1223
+ * @param {Message} msg - message to send
1160
1224
  * @param {number} [timeout=1000] - timeout in milliseconds
1161
- * @returns {Promise<?Message>} - a promise which resolves with the received response message, null on timeout
1225
+ * @returns {Promise<Message|void>} - a promise which resolves with the received response message, null on timeout
1162
1226
  */
1163
1227
  async request(msg, timeout=1000) {
1164
1228
  this.send(msg);
@@ -1169,10 +1233,10 @@ class Gateway {
1169
1233
  * Returns a response message received by the gateway. This method returns a {Promise} which resolves when
1170
1234
  * a response is received or if no response is received after the timeout.
1171
1235
  *
1172
- * @param {function} [filter=] - original message to which a response is expected, or a MessageClass of the type
1236
+ * @param {function|Message|typeof Message} filter - original message to which a response is expected, or a MessageClass of the type
1173
1237
  * of message to match, or a closure to use to match against the message
1174
1238
  * @param {number} [timeout=0] - timeout in milliseconds
1175
- * @returns {Promise<?Message>} - received response message, null on timeout
1239
+ * @returns {Promise<Message|void>} - received response message, null on timeout
1176
1240
  */
1177
1241
  async receive(filter, timeout=0) {
1178
1242
  return new Promise(resolve => {
@@ -1227,8 +1291,8 @@ const Services = {
1227
1291
  /**
1228
1292
  * Creates a unqualified message class based on a fully qualified name.
1229
1293
  * @param {string} name - fully qualified name of the message class to be created
1230
- * @param {class} [parent=Message] - class of the parent MessageClass to inherit from
1231
- * @returns {function} - constructor for the unqualified message class
1294
+ * @param {typeof Message} [parent] - class of the parent MessageClass to inherit from
1295
+ * @constructs Message
1232
1296
  * @example
1233
1297
  * const ParameterReq = MessageClass('org.arl.fjage.param.ParameterReq');
1234
1298
  * let pReq = new ParameterReq()
@@ -1237,6 +1301,9 @@ function MessageClass(name, parent=Message) {
1237
1301
  let sname = name.replace(/^.*\./, '');
1238
1302
  if (MessageClass[sname]) return MessageClass[sname];
1239
1303
  let cls = class extends parent {
1304
+ /**
1305
+ * @param {{ [x: string]: any; }} params
1306
+ */
1240
1307
  constructor(params) {
1241
1308
  super();
1242
1309
  this.__clazz__ = name;
@@ -1246,6 +1313,7 @@ function MessageClass(name, parent=Message) {
1246
1313
  this[k] = params[k];
1247
1314
  }
1248
1315
  }
1316
+ if (name.endsWith('Req')) this.perf = Performative.REQUEST;
1249
1317
  }
1250
1318
  };
1251
1319
  cls.__clazz__ = name;
@@ -1292,7 +1360,7 @@ function _b64toArray(base64, dtype, littleEndian=true) {
1292
1360
  break;
1293
1361
  case '[J': // long array
1294
1362
  for (i = 0; i < len; i+=8)
1295
- rv.push(view.getInt64(i, littleEndian));
1363
+ rv.push(view.getBigInt64(i, littleEndian));
1296
1364
  break;
1297
1365
  case '[F': // float array
1298
1366
  for (i = 0; i < len; i+=4)
@@ -1327,6 +1395,8 @@ function _decodeBase64(k, d) {
1327
1395
  ////// global
1328
1396
 
1329
1397
  const GATEWAY_DEFAULTS = {};
1398
+
1399
+ /** @type {Window & globalThis & Object} */
1330
1400
  let gObj = {};
1331
1401
  let DEFAULT_URL;
1332
1402
  if (isBrowser || isWebWorker){
@@ -1343,7 +1413,7 @@ if (isBrowser || isWebWorker){
1343
1413
  DEFAULT_URL = new URL('ws://localhost');
1344
1414
  // Enable caching of Gateways
1345
1415
  if (typeof gObj.fjage === 'undefined') gObj.fjage = {};
1346
- if (typeof gObj.fjage.gateways == 'undefined')gObj.fjage.gateways = [];
1416
+ if (typeof gObj.fjage.gateways == 'undefined') gObj.fjage.gateways = [];
1347
1417
  } else if (isJsDom || isNode){
1348
1418
  gObj = global;
1349
1419
  Object.assign(GATEWAY_DEFAULTS, {
@@ -1359,10 +1429,28 @@ if (isBrowser || isWebWorker){
1359
1429
  gObj.atob = a => Buffer.from(a, 'base64').toString('binary');
1360
1430
  }
1361
1431
 
1432
+ /**
1433
+ * @typedef {Object} ParameterReq.Entry
1434
+ * @property {string} param - parameter name
1435
+ * @property {Object} value - parameter value
1436
+ * @exports ParameterReq.Entry
1437
+ */
1438
+
1439
+
1440
+ /**
1441
+ * A message that requests one or more parameters of an agent.
1442
+ * @typedef {Message} ParameterReq
1443
+ * @property {string} param - parameters name to be get/set if only a single parameter is to be get/set
1444
+ * @property {Object} value - parameters value to be set if only a single parameter is to be set
1445
+ * @property {Array<ParameterReq.Entry>} requests - a list of multiple parameters to be get/set
1446
+ * @property {number} [index=-1] - index of parameter(s) to be set
1447
+ * @exports ParameterReq
1448
+ */
1362
1449
  const ParameterReq = MessageClass('org.arl.fjage.param.ParameterReq');
1363
1450
 
1364
1451
  const DatagramReq$1 = MessageClass('org.arl.unet.DatagramReq');
1365
1452
  const DatagramNtf$1 = MessageClass('org.arl.unet.DatagramNtf');
1453
+ const RxFrameNtf$1 = MessageClass('org.arl.unet.phy.RxFrameNtf', DatagramNtf$1);
1366
1454
  const BasebandSignal = MessageClass('org.arl.unet.bb.BasebandSignal');
1367
1455
 
1368
1456
  let UnetServices = {
@@ -1434,7 +1522,8 @@ let UnetMessages = {
1434
1522
 
1435
1523
  // phy
1436
1524
  'FecDecodeReq' : MessageClass('org.arl.unet.phy.FecDecodeReq'),
1437
- 'RxJanusFrameNtf' : MessageClass('org.arl.unet.phy.RxJanusFrameNtf'),
1525
+ 'RxSWiG1FrameNtf' : MessageClass('org.arl.unet.phy.RxSWiG1FrameNtf', RxFrameNtf$1),
1526
+ 'RxJanusFrameNtf' : MessageClass('org.arl.unet.phy.RxJanusFrameNtf', RxFrameNtf$1),
1438
1527
  'TxJanusFrameReq' : MessageClass('org.arl.unet.phy.TxJanusFrameReq'),
1439
1528
  'BadFrameNtf' : MessageClass('org.arl.unet.phy.BadFrameNtf'),
1440
1529
  'BadRangeNtf' : MessageClass('org.arl.unet.phy.BadRangeNtf'),