fyn 3.2.3 → 3.3.1
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/README.md +70 -31
- package/dist/fs-worker.mjs +5477 -0
- package/dist/fyn.mjs +1745 -502
- package/docs/reference.md +680 -0
- package/package.json +11 -8
|
@@ -0,0 +1,680 @@
|
|
|
1
|
+
# fyn reference
|
|
2
|
+
|
|
3
|
+
`fyn` is a Node.js package manager CLI. It installs from the npm registry and from local directories, links local packages by hardlinking their packed files, can keep one copy of each package in a central store, and runs as the installer for fynpo monorepos. It is a command line tool. The package has no documented JS API.
|
|
4
|
+
|
|
5
|
+
## Binaries and requirements
|
|
6
|
+
|
|
7
|
+
| Binary | Behavior |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `fyn` | The CLI. |
|
|
10
|
+
| `fun` | Shortcut for `fyn run`: `fun <script> [args]` is `fyn run <script> [args]`. Exits 0 on success and 1 on any rejection. |
|
|
11
|
+
| `0-npx-please-run-this-for-fyn` | Same entry as `fyn`. |
|
|
12
|
+
|
|
13
|
+
- Requires Node `>= 22.22.2`. An older Node prints `fyn requires node >= 22.22.2, and this is <version>.` and exits 1 before loading the bundle.
|
|
14
|
+
- `fyn` enables the V8 compile cache. `NODE_DISABLE_COMPILE_CACHE=1` turns it off and `NODE_COMPILE_CACHE` moves it. Both are Node variables.
|
|
15
|
+
- The package exports a programmatic entry (`run`, `fun`, `getAuditFilePath` from `bin/index.mjs`) that loads `dist/fyn.mjs` on first call. It is the CLI entry, not a library API.
|
|
16
|
+
|
|
17
|
+
## Invocation rules
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
fyn [options] <command> [command options] [args]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- No command: runs `install`. `fyn --verbose` and `fyn --fi` are installs.
|
|
24
|
+
- A first word that is not a command is treated as `fyn run <word>`. `fyn build` runs the `build` script.
|
|
25
|
+
- Global options (the table below) can be given before or after the command name.
|
|
26
|
+
- Boolean options take `<flag boolean>`. `--name`, `--name=true` and `--no-name` all work. Names are kebab-case on the command line and camelCase in rc files.
|
|
27
|
+
- `-- <args>` after `run` passes the remaining args to the script.
|
|
28
|
+
- `fyn --help` prints help. `fyn --version` prints the version.
|
|
29
|
+
- A parse error prints the error and leaves exit code 1 (the bin wrapper calls `process.exit()` with no argument, so a code already set is kept).
|
|
30
|
+
|
|
31
|
+
## Commands
|
|
32
|
+
|
|
33
|
+
Aliases are in parentheses. Command options are listed with each command. Global options are in "Global options".
|
|
34
|
+
|
|
35
|
+
| Command | Purpose |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| `install` (`i`) | Resolve, fetch and install dependencies. Default command. |
|
|
38
|
+
| `add` (`a`) | Add packages to `package.json`, then install. |
|
|
39
|
+
| `remove` (`rm`) | Remove packages from `package.json`, then install. |
|
|
40
|
+
| `update` | Update locked versions to the newest their ranges allow, then install. |
|
|
41
|
+
| `stat` | Show where an installed package comes from and who depends on it. |
|
|
42
|
+
| `outdated` | List direct registry dependencies that have newer versions. |
|
|
43
|
+
| `audit` | Check resolved packages for known vulnerabilities. |
|
|
44
|
+
| `run` (`rum`, `r`) | Run a `package.json` script. |
|
|
45
|
+
| `init` | Create a `package.json`. |
|
|
46
|
+
| `install-scripts` | Review and record install script approvals. |
|
|
47
|
+
| `prod-prune` | Remove non-runtime files from a production `node_modules`. |
|
|
48
|
+
| `sync-local` (`sl`) | Re-link files of local packages. |
|
|
49
|
+
| `global` | Install and manage global packages. |
|
|
50
|
+
|
|
51
|
+
### `install`
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
fyn [install] [options]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
| Option | Alias | Type | Default | Behavior |
|
|
58
|
+
| --- | --- | --- | --- | --- |
|
|
59
|
+
| `--run-npm [scripts..]` | | string list | none | Extra npm scripts to run after install. Not saved to `.fyn.json`. |
|
|
60
|
+
| `--force-install` | `--fi` | boolean | false | Install even when no file changed since the last install. |
|
|
61
|
+
| `--audit` | | boolean | true | Run a summary audit after install. `--no-audit` skips it. |
|
|
62
|
+
| `--audit-file <path>` | | string | none | After install, write the full audit report as JSON. A relative path is relative to the project dir. |
|
|
63
|
+
| `--allow-scripts-pending` | | boolean | false | Also record which packages would need approval under policy `review`, without changing what runs. |
|
|
64
|
+
|
|
65
|
+
Sequence:
|
|
66
|
+
|
|
67
|
+
1. Load `package.json`, then merge `package-fyn.json` over it (see "Package fyn section").
|
|
68
|
+
2. Skip with the message `No changes detected since last fyn install` when all of these hold: not `--force-install`, not changing production mode, the saved `fynlocal` equals the current one, a saved install time exists, no scanned file is newer than that time, no local package changed, and `fyn-lock.yaml` exists. The audit summary still runs in this case. Exit code is 0.
|
|
69
|
+
3. Take the install lock `<targetDir>/.f/.installing.lock` (waits 3 s, treats a lock older than 30 minutes as stale). A second concurrent install in the same dir fails to get the lock.
|
|
70
|
+
4. Run the project's `preinstall` script, if it has one.
|
|
71
|
+
5. Resolve dependencies, fetch tarballs, install into `node_modules`.
|
|
72
|
+
6. Run the project's `install`, `postinstall` and `prepare` scripts (those that exist, in that order). `prepublish` is not run.
|
|
73
|
+
7. Run the npm scripts from `--run-npm` and from the fynpo `command.bootstrap.npmRunScripts` setting, when `--auto-run` is on. In a fynpo package the default is `["build"]` unless `npmRunScripts` is `false`. An entry that is an array runs only its first script that exists.
|
|
74
|
+
8. Refresh hardlinks of local packages if scripts ran, save `fyn-lock.yaml` and the installed copy, save `.fyn.json`, and print the audit summary.
|
|
75
|
+
|
|
76
|
+
Files scanned for the freshness check include `package.json`, `package-fyn.json`, `fyn-lock.yaml`, `package-lock.json`, `npm-shrinkwrap.json`, `yarn.lock`, `.npmrc`, `.fynrc`, `fynpo.json`, `fynpo.config.js`, `fynpo.config.json`.
|
|
77
|
+
|
|
78
|
+
Production mode is sticky. If the existing `node_modules` was installed with `--production` and the flag source is the default, fyn keeps production mode. `--no-production` switches it off and reinstalls. `--production` on a non-production tree switches it on.
|
|
79
|
+
|
|
80
|
+
Layout is sticky. If `.fyn.json` records a different `layout`, that layout is used. A warning appears when `--layout` was given. Remove `node_modules` to change layout.
|
|
81
|
+
|
|
82
|
+
Exit codes:
|
|
83
|
+
|
|
84
|
+
| Code | Cause |
|
|
85
|
+
| --- | --- |
|
|
86
|
+
| 0 | Success, or "No Change". |
|
|
87
|
+
| 1 | Install failure (resolution, fetch, script, local build, unapproved scripts with no terminal, fatal config error). |
|
|
88
|
+
|
|
89
|
+
On failure fyn writes the log to `--save-logs` if set, else to `<os tmpdir>/fyn-debug-<pid>-<timestamp>.log`, and prints the path. Resolution and registry failures are "expected": the stack goes to the log, not the console.
|
|
90
|
+
|
|
91
|
+
### `add`
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
fyn add [packages..] [--dev <pkgs..>] [--opt <pkgs..>] [--peer <pkgs..>] [options]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
| Option | Alias | Type | Default | Behavior |
|
|
98
|
+
| --- | --- | --- | --- | --- |
|
|
99
|
+
| `[packages..]` | | string list | none | Added to `dependencies`. |
|
|
100
|
+
| `--dev [packages..]` | `-d` | string list | none | Added to `devDependencies`. |
|
|
101
|
+
| `--opt [packages..]` | | string list | none | Added to `optionalDependencies`. |
|
|
102
|
+
| `--peer [packages..]` | `-p` | string list | none | Added to `peerDependencies`. |
|
|
103
|
+
| `--install` | | boolean | true | Run `install` after adding. `--no-install` only edits `package.json`. |
|
|
104
|
+
| `--pkg-fyn` | | boolean | false | Save local-path entries in `package-fyn.json` instead of `package.json`. |
|
|
105
|
+
| `--audit` | | boolean | true | Passed to the follow-up install. |
|
|
106
|
+
|
|
107
|
+
Package argument forms:
|
|
108
|
+
|
|
109
|
+
- `name` or `name@spec`. A missing spec is `latest`.
|
|
110
|
+
- `name@tag` resolves a dist-tag to `^<version>`. If that is not a valid range it saves the bare version.
|
|
111
|
+
- `name@range` is saved as given when at least one published version satisfies it. Otherwise `no matching version found for <arg>` is logged and the package is skipped.
|
|
112
|
+
- `alias@npm:real@spec` saves the `npm:` specifier.
|
|
113
|
+
- A directory path, `file:` path, absolute path, `./`, `../` or `~/` path adds a local dependency. If the directory exists it is made relative to the project dir. The `package.json` gets `^<its version>` and a `fyn.<section>.<name>` entry holds the path. In a fynpo monorepo, a name that is a monorepo package gets no `fyn` entry.
|
|
114
|
+
|
|
115
|
+
Rules:
|
|
116
|
+
|
|
117
|
+
- Keys in each edited section are sorted.
|
|
118
|
+
- Up to 10 metadata lookups run at once. The first lookup error stops the rest.
|
|
119
|
+
- The add phase runs with the lockfile off. The install phase runs with it restored.
|
|
120
|
+
- No packages given: `No packages to add`, exit 1.
|
|
121
|
+
- No package resolved: `No packages found for add`, `package.json` unchanged, no install, exit code unchanged (0).
|
|
122
|
+
|
|
123
|
+
### `remove`
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
fyn remove <packages..> [--install] [--audit]
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
| Option | Type | Default | Behavior |
|
|
130
|
+
| --- | --- | --- | --- |
|
|
131
|
+
| `--install` | boolean | true | Run `install` after removing. |
|
|
132
|
+
| `--audit` | boolean | true | Passed to the follow-up install. |
|
|
133
|
+
|
|
134
|
+
Removes each name from `dependencies`, `devDependencies`, `optionalDependencies`, `peerDependencies`, and from the same sections inside the `fyn` block. Empty sections are deleted. Names not found are logged as `These packages don't exist in your package.json`. If nothing was removed it logs `No package was removed`, skips the install and does not set a failing exit code. No names given: `No packages to remove`, exit 1.
|
|
135
|
+
|
|
136
|
+
### `update`
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
fyn update [packages..] [--audit]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
| Option | Type | Default | Behavior |
|
|
143
|
+
| --- | --- | --- | --- |
|
|
144
|
+
| `--audit` | boolean | true | Run a summary audit after the update. |
|
|
145
|
+
|
|
146
|
+
Re-resolves dependencies to the newest versions their declared ranges allow, then installs.
|
|
147
|
+
|
|
148
|
+
- No names: ignores every pin in `fyn-lock.yaml`, or in `<targetDir>/.f/lock.yaml` when there is no lockfile. `package-lock.json`, `npm-shrinkwrap.json` and `yarn.lock` are also ignored.
|
|
149
|
+
- With names: unlocks those packages and every package they depend on, directly or not. Everything else stays pinned. A shared dependency in that subtree updates for all its dependents.
|
|
150
|
+
- A name that is not in the lock data fails with `not found in lock data: <names>`, exit 1.
|
|
151
|
+
- Always fetches fresh registry metadata and skips the "No Change" shortcut.
|
|
152
|
+
- Never edits `package.json`. Use `add` to move past a declared range.
|
|
153
|
+
- After install it prints `name old -> new` for each package whose locked versions changed, then the audit summary.
|
|
154
|
+
|
|
155
|
+
### `stat`
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
fyn stat <package-name>[@semver] [...]
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Resolves dependencies without building local packages, then for each argument lists the installed versions that match. For each match it prints dependents, circular dependencies, and the dependency paths (all of them, or the most significant ones when there are many). A name that matches nothing prints `<arg> is not installed`. At least one argument is required. Exit code 0 unless resolution fails.
|
|
162
|
+
|
|
163
|
+
### `outdated`
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
fyn outdated [package-name ...] [--json]
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
| Option | Alias | Type | Default | Behavior |
|
|
170
|
+
| --- | --- | --- | --- | --- |
|
|
171
|
+
| `--json` | `-j` | boolean | false | Print records as a JSON array on stdout. Logging is set to `none` for the run so stdout is only JSON. |
|
|
172
|
+
|
|
173
|
+
Rules:
|
|
174
|
+
|
|
175
|
+
- Checks direct dependencies from `dependencies`, `devDependencies`, `optionalDependencies` and `devOptDependencies`. When a name is in several sections, `optionalDependencies` wins, then `dependencies`, then `devOptDependencies`, then `devDependencies`.
|
|
176
|
+
- A named package that is not declared throws `dependency "<name>" is not declared`.
|
|
177
|
+
- Skipped without a comparison: local, URL and git dependencies, dependencies that fynlocal resolves to a local path, and optional dependencies whose `os`/`cpu` do not fit this machine.
|
|
178
|
+
- `wanted` is the dist-tag version when the spec is a tag. Otherwise it is the registry `latest` when `latest` satisfies the range, else the highest version that satisfies it. With `--lock-time`, versions published after that time are excluded in the fallback search.
|
|
179
|
+
- `latest` is the registry `latest` tag, or `null`.
|
|
180
|
+
- `current` is the version in `<targetDir>/<name>/package.json`, or `null` (shown as `MISSING`) when it is not installed.
|
|
181
|
+
- A dependency is reported unless `current === wanted` and (`latest` is missing or `wanted === latest`).
|
|
182
|
+
- Record fields: `name`, `type` (`prod`, `dev`, `optional`, `devOptional`), `requested`, `current`, `wanted`, `latest`, and `resolvedName` for aliases.
|
|
183
|
+
- The table has columns `Package`, `Current`, `Wanted`, `Latest`, `Type`, `Requested`. Empty results log `All N direct dependencies are up to date`, or `No registry dependencies to check` when everything was skipped. `--json` prints `[]`.
|
|
184
|
+
- Errors (bad spec, missing tag target, no matching version, registry failure, unreadable installed `package.json`) are thrown and make the process exit 1.
|
|
185
|
+
|
|
186
|
+
Exit code: 1 when at least one record is reported, 0 when none. It does not change any file.
|
|
187
|
+
|
|
188
|
+
### `audit`
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
fyn audit [options]
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
| Option | Alias | Type | Default | Behavior |
|
|
195
|
+
| --- | --- | --- | --- | --- |
|
|
196
|
+
| `--json` | `-j` | boolean | false | Print `{ vulnerabilities, metadata, advisories }` as JSON. |
|
|
197
|
+
| `--omit [types..]` | | string list | none | Dependency types to leave out: `dev`, `optional`, `peer`. A package is dropped only when every path to it is of an omitted type. |
|
|
198
|
+
| `--audit-level <level>` | | string | `info` | Lowest severity reported: `info`, `low`, `moderate`, `high`, `critical`. |
|
|
199
|
+
| `--cache` | | boolean | true | Use the audit cache. `--no-cache` always fetches. |
|
|
200
|
+
|
|
201
|
+
Rules:
|
|
202
|
+
|
|
203
|
+
- Resolves dependencies (without building local packages), then POSTs the package/version map to `<registry>/-/npm/v1/security/advisories/bulk`. The main `registry` is used, not scoped registries.
|
|
204
|
+
- One attempt, 10 second timeout, no retries.
|
|
205
|
+
- Cache: `<fynDir>/audit`, entries valid 30 minutes. On a network error an expired cache entry is still used with a warning.
|
|
206
|
+
- Failures are logged as `Audit failed: <message>` and do not set a failing exit code. `FYN_DEBUG` set also prints the stack.
|
|
207
|
+
- The exit code is 0 even when vulnerabilities are found.
|
|
208
|
+
- After `install`, a summary (`audited N packages`, counts by severity) is printed. An audit failure there only logs `Security audit failed:`.
|
|
209
|
+
|
|
210
|
+
### `run`
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
fyn run [script] [args...] [-- <args>...] [options]
|
|
214
|
+
fyn <script> [args...]
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
| Option | Alias | Type | Default | Behavior |
|
|
218
|
+
| --- | --- | --- | --- | --- |
|
|
219
|
+
| `--list` | `-l` | boolean | false | Print script names, one per line, and exit 0. Does not look for fynpo. |
|
|
220
|
+
| `--if-present` | | boolean | false | A missing script returns without error. |
|
|
221
|
+
|
|
222
|
+
Rules:
|
|
223
|
+
|
|
224
|
+
- No script name: prints `Lifecycle scripts included in <name>:` and the script names, exit 0.
|
|
225
|
+
- A missing script logs `Error: missing script: "<name>" - not found in package.json scripts` and exits 1, unless `--if-present`.
|
|
226
|
+
- For a name that does not start with `pre` or `post`, `pre<name>` and `post<name>` run around it when they exist. A name starting with `pre` or `post` runs alone.
|
|
227
|
+
- Args before and after `--` are all passed, but only to the main script, not to its pre/post scripts.
|
|
228
|
+
- Environment follows npm: `npm_*` variables from package data and config, `npm_node_execpath`, `NODE` (kept if set), `npm_execpath` (the fyn CLI), `INIT_CWD` (the project dir). `node_modules/.bin` of the fynpo top dir is added to the front of `PATH` in a monorepo. The node-gyp environment is set up.
|
|
229
|
+
- The rc key `script-shell` selects the shell.
|
|
230
|
+
- Scripts run with inherited stdio.
|
|
231
|
+
- A failing script exits with the script's exit code (`err.code`, else `errno`, else 1). The error report prints the event, path, command, exit code and signal.
|
|
232
|
+
|
|
233
|
+
### `init`
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
fyn init [--yes]
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
| Option | Alias | Type | Default | Behavior |
|
|
240
|
+
| --- | --- | --- | --- | --- |
|
|
241
|
+
| `--yes` | `-y` | boolean | false | Skip prompts and use defaults. |
|
|
242
|
+
|
|
243
|
+
Runs the `init-package` generator. Any error exits 1.
|
|
244
|
+
|
|
245
|
+
### `install-scripts`
|
|
246
|
+
|
|
247
|
+
Reviews and records which packages may run install scripts. See "Install script policy" for the rules these commands write to. All four subcommands load the project, then read the last install's recorded blocked and pending packages from `<targetDir>/.f/.fyn.json`. Any error is logged and exits 1.
|
|
248
|
+
|
|
249
|
+
| Subcommand | Alias | Args | Options | Behavior |
|
|
250
|
+
| --- | --- | --- | --- | --- |
|
|
251
|
+
| `ls` | `list` | none | `--json` | Lists packages awaiting review: those the last install blocked, plus those recorded by `--allow-scripts-pending`. `--json` writes the records to stdout. With none it logs `No packages are awaiting install-script review.` |
|
|
252
|
+
| `approve` | | `[packages..]` | `--all`, `--local` | Writes approvals to `allowScripts`. |
|
|
253
|
+
| `deny` | | `[packages..]` | `--local` | Writes `{}` entries to `denyScripts`. |
|
|
254
|
+
| `prune` | | none | `--local` | Drops `allowScripts` entries for packages that are not installed. |
|
|
255
|
+
|
|
256
|
+
Common option: `--local` (boolean) writes to the project's `package.json` `fyn` block. Without it, inside a fynpo monorepo the target is `<fynpo dir>/fynpo.json` under `fyn.options`. Outside a monorepo the target is always `package.json`. A missing `fynpo.json` target throws `cannot read <file> - the monorepo allowlist needs a fynpo.json. Use --local ...`.
|
|
257
|
+
|
|
258
|
+
`approve`:
|
|
259
|
+
|
|
260
|
+
- Each name must be awaiting review, or carry an explicit `@version`. Otherwise `not awaiting review: <names>` is logged and nothing is written.
|
|
261
|
+
- `--all` approves every awaiting package.
|
|
262
|
+
- Entries are keyed by the bare package name and hold `{ semver, scripts }`. `semver` is a caret range of the reviewed version, unless `--no-allow-scripts-pin` is set. `scripts` lists the blocked scripts and is omitted when it would cover all three. Approving a second version widens `semver` to a union.
|
|
263
|
+
- A package already denied (in `denyScripts` of any scope, or an `allowScripts` `false`) is skipped with a `denied, not approved` warning.
|
|
264
|
+
- Nothing runs retroactively. Run `fyn install` afterward.
|
|
265
|
+
|
|
266
|
+
`deny`: no names logs `no packages named to deny`. A name already in the list logs `already denied`. Names with `@spec` are cut to the bare name.
|
|
267
|
+
|
|
268
|
+
`prune`: installed names come from `<targetDir>` entries and the `.f/_` store. If none are found it logs an error and writes nothing.
|
|
269
|
+
|
|
270
|
+
### `prod-prune`
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
fyn prod-prune [dir] [--max-kb <n>] [--max-files <n>] [--force]
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
| Option | Type | Default | Behavior |
|
|
277
|
+
| --- | --- | --- | --- |
|
|
278
|
+
| `[dir]` | string | the output dir (`<cwd>/<targetDir>`) | Tree to prune. Resolved against the project dir. |
|
|
279
|
+
| `--max-kb <n>` | number | 0 (none) | Fail when the remaining tree is larger than `n` kB. Overrides `prodPruning.maxKb`. |
|
|
280
|
+
| `--max-files <n>` | number | 0 (none) | Fail when more than `n` files remain. Overrides `prodPruning.maxFiles`. |
|
|
281
|
+
| `--force` | boolean | false | Prune even when the tree is not from `fyn install --production`. |
|
|
282
|
+
|
|
283
|
+
Rules:
|
|
284
|
+
|
|
285
|
+
- Without `--force` the tree must have `.f/.fyn.json` with `production: true`. Otherwise it exits 1 with `<dir> is not from a production install (fyn install --production). Use --force to prune it anyway.`
|
|
286
|
+
- A missing directory throws `no such directory: <dir>` (exit 1).
|
|
287
|
+
- Removes by directory name (`test`, `tests`, `__tests__`, `spec`, `__mocks__`, `docs`, `doc`, `example`, `examples`, `benchmark`, `benchmarks`, `coverage`, `.nyc_output`, `.github`, `.circleci`, `.husky`, `.idea`, `.vscode`) and by file type (source maps, TypeScript sources, and other non-runtime files), only inside package roots. License files are merged into `THIRD-PARTY-LICENSES.txt` at the tree root.
|
|
288
|
+
- The `package.json` beside the tree can hold `prodPruning`: `{ "maxKb": n, "maxFiles": n, "keepPaths": ["pkg/dir-or-file", ...] }`. `keepPaths` spares those files or directories. A command line budget beats the manifest budget.
|
|
289
|
+
- Files larger than 100 kB are always listed. Size never decides what is removed.
|
|
290
|
+
- Exit 1 when a budget is exceeded or any error occurs.
|
|
291
|
+
|
|
292
|
+
### `sync-local`
|
|
293
|
+
|
|
294
|
+
```
|
|
295
|
+
fyn sync-local
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Re-hardlinks the packed files of each local package recorded in `.fyn.json` (`localPkgLinks`) and refreshes `fyn.localExports` links. Logs `There are no local packages` when there are none. Any error exits 1. It does not resolve dependencies or touch the lockfile.
|
|
299
|
+
|
|
300
|
+
### `global`
|
|
301
|
+
|
|
302
|
+
Manages packages installed outside any project.
|
|
303
|
+
|
|
304
|
+
```
|
|
305
|
+
fyn global [--tag <tag>] <subcommand> [options]
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
| Parent option | Type | Behavior |
|
|
309
|
+
| --- | --- | --- |
|
|
310
|
+
| `--tag <tag>` | string | Operate on one installed copy by tag id such as `g1`, `g2`. Used by `remove` and `link` when no package is named. |
|
|
311
|
+
|
|
312
|
+
Every subcommand takes `--dir <dir>` (string, default `~/.fyn/global`), the global root. All the fully merged global/rc options (registry, concurrency, and so on) are passed to the installs.
|
|
313
|
+
|
|
314
|
+
| Subcommand | Alias | Args | Extra options | Behavior |
|
|
315
|
+
| --- | --- | --- | --- | --- |
|
|
316
|
+
| `add` | | `<packages..>` | `--yes`/`-y`, `--new-tag` | Install each package. Local paths (`./x`, `file:`, existing dir) are supported. |
|
|
317
|
+
| `remove` | `rm` | `[package]` | `--yes`/`-y` | Remove a package, a `name@version`, or the copy named by `--tag`. |
|
|
318
|
+
| `link` | | `[package]` | none | Make one installed version the active one (`name@version`, or `--tag`). |
|
|
319
|
+
| `list` | `ls` | `[name]` | none | List installed packages. |
|
|
320
|
+
| `update` | | `[package]` | none | Update a global package. |
|
|
321
|
+
| `use` | | `[version]` | none | Point `<root>/current` at `v<node major>` (default: the running Node major). |
|
|
322
|
+
| `cleanup` | | `[package]` | none | Remove versions that are not linked. Skips a package with no linked version. |
|
|
323
|
+
| `setup-path` | | none | none | Print `PATH` instructions for `<root>/bin`. |
|
|
324
|
+
|
|
325
|
+
Layout and rules:
|
|
326
|
+
|
|
327
|
+
- Root `~/.fyn/global`. Per runtime dir `<root>/v<node major>` (`bun<major>` on Bun) with `packages/<gN>/`, `bin/`, and `installed.json`. `<root>/bin` is a symlink to the current runtime's `bin`.
|
|
328
|
+
- Each install lives in `packages/g<N>` with its own `node_modules`. A different version gets a new `gN`. Installs take `packages/.install.lock`.
|
|
329
|
+
- Installs always use `targetDir: node_modules`, `layout: normal`, `flattenTop: true`, `centralStore: true`, `lockfile: true`, `sourceMaps: false`. The central store is `<root>/_central-storage` (it sets `FYN_CENTRAL_DIR` in the process).
|
|
330
|
+
- A spec that looks like a package name but exists as a local path fails with `Ambiguous package spec`. Use `./name`.
|
|
331
|
+
- `add`: no packages logs `No packages specified`, exit 1. A failed package logs `Failed to install <pkg>: ...` and exits 1.
|
|
332
|
+
- `remove` with no name and no `--tag` logs usage and exits 1. `remove`, `link` and `update` exit 1 when they report failure.
|
|
333
|
+
- `cleanup` logs `Nothing to clean up` or `Cleaned up N version(s)`.
|
|
334
|
+
|
|
335
|
+
## Global options
|
|
336
|
+
|
|
337
|
+
Defined on the root command. All appear in `fyn --help`.
|
|
338
|
+
|
|
339
|
+
| Option | Alias | Type | Default | Behavior |
|
|
340
|
+
| --- | --- | --- | --- | --- |
|
|
341
|
+
| `--cwd <dir>` | | string | process cwd | Project directory. A relative path is joined to the process cwd. When explicit, fyn does not search parent dirs for `package.json`. A fynpo config can not change it. |
|
|
342
|
+
| `--fyn-dir <dir>` | | string | `~/.fyn` | Cache and data dir. Used as given. |
|
|
343
|
+
| `--registry <url>` | `--reg` | string | `https://registry.npmjs.org` | Registry URL. |
|
|
344
|
+
| `--production` | `--prod` | boolean | false | Ignore `devDependencies`. Also set by `NODE_ENV`. |
|
|
345
|
+
| `--lockfile` | `--lf` | boolean | true | Read and write `fyn-lock.yaml`. `--no-lockfile` disables both. |
|
|
346
|
+
| `--lock-only` | `-k` | boolean | false | Resolve only from the lockfile. Fails if changes are needed, or if the lockfile cannot be read (exit 1). Does not write `fyn-lock.yaml`. Tarballs are still fetched. |
|
|
347
|
+
| `--prefer-lock` | | boolean | false | Prefer versions in the lockfile. |
|
|
348
|
+
| `--lock-time <time>` | | string | none | Resolve only versions published at or before this time (anything `new Date()` accepts). Needs full registry metadata. |
|
|
349
|
+
| `--npm-lock` | | boolean | unset | `true` always reads `npm-shrinkwrap.json` or `package-lock.json`. `false` never does. Unset reads them only when no fyn lockfile exists. |
|
|
350
|
+
| `--offline` | | boolean | false | Use only the lockfile and the local cache. Fails on a miss. |
|
|
351
|
+
| `--force-cache` | `-f` | boolean | false | Do not check the registry when the cache has the entry. A cache miss still hits the registry. |
|
|
352
|
+
| `--refresh-meta` | | boolean | false | Force refresh of package metadata from the registry. |
|
|
353
|
+
| `--refresh-optionals` | | boolean | false | Re-check all `optionalDependencies` instead of trusting the lockfile record. |
|
|
354
|
+
| `--always-fetch-dist` | | boolean | false | Fetch the dist tarball while resolving. |
|
|
355
|
+
| `--deep-resolve` | `--dr` | boolean | false | Resolve the dependency tree as deep as possible. |
|
|
356
|
+
| `--ignore-dist` | `-i` | boolean | unset | Ignore the host in the tarball URL from metadata. No code outside the option getter reads it. |
|
|
357
|
+
| `--ignore-lock-url` | | boolean | false | Rebuild tarball URLs from the registry setting instead of the lockfile URL. |
|
|
358
|
+
| `--enforce-registry-deps` | | boolean | unset (on) | Require transitive dependencies to come from a registry. See "Registry-only transitive dependencies". |
|
|
359
|
+
| `--show-deprecated` | `-s` | boolean | unset | Always show deprecation messages. |
|
|
360
|
+
| `--fynlocal` | | boolean | true | Enable local package linking. See "Local packages (fynlocal)". |
|
|
361
|
+
| `--build-local` | | boolean | true | Run `fyn install` and the build scripts in local dependency packages first. |
|
|
362
|
+
| `--source-maps` | `--sm` | boolean | false | Generate pseudo source maps for linked local packages. |
|
|
363
|
+
| `--auto-run` | | boolean | true | Run the extra npm scripts after install. |
|
|
364
|
+
| `--flatten-top` | | boolean | true | Hoist packages to the top `node_modules`. Turning it off while `--layout` is unset switches the layout to `detail`. |
|
|
365
|
+
| `--layout <type>` | | string | `normal` | `normal` or `detail`. `detail` puts every package under its own versioned path and symlinks into `node_modules`. |
|
|
366
|
+
| `--central-store` | `--central`, `--cs` | boolean | unset | See "Central store". |
|
|
367
|
+
| `--hardlink` | | boolean | unset (on) | Hardlink central store files into `node_modules`. |
|
|
368
|
+
| `--reflink` | | boolean | true | Clone store files copy-on-write where the filesystem can. `--no-reflink` never uses `@fynjs/reflink`. |
|
|
369
|
+
| `--copy-fallback` | | boolean | true | Copy files that cannot be cloned or hardlinked. `--no-copy-fallback` fails the install instead. |
|
|
370
|
+
| `--copy [packages..]` | `--cp` | string list | none | Copy these packages even in central store mode. The value is stored but no code reads it. |
|
|
371
|
+
| `--script-policy <mode>` | | string | `review` | `all`, `source`, `review` or `off`. See "Install script policy". |
|
|
372
|
+
| `--allow-scripts [packages..]` | | string list | none | Allow these packages' install scripts for this run. Commas split names. |
|
|
373
|
+
| `--deny-scripts [packages..]` | | string list | none | Deny these packages' install scripts for this run. Wins over every approval. |
|
|
374
|
+
| `--allow-scripts-pin` | | boolean | true | Pin written approvals to the reviewed version. |
|
|
375
|
+
| `--concurrency <n>` | `--cc` | number | 32 | Network concurrency (registry sockets). |
|
|
376
|
+
| `--extract-concurrency <n>` | `--excc` | number | min(4, workers + 1) | Packages extracted at once. |
|
|
377
|
+
| `--meta-memoize <url>` | `--meta-mem` | string | none | URL of a server that shares a metadata cache across fyn processes. |
|
|
378
|
+
| `--log-level <level>` | `-q` | string | `info` | `debug`, `verbose`, `info`, `warn`, `error`, `fyi`, `none`. A unique prefix works (`-q=d`). The first level that starts with the text wins. An invalid value logs `Invalid log level` and exits 1. |
|
|
379
|
+
| `--save-logs [file]` | `--sl` | string | `fyn-debug.log` when given without a value | Save all logs to this file, relative to the project dir. Ignored when the value came from an rc file rather than the command line. |
|
|
380
|
+
| `--colors` | | boolean | true | `--no-colors` turns color off. |
|
|
381
|
+
| `--progress <type>` | `--pg` | string | `normal` | `normal`, `simple` or `none`. An unknown value means `none`. `normal` becomes `simple` when stdout is not a TTY. |
|
|
382
|
+
| `--rcfile` | | boolean | true | `--no-rcfile` skips every rc file and uses only the built-in defaults. |
|
|
383
|
+
|
|
384
|
+
Built-in defaults (`default-rc`): `registry` `https://registry.npmjs.org`, `targetDir` `node_modules`, `progress` `none` when a CI is detected (`ci-info`), else `normal`.
|
|
385
|
+
|
|
386
|
+
Options with no command line flag but read by fyn from rc, fynpo or the `Fyn` constructor: `targetDir` (default `node_modules`), `pkgFile` (default `package.json`), `allowTopLevelScripts`, `reviewLocalPackages`, `email`, `username`, `password`, `always-auth`, `script-shell`, `@scope:registry`, `//host/:_authToken`.
|
|
387
|
+
|
|
388
|
+
## Config sources and precedence
|
|
389
|
+
|
|
390
|
+
### rc files
|
|
391
|
+
|
|
392
|
+
rc files are read with an ini parser. Files, from lowest to highest priority (later wins, objects merge deeply):
|
|
393
|
+
|
|
394
|
+
1. `$NPM_CONFIG_GLOBALCONFIG`
|
|
395
|
+
2. `$PREFIX/etc/npmrc`
|
|
396
|
+
3. `$NPM_CONFIG_USERCONFIG`
|
|
397
|
+
4. `~/.npmrc`
|
|
398
|
+
5. `~/.fynrc`
|
|
399
|
+
6. `<fynpo dir>/.npmrc` (only when a fynpo dir exists and differs from the project dir)
|
|
400
|
+
7. `<fynpo dir>/.fynrc` (same condition)
|
|
401
|
+
8. `<project dir>/.npmrc`
|
|
402
|
+
9. `<project dir>/.fynrc`
|
|
403
|
+
|
|
404
|
+
Rules:
|
|
405
|
+
|
|
406
|
+
- The built-in defaults sit under all of these.
|
|
407
|
+
- A missing file is ignored. A file that fails to parse logs `Failed to process <name> RC file`, and is treated as empty.
|
|
408
|
+
- Every key from every file goes into the options. Registry keys (`registry`, `<scope>:registry`), `*:_authToken` keys and `email`, `always-auth`, `username`, `password` are read by the registry layer. Auth keys are removed from debug output.
|
|
409
|
+
- Keys are written in the file in kebab-case or camelCase (`logLevel`, `central-store`). Both match the option names.
|
|
410
|
+
- `${VAR}` in a string value is replaced from the environment. An unset variable stays as `${VAR}`. `\${VAR}` escapes it.
|
|
411
|
+
- `.npmrc` values are also exposed to lifecycle scripts as `npm_config_*`.
|
|
412
|
+
- `--no-rcfile` loads none of these.
|
|
413
|
+
|
|
414
|
+
`.fynrc` sections: a top-level key whose value is an ini section is applied only when it matches. Plain top-level keys are the defaults. Section names:
|
|
415
|
+
|
|
416
|
+
| Section | Matches when |
|
|
417
|
+
| --- | --- |
|
|
418
|
+
| `[IS_CI]` | `CI` or `BUILD_ENV` is set. |
|
|
419
|
+
| `[CI:<value>]` | `CI` or `BUILD_ENV` (the first one set) equals `<value>`. |
|
|
420
|
+
| `[VAR:<value>]` | environment variable `VAR` equals `<value>`. |
|
|
421
|
+
| `[VAR1\|VAR2:<value>]` | either variable equals `<value>`. |
|
|
422
|
+
|
|
423
|
+
Applied order: defaults, then env-match sections, then `IS_CI`, then `CI:<value>`. `.npmrc` files do not use sections.
|
|
424
|
+
|
|
425
|
+
### Order of precedence for an option
|
|
426
|
+
|
|
427
|
+
1. Command line (highest).
|
|
428
|
+
2. `NODE_ENV` for `production` only: when `NODE_ENV` is set, `production` becomes `NODE_ENV === "production"`, unless `--production` was given.
|
|
429
|
+
3. rc files, merged into the option set with lodash `defaults`: they fill options the parser has not set.
|
|
430
|
+
4. The fynpo config `fyn.options` (see below). The code documents the order as command line, then rc, then fynpo. It applies a fynpo value only when the option did not come from the command line.
|
|
431
|
+
5. Built-in defaults.
|
|
432
|
+
|
|
433
|
+
Unverified: the CLI also applies fynpo options through a second path that overrides every option not set on the command line, so rc versus fynpo order was not confirmed at runtime. Also, the rc step uses `defaults`, so an rc value does not replace an option that already carries a built-in argument default (for example `concurrency`, `progress`). Check with a runtime test before relying on rc to override those.
|
|
434
|
+
|
|
435
|
+
The `fyn` block of `package.json` does not accept general options. It accepts only the keys listed in "Package fyn section".
|
|
436
|
+
|
|
437
|
+
### Environment variables
|
|
438
|
+
|
|
439
|
+
| Variable | Effect |
|
|
440
|
+
| --- | --- |
|
|
441
|
+
| `FYN_DIR` | fyn data dir, used as given. Fallbacks `USERPROFILE`, then `HOME` get `/.fyn` appended. Default is `<cwd>/.fyn` if none are set. `--fyn-dir` wins. |
|
|
442
|
+
| `FYN_REGISTRY` | Registry when no `registry` option exists. The CLI always has one (the built-in default), so this applies only to programmatic use. |
|
|
443
|
+
| `FYN_TARGET_DIR` | Same story for `targetDir` (default would be `xout` without the CLI defaults). |
|
|
444
|
+
| `FYN_PACKAGE_FILE` | The package file name. Default `package.json`. |
|
|
445
|
+
| `FYN_CENTRAL_DIR` | Central store dir. A false value (`0`, `false`, `no`, `off`) disables the store. `1`, `on`, `true` or `yes` uses `<fynDir>/_central-storage`. See "Central store". |
|
|
446
|
+
| `FYN_HARDLINK` | Hardlink on or off when `--hardlink` is not given. |
|
|
447
|
+
| `FYN_SHORT_PKG_DIR` | Any non-empty value (even `0`): new installs store packages at `.f/_/<name>/<version>/<name>`. Default: `.f/_/<name>/<version>/node_modules/<name>`. An existing install's recorded form wins. |
|
|
448
|
+
| `FYN_LOCAL_COPY_MODE` | True: copy local package files instead of hardlinking them. |
|
|
449
|
+
| `FYN_LOCAL_PACK_SYMLINKS` | True: include symlinks when packing local package files. |
|
|
450
|
+
| `FYN_FYNPO_DIR` | Set by fyn to the detected monorepo top dir. Suppresses the "Detected a ..." message in child fyn processes. |
|
|
451
|
+
| `FYN_DEBUG` | Print stack traces for audit failures. |
|
|
452
|
+
| `NODE_ENV` | Sets `production`. See above. |
|
|
453
|
+
| `NPM_CONFIG_GLOBALCONFIG`, `NPM_CONFIG_USERCONFIG`, `PREFIX` | rc file locations. |
|
|
454
|
+
| `CI`, `BUILD_ENV` | `.fynrc` section matching. `ci-info` detection sets the default `progress`, enables prompts only off CI, and stops source map handling for `.js` files. |
|
|
455
|
+
| `NOPROXY` | Passed to the registry fetch as `noProxy`. |
|
|
456
|
+
| `NODE_DISABLE_COMPILE_CACHE`, `NODE_COMPILE_CACHE` | Node compile cache control. |
|
|
457
|
+
|
|
458
|
+
`FYN_HARDLINK`, `FYN_LOCAL_COPY_MODE` and `FYN_LOCAL_PACK_SYMLINKS` are read as booleans: unset, empty, `0`, `off`, `false` and `no` are false (case insensitive), anything else is true.
|
|
459
|
+
|
|
460
|
+
### fynpo.json `fyn` section
|
|
461
|
+
|
|
462
|
+
When the project is inside a fynpo monorepo (`fynpo.json`, `fynpo.config.js`, `fynpo.config.json`, or a lerna config found by walking up), fyn reads these keys from that config:
|
|
463
|
+
|
|
464
|
+
| Key | Effect |
|
|
465
|
+
| --- | --- |
|
|
466
|
+
| `fyn.options` | Object of option names (camelCase) applied as in "Order of precedence". `cwd` and `initCwd` are never taken from it. |
|
|
467
|
+
| `fyn.options.allowScripts`, `denyScripts`, `allowTopLevelScripts`, `scriptPolicy`, `reviewLocalPackages` | Have their own merge rules. See "Install script policy". |
|
|
468
|
+
| Other `fyn.options` object values | Deep merged with the existing value, with already-set keys winning. |
|
|
469
|
+
| `centralDir` | Central store dir for the monorepo (see "Central store"). |
|
|
470
|
+
| `noFynLocal` | Package names that must not be auto-linked. |
|
|
471
|
+
| `localDepAutoSemver` | `patch`, `minor` or `major`: how a monorepo sibling's range is widened when matching a local copy. |
|
|
472
|
+
| `resolutions`, `overrides` | Merged with the same keys in `package.json`. fynpo wins on a conflict. |
|
|
473
|
+
| `command.bootstrap.npmRunScripts` | Scripts run after install in a monorepo package. Default `["build"]`; `false` disables. |
|
|
474
|
+
| `packages` | Package globs. Used to find local copies. |
|
|
475
|
+
|
|
476
|
+
A fynpo config that does not parse logs a warning naming the file and exits 1.
|
|
477
|
+
|
|
478
|
+
### Package fyn section
|
|
479
|
+
|
|
480
|
+
`package.json` (merged with `package-fyn.json`) can carry:
|
|
481
|
+
|
|
482
|
+
| Key | Behavior |
|
|
483
|
+
| --- | --- |
|
|
484
|
+
| `fyn.dependencies`, `fyn.devDependencies`, `fyn.optionalDependencies`, `fyn.peerDependencies` | Map of name to a local path (or `false` or a string containing `no-fyn-local` to opt out of local linking). Only used with fynlocal on. A path that does not exist is ignored. |
|
|
485
|
+
| `fyn.allowScripts`, `fyn.denyScripts`, `fyn.allowTopLevelScripts`, `fyn.scriptPolicy`, `fyn.reviewLocalPackages` | Install script policy. |
|
|
486
|
+
| `fyn.enforceRegistryDeps` | `false` turns off the registry-only rule. |
|
|
487
|
+
| `fyn.localExports`, `fyn.localExportsDir`, `fyn.localExportsDirs` | Local source exports. |
|
|
488
|
+
| `resolutions` | Map of dependency path to version. Paths may use `**` between slashes. A bare name matches at any depth. |
|
|
489
|
+
| `overrides` | npm style overrides: simple, nested, `name@range` keys, and `$name` references to a direct dependency version. |
|
|
490
|
+
| `prodPruning` | Used by `prod-prune`. |
|
|
491
|
+
|
|
492
|
+
`package-fyn.json` in the project dir is deep merged over `package.json` in memory (the whole file, not only a `fyn` key). `fyn add --pkg-fyn` writes to it.
|
|
493
|
+
|
|
494
|
+
## Local packages (fynlocal)
|
|
495
|
+
|
|
496
|
+
`--fynlocal` (default true) lets a dependency resolve to a directory on disk instead of the registry.
|
|
497
|
+
|
|
498
|
+
Ways a dependency becomes local:
|
|
499
|
+
|
|
500
|
+
- A spec in `dependencies` and friends that is `file:<path>`, an absolute path, `./...`, `../...`, or `~/...`.
|
|
501
|
+
- A `fyn.<section>.<name>` path in `package.json` or `package-fyn.json`. It replaces the registry spec locally while the registry spec stays for publishing.
|
|
502
|
+
- In a fynpo monorepo, a dependency whose name is a monorepo package and whose range matches that package's version. Skipped when the name is in the config `noFynLocal`, when `fyn.<section>.<name>` is `false` or contains `no-fyn-local`, or when the spec is a URL. A name that matches no version logs the versions available.
|
|
503
|
+
|
|
504
|
+
Behavior:
|
|
505
|
+
|
|
506
|
+
- Local packages get a version tag `-fynlocal_h` (hardlinked). Soft symlink mode was removed and now throws.
|
|
507
|
+
- Install hardlinks the files that `npm pack` would include (npm-packlist rules, symlinks only with `FYN_LOCAL_PACK_SYMLINKS`) from the source dir into the consumer's `node_modules`, so edits show up without reinstall. `FYN_LOCAL_COPY_MODE` copies instead. Files in the target that are not in the pack list are removed.
|
|
508
|
+
- `--build-local` (default true): before linking, each local dependency whose files changed and which has any of the scripts `preinstall`, `install`, `postinstall`, `prepare`, `build` is built by running `fyn --reg=<registry> -q=d --pg=simple --no-build-local --sl=fyn-debug.log [--no-source-maps] install --no-audit [--force-install]` in its dir. One at a time, deepest dependencies first. Then it runs `prepublish` (skipped with a warning when `prepare` also exists, and a deprecation note is printed), `prepack` and `postpack`. A failed local build prints the primary error, the nested errors and the log path, and fails the install. Its own debug log is `fyn-debug.log` in that dir.
|
|
509
|
+
- A package that is the project itself is not built.
|
|
510
|
+
- `--source-maps`: for linked `.js` and `.mjs` files with no source map, writes `<file>.fyn.map` mapping each position to the source. A file with its own relative `.map` gets a rewritten map pointing back at the sources. Nothing is generated in CI. `.js.map` and `.mjs.map` files themselves are skipped outside CI.
|
|
511
|
+
- Freshness: the "No change" check also looks at local package files and at the linked packed files, so a rebuilt local package triggers a refresh.
|
|
512
|
+
- `fyn sync-local` refreshes the links without installing.
|
|
513
|
+
- The local link list is stored in `.fyn.json` as `localPkgLinks` (`{ "<node_modules path>": { srcDir, sourceMaps } }`).
|
|
514
|
+
- Local entries in `fyn-lock.yaml` have `$: local` and `_: <path>` (relative to the lockfile dir) and are not refreshed from the registry.
|
|
515
|
+
|
|
516
|
+
`fyn.localExports` (optional): a producer package can declare directories to expose to consumers.
|
|
517
|
+
|
|
518
|
+
- Producer `package.json`: `"fyn": { "localExports": { "<export name>": "<relative dir>" } }`. `false` disables one export or the whole field.
|
|
519
|
+
- Consumer `package.json`: `fyn.localExportsDir` (default `_fyn`) and `fyn.localExportsDirs` (`{ "<package>": "<dir>" }`) set where links go.
|
|
520
|
+
- A link is made at `<dir>/<package>/<export>` in the consumer only for fynpo siblings and for `file:`, `link:` or path dependencies. Registry, git and URL dependencies never create exports.
|
|
521
|
+
- Dirs must be relative, with no `..`, `node_modules` or `.git`, and must not nest in each other. Names must match `[A-Za-z0-9_][A-Za-z0-9._-]*`. Violations throw errors such as `Unsafe fyn.localExports source ...`.
|
|
522
|
+
- Each root dir has an ownership file `.fyn-local-exports.json`. fyn only removes links it owns. The dir is generated content and should be ignored by version control.
|
|
523
|
+
|
|
524
|
+
## Central store
|
|
525
|
+
|
|
526
|
+
The central store keeps one extracted copy of each package, keyed by tarball integrity, and `node_modules` gets links or clones of it.
|
|
527
|
+
|
|
528
|
+
Whether the store is used, in order:
|
|
529
|
+
|
|
530
|
+
1. `centralDir` already recorded in `<targetDir>/.f/.fyn.json` (an existing install keeps its store). A recorded `false` keeps it off.
|
|
531
|
+
2. `FYN_CENTRAL_DIR`: false value disables it, true value uses `<fynDir>/_central-storage`, any other value is the dir.
|
|
532
|
+
3. `--central-store` (or rc `centralStore`): `<fynDir>/_central-storage`. `--no-central-store` turns the default (rule 4) off. It does not disable the monorepo store of rule 5.
|
|
533
|
+
4. Not a fynpo project: on by default on macOS when `@fynjs/reflink` can clone directories (and `--reflink` is on), and on Linux when hardlink is on or reflink can clone files. Off on Windows and in all other cases.
|
|
534
|
+
5. In a fynpo monorepo: `centralDir` from the fynpo config, else `<monorepo>/.fynpo/_store`. If the monorepo is a git linked worktree, the main worktree's `.fynpo/_store` is shared.
|
|
535
|
+
|
|
536
|
+
The store is skipped (with an info message, and the dir remembered in `.fyn.json`) when it would only copy: `--no-hardlink` and `--no-reflink` together (unless `--no-copy-fallback`); hardlink off on macOS or Windows without `@fynjs/reflink`; or the store is on a different volume than the project.
|
|
537
|
+
|
|
538
|
+
Storage layout: `<store>/<algorithm>/<hex[0:2]>/<hex[2:4]>/<hex[4:]>/package/` for files, plus a `tree.json` with the file list, a content checksum and a `mutates` flag. Stores of concurrent installs are guarded by marker files. Stale temp entries are cleaned.
|
|
539
|
+
|
|
540
|
+
Placing files into `node_modules` (per package):
|
|
541
|
+
|
|
542
|
+
1. One directory clone when `--reflink` is on and the filesystem supports it (APFS).
|
|
543
|
+
2. Else per file clone (`@fynjs/reflink`), falling back to hardlink when `--hardlink` is on, then to copy when `--copy-fallback` is on.
|
|
544
|
+
3. Else hardlink, with a copy where hardlinking fails.
|
|
545
|
+
- `package.json` is always copied because fyn rewrites it.
|
|
546
|
+
- A failed hardlink (for example another volume) turns hardlinking off for the rest of the run and copies.
|
|
547
|
+
- `--no-copy-fallback` makes a file that cannot be cloned or linked fail the install.
|
|
548
|
+
|
|
549
|
+
Mutation guard: if a package's install scripts change its files, fyn compares a checksum before and after, marks that package as `mutates` in the store, and never shares it again.
|
|
550
|
+
|
|
551
|
+
`--hardlink` precedence: command line or rc, then `FYN_HARDLINK`, then the value saved in `.fyn.json`, then on. The choice is saved.
|
|
552
|
+
|
|
553
|
+
Global installs always use `<global root>/_central-storage`.
|
|
554
|
+
|
|
555
|
+
## Lockfile
|
|
556
|
+
|
|
557
|
+
`fyn-lock.yaml` is in the project dir. It is YAML with sorted keys and one space indent.
|
|
558
|
+
|
|
559
|
+
Top level keys:
|
|
560
|
+
|
|
561
|
+
| Key | Content |
|
|
562
|
+
| --- | --- |
|
|
563
|
+
| `$fyn` | Saved config: `layout`, `flattenTop`. |
|
|
564
|
+
| `$pkg` | The declared direct dependencies: `dep`, `dev`, `opt` maps of name to spec. |
|
|
565
|
+
| `<package name>` | One block per package (below). |
|
|
566
|
+
|
|
567
|
+
Package block:
|
|
568
|
+
|
|
569
|
+
| Key | Content |
|
|
570
|
+
| --- | --- |
|
|
571
|
+
| `_latest` | The registry `latest` version seen. |
|
|
572
|
+
| `_` | Map of comma joined semver specs to the resolved version (an array when several). |
|
|
573
|
+
| `<version>` | Entry for a resolved version. |
|
|
574
|
+
|
|
575
|
+
Version entry keys: `top: 1` (requested directly by the project), `$` (integrity, `0` if none, or `local`), `_` (tarball URL, or a local path), `dependencies`, `optionalDependencies`, `peerDependencies`, `bundleDependencies`, `hasPI: 1` (has `preinstall`), `hasI: 1` (has `install` or `postinstall`), `optFailed`, `_missingJson: true`, `deprecated`, `os`, `cpu`, `_hasShrinkwrap: 1`. A platform mismatch is not recorded in the lockfile.
|
|
576
|
+
|
|
577
|
+
Reading:
|
|
578
|
+
|
|
579
|
+
- Order of sources: `fyn-lock.yaml`; if absent and `--lockfile` and not `--lock-only`, the installed copy `<targetDir>/.f/lock.yaml`; if still none and not `--npm-lock=false`, `npm-shrinkwrap.json` then `package-lock.json`; then `yarn.lock`.
|
|
580
|
+
- A lockfile with git conflict markers is ignored with an error, and everything is resolved again.
|
|
581
|
+
- A lock version key that is not valid semver (and is not local) is ignored.
|
|
582
|
+
- An unreadable lockfile is an error only with `--lock-only` (exit 1).
|
|
583
|
+
- A tarball URL that does not start with the current registry is rewritten onto it when the path matches. `--ignore-lock-url` forces the rewrite.
|
|
584
|
+
- `layout` and `flattenTop` stored in the lock win over the defaults. A command line value that differs updates the lock and logs `You are changing <name> in your lockfile`. Other sources are overridden with the lock value and a `Setting <name> to ... from your lockfile` message.
|
|
585
|
+
|
|
586
|
+
Writing:
|
|
587
|
+
|
|
588
|
+
- Written after a successful install, only when its checksum changed, never with `--lock-only` and never with `--no-lockfile`.
|
|
589
|
+
- The installed copy `<targetDir>/.f/lock.yaml` is written on every install, including `--lock-only`.
|
|
590
|
+
- Local package paths are saved relative to the lock dir.
|
|
591
|
+
- `add` and `remove` run their edit step with the lockfile off.
|
|
592
|
+
|
|
593
|
+
Related files in `<targetDir>/.f/`: `.fyn.json` (install config), `lock.yaml` (installed lock copy), `.installing.lock`, `_/` (store for isolated package versions), `.fyn-audit.json` (the path `getAuditFilePath` returns for a generated audit report).
|
|
594
|
+
|
|
595
|
+
`.fyn.json` fields: `time` (install time in ms, 5 ms after the lock save), `centralDir` (string or `false`), `production`, `fynlocal`, `layout`, `shortPkgDir`, `hardlink`, `blockedScripts`, `pendingScripts`, `localPkgLinks`, `localExports`, `localsByDepth`. It is an internal format and changes without notice.
|
|
596
|
+
|
|
597
|
+
Caches under `<fynDir>`: `_cacache` (packages and registry cache), `fyn-packuments` (trimmed metadata), `audit`, `tmp`, `links`, `_central-storage`, `global`.
|
|
598
|
+
|
|
599
|
+
## Install script policy
|
|
600
|
+
|
|
601
|
+
The install scripts gated are `preinstall`, `install` and `postinstall`. The project's own scripts are not gated.
|
|
602
|
+
|
|
603
|
+
### Modes
|
|
604
|
+
|
|
605
|
+
`--script-policy` or `fyn.scriptPolicy`. Default `review`. The value is case insensitive. An unknown value throws `fyn scriptPolicy "<value>" is not valid - expected one of all, source, review, off`.
|
|
606
|
+
|
|
607
|
+
| Mode | Registry packages | git/URL packages | Workspace-local packages |
|
|
608
|
+
| --- | --- | --- | --- |
|
|
609
|
+
| `review` | need an `allowScripts` entry | need an entry | run |
|
|
610
|
+
| `source` | run | need an entry | run |
|
|
611
|
+
| `all` | run | run | run |
|
|
612
|
+
| `off` | none run | none run | none run |
|
|
613
|
+
|
|
614
|
+
- `off` ignores the allowlist.
|
|
615
|
+
- `npm:` aliases count as registry. A local path declared by a git or URL package is not workspace-local.
|
|
616
|
+
- Workspace-local means `file:`, `link:`, path dependencies and fynpo siblings. `reviewLocalPackages: true` removes their exemption.
|
|
617
|
+
- `fyn.allowTopLevelScripts` applies in `source` mode only. `true` or `"*"` allows all scripts, an array allows those script names, for non-registry packages declared directly in the project's `package.json`. It is ignored in every other mode. First defined wins: option (rc or fynpo option), then `package.json`, then fynpo config.
|
|
618
|
+
|
|
619
|
+
### Maps
|
|
620
|
+
|
|
621
|
+
`allowScripts` and `denyScripts` are maps of key to value.
|
|
622
|
+
|
|
623
|
+
Key forms: `name`, `name@<semver range>`, `@scope/name@<range>`, or `name@<requested spec>` for a git/URL spec (matched literally). A key's range is matched against the resolved version.
|
|
624
|
+
|
|
625
|
+
Value forms for `allowScripts`:
|
|
626
|
+
|
|
627
|
+
| Value | Meaning |
|
|
628
|
+
| --- | --- |
|
|
629
|
+
| `{ "semver": "<range>", "scripts": [...] }` | The form fyn writes. A missing field means all versions or all scripts. |
|
|
630
|
+
| `true` or `"*"` | All scripts, all versions. |
|
|
631
|
+
| `["install"]` or `"install"` | Only those scripts. |
|
|
632
|
+
| `"1.2.3"` or `"^1.2.0"` | All scripts, matching versions only (npm form). |
|
|
633
|
+
| `false` | Deny the package. |
|
|
634
|
+
| `[..., "!postinstall"]` | `!name` denies one script, `!*` denies all, `+name` allows it. A `!` beats an allow of the same name. |
|
|
635
|
+
|
|
636
|
+
`denyScripts` takes the same shape. A match denies. An empty `{}` entry denies every version and script. `--deny-scripts a,b` makes bare names.
|
|
637
|
+
|
|
638
|
+
### Precedence
|
|
639
|
+
|
|
640
|
+
- `denyScripts` is checked first and wins over every approval: the allowlist, `allowTopLevelScripts`, the local exemption and mode `all`. `off` is checked before it.
|
|
641
|
+
- `allowScripts` merges loosest to tightest: fynpo `fyn.options`, then `package.json`, then the command line. Approvals add up. A `false` at any scope is final.
|
|
642
|
+
- `denyScripts` unions across all three scopes. No scope removes another's denial.
|
|
643
|
+
- `scriptPolicy`: the command line overrides outright. Otherwise the stricter of the fynpo and `package.json` values wins (order `all`, `source`, `review`, `off`, loosest to strictest). A package can tighten but never loosen the monorepo's mode.
|
|
644
|
+
- `reviewLocalPackages`: on if any scope turns it on.
|
|
645
|
+
|
|
646
|
+
### Install-time behavior
|
|
647
|
+
|
|
648
|
+
- Under `review`, an install that would skip unapproved scripts stops before running scripts.
|
|
649
|
+
- With a terminal and no CI, it lists the packages and asks `Approve? [a]ll / [s]elect / [n]one (default)`. Approved packages are written to `package.json` (or the monorepo `fynpo.json`) and run in this install.
|
|
650
|
+
- Without a terminal, or on CI, it throws and exits 1: `N package(s) need approval to run their install scripts, and there is no terminal to ask on: ...`.
|
|
651
|
+
- Denied packages are not prompted. They appear in the end summary.
|
|
652
|
+
- Under `source`, `all` and `off`, blocked scripts are reported at the end and the install continues.
|
|
653
|
+
- Blocked and pending records are saved in `.fyn.json` for `install-scripts ls`.
|
|
654
|
+
|
|
655
|
+
## Registry-only transitive dependencies
|
|
656
|
+
|
|
657
|
+
On by default. A transitive (not top-level) dependency from `github:`, git, `http(s)` tarball or an unparseable selector aborts the install with an error naming the package and its parent. Accepted: registry ranges and tags, `npm:` aliases, local `file:`/`link:`/path deps, fynpo siblings. The project's own `package.json` may use any source.
|
|
658
|
+
|
|
659
|
+
Precedence: an explicit option value (command line, rc, or fynpo `fyn.options.enforceRegistryDeps`) wins over `package.json` `fyn.enforceRegistryDeps`, which wins over the default (on). Only `false` in `package.json` turns it off.
|
|
660
|
+
|
|
661
|
+
## Exit codes summary
|
|
662
|
+
|
|
663
|
+
| Where | Code |
|
|
664
|
+
| --- | --- |
|
|
665
|
+
| Any command | 0 on success. |
|
|
666
|
+
| Parse error | 1. |
|
|
667
|
+
| Node older than 22.22.2 | 1. |
|
|
668
|
+
| Uncaught rejection in the bin wrapper | 1 (prints the error). |
|
|
669
|
+
| `install` | 1 on failure. 0 on success or "No Change". |
|
|
670
|
+
| `add`, `remove` | 1 for no package names. Install failures follow `install`. |
|
|
671
|
+
| `update` | 1 for a name that is not locked. Install failures follow `install`. |
|
|
672
|
+
| `outdated` | 1 when anything is outdated. Errors also 1. |
|
|
673
|
+
| `audit` | 0 even with findings. Failures logged only. |
|
|
674
|
+
| `run` | The script's exit code, else 1. Missing script 1 (0 with `--if-present`). |
|
|
675
|
+
| `install-scripts`, `prod-prune`, `sync-local`, `init` | 1 on any error. `prod-prune` also 1 when over budget. |
|
|
676
|
+
| `global` | 1 on missing arguments or a reported failure. |
|
|
677
|
+
| `--log-level` invalid | 1. |
|
|
678
|
+
| fynpo config parse failure | 1. |
|
|
679
|
+
| `package.json` unreadable | 1. |
|
|
680
|
+
| `--lock-only` with unreadable lockfile | 1. |
|