u8-mqtt 0.3.1 → 0.4.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 (78) hide show
  1. package/README.md +5 -5
  2. package/cjs/basic-v4.cjs +1205 -0
  3. package/cjs/basic-v4.cjs.map +1 -0
  4. package/cjs/basic-v5.cjs +1469 -0
  5. package/cjs/basic-v5.cjs.map +1 -0
  6. package/cjs/index.cjs +312 -247
  7. package/cjs/index.cjs.map +1 -1
  8. package/cjs/v4.cjs +307 -242
  9. package/cjs/v4.cjs.map +1 -1
  10. package/cjs/v5.cjs +309 -243
  11. package/cjs/v5.cjs.map +1 -1
  12. package/code/_cmdid_dispatch.jsy +1 -3
  13. package/code/base.jsy +64 -84
  14. package/code/{v4.mjs → basic-v4.js} +1 -1
  15. package/code/{v5.mjs → basic-v5.js} +1 -1
  16. package/code/core.jsy +41 -15
  17. package/code/{index.mjs → index.js} +3 -2
  18. package/code/{_router.jsy → router_path.jsy} +30 -12
  19. package/code/v4.js +20 -0
  20. package/code/v5.js +29 -0
  21. package/code/version.js +1 -0
  22. package/code/with_topic_router.jsy +41 -0
  23. package/esm/deno/basic-v4.js +1193 -0
  24. package/esm/deno/basic-v4.js.map +1 -0
  25. package/esm/deno/basic-v5.js +1455 -0
  26. package/esm/deno/basic-v5.js.map +1 -0
  27. package/esm/deno/index.js +307 -242
  28. package/esm/deno/index.js.map +1 -1
  29. package/esm/deno/v4.js +304 -240
  30. package/esm/deno/v4.js.map +1 -1
  31. package/esm/deno/v5.js +306 -241
  32. package/esm/deno/v5.js.map +1 -1
  33. package/esm/node/basic-v4.js +1196 -0
  34. package/esm/node/basic-v4.js.map +1 -0
  35. package/esm/node/basic-v4.mjs +1196 -0
  36. package/esm/node/basic-v4.mjs.map +1 -0
  37. package/esm/node/basic-v5.js +1458 -0
  38. package/esm/node/basic-v5.js.map +1 -0
  39. package/esm/node/basic-v5.mjs +1458 -0
  40. package/esm/node/basic-v5.mjs.map +1 -0
  41. package/esm/node/index.js +309 -243
  42. package/esm/node/index.js.map +1 -1
  43. package/esm/node/index.mjs +309 -243
  44. package/esm/node/index.mjs.map +1 -1
  45. package/esm/node/v4.js +306 -241
  46. package/esm/node/v4.js.map +1 -1
  47. package/esm/node/v4.mjs +306 -241
  48. package/esm/node/v4.mjs.map +1 -1
  49. package/esm/node/v5.js +308 -242
  50. package/esm/node/v5.js.map +1 -1
  51. package/esm/node/v5.mjs +308 -242
  52. package/esm/node/v5.mjs.map +1 -1
  53. package/esm/web/basic-v4.js +1193 -0
  54. package/esm/web/basic-v4.js.map +1 -0
  55. package/esm/web/basic-v4.min.js +1 -0
  56. package/esm/web/basic-v4.min.js.br +0 -0
  57. package/esm/web/basic-v4.min.js.gz +0 -0
  58. package/esm/web/basic-v5.js +1455 -0
  59. package/esm/web/basic-v5.js.map +1 -0
  60. package/esm/web/basic-v5.min.js +1 -0
  61. package/esm/web/basic-v5.min.js.br +0 -0
  62. package/esm/web/basic-v5.min.js.gz +0 -0
  63. package/esm/web/index.js +307 -242
  64. package/esm/web/index.js.map +1 -1
  65. package/esm/web/index.min.js +1 -1
  66. package/esm/web/index.min.js.br +0 -0
  67. package/esm/web/index.min.js.gz +0 -0
  68. package/esm/web/v4.js +305 -241
  69. package/esm/web/v4.js.map +1 -1
  70. package/esm/web/v4.min.js +1 -1
  71. package/esm/web/v4.min.js.br +0 -0
  72. package/esm/web/v4.min.js.gz +0 -0
  73. package/esm/web/v5.js +306 -241
  74. package/esm/web/v5.js.map +1 -1
  75. package/esm/web/v5.min.js +1 -1
  76. package/esm/web/v5.min.js.br +0 -0
  77. package/esm/web/v5.min.js.gz +0 -0
  78. package/package.json +7 -7
