u8-mqtt 0.3.2-0 → 0.4.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.
Files changed (76) hide show
  1. package/README.md +5 -5
  2. package/cjs/basic-v4.cjs +1200 -0
  3. package/cjs/basic-v4.cjs.map +1 -0
  4. package/cjs/basic-v5.cjs +1464 -0
  5. package/cjs/basic-v5.cjs.map +1 -0
  6. package/cjs/index.cjs +312 -269
  7. package/cjs/index.cjs.map +1 -1
  8. package/cjs/v4.cjs +307 -264
  9. package/cjs/v4.cjs.map +1 -1
  10. package/cjs/v5.cjs +309 -265
  11. package/cjs/v5.cjs.map +1 -1
  12. package/code/_cmdid_dispatch.jsy +1 -3
  13. package/code/base.jsy +64 -89
  14. package/code/basic-v4.js +18 -0
  15. package/code/basic-v5.js +26 -0
  16. package/code/index.js +2 -1
  17. package/code/{_router.jsy → router_path.jsy} +36 -12
  18. package/code/v4.js +3 -1
  19. package/code/v5.js +5 -2
  20. package/code/with_topic_router.jsy +42 -0
  21. package/esm/deno/basic-v4.js +1188 -0
  22. package/esm/deno/basic-v4.js.map +1 -0
  23. package/esm/deno/basic-v5.js +1450 -0
  24. package/esm/deno/basic-v5.js.map +1 -0
  25. package/esm/deno/index.js +310 -266
  26. package/esm/deno/index.js.map +1 -1
  27. package/esm/deno/v4.js +307 -264
  28. package/esm/deno/v4.js.map +1 -1
  29. package/esm/deno/v5.js +309 -265
  30. package/esm/deno/v5.js.map +1 -1
  31. package/esm/node/basic-v4.js +1191 -0
  32. package/esm/node/basic-v4.js.map +1 -0
  33. package/esm/node/basic-v4.mjs +1191 -0
  34. package/esm/node/basic-v4.mjs.map +1 -0
  35. package/esm/node/basic-v5.js +1453 -0
  36. package/esm/node/basic-v5.js.map +1 -0
  37. package/esm/node/basic-v5.mjs +1453 -0
  38. package/esm/node/basic-v5.mjs.map +1 -0
  39. package/esm/node/index.js +310 -266
  40. package/esm/node/index.js.map +1 -1
  41. package/esm/node/index.mjs +310 -266
  42. package/esm/node/index.mjs.map +1 -1
  43. package/esm/node/v4.js +307 -264
  44. package/esm/node/v4.js.map +1 -1
  45. package/esm/node/v4.mjs +307 -264
  46. package/esm/node/v4.mjs.map +1 -1
  47. package/esm/node/v5.js +309 -265
  48. package/esm/node/v5.js.map +1 -1
  49. package/esm/node/v5.mjs +309 -265
  50. package/esm/node/v5.mjs.map +1 -1
  51. package/esm/web/basic-v4.js +1188 -0
  52. package/esm/web/basic-v4.js.map +1 -0
  53. package/esm/web/basic-v4.min.js +1 -0
  54. package/esm/web/basic-v4.min.js.br +0 -0
  55. package/esm/web/basic-v4.min.js.gz +0 -0
  56. package/esm/web/basic-v5.js +1450 -0
  57. package/esm/web/basic-v5.js.map +1 -0
  58. package/esm/web/basic-v5.min.js +1 -0
  59. package/esm/web/basic-v5.min.js.br +0 -0
  60. package/esm/web/basic-v5.min.js.gz +0 -0
  61. package/esm/web/index.js +309 -265
  62. package/esm/web/index.js.map +1 -1
  63. package/esm/web/index.min.js +1 -1
  64. package/esm/web/index.min.js.br +0 -0
  65. package/esm/web/index.min.js.gz +0 -0
  66. package/esm/web/v4.js +307 -264
  67. package/esm/web/v4.js.map +1 -1
  68. package/esm/web/v4.min.js +1 -1
  69. package/esm/web/v4.min.js.br +0 -0
  70. package/esm/web/v4.min.js.gz +0 -0
  71. package/esm/web/v5.js +308 -264
  72. package/esm/web/v5.js.map +1 -1
  73. package/esm/web/v5.min.js +1 -1
  74. package/esm/web/v5.min.js.br +0 -0
  75. package/esm/web/v5.min.js.gz +0 -0
  76. package/package.json +5 -5
