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/cjs/v5.cjs CHANGED
@@ -776,6 +776,191 @@ const mqtt_opts_v5 =
776
776
  encode_fns: mqtt_encode_v5,
777
777
  mqtt_writer: mqtt_writer_v5, };
778
778
 
779
+ function parse(str, loose) {
780
+ if (str instanceof RegExp) return { keys:false, pattern:str };
781
+ var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
782
+ arr[0] || arr.shift();
783
+
784
+ while (tmp = arr.shift()) {
785
+ c = tmp[0];
786
+ if (c === '*') {
787
+ keys.push('wild');
788
+ pattern += '/(.*)';
789
+ } else if (c === ':') {
790
+ o = tmp.indexOf('?', 1);
791
+ ext = tmp.indexOf('.', 1);
792
+ keys.push( tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length) );
793
+ pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';
794
+ if (!!~ext) pattern += (!!~o ? '?' : '') + '\\' + tmp.substring(ext);
795
+ } else {
796
+ pattern += '/' + tmp;
797
+ }
798
+ }
799
+
800
+ return {
801
+ keys: keys,
802
+ pattern: new RegExp('^' + pattern + (loose ? '(?=$|\/)' : '\/?$'), 'i')
803
+ };
804
+ }
805
+
806
+ /*
807
+ class AbstractTopicRouter ::
808
+ async invoke(pkt, ctx) ::
809
+ add(topic_route, ...args) ::
810
+ remove(topic_route, priority) ::
811
+ clear(priority) ::
812
+ find(topic) :: // optional
813
+ mqtt_topic(topic_route)
814
+ */
815
+
816
+ const with_topic_router = mqtt_topic_router =>
817
+ MQTTKlass => class extends MQTTKlass {
818
+ static _aliases() {
819
+ return super._aliases() +
820
+ ' sub_topic:subscribe_topic unsub_topic:unsubscribe_topic'}
821
+
822
+ _init_router(opt) {
823
+ return mqtt_topic_router(opt, this)}
824
+
825
+ get on_topic() {return this.router.add}
826
+
827
+ _sub_chain(topic, ex, topic_prefix) {
828
+ let res = this.subscribe([[ topic ]], ex, topic_prefix);
829
+ let subs = this.subs ||(this.subs = new Map());
830
+ subs.set((res.topic = topic), (subs.last = res));
831
+ return this }// fluent api -- return this and track side effects
832
+
833
+ // alias: sub_topic
834
+ subscribe_topic(topic_route, ...args) {
835
+ let router = this.router;
836
+ router.add(topic_route, true, args.pop() );// handler
837
+ let topic = router.mqtt_topic(topic_route);
838
+ return this._sub_chain(topic, ...args ) }// ex, topic_prefix
839
+
840
+ // alias: unsub_topic
841
+ unsubscribe_topic(topic_route, ...args) {
842
+ let router = this.router;
843
+ router.remove(topic_route, true);
844
+ let topic = router.mqtt_topic(topic_route);
845
+ return this.unsubscribe([[ topic ]], ...args ) } };// topic_prefix
846
+
847
+ // Use [regexparam][] for url-like topic parsing
848
+ // [regexparam]: https://github.com/lukeed/regexparam
849
+
850
+
851
+ const with_topic_path_router = /* #__PURE__ */
852
+ with_topic_router(mqtt_topic_path_router);
853
+
854
+
855
+ const mqtt_topic = topic_route =>
856
+ topic_route
857
+ .replace(/[*].*$/, '#')
858
+ .replace(/:\w+\??/g, '+');
859
+
860
+ const as_topic_path = topic_route =>(
861
+ topic_route
862
+ .replace(/#$/, '*') // replace MQTT # wildcard at end
863
+ .split(/([^\/]*[+][^\/]*)/) // split on MQTT + match tokens
864
+ .reduce (( sz, v, idx ) => sz +(
865
+ idx & 1 // even entires are body, odd are MQTT + tokens
866
+ ? `:$${1 + idx>>1}` // replace with `:$#` sequential ids, using ? for partial entries
867
+ : v ) ) );// pass through body
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
+
779
964
  /*
780
965
  export function decode_varint_loop(u8, i=0) {
781
966
  let i0 = i
@@ -957,138 +1142,13 @@ function _ping_interval(send_ping) {
957
1142
  if (td) {
958
1143
  tid = setInterval(send_ping, 1000 * td);
959
1144
 
960
-
961
-
1145
+
1146
+
962
1147
 
963
- // ensure the interval allows the NodeJS event loop to exit
964
- tid.unref?.();
1148
+ // ensure the interval allows the NodeJS event loop to exit
1149
+ tid.unref?.();
965
1150
  return true} }) }
966
1151
 
967
- function parse(str, loose) {
968
- if (str instanceof RegExp) return { keys:false, pattern:str };
969
- var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
970
- arr[0] || arr.shift();
971
-
972
- while (tmp = arr.shift()) {
973
- c = tmp[0];
974
- if (c === '*') {
975
- keys.push('wild');
976
- pattern += '/(.*)';
977
- } else if (c === ':') {
978
- o = tmp.indexOf('?', 1);
979
- ext = tmp.indexOf('.', 1);
980
- keys.push( tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length) );
981
- pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';
982
- if (!!~ext) pattern += (!!~o ? '?' : '') + '\\' + tmp.substring(ext);
983
- } else {
984
- pattern += '/' + tmp;
985
- }
986
- }
987
-
988
- return {
989
- keys: keys,
990
- pattern: new RegExp('^' + pattern + (loose ? '(?=$|\/)' : '\/?$'), 'i')
991
- };
992
- }
993
-
994
- // Use [regexparam][] for url-like topic parsing
995
-
996
- function _ignore(pkt, params, ctx) {ctx.done = true;}
997
-
998
- function _mqtt_topic_router() {
999
- let pri_lsts = [[],[]], rm = Symbol();
1000
- let find = topic => _mqtt_routes_iter(pri_lsts, topic);
1001
-
1002
- return {find,
1003
-
1004
- add(topic_route, ...args) {
1005
- let fn = args.pop();
1006
- let priority = args.pop();
1007
-
1008
- if ('function' !== typeof fn) {
1009
- if (false === fn) {
1010
- fn = _ignore;}
1011
- else throw new TypeError()}
1012
-
1013
- let rte = parse(
1014
- topic_route.replace(/[+#]$/, '*'));
1015
-
1016
- rte.key = topic_route;
1017
- rte.tgt = fn;
1018
- pri_lsts[priority ? 0 : 1].push(rte);
1019
- return this}
1020
-
1021
- , remove(topic_route, priority) {
1022
- let lst = pri_lsts[priority ? 0 : 1];
1023
- return _mqtt_route_remove([lst], topic_route)}
1024
-
1025
- , clear(priority) {
1026
- pri_lsts[priority ? 0 : 1] = [];
1027
- if (null == priority) {
1028
- pri_lsts[1] = [];} }
1029
-
1030
- , async invoke(pkt, ctx) {
1031
- ctx.idx = 0;
1032
- ctx.rm = rm;
1033
-
1034
- for (let [fn, params] of find(pkt.topic)) {
1035
- let res = await fn(pkt, params, ctx);
1036
-
1037
- if (rm === res) {
1038
- _mqtt_route_remove(pri_lsts, fn);}
1039
-
1040
- if (ctx.done) {
1041
- break}
1042
- else ctx.idx++;}
1043
-
1044
- let {pkt_id, qos} = pkt;
1045
- if (1 === qos) {
1046
- await ctx.mqtt._send('puback', {pkt_id});} } } }
1047
-
1048
-
1049
- function * _mqtt_routes_iter(all_route_lists, topic) {
1050
- for (let route_list of all_route_lists) {
1051
- for (let route of route_list) {
1052
- let res = _mqtt_route_match_one(topic, route);
1053
- if (undefined !== res) {
1054
- yield res;} } } }
1055
-
1056
-
1057
- function _mqtt_route_match_one(topic, {keys, pattern, tgt}) {
1058
- let match = '/' !== topic[0]
1059
- ? pattern.exec('/'+topic)
1060
- : pattern.exec(topic);
1061
-
1062
- if (null === match) {
1063
- return}
1064
-
1065
- if (false === keys) {
1066
- let {groups} = match;
1067
- if (! groups) {
1068
- return [tgt]}
1069
-
1070
- let params = {};
1071
- for (let k in groups) {
1072
- params[k] = groups[k];}
1073
-
1074
- return [tgt, params]}
1075
-
1076
- if (0 === keys.length) {
1077
- return [tgt]}
1078
-
1079
- let params = {};
1080
- for (let i=0; i<keys.length; i++) {
1081
- params[ keys[i] ] = match[1+i];}
1082
- return [tgt, params]}
1083
-
1084
-
1085
- function _mqtt_route_remove(all_route_lists, query) {
1086
- let match = route => route===query || route.tgt===query || route.key===query;
1087
- for (let lst of all_route_lists) {
1088
- let i = lst.findIndex(match);
1089
- if (0 <= i) {return !! lst.splice(i,1)} }
1090
- return false}
1091
-
1092
1152
  const _mqtt_cmdid_dispatch ={
1093
1153
  create(target) {
1094
1154
  return {__proto__: this, target, hashbelt: [new Map()]} }
@@ -1157,8 +1217,7 @@ const _mqtt_cmdid_dispatch ={
1157
1217
  let fn = target[`mqtt_${pkt.type}`]
1158
1218
  || target.mqtt_pkt;
1159
1219
 
1160
- if (undefined !== fn) {
1161
- await fn.call(target, pkt, ctx);} } })()) };
1220
+ await fn?.call(target, pkt, ctx);} })()) };
1162
1221
 
1163
1222
  function _mqtt_dispatch(opt, target) {
1164
1223
  let _disp_ = _mqtt_cmdid_dispatch.create(target);
@@ -1239,53 +1298,15 @@ class MQTTBase {
1239
1298
 
1240
1299
 
1241
1300
  // alias: sub
1242
- subscribe(pkt, ex) {
1243
- pkt = _as_topics(pkt, ex);
1301
+ subscribe(pkt, ex, topic_prefix) {
1302
+ pkt = _as_topics(pkt, ex, topic_prefix);
1244
1303
  return this._send('subscribe', pkt, pkt)}
1245
- _sub_chain(topic, ex) {
1246
- let res = this.subscribe([[ topic ]], ex);
1247
- let subs = this.subs ||(this.subs = new Map());
1248
- subs.set((res.topic = topic), (subs.last = res));
1249
- return this }// fluent api -- return this and track side effects
1250
1304
 
1251
1305
  // alias: unsub
1252
- unsubscribe(pkt, ex) {
1253
- pkt = _as_topics(pkt, ex);
1306
+ unsubscribe(pkt, ex, topic_prefix) {
1307
+ pkt = _as_topics(pkt, ex, topic_prefix);
1254
1308
  return this._send('unsubscribe', pkt, pkt)}
1255
1309
 
1256
- get on_topic() {return this.router.add}
1257
-
1258
- // alias: sub_topic
1259
- subscribe_topic(topic_route, ...args) {
1260
- this.router.add(topic_route, true, args.pop() );// handler
1261
- let topic = this.topic_for(topic_route);
1262
- return this._sub_chain(topic, args.pop() ) }// ex
1263
-
1264
- // alias: unsub_topic
1265
- unsubscribe_topic(topic_route) {
1266
- this.router.remove(topic_route, true);
1267
- let topic = this.topic_for(topic_route);
1268
- return this.unsubscribe([[ topic ]]) }
1269
-
1270
- // alias: shared_sub
1271
- shared_subscribe(group, topic_route, ...args) {
1272
- this.router.add(topic_route, true, args.pop() );// handler
1273
- let topic = this.topic_for(topic_route);
1274
- if (null != group) {
1275
- topic = `$share/${group}/${topic}`;}
1276
- return this._sub_chain(topic, args.pop() ) }// ex
1277
-
1278
- // alias: shared_unsub
1279
- shared_unsubscribe(group, topic_route) {
1280
- this.router.remove(topic_route, true);
1281
- let topic = this.topic_for(topic_route);
1282
- if (null != group) {
1283
- topic = `$share/${group}/${topic}`;}
1284
- return this.unsubscribe([[ topic ]]) }
1285
-
1286
- topic_for(topic_route) {
1287
- return topic_route.replace(/[:*].*$/, '#')}
1288
-
1289
1310
 
1290
1311
  // alias: pub
1291
1312
  publish(pkt, pub_opt) {return _pub(this, pkt, pub_opt)}
@@ -1311,9 +1332,9 @@ class MQTTBase {
1311
1332
  if (undefined === cid) {
1312
1333
  this.client_id = cid = (
1313
1334
 
1314
-
1335
+
1315
1336
 
1316
- this.new_client_id(parts)
1337
+ this.new_client_id(parts)
1317
1338
  );}
1318
1339
 
1319
1340
  return cid}
@@ -1322,66 +1343,85 @@ class MQTTBase {
1322
1343
  return [parts[0], Math.random().toString(36).slice(2), parts[1]].join('')}
1323
1344
 
1324
1345
 
1325
-
1326
-
1327
-
1328
-
1329
-
1330
-
1331
-
1346
+
1347
+
1348
+
1349
+
1350
+
1351
+
1352
+
1332
1353
 
1333
1354
 
1334
1355
  // Internal API
1335
1356
 
1336
1357
  /* async _send(type, pkt) -- provided by _conn_ and transport */
1337
1358
 
1338
- _init_router(opt) {
1339
- return this.router = _mqtt_topic_router()}
1340
-
1341
1359
  _init_dispatch(opt) {
1360
+ this.constructor?._once_();
1361
+ let router = this.router =
1362
+ this._init_router?.(opt, this);
1363
+
1342
1364
  let tgt ={
1343
1365
  __proto__: opt.on_mqtt_type || {}
1344
- , router: this._init_router(opt, this)};
1366
+ , router};
1345
1367
 
1346
- tgt.mqtt_publish ||= tgt.router.invoke;
1347
- return _mqtt_dispatch(this, tgt)} }
1368
+ tgt.mqtt_publish ||= router?.invoke;
1369
+ return _mqtt_dispatch(this, tgt)}
1348
1370
 
