u8-mqtt 0.4.0 → 0.5.0

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 (82) hide show
  1. package/README.md +3 -3
  2. package/cjs/basic-v4.cjs +107 -146
  3. package/cjs/basic-v4.cjs.map +1 -1
  4. package/cjs/basic-v5.cjs +106 -145
  5. package/cjs/basic-v5.cjs.map +1 -1
  6. package/cjs/index.cjs +163 -206
  7. package/cjs/index.cjs.map +1 -1
  8. package/cjs/v4.cjs +164 -207
  9. package/cjs/v4.cjs.map +1 -1
  10. package/cjs/v5.cjs +163 -206
  11. package/cjs/v5.cjs.map +1 -1
  12. package/code/_dispatch.jsy +16 -0
  13. package/code/base.jsy +72 -133
  14. package/code/core.jsy +15 -9
  15. package/code/router_path.jsy +38 -51
  16. package/code/with_topic_router.jsy +20 -11
  17. package/esm/basic-v4.js +1154 -0
  18. package/esm/basic-v4.js.map +1 -0
  19. package/esm/basic-v5.js +1416 -0
  20. package/esm/basic-v5.js.map +1 -0
  21. package/esm/deno/basic-v4.js +107 -146
  22. package/esm/deno/basic-v4.js.map +1 -1
  23. package/esm/deno/basic-v5.js +106 -145
  24. package/esm/deno/basic-v5.js.map +1 -1
  25. package/esm/deno/index.js +163 -206
  26. package/esm/deno/index.js.map +1 -1
  27. package/esm/deno/v4.js +164 -207
  28. package/esm/deno/v4.js.map +1 -1
  29. package/esm/deno/v5.js +163 -206
  30. package/esm/deno/v5.js.map +1 -1
  31. package/esm/index.js +1599 -0
  32. package/esm/index.js.map +1 -0
  33. package/esm/node/basic-v4.js +107 -146
  34. package/esm/node/basic-v4.js.map +1 -1
  35. package/esm/node/basic-v4.mjs +107 -146
  36. package/esm/node/basic-v4.mjs.map +1 -1
  37. package/esm/node/basic-v5.js +106 -145
  38. package/esm/node/basic-v5.js.map +1 -1
  39. package/esm/node/basic-v5.mjs +106 -145
  40. package/esm/node/basic-v5.mjs.map +1 -1
  41. package/esm/node/index.js +163 -206
  42. package/esm/node/index.js.map +1 -1
  43. package/esm/node/index.mjs +163 -206
  44. package/esm/node/index.mjs.map +1 -1
  45. package/esm/node/v4.js +164 -207
  46. package/esm/node/v4.js.map +1 -1
  47. package/esm/node/v4.mjs +164 -207
  48. package/esm/node/v4.mjs.map +1 -1
  49. package/esm/node/v5.js +163 -206
  50. package/esm/node/v5.js.map +1 -1
  51. package/esm/node/v5.mjs +163 -206
  52. package/esm/node/v5.mjs.map +1 -1
  53. package/esm/v4.js +1336 -0
  54. package/esm/v4.js.map +1 -0
  55. package/esm/v5.js +1599 -0
  56. package/esm/v5.js.map +1 -0
  57. package/esm/web/basic-v4.js +107 -146
  58. package/esm/web/basic-v4.js.map +1 -1
  59. package/esm/web/basic-v4.min.js +1 -1
  60. package/esm/web/basic-v4.min.js.br +0 -0
  61. package/esm/web/basic-v4.min.js.gz +0 -0
  62. package/esm/web/basic-v5.js +106 -145
  63. package/esm/web/basic-v5.js.map +1 -1
  64. package/esm/web/basic-v5.min.js +1 -1
  65. package/esm/web/basic-v5.min.js.br +0 -0
  66. package/esm/web/basic-v5.min.js.gz +0 -0
  67. package/esm/web/index.js +163 -206
  68. package/esm/web/index.js.map +1 -1
  69. package/esm/web/index.min.js +1 -1
  70. package/esm/web/index.min.js.br +0 -0
  71. package/esm/web/index.min.js.gz +0 -0
  72. package/esm/web/v4.js +164 -207
  73. package/esm/web/v4.js.map +1 -1
  74. package/esm/web/v4.min.js +1 -1
  75. package/esm/web/v4.min.js.br +0 -0
  76. package/esm/web/v4.min.js.gz +0 -0
  77. package/esm/web/v5.js +163 -206
  78. package/esm/web/v5.js.map +1 -1
  79. package/esm/web/v5.min.js +1 -1
  80. package/esm/web/v5.min.js.br +0 -0
  81. package/esm/web/v5.min.js.gz +0 -0
  82. package/package.json +7 -8
