@vltpkg/package-info 1.0.1 → 1.0.3
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.d.ts +4 -5
- package/dist/index.js +156 -72
- package/package.json +13 -13
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { PackageJson } from '@vltpkg/package-json';
|
|
2
2
|
import type { PickManifestOptions } from '@vltpkg/pick-manifest';
|
|
3
|
-
import type { RegistryClientOptions, RegistryClientRequestOptions } from '@vltpkg/registry-client';
|
|
4
|
-
import { RegistryClient } from '@vltpkg/registry-client';
|
|
3
|
+
import type { RegistryClient, RegistryClientOptions, RegistryClientRequestOptions } from '@vltpkg/registry-client';
|
|
5
4
|
import type { SpecOptions } from '@vltpkg/spec';
|
|
6
5
|
import { Spec } from '@vltpkg/spec';
|
|
7
|
-
import { Pool } from '@vltpkg/tar';
|
|
6
|
+
import type { Pool } from '@vltpkg/tar';
|
|
8
7
|
import type { Integrity, Manifest, Packument } from '@vltpkg/types';
|
|
9
8
|
import { Monorepo } from '@vltpkg/workspaces';
|
|
10
9
|
export declare const delimiter = "~";
|
|
@@ -45,8 +44,8 @@ export declare class PackageInfoClient {
|
|
|
45
44
|
options: PackageInfoClientOptions;
|
|
46
45
|
packageJson: PackageJson;
|
|
47
46
|
monorepo?: Monorepo;
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
getRegistryClient(): Promise<RegistryClient>;
|
|
48
|
+
getTarPool(): Promise<Pool>;
|
|
50
49
|
constructor(options?: PackageInfoClientOptions);
|
|
51
50
|
extract(spec: Spec | string, target: string, options?: PackageInfoClientExtractOptions): Promise<Resolution>;
|
|
52
51
|
/**
|
package/dist/index.js
CHANGED
|
@@ -2,9 +2,7 @@ import { error } from '@vltpkg/error-cause';
|
|
|
2
2
|
import { clone, resolve as gitResolve, revs } from '@vltpkg/git';
|
|
3
3
|
import { PackageJson } from '@vltpkg/package-json';
|
|
4
4
|
import { pickManifest } from '@vltpkg/pick-manifest';
|
|
5
|
-
import { RegistryClient } from '@vltpkg/registry-client';
|
|
6
5
|
import { Spec } from '@vltpkg/spec';
|
|
7
|
-
import { Pool } from '@vltpkg/tar';
|
|
8
6
|
import { asPackument } from '@vltpkg/types';
|
|
9
7
|
import ssri from 'ssri';
|
|
10
8
|
import { Monorepo } from '@vltpkg/workspaces';
|
|
@@ -36,17 +34,39 @@ export class PackageInfoClient {
|
|
|
36
34
|
#trustedIntegrities = new Map();
|
|
37
35
|
#manifestCacheMinAge = Date.now() - manifestCacheMaxAge;
|
|
38
36
|
#cachePath;
|
|
37
|
+
// In-flight coalescing key is `${registry}${name}` — no representation
|
|
38
|
+
// component. Safe only because every caller requests the same full
|
|
39
|
+
// packument (see #fetchPackument).
|
|
39
40
|
#packumentPromises = new Map();
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
// unique temp file names for atomic manifest cache writes
|
|
42
|
+
#manifestWriteRandom = randomBytes(6).toString('hex');
|
|
43
|
+
#manifestWriteCount = 0;
|
|
44
|
+
// cache paths already written this run. manifest() is called many
|
|
45
|
+
// times for the same cache key per install and content for a given
|
|
46
|
+
// path is deterministic within a run, so only the first write is
|
|
47
|
+
// needed. entries are removed when the on-disk file is invalidated
|
|
48
|
+
// so the refreshed manifest can be written again.
|
|
49
|
+
#manifestWritePaths = new Set();
|
|
50
|
+
#registryClientPromise;
|
|
51
|
+
#tarPoolPromise;
|
|
52
|
+
async getRegistryClient() {
|
|
53
|
+
if (this.#registryClient)
|
|
54
|
+
return this.#registryClient;
|
|
55
|
+
this.#registryClientPromise ??=
|
|
56
|
+
import('@vltpkg/registry-client').then(({ RegistryClient }) => {
|
|
57
|
+
this.#registryClient = new RegistryClient(this.options);
|
|
58
|
+
return this.#registryClient;
|
|
59
|
+
});
|
|
60
|
+
return this.#registryClientPromise;
|
|
45
61
|
}
|
|
46
|
-
|
|
47
|
-
if (
|
|
62
|
+
async getTarPool() {
|
|
63
|
+
if (this.#tarPool)
|
|
64
|
+
return this.#tarPool;
|
|
65
|
+
this.#tarPoolPromise ??= import('@vltpkg/tar').then(({ Pool }) => {
|
|
48
66
|
this.#tarPool = new Pool();
|
|
49
|
-
|
|
67
|
+
return this.#tarPool;
|
|
68
|
+
});
|
|
69
|
+
return this.#tarPoolPromise;
|
|
50
70
|
}
|
|
51
71
|
constructor(options = {}) {
|
|
52
72
|
this.options = options;
|
|
@@ -111,7 +131,7 @@ export class PackageInfoClient {
|
|
|
111
131
|
case 'registry': {
|
|
112
132
|
const fetchTarball = async (useCache) => {
|
|
113
133
|
const trustIntegrity = this.#trustedIntegrities.get(r.resolved) === r.integrity;
|
|
114
|
-
const response = await this.
|
|
134
|
+
const response = await (await this.getRegistryClient()).request(r.resolved, {
|
|
115
135
|
integrity: r.integrity,
|
|
116
136
|
trustIntegrity,
|
|
117
137
|
...(useCache === false ? { useCache } : {}),
|
|
@@ -131,20 +151,17 @@ export class PackageInfoClient {
|
|
|
131
151
|
this.#trustedIntegrities.set(r.resolved, response.integrity);
|
|
132
152
|
}
|
|
133
153
|
const buf = response.buffer();
|
|
134
|
-
// Verify tarball
|
|
135
|
-
//
|
|
136
|
-
// the
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
/* c8 ignore start - defense-in-depth: registry client's
|
|
141
|
-
* checkIntegrity() usually catches mismatches first since
|
|
142
|
-
* it checks the same gzip bytes. This fires only when the
|
|
143
|
-
* registry client check is skipped (trustIntegrity=true). */
|
|
144
|
-
if (r.integrity && !fromLockfile) {
|
|
154
|
+
// Verify network-delivered tarball bytes against dist.integrity.
|
|
155
|
+
// Skip cache-served bodies: they were verified on the fetch that
|
|
156
|
+
// populated the cache, and cache-unzip rewrites them un-gzipped
|
|
157
|
+
// so the gzip-hash can never match. Skip lockfile-sourced
|
|
158
|
+
// integrity: it was verified on first install.
|
|
159
|
+
if (r.integrity && !fromLockfile && !response.fromCache) {
|
|
145
160
|
const hash = createHash('sha512');
|
|
146
161
|
hash.update(buf);
|
|
147
162
|
const computed = `sha512-${hash.digest('base64')}`;
|
|
163
|
+
/* c8 ignore start - defense-in-depth: registry client's
|
|
164
|
+
* checkIntegrity() usually catches mismatches first. */
|
|
148
165
|
if (computed !== r.integrity) {
|
|
149
166
|
throw error('Tarball integrity check failed', {
|
|
150
167
|
code: 'EINTEGRITY',
|
|
@@ -154,8 +171,8 @@ export class PackageInfoClient {
|
|
|
154
171
|
found: computed,
|
|
155
172
|
});
|
|
156
173
|
}
|
|
174
|
+
/* c8 ignore stop */
|
|
157
175
|
}
|
|
158
|
-
/* c8 ignore stop */
|
|
159
176
|
return buf;
|
|
160
177
|
};
|
|
161
178
|
let buf;
|
|
@@ -178,7 +195,7 @@ export class PackageInfoClient {
|
|
|
178
195
|
}
|
|
179
196
|
}
|
|
180
197
|
try {
|
|
181
|
-
await this.
|
|
198
|
+
await (await this.getTarPool()).unpack(buf, target);
|
|
182
199
|
}
|
|
183
200
|
catch (er) {
|
|
184
201
|
throw this.#resolveError(spec, options, 'tar unpack failed', { cause: er });
|
|
@@ -186,7 +203,7 @@ export class PackageInfoClient {
|
|
|
186
203
|
return r;
|
|
187
204
|
}
|
|
188
205
|
case 'remote': {
|
|
189
|
-
const response = await this.
|
|
206
|
+
const response = await (await this.getRegistryClient()).request(r.resolved);
|
|
190
207
|
if (response.statusCode !== 200) {
|
|
191
208
|
throw this.#resolveError(spec, options, 'failed to fetch remote tarball', {
|
|
192
209
|
url: r.resolved,
|
|
@@ -209,7 +226,7 @@ export class PackageInfoClient {
|
|
|
209
226
|
}
|
|
210
227
|
r.integrity = computed;
|
|
211
228
|
try {
|
|
212
|
-
await this.
|
|
229
|
+
await (await this.getTarPool()).unpack(buf, target);
|
|
213
230
|
}
|
|
214
231
|
catch (er) {
|
|
215
232
|
throw this.#resolveError(spec, options, 'remote tar unpack failed', { cause: er });
|
|
@@ -227,7 +244,7 @@ export class PackageInfoClient {
|
|
|
227
244
|
const st = await stat(path);
|
|
228
245
|
if (st.isFile()) {
|
|
229
246
|
try {
|
|
230
|
-
await this.
|
|
247
|
+
await (await this.getTarPool()).unpack(await this.tarball(spec, options), target);
|
|
231
248
|
}
|
|
232
249
|
catch (er) {
|
|
233
250
|
throw this.#resolveError(spec, options, 'tar unpack failed', { cause: er });
|
|
@@ -304,6 +321,35 @@ export class PackageInfoClient {
|
|
|
304
321
|
const key = this.#manifestCacheKey(f, options);
|
|
305
322
|
return pathResolve(this.#cachePath, 'package-info', key);
|
|
306
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Write a manifest cache file atomically (write to a temp file in
|
|
326
|
+
* the same directory, then rename over the destination) so that
|
|
327
|
+
* concurrent readers never observe a partially written manifest.
|
|
328
|
+
* Freshness is tracked via the resulting file's mtime.
|
|
329
|
+
*/
|
|
330
|
+
async #writeManifestCache(cachePath, json) {
|
|
331
|
+
const tmp = `${cachePath}.${this.#manifestWriteRandom}.${this.#manifestWriteCount++}`;
|
|
332
|
+
try {
|
|
333
|
+
try {
|
|
334
|
+
await writeFile(tmp, json, 'utf8');
|
|
335
|
+
}
|
|
336
|
+
catch (err) {
|
|
337
|
+
// in case the cache directory doesn't exist
|
|
338
|
+
// just create it and retry
|
|
339
|
+
if (!(err instanceof Error &&
|
|
340
|
+
'code' in err &&
|
|
341
|
+
err.code === 'ENOENT')) {
|
|
342
|
+
throw err;
|
|
343
|
+
}
|
|
344
|
+
await mkdir(dirname(cachePath), { recursive: true });
|
|
345
|
+
await writeFile(tmp, json, 'utf8');
|
|
346
|
+
}
|
|
347
|
+
await rename(tmp, cachePath);
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
// failing to write the manifest cache is not an install failure
|
|
351
|
+
}
|
|
352
|
+
}
|
|
307
353
|
async tarball(spec, options = {}) {
|
|
308
354
|
if (typeof spec === 'string')
|
|
309
355
|
spec = Spec.parse(spec, this.options);
|
|
@@ -323,7 +369,7 @@ export class PackageInfoClient {
|
|
|
323
369
|
}
|
|
324
370
|
const fetchTarball = async (useCache) => {
|
|
325
371
|
const trustIntegrity = this.#trustedIntegrities.get(tarball) === integrity;
|
|
326
|
-
const response = await this.
|
|
372
|
+
const response = await (await this.getRegistryClient()).request(tarball, {
|
|
327
373
|
...options,
|
|
328
374
|
integrity,
|
|
329
375
|
trustIntegrity,
|
|
@@ -342,13 +388,12 @@ export class PackageInfoClient {
|
|
|
342
388
|
this.#trustedIntegrities.set(tarball, response.integrity);
|
|
343
389
|
}
|
|
344
390
|
const buf = response.buffer();
|
|
345
|
-
//
|
|
346
|
-
|
|
347
|
-
/* c8 ignore start - defense-in-depth (see extract) */
|
|
348
|
-
if (integrity) {
|
|
391
|
+
// Same as extract(): only hash network-delivered bodies.
|
|
392
|
+
if (integrity && !response.fromCache) {
|
|
349
393
|
const hash = createHash('sha512');
|
|
350
394
|
hash.update(buf);
|
|
351
395
|
const computed = `sha512-${hash.digest('base64')}`;
|
|
396
|
+
/* c8 ignore start - defense-in-depth (see extract) */
|
|
352
397
|
if (computed !== integrity) {
|
|
353
398
|
throw error('Tarball integrity check failed', {
|
|
354
399
|
code: 'EINTEGRITY',
|
|
@@ -358,8 +403,8 @@ export class PackageInfoClient {
|
|
|
358
403
|
found: computed,
|
|
359
404
|
});
|
|
360
405
|
}
|
|
406
|
+
/* c8 ignore stop */
|
|
361
407
|
}
|
|
362
|
-
/* c8 ignore stop */
|
|
363
408
|
return buf;
|
|
364
409
|
};
|
|
365
410
|
try {
|
|
@@ -409,7 +454,7 @@ export class PackageInfoClient {
|
|
|
409
454
|
if (!remoteURL) {
|
|
410
455
|
throw this.#resolveError(spec, options);
|
|
411
456
|
}
|
|
412
|
-
const response = await this.
|
|
457
|
+
const response = await (await this.getRegistryClient()).request(remoteURL);
|
|
413
458
|
if (response.statusCode !== 200) {
|
|
414
459
|
throw this.#resolveError(spec, options, 'failed to fetch URL', { response, url: remoteURL });
|
|
415
460
|
}
|
|
@@ -450,15 +495,21 @@ export class PackageInfoClient {
|
|
|
450
495
|
const cachePath = this._manifestCachePath(spec, options);
|
|
451
496
|
if (cachePath) {
|
|
452
497
|
try {
|
|
453
|
-
// Cache file exists, read and return it
|
|
454
|
-
|
|
498
|
+
// Cache file exists, read and return it. Freshness is
|
|
499
|
+
// tracked via the file's mtime, so the file content is
|
|
500
|
+
// exactly the manifest and can be returned as parsed.
|
|
501
|
+
const [st, cached] = await Promise.all([
|
|
502
|
+
stat(cachePath),
|
|
503
|
+
readFile(cachePath, 'utf8'),
|
|
504
|
+
]);
|
|
455
505
|
const json = JSON.parse(cached);
|
|
456
|
-
//
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
//
|
|
460
|
-
if (
|
|
461
|
-
|
|
506
|
+
// removes the cache file if older than its maximum age.
|
|
507
|
+
// entries written by older clients embed a timestamp in
|
|
508
|
+
// the manifest itself; treat those as expired so they get
|
|
509
|
+
// rewritten in the mtime-tracked format.
|
|
510
|
+
if (st.mtimeMs < this.#manifestCacheMinAge ||
|
|
511
|
+
json.__VLT_MANIFEST_CACHE_TIMESTAMP !== undefined) {
|
|
512
|
+
this.#manifestWritePaths.delete(cachePath);
|
|
462
513
|
void unlink(cachePath).catch(() => { });
|
|
463
514
|
throw new Error('manifest cache expired');
|
|
464
515
|
}
|
|
@@ -471,27 +522,12 @@ export class PackageInfoClient {
|
|
|
471
522
|
const mani = pickManifest(await this.packument(f, options), spec, options);
|
|
472
523
|
if (!mani)
|
|
473
524
|
throw this.#resolveError(spec, options);
|
|
474
|
-
// Cache the manifest data
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
__VLT_MANIFEST_CACHE_TIMESTAMP: Date.now(),
|
|
481
|
-
});
|
|
482
|
-
void writeFile(cachePath, json, 'utf8').catch((err) => {
|
|
483
|
-
// in case the cache directory doesn't exist
|
|
484
|
-
// just create it and retry
|
|
485
|
-
if (err instanceof Error &&
|
|
486
|
-
'code' in err &&
|
|
487
|
-
err.code === 'ENOENT') {
|
|
488
|
-
void mkdir(dirname(cachePath), {
|
|
489
|
-
recursive: true,
|
|
490
|
-
}).then(() => {
|
|
491
|
-
void writeFile(cachePath, json, 'utf8');
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
});
|
|
525
|
+
// Cache the manifest data. Skip paths already written this
|
|
526
|
+
// run — first writer wins, avoiding duplicate serialization
|
|
527
|
+
// and racing writers for the same path.
|
|
528
|
+
if (cachePath && !this.#manifestWritePaths.has(cachePath)) {
|
|
529
|
+
this.#manifestWritePaths.add(cachePath);
|
|
530
|
+
void this.#writeManifestCache(cachePath, JSON.stringify(mani));
|
|
495
531
|
}
|
|
496
532
|
return mani;
|
|
497
533
|
}
|
|
@@ -505,7 +541,7 @@ export class PackageInfoClient {
|
|
|
505
541
|
await clone(gitRemote, gitCommittish, dir, { spec: s });
|
|
506
542
|
const { path } = gitSelectorParsed ?? {};
|
|
507
543
|
const pkgDir = path !== undefined ? pathResolve(dir, path) : dir;
|
|
508
|
-
return this
|
|
544
|
+
return this.#readExtracted(pkgDir, s, options);
|
|
509
545
|
});
|
|
510
546
|
}
|
|
511
547
|
// fallthrough to remote
|
|
@@ -517,7 +553,7 @@ export class PackageInfoClient {
|
|
|
517
553
|
}
|
|
518
554
|
const s = spec;
|
|
519
555
|
return await this.#tmpdir(async (dir) => {
|
|
520
|
-
const response = await this.
|
|
556
|
+
const response = await (await this.getRegistryClient()).request(remoteURL);
|
|
521
557
|
if (response.statusCode !== 200) {
|
|
522
558
|
throw this.#resolveError(s, options, 'failed to fetch URL', { response, url: remoteURL });
|
|
523
559
|
}
|
|
@@ -527,13 +563,13 @@ export class PackageInfoClient {
|
|
|
527
563
|
.fromData(buf, { algorithms: ['sha512'] })
|
|
528
564
|
.toString();
|
|
529
565
|
try {
|
|
530
|
-
await this.
|
|
566
|
+
await (await this.getTarPool()).unpack(buf, dir);
|
|
531
567
|
}
|
|
532
568
|
catch (er) {
|
|
533
569
|
throw this.#resolveError(s, options, 'tar unpack failed', { cause: er });
|
|
534
570
|
}
|
|
535
571
|
// return manifest with computed integrity
|
|
536
|
-
const mani = this
|
|
572
|
+
const mani = this.#readExtracted(dir, s, options);
|
|
537
573
|
mani.dist = { integrity: computed };
|
|
538
574
|
return mani;
|
|
539
575
|
});
|
|
@@ -550,12 +586,12 @@ export class PackageInfoClient {
|
|
|
550
586
|
const s = spec;
|
|
551
587
|
return await this.#tmpdir(async (dir) => {
|
|
552
588
|
try {
|
|
553
|
-
await this.
|
|
589
|
+
await (await this.getTarPool()).unpack(await readFile(path), dir);
|
|
554
590
|
}
|
|
555
591
|
catch (er) {
|
|
556
592
|
throw this.#resolveError(s, options, 'tar unpack failed', { cause: er });
|
|
557
593
|
}
|
|
558
|
-
return this
|
|
594
|
+
return this.#readExtracted(dir, s, options);
|
|
559
595
|
});
|
|
560
596
|
}
|
|
561
597
|
case 'workspace': {
|
|
@@ -600,6 +636,7 @@ export class PackageInfoClient {
|
|
|
600
636
|
const { registry, name } = f;
|
|
601
637
|
if (!registry)
|
|
602
638
|
throw noRegistryError(spec);
|
|
639
|
+
// Coalescing key has no representation component (see #fetchPackument).
|
|
603
640
|
const packumentKey = `${registry}${name}`;
|
|
604
641
|
const inflight = this.#packumentPromises.get(packumentKey);
|
|
605
642
|
if (inflight)
|
|
@@ -615,9 +652,35 @@ export class PackageInfoClient {
|
|
|
615
652
|
}
|
|
616
653
|
}
|
|
617
654
|
}
|
|
618
|
-
async #fetchPackument(spec, options, pakuURL) {
|
|
619
|
-
|
|
655
|
+
async #fetchPackument(spec, options, pakuURL, useCache) {
|
|
656
|
+
// Always request the full packument (`application/json`), never the
|
|
657
|
+
// abbreviated "corgi" form:
|
|
658
|
+
// accept: application/vnd.npm.install-v1+json; q=1.0,
|
|
659
|
+
// application/json; q=0.8, */*
|
|
660
|
+
//
|
|
661
|
+
// Corgi is smaller (~−41% packument bytes, est. 1–3s on clean installs)
|
|
662
|
+
// but is disabled for two load-bearing reasons:
|
|
663
|
+
//
|
|
664
|
+
// 1. Metadata loss reaches the lockfile. The version entry returned
|
|
665
|
+
// here is `node.manifest` and is persisted to vlt-lock.json / the
|
|
666
|
+
// hidden lockfile. Corgi drops `license` (also `time`, `readme`,
|
|
667
|
+
// `maintainers`, `_rev`, `scripts`), so graph queries like
|
|
668
|
+
// `[license=MPL-2.0]` cannot match a field that was never stored.
|
|
669
|
+
// Shipped in 1.0.0-rc.33 via #1692 (8ba2b10c); 24 false-positive
|
|
670
|
+
// edges in the dependency-check job on #1704
|
|
671
|
+
// (`@resvg/resvg-wasm@2.6.2` MPL-2.0 in package.json, blank in the
|
|
672
|
+
// stored graph); isolated in #1705; reverted in #1707.
|
|
673
|
+
//
|
|
674
|
+
// 2. The RegistryClient disk cache key is method + URL only — no
|
|
675
|
+
// accept, no Vary — so a full-packument request can be served a
|
|
676
|
+
// cached abbreviated body (and vice versa).
|
|
677
|
+
//
|
|
678
|
+
// To revisit: put the requested representation on both the disk-cache
|
|
679
|
+
// key and the in-flight coalescing key, and have the SWR child
|
|
680
|
+
// (cache-revalidate / revalidate) re-request the same representation.
|
|
681
|
+
const response = await (await this.getRegistryClient()).request(pakuURL, {
|
|
620
682
|
headers: { accept: 'application/json' },
|
|
683
|
+
...(useCache === false ? { useCache } : {}),
|
|
621
684
|
});
|
|
622
685
|
if (response.statusCode !== 200) {
|
|
623
686
|
throw this.#resolveError(spec, options, 'failed to fetch packument', {
|
|
@@ -625,7 +688,15 @@ export class PackageInfoClient {
|
|
|
625
688
|
response,
|
|
626
689
|
});
|
|
627
690
|
}
|
|
628
|
-
|
|
691
|
+
try {
|
|
692
|
+
return response.json();
|
|
693
|
+
}
|
|
694
|
+
catch (er) {
|
|
695
|
+
if (useCache !== false) {
|
|
696
|
+
return this.#fetchPackument(spec, options, pakuURL, false);
|
|
697
|
+
}
|
|
698
|
+
throw er;
|
|
699
|
+
}
|
|
629
700
|
}
|
|
630
701
|
async resolve(spec, options = {}) {
|
|
631
702
|
const memoKey = String(spec);
|
|
@@ -723,6 +794,19 @@ export class PackageInfoClient {
|
|
|
723
794
|
}
|
|
724
795
|
}
|
|
725
796
|
}
|
|
797
|
+
/**
|
|
798
|
+
* Read the manifest out of a directory we cloned or unpacked. Failures are
|
|
799
|
+
* labeled with the spec, because the internal directory says nothing about
|
|
800
|
+
* which dependency is at fault.
|
|
801
|
+
*/
|
|
802
|
+
#readExtracted(dir, spec, options) {
|
|
803
|
+
try {
|
|
804
|
+
return this.packageJson.read(dir);
|
|
805
|
+
}
|
|
806
|
+
catch (er) {
|
|
807
|
+
throw this.#resolveError(spec, options, 'invalid package manifest', { cause: er });
|
|
808
|
+
}
|
|
809
|
+
}
|
|
726
810
|
async #tmpdir(fn) {
|
|
727
811
|
const p = `package-info/${randomBytes(6).toString('hex')}`;
|
|
728
812
|
const dir = xdg.runtime(p);
|
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.3",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/vltpkg/vltpkg.git",
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
"url": "http://vlt.sh"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@vltpkg/error-cause": "1.0.
|
|
17
|
-
"@vltpkg/git": "1.0.
|
|
18
|
-
"@vltpkg/package-json": "1.0.
|
|
19
|
-
"@vltpkg/pick-manifest": "1.0.
|
|
20
|
-
"@vltpkg/registry-client": "1.0.
|
|
21
|
-
"@vltpkg/spec": "1.0.
|
|
22
|
-
"@vltpkg/tar": "1.0.
|
|
23
|
-
"@vltpkg/types": "1.0.
|
|
24
|
-
"@vltpkg/workspaces": "1.0.
|
|
25
|
-
"@vltpkg/xdg": "1.0.
|
|
16
|
+
"@vltpkg/error-cause": "1.0.3",
|
|
17
|
+
"@vltpkg/git": "1.0.3",
|
|
18
|
+
"@vltpkg/package-json": "1.0.3",
|
|
19
|
+
"@vltpkg/pick-manifest": "1.0.3",
|
|
20
|
+
"@vltpkg/registry-client": "1.0.3",
|
|
21
|
+
"@vltpkg/spec": "1.0.3",
|
|
22
|
+
"@vltpkg/tar": "1.0.3",
|
|
23
|
+
"@vltpkg/types": "1.0.3",
|
|
24
|
+
"@vltpkg/workspaces": "1.0.3",
|
|
25
|
+
"@vltpkg/xdg": "1.0.3",
|
|
26
26
|
"ssri": "^13.0.0",
|
|
27
27
|
"tar": "^7.5.2"
|
|
28
28
|
},
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"@types/node": "^22.19.2",
|
|
32
32
|
"@types/pacote": "^11.1.8",
|
|
33
33
|
"@vltpkg/benchmark": "0.0.0",
|
|
34
|
-
"@vltpkg/cache-unzip": "1.0.
|
|
35
|
-
"@vltpkg/vlt-json": "1.0.
|
|
34
|
+
"@vltpkg/cache-unzip": "1.0.3",
|
|
35
|
+
"@vltpkg/vlt-json": "1.0.3",
|
|
36
36
|
"eslint": "^9.39.1",
|
|
37
37
|
"pacote": "^21.0.4",
|
|
38
38
|
"prettier": "^3.7.4",
|