@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.
@@ -54,12 +54,14 @@ var index_cjs = require('@socketregistry/hyrious__bun.lockb/index.cjs');
54
54
  var sorts = require('@socketsecurity/registry/lib/sorts');
55
55
  var strings = require('@socketsecurity/registry/lib/strings');
56
56
  var yaml = _socketInterop(require('yaml'));
57
- var npm$1 = require('./npm.js');
58
57
  var npmPaths = require('./npm-paths.js');
58
+ var npm$1 = require('./npm.js');
59
59
  var betterAjvErrors = _socketInterop(require('@apideck/better-ajv-errors'));
60
60
  var config$A = require('@socketsecurity/config');
61
+ var assert = require('node:assert');
61
62
  var readline = require('node:readline/promises');
62
63
  var open = _socketInterop(require('open'));
64
+ var node_child_process = require('node:child_process');
63
65
  var TableWidget = _socketInterop(require('blessed-contrib/lib/widget/table'));
64
66
  var readline$1 = require('node:readline');
65
67
 
@@ -1285,6 +1287,51 @@ async function runAction(githubEventBefore, githubEventAfter) {
1285
1287
  }
1286
1288
  }
1287
1289
 
1290
+ const {
1291
+ API_V0_URL
1292
+ } = constants;
1293
+ function handleUnsuccessfulApiResponse(_name, result, spinner) {
1294
+ // SocketSdkErrorType['error'] is not typed.
1295
+ const resultErrorMessage = result.error?.message;
1296
+ const message = typeof resultErrorMessage === 'string' ? resultErrorMessage : 'No error message returned';
1297
+ if (result.status === 401 || result.status === 403) {
1298
+ spinner.stop();
1299
+ throw new index.AuthError(message);
1300
+ }
1301
+ spinner.errorAndStop(`${colors.bgRed(colors.white('API returned an error:'))} ${message}`);
1302
+ process$1.exit(1);
1303
+ }
1304
+ async function handleApiCall(value, description) {
1305
+ let result;
1306
+ try {
1307
+ result = await value;
1308
+ } catch (cause) {
1309
+ throw new Error(`Failed ${description}`, {
1310
+ cause
1311
+ });
1312
+ }
1313
+ return result;
1314
+ }
1315
+ async function handleAPIError(code) {
1316
+ if (code === 400) {
1317
+ return 'One of the options passed might be incorrect.';
1318
+ } else if (code === 403) {
1319
+ return 'You might be trying to access an organization that is not linked to the API key you are logged in with.';
1320
+ }
1321
+ }
1322
+ function getLastFiveOfApiToken(token) {
1323
+ // Get the last 5 characters of the API token before the trailing "_api".
1324
+ return token.slice(-9, -4);
1325
+ }
1326
+ async function queryAPI(path, apiToken) {
1327
+ return await fetch(`${API_V0_URL}/${path}`, {
1328
+ method: 'GET',
1329
+ headers: {
1330
+ Authorization: `Basic ${btoa(`${apiToken}:${apiToken}`)}`
1331
+ }
1332
+ });
1333
+ }
1334
+
1288
1335
  function getFlagListOutput(list, indent, {
1289
1336
  keyPrefix = '--',
1290
1337
  padName
@@ -1452,6 +1499,7 @@ function meowOrExit({
1452
1499
  if (constants.ENV[SOCKET_CLI_SHOW_BANNER]) {
1453
1500
  console.log(getAsciiHeader(command));
1454
1501
  }
1502
+
1455
1503
  // This exits if .printHelp() is called either by meow itself or by us.
1456
1504
  const cli = meow({
1457
1505
  argv,
@@ -1469,15 +1517,15 @@ function meowOrExit({
1469
1517
  }
1470
1518
  function getAsciiHeader(command) {
1471
1519
  const cliVersion = // The '@rollup/plugin-replace' will replace "process.env['SOCKET_CLI_VERSION_HASH']".
1472
- "0.14.48:61ff8dc:d16eb84e:pub";
1520
+ "0.14.50:c8e152a:9126d091:pub";
1473
1521
  const nodeVersion = process.version;
1474
- // Get the last 5 characters of the API token before the trailing "_api".
1475
- const lastFiveCharsOfApiToken = index.getSetting('apiToken')?.slice(-9, -4) || 'no';
1522
+ const apiToken = index.getSetting('apiToken');
1523
+ const shownToken = apiToken ? getLastFiveOfApiToken(apiToken) : 'no';
1476
1524
  const relCwd = process.cwd().replace(new RegExp(`^${regexps.escapeRegExp(constants.homePath)}`, 'i'), '~/');
1477
1525
  const body = `
1478
1526
  _____ _ _ /---------------
1479
1527
  | __|___ ___| |_ ___| |_ | Socket.dev CLI ver ${cliVersion}
1480
- |__ | . | _| '_| -_| _| | Node: ${nodeVersion}, API token set: ${lastFiveCharsOfApiToken}
1528
+ |__ | . | _| '_| -_| _| | Node: ${nodeVersion}, API token set: ${shownToken}
1481
1529
  |_____|___|___|_,_|___|_|.dev | Command: \`${command}\`, cwd: ${relCwd}`.trimStart();
1482
1530
  return ` ${body}\n`;
1483
1531
  }
@@ -1533,49 +1581,10 @@ async function run$z(argv, importMeta, {
1533
1581
  });
1534
1582
  const githubEventBefore = String(cli.flags['githubEventBefore'] || '');
1535
1583
  const githubEventAfter = String(cli.flags['githubEventAfter'] || '');
1536
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
1537
- await runAction(githubEventBefore, githubEventAfter);
1538
- }
1539
-
1540
- const {
1541
- API_V0_URL
1542
- } = constants;
1543
- function handleUnsuccessfulApiResponse(_name, result, spinner) {
1544
- // SocketSdkErrorType['error'] is not typed.
1545
- const resultErrorMessage = result.error?.message;
1546
- const message = typeof resultErrorMessage === 'string' ? resultErrorMessage : 'No error message returned';
1547
- if (result.status === 401 || result.status === 403) {
1548
- spinner.stop();
1549
- throw new index.AuthError(message);
1550
- }
1551
- spinner.error(`${colors.bgRed(colors.white('API returned an error:'))} ${message}`);
1552
- process$1.exit(1);
1553
- }
1554
- async function handleApiCall(value, description) {
1555
- let result;
1556
- try {
1557
- result = await value;
1558
- } catch (cause) {
1559
- throw new Error(`Failed ${description}`, {
1560
- cause
1561
- });
1562
- }
1563
- return result;
1564
- }
1565
- async function handleAPIError(code) {
1566
- if (code === 400) {
1567
- return 'One of the options passed might be incorrect.';
1568
- } else if (code === 403) {
1569
- return 'You might be trying to access an organization that is not linked to the API key you are logged in with.';
1584
+ if (cli.flags['dryRun']) {
1585
+ return console.log('[DryRun] Bailing now');
1570
1586
  }
1571
- }
1572
- async function queryAPI(path, apiToken) {
1573
- return await fetch(`${API_V0_URL}/${path}`, {
1574
- method: 'GET',
1575
- headers: {
1576
- Authorization: `Basic ${btoa(`${apiToken}:${apiToken}`)}`
1577
- }
1578
- });
1587
+ await runAction(githubEventBefore, githubEventAfter);
1579
1588
  }
1580
1589
 
1581
1590
  // Note: Widgets does not seem to actually work as code :'(
@@ -1850,7 +1859,9 @@ async function run$y(argv, importMeta, {
1850
1859
  - Repository name using --repo when scope is "repo" ${badRepo ? colors.red('(bad!)') : colors.green('(ok)')}\n`);
1851
1860
  return;
1852
1861
  }
1853
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
1862
+ if (cli.flags['dryRun']) {
1863
+ return console.log('[DryRun] Bailing now');
1864
+ }
1854
1865
  const apiToken = index.getDefaultToken();
1855
1866
  if (!apiToken) {
1856
1867
  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.');
@@ -1978,7 +1989,9 @@ async function run$x(argv, importMeta, {
1978
1989
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}\n`);
1979
1990
  return;
1980
1991
  }
1981
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
1992
+ if (cli.flags['dryRun']) {
1993
+ return console.log('[DryRun] Bailing now');
1994
+ }
1982
1995
  const apiToken = index.getDefaultToken();
1983
1996
  if (!apiToken) {
1984
1997
  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.');
@@ -2200,7 +2213,9 @@ async function run$w(argv, importMeta, {
2200
2213
  if (yargv.output === undefined) {
2201
2214
  yargv.output = 'socket-cdx.json';
2202
2215
  }
2203
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
2216
+ if (cli.flags['dryRun']) {
2217
+ return console.log('[DryRun] Bailing now');
2218
+ }
2204
2219
  await runCycloneDX(yargv);
2205
2220
  }
2206
2221
 
@@ -2303,7 +2318,9 @@ async function run$v(argv, importMeta, {
2303
2318
  importMeta,
2304
2319
  parentName
2305
2320
  });
2306
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
2321
+ if (cli.flags['dryRun']) {
2322
+ return console.log('[DryRun] Bailing now');
2323
+ }
2307
2324
 
2308
2325
  // TODO: markdown flag is ignored
2309
2326
  await findDependencies({
@@ -2328,7 +2345,7 @@ async function getDiffScan({
2328
2345
  const data = await response.json();
2329
2346
  if (!response.ok) {
2330
2347
  const err = await handleAPIError(response.status);
2331
- spinner$1.error(`${colors.bgRed(colors.white(response.statusText))}: ${err}`);
2348
+ spinner$1.errorAndStop(`${colors.bgRed(colors.white(response.statusText))}: ${err}`);
2332
2349
  return;
2333
2350
  }
2334
2351
  spinner$1.stop();
@@ -2425,7 +2442,9 @@ async function run$u(argv, importMeta, {
2425
2442
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}\n`);
2426
2443
  return;
2427
2444
  }
2428
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
2445
+ if (cli.flags['dryRun']) {
2446
+ return console.log('[DryRun] Bailing now');
2447
+ }
2429
2448
  const apiToken = index.getDefaultToken();
2430
2449
  if (!apiToken) {
2431
2450
  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.');
@@ -2458,7 +2477,7 @@ const cmdDiffScan = {
2458
2477
  }
2459
2478
  };
2460
2479
 
2461
- // import { detect } from '../../utils/package-manager-detector'
2480
+ // import { detect } from '../../utils/package-environment-detector'
2462
2481
 
2463
2482
  const {
2464
2483
  NPM: NPM$d
@@ -2542,7 +2561,7 @@ async function runFix() {
2542
2561
  // eslint-disable-next-line no-await-in-loop
2543
2562
  await editablePkgJson.save();
2544
2563
  } catch {
2545
- spinner$1.error(`Reverting ${name} to ${oldVersion}`);
2564
+ spinner$1.errorAndStop(`Reverting ${name} to ${oldVersion}`);
2546
2565
  spinner$1.start();
2547
2566
  arb.idealTree = revertToIdealTree;
2548
2567
  }
@@ -2593,7 +2612,9 @@ async function run$t(argv, importMeta, {
2593
2612
  importMeta,
2594
2613
  parentName
2595
2614
  });
2596
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
2615
+ if (cli.flags['dryRun']) {
2616
+ return console.log('[DryRun] Bailing now');
2617
+ }
2597
2618
  await runFix();
2598
2619
  }
2599
2620
 
@@ -2720,7 +2741,7 @@ function formatPackageInfo({
2720
2741
  spinner[strict ? 'error' : 'success'](`Package has these issues: ${formatSeverityCount(severityCount)}`);
2721
2742
  formatPackageIssuesDetails(data, outputMarkdown);
2722
2743
  } else {
2723
- spinner.success('Package has no issues');
2744
+ spinner.successAndStop('Package has no issues');
2724
2745
  }
2725
2746
  const format = new index.ColorOrMarkdown(!!outputMarkdown);
2726
2747
  const url = index.getSocketDevPackageOverviewUrl(NPM$c, pkgName, pkgVersion);
@@ -2856,7 +2877,9 @@ async function run$s(argv, importMeta, {
2856
2877
  const versionSeparator = rawPkgName.lastIndexOf('@');
2857
2878
  const pkgName = versionSeparator < 1 ? rawPkgName : rawPkgName.slice(0, versionSeparator);
2858
2879
  const pkgVersion = versionSeparator < 1 ? 'latest' : rawPkgName.slice(versionSeparator + 1);
2859
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
2880
+ if (cli.flags['dryRun']) {
2881
+ return console.log('[DryRun] Bailing now');
2882
+ }
2860
2883
  await getPackageInfo({
2861
2884
  commandName: `${parentName} ${config$s.commandName}`,
2862
2885
  includeAllIssues: Boolean(cli.flags['all']),
@@ -2899,7 +2922,7 @@ async function attemptLogin(apiBaseUrl, apiProxy) {
2899
2922
  orgs = result.data;
2900
2923
  spinner$1.success('API key verified');
2901
2924
  } catch {
2902
- spinner$1.error('Invalid API key');
2925
+ spinner$1.errorAndStop('Invalid API key');
2903
2926
  return;
2904
2927
  }
2905
2928
  const enforcedChoices = Object.values(orgs.organizations).filter(org => org?.plan === 'enterprise').map(org => ({
@@ -2934,9 +2957,9 @@ async function attemptLogin(apiBaseUrl, apiProxy) {
2934
2957
  const oldToken = index.getSetting('apiToken');
2935
2958
  try {
2936
2959
  applyLogin(apiToken, enforcedOrgs, apiBaseUrl, apiProxy);
2937
- spinner$1.success(`API credentials ${oldToken ? 'updated' : 'set'}`);
2960
+ spinner$1.successAndStop(`API credentials ${oldToken ? 'updated' : 'set'}`);
2938
2961
  } catch {
2939
- spinner$1.error(`API login failed`);
2962
+ spinner$1.errorAndStop(`API login failed`);
2940
2963
  }
2941
2964
  }
2942
2965
 
@@ -2985,7 +3008,9 @@ async function run$r(argv, importMeta, {
2985
3008
  });
2986
3009
  let apiBaseUrl = cli.flags['apiBaseUrl'];
2987
3010
  let apiProxy = cli.flags['apiProxy'];
2988
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3011
+ if (cli.flags['dryRun']) {
3012
+ return console.log('[DryRun] Bailing now');
3013
+ }
2989
3014
  if (!isInteractive()) {
2990
3015
  throw new index.InputError('Cannot prompt for credentials in a non-interactive shell');
2991
3016
  }
@@ -3036,7 +3061,9 @@ async function run$q(argv, importMeta, {
3036
3061
  importMeta,
3037
3062
  parentName
3038
3063
  });
3039
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3064
+ if (cli.flags['dryRun']) {
3065
+ return console.log('[DryRun] Bailing now');
3066
+ }
3040
3067
  attemptLogout();
3041
3068
  }
3042
3069
 
@@ -3074,14 +3101,14 @@ async function convertGradleToMaven(target, bin, _out, verbose, gradleOpts) {
3074
3101
  const output = await spawn(bin, commandArgs, {
3075
3102
  cwd: target || '.'
3076
3103
  });
3077
- spinner$1.success();
3104
+ spinner$1.stop();
3078
3105
  if (verbose) {
3079
3106
  console.group('[VERBOSE] gradle stdout:');
3080
3107
  console.log(output);
3081
3108
  console.groupEnd();
3082
3109
  }
3083
3110
  if (output.stderr) {
3084
- spinner$1.error('There were errors while running gradle');
3111
+ spinner$1.errorAndStop('There were errors while running gradle');
3085
3112
  // (In verbose mode, stderr was printed above, no need to repeat it)
3086
3113
  if (!verbose) {
3087
3114
  console.group('[VERBOSE] stderr:');
@@ -3090,6 +3117,8 @@ async function convertGradleToMaven(target, bin, _out, verbose, gradleOpts) {
3090
3117
  }
3091
3118
  process.exit(1);
3092
3119
  }
3120
+ spinner$1.start();
3121
+ spinner$1.successAndStop('Executed gradle successfully');
3093
3122
  console.log('Reported exports:');
3094
3123
  output.stdout.replace(/^POM file copied to: (.*)/gm, (_all, fn) => {
3095
3124
  console.log('- ', fn);
@@ -3098,7 +3127,7 @@ async function convertGradleToMaven(target, bin, _out, verbose, gradleOpts) {
3098
3127
 
3099
3128
  // const loc = output.stdout?.match(/Wrote (.*?.pom)\n/)?.[1]?.trim()
3100
3129
  // if (!loc) {
3101
- // spinner.error(
3130
+ // spinner.errorAndStop(
3102
3131
  // 'There were no errors from sbt but could not find the location of resulting .pom file either'
3103
3132
  // )
3104
3133
  // process.exit(1)
@@ -3120,11 +3149,11 @@ async function convertGradleToMaven(target, bin, _out, verbose, gradleOpts) {
3120
3149
  // }
3121
3150
  // // TODO: do we prefer fs-extra? renaming can be gnarly on windows and fs-extra's version is better
3122
3151
  // await renamep(loc, out)
3123
- // spinner.success()
3152
+ // spinner.successAndStop()
3124
3153
  // spinner.start().success(`OK. File should be available in \`${out}\``)
3125
3154
  // }
3126
3155
  } catch (e) {
3127
- spinner$1.error('There was an unexpected error while running this' + (verbose ? '' : ' (use --verbose for details)'));
3156
+ spinner$1.errorAndStop('There was an unexpected error while running this' + (verbose ? '' : ' (use --verbose for details)'));
3128
3157
  if (verbose) {
3129
3158
  console.group('[VERBOSE] error:');
3130
3159
  console.log(e);
@@ -3265,7 +3294,9 @@ async function run$p(argv, importMeta, {
3265
3294
  if (cli.flags['gradleOpts']) {
3266
3295
  gradleOpts = cli.flags['gradleOpts'].split(' ').map(s => s.trim()).filter(Boolean);
3267
3296
  }
3268
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3297
+ if (cli.flags['dryRun']) {
3298
+ return console.log('[DryRun] Bailing now');
3299
+ }
3269
3300
  await convertGradleToMaven(target, bin, out, verbose, gradleOpts);
3270
3301
  }
3271
3302
 
@@ -3297,14 +3328,15 @@ async function convertSbtToMaven(target, bin, out, verbose, sbtOpts) {
3297
3328
  const output = await spawn(bin, ['makePom'].concat(sbtOpts), {
3298
3329
  cwd: target || '.'
3299
3330
  });
3300
- spinner$1.success();
3331
+ spinner$1.successAndStop();
3301
3332
  if (verbose) {
3302
3333
  console.group('[VERBOSE] sbt stdout:');
3303
3334
  console.log(output);
3304
3335
  console.groupEnd();
3305
3336
  }
3306
3337
  if (output.stderr) {
3307
- spinner$1.error('There were errors while running sbt');
3338
+ spinner$1.start();
3339
+ spinner$1.errorAndStop('There were errors while running sbt');
3308
3340
  // (In verbose mode, stderr was printed above, no need to repeat it)
3309
3341
  if (!verbose) {
3310
3342
  console.group('[VERBOSE] stderr:');
@@ -3319,7 +3351,7 @@ async function convertSbtToMaven(target, bin, out, verbose, sbtOpts) {
3319
3351
  return fn;
3320
3352
  });
3321
3353
  if (!poms.length) {
3322
- spinner$1.error('There were no errors from sbt but it seems to not have generated any poms either');
3354
+ spinner$1.errorAndStop('There were no errors from sbt but it seems to not have generated any poms either');
3323
3355
  process.exit(1);
3324
3356
  }
3325
3357
 
@@ -3351,7 +3383,7 @@ async function convertSbtToMaven(target, bin, out, verbose, sbtOpts) {
3351
3383
  spinner$1.start().success(`OK`);
3352
3384
  }
3353
3385
  } catch (e) {
3354
- spinner$1.error('There was an unexpected error while running this' + (verbose ? '' : ' (use --verbose for details)'));
3386
+ spinner$1.errorAndStop('There was an unexpected error while running this' + (verbose ? '' : ' (use --verbose for details)'));
3355
3387
  if (verbose) {
3356
3388
  console.group('[VERBOSE] error:');
3357
3389
  console.log(e);
@@ -3489,7 +3521,9 @@ async function run$o(argv, importMeta, {
3489
3521
  if (cli.flags['sbtOpts']) {
3490
3522
  sbtOpts = cli.flags['sbtOpts'].split(' ').map(s => s.trim()).filter(Boolean);
3491
3523
  }
3492
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3524
+ if (cli.flags['dryRun']) {
3525
+ return console.log('[DryRun] Bailing now');
3526
+ }
3493
3527
  await convertSbtToMaven(target, bin, out, verbose, sbtOpts);
3494
3528
  }
3495
3529
 
@@ -3557,7 +3591,9 @@ async function run$n(argv, importMeta, {
3557
3591
  subArgs.push('--cwd', cwd);
3558
3592
  }
3559
3593
  subArgs.push(dir);
3560
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3594
+ if (cli.flags['dryRun']) {
3595
+ return console.log('[DryRun] Bailing now');
3596
+ }
3561
3597
  await cmdManifestScala.run(subArgs, importMeta, {
3562
3598
  parentName
3563
3599
  });
@@ -3569,7 +3605,9 @@ async function run$n(argv, importMeta, {
3569
3605
  // This command takes the cwd as first arg.
3570
3606
  subArgs.push(cwd);
3571
3607
  }
3572
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3608
+ if (cli.flags['dryRun']) {
3609
+ return console.log('[DryRun] Bailing now');
3610
+ }
3573
3611
  await cmdManifestGradle.run(subArgs, importMeta, {
3574
3612
  parentName
3575
3613
  });
@@ -3732,7 +3770,9 @@ async function run$m(argv, importMeta, {
3732
3770
  if (cli.flags['gradleOpts']) {
3733
3771
  gradleOpts = cli.flags['gradleOpts'].split(' ').map(s => s.trim()).filter(Boolean);
3734
3772
  }
3735
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3773
+ if (cli.flags['dryRun']) {
3774
+ return console.log('[DryRun] Bailing now');
3775
+ }
3736
3776
  await convertGradleToMaven(target, bin, out, verbose, gradleOpts);
3737
3777
  }
3738
3778
 
@@ -3810,7 +3850,9 @@ async function run$k(argv, importMeta, {
3810
3850
  importMeta,
3811
3851
  parentName
3812
3852
  });
3813
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3853
+ if (cli.flags['dryRun']) {
3854
+ return console.log('[DryRun] Bailing now');
3855
+ }
3814
3856
  await wrapNpm(argv);
3815
3857
  }
3816
3858
 
@@ -3852,7 +3894,9 @@ async function run$j(argv, importMeta, {
3852
3894
  importMeta,
3853
3895
  parentName
3854
3896
  });
3855
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3897
+ if (cli.flags['dryRun']) {
3898
+ return console.log('[DryRun] Bailing now');
3899
+ }
3856
3900
  await wrapNpx(argv);
3857
3901
  }
3858
3902
 
@@ -3884,7 +3928,9 @@ async function run$i(argv, importMeta, {
3884
3928
  importMeta,
3885
3929
  parentName
3886
3930
  });
3887
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
3931
+ if (cli.flags['dryRun']) {
3932
+ return console.log('[DryRun] Bailing now');
3933
+ }
3888
3934
  throw new Error('This error was intentionally left blank');
3889
3935
  }
3890
3936
 
@@ -3902,16 +3948,7 @@ function matchHumanStdout(stdout, name) {
3902
3948
  function matchQueryStdout(stdout, name) {
3903
3949
  return stdout.includes(`"${name}"`);
3904
3950
  }
3905
- const depsIncludesByAgent = {
3906
- // @ts-ignore
3907
- __proto__: null,
3908
- [BUN$6]: matchHumanStdout,
3909
- [NPM$9]: matchQueryStdout,
3910
- [PNPM$7]: matchQueryStdout,
3911
- [VLT$6]: matchQueryStdout,
3912
- [YARN_BERRY$6]: matchHumanStdout,
3913
- [YARN_CLASSIC$6]: matchHumanStdout
3914
- };
3951
+ const depsIncludesByAgent = new Map([[BUN$6, matchHumanStdout], [NPM$9, matchQueryStdout], [PNPM$7, matchQueryStdout], [VLT$6, matchQueryStdout], [YARN_BERRY$6, matchHumanStdout], [YARN_CLASSIC$6, matchHumanStdout]]);
3915
3952
 
3916
3953
  const {
3917
3954
  BINARY_LOCK_EXT,
@@ -4011,15 +4048,15 @@ const readLockFileByAgent = (() => {
4011
4048
  [YARN_CLASSIC$5]: defaultReader
4012
4049
  };
4013
4050
  })();
4014
- async function detect({
4051
+ async function detectPackageEnvironment({
4015
4052
  cwd = process$1.cwd(),
4016
4053
  onUnknown
4017
4054
  } = {}) {
4018
4055
  let lockPath = await index.findUp(Object.keys(LOCKS), {
4019
4056
  cwd
4020
4057
  });
4021
- let lockBasename = lockPath ? path.basename(lockPath) : undefined;
4022
- const isHiddenLockFile = lockBasename === '.package-lock.json';
4058
+ let lockName = lockPath ? path.basename(lockPath) : undefined;
4059
+ const isHiddenLockFile = lockName === '.package-lock.json';
4023
4060
  const pkgJsonPath = lockPath ? path.resolve(lockPath, `${isHiddenLockFile ? '../' : ''}../package.json`) : await index.findUp('package.json', {
4024
4061
  cwd
4025
4062
  });
@@ -4044,8 +4081,8 @@ async function detect({
4044
4081
  }
4045
4082
  }
4046
4083
  }
4047
- if (agent === undefined && !isHiddenLockFile && typeof pkgJsonPath === 'string' && typeof lockBasename === 'string') {
4048
- agent = LOCKS[lockBasename];
4084
+ if (agent === undefined && !isHiddenLockFile && typeof pkgJsonPath === 'string' && typeof lockName === 'string') {
4085
+ agent = LOCKS[lockName];
4049
4086
  }
4050
4087
  if (agent === undefined) {
4051
4088
  agent = NPM$8;
@@ -4096,14 +4133,14 @@ async function detect({
4096
4133
  targets.node = constants.maintainedNodeVersions.some(v => semver.satisfies(v, `>=${minimumNodeVersion}`));
4097
4134
  lockSrc = typeof lockPath === 'string' ? await readLockFileByAgent[agent](lockPath, agentExecPath) : undefined;
4098
4135
  } else {
4099
- lockBasename = undefined;
4136
+ lockName = undefined;
4100
4137
  lockPath = undefined;
4101
4138
  }
4102
4139
  return {
4103
4140
  agent,
4104
4141
  agentExecPath,
4105
4142
  agentVersion,
4106
- lockBasename,
4143
+ lockName,
4107
4144
  lockPath,
4108
4145
  lockSrc,
4109
4146
  minimumNodeVersion,
@@ -4117,74 +4154,53 @@ async function detect({
4117
4154
 
4118
4155
  const {
4119
4156
  BUN: BUN$4,
4120
- NPM: NPM$7,
4121
4157
  VLT: VLT$4,
4122
4158
  YARN_BERRY: YARN_BERRY$4
4123
4159
  } = constants;
4124
4160
  const COMMAND_TITLE$2 = 'Socket Optimize';
4125
- const manifestNpmOverrides = registry.getManifestData(NPM$7);
4126
- async function detectAndValidatePackageManager(cwd, prod) {
4161
+ async function detectAndValidatePackageEnvironment(cwd, options) {
4127
4162
  const {
4128
- agent,
4129
- agentExecPath,
4130
- agentVersion,
4131
- lockBasename,
4132
- lockPath,
4133
- lockSrc,
4134
- minimumNodeVersion,
4135
- npmExecPath,
4136
- pkgJson,
4137
- pkgPath,
4138
- supported
4139
- } = await detect({
4163
+ logger,
4164
+ prod
4165
+ } = {
4166
+ __proto__: null,
4167
+ ...options
4168
+ };
4169
+ const details = await detectPackageEnvironment({
4140
4170
  cwd,
4141
4171
  onUnknown(pkgManager) {
4142
- console.warn(`⚠️ ${COMMAND_TITLE$2}: Unknown package manager${pkgManager ? ` ${pkgManager}` : ''}, defaulting to npm`);
4172
+ logger?.warn(`⚠️ ${COMMAND_TITLE$2}: Unknown package manager${pkgManager ? ` ${pkgManager}` : ''}, defaulting to npm`);
4143
4173
  }
4144
4174
  });
4145
- if (!supported) {
4146
- console.error(`✖️ ${COMMAND_TITLE$2}: No supported Node or browser range detected`);
4175
+ if (!details.supported) {
4176
+ logger?.error(`✖️ ${COMMAND_TITLE$2}: No supported Node or browser range detected`);
4147
4177
  return;
4148
4178
  }
4149
- if (agent === VLT$4) {
4150
- console.error(`✖️ ${COMMAND_TITLE$2}: ${agent} does not support overrides. Soon, though ⚡`);
4179
+ if (details.agent === VLT$4) {
4180
+ logger?.error(`✖️ ${COMMAND_TITLE$2}: ${details.agent} does not support overrides. Soon, though ⚡`);
4151
4181
  return;
4152
4182
  }
4153
- const lockName = lockPath && lockBasename ? lockBasename : 'lock file';
4154
- if (lockBasename === undefined || lockSrc === undefined) {
4155
- console.error(`✖️ ${COMMAND_TITLE$2}: No ${lockName} found`);
4183
+ const lockName = details.lockName ?? 'lock file';
4184
+ if (details.lockName === undefined || details.lockSrc === undefined) {
4185
+ logger?.error(`✖️ ${COMMAND_TITLE$2}: No ${lockName} found`);
4156
4186
  return;
4157
4187
  }
4158
- if (lockSrc.trim() === '') {
4159
- console.error(`✖️ ${COMMAND_TITLE$2}: ${lockName} is empty`);
4188
+ if (details.lockSrc.trim() === '') {
4189
+ logger?.error(`✖️ ${COMMAND_TITLE$2}: ${lockName} is empty`);
4160
4190
  return;
4161
4191
  }
4162
- if (pkgPath === undefined) {
4163
- console.error(`✖️ ${COMMAND_TITLE$2}: No package.json found`);
4192
+ if (details.pkgPath === undefined) {
4193
+ logger?.error(`✖️ ${COMMAND_TITLE$2}: No package.json found`);
4164
4194
  return;
4165
4195
  }
4166
- if (prod && (agent === BUN$4 || agent === YARN_BERRY$4)) {
4167
- console.error(`✖️ ${COMMAND_TITLE$2}: --prod not supported for ${agent}${agentVersion ? `@${agentVersion.toString()}` : ''}`);
4196
+ if (prod && (details.agent === BUN$4 || details.agent === YARN_BERRY$4)) {
4197
+ logger?.error(`✖️ ${COMMAND_TITLE$2}: --prod not supported for ${details.agent}${details.agentVersion ? `@${details.agentVersion.toString()}` : ''}`);
4168
4198
  return;
4169
4199
  }
4170
- if (lockPath && path.relative(cwd, lockPath).startsWith('.')) {
4171
- console.warn(`⚠️ ${COMMAND_TITLE$2}: Package ${lockName} found at ${lockPath}`);
4200
+ if (details.lockPath && path.relative(cwd, details.lockPath).startsWith('.')) {
4201
+ logger?.warn(`⚠️ ${COMMAND_TITLE$2}: Package ${lockName} found at ${details.lockPath}`);
4172
4202
  }
4173
- const nodeRange = `>=${minimumNodeVersion}`;
4174
- const manifestEntries = manifestNpmOverrides.filter(({
4175
- 1: data
4176
- }) => semver.satisfies(semver.coerce(data.engines.node), nodeRange));
4177
- return {
4178
- agent,
4179
- agentExecPath,
4180
- lockBasename,
4181
- lockName,
4182
- lockSrc,
4183
- manifestEntries,
4184
- npmExecPath,
4185
- pkgJson,
4186
- pkgPath
4187
- };
4203
+ return details;
4188
4204
  }
4189
4205
 
4190
4206
  function getDependencyEntries(pkgJson) {
@@ -4213,7 +4229,7 @@ function getDependencyEntries(pkgJson) {
4213
4229
 
4214
4230
  const {
4215
4231
  BUN: BUN$3,
4216
- NPM: NPM$6,
4232
+ NPM: NPM$7,
4217
4233
  OVERRIDES: OVERRIDES$1,
4218
4234
  PNPM: PNPM$5,
4219
4235
  RESOLUTIONS: RESOLUTIONS$1,
@@ -4234,7 +4250,7 @@ function getOverridesDataBun(pkgJson) {
4234
4250
  function getOverridesDataNpm(pkgJson) {
4235
4251
  const overrides = pkgJson?.[OVERRIDES$1] ?? {};
4236
4252
  return {
4237
- type: NPM$6,
4253
+ type: NPM$7,
4238
4254
  overrides
4239
4255
  };
4240
4256
  }
@@ -4275,16 +4291,7 @@ function getOverridesDataClassic(pkgJson) {
4275
4291
  overrides
4276
4292
  };
4277
4293
  }
4278
- const getOverridesDataByAgent = {
4279
- // @ts-ignore
4280
- __proto__: null,
4281
- [BUN$3]: getOverridesDataBun,
4282
- [NPM$6]: getOverridesDataNpm,
4283
- [PNPM$5]: getOverridesDataPnpm,
4284
- [VLT$3]: getOverridesDataVlt,
4285
- [YARN_BERRY$3]: getOverridesDataYarn,
4286
- [YARN_CLASSIC$4]: getOverridesDataClassic
4287
- };
4294
+ const overridesDataByAgent = new Map([[BUN$3, getOverridesDataBun], [NPM$7, getOverridesDataNpm], [PNPM$5, getOverridesDataPnpm], [VLT$3, getOverridesDataVlt], [YARN_BERRY$3, getOverridesDataYarn], [YARN_CLASSIC$4, getOverridesDataClassic]]);
4288
4295
 
4289
4296
  const {
4290
4297
  PNPM: PNPM$4
@@ -4332,7 +4339,7 @@ function workspacePatternToGlobPattern(workspace) {
4332
4339
  const {
4333
4340
  BUN: BUN$2,
4334
4341
  LOCK_EXT,
4335
- NPM: NPM$5,
4342
+ NPM: NPM$6,
4336
4343
  PNPM: PNPM$3,
4337
4344
  VLT: VLT$2,
4338
4345
  YARN_BERRY: YARN_BERRY$2,
@@ -4343,12 +4350,12 @@ function lockIncludesNpm(lockSrc, name) {
4343
4350
  // "name":
4344
4351
  return lockSrc.includes(`"${name}":`);
4345
4352
  }
4346
- function lockIncludesBun(lockSrc, name, lockBasename) {
4347
- // This is a bit counterintuitive. When lockBasename ends with a .lockb
4348
- // we treat it as a yarn.lock. When lockBasename ends with a .lock we
4353
+ function lockIncludesBun(lockSrc, name, lockName) {
4354
+ // This is a bit counterintuitive. When lockName ends with a .lockb
4355
+ // we treat it as a yarn.lock. When lockName ends with a .lock we
4349
4356
  // treat it as a package-lock.json. The bun.lock format is not identical
4350
4357
  // package-lock.json, however it close enough for npmLockIncludes to work.
4351
- const lockScanner = lockBasename?.endsWith(LOCK_EXT) ? lockIncludesNpm : lockIncludesYarn;
4358
+ const lockScanner = lockName?.endsWith(LOCK_EXT) ? lockIncludesNpm : lockIncludesYarn;
4352
4359
  return lockScanner(lockSrc, name);
4353
4360
  }
4354
4361
  function lockIncludesPnpm(lockSrc, name) {
@@ -4376,20 +4383,11 @@ function lockIncludesYarn(lockSrc, name) {
4376
4383
  // , name@
4377
4384
  `(?<=(?:^\\s*|,\\s*)"?)${escapedName}(?=@)`, 'm').test(lockSrc);
4378
4385
  }
4379
- const lockIncludesByAgent = {
4380
- // @ts-ignore
4381
- __proto__: null,
4382
- [BUN$2]: lockIncludesBun,
4383
- [NPM$5]: lockIncludesNpm,
4384
- [PNPM$3]: lockIncludesPnpm,
4385
- [VLT$2]: lockIncludesVlt,
4386
- [YARN_BERRY$2]: lockIncludesYarn,
4387
- [YARN_CLASSIC$3]: lockIncludesYarn
4388
- };
4386
+ const lockIncludesByAgent = new Map([[BUN$2, lockIncludesBun], [NPM$6, lockIncludesNpm], [PNPM$3, lockIncludesPnpm], [VLT$2, lockIncludesVlt], [YARN_BERRY$2, lockIncludesYarn], [YARN_CLASSIC$3, lockIncludesYarn]]);
4389
4387
 
4390
4388
  const {
4391
4389
  BUN: BUN$1,
4392
- NPM: NPM$4,
4390
+ NPM: NPM$5,
4393
4391
  PNPM: PNPM$2,
4394
4392
  VLT: VLT$1,
4395
4393
  YARN_BERRY: YARN_BERRY$1,
@@ -4459,7 +4457,7 @@ async function lsNpm(agentExecPath, cwd) {
4459
4457
  }
4460
4458
  async function lsPnpm(agentExecPath, cwd, options) {
4461
4459
  const npmExecPath = options?.npmExecPath;
4462
- if (npmExecPath && npmExecPath !== NPM$4) {
4460
+ if (npmExecPath && npmExecPath !== NPM$5) {
4463
4461
  const result = await npmQuery(npmExecPath, cwd);
4464
4462
  if (result) {
4465
4463
  return result;
@@ -4510,7 +4508,7 @@ const lsByAgent = {
4510
4508
  // @ts-ignore
4511
4509
  __proto__: null,
4512
4510
  [BUN$1]: lsBun,
4513
- [NPM$4]: lsNpm,
4511
+ [NPM$5]: lsNpm,
4514
4512
  [PNPM$2]: lsPnpm,
4515
4513
  [VLT$1]: lsVlt,
4516
4514
  [YARN_BERRY$1]: lsYarnBerry,
@@ -4519,7 +4517,7 @@ const lsByAgent = {
4519
4517
 
4520
4518
  const {
4521
4519
  BUN,
4522
- NPM: NPM$3,
4520
+ NPM: NPM$4,
4523
4521
  OVERRIDES,
4524
4522
  PNPM: PNPM$1,
4525
4523
  RESOLUTIONS,
@@ -4623,55 +4621,75 @@ function updateResolutions(editablePkgJson, overrides) {
4623
4621
  function pnpmUpdatePkgJson(editablePkgJson, overrides) {
4624
4622
  updatePkgJson(editablePkgJson, PNPM_FIELD_NAME, overrides);
4625
4623
  }
4626
- const updateManifestByAgent = {
4627
- // @ts-ignore
4628
- __proto__: null,
4629
- [BUN]: updateResolutions,
4630
- [NPM$3]: updateOverrides,
4631
- [PNPM$1]: pnpmUpdatePkgJson,
4632
- [VLT]: updateOverrides,
4633
- [YARN_BERRY]: updateResolutions,
4634
- [YARN_CLASSIC$1]: updateResolutions
4635
- };
4624
+ const updateManifestByAgent = new Map([[BUN, updateResolutions], [NPM$4, updateOverrides], [PNPM$1, pnpmUpdatePkgJson], [VLT, updateOverrides], [YARN_BERRY, updateResolutions], [YARN_CLASSIC$1, updateResolutions]]);
4636
4625
 
4637
4626
  const {
4638
- NPM: NPM$2,
4639
- SOCKET_CLI_SAFE_WRAPPER,
4627
+ NPM: NPM$3,
4640
4628
  abortSignal: abortSignal$2
4641
4629
  } = constants;
4630
+ function runAgentInstall(agent, agentExecPath, options) {
4631
+ // All package managers support the "install" command.
4632
+ if (agent === NPM$3) {
4633
+ return npm$1.safeNpmInstall(options);
4634
+ }
4635
+ const {
4636
+ args = [],
4637
+ spinner,
4638
+ ...spawnOptions
4639
+ } = {
4640
+ __proto__: null,
4641
+ ...options
4642
+ };
4643
+ const isSilent = !npmPaths.isDebug();
4644
+ const isSpinning = spinner?.isSpinning ?? false;
4645
+ if (!isSilent) {
4646
+ spinner?.stop();
4647
+ }
4648
+ let spawnPromise = spawn(agentExecPath, ['install', ...args], {
4649
+ signal: abortSignal$2,
4650
+ stdio: isSilent ? 'ignore' : 'inherit',
4651
+ ...spawnOptions,
4652
+ env: {
4653
+ ...process.env,
4654
+ ...spawnOptions.env
4655
+ }
4656
+ });
4657
+ if (!isSilent && isSpinning) {
4658
+ const oldSpawnPromise = spawnPromise;
4659
+ spawnPromise = spawnPromise.finally(() => {
4660
+ spinner?.start();
4661
+ });
4662
+ spawnPromise.process = oldSpawnPromise.process;
4663
+ spawnPromise.stdin = spawnPromise.stdin;
4664
+ }
4665
+ return spawnPromise;
4666
+ }
4667
+
4668
+ const {
4669
+ NPM: NPM$2
4670
+ } = constants;
4642
4671
  const COMMAND_TITLE$1 = 'Socket Optimize';
4643
4672
  const NPM_OVERRIDE_PR_URL = 'https://github.com/npm/cli/pull/8089';
4644
- async function updatePackageLockJson(lockName, agentExecPath, agent, spinner) {
4645
- spinner.start(`Updating ${lockName}...`);
4673
+ async function updatePackageLockJson(pkgEnvDetails, options) {
4674
+ const {
4675
+ logger,
4676
+ spinner
4677
+ } = {
4678
+ __proto__: null,
4679
+ ...options
4680
+ };
4681
+ spinner?.start(`Updating ${pkgEnvDetails.lockName}...`);
4646
4682
  try {
4647
- if (agent === NPM$2) {
4648
- const ipc = {
4649
- [SOCKET_CLI_SAFE_WRAPPER]: true
4650
- };
4651
- await npm$1.safeNpmInstall({
4652
- ipc
4653
- });
4654
- // TODO: This is a temporary workaround for a `npm ci` bug where it
4655
- // will error out after Socket Optimize generates a lock file.
4656
- // More investigation is needed.
4657
- await npm$1.safeNpmInstall({
4658
- args: ['--ignore-scripts', '--package-lock-only'],
4659
- ipc
4660
- });
4661
- } else {
4662
- // All package managers support the "install" command.
4663
- await spawn(agentExecPath, ['install'], {
4664
- signal: abortSignal$2,
4665
- stdio: 'ignore'
4666
- });
4667
- }
4668
- spinner.stop();
4669
- if (agent === NPM$2) {
4670
- console.log(`💡 Re-run ${COMMAND_TITLE$1} whenever ${lockName} changes.\n This can be skipped once npm ships ${NPM_OVERRIDE_PR_URL}.`);
4683
+ await runAgentInstall(pkgEnvDetails.agent, pkgEnvDetails.agentExecPath, {
4684
+ spinner
4685
+ });
4686
+ spinner?.stop();
4687
+ if (pkgEnvDetails.agent === NPM$2) {
4688
+ logger?.log(`💡 Re-run ${COMMAND_TITLE$1} whenever ${pkgEnvDetails.lockName} changes.\n This can be skipped once npm ships ${NPM_OVERRIDE_PR_URL}.`);
4671
4689
  }
4672
4690
  } catch (e) {
4673
- spinner.error(`${COMMAND_TITLE$1}: ${agent} install failed to update ${lockName}`);
4674
- console.error(e);
4691
+ spinner?.error(`${COMMAND_TITLE$1}: ${pkgEnvDetails.agent} install failed to update ${pkgEnvDetails.lockName}`);
4692
+ logger?.error(e);
4675
4693
  }
4676
4694
  }
4677
4695
 
@@ -4681,91 +4699,85 @@ const {
4681
4699
  YARN_CLASSIC
4682
4700
  } = constants;
4683
4701
  const COMMAND_TITLE = 'Socket Optimize';
4702
+ const manifestNpmOverrides = registry.getManifestData(NPM$1);
4684
4703
  async function applyOptimization(cwd, pin, prod) {
4685
- const pkgMgrData = await detectAndValidatePackageManager(cwd, prod);
4686
- if (!pkgMgrData) return;
4687
- const {
4688
- agent,
4689
- agentExecPath,
4690
- lockBasename,
4691
- lockName,
4692
- lockSrc,
4693
- manifestEntries,
4694
- npmExecPath,
4695
- pkgJson,
4696
- pkgPath
4697
- } = pkgMgrData;
4704
+ const logger = console;
4705
+ const pkgEnvDetails = await detectAndValidatePackageEnvironment(cwd, {
4706
+ logger,
4707
+ prod
4708
+ });
4709
+ if (!pkgEnvDetails) {
4710
+ return;
4711
+ }
4698
4712
  const spinner$1 = new spinner.Spinner({
4699
4713
  text: 'Socket optimizing...'
4700
4714
  });
4701
4715
  spinner$1.start();
4702
- const state = await addOverrides({
4703
- agent,
4704
- agentExecPath,
4705
- lockBasename,
4706
- lockSrc,
4707
- manifestEntries,
4708
- npmExecPath,
4716
+ const state = await addOverrides(pkgEnvDetails.pkgPath, pkgEnvDetails, {
4717
+ logger,
4709
4718
  pin,
4710
- pkgJson,
4711
- pkgPath,
4712
4719
  prod,
4713
- rootPath: pkgPath
4714
- }, createAddOverridesState(spinner$1));
4720
+ spinner: spinner$1
4721
+ });
4715
4722
  spinner$1.stop();
4716
4723
  const addedCount = state.added.size;
4717
4724
  const updatedCount = state.updated.size;
4718
4725
  const pkgJsonChanged = addedCount > 0 || updatedCount > 0;
4719
4726
  if (pkgJsonChanged) {
4720
4727
  if (updatedCount > 0) {
4721
- console.log(`${createActionMessage('Updated', updatedCount, state.updatedInWorkspaces.size)}${addedCount ? '.' : '🚀'}`);
4728
+ logger?.log(`${createActionMessage('Updated', updatedCount, state.updatedInWorkspaces.size)}${addedCount ? '.' : '🚀'}`);
4722
4729
  }
4723
4730
  if (addedCount > 0) {
4724
- console.log(`${createActionMessage('Added', addedCount, state.addedInWorkspaces.size)} 🚀`);
4731
+ logger?.log(`${createActionMessage('Added', addedCount, state.addedInWorkspaces.size)} 🚀`);
4725
4732
  }
4726
4733
  } else {
4727
- console.log('Congratulations! Already Socket.dev optimized 🎉');
4734
+ logger?.log('Congratulations! Already Socket.dev optimized 🎉');
4728
4735
  }
4729
- if (agent === NPM$1 || pkgJsonChanged) {
4736
+ if (pkgEnvDetails.agent === NPM$1 || pkgJsonChanged) {
4730
4737
  // Always update package-lock.json until the npm overrides PR lands:
4731
4738
  // https://github.com/npm/cli/pull/8089
4732
- await updatePackageLockJson(lockName, agentExecPath, agent, spinner$1);
4739
+ await updatePackageLockJson(pkgEnvDetails, {
4740
+ logger,
4741
+ spinner: spinner$1
4742
+ });
4733
4743
  }
4734
4744
  }
4735
4745
  function createActionMessage(verb, overrideCount, workspaceCount) {
4736
4746
  return `${verb} ${overrideCount} Socket.dev optimized ${words.pluralize('override', overrideCount)}${workspaceCount ? ` in ${workspaceCount} ${words.pluralize('workspace', workspaceCount)}` : ''}`;
4737
4747
  }
4738
- function createAddOverridesState(spinner) {
4739
- return {
4740
- added: new Set(),
4741
- addedInWorkspaces: new Set(),
4748
+ async function addOverrides(pkgPath, pkgEnvDetails, options) {
4749
+ const {
4750
+ agent,
4751
+ agentExecPath,
4752
+ lockName,
4753
+ lockSrc,
4754
+ npmExecPath,
4755
+ pkgPath: rootPath
4756
+ } = pkgEnvDetails;
4757
+ const {
4758
+ logger,
4759
+ pin,
4760
+ prod,
4742
4761
  spinner,
4743
- updated: new Set(),
4744
- updatedInWorkspaces: new Set(),
4745
- warnedPnpmWorkspaceRequiresNpm: false
4762
+ state = {
4763
+ added: new Set(),
4764
+ addedInWorkspaces: new Set(),
4765
+ updated: new Set(),
4766
+ updatedInWorkspaces: new Set(),
4767
+ warnedPnpmWorkspaceRequiresNpm: false
4768
+ }
4769
+ } = {
4770
+ __proto__: null,
4771
+ ...options
4746
4772
  };
4747
- }
4748
- async function addOverrides({
4749
- agent,
4750
- agentExecPath,
4751
- lockBasename,
4752
- lockSrc,
4753
- manifestEntries,
4754
- npmExecPath,
4755
- pin,
4756
- pkgJson: editablePkgJson,
4757
- pkgPath,
4758
- prod,
4759
- rootPath
4760
- }, state) {
4773
+ let {
4774
+ pkgJson: editablePkgJson
4775
+ } = pkgEnvDetails;
4761
4776
  if (editablePkgJson === undefined) {
4762
4777
  editablePkgJson = await packages.readPackageJson(pkgPath, {
4763
4778
  editable: true
4764
4779
  });
4765
4780
  }
4766
- const {
4767
- spinner
4768
- } = state;
4769
4781
  const {
4770
4782
  content: pkgJson
4771
4783
  } = editablePkgJson;
@@ -4776,7 +4788,7 @@ async function addOverrides({
4776
4788
  const isWorkspace = !!workspaceGlobs;
4777
4789
  if (isWorkspace && agent === PNPM && npmExecPath === NPM$1 && !state.warnedPnpmWorkspaceRequiresNpm) {
4778
4790
  state.warnedPnpmWorkspaceRequiresNpm = true;
4779
- console.warn(`⚠️ ${COMMAND_TITLE}: pnpm workspace support requires \`npm ls\`, falling back to \`pnpm list\``);
4791
+ logger?.warn(`⚠️ ${COMMAND_TITLE}: pnpm workspace support requires \`npm ls\`, falling back to \`pnpm list\``);
4780
4792
  }
4781
4793
  const thingToScan = isLockScanned ? lockSrc : await lsByAgent[agent](agentExecPath, pkgPath, {
4782
4794
  npmExecPath
@@ -4785,18 +4797,22 @@ async function addOverrides({
4785
4797
  // first two parameters. AgentLockIncludesFn accepts an optional third
4786
4798
  // parameter which AgentDepsIncludesFn will ignore so we cast thingScanner
4787
4799
  // as an AgentLockIncludesFn type.
4788
- const thingScanner = isLockScanned ? lockIncludesByAgent[agent] : depsIncludesByAgent[agent];
4800
+ const thingScanner = isLockScanned ? lockIncludesByAgent.get(agent) : depsIncludesByAgent.get(agent);
4789
4801
  const depEntries = getDependencyEntries(pkgJson);
4790
4802
  const overridesDataObjects = [];
4791
4803
  if (pkgJson['private'] || isWorkspace) {
4792
- overridesDataObjects.push(getOverridesDataByAgent[agent](pkgJson));
4804
+ overridesDataObjects.push(overridesDataByAgent.get(agent)(pkgJson));
4793
4805
  } else {
4794
- overridesDataObjects.push(getOverridesDataByAgent[NPM$1](pkgJson), getOverridesDataByAgent[YARN_CLASSIC](pkgJson));
4806
+ overridesDataObjects.push(overridesDataByAgent.get(NPM$1)(pkgJson), overridesDataByAgent.get(YARN_CLASSIC)(pkgJson));
4795
4807
  }
4796
4808
  if (spinner) {
4797
4809
  spinner.text = `Adding overrides${workspaceName ? ` to ${workspaceName}` : ''}...`;
4798
4810
  }
4799
4811
  const depAliasMap = new Map();
4812
+ const nodeRange = `>=${pkgEnvDetails.minimumNodeVersion}`;
4813
+ const manifestEntries = manifestNpmOverrides.filter(({
4814
+ 1: data
4815
+ }) => semver.satisfies(semver.coerce(data.engines.node), nodeRange));
4800
4816
  // Chunk package names to process them in parallel 3 at a time.
4801
4817
  await promises.pEach(manifestEntries, 3, async ({
4802
4818
  1: data
@@ -4839,7 +4855,7 @@ async function addOverrides({
4839
4855
  type
4840
4856
  }) => {
4841
4857
  const overrideExists = objects.hasOwn(overrides, origPkgName);
4842
- if (overrideExists || thingScanner(thingToScan, origPkgName, lockBasename)) {
4858
+ if (overrideExists || thingScanner(thingToScan, origPkgName, lockName)) {
4843
4859
  const oldSpec = overrideExists ? overrides[origPkgName] : undefined;
4844
4860
  const origDepAlias = depAliasMap.get(origPkgName);
4845
4861
  const sockRegDepAlias = depAliasMap.get(sockRegPkgName);
@@ -4884,18 +4900,12 @@ async function addOverrides({
4884
4900
  });
4885
4901
  // Chunk package names to process them in parallel 3 at a time.
4886
4902
  await promises.pEach(workspacePkgJsonPaths, 3, async workspacePkgJsonPath => {
4887
- const otherState = await addOverrides({
4888
- agent,
4889
- agentExecPath,
4890
- lockBasename,
4891
- lockSrc,
4892
- manifestEntries,
4893
- npmExecPath,
4903
+ const otherState = await addOverrides(path.dirname(workspacePkgJsonPath), pkgEnvDetails, {
4904
+ logger,
4894
4905
  pin,
4895
- pkgPath: path.dirname(workspacePkgJsonPath),
4896
4906
  prod,
4897
- rootPath
4898
- }, createAddOverridesState(spinner));
4907
+ spinner
4908
+ });
4899
4909
  for (const key of ['added', 'addedInWorkspaces', 'updated', 'updatedInWorkspaces']) {
4900
4910
  for (const value of otherState[key]) {
4901
4911
  state[key].add(value);
@@ -4909,7 +4919,7 @@ async function addOverrides({
4909
4919
  overrides,
4910
4920
  type
4911
4921
  } of overridesDataObjects) {
4912
- updateManifestByAgent[type](editablePkgJson, objects.toSortedObject(overrides));
4922
+ updateManifestByAgent.get(type)(editablePkgJson, objects.toSortedObject(overrides));
4913
4923
  }
4914
4924
  await editablePkgJson.save();
4915
4925
  }
@@ -4960,32 +4970,74 @@ async function run$h(argv, importMeta, {
4960
4970
  parentName
4961
4971
  });
4962
4972
  const cwd = process$1.cwd();
4963
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
4973
+ if (cli.flags['dryRun']) {
4974
+ return console.log('[DryRun] Bailing now');
4975
+ }
4964
4976
  await applyOptimization(cwd, Boolean(cli.flags['pin']), Boolean(cli.flags['prod']));
4965
4977
  }
4966
4978
 
4967
- async function getOrganizations() {
4979
+ async function getOrganization(format = 'text') {
4968
4980
  const apiToken = index.getDefaultToken();
4969
4981
  if (!apiToken) {
4970
4982
  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.');
4971
4983
  }
4984
+ await printOrganizationsFromToken(apiToken, format);
4985
+ }
4986
+ async function printOrganizationsFromToken(apiToken, format = 'text') {
4972
4987
  const spinner$1 = new spinner.Spinner({
4973
4988
  text: 'Fetching organizations...'
4974
4989
  }).start();
4975
4990
  const socketSdk = await index.setupSdk(apiToken);
4976
4991
  const result = await handleApiCall(socketSdk.getOrganizations(), 'looking up organizations');
4977
- if (result.success === false) {
4992
+ if (!result.success) {
4978
4993
  handleUnsuccessfulApiResponse('getOrganizations', result, spinner$1);
4979
4994
  return;
4980
4995
  }
4981
- spinner$1.stop(`List of organizations associated with your API key: ${colors.italic(apiToken)}`);
4996
+ spinner$1.stop();
4982
4997
  const organizations = Object.values(result.data.organizations);
4983
- for (const o of organizations) {
4984
- console.log(`
4985
- Name: ${o?.name}
4986
- ID: ${o?.id}
4987
- Plan: ${o?.plan}
4988
- `);
4998
+ const lastFiveOfApiToken = getLastFiveOfApiToken(apiToken);
4999
+ switch (format) {
5000
+ case 'json':
5001
+ {
5002
+ console.log(JSON.stringify(organizations.map(o => ({
5003
+ name: o.name,
5004
+ id: o.id,
5005
+ plan: o.plan
5006
+ })), null, 2));
5007
+ return;
5008
+ }
5009
+ case 'markdown':
5010
+ {
5011
+ // | Syntax | Description |
5012
+ // | ----------- | ----------- |
5013
+ // | Header | Title |
5014
+ // | Paragraph | Text |
5015
+ let mw1 = 4;
5016
+ let mw2 = 2;
5017
+ let mw3 = 4;
5018
+ for (const o of organizations) {
5019
+ mw1 = Math.max(mw1, o.name.length);
5020
+ mw2 = Math.max(mw2, o.id.length);
5021
+ mw3 = Math.max(mw3, o.plan.length);
5022
+ }
5023
+ console.log('# Organizations\n');
5024
+ console.log(`List of organizations associated with your API key, ending with: ${colors.italic(lastFiveOfApiToken)}\n`);
5025
+ console.log(`| Name${' '.repeat(mw1 - 4)} | ID${' '.repeat(mw2 - 2)} | Plan${' '.repeat(mw3 - 4)} |`);
5026
+ console.log(`| ${'-'.repeat(mw1)} | ${'-'.repeat(mw2)} | ${'-'.repeat(mw3)} |`);
5027
+ for (const o of organizations) {
5028
+ console.log(`| ${(o.name || '').padEnd(mw1, ' ')} | ${(o.id || '').padEnd(mw2, ' ')} | ${(o.plan || '').padEnd(mw3, ' ')} |`);
5029
+ }
5030
+ console.log(`| ${'-'.repeat(mw1)} | ${'-'.repeat(mw2)} | ${'-'.repeat(mw3)} |`);
5031
+ return;
5032
+ }
5033
+ default:
5034
+ {
5035
+ console.log(`List of organizations associated with your API key, ending with: ${colors.italic(lastFiveOfApiToken)}\n`);
5036
+ // Just dump
5037
+ for (const o of organizations) {
5038
+ console.log(`- Name: ${colors.bold(o.name)}, ID: ${colors.bold(o.id)}, Plan: ${colors.bold(o.plan)}`);
5039
+ }
5040
+ }
4989
5041
  }
4990
5042
  }
4991
5043
 
@@ -4993,13 +5045,19 @@ const config$g = {
4993
5045
  commandName: 'organizations',
4994
5046
  description: 'List organizations associated with the API key used',
4995
5047
  hidden: false,
4996
- flags: {},
5048
+ flags: {
5049
+ ...commonFlags,
5050
+ ...outputFlags
5051
+ },
4997
5052
  help: (command, _config) => `
4998
5053
  Usage
4999
5054
  $ ${command}
5055
+
5056
+ Options
5057
+ ${getFlagListOutput(config$g.flags, 6)}
5000
5058
  `
5001
5059
  };
5002
- const cmdOrganizations = {
5060
+ const cmdOrganization = {
5003
5061
  description: config$g.description,
5004
5062
  hidden: config$g.hidden,
5005
5063
  run: run$g
@@ -5013,8 +5071,23 @@ async function run$g(argv, importMeta, {
5013
5071
  importMeta,
5014
5072
  parentName
5015
5073
  });
5016
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5017
- await getOrganizations();
5074
+ const json = Boolean(cli.flags['json']);
5075
+ const markdown = Boolean(cli.flags['markdown']);
5076
+ if (json && markdown) {
5077
+ // Use exit status of 2 to indicate incorrect usage, generally invalid
5078
+ // options or missing arguments.
5079
+ // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
5080
+ process.exitCode = 2;
5081
+ console.error(`
5082
+ ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
5083
+ - The json and markdown flags cannot be both set, pick one
5084
+ `);
5085
+ return;
5086
+ }
5087
+ if (cli.flags['dryRun']) {
5088
+ return console.log('[DryRun] Bailing now');
5089
+ }
5090
+ await getOrganization(json ? 'json' : markdown ? 'markdown' : 'text');
5018
5091
  }
5019
5092
 
5020
5093
  const {
@@ -5073,7 +5146,9 @@ async function run$f(argv, importMeta, {
5073
5146
  importMeta,
5074
5147
  parentName
5075
5148
  });
5076
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5149
+ if (cli.flags['dryRun']) {
5150
+ return console.log('[DryRun] Bailing now');
5151
+ }
5077
5152
  await runRawNpm(argv);
5078
5153
  }
5079
5154
 
@@ -5133,7 +5208,9 @@ async function run$e(argv, importMeta, {
5133
5208
  importMeta,
5134
5209
  parentName
5135
5210
  });
5136
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5211
+ if (cli.flags['dryRun']) {
5212
+ return console.log('[DryRun] Bailing now');
5213
+ }
5137
5214
  await runRawNpx(argv);
5138
5215
  }
5139
5216
 
@@ -5166,7 +5243,7 @@ async function createReport(socketConfig, inputPaths, {
5166
5243
  handleUnsuccessfulApiResponse('createReport', result, spinner$1);
5167
5244
  return undefined;
5168
5245
  }
5169
- spinner$1.success();
5246
+ spinner$1.successAndStop();
5170
5247
  return result;
5171
5248
  }
5172
5249
  }
@@ -5218,16 +5295,16 @@ async function fetchReportData(reportId, includeAllIssues, strict) {
5218
5295
 
5219
5296
  if (strict) {
5220
5297
  if (result.data.healthy) {
5221
- spinner$1.success('Report result is healthy and great!');
5298
+ spinner$1.successAndStop('Report result is healthy and great!');
5222
5299
  } else {
5223
- spinner$1.error('Report result deemed unhealthy for project');
5300
+ spinner$1.errorAndStop('Report result deemed unhealthy for project');
5224
5301
  }
5225
5302
  } else if (!result.data.healthy) {
5226
5303
  const severityCount = getSeverityCount(result.data.issues, includeAllIssues ? undefined : 'high');
5227
5304
  const issueSummary = formatSeverityCount(severityCount);
5228
- spinner$1.success(`Report has these issues: ${issueSummary}`);
5305
+ spinner$1.successAndStop(`Report has these issues: ${issueSummary}`);
5229
5306
  } else {
5230
- spinner$1.success('Report has no issues');
5307
+ spinner$1.successAndStop('Report has no issues');
5231
5308
  }
5232
5309
  return result.data;
5233
5310
  }
@@ -5331,7 +5408,9 @@ async function run$d(argv, importMeta, {
5331
5408
  const view = Boolean(cli.flags['view']);
5332
5409
 
5333
5410
  // Note exiting earlier to skirt a hidden auth requirement
5334
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5411
+ if (cli.flags['dryRun']) {
5412
+ return console.log('[DryRun] Bailing now');
5413
+ }
5335
5414
  const socketConfig = await getSocketConfig(absoluteConfigPath);
5336
5415
  const result = await createReport(socketConfig, cli.input, {
5337
5416
  cwd,
@@ -5407,7 +5486,9 @@ async function run$c(argv, importMeta, {
5407
5486
  - Can only handle a single report ID ${extraInput.length < 2 ? colors.red(`(received ${extraInput.length}!)`) : colors.green('(ok)')}\n`);
5408
5487
  return;
5409
5488
  }
5410
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5489
+ if (cli.flags['dryRun']) {
5490
+ return console.log('[DryRun] Bailing now');
5491
+ }
5411
5492
  await viewReport(reportId, {
5412
5493
  all: Boolean(cli.flags['all']),
5413
5494
  commandName: `${parentName} ${config$c.commandName}`,
@@ -5462,7 +5543,7 @@ async function createRepo({
5462
5543
  visibility
5463
5544
  }), 'creating repository');
5464
5545
  if (result.success) {
5465
- spinner$1.success('Repository created successfully');
5546
+ spinner$1.successAndStop('Repository created successfully');
5466
5547
  } else {
5467
5548
  handleUnsuccessfulApiResponse('createOrgRepo', result, spinner$1);
5468
5549
  }
@@ -5543,7 +5624,9 @@ async function run$b(argv, importMeta, {
5543
5624
  - Repository name using --repoName ${!repoName ? colors.red('(missing!)') : typeof repoName !== 'string' ? colors.red('(invalid!)') : colors.green('(ok)')}\n`);
5544
5625
  return;
5545
5626
  }
5546
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5627
+ if (cli.flags['dryRun']) {
5628
+ return console.log('[DryRun] Bailing now');
5629
+ }
5547
5630
  const apiToken = index.getDefaultToken();
5548
5631
  if (!apiToken) {
5549
5632
  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.');
@@ -5569,7 +5652,7 @@ async function deleteRepo(orgSlug, repoName, apiToken) {
5569
5652
  const socketSdk = await index.setupSdk(apiToken);
5570
5653
  const result = await handleApiCall(socketSdk.deleteOrgRepo(orgSlug, repoName), 'deleting repository');
5571
5654
  if (result.success) {
5572
- spinner$1.success('Repository deleted successfully');
5655
+ spinner$1.successAndStop('Repository deleted successfully');
5573
5656
  } else {
5574
5657
  handleUnsuccessfulApiResponse('deleteOrgRepo', result, spinner$1);
5575
5658
  }
@@ -5619,7 +5702,9 @@ async function run$a(argv, importMeta, {
5619
5702
  - At least one TARGET (e.g. \`.\` or \`./package.json\`\n`);
5620
5703
  return;
5621
5704
  }
5622
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5705
+ if (cli.flags['dryRun']) {
5706
+ return console.log('[DryRun] Bailing now');
5707
+ }
5623
5708
  const apiToken = index.getDefaultToken();
5624
5709
  if (!apiToken) {
5625
5710
  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.');
@@ -5656,6 +5741,18 @@ async function listRepos({
5656
5741
  handleUnsuccessfulApiResponse('getOrgRepoList', result, spinner$1);
5657
5742
  return;
5658
5743
  }
5744
+ spinner$1.stop();
5745
+ if (outputJson) {
5746
+ const data = result.data.results.map(o => ({
5747
+ id: o.id,
5748
+ name: o.name,
5749
+ visibility: o.visibility,
5750
+ defaultBranch: o.default_branch,
5751
+ archived: o.archived
5752
+ }));
5753
+ console.log(JSON.stringify(data, null, 2));
5754
+ return;
5755
+ }
5659
5756
  const options = {
5660
5757
  columns: [{
5661
5758
  field: 'id',
@@ -5674,7 +5771,7 @@ async function listRepos({
5674
5771
  name: colors.magenta('Archived')
5675
5772
  }]
5676
5773
  };
5677
- spinner$1.stop(chalkTable(options, result.data.results));
5774
+ console.log(chalkTable(options, result.data.results));
5678
5775
  }
5679
5776
 
5680
5777
  const config$9 = {
@@ -5744,7 +5841,9 @@ async function run$9(argv, importMeta, {
5744
5841
  - At least one TARGET (e.g. \`.\` or \`./package.json\`\n`);
5745
5842
  return;
5746
5843
  }
5747
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5844
+ if (cli.flags['dryRun']) {
5845
+ return console.log('[DryRun] Bailing now');
5846
+ }
5748
5847
  const apiToken = index.getDefaultToken();
5749
5848
  if (!apiToken) {
5750
5849
  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.');
@@ -5788,7 +5887,7 @@ async function updateRepo({
5788
5887
  visibility
5789
5888
  }), 'updating repository');
5790
5889
  if (result.success) {
5791
- spinner$1.success('Repository updated successfully');
5890
+ spinner$1.successAndStop('Repository updated successfully');
5792
5891
  } else {
5793
5892
  handleUnsuccessfulApiResponse('updateOrgRepo', result, spinner$1);
5794
5893
  }
@@ -5870,7 +5969,9 @@ async function run$8(argv, importMeta, {
5870
5969
  - At least one TARGET (e.g. \`.\` or \`./package.json\`\n`);
5871
5970
  return;
5872
5971
  }
5873
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
5972
+ if (cli.flags['dryRun']) {
5973
+ return console.log('[DryRun] Bailing now');
5974
+ }
5874
5975
  const apiToken = index.getDefaultToken();
5875
5976
  if (!apiToken) {
5876
5977
  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.');
@@ -5972,7 +6073,9 @@ async function run$7(argv, importMeta, {
5972
6073
  - Repository name using --repoName ${!repoName ? colors.red('(missing!)') : typeof repoName !== 'string' ? colors.red('(invalid!)') : colors.green('(ok)')}\n`);
5973
6074
  return;
5974
6075
  }
5975
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
6076
+ if (cli.flags['dryRun']) {
6077
+ return console.log('[DryRun] Bailing now');
6078
+ }
5976
6079
  const apiToken = index.getDefaultToken();
5977
6080
  if (!apiToken) {
5978
6081
  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.');
@@ -6001,8 +6104,149 @@ const cmdRepos = {
6001
6104
  }
6002
6105
  };
6003
6106
 
6107
+ async function suggestOrgSlug(socketSdk) {
6108
+ const result = await handleApiCall(socketSdk.getOrganizations(), 'looking up organizations');
6109
+ // Ignore a failed request here. It was not the primary goal of
6110
+ // running this command and reporting it only leads to end-user confusion.
6111
+ if (result.success) {
6112
+ const proceed = await prompts.select({
6113
+ message: 'Missing org name; do you want to use any of these orgs for this scan?',
6114
+ choices: Array.from(Object.values(result.data.organizations)).map(({
6115
+ name: slug
6116
+ }) => ({
6117
+ name: 'Yes [' + slug + ']',
6118
+ value: slug,
6119
+ description: `Use "${slug}" as the organization`
6120
+ })).concat({
6121
+ name: 'No',
6122
+ value: '',
6123
+ description: 'Do not use any of these organizations (will end in a no-op)'
6124
+ })
6125
+ });
6126
+ if (proceed) {
6127
+ return proceed;
6128
+ }
6129
+ }
6130
+ }
6131
+
6132
+ async function suggestRepoSlug(socketSdk, orgSlug) {
6133
+ // Same as above, but if there's a repo with the same name as cwd then
6134
+ // default the selection to that name.
6135
+ const result = await handleApiCall(socketSdk.getOrgRepoList(orgSlug, {
6136
+ orgSlug,
6137
+ sort: 'name',
6138
+ direction: 'asc',
6139
+ // There's no guarantee that the cwd is part of this page. If it's not
6140
+ // then do an additional request and specific search for it instead.
6141
+ // This way we can offer the tip of "do you want to create [cwd]?".
6142
+ perPage: 10,
6143
+ page: 0
6144
+ }), 'looking up known repos');
6145
+ // Ignore a failed request here. It was not the primary goal of
6146
+ // running this command and reporting it only leads to end-user confusion.
6147
+ if (result.success) {
6148
+ const currentDirName = dirNameToSlug(path.basename(process$1.cwd()));
6149
+ let cwdIsKnown = !!currentDirName && result.data.results.some(obj => obj.slug === currentDirName);
6150
+ if (!cwdIsKnown && currentDirName) {
6151
+ // Do an explicit request so we can assert that the cwd exists or not
6152
+ const result = await handleApiCall(socketSdk.getOrgRepo(orgSlug, currentDirName), 'checking if current cwd is a known repo');
6153
+ if (result.success) {
6154
+ cwdIsKnown = true;
6155
+ }
6156
+ }
6157
+ const proceed = await prompts.select({
6158
+ message: 'Missing repo name; do you want to use any of these known repo names for this scan?',
6159
+ choices:
6160
+ // Put the CWD suggestion at the top, whether it exists or not
6161
+ (currentDirName ? [{
6162
+ name: `Yes, current dir [${cwdIsKnown ? currentDirName : `create repo for ${currentDirName}`}]`,
6163
+ value: currentDirName,
6164
+ description: cwdIsKnown ? 'Register a new repo name under the given org and use it' : 'Use current dir as repo'
6165
+ }] : []).concat(result.data.results.filter(({
6166
+ slug
6167
+ }) => !!slug && slug !== currentDirName).map(({
6168
+ slug
6169
+ }) => ({
6170
+ name: 'Yes [' + slug + ']',
6171
+ value: slug || '',
6172
+ // Filtered above but TS is like nah.
6173
+ description: `Use "${slug}" as the repo name`
6174
+ })), {
6175
+ name: 'No',
6176
+ value: '',
6177
+ description: 'Do not use any of these repos (will end in a no-op)'
6178
+ })
6179
+ });
6180
+ if (proceed) {
6181
+ const repoName = proceed;
6182
+ let repoDefaultBranch = '';
6183
+ // Store the default branch to help with the branch name question next
6184
+ result.data.results.some(obj => {
6185
+ if (obj.slug === proceed && obj.default_branch) {
6186
+ repoDefaultBranch = obj.default_branch;
6187
+ return;
6188
+ }
6189
+ });
6190
+ return {
6191
+ slug: repoName,
6192
+ defaultBranch: repoDefaultBranch
6193
+ };
6194
+ }
6195
+ }
6196
+ }
6197
+ function dirNameToSlug(name) {
6198
+ // Uses slug specs asserted by our servers
6199
+ // Note: this can lead to collisions; eg. slug for `x--y` and `x---y` is `x-y`
6200
+ return name.toLowerCase().replace(/[^[a-zA-Z0-9_.-]/g, '_').replace(/--+/g, '-').replace(/__+/g, '_').replace(/\.\.+/g, '.').replace(/[._-]+$/, '');
6201
+ }
6202
+
6203
+ async function suggestBranchSlug(repoDefaultBranch) {
6204
+ const spawnResult = node_child_process.spawnSync('git', ['branch', '--show-current']);
6205
+ const currentBranch = spawnResult.stdout.toString('utf8').trim();
6206
+ if (spawnResult.status === 0 && currentBranch) {
6207
+ const proceed = await prompts.select({
6208
+ message: 'Use the current git branch as target branch name?',
6209
+ choices: [{
6210
+ name: `Yes [${currentBranch}]`,
6211
+ value: currentBranch,
6212
+ description: 'Use the current git branch for branch name'
6213
+ }, ...(repoDefaultBranch && repoDefaultBranch !== currentBranch ? [{
6214
+ name: `No, use the default branch [${repoDefaultBranch}]`,
6215
+ value: repoDefaultBranch,
6216
+ description: 'Use the default branch for target repo as the target branch name'
6217
+ }] : []), {
6218
+ name: 'No',
6219
+ value: '',
6220
+ description: 'Do not use the current git branch as name (will end in a no-op)'
6221
+ }].filter(Boolean)
6222
+ });
6223
+ if (proceed) {
6224
+ return proceed;
6225
+ }
6226
+ }
6227
+ }
6228
+
6229
+ async function suggestTarget() {
6230
+ // We could prefill this with sub-dirs of the current
6231
+ // dir ... but is that going to be useful?
6232
+ const proceed = await prompts.select({
6233
+ message: 'No TARGET given. Do you want to use the current directory?',
6234
+ choices: [{
6235
+ name: 'Yes',
6236
+ value: true,
6237
+ description: 'Target the current directory'
6238
+ }, {
6239
+ name: 'No',
6240
+ value: false,
6241
+ description: 'Do not use the current directory (this will end in a no-op)'
6242
+ }]
6243
+ });
6244
+ if (proceed) {
6245
+ return ['.'];
6246
+ }
6247
+ }
6248
+
6004
6249
  async function createFullScan({
6005
- apiToken,
6006
6250
  branchName,
6007
6251
  commitHash: _commitHash,
6008
6252
  commitMessage,
@@ -6010,17 +6254,100 @@ async function createFullScan({
6010
6254
  cwd,
6011
6255
  defaultBranch,
6012
6256
  orgSlug,
6013
- packagePaths,
6014
6257
  pendingHead,
6015
6258
  pullRequest: _pullRequest,
6259
+ readOnly,
6016
6260
  repoName,
6261
+ targets,
6017
6262
  tmp
6018
6263
  }) {
6264
+ const socketSdk = await index.setupSdk();
6265
+ const supportedFiles = await socketSdk.getReportSupportedFiles().then(res => {
6266
+ if (!res.success) {
6267
+ handleUnsuccessfulApiResponse('getReportSupportedFiles', res, new spinner.Spinner());
6268
+ assert(false, 'handleUnsuccessfulApiResponse should unconditionally throw');
6269
+ }
6270
+ return res.data;
6271
+ }).catch(cause => {
6272
+ throw new Error('Failed getting supported files for report', {
6273
+ cause
6274
+ });
6275
+ });
6276
+
6277
+ // If we updated any inputs then we should print the command line to repeat
6278
+ // the command without requiring user input, as a suggestion.
6279
+ let updatedInput = false;
6280
+ if (!targets.length) {
6281
+ const received = await suggestTarget();
6282
+ targets = received ?? [];
6283
+ updatedInput = true;
6284
+ }
6285
+ const packagePaths = await npmPaths.getPackageFilesFullScans(cwd, targets, supportedFiles);
6286
+
6287
+ // We're going to need an api token to suggest data because those suggestions
6288
+ // must come from data we already know. Don't error on missing api token yet.
6289
+ // If the api-token is not set, ignore it for the sake of suggestions.
6290
+ const apiToken = index.getDefaultToken();
6291
+ if (apiToken && !orgSlug) {
6292
+ const suggestion = await suggestOrgSlug(socketSdk);
6293
+ if (suggestion) orgSlug = suggestion;
6294
+ updatedInput = true;
6295
+ }
6296
+
6297
+ // If the current cwd is unknown and is used as a repo slug anyways, we will
6298
+ // first need to register the slug before we can use it.
6299
+ let repoDefaultBranch = '';
6300
+
6301
+ // (Don't bother asking for the rest if we didn't get an org slug above)
6302
+ if (apiToken && orgSlug && !repoName) {
6303
+ const suggestion = await suggestRepoSlug(socketSdk, orgSlug);
6304
+ if (suggestion) {
6305
+ ({
6306
+ defaultBranch: repoDefaultBranch,
6307
+ slug: repoName
6308
+ } = suggestion);
6309
+ }
6310
+ updatedInput = true;
6311
+ }
6312
+
6313
+ // (Don't bother asking for the rest if we didn't get an org/repo above)
6314
+ if (apiToken && orgSlug && repoName && !branchName) {
6315
+ const suggestion = await suggestBranchSlug(repoDefaultBranch);
6316
+ if (suggestion) branchName = suggestion;
6317
+ updatedInput = true;
6318
+ }
6319
+ if (!orgSlug || !repoName || !branchName || !packagePaths.length) {
6320
+ // Use exit status of 2 to indicate incorrect usage, generally invalid
6321
+ // options or missing arguments.
6322
+ // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
6323
+ process$1.exitCode = 2;
6324
+ console.error(`
6325
+ ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
6326
+ - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}\n
6327
+ - Repository name using --repo ${!repoName ? colors.red('(missing!)') : colors.green('(ok)')}\n
6328
+ - Branch name using --branch ${!branchName ? colors.red('(missing!)') : colors.green('(ok)')}\n
6329
+ - 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
6330
+ ${!apiToken ? 'Note: was unable to make suggestions because no API Token was found; this would make command fail regardless\n' : ''}
6331
+ `);
6332
+ return;
6333
+ }
6334
+ if (updatedInput) {
6335
+ console.log('Note: You can invoke this command next time to skip the interactive questions:');
6336
+ console.log('```');
6337
+ console.log(` socket scan create [other flags...] --repo ${repoName} --branch ${branchName} ${orgSlug} ${targets.join(' ')}`);
6338
+ console.log('```');
6339
+ }
6340
+ if (!apiToken) {
6341
+ 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.');
6342
+ }
6343
+ if (readOnly) {
6344
+ console.log('[ReadOnly] Bailing now');
6345
+ return;
6346
+ }
6019
6347
  const spinnerText = 'Creating a scan... \n';
6020
6348
  const spinner$1 = new spinner.Spinner({
6021
6349
  text: spinnerText
6022
6350
  }).start();
6023
- const socketSdk = await index.setupSdk(apiToken);
6024
6351
  const result = await handleApiCall(socketSdk.createOrgFullScan(orgSlug, {
6025
6352
  repo: repoName,
6026
6353
  branch: branchName,
@@ -6033,7 +6360,7 @@ async function createFullScan({
6033
6360
  handleUnsuccessfulApiResponse('CreateOrgFullScan', result, spinner$1);
6034
6361
  return;
6035
6362
  }
6036
- spinner$1.success('Scan created successfully');
6363
+ spinner$1.successAndStop('Scan created successfully');
6037
6364
  const link = colors.underline(colors.cyan(`${result.data.html_report_url}`));
6038
6365
  console.log(`Available at: ${link}`);
6039
6366
  const rl = readline.createInterface({
@@ -6107,6 +6434,11 @@ const config$6 = {
6107
6434
  default: false,
6108
6435
  description: 'Set as pending head'
6109
6436
  },
6437
+ readOnly: {
6438
+ type: 'boolean',
6439
+ default: false,
6440
+ description: 'Similar to --dry-run except it can read from remote, stops before it would create an actual report'
6441
+ },
6110
6442
  tmp: {
6111
6443
  type: 'boolean',
6112
6444
  shortFlag: 't',
@@ -6146,54 +6478,47 @@ async function run$6(argv, importMeta, {
6146
6478
  });
6147
6479
  const [orgSlug = '', ...targets] = cli.input;
6148
6480
  const cwd = cli.flags['cwd'] && cli.flags['cwd'] !== 'process.cwd()' ? String(cli.flags['cwd']) : process$1.cwd();
6149
-
6150
- // Note exiting earlier to skirt a hidden auth requirement
6151
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
6152
- const socketSdk = await index.setupSdk();
6153
- const supportedFiles = await socketSdk.getReportSupportedFiles().then(res => {
6154
- if (!res.success) handleUnsuccessfulApiResponse('getReportSupportedFiles', res, new spinner.Spinner());
6155
- // TODO: verify type at runtime? Consider it trusted data and assume type?
6156
- return res.data;
6157
- }).catch(cause => {
6158
- throw new Error('Failed getting supported files for report', {
6159
- cause
6160
- });
6161
- });
6162
- const packagePaths = await npmPaths.getPackageFilesFullScans(cwd, targets, supportedFiles);
6163
- const {
6481
+ let {
6164
6482
  branch: branchName,
6165
6483
  repo: repoName
6166
6484
  } = cli.flags;
6167
- if (!orgSlug || !repoName || !branchName || !packagePaths.length) {
6485
+ const apiToken = index.getDefaultToken();
6486
+ if (!apiToken && (!orgSlug || !repoName || !branchName || !targets.length)) {
6487
+ // Without api token we cannot recover because we can't request more info
6488
+ // from the server, to match and help with the current cwd/git status.
6168
6489
  // Use exit status of 2 to indicate incorrect usage, generally invalid
6169
6490
  // options or missing arguments.
6170
6491
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
6171
6492
  process$1.exitCode = 2;
6172
- console.error(`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
6173
- - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}\n
6174
- - Repository name using --repo ${!repoName ? colors.red('(missing!)') : colors.green('(ok)')}\n
6175
- - Branch name using --branch ${!branchName ? colors.red('(missing!)') : colors.green('(ok)')}\n
6176
- - 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`);
6493
+ console.error(`
6494
+ ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
6495
+ - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}\n
6496
+ - Repository name using --repo ${!repoName ? colors.red('(missing!)') : colors.green('(ok)')}\n
6497
+ - Branch name using --branch ${!branchName ? colors.red('(missing!)') : colors.green('(ok)')}\n
6498
+ - At least one TARGET (e.g. \`.\` or \`./package.json\`) ${!targets.length ? '(missing)' : colors.green('(ok)')}\n
6499
+ (Additionally, no API Token was set so we cannot auto-discover these details)\n
6500
+ `);
6177
6501
  return;
6178
6502
  }
6179
- const apiToken = index.getDefaultToken();
6180
- if (!apiToken) {
6181
- 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.');
6503
+
6504
+ // Note exiting earlier to skirt a hidden auth requirement
6505
+ if (cli.flags['dryRun']) {
6506
+ return console.log('[DryRun] Bailing now');
6182
6507
  }
6183
6508
  await createFullScan({
6184
- apiToken,
6185
- orgSlug,
6186
- repoName: repoName,
6187
6509
  branchName: branchName,
6510
+ commitHash: cli.flags['commitHash'] ?? '',
6188
6511
  commitMessage: cli.flags['commitMessage'] ?? '',
6512
+ committers: cli.flags['committers'] ?? '',
6513
+ cwd,
6189
6514
  defaultBranch: Boolean(cli.flags['defaultBranch']),
6515
+ orgSlug,
6190
6516
  pendingHead: Boolean(cli.flags['pendingHead']),
6191
- tmp: Boolean(cli.flags['tmp']),
6192
- packagePaths,
6193
- cwd,
6194
- commitHash: cli.flags['commitHash'] ?? '',
6195
- committers: cli.flags['committers'] ?? '',
6196
- pullRequest: cli.flags['pullRequest'] ?? undefined
6517
+ pullRequest: cli.flags['pullRequest'] ?? undefined,
6518
+ readOnly: Boolean(cli.flags['readOnly']),
6519
+ repoName: repoName,
6520
+ targets,
6521
+ tmp: Boolean(cli.flags['tmp'])
6197
6522
  });
6198
6523
  }
6199
6524
 
@@ -6205,7 +6530,7 @@ async function deleteOrgFullScan(orgSlug, fullScanId, apiToken) {
6205
6530
  const socketSdk = await index.setupSdk(apiToken);
6206
6531
  const result = await handleApiCall(socketSdk.deleteOrgFullScan(orgSlug, fullScanId), 'Deleting scan');
6207
6532
  if (result.success) {
6208
- spinner$1.success('Scan deleted successfully');
6533
+ spinner$1.successAndStop('Scan deleted successfully');
6209
6534
  } else {
6210
6535
  handleUnsuccessfulApiResponse('deleteOrgFullScan', result, spinner$1);
6211
6536
  }
@@ -6255,7 +6580,9 @@ async function run$5(argv, importMeta, {
6255
6580
  - Full Scan ID to delete as second argument ${!fullScanId ? colors.red('(missing!)') : colors.green('(ok)')}\n`);
6256
6581
  return;
6257
6582
  }
6258
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
6583
+ if (cli.flags['dryRun']) {
6584
+ return console.log('[DryRun] Bailing now');
6585
+ }
6259
6586
  const apiToken = index.getDefaultToken();
6260
6587
  if (!apiToken) {
6261
6588
  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.');
@@ -6385,7 +6712,9 @@ async function run$4(argv, importMeta, {
6385
6712
  - Org name as the argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}\n`);
6386
6713
  return;
6387
6714
  }
6388
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
6715
+ if (cli.flags['dryRun']) {
6716
+ return console.log('[DryRun] Bailing now');
6717
+ }
6389
6718
  const apiToken = index.getDefaultToken();
6390
6719
  if (!apiToken) {
6391
6720
  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.');
@@ -6464,7 +6793,9 @@ async function run$3(argv, importMeta, {
6464
6793
  - Full Scan ID to inspect as second argument ${!fullScanId ? colors.red('(missing!)') : colors.green('(ok)')}\n`);
6465
6794
  return;
6466
6795
  }
6467
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
6796
+ if (cli.flags['dryRun']) {
6797
+ return console.log('[DryRun] Bailing now');
6798
+ }
6468
6799
  const apiToken = index.getDefaultToken();
6469
6800
  if (!apiToken) {
6470
6801
  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.');
@@ -6532,7 +6863,9 @@ async function run$2(argv, importMeta, {
6532
6863
  - Full Scan ID to fetch as second argument ${!fullScanId ? colors.red('(missing!)') : colors.green('(ok)')}\n`);
6533
6864
  return;
6534
6865
  }
6535
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
6866
+ if (cli.flags['dryRun']) {
6867
+ return console.log('[DryRun] Bailing now');
6868
+ }
6536
6869
  const apiToken = index.getDefaultToken();
6537
6870
  if (!apiToken) {
6538
6871
  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.');
@@ -6695,7 +7028,9 @@ async function run$1(argv, importMeta, {
6695
7028
  importMeta,
6696
7029
  parentName
6697
7030
  });
6698
- if (cli.flags['dryRun']) return console.log('[DryRun] Bailing now');
7031
+ if (cli.flags['dryRun']) {
7032
+ return console.log('[DryRun] Bailing now');
7033
+ }
6699
7034
  const apiToken = index.getDefaultToken();
6700
7035
  if (!apiToken) {
6701
7036
  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.');
@@ -6924,7 +7259,7 @@ void (async () => {
6924
7259
  npx: cmdNpx,
6925
7260
  oops: cmdOops,
6926
7261
  optimize: cmdOptimize,
6927
- organization: cmdOrganizations,
7262
+ organization: cmdOrganization,
6928
7263
  'raw-npm': cmdRawNpm,
6929
7264
  'raw-npx': cmdRawNpx,
6930
7265
  report: cmdReport,
@@ -6976,5 +7311,5 @@ void (async () => {
6976
7311
  await index.captureException(e);
6977
7312
  }
6978
7313
  })();
6979
- //# debugId=d30f7250-79de-4641-a3e0-e622cbd34263
7314
+ //# debugId=946935cf-d1a8-421f-98f6-c3164cb5288a
6980
7315
  //# sourceMappingURL=cli.js.map