u8-mqtt 0.3.2-0 → 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 (76) 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 +308 -267
  7. package/cjs/index.cjs.map +1 -1
  8. package/cjs/v4.cjs +303 -262
  9. package/cjs/v4.cjs.map +1 -1
  10. package/cjs/v5.cjs +305 -263
  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/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} +30 -12
  18. package/code/v4.js +3 -1
  19. package/code/v5.js +5 -2
  20. package/code/with_topic_router.jsy +41 -0
  21. package/esm/deno/basic-v4.js +1193 -0
  22. package/esm/deno/basic-v4.js.map +1 -0
  23. package/esm/deno/basic-v5.js +1455 -0
  24. package/esm/deno/basic-v5.js.map +1 -0
  25. package/esm/deno/index.js +306 -264
  26. package/esm/deno/index.js.map +1 -1
  27. package/esm/deno/v4.js +303 -262
  28. package/esm/deno/v4.js.map +1 -1
  29. package/esm/deno/v5.js +305 -263
  30. package/esm/deno/v5.js.map +1 -1
  31. package/esm/node/basic-v4.js +1196 -0
  32. package/esm/node/basic-v4.js.map +1 -0
  33. package/esm/node/basic-v4.mjs +1196 -0
  34. package/esm/node/basic-v4.mjs.map +1 -0
  35. package/esm/node/basic-v5.js +1458 -0
  36. package/esm/node/basic-v5.js.map +1 -0
  37. package/esm/node/basic-v5.mjs +1458 -0
  38. package/esm/node/basic-v5.mjs.map +1 -0
  39. package/esm/node/index.js +306 -264
  40. package/esm/node/index.js.map +1 -1
  41. package/esm/node/index.mjs +306 -264
  42. package/esm/node/index.mjs.map +1 -1
  43. package/esm/node/v4.js +303 -262
  44. package/esm/node/v4.js.map +1 -1
  45. package/esm/node/v4.mjs +303 -262
  46. package/esm/node/v4.mjs.map +1 -1
  47. package/esm/node/v5.js +305 -263
  48. package/esm/node/v5.js.map +1 -1
  49. package/esm/node/v5.mjs +305 -263
  50. package/esm/node/v5.mjs.map +1 -1
  51. package/esm/web/basic-v4.js +1193 -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 +1455 -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 +305 -263
  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 +303 -262
  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 +304 -262
  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/web/v4.js CHANGED
@@ -513,6 +513,191 @@ const mqtt_opts_v4 =
513
513
  encode_fns: mqtt_encode_v4,
514
514
  mqtt_writer: mqtt_writer_v4, };
515
515
 
