UNPKG

30.9 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var validatePackageName = require('validate-npm-package-name');
6var makeError = require('make-error');
7var unfetch = require('isomorphic-unfetch');
8var lru = require('tiny-lru');
9var urlJoin = require('url-join');
10var gitUrlParse = require('git-url-parse');
11
12function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
14function _interopNamespace(e) {
15 if (e && e.__esModule) return e;
16 var n = Object.create(null);
17 if (e) {
18 Object.keys(e).forEach(function (k) {
19 if (k !== 'default') {
20 var d = Object.getOwnPropertyDescriptor(e, k);
21 Object.defineProperty(n, k, d.get ? d : {
22 enumerable: true,
23 get: function () { return e[k]; }
24 });
25 }
26 });
27 }
28 n["default"] = e;
29 return n;
30}
31
32var validatePackageName__default = /*#__PURE__*/_interopDefaultLegacy(validatePackageName);
33var makeError__default = /*#__PURE__*/_interopDefaultLegacy(makeError);
34var unfetch__default = /*#__PURE__*/_interopDefaultLegacy(unfetch);
35var lru__default = /*#__PURE__*/_interopDefaultLegacy(lru);
36var urlJoin__default = /*#__PURE__*/_interopDefaultLegacy(urlJoin);
37var gitUrlParse__default = /*#__PURE__*/_interopDefaultLegacy(gitUrlParse);
38
39/**
40 * npm registry
41 *
42 * @see {@link https://registry.npmjs.org}
43 */
44const npmRegistry = 'https://registry.npmjs.org';
45/**
46 * npm registry mirror by Cloudflare
47 *
48 * @remarks
49 * This registry has CORS enabled and can be used to retrieve
50 * package manifests and packuments in the browser.
51 *
52 * @see {@link https://npmjs.cf}
53 * @see {@link https://registry.npmjs.cf}
54 */
55
56const cloudflareRegistry = 'https://registry.npmjs.cf';
57/**
58 * npm registry mirror by Yarn
59 *
60 * @see {@link https://registry.yarnpkg.com}
61 */
62
63const yarnRegistry = 'https://registry.yarnpkg.com';
64/**
65 * Mirrors of the npm registry.
66 *
67 * @see {@link cloudflareRegistry}
68 * @see {@link yarnRegistry}
69 */
70
71const npmRegistryMirrors = [cloudflareRegistry, yarnRegistry];
72/**
73 * Downloads API for the npm registry
74 *
75 * @see {@link https://api.npmjs.org}
76 */
77
78const npmRegistryDownloadsAPI = 'https://api.npmjs.org';
79
80function normalizeRawAbbreviatedPackument({
81 rawAbbreviatedPackument
82}) {
83 const {
84 'dist-tags': distTags,
85 name: id,
86 modified: modifiedAt
87 } = rawAbbreviatedPackument;
88 return { ...rawAbbreviatedPackument,
89 id,
90 distTags,
91 modifiedAt
92 };
93}
94
95/**
96 * `FetchError` represents an error that happened when fetching a URL.
97 *
98 * The `instanceof` operator can be used to check for this error.
99 */
100
101class FetchError extends makeError.BaseError {
102 constructor(
103 /** URL originally fetched */
104 url,
105 /** Response received */
106 response) {
107 super(`fetch: request to ${url} failed with status ${response.statusText}`);
108 this.url = void 0;
109 this.response = void 0;
110 this.url = url;
111 this.response = response;
112 }
113
114}
115/**
116 * `InvalidPackageNameError` is thrown when the name of a package
117 * is not valid according to the npm registry naming rules.
118 *
119 * The `instanceof` operator can be used to check for this error.
120 *
121 * @see {@link https://www.npmjs.com/package/validate-npm-package-name}
122 */
123
124const InvalidPackageNameError = /*#__PURE__*/makeError__default["default"]('InvalidPackageNameError');
125/**
126 * `InvalidPackageVersionError` is thrown when a package's version does not exist.
127 *
128 * The `instanceof` operator can be used to check for this error.
129 */
130
131const InvalidPackageVersionError = /*#__PURE__*/makeError__default["default"]('InvalidPackageVersionError');
132
133async function log(formatter, ...args) {
134 {
135 try {
136 const {
137 debug
138 } = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('debug')); });
139 const logger = debug('query-registry');
140 logger(formatter, args);
141 } catch {}
142 }
143}
144
145function assertValidPackageName({
146 name
147}) {
148 const {
149 validForOldPackages,
150 validForNewPackages
151 } = validatePackageName__default["default"](name);
152 const valid = validForOldPackages || validForNewPackages;
153
154 if (!valid) {
155 log('assertValidPackageName: invalid package name: %O', {
156 name
157 });
158 throw new InvalidPackageNameError(`invalid package name: '${name}'`);
159 }
160}
161
162const maxItems = 250;
163const fiveMinutesTTL = 5 * 60 * 1000;
164const cache = /*#__PURE__*/lru__default["default"](maxItems, fiveMinutesTTL);
165async function fetch({
166 url,
167 headers,
168 cached = true
169}) {
170 const cacheKey = `headers=${JSON.stringify(headers)};url=${url}`;
171 const cachedJSON = cache.get(cacheKey);
172
173 if (cached && cachedJSON) {
174 log('fetch: returning cached response: %O', {
175 cacheKey,
176 url,
177 cachedJSON
178 });
179 return cachedJSON;
180 }
181
182 const response = await unfetch__default["default"](url, {
183 headers
184 });
185
186 if (!response.ok) {
187 log('fetch: request failed: %O', {
188 url,
189 headers,
190 status: response.statusText,
191 response
192 });
193 throw new FetchError(url, response);
194 }
195
196 const json = await response.json();
197
198 if (cached) {
199 cache.set(cacheKey, json);
200 }
201
202 log('fetch: returning fresh response: %O', {
203 url,
204 json
205 });
206 return json;
207}
208
209async function fetchFromRegistry({
210 endpoint,
211 headers,
212 query,
213 registry = npmRegistry,
214 mirrors = npmRegistryMirrors,
215 cached
216}) {
217 const urls = [registry, ...mirrors].map(base => urlJoin__default["default"](base, endpoint, query ? `?${query}` : ''));
218 let lastError;
219
220 for (const url of urls) {
221 try {
222 const json = await fetch({
223 url,
224 headers,
225 cached
226 });
227 return json;
228 } catch (err) {
229 // Keep last fetch error
230 lastError = err;
231 }
232 }
233
234 log('fetchFromRegistry: cannot retrieve data from registry or mirrors: %O', {
235 endpoint,
236 headers,
237 query,
238 registry,
239 mirrors,
240 lastError
241 });
242 throw lastError;
243}
244
245/**
246 * `getRawAbbreviatedPackument` returns the abbreviated packument (package document)
247 * containing only the metadata necessary to install a package present on the registry.
248 *
249 * Note: the abbreviated packument is returned as retrieved from the registry.
250 *
251 * @param name - package name
252 * @param registry - URL of the registry (default: npm registry)
253 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
254 * @param cached - accept cached responses (default: `true`)
255 *
256 * @example
257 * Get the abbreviated packument for package `query-registry` from the npm registry:
258 *
259 * ```typescript
260 * import { getRawAbbreviatedPackument } from 'query-registry';
261 *
262 * (async () => {
263 * const packument = await getRawAbbreviatedPackument({ name: 'query-registry' });
264 *
265 * // Output: 'query-registry'
266 * console.log(packument.name);
267 * })();
268 * ```
269 *
270 * @see {@link RawAbbreviatedPackument}
271 * @see {@link npmRegistry}
272 * @see {@link npmRegistryMirrors}
273 */
274
275async function getRawAbbreviatedPackument({
276 name,
277 registry,
278 mirrors,
279 cached
280}) {
281 assertValidPackageName({
282 name
283 });
284 const endpoint = `/${name}`;
285 const headers = {
286 Accept: 'application/vnd.npm.install-v1+json'
287 };
288 return fetchFromRegistry({
289 endpoint,
290 headers,
291 registry,
292 mirrors,
293 cached
294 });
295}
296
297/**
298 * `getAbbreviatedPackument` returns the abbreviated packument (package document)
299 * containing only the metadata necessary to install a package present on the registry.
300 *
301 * @remarks
302 * To get all the metadata (full packument) about a package see {@link getPackument}.
303 *
304 * @param name - package name
305 * @param registry - URL of the registry (default: npm registry)
306 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
307 * @param cached - accept cached responses (default: `true`)
308 *
309 * @example
310 * Get the abbreviated packument for package `query-registry` from the npm registry:
311 *
312 * ```typescript
313 * import { getAbbreviatedPackument } from 'query-registry';
314 *
315 * (async () => {
316 * const packument = await getAbbreviatedPackument({ name: 'query-registry' });
317 *
318 * // Output: 'query-registry'
319 * console.log(packument.name);
320 * })();
321 * ```
322 *
323 * @see {@link AbbreviatedPackument}
324 * @see {@link RawAbbreviatedPackument}
325 * @see {@link npmRegistry}
326 * @see {@link npmRegistryMirrors}
327 */
328
329async function getAbbreviatedPackument({
330 name,
331 registry,
332 mirrors,
333 cached
334}) {
335 const rawAbbreviatedPackument = await getRawAbbreviatedPackument({
336 name,
337 registry,
338 mirrors,
339 cached
340 });
341 return normalizeRawAbbreviatedPackument({
342 rawAbbreviatedPackument
343 });
344}
345
346async function fetchDownloadsFromRegistry({
347 endpoint,
348 registryDownloadsAPI = npmRegistryDownloadsAPI,
349 cached
350}) {
351 return fetchFromRegistry({
352 endpoint,
353 registry: registryDownloadsAPI,
354 mirrors: [],
355 cached
356 });
357}
358
359function normalizeRawDownloadPeriod({
360 rawDownloadPeriod = 'last-week'
361}) {
362 if (typeof rawDownloadPeriod === 'string') {
363 return rawDownloadPeriod;
364 }
365
366 if (rawDownloadPeriod instanceof Date) {
367 return getDay(rawDownloadPeriod);
368 }
369
370 const {
371 start,
372 end
373 } = rawDownloadPeriod;
374 return `${getDay(start)}:${getDay(end)}`;
375}
376
377function getDay(date) {
378 return date.toISOString().split('T')[0];
379}
380
381/**
382 * `getDailyPackageDownloads` returns the number of downloads for a package
383 * for each day in a given time period.
384 *
385 * @param name - package name
386 * @param period - time period in which downloads happened (default: `last-week`)
387 * @param registryDownloadsAPI - URL of the registry's downloads API (default: npm registry)
388 * @param cached - accept cached responses (default: `true`)
389 *
390 * @example
391 * Get the day by day weekly downloads for package `query-registry` from the npm registry:
392 *
393 * ```typescript
394 * import { getDailyPackageDownloads } from 'query-registry';
395 *
396 * (async () => {
397 * const downloads = await getDailyPackageDownloads({ name: 'query-registry' });
398 *
399 * // Output: 'query-registry'
400 * console.log(downloads.package);
401 *
402 * // Output: 'number'
403 * console.log(typeof downloads.downloads[0].downloads);
404 * })();
405 * ```
406 *
407 * @example
408 * Get the day by day monthly downloads for package `query-registry` from the npm registry:
409 *
410 * ```typescript
411 * import { getDailyPackageDownloads } from 'query-registry';
412 *
413 * (async () => {
414 * const downloads = await getDailyPackageDownloads({ name: 'query-registry', period: 'last-month' });
415 *
416 * // Output: 'query-registry'
417 * console.log(downloads.package);
418 *
419 * // Output: 'number'
420 * console.log(typeof downloads.downloads[0].downloads);
421 * })();
422 * ```
423 *
424 * @see {@link DailyPackageDownloads}
425 * @see {@link DownloadPeriod}
426 * @see {@link npmRegistryDownloadsAPI}
427 * @see {@link https://github.com/npm/registry/blob/master/docs/download-counts.md#ranges}
428 */
429
430async function getDailyPackageDownloads({
431 name,
432 period: rawDownloadPeriod,
433 registryDownloadsAPI,
434 cached
435}) {
436 assertValidPackageName({
437 name
438 });
439 const period = normalizeRawDownloadPeriod({
440 rawDownloadPeriod
441 });
442 const endpoint = `/downloads/range/${period}/${name}`;
443 return fetchDownloadsFromRegistry({
444 endpoint,
445 registryDownloadsAPI,
446 cached
447 });
448}
449
450/**
451 * `getDailyRegistryDownloads` returns the number of downloads for all registry packages
452 * for each day in a given time period.
453 *
454 * @param period - time period in which downloads happened (default: `last-week`)
455 * @param registryDownloadsAPI - URL of the registry's downloads API (default: npm registry)
456 * @param cached - accept cached responses (default: `true`)
457 *
458 * @example
459 * Get the day by day weekly downloads for the npm registry:
460 *
461 * ```typescript
462 * import { getDailyRegistryDownloads } from 'query-registry';
463 *
464 * (async () => {
465 * const downloads = await getDailyRegistryDownloads();
466 *
467 * // Output: 'number'
468 * console.log(typeof downloads.downloads[0].downloads);
469 * })();
470 * ```
471 *
472 * @example
473 * Get the day by day monthly downloads for the npm registry:
474 *
475 * ```typescript
476 * import { getDailyRegistryDownloads } from 'query-registry';
477 *
478 * (async () => {
479 * const downloads = await getDailyRegistryDownloads({ period: 'last-month' });
480 *
481 * // Output: 'number'
482 * console.log(typeof downloads.downloads[0].downloads);
483 * })();
484 * ```
485 *
486 * @see {@link DailyRegistryDownloads}
487 * @see {@link DownloadPeriod}
488 * @see {@link npmRegistryDownloadsAPI}
489 * @see {@link https://github.com/npm/registry/blob/master/docs/download-counts.md#ranges}
490 */
491
492async function getDailyRegistryDownloads({
493 period: rawDownloadPeriod,
494 registryDownloadsAPI,
495 cached
496} = {}) {
497 const period = normalizeRawDownloadPeriod({
498 rawDownloadPeriod
499 });
500 const endpoint = `/downloads/range/${period}`;
501 return fetchDownloadsFromRegistry({
502 endpoint,
503 registryDownloadsAPI,
504 cached
505 });
506}
507
508/**
509 * `getPackageDownloads` returns the number of downloads for a package
510 * in a given time period.
511 *
512 * @param name - package name
513 * @param period - time period in which downloads happened (default: `last-week`)
514 * @param registryDownloadsAPI - URL of the registry's downloads API (default: npm registry)
515 * @param cached - accept cached responses (default: `true`)
516 *
517 * @example
518 * Get the weekly downloads for package `query-registry` from the npm registry:
519 *
520 * ```typescript
521 * import { getPackageDownloads } from 'query-registry';
522 *
523 * (async () => {
524 * const downloads = await getPackageDownloads({ name: 'query-registry' });
525 *
526 * // Output: 'query-registry'
527 * console.log(downloads.package);
528 *
529 * // Output: 'number'
530 * console.log(typeof downloads.downloads);
531 * })();
532 * ```
533 *
534 * @example
535 * Get the monthly downloads for package `query-registry` from the npm registry:
536 *
537 * ```typescript
538 * import { getPackageDownloads } from 'query-registry';
539 *
540 * (async () => {
541 * const downloads = await getPackageDownloads({ name: 'query-registry', period: 'last-month' });
542 *
543 * // Output: 'query-registry'
544 * console.log(downloads.package);
545 *
546 * // Output: 'number'
547 * console.log(typeof downloads.downloads);
548 * })();
549 * ```
550 *
551 * @see {@link PackageDownloads}
552 * @see {@link DownloadPeriod}
553 * @see {@link npmRegistryDownloadsAPI}
554 * @see {@link https://github.com/npm/registry/blob/master/docs/download-counts.md#point-values}
555 */
556
557async function getPackageDownloads({
558 name,
559 period: rawDownloadPeriod,
560 registryDownloadsAPI,
561 cached
562}) {
563 assertValidPackageName({
564 name
565 });
566 const period = normalizeRawDownloadPeriod({
567 rawDownloadPeriod
568 });
569 const endpoint = `/downloads/point/${period}/${name}`;
570 return fetchDownloadsFromRegistry({
571 endpoint,
572 registryDownloadsAPI,
573 cached
574 });
575}
576
577function extractRawPackageManifest({
578 rawPackument,
579 version = 'latest'
580}) {
581 var _distTags$version;
582
583 const {
584 name,
585 'dist-tags': distTags,
586 versions
587 } = rawPackument;
588 const versionNumber = (_distTags$version = distTags[version]) != null ? _distTags$version : version;
589 const manifest = versions[versionNumber];
590
591 if (!manifest) {
592 log('getPackageManifest: invalid package version: %O', {
593 name,
594 version
595 });
596 throw new InvalidPackageVersionError(`invalid package version: '${name}@${version}'`);
597 }
598
599 return manifest;
600}
601
602/**
603 * `getRawPackument` returns the packument (package document) containing
604 * all the metadata about a package present on the registry.
605 *
606 * Note: the packument is returned as retrieved from the registry.
607 *
608 * @param name - package name
609 * @param registry - URL of the registry (default: npm registry)
610 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
611 * @param cached - accept cached responses (default: `true`)
612 *
613 * @example
614 * Get the packument for package `query-registry` from the npm registry:
615 *
616 * ```typescript
617 * import { getRawPackument } from 'query-registry';
618 *
619 * (async () => {
620 * const packument = await getRawPackument({ name: 'query-registry' });
621 *
622 * // Output: 'query-registry'
623 * console.log(packument.name);
624 * })();
625 * ```
626 *
627 * @see {@link RawPackument}
628 * @see {@link npmRegistry}
629 * @see {@link npmRegistryMirrors}
630 */
631
632async function getRawPackument({
633 name,
634 registry,
635 mirrors,
636 cached
637}) {
638 assertValidPackageName({
639 name
640 });
641 const endpoint = `/${name}`;
642 return fetchFromRegistry({
643 endpoint,
644 registry,
645 mirrors,
646 cached
647 });
648}
649
650/**
651 * `getRawPackageManifest` returns the manifest describing
652 * a specific version of a package.
653 *
654 * Note: the manifest is returned as retrieved from the registry.
655 *
656 * @param name - package name
657 * @param version - package version (default: `latest`)
658 * @param registry - URL of the registry (default: npm registry)
659 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
660 * @param cached - accept cached responses (default: `true`)
661 *
662 * @example
663 * Get the latest manifest for package `query-registry` from the npm registry:
664 *
665 * ```typescript
666 * import { getRawPackageManifest } from 'query-registry';
667 *
668 * (async () => {
669 * const manifest = await getRawPackageManifest({ name: 'query-registry' });
670 *
671 * // Output: 'query-registry'
672 * console.log(manifest.name);
673 * })();
674 * ```
675 *
676 * @example
677 * Get the manifest for package `query-registry@1.0.0` from the npm registry:
678 *
679 * ```typescript
680 * import { getRawPackageManifest } from 'query-registry';
681 *
682 * (async () => {
683 * const manifest = await getRawPackageManifest({ name: 'query-registry', version: '1.0.0' });
684 *
685 * // Output: 'query-registry'
686 * console.log(manifest.name);
687 *
688 * // Output: '1.0.0'
689 * console.log(manifest.version);
690 * })();
691 * ```
692 *
693 * @see {@link RawPackageManifest}
694 * @see {@link npmRegistry}
695 * @see {@link npmRegistryMirrors}
696 */
697
698async function getRawPackageManifest({
699 name,
700 version,
701 registry,
702 mirrors,
703 cached
704}) {
705 const rawPackument = await getRawPackument({
706 name,
707 registry,
708 mirrors,
709 cached
710 });
711 return extractRawPackageManifest({
712 rawPackument,
713 version
714 });
715}
716
717async function getDefinitelyTypedName({
718 rawPackageManifest,
719 registry,
720 mirrors,
721 cached
722}) {
723 const {
724 name,
725 types,
726 typings
727 } = rawPackageManifest;
728 const definitelyTypedName = toDefinitelyTypedName({
729 name
730 });
731 const alreadyTyped = name === definitelyTypedName || !!types || !!typings;
732
733 if (alreadyTyped) {
734 return undefined;
735 }
736
737 let ok = false;
738
739 try {
740 const {
741 deprecated
742 } = await getRawPackageManifest({
743 name: definitelyTypedName,
744 registry,
745 mirrors,
746 cached
747 });
748 ok = deprecated === undefined;
749 } catch {}
750
751 return ok ? definitelyTypedName : undefined;
752}
753/**
754 * `toDefinitelyTypedName` returns the name of the corresponding
755 * DefinitelyTyped package (for example,
756 * `foo` => `@types/foo`,
757 * `@bar/baz` => `@types/bar__baz`).
758 */
759
760function toDefinitelyTypedName({
761 name
762}) {
763 return name.startsWith('@types/') ? name : `@types/${name.replace('@', '').replace('/', '__')}`;
764}
765
766/**
767 * `getUntypedName` returns the name of the normal package
768 * corresponding to a DefinitelyTyped package.
769 */
770function getUntypedName({
771 name
772}) {
773 if (!name.startsWith('@types/')) {
774 return undefined;
775 } // ['foo', undefined] or ['@bar', 'baz']
776
777
778 const [scopeOrName, scopedName] = name.replace('@types/', '').split('__');
779 return scopedName ? `@${scopeOrName}/${scopedName}` : scopeOrName;
780}
781
782function normalizeRawLicense({
783 rawLicense
784}) {
785 if (!rawLicense) {
786 return undefined;
787 }
788
789 if (typeof rawLicense !== 'string') {
790 return undefined;
791 }
792
793 return rawLicense;
794}
795
796function normalizeRawRepository({
797 rawRepository
798}) {
799 if (isRepository(rawRepository)) {
800 return normalizeRepository({
801 rawRepository
802 });
803 }
804
805 if (typeof rawRepository === 'string') {
806 return normalizeRepository({
807 rawRepository: {
808 url: rawRepository
809 }
810 });
811 }
812
813 return undefined;
814}
815
816function isRepository(rawRepository) {
817 return rawRepository && typeof rawRepository === 'object' && typeof rawRepository['url'] === 'string' && ['string', 'undefined'].includes(typeof rawRepository['type']) && ['string', 'undefined'].includes(typeof rawRepository['directory']);
818}
819
820function normalizeRepository({
821 rawRepository
822}) {
823 const {
824 url,
825 directory: repositoryDir
826 } = rawRepository;
827 const info = parseGitURL({
828 url
829 });
830
831 if (!info) {
832 return undefined;
833 }
834
835 const {
836 resource,
837 full_name: repositoryID,
838 filepath
839 } = info; // Add domain to sources derived from npm-style shortcuts
840
841 const host = resource.replace(/^$/, 'github.com').replace(/^github$/, 'github.com').replace(/^gitlab$/, 'gitlab.com').replace(/^bitbucket$/, 'bitbucket.org');
842 const parsedDir = filepath !== '' ? filepath : undefined;
843 return {
844 type: 'git',
845 url: `https://${host}/${repositoryID}`,
846 directory: repositoryDir != null ? repositoryDir : parsedDir
847 };
848}
849
850function parseGitURL({
851 url
852}) {
853 let info;
854
855 try {
856 info = gitUrlParse__default["default"](url);
857 } catch {}
858
859 return info;
860}
861
862async function normalizeRawPackageManifest({
863 rawPackageManifest,
864 rawPackument,
865 registry,
866 mirrors,
867 cached
868}) {
869 const {
870 _id: id,
871 name,
872 version,
873 license: rawLicense,
874 repository: rawRepository,
875 _npmUser: publisher
876 } = rawPackageManifest;
877 const createdAt = rawPackument.time[version];
878 const license = normalizeRawLicense({
879 rawLicense
880 });
881 const gitRepository = normalizeRawRepository({
882 rawRepository
883 });
884 const definitelyTypedName = await getDefinitelyTypedName({
885 rawPackageManifest,
886 registry,
887 mirrors,
888 cached
889 });
890 const untypedName = getUntypedName({
891 name
892 });
893 return { ...rawPackageManifest,
894 id,
895 createdAt,
896 publisher,
897 license,
898 gitRepository,
899 definitelyTypedName,
900 untypedName
901 };
902}
903
904/**
905 * `getPackageManifest` returns the manifest describing
906 * a specific version of a package.
907 *
908 * @param name - package name
909 * @param version - package version (default: `latest`)
910 * @param registry - URL of the registry (default: npm registry)
911 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
912 * @param cached - accept cached responses (default: `true`)
913 *
914 * @example
915 * Get the latest manifest for package `query-registry` from the npm registry:
916 *
917 * ```typescript
918 * import { getPackageManifest } from 'query-registry';
919 *
920 * (async () => {
921 * const manifest = await getPackageManifest({ name: 'query-registry' });
922 *
923 * // Output: 'query-registry'
924 * console.log(manifest.name);
925 * })();
926 * ```
927 *
928 * @example
929 * Get the manifest for package `query-registry@1.0.0` from the npm registry:
930 *
931 * ```typescript
932 * import { getPackageManifest } from 'query-registry';
933 *
934 * (async () => {
935 * const manifest = await getPackageManifest({ name: 'query-registry', version: '1.0.0' });
936 *
937 * // Output: 'query-registry'
938 * console.log(manifest.name);
939 *
940 * // Output: '1.0.0'
941 * console.log(manifest.version);
942 * })();
943 * ```
944 *
945 * @see {@link PackageManifest}
946 * @see {@link RawPackageManifest}
947 * @see {@link npmRegistry}
948 * @see {@link npmRegistryMirrors}
949 */
950
951async function getPackageManifest({
952 name,
953 version,
954 registry,
955 mirrors,
956 cached
957}) {
958 const rawPackument = await getRawPackument({
959 name,
960 registry,
961 mirrors,
962 cached
963 });
964 const rawPackageManifest = extractRawPackageManifest({
965 rawPackument,
966 version
967 });
968 const packageManifest = await normalizeRawPackageManifest({
969 rawPackageManifest,
970 rawPackument,
971 registry,
972 mirrors,
973 cached
974 });
975 return packageManifest;
976}
977
978function normalizeRawPackument({
979 rawPackument
980}) {
981 const {
982 _id: id,
983 'dist-tags': distTags,
984 time,
985 license: rawLicense,
986 repository: rawRepository
987 } = rawPackument;
988 const license = normalizeRawLicense({
989 rawLicense
990 });
991 const gitRepository = normalizeRawRepository({
992 rawRepository
993 });
994 const versionsToTimestamps = Object.fromEntries(Object.entries(time).filter(([key]) => {
995 return !['created', 'modified'].includes(key);
996 }));
997 return { ...rawPackument,
998 id,
999 distTags,
1000 versionsToTimestamps,
1001 license,
1002 gitRepository
1003 };
1004}
1005
1006/**
1007 * `getPackument` returns the packument (package document) containing
1008 * all the metadata about a package present on the registry.
1009 *
1010 * @param name - package name
1011 * @param registry - URL of the registry (default: npm registry)
1012 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
1013 * @param cached - accept cached responses (default: `true`)
1014 *
1015 * @example
1016 * Get the packument for package `query-registry` from the npm registry:
1017 *
1018 * ```typescript
1019 * import { getPackument } from 'query-registry';
1020 *
1021 * (async () => {
1022 * const packument = await getPackument({ name: 'query-registry' });
1023 *
1024 * // Output: 'query-registry'
1025 * console.log(packument.name);
1026 * })();
1027 * ```
1028 *
1029 * @see {@link Packument}
1030 * @see {@link RawPackument}
1031 * @see {@link npmRegistry}
1032 * @see {@link npmRegistryMirrors}
1033 */
1034
1035async function getPackument({
1036 name,
1037 registry,
1038 mirrors,
1039 cached
1040}) {
1041 const rawPackument = await getRawPackument({
1042 name,
1043 registry,
1044 mirrors,
1045 cached
1046 });
1047 return normalizeRawPackument({
1048 rawPackument
1049 });
1050}
1051
1052/**
1053 * `getRegistryDownloads` returns the number of downloads for all registry packages
1054 * in a given time period.
1055 *
1056 * @param period - time period in which downloads happened (default: `last-week`)
1057 * @param registryDownloadsAPI - URL of the registry's downloads API (default: npm registry)
1058 * @param cached - accept cached responses (default: `true`)
1059 *
1060 * @example
1061 * Get the weekly downloads for the npm registry:
1062 *
1063 * ```typescript
1064 * import { getRegistryDownloads } from 'query-registry';
1065 *
1066 * (async () => {
1067 * const downloads = await getRegistryDownloads();
1068 *
1069 * // Output: 'number'
1070 * console.log(typeof downloads.downloads);
1071 * })();
1072 * ```
1073 *
1074 * @example
1075 * Get the monthly downloads for the npm registry:
1076 *
1077 * ```typescript
1078 * import { getRegistryDownloads } from 'query-registry';
1079 *
1080 * (async () => {
1081 * const downloads = await getRegistryDownloads({ period: 'last-month' });
1082 *
1083 * // Output: 'number'
1084 * console.log(typeof downloads.downloads);
1085 * })();
1086 * ```
1087 *
1088 * @see {@link RegistryDownloads}
1089 * @see {@link DownloadPeriod}
1090 * @see {@link npmRegistryDownloadsAPI}
1091 * @see {@link https://github.com/npm/registry/blob/master/docs/download-counts.md#point-values}
1092 */
1093
1094async function getRegistryDownloads({
1095 period: rawDownloadPeriod,
1096 registryDownloadsAPI,
1097 cached
1098} = {}) {
1099 const period = normalizeRawDownloadPeriod({
1100 rawDownloadPeriod
1101 });
1102 const endpoint = `/downloads/point/${period}`;
1103 return fetchDownloadsFromRegistry({
1104 endpoint,
1105 registryDownloadsAPI,
1106 cached
1107 });
1108}
1109
1110/**
1111 * `getRegistryMetadata` returns the metadata describing the registry itself.
1112 *
1113 * @param registry - URL of the registry (default: npm registry)
1114 * @param cached - accept cached responses (default: `true`)
1115 *
1116 * @example
1117 * Get the metadata for the npm registry:
1118 *
1119 * ```typescript
1120 * import { getRegistryMetadata } from 'query-registry';
1121 *
1122 * (async () => {
1123 * const metadata = await getRegistryMetadata();
1124 *
1125 * // Output: 'registry'
1126 * console.log(metadata.db_name);
1127 * })();
1128 * ```
1129 *
1130 * @example
1131 * Get the metadata for a custom registry:
1132 *
1133 * ```typescript
1134 * import { getRegistryMetadata } from 'query-registry';
1135 *
1136 * (async () => {
1137 * const metadata = await getRegistryMetadata({ registry: 'https://example.com' });
1138 * })();
1139 * ```
1140 *
1141 * @see {@link RegistryMetadata}
1142 * @see {@link npmRegistry}
1143 */
1144
1145async function getRegistryMetadata({
1146 registry,
1147 cached
1148} = {}) {
1149 const endpoint = '/';
1150 return fetchFromRegistry({
1151 registry,
1152 mirrors: [],
1153 endpoint,
1154 cached
1155 });
1156}
1157
1158function normalizeRawSearchCriteria({
1159 rawSearchCriteria
1160}) {
1161 // Convert SearchCriteria to a URL query string
1162 return Object.entries(rawSearchCriteria).filter(([, value]) => ['string', 'number'].includes(typeof value)).map(([key, value]) => `${key}=${value}`).join('&');
1163}
1164
1165/**
1166 * `searchPackages` returns the packages corresponding to a given query.
1167 *
1168 * @param query - one or more search criteria
1169 * @param registry - URL of the registry (default: npm registry)
1170 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
1171 * @param cached - accept cached responses (default: `true`)
1172 *
1173 * @example
1174 * Get the search results for text query `query-registry` from the npm registry:
1175 *
1176 * ```typescript
1177 * import { searchPackages } from 'query-registry';
1178 *
1179 * (async () => {
1180 * const results = await searchPackages({ query: { text: 'query-registry' } });
1181 *
1182 * // Output: 'query-registry'
1183 * console.log(results.objects[0].package.name);
1184 * })();
1185 * ```
1186 *
1187 * @see {@link SearchResults}
1188 * @see {@link SearchCriteria}
1189 * @see {@link npmRegistry}
1190 * @see {@link npmRegistryMirrors}
1191 */
1192
1193async function searchPackages({
1194 query: rawSearchCriteria,
1195 registry,
1196 mirrors,
1197 cached
1198}) {
1199 const endpoint = '/-/v1/search';
1200 const query = normalizeRawSearchCriteria({
1201 rawSearchCriteria
1202 });
1203 return fetchFromRegistry({
1204 endpoint,
1205 query,
1206 registry,
1207 mirrors,
1208 cached
1209 });
1210}
1211
1212exports.FetchError = FetchError;
1213exports.InvalidPackageNameError = InvalidPackageNameError;
1214exports.InvalidPackageVersionError = InvalidPackageVersionError;
1215exports.cloudflareRegistry = cloudflareRegistry;
1216exports.getAbbreviatedPackument = getAbbreviatedPackument;
1217exports.getDailyPackageDownloads = getDailyPackageDownloads;
1218exports.getDailyRegistryDownloads = getDailyRegistryDownloads;
1219exports.getPackageDownloads = getPackageDownloads;
1220exports.getPackageManifest = getPackageManifest;
1221exports.getPackument = getPackument;
1222exports.getRawAbbreviatedPackument = getRawAbbreviatedPackument;
1223exports.getRawPackageManifest = getRawPackageManifest;
1224exports.getRawPackument = getRawPackument;
1225exports.getRegistryDownloads = getRegistryDownloads;
1226exports.getRegistryMetadata = getRegistryMetadata;
1227exports.npmRegistry = npmRegistry;
1228exports.npmRegistryDownloadsAPI = npmRegistryDownloadsAPI;
1229exports.npmRegistryMirrors = npmRegistryMirrors;
1230exports.searchPackages = searchPackages;
1231exports.yarnRegistry = yarnRegistry;
1232//# sourceMappingURL=query-registry.cjs.development.js.map