u8-mqtt 0.5.3 → 0.6.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 (114) hide show
  1. package/README.md +1 -1
  2. package/cjs/basic-v4.cjs +283 -277
  3. package/cjs/basic-v4.cjs.map +1 -1
  4. package/cjs/basic-v5.cjs +297 -281
  5. package/cjs/basic-v5.cjs.map +1 -1
  6. package/cjs/full-v4.cjs +295 -289
  7. package/cjs/full-v4.cjs.map +1 -1
  8. package/cjs/full-v5.cjs +309 -293
  9. package/cjs/full-v5.cjs.map +1 -1
  10. package/cjs/index.cjs +310 -295
  11. package/cjs/index.cjs.map +1 -1
  12. package/cjs/v4.cjs +295 -289
  13. package/cjs/v4.cjs.map +1 -1
  14. package/cjs/v5.cjs +309 -293
  15. package/cjs/v5.cjs.map +1 -1
  16. package/code/_cmdid_dispatch.jsy +45 -69
  17. package/code/_conn.jsy +96 -72
  18. package/code/_dispatch.jsy +36 -28
  19. package/code/_utils.jsy +17 -0
  20. package/code/base.jsy +33 -61
  21. package/code/core.jsy +73 -51
  22. package/code/router_path.jsy +2 -1
  23. package/esm/basic-v4.js +283 -277
  24. package/esm/basic-v4.js.map +1 -1
  25. package/esm/basic-v5.js +297 -281
  26. package/esm/basic-v5.js.map +1 -1
  27. package/esm/deno/basic-v4.js +287 -281
  28. package/esm/deno/basic-v4.js.map +1 -1
  29. package/esm/deno/basic-v5.js +301 -285
  30. package/esm/deno/basic-v5.js.map +1 -1
  31. package/esm/deno/full-v4.js +299 -293
  32. package/esm/deno/full-v4.js.map +1 -1
  33. package/esm/deno/full-v5.js +313 -297
  34. package/esm/deno/full-v5.js.map +1 -1
  35. package/esm/deno/index.js +314 -298
  36. package/esm/deno/index.js.map +1 -1
  37. package/esm/deno/v4.js +299 -293
  38. package/esm/deno/v4.js.map +1 -1
  39. package/esm/deno/v5.js +313 -297
  40. package/esm/deno/v5.js.map +1 -1
  41. package/esm/full-v4.js +295 -289
  42. package/esm/full-v4.js.map +1 -1
  43. package/esm/full-v5.js +309 -293
  44. package/esm/full-v5.js.map +1 -1
  45. package/esm/index.js +310 -294
  46. package/esm/index.js.map +1 -1
  47. package/esm/node/basic-v4.js +283 -277
  48. package/esm/node/basic-v4.js.map +1 -1
  49. package/esm/node/basic-v4.mjs +283 -277
  50. package/esm/node/basic-v4.mjs.map +1 -1
  51. package/esm/node/basic-v5.js +297 -281
  52. package/esm/node/basic-v5.js.map +1 -1
  53. package/esm/node/basic-v5.mjs +297 -281
  54. package/esm/node/basic-v5.mjs.map +1 -1
  55. package/esm/node/full-v4.js +295 -289
  56. package/esm/node/full-v4.js.map +1 -1
  57. package/esm/node/full-v4.mjs +295 -289
  58. package/esm/node/full-v4.mjs.map +1 -1
  59. package/esm/node/full-v5.js +309 -293
  60. package/esm/node/full-v5.js.map +1 -1
  61. package/esm/node/full-v5.mjs +309 -293
  62. package/esm/node/full-v5.mjs.map +1 -1
  63. package/esm/node/index.js +310 -294
  64. package/esm/node/index.js.map +1 -1
  65. package/esm/node/index.mjs +310 -294
  66. package/esm/node/index.mjs.map +1 -1
  67. package/esm/node/v4.js +295 -289
  68. package/esm/node/v4.js.map +1 -1
  69. package/esm/node/v4.mjs +295 -289
  70. package/esm/node/v4.mjs.map +1 -1
  71. package/esm/node/v5.js +309 -293
  72. package/esm/node/v5.js.map +1 -1
  73. package/esm/node/v5.mjs +309 -293
  74. package/esm/node/v5.mjs.map +1 -1
  75. package/esm/v4.js +295 -289
  76. package/esm/v4.js.map +1 -1
  77. package/esm/v5.js +309 -293
  78. package/esm/v5.js.map +1 -1
  79. package/esm/web/basic-v4.js +283 -277
  80. package/esm/web/basic-v4.js.map +1 -1
  81. package/esm/web/basic-v4.min.js +1 -1
  82. package/esm/web/basic-v4.min.js.br +0 -0
  83. package/esm/web/basic-v4.min.js.gz +0 -0
  84. package/esm/web/basic-v5.js +297 -281
  85. package/esm/web/basic-v5.js.map +1 -1
  86. package/esm/web/basic-v5.min.js +1 -1
  87. package/esm/web/basic-v5.min.js.br +0 -0
  88. package/esm/web/basic-v5.min.js.gz +0 -0
  89. package/esm/web/full-v4.js +295 -289
  90. package/esm/web/full-v4.js.map +1 -1
  91. package/esm/web/full-v4.min.js +1 -1
  92. package/esm/web/full-v4.min.js.br +0 -0
  93. package/esm/web/full-v4.min.js.gz +0 -0
  94. package/esm/web/full-v5.js +309 -293
  95. package/esm/web/full-v5.js.map +1 -1
  96. package/esm/web/full-v5.min.js +1 -1
  97. package/esm/web/full-v5.min.js.br +0 -0
  98. package/esm/web/full-v5.min.js.gz +0 -0
  99. package/esm/web/index.js +310 -294
  100. package/esm/web/index.js.map +1 -1
  101. package/esm/web/index.min.js +1 -1
  102. package/esm/web/index.min.js.br +0 -0
  103. package/esm/web/index.min.js.gz +0 -0
  104. package/esm/web/v4.js +295 -289
  105. package/esm/web/v4.js.map +1 -1
  106. package/esm/web/v4.min.js +1 -1
  107. package/esm/web/v4.min.js.br +0 -0
  108. package/esm/web/v4.min.js.gz +0 -0
  109. package/esm/web/v5.js +309 -293
  110. package/esm/web/v5.js.map +1 -1
  111. package/esm/web/v5.min.js +1 -1
  112. package/esm/web/v5.min.js.br +0 -0
  113. package/esm/web/v5.min.js.gz +0 -0
  114. package/package.json +7 -8
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # [u8-mqtt ![npm published version][img-npm-ver]][npm-u8-mqtt] [![][img-deps] ![][img-treeshake] ![][img-min] ![][img-minzip]][bundlephobia-u8-mqtt]
1
+ # [u8-mqtt ![npm published version][img-npm-ver]][npm-u8-mqtt]
2
2
 