package/cjs/v4.cjs CHANGED
@@ -51,7 +51,7 @@ class U8_Reason extends Number {
51
51
  }
52
52
  }
53
53
 
54
- class mqtt_reader_v4$1 {
54
+ let mqtt_reader_v4$1 = class mqtt_reader_v4 {
55
55
  static of(buf) { return this.prototype.of(buf) }
56
56
  of(buf) {
57
57
  let step = (width, k) => (k=0|step.k, step.k=k+width, k);
@@ -107,7 +107,7 @@ class mqtt_reader_v4$1 {
107
107
  return buf.subarray(step.k|0)
108
108
  }
109
109
 
110
- }
110
+ };
111
111
 
112
112
  function mqtt_reader_info(mqtt_reader, ... info_fn_list) {
113
113
  mqtt_reader = class extends mqtt_reader {
@@ -482,7 +482,7 @@ function mqtt_encode_disconnect(ns, mqtt_writer) {
482
482
  }
483
483
  }
484
484
 
485
- // not a v4 packet: import { mqtt_encode_auth } from './encode/auth.mjs'
485
+ // not a v4 packet: import { mqtt_encode_auth } from './encode/auth.js'
486
486
 
487
487
 
488
488
  const mqtt_decode_v4 = [
@@ -563,30 +563,39 @@ const with_topic_router = mqtt_topic_router =>
563
563
  return super._aliases() +
564
564
  ' sub_topic:subscribe_topic unsub_topic:unsubscribe_topic'}
565
565
 
566
- _init_router(opt) {
567
- return mqtt_topic_router(opt, this)}
568
-
569
- get on_topic() {return this.router.add}
566
+ _init_router(opt, self, target) {
567
+ this._subs = [];
568
+ let router = this.router = target.router =
569
+ mqtt_topic_router(opt, this, target);
570
+ return router?.invoke}
570
571
 
571
- _sub_chain(topic, ex, topic_prefix) {
572
- let res = this.subscribe([[ topic ]], ex, topic_prefix);
573
- let subs = this.subs ||(this.subs = new Map());
574
- subs.set((res.topic = topic), (subs.last = res));
575
- return this }// fluent api -- return this and track side effects
572
+ on_sub(suback, pkt) {
573
+ suback.pkt = pkt;
574
+ this._subs.push(suback);
575
+ return suback}
576
+ subs_settled() {
577
+ return Promise.allSettled(
578
+ this._subs.splice(0,Infinity)) }
576
579
 
577
580
  // alias: sub_topic
578
581
  subscribe_topic(topic_route, ...args) {
579
582
  let router = this.router;
580
583
  router.add(topic_route, true, args.pop() );// handler
581
584
  let topic = router.mqtt_topic(topic_route);
582
- return this._sub_chain(topic, ...args ) }// ex, topic_prefix
585
+ this.subscribe(topic, ...args );// ex, topic_prefix
586
+ return this }// fluent api -- return this and track side effects
583
587
 
584
588
  // alias: unsub_topic
585
589
  unsubscribe_topic(topic_route, ...args) {
586
590
  let router = this.router;
587
591
  router.remove(topic_route, true);
588
592
  let topic = router.mqtt_topic(topic_route);
589
- return this.unsubscribe([[ topic ]], ...args ) } };// topic_prefix
593
+ return this.unsubscribe(topic, ...args ) }// topic_prefix
594
+
595
+ // add topic handlers without corresponding subscribe packet
596
+ on_topic(...args) {
597
+ this.router.add(...args);
598
+ return this} };
590
599
 
591
600
  // Use [regexparam][] for url-like topic parsing
592
601
  // [regexparam]: https://github.com/lukeed/regexparam
@@ -599,16 +608,22 @@ const with_topic_path_router = /* #__PURE__ */
599
608
  const mqtt_topic = topic_route =>
600
609
  topic_route
601
610
  .replace(/[*].*$/, '#')
602
- .replace(/:\w+\??/g, '+');
611
+ .replace(/:\w[^\/]*/g, '+');
603
612
 
