@mcptoolshop/registry-stats 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -25,8 +25,10 @@ var REGISTRY_DELAYS = {
25
25
  // ~2.5 req/s — safe for 54+ scoped packages
26
26
  pypi: 2200,
27
27
  // 30 req/60s = 1 per 2s, with headroom
28
- docker: 4e3
28
+ docker: 4e3,
29
29
  // 10 req/3600s — very tight
30
+ ghcr: 200
31
+ // 5000 req/hr authenticated, 60/hr unauth
30
32
  };
31
33
  var DEFAULT_DELAY = 100;
32
34
  function acquireSlot(registry) {
@@ -301,6 +303,46 @@ var docker = {
301
303
  }
302
304
  };
303
305
 
306
+ // src/providers/ghcr.ts
307
+ var API5 = "https://api.github.com";
308
+ var ghcr = {
309
+ name: "ghcr",
310
+ rateLimit: { maxRequests: 50, windowSeconds: 3600, authRaisesLimit: true },
311
+ async getStats(pkg, options) {
312
+ const slash = pkg.indexOf("/");
313
+ if (slash === -1) return null;
314
+ const owner = pkg.slice(0, slash);
315
+ const name = pkg.slice(slash + 1);
316
+ const headers = {
317
+ "Accept": "application/vnd.github+json",
318
+ "X-GitHub-Api-Version": "2022-11-28"
319
+ };
320
+ if (options?.ghcrToken) {
321
+ headers["Authorization"] = `Bearer ${options.ghcrToken}`;
322
+ }
323
+ const versions = await fetchWithRetry(
324
+ `${API5}/orgs/${owner}/packages/container/${encodeURIComponent(name)}/versions?per_page=100`,
325
+ "ghcr",
326
+ { headers }
327
+ );
328
+ if (!versions || !Array.isArray(versions)) return null;
329
+ const totalPulls = versions.reduce((sum, v) => sum + (v.download_count ?? 0), 0);
330
+ const tags = versions.flatMap((v) => v.metadata?.container?.tags ?? []);
331
+ return {
332
+ registry: "ghcr",
333
+ package: pkg,
334
+ downloads: {
335
+ total: totalPulls
336
+ },
337
+ extra: {
338
+ tags: tags.slice(0, 10),
339
+ versionCount: versions.length
340
+ },
341
+ fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
342
+ };
343
+ }
344
+ };
345
+
304
346
  // src/calc.ts
