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