@kadi.build/file-sharing 1.1.0 → 1.1.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/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.1",
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
  // ----------------------------------------------------------------
@@ -412,12 +440,13 @@ export class FileSharingServer extends EventEmitter {
412
440
  * @returns {object} Server information
413
441
  */
414
442
  getInfo() {
443
+ const host = _clientHost(this.config.host);
415
444
  return {
416
445
  isRunning: this.isRunning,
417
- localUrl: `http://${this.config.host}:${this.config.port}`,
446
+ localUrl: `http://${host}:${this.config.port}`,
418
447
  publicUrl: this.tunnel?.publicUrl || null,
419
448
  s3Endpoint: this.s3Server?.isRunning
420
- ? `http://${this.config.host}:${this.config.s3Port}`
449
+ ? `http://${host}:${this.s3Server.config.port}`
421
450
  : null,
422
451
  staticDir: this.config.staticDir,
423
452
  stats: this.downloadMonitor.getStats(),
@@ -488,7 +517,7 @@ export class FileSharingServer extends EventEmitter {
488
517
  /** @type {string|null} */
489
518
  get s3Endpoint() {
490
519
  return this.s3Server?.isRunning
491
- ? `http://${this.config.host}:${this.config.s3Port}`
520
+ ? `http://${_clientHost(this.config.host)}:${this.s3Server.config.port}`
492
521
  : null;
493
522
  }
494
523
 
@@ -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