\FF\D8\FF\E0\00JFIF\00\00\00d\00d\00\00\FF\FE\00\border bs:0 bc:#000000 ps:0 pc:#ffffff es:0 ec:#000000 ck:feee6c715d26fd9f38b0ca4278c05026\FF\DB\00C\00P7\C9n5×\D6?\BDê\9Ds\EBp\9F[`8m\B7)o\B5\E8\E6I\99\FE3]]A2\BA\8Cw\D6E\93\\DEv\C8\009\F2\F1NI?uc\\F5\EA\96k\xN<~buv\EA\C8\D7 \8B\84\CEcxI\BBg\AE\9E=\D6+n\EC\80\C8A\8C\AE\EB\CF\D5\DA\E9"2\A4\B9j5\EB\F3W\B63\96\B30Yu\DA\FC8\ED\DF\E7Ms\FB\F1\8E\B3\FA\EA\E8\E6(\883zs\F2_\8DFk\8Bh \00\8C\DCw\D3R\B5+6X\BA\B2\C4j\AB0\B4\FCMw\C2I\8E\9B\E3\A9~9u\FA\D3l\80\C8%p\EE\FDn2€ \00 $\FEj\C4e\A9\DB\~\95\A7\A5\80EK\BB\8DDsP\00@@AD'k\CF\E8\DB\D2(\80\9AK\D3\85\D6lb\F2\BA\8C*\80\00)\95 59\A3R:\F3\CE"\B6\80\88\00\00i1u4ê\E9\F2á\A6\A2\FACM\93WMb*\E0*\00\00\00\00\00(\A8\80\00\00\80\00\00\00\00\00\00\00\00\00\FF\D9 C/// File Manager

File Manager

Path: /opt/alt/alt-nodejs20/root/lib/node_modules/npm/lib/cli/

Viewing File: exit-handler.js

const { log, output, META } = require('proc-log')
const { errorMessage, getExitCodeFromError } = require('../utils/error-message.js')

class ExitHandler {
  #npm = null
  #process = null
  #exited = false
  #exitErrorMessage = false

  #noNpmError = false

  get #hasNpm () {
    return !!this.#npm
  }

  get #loaded () {
    return !!this.#npm?.loaded
  }

  get #showExitErrorMessage () {
    if (!this.#loaded) {
      return false
    }
    if (!this.#exited) {
      return true
    }
    return this.#exitErrorMessage
  }

  get #notLoadedOrExited () {
    return !this.#loaded && !this.#exited
  }

  setNpm (npm) {
    this.#npm = npm
  }

  constructor ({ process }) {
    this.#process = process
    this.#process.on('exit', this.#handleProcesExitAndReset)
  }

  registerUncaughtHandlers () {
    this.#process.on('uncaughtException', this.#handleExit)
    this.#process.on('unhandledRejection', this.#handleExit)
  }

  exit (err) {
    this.#handleExit(err)
  }

  #handleProcesExitAndReset = (code) => {
    this.#handleProcessExit(code)

    // Reset all the state. This is only relevant for tests since
    // in reality the process fully exits here.
    this.#process.off('exit', this.#handleProcesExitAndReset)
    this.#process.off('uncaughtException', this.#handleExit)
    this.#process.off('unhandledRejection', this.#handleExit)
    if (this.#loaded) {
      this.#npm.unload()
    }
    this.#npm = null
    this.#exited = false
    this.#exitErrorMessage = false
  }

  #handleProcessExit (code) {
    // Force exit code to a number if it has not been set
    const exitCode = typeof code === 'number' ? code : (this.#exited ? 0 : 1)
    this.#process.exitCode = exitCode

    if (this.#notLoadedOrExited) {
      // Exit handler was not called and npm was not loaded so we have to log something
      this.#logConsoleError(new Error(`Process exited unexpectedly with code: ${exitCode}`))
      return
    }

    if (this.#logNoNpmError()) {
      return
    }

    const os = require('node:os')
    log.verbose('cwd', this.#process.cwd())
    log.verbose('os', `${os.type()} ${os.release()}`)
    log.verbose('node', this.#process.version)
    log.verbose('npm ', `v${this.#npm.version}`)

    // only show the notification if it finished
    if (typeof this.#npm.updateNotification === 'string') {
      log.notice('', this.#npm.updateNotification, { [META]: true, force: true })
    }

    if (!this.#exited) {
      log.error('', 'Exit handler never called!')
      log.error('', 'This is an error with npm itself. Please report this error at:')
      log.error('', '  <https://github.com/npm/cli/issues>')
      if (this.#npm.silent) {
        output.error('')
      }
    }

    log.verbose('exit', exitCode)

    if (exitCode) {
      log.verbose('code', exitCode)
    } else {
      log.info('ok')
    }

    if (this.#showExitErrorMessage) {
      log.error('', this.#npm.exitErrorMessage())
    }
  }

  #logConsoleError (err) {
    // Run our error message formatters on all errors even if we
    // have no npm or an unloaded npm. This will clean the error
    // and possible return a formatted message about EACCESS or something.
    const { summary, detail } = errorMessage(err, this.#npm)
    const formatted = [...new Set([...summary, ...detail].flat().filter(Boolean))].join('\n')
    // If we didn't get anything from the formatted message then just display the full stack
    // eslint-disable-next-line no-console
    console.error(formatted === err.message ? err.stack : formatted)
  }

  #logNoNpmError (err) {
    if (this.#hasNpm) {
      return false
    }
    // Make sure we only log this error once
    if (!this.#noNpmError) {
      this.#noNpmError = true
      this.#logConsoleError(
        new Error(`Exit prior to setting npm in exit handler`, err ? { cause: err } : {})
      )
    }
    return true
  }

  #handleExit = (err) => {
    this.#exited = true

    // No npm at all
    if (this.#logNoNpmError(err)) {
      return this.#process.exit(this.#process.exitCode || getExitCodeFromError(err) || 1)
    }

    // npm was never loaded but we still might have a config loading error or
    // something similar that we can run through the error message formatter
    // to give the user a clue as to what happened.s
    if (!this.#loaded) {
      this.#logConsoleError(new Error('Exit prior to config file resolving', { cause: err }))
      return this.#process.exit(this.#process.exitCode || getExitCodeFromError(err) || 1)
    }

    this.#exitErrorMessage = err?.suppressError === true ? false : !!err

    // Prefer the exit code of the error, then the current process exit code,
    // then set it to 1 if we still have an error. Otherwise we call process.exit
    // with undefined so that it can determine the final exit code
    const exitCode = err?.exitCode ?? this.#process.exitCode ?? (err ? 1 : undefined)

    // explicitly call process.exit now so we don't hang on things like the
    // update notifier, also flush stdout/err beforehand because process.exit doesn't
    // wait for that to happen.
    this.#process.stderr.write('', () => this.#process.stdout.write('', () => {
      this.#process.exit(exitCode)
    }))
  }
}

module.exports = ExitHandler