mqtt-plus 1.4.18 → 1.4.19

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
  ChangeLog
3
3
  =========
4
4
 
5
+ 1.4.19 (2026-04-18)
6
+ -------------------
7
+
8
+ - IMPROVEMENT: improve error handling in source and sink traits
9
+ - UPDATE: upgrade NPM dependencies
10
+
5
11
  1.4.18 (2026-04-17)
6
12
  -------------------
7
13
 
@@ -22,4 +22,3 @@
22
22
  ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
24
  export {};
25
- //# sourceMappingURL=mqtt-plus-api.js.map
@@ -127,4 +127,3 @@ export class AuthTrait extends MetaTrait {
127
127
  return authenticated;
128
128
  }
129
129
  }
130
- //# sourceMappingURL=mqtt-plus-auth.js.map
@@ -233,4 +233,3 @@ export class BaseTrait extends TraceTrait {
233
233
  }
234
234
  }
235
235
  }
236
- //# sourceMappingURL=mqtt-plus-base.js.map
@@ -121,4 +121,3 @@ export class CodecTrait extends OptionsTrait {
121
121
  this.codec = new Codec(this.options.codec);
122
122
  }
123
123
  }
124
- //# sourceMappingURL=mqtt-plus-codec.js.map
@@ -60,4 +60,3 @@ export class EncodeTrait extends CodecTrait {
60
60
  return arr;
61
61
  }
62
62
  }
63
- //# sourceMappingURL=mqtt-plus-encode.js.map
@@ -290,4 +290,3 @@ export function run(...args) {
290
290
  return result;
291
291
  }
292
292
  }
293
- //# sourceMappingURL=mqtt-plus-error.js.map
@@ -186,4 +186,3 @@ export class EventTrait extends AuthTrait {
186
186
  return run(`publish event as MQTT message to topic "${topic}"`, () => this.publishToTopic(topic, message, { qos: 2, ...options }));
187
187
  }
188
188
  }
189
- //# sourceMappingURL=mqtt-plus-event.js.map
@@ -22,4 +22,3 @@
22
22
  ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
24
  export {};
25
- //# sourceMappingURL=mqtt-plus-info.js.map
@@ -53,4 +53,3 @@ export class MetaTrait extends TimerTrait {
53
53
  return { ...Object.fromEntries(this._meta), ...extra };
54
54
  }
55
55
  }
56
- //# sourceMappingURL=mqtt-plus-meta.js.map
@@ -370,4 +370,3 @@ export class MsgTrait extends EncodeTrait {
370
370
  this.msg = new Msg();
371
371
  }
372
372
  }
373
- //# sourceMappingURL=mqtt-plus-msg.js.map
@@ -50,4 +50,3 @@ export class OptionsTrait {
50
50
  };
51
51
  }
52
52
  }
53
- //# sourceMappingURL=mqtt-plus-options.js.map
@@ -303,4 +303,3 @@ export class ServiceTrait extends EventTrait {
303
303
  return promise;
304
304
  }
305
305
  }
306
- //# sourceMappingURL=mqtt-plus-service.js.map
@@ -120,8 +120,6 @@ export class SinkTrait extends SourceTrait {
120
120
  const receiver = request.receiver;
121
121
  /* create a resource spool for request cleanup */
122
122
  const reqSpool = new Spool();
123
- this.pushSpools.set(requestId, reqSpool);
124
- reqSpool.roll(() => { this.pushSpools.delete(requestId); });
125
123
  /* sanity check sender */
126
124
  if (sender === undefined || sender === "") {
127
125
  this.error(new Error("invalid request: missing sender"));
@@ -162,6 +160,8 @@ export class SinkTrait extends SourceTrait {
162
160
  }
163
161
  this.pushRecvControllers.set(requestId, abortController);
164
162
  reqSpool.roll(() => { this.pushRecvControllers.delete(requestId); });
163
+ this.pushSpools.set(requestId, reqSpool);
164
+ reqSpool.roll(() => { this.pushSpools.delete(requestId); });
165
165
  /* check authentication and prepare stream */
166
166
  let dataCompleted = false;
167
167
  let ackSent = false;
@@ -358,10 +358,9 @@ export class SinkTrait extends SourceTrait {
358
358
  await sendResponse(undefined, true);
359
359
  ackSent = true;
360
360
  /* call handler */
361
- await Promise.race([
362
- Promise.resolve(callback(...params, info)),
363
- abortPromise
364
- ]);
361
+ const callbackPromise = Promise.resolve(callback(...params, info));
362
+ callbackPromise.catch(() => { }); /* guard against unhandled rejection if abort wins the race */
363
+ await Promise.race([callbackPromise, abortPromise]);
365
364
  /* ensure stream is consumed or destroyed to prevent hang */
366
365
  if (readable.readableFlowing !== true && !readable.destroyed)
367
366
  readable.resume();
@@ -395,10 +394,14 @@ export class SinkTrait extends SourceTrait {
395
394
  if (stream !== undefined && !stream.destroyed)
396
395
  stream.destroy(error);
397
396
  }
398
- /* send error as nak response or as mid-stream error response */
397
+ /* send error as nak response or as mid-stream error response
398
+ (skip when a terminal signal was already emitted, e.g. the
399
+ pre-emptive credit=0 cancel published by the timeout handler) */
399
400
  this.error(error);
400
- errorResponseSent = true;
401
- await sendResponse(error.message).catch(() => { });
401
+ if (!errorResponseSent) {
402
+ errorResponseSent = true;
403
+ await sendResponse(error.message).catch(() => { });
404
+ }
402
405
  }
403
406
  finally {
404
407
  /* cleanup resources */
@@ -625,6 +628,17 @@ export class SinkTrait extends SourceTrait {
625
628
  creditGate.replenish(response.credit);
626
629
  refreshTimeout();
627
630
  }
631
+ else if (pushAcked && initialCredit === undefined) {
632
+ /* protocol violation: receiver sent credit despite
633
+ not granting initial credit during ack */
634
+ const error = new Error(`push to sink "${name}" received unsolicited credit (credit-flow disabled)`);
635
+ remoteErrorObject = error;
636
+ abortController.abort(error);
637
+ if (!pushFinalized) {
638
+ pushFinalized = true;
639
+ pushFinalizeReject(error);
640
+ }
641
+ }
628
642
  else
629
643
  pendingCredit += response.credit;
630
644
  });
@@ -660,6 +674,9 @@ export class SinkTrait extends SourceTrait {
660
674
  refreshTimeout();
661
675
  pendingCredit = 0;
662
676
  }
677
+ else if (pendingCredit > 0)
678
+ /* protocol violation: receiver sent credit before ack despite not granting initial credit */
679
+ throw new Error(`push to sink "${name}" received unsolicited credit (credit-flow disabled)`);
663
680
  /* register credit gate at instance level */
664
681
  if (creditGate) {
665
682
  this.pushCreditGates.set(requestId, creditGate);
@@ -736,4 +753,3 @@ export class SinkTrait extends SourceTrait {
736
753
  }
737
754
  }
738
755
  }
739
- //# sourceMappingURL=mqtt-plus-sink.js.map
@@ -199,9 +199,8 @@ export class SourceTrait extends ServiceTrait {
199
199
  try {
200
200
  if (topicName !== request.name)
201
201
  throw new Error(`source name mismatch (topic: "${topicName}", payload: "${request.name}")`);
202
- if (auth)
203
- info.authenticated = await this.authenticated(sender, request.auth, auth, `source "${name}"`);
204
- /* register credit/cancel handler (unconditional for cancel support) */
202
+ /* register credit/cancel handler early (before any await) so cancel
203
+ signals arriving during async authentication are not lost */
205
204
  this.onResponse.set(`source-fetch-credit:${requestId}`, (creditParsed) => {
206
205
  if (abortSignal.aborted)
207
206
  return;
@@ -229,10 +228,13 @@ export class SourceTrait extends ServiceTrait {
229
228
  reqSpool.roll(() => {
230
229
  this.onResponse.delete(`source-fetch-credit:${requestId}`);
231
230
  });
232
- await Promise.race([
233
- Promise.resolve(callback(...params, info)),
234
- abortPromise
235
- ]);
231
+ /* check for authentication */
232
+ if (auth)
233
+ info.authenticated = await this.authenticated(sender, request.auth, auth, `source "${name}"`);
234
+ /* finally call the handler callback */
235
+ const callbackPromise = Promise.resolve(callback(...params, info));
236
+ callbackPromise.catch(() => { }); /* guard against unhandled rejection if abort wins the race */
237
+ await Promise.race([callbackPromise, abortPromise]);
236
238
  /* check for valid data source */
237
239
  if (!(info.stream instanceof Readable) && !(info.buffer instanceof Promise) && !(info.buffer instanceof Uint8Array))
238
240
  throw new Error("handler did not provide data via info.stream or info.buffer fields");
@@ -259,9 +261,14 @@ export class SourceTrait extends ServiceTrait {
259
261
  await sendStreamAsChunks(info.stream, this.options.chunkSize, sendChunk, creditGate, abortSignal);
260
262
  else if (info.buffer instanceof Promise || info.buffer instanceof Uint8Array) {
261
263
  /* handle Buffer result */
262
- const buffer = (info.buffer instanceof Promise)
263
- ? await Promise.race([info.buffer, abortPromise])
264
- : info.buffer;
264
+ let buffer;
265
+ if (info.buffer instanceof Promise) {
266
+ const bufferPromise = info.buffer;
267
+ bufferPromise.catch(() => { }); /* guard against unhandled rejection if abort wins the race */
268
+ buffer = await Promise.race([bufferPromise, abortPromise]);
269
+ }
270
+ else
271
+ buffer = info.buffer;
265
272
  /* re-check abort: a late info.buffer resolution could win the race */
266
273
  /* by a microtask margin even after abort fired -- discard silently */
267
274
  abortSignal.throwIfAborted();
@@ -557,4 +564,3 @@ export class SourceTrait extends ServiceTrait {
557
564
  return result;
558
565
  }
559
566
  }
560
- //# sourceMappingURL=mqtt-plus-source.js.map
@@ -180,4 +180,3 @@ export class SubscriptionTrait extends BaseTrait {
180
180
  await super.destroy();
181
181
  }
182
182
  }
183
- //# sourceMappingURL=mqtt-plus-subscription.js.map
@@ -113,4 +113,3 @@ export class TimerTrait extends SubscriptionTrait {
113
113
  });
114
114
  }
115
115
  }
116
- //# sourceMappingURL=mqtt-plus-timer.js.map
@@ -109,4 +109,3 @@ export class TraceTrait extends MsgTrait {
109
109
  }
110
110
  }
111
111
  }
112
- //# sourceMappingURL=mqtt-plus-trace.js.map
@@ -245,4 +245,3 @@ export function makeMutuallyExclusiveFields(obj, f1Name, f2Name, onConsumed) {
245
245
  configurable: true
246
246
  });
247
247
  }
248
- //# sourceMappingURL=mqtt-plus-util.js.map
@@ -38,4 +38,3 @@ export const MIN_VERSION = "0.0";
38
38
  /* package version (numeric format) */
39
39
  export const version = versionToNum(VERSION);
40
40
  export const minVersion = versionToNum(MIN_VERSION);
41
- //# sourceMappingURL=mqtt-plus-version.js.map
@@ -25,4 +25,3 @@ import { SinkTrait } from "./mqtt-plus-sink";
25
25
  /* export the default API class */
26
26
  export default class MQTTp extends SinkTrait {
27
27
  }
