@matter/nodejs 0.16.0-alpha.0-20251006-3fe1e7c57 → 0.16.0-alpha.0-20251013-89bb7099d

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 (60) hide show
  1. package/dist/cjs/config.d.ts +1 -1
  2. package/dist/cjs/config.js +1 -1
  3. package/dist/cjs/environment/NodeJsEnvironment.d.ts +2 -0
  4. package/dist/cjs/environment/NodeJsEnvironment.d.ts.map +1 -1
  5. package/dist/cjs/environment/NodeJsEnvironment.js +15 -3
  6. package/dist/cjs/environment/NodeJsEnvironment.js.map +1 -1
  7. package/dist/cjs/environment/ProcessManager.d.ts +1 -0
  8. package/dist/cjs/environment/ProcessManager.d.ts.map +1 -1
  9. package/dist/cjs/environment/ProcessManager.js +8 -0
  10. package/dist/cjs/environment/ProcessManager.js.map +1 -1
  11. package/dist/cjs/net/NodeJsHttpEndpoint.d.ts +42 -0
  12. package/dist/cjs/net/NodeJsHttpEndpoint.d.ts.map +1 -0
  13. package/dist/cjs/net/NodeJsHttpEndpoint.js +304 -0
  14. package/dist/cjs/net/NodeJsHttpEndpoint.js.map +6 -0
  15. package/dist/cjs/net/NodeJsUdpChannel.d.ts +1 -1
  16. package/dist/cjs/net/NodeJsUdpChannel.d.ts.map +1 -1
  17. package/dist/cjs/net/NodeJsUdpChannel.js +31 -3
  18. package/dist/cjs/net/NodeJsUdpChannel.js.map +1 -1
  19. package/dist/cjs/net/WsAdapter.d.ts +25 -0
  20. package/dist/cjs/net/WsAdapter.d.ts.map +1 -0
  21. package/dist/cjs/net/WsAdapter.js +33 -0
  22. package/dist/cjs/net/WsAdapter.js.map +6 -0
  23. package/dist/cjs/net/index.d.ts +2 -0
  24. package/dist/cjs/net/index.d.ts.map +1 -1
  25. package/dist/cjs/net/index.js +2 -0
  26. package/dist/cjs/net/index.js.map +1 -1
  27. package/dist/esm/config.d.ts +1 -1
  28. package/dist/esm/config.js +1 -1
  29. package/dist/esm/environment/NodeJsEnvironment.d.ts +2 -0
  30. package/dist/esm/environment/NodeJsEnvironment.d.ts.map +1 -1
  31. package/dist/esm/environment/NodeJsEnvironment.js +16 -3
  32. package/dist/esm/environment/NodeJsEnvironment.js.map +1 -1
  33. package/dist/esm/environment/ProcessManager.d.ts +1 -0
  34. package/dist/esm/environment/ProcessManager.d.ts.map +1 -1
  35. package/dist/esm/environment/ProcessManager.js +8 -0
  36. package/dist/esm/environment/ProcessManager.js.map +1 -1
  37. package/dist/esm/net/NodeJsHttpEndpoint.d.ts +42 -0
  38. package/dist/esm/net/NodeJsHttpEndpoint.d.ts.map +1 -0
  39. package/dist/esm/net/NodeJsHttpEndpoint.js +284 -0
  40. package/dist/esm/net/NodeJsHttpEndpoint.js.map +6 -0
  41. package/dist/esm/net/NodeJsUdpChannel.d.ts +1 -1
  42. package/dist/esm/net/NodeJsUdpChannel.d.ts.map +1 -1
  43. package/dist/esm/net/NodeJsUdpChannel.js +34 -3
  44. package/dist/esm/net/NodeJsUdpChannel.js.map +1 -1
  45. package/dist/esm/net/WsAdapter.d.ts +25 -0
  46. package/dist/esm/net/WsAdapter.d.ts.map +1 -0
  47. package/dist/esm/net/WsAdapter.js +13 -0
  48. package/dist/esm/net/WsAdapter.js.map +6 -0
  49. package/dist/esm/net/index.d.ts +2 -0
  50. package/dist/esm/net/index.d.ts.map +1 -1
  51. package/dist/esm/net/index.js +2 -0
  52. package/dist/esm/net/index.js.map +1 -1
  53. package/package.json +10 -10
  54. package/src/config.ts +1 -1
  55. package/src/environment/NodeJsEnvironment.ts +21 -3
  56. package/src/environment/ProcessManager.ts +12 -0
  57. package/src/net/NodeJsHttpEndpoint.ts +358 -0
  58. package/src/net/NodeJsUdpChannel.ts +42 -3
  59. package/src/net/WsAdapter.ts +30 -0
  60. package/src/net/index.ts +2 -0
