Skip to content

Commit f5f7ec7

Browse files
committed
doc: add path rules and validation for export targets in package.json
1 parent c1f090d commit f5f7ec7

1 file changed

Lines changed: 57 additions & 0 deletions

File tree

doc/api/packages.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,63 @@ subpaths where possible instead of a separate map entry per package subpath
433433
export. This also mirrors the requirement of using [the full specifier path][]
434434
in relative and absolute import specifiers.
435435

436+
#### Path Rules and Validation for Export Targets
437+
438+
When defining paths as targets in the [`"exports"`][] field, Node.js enforces
439+
several rules to ensure security, predictability, and proper encapsulation.
440+
Understanding these rules is crucial for authors publishing packages.
441+
442+
**1. Targets Must Be Relative and Start with `./`**
443+
444+
All target paths in the [`"exports"`][] map (the values associated with export
445+
keys) **must** be relative path strings starting with `./`.
446+
447+
```json
448+
// package.json
449+
{
450+
"name": "my-package",
451+
"exports": {
452+
".": "./dist/main.js", // Correct
453+
"./feature": "./lib/feature.js", // Correct
454+
// "absolute": "/dist/main.js", // Incorrect: Must start with ./
455+
// "outside": "../common/util.js" // Incorrect: Must start with ./
456+
}
457+
}
458+
```
459+
460+
* **Why?**
461+
* **Security:** Prevents exporting arbitrary files from outside the
462+
package's own directory.
463+
* **Encapsulation:** Ensures all exported paths are resolved relative to
464+
the package root, making the package self-contained.
465+
466+
**2. No Path Traversal and Invalid Segments Disallowed**
467+
468+
Export targets **must not** resolve to a location outside the package's root
469+
directory. Additionally, path segments like `.` (single dot), `..` (double dot),
470+
or `node_modules` (and their URL-encoded equivalents) are generally disallowed
471+
within the `target` string after the initial `./` and in any `subpath` part
472+
substituted into a target pattern.
473+
474+
```json
475+
// package.json
476+
{
477+
"name": "my-package",
478+
"exports": {
479+
// ".": "./dist/../../elsewhere/file.js", // Invalid: path traversal
480+
// ".": "././dist/main.js", // Invalid: contains "." segment
481+
// ".": "./dist/../dist/main.js", // Invalid: contains ".." segment
482+
// "./utils/./helper.js": "./utils/helper.js" // Key has invalid segment
483+
}
484+
}
485+
```
486+
Node.js's resolver (`lib/internal/modules/esm/resolve.js`) checks these.
487+
488+
* **Why?**
489+
* **Security:** Prevents path manipulation, obfuscation, and exposing
490+
sensitive files or executing unintended code.
491+
* **Consistency:** Ensures a standardized and predictable path structure.
492+
436493
### Exports sugar
437494

438495
<!-- YAML

0 commit comments

Comments
 (0)