@bobfrankston/npmglobalize 1.0.234 → 1.0.236

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.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/lib.js +32 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -527,6 +527,8 @@ not what you meant to publish, so npmglobalize lists the conflicted files and st
527
527
  Example: -npm public,ts
528
528
  ```
529
529
 
530
+ Flipping an already-published package between private and public runs `npm access set`. Since Aug 2026 that fails with a bare 403 when the token in `.npmrc` is a bypass-2FA granular token (npm no longer lets such tokens change package access, and offers no OTP prompt). npmglobalize recognizes that case, says so, and points at the package's Access page on npmjs.com (`https://www.npmjs.com/package/<name>/access`, browser sign-in with 2FA); set the status there and rerun. The finding is repeated in the Issues Summary. Publishing itself is unaffected until the Jan 2027 phase of the same deprecation. (2026-09-23)
531
+
530
532
  `ts` is already the default on git (source is tracked). Pass `-npm ts` to ship
531
533
  the same files to npm — useful for debugging installed packages or "source on
532
534
  demand" packages. `noEmit` projects automatically ship `.ts` files (they *are*
package/lib.js CHANGED
@@ -1088,7 +1088,7 @@ export async function cascadePublicVisibility(cwd, opts = {}) {
1088
1088
  console.log(colors.green(` ✓ Flipped ${targetName} to PUBLIC on npm`));
1089
1089
  }
1090
1090
  else {
1091
- blockers.push({ name: targetName, reason: `npm access set failed: ${r.stderr || r.output || 'unknown'}` });
1091
+ blockers.push({ name: targetName, reason: explainAccessChangeFailure(targetName, 'public', r) });
1092
1092
  }
1093
1093
  }
1094
1094
  else {
@@ -6107,6 +6107,24 @@ function checkNpmAuth() {
6107
6107
  return { authenticated: false, error: error.message };
6108
6108
  }
6109
6109
  }
6110
+ /** Explain a failed `npm access set status=...` and say what will actually work.
6111
+ * 2026-09-23 01:10 EDT — Claude Code (Fable 5.1), at Bob's direction. Since early Aug
6112
+ * 2026 a granular token that bypasses 2FA no longer covers package-access changes
6113
+ * (https://gh.io/npm-gat-bypass2fa-deprecation): the registry answers the access POST
6114
+ * with a bare 403 and npm never offers an OTP prompt. The old message here said "Try
6115
+ * manually: npm access set ..." — the same command with the same token, which fails
6116
+ * the same way. The path that works is the package's Access page on npmjs.com, signed
6117
+ * in with 2FA. Recorded as a build issue too, so it survives to the Issues Summary. */
6118
+ function explainAccessChangeFailure(name, status, result) {
6119
+ const text = `${result.stderr}\n${result.output}`;
6120
+ const tokenBlocked = /\bE?403\b/.test(text) && /\/access\b/.test(text);
6121
+ const page = `https://www.npmjs.com/package/${name}/access`;
6122
+ const message = tokenBlocked
6123
+ ? `Cannot change ${name} to ${status} with the npm token in .npmrc (403 on the access endpoint): since Aug 2026 bypass-2FA tokens no longer cover access changes. Set Package Status on ${page} (browser, 2FA), then rerun.`
6124
+ : `Failed to change ${name} to ${status}. Try manually: npm access set status=${status} ${name} (or on ${page}).`;
6125
+ recordBuildIssue(name, 'error', message);
6126
+ return message;
6127
+ }
6110
6128
  /** Get authentication setup instructions */
6111
6129
  function getAuthInstructions() {
6112
6130
  const npmrcPath = path.join(process.env.USERPROFILE || process.env.HOME || '~', '.npmrc');
@@ -7975,13 +7993,18 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
7975
7993
  if (currentAccess === 'public') {
7976
7994
  console.log(colors.yellow(`Package '${pkg.name}' is currently PUBLIC on npm. Converting to private...`));
7977
7995
  if (!dryRun) {
7978
- const accessResult = await runCommandAsync('npm', ['access', 'set', 'status=restricted', pkg.name], { cwd, silent: false });
7996
+ // 2026-09-23 01:15 EDT — Claude Code (Fable 5.1): silent:true so npm's output is
7997
+ // CAPTURED (stdio 'inherit' captures nothing, and v1.0.235's 403 detection never
7998
+ // fired on httppoly). The captured text is echoed below on failure, so nothing is lost.
7999
+ const accessResult = await runCommandAsync('npm', ['access', 'set', 'status=restricted', pkg.name], { cwd, silent: true });
7979
8000
  if (accessResult.success) {
7980
8001
  console.log(colors.green(`✓ Changed ${pkg.name} to PRIVATE on npm`));
7981
8002
  currentAccess = 'restricted';
7982
8003
  }
7983
8004
  else {
7984
- console.error(colors.red(`Failed to change access. Try manually: npm access set status=restricted ${pkg.name}`));
8005
+ if (accessResult.stderr.trim())
8006
+ console.error(colors.dim(accessResult.stderr.trim()));
8007
+ console.error(colors.red(explainAccessChangeFailure(pkg.name, 'restricted', accessResult)));
7985
8008
  if (!force)
7986
8009
  return false;
7987
8010
  }
@@ -7998,13 +8021,17 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
7998
8021
  if (currentAccess === 'restricted') {
7999
8022
  console.log(colors.yellow(`Package '${pkg.name}' is currently PRIVATE on npm. Converting to public...`));
8000
8023
  if (!dryRun) {
8001
- const accessResult = await runCommandAsync('npm', ['access', 'set', 'status=public', pkg.name], { cwd, silent: false });
8024
+ // 2026-09-23 01:15 EDT — Claude Code (Fable 5.1): silent:true to capture npm's
8025
+ // output for the 403 detection; echoed on failure. Same as the restricted branch.
8026
+ const accessResult = await runCommandAsync('npm', ['access', 'set', 'status=public', pkg.name], { cwd, silent: true });
8002
8027
  if (accessResult.success) {
8003
8028
  console.log(colors.green(`✓ Changed ${pkg.name} to PUBLIC on npm`));
8004
8029
  currentAccess = 'public';
8005
8030
  }
8006
8031
  else {
8007
- console.error(colors.red(`Failed to change access. Try manually: npm access set status=public ${pkg.name}`));
8032
+ if (accessResult.stderr.trim())
8033
+ console.error(colors.dim(accessResult.stderr.trim()));
8034
+ console.error(colors.red(explainAccessChangeFailure(pkg.name, 'public', accessResult)));
8008
8035
  if (!force)
8009
8036
  return false;
8010
8037
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/npmglobalize",
3
- "version": "1.0.234",
3
+ "version": "1.0.236",
4
4
  "description": "Transform file: dependencies to npm versions for publishing",
5
5
  "main": "index.js",
6
6
  "type": "module",