mqtt-plus 0.9.15 → 0.9.16

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.
@@ -42,7 +42,7 @@ class JSONX {
42
42
  : value);
43
43
  }
44
44
  static parse(json) {
45
- return JSON.parse(json, (_, value) => value?.__Uint8Array
45
+ return JSON.parse(json, (_, value) => typeof value?.__Uint8Array === "string"
46
46
  ? this.base64ToUint8Array(value.__Uint8Array)
47
47
  : value);
48
48
  }
@@ -147,8 +147,14 @@ export class ServiceTrait extends EventTrait {
147
147
  if (!this.responseSubscriptions.has(topic)) {
148
148
  this.responseSubscriptions.set(topic, 0);
149
149
  this.mqtt.subscribe(topic, options, (err) => {
150
- if (err)
150
+ if (err) {
151
+ const count = this.responseSubscriptions.get(topic) ?? 0;
152
+ if (count > 1)
153
+ this.responseSubscriptions.set(topic, count - 1);
154
+ else
155
+ this.responseSubscriptions.delete(topic);
151
156
  this.mqtt.emit("error", err);
157
+ }
152
158
  });
153
159
  }
154
160
  const count = this.responseSubscriptions.get(topic) ?? 0;
@@ -163,8 +169,9 @@ export class ServiceTrait extends EventTrait {
163
169
  return;
164
170
  /* unsubscribe from MQTT topic and forget subscription */
165
171
  const count = this.responseSubscriptions.get(topic) ?? 0;
166
- this.responseSubscriptions.set(topic, count - 1);
167
- if (this.responseSubscriptions.get(topic) === 0) {
172
+ if (count > 1)
173
+ this.responseSubscriptions.set(topic, count - 1);
174
+ else {
168
175
  this.responseSubscriptions.delete(topic);
169
176
  this.mqtt.unsubscribe(topic, (err) => {
170
177
  if (err)
@@ -125,7 +125,7 @@ class JSONX {
125
125
  return JSON.stringify(obj, (_, value) => value instanceof Uint8Array ? { __Uint8Array: this.uint8ArrayToBase64(value) } : value);
126
126
  }
127
127
  static parse(json) {
128
- return JSON.parse(json, (_, value) => value?.__Uint8Array ? this.base64ToUint8Array(value.__Uint8Array) : value);
128
+ return JSON.parse(json, (_, value) => typeof value?.__Uint8Array === "string" ? this.base64ToUint8Array(value.__Uint8Array) : value);
129
129
  }
130
130
  }
131
131
  class Codec {
@@ -570,8 +570,14 @@ class ServiceTrait extends EventTrait {
570
570
  if (!this.responseSubscriptions.has(topic)) {
571
571
  this.responseSubscriptions.set(topic, 0);
572
572
  this.mqtt.subscribe(topic, options, (err) => {
573
- if (err)
573
+ if (err) {
574
+ const count2 = this.responseSubscriptions.get(topic) ?? 0;
575
+ if (count2 > 1)
576
+ this.responseSubscriptions.set(topic, count2 - 1);
577
+ else
578
+ this.responseSubscriptions.delete(topic);
574
579
  this.mqtt.emit("error", err);
580
+ }
575
581
  });
576
582
  }
577
583
  const count = this.responseSubscriptions.get(topic) ?? 0;
@@ -583,8 +589,9 @@ class ServiceTrait extends EventTrait {
583
589
  if (!this.responseSubscriptions.has(topic))
584
590
  return;
585
591
  const count = this.responseSubscriptions.get(topic) ?? 0;
586
- this.responseSubscriptions.set(topic, count - 1);
587
- if (this.responseSubscriptions.get(topic) === 0) {
592
+ if (count > 1)
593
+ this.responseSubscriptions.set(topic, count - 1);
594
+ else {
588
595
  this.responseSubscriptions.delete(topic);
589
596
  this.mqtt.unsubscribe(topic, (err) => {
590
597
  if (err)
@@ -107,7 +107,7 @@ class JSONX {
107
107
  return JSON.stringify(obj, (_, value) => value instanceof Uint8Array ? { __Uint8Array: this.uint8ArrayToBase64(value) } : value);
108
108
  }
109
109
  static parse(json) {
110
- return JSON.parse(json, (_, value) => value?.__Uint8Array ? this.base64ToUint8Array(value.__Uint8Array) : value);
110
+ return JSON.parse(json, (_, value) => typeof value?.__Uint8Array === "string" ? this.base64ToUint8Array(value.__Uint8Array) : value);
111
111
  }
112
112
  }
113
113
  class Codec {
@@ -552,8 +552,14 @@ class ServiceTrait extends EventTrait {
552
552
  if (!this.responseSubscriptions.has(topic)) {
553
553
  this.responseSubscriptions.set(topic, 0);
554
554
  this.mqtt.subscribe(topic, options, (err) => {
555
- if (err)
555
+ if (err) {
556
+ const count2 = this.responseSubscriptions.get(topic) ?? 0;
557
+ if (count2 > 1)
558
+ this.responseSubscriptions.set(topic, count2 - 1);
559
+ else
560
+ this.responseSubscriptions.delete(topic);
556
561
  this.mqtt.emit("error", err);
562
+ }
557
563
  });
558
564
  }
559
565
  const count = this.responseSubscriptions.get(topic) ?? 0;
@@ -565,8 +571,9 @@ class ServiceTrait extends EventTrait {
565
571
  if (!this.responseSubscriptions.has(topic))
566
572
  return;
567
573
  const count = this.responseSubscriptions.get(topic) ?? 0;
568
- this.responseSubscriptions.set(topic, count - 1);
569
- if (this.responseSubscriptions.get(topic) === 0) {
574
+ if (count > 1)
575
+ this.responseSubscriptions.set(topic, count - 1);
576
+ else {
570
577
  this.responseSubscriptions.delete(topic);
571
578
  this.mqtt.unsubscribe(topic, (err) => {
572
579
  if (err)
@@ -10,4 +10,4 @@ ${Fr.repeat(u.depth)}}`:u.close="}";break}case Y.TAG:c+=String(p),c+=tt(Y.POS_IN
10
10
  `;let g=0;for(const b of t.children){if(zn(b)){let p=String(g);t.mt===Y.MAP?p=g%2?`val ${(g-1)/2}`:`key ${g/2}`:t.mt===Y.TAG&&(p=""),o+=Vn(b,e,p)}g++}}return o}const vo={...Fe.defaultDecodeOptions,initialDepth:0,noPrefixHex:!1,minCol:0};function Xn(t,e){const r={...vo,...e,ParentType:Ur,saveOriginal:!0},o=new Kt(t,r);let f,u;for(const d of o){if(u=Fe.create(d,f,r,o),d[2]===Ie.BREAK)if(f?.isStreaming)f.left=1;else throw new Error("Unexpected BREAK");if(!zn(u)){const p=new Ur(d,0,f,r);p.leaf=!0,p.children.push(u),Tt(p,o.toHere(d[3])),u=p}let g=(u.depth+1)*2;const b=u.numBytes();for(b&&(g+=1,g+=b*2),r.minCol=Math.max(r.minCol,g),f&&f.push(u,o,d[3]),f=u;f?.done;)u=f,u.leaf||Tt(u,o.toHere(u.offset)),{parent:f}=f}e&&(e.minCol=r.minCol);let c=r.noPrefixHex?"":`0x${Ne(o.toHere(0))}
11
11
  `;return c+=Vn(u,r),c}const Jn=!$i();function zt(t){if(typeof t=="object"&&t){if(t.constructor!==Number)throw new Error(`Expected number: ${t}`)}else if(typeof t!="number")throw new Error(`Expected number: ${t}`)}function rt(t){if(typeof t=="object"&&t){if(t.constructor!==String)throw new Error(`Expected string: ${t}`)}else if(typeof t!="string")throw new Error(`Expected string: ${t}`)}function Ze(t){if(!(t instanceof Uint8Array))throw new Error(`Expected Uint8Array: ${t}`)}function Zn(t){if(!Array.isArray(t))throw new Error(`Expected Array: ${t}`)}we(Map,(t,e,r)=>{const o=[...t.entries()].map(f=>[f[0],f[1],mt(f[0],r)]);if(r.rejectDuplicateKeys){const f=new Set;for(const[u,c,d]of o){const g=Ne(d);if(f.has(g))throw new Error(`Duplicate map key: 0x${g}`);f.add(g)}}r.sortKeys&&o.sort(r.sortKeys),Nr(t,t.size,Y.MAP,e,r);for(const[f,u,c]of o)e.write(c),ct(u,e,r)});function Lr(t){return rt(t.contents),new Date(t.contents)}Lr.comment=t=>{rt(t.contents);const e=new Date(t.contents);return`(String ${t.tag===ie.DATE_FULL?"Full ":""}Date) ${e.toISOString()}`},Z.registerDecoder(ie.DATE_STRING,Lr),Z.registerDecoder(ie.DATE_FULL,Lr);function Qn(t){return zt(t.contents),new Date(t.contents*1e3)}Qn.comment=t=>(zt(t.contents),`(Epoch Date) ${new Date(t.contents*1e3).toISOString()}`),Z.registerDecoder(ie.DATE_EPOCH,Qn);const Or=1e3*60*60*24;function ei(t){return zt(t.contents),new Date(t.contents*Or)}ei.comment=t=>(zt(t.contents),`(Epoch Date) ${new Date(t.contents*Or).toISOString()}`),Z.registerDecoder(ie.DATE_EPOCH_DAYS,ei),we(Date,(t,e,r)=>{switch(r.dateTag){case ie.DATE_EPOCH:return[r.dateTag,t.valueOf()/1e3];case ie.DATE_STRING:return[r.dateTag,t.toISOString().replace(/\.000Z$/,"Z")];case ie.DATE_EPOCH_DAYS:return[r.dateTag,Math.floor(t.valueOf()/Or)];case ie.DATE_FULL:return[r.dateTag,t.toISOString().split("T")[0]];default:throw new Error(`Unsupported date tag: ${r.dateTag}`)}});function Vt(t,e,r){if(Ze(e.contents),r.rejectBigInts)throw new Error(`Decoding unwanted big integer: ${e}(h'${Ne(e.contents)}')`);if(r.requirePreferred&&e.contents[0]===0)throw new Error(`Decoding overly-large bigint: ${e.tag}(h'${Ne(e.contents)})`);let o=e.contents.reduce((u,c)=>u<<8n|BigInt(c),0n);t&&(o=-1n-o);const f=o>=Number.MIN_SAFE_INTEGER&&o<=Number.MAX_SAFE_INTEGER;if(r.requirePreferred&&f)throw new Error(`Decoding bigint that could have been int: ${o}n`);return r.collapseBigInts&&f&&(o=Number(o)),r.boxed?xt(o,e.contents):o}const ti=Vt.bind(null,!1),ri=Vt.bind(null,!0);ti.comment=(t,e)=>`(Positive BigInt) ${Vt(!1,t,e)}n`,ri.comment=(t,e)=>`(Negative BigInt) ${Vt(!0,t,e)}n`,Z.registerDecoder(ie.POS_BIGINT,ti),Z.registerDecoder(ie.NEG_BIGINT,ri);function Mr(t,e){return Ze(t.contents),t}Mr.comment=(t,e,r)=>{Ze(t.contents);const o={...e,initialDepth:r+2,noPrefixHex:!0},f=Pt(t);let u=2**((f[0]&31)-24)+1;const c=f[u]&31;let d=Ne(f.subarray(u,++u));c>=24&&(d+=" ",d+=Ne(f.subarray(u,u+2**(c-24)))),o.minCol=Math.max(o.minCol,(r+1)*2+d.length);const g=Xn(t.contents,o);let b=`Embedded CBOR
12
12
  `;return b+=`${"".padStart((r+1)*2," ")}${d}`.padEnd(o.minCol+1," "),b+=`-- Bytes (Length: ${t.contents.length})
13
- `,b+=g,b},Mr.noChildren=!0,Z.registerDecoder(ie.CBOR,Mr),Z.registerDecoder(ie.URI,t=>(rt(t.contents),new URL(t.contents)),"URI"),we(URL,t=>[ie.URI,t.toString()]),Z.registerDecoder(ie.BASE64URL,t=>(rt(t.contents),ki(t.contents)),"Base64url-encoded"),Z.registerDecoder(ie.BASE64,t=>(rt(t.contents),Rr(t.contents)),"Base64-encoded"),Z.registerDecoder(35,t=>(rt(t.contents),new RegExp(t.contents)),"RegExp"),Z.registerDecoder(21065,t=>{rt(t.contents);const e=`^(?:${t.contents})$`;return new RegExp(e,"u")},"I-RegExp"),Z.registerDecoder(ie.REGEXP,t=>{if(Zn(t.contents),t.contents.length<1||t.contents.length>2)throw new Error(`Invalid RegExp Array: ${t.contents}`);return new RegExp(t.contents[0],t.contents[1])},"RegExp"),we(RegExp,t=>[ie.REGEXP,[t.source,t.flags]]),Z.registerDecoder(64,t=>(Ze(t.contents),t.contents),"uint8 Typed Array");function Be(t,e,r){Ze(t.contents);let o=t.contents.length;if(o%e.BYTES_PER_ELEMENT!==0)throw new Error(`Number of bytes must be divisible by ${e.BYTES_PER_ELEMENT}, got: ${o}`);o/=e.BYTES_PER_ELEMENT;const f=new e(o),u=new DataView(t.contents.buffer,t.contents.byteOffset,t.contents.byteLength),c=u[`get${e.name.replace(/Array/,"")}`].bind(u);for(let d=0;d<o;d++)f[d]=c(d*e.BYTES_PER_ELEMENT,r);return f}function nt(t,e,r,o,f){const u=f.forceEndian??Jn;if(It(u?e:r,t,f),Oe(o.byteLength,t,Y.BYTE_STRING),Jn===u)t.write(new Uint8Array(o.buffer,o.byteOffset,o.byteLength));else{const c=`write${o.constructor.name.replace(/Array/,"")}`,d=t[c].bind(t);for(const g of o)d(g,u)}}Z.registerDecoder(65,t=>Be(t,Uint16Array,!1),"uint16, big endian, Typed Array"),Z.registerDecoder(66,t=>Be(t,Uint32Array,!1),"uint32, big endian, Typed Array"),Z.registerDecoder(67,t=>Be(t,BigUint64Array,!1),"uint64, big endian, Typed Array"),Z.registerDecoder(68,t=>(Ze(t.contents),new Uint8ClampedArray(t.contents)),"uint8 Typed Array, clamped arithmetic"),we(Uint8ClampedArray,t=>[68,new Uint8Array(t.buffer,t.byteOffset,t.byteLength)]),Z.registerDecoder(69,t=>Be(t,Uint16Array,!0),"uint16, little endian, Typed Array"),we(Uint16Array,(t,e,r)=>nt(e,69,65,t,r)),Z.registerDecoder(70,t=>Be(t,Uint32Array,!0),"uint32, little endian, Typed Array"),we(Uint32Array,(t,e,r)=>nt(e,70,66,t,r)),Z.registerDecoder(71,t=>Be(t,BigUint64Array,!0),"uint64, little endian, Typed Array"),we(BigUint64Array,(t,e,r)=>nt(e,71,67,t,r)),Z.registerDecoder(72,t=>(Ze(t.contents),new Int8Array(t.contents)),"sint8 Typed Array"),we(Int8Array,t=>[72,new Uint8Array(t.buffer,t.byteOffset,t.byteLength)]),Z.registerDecoder(73,t=>Be(t,Int16Array,!1),"sint16, big endian, Typed Array"),Z.registerDecoder(74,t=>Be(t,Int32Array,!1),"sint32, big endian, Typed Array"),Z.registerDecoder(75,t=>Be(t,BigInt64Array,!1),"sint64, big endian, Typed Array"),Z.registerDecoder(77,t=>Be(t,Int16Array,!0),"sint16, little endian, Typed Array"),we(Int16Array,(t,e,r)=>nt(e,77,73,t,r)),Z.registerDecoder(78,t=>Be(t,Int32Array,!0),"sint32, little endian, Typed Array"),we(Int32Array,(t,e,r)=>nt(e,78,74,t,r)),Z.registerDecoder(79,t=>Be(t,BigInt64Array,!0),"sint64, little endian, Typed Array"),we(BigInt64Array,(t,e,r)=>nt(e,79,75,t,r)),Z.registerDecoder(81,t=>Be(t,Float32Array,!1),"IEEE 754 binary32, big endian, Typed Array"),Z.registerDecoder(82,t=>Be(t,Float64Array,!1),"IEEE 754 binary64, big endian, Typed Array"),Z.registerDecoder(85,t=>Be(t,Float32Array,!0),"IEEE 754 binary32, little endian, Typed Array"),we(Float32Array,(t,e,r)=>nt(e,85,81,t,r)),Z.registerDecoder(86,t=>Be(t,Float64Array,!0),"IEEE 754 binary64, big endian, Typed Array"),we(Float64Array,(t,e,r)=>nt(e,86,82,t,r)),Z.registerDecoder(ie.SET,(t,e)=>{if(Zn(t.contents),e.sortKeys){const r=Fe.decodeToEncodeOpts(e);let o=null;for(const f of t.contents){const u=[f,void 0,mt(f,r)];if(o&&e.sortKeys(o,u)>=0)throw new Error(`Set items out of order in tag #${ie.SET}`);o=u}}return new Set(t.contents)},"Set"),we(Set,(t,e,r)=>{let o=[...t];if(r.sortKeys){const f=o.map(u=>[u,void 0,mt(u,r)]);f.sort(r.sortKeys),o=f.map(([u])=>u)}return[ie.SET,o]}),Z.registerDecoder(ie.JSON,t=>(rt(t.contents),JSON.parse(t.contents)),"JSON-encoded");function ni(t){return Ze(t.contents),new Gt().decode(t.contents)}ni.comment=t=>{Ze(t.contents);const e=new Gt;return`(WTF8 string): ${JSON.stringify(e.decode(t.contents))}`},Z.registerDecoder(ie.WTF8,ni),Z.registerDecoder(ie.SELF_DESCRIBED,t=>t.contents,"Self-Described"),Z.registerDecoder(ie.INVALID_16,()=>{throw new Error(`Tag always invalid: ${ie.INVALID_16}`)},"Invalid"),Z.registerDecoder(ie.INVALID_32,()=>{throw new Error(`Tag always invalid: ${ie.INVALID_32}`)},"Invalid"),Z.registerDecoder(ie.INVALID_64,()=>{throw new Error(`Tag always invalid: ${ie.INVALID_64}`)},"Invalid");function Dr(t){throw new Error(`Encoding ${t.constructor.name} intentionally unimplmented. It is not concrete enough to interoperate. Convert to Uint8Array first.`)}we(ArrayBuffer,Dr),we(DataView,Dr),typeof SharedArrayBuffer<"u"&&we(SharedArrayBuffer,Dr);function Xt(t){return[NaN,t.valueOf()]}we(Boolean,Xt),we(Number,Xt),we(String,Xt),we(BigInt,Xt);function Ro(t){const e={...Fe.defaultDecodeOptions};if(t.dcbor?Object.assign(e,Fe.dcborDecodeOptions):t.cde&&Object.assign(e,Fe.cdeDecodeOptions),Object.assign(e,t),Object.hasOwn(e,"rejectLongNumbers"))throw new TypeError("rejectLongNumbers has changed to requirePreferred");return e.boxed&&(e.saveOriginal=!0),e}let Io=class{parent=void 0;ret=void 0;step(e,r,o){if(this.ret=Fe.create(e,this.parent,r,o),e[2]===Ie.BREAK)if(this.parent?.isStreaming)this.parent.left=0;else throw new Error("Unexpected BREAK");else this.parent&&this.parent.push(this.ret,o,e[3]);for(this.ret instanceof Fe&&(this.parent=this.ret);this.parent?.done;){this.ret=this.parent.convert(o);const f=this.parent.parent;f?.replaceLast(this.ret,this.parent,o),this.parent=f}}};function Bo(t,e={}){const r=Ro(e),o=new Kt(t,r),f=new Io;for(const u of o)f.step(u,r,o);return f.ret}const{cdeDecodeOptions:Go,dcborDecodeOptions:Wo,defaultDecodeOptions:Ho}=Fe;class Ao{constructor(e={}){this.options={id:bt(),codec:"cbor",timeout:10*1e3,chunkSize:16*1024,topicMake:(r,o,f)=>`${r}/${o}/${f??"any"}`,topicMatch:r=>{const o=r.match(/^(.+)\/([^/]+)\/([^/]+)$/);return o?{name:o[1],operation:o[2],peerId:o[3]==="any"?void 0:o[3]}:null},...e}}}class ii{static uint8ArrayToBase64(e){return btoa(String.fromCharCode(...e))}static base64ToUint8Array(e){const r=atob(e),o=new Uint8Array(r.length);for(let f=0;f<r.length;f++)o[f]=r.charCodeAt(f);return o}static stringify(e){return JSON.stringify(e,(r,o)=>o instanceof Uint8Array?{__Uint8Array:this.uint8ArrayToBase64(o)}:o)}static parse(e){return JSON.parse(e,(r,o)=>o?.__Uint8Array?this.base64ToUint8Array(o.__Uint8Array):o)}}class No{constructor(e){this.type=e,this.types=new Rn,this.tags=new Map;const r=64e3;this.types.registerEncoder(tr,o=>[r,new Uint8Array(o.buffer,o.byteOffset,o.byteLength)]),this.tags.set(r,o=>tr.from(o.contents))}encode(e){let r;if(this.type==="cbor")try{r=mt(e,{types:this.types})}catch{throw new Error("failed to encode CBOR format")}else if(this.type==="json")try{r=ii.stringify(e)}catch{throw new Error("failed to encode JSON format")}else throw new Error("invalid format");return r}decode(e){let r;if(this.type==="cbor"&&typeof e=="object"&&e instanceof Uint8Array)try{r=Bo(e,{tags:this.tags})}catch{throw new Error("failed to decode CBOR format")}else if(this.type==="json"&&typeof e=="string")try{r=ii.parse(e)}catch{throw new Error("failed to decode JSON format")}else throw new Error("invalid format or wrong data type");return r}}class Fo extends Ao{constructor(e={}){super(e),this.codec=new No(this.options.codec)}}class At{constructor(e,r,o,f){this.type=e,this.id=r,this.sender=o,this.receiver=f}}class oi extends At{constructor(e,r,o,f,u){super("event-emission",e,f,u),this.event=r,this.params=o}}class si extends At{constructor(e,r,o,f,u){super("service-call-request",e,f,u),this.service=r,this.params=o}}class ai extends At{constructor(e,r,o,f,u){super("service-call-response",e,f,u),this.result=r,this.error=o}}class ui extends At{constructor(e,r,o,f,u){super("resource-transfer-request",e,f,u),this.resource=r,this.params=o}}class fi extends At{constructor(e,r,o,f,u,c,d,g,b){super("resource-transfer-response",e,g,b),this.resource=r,this.params=o,this.chunk=f,this.meta=u,this.error=c,this.final=d}}class Uo{makeEventEmission(e,r,o,f,u){return new oi(e,r,o,f,u)}makeServiceCallRequest(e,r,o,f,u){return new si(e,r,o,f,u)}makeServiceCallResponse(e,r,o,f,u){return new ai(e,r,o,f,u)}makeResourceTransferRequest(e,r,o,f,u){return new ui(e,r,o,f,u)}makeResourceTransferResponse(e,r,o,f,u,c,d,g,b){return new fi(e,r,o,f,u,c,d,g,b)}parse(e){if(typeof e!="object"||e===null)throw new Error("invalid argument: not an object");if(!("type"in e)||typeof e.type!="string")throw new Error('invalid object: missing or invalid "type" field');if(!("id"in e)||typeof e.id!="string")throw new Error('invalid object: missing or invalid "id" field');if("sender"in e&&e.sender!==void 0&&typeof e.sender!="string")throw new Error('invalid object: invalid "sender" field');if("receiver"in e&&e.receiver!==void 0&&typeof e.receiver!="string")throw new Error('invalid object: invalid "receiver" field');const r=(f,u)=>Object.keys(f).some(c=>!u.includes(c)),o=f=>f.params===void 0||typeof f.params=="object"&&Array.isArray(f.params);if(e.type==="event-emission"){if(typeof e.event!="string")throw new Error('invalid EventEmission object: "event" field must be a string');if(r(e,["type","id","event","params","sender","receiver"]))throw new Error("invalid EventEmission object: contains unknown fields");if(!o(e))throw new Error('invalid EventEmission object: "params" field must be an array');return this.makeEventEmission(e.id,e.event,e.params,e.sender,e.receiver)}else if(e.type==="service-call-request"){if(typeof e.service!="string")throw new Error('invalid ServiceCallRequest object: "service" field must be a string');if(r(e,["type","id","service","params","sender","receiver"]))throw new Error("invalid ServiceCallRequest object: contains unknown fields");if(!o(e))throw new Error('invalid ServiceCallRequest object: "params" field must be an array');return this.makeServiceCallRequest(e.id,e.service,e.params,e.sender,e.receiver)}else if(e.type==="service-call-response"){if(r(e,["type","id","result","error","sender","receiver"]))throw new Error("invalid ServiceCallResponse object: contains unknown fields");return this.makeServiceCallResponse(e.id,e.result,e.error,e.sender,e.receiver)}else if(e.type==="resource-transfer-request"){if(typeof e.resource!="string")throw new Error('invalid ResourceTransferRequest object: "resource" field must be a string');if(r(e,["type","id","resource","params","sender","receiver"]))throw new Error("invalid ResourceTransferRequest object: contains unknown fields");if(!o(e))throw new Error('invalid ResourceTransferRequest object: "params" field must be an array');return this.makeResourceTransferRequest(e.id,e.resource,e.params,e.sender,e.receiver)}else if(e.type==="resource-transfer-response"){if(e.resource!==void 0&&typeof e.resource!="string")throw new Error('invalid ResourceTransferResponse object: "resource" field must be a string');if(e.chunk!==void 0&&typeof e.chunk!="object")throw new Error('invalid ResourceTransferResponse object: "chunk" field must be an object');if(e.meta!==void 0&&(typeof e.meta!="object"||e.meta===null||Array.isArray(e.meta)))throw new Error('invalid ResourceTransferResponse object: "meta" field must be an object');if(e.error!==void 0&&typeof e.error!="string")throw new Error('invalid ResourceTransferResponse object: "error" field must be a string');if(e.final!==void 0&&typeof e.final!="boolean")throw new Error('invalid ResourceTransferResponse object: "final" field must be a boolean');if(!o(e))throw new Error('invalid ResourceTransferResponse object: "params" field must be an array');if(r(e,["type","id","resource","params","chunk","meta","error","final","sender","receiver"]))throw new Error("invalid ResourceTransferResponse object: contains unknown fields");return this.makeResourceTransferResponse(e.id,e.resource,e.params,e.chunk,e.meta,e.error,e.final,e.sender,e.receiver)}else throw new Error("invalid object: not of any known type")}}class Lo extends Fo{constructor(){super(...arguments),this.msg=new Uo}}class Oo extends Lo{constructor(e,r={}){super(r),this.mqtt=e,this._messageHandler=(o,f,u)=>{this._onMessage(o,f,u)},this.mqtt.on("message",this._messageHandler)}destroy(){this.mqtt.off("message",this._messageHandler)}async _subscribeTopic(e,r={}){return new Promise((o,f)=>{this.mqtt.subscribe(e,{qos:2,...r},(u,c)=>{u?f(u):o()})})}async _unsubscribeTopic(e){return new Promise((r,o)=>{this.mqtt.unsubscribe(e,(f,u)=>{f?o(f):r()})})}_onMessage(e,r,o){let f;try{let u=r;this.options.codec==="json"&&(u=r.toString());const c=this.codec.decode(u);f=this.msg.parse(c)}catch(u){const c=u instanceof Error?new Error(`failed to parse message: ${u.message}`):new Error("failed to parse message");this.mqtt.emit("error",c);return}this._dispatchMessage(e,f)}_dispatchMessage(e,r){}}class Mo extends Oo{constructor(){super(...arguments),this.subscriptions=new Map}async subscribe(e,...r){let o={},f=r[0];if(r.length===2&&typeof r[0]=="object"&&(o=r[0],f=r[1]),this.subscriptions.has(e))throw new Error(`subscribe: event "${e}" already subscribed`);const u=this.options.topicMake(e,"event-emission"),c=this.options.topicMake(e,"event-emission",this.options.id);await Promise.all([this._subscribeTopic(u,{qos:0,...o}),this._subscribeTopic(c,{qos:0,...o})]).catch(b=>{throw this._unsubscribeTopic(u).catch(()=>{}),this._unsubscribeTopic(c).catch(()=>{}),b}),this.subscriptions.set(e,f);const d=this;return{async unsubscribe(){if(!d.subscriptions.has(e))throw new Error(`unsubscribe: event "${e}" not subscribed`);return d.subscriptions.delete(e),Promise.all([d._unsubscribeTopic(u),d._unsubscribeTopic(c)]).then(()=>{})}}}emit(e,...r){let o,f,u,c={};typeof e=="object"&&e!==null?(o=e.event,f=e.params,u=e.receiver,c=e.options??{}):(o=e,f=r);const d=bt(),g=this.msg.makeEventEmission(d,o,f,this.options.id,u),b=this.codec.encode(g),p=this.options.topicMake(o,"event-emission",u);this.mqtt.publish(p,dt.from(b),{qos:0,...c})}_dispatchMessage(e,r){super._dispatchMessage(e,r);const o=this.options.topicMatch(e);if(o!==null&&o.operation==="event-emission"&&r instanceof oi){const f=r.event,u=this.subscriptions.get(f),c=r.params??[],d={sender:r.sender??""};r.receiver&&(d.receiver=r.receiver),Promise.resolve().then(()=>u?.(...c,d)).catch(g=>{this.mqtt.emit("error",g)})}}}class Do extends Mo{constructor(){super(...arguments),this.registrations=new Map,this.responseCallback=new Map,this.responseSubscriptions=new Map}async register(e,...r){let o={},f=r[0];if(r.length===2&&typeof r[0]=="object"&&(o=r[0],f=r[1]),this.registrations.has(e))throw new Error(`register: service "${e}" already registered`);const u=this.options.topicMake(e,"service-call-request"),c=this.options.topicMake(e,"service-call-request",this.options.id);await Promise.all([this._subscribeTopic(u,{qos:2,...o}),this._subscribeTopic(c,{qos:2,...o})]).catch(b=>{throw this._unsubscribeTopic(u).catch(()=>{}),this._unsubscribeTopic(c).catch(()=>{}),b}),this.registrations.set(e,f);const d=this;return{async unregister(){if(!d.registrations.has(e))throw new Error(`unregister: service "${e}" not registered`);return d.registrations.delete(e),Promise.all([d._unsubscribeTopic(u),d._unsubscribeTopic(c)]).then(()=>{})}}}call(e,...r){let o,f,u,c={};typeof e=="object"&&e!==null?(o=e.service,f=e.params,u=e.receiver,c=e.options??{}):(o=e,f=r);const d=bt();this._responseSubscribe(o,{qos:c.qos??2});const g=new Promise((O,q)=>{let k=setTimeout(()=>{this.responseCallback.delete(d),this._responseUnsubscribe(o),k=null,q(new Error("communication timeout"))},this.options.timeout);this.responseCallback.set(d,{service:o,callback:(W,j)=>{k!==null&&(clearTimeout(k),k=null),W?q(W):O(j)}})}),b=this.msg.makeServiceCallRequest(d,o,f,this.options.id,u),p=this.codec.encode(b),A=this.options.topicMake(o,"service-call-request",u);return this.mqtt.publish(A,dt.from(p),{qos:2,...c},O=>{if(O){const q=this.responseCallback.get(d);q!==void 0&&(this.responseCallback.delete(d),this._responseUnsubscribe(o),q.callback(O,void 0))}}),g}_responseSubscribe(e,r={qos:2}){const o=this.options.topicMake(e,"service-call-response",this.options.id);this.responseSubscriptions.has(o)||(this.responseSubscriptions.set(o,0),this.mqtt.subscribe(o,r,u=>{u&&this.mqtt.emit("error",u)}));const f=this.responseSubscriptions.get(o)??0;this.responseSubscriptions.set(o,f+1)}_responseUnsubscribe(e){const r=this.options.topicMake(e,"service-call-response",this.options.id);if(!this.responseSubscriptions.has(r))return;const o=this.responseSubscriptions.get(r)??0;this.responseSubscriptions.set(r,o-1),this.responseSubscriptions.get(r)===0&&(this.responseSubscriptions.delete(r),this.mqtt.unsubscribe(r,f=>{f&&this.mqtt.emit("error",f)}))}_dispatchMessage(e,r){super._dispatchMessage(e,r);const o=this.options.topicMatch(e);if(o!==null&&o.operation==="service-call-request"&&r instanceof si){const f=r.id,u=r.service,c=this.registrations.get(u);let d;if(c!==void 0){const g=r.params??[],b={sender:r.sender??""};r.receiver&&(b.receiver=r.receiver),d=Promise.resolve().then(()=>c(...g,b))}else d=Promise.reject(new Error(`method not found: ${u}`));d.then(g=>this.msg.makeServiceCallResponse(f,g,void 0,this.options.id,r.sender),g=>{let b;return g==null?b="undefined error":typeof g=="string"?b=g:g instanceof Error?b=g.message:b=String(g),this.msg.makeServiceCallResponse(f,void 0,b,this.options.id,r.sender)}).then(g=>{const b=r.sender;if(b===void 0)throw new Error("invalid request: missing sender");const p=this.codec.encode(g),A=this.options.topicMake(u,"service-call-response",b);this.mqtt.publish(A,dt.from(p),{qos:2})}).catch(g=>{this.mqtt.emit("error",g)})}else if(o!==null&&o.operation==="service-call-response"&&o.peerId===this.options.id&&r instanceof ai){const f=r.id,u=this.responseCallback.get(f);u!==void 0&&(r.error!==void 0?u.callback(new Error(r.error),void 0):u.callback(void 0,r.result),this.responseCallback.delete(f),this._responseUnsubscribe(u.service))}}}class Co extends Do{constructor(){super(...arguments),this.provisionings=new Map,this.callbacks=new Map,this.pushStreams=new Map,this.pushTimers=new Map}async provision(e,...r){let o={},f=r[0];if(r.length===2&&typeof r[0]=="object"&&(o=r[0],f=r[1]),this.provisionings.has(e))throw new Error(`provision: resource "${e}" already provisioned`);const u=this.options.topicMake(e,"resource-transfer-request"),c=this.options.topicMake(e,"resource-transfer-request",this.options.id),d=this.options.topicMake(e,"resource-transfer-response"),g=this.options.topicMake(e,"resource-transfer-response",this.options.id);await Promise.all([this._subscribeTopic(u,{qos:2,...o}),this._subscribeTopic(c,{qos:2,...o}),this._subscribeTopic(d,{qos:2,...o}),this._subscribeTopic(g,{qos:2,...o})]).catch(A=>{throw this._unsubscribeTopic(u).catch(()=>{}),this._unsubscribeTopic(c).catch(()=>{}),this._unsubscribeTopic(d).catch(()=>{}),this._unsubscribeTopic(g).catch(()=>{}),A}),this.provisionings.set(e,f);const b=this;return{async unprovision(){if(!b.provisionings.has(e))throw new Error(`unprovision: resource "${e}" not provisioned`);return b.provisionings.delete(e),Promise.all([b._unsubscribeTopic(u),b._unsubscribeTopic(c),b._unsubscribeTopic(d),b._unsubscribeTopic(g)]).then(()=>{})}}}push(e,...r){let o,f,u,c,d,g={};typeof e=="object"&&e!==null?(o=e.resource,f=e.data,u=e.params,c=e.meta,d=e.receiver,g=e.options??{}):(o=e,f=r[0],u=r.slice(1));const b=bt(),p=this.options.topicMake(o,"resource-transfer-response",d);let A=!0;const O=(q,k,W)=>{const j=A?c:void 0;A=!1;const x=this.msg.makeResourceTransferResponse(b,o,u,q,j,k,W,this.options.id,d),R=this.codec.encode(x);this.mqtt.publish(p,dt.from(R),{qos:2,...g})};return new Promise((q,k)=>{f instanceof Dt.Readable?Tn(f,this.options.chunkSize,O,()=>q(),W=>k(W)):f instanceof Uint8Array&&(_n(f,this.options.chunkSize,O),q())})}async fetch(e,...r){let o,f,u={},c;typeof e=="object"&&e!==null?(o=e.resource,c=e.params,f=e.receiver,u=e.options??{}):(o=e,c=r);const d=bt(),g=this.options.topicMake(o,"resource-transfer-response",this.options.id);await this._subscribeTopic(g,{qos:2});const b=new Dt.Readable({read(I){}}),p=mn(b);let A;const O=new Promise(I=>{A=I});let q=null;const k=(I=!1)=>{q!==null&&(clearTimeout(q),q=null),this._unsubscribeTopic(g).catch(()=>{}),this.callbacks.delete(d),I&&A?.(void 0)};q=setTimeout(()=>{k(),A?.(void 0),b.destroy(new Error("communication timeout"))},this.options.timeout);let W=!0;this.callbacks.set(d,{resource:o,callback:(I,_,v,F)=>{W&&(W=!1,A?.(v)),I!==void 0?(k(!0),b.destroy(I)):(_!==void 0&&b.push(_),F&&(k(),b.push(null)))}});const j=this.msg.makeResourceTransferRequest(d,o,c,this.options.id,f),x=this.codec.encode(j),R=this.options.topicMake(o,"resource-transfer-request",f);return this.mqtt.publish(R,dt.from(x),{qos:2,...u}),{stream:b,buffer:p,meta:O}}_dispatchMessage(e,r){super._dispatchMessage(e,r);const o=this.options.topicMatch(e);if(o!==null&&o.operation==="resource-transfer-request"&&r instanceof ui){const f=r.resource,u=this.provisionings.get(f);if(u!==void 0){const c=r.id,d=r.resource,g=r.params??[],b=r.sender??"",p=r.receiver,A={sender:b};p&&(A.receiver=p);const O=this.options.topicMake(d,"resource-transfer-response",b);let q=!0;const k=(W,j,x)=>{const R=q?A.meta:void 0;q=!1;const I=this.msg.makeResourceTransferResponse(c,d,void 0,W,R,j,x,this.options.id,b),_=dt.from(this.codec.encode(I));this.mqtt.publish(O,_,{qos:2})};Promise.resolve().then(()=>u(...g,A)).then(async()=>{if(A.stream instanceof Dt.Readable)Tn(A.stream,this.options.chunkSize,k,()=>{},W=>k(void 0,W.message,!0));else if(A.buffer!==void 0&&typeof A.buffer.then=="function")_n(await A.buffer,this.options.chunkSize,k);else throw new Error("handler did not provide data via info.stream or info.buffer field")}).catch(W=>{k(void 0,W.message,!0)})}}else if(o!==null&&o.operation==="resource-transfer-response"&&r instanceof fi){const f=r.id,u=r.error,c=r.meta,d=r.final,g=r.chunk!==void 0&&!(r.chunk instanceof Uint8Array)?Uint8Array.from(r.chunk):r.chunk,b=this.callbacks.get(f);if(b!==void 0)b.callback(u?new Error(u):void 0,g,c,d);else if(r.resource!==void 0){const p=r.resource,A=this.provisionings.get(p);if(A!==void 0){let O=this.pushStreams.get(f);if(O===void 0){O=new Dt.Readable({read(R){}}),this.pushStreams.set(f,O);const k=setTimeout(()=>{const R=this.pushStreams.get(f);R!==void 0&&(R.destroy(new Error("push stream timeout")),this.pushStreams.delete(f),this.pushTimers.delete(f))},this.options.timeout);this.pushTimers.set(f,k);const W=mn(O),j=r.params??[],x={sender:r.sender??""};r.receiver&&(x.receiver=r.receiver),r.meta&&(x.meta=c),x.stream=O,x.buffer=W,Promise.resolve().then(()=>A(...j,x)).catch(R=>{this.mqtt.emit("error",R)})}const q=()=>{const k=this.pushTimers.get(f);k!==void 0&&(clearTimeout(k),this.pushTimers.delete(f))};u!==void 0?(q(),O.destroy(new Error(u)),this.pushStreams.delete(f)):(g!==void 0&&O.push(g),d&&(q(),O.push(null),this.pushStreams.delete(f)))}}}}}class Po extends Co{}return Po}));
13
+ `,b+=g,b},Mr.noChildren=!0,Z.registerDecoder(ie.CBOR,Mr),Z.registerDecoder(ie.URI,t=>(rt(t.contents),new URL(t.contents)),"URI"),we(URL,t=>[ie.URI,t.toString()]),Z.registerDecoder(ie.BASE64URL,t=>(rt(t.contents),ki(t.contents)),"Base64url-encoded"),Z.registerDecoder(ie.BASE64,t=>(rt(t.contents),Rr(t.contents)),"Base64-encoded"),Z.registerDecoder(35,t=>(rt(t.contents),new RegExp(t.contents)),"RegExp"),Z.registerDecoder(21065,t=>{rt(t.contents);const e=`^(?:${t.contents})$`;return new RegExp(e,"u")},"I-RegExp"),Z.registerDecoder(ie.REGEXP,t=>{if(Zn(t.contents),t.contents.length<1||t.contents.length>2)throw new Error(`Invalid RegExp Array: ${t.contents}`);return new RegExp(t.contents[0],t.contents[1])},"RegExp"),we(RegExp,t=>[ie.REGEXP,[t.source,t.flags]]),Z.registerDecoder(64,t=>(Ze(t.contents),t.contents),"uint8 Typed Array");function Be(t,e,r){Ze(t.contents);let o=t.contents.length;if(o%e.BYTES_PER_ELEMENT!==0)throw new Error(`Number of bytes must be divisible by ${e.BYTES_PER_ELEMENT}, got: ${o}`);o/=e.BYTES_PER_ELEMENT;const f=new e(o),u=new DataView(t.contents.buffer,t.contents.byteOffset,t.contents.byteLength),c=u[`get${e.name.replace(/Array/,"")}`].bind(u);for(let d=0;d<o;d++)f[d]=c(d*e.BYTES_PER_ELEMENT,r);return f}function nt(t,e,r,o,f){const u=f.forceEndian??Jn;if(It(u?e:r,t,f),Oe(o.byteLength,t,Y.BYTE_STRING),Jn===u)t.write(new Uint8Array(o.buffer,o.byteOffset,o.byteLength));else{const c=`write${o.constructor.name.replace(/Array/,"")}`,d=t[c].bind(t);for(const g of o)d(g,u)}}Z.registerDecoder(65,t=>Be(t,Uint16Array,!1),"uint16, big endian, Typed Array"),Z.registerDecoder(66,t=>Be(t,Uint32Array,!1),"uint32, big endian, Typed Array"),Z.registerDecoder(67,t=>Be(t,BigUint64Array,!1),"uint64, big endian, Typed Array"),Z.registerDecoder(68,t=>(Ze(t.contents),new Uint8ClampedArray(t.contents)),"uint8 Typed Array, clamped arithmetic"),we(Uint8ClampedArray,t=>[68,new Uint8Array(t.buffer,t.byteOffset,t.byteLength)]),Z.registerDecoder(69,t=>Be(t,Uint16Array,!0),"uint16, little endian, Typed Array"),we(Uint16Array,(t,e,r)=>nt(e,69,65,t,r)),Z.registerDecoder(70,t=>Be(t,Uint32Array,!0),"uint32, little endian, Typed Array"),we(Uint32Array,(t,e,r)=>nt(e,70,66,t,r)),Z.registerDecoder(71,t=>Be(t,BigUint64Array,!0),"uint64, little endian, Typed Array"),we(BigUint64Array,(t,e,r)=>nt(e,71,67,t,r)),Z.registerDecoder(72,t=>(Ze(t.contents),new Int8Array(t.contents)),"sint8 Typed Array"),we(Int8Array,t=>[72,new Uint8Array(t.buffer,t.byteOffset,t.byteLength)]),Z.registerDecoder(73,t=>Be(t,Int16Array,!1),"sint16, big endian, Typed Array"),Z.registerDecoder(74,t=>Be(t,Int32Array,!1),"sint32, big endian, Typed Array"),Z.registerDecoder(75,t=>Be(t,BigInt64Array,!1),"sint64, big endian, Typed Array"),Z.registerDecoder(77,t=>Be(t,Int16Array,!0),"sint16, little endian, Typed Array"),we(Int16Array,(t,e,r)=>nt(e,77,73,t,r)),Z.registerDecoder(78,t=>Be(t,Int32Array,!0),"sint32, little endian, Typed Array"),we(Int32Array,(t,e,r)=>nt(e,78,74,t,r)),Z.registerDecoder(79,t=>Be(t,BigInt64Array,!0),"sint64, little endian, Typed Array"),we(BigInt64Array,(t,e,r)=>nt(e,79,75,t,r)),Z.registerDecoder(81,t=>Be(t,Float32Array,!1),"IEEE 754 binary32, big endian, Typed Array"),Z.registerDecoder(82,t=>Be(t,Float64Array,!1),"IEEE 754 binary64, big endian, Typed Array"),Z.registerDecoder(85,t=>Be(t,Float32Array,!0),"IEEE 754 binary32, little endian, Typed Array"),we(Float32Array,(t,e,r)=>nt(e,85,81,t,r)),Z.registerDecoder(86,t=>Be(t,Float64Array,!0),"IEEE 754 binary64, big endian, Typed Array"),we(Float64Array,(t,e,r)=>nt(e,86,82,t,r)),Z.registerDecoder(ie.SET,(t,e)=>{if(Zn(t.contents),e.sortKeys){const r=Fe.decodeToEncodeOpts(e);let o=null;for(const f of t.contents){const u=[f,void 0,mt(f,r)];if(o&&e.sortKeys(o,u)>=0)throw new Error(`Set items out of order in tag #${ie.SET}`);o=u}}return new Set(t.contents)},"Set"),we(Set,(t,e,r)=>{let o=[...t];if(r.sortKeys){const f=o.map(u=>[u,void 0,mt(u,r)]);f.sort(r.sortKeys),o=f.map(([u])=>u)}return[ie.SET,o]}),Z.registerDecoder(ie.JSON,t=>(rt(t.contents),JSON.parse(t.contents)),"JSON-encoded");function ni(t){return Ze(t.contents),new Gt().decode(t.contents)}ni.comment=t=>{Ze(t.contents);const e=new Gt;return`(WTF8 string): ${JSON.stringify(e.decode(t.contents))}`},Z.registerDecoder(ie.WTF8,ni),Z.registerDecoder(ie.SELF_DESCRIBED,t=>t.contents,"Self-Described"),Z.registerDecoder(ie.INVALID_16,()=>{throw new Error(`Tag always invalid: ${ie.INVALID_16}`)},"Invalid"),Z.registerDecoder(ie.INVALID_32,()=>{throw new Error(`Tag always invalid: ${ie.INVALID_32}`)},"Invalid"),Z.registerDecoder(ie.INVALID_64,()=>{throw new Error(`Tag always invalid: ${ie.INVALID_64}`)},"Invalid");function Dr(t){throw new Error(`Encoding ${t.constructor.name} intentionally unimplmented. It is not concrete enough to interoperate. Convert to Uint8Array first.`)}we(ArrayBuffer,Dr),we(DataView,Dr),typeof SharedArrayBuffer<"u"&&we(SharedArrayBuffer,Dr);function Xt(t){return[NaN,t.valueOf()]}we(Boolean,Xt),we(Number,Xt),we(String,Xt),we(BigInt,Xt);function Ro(t){const e={...Fe.defaultDecodeOptions};if(t.dcbor?Object.assign(e,Fe.dcborDecodeOptions):t.cde&&Object.assign(e,Fe.cdeDecodeOptions),Object.assign(e,t),Object.hasOwn(e,"rejectLongNumbers"))throw new TypeError("rejectLongNumbers has changed to requirePreferred");return e.boxed&&(e.saveOriginal=!0),e}let Io=class{parent=void 0;ret=void 0;step(e,r,o){if(this.ret=Fe.create(e,this.parent,r,o),e[2]===Ie.BREAK)if(this.parent?.isStreaming)this.parent.left=0;else throw new Error("Unexpected BREAK");else this.parent&&this.parent.push(this.ret,o,e[3]);for(this.ret instanceof Fe&&(this.parent=this.ret);this.parent?.done;){this.ret=this.parent.convert(o);const f=this.parent.parent;f?.replaceLast(this.ret,this.parent,o),this.parent=f}}};function Bo(t,e={}){const r=Ro(e),o=new Kt(t,r),f=new Io;for(const u of o)f.step(u,r,o);return f.ret}const{cdeDecodeOptions:Go,dcborDecodeOptions:Wo,defaultDecodeOptions:Ho}=Fe;class Ao{constructor(e={}){this.options={id:bt(),codec:"cbor",timeout:10*1e3,chunkSize:16*1024,topicMake:(r,o,f)=>`${r}/${o}/${f??"any"}`,topicMatch:r=>{const o=r.match(/^(.+)\/([^/]+)\/([^/]+)$/);return o?{name:o[1],operation:o[2],peerId:o[3]==="any"?void 0:o[3]}:null},...e}}}class ii{static uint8ArrayToBase64(e){return btoa(String.fromCharCode(...e))}static base64ToUint8Array(e){const r=atob(e),o=new Uint8Array(r.length);for(let f=0;f<r.length;f++)o[f]=r.charCodeAt(f);return o}static stringify(e){return JSON.stringify(e,(r,o)=>o instanceof Uint8Array?{__Uint8Array:this.uint8ArrayToBase64(o)}:o)}static parse(e){return JSON.parse(e,(r,o)=>typeof o?.__Uint8Array=="string"?this.base64ToUint8Array(o.__Uint8Array):o)}}class No{constructor(e){this.type=e,this.types=new Rn,this.tags=new Map;const r=64e3;this.types.registerEncoder(tr,o=>[r,new Uint8Array(o.buffer,o.byteOffset,o.byteLength)]),this.tags.set(r,o=>tr.from(o.contents))}encode(e){let r;if(this.type==="cbor")try{r=mt(e,{types:this.types})}catch{throw new Error("failed to encode CBOR format")}else if(this.type==="json")try{r=ii.stringify(e)}catch{throw new Error("failed to encode JSON format")}else throw new Error("invalid format");return r}decode(e){let r;if(this.type==="cbor"&&typeof e=="object"&&e instanceof Uint8Array)try{r=Bo(e,{tags:this.tags})}catch{throw new Error("failed to decode CBOR format")}else if(this.type==="json"&&typeof e=="string")try{r=ii.parse(e)}catch{throw new Error("failed to decode JSON format")}else throw new Error("invalid format or wrong data type");return r}}class Fo extends Ao{constructor(e={}){super(e),this.codec=new No(this.options.codec)}}class At{constructor(e,r,o,f){this.type=e,this.id=r,this.sender=o,this.receiver=f}}class oi extends At{constructor(e,r,o,f,u){super("event-emission",e,f,u),this.event=r,this.params=o}}class si extends At{constructor(e,r,o,f,u){super("service-call-request",e,f,u),this.service=r,this.params=o}}class ai extends At{constructor(e,r,o,f,u){super("service-call-response",e,f,u),this.result=r,this.error=o}}class ui extends At{constructor(e,r,o,f,u){super("resource-transfer-request",e,f,u),this.resource=r,this.params=o}}class fi extends At{constructor(e,r,o,f,u,c,d,g,b){super("resource-transfer-response",e,g,b),this.resource=r,this.params=o,this.chunk=f,this.meta=u,this.error=c,this.final=d}}class Uo{makeEventEmission(e,r,o,f,u){return new oi(e,r,o,f,u)}makeServiceCallRequest(e,r,o,f,u){return new si(e,r,o,f,u)}makeServiceCallResponse(e,r,o,f,u){return new ai(e,r,o,f,u)}makeResourceTransferRequest(e,r,o,f,u){return new ui(e,r,o,f,u)}makeResourceTransferResponse(e,r,o,f,u,c,d,g,b){return new fi(e,r,o,f,u,c,d,g,b)}parse(e){if(typeof e!="object"||e===null)throw new Error("invalid argument: not an object");if(!("type"in e)||typeof e.type!="string")throw new Error('invalid object: missing or invalid "type" field');if(!("id"in e)||typeof e.id!="string")throw new Error('invalid object: missing or invalid "id" field');if("sender"in e&&e.sender!==void 0&&typeof e.sender!="string")throw new Error('invalid object: invalid "sender" field');if("receiver"in e&&e.receiver!==void 0&&typeof e.receiver!="string")throw new Error('invalid object: invalid "receiver" field');const r=(f,u)=>Object.keys(f).some(c=>!u.includes(c)),o=f=>f.params===void 0||typeof f.params=="object"&&Array.isArray(f.params);if(e.type==="event-emission"){if(typeof e.event!="string")throw new Error('invalid EventEmission object: "event" field must be a string');if(r(e,["type","id","event","params","sender","receiver"]))throw new Error("invalid EventEmission object: contains unknown fields");if(!o(e))throw new Error('invalid EventEmission object: "params" field must be an array');return this.makeEventEmission(e.id,e.event,e.params,e.sender,e.receiver)}else if(e.type==="service-call-request"){if(typeof e.service!="string")throw new Error('invalid ServiceCallRequest object: "service" field must be a string');if(r(e,["type","id","service","params","sender","receiver"]))throw new Error("invalid ServiceCallRequest object: contains unknown fields");if(!o(e))throw new Error('invalid ServiceCallRequest object: "params" field must be an array');return this.makeServiceCallRequest(e.id,e.service,e.params,e.sender,e.receiver)}else if(e.type==="service-call-response"){if(r(e,["type","id","result","error","sender","receiver"]))throw new Error("invalid ServiceCallResponse object: contains unknown fields");return this.makeServiceCallResponse(e.id,e.result,e.error,e.sender,e.receiver)}else if(e.type==="resource-transfer-request"){if(typeof e.resource!="string")throw new Error('invalid ResourceTransferRequest object: "resource" field must be a string');if(r(e,["type","id","resource","params","sender","receiver"]))throw new Error("invalid ResourceTransferRequest object: contains unknown fields");if(!o(e))throw new Error('invalid ResourceTransferRequest object: "params" field must be an array');return this.makeResourceTransferRequest(e.id,e.resource,e.params,e.sender,e.receiver)}else if(e.type==="resource-transfer-response"){if(e.resource!==void 0&&typeof e.resource!="string")throw new Error('invalid ResourceTransferResponse object: "resource" field must be a string');if(e.chunk!==void 0&&typeof e.chunk!="object")throw new Error('invalid ResourceTransferResponse object: "chunk" field must be an object');if(e.meta!==void 0&&(typeof e.meta!="object"||e.meta===null||Array.isArray(e.meta)))throw new Error('invalid ResourceTransferResponse object: "meta" field must be an object');if(e.error!==void 0&&typeof e.error!="string")throw new Error('invalid ResourceTransferResponse object: "error" field must be a string');if(e.final!==void 0&&typeof e.final!="boolean")throw new Error('invalid ResourceTransferResponse object: "final" field must be a boolean');if(!o(e))throw new Error('invalid ResourceTransferResponse object: "params" field must be an array');if(r(e,["type","id","resource","params","chunk","meta","error","final","sender","receiver"]))throw new Error("invalid ResourceTransferResponse object: contains unknown fields");return this.makeResourceTransferResponse(e.id,e.resource,e.params,e.chunk,e.meta,e.error,e.final,e.sender,e.receiver)}else throw new Error("invalid object: not of any known type")}}class Lo extends Fo{constructor(){super(...arguments),this.msg=new Uo}}class Oo extends Lo{constructor(e,r={}){super(r),this.mqtt=e,this._messageHandler=(o,f,u)=>{this._onMessage(o,f,u)},this.mqtt.on("message",this._messageHandler)}destroy(){this.mqtt.off("message",this._messageHandler)}async _subscribeTopic(e,r={}){return new Promise((o,f)=>{this.mqtt.subscribe(e,{qos:2,...r},(u,c)=>{u?f(u):o()})})}async _unsubscribeTopic(e){return new Promise((r,o)=>{this.mqtt.unsubscribe(e,(f,u)=>{f?o(f):r()})})}_onMessage(e,r,o){let f;try{let u=r;this.options.codec==="json"&&(u=r.toString());const c=this.codec.decode(u);f=this.msg.parse(c)}catch(u){const c=u instanceof Error?new Error(`failed to parse message: ${u.message}`):new Error("failed to parse message");this.mqtt.emit("error",c);return}this._dispatchMessage(e,f)}_dispatchMessage(e,r){}}class Mo extends Oo{constructor(){super(...arguments),this.subscriptions=new Map}async subscribe(e,...r){let o={},f=r[0];if(r.length===2&&typeof r[0]=="object"&&(o=r[0],f=r[1]),this.subscriptions.has(e))throw new Error(`subscribe: event "${e}" already subscribed`);const u=this.options.topicMake(e,"event-emission"),c=this.options.topicMake(e,"event-emission",this.options.id);await Promise.all([this._subscribeTopic(u,{qos:0,...o}),this._subscribeTopic(c,{qos:0,...o})]).catch(b=>{throw this._unsubscribeTopic(u).catch(()=>{}),this._unsubscribeTopic(c).catch(()=>{}),b}),this.subscriptions.set(e,f);const d=this;return{async unsubscribe(){if(!d.subscriptions.has(e))throw new Error(`unsubscribe: event "${e}" not subscribed`);return d.subscriptions.delete(e),Promise.all([d._unsubscribeTopic(u),d._unsubscribeTopic(c)]).then(()=>{})}}}emit(e,...r){let o,f,u,c={};typeof e=="object"&&e!==null?(o=e.event,f=e.params,u=e.receiver,c=e.options??{}):(o=e,f=r);const d=bt(),g=this.msg.makeEventEmission(d,o,f,this.options.id,u),b=this.codec.encode(g),p=this.options.topicMake(o,"event-emission",u);this.mqtt.publish(p,dt.from(b),{qos:0,...c})}_dispatchMessage(e,r){super._dispatchMessage(e,r);const o=this.options.topicMatch(e);if(o!==null&&o.operation==="event-emission"&&r instanceof oi){const f=r.event,u=this.subscriptions.get(f),c=r.params??[],d={sender:r.sender??""};r.receiver&&(d.receiver=r.receiver),Promise.resolve().then(()=>u?.(...c,d)).catch(g=>{this.mqtt.emit("error",g)})}}}class Do extends Mo{constructor(){super(...arguments),this.registrations=new Map,this.responseCallback=new Map,this.responseSubscriptions=new Map}async register(e,...r){let o={},f=r[0];if(r.length===2&&typeof r[0]=="object"&&(o=r[0],f=r[1]),this.registrations.has(e))throw new Error(`register: service "${e}" already registered`);const u=this.options.topicMake(e,"service-call-request"),c=this.options.topicMake(e,"service-call-request",this.options.id);await Promise.all([this._subscribeTopic(u,{qos:2,...o}),this._subscribeTopic(c,{qos:2,...o})]).catch(b=>{throw this._unsubscribeTopic(u).catch(()=>{}),this._unsubscribeTopic(c).catch(()=>{}),b}),this.registrations.set(e,f);const d=this;return{async unregister(){if(!d.registrations.has(e))throw new Error(`unregister: service "${e}" not registered`);return d.registrations.delete(e),Promise.all([d._unsubscribeTopic(u),d._unsubscribeTopic(c)]).then(()=>{})}}}call(e,...r){let o,f,u,c={};typeof e=="object"&&e!==null?(o=e.service,f=e.params,u=e.receiver,c=e.options??{}):(o=e,f=r);const d=bt();this._responseSubscribe(o,{qos:c.qos??2});const g=new Promise((O,q)=>{let k=setTimeout(()=>{this.responseCallback.delete(d),this._responseUnsubscribe(o),k=null,q(new Error("communication timeout"))},this.options.timeout);this.responseCallback.set(d,{service:o,callback:(W,j)=>{k!==null&&(clearTimeout(k),k=null),W?q(W):O(j)}})}),b=this.msg.makeServiceCallRequest(d,o,f,this.options.id,u),p=this.codec.encode(b),A=this.options.topicMake(o,"service-call-request",u);return this.mqtt.publish(A,dt.from(p),{qos:2,...c},O=>{if(O){const q=this.responseCallback.get(d);q!==void 0&&(this.responseCallback.delete(d),this._responseUnsubscribe(o),q.callback(O,void 0))}}),g}_responseSubscribe(e,r={qos:2}){const o=this.options.topicMake(e,"service-call-response",this.options.id);this.responseSubscriptions.has(o)||(this.responseSubscriptions.set(o,0),this.mqtt.subscribe(o,r,u=>{if(u){const c=this.responseSubscriptions.get(o)??0;c>1?this.responseSubscriptions.set(o,c-1):this.responseSubscriptions.delete(o),this.mqtt.emit("error",u)}}));const f=this.responseSubscriptions.get(o)??0;this.responseSubscriptions.set(o,f+1)}_responseUnsubscribe(e){const r=this.options.topicMake(e,"service-call-response",this.options.id);if(!this.responseSubscriptions.has(r))return;const o=this.responseSubscriptions.get(r)??0;o>1?this.responseSubscriptions.set(r,o-1):(this.responseSubscriptions.delete(r),this.mqtt.unsubscribe(r,f=>{f&&this.mqtt.emit("error",f)}))}_dispatchMessage(e,r){super._dispatchMessage(e,r);const o=this.options.topicMatch(e);if(o!==null&&o.operation==="service-call-request"&&r instanceof si){const f=r.id,u=r.service,c=this.registrations.get(u);let d;if(c!==void 0){const g=r.params??[],b={sender:r.sender??""};r.receiver&&(b.receiver=r.receiver),d=Promise.resolve().then(()=>c(...g,b))}else d=Promise.reject(new Error(`method not found: ${u}`));d.then(g=>this.msg.makeServiceCallResponse(f,g,void 0,this.options.id,r.sender),g=>{let b;return g==null?b="undefined error":typeof g=="string"?b=g:g instanceof Error?b=g.message:b=String(g),this.msg.makeServiceCallResponse(f,void 0,b,this.options.id,r.sender)}).then(g=>{const b=r.sender;if(b===void 0)throw new Error("invalid request: missing sender");const p=this.codec.encode(g),A=this.options.topicMake(u,"service-call-response",b);this.mqtt.publish(A,dt.from(p),{qos:2})}).catch(g=>{this.mqtt.emit("error",g)})}else if(o!==null&&o.operation==="service-call-response"&&o.peerId===this.options.id&&r instanceof ai){const f=r.id,u=this.responseCallback.get(f);u!==void 0&&(r.error!==void 0?u.callback(new Error(r.error),void 0):u.callback(void 0,r.result),this.responseCallback.delete(f),this._responseUnsubscribe(u.service))}}}class Co extends Do{constructor(){super(...arguments),this.provisionings=new Map,this.callbacks=new Map,this.pushStreams=new Map,this.pushTimers=new Map}async provision(e,...r){let o={},f=r[0];if(r.length===2&&typeof r[0]=="object"&&(o=r[0],f=r[1]),this.provisionings.has(e))throw new Error(`provision: resource "${e}" already provisioned`);const u=this.options.topicMake(e,"resource-transfer-request"),c=this.options.topicMake(e,"resource-transfer-request",this.options.id),d=this.options.topicMake(e,"resource-transfer-response"),g=this.options.topicMake(e,"resource-transfer-response",this.options.id);await Promise.all([this._subscribeTopic(u,{qos:2,...o}),this._subscribeTopic(c,{qos:2,...o}),this._subscribeTopic(d,{qos:2,...o}),this._subscribeTopic(g,{qos:2,...o})]).catch(A=>{throw this._unsubscribeTopic(u).catch(()=>{}),this._unsubscribeTopic(c).catch(()=>{}),this._unsubscribeTopic(d).catch(()=>{}),this._unsubscribeTopic(g).catch(()=>{}),A}),this.provisionings.set(e,f);const b=this;return{async unprovision(){if(!b.provisionings.has(e))throw new Error(`unprovision: resource "${e}" not provisioned`);return b.provisionings.delete(e),Promise.all([b._unsubscribeTopic(u),b._unsubscribeTopic(c),b._unsubscribeTopic(d),b._unsubscribeTopic(g)]).then(()=>{})}}}push(e,...r){let o,f,u,c,d,g={};typeof e=="object"&&e!==null?(o=e.resource,f=e.data,u=e.params,c=e.meta,d=e.receiver,g=e.options??{}):(o=e,f=r[0],u=r.slice(1));const b=bt(),p=this.options.topicMake(o,"resource-transfer-response",d);let A=!0;const O=(q,k,W)=>{const j=A?c:void 0;A=!1;const x=this.msg.makeResourceTransferResponse(b,o,u,q,j,k,W,this.options.id,d),R=this.codec.encode(x);this.mqtt.publish(p,dt.from(R),{qos:2,...g})};return new Promise((q,k)=>{f instanceof Dt.Readable?Tn(f,this.options.chunkSize,O,()=>q(),W=>k(W)):f instanceof Uint8Array&&(_n(f,this.options.chunkSize,O),q())})}async fetch(e,...r){let o,f,u={},c;typeof e=="object"&&e!==null?(o=e.resource,c=e.params,f=e.receiver,u=e.options??{}):(o=e,c=r);const d=bt(),g=this.options.topicMake(o,"resource-transfer-response",this.options.id);await this._subscribeTopic(g,{qos:2});const b=new Dt.Readable({read(I){}}),p=mn(b);let A;const O=new Promise(I=>{A=I});let q=null;const k=(I=!1)=>{q!==null&&(clearTimeout(q),q=null),this._unsubscribeTopic(g).catch(()=>{}),this.callbacks.delete(d),I&&A?.(void 0)};q=setTimeout(()=>{k(),A?.(void 0),b.destroy(new Error("communication timeout"))},this.options.timeout);let W=!0;this.callbacks.set(d,{resource:o,callback:(I,_,v,F)=>{W&&(W=!1,A?.(v)),I!==void 0?(k(!0),b.destroy(I)):(_!==void 0&&b.push(_),F&&(k(),b.push(null)))}});const j=this.msg.makeResourceTransferRequest(d,o,c,this.options.id,f),x=this.codec.encode(j),R=this.options.topicMake(o,"resource-transfer-request",f);return this.mqtt.publish(R,dt.from(x),{qos:2,...u}),{stream:b,buffer:p,meta:O}}_dispatchMessage(e,r){super._dispatchMessage(e,r);const o=this.options.topicMatch(e);if(o!==null&&o.operation==="resource-transfer-request"&&r instanceof ui){const f=r.resource,u=this.provisionings.get(f);if(u!==void 0){const c=r.id,d=r.resource,g=r.params??[],b=r.sender??"",p=r.receiver,A={sender:b};p&&(A.receiver=p);const O=this.options.topicMake(d,"resource-transfer-response",b);let q=!0;const k=(W,j,x)=>{const R=q?A.meta:void 0;q=!1;const I=this.msg.makeResourceTransferResponse(c,d,void 0,W,R,j,x,this.options.id,b),_=dt.from(this.codec.encode(I));this.mqtt.publish(O,_,{qos:2})};Promise.resolve().then(()=>u(...g,A)).then(async()=>{if(A.stream instanceof Dt.Readable)Tn(A.stream,this.options.chunkSize,k,()=>{},W=>k(void 0,W.message,!0));else if(A.buffer!==void 0&&typeof A.buffer.then=="function")_n(await A.buffer,this.options.chunkSize,k);else throw new Error("handler did not provide data via info.stream or info.buffer field")}).catch(W=>{k(void 0,W.message,!0)})}}else if(o!==null&&o.operation==="resource-transfer-response"&&r instanceof fi){const f=r.id,u=r.error,c=r.meta,d=r.final,g=r.chunk!==void 0&&!(r.chunk instanceof Uint8Array)?Uint8Array.from(r.chunk):r.chunk,b=this.callbacks.get(f);if(b!==void 0)b.callback(u?new Error(u):void 0,g,c,d);else if(r.resource!==void 0){const p=r.resource,A=this.provisionings.get(p);if(A!==void 0){let O=this.pushStreams.get(f);if(O===void 0){O=new Dt.Readable({read(R){}}),this.pushStreams.set(f,O);const k=setTimeout(()=>{const R=this.pushStreams.get(f);R!==void 0&&(R.destroy(new Error("push stream timeout")),this.pushStreams.delete(f),this.pushTimers.delete(f))},this.options.timeout);this.pushTimers.set(f,k);const W=mn(O),j=r.params??[],x={sender:r.sender??""};r.receiver&&(x.receiver=r.receiver),r.meta&&(x.meta=c),x.stream=O,x.buffer=W,Promise.resolve().then(()=>A(...j,x)).catch(R=>{this.mqtt.emit("error",R)})}const q=()=>{const k=this.pushTimers.get(f);k!==void 0&&(clearTimeout(k),this.pushTimers.delete(f))};u!==void 0?(q(),O.destroy(new Error(u)),this.pushStreams.delete(f)):(g!==void 0&&O.push(g),d&&(q(),O.push(null),this.pushStreams.delete(f)))}}}}}class Po extends Co{}return Po}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mqtt-plus",
3
- "version": "0.9.15",
3
+ "version": "0.9.16",
4
4
  "description": "MQTT Communication Patterns",
5
5
  "keywords": [ "mqtt",
6
6
  "event", "emit",
@@ -34,7 +34,7 @@ class JSONX {
34
34
  private static uint8ArrayToBase64 (arr: Uint8Array): string {
35
35
  return btoa(String.fromCharCode(...arr))
36
36
  }
37
- private static base64ToUint8Array(base64: string): Uint8Array {
37
+ private static base64ToUint8Array (base64: string): Uint8Array {
38
38
  const binary = atob(base64)
39
39
  const arr = new Uint8Array(binary.length)
40
40
  for (let i = 0; i < binary.length; i++)
@@ -50,7 +50,7 @@ class JSONX {
50
50
  }
51
51
  static parse (json: string): any {
52
52
  return JSON.parse(json, (_, value) =>
53
- value?.__Uint8Array
53
+ typeof value?.__Uint8Array === "string"
54
54
  ? this.base64ToUint8Array(value.__Uint8Array)
55
55
  : value
56
56
  )
@@ -208,8 +208,14 @@ export class ServiceTrait<T extends APISchema = APISchema> extends EventTrait<T>
208
208
  if (!this.responseSubscriptions.has(topic)) {
209
209
  this.responseSubscriptions.set(topic, 0)
210
210
  this.mqtt.subscribe(topic, options, (err: Error | null) => {
211
- if (err)
211
+ if (err) {
212
+ const count = this.responseSubscriptions.get(topic) ?? 0
213
+ if (count > 1)
214
+ this.responseSubscriptions.set(topic, count - 1)
215
+ else
216
+ this.responseSubscriptions.delete(topic)
212
217
  this.mqtt.emit("error", err)
218
+ }
213
219
  })
214
220
  }
215
221
  const count = this.responseSubscriptions.get(topic) ?? 0
@@ -227,8 +233,9 @@ export class ServiceTrait<T extends APISchema = APISchema> extends EventTrait<T>
227
233
 
228
234
  /* unsubscribe from MQTT topic and forget subscription */
229
235
  const count = this.responseSubscriptions.get(topic) ?? 0
230
- this.responseSubscriptions.set(topic, count - 1)
231
- if (this.responseSubscriptions.get(topic) === 0) {
236
+ if (count > 1)
237
+ this.responseSubscriptions.set(topic, count - 1)
238
+ else {
232
239
  this.responseSubscriptions.delete(topic)
233
240
  this.mqtt.unsubscribe(topic, (err?: Error) => {
234
241
  if (err)