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