@socketsecurity/cli-with-sentry 0.14.48 → 0.14.50

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.
@@ -52,11 +52,13 @@ var index_cjs = require('@socketregistry/hyrious__bun.lockb/index.cjs');
52
52
  var sorts = require('@socketsecurity/registry/lib/sorts');
53
53
  var strings = require('@socketsecurity/registry/lib/strings');
54
54
  var yaml = _socketInterop(require('yaml'));
55
- var npm$1 = require('./npm.js');
56
55
  var npmPaths = require('./npm-paths.js');
56
+ var npm$1 = require('./npm.js');
57
57
  var betterAjvErrors = _socketInterop(require('@apideck/better-ajv-errors'));
58
58
  var config$A = require('@socketsecurity/config');
59
+ var assert = require('node:assert');
59
60
  var readline = require('node:readline/promises');
61
+ var childProcess = require('node:child_process');
60
62
  var TableWidget = _socketInterop(require('blessed-contrib/lib/widget/table'));
61
63
  var readline$1 = require('node:readline');
62
64
 
@@ -1282,6 +1284,51 @@ async function runAction(githubEventBefore, githubEventAfter) {
1282
1284
  }
1283
1285
  }
1284
1286
 
1287
+ const {
1288
+ API_V0_URL
1289
+ } = constants;
1290
+ function handleUnsuccessfulApiResponse(_name, result, spinner) {
1291
+ // SocketSdkErrorType['error'] is not typed.
1292
+ const resultErrorMessage = result.error?.message;
1293
+ const message = typeof resultErrorMessage === 'string' ? resultErrorMessage : 'No error message returned';
1294
+ if (result.status === 401 || result.status === 403) {
1295
+ spinner.stop();
1296
+ throw new index.AuthError(message);
1297
+ }
1298
+ spinner.errorAndStop(`${colors.bgRed(colors.white('API returned an error:'))} ${message}`);
1299
+ process$1.exit(1);
1300
+ }
1301
+ async function handleApiCall(value, description) {
1302
+ let result;
1303
+ try {
1304
+ result = await value;
1305
+ } catch (cause) {
1306
+ throw new Error(`Failed ${description}`, {
1307
+ cause
1308
+ });
1309
+ }
1310
+ return result;
1311
+ }
1312
+ async function handleAPIError(code) {
1313
+ if (code === 400) {
1314
+ return 'One of the options passed might be incorrect.';
1315
+ } else if (code === 403) {
1316
+ return 'You might be trying to access an organization that is not linked to the API key you are logged in with.';
1317
+ }
1318
+ }
1319
+ function getLastFiveOfApiToken(token) {
1320
+ // Get the last 5 characters of the API token before the trailing "_api".
1321
+ return token.slice(-9, -4);
1322
+ }
1323
+ async function queryAPI(path, apiToken) {
1324
+ return await fetch(`${API_V0_URL}/${path}`, {
1325
+ method: 'GET',
1326
+ headers: {
1327
+ Authorization: `Basic ${btoa(`${apiToken}:${apiToken}`)}`
1328
+ }
1329
+ });
1330
+ }
1331
+
1285
1332
  function getFlagListOutput(list, indent, {
1286
1333
  keyPrefix = '--',
1287
1334
  padName
@@ -1449,6 +1496,7 @@ function meowOrExit({
1449
1496
  if (constants.ENV[SOCKET_CLI_SHOW_BANNER]) {
1450
1497
  console.log(getAsciiHeader(command));
1451
1498
  }
1499
+
1452
1500
  // This exits if .printHelp() is called either by meow itself or by us.
1453
1501
  const cli = vendor.meow({
1454
1502
  argv,
@@ -1466,15 +1514,15 @@ function meowOrExit({
1466
1514
  }
1467
1515
  function getAsciiHeader(command) {
1468
1516
  const cliVersion = // The '@rollup/plugin-replace' will replace "process.env['SOCKET_CLI_VERSION_HASH']".
1469
- "0.14.48:61ff8dc:d16eb84e:pub";
1517
+ "0.14.50:c8e152a:9126d091:pub";
1470
1518
  const nodeVersion = process.version;
1471
- // Get the last 5 characters of the API token before the trailing "_api".
1472
- const lastFiveCharsOfApiToken = index.getSetting('apiToken')?.slice(-9, -4) || 'no';
1519
+ const apiToken = index.getSetting('apiToken');
1520
+ const shownToken = apiToken ? getLastFiveOfApiToken(apiToken) : 'no';
1473
1521
  const relCwd = process.cwd().replace(new RegExp(`^${regexps.escapeRegExp(constants.homePath)}`, 'i'), '~/');
1474
1522
  const body = `
1475
1523
  _____ _ _ /---------------
1476
1524
  | __|___ ___| |_ ___| |_ | Socket.dev CLI ver ${cliVersion}
1477
- |__ | . | _| '_| -_| _| | Node: ${nodeVersion}, API token set: ${lastFiveCharsOfApiToken}
1525
+ |__ | . | _| '_| -_| _| | Node: ${nodeVersion}, API token set: ${shownToken}
1478
1526
  |_____|___|___|_,_|___|_|.dev | Command: \`${command}\`, cwd: ${relCwd}`.trimStart();
1479
1527
  return ` ${body}\n`;
1480
1528
  }
@@ -1530,49 +1578,10 @@ async function run$z(argv, importMeta, {
1530
1578
  });
1531
1579
  const githubEventBefore = String(cli.flags['githubEventBefore'] || '');
1532
1580
  const githubEventAfter = String(cli.flags['githubEventAfter'] || '');
1533
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
1534
- await runAction(githubEventBefore, githubEventAfter);
1535
- }
1536
-
1537
- const {
1538
- API_V0_URL
1539
- } = constants;
1540
- function handleUnsuccessfulApiResponse(_name, result, spinner) {
1541
- // SocketSdkErrorType['error'] is not typed.
1542
- const resultErrorMessage = result.error?.message;
1543
- const message = typeof resultErrorMessage === 'string' ? resultErrorMessage : 'No error message returned';
1544
- if (result.status === 401 || result.status === 403) {
1545
- spinner.stop();
1546
- throw new index.AuthError(message);
1547
- }
1548
- spinner.error(`${colors.bgRed(colors.white('API returned an error:'))} ${message}`);
1549
- process$1.exit(1);
1550
- }
1551
- async function handleApiCall(value, description) {
1552
- let result;
1553
- try {
1554
- result = await value;
1555
- } catch (cause) {
1556
- throw new Error(`Failed ${description}`, {
1557
- cause
1558
- });
1559
- }
1560
- return result;
1561
- }
1562
- async function handleAPIError(code) {
1563
- if (code === 400) {
1564
- return 'One of the options passed might be incorrect.';
1565
- } else if (code === 403) {
1566
- return 'You might be trying to access an organization that is not linked to the API key you are logged in with.';
1581
+ if (cli.flags['dryRun']) {
1582
+ return console.log('[DryRun] Bailing now');
1567
1583
  }
1568
- }
1569
- async function queryAPI(path, apiToken) {
1570
- return await fetch(`${API_V0_URL}/${path}`, {
1571
- method: 'GET',
1572
- headers: {
1573
- Authorization: `Basic ${btoa(`${apiToken}:${apiToken}`)}`
1574
- }
1575
- });
1584
+ await runAction(githubEventBefore, githubEventAfter);
1576
1585
  }
1577
1586
 
1578
1587
  // Note: Widgets does not seem to actually work as code :'(
@@ -1847,7 +1856,9 @@ async function run$y(argv, importMeta, {
1847
1856
  - Repository name using --repo when scope is "repo" ${badRepo ? colors.red('(bad!)') : colors.green('(ok)')}\n`);
1848
1857
  return;
1849
1858
  }
1850
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
1859
+ if (cli.flags['dryRun']) {
1860
+ return console.log('[DryRun] Bailing now');
1861
+ }
1851
1862
  const apiToken = index.getDefaultToken();
1852
1863
  if (!apiToken) {
1853
1864
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API token.');
@@ -1975,7 +1986,9 @@ async function run$x(argv, importMeta, {
1975
1986
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}\n`);
1976
1987
  return;
1977
1988
  }
1978
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
1989
+ if (cli.flags['dryRun']) {
1990
+ return console.log('[DryRun] Bailing now');
1991
+ }
1979
1992
  const apiToken = index.getDefaultToken();
1980
1993
  if (!apiToken) {
1981
1994
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
@@ -2197,7 +2210,9 @@ async function run$w(argv, importMeta, {
2197
2210
  if (yargv.output === undefined) {
2198
2211
  yargv.output = 'socket-cdx.json';
2199
2212
  }
2200
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
2213
+ if (cli.flags['dryRun']) {
2214
+ return console.log('[DryRun] Bailing now');
2215
+ }
2201
2216
  await runCycloneDX(yargv);
2202
2217
  }
2203
2218
 
@@ -2300,7 +2315,9 @@ async function run$v(argv, importMeta, {
2300
2315
  importMeta,
2301
2316
  parentName
2302
2317
  });
2303
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
2318
+ if (cli.flags['dryRun']) {
2319
+ return console.log('[DryRun] Bailing now');
2320
+ }
2304
2321
 
2305
2322
  // TODO: markdown flag is ignored
2306
2323
  await findDependencies({
@@ -2325,7 +2342,7 @@ async function getDiffScan({
2325
2342
  const data = await response.json();
2326
2343
  if (!response.ok) {
2327
2344
  const err = await handleAPIError(response.status);
2328
- spinner$1.error(`${colors.bgRed(colors.white(response.statusText))}: ${err}`);
2345
+ spinner$1.errorAndStop(`${colors.bgRed(colors.white(response.statusText))}: ${err}`);
2329
2346
  return;
2330
2347
  }
2331
2348
  spinner$1.stop();
@@ -2422,7 +2439,9 @@ async function run$u(argv, importMeta, {
2422
2439
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}\n`);
2423
2440
  return;
2424
2441
  }
2425
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
2442
+ if (cli.flags['dryRun']) {
2443
+ return console.log('[DryRun] Bailing now');
2444
+ }
2426
2445
  const apiToken = index.getDefaultToken();
2427
2446
  if (!apiToken) {
2428
2447
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
@@ -2455,7 +2474,7 @@ const cmdDiffScan = {
2455
2474
  }
2456
2475
  };
2457
2476
 
2458
- // import { detect } from '../../utils/package-manager-detector'
2477
+ // import { detect } from '../../utils/package-environment-detector'
2459
2478
 
2460
2479
  const {
2461
2480
  NPM: NPM$d
@@ -2539,7 +2558,7 @@ async function runFix() {
2539
2558
  // eslint-disable-next-line no-await-in-loop
2540
2559
  await editablePkgJson.save();
2541
2560
  } catch {
2542
- spinner$1.error(`Reverting ${name} to ${oldVersion}`);
2561
+ spinner$1.errorAndStop(`Reverting ${name} to ${oldVersion}`);
2543
2562
  spinner$1.start();
2544
2563
  arb.idealTree = revertToIdealTree;
2545
2564
  }
@@ -2590,7 +2609,9 @@ async function run$t(argv, importMeta, {
2590
2609
  importMeta,
2591
2610
  parentName
2592
2611
  });
2593
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
2612
+ if (cli.flags['dryRun']) {
2613
+ return console.log('[DryRun] Bailing now');
2614
+ }
2594
2615
  await runFix();
2595
2616
  }
2596
2617
 
@@ -2717,7 +2738,7 @@ function formatPackageInfo({
2717
2738
  spinner[strict ? 'error' : 'success'](`Package has these issues: ${formatSeverityCount(severityCount)}`);
2718
2739
  formatPackageIssuesDetails(data, outputMarkdown);
2719
2740
  } else {
2720
- spinner.success('Package has no issues');
2741
+ spinner.successAndStop('Package has no issues');
2721
2742
  }
2722
2743
  const format = new index.ColorOrMarkdown(!!outputMarkdown);
2723
2744
  const url = index.getSocketDevPackageOverviewUrl(NPM$c, pkgName, pkgVersion);
@@ -2853,7 +2874,9 @@ async function run$s(argv, importMeta, {
2853
2874
  const versionSeparator = rawPkgName.lastIndexOf('@');
2854
2875
  const pkgName = versionSeparator < 1 ? rawPkgName : rawPkgName.slice(0, versionSeparator);
2855
2876
  const pkgVersion = versionSeparator < 1 ? 'latest' : rawPkgName.slice(versionSeparator + 1);
2856
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
2877
+ if (cli.flags['dryRun']) {
2878
+ return console.log('[DryRun] Bailing now');
2879
+ }
2857
2880
  await getPackageInfo({
2858
2881
  commandName: `${parentName} ${config$s.commandName}`,
2859
2882
  includeAllIssues: Boolean(cli.flags['all']),
@@ -2896,7 +2919,7 @@ async function attemptLogin(apiBaseUrl, apiProxy) {
2896
2919
  orgs = result.data;
2897
2920
  spinner$1.success('API key verified');
2898
2921
  } catch {
2899
- spinner$1.error('Invalid API key');
2922
+ spinner$1.errorAndStop('Invalid API key');
2900
2923
  return;
2901
2924
  }
2902
2925
  const enforcedChoices = Object.values(orgs.organizations).filter(org => org?.plan === 'enterprise').map(org => ({
@@ -2931,9 +2954,9 @@ async function attemptLogin(apiBaseUrl, apiProxy) {
2931
2954
  const oldToken = index.getSetting('apiToken');
2932
2955
  try {
2933
2956
  applyLogin(apiToken, enforcedOrgs, apiBaseUrl, apiProxy);
2934
- spinner$1.success(`API credentials ${oldToken ? 'updated' : 'set'}`);
2957
+ spinner$1.successAndStop(`API credentials ${oldToken ? 'updated' : 'set'}`);
2935
2958
  } catch {
2936
- spinner$1.error(`API login failed`);
2959
+ spinner$1.errorAndStop(`API login failed`);
2937
2960
  }
2938
2961
  }
2939
2962
 
@@ -2982,7 +3005,9 @@ async function run$r(argv, importMeta, {
2982
3005
  });
2983
3006
  let apiBaseUrl = cli.flags['apiBaseUrl'];
2984
3007
  let apiProxy = cli.flags['apiProxy'];
2985
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3008
+ if (cli.flags['dryRun']) {
3009
+ return console.log('[DryRun] Bailing now');
3010
+ }
2986
3011
  if (!isInteractive()) {
2987
3012
  throw new index.InputError('Cannot prompt for credentials in a non-interactive shell');
2988
3013
  }
@@ -3033,7 +3058,9 @@ async function run$q(argv, importMeta, {
3033
3058
  importMeta,
3034
3059
  parentName
3035
3060
  });
3036
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3061
+ if (cli.flags['dryRun']) {
3062
+ return console.log('[DryRun] Bailing now');
3063
+ }
3037
3064
  attemptLogout();
3038
3065
  }
3039
3066
 
@@ -3071,14 +3098,14 @@ async function convertGradleToMaven(target, bin, _out, verbose, gradleOpts) {
3071
3098
  const output = await spawn(bin, commandArgs, {
3072
3099
  cwd: target || '.'
3073
3100
  });
3074
- spinner$1.success();
3101
+ spinner$1.stop();
3075
3102
  if (verbose) {
3076
3103
  console.group('[VERBOSE] gradle stdout:');
3077
3104
  console.log(output);
3078
3105
  console.groupEnd();
3079
3106
  }
3080
3107
  if (output.stderr) {
3081
- spinner$1.error('There were errors while running gradle');
3108
+ spinner$1.errorAndStop('There were errors while running gradle');
3082
3109
  // (In verbose mode, stderr was printed above, no need to repeat it)
3083
3110
  if (!verbose) {
3084
3111
  console.group('[VERBOSE] stderr:');
@@ -3087,6 +3114,8 @@ async function convertGradleToMaven(target, bin, _out, verbose, gradleOpts) {
3087
3114
  }
3088
3115
  process.exit(1);
3089
3116
  }
3117
+ spinner$1.start();
3118
+ spinner$1.successAndStop('Executed gradle successfully');
3090
3119
  console.log('Reported exports:');
3091
3120
  output.stdout.replace(/^POM file copied to: (.*)/gm, (_all, fn) => {
3092
3121
  console.log('- ', fn);
@@ -3095,7 +3124,7 @@ async function convertGradleToMaven(target, bin, _out, verbose, gradleOpts) {
3095
3124
 
3096
3125
  // const loc = output.stdout?.match(/Wrote (.*?.pom)\n/)?.[1]?.trim()
3097
3126
  // if (!loc) {
3098
- // spinner.error(
3127
+ // spinner.errorAndStop(
3099
3128
  // 'There were no errors from sbt but could not find the location of resulting .pom file either'
3100
3129
  // )
3101
3130
  // process.exit(1)
@@ -3117,11 +3146,11 @@ async function convertGradleToMaven(target, bin, _out, verbose, gradleOpts) {
3117
3146
  // }
3118
3147
  // // TODO: do we prefer fs-extra? renaming can be gnarly on windows and fs-extra's version is better
3119
3148
  // await renamep(loc, out)
3120
- // spinner.success()
3149
+ // spinner.successAndStop()
3121
3150
  // spinner.start().success(`OK. File should be available in \`${out}\``)
3122
3151
  // }
3123
3152
  } catch (e) {
3124
- spinner$1.error('There was an unexpected error while running this' + (verbose ? '' : ' (use --verbose for details)'));
3153
+ spinner$1.errorAndStop('There was an unexpected error while running this' + (verbose ? '' : ' (use --verbose for details)'));
3125
3154
  if (verbose) {
3126
3155
  console.group('[VERBOSE] error:');
3127
3156
  console.log(e);
@@ -3262,7 +3291,9 @@ async function run$p(argv, importMeta, {
3262
3291
  if (cli.flags['gradleOpts']) {
3263
3292
  gradleOpts = cli.flags['gradleOpts'].split(' ').map(s => s.trim()).filter(Boolean);
3264
3293
  }
3265
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3294
+ if (cli.flags['dryRun']) {
3295
+ return console.log('[DryRun] Bailing now');
3296
+ }
3266
3297
  await convertGradleToMaven(target, bin, out, verbose, gradleOpts);
3267
3298
  }
3268
3299
 
@@ -3294,14 +3325,15 @@ async function convertSbtToMaven(target, bin, out, verbose, sbtOpts) {
3294
3325
  const output = await spawn(bin, ['makePom'].concat(sbtOpts), {
3295
3326
  cwd: target || '.'
3296
3327
  });
3297
- spinner$1.success();
3328
+ spinner$1.successAndStop();
3298
3329
  if (verbose) {
3299
3330
  console.group('[VERBOSE] sbt stdout:');
3300
3331
  console.log(output);
3301
3332
  console.groupEnd();
3302
3333
  }
3303
3334
  if (output.stderr) {
3304
- spinner$1.error('There were errors while running sbt');
3335
+ spinner$1.start();
3336
+ spinner$1.errorAndStop('There were errors while running sbt');
3305
3337
  // (In verbose mode, stderr was printed above, no need to repeat it)
3306
3338
  if (!verbose) {
3307
3339
  console.group('[VERBOSE] stderr:');
@@ -3316,7 +3348,7 @@ async function convertSbtToMaven(target, bin, out, verbose, sbtOpts) {
3316
3348
  return fn;
3317
3349
  });
3318
3350
  if (!poms.length) {
3319
- spinner$1.error('There were no errors from sbt but it seems to not have generated any poms either');
3351
+ spinner$1.errorAndStop('There were no errors from sbt but it seems to not have generated any poms either');
3320
3352
  process.exit(1);
3321
3353
  }
3322
3354
 
@@ -3348,7 +3380,7 @@ async function convertSbtToMaven(target, bin, out, verbose, sbtOpts) {
3348
3380
  spinner$1.start().success(`OK`);
3349
3381
  }
3350
3382
  } catch (e) {
3351
- spinner$1.error('There was an unexpected error while running this' + (verbose ? '' : ' (use --verbose for details)'));
3383
+ spinner$1.errorAndStop('There was an unexpected error while running this' + (verbose ? '' : ' (use --verbose for details)'));
3352
3384
  if (verbose) {
3353
3385
  console.group('[VERBOSE] error:');
3354
3386
  console.log(e);
@@ -3486,7 +3518,9 @@ async function run$o(argv, importMeta, {
3486
3518
  if (cli.flags['sbtOpts']) {
3487
3519
  sbtOpts = cli.flags['sbtOpts'].split(' ').map(s => s.trim()).filter(Boolean);
3488
3520
  }
3489
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3521
+ if (cli.flags['dryRun']) {
3522
+ return console.log('[DryRun] Bailing now');
3523
+ }
3490
3524
  await convertSbtToMaven(target, bin, out, verbose, sbtOpts);
3491
3525
  }
3492
3526
 
@@ -3554,7 +3588,9 @@ async function run$n(argv, importMeta, {
3554
3588
  subArgs.push('--cwd', cwd);
3555
3589
  }
3556
3590
  subArgs.push(dir);
3557
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3591
+ if (cli.flags['dryRun']) {
3592
+ return console.log('[DryRun] Bailing now');
3593
+ }
3558
3594
  await cmdManifestScala.run(subArgs, importMeta, {
3559
3595
  parentName
3560
3596
  });
@@ -3566,7 +3602,9 @@ async function run$n(argv, importMeta, {
3566
3602
  // This command takes the cwd as first arg.
3567
3603
  subArgs.push(cwd);
3568
3604
  }
3569
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3605
+ if (cli.flags['dryRun']) {
3606
+ return console.log('[DryRun] Bailing now');
3607
+ }
3570
3608
  await cmdManifestGradle.run(subArgs, importMeta, {
3571
3609
  parentName
3572
3610
  });
@@ -3729,7 +3767,9 @@ async function run$m(argv, importMeta, {
3729
3767
  if (cli.flags['gradleOpts']) {
3730
3768
  gradleOpts = cli.flags['gradleOpts'].split(' ').map(s => s.trim()).filter(Boolean);
3731
3769
  }
3732
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3770
+ if (cli.flags['dryRun']) {
3771
+ return console.log('[DryRun] Bailing now');
3772
+ }
3733
3773
  await convertGradleToMaven(target, bin, out, verbose, gradleOpts);
3734
3774
  }
3735
3775
 
@@ -3807,7 +3847,9 @@ async function run$k(argv, importMeta, {
3807
3847
  importMeta,
3808
3848
  parentName
3809
3849
  });
3810
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3850
+ if (cli.flags['dryRun']) {
3851
+ return console.log('[DryRun] Bailing now');
3852
+ }
3811
3853
  await wrapNpm(argv);
3812
3854
  }
3813
3855
 
@@ -3849,7 +3891,9 @@ async function run$j(argv, importMeta, {
3849
3891
  importMeta,
3850
3892
  parentName
3851
3893
  });
3852
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3894
+ if (cli.flags['dryRun']) {
3895
+ return console.log('[DryRun] Bailing now');
3896
+ }
3853
3897
  await wrapNpx(argv);
3854
3898
  }
3855
3899
 
@@ -3881,7 +3925,9 @@ async function run$i(argv, importMeta, {
3881
3925
  importMeta,
3882
3926
  parentName
3883
3927
  });
3884
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3928
+ if (cli.flags['dryRun']) {
3929
+ return console.log('[DryRun] Bailing now');
3930
+ }
3885
3931
  throw new Error('This error was intentionally left blank');
3886
3932
  }
3887
3933
 
@@ -3899,16 +3945,7 @@ function matchHumanStdout(stdout, name) {
3899
3945
  function matchQueryStdout(stdout, name) {
3900
3946
  return stdout.includes(`"${name}"`);
3901
3947
  }
3902
- const depsIncludesByAgent = {
3903
- // @ts-ignore
3904
- __proto__: null,
3905
- [BUN$6]: matchHumanStdout,
3906
- [NPM$9]: matchQueryStdout,
3907
- [PNPM$7]: matchQueryStdout,
3908
- [VLT$6]: matchQueryStdout,
3909
- [YARN_BERRY$6]: matchHumanStdout,
3910
- [YARN_CLASSIC$6]: matchHumanStdout
3911
- };
3948
+ const depsIncludesByAgent = new Map([[BUN$6, matchHumanStdout], [NPM$9, matchQueryStdout], [PNPM$7, matchQueryStdout], [VLT$6, matchQueryStdout], [YARN_BERRY$6, matchHumanStdout], [YARN_CLASSIC$6, matchHumanStdout]]);
3912
3949
 
3913
3950
  const {
3914
3951
  BINARY_LOCK_EXT,
@@ -4008,15 +4045,15 @@ const readLockFileByAgent = (() => {
4008
4045
  [YARN_CLASSIC$5]: defaultReader
4009
4046
  };
4010
4047
  })();
4011
- async function detect({
4048
+ async function detectPackageEnvironment({
4012
4049
  cwd = process$1.cwd(),
4013
4050
  onUnknown
4014
4051
  } = {}) {
4015
4052
  let lockPath = await index.findUp(Object.keys(LOCKS), {
4016
4053
  cwd
4017
4054
  });
4018
- let lockBasename = lockPath ? path.basename(lockPath) : undefined;
4019
- const isHiddenLockFile = lockBasename === '.package-lock.json';
4055
+ let lockName = lockPath ? path.basename(lockPath) : undefined;
4056
+ const isHiddenLockFile = lockName === '.package-lock.json';
4020
4057
  const pkgJsonPath = lockPath ? path.resolve(lockPath, `${isHiddenLockFile ? '../' : ''}../package.json`) : await index.findUp('package.json', {
4021
4058
  cwd
4022
4059
  });
@@ -4041,8 +4078,8 @@ async function detect({
4041
4078
  }
4042
4079
  }
4043
4080
  }
4044
- if (agent === undefined && !isHiddenLockFile && typeof pkgJsonPath === 'string' && typeof lockBasename === 'string') {
4045
- agent = LOCKS[lockBasename];
4081
+ if (agent === undefined && !isHiddenLockFile && typeof pkgJsonPath === 'string' && typeof lockName === 'string') {
4082
+ agent = LOCKS[lockName];
4046
4083
  }
4047
4084
  if (agent === undefined) {
4048
4085
  agent = NPM$8;
@@ -4093,14 +4130,14 @@ async function detect({
4093
4130
  targets.node = constants.maintainedNodeVersions.some(v => semver.satisfies(v, `>=${minimumNodeVersion}`));
4094
4131
  lockSrc = typeof lockPath === 'string' ? await readLockFileByAgent[agent](lockPath, agentExecPath) : undefined;
4095
4132
  } else {
4096
- lockBasename = undefined;
4133
+ lockName = undefined;
4097
4134
  lockPath = undefined;
4098
4135
  }
4099
4136
  return {
4100
4137
  agent,
4101
4138
  agentExecPath,
4102
4139
  agentVersion,
4103
- lockBasename,
4140
+ lockName,
4104
4141
  lockPath,
4105
4142
  lockSrc,
4106
4143
  minimumNodeVersion,
@@ -4114,74 +4151,53 @@ async function detect({
4114
4151
 
4115
4152
  const {
4116
4153
  BUN: BUN$4,
4117
- NPM: NPM$7,
4118
4154
  VLT: VLT$4,
4119
4155
  YARN_BERRY: YARN_BERRY$4
4120
4156
  } = constants;
4121
4157
  const COMMAND_TITLE$2 = 'Socket Optimize';
4122
- const manifestNpmOverrides = registry.getManifestData(NPM$7);
4123
- async function detectAndValidatePackageManager(cwd, prod) {
4158
+ async function detectAndValidatePackageEnvironment(cwd, options) {
4124
4159
  const {
4125
- agent,
4126
- agentExecPath,
4127
- agentVersion,
4128
- lockBasename,
4129
- lockPath,
4130
- lockSrc,
4131
- minimumNodeVersion,
4132
- npmExecPath,
4133
- pkgJson,
4134
- pkgPath,
4135
- supported
4136
- } = await detect({
4160
+ logger,
4161
+ prod
4162
+ } = {
4163
+ __proto__: null,
4164
+ ...options
4165
+ };
4166
+ const details = await detectPackageEnvironment({
4137
4167
  cwd,
4138
4168
  onUnknown(pkgManager) {
4139
- console.warn(`⚠️ ${COMMAND_TITLE$2}: Unknown package manager${pkgManager ? ` ${pkgManager}` : ''}, defaulting to npm`);
4169
+ logger?.warn(`⚠️ ${COMMAND_TITLE$2}: Unknown package manager${pkgManager ? ` ${pkgManager}` : ''}, defaulting to npm`);
4140
4170
  }
4141
4171
  });
4142
- if (!supported) {
4143
- console.error(`✖️ ${COMMAND_TITLE$2}: No supported Node or browser range detected`);
4172
+ if (!details.supported) {
4173
+ logger?.error(`✖️ ${COMMAND_TITLE$2}: No supported Node or browser range detected`);
4144
4174
  return;
4145
4175
  }
4146
- if (agent === VLT$4) {
4147
- console.error(`✖️ ${COMMAND_TITLE$2}: ${agent} does not support overrides. Soon, though ⚡`);
4176
+ if (details.agent === VLT$4) {
4177
+ logger?.error(`✖️ ${COMMAND_TITLE$2}: ${details.agent} does not support overrides. Soon, though ⚡`);
4148
4178
  return;
4149
4179
  }
4150
- const lockName = lockPath && lockBasename ? lockBasename : 'lock file';
4151
- if (lockBasename === undefined || lockSrc === undefined) {
4152
- console.error(`✖️ ${COMMAND_TITLE$2}: No ${lockName} found`);
4180
+ const lockName = details.lockName ?? 'lock file';
4181
+ if (details.lockName === undefined || details.lockSrc === undefined) {
4182
+ logger?.error(`✖️ ${COMMAND_TITLE$2}: No ${lockName} found`);
4153
4183
  return;
4154
4184
  }
4155
- if (lockSrc.trim() === '') {
4156
- console.error(`✖️ ${COMMAND_TITLE$2}: ${lockName} is empty`);
4185
+ if (details.lockSrc.trim() === '') {
4186
+ logger?.error(`✖️ ${COMMAND_TITLE$2}: ${lockName} is empty`);
4157
4187
  return;
4158
4188
  }
4159
- if (pkgPath === undefined) {
4160
- console.error(`✖️ ${COMMAND_TITLE$2}: No package.json found`);
4189
+ if (details.pkgPath === undefined) {
4190
+ logger?.error(`✖️ ${COMMAND_TITLE$2}: No package.json found`);
4161
4191
  return;
4162
4192
  }
4163
- if (prod && (agent === BUN$4 || agent === YARN_BERRY$4)) {
4164
- console.error(`✖️ ${COMMAND_TITLE$2}: --prod not supported for ${agent}${agentVersion ? `@${agentVersion.toString()}` : ''}`);
4193
+ if (prod && (details.agent === BUN$4 || details.agent === YARN_BERRY$4)) {
4194
+ logger?.error(`✖️ ${COMMAND_TITLE$2}: --prod not supported for ${details.agent}${details.agentVersion ? `@${details.agentVersion.toString()}` : ''}`);
4165
4195
  return;
4166
4196
  }
4167
- if (lockPath && path.relative(cwd, lockPath).startsWith('.')) {
4168
- console.warn(`⚠️ ${COMMAND_TITLE$2}: Package ${lockName} found at ${lockPath}`);
4197
+ if (details.lockPath && path.relative(cwd, details.lockPath).startsWith('.')) {
4198
+ logger?.warn(`⚠️ ${COMMAND_TITLE$2}: Package ${lockName} found at ${details.lockPath}`);
4169
4199
  }
4170
- const nodeRange = `>=${minimumNodeVersion}`;
4171
- const manifestEntries = manifestNpmOverrides.filter(({
4172
- 1: data
4173
- }) => semver.satisfies(semver.coerce(data.engines.node), nodeRange));
4174
- return {
4175
- agent,
4176
- agentExecPath,
4177
- lockBasename,
4178
- lockName,
4179
- lockSrc,
4180
- manifestEntries,
4181
- npmExecPath,
4182
- pkgJson,
4183
- pkgPath
4184
- };
4200
+ return details;
4185
4201
  }
4186
4202
 
4187
4203
  function getDependencyEntries(pkgJson) {
@@ -4210,7 +4226,7 @@ function getDependencyEntries(pkgJson) {
4210
4226
 
4211
4227
  const {
4212
4228
  BUN: BUN$3,
4213
- NPM: NPM$6,
4229
+ NPM: NPM$7,
4214
4230
  OVERRIDES: OVERRIDES$1,
4215
4231
  PNPM: PNPM$5,
4216
4232
  RESOLUTIONS: RESOLUTIONS$1,
@@ -4231,7 +4247,7 @@ function getOverridesDataBun(pkgJson) {
4231
4247
  function getOverridesDataNpm(pkgJson) {
4232
4248
  const overrides = pkgJson?.[OVERRIDES$1] ?? {};
4233
4249
  return {
4234
- type: NPM$6,
4250
+ type: NPM$7,
4235
4251
  overrides
4236
4252
  };
4237
4253
  }
@@ -4272,16 +4288,7 @@ function getOverridesDataClassic(pkgJson) {
4272
4288
  overrides
4273
4289
  };
4274
4290
  }
4275
- const getOverridesDataByAgent = {
4276
- // @ts-ignore
4277
- __proto__: null,
4278
- [BUN$3]: getOverridesDataBun,
4279
- [NPM$6]: getOverridesDataNpm,
4280
- [PNPM$5]: getOverridesDataPnpm,
4281
- [VLT$3]: getOverridesDataVlt,
4282
- [YARN_BERRY$3]: getOverridesDataYarn,
4283
- [YARN_CLASSIC$4]: getOverridesDataClassic
4284
- };
4291
+ const overridesDataByAgent = new Map([[BUN$3, getOverridesDataBun], [NPM$7, getOverridesDataNpm], [PNPM$5, getOverridesDataPnpm], [VLT$3, getOverridesDataVlt], [YARN_BERRY$3, getOverridesDataYarn], [YARN_CLASSIC$4, getOverridesDataClassic]]);
4285
4292
 
4286
4293
  const {
4287
4294
  PNPM: PNPM$4
@@ -4329,7 +4336,7 @@ function workspacePatternToGlobPattern(workspace) {
4329
4336
  const {
4330
4337
  BUN: BUN$2,
4331
4338
  LOCK_EXT,
4332
- NPM: NPM$5,
4339
+ NPM: NPM$6,
4333
4340
  PNPM: PNPM$3,
4334
4341
  VLT: VLT$2,
4335
4342
  YARN_BERRY: YARN_BERRY$2,
@@ -4340,12 +4347,12 @@ function lockIncludesNpm(lockSrc, name) {
4340
4347
  // "name":
4341
4348
  return lockSrc.includes(`"${name}":`);
4342
4349
  }
4343
- function lockIncludesBun(lockSrc, name, lockBasename) {
4344
- // This is a bit counterintuitive. When lockBasename ends with a .lockb
4345
- // we treat it as a yarn.lock. When lockBasename ends with a .lock we
4350
+ function lockIncludesBun(lockSrc, name, lockName) {
4351
+ // This is a bit counterintuitive. When lockName ends with a .lockb
4352
+ // we treat it as a yarn.lock. When lockName ends with a .lock we
4346
4353
  // treat it as a package-lock.json. The bun.lock format is not identical
4347
4354
  // package-lock.json, however it close enough for npmLockIncludes to work.
4348
- const lockScanner = lockBasename?.endsWith(LOCK_EXT) ? lockIncludesNpm : lockIncludesYarn;
4355
+ const lockScanner = lockName?.endsWith(LOCK_EXT) ? lockIncludesNpm : lockIncludesYarn;
4349
4356
  return lockScanner(lockSrc, name);
4350
4357
  }
4351
4358
  function lockIncludesPnpm(lockSrc, name) {
@@ -4373,20 +4380,11 @@ function lockIncludesYarn(lockSrc, name) {
4373
4380
  // , name@
4374
4381
  `(?<=(?:^\\s*|,\\s*)"?)${escapedName}(?=@)`, 'm').test(lockSrc);
4375
4382
  }
4376
- const lockIncludesByAgent = {
4377
- // @ts-ignore
4378
- __proto__: null,
4379
- [BUN$2]: lockIncludesBun,
4380
- [NPM$5]: lockIncludesNpm,
4381
- [PNPM$3]: lockIncludesPnpm,
4382
- [VLT$2]: lockIncludesVlt,
4383
- [YARN_BERRY$2]: lockIncludesYarn,
4384
- [YARN_CLASSIC$3]: lockIncludesYarn
4385
- };
4383
+ const lockIncludesByAgent = new Map([[BUN$2, lockIncludesBun], [NPM$6, lockIncludesNpm], [PNPM$3, lockIncludesPnpm], [VLT$2, lockIncludesVlt], [YARN_BERRY$2, lockIncludesYarn], [YARN_CLASSIC$3, lockIncludesYarn]]);
4386
4384
 
4387
4385
  const {
4388
4386
  BUN: BUN$1,
4389
- NPM: NPM$4,
4387
+ NPM: NPM$5,
4390
4388
  PNPM: PNPM$2,
4391
4389
  VLT: VLT$1,
4392
4390
  YARN_BERRY: YARN_BERRY$1,
@@ -4456,7 +4454,7 @@ async function lsNpm(agentExecPath, cwd) {
4456
4454
  }
4457
4455
  async function lsPnpm(agentExecPath, cwd, options) {
4458
4456
  const npmExecPath = options?.npmExecPath;
4459
- if (npmExecPath && npmExecPath !== NPM$4) {
4457
+ if (npmExecPath && npmExecPath !== NPM$5) {
4460
4458
  const result = await npmQuery(npmExecPath, cwd);
4461
4459
  if (result) {
4462
4460
  return result;
@@ -4507,7 +4505,7 @@ const lsByAgent = {
4507
4505
  // @ts-ignore
4508
4506
  __proto__: null,
4509
4507
  [BUN$1]: lsBun,
4510
- [NPM$4]: lsNpm,
4508
+ [NPM$5]: lsNpm,
4511
4509
  [PNPM$2]: lsPnpm,
4512
4510
  [VLT$1]: lsVlt,
4513
4511
  [YARN_BERRY$1]: lsYarnBerry,
@@ -4516,7 +4514,7 @@ const lsByAgent = {
4516
4514
 
4517
4515
  const {
4518
4516
  BUN,
4519
- NPM: NPM$3,
4517
+ NPM: NPM$4,
4520
4518
  OVERRIDES,
4521
4519
  PNPM: PNPM$1,
4522
4520
  RESOLUTIONS,
@@ -4620,55 +4618,75 @@ function updateResolutions(editablePkgJson, overrides) {
4620
4618
  function pnpmUpdatePkgJson(editablePkgJson, overrides) {
4621
4619
  updatePkgJson(editablePkgJson, PNPM_FIELD_NAME, overrides);
4622
4620
  }
4623
- const updateManifestByAgent = {
4624
- // @ts-ignore
4625
- __proto__: null,
4626
- [BUN]: updateResolutions,
4627
- [NPM$3]: updateOverrides,
4628
- [PNPM$1]: pnpmUpdatePkgJson,
4629
- [VLT]: updateOverrides,
4630
- [YARN_BERRY]: updateResolutions,
4631
- [YARN_CLASSIC$1]: updateResolutions
4632
- };
4621
+ const updateManifestByAgent = new Map([[BUN, updateResolutions], [NPM$4, updateOverrides], [PNPM$1, pnpmUpdatePkgJson], [VLT, updateOverrides], [YARN_BERRY, updateResolutions], [YARN_CLASSIC$1, updateResolutions]]);
4633
4622
 
4634
4623
  const {
4635
- NPM: NPM$2,
4636
- SOCKET_CLI_SAFE_WRAPPER,
4624
+ NPM: NPM$3,
4637
4625
  abortSignal: abortSignal$2
4638
4626
  } = constants;
4627
+ function runAgentInstall(agent, agentExecPath, options) {
4628
+ // All package managers support the "install" command.
4629
+ if (agent === NPM$3) {
4630
+ return npm$1.safeNpmInstall(options);
4631
+ }
4632
+ const {
4633
+ args = [],
4634
+ spinner,
4635
+ ...spawnOptions
4636
+ } = {
4637
+ __proto__: null,
4638
+ ...options
4639
+ };
4640
+ const isSilent = !npmPaths.isDebug();
4641
+ const isSpinning = spinner?.isSpinning ?? false;
4642
+ if (!isSilent) {
4643
+ spinner?.stop();
4644
+ }
4645
+ let spawnPromise = spawn(agentExecPath, ['install', ...args], {
4646
+ signal: abortSignal$2,
4647
+ stdio: isSilent ? 'ignore' : 'inherit',
4648
+ ...spawnOptions,
4649
+ env: {
4650
+ ...process.env,
4651
+ ...spawnOptions.env
4652
+ }
4653
+ });
4654
+ if (!isSilent && isSpinning) {
4655
+ const oldSpawnPromise = spawnPromise;
4656
+ spawnPromise = spawnPromise.finally(() => {
4657
+ spinner?.start();
4658
+ });
4659
+ spawnPromise.process = oldSpawnPromise.process;
4660
+ spawnPromise.stdin = spawnPromise.stdin;
4661
+ }
4662
+ return spawnPromise;
4663
+ }
4664
+
4665
+ const {
4666
+ NPM: NPM$2
4667
+ } = constants;
4639
4668
  const COMMAND_TITLE$1 = 'Socket Optimize';
4640
4669
  const NPM_OVERRIDE_PR_URL = 'https://github.com/npm/cli/pull/8089';
4641
- async function updatePackageLockJson(lockName, agentExecPath, agent, spinner) {
4642
- spinner.start(`Updating ${lockName}...`);
4670
+ async function updatePackageLockJson(pkgEnvDetails, options) {
4671
+ const {
4672
+ logger,
4673
+ spinner
4674
+ } = {
4675
+ __proto__: null,
4676
+ ...options
4677
+ };
4678
+ spinner?.start(`Updating ${pkgEnvDetails.lockName}...`);
4643
4679
  try {
4644
- if (agent === NPM$2) {
4645
- const ipc = {
4646
- [SOCKET_CLI_SAFE_WRAPPER]: true
4647
- };
4648
- await npm$1.safeNpmInstall({
4649
- ipc
4650
- });
4651
- // TODO: This is a temporary workaround for a `npm ci` bug where it
4652
- // will error out after Socket Optimize generates a lock file.
4653
- // More investigation is needed.
4654
- await npm$1.safeNpmInstall({
4655
- args: ['--ignore-scripts', '--package-lock-only'],
4656
- ipc
4657
- });
4658
- } else {
4659
- // All package managers support the "install" command.
4660
- await spawn(agentExecPath, ['install'], {
4661
- signal: abortSignal$2,
4662
- stdio: 'ignore'
4663
- });
4664
- }
4665
- spinner.stop();
4666
- if (agent === NPM$2) {
4667
- console.log(`💡 Re-run ${COMMAND_TITLE$1} whenever ${lockName} changes.\n This can be skipped once npm ships ${NPM_OVERRIDE_PR_URL}.`);
4680
+ await runAgentInstall(pkgEnvDetails.agent, pkgEnvDetails.agentExecPath, {
4681
+ spinner
4682
+ });
4683
+ spinner?.stop();
4684
+ if (pkgEnvDetails.agent === NPM$2) {
4685
+ logger?.log(`💡 Re-run ${COMMAND_TITLE$1} whenever ${pkgEnvDetails.lockName} changes.\n This can be skipped once npm ships ${NPM_OVERRIDE_PR_URL}.`);
4668
4686
  }
4669
4687
  } catch (e) {
4670
- spinner.error(`${COMMAND_TITLE$1}: ${agent} install failed to update ${lockName}`);
4671
- console.error(e);
4688
+ spinner?.error(`${COMMAND_TITLE$1}: ${pkgEnvDetails.agent} install failed to update ${pkgEnvDetails.lockName}`);
4689
+ logger?.error(e);
4672
4690
  }
4673
4691
  }
4674
4692
 
@@ -4678,91 +4696,85 @@ const {
4678
4696
  YARN_CLASSIC
4679
4697
  } = constants;
4680
4698
  const COMMAND_TITLE = 'Socket Optimize';
4699
+ const manifestNpmOverrides = registry.getManifestData(NPM$1);
4681
4700
  async function applyOptimization(cwd, pin, prod) {
4682
- const pkgMgrData = await detectAndValidatePackageManager(cwd, prod);
4683
- if (!pkgMgrData) return;
4684
- const {
4685
- agent,
4686
- agentExecPath,
4687
- lockBasename,
4688
- lockName,
4689
- lockSrc,
4690
- manifestEntries,
4691
- npmExecPath,
4692
- pkgJson,
4693
- pkgPath
4694
- } = pkgMgrData;
4701
+ const logger = console;
4702
+ const pkgEnvDetails = await detectAndValidatePackageEnvironment(cwd, {
4703
+ logger,
4704
+ prod
4705
+ });
4706
+ if (!pkgEnvDetails) {
4707
+ return;
4708
+ }
4695
4709
  const spinner$1 = new spinner.Spinner({
4696
4710
  text: 'Socket optimizing...'
4697
4711
  });
4698
4712
  spinner$1.start();
4699
- const state = await addOverrides({
4700
- agent,
4701
- agentExecPath,
4702
- lockBasename,
4703
- lockSrc,
4704
- manifestEntries,
4705
- npmExecPath,
4713
+ const state = await addOverrides(pkgEnvDetails.pkgPath, pkgEnvDetails, {
4714
+ logger,
4706
4715
  pin,
4707
- pkgJson,
4708
- pkgPath,
4709
4716
  prod,
4710
- rootPath: pkgPath
4711
- }, createAddOverridesState(spinner$1));
4717
+ spinner: spinner$1
4718
+ });
4712
4719
  spinner$1.stop();
4713
4720
  const addedCount = state.added.size;
4714
4721
  const updatedCount = state.updated.size;
4715
4722
  const pkgJsonChanged = addedCount > 0 || updatedCount > 0;
4716
4723
  if (pkgJsonChanged) {
4717
4724
  if (updatedCount > 0) {
4718
- console.log(`${createActionMessage('Updated', updatedCount, state.updatedInWorkspaces.size)}${addedCount ? '.' : '🚀'}`);
4725
+ logger?.log(`${createActionMessage('Updated', updatedCount, state.updatedInWorkspaces.size)}${addedCount ? '.' : '🚀'}`);
4719
4726
  }
4720
4727
  if (addedCount > 0) {
4721
- console.log(`${createActionMessage('Added', addedCount, state.addedInWorkspaces.size)} 🚀`);
4728
+ logger?.log(`${createActionMessage('Added', addedCount, state.addedInWorkspaces.size)} 🚀`);
4722
4729
  }
4723
4730
  } else {
4724
- console.log('Congratulations! Already Socket.dev optimized 🎉');
4731
+ logger?.log('Congratulations! Already Socket.dev optimized 🎉');
4725
4732
  }
4726
- if (agent === NPM$1 || pkgJsonChanged) {
4733
+ if (pkgEnvDetails.agent === NPM$1 || pkgJsonChanged) {
4727
4734
  // Always update package-lock.json until the npm overrides PR lands:
4728
4735
  // https://github.com/npm/cli/pull/8089
4729
- await updatePackageLockJson(lockName, agentExecPath, agent, spinner$1);
4736
+ await updatePackageLockJson(pkgEnvDetails, {
4737
+ logger,
4738
+ spinner: spinner$1
4739
+ });
4730
4740
  }
4731
4741
  }
4732
4742
  function createActionMessage(verb, overrideCount, workspaceCount) {
4733
4743
  return `${verb} ${overrideCount} Socket.dev optimized ${words.pluralize('override', overrideCount)}${workspaceCount ? ` in ${workspaceCount} ${words.pluralize('workspace', workspaceCount)}` : ''}`;
4734
4744
  }
4735
- function createAddOverridesState(spinner) {
4736
- return {
4737
- added: new Set(),
4738
- addedInWorkspaces: new Set(),
4745
+ async function addOverrides(pkgPath, pkgEnvDetails, options) {
4746
+ const {
4747
+ agent,
4748
+ agentExecPath,
4749
+ lockName,
4750
+ lockSrc,
4751
+ npmExecPath,
4752
+ pkgPath: rootPath
4753
+ } = pkgEnvDetails;
4754
+ const {
4755
+ logger,
4756
+ pin,
4757
+ prod,
4739
4758
  spinner,
4740
- updated: new Set(),
4741
- updatedInWorkspaces: new Set(),
4742
- warnedPnpmWorkspaceRequiresNpm: false
4759
+ state = {
4760
+ added: new Set(),
4761
+ addedInWorkspaces: new Set(),
4762
+ updated: new Set(),
4763
+ updatedInWorkspaces: new Set(),
4764
+ warnedPnpmWorkspaceRequiresNpm: false
4765
+ }
4766
+ } = {
4767
+ __proto__: null,
4768
+ ...options
4743
4769
  };
4744
- }
4745
- async function addOverrides({
4746
- agent,
4747
- agentExecPath,
4748
- lockBasename,
4749
- lockSrc,
4750
- manifestEntries,
4751
- npmExecPath,
4752
- pin,
4753
- pkgJson: editablePkgJson,
4754
- pkgPath,
4755
- prod,
4756
- rootPath
4757
- }, state) {
4770
+ let {
4771
+ pkgJson: editablePkgJson
4772
+ } = pkgEnvDetails;
4758
4773
  if (editablePkgJson === undefined) {
4759
4774
  editablePkgJson = await packages.readPackageJson(pkgPath, {
4760
4775
  editable: true
4761
4776
  });
4762
4777
  }
4763
- const {
4764
- spinner
4765
- } = state;
4766
4778
  const {
4767
4779
  content: pkgJson
4768
4780
  } = editablePkgJson;
@@ -4773,7 +4785,7 @@ async function addOverrides({
4773
4785
  const isWorkspace = !!workspaceGlobs;
4774
4786
  if (isWorkspace && agent === PNPM && npmExecPath === NPM$1 && !state.warnedPnpmWorkspaceRequiresNpm) {
4775
4787
  state.warnedPnpmWorkspaceRequiresNpm = true;
4776
- console.warn(`⚠️ ${COMMAND_TITLE}: pnpm workspace support requires \`npm ls\`, falling back to \`pnpm list\``);
4788
+ logger?.warn(`⚠️ ${COMMAND_TITLE}: pnpm workspace support requires \`npm ls\`, falling back to \`pnpm list\``);
4777
4789
  }
4778
4790
  const thingToScan = isLockScanned ? lockSrc : await lsByAgent[agent](agentExecPath, pkgPath, {
4779
4791
  npmExecPath
@@ -4782,18 +4794,22 @@ async function addOverrides({
4782
4794
  // first two parameters. AgentLockIncludesFn accepts an optional third
4783
4795
  // parameter which AgentDepsIncludesFn will ignore so we cast thingScanner
4784
4796
  // as an AgentLockIncludesFn type.
4785
- const thingScanner = isLockScanned ? lockIncludesByAgent[agent] : depsIncludesByAgent[agent];
4797
+ const thingScanner = isLockScanned ? lockIncludesByAgent.get(agent) : depsIncludesByAgent.get(agent);
4786
4798
  const depEntries = getDependencyEntries(pkgJson);
4787
4799
  const overridesDataObjects = [];
4788
4800
  if (pkgJson['private'] || isWorkspace) {
4789
- overridesDataObjects.push(getOverridesDataByAgent[agent](pkgJson));
4801
+ overridesDataObjects.push(overridesDataByAgent.get(agent)(pkgJson));
4790
4802
  } else {
4791
- overridesDataObjects.push(getOverridesDataByAgent[NPM$1](pkgJson), getOverridesDataByAgent[YARN_CLASSIC](pkgJson));
4803
+ overridesDataObjects.push(overridesDataByAgent.get(NPM$1)(pkgJson), overridesDataByAgent.get(YARN_CLASSIC)(pkgJson));
4792
4804
  }
4793
4805
  if (spinner) {
4794
4806
  spinner.text = `Adding overrides${workspaceName ? ` to ${workspaceName}` : ''}...`;
4795
4807
  }
4796
4808
  const depAliasMap = new Map();
4809
+ const nodeRange = `>=${pkgEnvDetails.minimumNodeVersion}`;
4810
+ const manifestEntries = manifestNpmOverrides.filter(({
4811
+ 1: data
4812
+ }) => semver.satisfies(semver.coerce(data.engines.node), nodeRange));
4797
4813
  // Chunk package names to process them in parallel 3 at a time.
4798
4814
  await promises.pEach(manifestEntries, 3, async ({
4799
4815
  1: data
@@ -4836,7 +4852,7 @@ async function addOverrides({
4836
4852
  type
4837
4853
  }) => {
4838
4854
  const overrideExists = objects.hasOwn(overrides, origPkgName);
4839
- if (overrideExists || thingScanner(thingToScan, origPkgName, lockBasename)) {
4855
+ if (overrideExists || thingScanner(thingToScan, origPkgName, lockName)) {
4840
4856
  const oldSpec = overrideExists ? overrides[origPkgName] : undefined;
4841
4857
  const origDepAlias = depAliasMap.get(origPkgName);
4842
4858
  const sockRegDepAlias = depAliasMap.get(sockRegPkgName);
@@ -4881,18 +4897,12 @@ async function addOverrides({
4881
4897
  });
4882
4898
  // Chunk package names to process them in parallel 3 at a time.
4883
4899
  await promises.pEach(workspacePkgJsonPaths, 3, async workspacePkgJsonPath => {
4884
- const otherState = await addOverrides({
4885
- agent,
4886
- agentExecPath,
4887
- lockBasename,
4888
- lockSrc,
4889
- manifestEntries,
4890
- npmExecPath,
4900
+ const otherState = await addOverrides(path.dirname(workspacePkgJsonPath), pkgEnvDetails, {
4901
+ logger,
4891
4902
  pin,
4892
- pkgPath: path.dirname(workspacePkgJsonPath),
4893
4903
  prod,
4894
- rootPath
4895
- }, createAddOverridesState(spinner));
4904
+ spinner
4905
+ });
4896
4906
  for (const key of ['added', 'addedInWorkspaces', 'updated', 'updatedInWorkspaces']) {
4897
4907
  for (const value of otherState[key]) {
4898
4908
  state[key].add(value);
@@ -4906,7 +4916,7 @@ async function addOverrides({
4906
4916
  overrides,
4907
4917
  type
4908
4918
  } of overridesDataObjects) {
4909
- updateManifestByAgent[type](editablePkgJson, objects.toSortedObject(overrides));
4919
+ updateManifestByAgent.get(type)(editablePkgJson, objects.toSortedObject(overrides));
4910
4920
  }
4911
4921
  await editablePkgJson.save();
4912
4922
  }
@@ -4957,32 +4967,74 @@ async function run$h(argv, importMeta, {
4957
4967
  parentName
4958
4968
  });
4959
4969
  const cwd = process$1.cwd();
4960
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
4970
+ if (cli.flags['dryRun']) {
4971
+ return console.log('[DryRun] Bailing now');
4972
+ }
4961
4973
  await applyOptimization(cwd, Boolean(cli.flags['pin']), Boolean(cli.flags['prod']));
4962
4974
  }
4963
4975
 
4964
- async function getOrganizations() {
4976
+ async function getOrganization(format = 'text') {
4965
4977
  const apiToken = index.getDefaultToken();
4966
4978
  if (!apiToken) {
4967
4979
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
4968
4980
  }
4981
+ await printOrganizationsFromToken(apiToken, format);
4982
+ }
4983
+ async function printOrganizationsFromToken(apiToken, format = 'text') {
4969
4984
  const spinner$1 = new spinner.Spinner({
4970
4985
  text: 'Fetching organizations...'
4971
4986
  }).start();
4972
4987
  const socketSdk = await index.setupSdk(apiToken);
4973
4988
  const result = await handleApiCall(socketSdk.getOrganizations(), 'looking up organizations');
4974
- if (result.success === false) {
4989
+ if (!result.success) {
4975
4990
  handleUnsuccessfulApiResponse('getOrganizations', result, spinner$1);
4976
4991
  return;
4977
4992
  }
4978
- spinner$1.stop(`List of organizations associated with your API key: ${colors.italic(apiToken)}`);
4993
+ spinner$1.stop();
4979
4994
  const organizations = Object.values(result.data.organizations);
4980
- for (const o of organizations) {
4981
- console.log(`
4982
- Name: ${o?.name}
4983
- ID: ${o?.id}
4984
- Plan: ${o?.plan}
4985
- `);
4995
+ const lastFiveOfApiToken = getLastFiveOfApiToken(apiToken);
4996
+ switch (format) {
4997
+ case 'json':
4998
+ {
4999
+ console.log(JSON.stringify(organizations.map(o => ({
5000
+ name: o.name,
5001
+ id: o.id,
5002
+ plan: o.plan
5003
+ })), null, 2));
5004
+ return;
5005
+ }
5006
+ case 'markdown':
5007
+ {
5008
+ // | Syntax | Description |
5009
+ // | ----------- | ----------- |
5010
+ // | Header | Title |
5011
+ // | Paragraph | Text |
5012
+ let mw1 = 4;
5013
+ let mw2 = 2;
5014
+ let mw3 = 4;
5015
+ for (const o of organizations) {
5016
+ mw1 = Math.max(mw1, o.name.length);
5017
+ mw2 = Math.max(mw2, o.id.length);
5018
+ mw3 = Math.max(mw3, o.plan.length);
5019
+ }
5020
+ console.log('# Organizations\n');
5021
+ console.log(`List of organizations associated with your API key, ending with: ${colors.italic(lastFiveOfApiToken)}\n`);
5022
+ console.log(`| Name${' '.repeat(mw1 - 4)} | ID${' '.repeat(mw2 - 2)} | Plan${' '.repeat(mw3 - 4)} |`);
5023
+ console.log(`| ${'-'.repeat(mw1)} | ${'-'.repeat(mw2)} | ${'-'.repeat(mw3)} |`);
5024
+ for (const o of organizations) {
5025
+ console.log(`| ${(o.name || '').padEnd(mw1, ' ')} | ${(o.id || '').padEnd(mw2, ' ')} | ${(o.plan || '').padEnd(mw3, ' ')} |`);
5026
+ }
5027
+ console.log(`| ${'-'.repeat(mw1)} | ${'-'.repeat(mw2)} | ${'-'.repeat(mw3)} |`);
5028
+ return;
5029
+ }
5030
+ default:
5031
+ {
5032
+ console.log(`List of organizations associated with your API key, ending with: ${colors.italic(lastFiveOfApiToken)}\n`);
5033
+ // Just dump
5034
+ for (const o of organizations) {
5035
+ console.log(`- Name: ${colors.bold(o.name)}, ID: ${colors.bold(o.id)}, Plan: ${colors.bold(o.plan)}`);
5036
+ }
5037
+ }
4986
5038
  }
4987
5039
  }
4988
5040
 
@@ -4990,13 +5042,19 @@ const config$g = {
4990
5042
  commandName: 'organizations',
4991
5043
  description: 'List organizations associated with the API key used',
4992
5044
  hidden: false,
4993
- flags: {},
5045
+ flags: {
5046
+ ...commonFlags,
5047
+ ...outputFlags
5048
+ },
4994
5049
  help: (command, _config) => `
4995
5050
  Usage
4996
5051
  $ ${command}
5052
+
5053
+ Options
5054
+ ${getFlagListOutput(config$g.flags, 6)}
4997
5055
  `
4998
5056
  };
4999
- const cmdOrganizations = {
5057
+ const cmdOrganization = {
5000
5058
  description: config$g.description,
5001
5059
  hidden: config$g.hidden,
5002
5060
  run: run$g
@@ -5010,8 +5068,23 @@ async function run$g(argv, importMeta, {
5010
5068
  importMeta,
5011
5069
  parentName
5012
5070
  });
5013
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5014
- await getOrganizations();
5071
+ const json = Boolean(cli.flags['json']);
5072
+ const markdown = Boolean(cli.flags['markdown']);
5073
+ if (json && markdown) {
5074
+ // Use exit status of 2 to indicate incorrect usage, generally invalid
5075
+ // options or missing arguments.
5076
+ // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
5077
+ process.exitCode = 2;
5078
+ console.error(`
5079
+ ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
5080
+ - The json and markdown flags cannot be both set, pick one
5081
+ `);
5082
+ return;
5083
+ }
5084
+ if (cli.flags['dryRun']) {
5085
+ return console.log('[DryRun] Bailing now');
5086
+ }
5087
+ await getOrganization(json ? 'json' : markdown ? 'markdown' : 'text');
5015
5088
  }
5016
5089
 
5017
5090
  const {
@@ -5070,7 +5143,9 @@ async function run$f(argv, importMeta, {
5070
5143
  importMeta,
5071
5144
  parentName
5072
5145
  });
5073
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5146
+ if (cli.flags['dryRun']) {
5147
+ return console.log('[DryRun] Bailing now');
5148
+ }
5074
5149
  await runRawNpm(argv);
5075
5150
  }
5076
5151
 
@@ -5130,7 +5205,9 @@ async function run$e(argv, importMeta, {
5130
5205
  importMeta,
5131
5206
  parentName
5132
5207
  });
5133
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5208
+ if (cli.flags['dryRun']) {
5209
+ return console.log('[DryRun] Bailing now');
5210
+ }
5134
5211
  await runRawNpx(argv);
5135
5212
  }
5136
5213
 
@@ -5163,7 +5240,7 @@ async function createReport(socketConfig, inputPaths, {
5163
5240
  handleUnsuccessfulApiResponse('createReport', result, spinner$1);
5164
5241
  return undefined;
5165
5242
  }
5166
- spinner$1.success();
5243
+ spinner$1.successAndStop();
5167
5244
  return result;
5168
5245
  }
5169
5246
  }
@@ -5215,16 +5292,16 @@ async function fetchReportData(reportId, includeAllIssues, strict) {
5215
5292
 
5216
5293
  if (strict) {
5217
5294
  if (result.data.healthy) {
5218
- spinner$1.success('Report result is healthy and great!');
5295
+ spinner$1.successAndStop('Report result is healthy and great!');
5219
5296
  } else {
5220
- spinner$1.error('Report result deemed unhealthy for project');
5297
+ spinner$1.errorAndStop('Report result deemed unhealthy for project');
5221
5298
  }
5222
5299
  } else if (!result.data.healthy) {
5223
5300
  const severityCount = getSeverityCount(result.data.issues, includeAllIssues ? undefined : 'high');
5224
5301
  const issueSummary = formatSeverityCount(severityCount);
5225
- spinner$1.success(`Report has these issues: ${issueSummary}`);
5302
+ spinner$1.successAndStop(`Report has these issues: ${issueSummary}`);
5226
5303
  } else {
5227
- spinner$1.success('Report has no issues');
5304
+ spinner$1.successAndStop('Report has no issues');
5228
5305
  }
5229
5306
  return result.data;
5230
5307
  }
@@ -5328,7 +5405,9 @@ async function run$d(argv, importMeta, {
5328
5405
  const view = Boolean(cli.flags['view']);
5329
5406
 
5330
5407
  // Note exiting earlier to skirt a hidden auth requirement
5331
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5408
+ if (cli.flags['dryRun']) {
5409
+ return console.log('[DryRun] Bailing now');
5410
+ }
5332
5411
  const socketConfig = await getSocketConfig(absoluteConfigPath);
5333
5412
  const result = await createReport(socketConfig, cli.input, {
5334
5413
  cwd,
@@ -5404,7 +5483,9 @@ async function run$c(argv, importMeta, {
5404
5483
  - Can only handle a single report ID ${extraInput.length < 2 ? colors.red(`(received ${extraInput.length}!)`) : colors.green('(ok)')}\n`);
5405
5484
  return;
5406
5485
  }
5407
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5486
+ if (cli.flags['dryRun']) {
5487
+ return console.log('[DryRun] Bailing now');
5488
+ }
5408
5489
  await viewReport(reportId, {
5409
5490
  all: Boolean(cli.flags['all']),
5410
5491
  commandName: `${parentName} ${config$c.commandName}`,
@@ -5459,7 +5540,7 @@ async function createRepo({
5459
5540
  visibility
5460
5541
  }), 'creating repository');
5461
5542
  if (result.success) {
5462
- spinner$1.success('Repository created successfully');
5543
+ spinner$1.successAndStop('Repository created successfully');
5463
5544
  } else {
5464
5545
  handleUnsuccessfulApiResponse('createOrgRepo', result, spinner$1);
5465
5546
  }
@@ -5540,7 +5621,9 @@ async function run$b(argv, importMeta, {
5540
5621
  - Repository name using --repoName ${!repoName ? colors.red('(missing!)') : typeof repoName !== 'string' ? colors.red('(invalid!)') : colors.green('(ok)')}\n`);
5541
5622
  return;
5542
5623
  }
5543
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5624
+ if (cli.flags['dryRun']) {
5625
+ return console.log('[DryRun] Bailing now');
5626
+ }
5544
5627
  const apiToken = index.getDefaultToken();
5545
5628
  if (!apiToken) {
5546
5629
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
@@ -5566,7 +5649,7 @@ async function deleteRepo(orgSlug, repoName, apiToken) {
5566
5649
  const socketSdk = await index.setupSdk(apiToken);
5567
5650
  const result = await handleApiCall(socketSdk.deleteOrgRepo(orgSlug, repoName), 'deleting repository');
5568
5651
  if (result.success) {
5569
- spinner$1.success('Repository deleted successfully');
5652
+ spinner$1.successAndStop('Repository deleted successfully');
5570
5653
  } else {
5571
5654
  handleUnsuccessfulApiResponse('deleteOrgRepo', result, spinner$1);
5572
5655
  }
@@ -5616,7 +5699,9 @@ async function run$a(argv, importMeta, {
5616
5699
  - At least one TARGET (e.g. \`.\` or \`./package.json\`\n`);
5617
5700
  return;
5618
5701
  }
5619
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5702
+ if (cli.flags['dryRun']) {
5703
+ return console.log('[DryRun] Bailing now');
5704
+ }
5620
5705
  const apiToken = index.getDefaultToken();
5621
5706
  if (!apiToken) {
5622
5707
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
@@ -5653,6 +5738,18 @@ async function listRepos({
5653
5738
  handleUnsuccessfulApiResponse('getOrgRepoList', result, spinner$1);
5654
5739
  return;
5655
5740
  }
5741
+ spinner$1.stop();
5742
+ if (outputJson) {
5743
+ const data = result.data.results.map(o => ({
5744
+ id: o.id,
5745
+ name: o.name,
5746
+ visibility: o.visibility,
5747
+ defaultBranch: o.default_branch,
5748
+ archived: o.archived
5749
+ }));
5750
+ console.log(JSON.stringify(data, null, 2));
5751
+ return;
5752
+ }
5656
5753
  const options = {
5657
5754
  columns: [{
5658
5755
  field: 'id',
@@ -5671,7 +5768,7 @@ async function listRepos({
5671
5768
  name: colors.magenta('Archived')
5672
5769
  }]
5673
5770
  };
5674
- spinner$1.stop(chalkTable(options, result.data.results));
5771
+ console.log(chalkTable(options, result.data.results));
5675
5772
  }
5676
5773
 
5677
5774
  const config$9 = {
@@ -5741,7 +5838,9 @@ async function run$9(argv, importMeta, {
5741
5838
  - At least one TARGET (e.g. \`.\` or \`./package.json\`\n`);
5742
5839
  return;
5743
5840
  }
5744
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5841
+ if (cli.flags['dryRun']) {
5842
+ return console.log('[DryRun] Bailing now');
5843
+ }
5745
5844
  const apiToken = index.getDefaultToken();
5746
5845
  if (!apiToken) {
5747
5846
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
@@ -5785,7 +5884,7 @@ async function updateRepo({
5785
5884
  visibility
5786
5885
  }), 'updating repository');
5787
5886
  if (result.success) {
5788
- spinner$1.success('Repository updated successfully');
5887
+ spinner$1.successAndStop('Repository updated successfully');
5789
5888
  } else {
5790
5889
  handleUnsuccessfulApiResponse('updateOrgRepo', result, spinner$1);
5791
5890
  }
@@ -5867,7 +5966,9 @@ async function run$8(argv, importMeta, {
5867
5966
  - At least one TARGET (e.g. \`.\` or \`./package.json\`\n`);
5868
5967
  return;
5869
5968
  }
5870
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5969
+ if (cli.flags['dryRun']) {
5970
+ return console.log('[DryRun] Bailing now');
5971
+ }
5871
5972
  const apiToken = index.getDefaultToken();
5872
5973
  if (!apiToken) {
5873
5974
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
@@ -5969,7 +6070,9 @@ async function run$7(argv, importMeta, {
5969
6070
  - Repository name using --repoName ${!repoName ? colors.red('(missing!)') : typeof repoName !== 'string' ? colors.red('(invalid!)') : colors.green('(ok)')}\n`);
5970
6071
  return;
5971
6072
  }
5972
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
6073
+ if (cli.flags['dryRun']) {
6074
+ return console.log('[DryRun] Bailing now');
6075
+ }
5973
6076
  const apiToken = index.getDefaultToken();
5974
6077
  if (!apiToken) {
5975
6078
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
@@ -5998,8 +6101,149 @@ const cmdRepos = {
5998
6101
  }
5999
6102
  };
6000
6103
 
6104
+ async function suggestOrgSlug(socketSdk) {
6105
+ const result = await handleApiCall(socketSdk.getOrganizations(), 'looking up organizations');
6106
+ // Ignore a failed request here. It was not the primary goal of
6107
+ // running this command and reporting it only leads to end-user confusion.
6108
+ if (result.success) {
6109
+ const proceed = await prompts.select({
6110
+ message: 'Missing org name; do you want to use any of these orgs for this scan?',
6111
+ choices: Array.from(Object.values(result.data.organizations)).map(({
6112
+ name: slug
6113
+ }) => ({
6114
+ name: 'Yes [' + slug + ']',
6115
+ value: slug,
6116
+ description: `Use "${slug}" as the organization`
6117
+ })).concat({
6118
+ name: 'No',
6119
+ value: '',
6120
+ description: 'Do not use any of these organizations (will end in a no-op)'
6121
+ })
6122
+ });
6123
+ if (proceed) {
6124
+ return proceed;
6125
+ }
6126
+ }
6127
+ }
6128
+
6129
+ async function suggestRepoSlug(socketSdk, orgSlug) {
6130
+ // Same as above, but if there's a repo with the same name as cwd then
6131
+ // default the selection to that name.
6132
+ const result = await handleApiCall(socketSdk.getOrgRepoList(orgSlug, {
6133
+ orgSlug,
6134
+ sort: 'name',
6135
+ direction: 'asc',
6136
+ // There's no guarantee that the cwd is part of this page. If it's not
6137
+ // then do an additional request and specific search for it instead.
6138
+ // This way we can offer the tip of "do you want to create [cwd]?".
6139
+ perPage: 10,
6140
+ page: 0
6141
+ }), 'looking up known repos');
6142
+ // Ignore a failed request here. It was not the primary goal of
6143
+ // running this command and reporting it only leads to end-user confusion.
6144
+ if (result.success) {
6145
+ const currentDirName = dirNameToSlug(path.basename(process$1.cwd()));
6146
+ let cwdIsKnown = !!currentDirName && result.data.results.some(obj => obj.slug === currentDirName);
6147
+ if (!cwdIsKnown && currentDirName) {
6148
+ // Do an explicit request so we can assert that the cwd exists or not
6149
+ const result = await handleApiCall(socketSdk.getOrgRepo(orgSlug, currentDirName), 'checking if current cwd is a known repo');
6150
+ if (result.success) {
6151
+ cwdIsKnown = true;
6152
+ }
6153
+ }
6154
+ const proceed = await prompts.select({
6155
+ message: 'Missing repo name; do you want to use any of these known repo names for this scan?',
6156
+ choices:
6157
+ // Put the CWD suggestion at the top, whether it exists or not
6158
+ (currentDirName ? [{
6159
+ name: `Yes, current dir [${cwdIsKnown ? currentDirName : `create repo for ${currentDirName}`}]`,
6160
+ value: currentDirName,
6161
+ description: cwdIsKnown ? 'Register a new repo name under the given org and use it' : 'Use current dir as repo'
6162
+ }] : []).concat(result.data.results.filter(({
6163
+ slug
6164
+ }) => !!slug && slug !== currentDirName).map(({
6165
+ slug
6166
+ }) => ({
6167
+ name: 'Yes [' + slug + ']',
6168
+ value: slug || '',
6169
+ // Filtered above but TS is like nah.
6170
+ description: `Use "${slug}" as the repo name`
6171
+ })), {
6172
+ name: 'No',
6173
+ value: '',
6174
+ description: 'Do not use any of these repos (will end in a no-op)'
6175
+ })
6176
+ });
6177
+ if (proceed) {
6178
+ const repoName = proceed;
6179
+ let repoDefaultBranch = '';
6180
+ // Store the default branch to help with the branch name question next
6181
+ result.data.results.some(obj => {
6182
+ if (obj.slug === proceed && obj.default_branch) {
6183
+ repoDefaultBranch = obj.default_branch;
6184
+ return;
6185
+ }
6186
+ });
6187
+ return {
6188
+ slug: repoName,
6189
+ defaultBranch: repoDefaultBranch
6190
+ };
6191
+ }
6192
+ }
6193
+ }
6194
+ function dirNameToSlug(name) {
6195
+ // Uses slug specs asserted by our servers
6196
+ // Note: this can lead to collisions; eg. slug for `x--y` and `x---y` is `x-y`
6197
+ return name.toLowerCase().replace(/[^[a-zA-Z0-9_.-]/g, '_').replace(/--+/g, '-').replace(/__+/g, '_').replace(/\.\.+/g, '.').replace(/[._-]+$/, '');
6198
+ }
6199
+
6200
+ async function suggestBranchSlug(repoDefaultBranch) {
6201
+ const spawnResult = childProcess.spawnSync('git', ['branch', '--show-current']);
6202
+ const currentBranch = spawnResult.stdout.toString('utf8').trim();
6203
+ if (spawnResult.status === 0 && currentBranch) {
6204
+ const proceed = await prompts.select({
6205
+ message: 'Use the current git branch as target branch name?',
6206
+ choices: [{
6207
+ name: `Yes [${currentBranch}]`,
6208
+ value: currentBranch,
6209
+ description: 'Use the current git branch for branch name'
6210
+ }, ...(repoDefaultBranch && repoDefaultBranch !== currentBranch ? [{
6211
+ name: `No, use the default branch [${repoDefaultBranch}]`,
6212
+ value: repoDefaultBranch,
6213
+ description: 'Use the default branch for target repo as the target branch name'
6214
+ }] : []), {
6215
+ name: 'No',
6216
+ value: '',
6217
+ description: 'Do not use the current git branch as name (will end in a no-op)'
6218
+ }].filter(Boolean)
6219
+ });
6220
+ if (proceed) {
6221
+ return proceed;
6222
+ }
6223
+ }
6224
+ }
6225
+
6226
+ async function suggestTarget() {
6227
+ // We could prefill this with sub-dirs of the current
6228
+ // dir ... but is that going to be useful?
6229
+ const proceed = await prompts.select({
6230
+ message: 'No TARGET given. Do you want to use the current directory?',
6231
+ choices: [{
6232
+ name: 'Yes',
6233
+ value: true,
6234
+ description: 'Target the current directory'
6235
+ }, {
6236
+ name: 'No',
6237
+ value: false,
6238
+ description: 'Do not use the current directory (this will end in a no-op)'
6239
+ }]
6240
+ });
6241
+ if (proceed) {
6242
+ return ['.'];
6243
+ }
6244
+ }
6245
+
6001
6246
  async function createFullScan({
6002
- apiToken,
6003
6247
  branchName,
6004
6248
  commitHash: _commitHash,
6005
6249
  commitMessage,
@@ -6007,17 +6251,100 @@ async function createFullScan({
6007
6251
  cwd,
6008
6252
  defaultBranch,
6009
6253
  orgSlug,
6010
- packagePaths,
6011
6254
  pendingHead,
6012
6255
  pullRequest: _pullRequest,
6256
+ readOnly,
6013
6257
  repoName,
6258
+ targets,
6014
6259
  tmp
6015
6260
  }) {
6261
+ const socketSdk = await index.setupSdk();
6262
+ const supportedFiles = await socketSdk.getReportSupportedFiles().then(res => {
6263
+ if (!res.success) {
6264
+ handleUnsuccessfulApiResponse('getReportSupportedFiles', res, new spinner.Spinner());
6265
+ assert(false, 'handleUnsuccessfulApiResponse should unconditionally throw');
6266
+ }
6267
+ return res.data;
6268
+ }).catch(cause => {
6269
+ throw new Error('Failed getting supported files for report', {
6270
+ cause
6271
+ });
6272
+ });
6273
+
6274
+ // If we updated any inputs then we should print the command line to repeat
6275
+ // the command without requiring user input, as a suggestion.
6276
+ let updatedInput = false;
6277
+ if (!targets.length) {
6278
+ const received = await suggestTarget();
6279
+ targets = received ?? [];
6280
+ updatedInput = true;
6281
+ }
6282
+ const packagePaths = await npmPaths.getPackageFilesFullScans(cwd, targets, supportedFiles);
6283
+
6284
+ // We're going to need an api token to suggest data because those suggestions
6285
+ // must come from data we already know. Don't error on missing api token yet.
6286
+ // If the api-token is not set, ignore it for the sake of suggestions.
6287
+ const apiToken = index.getDefaultToken();
6288
+ if (apiToken && !orgSlug) {
6289
+ const suggestion = await suggestOrgSlug(socketSdk);
6290
+ if (suggestion) orgSlug = suggestion;
6291
+ updatedInput = true;
6292
+ }
6293
+
6294
+ // If the current cwd is unknown and is used as a repo slug anyways, we will
6295
+ // first need to register the slug before we can use it.
6296
+ let repoDefaultBranch = '';
6297
+
6298
+ // (Don't bother asking for the rest if we didn't get an org slug above)
6299
+ if (apiToken && orgSlug && !repoName) {
6300
+ const suggestion = await suggestRepoSlug(socketSdk, orgSlug);
6301
+ if (suggestion) {
6302
+ ({
6303
+ defaultBranch: repoDefaultBranch,
6304
+ slug: repoName
6305
+ } = suggestion);
6306
+ }
6307
+ updatedInput = true;
6308
+ }
6309
+
6310
+ // (Don't bother asking for the rest if we didn't get an org/repo above)
6311
+ if (apiToken && orgSlug && repoName && !branchName) {
6312
+ const suggestion = await suggestBranchSlug(repoDefaultBranch);
6313
+ if (suggestion) branchName = suggestion;
6314
+ updatedInput = true;
6315
+ }
6316
+ if (!orgSlug || !repoName || !branchName || !packagePaths.length) {
6317
+ // Use exit status of 2 to indicate incorrect usage, generally invalid
6318
+ // options or missing arguments.
6319
+ // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
6320
+ process$1.exitCode = 2;
6321
+ console.error(`
6322
+ ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
6323
+ - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}\n
6324
+ - Repository name using --repo ${!repoName ? colors.red('(missing!)') : colors.green('(ok)')}\n
6325
+ - Branch name using --branch ${!branchName ? colors.red('(missing!)') : colors.green('(ok)')}\n
6326
+ - At least one TARGET (e.g. \`.\` or \`./package.json\`) ${!packagePaths.length ? colors.red(targets.length > 0 ? '(TARGET' + (targets.length ? 's' : '') + ' contained no matching/supported files!)' : '(missing)') : colors.green('(ok)')}\n
6327
+ ${!apiToken ? 'Note: was unable to make suggestions because no API Token was found; this would make command fail regardless\n' : ''}
6328
+ `);
6329
+ return;
6330
+ }
6331
+ if (updatedInput) {
6332
+ console.log('Note: You can invoke this command next time to skip the interactive questions:');
6333
+ console.log('```');
6334
+ console.log(` socket scan create [other flags...] --repo ${repoName} --branch ${branchName} ${orgSlug} ${targets.join(' ')}`);
6335
+ console.log('```');
6336
+ }
6337
+ if (!apiToken) {
6338
+ throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
6339
+ }
6340
+ if (readOnly) {
6341
+ console.log('[ReadOnly] Bailing now');
6342
+ return;
6343
+ }
6016
6344
  const spinnerText = 'Creating a scan... \n';
6017
6345
  const spinner$1 = new spinner.Spinner({
6018
6346
  text: spinnerText
6019
6347
  }).start();
6020
- const socketSdk = await index.setupSdk(apiToken);
6021
6348
  const result = await handleApiCall(socketSdk.createOrgFullScan(orgSlug, {
6022
6349
  repo: repoName,
6023
6350
  branch: branchName,
@@ -6030,7 +6357,7 @@ async function createFullScan({
6030
6357
  handleUnsuccessfulApiResponse('CreateOrgFullScan', result, spinner$1);
6031
6358
  return;
6032
6359
  }
6033
- spinner$1.success('Scan created successfully');
6360
+ spinner$1.successAndStop('Scan created successfully');
6034
6361
  const link = colors.underline(colors.cyan(`${result.data.html_report_url}`));
6035
6362
  console.log(`Available at: ${link}`);
6036
6363
  const rl = readline.createInterface({
@@ -6104,6 +6431,11 @@ const config$6 = {
6104
6431
  default: false,
6105
6432
  description: 'Set as pending head'
6106
6433
  },
6434
+ readOnly: {
6435
+ type: 'boolean',
6436
+ default: false,
6437
+ description: 'Similar to --dry-run except it can read from remote, stops before it would create an actual report'
6438
+ },
6107
6439
  tmp: {
6108
6440
  type: 'boolean',
6109
6441
  shortFlag: 't',
@@ -6143,54 +6475,47 @@ async function run$6(argv, importMeta, {
6143
6475
  });
6144
6476
  const [orgSlug = '', ...targets] = cli.input;
6145
6477
  const cwd = cli.flags['cwd'] && cli.flags['cwd'] !== 'process.cwd()' ? String(cli.flags['cwd']) : process$1.cwd();
6146
-
6147
- // Note exiting earlier to skirt a hidden auth requirement
6148
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
6149
- const socketSdk = await index.setupSdk();
6150
- const supportedFiles = await socketSdk.getReportSupportedFiles().then(res => {
6151
- if (!res.success) handleUnsuccessfulApiResponse('getReportSupportedFiles', res, new spinner.Spinner());
6152
- // TODO: verify type at runtime? Consider it trusted data and assume type?
6153
- return res.data;
6154
- }).catch(cause => {
6155
- throw new Error('Failed getting supported files for report', {
6156
- cause
6157
- });
6158
- });
6159
- const packagePaths = await npmPaths.getPackageFilesFullScans(cwd, targets, supportedFiles);
6160
- const {
6478
+ let {
6161
6479
  branch: branchName,
6162
6480
  repo: repoName
6163
6481
  } = cli.flags;
6164
- if (!orgSlug || !repoName || !branchName || !packagePaths.length) {
6482
+ const apiToken = index.getDefaultToken();
6483
+ if (!apiToken && (!orgSlug || !repoName || !branchName || !targets.length)) {
6484
+ // Without api token we cannot recover because we can't request more info
6485
+ // from the server, to match and help with the current cwd/git status.
6165
6486
  // Use exit status of 2 to indicate incorrect usage, generally invalid
6166
6487
  // options or missing arguments.
6167
6488
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
6168
6489
  process$1.exitCode = 2;
6169
- console.error(`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
6170
- - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}\n
6171
- - Repository name using --repo ${!repoName ? colors.red('(missing!)') : colors.green('(ok)')}\n
6172
- - Branch name using --branch ${!branchName ? colors.red('(missing!)') : colors.green('(ok)')}\n
6173
- - At least one TARGET (e.g. \`.\` or \`./package.json\`) ${!packagePaths.length ? colors.red(targets.length > 0 ? '(TARGET' + (targets.length ? 's' : '') + ' contained no matching/supported files!)' : '(missing)') : colors.green('(ok)')}\n`);
6490
+ console.error(`
6491
+ ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
6492
+ - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}\n
6493
+ - Repository name using --repo ${!repoName ? colors.red('(missing!)') : colors.green('(ok)')}\n
6494
+ - Branch name using --branch ${!branchName ? colors.red('(missing!)') : colors.green('(ok)')}\n
6495
+ - At least one TARGET (e.g. \`.\` or \`./package.json\`) ${!targets.length ? '(missing)' : colors.green('(ok)')}\n
6496
+ (Additionally, no API Token was set so we cannot auto-discover these details)\n
6497
+ `);
6174
6498
  return;
6175
6499
  }
6176
- const apiToken = index.getDefaultToken();
6177
- if (!apiToken) {
6178
- throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
6500
+
6501
+ // Note exiting earlier to skirt a hidden auth requirement
6502
+ if (cli.flags['dryRun']) {
6503
+ return console.log('[DryRun] Bailing now');
6179
6504
  }
6180
6505
  await createFullScan({
6181
- apiToken,
6182
- orgSlug,
6183
- repoName: repoName,
6184
6506
  branchName: branchName,
6507
+ commitHash: cli.flags['commitHash'] ?? '',
6185
6508
  commitMessage: cli.flags['commitMessage'] ?? '',
6509
+ committers: cli.flags['committers'] ?? '',
6510
+ cwd,
6186
6511
  defaultBranch: Boolean(cli.flags['defaultBranch']),
6512
+ orgSlug,
6187
6513
  pendingHead: Boolean(cli.flags['pendingHead']),
6188
- tmp: Boolean(cli.flags['tmp']),
6189
- packagePaths,
6190
- cwd,
6191
- commitHash: cli.flags['commitHash'] ?? '',
6192
- committers: cli.flags['committers'] ?? '',
6193
- pullRequest: cli.flags['pullRequest'] ?? undefined
6514
+ pullRequest: cli.flags['pullRequest'] ?? undefined,
6515
+ readOnly: Boolean(cli.flags['readOnly']),
6516
+ repoName: repoName,
6517
+ targets,
6518
+ tmp: Boolean(cli.flags['tmp'])
6194
6519
  });
6195
6520
  }
6196
6521
 
@@ -6202,7 +6527,7 @@ async function deleteOrgFullScan(orgSlug, fullScanId, apiToken) {
6202
6527
  const socketSdk = await index.setupSdk(apiToken);
6203
6528
  const result = await handleApiCall(socketSdk.deleteOrgFullScan(orgSlug, fullScanId), 'Deleting scan');
6204
6529
  if (result.success) {
6205
- spinner$1.success('Scan deleted successfully');
6530
+ spinner$1.successAndStop('Scan deleted successfully');
6206
6531
  } else {
6207
6532
  handleUnsuccessfulApiResponse('deleteOrgFullScan', result, spinner$1);
6208
6533
  }
@@ -6252,7 +6577,9 @@ async function run$5(argv, importMeta, {
6252
6577
  - Full Scan ID to delete as second argument ${!fullScanId ? colors.red('(missing!)') : colors.green('(ok)')}\n`);
6253
6578
  return;
6254
6579
  }
6255
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
6580
+ if (cli.flags['dryRun']) {
6581
+ return console.log('[DryRun] Bailing now');
6582
+ }
6256
6583
  const apiToken = index.getDefaultToken();
6257
6584
  if (!apiToken) {
6258
6585
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
@@ -6382,7 +6709,9 @@ async function run$4(argv, importMeta, {
6382
6709
  - Org name as the argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}\n`);
6383
6710
  return;
6384
6711
  }
6385
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
6712
+ if (cli.flags['dryRun']) {
6713
+ return console.log('[DryRun] Bailing now');
6714
+ }
6386
6715
  const apiToken = index.getDefaultToken();
6387
6716
  if (!apiToken) {
6388
6717
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
@@ -6461,7 +6790,9 @@ async function run$3(argv, importMeta, {
6461
6790
  - Full Scan ID to inspect as second argument ${!fullScanId ? colors.red('(missing!)') : colors.green('(ok)')}\n`);
6462
6791
  return;
6463
6792
  }
6464
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
6793
+ if (cli.flags['dryRun']) {
6794
+ return console.log('[DryRun] Bailing now');
6795
+ }
6465
6796
  const apiToken = index.getDefaultToken();
6466
6797
  if (!apiToken) {
6467
6798
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
@@ -6529,7 +6860,9 @@ async function run$2(argv, importMeta, {
6529
6860
  - Full Scan ID to fetch as second argument ${!fullScanId ? colors.red('(missing!)') : colors.green('(ok)')}\n`);
6530
6861
  return;
6531
6862
  }
6532
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
6863
+ if (cli.flags['dryRun']) {
6864
+ return console.log('[DryRun] Bailing now');
6865
+ }
6533
6866
  const apiToken = index.getDefaultToken();
6534
6867
  if (!apiToken) {
6535
6868
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
@@ -6692,7 +7025,9 @@ async function run$1(argv, importMeta, {
6692
7025
  importMeta,
6693
7026
  parentName
6694
7027
  });
6695
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
7028
+ if (cli.flags['dryRun']) {
7029
+ return console.log('[DryRun] Bailing now');
7030
+ }
6696
7031
  const apiToken = index.getDefaultToken();
6697
7032
  if (!apiToken) {
6698
7033
  throw new index.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
@@ -6921,7 +7256,7 @@ void (async () => {
6921
7256
  npx: cmdNpx,
6922
7257
  oops: cmdOops,
6923
7258
  optimize: cmdOptimize,
6924
- organization: cmdOrganizations,
7259
+ organization: cmdOrganization,
6925
7260
  'raw-npm': cmdRawNpm,
6926
7261
  'raw-npx': cmdRawNpx,
6927
7262
  report: cmdReport,
@@ -6973,5 +7308,5 @@ void (async () => {
6973
7308
  await index.captureException(e);
6974
7309
  }
6975
7310
  })();
6976
- //# debugId=24a4ade4-3f5e-4a46-8f9b-ccd0f4cf485d
7311
+ //# debugId=76095f49-6cee-41ed-8752-1e7608d29b7d
6977
7312
  //# sourceMappingURL=cli.js.map