Skip to content

fix: get url from pkg.repository when string - #3173

Draft
WilcoSp wants to merge 9 commits into
npmx-dev:mainfrom
WilcoSp:fix/parseRepo
Draft

fix: get url from pkg.repository when string#3173
WilcoSp wants to merge 9 commits into
npmx-dev:mainfrom
WilcoSp:fix/parseRepo

Conversation

@WilcoSp

@WilcoSp WilcoSp commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

🔗 Linked issue

I haven't found any yet

🧭 Context

I had noticed with date-fns that since version 4.3.0 that the links to github & changelog wasn't available

I've now at useRepositoryUrl, detectChangelog, package.takumi.vue & package analysis changed parsing the repo url to allow pkg.repository to be either a string or an object.

idk if this happens with more packages but at least with date-fns I did notice it.

📚 Description

What happened is that since date-fns 4.3.0 that the repository field of the meta data isn't being normalized anymore and is now the same as in package.json, (more info)

For detectChangelog & package analysis I've change parseRepoUrl to parseRepositoryInfo and given the pkg.repository string/object

For useRepositoryUrl I've added a check whether repo is a string and if it is then I normalized it and return the result, I had tests at first for this but removed them because the types changes needed would've made a lot for something that is a fallback

for package.takumi.vue I've also add a type check for whether repository is a string or not

Also I do question whether we should do something with the issues link at the package page.

what might have caused this

I think that this is caused due to the fact that the npm cli normalizes the repository field in package.json, but with pnpm v11 they've made their own publish command which might not normalize the repository

previews

date-fns 4.4.0

date-fns 4.2.1:

@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview Aug 12, 2026 10:06pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Aug 12, 2026 10:06pm
npmx-lunaria Ignored Ignored Aug 12, 2026 10:06pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of repository references provided as URLs or metadata objects.
    • Added support for shorthand HTTPS and git+https repository URLs, including .git suffixes.
    • Improved repository ownership matching across multiple Git hosting providers while validating provider and host details.
    • Changelog and release detection now works consistently with varied repository formats and optional repository directories.
    • Repository links and generated package images now handle missing or directory-specific repository information more reliably.

Walkthrough

Repository metadata now accepts string and object forms. URL normalisation, package image rendering, registry association, and changelog detection handle both forms. Repository comparisons use parseRepositoryInfo.

Changes

Repository URL handling

Layer / File(s) Summary
Normalise string repository metadata
shared/types/npm-registry.ts, shared/utils/package-analysis.ts, app/composables/useRepositoryUrl.ts, app/components/OgImage/Package.takumi.vue, test/nuxt/composables/use-repository-url.spec.ts
Shared types accept string repositories. URL normalisation and package image rendering handle string and object values. Test helpers use the updated repository shape.
Compare repository metadata during registry association
server/api/registry/analysis/[...pkg].get.ts
Registry association accepts string or object repository values. Provider, host, and owner matching use parseRepositoryInfo.
Parse repository configuration for changelog detection
server/utils/changelog/detectChangelog.ts
Changelog detection parses the complete repository configuration and passes the parsed reference and optional directory to release and changelog checks.

Possibly related PRs

  • npmx-dev/npmx.dev#2983: Both PRs modify repository parsing and changelog detection, including support for repository objects and multiple providers.

Mergeability Score: 🟡 Moderate · up to dbd82

The repository URL fallback can accept an invalid empty metadata shape because null is not excluded before the type transformation, weakening compile-time protection for package links. Merge should wait for this type to exclude null or for explicit owner acceptance.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarises the main change: retrieving repository URLs when package metadata provides a string.
Description check ✅ Passed The description directly explains the repository parsing changes and the issue they resolve.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 35.71429% with 9 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
server/api/registry/analysis/[...pkg].get.ts 0.00% 2 Missing and 2 partials ⚠️
server/utils/changelog/detectChangelog.ts 0.00% 3 Missing and 1 partial ⚠️
app/composables/useRepositoryUrl.ts 50.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
server/utils/changelog/detectChangelog.ts (1)

23-33: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Pass the parsed directory to both checks.

parseRepositoryInfo already normalises repository.directory into repoRef.directory. Both calls read pkg.repository?.directory again. Pass repoRef.directory to keep normalisation in one place and support string-valued repositories without raw object property access.