package/esm/node/v4.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { connect } from 'node:net';
2
+ import { connect as connect$1 } from 'node:tls';
2
3
 
3
4
  function encode_varint(n, a=[]) {
4
5
  do {
@@ -515,6 +516,191 @@ const mqtt_opts_v4 =
515
516
  encode_fns: mqtt_encode_v4,
516
517
  mqtt_writer: mqtt_writer_v4, };
517
518
 
519
+ function parse(str, loose) {
520
+ if (str instanceof RegExp) return { keys:false, pattern:str };
521
+ var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
522
+ arr[0] || arr.shift();
523
+
524
+ while (tmp = arr.shift()) {
525
+ c = tmp[0];
526
+ if (c === '*') {
527
+ keys.push('wild');
528
+ pattern += '/(.*)';
529
+ } else if (c === ':') {
530
+ o = tmp.indexOf('?', 1);
531
+ ext = tmp.indexOf('.', 1);
532
+ keys.push( tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length) );
533
+ pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';
534
+ if (!!~ext) pattern += (!!~o ? '?' : '') + '\\' + tmp.substring(ext);
535
+ } else {
536
+ pattern += '/' + tmp;
537
+ }
538
+ }
539
+
540
+ return {
541
+ keys: keys,
542
+ pattern: new RegExp('^' + pattern + (loose ? '(?=$|\/)' : '\/?$'), 'i')
543
+ };
544
+ }
545
+
546
+ /*
547
+ class AbstractTopicRouter ::
548
+ async invoke(pkt, ctx) ::
549
+ add(topic_route, ...args) ::
550
+ remove(topic_route, priority) ::
551
+ clear(priority) ::
552
+ find(topic) :: // optional
553
+ mqtt_topic(topic_route)
554
+ */
555
+
556
+ const with_topic_router = mqtt_topic_router =>
557
+ MQTTKlass => class extends MQTTKlass {
558
+ static _aliases() {
559
+ return super._aliases() +
560
+ ' sub_topic:subscribe_topic unsub_topic:unsubscribe_topic'}
561
+
562
+ _init_router(opt) {
563
+ return mqtt_topic_router(opt, this)}
564
+
565
+ get on_topic() {return this.router.add}
566
+
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
572
+
573
+ // alias: sub_topic
574
+ subscribe_topic(topic_route, ...args) {
575
+ let router = this.router;
576
+ router.add(topic_route, true, args.pop() );// handler
577
+ let topic = router.mqtt_topic(topic_route);
578
+ return this._sub_chain(topic, ...args ) }// ex, topic_prefix
579
+
580
+ // alias: unsub_topic
581
+ unsubscribe_topic(topic_route, ...args) {
582
+ let router = this.router;
583
+ router.remove(topic_route, true);
584
+ let topic = router.mqtt_topic(topic_route);
585
+ return this.unsubscribe([[ topic ]], ...args ) } };// topic_prefix
586
+
587
+ // Use [regexparam][] for url-like topic parsing
588
+ // [regexparam]: https://github.com/lukeed/regexparam
589
+
590
+
591
+ const with_topic_path_router = /* #__PURE__ */
592
+ with_topic_router(mqtt_topic_path_router);
593
+
594
+
595
+ const mqtt_topic = topic_route =>
596
+ topic_route
597
+ .replace(/[*].*$/, '#')
598
+ .replace(/:\w+\??/g, '+');
599
+
600
+ const as_topic_path = topic_route =>(
601
+ 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
608
+
609
+ function _ignore(pkt, params, ctx) {ctx.done = true;}
610
+
611
+ function mqtt_topic_path_router() {
612
+ let pri_lsts = [[],[]], rm = Symbol();
613
+ let find = topic => _routes_iter(pri_lsts, topic);
614
+
615
+ // return duck-type compatible with AbstractTopicRouter in ./with_topic_router
616
+ return {find, mqtt_topic,
617
+ add(topic_route, ...args) {
618
+ let fn = args.pop();
619
+ let priority = args.pop();
620
+
621
+ if ('function' !== typeof fn) {
622
+ if (false === fn) {
623
+ fn = _ignore;}
624
+ else throw new TypeError()}
625
+
626
+ let rte = parse(as_topic_path(topic_route));
627
+
628
+ rte.key = topic_route;
629
+ rte.tgt = fn;
630
+ pri_lsts[priority ? 0 : 1].push(rte);
631
+ return this}
632
+
633
+ , remove(topic_route, priority) {
634
+ let lst = pri_lsts[priority ? 0 : 1];
635
+ return _route_remove([lst], topic_route)}
636
+
637
+ , clear(priority) {
638
+ pri_lsts[priority ? 0 : 1] = [];
639
+ if (null == priority) {
640
+ pri_lsts[1] = [];} }
641
+
642
+ , async invoke(pkt, ctx) {
643
+ ctx.idx = 0;
644
+ ctx.rm = rm;
645
+
646
+ for (let [fn, params] of find(pkt.topic)) {
647
+ let res = await fn(pkt, params, ctx);
648
+
649
+ if (rm === res) {
650
+ _route_remove(pri_lsts, fn);}
651
+
652
+ if (ctx.done) {
653
+ break}
654
+ else ctx.idx++;}
655
+
656
+ let {pkt_id, qos} = pkt;
657
+ if (1 === qos) {
658
+ await ctx.mqtt._send('puback', {pkt_id});} } } }
659
+
660
+
661
+ function * _routes_iter(all_route_lists, topic) {
662
+ 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]}
695
+
696
+
697
+ function _route_remove(all_route_lists, query) {
698
+ let match = route => route===query || route.tgt===query || route.key===query;
699
+ for (let lst of all_route_lists) {
700
+ let i = lst.findIndex(match);
701
+ if (0 <= i) {return !! lst.splice(i,1)} }
702
+ return false}
703
+
518
704
  /*
519
705
  export function decode_varint_loop(u8, i=0) {
520
706
  let i0 = i
@@ -613,8 +799,6 @@ function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
613
799
  }
614
800
  }
615
801
 
616
- Object.freeze({ao_done: true});
617
-
618
802
  function ao_defer_ctx(as_res = (...args) => args) {
619
803
  let y,n,_pset = (a,b) => { y=a, n=b; };
620
804
  return p =>(
@@ -698,138 +882,13 @@ function _ping_interval(send_ping) {
698
882
  if (td) {
699
883
  tid = setInterval(send_ping, 1000 * td);
700
884
 
701
-
702
-
885
+
886
+
703
887
 
704
- // ensure the interval allows the NodeJS event loop to exit
705
- tid.unref?.();
888
+ // ensure the interval allows the NodeJS event loop to exit
889
+ tid.unref?.();
706
890
  return true} }) }
707
891
 
708
- function parse(str, loose) {
709
- if (str instanceof RegExp) return { keys:false, pattern:str };
710
- var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
711
- arr[0] || arr.shift();
712
-
713
- while (tmp = arr.shift()) {
714
- c = tmp[0];
715
- if (c === '*') {
716
- keys.push('wild');
717
- pattern += '/(.*)';
718
- } else if (c === ':') {
719
- o = tmp.indexOf('?', 1);
720
- ext = tmp.indexOf('.', 1);
721
- keys.push( tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length) );
722
- pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';
723
- if (!!~ext) pattern += (!!~o ? '?' : '') + '\\' + tmp.substring(ext);
724
- } else {
725
- pattern += '/' + tmp;
726
- }
727
- }
728
-
729
- return {
730
- keys: keys,
731
- pattern: new RegExp('^' + pattern + (loose ? '(?=$|\/)' : '\/?$'), 'i')
732
- };
733
- }
734
-
735
- // Use [regexparam][] for url-like topic parsing
736
-
737
- function _ignore(pkt, params, ctx) {ctx.done = true;}
738
-
739
- function _mqtt_topic_router() {
740
- let pri_lsts = [[],[]], rm = Symbol();
741
- let find = topic => _mqtt_routes_iter(pri_lsts, topic);
742
-
743
- return {find,
744
-
745
- add(topic_route, ...args) {
746
- let fn = args.pop();
747
- let priority = args.pop();
748
-
749
- if ('function' !== typeof fn) {
750
- if (false === fn) {
751
- fn = _ignore;}
752
- else throw new TypeError()}
753
-
754
- let rte = parse(
755
- topic_route.replace(/[+#]$/, '*'));
756
-
757
- rte.key = topic_route;
758
- rte.tgt = fn;
759
- pri_lsts[priority ? 0 : 1].push(rte);
760
- return this}
761
-
762
- , remove(topic_route, priority) {
763
- let lst = pri_lsts[priority ? 0 : 1];
764
- return _mqtt_route_remove([lst], topic_route)}
765
-
766
- , clear(priority) {
767
- pri_lsts[priority ? 0 : 1] = [];
768
- if (null == priority) {
769
- pri_lsts[1] = [];} }
770
-
771
- , async invoke(pkt, ctx) {
772
- ctx.idx = 0;
773
- ctx.rm = rm;
774
-
775
- for (let [fn, params] of find(pkt.topic)) {
776
- let res = await fn(pkt, params, ctx);
777
-
778
- if (rm === res) {
779
- _mqtt_route_remove(pri_lsts, fn);}
780
-
781
- if (ctx.done) {
782
- break}
783
- else ctx.idx++;}
784
-
785
- let {pkt_id, qos} = pkt;
786
- if (1 === qos) {
787
- await ctx.mqtt._send('puback', {pkt_id});} } } }
788
-
789
-
790
- function * _mqtt_routes_iter(all_route_lists, topic) {
791
- for (let route_list of all_route_lists) {
792
- for (let route of route_list) {
793
- let res = _mqtt_route_match_one(topic, route);
794
- if (undefined !== res) {
795
- yield res;} } } }
796
-
797
-
798
- function _mqtt_route_match_one(topic, {keys, pattern, tgt}) {
799
- let match = '/' !== topic[0]
800
- ? pattern.exec('/'+topic)
801
- : pattern.exec(topic);
802
-
803
- if (null === match) {
804
- return}
805
-
806
- if (false === keys) {
807
- let {groups} = match;
808
- if (! groups) {
809
- return [tgt]}
810
-
811
- let params = {};
812
- for (let k in groups) {
813
- params[k] = groups[k];}
814
-
815
- return [tgt, params]}
816
-
817
- if (0 === keys.length) {
818
- return [tgt]}
819
-
820
- let params = {};
821
- for (let i=0; i<keys.length; i++) {
822
- params[ keys[i] ] = match[1+i];}
823
- return [tgt, params]}
824
-
825
-
826
- function _mqtt_route_remove(all_route_lists, query) {
827
- let match = route => route===query || route.tgt===query || route.key===query;
828
- for (let lst of all_route_lists) {
829
- let i = lst.findIndex(match);
830
- if (0 <= i) {return !! lst.splice(i,1)} }
831
- return false}
832
-
833
892
  const _mqtt_cmdid_dispatch ={
834
893
  create(target) {
835
894
  return {__proto__: this, target, hashbelt: [new Map()]} }
@@ -898,8 +957,7 @@ const _mqtt_cmdid_dispatch ={
898
957
  let fn = target[`mqtt_${pkt.type}`]
899
958
  || target.mqtt_pkt;
900
959
 
901
- if (undefined !== fn) {
902
- await fn.call(target, pkt, ctx);} } })()) };
960
+ await fn?.call(target, pkt, ctx);} })()) };
903
961
 
904
962
  function _mqtt_dispatch(opt, target) {
905
963
  let _disp_ = _mqtt_cmdid_dispatch.create(target);
@@ -980,53 +1038,15 @@ class MQTTBase {
980
1038
 
981
1039
 
982
1040
  // alias: sub
983
- subscribe(pkt, ex) {
984
- pkt = _as_topics(pkt, ex);
1041
+ subscribe(pkt, ex, topic_prefix) {
1042
+ pkt = _as_topics(pkt, ex, topic_prefix);
985
1043
  return this._send('subscribe', pkt, pkt)}
986
- _sub_chain(topic, ex) {
987
- let res = this.subscribe([[ topic ]], ex);
988
- let subs = this.subs ||(this.subs = new Map());
989
- subs.set((res.topic = topic), (subs.last = res));
990
- return this }// fluent api -- return this and track side effects
991
1044
 
992
1045
  // alias: unsub
993
- unsubscribe(pkt, ex) {
994
- pkt = _as_topics(pkt, ex);
1046
+ unsubscribe(pkt, ex, topic_prefix) {
1047
+ pkt = _as_topics(pkt, ex, topic_prefix);
995
1048
  return this._send('unsubscribe', pkt, pkt)}
996
1049
 
997
- get on_topic() {return this.router.add}
998
-
999
- // alias: sub_topic
1000
- subscribe_topic(topic_route, ...args) {
1001
- this.router.add(topic_route, true, args.pop() );// handler
1002
- let topic = this.topic_for(topic_route);
1003
- return this._sub_chain(topic, args.pop() ) }// ex
1004
-
1005
- // alias: unsub_topic
1006
- unsubscribe_topic(topic_route) {
1007
- this.router.remove(topic_route, true);
1008
- let topic = this.topic_for(topic_route);
1009
- return this.unsubscribe([[ topic ]]) }
1010
-
1011
- // alias: shared_sub
1012
- shared_subscribe(group, topic_route, ...args) {
1013
- this.router.add(topic_route, true, args.pop() );// handler
1014
- let topic = this.topic_for(topic_route);
1015
- if (null != group) {
1016
- topic = `$share/${group}/${topic}`;}
1017
- return this._sub_chain(topic, args.pop() ) }// ex
1018
-
1019
- // alias: shared_unsub
1020
- shared_unsubscribe(group, topic_route) {
1021
- this.router.remove(topic_route, true);
1022
- let topic = this.topic_for(topic_route);
1023
- if (null != group) {
1024
- topic = `$share/${group}/${topic}`;}
1025
- return this.unsubscribe([[ topic ]]) }
1026
-
1027
- topic_for(topic_route) {
1028
- return topic_route.replace(/[:*].*$/, '#')}
1029
-
1030
1050
 
1031
1051
  // alias: pub
1032
1052
  publish(pkt, pub_opt) {return _pub(this, pkt, pub_opt)}
@@ -1052,9 +1072,9 @@ class MQTTBase {
1052
1072
  if (undefined === cid) {
1053
1073
  this.client_id = cid = (
1054
1074
 
1055
-
1075
+
1056
1076
 
1057
- this.new_client_id(parts)
1077
+ this.new_client_id(parts)
1058
1078
  );}
1059
1079
 
1060
1080
  return cid}
@@ -1063,66 +1083,85 @@ class MQTTBase {
1063
1083
  return [parts[0], Math.random().toString(36).slice(2), parts[1]].join('')}
1064
1084
 
1065
1085
 
1086
+
1087
+
1088
+
1089
+
1090
+
1091
+
1092
+
1066
1093
 
1067
1094
 
1095
+ // Internal API
1068
1096
 
1097
+ /* async _send(type, pkt) -- provided by _conn_ and transport */
1069
1098
 
