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/deno/v5.js CHANGED
@@ -769,6 +769,198 @@ const mqtt_opts_v5 =
769
769
  encode_fns: mqtt_encode_v5,
770
770
  mqtt_writer: mqtt_writer_v5, };
771
771
 
772
+ function parse(str, loose) {
773
+ if (str instanceof RegExp) return { keys:false, pattern:str };
774
+ var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
775
+ arr[0] || arr.shift();
776
+
777
+ while (tmp = arr.shift()) {
778
+ c = tmp[0];
779
+ if (c === '*') {
780
+ keys.push('wild');
781
+ pattern += '/(.*)';
782
+ } else if (c === ':') {
783
+ o = tmp.indexOf('?', 1);
784
+ ext = tmp.indexOf('.', 1);
785
+ keys.push( tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length) );
786
+ pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';
787
+ if (!!~ext) pattern += (!!~o ? '?' : '') + '\\' + tmp.substring(ext);
788
+ } else {
789
+ pattern += '/' + tmp;
790
+ }
791
+ }
792
+
793
+ return {
794
+ keys: keys,
795
+ pattern: new RegExp('^' + pattern + (loose ? '(?=$|\/)' : '\/?$'), 'i')
796
+ };
797
+ }
798
+
799
+ /*
800
+ class AbstractTopicRouter ::
801
+ async invoke(pkt, ctx) ::
802
+ add(topic_route, ...args) ::
803
+ remove(topic_route, priority) ::
804
+ clear(priority) ::
805
+ find(topic) :: // optional
806
+ mqtt_topic(topic_route)
807
+ */
808
+
809
+ const with_topic_router = mqtt_topic_router =>
810
+ MQTTKlass => class extends MQTTKlass {
811
+ static _aliases() {
812
+ return super._aliases() +
813
+ ' sub_topic:subscribe_topic unsub_topic:unsubscribe_topic'}
814
+
815
+ _init_router(opt, client, target) {
816
+ let router = this.router = target.router =
817
+ mqtt_topic_router(opt, this);
818
+ return router?.invoke}
819
+ get on_topic() {return this.router.add}
820
+
821
+ _sub_chain(topic, ex, topic_prefix) {
822
+ let res = this.subscribe([[ topic ]], ex, topic_prefix);
823
+ let subs = this.subs ||(this.subs = new Map());
824
+ subs.set((res.topic = topic), (subs.last = res));
825
+ return this }// fluent api -- return this and track side effects
826
+
827
+ // alias: sub_topic
828
+ subscribe_topic(topic_route, ...args) {
829
+ let router = this.router;
830
+ router.add(topic_route, true, args.pop() );// handler
831
+ let topic = router.mqtt_topic(topic_route);
832
+ return this._sub_chain(topic, ...args ) }// ex, topic_prefix
833
+
834
+ // alias: unsub_topic
835
+ unsubscribe_topic(topic_route, ...args) {
836
+ let router = this.router;
837
+ router.remove(topic_route, true);
838
+ let topic = router.mqtt_topic(topic_route);
839
+ return this.unsubscribe([[ topic ]], ...args ) } };// topic_prefix
840
+
841
+ // Use [regexparam][] for url-like topic parsing
842
+ // [regexparam]: https://github.com/lukeed/regexparam
843
+
844
+
845
+ const with_topic_path_router = /* #__PURE__ */
846
+ with_topic_router(mqtt_topic_path_router);
847
+
848
+
849
+ const mqtt_topic = topic_route =>
850
+ topic_route
851
+ .replace(/[*].*$/, '#')
852
+ .replace(/:\w+\??/g, '+');
853
+
854
+ /* From the [MQTT v5 Spec](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Topic_Names_and)
855
+ 4.7.1.2 Multi-level wildcard -- (‘#’ U+0023)
856
+ ... MUST be specified either on its own or following a topic level separator.
857
+ In either case it MUST be the last character specified in the Topic Filter
858
+
859
+ 4.7.1.3 Single-level wildcard -- (‘+’ U+002B)
860
+ ...it MUST occupy an entire level of the filter.
861
+ */
862
+
863
+ const as_topic_path = (topic_route, id) =>(
864
+ id=1,
865
+ topic_route
866
+ .replace(/#$/, '*' )// replace MQTT '#' multi-level wildcard at end
867
+ .replace(/\+/g, () => `:$${id++}` ) );// replace MQTT '+' single-level wildcards
868
+
869
+ function _ignore(pkt, params, ctx) {ctx.done = true;}
870
+
871
+ function mqtt_topic_path_router() {
872
+ let pri_lsts = [[],[]], rm = Symbol();
873
+ let find = topic => _routes_iter(pri_lsts, topic);
874
+
875
+ // return duck-type compatible with AbstractTopicRouter in ./with_topic_router
876
+ return {find, mqtt_topic,
877
+ add(topic_route, ...args) {
878
+ let fn = args.pop();
879
+ let priority = args.pop();
880
+
881
+ if ('function' !== typeof fn) {
882
+ if (false === fn) {
883
+ fn = _ignore;}
884
+ else throw new TypeError()}
885
+
886
+ let rte = parse(as_topic_path(topic_route));
887
+
888
+ rte.key = topic_route;
889
+ rte.tgt = fn;
890
+ pri_lsts[priority ? 0 : 1].push(rte);
891
+ return this}
892
+
893
+ , remove(topic_route, priority) {
894
+ let lst = pri_lsts[priority ? 0 : 1];
895
+ return _route_remove([lst], topic_route)}
896
+
897
+ , clear(priority) {
898
+ pri_lsts[priority ? 0 : 1] = [];
899
+ if (null == priority) {
900
+ pri_lsts[1] = [];} }
901
+
902
+ , async invoke(pkt, ctx) {
903
+ ctx.idx = 0;
904
+ ctx.rm = rm;
905
+
906
+ for (let [fn, params] of find(pkt.topic)) {
907
+ let res = await fn(pkt, params, ctx);
908
+
909
+ if (rm === res) {
910
+ _route_remove(pri_lsts, fn);}
911
+
912
+ if (ctx.done) {
913
+ break}
914
+ else ctx.idx++;}
915
+
916
+ let {pkt_id, qos} = pkt;
917
+ if (1 === qos) {
918
+ await ctx.mqtt._send('puback', {pkt_id});} } } }
919
+
920
+
921
+ function * _routes_iter(all_route_lists, topic) {
922
+ for (let route_list of all_route_lists) {
923
+ for (let route of route_list) {
924
+ let res = _route_match_one(topic, route);
925
+ if (undefined !== res) {
926
+ yield res;} } } }
927
+
928
+
929
+ function _route_match_one(topic, {keys, pattern, tgt}) {
930
+ let match = '/' !== topic[0]
931
+ ? pattern.exec('/'+topic)
932
+ : pattern.exec(topic);
933
+
934
+ if (null === match) {
935
+ return}
936
+
937
+ if (false === keys) {
938
+ let {groups} = match;
939
+ if (! groups) {
940
+ return [tgt]}
941
+
942
+ let params = {};
943
+ for (let k in groups) {
944
+ params[k] = groups[k];}
945
+
946
+ return [tgt, params]}
947
+
948
+ if (0 === keys.length) {
949
+ return [tgt]}
950
+
951
+ let params = {};
952
+ for (let i=0; i<keys.length; i++) {
953
+ params[ keys[i] ] = match[1+i];}
954
+ return [tgt, params]}
955
+
956
+
957
+ function _route_remove(all_route_lists, query) {
958
+ let match = route => route===query || route.tgt===query || route.key===query;
959
+ for (let lst of all_route_lists) {
960
+ let i = lst.findIndex(match);
961
+ if (0 <= i) {return !! lst.splice(i,1)} }
962
+ return false}
963
+
772
964
  /*
773
965
  export function decode_varint_loop(u8, i=0) {
774
966
  let i0 = i
@@ -950,138 +1142,13 @@ function _ping_interval(send_ping) {
950
1142
  if (td) {
951
1143
  tid = setInterval(send_ping, 1000 * td);
952
1144
 
953
- // ensure the interval allows the Deno event loop to exit
954
- Deno.unrefTimer(tid);
1145
+ // ensure the interval allows the Deno event loop to exit
1146
+ Deno.unrefTimer(tid);
955
1147
 
956
-
957
-
1148
+
1149
+
958
1150
  return true} }) }
959
1151
 
960
- function parse(str, loose) {
961
- if (str instanceof RegExp) return { keys:false, pattern:str };
962
- var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
963
- arr[0] || arr.shift();
964
-
965
- while (tmp = arr.shift()) {
966
- c = tmp[0];
967
- if (c === '*') {
968
- keys.push('wild');
969
- pattern += '/(.*)';
970
- } else if (c === ':') {
971
- o = tmp.indexOf('?', 1);
972
- ext = tmp.indexOf('.', 1);
973
- keys.push( tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length) );
974
- pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';
975
- if (!!~ext) pattern += (!!~o ? '?' : '') + '\\' + tmp.substring(ext);
976
- } else {
977
- pattern += '/' + tmp;
978
- }
979
- }
980
-
981
- return {
982
- keys: keys,
983
- pattern: new RegExp('^' + pattern + (loose ? '(?=$|\/)' : '\/?$'), 'i')
984
- };
985
- }
986
-
987
- // Use [regexparam][] for url-like topic parsing
988
-
989
- function _ignore(pkt, params, ctx) {ctx.done = true;}
990
-
991
- function _mqtt_topic_router() {
992
- let pri_lsts = [[],[]], rm = Symbol();
993
- let find = topic => _mqtt_routes_iter(pri_lsts, topic);
994
-
995
- return {find,
996
-
997
- add(topic_route, ...args) {
998
- let fn = args.pop();
999
- let priority = args.pop();
1000
-
1001
- if ('function' !== typeof fn) {
1002
- if (false === fn) {
1003
- fn = _ignore;}
1004
- else throw new TypeError()}
1005
-
1006
- let rte = parse(
1007
- topic_route.replace(/[+#]$/, '*'));
1008
-
1009
- rte.key = topic_route;
1010
- rte.tgt = fn;
1011
- pri_lsts[priority ? 0 : 1].push(rte);
1012
- return this}
1013
-
1014
- , remove(topic_route, priority) {
1015
- let lst = pri_lsts[priority ? 0 : 1];
1016
- return _mqtt_route_remove([lst], topic_route)}
1017
-
1018
- , clear(priority) {
1019
- pri_lsts[priority ? 0 : 1] = [];
1020
- if (null == priority) {
1021
- pri_lsts[1] = [];} }
1022
-
1023
- , async invoke(pkt, ctx) {
1024
- ctx.idx = 0;
1025
- ctx.rm = rm;
1026
-
1027
- for (let [fn, params] of find(pkt.topic)) {
1028
- let res = await fn(pkt, params, ctx);
1029
-
1030
- if (rm === res) {
1031
- _mqtt_route_remove(pri_lsts, fn);}
1032
-
1033
- if (ctx.done) {
1034
- break}
1035
- else ctx.idx++;}
1036
-
1037
- let {pkt_id, qos} = pkt;
1038
- if (1 === qos) {
1039
- await ctx.mqtt._send('puback', {pkt_id});} } } }
1040
-
1041
-
1042
- function * _mqtt_routes_iter(all_route_lists, topic) {
1043
- for (let route_list of all_route_lists) {
1044
- for (let route of route_list) {
1045
- let res = _mqtt_route_match_one(topic, route);
1046
- if (undefined !== res) {
1047
- yield res;} } } }
1048
-
1049
-
1050
- function _mqtt_route_match_one(topic, {keys, pattern, tgt}) {
1051
- let match = '/' !== topic[0]
1052
- ? pattern.exec('/'+topic)
1053
- : pattern.exec(topic);
1054
-
1055
- if (null === match) {
1056
- return}
1057
-
1058
- if (false === keys) {
1059
- let {groups} = match;
1060
- if (! groups) {
1061
- return [tgt]}
1062
-
1063
- let params = {};
1064
- for (let k in groups) {
1065
- params[k] = groups[k];}
1066
-
1067
- return [tgt, params]}
1068
-
1069
- if (0 === keys.length) {
1070
- return [tgt]}
1071
-
1072
- let params = {};
1073
- for (let i=0; i<keys.length; i++) {
1074
- params[ keys[i] ] = match[1+i];}
1075
- return [tgt, params]}
1076
-
1077
-
1078
- function _mqtt_route_remove(all_route_lists, query) {
1079
- let match = route => route===query || route.tgt===query || route.key===query;
1080
- for (let lst of all_route_lists) {
1081
- let i = lst.findIndex(match);
1082
- if (0 <= i) {return !! lst.splice(i,1)} }
1083
- return false}
1084
-
1085
1152
  const _mqtt_cmdid_dispatch ={
1086
1153
  create(target) {
1087
1154
  return {__proto__: this, target, hashbelt: [new Map()]} }
@@ -1150,8 +1217,7 @@ const _mqtt_cmdid_dispatch ={
1150
1217
  let fn = target[`mqtt_${pkt.type}`]
1151
1218
  || target.mqtt_pkt;
1152
1219
 
1153
- if (undefined !== fn) {
1154
- await fn.call(target, pkt, ctx);} } })()) };
1220
+ await fn?.call(target, pkt, ctx);} })()) };
1155
1221
 
1156
1222
  function _mqtt_dispatch(opt, target) {
1157
1223
  let _disp_ = _mqtt_cmdid_dispatch.create(target);
@@ -1232,53 +1298,15 @@ class MQTTBase {
1232
1298
 
1233
1299
 
1234
1300
  // alias: sub
1235
- subscribe(pkt, ex) {
1236
- pkt = _as_topics(pkt, ex);
1301
+ subscribe(pkt, ex, topic_prefix) {
1302
+ pkt = _as_topics(pkt, ex, topic_prefix);
1237
1303
  return this._send('subscribe', pkt, pkt)}
1238
- _sub_chain(topic, ex) {
1239
- let res = this.subscribe([[ topic ]], ex);
1240
- let subs = this.subs ||(this.subs = new Map());
1241
- subs.set((res.topic = topic), (subs.last = res));
1242
- return this }// fluent api -- return this and track side effects
1243
1304
 
1244
1305
  // alias: unsub
1245
- unsubscribe(pkt, ex) {
1246
- pkt = _as_topics(pkt, ex);
1306
+ unsubscribe(pkt, ex, topic_prefix) {
1307
+ pkt = _as_topics(pkt, ex, topic_prefix);
1247
1308
  return this._send('unsubscribe', pkt, pkt)}
1248
1309
 
1249
- get on_topic() {return this.router.add}
1250
-
1251
- // alias: sub_topic
1252
- subscribe_topic(topic_route, ...args) {
1253
- this.router.add(topic_route, true, args.pop() );// handler
1254
- let topic = this.topic_for(topic_route);
1255
- return this._sub_chain(topic, args.pop() ) }// ex
1256
-
1257
- // alias: unsub_topic
1258
- unsubscribe_topic(topic_route) {
1259
- this.router.remove(topic_route, true);
1260
- let topic = this.topic_for(topic_route);
1261
- return this.unsubscribe([[ topic ]]) }
1262
-
1263
- // alias: shared_sub
1264
- shared_subscribe(group, topic_route, ...args) {
1265
- this.router.add(topic_route, true, args.pop() );// handler
1266
- let topic = this.topic_for(topic_route);
1267
- if (null != group) {
1268
- topic = `$share/${group}/${topic}`;}
1269
- return this._sub_chain(topic, args.pop() ) }// ex
1270
-
1271
- // alias: shared_unsub
1272
- shared_unsubscribe(group, topic_route) {
1273
- this.router.remove(topic_route, true);
1274
- let topic = this.topic_for(topic_route);
1275
- if (null != group) {
1276
- topic = `$share/${group}/${topic}`;}
1277
- return this.unsubscribe([[ topic ]]) }
1278
-
1279
- topic_for(topic_route) {
1280
- return topic_route.replace(/[:*].*$/, '#')}
1281
-
1282
1310
 
1283
1311
  // alias: pub
1284
1312
  publish(pkt, pub_opt) {return _pub(this, pkt, pub_opt)}
@@ -1304,9 +1332,9 @@ class MQTTBase {
1304
1332
  if (undefined === cid) {
1305
1333
  this.client_id = cid = (
1306
1334
 
1307
-
1335
+
1308
1336
 
1309
- this.new_client_id(parts)
1337
+ this.new_client_id(parts)
1310
1338
  );}
1311
1339
 
1312
1340
  return cid}
@@ -1315,66 +1343,80 @@ class MQTTBase {
1315
1343
  return [parts[0], Math.random().toString(36).slice(2), parts[1]].join('')}
1316
1344
 
1317
1345
 
1318
-
1319
-
1320
-
1321
-
1322
-
1323
-
1324
-
1346
+
1347
+
1348
+
1349
+
1350
+
1351
+
1352
+
1325
1353
 
1326
1354
 
1327
1355
  // Internal API
1328
1356
 
1329
1357
  /* async _send(type, pkt) -- provided by _conn_ and transport */
1330
1358
 
1331
- _init_router(opt) {
1332
- return this.router = _mqtt_topic_router()}
1333
-
1334
1359
  _init_dispatch(opt) {
1335
- let tgt ={
1336
- __proto__: opt.on_mqtt_type || {}
1337
- , router: this._init_router(opt, this)};
1360
+ this.constructor?._once_();
1361
+ let target ={__proto__: opt.on_mqtt_type};
1362
+ target.mqtt_publish ||=
1363
+ this._init_router?.(opt, this, target);
1364
+ return _mqtt_dispatch(this, target)}
1338
1365
 
1339
- tgt.mqtt_publish ||= tgt.router.invoke;
1340
- return _mqtt_dispatch(this, tgt)} }
1366
+ static _aliases() {
1367
+ return ' pub:publish sub:subscribe unsub:unsubscribe '}
1341
1368
 