3
3
  A JavaScript MQTT client using async/await support QOS-0 and QOS-1.
4
4
  for use in modern ES6 environments: the Browser, [NodeJS](https://nodejs.org/en/), and [Deno](https://deno.land/).
package/cjs/basic-v4.cjs CHANGED
@@ -621,88 +621,15 @@ function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
621
621
  }
622
622
  }
623
623
 
624
- function ao_defer_ctx(as_res = (...args) => args) {
625
- let y,n,_pset = (a,b) => { y=a, n=b; };
626
- return p =>(
627
- p = new Promise(_pset)
628
- , as_res(p, y, n)) }
624
+ const _isfn = v => typeof v === 'function';
625
+ const _isstr = v => typeof v === 'string';
629
626
 
630
- const ao_defer_v = /* #__PURE__ */
631
- ao_defer_ctx();
632
-
633
- Promise.resolve({type:'init'});
634
-
635
- function _mqtt_conn(client, [on_mqtt, pkt_future]) {
636
- let _q_init = ao_defer_v(), _q_ready = ao_defer_v();
637
- let _send_ready = async (...args) => (await _q_ready[0])(...args);
638
- let _send_mqtt_pkt, _has_connected;
639
- client._send = _send_ready;
640
-
641
- return {
642
- async when_ready() {await _q_ready[0];}
643
-
644
- , ping: _ping_interval (() =>_send_mqtt_pkt?.('pingreq'))
645
-
646
- , reset(err) {
647
- if (! _send_mqtt_pkt) {return}
648
-
649
- if (err) {
650
- _q_init[2](err);}
651
-
652
- _send_mqtt_pkt = null;
653
- _q_init = ao_defer_v();
654
- client._send = _send_ready;
655
-
656
- // call client.on_conn_reset in next promise microtask
657
- client.conn_emit('on_disconnect', false===err, err);}
658
-
659
- , async send_connect(... args) {
660
- if (! _send_mqtt_pkt) {
661
- await _q_init[0]; }// _send_mqtt_pkt is set before fulfilled
662
-
663
- // await connack response
664
- let res = await _send_mqtt_pkt(...args);
665
- if (0 == res[0].reason) {
666
- _has_connected = true;
667
- // resolve _q_ready[0] with _send_mqtt_pkt closure
668
- _q_ready[1](client._send = _send_mqtt_pkt);
669
- _q_ready = ao_defer_v();
670
- client.conn_emit('on_ready');}
671
-
672
- return res}
673
-
674
- , is_set: (() =>!! _send_mqtt_pkt)
675
- , set(mqtt_ctx, send_u8_pkt) {
676
- if (_send_mqtt_pkt) {
677
- throw new Error('Already connected')}
678
-
679
- mqtt_ctx = mqtt_ctx.mqtt_stream();
680
- let sess_ctx = {mqtt: client};
681
- let on_mqtt_chunk = u8_buf =>
682
- on_mqtt(mqtt_ctx.decode(u8_buf), sess_ctx);
683
-
684
- _send_mqtt_pkt = async (type, pkt, key) => {
685
- let res = undefined !== key
686
- ? pkt_future(key) : true;
687
-
688
- await send_u8_pkt(
689
- mqtt_ctx.encode_pkt(type, pkt));
690
-
691
- return res};
692
-
693
- _q_init[1](_send_mqtt_pkt); // resolve _q_init with _send_mqtt_pkt closure
694
-
695
- // call client.on_live in next promise microtask
696
- client.conn_emit('on_live', _has_connected);
697
- return on_mqtt_chunk} } }
698
-
699
-
700
- function _ping_interval(send_ping) {
627
+ function _interval(fn_callback) {
701
628
  let tid;
702
629
  return (( td ) => {
703
630
  tid = clearInterval(tid);
704
631
  if (td) {
705
- tid = setInterval(send_ping, 1000 * td);
632
+ tid = setInterval(fn_callback, 1000 * td);
706
633
 
707
634
 
708
635
 
@@ -711,148 +638,108 @@ function _ping_interval(send_ping) {
711
638
  tid.unref?.();
712
639
  return true} }) }
713
640
 
714
- const _mqtt_cmdid_dispatch ={
715
- create(target) {
716
- return {__proto__: this, target, hashbelt: [new Map()]} }
641
+ async function _mqtt_cmd_evt(target, answer, pkt, ctx) {
642
+ /* target : on_mqtt_type = {
643
+ mqtt_pkt(pkt, ctx) {}, // generic
644
+
645
+ mqtt_auth(pkt, ctx) {},
646
+ mqtt_connect(pkt, ctx) {},
647
+ mqtt_connack(pkt, ctx) {},
648
+ mqtt_disconnect(pkt, ctx) {},
649
+
650
+ mqtt_publish(pkt, ctx) {},
651
+ mqtt_subscribe(pkt, ctx) {},
652
+ mqtt_unsubscribe(pkt, ctx) {},
653
+
654
+ mqtt_pingreq(pkt, ctx) {},
655
+ mqtt_pingresp(pkt, ctx) {},
656
+ } */
657
+
658
+ let pkt_fn = target[`mqtt_${pkt.type}`] || target.mqtt_pkt;
659
+ await pkt_fn?.call(target, pkt, ctx);}
660
+
661
+ function _mqtt_cmd_type(target, answer, pkt, ctx) {
662
+ answer(pkt.type, pkt);
663
+ _mqtt_cmd_evt(target, answer, pkt, ctx);}
664
+
665
+ function _mqtt_cmd_id(target, answer, pkt) {
666
+ answer(pkt.pkt_id, pkt);}
667
+
668
+
669
+ const _mqtt_cmdids =[
670
+ _ => {} // 0x0 reserved
671
+ , _mqtt_cmd_evt // 0x1 connect
672
+ , _mqtt_cmd_type // 0x2 connack
673
+ , _mqtt_cmd_evt // 0x3 publish
674
+ , _mqtt_cmd_id // 0x4 puback
675
+ , _mqtt_cmd_id // 0x5 pubrec
676
+ , _mqtt_cmd_id // 0x6 pubrel
677
+ , _mqtt_cmd_id // 0x7 pubcomp
678
+ , _mqtt_cmd_evt // 0x8 subscribe
679
+ , _mqtt_cmd_id // 0x9 suback
680
+ , _mqtt_cmd_evt // 0xa unsubscribe
681
+ , _mqtt_cmd_id // 0xb unsuback
682
+ , _mqtt_cmd_type // 0xc pingreq
683
+ , _mqtt_cmd_type // 0xd pingresp
684
+ , _mqtt_cmd_evt // 0xe disconnect
685
+ , _mqtt_cmd_type ];// 0xf auth
686
+
687
+ function _mqtt_dispatch(opt, target) {
688
+ let hashbelt=[], rotate_ts=0;
689
+ // default rotate at 1s across 5 buckets
690
+ let { td: rotate_td=1000, n: rotate_n=5 } = opt?.rotate || {};
691
+
692
+ // Promise / future scaffolding
693
+ let _pkt_id=100, _ftr_key; // use _ftr_key to reuse _by_key closure
694
+ let _ftr_by_key = fn_answer => hashbelt[0].set(_ftr_key, fn_answer);
717
695
 
718
- , bind_pkt_future(_pkt_id=100) {
719
- let {hashbelt} = this;
696
+ on_mqtt([]); // init hashbelt and rotate_ts
697
+ return [on_mqtt, pkt_future]
720
698
 
721
- let _tmp_; // use _tmp_ to reuse _by_key closure
722
- let _by_key = answer_monad =>
723
- hashbelt[0].set(_tmp_, answer_monad);
724
699
 
725
- return (( pkt_or_key ) => {
726
- if ('string' === typeof pkt_or_key) {
727
- _tmp_ = pkt_or_key;}
728
- else {
729
- _pkt_id = (_pkt_id + 1) & 0xffff;
730
- _tmp_ = pkt_or_key.pkt_id = _pkt_id;}
700
+ function pkt_future(pkt_or_key) {
701
+ if (! _isstr(pkt_or_key)) {
702
+ _pkt_id = (_pkt_id + 1) & 0xffff; // 16-bit unsigned short
703
+ _ftr_key = pkt_or_key.pkt_id = _pkt_id;}
704
+ else _ftr_key = pkt_or_key;
731
705
 
732
- return new Promise(_by_key)}) }
706
+ return new Promise(_ftr_by_key)}
733
707
 
734
- , answer(key, pkt) {
735
- for (let map of this.hashbelt) {
736
- let answer_monad = map.get(key);
737
- if (undefined !== answer_monad) {
708
+ function answer(key, pkt) {
709
+ for (let map of hashbelt) {
710
+ let fn_answer = map.get(key);
711
+ if (fn_answer) {
738
712
  map.delete(key);
739
713
 
740
- answer_monad([pkt, /*err*/]); // option/maybe monad
714
+ fn_answer([pkt, /*err*/]); // option/maybe monad
741
715
  return true} }
742
716
  return false}
743
717
 
744
- , rotate_belt(n) {
745
- let {hashbelt} = this;
746
- hashbelt.unshift(new Map());
747
- for (let old of hashbelt.splice(n || 5)) {
748
- for (let answer_monad of old.values()) {
749
- answer_monad([/*pkt*/, 'expired']); } } }// option/maybe monad
750
-
751
- , cmdids: ((() => {
752
- return [
753
- (() =>{} )// 0x0 reserved
754
- , by_evt // 0x1 connect
755
- , by_type // 0x2 connack
756
- , by_evt // 0x3 publish
757
- , by_id // 0x4 puback
758
- , by_id // 0x5 pubrec
759
- , by_id // 0x6 pubrel
760
- , by_id // 0x7 pubcomp
761
- , by_evt // 0x8 subscribe
762
- , by_id // 0x9 suback
763
- , by_evt // 0xa unsubscribe
764
- , by_id // 0xb unsuback
765
- , by_type // 0xc pingreq
766
- , by_type // 0xd pingresp
767
- , by_evt // 0xe disconnect
768
- , by_type ]// 0xf auth
769
-
770
-
771
- function by_id(disp, pkt) {
772
- disp.answer(pkt.pkt_id, pkt); }
773
-
774
- function by_type(disp, pkt, ctx) {
775
- disp.answer(pkt.type, pkt);
776
- by_evt(disp, pkt, ctx);}
777
-
778
- async function by_evt({target}, pkt, ctx) {
779
- let fn = target[`mqtt_${pkt.type}`]
780
- || target.mqtt_pkt;
781
-
782
- await fn?.call(target, pkt, ctx);} })()) };
783
-
784
- /*
785
- on_mqtt_type = {
786
- mqtt_auth(pkt, ctx) ::
787
- mqtt_connect(pkt, ctx) ::
788
- mqtt_connack(pkt, ctx) ::
789
- mqtt_disconnect(pkt, ctx) ::
790
-
791
- mqtt_publish(pkt, ctx)
792
- mqtt_subscribe(pkt, ctx) ::
793
- mqtt_unsubscribe(pkt, ctx) ::
794
-
795
- mqtt_pingreq(pkt, ctx) ::
796
- mqtt_pingresp(pkt, ctx) ::
797
- }
798
- */
799
-
800
- function _mqtt_dispatch(opt, target) {
801
- let _disp_ = _mqtt_cmdid_dispatch.create(target);
802
- let { cmdids } = _disp_;
803
-
804
- // default rotate at 1s across 5 buckets
805
- let { td: rotate_td=1000, n: rotate_n=5 } =
806
- opt && opt.rotate || {};
807
-
808
- let rotate_ts = rotate_td + Date.now();
809
-
810
- return [on_mqtt,
811
- _disp_.bind_pkt_future()]
812
-
813
718
  function on_mqtt(pkt_list, ctx) {
814
719
  for (let pkt of pkt_list) {
815
- cmdids[pkt.id](_disp_, pkt, ctx); }
720
+ _mqtt_cmdids[pkt.id](target, answer, pkt, ctx);}
816
721
 
817
- if (Date.now() > rotate_ts) {
818
- _disp_.rotate_belt(rotate_n);
819
- rotate_ts = rotate_td + Date.now();} } }
722
+ // rotate after rotate_ts
723
+ let now = Date.now();
724
+ if (now > rotate_ts) {
725
+ rotate_ts = rotate_td + now;
726
+ hashbelt.unshift(new Map());
727
+ while (hashbelt.length > rotate_n) {
728
+ for (let fn_answer of hashbelt.pop().values()) {
729
+ fn_answer([/*pkt*/, 'expired']); } } } } }// option/maybe monad
820
730
 
821
731
  class MQTTError extends Error {
822
732
  constructor(mqtt_pkt, reason=mqtt_pkt.reason) {
733
+ // use hex-encoded reasons to match MQTT spec documentation
823
734
  super(`[0x${reason.toString(16)}] ${reason.reason}`);
824
735
  this.mqtt_pkt = mqtt_pkt;
825
736
  this.reason = reason;} }
826
737
 
827
738
  class MQTTBase {
828
- constructor(opt={}) {
829
- this.with(opt);
830
- this._conn_ = _mqtt_conn(this,
831
- this._init_dispatch(opt, this)); }
832
-
833
- with(fns_ns) {
834
- for (let [k,v] of Object.entries(fns_ns)) {
835
- if ('function' === typeof v) {this[k] = v;} }
836
- return this}
837
-
838
- async conn_emit(evt, arg, err_arg) {
839
- this.log_conn?.(evt, arg, err_arg);
840
- try {
841
- let fn_evt = this[await evt]; // microtask break using `await evt`
842
- if (fn_evt) {
843
- await fn_evt.call(this, this, arg, err_arg);}
844
- else if (err_arg) {throw err_arg} }
845
- catch (err) {
846
- this.on_error(err, evt);} }
847
-
848
- on_error(err, evt) {
849
- console.warn('[[u8-mqtt error: %s]]', evt, err); }
850
-
851
739
  // Handshaking Packets
852
-
853
740
  async connect(pkt={}) {
854
741
  let cid = pkt.client_id;
855
- if ('string' !== typeof cid) {
742
+ if (! _isstr(cid)) {
856
743
  // see init_client_id implementation in core.jsy
857
744
  pkt.client_id = cid = this.client_id || this.init_client_id(cid);}
858
745
  this.client_id = cid;
@@ -860,23 +747,20 @@ class MQTTBase {
860
747
  if (null == pkt.keep_alive) {
861
748
  pkt.keep_alive = 60;}
862
749
 
863
- let res = await this._conn_
864
- .send_connect('connect', pkt, 'connack');
865
-
866
- if (0 != res[0].reason) {
867
- throw new this.MQTTError(res[0])}
868
-
869
- // TODO: merge with server's keep_alive frequency
870
- this._conn_.ping(pkt.keep_alive);
871
- return res}
750
+ let response = await this._send0('connect', pkt, 'connack');
751
+ if (0 != response[0].reason) {// compare to 0 to coerce to number
752
+ throw new this.MQTTError(response[0])}
753
+ return this.conn.on_conn(pkt, response)}
872
754
 
873
755
  async disconnect(pkt={}) {
874
- let res = await this._send('disconnect', pkt);
875
- this._conn_.reset(false);
876
- return res}
756
+ let response = await this._send0('disconnect', pkt);
757
+ return this.conn.on_dis(pkt, response)}
877
758
 
878
- auth(pkt={}) {
879
- return this._send('auth', pkt, 'auth')}
759
+ async auth(pkt={}) {
760
+ let response = await this._send0('auth', pkt, 'auth');
761
+ if (response[0].reason) {
762
+ throw new this.MQTTError(response[0])}
763
+ return this.conn.on_auth(pkt, response)}
880
764
 
881
765
  ping() {return this._send('pingreq', null, 'pingresp')}
882
766
  puback({pkt_id}) {return this._send('puback', {pkt_id})}
@@ -913,20 +797,18 @@ class MQTTBase {
913
797
  // alias: publish -- because 'pub' is shorter for semantic aliases above
914
798
  async pub(pkt, pub_opt) {
915
799
  if (undefined === pkt.payload) {
916
- if ('function' === typeof pub_opt) {
800
+ if (_isfn(pub_opt)) {
801
+ // pub_opt as a function is fn_encode value
917
802
  pub_opt = {fn_encode: pub_opt};}
918
803
 
919
- let {msg} = pkt;
920
- switch (typeof msg) {
921
- case 'function':
922
- pub_opt = {...pub_opt, fn_encode: msg};
923
- // flow into 'undefined' case
924
- case 'undefined':
925
- // return a single-value closure to publish packets
926
- return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)}
804
+ let msg = pkt.msg, fn_encode = pub_opt?.fn_encode;
805
+ if (null == msg || _isfn(msg)) {
806
+ // when msg is a function, return closure using fn_encode
807
+ if (msg) {pub_opt = {...pub_opt, fn_encode: msg};}
808
+ // return a single-value closure to publish packets
809
+ return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)}
927
810
 
928
811
  // Encode payload from msg; fn_encode allows alternative to JSON.stringify
929
- let {fn_encode} = pub_opt || {};
930
812
  pkt.payload = fn_encode
931
813
  ? await fn_encode(msg)
932
814
  : JSON.stringify(msg);}
@@ -938,31 +820,31 @@ class MQTTBase {
938
820
  pkt = pub_opt.xform(pkt) || pkt;} }
939
821
 
940
822
  return this._send('publish', pkt,
941
- pkt.qos ? pkt : void 0 ) }// key
823
+ pkt.qos ? pkt : null ) }// key
942
824
 
943
825
 
944
826
  // Internal API
945
827
 
946
- /* async _send(type, pkt) -- provided by _conn_ and transport */
828
+ /* async _send0(type, pkt) -- provided by conn and transport */
829
+ /* async _send(type, pkt) -- provided by conn and transport */
947
830
 
948
831
  _init_dispatch(opt) {
949
832
  this.constructor?._once_();
950
833
  let target ={__proto__: opt.on_mqtt_type};
951
834
  target.mqtt_publish ||=
952
835
  this._init_router?.(opt, this, target);
953
- return _mqtt_dispatch(this, target)}
836
+ return _mqtt_dispatch(opt, target)}
954
837
 