1371
+ static _aliases() {
1372
+ return ' pub:publish sub:subscribe unsub:unsubscribe '}
1349
1373
 
1350
- {
1351
- let p = MQTTBase.prototype;
1352
- Object.assign(p,{
1353
- MQTTError
1354
- , pub: p.publish
1355
- , sub: p.subscribe
1356
- , unsub: p.unsubscribe
1357
- , sub_topic: p.subscribe_topic
1358
- , unsub_topic: p.unsubscribe_topic
1359
- , shared_sub: p.shared_subscribe
1360
- , shared_unsub: p.shared_unsubscribe} );
1374
+ static _once_(self=this) {
1375
+ self._once_ = _=>0;
1376
+ self.MQTTError = MQTTError;
1377
+ let p = self.prototype;
1378
+ for (let alias of self._aliases().split(/\s+/)) {
1379
+ alias = alias.split(':');
1380
+ let fn = alias[1] && p[alias[1]];
1381
+ if (fn) {p[alias[0]] = fn;} } } }
1361
1382
 
1362
- /*
1363
- p.on_mqtt_type = {
1364
- mqtt_auth(pkt, ctx) ::
1365
- mqtt_connect(pkt, ctx) ::
1366
- mqtt_connack(pkt, ctx) ::
1367
- mqtt_disconnect(pkt, ctx) ::
1368
-
1369
- mqtt_publish(pkt, ctx)
1370
- mqtt_subscribe(pkt, ctx) ::
1371
- mqtt_unsubscribe(pkt, ctx) ::
1372
-
1373
- mqtt_pingreq(pkt, ctx) ::
1374
- mqtt_pingresp(pkt, ctx) ::
1375
- }
1376
- */}
1383
+
1384
+ /*
1385
+ on_mqtt_type = {
1386
+ mqtt_auth(pkt, ctx) ::
1387
+ mqtt_connect(pkt, ctx) ::
1388
+ mqtt_connack(pkt, ctx) ::
1389
+ mqtt_disconnect(pkt, ctx) ::
1390
+
1391
+ mqtt_publish(pkt, ctx)
1392
+ mqtt_subscribe(pkt, ctx) ::
1393
+ mqtt_unsubscribe(pkt, ctx) ::
1394
+
1395
+ mqtt_pingreq(pkt, ctx) ::
1396
+ mqtt_pingresp(pkt, ctx) ::
1397
+ }
1398
+ */
1377
1399
 
