Concurrent downloader of npm-compatible packages within the pnpm ecosystem
npx @tessl/cli install tessl/npm-pnpm--package-requester@1006.0.00
# @pnpm/package-requester
1
2
@pnpm/package-requester is a concurrent downloader for npm-compatible packages within the pnpm ecosystem. It provides a factory function that creates a package requester instance capable of resolving, fetching, and managing packages with advanced concurrency control, caching, and integrity verification.
3
4
## Package Information
5
6
- **Package Name**: @pnpm/package-requester
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `pnpm add @pnpm/logger @pnpm/package-requester`
10
11
## Core Imports
12
13
```typescript
14
import { createPackageRequester, type PackageResponse } from "@pnpm/package-requester";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const { createPackageRequester } = require("@pnpm/package-requester");
21
```
22
23
## Basic Usage
24
25
```typescript
26
import { createPackageRequester } from "@pnpm/package-requester";
27
28
// Create a package requester instance
29
const { requestPackage, fetchPackageToStore, getFilesIndexFilePath } = createPackageRequester({
30
resolve: myResolveFunction,
31
fetchers: myFetchers,
32
cafs: myCafs,
33
storeDir: "/path/to/store",
34
verifyStoreIntegrity: true,
35
virtualStoreDirMaxLength: 1024
36
});
37
38
// Request a package with resolution and fetching
39
const response = await requestPackage(
40
{ bareSpecifier: "^4.17.0", alias: "lodash" },
41
{
42
projectDir: "/path/to/project",
43
lockfileDir: "/path/to/project",
44
preferredVersions: {},
45
downloadPriority: 0
46
}
47
);
48
49
// Access the resolved package
50
console.log(response.body.manifest.name); // "lodash"
51
console.log(response.body.resolution.integrity); // integrity hash
52
```
53
54
## Capabilities
55
56
### Package Requester Factory
57
58
Creates a package requester instance with methods for requesting, fetching, and managing packages.
59
60
```typescript { .api }
61
function createPackageRequester(opts: CreatePackageRequesterOptions): PackageRequesterInstance;
62
63
interface CreatePackageRequesterOptions {
64
/** Enforce engine compatibility strict mode */
65
engineStrict?: boolean;
66
/** Force refetch packages, ignoring cache */
67
force?: boolean;
68
/** Node.js version for compatibility checks */
69
nodeVersion?: string;
70
/** pnpm version */
71
pnpmVersion?: string;
72
/** Package resolution function */
73
resolve: ResolveFunction;
74
/** Package fetchers organized by hosting type */
75
fetchers: Fetchers;
76
/** Content-addressable file store instance */
77
cafs: Cafs;
78
/** File ignore predicate function */
79
ignoreFile?: (filename: string) => boolean;
80
/** Network request concurrency limit (minimum 16) */
81
networkConcurrency?: number;
82
/** Store directory path */
83
storeDir: string;
84
/** Enable store integrity verification */
85
verifyStoreIntegrity: boolean;
86
/** Maximum virtual store directory path length */
87
virtualStoreDirMaxLength: number;
88
/** Enable strict package content validation */
89
strictStorePkgContentCheck?: boolean;
90
}
91
92
interface PackageRequesterInstance {
93
/** Request and resolve packages with caching and concurrency control */
94
requestPackage: RequestPackageFunction;
95
/** Fetch packages directly to store without resolution */
96
fetchPackageToStore: FetchPackageToStoreFunction;
97
/** Get package files index path */
98
getFilesIndexFilePath: GetFilesIndexFilePath;
99
/** Direct access to the request package function (same as requestPackage) */
100
(wantedDependency: WantedDependency & { optional?: boolean }, options: RequestPackageOptions): Promise<PackageResponse>;
101
}
102
```
103
104
### Request Package Function
105
106
Main function for requesting packages with resolution, fetching, and caching.
107
108
```typescript { .api }
109
interface RequestPackageFunction {
110
(
111
wantedDependency: WantedDependency & { optional?: boolean },
112
options: RequestPackageOptions
113
): Promise<PackageResponse>;
114
}
115
116
type WantedDependency = {
117
/** Whether dependency was injected */
118
injected?: boolean;
119
/** Previous version specifier */
120
prevSpecifier?: string;
121
} & ({
122
/** Package alias (optional when bareSpecifier provided) */
123
alias?: string;
124
/** Version range, tag, or exact version */
125
bareSpecifier: string;
126
} | {
127
/** Package alias (required when bareSpecifier is optional) */
128
alias: string;
129
/** Version range, tag, or exact version (optional when alias provided) */
130
bareSpecifier?: string;
131
});
132
133
interface RequestPackageOptions {
134
/** Always try workspace packages first */
135
alwaysTryWorkspacePackages?: boolean;
136
/** Current package info for updates */
137
currentPkg?: {
138
id?: PkgResolutionId;
139
name?: string;
140
resolution?: Resolution;
141
version?: string;
142
};
143
/** Expected package name/version from lockfile */
144
expectedPkg?: PkgNameVersion;
145
/** Default tag for resolution (e.g., 'latest') */
146
defaultTag?: string;
147
/** Pick lowest version when multiple options available */
148
pickLowestVersion?: boolean;
149
/** Filter packages by publication date */
150
publishedBy?: Date;
151
/** Download priority level (0 = highest) */
152
downloadPriority: number;
153
/** Skip running scripts during processing */
154
ignoreScripts?: boolean;
155
/** Project directory path */
156
projectDir: string;
157
/** Lockfile directory path */
158
lockfileDir: string;
159
/** Version preferences for resolution */
160
preferredVersions: PreferredVersions;
161
/** Prefer workspace packages over registry packages */
162
preferWorkspacePackages?: boolean;
163
/** Enable side effects caching */
164
sideEffectsCache?: boolean;
165
/** Skip fetching, only resolve */
166
skipFetch?: boolean;
167
/** Update strategy: 'compatible', 'latest', or false */
168
update?: 'compatible' | 'latest' | false;
169
/** Available workspace packages */
170
workspacePackages?: WorkspacePackages;
171
/** Force resolution even if cached */
172
forceResolve?: boolean;
173
/** Platform architecture constraints */
174
supportedArchitectures?: SupportedArchitectures;
175
/** Error handling callback for fetch errors */
176
onFetchError?: OnFetchError;
177
/** Inject workspace packages into dependency resolution */
178
injectWorkspacePackages?: boolean;
179
/** Calculate exact version specifier */
180
calcSpecifier?: boolean;
181
/** Pinned version preference */
182
pinnedVersion?: PinnedVersion;
183
}
184
```
185
186
### Fetch Package to Store Function
187
188
Fetch packages directly to store without resolution step.
189
190
```typescript { .api }
191
interface FetchPackageToStoreFunction {
192
(opts: FetchPackageToStoreOptions): Promise<FetchResponse>;
193
}
194
195
interface FetchPackageToStoreOptions {
196
/** Fetch raw manifest without processing */
197
fetchRawManifest?: boolean;
198
/** Force refetch, ignoring cache */
199
force: boolean;
200
/** Skip running scripts during package processing */
201
ignoreScripts?: boolean;
202
/** Lockfile directory path */
203
lockfileDir: string;
204
/** Package information with ID and resolution */
205
pkg: PkgNameVersion & {
206
id: string;
207
resolution: Resolution;
208
};
209
/** Error handling callback */
210
onFetchError?: OnFetchError;
211
/** Platform architecture constraints */
212
supportedArchitectures?: SupportedArchitectures;
213
}
214
215
type OnFetchError = (error: Error) => Error;
216
217
interface FetchResponse {
218
/** Files index file path */
219
filesIndexFile: string;
220
/** Fetching promise for lazy evaluation */
221
fetching: () => Promise<PkgRequestFetchResult>;
222
}
223
```
224
225
### Get Files Index File Path Function
226
227
Get file index path for package files management.
228
229
```typescript { .api }
230
interface GetFilesIndexFilePath {
231
(
232
opts: Pick<FetchPackageToStoreOptions, 'pkg' | 'ignoreScripts' | 'supportedArchitectures'>
233
): {
234
target: string;
235
filesIndexFile: string;
236
resolution: AtomicResolution;
237
};
238
}
239
```
240
241
## Types
242
243
```typescript { .api }
244
interface PackageResponse {
245
/** Optional fetching promise for lazy evaluation */
246
fetching?: () => Promise<PkgRequestFetchResult>;
247
/** Files index file path */
248
filesIndexFile?: string;
249
/** Response body with package metadata */
250
body: {
251
/** Whether package is local */
252
isLocal: boolean;
253
/** Installation compatibility flag */
254
isInstallable?: boolean;
255
/** Package resolution information */
256
resolution: Resolution;
257
/** Package manifest (package.json content) */
258
manifest?: PackageManifest;
259
/** Package resolution ID */
260
id: string;
261
/** Normalized bare specifier */
262
normalizedBareSpecifier?: string;
263
/** Whether package was updated */
264
updated: boolean;
265
/** Publication timestamp */
266
publishedAt?: string;
267
/** Resolution method used */
268
resolvedVia?: string;
269
/** Latest version information */
270
latest?: string;
271
/** Package alias */
272
alias?: string;
273
};
274
}
275
276
interface BundledManifest {
277
/** Binary executable definitions */
278
bin?: Record<string, string>;
279
/** Bundled dependencies list */
280
bundledDependencies?: string[];
281
/** Legacy bundled dependencies list */
282
bundleDependencies?: string[];
283
/** CPU architecture constraints */
284
cpu?: string[];
285
/** Runtime dependencies */
286
dependencies?: Record<string, string>;
287
/** Directory mappings */
288
directories?: Record<string, string>;
289
/** Engine requirements */
290
engines?: Record<string, string>;
291
/** Package name */
292
name?: string;
293
/** Optional dependencies */
294
optionalDependencies?: Record<string, string>;
295
/** Operating system constraints */
296
os?: string[];
297
/** Peer dependencies */
298
peerDependencies?: Record<string, string>;
299
/** Peer dependencies metadata */
300
peerDependenciesMeta?: Record<string, any>;
301
/** Build and lifecycle scripts */
302
scripts?: Record<string, string>;
303
/** Package version */
304
version?: string;
305
}
306
307
interface PreferredVersions {
308
[packageName: string]: VersionSelectors;
309
}
310
311
interface SupportedArchitectures {
312
os?: string[];
313
cpu?: string[];
314
libc?: string[];
315
}
316
317
type Resolution = AtomicResolution | VariationsResolution;
318
319
interface PackageManifest {
320
/** Package name */
321
name: string;
322
/** Package version */
323
version: string;
324
/** Package description */
325
description?: string;
326
/** Main entry point */
327
main?: string;
328
/** Module entry point */
329
module?: string;
330
/** TypeScript definitions */
331
types?: string;
332
/** Package dependencies */
333
dependencies?: Record<string, string>;
334
/** Development dependencies */
335
devDependencies?: Record<string, string>;
336
/** Peer dependencies */
337
peerDependencies?: Record<string, string>;
338
/** Optional dependencies */
339
optionalDependencies?: Record<string, string>;
340
[key: string]: any;
341
}
342
343
interface PkgRequestFetchResult {
344
/** Bundled manifest */
345
bundledManifest?: BundledManifest;
346
/** Package files response with index and metadata */
347
files: PackageFilesResponse;
348
}
349
350
interface PkgNameVersion {
351
/** Package name */
352
name?: string;
353
/** Package version */
354
version?: string;
355
}
356
357
interface PackageFilesIndex {
358
/** Package name (nullable for backward compatibility) */
359
name?: string;
360
/** Package version (nullable for backward compatibility) */
361
version?: string;
362
/** Whether package requires build step */
363
requiresBuild?: boolean;
364
/** File entries mapping */
365
files: PackageFiles;
366
/** Side effects information */
367
sideEffects?: SideEffects;
368
}
369
370
interface PackageFileInfo {
371
/** Last checked timestamp (nullable for backward compatibility) */
372
checkedAt?: number;
373
/** File integrity hash */
374
integrity: string;
375
/** File mode/permissions */
376
mode: number;
377
/** File size in bytes */
378
size: number;
379
}
380
381
type PackageFiles = Record<string, PackageFileInfo>;
382
383
type SideEffects = Record<string, boolean>;
384
385
interface PackageFilesResponse {
386
/** Whether files came from cache without processing */
387
unprocessed?: boolean;
388
/** Files index mapping filenames to file info */
389
filesIndex: PackageFiles;
390
/** Where files were resolved from */
391
resolvedFrom: ResolvedFrom;
392
/** Package import method for directory packages */
393
packageImportMethod?: string;
394
/** Side effects information */
395
sideEffects?: SideEffects;
396
/** Whether package requires build step */
397
requiresBuild: boolean;
398
}
399
400
type ResolvedFrom = 'remote' | 'store' | 'local-dir';
401
402
type VersionSelectorType = 'version' | 'range' | 'tag';
403
404
interface VersionSelectors {
405
[selector: string]: VersionSelectorWithWeight | VersionSelectorType;
406
}
407
408
interface VersionSelectorWithWeight {
409
selectorType: VersionSelectorType;
410
weight: number;
411
}
412
413
type PkgResolutionId = string;
414
415
type WorkspacePackages = Map<string, WorkspacePackagesByVersion>;
416
417
interface WorkspacePackagesByVersion {
418
[version: string]: {
419
dir: string;
420
manifest: PackageManifest;
421
};
422
}
423
424
type PinnedVersion = 'major' | 'minor' | 'patch';
425
426
type AtomicResolution = TarballResolution | DirectoryResolution | GitResolution | BinaryResolution;
427
428
interface TarballResolution {
429
type?: undefined;
430
tarball: string;
431
integrity?: string;
432
path?: string;
433
}
434
435
interface BinaryResolution {
436
type: 'binary';
437
archive: 'tarball' | 'zip';
438
url: string;
439
integrity: string;
440
bin: string;
441
prefix?: string;
442
}
443
444
interface DirectoryResolution {
445
type: 'directory';
446
directory: string;
447
}
448
449
interface GitResolution {
450
commit: string;
451
repo: string;
452
path?: string;
453
type: 'git';
454
}
455
456
type VariationsResolution = {
457
type: 'variations';
458
variants: PlatformAssetResolution[];
459
};
460
461
interface PlatformAssetResolution {
462
resolution: AtomicResolution;
463
targets: PlatformAssetTarget[];
464
}
465
466
interface PlatformAssetTarget {
467
os: string;
468
cpu: string;
469
libc?: 'musl';
470
}
471
```
472
473
## Error Handling
474
475
The package requester handles various error conditions:
476
477
- **Resolution failures**: Throws `PnpmError` when packages cannot be resolved
478
- **Network failures**: Implements retry logic for temporary network issues
479
- **Integrity violations**: Validates package integrity and refetches on mismatch
480
- **Store corruption**: Detects corrupted store content and triggers refetch
481
- **Package compatibility**: Validates engine requirements and architecture constraints
482
483
## Architecture
484
485
The package requester is built on several key components:
486
487
- **Concurrency Control**: Uses `p-queue` for managing concurrent network requests with configurable limits
488
- **Content-Addressable Storage**: Integrates with pnpm's CAFS for efficient package storage and deduplication
489
- **Resolution Pipeline**: Separates package resolution from fetching for flexibility and performance
490
- **Integrity Verification**: Uses subresource integrity (SRI) for package validation
491
- **Platform Awareness**: Handles platform-specific packages and architecture constraints
492
- **Caching Layer**: Implements sophisticated caching with integrity checks and staleness detection