955
838
  static _aliases() {
956
839
  return ' publish:pub sub:subscribe unsub:unsubscribe json_post:obj_post json_send:obj_send json_store:obj_store'}
957
840
 
958
- static _once_(self=this) {
959
- self._once_ = _=>0;
960
- let p = self.prototype;
841
+ static _once_(klass=this) {
842
+ klass._once_ = _=>0;
843
+ var alias, name, p = klass.prototype;
961
844
  p.MQTTError = MQTTError;
962
- for (let alias of self._aliases().split(/\s+/)) {
963
- alias = alias.split(':');
964
- let fn = alias[1] && p[alias[1]];
965
- if (fn) {p[alias[0]] = fn;} } } }
845
+ for (alias of klass._aliases().split(/\s+/)) {
846
+ [alias, name] = alias.split(':');
847
+ p[alias] = p[name];} } }
966
848
 
967
849
 
968
850
  function _as_topics(pkt, ex, topic_prefix) {
@@ -987,37 +869,167 @@ function _as_topics(pkt, ex, topic_prefix) {
987
869
  pkt.topics = pkt.topics.map(_prefix_topics);}
988
870
  return pkt}
989
871
 
990
- const pkt_api = {
991
- utf8(u8) { return new TextDecoder('utf-8').decode(u8 || this.payload ) },
992
- json(u8) { return JSON.parse( this.utf8(u8) || null ) },
993
- text(u8) { return this.utf8(u8) },
994
- };
872
+ const _defer_obj = o =>(
873
+ o.p = new Promise((a,e) => { o.a=a; o.e=e; })
874
+ , o);
875
+
876
+ function _dfn_reset(client, attr, fn_after) {
877
+ // a resetable deferred for a function
878
+ let self = {set}, afn = async (...args) => (await self.p)(...args);
879
+ return set()
880
+
881
+ function set() {
882
+ if (afn !== client[attr]) {
883
+ _defer_obj(self).p.then(fn_after, _=>0);
884
+ client[attr] = afn;}
885
+ return self} }
886
+
887
+ function _mqtt_conn(opt, client, [on_mqtt, pkt_future]) {
888
+ let _abort;
889
+ let _dfn_send0 = _dfn_reset(client, '_send0', // client._send0 getter/setter
890
+ _=> client.conn_emit('on_live', conn.has_connected));
891
+ let _dfn_ready = _dfn_reset(client, '_send', // client._send getter/setter
892
+ _=> client.conn_emit('on_ready'));
893
+ let _keep_alive_ival = _interval (() =>client._send0('pingreq') );// resettable interval for keep_alive ping
894
+
895
+ let conn = Object.create({
896
+ ping: (td=conn.keep_alive) => _keep_alive_ival(td)
897
+
898
+ , on_conn(pkt, response) {
899
+ conn.has_connected = true;
900
+ conn.keep_alive = opt.keep_alive || response[0].props?.server_keep_alive || pkt.keep_alive;
901
+ client.conn_emit('on_conn');
902
+ return opt.use_auth
903
+ ? response // wait on enhanced authentication step
904
+ : conn.on_auth(null, response) }// otherwise, connect is also auth
905
+
906
+ , on_auth(pkt, response) {
907
+ _dfn_ready.a(_dfn_send0.p);
908
+ if (0 != opt.keep_alive) {
909
+ conn.ping();}
910
+ client.conn_emit('on_auth', !pkt);
911
+ return response}
912
+
913
+ , on_dis(pkt, response) {
914
+ conn.reset(false);
915
+ return response}
916
+
917
+ , reset(err) {
918
+ if (err) {
919
+ _dfn_send0.e(err); }// send error to uses of _send0 (connect, auth)
920
+ _abort.e(err); // abort in-progress connections
921
+
922
+ delete conn.is_set;
923
+ conn.ready = handshake();
924
+ client.conn_emit('on_disconnect', false===err, err);}
925
+
926
+ , abort() {
927
+ _dfn_ready.e(err); // abort all messages awaiting ready state
928
+ return conn.reset(err)}
929
+
930
+ , async setup(gate, send_u8_pkt, init_msg_loop) {
931
+ if (conn.is_set) {
932
+ throw new Error() }// already in-progress
933
+
934
+ conn.is_set = true;
935
+ await gate;
936
+
937
+ // setup send/recv MQTT parsing context
938
+ let mqtt_ctx = client.mqtt_ctx.mqtt_stream();
939
+
940
+ {// setup inbound message loop
941
+ let sess_ctx = {mqtt: client}; // mutable session context
942
+ let on_mqtt_chunk = u8 => on_mqtt(mqtt_ctx.decode(u8), sess_ctx);
943
+ init_msg_loop(on_mqtt_chunk, conn);}
944
+
945
+ // setup outbound message path and transport connection
946
+ send_u8_pkt = await send_u8_pkt;
947
+ _dfn_send0.a(
948
+ async (type, pkt, key) => {
949
+ let res = undefined !== key
950
+ ? pkt_future(key) : true;
951
+
952
+ await send_u8_pkt(
953
+ mqtt_ctx.encode_pkt(type, pkt));
954
+ return res} ); } });
955
+
956
+ conn.ready = handshake();
957
+ return conn
958
+
959
+ async function handshake() {
960
+ _abort = _defer_obj({});
961
+
962
+ _keep_alive_ival(0); // clearInterval on keep alive ping
963
+ _dfn_send0.set(); // reset client._send0 if necessary
964
+ _dfn_ready.set(); // reset client._send if necessary
965
+
966
+ try {
967
+ // set client._send0 as passtrhough after transport connection
968
+ client._send0 = await Promise.race([_dfn_send0.p, _abort.p]);
969
+
970
+ // set client._send as passtrhough after ready
971
+ client._send = await Promise.race([_dfn_ready.p, _abort.p]);
972
+ return true}
973
+ catch (err) {
974
+ return false} } }
975
+
976
+ const pkt_api ={
977
+ utf8(u8) {return new TextDecoder('utf-8').decode(u8 || this.payload )}
978
+ , json(u8) {return JSON.parse( this.utf8(u8) || null )}
979
+ , text(u8) {return this.utf8(u8)} };
980
+
981
+ const opt_default ={
982
+ sess_stg: globalThis.sessionStorage};
995
983
 
