@pnpm/installing.deps-installer 1101.1.2 → 1101.3.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.
@@ -0,0 +1,335 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import util from 'node:util';
4
+ import { logger } from '@pnpm/logger';
5
+ /**
6
+ * On-disk cache of verifyLockfileResolutions results, keyed by lockfile
7
+ * content hash. Lets repeat installs against an unchanged lockfile skip
8
+ * the per-package registry round trips entirely — including across git
9
+ * worktrees, where the same lockfile content lives at different paths.
10
+ *
11
+ * Two indexes share the same JSONL records:
12
+ *
13
+ * - **by content hash** — the primary index. Recognizing the same
14
+ * lockfile content regardless of where it sits on disk is what makes
15
+ * worktrees and lockfile copies hit.
16
+ * - **by absolute path** — a same-machine stat shortcut. When we've
17
+ * seen this exact path before with these exact stat values, we
18
+ * trust the cached hash and skip reading the lockfile entirely
19
+ * (microseconds vs. ms-per-MB). Worktrees that get reinstalled in
20
+ * pay the hash cost once, then hit the stat fast path.
21
+ *
22
+ * All filesystem operations are synchronous: the cache is consulted
23
+ * once before verification fan-out and recorded once after — there's
24
+ * no concurrent install work to overlap with, so blocking the event
25
+ * loop for the brief read/stat/hash is fine and keeps the call sites
26
+ * straight-line.
27
+ *
28
+ * Persisted as JSON Lines: each verification appends one record;
29
+ * later records overwrite earlier ones on key collision when read.
30
+ * Appends of a single line are atomic on POSIX and NTFS, so parallel
31
+ * pnpm processes (monorepo installs, CI matrices sharing a cache) can
32
+ * write without coordination.
33
+ *
34
+ * Policy-neutral. Every active verifier's `policy` contribution merges
35
+ * into a single `policy` bag on the record; verifiers sharing a
36
+ * logical policy (same field name) share the slot — no resolver-level
37
+ * namespacing.
38
+ */
39
+ const CACHE_FILE_NAME = 'lockfile-verified.jsonl';
40
+ // Cap the file before it grows large enough to slow down reads. When the
41
+ // cap is exceeded we rewrite the file keeping the N most recently
42
+ // verified entries. The number is generous — a developer machine that
43
+ // touches a thousand distinct (path, content) tuples is far past steady
44
+ // state.
45
+ const MAX_CACHE_ENTRIES = 1000;
46
+ // Records cluster around 250–400 bytes; budget 1 KiB per entry as a
47
+ // conservative upper bound. The compaction check uses `stat().size` to
48
+ // decide whether to read+rewrite, so we never parse the file unless it
49
+ // has actually grown past the cap.
50
+ const COMPACT_TRIGGER_BYTES = MAX_CACHE_ENTRIES * 1024 * 3 / 2;
51
+ /**
52
+ * Build two indexes over the JSONL records in one pass: by content
53
+ * hash (primary) and by absolute path (stat shortcut). Records are
54
+ * walked in file order so the last record for any key wins.
55
+ */
56
+ function readCache(cacheDir) {
57
+ const cacheFilePath = path.join(cacheDir, CACHE_FILE_NAME);
58
+ let contents;
59
+ try {
60
+ contents = fs.readFileSync(cacheFilePath, 'utf8');
61
+ }
62
+ catch (err) {
63
+ if (isNodeError(err) && err.code === 'ENOENT')
64
+ return { byHash: new Map(), byPath: new Map() };
65
+ throw err;
66
+ }
67
+ const byHash = new Map();
68
+ const byPath = new Map();
69
+ for (const line of contents.split('\n')) {
70
+ if (!line)
71
+ continue;
72
+ try {
73
+ const parsed = JSON.parse(line);
74
+ const hash = parsed?.lockfile?.hash;
75
+ const lockfilePath = parsed?.lockfile?.path;
76
+ if (typeof hash !== 'string' || typeof lockfilePath !== 'string')
77
+ continue;
78
+ const record = normalizeRecord(parsed);
79
+ byHash.set(hash, record);
80
+ byPath.set(lockfilePath, record);
81
+ }
82
+ catch {
83
+ // Skip malformed lines; the next clean append will still work.
84
+ }
85
+ }
86
+ return { byHash, byPath };
87
+ }
88
+ function normalizeRecord(parsed) {
89
+ const lockfile = parsed.lockfile ?? {};
90
+ return {
91
+ lockfile: {
92
+ hash: lockfile.hash ?? '',
93
+ path: lockfile.path ?? '',
94
+ size: lockfile.size ?? -1,
95
+ mtimeNs: lockfile.mtimeNs ?? '',
96
+ inode: lockfile.inode ?? '',
97
+ },
98
+ verifiedAt: parsed.verifiedAt ?? '',
99
+ policy: parsed.policy && typeof parsed.policy === 'object' ? parsed.policy : {},
100
+ };
101
+ }
102
+ function statLockfile(lockfilePath) {
103
+ try {
104
+ const stat = fs.statSync(lockfilePath, { bigint: true });
105
+ return {
106
+ size: Number(stat.size),
107
+ mtimeNs: stat.mtimeNs.toString(),
108
+ inode: stat.ino.toString(),
109
+ };
110
+ }
111
+ catch (err) {
112
+ if (isNodeError(err) && err.code === 'ENOENT')
113
+ return null;
114
+ throw err;
115
+ }
116
+ }
117
+ function statMatches(stat, lockfile) {
118
+ return stat.size === lockfile.size &&
119
+ stat.mtimeNs === lockfile.mtimeNs &&
120
+ stat.inode === lockfile.inode;
121
+ }
122
+ /**
123
+ * Try to confirm a cached verification covers the lockfile as it
124
+ * currently sits on disk and the policies currently in effect. Returns
125
+ * `{ hit: true }` to skip the gate; `{ hit: false }` means the caller
126
+ * should run the verifier and persist the result with
127
+ * {@link recordVerification}.
128
+ *
129
+ * Lookup order:
130
+ *
131
+ * 1. **Stat shortcut** — if we've previously verified this exact path
132
+ * with these exact stat values, trust the cached hash and skip
133
+ * reading the lockfile.
134
+ * 2. **Content lookup** — hash the lockfile and look up by hash.
135
+ * Catches the worktree case (same content, different path) and
136
+ * CI checkouts where stat fields got reset. Refreshes the
137
+ * stat-shortcut entry on hit so the next install at this path
138
+ * skips the hash.
139
+ *
140
+ * Every active verifier must agree the cached policy snapshot is still
141
+ * trustworthy under what it currently demands; if any rejects, the
142
+ * full gate runs.
143
+ */
144
+ export function tryLockfileVerificationCache(cacheDir, key) {
145
+ let indexes;
146
+ try {
147
+ indexes = readCache(cacheDir);
148
+ }
149
+ catch (err) {
150
+ // A corrupt cache file should never block the install; fall
151
+ // through to verification so the gate still runs.
152
+ logger.debug({ msg: 'lockfile-verified cache: read failed', err });
153
+ return { hit: false, precomputed: {} };
154
+ }
155
+ const stat = statLockfile(key.lockfilePath);
156
+ if (!stat)
157
+ return { hit: false, precomputed: {} };
158
+ // Stat shortcut: same path + same stat means we trust the cached
159
+ // hash without reading the file. Microseconds.
160
+ const byPathRecord = indexes.byPath.get(key.lockfilePath);
161
+ if (byPathRecord && statMatches(stat, byPathRecord.lockfile)) {
162
+ return {
163
+ hit: everyVerifierTrustsCachedRun(byPathRecord, key.verifiers),
164
+ // The stat-match implies the file content is unchanged since the
165
+ // cached record was written, so its hash is still correct. Pass
166
+ // it through to skip hashing on the miss-then-record path.
167
+ precomputed: { stat, hash: byPathRecord.lockfile.hash },
168
+ };
169
+ }
170
+ // Content lookup: hash the in-memory lockfile, look up by content
171
+ // hash. Catches worktrees (same content, different path) and CI
172
+ // checkouts (same content, reset stat). On hit, refresh the
173
+ // path/stat entry so the next install at this path takes the stat
174
+ // shortcut above.
175
+ let hash;
176
+ try {
177
+ hash = key.hashLockfile();
178
+ }
179
+ catch (err) {
180
+ logger.debug({ msg: 'lockfile-verified cache: lockfile hash failed', err });
181
+ return { hit: false, precomputed: { stat } };
182
+ }
183
+ const byHashRecord = indexes.byHash.get(hash);
184
+ if (!byHashRecord)
185
+ return { hit: false, precomputed: { stat, hash } };
186
+ if (!everyVerifierTrustsCachedRun(byHashRecord, key.verifiers)) {
187
+ return { hit: false, precomputed: { stat, hash } };
188
+ }
189
+ appendRecord(cacheDir, {
190
+ ...byHashRecord,
191
+ lockfile: { ...byHashRecord.lockfile, path: key.lockfilePath, size: stat.size, mtimeNs: stat.mtimeNs, inode: stat.inode },
192
+ });
193
+ return { hit: true, precomputed: { stat, hash } };
194
+ }
195
+ function everyVerifierTrustsCachedRun(record, verifiers) {
196
+ for (const verifier of verifiers) {
197
+ if (!verifier.canTrustPastCheck(record.policy))
198
+ return false;
199
+ }
200
+ return true;
201
+ }
202
+ function mergePolicies(verifiers) {
203
+ // Later verifiers overwrite earlier ones on conflict — a shared field
204
+ // should carry the same value across verifiers by convention; mismatch
205
+ // is a config bug and we don't try to reconcile it here.
206
+ const merged = {};
207
+ for (const verifier of verifiers) {
208
+ Object.assign(merged, verifier.policy);
209
+ }
210
+ return merged;
211
+ }
212
+ /**
213
+ * Persist a successful verification. Called after the gate passes; the
214
+ * lockfile is hashed once and the resulting record is appended to the
215
+ * cache file. If the file is past {@link MAX_CACHE_ENTRIES}, it is
216
+ * rewritten keeping the most recent entries.
217
+ *
218
+ * Reuses `precomputed` values from a prior
219
+ * {@link tryLockfileVerificationCache} lookup so we don't re-stat or
220
+ * (especially) re-hash the lockfile a second time on the miss-then-
221
+ * record path.
222
+ */
223
+ export function recordVerification(cacheDir, key, precomputed) {
224
+ let stat;
225
+ let hash;
226
+ try {
227
+ stat = precomputed?.stat ?? statLockfile(key.lockfilePath);
228
+ if (!stat)
229
+ return;
230
+ hash = precomputed?.hash ?? key.hashLockfile();
231
+ }
232
+ catch (err) {
233
+ // The gate has already passed; if we can't record the cache entry we
234
+ // just won't get the speedup next time. Not a reason to fail install.
235
+ logger.debug({ msg: 'lockfile-verified cache: could not record verification', err });
236
+ return;
237
+ }
238
+ const record = {
239
+ lockfile: {
240
+ hash,
241
+ path: key.lockfilePath,
242
+ size: stat.size,
243
+ mtimeNs: stat.mtimeNs,
244
+ inode: stat.inode,
245
+ },
246
+ verifiedAt: new Date().toISOString(),
247
+ policy: mergePolicies(key.verifiers),
248
+ };
249
+ appendRecord(cacheDir, record);
250
+ }
251
+ function appendRecord(cacheDir, record) {
252
+ const cacheFilePath = path.join(cacheDir, CACHE_FILE_NAME);
253
+ const line = `${JSON.stringify(record)}\n`;
254
+ try {
255
+ fs.mkdirSync(cacheDir, { recursive: true });
256
+ fs.appendFileSync(cacheFilePath, line);
257
+ }
258
+ catch (err) {
259
+ logger.debug({ msg: 'lockfile-verified cache: append failed', err });
260
+ return;
261
+ }
262
+ maybeCompactCache(cacheDir);
263
+ }
264
+ function maybeCompactCache(cacheDir) {
265
+ const cacheFilePath = path.join(cacheDir, CACHE_FILE_NAME);
266
+ // Decide whether to compact from the file size alone — avoids reading
267
+ // and parsing the file on every successful install. Records cluster
268
+ // around a few hundred bytes; the byte budget translates directly to
269
+ // the entry cap with generous slack so we don't trigger a rewrite on
270
+ // every append once we cross the line.
271
+ let size;
272
+ try {
273
+ size = fs.statSync(cacheFilePath).size;
274
+ }
275
+ catch (err) {
276
+ if (isNodeError(err) && err.code === 'ENOENT')
277
+ return;
278
+ logger.debug({ msg: 'lockfile-verified cache: stat for compaction failed', err });
279
+ return;
280
+ }
281
+ if (size <= COMPACT_TRIGGER_BYTES)
282
+ return;
283
+ let contents;
284
+ try {
285
+ contents = fs.readFileSync(cacheFilePath, 'utf8');
286
+ }
287
+ catch (err) {
288
+ if (isNodeError(err) && err.code === 'ENOENT')
289
+ return;
290
+ logger.debug({ msg: 'lockfile-verified cache: read for compaction failed', err });
291
+ return;
292
+ }
293
+ const lines = contents.split('\n').filter(Boolean);
294
+ // Dedup by (path, hash) — that's the unit both indexes care about.
295
+ // Walking reverse keeps the newest record per tuple; we then trim to
296
+ // MAX_CACHE_ENTRIES and write back in original order.
297
+ const seen = new Set();
298
+ const reversed = [];
299
+ for (let i = lines.length - 1; i >= 0; i--) {
300
+ const line = lines[i];
301
+ try {
302
+ const parsed = JSON.parse(line);
303
+ const lockfilePath = parsed?.lockfile?.path;
304
+ const hash = parsed?.lockfile?.hash;
305
+ if (typeof lockfilePath !== 'string' || typeof hash !== 'string')
306
+ continue;
307
+ const tupleKey = `${lockfilePath}${hash}`;
308
+ if (seen.has(tupleKey))
309
+ continue;
310
+ seen.add(tupleKey);
311
+ reversed.push(line);
312
+ }
313
+ catch {
314
+ // Skip malformed lines.
315
+ }
316
+ }
317
+ reversed.reverse();
318
+ const kept = reversed.slice(-MAX_CACHE_ENTRIES);
319
+ try {
320
+ // Write to a sibling tempfile + rename so a concurrent pnpm process
321
+ // can't observe a half-written file.
322
+ const tmpPath = `${cacheFilePath}.${process.pid}.tmp`;
323
+ fs.writeFileSync(tmpPath, kept.map((line) => `${line}\n`).join(''));
324
+ fs.renameSync(tmpPath, cacheFilePath);
325
+ }
326
+ catch (err) {
327
+ logger.debug({ msg: 'lockfile-verified cache: compaction failed', err });
328
+ }
329
+ }
330
+ function isNodeError(err) {
331
+ // `instanceof Error` is unreliable across realms (Jest's VM context), so
332
+ // route through util.types.isNativeError per the repo guideline.
333
+ return util.types.isNativeError(err) && 'code' in err;
334
+ }
335
+ //# sourceMappingURL=verifyLockfileResolutionsCache.js.map
@@ -0,0 +1,14 @@
1
+ import { type LockfileObject, type WriteLockfilesResult } from '@pnpm/lockfile.fs';
2
+ import type { ResolutionVerifier } from '@pnpm/resolving.resolver-base';
3
+ export interface WriteLockfilesAndRecordVerifiedOptions {
4
+ wantedLockfile: LockfileObject;
5
+ wantedLockfileDir: string;
6
+ currentLockfile: LockfileObject;
7
+ currentLockfileDir: string;
8
+ useGitBranchLockfile?: boolean;
9
+ mergeGitBranchLockfiles?: boolean;
10
+ cacheDir?: string;
11
+ resolutionVerifiers: readonly ResolutionVerifier[] | undefined;
12
+ }
13
+ /** Plural counterpart of {@link writeWantedLockfileAndRecordVerified}. */
14
+ export declare function writeLockfilesAndRecordVerified(opts: WriteLockfilesAndRecordVerifiedOptions): Promise<WriteLockfilesResult>;
@@ -0,0 +1,32 @@
1
+ import path from 'node:path';
2
+ import { getWantedLockfileName, writeLockfiles } from '@pnpm/lockfile.fs';
3
+ import { recordLockfileVerified } from './recordLockfileVerified.js';
4
+ /** Plural counterpart of {@link writeWantedLockfileAndRecordVerified}. */
5
+ export async function writeLockfilesAndRecordVerified(opts) {
6
+ const cacheActive = opts.cacheDir != null && (opts.resolutionVerifiers?.length ?? 0) > 0;
7
+ const wantedLockfileName = cacheActive
8
+ ? await getWantedLockfileName({
9
+ useGitBranchLockfile: opts.useGitBranchLockfile,
10
+ mergeGitBranchLockfiles: opts.mergeGitBranchLockfiles,
11
+ })
12
+ : undefined;
13
+ const written = await writeLockfiles({
14
+ wantedLockfile: opts.wantedLockfile,
15
+ wantedLockfileDir: opts.wantedLockfileDir,
16
+ currentLockfile: opts.currentLockfile,
17
+ currentLockfileDir: opts.currentLockfileDir,
18
+ useGitBranchLockfile: opts.useGitBranchLockfile,
19
+ mergeGitBranchLockfiles: opts.mergeGitBranchLockfiles,
20
+ wantedLockfileName,
21
+ });
22
+ if (cacheActive) {
23
+ recordLockfileVerified({
24
+ cacheDir: opts.cacheDir,
25
+ lockfilePath: path.resolve(opts.wantedLockfileDir, wantedLockfileName),
26
+ lockfile: written.wantedLockfile,
27
+ resolutionVerifiers: opts.resolutionVerifiers,
28
+ });
29
+ }
30
+ return written;
31
+ }
32
+ //# sourceMappingURL=writeLockfilesAndRecordVerified.js.map
@@ -0,0 +1,12 @@
1
+ import { type LockfileObject } from '@pnpm/lockfile.fs';
2
+ import type { ResolutionVerifier } from '@pnpm/resolving.resolver-base';
3
+ export interface WriteWantedLockfileAndRecordVerifiedOptions {
4
+ lockfileDir: string;
5
+ lockfile: LockfileObject;
6
+ cacheDir?: string;
7
+ resolutionVerifiers: readonly ResolutionVerifier[] | undefined;
8
+ useGitBranchLockfile?: boolean;
9
+ mergeGitBranchLockfiles?: boolean;
10
+ }
11
+ /** Combines {@link writeWantedLockfile} and {@link recordLockfileVerified} — see each for semantics. */
12
+ export declare function writeWantedLockfileAndRecordVerified(opts: WriteWantedLockfileAndRecordVerifiedOptions): Promise<LockfileObject>;
@@ -0,0 +1,28 @@
1
+ import path from 'node:path';
2
+ import { getWantedLockfileName, writeWantedLockfile } from '@pnpm/lockfile.fs';
3
+ import { recordLockfileVerified } from './recordLockfileVerified.js';
4
+ /** Combines {@link writeWantedLockfile} and {@link recordLockfileVerified} — see each for semantics. */
5
+ export async function writeWantedLockfileAndRecordVerified(opts) {
6
+ const cacheActive = opts.cacheDir != null && (opts.resolutionVerifiers?.length ?? 0) > 0;
7
+ const lockfileName = cacheActive
8
+ ? await getWantedLockfileName({
9
+ useGitBranchLockfile: opts.useGitBranchLockfile,
10
+ mergeGitBranchLockfiles: opts.mergeGitBranchLockfiles,
11
+ })
12
+ : undefined;
13
+ const written = await writeWantedLockfile(opts.lockfileDir, opts.lockfile, {
14
+ useGitBranchLockfile: opts.useGitBranchLockfile,
15
+ mergeGitBranchLockfiles: opts.mergeGitBranchLockfiles,
16
+ lockfileName,
17
+ });
18
+ if (cacheActive) {
19
+ recordLockfileVerified({
20
+ cacheDir: opts.cacheDir,
21
+ lockfilePath: path.resolve(opts.lockfileDir, lockfileName),
22
+ lockfile: written,
23
+ resolutionVerifiers: opts.resolutionVerifiers,
24
+ });
25
+ }
26
+ return written;
27
+ }
28
+ //# sourceMappingURL=writeWantedLockfileAndRecordVerified.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/installing.deps-installer",
3
- "version": "1101.1.2",
3
+ "version": "1101.3.0",
4
4
  "description": "Fast, disk space efficient installation engine",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -62,60 +62,60 @@
