roster-server 2.3.6 → 2.3.10
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
CHANGED
|
@@ -309,12 +309,13 @@ await roster.start();
|
|
|
309
309
|
const url = roster.getUrl('example.com');
|
|
310
310
|
console.log(url);
|
|
311
311
|
// Local mode: http://localhost:9465
|
|
312
|
+
// Local subdomain: http://api.localhost:9465
|
|
312
313
|
// Production mode: https://example.com
|
|
313
314
|
```
|
|
314
315
|
|
|
315
316
|
This method:
|
|
316
317
|
- Returns the correct URL based on your environment (`local: true/false`)
|
|
317
|
-
- In **local mode**: Returns `http://localhost:{port}`
|
|
318
|
+
- In **local mode**: Returns `http://localhost:{port}` for apex domains and `http://{subdomain}.localhost:{port}` for subdomains
|
|
318
319
|
- In **production mode**: Returns `https://{domain}` (or with custom port if configured)
|
|
319
320
|
- Handles `www.` prefix automatically (returns same URL)
|
|
320
321
|
- Returns `null` for domains that aren't registered
|
|
@@ -327,9 +328,12 @@ import Roster from 'roster-server';
|
|
|
327
328
|
// Local development
|
|
328
329
|
const localRoster = new Roster({ local: true });
|
|
329
330
|
localRoster.register('example.com', handler);
|
|
331
|
+
localRoster.register('api.example.com', handler);
|
|
330
332
|
await localRoster.start();
|
|
331
333
|
console.log(localRoster.getUrl('example.com'));
|
|
332
334
|
// → http://localhost:9465
|
|
335
|
+
console.log(localRoster.getUrl('api.example.com'));
|
|
336
|
+
// → http://api.localhost:7342
|
|
333
337
|
|
|
334
338
|
// Production
|
|
335
339
|
const prodRoster = new Roster({ local: false });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module.exports = (httpsServer) => {
|
|
2
2
|
return (req, res) => {
|
|
3
3
|
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
4
|
-
res.end('"
|
|
4
|
+
res.end('"api.example.com: Crazy from thinking, wanting to be reasonable, and the heart has reasons that reason itself will never understand."');
|
|
5
5
|
};
|
|
6
6
|
};
|
|
@@ -4,7 +4,7 @@ module.exports = (httpsServer) => {
|
|
|
4
4
|
const app = express();
|
|
5
5
|
app.get('/', (req, res) => {
|
|
6
6
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
7
|
-
res.send('"
|
|
7
|
+
res.send('"express.example.com: Loco de pensar, queriendo entrar en razón, y el corazón tiene razones que la propia razón nunca entenderá."');
|
|
8
8
|
});
|
|
9
9
|
|
|
10
10
|
return app;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: fralm92cih
|
|
3
|
+
type: bugfix
|
|
4
|
+
title: 'Bugfix: local mode startup logs show subdomain.localhost'
|
|
5
|
+
created: '2026-03-16 17:19:26'
|
|
6
|
+
---
|
|
7
|
+
# Bug: local mode startup logs ignored subdomain localhost format
|
|
8
|
+
|
|
9
|
+
**Symptom**: Startup logs still printed `http://localhost:<port>` for subdomains (e.g. `api.example.com`) even after local URL behavior changed.
|
|
10
|
+
**Root cause**: `startLocalMode()` log message used a hardcoded `localhost` string.
|
|
11
|
+
**Solution**: Added `localHostForDomain(domain)` helper and reused it in both `getUrl()` and local-mode startup logs so they stay consistent.
|
|
12
|
+
**Location**: `index.js` (`localHostForDomain`, `getUrl`, `startLocalMode` listen log).
|
package/index.js
CHANGED
|
@@ -109,6 +109,19 @@ function parseBooleanFlag(value, fallback = false) {
|
|
|
109
109
|
return fallback;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
function normalizeDomainForLocalHost(domain) {
|
|
113
|
+
return (domain || '').trim().toLowerCase().replace(/^www\./, '');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function localHostForDomain(normalizedDomain) {
|
|
117
|
+
const normalized = normalizedDomain;
|
|
118
|
+
if (!normalized) return 'localhost';
|
|
119
|
+
if (normalized.startsWith('*.')) return '*.localhost';
|
|
120
|
+
const labels = normalized.split('.').filter(Boolean);
|
|
121
|
+
if (labels.length > 2) return `${labels.slice(0, -2).join('.')}.localhost`;
|
|
122
|
+
return 'localhost';
|
|
123
|
+
}
|
|
124
|
+
|
|
112
125
|
// Virtual Server that completely isolates applications
|
|
113
126
|
class VirtualServer extends EventEmitter {
|
|
114
127
|
constructor(domain) {
|
|
@@ -597,7 +610,7 @@ class Roster {
|
|
|
597
610
|
* @returns {string|null} The URL if domain is registered (exact or wildcard), null otherwise
|
|
598
611
|
*/
|
|
599
612
|
getUrl(domain) {
|
|
600
|
-
const cleanDomain =
|
|
613
|
+
const cleanDomain = normalizeDomainForLocalHost(domain);
|
|
601
614
|
|
|
602
615
|
const exactMatch = this.sites[cleanDomain] || this.sites[`www.${cleanDomain}`];
|
|
603
616
|
const resolved = exactMatch ? { handler: exactMatch, siteKey: cleanDomain } : this.getHandlerAndKeyForHost(cleanDomain);
|
|
@@ -606,7 +619,7 @@ class Roster {
|
|
|
606
619
|
if (this.local) {
|
|
607
620
|
const pattern = resolved.siteKey.split(':')[0];
|
|
608
621
|
if (this.domainPorts && this.domainPorts[pattern] !== undefined) {
|
|
609
|
-
return `http
|
|
622
|
+
return `http://${localHostForDomain(cleanDomain)}:${this.domainPorts[pattern]}`;
|
|
610
623
|
}
|
|
611
624
|
return null;
|
|
612
625
|
}
|
|
@@ -704,7 +717,8 @@ class Roster {
|
|
|
704
717
|
});
|
|
705
718
|
|
|
706
719
|
httpServer.listen(port, 'localhost', () => {
|
|
707
|
-
|
|
720
|
+
const cleanDomain = normalizeDomainForLocalHost(domain);
|
|
721
|
+
log.info(`🌐 ${domain} → http://${localHostForDomain(cleanDomain)}:${port}`);
|
|
708
722
|
});
|
|
709
723
|
|
|
710
724
|
httpServer.on('error', (error) => {
|
|
@@ -778,8 +792,8 @@ class Roster {
|
|
|
778
792
|
}
|
|
779
793
|
}
|
|
780
794
|
if (!msg || msg === 'undefined') msg = `[${event}] (no details)`;
|
|
781
|
-
if (eventDomain && !msg.includes(`[
|
|
782
|
-
msg = `[
|
|
795
|
+
if (eventDomain && !msg.includes(`[${eventDomain}]`)) {
|
|
796
|
+
msg = `[${eventDomain}] ${msg}`;
|
|
783
797
|
}
|
|
784
798
|
// Suppress known benign warnings from ACME when using acme-dns-01-cli
|
|
785
799
|
if (event === 'warning' && typeof msg === 'string') {
|
package/package.json
CHANGED
|
@@ -218,7 +218,7 @@ describe('Roster', () => {
|
|
|
218
218
|
roster.register('*.example.com', () => {});
|
|
219
219
|
roster.domainPorts = { '*.example.com': 9999 };
|
|
220
220
|
roster.local = true;
|
|
221
|
-
assert.strictEqual(roster.getUrl('api.example.com'), 'http://localhost:9999');
|
|
221
|
+
assert.strictEqual(roster.getUrl('api.example.com'), 'http://api.localhost:9999');
|
|
222
222
|
});
|
|
223
223
|
it('returns https URL for wildcard-matched host in production', () => {
|
|
224
224
|
const roster = new Roster({ local: false });
|
|
@@ -359,6 +359,13 @@ describe('Roster', () => {
|
|
|
359
359
|
roster.local = true;
|
|
360
360
|
assert.strictEqual(roster.getUrl('exact.local'), 'http://localhost:4567');
|
|
361
361
|
});
|
|
362
|
+
it('returns http://subdomain.localhost:PORT in local mode for exact subdomain', () => {
|
|
363
|
+
const roster = new Roster({ local: true });
|
|
364
|
+
roster.register('api.example.com', () => {});
|
|
365
|
+
roster.domainPorts = { 'api.example.com': 5678 };
|
|
366
|
+
roster.local = true;
|
|
367
|
+
assert.strictEqual(roster.getUrl('api.example.com'), 'http://api.localhost:5678');
|
|
368
|
+
});
|
|
362
369
|
it('returns https URL in production for registered domain', () => {
|
|
363
370
|
const roster = new Roster({ local: false });
|
|
364
371
|
roster.register('example.com', () => {});
|