@weborigami/origami 0.6.13 → 0.6.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weborigami/origami",
3
- "version": "0.6.13",
3
+ "version": "0.6.14",
4
4
  "description": "Web Origami language, CLI, framework, and server",
5
5
  "type": "module",
6
6
  "repository": {
@@ -18,9 +18,9 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@hpcc-js/wasm-graphviz": "^1.21.0",
21
- "@weborigami/async-tree": "0.6.13",
21
+ "@weborigami/async-tree": "0.6.14",
22
22
  "@weborigami/json-feed-to-rss": "1.0.1",
23
- "@weborigami/language": "0.6.13",
23
+ "@weborigami/language": "0.6.14",
24
24
  "css-tree": "3.1.0",
25
25
  "highlight.js": "11.11.1",
26
26
  "jsdom": "28.1.0",
@@ -1,10 +1,11 @@
1
1
  import { OrigamiFileMap } from "@weborigami/language";
2
2
  import { fork } from "node:child_process";
3
3
  import http from "node:http";
4
+ import net from "node:net";
4
5
  import path from "node:path";
5
6
 
6
7
  const PUBLIC_HOST = "127.0.0.1";
7
- const PUBLIC_PORT = 5000;
8
+ const DEFAULT_PORT = 5000;
8
9
 
9
10
  // Module that loads the server in the child process
10
11
  const childModuleUrl = new URL("./debugChild.js", import.meta.url);
@@ -74,12 +75,14 @@ export default async function debug2(code, state) {
74
75
  }
75
76
  });
76
77
 
78
+ const port = await findOpenPort(PUBLIC_HOST);
79
+
77
80
  // ---- Public server
78
81
  const publicServer = http.createServer(proxyRequest);
79
- publicServer.listen(PUBLIC_PORT, PUBLIC_HOST, () => {
82
+ publicServer.listen(port, PUBLIC_HOST, () => {
80
83
  startChild(serverOptions);
81
84
  console.log(
82
- `Server running at http://localhost:${PUBLIC_PORT}. Press Ctrl+C to stop.`,
85
+ `Server running at http://localhost:${port}. Press Ctrl+C to stop.`,
83
86
  );
84
87
  });
85
88
  }
@@ -142,6 +145,18 @@ async function drainAndStopChild(childProcess) {
142
145
  }, GRACE_MS).unref();
143
146
  }
144
147
 
148
+ // Return the first open port number on or after the given port number.
149
+ async function findOpenPort(host, startPort = DEFAULT_PORT) {
150
+ for (let port = startPort; port <= 65535; port++) {
151
+ const open = await isPortAvailable(host, port);
152
+ if (open) {
153
+ return port;
154
+ }
155
+ }
156
+
157
+ throw new Error(`No open port found on or after ${startPort}`);
158
+ }
159
+
145
160
  function isJavaScriptFile(filePath) {
146
161
  const extname = path.extname(filePath).toLowerCase();
147
162
  const jsExtensions = [".cjs", ".js", ".mjs", ".ts"];
@@ -152,6 +167,40 @@ function isPackageJsonFile(filePath) {
152
167
  return path.basename(filePath).toLowerCase() === "package.json";
153
168
  }
154
169
 
170
+ /**
171
+ * Check whether a TCP port can be bound.
172
+ *
173
+ * @param {string} host
174
+ * @param {number} port
175
+ * @returns {Promise<boolean>}
176
+ */
177
+ async function isPortAvailable(host, port) {
178
+ return new Promise((resolve) => {
179
+ const server = net.createServer();
180
+
181
+ server.unref();
182
+
183
+ server.once("error", (/** @type {any} */ error) => {
184
+ // Port is unavailable or cannot be bound on this host.
185
+ if (
186
+ error.code === "EADDRINUSE" ||
187
+ error.code === "EACCES" ||
188
+ error.code === "EADDRNOTAVAIL"
189
+ ) {
190
+ resolve(false);
191
+ } else {
192
+ resolve(false);
193
+ }
194
+ });
195
+
196
+ server.once("listening", () => {
197
+ server.close(() => resolve(true));
198
+ });
199
+
200
+ server.listen(port, host);
201
+ });
202
+ }
203
+
155
204
  /**
156
205
  * Proxy incoming requests to the active child server, or return a 503 if not
157
206
  * ready.