516
+ function parse(str, loose) {
517
+ if (str instanceof RegExp) return { keys:false, pattern:str };
518
+ var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
519
+ arr[0] || arr.shift();
520
+
521
+ while (tmp = arr.shift()) {
522
+ c = tmp[0];
523
+ if (c === '*') {
524
+ keys.push('wild');
525
+ pattern += '/(.*)';
526
+ } else if (c === ':') {
527
+ o = tmp.indexOf('?', 1);
528
+ ext = tmp.indexOf('.', 1);
529
+ keys.push( tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length) );
530
+ pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';
531
+ if (!!~ext) pattern += (!!~o ? '?' : '') + '\\' + tmp.substring(ext);
532
+ } else {
533
+ pattern += '/' + tmp;
534
+ }
535
+ }
536
+
537
+ return {
538
+ keys: keys,
539
+ pattern: new RegExp('^' + pattern + (loose ? '(?=$|\/)' : '\/?$'), 'i')
540
+ };
541
+ }
542
+
543
+ /*
544
+ class AbstractTopicRouter ::
545
+ async invoke(pkt, ctx) ::
546
+ add(topic_route, ...args) ::
547
+ remove(topic_route, priority) ::
548
+ clear(priority) ::
549
+ find(topic) :: // optional
550
+ mqtt_topic(topic_route)
551
+ */
552
+
553
+ const with_topic_router = mqtt_topic_router =>
554
+ MQTTKlass => class extends MQTTKlass {
555
+ static _aliases() {
556
+ return super._aliases() +
557
+ ' sub_topic:subscribe_topic unsub_topic:unsubscribe_topic'}
558
+
559
+ _init_router(opt) {
560
+ return mqtt_topic_router(opt, this)}
561
+
562
+ get on_topic() {return this.router.add}
563
+
564
+ _sub_chain(topic, ex, topic_prefix) {
565
+ let res = this.subscribe([[ topic ]], ex, topic_prefix);
566
+ let subs = this.subs ||(this.subs = new Map());
567
+ subs.set((res.topic = topic), (subs.last = res));
568
+ return this }// fluent api -- return this and track side effects
569
+
570
+ // alias: sub_topic
571
+ subscribe_topic(topic_route, ...args) {
572
+ let router = this.router;
573
+ router.add(topic_route, true, args.pop() );// handler
574
+ let topic = router.mqtt_topic(topic_route);
575
+ return this._sub_chain(topic, ...args ) }// ex, topic_prefix
576
+
577
+ // alias: unsub_topic
578
+ unsubscribe_topic(topic_route, ...args) {
579
+ let router = this.router;
580
+ router.remove(topic_route, true);
581
+ let topic = router.mqtt_topic(topic_route);
582
+ return this.unsubscribe([[ topic ]], ...args ) } };// topic_prefix
583
+
584
+ // Use [regexparam][] for url-like topic parsing
585
+ // [regexparam]: https://github.com/lukeed/regexparam
586
+
587
+
588
+ const with_topic_path_router = /* #__PURE__ */
589
+ with_topic_router(mqtt_topic_path_router);
590
+
591
+
592
+ const mqtt_topic = topic_route =>
593
+ topic_route
594
+ .replace(/[*].*$/, '#')
595
+ .replace(/:\w+\??/g, '+');
596
+
597
+ const as_topic_path = topic_route =>(
598
+ topic_route
599
+ .replace(/#$/, '*') // replace MQTT # wildcard at end
600
+ .split(/([^\/]*[+][^\/]*)/) // split on MQTT + match tokens
601
+ .reduce (( sz, v, idx ) => sz +(
602
+ idx & 1 // even entires are body, odd are MQTT + tokens
603
+ ? `:$${1 + idx>>1}` // replace with `:$#` sequential ids, using ? for partial entries
604
+ : v ) ) );// pass through body
605
+
606
+ function _ignore(pkt, params, ctx) {ctx.done = true;}
607
+
608
+ function mqtt_topic_path_router() {
609
+ let pri_lsts = [[],[]], rm = Symbol();
610
+ let find = topic => _routes_iter(pri_lsts, topic);
611
+
612
+ // return duck-type compatible with AbstractTopicRouter in ./with_topic_router
613
+ return {find, mqtt_topic,
614
+ add(topic_route, ...args) {
615
+ let fn = args.pop();
616
+ let priority = args.pop();
617
+
618
+ if ('function' !== typeof fn) {
619
+ if (false === fn) {
620
+ fn = _ignore;}
621
+ else throw new TypeError()}
622
+
623
+ let rte = parse(as_topic_path(topic_route));
624
+
625
+ rte.key = topic_route;
626
+ rte.tgt = fn;
627
+ pri_lsts[priority ? 0 : 1].push(rte);
628
+ return this}
629
+
630
+ , remove(topic_route, priority) {
631
+ let lst = pri_lsts[priority ? 0 : 1];
632
+ return _route_remove([lst], topic_route)}
633
+
634
+ , clear(priority) {
635
+ pri_lsts[priority ? 0 : 1] = [];
636
+ if (null == priority) {
637
+ pri_lsts[1] = [];} }
638
+
639
+ , async invoke(pkt, ctx) {
640
+ ctx.idx = 0;
641
+ ctx.rm = rm;
642
+
643
+ for (let [fn, params] of find(pkt.topic)) {
644
+ let res = await fn(pkt, params, ctx);
645
+
646
+ if (rm === res) {
647
+ _route_remove(pri_lsts, fn);}
648
+
649
+ if (ctx.done) {
650
+ break}
651
+ else ctx.idx++;}
652
+
653
+ let {pkt_id, qos} = pkt;
654
+ if (1 === qos) {
655
+ await ctx.mqtt._send('puback', {pkt_id});} } } }
656
+
657
+
658
+ function * _routes_iter(all_route_lists, topic) {
659
+ for (let route_list of all_route_lists) {
660
+ for (let route of route_list) {
661
+ let res = _route_match_one(topic, route);
662
+ if (undefined !== res) {
663
+ yield res;} } } }
664
+
665
+
666
+ function _route_match_one(topic, {keys, pattern, tgt}) {
667
+ let match = '/' !== topic[0]
668
+ ? pattern.exec('/'+topic)
669
+ : pattern.exec(topic);
670
+
671
+ if (null === match) {
672
+ return}
673
+
674
+ if (false === keys) {
675
+ let {groups} = match;
676
+ if (! groups) {
677
+ return [tgt]}
678
+
679
+ let params = {};
680
+ for (let k in groups) {
681
+ params[k] = groups[k];}
682
+
683
+ return [tgt, params]}
684
+
685
+ if (0 === keys.length) {
686
+ return [tgt]}
687
+
688
+ let params = {};
689
+ for (let i=0; i<keys.length; i++) {
690
+ params[ keys[i] ] = match[1+i];}
691
+ return [tgt, params]}
692
+
693
+
694
+ function _route_remove(all_route_lists, query) {
695
+ let match = route => route===query || route.tgt===query || route.key===query;
696
+ for (let lst of all_route_lists) {
697
+ let i = lst.findIndex(match);
698
+ if (0 <= i) {return !! lst.splice(i,1)} }
699
+ return false}
700
+
516
701
  /*
517
702
  export function decode_varint_loop(u8, i=0) {
518
703
  let i0 = i
@@ -694,138 +879,13 @@ function _ping_interval(send_ping) {
694
879
  if (td) {
695
880
  tid = setInterval(send_ping, 1000 * td);
696
881
 
697
-
698
-
882
+
883
+
699
884
 
700
- // ensure the interval allows the NodeJS event loop to exit
701
- tid.unref?.();
885
+ // ensure the interval allows the NodeJS event loop to exit
886
+ tid.unref?.();
702
887
  return true} }) }
703
888
 
704
- function parse(str, loose) {
705
- if (str instanceof RegExp) return { keys:false, pattern:str };
706
- var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
707
- arr[0] || arr.shift();
708
-
709
- while (tmp = arr.shift()) {
710
- c = tmp[0];
711
- if (c === '*') {
712
- keys.push('wild');
713
- pattern += '/(.*)';
714
- } else if (c === ':') {
715
- o = tmp.indexOf('?', 1);
716
- ext = tmp.indexOf('.', 1);
717
- keys.push( tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length) );
718
- pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';
719
- if (!!~ext) pattern += (!!~o ? '?' : '') + '\\' + tmp.substring(ext);
720
- } else {
721
- pattern += '/' + tmp;
722
- }
723
- }
724
-
725
- return {
726
- keys: keys,
727
- pattern: new RegExp('^' + pattern + (loose ? '(?=$|\/)' : '\/?$'), 'i')
728
- };
729
- }
730
-
731
- // Use [regexparam][] for url-like topic parsing
732
-
733
- function _ignore(pkt, params, ctx) {ctx.done = true;}
734
-
735
- function _mqtt_topic_router() {
736
- let pri_lsts = [[],[]], rm = Symbol();
737
- let find = topic => _mqtt_routes_iter(pri_lsts, topic);
738
-
739
- return {find,
740
-
741
- add(topic_route, ...args) {
742
- let fn = args.pop();
743
- let priority = args.pop();
744
-
745
- if ('function' !== typeof fn) {
746
- if (false === fn) {
747
- fn = _ignore;}
748
- else throw new TypeError()}
749
-
750
- let rte = parse(
751
- topic_route.replace(/[+#]$/, '*'));
752
-
753
- rte.key = topic_route;
754
- rte.tgt = fn;
755
- pri_lsts[priority ? 0 : 1].push(rte);
756
- return this}
757
-
758
- , remove(topic_route, priority) {
759
- let lst = pri_lsts[priority ? 0 : 1];
760
- return _mqtt_route_remove([lst], topic_route)}
761
-
762
- , clear(priority) {
763
- pri_lsts[priority ? 0 : 1] = [];
764
- if (null == priority) {
765
- pri_lsts[1] = [];} }
766
-
767
- , async invoke(pkt, ctx) {
768
- ctx.idx = 0;
769
- ctx.rm = rm;
770
-
771
- for (let [fn, params] of find(pkt.topic)) {
772
- let res = await fn(pkt, params, ctx);
773
-
774
- if (rm === res) {
775
- _mqtt_route_remove(pri_lsts, fn);}
776
-
777
- if (ctx.done) {
778
- break}
779
- else ctx.idx++;}
780
-
781
- let {pkt_id, qos} = pkt;
782
- if (1 === qos) {
783
- await ctx.mqtt._send('puback', {pkt_id});} } } }
784
-
785
-
786
- function * _mqtt_routes_iter(all_route_lists, topic) {
787
- for (let route_list of all_route_lists) {
788
- for (let route of route_list) {
789
- let res = _mqtt_route_match_one(topic, route);
790
- if (undefined !== res) {
791
- yield res;} } } }
792
-
793
-
794
- function _mqtt_route_match_one(topic, {keys, pattern, tgt}) {
795
- let match = '/' !== topic[0]
796
- ? pattern.exec('/'+topic)
797
- : pattern.exec(topic);
798
-
799
- if (null === match) {
800
- return}
801
-
802
- if (false === keys) {
803
- let {groups} = match;
804
- if (! groups) {
805
- return [tgt]}
806
-
807
- let params = {};
808
- for (let k in groups) {
809
- params[k] = groups[k];}
810
-
811
- return [tgt, params]}
812
-
813
- if (0 === keys.length) {
814
- return [tgt]}
815
-
816
- let params = {};
817
- for (let i=0; i<keys.length; i++) {
818
- params[ keys[i] ] = match[1+i];}
819
- return [tgt, params]}
820
-
821
-
822
- function _mqtt_route_remove(all_route_lists, query) {
823
- let match = route => route===query || route.tgt===query || route.key===query;
824
- for (let lst of all_route_lists) {
825
- let i = lst.findIndex(match);
826
- if (0 <= i) {return !! lst.splice(i,1)} }
827
- return false}
828
-
829
889
  const _mqtt_cmdid_dispatch ={
830
890
  create(target) {
831
891
  return {__proto__: this, target, hashbelt: [new Map()]} }
@@ -894,8 +954,7 @@ const _mqtt_cmdid_dispatch ={
894
954
  let fn = target[`mqtt_${pkt.type}`]
895
955
  || target.mqtt_pkt;
896
956
 
897
- if (undefined !== fn) {
898
- await fn.call(target, pkt, ctx);} } })()) };
957
+ await fn?.call(target, pkt, ctx);} })()) };
899
958
 
900
959
  function _mqtt_dispatch(opt, target) {
901
960
  let _disp_ = _mqtt_cmdid_dispatch.create(target);
@@ -976,53 +1035,15 @@ class MQTTBase {
976
1035
 
977
1036
 
978
1037
  // alias: sub
979
- subscribe(pkt, ex) {
980
- pkt = _as_topics(pkt, ex);
1038
+ subscribe(pkt, ex, topic_prefix) {
1039
+ pkt = _as_topics(pkt, ex, topic_prefix);
981
1040
  return this._send('subscribe', pkt, pkt)}
982
- _sub_chain(topic, ex) {
983
- let res = this.subscribe([[ topic ]], ex);
984
- let subs = this.subs ||(this.subs = new Map());
985
- subs.set((res.topic = topic), (subs.last = res));
986
- return this }// fluent api -- return this and track side effects
987
1041
 
988
1042
  // alias: unsub
989
- unsubscribe(pkt, ex) {
990
- pkt = _as_topics(pkt, ex);
1043
+ unsubscribe(pkt, ex, topic_prefix) {
1044
+ pkt = _as_topics(pkt, ex, topic_prefix);
991
1045
  return this._send('unsubscribe', pkt, pkt)}
992
1046
 
993
- get on_topic() {return this.router.add}
994
-
995
- // alias: sub_topic
996
- subscribe_topic(topic_route, ...args) {
997
- this.router.add(topic_route, true, args.pop() );// handler
998
- let topic = this.topic_for(topic_route);
999
- return this._sub_chain(topic, args.pop() ) }// ex
1000
-
1001
- // alias: unsub_topic
1002
- unsubscribe_topic(topic_route) {
1003
- this.router.remove(topic_route, true);
1004
- let topic = this.topic_for(topic_route);
1005
- return this.unsubscribe([[ topic ]]) }
1006
-
1007
- // alias: shared_sub
1008
- shared_subscribe(group, topic_route, ...args) {
1009
- this.router.add(topic_route, true, args.pop() );// handler
1010
- let topic = this.topic_for(topic_route);
1011
- if (null != group) {
1012
- topic = `$share/${group}/${topic}`;}
1013
- return this._sub_chain(topic, args.pop() ) }// ex
1014
-
1015
- // alias: shared_unsub
1016
- shared_unsubscribe(group, topic_route) {
1017
- this.router.remove(topic_route, true);
1018
- let topic = this.topic_for(topic_route);
1019
- if (null != group) {
1020
- topic = `$share/${group}/${topic}`;}
1021
- return this.unsubscribe([[ topic ]]) }
1022
-
1023
- topic_for(topic_route) {
1024
- return topic_route.replace(/[:*].*$/, '#')}
1025
-
1026
1047
 
1027
1048
  // alias: pub
1028
1049
  publish(pkt, pub_opt) {return _pub(this, pkt, pub_opt)}
@@ -1048,9 +1069,9 @@ class MQTTBase {
1048
1069
  if (undefined === cid) {
1049
1070
  this.client_id = cid = (
1050
1071
 
1051
- this.sess_client_id(parts)
1072
+ this.sess_client_id(parts)
1052
1073
 
1053
-
1074
+
1054
1075
  );}
1055
1076
 
1056
1077
  return cid}
@@ -1059,66 +1080,85 @@ class MQTTBase {
1059
1080
  return [parts[0], Math.random().toString(36).slice(2), parts[1]].join('')}
1060
1081
 
1061
1082
 
1062
- sess_client_id(parts) {
1063
- let key = parts.join('\x20');
1064
- let cid = sessionStorage.getItem(key);
1065
- if (null == cid) {
1066
- cid = this.new_client_id(parts);
1067
- sessionStorage.setItem(key, cid);}
1068
- return cid}
1083
+ sess_client_id(parts) {
1084
+ let key = parts.join('\x20');
1085
+ let cid = sessionStorage.getItem(key);
1086
+ if (null == cid) {
1087
+ cid = this.new_client_id(parts);
1088
+ sessionStorage.setItem(key, cid);}
1089
+ return cid}
1069
1090
 
1070
1091
 
1071
1092
  // Internal API
1072
1093
 
1073
1094
  /* async _send(type, pkt) -- provided by _conn_ and transport */
1074
1095
 
1075
- _init_router(opt) {
1076
- return this.router = _mqtt_topic_router()}
1077
-
1078
1096
  _init_dispatch(opt) {
1097
+ this.constructor?._once_();
1098
+ let router = this.router =
1099
+ this._init_router?.(opt, this);
1100
+
1079
1101
  let tgt ={
1080
1102
  __proto__: opt.on_mqtt_type || {}
1081
- , router: this._init_router(opt, this)};
1103
+ , router};
1082
1104
 
1083
- tgt.mqtt_publish ||= tgt.router.invoke;
1084
- return _mqtt_dispatch(this, tgt)} }
1105
+ tgt.mqtt_publish ||= router?.invoke;
1106
+ return _mqtt_dispatch(this, tgt)}
1085
1107
 
