@socketsecurity/cli-with-sentry 0.14.56 → 0.14.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/bin/cli.js +10 -10
  2. package/bin/npm-cli.js +1 -1
  3. package/bin/npx-cli.js +3 -1
  4. package/dist/constants.d.ts +20 -8
  5. package/dist/constants.js +54 -25
  6. package/dist/constants.js.map +1 -1
  7. package/dist/instrument-with-sentry.js +3 -3
  8. package/dist/instrument-with-sentry.js.map +1 -1
  9. package/dist/module-sync/artifact.d.ts +75 -0
  10. package/dist/module-sync/cli.js +1372 -1062
  11. package/dist/module-sync/cli.js.map +1 -1
  12. package/dist/module-sync/edge.d.ts +1 -1
  13. package/dist/module-sync/index.d.ts +5 -173
  14. package/dist/module-sync/node.d.ts +1 -1
  15. package/dist/module-sync/override-set.d.ts +37 -0
  16. package/dist/module-sync/shadow-bin.js +10 -8
  17. package/dist/module-sync/shadow-bin.js.map +1 -1
  18. package/dist/module-sync/{index.js → shadow-npm-inject.js} +1436 -1302
  19. package/dist/module-sync/shadow-npm-inject.js.map +1 -0
  20. package/dist/module-sync/{npm-paths.js → shadow-npm-paths.js} +4 -4
  21. package/dist/module-sync/shadow-npm-paths.js.map +1 -0
  22. package/dist/module-sync/socket-package-alert.d.ts +46 -0
  23. package/dist/module-sync/types.d.ts +11 -3
  24. package/dist/require/cli.js +1372 -1062
  25. package/dist/require/cli.js.map +1 -1
  26. package/dist/require/shadow-npm-inject.js +3 -0
  27. package/dist/require/shadow-npm-paths.js +3 -0
  28. package/package.json +14 -11
  29. package/dist/module-sync/index.js.map +0 -1
  30. package/dist/module-sync/npm-injection.js +0 -26
  31. package/dist/module-sync/npm-injection.js.map +0 -1
  32. package/dist/module-sync/npm-paths.js.map +0 -1
  33. package/dist/module-sync/proc-log.d.ts +0 -3
  34. package/dist/module-sync/reify.d.ts +0 -1020
  35. package/dist/require/index.js +0 -3
  36. package/dist/require/npm-injection.js +0 -3
  37. package/dist/require/npm-paths.js +0 -3
  38. /package/dist/module-sync/{npm-injection.d.ts → shadow-npm-inject.d.ts} +0 -0
  39. /package/dist/module-sync/{npm-paths.d.ts → shadow-npm-paths.d.ts} +0 -0
@@ -24,10 +24,11 @@ var fs = require('node:fs');
24
24
  var path = require('node:path');
25
25
  var ndjson = _socketInterop(require('ndjson'));
26
26
  var rest = _socketInterop(require('@octokit/rest'));
27
- var index = require('./index.js');
27
+ var shadowNpmInject = require('./shadow-npm-inject.js');
28
28
  var constants = require('./constants.js');
29
29
  var meow = _socketInterop(require('meow'));
30
30
  var objects = require('@socketsecurity/registry/lib/objects');
31
+ var path$1 = require('@socketsecurity/registry/lib/path');
31
32
  var regexps = require('@socketsecurity/registry/lib/regexps');
32
33
  var commonTags = _socketInterop(require('common-tags'));
33
34
  var fs$1 = require('node:fs/promises');
@@ -42,27 +43,30 @@ var util = require('node:util');
42
43
  var registry = require('@socketsecurity/registry');
43
44
  var npm = require('@socketsecurity/registry/lib/npm');
44
45
  var packages = require('@socketsecurity/registry/lib/packages');
45
- var registryConstants = require('@socketsecurity/registry/lib/constants');
46
- var isInteractive = require('@socketregistry/is-interactive/index.cjs');
47
- var terminalLink = _socketInterop(require('terminal-link'));
46
+ var lockfileFile = _socketInterop(require('@pnpm/lockfile-file'));
47
+ var lockfile_detectDepTypes = _socketInterop(require('@pnpm/lockfile.detect-dep-types'));
48
+ var debug = require('@socketsecurity/registry/lib/debug');
48
49
  var spawn = require('@socketsecurity/registry/lib/spawn');
49
- var npa = _socketInterop(require('npm-package-arg'));
50
- var semver = _socketInterop(require('semver'));
51
- var tinyglobby = _socketInterop(require('tinyglobby'));
52
- var promises = require('@socketsecurity/registry/lib/promises');
50
+ var shadowNpmPaths = require('./shadow-npm-paths.js');
53
51
  var browserslist = _socketInterop(require('browserslist'));
52
+ var semver = _socketInterop(require('semver'));
54
53
  var which = _socketInterop(require('which'));
55
54
  var index_cjs = require('@socketregistry/hyrious__bun.lockb/index.cjs');
56
55
  var sorts = require('@socketsecurity/registry/lib/sorts');
57
56
  var strings = require('@socketsecurity/registry/lib/strings');
57
+ var registryConstants = require('@socketsecurity/registry/lib/constants');
58
+ var isInteractive = require('@socketregistry/is-interactive/index.cjs');
59
+ var terminalLink = _socketInterop(require('terminal-link'));
60
+ var npa = _socketInterop(require('npm-package-arg'));
61
+ var tinyglobby = _socketInterop(require('tinyglobby'));
62
+ var promises = require('@socketsecurity/registry/lib/promises');
58
63
  var yaml = _socketInterop(require('yaml'));
59
- var debug = require('@socketsecurity/registry/lib/debug');
60
- var npmPaths = require('./npm-paths.js');
61
64
  var betterAjvErrors = _socketInterop(require('@apideck/better-ajv-errors'));
62
65
  var config$A = require('@socketsecurity/config');
63
66
  var assert = require('node:assert');
64
67
  var readline = require('node:readline/promises');
65
68
  var open = _socketInterop(require('open'));
69
+ var BoxWidget = _socketInterop(require('blessed/lib/widgets/box'));
66
70
  var TableWidget = _socketInterop(require('blessed-contrib/lib/widget/table'));
67
71
  var readline$1 = require('node:readline');
68
72
 