1099
+ _init_dispatch(opt) {
1100
+ this.constructor?._once_();
1101
+ let router = this.router =
1102
+ this._init_router?.(opt, this);
1070
1103
 
1104
+ let tgt ={
1105
+ __proto__: opt.on_mqtt_type || {}
1106
+ , router};
1071
1107
 
1108
+ tgt.mqtt_publish ||= router?.invoke;
1109
+ return _mqtt_dispatch(this, tgt)}
1072
1110
 
1111
+ static _aliases() {
1112
+ return ' pub:publish sub:subscribe unsub:unsubscribe '}
1073
1113
 
1114
+ static _once_(self=this) {
1115
+ self._once_ = _=>0;
1116
+ self.MQTTError = MQTTError;
1117
+ let p = self.prototype;
1118
+ for (let alias of self._aliases().split(/\s+/)) {
1119
+ alias = alias.split(':');
1120
+ let fn = alias[1] && p[alias[1]];
1121
+ if (fn) {p[alias[0]] = fn;} } } }
1074
1122
 
1075
- // Internal API
1076
-
1077
- /* async _send(type, pkt) -- provided by _conn_ and transport */
1078
-
1079
- _init_router(opt) {
1080
- return this.router = _mqtt_topic_router()}
1081
1123
 
1082
- _init_dispatch(opt) {
1083
- let tgt ={
1084
- __proto__: opt.on_mqtt_type || {}
1085
- , router: this._init_router(opt, this)};
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
+ */
1086
1139
 
1087
- tgt.mqtt_publish ||= tgt.router.invoke;
1088
- return _mqtt_dispatch(this, tgt)} }
1089
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) );
1090
1146
 