1108
+ static _aliases() {
1109
+ return ' pub:publish sub:subscribe unsub:unsubscribe '}
1110
+
1111
+ static _once_(self=this) {
1112
+ self._once_ = _=>0;
1113
+ self.MQTTError = MQTTError;
1114
+ let p = self.prototype;
1115
+ for (let alias of self._aliases().split(/\s+/)) {
1116
+ alias = alias.split(':');
1117
+ let fn = alias[1] && p[alias[1]];
1118
+ if (fn) {p[alias[0]] = fn;} } } }
1086
1119
 
1087
- {
1088
- let p = MQTTBase.prototype;
1089
- Object.assign(p,{
1090
- MQTTError
1091
- , pub: p.publish
1092
- , sub: p.subscribe
1093
- , unsub: p.unsubscribe
1094
- , sub_topic: p.subscribe_topic
1095
- , unsub_topic: p.unsubscribe_topic
1096
- , shared_sub: p.shared_subscribe
1097
- , shared_unsub: p.shared_unsubscribe} );
1098
-
1099
- /*
1100
- p.on_mqtt_type = {
1101
- mqtt_auth(pkt, ctx) ::
1102
- mqtt_connect(pkt, ctx) ::
1103
- mqtt_connack(pkt, ctx) ::
1104
- mqtt_disconnect(pkt, ctx) ::
1105
-
1106
- mqtt_publish(pkt, ctx)
1107
- mqtt_subscribe(pkt, ctx) ::
1108
- mqtt_unsubscribe(pkt, ctx) ::
1109
-
1110
- mqtt_pingreq(pkt, ctx) ::
1111
- mqtt_pingresp(pkt, ctx) ::
1112
- }
1113
- */}
1114
1120
 
