@vltpkg/package-info 1.0.9 → 1.0.10
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/dist/index.js +39 -10
- package/package.json +14 -14
package/dist/index.js
CHANGED
|
@@ -26,6 +26,15 @@ const manifestCacheMaxAge = 5 * 60 * 1000;
|
|
|
26
26
|
const noRegistryError = (spec) => error('No registry configured to resolve this spec. Set "registry" in ' +
|
|
27
27
|
'vlt.json, pass --registry, or run `vlt login --registry=<url>`. ' +
|
|
28
28
|
'See https://docs.vlt.sh/cli', { code: 'ECONFIG', spec });
|
|
29
|
+
/**
|
|
30
|
+
* A selector that can point at a different version tomorrow: a dist tag,
|
|
31
|
+
* or a range matching anything (`*`, empty string). Manifest results for
|
|
32
|
+
* these are not cached to disk, and packument requests for them force a
|
|
33
|
+
* revalidation of the registry client's cache entry.
|
|
34
|
+
*
|
|
35
|
+
* Takes a *final* spec (`spec.final`), same as `pickManifest` sees.
|
|
36
|
+
*/
|
|
37
|
+
const isMovingSelector = (f) => !!(f.distTag || f.range?.isAny);
|
|
29
38
|
export class PackageInfoClient {
|
|
30
39
|
#registryClient;
|
|
31
40
|
#projectRoot;
|
|
@@ -39,7 +48,9 @@ export class PackageInfoClient {
|
|
|
39
48
|
#cachePath;
|
|
40
49
|
// In-flight coalescing key is `${registry}${name}` — no representation
|
|
41
50
|
// component. Safe only because every caller requests the same full
|
|
42
|
-
// packument (see #fetchPackument).
|
|
51
|
+
// packument (see #fetchPackument). The one thing that does vary per
|
|
52
|
+
// caller is forceRevalidate, so record it and let a moving selector
|
|
53
|
+
// reuse a forced promise but never a non-forced one (see packument()).
|
|
43
54
|
#packumentPromises = new Map();
|
|
44
55
|
// unique temp file names for atomic manifest cache writes
|
|
45
56
|
#manifestWriteRandom = randomBytes(6).toString('hex');
|
|
@@ -333,11 +344,9 @@ export class PackageInfoClient {
|
|
|
333
344
|
if (options.before) {
|
|
334
345
|
return;
|
|
335
346
|
}
|
|
336
|
-
//
|
|
337
|
-
// matches any range (such as a semver range of `*` or empty string)
|
|
338
|
-
// then we skip caching
|
|
347
|
+
// a moving selector's result is variable, so don't cache it
|
|
339
348
|
const f = spec.final;
|
|
340
|
-
if (f
|
|
349
|
+
if (isMovingSelector(f)) {
|
|
341
350
|
return;
|
|
342
351
|
}
|
|
343
352
|
const key = this.#manifestCacheKey(f, options);
|
|
@@ -660,16 +669,30 @@ export class PackageInfoClient {
|
|
|
660
669
|
throw noRegistryError(spec);
|
|
661
670
|
// Coalescing key has no representation component (see #fetchPackument).
|
|
662
671
|
const packumentKey = `${registry}${name}`;
|
|
672
|
+
const forced = isMovingSelector(f);
|
|
663
673
|
const inflight = this.#packumentPromises.get(packumentKey);
|
|
664
|
-
|
|
665
|
-
|
|
674
|
+
// a moving selector must not ride along on a non-forced request:
|
|
675
|
+
// that one can settle to a fresh-but-stale cache hit, which is
|
|
676
|
+
// exactly what forceRevalidate exists to avoid. the other
|
|
677
|
+
// direction is fine -- a forced result is never staler.
|
|
678
|
+
// costs at most one extra concurrent GET for the same packument
|
|
679
|
+
// when both shapes are asked for at once.
|
|
680
|
+
if (inflight && (!forced || inflight.forced))
|
|
681
|
+
return inflight.promise;
|
|
666
682
|
const pakuURL = new URL(name, registry);
|
|
667
683
|
const promise = this.#fetchPackument(spec, options, pakuURL);
|
|
668
|
-
|
|
669
|
-
|
|
684
|
+
const record = { promise, forced };
|
|
685
|
+
this.#packumentPromises.set(packumentKey, record);
|
|
686
|
+
// Clean up once settled so we don't leak memory, unless a forced
|
|
687
|
+
// request has since taken the slot over.
|
|
670
688
|
// Use .then/.catch instead of .finally to avoid creating
|
|
671
689
|
// an unhandled rejection from the derived promise.
|
|
672
|
-
|
|
690
|
+
const clear = () => {
|
|
691
|
+
if (this.#packumentPromises.get(packumentKey) === record) {
|
|
692
|
+
this.#packumentPromises.delete(packumentKey);
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
promise.then(clear, clear);
|
|
673
696
|
return promise;
|
|
674
697
|
}
|
|
675
698
|
}
|
|
@@ -703,6 +726,12 @@ export class PackageInfoClient {
|
|
|
703
726
|
const response = await (await this.getRegistryClient()).request(pakuURL, {
|
|
704
727
|
headers: { accept: 'application/json' },
|
|
705
728
|
...(useCache === false ? { useCache } : {}),
|
|
729
|
+
// costs a conditional GET per moving selector on an otherwise warm
|
|
730
|
+
// cache, install included. 304s are cheap but not free; the
|
|
731
|
+
// alternative is serving a dist tag that moved (#1656).
|
|
732
|
+
...(isMovingSelector(spec.final) ?
|
|
733
|
+
{ forceRevalidate: true }
|
|
734
|
+
: {}),
|
|
706
735
|
});
|
|
707
736
|
if (response.statusCode !== 200) {
|
|
708
737
|
throw this.#resolveError(spec, options, 'failed to fetch packument', {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vltpkg/package-info",
|
|
3
3
|
"description": "Resolve and fetch package metadata and tarballs",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.10",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/vltpkg/vltpkg.git",
|
|
@@ -13,17 +13,17 @@
|
|
|
13
13
|
"url": "http://vlt.sh"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@vltpkg/error-cause": "1.0.
|
|
17
|
-
"@vltpkg/git": "1.0.
|
|
18
|
-
"@vltpkg/output": "1.0.
|
|
19
|
-
"@vltpkg/package-json": "1.0.
|
|
20
|
-
"@vltpkg/pick-manifest": "1.0.
|
|
21
|
-
"@vltpkg/registry-client": "1.0.
|
|
22
|
-
"@vltpkg/spec": "1.0.
|
|
23
|
-
"@vltpkg/tar": "1.0.
|
|
24
|
-
"@vltpkg/types": "1.0.
|
|
25
|
-
"@vltpkg/workspaces": "1.0.
|
|
26
|
-
"@vltpkg/xdg": "1.0.
|
|
16
|
+
"@vltpkg/error-cause": "1.0.10",
|
|
17
|
+
"@vltpkg/git": "1.0.10",
|
|
18
|
+
"@vltpkg/output": "1.0.10",
|
|
19
|
+
"@vltpkg/package-json": "1.0.10",
|
|
20
|
+
"@vltpkg/pick-manifest": "1.0.10",
|
|
21
|
+
"@vltpkg/registry-client": "1.0.10",
|
|
22
|
+
"@vltpkg/spec": "1.0.10",
|
|
23
|
+
"@vltpkg/tar": "1.0.10",
|
|
24
|
+
"@vltpkg/types": "1.0.10",
|
|
25
|
+
"@vltpkg/workspaces": "1.0.10",
|
|
26
|
+
"@vltpkg/xdg": "1.0.10",
|
|
27
27
|
"ssri": "^13.0.0",
|
|
28
28
|
"tar": "^7.5.2"
|
|
29
29
|
},
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"@types/node": "^22.19.2",
|
|
33
33
|
"@types/pacote": "^11.1.8",
|
|
34
34
|
"@vltpkg/benchmark": "0.0.0",
|
|
35
|
-
"@vltpkg/cache-unzip": "1.0.
|
|
36
|
-
"@vltpkg/vlt-json": "1.0.
|
|
35
|
+
"@vltpkg/cache-unzip": "1.0.10",
|
|
36
|
+
"@vltpkg/vlt-json": "1.0.10",
|
|
37
37
|
"eslint": "^9.39.1",
|
|
38
38
|
"pacote": "^21.0.4",
|
|
39
39
|
"prettier": "^3.7.4",
|