pax_global_header00006660000000000000000000000064144423536570014527gustar00rootroot0000000000000052 comment=0b9859ad8c814782d62cdedd8227787589f798d5 package-json-8.1.1/000077500000000000000000000000001444235365700141005ustar00rootroot00000000000000package-json-8.1.1/.editorconfig000066400000000000000000000002571444235365700165610ustar00rootroot00000000000000root = true [*] indent_style = tab end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.yml] indent_style = space indent_size = 2 package-json-8.1.1/.gitattributes000066400000000000000000000000231444235365700167660ustar00rootroot00000000000000* text=auto eol=lf package-json-8.1.1/.github/000077500000000000000000000000001444235365700154405ustar00rootroot00000000000000package-json-8.1.1/.github/funding.yml000066400000000000000000000001661444235365700176200ustar00rootroot00000000000000github: sindresorhus open_collective: sindresorhus tidelift: npm/package-json custom: https://sindresorhus.com/donate package-json-8.1.1/.github/security.md000066400000000000000000000002631444235365700176320ustar00rootroot00000000000000# Security Policy To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. package-json-8.1.1/.github/workflows/000077500000000000000000000000001444235365700174755ustar00rootroot00000000000000package-json-8.1.1/.github/workflows/main.yml000066400000000000000000000006451444235365700211510ustar00rootroot00000000000000name: CI on: - push - pull_request jobs: test: name: Node.js ${{ matrix.node-version }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: node-version: - 16 - 14 steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - run: npm install - run: npm test package-json-8.1.1/.gitignore000066400000000000000000000000271444235365700160670ustar00rootroot00000000000000node_modules yarn.lock package-json-8.1.1/.npmrc000066400000000000000000000004271444235365700152230ustar00rootroot00000000000000package-lock=false @mockscope:registry=http://localhost:63142 //localhost:63142/:_authToken=MySecretToken @mockscope2:registry=http://localhost:63143 //localhost:63143/:username=Aladdin //localhost:63143/:_password=T3BlblNlc2FtZQ== @mockscope3:registry=http://localhost:63144 package-json-8.1.1/index.d.ts000066400000000000000000000123361444235365700160060ustar00rootroot00000000000000import {Agent as HttpAgent} from 'node:http'; import {Agent as HttpsAgent} from 'node:https'; import {Agents} from 'got'; /** The error thrown when the given package version cannot be found. */ export class VersionNotFoundError extends Error { readonly name: 'VersionNotFoundError'; constructor(packageName: string, version: string); } /** The error thrown when the given package name cannot be found. */ export class PackageNotFoundError extends Error { readonly name: 'PackageNotFoundError'; constructor(packageName: string); } export type Options = { /** Package version such as `1.0.0` or a [dist tag](https://docs.npmjs.com/cli/dist-tag) such as `latest`. The version can also be in any format supported by the [semver](https://github.com/npm/node-semver) module. For example: - `1` - Get the latest `1.x.x` - `1.2` - Get the latest `1.2.x` - `^1.2.3` - Get the latest `1.x.x` but at least `1.2.3` - `~1.2.3` - Get the latest `1.2.x` but at least `1.2.3` @default 'latest' */ readonly version?: string; /** By default, only an abbreviated metadata object is returned for performance reasons. [Read more.](https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md) @default false */ readonly fullMetadata?: boolean; /** Return the [main entry](https://registry.npmjs.org/ava) containing all versions. @default false */ readonly allVersions?: boolean; /** The registry URL is by default inferred from the npm defaults and `.npmrc`. This is beneficial as `package-json` and any project using it will work just like npm. This option is*only** intended for internal tools. You should __not__ use this option in reusable packages. Prefer just using `.npmrc` whenever possible. */ readonly registryUrl?: string; /** Overwrite the `agent` option that is passed down to [`got`](https://github.com/sindresorhus/got#agent). This might be useful to add [proxy support](https://github.com/sindresorhus/got#proxies). */ readonly agent?: Agents; }; export type FullMetadataOptions = { /** By default, only an abbreviated metadata object is returned for performance reasons. [Read more.](https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md) @default false */ readonly fullMetadata: true; } & Options; interface DistTags { readonly [tagName: string]: string; readonly latest: string; } interface AbbreviatedVersion { readonly [key: string]: unknown; readonly name: string; readonly version: string; readonly dist: { readonly shasum: string; readonly tarball: string; readonly integrity?: string; }; readonly deprecated?: string; readonly dependencies?: Readonly>; readonly optionalDependencies?: Readonly>; readonly devDependencies?: Readonly>; readonly bundleDependencies?: Readonly>; readonly peerDependencies?: Readonly>; readonly bin?: Readonly>; readonly directories?: readonly string[]; readonly engines?: Readonly>; readonly _hasShrinkwrap?: boolean; } interface Person { readonly name?: string; readonly email?: string; readonly url?: string; } interface HoistedData { readonly author?: Person; readonly bugs?: | {readonly url: string; readonly email?: string} | {readonly url?: string; readonly email: string}; readonly contributors?: readonly Person[]; readonly description?: string; readonly homepage?: string; readonly keywords?: readonly string[]; readonly license?: string; readonly maintainers?: readonly Person[]; readonly readme?: string; readonly readmeFilename?: string; readonly repository?: {readonly type: string; readonly url: string}; } interface FullVersion extends AbbreviatedVersion, HoistedData { readonly [key: string]: unknown; readonly _id: string; readonly _nodeVersion: string; readonly _npmUser: string; readonly _npmVersion: string; readonly main?: string; readonly files?: readonly string[]; readonly man?: readonly string[]; readonly scripts?: Readonly>; readonly gitHead?: string; readonly types?: string; readonly typings?: string; } export interface FullMetadata extends AbbreviatedMetadata, HoistedData { readonly [key: string]: unknown; readonly _id: string; readonly _rev: string; readonly time: { readonly [version: string]: string; readonly created: string; readonly modified: string; }; readonly users?: Readonly>; readonly versions: Readonly>; } export interface AbbreviatedMetadata { readonly [key: string]: unknown; readonly 'dist-tags': DistTags; readonly modified: string; readonly name: string; readonly versions: Readonly>; } /** Get metadata of a package from the npm registry. @param packageName - Name of the package. @example ``` import packageJson from 'package-json'; console.log(await packageJson('ava')); //=> {name: 'ava', …} // Also works with scoped packages console.log(await packageJson('@sindresorhus/df')); ``` */ export default function packageJson(packageName: string, options: FullMetadataOptions): Promise; export default function packageJson(packageName: string, options?: Options): Promise; package-json-8.1.1/index.js000066400000000000000000000050301444235365700155430ustar00rootroot00000000000000import {Agent as HttpAgent} from 'node:http'; import {Agent as HttpsAgent} from 'node:https'; import got from 'got'; import registryUrl from 'registry-url'; import registryAuthToken from 'registry-auth-token'; import semver from 'semver'; // These agent options are chosen to match the npm client defaults and help with performance // See: `npm config get maxsockets` and #50 const agentOptions = { keepAlive: true, maxSockets: 50, }; const httpAgent = new HttpAgent(agentOptions); const httpsAgent = new HttpsAgent(agentOptions); 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) { options = { version: 'latest', ...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}`; } const gotOptions = { headers, agent: { http: httpAgent, https: httpsAgent, }, }; if (options.agent) { gotOptions.agent = options.agent; } let data; try { data = await got(packageUrl, gotOptions).json(); } catch (error) { if (error?.response?.statusCode === 404) { throw new PackageNotFoundError(packageName); } throw error; } if (options.allVersions) { return data; } let {version} = options; const versionError = new VersionNotFoundError(packageName, version); if (data['dist-tags'][version]) { const time = data.time; data = data.versions[data['dist-tags'][version]]; data.time = time; } else if (version) { if (!data.versions[version]) { const versions = Object.keys(data.versions); version = semver.maxSatisfying(versions, version); if (!version) { throw versionError; } } const time = data.time; data = data.versions[version]; data.time = time; if (!data) { throw versionError; } } return data; } package-json-8.1.1/index.test-d.ts000066400000000000000000000026201444235365700167560ustar00rootroot00000000000000import {expectType} from 'tsd'; import packageJson, { FullMetadata, FullVersion, AbbreviatedMetadata, AbbreviatedVersion, PackageNotFoundError, VersionNotFoundError, } from './index.js'; expectType>(packageJson('package-json')); expectType>( packageJson('package-json', {version: '1.2.3'}), ); expectType>( packageJson('package-json', {allVersions: true}), ); expectType>( packageJson('package-json', {fullMetadata: true}), ); const abbreviatedMetadata = await packageJson('package-json'); expectType(abbreviatedMetadata.versions['1.2.3']); const fullMetadata = await packageJson('package-json', {fullMetadata: true}); expectType(fullMetadata.versions['1.2.3']); expectType(PackageNotFoundError); expectType(VersionNotFoundError); const packageNotFoundError = new PackageNotFoundError('foo'); packageNotFoundError instanceof PackageNotFoundError; // eslint-disable-line @typescript-eslint/no-unused-expressions expectType(packageNotFoundError); const versionNotFoundError = new VersionNotFoundError('foo', 'bar'); versionNotFoundError instanceof VersionNotFoundError; // eslint-disable-line @typescript-eslint/no-unused-expressions expectType(versionNotFoundError); package-json-8.1.1/license000066400000000000000000000021351444235365700154460ustar00rootroot00000000000000MIT License Copyright (c) Sindre Sorhus (https://sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. package-json-8.1.1/package.json000066400000000000000000000017251444235365700163730ustar00rootroot00000000000000{ "name": "package-json", "version": "8.1.1", "description": "Get metadata of a package from the npm registry", "license": "MIT", "repository": "sindresorhus/package-json", "funding": "https://github.com/sponsors/sindresorhus", "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", "url": "https://sindresorhus.com" }, "type": "module", "exports": "./index.js", "types": "./index.d.ts", "engines": { "node": ">=14.16" }, "scripts": { "//test": "xo && ava && tsd", "test": "ava && tsd" }, "files": [ "index.js", "index.d.ts" ], "keywords": [ "npm", "registry", "package", "pkg", "package.json", "json", "module", "scope", "scoped" ], "dependencies": { "got": "^12.1.0", "registry-auth-token": "^5.0.1", "registry-url": "^6.0.0", "semver": "^7.3.7" }, "devDependencies": { "@types/node": "^17.0.40", "ava": "^4.3.0", "mock-private-registry": "^1.1.2", "tsd": "^0.20.0", "xo": "^0.49.0" } } package-json-8.1.1/readme.md000066400000000000000000000055011444235365700156600ustar00rootroot00000000000000# package-json > Get metadata of a package from the npm registry ## Install ```sh npm install package-json ``` ## Usage ```js import packageJson from 'package-json'; console.log(await packageJson('ava')); //=> {name: 'ava', …} // Also works with scoped packages console.log(await packageJson('@sindresorhus/df')); ``` ## API ### packageJson(packageName, options?) #### packageName Type: `string` Name of the package. #### options Type: `object` ##### version Type: `string`\ Default: `latest` Package version such as `1.0.0` or a [dist tag](https://docs.npmjs.com/cli/dist-tag) such as `latest`. The version can also be in any format supported by the [semver](https://github.com/npm/node-semver) module. For example: - `1` - Get the latest `1.x.x` - `1.2` - Get the latest `1.2.x` - `^1.2.3` - Get the latest `1.x.x` but at least `1.2.3` - `~1.2.3` - Get the latest `1.2.x` but at least `1.2.3` ##### fullMetadata Type: `boolean`\ Default: `false` By default, only an abbreviated metadata object is returned for performance reasons. [Read more.](https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md) ##### allVersions Type: `boolean`\ Default: `false` Return the [main entry](https://registry.npmjs.org/ava) containing all versions. ##### registryUrl Type: `string`\ Default: Auto-detected The registry URL is by default inferred from the npm defaults and `.npmrc`. This is beneficial as `package-json` and any project using it will work just like npm. This option is **only** intended for internal tools. You should **not** use this option in reusable packages. Prefer just using `.npmrc` whenever possible. ##### agent Type: `object` Overwrite the `agent` option that is passed down to [`got`](https://github.com/sindresorhus/got#agent). This might be useful to add [proxy support](https://github.com/sindresorhus/got#proxies). ### PackageNotFoundError The error thrown when the given package name cannot be found. ### VersionNotFoundError The error thrown when the given package version cannot be found. ## Authentication Both public and private registries are supported, for both scoped and unscoped packages, as long as the registry uses either bearer tokens or basic authentication. ## Related - [package-json-cli](https://github.com/sindresorhus/package-json-cli) - CLI for this module - [latest-version](https://github.com/sindresorhus/latest-version) - Get the latest version of an npm package - [pkg-versions](https://github.com/sindresorhus/pkg-versions) - Get the version numbers of a package from the npm registry - [npm-keyword](https://github.com/sindresorhus/npm-keyword) - Get a list of npm packages with a certain keyword - [npm-user](https://github.com/sindresorhus/npm-user) - Get user info of an npm user - [npm-email](https://github.com/sindresorhus/npm-email) - Get the email of an npm user package-json-8.1.1/test.js000066400000000000000000000072131444235365700154200ustar00rootroot00000000000000import {promisify} from 'node:util'; import http from 'node:http'; import test from 'ava'; import privateRegistry from 'mock-private-registry/promise.js'; import packageJson, {PackageNotFoundError, VersionNotFoundError} from './index.js'; test('latest version', async t => { const json = await packageJson('ava'); t.is(json.name, 'ava'); t.falsy(json.versions); }); test('full metadata', async t => { const json = await packageJson('pageres', { fullMetadata: true, version: '4.4.0', }); t.is(json.name, 'pageres'); t.is(json._id, 'pageres@4.4.0'); t.is(json.time.created, '2014-02-07T18:17:46.737Z'); t.is(json.time.modified, '2022-10-27T08:57:30.321Z'); }); test('all version', async t => { const json = await packageJson('pageres', {allVersions: true}); t.is(json.name, 'pageres'); t.is(json.versions['0.1.0'].name, 'pageres'); }); test('specific version', async t => { const json = await packageJson('pageres', {version: '0.1.0'}); t.is(json.version, '0.1.0'); }); test('incomplete version x', async t => { const json = await packageJson('pageres', {version: '0'}); t.is(json.version.slice(0, 2), '0.'); }); // TODO: Find an alternative npm instance. // test.failing('custom registry url', async t => { // const json = await packageJson('ava', {registryUrl: 'https://npm.open-registry.dev/'}); // t.is(json.name, 'ava'); // t.falsy(json.versions); // }); test('scoped - latest version', async t => { const json = await packageJson('@sindresorhus/df'); t.is(json.name, '@sindresorhus/df'); }); test('scoped - full metadata', async t => { const json = await packageJson('@sindresorhus/df', { fullMetadata: true, version: '1.0.1', }); t.is(json.name, '@sindresorhus/df'); t.is(json._id, '@sindresorhus/df@1.0.1'); t.is(json.time.created, '2015-05-04T18:10:02.416Z'); t.is(json.time.modified, '2022-06-12T23:49:38.166Z'); }); test('scoped - all version', async t => { const json = await packageJson('@sindresorhus/df', {allVersions: true}); t.is(json.name, '@sindresorhus/df'); t.is(json.versions['1.0.1'].name, '@sindresorhus/df'); }); test('scoped - specific version', async t => { const json = await packageJson('@sindresorhus/df', {version: '1.0.1'}); t.is(json.version, '1.0.1'); }); test('scoped - dist tag', async t => { const json = await packageJson('@rexxars/npmtest', {version: 'next'}); t.is(json.version, '2.0.0'); }); test('reject when package doesn\'t exist', async t => { await t.throwsAsync(packageJson('nnnope'), {instanceOf: PackageNotFoundError}); }); test('reject when version doesn\'t exist', async t => { await t.throwsAsync(packageJson('hapi', {version: '6.6.6'}), {instanceOf: VersionNotFoundError}); }); test('does not send any auth token for unconfigured registries', async t => { const server = http.createServer((request, response) => { response.end(JSON.stringify({headers: request.headers, 'dist-tags': {}})); }); await promisify(server.listen.bind(server))(63_144, '127.0.0.1'); const json = await packageJson('@mockscope3/foobar', {allVersions: true}); t.is(json.headers.host, 'localhost:63144'); t.is(json.headers.authorization, undefined); await promisify(server.close.bind(server))(); }); test('private registry (bearer token)', async t => { const server = await privateRegistry(); const json = await packageJson('@mockscope/foobar'); t.is(json.name, '@mockscope/foobar'); server.close(); }); test('private registry (basic token)', async t => { const server = await privateRegistry({ port: 63_143, pkgName: '@mockscope2/foobar', token: 'QWxhZGRpbjpPcGVuU2VzYW1l', tokenType: 'Basic', }); const json = await packageJson('@mockscope2/foobar'); t.is(json.name, '@mockscope2/foobar'); server.close(); });