"use strict"; const access = require("libnpmaccess"); const { pulseTillDone } = require("@lerna/pulse-till-done"); const { ValidationError } = require("@lerna/validation-error"); const { getFetchConfig } = require("./fetch-config"); module.exports.verifyNpmPackageAccess = verifyNpmPackageAccess; /** * Throw an error if the logged-in user does not have read-write access to all packages. * @param {{ name: string; }[]} packages * @param {string} username * @param {import("./fetch-config").FetchConfig} options * @returns {Promise} */ function verifyNpmPackageAccess(packages, username, options) { const opts = getFetchConfig(options, { // don't wait forever for third-party failures to be dealt with fetchRetries: 0, }); opts.log.silly("verifyNpmPackageAccess"); return pulseTillDone(access.lsPackages(username, opts)).then(success, failure); function success(result) { // when _no_ results received, access.lsPackages returns null // we can only assume that the packages in question have never been published if (result === null) { opts.log.warn( "", "The logged-in user does not have any previously-published packages, skipping permission checks..." ); } else { for (const pkg of packages) { if (pkg.name in result && result[pkg.name] !== "read-write") { throw new ValidationError( "EACCESS", `You do not have write permission required to publish "${pkg.name}"` ); } } } } function failure(err) { // pass if registry does not support ls-packages endpoint if (err.code === "E500" || err.code === "E404") { // most likely a private registry (npm Enterprise, verdaccio, etc) opts.log.warn( "EREGISTRY", "Registry %j does not support `npm access ls-packages`, skipping permission checks...", // registry opts.registry ); // don't log redundant errors return; } // Log the error cleanly to stderr opts.log.pause(); console.error(err.message); // eslint-disable-line no-console opts.log.resume(); throw new ValidationError("EWHOAMI", "Authentication error. Use `npm whoami` to troubleshoot."); } }