996
984
  class MQTTCore extends MQTTBase {
985
+ constructor(opt) {
986
+ opt = {...opt_default, ...opt};
987
+ super();
988
+ this.with(opt);
989
+ // settings for MQTTCore
990
+ this.sess_stg = opt.sess_stg;
991
+ // setup connection and dispatch
992
+ this.conn = _mqtt_conn(opt, this,
993
+ this._init_dispatch(opt)); }
994
+
995
+ with(fns_ns) {
996
+ for (let [k,v] of Object.entries(fns_ns)) {
997
+ if (_isfn(v)) {this[k] = v;} }
998
+ return this}
999
+
1000
+
997
1001
  static mqtt_ctx(mqtt_level, mqtt_opts, pkt_ctx=pkt_api) {
998
- let self = class extends this {};
999
- self.prototype.mqtt_ctx =
1002
+ let klass = class extends this {};
1003
+ klass.prototype.mqtt_ctx =
1000
1004
  mqtt_pkt_ctx(mqtt_level, mqtt_opts, pkt_ctx);
1001
- return self}
1005
+ return klass}
1006
+
1007
+
1008
+ async conn_emit(evt, arg, err_arg) {
1009
+ this.log_conn?.(evt, arg, err_arg);
1010
+ try {
1011
+ let fn_evt = this[await evt]; // microtask break using `await evt`
1012
+ if (fn_evt) {
1013
+ await fn_evt.call(this, this, arg, err_arg);}
1014
+ else if (err_arg) {throw err_arg} }
1015
+ catch (err) {
1016
+ this.on_error(err, evt);} }
1017
+
1018
+ on_error(err, evt) {
1019
+ console.warn('[[u8-mqtt error: %s]]', evt, err); }
1020
+ log_conn(evt, arg, err_arg) {
1021
+ console.info('[[u8-mqtt conn: %s]]', evt, arg, err_arg); }
1002
1022
 
