From e6c8e0d3ce198eb09258f09a0bb698d5d49c4cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Kj=C3=A6rgaard?= Date: Thu, 24 Oct 2024 11:38:54 +0200 Subject: [PATCH] fix(#518): Adds auth token to fetch req --- src/commands/module/add.ts | 76 +++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/src/commands/module/add.ts b/src/commands/module/add.ts index c139f2ef..ef1830e2 100644 --- a/src/commands/module/add.ts +++ b/src/commands/module/add.ts @@ -21,6 +21,11 @@ import { } from './_utils' import type { NuxtModule } from './_utils' +export type RegistryMeta = { + registry: string + authToken: string | null +} + export default defineCommand({ meta: { name: 'add', @@ -227,8 +232,22 @@ async function resolveModule( // Fetch package on npm pkgVersion = pkgVersion || 'latest' const pkgScope = pkgName.startsWith('@') ? pkgName.split('/')[0] : null - const registry = await detectNpmRegistry(pkgScope) - const pkg = await $fetch(joinURL(registry, `${pkgName}/${pkgVersion}`)) + const meta: RegistryMeta = await detectNpmRegistry(pkgScope) + const headers: HeadersInit = {} + + if (meta.authToken) { + headers.Authorization = `Bearer ${meta.authToken}` + } + + const pkgDetails = await $fetch(joinURL(meta.registry, `${pkgName}`), { + headers, + }) + + // check if a dist-tag exists + pkgVersion = (pkgDetails['dist-tags']?.[pkgVersion] || pkgVersion) as string + + const pkg = pkgDetails.versions[pkgVersion] + const pkgDependencies = Object.assign( pkg.dependencies || {}, pkg.devDependencies || {}, @@ -259,16 +278,61 @@ async function resolveModule( } } -async function detectNpmRegistry(scope: string | null) { +function getNpmrcPaths(): string[] { + const userNpmrcPath = join(homedir(), '.npmrc') + const cwdNpmrcPath = join(process.cwd(), '.npmrc') + + return [cwdNpmrcPath, userNpmrcPath] +} + +async function getAuthToken(registry: RegistryMeta['registry']): Promise { + const paths = getNpmrcPaths() + const authTokenRegex = new RegExp(`^//${registry.replace(/^https?:\/\//, '').replace(/\/$/, '')}/:_authToken=(.+)$`, 'm') + + for (const npmrcPath of paths) { + let fd: FileHandle | undefined + try { + fd = await fs.promises.open(npmrcPath, 'r') + if (await fd.stat().then(r => r.isFile())) { + const npmrcContent = await fd.readFile('utf-8') + const authTokenMatch = npmrcContent.match(authTokenRegex) + + if (authTokenMatch) { + return authTokenMatch[1].trim() + } + } + } + catch { + // swallow errors as file does not exist + } + finally { + await fd?.close() + } + } + + return null +} + +async function detectNpmRegistry(scope: string | null): Promise { + const registry = await getRegistry(scope) + const authToken = await getAuthToken(registry) + + return { + registry, + authToken, + } +} + +async function getRegistry(scope: string | null): Promise { if (process.env.COREPACK_NPM_REGISTRY) { return process.env.COREPACK_NPM_REGISTRY } - const userNpmrcPath = join(homedir(), '.npmrc') - const cwdNpmrcPath = join(process.cwd(), '.npmrc') - const registry = await getRegistryFromFile([cwdNpmrcPath, userNpmrcPath], scope) + const registry = await getRegistryFromFile(getNpmrcPaths(), scope) + if (registry) { process.env.COREPACK_NPM_REGISTRY = registry } + return registry || 'https://registry.npmjs.org' }