u8-mqtt 0.3.1 → 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 (78) 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 +312 -247
  7. package/cjs/index.cjs.map +1 -1
  8. package/cjs/v4.cjs +307 -242
  9. package/cjs/v4.cjs.map +1 -1
  10. package/cjs/v5.cjs +309 -243
  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/{v4.mjs → basic-v4.js} +1 -1
  15. package/code/{v5.mjs → basic-v5.js} +1 -1
  16. package/code/core.jsy +41 -15
  17. package/code/{index.mjs → index.js} +3 -2
  18. package/code/{_router.jsy → router_path.jsy} +30 -12
  19. package/code/v4.js +20 -0
  20. package/code/v5.js +29 -0
  21. package/code/version.js +1 -0
  22. package/code/with_topic_router.jsy +41 -0
  23. package/esm/deno/basic-v4.js +1193 -0
  24. package/esm/deno/basic-v4.js.map +1 -0
  25. package/esm/deno/basic-v5.js +1455 -0
  26. package/esm/deno/basic-v5.js.map +1 -0
  27. package/esm/deno/index.js +307 -242
  28. package/esm/deno/index.js.map +1 -1
  29. package/esm/deno/v4.js +304 -240
  30. package/esm/deno/v4.js.map +1 -1
  31. package/esm/deno/v5.js +306 -241
  32. package/esm/deno/v5.js.map +1 -1
  33. package/esm/node/basic-v4.js +1196 -0
  34. package/esm/node/basic-v4.js.map +1 -0
  35. package/esm/node/basic-v4.mjs +1196 -0
  36. package/esm/node/basic-v4.mjs.map +1 -0
  37. package/esm/node/basic-v5.js +1458 -0
  38. package/esm/node/basic-v5.js.map +1 -0
  39. package/esm/node/basic-v5.mjs +1458 -0
  40. package/esm/node/basic-v5.mjs.map +1 -0
  41. package/esm/node/index.js +309 -243
  42. package/esm/node/index.js.map +1 -1
  43. package/esm/node/index.mjs +309 -243
  44. package/esm/node/index.mjs.map +1 -1
  45. package/esm/node/v4.js +306 -241
  46. package/esm/node/v4.js.map +1 -1
  47. package/esm/node/v4.mjs +306 -241
  48. package/esm/node/v4.mjs.map +1 -1
  49. package/esm/node/v5.js +308 -242
  50. package/esm/node/v5.js.map +1 -1
  51. package/esm/node/v5.mjs +308 -242
  52. package/esm/node/v5.mjs.map +1 -1
  53. package/esm/web/basic-v4.js +1193 -0
  54. package/esm/web/basic-v4.js.map +1 -0
  55. package/esm/web/basic-v4.min.js +1 -0
  56. package/esm/web/basic-v4.min.js.br +0 -0
  57. package/esm/web/basic-v4.min.js.gz +0 -0
  58. package/esm/web/basic-v5.js +1455 -0
  59. package/esm/web/basic-v5.js.map +1 -0
  60. package/esm/web/basic-v5.min.js +1 -0
  61. package/esm/web/basic-v5.min.js.br +0 -0
  62. package/esm/web/basic-v5.min.js.gz +0 -0
  63. package/esm/web/index.js +307 -242
  64. package/esm/web/index.js.map +1 -1
  65. package/esm/web/index.min.js +1 -1
  66. package/esm/web/index.min.js.br +0 -0
  67. package/esm/web/index.min.js.gz +0 -0
  68. package/esm/web/v4.js +305 -241
  69. package/esm/web/v4.js.map +1 -1
  70. package/esm/web/v4.min.js +1 -1
  71. package/esm/web/v4.min.js.br +0 -0
  72. package/esm/web/v4.min.js.gz +0 -0
  73. package/esm/web/v5.js +306 -241
  74. package/esm/web/v5.js.map +1 -1
  75. package/esm/web/v5.min.js +1 -1
  76. package/esm/web/v5.min.js.br +0 -0
  77. package/esm/web/v5.min.js.gz +0 -0
  78. package/package.json +7 -7
package/cjs/index.cjs CHANGED
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var node_net = require('node:net');
6
+ var node_tls = require('node:tls');
6
7
 
