@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.
@@ -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> &middot;
17
+ <a href="#cli">CLI</a> &middot;
18
+ <a href="#arquivo-de-configuração">Configuração</a> &middot;
19
+ <a href="#api-programática">API</a> &middot;
20
+ <a href="#servidor-rest-api">Servidor REST</a> &middot;
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> &middot;
17
+ <a href="#cli">CLI</a> &middot;
18
+ <a href="#配置文件">配置</a> &middot;
19
+ <a href="#编程接口">API</a> &middot;
20
+ <a href="#rest-api-服务器">REST 服务器</a> &middot;
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
Binary file