UNPKG

31.4 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');
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 urlJoin__default = /*#__PURE__*/_interopDefaultLegacy(urlJoin);
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(base => urlJoin__default["default"](base, endpoint, query ? `?${query}` : ''));
216 let lastError;
217
218 for (const url of urls) {
219 try {
220 const json = await fetch({
221 url,
222 headers,
223 cached
224 });
225 return json;
226 } catch (err) {
227 // Keep last fetch error
228 lastError = err;
229 }
230 }
231
232 log('fetchFromRegistry: cannot retrieve data from registry or mirrors: %O', {
233 endpoint,
234 headers,
235 query,
236 registry,
237 mirrors,
238 lastError
239 });
240 throw lastError;
241}
242
243/**
244 * `getRawAbbreviatedPackument` returns the abbreviated packument (package document)
245 * containing only the metadata necessary to install a package present on the registry.
246 *
247 * Note: the abbreviated packument is returned as retrieved from the registry.
248 *
249 * @param name - package name
250 * @param registry - URL of the registry (default: npm registry)
251 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
252 * @param cached - accept cached responses (default: `true`)
253 *
254 * @example
255 * Get the abbreviated packument for package `query-registry` from the npm registry:
256 *
257 * ```typescript
258 * import { getRawAbbreviatedPackument } from 'query-registry';
259 *
260 * (async () => {
261 * const packument = await getRawAbbreviatedPackument({ name: 'query-registry' });
262 *
263 * // Output: 'query-registry'
264 * console.log(packument.name);
265 * })();
266 * ```
267 *
268 * @see {@link RawAbbreviatedPackument}
269 * @see {@link npmRegistry}
270 * @see {@link npmRegistryMirrors}
271 */
272
273async function getRawAbbreviatedPackument({
274 name,
275 registry,
276 mirrors,
277 cached
278}) {
279 assertValidPackageName({
280 name
281 });
282 const endpoint = `/${name}`;
283 const headers = {
284 Accept: 'application/vnd.npm.install-v1+json'
285 };
286 return fetchFromRegistry({
287 endpoint,
288 headers,
289 registry,
290 mirrors,
291 cached
292 });
293}
294
295/**
296 * `getAbbreviatedPackument` returns the abbreviated packument (package document)
297 * containing only the metadata necessary to install a package present on the registry.
298 *
299 * @remarks
300 * To get all the metadata (full packument) about a package see {@link getPackument}.
301 *
302 * @param name - package name
303 * @param registry - URL of the registry (default: npm registry)
304 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
305 * @param cached - accept cached responses (default: `true`)
306 *
307 * @example
308 * Get the abbreviated packument for package `query-registry` from the npm registry:
309 *
310 * ```typescript
311 * import { getAbbreviatedPackument } from 'query-registry';
312 *
313 * (async () => {
314 * const packument = await getAbbreviatedPackument({ name: 'query-registry' });
315 *
316 * // Output: 'query-registry'
317 * console.log(packument.name);
318 * })();
319 * ```
320 *
321 * @see {@link AbbreviatedPackument}
322 * @see {@link RawAbbreviatedPackument}
323 * @see {@link npmRegistry}
324 * @see {@link npmRegistryMirrors}
325 */
326
327async function getAbbreviatedPackument({
328 name,
329 registry,
330 mirrors,
331 cached
332}) {
333 const rawAbbreviatedPackument = await getRawAbbreviatedPackument({
334 name,
335 registry,
336 mirrors,
337 cached
338 });
339 return normalizeRawAbbreviatedPackument({
340 rawAbbreviatedPackument
341 });
342}
343
344async function fetchDownloadsFromRegistry({
345 endpoint,
346 registryDownloadsAPI = npmRegistryDownloadsAPI,
347 cached
348}) {
349 return fetchFromRegistry({
350 endpoint,
351 registry: registryDownloadsAPI,
352 mirrors: [],
353 cached
354 });
355}
356
357function normalizeRawDownloadPeriod({
358 rawDownloadPeriod = 'last-week'
359}) {
360 if (typeof rawDownloadPeriod === 'string') {
361 return rawDownloadPeriod;
362 }
363
364 if (rawDownloadPeriod instanceof Date) {
365 return getDay(rawDownloadPeriod);
366 }
367
368 const {
369 start,
370 end
371 } = rawDownloadPeriod;
372 return `${getDay(start)}:${getDay(end)}`;
373}
374
375function getDay(date) {
376 return date.toISOString().split('T')[0];
377}
378
379/**
380 * `getDailyPackageDownloads` returns the number of downloads for a package
381 * for each day in a given time period.
382 *
383 * @param name - package name
384 * @param period - time period in which downloads happened (default: `last-week`)
385 * @param registryDownloadsAPI - URL of the registry's downloads API (default: npm registry)
386 * @param cached - accept cached responses (default: `true`)
387 *
388 * @example
389 * Get the day by day weekly downloads for package `query-registry` from the npm registry:
390 *
391 * ```typescript
392 * import { getDailyPackageDownloads } from 'query-registry';
393 *
394 * (async () => {
395 * const downloads = await getDailyPackageDownloads({ name: 'query-registry' });
396 *
397 * // Output: 'query-registry'
398 * console.log(downloads.package);
399 *
400 * // Output: 'number'
401 * console.log(typeof downloads.downloads[0].downloads);
402 * })();
403 * ```
404 *
405 * @example
406 * Get the day by day monthly downloads for package `query-registry` from the npm registry:
407 *
408 * ```typescript
409 * import { getDailyPackageDownloads } from 'query-registry';
410 *
411 * (async () => {
412 * const downloads = await getDailyPackageDownloads({ name: 'query-registry', period: 'last-month' });
413 *
414 * // Output: 'query-registry'
415 * console.log(downloads.package);
416 *
417 * // Output: 'number'
418 * console.log(typeof downloads.downloads[0].downloads);
419 * })();
420 * ```
421 *
422 * @see {@link DailyPackageDownloads}
423 * @see {@link DownloadPeriod}
424 * @see {@link npmRegistryDownloadsAPI}
425 * @see {@link https://github.com/npm/registry/blob/master/docs/download-counts.md#ranges}
426 */
427
428async function getDailyPackageDownloads({
429 name,
430 period: rawDownloadPeriod,
431 registryDownloadsAPI,
432 cached
433}) {
434 assertValidPackageName({
435 name
436 });
437 const period = normalizeRawDownloadPeriod({
438 rawDownloadPeriod
439 });
440 const endpoint = `/downloads/range/${period}/${name}`;
441 return fetchDownloadsFromRegistry({
442 endpoint,
443 registryDownloadsAPI,
444 cached
445 });
446}
447
448/**
449 * `getDailyRegistryDownloads` returns the number of downloads for all registry packages
450 * for each day in a given time period.
451 *
452 * @param period - time period in which downloads happened (default: `last-week`)
453 * @param registryDownloadsAPI - URL of the registry's downloads API (default: npm registry)
454 * @param cached - accept cached responses (default: `true`)
455 *
456 * @example
457 * Get the day by day weekly downloads for the npm registry:
458 *
459 * ```typescript
460 * import { getDailyRegistryDownloads } from 'query-registry';
461 *
462 * (async () => {
463 * const downloads = await getDailyRegistryDownloads();
464 *
465 * // Output: 'number'
466 * console.log(typeof downloads.downloads[0].downloads);
467 * })();
468 * ```
469 *
470 * @example
471 * Get the day by day monthly downloads for the npm registry:
472 *
473 * ```typescript
474 * import { getDailyRegistryDownloads } from 'query-registry';
475 *
476 * (async () => {
477 * const downloads = await getDailyRegistryDownloads({ period: 'last-month' });
478 *
479 * // Output: 'number'
480 * console.log(typeof downloads.downloads[0].downloads);
481 * })();
482 * ```
483 *
484 * @see {@link DailyRegistryDownloads}
485 * @see {@link DownloadPeriod}
486 * @see {@link npmRegistryDownloadsAPI}
487 * @see {@link https://github.com/npm/registry/blob/master/docs/download-counts.md#ranges}
488 */
489
490async function getDailyRegistryDownloads({
491 period: rawDownloadPeriod,
492 registryDownloadsAPI,
493 cached
494} = {}) {
495 const period = normalizeRawDownloadPeriod({
496 rawDownloadPeriod
497 });
498 const endpoint = `/downloads/range/${period}`;
499 return fetchDownloadsFromRegistry({
500 endpoint,
501 registryDownloadsAPI,
502 cached
503 });
504}
505
506/**
507 * `getPackageDownloads` returns the number of downloads for a package
508 * in a given time period.
509 *
510 * @param name - package name
511 * @param period - time period in which downloads happened (default: `last-week`)
512 * @param registryDownloadsAPI - URL of the registry's downloads API (default: npm registry)
513 * @param cached - accept cached responses (default: `true`)
514 *
515 * @example
516 * Get the weekly downloads for package `query-registry` from the npm registry:
517 *
518 * ```typescript
519 * import { getPackageDownloads } from 'query-registry';
520 *
521 * (async () => {
522 * const downloads = await getPackageDownloads({ name: 'query-registry' });
523 *
524 * // Output: 'query-registry'
525 * console.log(downloads.package);
526 *
527 * // Output: 'number'
528 * console.log(typeof downloads.downloads);
529 * })();
530 * ```
531 *
532 * @example
533 * Get the monthly downloads for package `query-registry` from the npm registry:
534 *
535 * ```typescript
536 * import { getPackageDownloads } from 'query-registry';
537 *
538 * (async () => {
539 * const downloads = await getPackageDownloads({ name: 'query-registry', period: 'last-month' });
540 *
541 * // Output: 'query-registry'
542 * console.log(downloads.package);
543 *
544 * // Output: 'number'
545 * console.log(typeof downloads.downloads);
546 * })();
547 * ```
548 *
549 * @see {@link PackageDownloads}
550 * @see {@link DownloadPeriod}
551 * @see {@link npmRegistryDownloadsAPI}
552 * @see {@link https://github.com/npm/registry/blob/master/docs/download-counts.md#point-values}
553 */
554
555async function getPackageDownloads({
556 name,
557 period: rawDownloadPeriod,
558 registryDownloadsAPI,
559 cached
560}) {
561 assertValidPackageName({
562 name
563 });
564 const period = normalizeRawDownloadPeriod({
565 rawDownloadPeriod
566 });
567 const endpoint = `/downloads/point/${period}/${name}`;
568 return fetchDownloadsFromRegistry({
569 endpoint,
570 registryDownloadsAPI,
571 cached
572 });
573}
574
575function extractRawPackageManifest({
576 rawPackument,
577 version = 'latest'
578}) {
579 var _distTags$version;
580
581 const {
582 name,
583 'dist-tags': distTags,
584 versions
585 } = rawPackument;
586 const versionNumber = (_distTags$version = distTags[version]) != null ? _distTags$version : version;
587 const manifest = versions[versionNumber];
588
589 if (!manifest) {
590 log('getPackageManifest: invalid package version: %O', {
591 name,
592 version
593 });
594 throw new InvalidPackageVersionError(`invalid package version: '${name}@${version}'`);
595 }
596
597 return manifest;
598}
599
600/**
601 * `getRawPackument` returns the packument (package document) containing
602 * all the metadata about a package present on the registry.
603 *
604 * Note: the packument is returned as retrieved from the registry.
605 *
606 * @param name - package name
607 * @param registry - URL of the registry (default: npm registry)
608 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
609 * @param cached - accept cached responses (default: `true`)
610 *
611 * @example
612 * Get the packument for package `query-registry` from the npm registry:
613 *
614 * ```typescript
615 * import { getRawPackument } from 'query-registry';
616 *
617 * (async () => {
618 * const packument = await getRawPackument({ name: 'query-registry' });
619 *
620 * // Output: 'query-registry'
621 * console.log(packument.name);
622 * })();
623 * ```
624 *
625 * @see {@link RawPackument}
626 * @see {@link npmRegistry}
627 * @see {@link npmRegistryMirrors}
628 */
629
630async function getRawPackument({
631 name,
632 registry,
633 mirrors,
634 cached
635}) {
636 assertValidPackageName({
637 name
638 });
639 const endpoint = `/${name}`;
640 return fetchFromRegistry({
641 endpoint,
642 registry,
643 mirrors,
644 cached
645 });
646}
647
648/**
649 * `getRawPackageManifest` returns the manifest describing
650 * a specific version of a package.
651 *
652 * Note: the manifest is returned as retrieved from the registry.
653 *
654 * @param name - package name
655 * @param version - package version (default: `latest`)
656 * @param registry - URL of the registry (default: npm registry)
657 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
658 * @param cached - accept cached responses (default: `true`)
659 *
660 * @example
661 * Get the latest manifest for package `query-registry` from the npm registry:
662 *
663 * ```typescript
664 * import { getRawPackageManifest } from 'query-registry';
665 *
666 * (async () => {
667 * const manifest = await getRawPackageManifest({ name: 'query-registry' });
668 *
669 * // Output: 'query-registry'
670 * console.log(manifest.name);
671 * })();
672 * ```
673 *
674 * @example
675 * Get the manifest for package `query-registry@1.0.0` from the npm registry:
676 *
677 * ```typescript
678 * import { getRawPackageManifest } from 'query-registry';
679 *
680 * (async () => {
681 * const manifest = await getRawPackageManifest({ name: 'query-registry', version: '1.0.0' });
682 *
683 * // Output: 'query-registry'
684 * console.log(manifest.name);
685 *
686 * // Output: '1.0.0'
687 * console.log(manifest.version);
688 * })();
689 * ```
690 *
691 * @see {@link RawPackageManifest}
692 * @see {@link npmRegistry}
693 * @see {@link npmRegistryMirrors}
694 */
695
696async function getRawPackageManifest({
697 name,
698 version,
699 registry,
700 mirrors,
701 cached
702}) {
703 const rawPackument = await getRawPackument({
704 name,
705 registry,
706 mirrors,
707 cached
708 });
709 return extractRawPackageManifest({
710 rawPackument,
711 version
712 });
713}
714
715async function getDefinitelyTypedName({
716 rawPackageManifest,
717 registry,
718 mirrors,
719 cached
720}) {
721 const {
722 name,
723 types,
724 typings
725 } = rawPackageManifest;
726 const definitelyTypedName = toDefinitelyTypedName({
727 name
728 });
729 const alreadyTyped = name === definitelyTypedName || !!types || !!typings;
730
731 if (alreadyTyped) {
732 return undefined;
733 }
734
735 let ok = false;
736
737 try {
738 const {
739 deprecated
740 } = await getRawPackageManifest({
741 name: definitelyTypedName,
742 registry,
743 mirrors,
744 cached
745 });
746 ok = deprecated === undefined;
747 } catch {}
748
749 return ok ? definitelyTypedName : undefined;
750}
751/**
752 * `toDefinitelyTypedName` returns the name of the corresponding
753 * DefinitelyTyped package (for example,
754 * `foo` => `@types/foo`,
755 * `@bar/baz` => `@types/bar__baz`).
756 */
757
758function toDefinitelyTypedName({
759 name
760}) {
761 return name.startsWith('@types/') ? name : `@types/${name.replace('@', '').replace('/', '__')}`;
762}
763
764/**
765 * `getUntypedName` returns the name of the normal package
766 * corresponding to a DefinitelyTyped package.
767 */
768function getUntypedName({
769 name
770}) {
771 if (!name.startsWith('@types/')) {
772 return undefined;
773 } // ['foo', undefined] or ['@bar', 'baz']
774
775
776 const [scopeOrName, scopedName] = name.replace('@types/', '').split('__');
777 return scopedName ? `@${scopeOrName}/${scopedName}` : scopeOrName;
778}
779
780function normalizeRawLicense({
781 rawLicense
782}) {
783 if (!rawLicense) {
784 return undefined;
785 }
786
787 if (typeof rawLicense !== 'string') {
788 return undefined;
789 }
790
791 return rawLicense;
792}
793
794function normalizeRawRepository({
795 rawRepository
796}) {
797 if (isRepository(rawRepository)) {
798 return normalizeRepository({
799 rawRepository
800 });
801 }
802
803 if (typeof rawRepository === 'string') {
804 return normalizeRepository({
805 rawRepository: {
806 url: rawRepository
807 }
808 });
809 }
810
811 return undefined;
812}
813
814function isRepository(rawRepository) {
815 return rawRepository && typeof rawRepository === 'object' && typeof rawRepository['url'] === 'string' && ['string', 'undefined'].includes(typeof rawRepository['type']) && ['string', 'undefined'].includes(typeof rawRepository['directory']);
816}
817
818function normalizeRepository({
819 rawRepository
820}) {
821 const {
822 url,
823 directory
824 } = rawRepository;
825 const parsedUrl = parseGitURL({
826 url
827 });
828
829 if (!parsedUrl) {
830 return undefined;
831 }
832
833 return {
834 type: 'git',
835 url: parsedUrl,
836 directory
837 };
838}
839
840function parseGitURL({
841 url
842}) {
843 const urlWithProtocol = url.includes(':') ? // A normal URL or a shortcut like `github:user/repository`
844 url : // The short form github shortcut `user/repository`
845 url.includes('/') ? `github:${url}` : // Not a URL
846 '';
847
848 try {
849 const {
850 protocol,
851 hostname,
852 pathname
853 } = new URL(urlWithProtocol);
854 const cleanPathname = pathname.replace(/\.git$/, '');
855
856 if (protocol === 'github:' || hostname === 'github.com') {
857 return urlJoin__default["default"]('https://github.com', cleanPathname);
858 }
859
860 if (protocol === 'gist:' || hostname === 'gist.github.com') {
861 return urlJoin__default["default"]('https://gist.github.com', cleanPathname);
862 }
863
864 if (protocol === 'bitbucket:' || hostname === 'bitbucket.org') {
865 return urlJoin__default["default"]('https://bitbucket.org', cleanPathname);
866 }
867
868 if (protocol === 'gitlab:' || hostname === 'gitlab.com') {
869 return urlJoin__default["default"]('https://gitlab.com', cleanPathname);
870 }
871
872 return urlWithProtocol;
873 } catch {
874 return undefined;
875 }
876}
877
878async function normalizeRawPackageManifest({
879 rawPackageManifest,
880 rawPackument,
881 registry,
882 mirrors,
883 cached
884}) {
885 const {
886 _id: id,
887 name,
888 version,
889 license: rawLicense,
890 repository: rawRepository,
891 _npmUser: publisher
892 } = rawPackageManifest;
893 const createdAt = rawPackument.time[version];
894 const license = normalizeRawLicense({
895 rawLicense
896 });
897 const gitRepository = normalizeRawRepository({
898 rawRepository
899 });
900 const definitelyTypedName = await getDefinitelyTypedName({
901 rawPackageManifest,
902 registry,
903 mirrors,
904 cached
905 });
906 const untypedName = getUntypedName({
907 name
908 });
909 return { ...rawPackageManifest,
910 id,
911 createdAt,
912 publisher,
913 license,
914 gitRepository,
915 definitelyTypedName,
916 untypedName
917 };
918}
919
920/**
921 * `getPackageManifest` returns the manifest describing
922 * a specific version of a package.
923 *
924 * @param name - package name
925 * @param version - package version (default: `latest`)
926 * @param registry - URL of the registry (default: npm registry)
927 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
928 * @param cached - accept cached responses (default: `true`)
929 *
930 * @example
931 * Get the latest manifest for package `query-registry` from the npm registry:
932 *
933 * ```typescript
934 * import { getPackageManifest } from 'query-registry';
935 *
936 * (async () => {
937 * const manifest = await getPackageManifest({ name: 'query-registry' });
938 *
939 * // Output: 'query-registry'
940 * console.log(manifest.name);
941 * })();
942 * ```
943 *
944 * @example
945 * Get the manifest for package `query-registry@1.0.0` from the npm registry:
946 *
947 * ```typescript
948 * import { getPackageManifest } from 'query-registry';
949 *
950 * (async () => {
951 * const manifest = await getPackageManifest({ name: 'query-registry', version: '1.0.0' });
952 *
953 * // Output: 'query-registry'
954 * console.log(manifest.name);
955 *
956 * // Output: '1.0.0'
957 * console.log(manifest.version);
958 * })();
959 * ```
960 *
961 * @see {@link PackageManifest}
962 * @see {@link RawPackageManifest}
963 * @see {@link npmRegistry}
964 * @see {@link npmRegistryMirrors}
965 */
966
967async function getPackageManifest({
968 name,
969 version,
970 registry,
971 mirrors,
972 cached
973}) {
974 const rawPackument = await getRawPackument({
975 name,
976 registry,
977 mirrors,
978 cached
979 });
980 const rawPackageManifest = extractRawPackageManifest({
981 rawPackument,
982 version
983 });
984 const packageManifest = await normalizeRawPackageManifest({
985 rawPackageManifest,
986 rawPackument,
987 registry,
988 mirrors,
989 cached
990 });
991 return packageManifest;
992}
993
994function normalizeRawPackument({
995 rawPackument
996}) {
997 const {
998 _id: id,
999 'dist-tags': distTags,
1000 time,
1001 license: rawLicense,
1002 repository: rawRepository
1003 } = rawPackument;
1004 const license = normalizeRawLicense({
1005 rawLicense
1006 });
1007 const gitRepository = normalizeRawRepository({
1008 rawRepository
1009 });
1010 const versionsToTimestamps = Object.fromEntries(Object.entries(time).filter(([key]) => {
1011 return !['created', 'modified'].includes(key);
1012 }));
1013 return { ...rawPackument,
1014 id,
1015 distTags,
1016 versionsToTimestamps,
1017 license,
1018 gitRepository
1019 };
1020}
1021
1022/**
1023 * `getPackument` returns the packument (package document) containing
1024 * all the metadata about a package present on the registry.
1025 *
1026 * @param name - package name
1027 * @param registry - URL of the registry (default: npm registry)
1028 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
1029 * @param cached - accept cached responses (default: `true`)
1030 *
1031 * @example
1032 * Get the packument for package `query-registry` from the npm registry:
1033 *
1034 * ```typescript
1035 * import { getPackument } from 'query-registry';
1036 *
1037 * (async () => {
1038 * const packument = await getPackument({ name: 'query-registry' });
1039 *
1040 * // Output: 'query-registry'
1041 * console.log(packument.name);
1042 * })();
1043 * ```
1044 *
1045 * @see {@link Packument}
1046 * @see {@link RawPackument}
1047 * @see {@link npmRegistry}
1048 * @see {@link npmRegistryMirrors}
1049 */
1050
1051async function getPackument({
1052 name,
1053 registry,
1054 mirrors,
1055 cached
1056}) {
1057 const rawPackument = await getRawPackument({
1058 name,
1059 registry,
1060 mirrors,
1061 cached
1062 });
1063 return normalizeRawPackument({
1064 rawPackument
1065 });
1066}
1067
1068/**
1069 * `getRegistryDownloads` returns the number of downloads for all registry packages
1070 * in a given time period.
1071 *
1072 * @param period - time period in which downloads happened (default: `last-week`)
1073 * @param registryDownloadsAPI - URL of the registry's downloads API (default: npm registry)
1074 * @param cached - accept cached responses (default: `true`)
1075 *
1076 * @example
1077 * Get the weekly downloads for the npm registry:
1078 *
1079 * ```typescript
1080 * import { getRegistryDownloads } from 'query-registry';
1081 *
1082 * (async () => {
1083 * const downloads = await getRegistryDownloads();
1084 *
1085 * // Output: 'number'
1086 * console.log(typeof downloads.downloads);
1087 * })();
1088 * ```
1089 *
1090 * @example
1091 * Get the monthly downloads for the npm registry:
1092 *
1093 * ```typescript
1094 * import { getRegistryDownloads } from 'query-registry';
1095 *
1096 * (async () => {
1097 * const downloads = await getRegistryDownloads({ period: 'last-month' });
1098 *
1099 * // Output: 'number'
1100 * console.log(typeof downloads.downloads);
1101 * })();
1102 * ```
1103 *
1104 * @see {@link RegistryDownloads}
1105 * @see {@link DownloadPeriod}
1106 * @see {@link npmRegistryDownloadsAPI}
1107 * @see {@link https://github.com/npm/registry/blob/master/docs/download-counts.md#point-values}
1108 */
1109
1110async function getRegistryDownloads({
1111 period: rawDownloadPeriod,
1112 registryDownloadsAPI,
1113 cached
1114} = {}) {
1115 const period = normalizeRawDownloadPeriod({
1116 rawDownloadPeriod
1117 });
1118 const endpoint = `/downloads/point/${period}`;
1119 return fetchDownloadsFromRegistry({
1120 endpoint,
1121 registryDownloadsAPI,
1122 cached
1123 });
1124}
1125
1126/**
1127 * `getRegistryMetadata` returns the metadata describing the registry itself.
1128 *
1129 * @param registry - URL of the registry (default: npm registry)
1130 * @param cached - accept cached responses (default: `true`)
1131 *
1132 * @example
1133 * Get the metadata for the npm registry:
1134 *
1135 * ```typescript
1136 * import { getRegistryMetadata } from 'query-registry';
1137 *
1138 * (async () => {
1139 * const metadata = await getRegistryMetadata();
1140 *
1141 * // Output: 'registry'
1142 * console.log(metadata.db_name);
1143 * })();
1144 * ```
1145 *
1146 * @example
1147 * Get the metadata for a custom registry:
1148 *
1149 * ```typescript
1150 * import { getRegistryMetadata } from 'query-registry';
1151 *
1152 * (async () => {
1153 * const metadata = await getRegistryMetadata({ registry: 'https://example.com' });
1154 * })();
1155 * ```
1156 *
1157 * @see {@link RegistryMetadata}
1158 * @see {@link npmRegistry}
1159 */
1160
1161async function getRegistryMetadata({
1162 registry,
1163 cached
1164} = {}) {
1165 const endpoint = '/';
1166 return fetchFromRegistry({
1167 registry,
1168 mirrors: [],
1169 endpoint,
1170 cached
1171 });
1172}
1173
1174function normalizeRawSearchCriteria({
1175 rawSearchCriteria
1176}) {
1177 // Convert SearchCriteria to a URL query string
1178 return Object.entries(rawSearchCriteria).filter(([, value]) => ['string', 'number'].includes(typeof value)).map(([key, value]) => `${key}=${value}`).join('&');
1179}
1180
1181/**
1182 * `searchPackages` returns the packages corresponding to a given query.
1183 *
1184 * @param query - one or more search criteria
1185 * @param registry - URL of the registry (default: npm registry)
1186 * @param mirrors - URLs of the registry mirrors (default: npm registry mirrors)
1187 * @param cached - accept cached responses (default: `true`)
1188 *
1189 * @example
1190 * Get the search results for text query `query-registry` from the npm registry:
1191 *
1192 * ```typescript
1193 * import { searchPackages } from 'query-registry';
1194 *
1195 * (async () => {
1196 * const results = await searchPackages({ query: { text: 'query-registry' } });
1197 *
1198 * // Output: 'query-registry'
1199 * console.log(results.objects[0].package.name);
1200 * })();
1201 * ```
1202 *
1203 * @see {@link SearchResults}
1204 * @see {@link SearchCriteria}
1205 * @see {@link npmRegistry}
1206 * @see {@link npmRegistryMirrors}
1207 */
1208
1209async function searchPackages({
1210 query: rawSearchCriteria,
1211 registry,
1212 mirrors,
1213 cached
1214}) {
1215 const endpoint = '/-/v1/search';
1216 const query = normalizeRawSearchCriteria({
1217 rawSearchCriteria
1218 });
1219 return fetchFromRegistry({
1220 endpoint,
1221 query,
1222 registry,
1223 mirrors,
1224 cached
1225 });
1226}
1227
1228exports.FetchError = FetchError;
1229exports.InvalidPackageNameError = InvalidPackageNameError;
1230exports.InvalidPackageVersionError = InvalidPackageVersionError;
1231exports.cloudflareRegistry = cloudflareRegistry;
1232exports.getAbbreviatedPackument = getAbbreviatedPackument;
1233exports.getDailyPackageDownloads = getDailyPackageDownloads;
1234exports.getDailyRegistryDownloads = getDailyRegistryDownloads;
1235exports.getPackageDownloads = getPackageDownloads;
1236exports.getPackageManifest = getPackageManifest;
1237exports.getPackument = getPackument;
1238exports.getRawAbbreviatedPackument = getRawAbbreviatedPackument;
1239exports.getRawPackageManifest = getRawPackageManifest;
1240exports.getRawPackument = getRawPackument;
1241exports.getRegistryDownloads = getRegistryDownloads;
1242exports.getRegistryMetadata = getRegistryMetadata;
1243exports.npmRegistry = npmRegistry;
1244exports.npmRegistryDownloadsAPI = npmRegistryDownloadsAPI;
1245exports.npmRegistryMirrors = npmRegistryMirrors;
1246exports.searchPackages = searchPackages;
1247exports.yarnRegistry = yarnRegistry;
1248//# sourceMappingURL=query-registry.cjs.development.js.map