@pnpm/engine.runtime.node-resolver 1101.1.22 → 1101.2.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 +13 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +58 -11
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @pnpm/node.resolver
|
|
2
2
|
|
|
3
|
+
## 1101.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Resolving a Node.js runtime version (`devEngines.runtime` / `runtime:` specifiers) is now much faster: the per-version release metadata is cached in the pnpm cache directory after its signature is verified, and an exact stable version such as `runtime:22.23.2` no longer downloads the Node.js release index. A pinned runtime whose metadata was fetched once resolves without any network access, which removes the noticeable delay on the first `node` invocation in a project pinning an already-downloaded runtime [#13899](https://github.com/pnpm/pnpm/issues/13899).
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies:
|
|
12
|
+
- @pnpm/config.reader@1101.17.0
|
|
13
|
+
- @pnpm/crypto.shasums-file@1100.2.0
|
|
14
|
+
- @pnpm/error@1100.1.2
|
|
15
|
+
|
|
3
16
|
## 1101.1.22
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/lib/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export declare function resolveNodeRuntime(ctx: {
|
|
|
15
15
|
fetchFromRegistry: FetchFromRegistry;
|
|
16
16
|
nodeDownloadMirrors?: Record<string, string>;
|
|
17
17
|
offline?: boolean;
|
|
18
|
+
cacheDir?: string;
|
|
18
19
|
}, wantedDependency: WantedDependency, opts?: Partial<ResolveOptions>): Promise<NodeRuntimeResolveResult | null>;
|
|
19
20
|
export declare function resolveLatestNodeRuntime(ctx: {
|
|
20
21
|
fetchFromRegistry: FetchFromRegistry;
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { fetchShasumsFileCached, fetchVerifiedNodeShasumsFileCached } from '@pnpm/crypto.shasums-file';
|
|
2
2
|
import { PnpmError } from '@pnpm/error';
|
|
3
3
|
import semver from 'semver';
|
|
4
4
|
import versionSelectorType from 'version-selector-type';
|
|
@@ -28,11 +28,32 @@ export async function resolveNodeRuntime(ctx, wantedDependency, opts) {
|
|
|
28
28
|
const versionSpec = normalizeRuntimeSpec(wantedDependency.bareSpecifier.substring('runtime:'.length));
|
|
29
29
|
const { releaseChannel, versionSpecifier } = parseNodeSpecifier(versionSpec);
|
|
30
30
|
const nodeMirrorBaseUrl = getNodeMirror(ctx.nodeDownloadMirrors, releaseChannel);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
// An exact stable-release specifier is its own resolution, so the
|
|
32
|
+
// release-index fetch is skipped for it and existence is proven by the
|
|
33
|
+
// asset-list fetch below.
|
|
34
|
+
const exactVersion = exactReleaseVersion(releaseChannel, versionSpecifier);
|
|
35
|
+
let version = exactVersion;
|
|
36
|
+
if (version == null) {
|
|
37
|
+
version = await resolveNodeVersion(ctx.fetchFromRegistry, versionSpecifier, nodeMirrorBaseUrl) ?? undefined;
|
|
38
|
+
if (!version) {
|
|
39
|
+
throw new PnpmError('NODEJS_VERSION_NOT_FOUND', `Could not find a Node.js version that satisfies ${versionSpec}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
let variants;
|
|
43
|
+
try {
|
|
44
|
+
variants = await readNodeAssets(ctx.fetchFromRegistry, { nodeMirrorBaseUrl, version, releaseChannel, cacheDir: ctx.cacheDir });
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
// The exact-specifier pick skipped the release index, so a failed asset
|
|
48
|
+
// read is ambiguous: the version may simply not exist. Consult the index
|
|
49
|
+
// now, purely to raise the same NODEJS_VERSION_NOT_FOUND the index-first
|
|
50
|
+
// path raises for a nonexistent version; any other outcome re-raises the
|
|
51
|
+
// asset error unchanged.
|
|
52
|
+
if (exactVersion != null && await versionMissingFromIndex(ctx.fetchFromRegistry, exactVersion, nodeMirrorBaseUrl)) {
|
|
53
|
+
throw new PnpmError('NODEJS_VERSION_NOT_FOUND', `Could not find a Node.js version that satisfies ${versionSpec}`);
|
|
54
|
+
}
|
|
55
|
+
throw err;
|
|
34
56
|
}
|
|
35
|
-
const variants = await readNodeAssets(ctx.fetchFromRegistry, nodeMirrorBaseUrl, version, releaseChannel);
|
|
36
57
|
const range = createNodeRuntimeVersionSpec(versionSpec, version, wantedDependency);
|
|
37
58
|
return {
|
|
38
59
|
id: `node@runtime:${version}`,
|
|
@@ -75,20 +96,44 @@ function createNodeRuntimeVersionSpec(versionSpec, resolvedVersion, wantedDepend
|
|
|
75
96
|
return `~${resolvedVersion}`;
|
|
76
97
|
return resolvedVersion;
|
|
77
98
|
}
|
|
78
|
-
|
|
99
|
+
/**
|
|
100
|
+
* The concrete version an exact stable-release specifier names, when the
|
|
101
|
+
* specifier is already in canonical `X.Y.Z` form. Such a specifier needs no
|
|
102
|
+
* release-index lookup: the index would resolve it to itself. Prereleases are
|
|
103
|
+
* excluded — on the `release` channel they never exist, so routing them
|
|
104
|
+
* through the index keeps the canonical not-found error path.
|
|
105
|
+
*/
|
|
106
|
+
function exactReleaseVersion(releaseChannel, versionSpecifier) {
|
|
107
|
+
if (releaseChannel !== 'release')
|
|
108
|
+
return undefined;
|
|
109
|
+
const parsed = semver.parse(versionSpecifier);
|
|
110
|
+
if (parsed == null || parsed.prerelease.length > 0 || parsed.build.length > 0 || parsed.version !== versionSpecifier)
|
|
111
|
+
return undefined;
|
|
112
|
+
return parsed.version;
|
|
113
|
+
}
|
|
114
|
+
async function versionMissingFromIndex(fetch, version, nodeMirrorBaseUrl) {
|
|
115
|
+
try {
|
|
116
|
+
return (await resolveNodeVersion(fetch, version, nodeMirrorBaseUrl)) == null;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async function readNodeAssets(fetch, opts) {
|
|
123
|
+
const { nodeMirrorBaseUrl, version, releaseChannel, cacheDir } = opts;
|
|
79
124
|
// The mirror is repository-configurable, so the SHASUMS file's hashes are only
|
|
80
125
|
// trustworthy once its OpenPGP signature is verified against the Node.js
|
|
81
126
|
// release keys embedded in pnpm. Only the `release` channel publishes a signed
|
|
82
127
|
// SHASUMS256.txt; pre-release channels (rc, nightly, …) are unsigned by Node,
|
|
83
128
|
// so they cannot be verified this way.
|
|
84
|
-
const assets = await readNodeAssetsFromMirror(fetch, { nodeMirrorBaseUrl, version, muslOnly: false, verifySignature: releaseChannel === 'release' });
|
|
129
|
+
const assets = await readNodeAssetsFromMirror(fetch, { nodeMirrorBaseUrl, version, muslOnly: false, verifySignature: releaseChannel === 'release', cacheDir });
|
|
85
130
|
// When using the default mirror, also fetch musl variants from unofficial-builds.nodejs.org,
|
|
86
131
|
// since musl builds are not available on the official mirror. That URL is hardcoded (not
|
|
87
132
|
// repository-configurable) and signed by a different (unofficial-builds) key, so it is trusted
|
|
88
133
|
// over TLS rather than verified against the official release keys.
|
|
89
134
|
if (nodeMirrorBaseUrl === DEFAULT_NODE_MIRROR_BASE_URL) {
|
|
90
135
|
try {
|
|
91
|
-
const muslAssets = await readNodeAssetsFromMirror(fetch, { nodeMirrorBaseUrl: UNOFFICIAL_NODE_MIRROR_BASE_URL, version, muslOnly: true, verifySignature: false });
|
|
136
|
+
const muslAssets = await readNodeAssetsFromMirror(fetch, { nodeMirrorBaseUrl: UNOFFICIAL_NODE_MIRROR_BASE_URL, version, muslOnly: true, verifySignature: false, cacheDir });
|
|
92
137
|
assets.push(...muslAssets);
|
|
93
138
|
}
|
|
94
139
|
catch {
|
|
@@ -98,11 +143,13 @@ async function readNodeAssets(fetch, nodeMirrorBaseUrl, version, releaseChannel)
|
|
|
98
143
|
return assets;
|
|
99
144
|
}
|
|
100
145
|
async function readNodeAssetsFromMirror(fetch, opts) {
|
|
101
|
-
const { nodeMirrorBaseUrl, version, muslOnly, verifySignature } = opts;
|
|
146
|
+
const { nodeMirrorBaseUrl, version, muslOnly, verifySignature, cacheDir } = opts;
|
|
147
|
+
// The URL is pinned to one released version, which is what makes it
|
|
148
|
+
// eligible for the SHASUMS disk cache.
|
|
102
149
|
const integritiesFileUrl = `${nodeMirrorBaseUrl}v${version}/SHASUMS256.txt`;
|
|
103
150
|
const shasumsFileItems = verifySignature
|
|
104
|
-
? await
|
|
105
|
-
: await
|
|
151
|
+
? await fetchVerifiedNodeShasumsFileCached(fetch, integritiesFileUrl, { cacheDir })
|
|
152
|
+
: await fetchShasumsFileCached(fetch, integritiesFileUrl, { cacheDir });
|
|
106
153
|
const escaped = version.replace(/\\/g, '\\\\').replace(/\./g, '\\.');
|
|
107
154
|
// The second capture group uses [^.-]+ to stop at a dash, so that the optional
|
|
108
155
|
// third group can capture the '-musl' suffix separately (e.g. 'x64' + '-musl').
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/engine.runtime.node-resolver",
|
|
3
|
-
"version": "1101.
|
|
3
|
+
"version": "1101.2.0",
|
|
4
4
|
"description": "Resolves a Node.js version specifier to an exact Node.js version",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"!*.map"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@pnpm/config.reader": "1101.
|
|
33
|
-
"@pnpm/crypto.shasums-file": "1100.
|
|
34
|
-
"@pnpm/error": "1100.1.
|
|
32
|
+
"@pnpm/config.reader": "1101.17.0",
|
|
33
|
+
"@pnpm/crypto.shasums-file": "1100.2.0",
|
|
34
|
+
"@pnpm/error": "1100.1.2",
|
|
35
35
|
"@pnpm/fetching.types": "1100.0.3",
|
|
36
36
|
"@pnpm/resolving.resolver-base": "1101.1.0",
|
|
37
37
|
"@pnpm/types": "1101.9.0",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@jest/globals": "30.4.1",
|
|
43
|
-
"@pnpm/engine.runtime.node-resolver": "1101.
|
|
44
|
-
"@pnpm/network.fetch": "1100.1.
|
|
43
|
+
"@pnpm/engine.runtime.node-resolver": "1101.2.0",
|
|
44
|
+
"@pnpm/network.fetch": "1100.1.12",
|
|
45
45
|
"@types/semver": "7.8.0"
|
|
46
46
|
},
|
|
47
47
|
"engines": {
|