62
62
  "ramda": "npm:@pnpm/ramda@0.28.1",
63
63
  "run-groups": "^5.0.0",
64
64
  "semver": "^7.7.2",
65
- "@pnpm/bins.linker": "1100.0.6",
66
- "@pnpm/agent.client": "1.0.5",
67
- "@pnpm/building.after-install": "1101.0.12",
68
- "@pnpm/bins.remover": "1100.0.3",
69
- "@pnpm/building.policy": "1100.0.4",
70
- "@pnpm/building.during-install": "1101.0.10",
65
+ "@pnpm/agent.client": "1.0.7",
66
+ "@pnpm/bins.linker": "1100.0.8",
67
+ "@pnpm/bins.remover": "1100.0.5",
68
+ "@pnpm/building.after-install": "1101.0.14",
69
+ "@pnpm/building.during-install": "1101.0.12",
70
+ "@pnpm/building.policy": "1100.0.6",
71
71
  "@pnpm/catalogs.protocol-parser": "1100.0.0",
72
72
  "@pnpm/catalogs.resolver": "1100.0.0",
73
- "@pnpm/config.matcher": "1100.0.1",
74
73
  "@pnpm/catalogs.types": "1100.0.0",
75
- "@pnpm/config.normalize-registries": "1100.0.3",
76
- "@pnpm/constants": "1100.0.0",
74
+ "@pnpm/config.matcher": "1100.0.1",
75
+ "@pnpm/config.normalize-registries": "1100.0.4",
77
76
  "@pnpm/config.parse-overrides": "1100.0.1",
