mqtt-plus 1.4.16 → 1.4.17
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/.claude/CLAUDE.md +1 -0
- package/.gemini/settings.json +5 -0
- package/AGENTS.md +86 -97
- package/CHANGELOG.md +26 -0
- package/README.md +1 -1
- package/doc/mqtt-plus-api.md +21 -12
- package/doc/mqtt-plus-architecture.md +1 -1
- package/doc/mqtt-plus-broker-setup.md +2 -2
- package/doc/mqtt-plus-comm.md +3 -2
- package/doc/mqtt-plus-internals.md +11 -1
- package/dst-stage1/mqtt-plus-auth.js +2 -13
- package/dst-stage1/mqtt-plus-auth.js.map +1 -1
- package/dst-stage1/mqtt-plus-base.d.ts +2 -1
- package/dst-stage1/mqtt-plus-base.js +14 -3
- package/dst-stage1/mqtt-plus-base.js.map +1 -1
- package/dst-stage1/mqtt-plus-error.d.ts +1 -0
- package/dst-stage1/mqtt-plus-error.js +62 -38
- package/dst-stage1/mqtt-plus-error.js.map +1 -1
- package/dst-stage1/mqtt-plus-event.d.ts +2 -0
- package/dst-stage1/mqtt-plus-event.js +52 -10
- package/dst-stage1/mqtt-plus-event.js.map +1 -1
- package/dst-stage1/mqtt-plus-info.d.ts +2 -0
- package/dst-stage1/mqtt-plus-msg.d.ts +3 -2
- package/dst-stage1/mqtt-plus-msg.js +10 -8
- package/dst-stage1/mqtt-plus-msg.js.map +1 -1
- package/dst-stage1/mqtt-plus-service.d.ts +2 -0
- package/dst-stage1/mqtt-plus-service.js +120 -19
- package/dst-stage1/mqtt-plus-service.js.map +1 -1
- package/dst-stage1/mqtt-plus-sink.js +104 -39
- package/dst-stage1/mqtt-plus-sink.js.map +1 -1
- package/dst-stage1/mqtt-plus-source.d.ts +1 -0
- package/dst-stage1/mqtt-plus-source.js +81 -59
- package/dst-stage1/mqtt-plus-source.js.map +1 -1
- package/dst-stage1/mqtt-plus-subscription.js +14 -8
- package/dst-stage1/mqtt-plus-subscription.js.map +1 -1
- package/dst-stage1/mqtt-plus-timer.d.ts +2 -0
- package/dst-stage1/mqtt-plus-timer.js +48 -0
- package/dst-stage1/mqtt-plus-timer.js.map +1 -1
- package/dst-stage1/mqtt-plus-trace.js +3 -1
- package/dst-stage1/mqtt-plus-trace.js.map +1 -1
- package/dst-stage1/mqtt-plus-util.js +10 -2
- package/dst-stage1/mqtt-plus-util.js.map +1 -1
- package/dst-stage1/mqtt-plus-version.d.ts +2 -0
- package/dst-stage1/mqtt-plus-version.js +3 -0
- package/dst-stage1/mqtt-plus-version.js.map +1 -1
- package/dst-stage2/mqtt-plus.cjs.cjs +415 -162
- package/dst-stage2/mqtt-plus.esm.js +415 -162
- package/dst-stage2/mqtt-plus.umd.js +2 -2
- package/etc/d2.mts +19 -13
- package/etc/stx.conf +8 -6
- package/etc/vite.mts +1 -1
- package/package.json +4 -4
- package/src/mqtt-plus-auth.ts +2 -14
- package/src/mqtt-plus-base.ts +16 -3
- package/src/mqtt-plus-error.ts +68 -40
- package/src/mqtt-plus-event.ts +56 -11
- package/src/mqtt-plus-info.ts +6 -2
- package/src/mqtt-plus-msg.ts +9 -6
- package/src/mqtt-plus-service.ts +125 -19
- package/src/mqtt-plus-sink.ts +109 -39
- package/src/mqtt-plus-source.ts +87 -59
- package/src/mqtt-plus-subscription.ts +17 -9
- package/src/mqtt-plus-timer.ts +52 -0
- package/src/mqtt-plus-trace.ts +3 -1
- package/src/mqtt-plus-util.ts +11 -2
- package/src/mqtt-plus-version.ts +5 -1
- package/tst/mqtt-plus-0-broker-mosquitto.ts +2 -2
- package/tst/mqtt-plus-7-spool.spec.ts +65 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@../AGENTS.md
|
package/AGENTS.md
CHANGED
|
@@ -1,49 +1,41 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
3
|
-
======
|
|
2
|
+
# Overview for AI Agents
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
## Project Abstract
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
MQTT+ (`mqtt-plus`) is a TypeScript library implementing four MQTT
|
|
7
|
+
communication patterns with full type safety: Event Emission, Service
|
|
8
|
+
Call (RPC), Source Fetch, and Sink Push. It uses `mqtt` as a peer
|
|
9
|
+
dependency and builds to ESM, CJS, and UMD formats.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
with full type safety: Event Emission, Service Call (RPC), Source Fetch, and Sink Push.
|
|
12
|
-
It uses `mqtt` as a peer dependency and builds to ESM, CJS, and UMD formats.
|
|
11
|
+
## Technology Stack
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
Build-Tools: npm, @rse/stx, vite, eslint, typescript
|
|
14
|
+
Language: TypeScript
|
|
15
|
+
Libraries: nanoid, cbor2, p-lazy, valibot, jose, @stablelib/pbkdf2, @stablelib/sha256
|
|
16
|
+
Runtime: Browser, Node.js
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
## Build Commands
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
npm install # install dependencies
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Build and development commands use STX (`@rse/stx`) as the task runner:
|
|
20
|
+
Build and development commands use NPM and STX (`@rse/stx`) as the task runner:
|
|
24
21
|
|
|
25
22
|
```bash
|
|
26
|
-
npm
|
|
27
|
-
npm start build # standard: build everything
|
|
28
|
-
npm start test # standard: run unit test suite
|
|
29
|
-
|
|
30
|
-
npm start build-doc # generate SVG diagrams from D2 sources only
|
|
31
|
-
npm start dev # development watch mode (rebuild on change)
|
|
32
|
-
npm start sample # run sample/sample.ts via `tsx`
|
|
23
|
+
npm install # install dependencies
|
|
33
24
|
|
|
34
|
-
npm start
|
|
35
|
-
npm start
|
|
36
|
-
npm start
|
|
37
|
-
```
|
|
25
|
+
npm start lint # standard: perform static code analysis
|
|
26
|
+
npm start build # standard: build everything
|
|
27
|
+
npm start test # standard: run unit test suite
|
|
38
28
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
29
|
+
npm start build-doc # generate SVG diagrams from D2 sources only
|
|
30
|
+
npm start dev # development watch mode (rebuild on change)
|
|
31
|
+
npm start sample # run sample/sample.ts via `tsx`
|
|
42
32
|
|
|
43
|
-
|
|
33
|
+
npm start clean # remove dst-stage1/ and dst-stage2/
|
|
34
|
+
npm start distclean # remove node_modules/ and package-lock.json
|
|
35
|
+
npm start publish # publish to npm (restricted to maintainer host)
|
|
36
|
+
```
|
|
44
37
|
|
|
45
|
-
Build Pipeline
|
|
46
|
-
--------------
|
|
38
|
+
## Build Pipeline
|
|
47
39
|
|
|
48
40
|
Two-stage build:
|
|
49
41
|
|
|
@@ -54,16 +46,22 @@ Two-stage build:
|
|
|
54
46
|
`mqtt-plus.esm.js`, `mqtt-plus.cjs.js`, `mqtt-plus.umd.js`.
|
|
55
47
|
UMD build includes Node polyfills (events, stream, buffer).
|
|
56
48
|
|
|
57
|
-
Configuration lives in `etc/`: `tsc.json`, `vite.mts`, `eslint.mts`,
|
|
49
|
+
Configuration lives in `etc/`: `tsc.json`, `vite.mts`, `eslint.mts`,
|
|
50
|
+
`knip.jsonc`, `stx.conf`, `d2.mts`, `d2.theme.d2`, `logo.ai`,
|
|
51
|
+
`logo.svg`.
|
|
52
|
+
|
|
53
|
+
Tests require an MQTT broker under run-time; the test suite starts/stops
|
|
54
|
+
one automatically. If Docker is available, a Mosquitto broker is used;
|
|
55
|
+
otherwise, the Aedes in-process broker serves as the fallback.
|
|
56
|
+
For regression testing always use the all-in-one command `npm start build test`.
|
|
58
57
|
|
|
59
|
-
Architecture
|
|
60
|
-
------------
|
|
58
|
+
## Architecture
|
|
61
59
|
|
|
62
60
|
### Trait-Based Mixin Tower
|
|
63
61
|
|
|
64
62
|
The library is composed as a vertical chain of trait classes (mixins),
|
|
65
|
-
each extending the previous. The final exported class `MQTTp` sits
|
|
66
|
-
the bottom of this chain:
|
|
63
|
+
each extending the previous one. The final exported class `MQTTp` sits
|
|
64
|
+
at the bottom of this chain:
|
|
67
65
|
|
|
68
66
|
```
|
|
69
67
|
OptionsTrait — configuration (id, codec, timeout, share, chunkSize, chunkCredit, topicMake/topicMatch)
|
|
@@ -87,63 +85,55 @@ Each trait lives in its own file: `src/mqtt-plus-<trait>.ts`.
|
|
|
87
85
|
|
|
88
86
|
### Key Source Files
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
- `
|
|
119
|
-
- `
|
|
120
|
-
- `
|
|
121
|
-
- `
|
|
122
|
-
- `
|
|
123
|
-
- `
|
|
124
|
-
- `
|
|
125
|
-
- `
|
|
126
|
-
- `
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
| `tst/mqtt-plus-0-broker-mosquitto.ts` | Helper for starting/stopping the Mosquitto MQTT broker |
|
|
140
|
-
| `tst/mqtt-plus-1-api.spec.ts` | API type and endpoint definition tests |
|
|
141
|
-
| `tst/mqtt-plus-2-event.spec.ts` | Event Emission pattern tests |
|
|
142
|
-
| `tst/mqtt-plus-3-service.spec.ts` | Service Call / RPC pattern tests |
|
|
143
|
-
| `tst/mqtt-plus-4-sink.spec.ts` | Sink Push pattern tests |
|
|
144
|
-
| `tst/mqtt-plus-5-source.spec.ts` | Source Fetch pattern tests |
|
|
145
|
-
| `tst/mqtt-plus-6-misc.spec.ts` | Miscellaneous / edge-case tests |
|
|
146
|
-
| `tst/tsc.json` | TypeScript configuration for the test directory |
|
|
88
|
+
- `src/mqtt-plus.ts`: Main entry point, re-exports public API types and the final MQTTp class
|
|
89
|
+
- `src/mqtt-plus-api.ts`: Branded endpoint type definitions (Event, Service, Source, Sink) and APISchema generic
|
|
90
|
+
- `src/mqtt-plus-info.ts`: Info/context object types passed to pattern callbacks (sender metadata, etc.)
|
|
91
|
+
- `src/mqtt-plus-error.ts`: Spool (resource cleanup) and run (error handling) utilities
|
|
92
|
+
- `src/mqtt-plus-util.ts`: PLazy, CreditGate flow control, and stream/buffer collection utilities
|
|
93
|
+
- `src/mqtt-plus-version.ts`: Version utility for converting version strings to numeric format
|
|
94
|
+
- `src/mqtt-plus-options.ts`: OptionsTrait — configuration (id, codec, timeout, share, chunkSize, chunkCredit, topicMake/topicMatch)
|
|
95
|
+
- `src/mqtt-plus-codec.ts`: CodecTrait — CBOR and JSON codec encoding/decoding
|
|
96
|
+
- `src/mqtt-plus-encode.ts`: EncodeTrait — string/buffer conversion utilities (str2buf, buf2str)
|
|
97
|
+
- `src/mqtt-plus-msg.ts`: MsgTrait — message class definitions, valibot schemas, and parsing logic
|
|
98
|
+
- `src/mqtt-plus-trace.ts`: TraceTrait — EventEmitter and structured logging
|
|
99
|
+
- `src/mqtt-plus-base.ts`: BaseTrait — MQTT client connection, subscription management, message routing
|
|
100
|
+
- `src/mqtt-plus-subscription.ts`: SubscriptionTrait — RefCountedSubscription class and ref-counted MQTT topic subscription management
|
|
101
|
+
- `src/mqtt-plus-timer.ts`: TimerTrait — named timer management (refresh/clear)
|
|
102
|
+
- `src/mqtt-plus-meta.ts`: MetaTrait — instance and per-request metadata management
|
|
103
|
+
- `src/mqtt-plus-auth.ts`: AuthTrait — JWT authentication (jose) and role-based access control
|
|
104
|
+
- `src/mqtt-plus-event.ts`: EventTrait — Event Emission communication pattern (event/emit)
|
|
105
|
+
- `src/mqtt-plus-service.ts`: ServiceTrait — Service Call / RPC communication pattern (service/call)
|
|
106
|
+
- `src/mqtt-plus-source.ts`: SourceTrait — Source Fetch communication pattern (source/fetch)
|
|
107
|
+
- `src/mqtt-plus-sink.ts`: SinkTrait — Sink Push communication pattern (sink/push)
|
|
108
|
+
|
|
109
|
+
### Key Test Files
|
|
110
|
+
|
|
111
|
+
- `tst/mqtt-plus-0-fixture.ts`: Shared test fixture setup (broker, MQTTp instances, etc.)
|
|
112
|
+
- `tst/mqtt-plus-0-broker.ts`: Broker dispatch: creates Aedes or Mosquitto broker based on env
|
|
113
|
+
- `tst/mqtt-plus-0-broker-aedes.ts`: Helper for starting/stopping the Aedes MQTT broker
|
|
114
|
+
- `tst/mqtt-plus-0-broker-mosquitto.ts`: Helper for starting/stopping the Mosquitto MQTT broker
|
|
115
|
+
- `tst/mqtt-plus-1-api.spec.ts`: API type and endpoint definition tests
|
|
116
|
+
- `tst/mqtt-plus-2-event.spec.ts`: Event Emission pattern tests
|
|
117
|
+
- `tst/mqtt-plus-3-service.spec.ts`: Service Call / RPC pattern tests
|
|
118
|
+
- `tst/mqtt-plus-4-sink.spec.ts`: Sink Push pattern tests
|
|
119
|
+
- `tst/mqtt-plus-5-source.spec.ts`: Source Fetch pattern tests
|
|
120
|
+
- `tst/mqtt-plus-6-misc.spec.ts`: Miscellaneous / edge-case tests
|
|
121
|
+
- `tst/mqtt-plus-7-spool.spec.ts`: Spool (resource cleanup) utility tests
|
|
122
|
+
- `tst/mqtt-plus-8-run.spec.ts`: Run (error handling) utility tests
|
|
123
|
+
- `tst/tsc.std.json`: TypeScript configuration for the test directory (standard)
|
|
124
|
+
- `tst/tsc.cov.json`: TypeScript configuration for the test directory (coverage)
|
|
125
|
+
|
|
126
|
+
### Key Documentation Files
|
|
127
|
+
|
|
128
|
+
- `doc/mqtt-plus-api.md`: public API reference
|
|
129
|
+
- `doc/mqtt-plus-architecture.{d2,svg,md}`: architecture overview (diagram + docs)
|
|
130
|
+
- `doc/mqtt-plus-broker-setup.md`: MQTT broker setup guide
|
|
131
|
+
- `doc/mqtt-plus-comm.md`: communication patterns overview
|
|
132
|
+
- `doc/mqtt-plus-comm-event-emission.{d2,svg}`: Event Emission pattern diagram
|
|
133
|
+
- `doc/mqtt-plus-comm-service-call.{d2,svg}`: Service Call pattern diagram
|
|
134
|
+
- `doc/mqtt-plus-comm-sink-push.{d2,svg}`: Sink Push pattern diagram
|
|
135
|
+
- `doc/mqtt-plus-comm-source-fetch.{d2,svg}`: Source Fetch pattern diagram
|
|
136
|
+
- `doc/mqtt-plus-internals.md`: internal implementation details
|
|
147
137
|
|
|
148
138
|
### Type System
|
|
149
139
|
|
|
@@ -152,8 +142,7 @@ The API uses branded types (`Event<...>`, `Service<...>`, `Source<...>`,
|
|
|
152
142
|
type parameter threads through the trait tower, enabling full type
|
|
153
143
|
inference for pattern names and parameter types.
|
|
154
144
|
|
|
155
|
-
Coding Style
|
|
156
|
-
------------
|
|
145
|
+
## Coding Style
|
|
157
146
|
|
|
158
147
|
- 4-space indentation, double quotes, no semicolons
|
|
159
148
|
- Stroustrup brace style (`else`/`catch`/`finally` on new line after closing brace)
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
ChangeLog
|
|
3
3
|
=========
|
|
4
4
|
|
|
5
|
+
1.4.17 (2026-04-11)
|
|
6
|
+
-------------------
|
|
7
|
+
|
|
8
|
+
- IMPROVEMENT: add "signal" field to info of service and event callbacks for signalling abortion
|
|
9
|
+
- IMPROVEMENT: add more utility functions related to timers
|
|
10
|
+
- IMPROVEMENT: support cancelling push operations with a credit of zero
|
|
11
|
+
- IMPROVEMENT: let Spool.unroll() always execute the cleanup callback
|
|
12
|
+
- IMPROVEMENT: perform a minimum version check in the protocol
|
|
13
|
+
- IMPROVEMENT: log invalid requests with missing senders
|
|
14
|
+
- IMPROVEMENT: add upper bound for the nanoid iteration
|
|
15
|
+
- IMPROVEMENT: perform topic receiver matching and validate service response names
|
|
16
|
+
- IMPROVEMENT: move the destroyed flag to the base class and protect other methods
|
|
17
|
+
- IMPROVEMENT: send errors to peer and provide AggregateError to not lose errors
|
|
18
|
+
- IMPROVEMENT: bump minimum Node version to 20 for ES2022
|
|
19
|
+
- BUGFIX: Spool.unroll() silently skipped remaining cleanups on first async failure
|
|
20
|
+
- BUGFIX: improve semantics of info.authenticated field for event/service/sink/source in case of optional authentication
|
|
21
|
+
- BUGFIX: in the ReadableTee class, do not run read() twice: once ourself and once via the base class
|
|
22
|
+
- BUGFIX: correctly propagate description in run() also to finally callback
|
|
23
|
+
- BUGFIX: fix resource handling in source trait
|
|
24
|
+
- BUGFIX: avoid race conditions and unhandled promise rejections in async processing
|
|
25
|
+
- BUGFIX: fix cleanup and error handling across sink/source traits
|
|
26
|
+
- BUGFIX: fix Mosqitto ACL
|
|
27
|
+
- UPDATE: upgrade NPM dependencies
|
|
28
|
+
- CLEANUP: various code cleanups (callback handling, settle code, destroy handling, termination, subscriptions)
|
|
29
|
+
- CLEANUP: align with ensureError code and fix typos
|
|
30
|
+
|
|
5
31
|
1.4.16 (2026-03-27)
|
|
6
32
|
-------------------
|
|
7
33
|
|
package/README.md
CHANGED
|
@@ -165,7 +165,7 @@ Main documentation:
|
|
|
165
165
|
- [**Communication Patterns**](doc/mqtt-plus-comm.md)
|
|
166
166
|
- [**Application Programming Interface (API)**](doc/mqtt-plus-api.md)
|
|
167
167
|
|
|
168
|
-
Additional
|
|
168
|
+
Additional auxiliary documentation:
|
|
169
169
|
|
|
170
170
|
- [Extra: Architecture Overview](doc/mqtt-plus-architecture.md)
|
|
171
171
|
- [Extra: Internal Protocol](doc/mqtt-plus-internals.md)
|
package/doc/mqtt-plus-api.md
CHANGED
|
@@ -250,9 +250,10 @@ Register for an event.
|
|
|
250
250
|
- The optional `auth` enables authentication validation on incoming events.
|
|
251
251
|
When set to a role name string (e.g., `"admin"`), authentication is required
|
|
252
252
|
and the token must include that role. When set to an object `{ mode, roles }`,
|
|
253
|
-
the mode can be `"require"` (reject unauthenticated
|
|
254
|
-
|
|
255
|
-
the
|
|
253
|
+
the mode can be `"require"` (reject unauthenticated, so `info.authenticated`
|
|
254
|
+
is always `true` in the callback) or `"optional"` (accept all, but set
|
|
255
|
+
`info.authenticated` to `true` or `false` to reflect the validation result),
|
|
256
|
+
and roles specifies the required role names.
|
|
256
257
|
|
|
257
258
|
- Internally, on the MQTT broker, the topics generated by
|
|
258
259
|
`topicMake(name, "event-emission")` (default: `${name}/event-emission/any` and
|
|
@@ -380,9 +381,10 @@ Register a service.
|
|
|
380
381
|
- The optional `auth` enables authentication validation on incoming service calls.
|
|
381
382
|
When set to a role name string (e.g., `"admin"`), authentication is required
|
|
382
383
|
and the token must include that role. When set to an object `{ mode, roles }`,
|
|
383
|
-
the mode can be `"require"` (reject unauthenticated with error response
|
|
384
|
-
`
|
|
385
|
-
|
|
384
|
+
the mode can be `"require"` (reject unauthenticated with error response, so
|
|
385
|
+
`info.authenticated` is always `true` in the callback) or `"optional"` (accept
|
|
386
|
+
all, but set `info.authenticated` to `true` or `false` to reflect the validation
|
|
387
|
+
result), and roles specifies the required role names.
|
|
386
388
|
|
|
387
389
|
- Internally, on the MQTT broker, the topics generated by
|
|
388
390
|
`topicMake(name, "service-call-request")` (default: `${name}/service-call-request/any` and
|
|
@@ -471,6 +473,9 @@ Register a sink for receiving data.
|
|
|
471
473
|
The `info.buffer` provides a lazy `Promise<Uint8Array>` that resolves to the complete data once the stream ends.
|
|
472
474
|
The `info.signal` is aborted when the push request is cancelled, times out, or is otherwise torn down,
|
|
473
475
|
allowing the sink handler to stop any related side work cooperatively.
|
|
476
|
+
When the sink handler's stream closes abnormally (before normal completion),
|
|
477
|
+
a cancel signal (`credit=0`) is automatically sent to the pusher to abort
|
|
478
|
+
the data transfer on the sender side.
|
|
474
479
|
The `info.meta` contains optional metadata sent by the pusher via `push()`.
|
|
475
480
|
|
|
476
481
|
- The optional `options` allows setting MQTT.js `subscribe()` options like `qos`.
|
|
@@ -486,9 +491,10 @@ Register a sink for receiving data.
|
|
|
486
491
|
When set to a role name string (e.g., `"admin"`), authentication
|
|
487
492
|
is required and the token must include that role. When set to an
|
|
488
493
|
object `{ mode, roles }`, the mode can be `"require"` (reject
|
|
489
|
-
unauthenticated
|
|
490
|
-
|
|
491
|
-
|
|
494
|
+
unauthenticated, so `info.authenticated` is always `true` in the
|
|
495
|
+
callback) or `"optional"` (accept all, but set `info.authenticated`
|
|
496
|
+
to `true` or `false` to reflect the validation result), and roles
|
|
497
|
+
specifies the required role names.
|
|
492
498
|
|
|
493
499
|
- Internally, on the MQTT broker, the topics generated by
|
|
494
500
|
`topicMake(name, "sink-push-request")`
|
|
@@ -532,6 +538,8 @@ Pushes data to all established sinks or a specific sink handler.
|
|
|
532
538
|
configurable via `chunkSize` option) and sent over MQTT until the
|
|
533
539
|
stream is closed or the buffer is fully transferred.
|
|
534
540
|
The returned `Promise` resolves when the entire data has been pushed.
|
|
541
|
+
If the receiver cancels the push (via a cancel signal with `credit=0`),
|
|
542
|
+
the returned `Promise` rejects with a cancellation error.
|
|
535
543
|
|
|
536
544
|
- The remote `sink()` `callback` is called with `params` and an `info` object
|
|
537
545
|
containing `signal` (`AbortSignal`) for cooperative cancellation,
|
|
@@ -614,9 +622,10 @@ Register a source for sending data.
|
|
|
614
622
|
When set to a role name string (e.g., `"admin"`), authentication
|
|
615
623
|
is required and the token must include that role. When set to an
|
|
616
624
|
object `{ mode, roles }`, the mode can be `"require"` (reject
|
|
617
|
-
unauthenticated
|
|
618
|
-
|
|
619
|
-
|
|
625
|
+
unauthenticated, so `info.authenticated` is always `true` in the
|
|
626
|
+
callback) or `"optional"` (accept all, but set `info.authenticated`
|
|
627
|
+
to `true` or `false` to reflect the validation result), and roles
|
|
628
|
+
specifies the required role names.
|
|
620
629
|
|
|
621
630
|
- Internally, on the MQTT broker, the topics generated by
|
|
622
631
|
`topicMake(name, "source-fetch-request")`
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
MQTT+ Architecture
|
|
3
3
|
==================
|
|
4
4
|
|
|
5
|
-
**MQTT+** is composed as a vertical chain of API and
|
|
5
|
+
**MQTT+** is composed as a vertical chain of API and infrastructure trait
|
|
6
6
|
classes (mixins), each extending the previous. Additionally, some base
|
|
7
7
|
modules complement the functionality.
|
|
8
8
|
|
|
@@ -69,7 +69,7 @@ pattern read example/server/+/service-call-response/%c
|
|
|
69
69
|
|
|
70
70
|
topic read example/client/+/service-call-request/any
|
|
71
71
|
pattern read example/client/+/service-call-request/%c
|
|
72
|
-
pattern write example/client/+/service-call-response
|
|
72
|
+
pattern write example/client/+/service-call-response/+
|
|
73
73
|
|
|
74
74
|
# ---- source fetch ----
|
|
75
75
|
|
|
@@ -87,7 +87,7 @@ pattern read example/server/+/sink-push-response/%c
|
|
|
87
87
|
|
|
88
88
|
topic read example/client/+/sink-push-request/any
|
|
89
89
|
pattern read example/client/+/sink-push-request/%c
|
|
90
|
-
pattern write example/client/+/sink-push-response
|
|
90
|
+
pattern write example/client/+/sink-push-response/+
|
|
91
91
|
|
|
92
92
|
# ==== server/authenticated ACL ====
|
|
93
93
|
|
package/doc/mqtt-plus-comm.md
CHANGED
|
@@ -50,8 +50,9 @@ chunks as a stream with arguments.
|
|
|
50
50
|
> In contrast to the regular MQTT message publish/subscribe, this
|
|
51
51
|
> pattern allows to transfer arbitrary amounts of arbitrary data by
|
|
52
52
|
> chunking the data via a stream. Additionally, it supports authentication
|
|
53
|
-
> and meta-data,
|
|
54
|
-
> cooperative cancellation,
|
|
53
|
+
> and meta-data, provides an `AbortSignal` to the sink handler for
|
|
54
|
+
> cooperative cancellation, and allows the receiver to cancel an
|
|
55
|
+
> in-progress push via a cancel signal (`credit=0`), etc.
|
|
55
56
|
|
|
56
57
|