1003
1023
 
1004
1024
  // automatic Client Id for connect()
1005
1025
  init_client_id(parts=['u8-mqtt--','']) {
1006
- let sess_stg=this.sess_stg;
1026
+ let sess_stg = this.sess_stg;
1007
1027
  let key, cid = sess_stg?.getItem(key=parts.join(' '));
1008
1028
  if (! cid) {
1009
1029
  cid = parts.join(Math.random().toString(36).slice(2));
1010
1030
  sess_stg?.setItem(key, cid);}
1011
1031
  return cid}
1012
1032
 
1013
- get sess_stg() {return globalThis.sessionStorage}
1014
-
1015
-
1016
- //on_error(err, evt) ::
1017
- // console.warn @ '[[u8-mqtt error: %s]]', evt, err
1018
-
1019
- //log_conn(evt, arg, err_arg) ::
1020
- // console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
1021
1033
 
1022
1034
  on_live(client, is_reconnect) {
1023
1035
  if (is_reconnect) {
@@ -1043,19 +1055,16 @@ class MQTTCore extends MQTTBase {
1043
1055
  return new Promise(done => setTimeout(done, ms)) }
1044
1056
 
1045
1057
  with_async_iter(async_iter, write_u8_pkt) {
1046
- let on_mqtt_chunk = this._conn_.set(
1047
- this.mqtt_ctx,
1048
- write_u8_pkt);
1049
-
1050
- this._msg_loop = ((async () => {
1051
- try {
1052
- async_iter = await async_iter;
1053
- for await (let chunk of async_iter)
1054
- on_mqtt_chunk(chunk);
1055
- this._conn_.reset();}
1056
- catch (err) {
1057
- this._conn_.reset(err);} })());
1058
-
1058
+ this.conn.setup(async_iter,
1059
+ write_u8_pkt,
1060
+ async (on_mqtt_chunk, conn) => {
1061
+ try {
1062
+ async_iter = await async_iter;
1063
+ for await (let chunk of async_iter)
1064
+ on_mqtt_chunk(chunk);
1065
+ conn.reset();}
1066
+ catch (err) {
1067
+ conn.reset(err);} } );
1059
1068
  return this}
1060
1069
 
1061
1070
 
@@ -1126,33 +1135,30 @@ class MQTTCore extends MQTTBase {
1126
1135
 
1127
1136
  websock.binaryType = 'arraybuffer';
1128
1137
 
1129
- let ready, {readyState} = websock;
1138
+ let ws_ready, readyState = websock.readyState;
1130
1139
  if (1 !== readyState) {
1131
1140
  if (0 !== readyState) {
1132
- throw new Error('Invalid WebSocket readyState') }
1133
-
1134
- ready = new Promise(fn => websock.onopen = fn); }
1141
+ throw new Error('WS readyState') }
1135
1142
 
1143
+ ws_ready = new Promise(ready => websock.onopen = ready); }
1136
1144
 
1137
- let {_conn_} = this;
1138
- let on_mqtt_chunk = _conn_.set(
1139
- this.mqtt_ctx,
1140
- async u8_pkt =>(
1141
- await ready
1142
- , websock.send(u8_pkt)) );
1145
+ this.conn.setup(ws_ready,
1146
+ u8_pkt => websock.send(u8_pkt),
1147
+ (on_mqtt_chunk, conn) => {
1148
+ websock.onmessage = evt =>(
1149
+ on_mqtt_chunk(new Uint8Array(evt.data)) );
1143
1150
 
1144
- websock.onmessage = evt =>(on_mqtt_chunk(new Uint8Array(evt.data)));
1145
- websock.onclose = evt => {
1146
- if (! evt.wasClean) {
1147
- var err = new Error('websocket connection close');
1148
- err.code = evt.code;
1149
- err.reason = evt.reason;}
1151
+ websock.onclose = evt => {
1152
+ if (! evt.wasClean) {
1153
+ var err = new Error('websocket close');
1154
+ err.code = evt.code;
1155
+ err.reason = evt.reason;}
1150
1156
 
1151
- _conn_.reset(err);};
1157
+ conn.reset(err);}; } );
1152
1158
 
1153
1159
  return this} }
1154
1160
 
1155
- const version = '0.5.3-node';
1161
+ const version = '0.6.1-node';
1156
1162
 
1157
1163
  const MQTTClient_v4 = /* #__PURE__ */
1158
1164
  MQTTCore.mqtt_ctx(4, mqtt_opts_v4);