1378
1400
 
1379
- function _as_topics(pkt, ex) {
1380
- if ('string' === typeof pkt) {
1381
- return {topics:[pkt], ... ex}}
1382
- if (pkt[Symbol.iterator]) {
1383
- return {topics:[... pkt], ... ex}}
1384
- return ex ? {...pkt, ...ex} : pkt}
1401
+ const _prefix_topics = (topic_prefix, iterable) =>
1402
+ Array.from(iterable, value =>(
1403
+ value.trim // string
1404
+ ? _prefix_topics(topic_prefix, value)
1405
+ : topic_prefix + value) );
1406
+
1407
+ function _as_topics(pkt, ex, topic_prefix) {
1408
+ if (ex?.trim) {// string
1409
+ topic_prefix = ex;
1410
+ ex = null;}
1411
+
1412
+ pkt =(
1413
+ pkt.trim // string
1414
+ ? {topics:[pkt], ... ex}
1415
+ : pkt[Symbol.iterator]
1416
+ ? {topics:[... pkt], ... ex}
1417
+ : ex ? {...pkt, ...ex}
1418
+ : pkt);
1419
+
1420
+ if (topic_prefix) {
1421
+ // particularly useful with shared queues, e.g.
1422
+ // topic_prefix = '$share/some-queue-name/'
1423
+ pkt.topics = _prefix_topics(topic_prefix, pkt.topics);}
1424
+ return pkt}
1385
1425
 