1369
+ static _once_(self=this) {
1370
+ self._once_ = _=>0;
1371
+ self.MQTTError = MQTTError;
1372
+ let p = self.prototype;
1373
+ for (let alias of self._aliases().split(/\s+/)) {
1374
+ alias = alias.split(':');
1375
+ let fn = alias[1] && p[alias[1]];
1376
+ if (fn) {p[alias[0]] = fn;} } } }
1342
1377
 
1343
- {
1344
- let p = MQTTBase.prototype;
1345
- Object.assign(p,{
1346
- MQTTError
1347
- , pub: p.publish
1348
- , sub: p.subscribe
1349
- , unsub: p.unsubscribe
1350
- , sub_topic: p.subscribe_topic
1351
- , unsub_topic: p.unsubscribe_topic
1352
- , shared_sub: p.shared_subscribe
1353
- , shared_unsub: p.shared_unsubscribe} );
1354
1378
 
1355
- /*
1356
- p.on_mqtt_type = {
1357
- mqtt_auth(pkt, ctx) ::
1358
- mqtt_connect(pkt, ctx) ::
1359
- mqtt_connack(pkt, ctx) ::
1360
- mqtt_disconnect(pkt, ctx) ::
1361
-
1362
- mqtt_publish(pkt, ctx)
1363
- mqtt_subscribe(pkt, ctx) ::
1364
- mqtt_unsubscribe(pkt, ctx) ::
1365
-
1366
- mqtt_pingreq(pkt, ctx) ::
1367
- mqtt_pingresp(pkt, ctx) ::
1368
- }
1369
- */}
1379
+ /*
1380
+ on_mqtt_type = {
1381
+ mqtt_auth(pkt, ctx) ::
1382
+ mqtt_connect(pkt, ctx) ::
1383
+ mqtt_connack(pkt, ctx) ::
1384
+ mqtt_disconnect(pkt, ctx) ::
1385
+
1386
+ mqtt_publish(pkt, ctx)
1387
+ mqtt_subscribe(pkt, ctx) ::
1388
+ mqtt_unsubscribe(pkt, ctx) ::
1389
+
1390
+ mqtt_pingreq(pkt, ctx) ::
1391
+ mqtt_pingresp(pkt, ctx) ::
1392
+ }
1393
+ */
1370
1394
 
