UNPKG

19.6 kBJavaScriptView Raw
1// src/index.ts
2import { PackageJson as PackageJson4 } from "zod-package-json";
3
4// src/cache.ts
5import QuickLRU from "quick-lru";
6var cache = new QuickLRU({
7 // 100 items.
8 maxSize: 100,
9 // 5 minutes.
10 maxAge: 5 * 60 * 1e3
11});
12
13// src/download-period.ts
14import { z } from "zod";
15var DownloadPeriod = z.union([
16 z.literal("last-day"),
17 z.literal("last-week"),
18 z.literal("last-month"),
19 z.literal("last-year"),
20 z.string().regex(/^\d{4}-\d{2}-\d{2}(:\d{4}-\d{2}-\d{2})?$/)
21]);
22
23// src/get-abbreviated-packument.ts
24import urlJoin2 from "url-join";
25import { z as z4 } from "zod";
26
27// src/assert-valid-package-name.ts
28import validatePackageName from "validate-npm-package-name";
29var assertValidPackageName = (name) => {
30 const { validForOldPackages, validForNewPackages, warnings, errors } = validatePackageName(name);
31 const isValid = validForOldPackages || validForNewPackages;
32 if (!isValid) {
33 throw new Error("invalid package name", { cause: { name, warnings, errors } });
34 }
35};
36
37// src/dist-tags.ts
38import { z as z2 } from "zod";
39var DistTags = z2.object({
40 /** Latest semver version number. */
41 latest: z2.string(),
42 // The following tags have no special meaning for the npm registry
43 // but they are commonly used by packages.
44 next: z2.string().optional(),
45 alpha: z2.string().optional(),
46 beta: z2.string().optional(),
47 rc: z2.string().optional(),
48 canary: z2.string().optional(),
49 dev: z2.string().optional()
50}).catchall(z2.string());
51
52// src/fetch-data.ts
53var fetchData = async (schema, url, headers) => {
54 const cacheKey = JSON.stringify({ url, headers });
55 const cachedJson = cache.get(cacheKey);
56 if (cachedJson) {
57 return schema.parse(cachedJson);
58 }
59 const response = await fetch(url, { headers });
60 const json = await response.json();
61 cache.set(cacheKey, json);
62 return schema.parse(json);
63};
64
65// src/get-package-manifest.ts
66import urlJoin from "url-join";
67import { z as z3 } from "zod";
68import { PackageJson } from "zod-package-json";
69
70// src/npm-registry.ts
71var npmRegistryUrl = "https://registry.npmjs.org";
72var npmRegistryDownloadsApiUrl = "https://api.npmjs.org";
73
74// src/get-package-manifest.ts
75var Dist = z3.object({
76 /** Tarball URL. */
77 tarball: z3.string(),
78 /** SHA1 sum of the tarball. */
79 shasum: z3.string(),
80 /** String in the format `<hashAlgorithm>-<base64-hash>`. */
81 integrity: z3.string().optional(),
82 /** Number of files in the tarball. */
83 fileCount: z3.number().optional(),
84 /** Total unpacked size in bytes of the files in the tarball. */
85 unpackedSize: z3.number().optional(),
86 /**
87 PGP signature in the format `<package>@<version>:<integrity>`.
88 @deprecated {@link https://docs.npmjs.com/about-registry-signatures#migrating-from-pgp-to-ecdsa-signatures}
89 */
90 "npm-signature": z3.string().optional(),
91 /**
92 ECDSA registry signatures.
93 @see {@link https://docs.npmjs.com/about-registry-signatures}
94 */
95 signatures: z3.array(
96 z3.object({
97 keyid: z3.string(),
98 sig: z3.string()
99 })
100 ).optional()
101});
102var PackageManifest = PackageJson.extend({
103 /** Package version ID in the format `<name>@<version>` (e.g., `foo@1.0.0`). */
104 _id: z3.string(),
105 /** Distribution metadata generated by the registry. */
106 dist: Dist,
107 /** Text extracted from the README file. */
108 readme: z3.string().optional(),
109 /** Name of the README file. */
110 readmeFilename: z3.string().optional(),
111 /** Commit corresponding to the published package version. */
112 gitHead: z3.string().optional(),
113 /** True if the package contains a shrinkwrap file. */
114 _hasShrinkwrap: z3.boolean().optional(),
115 /** Node.js version used to publish the package. */
116 _nodeVersion: z3.string().optional(),
117 /** npm CLI version used to publish the package. */
118 _npmVersion: z3.string().optional(),
119 /** npm user who published the specific version of the package. */
120 _npmUser: PackageJson.shape.author.optional(),
121 /** Internal npm registry data. */
122 _npmOperationalInternal: z3.object({
123 host: z3.string().optional(),
124 tmp: z3.string().optional()
125 }).optional(),
126 /**
127 Runtime systems supported by the package.
128
129 @remarks
130 In some old packages (like `lodash@0.1.0`) the `engines` property is an array of strings
131 instead of an object and with catch it becomes `undefined`.
132 */
133 engines: z3.record(z3.string()).optional().catch(void 0),
134 /**
135 SPDX license expression or a custom license.
136
137 @remarks
138 In some old packages (like `eslint@0.0.6`) the `license` property is an object
139 and with catch `license` becomes `undefined`.
140 */
141 license: z3.string().optional().catch(void 0),
142 /**
143 URL of the package's homepage.
144
145 @remarks
146 In some old packages (like `fs-extra@0.0.1`) the `homepage` property is an array
147 of strings and with catch it becomes `undefined`.
148 */
149 homepage: z3.string().optional().catch(void 0),
150 /**
151 Deprecation status/message.
152
153 @remarks
154 In some packages (like `react@16.14.0`) the `deprecated` property is a boolean
155 instead of a deprecation message.
156 */
157 deprecated: z3.union([z3.string(), z3.boolean()]).optional()
158});
159var getPackageManifest = async (name, versionOrTag = "latest", registry = npmRegistryUrl) => {
160 assertValidPackageName(name);
161 return fetchData(PackageManifest, urlJoin(registry, name, versionOrTag));
162};
163
164// src/get-abbreviated-packument.ts
165var AbbreviatedPackument = z4.object({
166 /** Package name. */
167 name: z4.string(),
168 /** Timestamp of when the package was last modified in ISO 8601 format (e.g., `2021-11-23T19:12:24.006Z`). */
169 modified: z4.string(),
170 /** Mapping of distribution tags to semver version numbers e.g., `{ "latest": "1.0.0" }`). */
171 "dist-tags": DistTags,
172 /** Mapping of semver version numbers to the required metadata for installing a package version. */
173 versions: z4.record(
174 z4.string(),
175 PackageManifest.pick({
176 name: true,
177 version: true,
178 dist: true,
179 deprecated: true,
180 dependencies: true,
181 optionalDependencies: true,
182 devDependencies: true,
183 bundleDependencies: true,
184 peerDependencies: true,
185 peerDependenciesMeta: true,
186 bin: true,
187 directories: true,
188 engines: true,
189 cpu: true,
190 os: true,
191 _hasShrinkwrap: true
192 }).extend({
193 /** True if the package contains an `install` script. */
194 hasInstallScript: z4.boolean().optional()
195 })
196 )
197});
198var getAbbreviatedPackument = async (name, registry = npmRegistryUrl) => {
199 assertValidPackageName(name);
200 return fetchData(AbbreviatedPackument, urlJoin2(registry, name), {
201 Accept: "application/vnd.npm.install-v1+json"
202 });
203};
204
205// src/get-bulk-daily-package-downloads.ts
206import urlJoin5 from "url-join";
207import { z as z7 } from "zod";
208
209// src/get-daily-package-downloads.ts
210import urlJoin4 from "url-join";
211import { z as z6 } from "zod";
212
213// src/get-daily-registry-downloads.ts
214import urlJoin3 from "url-join";
215import { z as z5 } from "zod";
216var DailyRegistryDownloads = z5.object({
217 /** Date of the first day (inclusive) in the format `YYYY-MM-DD`. */
218 start: z5.string(),
219 /** Date of the last day (inclusive) in the format `YYYY-MM-DD`. */
220 end: z5.string(),
221 /** Download counts for each day. */
222 downloads: z5.array(
223 z5.object({
224 /** Total number of downloads for the day. */
225 downloads: z5.number(),
226 /** Date of the day in the format `YYYY-MM-DD`. */
227 day: z5.string()
228 })
229 )
230});
231var getDailyRegistryDownloads = async (period, registry = npmRegistryDownloadsApiUrl) => fetchData(DailyRegistryDownloads, urlJoin3(registry, `/downloads/range/${period}`));
232
233// src/get-daily-package-downloads.ts
234var DailyPackageDownloads = DailyRegistryDownloads.extend({
235 /** Package name. */
236 package: z6.string()
237});
238var getDailyPackageDownloads = async (name, period, registry = npmRegistryDownloadsApiUrl) => {
239 assertValidPackageName(name);
240 return fetchData(DailyPackageDownloads, urlJoin4(registry, `/downloads/range/${period}/${name}`));
241};
242
243// src/get-bulk-daily-package-downloads.ts
244var BulkDailyPackageDownloads = z7.record(z7.union([z7.null(), DailyPackageDownloads]));
245var getBulkDailyPackageDownloads = async (names, period, registry = npmRegistryDownloadsApiUrl) => {
246 for (const name of names) {
247 assertValidPackageName(name);
248 }
249 return fetchData(
250 BulkDailyPackageDownloads,
251 urlJoin5(registry, `/downloads/range/${period}/${names.join(",")}`)
252 );
253};
254
255// src/get-bulk-package-downloads.ts
256import urlJoin8 from "url-join";
257import { z as z10 } from "zod";
258
259// src/get-package-downloads.ts
260import urlJoin7 from "url-join";
261import { z as z9 } from "zod";
262
263// src/get-registry-downloads.ts
264import urlJoin6 from "url-join";
265import { z as z8 } from "zod";
266var RegistryDownloads = z8.object({
267 /** Total number of downloads. */
268 downloads: z8.number(),
269 /** Date of the first day (inclusive) in the format `YYYY-MM-DD`. */
270 start: z8.string(),
271 /** Date of the last day (inclusive) in the format `YYYY-MM-DD`. */
272 end: z8.string()
273});
274var getRegistryDownloads = async (period, registry = npmRegistryDownloadsApiUrl) => fetchData(RegistryDownloads, urlJoin6(registry, `/downloads/point/${period}`));
275
276// src/get-package-downloads.ts
277var PackageDownloads = RegistryDownloads.extend({
278 /** Package name. */
279 package: z9.string()
280});
281var getPackageDownloads = async (name, period, registry = npmRegistryDownloadsApiUrl) => {
282 assertValidPackageName(name);
283 return fetchData(PackageDownloads, urlJoin7(registry, `/downloads/point/${period}/${name}`));
284};
285
286// src/get-bulk-package-downloads.ts
287var BulkPackageDownloads = z10.record(z10.union([z10.null(), PackageDownloads]));
288var getBulkPackageDownloads = async (names, period, registry = npmRegistryDownloadsApiUrl) => {
289 for (const name of names) {
290 assertValidPackageName(name);
291 }
292 return fetchData(
293 BulkPackageDownloads,
294 urlJoin8(registry, `/downloads/point/${period}/${names.join(",")}`)
295 );
296};
297
298// src/get-package-versions-downloads.ts
299import urlJoin9 from "url-join";
300import { z as z11 } from "zod";
301var PackageVersionsDownloads = z11.object({
302 /** Package name. */
303 package: z11.string(),
304 /** Mapping of semver version numbers to total number of downloads. */
305 downloads: z11.record(z11.number())
306});
307var getPackageVersionsDownloads = async (name, registry = npmRegistryDownloadsApiUrl) => {
308 assertValidPackageName(name);
309 return fetchData(
310 PackageVersionsDownloads,
311 urlJoin9(registry, `/versions/${encodeURIComponent(name)}/last-week`)
312 );
313};
314
315// src/get-packument.ts
316import urlJoin10 from "url-join";
317import { z as z12 } from "zod";
318import { PackageJson as PackageJson2 } from "zod-package-json";
319var Time = z12.object({
320 /** Timestamp of when the package was created in ISO 8601 format (e.g., `2021-11-23T19:12:24.006Z`). */
321 created: z12.string(),
322 /** Timestamp of when the package was last modified in ISO 8601 format (e.g., `2021-11-23T19:12:24.006Z`). */
323 modified: z12.string()
324}).catchall(z12.string());
325var Packument = PackageJson2.pick({
326 author: true,
327 bugs: true,
328 contributors: true,
329 description: true,
330 homepage: true,
331 keywords: true,
332 license: true,
333 maintainers: true,
334 repository: true
335}).extend({
336 /** Package name used as the ID in CouchDB. */
337 _id: z12.string(),
338 /** Package name. */
339 name: z12.string(),
340 /** Mapping of distribution tags to semver version numbers e.g., `{ "latest": "1.0.0" }`). */
341 "dist-tags": DistTags,
342 /**
343 Mapping of semver version numbers to timestamps in ISO 8601 format representing
344 the publishing time (e.g., `{ "1.0.0": "2021-11-23T19:12:24.006Z" }`).
345 Also includes the timestamps of when the package was `created` and last `modified`.
346 */
347 time: Time,
348 /**
349 Mapping of semver version numbers to package manifests.
350 @see {@link PackageManifest}
351 */
352 versions: z12.record(PackageManifest),
353 /** Revision ID of the document in CouchDB. */
354 _rev: z12.coerce.string().optional(),
355 /** Mapping of npm usernames of users who starred the package to `true`. */
356 users: z12.record(z12.boolean()).optional(),
357 /** Text extracted from the README file. */
358 readme: z12.string().optional(),
359 /** Name of the README file. */
360 readmeFilename: z12.string().optional()
361});
362var getPackument = async (name, registry = npmRegistryUrl) => {
363 assertValidPackageName(name);
364 return fetchData(Packument, urlJoin10(registry, name));
365};
366
367// src/get-registry-metadata.ts
368import { z as z13 } from "zod";
369var RegistryMetadata = z13.object({
370 /** Database name, usually `registry` */
371 db_name: z13.string().optional(),
372 doc_count: z13.number().optional(),
373 doc_del_count: z13.number().optional(),
374 update_seq: z13.number().optional(),
375 purge_seq: z13.number().optional(),
376 compact_running: z13.boolean().optional(),
377 disk_size: z13.number().optional(),
378 data_size: z13.number().optional(),
379 instance_start_time: z13.string().optional(),
380 disk_format_version: z13.number().optional(),
381 committed_update_seq: z13.number().optional(),
382 compacted_seq: z13.number().optional(),
383 uuid: z13.string().optional(),
384 other: z13.object({ data_size: z13.number().optional() }).optional(),
385 sizes: z13.object({
386 file: z13.number().optional(),
387 active: z13.number().optional(),
388 external: z13.number().optional()
389 }).optional()
390});
391var getRegistryMetadata = async (registry = npmRegistryUrl) => fetchData(RegistryMetadata, registry);
392
393// src/get-registry-signing-keys.ts
394import urlJoin11 from "url-join";
395import { z as z14 } from "zod";
396var RegistrySigningKeys = z14.object({
397 keys: z14.array(
398 z14.object({
399 /**
400 String in the simplified extended ISO 8601 format
401 (e.g., `YYYY-MM-DDTHH:mm:ss.sssZ`) or `null`.
402 */
403 expires: z14.string().nullable(),
404 /** SHA256 fingerprint of the public key. */
405 keyid: z14.string(),
406 /** Key type; only `ecdsa-sha2-nistp256` is currently supported by the npm CLI. */
407 keytype: z14.string(),
408 /** Key scheme; only `ecdsa-sha2-nistp256` is currently supported by the npm CLI. */
409 scheme: z14.string(),
410 /** Public key encoded in base64. */
411 key: z14.string()
412 })
413 )
414});
415var getRegistrySigningKeys = async (registry = npmRegistryUrl) => fetchData(RegistrySigningKeys, urlJoin11(registry, "-/npm/v1/keys"));
416
417// src/search-packages.ts
418import queryString from "query-string";
419import urlJoin12 from "url-join";
420import { z as z15 } from "zod";
421import { PackageJson as PackageJson3 } from "zod-package-json";
422var SearchCriteria = z15.object({
423 /**
424 Query text.
425
426 @remarks
427 The following special text attributes can be used to refine results:
428 - `author:<name>`: show packages from the given author (e.g., `author:someone`)
429 - `maintainer:<name>`: show packages with the given maintainer (e.g., `maintainer:someone`)
430 - `keywords:<keyword list>`: show packages matching the given keyword(s);
431 separators `,`, `+` and `,-` act respectively as `OR`, `AND` and `NOT`
432 (e.g., use `keywords:foo,bar+baz,-quux` to include keywords `foo` OR (`bar` AND `baz`) but NOT `quux`)
433 - `not:unstable`: exclude unstable packages (semver version `<1.0.0`)
434 - `not:insecure`: exclude insecure packages
435 - `is:unstable`: include only unstable packages (semver version `<1.0.0`)
436 - `is:insecure`: include only insecure packages
437 - `boost-exact:<true/false>`: boost packages with exact name match (default: `true`)
438 */
439 text: z15.string().optional(),
440 /** Number of results to return (the npm registry accepts a maximum of `250` with a default of `20`). */
441 size: z15.number().optional(),
442 /** Return results from this offset. */
443 from: z15.number().optional(),
444 /** Package quality weight (from `0.0` to `1.0`). */
445 quality: z15.number().optional(),
446 /** Package popularity weight (from `0.0` to `1.0`). */
447 popularity: z15.number().optional(),
448 /** Package maintenance weight (from `0.0` to `1.0`). */
449 maintenance: z15.number().optional()
450});
451var SearchResult = z15.object({
452 /** Package metadata. */
453 package: PackageJson3.pick({
454 name: true,
455 version: true,
456 description: true,
457 keywords: true
458 }).extend({
459 /**
460 Either `unscoped` for unscoped packages (e.g., `foo` -> `unscoped`) or
461 the package's scope for scoped packages (e.g., `@foo/bar` -> `foo`).
462 */
463 scope: z15.string(),
464 /**
465 Timestamp of when the `latest` version of the package was published
466 in ISO 8601 format (e.g., `2021-11-23T19:12:24.006Z`).
467 */
468 date: z15.string(),
469 /** Author of the package. */
470 author: z15.object({
471 username: z15.string().optional(),
472 name: z15.string().optional(),
473 email: z15.string().optional(),
474 url: z15.string().optional()
475 }).optional(),
476 /** User who published the `latest` version of the package. */
477 publisher: z15.object({
478 username: z15.string(),
479 email: z15.string()
480 }),
481 /** Maintainers of the `latest` version of the package. */
482 maintainers: z15.array(
483 z15.object({
484 username: z15.string(),
485 email: z15.string()
486 })
487 ),
488 /** Links to resources associated to the package. */
489 links: z15.object({
490 /** Page for the package on npmjs.com. */
491 npm: z15.string().optional(),
492 /** Homepage for the package. */
493 homepage: z15.string().optional(),
494 /** Repository for the package. */
495 repository: z15.string().optional(),
496 /** Issue tracker for the package. */
497 bugs: z15.string().optional()
498 })
499 }),
500 /** Final and detailed search score values. */
501 score: z15.object({
502 /** Final search score value (from `0.0` to `1.0`), computed from the detailed scores. */
503 final: z15.number(),
504 /** Detailed search score values. */
505 detail: z15.object({
506 /** Quality search score value (from `0.0` to `1.0`). */
507 quality: z15.number(),
508 /** Popularity search score value (from `0.0` to `1.0`). */
509 popularity: z15.number(),
510 /** Maintenance search score value (from `0.0` to `1.0`). */
511 maintenance: z15.number()
512 })
513 }),
514 /** Search score value; may be different from `score.final`. */
515 searchScore: z15.number(),
516 /** Flag attributes for the package. */
517 flags: z15.object({
518 /** True if the package semver version number is `<1.0.0`. */
519 unstable: z15.coerce.boolean().optional(),
520 /** True if the package is insecure or has vulnerable dependencies. */
521 insecure: z15.coerce.boolean().optional()
522 }).optional()
523});
524var SearchResults = z15.object({
525 objects: z15.array(SearchResult),
526 /**
527 Total number of corresponding search results available;
528 may be higher than the number of `objects` returned.
529 */
530 total: z15.number(),
531 /** Date at which the search happened. */
532 time: z15.string()
533});
534var searchPackages = async (criteria, registry = npmRegistryUrl) => fetchData(SearchResults, urlJoin12(registry, "-/v1/search", `?${queryString.stringify(criteria)}`));
535export {
536 AbbreviatedPackument,
537 BulkDailyPackageDownloads,
538 BulkPackageDownloads,
539 DailyPackageDownloads,
540 DailyRegistryDownloads,
541 DownloadPeriod,
542 PackageDownloads,
543 PackageJson4 as PackageJson,
544 PackageManifest,
545 PackageVersionsDownloads,
546 Packument,
547 RegistryDownloads,
548 RegistryMetadata,
549 RegistrySigningKeys,
550 SearchCriteria,
551 SearchResults,
552 cache,
553 getAbbreviatedPackument,
554 getBulkDailyPackageDownloads,
555 getBulkPackageDownloads,
556 getDailyPackageDownloads,
557 getDailyRegistryDownloads,
558 getPackageDownloads,
559 getPackageManifest,
560 getPackageVersionsDownloads,
561 getPackument,
562 getRegistryDownloads,
563 getRegistryMetadata,
564 getRegistrySigningKeys,
565 npmRegistryDownloadsApiUrl,
566 npmRegistryUrl,
567 searchPackages
568};