92 lines
2.3 KiB
JavaScript
92 lines
2.3 KiB
JavaScript
import ky from 'ky';
|
|
import registryUrl from 'registry-url';
|
|
import registryAuthToken from 'registry-auth-token';
|
|
import semver from 'semver';
|
|
|
|
export class PackageNotFoundError extends Error {
|
|
constructor(packageName) {
|
|
super(`Package \`${packageName}\` could not be found`);
|
|
this.name = 'PackageNotFoundError';
|
|
}
|
|
}
|
|
|
|
export class VersionNotFoundError extends Error {
|
|
constructor(packageName, version) {
|
|
super(`Version \`${version}\` for package \`${packageName}\` could not be found`);
|
|
this.name = 'VersionNotFoundError';
|
|
}
|
|
}
|
|
|
|
export default async function packageJson(packageName, options = {}) {
|
|
let {version = 'latest'} = options;
|
|
const {omitDeprecated = true} = options;
|
|
|
|
const scope = packageName.split('/')[0];
|
|
const registryUrl_ = options.registryUrl ?? registryUrl(scope);
|
|
const packageUrl = new URL(encodeURIComponent(packageName).replace(/^%40/, '@'), registryUrl_);
|
|
const authInfo = registryAuthToken(registryUrl_.toString(), {recursive: true});
|
|
|
|
const headers = {
|
|
accept: 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*',
|
|
};
|
|
|
|
if (options.fullMetadata) {
|
|
delete headers.accept;
|
|
}
|
|
|
|
if (authInfo) {
|
|
headers.authorization = `${authInfo.type} ${authInfo.token}`;
|
|
}
|
|
|
|
let data;
|
|
try {
|
|
data = await ky(packageUrl, {headers, keepalive: true}).json();
|
|
} catch (error) {
|
|
if (error?.response?.status === 404) {
|
|
throw new PackageNotFoundError(packageName);
|
|
}
|
|
|
|
throw error;
|
|
}
|
|
|
|
if (options.allVersions) {
|
|
return data;
|
|
}
|
|
|
|
const versionError = new VersionNotFoundError(packageName, version);
|
|
|
|
if (data['dist-tags'][version]) {
|
|
const {time} = data;
|
|
data = data.versions[data['dist-tags'][version]];
|
|
data.time = time;
|
|
} else if (version) {
|
|
const versionExists = Boolean(data.versions[version]);
|
|
|
|
if (omitDeprecated && !versionExists) {
|
|
for (const [metadataVersion, metadata] of Object.entries(data.versions)) {
|
|
if (metadata.deprecated) {
|
|
delete data.versions[metadataVersion];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!versionExists) {
|
|
const versions = Object.keys(data.versions);
|
|
version = semver.maxSatisfying(versions, version);
|
|
|
|
if (!version) {
|
|
throw versionError;
|
|
}
|
|
}
|
|
|
|
const {time} = data;
|
|
data = data.versions[version];
|
|
data.time = time;
|
|
|
|
if (!data) {
|
|
throw versionError;
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|