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