77
+ "@pnpm/constants": "1100.0.0",
78
+ "@pnpm/core-loggers": "1100.1.1",
78
79
  "@pnpm/crypto.hash": "1100.0.1",
79
- "@pnpm/core-loggers": "1100.0.2",
80
- "@pnpm/crypto.object-hasher": "1100.0.0",
81
- "@pnpm/deps.graph-hasher": "1100.1.5",
80
+ "@pnpm/deps.graph-hasher": "1100.2.1",
81
+ "@pnpm/deps.path": "1100.0.4",
82
82
  "@pnpm/deps.graph-sequencer": "1100.0.0",
83
- "@pnpm/deps.path": "1100.0.3",
84
83
  "@pnpm/error": "1100.0.0",
85
- "@pnpm/exec.lifecycle": "1100.0.10",
84
+ "@pnpm/exec.lifecycle": "1100.0.12",
86
85
  "@pnpm/fs.read-modules-dir": "1100.0.1",
87
- "@pnpm/fs.symlink-dependency": "1100.0.3",
88
- "@pnpm/hooks.read-package-hook": "1100.0.3",
89
- "@pnpm/hooks.types": "1100.0.6",
90
- "@pnpm/installing.deps-resolver": "1100.0.10",
91
- "@pnpm/installing.deps-restorer": "1101.1.2",
92
- "@pnpm/installing.linking.direct-dep-linker": "1100.0.3",
93
- "@pnpm/installing.context": "1100.0.10",
94
- "@pnpm/installing.linking.modules-cleaner": "1100.1.1",
95
- "@pnpm/installing.linking.hoist": "1100.0.6",
96
- "@pnpm/installing.modules-yaml": "1100.0.4",
97
- "@pnpm/installing.package-requester": "1101.0.6",
98
- "@pnpm/lockfile.filtering": "1100.1.0",
99
- "@pnpm/lockfile.fs": "1100.0.8",
100
- "@pnpm/lockfile.preferred-versions": "1100.0.9",
101
- "@pnpm/lockfile.pruner": "1100.0.5",
102
- "@pnpm/lockfile.to-pnp": "1100.0.8",
103
- "@pnpm/lockfile.settings-checker": "1100.0.10",
104
- "@pnpm/lockfile.utils": "1100.0.7",
105
- "@pnpm/lockfile.verification": "1100.0.10",
106
- "@pnpm/lockfile.walker": "1100.0.5",
107
- "@pnpm/patching.config": "1100.0.3",
108
- "@pnpm/resolving.resolver-base": "1100.1.3",
109
- "@pnpm/store.controller-types": "1100.0.7",
86
+ "@pnpm/fs.symlink-dependency": "1100.0.5",
87
+ "@pnpm/installing.context": "1100.0.12",
88
+ "@pnpm/crypto.object-hasher": "1100.0.0",
89
+ "@pnpm/installing.deps-restorer": "1101.1.4",
90
+ "@pnpm/hooks.types": "1100.0.8",
91
+ "@pnpm/installing.deps-resolver": "1100.1.1",
92
+ "@pnpm/installing.linking.direct-dep-linker": "1100.0.5",
93
+ "@pnpm/installing.linking.hoist": "1100.0.8",
94
+ "@pnpm/installing.linking.modules-cleaner": "1100.1.3",
95
+ "@pnpm/installing.package-requester": "1101.0.8",
96
+ "@pnpm/installing.modules-yaml": "1100.0.5",
97
+ "@pnpm/lockfile.filtering": "1100.1.2",
98
+ "@pnpm/hooks.read-package-hook": "1100.0.4",
99
+ "@pnpm/lockfile.fs": "1100.1.1",
100
+ "@pnpm/lockfile.preferred-versions": "1100.0.11",
101
+ "@pnpm/lockfile.pruner": "1100.0.7",
102
+ "@pnpm/lockfile.to-pnp": "1100.0.10",
103
+ "@pnpm/lockfile.utils": "1100.0.9",
104
+ "@pnpm/lockfile.walker": "1100.0.7",
105
+ "@pnpm/lockfile.settings-checker": "1100.0.12",
106
+ "@pnpm/lockfile.verification": "1100.0.12",
107
+ "@pnpm/patching.config": "1100.0.4",
108
+ "@pnpm/pkg-manifest.utils": "1100.2.0",
110
109
  "@pnpm/resolving.parse-wanted-dependency": "1100.0.1",