package/cjs/v4.cjs CHANGED
@@ -520,6 +520,198 @@ const mqtt_opts_v4 =
520
520
  encode_fns: mqtt_encode_v4,
521
521
  mqtt_writer: mqtt_writer_v4, };
522
522
 
523
+ function parse(str, loose) {
524
+ if (str instanceof RegExp) return { keys:false, pattern:str };
525
+ var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
526
+ arr[0] || arr.shift();
527
+
528
+ while (tmp = arr.shift()) {
529
+ c = tmp[0];
530
+ if (c === '*') {
531
+ keys.push('wild');
532
+ pattern += '/(.*)';
533
+ } else if (c === ':') {
534
+ o = tmp.indexOf('?', 1);
535
+ ext = tmp.indexOf('.', 1);
536
+ keys.push( tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length) );
537
+ pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';
538
+ if (!!~ext) pattern += (!!~o ? '?' : '') + '\\' + tmp.substring(ext);
539
+ } else {
540
+ pattern += '/' + tmp;
541
+ }
542
+ }
543
+
544
+ return {
545
+ keys: keys,
546
+ pattern: new RegExp('^' + pattern + (loose ? '(?=$|\/)' : '\/?$'), 'i')
547
+ };
548
+ }
549
+
550
+ /*
551
+ class AbstractTopicRouter ::
552
+ async invoke(pkt, ctx) ::
553
+ add(topic_route, ...args) ::
554
+ remove(topic_route, priority) ::
555
+ clear(priority) ::
556
+ find(topic) :: // optional
557
+ mqtt_topic(topic_route)
558
+ */
559
+
560
+ const with_topic_router = mqtt_topic_router =>
561
+ MQTTKlass => class extends MQTTKlass {
562
+ static _aliases() {
563
+ return super._aliases() +
564
+ ' sub_topic:subscribe_topic unsub_topic:unsubscribe_topic'}
565
+
566
+ _init_router(opt, client, target) {
567
+ let router = this.router = target.router =
568
+ mqtt_topic_router(opt, this);
569
+ return router?.invoke}
570
+ get on_topic() {return this.router.add}
571
+
572
+ _sub_chain(topic, ex, topic_prefix) {
573
+ let res = this.subscribe([[ topic ]], ex, topic_prefix);
574
+ let subs = this.subs ||(this.subs = new Map());
575
+ subs.set((res.topic = topic), (subs.last = res));
576
+ return this }// fluent api -- return this and track side effects
577
+
578
+ // alias: sub_topic
579
+ subscribe_topic(topic_route, ...args) {
580
+ let router = this.router;
581
+ router.add(topic_route, true, args.pop() );// handler
582
+ let topic = router.mqtt_topic(topic_route);
583
+ return this._sub_chain(topic, ...args ) }// ex, topic_prefix
584
+
585
+ // alias: unsub_topic
586
+ unsubscribe_topic(topic_route, ...args) {
587
+ let router = this.router;
588
+ router.remove(topic_route, true);
589
+ let topic = router.mqtt_topic(topic_route);
590
+ return this.unsubscribe([[ topic ]], ...args ) } };// topic_prefix
591
+
592
+ // Use [regexparam][] for url-like topic parsing
593
+ // [regexparam]: https://github.com/lukeed/regexparam
594
+
595
+
596
+ const with_topic_path_router = /* #__PURE__ */
597
+ with_topic_router(mqtt_topic_path_router);
598
+
599
+
600
+ const mqtt_topic = topic_route =>
601
+ topic_route
602
+ .replace(/[*].*$/, '#')
603
+ .replace(/:\w+\??/g, '+');
604
+
605
+ /* From the [MQTT v5 Spec](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Topic_Names_and)
606
+ 4.7.1.2 Multi-level wildcard -- (‘#’ U+0023)
607
+ ... MUST be specified either on its own or following a topic level separator.
608
+ In either case it MUST be the last character specified in the Topic Filter
609
+
610
+ 4.7.1.3 Single-level wildcard -- (‘+’ U+002B)
611
+ ...it MUST occupy an entire level of the filter.
612
+ */
613
+
614
+ const as_topic_path = (topic_route, id) =>(
615
+ id=1,
616
+ topic_route
617
+ .replace(/#$/, '*' )// replace MQTT '#' multi-level wildcard at end
618
+ .replace(/\+/g, () => `:$${id++}` ) );// replace MQTT '+' single-level wildcards
619
+
620
+ function _ignore(pkt, params, ctx) {ctx.done = true;}
621
+
622
+ function mqtt_topic_path_router() {
623
+ let pri_lsts = [[],[]], rm = Symbol();
624
+ let find = topic => _routes_iter(pri_lsts, topic);
625
+
626
+ // return duck-type compatible with AbstractTopicRouter in ./with_topic_router
627
+ return {find, mqtt_topic,
628
+ add(topic_route, ...args) {
629
+ let fn = args.pop();
630
+ let priority = args.pop();
631
+
632
+ if ('function' !== typeof fn) {
633
+ if (false === fn) {
634
+ fn = _ignore;}
635
+ else throw new TypeError()}
636
+
637
+ let rte = parse(as_topic_path(topic_route));
638
+
639
+ rte.key = topic_route;
640
+ rte.tgt = fn;
641
+ pri_lsts[priority ? 0 : 1].push(rte);
642
+ return this}
643
+
644
+ , remove(topic_route, priority) {
645
+ let lst = pri_lsts[priority ? 0 : 1];
646
+ return _route_remove([lst], topic_route)}
647
+
648
+ , clear(priority) {
649
+ pri_lsts[priority ? 0 : 1] = [];
650
+ if (null == priority) {
651
+ pri_lsts[1] = [];} }
652
+
653
+ , async invoke(pkt, ctx) {
654
+ ctx.idx = 0;
655
+ ctx.rm = rm;
656
+
657
+ for (let [fn, params] of find(pkt.topic)) {
658
+ let res = await fn(pkt, params, ctx);
659
+
660
+ if (rm === res) {
661
+ _route_remove(pri_lsts, fn);}
662
+
663
+ if (ctx.done) {
664
+ break}
665
+ else ctx.idx++;}
666
+
667
+ let {pkt_id, qos} = pkt;
668
+ if (1 === qos) {
669
+ await ctx.mqtt._send('puback', {pkt_id});} } } }
670
+
671
+
672
+ function * _routes_iter(all_route_lists, topic) {
673
+ for (let route_list of all_route_lists) {
674
+ for (let route of route_list) {
675
+ let res = _route_match_one(topic, route);
676
+ if (undefined !== res) {
677
+ yield res;} } } }
678
+
679
+
680
+ function _route_match_one(topic, {keys, pattern, tgt}) {
681
+ let match = '/' !== topic[0]
682
+ ? pattern.exec('/'+topic)
683
+ : pattern.exec(topic);
684
+
685
+ if (null === match) {
686
+ return}
687
+
688
+ if (false === keys) {
689
+ let {groups} = match;
690
+ if (! groups) {
691
+ return [tgt]}
692
+
693
+ let params = {};
694
+ for (let k in groups) {
695
+ params[k] = groups[k];}
696
+
697
+ return [tgt, params]}
698
+
699
+ if (0 === keys.length) {
700
+ return [tgt]}
701
+
702
+ let params = {};
703
+ for (let i=0; i<keys.length; i++) {
704
+ params[ keys[i] ] = match[1+i];}
705
+ return [tgt, params]}
706
+
707
+
708
+ function _route_remove(all_route_lists, query) {
709
+ let match = route => route===query || route.tgt===query || route.key===query;
710
+ for (let lst of all_route_lists) {
711
+ let i = lst.findIndex(match);
712
+ if (0 <= i) {return !! lst.splice(i,1)} }
713
+ return false}
714
+
523
715
  /*
524
716
  export function decode_varint_loop(u8, i=0) {
525
717
  let i0 = i
@@ -701,138 +893,13 @@ function _ping_interval(send_ping) {
701
893
  if (td) {
702
894
  tid = setInterval(send_ping, 1000 * td);
703
895
 
704
-
705
-
896
+
897
+
706
898
 
707
- // ensure the interval allows the NodeJS event loop to exit
708
- tid.unref?.();
899
+ // ensure the interval allows the NodeJS event loop to exit
900
+ tid.unref?.();
709
901
  return true} }) }
710
902
 
711
- function parse(str, loose) {
712
- if (str instanceof RegExp) return { keys:false, pattern:str };
713
- var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
714
- arr[0] || arr.shift();
715
-
716
- while (tmp = arr.shift()) {
717
- c = tmp[0];
718
- if (c === '*') {
719
- keys.push('wild');
720
- pattern += '/(.*)';
721
- } else if (c === ':') {
722
- o = tmp.indexOf('?', 1);
723
- ext = tmp.indexOf('.', 1);
724
- keys.push( tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length) );
725
- pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';
726
- if (!!~ext) pattern += (!!~o ? '?' : '') + '\\' + tmp.substring(ext);
727
- } else {
728
- pattern += '/' + tmp;
729
- }
730
- }
731
-
732
- return {
733
- keys: keys,
734
- pattern: new RegExp('^' + pattern + (loose ? '(?=$|\/)' : '\/?$'), 'i')
735
- };
736
- }
737
-
738
- // Use [regexparam][] for url-like topic parsing
739
-
740
- function _ignore(pkt, params, ctx) {ctx.done = true;}
741
-
742
- function _mqtt_topic_router() {
743
- let pri_lsts = [[],[]], rm = Symbol();
744
- let find = topic => _mqtt_routes_iter(pri_lsts, topic);
745
-
746
- return {find,
747
-
748
- add(topic_route, ...args) {
749
- let fn = args.pop();
750
- let priority = args.pop();
751
-
752
- if ('function' !== typeof fn) {
753
- if (false === fn) {
754
- fn = _ignore;}
755
- else throw new TypeError()}
756
-
757
- let rte = parse(
758
- topic_route.replace(/[+#]$/, '*'));
759
-
760
- rte.key = topic_route;
761
- rte.tgt = fn;
762
- pri_lsts[priority ? 0 : 1].push(rte);
763
- return this}
764
-
765
- , remove(topic_route, priority) {
766
- let lst = pri_lsts[priority ? 0 : 1];
767
- return _mqtt_route_remove([lst], topic_route)}
768
-
769
- , clear(priority) {
770
- pri_lsts[priority ? 0 : 1] = [];
771
- if (null == priority) {
772
- pri_lsts[1] = [];} }
773
-
774
- , async invoke(pkt, ctx) {
775
- ctx.idx = 0;
776
- ctx.rm = rm;
777
-
778
- for (let [fn, params] of find(pkt.topic)) {
779
- let res = await fn(pkt, params, ctx);
780
-
781
- if (rm === res) {
782
- _mqtt_route_remove(pri_lsts, fn);}
783
-
784
- if (ctx.done) {
785
- break}
786
- else ctx.idx++;}
787
-
788
- let {pkt_id, qos} = pkt;
789
- if (1 === qos) {
790
- await ctx.mqtt._send('puback', {pkt_id});} } } }
791
-
792
-
793
- function * _mqtt_routes_iter(all_route_lists, topic) {
794
- for (let route_list of all_route_lists) {
795
- for (let route of route_list) {
796
- let res = _mqtt_route_match_one(topic, route);
797
- if (undefined !== res) {
798
- yield res;} } } }
799
-
800
-
801
- function _mqtt_route_match_one(topic, {keys, pattern, tgt}) {
802
- let match = '/' !== topic[0]
803
- ? pattern.exec('/'+topic)
804
- : pattern.exec(topic);
805
-
806
- if (null === match) {
807
- return}
808
-
809
- if (false === keys) {
810
- let {groups} = match;
811
- if (! groups) {
812
- return [tgt]}
813
-
814
- let params = {};
815
- for (let k in groups) {
816
- params[k] = groups[k];}
817
-
818
- return [tgt, params]}
819
-
820
- if (0 === keys.length) {
821
- return [tgt]}
822
-
823
- let params = {};
824
- for (let i=0; i<keys.length; i++) {
825
- params[ keys[i] ] = match[1+i];}
826
- return [tgt, params]}
827
-
828
-
829
- function _mqtt_route_remove(all_route_lists, query) {
830
- let match = route => route===query || route.tgt===query || route.key===query;
831
- for (let lst of all_route_lists) {
832
- let i = lst.findIndex(match);
833
- if (0 <= i) {return !! lst.splice(i,1)} }
834
- return false}
835
-
836
903
  const _mqtt_cmdid_dispatch ={
837
904
  create(target) {
838
905
  return {__proto__: this, target, hashbelt: [new Map()]} }
@@ -901,8 +968,7 @@ const _mqtt_cmdid_dispatch ={
901
968
  let fn = target[`mqtt_${pkt.type}`]
902
969
  || target.mqtt_pkt;
903
970
 
904
- if (undefined !== fn) {
905
- await fn.call(target, pkt, ctx);} } })()) };
971
+ await fn?.call(target, pkt, ctx);} })()) };
906
972
 
907
973
  function _mqtt_dispatch(opt, target) {
908
974
  let _disp_ = _mqtt_cmdid_dispatch.create(target);
@@ -983,53 +1049,15 @@ class MQTTBase {
983
1049
 
984
1050
 
985
1051
  // alias: sub
986
- subscribe(pkt, ex) {
987
- pkt = _as_topics(pkt, ex);
1052
+ subscribe(pkt, ex, topic_prefix) {
1053
+ pkt = _as_topics(pkt, ex, topic_prefix);
988
1054
  return this._send('subscribe', pkt, pkt)}
989
- _sub_chain(topic, ex) {
990
- let res = this.subscribe([[ topic ]], ex);
991
- let subs = this.subs ||(this.subs = new Map());
992
- subs.set((res.topic = topic), (subs.last = res));
993
- return this }// fluent api -- return this and track side effects
994
1055
 
995
1056
  // alias: unsub
996
- unsubscribe(pkt, ex) {
997
- pkt = _as_topics(pkt, ex);
1057
+ unsubscribe(pkt, ex, topic_prefix) {
1058
+ pkt = _as_topics(pkt, ex, topic_prefix);
998
1059
  return this._send('unsubscribe', pkt, pkt)}
999
1060
 
1000
- get on_topic() {return this.router.add}
1001
-
1002
- // alias: sub_topic
1003
- subscribe_topic(topic_route, ...args) {
1004
- this.router.add(topic_route, true, args.pop() );// handler
1005
- let topic = this.topic_for(topic_route);
1006
- return this._sub_chain(topic, args.pop() ) }// ex
1007
-
1008
- // alias: unsub_topic
1009
- unsubscribe_topic(topic_route) {
1010
- this.router.remove(topic_route, true);
1011
- let topic = this.topic_for(topic_route);
1012
- return this.unsubscribe([[ topic ]]) }
1013
-
1014
- // alias: shared_sub
1015
- shared_subscribe(group, topic_route, ...args) {
1016
- this.router.add(topic_route, true, args.pop() );// handler
1017
- let topic = this.topic_for(topic_route);
1018
- if (null != group) {
1019
- topic = `$share/${group}/${topic}`;}
1020
- return this._sub_chain(topic, args.pop() ) }// ex
1021
-
1022
- // alias: shared_unsub
1023
- shared_unsubscribe(group, topic_route) {
1024
- this.router.remove(topic_route, true);
1025
- let topic = this.topic_for(topic_route);
1026
- if (null != group) {
1027
- topic = `$share/${group}/${topic}`;}
1028
- return this.unsubscribe([[ topic ]]) }
1029
-
1030
- topic_for(topic_route) {
1031
- return topic_route.replace(/[:*].*$/, '#')}
1032
-
1033
1061
 
1034
1062
  // alias: pub
1035
1063
  publish(pkt, pub_opt) {return _pub(this, pkt, pub_opt)}
@@ -1055,9 +1083,9 @@ class MQTTBase {
1055
1083
  if (undefined === cid) {
1056
1084
  this.client_id = cid = (
1057
1085
 
1058
-
1086
+
1059
1087
 
1060
- this.new_client_id(parts)
1088
+ this.new_client_id(parts)
1061
1089
  );}
1062
1090
 
1063
1091
  return cid}
@@ -1066,66 +1094,80 @@ class MQTTBase {
1066
1094
  return [parts[0], Math.random().toString(36).slice(2), parts[1]].join('')}
1067
1095
 
1068
1096
 
1097
+
1098
+
1099
+
1100
+
1101
+
1102
+
1103
+
1069
1104
 
1070
1105
 
1106
+ // Internal API
1071
1107
 
1108
+ /* async _send(type, pkt) -- provided by _conn_ and transport */
1072
1109
 
1110
+ _init_dispatch(opt) {
1111
+ this.constructor?._once_();
1112
+ let target ={__proto__: opt.on_mqtt_type};
1113
+ target.mqtt_publish ||=
1114
+ this._init_router?.(opt, this, target);
1115
+ return _mqtt_dispatch(this, target)}
1073
1116
 
1117
+ static _aliases() {
1118
+ return ' pub:publish sub:subscribe unsub:unsubscribe '}
1074
1119
 
1120
+ static _once_(self=this) {
1121
+ self._once_ = _=>0;
1122
+ self.MQTTError = MQTTError;
1123
+ let p = self.prototype;
1124
+ for (let alias of self._aliases().split(/\s+/)) {
1125
+ alias = alias.split(':');
1126
+ let fn = alias[1] && p[alias[1]];
1127
+ if (fn) {p[alias[0]] = fn;} } } }
1075
1128
 
