@eik/service 5.0.53 → 5.1.0

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,17 @@
1
+ # [5.1.0](https://github.com/eik-lib/service/compare/v5.0.54...v5.1.0) (2025-10-13)
2
+
3
+
4
+ ### Features
5
+
6
+ * add variant of alias GET routes that use stale-while-revalidate ([#688](https://github.com/eik-lib/service/issues/688)) ([b94cb4e](https://github.com/eik-lib/service/commit/b94cb4ec7146d916f96adfbcd7eb6bc7eb5b4924))
7
+
8
+ ## [5.0.54](https://github.com/eik-lib/service/compare/v5.0.53...v5.0.54) (2025-10-13)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **deps:** update dependency @eik/core to v2.1.2 ([#687](https://github.com/eik-lib/service/issues/687)) ([d9fd353](https://github.com/eik-lib/service/commit/d9fd353b96c6d47375a7d8f7e18ddfe20c8d3d2a))
14
+
1
15
  ## [5.0.53](https://github.com/eik-lib/service/compare/v5.0.52...v5.0.53) (2025-10-06)
2
16
 
3
17
 
package/lib/main.js CHANGED
@@ -18,6 +18,7 @@ import * as utils from "./utils.js";
18
18
  * @property {import('pino').Logger} [logger]
19
19
  * @property {import('@eik/sink').default} [customSink] [Deprecated] Use sink instead
20
20
  * @property {string} [aliasCacheControl]
21
+ * @property {string} [staleWhileRevalidateCacheControl] Set the cache-control header used by the stale-while-revalidate alias GET URLs
21
22
  * @property {string} [notFoundCacheControl="public, max-age=5"]
22
23
  * @property {number} [pkgMaxFileSize=10000000] The limit in bytes before PUT /pkg/ starts returning 413 Content Too Large
23
24
  * @property {number} [mapMaxFileSize=1000000] The limit in bytes before PUT /map/ starts returning 413 Content Too Large
@@ -33,6 +34,7 @@ const EikService = class EikService {
33
34
  const {
34
35
  customSink,
35
36
  notFoundCacheControl,
37
+ staleWhileRevalidateCacheControl,
36
38
  aliasCacheControl,
37
39
  pkgMaxFileSize = 10000000,
38
40
  mapMaxFileSize = 1000000,
@@ -92,6 +94,12 @@ const EikService = class EikService {
92
94
  logger,
93
95
  cacheControl: aliasCacheControl,
94
96
  });
97
+ this._aliasGetSWR = new eik.http.AliasGetV2({
98
+ organizations,
99
+ sink,
100
+ logger,
101
+ cacheControl: staleWhileRevalidateCacheControl,
102
+ });
95
103
  this._aliasPut = new eik.http.AliasPut({ organizations, sink, logger });
96
104
  this._authPost = new eik.http.AuthPost({
97
105
  organizations,
@@ -420,6 +428,23 @@ const EikService = class EikService {
420
428
  reply.redirect(outgoing.location);
421
429
  };
422
430
 
431
+ // Relies on stale-while-revalidate to serve the aliased asset without a redirect
432
+ const aliasGetSWRRoute = async (request, reply) => {
433
+ const params = utils.sanitizeParameters(request.raw.url);
434
+ const outgoing = await this._aliasGetSWR.handler(
435
+ request.raw,
436
+ params.type,
437
+ params.name,
438
+ params.alias,
439
+ params.extras,
440
+ );
441
+ reply.header("cache-control", outgoing.cacheControl);
442
+ reply.header("etag", outgoing.etag);
443
+ reply.type(outgoing.mimeType);
444
+ reply.code(outgoing.statusCode);
445
+ return reply.send(outgoing.stream);
446
+ };
447
+
423
448
  const aliasPutRoute = async (request, reply) => {
424
449
  const params = utils.sanitizeParameters(request.raw.url);
425
450
  const outgoing = await this._aliasPut.handler(
@@ -641,6 +666,23 @@ const EikService = class EikService {
641
666
  // curl -X GET -L http://localhost:4001/pkg/fuzz/v8/main/index.js
642
667
  app.get(`/${eik.prop.base_pkg}/:name/v:alias/*`, aliasGetRoute);
643
668
 
669
+ // Redirect these as usual, just a dev nicety
670
+ // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/~8
671
+ app.get(`/${eik.prop.base_pkg}/@:scope/:name/~:alias`, aliasGetRoute);
672
+
673
+ // Redirect these as usual, just a dev nicety
674
+ // curl -X GET -L http://localhost:4001/pkg/fuzz/~8
675
+ app.get(`/${eik.prop.base_pkg}/:name/~:alias`, aliasGetRoute);
676
+
677
+ // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/~8/main/index.js
678
+ app.get(
679
+ `/${eik.prop.base_pkg}/@:scope/:name/~:alias/*`,
680
+ aliasGetSWRRoute,
681
+ );
682
+
683
+ // curl -X GET -L http://localhost:4001/pkg/fuzz/~8/main/index.js
684
+ app.get(`/${eik.prop.base_pkg}/:name/~:alias/*`, aliasGetSWRRoute);
685
+
644
686
  // curl -X PUT -i -F version=8.4.1 http://localhost:4001/pkg/@cuz/fuzz/v8
645
687
  app.put(
646
688
  `/${eik.prop.base_pkg}/@:scope/:name/v:alias`,
@@ -699,6 +741,23 @@ const EikService = class EikService {
699
741
  // curl -X GET -L http://localhost:4001/npm/fuzz/v8/main/index.js
700
742
  app.get(`/${eik.prop.base_npm}/:name/v:alias/*`, aliasGetRoute);
701
743
 
744
+ // Redirect these as usual, just a dev nicety
745
+ // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/~8
746
+ app.get(`/${eik.prop.base_npm}/@:scope/:name/~:alias`, aliasGetRoute);
747
+
748
+ // Redirect these as usual, just a dev nicety
749
+ // curl -X GET -L http://localhost:4001/pkg/fuzz/~8
750
+ app.get(`/${eik.prop.base_npm}/:name/~:alias`, aliasGetRoute);
751
+
752
+ // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/~8/main/index.js
753
+ app.get(
754
+ `/${eik.prop.base_npm}/@:scope/:name/~:alias/*`,
755
+ aliasGetSWRRoute,
756
+ );
757
+
758
+ // curl -X GET -L http://localhost:4001/pkg/fuzz/~8/main/index.js
759
+ app.get(`/${eik.prop.base_npm}/:name/~:alias/*`, aliasGetSWRRoute);
760
+
702
761
  // curl -X PUT -i -F version=8.4.1 http://localhost:4001/npm/@cuz/fuzz/v8
703
762
  app.put(
704
763
  `/${eik.prop.base_npm}/@:scope/:name/v:alias`,
@@ -757,6 +816,23 @@ const EikService = class EikService {
757
816
  // curl -X GET -L http://localhost:4001/img/fuzz/v8/main/index.js
758
817
  app.get(`/${eik.prop.base_img}/:name/v:alias/*`, aliasGetRoute);
759
818
 
819
+ // Redirect these as usual, just a dev nicety
820
+ // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/~8
821
+ app.get(`/${eik.prop.base_img}/@:scope/:name/~:alias`, aliasGetRoute);
822
+
823
+ // Redirect these as usual, just a dev nicety
824
+ // curl -X GET -L http://localhost:4001/pkg/fuzz/~8
825
+ app.get(`/${eik.prop.base_img}/:name/~:alias`, aliasGetRoute);
826
+
827
+ // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/~8/main/index.js
828
+ app.get(
829
+ `/${eik.prop.base_img}/@:scope/:name/~:alias/*`,
830
+ aliasGetSWRRoute,
831
+ );
832
+
833
+ // curl -X GET -L http://localhost:4001/pkg/fuzz/~8/main/index.js
834
+ app.get(`/${eik.prop.base_img}/:name/~:alias/*`, aliasGetSWRRoute);
835
+
760
836
  // curl -X PUT -i -F version=8.4.1 http://localhost:4001/img/@cuz/fuzz/v8
761
837
  app.put(
762
838
  `/${eik.prop.base_img}/@:scope/:name/v:alias`,
package/lib/utils.js CHANGED
@@ -19,19 +19,26 @@ const sanitizeName = (scope, name) => {
19
19
  };
20
20
 
21
21
  const sanitizeAlias = (alias = "") => {
22
- if (alias.startsWith("v")) {
22
+ if (alias.startsWith("v") || alias.startsWith("~")) {
23
23
  return alias.slice(1);
24
24
  }
25
25
  return alias;
26
26
  };
27
27
 
28
+ const sanitizeVersion = (version = "") => {
29
+ if (version.startsWith("~")) {
30
+ return `v${version.slice(1)}`;
31
+ }
32
+ return version;
33
+ };
34
+
28
35
  const sanitizeParameters = (url = "") => {
29
36
  const { pathname } = new URL(url, "http://localhost/");
30
37
  const paths = pathname.split("/");
31
38
 
32
39
  if (paths[2] && paths[2].startsWith("@")) {
33
40
  return {
34
- version: paths[4] || "",
41
+ version: sanitizeVersion(paths[4]),
35
42
  extras: sanitizeExtras(paths.slice(5).join("/")),
36
43
  alias: sanitizeAlias(paths[4]),
37
44
  name: sanitizeName(paths[2] || "", paths[3] || ""),
@@ -40,7 +47,7 @@ const sanitizeParameters = (url = "") => {
40
47
  }
41
48
 
42
49
  return {
43
- version: paths[3] || "",
50
+ version: sanitizeVersion(paths[3]),
44
51
  extras: sanitizeExtras(paths.slice(4).join("/")),
45
52
  alias: sanitizeAlias(paths[3]),
46
53
  name: sanitizeName(paths[2] || ""),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eik/service",
3
- "version": "5.0.53",
3
+ "version": "5.1.0",
4
4
  "description": "Eik REST API as a standalone HTTP service",
5
5
  "type": "module",
6
6
  "main": "./lib/main.js",
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "homepage": "https://github.com/eik-lib/service#readme",
46
46
  "dependencies": {
47
- "@eik/core": "2.1.0",
47
+ "@eik/core": "2.1.2",
48
48
  "@eik/sink": "1.2.5",
49
49
  "@eik/sink-file-system": "2.0.13",
50
50
  "@eik/sink-memory": "2.0.12",
package/types/main.d.ts CHANGED
@@ -7,6 +7,10 @@ export type EikServiceOptions = {
7
7
  */
8
8
  customSink?: import("@eik/sink").default;
9
9
  aliasCacheControl?: string;
10
+ /**
11
+ * Set the cache-control header used by the stale-while-revalidate alias GET URLs
12
+ */
13
+ staleWhileRevalidateCacheControl?: string;
10
14
  notFoundCacheControl?: string;
11
15
  /**
12
16
  * The limit in bytes before PUT /pkg/ starts returning 413 Content Too Large
@@ -27,6 +31,7 @@ export type EikServiceOptions = {
27
31
  * @property {import('pino').Logger} [logger]
28
32
  * @property {import('@eik/sink').default} [customSink] [Deprecated] Use sink instead
29
33
  * @property {string} [aliasCacheControl]
34
+ * @property {string} [staleWhileRevalidateCacheControl] Set the cache-control header used by the stale-while-revalidate alias GET URLs
30
35
  * @property {string} [notFoundCacheControl="public, max-age=5"]
31
36
  * @property {number} [pkgMaxFileSize=10000000] The limit in bytes before PUT /pkg/ starts returning 413 Content Too Large
32
37
  * @property {number} [mapMaxFileSize=1000000] The limit in bytes before PUT /map/ starts returning 413 Content Too Large
@@ -164,6 +169,34 @@ declare const EikService: {
164
169
  readonly [Symbol.toStringTag]: string;
165
170
  }>;
166
171
  };
172
+ _aliasGetSWR: {
173
+ _organizations: [string, string][];
174
+ _cacheControl: string;
175
+ _sink: import("@eik/sink").default;
176
+ _etag: boolean;
177
+ _log: import("abslog").ValidLogger;
178
+ _metrics: import("@metrics/client");
179
+ _histogram: import("@metrics/client").MetricsHistogram;
180
+ _orgRegistry: Map<string, string>;
181
+ readonly metrics: import("@metrics/client");
182
+ handler(req: any, type: any, name: any, alias: any, extra: any): Promise<{
183
+ _cacheControl: string;
184
+ _statusCode: number;
185
+ _mimeType: string;
186
+ _location: string;
187
+ _stream: any;
188
+ _body: any;
189
+ _etag: string;
190
+ cacheControl: string;
191
+ statusCode: number;
192
+ location: string;
193
+ mimeType: string;
194
+ stream: any;
195
+ body: any;
196
+ etag: string;
197
+ readonly [Symbol.toStringTag]: string;
198
+ }>;
199
+ };
167
200
  _aliasPut: {
168
201
  _organizations: [string, string][];
169
202
  _cacheControl: string;