diff --git a/src/RepositoryParser.ts b/src/RepositoryParser.ts index f017517a..0c5d04ba 100644 --- a/src/RepositoryParser.ts +++ b/src/RepositoryParser.ts @@ -15,14 +15,15 @@ export enum ParseStatus { VERSION_NOT_FOUND = 'VERSION_NOT_FOUND', } -export type ParseResult = +export type ParseResult = {packageInfo?: packageJson.FullVersion & Pick} & ( | { status: Exclude; } | { status: ParseStatus.SUCCESS; url: string; - }; + } +); const knownSSLHosts = ['bitbucket.org', 'github.com', 'gitlab.com', 'sourceforge.net']; @@ -73,17 +74,18 @@ export async function getPackageUrl(rawPackageName: string, version: string = 'l if (!foundUrl) { logger.info(`No source URL found in package "${rawPackageName}".`); - return {status: ParseStatus.NO_URL_FOUND}; + return {packageInfo, status: ParseStatus.NO_URL_FOUND}; } foundUrl = cleanUrl(foundUrl); if (!foundUrl) { logger.info(`Invalid URL "${foundUrl}" for package "${rawPackageName}".`); - return {status: ParseStatus.INVALID_URL}; + return {packageInfo, status: ParseStatus.INVALID_URL}; } return { + packageInfo, status: ParseStatus.SUCCESS, url: foundUrl, }; diff --git a/src/controllers/packages.controller.ts b/src/controllers/packages.controller.ts index 7f635af8..b24aea54 100644 --- a/src/controllers/packages.controller.ts +++ b/src/controllers/packages.controller.ts @@ -5,12 +5,13 @@ import {StatusCodes as HTTP_STATUS} from 'http-status-codes'; import {URL} from 'node:url'; import {getPackageUrl, ParseStatus} from '../RepositoryParser'; -import {RawError, RawResult} from '../swagger'; +import {RawError, RawErrorWithPackageInfo, RawResult} from '../swagger'; import {getLogger, validateUrl} from '../utils'; interface PackagesRouteResponseBody { code: HTTP_STATUS; message?: string; + packageInfo?: object; url?: string; } @@ -48,6 +49,7 @@ async function handlePackageRequest( } const parseResult = await getPackageUrl(packageName, version); + const packageInfo = parseResult.packageInfo; let errorCode: HTTP_STATUS; let errorMessage: string; @@ -63,7 +65,10 @@ async function handlePackageRequest( case ParseStatus.NO_URL_FOUND: { errorCode = HTTP_STATUS.NOT_FOUND; errorMessage = `No source URL found. Please visit https://www.npmjs.com/package/${packageName}.`; - break; + response + .status(errorCode) + .json({code: errorCode, message: errorMessage, packageInfo} satisfies PackagesRouteResponseBody); + return; } case ParseStatus.PACKAGE_NOT_FOUND: { @@ -122,7 +127,11 @@ export class PackagesController { @ApiQuery({description: 'Get a link to unpkg.com', name: 'unpkg', required: false, type: Boolean}) @ApiResponse({description: 'That worked', status: HTTP_STATUS.OK, type: RawResult}) @ApiResponse({description: 'Redirect to repository URL', status: HTTP_STATUS.MOVED_TEMPORARILY}) - @ApiResponse({description: 'Version or package not found', status: HTTP_STATUS.NOT_FOUND, type: RawError}) + @ApiResponse({ + description: 'Version, package, or source URL not found', + status: HTTP_STATUS.NOT_FOUND, + type: RawErrorWithPackageInfo, + }) @ApiResponse({description: 'Invalid package name', status: HTTP_STATUS.UNPROCESSABLE_ENTITY, type: RawError}) @ApiResponse({description: 'Internal server error', status: HTTP_STATUS.INTERNAL_SERVER_ERROR, type: RawError}) @Get(':packageName') diff --git a/src/swagger.ts b/src/swagger.ts index 15e9ac2a..419e083d 100644 --- a/src/swagger.ts +++ b/src/swagger.ts @@ -19,6 +19,16 @@ export class RawError { message!: string; } +export class RawErrorWithPackageInfo extends RawError { + @ApiPropertyOptional({ + additionalProperties: true, + description: + 'Metadata from npm for the requested package/version (for example name and version). Returned when no valid source URL can be resolved.', + type: Object, + }) + packageInfo?: Record; +} + export class RawResult { @ApiProperty() code!: number;