7
8
  function encode_varint(n, a=[]) {
8
9
  do {
@@ -775,6 +776,191 @@ const mqtt_opts_v5 =
775
776
  encode_fns: mqtt_encode_v5,
776
777
  mqtt_writer: mqtt_writer_v5, };
777
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
+
778
964
  /*
779
965
  export function decode_varint_loop(u8, i=0) {
780
966
  let i0 = i
@@ -873,8 +1059,6 @@ function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
873
1059
  }
874
1060
  }
875
1061
 
876
- Object.freeze({ao_done: true});
877
-
878
1062
  function ao_defer_ctx(as_res = (...args) => args) {
879
1063
  let y,n,_pset = (a,b) => { y=a, n=b; };
880
1064
  return p =>(
@@ -958,138 +1142,13 @@ function _ping_interval(send_ping) {
958
1142
  if (td) {
959
1143
  tid = setInterval(send_ping, 1000 * td);
960
1144
 
961
-
962
-
1145
+
1146
+
963
1147
 
964
- // ensure the interval allows the NodeJS event loop to exit
965
- tid.unref?.();
1148
+ // ensure the interval allows the NodeJS event loop to exit
1149
+ tid.unref?.();
966
1150
  return true} }) }
967
1151
 
968
- function parse(str, loose) {
969
- if (str instanceof RegExp) return { keys:false, pattern:str };
970
- var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
971
- arr[0] || arr.shift();
972
-
973
- while (tmp = arr.shift()) {
974
- c = tmp[0];
975
- if (c === '*') {
976
- keys.push('wild');
977
- pattern += '/(.*)';
978
- } else if (c === ':') {
979
- o = tmp.indexOf('?', 1);
980
- ext = tmp.indexOf('.', 1);
981
- keys.push( tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length) );
982
- pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';
983
- if (!!~ext) pattern += (!!~o ? '?' : '') + '\\' + tmp.substring(ext);
984
- } else {
985
- pattern += '/' + tmp;
986
- }
987
- }
988
-
989
- return {
990
- keys: keys,
991
- pattern: new RegExp('^' + pattern + (loose ? '(?=$|\/)' : '\/?$'), 'i')
992
- };
993
- }
994
-
995
- // Use [regexparam][] for url-like topic parsing
996
-
997
- function _ignore(pkt, params, ctx) {ctx.done = true;}
998
-
999
- function _mqtt_topic_router() {
1000
- let pri_lsts = [[],[]], rm = Symbol();
1001
- let find = topic => _mqtt_routes_iter(pri_lsts, topic);
1002
-
1003
- return {find,
1004
-
1005
- add(topic_route, ...args) {
1006
- let fn = args.pop();
1007
- let priority = args.pop();
1008
-
1009
- if ('function' !== typeof fn) {
1010
- if (false === fn) {
1011
- fn = _ignore;}
1012
- else throw new TypeError()}
1013
-
1014
- let rte = parse(
1015
- topic_route.replace(/[+#]$/, '*'));
1016
-
1017
- rte.key = topic_route;
1018
- rte.tgt = fn;
1019
- pri_lsts[priority ? 0 : 1].push(rte);
1020
- return this}
1021
-
1022
- , remove(topic_route, priority) {
1023
- let lst = pri_lsts[priority ? 0 : 1];
1024
- return _mqtt_route_remove([lst], topic_route)}
1025
-
1026
- , clear(priority) {
1027
- pri_lsts[priority ? 0 : 1] = [];
1028
- if (null == priority) {
1029
- pri_lsts[1] = [];} }
1030
-
1031
- , async invoke(pkt, ctx) {
1032
- ctx.idx = 0;
1033
- ctx.rm = rm;
1034
-
1035
- for (let [fn, params] of find(pkt.topic)) {
1036
- let res = await fn(pkt, params, ctx);
1037
-
1038
- if (rm === res) {
1039
- _mqtt_route_remove(pri_lsts, fn);}
1040
-
1041
- if (ctx.done) {
1042
- break}
1043
- else ctx.idx++;}
1044
-
1045
- let {pkt_id, qos} = pkt;
1046
- if (1 === qos) {
1047
- await ctx.mqtt._send('puback', {pkt_id});} } } }
1048
-
1049
-
1050
- function * _mqtt_routes_iter(all_route_lists, topic) {
1051
- for (let route_list of all_route_lists) {
1052
- for (let route of route_list) {
1053
- let res = _mqtt_route_match_one(topic, route);
1054
- if (undefined !== res) {
1055
- yield res;} } } }
1056
-
1057
-
1058
- function _mqtt_route_match_one(topic, {keys, pattern, tgt}) {
1059
- let match = '/' !== topic[0]
1060
- ? pattern.exec('/'+topic)
1061
- : pattern.exec(topic);
1062
-
1063
- if (null === match) {
1064
- return}
1065
-
1066
- if (false === keys) {
1067
- let {groups} = match;
1068
- if (! groups) {
1069
- return [tgt]}
1070
-
1071
- let params = {};
1072
- for (let k in groups) {
1073
- params[k] = groups[k];}
1074
-
1075
- return [tgt, params]}
1076
-
1077
- if (0 === keys.length) {
1078
- return [tgt]}
1079
-
1080
- let params = {};
1081
- for (let i=0; i<keys.length; i++) {
1082
- params[ keys[i] ] = match[1+i];}
1083
- return [tgt, params]}
1084
-
1085
-
1086
- function _mqtt_route_remove(all_route_lists, query) {
1087
- let match = route => route===query || route.tgt===query || route.key===query;
1088
- for (let lst of all_route_lists) {
1089
- let i = lst.findIndex(match);
1090
- if (0 <= i) {return !! lst.splice(i,1)} }
1091
- return false}
1092
-
1093
1152
  const _mqtt_cmdid_dispatch ={
1094
1153
  create(target) {
1095
1154
  return {__proto__: this, target, hashbelt: [new Map()]} }
@@ -1158,8 +1217,7 @@ const _mqtt_cmdid_dispatch ={
1158
1217
  let fn = target[`mqtt_${pkt.type}`]
1159
1218
  || target.mqtt_pkt;
1160
1219
 
1161
- if (undefined !== fn) {
1162
- await fn.call(target, pkt, ctx);} } })()) };
1220
+ await fn?.call(target, pkt, ctx);} })()) };
1163
1221
 
1164
1222
  function _mqtt_dispatch(opt, target) {
1165
1223
  let _disp_ = _mqtt_cmdid_dispatch.create(target);
@@ -1240,53 +1298,15 @@ class MQTTBase {
1240
1298
 
1241
1299
 
1242
1300
  // alias: sub
1243
- subscribe(pkt, ex) {
1244
- pkt = _as_topics(pkt, ex);
1301
+ subscribe(pkt, ex, topic_prefix) {
1302
+ pkt = _as_topics(pkt, ex, topic_prefix);
1245
1303
  return this._send('subscribe', pkt, pkt)}
1246
- _sub_chain(topic, ex) {
1247
- let res = this.subscribe([[ topic ]], ex);
1248
- let subs = this.subs ||(this.subs = new Map());
1249
- subs.set((res.topic = topic), (subs.last = res));
1250
- return this }// fluent api -- return this and track side effects
1251
1304
 
1252
1305
  // alias: unsub
1253
- unsubscribe(pkt, ex) {
1254
- pkt = _as_topics(pkt, ex);
1306
+ unsubscribe(pkt, ex, topic_prefix) {
1307
+ pkt = _as_topics(pkt, ex, topic_prefix);
1255
1308
  return this._send('unsubscribe', pkt, pkt)}
1256
1309
 
1257
- get on_topic() {return this.router.add}
1258
-
1259
- // alias: sub_topic
1260
- subscribe_topic(topic_route, ...args) {
1261
- this.router.add(topic_route, true, args.pop() );// handler
1262
- let topic = this.topic_for(topic_route);
1263
- return this._sub_chain(topic, args.pop() ) }// ex
1264
-
1265
- // alias: unsub_topic
1266
- unsubscribe_topic(topic_route) {
1267
- this.router.remove(topic_route, true);
1268
- let topic = this.topic_for(topic_route);
1269
- return this.unsubscribe([[ topic ]]) }
1270
-
1271
- // alias: shared_sub
1272
- shared_subscribe(group, topic_route, ...args) {
1273
- this.router.add(topic_route, true, args.pop() );// handler
1274
- let topic = this.topic_for(topic_route);
1275
- if (null != group) {
1276
- topic = `$share/${group}/${topic}`;}
1277
- return this._sub_chain(topic, args.pop() ) }// ex
1278
-
1279
- // alias: shared_unsub
1280
- shared_unsubscribe(group, topic_route) {
1281
- this.router.remove(topic_route, true);
1282
- let topic = this.topic_for(topic_route);
1283
- if (null != group) {
1284
- topic = `$share/${group}/${topic}`;}
1285
- return this.unsubscribe([[ topic ]]) }
1286
-
1287
- topic_for(topic_route) {
1288
- return topic_route.replace(/[:*].*$/, '#')}
1289
-
1290
1310
 
1291
1311
  // alias: pub
1292
1312
  publish(pkt, pub_opt) {return _pub(this, pkt, pub_opt)}
@@ -1312,9 +1332,9 @@ class MQTTBase {
1312
1332
  if (undefined === cid) {
1313
1333
  this.client_id = cid = (
1314
1334
 
1315
-
1335
+
1316
1336
 
1317
- this.new_client_id(parts)
1337
+ this.new_client_id(parts)
1318
1338
  );}
1319
1339
 
1320
1340
  return cid}
@@ -1323,66 +1343,85 @@ class MQTTBase {
1323
1343
  return [parts[0], Math.random().toString(36).slice(2), parts[1]].join('')}
1324
1344
 
1325
1345
 
1326
-
1327
-
1328
-
1329
-
1330
-
1331
-
1332
-
1346
+
1347
+
1348
+
1349
+
1350
+
1351
+
1352
+
1333
1353
 
1334
1354
 
1335
1355
  // Internal API
1336
1356
 
1337
1357
  /* async _send(type, pkt) -- provided by _conn_ and transport */
1338
1358
 
1339
- _init_router(opt) {
1340
- return this.router = _mqtt_topic_router()}
1341
-
1342
1359
  _init_dispatch(opt) {
1360
+ this.constructor?._once_();
1361
+ let router = this.router =
1362
+ this._init_router?.(opt, this);
1363
+
1343
1364
  let tgt ={
1344
1365
  __proto__: opt.on_mqtt_type || {}
1345
- , router: this._init_router(opt, this)};
1366
+ , router};
1346
1367
 
1347
- tgt.mqtt_publish ||= tgt.router.invoke;
1348
- return _mqtt_dispatch(this, tgt)} }
1368
+ tgt.mqtt_publish ||= router?.invoke;
1369
+ return _mqtt_dispatch(this, tgt)}
1349
1370
 
