roster-server 2.0.2 → 2.0.6

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 (3) hide show
  1. package/README.md +14 -1
  2. package/index.js +39 -6
  3. package/package.json +2 -1
package/README.md CHANGED
@@ -11,6 +11,7 @@ Welcome to **RosterServer**, the ultimate domain host router with automatic HTTP
11
11
  - **Virtual Hosting**: Serve multiple domains from a single server.
12
12
  - **Automatic Redirects**: Redirect `www` subdomains to the root domain.
13
13
  - **Zero Configuration**: Well, almost zero. Just a tiny bit of setup.
14
+ - **Bun compatible**: Works with both Node.js and [Bun](https://bun.sh).
14
15
 
15
16
  ## 📦 Installation
16
17
 
@@ -18,6 +19,12 @@ Welcome to **RosterServer**, the ultimate domain host router with automatic HTTP
18
19
  npm install roster-server
19
20
  ```
20
21
 
22
+ Or with [Bun](https://bun.sh):
23
+
24
+ ```bash
25
+ bun add roster-server
26
+ ```
27
+
21
28
  ## 🤖 AI Skill
22
29
 
23
30
  You can also add RosterServer as a skill for AI agentic development:
@@ -145,10 +152,16 @@ roster.register('example.com:8080', (httpsServer) => {
145
152
  ### Running the Server
146
153
 
147
154
  ```bash
148
- # /srv/roster/server.js
155
+ # With Node.js
149
156
  node server.js
150
157
  ```
151
158
 
159
+ Or with Bun:
160
+
161
+ ```bash
162
+ bun server.js
163
+ ```
164
+
152
165
  And that's it! Your server is now hosting multiple HTTPS-enabled sites. 🎉
153
166
 
154
167
  ## 🤯 But Wait, There's More!
package/index.js CHANGED
@@ -166,6 +166,8 @@ class Roster {
166
166
  this.filename = options.filename || 'index';
167
167
  this.minLocalPort = options.minLocalPort || 4000;
168
168
  this.maxLocalPort = options.maxLocalPort || 9999;
169
+ this.tlsMinVersion = options.tlsMinVersion ?? 'TLSv1.2';
170
+ this.tlsMaxVersion = options.tlsMaxVersion ?? 'TLSv1.3';
169
171
 
170
172
  const port = options.port === undefined ? 443 : options.port;
171
173
  if (port === 80 && !this.local) {
@@ -374,13 +376,13 @@ class Roster {
374
376
  getUrl(domain) {
375
377
  // Remove www prefix if present
376
378
  const cleanDomain = domain.startsWith('www.') ? domain.slice(4) : domain;
377
-
379
+
378
380
  // Check if domain is registered
379
381
  const isRegistered = this.sites[cleanDomain] || this.sites[`www.${cleanDomain}`];
380
382
  if (!isRegistered) {
381
383
  return null;
382
384
  }
383
-
385
+
384
386
  // Return URL based on environment
385
387
  if (this.local) {
386
388
  // Local mode: return localhost URL with assigned port
@@ -437,7 +439,7 @@ class Roster {
437
439
  startLocalMode() {
438
440
  // Store mapping of domain to port for later retrieval
439
441
  this.domainPorts = {};
440
-
442
+
441
443
  // Create a simple HTTP server for each domain with CRC32-based ports
442
444
  for (const [hostKey, siteApp] of Object.entries(this.sites)) {
443
445
  const domain = hostKey.split(':')[0]; // Remove port if present
@@ -449,7 +451,7 @@ class Roster {
449
451
 
450
452
  // Calculate deterministic port based on domain CRC32, with collision detection
451
453
  const port = this.assignPortToDomain(domain);
452
-
454
+
453
455
  // Store domain → port mapping
454
456
  this.domainPorts[domain] = port;
455
457
 
@@ -608,8 +610,37 @@ class Roster {
608
610
  const upgradeHandler = createUpgradeHandler(portData);
609
611
 
610
612
  if (portNum === this.defaultPort) {
611
- // Use Greenlock for default port (443) with SSL
612
- const httpsServer = glx.httpsServer(null, dispatcher);
613
+ // Bun has known gaps around SNICallback compatibility.
614
+ // Fallback to static cert loading for the primary domain on default HTTPS port.
615
+ const isBunRuntime = typeof Bun !== 'undefined' || process.release?.name === 'bun';
616
+ const tlsOpts = { minVersion: this.tlsMinVersion, maxVersion: this.tlsMaxVersion };
617
+ let httpsServer;
618
+
619
+ if (isBunRuntime) {
620
+ const primaryDomain = Object.keys(portData.virtualServers)[0];
621
+ const certPath = path.join(this.greenlockStorePath, 'live', primaryDomain);
622
+ const keyPath = path.join(certPath, 'privkey.pem');
623
+ const certFilePath = path.join(certPath, 'cert.pem');
624
+ const chainPath = path.join(certPath, 'chain.pem');
625
+
626
+ if (fs.existsSync(keyPath) && fs.existsSync(certFilePath) && fs.existsSync(chainPath)) {
627
+ const key = fs.readFileSync(keyPath, 'utf8');
628
+ const cert = fs.readFileSync(certFilePath, 'utf8');
629
+ const chain = fs.readFileSync(chainPath, 'utf8');
630
+ httpsServer = https.createServer({
631
+ ...tlsOpts,
632
+ key,
633
+ cert: cert + chain
634
+ }, dispatcher);
635
+ log.warn(`⚠️ Bun runtime detected: using static TLS cert for ${primaryDomain} on port ${portNum}`);
636
+ } else {
637
+ log.warn(`⚠️ Bun runtime detected but cert files missing for ${primaryDomain}; falling back to Greenlock HTTPS server`);
638
+ httpsServer = glx.httpsServer(tlsOpts, dispatcher);
639
+ }
640
+ } else {
641
+ httpsServer = glx.httpsServer(tlsOpts, dispatcher);
642
+ }
643
+
613
644
  this.portServers[portNum] = httpsServer;
614
645
 
615
646
  // Handle WebSocket upgrade events
@@ -621,6 +652,8 @@ class Roster {
621
652
  } else {
622
653
  // Create HTTPS server for custom ports using Greenlock certificates
623
654
  const httpsOptions = {
655
+ minVersion: this.tlsMinVersion,
656
+ maxVersion: this.tlsMaxVersion,
624
657
  // SNI callback to get certificates dynamically
625
658
  SNICallback: (domain, callback) => {
626
659
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roster-server",
3
- "version": "2.0.2",
3
+ "version": "2.0.6",
4
4
  "description": "👾 RosterServer - A domain host router to host multiple HTTPS.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -26,6 +26,7 @@
26
26
  "express",
27
27
  "greenlock-express",
28
28
  "shotx",
29
+ "bun",
29
30
  "clasen"
30
31
  ],
31
32
  "author": "Martin Clasen",