@ssolis-ti/mcp-compra-agil 2.1.0 → 2.4.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/README.md +31 -11
- package/dist/api/compra-agil-client.d.ts +35 -1
- package/dist/api/compra-agil-client.d.ts.map +1 -1
- package/dist/api/compra-agil-client.js +69 -4
- package/dist/api/compra-agil-client.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/reports/templates/radar-oportunidades.d.ts +1 -1
- package/dist/reports/templates/radar-oportunidades.js +2 -2
- package/dist/reports/templates/radar-oportunidades.js.map +1 -1
- package/dist/resources/glosario.d.ts.map +1 -1
- package/dist/resources/glosario.js +6 -2
- package/dist/resources/glosario.js.map +1 -1
- package/dist/services/monitor.js +1 -1
- package/dist/services/monitor.js.map +1 -1
- package/dist/tools/analizar-precios-mercado.js +2 -2
- package/dist/tools/auditar-desiertas.js +2 -2
- package/dist/tools/detalle-oc.d.ts.map +1 -1
- package/dist/tools/detalle-oc.js +2 -3
- package/dist/tools/detalle-oc.js.map +1 -1
- package/dist/tools/documentos.d.ts.map +1 -1
- package/dist/tools/documentos.js +68 -37
- package/dist/tools/documentos.js.map +1 -1
- package/dist/tools/estadisticas-uso.d.ts.map +1 -1
- package/dist/tools/estadisticas-uso.js +12 -2
- package/dist/tools/estadisticas-uso.js.map +1 -1
- package/dist/tools/generar-borrador.d.ts +25 -1
- package/dist/tools/generar-borrador.d.ts.map +1 -1
- package/dist/tools/generar-borrador.js +96 -78
- package/dist/tools/generar-borrador.js.map +1 -1
- package/dist/tools/radar-oportunidades.d.ts +4 -1
- package/dist/tools/radar-oportunidades.d.ts.map +1 -1
- package/dist/tools/radar-oportunidades.js +24 -2
- package/dist/tools/radar-oportunidades.js.map +1 -1
- package/dist/tools/verificar-oc.d.ts.map +1 -1
- package/dist/tools/verificar-oc.js +30 -4
- package/dist/tools/verificar-oc.js.map +1 -1
- package/dist/utils/cache.d.ts +53 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +131 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/doc-search.d.ts +52 -0
- package/dist/utils/doc-search.d.ts.map +1 -0
- package/dist/utils/doc-search.js +97 -0
- package/dist/utils/doc-search.js.map +1 -0
- package/dist/utils/error-handler.d.ts.map +1 -1
- package/dist/utils/error-handler.js +4 -6
- package/dist/utils/error-handler.js.map +1 -1
- package/dist/utils/rate-limiter.d.ts +37 -2
- package/dist/utils/rate-limiter.d.ts.map +1 -1
- package/dist/utils/rate-limiter.js +101 -13
- package/dist/utils/rate-limiter.js.map +1 -1
- package/package.json +1 -1
|
@@ -5,18 +5,74 @@
|
|
|
5
5
|
* Este módulo lleva un contador local de requests para advertir
|
|
6
6
|
* proactivamente antes de alcanzar el límite.
|
|
7
7
|
*/
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
8
10
|
import { logger } from './logger.js';
|
|
11
|
+
/** Archivo donde el servidor recuerda la cuota entre reinicios. */
|
|
12
|
+
export const RUTA_ESTADO_POR_DEFECTO = path.resolve(process.cwd(), '.rate-limit-state.json');
|
|
9
13
|
export class RateLimiter {
|
|
10
14
|
requestCount = 0;
|
|
11
15
|
currentDay;
|
|
12
16
|
isLimited = false;
|
|
13
17
|
limitResetTime = null;
|
|
18
|
+
/** 429 seguidos sin una consulta exitosa en medio; gradúa la espera. */
|
|
19
|
+
consecutive429 = 0;
|
|
14
20
|
// Throttle proactivo por minuto (ventana deslizante de timestamps).
|
|
15
21
|
maxPerMinute;
|
|
16
22
|
requestTimestamps = [];
|
|
17
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Ruta de persistencia, o `null` para operar solo en memoria.
|
|
25
|
+
*
|
|
26
|
+
* ⚠ POR QUÉ SE PERSISTE: el contador vivía únicamente en memoria, así que
|
|
27
|
+
* cada arranque del servidor empezaba en cero. Como un servidor MCP se
|
|
28
|
+
* reinicia cada vez que el usuario reinicia su cliente, `obtener_estadisticas_uso`
|
|
29
|
+
* informaba `isLimited: false` incluso segundos después de que la API
|
|
30
|
+
* hubiera respondido 429 por cuota agotada, y el throttle preventivo
|
|
31
|
+
* disparaba peticiones contra un muro. Detectado en auditoría.
|
|
32
|
+
*/
|
|
33
|
+
statePath;
|
|
34
|
+
constructor(maxPerMinute = 40, statePath = null) {
|
|
18
35
|
this.currentDay = this.getTodayUTC();
|
|
19
36
|
this.maxPerMinute = maxPerMinute;
|
|
37
|
+
this.statePath = statePath;
|
|
38
|
+
this.cargarEstado();
|
|
39
|
+
}
|
|
40
|
+
/** Lee el estado del día en curso. Un estado de otro día se descarta. */
|
|
41
|
+
cargarEstado() {
|
|
42
|
+
if (!this.statePath)
|
|
43
|
+
return;
|
|
44
|
+
try {
|
|
45
|
+
if (!fs.existsSync(this.statePath))
|
|
46
|
+
return;
|
|
47
|
+
const raw = JSON.parse(fs.readFileSync(this.statePath, 'utf8'));
|
|
48
|
+
if (raw.day !== this.currentDay)
|
|
49
|
+
return;
|
|
50
|
+
this.requestCount = raw.requestCount ?? 0;
|
|
51
|
+
this.isLimited = raw.isLimited ?? false;
|
|
52
|
+
this.limitResetTime = raw.limitResetTime ? new Date(raw.limitResetTime) : null;
|
|
53
|
+
if (this.isLimited) {
|
|
54
|
+
logger.info('Rate limiter: se recuperó un estado de cuota agotada de esta misma jornada UTC.');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Un estado ilegible no debe impedir arrancar: se sigue en memoria.
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
guardarEstado() {
|
|
62
|
+
if (!this.statePath)
|
|
63
|
+
return;
|
|
64
|
+
try {
|
|
65
|
+
const estado = {
|
|
66
|
+
day: this.currentDay,
|
|
67
|
+
requestCount: this.requestCount,
|
|
68
|
+
isLimited: this.isLimited,
|
|
69
|
+
limitResetTime: this.limitResetTime?.toISOString() ?? null,
|
|
70
|
+
};
|
|
71
|
+
fs.writeFileSync(this.statePath, JSON.stringify(estado), 'utf8');
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Persistir es una mejora, no un requisito: si el disco no deja, se sigue.
|
|
75
|
+
}
|
|
20
76
|
}
|
|
21
77
|
getTodayUTC() {
|
|
22
78
|
return new Date().toISOString().split('T')[0];
|
|
@@ -54,19 +110,50 @@ export class RateLimiter {
|
|
|
54
110
|
logger.info('Rate limiter: contador diario reseteado (nuevo día calendario UTC).');
|
|
55
111
|
}
|
|
56
112
|
this.requestCount++;
|
|
113
|
+
// Una consulta exitosa prueba que el balde volvió a tener fichas.
|
|
114
|
+
if (this.consecutive429 > 0 || this.isLimited) {
|
|
115
|
+
this.consecutive429 = 0;
|
|
116
|
+
this.isLimited = false;
|
|
117
|
+
this.limitResetTime = null;
|
|
118
|
+
}
|
|
57
119
|
logger.debug(`Rate limiter: request #${this.requestCount} del día.`);
|
|
120
|
+
this.guardarEstado();
|
|
58
121
|
}
|
|
59
122
|
/**
|
|
60
123
|
* Marca que se recibió un error 429.
|
|
124
|
+
*
|
|
125
|
+
* ⚠ POR QUÉ NO SE BLOQUEA HASTA MAÑANA: antes, un solo 429 fijaba el reset
|
|
126
|
+
* en las 00:01 UTC del día siguiente y `checkLimit()` rechazaba localmente
|
|
127
|
+
* TODA consulta posterior — el MCP quedaba inutilizable durante horas sin
|
|
128
|
+
* siquiera intentar llegar a la API. Medido en auditoría: tras un 429, la
|
|
129
|
+
* API volvió a responder con normalidad 13 minutos después. La propia guía
|
|
130
|
+
* oficial describe la cuota como un *token bucket* que "se recarga
|
|
131
|
+
* automáticamente" (glosario) y manda esperar el header `Retry-After`
|
|
132
|
+
* (§7), aunque su §4 diga que el límite es por día calendario.
|
|
133
|
+
*
|
|
134
|
+
* Ahora se espera lo que indique `Retry-After`; si no viene, se aplica una
|
|
135
|
+
* espera creciente (15 → 30 → 60 min, tope 2 h) que se reinicia con la
|
|
136
|
+
* primera consulta exitosa.
|
|
137
|
+
*
|
|
138
|
+
* @param retryAfterSeconds Valor del header `Retry-After`, si la API lo envió.
|
|
61
139
|
*/
|
|
62
|
-
markLimited() {
|
|
140
|
+
markLimited(retryAfterSeconds) {
|
|
63
141
|
this.isLimited = true;
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
this.limitResetTime =
|
|
69
|
-
|
|
142
|
+
this.consecutive429++;
|
|
143
|
+
const esperaSegundos = retryAfterSeconds && retryAfterSeconds > 0
|
|
144
|
+
? retryAfterSeconds
|
|
145
|
+
: this.esperaPorDefecto();
|
|
146
|
+
this.limitResetTime = new Date(Date.now() + esperaSegundos * 1000);
|
|
147
|
+
const origen = retryAfterSeconds && retryAfterSeconds > 0 ? 'header Retry-After' : 'espera progresiva local';
|
|
148
|
+
logger.warn(`Rate limiter: 429 recibido (#${this.consecutive429} consecutivo). ` +
|
|
149
|
+
`Reintentable a partir de ${this.limitResetTime.toISOString()} (${origen}).`);
|
|
150
|
+
this.guardarEstado();
|
|
151
|
+
}
|
|
152
|
+
/** Espera creciente ante 429 sucesivos, para no martillar la API. */
|
|
153
|
+
esperaPorDefecto() {
|
|
154
|
+
const escala = [15, 30, 60, 120]; // minutos
|
|
155
|
+
const i = Math.min(this.consecutive429 - 1, escala.length - 1);
|
|
156
|
+
return escala[Math.max(0, i)] * 60;
|
|
70
157
|
}
|
|
71
158
|
/**
|
|
72
159
|
* Verifica si estamos actualmente limitados.
|
|
@@ -81,16 +168,17 @@ export class RateLimiter {
|
|
|
81
168
|
this.limitResetTime = null;
|
|
82
169
|
this.requestCount = 0;
|
|
83
170
|
this.currentDay = this.getTodayUTC();
|
|
171
|
+
this.guardarEstado();
|
|
84
172
|
return { limited: false };
|
|
85
173
|
}
|
|
86
174
|
const waitMs = this.limitResetTime
|
|
87
175
|
? this.limitResetTime.getTime() - now.getTime()
|
|
88
176
|
: 0;
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
};
|
|
177
|
+
const waitMin = Math.max(1, Math.ceil(waitMs / 60_000));
|
|
178
|
+
const resetIn = waitMin >= 60
|
|
179
|
+
? `aproximadamente ${Math.ceil(waitMin / 60)} hora(s)`
|
|
180
|
+
: `aproximadamente ${waitMin} minuto(s)`;
|
|
181
|
+
return { limited: true, resetIn };
|
|
94
182
|
}
|
|
95
183
|
/**
|
|
96
184
|
* Obtiene estadísticas del uso actual.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,OAAO,WAAW;IACd,YAAY,GAAG,CAAC,CAAC;IACjB,UAAU,CAAS;IACnB,SAAS,GAAG,KAAK,CAAC;IAClB,cAAc,GAAgB,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"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"}
|