1076
1129
 
1130
+ /*
1131
+ on_mqtt_type = {
1132
+ mqtt_auth(pkt, ctx) ::
1133
+ mqtt_connect(pkt, ctx) ::
1134
+ mqtt_connack(pkt, ctx) ::
1135
+ mqtt_disconnect(pkt, ctx) ::
1136
+
1137
+ mqtt_publish(pkt, ctx)
1138
+ mqtt_subscribe(pkt, ctx) ::
1139
+ mqtt_unsubscribe(pkt, ctx) ::
1140
+
1141
+ mqtt_pingreq(pkt, ctx) ::
1142
+ mqtt_pingresp(pkt, ctx) ::
1143
+ }
1144
+ */
1077
1145
 
1078
- // Internal API
1079
-
1080
- /* async _send(type, pkt) -- provided by _conn_ and transport */
1081
-
1082
- _init_router(opt) {
1083
- return this.router = _mqtt_topic_router()}
1084
-
1085
- _init_dispatch(opt) {
1086
- let tgt ={
1087
- __proto__: opt.on_mqtt_type || {}
1088
- , router: this._init_router(opt, this)};
1089
-
1090
- tgt.mqtt_publish ||= tgt.router.invoke;
1091
- return _mqtt_dispatch(this, tgt)} }
1092
1146
 
