@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 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
- # Eik HTTP Service
1
+ # @eik/service
2
2
 
3
- As a standalone running HTTP service exposing the Eik Service.
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, { join } from '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(), '/eik'),
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, `/config/${env}.yaml`));
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 path.join(version, extras);
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 path.join(scope, name);
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.2.1",
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 tap ./test --disable-coverage --allow-empty-coverage --serial=test",
19
- "test:snapshots": "cross-env LOG_LEVEL=fatal tap --snapshot --disable-coverage --allow-empty-coverage --serial=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.3.58",
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.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.1",
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": "18.8.0",
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;