1371
+ static _aliases() {
1372
+ return ' pub:publish sub:subscribe unsub:unsubscribe '}
1350
1373
 
1351
- {
1352
- let p = MQTTBase.prototype;
1353
- Object.assign(p,{
1354
- MQTTError
1355
- , pub: p.publish
1356
- , sub: p.subscribe
1357
- , unsub: p.unsubscribe
1358
- , sub_topic: p.subscribe_topic
1359
- , unsub_topic: p.unsubscribe_topic
1360
- , shared_sub: p.shared_subscribe
1361
- , 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;} } } }
1362
1382
 
1363
- /*
1364
- p.on_mqtt_type = {
1365
- mqtt_auth(pkt, ctx) ::
1366
- mqtt_connect(pkt, ctx) ::
1367
- mqtt_connack(pkt, ctx) ::
1368
- mqtt_disconnect(pkt, ctx) ::
1369
-
1370
- mqtt_publish(pkt, ctx)
1371
- mqtt_subscribe(pkt, ctx) ::
1372
- mqtt_unsubscribe(pkt, ctx) ::
1373
-
1374
- mqtt_pingreq(pkt, ctx) ::
1375
- mqtt_pingresp(pkt, ctx) ::
1376
- }
1377
- */}
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
+ */
1378
1399
 