@@ -4,10 +4,13 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  import {
7
+ AddressInUseError,
8
+ BindError,
7
9
  Bytes,
8
10
  ChannelType,
9
11
  createPromise,
10
12
  Diagnostic,
13
+ ImplementationError,
11
14
  isIPv4,
12
15
  isIPv6,
13
16
  Logger,
@@ -31,7 +34,20 @@ function createDgramSocket(host, port, options) {
31
34
  try {
32
35
  socket.close();
33
36
  } catch (error2) {
34
- logger.debug("Error closing socket", error2);
37
+ logger.debug("Error closing socket:", error2);
38
+ }
39
+ const code = error?.code;
40
+ let desc = `${host ? host : options.type === "udp4" ? "0.0.0.0" : "{::}"}`;
41
+ if (port !== void 0) {
42
+ desc = `${desc}:${port}`;
43
+ }
44
+ switch (code) {
45
+ case "EADDRINUSE":
46
+ error = new AddressInUseError(`Cannot bind ${desc} because port is already in use`);
47
+ break;
48
+ default:
49
+ error = new BindError(`Cannot bind to ${desc} (code ${code})`);
50
+ break;
35
51
  }
36
52
  reject(error);
37
53
  };
@@ -55,11 +71,26 @@ class NodeJsUdpChannel {
55
71
  #type;
56
72
  #socket;
57
73
  #netInterface;
58
- static async create({ listeningPort, type, listeningAddress, netInterface }) {
59
- const socketOptions = { type, reuseAddr: true };
74
+ static async create({ listeningPort, type, listeningAddress, netInterface, reuseAddress }) {
75
+ let dgramType;
76
+ switch (type) {
77
+ case "udp":
78
+ case "udp6":
79
+ dgramType = "udp6";
80
+ break;
81
+ case "udp4":
82
+ dgramType = "udp4";
83
+ break;
84
+ default:
85
+ throw new ImplementationError(`Unrecognized UDP socket type ${type}`);
86
+ }
87
+ const socketOptions = { type: dgramType };
60
88
  if (type === "udp6") {
61
89
  socketOptions.ipv6Only = true;
62
90
  }
91
+ if (reuseAddress) {
92
+ socketOptions.reuseAddr = true;
93
+ }
63
94
  const socket = await createDgramSocket(listeningAddress, listeningPort, socketOptions);
64
95
  socket.setBroadcast(true);
65
96
  let netInterfaceZone;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/net/NodeJsUdpChannel.ts"],
4
- "mappings": "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",
4
+ "mappings": "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",
5
5
  "names": ["error"]
6
6
  }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { HttpEndpoint } from "#general";
7
+ import { IncomingMessage } from "node:http";
8
+ import { Duplex } from "node:stream";
9
+ /**
10
+ * This is a pluggable component that handles the upgrade to a WsConnection.
11
+ *
12
+ * We do not implement directly here because Node.js does not support WebSocket servers natively, so we must use a
13
+ * third-party dependency.
14
+ */
15
+ export interface WsAdapter {
16
+ handle(req: IncomingMessage, socket: Duplex, head: Buffer): Promise<HttpEndpoint.WsConnection>;
17
+ close(): Promise<void>;
18
+ }
19
+ export declare namespace WsAdapter {
20
+ let defaultFactory: undefined | Factory;
21
+ interface Factory {
22
+ (): WsAdapter;
23
+ }
24
+ }
25
+ //# sourceMappingURL=WsAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WsAdapter.d.ts","sourceRoot":"","sources":["../../../src/net/WsAdapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACtB,MAAM,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;IAC/F,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,yBAAiB,SAAS,CAAC;IAEhB,IAAI,cAAc,EAAgB,SAAS,GAAG,OAAO,CAAC;IAE7D,UAAiB,OAAO;QACpB,IAAI,SAAS,CAAC;KACjB;CACJ"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ var WsAdapter;
7
+ ((WsAdapter2) => {
8
+ WsAdapter2.defaultFactory = void 0;
9
+ })(WsAdapter || (WsAdapter = {}));
10
+ export {
11
+ WsAdapter
12
+ };
13
+ //# sourceMappingURL=WsAdapter.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/net/WsAdapter.ts"],
4
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAsBO,IAAU;AAAA,CAAV,CAAUA,eAAV;AAEI,EAAIA,WAAA,iBAAiB;AAAA,GAFf;",
5
+ "names": ["WsAdapter"]
6
+ }
@@ -3,6 +3,8 @@
3
3
  * Copyright 2022-2025 Matter.js Authors
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
+ export * from "./NodeJsHttpEndpoint.js";
6
7
  export * from "./NodeJsNetwork.js";
7
8
  export * from "./NodeJsUdpChannel.js";
9
+ export * from "./WsAdapter.js";
8
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/net/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/net/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC"}
@@ -3,6 +3,8 @@
3
3
  * Copyright 2022-2025 Matter.js Authors
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
+ export * from "./NodeJsHttpEndpoint.js";
6
7
  export * from "./NodeJsNetwork.js";
7
8
  export * from "./NodeJsUdpChannel.js";
9
+ export * from "./WsAdapter.js";
8
10
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/net/index.ts"],
4
- "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,cAAc;AACd,cAAc;",
4
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
5
5
  "names": []
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matter/nodejs",
3
- "version": "0.16.0-alpha.0-20251006-3fe1e7c57",
3
+ "version": "0.16.0-alpha.0-20251013-89bb7099d",
4
4
  "description": "Node.js platform support for matter.js",
5
5
  "keywords": [
6
6
  "iot",
@@ -44,17 +44,17 @@
44
44
  "#*": "./src/*"
45
45
  },
46
46
  "dependencies": {
47
- "@matter/general": "0.16.0-alpha.0-20251006-3fe1e7c57",
48
- "@matter/node": "0.16.0-alpha.0-20251006-3fe1e7c57",
49
- "@matter/protocol": "0.16.0-alpha.0-20251006-3fe1e7c57",
50
- "@matter/types": "0.16.0-alpha.0-20251006-3fe1e7c57"
47
+ "@matter/general": "0.16.0-alpha.0-20251013-89bb7099d",
48
+ "@matter/node": "0.16.0-alpha.0-20251013-89bb7099d",
49
+ "@matter/protocol": "0.16.0-alpha.0-20251013-89bb7099d",
50
+ "@matter/types": "0.16.0-alpha.0-20251013-89bb7099d"
51
51
  },
52
52
  "devDependencies": {
53
- "@matter/model": "0.16.0-alpha.0-20251006-3fe1e7c57",
54
- "@matter/protocol": "0.16.0-alpha.0-20251006-3fe1e7c57",
55
- "@matter/tools": "0.16.0-alpha.0-20251006-3fe1e7c57",
56
- "@matter/testing": "0.16.0-alpha.0-20251006-3fe1e7c57",
57
- "@project-chip/matter.js": "0.16.0-alpha.0-20251006-3fe1e7c57",
53
+ "@matter/model": "0.16.0-alpha.0-20251013-89bb7099d",
54
+ "@matter/protocol": "0.16.0-alpha.0-20251013-89bb7099d",
55
+ "@matter/testing": "0.16.0-alpha.0-20251013-89bb7099d",
56
+ "@matter/tools": "0.16.0-alpha.0-20251013-89bb7099d",
57
+ "@project-chip/matter.js": "0.16.0-alpha.0-20251013-89bb7099d",
58
58
  "@types/bytebuffer": "^5.0.49"
59
59
  },
60
60
  "files": [
package/src/config.ts CHANGED
@@ -164,7 +164,7 @@ export const config = {
164
164
  },
165
165
 
166
166
  /**
167
- * Enables handling of SIGINT, SIGTERM and SIGUSR2 (depending on platform; default: true).
167
+ * Enables handling of SIGINT, SIGTERM, SIGUSR2 and SIGABRT (depending on platform; default: true).
168
168
  */
169
169
  get trapProcessSignals() {
170
170
  return trapProcessSignals;
@@ -11,6 +11,7 @@ import {
11
11
  Boot,
12
12
  Crypto,
13
13
  Environment,
14
+ HttpEndpointFactory,
14
15
  ImplementationError,
15
16
  LogFormat,
16
17
  Logger,
@@ -19,6 +20,7 @@ import {
19
20
  StorageService,
20
21
  VariableService,
21
22
  } from "#general";
23
+ import { NodeJsHttpEndpoint } from "#net/NodeJsHttpEndpoint.js";
22
24
  import { existsSync, readFileSync } from "node:fs";
23
25
  import { writeFile } from "node:fs/promises";
24
26
  import { resolve } from "node:path";
@@ -65,6 +67,8 @@ import { ProcessManager } from "./ProcessManager.js";
65
67
  * * `runtime.signals` - By default register SIGINT and SIGUSR2 (diag) handlers, set to false if not wanted
66
68
  * * `runtime.exitcode` - By default we set the process.exitcode to 0 (ok) or 1 (crash); set to false to disable
67
69
  * * `runtime.unhandlederrors` - By default we log unhandled errors to matter.js log; set to false to disable
70
+ *
71
+ * TODO - this should go away. Node.js services should register with {@link ServiceBundle.default}
68
72
  */
69
73
  export function NodeJsEnvironment() {
70
74
  const env = new Environment("default");
@@ -127,6 +131,11 @@ function loadVariables(env: Environment) {
127
131
  };
128
132
  }
129
133
 
134
+ function rootDirOf(env: Environment) {
135
+ // path.root should always be set when this is called so the "." fallback should not be used
136
+ return env.vars.get("path.root", ".");
137
+ }
138
+
130
139
  function configureCrypto(env: Environment) {
131
140
  Boot.init(() => {
132
141
  if (config.installCrypto || (env.vars.boolean("nodejs.crypto") ?? true)) {
@@ -144,9 +153,16 @@ function configureNetwork(env: Environment) {
144
153
 
145
154
  Boot.init(() => {
146
155
  if (config.installNetwork || (env.vars.boolean("nodejs.network") ?? true)) {
156
+ const basePathForUnixSockets = rootDirOf(env);
147
157
  env.set(Network, new NodeJsNetwork());
148
- } else if (Environment.default.has(Network)) {
149
- env.set(Network, Environment.default.get(Network));
158
+ env.set(HttpEndpointFactory, new NodeJsHttpEndpoint.Factory(basePathForUnixSockets));
159
+ } else {
160
+ if (Environment.default.has(Network)) {
161
+ env.set(Network, Environment.default.get(Network));
162
+ }
163
+ if (Environment.default.has(HttpEndpointFactory)) {
164
+ env.set(HttpEndpointFactory, Environment.default.get(HttpEndpointFactory));
165
+ }
150
166
  }
151
167
  });
152
168
  }
@@ -164,11 +180,13 @@ function configureStorage(env: Environment) {
164
180
  const service = env.get(StorageService);
165
181
 
166
182
  env.vars.use(() => {
167
- service.location = env.vars.get("storage.path", env.vars.get("path.root", "."));
183
+ service.location = env.vars.get("storage.path", rootDirOf(env));
168
184
  });
169
185
 
170
186
  service.factory = namespace =>
171
187
  new StorageBackendDisk(resolve(service.location ?? ".", namespace), env.vars.get("storage.clear", false));
188
+
189
+ service.resolve = (...paths) => resolve(rootDirOf(env), ...paths);
172
190
  }
173
191
 
174
192
  export function loadConfigFile(vars: VariableService) {
@@ -110,6 +110,16 @@ export class ProcessManager implements Destructable {
110
110
  this.runtime.interrupt();
111
111
  };
112
112
 
113
+ protected abortHandler = () => {
114
+ this.uninstallInterruptHandlers();
115
+
116
+ logger.fatal("Terminating due to SIGABRT of JS runtime, diagnostics follow");
117
+ logger.info(JSON.stringify(process.report.getReport(), undefined, 2));
118
+
119
+ // Arbitrary code that kind of looks like standard SIGABRT exit code of -6
120
+ process.exit(-66);
121
+ };
122
+
113
123
  protected exitHandler = () => {
114
124
  if (process.exitCode === 13) {
115
125
  logger.error("Internal error: Premature process exit because ongoing work has stalled");
@@ -123,11 +133,13 @@ export class ProcessManager implements Destructable {
123
133
  protected installInterruptHandlers = () => {
124
134
  process.on("SIGINT", this.interruptHandler);
125
135
  process.on("SIGTERM", this.interruptHandler);
136
+ process.on("SIGABRT", this.abortHandler);
126
137
  };
127
138
 
128
139
  protected uninstallInterruptHandlers = () => {
129
140
  process.off("SIGINT", this.interruptHandler);
130
141
  process.off("SIGTERM", this.interruptHandler);
142
+ process.off("SIGABRT", this.abortHandler);
131
143
  };
132
144
 
133
145
  #ignoreSignals() {
@@ -0,0 +1,358 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { AppAddress, asError, HttpEndpoint, HttpEndpointFactory, Logger, NetworkError } from "#general";
8
+ import { existsSync, ReadStream, rmSync, statSync } from "node:fs";
9
+ import { createServer, IncomingMessage, Server, ServerResponse } from "node:http";
10
+ import { ListenOptions } from "node:net";
11
+ import { normalize, resolve } from "node:path";
12
+ import { Duplex } from "node:stream";
13
+
14
+ // Node's ReadableStream type definition do not exactly match the standard version so we need to import to support casts
15
+ import type { ReadableStream as NodeReadableStream } from "node:stream/web";
16
+ import { WsAdapter } from "./WsAdapter.js";
17
+
18
+ const logger = new Logger("NodeJsHttpEndpoint");
19
+
20
+ /**
21
+ * An implementation of {@link HttpEndpoint} that uses Node.js's standard {@link Server}.
22
+ *
23
+ * WebSocket support is optional. You can install by importing `@matter/nodejs-ws`.
24
+ *
25
+ * This implementation is a little ugly because the native Node.js HTTP server API is pre-async and has some design
26
+ * flaws. Other runtimes tend build on WinterTC standards and adapters will be much simpler.
27
+ */
28
+ export class NodeJsHttpEndpoint implements HttpEndpoint {
29
+ #server: Server;
30
+ #ready: Promise<void>;
31
+ #http?: HttpEndpoint.HttpHandler;
32
+ #httpListener?: (req: IncomingMessage, res: ServerResponse) => void;
33
+ #ws?: HttpEndpoint.WsHandler;
34
+ #wsListener?: (req: IncomingMessage, socket: Duplex, head: Buffer) => void;
35
+ #notFound: (res: ServerResponse) => void;
36
+
37
+ #wsAdapter?: WsAdapter;
38
+ #wsAdapterFactory?: WsAdapter.Factory;
39
+
40
+ static async create(options: NodeJsHttpEndpoint.Options): Promise<NodeJsHttpEndpoint> {
41
+ const endpoint = new NodeJsHttpEndpoint(options);
42
+ await endpoint.ready;
43
+ return endpoint;
44
+ }
45
+
46
+ /**
47
+ * Create a new endpoint.
48
+ *
49
+ * You may pass an existing {@link Server} or pass {@link NodeJsHttpEndpoint.Options} to create a server dedicated
50
+ * to this endpoint.
51
+ */
52
+ constructor(optionsOrServer: Server | NodeJsHttpEndpoint.Options) {
53
+ let close, ready, server, notFound;
54
+
55
+ if ("on" in optionsOrServer) {
56
+ ({ close, ready, server, notFound } = this.#bindToServer(optionsOrServer));
57
+ } else {
58
+ ({ close, ready, server, notFound } = this.#createDedicatedServer(optionsOrServer));
59
+ }
60
+
61
+ this.#server = server;
62
+ this.#ready = ready;
63
+ this.close = close;
64
+ this.#notFound = notFound;
65
+ }
66
+
67
+ get server() {
68
+ return this.#server;
69
+ }
70
+
71
+ #bindToServer(server: Server) {
72
+ return {
73
+ server,
74
+ ready: Promise.resolve(),
75
+ close: async () => {
76
+ this.http = undefined;
77
+ this.ws = undefined;
78
+ },
79
+ notFound: () => undefined,
80
+ };
81
+ }
82
+
83
+ #createDedicatedServer(options: NodeJsHttpEndpoint.Options) {
84
+ const server = createServer({ keepAlive: true });
85
+
86
+ const opts = {} as ListenOptions;
87
+
88
+ const address = AppAddress.for(options.address);
89
+ const { transport } = address;
90
+ switch (transport.kind) {
91
+ case "ip":
92
+ if (!address.isWildcardHost) {
93
+ opts.host = address.host;
94
+ }
95
+ if (!address.isWildcardPort) {
96
+ opts.port = address.portNum;
97
+ }
98
+ break;
99
+
100
+ case "unix":
101
+ const path = decodeURIComponent(address.hostname);
102
+ if (options.basePathForUnixSockets) {
103
+ opts.path = resolve(options.basePathForUnixSockets, normalize(path));
104
+ } else {
105
+ opts.path = normalize(path);
106
+ }
107
+ if (existsSync(opts.path)) {
108
+ if (statSync(opts.path).isSocket()) {
109
+ try {
110
+ rmSync(opts.path);
111
+ } catch (e) {
112
+ throw new NetworkError(
113
+ `Error deleting previous socket at ${opts.path}: ${asError(e).message}`,
114
+ );
115
+ }
116
+ } else {
117
+ throw new NetworkError(`UNIX socket path ${opts.path} exists and is not a socket`);
118
+ }
119
+ }
120
+ break;
121
+
122
+ default:
123
+ throw new NetworkError(
124
+ `Unsupported address type "${(options.address as any)?.type}" for HTTP endpoint`,
125
+ );
126
+ }
127
+
128
+ server.listen(opts);
129
+
130
+ return {
131
+ server,
132
+
133
+ ready: new Promise<void>((resolve, reject) => {
134
+ let settled = false;
135
+ server.once("listening", () => {
136
+ if (settled) {
137
+ return;
138
+ }
139
+
140
+ settled = true;
141
+ resolve();
142
+ });
143
+ server.on("error", error => {
144
+ if (settled) {
145
+ logger.warn("HTTP server error:", error.message);
146
+ return;
147
+ }
148
+
149
+ settled = true;
150
+ reject(error);
151
+ });
152
+ }),
153
+
154
+ close: async () => {
155
+ return new Promise<void>((resolve, reject) => {
156
+ server.close(err => {
157
+ if (err) {
158
+ reject(err);
159
+ return;
160
+ }
161
+
162
+ resolve();
163
+ });
164
+ });
165
+ },
166
+
167
+ notFound: (res: ServerResponse) => respondError(res, 404),
168
+ };
169
+ }
170
+
171
+ get ready() {
172
+ return this.#ready;
173
+ }
174
+
175
+ set http(handler: HttpEndpoint.HttpHandler | undefined) {
176
+ this.#http = handler;
177
+
178
+ if (!this.#http) {
179
+ if (this.#httpListener) {
180
+ this.#server.off("request", this.#httpListener);
181
+ }
182
+ return;
183
+ }
184
+
185
+ if (this.#httpListener) {
186
+ return;
187
+ }
188
+
189
+ this.#httpListener = (req, res) => {
190
+ this.#handleHttp(req, res).catch(error => {
191
+ logger.error("Unhandled error in HTTP endpoint handler", error);
192
+ respondError(res, 500);
193
+ });
194
+ };
195
+
196
+ this.#server.on("request", this.#httpListener);
197
+ }
198
+
199
+ set ws(handler: HttpEndpoint.WsHandler | undefined) {
200
+ this.#ws = handler;
201
+
202
+ if (!this.#ws) {
203
+ if (this.#wsListener) {
204
+ this.#server.off("upgrade", this.#wsListener);
205
+ }
206
+ return;
207
+ }
208
+
209
+ let adapter = this.#wsAdapter;
210
+ if (!adapter) {
211
+ const factory = this.#wsAdapterFactory ?? WsAdapter.defaultFactory;
212
+ if (!factory) {
213
+ logger.warn(
214
+ "WebSocket support disabled because no adapter is installed; please import @matter/nodejs-ws or equivalent",
215
+ );
216
+ return;
217
+ }
218
+ adapter = this.#wsAdapter = factory();
219
+ }
220
+
221
+ this.#wsListener = (req, socket, head) => {
222
+ this.#handleUpgrade(adapter, req, socket, head).catch(error => {
223
+ logger.error("Unhandled error WebSocket endpoint", error);
224
+ });
225
+ };
226
+
227
+ this.#server.on("upgrade", this.#wsListener);
228
+ }
229
+
230
+ close: () => Promise<void>;
231
+
232
+ async #handleHttp(req: IncomingMessage, res: ServerResponse) {
233
+ if (!this.#http) {
234
+ return;
235
+ }
236
+
237
+ const request = new NodeJsHttpRequest(req);
238
+
239
+ const response = await this.#http(request);
240
+ if (!response) {
241
+ this.#notFound(res);
242
+ return;
243
+ }
244
+
245
+ res.statusCode = response.status;
246
+ res.statusMessage = response.statusText;
247
+
248
+ response.headers.forEach(([name, value]) => res.appendHeader(name, value));
249
+
250
+ if (response.body === null) {
251
+ res.end();
252
+ return;
253
+ }
254
+
255
+ const nodeBodyStream = ReadStream.fromWeb(response.body as NodeReadableStream);
256
+
257
+ nodeBodyStream.on("error", error => {
258
+ logger.error("Error transmitting HTTP body", error);
259
+ respondError(res, 500);
260
+ });
261
+
262
+ nodeBodyStream.pipe(res);
263
+ }
264
+
265
+ async #handleUpgrade(adapter: WsAdapter, req: IncomingMessage, socket: Duplex, head: Buffer) {
266
+ if (req.headers.upgrade !== "websocket") {
267
+ // Not clear how to send a 426 with Node's API
268
+ socket.destroy();
269
+ return;
270
+ }
271
+
272
+ // This shouldn't happen
273
+ if (!this.#ws) {
274
+ socket.destroy();
275
+ return;
276
+ }
277
+
278
+ const request = new NodeJsHttpRequest(req);
279
+
280
+ try {
281
+ await this.#ws(request, async () => {
282
+ return adapter.handle(req, socket, head);
283
+ });
284
+ } finally {
285
+ // Node API is fairly broken and offers no way to indicate we've skipped the socket so we must destroy it
286
+ // if not already handled
287
+ if (!socket.destroyed) {
288
+ socket.destroy();
289
+ }
290
+ }
291
+ }
292
+ }
293
+
294
+ class NodeJsHttpRequest extends Request {
295
+ constructor(message: IncomingMessage) {
296
+ const { method, rawHeaders } = message;
297
+
298
+ const url = `http://${message.headers.host ?? "unknown"}${message.url ?? "/"}`;
299
+
300
+ const headers = new Headers();
301
+
302
+ for (let i = 0; i < message.rawHeaders.length; i += 2) {
303
+ headers.append(rawHeaders[i], rawHeaders[i + 1]);
304
+ }
305
+
306
+ const init = {
307
+ method,
308
+ headers,
309
+ duplex: "half", // Not in RequestInit type but required by node
310
+ } as RequestInit;
311
+
312
+ if (method !== "GET" && method !== "HEAD") {
313
+ init.body = IncomingMessage.toWeb(message) as ReadableStream;
314
+ }
315
+
316
+ super(url, init);
317
+ }
318
+ }
319
+
320
+ function respondError(res: ServerResponse, code: number) {
321
+ if (res.closed) {
322
+ return;
323
+ }
324
+
325
+ try {
326
+ if (!res.headersSent) {
327
+ res.statusCode = code;
328
+ res.setHeader("Content-Type", "text/plain");
329
+ res.end(`HTTP error ${code}\n`);
330
+ } else {
331
+ res.end();
332
+ }
333
+ } catch (e) {
334
+ logger.warn(`Error conveying ${code} error:`, asError(e).message);
335
+ }
336
+ }
337
+
338
+ export namespace NodeJsHttpEndpoint {
339
+ export interface Options extends HttpEndpoint.Options {
340
+ basePathForUnixSockets?: string;
341
+ }
342
+
343
+ export class Factory extends HttpEndpointFactory {
344
+ #basePathForUnixSockets?: string;
345
+
346
+ constructor(basePathForUnixSockets?: string) {
347
+ super();
348
+ this.#basePathForUnixSockets = basePathForUnixSockets;
349
+ }
350
+
351
+ async create(options: HttpEndpoint.Options) {
352
+ return NodeJsHttpEndpoint.create({
353
+ basePathForUnixSockets: this.#basePathForUnixSockets,
354
+ ...options,
355
+ });
356
+ }
357
+ }
358
+ }