305
347
  var calc = {
306
348
  total(records) {
@@ -604,7 +646,8 @@ var providers = {
604
646
  pypi,
605
647
  nuget,
606
648
  vscode,
607
- docker
649
+ docker,
650
+ ghcr
608
651
  };
609
652
  var DEFAULT_TTL = 3e5;
610
653
  async function stats(registry, pkg, options) {
package/dist/index.cjs CHANGED
@@ -54,8 +54,10 @@ var REGISTRY_DELAYS = {
54
54
  // ~2.5 req/s — safe for 54+ scoped packages
55
55
  pypi: 2200,
56
56
  // 30 req/60s = 1 per 2s, with headroom
57
- docker: 4e3
57
+ docker: 4e3,
58
58
  // 10 req/3600s — very tight
59
+ ghcr: 200
60
+ // 5000 req/hr authenticated, 60/hr unauth
59
61
  };
60
62
  var DEFAULT_DELAY = 100;
61
63
  function acquireSlot(registry) {
@@ -330,6 +332,46 @@ var docker = {
330
332
  }
331
333
  };
332
334
 
335
+ // src/providers/ghcr.ts
336
+ var API5 = "https://api.github.com";
337
+ var ghcr = {
338
+ name: "ghcr",
339
+ rateLimit: { maxRequests: 50, windowSeconds: 3600, authRaisesLimit: true },
340
+ async getStats(pkg, options) {
341
+ const slash = pkg.indexOf("/");
342
+ if (slash === -1) return null;
343
+ const owner = pkg.slice(0, slash);
344
+ const name = pkg.slice(slash + 1);
345
+ const headers = {
346
+ "Accept": "application/vnd.github+json",
347
+ "X-GitHub-Api-Version": "2022-11-28"
348
+ };
349
+ if (options?.ghcrToken) {
350
+ headers["Authorization"] = `Bearer ${options.ghcrToken}`;
351
+ }
352
+ const versions = await fetchWithRetry(
353
+ `${API5}/orgs/${owner}/packages/container/${encodeURIComponent(name)}/versions?per_page=100`,
354
+ "ghcr",
355
+ { headers }
356
+ );
357
+ if (!versions || !Array.isArray(versions)) return null;
358
+ const totalPulls = versions.reduce((sum, v) => sum + (v.download_count ?? 0), 0);
359
+ const tags = versions.flatMap((v) => v.metadata?.container?.tags ?? []);
360
+ return {
361
+ registry: "ghcr",
362
+ package: pkg,
363
+ downloads: {
364
+ total: totalPulls
365
+ },
366
+ extra: {
367
+ tags: tags.slice(0, 10),
368
+ versionCount: versions.length
369
+ },
370
+ fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
371
+ };
372
+ }
373
+ };
374
+
333
375
  // src/calc.ts
334
376
  var calc = {
335
377
  total(records) {
@@ -642,7 +684,8 @@ var providers = {
642
684
  pypi,
643
685
  nuget,
644
686
  vscode,
645
- docker
687
+ docker,
688
+ ghcr
646
689
  };
647
690
  function registerProvider(provider) {
648
691
  providers[provider.name] = provider;
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as node_http from 'node:http';
2
2
  import { IncomingMessage, ServerResponse } from 'node:http';
3
3
 
4
- type RegistryName = 'npm' | 'pypi' | 'nuget' | 'vscode' | 'docker';
4
+ type RegistryName = 'npm' | 'pypi' | 'nuget' | 'vscode' | 'docker' | 'ghcr';
5
5
  interface PackageStats {
6
6
  registry: RegistryName;
7
7
  package: string;
@@ -38,6 +38,8 @@ interface StatsCache {
38
38
  }
39
39
  interface StatsOptions {
40
40
  dockerToken?: string;
41
+ /** GitHub token for GHCR (GitHub Container Registry) — read:packages scope */
42
+ ghcrToken?: string;
41
43
  /** Max concurrent requests for bulk operations (default: 5) */
42
44
  concurrency?: number;
43
45
  /** Cache instance — use createCache() for built-in TTL cache */
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as node_http from 'node:http';
2
2
  import { IncomingMessage, ServerResponse } from 'node:http';
3
3
 
4
- type RegistryName = 'npm' | 'pypi' | 'nuget' | 'vscode' | 'docker';
4
+ type RegistryName = 'npm' | 'pypi' | 'nuget' | 'vscode' | 'docker' | 'ghcr';
5
5
  interface PackageStats {
6
6
  registry: RegistryName;
7
7
  package: string;
@@ -38,6 +38,8 @@ interface StatsCache {
38
38
  }
39
39
  interface StatsOptions {
40
40
  dockerToken?: string;
41
+ /** GitHub token for GHCR (GitHub Container Registry) — read:packages scope */
42
+ ghcrToken?: string;
41
43
  /** Max concurrent requests for bulk operations (default: 5) */
42
44
  concurrency?: number;
43
45
  /** Cache instance — use createCache() for built-in TTL cache */
package/dist/index.js CHANGED
@@ -19,8 +19,10 @@ var REGISTRY_DELAYS = {
19
19
  // ~2.5 req/s — safe for 54+ scoped packages
20
20
  pypi: 2200,
21
21
  // 30 req/60s = 1 per 2s, with headroom
22
- docker: 4e3
22
+ docker: 4e3,
23
23
  // 10 req/3600s — very tight
24
+ ghcr: 200
25
+ // 5000 req/hr authenticated, 60/hr unauth
24
26
  };
25
27
  var DEFAULT_DELAY = 100;
26
28
  function acquireSlot(registry) {
@@ -295,6 +297,46 @@ var docker = {
295
297
  }
296
298
  };
297
299
 
300
+ // src/providers/ghcr.ts
301
+ var API5 = "https://api.github.com";
302
+ var ghcr = {
303
+ name: "ghcr",
304
+ rateLimit: { maxRequests: 50, windowSeconds: 3600, authRaisesLimit: true },
305
+ async getStats(pkg, options) {
306
+ const slash = pkg.indexOf("/");
307
+ if (slash === -1) return null;
308
+ const owner = pkg.slice(0, slash);
309
+ const name = pkg.slice(slash + 1);
310
+ const headers = {
311
+ "Accept": "application/vnd.github+json",
312
+ "X-GitHub-Api-Version": "2022-11-28"
313
+ };
314
+ if (options?.ghcrToken) {
315
+ headers["Authorization"] = `Bearer ${options.ghcrToken}`;
316
+ }
317
+ const versions = await fetchWithRetry(
318
+ `${API5}/orgs/${owner}/packages/container/${encodeURIComponent(name)}/versions?per_page=100`,
319
+ "ghcr",
320
+ { headers }
321
+ );
322
+ if (!versions || !Array.isArray(versions)) return null;
323
+ const totalPulls = versions.reduce((sum, v) => sum + (v.download_count ?? 0), 0);
324
+ const tags = versions.flatMap((v) => v.metadata?.container?.tags ?? []);
325
+ return {
326
+ registry: "ghcr",
327
+ package: pkg,
328
+ downloads: {
329
+ total: totalPulls
330
+ },
331
+ extra: {
332
+ tags: tags.slice(0, 10),
333
+ versionCount: versions.length
334
+ },
335
+ fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
336
+ };
337
+ }
338
+ };
339
+
298
340
  // src/calc.ts
299
341
  var calc = {
300
342
  total(records) {
@@ -607,7 +649,8 @@ var providers = {
607
649
  pypi,
608
650
  nuget,
609
651
  vscode,
610
- docker
652
+ docker,
653
+ ghcr
611
654
  };
612
655
  function registerProvider(provider) {
613
656
  providers[provider.name] = provider;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcptoolshop/registry-stats",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Multi-registry download stats for npm, PyPI, NuGet, VS Code Marketplace, and Docker Hub",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",