@matter/mqtt 0.16.0-alpha.0-20251011-d8942d7d5
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/LICENSE +201 -0
- package/README.md +9 -0
- package/dist/cjs/MqttJsEndpoint.d.ts +18 -0
- package/dist/cjs/MqttJsEndpoint.d.ts.map +1 -0
- package/dist/cjs/MqttJsEndpoint.js +100 -0
- package/dist/cjs/MqttJsEndpoint.js.map +6 -0
- package/dist/cjs/MqttJsEndpointFactory.d.ts +14 -0
- package/dist/cjs/MqttJsEndpointFactory.d.ts.map +1 -0
- package/dist/cjs/MqttJsEndpointFactory.js +83 -0
- package/dist/cjs/MqttJsEndpointFactory.js.map +6 -0
- package/dist/cjs/MqttJsMessage.d.ts +16 -0
- package/dist/cjs/MqttJsMessage.d.ts.map +1 -0
- package/dist/cjs/MqttJsMessage.js +83 -0
- package/dist/cjs/MqttJsMessage.js.map +6 -0
- package/dist/cjs/index.d.ts +8 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +25 -0
- package/dist/cjs/index.js.map +6 -0
- package/dist/cjs/install.d.ts +7 -0
- package/dist/cjs/install.d.ts.map +1 -0
- package/dist/cjs/install.js +10 -0
- package/dist/cjs/install.js.map +6 -0
- package/dist/cjs/package.json +6 -0
- package/dist/esm/MqttJsEndpoint.d.ts +18 -0
- package/dist/esm/MqttJsEndpoint.d.ts.map +1 -0
- package/dist/esm/MqttJsEndpoint.js +80 -0
- package/dist/esm/MqttJsEndpoint.js.map +6 -0
- package/dist/esm/MqttJsEndpointFactory.d.ts +14 -0
- package/dist/esm/MqttJsEndpointFactory.d.ts.map +1 -0
- package/dist/esm/MqttJsEndpointFactory.js +63 -0
- package/dist/esm/MqttJsEndpointFactory.js.map +6 -0
- package/dist/esm/MqttJsMessage.d.ts +16 -0
- package/dist/esm/MqttJsMessage.d.ts.map +1 -0
- package/dist/esm/MqttJsMessage.js +63 -0
- package/dist/esm/MqttJsMessage.js.map +6 -0
- package/dist/esm/index.d.ts +8 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/index.js.map +6 -0
- package/dist/esm/install.d.ts +7 -0
- package/dist/esm/install.d.ts.map +1 -0
- package/dist/esm/install.js +9 -0
- package/dist/esm/install.js.map +6 -0
- package/dist/esm/package.json +6 -0
- package/package.json +74 -0
- package/src/MqttJsEndpoint.ts +99 -0
- package/src/MqttJsEndpointFactory.ts +75 -0
- package/src/MqttJsMessage.ts +73 -0
- package/src/index.ts +9 -0
- package/src/install.ts +10 -0
- package/src/tsconfig.json +16 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { MqttEndpoint } from "#general";
|
|
7
|
+
import { MqttClient } from "mqtt";
|
|
8
|
+
/**
|
|
9
|
+
* MQTT.js-based MQTT endpoint.
|
|
10
|
+
*/
|
|
11
|
+
export declare class MqttJsEndpoint implements MqttEndpoint {
|
|
12
|
+
#private;
|
|
13
|
+
constructor(client: MqttClient, options: MqttEndpoint.ConnectionOptions);
|
|
14
|
+
subscribe(topic: string, options?: MqttEndpoint.SubscriptionOptions): AsyncIterableIterator<MqttEndpoint.Message>;
|
|
15
|
+
publish(message: MqttEndpoint.Message): Promise<void>;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=MqttJsEndpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MqttJsEndpoint.d.ts","sourceRoot":"","sources":["../../src/MqttJsEndpoint.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAe,YAAY,EAAS,MAAM,UAAU,CAAC;AAC5D,OAAO,EAAsC,UAAU,EAAqB,MAAM,MAAM,CAAC;AAGzF;;GAEG;AACH,qBAAa,cAAe,YAAW,YAAY;;gBAKnC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,CAAC,iBAAiB;IAiBhE,SAAS,CACZ,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,YAAY,CAAC,mBAAmB,GAC3C,qBAAqB,CAAC,YAAY,CAAC,OAAO,CAAC;IAmDxC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrD,KAAK;CAId"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { Abort, Gate, Mutex } from "#general";
|
|
7
|
+
import { MqttJsMessage } from "./MqttJsMessage.js";
|
|
8
|
+
class MqttJsEndpoint {
|
|
9
|
+
#client;
|
|
10
|
+
#nextSubscriptionIdentifier = 1;
|
|
11
|
+
#mutex = new Mutex(this);
|
|
12
|
+
constructor(client, options) {
|
|
13
|
+
this.#client = client;
|
|
14
|
+
const { onUp, onDown } = options;
|
|
15
|
+
if (onUp) {
|
|
16
|
+
const onConnect = () => this.#mutex.run(async () => onUp(this));
|
|
17
|
+
queueMicrotask(onConnect);
|
|
18
|
+
this.#client.on("connect", () => this.#mutex.run(async () => onUp(this)));
|
|
19
|
+
}
|
|
20
|
+
if (onDown) {
|
|
21
|
+
this.#client.on("offline", () => this.#mutex.run(async () => onDown(this)));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async *subscribe(topic, options) {
|
|
25
|
+
const subscriptionIdentifier = this.#nextSubscriptionIdentifier++;
|
|
26
|
+
const queue = new Array();
|
|
27
|
+
const gate = new Gate();
|
|
28
|
+
let grants;
|
|
29
|
+
try {
|
|
30
|
+
this.#client.on("message", onMessage);
|
|
31
|
+
grants = await this.#client.subscribeAsync(topic, {
|
|
32
|
+
nl: options?.noLocal ?? true,
|
|
33
|
+
properties: {
|
|
34
|
+
subscriptionIdentifier
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
while (true) {
|
|
38
|
+
await Abort.race(options?.abort, gate);
|
|
39
|
+
if (Abort.is(options?.abort)) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
while (true) {
|
|
43
|
+
const message = queue.shift();
|
|
44
|
+
if (message === void 0) {
|
|
45
|
+
gate.close();
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
yield message;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} finally {
|
|
52
|
+
this.#client.off("message", onMessage);
|
|
53
|
+
if (grants && !(this.#client.disconnecting || this.#client.disconnected)) {
|
|
54
|
+
for (const grant of grants) {
|
|
55
|
+
await this.#client.unsubscribeAsync(grant.topic);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function onMessage(_topic, _payload, packet) {
|
|
60
|
+
if (packet.properties?.subscriptionIdentifier !== subscriptionIdentifier) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
queue.push(MqttJsMessage.decode(packet));
|
|
64
|
+
gate.open();
|
|
65
|
+
}
|
|
66
|
+
onMessage;
|
|
67
|
+
}
|
|
68
|
+
async publish(message) {
|
|
69
|
+
const { topic, payload, options } = MqttJsMessage.encode(message);
|
|
70
|
+
await this.#client.publishAsync(topic, payload, options);
|
|
71
|
+
}
|
|
72
|
+
async close() {
|
|
73
|
+
await this.#client.endAsync();
|
|
74
|
+
await this.#mutex.then();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
MqttJsEndpoint
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=MqttJsEndpoint.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/MqttJsEndpoint.ts"],
|
|
4
|
+
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,OAAO,MAAoB,aAAa;AAEjD,SAAS,qBAAqB;AAKvB,MAAM,eAAuC;AAAA,EAChD;AAAA,EACA,8BAA8B;AAAA,EAC9B,SAAS,IAAI,MAAM,IAAI;AAAA,EAEvB,YAAY,QAAoB,SAAyC;AACrE,SAAK,UAAU;AAEf,UAAM,EAAE,MAAM,OAAO,IAAI;AAEzB,QAAI,MAAM;AACN,YAAM,YAAY,MAAM,KAAK,OAAO,IAAI,YAAY,KAAK,IAAI,CAAC;AAE9D,qBAAe,SAAS;AACxB,WAAK,QAAQ,GAAG,WAAW,MAAM,KAAK,OAAO,IAAI,YAAY,KAAK,IAAI,CAAC,CAAC;AAAA,IAC5E;AAEA,QAAI,QAAQ;AACR,WAAK,QAAQ,GAAG,WAAW,MAAM,KAAK,OAAO,IAAI,YAAY,OAAO,IAAI,CAAC,CAAC;AAAA,IAC9E;AAAA,EACJ;AAAA,EAEA,OAAO,UACH,OACA,SAC2C;AAC3C,UAAM,yBAAyB,KAAK;AAEpC,UAAM,QAAQ,IAAI,MAA4B;AAC9C,UAAM,OAAO,IAAI,KAAK;AAEtB,QAAI;AACJ,QAAI;AACA,WAAK,QAAQ,GAAG,WAAW,SAAS;AACpC,eAAS,MAAM,KAAK,QAAQ,eAAe,OAAO;AAAA,QAC9C,IAAI,SAAS,WAAW;AAAA,QACxB,YAAY;AAAA,UACR;AAAA,QACJ;AAAA,MACJ,CAAC;AAED,aAAO,MAAM;AACT,cAAM,MAAM,KAAK,SAAS,OAAO,IAAI;AACrC,YAAI,MAAM,GAAG,SAAS,KAAK,GAAG;AAC1B;AAAA,QACJ;AAEA,eAAO,MAAM;AACT,gBAAM,UAAU,MAAM,MAAM;AAC5B,cAAI,YAAY,QAAW;AACvB,iBAAK,MAAM;AACX;AAAA,UACJ;AACA,gBAAM;AAAA,QACV;AAAA,MACJ;AAAA,IACJ,UAAE;AACE,WAAK,QAAQ,IAAI,WAAW,SAAS;AACrC,UAAI,UAAU,EAAE,KAAK,QAAQ,iBAAiB,KAAK,QAAQ,eAAe;AACtE,mBAAW,SAAS,QAAQ;AACxB,gBAAM,KAAK,QAAQ,iBAAiB,MAAM,KAAK;AAAA,QACnD;AAAA,MACJ;AAAA,IACJ;AAEA,aAAS,UAAU,QAAiB,UAAmB,QAAwB;AAC3E,UAAI,OAAO,YAAY,2BAA2B,wBAAwB;AACtE;AAAA,MACJ;AACA,YAAM,KAAK,cAAc,OAAO,MAAM,CAAC;AACvC,WAAK,KAAK;AAAA,IACd;AAEA;AAAA,EACJ;AAAA,EAEA,MAAM,QAAQ,SAA8C;AACxD,UAAM,EAAE,OAAO,SAAS,QAAQ,IAAI,cAAc,OAAO,OAAO;AAChE,UAAM,KAAK,QAAQ,aAAa,OAAO,SAAS,OAAO;AAAA,EAC3D;AAAA,EAEA,MAAM,QAAQ;AACV,UAAM,KAAK,QAAQ,SAAS;AAC5B,UAAM,KAAK,OAAO,KAAK;AAAA,EAC3B;AACJ;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { MqttEndpoint, MqttEndpointFactory } from "#general";
|
|
7
|
+
import { MqttJsEndpoint } from "./MqttJsEndpoint.js";
|
|
8
|
+
/**
|
|
9
|
+
* MQTT.js-based MQTT implementation.
|
|
10
|
+
*/
|
|
11
|
+
export declare class MqttJsEndpointFactory extends MqttEndpointFactory {
|
|
12
|
+
connect(options: MqttEndpoint.ConnectionOptions): Promise<MqttJsEndpoint>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=MqttJsEndpointFactory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MqttJsEndpointFactory.d.ts","sourceRoot":"","sources":["../../src/MqttJsEndpointFactory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAmC,YAAY,EAAE,mBAAmB,EAAkB,MAAM,UAAU,CAAC;AAE9G,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,mBAAmB;IAC3C,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,iBAAiB;CA2DjE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { AppAddress, ImplementationError, MqttEndpointFactory, StorageService } from "#general";
|
|
7
|
+
import { connectAsync } from "mqtt";
|
|
8
|
+
import { MqttJsEndpoint } from "./MqttJsEndpoint.js";
|
|
9
|
+
import { MqttJsMessage } from "./MqttJsMessage.js";
|
|
10
|
+
class MqttJsEndpointFactory extends MqttEndpointFactory {
|
|
11
|
+
async connect(options) {
|
|
12
|
+
const addr = AppAddress.for(options.address);
|
|
13
|
+
const opts = {
|
|
14
|
+
protocolVersion: 5
|
|
15
|
+
};
|
|
16
|
+
if (addr.protocolModifiers.includes("ws")) {
|
|
17
|
+
opts.protocol = "ws";
|
|
18
|
+
opts.path = addr.pathname;
|
|
19
|
+
} else {
|
|
20
|
+
opts.protocol = "mqtt";
|
|
21
|
+
}
|
|
22
|
+
if (addr.isTls) {
|
|
23
|
+
opts.protocol += "s";
|
|
24
|
+
}
|
|
25
|
+
const transport = addr.transport;
|
|
26
|
+
switch (transport.kind) {
|
|
27
|
+
case "ip":
|
|
28
|
+
opts.hostname = addr.hostname;
|
|
29
|
+
if (addr.port) {
|
|
30
|
+
opts.port = Number(addr.port);
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
case "unix":
|
|
34
|
+
opts.protocol += "+unix";
|
|
35
|
+
opts.unixSocket = true;
|
|
36
|
+
opts.path = decodeURIComponent(addr.hostname);
|
|
37
|
+
const storage = options.environment?.get(StorageService);
|
|
38
|
+
if (storage) {
|
|
39
|
+
opts.path = storage.resolve(opts.path);
|
|
40
|
+
}
|
|
41
|
+
break;
|
|
42
|
+
default:
|
|
43
|
+
throw new ImplementationError(
|
|
44
|
+
`Unknown transport address kind ${transport.kind}`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (addr.username) {
|
|
48
|
+
opts.username = addr.username;
|
|
49
|
+
}
|
|
50
|
+
if (addr.password) {
|
|
51
|
+
opts.password = addr.password;
|
|
52
|
+
}
|
|
53
|
+
if (options.will) {
|
|
54
|
+
opts.will = MqttJsMessage.encode(options.will);
|
|
55
|
+
}
|
|
56
|
+
const client = await connectAsync(opts);
|
|
57
|
+
return new MqttJsEndpoint(client, options);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
MqttJsEndpointFactory
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=MqttJsEndpointFactory.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/MqttJsEndpointFactory.ts"],
|
|
4
|
+
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,YAAY,qBAAmC,qBAAqB,sBAAsB;AACnG,SAAS,oBAAoC;AAC7C,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAKvB,MAAM,8BAA8B,oBAAoB;AAAA,EAC3D,MAAe,QAAQ,SAAyC;AAC5D,UAAM,OAAO,WAAW,IAAI,QAAQ,OAAO;AAC3C,UAAM,OAAuB;AAAA,MACzB,iBAAiB;AAAA,IACrB;AAEA,QAAI,KAAK,kBAAkB,SAAS,IAAI,GAAG;AACvC,WAAK,WAAW;AAGhB,WAAK,OAAO,KAAK;AAAA,IACrB,OAAO;AACH,WAAK,WAAW;AAAA,IACpB;AAEA,QAAI,KAAK,OAAO;AACZ,WAAK,YAAY;AAAA,IACrB;AAEA,UAAM,YAAY,KAAK;AACvB,YAAQ,UAAU,MAAM;AAAA,MACpB,KAAK;AACD,aAAK,WAAW,KAAK;AACrB,YAAI,KAAK,MAAM;AACX,eAAK,OAAO,OAAO,KAAK,IAAI;AAAA,QAChC;AACA;AAAA,MAEJ,KAAK;AACD,aAAK,YAAY;AACjB,aAAK,aAAa;AAClB,aAAK,OAAO,mBAAmB,KAAK,QAAQ;AAC5C,cAAM,UAAU,QAAQ,aAAa,IAAI,cAAc;AACvD,YAAI,SAAS;AACT,eAAK,OAAO,QAAQ,QAAQ,KAAK,IAAI;AAAA,QACzC;AACA;AAAA,MAEJ;AACI,cAAM,IAAI;AAAA,UACN,kCAAmC,UAA0C,IAAI;AAAA,QACrF;AAAA,IACR;AAEA,QAAI,KAAK,UAAU;AACf,WAAK,WAAW,KAAK;AAAA,IACzB;AACA,QAAI,KAAK,UAAU;AACf,WAAK,WAAW,KAAK;AAAA,IACzB;AAEA,QAAI,QAAQ,MAAM;AACd,WAAK,OAAO,cAAc,OAAO,QAAQ,IAAI;AAAA,IACjD;AAEA,UAAM,SAAS,MAAM,aAAa,IAAI;AAEtC,WAAO,IAAI,eAAe,QAAQ,OAAO;AAAA,EAC7C;AACJ;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { MqttEndpoint } from "#general";
|
|
7
|
+
import { IClientPublishOptions, IPublishPacket } from "mqtt";
|
|
8
|
+
export declare namespace MqttJsMessage {
|
|
9
|
+
function encode(message: MqttEndpoint.Message): {
|
|
10
|
+
topic: string;
|
|
11
|
+
payload: string | Buffer;
|
|
12
|
+
options?: IClientPublishOptions;
|
|
13
|
+
};
|
|
14
|
+
function decode(message: IPublishPacket): MqttEndpoint.Message;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=MqttJsMessage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MqttJsMessage.d.ts","sourceRoot":"","sources":["../../src/MqttJsMessage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAS,YAAY,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAQ7D,yBAAiB,aAAa,CAAC;IAC3B,SAAgB,MAAM,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,GAAG;QACnD,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;QACzB,OAAO,CAAC,EAAE,qBAAqB,CAAC;KACnC,CA6BA;IAED,SAAgB,MAAM,CAAC,OAAO,EAAE,cAAc,GAAG,YAAY,CAAC,OAAO,CAUpE;CACJ"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { Bytes } from "#general";
|
|
7
|
+
import { Buffer as SafeBuffer } from "safe-buffer";
|
|
8
|
+
const Buffer = globalThis.Buffer ?? SafeBuffer;
|
|
9
|
+
const empty = Buffer.alloc(0);
|
|
10
|
+
var MqttJsMessage;
|
|
11
|
+
((MqttJsMessage2) => {
|
|
12
|
+
function encode(message) {
|
|
13
|
+
let payload, payloadFormatIndicator;
|
|
14
|
+
if (message.payload === null) {
|
|
15
|
+
payload = empty;
|
|
16
|
+
payloadFormatIndicator = false;
|
|
17
|
+
} else if (Bytes.isBytes(message.payload)) {
|
|
18
|
+
payload = bytesToBuffer(message.payload);
|
|
19
|
+
payloadFormatIndicator = false;
|
|
20
|
+
} else {
|
|
21
|
+
payload = message.payload;
|
|
22
|
+
payloadFormatIndicator = true;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
topic: message.topic,
|
|
26
|
+
payload,
|
|
27
|
+
options: {
|
|
28
|
+
qos: message.qos,
|
|
29
|
+
retain: message.retain,
|
|
30
|
+
properties: {
|
|
31
|
+
payloadFormatIndicator,
|
|
32
|
+
contentType: message.contentType,
|
|
33
|
+
correlationData: message.correlationData && bytesToBuffer(message.correlationData),
|
|
34
|
+
responseTopic: message.responseTopic
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
MqttJsMessage2.encode = encode;
|
|
40
|
+
function decode(message) {
|
|
41
|
+
return {
|
|
42
|
+
topic: message.topic,
|
|
43
|
+
payload: message.payload.length ? message.payload : null,
|
|
44
|
+
qos: message.qos,
|
|
45
|
+
retain: message.retain,
|
|
46
|
+
contentType: message.properties?.contentType,
|
|
47
|
+
correlationData: message.properties?.correlationData,
|
|
48
|
+
responseTopic: message.properties?.responseTopic
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
MqttJsMessage2.decode = decode;
|
|
52
|
+
})(MqttJsMessage || (MqttJsMessage = {}));
|
|
53
|
+
function bytesToBuffer(bytes) {
|
|
54
|
+
bytes = Bytes.exclusive(bytes);
|
|
55
|
+
if (bytes instanceof ArrayBuffer) {
|
|
56
|
+
return Buffer.from(bytes);
|
|
57
|
+
}
|
|
58
|
+
return Buffer.from(bytes.buffer, bytes.byteLength, bytes.byteOffset);
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
MqttJsMessage
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=MqttJsMessage.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/MqttJsMessage.ts"],
|
|
4
|
+
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,aAA2B;AAEpC,SAAS,UAAU,kBAAkB;AAIrC,MAAM,SAAS,WAAW,UAAU;AACpC,MAAM,QAAQ,OAAO,MAAM,CAAC;AAErB,IAAU;AAAA,CAAV,CAAUA,mBAAV;AACI,WAAS,OAAO,SAIrB;AACE,QAAI,SAA0B;AAC9B,QAAI,QAAQ,YAAY,MAAM;AAC1B,gBAAU;AACV,+BAAyB;AAAA,IAC7B,WAAW,MAAM,QAAQ,QAAQ,OAAO,GAAG;AACvC,gBAAU,cAAc,QAAQ,OAAO;AACvC,+BAAyB;AAAA,IAC7B,OAAO;AACH,gBAAU,QAAQ;AAClB,+BAAyB;AAAA,IAC7B;AAEA,WAAO;AAAA,MACH,OAAO,QAAQ;AAAA,MACf;AAAA,MAEA,SAAS;AAAA,QACL,KAAK,QAAQ;AAAA,QACb,QAAQ,QAAQ;AAAA,QAEhB,YAAY;AAAA,UACR;AAAA,UACA,aAAa,QAAQ;AAAA,UACrB,iBAAiB,QAAQ,mBAAmB,cAAc,QAAQ,eAAe;AAAA,UACjF,eAAe,QAAQ;AAAA,QAC3B;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAjCO,EAAAA,eAAS;AAmCT,WAAS,OAAO,SAA+C;AAClE,WAAO;AAAA,MACH,OAAO,QAAQ;AAAA,MACf,SAAS,QAAQ,QAAQ,SAAS,QAAQ,UAAU;AAAA,MACpD,KAAK,QAAQ;AAAA,MACb,QAAQ,QAAQ;AAAA,MAChB,aAAa,QAAQ,YAAY;AAAA,MACjC,iBAAiB,QAAQ,YAAY;AAAA,MACrC,eAAe,QAAQ,YAAY;AAAA,IACvC;AAAA,EACJ;AAVO,EAAAA,eAAS;AAAA,GApCH;AAiDjB,SAAS,cAAc,OAAc;AACjC,UAAQ,MAAM,UAAU,KAAK;AAE7B,MAAI,iBAAiB,aAAa;AAC9B,WAAO,OAAO,KAAK,KAAK;AAAA,EAC5B;AAEA,SAAO,OAAO,KAAK,MAAM,QAAQ,MAAM,YAAY,MAAM,UAAU;AACvE;",
|
|
5
|
+
"names": ["MqttJsMessage"]
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,4BAA4B,CAAC;AAE3C,OAAO,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/install.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { MqttEndpointFactory, ServiceBundle } from "#general";
|
|
7
|
+
import { MqttJsEndpointFactory } from "./MqttJsEndpointFactory.js";
|
|
8
|
+
ServiceBundle.default.add((env) => env.set(MqttEndpointFactory, new MqttJsEndpointFactory()));
|
|
9
|
+
//# sourceMappingURL=install.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@matter/mqtt",
|
|
3
|
+
"version": "0.16.0-alpha.0-20251011-d8942d7d5",
|
|
4
|
+
"description": "matter.js MQTT support",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"iot",
|
|
7
|
+
"home automation",
|
|
8
|
+
"matter",
|
|
9
|
+
"smart device",
|
|
10
|
+
"MQTT"
|
|
11
|
+
],
|
|
12
|
+
"license": "Apache-2.0",
|
|
13
|
+
"author": "matter.js authors",
|
|
14
|
+
"contributors": [
|
|
15
|
+
"Greg Lauckhart <greg@lauckhart.com>"
|
|
16
|
+
],
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/matter-js/matter.js/issues"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/matter-js/matter.js",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/matter-js/matter.js.git"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"clean": "matter-build clean",
|
|
27
|
+
"build": "matter-build",
|
|
28
|
+
"build-clean": "matter-build --clean"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@matter/general": "0.16.0-alpha.0-20251011-d8942d7d5",
|
|
32
|
+
"mqtt": "^5.14.1",
|
|
33
|
+
"safe-buffer": "^5.2.1"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@matter/tools": "0.16.0-alpha.0-20251011-d8942d7d5"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20.19.0 <22.0.0 || >=22.13.0"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist/**/*",
|
|
43
|
+
"src/**/*",
|
|
44
|
+
"LICENSE"
|
|
45
|
+
],
|
|
46
|
+
"imports": {
|
|
47
|
+
"#general": "@matter/general"
|
|
48
|
+
},
|
|
49
|
+
"type": "module",
|
|
50
|
+
"main": "dist/cjs/index.js",
|
|
51
|
+
"types": "dist/cjs/index.d.ts",
|
|
52
|
+
"exports": {
|
|
53
|
+
".": {
|
|
54
|
+
"import": {
|
|
55
|
+
"types": "./dist/esm/index.d.ts",
|
|
56
|
+
"default": "./dist/esm/index.js"
|
|
57
|
+
},
|
|
58
|
+
"require": {
|
|
59
|
+
"types": "./dist/cjs/index.d.ts",
|
|
60
|
+
"default": "./dist/cjs/index.js"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"typesVersions": {
|
|
65
|
+
"*": {
|
|
66
|
+
".": [
|
|
67
|
+
"/dist/cjs/index.d.ts"
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"publishConfig": {
|
|
72
|
+
"access": "public"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Abort, Gate, MqttEndpoint, Mutex } from "#general";
|
|
8
|
+
import { IPublishPacket, ISubscriptionGrant, MqttClient, OnMessageCallback } from "mqtt";
|
|
9
|
+
import { MqttJsMessage } from "./MqttJsMessage.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* MQTT.js-based MQTT endpoint.
|
|
13
|
+
*/
|
|
14
|
+
export class MqttJsEndpoint implements MqttEndpoint {
|
|
15
|
+
#client: MqttClient;
|
|
16
|
+
#nextSubscriptionIdentifier = 1;
|
|
17
|
+
#mutex = new Mutex(this);
|
|
18
|
+
|
|
19
|
+
constructor(client: MqttClient, options: MqttEndpoint.ConnectionOptions) {
|
|
20
|
+
this.#client = client;
|
|
21
|
+
|
|
22
|
+
const { onUp, onDown } = options;
|
|
23
|
+
|
|
24
|
+
if (onUp) {
|
|
25
|
+
const onConnect = () => this.#mutex.run(async () => onUp(this));
|
|
26
|
+
|
|
27
|
+
queueMicrotask(onConnect);
|
|
28
|
+
this.#client.on("connect", () => this.#mutex.run(async () => onUp(this)));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (onDown) {
|
|
32
|
+
this.#client.on("offline", () => this.#mutex.run(async () => onDown(this)));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async *subscribe(
|
|
37
|
+
topic: string,
|
|
38
|
+
options?: MqttEndpoint.SubscriptionOptions,
|
|
39
|
+
): AsyncIterableIterator<MqttEndpoint.Message> {
|
|
40
|
+
const subscriptionIdentifier = this.#nextSubscriptionIdentifier++;
|
|
41
|
+
|
|
42
|
+
const queue = new Array<MqttEndpoint.Message>();
|
|
43
|
+
const gate = new Gate();
|
|
44
|
+
|
|
45
|
+
let grants: ISubscriptionGrant[] | undefined;
|
|
46
|
+
try {
|
|
47
|
+
this.#client.on("message", onMessage);
|
|
48
|
+
grants = await this.#client.subscribeAsync(topic, {
|
|
49
|
+
nl: options?.noLocal ?? true,
|
|
50
|
+
properties: {
|
|
51
|
+
subscriptionIdentifier,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
while (true) {
|
|
56
|
+
await Abort.race(options?.abort, gate);
|
|
57
|
+
if (Abort.is(options?.abort)) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
while (true) {
|
|
62
|
+
const message = queue.shift();
|
|
63
|
+
if (message === undefined) {
|
|
64
|
+
gate.close();
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
yield message;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
} finally {
|
|
71
|
+
this.#client.off("message", onMessage);
|
|
72
|
+
if (grants && !(this.#client.disconnecting || this.#client.disconnected)) {
|
|
73
|
+
for (const grant of grants) {
|
|
74
|
+
await this.#client.unsubscribeAsync(grant.topic);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function onMessage(_topic: unknown, _payload: unknown, packet: IPublishPacket) {
|
|
80
|
+
if (packet.properties?.subscriptionIdentifier !== subscriptionIdentifier) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
queue.push(MqttJsMessage.decode(packet));
|
|
84
|
+
gate.open();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
onMessage satisfies OnMessageCallback;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async publish(message: MqttEndpoint.Message): Promise<void> {
|
|
91
|
+
const { topic, payload, options } = MqttJsMessage.encode(message);
|
|
92
|
+
await this.#client.publishAsync(topic, payload, options);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async close() {
|
|
96
|
+
await this.#client.endAsync();
|
|
97
|
+
await this.#mutex.then();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { AppAddress, ImplementationError, MqttEndpoint, MqttEndpointFactory, StorageService } from "#general";
|
|
8
|
+
import { connectAsync, IClientOptions } from "mqtt";
|
|
9
|
+
import { MqttJsEndpoint } from "./MqttJsEndpoint.js";
|
|
10
|
+
import { MqttJsMessage } from "./MqttJsMessage.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* MQTT.js-based MQTT implementation.
|
|
14
|
+
*/
|
|
15
|
+
export class MqttJsEndpointFactory extends MqttEndpointFactory {
|
|
16
|
+
override async connect(options: MqttEndpoint.ConnectionOptions) {
|
|
17
|
+
const addr = AppAddress.for(options.address);
|
|
18
|
+
const opts: IClientOptions = {
|
|
19
|
+
protocolVersion: 5,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
if (addr.protocolModifiers.includes("ws")) {
|
|
23
|
+
opts.protocol = "ws";
|
|
24
|
+
// This conflicts for WS + UNIX socket but that's an MQTT.js problem and likely not a real-world issue since
|
|
25
|
+
// MQTT over WS is generally for browsers
|
|
26
|
+
opts.path = addr.pathname;
|
|
27
|
+
} else {
|
|
28
|
+
opts.protocol = "mqtt";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (addr.isTls) {
|
|
32
|
+
opts.protocol += "s";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const transport = addr.transport;
|
|
36
|
+
switch (transport.kind) {
|
|
37
|
+
case "ip":
|
|
38
|
+
opts.hostname = addr.hostname;
|
|
39
|
+
if (addr.port) {
|
|
40
|
+
opts.port = Number(addr.port);
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
|
|
44
|
+
case "unix":
|
|
45
|
+
opts.protocol += "+unix";
|
|
46
|
+
opts.unixSocket = true;
|
|
47
|
+
opts.path = decodeURIComponent(addr.hostname);
|
|
48
|
+
const storage = options.environment?.get(StorageService);
|
|
49
|
+
if (storage) {
|
|
50
|
+
opts.path = storage.resolve(opts.path);
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
|
|
54
|
+
default:
|
|
55
|
+
throw new ImplementationError(
|
|
56
|
+
`Unknown transport address kind ${(transport as AppAddress.TransportAddress).kind}`,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (addr.username) {
|
|
61
|
+
opts.username = addr.username;
|
|
62
|
+
}
|
|
63
|
+
if (addr.password) {
|
|
64
|
+
opts.password = addr.password;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (options.will) {
|
|
68
|
+
opts.will = MqttJsMessage.encode(options.will);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const client = await connectAsync(opts);
|
|
72
|
+
|
|
73
|
+
return new MqttJsEndpoint(client, options);
|
|
74
|
+
}
|
|
75
|
+
}
|