1386
1426
 
1387
1427
  async function _pub(self, pkt, pub_opt) {
@@ -1497,53 +1537,53 @@ class MQTTCore extends MQTTBase {
1497
1537
 
1498
1538
 
1499
1539
 
1540
+
1541
+
1542
+
1543
+
1544
+
1545
+
1500
1546
 
1547
+
1548
+
1549
+
1550
+
1551
+
1501
1552
 
1553
+
1554
+
1555
+
1556
+
1557
+
1502
1558
 
1559
+
1560
+
1561
+
1562
+
1503
1563
 
1564
+
1565
+
1504
1566
 
1567
+
1568
+ with_tcp(...opt) {
1569
+ opt = this._conn_opt(opt);
1570
+ console.log({opt});
1571
+ return this._use_conn (() =>
1572
+ this.with_stream(
1573
+ node_net.connect(opt)) ) }
1505
1574
 
1575
+ with_tls(...opt) {
1576
+ opt = this._conn_opt(opt);
1577
+ return this._use_conn (() =>
1578
+ this.with_stream(
1579
+ node_tls.connect(opt)) ) }
1506
1580
 
1507
-
1508
-
1509
-
1510
-
1511
-
1512
-
1513
-
1514
-
1515
-
1516
-
1517
-
1518
-
1519
-
1520
-
1521
-
1522
-
1523
-
1524
-
1525
-
1526
-
1527
-
1528
- with_tcp(...opt) {
1529
- opt = this._conn_opt(opt);
1530
- console.log({opt});
1531
- return this._use_conn (() =>
1532
- this.with_stream(
1533
- node_net.connect(opt)) ) }
1534
-
1535
- with_tls(...opt) {
1536
- opt = this._conn_opt(opt);
1537
- return this._use_conn (() =>
1538
- this.with_stream(
1539
- node_tls.connect(opt)) ) }
1540
-
1541
- _conn_opt([a0, a1, a2]) {
1542
- // (port, hostname, options) or (url, options)
1543
- if (Number.isFinite(a0)) {
1544
- return {...a2, port: a0, host: a1}}
1545
- a0 = new URL(a0);
1546
- return {...a1, port: a0.port, host: a0.hostname}}
1581
+ _conn_opt([a0, a1, a2]) {
1582
+ // (port, hostname, options) or (url, options)
1583
+ if (Number.isFinite(a0)) {
1584
+ return {...a2, port: a0, host: a1}}
1585
+ a0 = new URL(a0);
1586
+ return {...a1, port: a0.port, host: a0.hostname}}
1547
1587
 
1548
1588
 
1549
1589
  with_stream(read_stream, write_stream) {
@@ -1589,13 +1629,15 @@ class MQTTCore extends MQTTBase {
1589
1629
 
1590
1630
  return this} }
1591
1631
 
1592
- const version = '0.3.2-0';
1632
+ const version = '0.4.0';
1593
1633
 
1594
1634
  const MQTTClient_v4 = /* #__PURE__ */
1595
- MQTTCore.mqtt_ctx(4, mqtt_opts_v5);
1635
+ with_topic_path_router(
1636
+ MQTTCore.mqtt_ctx(4, mqtt_opts_v5) );
1596
1637
 
1597
1638
  const MQTTClient_v5 = /* #__PURE__ */
1598
- MQTTCore.mqtt_ctx(5, mqtt_opts_v5);
1639
+ with_topic_path_router(
1640
+ MQTTCore.mqtt_ctx(5, mqtt_opts_v5) );
1599
1641
 
1600
1642
  const mqtt_v4 = opt =>
1601
1643
  new MQTTClient_v4(opt);