roster-server 3.4.0 → 3.4.1
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/README.md +2 -2
- package/index.js +2 -1
- package/lib/site-worker.js +1 -1
- package/package.json +1 -1
- package/skills/roster-server/SKILL.md +1 -1
- package/test/isolation.test.js +6 -2
- package/test/lifecycle.test.js +1 -1
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ await roster.start();
|
|
|
28
28
|
console.log(roster.getUrl('example.com'));
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
Local mode binds to `
|
|
31
|
+
Local mode binds to `hostname` (default `::`, IPv4 and IPv6 on all interfaces), skips certificates, and assigns domain ports within `minLocalPort`–`maxLocalPort` (default `4000`–`9999`). Assignments use a domain hash and resolve collisions within the instance; they do not probe for available OS ports. A bind failure rejects startup. Read the assigned URL with `getUrl()` instead of hardcoding a sample port.
|
|
32
32
|
|
|
33
33
|
For production HTTPS, use a real contact email, public DNS pointing to the host, and explicit storage paths:
|
|
34
34
|
|
|
@@ -313,7 +313,7 @@ Pass operational settings through the constructor, using the consuming applicati
|
|
|
313
313
|
| `filename` | `index` | Script entry basename, without extension. |
|
|
314
314
|
| `local` | `false` | Local HTTP mode with assigned ports and no certificates. |
|
|
315
315
|
| `port` | `443` | Default port for manual registrations and routing helpers. |
|
|
316
|
-
| `hostname` | `::` |
|
|
316
|
+
| `hostname` | `::` | Bind address in production and local mode. |
|
|
317
317
|
| `minLocalPort`, `maxLocalPort` | `4000`, `9999` | Inclusive local assignment range. |
|
|
318
318
|
| `staging` | `false` | ACME staging environment. |
|
|
319
319
|
| `autoCertificates` | `true` | Certificate runtime during `init()`; disable for serving-only workers. |
|
package/index.js
CHANGED
|
@@ -950,6 +950,7 @@ class Roster {
|
|
|
950
950
|
const plugins = this.plugins.map(isolatedPluginSource);
|
|
951
951
|
const options = {
|
|
952
952
|
local: this.local,
|
|
953
|
+
hostname: this.hostname,
|
|
953
954
|
port: this.defaultPort,
|
|
954
955
|
filename: this.filename,
|
|
955
956
|
greenlockStorePath: this.greenlockStorePath,
|
|
@@ -1630,7 +1631,7 @@ class Roster {
|
|
|
1630
1631
|
virtualServer.processUpgrade(req, socket, head);
|
|
1631
1632
|
});
|
|
1632
1633
|
|
|
1633
|
-
await this._listen(httpServer, port,
|
|
1634
|
+
await this._listen(httpServer, port, this.hostname);
|
|
1634
1635
|
const cleanDomain = normalizeDomainForLocalHost(domain);
|
|
1635
1636
|
log.info(`🌐 ${domain} → http://${localHostForDomain(cleanDomain)}:${port}`);
|
|
1636
1637
|
}
|
package/lib/site-worker.js
CHANGED
|
@@ -57,7 +57,7 @@ class SiteWorkerRoster extends Roster {
|
|
|
57
57
|
if (key.startsWith('www.')) continue;
|
|
58
58
|
const { domain, port } = this.parseDomainWithPort(key);
|
|
59
59
|
const server = net.createServer({ pauseOnConnect: true });
|
|
60
|
-
const listening = this._listen(server, this._site.localPorts[`${domain}:${port}`],
|
|
60
|
+
const listening = this._listen(server, this._site.localPorts[`${domain}:${port}`], this.hostname);
|
|
61
61
|
server.on('connection', socket => {
|
|
62
62
|
// The site owns the connection from here; it may pass it to another process.
|
|
63
63
|
this._sockets.delete(socket);
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ Use this skill to configure a consuming application. Keep its existing configura
|
|
|
9
9
|
|
|
10
10
|
## Choose the lifecycle owner
|
|
11
11
|
|
|
12
|
-
- **Local development:** `new Roster({ local: true, wwwPath: absolutePath })`, register sites, then `await roster.start()`. Local mode binds to `
|
|
12
|
+
- **Local development:** `new Roster({ local: true, wwwPath: absolutePath })`, register sites, then `await roster.start()`. Local mode binds to `hostname` (default `::`, IPv4 and IPv6) and assigns ports; read URLs with `roster.getUrl(domain)` after startup.
|
|
13
13
|
- **Standalone HTTPS:** set the real `email`, absolute `wwwPath` and `greenlockStorePath`; leave `local` false. `await roster.start()` owns ACME HTTP on port 80 and the configured HTTPS listeners. A different HTTPS port does not eliminate the need for port 80.
|
|
14
14
|
- **External server/worker:** `await roster.init()`, then `roster.attach(server, { port })` or an HTTPS helper. The caller owns listening and closing that server. `port` on `attach()` selects the routing table, not the TCP port.
|
|
15
15
|
- **Serving-only worker:** use `autoCertificates: false` with `init()` and `createServingHttpsServer({ servername })`. A separate manager must provide certificates first. Calling `start()` still enables the standalone ACME lifecycle.
|
package/test/isolation.test.js
CHANGED
|
@@ -91,9 +91,9 @@ function get(port, servername, { pathname = '/', headers = {} } = {}) {
|
|
|
91
91
|
});
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
function localGet(port, pathname = '/') {
|
|
94
|
+
function localGet(port, pathname = '/', hostname = 'localhost') {
|
|
95
95
|
return new Promise((resolve, reject) => {
|
|
96
|
-
http.get({ hostname
|
|
96
|
+
http.get({ hostname, port, path: pathname, agent: false }, res => {
|
|
97
97
|
let body = '';
|
|
98
98
|
res.on('data', chunk => { body += chunk; });
|
|
99
99
|
res.on('end', () => resolve({ status: res.statusCode, body }));
|
|
@@ -315,6 +315,9 @@ it('isolates directory sites in local mode, including aliases and request plugin
|
|
|
315
315
|
assert.equal(alias.pid, site.pid);
|
|
316
316
|
assert.notEqual(other.pid, site.pid);
|
|
317
317
|
assert.deepEqual(await localGet(port('other.example'), '/wp-login.php'), { status: 404, body: 'Not Found' });
|
|
318
|
+
for (const address of ['127.0.0.1', '::1']) {
|
|
319
|
+
assert.equal(JSON.parse((await localGet(port('site.example'), '/', address)).body).pid, site.pid);
|
|
320
|
+
}
|
|
318
321
|
});
|
|
319
322
|
|
|
320
323
|
it('serves a site module already loaded by the main process from that process', { timeout: 20000 }, async t => {
|
|
@@ -479,6 +482,7 @@ it('gives a socket site plain connections on its local port', { timeout: 20000 }
|
|
|
479
482
|
await roster.start();
|
|
480
483
|
const { port } = new URL(roster.getUrl('raw.example'));
|
|
481
484
|
assert.notEqual(JSON.parse((await localGet(port)).body).pid, process.pid);
|
|
485
|
+
for (const address of ['127.0.0.1', '::1']) assert.equal((await localGet(port, '/', address)).status, 200);
|
|
482
486
|
assert.equal(fs.readFileSync(`${marker}.head`, 'utf8'), '0');
|
|
483
487
|
await roster.close();
|
|
484
488
|
assert.equal(fs.readFileSync(marker, 'utf8'), 'closed');
|
package/test/lifecycle.test.js
CHANGED
|
@@ -94,7 +94,7 @@ it('waits for listening, shares start, and closes owned servers once', async t =
|
|
|
94
94
|
|
|
95
95
|
it('rejects bind failures and rolls back already opened ports', async t => {
|
|
96
96
|
const blocker = http.createServer();
|
|
97
|
-
await new Promise(resolve => blocker.listen(0, '
|
|
97
|
+
await new Promise(resolve => blocker.listen(0, '::', resolve));
|
|
98
98
|
t.after(() => new Promise(resolve => blocker.close(resolve)));
|
|
99
99
|
const roster = createRoster(t);
|
|
100
100
|
const ports = [0, blocker.address().port];
|