diff --git a/sources/npmRegistryUtils.ts b/sources/npmRegistryUtils.ts index 706046be2..a19e0a804 100644 --- a/sources/npmRegistryUtils.ts +++ b/sources/npmRegistryUtils.ts @@ -13,11 +13,15 @@ export const DEFAULT_HEADERS: Record = { }; export const DEFAULT_NPM_REGISTRY_URL = `https://registry.npmjs.org`; -export async function fetchAsJson(packageName: string, version?: string) { +function getRegistryURL() { // Strip any trailing slashes so a `COREPACK_NPM_REGISTRY` with a trailing // slash does not produce a double slash in the request URL (some registries, // e.g. registry.npmmirror.com, reject `//package` with a 404). - const npmRegistryUrl = (process.env.COREPACK_NPM_REGISTRY || DEFAULT_NPM_REGISTRY_URL).replace(/\/+$/, ``); + return (process.env.COREPACK_NPM_REGISTRY || DEFAULT_NPM_REGISTRY_URL).replace(/\/+$/, ``); +} + +export async function fetchAsJson(packageName: string, version?: string) { + const npmRegistryUrl = getRegistryURL(); if (process.env.COREPACK_ENABLE_NETWORK === `0`) throw new UsageError(`Network access disabled by the environment; can't reach npm repository ${npmRegistryUrl}`); @@ -116,5 +120,11 @@ export async function fetchTarballURLAndSignature(packageName: string, version: if (tarball === undefined || !tarball.startsWith(`http`)) throw new Error(`${packageName}@${version} does not have a valid tarball.`); - return {tarball, signatures, integrity}; + const tarballPath = tarball.indexOf(`/${packageName}/-/`); + + return { + tarball: tarballPath === -1 ? tarball : getRegistryURL() + tarball.slice(tarballPath), + signatures, + integrity, + }; } diff --git a/tests/_registryServer.mjs b/tests/_registryServer.mjs index cb4553d04..0ee5fbd1d 100644 --- a/tests/_registryServer.mjs +++ b/tests/_registryServer.mjs @@ -102,7 +102,7 @@ function generateVersionMetadata(packageName, version) { dist: { shasum, size: mockPackageTarGz.length, - tarball: `https://registry.npmjs.org/${packageName}/-/${packageName}-${version}.tgz`, + tarball: `${process.env.TEST_TARBALL_HOST ?? `https://registry.npmjs.org`}/${packageName}/-/${packageName}-${version}.tgz`, ...generateSignature(packageName, version), }, }; diff --git a/tests/main.test.ts b/tests/main.test.ts index 4bb7f40f4..2e166c257 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -1929,6 +1929,20 @@ for (const authType of [`COREPACK_NPM_REGISTRY`, `COREPACK_NPM_TOKEN`, `COREPACK }); } +it(`should download from COREPACK_NPM_REGISTRY when the registry advertises the tarball on another host`, async () => { + await xfs.mktempPromise(async cwd => { + process.env.AUTH_TYPE = `COREPACK_NPM_TOKEN`; // See `_registryServer.mjs` + process.env.COREPACK_INTEGRITY_KEYS = ``; + process.env.TEST_TARBALL_HOST = `https://cdn.example.org`; // See `_registryServer.mjs` + + await expect(runCli(cwd, [`pnpm@1.x`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `pnpm: Hello from custom registry\n`, + stderr: ``, + }); + }); +}); + describe(`handle integrity checks`, () => { beforeEach(() => { process.env.AUTH_TYPE = `COREPACK_NPM_TOKEN`; // See `_registryServer.mjs`