From c0a23b49f7dade8b2ed04b420a6ea86725d4cfe5 Mon Sep 17 00:00:00 2001 From: WilcoSp Date: Wed, 4 Feb 2026 21:17:53 +0100 Subject: [PATCH 1/4] now able to detect whether gh releases are biing used by a package. --- app/composables/usePackageAnalysis.ts | 2 + app/pages/package/[...package].vue | 8 +++ server/api/registry/analysis/[...pkg].get.ts | 6 +- server/utils/has-changelog.ts | 66 ++++++++++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 server/utils/has-changelog.ts diff --git a/app/composables/usePackageAnalysis.ts b/app/composables/usePackageAnalysis.ts index 334e38446..a324792d2 100644 --- a/app/composables/usePackageAnalysis.ts +++ b/app/composables/usePackageAnalysis.ts @@ -10,6 +10,8 @@ export interface PackageAnalysisResponse { npm?: string } createPackage?: CreatePackageInfo + // TODO move this to it's own composable + hasChangelog?: boolean } /** diff --git a/app/pages/package/[...package].vue b/app/pages/package/[...package].vue index 108bb5fc8..3fe25ec00 100644 --- a/app/pages/package/[...package].vue +++ b/app/pages/package/[...package].vue @@ -699,6 +699,14 @@ defineOgImageComponent('Package', { {{ $t('package.links.issues') }} + + +
  • { @@ -53,11 +54,13 @@ export default defineCachedEventHandler( const createPackage = await findAssociatedCreatePackage(packageName, pkg) const analysis = analyzePackage(pkg, { typesPackage, createPackage }) - + // TODO move this to it's own endpoint + const hasChangelog = await detectHasChangelog(pkg) return { package: packageName, version: pkg.version ?? version ?? 'latest', ...analysis, + hasChangelog, } satisfies PackageAnalysisResponse } catch (error: unknown) { handleApiError(error, { @@ -215,4 +218,5 @@ function hasSameRepositoryOwner( export interface PackageAnalysisResponse extends PackageAnalysis { package: string version: string + hasChangelog: boolean | null } diff --git a/server/utils/has-changelog.ts b/server/utils/has-changelog.ts new file mode 100644 index 000000000..1a697f504 --- /dev/null +++ b/server/utils/has-changelog.ts @@ -0,0 +1,66 @@ +import type { ExtendedPackageJson } from '~~/shared/utils/package-analysis' +import { parseRepoUrl, type RepoRef } from '~~/shared/utils/git-providers' + +/** + * Detect whether changelogs/releases are available for this package + * + * first checks if releases are available and then changelog.md + */ +export async function detectHasChangelog( + pkg: ExtendedPackageJson, + // packageName: string, + // version: string, +) { + if (!pkg.repository?.url) { + return false + } + + const repoRef = parseRepoUrl(pkg.repository.url) + if (!repoRef) { + return false + } + + if (await checkReleases(repoRef)) { + return true + } + + return null +} + +/** + * check whether releases are being used with this repo + * @returns true if in use + */ +async function checkReleases(ref: RepoRef): Promise { + const checkUrls = getLatestReleaseUrl(ref) + + for (const checkUrl of checkUrls ?? []) { + const exists = await fetch(checkUrl, { + headers: { + // GitHub API requires User-Agent + 'User-Agent': 'npmx.dev', + }, + method: 'HEAD', // we just need to know if it exists or not + }) + .then(r => r.ok) + .catch(() => false) + if (exists) { + return true + } + } + return false +} + +/** + * get the url to check if releases are being used. + * + * @returns returns an array so that if providers don't have a latest that we can check for versions + */ +function getLatestReleaseUrl(ref: RepoRef): null | string[] { + switch (ref.provider) { + case 'github': + return [`https://ungh.cc/repos/${ref.owner}/${ref.repo}/releases/latest`] + } + + return null +} From 92193b55628fdee0d3d03b0f34cc1958c49c6c73 Mon Sep 17 00:00:00 2001 From: WilcoSp Date: Sat, 7 Feb 2026 11:39:50 +0100 Subject: [PATCH 2/4] moved has changelog to it's own api endpoint --- app/composables/usePackageAnalysis.ts | 2 - app/composables/usePackageHasChangelog.ts | 18 ++++++++ app/pages/package/[...package].vue | 6 ++- i18n/locales/en.json | 3 +- lunaria/files/en-GB.json | 3 +- lunaria/files/en-US.json | 3 +- server/api/changelog/has/[...pkg].get.ts | 45 ++++++++++++++++++++ server/api/registry/analysis/[...pkg].get.ts | 5 --- server/utils/has-changelog.ts | 2 +- shared/utils/constants.ts | 1 + 10 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 app/composables/usePackageHasChangelog.ts create mode 100644 server/api/changelog/has/[...pkg].get.ts diff --git a/app/composables/usePackageAnalysis.ts b/app/composables/usePackageAnalysis.ts index a324792d2..334e38446 100644 --- a/app/composables/usePackageAnalysis.ts +++ b/app/composables/usePackageAnalysis.ts @@ -10,8 +10,6 @@ export interface PackageAnalysisResponse { npm?: string } createPackage?: CreatePackageInfo - // TODO move this to it's own composable - hasChangelog?: boolean } /** diff --git a/app/composables/usePackageHasChangelog.ts b/app/composables/usePackageHasChangelog.ts new file mode 100644 index 000000000..8dac3bc4c --- /dev/null +++ b/app/composables/usePackageHasChangelog.ts @@ -0,0 +1,18 @@ +export function usePackageHasChangelog( + packageName: MaybeRefOrGetter, + version?: MaybeRefOrGetter, +) { + return useLazyFetch( + () => { + const name = toValue(packageName) + const ver = toValue(version) + const base = `/api/changelog/has/${name}` + return ver ? `${base}/v/${ver}` : base + }, + { + onResponse(r) { + console.log({ r }) + }, + }, + ) +} diff --git a/app/pages/package/[...package].vue b/app/pages/package/[...package].vue index 84d07d280..67dfb64bb 100644 --- a/app/pages/package/[...package].vue +++ b/app/pages/package/[...package].vue @@ -117,6 +117,9 @@ const { data: skillsData } = useLazyFetch( const { data: packageAnalysis } = usePackageAnalysis(packageName, requestedVersion) const { data: moduleReplacement } = useModuleReplacement(packageName) +const { data: hasChangelog } = usePackageHasChangelog(packageName, requestedVersion) + +watchEffect(() => console.log('hasChangelog', hasChangelog.value)) const { data: resolvedVersion, @@ -756,9 +759,8 @@ onKeyStroke( {{ $t('package.links.issues') }}
  • -