604
- const as_topic_path = topic_route =>(
613
+ /* From the [MQTT v5 Spec](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Topic_Names_and)
614
+ 4.7.1.2 Multi-level wildcard -- (‘#’ U+0023)
615
+ ... MUST be specified either on its own or following a topic level separator.
616
+ In either case it MUST be the last character specified in the Topic Filter
617
+
618
+ 4.7.1.3 Single-level wildcard -- (‘+’ U+002B)
619
+ ...it MUST occupy an entire level of the filter.
620
+ */
621
+
622
+ const as_topic_path = (topic_route, id) =>(
623
+ id=1,
605
624
  topic_route
606
- .replace(/#$/, '*') // replace MQTT # wildcard at end
607
- .split(/([^\/]*[+][^\/]*)/) // split on MQTT + match tokens
608
- .reduce (( sz, v, idx ) => sz +(
609
- idx & 1 // even entires are body, odd are MQTT + tokens
610
- ? `:$${1 + idx>>1}` // replace with `:$#` sequential ids, using ? for partial entries
611
- : v ) ) );// pass through body
625
+ .replace(/#$/, '*' )// replace MQTT '#' multi-level wildcard at end
626
+ .replace(/\+/g, () => `:$${id++}` ) );// replace MQTT '+' single-level wildcards
612
627
 
613
628
  function _ignore(pkt, params, ctx) {ctx.done = true;}
614
629
 
@@ -623,9 +638,8 @@ function mqtt_topic_path_router() {
623
638
  let priority = args.pop();
624
639
 
625
640
  if ('function' !== typeof fn) {
626
- if (false === fn) {
627
- fn = _ignore;}
628
- else throw new TypeError()}
641
+ if (fn) {throw new TypeError()}
642
+ fn = _ignore;}
629
643
 
630
644
  let rte = parse(as_topic_path(topic_route));
631
645
 
@@ -641,7 +655,7 @@ function mqtt_topic_path_router() {
641
655
  , clear(priority) {
642
656
  pri_lsts[priority ? 0 : 1] = [];
643
657
  if (null == priority) {
644
- pri_lsts[1] = [];} }
658
+ pri_lsts[1] = []; } }// null clears both lists
645
659
 
646
660
  , async invoke(pkt, ctx) {
647
661
  ctx.idx = 0;
@@ -657,52 +671,34 @@ function mqtt_topic_path_router() {
657
671
  break}
658
672
  else ctx.idx++;}
659
673
 
660
- let {pkt_id, qos} = pkt;
661
- if (1 === qos) {
662
- await ctx.mqtt._send('puback', {pkt_id});} } } }
674
+ if (1 === pkt.qos) {
675
+ await ctx.mqtt.puback(pkt);} } } }
663
676
 
664
677
 
665
678
  function * _routes_iter(all_route_lists, topic) {
679
+ topic = topic.replace(/^[\/]*/, '/'); // ensure '/' prefix for regexparam library
666
680
  for (let route_list of all_route_lists) {
667
- for (let route of route_list) {
668
- let res = _route_match_one(topic, route);
669
- if (undefined !== res) {
670
- yield res;} } } }
671
-
672
-
673
- function _route_match_one(topic, {keys, pattern, tgt}) {
674
- let match = '/' !== topic[0]
675
- ? pattern.exec('/'+topic)
676
- : pattern.exec(topic);
677
-
678
- if (null === match) {
679
- return}
680
-
681
- if (false === keys) {
682
- let {groups} = match;
683
- if (! groups) {
684
- return [tgt]}
685
-
686
- let params = {};
687
- for (let k in groups) {
688
- params[k] = groups[k];}
689
-
690
- return [tgt, params]}
691
-
692
- if (0 === keys.length) {
693
- return [tgt]}
694
-
695
- let params = {};
696
- for (let i=0; i<keys.length; i++) {
697
- params[ keys[i] ] = match[1+i];}
698
- return [tgt, params]}
681
+ for (let {keys, pattern, tgt} of route_list) {
682
+ let match = pattern.exec(topic);
683
+ if (match) {
684
+ let params = keys
685
+ ? keys.reduce(
686
+ (o, k, i) => (o[k] = match[1+i], o)
687
+ , {})
688
+ : match.groups ?? match;
689
+ yield [tgt, params];} } } }
699
690
 
