mqtt-plus 1.4.13 → 1.4.15
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/AGENTS.md +0 -1
- package/CHANGELOG.md +18 -0
- package/dst-stage1/mqtt-plus-api.js +1 -0
- package/dst-stage1/mqtt-plus-api.js.map +1 -0
- package/dst-stage1/mqtt-plus-auth.js +1 -0
- package/dst-stage1/mqtt-plus-auth.js.map +1 -0
- package/dst-stage1/mqtt-plus-base.js +1 -0
- package/dst-stage1/mqtt-plus-base.js.map +1 -0
- package/dst-stage1/mqtt-plus-codec.js +1 -0
- package/dst-stage1/mqtt-plus-codec.js.map +1 -0
- package/dst-stage1/mqtt-plus-encode.js +1 -0
- package/dst-stage1/mqtt-plus-encode.js.map +1 -0
- package/dst-stage1/mqtt-plus-error.js +1 -0
- package/dst-stage1/mqtt-plus-error.js.map +1 -0
- package/dst-stage1/mqtt-plus-event.js +1 -0
- package/dst-stage1/mqtt-plus-event.js.map +1 -0
- package/dst-stage1/mqtt-plus-info.js +1 -0
- package/dst-stage1/mqtt-plus-info.js.map +1 -0
- package/dst-stage1/mqtt-plus-meta.js +1 -0
- package/dst-stage1/mqtt-plus-meta.js.map +1 -0
- package/dst-stage1/mqtt-plus-msg.js +1 -0
- package/dst-stage1/mqtt-plus-msg.js.map +1 -0
- package/dst-stage1/mqtt-plus-options.js +1 -0
- package/dst-stage1/mqtt-plus-options.js.map +1 -0
- package/dst-stage1/mqtt-plus-service.js +1 -0
- package/dst-stage1/mqtt-plus-service.js.map +1 -0
- package/dst-stage1/mqtt-plus-sink.js +14 -2
- package/dst-stage1/mqtt-plus-sink.js.map +1 -0
- package/dst-stage1/mqtt-plus-source.js +27 -16
- package/dst-stage1/mqtt-plus-source.js.map +1 -0
- package/dst-stage1/mqtt-plus-subscription.js +1 -0
- package/dst-stage1/mqtt-plus-subscription.js.map +1 -0
- package/dst-stage1/mqtt-plus-timer.js +1 -0
- package/dst-stage1/mqtt-plus-timer.js.map +1 -0
- package/dst-stage1/mqtt-plus-trace.js +1 -0
- package/dst-stage1/mqtt-plus-trace.js.map +1 -0
- package/dst-stage1/mqtt-plus-util.js +1 -0
- package/dst-stage1/mqtt-plus-util.js.map +1 -0
- package/dst-stage1/mqtt-plus-version.d.ts +1 -1
- package/dst-stage1/mqtt-plus-version.js +3 -1
- package/dst-stage1/mqtt-plus-version.js.map +1 -0
- package/dst-stage1/mqtt-plus.js +1 -0
- package/dst-stage1/mqtt-plus.js.map +1 -0
- package/dst-stage2/mqtt-plus.cjs.js +1972 -2161
- package/dst-stage2/mqtt-plus.esm.js +1934 -2131
- package/dst-stage2/mqtt-plus.umd.js +13 -14
- package/etc/c8.json +16 -0
- package/etc/knip.jsonc +7 -1
- package/etc/stx.conf +36 -4
- package/etc/tsc.json +1 -1
- package/etc/vite.mts +11 -5
- package/package.d/vite+8.0.0.patch +12 -0
- package/package.json +12 -3
- package/src/mqtt-plus-sink.ts +14 -2
- package/src/mqtt-plus-source.ts +27 -16
- package/src/mqtt-plus-version.ts +2 -3
- package/tst/.c8/base.css +224 -0
- package/tst/.c8/block-navigation.js +87 -0
- package/tst/.c8/favicon.png +0 -0
- package/tst/.c8/index.html +371 -0
- package/tst/.c8/mqtt-plus-auth.ts.html +538 -0
- package/tst/.c8/mqtt-plus-base.ts.html +826 -0
- package/tst/.c8/mqtt-plus-codec.ts.html +457 -0
- package/tst/.c8/mqtt-plus-encode.ts.html +310 -0
- package/tst/.c8/mqtt-plus-error.ts.html +1186 -0
- package/tst/.c8/mqtt-plus-event.ts.html +733 -0
- package/tst/.c8/mqtt-plus-meta.ts.html +271 -0
- package/tst/.c8/mqtt-plus-msg.ts.html +1693 -0
- package/tst/.c8/mqtt-plus-options.ts.html +319 -0
- package/tst/.c8/mqtt-plus-service.ts.html +865 -0
- package/tst/.c8/mqtt-plus-sink.ts.html +1645 -0
- package/tst/.c8/mqtt-plus-source.ts.html +1585 -0
- package/tst/.c8/mqtt-plus-subscription.ts.html +706 -0
- package/tst/.c8/mqtt-plus-timer.ts.html +286 -0
- package/tst/.c8/mqtt-plus-trace.ts.html +463 -0
- package/tst/.c8/mqtt-plus-util.ts.html +823 -0
- package/tst/.c8/mqtt-plus-version.ts.html +205 -0
- package/tst/.c8/mqtt-plus.ts.html +193 -0
- package/tst/.c8/prettify.css +1 -0
- package/tst/.c8/prettify.js +2 -0
- package/tst/.c8/sort-arrow-sprite.png +0 -0
- package/tst/.c8/sorter.js +210 -0
- package/tst/.c8/tmp/coverage-6577-1773528098323-2.json +1 -0
- package/tst/.c8/tmp/coverage-6577-1773528098331-1.json +1 -0
- package/tst/.c8/tmp/coverage-6577-1773528098353-0.json +1 -0
- package/tst/.c8/tmp/coverage-6578-1773528089194-0.json +1 -0
- package/tst/mqtt-plus-2-event.spec.ts +29 -0
- package/tst/mqtt-plus-6-misc.spec.ts +79 -2
- package/tst/mqtt-plus-7-spool.spec.ts +101 -0
- package/tst/mqtt-plus-8-run.spec.ts +115 -0
- package/tst/{tsc.json → tsc.cov.json} +4 -3
- package/tst/tsc.std.json +31 -0
package/etc/c8.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"all": false,
|
|
3
|
+
"reports-dir": "tst/.c8",
|
|
4
|
+
"extension": [ ".ts", ".js" ],
|
|
5
|
+
"src": [ "." ],
|
|
6
|
+
"include": [ "src/**/*.ts" ],
|
|
7
|
+
"exclude": [ "node_modules/**/*" ],
|
|
8
|
+
"exclude-after-remap": true,
|
|
9
|
+
"check-coverage": true,
|
|
10
|
+
"statements": 95,
|
|
11
|
+
"branches": 75,
|
|
12
|
+
"functions": 95,
|
|
13
|
+
"lines": 95,
|
|
14
|
+
"reporter": [ "text", "html" ],
|
|
15
|
+
"clean": true
|
|
16
|
+
}
|
package/etc/knip.jsonc
CHANGED
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
"tst/mqtt-plus-4-sink.spec.ts",
|
|
38
38
|
"tst/mqtt-plus-5-source.spec.ts",
|
|
39
39
|
"tst/mqtt-plus-6-misc.spec.ts",
|
|
40
|
+
"tst/mqtt-plus-7-spool.spec.ts",
|
|
41
|
+
"tst/mqtt-plus-8-run.spec.ts",
|
|
40
42
|
"etc/vite.mts",
|
|
41
43
|
"etc/d2.mts"
|
|
42
44
|
],
|
|
@@ -46,7 +48,11 @@
|
|
|
46
48
|
],
|
|
47
49
|
"ignoreDependencies": [
|
|
48
50
|
"shx",
|
|
49
|
-
"chokidar-cli"
|
|
51
|
+
"chokidar-cli",
|
|
52
|
+
"patch-package",
|
|
53
|
+
"c8",
|
|
54
|
+
"source-map-support",
|
|
55
|
+
"open-cli"
|
|
50
56
|
]
|
|
51
57
|
}
|
|
52
58
|
|
package/etc/stx.conf
CHANGED
|
@@ -22,6 +22,16 @@
|
|
|
22
22
|
## SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
23
|
##
|
|
24
24
|
|
|
25
|
+
# make patches
|
|
26
|
+
patch-make
|
|
27
|
+
npm shrinkwrap && \
|
|
28
|
+
patch-package --patch-dir package.d && \
|
|
29
|
+
shx rm -f npm-shrinkwrap.json
|
|
30
|
+
|
|
31
|
+
# (internal) apply patches
|
|
32
|
+
patch-apply
|
|
33
|
+
patch-package --patch-dir package.d
|
|
34
|
+
|
|
25
35
|
# static code analysis (linting)
|
|
26
36
|
lint
|
|
27
37
|
tsc --project etc/tsc.json --noEmit && \
|
|
@@ -33,6 +43,11 @@ build : lint
|
|
|
33
43
|
VITE_BUILD_FORMATS=es,cjs vite --config etc/vite.mts build --mode production
|
|
34
44
|
VITE_BUILD_FORMATS=umd vite --config etc/vite.mts build --mode production
|
|
35
45
|
|
|
46
|
+
# code compilation/transpiling (building, development)
|
|
47
|
+
build-dev : lint
|
|
48
|
+
VITE_BUILD_FORMATS=es,cjs vite --config etc/vite.mts build --mode development
|
|
49
|
+
VITE_BUILD_FORMATS=umd vite --config etc/vite.mts build --mode development
|
|
50
|
+
|
|
36
51
|
# documentation compilation
|
|
37
52
|
build-doc
|
|
38
53
|
node etc/d2.mts etc/d2.theme.d2 doc/mqtt-plus-comm-event-emission.d2 doc/mqtt-plus-comm-event-emission.svg
|
|
@@ -44,19 +59,36 @@ build-doc
|
|
|
44
59
|
# development loop
|
|
45
60
|
dev
|
|
46
61
|
chokidar \
|
|
47
|
-
"etc/*" "src
|
|
48
|
-
-c "npm start build" \
|
|
62
|
+
"etc/*" "src/*.ts" "tst/*.ts" \
|
|
63
|
+
-c "npm start build-dev" \
|
|
49
64
|
--debounce 1000 --throttle 1000 \
|
|
50
65
|
--initial --verbose
|
|
51
66
|
|
|
52
67
|
# run test suite
|
|
53
68
|
test
|
|
54
|
-
tsc --project tst/tsc.json --noEmit && \
|
|
69
|
+
tsc --project tst/tsc.std.json --noEmit && \
|
|
70
|
+
eslint --config etc/eslint.mts tst/mqtt-plus-0-*.ts tst/*.spec.ts && \
|
|
71
|
+
if [ ".$MQTT_BROKER" = . ]; then if [ ".`which docker 2>&1`" != . ]; then MQTT_BROKER=mosquitto; fi; else MQTT_BROKER=aedes; fi && \
|
|
72
|
+
MQTT_BROKER="$MQTT_BROKER" \
|
|
73
|
+
TSX_TSCONFIG_PATH="tst/tsc.std.json" \
|
|
74
|
+
NODE_OPTIONS="--import=tsx --trace-warnings -r source-map-support/register" \
|
|
75
|
+
mocha --require tst/mqtt-plus-0-fixture.ts tst/*.spec.ts
|
|
76
|
+
|
|
77
|
+
# run test suite (with code coverage)
|
|
78
|
+
test-cov
|
|
79
|
+
tsc --project tst/tsc.cov.json --noEmit && \
|
|
55
80
|
eslint --config etc/eslint.mts tst/mqtt-plus-0-*.ts tst/*.spec.ts && \
|
|
56
81
|
if [ ".$MQTT_BROKER" = . ]; then if [ ".`which docker 2>&1`" != . ]; then MQTT_BROKER=mosquitto; fi; else MQTT_BROKER=aedes; fi && \
|
|
57
|
-
MQTT_BROKER="$MQTT_BROKER"
|
|
82
|
+
MQTT_BROKER="$MQTT_BROKER" \
|
|
83
|
+
TSX_TSCONFIG_PATH="tst/tsc.cov.json" \
|
|
84
|
+
NODE_OPTIONS="--import=tsx --trace-warnings -r source-map-support/register" \
|
|
85
|
+
c8 --config etc/c8.json \
|
|
58
86
|
mocha --require tst/mqtt-plus-0-fixture.ts tst/*.spec.ts
|
|
59
87
|
|
|
88
|
+
# open code coverage report
|
|
89
|
+
open-cov
|
|
90
|
+
open-cli tst/.c8/index.html
|
|
91
|
+
|
|
60
92
|
# execute simple sample for testing
|
|
61
93
|
sample
|
|
62
94
|
npx tsx sample/sample.ts
|
package/etc/tsc.json
CHANGED
package/etc/vite.mts
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
import * as Vite from "vite"
|
|
26
26
|
import { tscPlugin } from "@wroud/vite-plugin-tsc"
|
|
27
27
|
import { nodePolyfills } from "vite-plugin-node-polyfills"
|
|
28
|
+
import replace from "@rollup/plugin-replace"
|
|
28
29
|
import pkg from "../package.json"
|
|
29
30
|
|
|
30
31
|
const formats = process.env.VITE_BUILD_FORMATS ?? "es"
|
|
@@ -34,12 +35,12 @@ export default Vite.defineConfig(({ command, mode }) => ({
|
|
|
34
35
|
appType: "custom",
|
|
35
36
|
base: "",
|
|
36
37
|
root: "",
|
|
37
|
-
define: {
|
|
38
|
-
"__VERSION__": `"${pkg.version.replace(/\.\d+$/, "")}"`
|
|
39
|
-
},
|
|
40
38
|
plugins: [
|
|
41
39
|
tscPlugin({
|
|
42
|
-
tscArgs:
|
|
40
|
+
tscArgs: [
|
|
41
|
+
"--build", "etc/tsc.json",
|
|
42
|
+
...(mode === "development" ? [ "--sourceMap" ] : [])
|
|
43
|
+
],
|
|
43
44
|
packageManager: "npx",
|
|
44
45
|
prebuild: true
|
|
45
46
|
}),
|
|
@@ -47,7 +48,12 @@ export default Vite.defineConfig(({ command, mode }) => ({
|
|
|
47
48
|
include: [ "events", "stream", "buffer" ],
|
|
48
49
|
globals: {},
|
|
49
50
|
protocolImports: true
|
|
50
|
-
}) ] : [])
|
|
51
|
+
}) ] : []),
|
|
52
|
+
replace({
|
|
53
|
+
"\"0.0\"": `"${pkg.version.replace(/\.\d+$/, "")}"`,
|
|
54
|
+
delimiters: [ "", "" ],
|
|
55
|
+
preventAssignment: true
|
|
56
|
+
})
|
|
51
57
|
],
|
|
52
58
|
build: {
|
|
53
59
|
rollupOptions: {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
diff --git a/node_modules/vite/dist/node/chunks/node.js b/node_modules/vite/dist/node/chunks/node.js
|
|
2
|
+
index 8901df3..1f0f344 100644
|
|
3
|
+
--- a/node_modules/vite/dist/node/chunks/node.js
|
|
4
|
+
+++ b/node_modules/vite/dist/node/chunks/node.js
|
|
5
|
+
@@ -34548,7 +34548,6 @@ async function runConfigHook(config, plugins, configEnv) {
|
|
6
|
+
const res = await getHookHandler(hook).call(context, conf, configEnv);
|
|
7
|
+
if (res && res !== conf) {
|
|
8
|
+
if (hasBothRollupOptionsAndRolldownOptions(res)) context.warn(`Both \`rollupOptions\` and \`rolldownOptions\` were specified by ${JSON.stringify(p.name)} plugin. \`rollupOptions\` specified by that plugin will be ignored.`);
|
|
9
|
+
- if (res.esbuild) context.warn(`\`esbuild\` option was specified by ${JSON.stringify(p.name)} plugin. This option is deprecated, please use \`oxc\` instead.`);
|
|
10
|
+
if (res.optimizeDeps?.esbuildOptions) context.warn(`\`optimizeDeps.esbuildOptions\` option was specified by ${JSON.stringify(p.name)} plugin. This option is deprecated, please use \`optimizeDeps.rolldownOptions\` instead.`);
|
|
11
|
+
conf = mergeConfig(conf, res);
|
|
12
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mqtt-plus",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.15",
|
|
4
4
|
"description": "MQTT Communication Patterns",
|
|
5
5
|
"keywords": [ "mqtt",
|
|
6
6
|
"event", "emit",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"./umd": { "types": "./dst-stage1/mqtt-plus.d.ts", "default": "./dst-stage2/mqtt-plus.umd.js" }
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
+
"patch-package": "8.0.1",
|
|
33
34
|
"@rse/stx": "1.1.4",
|
|
34
35
|
"shx": "0.4.0",
|
|
35
36
|
"eslint": "10.0.3",
|
|
@@ -43,6 +44,8 @@
|
|
|
43
44
|
"chai": "6.2.2",
|
|
44
45
|
"sinon-chai": "4.0.1",
|
|
45
46
|
"sinon": "21.0.2",
|
|
47
|
+
"c8": "11.0.0",
|
|
48
|
+
"source-map-support": "0.5.21",
|
|
46
49
|
"typescript": "5.9.3",
|
|
47
50
|
"typescript-eslint": "8.57.0",
|
|
48
51
|
"@typescript-eslint/parser": "8.57.0",
|
|
@@ -50,14 +53,16 @@
|
|
|
50
53
|
"aedes": "1.0.1",
|
|
51
54
|
"mosquitto": "1.0.2",
|
|
52
55
|
"textframe": "1.2.1",
|
|
53
|
-
"vite": "
|
|
56
|
+
"vite": "8.0.0",
|
|
54
57
|
"vite-plugin-node-polyfills": "0.25.0",
|
|
58
|
+
"@rollup/plugin-replace": "6.0.3",
|
|
55
59
|
"@wroud/vite-plugin-tsc": "0.12.2",
|
|
56
60
|
"@terrastruct/d2": "0.1.33",
|
|
57
61
|
"chokidar-cli": "3.0.0",
|
|
58
62
|
"chalk": "5.6.2",
|
|
63
|
+
"open-cli": "8.0.0",
|
|
59
64
|
|
|
60
|
-
"@types/node": "25.
|
|
65
|
+
"@types/node": "25.5.0",
|
|
61
66
|
"@types/mocha": "10.0.10",
|
|
62
67
|
"@types/chai": "5.2.3",
|
|
63
68
|
"@types/sinon-chai": "4.0.0",
|
|
@@ -66,6 +71,9 @@
|
|
|
66
71
|
"peerDependencies": {
|
|
67
72
|
"mqtt": ">=4.0.0"
|
|
68
73
|
},
|
|
74
|
+
"overrides": {
|
|
75
|
+
"vite-plugin-node-polyfills": { "vite": ">=7.0.0" }
|
|
76
|
+
},
|
|
69
77
|
"dependencies": {
|
|
70
78
|
"nanoid": "5.1.6",
|
|
71
79
|
"cbor2": "2.3.0",
|
|
@@ -79,6 +87,7 @@
|
|
|
79
87
|
"node": ">=16.0.0"
|
|
80
88
|
},
|
|
81
89
|
"scripts": {
|
|
90
|
+
"postinstall": "npm start patch-apply",
|
|
82
91
|
"prepublishOnly": "npm start build",
|
|
83
92
|
"start": "stx -v4 -c etc/stx.conf",
|
|
84
93
|
"test": "npm start test"
|
package/src/mqtt-plus-sink.ts
CHANGED
|
@@ -162,6 +162,8 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
|
|
|
162
162
|
/* utility functions for timeout management */
|
|
163
163
|
const pushTimerId = `sink-push-recv:${requestId}`
|
|
164
164
|
const refreshPushTimeout = () => this.timerRefresh(pushTimerId, () => {
|
|
165
|
+
if (streamEnded)
|
|
166
|
+
return
|
|
165
167
|
const stream = this.pushStreams.get(requestId)
|
|
166
168
|
if (stream !== undefined)
|
|
167
169
|
stream.destroy(new Error("push stream timeout"))
|
|
@@ -201,6 +203,7 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
|
|
|
201
203
|
return
|
|
202
204
|
if (chunkParsed.error !== undefined) {
|
|
203
205
|
streamEnded = true
|
|
206
|
+
clearPushTimeout()
|
|
204
207
|
readable.destroy(new Error(chunkParsed.error))
|
|
205
208
|
}
|
|
206
209
|
else {
|
|
@@ -212,6 +215,7 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
|
|
|
212
215
|
}
|
|
213
216
|
if (chunkParsed.final) {
|
|
214
217
|
streamEnded = true
|
|
218
|
+
clearPushTimeout()
|
|
215
219
|
readable.push(null)
|
|
216
220
|
}
|
|
217
221
|
}
|
|
@@ -248,6 +252,10 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
|
|
|
248
252
|
/* call handler */
|
|
249
253
|
await callback(...params, info)
|
|
250
254
|
|
|
255
|
+
/* ensure stream is consumed or destroyed to prevent hang */
|
|
256
|
+
if (readable.readableFlowing !== true && !readable.destroyed)
|
|
257
|
+
readable.resume()
|
|
258
|
+
|
|
251
259
|
/* await full stream consumption before confirming success */
|
|
252
260
|
await streamDone
|
|
253
261
|
|
|
@@ -382,6 +390,7 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
|
|
|
382
390
|
let remoteError = false
|
|
383
391
|
let pushAcked = false
|
|
384
392
|
let pushFinalized = false
|
|
393
|
+
let pushDataFinalSent = false
|
|
385
394
|
let pushFinalizeResolve!: () => void
|
|
386
395
|
let pushFinalizeReject!: (reason?: any) => void
|
|
387
396
|
const pushFinalize = new Promise<void>((resolve, reject) => {
|
|
@@ -465,6 +474,8 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
|
|
|
465
474
|
name, chunk, error, final, this.options.id, receiver)
|
|
466
475
|
const message = this.codec.encode(chunkMsg)
|
|
467
476
|
await this.publishToTopic(chunkTopic, message, { qos: 2, ...options })
|
|
477
|
+
if (error === undefined && final)
|
|
478
|
+
pushDataFinalSent = true
|
|
468
479
|
}
|
|
469
480
|
|
|
470
481
|
/* iterate over all chunks of the buffer */
|
|
@@ -491,8 +502,9 @@ export class SinkTrait<T extends APISchema = APISchema> extends SourceTrait<T> {
|
|
|
491
502
|
abortController.abort(error)
|
|
492
503
|
|
|
493
504
|
/* send error chunk only if push was acked and error did not originate from receiver
|
|
494
|
-
(before ack, the sink has no chunk handler yet and will time out on its own
|
|
495
|
-
|
|
505
|
+
(before ack, the sink has no chunk handler yet and will time out on its own;
|
|
506
|
+
after final data chunk, no additional terminal chunk should be sent) */
|
|
507
|
+
if (pushAcked && !remoteError && !pushDataFinalSent) {
|
|
496
508
|
const chunkTopic = this.options.topicMake(name, "sink-push-request", receiver)
|
|
497
509
|
const chunkMsg = this.msg.makeSinkPushChunk(requestId,
|
|
498
510
|
name, undefined, error.message, true, this.options.id, receiver)
|
package/src/mqtt-plus-source.ts
CHANGED
|
@@ -142,6 +142,13 @@ export class SourceTrait<T extends APISchema = APISchema> extends ServiceTrait<T
|
|
|
142
142
|
await this.publishToTopic(responseTopic, message, { qos: options.qos ?? 2 })
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
/* create a resource spool for request cleanup */
|
|
146
|
+
const reqSpool = new Spool()
|
|
147
|
+
reqSpool.roll(() => {
|
|
148
|
+
this.onResponse.delete(`source-fetch-credit:${requestId}`)
|
|
149
|
+
this.sourceControllers.delete(requestId)
|
|
150
|
+
})
|
|
151
|
+
|
|
145
152
|
/* define abort controller and signal */
|
|
146
153
|
const abortController = new AbortController()
|
|
147
154
|
this.sourceControllers.set(requestId, abortController)
|
|
@@ -163,11 +170,11 @@ export class SourceTrait<T extends APISchema = APISchema> extends ServiceTrait<T
|
|
|
163
170
|
gate.abort()
|
|
164
171
|
this.sourceCreditGates.delete(requestId)
|
|
165
172
|
}
|
|
166
|
-
|
|
167
|
-
this.onResponse.delete(`source-fetch-credit:${requestId}`)
|
|
173
|
+
reqSpool.unroll()
|
|
168
174
|
})
|
|
169
175
|
const clearSourceTimeout = () => this.timerClear(sourceTimerId)
|
|
170
176
|
refreshSourceTimeout()
|
|
177
|
+
reqSpool.roll(() => { clearSourceTimeout() })
|
|
171
178
|
|
|
172
179
|
/* callback for creating and sending a chunk message */
|
|
173
180
|
const sendChunk = async (
|
|
@@ -185,6 +192,7 @@ export class SourceTrait<T extends APISchema = APISchema> extends ServiceTrait<T
|
|
|
185
192
|
/* call the handler callback */
|
|
186
193
|
let ackSent = false
|
|
187
194
|
let creditGate: CreditGate | undefined
|
|
195
|
+
let cancelledByFetcher = false
|
|
188
196
|
try {
|
|
189
197
|
if (topicName !== request.name)
|
|
190
198
|
throw new Error(`source name mismatch (topic: "${topicName}", payload: "${request.name}")`)
|
|
@@ -197,13 +205,19 @@ export class SourceTrait<T extends APISchema = APISchema> extends ServiceTrait<T
|
|
|
197
205
|
const initialCredit = request.credit
|
|
198
206
|
creditGate = (initialCredit !== undefined && initialCredit > 0)
|
|
199
207
|
? new CreditGate(initialCredit) : undefined
|
|
200
|
-
if (creditGate)
|
|
208
|
+
if (creditGate) {
|
|
201
209
|
this.sourceCreditGates.set(requestId, creditGate)
|
|
210
|
+
reqSpool.roll(() => {
|
|
211
|
+
creditGate!.abort()
|
|
212
|
+
this.sourceCreditGates.delete(requestId)
|
|
213
|
+
})
|
|
214
|
+
}
|
|
202
215
|
|
|
203
216
|
/* register credit/cancel handler (unconditional for cancel support) */
|
|
204
217
|
this.onResponse.set(`source-fetch-credit:${requestId}`, (creditParsed: SourceFetchCredit) => {
|
|
205
218
|
if (creditParsed.credit === 0) {
|
|
206
219
|
/* cancel signal from fetcher */
|
|
220
|
+
cancelledByFetcher = true
|
|
207
221
|
abortController.abort(new Error(`source fetch "${name}" cancelled by fetcher`))
|
|
208
222
|
return
|
|
209
223
|
}
|
|
@@ -238,22 +252,19 @@ export class SourceTrait<T extends APISchema = APISchema> extends ServiceTrait<T
|
|
|
238
252
|
const error = ensureError(err, `handler for source "${name}" failed`)
|
|
239
253
|
abortController.abort(error)
|
|
240
254
|
|
|
241
|
-
/*
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
255
|
+
/* on explicit fetcher cancellation, abort silently without emitting error responses */
|
|
256
|
+
if (!cancelledByFetcher) {
|
|
257
|
+
/* send error as nak response or as error chunk */
|
|
258
|
+
this.error(error)
|
|
259
|
+
if (ackSent)
|
|
260
|
+
await sendChunk(undefined, error.message, true).catch(() => {})
|
|
261
|
+
else
|
|
262
|
+
await sendResponse(error.message).catch(() => {})
|
|
263
|
+
}
|
|
247
264
|
}
|
|
248
265
|
finally {
|
|
249
266
|
/* cleanup resources */
|
|
250
|
-
|
|
251
|
-
if (creditGate) {
|
|
252
|
-
creditGate.abort()
|
|
253
|
-
this.sourceCreditGates.delete(requestId)
|
|
254
|
-
}
|
|
255
|
-
this.sourceControllers.delete(requestId)
|
|
256
|
-
this.onResponse.delete(`source-fetch-credit:${requestId}`)
|
|
267
|
+
await reqSpool.unroll()
|
|
257
268
|
}
|
|
258
269
|
})
|
|
259
270
|
spool.roll(() => { this.onRequest.delete(`source-fetch-request:${name}`) })
|
package/src/mqtt-plus-version.ts
CHANGED
|
@@ -33,9 +33,8 @@ export const versionToNum = (str: string) => {
|
|
|
33
33
|
return parseInt(m[1], 10) * 100 + minor
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
/* package version (string format,
|
|
37
|
-
|
|
38
|
-
export const VERSION = __VERSION__
|
|
36
|
+
/* package version (string format, overridden) */
|
|
37
|
+
export const VERSION = "0.0"
|
|
39
38
|
|
|
40
39
|
/* package version (numeric format) */
|
|
41
40
|
export const version = versionToNum(VERSION)
|
package/tst/.c8/base.css
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
body, html {
|
|
2
|
+
margin:0; padding: 0;
|
|
3
|
+
height: 100%;
|
|
4
|
+
}
|
|
5
|
+
body {
|
|
6
|
+
font-family: Helvetica Neue, Helvetica, Arial;
|
|
7
|
+
font-size: 14px;
|
|
8
|
+
color:#333;
|
|
9
|
+
}
|
|
10
|
+
.small { font-size: 12px; }
|
|
11
|
+
*, *:after, *:before {
|
|
12
|
+
-webkit-box-sizing:border-box;
|
|
13
|
+
-moz-box-sizing:border-box;
|
|
14
|
+
box-sizing:border-box;
|
|
15
|
+
}
|
|
16
|
+
h1 { font-size: 20px; margin: 0;}
|
|
17
|
+
h2 { font-size: 14px; }
|
|
18
|
+
pre {
|
|
19
|
+
font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 0;
|
|
22
|
+
-moz-tab-size: 2;
|
|
23
|
+
-o-tab-size: 2;
|
|
24
|
+
tab-size: 2;
|
|
25
|
+
}
|
|
26
|
+
a { color:#0074D9; text-decoration:none; }
|
|
27
|
+
a:hover { text-decoration:underline; }
|
|
28
|
+
.strong { font-weight: bold; }
|
|
29
|
+
.space-top1 { padding: 10px 0 0 0; }
|
|
30
|
+
.pad2y { padding: 20px 0; }
|
|
31
|
+
.pad1y { padding: 10px 0; }
|
|
32
|
+
.pad2x { padding: 0 20px; }
|
|
33
|
+
.pad2 { padding: 20px; }
|
|
34
|
+
.pad1 { padding: 10px; }
|
|
35
|
+
.space-left2 { padding-left:55px; }
|
|
36
|
+
.space-right2 { padding-right:20px; }
|
|
37
|
+
.center { text-align:center; }
|
|
38
|
+
.clearfix { display:block; }
|
|
39
|
+
.clearfix:after {
|
|
40
|
+
content:'';
|
|
41
|
+
display:block;
|
|
42
|
+
height:0;
|
|
43
|
+
clear:both;
|
|
44
|
+
visibility:hidden;
|
|
45
|
+
}
|
|
46
|
+
.fl { float: left; }
|
|
47
|
+
@media only screen and (max-width:640px) {
|
|
48
|
+
.col3 { width:100%; max-width:100%; }
|
|
49
|
+
.hide-mobile { display:none!important; }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.quiet {
|
|
53
|
+
color: #7f7f7f;
|
|
54
|
+
color: rgba(0,0,0,0.5);
|
|
55
|
+
}
|
|
56
|
+
.quiet a { opacity: 0.7; }
|
|
57
|
+
|
|
58
|
+
.fraction {
|
|
59
|
+
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
|
60
|
+
font-size: 10px;
|
|
61
|
+
color: #555;
|
|
62
|
+
background: #E8E8E8;
|
|
63
|
+
padding: 4px 5px;
|
|
64
|
+
border-radius: 3px;
|
|
65
|
+
vertical-align: middle;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
div.path a:link, div.path a:visited { color: #333; }
|
|
69
|
+
table.coverage {
|
|
70
|
+
border-collapse: collapse;
|
|
71
|
+
margin: 10px 0 0 0;
|
|
72
|
+
padding: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
table.coverage td {
|
|
76
|
+
margin: 0;
|
|
77
|
+
padding: 0;
|
|
78
|
+
vertical-align: top;
|
|
79
|
+
}
|
|
80
|
+
table.coverage td.line-count {
|
|
81
|
+
text-align: right;
|
|
82
|
+
padding: 0 5px 0 20px;
|
|
83
|
+
}
|
|
84
|
+
table.coverage td.line-coverage {
|
|
85
|
+
text-align: right;
|
|
86
|
+
padding-right: 10px;
|
|
87
|
+
min-width:20px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
table.coverage td span.cline-any {
|
|
91
|
+
display: inline-block;
|
|
92
|
+
padding: 0 5px;
|
|
93
|
+
width: 100%;
|
|
94
|
+
}
|
|
95
|
+
.missing-if-branch {
|
|
96
|
+
display: inline-block;
|
|
97
|
+
margin-right: 5px;
|
|
98
|
+
border-radius: 3px;
|
|
99
|
+
position: relative;
|
|
100
|
+
padding: 0 4px;
|
|
101
|
+
background: #333;
|
|
102
|
+
color: yellow;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.skip-if-branch {
|
|
106
|
+
display: none;
|
|
107
|
+
margin-right: 10px;
|
|
108
|
+
position: relative;
|
|
109
|
+
padding: 0 4px;
|
|
110
|
+
background: #ccc;
|
|
111
|
+
color: white;
|
|
112
|
+
}
|
|
113
|
+
.missing-if-branch .typ, .skip-if-branch .typ {
|
|
114
|
+
color: inherit !important;
|
|
115
|
+
}
|
|
116
|
+
.coverage-summary {
|
|
117
|
+
border-collapse: collapse;
|
|
118
|
+
width: 100%;
|
|
119
|
+
}
|
|
120
|
+
.coverage-summary tr { border-bottom: 1px solid #bbb; }
|
|
121
|
+
.keyline-all { border: 1px solid #ddd; }
|
|
122
|
+
.coverage-summary td, .coverage-summary th { padding: 10px; }
|
|
123
|
+
.coverage-summary tbody { border: 1px solid #bbb; }
|
|
124
|
+
.coverage-summary td { border-right: 1px solid #bbb; }
|
|
125
|
+
.coverage-summary td:last-child { border-right: none; }
|
|
126
|
+
.coverage-summary th {
|
|
127
|
+
text-align: left;
|
|
128
|
+
font-weight: normal;
|
|
129
|
+
white-space: nowrap;
|
|
130
|
+
}
|
|
131
|
+
.coverage-summary th.file { border-right: none !important; }
|
|
132
|
+
.coverage-summary th.pct { }
|
|
133
|
+
.coverage-summary th.pic,
|
|
134
|
+
.coverage-summary th.abs,
|
|
135
|
+
.coverage-summary td.pct,
|
|
136
|
+
.coverage-summary td.abs { text-align: right; }
|
|
137
|
+
.coverage-summary td.file { white-space: nowrap; }
|
|
138
|
+
.coverage-summary td.pic { min-width: 120px !important; }
|
|
139
|
+
.coverage-summary tfoot td { }
|
|
140
|
+
|
|
141
|
+
.coverage-summary .sorter {
|
|
142
|
+
height: 10px;
|
|
143
|
+
width: 7px;
|
|
144
|
+
display: inline-block;
|
|
145
|
+
margin-left: 0.5em;
|
|
146
|
+
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
|
|
147
|
+
}
|
|
148
|
+
.coverage-summary .sorted .sorter {
|
|
149
|
+
background-position: 0 -20px;
|
|
150
|
+
}
|
|
151
|
+
.coverage-summary .sorted-desc .sorter {
|
|
152
|
+
background-position: 0 -10px;
|
|
153
|
+
}
|
|
154
|
+
.status-line { height: 10px; }
|
|
155
|
+
/* yellow */
|
|
156
|
+
.cbranch-no { background: yellow !important; color: #111; }
|
|
157
|
+
/* dark red */
|
|
158
|
+
.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
|
|
159
|
+
.low .chart { border:1px solid #C21F39 }
|
|
160
|
+
.highlighted,
|
|
161
|
+
.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
|
|
162
|
+
background: #C21F39 !important;
|
|
163
|
+
}
|
|
164
|
+
/* medium red */
|
|
165
|
+
.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
|
|
166
|
+
/* light red */
|
|
167
|
+
.low, .cline-no { background:#FCE1E5 }
|
|
168
|
+
/* light green */
|
|
169
|
+
.high, .cline-yes { background:rgb(230,245,208) }
|
|
170
|
+
/* medium green */
|
|
171
|
+
.cstat-yes { background:rgb(161,215,106) }
|
|
172
|
+
/* dark green */
|
|
173
|
+
.status-line.high, .high .cover-fill { background:rgb(77,146,33) }
|
|
174
|
+
.high .chart { border:1px solid rgb(77,146,33) }
|
|
175
|
+
/* dark yellow (gold) */
|
|
176
|
+
.status-line.medium, .medium .cover-fill { background: #f9cd0b; }
|
|
177
|
+
.medium .chart { border:1px solid #f9cd0b; }
|
|
178
|
+
/* light yellow */
|
|
179
|
+
.medium { background: #fff4c2; }
|
|
180
|
+
|
|
181
|
+
.cstat-skip { background: #ddd; color: #111; }
|
|
182
|
+
.fstat-skip { background: #ddd; color: #111 !important; }
|
|
183
|
+
.cbranch-skip { background: #ddd !important; color: #111; }
|
|
184
|
+
|
|
185
|
+
span.cline-neutral { background: #eaeaea; }
|
|
186
|
+
|
|
187
|
+
.coverage-summary td.empty {
|
|
188
|
+
opacity: .5;
|
|
189
|
+
padding-top: 4px;
|
|
190
|
+
padding-bottom: 4px;
|
|
191
|
+
line-height: 1;
|
|
192
|
+
color: #888;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.cover-fill, .cover-empty {
|
|
196
|
+
display:inline-block;
|
|
197
|
+
height: 12px;
|
|
198
|
+
}
|
|
199
|
+
.chart {
|
|
200
|
+
line-height: 0;
|
|
201
|
+
}
|
|
202
|
+
.cover-empty {
|
|
203
|
+
background: white;
|
|
204
|
+
}
|
|
205
|
+
.cover-full {
|
|
206
|
+
border-right: none !important;
|
|
207
|
+
}
|
|
208
|
+
pre.prettyprint {
|
|
209
|
+
border: none !important;
|
|
210
|
+
padding: 0 !important;
|
|
211
|
+
margin: 0 !important;
|
|
212
|
+
}
|
|
213
|
+
.com { color: #999 !important; }
|
|
214
|
+
.ignore-none { color: #999; font-weight: normal; }
|
|
215
|
+
|
|
216
|
+
.wrapper {
|
|
217
|
+
min-height: 100%;
|
|
218
|
+
height: auto !important;
|
|
219
|
+
height: 100%;
|
|
220
|
+
margin: 0 auto -48px;
|
|
221
|
+
}
|
|
222
|
+
.footer, .push {
|
|
223
|
+
height: 48px;
|
|
224
|
+
}
|