'use strict';

var constants = require('./constants.js');
var agent = require('../external/@socketsecurity/registry/lib/agent');
var require$$9 = require('../external/@socketsecurity/registry/lib/debug');
var require$$11 = require('../external/@socketsecurity/registry/lib/objects');
var spawn = require('../external/@socketsecurity/registry/lib/spawn');
var utils = require('./utils.js');

/**
 * Ensures stdio configuration includes IPC channel for process communication.
 * Converts various stdio formats to include 'ipc' as the fourth element.
 */
function ensureIpcInStdio(stdio) {
  if (typeof stdio === 'string') {
    return [stdio, stdio, stdio, 'ipc'];
  } else if (Array.isArray(stdio)) {
    if (!stdio.includes('ipc')) {
      return stdio.concat('ipc');
    }
    return stdio;
  } else {
    return ['pipe', 'pipe', 'pipe', 'ipc'];
  }
}

async function shadowNpmBase(binName, args = process.argv.slice(2), options, extra) {
  const {
    env: spawnEnv,
    ipc,
    ...spawnOpts
  } = {
    __proto__: null,
    ...options
  };
  const cwd = require$$11.getOwn(spawnOpts, 'cwd') ?? process.cwd();
  const isShadowNpm = binName === constants.NPM;
  const terminatorPos = args.indexOf('--');
  const rawBinArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos);
  const nodeOptionsArg = rawBinArgs.findLast(agent.isNpmNodeOptionsFlag);
  const progressArg = rawBinArgs.findLast(agent.isNpmProgressFlag) !== '--no-progress';
  const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
  const permArgs = isShadowNpm && constants.default.SUPPORTS_NODE_PERMISSION_FLAG ? ['--permission', '--allow-child-process',
  // '--allow-addons',
  // '--allow-wasi',
  // Allow all reads because npm walks up directories looking for config
  // and package.json files.
  '--allow-fs-read=*', `--allow-fs-write=${cwd}/*`, `--allow-fs-write=${constants.default.npmGlobalPrefix}/*`, `--allow-fs-write=${constants.default.npmCachePath}/*`] : [];
  const useAudit = rawBinArgs.includes('--audit');
  const useDebug = require$$9.isDebug('stdio');
  const useNodeOptions = nodeOptionsArg || permArgs.length;
  const binArgs = rawBinArgs.filter(a => !agent.isNpmAuditFlag(a) && !agent.isNpmProgressFlag(a));
  const isSilent = !useDebug && !binArgs.some(agent.isNpmLoglevelFlag);
  // The default value of loglevel is "notice". We default to "error" which is
  // two levels quieter.
  const logLevelArgs = isSilent ? ['--loglevel', 'error'] : [];
  const noAuditArgs = useAudit || !(await utils.findUp(constants.NODE_MODULES, {
    cwd,
    onlyDirectories: true
  })) ? [] : ['--no-audit'];
  const stdio = ensureIpcInStdio(require$$11.getOwn(spawnOpts, 'stdio'));
  const realBinPath = isShadowNpm ? await utils.installNpmLinks(constants.default.shadowBinPath) : await utils.installNpxLinks(constants.default.shadowBinPath);
  const spawnPromise = spawn.spawn(constants.default.execPath, [...constants.default.nodeNoWarningsFlags, ...constants.default.nodeDebugFlags, ...constants.default.nodeHardenFlags, ...constants.default.nodeMemoryFlags, ...(constants.default.ENV.INLINED_SOCKET_CLI_SENTRY_BUILD ? ['--require', constants.default.instrumentWithSentryPath] : []), '--require', constants.default.shadowNpmInjectPath, realBinPath, ...noAuditArgs, ...(useNodeOptions ? [`--node-options='${nodeOptionsArg ? nodeOptionsArg.slice(15) : ''}${utils.cmdFlagsToString(permArgs)}'`] : []), '--no-fund',
  // Add '--no-progress' to fix input being swallowed by the npm spinner.
  '--no-progress',
  // Add '--loglevel=error' if a loglevel flag is not provided and the
  // SOCKET_CLI_DEBUG environment variable is not truthy.
  ...logLevelArgs, ...binArgs, ...otherArgs], {
    ...spawnOpts,
    env: {
      ...process.env,
      ...constants.default.processEnv,
      ...spawnEnv
    },
    stdio
  }, extra);
  spawnPromise.process.send({
    [constants.default.SOCKET_IPC_HANDSHAKE]: {
      [constants.default.SOCKET_CLI_SHADOW_API_TOKEN]: utils.getPublicApiToken(),
      [constants.default.SOCKET_CLI_SHADOW_BIN]: binName,
      [constants.default.SOCKET_CLI_SHADOW_PROGRESS]: progressArg,
      ...ipc
    }
  });
  return {
    spawnPromise
  };
}

async function shadowNpmBin(args = process.argv.slice(2), options, extra) {
  return await shadowNpmBase(constants.NPM, args, options, extra);
}

exports.ensureIpcInStdio = ensureIpcInStdio;
exports.shadowNpmBase = shadowNpmBase;
exports.shadowNpmBin = shadowNpmBin;
//# debugId=48432eab-a3e8-4d4e-af91-b2723ed5fbdd
//# sourceMappingURL=shadow-npm-bin2.js.map