700
691
 
701
692
  function _route_remove(all_route_lists, query) {
702
- let match = route => route===query || route.tgt===query || route.key===query;
693
+ let fn_match = route =>(
694
+ route===query
695
+ || route.tgt===query
696
+ || route.key===query);
703
697
  for (let lst of all_route_lists) {
704
- let i = lst.findIndex(match);
705
- if (0 <= i) {return !! lst.splice(i,1)} }
698
+ let i = lst.findIndex(fn_match);
699
+ if (0 <= i) {
700
+ lst.splice(i,1);
701
+ return true} }
706
702
  return false}
707
703
 
708
704
  /*
@@ -963,6 +959,22 @@ const _mqtt_cmdid_dispatch ={
963
959
 
964
960
  await fn?.call(target, pkt, ctx);} })()) };
965
961
 
962
+ /*
963
+ on_mqtt_type = {
964
+ mqtt_auth(pkt, ctx) ::
965
+ mqtt_connect(pkt, ctx) ::
966
+ mqtt_connack(pkt, ctx) ::
967
+ mqtt_disconnect(pkt, ctx) ::
968
+
969
+ mqtt_publish(pkt, ctx)
970
+ mqtt_subscribe(pkt, ctx) ::
971
+ mqtt_unsubscribe(pkt, ctx) ::
972
+
973
+ mqtt_pingreq(pkt, ctx) ::
974
+ mqtt_pingresp(pkt, ctx) ::
975
+ }
976
+ */
977
+
966
978
  function _mqtt_dispatch(opt, target) {
967
979
  let _disp_ = _mqtt_cmdid_dispatch.create(target);
968
980
  let { cmdids } = _disp_;
@@ -992,28 +1004,34 @@ class MQTTError extends Error {
992
1004
 
993
1005
  class MQTTBase {
994
1006
  constructor(opt={}) {
1007
+ this.with(opt);
995
1008
  this._conn_ = _mqtt_conn(this,
996
1009
  this._init_dispatch(opt, this)); }
997
1010
 
1011
+ with(fns_ns) {
1012
+ for (let [k,v] of Object.entries(fns_ns)) {
1013
+ if ('function' === typeof v) {this[k] = v;} }
1014
+ return this}
1015
+
998
1016
  async conn_emit(evt, arg, err_arg) {
999
1017
  this.log_conn?.(evt, arg, err_arg);
1000
1018
  try {
1001
- let fn_evt = this[await evt]; // microtask break
1019
+ let fn_evt = this[await evt]; // microtask break using `await evt`
1002
1020
  if (fn_evt) {
1003
1021
  await fn_evt.call(this, this, arg, err_arg);}
1004
- else if (err_arg) {
1005
- await this.on_error(err_arg, evt);} }
1022
+ else if (err_arg) {throw err_arg} }
1006
1023
  catch (err) {
1007
1024
  this.on_error(err, evt);} }
1008
1025
 
1009
- on_error(err, err_path) {
1010
- console.warn('[[u8-mqtt error: %s]]', err_path, err); }
1026
+ on_error(err, evt) {
1027
+ console.warn('[[u8-mqtt error: %s]]', evt, err); }
1011
1028
 
1012
1029
  // Handshaking Packets
1013
1030
 
1014
1031
  async connect(pkt={}) {
1015
- let cid = pkt.client_id || ['u8-mqtt--', ''];
1016
- if (Array.isArray(cid)) {
1032
+ let cid = pkt.client_id || this.client_id;
1033
+ if ('string' !== typeof cid) {
1034
+ // see init_client_id implementation in core.jsy
1017
1035
  pkt.client_id = cid = this.init_client_id(cid);}
1018
1036
  this.client_id = cid;
1019
1037
 
@@ -1039,12 +1057,13 @@ class MQTTBase {
1039
1057
  return this._send('auth', pkt, 'auth')}
1040
1058
 
1041
1059
  ping() {return this._send('pingreq', null, 'pingresp')}
1042
-
1060
+ puback({pkt_id}) {return this._send('puback', {pkt_id})}
1043
1061
 
1044
1062
  // alias: sub
1045
1063
  subscribe(pkt, ex, topic_prefix) {
1046
1064
  pkt = _as_topics(pkt, ex, topic_prefix);
1047
- return this._send('subscribe', pkt, pkt)}
1065
+ let suback = this._send('subscribe', pkt, pkt);
1066
+ return this.on_sub?.(suback, pkt) ?? suback}
1048
1067
 
1049
1068
  // alias: unsub
1050
1069
  unsubscribe(pkt, ex, topic_prefix) {
@@ -1052,48 +1071,52 @@ class MQTTBase {
1052
1071
  return this._send('unsubscribe', pkt, pkt)}
1053
1072
 
1054
1073
 
1055
- // alias: pub
1056
- publish(pkt, pub_opt) {return _pub(this, pkt, pub_opt)}
1057
- post(topic, payload, pub_opt) {return _pub.m(this, topic, payload, pub_opt)}
1058
- send(topic, payload, pub_opt) {return _pub.mq(this, topic, payload, pub_opt)}
1059
- store(topic, payload, pub_opt) {return _pub.mqr(this, topic, payload, pub_opt)}
1060
-
1061
- json_post(topic, msg, pub_opt) {return _pub.o(this, topic, msg, pub_opt)}
1062
- json_send(topic, msg, pub_opt) {return _pub.oq(this, topic, msg, pub_opt)}
1063
- json_store(topic, msg, pub_opt) {return _pub.oqr(this, topic, msg, pub_opt)}
1064
-
1065
- obj_post(topic, msg, pub_opt) {return _pub.o(this, topic, msg, pub_opt)}
1066
- obj_send(topic, msg, pub_opt) {return _pub.oq(this, topic, msg, pub_opt)}
1067
- obj_store(topic, msg, pub_opt) {return _pub.oqr(this, topic, msg, pub_opt)}
1068
-
1069
-
1070
-
1071
- // Utility Methods
1072
-
1073
- init_client_id(parts) {
1074
- let cid = this.client_id;
1075
-
1076
- if (undefined === cid) {
1077
- this.client_id = cid = (
1078
-
1079
-
1080
-
1081
- this.new_client_id(parts)
1082
- );}
1083
-
1084
- return cid}
1085
-
1086
- new_client_id(parts) {
1087
- return [parts[0], Math.random().toString(36).slice(2), parts[1]].join('')}
1088
-
1089
-
1090
-
1091
-
1092
-
1093
-
1094
-
1095
-
1096
-
1074
+ post(topic, payload, pub_opt) {// qos:0
1075
+ return this.pub({topic, payload, qos:0}, pub_opt)}
1076
+ send(topic, payload, pub_opt) {// qos:1
1077
+ return this.pub({topic, payload, qos:1}, pub_opt)}
1078
+ store(topic, payload, pub_opt) {// qos:1, retain: 1
1079
+ return this.pub({topic, payload, qos:1, retain: 1}, pub_opt)}
1080
+
1081
+ // alias: json_post
1082
+ obj_post(topic, msg, pub_opt) {// qos:0
1083
+ return this.pub({topic, msg, arg: 'msg', qos:0}, pub_opt)}
1084
+ // alias: json_send
1085
+ obj_send(topic, msg, pub_opt) {// qos:1
1086
+ return this.pub({topic, msg, arg: 'msg', qos:1}, pub_opt)}
1087
+ // alias: json_store
1088
+ obj_store(topic, msg, pub_opt) {// qos:1, retain: 1
1089
+ return this.pub({topic, msg, arg: 'msg', qos:1, retain: 1}, pub_opt)}
1090
+
1091
+ // alias: publish -- because 'pub' is shorter for semantic aliases above
1092
+ async pub(pkt, pub_opt) {
1093
+ if (undefined === pkt.payload) {
1094
+ if ('function' === typeof pub_opt) {
1095
+ pub_opt = {fn_encode: pub_opt};}
1096
+
1097
+ let {msg} = pkt;
1098
+ switch (typeof msg) {
1099
+ case 'function':
1100
+ pub_opt = {...pub_opt, fn_encode: msg};
1101
+ // flow into 'undefined' case
1102
+ case 'undefined':
1103
+ // return a single-value closure to publish packets
1104
+ return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)}
1105
+
1106
+ // Encode payload from msg; fn_encode allows alternative to JSON.stringify
1107
+ let {fn_encode} = pub_opt || {};
1108
+ pkt.payload = fn_encode
1109
+ ? await fn_encode(msg)
1110
+ : JSON.stringify(msg);}
1111
+
1112
+ if (pub_opt) {
1113
+ if (pub_opt.props) {
1114
+ pkt.props = pub_opt.props;}
1115
+ if (pub_opt.xform) {
1116
+ pkt = pub_opt.xform(pkt) || pkt;} }
1117
+
1118
+ return this._send('publish', pkt,
1119
+ pkt.qos ? pkt : void 0 ) }// key
1097
1120
 
1098
1121
 
1099
1122
  // Internal API
@@ -1102,52 +1125,24 @@ class MQTTBase {
1102
1125
 
1103
1126
  _init_dispatch(opt) {
1104
1127
  this.constructor?._once_();
1105
- let router = this.router =
1106
- this._init_router?.(opt, this);
1107
-
1108
- let tgt ={
1109
- __proto__: opt.on_mqtt_type || {}
1110
- , router};
1111
-
1112
- tgt.mqtt_publish ||= router?.invoke;
1113
- return _mqtt_dispatch(this, tgt)}
1128
+ let target ={__proto__: opt.on_mqtt_type};
1129
+ target.mqtt_publish ||=
1130
+ this._init_router?.(opt, this, target);
1131
+ return _mqtt_dispatch(this, target)}
1114
1132
 
1115
1133
  static _aliases() {
1116
- return ' pub:publish sub:subscribe unsub:unsubscribe '}
1134
+ return ' publish:pub sub:subscribe unsub:unsubscribe json_post:obj_post json_send:obj_send json_store:obj_store'}
1117
1135
 
1118
1136
  static _once_(self=this) {
1119
1137
  self._once_ = _=>0;
1120
- self.MQTTError = MQTTError;
1121
1138
  let p = self.prototype;
1139
+ p.MQTTError = MQTTError;
1122
1140
  for (let alias of self._aliases().split(/\s+/)) {
1123
1141
  alias = alias.split(':');
1124
1142
  let fn = alias[1] && p[alias[1]];
1125
1143
  if (fn) {p[alias[0]] = fn;} } } }
1126
1144
 
1127
1145
 
1128
- /*
1129
- on_mqtt_type = {
1130
- mqtt_auth(pkt, ctx) ::
1131
- mqtt_connect(pkt, ctx) ::
1132
- mqtt_connack(pkt, ctx) ::
1133
- mqtt_disconnect(pkt, ctx) ::
1134
-
1135
- mqtt_publish(pkt, ctx)
1136
- mqtt_subscribe(pkt, ctx) ::
1137
- mqtt_unsubscribe(pkt, ctx) ::
1138
-
1139
- mqtt_pingreq(pkt, ctx) ::
1140
- mqtt_pingresp(pkt, ctx) ::
1141
- }
1142
- */
1143
-
1144
-
1145
- const _prefix_topics = (topic_prefix, iterable) =>
1146
- Array.from(iterable, value =>(
1147
- value.trim // string
1148
- ? _prefix_topics(topic_prefix, value)
1149
- : topic_prefix + value) );
1150
-
1151
1146
  function _as_topics(pkt, ex, topic_prefix) {
1152
1147
  if (ex?.trim) {// string
1153
1148
  topic_prefix = ex;
@@ -1164,55 +1159,11 @@ function _as_topics(pkt, ex, topic_prefix) {
1164
1159
  if (topic_prefix) {
1165
1160
  // particularly useful with shared queues, e.g.
1166
1161
  // topic_prefix = '$share/some-queue-name/'
1167
- pkt.topics = _prefix_topics(topic_prefix, pkt.topics);}
1168
- return pkt}
1169
-
1162
+ let _prefix_topics = v =>
1163
+ v.trim ? topic_prefix+v : v.map(_prefix_topics);
1170
1164
 
1171
- async function _pub(self, pkt, pub_opt) {
1172
- if (undefined === pkt.payload) {
1173
- if ('function' === typeof pub_opt) {
1174
- pub_opt = {fn_encode: pub_opt};}
1175
-
1176
- let {msg} = pkt;
1177
- switch (typeof msg) {
1178
- case 'function':
1179
- pub_opt = {...pub_opt, fn_encode: msg};
1180
- // flow into 'undefined' case
1181
- case 'undefined':
1182
- // return a single-value closure to publish packets
1183
- return v => _pub(self, {...pkt, [pkt.arg || 'payload']: v}, pub_opt)
1184
-
1185
- default:
1186
- // Encode payload from msg; fn_encode allows alternative to JSON.stringify
1187
- let {fn_encode} = pub_opt || {};
1188
- pkt.payload = fn_encode
1189
- ? await fn_encode(msg)
1190
- : JSON.stringify(msg);} }
1191
-
1192
- if (pub_opt) {
1193
- if (pub_opt.props) {
1194
- pkt.props = pub_opt.props;}
1195
- if (pub_opt.xform) {
1196
- pkt = pub_opt.xform(pkt) || pkt;} }
1197
-
1198
- return self._send('publish', pkt,
1199
- pkt.qos ? pkt : void 0 ) }// key
1200
-
1201
- {
1202
- Object.assign(_pub,{
1203
- m: (self, topic, payload, pub_opt) =>
1204
- _pub(self, {topic, payload, qos:0}, pub_opt)
1205
- , mq: (self, topic, payload, pub_opt) =>
1206
- _pub(self, {topic, payload, qos:1}, pub_opt)
1207
- , mqr: (self, topic, payload, pub_opt) =>
1208
- _pub(self, {topic, payload, qos:1, retain: 1}, pub_opt)
1209
-
1210
- , o: (self, topic, msg, pub_opt) =>
1211
- _pub(self, {topic, msg, arg: 'msg', qos:0}, pub_opt)
1212
- , oq: (self, topic, msg, pub_opt) =>
1213
- _pub(self, {topic, msg, arg: 'msg', qos:1}, pub_opt)
1214
- , oqr: (self, topic, msg, pub_opt) =>
1215
- _pub(self, {topic, msg, arg: 'msg', qos:1, retain: 1}, pub_opt)} ); }
1165
+ pkt.topics = pkt.topics.map(_prefix_topics);}
1166
+ return pkt}
1216
1167
 
1217
1168
  const pkt_api = {
1218
1169
  utf8(u8) { return new TextDecoder('utf-8').decode(u8 || this.payload ) },
@@ -1221,20 +1172,27 @@ const pkt_api = {
1221
1172
  };
1222
1173
 
1223
1174
  class MQTTCore extends MQTTBase {
1224
- constructor(opt={}) {
1225
- super(opt);
1226
- this.with(opt);}
1227
-
1228
1175
  static mqtt_ctx(mqtt_level, mqtt_opts, pkt_ctx=pkt_api) {
1229
1176
  let self = class extends this {};
1230
1177
  self.prototype.mqtt_ctx =
1231
1178
  mqtt_pkt_ctx(mqtt_level, mqtt_opts, pkt_ctx);
1232
1179
  return self}
1233
1180
 
1234
- with(fns_ns) {
1235
- for (let [k,v] of Object.entries(fns_ns)) {
1236
- if ('function' === typeof v) {this[k] = v;} }
1237
- return this}
1181
+
1182
+ // automatic Client Id for connect()
1183
+ init_client_id(parts=['u8-mqtt--','']) {
1184
+ let sess_stg=this.sess_stg;
1185
+ let key, cid = sess_stg?.getItem(key=parts.join(' '));
1186
+ if (! cid) {
1187
+ cid = parts.join(Math.random().toString(36).slice(2));
1188
+ sess_stg?.setItem(key, cid);}
1189
+ return cid}
1190
+
1191
+ get sess_stg() {return globalThis.sessionStorage}
1192
+
1193
+
1194
+ //on_error(err, evt) ::
1195
+ // console.warn @ '[[u8-mqtt error: %s]]', evt, err
1238
1196
 
1239
1197
  //log_conn(evt, arg, err_arg) ::
1240
1198
  // console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
@@ -1311,7 +1269,6 @@ class MQTTCore extends MQTTBase {
1311
1269
 
1312
1270
  with_tcp(...opt) {
1313
1271
  opt = this._conn_opt(opt);
1314
- console.log({opt});
1315
1272
  return this._use_conn (() =>
1316
1273
  this.with_stream(
1317
1274
  node_net.connect(opt)) ) }
@@ -1373,7 +1330,7 @@ class MQTTCore extends MQTTBase {
1373
1330
 
1374
1331
  return this} }
1375
1332
 
1376
- const version = '0.4.0';
1333
+ const version = '0.5.0';
1377
1334
 
1378
1335
  const MQTTClient_v4 = /* #__PURE__ */
1379
1336
  with_topic_path_router(