@eik/service 5.2.7 → 5.2.8

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [5.2.8](https://github.com/eik-lib/service/compare/v5.2.7...v5.2.8) (2026-08-17)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * close stalled upload connections after configurable bodyTimeout ([#789](https://github.com/eik-lib/service/issues/789)) ([e765fe7](https://github.com/eik-lib/service/commit/e765fe74fae91b75467477f20110bf83f33b4e0e))
7
+
1
8
  ## [5.2.7](https://github.com/eik-lib/service/compare/v5.2.6...v5.2.7) (2026-08-17)
2
9
 
3
10
 
package/lib/main.js CHANGED
@@ -23,6 +23,7 @@ import * as utils from "./utils.js";
23
23
  * @property {number} [pkgMaxFileSize=10000000] The limit in bytes before PUT /pkg/ starts returning 413 Content Too Large
24
24
  * @property {number} [mapMaxFileSize=1000000] The limit in bytes before PUT /map/ starts returning 413 Content Too Large
25
25
  * @property {number} [imgMaxFileSize=20000000] The limit in bytes before PUT /img/ starts returning 413 Content Too Large
26
+ * @property {number} [bodyTimeout=30000] Milliseconds before an upload request whose body has not been fully received is terminated with 408
26
27
  */
27
28
 
28
29
  const EikService = class EikService {
@@ -39,7 +40,9 @@ const EikService = class EikService {
39
40
  pkgMaxFileSize = 10000000,
40
41
  mapMaxFileSize = 1000000,
41
42
  imgMaxFileSize = 20000000,
43
+ bodyTimeout = 30000,
42
44
  } = options;
45
+ this._bodyTimeout = bodyTimeout;
43
46
  this._notFoundCacheControl = notFoundCacheControl || "public, max-age=5";
44
47
 
45
48
  if (!logger) {
@@ -215,6 +218,27 @@ const EikService = class EikService {
215
218
  api() {
216
219
  /** @param {import('fastify').FastifyInstance} app */
217
220
  return async (app) => {
221
+ // Enforce a maximum idle time per connection so that slow or
222
+ // stalled uploads cannot hold busboy, the tar parser, and open
223
+ // sink write streams open indefinitely. When a socket is idle
224
+ // for longer than bodyTimeout ms the server closes the connection
225
+ // with 408 Request Timeout. The timer resets whenever data flows,
226
+ // so actively uploading connections are not affected.
227
+ if (this._bodyTimeout > 0) {
228
+ app.server.on("connection", (socket) => {
229
+ socket.setTimeout(this._bodyTimeout);
230
+ socket.on("timeout", () => {
231
+ if (!socket.destroyed) {
232
+ socket.end(
233
+ "HTTP/1.1 408 Request Timeout\r\n" +
234
+ "Content-Length: 0\r\n" +
235
+ "Connection: close\r\n\r\n",
236
+ );
237
+ }
238
+ });
239
+ });
240
+ }
241
+
218
242
  if (!app.initialConfig.routerOptions?.ignoreTrailingSlash) {
219
243
  this.logger.warn(
220
244
  'Fastify is configured with "routerOptions.ignoreTrailingSlash" set to "false". Its adviced to set "routerOptions.ignoreTrailingSlash" to "true"',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eik/service",
3
- "version": "5.2.7",
3
+ "version": "5.2.8",
4
4
  "description": "Eik REST API as a standalone HTTP service",
5
5
  "type": "module",
6
6
  "main": "./lib/main.js",
package/types/main.d.ts CHANGED
@@ -24,6 +24,10 @@ export type EikServiceOptions = {
24
24
  * The limit in bytes before PUT /img/ starts returning 413 Content Too Large
25
25
  */
26
26
  imgMaxFileSize?: number | undefined;
27
+ /**
28
+ * Milliseconds before an upload request whose body has not been fully received is terminated with 408
29
+ */
30
+ bodyTimeout?: number | undefined;
27
31
  };
28
32
  /**
29
33
  * @typedef {object} EikServiceOptions
@@ -36,9 +40,11 @@ export type EikServiceOptions = {
36
40
  * @property {number} [pkgMaxFileSize=10000000] The limit in bytes before PUT /pkg/ starts returning 413 Content Too Large
37
41
  * @property {number} [mapMaxFileSize=1000000] The limit in bytes before PUT /map/ starts returning 413 Content Too Large
38
42
  * @property {number} [imgMaxFileSize=20000000] The limit in bytes before PUT /img/ starts returning 413 Content Too Large
43
+ * @property {number} [bodyTimeout=30000] Milliseconds before an upload request whose body has not been fully received is terminated with 408
39
44
  */
40
45
  declare const EikService: {
41
46
  new (options?: EikServiceOptions): {
47
+ _bodyTimeout: number;
42
48
  _notFoundCacheControl: string;
43
49
  _versionsGet: {
44
50
  _organizations: [string, string][];