From e93c92f656c52e783180c71529007025b0561459 Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Mon, 2 Feb 2026 23:02:42 +0800 Subject: [PATCH 1/9] refactor: migrate to `fast-npm-meta` # Conflicts: # src/providers/completion-item/version.ts --- package.json | 2 +- pnpm-lock.yaml | 29 ++++------ src/providers/completion-item/version.ts | 18 ++++--- src/providers/diagnostics/index.ts | 4 +- .../diagnostics/rules/deprecation.ts | 2 +- .../diagnostics/rules/vulnerability.ts | 4 +- src/providers/hover/npmx.ts | 6 +-- src/utils/npm.ts | 54 ++++++------------- tsdown.config.ts | 1 + 9 files changed, 48 insertions(+), 72 deletions(-) diff --git a/package.json b/package.json index ac1883f..d1677d2 100644 --- a/package.json +++ b/package.json @@ -97,12 +97,12 @@ "*": "eslint --fix" }, "devDependencies": { - "@npm/types": "^2.1.0", "@types/node": "^25.1.0", "@types/vscode": "1.101.0", "@vida0905/eslint-config": "^2.9.0", "@vscode/vsce": "^3.7.1", "eslint": "^9.39.2", + "fast-npm-meta": "^1.0.0", "husky": "^9.1.7", "jsonc-parser": "^3.3.1", "module-replacements": "^2.11.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 09a64e4..a8d944f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,6 @@ importers: .: devDependencies: - '@npm/types': - specifier: ^2.1.0 - version: 2.1.0 '@types/node': specifier: ^25.1.0 version: 25.1.0 @@ -26,6 +23,9 @@ importers: eslint: specifier: ^9.39.2 version: 9.39.2(jiti@2.6.1) + fast-npm-meta: + specifier: ^1.0.0 + version: 1.0.0 husky: specifier: ^9.1.7 version: 9.1.7 @@ -513,10 +513,6 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@npm/types@2.1.0': - resolution: {integrity: sha512-humQVe2BrWR7Yum5hGDYBnIPnnZJvKSOH/I4QN1ZL2bdb4c4zQHaHupEJ3cOkSJ07G3YfN793ptbNh196BWLgA==} - engines: {node: '>=18.6.0'} - '@oxc-project/types@0.110.0': resolution: {integrity: sha512-6Ct21OIlrEnFEJk5LT4e63pk3btsI6/TusD/GStLi7wYlGJNOl1GI9qvXAnRAxQU9zqA2Oz+UwhfTOU2rPZVow==} @@ -1710,6 +1706,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-npm-meta@1.0.0: + resolution: {integrity: sha512-LZN+gRB2TnkkhRbNnTOgEXyhNBkDypngGX9nJzcKzrOaIQqfZnWEDYdxBqGw6bgiyl0tzpxDuTk1G7tKHyUcsg==} + fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} @@ -2470,10 +2469,6 @@ packages: resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} - postcss@8.5.5: - resolution: {integrity: sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -3554,8 +3549,6 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 - '@npm/types@2.1.0': {} - '@oxc-project/types@0.110.0': {} '@pkgr/core@0.2.7': {} @@ -4120,7 +4113,7 @@ snapshots: '@vue/shared': 3.5.14 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.5 + postcss: 8.5.6 source-map-js: 1.2.1 '@vue/compiler-ssr@3.5.14': @@ -4847,6 +4840,8 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-npm-meta@1.0.0: {} + fast-uri@3.1.0: {} fastq@1.19.1: @@ -5769,12 +5764,6 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss@8.5.5: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postcss@8.5.6: dependencies: nanoid: 3.3.11 diff --git a/src/providers/completion-item/version.ts b/src/providers/completion-item/version.ts index 760939d..3a20993 100644 --- a/src/providers/completion-item/version.ts +++ b/src/providers/completion-item/version.ts @@ -32,21 +32,27 @@ export class VersionCompletionItemProvider implements Compl const prefix = extractVersionPrefix(version) - let versionsKV = Object.values(pkg.versions) + const items: CompletionItem[] = [] - if (config.completion.version === 'provenance-only') - versionsKV = versionsKV.filter(({ hasProvenance }) => hasProvenance) + for (const version in pkg.versionsMeta) { + const meta = pkg.versionsMeta[version] + + if (config.completion.version === 'provenance-only' && !meta.provenance) + continue - return versionsKV.map(({ version, tag }) => { const text = `${prefix}${version}` const item = new CompletionItem(text, CompletionItemKind.Value) item.range = this.extractor.getNodeRange(document, versionNode) item.insertText = text + + const tag = pkg.versionToTag.get(version) if (tag) item.detail = tag - return item - }) + items.push(item) + } + + return items } } diff --git a/src/providers/diagnostics/index.ts b/src/providers/diagnostics/index.ts index 71e19ce..2b97c59 100644 --- a/src/providers/diagnostics/index.ts +++ b/src/providers/diagnostics/index.ts @@ -1,5 +1,5 @@ import type { DependencyInfo, Extractor, ValidNode } from '#types/extractor' -import type { ResolvedPackument } from '#utils/npm' +import type { PackageVersionsInfoWithMetadata } from 'fast-npm-meta' import type { Awaitable } from 'reactive-vscode' import type { Diagnostic, TextDocument } from 'vscode' import { basename } from 'node:path' @@ -15,7 +15,7 @@ import { checkVulnerability } from './rules/vulnerability' export interface NodeDiagnosticInfo extends Pick { node: ValidNode } -export type DiagnosticRule = (dep: DependencyInfo, pkg: ResolvedPackument) => Awaitable +export type DiagnosticRule = (dep: DependencyInfo, pkg: PackageVersionsInfoWithMetadata) => Awaitable function getEnabledRules(): DiagnosticRule[] { const rules: DiagnosticRule[] = [] diff --git a/src/providers/diagnostics/rules/deprecation.ts b/src/providers/diagnostics/rules/deprecation.ts index dbc8092..92c5aea 100644 --- a/src/providers/diagnostics/rules/deprecation.ts +++ b/src/providers/diagnostics/rules/deprecation.ts @@ -4,7 +4,7 @@ import { DiagnosticSeverity } from 'vscode' export const checkDeprecation: DiagnosticRule = (dep, pkg) => { const exactVersion = extractVersion(dep.version) - const versionInfo = pkg.versions[exactVersion] + const versionInfo = pkg.versionsMeta[exactVersion] if (!versionInfo?.deprecated) return diff --git a/src/providers/diagnostics/rules/vulnerability.ts b/src/providers/diagnostics/rules/vulnerability.ts index ef2d783..cb371a1 100644 --- a/src/providers/diagnostics/rules/vulnerability.ts +++ b/src/providers/diagnostics/rules/vulnerability.ts @@ -13,12 +13,12 @@ const DIAGNOSTIC_MAPPING: Record, Diagnosti export const checkVulnerability: DiagnosticRule = async (dep, pkg) => { const exactVersion = extractVersion(dep.version) - const versionInfo = pkg.versions[exactVersion] + const versionInfo = pkg.versionsMeta[exactVersion] if (!versionInfo) return - const { totalCounts } = await getVulnerability({ name: dep.name, version: versionInfo.version }) + const { totalCounts } = await getVulnerability({ name: dep.name, version: exactVersion }) const message: string[] = [] let severity: DiagnosticSeverity | null = null diff --git a/src/providers/hover/npmx.ts b/src/providers/hover/npmx.ts index 1541440..f22ed3c 100644 --- a/src/providers/hover/npmx.ts +++ b/src/providers/hover/npmx.ts @@ -27,10 +27,10 @@ export class NpmxHoverProvider implements HoverProvider { md.isTrusted = true const pkg = await getPackageInfo(name) - const currentVersion = pkg.versions[coercedVersion] + const currentVersion = pkg.versionsMeta[coercedVersion] if (currentVersion) { - if (currentVersion.hasProvenance) - md.appendMarkdown(`[$(verified) Verified provenance](https://www.npmjs.com/package/${name}/v/${currentVersion.version}#provenance)\n\n`) + if (currentVersion.provenance) + md.appendMarkdown(`[$(verified) Verified provenance](https://www.npmjs.com/package/${name}/v/${version}#provenance)\n\n`) } const footer = [ diff --git a/src/utils/npm.ts b/src/utils/npm.ts index 30f8ab5..0ad0487 100644 --- a/src/utils/npm.ts +++ b/src/utils/npm.ts @@ -1,20 +1,8 @@ -import type { Packument, PackumentVersion } from '@npm/types' +import type { PackageVersionsInfoWithMetadata } from 'fast-npm-meta' import { logger } from '#state' -import { ofetch } from 'ofetch' +import { getVersions } from 'fast-npm-meta' import { memoize } from './memoize' -const NPM_REGISTRY = 'https://registry.npmjs.org' - -interface ResolvedPackumentVersion extends Pick { - tag?: string - hasProvenance: boolean - deprecated?: string -} - -export interface ResolvedPackument { - versions: Record -} - /** * Encode a package name for use in npm registry URLs. * Handles scoped packages (e.g., @scope/name -> @scope%2Fname). @@ -26,32 +14,24 @@ export function encodePackageName(name: string): string { return encodeURIComponent(name) } -export const getPackageInfo = memoize>(async (name) => { - logger.info(`Fetching package info for ${name}`) - const encodedName = encodePackageName(name) - - const pkg = await ofetch(`${NPM_REGISTRY}/${encodedName}`) - logger.info(`Fetched package info for ${name}`) +export interface PackageInfo extends PackageVersionsInfoWithMetadata { + versionToTag: Map +} - const resolvedVersions = Object.fromEntries( - Object.keys(pkg.versions) - .filter((v) => pkg.time[v]) - .map<[string, ResolvedPackumentVersion]>((v) => [ - v, - { - version: v, - // @ts-expect-error present if published with provenance - hasProvenance: !!pkg.versions[v].dist.attestations, - deprecated: pkg.versions[v].deprecated, - }, - ]), - ) +export const getPackageInfo = memoize>(async (name) => { + logger.info(`Fetching package info for ${name}`) - Object.entries(pkg['dist-tags']).forEach(([tag, version]) => { - resolvedVersions[version].tag = tag + const pkg = await getVersions(name, { + metadata: true, }) + logger.info(`Fetched package info for ${name}`) - return { - versions: resolvedVersions, + const versionToTag = new Map() + if (pkg.distTags) { + for (const [tag, ver] of Object.entries(pkg.distTags)) { + versionToTag.set(ver, tag) + } } + + return { ...pkg, versionToTag } }) diff --git a/tsdown.config.ts b/tsdown.config.ts index 379225e..4d70c64 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -15,6 +15,7 @@ export default defineConfig({ 'jsonc-parser', 'yaml', 'ofetch', + 'fast-npm-meta', ], minify: 'dce-only', }) From ad5129cf03657ed6546bf16062a02cc1b421957b Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Tue, 3 Feb 2026 10:57:57 +0800 Subject: [PATCH 2/9] chore: reuse `PackageInfo` --- src/providers/diagnostics/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/providers/diagnostics/index.ts b/src/providers/diagnostics/index.ts index 79c2cbc..2476781 100644 --- a/src/providers/diagnostics/index.ts +++ b/src/providers/diagnostics/index.ts @@ -1,5 +1,5 @@ import type { DependencyInfo, Extractor, ValidNode } from '#types/extractor' -import type { PackageVersionsInfoWithMetadata } from 'fast-npm-meta' +import type { PackageInfo } from '#utils/api/package' import type { Awaitable } from 'reactive-vscode' import type { Diagnostic, TextDocument } from 'vscode' import { basename } from 'node:path' @@ -15,7 +15,7 @@ import { checkVulnerability } from './rules/vulnerability' export interface NodeDiagnosticInfo extends Pick { node: ValidNode } -export type DiagnosticRule = (dep: DependencyInfo, pkg: PackageVersionsInfoWithMetadata) => Awaitable +export type DiagnosticRule = (dep: DependencyInfo, pkg: PackageInfo) => Awaitable function getEnabledRules(): DiagnosticRule[] { const rules: DiagnosticRule[] = [] From 2d74988ebaf417a1f2fc11190c9c04ef81933071 Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Tue, 3 Feb 2026 13:59:03 +0800 Subject: [PATCH 3/9] update --- src/providers/diagnostics/rules/replacement.ts | 6 +++++- src/utils/api/package.ts | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/providers/diagnostics/rules/replacement.ts b/src/providers/diagnostics/rules/replacement.ts index d91659a..1fc475d 100644 --- a/src/providers/diagnostics/rules/replacement.ts +++ b/src/providers/diagnostics/rules/replacement.ts @@ -3,7 +3,11 @@ import type { DiagnosticRule } from '..' import { getReplacement } from '#utils/api/replacement' import { DiagnosticSeverity } from 'vscode' -// https://github.com/npmx-dev/npmx.dev/blob/main/app/components/PackageReplacement.vue#L8-L30 +/** + * Keep messages in sync with npmx.dev wording. + * + * https://github.com/npmx-dev/npmx.dev/blob/main/app/components/PackageReplacement.vue#L8-L30 + */ function generateMessage(replacement: ModuleReplacement) { switch (replacement.type) { case 'native': diff --git a/src/utils/api/package.ts b/src/utils/api/package.ts index 4929946..c685d22 100644 --- a/src/utils/api/package.ts +++ b/src/utils/api/package.ts @@ -7,6 +7,11 @@ export interface PackageInfo extends PackageVersionsInfoWithMetadata { versionToTag: Map } +/** + * Fetch npm package versions and build a version-to-tag lookup map. + * + * @see https://github.com/antfu/fast-npm-meta + */ export const getPackageInfo = memoize>(async (name) => { logger.info(`Fetching package info for ${name}`) From efd219628f5920d5697c1e8c9d8e732f625cd6bd Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Tue, 3 Feb 2026 14:48:29 +0800 Subject: [PATCH 4/9] fix: filter jsr packages (404 in npm registry) --- src/providers/completion-item/version.ts | 2 ++ src/providers/diagnostics/index.ts | 2 ++ src/providers/hover/npmx.ts | 3 +++ src/utils/api/package.ts | 10 +++++++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/providers/completion-item/version.ts b/src/providers/completion-item/version.ts index e42edcc..133a5d5 100644 --- a/src/providers/completion-item/version.ts +++ b/src/providers/completion-item/version.ts @@ -29,6 +29,8 @@ export class VersionCompletionItemProvider implements Compl } = info const pkg = await getPackageInfo(name) + if (!pkg) + return const prefix = extractVersionPrefix(version) diff --git a/src/providers/diagnostics/index.ts b/src/providers/diagnostics/index.ts index 952750e..0f42dc4 100644 --- a/src/providers/diagnostics/index.ts +++ b/src/providers/diagnostics/index.ts @@ -48,6 +48,8 @@ export function registerDiagnosticCollection(mapping: Record { try { const pkg = await getPackageInfo(dep.name) + if (!pkg) + return for (const rule of enabledRules.value) { const diagnostic = await rule(dep, pkg) diff --git a/src/providers/hover/npmx.ts b/src/providers/hover/npmx.ts index 5d84cce..74eedd7 100644 --- a/src/providers/hover/npmx.ts +++ b/src/providers/hover/npmx.ts @@ -27,6 +27,9 @@ export class NpmxHoverProvider implements HoverProvider { md.isTrusted = true const pkg = await getPackageInfo(name) + if (!pkg) + return + const currentVersion = pkg.versionsMeta[coercedVersion] if (currentVersion) { if (currentVersion.provenance) diff --git a/src/utils/api/package.ts b/src/utils/api/package.ts index c685d22..94fb689 100644 --- a/src/utils/api/package.ts +++ b/src/utils/api/package.ts @@ -12,14 +12,22 @@ export interface PackageInfo extends PackageVersionsInfoWithMetadata { * * @see https://github.com/antfu/fast-npm-meta */ -export const getPackageInfo = memoize>(async (name) => { +export const getPackageInfo = memoize>(async (name) => { logger.info(`Fetching package info for ${name}`) const pkg = await getVersions(name, { metadata: true, + }).catch((err) => { + logger.warn(`Fetching package info for ${name} error: `, err) + + if (typeof err === 'string' && err.includes('404 Not Found')) + return null }) logger.info(`Fetched package info for ${name}`) + if (!pkg) + return null + const versionToTag = new Map() if (pkg.distTags) { for (const [tag, ver] of Object.entries(pkg.distTags)) { From fbe12f66e14e0b4384234295450be728680e6269 Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Tue, 3 Feb 2026 17:49:10 +0800 Subject: [PATCH 5/9] fix: handle error --- src/utils/api/package.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/utils/api/package.ts b/src/utils/api/package.ts index 94fb689..bfffa9b 100644 --- a/src/utils/api/package.ts +++ b/src/utils/api/package.ts @@ -17,12 +17,20 @@ export const getPackageInfo = memoize>(async const pkg = await getVersions(name, { metadata: true, - }).catch((err) => { - logger.warn(`Fetching package info for ${name} error: `, err) + throw: false, + }) + + if ('error' in pkg) { + logger.warn(`Fetching package info for ${name} error: ${JSON.stringify(pkg)}`) - if (typeof err === 'string' && err.includes('404 Not Found')) + // TODO: waiting https://github.com/antfu/fast-npm-meta/pull/27 + // Return null to trigger a cache hit + if (pkg.error.includes('404')) return null - }) + + throw pkg + } + logger.info(`Fetched package info for ${name}`) if (!pkg) From 10725ee8e7961bed02965ce9d30fc6e96f16d9d9 Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Wed, 4 Feb 2026 14:36:56 +0800 Subject: [PATCH 6/9] upgrade `fast-npm-meta` --- package.json | 2 +- pnpm-lock.yaml | 29 +++++++++++++++-------------- src/utils/api/package.ts | 3 +-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 6c8d770..89e4e3f 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "@vida0905/eslint-config": "^2.9.0", "@vscode/vsce": "^3.7.1", "eslint": "^9.39.2", - "fast-npm-meta": "^1.0.0", + "fast-npm-meta": "^1.2.0", "husky": "^9.1.7", "jsonc-parser": "^3.3.1", "module-replacements": "^2.11.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a8d944f..98b4fb0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,8 +24,8 @@ importers: specifier: ^9.39.2 version: 9.39.2(jiti@2.6.1) fast-npm-meta: - specifier: ^1.0.0 - version: 1.0.0 + specifier: ^1.2.0 + version: 1.2.0 husky: specifier: ^9.1.7 version: 9.1.7 @@ -194,8 +194,8 @@ packages: resolution: {integrity: sha512-6t0IaUEzlinbLmsGIvBZIHEJGjuchx+cMj+FbS78zL17tucYervgbwO07V5/CgBenVraontpmyMCTVyqCfxhFQ==} engines: {node: ^20.19.0 || >=22.12.0} - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} engines: {node: '>=6.0.0'} hasBin: true @@ -204,8 +204,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} '@babel/types@8.0.0-beta.4': @@ -1706,8 +1706,8 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-npm-meta@1.0.0: - resolution: {integrity: sha512-LZN+gRB2TnkkhRbNnTOgEXyhNBkDypngGX9nJzcKzrOaIQqfZnWEDYdxBqGw6bgiyl0tzpxDuTk1G7tKHyUcsg==} + fast-npm-meta@1.2.0: + resolution: {integrity: sha512-v0ShpcJdqGAx0KAaGSQpyWXVaGf5SqPr0gwwQL/Y+Wcus0T5YmtH8aDstCpQ+t4SGFtJC2Hjf/rCoJjHpMJnew==} fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} @@ -1808,6 +1808,7 @@ packages: glob@11.0.3: resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} engines: {node: 20 || >=22} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true globals@14.0.0: @@ -3280,15 +3281,15 @@ snapshots: '@babel/helper-validator-identifier@8.0.0-beta.4': {} - '@babel/parser@7.28.5': + '@babel/parser@7.29.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 '@babel/parser@8.0.0-beta.4': dependencies: '@babel/types': 8.0.0-beta.4 - '@babel/types@7.28.5': + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 @@ -4093,7 +4094,7 @@ snapshots: '@vue/compiler-core@3.5.14': dependencies: - '@babel/parser': 7.28.5 + '@babel/parser': 7.29.0 '@vue/shared': 3.5.14 entities: 4.5.0 estree-walker: 2.0.2 @@ -4106,7 +4107,7 @@ snapshots: '@vue/compiler-sfc@3.5.14': dependencies: - '@babel/parser': 7.28.5 + '@babel/parser': 7.29.0 '@vue/compiler-core': 3.5.14 '@vue/compiler-dom': 3.5.14 '@vue/compiler-ssr': 3.5.14 @@ -4840,7 +4841,7 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-npm-meta@1.0.0: {} + fast-npm-meta@1.2.0: {} fast-uri@3.1.0: {} diff --git a/src/utils/api/package.ts b/src/utils/api/package.ts index bfffa9b..74055c8 100644 --- a/src/utils/api/package.ts +++ b/src/utils/api/package.ts @@ -23,9 +23,8 @@ export const getPackageInfo = memoize>(async if ('error' in pkg) { logger.warn(`Fetching package info for ${name} error: ${JSON.stringify(pkg)}`) - // TODO: waiting https://github.com/antfu/fast-npm-meta/pull/27 // Return null to trigger a cache hit - if (pkg.error.includes('404')) + if (pkg.status === 404) return null throw pkg From 2efb8afefb160a62d4a216f574a4342b1767906a Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Wed, 4 Feb 2026 15:05:31 +0800 Subject: [PATCH 7/9] fix: use correct version --- src/constants.ts | 3 +-- src/providers/hover/npmx.ts | 7 ++++--- src/utils/links.ts | 10 +++++++++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 056183d..91e6df0 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -8,7 +8,6 @@ export const VERSION_TRIGGER_CHARACTERS = ['.', '^', '~', ...Array.from({ length export const CACHE_TTL_ONE_DAY = 1000 * 60 * 60 * 24 +export const NPMJS_COM = 'https://npmjs.com' export const NPMX_DEV = 'https://npmx.dev' - -export const NPM_REGISTRY = 'https://registry.npmjs.org' export const NPMX_DEV_API = `${NPMX_DEV}/api` diff --git a/src/providers/hover/npmx.ts b/src/providers/hover/npmx.ts index 74eedd7..5dc4c72 100644 --- a/src/providers/hover/npmx.ts +++ b/src/providers/hover/npmx.ts @@ -1,6 +1,7 @@ import type { Extractor } from '#types/extractor' import type { HoverProvider, Position, TextDocument } from 'vscode' import { getPackageInfo } from '#utils/api/package' +import { npmPacakgeUrl, npmxDocsUrl, npmxPackageUrl } from '#utils/links' import { extractVersion } from '#utils/package' import { Hover, MarkdownString } from 'vscode' @@ -33,12 +34,12 @@ export class NpmxHoverProvider implements HoverProvider { const currentVersion = pkg.versionsMeta[coercedVersion] if (currentVersion) { if (currentVersion.provenance) - md.appendMarkdown(`[$(verified) Verified provenance](https://www.npmjs.com/package/${name}/v/${version}#provenance)\n\n`) + md.appendMarkdown(`[$(verified) Verified provenance](${npmPacakgeUrl(name, coercedVersion)}#provenance)\n\n`) } const footer = [ - `**[View on npmx](https://npmx.dev/package/${name})**`, - `**[View docs on npmx](https://npmx.dev/docs/${name}/v/${coercedVersion})**`, + `[View on npmx](${npmxPackageUrl(name)})`, + `[View docs on npmx](${npmxDocsUrl(name, coercedVersion)})`, ] md.appendMarkdown(`${footer.join(' | ')}\n`) diff --git a/src/utils/links.ts b/src/utils/links.ts index 7f5e5d3..5da0fdc 100644 --- a/src/utils/links.ts +++ b/src/utils/links.ts @@ -1,7 +1,15 @@ -import { NPMX_DEV } from '#constants' +import { NPMJS_COM, NPMX_DEV } from '#constants' + +export function npmPacakgeUrl(name: string, version?: string): string { + return `${NPMJS_COM}/package/${name}/v/${version}` +} export function npmxPackageUrl(name: string, version?: string): string { return version ? `${NPMX_DEV}/package/${name}/v/${version}` : `${NPMX_DEV}/package/${name}` } + +export function npmxDocsUrl(name: string, version: string): string { + return `${NPMX_DEV}/docs/${name}/v/${version}` +} From e3542078b730b529b694fe100719c23475ae6fb9 Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Wed, 4 Feb 2026 15:09:33 +0800 Subject: [PATCH 8/9] chore: update --- src/utils/api/package.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/utils/api/package.ts b/src/utils/api/package.ts index 74055c8..b4fd30e 100644 --- a/src/utils/api/package.ts +++ b/src/utils/api/package.ts @@ -32,9 +32,6 @@ export const getPackageInfo = memoize>(async logger.info(`Fetched package info for ${name}`) - if (!pkg) - return null - const versionToTag = new Map() if (pkg.distTags) { for (const [tag, ver] of Object.entries(pkg.distTags)) { From be44a6d68bc1e0329c6d73460d105c0d30410eca Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Wed, 4 Feb 2026 15:11:56 +0800 Subject: [PATCH 9/9] fix: handle undefined --- src/utils/links.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utils/links.ts b/src/utils/links.ts index 5da0fdc..3a411fb 100644 --- a/src/utils/links.ts +++ b/src/utils/links.ts @@ -1,7 +1,9 @@ import { NPMJS_COM, NPMX_DEV } from '#constants' export function npmPacakgeUrl(name: string, version?: string): string { - return `${NPMJS_COM}/package/${name}/v/${version}` + return version + ? `${NPMJS_COM}/package/${name}/v/${version}` + : `${NPMJS_COM}/package/${name}` } export function npmxPackageUrl(name: string, version?: string): string {