@mcptoolshop/registry-stats 0.3.0
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/LICENSE +21 -0
- package/README.es.md +206 -0
- package/README.fr.md +206 -0
- package/README.hi.md +206 -0
- package/README.it.md +206 -0
- package/README.ja.md +206 -0
- package/README.md +239 -0
- package/README.pt-BR.md +206 -0
- package/README.zh.md +206 -0
- package/assets/logo.png +0 -0
- package/dist/cli.js +880 -0
- package/dist/index.cjs +669 -0
- package/dist/index.d.cts +130 -0
- package/dist/index.d.ts +130 -0
- package/dist/index.js +633 -0
- package/package.json +62 -0
package/README.pt-BR.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="README.md">English</a> | <a href="README.ja.md">日本語</a> | <a href="README.zh.md">中文</a> | <a href="README.es.md">Español</a> | <a href="README.fr.md">Français</a> | <a href="README.hi.md">हिन्दी</a> | <a href="README.it.md">Italiano</a> | <strong>Português</strong>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<img src="assets/logo.png" alt="logo registry-stats" width="280" />
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<h1 align="center">@mcptoolshop/registry-stats</h1>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
Um comando. Cinco registros. Todas as suas estatísticas de download.
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<a href="#instalação">Instalação</a> ·
|
|
17
|
+
<a href="#cli">CLI</a> ·
|
|
18
|
+
<a href="#arquivo-de-configuração">Configuração</a> ·
|
|
19
|
+
<a href="#api-programática">API</a> ·
|
|
20
|
+
<a href="#servidor-rest-api">Servidor REST</a> ·
|
|
21
|
+
<a href="#licença">Licença</a>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
Se você publica no npm, PyPI, NuGet, VS Code Marketplace ou Docker Hub, atualmente precisa de cinco APIs diferentes para responder "quantos downloads eu tive este mês?" Esta biblioteca oferece uma interface unificada — como CLI ou API programática.
|
|
27
|
+
|
|
28
|
+
Zero dependências. Usa `fetch()` nativo. Node 18+.
|
|
29
|
+
|
|
30
|
+
## Instalação
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install @mcptoolshop/registry-stats
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## CLI
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Consultar um único registro
|
|
40
|
+
registry-stats express -r npm
|
|
41
|
+
|
|
42
|
+
# Consultar todos os registros
|
|
43
|
+
registry-stats express
|
|
44
|
+
|
|
45
|
+
# Série temporal com detalhamento mensal + tendência
|
|
46
|
+
registry-stats express -r npm --range 2025-01-01:2025-06-30
|
|
47
|
+
|
|
48
|
+
# Saída JSON
|
|
49
|
+
registry-stats express -r npm --json
|
|
50
|
+
|
|
51
|
+
# Outros registros
|
|
52
|
+
registry-stats requests -r pypi
|
|
53
|
+
registry-stats Newtonsoft.Json -r nuget
|
|
54
|
+
registry-stats esbenp.prettier-vscode -r vscode
|
|
55
|
+
registry-stats library/node -r docker
|
|
56
|
+
|
|
57
|
+
# Criar arquivo de configuração
|
|
58
|
+
registry-stats --init
|
|
59
|
+
|
|
60
|
+
# Executar com configuração — busca todos os pacotes rastreados
|
|
61
|
+
registry-stats
|
|
62
|
+
|
|
63
|
+
# Comparar entre registros
|
|
64
|
+
registry-stats express --compare
|
|
65
|
+
|
|
66
|
+
# Exportar como CSV ou JSON para gráficos
|
|
67
|
+
registry-stats express -r npm --range 2025-01-01:2025-06-30 --format csv
|
|
68
|
+
registry-stats express -r npm --range 2025-01-01:2025-06-30 --format chart
|
|
69
|
+
|
|
70
|
+
# Iniciar servidor REST API
|
|
71
|
+
registry-stats serve --port 3000
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Arquivo de Configuração
|
|
75
|
+
|
|
76
|
+
Crie um `registry-stats.config.json` na raiz do projeto (ou execute `registry-stats --init`):
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"registries": ["npm", "pypi", "nuget", "vscode", "docker"],
|
|
81
|
+
"packages": {
|
|
82
|
+
"mcpt": {
|
|
83
|
+
"npm": "mcpt",
|
|
84
|
+
"pypi": "mcpt"
|
|
85
|
+
},
|
|
86
|
+
"tool-compass": {
|
|
87
|
+
"npm": "@mcptoolshop/tool-compass",
|
|
88
|
+
"vscode": "mcp-tool-shop.tool-compass"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"cache": true,
|
|
92
|
+
"cacheTtlMs": 300000,
|
|
93
|
+
"concurrency": 5
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Execute `registry-stats` sem argumentos para obter estatísticas de todos os pacotes configurados. O CLI procura o arquivo de configuração subindo a partir do diretório atual.
|
|
98
|
+
|
|
99
|
+
## API Programática
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { stats, calc, createCache } from '@mcptoolshop/registry-stats';
|
|
103
|
+
|
|
104
|
+
// Registro único
|
|
105
|
+
const npm = await stats('npm', 'express');
|
|
106
|
+
const pypi = await stats('pypi', 'requests');
|
|
107
|
+
|
|
108
|
+
// Todos os registros (usa Promise.allSettled — nunca lança erro)
|
|
109
|
+
const all = await stats.all('express');
|
|
110
|
+
|
|
111
|
+
// Em massa — múltiplos pacotes, concorrência limitada (padrão: 5)
|
|
112
|
+
const bulk = await stats.bulk('npm', ['express', 'koa', 'fastify']);
|
|
113
|
+
|
|
114
|
+
// Série temporal (apenas npm + pypi)
|
|
115
|
+
const daily = await stats.range('npm', 'express', '2025-01-01', '2025-06-30');
|
|
116
|
+
|
|
117
|
+
// Cálculos
|
|
118
|
+
calc.total(daily); // total de downloads
|
|
119
|
+
calc.avg(daily); // média diária
|
|
120
|
+
calc.trend(daily); // { direction: 'up', changePercent: 8.3 }
|
|
121
|
+
calc.movingAvg(daily, 7); // média móvel de 7 dias
|
|
122
|
+
calc.popularity(daily); // pontuação 0-100 escala logarítmica
|
|
123
|
+
|
|
124
|
+
// Formatos de exportação
|
|
125
|
+
calc.toCSV(daily); // string CSV
|
|
126
|
+
calc.toChartData(daily, 'express'); // { labels: [...], datasets: [...] }
|
|
127
|
+
|
|
128
|
+
// Comparação — mesmo pacote entre registros
|
|
129
|
+
const comparison = await stats.compare('express');
|
|
130
|
+
await stats.compare('express', ['npm', 'pypi']);
|
|
131
|
+
|
|
132
|
+
// Cache (TTL 5 min, em memória)
|
|
133
|
+
const cache = createCache();
|
|
134
|
+
await stats('npm', 'express', { cache });
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Suporte de Registros
|
|
138
|
+
|
|
139
|
+
| Registro | Formato do pacote | Série temporal | Dados disponíveis |
|
|
140
|
+
|----------|------------------|----------------|-------------------|
|
|
141
|
+
| `npm` | `express`, `@scope/pkg` | Sim (549 dias) | lastDay, lastWeek, lastMonth |
|
|
142
|
+
| `pypi` | `requests` | Sim (180 dias) | lastDay, lastWeek, lastMonth, total |
|
|
143
|
+
| `nuget` | `Newtonsoft.Json` | Não | total |
|
|
144
|
+
| `vscode` | `publisher.extension` | Não | total (instalações), rating, trends |
|
|
145
|
+
| `docker` | `namespace/repo` | Não | total (pulls), stars |
|
|
146
|
+
|
|
147
|
+
## Confiabilidade Integrada
|
|
148
|
+
|
|
149
|
+
- Retry automático com backoff exponencial em erros 429/5xx
|
|
150
|
+
- Respeita os cabeçalhos `Retry-After`
|
|
151
|
+
- Limitação de concorrência para requisições em massa
|
|
152
|
+
- Cache TTL opcional (extensível — use Redis/arquivo via interface `StatsCache`)
|
|
153
|
+
|
|
154
|
+
## Servidor REST API
|
|
155
|
+
|
|
156
|
+
Execute como microsserviço ou integre ao seu servidor:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
registry-stats serve --port 3000
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
GET /stats/:package # todos os registros
|
|
164
|
+
GET /stats/:registry/:package # registro único
|
|
165
|
+
GET /compare/:package?registries=npm,pypi
|
|
166
|
+
GET /range/:registry/:package?start=YYYY-MM-DD&end=YYYY-MM-DD&format=json|csv|chart
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { createHandler, serve } from '@mcptoolshop/registry-stats';
|
|
171
|
+
|
|
172
|
+
// Início rápido
|
|
173
|
+
serve({ port: 3000 });
|
|
174
|
+
|
|
175
|
+
// Servidor personalizado
|
|
176
|
+
import { createServer } from 'node:http';
|
|
177
|
+
const handler = createHandler();
|
|
178
|
+
createServer(handler).listen(3000);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Registros Personalizados
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import { registerProvider, type RegistryProvider } from '@mcptoolshop/registry-stats';
|
|
185
|
+
|
|
186
|
+
const cargo: RegistryProvider = {
|
|
187
|
+
name: 'cargo',
|
|
188
|
+
async getStats(pkg) {
|
|
189
|
+
const res = await fetch(`https://crates.io/api/v1/crates/${pkg}`);
|
|
190
|
+
const json = await res.json();
|
|
191
|
+
return {
|
|
192
|
+
registry: 'cargo' as any,
|
|
193
|
+
package: pkg,
|
|
194
|
+
downloads: { total: json.crate.downloads },
|
|
195
|
+
fetchedAt: new Date().toISOString(),
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
registerProvider(cargo);
|
|
201
|
+
await stats('cargo', 'serde');
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Licença
|
|
205
|
+
|
|
206
|
+
MIT
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="README.md">English</a> | <a href="README.ja.md">日本語</a> | <strong>中文</strong> | <a href="README.es.md">Español</a> | <a href="README.fr.md">Français</a> | <a href="README.hi.md">हिन्दी</a> | <a href="README.it.md">Italiano</a> | <a href="README.pt-BR.md">Português</a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<img src="assets/logo.png" alt="registry-stats 标志" width="280" />
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<h1 align="center">@mcptoolshop/registry-stats</h1>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
一个命令。五个注册表。所有下载统计。
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<a href="#安装">安装</a> ·
|
|
17
|
+
<a href="#cli">CLI</a> ·
|
|
18
|
+
<a href="#配置文件">配置</a> ·
|
|
19
|
+
<a href="#编程接口">API</a> ·
|
|
20
|
+
<a href="#rest-api-服务器">REST 服务器</a> ·
|
|
21
|
+
<a href="#许可证">许可证</a>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
如果你在 npm、PyPI、NuGet、VS Code Marketplace 或 Docker Hub 上发布包,你目前需要五个不同的 API 来回答"这个月我有多少下载量?"这个库提供统一接口 — 支持 CLI 和编程方式。
|
|
27
|
+
|
|
28
|
+
零依赖。使用原生 `fetch()`。Node 18+。
|
|
29
|
+
|
|
30
|
+
## 安装
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install @mcptoolshop/registry-stats
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## CLI
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# 查询单个注册表
|
|
40
|
+
registry-stats express -r npm
|
|
41
|
+
|
|
42
|
+
# 一次查询所有注册表
|
|
43
|
+
registry-stats express
|
|
44
|
+
|
|
45
|
+
# 带月度细分和趋势的时间序列
|
|
46
|
+
registry-stats express -r npm --range 2025-01-01:2025-06-30
|
|
47
|
+
|
|
48
|
+
# JSON 输出
|
|
49
|
+
registry-stats express -r npm --json
|
|
50
|
+
|
|
51
|
+
# 其他注册表
|
|
52
|
+
registry-stats requests -r pypi
|
|
53
|
+
registry-stats Newtonsoft.Json -r nuget
|
|
54
|
+
registry-stats esbenp.prettier-vscode -r vscode
|
|
55
|
+
registry-stats library/node -r docker
|
|
56
|
+
|
|
57
|
+
# 创建配置文件
|
|
58
|
+
registry-stats --init
|
|
59
|
+
|
|
60
|
+
# 从配置运行 — 获取所有跟踪包的统计
|
|
61
|
+
registry-stats
|
|
62
|
+
|
|
63
|
+
# 跨注册表比较
|
|
64
|
+
registry-stats express --compare
|
|
65
|
+
|
|
66
|
+
# 导出为 CSV 或图表友好的 JSON
|
|
67
|
+
registry-stats express -r npm --range 2025-01-01:2025-06-30 --format csv
|
|
68
|
+
registry-stats express -r npm --range 2025-01-01:2025-06-30 --format chart
|
|
69
|
+
|
|
70
|
+
# 启动 REST API 服务器
|
|
71
|
+
registry-stats serve --port 3000
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 配置文件
|
|
75
|
+
|
|
76
|
+
在项目根目录创建 `registry-stats.config.json`(或运行 `registry-stats --init`):
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"registries": ["npm", "pypi", "nuget", "vscode", "docker"],
|
|
81
|
+
"packages": {
|
|
82
|
+
"mcpt": {
|
|
83
|
+
"npm": "mcpt",
|
|
84
|
+
"pypi": "mcpt"
|
|
85
|
+
},
|
|
86
|
+
"tool-compass": {
|
|
87
|
+
"npm": "@mcptoolshop/tool-compass",
|
|
88
|
+
"vscode": "mcp-tool-shop.tool-compass"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"cache": true,
|
|
92
|
+
"cacheTtlMs": 300000,
|
|
93
|
+
"concurrency": 5
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
不带参数运行 `registry-stats` 即可获取所有配置包的统计。CLI 会从当前目录向上查找配置文件。
|
|
98
|
+
|
|
99
|
+
## 编程接口
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { stats, calc, createCache } from '@mcptoolshop/registry-stats';
|
|
103
|
+
|
|
104
|
+
// 单个注册表
|
|
105
|
+
const npm = await stats('npm', 'express');
|
|
106
|
+
const pypi = await stats('pypi', 'requests');
|
|
107
|
+
|
|
108
|
+
// 所有注册表(使用 Promise.allSettled — 永不抛出)
|
|
109
|
+
const all = await stats.all('express');
|
|
110
|
+
|
|
111
|
+
// 批量 — 多个包,并发限制(默认:5)
|
|
112
|
+
const bulk = await stats.bulk('npm', ['express', 'koa', 'fastify']);
|
|
113
|
+
|
|
114
|
+
// 时间序列(仅 npm + pypi)
|
|
115
|
+
const daily = await stats.range('npm', 'express', '2025-01-01', '2025-06-30');
|
|
116
|
+
|
|
117
|
+
// 计算
|
|
118
|
+
calc.total(daily); // 下载总量
|
|
119
|
+
calc.avg(daily); // 日均量
|
|
120
|
+
calc.trend(daily); // { direction: 'up', changePercent: 8.3 }
|
|
121
|
+
calc.movingAvg(daily, 7); // 7天移动平均
|
|
122
|
+
calc.popularity(daily); // 0-100 对数刻度评分
|
|
123
|
+
|
|
124
|
+
// 导出格式
|
|
125
|
+
calc.toCSV(daily); // CSV 字符串
|
|
126
|
+
calc.toChartData(daily, 'express'); // { labels: [...], datasets: [...] }
|
|
127
|
+
|
|
128
|
+
// 比较 — 跨注册表的同一包
|
|
129
|
+
const comparison = await stats.compare('express');
|
|
130
|
+
await stats.compare('express', ['npm', 'pypi']);
|
|
131
|
+
|
|
132
|
+
// 缓存(5分钟 TTL,内存中)
|
|
133
|
+
const cache = createCache();
|
|
134
|
+
await stats('npm', 'express', { cache });
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## 注册表支持
|
|
138
|
+
|
|
139
|
+
| 注册表 | 包格式 | 时间序列 | 可用数据 |
|
|
140
|
+
|--------|--------|----------|----------|
|
|
141
|
+
| `npm` | `express`, `@scope/pkg` | 支持(549天) | lastDay, lastWeek, lastMonth |
|
|
142
|
+
| `pypi` | `requests` | 支持(180天) | lastDay, lastWeek, lastMonth, total |
|
|
143
|
+
| `nuget` | `Newtonsoft.Json` | 不支持 | total |
|
|
144
|
+
| `vscode` | `publisher.extension` | 不支持 | total(安装数)、rating、trends |
|
|
145
|
+
| `docker` | `namespace/repo` | 不支持 | total(拉取数)、stars |
|
|
146
|
+
|
|
147
|
+
## 内置可靠性
|
|
148
|
+
|
|
149
|
+
- 429/5xx 错误的指数退避自动重试
|
|
150
|
+
- 遵守 `Retry-After` 头部
|
|
151
|
+
- 批量请求的并发限制
|
|
152
|
+
- 可选的 TTL 缓存(可插拔 — 通过 `StatsCache` 接口使用 Redis/文件后端)
|
|
153
|
+
|
|
154
|
+
## REST API 服务器
|
|
155
|
+
|
|
156
|
+
作为微服务运行,或嵌入到自己的服务器中:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
registry-stats serve --port 3000
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
GET /stats/:package # 所有注册表
|
|
164
|
+
GET /stats/:registry/:package # 单个注册表
|
|
165
|
+
GET /compare/:package?registries=npm,pypi
|
|
166
|
+
GET /range/:registry/:package?start=YYYY-MM-DD&end=YYYY-MM-DD&format=json|csv|chart
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { createHandler, serve } from '@mcptoolshop/registry-stats';
|
|
171
|
+
|
|
172
|
+
// 快速启动
|
|
173
|
+
serve({ port: 3000 });
|
|
174
|
+
|
|
175
|
+
// 自定义服务器
|
|
176
|
+
import { createServer } from 'node:http';
|
|
177
|
+
const handler = createHandler();
|
|
178
|
+
createServer(handler).listen(3000);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## 自定义注册表
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import { registerProvider, type RegistryProvider } from '@mcptoolshop/registry-stats';
|
|
185
|
+
|
|
186
|
+
const cargo: RegistryProvider = {
|
|
187
|
+
name: 'cargo',
|
|
188
|
+
async getStats(pkg) {
|
|
189
|
+
const res = await fetch(`https://crates.io/api/v1/crates/${pkg}`);
|
|
190
|
+
const json = await res.json();
|
|
191
|
+
return {
|
|
192
|
+
registry: 'cargo' as any,
|
|
193
|
+
package: pkg,
|
|
194
|
+
downloads: { total: json.crate.downloads },
|
|
195
|
+
fetchedAt: new Date().toISOString(),
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
registerProvider(cargo);
|
|
201
|
+
await stats('cargo', 'serde');
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## 许可证
|
|
205
|
+
|
|
206
|
+
MIT
|
package/assets/logo.png
ADDED
|
Binary file
|