111
- "@pnpm/types": "1101.1.0",
110
+ "@pnpm/resolving.resolver-base": "1100.3.0",
111
+ "@pnpm/store.controller-types": "1100.1.1",
112
112
  "@pnpm/store.index": "1100.1.0",
113
- "@pnpm/pkg-manifest.utils": "1100.1.3",
114
- "@pnpm/workspace.project-manifest-reader": "1100.0.5"
113
+ "@pnpm/types": "1101.1.1",
114
+ "@pnpm/workspace.project-manifest-reader": "1100.0.7"
115
115
  },
116
116
  "peerDependencies": {
117
117
  "@pnpm/logger": ">=1001.0.0 <1002.0.0",
118
- "@pnpm/worker": "^1100.1.5"
118
+ "@pnpm/worker": "^1100.1.7"
119
119
  },
120
120
  "devDependencies": {
121
121
  "@jest/globals": "30.3.0",
@@ -138,21 +138,21 @@
138
138
  "symlink-dir": "^10.0.1",
139
139
  "write-json-file": "^7.0.0",
140
140
  "write-yaml-file": "^6.0.0",
141
- "@pnpm/assert-project": "1100.0.8",
142
- "@pnpm/installing.deps-installer": "1101.1.2",
143
- "@pnpm/assert-store": "1100.0.8",
144
- "@pnpm/lockfile.types": "1100.0.5",
145
- "@pnpm/network.git-utils": "1100.0.1",
141
+ "@pnpm/assert-project": "1100.0.10",
142
+ "@pnpm/assert-store": "1100.0.10",
143
+ "@pnpm/installing.deps-installer": "1101.3.0",
144
+ "@pnpm/lockfile.types": "1100.0.7",
146
145
  "@pnpm/logger": "1100.0.0",
147
- "@pnpm/resolving.registry.types": "1100.0.3",
148
- "@pnpm/pkg-manifest.reader": "1100.0.3",
149
- "@pnpm/store.cafs": "1100.1.4",
150
- "@pnpm/prepare": "1100.0.8",
146
+ "@pnpm/network.git-utils": "1100.0.1",
147
+ "@pnpm/pkg-manifest.reader": "1100.0.4",
148
+ "@pnpm/prepare": "1100.0.10",
149
+ "@pnpm/resolving.registry.types": "1100.0.4",
151
150
  "@pnpm/store.path": "1100.0.1",
151
+ "@pnpm/store.cafs": "1100.1.6",
152
152
  "@pnpm/test-fixtures": "1100.0.0",
153
153
  "@pnpm/test-ipc-server": "1100.0.0",
154
- "@pnpm/testing.mock-agent": "1100.0.4",
155
- "@pnpm/testing.temp-store": "1100.0.16"
154
+ "@pnpm/testing.mock-agent": "1100.0.6",
155
+ "@pnpm/testing.temp-store": "1100.1.1"
156
156
  },
157
157
  "engines": {
158
158
  "node": ">=22.13"