1091
- {
1092
- let p = MQTTBase.prototype;
1093
- Object.assign(p,{
1094
- MQTTError
1095
- , pub: p.publish
1096
- , sub: p.subscribe
1097
- , unsub: p.unsubscribe
1098
- , sub_topic: p.subscribe_topic
1099
- , unsub_topic: p.unsubscribe_topic
1100
- , shared_sub: p.shared_subscribe
1101
- , shared_unsub: p.shared_unsubscribe} );
1102
-
1103
- /*
1104
- p.on_mqtt_type = {
1105
- mqtt_auth(pkt, ctx) ::
1106
- mqtt_connect(pkt, ctx) ::
1107
- mqtt_connack(pkt, ctx) ::
1108
- mqtt_disconnect(pkt, ctx) ::
1109
-
1110
- mqtt_publish(pkt, ctx)
1111
- mqtt_subscribe(pkt, ctx) ::
1112
- mqtt_unsubscribe(pkt, ctx) ::
1113
-
1114
- mqtt_pingreq(pkt, ctx) ::
1115
- mqtt_pingresp(pkt, ctx) ::
1116
- }
1117
- */}
1147
+ function _as_topics(pkt, ex, topic_prefix) {
1148
+ if (ex?.trim) {// string
1149
+ topic_prefix = ex;
1150
+ ex = null;}
1118
1151
 
1152
+ pkt =(
1153
+ pkt.trim // string
1154
+ ? {topics:[pkt], ... ex}
1155
+ : pkt[Symbol.iterator]
1156
+ ? {topics:[... pkt], ... ex}
1157
+ : ex ? {...pkt, ...ex}
1158
+ : pkt);
1119
1159
 
1120
- function _as_topics(pkt, ex) {
1121
- if ('string' === typeof pkt) {
1122
- return {topics:[pkt], ... ex}}
1123
- if (pkt[Symbol.iterator]) {
1124
- return {topics:[... pkt], ... ex}}
1125
- return ex ? {...pkt, ...ex} : pkt}
1160
+ if (topic_prefix) {
1161
+ // particularly useful with shared queues, e.g.
1162
+ // topic_prefix = '$share/some-queue-name/'
1163
+ pkt.topics = _prefix_topics(topic_prefix, pkt.topics);}
1164
+ return pkt}
1126
1165
 
