🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

roster-server

Package Overview
Dependencies
Maintainers
1
Versions
84
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

roster-server - npm Package Compare versions

Comparing version
2.3.8
to
2.3.10
+12
docs/generated/local-mode-log-hostname-format.md
---
id: fralm92cih
type: bugfix
title: 'Bugfix: local mode startup logs show subdomain.localhost'
created: '2026-03-16 17:19:26'
---
# Bug: local mode startup logs ignored subdomain localhost format
**Symptom**: Startup logs still printed `http://localhost:<port>` for subdomains (e.g. `api.example.com`) even after local URL behavior changed.
**Root cause**: `startLocalMode()` log message used a hardcoded `localhost` string.
**Solution**: Added `localHostForDomain(domain)` helper and reused it in both `getUrl()` and local-mode startup logs so they stay consistent.
**Location**: `index.js` (`localHostForDomain`, `getUrl`, `startLocalMode` listen log).
+1
-1
module.exports = (httpsServer) => {
return (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('"subdomain.example.com: Crazy from thinking, wanting to be reasonable, and the heart has reasons that reason itself will never understand."');
res.end('"api.example.com: Crazy from thinking, wanting to be reasonable, and the heart has reasons that reason itself will never understand."');
};
};

@@ -7,3 +7,3 @@ const express = require('express');

res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.send('"subdomain.example.com: Loco de pensar, queriendo entrar en razón, y el corazón tiene razones que la propia razón nunca entenderá."');
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á."');
});

@@ -10,0 +10,0 @@

+18
-19

@@ -112,2 +112,15 @@ const fs = require('fs');

function normalizeDomainForLocalHost(domain) {
return (domain || '').trim().toLowerCase().replace(/^www\./, '');
}
function localHostForDomain(normalizedDomain) {
const normalized = normalizedDomain;
if (!normalized) return 'localhost';
if (normalized.startsWith('*.')) return '*.localhost';
const labels = normalized.split('.').filter(Boolean);
if (labels.length > 2) return `${labels.slice(0, -2).join('.')}.localhost`;
return 'localhost';
}
// Virtual Server that completely isolates applications

@@ -601,3 +614,3 @@ class VirtualServer extends EventEmitter {

getUrl(domain) {
const cleanDomain = domain.startsWith('www.') ? domain.slice(4) : domain;
const cleanDomain = normalizeDomainForLocalHost(domain);

@@ -611,18 +624,3 @@ const exactMatch = this.sites[cleanDomain] || this.sites[`www.${cleanDomain}`];

if (this.domainPorts && this.domainPorts[pattern] !== undefined) {
const labels = cleanDomain.split('.').filter(Boolean);
let localHost = 'localhost';
// For wildcard matches, preserve the full left-side subdomain chain.
if (pattern.startsWith('*.')) {
const root = wildcardRoot(pattern);
if (root && hostMatchesWildcard(cleanDomain, pattern)) {
const subdomain = cleanDomain.slice(0, -(root.length + 1));
if (subdomain) localHost = `${subdomain}.localhost`;
}
} else if (labels.length > 2) {
// For exact subdomains (e.g. api.example.com), map to api.localhost.
localHost = `${labels.slice(0, -2).join('.')}.localhost`;
}
return `http://${localHost}:${this.domainPorts[pattern]}`;
return `http://${localHostForDomain(cleanDomain)}:${this.domainPorts[pattern]}`;
}

@@ -725,3 +723,4 @@ return null;

httpServer.listen(port, 'localhost', () => {
log.info(`🌐 ${domain} → http://localhost:${port}`);
const cleanDomain = normalizeDomainForLocalHost(domain);
log.info(`🌐 ${domain} → http://${localHostForDomain(cleanDomain)}:${port}`);
});

@@ -801,3 +800,3 @@

if (eventDomain && !msg.includes(`[${eventDomain}]`)) {
msg = `[domain:${eventDomain}] ${msg}`;
msg = `[${eventDomain}] ${msg}`;
}

@@ -804,0 +803,0 @@ // Suppress known benign warnings from ACME when using acme-dns-01-cli

{
"name": "roster-server",
"version": "2.3.8",
"version": "2.3.10",
"description": "👾 RosterServer - A domain host router to host multiple HTTPS.",

@@ -5,0 +5,0 @@ "main": "index.js",

---
id: wrxv04lnq9
type: decision
title: 'Decision: Local subdomain URL format'
created: '2026-03-16 17:15:01'
---
# Decision: Local subdomain URL format
**What**: In local mode, `getUrl(domain)` now returns `http://<subdomain>.localhost:<port>` for subdomains, while apex domains keep `http://localhost:<port>`.
**Where**: Implemented in `index.js` (`getUrl` local branch), validated in `test/roster-server.test.js`, and documented in `README.md`.
**Why**: Local URLs should preserve subdomain semantics so multi-tenant/subdomain routes are explicit and easier to test.
**Alternatives rejected**: Keeping all local URLs as `http://localhost:<port>` was rejected because it hides host intent for subdomain-based apps.