1121
+ /*
1122
+ on_mqtt_type = {
1123
+ mqtt_auth(pkt, ctx) ::
1124
+ mqtt_connect(pkt, ctx) ::
1125
+ mqtt_connack(pkt, ctx) ::
1126
+ mqtt_disconnect(pkt, ctx) ::
1127
+
1128
+ mqtt_publish(pkt, ctx)
1129
+ mqtt_subscribe(pkt, ctx) ::
1130
+ mqtt_unsubscribe(pkt, ctx) ::
1131
+
1132
+ mqtt_pingreq(pkt, ctx) ::
1133
+ mqtt_pingresp(pkt, ctx) ::
1134
+ }
1135
+ */
1115
1136
 
1116
- function _as_topics(pkt, ex) {
1117
- if ('string' === typeof pkt) {
1118
- return {topics:[pkt], ... ex}}
1119
- if (pkt[Symbol.iterator]) {
1120
- return {topics:[... pkt], ... ex}}
1121
- return ex ? {...pkt, ...ex} : pkt}
1137
+
1138
+ const _prefix_topics = (topic_prefix, iterable) =>
1139
+ Array.from(iterable, value =>(
1140
+ value.trim // string
1141
+ ? _prefix_topics(topic_prefix, value)
1142
+ : topic_prefix + value) );
1143
+
1144
+ function _as_topics(pkt, ex, topic_prefix) {
1145
+ if (ex?.trim) {// string
1146
+ topic_prefix = ex;
1147
+ ex = null;}
1148
+
1149
+ pkt =(
1150
+ pkt.trim // string
1151
+ ? {topics:[pkt], ... ex}
1152
+ : pkt[Symbol.iterator]
1153
+ ? {topics:[... pkt], ... ex}
1154
+ : ex ? {...pkt, ...ex}
1155
+ : pkt);
1156
+
1157
+ if (topic_prefix) {
1158
+ // particularly useful with shared queues, e.g.
1159
+ // topic_prefix = '$share/some-queue-name/'
1160
+ pkt.topics = _prefix_topics(topic_prefix, pkt.topics);}
1161
+ return pkt}
1122
1162
 