|
|
57
58
|
|
|
@@ -138,7 +138,7 @@ Exactly one of `result` or `error` is present.
|
|
|
138
138
|
| Field | Type | Required | Description |
|
|
139
139
|
|----------|-----------|----------|-------------------------------------|
|
|
140
140
|
| `name` | `string` | yes | Sink endpoint name |
|
|
141
|
-
| `credit` | `integer` | yes | Number of additional credits (min
|
|
141
|
+
| `credit` | `integer` | yes | Number of additional credits (min 0). A value of `0` is a **cancel signal**, indicating that the receiver wants to abort the push stream. |
|
|
142
142
|
|
|
143
143
|
### `source-fetch-request`
|
|
144
144
|
|
|
@@ -272,6 +272,16 @@ Setting `chunkCredit` to `0` disables flow control entirely.
|
|
|
272
272
|
| Sink Push | Sink | Pusher | `sink-push-credit` |
|
|
273
273
|
| Source Fetch | Fetcher | Source | `source-fetch-credit` |
|
|
274
274
|
|
|
275
|
+
### Receiver-Initiated Cancellation (Sink Push)
|
|
276
|
+
|
|
277
|
+
The sink (receiver) can cancel an in-progress push by sending a
|
|
278
|
+
`sink-push-credit` message with `credit` set to `0`. This acts as
|
|
279
|
+
a **cancel signal**: the pusher aborts the data transfer immediately
|
|
280
|
+
and does not send an error chunk back to the receiver (since the
|
|
281
|
+
cancellation originated from the receiver itself). On the receiver
|
|
282
|
+
side, the `AbortSignal` provided to the sink callback is triggered
|
|
283
|
+
when the push stream closes abnormally.
|
|
284
|
+
|
|
275
285
|
Authentication
|
|
276
286
|
--------------
|
|
277
287
|
|
|
@@ -86,16 +86,8 @@ export class AuthTrait extends MetaTrait {
|
|
|
86
86
|
async authenticated(clientId, tokens, option) {
|
|
87
87
|
let authenticated = false;
|
|
88
88
|
/* determine authentication configuration */
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (typeof option === "string") {
|
|
92
|
-
mode = "require";
|
|
93
|
-
roles = [option];
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
mode = option.mode;
|
|
97
|
-
roles = option.roles;
|
|
98
|
-
}
|
|
89
|
+
const roles = typeof option === "string"
|
|
90
|
+
? [option] : option.roles;
|
|
99
91
|
/* iterate over all roles and try to authenticate token (first-match, max 8) */
|
|
100
92
|
if (tokens !== undefined) {
|
|
101
93
|
for (const token of tokens.slice(0, 8)) {
|
|
@@ -120,9 +112,6 @@ export class AuthTrait extends MetaTrait {
|
|
|
120
112
|
break;
|
|
121
113
|
}
|
|
122
114
|
}
|
|
123
|
-
/* handle optional case */
|
|
124
|
-
if (!authenticated && mode === "optional")
|
|
125
|
-
authenticated = true;
|
|
126
115
|
return authenticated;
|
|
127
116
|
}
|
|
128
117
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mqtt-plus-auth.js","sourceRoot":"","sources":["../src/mqtt-plus-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;EAsBE;AAEF,6BAA6B;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAc,eAAe,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAY,iBAAiB,CAAA;AACjD,OAAO,KAAK,MAAM,MAAc,mBAAmB,CAAA;AACnD,OAAO,KAAK,MAAM,MAAc,mBAAmB,CAAA;AAInD,OAAO,EAAE,SAAS,EAAE,MAAY,kBAAkB,CAAA;AAQlD,iCAAiC;AACjC,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAA;AAErC,4BAA4B;AAC5B,MAAM,OAAO,SAA2C,SAAQ,SAAY;IAA5E;;QACI,sBAAsB;QACd,gBAAW,GAAsB,IAAI,CAAA;QACrC,YAAO,GAAG,IAAI,GAAG,EAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"mqtt-plus-auth.js","sourceRoot":"","sources":["../src/mqtt-plus-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,11 +6,12 @@ import { Spool } from "./mqtt-plus-error";
|
|
|
6
6
|
export declare class BaseTrait<T extends APISchema = APISchema> extends TraceTrait<T> {
|
|
7
7
|
private mqtt;
|
|
8
8
|
private messageHandler;
|
|
9
|
+
protected destroyed: boolean;
|
|
9
10
|
protected onRequest: Map<string, (message: any, topicName: string) => void | Promise<void>>;
|
|
10
11
|
protected onResponse: Map<string, (message: any, topicName: string) => void | Promise<void>>;
|
|
11
12
|
constructor(mqtt: MqttClient | null, options?: Partial<APIOptions>);
|
|
12
13
|
destroy(): Promise<void>;
|
|
13
|
-
protected makeRegistration(spool: Spool, kind: string, name: string
|
|
14
|
+
protected makeRegistration(spool: Spool, kind: string, name: string): Registration;
|
|
14
15
|
protected subscribeTopic(topic: string, options?: Partial<IClientSubscribeOptions>): Promise<void>;
|
|
15
16
|
protected unsubscribeTopic(topic: string): Promise<void>;
|
|
16
17
|
protected publishToTopic(topic: string, message: string | Uint8Array, options?: IClientPublishOptions): Promise<void>;
|
|
@@ -29,6 +29,8 @@ export class BaseTrait extends TraceTrait {
|
|
|
29
29
|
/* construct API class */
|
|
30
30
|
constructor(mqtt, options = {}) {
|
|
31
31
|
super(options);
|
|
32
|
+
/* lifecycle state */
|
|
33
|
+
this.destroyed = false;
|
|
32
34
|
/* central message callback registries */
|
|
33
35
|
this.onRequest = new Map();
|
|
34
36
|
this.onResponse = new Map();
|
|
@@ -75,17 +77,20 @@ export class BaseTrait extends TraceTrait {
|
|
|
75
77
|
}
|
|
76
78
|
/* destroy API class */
|
|
77
79
|
async destroy() {
|
|
80
|
+
this.destroyed = true;
|
|
78
81
|
this.log("info", "un-hooking from MQTT client");
|
|
79
82
|
this.mqtt.off("message", this.messageHandler);
|
|
80
83
|
this.onRequest.clear();
|
|
81
84
|
this.onResponse.clear();
|
|
82
85
|
}
|
|
83
86
|
/* create a registration for subsequent destruction */
|
|
84
|
-
makeRegistration(spool, kind, name
|
|
87
|
+
makeRegistration(spool, kind, name) {
|
|
88
|
+
let destroyed = false;
|
|
85
89
|
return {
|
|
86
90
|
destroy: async () => {
|
|
87
|
-
if (
|
|
88
|
-
|
|
91
|
+
if (destroyed)
|
|
92
|
+
return;
|
|
93
|
+
destroyed = true;
|
|
89
94
|
await spool.unroll(false)?.catch((err) => {
|
|
90
95
|
const error = ensureError(err, `destroy: ${kind} "${name}" failed to cleanup`);
|
|
91
96
|
this.error(error);
|
|
@@ -187,6 +192,12 @@ export class BaseTrait extends TraceTrait {
|
|
|
187
192
|
return;
|
|
188
193
|
}
|
|
189
194
|
this.log("debug", `received from MQTT topic "${topic}"`, { message });
|
|
195
|
+
/* warn on receiver mismatch on direct topics */
|
|
196
|
+
if (topicMatch.peerId !== undefined
|
|
197
|
+
&& message.receiver !== undefined
|
|
198
|
+
&& message.receiver !== topicMatch.peerId)
|
|
199
|
+
this.log("warning", `receiver mismatch on direct topic "${topic}"` +
|
|
200
|
+
` (expected "${topicMatch.peerId}", got "${message.receiver}")`);
|
|
190
201
|
/* dispatch MQTT+ message */
|
|
191
202
|
if (this.msg.isRequest(message)) {
|
|
192
203
|
/* dispatch request message */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mqtt-plus-base.js","sourceRoot":"","sources":["../src/mqtt-plus-base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;EAsBE;AAaF,OAAO,EAAE,UAAU,EAAE,MAAwB,mBAAmB,CAAA;AAChE,OAAO,EAAS,WAAW,EAAE,MAAgB,mBAAmB,CAAA;AAChE,OAAO,EAAE,KAAK,EAAE,MAA6B,kBAAkB,CAAA;AAE/D,mDAAmD;AACnD,MAAM,OAAO,SAA2C,SAAQ,UAAa;
|
|
1
|
+
{"version":3,"file":"mqtt-plus-base.js","sourceRoot":"","sources":["../src/mqtt-plus-base.ts"],"names":[],"mappings":"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"}
|