@pnpm/deps.graph-hasher 1100.2.18 → 1100.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 +28 -0
- package/lib/index.d.ts +43 -3
- package/lib/index.js +126 -51
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @pnpm/calc-dep-state
|
|
2
2
|
|
|
3
|
+
## 1100.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fixed global virtual store hashes for dependency cycles. Every package that transitively depends on an allowed build now includes the engine in its store path, independent of traversal order [pnpm/pnpm#14341](https://github.com/pnpm/pnpm/issues/14341).
|
|
8
|
+
|
|
9
|
+
- Updated dependencies:
|
|
10
|
+
- @pnpm/lockfile.types@1100.1.1
|
|
11
|
+
- @pnpm/lockfile.utils@1102.1.1
|
|
12
|
+
|
|
13
|
+
## 1100.3.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- Added an opt-in proof of concept that lets installs reuse a dependency's build output across machines, by publishing and restoring signed, organization-scoped artifacts through pnpr instead of running the lifecycle scripts locally.
|
|
18
|
+
|
|
19
|
+
Configure it with the new `remoteSideEffectsCache` setting. A workspace names the eligible `organization` and `packages`; everything describing the act of signing — `publish`, `keyId`, `builderId`, `trustedKeys`, `privateKey` and the provenance fields — is refused in `pnpm-workspace.yaml` and read from the global config file or the environment instead.
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies:
|
|
24
|
+
- @pnpm/deps.path@1101.0.1
|
|
25
|
+
- @pnpm/engine.runtime.system-version@1100.0.11
|
|
26
|
+
- @pnpm/lockfile.types@1100.1.0
|
|
27
|
+
- @pnpm/lockfile.utils@1102.1.0
|
|
28
|
+
- @pnpm/resolving.resolver-base@1101.2.0
|
|
29
|
+
- @pnpm/types@1102.1.0
|
|
30
|
+
|
|
3
31
|
## 1100.2.18
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
package/lib/index.d.ts
CHANGED
|
@@ -51,6 +51,31 @@ export interface DepsGraphNode<T extends string> {
|
|
|
51
51
|
export interface DepsStateCache {
|
|
52
52
|
[depPath: string]: string;
|
|
53
53
|
}
|
|
54
|
+
export declare const DEPENDENCY_SIDE_EFFECTS_INPUT_KEY_PREFIX = "dependency-side-effects:v1:";
|
|
55
|
+
export interface CalcDepStateInputKeyOptions<T extends string> {
|
|
56
|
+
depsGraph: DepsGraph<T>;
|
|
57
|
+
depPath: T;
|
|
58
|
+
patchFileHash?: string;
|
|
59
|
+
supportedArchitectures?: SupportedArchitectures;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Compute the machine-independent lookup key for a remotely shareable
|
|
63
|
+
* dependency build.
|
|
64
|
+
*
|
|
65
|
+
* `depsGraph` must contain `depPath`, and every reachable node must provide
|
|
66
|
+
* either `fullPkgId` or the resolution metadata needed to derive it. The
|
|
67
|
+
* function does not mutate the graph or caller state. Each call uses an
|
|
68
|
+
* isolated cache, so the result is independent of earlier roots and platform
|
|
69
|
+
* selections.
|
|
70
|
+
*
|
|
71
|
+
* The returned key starts with {@link DEPENDENCY_SIDE_EFFECTS_INPUT_KEY_PREFIX},
|
|
72
|
+
* followed by the recursive dependency-graph hash and, when non-empty, the
|
|
73
|
+
* patch-file hash. Host identity is excluded and advertised by the artifact's
|
|
74
|
+
* signed compatibility constraints. When a resolution contains platform
|
|
75
|
+
* variations, `supportedArchitectures` selects the source integrity included
|
|
76
|
+
* in the graph hash.
|
|
77
|
+
*/
|
|
78
|
+
export declare function calcDepStateInputKey<T extends string>(opts: CalcDepStateInputKeyOptions<T>): string;
|
|
54
79
|
export declare function calcDepState<T extends string>(depsGraph: DepsGraph<T>, cache: DepsStateCache, depPath: string, opts: {
|
|
55
80
|
patchFileHash?: string;
|
|
56
81
|
includeDepGraphHash: boolean;
|
|
@@ -101,11 +126,11 @@ export interface GraphNodeHashOptions {
|
|
|
101
126
|
lockfileDir?: string;
|
|
102
127
|
}
|
|
103
128
|
export declare function iterateHashedGraphNodes<T extends PkgMeta>(graph: DepsGraph<DepPath>, pkgMetaIterator: PkgMetaIterator<T>, opts?: GraphNodeHashOptions): IterableIterator<HashedDepPath<T>>;
|
|
104
|
-
export declare function calcGraphNodeHash<T extends PkgMeta>({ graph, cache,
|
|
129
|
+
export declare function calcGraphNodeHash<T extends PkgMeta>({ graph, cache, buildRequiredDepPaths, supportedArchitectures, nodeVersion, lockfileDir }: {
|
|
105
130
|
graph: DepsGraph<DepPath>;
|
|
106
131
|
cache: DepsStateCache;
|
|
107
|
-
|
|
108
|
-
|
|
132
|
+
/** See {@link computeBuildRequiredDepPaths}. */
|
|
133
|
+
buildRequiredDepPaths?: Set<DepPath>;
|
|
109
134
|
supportedArchitectures?: SupportedArchitectures;
|
|
110
135
|
/** See {@link GraphNodeHashOptions.nodeVersion}. */
|
|
111
136
|
nodeVersion?: string;
|
|
@@ -127,3 +152,18 @@ export interface PkgMetaAndSnapshot extends PkgMeta {
|
|
|
127
152
|
}
|
|
128
153
|
export declare function iteratePkgMeta(lockfile: LockfileObject, graph: DepsGraph<DepPath>): PkgMetaIterator<PkgMetaAndSnapshot>;
|
|
129
154
|
export declare function lockfileToDepGraph(lockfile: LockfileObject, supportedArchitectures?: SupportedArchitectures, lockfileDir?: string): DepsGraph<DepPath>;
|
|
155
|
+
/**
|
|
156
|
+
* Expand `builtDepPaths` to every node that is, or transitively depends
|
|
157
|
+
* on, one of them.
|
|
158
|
+
*
|
|
159
|
+
* The result gates the engine string in {@link calcGraphNodeHash}: only a
|
|
160
|
+
* package that may run a build script — or that depends on one — keeps the
|
|
161
|
+
* engine in its GVS hash. It is computed as one graph-wide reverse closure,
|
|
162
|
+
* so a package inside a dependency cycle gets the same answer no matter
|
|
163
|
+
* which node the hasher reaches it from.
|
|
164
|
+
*
|
|
165
|
+
* A path with no node in `graph` is kept and still marks whatever depends on
|
|
166
|
+
* it: the built set comes from the allowBuild policy rather than the graph,
|
|
167
|
+
* so the two can disagree.
|
|
168
|
+
*/
|
|
169
|
+
export declare function computeBuildRequiredDepPaths(graph: DepsGraph<DepPath>, builtDepPaths: Set<DepPath>): Set<DepPath>;
|
package/lib/index.js
CHANGED
|
@@ -71,11 +71,52 @@ export function readSnapshotRuntimePin(children) {
|
|
|
71
71
|
const ref = children?.node;
|
|
72
72
|
return ref != null ? extractRuntimeNodeVersion(ref) : undefined;
|
|
73
73
|
}
|
|
74
|
+
export const DEPENDENCY_SIDE_EFFECTS_INPUT_KEY_PREFIX = 'dependency-side-effects:v1:';
|
|
75
|
+
/**
|
|
76
|
+
* Compute the machine-independent lookup key for a remotely shareable
|
|
77
|
+
* dependency build.
|
|
78
|
+
*
|
|
79
|
+
* `depsGraph` must contain `depPath`, and every reachable node must provide
|
|
80
|
+
* either `fullPkgId` or the resolution metadata needed to derive it. The
|
|
81
|
+
* function does not mutate the graph or caller state. Each call uses an
|
|
82
|
+
* isolated cache, so the result is independent of earlier roots and platform
|
|
83
|
+
* selections.
|
|
84
|
+
*
|
|
85
|
+
* The returned key starts with {@link DEPENDENCY_SIDE_EFFECTS_INPUT_KEY_PREFIX},
|
|
86
|
+
* followed by the recursive dependency-graph hash and, when non-empty, the
|
|
87
|
+
* patch-file hash. Host identity is excluded and advertised by the artifact's
|
|
88
|
+
* signed compatibility constraints. When a resolution contains platform
|
|
89
|
+
* variations, `supportedArchitectures` selects the source integrity included
|
|
90
|
+
* in the graph hash.
|
|
91
|
+
*/
|
|
92
|
+
export function calcDepStateInputKey(opts) {
|
|
93
|
+
if (opts.depsGraph[opts.depPath] == null) {
|
|
94
|
+
throw new Error(`Dependency side-effects input-key root ${opts.depPath} is not present in depsGraph`);
|
|
95
|
+
}
|
|
96
|
+
const depGraphHash = calcDepGraphHash({
|
|
97
|
+
depsGraph: opts.depsGraph,
|
|
98
|
+
cache: {},
|
|
99
|
+
parents: new Set(),
|
|
100
|
+
depPath: opts.depPath,
|
|
101
|
+
context: createDepGraphHashContext(opts.supportedArchitectures),
|
|
102
|
+
});
|
|
103
|
+
let result = `${DEPENDENCY_SIDE_EFFECTS_INPUT_KEY_PREFIX}deps=${depGraphHash}`;
|
|
104
|
+
if (opts.patchFileHash) {
|
|
105
|
+
result += `;patch=${opts.patchFileHash}`;
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
74
109
|
export function calcDepState(depsGraph, cache, depPath, opts) {
|
|
75
110
|
const ownPin = readSnapshotRuntimePin(depsGraph[depPath]?.children);
|
|
76
111
|
let result = engineName(ownPin ?? opts.nodeVersion);
|
|
77
112
|
if (opts.includeDepGraphHash) {
|
|
78
|
-
const depGraphHash = calcDepGraphHash(
|
|
113
|
+
const depGraphHash = calcDepGraphHash({
|
|
114
|
+
depsGraph,
|
|
115
|
+
cache,
|
|
116
|
+
parents: new Set(),
|
|
117
|
+
depPath: depPath,
|
|
118
|
+
context: createDepGraphHashContext(opts.supportedArchitectures),
|
|
119
|
+
});
|
|
79
120
|
result += `;deps=${depGraphHash}`;
|
|
80
121
|
}
|
|
81
122
|
if (opts.patchFileHash) {
|
|
@@ -83,43 +124,54 @@ export function calcDepState(depsGraph, cache, depPath, opts) {
|
|
|
83
124
|
}
|
|
84
125
|
return result;
|
|
85
126
|
}
|
|
86
|
-
function calcDepGraphHash(depsGraph, cache, parents, depPath,
|
|
87
|
-
|
|
88
|
-
|
|
127
|
+
function calcDepGraphHash({ depsGraph, cache, parents, depPath, context, }) {
|
|
128
|
+
const cacheKey = `${context.cacheKeyPrefix}${depPath}`;
|
|
129
|
+
if (cache[cacheKey])
|
|
130
|
+
return cache[cacheKey];
|
|
89
131
|
const node = depsGraph[depPath];
|
|
90
132
|
if (!node)
|
|
91
133
|
return '';
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
node.fullPkgId = createFullPkgId(node.pkgIdWithPatchHash, node.resolution, supportedArchitectures);
|
|
134
|
+
let fullPkgId = node.fullPkgId;
|
|
135
|
+
if (node.pkgIdWithPatchHash != null && node.resolution != null) {
|
|
136
|
+
fullPkgId = createFullPkgId(node.pkgIdWithPatchHash, node.resolution, context.supportedArchitectures);
|
|
137
|
+
}
|
|
138
|
+
else if (fullPkgId == null) {
|
|
139
|
+
throw new Error(`fullPkgId or resolution metadata is not defined for ${depPath} in depsGraph`);
|
|
100
140
|
}
|
|
101
141
|
const deps = {};
|
|
102
|
-
if (Object.keys(node.children).length && !parents.has(
|
|
103
|
-
const nextParents = new Set([...Array.from(parents),
|
|
142
|
+
if (Object.keys(node.children).length && !parents.has(fullPkgId)) {
|
|
143
|
+
const nextParents = new Set([...Array.from(parents), fullPkgId]);
|
|
104
144
|
for (const alias in node.children) {
|
|
105
145
|
if (Object.hasOwn(node.children, alias)) {
|
|
106
146
|
const childId = node.children[alias];
|
|
107
|
-
deps[alias] = calcDepGraphHash(
|
|
147
|
+
deps[alias] = calcDepGraphHash({
|
|
148
|
+
depsGraph,
|
|
149
|
+
cache,
|
|
150
|
+
parents: nextParents,
|
|
151
|
+
depPath: childId,
|
|
152
|
+
context,
|
|
153
|
+
});
|
|
108
154
|
}
|
|
109
155
|
}
|
|
110
156
|
}
|
|
111
|
-
cache[
|
|
112
|
-
id:
|
|
157
|
+
cache[cacheKey] = hashObject({
|
|
158
|
+
id: fullPkgId,
|
|
113
159
|
deps,
|
|
114
160
|
});
|
|
115
|
-
return cache[
|
|
161
|
+
return cache[cacheKey];
|
|
162
|
+
}
|
|
163
|
+
function createDepGraphHashContext(supportedArchitectures) {
|
|
164
|
+
return {
|
|
165
|
+
supportedArchitectures,
|
|
166
|
+
cacheKeyPrefix: supportedArchitectures == null ? '' : `\0architectures=${hashObject(supportedArchitectures)}\0`,
|
|
167
|
+
};
|
|
116
168
|
}
|
|
117
169
|
export function* iterateHashedGraphNodes(graph, pkgMetaIterator, opts = {}) {
|
|
118
|
-
let
|
|
170
|
+
let buildRequiredDepPaths;
|
|
119
171
|
let entries;
|
|
120
172
|
if (opts.allowBuild != null) {
|
|
121
173
|
const pkgMetaList = Array.from(pkgMetaIterator);
|
|
122
|
-
|
|
174
|
+
buildRequiredDepPaths = computeBuildRequiredDepPaths(graph, computeBuiltDepPaths(pkgMetaList, opts.allowBuild));
|
|
123
175
|
entries = pkgMetaList;
|
|
124
176
|
}
|
|
125
177
|
else {
|
|
@@ -128,8 +180,7 @@ export function* iterateHashedGraphNodes(graph, pkgMetaIterator, opts = {}) {
|
|
|
128
180
|
const ctx = {
|
|
129
181
|
graph,
|
|
130
182
|
cache: {},
|
|
131
|
-
|
|
132
|
-
buildRequiredCache: builtDepPaths !== undefined ? {} : undefined,
|
|
183
|
+
buildRequiredDepPaths,
|
|
133
184
|
supportedArchitectures: opts.supportedArchitectures,
|
|
134
185
|
nodeVersion: opts.nodeVersion,
|
|
135
186
|
lockfileDir: opts.lockfileDir,
|
|
@@ -141,15 +192,14 @@ export function* iterateHashedGraphNodes(graph, pkgMetaIterator, opts = {}) {
|
|
|
141
192
|
};
|
|
142
193
|
}
|
|
143
194
|
}
|
|
144
|
-
export function calcGraphNodeHash({ graph, cache,
|
|
195
|
+
export function calcGraphNodeHash({ graph, cache, buildRequiredDepPaths, supportedArchitectures, nodeVersion, lockfileDir }, pkgMeta) {
|
|
145
196
|
const { name, version, depPath } = pkgMeta;
|
|
146
|
-
// When
|
|
147
|
-
// we only include the engine name for packages that are allowed
|
|
148
|
-
// or transitively depend on a package that is allowed to build.
|
|
197
|
+
// When buildRequiredDepPaths is provided (derived from the allowBuilds
|
|
198
|
+
// config), we only include the engine name for packages that are allowed
|
|
199
|
+
// to build or transitively depend on a package that is allowed to build.
|
|
149
200
|
// This makes GVS hashes engine-agnostic for pure-JS packages,
|
|
150
201
|
// so they survive Node.js upgrades and architecture changes.
|
|
151
|
-
const includeEngine =
|
|
152
|
-
transitivelyRequiresBuild(graph, builtDepPaths, buildRequiredCache ??= {}, depPath, new Set());
|
|
202
|
+
const includeEngine = buildRequiredDepPaths === undefined || buildRequiredDepPaths.has(depPath);
|
|
153
203
|
// A snapshot that declares `engines.runtime` carries the desugared
|
|
154
204
|
// `node@runtime:<version>` pin as a child; that's the Node the bin
|
|
155
205
|
// linker spawns for its lifecycle scripts, so it has to drive the
|
|
@@ -157,7 +207,13 @@ export function calcGraphNodeHash({ graph, cache, builtDepPaths, buildRequiredCa
|
|
|
157
207
|
// to the install-wide value.
|
|
158
208
|
const ownPin = readSnapshotRuntimePin(graph[depPath]?.children);
|
|
159
209
|
const engine = includeEngine ? engineName(ownPin ?? nodeVersion) : null;
|
|
160
|
-
const deps = calcDepGraphHash(
|
|
210
|
+
const deps = calcDepGraphHash({
|
|
211
|
+
depsGraph: graph,
|
|
212
|
+
cache,
|
|
213
|
+
parents: new Set(),
|
|
214
|
+
depPath,
|
|
215
|
+
context: createDepGraphHashContext(supportedArchitectures),
|
|
216
|
+
});
|
|
161
217
|
const isLocalDirectory = isLocalDirectoryResolution(graph[depPath]?.resolution);
|
|
162
218
|
// Scoping the slot needs the project's identity; the segment only needs to
|
|
163
219
|
// know that the package is a local directory, so a caller that leaves
|
|
@@ -259,14 +315,16 @@ export function lockfileToDepGraph(lockfile, supportedArchitectures, lockfileDir
|
|
|
259
315
|
const linkTargetNodes = new Set();
|
|
260
316
|
if (lockfile.packages != null) {
|
|
261
317
|
for (const [depPath, pkgSnapshot] of Object.entries(lockfile.packages)) {
|
|
318
|
+
const pkgIdWithPatchHash = getPkgIdWithPatchHash(depPath);
|
|
262
319
|
const children = lockfileDepsToGraphChildren({
|
|
263
320
|
...pkgSnapshot.dependencies,
|
|
264
321
|
...pkgSnapshot.optionalDependencies,
|
|
265
322
|
}, lockfileDir, linkTargetNodes);
|
|
266
323
|
graph[depPath] = {
|
|
267
324
|
children,
|
|
325
|
+
pkgIdWithPatchHash,
|
|
268
326
|
resolution: pkgSnapshot.resolution,
|
|
269
|
-
fullPkgId: createFullPkgId(
|
|
327
|
+
fullPkgId: createFullPkgId(pkgIdWithPatchHash, pkgSnapshot.resolution, supportedArchitectures),
|
|
270
328
|
};
|
|
271
329
|
}
|
|
272
330
|
}
|
|
@@ -287,30 +345,47 @@ function computeBuiltDepPaths(entries, allowBuild) {
|
|
|
287
345
|
}
|
|
288
346
|
return builtDepPaths;
|
|
289
347
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
348
|
+
/**
|
|
349
|
+
* Expand `builtDepPaths` to every node that is, or transitively depends
|
|
350
|
+
* on, one of them.
|
|
351
|
+
*
|
|
352
|
+
* The result gates the engine string in {@link calcGraphNodeHash}: only a
|
|
353
|
+
* package that may run a build script — or that depends on one — keeps the
|
|
354
|
+
* engine in its GVS hash. It is computed as one graph-wide reverse closure,
|
|
355
|
+
* so a package inside a dependency cycle gets the same answer no matter
|
|
356
|
+
* which node the hasher reaches it from.
|
|
357
|
+
*
|
|
358
|
+
* A path with no node in `graph` is kept and still marks whatever depends on
|
|
359
|
+
* it: the built set comes from the allowBuild policy rather than the graph,
|
|
360
|
+
* so the two can disagree.
|
|
361
|
+
*/
|
|
362
|
+
export function computeBuildRequiredDepPaths(graph, builtDepPaths) {
|
|
363
|
+
const buildRequiredDepPaths = new Set(builtDepPaths);
|
|
364
|
+
if (builtDepPaths.size === 0)
|
|
365
|
+
return buildRequiredDepPaths;
|
|
366
|
+
const parentsByChild = new Map();
|
|
367
|
+
for (const parent of Object.keys(graph)) {
|
|
368
|
+
for (const child of Object.values(graph[parent].children)) {
|
|
369
|
+
const parents = parentsByChild.get(child);
|
|
370
|
+
if (parents == null) {
|
|
371
|
+
parentsByChild.set(child, [parent]);
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
parents.push(parent);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
304
377
|
}
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
378
|
+
const pending = Array.from(builtDepPaths);
|
|
379
|
+
while (pending.length > 0) {
|
|
380
|
+
const child = pending.pop();
|
|
381
|
+
for (const parent of parentsByChild.get(child) ?? []) {
|
|
382
|
+
if (!buildRequiredDepPaths.has(parent)) {
|
|
383
|
+
buildRequiredDepPaths.add(parent);
|
|
384
|
+
pending.push(parent);
|
|
385
|
+
}
|
|
310
386
|
}
|
|
311
387
|
}
|
|
312
|
-
|
|
313
|
-
return false;
|
|
388
|
+
return buildRequiredDepPaths;
|
|
314
389
|
}
|
|
315
390
|
function lockfileDepsToGraphChildren(deps, lockfileDir, linkTargetNodes) {
|
|
316
391
|
const children = {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/deps.graph-hasher",
|
|
3
|
-
"version": "1100.
|
|
3
|
+
"version": "1100.3.1",
|
|
4
4
|
"description": "Calculates the state of a dependency",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -28,17 +28,17 @@
|
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@pnpm/crypto.object-hasher": "1100.0.1",
|
|
31
|
-
"@pnpm/deps.path": "1101.0.
|
|
32
|
-
"@pnpm/engine.runtime.system-version": "1100.0.
|
|
33
|
-
"@pnpm/lockfile.types": "1100.
|
|
34
|
-
"@pnpm/lockfile.utils": "1102.
|
|
35
|
-
"@pnpm/resolving.resolver-base": "1101.
|
|
36
|
-
"@pnpm/types": "1102.
|
|
31
|
+
"@pnpm/deps.path": "1101.0.1",
|
|
32
|
+
"@pnpm/engine.runtime.system-version": "1100.0.11",
|
|
33
|
+
"@pnpm/lockfile.types": "1100.1.1",
|
|
34
|
+
"@pnpm/lockfile.utils": "1102.1.1",
|
|
35
|
+
"@pnpm/resolving.resolver-base": "1101.2.0",
|
|
36
|
+
"@pnpm/types": "1102.1.0",
|
|
37
37
|
"detect-libc": "^2.1.2"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@jest/globals": "30.4.1",
|
|
41
|
-
"@pnpm/deps.graph-hasher": "1100.
|
|
41
|
+
"@pnpm/deps.graph-hasher": "1100.3.1"
|
|
42
42
|
},
|
|
43
43
|
"engines": {
|
|
44
44
|
"node": ">=22.13"
|