@bobfrankston/npmglobalize 1.0.198 โ 1.0.200
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 +84 -15
- package/lib.js +40 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -157,6 +157,51 @@ npmglobalize --fix # Runs npm audit fix
|
|
|
157
157
|
npmglobalize --no-fix
|
|
158
158
|
```
|
|
159
159
|
|
|
160
|
+
### ๐งฉ Install Scripts (npm `allowScripts`)
|
|
161
|
+
|
|
162
|
+
npm 11.17+ skips install-time lifecycle scripts (`preinstall`/`install`/
|
|
163
|
+
`postinstall`) for packages that aren't on an allowlist. A **global** install
|
|
164
|
+
has no project `package.json` to record approvals in, so without help a
|
|
165
|
+
postinstall you wrote yourself silently never runs while the install still
|
|
166
|
+
exits 0 โ e.g. `@bobfrankston/msger`'s postinstall copies its native binary
|
|
167
|
+
into the per-user bin dir its launcher reads from, and skipping it leaves a
|
|
168
|
+
stale exe behind a green checkmark.
|
|
169
|
+
|
|
170
|
+
npmglobalize therefore allowlists **your own packages** on the global install
|
|
171
|
+
it performs โ it just built and published them from your source, so they're
|
|
172
|
+
trusted โ and leaves third-party packages gated:
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
> npm install -g @bobfrankston/winpos@2.0.51 --allow-scripts @bobfrankston/winpos,@bobfrankston/msger,@bobfrankston/msgcommon
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Anything npm skips is reported rather than buried in the captured output:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
ยท Skipped koffi@2.16.3 install script โ prebuilt-binary fetcher, the package ships binaries; normally harmless.
|
|
182
|
+
โ npm skipped install scripts for third-party packages: sharp@0.33.0
|
|
183
|
+
sharp@0.33.0 (install: node install/check)
|
|
184
|
+
These may be broken at runtime โ no prebuilt fallback recognized.
|
|
185
|
+
To run them anyway: npm install -g @bobfrankston/winpos@2.0.51 --allow-scripts @bobfrankston/winpos,@bobfrankston/msger,koffi,sharp
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Two details worth knowing:
|
|
189
|
+
|
|
190
|
+
- **Prebuilt fetchers are called out separately.** npm names the skipped
|
|
191
|
+
script, so a runner like `cnoke`, `prebuild-install`, `node-gyp-build`,
|
|
192
|
+
`prebuildify` or `napi-postinstall` is recognized as one that only compiles
|
|
193
|
+
when no prebuild matches. Those packages ship working binaries โ koffi
|
|
194
|
+
carries `build/koffi/<platform>/koffi.node` for every platform it supports โ
|
|
195
|
+
so the skip gets an informational note, not a warning.
|
|
196
|
+
- **The suggested re-run command includes your own packages.** npm takes the
|
|
197
|
+
allowlist from the first source that has one rather than merging sources, so
|
|
198
|
+
a command naming only the third-party package would silently re-gate yours.
|
|
199
|
+
Always run the full list.
|
|
200
|
+
|
|
201
|
+
An own-scope package showing up as skipped is reported louder โ that means the
|
|
202
|
+
allowlist missed it, usually a transitive dep not present in the local
|
|
203
|
+
`node_modules` tree.
|
|
204
|
+
|
|
160
205
|
### ๐ OAuth Credentials Handling
|
|
161
206
|
|
|
162
207
|
`npmglobalize` automatically detects `credentials.json` files and handles them based on OAuth app type:
|
|
@@ -534,8 +579,9 @@ is planned.
|
|
|
534
579
|
|
|
535
580
|
### `upstream` โ who consumes this package
|
|
536
581
|
|
|
537
|
-
Bookkeeping, not a setting. When a package with `file:` deps
|
|
538
|
-
npmglobalize appends an entry to each **dependency's**
|
|
582
|
+
**Experimental.** Bookkeeping, not a setting. When a package with `file:` deps
|
|
583
|
+
publishes, npmglobalize appends an entry to each **dependency's**
|
|
584
|
+
`.globalize.json5`:
|
|
539
585
|
|
|
540
586
|
```json5
|
|
541
587
|
{
|
|
@@ -557,19 +603,42 @@ checkout path, its version at the time, and the date.
|
|
|
557
603
|
|
|
558
604
|
Only **immediate** consumers are recorded. A full consumer tree is a walk, not
|
|
559
605
|
a copy: follow each entry's path and read that package's own `upstream` list.
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
606
|
+
That keeps each file small and self-maintaining โ no package has to know about
|
|
607
|
+
anything beyond its own direct consumers.
|
|
608
|
+
|
|
609
|
+
The list is **FYI** โ it is recorded, preserved across publishes, and printed
|
|
610
|
+
in the Release Summary of the package that owns it. Nothing is rebuilt,
|
|
611
|
+
republished, or reinstalled on its behalf. An entry appears the first time a
|
|
612
|
+
consumer publishes, and is refreshed in place on every publish after that.
|
|
613
|
+
|
|
614
|
+
#### Scope and limits
|
|
615
|
+
|
|
616
|
+
**`file:` deps only.** A dependency referenced by npm version (`"^0.1.39"`)
|
|
617
|
+
is never recorded, because npmglobalize has no checkout path for it โ it
|
|
618
|
+
consumes the published tarball, not a sibling directory. To have a consumer
|
|
619
|
+
show up in a library's list, that consumer must reference it as
|
|
620
|
+
`file:../<lib>`.
|
|
621
|
+
|
|
622
|
+
**Usually not committed.** The entry is written into the dependency's own
|
|
623
|
+
checkout, and npmglobalize then tries to commit it there
|
|
624
|
+
(`Record upstream <consumer>@<version>`) and push if that repo has a remote.
|
|
625
|
+
In practice that commit is usually skipped: `.globalize.json5` is in the
|
|
626
|
+
standard ignore template, so most repos ignore it and the entry stays as
|
|
627
|
+
untracked local state. That is a reasonable failure mode for an experimental
|
|
628
|
+
mechanism โ the list rewrites itself on every publish, so there is nothing to
|
|
629
|
+
merge and nothing to reconcile between machines. It also means the list is
|
|
630
|
+
**per-machine**, not shared history.
|
|
631
|
+
|
|
632
|
+
When the commit does happen (a repo that tracks its `.globalize.json5`, as
|
|
633
|
+
npmglobalize itself does), only that one file is staged and committed by
|
|
634
|
+
pathspec โ anything else the dependency had staged or modified is left exactly
|
|
635
|
+
as it was. A dependency that isn't a git repo is written and skipped the same
|
|
636
|
+
way.
|
|
637
|
+
|
|
638
|
+
The alternative would be recording this in `package.json`, which is tracked
|
|
639
|
+
and published โ every consumer of a library would then download that library's
|
|
640
|
+
list of local checkout paths in its tarball. Keeping it in `.globalize.json5`
|
|
641
|
+
keeps it out of the package entirely.
|
|
573
642
|
|
|
574
643
|
## Common Workflows
|
|
575
644
|
|
package/lib.js
CHANGED
|
@@ -3514,28 +3514,58 @@ function allowOwnScriptsArgs(dir) {
|
|
|
3514
3514
|
const own = ownScopePackages(dir);
|
|
3515
3515
|
return own.length ? ['--allow-scripts', own.join(',')] : [];
|
|
3516
3516
|
}
|
|
3517
|
+
/** Install-script runners that fetch or select a prebuilt binary and only
|
|
3518
|
+
* compile when no prebuild matches the platform. A package using one of these
|
|
3519
|
+
* ships working binaries in its tarball, so a skipped script is very rarely
|
|
3520
|
+
* the thing that breaks it โ koffi (cnoke) is the standing example: it carries
|
|
3521
|
+
* build/koffi/<platform>/koffi.node for every platform it supports. */
|
|
3522
|
+
const PREBUILT_SCRIPT_RUNNERS = /\b(prebuild-install|node-gyp-build|prebuildify|cnoke|napi-postinstall)\b/;
|
|
3517
3523
|
/** A skipped postinstall can leave a package broken at runtime (puppeteer
|
|
3518
3524
|
* without its browser, native modules unbuilt), so surface the warning
|
|
3519
3525
|
* instead of burying it in the captured output. Own-scope packages are
|
|
3520
3526
|
* reported separately and louder: those were supposed to be allowed, so
|
|
3521
|
-
* one showing up here means the allowlist missed it.
|
|
3522
|
-
|
|
3523
|
-
|
|
3527
|
+
* one showing up here means the allowlist missed it.
|
|
3528
|
+
*
|
|
3529
|
+
* npm names the script it skipped in the warn line โ "(install: node
|
|
3530
|
+
* src/cnoke/cnoke.js ... --prebuild)" โ so the report can say WHICH script
|
|
3531
|
+
* and whether it's the kind that has a prebuilt fallback, rather than
|
|
3532
|
+
* flatly claiming every skip may have broken something. */
|
|
3533
|
+
function warnSkippedScripts(combined, allowed = [], pkgSpec) {
|
|
3534
|
+
const pkgs = [...combined.matchAll(/^npm warn allow-scripts\s+(\S+@[^\s(]+) \(([^)]*)\)/gm)]
|
|
3535
|
+
.map(m => ({ spec: m[1], detail: m[2] }));
|
|
3524
3536
|
if (!pkgs.length)
|
|
3525
3537
|
return;
|
|
3526
3538
|
const nameOf = (spec) => spec.replace(/@[^@]+$/, '');
|
|
3527
3539
|
const first = allowed[0] || '';
|
|
3528
3540
|
const scope = first.startsWith('@') ? first.slice(0, first.indexOf('/') + 1) : '';
|
|
3529
|
-
const ours = scope ? pkgs.filter(
|
|
3530
|
-
const others = pkgs.filter(
|
|
3541
|
+
const ours = scope ? pkgs.filter(p => nameOf(p.spec).startsWith(scope)) : [];
|
|
3542
|
+
const others = pkgs.filter(p => !ours.includes(p));
|
|
3531
3543
|
if (ours.length) {
|
|
3532
|
-
console.log(colors.red(` โ Own-scope install scripts still skipped: ${ours.map(
|
|
3544
|
+
console.log(colors.red(` โ Own-scope install scripts still skipped: ${ours.map(p => p.spec).join(', ')}`));
|
|
3533
3545
|
console.log(colors.red(` npmglobalize allowlisted ${allowed.length} own package(s) but missed these โ likely transitive deps not present in the local node_modules tree.`));
|
|
3534
3546
|
}
|
|
3535
3547
|
if (others.length) {
|
|
3536
|
-
const
|
|
3537
|
-
|
|
3538
|
-
|
|
3548
|
+
const prebuilt = others.filter(p => PREBUILT_SCRIPT_RUNNERS.test(p.detail));
|
|
3549
|
+
const unknown = others.filter(p => !prebuilt.includes(p));
|
|
3550
|
+
for (const p of prebuilt) {
|
|
3551
|
+
const script = p.detail.split(':')[0];
|
|
3552
|
+
console.log(colors.dim(` ยท Skipped ${p.spec} ${script} script โ prebuilt-binary fetcher, the package ships binaries; normally harmless.`));
|
|
3553
|
+
}
|
|
3554
|
+
if (unknown.length) {
|
|
3555
|
+
console.log(colors.yellow(` โ npm skipped install scripts for third-party packages: ${unknown.map(p => p.spec).join(', ')}`));
|
|
3556
|
+
for (const p of unknown)
|
|
3557
|
+
console.log(colors.yellow(` ${p.spec} (${p.detail})`));
|
|
3558
|
+
console.log(colors.yellow(` These may be broken at runtime โ no prebuilt fallback recognized.`));
|
|
3559
|
+
}
|
|
3560
|
+
// The re-run command must carry the OWN packages too: npm takes the
|
|
3561
|
+
// allowlist from the first source that has one, so a command listing
|
|
3562
|
+
// only the third-party name silently re-gates ours (msger's postinstall
|
|
3563
|
+
// copies its native binary โ losing it is the failure this all exists
|
|
3564
|
+
// to prevent). Print the whole list, and the real spec rather than a
|
|
3565
|
+
// <pkg> placeholder nobody can paste.
|
|
3566
|
+
const rerun = [...allowed, ...new Set(others.map(p => nameOf(p.spec)))].join(',');
|
|
3567
|
+
const target = pkgSpec ?? '<pkg>';
|
|
3568
|
+
console.log(colors.dim(` To run them anyway: npm install -g ${target} --allow-scripts ${rerun}`));
|
|
3539
3569
|
}
|
|
3540
3570
|
}
|
|
3541
3571
|
/** Run npm install -g with retries for registry propagation delay.
|
|
@@ -3568,7 +3598,7 @@ async function installGlobalWithRetry(pkgSpec, cwd, isNewPackage = false, maxRet
|
|
|
3568
3598
|
const added = combined.match(/^(?:added|changed|removed) \d+ packages?.*$/m);
|
|
3569
3599
|
if (added)
|
|
3570
3600
|
console.log(colors.dim(` ${added[0]}`));
|
|
3571
|
-
warnSkippedScripts(combined, allowArgs.length ? allowArgs[1].split(',') : []);
|
|
3601
|
+
warnSkippedScripts(combined, allowArgs.length ? allowArgs[1].split(',') : [], pkgSpec);
|
|
3572
3602
|
// A truncated puppeteer browser extraction exits 0, so the install
|
|
3573
3603
|
// LOOKS fine while the cache is poisoned for every future install.
|
|
3574
3604
|
// Verify now, while the leftover archive still allows a repair.
|