1147
+ const _prefix_topics = (topic_prefix, iterable) =>
1148
+ Array.from(iterable, value =>(
1149
+ value.trim // string
1150
+ ? _prefix_topics(topic_prefix, value)
1151
+ : topic_prefix + value) );
1093
1152
 
1094
- {
1095
- let p = MQTTBase.prototype;
1096
- Object.assign(p,{
1097
- MQTTError
1098
- , pub: p.publish
1099
- , sub: p.subscribe
1100
- , unsub: p.unsubscribe
1101
- , sub_topic: p.subscribe_topic
1102
- , unsub_topic: p.unsubscribe_topic
1103
- , shared_sub: p.shared_subscribe
1104
- , shared_unsub: p.shared_unsubscribe} );
1105
-
1106
- /*
1107
- p.on_mqtt_type = {
1108
- mqtt_auth(pkt, ctx) ::
1109
- mqtt_connect(pkt, ctx) ::
1110
- mqtt_connack(pkt, ctx) ::
1111
- mqtt_disconnect(pkt, ctx) ::
1112
-
1113
- mqtt_publish(pkt, ctx)
1114
- mqtt_subscribe(pkt, ctx) ::
1115
- mqtt_unsubscribe(pkt, ctx) ::
1116
-
1117
- mqtt_pingreq(pkt, ctx) ::
1118
- mqtt_pingresp(pkt, ctx) ::
1119
- }
1120
- */}
1153
+ function _as_topics(pkt, ex, topic_prefix) {
1154
+ if (ex?.trim) {// string
1155
+ topic_prefix = ex;
1156
+ ex = null;}
1121
1157
 
1158
+ pkt =(
1159
+ pkt.trim // string
1160
+ ? {topics:[pkt], ... ex}
1161
+ : pkt[Symbol.iterator]
1162
+ ? {topics:[... pkt], ... ex}
1163
+ : ex ? {...pkt, ...ex}
1164
+ : pkt);
1122
1165
 
1123
- function _as_topics(pkt, ex) {
1124
- if ('string' === typeof pkt) {
1125
- return {topics:[pkt], ... ex}}
1126
- if (pkt[Symbol.iterator]) {
1127
- return {topics:[... pkt], ... ex}}
1128
- return ex ? {...pkt, ...ex} : pkt}
1166
+ if (topic_prefix) {
1167
+ // particularly useful with shared queues, e.g.
1168
+ // topic_prefix = '$share/some-queue-name/'
1169
+ pkt.topics = _prefix_topics(topic_prefix, pkt.topics);}
1170
+ return pkt}
1129
1171
 
