@bobfrankston/npmglobalize 1.0.14 → 1.0.18

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/lib.d.ts +1 -0
  2. package/lib.js +70 -54
  3. package/package.json +1 -1
package/lib.d.ts CHANGED
@@ -64,6 +64,7 @@ export declare function hasBackup(pkg: any): boolean;
64
64
  export declare function runCommand(cmd: string, args: string[], options?: {
65
65
  silent?: boolean;
66
66
  cwd?: string;
67
+ shell?: boolean;
67
68
  }): {
68
69
  success: boolean;
69
70
  output: string;
package/lib.js CHANGED
@@ -213,13 +213,13 @@ export function hasBackup(pkg) {
213
213
  }
214
214
  /** Run a command and return success status */
215
215
  export function runCommand(cmd, args, options = {}) {
216
- const { silent = false, cwd } = options;
216
+ const { silent = false, cwd, shell = false } = options;
217
217
  try {
218
218
  const result = spawnSync(cmd, args, {
219
219
  encoding: 'utf-8',
220
220
  stdio: silent ? 'pipe' : 'inherit',
221
221
  cwd,
222
- shell: false // Don't use shell to avoid argument parsing issues
222
+ shell // Use shell when explicitly requested (e.g., for npm publish on Windows)
223
223
  });
224
224
  // For non-silent commands, we can't capture output when using 'inherit'
225
225
  // So we return empty string for output, but the user sees it in the terminal
@@ -993,69 +993,85 @@ export async function globalize(cwd, options = {}) {
993
993
  }
994
994
  // Publish
995
995
  console.log('Publishing to npm...');
996
- const npmArgs = ['publish'];
997
- if (quiet) {
998
- npmArgs.push('--quiet');
999
- }
1000
996
  if (!dryRun) {
1001
- // Run with silent:true to capture the error message
1002
- const publishResult = runCommand('npm', npmArgs, { cwd, silent: true });
1003
- if (!publishResult.success) {
1004
- console.error(colors.red('\nERROR: npm publish failed\n'));
1005
- // Combine stdout and stderr for error analysis
1006
- const errorOutput = (publishResult.output + '\n' + publishResult.stderr).toLowerCase();
1007
- // Check for specific error types
1008
- if (errorOutput.includes('e403') && (errorOutput.includes('two-factor') || errorOutput.includes('2fa'))) {
1009
- console.error(colors.red('⚠ 2FA Required'));
1010
- console.error('');
1011
- console.error('Your npm account requires two-factor authentication or a');
1012
- console.error('granular access token with "bypass 2FA" enabled.');
1013
- console.error('');
1014
- console.error(colors.yellow('Your options:'));
1015
- console.error('');
1016
- console.error('1. Enable 2FA on your npm account:');
1017
- console.error(colors.green(' https://www.npmjs.com/settings/[username]/tfa'));
1018
- console.error('');
1019
- console.error('2. Create a granular access token:');
1020
- console.error(colors.green(' https://www.npmjs.com/settings/[username]/tokens'));
1021
- console.error(' - Select "Granular Access Token"');
1022
- console.error(' - Set permissions: Read and write');
1023
- console.error(' - Enable "Bypass 2FA requirement"');
1024
- console.error(' - Then set via environment variable or .npmrc:');
1025
- console.error(colors.green(' $env:NPM_TOKEN="npm_xxx..."'));
1026
- console.error(' Or add to ~/.npmrc:');
1027
- console.error(colors.green(' //registry.npmjs.org/:_authToken=npm_xxx...'));
1028
- console.error('');
997
+ // Create tarball first
998
+ const packResult = runCommand('npm', ['pack'], { cwd, silent: true, shell: true });
999
+ if (!packResult.success) {
1000
+ console.error(colors.red('ERROR: Failed to create package tarball'));
1001
+ if (packResult.stderr)
1002
+ console.error(packResult.stderr);
1003
+ return false;
1004
+ }
1005
+ // Get the tarball filename from npm pack output
1006
+ const tarballName = packResult.output.trim().split('\n').pop()?.trim();
1007
+ if (!tarballName) {
1008
+ console.error(colors.red('ERROR: Could not determine tarball filename'));
1009
+ return false;
1010
+ }
1011
+ const tarballPath = path.join(cwd, tarballName);
1012
+ if (verbose) {
1013
+ console.log(`Created tarball: ${tarballName}`);
1014
+ }
1015
+ // Publish the tarball
1016
+ const npmArgs = ['publish', tarballName];
1017
+ if (npmVisibility === 'public') {
1018
+ npmArgs.push('--access', 'public');
1019
+ }
1020
+ if (quiet) {
1021
+ npmArgs.push('--quiet');
1022
+ }
1023
+ // Retry logic for E409 conflicts (publishing too fast)
1024
+ const maxRetries = 12; // 12 attempts * 5 seconds = 60 seconds total
1025
+ const retryDelay = 5; // 5 seconds between attempts
1026
+ let publishResult;
1027
+ let attempt = 0;
1028
+ while (attempt < maxRetries) {
1029
+ if (attempt > 0) {
1030
+ console.log(colors.yellow(`⏱ Waiting ${retryDelay} seconds before retry (attempt ${attempt + 1}/${maxRetries})...`));
1031
+ await new Promise(resolve => setTimeout(resolve, retryDelay * 1000));
1029
1032
  }
1030
- else if (errorOutput.includes('e404') || errorOutput.includes('not found')) {
1031
- console.error(colors.yellow('Package not found or access denied.'));
1032
- console.error('');
1033
- console.error('Possible causes:');
1034
- console.error(' • Package name is not available');
1035
- console.error(' • You don\'t have permission to publish to this package');
1036
- console.error(' Scope (@username/) requires organization access');
1037
- console.error('');
1033
+ publishResult = runCommand('npm', npmArgs, { cwd, silent: true, shell: true });
1034
+ if (publishResult.success) {
1035
+ break; // Success!
1036
+ }
1037
+ // Check if it's an E409 error
1038
+ const output = (publishResult.output + '\n' + publishResult.stderr).toLowerCase();
1039
+ const isE409 = output.includes('e409') || output.includes('409 conflict');
1040
+ if (!isE409) {
1041
+ break; // Not an E409, don't retry
1042
+ }
1043
+ if (attempt === 0) {
1044
+ console.log(colors.yellow('⚠ npm is still processing the previous version, retrying...'));
1045
+ }
1046
+ attempt++;
1047
+ }
1048
+ // Clean up tarball
1049
+ try {
1050
+ fs.unlinkSync(tarballPath);
1051
+ if (verbose) {
1052
+ console.log(`Cleaned up tarball: ${tarballName}`);
1038
1053
  }
1039
- else if (errorOutput.includes('e402') || errorOutput.includes('payment required')) {
1040
- console.error(colors.yellow('Payment required for private packages.'));
1054
+ }
1055
+ catch (e) {
1056
+ // Ignore cleanup errors
1057
+ }
1058
+ if (!publishResult.success) {
1059
+ console.error(colors.red('\nERROR: npm publish failed\n'));
1060
+ // Check for E409 conflict (publishing too fast)
1061
+ const output = (publishResult.output + '\n' + publishResult.stderr).toLowerCase();
1062
+ if (output.includes('e409') || output.includes('409 conflict')) {
1063
+ console.error(colors.yellow('⚠ Publishing too quickly'));
1041
1064
  console.error('');
1042
- console.error('Private scoped packages require a paid npm account.');
1043
- console.error('Either upgrade your account or make the package public.');
1065
+ console.error('npm is still processing the previous version after multiple retries.');
1066
+ console.error(colors.green('Solution: Wait a few more minutes and try again'));
1044
1067
  console.error('');
1045
1068
  }
1046
1069
  else {
1047
- // Show the actual error output
1048
- if (publishResult.stderr) {
1049
- console.error(publishResult.stderr);
1050
- }
1051
- if (publishResult.output) {
1052
- console.error(publishResult.output);
1053
- }
1054
- console.error('');
1055
1070
  console.error(colors.yellow('Common causes:'));
1056
1071
  console.error(colors.yellow(' 1. Not logged in - run: npm login'));
1057
1072
  console.error(colors.yellow(' 2. Version already published'));
1058
1073
  console.error(colors.yellow(' 3. Authentication token expired'));
1074
+ console.error('');
1059
1075
  }
1060
1076
  if (transformed) {
1061
1077
  console.log('Run --cleanup to restore file: dependencies');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/npmglobalize",
3
- "version": "1.0.14",
3
+ "version": "1.0.18",
4
4
  "description": "Transform file: dependencies to npm versions for publishing",
5
5
  "main": "index.js",
6
6
  "type": "module",