mqtt-plus 1.4.25 → 1.4.27
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 +34 -0
- package/.ase/service.yaml +1 -1
- 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 +5 -1
- package/dst-stage1/mqtt-plus.js +10 -1
- package/dst-stage2/mqtt-plus.cjs.cjs +169 -123
- package/dst-stage2/mqtt-plus.esm.js +168 -122
- package/dst-stage2/mqtt-plus.umd.js +11 -11
- package/etc/stx.conf +3 -2
- package/etc/vite.mts +1 -1
- package/package.d/@typescript-eslint+typescript-estree+8.66.0.patch +12 -0
- package/package.d/{vite+8.1.4.patch → vite+8.2.1.patch} +2 -2
- package/package.json +16 -15
- 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 +14 -3
- 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.63.0.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
|
|
@@ -932,13 +971,13 @@ var BaseTrait = class extends TraceTrait {
|
|
|
932
971
|
};
|
|
933
972
|
} });
|
|
934
973
|
}
|
|
935
|
-
this.
|
|
974
|
+
this._mqtt = mqtt;
|
|
936
975
|
if (this.options.id === "") {
|
|
937
976
|
const clientId = mqtt.isFakeProxy ? void 0 : mqtt.options?.clientId;
|
|
938
977
|
this.options.id = typeof clientId === "string" && clientId !== "" ? clientId : nanoid();
|
|
939
978
|
}
|
|
940
979
|
this.log("info", "hooking into MQTT client");
|
|
941
|
-
this.
|
|
980
|
+
this._messageHandler = (topic, message, packet) => {
|
|
942
981
|
if (this.destroyed) return;
|
|
943
982
|
let input;
|
|
944
983
|
if (this.options.codec === "json") input = message.toString();
|
|
@@ -949,12 +988,12 @@ var BaseTrait = class extends TraceTrait {
|
|
|
949
988
|
}
|
|
950
989
|
this._onMessage(topic, input, packet);
|
|
951
990
|
};
|
|
952
|
-
this.
|
|
991
|
+
this._mqtt.on("message", this._messageHandler);
|
|
953
992
|
}
|
|
954
993
|
async destroy() {
|
|
955
994
|
this.destroyed = true;
|
|
956
995
|
this.log("info", "un-hooking from MQTT client");
|
|
957
|
-
this.
|
|
996
|
+
this._mqtt.off("message", this._messageHandler);
|
|
958
997
|
this.onRequest.clear();
|
|
959
998
|
this.onResponse.clear();
|
|
960
999
|
}
|
|
@@ -973,7 +1012,7 @@ var BaseTrait = class extends TraceTrait {
|
|
|
973
1012
|
async subscribeTopic(topic, options = {}) {
|
|
974
1013
|
this.log("info", `subscribing to MQTT topic "${topic}"`);
|
|
975
1014
|
return new Promise((resolve, reject) => {
|
|
976
|
-
this.
|
|
1015
|
+
this._mqtt.subscribe(topic, {
|
|
977
1016
|
qos: 2,
|
|
978
1017
|
...options
|
|
979
1018
|
}, (err, granted) => {
|
|
@@ -991,7 +1030,7 @@ var BaseTrait = class extends TraceTrait {
|
|
|
991
1030
|
async unsubscribeTopic(topic) {
|
|
992
1031
|
this.log("info", `unsubscribing from MQTT topic "${topic}"`);
|
|
993
1032
|
return new Promise((resolve, reject) => {
|
|
994
|
-
this.
|
|
1033
|
+
this._mqtt.unsubscribe(topic, (err, _packet) => {
|
|
995
1034
|
if (err) {
|
|
996
1035
|
this.error(err, `unsubscribing from MQTT topic "${topic}" failed`);
|
|
997
1036
|
reject(err);
|
|
@@ -1015,7 +1054,7 @@ var BaseTrait = class extends TraceTrait {
|
|
|
1015
1054
|
this.log("debug", `publishing to MQTT topic "${topic}"`, { message: messageOnDemand });
|
|
1016
1055
|
return new Promise((resolve, reject) => {
|
|
1017
1056
|
const messageData = typeof message === "string" ? message : Buffer.from(message.buffer, message.byteOffset, message.byteLength);
|
|
1018
|
-
this.
|
|
1057
|
+
this._mqtt.publish(topic, messageData, options, (err) => {
|
|
1019
1058
|
if (err) {
|
|
1020
1059
|
this.error(err, `publishing to MQTT topic "${topic}" failed`);
|
|
1021
1060
|
reject(err);
|
|
@@ -1050,7 +1089,10 @@ var BaseTrait = class extends TraceTrait {
|
|
|
1050
1089
|
return;
|
|
1051
1090
|
}
|
|
1052
1091
|
this.log("debug", `received from MQTT topic "${topic}"`, { message });
|
|
1053
|
-
if (topicMatch.peerId !== void 0 && message.receiver !== void 0 && message.receiver !== topicMatch.peerId)
|
|
1092
|
+
if (topicMatch.peerId !== void 0 && message.receiver !== void 0 && message.receiver !== topicMatch.peerId) {
|
|
1093
|
+
this.log("warning", `receiver mismatch -- dropped message from direct topic "${topic}" (expected "${topicMatch.peerId}", got "${message.receiver}")`);
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1054
1096
|
if (this.msg.isRequest(message)) {
|
|
1055
1097
|
const handler = this.onRequest.get(`${message.type}:${message.name}`);
|
|
1056
1098
|
if (handler !== void 0) Promise.resolve().then(() => {
|
|
@@ -1073,7 +1115,7 @@ var BaseTrait = class extends TraceTrait {
|
|
|
1073
1115
|
//#endregion
|
|
1074
1116
|
//#region dst-stage1/mqtt-plus-subscription.js
|
|
1075
1117
|
var RefCountedSubscription = class {
|
|
1076
|
-
constructor(subscribeFn, unsubscribeFn, lingerMs =
|
|
1118
|
+
constructor(subscribeFn, unsubscribeFn, lingerMs = 3e4) {
|
|
1077
1119
|
this.subscribeFn = subscribeFn;
|
|
1078
1120
|
this.unsubscribeFn = unsubscribeFn;
|
|
1079
1121
|
this.lingerMs = lingerMs;
|
|
@@ -1089,12 +1131,14 @@ var RefCountedSubscription = class {
|
|
|
1089
1131
|
}
|
|
1090
1132
|
decrementCount(topic) {
|
|
1091
1133
|
const count = this.counts.get(topic);
|
|
1092
|
-
if (count !== void 0)
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1134
|
+
if (count !== void 0) {
|
|
1135
|
+
if (count <= 1) {
|
|
1136
|
+
this.counts.delete(topic);
|
|
1137
|
+
return 0;
|
|
1138
|
+
} else {
|
|
1139
|
+
this.counts.set(topic, count - 1);
|
|
1140
|
+
return count - 1;
|
|
1141
|
+
}
|
|
1098
1142
|
}
|
|
1099
1143
|
}
|
|
1100
1144
|
clearCount(topic) {
|
|
@@ -1133,21 +1177,23 @@ var RefCountedSubscription = class {
|
|
|
1133
1177
|
}
|
|
1134
1178
|
}
|
|
1135
1179
|
async unsubscribe(topic) {
|
|
1136
|
-
if (this.decrementCount(topic) === 0)
|
|
1137
|
-
|
|
1138
|
-
|
|
1180
|
+
if (this.decrementCount(topic) === 0) {
|
|
1181
|
+
if (this.lingerMs > 0 && !topic.startsWith("$share/")) {
|
|
1182
|
+
const timer = setTimeout(() => {
|
|
1183
|
+
this.lingers.delete(topic);
|
|
1184
|
+
const promise = this.unsubscribeFn(topic).catch(() => {}).finally(() => {
|
|
1185
|
+
this.unsubbing.delete(topic);
|
|
1186
|
+
});
|
|
1187
|
+
this.unsubbing.set(topic, promise);
|
|
1188
|
+
}, this.lingerMs);
|
|
1189
|
+
this.lingers.set(topic, timer);
|
|
1190
|
+
} else {
|
|
1139
1191
|
const promise = this.unsubscribeFn(topic).catch(() => {}).finally(() => {
|
|
1140
1192
|
this.unsubbing.delete(topic);
|
|
1141
1193
|
});
|
|
1142
1194
|
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;
|
|
1195
|
+
await promise;
|
|
1196
|
+
}
|
|
1151
1197
|
}
|
|
1152
1198
|
}
|
|
1153
1199
|
async flush() {
|
|
@@ -1416,7 +1462,7 @@ var EventTrait = class extends AuthTrait {
|
|
|
1416
1462
|
this.log("warning", `event name mismatch -- dropped request for "${name}" (topic: "${topicName}", payload: "${request.name}")`, { requestId });
|
|
1417
1463
|
return;
|
|
1418
1464
|
}
|
|
1419
|
-
const params = request.params ?? [];
|
|
1465
|
+
const params = alignHandlerParams(request.params ?? [], callback);
|
|
1420
1466
|
if (this.eventControllers.has(requestId)) {
|
|
1421
1467
|
this.log("warning", `duplicate event request id -- dropped request for event "${name}"`, { requestId });
|
|
1422
1468
|
return;
|
|
@@ -1540,7 +1586,7 @@ var ServiceTrait = class extends EventTrait {
|
|
|
1540
1586
|
if (request.receiver && request.receiver !== this.options.id) return;
|
|
1541
1587
|
const requestId = request.id;
|
|
1542
1588
|
const senderId = request.sender;
|
|
1543
|
-
const params = request.params ?? [];
|
|
1589
|
+
const params = alignHandlerParams(request.params ?? [], callback);
|
|
1544
1590
|
if (senderId === void 0 || senderId === "") {
|
|
1545
1591
|
this.error(/* @__PURE__ */ new Error("invalid request: missing sender"));
|
|
1546
1592
|
return;
|
|
@@ -1644,7 +1690,9 @@ var ServiceTrait = class extends EventTrait {
|
|
|
1644
1690
|
const settle = () => {
|
|
1645
1691
|
if (settled) return false;
|
|
1646
1692
|
settled = true;
|
|
1647
|
-
spool.unroll()
|
|
1693
|
+
spool.unroll(false)?.catch((err) => {
|
|
1694
|
+
this.error(ensureError(err, `cleanup after call of service "${name}" failed`));
|
|
1695
|
+
});
|
|
1648
1696
|
return true;
|
|
1649
1697
|
};
|
|
1650
1698
|
const promise = new Promise((resolve, reject) => {
|
|
@@ -1751,7 +1799,7 @@ var SourceTrait = class extends ServiceTrait {
|
|
|
1751
1799
|
this.onRequest.set(`source-fetch-request:${name}`, async (request, topicName) => {
|
|
1752
1800
|
if (request.receiver && request.receiver !== this.options.id) return;
|
|
1753
1801
|
const requestId = request.id;
|
|
1754
|
-
const params = request.params ?? [];
|
|
1802
|
+
const params = alignHandlerParams(request.params ?? [], callback);
|
|
1755
1803
|
const sender = request.sender;
|
|
1756
1804
|
const receiver = request.receiver;
|
|
1757
1805
|
const reqSpool = new Spool();
|
|
@@ -1804,11 +1852,16 @@ var SourceTrait = class extends ServiceTrait {
|
|
|
1804
1852
|
if (current.size === 0) this.sourceRequests.delete(name);
|
|
1805
1853
|
}
|
|
1806
1854
|
});
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1855
|
+
const noopError = () => {};
|
|
1856
|
+
const destroyStream = () => {
|
|
1857
|
+
if (info.stream instanceof Readable && !info.stream.destroyed) {
|
|
1858
|
+
info.stream.on("error", noopError);
|
|
1859
|
+
info.stream.destroy(ensureError(abortSignal.reason));
|
|
1860
|
+
}
|
|
1861
|
+
};
|
|
1862
|
+
abortSignal.addEventListener("abort", destroyStream, { once: true });
|
|
1810
1863
|
reqSpool.roll(() => {
|
|
1811
|
-
if (abortSignal.aborted
|
|
1864
|
+
if (abortSignal.aborted) destroyStream();
|
|
1812
1865
|
});
|
|
1813
1866
|
let abortReject;
|
|
1814
1867
|
const abortPromise = new Promise((_resolve, reject) => {
|
|
@@ -1955,7 +2008,7 @@ var SourceTrait = class extends ServiceTrait {
|
|
|
1955
2008
|
const sourceNameMismatchError = (kind, actualName) => /* @__PURE__ */ new Error(`${kind} name mismatch (expected "${name}", got "${actualName}")`);
|
|
1956
2009
|
await this.subscribeTopicAndSpool(spool, responseTopic, { qos: options.qos ?? 2 });
|
|
1957
2010
|
const chunkCredit = this.options.chunkCredit;
|
|
1958
|
-
const maxBufferedBytes = chunkCredit > 0 ? chunkCredit * this.options.chunkSize :
|
|
2011
|
+
const maxBufferedBytes = chunkCredit > 0 ? chunkCredit * this.options.chunkSize : 16384;
|
|
1959
2012
|
let chunksReceived = 0;
|
|
1960
2013
|
let creditGranted = chunkCredit;
|
|
1961
2014
|
let responderId = receiver;
|
|
@@ -2193,7 +2246,7 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2193
2246
|
this.onRequest.set(`sink-push-request:${name}`, async (request, topicName) => {
|
|
2194
2247
|
if (request.receiver && request.receiver !== this.options.id) return;
|
|
2195
2248
|
const requestId = request.id;
|
|
2196
|
-
const params = request.params ?? [];
|
|
2249
|
+
const params = alignHandlerParams(request.params ?? [], callback);
|
|
2197
2250
|
const sender = request.sender;
|
|
2198
2251
|
const receiver = request.receiver;
|
|
2199
2252
|
const reqSpool = new Spool();
|
|
@@ -2254,7 +2307,7 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2254
2307
|
chunksReceived: 0,
|
|
2255
2308
|
creditGranted: chunkCredit
|
|
2256
2309
|
} : void 0;
|
|
2257
|
-
const maxBufferedBytes = chunkCredit > 0 ? chunkCredit * this.options.chunkSize :
|
|
2310
|
+
const maxBufferedBytes = chunkCredit > 0 ? chunkCredit * this.options.chunkSize : 16384;
|
|
2258
2311
|
let streamEnded = false;
|
|
2259
2312
|
const pushTimerId = `sink-push-recv:${requestId}`;
|
|
2260
2313
|
const refreshPushTimeout = () => this.timerRefresh(pushTimerId, () => {
|
|
@@ -2484,8 +2537,12 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2484
2537
|
});
|
|
2485
2538
|
if (data instanceof Readable) {
|
|
2486
2539
|
const stream = data;
|
|
2540
|
+
const noopError = () => {};
|
|
2487
2541
|
abortSignal.addEventListener("abort", () => {
|
|
2488
|
-
if (!stream.destroyed)
|
|
2542
|
+
if (!stream.destroyed) {
|
|
2543
|
+
stream.on("error", noopError);
|
|
2544
|
+
stream.destroy(ensureError(abortSignal.reason));
|
|
2545
|
+
}
|
|
2489
2546
|
}, { once: true });
|
|
2490
2547
|
}
|
|
2491
2548
|
const pushTimerId = `sink-push-send:${requestId}`;
|
|
@@ -2519,18 +2576,21 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2519
2576
|
pushFinalizeReject = reject;
|
|
2520
2577
|
});
|
|
2521
2578
|
pushFinalize.catch(() => {});
|
|
2579
|
+
const failPush = (error) => {
|
|
2580
|
+
abortController.abort(error);
|
|
2581
|
+
if (!pushAcked) {
|
|
2582
|
+
pushInitialSettled = true;
|
|
2583
|
+
pushInitialReject(error);
|
|
2584
|
+
} else if (!pushFinalized) {
|
|
2585
|
+
pushFinalized = true;
|
|
2586
|
+
pushFinalizeReject(error);
|
|
2587
|
+
}
|
|
2588
|
+
};
|
|
2522
2589
|
const lockResponder = (kind, sender) => {
|
|
2523
2590
|
if (sender === void 0 || sender === "") {
|
|
2524
2591
|
const error = /* @__PURE__ */ new Error(`received ${kind} without sender`);
|
|
2525
2592
|
remoteErrorObject = error;
|
|
2526
|
-
|
|
2527
|
-
if (!pushAcked) {
|
|
2528
|
-
pushInitialSettled = true;
|
|
2529
|
-
pushInitialReject(error);
|
|
2530
|
-
} else if (!pushFinalized) {
|
|
2531
|
-
pushFinalized = true;
|
|
2532
|
-
pushFinalizeReject(error);
|
|
2533
|
-
}
|
|
2593
|
+
failPush(error);
|
|
2534
2594
|
return false;
|
|
2535
2595
|
}
|
|
2536
2596
|
if (responderId === void 0) responderId = sender;
|
|
@@ -2548,37 +2608,25 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2548
2608
|
if (response.name !== name) {
|
|
2549
2609
|
const error = /* @__PURE__ */ new Error(`sink response name mismatch (expected "${name}", got "${response.name}")`);
|
|
2550
2610
|
remoteErrorObject = error;
|
|
2551
|
-
|
|
2552
|
-
if (!pushAcked) {
|
|
2553
|
-
pushInitialSettled = true;
|
|
2554
|
-
pushInitialReject(error);
|
|
2555
|
-
} else if (!pushFinalized) {
|
|
2556
|
-
pushFinalized = true;
|
|
2557
|
-
pushFinalizeReject(error);
|
|
2558
|
-
}
|
|
2611
|
+
failPush(error);
|
|
2559
2612
|
return;
|
|
2560
2613
|
}
|
|
2561
2614
|
if (!lockResponder("sink response", response.sender)) return;
|
|
2562
2615
|
if (response.error) {
|
|
2563
2616
|
const error = new Error(response.error);
|
|
2564
2617
|
remoteErrorObject = error;
|
|
2565
|
-
|
|
2566
|
-
if (!pushAcked) {
|
|
2567
|
-
pushInitialSettled = true;
|
|
2568
|
-
pushInitialReject(error);
|
|
2569
|
-
} else if (!pushFinalized) {
|
|
2570
|
-
pushFinalized = true;
|
|
2571
|
-
pushFinalizeReject(error);
|
|
2572
|
-
}
|
|
2618
|
+
failPush(error);
|
|
2573
2619
|
} else if (!pushAcked) {
|
|
2574
2620
|
initialCredit = response.credit;
|
|
2575
2621
|
pushAcked = true;
|
|
2576
2622
|
pushInitialSettled = true;
|
|
2577
2623
|
pushInitialResolve();
|
|
2578
|
-
} else if (!pushFinalized)
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2624
|
+
} else if (!pushFinalized) {
|
|
2625
|
+
if (pushDataComplete) {
|
|
2626
|
+
pushFinalized = true;
|
|
2627
|
+
pushFinalizeResolve();
|
|
2628
|
+
} else pushTerminalReceived = true;
|
|
2629
|
+
}
|
|
2582
2630
|
});
|
|
2583
2631
|
spool.roll(() => {
|
|
2584
2632
|
this.onResponse.delete(`sink-push-response:${requestId}`);
|
|
@@ -2587,28 +2635,14 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2587
2635
|
if (response.name !== name) {
|
|
2588
2636
|
const error = /* @__PURE__ */ new Error(`sink credit name mismatch (expected "${name}", got "${response.name}")`);
|
|
2589
2637
|
remoteErrorObject = error;
|
|
2590
|
-
|
|
2591
|
-
if (!pushAcked) {
|
|
2592
|
-
pushInitialSettled = true;
|
|
2593
|
-
pushInitialReject(error);
|
|
2594
|
-
} else if (!pushFinalized) {
|
|
2595
|
-
pushFinalized = true;
|
|
2596
|
-
pushFinalizeReject(error);
|
|
2597
|
-
}
|
|
2638
|
+
failPush(error);
|
|
2598
2639
|
return;
|
|
2599
2640
|
}
|
|
2600
2641
|
if (!lockResponder("sink credit", response.sender)) return;
|
|
2601
2642
|
if (response.credit === 0) {
|
|
2602
2643
|
cancelledByReceiver = true;
|
|
2603
2644
|
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
|
-
}
|
|
2645
|
+
failPush(error);
|
|
2612
2646
|
return;
|
|
2613
2647
|
}
|
|
2614
2648
|
if (creditGate !== void 0) {
|
|
@@ -2617,11 +2651,7 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2617
2651
|
} else if (pushAcked && initialCredit === void 0) {
|
|
2618
2652
|
const error = /* @__PURE__ */ new Error(`push to sink "${name}" received unsolicited credit (credit-flow disabled)`);
|
|
2619
2653
|
remoteErrorObject = error;
|
|
2620
|
-
|
|
2621
|
-
if (!pushFinalized) {
|
|
2622
|
-
pushFinalized = true;
|
|
2623
|
-
pushFinalizeReject(error);
|
|
2624
|
-
}
|
|
2654
|
+
failPush(error);
|
|
2625
2655
|
} else pendingCredit += response.credit;
|
|
2626
2656
|
});
|
|
2627
2657
|
spool.roll(() => {
|
|
@@ -2708,7 +2738,7 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2708
2738
|
}
|
|
2709
2739
|
} catch {}
|
|
2710
2740
|
if (pushAcked && !remoteErrorObject) await new Promise((resolve) => {
|
|
2711
|
-
|
|
2741
|
+
setTimeout(resolve, 0);
|
|
2712
2742
|
});
|
|
2713
2743
|
if (remoteErrorObject) throw remoteErrorObject;
|
|
2714
2744
|
throw err;
|
|
@@ -2719,6 +2749,22 @@ var SinkTrait = class extends SourceTrait {
|
|
|
2719
2749
|
};
|
|
2720
2750
|
//#endregion
|
|
2721
2751
|
//#region dst-stage1/mqtt-plus.js
|
|
2722
|
-
var MQTTp = class extends SinkTrait {
|
|
2752
|
+
var MQTTp = class extends SinkTrait {
|
|
2753
|
+
static {
|
|
2754
|
+
this.VERSION = "1.4";
|
|
2755
|
+
}
|
|
2756
|
+
static {
|
|
2757
|
+
this.MIN_VERSION = "1.4";
|
|
2758
|
+
}
|
|
2759
|
+
static {
|
|
2760
|
+
this.version = version;
|
|
2761
|
+
}
|
|
2762
|
+
static {
|
|
2763
|
+
this.minVersion = minVersion;
|
|
2764
|
+
}
|
|
2765
|
+
static {
|
|
2766
|
+
this.versionToNum = versionToNum;
|
|
2767
|
+
}
|
|
2768
|
+
};
|
|
2723
2769
|
//#endregion
|
|
2724
2770
|
export { MQTTp as default };
|