1 | ;
|
2 |
|
3 | Object.defineProperty(exports, '__esModule', { value: true });
|
4 |
|
5 | var validatePackageName = require('validate-npm-package-name');
|
6 | var makeError = require('make-error');
|
7 | var unfetch = require('isomorphic-unfetch');
|
8 | var lru = require('tiny-lru');
|
9 | var urlJoin = require('url-join');
|
10 | var gitUrlParse = require('git-url-parse');
|
11 |
|
12 | function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
13 |
|
14 | function _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 |
|
32 | var validatePackageName__default = /*#__PURE__*/_interopDefaultLegacy(validatePackageName);
|
33 | var makeError__default = /*#__PURE__*/_interopDefaultLegacy(makeError);
|
34 | var unfetch__default = /*#__PURE__*/_interopDefaultLegacy(unfetch);
|
35 | var lru__default = /*#__PURE__*/_interopDefaultLegacy(lru);
|
36 | var urlJoin__default = /*#__PURE__*/_interopDefaultLegacy(urlJoin);
|
37 | var gitUrlParse__default = /*#__PURE__*/_interopDefaultLegacy(gitUrlParse);
|
38 |
|
39 | /**
|
40 | * npm registry
|
41 | *
|
42 | * @see {@link https://registry.npmjs.org}
|
43 | */
|
44 | const 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 |
|
56 | const cloudflareRegistry = 'https://registry.npmjs.cf';
|
57 | /**
|
58 | * npm registry mirror by Yarn
|
59 | *
|
60 | * @see {@link https://registry.yarnpkg.com}
|
61 | */
|
62 |
|
63 | const yarnRegistry = 'https://registry.yarnpkg.com';
|
64 | /**
|
65 | * Mirrors of the npm registry.
|
66 | *
|
67 | * @see {@link cloudflareRegistry}
|
68 | * @see {@link yarnRegistry}
|
69 | */
|
70 |
|
71 | const npmRegistryMirrors = [cloudflareRegistry, yarnRegistry];
|
72 | /**
|
73 | * Downloads API for the npm registry
|
74 | *
|
75 | * @see {@link https://api.npmjs.org}
|
76 | */
|
77 |
|
78 | const npmRegistryDownloadsAPI = 'https://api.npmjs.org';
|
79 |
|
80 | function 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 |
|
101 | class 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 |
|
124 | const 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 |
|
131 | const InvalidPackageVersionError = /*#__PURE__*/makeError__default["default"]('InvalidPackageVersionError');
|
132 |
|
133 | async 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 |
|
145 | function 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 |
|
162 | const maxItems = 250;
|
163 | const fiveMinutesTTL = 5 * 60 * 1000;
|
164 | const cache = /*#__PURE__*/lru__default["default"](maxItems, fiveMinutesTTL);
|
165 | async 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 |
|
209 | async 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 |
|
275 | async 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 |
|
329 | async 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 |
|
346 | async 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 |
|
359 | function 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 |
|
377 | function 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 |
|
430 | async 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 |
|
492 | async 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 |
|
557 | async 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 |
|
577 | function 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 |
|
632 | async 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 |
|
698 | async 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 |
|
717 | async 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 |
|
760 | function 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 | */
|
770 | function 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 |
|
782 | function 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 |
|
796 | function 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 |
|
816 | function 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 |
|
820 | function 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 |
|
850 | function parseGitURL({
|
851 | url
|
852 | }) {
|
853 | let info;
|
854 |
|
855 | try {
|
856 | info = gitUrlParse__default["default"](url);
|
857 | } catch {}
|
858 |
|
859 | return info;
|
860 | }
|
861 |
|
862 | async 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 |
|
951 | async 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 |
|
978 | function 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 |
|
1035 | async 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 |
|
1094 | async 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 |
|
1145 | async function getRegistryMetadata({
|
1146 | registry,
|
1147 | cached
|
1148 | } = {}) {
|
1149 | const endpoint = '/';
|
1150 | return fetchFromRegistry({
|
1151 | registry,
|
1152 | mirrors: [],
|
1153 | endpoint,
|
1154 | cached
|
1155 | });
|
1156 | }
|
1157 |
|
1158 | function 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 |
|
1193 | async 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 |
|
1212 | exports.FetchError = FetchError;
|
1213 | exports.InvalidPackageNameError = InvalidPackageNameError;
|
1214 | exports.InvalidPackageVersionError = InvalidPackageVersionError;
|
1215 | exports.cloudflareRegistry = cloudflareRegistry;
|
1216 | exports.getAbbreviatedPackument = getAbbreviatedPackument;
|
1217 | exports.getDailyPackageDownloads = getDailyPackageDownloads;
|
1218 | exports.getDailyRegistryDownloads = getDailyRegistryDownloads;
|
1219 | exports.getPackageDownloads = getPackageDownloads;
|
1220 | exports.getPackageManifest = getPackageManifest;
|
1221 | exports.getPackument = getPackument;
|
1222 | exports.getRawAbbreviatedPackument = getRawAbbreviatedPackument;
|
1223 | exports.getRawPackageManifest = getRawPackageManifest;
|
1224 | exports.getRawPackument = getRawPackument;
|
1225 | exports.getRegistryDownloads = getRegistryDownloads;
|
1226 | exports.getRegistryMetadata = getRegistryMetadata;
|
1227 | exports.npmRegistry = npmRegistry;
|
1228 | exports.npmRegistryDownloadsAPI = npmRegistryDownloadsAPI;
|
1229 | exports.npmRegistryMirrors = npmRegistryMirrors;
|
1230 | exports.searchPackages = searchPackages;
|
1231 | exports.yarnRegistry = yarnRegistry;
|
1232 | //# sourceMappingURL=query-registry.cjs.development.js.map
|