1371
1395
 
1372
- function _as_topics(pkt, ex) {
1373
- if ('string' === typeof pkt) {
1374
- return {topics:[pkt], ... ex}}
1375
- if (pkt[Symbol.iterator]) {
1376
- return {topics:[... pkt], ... ex}}
1377
- return ex ? {...pkt, ...ex} : pkt}
1396
+ const _prefix_topics = (topic_prefix, iterable) =>
1397
+ Array.from(iterable, value =>(
1398
+ value.trim // string
1399
+ ? _prefix_topics(topic_prefix, value)
1400
+ : topic_prefix + value) );
1401
+
1402
+ function _as_topics(pkt, ex, topic_prefix) {
1403
+ if (ex?.trim) {// string
1404
+ topic_prefix = ex;
1405
+ ex = null;}
1406
+
1407
+ pkt =(
1408
+ pkt.trim // string
1409
+ ? {topics:[pkt], ... ex}
1410
+ : pkt[Symbol.iterator]
1411
+ ? {topics:[... pkt], ... ex}
1412
+ : ex ? {...pkt, ...ex}
1413
+ : pkt);
1414
+
1415
+ if (topic_prefix) {
1416
+ // particularly useful with shared queues, e.g.
1417
+ // topic_prefix = '$share/some-queue-name/'
1418
+ pkt.topics = _prefix_topics(topic_prefix, pkt.topics);}
1419
+ return pkt}
1378
1420
 