1127
1166
 
1128
1167
  async function _pub(self, pkt, pub_opt) {
@@ -1194,7 +1233,7 @@ class MQTTCore extends MQTTBase {
1194
1233
  return this}
1195
1234
 
1196
1235
  //log_conn(evt, arg, err_arg) ::
1197
- //console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
1236
+ // console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
1198
1237
 
1199
1238
  on_live(client, is_reconnect) {
1200
1239
  if (is_reconnect) {
@@ -1236,30 +1275,55 @@ class MQTTCore extends MQTTBase {
1236
1275
  return this}
1237
1276
 
1238
1277
 
1239
-
1240
-
1241
-
1242
-
1243
-
1244
-
1245
-
1246
-
1247
-
1248
-
1249
1278
 
1279
+
1280
+
1281
+
1282
+
1283
+
1284
+
1285
+
1250
1286
 
1287
+
1288
+
1289
+
1290
+
1291
+
1251
1292
 
1293
+
1294
+
1295
+
1296
+
1297
+
1252
1298
 
1299
+
1300
+
1301
+
1302
+
1253
1303
 
1304
+
1305
+
1254
1306
 
1255
1307
 
1256
- with_tcp(port, hostname) {
1257
- if (!Number.isFinite(port)) {
1258
- ({port, hostname} = new URL(port));}
1308
+ with_tcp(...opt) {
1309
+ opt = this._conn_opt(opt);
1310
+ console.log({opt});
1311
+ return this._use_conn (() =>
1312
+ this.with_stream(
1313
+ connect(opt)) ) }
1314
+
1315
+ with_tls(...opt) {
1316
+ opt = this._conn_opt(opt);
1317
+ return this._use_conn (() =>
1318
+ this.with_stream(
1319
+ connect$1(opt)) ) }
1259
1320
 
1260
- return this._use_conn (() =>
1261
- this.with_stream(
1262
- connect(port, hostname)) ) }
1321
+ _conn_opt([a0, a1, a2]) {
1322
+ // (port, hostname, options) or (url, options)
1323
+ if (Number.isFinite(a0)) {
1324
+ return {...a2, port: a0, host: a1}}
1325
+ a0 = new URL(a0);
1326
+ return {...a1, port: a0.port, host: a0.hostname}}
1263
1327
 
1264
1328
 
1265
1329
  with_stream(read_stream, write_stream) {
@@ -1305,10 +1369,11 @@ class MQTTCore extends MQTTBase {
1305
1369
 
1306
1370
  return this} }
1307
1371
 
1308
- var version = "0.3.1";
1372
+ const version = '0.4.0';
1309
1373
 
1310
1374
  const MQTTClient_v4 = /* #__PURE__ */
1311
- MQTTCore.mqtt_ctx(4, mqtt_opts_v4);
1375
+ with_topic_path_router(
1376
+ MQTTCore.mqtt_ctx(4, mqtt_opts_v4) );
1312
1377
 
1313
1378
  const mqtt_v4 = opt =>
1314
1379
  new MQTTClient_v4(opt);