[READ-ONLY] a fast, modern browser for the npm registry

fix: use jsdelivr when npm has a truncated readme (#1459)

authored by

Luke Oliff and committed by
GitHub
6a4aa00d bb0fd6fc

+37 -3
+12 -3
server/utils/readme-loaders.ts
··· 1 1 import * as v from 'valibot' 2 2 import { PackageRouteParamsSchema } from '#shared/schemas/package' 3 - import { CACHE_MAX_AGE_ONE_HOUR, NPM_MISSING_README_SENTINEL } from '#shared/utils/constants' 3 + import { 4 + CACHE_MAX_AGE_ONE_HOUR, 5 + NPM_MISSING_README_SENTINEL, 6 + NPM_README_TRUNCATION_THRESHOLD, 7 + } from '#shared/utils/constants' 4 8 5 9 /** Standard README filenames to try when fetching from jsdelivr (case-sensitive CDN) */ 6 10 const standardReadmeFilenames = [ ··· 75 79 76 80 const hasValidNpmReadme = readmeContent && readmeContent !== NPM_MISSING_README_SENTINEL 77 81 78 - if (!hasValidNpmReadme || !isStandardReadme(readmeFilename)) { 82 + if ( 83 + !hasValidNpmReadme || 84 + !isStandardReadme(readmeFilename) || 85 + readmeContent!.length >= NPM_README_TRUNCATION_THRESHOLD 86 + ) { 87 + const resolvedVersion = version ?? packageData['dist-tags']?.latest 79 88 const jsdelivrReadme = await fetchReadmeFromJsdelivr( 80 89 packageName, 81 90 standardReadmeFilenames, 82 - version, 91 + resolvedVersion, 83 92 ) 84 93 if (jsdelivrReadme) { 85 94 readmeContent = jsdelivrReadme
+2
shared/utils/constants.ts
··· 21 21 export const ERROR_FILE_LIST_FETCH_FAILED = 'Failed to fetch file list.' 22 22 export const ERROR_CALC_INSTALL_SIZE_FAILED = 'Failed to calculate install size.' 23 23 export const NPM_MISSING_README_SENTINEL = 'ERROR: No README data found!' 24 + /** The npm registry truncates the packument readme field at 65,536 characters (2^16) */ 25 + export const NPM_README_TRUNCATION_THRESHOLD = 64_000 24 26 export const ERROR_JSR_FETCH_FAILED = 'Failed to fetch package from JSR registry.' 25 27 export const ERROR_NPM_FETCH_FAILED = 'Failed to fetch package from npm registry.' 26 28 export const ERROR_PROVENANCE_FETCH_FAILED = 'Failed to fetch provenance.'
+23
test/unit/server/utils/readme-loaders.spec.ts
··· 214 214 }) 215 215 }) 216 216 217 + it('fetches from jsdelivr when packument readme exceeds truncation threshold', async () => { 218 + const truncatedReadme = 'x'.repeat(64_000) 219 + const fullReadme = 'x'.repeat(80_000) 220 + fetchNpmPackageMock.mockResolvedValue({ 221 + 'readme': truncatedReadme, 222 + 'readmeFilename': 'README.md', 223 + 'repository': undefined, 224 + 'versions': {}, 225 + 'dist-tags': { latest: '1.0.0' }, 226 + }) 227 + parseRepositoryInfoMock.mockReturnValue(undefined) 228 + const fetchMock = vi.fn().mockResolvedValue({ 229 + ok: true, 230 + text: async () => fullReadme, 231 + }) 232 + vi.stubGlobal('fetch', fetchMock) 233 + 234 + const result = await resolvePackageReadmeSource('pkg') 235 + 236 + expect(result).toMatchObject({ markdown: fullReadme }) 237 + expect(fetchMock).toHaveBeenCalled() 238 + }) 239 + 217 240 it('uses package repository for repoInfo when markdown is present', async () => { 218 241 fetchNpmPackageMock.mockResolvedValue({ 219 242 readme: '# Hi',