Suggested change
-  const [releases, releasesError] = await checkReleases(repoRef, pkg.repository?.directory)
+  const [releases, releasesError] = await checkReleases(repoRef, repoRef.directory)
...
-  const changelog = await checkChangelogFile(repoRef, pkg.repository?.directory)
+  const changelog = await checkChangelogFile(repoRef, repoRef.directory)

As per coding guidelines, “Ensure you write strictly type-safe code”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/utils/changelog/detectChangelog.ts` around lines 23 - 33, Update both
checkReleases and checkChangelogFile calls in detectChangelog to pass
repoRef.directory instead of pkg.repository?.directory, preserving the
normalized directory from parseRepositoryInfo and ensuring type-safe handling of
string-valued repositories.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/api/registry/analysis/`[...pkg].get.ts:
- Around line 150-170: Update the repository type definitions for
PackageWithMeta and ExtendedPackageJson to allow either repository metadata
objects or bare strings, then adjust detectChangelog.ts to narrow string
repository values before accessing the directory property. Preserve the existing
object-based directory handling.

---

Nitpick comments:
In `@server/utils/changelog/detectChangelog.ts`:
- Around line 23-33: Update both checkReleases and checkChangelogFile calls in
detectChangelog to pass repoRef.directory instead of pkg.repository?.directory,
preserving the normalized directory from parseRepositoryInfo and ensuring
type-safe handling of string-valued repositories.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3953b5ca-1399-446e-aa70-f52a3ff3a605

📥 Commits

Reviewing files that changed from the base of the PR and between 27f5bd7 and e12058d.

📒 Files selected for processing (4)
  • app/composables/useRepositoryUrl.ts
  • server/api/registry/analysis/[...pkg].get.ts
  • server/utils/changelog/detectChangelog.ts
  • test/nuxt/composables/use-repository-url.spec.ts

Comment thread server/api/registry/analysis/[...pkg].get.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shared/types/npm-registry.ts`:
- Line 87: Update SlimPackumentVersion to override its inherited repository
field with the same object-or-string type used by the package-level repository
definition, preserving existing optional fields. Add a type-level test that
accepts a string repository on a SlimPackumentVersion.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4953aa4f-0664-4205-a58a-d22a9706b20e

📥 Commits

Reviewing files that changed from the base of the PR and between e12058d and 6911a51.

📒 Files selected for processing (5)
  • app/components/OgImage/Package.takumi.vue
  • server/utils/changelog/detectChangelog.ts
  • shared/types/npm-registry.ts
  • shared/utils/package-analysis.ts
  • test/nuxt/composables/use-repository-url.spec.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/nuxt/composables/use-repository-url.spec.ts
  • server/utils/changelog/detectChangelog.ts

Comment thread shared/types/npm-registry.ts
@WilcoSp
WilcoSp marked this pull request as ready for review August 12, 2026 21:18
@WilcoSp WilcoSp changed the title fix: get url from from pkg.repository when string fix: get url from pkg.repository when string Aug 12, 2026
import { describe, expect, it } from 'vitest'

type RequestedVersion = Exclude<SlimPackument['requestedVersion'], null>
type RequestedVersion = Omit<Exclude<SlimPackument['requestedVersion'], null>, 'repository'> & {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not import the type from app/composables/useRepositoryUrl.ts?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still need to figure things out as it still seems to be that Omit still drops everything in a type instead of only "repository"

but when things with omit are solved, yes it would be possible

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/composables/useRepositoryUrl.ts`:
- Around line 4-6: Update the RequestedVersion type alias to exclude null from
SlimPackument['requestedVersion'] before applying Omit, using the existing
repository override and null union so the resulting type does not permit an
empty object from omitting fields on null.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 70a05311-85c6-4002-b198-c18201fadbca

📥 Commits

Reviewing files that changed from the base of the PR and between 3b1643c and dbd8252.

📒 Files selected for processing (2)
  • app/composables/useRepositoryUrl.ts
  • test/nuxt/composables/use-repository-url.spec.ts

Comment on lines +4 to +6
export type RequestedVersion =
| (Omit<SlimPackument['requestedVersion'], 'repository'> & { repository?: string | Repository })
| null

@coderabbitai coderabbitai Bot Aug 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tsc_bin="${TSC_BIN:-tsc}"
command -v "$tsc_bin" >/dev/null

