From d7d371745a05b710b2385ca3f4985501ab75eaa5 Mon Sep 17 00:00:00 2001 From: Ron Ilan Date: Fri, 25 Apr 2025 09:24:47 -0700 Subject: [PATCH 1/9] Fixed errors that were created when a three year old pull request (#652) was rebased over multiple configuration changes. --- lib/mock/http.js | 4 ++-- lib/mock/s3.js | 3 +-- package-lock.json | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/mock/http.js b/lib/mock/http.js index eb2fd09b7..b5625d8b3 100644 --- a/lib/mock/http.js +++ b/lib/mock/http.js @@ -7,8 +7,7 @@ const path = require('path'); const nock = require('nock'); const os = require('os'); -const log = require('npmlog'); -log.disableProgress(); // disable the display of a progress bar +const log = require('../util/log.js'); log.heading = 'node-pre-gyp'; // differentiate node-pre-gyp's logs from npm's function http_mock() { @@ -17,6 +16,7 @@ function http_mock() { const basePath = `${os.tmpdir()}/mock`; nock(new RegExp('([a-z0-9]+[.])*s3[.]us-east-1[.]amazonaws[.]com')) + .persist() .get(() => true) //a function that always returns true is a catch all for nock .reply( (uri) => { diff --git a/lib/mock/s3.js b/lib/mock/s3.js index 076b995be..e485e3bdb 100644 --- a/lib/mock/s3.js +++ b/lib/mock/s3.js @@ -5,8 +5,7 @@ module.exports = exports = s3_mock; const AWSMock = require('mock-aws-s3'); const os = require('os'); -const log = require('npmlog'); -log.disableProgress(); // disable the display of a progress bar +const log = require('../util/log.js'); log.heading = 'node-pre-gyp'; // differentiate node-pre-gyp's logs from npm's function s3_mock() { diff --git a/package-lock.json b/package-lock.json index 6515d46f2..43cf6bd86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,7 @@ "node-addon-api": "^8.1.0", "nyc": "^17.0.0", "tape": "^5.5.2", - "tar-fs": "^3.0.6" + "tar-fs": "^3.0.8" }, "engines": { "node": ">=18" From 29f00fd6f053362f14194d60417cab8eb592a85e Mon Sep 17 00:00:00 2001 From: Ron Ilan Date: Tue, 10 May 2022 12:33:54 -0700 Subject: [PATCH 2/9] Added service script to switch test apps bucket from mock to S3 and vis versa. Removed previous one. Fix CodeQL errors. --- lib/mock/http.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/mock/http.js b/lib/mock/http.js index b5625d8b3..423fe1eee 100644 --- a/lib/mock/http.js +++ b/lib/mock/http.js @@ -16,7 +16,6 @@ function http_mock() { const basePath = `${os.tmpdir()}/mock`; nock(new RegExp('([a-z0-9]+[.])*s3[.]us-east-1[.]amazonaws[.]com')) - .persist() .get(() => true) //a function that always returns true is a catch all for nock .reply( (uri) => { From 428cbae6549f5ee70baef562ade8eca99ecd4212 Mon Sep 17 00:00:00 2001 From: Ron Ilan Date: Thu, 12 May 2022 12:00:05 -0700 Subject: [PATCH 3/9] Created GitHub Actions Test Setup - Added a GitHub Actions workflow that runs whenever there is a push to the repo. - Workflow includes two jobs: - A matrix job of node versions (10, 12, 14, 16, 18) and operating systems (Linux (ubuntu), Mac and Windows (2019 Enterprise)) that runs all tests against mock and then runs s3 tests against a bucket (located at us-east-1-bucket) specified as a repo secret. - A matrix job of and NW.js versions (0.64.0, 0.50.2) and node versions (10, 12, ,14, 16) that runs the NW.js test script. --- .github/workflows/push.yml | 74 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 .github/workflows/push.yml diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 000000000..c0d9396bb --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,74 @@ +name: Push - Matrix Tests + +on: + push: + workflow_dispatch: + +jobs: + test-on-os-node-matrix: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-2019] # due to node-gyp & node compatibility issues, windows 2022 won't work for all node versions + node: [10, 12, 14, 16, 18] + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + S3_BUCKET: ${{ secrets.S3_BUCKET }} + + name: Test Node ${{ matrix.node }} on ${{ matrix.os }} + + steps: + - name: Checkout ${{ github.ref }} + uses: actions/checkout@v2 + + - name: Setup node ${{ matrix.node }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node }} + + - name: NPM Install + run: npm install + + - name: Configure Windows 2019 + run: | + echo "/c/Program Files/Microsoft Visual Studio/2019/Enterprise/MSBuild/Current/Bin/" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + npm config set msvs_version 2019 + if: ${{ matrix.os == 'windows-2019' }} + + - name: Show Environment Info + run: | + printenv + node --version + npm --version + + - name: Run All Tests (against mock) + run: npm test + env: + node_pre_gyp_mock_s3 : true + + - name: Run S3 Tests (against ${{ env.S3_BUCKET }} bucket) + run: | + npm run bucket ${{ env.S3_BUCKET }} + npm run test:s3 + if: ${{ env.S3_BUCKET != '' }} + + test-nw: + runs-on: ubuntu-18.04 # at current config the nw test requires python 2 as default. hence use older linux version + strategy: + matrix: + node: [10, 12, 14, 16] # node 18 requires glibc GLIBC_2.28 not available on older version of linux + nw: [0.64.0, 0.50.2] # current version as of may 2022 and the one tested before introduction of this action. + name: NW.js ${{ matrix.nw }} on Node ${{ matrix.node }} + + steps: + - name: Checkout ${{ github.ref }} + uses: actions/checkout@v2 + + - name: Setup node ${{ matrix.node }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node }} + + - name: Run Script + run: ./scripts/test-node-webkit.sh ${{ matrix.nw }} From 4d6e9ccb43a462dd7c4822679f80bfeb72ba1d9a Mon Sep 17 00:00:00 2001 From: Ron Ilan Date: Fri, 28 Jun 2024 20:28:28 -0700 Subject: [PATCH 4/9] Updated github actions to only test node 18, 20, 22. --- .github/workflows/push.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index c0d9396bb..ad66f7e01 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -10,7 +10,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-2019] # due to node-gyp & node compatibility issues, windows 2022 won't work for all node versions - node: [10, 12, 14, 16, 18] + node: [18, 20, 22] env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} @@ -57,7 +57,7 @@ jobs: runs-on: ubuntu-18.04 # at current config the nw test requires python 2 as default. hence use older linux version strategy: matrix: - node: [10, 12, 14, 16] # node 18 requires glibc GLIBC_2.28 not available on older version of linux + node: [18, 20, 22] nw: [0.64.0, 0.50.2] # current version as of may 2022 and the one tested before introduction of this action. name: NW.js ${{ matrix.nw }} on Node ${{ matrix.node }} From 4807a7618032a427ba6695a95c9dd4c88bce191d Mon Sep 17 00:00:00 2001 From: Ron Ilan Date: Fri, 28 Jun 2024 20:31:31 -0700 Subject: [PATCH 5/9] Trying windows-latest --- .github/workflows/push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index ad66f7e01..5870f2fcf 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -9,7 +9,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-2019] # due to node-gyp & node compatibility issues, windows 2022 won't work for all node versions + os: [ubuntu-latest, macos-latest, windows-latest] # due to node-gyp & node compatibility issues, windows 2022 won't work for all node versions node: [18, 20, 22] env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} From d26a6a5d8183433711aa0c3269cce738c1601ddf Mon Sep 17 00:00:00 2001 From: Ron Ilan Date: Fri, 28 Jun 2024 23:31:57 -0700 Subject: [PATCH 6/9] Removed nw tests from GitHub push actions as they are not working right now. --- .github/workflows/push.yml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 5870f2fcf..27e8e4336 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -53,22 +53,3 @@ jobs: npm run test:s3 if: ${{ env.S3_BUCKET != '' }} - test-nw: - runs-on: ubuntu-18.04 # at current config the nw test requires python 2 as default. hence use older linux version - strategy: - matrix: - node: [18, 20, 22] - nw: [0.64.0, 0.50.2] # current version as of may 2022 and the one tested before introduction of this action. - name: NW.js ${{ matrix.nw }} on Node ${{ matrix.node }} - - steps: - - name: Checkout ${{ github.ref }} - uses: actions/checkout@v2 - - - name: Setup node ${{ matrix.node }} - uses: actions/setup-node@v2 - with: - node-version: ${{ matrix.node }} - - - name: Run Script - run: ./scripts/test-node-webkit.sh ${{ matrix.nw }} From ba5efc05556833be81823396dbc7767a0b1961f9 Mon Sep 17 00:00:00 2001 From: Ron Ilan Date: Sat, 29 Jun 2024 00:35:35 -0700 Subject: [PATCH 7/9] Changed push to bucket only tests. --- .github/workflows/push.yml | 55 -------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 .github/workflows/push.yml diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml deleted file mode 100644 index 27e8e4336..000000000 --- a/.github/workflows/push.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: Push - Matrix Tests - -on: - push: - workflow_dispatch: - -jobs: - test-on-os-node-matrix: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] # due to node-gyp & node compatibility issues, windows 2022 won't work for all node versions - node: [18, 20, 22] - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - S3_BUCKET: ${{ secrets.S3_BUCKET }} - - name: Test Node ${{ matrix.node }} on ${{ matrix.os }} - - steps: - - name: Checkout ${{ github.ref }} - uses: actions/checkout@v2 - - - name: Setup node ${{ matrix.node }} - uses: actions/setup-node@v2 - with: - node-version: ${{ matrix.node }} - - - name: NPM Install - run: npm install - - - name: Configure Windows 2019 - run: | - echo "/c/Program Files/Microsoft Visual Studio/2019/Enterprise/MSBuild/Current/Bin/" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - npm config set msvs_version 2019 - if: ${{ matrix.os == 'windows-2019' }} - - - name: Show Environment Info - run: | - printenv - node --version - npm --version - - - name: Run All Tests (against mock) - run: npm test - env: - node_pre_gyp_mock_s3 : true - - - name: Run S3 Tests (against ${{ env.S3_BUCKET }} bucket) - run: | - npm run bucket ${{ env.S3_BUCKET }} - npm run test:s3 - if: ${{ env.S3_BUCKET != '' }} - From c33ea879cc6b87ca8ea49c25e2dc70979d47bba2 Mon Sep 17 00:00:00 2001 From: Ron Ilan Date: Wed, 18 May 2022 12:56:38 -0700 Subject: [PATCH 8/9] Refactor PR 533 and Fix issue 653 - Moved logic regarding host selection to versioning where all user defined values from package.json are transformed into command options. - Moved testing of feature from `run.test.js` to `versioning.test.js`. - Added `development_host` option. Becomes default option for `publish` `unpublish` when present. - Changed behavior when alternate hosts are defined. Now `production_host` acts as alias to host. Defining `staging_host` or `development_host` is enough to default `publish` and `unpublish` away from production. - When a chain of commands that includes `publish` or `unpublish`, when host not specifically set via command line or environment variable, ALL commands in the chain default away from production. - An invalid `s3_host` option does not result in error and is instead silently ignored. - Change is backwards compatible with previously valid configurations. --- lib/main.js | 6 - lib/mock/http.js | 1 + lib/node-pre-gyp.js | 66 +--- lib/pre-binding.js | 1 - lib/util/versioning.js | 83 +++-- test/run.test.js | 141 +-------- test/versioning.test.js | 652 +++++++++++++++++++++++++++++++++++++++- 7 files changed, 709 insertions(+), 241 deletions(-) diff --git a/lib/main.js b/lib/main.js index f46ea3299..264e3a8b6 100644 --- a/lib/main.js +++ b/lib/main.js @@ -72,12 +72,6 @@ function run() { return; } - // set binary.host when appropriate. host determines the s3 target bucket. - const target = prog.setBinaryHostProperty(command.name); - if (target && ['install', 'publish', 'unpublish', 'info'].indexOf(command.name) >= 0) { - log.info('using binary.host: ' + prog.package_json.binary.host); - } - prog.commands[command.name](command.args, function(err) { if (err) { log.error(command.name + ' error'); diff --git a/lib/mock/http.js b/lib/mock/http.js index 423fe1eee..b5625d8b3 100644 --- a/lib/mock/http.js +++ b/lib/mock/http.js @@ -16,6 +16,7 @@ function http_mock() { const basePath = `${os.tmpdir()}/mock`; nock(new RegExp('([a-z0-9]+[.])*s3[.]us-east-1[.]amazonaws[.]com')) + .persist() .get(() => true) //a function that always returns true is a catch all for nock .reply( (uri) => { diff --git a/lib/node-pre-gyp.js b/lib/node-pre-gyp.js index 26c0e5125..aefb65ba7 100644 --- a/lib/node-pre-gyp.js +++ b/lib/node-pre-gyp.js @@ -73,11 +73,8 @@ function Run({ package_json_path = './package.json', argv }) { }); this.parseArgv(argv); - - // this is set to true after the binary.host property was set to - // either staging_host or production_host. - this.binaryHostSet = false; } + inherits(Run, EE); exports.Run = Run; const proto = Run.prototype; @@ -201,67 +198,6 @@ proto.parseArgv = function parseOpts(argv) { log.resume(); }; -/** - * allow the binary.host property to be set at execution time. - * - * for this to take effect requires all the following to be true. - * - binary is a property in package.json - * - binary.host is falsey - * - binary.staging_host is not empty - * - binary.production_host is not empty - * - * if any of the previous checks fail then the function returns an empty string - * and makes no changes to package.json's binary property. - * - * - * if command is "publish" then the default is set to "binary.staging_host" - * if command is not "publish" the the default is set to "binary.production_host" - * - * if the command-line option '--s3_host' is set to "staging" or "production" then - * "binary.host" is set to the specified "staging_host" or "production_host". if - * '--s3_host' is any other value an exception is thrown. - * - * if '--s3_host' is not present then "binary.host" is set to the default as above. - * - * this strategy was chosen so that any command other than "publish" or "unpublish" uses "production" - * as the default without requiring any command-line options but that "publish" and "unpublish" require - * '--s3_host production_host' to be specified in order to *really* publish (or unpublish). publishing - * to staging can be done freely without worrying about disturbing any production releases. - */ -proto.setBinaryHostProperty = function(command) { - if (this.binaryHostSet) { - return this.package_json.binary.host; - } - const p = this.package_json; - // don't set anything if host is present. it must be left blank to trigger this. - if (!p || !p.binary || p.binary.host) { - return ''; - } - // and both staging and production must be present. errors will be reported later. - if (!p.binary.staging_host || !p.binary.production_host) { - return ''; - } - let target = 'production_host'; - if (command === 'publish' || command === 'unpublish') { - target = 'staging_host'; - } - // the environment variable has priority over the default or the command line. if - // either the env var or the command line option are invalid throw an error. - const npg_s3_host = process.env.node_pre_gyp_s3_host; - if (npg_s3_host === 'staging' || npg_s3_host === 'production') { - target = `${npg_s3_host}_host`; - } else if (this.opts['s3_host'] === 'staging' || this.opts['s3_host'] === 'production') { - target = `${this.opts['s3_host']}_host`; - } else if (this.opts['s3_host'] || npg_s3_host) { - throw new Error(`invalid s3_host ${this.opts['s3_host'] || npg_s3_host}`); - } - - p.binary.host = p.binary[target]; - this.binaryHostSet = true; - - return p.binary.host; -}; - /** * Returns the usage instructions for node-pre-gyp. */ diff --git a/lib/pre-binding.js b/lib/pre-binding.js index e110fe381..9fd4407fa 100644 --- a/lib/pre-binding.js +++ b/lib/pre-binding.js @@ -19,7 +19,6 @@ exports.find = function(package_json_path, opts) { throw new Error(package_json_path + 'does not exist'); } const prog = new npg.Run({ package_json_path, argv: process.argv }); - prog.setBinaryHostProperty(); const package_json = prog.package_json; versioning.validate_config(package_json, opts); diff --git a/lib/util/versioning.js b/lib/util/versioning.js index b65e84e7d..ad3048cee 100644 --- a/lib/util/versioning.js +++ b/lib/util/versioning.js @@ -186,12 +186,6 @@ function get_runtime_abi(runtime, target_version) { } module.exports.get_runtime_abi = get_runtime_abi; -const required_parameters = [ - 'module_name', - 'module_path', - 'host' -]; - function validate_config(package_json, opts) { const msg = package_json.name + ' package.json is not node-pre-gyp ready:\n'; const missing = []; @@ -207,25 +201,33 @@ function validate_config(package_json, opts) { if (!package_json.binary) { missing.push('binary'); } - const o = package_json.binary; - if (o) { - required_parameters.forEach((p) => { - if (!o[p] || typeof o[p] !== 'string') { - missing.push('binary.' + p); - } - }); + + if (package_json.binary) { + if (!package_json.binary.module_name) { + missing.push('binary.module_name'); + } + if (!package_json.binary.module_path) { + missing.push('binary.module_path'); + } + if (!package_json.binary.host && !package_json.binary.production_host) { + missing.push('binary.host'); + } } if (missing.length >= 1) { throw new Error(msg + 'package.json must declare these properties: \n' + missing.join('\n')); } - if (o) { - // enforce https over http - const protocol = url.parse(o.host).protocol; - if (protocol === 'http:') { - throw new Error("'host' protocol (" + protocol + ") is invalid - only 'https:' is accepted"); - } + + if (package_json.binary) { + // for all possible host definitions - verify https usage + ['host', 'production_host', 'staging_host', 'development_host'].filter((item) => package_json.binary[item]).forEach((item) => { + const protocol = url.parse(package_json.binary[item]).protocol; + if (protocol === 'http:') { + throw new Error(msg + "'" + item + "' protocol (" + protocol + ") is invalid - only 'https:' is accepted"); + } + }); } + napi.validate_package_json(package_json, opts); } @@ -309,11 +311,46 @@ module.exports.evaluate = function(package_json, options, napi_build_version) { region: package_json.binary.region, s3ForcePathStyle: package_json.binary.s3ForcePathStyle || false }; - // support host mirror with npm config `--{module_name}_binary_host_mirror` - // e.g.: https://github.com/node-inspector/v8-profiler/blob/master/package.json#L25 - // > npm install v8-profiler --profiler_binary_host_mirror=https://registry.npmmirror.com/node-inspector/ + + // user can define a target host key to use (development_host, staging_host, production_host) + // by setting the name of the host (development, staging, production) + // into an environment variable or via a command line option. + // the environment variable has priority over the the command line. + let targetHost = process.env.node_pre_gyp_s3_host || options.s3_host; + + // if value is not one of the allowed or the matching key is not found in package.json + // silently ignore the option + if (['production', 'staging', 'development'].indexOf(targetHost) === -1 || !package_json.binary[`${targetHost}_host`]) { + targetHost = ''; + } + + // the production host is as specified in 'host' key (default) + // unless there is none and alias production_host is specified (backwards compatibility) + // note: package.json is verified in validate_config to include at least one of the two. + let host = package_json.binary.host || package_json.binary.production_host; + + // when a valid target is specified by user, the host is from that target (or 'host') + if (targetHost === 'staging') { + host = package_json.binary.staging_host; + } else if (targetHost === 'development') { + host = package_json.binary.development_host; + } else if (!targetHost && (package_json.binary.development_host || package_json.binary.staging_host)) { + // when host not specifically set via command line or environment variable + // but staging and/or development host are present in package.json + // for any command (or command chain) that includes publish or unpublish + // default to lower host (development, and if not preset, staging). + if (options.argv && options.argv.remain.some((item) => (item === 'publish' || item === 'unpublish'))) { + host = package_json.binary.development_host || package_json.binary.staging_host; + } + } + + // support host mirror with npm config `--{module_name}_binary_host_mirror` + // e.g.: https://github.com/node-inspector/v8-profiler/blob/master/package.json#L25 + // > npm install v8-profiler --profiler_binary_host_mirror=https://npm.taobao.org/mirrors/node-inspector/ const validModuleName = opts.module_name.replace('-', '_'); - const host = process.env['npm_config_' + validModuleName + '_binary_host_mirror'] || package_json.binary.host; + // explicitly set mirror overrides everything set above + host = process.env['npm_config_' + validModuleName + '_binary_host_mirror'] || host; + opts.host = fix_slashes(eval_template(host, opts)); opts.module_path = eval_template(package_json.binary.module_path, opts); // now we resolve the module_path to ensure it is absolute so that binding.gyp variables work predictably diff --git a/test/run.test.js b/test/run.test.js index c45e900f8..e121df471 100644 --- a/test/run.test.js +++ b/test/run.test.js @@ -28,10 +28,6 @@ const package_json_template = { } }; - -const all_commands = ['build', 'clean', 'configure', 'info', 'install', 'package', 'publish', 'rebuild', - 'reinstall', 'reveal', 'testbinary', 'testpackage', 'unpublish']; - /** * before testing create a scratch directory to run tests in. */ @@ -67,82 +63,6 @@ test.onFinish(() => { rimraf(scratch).then(() => undefined, () => undefined); }); -test('should set staging and production hosts', (t) => { - // make sure it's good when specifying host. - const mock_package_json = makePackageJson(); - - let { prog } = setupTest(dir, mock_package_json); - t.deepEqual(prog.package_json, mock_package_json); - t.equal(prog.binaryHostSet, false, 'binary host should not be flagged as set'); - - // test with no s3_host option - all_commands.forEach((cmd) => { - const mpj = clone(mock_package_json); - mpj.binary.host = ''; - const opts = { argv: [cmd] }; - ({ prog } = setupTest(dir, mpj, opts)); - mpj.binary.host = (cmd === 'publish' || cmd === 'unpublish') ? mpj.binary.staging_host : mpj.binary.production_host; - t.deepEqual(prog.package_json, mpj, 'host should be correct for command: ' + cmd); - t.equal(prog.binaryHostSet, true, 'binary host should be flagged as set'); - }); - - // test with s3_host set to staging - all_commands.forEach((cmd) => { - const mpj = clone(mock_package_json); - mpj.binary.host = ''; - const opts = { argv: [cmd, '--s3_host=staging'] }; - ({ prog } = setupTest(dir, mpj, opts)); - mpj.binary.host = mpj.binary.staging_host; - t.deepEqual(prog.package_json, mpj, 'host should be correct for command: ' + cmd); - t.equal(prog.binaryHostSet, true, 'binary host should be flagged as set'); - }); - - // test with s3_host set to production - all_commands.forEach((cmd) => { - const mpj = clone(mock_package_json); - mpj.binary.host = ''; - const opts = { argv: [cmd, '--s3_host=production'] }; - ({ prog } = setupTest(dir, mpj, opts)); - mpj.binary.host = mpj.binary.production_host; - t.deepEqual(prog.package_json, mpj, 'host should be correct for command: ' + cmd); - t.equal(prog.binaryHostSet, true, 'binary host should be flagged as set'); - }); - - t.end(); -}); - -test('should execute setBinaryHostProperty() properly', (t) => { - // it only --s3_host only takes effect if host is falsey. - const mock_package_json = makePackageJson({ binary: { host: '' } }); - - const opts = { argv: ['publish', '--s3_host=staging'] }; - - let { prog, binaryHost } = setupTest(dir, mock_package_json, opts); - t.equal(binaryHost, mock_package_json.binary.staging_host); - - // set it again to verify that it returns the already set value - binaryHost = prog.setBinaryHostProperty('publish'); - t.equal(binaryHost, mock_package_json.binary.staging_host); - - // now do this again but expect an empty binary host value because - // staging_host is missing. - const mpj = clone(mock_package_json); - delete mpj.binary.staging_host; - ({ prog, binaryHost } = setupTest(dir, mpj, opts)); - t.equal(binaryHost, ''); - - // one more time but with an invalid value for s3_host - opts.argv = ['publish', '--s3_host=bad-news']; - try { - ({ prog, binaryHost } = setupTest(dir, mock_package_json, opts)); - t.fail('should throw with --s3_host=bad-news'); - } catch (e) { - t.equal(e.message, 'invalid s3_host bad-news'); - } - - t.end(); -}); - test('verify that the --directory option works', (t) => { const initial = process.cwd(); @@ -223,6 +143,10 @@ test('verify that a non-existent package.json fails', (t) => { // test helpers. // +// helper to clone mock package.json. +// // https://stackoverflow.com/questions/4459928/how-to-deep-clone-in-javascript +const clone = (obj) => JSON.parse(JSON.stringify(obj)); + function makePackageJson(options = {}) { const package_json = clone(package_json_template); // override binary values if supplied @@ -233,60 +157,3 @@ function makePackageJson(options = {}) { } return package_json; } - -// helper to write package.json to disk so Run() can be instantiated with it. -function setupTest(directory, package_json, opts) { - opts = opts || {}; - let argv = ['node', 'program']; - if (opts.argv) { - argv = argv.concat(opts.argv); - } - const prev_dir = process.cwd(); - if (!opts.noChdir) { - try { - fs.mkdirSync(directory); - } catch (e) { - if (e.code !== 'EEXIST') { - throw e; - } - } - process.chdir(directory); - } - - try { - fs.writeFileSync('package.json', JSON.stringify(package_json)); - const prog = new npg.Run({ package_json_path: './package.json', argv }); - const binaryHost = prog.setBinaryHostProperty(prog.todo[0] && prog.todo[0].name); - return { prog, binaryHost }; - } finally { - process.chdir(prev_dir); - } -} - -// helper to clone mock package.json. it's overkill for existing tests -// but is future-proof. -// https://stackoverflow.com/questions/4459928/how-to-deep-clone-in-javascript -function clone(obj, hash = new WeakMap()) { - if (Object(obj) !== obj) return obj; // primitives - if (hash.has(obj)) return hash.get(obj); // cyclic reference - let result; - - if (obj instanceof Set) { - result = new Set(obj); // treat set as a value - } else if (obj instanceof Map) { - result = new Map(Array.from(obj, ([key, val]) => [key, clone(val, hash)])); - } else if (obj instanceof Date) { - result = new Date(obj); - } else if (obj instanceof RegExp) { - result = new RegExp(obj.source, obj.flags); - } else if (obj.constructor) { - result = new obj.constructor(); - } else { - result = Object.create(null); - } - hash.set(obj, result); - return Object.assign(result, ...Object.keys(obj).map((key) => { - return { [key]: clone(obj[key], hash) }; - })); -} - diff --git a/test/versioning.test.js b/test/versioning.test.js index 455419998..3ea709a67 100644 --- a/test/versioning.test.js +++ b/test/versioning.test.js @@ -222,6 +222,107 @@ test('should verify that the binary property has required properties', (t) => { t.end(); }); +test('should allow production_host to act as alias to host (when host not preset)', (t) => { + const mock_package_json = { + 'name': 'test', + 'main': 'test.js', + 'version': '0.1.0', + 'binary': { + 'module_name': 'binary-module-name', + 'module_path': 'binary-module-path', + 'production_host': 's3-production-path' + } + }; + + const package_json = Object.assign({}, mock_package_json); + const opts = versioning.evaluate(package_json, { module_root: '/root' }); + t.equal(opts.host, mock_package_json.binary.production_host + '/'); + t.equal(opts.hosted_path, mock_package_json.binary.production_host + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary.production_host + '/' + opts.package_name); + + t.end(); +}); + +test('should use host over production_host (when both are preset)', (t) => { + const mock_package_json = { + 'name': 'test', + 'main': 'test.js', + 'version': '0.1.0', + 'binary': { + 'module_name': 'binary-module-name', + 'module_path': 'binary-module-path', + 'production_host': 's3-production-path', + 'host': 'binary-path' + } + }; + + const package_json = Object.assign({}, mock_package_json); + const opts = versioning.evaluate(package_json, { module_root: '/root' }); + t.equal(opts.host, mock_package_json.binary.host + '/'); + t.equal(opts.hosted_path, mock_package_json.binary.host + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary.host + '/' + opts.package_name); + + t.end(); +}); + +test('should verify that the host url protocol is https', (t) => { + const mock_package_json = { + 'name': 'test', + 'main': 'test.js', + 'version': '0.1.0', + 'binary': { + 'module_name': 'binary-module-name', + 'module_path': 'binary-module-path', + 'host': 'http://your_module.s3-us-west-1.amazonaws.com' + } + }; + + const package_json = Object.assign({}, mock_package_json); + + try { + // eslint-disable-next-line no-unused-vars + const opts = versioning.evaluate(package_json, {}); + } catch (e) { + // name won't be there if it's missing but both messages say 'undefined' + const msg = package_json.name + ' package.json is not node-pre-gyp ready:\n'; + const expectedMessage = msg + '\'host\' protocol (http:) is invalid - only \'https:\' is accepted'; + t.equal(e.message, expectedMessage); + } + + t.end(); +}); + +test('should verify that alternate hosts url protocol is https', (t) => { + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + host: 'https://your_module.s3-us-west-1.amazonaws.com' + } + }; + + const hosts = ['production', 'staging', 'development']; + hosts.forEach((host) => { + const package_json = Object.assign({}, mock_package_json); + package_json[`${host}_host`] = `https://${host}_bucket.s3-us-west-1.amazonaws.com`; + + try { + // eslint-disable-next-line no-unused-vars + const opts = versioning.evaluate(package_json, {}); + } catch (e) { + // name won't be there if it's missing but both messages say 'undefined' + const msg = package_json.name + ' package.json is not node-pre-gyp ready:\n'; + const expectedMessage = msg + `'${host}_host' protocol (http:) is invalid - only 'https:' is accepted`; + t.equal(e.message, expectedMessage); + } + }); + + t.end(); +}); + test('should not add bucket name to hosted_path when s3ForcePathStyle is false', (t) => { const mock_package_json = { 'name': 'test', @@ -266,7 +367,53 @@ test('should add bucket name to hosted_path when s3ForcePathStyle is true', (t) t.end(); }); -test('should verify host overrides staging and production values', (t) => { +test('should use host key by default for install, info, publish and unpublish commands (when no other hosts specified)', (t) => { + const makeOoptions = (cmd) => { + return { + argv: { + remain: [cmd], + cooked: [cmd], + original: [cmd] + } + }; + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + host: 'binary-path' + } + }; + + const cmds = ['install', 'info', 'publish', 'unpublish']; + cmds.forEach((cmd) => { + try { + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd)); + t.equal(opts.host, mock_package_json.binary.host + '/'); + t.equal(opts.hosted_path, mock_package_json.binary.host + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary.host + '/' + opts.package_name); + } catch (e) { + t.ifError(e, 'staging_host and production_host should be silently ignored'); + } + }); + t.end(); +}); + +test('should use production_host as alias for host for install and info commands (when host not preset)', (t) => { + const makeOoptions = (cmd) => { + return { + argv: { + remain: [cmd], + cooked: [cmd], + original: [cmd] + } + }; + }; + const mock_package_json = { name: 'test', main: 'test.js', @@ -274,25 +421,512 @@ test('should verify host overrides staging and production values', (t) => { binary: { module_name: 'binary-module-name', module_path: 'binary-module-path', - host: 'binary-path', - staging_host: 's3-staging-path', production_host: 's3-production-path' } }; - try { - const opts = versioning.evaluate(mock_package_json, { module_root: '/root' }); + const cmds = ['install', 'info']; + cmds.forEach((cmd) => { + + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd)); + t.equal(opts.host, mock_package_json.binary.production_host + '/'); + t.equal(opts.hosted_path, mock_package_json.binary.production_host + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary.production_host + '/' + opts.package_name); + + }); + t.end(); +}); + +test('should use host over production_host for install and info commands (when both are preset)', (t) => { + const makeOoptions = (cmd) => { + return { + argv: { + remain: [cmd], + cooked: [cmd], + original: [cmd] + } + }; + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + production_host: 's3-production-path', + host: 'binary-path' + } + }; + + const cmds = ['install', 'info']; + cmds.forEach((cmd) => { + + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd)); t.equal(opts.host, mock_package_json.binary.host + '/'); t.equal(opts.hosted_path, mock_package_json.binary.host + '/'); t.equal(opts.hosted_tarball, mock_package_json.binary.host + '/' + opts.package_name); - } catch (e) { - t.ifError(e, 'staging_host and production_host should be silently ignored'); - } + }); + t.end(); +}); + +test('should use host by default for install and info commands (overriding alternate hosts, production_host not present)', (t) => { + const options = { + argv: { + remain: ['install', 'info'], + cooked: ['install', 'info'], + original: ['install', 'info'] + } + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + host: 'binary-path', + development_host: 's3-development-path', + staging_host: 's3-staging-path' + } + }; + + + const opts = versioning.evaluate(mock_package_json, options); + t.equal(opts.host, mock_package_json.binary.host + '/'); + t.equal(opts.hosted_path, mock_package_json.binary.host + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary.host + '/' + opts.package_name); + + + t.end(); +}); + +test('should use host by default for install and info commands (overriding alternate hosts, host is present)', (t) => { + const options = { + argv: { + remain: ['install', 'info'], + cooked: ['install', 'info'], + original: ['install', 'info'] + } + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + host: 'binary-path', + development_host: 's3-development-path', + staging_host: 's3-staging-path', + production_host: 's3-production-path' + } + }; + + + const opts = versioning.evaluate(mock_package_json, options); + t.equal(opts.host, mock_package_json.binary.host + '/'); + t.equal(opts.hosted_path, mock_package_json.binary.host + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary.host + '/' + opts.package_name); + + + t.end(); +}); + +test('should use development_host key by default for publish and unpublish commands (when it is specified)', (t) => { + const makeOoptions = (cmd) => { + return { + argv: { + remain: [cmd], + cooked: [cmd], + original: [cmd] + } + }; + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + host: 'binary-path', + development_host: 's3-development-path', + staging_host: 's3-staging-path', + production_host: 's3-production-path' + } + }; + + const cmds = ['publish', 'unpublish']; + cmds.forEach((cmd) => { + + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd)); + t.equal(opts.host, mock_package_json.binary.development_host + '/'); + t.equal(opts.hosted_path, mock_package_json.binary.development_host + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary.development_host + '/' + opts.package_name); + + }); + t.end(); +}); + +test('should use staging_host key by default for publish and unpublish commands (when it is specified and no development_host)', (t) => { + const makeOoptions = (cmd) => { + return { + argv: { + remain: [cmd], + cooked: [cmd], + original: [cmd] + } + }; + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + host: 'binary-path', + staging_host: 's3-staging-path', + production_host: 's3-production-path' + } + }; + + const cmds = ['publish', 'unpublish']; + cmds.forEach((cmd) => { + + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd)); + t.equal(opts.host, mock_package_json.binary.staging_host + '/'); + t.equal(opts.hosted_path, mock_package_json.binary.staging_host + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary.staging_host + '/' + opts.package_name); + + }); + t.end(); +}); + +test('should use development_host key by default for publish and unpublish commands in a chain (when it is specified)', (t) => { + const makeOoptions = (cmd) => { + return { + argv: { + remain: ['info', cmd], + cooked: ['info', cmd], + original: ['info', cmd] + } + }; + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + host: 'binary-path', + development_host: 's3-development-path', + staging_host: 's3-staging-path', + production_host: 's3-production-path' + } + }; + + const cmds = ['publish', 'unpublish']; + cmds.forEach((cmd) => { + + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd)); + t.equal(opts.host, mock_package_json.binary.development_host + '/'); + t.equal(opts.hosted_path, mock_package_json.binary.development_host + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary.development_host + '/' + opts.package_name); + + }); + t.end(); +}); + +test('should use host specified by the --s3_host option', (t) => { + const makeOoptions = (cmd, host) => { + return { + s3_host: host, + argv: { + remain: [cmd], + cooked: [cmd, '--s3_host', host], + original: [cmd, `--s3_host=${host}`] + } + }; + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + // host: 'binary-path', + development_host: 's3-development-path', + staging_host: 's3-staging-path', + production_host: 's3-production-path' + } + }; + + const hosts = ['production', 'staging', 'development']; + const cmds = ['install', 'info', 'publish', 'unpublish']; + + cmds.forEach((cmd) => { + hosts.forEach((host) => { + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd, host)); + t.equal(opts.host, mock_package_json.binary[`${host}_host`] + '/'); + t.equal(opts.hosted_path, mock_package_json.binary[`${host}_host`] + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary[`${host}_host`] + '/' + opts.package_name); + }); + }); + t.end(); +}); + +test('should use defaults when --s3_host option is invalid', (t) => { + const makeOoptions = (cmd) => { + return { + s3_host: 'not-valid', + argv: { + remain: [cmd], + cooked: [cmd, '--s3_host', 'not-valid'], + original: [cmd, '--s3_host=not-valid'] + } + }; + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + host: 'binary-path', + development_host: 's3-development-path', + staging_host: 's3-staging-path', + production_host: 's3-production-path' + } + }; + + const cmds = ['install', 'info', 'publish', 'unpublish']; + + cmds.forEach((cmd) => { + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd)); + const host = cmd.indexOf('publish') === -1 ? 'host' : 'development_host'; + + t.equal(opts.host, mock_package_json.binary[host] + '/'); + t.equal(opts.hosted_path, mock_package_json.binary[host] + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary[host] + '/' + opts.package_name); + + }); + t.end(); +}); + +test('should use host specified by the s3_host environment variable', (t) => { + const makeOoptions = (cmd) => { + return { + argv: { + remain: [cmd], + cooked: [cmd], + original: [cmd] + } + }; + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + // host: 'binary-path', + development_host: 's3-development-path', + staging_host: 's3-staging-path', + production_host: 's3-production-path' + } + }; + + const hosts = ['production', 'staging', 'development']; + const cmds = ['install', 'info', 'publish', 'unpublish']; + + cmds.forEach((cmd) => { + hosts.forEach((host) => { + process.env.node_pre_gyp_s3_host = host; + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd)); + t.equal(opts.host, mock_package_json.binary[`${host}_host`] + '/'); + t.equal(opts.hosted_path, mock_package_json.binary[`${host}_host`] + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary[`${host}_host`] + '/' + opts.package_name); + }); + }); + t.end(); +}); + +test('should use defaults when s3_host environment variable is invalid', (t) => { + const makeOoptions = (cmd) => { + return { + argv: { + remain: [cmd], + cooked: [cmd], + original: [cmd] + } + }; + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + host: 'binary-path', + development_host: 's3-development-path', + staging_host: 's3-staging-path', + production_host: 's3-production-path' + } + }; + + const cmds = ['install', 'info', 'publish', 'unpublish']; + + cmds.forEach((cmd) => { + process.env.node_pre_gyp_s3_host = 'not-valid'; + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd)); + const host = cmd.indexOf('publish') === -1 ? 'host' : 'development_host'; + + t.equal(opts.host, mock_package_json.binary[host] + '/'); + t.equal(opts.hosted_path, mock_package_json.binary[host] + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary[host] + '/' + opts.package_name); + + }); + t.end(); +}); + +test('should use defaults when s3_host environment is valid but package.json does not match (production_host is default)', (t) => { + const makeOoptions = (cmd) => { + return { + argv: { + remain: [cmd], + cooked: [cmd], + original: [cmd] + } + }; + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + // no development_host + staging_host: 's3-staging-path', + // production_host not host + production_host: 's3-production-path' + } + }; + + const cmds = ['install', 'info', 'publish', 'unpublish']; + + cmds.forEach((cmd) => { + process.env.node_pre_gyp_s3_host = 'development'; // specify development_host + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd)); + const host = cmd.indexOf('publish') === -1 ? 'production_host' : 'staging_host'; // defaults + + t.equal(opts.host, mock_package_json.binary[host] + '/'); + t.equal(opts.hosted_path, mock_package_json.binary[host] + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary[host] + '/' + opts.package_name); + + }); + t.end(); +}); + +test('should use defaults when s3_host environment is valid but package.json does not match (host is default)', (t) => { + const makeOoptions = (cmd) => { + return { + argv: { + remain: [cmd], + cooked: [cmd], + original: [cmd] + } + }; + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + // host not production_host + host: 'binary-path', + // no development_host + staging_host: 's3-staging-path' + } + }; + + const cmds = ['install', 'info', 'publish', 'unpublish']; + + cmds.forEach((cmd) => { + process.env.node_pre_gyp_s3_host = 'development'; // specify development_host + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd)); + const host = cmd.indexOf('publish') === -1 ? 'host' : 'staging_host'; // defaults + + t.equal(opts.host, mock_package_json.binary[host] + '/'); + t.equal(opts.hosted_path, mock_package_json.binary[host] + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary[host] + '/' + opts.package_name); + + }); + t.end(); +}); + +test('should use host specified by environment variable overriding --s3_host option', (t) => { + const makeOoptions = (cmd) => { + return { + s3_host: 'staging', // from command line + argv: { + remain: [cmd], + cooked: [cmd, '--s3_host', 'staging'], + original: [cmd, '--s3_host=staging'] + } + }; + }; + + const mock_package_json = { + name: 'test', + main: 'test.js', + version: '0.1.0', + binary: { + module_name: 'binary-module-name', + module_path: 'binary-module-path', + // host: 'binary-path', + development_host: 's3-development-path', + staging_host: 's3-staging-path', + production_host: 's3-production-path' + } + }; + + + const cmds = ['install', 'info', 'publish', 'unpublish']; + cmds.forEach((cmd) => { + process.env.node_pre_gyp_s3_host = 'production'; + const opts = versioning.evaluate(mock_package_json, makeOoptions(cmd)); + t.equal(opts.host, mock_package_json.binary.production_host + '/'); + t.equal(opts.hosted_path, mock_package_json.binary.production_host + '/'); + t.equal(opts.hosted_tarball, mock_package_json.binary.production_host + '/' + opts.package_name); + + }); t.end(); }); -test('should replace "-" with "_" in custom binary host', (t) => { +test('should replace "-" with "_" in mirror binary host', (t) => { const mock_package_json = { name: 'test', main: 'test.js', From 7d55567a69f6f690f86435a0d154741ee38ae2a5 Mon Sep 17 00:00:00 2001 From: Ron Ilan Date: Thu, 24 Apr 2025 22:28:45 -0700 Subject: [PATCH 9/9] Update comment to resolve confilct. --- lib/util/versioning.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util/versioning.js b/lib/util/versioning.js index ad3048cee..af700bc8f 100644 --- a/lib/util/versioning.js +++ b/lib/util/versioning.js @@ -346,7 +346,7 @@ module.exports.evaluate = function(package_json, options, napi_build_version) { // support host mirror with npm config `--{module_name}_binary_host_mirror` // e.g.: https://github.com/node-inspector/v8-profiler/blob/master/package.json#L25 - // > npm install v8-profiler --profiler_binary_host_mirror=https://npm.taobao.org/mirrors/node-inspector/ + // > npm install v8-profiler --profiler_binary_host_mirror=https://registry.npmmirror.com/node-inspector/ const validModuleName = opts.module_name.replace('-', '_'); // explicitly set mirror overrides everything set above host = process.env['npm_config_' + validModuleName + '_binary_host_mirror'] || host;