1379
1400
 
1380
- function _as_topics(pkt, ex) {
1381
- if ('string' === typeof pkt) {
1382
- return {topics:[pkt], ... ex}}
1383
- if (pkt[Symbol.iterator]) {
1384
- return {topics:[... pkt], ... ex}}
1385
- 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}
1386
1425
 
1387
1426
 
1388
1427
  async function _pub(self, pkt, pub_opt) {
@@ -1454,7 +1493,7 @@ class MQTTCore extends MQTTBase {
1454
1493
  return this}
1455
1494
 
1456
1495
  //log_conn(evt, arg, err_arg) ::
1457
- //console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
1496
+ // console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
1458
1497
 
1459
1498
  on_live(client, is_reconnect) {
1460
1499
  if (is_reconnect) {
@@ -1496,30 +1535,55 @@ class MQTTCore extends MQTTBase {
1496
1535
  return this}
1497
1536
 
1498
1537
 
1499
-
1500
-
1501
-
1502
-
1503
-
1504
-
1505
-
1506
-
1507
-
1508
-
1509
1538
 
1539
+
1540
+
1541
+
1542
+
1543
+
1544
+
1545
+
1510
1546
 
1547
+
1548
+
1549
+
1550
+
1551
+
1511
1552
 
1553
+
1554
+
1555
+
1556
+
1557
+
1512
1558
 
1559
+
1560
+
1561
+
1562
+
1513
1563
 
1564
+
1565
+
1514
1566
 
1515
1567
 
1516
- with_tcp(port, hostname) {
1517
- if (!Number.isFinite(port)) {
1518
- ({port, hostname} = new URL(port));}
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)) ) }
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)) ) }
1519
1580
 
