@mcptoolshop/registry-stats 1.2.1 → 1.2.3
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 +70 -2
- package/dist/index.cjs +70 -2
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +70 -2
- package/package.json +1 -1
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,71 @@ 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 now = Date.now();
|
|
330
|
+
const DAY = 864e5;
|
|
331
|
+
let activity7d = 0;
|
|
332
|
+
let activity30d = 0;
|
|
333
|
+
let lastPublished = null;
|
|
334
|
+
for (const v of versions) {
|
|
335
|
+
const created = v.created_at ? new Date(v.created_at).getTime() : 0;
|
|
336
|
+
if (created > 0) {
|
|
337
|
+
const age = now - created;
|
|
338
|
+
if (age <= 7 * DAY) activity7d++;
|
|
339
|
+
if (age <= 30 * DAY) activity30d++;
|
|
340
|
+
if (!lastPublished || v.created_at > lastPublished) {
|
|
341
|
+
lastPublished = v.created_at;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const tags = versions.flatMap((v) => v.metadata?.container?.tags ?? []);
|
|
346
|
+
return {
|
|
347
|
+
registry: "ghcr",
|
|
348
|
+
package: pkg,
|
|
349
|
+
downloads: {
|
|
350
|
+
total: versions.length,
|
|
351
|
+
// versionCount as primary number
|
|
352
|
+
lastWeek: activity7d,
|
|
353
|
+
// new versions in 7d
|
|
354
|
+
lastMonth: activity30d
|
|
355
|
+
// new versions in 30d
|
|
356
|
+
},
|
|
357
|
+
extra: {
|
|
358
|
+
metricType: "versions",
|
|
359
|
+
// signals this is version activity, not downloads
|
|
360
|
+
tags: tags.slice(0, 10),
|
|
361
|
+
versionCount: versions.length,
|
|
362
|
+
activity7d,
|
|
363
|
+
activity30d,
|
|
364
|
+
lastPublished
|
|
365
|
+
},
|
|
366
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
|
|
304
371
|
// src/calc.ts
|
|
305
372
|
var calc = {
|
|
306
373
|
total(records) {
|
|
@@ -604,7 +671,8 @@ var providers = {
|
|
|
604
671
|
pypi,
|
|
605
672
|
nuget,
|
|
606
673
|
vscode,
|
|
607
|
-
docker
|
|
674
|
+
docker,
|
|
675
|
+
ghcr
|
|
608
676
|
};
|
|
609
677
|
var DEFAULT_TTL = 3e5;
|
|
610
678
|
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,71 @@ 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 now = Date.now();
|
|
359
|
+
const DAY = 864e5;
|
|
360
|
+
let activity7d = 0;
|
|
361
|
+
let activity30d = 0;
|
|
362
|
+
let lastPublished = null;
|
|
363
|
+
for (const v of versions) {
|
|
364
|
+
const created = v.created_at ? new Date(v.created_at).getTime() : 0;
|
|
365
|
+
if (created > 0) {
|
|
366
|
+
const age = now - created;
|
|
367
|
+
if (age <= 7 * DAY) activity7d++;
|
|
368
|
+
if (age <= 30 * DAY) activity30d++;
|
|
369
|
+
if (!lastPublished || v.created_at > lastPublished) {
|
|
370
|
+
lastPublished = v.created_at;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
const tags = versions.flatMap((v) => v.metadata?.container?.tags ?? []);
|
|
375
|
+
return {
|
|
376
|
+
registry: "ghcr",
|
|
377
|
+
package: pkg,
|
|
378
|
+
downloads: {
|
|
379
|
+
total: versions.length,
|
|
380
|
+
// versionCount as primary number
|
|
381
|
+
lastWeek: activity7d,
|
|
382
|
+
// new versions in 7d
|
|
383
|
+
lastMonth: activity30d
|
|
384
|
+
// new versions in 30d
|
|
385
|
+
},
|
|
386
|
+
extra: {
|
|
387
|
+
metricType: "versions",
|
|
388
|
+
// signals this is version activity, not downloads
|
|
389
|
+
tags: tags.slice(0, 10),
|
|
390
|
+
versionCount: versions.length,
|
|
391
|
+
activity7d,
|
|
392
|
+
activity30d,
|
|
393
|
+
lastPublished
|
|
394
|
+
},
|
|
395
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
|
|
333
400
|
// src/calc.ts
|
|
334
401
|
var calc = {
|
|
335
402
|
total(records) {
|
|
@@ -642,7 +709,8 @@ var providers = {
|
|
|
642
709
|
pypi,
|
|
643
710
|
nuget,
|
|
644
711
|
vscode,
|
|
645
|
-
docker
|
|
712
|
+
docker,
|
|
713
|
+
ghcr
|
|
646
714
|
};
|
|
647
715
|
function registerProvider(provider) {
|
|
648
716
|
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,71 @@ 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 now = Date.now();
|
|
324
|
+
const DAY = 864e5;
|
|
325
|
+
let activity7d = 0;
|
|
326
|
+
let activity30d = 0;
|
|
327
|
+
let lastPublished = null;
|
|
328
|
+
for (const v of versions) {
|
|
329
|
+
const created = v.created_at ? new Date(v.created_at).getTime() : 0;
|
|
330
|
+
if (created > 0) {
|
|
331
|
+
const age = now - created;
|
|
332
|
+
if (age <= 7 * DAY) activity7d++;
|
|
333
|
+
if (age <= 30 * DAY) activity30d++;
|
|
334
|
+
if (!lastPublished || v.created_at > lastPublished) {
|
|
335
|
+
lastPublished = v.created_at;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
const tags = versions.flatMap((v) => v.metadata?.container?.tags ?? []);
|
|
340
|
+
return {
|
|
341
|
+
registry: "ghcr",
|
|
342
|
+
package: pkg,
|
|
343
|
+
downloads: {
|
|
344
|
+
total: versions.length,
|
|
345
|
+
// versionCount as primary number
|
|
346
|
+
lastWeek: activity7d,
|
|
347
|
+
// new versions in 7d
|
|
348
|
+
lastMonth: activity30d
|
|
349
|
+
// new versions in 30d
|
|
350
|
+
},
|
|
351
|
+
extra: {
|
|
352
|
+
metricType: "versions",
|
|
353
|
+
// signals this is version activity, not downloads
|
|
354
|
+
tags: tags.slice(0, 10),
|
|
355
|
+
versionCount: versions.length,
|
|
356
|
+
activity7d,
|
|
357
|
+
activity30d,
|
|
358
|
+
lastPublished
|
|
359
|
+
},
|
|
360
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
|
|
298
365
|
// src/calc.ts
|
|
299
366
|
var calc = {
|
|
300
367
|
total(records) {
|
|
@@ -607,7 +674,8 @@ var providers = {
|
|
|
607
674
|
pypi,
|
|
608
675
|
nuget,
|
|
609
676
|
vscode,
|
|
610
|
-
docker
|
|
677
|
+
docker,
|
|
678
|
+
ghcr
|
|
611
679
|
};
|
|
612
680
|
function registerProvider(provider) {
|
|
613
681
|
providers[provider.name] = provider;
|
package/package.json
CHANGED