@eik/service 2.2.1 → 2.3.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/CHANGELOG.md +20 -0
- package/README.md +3 -2
- package/lib/config.js +4 -4
- package/lib/main.js +139 -2
- package/lib/utils.js +6 -2
- package/package.json +11 -7
- package/types/main.d.ts +89 -0
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
## [2.3.1](https://github.com/eik-lib/service/compare/v2.3.0...v2.3.1) (2024-08-19)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* add support for windows hosts ([ed263d6](https://github.com/eik-lib/service/commit/ed263d6ed72cc21ad89d0fb3c27b06ca96c6d416))
|
7
|
+
|
8
|
+
# [2.3.0](https://github.com/eik-lib/service/compare/v2.2.1...v2.3.0) (2024-08-14)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* set defaults to max types ([a5b67e3](https://github.com/eik-lib/service/commit/a5b67e335d006c84d8796dc3b7ede7455caf9de9))
|
14
|
+
* update @eik/core to v1.4.0 ([a09d12c](https://github.com/eik-lib/service/commit/a09d12c1f24ad2c2eadbfffbd0d47cf14ef3e2b6))
|
15
|
+
|
16
|
+
|
17
|
+
### Features
|
18
|
+
|
19
|
+
* add routes for /img/ with configurable upload limit ([0f6bda7](https://github.com/eik-lib/service/commit/0f6bda7a3b3c7ddc5f3f9959a9c1056616184981))
|
20
|
+
|
1
21
|
## [2.2.1](https://github.com/eik-lib/service/compare/v2.2.0...v2.2.1) (2024-08-12)
|
2
22
|
|
3
23
|
|
package/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
#
|
1
|
+
# @eik/service
|
2
2
|
|
3
|
-
|
3
|
+
This is the [HTTP server](https://eik.dev/docs/server/) running the Eik service.
|
4
|
+
The implementation for the different [HTTP endpoints](https://eik.dev/docs/server/http-api) are in [`@eik/core`](https://github.com/eik-lib/core#readme).
|
4
5
|
|
5
6
|
## Installation
|
6
7
|
|
package/lib/config.js
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
import convict from 'convict';
|
3
3
|
import yaml from 'js-yaml';
|
4
4
|
import pino from 'pino';
|
5
|
-
import path
|
5
|
+
import path from 'path';
|
6
6
|
import fs from 'fs';
|
7
7
|
import os from 'os';
|
8
8
|
|
@@ -10,7 +10,7 @@ const CWD = process.cwd();
|
|
10
10
|
|
11
11
|
let pack = {};
|
12
12
|
try {
|
13
|
-
pack = JSON.parse(fs.readFileSync(join(CWD, 'package.json'), 'utf-8'));
|
13
|
+
pack = JSON.parse(fs.readFileSync(path.join(CWD, 'package.json'), 'utf-8'));
|
14
14
|
} catch (error) {
|
15
15
|
/* empty */
|
16
16
|
}
|
@@ -148,7 +148,7 @@ const conf = convict({
|
|
148
148
|
path: {
|
149
149
|
doc: 'Absolute path to store files in when using the "fs" sink',
|
150
150
|
format: String,
|
151
|
-
default: path.join(os.tmpdir(), '
|
151
|
+
default: path.join(os.tmpdir(), 'eik'),
|
152
152
|
env: 'SINK_PATH',
|
153
153
|
},
|
154
154
|
},
|
@@ -163,7 +163,7 @@ const logger = pino({
|
|
163
163
|
});
|
164
164
|
|
165
165
|
try {
|
166
|
-
conf.loadFile(path.join(CWD,
|
166
|
+
conf.loadFile(path.join(CWD, 'config', `${env}.yaml`));
|
167
167
|
} catch (error) {
|
168
168
|
logger.error(error);
|
169
169
|
}
|
package/lib/main.js
CHANGED
@@ -20,6 +20,7 @@ import * as utils from './utils.js';
|
|
20
20
|
* @property {string} [notFoundCacheControl="public, max-age=5"]
|
21
21
|
* @property {number} [pkgMaxFileSize=10000000] The limit in bytes before PUT /pkg/ starts returning 413 Content Too Large
|
22
22
|
* @property {number} [mapMaxFileSize=1000000] The limit in bytes before PUT /map/ starts returning 413 Content Too Large
|
23
|
+
* @property {number} [imgMaxFileSize=20000000] The limit in bytes before PUT /img/ starts returning 413 Content Too Large
|
23
24
|
*/
|
24
25
|
|
25
26
|
const EikService = class EikService {
|
@@ -32,8 +33,9 @@ const EikService = class EikService {
|
|
32
33
|
customSink,
|
33
34
|
notFoundCacheControl,
|
34
35
|
aliasCacheControl,
|
35
|
-
pkgMaxFileSize,
|
36
|
-
mapMaxFileSize,
|
36
|
+
pkgMaxFileSize = 10000000,
|
37
|
+
mapMaxFileSize = 1000000,
|
38
|
+
imgMaxFileSize = 20000000,
|
37
39
|
} = options;
|
38
40
|
this._notFoundCacheControl =
|
39
41
|
notFoundCacheControl || 'public, max-age=5';
|
@@ -104,6 +106,12 @@ const EikService = class EikService {
|
|
104
106
|
logger,
|
105
107
|
pkgMaxFileSize,
|
106
108
|
});
|
109
|
+
this._imgPut = new eik.http.PkgPut({
|
110
|
+
organizations,
|
111
|
+
sink,
|
112
|
+
logger,
|
113
|
+
pkgMaxFileSize: imgMaxFileSize,
|
114
|
+
});
|
107
115
|
this._mapGet = new eik.http.MapGet({ organizations, sink, logger });
|
108
116
|
this._mapPut = new eik.http.MapPut({
|
109
117
|
organizations,
|
@@ -351,6 +359,21 @@ const EikService = class EikService {
|
|
351
359
|
reply.redirect(outgoing.location);
|
352
360
|
};
|
353
361
|
|
362
|
+
const imgPutRoute = async (request, reply) => {
|
363
|
+
const params = utils.sanitizeParameters(request.raw.url);
|
364
|
+
const outgoing = await this._imgPut.handler(
|
365
|
+
request.raw,
|
366
|
+
request.user,
|
367
|
+
params.type,
|
368
|
+
params.name,
|
369
|
+
params.version,
|
370
|
+
);
|
371
|
+
reply.header('cache-control', outgoing.cacheControl);
|
372
|
+
reply.type(outgoing.mimeType);
|
373
|
+
reply.code(outgoing.statusCode);
|
374
|
+
reply.redirect(outgoing.location);
|
375
|
+
};
|
376
|
+
|
354
377
|
const mapGetRoute = async (request, reply) => {
|
355
378
|
const params = utils.sanitizeParameters(request.raw.url);
|
356
379
|
const outgoing = await this._mapGet.handler(
|
@@ -547,6 +570,56 @@ const EikService = class EikService {
|
|
547
570
|
pkgPutRoute,
|
548
571
|
);
|
549
572
|
|
573
|
+
//
|
574
|
+
// Image Packages
|
575
|
+
//
|
576
|
+
|
577
|
+
// Get public IMG package - scoped
|
578
|
+
// curl -X GET http://localhost:4001/img/@cuz/fuzz/8.4.1/main/picture.jpg
|
579
|
+
app.get(
|
580
|
+
`/${eik.prop.base_img}/@:scope/:name/:version/*`,
|
581
|
+
pkgGetRoute,
|
582
|
+
);
|
583
|
+
|
584
|
+
// Get public IMG package - non-scoped
|
585
|
+
// curl -X GET http://localhost:4001/img/fuzz/8.4.1/main/picture.jpg
|
586
|
+
app.get(`/${eik.prop.base_img}/:name/:version/*`, pkgGetRoute);
|
587
|
+
|
588
|
+
// Get IMG package overview - scoped
|
589
|
+
// curl -X GET http://localhost:4001/img/@cuz/fuzz/8.4.1/
|
590
|
+
app.get(
|
591
|
+
`/${eik.prop.base_img}/@:scope/:name/:version`,
|
592
|
+
pkgLogRoute,
|
593
|
+
);
|
594
|
+
|
595
|
+
// Get IMG package overview - non-scoped
|
596
|
+
// curl -X GET http://localhost:4001/img/fuzz/8.4.1/
|
597
|
+
app.get(`/${eik.prop.base_img}/:name/:version`, pkgLogRoute);
|
598
|
+
|
599
|
+
// Get IMG package versions - scoped
|
600
|
+
// curl -X GET http://localhost:4001/img/@cuz/fuzz/
|
601
|
+
app.get(`/${eik.prop.base_img}/@:scope/:name`, versionsGetRoute);
|
602
|
+
|
603
|
+
// Get IMG package versions - non-scoped
|
604
|
+
// curl -X GET http://localhost:4001/img/fuzz/
|
605
|
+
app.get(`/${eik.prop.base_img}/:name`, versionsGetRoute);
|
606
|
+
|
607
|
+
// Put IMG package - scoped
|
608
|
+
// curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/img/@cuz/fuzz/8.4.1/
|
609
|
+
app.put(
|
610
|
+
`/${eik.prop.base_img}/@:scope/:name/:version`,
|
611
|
+
authOptions,
|
612
|
+
imgPutRoute,
|
613
|
+
);
|
614
|
+
|
615
|
+
// Put IMG package - non-scoped
|
616
|
+
// curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/img/fuzz/8.4.1/
|
617
|
+
app.put(
|
618
|
+
`/${eik.prop.base_img}/:name/:version`,
|
619
|
+
authOptions,
|
620
|
+
imgPutRoute,
|
621
|
+
);
|
622
|
+
|
550
623
|
//
|
551
624
|
// Import Maps
|
552
625
|
//
|
@@ -714,6 +787,70 @@ const EikService = class EikService {
|
|
714
787
|
aliasDelRoute,
|
715
788
|
);
|
716
789
|
|
790
|
+
//
|
791
|
+
// Alias Image Packages
|
792
|
+
//
|
793
|
+
|
794
|
+
// curl -X GET -L http://localhost:4001/img/@cuz/fuzz/v8
|
795
|
+
app.get(
|
796
|
+
`/${eik.prop.base_img}/@:scope/:name/v:alias`,
|
797
|
+
aliasGetRoute,
|
798
|
+
);
|
799
|
+
|
800
|
+
// curl -X GET -L http://localhost:4001/img/fuzz/v8
|
801
|
+
app.get(`/${eik.prop.base_img}/:name/v:alias`, aliasGetRoute);
|
802
|
+
|
803
|
+
// curl -X GET -L http://localhost:4001/img/@cuz/fuzz/v8/main/index.js
|
804
|
+
app.get(
|
805
|
+
`/${eik.prop.base_img}/@:scope/:name/v:alias/*`,
|
806
|
+
aliasGetRoute,
|
807
|
+
);
|
808
|
+
|
809
|
+
// curl -X GET -L http://localhost:4001/img/fuzz/v8/main/index.js
|
810
|
+
app.get(`/${eik.prop.base_img}/:name/v:alias/*`, aliasGetRoute);
|
811
|
+
|
812
|
+
// curl -X PUT -i -F version=8.4.1 http://localhost:4001/img/@cuz/fuzz/v8
|
813
|
+
app.put(
|
814
|
+
`/${eik.prop.base_img}/@:scope/:name/v:alias`,
|
815
|
+
authOptions,
|
816
|
+
aliasPutRoute,
|
817
|
+
);
|
818
|
+
|
819
|
+
// curl -X PUT -i -F version=8.4.1 http://localhost:4001/img/fuzz/v8
|
820
|
+
app.put(
|
821
|
+
`/${eik.prop.base_img}/:name/v:alias`,
|
822
|
+
authOptions,
|
823
|
+
aliasPutRoute,
|
824
|
+
);
|
825
|
+
|
826
|
+
// curl -X POST -i -F version=8.4.1 http://localhost:4001/img/@cuz/lit-html/v8
|
827
|
+
app.post(
|
828
|
+
`/${eik.prop.base_img}/@:scope/:name/v:alias`,
|
829
|
+
authOptions,
|
830
|
+
aliasPostRoute,
|
831
|
+
);
|
832
|
+
|
833
|
+
// curl -X POST -i -F version=8.4.1 http://localhost:4001/img/lit-html/v8
|
834
|
+
app.post(
|
835
|
+
`/${eik.prop.base_img}/:name/v:alias`,
|
836
|
+
authOptions,
|
837
|
+
aliasPostRoute,
|
838
|
+
);
|
839
|
+
|
840
|
+
// curl -X DELETE http://localhost:4001/img/@cuz/fuzz/v8
|
841
|
+
app.delete(
|
842
|
+
`/${eik.prop.base_img}/@:scope/:name/v:alias`,
|
843
|
+
authOptions,
|
844
|
+
aliasDelRoute,
|
845
|
+
);
|
846
|
+
|
847
|
+
// curl -X DELETE http://localhost:4001/img/fuzz/v8
|
848
|
+
app.delete(
|
849
|
+
`/${eik.prop.base_img}/:name/v:alias`,
|
850
|
+
authOptions,
|
851
|
+
aliasDelRoute,
|
852
|
+
);
|
853
|
+
|
717
854
|
//
|
718
855
|
// Alias Import Maps
|
719
856
|
//
|
package/lib/utils.js
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
import path from 'path';
|
2
2
|
|
3
|
+
function doJoin(a, b) {
|
4
|
+
return path.join(a, b).replace(/\\/g, '/');
|
5
|
+
}
|
6
|
+
|
3
7
|
const sanitizeExtras = (extras, version) => {
|
4
8
|
if (version && extras) {
|
5
|
-
return
|
9
|
+
return doJoin(version, extras);
|
6
10
|
}
|
7
11
|
return extras || '';
|
8
12
|
};
|
9
13
|
|
10
14
|
const sanitizeName = (scope, name) => {
|
11
15
|
if (scope && name) {
|
12
|
-
return
|
16
|
+
return doJoin(scope, name);
|
13
17
|
}
|
14
18
|
return scope || '';
|
15
19
|
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@eik/service",
|
3
|
-
"version": "2.
|
3
|
+
"version": "2.3.1",
|
4
4
|
"description": "Eik REST API as a standalone HTTP service",
|
5
5
|
"type": "module",
|
6
6
|
"main": "./lib/main.js",
|
@@ -15,8 +15,10 @@
|
|
15
15
|
"lint": "eslint .",
|
16
16
|
"lint:fix": "eslint --fix .",
|
17
17
|
"start": "node ./bin/eik-server.js | pino-pretty",
|
18
|
-
"test": "cross-env LOG_LEVEL=fatal
|
19
|
-
"test:
|
18
|
+
"test": "cross-env LOG_LEVEL=fatal npm run test:tap",
|
19
|
+
"test:ci": "cross-env LOG_LEVEL=trace npm run test:tap",
|
20
|
+
"test:snapshots": "cross-env LOG_LEVEL=fatal npm run test:tap -- --snapshot",
|
21
|
+
"test:tap": "tap ./test/**/*.test.js --disable-coverage --allow-empty-coverage",
|
20
22
|
"types": "run-s types:module types:test",
|
21
23
|
"types:module": "tsc",
|
22
24
|
"types:test": "tsc --project tsconfig.test.json"
|
@@ -39,10 +41,10 @@
|
|
39
41
|
},
|
40
42
|
"homepage": "https://github.com/eik-lib/service#readme",
|
41
43
|
"dependencies": {
|
42
|
-
"@eik/core": "1.
|
44
|
+
"@eik/core": "1.4.2",
|
43
45
|
"@eik/sink": "1.2.5",
|
44
46
|
"@eik/sink-file-system": "1.0.1",
|
45
|
-
"@eik/sink-memory": "1.1.
|
47
|
+
"@eik/sink-memory": "1.1.2",
|
46
48
|
"@fastify/compress": "6.5.0",
|
47
49
|
"@fastify/cors": "8.5.0",
|
48
50
|
"@fastify/jwt": "7.2.4",
|
@@ -57,16 +59,18 @@
|
|
57
59
|
"@eik/prettier-config": "1.0.1",
|
58
60
|
"@eik/semantic-release-config": "1.0.0",
|
59
61
|
"@eik/typescript-config": "1.0.0",
|
62
|
+
"@types/mime": "3.0.4",
|
63
|
+
"@types/readable-stream": "4.0.15",
|
60
64
|
"cross-env": "7.0.3",
|
61
65
|
"eslint": "9.8.0",
|
62
66
|
"form-data": "4.0.0",
|
63
|
-
"node-fetch": "3.3.
|
67
|
+
"node-fetch": "3.3.2",
|
64
68
|
"npm-run-all": "4.1.5",
|
65
69
|
"pino-pretty": "10.3.1",
|
66
70
|
"prettier": "3.3.3",
|
67
71
|
"rimraf": "6.0.1",
|
68
72
|
"semantic-release": "24.0.0",
|
69
|
-
"tap": "
|
73
|
+
"tap": "21.0.1",
|
70
74
|
"typescript": "5.5.4",
|
71
75
|
"unique-slug": "4.0.0"
|
72
76
|
}
|
package/types/main.d.ts
CHANGED
@@ -16,6 +16,10 @@ export type EikServiceOptions = {
|
|
16
16
|
* The limit in bytes before PUT /map/ starts returning 413 Content Too Large
|
17
17
|
*/
|
18
18
|
mapMaxFileSize?: number;
|
19
|
+
/**
|
20
|
+
* The limit in bytes before PUT /img/ starts returning 413 Content Too Large
|
21
|
+
*/
|
22
|
+
imgMaxFileSize?: number;
|
19
23
|
};
|
20
24
|
/**
|
21
25
|
* @typedef {object} EikServiceOptions
|
@@ -26,6 +30,7 @@ export type EikServiceOptions = {
|
|
26
30
|
* @property {string} [notFoundCacheControl="public, max-age=5"]
|
27
31
|
* @property {number} [pkgMaxFileSize=10000000] The limit in bytes before PUT /pkg/ starts returning 413 Content Too Large
|
28
32
|
* @property {number} [mapMaxFileSize=1000000] The limit in bytes before PUT /map/ starts returning 413 Content Too Large
|
33
|
+
* @property {number} [imgMaxFileSize=20000000] The limit in bytes before PUT /img/ starts returning 413 Content Too Large
|
29
34
|
*/
|
30
35
|
declare const EikService: {
|
31
36
|
new (options?: EikServiceOptions): {
|
@@ -422,6 +427,90 @@ declare const EikService: {
|
|
422
427
|
readonly [Symbol.toStringTag]: string;
|
423
428
|
}>;
|
424
429
|
};
|
430
|
+
_imgPut: {
|
431
|
+
_pkgMaxFileSize: number;
|
432
|
+
_organizations: [string, string][];
|
433
|
+
_cacheControl: string;
|
434
|
+
_sink: import("@eik/sink").default;
|
435
|
+
_log: import("abslog").ValidLogger;
|
436
|
+
_metrics: import("@metrics/client");
|
437
|
+
_histogram: import("@metrics/client").MetricsHistogram;
|
438
|
+
_orgRegistry: Map<string, string>;
|
439
|
+
_multipart: {
|
440
|
+
_pkgMaxFileSize: number;
|
441
|
+
_legalFields: string[];
|
442
|
+
_legalFiles: string[];
|
443
|
+
_sink: import("@eik/sink").default;
|
444
|
+
_log: import("abslog").ValidLogger;
|
445
|
+
parse(incoming: any): Promise<any>;
|
446
|
+
_handleField({ name, value }: {
|
447
|
+
name: any;
|
448
|
+
value: any;
|
449
|
+
}): {
|
450
|
+
_value: string;
|
451
|
+
_name: string;
|
452
|
+
readonly value: string;
|
453
|
+
readonly name: string;
|
454
|
+
toJSON(): {
|
455
|
+
value: string;
|
456
|
+
name: string;
|
457
|
+
};
|
458
|
+
readonly [Symbol.toStringTag]: string;
|
459
|
+
};
|
460
|
+
_handleFile({ fieldname, file, filename, incoming }: {
|
461
|
+
fieldname: any;
|
462
|
+
file: any;
|
463
|
+
filename: any;
|
464
|
+
incoming: any;
|
465
|
+
}): Promise<any>;
|
466
|
+
_persistFile({ incoming, entry }: {
|
467
|
+
incoming: any;
|
468
|
+
entry: any;
|
469
|
+
}): Promise<any>;
|
470
|
+
readonly [Symbol.toStringTag]: string;
|
471
|
+
};
|
472
|
+
readonly metrics: import("@metrics/client");
|
473
|
+
_parser(incoming: any): Promise<any>;
|
474
|
+
_readVersions(incoming: any): Promise<{
|
475
|
+
_versions: Map<any, any>;
|
476
|
+
_type: string;
|
477
|
+
_name: string;
|
478
|
+
_org: string;
|
479
|
+
readonly versions: [any, any][];
|
480
|
+
readonly type: string;
|
481
|
+
readonly name: string;
|
482
|
+
readonly org: string;
|
483
|
+
setVersion(version: any, integrity: any): void;
|
484
|
+
getVersion(major: any): any;
|
485
|
+
check(version: any): boolean;
|
486
|
+
toJSON(): {
|
487
|
+
versions: [any, any][];
|
488
|
+
type: string;
|
489
|
+
name: string;
|
490
|
+
org: string;
|
491
|
+
};
|
492
|
+
readonly [Symbol.toStringTag]: string;
|
493
|
+
}>;
|
494
|
+
_readVersion(incoming: any): Promise<boolean>;
|
495
|
+
_writeVersions(incoming: any, versions: any): Promise<void>;
|
496
|
+
handler(req: any, user: any, type: any, name: any, version: any): Promise<{
|
497
|
+
_cacheControl: string;
|
498
|
+
_statusCode: number;
|
499
|
+
_mimeType: string;
|
500
|
+
_location: string;
|
501
|
+
_stream: any;
|
502
|
+
_body: any;
|
503
|
+
_etag: string;
|
504
|
+
cacheControl: string;
|
505
|
+
statusCode: number;
|
506
|
+
location: string;
|
507
|
+
mimeType: string;
|
508
|
+
stream: any;
|
509
|
+
body: any;
|
510
|
+
etag: string;
|
511
|
+
readonly [Symbol.toStringTag]: string;
|
512
|
+
}>;
|
513
|
+
};
|
425
514
|
_mapGet: {
|
426
515
|
_organizations: [string, string][];
|
427
516
|
_cacheControl: string;
|