mqtt-plus 1.4.24 → 1.4.26
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/.ase/config.yaml +1 -0
- package/.ase/service.log +39 -0
- package/.ase/service.yaml +1 -0
- package/.ase/task/TASK-P18.md +1 -1
- package/.ase/task/TASK-P21.md +1 -1
- package/.claude/settings.local.json +4 -1
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +29 -5
- package/README.md +2 -2
- package/doc/mqtt-plus-broker-setup.md +1 -1
- package/doc/mqtt-plus-comm.md +3 -3
- package/doc/mqtt-plus-internals.md +6 -0
- package/dst-stage1/mqtt-plus-base.d.ts +2 -2
- package/dst-stage1/mqtt-plus-base.js +13 -10
- package/dst-stage1/mqtt-plus-error.js +54 -28
- package/dst-stage1/mqtt-plus-event.js +3 -1
- package/dst-stage1/mqtt-plus-options.js +7 -0
- package/dst-stage1/mqtt-plus-service.js +9 -6
- package/dst-stage1/mqtt-plus-sink.js +27 -54
- package/dst-stage1/mqtt-plus-source.js +13 -9
- package/dst-stage1/mqtt-plus-util.d.ts +1 -0
- package/dst-stage1/mqtt-plus-util.js +25 -4
- package/dst-stage1/mqtt-plus.d.ts +1 -1
- package/dst-stage1/mqtt-plus.js +2 -0
- package/dst-stage2/mqtt-plus.cjs.cjs +165 -124
- package/dst-stage2/mqtt-plus.esm.js +155 -123
- package/dst-stage2/mqtt-plus.umd.js +11 -11
- package/etc/stx.conf +3 -2
- package/package.d/@typescript-eslint+typescript-estree+8.66.0.patch +12 -0
- package/package.d/{vite+8.0.13.patch → vite+8.2.1.patch} +2 -2
- package/package.json +27 -28
- package/src/mqtt-plus-base.ts +15 -12
- package/src/mqtt-plus-error.ts +65 -33
- package/src/mqtt-plus-event.ts +2 -1
- package/src/mqtt-plus-options.ts +8 -0
- package/src/mqtt-plus-service.ts +9 -6
- package/src/mqtt-plus-sink.ts +28 -54
- package/src/mqtt-plus-source.ts +13 -9
- package/src/mqtt-plus-util.ts +27 -4
- package/src/mqtt-plus.ts +3 -1
- package/tst/mqtt-plus-0-fixture.ts +1 -0
- package/tst/mqtt-plus-2-event.spec.ts +25 -0
- package/tst/mqtt-plus-4-sink.spec.ts +23 -0
- package/tst/mqtt-plus-5-source.spec.ts +26 -0
- package/tst/mqtt-plus-6-misc.spec.ts +58 -0
- package/tst/mqtt-plus-8-run.spec.ts +60 -0
- package/dst-stage1/mqtt-plus-api.js.map +0 -1
- package/dst-stage1/mqtt-plus-auth.js.map +0 -1
- package/dst-stage1/mqtt-plus-base.js.map +0 -1
- package/dst-stage1/mqtt-plus-codec.js.map +0 -1
- package/dst-stage1/mqtt-plus-encode.js.map +0 -1
- package/dst-stage1/mqtt-plus-error.js.map +0 -1
- package/dst-stage1/mqtt-plus-event.js.map +0 -1
- package/dst-stage1/mqtt-plus-info.js.map +0 -1
- package/dst-stage1/mqtt-plus-meta.js.map +0 -1
- package/dst-stage1/mqtt-plus-msg.js.map +0 -1
- package/dst-stage1/mqtt-plus-options.js.map +0 -1
- package/dst-stage1/mqtt-plus-service.js.map +0 -1
- package/dst-stage1/mqtt-plus-sink.js.map +0 -1
- package/dst-stage1/mqtt-plus-source.js.map +0 -1
- package/dst-stage1/mqtt-plus-subscription.js.map +0 -1
- package/dst-stage1/mqtt-plus-timer.js.map +0 -1
- package/dst-stage1/mqtt-plus-trace.js.map +0 -1
- package/dst-stage1/mqtt-plus-util.js.map +0 -1
- package/dst-stage1/mqtt-plus-version.js.map +0 -1
- package/dst-stage1/mqtt-plus.js.map +0 -1
- package/package.d/@typescript-eslint+typescript-estree+8.59.3.patch +0 -12
|
@@ -119,6 +119,7 @@ var ReadableTee = class extends Readable {
|
|
|
119
119
|
}
|
|
120
120
|
};
|
|
121
121
|
async function sendBufferAsChunks(buffer, chunkSize, sendChunk, creditGate, abortSignal) {
|
|
122
|
+
if (!(Number.isFinite(chunkSize) && chunkSize > 0)) throw new Error("invalid chunk size");
|
|
122
123
|
if (buffer.byteLength === 0) await sendChunk(void 0, void 0, true);
|
|
123
124
|
else for (let i = 0; i < buffer.byteLength; i += chunkSize) {
|
|
124
125
|
if (abortSignal?.aborted) throw abortSignal.reason ?? /* @__PURE__ */ new Error("aborted");
|
|
@@ -130,6 +131,7 @@ async function sendBufferAsChunks(buffer, chunkSize, sendChunk, creditGate, abor
|
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
async function sendStreamAsChunks(readable, chunkSize, sendChunk, creditGate, abortSignal) {
|
|
134
|
+
if (!(Number.isFinite(chunkSize) && chunkSize > 0)) throw new Error("invalid chunk size");
|
|
133
135
|
let pending;
|
|
134
136
|
for await (const raw of readable) {
|
|
135
137
|
if (abortSignal?.aborted) throw abortSignal.reason ?? /* @__PURE__ */ new Error("aborted");
|
|
@@ -152,11 +154,17 @@ async function sendStreamAsChunks(readable, chunkSize, sendChunk, creditGate, ab
|
|
|
152
154
|
await sendChunk(pending, void 0, true);
|
|
153
155
|
} else await sendChunk(void 0, void 0, true);
|
|
154
156
|
}
|
|
157
|
+
function alignHandlerParams(params, handler) {
|
|
158
|
+
if (typeof handler !== "function") return params;
|
|
159
|
+
const arity = handler.length - 1;
|
|
160
|
+
if (params.length >= arity) return params;
|
|
161
|
+
return [...params, ...Array(arity - params.length).fill(void 0)];
|
|
162
|
+
}
|
|
155
163
|
function makeMutuallyExclusiveFields(obj, f1Name, f2Name, onConsumed) {
|
|
156
164
|
if (!(typeof obj === "object" && obj !== null)) throw new Error("invalid object");
|
|
157
165
|
let consumed;
|
|
158
|
-
|
|
159
|
-
|
|
166
|
+
let f1Value = obj[f1Name];
|
|
167
|
+
let f2Value = obj[f2Name];
|
|
160
168
|
Object.defineProperty(obj, f1Name, {
|
|
161
169
|
get: () => {
|
|
162
170
|
if (consumed === "f2") throw new Error(`field "${f1Name}" is mutually exclusive with field "${f2Name}" and "${f2Name}" was already consumed`);
|
|
@@ -164,7 +172,10 @@ function makeMutuallyExclusiveFields(obj, f1Name, f2Name, onConsumed) {
|
|
|
164
172
|
consumed = "f1";
|
|
165
173
|
return f1Value;
|
|
166
174
|
},
|
|
167
|
-
|
|
175
|
+
set: (value) => {
|
|
176
|
+
f1Value = value;
|
|
177
|
+
},
|
|
178
|
+
enumerable: false,
|
|
168
179
|
configurable: true
|
|
169
180
|
});
|
|
170
181
|
Object.defineProperty(obj, f2Name, {
|
|
@@ -174,7 +185,10 @@ function makeMutuallyExclusiveFields(obj, f1Name, f2Name, onConsumed) {
|
|
|
174
185
|
consumed = "f2";
|
|
175
186
|
return f2Value;
|
|
176
187
|
},
|
|
177
|
-
|
|
188
|
+
set: (value) => {
|
|
189
|
+
f2Value = value;
|
|
190
|
+
},
|
|
191
|
+
enumerable: false,
|
|
178
192
|
configurable: true
|
|
179
193
|
});
|
|
180
194
|
}
|
|
@@ -258,8 +272,10 @@ function ensureError(error, prefix, debug = false) {
|
|
|
258
272
|
} else return new Error(msg);
|
|
259
273
|
}
|
|
260
274
|
function runFinally(isAsync, onfinally, description) {
|
|
261
|
-
if (!onfinally)
|
|
262
|
-
|
|
275
|
+
if (!onfinally) {
|
|
276
|
+
if (isAsync) return Promise.resolve();
|
|
277
|
+
else return;
|
|
278
|
+
}
|
|
263
279
|
let result;
|
|
264
280
|
try {
|
|
265
281
|
result = onfinally();
|
|
@@ -275,8 +291,10 @@ function runFinally(isAsync, onfinally, description) {
|
|
|
275
291
|
return result;
|
|
276
292
|
}
|
|
277
293
|
function runUnroll(isAsync, spool) {
|
|
278
|
-
if (!spool)
|
|
279
|
-
|
|
294
|
+
if (!spool) {
|
|
295
|
+
if (isAsync) return Promise.resolve();
|
|
296
|
+
else return;
|
|
297
|
+
}
|
|
280
298
|
let result = spool.unroll();
|
|
281
299
|
if (!isAsync && result instanceof Promise) throw new Error("spool unroll returned Promise in non-async context");
|
|
282
300
|
if (isAsync && !(result instanceof Promise)) result = Promise.resolve(result);
|
|
@@ -290,9 +308,12 @@ function runSettle(isAsync, pending, spool, onfinally, description) {
|
|
|
290
308
|
} catch (arg) {
|
|
291
309
|
failure = ensureError(arg, description);
|
|
292
310
|
}
|
|
293
|
-
if (pending || failure !== void 0) {
|
|
311
|
+
if (pending !== void 0 || failure !== void 0) {
|
|
294
312
|
runUnroll(false, spool);
|
|
295
|
-
if (
|
|
313
|
+
if (failure !== void 0) {
|
|
314
|
+
if (pending !== void 0) pending.suppressed = failure;
|
|
315
|
+
else throw failure;
|
|
316
|
+
}
|
|
296
317
|
}
|
|
297
318
|
} else return (async () => {
|
|
298
319
|
let failure;
|
|
@@ -301,12 +322,34 @@ function runSettle(isAsync, pending, spool, onfinally, description) {
|
|
|
301
322
|
} catch (arg) {
|
|
302
323
|
failure = ensureError(arg, description);
|
|
303
324
|
}
|
|
304
|
-
if (pending || failure !== void 0) {
|
|
325
|
+
if (pending !== void 0 || failure !== void 0) {
|
|
305
326
|
await runUnroll(true, spool);
|
|
306
|
-
if (
|
|
327
|
+
if (failure !== void 0) {
|
|
328
|
+
if (pending !== void 0) pending.suppressed = failure;
|
|
329
|
+
else throw failure;
|
|
330
|
+
}
|
|
307
331
|
}
|
|
308
332
|
})();
|
|
309
333
|
}
|
|
334
|
+
function runFail(error, spool, onfinally, description) {
|
|
335
|
+
const attach = (arg) => {
|
|
336
|
+
error.suppressed = ensureError(arg, description);
|
|
337
|
+
};
|
|
338
|
+
let result = void 0;
|
|
339
|
+
try {
|
|
340
|
+
result = onfinally?.();
|
|
341
|
+
} catch (arg) {
|
|
342
|
+
attach(arg);
|
|
343
|
+
}
|
|
344
|
+
if (result instanceof Promise) return result.catch(attach).then(() => spool?.unroll()).then(() => {
|
|
345
|
+
throw error;
|
|
346
|
+
});
|
|
347
|
+
const unrolled = spool?.unroll();
|
|
348
|
+
if (unrolled instanceof Promise) return unrolled.then(() => {
|
|
349
|
+
throw error;
|
|
350
|
+
});
|
|
351
|
+
throw error;
|
|
352
|
+
}
|
|
310
353
|
function run(...args) {
|
|
311
354
|
let description;
|
|
312
355
|
let spool;
|
|
@@ -352,25 +395,18 @@ function run(...args) {
|
|
|
352
395
|
try {
|
|
353
396
|
result = action();
|
|
354
397
|
} catch (arg) {
|
|
355
|
-
|
|
356
|
-
if (oncatch)
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
runSettle(false, true, spool, onfinally, description);
|
|
362
|
-
throw error;
|
|
363
|
-
}
|
|
364
|
-
if (spool && oncleanup) spool.roll(result, oncleanup);
|
|
365
|
-
runSettle(false, false, spool, onfinally, description);
|
|
366
|
-
return result;
|
|
398
|
+
const error = ensureError(arg, description);
|
|
399
|
+
if (!oncatch) return runFail(error, spool, onfinally, description);
|
|
400
|
+
try {
|
|
401
|
+
result = oncatch(error);
|
|
402
|
+
} catch (arg) {
|
|
403
|
+
return runFail(ensureError(arg, description), spool, onfinally, description);
|
|
367
404
|
}
|
|
368
|
-
|
|
369
|
-
throw error;
|
|
405
|
+
oncatch = void 0;
|
|
370
406
|
}
|
|
371
407
|
if (result instanceof Promise) return result.then(async (result) => {
|
|
372
408
|
if (spool && oncleanup) spool.roll(result, oncleanup);
|
|
373
|
-
await runSettle(true,
|
|
409
|
+
await runSettle(true, void 0, spool, onfinally, description);
|
|
374
410
|
return result;
|
|
375
411
|
}, async (arg) => {
|
|
376
412
|
let error = ensureError(arg, description);
|
|
@@ -380,19 +416,19 @@ function run(...args) {
|
|
|
380
416
|
result = await oncatch(error);
|
|
381
417
|
} catch (arg) {
|
|
382
418
|
error = ensureError(arg, description);
|
|
383
|
-
await runSettle(true,
|
|
419
|
+
await runSettle(true, error, spool, onfinally, description);
|
|
384
420
|
throw error;
|
|
385
421
|
}
|
|
386
422
|
if (spool && oncleanup) spool.roll(result, oncleanup);
|
|
387
|
-
await runSettle(true,
|
|
423
|
+
await runSettle(true, void 0, spool, onfinally, description);
|
|
388
424
|
return result;
|
|
389
425
|
}
|
|
390
|
-
await runSettle(true,
|
|
426
|
+
await runSettle(true, error, spool, onfinally, description);
|
|
391
427
|
throw error;
|
|
392
428
|
});
|
|
393
429
|
else {
|
|
394
430
|
if (spool && oncleanup) spool.roll(result, oncleanup);
|
|
395
|
-
runSettle(false,
|
|
431
|
+
runSettle(false, void 0, spool, onfinally, description);
|
|
396
432
|
return result;
|
|
397
433
|
}
|
|
398
434
|
}
|
|
@@ -403,9 +439,9 @@ var OptionsTrait = class {
|
|
|
403
439
|
this.options = {
|
|
404
440
|
id: "",
|
|
405
441
|
codec: "cbor",
|
|
406
|
-
timeout:
|
|
442
|
+
timeout: 1e4,
|
|
407
443
|
share: "",
|
|
408
|
-
chunkSize:
|
|
444
|
+
chunkSize: 16384,
|
|
409
445
|
chunkCredit: 4,
|
|
410
446
|
topicMake: (name, operation, peerId) => {
|
|
411
447
|
return `${name}/${operation}/${peerId ?? "any"}`;
|
|
@@ -420,6 +456,9 @@ var OptionsTrait = class {
|
|
|
420
456
|
},
|
|
421
457
|
...options
|
|
422
458
|
};
|
|
459
|
+
if (!(Number.isFinite(this.options.timeout) && this.options.timeout > 0)) throw new Error("options: \"timeout\" must be a positive number");
|
|
460
|
+
if (!(Number.isInteger(this.options.chunkSize) && this.options.chunkSize > 0)) throw new Error("options: \"chunkSize\" must be a positive integer");
|
|
461
|
+
if (!(Number.isInteger(this.options.chunkCredit) && this.options.chunkCredit >= 0)) throw new Error("options: \"chunkCredit\" must be a non-negative integer");
|
|
423
462
|
}
|
|
424
463
|
};
|
|
425
464
|
//#endregion
|
|
@@ -537,6 +576,8 @@ var versionToNum = (str) => {
|
|
|
537
576
|
if (minor > 99) throw new Error("invalid version string: minor version exceeds 99");
|
|
538
577
|
return parseInt(m[1], 10) * 100 + minor;
|
|
539
578
|
};
|
|
579
|
+
var VERSION = "1.4";
|
|
580
|
+
var MIN_VERSION = "1.4";
|
|
540
581
|
var version = versionToNum("1.4");
|
|
541
582
|
var minVersion = versionToNum("1.4");
|
|
542
583
|
//#endregion
|
|
@@ -932,13 +973,13 @@ var BaseTrait = class extends TraceTrait {
|
|
|
932
973
|
};
|
|
933
974
|
} });
|
|
934
975
|
}
|
|
935
|
-
this.
|
|
976
|
+
this._mqtt = mqtt;
|
|
936
977
|
if (this.options.id === "") {
|
|
937
978
|
const clientId = mqtt.isFakeProxy ? void 0 : mqtt.options?.clientId;
|
|
938
979
|
this.options.id = typeof clientId === "string" && clientId !== "" ? clientId : nanoid();
|
|
939
980
|
}
|
|
940
981
|
this.log("info", "hooking into MQTT client");
|
|
941
|
-
this.
|
|
982
|
+
this._messageHandler = (topic, message, packet) => {
|
|
942
983
|
if (this.destroyed) return;
|
|
943
984
|
let input;
|
|
944
985
|
if (this.options.codec === "json") input = message.toString();
|
|
@@ -949,12 +990,12 @@ var BaseTrait = class extends TraceTrait {
|
|
|
949
990
|
}
|
|
950
991
|
this._onMessage(topic, input, packet);
|
|
951
992
|
};
|
|
952
|
-
this.
|
|
993
|
+
this._mqtt.on("message", this._messageHandler);
|
|
953
994
|
}
|
|
954
995
|
async destroy() {
|
|
955
996
|
this.destroyed = true;
|
|
956
997
|
this.log("info", "un-hooking from MQTT client");
|
|
957
|
-
this.
|
|
998
|
+
this._mqtt.off("message", this._messageHandler);
|
|
958
999
|
this.onRequest.clear();
|
|
959
1000
|
this.onResponse.clear();
|
|
960
1001
|
}
|
|
@@ -973,7 +1014,7 @@ var BaseTrait = class extends TraceTrait {
|
|
|
973
1014
|
async subscribeTopic(topic, options = {}) {
|
|
974
1015
|
this.log("info", `subscribing to MQTT topic "${topic}"`);
|
|
975
1016
|
return new Promise((resolve, reject) => {
|
|
976
|
-
this.
|
|
1017
|
+
this._mqtt.subscribe(topic, {
|
|
977
1018
|
qos: 2,
|
|
978
1019
|
...options
|
|
979
1020
|
}, (err, granted) => {
|
|
@@ -991,7 +1032,7 @@ var BaseTrait = class extends TraceTrait {
|
|
|
991
1032
|
async unsubscribeTopic(topic) {
|
|
992
1033
|
this.log("info", `unsubscribing from MQTT topic "${topic}"`);
|
|
993
1034
|
return new Promise((resolve, reject) => {
|
|
994
|
-
this.
|
|
1035
|
+
this._mqtt.unsubscribe(topic, (err, _packet) => {
|
|
995
1036
|
if (err) {
|
|
996
1037
|
this.error(err, `unsubscribing from MQTT topic "${topic}" failed`);
|
|
997
1038
|
reject(err);
|
|
@@ -1015,7 +1056,7 @@ var BaseTrait = class extends TraceTrait {
|
|
|
1015
1056
|
this.log("debug", `publishing to MQTT topic "${topic}"`, { message: messageOnDemand });
|
|
1016
1057
|
return new Promise((resolve, reject) => {
|
|
1017
1058
|
const messageData = typeof message === "string" ? message : Buffer.from(message.buffer, message.byteOffset, message.byteLength);
|
|
1018
|
-
this.
|
|
1059
|
+
this._mqtt.publish(topic, messageData, options, (err) => {
|
|
1019
1060
|
if (err) {
|
|
1020
1061
|
this.error(err, `publishing to MQTT topic "${topic}" failed`);
|
|
1021
1062
|
reject(err);
|
|
@@ -1050,7 +1091,10 @@ var BaseTrait = class extends TraceTrait {
|
|
|
1050
1091
|
return;
|
|
1051
1092
|
}
|
|
1052
1093
|
this.log("debug", `received from MQTT topic "${topic}"`, { message });
|
|
1053
|
-
if (topicMatch.peerId !== void 0 && message.receiver !== void 0 && message.receiver !== topicMatch.peerId)
|
|
1094
|
+
if (topicMatch.peerId !== void 0 && message.receiver !== void 0 && message.receiver !== topicMatch.peerId) {
|
|
1095
|
+
this.log("warning", `receiver mismatch -- dropped message from direct topic "${topic}" (expected "${topicMatch.peerId}", got "${message.receiver}")`);
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1054
1098
|
if (this.msg.isRequest(message)) {
|
|
1055
1099
|
const handler = this.onRequest.get(`${message.type}:${message.name}`);
|
|
1056
1100
|
if (handler !== void 0) Promise.resolve().then(() => {
|
|
@@ -1073,7 +1117,7 @@ var BaseTrait = class extends TraceTrait {
|
|
|
1073
1117
|
//#endregion
|
|
1074
1118
|
//#region dst-stage1/mqtt-plus-subscription.js
|
|
1075
1119
|
var RefCountedSubscription = class {
|
|
1076
|
-
constructor(subscribeFn, unsubscribeFn, lingerMs =
|
|
1120
|
+
constructor(subscribeFn, unsubscribeFn, lingerMs = 3e4) {
|
|
1077
1121
|
this.subscribeFn = subscribeFn;
|
|
1078
1122
|
this.unsubscribeFn = unsubscribeFn;
|
|
1079
1123
|
this.lingerMs = lingerMs;
|
|
@@ -1089,12 +1133,14 @@ var RefCountedSubscription = class {
|
|
|
1089
1133
|
}
|
|
1090
1134
|
decrementCount(topic) {
|
|
1091
1135
|
const count = this.counts.get(topic);
|
|
1092
|
-
if (count !== void 0)
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1136
|
+
if (count !== void 0) {
|
|
1137
|
+
if (count <= 1) {
|
|
1138
|
+
this.counts.delete(topic);
|
|
1139
|
+
return 0;
|
|
1140
|
+
} else {
|
|
1141
|
+
this.counts.set(topic, count - 1);
|
|
1142
|
+
return count - 1;
|
|
1143
|
+
}
|
|
1098
1144
|
}
|
|
1099
1145
|
}
|
|
1100
1146
|
clearCount(topic) {
|
|
@@ -1133,25 +1179,27 @@ var RefCountedSubscription = class {
|
|
|
1133
1179
|
}
|
|
1134
1180
|
}
|
|
1135
1181
|
async unsubscribe(topic) {
|
|
1136
|
-
if (this.decrementCount(topic) === 0)
|
|
1137
|
-
|
|
1138
|
-
|
|
1182
|
+
if (this.decrementCount(topic) === 0) {
|
|
1183
|
+
if (this.lingerMs > 0 && !topic.startsWith("$share/")) {
|
|
1184
|
+
const timer = setTimeout(() => {
|
|
1185
|
+
this.lingers.delete(topic);
|
|
1186
|
+
const promise = this.unsubscribeFn(topic).catch(() => {}).finally(() => {
|
|
1187
|
+
this.unsubbing.delete(topic);
|
|
1188
|
+
});
|
|
1189
|
+
this.unsubbing.set(topic, promise);
|
|
1190
|
+
}, this.lingerMs);
|
|
1191
|
+
this.lingers.set(topic, timer);
|
|
1192
|
+
} else {
|
|
1139
1193
|
const promise = this.unsubscribeFn(topic).catch(() => {}).finally(() => {
|
|
1140
1194
|
this.unsubbing.delete(topic);
|
|
1141
1195
|
});
|
|
1142
1196
|
this.unsubbing.set(topic, promise);
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
} else {
|
|
1146
|
-
const promise = this.unsubscribeFn(topic).catch(() => {}).finally(() => {
|
|
1147
|
-
this.unsubbing.delete(topic);
|
|
1148
|
-
});
|
|
1149
|
-
this.unsubbing.set(topic, promise);
|
|
1150
|
-
await promise;
|
|
1197
|
+
await promise;
|
|
1198
|
+
}
|
|
1151
1199
|
}
|
|
1152
1200
|
}
|
|
1153
1201
|
async flush() {
|
|
1154
|
-
const topics = new Set([
|
|
1202
|
+
const topics = /* @__PURE__ */ new Set([
|
|
1155
1203
|
...this.counts.keys(),
|
|
1156
1204
|
...this.lingers.keys(),
|
|
1157
1205
|
...this.pending.keys(),
|
|
@@ -1416,7 +1464,7 @@ var EventTrait = class extends AuthTrait {
|
|
|
1416
1464
|
this.log("warning", `event name mismatch -- dropped request for "${name}" (topic: "${topicName}", payload: "${request.name}")`, { requestId });
|
|
1417
1465
|
return;
|
|
1418
1466
|
}
|
|
1419
|
-
const params = request.params ?? [];
|
|
1467
|
+
const params = alignHandlerParams(request.params ?? [], callback);
|
|
1420
1468
|
if (this.eventControllers.has(requestId)) {
|
|
1421
1469
|
this.log("warning", `duplicate event request id -- dropped request for event "${name}"`, { requestId });
|
|
1422
1470
|
return;
|
|
@@ -1540,7 +1588,7 @@ var ServiceTrait = class extends EventTrait {
|
|
|
1540
1588
|
if (request.receiver && request.receiver !== this.options.id) return;
|
|
1541
1589
|
const requestId = request.id;
|
|
1542
1590
|
const senderId = request.sender;
|
|
1543
|
-
const params = request.params ?? [];
|
|
1591
|
+
const params = alignHandlerParams(request.params ?? [], callback);
|
|
1544
1592
|
if (senderId === void 0 || senderId === "") {
|
|
1545
1593
|
this.error(/* @__PURE__ */ new Error("invalid request: missing sender"));
|
|
1546
1594
|
return;
|
|
@@ -1644,7 +1692,9 @@ var ServiceTrait = class extends EventTrait {
|
|
|
1644
1692
|
const settle = () => {
|
|
1645
1693
|
if (settled) return false;
|
|
1646
1694
|
settled = true;
|
|
1647
|
-
spool.unroll()
|
|
1695
|
+
spool.unroll(false)?.catch((err) => {
|
|
1696
|
+
this.error(ensureError(err, `cleanup after call of service "${name}" failed`));
|
|
1697
|
+
});
|
|
1648
1698
|
return true;
|
|
1649
1699
|
};
|
|
1650
1700
|
const promise = new Promise((resolve, reject) => {
|
|
@@ -1751,7 +1801,7 @@ var SourceTrait = class extends ServiceTrait {
|
|
|
1751
1801
|
this.onRequest.set(`source-fetch-request:${name}`, async (request, topicName) => {
|
|
1752
1802
|
if (request.receiver && request.receiver !== this.options.id) return;
|
|
1753
1803
|
const requestId = request.id;
|
|
1754
|
-
const params = request.params ?? [];
|
|
1804
|
+
const params = alignHandlerParams(request.params ?? [], callback);
|
|
1755
1805
|
const sender = request.sender;
|
|
1756
1806
|
const receiver = request.receiver;
|
|
1757
1807
|
const reqSpool = new Spool();
|
|
@@ -1804,11 +1854,16 @@ var SourceTrait = class extends ServiceTrait {
|
|
|
1804
1854
|
if (current.size === 0) this.sourceRequests.delete(name);
|
|
1805
1855
|
}
|
|
1806
1856
|
});
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1857
|
+
const noopError = () => {};
|
|
1858
|
+
const destroyStream = () => {
|
|
1859
|
+
if (info.stream instanceof Readable && !info.stream.destroyed) {
|
|
1860
|
+
info.stream.on("error", noopError);
|
|
1861
|
+
info.stream.destroy(ensureError(abortSignal.reason));
|
|
1862
|
+
}
|
|
1863
|
+
};
|
|
1864
|
+
abortSignal.addEventListener("abort", destroyStream, { once: true });
|
|
1810
1865
|
reqSpool.roll(() => {
|
|
1811
|
-
if (abortSignal.aborted
|
|
1866
|
+
if (abortSignal.aborted) destroyStream();
|
|
1812
1867
|
});
|
|
1813
1868
|
let abortReject;
|
|
1814
1869
|
const abortPromise = new Promise((_resolve, reject) => {
|
|
@@ -1955,7 +2010,7 @@ var SourceTrait = class extends ServiceTrait {
|
|
|
1955
2010
|
const sourceNameMismatchError = (kind, actualName) => /* @__PURE__ */ new Error(`${kind} name mismatch (expected "${name}", got "${actualName}")`);
|
|
1956
2011
|
await this.subscribeTopicAndSpool(spool, responseTopic, { qos: options.qos ?? 2 });
|
|
1957
2012
|
const chunkCredit = this.options.chunkCredit;
|
|
1958
|
-
const maxBufferedBytes = chunkCredit > 0 ? chunkCredit * this.options.chunkSize :
|
|
2013
|
+
const maxBufferedBytes = chunkCredit > 0 ? chunkCredit * this.options.chunkSize : 16384;
|
|
1959
2014
|
let chunksReceived = 0;
|
|
1960
2015
|
let creditGranted = chunkCredit;
|
|
1961
2016
|
let responderId = receiver;
|
|
@@ -2193,7 +2248,7 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2193
2248
|
this.onRequest.set(`sink-push-request:${name}`, async (request, topicName) => {
|
|
2194
2249
|
if (request.receiver && request.receiver !== this.options.id) return;
|
|
2195
2250
|
const requestId = request.id;
|
|
2196
|
-
const params = request.params ?? [];
|
|
2251
|
+
const params = alignHandlerParams(request.params ?? [], callback);
|
|
2197
2252
|
const sender = request.sender;
|
|
2198
2253
|
const receiver = request.receiver;
|
|
2199
2254
|
const reqSpool = new Spool();
|
|
@@ -2254,7 +2309,7 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2254
2309
|
chunksReceived: 0,
|
|
2255
2310
|
creditGranted: chunkCredit
|
|
2256
2311
|
} : void 0;
|
|
2257
|
-
const maxBufferedBytes = chunkCredit > 0 ? chunkCredit * this.options.chunkSize :
|
|
2312
|
+
const maxBufferedBytes = chunkCredit > 0 ? chunkCredit * this.options.chunkSize : 16384;
|
|
2258
2313
|
let streamEnded = false;
|
|
2259
2314
|
const pushTimerId = `sink-push-recv:${requestId}`;
|
|
2260
2315
|
const refreshPushTimeout = () => this.timerRefresh(pushTimerId, () => {
|
|
@@ -2484,8 +2539,12 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2484
2539
|
});
|
|
2485
2540
|
if (data instanceof Readable) {
|
|
2486
2541
|
const stream = data;
|
|
2542
|
+
const noopError = () => {};
|
|
2487
2543
|
abortSignal.addEventListener("abort", () => {
|
|
2488
|
-
if (!stream.destroyed)
|
|
2544
|
+
if (!stream.destroyed) {
|
|
2545
|
+
stream.on("error", noopError);
|
|
2546
|
+
stream.destroy(ensureError(abortSignal.reason));
|
|
2547
|
+
}
|
|
2489
2548
|
}, { once: true });
|
|
2490
2549
|
}
|
|
2491
2550
|
const pushTimerId = `sink-push-send:${requestId}`;
|
|
@@ -2519,18 +2578,21 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2519
2578
|
pushFinalizeReject = reject;
|
|
2520
2579
|
});
|
|
2521
2580
|
pushFinalize.catch(() => {});
|
|
2581
|
+
const failPush = (error) => {
|
|
2582
|
+
abortController.abort(error);
|
|
2583
|
+
if (!pushAcked) {
|
|
2584
|
+
pushInitialSettled = true;
|
|
2585
|
+
pushInitialReject(error);
|
|
2586
|
+
} else if (!pushFinalized) {
|
|
2587
|
+
pushFinalized = true;
|
|
2588
|
+
pushFinalizeReject(error);
|
|
2589
|
+
}
|
|
2590
|
+
};
|
|
2522
2591
|
const lockResponder = (kind, sender) => {
|
|
2523
2592
|
if (sender === void 0 || sender === "") {
|
|
2524
2593
|
const error = /* @__PURE__ */ new Error(`received ${kind} without sender`);
|
|
2525
2594
|
remoteErrorObject = error;
|
|
2526
|
-
|
|
2527
|
-
if (!pushAcked) {
|
|
2528
|
-
pushInitialSettled = true;
|
|
2529
|
-
pushInitialReject(error);
|
|
2530
|
-
} else if (!pushFinalized) {
|
|
2531
|
-
pushFinalized = true;
|
|
2532
|
-
pushFinalizeReject(error);
|
|
2533
|
-
}
|
|
2595
|
+
failPush(error);
|
|
2534
2596
|
return false;
|
|
2535
2597
|
}
|
|
2536
2598
|
if (responderId === void 0) responderId = sender;
|
|
@@ -2548,37 +2610,25 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2548
2610
|
if (response.name !== name) {
|
|
2549
2611
|
const error = /* @__PURE__ */ new Error(`sink response name mismatch (expected "${name}", got "${response.name}")`);
|
|
2550
2612
|
remoteErrorObject = error;
|
|
2551
|
-
|
|
2552
|
-
if (!pushAcked) {
|
|
2553
|
-
pushInitialSettled = true;
|
|
2554
|
-
pushInitialReject(error);
|
|
2555
|
-
} else if (!pushFinalized) {
|
|
2556
|
-
pushFinalized = true;
|
|
2557
|
-
pushFinalizeReject(error);
|
|
2558
|
-
}
|
|
2613
|
+
failPush(error);
|
|
2559
2614
|
return;
|
|
2560
2615
|
}
|
|
2561
2616
|
if (!lockResponder("sink response", response.sender)) return;
|
|
2562
2617
|
if (response.error) {
|
|
2563
2618
|
const error = new Error(response.error);
|
|
2564
2619
|
remoteErrorObject = error;
|
|
2565
|
-
|
|
2566
|
-
if (!pushAcked) {
|
|
2567
|
-
pushInitialSettled = true;
|
|
2568
|
-
pushInitialReject(error);
|
|
2569
|
-
} else if (!pushFinalized) {
|
|
2570
|
-
pushFinalized = true;
|
|
2571
|
-
pushFinalizeReject(error);
|
|
2572
|
-
}
|
|
2620
|
+
failPush(error);
|
|
2573
2621
|
} else if (!pushAcked) {
|
|
2574
2622
|
initialCredit = response.credit;
|
|
2575
2623
|
pushAcked = true;
|
|
2576
2624
|
pushInitialSettled = true;
|
|
2577
2625
|
pushInitialResolve();
|
|
2578
|
-
} else if (!pushFinalized)
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2626
|
+
} else if (!pushFinalized) {
|
|
2627
|
+
if (pushDataComplete) {
|
|
2628
|
+
pushFinalized = true;
|
|
2629
|
+
pushFinalizeResolve();
|
|
2630
|
+
} else pushTerminalReceived = true;
|
|
2631
|
+
}
|
|
2582
2632
|
});
|
|
2583
2633
|
spool.roll(() => {
|
|
2584
2634
|
this.onResponse.delete(`sink-push-response:${requestId}`);
|
|
@@ -2587,28 +2637,14 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2587
2637
|
if (response.name !== name) {
|
|
2588
2638
|
const error = /* @__PURE__ */ new Error(`sink credit name mismatch (expected "${name}", got "${response.name}")`);
|
|
2589
2639
|
remoteErrorObject = error;
|
|
2590
|
-
|
|
2591
|
-
if (!pushAcked) {
|
|
2592
|
-
pushInitialSettled = true;
|
|
2593
|
-
pushInitialReject(error);
|
|
2594
|
-
} else if (!pushFinalized) {
|
|
2595
|
-
pushFinalized = true;
|
|
2596
|
-
pushFinalizeReject(error);
|
|
2597
|
-
}
|
|
2640
|
+
failPush(error);
|
|
2598
2641
|
return;
|
|
2599
2642
|
}
|
|
2600
2643
|
if (!lockResponder("sink credit", response.sender)) return;
|
|
2601
2644
|
if (response.credit === 0) {
|
|
2602
2645
|
cancelledByReceiver = true;
|
|
2603
2646
|
const error = /* @__PURE__ */ new Error(`push to sink "${name}" cancelled by receiver`);
|
|
2604
|
-
|
|
2605
|
-
if (!pushAcked) {
|
|
2606
|
-
pushInitialSettled = true;
|
|
2607
|
-
pushInitialReject(error);
|
|
2608
|
-
} else if (!pushFinalized) {
|
|
2609
|
-
pushFinalized = true;
|
|
2610
|
-
pushFinalizeReject(error);
|
|
2611
|
-
}
|
|
2647
|
+
failPush(error);
|
|
2612
2648
|
return;
|
|
2613
2649
|
}
|
|
2614
2650
|
if (creditGate !== void 0) {
|
|
@@ -2617,11 +2653,7 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2617
2653
|
} else if (pushAcked && initialCredit === void 0) {
|
|
2618
2654
|
const error = /* @__PURE__ */ new Error(`push to sink "${name}" received unsolicited credit (credit-flow disabled)`);
|
|
2619
2655
|
remoteErrorObject = error;
|
|
2620
|
-
|
|
2621
|
-
if (!pushFinalized) {
|
|
2622
|
-
pushFinalized = true;
|
|
2623
|
-
pushFinalizeReject(error);
|
|
2624
|
-
}
|
|
2656
|
+
failPush(error);
|
|
2625
2657
|
} else pendingCredit += response.credit;
|
|
2626
2658
|
});
|
|
2627
2659
|
spool.roll(() => {
|
|
@@ -2708,7 +2740,7 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2708
2740
|
}
|
|
2709
2741
|
} catch {}
|
|
2710
2742
|
if (pushAcked && !remoteErrorObject) await new Promise((resolve) => {
|
|
2711
|
-
|
|
2743
|
+
setTimeout(resolve, 0);
|
|
2712
2744
|
});
|
|
2713
2745
|
if (remoteErrorObject) throw remoteErrorObject;
|
|
2714
2746
|
throw err;
|
|
@@ -2721,4 +2753,4 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2721
2753
|
//#region dst-stage1/mqtt-plus.js
|
|
2722
2754
|
var MQTTp = class extends SinkTrait {};
|
|
2723
2755
|
//#endregion
|
|
2724
|
-
export { MQTTp as default };
|
|
2756
|
+
export { MIN_VERSION, VERSION, MQTTp as default, minVersion, version, versionToNum };
|