0
# Package Import and Linking
1
2
Import packages from the CAFS store and create symbolic links for module resolution in Node.js projects.
3
4
## Capabilities
5
6
### Import Package
7
8
Imports a package from the CAFS store to a target directory using various import methods. This operation is limited to 4 concurrent operations for optimal performance.
9
10
```typescript { .api }
11
/**
12
* Imports a package using the worker pool with concurrency limit
13
* @param opts - Import configuration options (excludes 'type' from LinkPkgMessage)
14
* @returns Promise resolving to import results with build status
15
*/
16
function importPackage(opts: Omit<LinkPkgMessage, 'type'>): Promise<ImportPackageResult>;
17
18
interface LinkPkgMessage {
19
type: 'link';
20
/** Store directory path where package files are located */
21
storeDir: string;
22
/** Import method to use for package installation */
23
packageImportMethod?: 'auto' | 'hardlink' | 'copy' | 'clone' | 'clone-or-copy';
24
/** Package files response containing file metadata */
25
filesResponse: PackageFilesResponse;
26
/** Optional cache key for side effects */
27
sideEffectsCacheKey?: string | undefined;
28
/** Target directory where package should be installed */
29
targetDir: string;
30
/** Whether the package requires a build step */
31
requiresBuild?: boolean;
32
/** Force import even if target already exists */
33
force: boolean;
34
/** Keep existing modules directory */
35
keepModulesDir?: boolean;
36
/** Disable relinking of local directory dependencies */
37
disableRelinkLocalDirDeps?: boolean;
38
}
39
40
interface ImportPackageResult {
41
/** Whether the package was built during import */
42
isBuilt: boolean;
43
/** Actual import method used (may differ from requested method) */
44
importMethod: string | undefined;
45
}
46
```
47
48
**Usage Examples:**
49
50
```typescript
51
import { importPackage } from "@pnpm/worker";
52
53
// Basic package import with auto method selection
54
const result = await importPackage({
55
storeDir: "/path/to/pnpm/store",
56
filesResponse: {
57
/* PackageFilesResponse data */
58
},
59
targetDir: "/project/node_modules/lodash",
60
force: false
61
});
62
63
console.log("Package imported with method:", result.importMethod);
64
console.log("Package was built:", result.isBuilt);
65
66
// Import with specific method and build requirements
67
const buildResult = await importPackage({
68
storeDir: "/path/to/store",
69
packageImportMethod: "hardlink",
70
filesResponse: packageFiles,
71
targetDir: "/project/node_modules/native-package",
72
requiresBuild: true,
73
force: true,
74
keepModulesDir: true
75
});
76
```
77
78
### Symlink All Modules
79
80
Creates symbolic links for all modules in dependencies. This is typically used for setting up module resolution after package import.
81
82
```typescript { .api }
83
/**
84
* Creates symbolic links for all modules in dependencies
85
* @param opts - Symlinking configuration options (excludes 'type' from SymlinkAllModulesMessage)
86
* @returns Promise resolving to symlinking results
87
*/
88
function symlinkAllModules(opts: Omit<SymlinkAllModulesMessage, 'type'>): Promise<ImportPackageResult>;
89
90
interface SymlinkAllModulesMessage {
91
type: 'symlinkAllModules';
92
/** Array of dependencies to create symlinks for */
93
deps: Array<{
94
/** Child dependencies mapping alias to package directory */
95
children: Record<string, string>;
96
/** Modules directory path */
97
modules: string;
98
/** Dependency name */
99
name: string;
100
}>;
101
}
102
```
103
104
**Usage Examples:**
105
106
```typescript
107
import { symlinkAllModules } from "@pnpm/worker";
108
109
// Create symlinks for multiple dependencies
110
const symlinkResult = await symlinkAllModules({
111
deps: [
112
{
113
name: "express",
114
modules: "/project/node_modules",
115
children: {
116
"body-parser": "/store/body-parser/1.19.0",
117
"cookie-parser": "/store/cookie-parser/1.4.5",
118
"debug": "/store/debug/4.3.2"
119
}
120
},
121
{
122
name: "lodash",
123
modules: "/project/node_modules",
124
children: {}
125
}
126
]
127
});
128
129
console.log("Symlinks created successfully");
130
```
131
132
### Read Package From CAFS
133
134
Reads package metadata and files from the content-addressable file system store, with optional integrity verification.
135
136
```typescript { .api }
137
/**
138
* Reads package from content-addressable file system store
139
* @param storeDir - Store directory path
140
* @param verifyStoreIntegrity - Whether to verify file integrity
141
* @param filesIndexFile - Path to files index file
142
* @param readManifest - Whether to read package manifest
143
* @returns Promise resolving to package read results
144
*/
145
function readPkgFromCafs(
146
storeDir: string,
147
verifyStoreIntegrity: boolean,
148
filesIndexFile: string,
149
readManifest?: boolean
150
): Promise<ReadPkgFromCafsResult>;
151
152
interface ReadPkgFromCafsResult {
153
/** Whether integrity verification passed */
154
verified: boolean;
155
/** Package files index metadata */
156
pkgFilesIndex: PackageFilesIndex;
157
/** Package manifest if requested and available */
158
manifest?: DependencyManifest;
159
/** Whether the package requires a build step */
160
requiresBuild: boolean;
161
}
162
```
163
164
**Usage Examples:**
165
166
```typescript
167
import { readPkgFromCafs } from "@pnpm/worker";
168
169
// Read package with integrity verification
170
const packageData = await readPkgFromCafs(
171
"/path/to/pnpm/store",
172
true, // verify integrity
173
"/path/to/package/index.json",
174
true // read manifest
175
);
176
177
if (packageData.verified) {
178
console.log("Package integrity verified");
179
console.log("Package name:", packageData.manifest?.name);
180
console.log("Requires build:", packageData.requiresBuild);
181
} else {
182
console.log("Package integrity check failed - refetch required");
183
}
184
185
// Quick read without verification
186
const quickRead = await readPkgFromCafs(
187
"/path/to/store",
188
false, // skip verification
189
"/path/to/index.json"
190
);
191
```
192
193
## Import Methods
194
195
The `packageImportMethod` parameter supports several strategies:
196
197
### Auto (Default)
198
Automatically selects the best method based on the environment and file system capabilities.
199
200
### Hardlink
201
Creates hard links to files in the store. Most efficient but requires same file system.
202
203
### Copy
204
Copies files from store to target. Slower but works across file systems.
205
206
### Clone
207
Uses copy-on-write cloning when supported by the file system (e.g., APFS, Btrfs).
208
209
### Clone-or-Copy
210
Attempts cloning first, falls back to copying if cloning is not supported.
211
212
## Error Handling
213
214
### ExFAT Drive Detection
215
216
On Windows, the library detects exFAT drives which don't support symlinks:
217
218
```typescript
219
// Error handling for exFAT drives
220
try {
221
await symlinkAllModules({
222
deps: [/* dependencies */]
223
});
224
} catch (error) {
225
if (error.code === 'EISDIR' && error.message.includes('exFAT')) {
226
console.error('ExFAT drive detected - symlinks not supported');
227
console.log('Consider setting node-linker to "hoisted"');
228
}
229
}
230
```
231
232
### Concurrent Import Limits
233
234
The `importPackage` function automatically limits concurrent operations to 4 for optimal performance. This prevents file system overwhelming during large installations.
235
236
## Package Files Response
237
238
The `PackageFilesResponse` interface contains metadata about package files stored in CAFS:
239
240
```typescript { .api }
241
interface PackageFilesResponse {
242
/** File integrity information and metadata */
243
files: Record<string, FileInfo>;
244
/** Additional package metadata */
245
[key: string]: any;
246
}
247
248
interface FileInfo {
249
/** File integrity hash */
250
integrity: string;
251
/** File permissions mode */
252
mode: number;
253
/** File size in bytes */
254
size: number;
255
/** Timestamp when file was last checked */
256
checkedAt?: number;
257
}
258
```