@eik/service 5.2.7 → 5.2.9
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 +14 -0
- package/lib/main.js +24 -0
- package/package.json +2 -2
- package/types/main.d.ts +66 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [5.2.9](https://github.com/eik-lib/service/compare/v5.2.8...v5.2.9) (2026-08-17)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* bump @eik/core to 2.1.78 ([#793](https://github.com/eik-lib/service/issues/793)) ([1d77ad8](https://github.com/eik-lib/service/commit/1d77ad8a829c8d03df7c9ab0ecafa3b8522c0230))
|
|
7
|
+
|
|
8
|
+
## [5.2.8](https://github.com/eik-lib/service/compare/v5.2.7...v5.2.8) (2026-08-17)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* 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))
|
|
14
|
+
|
|
1
15
|
## [5.2.7](https://github.com/eik-lib/service/compare/v5.2.6...v5.2.7) (2026-08-17)
|
|
2
16
|
|
|
3
17
|
|
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.
|
|
3
|
+
"version": "5.2.9",
|
|
4
4
|
"description": "Eik REST API as a standalone HTTP service",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/main.js",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
},
|
|
44
44
|
"homepage": "https://github.com/eik-lib/service#readme",
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@eik/core": "2.1.
|
|
46
|
+
"@eik/core": "2.1.78",
|
|
47
47
|
"@eik/sink": "1.2.7",
|
|
48
48
|
"@eik/sink-file-system": "2.0.40",
|
|
49
49
|
"@eik/sink-memory": "2.0.37",
|
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][];
|
|
@@ -480,7 +486,36 @@ declare const EikService: {
|
|
|
480
486
|
};
|
|
481
487
|
readonly metrics: import("@metrics/client");
|
|
482
488
|
_parser(incoming: any): Promise<any>;
|
|
483
|
-
_writeEikJson(incoming: any, capturedEikJson: Record<string, any> | null): Promise<
|
|
489
|
+
_writeEikJson(incoming: any, capturedEikJson: Record<string, any> | null): Promise<InstanceType<new ({ pathname, version, name, type, org, }?: import("@eik/core/types/classes/asset.js").AssetOptions) => {
|
|
490
|
+
_mimeType: string;
|
|
491
|
+
_type: string;
|
|
492
|
+
_size: number;
|
|
493
|
+
_integrity: string;
|
|
494
|
+
_pathname: string;
|
|
495
|
+
_version: string;
|
|
496
|
+
_name: string;
|
|
497
|
+
_org: string;
|
|
498
|
+
get integrity(): string;
|
|
499
|
+
set integrity(value: string): any;
|
|
500
|
+
get pathname(): string;
|
|
501
|
+
get mimeType(): string;
|
|
502
|
+
get version(): string;
|
|
503
|
+
get asset(): string;
|
|
504
|
+
get name(): string;
|
|
505
|
+
get type(): string;
|
|
506
|
+
set type(value: string): any;
|
|
507
|
+
get size(): number;
|
|
508
|
+
set size(value: number): any;
|
|
509
|
+
get org(): string;
|
|
510
|
+
toJSON(): {
|
|
511
|
+
integrity: string;
|
|
512
|
+
pathname: string;
|
|
513
|
+
mimeType: string;
|
|
514
|
+
type: string;
|
|
515
|
+
size: number;
|
|
516
|
+
};
|
|
517
|
+
get [Symbol.toStringTag](): string;
|
|
518
|
+
}>>;
|
|
484
519
|
_readVersions(incoming: any): Promise<InstanceType<new ({ versions, type, name, org }?: {
|
|
485
520
|
versions?: [any, any][];
|
|
486
521
|
type?: string;
|
|
@@ -578,7 +613,36 @@ declare const EikService: {
|
|
|
578
613
|
};
|
|
579
614
|
readonly metrics: import("@metrics/client");
|
|
580
615
|
_parser(incoming: any): Promise<any>;
|
|
581
|
-
_writeEikJson(incoming: any, capturedEikJson: Record<string, any> | null): Promise<
|
|
616
|
+
_writeEikJson(incoming: any, capturedEikJson: Record<string, any> | null): Promise<InstanceType<new ({ pathname, version, name, type, org, }?: import("@eik/core/types/classes/asset.js").AssetOptions) => {
|
|
617
|
+
_mimeType: string;
|
|
618
|
+
_type: string;
|
|
619
|
+
_size: number;
|
|
620
|
+
_integrity: string;
|
|
621
|
+
_pathname: string;
|
|
622
|
+
_version: string;
|
|
623
|
+
_name: string;
|
|
624
|
+
_org: string;
|
|
625
|
+
get integrity(): string;
|
|
626
|
+
set integrity(value: string): any;
|
|
627
|
+
get pathname(): string;
|
|
628
|
+
get mimeType(): string;
|
|
629
|
+
get version(): string;
|
|
630
|
+
get asset(): string;
|
|
631
|
+
get name(): string;
|
|
632
|
+
get type(): string;
|
|
633
|
+
set type(value: string): any;
|
|
634
|
+
get size(): number;
|
|
635
|
+
set size(value: number): any;
|
|
636
|
+
get org(): string;
|
|
637
|
+
toJSON(): {
|
|
638
|
+
integrity: string;
|
|
639
|
+
pathname: string;
|
|
640
|
+
mimeType: string;
|
|
641
|
+
type: string;
|
|
642
|
+
size: number;
|
|
643
|
+
};
|
|
644
|
+
get [Symbol.toStringTag](): string;
|
|
645
|
+
}>>;
|
|
582
646
|
_readVersions(incoming: any): Promise<InstanceType<new ({ versions, type, name, org }?: {
|
|
583
647
|
versions?: [any, any][];
|
|
584
648
|
type?: string;
|