1520
- return this._use_conn (() =>
1521
- this.with_stream(
1522
- node_net.connect(port, 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}}
1523
1587
 
1524
1588
 
1525
1589
  with_stream(read_stream, write_stream) {
@@ -1565,13 +1629,15 @@ class MQTTCore extends MQTTBase {
1565
1629
 
1566
1630
  return this} }
1567
1631
 
1568
- var version = "0.3.1";
1632
+ const version = '0.4.0';
1569
1633
 
1570
1634
  const MQTTClient_v4 = /* #__PURE__ */
1571
- MQTTCore.mqtt_ctx(4, mqtt_opts_v5);
1635
+ with_topic_path_router(
1636
+ MQTTCore.mqtt_ctx(4, mqtt_opts_v5) );
1572
1637
 
1573
1638
  const MQTTClient_v5 = /* #__PURE__ */
1574
- MQTTCore.mqtt_ctx(5, mqtt_opts_v5);
1639
+ with_topic_path_router(
1640
+ MQTTCore.mqtt_ctx(5, mqtt_opts_v5) );
1575
1641
 
1576
1642
  const mqtt_v4 = opt =>
1577
1643
  new MQTTClient_v4(opt);
@@ -1587,13 +1653,12 @@ exports.MQTTError = MQTTError;
1587
1653
  exports._mqtt_cmdid_dispatch = _mqtt_cmdid_dispatch;
1588
1654
  exports._mqtt_conn = _mqtt_conn;
1589
1655
  exports._mqtt_dispatch = _mqtt_dispatch;
1590
- exports._mqtt_route_match_one = _mqtt_route_match_one;
1591
- exports._mqtt_route_remove = _mqtt_route_remove;
1592
- exports._mqtt_routes_iter = _mqtt_routes_iter;
1593
- exports._mqtt_topic_router = _mqtt_topic_router;
1594
1656
  exports.ao_defer_v = ao_defer_v;
1595
- exports["default"] = mqtt_v4;
1657
+ exports.as_topic_path = as_topic_path;
1658
+ exports.default = mqtt_v4;
1596
1659
  exports.mqtt_v4 = mqtt_v4;
1597
1660
  exports.mqtt_v5 = mqtt_v5;
1598
1661
  exports.version = version;
1662
+ exports.with_topic_path_router = with_topic_path_router;
1663
+ exports.with_topic_router = with_topic_router;
1599
1664
  //# sourceMappingURL=index.cjs.map