1130
1172
 
1131
1173
  async function _pub(self, pkt, pub_opt) {
@@ -1241,53 +1283,53 @@ class MQTTCore extends MQTTBase {
1241
1283
 
1242
1284
 
1243
1285
 
1286
+
1287
+
1288
+
1289
+
1290
+
1291
+
1244
1292
 
1293
+
1294
+
1295
+
1296
+
1297
+
1245
1298
 
1299
+
1300
+
1301
+
1302
+
1303
+
1246
1304
 
1305
+
1306
+
1307
+
1308
+
1247
1309
 
1310
+
1311
+
1248
1312
 
1313
+
1314
+ with_tcp(...opt) {
1315
+ opt = this._conn_opt(opt);
1316
+ console.log({opt});
1317
+ return this._use_conn (() =>
1318
+ this.with_stream(
1319
+ node_net.connect(opt)) ) }
1249
1320
 
1321
+ with_tls(...opt) {
1322
+ opt = this._conn_opt(opt);
1323
+ return this._use_conn (() =>
1324
+ this.with_stream(
1325
+ node_tls.connect(opt)) ) }
1250
1326
 
1251
-
1252
-
1253
-
1254
-
1255
-
1256
-
1257
-
1258
-
1259
-
1260
-
1261
-
1262
-
1263
-
1264
-
1265
-
1266
-
1267
-
1268
-
1269
-
1270
-
1271
-
1272
- with_tcp(...opt) {
1273
- opt = this._conn_opt(opt);
1274
- console.log({opt});
1275
- return this._use_conn (() =>
1276
- this.with_stream(
1277
- node_net.connect(opt)) ) }
1278
-
1279
- with_tls(...opt) {
1280
- opt = this._conn_opt(opt);
1281
- return this._use_conn (() =>
1282
- this.with_stream(
1283
- node_tls.connect(opt)) ) }
1284
-
1285
- _conn_opt([a0, a1, a2]) {
1286
- // (port, hostname, options) or (url, options)
1287
- if (Number.isFinite(a0)) {
1288
- return {...a2, port: a0, host: a1}}
1289
- a0 = new URL(a0);
1290
- return {...a1, port: a0.port, host: a0.hostname}}
1327
+ _conn_opt([a0, a1, a2]) {
1328
+ // (port, hostname, options) or (url, options)
1329
+ if (Number.isFinite(a0)) {
1330
+ return {...a2, port: a0, host: a1}}
1331
+ a0 = new URL(a0);
1332
+ return {...a1, port: a0.port, host: a0.hostname}}
1291
1333
 
1292
1334
 
1293
1335
  with_stream(read_stream, write_stream) {
@@ -1333,10 +1375,11 @@ class MQTTCore extends MQTTBase {
1333
1375
 
1334
1376
  return this} }
1335
1377
 
1336
- const version = '0.3.2-0';
1378
+ const version = '0.4.1';
1337
1379
 
1338
1380
  const MQTTClient_v4 = /* #__PURE__ */
1339
- MQTTCore.mqtt_ctx(4, mqtt_opts_v4);
1381
+ with_topic_path_router(
1382
+ MQTTCore.mqtt_ctx(4, mqtt_opts_v4) );
1340
1383
 
1341
1384
  const mqtt_v4 = opt =>
1342
1385
  new MQTTClient_v4(opt);