28
- //# sourceMappingURL=mqtt-plus.js.map
@@ -1 +1 @@
1
- {"root":["../src/mqtt-plus-api.ts","../src/mqtt-plus-auth.ts","../src/mqtt-plus-base.ts","../src/mqtt-plus-codec.ts","../src/mqtt-plus-encode.ts","../src/mqtt-plus-error.ts","../src/mqtt-plus-event.ts","../src/mqtt-plus-info.ts","../src/mqtt-plus-meta.ts","../src/mqtt-plus-msg.ts","../src/mqtt-plus-options.ts","../src/mqtt-plus-service.ts","../src/mqtt-plus-sink.ts","../src/mqtt-plus-source.ts","../src/mqtt-plus-subscription.ts","../src/mqtt-plus-timer.ts","../src/mqtt-plus-trace.ts","../src/mqtt-plus-util.ts","../src/mqtt-plus-version.ts","../src/mqtt-plus.ts"],"version":"6.0.2"}
1
+ {"root":["../src/mqtt-plus-api.ts","../src/mqtt-plus-auth.ts","../src/mqtt-plus-base.ts","../src/mqtt-plus-codec.ts","../src/mqtt-plus-encode.ts","../src/mqtt-plus-error.ts","../src/mqtt-plus-event.ts","../src/mqtt-plus-info.ts","../src/mqtt-plus-meta.ts","../src/mqtt-plus-msg.ts","../src/mqtt-plus-options.ts","../src/mqtt-plus-service.ts","../src/mqtt-plus-sink.ts","../src/mqtt-plus-source.ts","../src/mqtt-plus-subscription.ts","../src/mqtt-plus-timer.ts","../src/mqtt-plus-trace.ts","../src/mqtt-plus-util.ts","../src/mqtt-plus-version.ts","../src/mqtt-plus.ts"],"version":"6.0.3"}
@@ -1824,7 +1824,6 @@ var SourceTrait = class extends ServiceTrait {
1824
1824
  let cancelledByFetcher = false;
1825
1825
  try {
1826
1826
  if (topicName !== request.name) throw new Error(`source name mismatch (topic: "${topicName}", payload: "${request.name}")`);
1827
- if (auth) info.authenticated = await this.authenticated(sender, request.auth, auth, `source "${name}"`);
1828
1827
  this.onResponse.set(`source-fetch-credit:${requestId}`, (creditParsed) => {
1829
1828
  if (abortSignal.aborted) return;
1830
1829
  if (creditParsed.name !== name) {
@@ -1849,7 +1848,10 @@ var SourceTrait = class extends ServiceTrait {
1849
1848
  reqSpool.roll(() => {
1850
1849
  this.onResponse.delete(`source-fetch-credit:${requestId}`);
1851
1850
  });
1852
- await Promise.race([Promise.resolve(callback(...params, info)), abortPromise]);
1851
+ if (auth) info.authenticated = await this.authenticated(sender, request.auth, auth, `source "${name}"`);
1852
+ const callbackPromise = Promise.resolve(callback(...params, info));
1853
+ callbackPromise.catch(() => {});
1854
+ await Promise.race([callbackPromise, abortPromise]);
1853
1855
  if (!(info.stream instanceof node_stream.Readable) && !(info.buffer instanceof Promise) && !(info.buffer instanceof Uint8Array)) throw new Error("handler did not provide data via info.stream or info.buffer fields");
1854
1856
  if (info.stream instanceof node_stream.Readable && (info.buffer instanceof Promise || info.buffer instanceof Uint8Array)) throw new Error("handler has set both info.stream and info.buffer fields");
1855
1857
  const initialCredit = request.credit;
@@ -1866,7 +1868,12 @@ var SourceTrait = class extends ServiceTrait {
1866
1868
  ackSent = true;
1867
1869
  if (info.stream instanceof node_stream.Readable) await sendStreamAsChunks(info.stream, this.options.chunkSize, sendChunk, creditGate, abortSignal);
1868
1870
  else if (info.buffer instanceof Promise || info.buffer instanceof Uint8Array) {
1869
- const buffer = info.buffer instanceof Promise ? await Promise.race([info.buffer, abortPromise]) : info.buffer;
1871
+ let buffer;
1872
+ if (info.buffer instanceof Promise) {
1873
+ const bufferPromise = info.buffer;
1874
+ bufferPromise.catch(() => {});
1875
+ buffer = await Promise.race([bufferPromise, abortPromise]);
1876
+ } else buffer = info.buffer;
1870
1877
  abortSignal.throwIfAborted();
1871
1878
  await sendBufferAsChunks(buffer, this.options.chunkSize, sendChunk, creditGate, abortSignal);
1872
1879
  }
@@ -2164,10 +2171,6 @@ var SinkTrait = class extends SourceTrait {
2164
2171
  const sender = request.sender;
2165
2172
  const receiver = request.receiver;
2166
2173
  const reqSpool = new Spool();
2167
- this.pushSpools.set(requestId, reqSpool);
2168
- reqSpool.roll(() => {
2169
- this.pushSpools.delete(requestId);
2170
- });
2171
2174
  if (sender === void 0 || sender === "") {
2172
2175
  this.error(/* @__PURE__ */ new Error("invalid request: missing sender"));
2173
2176
  await reqSpool.unroll();
@@ -2208,6 +2211,10 @@ var SinkTrait = class extends SourceTrait {
2208
2211
  reqSpool.roll(() => {
2209
2212
  this.pushRecvControllers.delete(requestId);
2210
2213
  });
2214
+ this.pushSpools.set(requestId, reqSpool);
2215
+ reqSpool.roll(() => {
2216
+ this.pushSpools.delete(requestId);
2217
+ });
2211
2218
  let dataCompleted = false;
2212
2219
  let ackSent = false;
2213
2220
  let errorResponseSent = false;
@@ -2367,7 +2374,9 @@ var SinkTrait = class extends SourceTrait {
2367
2374
  });
2368
2375
  await sendResponse(void 0, true);
2369
2376
  ackSent = true;
2370
- await Promise.race([Promise.resolve(callback(...params, info)), abortPromise]);
2377
+ const callbackPromise = Promise.resolve(callback(...params, info));
2378
+ callbackPromise.catch(() => {});
2379
+ await Promise.race([callbackPromise, abortPromise]);
2371
2380
  if (readable.readableFlowing !== true && !readable.destroyed) readable.resume();
2372
2381
  await streamDone.catch((err) => {
2373
2382
  this.error(ensureError(err), `stream drain after sink "${name}" callback failed`);
@@ -2388,8 +2397,10 @@ var SinkTrait = class extends SourceTrait {
2388
2397
  if (stream !== void 0 && !stream.destroyed) stream.destroy(error);
2389
2398
  }
2390
2399
  this.error(error);
2391
- errorResponseSent = true;
2392
- await sendResponse(error.message).catch(() => {});
2400
+ if (!errorResponseSent) {
2401
+ errorResponseSent = true;
2402
+ await sendResponse(error.message).catch(() => {});
2403
+ }
2393
2404
  } finally {
2394
2405
  const stream = this.pushStreams.get(requestId);
2395
2406
  if (stream !== void 0 && !stream.destroyed && !dataCompleted && !errorResponseSent) stream.destroy(abortSignal.aborted ? ensureError(abortSignal.reason) : /* @__PURE__ */ new Error("sink push aborted without cause"));
@@ -2572,6 +2583,14 @@ var SinkTrait = class extends SourceTrait {
2572
2583
  if (creditGate !== void 0) {
2573
2584
  creditGate.replenish(response.credit);
2574
2585
  refreshTimeout();
2586
+ } else if (pushAcked && initialCredit === void 0) {
2587
+ const error = /* @__PURE__ */ new Error(`push to sink "${name}" received unsolicited credit (credit-flow disabled)`);
2588
+ remoteErrorObject = error;
2589
+ abortController.abort(error);
2590
+ if (!pushFinalized) {
2591
+ pushFinalized = true;
2592
+ pushFinalizeReject(error);
2593
+ }
2575
2594
  } else pendingCredit += response.credit;
2576
2595
  });
2577
2596
  spool.roll(() => {
@@ -2607,7 +2626,7 @@ var SinkTrait = class extends SourceTrait {
2607
2626
  creditGate = new CreditGate(initialCredit + pendingCredit);
2608
2627
  if (pendingCredit > 0) refreshTimeout();
2609
2628
  pendingCredit = 0;
2610
- }
2629
+ } else if (pendingCredit > 0) throw new Error(`push to sink "${name}" received unsolicited credit (credit-flow disabled)`);
2611
2630
  if (creditGate) {
2612
2631
  this.pushCreditGates.set(requestId, creditGate);
2613
2632
  spool.roll(() => {
@@ -1797,7 +1797,6 @@ var SourceTrait = class extends ServiceTrait {
1797
1797
  let cancelledByFetcher = false;
1798
1798
  try {
1799
1799
  if (topicName !== request.name) throw new Error(`source name mismatch (topic: "${topicName}", payload: "${request.name}")`);
1800
- if (auth) info.authenticated = await this.authenticated(sender, request.auth, auth, `source "${name}"`);
1801
1800
  this.onResponse.set(`source-fetch-credit:${requestId}`, (creditParsed) => {
1802
1801
  if (abortSignal.aborted) return;
1803
1802
  if (creditParsed.name !== name) {
@@ -1822,7 +1821,10 @@ var SourceTrait = class extends ServiceTrait {
1822
1821
  reqSpool.roll(() => {
1823
1822
  this.onResponse.delete(`source-fetch-credit:${requestId}`);
1824
1823
  });
1825
- await Promise.race([Promise.resolve(callback(...params, info)), abortPromise]);
1824
+ if (auth) info.authenticated = await this.authenticated(sender, request.auth, auth, `source "${name}"`);
1825
+ const callbackPromise = Promise.resolve(callback(...params, info));
1826
+ callbackPromise.catch(() => {});
1827
+ await Promise.race([callbackPromise, abortPromise]);
1826
1828
  if (!(info.stream instanceof Readable) && !(info.buffer instanceof Promise) && !(info.buffer instanceof Uint8Array)) throw new Error("handler did not provide data via info.stream or info.buffer fields");
1827
1829
  if (info.stream instanceof Readable && (info.buffer instanceof Promise || info.buffer instanceof Uint8Array)) throw new Error("handler has set both info.stream and info.buffer fields");
1828
1830
  const initialCredit = request.credit;
@@ -1839,7 +1841,12 @@ var SourceTrait = class extends ServiceTrait {
1839
1841
  ackSent = true;
1840
1842
  if (info.stream instanceof Readable) await sendStreamAsChunks(info.stream, this.options.chunkSize, sendChunk, creditGate, abortSignal);
1841
1843
  else if (info.buffer instanceof Promise || info.buffer instanceof Uint8Array) {
1842
- const buffer = info.buffer instanceof Promise ? await Promise.race([info.buffer, abortPromise]) : info.buffer;
1844
+ let buffer;
1845
+ if (info.buffer instanceof Promise) {
1846
+ const bufferPromise = info.buffer;
1847
+ bufferPromise.catch(() => {});
1848
+ buffer = await Promise.race([bufferPromise, abortPromise]);
1849
+ } else buffer = info.buffer;
1843
1850
  abortSignal.throwIfAborted();
1844
1851
  await sendBufferAsChunks(buffer, this.options.chunkSize, sendChunk, creditGate, abortSignal);
1845
1852
  }
@@ -2137,10 +2144,6 @@ var SinkTrait = class extends SourceTrait {
2137
2144
  const sender = request.sender;
2138
2145
  const receiver = request.receiver;
2139
2146
  const reqSpool = new Spool();
2140
- this.pushSpools.set(requestId, reqSpool);
2141
- reqSpool.roll(() => {
2142
- this.pushSpools.delete(requestId);
2143
- });
2144
2147
  if (sender === void 0 || sender === "") {
2145
2148
  this.error(/* @__PURE__ */ new Error("invalid request: missing sender"));
2146
2149
  await reqSpool.unroll();
@@ -2181,6 +2184,10 @@ var SinkTrait = class extends SourceTrait {
2181
2184
  reqSpool.roll(() => {
2182
2185
  this.pushRecvControllers.delete(requestId);
2183
2186
  });
2187
+ this.pushSpools.set(requestId, reqSpool);
2188
+ reqSpool.roll(() => {
2189
+ this.pushSpools.delete(requestId);
2190
+ });
2184
2191
  let dataCompleted = false;
2185
2192
  let ackSent = false;
2186
2193
  let errorResponseSent = false;
@@ -2340,7 +2347,9 @@ var SinkTrait = class extends SourceTrait {
2340
2347
  });
2341
2348
  await sendResponse(void 0, true);
2342
2349
  ackSent = true;
2343
- await Promise.race([Promise.resolve(callback(...params, info)), abortPromise]);
2350
+ const callbackPromise = Promise.resolve(callback(...params, info));
2351
+ callbackPromise.catch(() => {});
2352
+ await Promise.race([callbackPromise, abortPromise]);
2344
2353
  if (readable.readableFlowing !== true && !readable.destroyed) readable.resume();
2345
2354
  await streamDone.catch((err) => {
2346
2355
  this.error(ensureError(err), `stream drain after sink "${name}" callback failed`);
@@ -2361,8 +2370,10 @@ var SinkTrait = class extends SourceTrait {
2361
2370
  if (stream !== void 0 && !stream.destroyed) stream.destroy(error);
2362
2371
  }
2363
2372
  this.error(error);
2364
- errorResponseSent = true;
2365
- await sendResponse(error.message).catch(() => {});
2373
+ if (!errorResponseSent) {
2374
+ errorResponseSent = true;
2375
+ await sendResponse(error.message).catch(() => {});
2376
+ }
2366
2377
  } finally {
2367
2378
  const stream = this.pushStreams.get(requestId);
2368
2379
  if (stream !== void 0 && !stream.destroyed && !dataCompleted && !errorResponseSent) stream.destroy(abortSignal.aborted ? ensureError(abortSignal.reason) : /* @__PURE__ */ new Error("sink push aborted without cause"));
@@ -2545,6 +2556,14 @@ var SinkTrait = class extends SourceTrait {
2545
2556
  if (creditGate !== void 0) {
2546
2557
  creditGate.replenish(response.credit);
2547
2558
  refreshTimeout();
2559
+ } else if (pushAcked && initialCredit === void 0) {
2560
+ const error = /* @__PURE__ */ new Error(`push to sink "${name}" received unsolicited credit (credit-flow disabled)`);
2561
+ remoteErrorObject = error;
2562
+ abortController.abort(error);
2563
+ if (!pushFinalized) {
2564
+ pushFinalized = true;
2565
+ pushFinalizeReject(error);
2566
+ }
2548
2567
  } else pendingCredit += response.credit;
2549
2568
  });
2550
2569
  spool.roll(() => {
@@ -2580,7 +2599,7 @@ var SinkTrait = class extends SourceTrait {
2580
2599
  creditGate = new CreditGate(initialCredit + pendingCredit);
2581
2600
  if (pendingCredit > 0) refreshTimeout();
2582
2601
  pendingCredit = 0;
2583
- }
2602
+ } else if (pendingCredit > 0) throw new Error(`push to sink "${name}" received unsolicited credit (credit-flow disabled)`);
2584
2603
  if (creditGate) {
2585
2604
  this.pushCreditGates.set(requestId, creditGate);
2586
2605
  spool.roll(() => {
@@ -10,4 +10,4 @@ ${Pi.repeat(a.depth)}}`:a.close=`}`;break}case Y.TAG:o+=String(c),o+=Li(Y.POS_IN
10
10
  `;let n=0;for(let i of e.children){if(Vi(i)){let a=String(n);e.mt===Y.MAP?a=n%2?`val ${(n-1)/2}`:`key ${n/2}`:e.mt===Y.TAG&&(a=``),r+=Wi(i,t,a)}n++}}return r}var Gi={...Ni.defaultDecodeOptions,initialDepth:0,noPrefixHex:!1,minCol:0};function Ki(e,t){let n={...Gi,...t,ParentType:Bi,saveOriginal:!0},r=new ki(e,n),i,a;for(let e of r){if(a=Ni.create(e,i,n,r),e[2]===Kn.BREAK)if(i?.isStreaming)i.left=1;else throw Error(`Unexpected BREAK`);if(!Vi(a)){let t=new Bi(e,0,i,n);t.leaf=!0,t.children.push(a),Xn(t,r.toHere(e[3])),a=t}let t=(a.depth+1)*2,o=a.numBytes();for(o&&(t+=1,t+=o*2),n.minCol=Math.max(n.minCol,t),i&&i.push(a,r,e[3]),i=a;i?.done;)a=i,a.leaf||Xn(a,r.toHere(a.offset)),{parent:i}=i}t&&(t.minCol=n.minCol);let o=n.noPrefixHex?``:`0x${ir(r.toHere(0))}
11
11
  `;return o+=Wi(a,n),o}var qi=!lr();function Ji(e){if(typeof e==`object`&&e){if(e.constructor!==Number)throw Error(`Expected number: ${e}`)}else if(typeof e!=`number`)throw Error(`Expected number: ${e}`)}function Yi(e){if(typeof e==`object`&&e){if(e.constructor!==String)throw Error(`Expected string: ${e}`)}else if(typeof e!=`string`)throw Error(`Expected string: ${e}`)}function Xi(e){if(!(e instanceof Uint8Array))throw Error(`Expected Uint8Array: ${e}`)}function Zi(e){if(!Array.isArray(e))throw Error(`Expected Array: ${e}`)}$(Map,(e,t,n)=>{let r=[...e.entries()].map(e=>[e[0],e[1],Ti(e[0],n)]);if(n.rejectDuplicateKeys){let e=new Set;for(let[t,n,i]of r){let t=ir(i);if(e.has(t))throw Error(`Duplicate map key: 0x${t}`);e.add(t)}}n.sortKeys&&r.sort(n.sortKeys),xi(e,e.size,Y.MAP,t,n);for(let[e,i,a]of r)t.write(a),wi(i,t,n)});function Qi(e){return Yi(e.contents),new Date(e.contents)}Qi.comment=e=>{Yi(e.contents);let t=new Date(e.contents);return`(String ${e.tag===X.DATE_FULL?`Full `:``}Date) ${t.toISOString()}`},Q.registerDecoder(X.DATE_STRING,Qi),Q.registerDecoder(X.DATE_FULL,Qi);function $i(e){return Ji(e.contents),new Date(e.contents*1e3)}$i.comment=e=>(Ji(e.contents),`(Epoch Date) ${new Date(e.contents*1e3).toISOString()}`),Q.registerDecoder(X.DATE_EPOCH,$i);var ea=1e3*60*60*24;function ta(e){return Ji(e.contents),new Date(e.contents*ea)}ta.comment=e=>(Ji(e.contents),`(Epoch Date) ${new Date(e.contents*ea).toISOString()}`),Q.registerDecoder(X.DATE_EPOCH_DAYS,ta),$(Date,(e,t,n)=>{switch(n.dateTag){case X.DATE_EPOCH:return[n.dateTag,e.valueOf()/1e3];case X.DATE_STRING:return[n.dateTag,e.toISOString().replace(/\.000Z$/,`Z`)];case X.DATE_EPOCH_DAYS:return[n.dateTag,Math.floor(e.valueOf()/ea)];case X.DATE_FULL:return[n.dateTag,e.toISOString().split(`T`)[0]];default:throw Error(`Unsupported date tag: ${n.dateTag}`)}});function na(e,t,n){if(Xi(t.contents),n.rejectBigInts)throw Error(`Decoding unwanted big integer: ${t}(h'${ir(t.contents)}')`);if(n.requirePreferred&&t.contents[0]===0)throw Error(`Decoding overly-large bigint: ${t.tag}(h'${ir(t.contents)})`);let r=t.contents.reduce((e,t)=>e<<8n|BigInt(t),0n);e&&(r=-1n-r);let i=r>=-(2**53-1)&&r<=2**53-1;if(n.requirePreferred&&i)throw Error(`Decoding bigint that could have been int: ${r}n`);return n.collapseBigInts&&i&&(r=Number(r)),n.boxed?Zn(r,t.contents):r}var ra=na.bind(null,!1),ia=na.bind(null,!0);ra.comment=(e,t)=>`(Positive BigInt) ${na(!1,e,t)}n`,ia.comment=(e,t)=>`(Negative BigInt) ${na(!0,e,t)}n`,Q.registerDecoder(X.POS_BIGINT,ra),Q.registerDecoder(X.NEG_BIGINT,ia);function aa(e,t){return Xi(e.contents),e}aa.comment=(e,t,n)=>{Xi(e.contents);let r={...t,initialDepth:n+2,noPrefixHex:!0},i=Jn(e),a=2**((i[0]&31)-24)+1,o=i[a]&31,s=ir(i.subarray(a,++a));o>=24&&(s+=` `,s+=ir(i.subarray(a,a+2**(o-24)))),r.minCol=Math.max(r.minCol,(n+1)*2+s.length);let c=Ki(e.contents,r),l=`Embedded CBOR
12
12
  `;return l+=`${``.padStart((n+1)*2,` `)}${s}`.padEnd(r.minCol+1,` `),l+=`-- Bytes (Length: ${e.contents.length})
13
- `,l+=c,l},aa.noChildren=!0,Q.registerDecoder(X.CBOR,aa),Q.registerDecoder(X.URI,e=>(Yi(e.contents),new URL(e.contents)),`URI`),$(URL,e=>[X.URI,e.toString()]),Q.registerDecoder(X.BASE64URL,e=>(Yi(e.contents),cr(e.contents)),`Base64url-encoded`),Q.registerDecoder(X.BASE64,e=>(Yi(e.contents),or(e.contents)),`Base64-encoded`),Q.registerDecoder(35,e=>(Yi(e.contents),new RegExp(e.contents)),`RegExp`),Q.registerDecoder(21065,e=>{Yi(e.contents);let t=`^(?:${e.contents})$`;return new RegExp(t,`u`)},`I-RegExp`),Q.registerDecoder(X.REGEXP,e=>{if(Zi(e.contents),e.contents.length<1||e.contents.length>2)throw Error(`Invalid RegExp Array: ${e.contents}`);return new RegExp(e.contents[0],e.contents[1])},`RegExp`),$(RegExp,e=>[X.REGEXP,[e.source,e.flags]]),Q.registerDecoder(64,e=>(Xi(e.contents),e.contents),`uint8 Typed Array`);function oa(e,t,n){Xi(e.contents);let r=e.contents.length;if(r%t.BYTES_PER_ELEMENT!==0)throw Error(`Number of bytes must be divisible by ${t.BYTES_PER_ELEMENT}, got: ${r}`);r/=t.BYTES_PER_ELEMENT;let i=new t(r),a=new DataView(e.contents.buffer,e.contents.byteOffset,e.contents.byteLength),o=a[`get${t.name.replace(/Array/,``)}`].bind(a);for(let e=0;e<r;e++)i[e]=o(e*t.BYTES_PER_ELEMENT,n);return i}function sa(e,t,n,r,i){let a=i.forceEndian??qi;if(mi(a?t:n,e,i),pi(r.byteLength,e,Y.BYTE_STRING),qi===a)e.write(new Uint8Array(r.buffer,r.byteOffset,r.byteLength));else{let t=e[`write${r.constructor.name.replace(/Array/,``)}`].bind(e);for(let e of r)t(e,a)}}Q.registerDecoder(65,e=>oa(e,Uint16Array,!1),`uint16, big endian, Typed Array`),Q.registerDecoder(66,e=>oa(e,Uint32Array,!1),`uint32, big endian, Typed Array`),Q.registerDecoder(67,e=>oa(e,BigUint64Array,!1),`uint64, big endian, Typed Array`),Q.registerDecoder(68,e=>(Xi(e.contents),new Uint8ClampedArray(e.contents)),`uint8 Typed Array, clamped arithmetic`),$(Uint8ClampedArray,e=>[68,new Uint8Array(e.buffer,e.byteOffset,e.byteLength)]),Q.registerDecoder(69,e=>oa(e,Uint16Array,!0),`uint16, little endian, Typed Array`),$(Uint16Array,(e,t,n)=>sa(t,69,65,e,n)),Q.registerDecoder(70,e=>oa(e,Uint32Array,!0),`uint32, little endian, Typed Array`),$(Uint32Array,(e,t,n)=>sa(t,70,66,e,n)),Q.registerDecoder(71,e=>oa(e,BigUint64Array,!0),`uint64, little endian, Typed Array`),$(BigUint64Array,(e,t,n)=>sa(t,71,67,e,n)),Q.registerDecoder(72,e=>(Xi(e.contents),new Int8Array(e.contents)),`sint8 Typed Array`),$(Int8Array,e=>[72,new Uint8Array(e.buffer,e.byteOffset,e.byteLength)]),Q.registerDecoder(73,e=>oa(e,Int16Array,!1),`sint16, big endian, Typed Array`),Q.registerDecoder(74,e=>oa(e,Int32Array,!1),`sint32, big endian, Typed Array`),Q.registerDecoder(75,e=>oa(e,BigInt64Array,!1),`sint64, big endian, Typed Array`),Q.registerDecoder(77,e=>oa(e,Int16Array,!0),`sint16, little endian, Typed Array`),$(Int16Array,(e,t,n)=>sa(t,77,73,e,n)),Q.registerDecoder(78,e=>oa(e,Int32Array,!0),`sint32, little endian, Typed Array`),$(Int32Array,(e,t,n)=>sa(t,78,74,e,n)),Q.registerDecoder(79,e=>oa(e,BigInt64Array,!0),`sint64, little endian, Typed Array`),$(BigInt64Array,(e,t,n)=>sa(t,79,75,e,n)),Q.registerDecoder(81,e=>oa(e,Float32Array,!1),`IEEE 754 binary32, big endian, Typed Array`),Q.registerDecoder(82,e=>oa(e,Float64Array,!1),`IEEE 754 binary64, big endian, Typed Array`),Q.registerDecoder(85,e=>oa(e,Float32Array,!0),`IEEE 754 binary32, little endian, Typed Array`),$(Float32Array,(e,t,n)=>sa(t,85,81,e,n)),Q.registerDecoder(86,e=>oa(e,Float64Array,!0),`IEEE 754 binary64, big endian, Typed Array`),$(Float64Array,(e,t,n)=>sa(t,86,82,e,n)),Q.registerDecoder(X.SET,(e,t)=>{if(Zi(e.contents),t.sortKeys){let n=Ni.decodeToEncodeOpts(t),r=null;for(let i of e.contents){let e=[i,void 0,Ti(i,n)];if(r&&t.sortKeys(r,e)>=0)throw Error(`Set items out of order in tag #${X.SET}`);r=e}}return new Set(e.contents)},`Set`),$(Set,(e,t,n)=>{let r=[...e];if(n.sortKeys){let e=r.map(e=>[e,void 0,Ti(e,n)]);e.sort(n.sortKeys),r=e.map(([e])=>e)}return[X.SET,r]}),Q.registerDecoder(X.JSON,e=>(Yi(e.contents),JSON.parse(e.contents)),`JSON-encoded`);function ca(e){return Xi(e.contents),new Yr().decode(e.contents)}ca.comment=e=>{Xi(e.contents);let t=new Yr;return`(WTF8 string): ${JSON.stringify(t.decode(e.contents))}`},Q.registerDecoder(X.WTF8,ca),Q.registerDecoder(X.SELF_DESCRIBED,e=>e.contents,`Self-Described`),Q.registerDecoder(X.INVALID_16,()=>{throw Error(`Tag always invalid: ${X.INVALID_16}`)},`Invalid`),Q.registerDecoder(X.INVALID_32,()=>{throw Error(`Tag always invalid: ${X.INVALID_32}`)},`Invalid`),Q.registerDecoder(X.INVALID_64,()=>{throw Error(`Tag always invalid: ${X.INVALID_64}`)},`Invalid`),Q.registerDecoder(X.SYMBOL,e=>{let t=e.contents;if(Array.isArray(e.contents)){if(e.contents.length!==1)throw Error(`Expected Array of size 1: ${e.contents}`);[t]=e.contents}if(Yi(t),!t.length)throw Error(`Expected non-empty string: ${e.contents}`);return Symbol.for(t)},`Symbol`);function la(e){throw Error(`Encoding ${e.constructor.name} intentionally unimplmented. It is not concrete enough to interoperate. Convert to Uint8Array first.`)}$(ArrayBuffer,la),$(DataView,la),typeof SharedArrayBuffer<`u`&&$(SharedArrayBuffer,la);function ua(e){return[NaN,e.valueOf()]}$(Boolean,ua),$(Number,ua),$(String,ua),$(BigInt,ua);function da(e){let t={...Ni.defaultDecodeOptions};if(e.dcbor?Object.assign(t,Ni.dcborDecodeOptions):e.cde&&Object.assign(t,Ni.cdeDecodeOptions),Object.assign(t,e),Object.hasOwn(t,`rejectLongNumbers`))throw TypeError(`rejectLongNumbers has changed to requirePreferred`);return t.boxed&&(t.saveOriginal=!0),t}var fa=class{parent=void 0;ret=void 0;step(e,t,n){if(this.ret=Ni.create(e,this.parent,t,n),e[2]===Kn.BREAK)if(this.parent?.isStreaming)this.parent.left=0;else throw Error(`Unexpected BREAK`);else this.parent&&this.parent.push(this.ret,n,e[3]);for(this.ret instanceof Ni&&(this.parent=this.ret);this.parent?.done;){this.ret=this.parent.convert(n);let e=this.parent.parent;e?.replaceLast(this.ret,this.parent,n),this.parent=e}}};function pa(e,t={}){let n=da(t),r=new ki(e,n),i=new fa;for(let e of r)i.step(e,n,r);return i.ret}var{cdeDecodeOptions:ma,dcborDecodeOptions:ha,defaultDecodeOptions:ga}=Ni,_a=class{constructor(e={}){this.options={id:R(),codec:`cbor`,timeout:10*1e3,share:``,chunkSize:16*1024,chunkCredit:4,topicMake:(e,t,n)=>`${e}/${t}/${n??`any`}`,topicMatch:e=>{let t=e.match(/^(.+)\/([^/]+)\/([^/]+)$/);return t?{name:t[1],operation:t[2],peerId:t[3]===`any`?void 0:t[3]}:null},...e}}},va=class{static uint8ArrayToBase64(e){return xe.from(e.buffer,e.byteOffset,e.byteLength).toString(`base64`)}static base64ToUint8Array(e){return new Uint8Array(xe.from(e,`base64`))}static stringify(e){return JSON.stringify(e,(e,t)=>t instanceof Uint8Array?{__Uint8Array:this.uint8ArrayToBase64(t)}:t)}static parse(e){return JSON.parse(e,(e,t)=>typeof t?.__Uint8Array==`string`?this.base64ToUint8Array(t.__Uint8Array):t)}},ya=class{constructor(e){this.format=e,this.types=new dr,this.tags=new Map;let t=64e3;this.types.registerEncoder(xe,e=>[t,new Uint8Array(e.buffer,e.byteOffset,e.byteLength)]),this.tags.set(t,e=>xe.from(e.contents))}encode(e){let t;if(this.format===`cbor`)try{t=Ti(e,{types:this.types})}catch(e){throw Error(`failed to encode CBOR format`,{cause:e})}else if(this.format===`json`)try{t=va.stringify(e)}catch(e){throw Error(`failed to encode JSON format`,{cause:e})}else throw Error(`invalid format "${this.format}"`);return t}decode(e){let t;if(this.format===`cbor`){if(!(e instanceof Uint8Array))throw Error(`failed to decode CBOR format (data type is not Uint8Array)`);if(e.byteLength===0)throw Error(`failed to decode CBOR format (data is empty)`);try{t=pa(e,{tags:this.tags})}catch(e){throw Error(`failed to decode CBOR format`,{cause:e})}}else if(this.format===`json`){if(typeof e!=`string`)throw Error(`failed to decode JSON format (data type is not string)`);if(e.length===0)throw Error(`failed to decode JSON format (data is empty)`);try{t=va.parse(e)}catch(e){throw Error(`failed to decode JSON format`,{cause:e})}}else throw Error(`invalid format "${this.format}"`);return t}},ba=class extends _a{constructor(e={}){super(e),this.codec=new ya(this.options.codec)}},xa=class e extends ba{static{this.encoder=new TextEncoder}static{this.decoder=new TextDecoder}str2buf(t){return e.encoder.encode(t)}buf2str(t){return e.decoder.decode(t)}arr2buf(e){let t;return t=e instanceof Uint8Array?e:new Uint8Array(e.buffer,e.byteOffset,e.byteLength),t}buf2arr(e,t){let n,r=t;if(r===xe)n=xe.from(e.buffer,e.byteOffset,e.byteLength);else if(r===Uint8Array)n=e;else if(r===Int8Array)n=new Int8Array(e.buffer,e.byteOffset,e.byteLength);else throw Error(`invalid data type`);return n}},Sa=e=>{let t=e.match(/^(\d+)\.(\d+)$/);if(t===null)throw Error(`invalid version string`);let n=parseInt(t[2],10);if(n>99)throw Error(`invalid version string: minor version exceeds 99`);return parseInt(t[1],10)*100+n},Ca=Sa(`1.4`),wa=Sa(`1.4`),Ta=Un(Bn(J(),Hn()),Dn(e=>!Array.isArray(e))),Ea=Un(Pn(Un(J(),kn(8192))),kn(8)),Da=class{constructor(e,t,n,r){this.type=e,this.id=t,this.sender=n,this.receiver=r,this.version=`MQTT+/1.4`}},Oa={version:Un(J(),jn(/^MQTT\+\/\d+\.\d+$/)),type:J(),id:J(),sender:q(J()),receiver:q(J())},ka=class extends Da{constructor(e,t,n,r,i,a,o){super(`event-emission`,e,r,i),this.name=t,this.params=n,this.auth=a,this.meta=o}},Aa=Vn({...Oa,type:Ln(`event-emission`),name:J(),params:q(Un(Pn(Hn()),kn(64))),auth:q(Ea),meta:q(Ta)}),ja=class extends Da{constructor(e,t,n,r,i,a,o,s){super(`service-call-request`,e,r,i),this.name=t,this.params=n,this.auth=a,this.meta=o,this.qos=s}},Ma=Vn({...Oa,type:Ln(`service-call-request`),name:J(),params:q(Un(Pn(Hn()),kn(64))),auth:q(Ea),meta:q(Ta),qos:q(zn([0,1,2]))}),Na=class extends Da{constructor(e,t,n,r,i,a){super(`service-call-response`,e,i,a),this.name=t,this.result=n,this.error=r}},Pa=Vn({...Oa,type:Ln(`service-call-response`),name:J(),result:q(Hn()),error:q(J())}),Fa=class extends Da{constructor(e,t,n,r,i,a,o,s){super(`sink-push-request`,e,r,i),this.name=t,this.params=n,this.auth=a,this.meta=o,this.qos=s}},Ia=Vn({...Oa,type:Ln(`sink-push-request`),name:J(),params:q(Un(Pn(Hn()),kn(64))),auth:q(Ea),meta:q(Ta),qos:q(zn([0,1,2]))}),La=class extends Da{constructor(e,t,n,r,i,a){super(`sink-push-response`,e,r,i),this.name=t,this.error=n,this.credit=a}},Ra=Vn({...Oa,type:Ln(`sink-push-response`),name:J(),error:q(J()),credit:q(Un(Rn(),On(),An(1)))}),za=class extends Da{constructor(e,t,n,r,i,a,o){super(`sink-push-chunk`,e,a,o),this.name=t,this.chunk=n,this.error=r,this.final=i}},Ba=Vn({...Oa,type:Ln(`sink-push-chunk`),name:J(),chunk:q(In(Uint8Array)),error:q(J()),final:q(Fn())}),Va=class extends Da{constructor(e,t,n,r,i){super(`sink-push-credit`,e,r,i),this.name=t,this.credit=n}},Ha=Vn({...Oa,type:Ln(`sink-push-credit`),name:J(),credit:Un(Rn(),On(),An(0))}),Ua=class extends Da{constructor(e,t,n,r,i,a,o,s,c){super(`source-fetch-request`,e,r,i),this.name=t,this.params=n,this.auth=a,this.meta=o,this.credit=s,this.qos=c}},Wa=Vn({...Oa,type:Ln(`source-fetch-request`),name:J(),params:q(Un(Pn(Hn()),kn(64))),auth:q(Ea),meta:q(Ta),credit:q(Un(Rn(),On(),An(1))),qos:q(zn([0,1,2]))}),Ga=class extends Da{constructor(e,t,n,r,i,a){super(`source-fetch-response`,e,r,i),this.name=t,this.error=n,this.meta=a}},Ka=Vn({...Oa,type:Ln(`source-fetch-response`),name:J(),error:q(J()),meta:q(Ta)}),qa=class extends Da{constructor(e,t,n,r,i,a,o){super(`source-fetch-chunk`,e,a,o),this.name=t,this.chunk=n,this.error=r,this.final=i}},Ja=Vn({...Oa,type:Ln(`source-fetch-chunk`),name:J(),chunk:q(In(Uint8Array)),error:q(J()),final:q(Fn())}),Ya=class extends Da{constructor(e,t,n,r,i){super(`source-fetch-credit`,e,r,i),this.name=t,this.credit=n}},Xa=Vn({...Oa,type:Ln(`source-fetch-credit`),name:J(),credit:Un(Rn(),On(),An(0))}),Za=class{makeEventEmission(e,t,n,r,i,a,o){return new ka(e,t,n,r,i,a,o)}makeServiceCallRequest(e,t,n,r,i,a,o,s){return new ja(e,t,n,r,i,a,o,s)}makeServiceCallResponse(e,t,n,r,i,a){return new Na(e,t,n,r,i,a)}makeSinkPushRequest(e,t,n,r,i,a,o,s){return new Fa(e,t,n,r,i,a,o,s)}makeSinkPushResponse(e,t,n,r,i,a){return new La(e,t,n,r,i,a)}makeSinkPushChunk(e,t,n,r,i,a,o){return new za(e,t,n,r,i,a,o)}makeSinkPushCredit(e,t,n,r,i){return new Va(e,t,n,r,i)}makeSourceFetchRequest(e,t,n,r,i,a,o,s,c){return new Ua(e,t,n,r,i,a,o,s,c)}makeSourceFetchResponse(e,t,n,r,i,a){return new Ga(e,t,n,r,i,a)}makeSourceFetchChunk(e,t,n,r,i,a,o){return new qa(e,t,n,r,i,a,o)}makeSourceFetchCredit(e,t,n,r,i){return new Ya(e,t,n,r,i)}parse(e){if(typeof e!=`object`||!e)throw Error(`invalid argument: not an object`);if(typeof e.version!=`string`)throw Error(`invalid object: missing or invalid "version" field`);let t=e.version.match(/^MQTT\+\/(\d+\.\d+)$/),n=t===null?0:Sa(t[1]);if(Math.floor(n/100)!==Math.floor(Ca/100)||n<wa)throw Error(`protocol version mismatch (expected version 1.4...1.4, got version ${e.version})`);let r=(e,t,n)=>{let r=Wn(n,e);if(!r.success){let e=r.issues.map(e=>e.message).join(`; `);throw Error(`invalid ${t} object: ${e}`)}return r.output};if(typeof e.type!=`string`)throw Error(`invalid object: missing or invalid "type" field`);if(e.type===`event-emission`){let t=r(e,`EventEmission`,Aa);return this.makeEventEmission(t.id,t.name,t.params,t.sender,t.receiver,t.auth,t.meta)}else if(e.type===`service-call-request`){let t=r(e,`ServiceCallRequest`,Ma);return this.makeServiceCallRequest(t.id,t.name,t.params,t.sender,t.receiver,t.auth,t.meta,t.qos)}else if(e.type===`service-call-response`){let t=r(e,`ServiceCallResponse`,Pa);return this.makeServiceCallResponse(t.id,t.name,t.result,t.error,t.sender,t.receiver)}else if(e.type===`sink-push-request`){let t=r(e,`SinkPushRequest`,Ia);return this.makeSinkPushRequest(t.id,t.name,t.params,t.sender,t.receiver,t.auth,t.meta,t.qos)}else if(e.type===`sink-push-response`){let t=r(e,`SinkPushResponse`,Ra);return this.makeSinkPushResponse(t.id,t.name,t.error,t.sender,t.receiver,t.credit)}else if(e.type===`sink-push-chunk`){let t=r(e,`SinkPushChunk`,Ba);return this.makeSinkPushChunk(t.id,t.name,t.chunk,t.error,t.final,t.sender,t.receiver)}else if(e.type===`sink-push-credit`){let t=r(e,`SinkPushCredit`,Ha);return this.makeSinkPushCredit(t.id,t.name,t.credit,t.sender,t.receiver)}else if(e.type===`source-fetch-request`){let t=r(e,`SourceFetchRequest`,Wa);return this.makeSourceFetchRequest(t.id,t.name,t.params,t.sender,t.receiver,t.auth,t.meta,t.credit,t.qos)}else if(e.type===`source-fetch-response`){let t=r(e,`SourceFetchResponse`,Ka);return this.makeSourceFetchResponse(t.id,t.name,t.error,t.sender,t.receiver,t.meta)}else if(e.type===`source-fetch-chunk`){let t=r(e,`SourceFetchChunk`,Ja);return this.makeSourceFetchChunk(t.id,t.name,t.chunk,t.error,t.final,t.sender,t.receiver)}else if(e.type===`source-fetch-credit`){let t=r(e,`SourceFetchCredit`,Xa);return this.makeSourceFetchCredit(t.id,t.name,t.credit,t.sender,t.receiver)}else throw Error(`invalid object: not of any known type`)}isRequest(e){return e instanceof ka||e instanceof ja||e instanceof Ua||e instanceof Fa}isResponse(e){return e instanceof Na||e instanceof La||e instanceof za||e instanceof Va||e instanceof Ga||e instanceof qa||e instanceof Ya}},Qa=class extends xa{constructor(){super(...arguments),this.msg=new Za}},$a=class{constructor(e,t,n,r){this.timestamp=e,this.level=t,this.msg=n,this.data=r}async resolve(){if(this.msg instanceof Promise&&(this.msg=await this.msg.catch(()=>`<resolve-failed>`)),this.data)for(let e of Object.keys(this.data))this.data[e]instanceof Promise&&(this.data[e]=await this.data[e].catch(()=>`<resolve-failed>`))}toString(){let e=new Date(this.timestamp),t=`${e.getFullYear()}-${(e.getMonth()+1).toString().padStart(2,`0`)}-${e.getDate().toString().padStart(2,`0`)} ${e.getHours().toString().padStart(2,`0`)}:${e.getMinutes().toString().padStart(2,`0`)}:${e.getSeconds().toString().padStart(2,`0`)}.${e.getMilliseconds().toString().padStart(3,`0`)}`,n=this.msg instanceof Promise?`<unresolved>`:this.msg,r=``;if(this.data!==void 0){let e=this.data;r=` (${Object.keys(e).map(t=>{let n=e[t]instanceof Promise?`<unresolved>`:e[t];return`${t}: ${va.stringify(n)}`}).join(`, `)})`}return`[${t}] ${this.level}: ${n}${r}`}},eo=class extends Qa{constructor(){super(...arguments),this._events=new pn.EventEmitter}on(...e){this._events.on(...e)}off(...e){this._events.off(...e)}emitEvent(...e){return this._events.listenerCount(e[0])===0?!1:this._events.emit(...e)}log(e,t,n){let r=new $a(Date.now(),e,t,n);this.emitEvent(`log`,r)}error(e,t){let n=e;t!==void 0&&(n=Error(`${t}: ${e.message}`,{cause:e}),n.stack=e.stack);try{this.emitEvent(`error`,n),this.log(`error`,n.message)}catch{}}},to=class extends eo{constructor(e,t={}){super(t),this.destroyed=!1,this.onRequest=new Map,this.onResponse=new Map,e===null&&(this.log(`info`,`establishing proxy MQTT client`),e=new Proxy({},{get(e,t,n){return t===`isFakeProxy`?!0:typeof t==`string`&&[`on`,`off`,`once`].includes(t)?()=>{}:()=>{throw Error(`Underlying MQTT operation "${String(t)}" called on a null MQTT client -- only MQTT+ "emit({ ..., dry: true })" is supported in this special operation mode`)}}})),this.mqtt=e,this.log(`info`,`hooking into MQTT client`),this.messageHandler=(e,t,n)=>{if(this.destroyed)return;let r;if(this.options.codec===`json`)r=t.toString();else if(this.options.codec===`cbor`)r=be.isBuffer(t)?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):t;else throw Error(`invalid codec configured`);this._onMessage(e,r,n)},this.mqtt.on(`message`,this.messageHandler)}async destroy(){this.destroyed=!0,this.log(`info`,`un-hooking from MQTT client`),this.mqtt.off(`message`,this.messageHandler),this.onRequest.clear(),this.onResponse.clear()}makeRegistration(e,t,n){let r=!1;return{destroy:async()=>{r||(r=!0,await e.unroll(!1)?.catch(e=>{let r=G(e,`destroy: ${t} "${n}" failed to cleanup`);throw this.error(r),r}))}}}async subscribeTopic(e,t={}){return this.log(`info`,`subscribing to MQTT topic "${e}"`),new Promise((n,r)=>{this.mqtt.subscribe(e,{qos:2,...t},(t,i)=>{t?(this.error(t,`subscribing to MQTT topic "${e}" failed`),r(t)):n()})})}async unsubscribeTopic(e){return this.log(`info`,`unsubscribing from MQTT topic "${e}"`),new Promise((t,n)=>{this.mqtt.unsubscribe(e,(r,i)=>{r?(this.error(r,`unsubscribing from MQTT topic "${e}" failed`),n(r)):t()})})}async publishToTopic(e,t,n={}){typeof t==`string`?this.log(`info`,`publishing to MQTT topic "${e}" (type: string, length: ${t.length} chars)`):this.log(`info`,`publishing to MQTT topic "${e}" (type: buffer, length: ${t.byteLength} bytes)`);let r=new Se((e,n)=>{let r;try{let e=this.codec.decode(t);r=this.msg.parse(e)}catch(e){return n(e)}e(r)});return this.log(`debug`,`publishing to MQTT topic "${e}"`,{message:r}),new Promise((r,i)=>{let a=typeof t==`string`?t:be.from(t.buffer,t.byteOffset,t.byteLength);this.mqtt.publish(e,a,n,t=>{t?(this.error(t,`publishing to MQTT topic "${e}" failed`),i(t)):r()})})}_onMessage(e,t,n){if(this.destroyed)return;let r=this.options.topicMatch(e);if(r===null)return;typeof t==`string`?this.log(`info`,`received from MQTT topic "${e}" (type: string, length: ${t.length} chars)`):this.log(`info`,`received from MQTT topic "${e}" (type: buffer, length: ${t.byteLength} bytes)`);let i;try{i=this.codec.decode(t)}catch(e){this.error(G(e,`failed to parse message into object`));return}let a;try{a=this.msg.parse(i)}catch(e){this.error(G(e,`failed to parse object into typed message object`));return}if(this.log(`debug`,`received from MQTT topic "${e}"`,{message:a}),r.peerId!==void 0&&a.receiver!==void 0&&a.receiver!==r.peerId&&this.log(`warning`,`receiver mismatch on direct topic "${e}" (expected "${r.peerId}", got "${a.receiver}")`),this.msg.isRequest(a)){let t=this.onRequest.get(`${a.type}:${a.name}`);t!==void 0&&Promise.resolve().then(()=>{if(!this.destroyed)return t(a,r.name)}).catch(t=>{this.error(G(t,`dispatching request message from MQTT topic "${e}" (type: ${a.type}, id: ${a.id}, name: ${a.name}) failed`))})}else if(this.msg.isResponse(a)){let t=this.onResponse.get(`${a.type}:${a.id}`);t!==void 0&&Promise.resolve().then(()=>{if(!this.destroyed)return t(a,r.name)}).catch(t=>{this.error(G(t,`dispatching response message from MQTT topic "${e}" (type: ${a.type}, id: ${a.id}, name: ${a.name}) failed`))})}}},no=class{constructor(e,t,n=30*1e3){this.subscribeFn=e,this.unsubscribeFn=t,this.lingerMs=n,this.counts=new Map,this.pending=new Map,this.lingers=new Map,this.unsubbing=new Map}incrementCount(e){let t=this.counts.get(e)??0;return this.counts.set(e,t+1),t}decrementCount(e){let t=this.counts.get(e);if(t!==void 0)return t<=1?(this.counts.delete(e),0):(this.counts.set(e,t-1),t-1)}clearCount(e){this.counts.delete(e)}async subscribe(e,t={qos:2}){if(this.incrementCount(e)===0){let n=this.lingers.get(e);if(n){clearTimeout(n),this.lingers.delete(e);return}let r,i,a=new Promise((e,t)=>{r=e,i=t});a.catch(()=>{}),this.pending.set(e,a);let o=this.unsubbing.get(e);return o&&await o,this.subscribeFn(e,t).then(()=>{this.pending.delete(e),r()},t=>{this.pending.delete(e),this.clearCount(e),i(t)}),a}else{let t=this.pending.get(e);if(t)return t}}async unsubscribe(e){if(this.decrementCount(e)===0)if(this.lingerMs>0){let t=setTimeout(()=>{this.lingers.delete(e);let t=this.unsubscribeFn(e).catch(()=>{}).finally(()=>{this.unsubbing.delete(e)});this.unsubbing.set(e,t)},this.lingerMs);this.lingers.set(e,t)}else{let t=this.unsubscribeFn(e).catch(()=>{}).finally(()=>{this.unsubbing.delete(e)});this.unsubbing.set(e,t),await t}}async flush(){let e=new Set([...this.counts.keys(),...this.lingers.keys(),...this.pending.keys(),...this.unsubbing.keys()]);for(let e of this.lingers.values())clearTimeout(e);this.lingers.clear(),this.counts.clear(),await Promise.allSettled([...this.pending.values(),...this.unsubbing.values()]),await Promise.allSettled([...e].map(e=>this.unsubscribeFn(e).catch(()=>{}))),this.pending.clear(),this.unsubbing.clear()}},ro=class extends to{constructor(){super(...arguments),this.subscriptions=new no((e,t)=>this.subscribeTopic(e,t),e=>this.unsubscribeTopic(e))}async subscribeTopicAndSpool(e,t,n={}){await Pe(`subscribe to MQTT topic "${t}"`,e,()=>this.subscriptions.subscribe(t,{qos:2,...n})),e.roll(()=>this.subscriptions.unsubscribe(t))}async destroy(){await this.subscriptions.flush(),await super.destroy()}},io=class extends ro{constructor(){super(...arguments),this.timers=new Map}async destroy(){for(let e of this.timers.values())clearTimeout(e);this.timers.clear(),await super.destroy()}timerRefresh(e,t){let n=this.timers.get(e);n!==void 0&&clearTimeout(n),this.timers.set(e,setTimeout(async()=>{if(!this.destroyed){this.timers.delete(e);try{await t()}catch(t){this.error(G(t),`timer "${e}" failed`)}}},this.options.timeout))}timerClear(e){let t=this.timers.get(e);t!==void 0&&(clearTimeout(t),this.timers.delete(e))}sleep(e,t){return new Promise(n=>{if(t?.aborted){n();return}let r=t===void 0?void 0:new AbortController,i=setTimeout(()=>{i=null,r!==void 0&&r.abort(),n()},e);i.unref(),t!==void 0&&r!==void 0&&t.addEventListener(`abort`,()=>{i!==null&&clearTimeout(i),n()},{once:!0,signal:r.signal})})}timeout(e,t=`timeout`,n){return new Promise((r,i)=>{if(n?.aborted){i(Error(`aborted`));return}let a=n===void 0?void 0:new AbortController,o=setTimeout(()=>{o=null,a!==void 0&&a.abort(),i(Error(t))},e);o.unref(),n!==void 0&&a!==void 0&&n.addEventListener(`abort`,()=>{o!==null&&clearTimeout(o),i(Error(`aborted`))},{once:!0,signal:a.signal})})}},ao=class extends io{constructor(){super(...arguments),this._meta=new Map}meta(...e){let[t,n]=e;if(e.length===0)return Object.fromEntries(this._meta);if(e.length===1)return this._meta.get(t);n==null?this._meta.delete(t):this._meta.set(t,n)}metaStore(e){let t=e===void 0||Object.keys(e).length===0;if(!(this._meta.size===0&&t))return this._meta.size>0&&t?Object.fromEntries(this._meta):this._meta.size===0&&!t?e:{...Object.fromEntries(this._meta),...e}}},oo=new TextEncoder,so=class extends ao{constructor(){super(...arguments),this._credential=null,this._tokens=new Set}credential(e){if(e.length===0)throw Error(`credential must not be empty`);this._credential=ln(un,oo.encode(e),oo.encode(`mqtt-plus`),6e5,32)}async issue(e){if(this._credential===null)throw Error(`credential has to be provided before issuing tokens`);if(e.roles.length===0)throw Error(`payload.roles must be a non-empty array`);if(e.roles.length>64)throw Error(`payload.roles must not exceed 64 roles`);let t=new Qt(e);return t.setProtectedHeader({alg:`HS256`,typ:`JWT`}),await t.sign(this._credential)}authenticate(e,t){if(e===void 0){let e=Array.from(this._tokens);return e.length>0?e:void 0}else if(t===!0)this._tokens.delete(e);else{if(e.length>8192)throw Error(`token must not exceed 8192 characters`);if(!this._tokens.has(e)&&this._tokens.size>=8)throw Error(`at most 8 tokens can be authenticated at once`);this._tokens.add(e)}}async validateToken(e){if(this._credential===null)throw Error(`credential has to be provided before validating tokens`);try{return(await nn(e,this._credential)).payload}catch(e){let t=e?.code??e?.name??`unknown`,n=e?.message??``;return this.log(`warning`,`token validation failed`,{code:t,reason:n}),null}}async authenticated(e,t,n,r){let i=!1,a=typeof n==`string`?[n]:n.roles;if(t!==void 0)for(let n of t.slice(0,8)){if(n.length>8192)continue;let t=await this.validateToken(n);if(t!==null&&!(t.id&&t.id!==e)&&Array.isArray(t.roles)&&!(t.roles.length>64)){for(let e of a)if(t.roles.includes(e)){i=!0;break}if(i)break}}let o=typeof n==`string`||n.mode===`require`;if(!i&&o)throw Error(`${r} failed authentication`);return i}},co=class extends so{constructor(){super(...arguments),this.eventControllers=new Map}async destroy(){for(let e of this.eventControllers.values())e.abort(Error(`event destroyed`));this.eventControllers.clear(),await super.destroy()}async event(e,...t){if(this.destroyed)throw Error(`event: instance already destroyed`);let n,r,i={},a=this.options.share,o;if(typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.callback,i=e.options??{},a=e.share??this.options.share,o=e.auth):(n=e,r=t[0]),typeof r!=`function`)throw Error(`event: callback argument is required and must be a function`);let s=new je;if(this.onRequest.has(`event-emission:${n}`))throw Error(`event: event "${n}" already registered`);let c=new Set;s.roll(()=>{for(let e of c)this.eventControllers.get(e)?.abort(Error(`event "${n}" destroyed`)),this.eventControllers.delete(e);c.clear()});let l=a===``?n:`$share/${a}/${n}`,u=this.options.topicMake(l,`event-emission`),d=this.options.topicMake(n,`event-emission`,this.options.id);return this.onRequest.set(`event-emission:${n}`,async(e,t)=>{if(e.receiver&&e.receiver!==this.options.id)return;let i=e.id,a=e.sender;if(a===void 0||a===``){this.error(Error(`invalid request: missing sender`));return}if(t!==e.name){this.log(`warning`,`event name mismatch -- dropped request for "${n}" (topic: "${t}", payload: "${e.name}")`,{requestId:i});return}let s=e.params??[];if(this.eventControllers.has(i)){this.log(`warning`,`duplicate event request id -- dropped request for event "${n}"`,{requestId:i});return}let l=new AbortController,u=l.signal;c.add(i),this.eventControllers.set(i,l);let d={sender:a,signal:u};e.receiver&&(d.receiver=e.receiver),e.meta&&(d.meta=e.meta);try{o&&(d.authenticated=await this.authenticated(a,e.auth,o,`event "${n}"`)),await r(...s,d)}catch(e){let t=G(e);this.error(t,`handler for event "${n}" failed`)}finally{l.abort(),c.delete(i),this.eventControllers.delete(i)}}),s.roll(()=>{this.onRequest.delete(`event-emission:${n}`)}),await this.subscribeTopicAndSpool(s,u,i),await this.subscribeTopicAndSpool(s,d,i),this.makeRegistration(s,`event`,n)}emit(e,...t){if(this.destroyed)throw Error(`emit: instance already destroyed`);let n,r,i,a={},o,s;typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.params,i=e.receiver,a=e.options??{},o=e.meta,s=e.dry):(n=e,r=t);let c=R(),l=this.authenticate(),u=this.metaStore(o),d=this.msg.makeEventEmission(c,n,r,this.options.id,i,l,u),f=this.codec.encode(d),p=this.options.topicMake(n,`event-emission`,i);return s?{topic:p,payload:f,options:{qos:2,...a}}:Pe(`publish event as MQTT message to topic "${p}"`,()=>this.publishToTopic(p,f,{qos:2,...a}))}},lo=class extends co{constructor(){super(...arguments),this.serviceControllers=new Map,this.pendingCalls=new Map}async destroy(){for(let e of this.serviceControllers.values())e.abort(Error(`service destroyed`));this.serviceControllers.clear();let e=[...this.pendingCalls.values()];this.pendingCalls.clear();for(let t of e)t(Error(`instance destroyed`));await super.destroy()}async service(e,...t){if(this.destroyed)throw Error(`service: instance already destroyed`);let n,r,i={},a=this.options.share,o;if(typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.callback,i=e.options??{},a=e.share??this.options.share,o=e.auth):(n=e,r=t[0]),typeof r!=`function`)throw Error(`service: callback argument is required and must be a function`);let s=new je;if(this.onRequest.has(`service-call-request:${n}`))throw Error(`service: service "${n}" already registered`);let c=new Set;s.roll(()=>{for(let e of c)this.serviceControllers.get(e)?.abort(Error(`service "${n}" destroyed`)),this.serviceControllers.delete(e);c.clear()});let l=a===``?n:`$share/${a}/${n}`,u=this.options.topicMake(l,`service-call-request`),d=this.options.topicMake(n,`service-call-request`,this.options.id);return this.onRequest.set(`service-call-request:${n}`,async(e,t)=>{if(e.receiver&&e.receiver!==this.options.id)return;let i=e.id,a=e.sender,s=e.params??[];if(a===void 0||a===``){this.error(Error(`invalid request: missing sender`));return}if(t!==e.name){this.log(`warning`,`service name mismatch -- dropped request for "${n}" (topic: "${t}", payload: "${e.name}")`,{requestId:i});return}if(this.serviceControllers.has(i)){this.log(`warning`,`duplicate service request id -- dropped request for "${n}"`,{requestId:i});return}let l=new AbortController,u=l.signal;c.add(i),this.serviceControllers.set(i,l);let d={sender:a,signal:u};e.receiver&&(d.receiver=e.receiver),e.meta&&(d.meta=e.meta);let f=`service-call-handler:${i}`,p=()=>{this.timerRefresh(f,()=>{l.abort(Error(`service "${n}" handler timeout`))})},m=()=>this.timerClear(f);p();let h;try{o&&(d.authenticated=await this.authenticated(a,e.auth,o,`service "${n}"`));let t=new Promise((e,t)=>{let n=()=>{t(G(u.reason))};u.aborted?n():(u.addEventListener(`abort`,n,{once:!0}),h=()=>u.removeEventListener(`abort`,n))}),c=await Promise.race([r(...s,d),t]),l=this.msg.makeServiceCallResponse(i,n,c,void 0,this.options.id,a),f=this.codec.encode(l),p=this.options.topicMake(n,`service-call-response`,a);await this.publishToTopic(p,f,{qos:e.qos??2})}catch(t){let r=G(t);this.error(r,`handler for service "${n}" failed`);let o=this.msg.makeServiceCallResponse(i,n,void 0,r.message,this.options.id,a);try{let t=this.codec.encode(o),r=this.options.topicMake(n,`service-call-response`,a);await this.publishToTopic(r,t,{qos:e.qos??2})}catch(e){this.error(G(e),`sending error response for service "${n}" failed`)}}finally{h?.(),m(),l.abort(),c.delete(i),this.serviceControllers.delete(i)}}),s.roll(()=>{this.onRequest.delete(`service-call-request:${n}`)}),await this.subscribeTopicAndSpool(s,u,i),await this.subscribeTopicAndSpool(s,d,i),this.makeRegistration(s,`service`,n)}async call(e,...t){if(this.destroyed)throw Error(`call: instance already destroyed`);let n,r,i,a={},o;typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.params,i=e.receiver,a=e.options??{},o=e.meta):(n=e,r=t);let s=new je,c=R();for(let e=0;e<10&&this.onResponse.has(`service-call-response:${c}`);e++)c=R();if(this.onResponse.has(`service-call-response:${c}`))throw Error(`failed to generate unique request id`);let l=this.options.topicMake(n,`service-call-response`,this.options.id);await this.subscribeTopicAndSpool(s,l,{qos:a.qos??2});let u=`service-call:${c}`,d,f=!1,p=()=>f?!1:(f=!0,s.unroll(),!0),m=new Promise((e,t)=>{d=t,this.timerRefresh(u,()=>{p()&&t(Error(`communication timeout`))}),s.roll(()=>{this.timerClear(u)}),this.pendingCalls.set(c,e=>{p()&&t(e)}),s.roll(()=>{this.pendingCalls.delete(c)}),this.onResponse.set(`service-call-response:${c}`,r=>{if(!(i!==void 0&&r.sender!==i)){if(r.sender===void 0||r.sender===``){if(!p())return;t(Error(`received service response without sender`));return}if(r.name!==n){if(!p())return;t(Error(`received service response with name mismatch (expected: "${n}", received: "${r.name}")`));return}p()&&(r.error===void 0?e(r.result):t(Error(r.error)))}}),s.roll(()=>{this.onResponse.delete(`service-call-response:${c}`)})}),h=this.authenticate(),g=this.metaStore(o),_=a.qos??2,v=this.msg.makeServiceCallRequest(c,n,r,this.options.id,i,h,g,_),y=this.codec.encode(v),b=this.options.topicMake(n,`service-call-request`,i);try{await Pe(`publish service request as MQTT message to topic "${b}"`,()=>this.publishToTopic(b,y,{...a,qos:_}))}catch(e){return p()&&d(e),m}return m}},uo=class extends lo{constructor(){super(...arguments),this.sourceCreditGates=new Map,this.sourceControllers=new Map,this.sourceSpools=new Map,this.sourceRequests=new Map}async destroy(){for(let e of this.sourceControllers.values())e.abort(Error(`source destroyed`));for(let e of this.sourceCreditGates.values())e.abort();for(let e of[...this.sourceSpools.values()])await e.unroll();this.sourceSpools.clear(),this.sourceControllers.clear(),this.sourceCreditGates.clear(),this.sourceRequests.clear(),await super.destroy()}async source(e,...t){if(this.destroyed)throw Error(`source: instance already destroyed`);let n,r,i={},a=this.options.share,o;if(typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.callback,i=e.options??{},a=e.share??this.options.share,o=e.auth):(n=e,r=t[0]),typeof r!=`function`)throw Error(`source: callback argument is required and must be a function`);let s=new je;if(this.onRequest.has(`source-fetch-request:${n}`))throw Error(`source: source "${n}" already registered`);let c=a===``?n:`$share/${a}/${n}`,l=this.options.topicMake(c,`source-fetch-request`),u=this.options.topicMake(n,`source-fetch-request`,this.options.id);return this.onRequest.set(`source-fetch-request:${n}`,async(e,t)=>{if(e.receiver&&e.receiver!==this.options.id)return;let a=e.id,s=e.params??[],c=e.sender,l=e.receiver,u=new je;if(this.sourceSpools.set(a,u),u.roll(()=>{this.sourceSpools.delete(a)}),c===void 0||c===``){this.error(Error(`invalid request: missing sender`)),await u.unroll();return}let d=this.options.topicMake(n,`source-fetch-response`,c),f=(e,t)=>Error(`${e} name mismatch (expected "${n}", got "${t}")`),p=async(t,r)=>{let o=this.metaStore(r),s=this.msg.makeSourceFetchResponse(a,n,t,this.options.id,c,o),l=this.codec.encode(s);await this.publishToTopic(d,l,{qos:e.qos??i.qos??2})},m=new AbortController,h=m.signal;if(this.sourceControllers.has(a)){let e=Error(`source: duplicate request id "${a}"`);this.error(e),await p(e.message).catch(()=>{}),await u.unroll();return}this.sourceControllers.set(a,m),u.roll(()=>{this.sourceControllers.delete(a)});let g={sender:c,signal:h};l&&(g.receiver=l),e.meta&&(g.meta=e.meta);let _=this.sourceRequests.get(n);_||(_=new Set,this.sourceRequests.set(n,_)),_.add(a),u.roll(()=>{let e=this.sourceRequests.get(n);e===_&&(e.delete(a),e.size===0&&this.sourceRequests.delete(n))}),h.addEventListener(`abort`,()=>{g.stream instanceof L.Readable&&!g.stream.destroyed&&g.stream.destroy(G(h.reason))},{once:!0}),u.roll(()=>{h.aborted&&g.stream instanceof L.Readable&&!g.stream.destroyed&&g.stream.destroy(G(h.reason))});let v,y=new Promise((e,t)=>{v=t});y.catch(()=>{});let b=()=>{v(G(h.reason))};h.aborted?b():h.addEventListener(`abort`,b,{once:!0}),u.roll(()=>{h.removeEventListener(`abort`,b)});let x=`source-fetch-send:${a}`,S=()=>{h.aborted||this.timerRefresh(x,()=>{m.abort(Error(`source fetch "${n}" timed out`))})},C=()=>this.timerClear(x);S(),u.roll(()=>{C()});let w=async(t,r,o)=>{S();let s=this.msg.makeSourceFetchChunk(a,n,t,r,o,this.options.id,c),l=this.codec.encode(s);await this.publishToTopic(d,l,{qos:e.qos??i.qos??2})},T=!1,E,D=!1;try{if(t!==e.name)throw Error(`source name mismatch (topic: "${t}", payload: "${e.name}")`);if(o&&(g.authenticated=await this.authenticated(c,e.auth,o,`source "${n}"`)),this.onResponse.set(`source-fetch-credit:${a}`,e=>{if(!h.aborted){if(e.name!==n){m.abort(f(`source credit`,e.name));return}if(e.sender===void 0||e.sender===``){m.abort(Error(`source credit for "${n}" missing sender`));return}if(e.sender===c){if(e.credit===0){D=!0,m.abort(Error(`source fetch "${n}" cancelled by fetcher`));return}E&&(E.replenish(e.credit),S())}}}),u.roll(()=>{this.onResponse.delete(`source-fetch-credit:${a}`)}),await Promise.race([Promise.resolve(r(...s,g)),y]),!(g.stream instanceof L.Readable)&&!(g.buffer instanceof Promise)&&!(g.buffer instanceof Uint8Array))throw Error(`handler did not provide data via info.stream or info.buffer fields`);if(g.stream instanceof L.Readable&&(g.buffer instanceof Promise||g.buffer instanceof Uint8Array))throw Error(`handler has set both info.stream and info.buffer fields`);let i=e.credit;if(E=i!==void 0&&i>0?new Ce(i):void 0,E){let e=E;this.sourceCreditGates.set(a,e),u.roll(()=>{e.abort(),this.sourceCreditGates.delete(a)})}if(await p(void 0,g.meta),T=!0,g.stream instanceof L.Readable)await ke(g.stream,this.options.chunkSize,w,E,h);else if(g.buffer instanceof Promise||g.buffer instanceof Uint8Array){let e=g.buffer instanceof Promise?await Promise.race([g.buffer,y]):g.buffer;h.throwIfAborted(),await Oe(e,this.options.chunkSize,w,E,h)}}catch(e){let t=G(e,`handler for source "${n}" failed`);m.abort(t),D||(this.error(t),T?await w(void 0,t.message,!0).catch(()=>{}):await p(t.message).catch(()=>{}))}finally{await u.unroll()}}),s.roll(()=>{this.onRequest.delete(`source-fetch-request:${n}`)}),s.roll(()=>{let e=this.sourceRequests.get(n);if(e){for(let t of e){let e=this.sourceControllers.get(t);e&&e.abort(Error(`source "${n}" destroyed`));let r=this.sourceCreditGates.get(t);r&&r.abort()}this.sourceRequests.delete(n)}}),await this.subscribeTopicAndSpool(s,l,i),await this.subscribeTopicAndSpool(s,u,i),this.makeRegistration(s,`source`,n)}async fetch(e,...t){if(this.destroyed)throw Error(`fetch: instance already destroyed`);let n,r,i,a={},o;typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.params,i=e.receiver,a=e.options??{},o=e.meta):(n=e,r=t);let s=new je,c=R();for(let e=0;e<10&&(this.onResponse.has(`source-fetch-response:${c}`)||this.onResponse.has(`source-fetch-chunk:${c}`));e++)c=R();if(this.onResponse.has(`source-fetch-response:${c}`)||this.onResponse.has(`source-fetch-chunk:${c}`))throw Error(`failed to generate unique request id`);let l=this.options.topicMake(n,`source-fetch-response`,this.options.id),u=(e,t)=>Error(`${e} name mismatch (expected "${n}", got "${t}")`);await this.subscribeTopicAndSpool(s,l,{qos:a.qos??2});let d=this.options.chunkCredit,f=d>0?d*this.options.chunkSize:16*1024,p=0,m=d,h=i,g=!1,_=!1,v=[],y=(e,t)=>{if(t===void 0||t===``){_=!0;let t=Error(`received ${e} without sender`);return x(t),w?.destroy(t),s.unroll()?.catch(()=>{}),!1}if(h===void 0)h=t;else if(t!==h)return!1;return!0},b,x,S=new Promise((e,t)=>{b=e,x=t});S.catch(()=>{}),s.roll(()=>{b(void 0)});let C=`source-fetch-recv:${c}`,w,T=()=>{_||w&&w.destroyed||this.timerRefresh(C,()=>{let e=Error(`communication timeout`);x(e),w?.destroy(e)})};s.roll(()=>{this.timerClear(C)}),w=new De({highWaterMark:f,read:e=>{if(d<=0||_)return;let t=h;if(!t)return;let r=m-p,i=Math.max(0,f-(w?.readableLength??0)),o=Math.floor(i/this.options.chunkSize),s=Math.max(0,o-r);if(s>0){m+=s;let e=this.msg.makeSourceFetchCredit(c,n,s,this.options.id,t),r=this.codec.encode(e),i=this.options.topicMake(n,`source-fetch-request`,t);this.publishToTopic(i,r,{qos:a.qos??2}).catch(e=>{let t=G(e,`sending source fetch credit failed`);this.error(t),D(t)}),T()}}});let E=w.buffer;T();let D=e=>{_=!0,x(e),w.destroy(e)},O=!1,ee=e=>{if(!O&&!_){O=!0;let e=h;if(e){let t=this.msg.makeSourceFetchCredit(c,n,0,this.options.id,e),r=this.codec.encode(t),i=this.options.topicMake(n,`source-fetch-request`,e);this.publishToTopic(i,r,{qos:a.qos??2}).catch(e=>this.error(G(e,`sending source fetch cancel failed`)))}}_||x(e===void 0?Error(`stream aborted`):G(e)),s.unroll()?.catch(()=>{})};w.once(`close`,()=>ee()),w.once(`error`,e=>ee(e));let k=e=>{if(e.error)D(Error(e.error));else{if(T(),e.chunk!==void 0){if(d>0&&p>=m){D(Error(`flow control violation`));return}p++,w.destroyed||w.push(e.chunk)}e.final&&(_=!0,w.destroyed||w.push(null),s.unroll()?.catch(()=>{}))}};this.onResponse.set(`source-fetch-response:${c}`,e=>{if(!_){if(e.name!==n){D(u(`source response`,e.name));return}if(y(`source response`,e.sender))if(e.error)D(Error(e.error));else{if(g)return;g=!0,b(e.meta),T();for(let e of v){if(_)break;k(e)}v.length=0}}}),this.onResponse.set(`source-fetch-chunk:${c}`,e=>{if(!_){if(e.name!==n){D(u(`source chunk`,e.name));return}if(y(`source chunk`,e.sender)){if(!g){if(d>0&&v.length>=m){D(Error(`flow control violation`));return}v.push(e);return}k(e)}}}),s.roll(()=>{this.onResponse.delete(`source-fetch-response:${c}`),this.onResponse.delete(`source-fetch-chunk:${c}`)});let te=this.authenticate(),A=this.metaStore(o),ne=d>0?d:void 0,re=this.msg.makeSourceFetchRequest(c,n,r,this.options.id,i,te,A,ne,a.qos),ie=this.codec.encode(re),j=this.options.topicMake(n,`source-fetch-request`,i);await Pe(`publish fetch request as MQTT message to topic "${j}"`,()=>this.publishToTopic(j,ie,{qos:2,...a})).catch(e=>{let t=G(e);x(t),w.destroy(t)});let M={stream:w,buffer:E,meta:S};return Ae(M,`stream`,`buffer`,e=>{e===`stream`?w.stopCollecting():e===`buffer`&&w.resume()}),M}},fo=class extends uo{constructor(){super(...arguments),this.pushStreams=new Map,this.pushSpools=new Map,this.pushRecvControllers=new Map,this.destroying=!1,this.pushControllers=new Map,this.pushCreditGates=new Map,this.pushSenderSpools=new Map}async destroy(){this.destroying=!0;for(let e of this.pushSenderSpools.keys())this.timerClear(`sink-push-send:${e}`);for(let e of this.pushSpools.keys())this.timerClear(`sink-push-recv:${e}`);for(let e of this.pushControllers.values())e.abort(Error(`sink destroyed`));for(let e of this.pushCreditGates.values())e.abort();for(let e of[...this.pushSenderSpools.values()])await e.unroll();this.pushSenderSpools.clear(),this.pushControllers.clear(),this.pushCreditGates.clear();for(let e of this.pushRecvControllers.values())e.abort(Error(`sink destroyed`));this.pushRecvControllers.clear();for(let e of this.pushStreams.values())e.destroy(Error(`sink destroyed`));this.pushStreams.clear();for(let e of[...this.pushSpools.values()])await e.unroll();this.pushSpools.clear(),await super.destroy()}async sink(e,...t){if(this.destroyed)throw Error(`sink: instance already destroyed`);let n,r,i={},a=this.options.share,o;if(typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.callback,i=e.options??{},a=e.share??this.options.share,o=e.auth):(n=e,r=t[0]),typeof r!=`function`)throw Error(`sink: callback argument is required and must be a function`);let s=new je;if(this.onRequest.has(`sink-push-request:${n}`))throw Error(`sink: sink "${n}" already registered`);let c=a===``?n:`$share/${a}/${n}`,l=this.options.topicMake(c,`sink-push-request`),u=this.options.topicMake(n,`sink-push-request`,this.options.id);return this.onRequest.set(`sink-push-request:${n}`,async(e,t)=>{if(e.receiver&&e.receiver!==this.options.id)return;let a=e.id,s=e.params??[],c=e.sender,l=e.receiver,u=new je;if(this.pushSpools.set(a,u),u.roll(()=>{this.pushSpools.delete(a)}),c===void 0||c===``){this.error(Error(`invalid request: missing sender`)),await u.unroll();return}let d=this.options.topicMake(n,`sink-push-response`,c),f=e=>Error(`sink name mismatch (expected "${n}", got "${e}")`),p=this.options.chunkCredit,m=async(t,r=!1)=>{let o=t===void 0&&r&&p>0?p:void 0,s=this.msg.makeSinkPushResponse(a,n,t,this.options.id,c,o),l=this.codec.encode(s);await this.publishToTopic(d,l,{qos:e.qos??i.qos??2})},h=new AbortController,g=h.signal,_,v=new Promise((e,t)=>{_=t});v.catch(()=>{});let y=()=>{_(G(g.reason))};if(g.aborted?y():g.addEventListener(`abort`,y,{once:!0}),u.roll(()=>{g.removeEventListener(`abort`,y)}),this.pushRecvControllers.has(a)){let e=Error(`sink: duplicate request id "${a}"`);this.error(e),await m(e.message).catch(()=>{}),await u.unroll();return}this.pushRecvControllers.set(a,h),u.roll(()=>{this.pushRecvControllers.delete(a)});let b=!1,x=!1,S=!1,C,w=()=>{};try{if(t!==e.name)throw Error(`sink name mismatch (topic: "${t}", payload: "${e.name}")`);let _;o&&(_=await this.authenticated(c,e.auth,o,`sink "${n}"`));let y=p>0?{chunksReceived:0,creditGranted:p}:void 0,T=p>0?p*this.options.chunkSize:16*1024,E=!1,D=`sink-push-recv:${a}`,O=()=>this.timerRefresh(D,()=>{if(!(E||this.destroying)&&(h.abort(Error(`push stream timeout`)),c&&!S)){S=!0;let t=this.msg.makeSinkPushCredit(a,n,0,this.options.id,c),r=this.codec.encode(t);this.publishToTopic(d,r,{qos:e.qos??i.qos??2}).catch(()=>{})}}),ee=()=>this.timerClear(D),k=new De({highWaterMark:T,read:t=>{if(!y||!this.pushSpools.has(a))return;let r=y.creditGranted-y.chunksReceived,o=Math.max(0,T-k.readableLength),s=Math.floor(o/this.options.chunkSize),l=Math.max(0,s-r);if(l>0){y.creditGranted+=l;let t=this.msg.makeSinkPushCredit(a,n,l,this.options.id,c),r=this.codec.encode(t);this.publishToTopic(d,r,{qos:e.qos??i.qos??2}).catch(e=>{let t=G(e,`sending sink push credit failed`);this.error(t),k.destroy(t)}),O()}}});C=k,this.pushStreams.set(a,k),u.roll(()=>{this.pushStreams.delete(a)}),k.on(`error`,w),u.roll(()=>{if(!b&&!g.aborted&&!this.destroying&&h.abort(Error(`push stream closed`)),!b&&!this.destroying&&!S&&c){let t=this.msg.makeSinkPushCredit(a,n,0,this.options.id,c),r=this.codec.encode(t);this.publishToTopic(d,r,{qos:e.qos??i.qos??2}).catch(e=>this.error(G(e,`sending sink push cancel failed`)))}}),this.onResponse.set(`sink-push-chunk:${a}`,async e=>{if(!E){if(e.name!==n){E=!0,ee(),k.destroy(f(e.name));return}if(e.sender===void 0||e.sender===``){E=!0,ee(),k.destroy(Error(`sink chunk for "${n}" missing sender`));return}if(e.sender===c)if(e.error!==void 0)E=!0,ee(),k.destroy(Error(e.error));else{if(O(),e.chunk!==void 0){if(y){if(y.chunksReceived>=y.creditGranted){E=!0,ee(),k.destroy(Error(`flow control violation`));return}y.chunksReceived++}k.destroyed||k.push(e.chunk)}e.final&&(E=!0,ee(),k.destroyed||k.push(null))}}}),u.roll(()=>{this.onResponse.delete(`sink-push-chunk:${a}`)}),O(),u.roll(()=>{ee()});let te=k.buffer,A=!1,ne,re,ie=()=>{A||(A=!0,ne())},j=()=>{A||(A=!0,E||k.readableEnded?ne():re(Error(`push stream closed before end`)))},M=e=>{A||(A=!0,re(e))},ae=new Promise((e,t)=>{ne=e,re=t,k.once(`end`,ie),k.once(`close`,j),k.once(`error`,M)});ae.finally(()=>{k.removeListener(`end`,ie),k.removeListener(`close`,j),k.removeListener(`error`,M)}).catch(()=>{});let oe={sender:c,signal:g,stream:k,buffer:te};if(l&&(oe.receiver=l),_!==void 0&&(oe.authenticated=_),e.meta&&(oe.meta=e.meta),Ae(oe,`stream`,`buffer`,e=>{e===`stream`?k.stopCollecting():e===`buffer`&&k.resume()}),await m(void 0,!0),x=!0,await Promise.race([Promise.resolve(r(...s,oe)),v]),k.readableFlowing!==!0&&!k.destroyed&&k.resume(),await ae.catch(e=>{throw this.error(G(e),`stream drain after sink "${n}" callback failed`),e}),k.collecting&&k.stopCollecting(),!g.aborted)try{b=!0,await m()}catch(e){this.error(G(e),`sending terminal response for sink "${n}" failed`)}}catch(e){let t=G(e,`handler for sink "${n}" failed`);if(h.abort(t),x&&!this.destroying){let e=this.pushStreams.get(a);e!==void 0&&!e.destroyed&&e.destroy(t)}this.error(t),S=!0,await m(t.message).catch(()=>{})}finally{let e=this.pushStreams.get(a);e!==void 0&&!e.destroyed&&!b&&!S&&e.destroy(g.aborted?G(g.reason):Error(`sink push aborted without cause`)),await u.unroll(),C!==void 0&&C.removeListener(`error`,w)}}),s.roll(()=>{this.onRequest.delete(`sink-push-request:${n}`)}),await this.subscribeTopicAndSpool(s,l,i),await this.subscribeTopicAndSpool(s,u,i),this.makeRegistration(s,`sink`,n)}async push(e,...t){if(this.destroyed)throw Error(`push: instance already destroyed`);let n,r,i,a,o={},s;if(typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.data,i=e.params,a=e.receiver,o=e.options??{},s=e.meta):(n=e,r=t[0],i=t.slice(1)),!(r instanceof L.Readable)&&!(r instanceof Uint8Array))throw Error(`invalid data type: expected Readable or Uint8Array`);let c=new je,l=R();for(let e=0;e<10&&(this.onResponse.has(`sink-push-response:${l}`)||this.onResponse.has(`sink-push-credit:${l}`));e++)l=R();if(this.onResponse.has(`sink-push-response:${l}`)||this.onResponse.has(`sink-push-credit:${l}`))throw Error(`failed to generate unique request id`);this.pushSenderSpools.set(l,c),c.roll(()=>{this.pushSenderSpools.delete(l)});let u=this.options.topicMake(n,`sink-push-response`,this.options.id);await this.subscribeTopicAndSpool(c,u,{qos:o.qos??2});let d=new AbortController,f=d.signal;if(this.pushControllers.set(l,d),c.roll(()=>{this.pushControllers.delete(l)}),r instanceof L.Readable){let e=r;f.addEventListener(`abort`,()=>{e.destroyed||e.destroy(G(f.reason))},{once:!0})}let p=`sink-push-send:${l}`,m=()=>{f.aborted||this.timerRefresh(p,()=>{let e=Error(`push to sink "${n}" timed out`);d.abort(e)})};c.roll(()=>{this.timerClear(p)}),m();let h,g,_=0,v,y=!1,b=!1,x=!1,S=!1,C=!1,w=!1,T=!1,E=a,D,O,ee=new Promise((e,t)=>{D=e,O=t});ee.catch(()=>{});let k=(e,t)=>{if(t===void 0||t===``){let t=Error(`received ${e} without sender`);return v=t,d.abort(t),b?S||(S=!0,O(t)):(x=!0,A(t)),!1}if(E===void 0)E=t;else if(t!==E)return!1;return!0},te,A,ne=new Promise((e,t)=>{te=e,A=t});this.onResponse.set(`sink-push-response:${l}`,e=>{if(e.name!==n){let t=Error(`sink response name mismatch (expected "${n}", got "${e.name}")`);v=t,d.abort(t),b?S||(S=!0,O(t)):(x=!0,A(t));return}if(k(`sink response`,e.sender))if(e.error){let t=Error(e.error);v=t,d.abort(t),b?S||(S=!0,O(t)):(x=!0,A(t))}else b?S||(w?(S=!0,D()):T=!0):(h=e.credit,b=!0,x=!0,te())}),c.roll(()=>{this.onResponse.delete(`sink-push-response:${l}`)}),this.onResponse.set(`sink-push-credit:${l}`,e=>{if(e.name!==n){let t=Error(`sink credit name mismatch (expected "${n}", got "${e.name}")`);v=t,d.abort(t),b?S||(S=!0,O(t)):(x=!0,A(t));return}if(k(`sink credit`,e.sender)){if(e.credit===0){y=!0;let e=Error(`push to sink "${n}" cancelled by receiver`);d.abort(e),b?S||(S=!0,O(e)):(x=!0,A(e));return}g===void 0?_+=e.credit:(g.replenish(e.credit),m())}}),c.roll(()=>{this.onResponse.delete(`sink-push-credit:${l}`)});try{let e=()=>{let e=G(f.reason);x||(x=!0,A(e)),S||(S=!0,O(e))};f.addEventListener(`abort`,e,{once:!0}),c.roll(()=>{f.removeEventListener(`abort`,e)});let t=this.authenticate(),u=this.metaStore(s),d=this.msg.makeSinkPushRequest(l,n,i,this.options.id,a,t,u,o.qos),p=this.codec.encode(d),v=this.options.topicMake(n,`sink-push-request`,a);if(await Pe(`publish push request as MQTT message to topic "${v}"`,()=>this.publishToTopic(v,p,{qos:2,...o})),await ne,h!==void 0&&h>0&&(g=new Ce(h+_),_>0&&m(),_=0),g&&(this.pushCreditGates.set(l,g),c.roll(()=>{this.pushCreditGates.delete(l)})),g){let e=g;c.roll(()=>{e.abort()})}let y=E;if(y===void 0)throw Error(`push to sink "${n}" missing responder`);let b=this.options.topicMake(n,`sink-push-request`,y),k=async(e,t,r)=>{m();let i=this.msg.makeSinkPushChunk(l,n,e,t,r,this.options.id,y),a=this.codec.encode(i);await this.publishToTopic(b,a,{qos:2,...o}),t===void 0&&r&&(C=!0)};r instanceof L.Readable?await ke(r,this.options.chunkSize,k,g,f):r instanceof Uint8Array&&await Oe(r,this.options.chunkSize,k,g,f),w=!0,T&&!S&&(S=!0,D()),m(),S||await ee}catch(e){let t=G(e);if(d.abort(t),b&&!v&&!y&&!C)try{let e=E;if(e!==void 0){let r=this.options.topicMake(n,`sink-push-request`,e),i=this.msg.makeSinkPushChunk(l,n,void 0,t.message,!0,this.options.id,e),a=this.codec.encode(i);await this.publishToTopic(r,a,{qos:2,...o}).catch(()=>{})}}catch{}throw b&&!v&&await new Promise(e=>{setImmediate(e)}),v||e}finally{await c.unroll()}}};return class extends fo{}});
13
+ `,l+=c,l},aa.noChildren=!0,Q.registerDecoder(X.CBOR,aa),Q.registerDecoder(X.URI,e=>(Yi(e.contents),new URL(e.contents)),`URI`),$(URL,e=>[X.URI,e.toString()]),Q.registerDecoder(X.BASE64URL,e=>(Yi(e.contents),cr(e.contents)),`Base64url-encoded`),Q.registerDecoder(X.BASE64,e=>(Yi(e.contents),or(e.contents)),`Base64-encoded`),Q.registerDecoder(35,e=>(Yi(e.contents),new RegExp(e.contents)),`RegExp`),Q.registerDecoder(21065,e=>{Yi(e.contents);let t=`^(?:${e.contents})$`;return new RegExp(t,`u`)},`I-RegExp`),Q.registerDecoder(X.REGEXP,e=>{if(Zi(e.contents),e.contents.length<1||e.contents.length>2)throw Error(`Invalid RegExp Array: ${e.contents}`);return new RegExp(e.contents[0],e.contents[1])},`RegExp`),$(RegExp,e=>[X.REGEXP,[e.source,e.flags]]),Q.registerDecoder(64,e=>(Xi(e.contents),e.contents),`uint8 Typed Array`);function oa(e,t,n){Xi(e.contents);let r=e.contents.length;if(r%t.BYTES_PER_ELEMENT!==0)throw Error(`Number of bytes must be divisible by ${t.BYTES_PER_ELEMENT}, got: ${r}`);r/=t.BYTES_PER_ELEMENT;let i=new t(r),a=new DataView(e.contents.buffer,e.contents.byteOffset,e.contents.byteLength),o=a[`get${t.name.replace(/Array/,``)}`].bind(a);for(let e=0;e<r;e++)i[e]=o(e*t.BYTES_PER_ELEMENT,n);return i}function sa(e,t,n,r,i){let a=i.forceEndian??qi;if(mi(a?t:n,e,i),pi(r.byteLength,e,Y.BYTE_STRING),qi===a)e.write(new Uint8Array(r.buffer,r.byteOffset,r.byteLength));else{let t=e[`write${r.constructor.name.replace(/Array/,``)}`].bind(e);for(let e of r)t(e,a)}}Q.registerDecoder(65,e=>oa(e,Uint16Array,!1),`uint16, big endian, Typed Array`),Q.registerDecoder(66,e=>oa(e,Uint32Array,!1),`uint32, big endian, Typed Array`),Q.registerDecoder(67,e=>oa(e,BigUint64Array,!1),`uint64, big endian, Typed Array`),Q.registerDecoder(68,e=>(Xi(e.contents),new Uint8ClampedArray(e.contents)),`uint8 Typed Array, clamped arithmetic`),$(Uint8ClampedArray,e=>[68,new Uint8Array(e.buffer,e.byteOffset,e.byteLength)]),Q.registerDecoder(69,e=>oa(e,Uint16Array,!0),`uint16, little endian, Typed Array`),$(Uint16Array,(e,t,n)=>sa(t,69,65,e,n)),Q.registerDecoder(70,e=>oa(e,Uint32Array,!0),`uint32, little endian, Typed Array`),$(Uint32Array,(e,t,n)=>sa(t,70,66,e,n)),Q.registerDecoder(71,e=>oa(e,BigUint64Array,!0),`uint64, little endian, Typed Array`),$(BigUint64Array,(e,t,n)=>sa(t,71,67,e,n)),Q.registerDecoder(72,e=>(Xi(e.contents),new Int8Array(e.contents)),`sint8 Typed Array`),$(Int8Array,e=>[72,new Uint8Array(e.buffer,e.byteOffset,e.byteLength)]),Q.registerDecoder(73,e=>oa(e,Int16Array,!1),`sint16, big endian, Typed Array`),Q.registerDecoder(74,e=>oa(e,Int32Array,!1),`sint32, big endian, Typed Array`),Q.registerDecoder(75,e=>oa(e,BigInt64Array,!1),`sint64, big endian, Typed Array`),Q.registerDecoder(77,e=>oa(e,Int16Array,!0),`sint16, little endian, Typed Array`),$(Int16Array,(e,t,n)=>sa(t,77,73,e,n)),Q.registerDecoder(78,e=>oa(e,Int32Array,!0),`sint32, little endian, Typed Array`),$(Int32Array,(e,t,n)=>sa(t,78,74,e,n)),Q.registerDecoder(79,e=>oa(e,BigInt64Array,!0),`sint64, little endian, Typed Array`),$(BigInt64Array,(e,t,n)=>sa(t,79,75,e,n)),Q.registerDecoder(81,e=>oa(e,Float32Array,!1),`IEEE 754 binary32, big endian, Typed Array`),Q.registerDecoder(82,e=>oa(e,Float64Array,!1),`IEEE 754 binary64, big endian, Typed Array`),Q.registerDecoder(85,e=>oa(e,Float32Array,!0),`IEEE 754 binary32, little endian, Typed Array`),$(Float32Array,(e,t,n)=>sa(t,85,81,e,n)),Q.registerDecoder(86,e=>oa(e,Float64Array,!0),`IEEE 754 binary64, big endian, Typed Array`),$(Float64Array,(e,t,n)=>sa(t,86,82,e,n)),Q.registerDecoder(X.SET,(e,t)=>{if(Zi(e.contents),t.sortKeys){let n=Ni.decodeToEncodeOpts(t),r=null;for(let i of e.contents){let e=[i,void 0,Ti(i,n)];if(r&&t.sortKeys(r,e)>=0)throw Error(`Set items out of order in tag #${X.SET}`);r=e}}return new Set(e.contents)},`Set`),$(Set,(e,t,n)=>{let r=[...e];if(n.sortKeys){let e=r.map(e=>[e,void 0,Ti(e,n)]);e.sort(n.sortKeys),r=e.map(([e])=>e)}return[X.SET,r]}),Q.registerDecoder(X.JSON,e=>(Yi(e.contents),JSON.parse(e.contents)),`JSON-encoded`);function ca(e){return Xi(e.contents),new Yr().decode(e.contents)}ca.comment=e=>{Xi(e.contents);let t=new Yr;return`(WTF8 string): ${JSON.stringify(t.decode(e.contents))}`},Q.registerDecoder(X.WTF8,ca),Q.registerDecoder(X.SELF_DESCRIBED,e=>e.contents,`Self-Described`),Q.registerDecoder(X.INVALID_16,()=>{throw Error(`Tag always invalid: ${X.INVALID_16}`)},`Invalid`),Q.registerDecoder(X.INVALID_32,()=>{throw Error(`Tag always invalid: ${X.INVALID_32}`)},`Invalid`),Q.registerDecoder(X.INVALID_64,()=>{throw Error(`Tag always invalid: ${X.INVALID_64}`)},`Invalid`),Q.registerDecoder(X.SYMBOL,e=>{let t=e.contents;if(Array.isArray(e.contents)){if(e.contents.length!==1)throw Error(`Expected Array of size 1: ${e.contents}`);[t]=e.contents}if(Yi(t),!t.length)throw Error(`Expected non-empty string: ${e.contents}`);return Symbol.for(t)},`Symbol`);function la(e){throw Error(`Encoding ${e.constructor.name} intentionally unimplmented. It is not concrete enough to interoperate. Convert to Uint8Array first.`)}$(ArrayBuffer,la),$(DataView,la),typeof SharedArrayBuffer<`u`&&$(SharedArrayBuffer,la);function ua(e){return[NaN,e.valueOf()]}$(Boolean,ua),$(Number,ua),$(String,ua),$(BigInt,ua);function da(e){let t={...Ni.defaultDecodeOptions};if(e.dcbor?Object.assign(t,Ni.dcborDecodeOptions):e.cde&&Object.assign(t,Ni.cdeDecodeOptions),Object.assign(t,e),Object.hasOwn(t,`rejectLongNumbers`))throw TypeError(`rejectLongNumbers has changed to requirePreferred`);return t.boxed&&(t.saveOriginal=!0),t}var fa=class{parent=void 0;ret=void 0;step(e,t,n){if(this.ret=Ni.create(e,this.parent,t,n),e[2]===Kn.BREAK)if(this.parent?.isStreaming)this.parent.left=0;else throw Error(`Unexpected BREAK`);else this.parent&&this.parent.push(this.ret,n,e[3]);for(this.ret instanceof Ni&&(this.parent=this.ret);this.parent?.done;){this.ret=this.parent.convert(n);let e=this.parent.parent;e?.replaceLast(this.ret,this.parent,n),this.parent=e}}};function pa(e,t={}){let n=da(t),r=new ki(e,n),i=new fa;for(let e of r)i.step(e,n,r);return i.ret}var{cdeDecodeOptions:ma,dcborDecodeOptions:ha,defaultDecodeOptions:ga}=Ni,_a=class{constructor(e={}){this.options={id:R(),codec:`cbor`,timeout:10*1e3,share:``,chunkSize:16*1024,chunkCredit:4,topicMake:(e,t,n)=>`${e}/${t}/${n??`any`}`,topicMatch:e=>{let t=e.match(/^(.+)\/([^/]+)\/([^/]+)$/);return t?{name:t[1],operation:t[2],peerId:t[3]===`any`?void 0:t[3]}:null},...e}}},va=class{static uint8ArrayToBase64(e){return xe.from(e.buffer,e.byteOffset,e.byteLength).toString(`base64`)}static base64ToUint8Array(e){return new Uint8Array(xe.from(e,`base64`))}static stringify(e){return JSON.stringify(e,(e,t)=>t instanceof Uint8Array?{__Uint8Array:this.uint8ArrayToBase64(t)}:t)}static parse(e){return JSON.parse(e,(e,t)=>typeof t?.__Uint8Array==`string`?this.base64ToUint8Array(t.__Uint8Array):t)}},ya=class{constructor(e){this.format=e,this.types=new dr,this.tags=new Map;let t=64e3;this.types.registerEncoder(xe,e=>[t,new Uint8Array(e.buffer,e.byteOffset,e.byteLength)]),this.tags.set(t,e=>xe.from(e.contents))}encode(e){let t;if(this.format===`cbor`)try{t=Ti(e,{types:this.types})}catch(e){throw Error(`failed to encode CBOR format`,{cause:e})}else if(this.format===`json`)try{t=va.stringify(e)}catch(e){throw Error(`failed to encode JSON format`,{cause:e})}else throw Error(`invalid format "${this.format}"`);return t}decode(e){let t;if(this.format===`cbor`){if(!(e instanceof Uint8Array))throw Error(`failed to decode CBOR format (data type is not Uint8Array)`);if(e.byteLength===0)throw Error(`failed to decode CBOR format (data is empty)`);try{t=pa(e,{tags:this.tags})}catch(e){throw Error(`failed to decode CBOR format`,{cause:e})}}else if(this.format===`json`){if(typeof e!=`string`)throw Error(`failed to decode JSON format (data type is not string)`);if(e.length===0)throw Error(`failed to decode JSON format (data is empty)`);try{t=va.parse(e)}catch(e){throw Error(`failed to decode JSON format`,{cause:e})}}else throw Error(`invalid format "${this.format}"`);return t}},ba=class extends _a{constructor(e={}){super(e),this.codec=new ya(this.options.codec)}},xa=class e extends ba{static{this.encoder=new TextEncoder}static{this.decoder=new TextDecoder}str2buf(t){return e.encoder.encode(t)}buf2str(t){return e.decoder.decode(t)}arr2buf(e){let t;return t=e instanceof Uint8Array?e:new Uint8Array(e.buffer,e.byteOffset,e.byteLength),t}buf2arr(e,t){let n,r=t;if(r===xe)n=xe.from(e.buffer,e.byteOffset,e.byteLength);else if(r===Uint8Array)n=e;else if(r===Int8Array)n=new Int8Array(e.buffer,e.byteOffset,e.byteLength);else throw Error(`invalid data type`);return n}},Sa=e=>{let t=e.match(/^(\d+)\.(\d+)$/);if(t===null)throw Error(`invalid version string`);let n=parseInt(t[2],10);if(n>99)throw Error(`invalid version string: minor version exceeds 99`);return parseInt(t[1],10)*100+n},Ca=Sa(`1.4`),wa=Sa(`1.4`),Ta=Un(Bn(J(),Hn()),Dn(e=>!Array.isArray(e))),Ea=Un(Pn(Un(J(),kn(8192))),kn(8)),Da=class{constructor(e,t,n,r){this.type=e,this.id=t,this.sender=n,this.receiver=r,this.version=`MQTT+/1.4`}},Oa={version:Un(J(),jn(/^MQTT\+\/\d+\.\d+$/)),type:J(),id:J(),sender:q(J()),receiver:q(J())},ka=class extends Da{constructor(e,t,n,r,i,a,o){super(`event-emission`,e,r,i),this.name=t,this.params=n,this.auth=a,this.meta=o}},Aa=Vn({...Oa,type:Ln(`event-emission`),name:J(),params:q(Un(Pn(Hn()),kn(64))),auth:q(Ea),meta:q(Ta)}),ja=class extends Da{constructor(e,t,n,r,i,a,o,s){super(`service-call-request`,e,r,i),this.name=t,this.params=n,this.auth=a,this.meta=o,this.qos=s}},Ma=Vn({...Oa,type:Ln(`service-call-request`),name:J(),params:q(Un(Pn(Hn()),kn(64))),auth:q(Ea),meta:q(Ta),qos:q(zn([0,1,2]))}),Na=class extends Da{constructor(e,t,n,r,i,a){super(`service-call-response`,e,i,a),this.name=t,this.result=n,this.error=r}},Pa=Vn({...Oa,type:Ln(`service-call-response`),name:J(),result:q(Hn()),error:q(J())}),Fa=class extends Da{constructor(e,t,n,r,i,a,o,s){super(`sink-push-request`,e,r,i),this.name=t,this.params=n,this.auth=a,this.meta=o,this.qos=s}},Ia=Vn({...Oa,type:Ln(`sink-push-request`),name:J(),params:q(Un(Pn(Hn()),kn(64))),auth:q(Ea),meta:q(Ta),qos:q(zn([0,1,2]))}),La=class extends Da{constructor(e,t,n,r,i,a){super(`sink-push-response`,e,r,i),this.name=t,this.error=n,this.credit=a}},Ra=Vn({...Oa,type:Ln(`sink-push-response`),name:J(),error:q(J()),credit:q(Un(Rn(),On(),An(1)))}),za=class extends Da{constructor(e,t,n,r,i,a,o){super(`sink-push-chunk`,e,a,o),this.name=t,this.chunk=n,this.error=r,this.final=i}},Ba=Vn({...Oa,type:Ln(`sink-push-chunk`),name:J(),chunk:q(In(Uint8Array)),error:q(J()),final:q(Fn())}),Va=class extends Da{constructor(e,t,n,r,i){super(`sink-push-credit`,e,r,i),this.name=t,this.credit=n}},Ha=Vn({...Oa,type:Ln(`sink-push-credit`),name:J(),credit:Un(Rn(),On(),An(0))}),Ua=class extends Da{constructor(e,t,n,r,i,a,o,s,c){super(`source-fetch-request`,e,r,i),this.name=t,this.params=n,this.auth=a,this.meta=o,this.credit=s,this.qos=c}},Wa=Vn({...Oa,type:Ln(`source-fetch-request`),name:J(),params:q(Un(Pn(Hn()),kn(64))),auth:q(Ea),meta:q(Ta),credit:q(Un(Rn(),On(),An(1))),qos:q(zn([0,1,2]))}),Ga=class extends Da{constructor(e,t,n,r,i,a){super(`source-fetch-response`,e,r,i),this.name=t,this.error=n,this.meta=a}},Ka=Vn({...Oa,type:Ln(`source-fetch-response`),name:J(),error:q(J()),meta:q(Ta)}),qa=class extends Da{constructor(e,t,n,r,i,a,o){super(`source-fetch-chunk`,e,a,o),this.name=t,this.chunk=n,this.error=r,this.final=i}},Ja=Vn({...Oa,type:Ln(`source-fetch-chunk`),name:J(),chunk:q(In(Uint8Array)),error:q(J()),final:q(Fn())}),Ya=class extends Da{constructor(e,t,n,r,i){super(`source-fetch-credit`,e,r,i),this.name=t,this.credit=n}},Xa=Vn({...Oa,type:Ln(`source-fetch-credit`),name:J(),credit:Un(Rn(),On(),An(0))}),Za=class{makeEventEmission(e,t,n,r,i,a,o){return new ka(e,t,n,r,i,a,o)}makeServiceCallRequest(e,t,n,r,i,a,o,s){return new ja(e,t,n,r,i,a,o,s)}makeServiceCallResponse(e,t,n,r,i,a){return new Na(e,t,n,r,i,a)}makeSinkPushRequest(e,t,n,r,i,a,o,s){return new Fa(e,t,n,r,i,a,o,s)}makeSinkPushResponse(e,t,n,r,i,a){return new La(e,t,n,r,i,a)}makeSinkPushChunk(e,t,n,r,i,a,o){return new za(e,t,n,r,i,a,o)}makeSinkPushCredit(e,t,n,r,i){return new Va(e,t,n,r,i)}makeSourceFetchRequest(e,t,n,r,i,a,o,s,c){return new Ua(e,t,n,r,i,a,o,s,c)}makeSourceFetchResponse(e,t,n,r,i,a){return new Ga(e,t,n,r,i,a)}makeSourceFetchChunk(e,t,n,r,i,a,o){return new qa(e,t,n,r,i,a,o)}makeSourceFetchCredit(e,t,n,r,i){return new Ya(e,t,n,r,i)}parse(e){if(typeof e!=`object`||!e)throw Error(`invalid argument: not an object`);if(typeof e.version!=`string`)throw Error(`invalid object: missing or invalid "version" field`);let t=e.version.match(/^MQTT\+\/(\d+\.\d+)$/),n=t===null?0:Sa(t[1]);if(Math.floor(n/100)!==Math.floor(Ca/100)||n<wa)throw Error(`protocol version mismatch (expected version 1.4...1.4, got version ${e.version})`);let r=(e,t,n)=>{let r=Wn(n,e);if(!r.success){let e=r.issues.map(e=>e.message).join(`; `);throw Error(`invalid ${t} object: ${e}`)}return r.output};if(typeof e.type!=`string`)throw Error(`invalid object: missing or invalid "type" field`);if(e.type===`event-emission`){let t=r(e,`EventEmission`,Aa);return this.makeEventEmission(t.id,t.name,t.params,t.sender,t.receiver,t.auth,t.meta)}else if(e.type===`service-call-request`){let t=r(e,`ServiceCallRequest`,Ma);return this.makeServiceCallRequest(t.id,t.name,t.params,t.sender,t.receiver,t.auth,t.meta,t.qos)}else if(e.type===`service-call-response`){let t=r(e,`ServiceCallResponse`,Pa);return this.makeServiceCallResponse(t.id,t.name,t.result,t.error,t.sender,t.receiver)}else if(e.type===`sink-push-request`){let t=r(e,`SinkPushRequest`,Ia);return this.makeSinkPushRequest(t.id,t.name,t.params,t.sender,t.receiver,t.auth,t.meta,t.qos)}else if(e.type===`sink-push-response`){let t=r(e,`SinkPushResponse`,Ra);return this.makeSinkPushResponse(t.id,t.name,t.error,t.sender,t.receiver,t.credit)}else if(e.type===`sink-push-chunk`){let t=r(e,`SinkPushChunk`,Ba);return this.makeSinkPushChunk(t.id,t.name,t.chunk,t.error,t.final,t.sender,t.receiver)}else if(e.type===`sink-push-credit`){let t=r(e,`SinkPushCredit`,Ha);return this.makeSinkPushCredit(t.id,t.name,t.credit,t.sender,t.receiver)}else if(e.type===`source-fetch-request`){let t=r(e,`SourceFetchRequest`,Wa);return this.makeSourceFetchRequest(t.id,t.name,t.params,t.sender,t.receiver,t.auth,t.meta,t.credit,t.qos)}else if(e.type===`source-fetch-response`){let t=r(e,`SourceFetchResponse`,Ka);return this.makeSourceFetchResponse(t.id,t.name,t.error,t.sender,t.receiver,t.meta)}else if(e.type===`source-fetch-chunk`){let t=r(e,`SourceFetchChunk`,Ja);return this.makeSourceFetchChunk(t.id,t.name,t.chunk,t.error,t.final,t.sender,t.receiver)}else if(e.type===`source-fetch-credit`){let t=r(e,`SourceFetchCredit`,Xa);return this.makeSourceFetchCredit(t.id,t.name,t.credit,t.sender,t.receiver)}else throw Error(`invalid object: not of any known type`)}isRequest(e){return e instanceof ka||e instanceof ja||e instanceof Ua||e instanceof Fa}isResponse(e){return e instanceof Na||e instanceof La||e instanceof za||e instanceof Va||e instanceof Ga||e instanceof qa||e instanceof Ya}},Qa=class extends xa{constructor(){super(...arguments),this.msg=new Za}},$a=class{constructor(e,t,n,r){this.timestamp=e,this.level=t,this.msg=n,this.data=r}async resolve(){if(this.msg instanceof Promise&&(this.msg=await this.msg.catch(()=>`<resolve-failed>`)),this.data)for(let e of Object.keys(this.data))this.data[e]instanceof Promise&&(this.data[e]=await this.data[e].catch(()=>`<resolve-failed>`))}toString(){let e=new Date(this.timestamp),t=`${e.getFullYear()}-${(e.getMonth()+1).toString().padStart(2,`0`)}-${e.getDate().toString().padStart(2,`0`)} ${e.getHours().toString().padStart(2,`0`)}:${e.getMinutes().toString().padStart(2,`0`)}:${e.getSeconds().toString().padStart(2,`0`)}.${e.getMilliseconds().toString().padStart(3,`0`)}`,n=this.msg instanceof Promise?`<unresolved>`:this.msg,r=``;if(this.data!==void 0){let e=this.data;r=` (${Object.keys(e).map(t=>{let n=e[t]instanceof Promise?`<unresolved>`:e[t];return`${t}: ${va.stringify(n)}`}).join(`, `)})`}return`[${t}] ${this.level}: ${n}${r}`}},eo=class extends Qa{constructor(){super(...arguments),this._events=new pn.EventEmitter}on(...e){this._events.on(...e)}off(...e){this._events.off(...e)}emitEvent(...e){return this._events.listenerCount(e[0])===0?!1:this._events.emit(...e)}log(e,t,n){let r=new $a(Date.now(),e,t,n);this.emitEvent(`log`,r)}error(e,t){let n=e;t!==void 0&&(n=Error(`${t}: ${e.message}`,{cause:e}),n.stack=e.stack);try{this.emitEvent(`error`,n),this.log(`error`,n.message)}catch{}}},to=class extends eo{constructor(e,t={}){super(t),this.destroyed=!1,this.onRequest=new Map,this.onResponse=new Map,e===null&&(this.log(`info`,`establishing proxy MQTT client`),e=new Proxy({},{get(e,t,n){return t===`isFakeProxy`?!0:typeof t==`string`&&[`on`,`off`,`once`].includes(t)?()=>{}:()=>{throw Error(`Underlying MQTT operation "${String(t)}" called on a null MQTT client -- only MQTT+ "emit({ ..., dry: true })" is supported in this special operation mode`)}}})),this.mqtt=e,this.log(`info`,`hooking into MQTT client`),this.messageHandler=(e,t,n)=>{if(this.destroyed)return;let r;if(this.options.codec===`json`)r=t.toString();else if(this.options.codec===`cbor`)r=be.isBuffer(t)?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):t;else throw Error(`invalid codec configured`);this._onMessage(e,r,n)},this.mqtt.on(`message`,this.messageHandler)}async destroy(){this.destroyed=!0,this.log(`info`,`un-hooking from MQTT client`),this.mqtt.off(`message`,this.messageHandler),this.onRequest.clear(),this.onResponse.clear()}makeRegistration(e,t,n){let r=!1;return{destroy:async()=>{r||(r=!0,await e.unroll(!1)?.catch(e=>{let r=G(e,`destroy: ${t} "${n}" failed to cleanup`);throw this.error(r),r}))}}}async subscribeTopic(e,t={}){return this.log(`info`,`subscribing to MQTT topic "${e}"`),new Promise((n,r)=>{this.mqtt.subscribe(e,{qos:2,...t},(t,i)=>{t?(this.error(t,`subscribing to MQTT topic "${e}" failed`),r(t)):n()})})}async unsubscribeTopic(e){return this.log(`info`,`unsubscribing from MQTT topic "${e}"`),new Promise((t,n)=>{this.mqtt.unsubscribe(e,(r,i)=>{r?(this.error(r,`unsubscribing from MQTT topic "${e}" failed`),n(r)):t()})})}async publishToTopic(e,t,n={}){typeof t==`string`?this.log(`info`,`publishing to MQTT topic "${e}" (type: string, length: ${t.length} chars)`):this.log(`info`,`publishing to MQTT topic "${e}" (type: buffer, length: ${t.byteLength} bytes)`);let r=new Se((e,n)=>{let r;try{let e=this.codec.decode(t);r=this.msg.parse(e)}catch(e){return n(e)}e(r)});return this.log(`debug`,`publishing to MQTT topic "${e}"`,{message:r}),new Promise((r,i)=>{let a=typeof t==`string`?t:be.from(t.buffer,t.byteOffset,t.byteLength);this.mqtt.publish(e,a,n,t=>{t?(this.error(t,`publishing to MQTT topic "${e}" failed`),i(t)):r()})})}_onMessage(e,t,n){if(this.destroyed)return;let r=this.options.topicMatch(e);if(r===null)return;typeof t==`string`?this.log(`info`,`received from MQTT topic "${e}" (type: string, length: ${t.length} chars)`):this.log(`info`,`received from MQTT topic "${e}" (type: buffer, length: ${t.byteLength} bytes)`);let i;try{i=this.codec.decode(t)}catch(e){this.error(G(e,`failed to parse message into object`));return}let a;try{a=this.msg.parse(i)}catch(e){this.error(G(e,`failed to parse object into typed message object`));return}if(this.log(`debug`,`received from MQTT topic "${e}"`,{message:a}),r.peerId!==void 0&&a.receiver!==void 0&&a.receiver!==r.peerId&&this.log(`warning`,`receiver mismatch on direct topic "${e}" (expected "${r.peerId}", got "${a.receiver}")`),this.msg.isRequest(a)){let t=this.onRequest.get(`${a.type}:${a.name}`);t!==void 0&&Promise.resolve().then(()=>{if(!this.destroyed)return t(a,r.name)}).catch(t=>{this.error(G(t,`dispatching request message from MQTT topic "${e}" (type: ${a.type}, id: ${a.id}, name: ${a.name}) failed`))})}else if(this.msg.isResponse(a)){let t=this.onResponse.get(`${a.type}:${a.id}`);t!==void 0&&Promise.resolve().then(()=>{if(!this.destroyed)return t(a,r.name)}).catch(t=>{this.error(G(t,`dispatching response message from MQTT topic "${e}" (type: ${a.type}, id: ${a.id}, name: ${a.name}) failed`))})}}},no=class{constructor(e,t,n=30*1e3){this.subscribeFn=e,this.unsubscribeFn=t,this.lingerMs=n,this.counts=new Map,this.pending=new Map,this.lingers=new Map,this.unsubbing=new Map}incrementCount(e){let t=this.counts.get(e)??0;return this.counts.set(e,t+1),t}decrementCount(e){let t=this.counts.get(e);if(t!==void 0)return t<=1?(this.counts.delete(e),0):(this.counts.set(e,t-1),t-1)}clearCount(e){this.counts.delete(e)}async subscribe(e,t={qos:2}){if(this.incrementCount(e)===0){let n=this.lingers.get(e);if(n){clearTimeout(n),this.lingers.delete(e);return}let r,i,a=new Promise((e,t)=>{r=e,i=t});a.catch(()=>{}),this.pending.set(e,a);let o=this.unsubbing.get(e);return o&&await o,this.subscribeFn(e,t).then(()=>{this.pending.delete(e),r()},t=>{this.pending.delete(e),this.clearCount(e),i(t)}),a}else{let t=this.pending.get(e);if(t)return t}}async unsubscribe(e){if(this.decrementCount(e)===0)if(this.lingerMs>0){let t=setTimeout(()=>{this.lingers.delete(e);let t=this.unsubscribeFn(e).catch(()=>{}).finally(()=>{this.unsubbing.delete(e)});this.unsubbing.set(e,t)},this.lingerMs);this.lingers.set(e,t)}else{let t=this.unsubscribeFn(e).catch(()=>{}).finally(()=>{this.unsubbing.delete(e)});this.unsubbing.set(e,t),await t}}async flush(){let e=new Set([...this.counts.keys(),...this.lingers.keys(),...this.pending.keys(),...this.unsubbing.keys()]);for(let e of this.lingers.values())clearTimeout(e);this.lingers.clear(),this.counts.clear(),await Promise.allSettled([...this.pending.values(),...this.unsubbing.values()]),await Promise.allSettled([...e].map(e=>this.unsubscribeFn(e).catch(()=>{}))),this.pending.clear(),this.unsubbing.clear()}},ro=class extends to{constructor(){super(...arguments),this.subscriptions=new no((e,t)=>this.subscribeTopic(e,t),e=>this.unsubscribeTopic(e))}async subscribeTopicAndSpool(e,t,n={}){await Pe(`subscribe to MQTT topic "${t}"`,e,()=>this.subscriptions.subscribe(t,{qos:2,...n})),e.roll(()=>this.subscriptions.unsubscribe(t))}async destroy(){await this.subscriptions.flush(),await super.destroy()}},io=class extends ro{constructor(){super(...arguments),this.timers=new Map}async destroy(){for(let e of this.timers.values())clearTimeout(e);this.timers.clear(),await super.destroy()}timerRefresh(e,t){let n=this.timers.get(e);n!==void 0&&clearTimeout(n),this.timers.set(e,setTimeout(async()=>{if(!this.destroyed){this.timers.delete(e);try{await t()}catch(t){this.error(G(t),`timer "${e}" failed`)}}},this.options.timeout))}timerClear(e){let t=this.timers.get(e);t!==void 0&&(clearTimeout(t),this.timers.delete(e))}sleep(e,t){return new Promise(n=>{if(t?.aborted){n();return}let r=t===void 0?void 0:new AbortController,i=setTimeout(()=>{i=null,r!==void 0&&r.abort(),n()},e);i.unref(),t!==void 0&&r!==void 0&&t.addEventListener(`abort`,()=>{i!==null&&clearTimeout(i),n()},{once:!0,signal:r.signal})})}timeout(e,t=`timeout`,n){return new Promise((r,i)=>{if(n?.aborted){i(Error(`aborted`));return}let a=n===void 0?void 0:new AbortController,o=setTimeout(()=>{o=null,a!==void 0&&a.abort(),i(Error(t))},e);o.unref(),n!==void 0&&a!==void 0&&n.addEventListener(`abort`,()=>{o!==null&&clearTimeout(o),i(Error(`aborted`))},{once:!0,signal:a.signal})})}},ao=class extends io{constructor(){super(...arguments),this._meta=new Map}meta(...e){let[t,n]=e;if(e.length===0)return Object.fromEntries(this._meta);if(e.length===1)return this._meta.get(t);n==null?this._meta.delete(t):this._meta.set(t,n)}metaStore(e){let t=e===void 0||Object.keys(e).length===0;if(!(this._meta.size===0&&t))return this._meta.size>0&&t?Object.fromEntries(this._meta):this._meta.size===0&&!t?e:{...Object.fromEntries(this._meta),...e}}},oo=new TextEncoder,so=class extends ao{constructor(){super(...arguments),this._credential=null,this._tokens=new Set}credential(e){if(e.length===0)throw Error(`credential must not be empty`);this._credential=ln(un,oo.encode(e),oo.encode(`mqtt-plus`),6e5,32)}async issue(e){if(this._credential===null)throw Error(`credential has to be provided before issuing tokens`);if(e.roles.length===0)throw Error(`payload.roles must be a non-empty array`);if(e.roles.length>64)throw Error(`payload.roles must not exceed 64 roles`);let t=new Qt(e);return t.setProtectedHeader({alg:`HS256`,typ:`JWT`}),await t.sign(this._credential)}authenticate(e,t){if(e===void 0){let e=Array.from(this._tokens);return e.length>0?e:void 0}else if(t===!0)this._tokens.delete(e);else{if(e.length>8192)throw Error(`token must not exceed 8192 characters`);if(!this._tokens.has(e)&&this._tokens.size>=8)throw Error(`at most 8 tokens can be authenticated at once`);this._tokens.add(e)}}async validateToken(e){if(this._credential===null)throw Error(`credential has to be provided before validating tokens`);try{return(await nn(e,this._credential)).payload}catch(e){let t=e?.code??e?.name??`unknown`,n=e?.message??``;return this.log(`warning`,`token validation failed`,{code:t,reason:n}),null}}async authenticated(e,t,n,r){let i=!1,a=typeof n==`string`?[n]:n.roles;if(t!==void 0)for(let n of t.slice(0,8)){if(n.length>8192)continue;let t=await this.validateToken(n);if(t!==null&&!(t.id&&t.id!==e)&&Array.isArray(t.roles)&&!(t.roles.length>64)){for(let e of a)if(t.roles.includes(e)){i=!0;break}if(i)break}}let o=typeof n==`string`||n.mode===`require`;if(!i&&o)throw Error(`${r} failed authentication`);return i}},co=class extends so{constructor(){super(...arguments),this.eventControllers=new Map}async destroy(){for(let e of this.eventControllers.values())e.abort(Error(`event destroyed`));this.eventControllers.clear(),await super.destroy()}async event(e,...t){if(this.destroyed)throw Error(`event: instance already destroyed`);let n,r,i={},a=this.options.share,o;if(typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.callback,i=e.options??{},a=e.share??this.options.share,o=e.auth):(n=e,r=t[0]),typeof r!=`function`)throw Error(`event: callback argument is required and must be a function`);let s=new je;if(this.onRequest.has(`event-emission:${n}`))throw Error(`event: event "${n}" already registered`);let c=new Set;s.roll(()=>{for(let e of c)this.eventControllers.get(e)?.abort(Error(`event "${n}" destroyed`)),this.eventControllers.delete(e);c.clear()});let l=a===``?n:`$share/${a}/${n}`,u=this.options.topicMake(l,`event-emission`),d=this.options.topicMake(n,`event-emission`,this.options.id);return this.onRequest.set(`event-emission:${n}`,async(e,t)=>{if(e.receiver&&e.receiver!==this.options.id)return;let i=e.id,a=e.sender;if(a===void 0||a===``){this.error(Error(`invalid request: missing sender`));return}if(t!==e.name){this.log(`warning`,`event name mismatch -- dropped request for "${n}" (topic: "${t}", payload: "${e.name}")`,{requestId:i});return}let s=e.params??[];if(this.eventControllers.has(i)){this.log(`warning`,`duplicate event request id -- dropped request for event "${n}"`,{requestId:i});return}let l=new AbortController,u=l.signal;c.add(i),this.eventControllers.set(i,l);let d={sender:a,signal:u};e.receiver&&(d.receiver=e.receiver),e.meta&&(d.meta=e.meta);try{o&&(d.authenticated=await this.authenticated(a,e.auth,o,`event "${n}"`)),await r(...s,d)}catch(e){let t=G(e);this.error(t,`handler for event "${n}" failed`)}finally{l.abort(),c.delete(i),this.eventControllers.delete(i)}}),s.roll(()=>{this.onRequest.delete(`event-emission:${n}`)}),await this.subscribeTopicAndSpool(s,u,i),await this.subscribeTopicAndSpool(s,d,i),this.makeRegistration(s,`event`,n)}emit(e,...t){if(this.destroyed)throw Error(`emit: instance already destroyed`);let n,r,i,a={},o,s;typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.params,i=e.receiver,a=e.options??{},o=e.meta,s=e.dry):(n=e,r=t);let c=R(),l=this.authenticate(),u=this.metaStore(o),d=this.msg.makeEventEmission(c,n,r,this.options.id,i,l,u),f=this.codec.encode(d),p=this.options.topicMake(n,`event-emission`,i);return s?{topic:p,payload:f,options:{qos:2,...a}}:Pe(`publish event as MQTT message to topic "${p}"`,()=>this.publishToTopic(p,f,{qos:2,...a}))}},lo=class extends co{constructor(){super(...arguments),this.serviceControllers=new Map,this.pendingCalls=new Map}async destroy(){for(let e of this.serviceControllers.values())e.abort(Error(`service destroyed`));this.serviceControllers.clear();let e=[...this.pendingCalls.values()];this.pendingCalls.clear();for(let t of e)t(Error(`instance destroyed`));await super.destroy()}async service(e,...t){if(this.destroyed)throw Error(`service: instance already destroyed`);let n,r,i={},a=this.options.share,o;if(typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.callback,i=e.options??{},a=e.share??this.options.share,o=e.auth):(n=e,r=t[0]),typeof r!=`function`)throw Error(`service: callback argument is required and must be a function`);let s=new je;if(this.onRequest.has(`service-call-request:${n}`))throw Error(`service: service "${n}" already registered`);let c=new Set;s.roll(()=>{for(let e of c)this.serviceControllers.get(e)?.abort(Error(`service "${n}" destroyed`)),this.serviceControllers.delete(e);c.clear()});let l=a===``?n:`$share/${a}/${n}`,u=this.options.topicMake(l,`service-call-request`),d=this.options.topicMake(n,`service-call-request`,this.options.id);return this.onRequest.set(`service-call-request:${n}`,async(e,t)=>{if(e.receiver&&e.receiver!==this.options.id)return;let i=e.id,a=e.sender,s=e.params??[];if(a===void 0||a===``){this.error(Error(`invalid request: missing sender`));return}if(t!==e.name){this.log(`warning`,`service name mismatch -- dropped request for "${n}" (topic: "${t}", payload: "${e.name}")`,{requestId:i});return}if(this.serviceControllers.has(i)){this.log(`warning`,`duplicate service request id -- dropped request for "${n}"`,{requestId:i});return}let l=new AbortController,u=l.signal;c.add(i),this.serviceControllers.set(i,l);let d={sender:a,signal:u};e.receiver&&(d.receiver=e.receiver),e.meta&&(d.meta=e.meta);let f=`service-call-handler:${i}`,p=()=>{this.timerRefresh(f,()=>{l.abort(Error(`service "${n}" handler timeout`))})},m=()=>this.timerClear(f);p();let h;try{o&&(d.authenticated=await this.authenticated(a,e.auth,o,`service "${n}"`));let t=new Promise((e,t)=>{let n=()=>{t(G(u.reason))};u.aborted?n():(u.addEventListener(`abort`,n,{once:!0}),h=()=>u.removeEventListener(`abort`,n))}),c=await Promise.race([r(...s,d),t]),l=this.msg.makeServiceCallResponse(i,n,c,void 0,this.options.id,a),f=this.codec.encode(l),p=this.options.topicMake(n,`service-call-response`,a);await this.publishToTopic(p,f,{qos:e.qos??2})}catch(t){let r=G(t);this.error(r,`handler for service "${n}" failed`);let o=this.msg.makeServiceCallResponse(i,n,void 0,r.message,this.options.id,a);try{let t=this.codec.encode(o),r=this.options.topicMake(n,`service-call-response`,a);await this.publishToTopic(r,t,{qos:e.qos??2})}catch(e){this.error(G(e),`sending error response for service "${n}" failed`)}}finally{h?.(),m(),l.abort(),c.delete(i),this.serviceControllers.delete(i)}}),s.roll(()=>{this.onRequest.delete(`service-call-request:${n}`)}),await this.subscribeTopicAndSpool(s,u,i),await this.subscribeTopicAndSpool(s,d,i),this.makeRegistration(s,`service`,n)}async call(e,...t){if(this.destroyed)throw Error(`call: instance already destroyed`);let n,r,i,a={},o;typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.params,i=e.receiver,a=e.options??{},o=e.meta):(n=e,r=t);let s=new je,c=R();for(let e=0;e<10&&this.onResponse.has(`service-call-response:${c}`);e++)c=R();if(this.onResponse.has(`service-call-response:${c}`))throw Error(`failed to generate unique request id`);let l=this.options.topicMake(n,`service-call-response`,this.options.id);await this.subscribeTopicAndSpool(s,l,{qos:a.qos??2});let u=`service-call:${c}`,d,f=!1,p=()=>f?!1:(f=!0,s.unroll(),!0),m=new Promise((e,t)=>{d=t,this.timerRefresh(u,()=>{p()&&t(Error(`communication timeout`))}),s.roll(()=>{this.timerClear(u)}),this.pendingCalls.set(c,e=>{p()&&t(e)}),s.roll(()=>{this.pendingCalls.delete(c)}),this.onResponse.set(`service-call-response:${c}`,r=>{if(!(i!==void 0&&r.sender!==i)){if(r.sender===void 0||r.sender===``){if(!p())return;t(Error(`received service response without sender`));return}if(r.name!==n){if(!p())return;t(Error(`received service response with name mismatch (expected: "${n}", received: "${r.name}")`));return}p()&&(r.error===void 0?e(r.result):t(Error(r.error)))}}),s.roll(()=>{this.onResponse.delete(`service-call-response:${c}`)})}),h=this.authenticate(),g=this.metaStore(o),_=a.qos??2,v=this.msg.makeServiceCallRequest(c,n,r,this.options.id,i,h,g,_),y=this.codec.encode(v),b=this.options.topicMake(n,`service-call-request`,i);try{await Pe(`publish service request as MQTT message to topic "${b}"`,()=>this.publishToTopic(b,y,{...a,qos:_}))}catch(e){return p()&&d(e),m}return m}},uo=class extends lo{constructor(){super(...arguments),this.sourceCreditGates=new Map,this.sourceControllers=new Map,this.sourceSpools=new Map,this.sourceRequests=new Map}async destroy(){for(let e of this.sourceControllers.values())e.abort(Error(`source destroyed`));for(let e of this.sourceCreditGates.values())e.abort();for(let e of[...this.sourceSpools.values()])await e.unroll();this.sourceSpools.clear(),this.sourceControllers.clear(),this.sourceCreditGates.clear(),this.sourceRequests.clear(),await super.destroy()}async source(e,...t){if(this.destroyed)throw Error(`source: instance already destroyed`);let n,r,i={},a=this.options.share,o;if(typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.callback,i=e.options??{},a=e.share??this.options.share,o=e.auth):(n=e,r=t[0]),typeof r!=`function`)throw Error(`source: callback argument is required and must be a function`);let s=new je;if(this.onRequest.has(`source-fetch-request:${n}`))throw Error(`source: source "${n}" already registered`);let c=a===``?n:`$share/${a}/${n}`,l=this.options.topicMake(c,`source-fetch-request`),u=this.options.topicMake(n,`source-fetch-request`,this.options.id);return this.onRequest.set(`source-fetch-request:${n}`,async(e,t)=>{if(e.receiver&&e.receiver!==this.options.id)return;let a=e.id,s=e.params??[],c=e.sender,l=e.receiver,u=new je;if(this.sourceSpools.set(a,u),u.roll(()=>{this.sourceSpools.delete(a)}),c===void 0||c===``){this.error(Error(`invalid request: missing sender`)),await u.unroll();return}let d=this.options.topicMake(n,`source-fetch-response`,c),f=(e,t)=>Error(`${e} name mismatch (expected "${n}", got "${t}")`),p=async(t,r)=>{let o=this.metaStore(r),s=this.msg.makeSourceFetchResponse(a,n,t,this.options.id,c,o),l=this.codec.encode(s);await this.publishToTopic(d,l,{qos:e.qos??i.qos??2})},m=new AbortController,h=m.signal;if(this.sourceControllers.has(a)){let e=Error(`source: duplicate request id "${a}"`);this.error(e),await p(e.message).catch(()=>{}),await u.unroll();return}this.sourceControllers.set(a,m),u.roll(()=>{this.sourceControllers.delete(a)});let g={sender:c,signal:h};l&&(g.receiver=l),e.meta&&(g.meta=e.meta);let _=this.sourceRequests.get(n);_||(_=new Set,this.sourceRequests.set(n,_)),_.add(a),u.roll(()=>{let e=this.sourceRequests.get(n);e===_&&(e.delete(a),e.size===0&&this.sourceRequests.delete(n))}),h.addEventListener(`abort`,()=>{g.stream instanceof L.Readable&&!g.stream.destroyed&&g.stream.destroy(G(h.reason))},{once:!0}),u.roll(()=>{h.aborted&&g.stream instanceof L.Readable&&!g.stream.destroyed&&g.stream.destroy(G(h.reason))});let v,y=new Promise((e,t)=>{v=t});y.catch(()=>{});let b=()=>{v(G(h.reason))};h.aborted?b():h.addEventListener(`abort`,b,{once:!0}),u.roll(()=>{h.removeEventListener(`abort`,b)});let x=`source-fetch-send:${a}`,S=()=>{h.aborted||this.timerRefresh(x,()=>{m.abort(Error(`source fetch "${n}" timed out`))})},C=()=>this.timerClear(x);S(),u.roll(()=>{C()});let w=async(t,r,o)=>{S();let s=this.msg.makeSourceFetchChunk(a,n,t,r,o,this.options.id,c),l=this.codec.encode(s);await this.publishToTopic(d,l,{qos:e.qos??i.qos??2})},T=!1,E,D=!1;try{if(t!==e.name)throw Error(`source name mismatch (topic: "${t}", payload: "${e.name}")`);this.onResponse.set(`source-fetch-credit:${a}`,e=>{if(!h.aborted){if(e.name!==n){m.abort(f(`source credit`,e.name));return}if(e.sender===void 0||e.sender===``){m.abort(Error(`source credit for "${n}" missing sender`));return}if(e.sender===c){if(e.credit===0){D=!0,m.abort(Error(`source fetch "${n}" cancelled by fetcher`));return}E&&(E.replenish(e.credit),S())}}}),u.roll(()=>{this.onResponse.delete(`source-fetch-credit:${a}`)}),o&&(g.authenticated=await this.authenticated(c,e.auth,o,`source "${n}"`));let i=Promise.resolve(r(...s,g));if(i.catch(()=>{}),await Promise.race([i,y]),!(g.stream instanceof L.Readable)&&!(g.buffer instanceof Promise)&&!(g.buffer instanceof Uint8Array))throw Error(`handler did not provide data via info.stream or info.buffer fields`);if(g.stream instanceof L.Readable&&(g.buffer instanceof Promise||g.buffer instanceof Uint8Array))throw Error(`handler has set both info.stream and info.buffer fields`);let l=e.credit;if(E=l!==void 0&&l>0?new Ce(l):void 0,E){let e=E;this.sourceCreditGates.set(a,e),u.roll(()=>{e.abort(),this.sourceCreditGates.delete(a)})}if(await p(void 0,g.meta),T=!0,g.stream instanceof L.Readable)await ke(g.stream,this.options.chunkSize,w,E,h);else if(g.buffer instanceof Promise||g.buffer instanceof Uint8Array){let e;if(g.buffer instanceof Promise){let t=g.buffer;t.catch(()=>{}),e=await Promise.race([t,y])}else e=g.buffer;h.throwIfAborted(),await Oe(e,this.options.chunkSize,w,E,h)}}catch(e){let t=G(e,`handler for source "${n}" failed`);m.abort(t),D||(this.error(t),T?await w(void 0,t.message,!0).catch(()=>{}):await p(t.message).catch(()=>{}))}finally{await u.unroll()}}),s.roll(()=>{this.onRequest.delete(`source-fetch-request:${n}`)}),s.roll(()=>{let e=this.sourceRequests.get(n);if(e){for(let t of e){let e=this.sourceControllers.get(t);e&&e.abort(Error(`source "${n}" destroyed`));let r=this.sourceCreditGates.get(t);r&&r.abort()}this.sourceRequests.delete(n)}}),await this.subscribeTopicAndSpool(s,l,i),await this.subscribeTopicAndSpool(s,u,i),this.makeRegistration(s,`source`,n)}async fetch(e,...t){if(this.destroyed)throw Error(`fetch: instance already destroyed`);let n,r,i,a={},o;typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.params,i=e.receiver,a=e.options??{},o=e.meta):(n=e,r=t);let s=new je,c=R();for(let e=0;e<10&&(this.onResponse.has(`source-fetch-response:${c}`)||this.onResponse.has(`source-fetch-chunk:${c}`));e++)c=R();if(this.onResponse.has(`source-fetch-response:${c}`)||this.onResponse.has(`source-fetch-chunk:${c}`))throw Error(`failed to generate unique request id`);let l=this.options.topicMake(n,`source-fetch-response`,this.options.id),u=(e,t)=>Error(`${e} name mismatch (expected "${n}", got "${t}")`);await this.subscribeTopicAndSpool(s,l,{qos:a.qos??2});let d=this.options.chunkCredit,f=d>0?d*this.options.chunkSize:16*1024,p=0,m=d,h=i,g=!1,_=!1,v=[],y=(e,t)=>{if(t===void 0||t===``){_=!0;let t=Error(`received ${e} without sender`);return x(t),w?.destroy(t),s.unroll()?.catch(()=>{}),!1}if(h===void 0)h=t;else if(t!==h)return!1;return!0},b,x,S=new Promise((e,t)=>{b=e,x=t});S.catch(()=>{}),s.roll(()=>{b(void 0)});let C=`source-fetch-recv:${c}`,w,T=()=>{_||w&&w.destroyed||this.timerRefresh(C,()=>{let e=Error(`communication timeout`);x(e),w?.destroy(e)})};s.roll(()=>{this.timerClear(C)}),w=new De({highWaterMark:f,read:e=>{if(d<=0||_)return;let t=h;if(!t)return;let r=m-p,i=Math.max(0,f-(w?.readableLength??0)),o=Math.floor(i/this.options.chunkSize),s=Math.max(0,o-r);if(s>0){m+=s;let e=this.msg.makeSourceFetchCredit(c,n,s,this.options.id,t),r=this.codec.encode(e),i=this.options.topicMake(n,`source-fetch-request`,t);this.publishToTopic(i,r,{qos:a.qos??2}).catch(e=>{let t=G(e,`sending source fetch credit failed`);this.error(t),D(t)}),T()}}});let E=w.buffer;T();let D=e=>{_=!0,x(e),w.destroy(e)},O=!1,ee=e=>{if(!O&&!_){O=!0;let e=h;if(e){let t=this.msg.makeSourceFetchCredit(c,n,0,this.options.id,e),r=this.codec.encode(t),i=this.options.topicMake(n,`source-fetch-request`,e);this.publishToTopic(i,r,{qos:a.qos??2}).catch(e=>this.error(G(e,`sending source fetch cancel failed`)))}}_||x(e===void 0?Error(`stream aborted`):G(e)),s.unroll()?.catch(()=>{})};w.once(`close`,()=>ee()),w.once(`error`,e=>ee(e));let k=e=>{if(e.error)D(Error(e.error));else{if(T(),e.chunk!==void 0){if(d>0&&p>=m){D(Error(`flow control violation`));return}p++,w.destroyed||w.push(e.chunk)}e.final&&(_=!0,w.destroyed||w.push(null),s.unroll()?.catch(()=>{}))}};this.onResponse.set(`source-fetch-response:${c}`,e=>{if(!_){if(e.name!==n){D(u(`source response`,e.name));return}if(y(`source response`,e.sender))if(e.error)D(Error(e.error));else{if(g)return;g=!0,b(e.meta),T();for(let e of v){if(_)break;k(e)}v.length=0}}}),this.onResponse.set(`source-fetch-chunk:${c}`,e=>{if(!_){if(e.name!==n){D(u(`source chunk`,e.name));return}if(y(`source chunk`,e.sender)){if(!g){if(d>0&&v.length>=m){D(Error(`flow control violation`));return}v.push(e);return}k(e)}}}),s.roll(()=>{this.onResponse.delete(`source-fetch-response:${c}`),this.onResponse.delete(`source-fetch-chunk:${c}`)});let te=this.authenticate(),A=this.metaStore(o),ne=d>0?d:void 0,re=this.msg.makeSourceFetchRequest(c,n,r,this.options.id,i,te,A,ne,a.qos),ie=this.codec.encode(re),j=this.options.topicMake(n,`source-fetch-request`,i);await Pe(`publish fetch request as MQTT message to topic "${j}"`,()=>this.publishToTopic(j,ie,{qos:2,...a})).catch(e=>{let t=G(e);x(t),w.destroy(t)});let M={stream:w,buffer:E,meta:S};return Ae(M,`stream`,`buffer`,e=>{e===`stream`?w.stopCollecting():e===`buffer`&&w.resume()}),M}},fo=class extends uo{constructor(){super(...arguments),this.pushStreams=new Map,this.pushSpools=new Map,this.pushRecvControllers=new Map,this.destroying=!1,this.pushControllers=new Map,this.pushCreditGates=new Map,this.pushSenderSpools=new Map}async destroy(){this.destroying=!0;for(let e of this.pushSenderSpools.keys())this.timerClear(`sink-push-send:${e}`);for(let e of this.pushSpools.keys())this.timerClear(`sink-push-recv:${e}`);for(let e of this.pushControllers.values())e.abort(Error(`sink destroyed`));for(let e of this.pushCreditGates.values())e.abort();for(let e of[...this.pushSenderSpools.values()])await e.unroll();this.pushSenderSpools.clear(),this.pushControllers.clear(),this.pushCreditGates.clear();for(let e of this.pushRecvControllers.values())e.abort(Error(`sink destroyed`));this.pushRecvControllers.clear();for(let e of this.pushStreams.values())e.destroy(Error(`sink destroyed`));this.pushStreams.clear();for(let e of[...this.pushSpools.values()])await e.unroll();this.pushSpools.clear(),await super.destroy()}async sink(e,...t){if(this.destroyed)throw Error(`sink: instance already destroyed`);let n,r,i={},a=this.options.share,o;if(typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.callback,i=e.options??{},a=e.share??this.options.share,o=e.auth):(n=e,r=t[0]),typeof r!=`function`)throw Error(`sink: callback argument is required and must be a function`);let s=new je;if(this.onRequest.has(`sink-push-request:${n}`))throw Error(`sink: sink "${n}" already registered`);let c=a===``?n:`$share/${a}/${n}`,l=this.options.topicMake(c,`sink-push-request`),u=this.options.topicMake(n,`sink-push-request`,this.options.id);return this.onRequest.set(`sink-push-request:${n}`,async(e,t)=>{if(e.receiver&&e.receiver!==this.options.id)return;let a=e.id,s=e.params??[],c=e.sender,l=e.receiver,u=new je;if(c===void 0||c===``){this.error(Error(`invalid request: missing sender`)),await u.unroll();return}let d=this.options.topicMake(n,`sink-push-response`,c),f=e=>Error(`sink name mismatch (expected "${n}", got "${e}")`),p=this.options.chunkCredit,m=async(t,r=!1)=>{let o=t===void 0&&r&&p>0?p:void 0,s=this.msg.makeSinkPushResponse(a,n,t,this.options.id,c,o),l=this.codec.encode(s);await this.publishToTopic(d,l,{qos:e.qos??i.qos??2})},h=new AbortController,g=h.signal,_,v=new Promise((e,t)=>{_=t});v.catch(()=>{});let y=()=>{_(G(g.reason))};if(g.aborted?y():g.addEventListener(`abort`,y,{once:!0}),u.roll(()=>{g.removeEventListener(`abort`,y)}),this.pushRecvControllers.has(a)){let e=Error(`sink: duplicate request id "${a}"`);this.error(e),await m(e.message).catch(()=>{}),await u.unroll();return}this.pushRecvControllers.set(a,h),u.roll(()=>{this.pushRecvControllers.delete(a)}),this.pushSpools.set(a,u),u.roll(()=>{this.pushSpools.delete(a)});let b=!1,x=!1,S=!1,C,w=()=>{};try{if(t!==e.name)throw Error(`sink name mismatch (topic: "${t}", payload: "${e.name}")`);let _;o&&(_=await this.authenticated(c,e.auth,o,`sink "${n}"`));let y=p>0?{chunksReceived:0,creditGranted:p}:void 0,T=p>0?p*this.options.chunkSize:16*1024,E=!1,D=`sink-push-recv:${a}`,O=()=>this.timerRefresh(D,()=>{if(!(E||this.destroying)&&(h.abort(Error(`push stream timeout`)),c&&!S)){S=!0;let t=this.msg.makeSinkPushCredit(a,n,0,this.options.id,c),r=this.codec.encode(t);this.publishToTopic(d,r,{qos:e.qos??i.qos??2}).catch(()=>{})}}),ee=()=>this.timerClear(D),k=new De({highWaterMark:T,read:t=>{if(!y||!this.pushSpools.has(a))return;let r=y.creditGranted-y.chunksReceived,o=Math.max(0,T-k.readableLength),s=Math.floor(o/this.options.chunkSize),l=Math.max(0,s-r);if(l>0){y.creditGranted+=l;let t=this.msg.makeSinkPushCredit(a,n,l,this.options.id,c),r=this.codec.encode(t);this.publishToTopic(d,r,{qos:e.qos??i.qos??2}).catch(e=>{let t=G(e,`sending sink push credit failed`);this.error(t),k.destroy(t)}),O()}}});C=k,this.pushStreams.set(a,k),u.roll(()=>{this.pushStreams.delete(a)}),k.on(`error`,w),u.roll(()=>{if(!b&&!g.aborted&&!this.destroying&&h.abort(Error(`push stream closed`)),!b&&!this.destroying&&!S&&c){let t=this.msg.makeSinkPushCredit(a,n,0,this.options.id,c),r=this.codec.encode(t);this.publishToTopic(d,r,{qos:e.qos??i.qos??2}).catch(e=>this.error(G(e,`sending sink push cancel failed`)))}}),this.onResponse.set(`sink-push-chunk:${a}`,async e=>{if(!E){if(e.name!==n){E=!0,ee(),k.destroy(f(e.name));return}if(e.sender===void 0||e.sender===``){E=!0,ee(),k.destroy(Error(`sink chunk for "${n}" missing sender`));return}if(e.sender===c)if(e.error!==void 0)E=!0,ee(),k.destroy(Error(e.error));else{if(O(),e.chunk!==void 0){if(y){if(y.chunksReceived>=y.creditGranted){E=!0,ee(),k.destroy(Error(`flow control violation`));return}y.chunksReceived++}k.destroyed||k.push(e.chunk)}e.final&&(E=!0,ee(),k.destroyed||k.push(null))}}}),u.roll(()=>{this.onResponse.delete(`sink-push-chunk:${a}`)}),O(),u.roll(()=>{ee()});let te=k.buffer,A=!1,ne,re,ie=()=>{A||(A=!0,ne())},j=()=>{A||(A=!0,E||k.readableEnded?ne():re(Error(`push stream closed before end`)))},M=e=>{A||(A=!0,re(e))},ae=new Promise((e,t)=>{ne=e,re=t,k.once(`end`,ie),k.once(`close`,j),k.once(`error`,M)});ae.finally(()=>{k.removeListener(`end`,ie),k.removeListener(`close`,j),k.removeListener(`error`,M)}).catch(()=>{});let oe={sender:c,signal:g,stream:k,buffer:te};l&&(oe.receiver=l),_!==void 0&&(oe.authenticated=_),e.meta&&(oe.meta=e.meta),Ae(oe,`stream`,`buffer`,e=>{e===`stream`?k.stopCollecting():e===`buffer`&&k.resume()}),await m(void 0,!0),x=!0;let N=Promise.resolve(r(...s,oe));if(N.catch(()=>{}),await Promise.race([N,v]),k.readableFlowing!==!0&&!k.destroyed&&k.resume(),await ae.catch(e=>{throw this.error(G(e),`stream drain after sink "${n}" callback failed`),e}),k.collecting&&k.stopCollecting(),!g.aborted)try{b=!0,await m()}catch(e){this.error(G(e),`sending terminal response for sink "${n}" failed`)}}catch(e){let t=G(e,`handler for sink "${n}" failed`);if(h.abort(t),x&&!this.destroying){let e=this.pushStreams.get(a);e!==void 0&&!e.destroyed&&e.destroy(t)}this.error(t),S||(S=!0,await m(t.message).catch(()=>{}))}finally{let e=this.pushStreams.get(a);e!==void 0&&!e.destroyed&&!b&&!S&&e.destroy(g.aborted?G(g.reason):Error(`sink push aborted without cause`)),await u.unroll(),C!==void 0&&C.removeListener(`error`,w)}}),s.roll(()=>{this.onRequest.delete(`sink-push-request:${n}`)}),await this.subscribeTopicAndSpool(s,l,i),await this.subscribeTopicAndSpool(s,u,i),this.makeRegistration(s,`sink`,n)}async push(e,...t){if(this.destroyed)throw Error(`push: instance already destroyed`);let n,r,i,a,o={},s;if(typeof e==`object`&&e&&`name`in e?(n=e.name,r=e.data,i=e.params,a=e.receiver,o=e.options??{},s=e.meta):(n=e,r=t[0],i=t.slice(1)),!(r instanceof L.Readable)&&!(r instanceof Uint8Array))throw Error(`invalid data type: expected Readable or Uint8Array`);let c=new je,l=R();for(let e=0;e<10&&(this.onResponse.has(`sink-push-response:${l}`)||this.onResponse.has(`sink-push-credit:${l}`));e++)l=R();if(this.onResponse.has(`sink-push-response:${l}`)||this.onResponse.has(`sink-push-credit:${l}`))throw Error(`failed to generate unique request id`);this.pushSenderSpools.set(l,c),c.roll(()=>{this.pushSenderSpools.delete(l)});let u=this.options.topicMake(n,`sink-push-response`,this.options.id);await this.subscribeTopicAndSpool(c,u,{qos:o.qos??2});let d=new AbortController,f=d.signal;if(this.pushControllers.set(l,d),c.roll(()=>{this.pushControllers.delete(l)}),r instanceof L.Readable){let e=r;f.addEventListener(`abort`,()=>{e.destroyed||e.destroy(G(f.reason))},{once:!0})}let p=`sink-push-send:${l}`,m=()=>{f.aborted||this.timerRefresh(p,()=>{let e=Error(`push to sink "${n}" timed out`);d.abort(e)})};c.roll(()=>{this.timerClear(p)}),m();let h,g,_=0,v,y=!1,b=!1,x=!1,S=!1,C=!1,w=!1,T=!1,E=a,D,O,ee=new Promise((e,t)=>{D=e,O=t});ee.catch(()=>{});let k=(e,t)=>{if(t===void 0||t===``){let t=Error(`received ${e} without sender`);return v=t,d.abort(t),b?S||(S=!0,O(t)):(x=!0,A(t)),!1}if(E===void 0)E=t;else if(t!==E)return!1;return!0},te,A,ne=new Promise((e,t)=>{te=e,A=t});this.onResponse.set(`sink-push-response:${l}`,e=>{if(e.name!==n){let t=Error(`sink response name mismatch (expected "${n}", got "${e.name}")`);v=t,d.abort(t),b?S||(S=!0,O(t)):(x=!0,A(t));return}if(k(`sink response`,e.sender))if(e.error){let t=Error(e.error);v=t,d.abort(t),b?S||(S=!0,O(t)):(x=!0,A(t))}else b?S||(w?(S=!0,D()):T=!0):(h=e.credit,b=!0,x=!0,te())}),c.roll(()=>{this.onResponse.delete(`sink-push-response:${l}`)}),this.onResponse.set(`sink-push-credit:${l}`,e=>{if(e.name!==n){let t=Error(`sink credit name mismatch (expected "${n}", got "${e.name}")`);v=t,d.abort(t),b?S||(S=!0,O(t)):(x=!0,A(t));return}if(k(`sink credit`,e.sender)){if(e.credit===0){y=!0;let e=Error(`push to sink "${n}" cancelled by receiver`);d.abort(e),b?S||(S=!0,O(e)):(x=!0,A(e));return}if(g!==void 0)g.replenish(e.credit),m();else if(b&&h===void 0){let e=Error(`push to sink "${n}" received unsolicited credit (credit-flow disabled)`);v=e,d.abort(e),S||(S=!0,O(e))}else _+=e.credit}}),c.roll(()=>{this.onResponse.delete(`sink-push-credit:${l}`)});try{let e=()=>{let e=G(f.reason);x||(x=!0,A(e)),S||(S=!0,O(e))};f.addEventListener(`abort`,e,{once:!0}),c.roll(()=>{f.removeEventListener(`abort`,e)});let t=this.authenticate(),u=this.metaStore(s),d=this.msg.makeSinkPushRequest(l,n,i,this.options.id,a,t,u,o.qos),p=this.codec.encode(d),v=this.options.topicMake(n,`sink-push-request`,a);if(await Pe(`publish push request as MQTT message to topic "${v}"`,()=>this.publishToTopic(v,p,{qos:2,...o})),await ne,h!==void 0&&h>0)g=new Ce(h+_),_>0&&m(),_=0;else if(_>0)throw Error(`push to sink "${n}" received unsolicited credit (credit-flow disabled)`);if(g&&(this.pushCreditGates.set(l,g),c.roll(()=>{this.pushCreditGates.delete(l)})),g){let e=g;c.roll(()=>{e.abort()})}let y=E;if(y===void 0)throw Error(`push to sink "${n}" missing responder`);let b=this.options.topicMake(n,`sink-push-request`,y),k=async(e,t,r)=>{m();let i=this.msg.makeSinkPushChunk(l,n,e,t,r,this.options.id,y),a=this.codec.encode(i);await this.publishToTopic(b,a,{qos:2,...o}),t===void 0&&r&&(C=!0)};r instanceof L.Readable?await ke(r,this.options.chunkSize,k,g,f):r instanceof Uint8Array&&await Oe(r,this.options.chunkSize,k,g,f),w=!0,T&&!S&&(S=!0,D()),m(),S||await ee}catch(e){let t=G(e);if(d.abort(t),b&&!v&&!y&&!C)try{let e=E;if(e!==void 0){let r=this.options.topicMake(n,`sink-push-request`,e),i=this.msg.makeSinkPushChunk(l,n,void 0,t.message,!0,this.options.id,e),a=this.codec.encode(i);await this.publishToTopic(r,a,{qos:2,...o}).catch(()=>{})}}catch{}throw b&&!v&&await new Promise(e=>{setImmediate(e)}),v||e}finally{await c.unroll()}}};return class extends fo{}});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mqtt-plus",
3
- "version": "1.4.18",
3
+ "version": "1.4.19",
4
4
  "description": "MQTT Communication Patterns",
5
5
  "keywords": [ "mqtt",
6
6
  "event", "emit",
@@ -33,7 +33,7 @@
33
33
  "patch-package": "8.0.1",
34
34
  "@rse/stx": "1.1.5",
35
35
  "shx": "0.4.0",
36
- "eslint": "10.2.0",
36
+ "eslint": "10.2.1",
37
37
  "globals": "17.5.0",
38
38
  "@eslint/js": "10.0.1",
39
39
  "@eslint/eslintrc": "3.3.5",
@@ -46,7 +46,7 @@
46
46
  "sinon": "21.1.2",
47
47
  "c8": "11.0.0",
48
48
  "source-map-support": "0.5.21",
49
- "typescript": "6.0.2",
49
+ "typescript": "6.0.3",
50
50
  "typescript-eslint": "8.58.2",
51
51
  "@typescript-eslint/parser": "8.58.2",
52
52
  "mqtt": "5.15.1",
@@ -169,8 +169,6 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
169
169
 
170
170
  /* create a resource spool for request cleanup */
171
171
  const reqSpool = new Spool()
172
- this.pushSpools.set(requestId, reqSpool)
173
- reqSpool.roll(() => { this.pushSpools.delete(requestId) })
174
172
 
175
173
  /* sanity check sender */
176
174
  if (sender === undefined || sender === "") {
@@ -218,6 +216,8 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
218
216
  }
219
217
  this.pushRecvControllers.set(requestId, abortController)
220
218
  reqSpool.roll(() => { this.pushRecvControllers.delete(requestId) })
219
+ this.pushSpools.set(requestId, reqSpool)
220
+ reqSpool.roll(() => { this.pushSpools.delete(requestId) })
221
221
 
222
222
  /* check authentication and prepare stream */
223
223
  let dataCompleted = false
@@ -432,10 +432,9 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
432
432
  ackSent = true
433
433
 
434
434
  /* call handler */
435
- await Promise.race([
436
- Promise.resolve(callback(...params, info)),
437
- abortPromise
438
- ])
435
+ const callbackPromise = Promise.resolve(callback(...params, info))
436
+ callbackPromise.catch(() => {}) /* guard against unhandled rejection if abort wins the race */
437
+ await Promise.race([ callbackPromise, abortPromise ])
439
438
 
440
439
  /* ensure stream is consumed or destroyed to prevent hang */
441
440
  if (readable.readableFlowing !== true && !readable.destroyed)
@@ -475,10 +474,14 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
475
474
  stream.destroy(error)
476
475
  }
477
476
 
478
- /* send error as nak response or as mid-stream error response */
477
+ /* send error as nak response or as mid-stream error response
478
+ (skip when a terminal signal was already emitted, e.g. the
479
+ pre-emptive credit=0 cancel published by the timeout handler) */
479
480
  this.error(error)
480
- errorResponseSent = true
481
- await sendResponse(error.message).catch(() => {})
481
+ if (!errorResponseSent) {
482
+ errorResponseSent = true
483
+ await sendResponse(error.message).catch(() => {})
484
+ }
482
485
  }
483
486
  finally {
484
487
  /* cleanup resources */
@@ -749,6 +752,17 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
749
752
  creditGate.replenish(response.credit)
750
753
  refreshTimeout()
751
754
  }
755
+ else if (pushAcked && initialCredit === undefined) {
756
+ /* protocol violation: receiver sent credit despite
757
+ not granting initial credit during ack */
758
+ const error = new Error(`push to sink "${name}" received unsolicited credit (credit-flow disabled)`)
759
+ remoteErrorObject = error
760
+ abortController.abort(error)
761
+ if (!pushFinalized) {
762
+ pushFinalized = true
763
+ pushFinalizeReject(error)
764
+ }
765
+ }
752
766
  else
753
767
  pendingCredit += response.credit
754
768
  })
@@ -790,6 +804,9 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
790
804
  refreshTimeout()
791
805
  pendingCredit = 0
792
806
  }
807
+ else if (pendingCredit > 0)
808
+ /* protocol violation: receiver sent credit before ack despite not granting initial credit */
809
+ throw new Error(`push to sink "${name}" received unsolicited credit (credit-flow disabled)`)
793
810
 
794
811
  /* register credit gate at instance level */
795
812
  if (creditGate) {
@@ -263,10 +263,9 @@ export class SourceTrait<T extends APISchema = APISchema> extends ServiceTrait<T
263
263
  try {
264
264
  if (topicName !== request.name)
265
265
  throw new Error(`source name mismatch (topic: "${topicName}", payload: "${request.name}")`)
266
- if (auth)
267
- info.authenticated = await this.authenticated(sender, request.auth, auth, `source "${name}"`)
268
266
 
269
- /* register credit/cancel handler (unconditional for cancel support) */
267
+ /* register credit/cancel handler early (before any await) so cancel
268
+ signals arriving during async authentication are not lost */
270
269
  this.onResponse.set(`source-fetch-credit:${requestId}`, (creditParsed: SourceFetchCredit) => {
271
270
  if (abortSignal.aborted)
272
271
  return
@@ -295,10 +294,14 @@ export class SourceTrait<T extends APISchema = APISchema> extends ServiceTrait<T
295
294
  this.onResponse.delete(`source-fetch-credit:${requestId}`)
296
295
  })
297
296
 
298
- await Promise.race([
299
- Promise.resolve(callback(...params, info)),
300
- abortPromise
301
- ])
297
+ /* check for authentication */
298
+ if (auth)
299
+ info.authenticated = await this.authenticated(sender, request.auth, auth, `source "${name}"`)
300
+
301
+ /* finally call the handler callback */
302
+ const callbackPromise = Promise.resolve(callback(...params, info))
303
+ callbackPromise.catch(() => {}) /* guard against unhandled rejection if abort wins the race */
304
+ await Promise.race([ callbackPromise, abortPromise ])
302
305
 
303
306
  /* check for valid data source */
304
307
  if (!(info.stream instanceof Readable) && !(info.buffer instanceof Promise) && !(info.buffer instanceof Uint8Array))
@@ -329,9 +332,14 @@ export class SourceTrait<T extends APISchema = APISchema> extends ServiceTrait<T
329
332
  await sendStreamAsChunks(info.stream, this.options.chunkSize, sendChunk, creditGate, abortSignal)
330
333
  else if (info.buffer instanceof Promise || info.buffer instanceof Uint8Array) {
331
334
  /* handle Buffer result */
332
- const buffer = (info.buffer instanceof Promise)
333
- ? await Promise.race([ info.buffer, abortPromise ])
334
- : info.buffer
335
+ let buffer: Uint8Array
336
+ if (info.buffer instanceof Promise) {
337
+ const bufferPromise = info.buffer
338
+ bufferPromise.catch(() => {}) /* guard against unhandled rejection if abort wins the race */
339
+ buffer = await Promise.race([ bufferPromise, abortPromise ])
340
+ }
341
+ else
342
+ buffer = info.buffer
335
343
 
336
344
  /* re-check abort: a late info.buffer resolution could win the race */
337
345
  /* by a microtask margin even after abort fired -- discard silently */