1123
1163
 
1124
1164
  async function _pub(self, pkt, pub_opt) {
@@ -1234,53 +1274,53 @@ class MQTTCore extends MQTTBase {
1234
1274
 
1235
1275
 
1236
1276
 
1277
+
1278
+
1279
+
1280
+
1281
+
1282
+
1237
1283
 
1284
+
1285
+
1286
+
1287
+
1288
+
1238
1289
 
1290
+
1291
+
1292
+
1293
+
1294
+
1239
1295
 
1296
+
1297
+
1298
+
1299
+
1240
1300
 
1241
-
1242
-
1243
-
1244
-
1245
-
1246
-
1247
-
1248
-
1249
-
1250
-
1251
-
1252
-
1253
-
1254
-
1255
-
1256
-
1257
-
1258
-
1259
-
1260
-
1261
-
1262
-
1301
+
1302
+
1263
1303
 
1264
1304
 
1305
+
1306
+
1307
+
1308
+
1309
+
1310
+
1265
1311
 
1312
+
1313
+
1314
+
1315
+
1316
+
1266
1317
 
1267
-
1268
-
1269
-
1270
-
1271
-
1272
-
1273
-
1274
-
1275
-
1276
-
1277
-
1278
-
1279
-
1280
-
1281
-
1282
-
1283
-
1318
+
1319
+
1320
+
1321
+
1322
+
1323
+
1284
1324
 
1285
1325
 
1286
1326
  with_stream(read_stream, write_stream) {
@@ -1326,10 +1366,11 @@ class MQTTCore extends MQTTBase {
1326
1366
 
1327
1367
  return this} }
1328
1368
 
1329
- const version = '0.3.2-0';
1369
+ const version = '0.4.0';
1330
1370
 
1331
1371
  const MQTTClient_v4 = /* #__PURE__ */
1332
- MQTTCore.mqtt_ctx(4, mqtt_opts_v4);
1372
+ with_topic_path_router(
1373
+ MQTTCore.mqtt_ctx(4, mqtt_opts_v4) );
1333
1374
 
1334
1375
  const mqtt_v4 = opt =>
1335
1376
  new MQTTClient_v4(opt);