@kadi.build/file-sharing 1.1.0 → 1.1.2

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": "@kadi.build/file-sharing",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "File sharing service with tunneling and local S3-compatible interface",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -123,6 +123,16 @@ function _filterDefined(obj) {
123
123
  return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined));
124
124
  }
125
125
 
126
+ /**
127
+ * Convert a bind address (like `0.0.0.0` or `::`) into a client-usable address.
128
+ * Bind-all addresses are not connectable by clients; replace them with `127.0.0.1`.
129
+ * @param {string} host
130
+ * @returns {string}
131
+ */
132
+ function _clientHost(host) {
133
+ return (host === '0.0.0.0' || host === '::' || host === '[::]') ? '127.0.0.1' : host;
134
+ }
135
+
126
136
  export class FileSharingServer extends EventEmitter {
127
137
  constructor(config = {}) {
128
138
  super();
@@ -169,6 +179,24 @@ export class FileSharingServer extends EventEmitter {
169
179
  };
170
180
  }
171
181
 
182
+ // ----------------------------------------------------------------
183
+ // Port collision detection: when S3 is enabled and both ports match,
184
+ // auto-assign s3Port to 0 (OS picks a free port) to avoid EADDRINUSE.
185
+ // ----------------------------------------------------------------
186
+ if (this.config.enableS3 && this.config.port === this.config.s3Port && this.config.port !== 0) {
187
+ const userExplicitlySetS3Port = config.s3Port !== undefined;
188
+ if (userExplicitlySetS3Port) {
189
+ throw new Error(
190
+ `Port collision: port and s3Port are both set to ${this.config.port}. ` +
191
+ `The HTTP server and S3 server cannot bind the same port. ` +
192
+ `Please specify a different s3Port (or use s3Port: 0 for auto-assign).`
193
+ );
194
+ }
195
+ // User only set `port` (not s3Port) and it happens to match the s3Port default.
196
+ // Auto-resolve by letting the OS pick a free port for S3.
197
+ this.config.s3Port = 0;
198
+ }
199
+
172
200
  // ----------------------------------------------------------------
173
201
  // Load secrets from env vars / .env (constructor config takes priority)
174
202
  // ----------------------------------------------------------------
@@ -337,7 +365,13 @@ export class FileSharingServer extends EventEmitter {
337
365
  }
338
366
 
339
367
  const service = options.service || 'kadi'; // KĀDI is the default
340
- const port = this.config.port;
368
+
369
+ // Allow caller to specify which port to tunnel via options.port.
370
+ // Default: when S3 is running, target the S3 port (where custom routes
371
+ // and middleware are installed via addCustomRoute/addMiddleware).
372
+ // Otherwise fall back to the HTTP file-server port.
373
+ const port = options.port
374
+ ?? (this.s3Server?.isRunning ? this.s3Server.config.port : this.config.port);
341
375
 
342
376
  // TunnelManager.createTunnel(port, options) — port is first arg (number),
343
377
  // options.service tells it which provider to use.
@@ -412,12 +446,13 @@ export class FileSharingServer extends EventEmitter {
412
446
  * @returns {object} Server information
413
447
  */
414
448
  getInfo() {
449
+ const host = _clientHost(this.config.host);
415
450
  return {
416
451
  isRunning: this.isRunning,
417
- localUrl: `http://${this.config.host}:${this.config.port}`,
452
+ localUrl: `http://${host}:${this.config.port}`,
418
453
  publicUrl: this.tunnel?.publicUrl || null,
419
454
  s3Endpoint: this.s3Server?.isRunning
420
- ? `http://${this.config.host}:${this.config.s3Port}`
455
+ ? `http://${host}:${this.s3Server.config.port}`
421
456
  : null,
422
457
  staticDir: this.config.staticDir,
423
458
  stats: this.downloadMonitor.getStats(),
@@ -488,7 +523,7 @@ export class FileSharingServer extends EventEmitter {
488
523
  /** @type {string|null} */
489
524
  get s3Endpoint() {
490
525
  return this.s3Server?.isRunning
491
- ? `http://${this.config.host}:${this.config.s3Port}`
526
+ ? `http://${_clientHost(this.config.host)}:${this.s3Server.config.port}`
492
527
  : null;
493
528
  }
494
529
 
@@ -88,10 +88,14 @@ export class HttpServerProvider extends EventEmitter {
88
88
  this.startTime = new Date();
89
89
 
90
90
  const protocol = this.config.ssl ? 'https' : 'http';
91
+ // Use a client-connectable host in the URL (0.0.0.0 is a bind address, not routable)
92
+ const clientHost = (this.config.host === '0.0.0.0' || this.config.host === '::' || this.config.host === '[::]')
93
+ ? '127.0.0.1'
94
+ : this.config.host;
91
95
  const info = {
92
96
  port: addr.port,
93
97
  host: this.config.host,
94
- url: `${protocol}://${this.config.host}:${addr.port}`
98
+ url: `${protocol}://${clientHost}:${addr.port}`
95
99
  };
96
100
 
97
101
  this.emit('started', info);
package/src/S3Server.js CHANGED
@@ -70,9 +70,12 @@ export class S3Server extends EventEmitter {
70
70
  */
71
71
  async start() {
72
72
  if (this.isRunning) {
73
+ const clientHost = (this.config.host === '0.0.0.0' || this.config.host === '::' || this.config.host === '[::]')
74
+ ? '127.0.0.1'
75
+ : this.config.host;
73
76
  return {
74
77
  port: this.config.port,
75
- endpoint: `http://${this.config.host}:${this.config.port}`
78
+ endpoint: `http://${clientHost}:${this.config.port}`
76
79
  };
77
80
  }
78
81
 
@@ -118,10 +121,14 @@ export class S3Server extends EventEmitter {
118
121
  this.isRunning = true;
119
122
  this._serverId = `kadi-s3-${addr.port}`;
120
123
 
124
+ // Use a client-connectable host in the endpoint (0.0.0.0 is a bind address, not routable)
125
+ const clientHost = (this.config.host === '0.0.0.0' || this.config.host === '::' || this.config.host === '[::]')
126
+ ? '127.0.0.1'
127
+ : this.config.host;
121
128
  const info = {
122
129
  port: addr.port,
123
130
  host: this.config.host,
124
- endpoint: `http://${this.config.host}:${addr.port}`,
131
+ endpoint: `http://${clientHost}:${addr.port}`,
125
132
  serverId: this._serverId
126
133
  };
127
134