@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.
Files changed (51) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +9 -0
  3. package/dist/cjs/MqttJsEndpoint.d.ts +18 -0
  4. package/dist/cjs/MqttJsEndpoint.d.ts.map +1 -0
  5. package/dist/cjs/MqttJsEndpoint.js +100 -0
  6. package/dist/cjs/MqttJsEndpoint.js.map +6 -0
  7. package/dist/cjs/MqttJsEndpointFactory.d.ts +14 -0
  8. package/dist/cjs/MqttJsEndpointFactory.d.ts.map +1 -0
  9. package/dist/cjs/MqttJsEndpointFactory.js +83 -0
  10. package/dist/cjs/MqttJsEndpointFactory.js.map +6 -0
  11. package/dist/cjs/MqttJsMessage.d.ts +16 -0
  12. package/dist/cjs/MqttJsMessage.d.ts.map +1 -0
  13. package/dist/cjs/MqttJsMessage.js +83 -0
  14. package/dist/cjs/MqttJsMessage.js.map +6 -0
  15. package/dist/cjs/index.d.ts +8 -0
  16. package/dist/cjs/index.d.ts.map +1 -0
  17. package/dist/cjs/index.js +25 -0
  18. package/dist/cjs/index.js.map +6 -0
  19. package/dist/cjs/install.d.ts +7 -0
  20. package/dist/cjs/install.d.ts.map +1 -0
  21. package/dist/cjs/install.js +10 -0
  22. package/dist/cjs/install.js.map +6 -0
  23. package/dist/cjs/package.json +6 -0
  24. package/dist/esm/MqttJsEndpoint.d.ts +18 -0
  25. package/dist/esm/MqttJsEndpoint.d.ts.map +1 -0
  26. package/dist/esm/MqttJsEndpoint.js +80 -0
  27. package/dist/esm/MqttJsEndpoint.js.map +6 -0
  28. package/dist/esm/MqttJsEndpointFactory.d.ts +14 -0
  29. package/dist/esm/MqttJsEndpointFactory.d.ts.map +1 -0
  30. package/dist/esm/MqttJsEndpointFactory.js +63 -0
  31. package/dist/esm/MqttJsEndpointFactory.js.map +6 -0
  32. package/dist/esm/MqttJsMessage.d.ts +16 -0
  33. package/dist/esm/MqttJsMessage.d.ts.map +1 -0
  34. package/dist/esm/MqttJsMessage.js +63 -0
  35. package/dist/esm/MqttJsMessage.js.map +6 -0
  36. package/dist/esm/index.d.ts +8 -0
  37. package/dist/esm/index.d.ts.map +1 -0
  38. package/dist/esm/index.js +8 -0
  39. package/dist/esm/index.js.map +6 -0
  40. package/dist/esm/install.d.ts +7 -0
  41. package/dist/esm/install.d.ts.map +1 -0
  42. package/dist/esm/install.js +9 -0
  43. package/dist/esm/install.js.map +6 -0
  44. package/dist/esm/package.json +6 -0
  45. package/package.json +74 -0
  46. package/src/MqttJsEndpoint.ts +99 -0
  47. package/src/MqttJsEndpointFactory.ts +75 -0
  48. package/src/MqttJsMessage.ts +73 -0
  49. package/src/index.ts +9 -0
  50. package/src/install.ts +10 -0
  51. 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,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export * from "./MqttJsEndpointFactory.js";
7
+ import "./install.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -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,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export * from "./MqttJsEndpointFactory.js";
7
+ import "./install.js";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/index.ts"],
4
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,cAAc;AAEd,OAAO;",
5
+ "names": []
6
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=install.d.ts.map
@@ -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
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/install.ts"],
4
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,qBAAqB,qBAAqB;AACnD,SAAS,6BAA6B;AAEtC,cAAc,QAAQ,IAAI,SAAO,IAAI,IAAI,qBAAqB,IAAI,sBAAsB,CAAC,CAAC;",
5
+ "names": []
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "type": "module",
3
+ "imports": {
4
+ "#general": "@matter/general"
5
+ }
6
+ }
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
+ }