1379
1421
 
1380
1422
  async function _pub(self, pkt, pub_opt) {
@@ -1490,53 +1532,53 @@ class MQTTCore extends MQTTBase {
1490
1532
 
1491
1533
 
1492
1534
 
1493
- with_tcp(...opt) {
1494
- opt = this._conn_opt(opt);
1495
- opt.transport = 'tcp';
1496
- return this._use_conn (() =>
1497
- this.with_deno_iter(
1498
- Deno.connect(opt)) ) }
1499
-
1500
- with_tls(...opt) {
1501
- opt = this._conn_opt(opt);
1502
- return this._use_conn (() =>
1503
- this.with_deno_iter(
1504
- Deno.connectTls(opt)) ) }
1505
-
1506
- with_deno_iter(conn) {
1507
- return this.with_async_iter(
1508
- conn.then(Deno.iter),
1509
- async u8_pkt =>
1510
- (await conn).write(u8_pkt)) }
1511
-
1512
- _conn_opt([a0, a1, a2]) {
1513
- // (port, hostname, options) or (url, options)
1514
- if (Number.isFinite(a0)) {
1515
- return {...a2, port: a0, hostname: a1}}
1516
-
1517
- a0 = new URL(a0);
1518
- return {...a1, port: a0.port, hostname: a0.hostname}}
1519
-
1520
-
1521
-
1522
-
1523
-
1524
-
1525
-
1526
-
1527
-
1528
-
1529
-
1530
-
1531
-
1532
-
1535
+ with_tcp(...opt) {
1536
+ opt = this._conn_opt(opt);
1537
+ opt.transport = 'tcp';
1538
+ return this._use_conn (() =>
1539
+ this.with_deno_iter(
1540
+ Deno.connect(opt)) ) }
1533
1541
 
1542
+ with_tls(...opt) {
1543
+ opt = this._conn_opt(opt);
1544
+ return this._use_conn (() =>
1545
+ this.with_deno_iter(
1546
+ Deno.connectTls(opt)) ) }
1534
1547
 
1548
+ with_deno_iter(conn) {
1549
+ return this.with_async_iter(
1550
+ conn.then(Deno.iter),
1551
+ async u8_pkt =>
1552
+ (await conn).write(u8_pkt)) }
1535
1553
 
1554
+ _conn_opt([a0, a1, a2]) {
1555
+ // (port, hostname, options) or (url, options)
1556
+ if (Number.isFinite(a0)) {
1557
+ return {...a2, port: a0, hostname: a1}}
1536
1558
 
1559
+ a0 = new URL(a0);
1560
+ return {...a1, port: a0.port, hostname: a0.hostname}}
1537
1561
 
1562
+
1563
+
1564
+
1565
+
1566
+
1567
+
1568
+
1538
1569
 
1570
+
1571
+
1572
+
1573
+
1574
+
1539
1575
 
1576
+
1577
+
1578
+
1579
+
1580
+
1581
+
1540
1582
 
1541
1583
 
1542
1584
  with_stream(read_stream, write_stream) {
@@ -1582,13 +1624,15 @@ class MQTTCore extends MQTTBase {
1582
1624
 
1583
1625
  return this} }
1584
1626
 
1585
- const version = '0.3.2-0';
1627
+ const version = '0.4.1';
1586
1628
 
1587
1629
  const MQTTClient_v4 = /* #__PURE__ */
1588
- MQTTCore.mqtt_ctx(4, mqtt_opts_v5);
1630
+ with_topic_path_router(
1631
+ MQTTCore.mqtt_ctx(4, mqtt_opts_v5) );
1589
1632
 
1590
1633
  const MQTTClient_v5 = /* #__PURE__ */
1591
- MQTTCore.mqtt_ctx(5, mqtt_opts_v5);
1634
+ with_topic_path_router(
1635
+ MQTTCore.mqtt_ctx(5, mqtt_opts_v5) );
1592
1636
 
1593
1637
  const mqtt_v4 = opt =>
1594
1638
  new MQTTClient_v4(opt);