@bobfrankston/npmglobalize 1.0.137 → 1.0.139
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/colors.d.ts +29 -0
- package/colors.js +64 -0
- package/ignorepatterns.json5 +1 -0
- package/lib/git.js +38 -1
- package/lib.js +158 -125
- package/package.json +6 -4
- package/bobfrankston-npmglobalize-1.0.77.tgz +0 -0
package/colors.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Functional color module for npmglobalize.
|
|
3
|
+
* Uses semantic names (success, warn, error, info, muted) instead of raw colors.
|
|
4
|
+
* Adapts to light/dark terminal backgrounds.
|
|
5
|
+
*/
|
|
6
|
+
/** Semantic color functions — use these instead of raw colors */
|
|
7
|
+
export declare const colors: {
|
|
8
|
+
/** Success: green on both themes */
|
|
9
|
+
success: (text: string) => string;
|
|
10
|
+
/** Warning: yellow on dark, magenta on light */
|
|
11
|
+
warn: (text: string) => string;
|
|
12
|
+
/** Error: red on both themes */
|
|
13
|
+
error: (text: string) => string;
|
|
14
|
+
/** Info: blue on both themes */
|
|
15
|
+
info: (text: string) => string;
|
|
16
|
+
/** Accent: cyan on both themes */
|
|
17
|
+
accent: (text: string) => string;
|
|
18
|
+
/** Muted/dim text */
|
|
19
|
+
muted: (text: string) => string;
|
|
20
|
+
/** Italic */
|
|
21
|
+
italic: (text: string) => string;
|
|
22
|
+
red: (text: string) => string;
|
|
23
|
+
yellow: (text: string) => string;
|
|
24
|
+
green: (text: string) => string;
|
|
25
|
+
blue: (text: string) => string;
|
|
26
|
+
cyan: (text: string) => string;
|
|
27
|
+
dim: (text: string) => string;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=colors.d.ts.map
|
package/colors.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Functional color module for npmglobalize.
|
|
3
|
+
* Uses semantic names (success, warn, error, info, muted) instead of raw colors.
|
|
4
|
+
* Adapts to light/dark terminal backgrounds.
|
|
5
|
+
*/
|
|
6
|
+
import { styleText } from 'util';
|
|
7
|
+
/** Detect terminal theme from environment or default to dark */
|
|
8
|
+
function detectTheme() {
|
|
9
|
+
// COLORFGBG is set by some terminals: "fg;bg" — high bg = light theme
|
|
10
|
+
const colorfgbg = process.env.COLORFGBG;
|
|
11
|
+
if (colorfgbg) {
|
|
12
|
+
const bg = parseInt(colorfgbg.split(';').pop() || '0', 10);
|
|
13
|
+
if (bg > 8)
|
|
14
|
+
return 'light';
|
|
15
|
+
}
|
|
16
|
+
// Explicit override
|
|
17
|
+
if (process.env.NPMG_THEME === 'light')
|
|
18
|
+
return 'light';
|
|
19
|
+
if (process.env.NPMG_THEME === 'dark')
|
|
20
|
+
return 'dark';
|
|
21
|
+
return 'dark';
|
|
22
|
+
}
|
|
23
|
+
const theme = detectTheme();
|
|
24
|
+
// Raw ANSI colors per theme — semantic → [dark, light]
|
|
25
|
+
const themeMap = {
|
|
26
|
+
success: ['green', 'green'],
|
|
27
|
+
warn: ['yellow', 'magenta'], // yellow is invisible on light bg
|
|
28
|
+
error: ['red', 'red'],
|
|
29
|
+
info: ['blue', 'blue'],
|
|
30
|
+
accent: ['cyan', 'cyan'],
|
|
31
|
+
muted: ['dim', 'dim'],
|
|
32
|
+
italic: ['italic', 'italic'],
|
|
33
|
+
};
|
|
34
|
+
function pick(semantic) {
|
|
35
|
+
const entry = themeMap[semantic];
|
|
36
|
+
if (!entry)
|
|
37
|
+
return semantic;
|
|
38
|
+
return theme === 'light' ? entry[1] : entry[0];
|
|
39
|
+
}
|
|
40
|
+
/** Semantic color functions — use these instead of raw colors */
|
|
41
|
+
export const colors = {
|
|
42
|
+
/** Success: green on both themes */
|
|
43
|
+
success: (text) => styleText(pick('success'), text),
|
|
44
|
+
/** Warning: yellow on dark, magenta on light */
|
|
45
|
+
warn: (text) => styleText(pick('warn'), text),
|
|
46
|
+
/** Error: red on both themes */
|
|
47
|
+
error: (text) => styleText(pick('error'), text),
|
|
48
|
+
/** Info: blue on both themes */
|
|
49
|
+
info: (text) => styleText(pick('info'), text),
|
|
50
|
+
/** Accent: cyan on both themes */
|
|
51
|
+
accent: (text) => styleText(pick('accent'), text),
|
|
52
|
+
/** Muted/dim text */
|
|
53
|
+
muted: (text) => styleText(pick('muted'), text),
|
|
54
|
+
/** Italic */
|
|
55
|
+
italic: (text) => styleText('italic', text),
|
|
56
|
+
// Legacy aliases for gradual migration
|
|
57
|
+
red: (text) => styleText(pick('error'), text),
|
|
58
|
+
yellow: (text) => styleText(pick('warn'), text),
|
|
59
|
+
green: (text) => styleText(pick('success'), text),
|
|
60
|
+
blue: (text) => styleText(pick('info'), text),
|
|
61
|
+
cyan: (text) => styleText(pick('accent'), text),
|
|
62
|
+
dim: (text) => styleText(pick('muted'), text),
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=colors.js.map
|
package/ignorepatterns.json5
CHANGED
package/lib/git.js
CHANGED
|
@@ -659,12 +659,49 @@ export function showPushProtectionGuidance(ppInfo) {
|
|
|
659
659
|
/** Push to git with push-protection detection and auto-bypass for installed OAuth.
|
|
660
660
|
* Returns true if push succeeded (possibly after auto-bypass). */
|
|
661
661
|
export function pushWithProtection(cwd, verbose) {
|
|
662
|
-
|
|
662
|
+
let pushResult = runCommand('git', ['push'], { cwd, silent: true });
|
|
663
663
|
if (pushResult.success) {
|
|
664
664
|
if (verbose)
|
|
665
665
|
console.log(colors.green(' ✓ Pushed to remote'));
|
|
666
666
|
return true;
|
|
667
667
|
}
|
|
668
|
+
// Check for "Everything up-to-date" — git sometimes returns non-zero
|
|
669
|
+
// alongside transient errors even though there's nothing to push
|
|
670
|
+
const combined = (pushResult.output + ' ' + pushResult.stderr).toLowerCase();
|
|
671
|
+
if (combined.includes('everything up-to-date')) {
|
|
672
|
+
if (verbose)
|
|
673
|
+
console.log(colors.green(' ✓ Already up-to-date'));
|
|
674
|
+
return true;
|
|
675
|
+
}
|
|
676
|
+
// No upstream branch — auto-set and retry
|
|
677
|
+
if (combined.includes('no upstream branch') || combined.includes('has no upstream')) {
|
|
678
|
+
if (verbose)
|
|
679
|
+
console.log(colors.yellow(' No upstream branch — setting upstream...'));
|
|
680
|
+
const branchResult = runCommand('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd, silent: true });
|
|
681
|
+
const branch = branchResult.output.trim() || 'master';
|
|
682
|
+
pushResult = runCommand('git', ['push', '--set-upstream', 'origin', branch], { cwd, silent: true });
|
|
683
|
+
if (pushResult.success) {
|
|
684
|
+
if (verbose)
|
|
685
|
+
console.log(colors.green(' ✓ Pushed to remote (set upstream)'));
|
|
686
|
+
return true;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
// Transient network errors (HTTP 408, RPC failed, unexpected disconnect) — retry once
|
|
690
|
+
if (/rpc failed|curl \d+|unexpected disconnect|hung up unexpectedly/i.test(pushResult.stderr)) {
|
|
691
|
+
console.log(colors.yellow('Git push failed with transient error — retrying...'));
|
|
692
|
+
pushResult = runCommand('git', ['push'], { cwd, silent: true });
|
|
693
|
+
if (pushResult.success) {
|
|
694
|
+
if (verbose)
|
|
695
|
+
console.log(colors.green(' ✓ Pushed to remote (retry)'));
|
|
696
|
+
return true;
|
|
697
|
+
}
|
|
698
|
+
const retryCombo = (pushResult.output + ' ' + pushResult.stderr).toLowerCase();
|
|
699
|
+
if (retryCombo.includes('everything up-to-date')) {
|
|
700
|
+
if (verbose)
|
|
701
|
+
console.log(colors.green(' ✓ Already up-to-date'));
|
|
702
|
+
return true;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
668
705
|
const ppInfo = parsePushProtection(pushResult.stderr, cwd);
|
|
669
706
|
if (!ppInfo.detected) {
|
|
670
707
|
console.error(colors.red('Git push failed:'));
|
package/lib.js
CHANGED
|
@@ -30,17 +30,9 @@ import readline from 'readline';
|
|
|
30
30
|
import libversion from 'libnpmversion';
|
|
31
31
|
import JSON5 from 'json5';
|
|
32
32
|
import { fileURLToPath } from 'url';
|
|
33
|
-
import {
|
|
34
|
-
/**
|
|
35
|
-
const colors =
|
|
36
|
-
red: (text) => styleText('red', text),
|
|
37
|
-
yellow: (text) => styleText('yellow', text),
|
|
38
|
-
green: (text) => styleText('green', text),
|
|
39
|
-
italic: (text) => styleText('italic', text),
|
|
40
|
-
blue: (text) => styleText('blue', text),
|
|
41
|
-
cyan: (text) => styleText('cyan', text),
|
|
42
|
-
dim: (text) => styleText('dim', text),
|
|
43
|
-
};
|
|
33
|
+
import { themeColors } from '@bobfrankston/themecolors';
|
|
34
|
+
/** Semantic color functions — adapts to terminal light/dark theme */
|
|
35
|
+
const colors = themeColors();
|
|
44
36
|
/**
|
|
45
37
|
* Remove 'nul' files from a directory tree (Windows reserved name issue).
|
|
46
38
|
* These files break git and npm on Windows. Uses \\?\ prefix to bypass name validation.
|
|
@@ -1641,12 +1633,50 @@ function showPushProtectionGuidance(ppInfo) {
|
|
|
1641
1633
|
/** Push to git with push-protection detection and auto-bypass for installed OAuth.
|
|
1642
1634
|
* Returns true if push succeeded (possibly after auto-bypass). */
|
|
1643
1635
|
function pushWithProtection(cwd, verbose) {
|
|
1644
|
-
|
|
1636
|
+
let pushResult = runCommand('git', ['push'], { cwd, silent: true });
|
|
1645
1637
|
if (pushResult.success) {
|
|
1646
1638
|
if (verbose)
|
|
1647
1639
|
console.log(colors.green(' ✓ Pushed to remote'));
|
|
1648
1640
|
return true;
|
|
1649
1641
|
}
|
|
1642
|
+
// Check for "Everything up-to-date" — git sometimes returns non-zero
|
|
1643
|
+
// alongside transient errors even though there's nothing to push
|
|
1644
|
+
const combined = (pushResult.output + ' ' + pushResult.stderr).toLowerCase();
|
|
1645
|
+
if (combined.includes('everything up-to-date')) {
|
|
1646
|
+
if (verbose)
|
|
1647
|
+
console.log(colors.green(' ✓ Already up-to-date'));
|
|
1648
|
+
return true;
|
|
1649
|
+
}
|
|
1650
|
+
// No upstream branch — auto-set and retry
|
|
1651
|
+
if (combined.includes('no upstream branch') || combined.includes('has no upstream')) {
|
|
1652
|
+
if (verbose)
|
|
1653
|
+
console.log(colors.yellow(' No upstream branch — setting upstream...'));
|
|
1654
|
+
// Detect current branch name
|
|
1655
|
+
const branchResult = runCommand('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd, silent: true });
|
|
1656
|
+
const branch = branchResult.output.trim() || 'master';
|
|
1657
|
+
pushResult = runCommand('git', ['push', '--set-upstream', 'origin', branch], { cwd, silent: true });
|
|
1658
|
+
if (pushResult.success) {
|
|
1659
|
+
if (verbose)
|
|
1660
|
+
console.log(colors.green(' ✓ Pushed to remote (set upstream)'));
|
|
1661
|
+
return true;
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
// Transient network errors (HTTP 408, RPC failed, unexpected disconnect) — retry once
|
|
1665
|
+
if (/rpc failed|curl \d+|unexpected disconnect|hung up unexpectedly/i.test(pushResult.stderr)) {
|
|
1666
|
+
console.log(colors.yellow('Git push failed with transient error — retrying...'));
|
|
1667
|
+
pushResult = runCommand('git', ['push'], { cwd, silent: true });
|
|
1668
|
+
if (pushResult.success) {
|
|
1669
|
+
if (verbose)
|
|
1670
|
+
console.log(colors.green(' ✓ Pushed to remote (retry)'));
|
|
1671
|
+
return true;
|
|
1672
|
+
}
|
|
1673
|
+
const retryCombo = (pushResult.output + ' ' + pushResult.stderr).toLowerCase();
|
|
1674
|
+
if (retryCombo.includes('everything up-to-date')) {
|
|
1675
|
+
if (verbose)
|
|
1676
|
+
console.log(colors.green(' ✓ Already up-to-date'));
|
|
1677
|
+
return true;
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1650
1680
|
const ppInfo = parsePushProtection(pushResult.stderr, cwd);
|
|
1651
1681
|
if (!ppInfo.detected) {
|
|
1652
1682
|
console.error(colors.red('Git push failed:'));
|
|
@@ -2035,9 +2065,17 @@ export async function initGit(cwd, visibility, dryRun) {
|
|
|
2035
2065
|
const createResult = runCommand('gh', ['repo', 'create', repoName, visFlag, '--source=.', '--push'], { cwd, silent: true });
|
|
2036
2066
|
if (!createResult.success) {
|
|
2037
2067
|
const errText = createResult.stderr + createResult.output;
|
|
2038
|
-
if (
|
|
2068
|
+
// Check if repo was created but push failed (GitHub propagation delay)
|
|
2069
|
+
const repoCreatedButPushFailed = /repository not found|hung up unexpectedly|rpc failed/i.test(errText)
|
|
2070
|
+
&& /https?:\/\/github\.com\//i.test(errText);
|
|
2071
|
+
if (errText.includes('Name already exists') || repoCreatedButPushFailed) {
|
|
2039
2072
|
// Repo exists on GitHub — look up the owner and add as remote
|
|
2040
|
-
|
|
2073
|
+
if (repoCreatedButPushFailed) {
|
|
2074
|
+
console.log(colors.yellow(` GitHub repo created but initial push failed — retrying...`));
|
|
2075
|
+
}
|
|
2076
|
+
else {
|
|
2077
|
+
console.log(colors.yellow(` GitHub repo '${repoName}' already exists — linking as remote...`));
|
|
2078
|
+
}
|
|
2041
2079
|
const whoResult = runCommand('gh', ['api', 'user', '--jq', '.login'], { cwd, silent: true });
|
|
2042
2080
|
const ghUser = (whoResult.output || '').trim();
|
|
2043
2081
|
if (!ghUser) {
|
|
@@ -2050,9 +2088,22 @@ export async function initGit(cwd, visibility, dryRun) {
|
|
|
2050
2088
|
// Remote might already exist with wrong URL
|
|
2051
2089
|
runCommand('git', ['remote', 'set-url', 'origin', remoteUrl], { cwd, silent: true });
|
|
2052
2090
|
}
|
|
2053
|
-
// Push existing commits
|
|
2054
|
-
|
|
2055
|
-
|
|
2091
|
+
// Push existing commits (retry up to 2 times for propagation delay)
|
|
2092
|
+
let pushed = false;
|
|
2093
|
+
for (let attempt = 0; attempt < 2 && !pushed; attempt++) {
|
|
2094
|
+
if (attempt > 0) {
|
|
2095
|
+
console.log(colors.yellow(' Retrying push...'));
|
|
2096
|
+
spawnSafe(process.platform === 'win32' ? 'timeout' : 'sleep', process.platform === 'win32' ? ['\t', '3', '\nobreak'] : ['3'], { stdio: 'pipe' }); // brief delay for GitHub propagation
|
|
2097
|
+
}
|
|
2098
|
+
const pushRes = runCommand('git', ['push', '-u', 'origin', 'master'], { cwd, silent: true });
|
|
2099
|
+
pushed = pushRes.success;
|
|
2100
|
+
}
|
|
2101
|
+
if (pushed) {
|
|
2102
|
+
console.log(colors.green(` ✓ Linked to repo: ${remoteUrl}`));
|
|
2103
|
+
}
|
|
2104
|
+
else {
|
|
2105
|
+
console.log(colors.yellow(` ✓ Repo created but push failed — push manually: git push -u origin master`));
|
|
2106
|
+
}
|
|
2056
2107
|
}
|
|
2057
2108
|
else {
|
|
2058
2109
|
console.error(colors.red(`Failed to create GitHub repo: ${errText}`));
|
|
@@ -3641,12 +3692,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3641
3692
|
}
|
|
3642
3693
|
}
|
|
3643
3694
|
else if (error.message?.includes('unknown git error')) {
|
|
3644
|
-
console.error(colors.yellow('
|
|
3645
|
-
console.error(' • Git hooks (pre-commit, commit-msg) might be failing');
|
|
3646
|
-
console.error(' • GPG signing might be required but not configured');
|
|
3647
|
-
console.error(' • Git config issues (user.name, user.email)');
|
|
3648
|
-
console.error(' • Disk space or permissions issues');
|
|
3649
|
-
console.error(colors.yellow('\nTry running with --verbose or check git status manually'));
|
|
3695
|
+
console.error(colors.yellow('Unknown git error — check git hooks, signing, or permissions'));
|
|
3650
3696
|
}
|
|
3651
3697
|
else if (combinedOutput.includes('gh013') || combinedOutput.includes('push protection') || combinedOutput.includes('push declined due to repository rule')) {
|
|
3652
3698
|
// GitHub push protection blocked a push (from postversion script)
|
|
@@ -3688,35 +3734,43 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3688
3734
|
else if (!skipVersionBump) {
|
|
3689
3735
|
console.log(` [dry-run] Would run: npm version ${bump}`);
|
|
3690
3736
|
}
|
|
3737
|
+
// Check for public package depending on private dependencies
|
|
3738
|
+
const publishAccess = effectiveNpmVisibility || currentAccess || (isScoped ? 'restricted' : 'public');
|
|
3739
|
+
if (publishAccess === 'public') {
|
|
3740
|
+
const privateDeps = [];
|
|
3741
|
+
for (const depKey of ['dependencies', 'peerDependencies']) {
|
|
3742
|
+
const deps = pkg[depKey];
|
|
3743
|
+
if (!deps)
|
|
3744
|
+
continue;
|
|
3745
|
+
for (const depName of Object.keys(deps)) {
|
|
3746
|
+
const depAccess = checkNpmAccess(depName);
|
|
3747
|
+
if (depAccess === 'restricted') {
|
|
3748
|
+
privateDeps.push(depName);
|
|
3749
|
+
}
|
|
3750
|
+
else if (depAccess === null && depName.startsWith('@')) {
|
|
3751
|
+
// Scoped package not on npm — will be private by default
|
|
3752
|
+
privateDeps.push(`${depName} (not yet published)`);
|
|
3753
|
+
}
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
if (privateDeps.length > 0) {
|
|
3757
|
+
console.log('');
|
|
3758
|
+
console.error(colors.red('WARNING: Public package depends on PRIVATE dependencies:'));
|
|
3759
|
+
for (const d of privateDeps) {
|
|
3760
|
+
console.error(colors.red(` ${d}`));
|
|
3761
|
+
}
|
|
3762
|
+
console.error(colors.yellow('Consumers will get E404 when installing this package.'));
|
|
3763
|
+
console.error(colors.yellow('Fix: publish those deps as public, or make this package private.'));
|
|
3764
|
+
console.log('');
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3691
3767
|
// Publish
|
|
3692
3768
|
console.log('Publishing to npm...');
|
|
3693
3769
|
if (!dryRun) {
|
|
3694
3770
|
// Check npm authentication right before publishing
|
|
3695
3771
|
const authStatus = checkNpmAuth();
|
|
3696
3772
|
if (!authStatus.authenticated) {
|
|
3697
|
-
console.error(colors.red(
|
|
3698
|
-
console.error('');
|
|
3699
|
-
if (authStatus.error === 'token expired') {
|
|
3700
|
-
console.error('Your npm access token has expired or been revoked.');
|
|
3701
|
-
console.error('');
|
|
3702
|
-
console.error('To fix this, run:');
|
|
3703
|
-
console.error(colors.yellow(' npm logout'));
|
|
3704
|
-
console.error(colors.yellow(' npm login'));
|
|
3705
|
-
}
|
|
3706
|
-
else if (authStatus.error === 'not logged in') {
|
|
3707
|
-
console.error('You are not logged in to npm.');
|
|
3708
|
-
console.error('');
|
|
3709
|
-
console.error('To fix this, run:');
|
|
3710
|
-
console.error(colors.yellow(' npm login'));
|
|
3711
|
-
}
|
|
3712
|
-
else {
|
|
3713
|
-
console.error(`Authentication error: ${authStatus.error}`);
|
|
3714
|
-
console.error('');
|
|
3715
|
-
console.error('Try running:');
|
|
3716
|
-
console.error(colors.yellow(' npm whoami'));
|
|
3717
|
-
}
|
|
3718
|
-
console.error('');
|
|
3719
|
-
console.error('After logging in, try running this command again.');
|
|
3773
|
+
console.error(colors.red(`Not authenticated to npm (${authStatus.error}) — run: npm login`));
|
|
3720
3774
|
return false;
|
|
3721
3775
|
}
|
|
3722
3776
|
if (verbose) {
|
|
@@ -3738,9 +3792,40 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3738
3792
|
return false;
|
|
3739
3793
|
}
|
|
3740
3794
|
const tarballPath = path.join(cwd, tarballName);
|
|
3741
|
-
if
|
|
3742
|
-
|
|
3795
|
+
// Check tarball size — warn if suspiciously large
|
|
3796
|
+
try {
|
|
3797
|
+
const tarballSize = fs.statSync(tarballPath).size;
|
|
3798
|
+
const sizeMB = tarballSize / (1024 * 1024);
|
|
3799
|
+
if (sizeMB > 50) {
|
|
3800
|
+
console.error(colors.red(`\n⚠ Tarball is ${sizeMB.toFixed(0)}MB — something large is being included!`));
|
|
3801
|
+
// Show biggest files in the tarball
|
|
3802
|
+
const listResult = runCommand('npm', ['pack', '--dry-run'], { cwd, silent: true });
|
|
3803
|
+
if (listResult.success) {
|
|
3804
|
+
const lines = listResult.output.trim().split('\n')
|
|
3805
|
+
.filter(l => l.includes('B '))
|
|
3806
|
+
.map(l => { const m = l.match(/([\d.]+[kMG]?B)\s+(.*)/); return m ? { size: m[1], file: m[2] } : null; })
|
|
3807
|
+
.filter(Boolean)
|
|
3808
|
+
.filter((e) => e.size.includes('M') || e.size.includes('G'))
|
|
3809
|
+
.slice(0, 10);
|
|
3810
|
+
if (lines.length > 0) {
|
|
3811
|
+
console.error(colors.yellow(' Large files in tarball:'));
|
|
3812
|
+
for (const e of lines)
|
|
3813
|
+
console.error(colors.yellow(` ${e.size}\t${e.file}`));
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
console.error(colors.yellow(' Check .npmignore — you may need to exclude large files or directories.'));
|
|
3817
|
+
// Clean up and abort
|
|
3818
|
+
try {
|
|
3819
|
+
fs.unlinkSync(tarballPath);
|
|
3820
|
+
}
|
|
3821
|
+
catch { /* */ }
|
|
3822
|
+
return false;
|
|
3823
|
+
}
|
|
3824
|
+
if (verbose) {
|
|
3825
|
+
console.log(` Tarball: ${tarballName} (${sizeMB.toFixed(1)}MB)`);
|
|
3826
|
+
}
|
|
3743
3827
|
}
|
|
3828
|
+
catch { /* proceed if stat fails */ }
|
|
3744
3829
|
// Publish the tarball
|
|
3745
3830
|
const npmArgs = ['publish', tarballName];
|
|
3746
3831
|
// Determine access level (use effectiveNpmVisibility which accounts for current npm status)
|
|
@@ -3789,78 +3874,22 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3789
3874
|
}
|
|
3790
3875
|
if (!publishResult.success) {
|
|
3791
3876
|
console.error(colors.red('\nERROR: npm publish failed\n'));
|
|
3792
|
-
//
|
|
3793
|
-
if (publishResult.stderr && publishResult.stderr.trim()) {
|
|
3794
|
-
console.error('npm error output:');
|
|
3795
|
-
console.error(publishResult.stderr.trim());
|
|
3796
|
-
console.error('');
|
|
3797
|
-
}
|
|
3798
|
-
else if (publishResult.output && publishResult.output.trim()) {
|
|
3799
|
-
console.error('npm output:');
|
|
3800
|
-
console.error(publishResult.output.trim());
|
|
3801
|
-
console.error('');
|
|
3802
|
-
}
|
|
3803
|
-
// Check for E409 conflict (publishing too fast)
|
|
3877
|
+
// Check for specific error types
|
|
3804
3878
|
const output = (publishResult.output + '\n' + publishResult.stderr).toLowerCase();
|
|
3805
|
-
if (output.includes('
|
|
3806
|
-
console.error(colors.
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
console.error(colors.
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
// Extract the version number from the error if possible
|
|
3816
|
-
const versionMatch = output.match(/versions?[:\s]+(\d+\.\d+\.\d+)/);
|
|
3817
|
-
const failedVersion = versionMatch ? versionMatch[1] : null;
|
|
3818
|
-
// Check if this is the version we just bumped to
|
|
3819
|
-
const currentPkgVersion = readPackageJson(cwd).version;
|
|
3820
|
-
const isCurrentVersion = failedVersion === currentPkgVersion;
|
|
3821
|
-
console.error(colors.yellow('⚠ Version already published to npm'));
|
|
3822
|
-
console.error('');
|
|
3823
|
-
if (isCurrentVersion) {
|
|
3824
|
-
console.error(colors.green('✓ Good news: This version was already published (possibly just now)'));
|
|
3825
|
-
console.error('');
|
|
3826
|
-
console.error('The git commit and tag were created, but npm says this version exists.');
|
|
3827
|
-
console.error('This is actually SUCCESS - your package is published!');
|
|
3828
|
-
console.error('');
|
|
3829
|
-
console.error('Verify with: ' + colors.yellow(`npm view ${pkg.name}@${currentPkgVersion}`));
|
|
3830
|
-
console.error('');
|
|
3831
|
-
console.error(colors.yellow('Note: You may have a postversion script that auto-publishes.'));
|
|
3832
|
-
console.error(colors.yellow('npmglobalize will now skip that hook to prevent this issue.'));
|
|
3833
|
-
console.error('');
|
|
3834
|
-
// Treat as success and continue
|
|
3835
|
-
console.log(colors.green('✓ Treating as successful publish'));
|
|
3836
|
-
// Don't return false - let it continue to push git tags
|
|
3837
|
-
}
|
|
3838
|
-
else {
|
|
3839
|
-
console.error('Version ' + colors.yellow(failedVersion || 'unknown') + ' is already on npm.');
|
|
3840
|
-
console.error('This shouldn\'t happen - the version was bumped but publish failed.');
|
|
3841
|
-
console.error('');
|
|
3842
|
-
console.error(colors.yellow('To recover:'));
|
|
3843
|
-
console.error(' Just run npmglobalize again (it will bump to next version)');
|
|
3844
|
-
console.error('');
|
|
3845
|
-
if (transformResult.transformed) {
|
|
3846
|
-
console.log('Restoring file: dependencies...');
|
|
3847
|
-
const failPkg = readPackageJson(cwd);
|
|
3848
|
-
restoreDeps(failPkg, verbose);
|
|
3849
|
-
writePackageJson(cwd, failPkg);
|
|
3850
|
-
runCommand('git', ['add', 'package.json'], { cwd, silent: true });
|
|
3851
|
-
gitCommit('Restore file: dependencies', cwd);
|
|
3852
|
-
}
|
|
3853
|
-
return false;
|
|
3854
|
-
}
|
|
3879
|
+
if (output.includes('err_string_too_long') || output.includes('string longer than')) {
|
|
3880
|
+
console.error(colors.red('Tarball too large — check .npmignore. Run: npm pack --dry-run'));
|
|
3881
|
+
}
|
|
3882
|
+
else if (output.includes('e409') || output.includes('409 conflict')) {
|
|
3883
|
+
console.error(colors.yellow('npm still processing previous version — wait and retry'));
|
|
3884
|
+
}
|
|
3885
|
+
else if (output.includes('cannot publish over') || output.includes('previously published')) {
|
|
3886
|
+
const currentPkgVersion = readPackageJson(cwd).version;
|
|
3887
|
+
if (output.includes(currentPkgVersion)) {
|
|
3888
|
+
console.log(colors.green('✓ Already published — continuing'));
|
|
3855
3889
|
}
|
|
3856
3890
|
else {
|
|
3857
|
-
console.error(colors.yellow('
|
|
3858
|
-
console.error(' 1. Package name already taken by another user');
|
|
3859
|
-
console.error(' 2. No publish access to this package');
|
|
3860
|
-
console.error(' 3. Scope (@username) requires authentication');
|
|
3861
|
-
console.error('');
|
|
3891
|
+
console.error(colors.yellow('Version conflict — run npmglobalize again'));
|
|
3862
3892
|
if (transformResult.transformed) {
|
|
3863
|
-
console.log('Restoring file: dependencies...');
|
|
3864
3893
|
const failPkg = readPackageJson(cwd);
|
|
3865
3894
|
restoreDeps(failPkg, verbose);
|
|
3866
3895
|
writePackageJson(cwd, failPkg);
|
|
@@ -3870,18 +3899,22 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3870
3899
|
return false;
|
|
3871
3900
|
}
|
|
3872
3901
|
}
|
|
3902
|
+
else if (output.includes('403') || output.includes('forbidden')) {
|
|
3903
|
+
console.error(colors.yellow('Publish forbidden — check npm login and package access'));
|
|
3904
|
+
if (transformResult.transformed) {
|
|
3905
|
+
const failPkg = readPackageJson(cwd);
|
|
3906
|
+
restoreDeps(failPkg, verbose);
|
|
3907
|
+
writePackageJson(cwd, failPkg);
|
|
3908
|
+
runCommand('git', ['add', 'package.json'], { cwd, silent: true });
|
|
3909
|
+
gitCommit('Restore file: dependencies', cwd);
|
|
3910
|
+
}
|
|
3911
|
+
return false;
|
|
3912
|
+
}
|
|
3873
3913
|
else if (output.includes('402') || output.includes('payment required')) {
|
|
3874
|
-
console.error(colors.yellow('Private packages
|
|
3875
|
-
console.error(' • Use --npm public to publish as public');
|
|
3876
|
-
console.error(' • Or upgrade your npm account for private packages');
|
|
3877
|
-
console.error('');
|
|
3914
|
+
console.error(colors.yellow('Private packages need paid npm account — use --npm public'));
|
|
3878
3915
|
}
|
|
3879
3916
|
else {
|
|
3880
|
-
console.error(colors.yellow('
|
|
3881
|
-
console.error(' 1. Not logged in - run: npm login');
|
|
3882
|
-
console.error(' 2. Version already published');
|
|
3883
|
-
console.error(' 3. Authentication token expired');
|
|
3884
|
-
console.error('');
|
|
3917
|
+
console.error(colors.yellow('Publish failed — run npm login or check npm whoami'));
|
|
3885
3918
|
}
|
|
3886
3919
|
if (transformResult.transformed) {
|
|
3887
3920
|
console.log('Restoring file: dependencies...');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/npmglobalize",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.139",
|
|
4
4
|
"description": "Transform file: dependencies to npm versions for publishing",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -31,9 +31,10 @@
|
|
|
31
31
|
"url": "https://github.com/BobFrankston/npmglobalize.git"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@bobfrankston/freezepak": "^0.1.
|
|
35
|
-
"@bobfrankston/importgen": "^0.1.
|
|
36
|
-
"@bobfrankston/
|
|
34
|
+
"@bobfrankston/freezepak": "^0.1.6",
|
|
35
|
+
"@bobfrankston/importgen": "^0.1.32",
|
|
36
|
+
"@bobfrankston/themecolors": "^0.1.2",
|
|
37
|
+
"@bobfrankston/userconfig": "^1.0.6",
|
|
37
38
|
"@npmcli/package-json": "^7.0.4",
|
|
38
39
|
"json5": "^2.2.3",
|
|
39
40
|
"libnpmversion": "^8.0.3",
|
|
@@ -47,6 +48,7 @@
|
|
|
47
48
|
".dependencies": {
|
|
48
49
|
"@bobfrankston/freezepak": "file:../freezepak",
|
|
49
50
|
"@bobfrankston/importgen": "file:../importgen",
|
|
51
|
+
"@bobfrankston/themecolors": "file:../themecolors",
|
|
50
52
|
"@bobfrankston/userconfig": "file:../userconfig",
|
|
51
53
|
"@npmcli/package-json": "^7.0.4",
|
|
52
54
|
"json5": "^2.2.3",
|
|
Binary file
|