@@ -324,7 +328,7 @@ class Core {
324
328
  }) {
325
329
  const introducedBy = [];
326
330
  if (pkg.direct) {
327
- let manifests = pkg.manifestFiles.map(({
331
+ const manifests = pkg.manifestFiles.map(({
328
332
  file
329
333
  }) => file).join(';');
330
334
  introducedBy.push(['direct', manifests]);
@@ -335,7 +339,7 @@ class Core {
335
339
  continue;
336
340
  }
337
341
  const topPurl = `${topPackage.type}/${topPackage.name}@${topPackage.version}`;
338
- let manifests = topPackage.manifestFiles.map(({
342
+ const manifests = topPackage.manifestFiles.map(({
339
343
  file
340
344
  }) => file).join(';');
341
345
  introducedBy.push([topPurl, manifests]);
@@ -767,7 +771,7 @@ function processSecurityComment({
767
771
  const result = [];
768
772
  let start = false;
769
773
  let ignoreAll = false;
770
- let ignoredPackages = [];
774
+ const ignoredPackages = [];
771
775
  for (const ignoreComment of ignoreComments) {
772
776
  const parsed = parseIgnoreCommand(ignoreComment.body?.split('\n').at(0) ?? '');
773
777
  if (parsed.ignoreAll) {
@@ -791,7 +795,7 @@ function processSecurityComment({
791
795
  const [_, _title, packageLink, _introducedBy, _manifest, _ci] = line.split('|');
792
796
 
793
797
  // Parsing package link [npm/pkg](url)
794
- let [_ecosystem, pkg] = packageLink.slice(1, packageLink.indexOf(']')).split('/', 2);
798
+ const [_ecosystem, pkg] = packageLink.slice(1, packageLink.indexOf(']')).split('/', 2);
795
799
  const [pkgName, pkgVersion] = pkg.split('@');
796
800
 
797
801
  // Checking if this package should be ignored
@@ -840,7 +844,7 @@ function getIgnoreOptions({
840
844
  ignoreCommands.push(data);
841
845
  }
842
846
  } catch (e) {
843
- logger.logger.error(`Unable to process ignore command for ${comment}`);
847
+ logger.logger.fail(`Unable to process ignore command for ${comment}`);
844
848
  logger.logger.error(e);
845
849
  }
846
850
  }
@@ -1114,8 +1118,8 @@ function createSources(alert) {
1114
1118
  manifests.push(addStr);
1115
1119
  }
1116
1120
  }
1117
- let manifestList = manifests.join('');
1118
- let sourceList = sources.join('');
1121
+ const manifestList = manifests.join('');
1122
+ const sourceList = sources.join('');
1119
1123
  const manifestStr = `<ul>${manifestList}</ul>`;
1120
1124
  const sourcesStr = `<ul>${sourceList}</ul>`;
1121
1125
  return [manifestStr, sourcesStr];
@@ -1226,7 +1230,7 @@ function securityCommentTemplate(diff) {
1226
1230
  // TODO: is this a github action handler?
1227
1231
  async function runAction(githubEventBefore, githubEventAfter) {
1228
1232
  //TODO
1229
- const socket = new sdk.SocketSdk(index.getDefaultToken());
1233
+ const socket = new sdk.SocketSdk(shadowNpmInject.getDefaultToken());
1230
1234
  const git = simpleGit.simpleGit();
1231
1235
  const changedFiles = (await git.diff(process.env['GITHUB_EVENT_NAME'] === 'pull_request' ? ['--name-only', 'HEAD^1', 'HEAD'] : ['--name-only', githubEventBefore, githubEventAfter])).split('\n');
1232
1236
  logger.logger.log({
@@ -1260,8 +1264,8 @@ async function runAction(githubEventBefore, githubEventAfter) {
1260
1264
  const securityComment = securityCommentTemplate(diff);
1261
1265
  let newSecurityComment = true;
1262
1266
  let newOverviewComment = true;
1263
- let updateOldSecurityComment = comments.security !== undefined;
1264
- let updateOldOverviewComment = comments.overview !== undefined;
1267
+ const updateOldSecurityComment = comments.security !== undefined;
1268
+ const updateOldOverviewComment = comments.overview !== undefined;
1265
1269
  if (diff.newAlerts.length === 0) {
1266
1270
  if (!updateOldSecurityComment) {
1267
1271
  newSecurityComment = false;
@@ -1291,15 +1295,14 @@ async function runAction(githubEventBefore, githubEventAfter) {
1291
1295
  const {
1292
1296
  API_V0_URL
1293
1297
  } = constants;
1294
- function handleUnsuccessfulApiResponse(_name, result, spinner) {
1298
+ function handleUnsuccessfulApiResponse(_name, result) {
1295
1299
  // SocketSdkErrorType['error'] is not typed.
1296
1300
  const resultErrorMessage = result.error?.message;
1297
1301
  const message = typeof resultErrorMessage === 'string' ? resultErrorMessage : 'No error message returned';
1298
1302
  if (result.status === 401 || result.status === 403) {
1299
- spinner.stop();
1300
- throw new index.AuthError(message);
1303
+ throw new shadowNpmInject.AuthError(message);
1301
1304
  }
1302
- spinner.errorAndStop(`${colors.bgRed(colors.white('API returned an error:'))} ${message}`);
1305
+ logger.logger.fail(`${colors.bgRed(colors.white('API returned an error:'))} ${message}`);
1303
1306
  process$1.exit(1);
1304
1307
  }
1305
1308
  async function handleApiCall(value, description) {
@@ -1404,8 +1407,7 @@ const validationFlags = {
1404
1407
 
1405
1408
  const {
1406
1409
  DRY_RUN_LABEL: DRY_RUN_LABEL$1,
1407
- REDACTED,
1408
- SOCKET_CLI_SHOW_BANNER
1410
+ REDACTED
1409
1411
  } = constants;
1410
1412
  async function meowWithSubcommands(subcommands, options) {
1411
1413
  const {
@@ -1439,11 +1441,7 @@ async function meowWithSubcommands(subcommands, options) {
1439
1441
  };
1440
1442
  // ...else we provide basic instructions and help.
1441
1443
 
1442
- // Temp disable until we clear the --json and --markdown usage
1443
- // Lazily access constants.ENV[SOCKET_CLI_SHOW_BANNER].
1444
- if (constants.ENV[SOCKET_CLI_SHOW_BANNER]) {
1445
- logger.logger.log(getAsciiHeader(name));
1446
- }
1444
+ emitBanner(name);
1447
1445
  const cli = meow(`
1448
1446
  Usage
1449
1447
  $ ${name} <command>
@@ -1478,8 +1476,8 @@ async function meowWithSubcommands(subcommands, options) {
1478
1476
  autoHelp: false // otherwise we can't exit(0)
1479
1477
  });
1480
1478
  if (!cli.flags['help'] && cli.flags['dryRun']) {
1481
- logger.logger.log(`${DRY_RUN_LABEL$1}: No-op, call a sub-command; ok`);
1482
1479
  process.exitCode = 0;
1480
+ logger.logger.log(`${DRY_RUN_LABEL$1}: No-op, call a sub-command; ok`);
1483
1481
  } else {
1484
1482
  cli.showHelp();
1485
1483
  }
@@ -1497,11 +1495,7 @@ function meowOrExit({
1497
1495
  parentName
1498
1496
  }) {
1499
1497
  const command = `${parentName} ${config.commandName}`;
1500
- // Temp disable until we clear the --json and --markdown usage.
1501
- // Lazily access constants.ENV[SOCKET_CLI_SHOW_BANNER].
1502
- if (constants.ENV[SOCKET_CLI_SHOW_BANNER]) {
1503
- logger.logger.log(getAsciiHeader(command));
1504
- }
1498
+ emitBanner(command);
1505
1499
 
1506
1500
  // This exits if .printHelp() is called either by meow itself or by us.
1507
1501
  const cli = meow({
@@ -1518,13 +1512,24 @@ function meowOrExit({
1518
1512
  }
1519
1513
  return cli;
1520
1514
  }
1515
+ function emitBanner(name) {
1516
+ // Print a banner at the top of each command.
1517
+ // This helps with brand recognition and marketing.
1518
+ // It also helps with debugging since it contains version and command details.
1519
+ // Note: print over stderr to preserve stdout for flags like --json and
1520
+ // --markdown. If we don't do this, you can't use --json in particular
1521
+ // and pipe the result to other tools. By emiting the banner over stderr
1522
+ // you can do something like `socket scan view xyz | jq | process`.
1523
+ // The spinner also emits over stderr for example.
1524
+ logger.logger.error(getAsciiHeader(name));
1525
+ }
1521
1526
  function getAsciiHeader(command) {
1522
1527
  const cliVersion = // The '@rollup/plugin-replace' will replace "process.env['SOCKET_CLI_VERSION_HASH']".
1523
- "0.14.56:5a261bf:186ce7ee:pub";
1528
+ "0.14.58:f270068:05655527:pub";
1524
1529
  const nodeVersion = process.version;
1525
- const apiToken = index.getSetting('apiToken');
1530
+ const apiToken = shadowNpmInject.getSetting('apiToken');
1526
1531
  const shownToken = apiToken ? getLastFiveOfApiToken(apiToken) : 'no';
1527
- const relCwd = process.cwd().replace(new RegExp(`^${regexps.escapeRegExp(constants.homePath)}`, 'i'), '~/');
1532
+ const relCwd = path$1.normalizePath(process.cwd().replace(new RegExp(`^${regexps.escapeRegExp(constants.homePath)}(?:${path.sep}|$)`, 'i'), '~/'));
1528
1533
  const body = `
1529
1534
  _____ _ _ /---------------
1530
1535
  | __|___ ___| |_ ___| |_ | Socket.dev CLI ver ${cliVersion}
@@ -1595,10 +1600,10 @@ async function run$z(argv, importMeta, {
1595
1600
  }
1596
1601
 
1597
1602
  async function fetchOrgAnalyticsData(time, spinner, apiToken) {
1598
- const socketSdk = await index.setupSdk(apiToken);
1603
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
1599
1604
  const result = await handleApiCall(socketSdk.getOrgAnalytics(time.toString()), 'fetching analytics data');
1600
1605
  if (result.success === false) {
1601
- handleUnsuccessfulApiResponse('getOrgAnalytics', result, spinner);
1606
+ handleUnsuccessfulApiResponse('getOrgAnalytics', result);
1602
1607
  return undefined;
1603
1608
  }
1604
1609
  spinner.stop();
@@ -1610,10 +1615,10 @@ async function fetchOrgAnalyticsData(time, spinner, apiToken) {
1610
1615
  }
1611
1616
 
1612
1617
  async function fetchRepoAnalyticsData(repo, time, spinner, apiToken) {
1613
- const socketSdk = await index.setupSdk(apiToken);
1618
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
1614
1619
  const result = await handleApiCall(socketSdk.getRepoAnalytics(repo, time.toString()), 'fetching analytics data');
1615
1620
  if (result.success === false) {
1616
- handleUnsuccessfulApiResponse('getRepoAnalytics', result, spinner);
1621
+ handleUnsuccessfulApiResponse('getRepoAnalytics', result);
1617
1622
  return undefined;
1618
1623
  }
1619
1624
  spinner.stop();
@@ -1687,9 +1692,9 @@ async function displayAnalytics({
1687
1692
  scope,
1688
1693
  time
1689
1694
  }) {
1690
- const apiToken = index.getDefaultToken();
1695
+ const apiToken = shadowNpmInject.getDefaultToken();
1691
1696
  if (!apiToken) {
1692
- 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.');
1697
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API token.');
1693
1698
  }
1694
1699
  await outputAnalyticsWithToken({
1695
1700
  apiToken,
@@ -1723,16 +1728,16 @@ async function outputAnalyticsWithToken({
1723
1728
  // A message should already have been printed if we have no data here
1724
1729
  if (!data) return;
1725
1730
  if (outputKind === 'json') {
1726
- let serialized = renderJson(data);
1731
+ const serialized = renderJson(data);
1727
1732
  if (!serialized) return;
1728
1733
  if (filePath && filePath !== '-') {
1729
1734
  try {
1730
1735
  await fs$1.writeFile(filePath, serialized, 'utf8');
1731
1736
  logger.logger.log(`Data successfully written to ${filePath}`);
1732
1737
  } catch (e) {
1733
- logger.logger.error('There was an error trying to write the json to disk');
1734
- logger.logger.error(e);
1735
1738
  process.exitCode = 1;
1739
+ logger.logger.fail('There was an error trying to write the json to disk');
1740
+ logger.logger.error(e);
1736
1741
  }
1737
1742
  } else {
1738
1743
  logger.logger.log(serialized);
@@ -1760,9 +1765,9 @@ function renderJson(data) {
1760
1765
  try {
1761
1766
  return JSON.stringify(data, null, 2);
1762
1767
  } catch (e) {
1763
- // This could be caused by circular references, which is an "us" problem
1764
- logger.logger.error('There was a problem converting the data set to JSON. Please try without --json or with --markdown');
1765
1768
  process.exitCode = 1;
1769
+ // This could be caused by circular references, which is an "us" problem
1770
+ logger.logger.fail('There was a problem converting the data set to JSON. Please try without --json or with --markdown');
1766
1771
  return;
1767
1772
  }
1768
1773
  }
@@ -1997,7 +2002,7 @@ async function run$y(argv, importMeta, {
1997
2002
  // options or missing arguments.
1998
2003
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
1999
2004
  process.exitCode = 2;
2000
- logger.logger.error(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
2005
+ logger.logger.fail(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
2001
2006
 
2002
2007
  - Scope must be "repo" or "org" ${badScope ? colors.red('(bad!)') : colors.green('(ok)')}
2003
2008
 
@@ -2031,9 +2036,9 @@ async function getAuditLog({
2031
2036
  page,
2032
2037
  perPage
2033
2038
  }) {
2034
- const apiToken = index.getDefaultToken();
2039
+ const apiToken = shadowNpmInject.getDefaultToken();
2035
2040
  if (!apiToken) {
2036
- 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.');
2041
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
2037
2042
  }
2038
2043
  const auditLogs = await getAuditLogWithToken({
2039
2044
  apiToken,
@@ -2077,8 +2082,8 @@ async function outputAsJson(auditLogs, orgSlug, logType, page, perPage) {
2077
2082
  })
2078
2083
  }, null, 2);
2079
2084
  } catch (e) {
2080
- logger.logger.error('There was a problem converting the logs to JSON, please try without the `--json` flag');
2081
2085
  process.exitCode = 1;
2086
+ logger.logger.fail('There was a problem converting the logs to JSON, please try without the `--json` flag');
2082
2087
  return;
2083
2088
  }
2084
2089
  logger.logger.log(json);
@@ -2099,9 +2104,9 @@ These are the Socket.dev audit logs as per requested query.
2099
2104
  ${table}
2100
2105
  `);
2101
2106
  } catch (e) {
2102
- logger.logger.error('There was a problem converting the logs to JSON, please try without the `--json` flag');
2103
- logger.logger.error(e);
2104
2107
  process.exitCode = 1;
2108
+ logger.logger.fail('There was a problem converting the logs to JSON, please try without the `--json` flag');
2109
+ logger.logger.error(e);
2105
2110
  return;
2106
2111
  }
2107
2112
  }
@@ -2143,7 +2148,7 @@ async function getAuditLogWithToken({
2143
2148
  spinner
2144
2149
  } = constants;
2145
2150
  spinner.start(`Looking up audit log for ${orgSlug}`);
2146
- const socketSdk = await index.setupSdk(apiToken);
2151
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
2147
2152
  const result = await handleApiCall(socketSdk.getAuditLogEvents(orgSlug, {
2148
2153
  outputJson: outputKind === 'json',
2149
2154
  // I'm not sure this is used at all
@@ -2155,7 +2160,7 @@ async function getAuditLogWithToken({
2155
2160
  per_page: perPage
2156
2161
  }), `Looking up audit log for ${orgSlug}\n`);
2157
2162
  if (!result.success) {
2158
- handleUnsuccessfulApiResponse('getAuditLogEvents', result, spinner);
2163
+ handleUnsuccessfulApiResponse('getAuditLogEvents', result);
2159
2164
  return;
2160
2165
  }
2161
2166
  spinner.stop();
@@ -2195,6 +2200,9 @@ const config$x = {
2195
2200
  Usage
2196
2201
  $ ${command} <org slug>
2197
2202
 
2203
+ This feature requires an Enterprise Plan. To learn more about getting access
2204
+ to this feature and many more, please visit https://socket.dev/pricing
2205
+
2198
2206
  Options
2199
2207
  ${getFlagListOutput(config.flags, 6)}
2200
2208
 
@@ -2230,7 +2238,7 @@ async function run$x(argv, importMeta, {
2230
2238
  // options or missing arguments.
2231
2239
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
2232
2240
  process.exitCode = 2;
2233
- logger.logger.error(commonTags.stripIndents`
2241
+ logger.logger.fail(commonTags.stripIndents`
2234
2242
  ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
2235
2243
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}
2236
2244
  `);
@@ -2250,22 +2258,22 @@ async function run$x(argv, importMeta, {
2250
2258
  }
2251
2259
 
2252
2260
  const {
2253
- NPM: NPM$e,
2261
+ NPM: NPM$g,
2254
2262
  NPX: NPX$3,
2255
- PNPM: PNPM$8
2263
+ PNPM: PNPM$a
2256
2264
  } = constants;
2257
- const nodejsPlatformTypes = new Set(['javascript', 'js', 'nodejs', NPM$e, PNPM$8, 'ts', 'tsx', 'typescript']);
2265
+ const nodejsPlatformTypes = new Set(['javascript', 'js', 'nodejs', NPM$g, PNPM$a, 'ts', 'tsx', 'typescript']);
2258
2266
  async function runCycloneDX(yargv) {
2259
2267
  let cleanupPackageLock = false;
2260
2268
  if (yargv.type !== 'yarn' && nodejsPlatformTypes.has(yargv.type) && fs.existsSync('./yarn.lock')) {
2261
2269
  if (fs.existsSync('./package-lock.json')) {
2262
- yargv.type = NPM$e;
2270
+ yargv.type = NPM$g;
2263
2271
  } else {
2264
2272
  // Use synp to create a package-lock.json from the yarn.lock,
2265
2273
  // based on the node_modules folder, for a more accurate SBOM.
2266
2274
  try {
2267
2275
  await shadowBin(NPX$3, ['synp@1.9.14', '--', '--source-file', './yarn.lock'], 2);
2268
- yargv.type = NPM$e;
2276
+ yargv.type = NPM$g;
2269
2277
  cleanupPackageLock = true;
2270
2278
  } catch {}
2271
2279
  }
@@ -2416,7 +2424,7 @@ async function run$w(argv, importMeta, {
2416
2424
  //
2417
2425
  //
2418
2426
  // if (cli.input.length)
2419
- // logger.error(
2427
+ // logger.fail(
2420
2428
  // stripIndents`
2421
2429
  // ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
2422
2430
  //
@@ -2440,7 +2448,7 @@ async function run$w(argv, importMeta, {
2440
2448
  // options or missing arguments.
2441
2449
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
2442
2450
  process$1.exitCode = 2;
2443
- logger.logger.error(`Unknown ${words.pluralize('argument', unknownLength)}: ${yargv._.join(', ')}`);
2451
+ logger.logger.fail(`Unknown ${words.pluralize('argument', unknownLength)}: ${yargv._.join(', ')}`);
2444
2452
  return;
2445
2453
  }
2446
2454
  if (yargv.output === undefined) {
@@ -2459,22 +2467,22 @@ async function findDependencies({
2459
2467
  offset,
2460
2468
  outputJson
2461
2469
  }) {
2462
- const apiToken = index.getDefaultToken();
2470
+ const apiToken = shadowNpmInject.getDefaultToken();
2463
2471
  if (!apiToken) {
2464
- 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.');
2472
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
2465
2473
  }
2466
2474
  // Lazily access constants.spinner.
2467
2475
  const {
2468
2476
  spinner
2469
2477
  } = constants;
2470
2478
  spinner.start('Searching dependencies...');
2471
- const socketSdk = await index.setupSdk(apiToken);
2479
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
2472
2480
  const result = await handleApiCall(socketSdk.searchDependencies({
2473
2481
  limit,
2474
2482
  offset
2475
2483
  }), 'Searching dependencies');
2476
2484
  if (!result.success) {
2477
- handleUnsuccessfulApiResponse('searchDependencies', result, spinner);
2485
+ handleUnsuccessfulApiResponse('searchDependencies', result);
2478
2486
  return;
2479
2487
  }
2480
2488
  spinner.stop('Organization dependencies:');
@@ -2579,9 +2587,9 @@ async function getDiffScan({
2579
2587
  orgSlug,
2580
2588
  outputJson
2581
2589
  }) {
2582
- const apiToken = index.getDefaultToken();
2590
+ const apiToken = shadowNpmInject.getDefaultToken();
2583
2591
  if (!apiToken) {
2584
- 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.');
2592
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
2585
2593
  }
2586
2594
  await getDiffScanWithToken({
2587
2595
  after,
@@ -2626,16 +2634,17 @@ async function getDiffScanWithToken({
2626
2634
  try {
2627
2635
  json = JSON.stringify(result, null, 2);
2628
2636
  } catch (e) {
2629
- // Most likely caused by a circular reference (or OOM)
2630
- logger.logger.error('There was a problem converting the data to JSON');
2631
2637
  process.exitCode = 1;
2638
+ // Most likely caused by a circular reference (or OOM)
2639
+ logger.logger.fail('There was a problem converting the data to JSON');
2640
+ logger.logger.error(e);
2632
2641
  return;
2633
2642
  }
2634
2643
  if (file && file !== '-') {
2635
2644
  logger.logger.log(`Writing json to \`${file}\``);
2636
2645
  fs.writeFile(file, JSON.stringify(result, null, 2), err => {
2637
2646
  if (err) {
2638
- logger.logger.error(`Writing to \`${file}\` failed...`);
2647
+ logger.logger.fail(`Writing to \`${file}\` failed...`);
2639
2648
  logger.logger.error(err);
2640
2649
  } else {
2641
2650
  logger.logger.log(`Data successfully written to \`${file}\``);
@@ -2741,7 +2750,7 @@ async function run$u(argv, importMeta, {
2741
2750
  // options or missing arguments.
2742
2751
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
2743
2752
  process.exitCode = 2;
2744
- logger.logger.error(`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
2753
+ logger.logger.fail(`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
2745
2754
  - Specify a before and after full scan ID ${!before && !after ? colors.red('(missing before and after!)') : !before ? colors.red('(missing before!)') : !after ? colors.red('(missing after!)') : colors.green('(ok)')}\n
2746
2755
  - To get full scans IDs, you can run the command "socket scan list <your org slug>".
2747
2756
  The args are expecting a full \`aaa0aa0a-aaaa-0000-0a0a-0000000a00a0\` ID.\n
@@ -2784,254 +2793,766 @@ const cmdDiffScan = {
2784
2793
  }
2785
2794
  };
2786
2795
 
2787
- // import { detect } from '../../utils/package-environment-detector'
2788
-
2789
2796
  const {
2790
- NPM: NPM$d
2797
+ NPM: NPM$f
2791
2798
  } = constants;
2792
2799
  function isTopLevel(tree, node) {
2793
2800
  return tree.children.get(node.name) === node;
2794
2801
  }
2795
- async function runFix() {
2796
- // Lazily access constants.spinner.
2802
+ async function npmFix(_pkgEnvDetails, cwd, options) {
2797
2803
  const {
2798
2804
  spinner
2799
- } = constants;
2800
- spinner.start();
2801
- const cwd = process.cwd();
2802
- const editablePkgJson = await packages.readPackageJson(cwd, {
2803
- editable: true
2804
- });
2805
- // const agentDetails = await detect()
2806
-
2807
- const arb = new index.SafeArborist({
2805
+ } = {
2806
+ __proto__: null,
2807
+ ...options
2808
+ };
2809
+ spinner?.start();
2810
+ const arb = new shadowNpmInject.SafeArborist({
2808
2811
  path: cwd,
2809
- ...index.SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES
2812
+ ...shadowNpmInject.SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES
2810
2813
  });
2811
2814
  await arb.reify();
2812
- const alerts = await index.getPackagesAlerts(arb, {
2815
+ const alertsMap = await shadowNpmInject.getAlertsMapFromArborist(arb, {
2813
2816
  consolidate: true,
2814
- includeExisting: true,
2815
- includeUnfixable: false
2817
+ include: {
2818
+ existing: true,
2819
+ unfixable: false,
2820
+ upgrade: false
2821
+ }
2816
2822
  });
2817
- const infoByPkg = index.getCveInfoByPackage(alerts);
2823
+ const infoByPkg = shadowNpmInject.getCveInfoByAlertsMap(alertsMap);
2824
+ if (!infoByPkg) {
2825
+ spinner?.stop();
2826
+ return;
2827
+ }
2818
2828
  await arb.buildIdealTree();
2819
- if (infoByPkg) {
2820
- for (const {
2821
- 0: name,
2822
- 1: infos
2823
- } of infoByPkg) {
2824
- let revertToIdealTree = arb.idealTree;
2825
- arb.idealTree = null;
2826
- // eslint-disable-next-line no-await-in-loop
2827
- await arb.buildIdealTree();
2828
- const tree = arb.idealTree;
2829
- const hasUpgrade = !!registry.getManifestData(NPM$d, name);
2830
- if (hasUpgrade) {
2831
- spinner.info(`Skipping ${name}. Socket Optimize package exists.`);
2832
- continue;
2833
- }
2834
- const nodes = index.findPackageNodes(tree, name);
2835
- const packument = nodes.length && infos.length ?
2836
- // eslint-disable-next-line no-await-in-loop
2837
- await packages.fetchPackagePackument(name) : null;
2838
- if (packument) {
2839
- for (let i = 0, {
2840
- length: nodesLength
2841
- } = nodes; i < nodesLength; i += 1) {
2842
- const node = nodes[i];
2843
- for (let j = 0, {
2844
- length: infosLength
2845
- } = infos; j < infosLength; j += 1) {
2846
- const {
2847
- firstPatchedVersionIdentifier,
2848
- vulnerableVersionRange
2849
- } = infos[j];
2850
- const {
2851
- version: oldVersion
2852
- } = node;
2853
- if (index.updateNode(node, packument, vulnerableVersionRange)) {
2854
- try {
2855
- // eslint-disable-next-line no-await-in-loop
2856
- await npm.runScript('test', [], {
2857
- spinner,
2858
- stdio: 'ignore'
2859
- });
2860
- spinner.info(`Patched ${name} ${oldVersion} -> ${node.version}`);
2861
- if (isTopLevel(tree, node)) {
2862
- for (const depField of ['dependencies', 'optionalDependencies', 'peerDependencies']) {
2863
- const oldVersion = editablePkgJson.content[depField]?.[name];
2864
- if (oldVersion) {
2865
- const decorator = /^[~^]/.exec(oldVersion)?.[0] ?? '';
2866
- editablePkgJson.content[depField][name] = `${decorator}${node.version}`;
2867
- }
2868
- }
2829
+ const editablePkgJson = await packages.readPackageJson(cwd, {
2830
+ editable: true
2831
+ });
2832
+ for (const {
2833
+ 0: name,
2834
+ 1: infos
2835
+ } of infoByPkg) {
2836
+ const revertToIdealTree = arb.idealTree;
2837
+ arb.idealTree = null;
2838
+ // eslint-disable-next-line no-await-in-loop
2839
+ await arb.buildIdealTree();
2840
+ const tree = arb.idealTree;
2841
+ const hasUpgrade = !!registry.getManifestData(NPM$f, name);
2842
+ if (hasUpgrade) {
2843
+ spinner?.info(`Skipping ${name}. Socket Optimize package exists.`);
2844
+ continue;
2845
+ }
2846
+ const nodes = shadowNpmInject.findPackageNodes(tree, name);
2847
+ const packument = nodes.length && infos.length ?
2848
+ // eslint-disable-next-line no-await-in-loop
2849
+ await packages.fetchPackagePackument(name) : null;
2850
+ if (!packument) {
2851
+ continue;
2852
+ }
2853
+ for (let i = 0, {
2854
+ length: nodesLength
2855
+ } = nodes; i < nodesLength; i += 1) {
2856
+ const node = nodes[i];
2857
+ for (let j = 0, {
2858
+ length: infosLength
2859
+ } = infos; j < infosLength; j += 1) {
2860
+ const {
2861
+ firstPatchedVersionIdentifier,
2862
+ vulnerableVersionRange
2863
+ } = infos[j];
2864
+ const {
2865
+ version: oldVersion
2866
+ } = node;
2867
+ if (shadowNpmInject.updateNode(node, packument, vulnerableVersionRange)) {
2868
+ try {
2869
+ // eslint-disable-next-line no-await-in-loop
2870
+ await npm.runScript('test', [], {
2871
+ spinner,
2872
+ stdio: 'ignore'
2873
+ });
2874
+ spinner?.info(`Patched ${name} ${oldVersion} -> ${node.version}`);
2875
+ if (isTopLevel(tree, node)) {
2876
+ for (const depField of ['dependencies', 'optionalDependencies', 'peerDependencies']) {
2877
+ const {
2878
+ content: pkgJson
2879
+ } = editablePkgJson;
2880
+ const oldVersion = pkgJson[depField]?.[name];
2881
+ if (oldVersion) {
2882
+ const decorator = /^[~^]/.exec(oldVersion)?.[0] ?? '';
2883
+ pkgJson[depField][name] = `${decorator}${node.version}`;
2869
2884
  }
2870
- // eslint-disable-next-line no-await-in-loop
2871
- await editablePkgJson.save();
2872
- } catch {
2873
- spinner.error(`Reverting ${name} to ${oldVersion}`);
2874
- arb.idealTree = revertToIdealTree;
2875
2885
  }
2876
- } else {
2877
- spinner.error(`Could not patch ${name} ${oldVersion}`);
2878
2886
  }
2887
+ // eslint-disable-next-line no-await-in-loop
2888
+ await editablePkgJson.save();
2889
+ } catch {
2890
+ spinner?.error(`Reverting ${name} to ${oldVersion}`);
2891
+ arb.idealTree = revertToIdealTree;
2879
2892
  }
2893
+ } else {
2894
+ spinner?.error(`Could not patch ${name} ${oldVersion}`);
2880
2895
  }
2881
2896
  }
2882
2897
  }
2883
2898
  }
2884
- const arb2 = new index.Arborist({
2899
+ const arb2 = new shadowNpmInject.Arborist({
2885
2900
  path: cwd
2886
2901
  });
2887
2902
  arb2.idealTree = arb.idealTree;
2888
2903
  await arb2.reify();
2889
- spinner.stop();
2904
+ spinner?.stop();
2890
2905
  }
2891
2906
 
2892
- const {
2893
- DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$s
2894
- } = constants;
2895
- const config$t = {
2896
- commandName: 'fix',
2897
- description: 'Fix "fixable" Socket alerts',
2898
- hidden: true,
2899
- flags: {
2900
- ...commonFlags
2901
- },
2902
- help: (command, config) => `
2903
- Usage
2904
- $ ${command}
2905
-
2906
- Options
2907
- ${getFlagListOutput(config.flags, 6)}
2908
- `
2909
- };
2910
- const cmdFix = {
2911
- description: config$t.description,
2912
- hidden: config$t.hidden,
2913
- run: run$t
2914
- };
2915
- async function run$t(argv, importMeta, {
2916
- parentName
2917
- }) {
2918
- const cli = meowOrExit({
2919
- argv,
2920
- config: config$t,
2921
- importMeta,
2922
- parentName
2923
- });
2924
- if (cli.flags['dryRun']) {
2925
- logger.logger.log(DRY_RUN_BAIL_TEXT$s);
2926
- return;
2907
+ async function getAlertsMapFromPnpmLockfile(lockfile, options) {
2908
+ const {
2909
+ spinner
2910
+ } = {
2911
+ __proto__: null,
2912
+ ...options
2913
+ };
2914
+ const depTypes = lockfile_detectDepTypes.detectDepTypes(lockfile);
2915
+ const pkgIds = Object.keys(depTypes);
2916
+ let {
2917
+ length: remaining
2918
+ } = pkgIds;
2919
+ const alertsByPkgId = new Map();
2920
+ if (!remaining) {
2921
+ return alertsByPkgId;
2922
+ }
2923
+ const getText = () => `Looking up data for ${remaining} packages`;
2924
+ spinner?.start(getText());
2925
+ const toAlertsMapOptions = {
2926
+ overrides: lockfile.overrides,
2927
+ ...options
2928
+ };
2929
+ for await (const artifact of shadowNpmInject.batchScan(pkgIds)) {
2930
+ await shadowNpmInject.addArtifactToAlertsMap(artifact, alertsByPkgId, toAlertsMapOptions);
2931
+ remaining -= 1;
2932
+ if (spinner && remaining > 0) {
2933
+ spinner.start();
2934
+ spinner.setText(getText());
2935
+ }
2927
2936
  }
2928
- await runFix();
2937
+ spinner?.stop();
2938
+ return alertsByPkgId;
2929
2939
  }
2930
2940
 
2931
- function objectSome(obj) {
2932
- for (const key in obj) {
2933
- if (obj[key]) {
2934
- return true;
2941
+ function cmdFlagsToString(args) {
2942
+ const result = [];
2943
+ for (let i = 0, {
2944
+ length
2945
+ } = args; i < length; i += 1) {
2946
+ if (args[i].startsWith('--')) {
2947
+ // Check if the next item exists and is NOT another flag.
2948
+ if (i + 1 < length && !args[i + 1].startsWith('--')) {
2949
+ result.push(`${args[i]}=${args[i + 1]}`);
2950
+ i += 1;
2951
+ } else {
2952
+ result.push(args[i]);
2953
+ }
2935
2954
  }
2936
2955
  }
2937
- return false;
2956
+ return result.join(' ');
2938
2957
  }
2939
- function pick(input, keys) {
2940
- const result = {};
2941
- for (const key of keys) {
2942
- result[key] = input[key];
2958
+
2959
+ const {
2960
+ SOCKET_IPC_HANDSHAKE
2961
+ } = constants;
2962
+ function safeNpmInstall(options) {
2963
+ const {
2964
+ agentExecPath = shadowNpmPaths.getNpmBinPath(),
2965
+ args = [],
2966
+ ipc,
2967
+ spinner,
2968
+ ...spawnOptions
2969
+ } = {
2970
+ __proto__: null,
2971
+ ...options
2972
+ };
2973
+ const useIpc = objects.isObject(ipc);
2974
+ const useDebug = debug.isDebug();
2975
+ const terminatorPos = args.indexOf('--');
2976
+ const npmArgs = (terminatorPos === -1 ? args : args.slice(0, terminatorPos)).filter(a => !npm.isAuditFlag(a) && !npm.isFundFlag(a) && !npm.isProgressFlag(a));
2977
+ const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
2978
+ const isSilent = !useDebug && !npmArgs.some(npm.isLoglevelFlag);
2979
+ const logLevelArgs = isSilent ? ['--loglevel', 'error'] : [];
2980
+ const spawnPromise = spawn.spawn(
2981
+ // Lazily access constants.execPath.
2982
+ constants.execPath, [
2983
+ // Lazily access constants.nodeHardenFlags.
2984
+ ...constants.nodeHardenFlags,
2985
+ // Lazily access constants.nodeNoWarningsFlags.
2986
+ ...constants.nodeNoWarningsFlags, '--require',
2987
+ // Lazily access constants.distShadowNpmInjectPath.
2988
+ constants.distShadowNpmInjectPath, agentExecPath, 'install',
2989
+ // Avoid code paths for 'audit' and 'fund'.
2990
+ '--no-audit', '--no-fund',
2991
+ // Add `--no-progress` flag to fix input being swallowed by the spinner
2992
+ // when running the command with recent versions of npm.
2993
+ '--no-progress',
2994
+ // Add '--loglevel=error' if a loglevel flag is not provided and the
2995
+ // SOCKET_CLI_DEBUG environment variable is not truthy.
2996
+ ...logLevelArgs, ...npmArgs, ...otherArgs], {
2997
+ spinner,
2998
+ // Set stdio to include 'ipc'.
2999
+ // See https://github.com/nodejs/node/blob/v23.6.0/lib/child_process.js#L161-L166
3000
+ // and https://github.com/nodejs/node/blob/v23.6.0/lib/internal/child_process.js#L238.
3001
+ stdio: useIpc ? [0, 1, 2, 'ipc'] : 'inherit',
3002
+ ...spawnOptions,
3003
+ env: {
3004
+ ...process$1.env,
3005
+ ...spawnOptions.env
3006
+ }
3007
+ });
3008
+ if (useIpc) {
3009
+ spawnPromise.process.send({
3010
+ [SOCKET_IPC_HANDSHAKE]: ipc
3011
+ });
2943
3012
  }
2944
- return result;
3013
+ return spawnPromise;
2945
3014
  }
2946
3015
 
2947
- function stringJoinWithSeparateFinalSeparator(list, separator = ' and ') {
2948
- const values = list.filter(Boolean);
3016
+ const {
3017
+ NPM: NPM$e
3018
+ } = constants;
3019
+ function runAgentInstall(pkgEnvDetails, options) {
2949
3020
  const {
2950
- length
2951
- } = values;
2952
- if (!length) {
2953
- return '';
2954
- }
2955
- if (length === 1) {
2956
- return values[0];
3021
+ agent,
3022
+ agentExecPath
3023
+ } = pkgEnvDetails;
3024
+ // All package managers support the "install" command.
3025
+ if (agent === NPM$e) {
3026
+ return safeNpmInstall({
3027
+ agentExecPath,
3028
+ ...options
3029
+ });
2957
3030
  }
2958
- const finalValue = values.pop();
2959
- return `${values.join(', ')}${separator}${finalValue}`;
3031
+ const {
3032
+ args = [],
3033
+ spinner,
3034
+ ...spawnOptions
3035
+ } = {
3036
+ __proto__: null,
3037
+ ...options
3038
+ };
3039
+ return spawn.spawn(agentExecPath, ['install', ...args], {
3040
+ spinner,
3041
+ stdio: debug.isDebug() ? 'inherit' : 'ignore',
3042
+ ...spawnOptions,
3043
+ env: {
3044
+ ...process.env,
3045
+ NODE_OPTIONS: cmdFlagsToString([
3046
+ // Lazily access constants.nodeHardenFlags.
3047
+ ...constants.nodeHardenFlags,
3048
+ // Lazily access constants.nodeNoWarningsFlags.
3049
+ ...constants.nodeNoWarningsFlags]),
3050
+ ...spawnOptions.env
3051
+ }
3052
+ });
2960
3053
  }
2961
3054
 
2962
- // Ordered from most severe to least.
2963
- const SEVERITIES_BY_ORDER = ['critical', 'high', 'middle', 'low'];
2964
- function getDesiredSeverities(lowestToInclude) {
2965
- const result = [];
2966
- for (const severity of SEVERITIES_BY_ORDER) {
2967
- result.push(severity);
2968
- if (severity === lowestToInclude) {
2969
- break;
2970
- }
3055
+ const {
3056
+ NPM: NPM$d,
3057
+ OVERRIDES: OVERRIDES$2,
3058
+ PNPM: PNPM$9
3059
+ } = constants;
3060
+ async function pnpmFix(pkgEnvDetails, cwd, options) {
3061
+ const {
3062
+ spinner
3063
+ } = {
3064
+ __proto__: null,
3065
+ ...options
3066
+ };
3067
+ spinner?.start();
3068
+ const lockfile = await lockfileFile.readWantedLockfile(cwd, {
3069
+ ignoreIncompatible: false
3070
+ });
3071
+ if (!lockfile) {
3072
+ spinner?.stop();
3073
+ return;
2971
3074
  }
2972
- return result;
2973
- }
2974
- function formatSeverityCount(severityCount) {
2975
- const summary = [];
2976
- for (const severity of SEVERITIES_BY_ORDER) {
2977
- if (severityCount[severity]) {
2978
- summary.push(`${severityCount[severity]} ${severity}`);
3075
+ const alertsMap = await getAlertsMapFromPnpmLockfile(lockfile, {
3076
+ consolidate: true,
3077
+ include: {
3078
+ existing: true,
3079
+ unfixable: false,
3080
+ upgrade: false
2979
3081
  }
3082
+ });
3083
+ const infoByPkg = shadowNpmInject.getCveInfoByAlertsMap(alertsMap);
3084
+ if (!infoByPkg) {
3085
+ spinner?.stop();
3086
+ return;
2980
3087
  }
2981
- return stringJoinWithSeparateFinalSeparator(summary);
2982
- }
2983
- function getSeverityCount(issues, lowestToInclude) {
2984
- const severityCount = pick({
2985
- low: 0,
2986
- middle: 0,
2987
- high: 0,
2988
- critical: 0
2989
- }, getDesiredSeverities(lowestToInclude));
2990
- for (const issue of issues) {
2991
- const {
2992
- value
2993
- } = issue;
2994
- if (!value) {
3088
+ const arb = new shadowNpmInject.SafeArborist({
3089
+ path: cwd,
3090
+ ...shadowNpmInject.SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES
3091
+ });
3092
+ await arb.loadActual();
3093
+ const editablePkgJson = await packages.readPackageJson(cwd, {
3094
+ editable: true
3095
+ });
3096
+ const {
3097
+ content: pkgJson
3098
+ } = editablePkgJson;
3099
+ for (const {
3100
+ 0: name,
3101
+ 1: infos
3102
+ } of infoByPkg) {
3103
+ const tree = arb.actualTree;
3104
+ const hasUpgrade = !!registry.getManifestData(NPM$d, name);
3105
+ if (hasUpgrade) {
3106
+ spinner?.info(`Skipping ${name}. Socket Optimize package exists.`);
2995
3107
  continue;
2996
3108
  }
2997
- if (severityCount[value.severity] !== undefined) {
2998
- severityCount[value.severity] += 1;
3109
+ const nodes = shadowNpmInject.findPackageNodes(tree, name);
3110
+ const packument = nodes.length && infos.length ?
3111
+ // eslint-disable-next-line no-await-in-loop
3112
+ await packages.fetchPackagePackument(name) : null;
3113
+ if (!packument) {
3114
+ continue;
2999
3115
  }
3000
- }
3001
- return severityCount;
3002
- }
3116
+ for (let i = 0, {
3117
+ length: nodesLength
3118
+ } = nodes; i < nodesLength; i += 1) {
3119
+ const node = nodes[i];
3120
+ for (let j = 0, {
3121
+ length: infosLength
3122
+ } = infos; j < infosLength; j += 1) {
3123
+ const {
3124
+ firstPatchedVersionIdentifier,
3125
+ vulnerableVersionRange
3126
+ } = infos[j];
3127
+ const {
3128
+ version: oldVersion
3129
+ } = node;
3130
+ const availableVersions = Object.keys(packument.versions);
3131
+ // Find the highest non-vulnerable version within the same major range
3132
+ const targetVersion = shadowNpmInject.findBestPatchVersion(node, availableVersions, vulnerableVersionRange);
3133
+ const targetPackument = targetVersion ? packument.versions[targetVersion] : undefined;
3134
+ if (targetPackument) {
3135
+ const oldPnpm = pkgJson[PNPM$9];
3136
+ const oldOverrides = oldPnpm?.[OVERRIDES$2];
3137
+ try {
3138
+ editablePkgJson.update({
3139
+ [PNPM$9]: {
3140
+ ...oldPnpm,
3141
+ [OVERRIDES$2]: {
3142
+ [`${node.name}@${vulnerableVersionRange}`]: `^${targetVersion}`,
3143
+ ...oldOverrides
3144
+ }
3145
+ }
3146
+ });
3147
+ spinner?.info(`Patched ${name} ${oldVersion} -> ${node.version}`);
3003
3148
 
3004
- async function fetchPackageInfo(pkgName, pkgVersion, includeAllIssues) {
3005
- // Lazily access constants.spinner.
3006
- const {
3007
- spinner
3008
- } = constants;
3009
- spinner.start(pkgVersion === 'latest' ? `Looking up data for the latest version of ${pkgName}` : `Looking up data for version ${pkgVersion} of ${pkgName}`);
3010
- const socketSdk = await index.setupSdk(index.getPublicToken());
3011
- const result = await handleApiCall(socketSdk.getIssuesByNPMPackage(pkgName, pkgVersion), 'looking up package');
3012
- const scoreResult = await handleApiCall(socketSdk.getScoreByNPMPackage(pkgName, pkgVersion), 'looking up package score');
3013
- if (result.success === false) {
3014
- return handleUnsuccessfulApiResponse('getIssuesByNPMPackage', result, spinner);
3015
- }
3016
- if (scoreResult.success === false) {
3017
- return handleUnsuccessfulApiResponse('getScoreByNPMPackage', scoreResult, spinner);
3149
+ // eslint-disable-next-line no-await-in-loop
3150
+ await editablePkgJson.save();
3151
+ // eslint-disable-next-line no-await-in-loop
3152
+ await runAgentInstall(pkgEnvDetails, {
3153
+ spinner
3154
+ });
3155
+ } catch {
3156
+ spinner?.error(`Reverting ${name} to ${oldVersion}`);
3157
+ }
3158
+ } else {
3159
+ spinner?.error(`Could not patch ${name} ${oldVersion}`);
3160
+ }
3161
+ }
3162
+ }
3018
3163
  }
3019
- const severityCount = getSeverityCount(result.data, includeAllIssues ? undefined : 'high');
3020
- spinner?.successAndStop('Data fetched');
3021
- return {
3022
- data: result.data,
3023
- severityCount,
3024
- score: scoreResult.data
3025
- };
3164
+ spinner?.stop();
3026
3165
  }
3027
3166
 
3028
3167
  const {
3029
- NPM: NPM$c
3030
- } = registryConstants;
3031
- function formatPackageInfo({
3032
- data,
3033
- score,
3034
- severityCount
3168
+ BINARY_LOCK_EXT,
3169
+ BUN: BUN$6,
3170
+ LOCK_EXT: LOCK_EXT$1,
3171
+ NPM: NPM$c,
3172
+ PNPM: PNPM$8,
3173
+ VLT: VLT$6,
3174
+ YARN,
3175
+ YARN_BERRY: YARN_BERRY$6,
3176
+ YARN_CLASSIC: YARN_CLASSIC$6
3177
+ } = constants;
3178
+ const AGENTS = [BUN$6, NPM$c, PNPM$8, YARN_BERRY$6, YARN_CLASSIC$6, VLT$6];
3179
+ const binByAgent = {
3180
+ __proto__: null,
3181
+ [BUN$6]: BUN$6,
3182
+ [NPM$c]: NPM$c,
3183
+ [PNPM$8]: PNPM$8,
3184
+ [YARN_BERRY$6]: YARN,
3185
+ [YARN_CLASSIC$6]: YARN,
3186
+ [VLT$6]: VLT$6
3187
+ };
3188
+ async function getAgentExecPath(agent) {
3189
+ const binName = binByAgent[agent];
3190
+ return (await which(binName, {
3191
+ nothrow: true
3192
+ })) ?? binName;
3193
+ }
3194
+ async function getAgentVersion(agentExecPath, cwd) {
3195
+ let result;
3196
+ try {
3197
+ result = semver.coerce(
3198
+ // All package managers support the "--version" flag.
3199
+ (await spawn.spawn(agentExecPath, ['--version'], {
3200
+ cwd
3201
+ })).stdout) ?? undefined;
3202
+ } catch {}
3203
+ return result;
3204
+ }
3205
+
3206
+ // The order of LOCKS properties IS significant as it affects iteration order.
3207
+ const LOCKS = {
3208
+ [`bun${LOCK_EXT$1}`]: BUN$6,
3209
+ [`bun${BINARY_LOCK_EXT}`]: BUN$6,
3210
+ // If both package-lock.json and npm-shrinkwrap.json are present in the root
3211
+ // of a project, npm-shrinkwrap.json will take precedence and package-lock.json
3212
+ // will be ignored.
3213
+ // https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json#package-lockjson-vs-npm-shrinkwrapjson
3214
+ 'npm-shrinkwrap.json': NPM$c,
3215
+ 'package-lock.json': NPM$c,
3216
+ 'pnpm-lock.yaml': PNPM$8,
3217
+ 'pnpm-lock.yml': PNPM$8,
3218
+ [`yarn${LOCK_EXT$1}`]: YARN_CLASSIC$6,
3219
+ 'vlt-lock.json': VLT$6,
3220
+ // Lastly, look for a hidden lock file which is present if .npmrc has package-lock=false:
3221
+ // https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json#hidden-lockfiles
3222
+ //
3223
+ // Unlike the other LOCKS keys this key contains a directory AND filename so
3224
+ // it has to be handled differently.
3225
+ 'node_modules/.package-lock.json': NPM$c
3226
+ };
3227
+ const readLockFileByAgent = (() => {
3228
+ function wrapReader(reader) {
3229
+ return async (...args) => {
3230
+ try {
3231
+ return await reader(...args);
3232
+ } catch {}
3233
+ return undefined;
3234
+ };
3235
+ }
3236
+ const binaryReader = wrapReader(shadowNpmInject.readFileBinary);
3237
+ const defaultReader = wrapReader(async lockPath => await shadowNpmInject.readFileUtf8(lockPath));
3238
+ return {
3239
+ [BUN$6]: wrapReader(async (lockPath, agentExecPath) => {
3240
+ const ext = path.extname(lockPath);
3241
+ if (ext === LOCK_EXT$1) {
3242
+ return await defaultReader(lockPath);
3243
+ }
3244
+ if (ext === BINARY_LOCK_EXT) {
3245
+ const lockBuffer = await binaryReader(lockPath);
3246
+ if (lockBuffer) {
3247
+ try {
3248
+ return index_cjs.parse(lockBuffer);
3249
+ } catch {}
3250
+ }
3251
+ // To print a Yarn lockfile to your console without writing it to disk
3252
+ // use `bun bun.lockb`.
3253
+ // https://bun.sh/guides/install/yarnlock
3254
+ return (await spawn.spawn(agentExecPath, [lockPath])).stdout.trim();
3255
+ }
3256
+ return undefined;
3257
+ }),
3258
+ [NPM$c]: defaultReader,
3259
+ [PNPM$8]: defaultReader,
3260
+ [VLT$6]: defaultReader,
3261
+ [YARN_BERRY$6]: defaultReader,
3262
+ [YARN_CLASSIC$6]: defaultReader
3263
+ };
3264
+ })();
3265
+ async function detectPackageEnvironment({
3266
+ cwd = process$1.cwd(),
3267
+ onUnknown
3268
+ } = {}) {
3269
+ let lockPath = await shadowNpmInject.findUp(Object.keys(LOCKS), {
3270
+ cwd
3271
+ });
3272
+ let lockName = lockPath ? path.basename(lockPath) : undefined;
3273
+ const isHiddenLockFile = lockName === '.package-lock.json';
3274
+ const pkgJsonPath = lockPath ? path.resolve(lockPath, `${isHiddenLockFile ? '../' : ''}../package.json`) : await shadowNpmInject.findUp('package.json', {
3275
+ cwd
3276
+ });
3277
+ const pkgPath = pkgJsonPath && fs.existsSync(pkgJsonPath) ? path.dirname(pkgJsonPath) : undefined;
3278
+ const editablePkgJson = pkgPath ? await packages.readPackageJson(pkgPath, {
3279
+ editable: true
3280
+ }) : undefined;
3281
+ const pkgJson = editablePkgJson?.content;
3282
+ // Read Corepack `packageManager` field in package.json:
3283
+ // https://nodejs.org/api/packages.html#packagemanager
3284
+ const pkgManager = strings.isNonEmptyString(pkgJson?.packageManager) ? pkgJson.packageManager : undefined;
3285
+ let agent;
3286
+ let agentVersion;
3287
+ if (pkgManager) {
3288
+ const atSignIndex = pkgManager.lastIndexOf('@');
3289
+ if (atSignIndex !== -1) {
3290
+ const name = pkgManager.slice(0, atSignIndex);
3291
+ const version = pkgManager.slice(atSignIndex + 1);
3292
+ if (version && AGENTS.includes(name)) {
3293
+ agent = name;
3294
+ agentVersion = semver.coerce(version) ?? undefined;
3295
+ }
3296
+ }
3297
+ }
3298
+ if (agent === undefined && !isHiddenLockFile && typeof pkgJsonPath === 'string' && typeof lockName === 'string') {
3299
+ agent = LOCKS[lockName];
3300
+ }
3301
+ if (agent === undefined) {
3302
+ agent = NPM$c;
3303
+ onUnknown?.(pkgManager);
3304
+ }
3305
+ const agentExecPath = await getAgentExecPath(agent);
3306
+ const npmExecPath = agent === NPM$c ? agentExecPath : await getAgentExecPath(NPM$c);
3307
+ if (agentVersion === undefined) {
3308
+ agentVersion = await getAgentVersion(agentExecPath, cwd);
3309
+ }
3310
+ if (agent === YARN_CLASSIC$6 && (agentVersion?.major ?? 0) > 1) {
3311
+ agent = YARN_BERRY$6;
3312
+ }
3313
+ const targets = {
3314
+ browser: false,
3315
+ node: true
3316
+ };
3317
+ let lockSrc;
3318
+ // Lazily access constants.maintainedNodeVersions.
3319
+ let minimumNodeVersion = constants.maintainedNodeVersions.last;
3320
+ if (pkgJson) {
3321
+ const browserField = pkgJson.browser;
3322
+ if (strings.isNonEmptyString(browserField) || objects.isObjectObject(browserField)) {
3323
+ targets.browser = true;
3324
+ }
3325
+ const nodeRange = pkgJson.engines?.['node'];
3326
+ if (strings.isNonEmptyString(nodeRange)) {
3327
+ const coerced = semver.coerce(nodeRange);
3328
+ if (coerced && semver.lt(coerced, minimumNodeVersion)) {
3329
+ minimumNodeVersion = coerced.version;
3330
+ }
3331
+ }
3332
+ const browserslistQuery = pkgJson['browserslist'];
3333
+ if (Array.isArray(browserslistQuery)) {
3334
+ const browserslistTargets = browserslist(browserslistQuery).map(s => s.toLowerCase()).sort(sorts.naturalCompare);
3335
+ const browserslistNodeTargets = browserslistTargets.filter(v => v.startsWith('node ')).map(v => v.slice(5 /*'node '.length*/));
3336
+ if (!targets.browser && browserslistTargets.length) {
3337
+ targets.browser = browserslistTargets.length !== browserslistNodeTargets.length;
3338
+ }
3339
+ if (browserslistNodeTargets.length) {
3340
+ const coerced = semver.coerce(browserslistNodeTargets[0]);
3341
+ if (coerced && semver.lt(coerced, minimumNodeVersion)) {
3342
+ minimumNodeVersion = coerced.version;
3343
+ }
3344
+ }
3345
+ }
3346
+ // Lazily access constants.maintainedNodeVersions.
3347
+ targets.node = constants.maintainedNodeVersions.some(v => semver.satisfies(v, `>=${minimumNodeVersion}`));
3348
+ lockSrc = typeof lockPath === 'string' ? await readLockFileByAgent[agent](lockPath, agentExecPath) : undefined;
3349
+ } else {
3350
+ lockName = undefined;
3351
+ lockPath = undefined;
3352
+ }
3353
+ return {
3354
+ agent,
3355
+ agentExecPath,
3356
+ agentVersion,
3357
+ lockName,
3358
+ lockPath,
3359
+ lockSrc,
3360
+ minimumNodeVersion,
3361
+ npmExecPath,
3362
+ pkgJson: editablePkgJson,
3363
+ pkgPath,
3364
+ supported: targets.browser || targets.node,
3365
+ targets
3366
+ };
3367
+ }
3368
+
3369
+ const {
3370
+ BUN: BUN$5,
3371
+ VLT: VLT$5,
3372
+ YARN_BERRY: YARN_BERRY$5
3373
+ } = constants;
3374
+ const COMMAND_TITLE$2 = 'Socket Optimize';
3375
+ async function detectAndValidatePackageEnvironment(cwd, options) {
3376
+ const {
3377
+ logger,
3378
+ prod
3379
+ } = {
3380
+ __proto__: null,
3381
+ ...options
3382
+ };
3383
+ const details = await detectPackageEnvironment({
3384
+ cwd,
3385
+ onUnknown(pkgManager) {
3386
+ logger?.warn(`${COMMAND_TITLE$2}: Unknown package manager${pkgManager ? ` ${pkgManager}` : ''}, defaulting to npm`);
3387
+ }
3388
+ });
3389
+ if (!details.supported) {
3390
+ logger?.fail(`${COMMAND_TITLE$2}: No supported Node or browser range detected`);
3391
+ return;
3392
+ }
3393
+ if (details.agent === VLT$5) {
3394
+ logger?.fail(`${COMMAND_TITLE$2}: ${details.agent} does not support overrides. Soon, though ⚡`);
3395
+ return;
3396
+ }
3397
+ const lockName = details.lockName ?? 'lock file';
3398
+ if (details.lockName === undefined || details.lockSrc === undefined) {
3399
+ logger?.fail(`${COMMAND_TITLE$2}: No ${lockName} found`);
3400
+ return;
3401
+ }
3402
+ if (details.lockSrc.trim() === '') {
3403
+ logger?.fail(`${COMMAND_TITLE$2}: ${lockName} is empty`);
3404
+ return;
3405
+ }
3406
+ if (details.pkgPath === undefined) {
3407
+ logger?.fail(`${COMMAND_TITLE$2}: No package.json found`);
3408
+ return;
3409
+ }
3410
+ if (prod && (details.agent === BUN$5 || details.agent === YARN_BERRY$5)) {
3411
+ logger?.fail(`${COMMAND_TITLE$2}: --prod not supported for ${details.agent}${details.agentVersion ? `@${details.agentVersion.toString()}` : ''}`);
3412
+ return;
3413
+ }
3414
+ if (details.lockPath && path.relative(cwd, details.lockPath).startsWith('.')) {
3415
+ logger?.warn(`${COMMAND_TITLE$2}: Package ${lockName} found at ${details.lockPath}`);
3416
+ }
3417
+ return details;
3418
+ }
3419
+
3420
+ const {
3421
+ NPM: NPM$b,
3422
+ PNPM: PNPM$7
3423
+ } = constants;
3424
+ async function runFix() {
3425
+ // Lazily access constants.spinner.
3426
+ const {
3427
+ spinner
3428
+ } = constants;
3429
+ spinner.start();
3430
+ const cwd = process.cwd();
3431
+ const pkgEnvDetails = await detectAndValidatePackageEnvironment(cwd, {
3432
+ logger: logger.logger
3433
+ });
3434
+ if (!pkgEnvDetails) {
3435
+ spinner.stop();
3436
+ return;
3437
+ }
3438
+ switch (pkgEnvDetails.agent) {
3439
+ case NPM$b:
3440
+ {
3441
+ await npmFix(pkgEnvDetails, cwd);
3442
+ break;
3443
+ }
3444
+ case PNPM$7:
3445
+ {
3446
+ await pnpmFix(pkgEnvDetails, cwd);
3447
+ break;
3448
+ }
3449
+ }
3450
+ spinner.successAndStop('Socket.dev fix successful');
3451
+ }
3452
+
3453
+ const {
3454
+ DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$s
3455
+ } = constants;
3456
+ const config$t = {
3457
+ commandName: 'fix',
3458
+ description: 'Fix "fixable" Socket alerts',
3459
+ hidden: true,
3460
+ flags: {
3461
+ ...commonFlags
3462
+ },
3463
+ help: (command, config) => `
3464
+ Usage
3465
+ $ ${command}
3466
+
3467
+ Options
3468
+ ${getFlagListOutput(config.flags, 6)}
3469
+ `
3470
+ };
3471
+ const cmdFix = {
3472
+ description: config$t.description,
3473
+ hidden: config$t.hidden,
3474
+ run: run$t
3475
+ };
3476
+ async function run$t(argv, importMeta, {
3477
+ parentName
3478
+ }) {
3479
+ const cli = meowOrExit({
3480
+ argv,
3481
+ config: config$t,
3482
+ importMeta,
3483
+ parentName
3484
+ });
3485
+ if (cli.flags['dryRun']) {
3486
+ logger.logger.log(DRY_RUN_BAIL_TEXT$s);
3487
+ return;
3488
+ }
3489
+ await runFix();
3490
+ }
3491
+
3492
+ async function fetchPackageInfo(pkgName, pkgVersion, includeAllIssues) {
3493
+ const socketSdk = await shadowNpmInject.setupSdk(shadowNpmInject.getPublicToken());
3494
+ const result = await handleApiCall(socketSdk.getIssuesByNPMPackage(pkgName, pkgVersion), 'looking up package');
3495
+ const scoreResult = await handleApiCall(socketSdk.getScoreByNPMPackage(pkgName, pkgVersion), 'looking up package score');
3496
+ if (result.success === false) {
3497
+ return handleUnsuccessfulApiResponse('getIssuesByNPMPackage', result);
3498
+ }
3499
+ if (scoreResult.success === false) {
3500
+ return handleUnsuccessfulApiResponse('getScoreByNPMPackage', scoreResult);
3501
+ }
3502
+ const severityCount = shadowNpmInject.getSeverityCount(result.data, includeAllIssues ? undefined : 'high');
3503
+ return {
3504
+ data: result.data,
3505
+ severityCount,
3506
+ score: scoreResult.data
3507
+ };
3508
+ }
3509
+
3510
+ const {
3511
+ NPM: NPM$a
3512
+ } = registryConstants;
3513
+ function formatScore(score) {
3514
+ if (score > 80) {
3515
+ return colors.green(`${score}`);
3516
+ } else if (score < 80 && score > 60) {
3517
+ return colors.yellow(`${score}`);
3518
+ }
3519
+ return colors.red(`${score}`);
3520
+ }
3521
+ function logPackageIssuesDetails(packageData, outputMarkdown) {
3522
+ const issueDetails = packageData.filter(d => d.value?.severity === shadowNpmInject.SEVERITY.critical || d.value?.severity === shadowNpmInject.SEVERITY.high);
3523
+ const uniqueIssueDetails = issueDetails.reduce((acc, issue) => {
3524
+ const {
3525
+ type
3526
+ } = issue;
3527
+ if (type) {
3528
+ const details = acc.get(type);
3529
+ if (details) {
3530
+ details.count += 1;
3531
+ } else {
3532
+ acc.set(type, {
3533
+ label: issue.value?.label ?? '',
3534
+ count: 1
3535
+ });
3536
+ }
3537
+ }
3538
+ return acc;
3539
+ }, new Map());
3540
+ const format = new shadowNpmInject.ColorOrMarkdown(outputMarkdown);
3541
+ for (const [type, details] of uniqueIssueDetails.entries()) {
3542
+ const issueWithLink = format.hyperlink(details.label, shadowNpmInject.getSocketDevAlertUrl(type), {
3543
+ fallbackToUrl: true
3544
+ });
3545
+ if (details.count === 1) {
3546
+ logger.logger.log(`- ${issueWithLink}`);
3547
+ } else {
3548
+ logger.logger.log(`- ${issueWithLink}: ${details.count}`);
3549
+ }
3550
+ }
3551
+ }
3552
+ function logPackageInfo({
3553
+ data,
3554
+ score,
3555
+ severityCount
3035
3556
  }, {
3036
3557
  name,
3037
3558
  outputKind,
@@ -3043,10 +3564,13 @@ function formatPackageInfo({
3043
3564
  return;
3044
3565
  }
3045
3566
  if (outputKind === 'markdown') {
3046
- logger.logger.log(`\n# Package report for ${pkgName}\n`);
3047
- logger.logger.log('Package report card:\n');
3567
+ logger.logger.log(commonTags.stripIndents`
3568
+ # Package report for ${pkgName}
3569
+
3570
+ Package report card:
3571
+ `);
3048
3572
  } else {
3049
- logger.logger.log(`\nPackage report card for ${pkgName}:\n`);
3573
+ logger.logger.log(`Package report card for ${pkgName}:`);
3050
3574
  }
3051
3575
  const scoreResult = {
3052
3576
  'Supply Chain Risk': Math.floor(score.supplyChainRisk.score * 100),
@@ -3055,19 +3579,20 @@ function formatPackageInfo({
3055
3579
  Vulnerabilities: Math.floor(score.vulnerability.score * 100),
3056
3580
  License: Math.floor(score.license.score * 100)
3057
3581
  };
3582
+ logger.logger.log('\n');
3058
3583
  Object.entries(scoreResult).map(score => logger.logger.log(`- ${score[0]}: ${formatScore(score[1])}`));
3059
3584
  logger.logger.log('\n');
3060
- if (objectSome(severityCount)) {
3585
+ if (objects.hasKeys(severityCount)) {
3061
3586
  if (outputKind === 'markdown') {
3062
3587
  logger.logger.log('# Issues\n');
3063
3588
  }
3064
- logger.logger.log(`Package has these issues: ${formatSeverityCount(severityCount)}\n`);
3065
- formatPackageIssuesDetails(data, outputKind === 'markdown');
3589
+ logger.logger.log(`Package has these issues: ${shadowNpmInject.formatSeverityCount(severityCount)}\n`);
3590
+ logPackageIssuesDetails(data, outputKind === 'markdown');
3066
3591
  } else {
3067
3592
  logger.logger.log('Package has no issues');
3068
3593
  }
3069
- const format = new index.ColorOrMarkdown(outputKind === 'markdown');
3070
- const url = index.getSocketDevPackageOverviewUrl(NPM$c, pkgName, pkgVersion);
3594
+ const format = new shadowNpmInject.ColorOrMarkdown(outputKind === 'markdown');
3595
+ const url = shadowNpmInject.getSocketDevPackageOverviewUrl(NPM$a, pkgName, pkgVersion);
3071
3596
  logger.logger.log('\n');
3072
3597
  if (pkgVersion === 'latest') {
3073
3598
  logger.logger.log(`Detailed info on socket.dev: ${format.hyperlink(`${pkgName}`, url, {
@@ -3084,44 +3609,6 @@ function formatPackageInfo({
3084
3609
  logger.logger.log('');
3085
3610
  }
3086
3611
  }
3087
- function formatPackageIssuesDetails(packageData, outputMarkdown) {
3088
- const issueDetails = packageData.filter(d => d.value?.severity === 'high' || d.value?.severity === 'critical');
3089
- const uniqueIssues = issueDetails.reduce((acc, issue) => {
3090
- const {
3091
- type
3092
- } = issue;
3093
- if (type) {
3094
- if (acc[type] === undefined) {
3095
- acc[type] = {
3096
- label: issue.value?.label,
3097
- count: 1
3098
- };
3099
- } else {
3100
- acc[type].count += 1;
3101
- }
3102
- }
3103
- return acc;
3104
- }, {});
3105
- const format = new index.ColorOrMarkdown(outputMarkdown);
3106
- for (const issue of Object.keys(uniqueIssues)) {
3107
- const issueWithLink = format.hyperlink(`${uniqueIssues[issue]?.label}`, index.getSocketDevAlertUrl(issue), {
3108
- fallbackToUrl: true
3109
- });
3110
- if (uniqueIssues[issue]?.count === 1) {
3111
- logger.logger.log(`- ${issueWithLink}`);
3112
- } else {
3113
- logger.logger.log(`- ${issueWithLink}: ${uniqueIssues[issue]?.count}`);
3114
- }
3115
- }
3116
- }
3117
- function formatScore(score) {
3118
- if (score > 80) {
3119
- return colors.green(`${score}`);
3120
- } else if (score < 80 && score > 60) {
3121
- return colors.yellow(`${score}`);
3122
- }
3123
- return colors.red(`${score}`);
3124
- }
3125
3612
 
3126
3613
  async function getPackageInfo({
3127
3614
  commandName,
@@ -3131,15 +3618,21 @@ async function getPackageInfo({
3131
3618
  pkgVersion,
3132
3619
  strict
3133
3620
  }) {
3621
+ // Lazily access constants.spinner.
3622
+ const {
3623
+ spinner
3624
+ } = constants;
3625
+ spinner.start(pkgVersion === 'latest' ? `Looking up data for the latest version of ${pkgName}` : `Looking up data for version ${pkgVersion} of ${pkgName}`);
3134
3626
  const packageData = await fetchPackageInfo(pkgName, pkgVersion, includeAllIssues);
3627
+ spinner.successAndStop('Data fetched');
3135
3628
  if (packageData) {
3136
- formatPackageInfo(packageData, {
3629
+ logPackageInfo(packageData, {
3137
3630
  name: commandName,
3138
3631
  outputKind,
3139
3632
  pkgName,
3140
3633
  pkgVersion
3141
3634
  });
3142
- if (strict && objectSome(packageData.severityCount)) {
3635
+ if (strict && objects.hasKeys(packageData.severityCount)) {
3143
3636
  // Let NodeJS exit gracefully but with exit(1)
3144
3637
  process$1.exitCode = 1;
3145
3638
  }
@@ -3196,7 +3689,7 @@ async function run$s(argv, importMeta, {
3196
3689
  // options or missing arguments.
3197
3690
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
3198
3691
  process.exitCode = 2;
3199
- logger.logger.error(`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
3692
+ logger.logger.fail(`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:\n
3200
3693
  - Expecting a package name ${!rawPkgName ? colors.red('(missing!)') : colors.green('(ok)')}\n
3201
3694
  - Can only accept one package at a time ${cli.input.length > 1 ? colors.red('(got ' + cli.input.length + '!)') : colors.green('(ok)')}\n`);
3202
3695
  return;
@@ -3219,18 +3712,18 @@ async function run$s(argv, importMeta, {
3219
3712
  }
3220
3713
 
3221
3714
  function applyLogin(apiToken, enforcedOrgs, apiBaseUrl, apiProxy) {
3222
- index.updateSetting('enforcedOrgs', enforcedOrgs);
3223
- index.updateSetting('apiToken', apiToken);
3224
- index.updateSetting('apiBaseUrl', apiBaseUrl);
3225
- index.updateSetting('apiProxy', apiProxy);
3715
+ shadowNpmInject.updateSetting('enforcedOrgs', enforcedOrgs);
3716
+ shadowNpmInject.updateSetting('apiToken', apiToken);
3717
+ shadowNpmInject.updateSetting('apiBaseUrl', apiBaseUrl);
3718
+ shadowNpmInject.updateSetting('apiProxy', apiProxy);
3226
3719
  }
3227
3720
 
3228
3721
  const {
3229
3722
  SOCKET_PUBLIC_API_TOKEN
3230
3723
  } = constants;
3231
3724
  async function attemptLogin(apiBaseUrl, apiProxy) {
3232
- apiBaseUrl ??= index.getSetting('apiBaseUrl') ?? undefined;
3233
- apiProxy ??= index.getSetting('apiProxy') ?? undefined;
3725
+ apiBaseUrl ??= shadowNpmInject.getSetting('apiBaseUrl') ?? undefined;
3726
+ apiProxy ??= shadowNpmInject.getSetting('apiProxy') ?? undefined;
3234
3727
  const apiToken = (await prompts.password({
3235
3728
  message: `Enter your ${terminalLink('Socket.dev API key', 'https://docs.socket.dev/docs/api-keys')} (leave blank for a public key)`
3236
3729
  })) || SOCKET_PUBLIC_API_TOKEN;
@@ -3241,13 +3734,13 @@ async function attemptLogin(apiBaseUrl, apiProxy) {
3241
3734
  spinner.start('Verifying API key...');
3242
3735
  let orgs;
3243
3736
  try {
3244
- const sdk = await index.setupSdk(apiToken, apiBaseUrl, apiProxy);
3737
+ const sdk = await shadowNpmInject.setupSdk(apiToken, apiBaseUrl, apiProxy);
3245
3738
  const result = await sdk.getOrganizations();
3246
3739
  if (!result.success) {
3247
- throw new index.AuthError();
3740
+ throw new shadowNpmInject.AuthError();
3248
3741
  }
3249
3742
  orgs = result.data;
3250
- spinner.successAndStop('API key verified');
3743
+ spinner.success('API key verified');
3251
3744
  } catch {
3252
3745
  spinner.errorAndStop('Invalid API key');
3253
3746
  return;
@@ -3285,14 +3778,13 @@ async function attemptLogin(apiBaseUrl, apiProxy) {
3285
3778
  }
3286
3779
  }
3287
3780
  }
3288
- const oldToken = index.getSetting('apiToken');
3781
+ spinner.stop();
3782
+ const oldToken = shadowNpmInject.getSetting('apiToken');
3289
3783
  try {
3290
3784
  applyLogin(apiToken, enforcedOrgs, apiBaseUrl, apiProxy);
3291
- spinner.start();
3292
- spinner.successAndStop(`API credentials ${oldToken ? 'updated' : 'set'}`);
3785
+ logger.logger.success(`API credentials ${oldToken ? 'updated' : 'set'}`);
3293
3786
  } catch {
3294
- spinner.start();
3295
- spinner.errorAndStop(`API login failed`);
3787
+ logger.logger.fail(`API login failed`);
3296
3788
  }
3297
3789
  }
3298
3790
 
@@ -3342,23 +3834,23 @@ async function run$r(argv, importMeta, {
3342
3834
  importMeta,
3343
3835
  parentName
3344
3836
  });
3345
- let apiBaseUrl = cli.flags['apiBaseUrl'];
3346
- let apiProxy = cli.flags['apiProxy'];
3837
+ const apiBaseUrl = cli.flags['apiBaseUrl'];
3838
+ const apiProxy = cli.flags['apiProxy'];
3347
3839
  if (cli.flags['dryRun']) {
3348
3840
  logger.logger.log(DRY_RUN_BAIL_TEXT$q);
3349
3841
  return;
3350
3842
  }
3351
3843
  if (!isInteractive()) {
3352
- throw new index.InputError('Cannot prompt for credentials in a non-interactive shell');
3844
+ throw new shadowNpmInject.InputError('Cannot prompt for credentials in a non-interactive shell');
3353
3845
  }
3354
3846
  await attemptLogin(apiBaseUrl, apiProxy);
3355
3847
  }
3356
3848
 
3357
3849
  function applyLogout() {
3358
- index.updateSetting('apiToken', null);
3359
- index.updateSetting('apiBaseUrl', null);
3360
- index.updateSetting('apiProxy', null);
3361
- index.updateSetting('enforcedOrgs', null);
3850
+ shadowNpmInject.updateSetting('apiToken', null);
3851
+ shadowNpmInject.updateSetting('apiBaseUrl', null);
3852
+ shadowNpmInject.updateSetting('apiProxy', null);
3853
+ shadowNpmInject.updateSetting('enforcedOrgs', null);
3362
3854
  }
3363
3855
 
3364
3856
  function attemptLogout() {
@@ -3366,7 +3858,7 @@ function attemptLogout() {
3366
3858
  applyLogout();
3367
3859
  logger.logger.success('Successfully logged out');
3368
3860
  } catch {
3369
- logger.logger.error('Failed to complete logout steps');
3861
+ logger.logger.fail('Failed to complete logout steps');
3370
3862
  }
3371
3863
  }
3372
3864
 
@@ -3448,14 +3940,14 @@ async function convertGradleToMaven(target, bin, _out, verbose, gradleOpts) {
3448
3940
  logger.logger.groupEnd();
3449
3941
  }
3450
3942
  if (output.stderr) {
3451
- logger.logger.error('There were errors while running gradle');
3943
+ process.exitCode = 1;
3944
+ logger.logger.fail('There were errors while running gradle');
3452
3945
  // (In verbose mode, stderr was printed above, no need to repeat it)
3453
3946
  if (!verbose) {
3454
3947
  logger.logger.group('[VERBOSE] stderr:');
3455
3948
  logger.logger.error(output.stderr);
3456
3949
  logger.logger.groupEnd();
3457
3950
  }
3458
- process.exitCode = 1;
3459
3951
  return;
3460
3952
  }
3461
3953
  logger.logger.success('Executed gradle successfully');
@@ -3467,7 +3959,7 @@ async function convertGradleToMaven(target, bin, _out, verbose, gradleOpts) {
3467
3959
 
3468
3960
  // const loc = output.stdout?.match(/Wrote (.*?.pom)\n/)?.[1]?.trim()
3469
3961
  // if (!loc) {
3470
- // logger.error(
3962
+ // logger.fail(
3471
3963
  // 'There were no errors from sbt but could not find the location of resulting .pom file either'
3472
3964
  // )
3473
3965
  // process.exit(1)
@@ -3493,15 +3985,14 @@ async function convertGradleToMaven(target, bin, _out, verbose, gradleOpts) {
3493
3985
  // spinner.successAndStop(`OK. File should be available in \`${out}\``)
3494
3986
  // }
3495
3987
  } catch (e) {
3496
- spinner.errorAndStop('There was an unexpected error while running this' + (verbose ? '' : ' (use --verbose for details)'));
3988
+ process.exitCode = 1;
3989
+ spinner.stop();
3990
+ logger.logger.fail('There was an unexpected error while running this' + (verbose ? '' : ' (use --verbose for details)'));
3497
3991
  if (verbose) {
3498
3992
  logger.logger.group('[VERBOSE] error:');
3499
3993
  logger.logger.log(e);
3500
3994
  logger.logger.groupEnd();
3501
3995
  }
3502
- process.exitCode = 1;
3503
- } finally {
3504
- spinner.stop();
3505
3996
  }
3506
3997
  }
3507
3998
 
@@ -3611,7 +4102,7 @@ async function run$p(argv, importMeta, {
3611
4102
  // options or missing arguments.
3612
4103
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
3613
4104
  process.exitCode = 2;
3614
- logger.logger.error(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
4105
+ logger.logger.fail(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
3615
4106
 
3616
4107
  - The DIR arg is required ${!target ? colors.red('(missing!)') : target === '-' ? colors.red('(stdin is not supported)') : colors.green('(ok)')}
3617
4108
 
@@ -3687,14 +4178,14 @@ async function convertSbtToMaven(target, bin, out, verbose, sbtOpts) {
3687
4178
  logger.logger.groupEnd();
3688
4179
  }
3689
4180
  if (output.stderr) {
3690
- logger.logger.error('There were errors while running sbt');
4181
+ process.exitCode = 1;
4182
+ logger.logger.fail('There were errors while running sbt');
3691
4183
  // (In verbose mode, stderr was printed above, no need to repeat it)
3692
4184
  if (!verbose) {
3693
4185
  logger.logger.group('[VERBOSE] stderr:');
3694
4186
  logger.logger.error(output.stderr);
3695
4187
  logger.logger.groupEnd();
3696
4188
  }
3697
- process.exitCode = 1;
3698
4189
  return;
3699
4190
  }
3700
4191
  const poms = [];
@@ -3703,8 +4194,8 @@ async function convertSbtToMaven(target, bin, out, verbose, sbtOpts) {
3703
4194
  return fn;
3704
4195
  });
3705
4196
  if (!poms.length) {
3706
- logger.logger.error('There were no errors from sbt but it seems to not have generated any poms either');
3707
4197
  process.exitCode = 1;
4198
+ logger.logger.fail('There were no errors from sbt but it seems to not have generated any poms either');
3708
4199
  return;
3709
4200
  }
3710
4201
  // Move the pom file to ...? initial cwd? loc will be an absolute path, or dump to stdout
@@ -3712,14 +4203,14 @@ async function convertSbtToMaven(target, bin, out, verbose, sbtOpts) {
3712
4203
  // TODO: maybe we can add an option to target a specific file to dump to stdout
3713
4204
  if (out === '-' && poms.length === 1) {
3714
4205
  logger.logger.log('Result:\n```');
3715
- logger.logger.log(await index.safeReadFile(poms[0], 'utf8'));
4206
+ logger.logger.log(await shadowNpmInject.safeReadFile(poms[0], 'utf8'));
3716
4207
  logger.logger.log('```');
3717
4208
  logger.logger.success(`OK`);
3718
4209
  } else if (out === '-') {
3719
- logger.logger.error('Requested out target was stdout but there are multiple generated files');
4210
+ process.exitCode = 1;
4211
+ logger.logger.fail('Requested out target was stdout but there are multiple generated files');
3720
4212
  poms.forEach(fn => logger.logger.error('-', fn));
3721
4213
  logger.logger.error('Exiting now...');
3722
- process.exitCode = 1;
3723
4214
  return;
3724
4215
  } else {
3725
4216
  // if (verbose) {
@@ -3736,15 +4227,14 @@ async function convertSbtToMaven(target, bin, out, verbose, sbtOpts) {
3736
4227
  logger.logger.success(`OK`);
3737
4228
  }
3738
4229
  } catch (e) {
3739
- spinner?.errorAndStop('There was an unexpected error while running this' + (verbose ? '' : ' (use --verbose for details)'));
4230
+ process.exitCode = 1;
4231
+ spinner.stop();
4232
+ logger.logger.fail('There was an unexpected error while running this' + (verbose ? '' : ' (use --verbose for details)'));
3740
4233
  if (verbose) {
3741
4234
  logger.logger.group('[VERBOSE] error:');
3742
4235
  logger.logger.log(e);
3743
4236
  logger.logger.groupEnd();
3744
4237
  }
3745
- process.exitCode = 1;
3746
- } finally {
3747
- spinner.stop();
3748
4238
  }
3749
4239
  }
3750
4240
 
@@ -3814,6 +4304,9 @@ const config$o = {
3814
4304
 
3815
4305
  Support is beta. Please report issues or give us feedback on what's missing.
3816
4306
 
4307
+ This is only for SBT. If your Scala setup uses gradle, please see the help
4308
+ sections for \`socket manifest gradle\` or \`socket cdxgen\`.
4309
+
3817
4310
  Examples
3818
4311
 
3819
4312
  $ ${command} ./build.sbt
@@ -3852,7 +4345,7 @@ async function run$o(argv, importMeta, {
3852
4345
  // options or missing arguments.
3853
4346
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
3854
4347
  process.exitCode = 2;
3855
- logger.logger.error(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
4348
+ logger.logger.fail(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
3856
4349
 
3857
4350
  - The DIR or FILE arg is required ${!target ? colors.red('(missing!)') : target === '-' ? colors.red('(stdin is not supported)') : colors.green('(ok)')}
3858
4351
 
@@ -4112,7 +4605,7 @@ async function run$m(argv, importMeta, {
4112
4605
  // options or missing arguments.
4113
4606
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
4114
4607
  process.exitCode = 2;
4115
- logger.logger.error(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
4608
+ logger.logger.fail(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
4116
4609
 
4117
4610
  - The DIR arg is required ${!target ? colors.red('(missing!)') : target === '-' ? colors.red('(stdin is not supported)') : colors.green('(ok)')}
4118
4611
 
@@ -4187,22 +4680,21 @@ async function run$l(argv, importMeta, {
4187
4680
  }
4188
4681
 
4189
4682
  const {
4190
- NPM: NPM$b,
4191
- SHADOW_BIN: SHADOW_BIN$1
4683
+ NPM: NPM$9
4192
4684
  } = constants;
4193
4685
  async function wrapNpm(argv) {
4194
- // Lazily access constants.distPath.
4195
- const shadowBin = require(`${constants.distPath}/${SHADOW_BIN$1}.js`);
4196
- await shadowBin(NPM$b, argv);
4686
+ // Lazily access constants.distShadowNpmBinPath.
4687
+ const shadowBin = require(constants.distShadowNpmBinPath);
4688
+ await shadowBin(NPM$9, argv);
4197
4689
  }
4198
4690
 
4199
4691
  const {
4200
4692
  DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$k,
4201
- NPM: NPM$a
4693
+ NPM: NPM$8
4202
4694
  } = constants;
4203
4695
  const config$k = {
4204
4696
  commandName: 'npm',
4205
- description: `${NPM$a} wrapper functionality`,
4697
+ description: `${NPM$8} wrapper functionality`,
4206
4698
  hidden: false,
4207
4699
  flags: {},
4208
4700
  help: (command, _config) => `
@@ -4233,12 +4725,11 @@ async function run$k(argv, importMeta, {
4233
4725
  }
4234
4726
 
4235
4727
  const {
4236
- NPX: NPX$2,
4237
- SHADOW_BIN
4728
+ NPX: NPX$2
4238
4729
  } = constants;
4239
4730
  async function wrapNpx(argv) {
4240
- // Lazily access constants.distPath.
4241
- const shadowBin = require(`${constants.distPath}/${SHADOW_BIN}.js`);
4731
+ // Lazily access constants.distShadowNpmBinPath.
4732
+ const shadowBin = require(constants.distShadowNpmBinPath);
4242
4733
  await shadowBin(NPX$2, argv);
4243
4734
  }
4244
4735
 
@@ -4301,289 +4792,36 @@ const cmdOops = {
4301
4792
  run: run$i
4302
4793
  };
4303
4794
  async function run$i(argv, importMeta, {
4304
- parentName
4305
- }) {
4306
- const cli = meowOrExit({
4307
- argv,
4308
- config: config$i,
4309
- importMeta,
4310
- parentName
4311
- });
4312
- if (cli.flags['dryRun']) {
4313
- logger.logger.log(DRY_RUN_BAIL_TEXT$i);
4314
- return;
4315
- }
4316
- throw new Error('This error was intentionally left blank');
4317
- }
4318
-
4319
- const {
4320
- BUN: BUN$6,
4321
- NPM: NPM$9,
4322
- PNPM: PNPM$7,
4323
- VLT: VLT$6,
4324
- YARN_BERRY: YARN_BERRY$6,
4325
- YARN_CLASSIC: YARN_CLASSIC$6
4326
- } = constants;
4327
- function matchHumanStdout(stdout, name) {
4328
- return stdout.includes(` ${name}@`);
4329
- }
4330
- function matchQueryStdout(stdout, name) {
4331
- return stdout.includes(`"${name}"`);
4332
- }
4333
- const depsIncludesByAgent = new Map([[BUN$6, matchHumanStdout], [NPM$9, matchQueryStdout], [PNPM$7, matchQueryStdout], [VLT$6, matchQueryStdout], [YARN_BERRY$6, matchHumanStdout], [YARN_CLASSIC$6, matchHumanStdout]]);
4334
-
4335
- const {
4336
- BINARY_LOCK_EXT,
4337
- BUN: BUN$5,
4338
- LOCK_EXT: LOCK_EXT$1,
4339
- NPM: NPM$8,
4340
- PNPM: PNPM$6,
4341
- VLT: VLT$5,
4342
- YARN,
4343
- YARN_BERRY: YARN_BERRY$5,
4344
- YARN_CLASSIC: YARN_CLASSIC$5
4345
- } = constants;
4346
- const AGENTS = [BUN$5, NPM$8, PNPM$6, YARN_BERRY$5, YARN_CLASSIC$5, VLT$5];
4347
- const binByAgent = {
4348
- __proto__: null,
4349
- [BUN$5]: BUN$5,
4350
- [NPM$8]: NPM$8,
4351
- [PNPM$6]: PNPM$6,
4352
- [YARN_BERRY$5]: YARN,
4353
- [YARN_CLASSIC$5]: YARN,
4354
- [VLT$5]: VLT$5
4355
- };
4356
- async function getAgentExecPath(agent) {
4357
- const binName = binByAgent[agent];
4358
- return (await which(binName, {
4359
- nothrow: true
4360
- })) ?? binName;
4361
- }
4362
- async function getAgentVersion(agentExecPath, cwd) {
4363
- let result;
4364
- try {
4365
- result = semver.coerce(
4366
- // All package managers support the "--version" flag.
4367
- (await spawn.spawn(agentExecPath, ['--version'], {
4368
- cwd
4369
- })).stdout) ?? undefined;
4370
- } catch {}
4371
- return result;
4372
- }
4373
-
4374
- // The order of LOCKS properties IS significant as it affects iteration order.
4375
- const LOCKS = {
4376
- [`bun${LOCK_EXT$1}`]: BUN$5,
4377
- [`bun${BINARY_LOCK_EXT}`]: BUN$5,
4378
- // If both package-lock.json and npm-shrinkwrap.json are present in the root
4379
- // of a project, npm-shrinkwrap.json will take precedence and package-lock.json
4380
- // will be ignored.
4381
- // https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json#package-lockjson-vs-npm-shrinkwrapjson
4382
- 'npm-shrinkwrap.json': NPM$8,
4383
- 'package-lock.json': NPM$8,
4384
- 'pnpm-lock.yaml': PNPM$6,
4385
- 'pnpm-lock.yml': PNPM$6,
4386
- [`yarn${LOCK_EXT$1}`]: YARN_CLASSIC$5,
4387
- 'vlt-lock.json': VLT$5,
4388
- // Lastly, look for a hidden lock file which is present if .npmrc has package-lock=false:
4389
- // https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json#hidden-lockfiles
4390
- //
4391
- // Unlike the other LOCKS keys this key contains a directory AND filename so
4392
- // it has to be handled differently.
4393
- 'node_modules/.package-lock.json': NPM$8
4394
- };
4395
- const readLockFileByAgent = (() => {
4396
- function wrapReader(reader) {
4397
- return async (...args) => {
4398
- try {
4399
- return await reader(...args);
4400
- } catch {}
4401
- return undefined;
4402
- };
4403
- }
4404
- const binaryReader = wrapReader(index.readFileBinary);
4405
- const defaultReader = wrapReader(async lockPath => await index.readFileUtf8(lockPath));
4406
- return {
4407
- [BUN$5]: wrapReader(async (lockPath, agentExecPath) => {
4408
- const ext = path.extname(lockPath);
4409
- if (ext === LOCK_EXT$1) {
4410
- return await defaultReader(lockPath);
4411
- }
4412
- if (ext === BINARY_LOCK_EXT) {
4413
- const lockBuffer = await binaryReader(lockPath);
4414
- if (lockBuffer) {
4415
- try {
4416
- return index_cjs.parse(lockBuffer);
4417
- } catch {}
4418
- }
4419
- // To print a Yarn lockfile to your console without writing it to disk
4420
- // use `bun bun.lockb`.
4421
- // https://bun.sh/guides/install/yarnlock
4422
- return (await spawn.spawn(agentExecPath, [lockPath])).stdout.trim();
4423
- }
4424
- return undefined;
4425
- }),
4426
- [NPM$8]: defaultReader,
4427
- [PNPM$6]: defaultReader,
4428
- [VLT$5]: defaultReader,
4429
- [YARN_BERRY$5]: defaultReader,
4430
- [YARN_CLASSIC$5]: defaultReader
4431
- };
4432
- })();
4433
- async function detectPackageEnvironment({
4434
- cwd = process$1.cwd(),
4435
- onUnknown
4436
- } = {}) {
4437
- let lockPath = await index.findUp(Object.keys(LOCKS), {
4438
- cwd
4439
- });
4440
- let lockName = lockPath ? path.basename(lockPath) : undefined;
4441
- const isHiddenLockFile = lockName === '.package-lock.json';
4442
- const pkgJsonPath = lockPath ? path.resolve(lockPath, `${isHiddenLockFile ? '../' : ''}../package.json`) : await index.findUp('package.json', {
4443
- cwd
4444
- });
4445
- const pkgPath = pkgJsonPath && fs.existsSync(pkgJsonPath) ? path.dirname(pkgJsonPath) : undefined;
4446
- const editablePkgJson = pkgPath ? await packages.readPackageJson(pkgPath, {
4447
- editable: true
4448
- }) : undefined;
4449
- const pkgJson = editablePkgJson?.content;
4450
- // Read Corepack `packageManager` field in package.json:
4451
- // https://nodejs.org/api/packages.html#packagemanager
4452
- const pkgManager = strings.isNonEmptyString(pkgJson?.packageManager) ? pkgJson.packageManager : undefined;
4453
- let agent;
4454
- let agentVersion;
4455
- if (pkgManager) {
4456
- const atSignIndex = pkgManager.lastIndexOf('@');
4457
- if (atSignIndex !== -1) {
4458
- const name = pkgManager.slice(0, atSignIndex);
4459
- const version = pkgManager.slice(atSignIndex + 1);
4460
- if (version && AGENTS.includes(name)) {
4461
- agent = name;
4462
- agentVersion = semver.coerce(version) ?? undefined;
4463
- }
4464
- }
4465
- }
4466
- if (agent === undefined && !isHiddenLockFile && typeof pkgJsonPath === 'string' && typeof lockName === 'string') {
4467
- agent = LOCKS[lockName];
4468
- }
4469
- if (agent === undefined) {
4470
- agent = NPM$8;
4471
- onUnknown?.(pkgManager);
4472
- }
4473
- const agentExecPath = await getAgentExecPath(agent);
4474
- const npmExecPath = agent === NPM$8 ? agentExecPath : await getAgentExecPath(NPM$8);
4475
- if (agentVersion === undefined) {
4476
- agentVersion = await getAgentVersion(agentExecPath, cwd);
4477
- }
4478
- if (agent === YARN_CLASSIC$5 && (agentVersion?.major ?? 0) > 1) {
4479
- agent = YARN_BERRY$5;
4480
- }
4481
- const targets = {
4482
- browser: false,
4483
- node: true
4484
- };
4485
- let lockSrc;
4486
- // Lazily access constants.maintainedNodeVersions.
4487
- let minimumNodeVersion = constants.maintainedNodeVersions.previous;
4488
- if (pkgJson) {
4489
- const browserField = pkgJson.browser;
4490
- if (strings.isNonEmptyString(browserField) || objects.isObjectObject(browserField)) {
4491
- targets.browser = true;
4492
- }
4493
- const nodeRange = pkgJson.engines?.['node'];
4494
- if (strings.isNonEmptyString(nodeRange)) {
4495
- const coerced = semver.coerce(nodeRange);
4496
- if (coerced && semver.lt(coerced, minimumNodeVersion)) {
4497
- minimumNodeVersion = coerced.version;
4498
- }
4499
- }
4500
- const browserslistQuery = pkgJson['browserslist'];
4501
- if (Array.isArray(browserslistQuery)) {
4502
- const browserslistTargets = browserslist(browserslistQuery).map(s => s.toLowerCase()).sort(sorts.naturalCompare);
4503
- const browserslistNodeTargets = browserslistTargets.filter(v => v.startsWith('node ')).map(v => v.slice(5 /*'node '.length*/));
4504
- if (!targets.browser && browserslistTargets.length) {
4505
- targets.browser = browserslistTargets.length !== browserslistNodeTargets.length;
4506
- }
4507
- if (browserslistNodeTargets.length) {
4508
- const coerced = semver.coerce(browserslistNodeTargets[0]);
4509
- if (coerced && semver.lt(coerced, minimumNodeVersion)) {
4510
- minimumNodeVersion = coerced.version;
4511
- }
4512
- }
4513
- }
4514
- // Lazily access constants.maintainedNodeVersions.
4515
- targets.node = constants.maintainedNodeVersions.some(v => semver.satisfies(v, `>=${minimumNodeVersion}`));
4516
- lockSrc = typeof lockPath === 'string' ? await readLockFileByAgent[agent](lockPath, agentExecPath) : undefined;
4517
- } else {
4518
- lockName = undefined;
4519
- lockPath = undefined;
4795
+ parentName
4796
+ }) {
4797
+ const cli = meowOrExit({
4798
+ argv,
4799
+ config: config$i,
4800
+ importMeta,
4801
+ parentName
4802
+ });
4803
+ if (cli.flags['dryRun']) {
4804
+ logger.logger.log(DRY_RUN_BAIL_TEXT$i);
4805
+ return;
4520
4806
  }
4521
- return {
4522
- agent,
4523
- agentExecPath,
4524
- agentVersion,
4525
- lockName,
4526
- lockPath,
4527
- lockSrc,
4528
- minimumNodeVersion,
4529
- npmExecPath,
4530
- pkgJson: editablePkgJson,
4531
- pkgPath,
4532
- supported: targets.browser || targets.node,
4533
- targets
4534
- };
4807
+ throw new Error('This error was intentionally left blank');
4535
4808
  }
4536
4809
 
4537
4810
  const {
4538
4811
  BUN: BUN$4,
4812
+ NPM: NPM$7,
4813
+ PNPM: PNPM$6,
4539
4814
  VLT: VLT$4,
4540
- YARN_BERRY: YARN_BERRY$4
4815
+ YARN_BERRY: YARN_BERRY$4,
4816
+ YARN_CLASSIC: YARN_CLASSIC$5
4541
4817
  } = constants;
4542
- const COMMAND_TITLE$2 = 'Socket Optimize';
4543
- async function detectAndValidatePackageEnvironment(cwd, options) {
4544
- const {
4545
- logger,
4546
- prod
4547
- } = {
4548
- __proto__: null,
4549
- ...options
4550
- };
4551
- const details = await detectPackageEnvironment({
4552
- cwd,
4553
- onUnknown(pkgManager) {
4554
- logger?.warn(`⚠️ ${COMMAND_TITLE$2}: Unknown package manager${pkgManager ? ` ${pkgManager}` : ''}, defaulting to npm`);
4555
- }
4556
- });
4557
- if (!details.supported) {
4558
- logger?.error(`✖️ ${COMMAND_TITLE$2}: No supported Node or browser range detected`);
4559
- return;
4560
- }
4561
- if (details.agent === VLT$4) {
4562
- logger?.error(`✖️ ${COMMAND_TITLE$2}: ${details.agent} does not support overrides. Soon, though ⚡`);
4563
- return;
4564
- }
4565
- const lockName = details.lockName ?? 'lock file';
4566
- if (details.lockName === undefined || details.lockSrc === undefined) {
4567
- logger?.error(`✖️ ${COMMAND_TITLE$2}: No ${lockName} found`);
4568
- return;
4569
- }
4570
- if (details.lockSrc.trim() === '') {
4571
- logger?.error(`✖️ ${COMMAND_TITLE$2}: ${lockName} is empty`);
4572
- return;
4573
- }
4574
- if (details.pkgPath === undefined) {
4575
- logger?.error(`✖️ ${COMMAND_TITLE$2}: No package.json found`);
4576
- return;
4577
- }
4578
- if (prod && (details.agent === BUN$4 || details.agent === YARN_BERRY$4)) {
4579
- logger?.error(`✖️ ${COMMAND_TITLE$2}: --prod not supported for ${details.agent}${details.agentVersion ? `@${details.agentVersion.toString()}` : ''}`);
4580
- return;
4581
- }
4582
- if (details.lockPath && path.relative(cwd, details.lockPath).startsWith('.')) {
4583
- logger?.warn(`⚠️ ${COMMAND_TITLE$2}: Package ${lockName} found at ${details.lockPath}`);
4584
- }
4585
- return details;
4818
+ function matchLsCmdViewHumanStdout(stdout, name) {
4819
+ return stdout.includes(` ${name}@`);
4586
4820
  }
4821
+ function matchQueryCmdStdout(stdout, name) {
4822
+ return stdout.includes(`"${name}"`);
4823
+ }
4824
+ const depsIncludesByAgent = new Map([[BUN$4, matchLsCmdViewHumanStdout], [NPM$7, matchQueryCmdStdout], [PNPM$6, matchQueryCmdStdout], [VLT$4, matchQueryCmdStdout], [YARN_BERRY$4, matchLsCmdViewHumanStdout], [YARN_CLASSIC$5, matchLsCmdViewHumanStdout]]);
4587
4825
 
4588
4826
  function getDependencyEntries(pkgJson) {
4589
4827
  const {
@@ -4611,7 +4849,7 @@ function getDependencyEntries(pkgJson) {
4611
4849
 
4612
4850
  const {
4613
4851
  BUN: BUN$3,
4614
- NPM: NPM$7,
4852
+ NPM: NPM$6,
4615
4853
  OVERRIDES: OVERRIDES$1,
4616
4854
  PNPM: PNPM$5,
4617
4855
  RESOLUTIONS: RESOLUTIONS$1,
@@ -4632,7 +4870,7 @@ function getOverridesDataBun(pkgJson) {
4632
4870
  function getOverridesDataNpm(pkgJson) {
4633
4871
  const overrides = pkgJson?.[OVERRIDES$1] ?? {};
4634
4872
  return {
4635
- type: NPM$7,
4873
+ type: NPM$6,
4636
4874
  overrides
4637
4875
  };
4638
4876
  }
@@ -4673,7 +4911,7 @@ function getOverridesDataClassic(pkgJson) {
4673
4911
  overrides
4674
4912
  };
4675
4913
  }
4676
- const overridesDataByAgent = new Map([[BUN$3, getOverridesDataBun], [NPM$7, getOverridesDataNpm], [PNPM$5, getOverridesDataPnpm], [VLT$3, getOverridesDataVlt], [YARN_BERRY$3, getOverridesDataYarn], [YARN_CLASSIC$4, getOverridesDataClassic]]);
4914
+ const overridesDataByAgent = new Map([[BUN$3, getOverridesDataBun], [NPM$6, getOverridesDataNpm], [PNPM$5, getOverridesDataPnpm], [VLT$3, getOverridesDataVlt], [YARN_BERRY$3, getOverridesDataYarn], [YARN_CLASSIC$4, getOverridesDataClassic]]);
4677
4915
 
4678
4916
  const {
4679
4917
  PNPM: PNPM$4
@@ -4684,7 +4922,7 @@ async function getWorkspaceGlobs(agent, pkgPath, pkgJson) {
4684
4922
  if (agent === PNPM$4) {
4685
4923
  for (const workspacePath of [path.join(pkgPath, `${PNPM_WORKSPACE}.yaml`), path.join(pkgPath, `${PNPM_WORKSPACE}.yml`)]) {
4686
4924
  // eslint-disable-next-line no-await-in-loop
4687
- const yml = await index.safeReadFile(workspacePath, 'utf8');
4925
+ const yml = await shadowNpmInject.safeReadFile(workspacePath, 'utf8');
4688
4926
  if (yml) {
4689
4927
  try {
4690
4928
  workspacePatterns = yaml.parse(yml)?.packages;
@@ -4721,26 +4959,26 @@ function workspacePatternToGlobPattern(workspace) {
4721
4959
  const {
4722
4960
  BUN: BUN$2,
4723
4961
  LOCK_EXT,
4724
- NPM: NPM$6,
4962
+ NPM: NPM$5,
4725
4963
  PNPM: PNPM$3,
4726
4964
  VLT: VLT$2,
4727
4965
  YARN_BERRY: YARN_BERRY$2,
4728
4966
  YARN_CLASSIC: YARN_CLASSIC$3
4729
4967
  } = constants;
4730
- function lockIncludesNpm(lockSrc, name) {
4968
+ function includesNpm(lockSrc, name) {
4731
4969
  // Detects the package name in the following cases:
4732
4970
  // "name":
4733
4971
  return lockSrc.includes(`"${name}":`);
4734
4972
  }
4735
- function lockIncludesBun(lockSrc, name, lockName) {
4973
+ function includesBun(lockSrc, name, lockName) {
4736
4974
  // This is a bit counterintuitive. When lockName ends with a .lockb
4737
4975
  // we treat it as a yarn.lock. When lockName ends with a .lock we
4738
4976
  // treat it as a package-lock.json. The bun.lock format is not identical
4739
4977
  // package-lock.json, however it close enough for npmLockIncludes to work.
4740
- const lockScanner = lockName?.endsWith(LOCK_EXT) ? lockIncludesNpm : lockIncludesYarn;
4741
- return lockScanner(lockSrc, name);
4978
+ const lockfileScanner = lockName?.endsWith(LOCK_EXT) ? includesNpm : includesYarn;
4979
+ return lockfileScanner(lockSrc, name);
4742
4980
  }
4743
- function lockIncludesPnpm(lockSrc, name) {
4981
+ function includesPnpm(lockSrc, name) {
4744
4982
  const escapedName = regexps.escapeRegExp(name);
4745
4983
  return new RegExp(
4746
4984
  // Detects the package name in the following cases:
@@ -4750,12 +4988,12 @@ function lockIncludesPnpm(lockSrc, name) {
4750
4988
  // name@
4751
4989
  `(?<=^\\s*)(?:(['/])${escapedName}\\1|${escapedName}(?=[:@]))`, 'm').test(lockSrc);
4752
4990
  }
4753
- function lockIncludesVlt(lockSrc, name) {
4991
+ function includesVlt(lockSrc, name) {
4754
4992
  // Detects the package name in the following cases:
4755
4993
  // "name"
4756
4994
  return lockSrc.includes(`"${name}"`);
4757
4995
  }
4758
- function lockIncludesYarn(lockSrc, name) {
4996
+ function includesYarn(lockSrc, name) {
4759
4997
  const escapedName = regexps.escapeRegExp(name);
4760
4998
  return new RegExp(
4761
4999
  // Detects the package name in the following cases:
@@ -4765,11 +5003,11 @@ function lockIncludesYarn(lockSrc, name) {
4765
5003
  // , name@
4766
5004
  `(?<=(?:^\\s*|,\\s*)"?)${escapedName}(?=@)`, 'm').test(lockSrc);
4767
5005
  }
4768
- const lockIncludesByAgent = new Map([[BUN$2, lockIncludesBun], [NPM$6, lockIncludesNpm], [PNPM$3, lockIncludesPnpm], [VLT$2, lockIncludesVlt], [YARN_BERRY$2, lockIncludesYarn], [YARN_CLASSIC$3, lockIncludesYarn]]);
5006
+ const lockfileIncludesByAgent = new Map([[BUN$2, includesBun], [NPM$5, includesNpm], [PNPM$3, includesPnpm], [VLT$2, includesVlt], [YARN_BERRY$2, includesYarn], [YARN_CLASSIC$3, includesYarn]]);
4769
5007
 
4770
5008
  const {
4771
5009
  BUN: BUN$1,
4772
- NPM: NPM$5,
5010
+ NPM: NPM$4,
4773
5011
  PNPM: PNPM$2,
4774
5012
  VLT: VLT$1,
4775
5013
  YARN_BERRY: YARN_BERRY$1,
@@ -4805,11 +5043,11 @@ function cleanupQueryStdout(stdout) {
4805
5043
  }
4806
5044
  return JSON.stringify([...names], null, 2);
4807
5045
  }
4808
- function parseableToQueryStdout(stdout) {
5046
+ function parsableToQueryStdout(stdout) {
4809
5047
  if (stdout === '') {
4810
5048
  return '';
4811
5049
  }
4812
- // Convert the parseable stdout into a json array of unique names.
5050
+ // Convert the parsable stdout into a json array of unique names.
4813
5051
  // The matchAll regexp looks for a forward (posix) or backward (win32) slash
4814
5052
  // and matches one or more non-slashes until the newline.
4815
5053
  const names = new Set(stdout.matchAll(/(?<=[/\\])[^/\\]+(?=\n)/g));
@@ -4839,7 +5077,7 @@ async function lsNpm(agentExecPath, cwd) {
4839
5077
  }
4840
5078
  async function lsPnpm(agentExecPath, cwd, options) {
4841
5079
  const npmExecPath = options?.npmExecPath;
4842
- if (npmExecPath && npmExecPath !== NPM$5) {
5080
+ if (npmExecPath && npmExecPath !== NPM$4) {
4843
5081
  const result = await npmQuery(npmExecPath, cwd);
4844
5082
  if (result) {
4845
5083
  return result;
@@ -4847,15 +5085,19 @@ async function lsPnpm(agentExecPath, cwd, options) {
4847
5085
  }
4848
5086
  let stdout = '';
4849
5087
  try {
4850
- stdout = (await spawn.spawn(agentExecPath, ['ls', '--parseable', '--prod', '--depth', 'Infinity'], {
5088
+ stdout = (await spawn.spawn(agentExecPath,
5089
+ // Pnpm uses the alternative spelling of parsable.
5090
+ // https://en.wiktionary.org/wiki/parsable
5091
+ ['ls', '--parseable', '--prod', '--depth', 'Infinity'], {
4851
5092
  cwd
4852
5093
  })).stdout;
4853
5094
  } catch {}
4854
- return parseableToQueryStdout(stdout);
5095
+ return parsableToQueryStdout(stdout);
4855
5096
  }
4856
5097
  async function lsVlt(agentExecPath, cwd) {
4857
5098
  let stdout = '';
4858
5099
  try {
5100
+ // See https://docs.vlt.sh/cli/commands/list#options.
4859
5101
  stdout = (await spawn.spawn(agentExecPath, ['ls', '--view', 'human', ':not(.dev)'], {
4860
5102
  cwd
4861
5103
  })).stdout;
@@ -4886,20 +5128,39 @@ async function lsYarnClassic(agentExecPath, cwd) {
4886
5128
  } catch {}
4887
5129
  return '';
4888
5130
  }
4889
- const lsByAgent = {
4890
- // @ts-ignore
4891
- __proto__: null,
4892
- [BUN$1]: lsBun,
4893
- [NPM$5]: lsNpm,
4894
- [PNPM$2]: lsPnpm,
4895
- [VLT$1]: lsVlt,
4896
- [YARN_BERRY$1]: lsYarnBerry,
4897
- [YARN_CLASSIC$2]: lsYarnClassic
4898
- };
5131
+ const lsByAgent = new Map([[BUN$1, lsBun], [NPM$4, lsNpm], [PNPM$2, lsPnpm], [VLT$1, lsVlt], [YARN_BERRY$1, lsYarnBerry], [YARN_CLASSIC$2, lsYarnClassic]]);
5132
+
5133
+ const {
5134
+ NPM: NPM$3
5135
+ } = constants;
5136
+ const COMMAND_TITLE$1 = 'Socket Optimize';
5137
+ async function updateLockfile(pkgEnvDetails, options) {
5138
+ const {
5139
+ logger,
5140
+ spinner
5141
+ } = {
5142
+ __proto__: null,
5143
+ ...options
5144
+ };
5145
+ spinner?.start(`Updating ${pkgEnvDetails.lockName}...`);
5146
+ try {
5147
+ await runAgentInstall(pkgEnvDetails, {
5148
+ spinner
5149
+ });
5150
+ spinner?.stop();
5151
+ if (pkgEnvDetails.agent === NPM$3) {
5152
+ logger?.log(`💡 Re-run ${COMMAND_TITLE$1} whenever ${pkgEnvDetails.lockName} changes.\n This can be skipped once npm v11.2.0 is released.`);
5153
+ }
5154
+ } catch (e) {
5155
+ spinner?.stop();
5156
+ logger?.fail(`${COMMAND_TITLE$1}: ${pkgEnvDetails.agent} install failed to update ${pkgEnvDetails.lockName}`);
5157
+ logger?.error(e);
5158
+ }
5159
+ }
4899
5160
 
4900
5161
  const {
4901
5162
  BUN,
4902
- NPM: NPM$4,
5163
+ NPM: NPM$2,
4903
5164
  OVERRIDES,
4904
5165
  PNPM: PNPM$1,
4905
5166
  RESOLUTIONS,
@@ -4919,7 +5180,9 @@ function getHighestEntryIndex(entries, keys) {
4919
5180
  return getEntryIndexes(entries, keys).at(-1) ?? -1;
4920
5181
  }
4921
5182
  function updatePkgJson(editablePkgJson, field, value) {
4922
- const pkgJson = editablePkgJson.content;
5183
+ const {
5184
+ content: pkgJson
5185
+ } = editablePkgJson;
4923
5186
  const oldValue = pkgJson[field];
4924
5187
  if (oldValue) {
4925
5188
  // The field already exists so we simply update the field value.
@@ -4975,205 +5238,43 @@ function updatePkgJson(editablePkgJson, field, value) {
4975
5238
  } else if (field === PNPM_FIELD_NAME) {
4976
5239
  insertIndex = getLowestEntryIndex(entries, [OVERRIDES, RESOLUTIONS]);
4977
5240
  if (insertIndex === -1) {
4978
- isPlacingHigher = true;
4979
- insertIndex = getHighestEntryIndex(entries, depFields);
4980
- }
4981
- }
4982
- if (insertIndex === -1) {
4983
- insertIndex = getLowestEntryIndex(entries, ['engines', 'files']);
4984
- }
4985
- if (insertIndex === -1) {
4986
- isPlacingHigher = true;
4987
- insertIndex = getHighestEntryIndex(entries, ['exports', 'imports', 'main']);
4988
- }
4989
- if (insertIndex === -1) {
4990
- insertIndex = entries.length;
4991
- } else if (isPlacingHigher) {
4992
- insertIndex += 1;
4993
- }
4994
- entries.splice(insertIndex, 0, [field, value]);
4995
- editablePkgJson.fromJSON(`${JSON.stringify(Object.fromEntries(entries), null, 2)}\n`);
4996
- }
4997
- function updateOverrides(editablePkgJson, overrides) {
4998
- updatePkgJson(editablePkgJson, OVERRIDES, overrides);
4999
- }
5000
- function updateResolutions(editablePkgJson, overrides) {
5001
- updatePkgJson(editablePkgJson, RESOLUTIONS, overrides);
5002
- }
5003
- function pnpmUpdatePkgJson(editablePkgJson, overrides) {
5004
- updatePkgJson(editablePkgJson, PNPM_FIELD_NAME, overrides);
5005
- }
5006
- const updateManifestByAgent = new Map([[BUN, updateResolutions], [NPM$4, updateOverrides], [PNPM$1, pnpmUpdatePkgJson], [VLT, updateOverrides], [YARN_BERRY, updateResolutions], [YARN_CLASSIC$1, updateResolutions]]);
5007
-
5008
- const {
5009
- SOCKET_IPC_HANDSHAKE
5010
- } = constants;
5011
- function safeNpmInstall(options) {
5012
- const {
5013
- args = [],
5014
- ipc,
5015
- spinner,
5016
- ...spawnOptions
5017
- } = {
5018
- __proto__: null,
5019
- ...options
5020
- };
5021
- const terminatorPos = args.indexOf('--');
5022
- const npmArgs = (terminatorPos === -1 ? args : args.slice(0, terminatorPos)).filter(a => !npm.isAuditFlag(a) && !npm.isFundFlag(a) && !npm.isProgressFlag(a));
5023
- const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
5024
- const useIpc = objects.isObject(ipc);
5025
- const useDebug = debug.isDebug();
5026
- const isSilent = !useDebug && !npmArgs.some(npm.isLoglevelFlag);
5027
- const spawnPromise = spawn.spawn(
5028
- // Lazily access constants.execPath.
5029
- constants.execPath, [
5030
- // Lazily access constants.nodeNoWarningsFlags.
5031
- ...constants.nodeNoWarningsFlags, '--require',
5032
- // Lazily access constants.npmInjectionPath.
5033
- constants.npmInjectionPath, npmPaths.getNpmBinPath(), 'install',
5034
- // Even though the '--silent' flag is passed npm will still run through
5035
- // code paths for 'audit' and 'fund' unless '--no-audit' and '--no-fund'
5036
- // flags are passed.
5037
- '--no-audit', '--no-fund',
5038
- // Add `--no-progress` and `--silent` flags to fix input being swallowed
5039
- // by the spinner when running the command with recent versions of npm.
5040
- '--no-progress',
5041
- // Add the '--silent' flag if a loglevel flag is not provided and the
5042
- // SOCKET_CLI_DEBUG environment variable is not truthy.
5043
- ...(isSilent ? ['--silent'] : []), ...npmArgs, ...otherArgs], {
5044
- spinner,
5045
- // Set stdio to include 'ipc'.
5046
- // See https://github.com/nodejs/node/blob/v23.6.0/lib/child_process.js#L161-L166
5047
- // and https://github.com/nodejs/node/blob/v23.6.0/lib/internal/child_process.js#L238.
5048
- stdio: isSilent ?
5049
- // 'ignore'
5050
- useIpc ? ['ignore', 'ignore', 'ignore', 'ipc'] : 'ignore' :
5051
- // 'inherit'
5052
- useIpc ? [0, 1, 2, 'ipc'] : 'inherit',
5053
- ...spawnOptions,
5054
- env: {
5055
- ...process$1.env,
5056
- ...spawnOptions.env
5057
- }
5058
- });
5059
- if (useIpc) {
5060
- spawnPromise.process.send({
5061
- [SOCKET_IPC_HANDSHAKE]: ipc
5062
- });
5063
- }
5064
- return spawnPromise;
5065
- }
5066
-
5067
- const {
5068
- NPM: NPM$3,
5069
- abortSignal
5070
- } = constants;
5071
- function runAgentInstall(agent, agentExecPath, options) {
5072
- // All package managers support the "install" command.
5073
- if (agent === NPM$3) {
5074
- return safeNpmInstall(options);
5075
- }
5076
- const {
5077
- args = [],
5078
- spinner,
5079
- ...spawnOptions
5080
- } = {
5081
- __proto__: null,
5082
- ...options
5083
- };
5084
- const isSilent = !debug.isDebug();
5085
- return spawn.spawn(agentExecPath, ['install', ...args], {
5086
- signal: abortSignal,
5087
- spinner,
5088
- stdio: isSilent ? 'ignore' : 'inherit',
5089
- ...spawnOptions,
5090
- env: {
5091
- ...process.env,
5092
- ...spawnOptions.env
5093
- }
5094
- });
5095
- }
5096
-
5097
- const {
5098
- NPM: NPM$2
5099
- } = constants;
5100
- const COMMAND_TITLE$1 = 'Socket Optimize';
5101
- async function updatePackageLockJson(pkgEnvDetails, options) {
5102
- const {
5103
- logger,
5104
- spinner
5105
- } = {
5106
- __proto__: null,
5107
- ...options
5108
- };
5109
- spinner?.start(`Updating ${pkgEnvDetails.lockName}...`);
5110
- try {
5111
- await runAgentInstall(pkgEnvDetails.agent, pkgEnvDetails.agentExecPath, {
5112
- spinner
5113
- });
5114
- spinner?.stop();
5115
- if (pkgEnvDetails.agent === NPM$2) {
5116
- logger?.log(`💡 Re-run ${COMMAND_TITLE$1} whenever ${pkgEnvDetails.lockName} changes.\n This can be skipped once npm v11.2.0 is released.`);
5117
- }
5118
- } catch (e) {
5119
- spinner?.stop();
5120
- logger?.error(`${COMMAND_TITLE$1}: ${pkgEnvDetails.agent} install failed to update ${pkgEnvDetails.lockName}`);
5121
- logger?.error(e);
5122
- }
5123
- }
5124
-
5125
- const {
5126
- NPM: NPM$1,
5127
- PNPM,
5128
- YARN_CLASSIC
5129
- } = constants;
5130
- const COMMAND_TITLE = 'Socket Optimize';
5131
- const manifestNpmOverrides = registry.getManifestData(NPM$1);
5132
- async function applyOptimization(cwd, pin, prod) {
5133
- const pkgEnvDetails = await detectAndValidatePackageEnvironment(cwd, {
5134
- logger: logger.logger,
5135
- prod
5136
- });
5137
- if (!pkgEnvDetails) {
5138
- return;
5139
- }
5140
- // Lazily access constants.spinner.
5141
- const {
5142
- spinner
5143
- } = constants;
5144
- spinner.start('Socket optimizing...');
5145
- const state = await addOverrides(pkgEnvDetails.pkgPath, pkgEnvDetails, {
5146
- logger: logger.logger,
5147
- pin,
5148
- prod,
5149
- spinner
5150
- });
5151
- spinner.stop();
5152
- const addedCount = state.added.size;
5153
- const updatedCount = state.updated.size;
5154
- const pkgJsonChanged = addedCount > 0 || updatedCount > 0;
5155
- if (pkgJsonChanged) {
5156
- if (updatedCount > 0) {
5157
- logger.logger?.log(`${createActionMessage('Updated', updatedCount, state.updatedInWorkspaces.size)}${addedCount ? '.' : '🚀'}`);
5158
- }
5159
- if (addedCount > 0) {
5160
- logger.logger?.log(`${createActionMessage('Added', addedCount, state.addedInWorkspaces.size)} 🚀`);
5241
+ isPlacingHigher = true;
5242
+ insertIndex = getHighestEntryIndex(entries, depFields);
5161
5243
  }
5162
- } else {
5163
- logger.logger?.log('Congratulations! Already Socket.dev optimized 🎉');
5164
5244
  }
5165
- if (pkgEnvDetails.agent === NPM$1 || pkgJsonChanged) {
5166
- // Always update package-lock.json until the npm overrides PR lands:
5167
- // https://github.com/npm/cli/pull/8089
5168
- await updatePackageLockJson(pkgEnvDetails, {
5169
- logger: logger.logger,
5170
- spinner
5171
- });
5245
+ if (insertIndex === -1) {
5246
+ insertIndex = getLowestEntryIndex(entries, ['engines', 'files']);
5247
+ }
5248
+ if (insertIndex === -1) {
5249
+ isPlacingHigher = true;
5250
+ insertIndex = getHighestEntryIndex(entries, ['exports', 'imports', 'main']);
5172
5251
  }
5252
+ if (insertIndex === -1) {
5253
+ insertIndex = entries.length;
5254
+ } else if (isPlacingHigher) {
5255
+ insertIndex += 1;
5256
+ }
5257
+ entries.splice(insertIndex, 0, [field, value]);
5258
+ editablePkgJson.fromJSON(`${JSON.stringify(Object.fromEntries(entries), null, 2)}\n`);
5173
5259
  }
5174
- function createActionMessage(verb, overrideCount, workspaceCount) {
5175
- return `${verb} ${overrideCount} Socket.dev optimized ${words.pluralize('override', overrideCount)}${workspaceCount ? ` in ${workspaceCount} ${words.pluralize('workspace', workspaceCount)}` : ''}`;
5260
+ function updateOverrides(editablePkgJson, overrides) {
5261
+ updatePkgJson(editablePkgJson, OVERRIDES, overrides);
5262
+ }
5263
+ function updateResolutions(editablePkgJson, overrides) {
5264
+ updatePkgJson(editablePkgJson, RESOLUTIONS, overrides);
5265
+ }
5266
+ function pnpmUpdatePkgJson(editablePkgJson, overrides) {
5267
+ updatePkgJson(editablePkgJson, PNPM_FIELD_NAME, overrides);
5176
5268
  }
5269
+ const updateManifestByAgent = new Map([[BUN, updateResolutions], [NPM$2, updateOverrides], [PNPM$1, pnpmUpdatePkgJson], [VLT, updateOverrides], [YARN_BERRY, updateResolutions], [YARN_CLASSIC$1, updateResolutions]]);
5270
+
5271
+ const {
5272
+ NPM: NPM$1,
5273
+ PNPM,
5274
+ YARN_CLASSIC
5275
+ } = constants;
5276
+ const COMMAND_TITLE = 'Socket Optimize';
5277
+ const manifestNpmOverrides = registry.getManifestData(NPM$1);
5177
5278
  async function addOverrides(pkgPath, pkgEnvDetails, options) {
5178
5279
  const {
5179
5280
  agent,
@@ -5217,16 +5318,16 @@ async function addOverrides(pkgPath, pkgEnvDetails, options) {
5217
5318
  const isWorkspace = !!workspaceGlobs;
5218
5319
  if (isWorkspace && agent === PNPM && npmExecPath === NPM$1 && !state.warnedPnpmWorkspaceRequiresNpm) {
5219
5320
  state.warnedPnpmWorkspaceRequiresNpm = true;
5220
- logger?.warn(`⚠️ ${COMMAND_TITLE}: pnpm workspace support requires \`npm ls\`, falling back to \`pnpm list\``);
5321
+ logger?.warn(`${COMMAND_TITLE}: pnpm workspace support requires \`npm ls\`, falling back to \`pnpm list\``);
5221
5322
  }
5222
- const thingToScan = isLockScanned ? lockSrc : await lsByAgent[agent](agentExecPath, pkgPath, {
5323
+ const thingToScan = isLockScanned ? lockSrc : await lsByAgent.get(agent)(agentExecPath, pkgPath, {
5223
5324
  npmExecPath
5224
5325
  });
5225
5326
  // The AgentDepsIncludesFn and AgentLockIncludesFn types overlap in their
5226
5327
  // first two parameters. AgentLockIncludesFn accepts an optional third
5227
5328
  // parameter which AgentDepsIncludesFn will ignore so we cast thingScanner
5228
5329
  // as an AgentLockIncludesFn type.
5229
- const thingScanner = isLockScanned ? lockIncludesByAgent.get(agent) : depsIncludesByAgent.get(agent);
5330
+ const thingScanner = isLockScanned ? lockfileIncludesByAgent.get(agent) : depsIncludesByAgent.get(agent);
5230
5331
  const depEntries = getDependencyEntries(pkgJson);
5231
5332
  const overridesDataObjects = [];
5232
5333
  if (pkgJson['private'] || isWorkspace) {
@@ -5352,6 +5453,51 @@ async function addOverrides(pkgPath, pkgEnvDetails, options) {
5352
5453
  }
5353
5454
  return state;
5354
5455
  }
5456
+ function createActionMessage(verb, overrideCount, workspaceCount) {
5457
+ return `${verb} ${overrideCount} Socket.dev optimized ${words.pluralize('override', overrideCount)}${workspaceCount ? ` in ${workspaceCount} ${words.pluralize('workspace', workspaceCount)}` : ''}`;
5458
+ }
5459
+ async function applyOptimization(cwd, pin, prod) {
5460
+ const pkgEnvDetails = await detectAndValidatePackageEnvironment(cwd, {
5461
+ logger: logger.logger,
5462
+ prod
5463
+ });
5464
+ if (!pkgEnvDetails) {
5465
+ return;
5466
+ }
5467
+ // Lazily access constants.spinner.
5468
+ const {
5469
+ spinner
5470
+ } = constants;
5471
+ spinner.start('Socket optimizing...');
5472
+ const state = await addOverrides(pkgEnvDetails.pkgPath, pkgEnvDetails, {
5473
+ logger: logger.logger,
5474
+ pin,
5475
+ prod,
5476
+ spinner
5477
+ });
5478
+ spinner.stop();
5479
+ const addedCount = state.added.size;
5480
+ const updatedCount = state.updated.size;
5481
+ const pkgJsonChanged = addedCount > 0 || updatedCount > 0;
5482
+ if (pkgJsonChanged) {
5483
+ if (updatedCount > 0) {
5484
+ logger.logger?.log(`${createActionMessage('Updated', updatedCount, state.updatedInWorkspaces.size)}${addedCount ? '.' : '🚀'}`);
5485
+ }
5486
+ if (addedCount > 0) {
5487
+ logger.logger?.log(`${createActionMessage('Added', addedCount, state.addedInWorkspaces.size)} 🚀`);
5488
+ }
5489
+ } else {
5490
+ logger.logger?.log('Congratulations! Already Socket.dev optimized 🎉');
5491
+ }
5492
+ if (pkgEnvDetails.agent === NPM$1 || pkgJsonChanged) {
5493
+ // Always update package-lock.json until the npm overrides PR lands:
5494
+ // https://github.com/npm/cli/pull/8089
5495
+ await updateLockfile(pkgEnvDetails, {
5496
+ logger: logger.logger,
5497
+ spinner
5498
+ });
5499
+ }
5500
+ }
5355
5501
 
5356
5502
  const {
5357
5503
  DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$h
@@ -5408,9 +5554,9 @@ async function run$h(argv, importMeta, {
5408
5554
  }
5409
5555
 
5410
5556
  async function getOrganization(format = 'text') {
5411
- const apiToken = index.getDefaultToken();
5557
+ const apiToken = shadowNpmInject.getDefaultToken();
5412
5558
  if (!apiToken) {
5413
- 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.');
5559
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
5414
5560
  }
5415
5561
  await printOrganizationsFromToken(apiToken, format);
5416
5562
  }
@@ -5420,10 +5566,10 @@ async function printOrganizationsFromToken(apiToken, format = 'text') {
5420
5566
  spinner
5421
5567
  } = constants;
5422
5568
  spinner.start('Fetching organizations...');
5423
- const socketSdk = await index.setupSdk(apiToken);
5569
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
5424
5570
  const result = await handleApiCall(socketSdk.getOrganizations(), 'looking up organizations');
5425
5571
  if (!result.success) {
5426
- handleUnsuccessfulApiResponse('getOrganizations', result, spinner);
5572
+ handleUnsuccessfulApiResponse('getOrganizations', result);
5427
5573
  return;
5428
5574
  }
5429
5575
  spinner.stop();
@@ -5514,7 +5660,7 @@ async function run$g(argv, importMeta, {
5514
5660
  // options or missing arguments.
5515
5661
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
5516
5662
  process.exitCode = 2;
5517
- logger.logger.error(commonTags.stripIndents`
5663
+ logger.logger.fail(commonTags.stripIndents`
5518
5664
  ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
5519
5665
 
5520
5666
  - The json and markdown flags cannot be both set, pick one
@@ -5529,7 +5675,7 @@ ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields
5529
5675
  }
5530
5676
 
5531
5677
  async function runRawNpm(argv) {
5532
- const spawnPromise = spawn.spawn(npmPaths.getNpmBinPath(), argv, {
5678
+ const spawnPromise = spawn.spawn(shadowNpmPaths.getNpmBinPath(), argv, {
5533
5679
  stdio: 'inherit'
5534
5680
  });
5535
5681
  // See https://nodejs.org/api/all.html#all_child_process_event-exit.
@@ -5583,7 +5729,7 @@ async function run$f(argv, importMeta, {
5583
5729
  }
5584
5730
 
5585
5731
  async function runRawNpx(argv) {
5586
- const spawnPromise = spawn.spawn(npmPaths.getNpxBinPath(), argv, {
5732
+ const spawnPromise = spawn.spawn(shadowNpmPaths.getNpxBinPath(), argv, {
5587
5733
  stdio: 'inherit'
5588
5734
  });
5589
5735
  // See https://nodejs.org/api/all.html#all_child_process_event-exit.
@@ -5647,16 +5793,16 @@ async function createReport(socketConfig, inputPaths, {
5647
5793
  const {
5648
5794
  spinner
5649
5795
  } = constants;
5650
- const socketSdk = await index.setupSdk();
5796
+ const socketSdk = await shadowNpmInject.setupSdk();
5651
5797
  const supportedFiles = await socketSdk.getReportSupportedFiles().then(res => {
5652
- if (!res.success) handleUnsuccessfulApiResponse('getReportSupportedFiles', res, spinner);
5798
+ if (!res.success) handleUnsuccessfulApiResponse('getReportSupportedFiles', res);
5653
5799
  return res.data;
5654
5800
  }).catch(cause => {
5655
5801
  throw new Error('Failed getting supported files for report', {
5656
5802
  cause
5657
5803
  });
5658
5804
  });
5659
- const packagePaths = await npmPaths.getPackageFilesFullScans(cwd, inputPaths, supportedFiles, socketConfig);
5805
+ const packagePaths = await shadowNpmPaths.getPackageFilesFullScans(cwd, inputPaths, supportedFiles, socketConfig);
5660
5806
  const packagePathsCount = packagePaths.length;
5661
5807
  if (packagePathsCount && debug.isDebug()) {
5662
5808
  for (const pkgPath of packagePaths) {
@@ -5671,7 +5817,7 @@ async function createReport(socketConfig, inputPaths, {
5671
5817
  const apiCall = socketSdk.createReportFromFilePaths(packagePaths, cwd, socketConfig?.issueRules);
5672
5818
  const result = await handleApiCall(apiCall, 'creating report');
5673
5819
  if (!result.success) {
5674
- handleUnsuccessfulApiResponse('createReport', result, spinner);
5820
+ handleUnsuccessfulApiResponse('createReport', result);
5675
5821
  return undefined;
5676
5822
  }
5677
5823
  spinner.successAndStop();
@@ -5689,7 +5835,7 @@ async function getSocketConfig(absoluteConfigPath) {
5689
5835
  errors: cause.validationErrors,
5690
5836
  schema: cause.schema
5691
5837
  });
5692
- throw new index.InputError('The socket.yml config is not valid', betterErrors.map(err => `[${err.path}] ${err.message}.${err.suggestion ? err.suggestion : ''}`).join('\n'));
5838
+ throw new shadowNpmInject.InputError('The socket.yml config is not valid', betterErrors.map(err => `[${err.path}] ${err.message}.${err.suggestion ? err.suggestion : ''}`).join('\n'));
5693
5839
  } else {
5694
5840
  throw new Error('Failed to read socket.yml config', {
5695
5841
  cause
@@ -5707,7 +5853,7 @@ async function fetchReportData(reportId, includeAllIssues, strict) {
5707
5853
  spinner
5708
5854
  } = constants;
5709
5855
  spinner.start(`Fetching report with ID ${reportId} (this could take a while)`);
5710
- const socketSdk = await index.setupSdk();
5856
+ const socketSdk = await shadowNpmInject.setupSdk();
5711
5857
  let result;
5712
5858
  for (let retry = 1; !result; ++retry) {
5713
5859
  try {
@@ -5721,7 +5867,7 @@ async function fetchReportData(reportId, includeAllIssues, strict) {
5721
5867
  }
5722
5868
  }
5723
5869
  if (!result.success) {
5724
- return handleUnsuccessfulApiResponse('getReport', result, spinner);
5870
+ return handleUnsuccessfulApiResponse('getReport', result);
5725
5871
  }
5726
5872
 
5727
5873
  // Conclude the status of the API call.
@@ -5732,8 +5878,8 @@ async function fetchReportData(reportId, includeAllIssues, strict) {
5732
5878
  spinner.error('Report result deemed unhealthy for project');
5733
5879
  }
5734
5880
  } else if (!result.data.healthy) {
5735
- const severityCount = getSeverityCount(result.data.issues, includeAllIssues ? undefined : 'high');
5736
- const issueSummary = formatSeverityCount(severityCount);
5881
+ const severityCount = shadowNpmInject.getSeverityCount(result.data.issues, includeAllIssues ? undefined : 'high');
5882
+ const issueSummary = shadowNpmInject.formatSeverityCount(severityCount);
5737
5883
  spinner.success(`Report has these issues: ${issueSummary}`);
5738
5884
  } else {
5739
5885
  spinner.success('Report has no issues');
@@ -5746,7 +5892,7 @@ function formatReportDataOutput(reportId, data, commandName, outputJson, outputM
5746
5892
  if (outputJson) {
5747
5893
  logger.logger.log(JSON.stringify(data, undefined, 2));
5748
5894
  } else {
5749
- const format = new index.ColorOrMarkdown(outputMarkdown);
5895
+ const format = new shadowNpmInject.ColorOrMarkdown(outputMarkdown);
5750
5896
  logger.logger.log(commonTags.stripIndents`
5751
5897
  Detailed info on socket.dev: ${format.hyperlink(reportId, data.url, {
5752
5898
  fallbackToUrl: true
@@ -5850,7 +5996,7 @@ async function run$d(argv, importMeta, {
5850
5996
  } else if (json) {
5851
5997
  logger.logger.log(JSON.stringify(result.data, undefined, 2));
5852
5998
  } else {
5853
- const format = new index.ColorOrMarkdown(markdown);
5999
+ const format = new shadowNpmInject.ColorOrMarkdown(markdown);
5854
6000
  logger.logger.log(`New report: ${format.hyperlink(result.data.id, result.data.url, {
5855
6001
  fallbackToUrl: true
5856
6002
  })}`);
@@ -5897,7 +6043,7 @@ async function run$c(argv, importMeta, {
5897
6043
  // options or missing arguments.
5898
6044
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
5899
6045
  process.exitCode = 2;
5900
- logger.logger.error(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
6046
+ logger.logger.fail(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
5901
6047
 
5902
6048
  - Need at least one report ID ${!reportId ? colors.red('(missing!)') : colors.green('(ok)')}
5903
6049
 
@@ -5938,13 +6084,33 @@ const cmdReport = {
5938
6084
  };
5939
6085
 
5940
6086
  async function createRepo({
6087
+ default_branch,
6088
+ description,
6089
+ homepage,
6090
+ orgSlug,
6091
+ repoName,
6092
+ visibility
6093
+ }) {
6094
+ const apiToken = shadowNpmInject.getDefaultToken();
6095
+ if (!apiToken) {
6096
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
6097
+ }
6098
+ await createRepoWithToken({
6099
+ apiToken,
6100
+ default_branch,
6101
+ description,
6102
+ homepage,
6103
+ orgSlug,
6104
+ repoName,
6105
+ visibility
6106
+ });
6107
+ }
6108
+ async function createRepoWithToken({
5941
6109
  apiToken,
5942
6110
  default_branch,
5943
6111
  description,
5944
6112
  homepage,
5945
6113
  orgSlug,
5946
- outputJson,
5947
- outputMarkdown,
5948
6114
  repoName,
5949
6115
  visibility
5950
6116
  }) {
@@ -5953,22 +6119,19 @@ async function createRepo({
5953
6119
  spinner
5954
6120
  } = constants;
5955
6121
  spinner.start('Creating repository...');
5956
- const socketSdk = await index.setupSdk(apiToken);
6122
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
5957
6123
  const result = await handleApiCall(socketSdk.createOrgRepo(orgSlug, {
5958
- outputJson,
5959
- outputMarkdown,
5960
- orgSlug,
5961
6124
  name: repoName,
5962
6125
  description,
5963
6126
  homepage,
5964
6127
  default_branch,
5965
6128
  visibility
5966
6129
  }), 'creating repository');
5967
- if (result.success) {
5968
- spinner.successAndStop('Repository created successfully');
5969
- } else {
5970
- handleUnsuccessfulApiResponse('createOrgRepo', result, spinner);
6130
+ if (!result.success) {
6131
+ handleUnsuccessfulApiResponse('createOrgRepo', result);
6132
+ return;
5971
6133
  }
6134
+ spinner.successAndStop('Repository created successfully');
5972
6135
  }
5973
6136
 
5974
6137
  const {
@@ -5980,7 +6143,6 @@ const config$b = {
5980
6143
  hidden: false,
5981
6144
  flags: {
5982
6145
  ...commonFlags,
5983
- ...outputFlags,
5984
6146
  repoName: {
5985
6147
  type: 'string',
5986
6148
  shortFlag: 'n',
@@ -6044,7 +6206,7 @@ async function run$b(argv, importMeta, {
6044
6206
  // options or missing arguments.
6045
6207
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
6046
6208
  process.exitCode = 2;
6047
- logger.logger.error(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
6209
+ logger.logger.fail(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
6048
6210
 
6049
6211
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}
6050
6212
 
@@ -6055,36 +6217,36 @@ async function run$b(argv, importMeta, {
6055
6217
  logger.logger.log(DRY_RUN_BAIL_TEXT$b);
6056
6218
  return;
6057
6219
  }
6058
- const apiToken = index.getDefaultToken();
6059
- if (!apiToken) {
6060
- 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.');
6061
- }
6062
6220
  await createRepo({
6063
- outputJson: Boolean(cli.flags['json']),
6064
- outputMarkdown: Boolean(cli.flags['markdown']),
6065
6221
  orgSlug,
6066
6222
  repoName,
6067
6223
  description: String(cli.flags['repoDescription'] || ''),
6068
6224
  homepage: String(cli.flags['homepage'] || ''),
6069
6225
  default_branch: String(cli.flags['defaultBranch'] || ''),
6070
- visibility: String(cli.flags['visibility'] || 'private'),
6071
- apiToken
6226
+ visibility: String(cli.flags['visibility'] || 'private')
6072
6227
  });
6073
6228
  }
6074
6229
 
6075
- async function deleteRepo(orgSlug, repoName, apiToken) {
6230
+ async function deleteRepo(orgSlug, repoName) {
6231
+ const apiToken = shadowNpmInject.getDefaultToken();
6232
+ if (!apiToken) {
6233
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
6234
+ }
6235
+ await deleteRepoWithToken(orgSlug, repoName, apiToken);
6236
+ }
6237
+ async function deleteRepoWithToken(orgSlug, repoName, apiToken) {
6076
6238
  // Lazily access constants.spinner.
6077
6239
  const {
6078
6240
  spinner
6079
6241
  } = constants;
6080
6242
  spinner.start('Deleting repository...');
6081
- const socketSdk = await index.setupSdk(apiToken);
6243
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
6082
6244
  const result = await handleApiCall(socketSdk.deleteOrgRepo(orgSlug, repoName), 'deleting repository');
6083
- if (result.success) {
6084
- spinner.successAndStop('Repository deleted successfully');
6085
- } else {
6086
- handleUnsuccessfulApiResponse('deleteOrgRepo', result, spinner);
6245
+ if (!result.success) {
6246
+ handleUnsuccessfulApiResponse('deleteOrgRepo', result);
6247
+ return;
6087
6248
  }
6249
+ spinner.successAndStop('Repository deleted successfully');
6088
6250
  }
6089
6251
 
6090
6252
  const {
@@ -6128,7 +6290,7 @@ async function run$a(argv, importMeta, {
6128
6290
  // options or missing arguments.
6129
6291
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
6130
6292
  process.exitCode = 2;
6131
- logger.logger.error(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
6293
+ logger.logger.fail(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
6132
6294
 
6133
6295
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}
6134
6296
 
@@ -6141,20 +6303,37 @@ async function run$a(argv, importMeta, {
6141
6303
  logger.logger.log(DRY_RUN_BAIL_TEXT$a);
6142
6304
  return;
6143
6305
  }
6144
- const apiToken = index.getDefaultToken();
6145
- if (!apiToken) {
6146
- 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.');
6147
- }
6148
- await deleteRepo(orgSlug, repoName, apiToken);
6306
+ await deleteRepo(orgSlug, repoName);
6149
6307
  }
6150
6308
 
6151
6309
  // @ts-ignore
6152
6310
  async function listRepos({
6311
+ direction,
6312
+ orgSlug,
6313
+ outputKind,
6314
+ page,
6315
+ per_page,
6316
+ sort
6317
+ }) {
6318
+ const apiToken = shadowNpmInject.getDefaultToken();
6319
+ if (!apiToken) {
6320
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
6321
+ }
6322
+ await listReposWithToken({
6323
+ apiToken,
6324
+ direction,
6325
+ orgSlug,
6326
+ outputKind,
6327
+ page,
6328
+ per_page,
6329
+ sort
6330
+ });
6331
+ }
6332
+ async function listReposWithToken({
6153
6333
  apiToken,
6154
6334
  direction,
6155
6335
  orgSlug,
6156
- outputJson,
6157
- outputMarkdown,
6336
+ outputKind,
6158
6337
  page,
6159
6338
  per_page,
6160
6339
  sort
@@ -6163,23 +6342,20 @@ async function listRepos({
6163
6342
  const {
6164
6343
  spinner
6165
6344
  } = constants;
6166
- spinner.start('Listing repositories...');
6167
- const socketSdk = await index.setupSdk(apiToken);
6345
+ spinner.start('Fetching list of repositories...');
6346
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
6168
6347
  const result = await handleApiCall(socketSdk.getOrgRepoList(orgSlug, {
6169
- outputJson,
6170
- outputMarkdown,
6171
- orgSlug,
6172
6348
  sort,
6173
6349
  direction,
6174
6350
  per_page,
6175
6351
  page
6176
6352
  }), 'listing repositories');
6177
6353
  if (!result.success) {
6178
- handleUnsuccessfulApiResponse('getOrgRepoList', result, spinner);
6354
+ handleUnsuccessfulApiResponse('getOrgRepoList', result);
6179
6355
  return;
6180
6356
  }
6181
- spinner.stop();
6182
- if (outputJson) {
6357
+ spinner.stop('Fetch complete.');
6358
+ if (outputKind === 'json') {
6183
6359
  const data = result.data.results.map(o => ({
6184
6360
  id: o.id,
6185
6361
  name: o.name,
@@ -6276,7 +6452,7 @@ async function run$9(argv, importMeta, {
6276
6452
  // options or missing arguments.
6277
6453
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
6278
6454
  process.exitCode = 2;
6279
- logger.logger.error(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
6455
+ logger.logger.fail(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
6280
6456
 
6281
6457
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}
6282
6458
 
@@ -6287,30 +6463,44 @@ async function run$9(argv, importMeta, {
6287
6463
  logger.logger.log(DRY_RUN_BAIL_TEXT$9);
6288
6464
  return;
6289
6465
  }
6290
- const apiToken = index.getDefaultToken();
6291
- if (!apiToken) {
6292
- 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.');
6293
- }
6294
6466
  await listRepos({
6295
- apiToken,
6296
- outputJson: Boolean(cli.flags['json']),
6297
- outputMarkdown: Boolean(cli.flags['markdown']),
6298
- orgSlug,
6299
- sort: String(cli.flags['sort'] || 'created_at'),
6300
6467
  direction: cli.flags['direction'] === 'asc' ? 'asc' : 'desc',
6468
+ orgSlug,
6469
+ outputKind: cli.flags['json'] ? 'json' : cli.flags['markdown'] ? 'markdown' : 'print',
6301
6470
  page: Number(cli.flags['page']) || 1,
6302
- per_page: Number(cli.flags['perPage']) || 30
6471
+ per_page: Number(cli.flags['perPage']) || 30,
6472
+ sort: String(cli.flags['sort'] || 'created_at')
6303
6473
  });
6304
6474
  }
6305
6475
 
6306
6476
  async function updateRepo({
6477
+ default_branch,
6478
+ description,
6479
+ homepage,
6480
+ orgSlug,
6481
+ repoName,
6482
+ visibility
6483
+ }) {
6484
+ const apiToken = shadowNpmInject.getDefaultToken();
6485
+ if (!apiToken) {
6486
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
6487
+ }
6488
+ await updateRepoWithToken({
6489
+ apiToken,
6490
+ default_branch,
6491
+ description,
6492
+ homepage,
6493
+ orgSlug,
6494
+ repoName,
6495
+ visibility
6496
+ });
6497
+ }
6498
+ async function updateRepoWithToken({
6307
6499
  apiToken,
6308
6500
  default_branch,
6309
6501
  description,
6310
6502
  homepage,
6311
6503
  orgSlug,
6312
- outputJson,
6313
- outputMarkdown,
6314
6504
  repoName,
6315
6505
  visibility
6316
6506
  }) {
@@ -6319,10 +6509,8 @@ async function updateRepo({
6319
6509
  spinner
6320
6510
  } = constants;
6321
6511
  spinner.start('Updating repository...');
6322
- const socketSdk = await index.setupSdk(apiToken);
6512
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
6323
6513
  const result = await handleApiCall(socketSdk.updateOrgRepo(orgSlug, repoName, {
6324
- outputJson,
6325
- outputMarkdown,
6326
6514
  orgSlug,
6327
6515
  name: repoName,
6328
6516
  description,
@@ -6330,11 +6518,11 @@ async function updateRepo({
6330
6518
  default_branch,
6331
6519
  visibility
6332
6520
  }), 'updating repository');
6333
- if (result.success) {
6334
- spinner.successAndStop('Repository updated successfully');
6335
- } else {
6336
- handleUnsuccessfulApiResponse('updateOrgRepo', result, spinner);
6521
+ if (!result.success) {
6522
+ handleUnsuccessfulApiResponse('updateOrgRepo', result);
6523
+ return;
6337
6524
  }
6525
+ spinner.successAndStop('Repository updated successfully');
6338
6526
  }
6339
6527
 
6340
6528
  const {
@@ -6346,7 +6534,6 @@ const config$8 = {
6346
6534
  hidden: false,
6347
6535
  flags: {
6348
6536
  ...commonFlags,
6349
- ...outputFlags,
6350
6537
  repoName: {
6351
6538
  type: 'string',
6352
6539
  shortFlag: 'n',
@@ -6410,7 +6597,7 @@ async function run$8(argv, importMeta, {
6410
6597
  // options or missing arguments.
6411
6598
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
6412
6599
  process.exitCode = 2;
6413
- logger.logger.error(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
6600
+ logger.logger.fail(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
6414
6601
 
6415
6602
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}
6416
6603
 
@@ -6423,14 +6610,7 @@ async function run$8(argv, importMeta, {
6423
6610
  logger.logger.log(DRY_RUN_BAIL_TEXT$8);
6424
6611
  return;
6425
6612
  }
6426
- const apiToken = index.getDefaultToken();
6427
- if (!apiToken) {
6428
- 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.');
6429
- }
6430
6613
  await updateRepo({
6431
- apiToken,
6432
- outputJson: Boolean(cli.flags['json']),
6433
- outputMarkdown: Boolean(cli.flags['markdown']),
6434
6614
  orgSlug,
6435
6615
  repoName,
6436
6616
  description: String(cli.flags['repoDescription'] || ''),
@@ -6441,16 +6621,45 @@ async function run$8(argv, importMeta, {
6441
6621
  }
6442
6622
 
6443
6623
  // @ts-ignore
6444
- async function viewRepo(orgSlug, repoName, apiToken) {
6624
+ async function viewRepo(orgSlug, repoName, outputKind) {
6625
+ const apiToken = shadowNpmInject.getDefaultToken();
6626
+ if (!apiToken) {
6627
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
6628
+ }
6629
+ await viewRepoWithToken(orgSlug, repoName, apiToken, outputKind);
6630
+ }
6631
+ async function viewRepoWithToken(orgSlug, repoName, apiToken, outputKind) {
6445
6632
  // Lazily access constants.spinner.
6446
6633
  const {
6447
6634
  spinner
6448
6635
  } = constants;
6449
- spinner.start('Fetching repository...');
6450
- const socketSdk = await index.setupSdk(apiToken);
6636
+ spinner.start('Fetching repository data...');
6637
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
6451
6638
  const result = await handleApiCall(socketSdk.getOrgRepo(orgSlug, repoName), 'fetching repository');
6452
6639
  if (!result.success) {
6453
- handleUnsuccessfulApiResponse('getOrgRepo', result, spinner);
6640
+ handleUnsuccessfulApiResponse('getOrgRepo', result);
6641
+ return;
6642
+ }
6643
+ spinner.stop('Fetched repository data.');
6644
+ if (outputKind === 'json') {
6645
+ const {
6646
+ archived,
6647
+ created_at,
6648
+ default_branch,
6649
+ homepage,
6650
+ id,
6651
+ name,
6652
+ visibility
6653
+ } = result.data;
6654
+ logger.logger.log(JSON.stringify({
6655
+ id,
6656
+ name,
6657
+ visibility,
6658
+ default_branch,
6659
+ homepage,
6660
+ archived,
6661
+ created_at
6662
+ }, null, 2));
6454
6663
  return;
6455
6664
  }
6456
6665
  const options = {
@@ -6477,7 +6686,7 @@ async function viewRepo(orgSlug, repoName, apiToken) {
6477
6686
  name: colors.magenta('Created at')
6478
6687
  }]
6479
6688
  };
6480
- spinner.stop(chalkTable(options, [result.data]));
6689
+ logger.logger.log(chalkTable(options, [result.data]));
6481
6690
  }
6482
6691
 
6483
6692
  const {
@@ -6489,7 +6698,12 @@ const config$7 = {
6489
6698
  hidden: false,
6490
6699
  flags: {
6491
6700
  ...commonFlags,
6492
- ...outputFlags
6701
+ ...outputFlags,
6702
+ repoName: {
6703
+ description: 'The repository to check',
6704
+ default: '',
6705
+ type: 'string'
6706
+ }
6493
6707
  },
6494
6708
  help: (command, config) => `
6495
6709
  Usage
@@ -6523,7 +6737,7 @@ async function run$7(argv, importMeta, {
6523
6737
  // options or missing arguments.
6524
6738
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
6525
6739
  process.exitCode = 2;
6526
- logger.logger.error(commonTags.stripIndents`
6740
+ logger.logger.fail(commonTags.stripIndents`
6527
6741
  ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
6528
6742
 
6529
6743
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}
@@ -6536,11 +6750,7 @@ async function run$7(argv, importMeta, {
6536
6750
  logger.logger.log(DRY_RUN_BAIL_TEXT$7);
6537
6751
  return;
6538
6752
  }
6539
- const apiToken = index.getDefaultToken();
6540
- if (!apiToken) {
6541
- 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.');
6542
- }
6543
- await viewRepo(orgSlug, repoName, apiToken);
6753
+ await viewRepo(orgSlug, repoName, cli.flags['json'] ? 'json' : cli.flags['markdown'] ? 'markdown' : 'print');
6544
6754
  }
6545
6755
 
6546
6756
  const description$1 = 'Repositories related commands';
@@ -6725,10 +6935,10 @@ async function createFullScan({
6725
6935
  const {
6726
6936
  spinner
6727
6937
  } = constants;
6728
- const socketSdk = await index.setupSdk();
6938
+ const socketSdk = await shadowNpmInject.setupSdk();
6729
6939
  const supportedFiles = await socketSdk.getReportSupportedFiles().then(res => {
6730
6940
  if (!res.success) {
6731
- handleUnsuccessfulApiResponse('getReportSupportedFiles', res, spinner);
6941
+ handleUnsuccessfulApiResponse('getReportSupportedFiles', res);
6732
6942
  assert(false, 'handleUnsuccessfulApiResponse should unconditionally throw');
6733
6943
  }
6734
6944
  return res.data;
@@ -6751,14 +6961,14 @@ async function createFullScan({
6751
6961
  // const absoluteConfigPath = path.join(cwd, 'socket.yml')
6752
6962
  // const socketConfig = await getSocketConfig(absoluteConfigPath)
6753
6963
 
6754
- const packagePaths = await npmPaths.getPackageFilesFullScans(cwd, targets, supportedFiles
6964
+ const packagePaths = await shadowNpmPaths.getPackageFilesFullScans(cwd, targets, supportedFiles
6755
6965
  // socketConfig
6756
6966
  );
6757
6967
 
6758
6968
  // We're going to need an api token to suggest data because those suggestions
6759
6969
  // must come from data we already know. Don't error on missing api token yet.
6760
6970
  // If the api-token is not set, ignore it for the sake of suggestions.
6761
- const apiToken = index.getDefaultToken();
6971
+ const apiToken = shadowNpmInject.getDefaultToken();
6762
6972
 
6763
6973
  // If the current cwd is unknown and is used as a repo slug anyways, we will
6764
6974
  // first need to register the slug before we can use it.
@@ -6792,7 +7002,7 @@ async function createFullScan({
6792
7002
  // options or missing arguments.
6793
7003
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
6794
7004
  process$1.exitCode = 2;
6795
- logger.logger.error(commonTags.stripIndents`
7005
+ logger.logger.fail(commonTags.stripIndents`
6796
7006
  ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
6797
7007
 
6798
7008
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}
@@ -6814,7 +7024,7 @@ async function createFullScan({
6814
7024
  logger.logger.log('```');
6815
7025
  }
6816
7026
  if (!apiToken) {
6817
- 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.');
7027
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
6818
7028
  }
6819
7029
  if (readOnly) {
6820
7030
  logger.logger.log('[ReadOnly] Bailing now');
@@ -6830,7 +7040,7 @@ async function createFullScan({
6830
7040
  tmp
6831
7041
  }, packagePaths, cwd), 'Creating scan');
6832
7042
  if (!result.success) {
6833
- handleUnsuccessfulApiResponse('CreateOrgFullScan', result, spinner);
7043
+ handleUnsuccessfulApiResponse('CreateOrgFullScan', result);
6834
7044
  return;
6835
7045
  }
6836
7046
  spinner.successAndStop('Scan created successfully');
@@ -6970,20 +7180,21 @@ async function run$6(argv, importMeta, {
6970
7180
  });
6971
7181
  const [orgSlug = '', ...targets] = cli.input;
6972
7182
  const cwd = cli.flags['cwd'] && cli.flags['cwd'] !== 'process.cwd()' ? String(cli.flags['cwd']) : process$1.cwd();
6973
- let {
7183
+ const {
6974
7184
  branch: branchName,
6975
7185
  repo: repoName
6976
7186
  } = cli.flags;
6977
- const apiToken = index.getDefaultToken(); // This checks if we _can_ suggest anything
7187
+ const apiToken = shadowNpmInject.getDefaultToken(); // This checks if we _can_ suggest anything
6978
7188
 
6979
7189
  if (!apiToken && (!orgSlug || !repoName || !branchName || !targets.length)) {
6980
7190
  // Without api token we cannot recover because we can't request more info
6981
7191
  // from the server, to match and help with the current cwd/git status.
7192
+ //
6982
7193
  // Use exit status of 2 to indicate incorrect usage, generally invalid
6983
7194
  // options or missing arguments.
6984
7195
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
6985
7196
  process$1.exitCode = 2;
6986
- logger.logger.error(commonTags.stripIndents`
7197
+ logger.logger.fail(commonTags.stripIndents`
6987
7198
  ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
6988
7199
 
6989
7200
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}
@@ -7022,9 +7233,9 @@ async function run$6(argv, importMeta, {
7022
7233
  }
7023
7234
 
7024
7235
  async function deleteOrgFullScan(orgSlug, fullScanId) {
7025
- const apiToken = index.getDefaultToken();
7236
+ const apiToken = shadowNpmInject.getDefaultToken();
7026
7237
  if (!apiToken) {
7027
- 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.');
7238
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
7028
7239
  }
7029
7240
  await deleteOrgFullScanWithToken(orgSlug, fullScanId, apiToken);
7030
7241
  }
@@ -7034,10 +7245,10 @@ async function deleteOrgFullScanWithToken(orgSlug, fullScanId, apiToken) {
7034
7245
  spinner
7035
7246
  } = constants;
7036
7247
  spinner.start('Deleting scan...');
7037
- const socketSdk = await index.setupSdk(apiToken);
7248
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
7038
7249
  const result = await handleApiCall(socketSdk.deleteOrgFullScan(orgSlug, fullScanId), 'Deleting scan');
7039
7250
  if (!result.success) {
7040
- handleUnsuccessfulApiResponse('deleteOrgFullScan', result, spinner);
7251
+ handleUnsuccessfulApiResponse('deleteOrgFullScan', result);
7041
7252
  return;
7042
7253
  }
7043
7254
  spinner.successAndStop('Scan deleted successfully');
@@ -7085,7 +7296,7 @@ async function run$5(argv, importMeta, {
7085
7296
  // options or missing arguments.
7086
7297
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
7087
7298
  process.exitCode = 2;
7088
- logger.logger.error(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
7299
+ logger.logger.fail(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
7089
7300
 
7090
7301
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}
7091
7302
 
@@ -7109,9 +7320,9 @@ async function listFullScans({
7109
7320
  per_page,
7110
7321
  sort
7111
7322
  }) {
7112
- const apiToken = index.getDefaultToken();
7323
+ const apiToken = shadowNpmInject.getDefaultToken();
7113
7324
  if (!apiToken) {
7114
- 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.');
7325
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
7115
7326
  }
7116
7327
  await listFullScansWithToken({
7117
7328
  apiToken,
@@ -7139,7 +7350,7 @@ async function listFullScansWithToken({
7139
7350
  spinner
7140
7351
  } = constants;
7141
7352
  spinner.start('Fetching list of scans...');
7142
- const socketSdk = await index.setupSdk(apiToken);
7353
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
7143
7354
  const result = await handleApiCall(socketSdk.getOrgFullScanList(orgSlug, {
7144
7355
  sort,
7145
7356
  direction,
@@ -7148,7 +7359,7 @@ async function listFullScansWithToken({
7148
7359
  from: from_time
7149
7360
  }), 'Listing scans');
7150
7361
  if (!result.success) {
7151
- handleUnsuccessfulApiResponse('getOrgFullScanList', result, spinner);
7362
+ handleUnsuccessfulApiResponse('getOrgFullScanList', result);
7152
7363
  return;
7153
7364
  }
7154
7365
  spinner.stop(`Fetch complete`);
@@ -7264,7 +7475,7 @@ async function run$4(argv, importMeta, {
7264
7475
  // options or missing arguments.
7265
7476
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
7266
7477
  process.exitCode = 2;
7267
- logger.logger.error(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
7478
+ logger.logger.fail(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
7268
7479
 
7269
7480
  - Org name as the argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}`);
7270
7481
  return;
@@ -7285,9 +7496,9 @@ async function run$4(argv, importMeta, {
7285
7496
  }
7286
7497
 
7287
7498
  async function getOrgScanMetadata(orgSlug, scanId, outputKind) {
7288
- const apiToken = index.getDefaultToken();
7499
+ const apiToken = shadowNpmInject.getDefaultToken();
7289
7500
  if (!apiToken) {
7290
- 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.');
7501
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
7291
7502
  }
7292
7503
  await getOrgScanMetadataWithToken(orgSlug, scanId, apiToken, outputKind);
7293
7504
  }
@@ -7297,10 +7508,10 @@ async function getOrgScanMetadataWithToken(orgSlug, scanId, apiToken, outputKind
7297
7508
  spinner
7298
7509
  } = constants;
7299
7510
  spinner.start('Fetching meta data for a full scan...');
7300
- const socketSdk = await index.setupSdk(apiToken);
7511
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
7301
7512
  const result = await handleApiCall(socketSdk.getOrgFullScanMetadata(orgSlug, scanId), 'Listing scans');
7302
7513
  if (!result.success) {
7303
- handleUnsuccessfulApiResponse('getOrgFullScanMetadata', result, spinner);
7514
+ handleUnsuccessfulApiResponse('getOrgFullScanMetadata', result);
7304
7515
  return;
7305
7516
  }
7306
7517
  spinner?.successAndStop('Fetched the meta data\n');
@@ -7366,7 +7577,7 @@ async function run$3(argv, importMeta, {
7366
7577
  // options or missing arguments.
7367
7578
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
7368
7579
  process.exitCode = 2;
7369
- logger.logger.error(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
7580
+ logger.logger.fail(commonTags.stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
7370
7581
 
7371
7582
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}
7372
7583
 
@@ -7385,15 +7596,15 @@ async function streamFullScan(orgSlug, fullScanId, file) {
7385
7596
  const {
7386
7597
  spinner
7387
7598
  } = constants;
7388
- const apiToken = index.getDefaultToken();
7599
+ const apiToken = shadowNpmInject.getDefaultToken();
7389
7600
  if (!apiToken) {
7390
- 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.');
7601
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
7391
7602
  }
7392
7603
  spinner.start('Fetching scan...');
7393
- const socketSdk = await index.setupSdk(apiToken);
7604
+ const socketSdk = await shadowNpmInject.setupSdk(apiToken);
7394
7605
  const data = await handleApiCall(socketSdk.getOrgFullScan(orgSlug, fullScanId, file === '-' ? undefined : file), 'Fetching a scan');
7395
7606
  if (!data?.success) {
7396
- handleUnsuccessfulApiResponse('getOrgFullScan', data, spinner);
7607
+ handleUnsuccessfulApiResponse('getOrgFullScan', data);
7397
7608
  return;
7398
7609
  }
7399
7610
  spinner?.successAndStop(file ? `Full scan details written to ${file}` : 'stdout');
@@ -7405,16 +7616,16 @@ async function getFullScan(orgSlug, fullScanId) {
7405
7616
  const {
7406
7617
  spinner
7407
7618
  } = constants;
7408
- const apiToken = index.getDefaultToken();
7619
+ const apiToken = shadowNpmInject.getDefaultToken();
7409
7620
  if (!apiToken) {
7410
- 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.');
7621
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
7411
7622
  }
7412
7623
  spinner.start('Fetching full-scan...');
7413
7624
  const response = await queryAPI(`orgs/${orgSlug}/full-scans/${encodeURIComponent(fullScanId)}`, apiToken);
7414
7625
  spinner.stop('Fetch complete.');
7415
7626
  if (!response.ok) {
7416
7627
  const err = await handleAPIError(response.status);
7417
- logger.logger.error(`${colors.bgRed(colors.white(response.statusText))}: Fetch error: ${err}`);
7628
+ logger.logger.fail(`${colors.bgRed(colors.white(response.statusText))}: Fetch error: ${err}`);
7418
7629
  return;
7419
7630
  }
7420
7631
 
@@ -7462,9 +7673,9 @@ View this report at: https://socket.dev/dashboard/org/${orgSlug}/sbom/${fullScan
7462
7673
  await fs$1.writeFile(filePath, report, 'utf8');
7463
7674
  logger.logger.log(`Data successfully written to ${filePath}`);
7464
7675
  } catch (e) {
7465
- logger.logger.error('There was an error trying to write the json to disk');
7466
- logger.logger.error(e);
7467
7676
  process.exitCode = 1;
7677
+ logger.logger.fail('There was an error trying to write the json to disk');
7678
+ logger.logger.error(e);
7468
7679
  }
7469
7680
  } else {
7470
7681
  logger.logger.log(report);
@@ -7515,7 +7726,7 @@ async function run$2(argv, importMeta, {
7515
7726
  // options or missing arguments.
7516
7727
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
7517
7728
  process.exitCode = 2;
7518
- logger.logger.error(commonTags.stripIndents`
7729
+ logger.logger.fail(commonTags.stripIndents`
7519
7730
  ${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:
7520
7731
 
7521
7732
  - Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}
@@ -7564,11 +7775,36 @@ const cmdScan = {
7564
7775
  }
7565
7776
  };
7566
7777
 
7778
+ // Note: Widgets does not seem to actually work as code :'(
7779
+
7567
7780
  async function getThreatFeed({
7781
+ direction,
7782
+ ecosystem,
7783
+ filter,
7784
+ outputKind,
7785
+ page,
7786
+ perPage
7787
+ }) {
7788
+ const apiToken = shadowNpmInject.getDefaultToken();
7789
+ if (!apiToken) {
7790
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
7791
+ }
7792
+ await getThreatFeedWithToken({
7793
+ apiToken,
7794
+ direction,
7795
+ ecosystem,
7796
+ filter,
7797
+ outputKind,
7798
+ page,
7799
+ perPage
7800
+ });
7801
+ }
7802
+ async function getThreatFeedWithToken({
7568
7803
  apiToken,
7569
7804
  direction,
7805
+ ecosystem,
7570
7806
  filter,
7571
- outputJson,
7807
+ outputKind,
7572
7808
  page,
7573
7809
  perPage
7574
7810
  }) {
@@ -7576,17 +7812,12 @@ async function getThreatFeed({
7576
7812
  const {
7577
7813
  spinner
7578
7814
  } = constants;
7579
- spinner.start('Looking up the threat feed');
7580
- const formattedQueryParams = formatQueryParams({
7581
- per_page: perPage,
7582
- page,
7583
- direction,
7584
- filter
7585
- }).join('&');
7586
- const response = await queryAPI(`threat-feed?${formattedQueryParams}`, apiToken);
7815
+ const queryParams = new URLSearchParams([['direction', direction], ['ecosystem', ecosystem], ['filter', filter], ['page', page], ['per_page', String(perPage)]]);
7816
+ spinner.start('Fetching Threat Feed data...');
7817
+ const response = await queryAPI(`threat-feed?${queryParams}`, apiToken);
7587
7818
  const data = await response.json();
7588
- spinner.stop();
7589
- if (outputJson) {
7819
+ spinner.stop('Threat feed data fetched');
7820
+ if (outputKind === 'json') {
7590
7821
  logger.logger.log(data);
7591
7822
  return;
7592
7823
  }
@@ -7599,47 +7830,98 @@ async function getThreatFeed({
7599
7830
  interactive: 'true',
7600
7831
  label: 'Threat feed',
7601
7832
  width: '100%',
7602
- height: '100%',
7833
+ height: '70%',
7834
+ // Changed from 100% to 70%
7835
+ border: {
7836
+ type: 'line',
7837
+ fg: 'cyan'
7838
+ },
7839
+ columnWidth: [10, 30, 20, 18, 15, 200],
7840
+ // TODO: the truncation doesn't seem to work too well yet but when we add
7841
+ // `pad` alignment fails, when we extend columnSpacing alignment fails
7842
+ columnSpacing: 1,
7843
+ truncate: '_'
7844
+ });
7845
+
7846
+ // Create details box at the bottom
7847
+ const detailsBox = new BoxWidget({
7848
+ bottom: 0,
7849
+ height: '30%',
7850
+ width: '100%',
7603
7851
  border: {
7604
7852
  type: 'line',
7605
7853
  fg: 'cyan'
7606
7854
  },
7607
- columnSpacing: 3,
7608
- //in chars
7609
- columnWidth: [9, 30, 10, 17, 13, 100] /*in chars*/
7855
+ label: 'Details',
7856
+ content: 'Use arrow keys to navigate. Press Enter to select a threat. Press q to exit.',
7857
+ style: {
7858
+ fg: 'white'
7859
+ }
7610
7860
  });
7611
7861
 
7612
7862
  // allow control the table with the keyboard
7613
7863
  table.focus();
7614
7864
  screen.append(table);
7865
+ screen.append(detailsBox);
7615
7866
  const formattedOutput = formatResults(data.results);
7867
+ const descriptions = data.results.map(d => d.description);
7616
7868
  table.setData({
7617
- headers: ['Ecosystem', 'Name', 'Version', 'Threat type', 'Detected at', 'Details'],
7869
+ headers: [' Ecosystem', ' Name', ' Version', ' Threat type', ' Detected at', ' Details'],
7618
7870
  data: formattedOutput
7619
7871
  });
7872
+
7873
+ // Update details box when selection changes
7874
+ table.rows.on('select item', () => {
7875
+ const selectedIndex = table.rows.selected;
7876
+ if (selectedIndex !== undefined && selectedIndex >= 0) {
7877
+ const selectedRow = formattedOutput[selectedIndex];
7878
+ if (selectedRow) {
7879
+ // Note: the spacing works around issues with the table; it refuses to pad!
7880
+ detailsBox.setContent(`Ecosystem: ${selectedRow[0]}\n` + `Name: ${selectedRow[1]}\n` + `Version:${selectedRow[2]}\n` + `Threat type:${selectedRow[3]}\n` + `Detected at:${selectedRow[4]}\n` + `Details: ${selectedRow[5]}\n` + `Description: ${descriptions[selectedIndex]}`);
7881
+ screen.render();
7882
+ }
7883
+ }
7884
+ });
7620
7885
  screen.render();
7621
7886
  screen.key(['escape', 'q', 'C-c'], () => process$1.exit(0));
7887
+ screen.key(['return'], () => {
7888
+ const selectedIndex = table.rows.selected;
7889
+ screen.destroy();
7890
+ const selectedRow = formattedOutput[selectedIndex];
7891
+ console.log(selectedRow);
7892
+ });
7622
7893
  }
7623
7894
  function formatResults(data) {
7624
7895
  return data.map(d => {
7625
7896
  const ecosystem = d.purl.split('pkg:')[1].split('/')[0];
7626
7897
  const name = d.purl.split('/')[1].split('@')[0];
7627
7898
  const version = d.purl.split('@')[1];
7628
- const timeStart = new Date(d.createdAt).getMilliseconds();
7629
- const timeEnd = Date.now();
7630
- const diff = getHourDiff(timeStart, timeEnd);
7631
- const hourDiff = diff > 0 ? `${diff} hours ago` : `${getMinDiff(timeStart, timeEnd)} minutes ago`;
7632
- return [ecosystem, decodeURIComponent(name), version, d.threatType, hourDiff, d.locationHtmlUrl];
7899
+ const timeDiff = msAtHome(d.createdAt);
7900
+
7901
+ // Note: the spacing works around issues with the table; it refuses to pad!
7902
+ return [ecosystem, decodeURIComponent(name), ` ${version}`, ` ${d.threatType}`, ` ${timeDiff}`, d.locationHtmlUrl];
7633
7903
  });
7634
7904
  }
7635
- function formatQueryParams(params) {
7636
- return Object.entries(params).map(entry => `${entry[0]}=${entry[1]}`);
7637
- }
7638
- function getHourDiff(start, end) {
7639
- return Math.floor((end - start) / 3600000);
7640
- }
7641
- function getMinDiff(start, end) {
7642
- return Math.floor((end - start) / 60000);
7905
+ function msAtHome(isoTimeStamp) {
7906
+ const timeStart = Date.parse(isoTimeStamp);
7907
+ const timeEnd = Date.now();
7908
+ const rtf = new Intl.RelativeTimeFormat('en', {
7909
+ numeric: 'always',
7910
+ style: 'short'
7911
+ });
7912
+ const delta = timeEnd - timeStart;
7913
+ if (delta < 60 * 60 * 1000) {
7914
+ return rtf.format(-Math.round(delta / (60 * 1000)), 'minute');
7915
+ // return Math.round(delta / (60 * 1000)) + ' min ago'
7916
+ } else if (delta < 24 * 60 * 60 * 1000) {
7917
+ return rtf.format(-(delta / (60 * 60 * 1000)).toFixed(1), 'hour');
7918
+ // return (delta / (60 * 60 * 1000)).toFixed(1) + ' hr ago'
7919
+ } else if (delta < 7 * 24 * 60 * 60 * 1000) {
7920
+ return rtf.format(-(delta / (24 * 60 * 60 * 1000)).toFixed(1), 'day');
7921
+ // return (delta / (24 * 60 * 60 * 1000)).toFixed(1) + ' day ago'
7922
+ } else {
7923
+ return isoTimeStamp.slice(0, 10);
7924
+ }
7643
7925
  }
7644
7926
 
7645
7927
  const {
@@ -7647,7 +7929,7 @@ const {
7647
7929
  } = constants;
7648
7930
  const config$1 = {
7649
7931
  commandName: 'threat-feed',
7650
- description: 'Look up the threat feed',
7932
+ description: '[beta] View the threat feed',
7651
7933
  hidden: false,
7652
7934
  flags: {
7653
7935
  ...commonFlags,
@@ -7670,6 +7952,12 @@ const config$1 = {
7670
7952
  default: 'desc',
7671
7953
  description: 'Order asc or desc by the createdAt attribute.'
7672
7954
  },
7955
+ eco: {
7956
+ type: 'string',
7957
+ shortFlag: 'e',
7958
+ default: '',
7959
+ description: 'Only show threats for a particular ecosystem'
7960
+ },
7673
7961
  filter: {
7674
7962
  type: 'string',
7675
7963
  shortFlag: 'f',
@@ -7681,9 +7969,35 @@ const config$1 = {
7681
7969
  Usage
7682
7970
  $ ${command}
7683
7971
 
7972
+ This feature requires a Threat Feed license. Please contact
7973
+ sales@socket.dev if you are interested in purchasing this access.
7974
+
7684
7975
  Options
7685
7976
  ${getFlagListOutput(config.flags, 6)}
7686
7977
 
7978
+ Valid filters:
7979
+
7980
+ - anom Anomaly
7981
+ - c Do not filter
7982
+ - fp False Positives
7983
+ - joke Joke / Fake
7984
+ - mal Malware and Possible Malware [default]
7985
+ - secret Secrets
7986
+ - spy Telemetry
7987
+ - tp False Positives and Unreviewed
7988
+ - typo Typo-squat
7989
+ - u Unreviewed
7990
+ - vuln Vulnerability
7991
+
7992
+ Valid ecosystems:
7993
+
7994
+ - gem
7995
+ - golang
7996
+ - maven
7997
+ - npm
7998
+ - nuget
7999
+ - pypi
8000
+
7687
8001
  Examples
7688
8002
  $ ${command}
7689
8003
  $ ${command} --perPage=5 --page=2 --direction=asc --filter=joke
@@ -7707,17 +8021,13 @@ async function run$1(argv, importMeta, {
7707
8021
  logger.logger.log(DRY_RUN_BAIL_TEXT$1);
7708
8022
  return;
7709
8023
  }
7710
- const apiToken = index.getDefaultToken();
7711
- if (!apiToken) {
7712
- 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.');
7713
- }
7714
8024
  await getThreatFeed({
7715
- apiToken,
7716
8025
  direction: String(cli.flags['direction'] || 'desc'),
8026
+ ecosystem: String(cli.flags['eco'] || ''),
7717
8027
  filter: String(cli.flags['filter'] || 'mal'),
7718
- outputJson: Boolean(cli.flags['json']),
7719
- page: String(cli.flags['filter'] || '1'),
7720
- perPage: Number(cli.flags['per_page'] || 0)
8028
+ outputKind: cli.flags['json'] ? 'json' : cli.flags['markdown'] ? 'markdown' : 'print',
8029
+ page: String(cli.flags['page'] || '1'),
8030
+ perPage: Number(cli.flags['perPage']) || 30
7721
8031
  });
7722
8032
  }
7723
8033
 
@@ -7804,7 +8114,7 @@ function askQuestion(rl, query) {
7804
8114
  function removeSocketWrapper(file) {
7805
8115
  return fs.readFile(file, 'utf8', function (err, data) {
7806
8116
  if (err) {
7807
- logger.logger.error('There was an error removing the alias:');
8117
+ logger.logger.fail('There was an error removing the alias:');
7808
8118
  logger.logger.error(err);
7809
8119
  return;
7810
8120
  }
@@ -7881,7 +8191,7 @@ async function run(argv, importMeta, {
7881
8191
  // options or missing arguments.
7882
8192
  // https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
7883
8193
  process.exitCode = 2;
7884
- logger.logger.error(commonTags.stripIndents`
8194
+ logger.logger.fail(commonTags.stripIndents`
7885
8195
  ${colors.bgRed(colors.white('Input error'))}: Please provide the required flags:
7886
8196
 
7887
8197
  - Must use --enabled or --disabled
@@ -7914,7 +8224,7 @@ async function run(argv, importMeta, {
7914
8224
  }
7915
8225
  }
7916
8226
  if (!fs.existsSync(bashRcPath) && !fs.existsSync(zshRcPath)) {
7917
- logger.logger.error('There was an issue setting up the alias in your bash profile');
8227
+ logger.logger.fail('There was an issue setting up the alias in your bash profile');
7918
8228
  }
7919
8229
  }
7920
8230
 
@@ -7973,10 +8283,10 @@ void (async () => {
7973
8283
  let errorBody;
7974
8284
  let errorTitle;
7975
8285
  let errorMessage = '';
7976
- if (e instanceof index.AuthError) {
8286
+ if (e instanceof shadowNpmInject.AuthError) {
7977
8287
  errorTitle = 'Authentication error';
7978
8288
  errorMessage = e.message;
7979
- } else if (e instanceof index.InputError) {
8289
+ } else if (e instanceof shadowNpmInject.InputError) {
7980
8290
  errorTitle = 'Invalid input';
7981
8291
  errorMessage = e.message;
7982
8292
  errorBody = e.body;
@@ -7987,12 +8297,12 @@ void (async () => {
7987
8297
  } else {
7988
8298
  errorTitle = 'Unexpected error with no details';
7989
8299
  }
7990
- logger.logger.error(`${colors.bgRed(colors.white(errorTitle + ':'))} ${errorMessage}`);
8300
+ logger.logger.fail(`${colors.bgRed(colors.white(errorTitle + ':'))} ${errorMessage}`);
7991
8301
  if (errorBody) {
7992
8302
  logger.logger.error(`\n${errorBody}`);
7993
8303
  }
7994
- await index.captureException(e);
8304
+ await shadowNpmInject.captureException(e);
7995
8305
  }
7996
8306
  })();
7997
- //# debugId=4fe0e5e5-54cb-444b-88dc-36bf76ff766a
8307
+ //# debugId=e7fc426e-8da9-4a73-b05c-6a96ab758857
7998
8308
  //# sourceMappingURL=cli.js.map