probe="$(mktemp --suffix=.ts)"
trap 'rm -f "$probe"' EXIT

cat >"$probe" <<'EOF'
type Version = { version: string; repository?: { url?: string } } | null
type Broken = Omit<Version, 'repository'>
type Fixed = Omit<Exclude<Version, null>, 'repository'>

declare const broken: Broken
// `@ts-expect-error`: the nullable Omit form must not retain `version`.
const brokenVersion: string = broken.version

declare const fixed: Fixed
const fixedVersion: string = fixed.version

void brokenVersion
void fixedVersion
EOF

"$tsc_bin" --strict --noEmit "$probe"

rg -n 'Omit<.*SlimPackument.*requestedVersion|Omit<Exclude<.*SlimPackument.*requestedVersion' \
  app/composables/useRepositoryUrl.ts \
  test/nuxt/composables/use-repository-url.spec.ts

Repository: npmx-dev/npmx.dev

Length of output: 297


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tsc_bin="${TSC_BIN:-tsc}"
command -v "$tsc_bin" >/dev/null

probe="$(mktemp --suffix=.ts)"
trap 'rm -f "$probe"' EXIT

cat >"$probe" <<'EOF'
type Version = { version: string; repository?: { url?: string } } | null
type Broken = Omit<Version, 'repository'>
type Fixed = Omit<Exclude<Version, null>, 'repository'>

declare const broken: Broken
// `@ts-expect-error`: the nullable Omit form must not retain `version`.
const brokenVersion: string = broken.version

declare const fixed: Fixed
const fixedVersion: string = fixed.version

void brokenVersion
void fixedVersion
EOF

"$tsc_bin" --strict --noEmit --ignoreConfig "$probe"

printf '%s\n' '--- relevant declarations and uses ---'
rg -n -C 4 \
  'RequestedVersion|requestedVersion|type SlimPackument|interface SlimPackument|type SlimPackumentVersion|interface SlimPackumentVersion' \
  app/composables/useRepositoryUrl.ts \
  shared/types \
  test/nuxt/composables/use-repository-url.spec.ts

Repository: npmx-dev/npmx.dev

Length of output: 4554


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- RequestedVersion references ---'
rg -n -C 3 '\bRequestedVersion\b' app test shared

tsc_bin="${TSC_BIN:-tsc}"
command -v "$tsc_bin" >/dev/null

probe="$(mktemp --suffix=.ts)"
trap 'rm -f "$probe"' EXIT

cat >"$probe" <<'EOF'
type Version = { version: string; name: string; repository?: { url?: string } } | null
type Broken = Omit<Version, 'repository'> & { repository?: string }
type Fixed = Omit<Exclude<Version, null>, 'repository'> & { repository?: string }

const emptyBroken: Broken = {}
// `@ts-expect-error`: the broken type must not expose version.
const brokenVersion: string = ({} as Broken).version

// `@ts-expect-error`: the fixed type requires the version fields.
const emptyFixed: Fixed = {}

const fixed: Fixed = { version: '1.0.0', name: 'pkg' }
const fixedVersion: string = fixed.version

void emptyBroken
void brokenVersion
void emptyFixed
void fixedVersion
EOF

"$tsc_bin" --strict --noEmit --ignoreConfig "$probe"

Repository: npmx-dev/npmx.dev

Length of output: 2112


Exclude null before applying Omit.

SlimPackument['requestedVersion'] is nullable. The current type removes its version fields and accepts {}. Use Omit<Exclude<SlimPackument['requestedVersion'], null>, 'repository'>.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/composables/useRepositoryUrl.ts` around lines 4 - 6, Update the
RequestedVersion type alias to exclude null from
SlimPackument['requestedVersion'] before applying Omit, using the existing
repository override and null union so the resulting type does not permit an
empty object from omitting fields on null.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm already doing that

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WilcoSp, the outer | null keeps the nullable result, but it does not exclude null before Omit.

The required change is:

export type RequestedVersion =
  | (Omit<Exclude<SlimPackument['requestedVersion'], null>, 'repository'> & {
      repository?: string | Repository
    })
  | null

This preserves the requested-version fields and still permits null.

You are interacting with an AI system.

@WilcoSp
WilcoSp marked this pull request as draft August 12, 2026 22:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants