@gotza02/sequential-thinking 10000.1.2 → 10000.1.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/README.md +39 -249
- package/dist/dashboard/server.d.ts +2 -45
- package/dist/dashboard/server.js +64 -250
- package/dist/index.js +4 -1
- package/dist/tools/sports/core/cache.d.ts +8 -19
- package/dist/tools/sports/core/cache.js +38 -95
- package/dist/tools/sports/core/constants.d.ts +4 -63
- package/dist/tools/sports/core/constants.js +11 -86
- package/dist/tools/sports/core/types.d.ts +1 -40
- package/package.json +1 -1
- package/dist/tools/sports/core/alert-manager.d.ts +0 -96
- package/dist/tools/sports/core/alert-manager.js +0 -319
- package/dist/tools/sports/core/circuit-breaker.d.ts +0 -40
- package/dist/tools/sports/core/circuit-breaker.js +0 -99
- package/dist/tools/sports/core/data-quality.d.ts +0 -36
- package/dist/tools/sports/core/data-quality.js +0 -243
- package/dist/tools/sports/core/historical-analyzer.d.ts +0 -54
- package/dist/tools/sports/core/historical-analyzer.js +0 -261
- package/dist/tools/sports/core/index.d.ts +0 -13
- package/dist/tools/sports/core/index.js +0 -16
- package/dist/tools/sports/core/ml-prediction.d.ts +0 -76
- package/dist/tools/sports/core/ml-prediction.js +0 -260
- package/dist/tools/sports/core/realtime-manager.d.ts +0 -51
- package/dist/tools/sports/core/realtime-manager.js +0 -222
- package/dist/tools/sports/core/retry.d.ts +0 -29
- package/dist/tools/sports/core/retry.js +0 -77
package/dist/index.js
CHANGED
|
@@ -29,7 +29,10 @@ const server = new McpServer({
|
|
|
29
29
|
});
|
|
30
30
|
const thinkingServer = new SequentialThinkingServer(process.env.THOUGHTS_STORAGE_PATH || 'thoughts_history.json', parseInt(process.env.THOUGHT_DELAY_MS || '0', 10));
|
|
31
31
|
// Start Dashboard
|
|
32
|
-
|
|
32
|
+
const historyPath = process.env.THOUGHTS_STORAGE_PATH || 'thoughts_history.json';
|
|
33
|
+
startDashboard(3001, historyPath).catch(err => {
|
|
34
|
+
console.error("[Dashboard] Failed to start:", err);
|
|
35
|
+
});
|
|
33
36
|
const knowledgeGraph = new ProjectKnowledgeGraph();
|
|
34
37
|
const memoryGraph = new KnowledgeGraphManager(process.env.MEMORY_GRAPH_PATH || 'knowledge_graph.json');
|
|
35
38
|
const notesManager = new NotesManager(process.env.NOTES_STORAGE_PATH || 'project_notes.json');
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* TTL-based caching with
|
|
2
|
+
* SPORTS MODULE CACHE SERVICE
|
|
3
|
+
* TTL-based caching with file persistence for the football intelligence system
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
* CacheService - Thread-safe TTL-based caching with
|
|
6
|
+
* CacheService - Thread-safe TTL-based caching with persistence
|
|
7
7
|
*/
|
|
8
8
|
export declare class CacheService {
|
|
9
9
|
private cache;
|
|
10
10
|
private cachePath;
|
|
11
11
|
private maxAge;
|
|
12
|
-
private staleAge;
|
|
13
12
|
private maxSize;
|
|
14
13
|
private savePending;
|
|
15
14
|
private saveTimer;
|
|
16
|
-
constructor(cachePath?: string, maxAge?: number, maxSize?: number
|
|
15
|
+
constructor(cachePath?: string, maxAge?: number, maxSize?: number);
|
|
17
16
|
/**
|
|
18
17
|
* Generate a cache key from components
|
|
19
18
|
*/
|
|
@@ -25,16 +24,7 @@ export declare class CacheService {
|
|
|
25
24
|
/**
|
|
26
25
|
* Set a value in cache
|
|
27
26
|
*/
|
|
28
|
-
set<T>(key: string, data: T, ttl?: number
|
|
29
|
-
/**
|
|
30
|
-
* Get or set with stale-while-revalidate pattern
|
|
31
|
-
* Returns cached value immediately, refreshes in background if stale
|
|
32
|
-
*/
|
|
33
|
-
getOrSetWithStaleRevalidate<T>(key: string, factory: () => T | Promise<T>, ttl?: number, staleTtl?: number): Promise<T>;
|
|
34
|
-
/**
|
|
35
|
-
* Refresh data in background
|
|
36
|
-
*/
|
|
37
|
-
private refreshInBackground;
|
|
27
|
+
set<T>(key: string, data: T, ttl?: number): void;
|
|
38
28
|
/**
|
|
39
29
|
* Check if a key exists and is not expired
|
|
40
30
|
*/
|
|
@@ -59,7 +49,6 @@ export declare class CacheService {
|
|
|
59
49
|
hits: number;
|
|
60
50
|
age: number;
|
|
61
51
|
ttl: number;
|
|
62
|
-
isStale: boolean;
|
|
63
52
|
}>;
|
|
64
53
|
};
|
|
65
54
|
/**
|
|
@@ -67,7 +56,7 @@ export declare class CacheService {
|
|
|
67
56
|
*/
|
|
68
57
|
cleanup(): number;
|
|
69
58
|
/**
|
|
70
|
-
* Evict the oldest entry (LRU
|
|
59
|
+
* Evict the oldest entry (LRU)
|
|
71
60
|
*/
|
|
72
61
|
private evictOldest;
|
|
73
62
|
/**
|
|
@@ -89,7 +78,7 @@ export declare class CacheService {
|
|
|
89
78
|
/**
|
|
90
79
|
* Get or set pattern - returns cached value or computes and caches it
|
|
91
80
|
*/
|
|
92
|
-
getOrSet<T>(key: string, factory: () => T | Promise<T>, ttl?: number
|
|
81
|
+
getOrSet<T>(key: string, factory: () => T | Promise<T>, ttl?: number): Promise<T>;
|
|
93
82
|
/**
|
|
94
83
|
* Get multiple keys at once
|
|
95
84
|
*/
|
|
@@ -97,7 +86,7 @@ export declare class CacheService {
|
|
|
97
86
|
/**
|
|
98
87
|
* Set multiple keys at once
|
|
99
88
|
*/
|
|
100
|
-
setMultiple<T>(entries: Map<string, T>, ttl?: number
|
|
89
|
+
setMultiple<T>(entries: Map<string, T>, ttl?: number): void;
|
|
101
90
|
/**
|
|
102
91
|
* Invalidate cache by pattern
|
|
103
92
|
*/
|
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* TTL-based caching with
|
|
2
|
+
* SPORTS MODULE CACHE SERVICE
|
|
3
|
+
* TTL-based caching with file persistence for the football intelligence system
|
|
4
4
|
*/
|
|
5
5
|
import * as fs from 'fs/promises';
|
|
6
6
|
import * as path from 'path';
|
|
7
7
|
import { CACHE_CONFIG } from './constants.js';
|
|
8
8
|
import { logger, createSafeRegex } from '../../../utils.js';
|
|
9
9
|
/**
|
|
10
|
-
* CacheService - Thread-safe TTL-based caching with
|
|
10
|
+
* CacheService - Thread-safe TTL-based caching with persistence
|
|
11
11
|
*/
|
|
12
12
|
export class CacheService {
|
|
13
13
|
cache = new Map();
|
|
14
14
|
cachePath;
|
|
15
15
|
maxAge;
|
|
16
|
-
staleAge;
|
|
17
16
|
maxSize;
|
|
18
17
|
savePending = false;
|
|
19
18
|
saveTimer = null;
|
|
20
|
-
constructor(cachePath = CACHE_CONFIG.CACHE_PATH, maxAge = CACHE_CONFIG.DEFAULT_TTL, maxSize = CACHE_CONFIG.MAX_SIZE
|
|
19
|
+
constructor(cachePath = CACHE_CONFIG.CACHE_PATH, maxAge = CACHE_CONFIG.DEFAULT_TTL, maxSize = CACHE_CONFIG.MAX_SIZE) {
|
|
21
20
|
this.cachePath = path.resolve(cachePath);
|
|
22
21
|
this.maxAge = maxAge;
|
|
23
|
-
this.staleAge = staleAge || maxAge * 2;
|
|
24
22
|
this.maxSize = maxSize;
|
|
25
23
|
this.loadFromFile();
|
|
26
24
|
}
|
|
@@ -38,12 +36,11 @@ export class CacheService {
|
|
|
38
36
|
if (!entry) {
|
|
39
37
|
return null;
|
|
40
38
|
}
|
|
41
|
-
// Check if expired
|
|
39
|
+
// Check if expired
|
|
42
40
|
const now = Date.now();
|
|
43
|
-
|
|
44
|
-
if (now - entry.timestamp > totalTtl) {
|
|
41
|
+
if (now - entry.timestamp > entry.ttl) {
|
|
45
42
|
this.cache.delete(key);
|
|
46
|
-
logger.debug(`Cache expired
|
|
43
|
+
logger.debug(`Cache expired: ${key}`);
|
|
47
44
|
return null;
|
|
48
45
|
}
|
|
49
46
|
// Increment hit counter
|
|
@@ -54,7 +51,7 @@ export class CacheService {
|
|
|
54
51
|
/**
|
|
55
52
|
* Set a value in cache
|
|
56
53
|
*/
|
|
57
|
-
set(key, data, ttl
|
|
54
|
+
set(key, data, ttl) {
|
|
58
55
|
const now = Date.now();
|
|
59
56
|
// Check if we need to evict old entries
|
|
60
57
|
if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
|
|
@@ -65,64 +62,11 @@ export class CacheService {
|
|
|
65
62
|
data,
|
|
66
63
|
timestamp: now,
|
|
67
64
|
ttl: ttl || this.maxAge,
|
|
68
|
-
staleTtl: staleTtl || this.staleAge,
|
|
69
65
|
hits: 0,
|
|
70
66
|
});
|
|
71
|
-
logger.debug(`Cache set: ${key} (TTL: ${ttl || this.maxAge}ms
|
|
67
|
+
logger.debug(`Cache set: ${key} (TTL: ${ttl || this.maxAge}ms)`);
|
|
72
68
|
this.scheduleSave();
|
|
73
69
|
}
|
|
74
|
-
/**
|
|
75
|
-
* Get or set with stale-while-revalidate pattern
|
|
76
|
-
* Returns cached value immediately, refreshes in background if stale
|
|
77
|
-
*/
|
|
78
|
-
async getOrSetWithStaleRevalidate(key, factory, ttl, staleTtl) {
|
|
79
|
-
const entry = this.cache.get(key);
|
|
80
|
-
const now = Date.now();
|
|
81
|
-
const effectiveTtl = ttl || this.maxAge;
|
|
82
|
-
const effectiveStaleTtl = staleTtl || this.staleAge;
|
|
83
|
-
if (entry) {
|
|
84
|
-
const age = now - entry.timestamp;
|
|
85
|
-
// Data is fresh - use it
|
|
86
|
-
if (age < effectiveTtl) {
|
|
87
|
-
entry.hits++;
|
|
88
|
-
return entry.data;
|
|
89
|
-
}
|
|
90
|
-
// Data is stale but within stale TTL - use it and refresh in background
|
|
91
|
-
if (age < effectiveTtl + effectiveStaleTtl) {
|
|
92
|
-
entry.hits++;
|
|
93
|
-
if (!entry.isRefreshing) {
|
|
94
|
-
this.refreshInBackground(key, factory, effectiveTtl, effectiveStaleTtl);
|
|
95
|
-
}
|
|
96
|
-
return entry.data;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
// No data or expired beyond stale TTL - fetch new data
|
|
100
|
-
const value = await factory();
|
|
101
|
-
this.set(key, value, effectiveTtl, effectiveStaleTtl);
|
|
102
|
-
return value;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Refresh data in background
|
|
106
|
-
*/
|
|
107
|
-
async refreshInBackground(key, factory, ttl, staleTtl) {
|
|
108
|
-
const entry = this.cache.get(key);
|
|
109
|
-
if (entry) {
|
|
110
|
-
entry.isRefreshing = true;
|
|
111
|
-
}
|
|
112
|
-
try {
|
|
113
|
-
const value = await factory();
|
|
114
|
-
this.set(key, value, ttl, staleTtl);
|
|
115
|
-
logger.debug(`Background refresh successful: ${key}`);
|
|
116
|
-
}
|
|
117
|
-
catch (error) {
|
|
118
|
-
logger.error(`Background refresh failed for ${key}: ${error}`);
|
|
119
|
-
}
|
|
120
|
-
finally {
|
|
121
|
-
if (entry) {
|
|
122
|
-
entry.isRefreshing = false;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
70
|
/**
|
|
127
71
|
* Check if a key exists and is not expired
|
|
128
72
|
*/
|
|
@@ -131,8 +75,7 @@ export class CacheService {
|
|
|
131
75
|
if (!entry)
|
|
132
76
|
return false;
|
|
133
77
|
const now = Date.now();
|
|
134
|
-
|
|
135
|
-
if (now - entry.timestamp > totalTtl) {
|
|
78
|
+
if (now - entry.timestamp > entry.ttl) {
|
|
136
79
|
this.cache.delete(key);
|
|
137
80
|
return false;
|
|
138
81
|
}
|
|
@@ -157,16 +100,12 @@ export class CacheService {
|
|
|
157
100
|
*/
|
|
158
101
|
getStats() {
|
|
159
102
|
const now = Date.now();
|
|
160
|
-
const entries = Array.from(this.cache.values()).map(entry => {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
ttl: entry.ttl,
|
|
167
|
-
isStale: age > entry.ttl,
|
|
168
|
-
};
|
|
169
|
-
});
|
|
103
|
+
const entries = Array.from(this.cache.values()).map(entry => ({
|
|
104
|
+
key: entry.key,
|
|
105
|
+
hits: entry.hits,
|
|
106
|
+
age: now - entry.timestamp,
|
|
107
|
+
ttl: entry.ttl,
|
|
108
|
+
}));
|
|
170
109
|
return {
|
|
171
110
|
size: this.cache.size,
|
|
172
111
|
maxSize: this.maxSize,
|
|
@@ -181,8 +120,7 @@ export class CacheService {
|
|
|
181
120
|
const now = Date.now();
|
|
182
121
|
let removed = 0;
|
|
183
122
|
for (const [key, entry] of this.cache.entries()) {
|
|
184
|
-
|
|
185
|
-
if (now - entry.timestamp > totalTtl) {
|
|
123
|
+
if (now - entry.timestamp > entry.ttl) {
|
|
186
124
|
this.cache.delete(key);
|
|
187
125
|
removed++;
|
|
188
126
|
}
|
|
@@ -194,22 +132,20 @@ export class CacheService {
|
|
|
194
132
|
return removed;
|
|
195
133
|
}
|
|
196
134
|
/**
|
|
197
|
-
* Evict the oldest entry (LRU
|
|
135
|
+
* Evict the oldest entry (LRU)
|
|
198
136
|
*/
|
|
199
137
|
evictOldest() {
|
|
200
138
|
let oldestKey = null;
|
|
201
|
-
let
|
|
202
|
-
// Evict based on age weighted by hits
|
|
139
|
+
let oldestTime = Infinity;
|
|
203
140
|
for (const [key, entry] of this.cache.entries()) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
lowestScore = score;
|
|
141
|
+
if (entry.timestamp < oldestTime) {
|
|
142
|
+
oldestTime = entry.timestamp;
|
|
207
143
|
oldestKey = key;
|
|
208
144
|
}
|
|
209
145
|
}
|
|
210
146
|
if (oldestKey) {
|
|
211
147
|
this.cache.delete(oldestKey);
|
|
212
|
-
logger.debug(`Evicted
|
|
148
|
+
logger.debug(`Evicted oldest cache entry: ${oldestKey}`);
|
|
213
149
|
}
|
|
214
150
|
}
|
|
215
151
|
/**
|
|
@@ -222,7 +158,7 @@ export class CacheService {
|
|
|
222
158
|
this.saveTimer = setTimeout(() => {
|
|
223
159
|
this.saveToFile();
|
|
224
160
|
this.saveTimer = null;
|
|
225
|
-
}, 1000);
|
|
161
|
+
}, 1000); // Save after 1 second of inactivity
|
|
226
162
|
}
|
|
227
163
|
/**
|
|
228
164
|
* Save cache to file
|
|
@@ -256,8 +192,7 @@ export class CacheService {
|
|
|
256
192
|
const now = Date.now();
|
|
257
193
|
let restored = 0;
|
|
258
194
|
for (const [key, entry] of entries) {
|
|
259
|
-
|
|
260
|
-
if (now - entry.timestamp < totalTtl) {
|
|
195
|
+
if (now - entry.timestamp < entry.ttl) {
|
|
261
196
|
this.cache.set(key, entry);
|
|
262
197
|
restored++;
|
|
263
198
|
}
|
|
@@ -265,6 +200,7 @@ export class CacheService {
|
|
|
265
200
|
logger.info(`Cache loaded: ${restored}/${entries.length} entries restored`);
|
|
266
201
|
}
|
|
267
202
|
catch (error) {
|
|
203
|
+
// File doesn't exist or is invalid - start fresh
|
|
268
204
|
logger.debug('No existing cache file found, starting fresh');
|
|
269
205
|
}
|
|
270
206
|
}
|
|
@@ -281,8 +217,14 @@ export class CacheService {
|
|
|
281
217
|
/**
|
|
282
218
|
* Get or set pattern - returns cached value or computes and caches it
|
|
283
219
|
*/
|
|
284
|
-
async getOrSet(key, factory, ttl
|
|
285
|
-
|
|
220
|
+
async getOrSet(key, factory, ttl) {
|
|
221
|
+
const cached = this.get(key);
|
|
222
|
+
if (cached !== null) {
|
|
223
|
+
return cached;
|
|
224
|
+
}
|
|
225
|
+
const value = await factory();
|
|
226
|
+
this.set(key, value, ttl);
|
|
227
|
+
return value;
|
|
286
228
|
}
|
|
287
229
|
/**
|
|
288
230
|
* Get multiple keys at once
|
|
@@ -300,15 +242,16 @@ export class CacheService {
|
|
|
300
242
|
/**
|
|
301
243
|
* Set multiple keys at once
|
|
302
244
|
*/
|
|
303
|
-
setMultiple(entries, ttl
|
|
245
|
+
setMultiple(entries, ttl) {
|
|
304
246
|
for (const [key, value] of entries.entries()) {
|
|
305
|
-
this.set(key, value, ttl
|
|
247
|
+
this.set(key, value, ttl);
|
|
306
248
|
}
|
|
307
249
|
}
|
|
308
250
|
/**
|
|
309
251
|
* Invalidate cache by pattern
|
|
310
252
|
*/
|
|
311
253
|
invalidatePattern(pattern) {
|
|
254
|
+
// Use safe regex creation to prevent ReDoS attacks
|
|
312
255
|
const regex = createSafeRegex(pattern);
|
|
313
256
|
let removed = 0;
|
|
314
257
|
for (const key of this.cache.keys()) {
|
|
@@ -345,10 +288,10 @@ let globalCache = null;
|
|
|
345
288
|
export function getGlobalCache() {
|
|
346
289
|
if (!globalCache) {
|
|
347
290
|
globalCache = new CacheService();
|
|
348
|
-
// Cleanup expired entries every
|
|
291
|
+
// Cleanup expired entries every 5 minutes
|
|
349
292
|
setInterval(() => {
|
|
350
293
|
globalCache?.cleanup();
|
|
351
|
-
},
|
|
294
|
+
}, 5 * 60 * 1000);
|
|
352
295
|
}
|
|
353
296
|
return globalCache;
|
|
354
297
|
}
|
|
@@ -10,40 +10,25 @@ export declare const API_CONFIG: {
|
|
|
10
10
|
readonly FOOTBALL_DATA_BASE: "https://api.football-data.org/v4";
|
|
11
11
|
readonly SPORTS_DB_KEY: string;
|
|
12
12
|
readonly SPORTS_DB_BASE: "https://www.thesportsdb.com/api/v1/json";
|
|
13
|
-
readonly ODDS_API_KEY: string;
|
|
14
|
-
readonly ODDS_API_BASE: "https://api.the-odds-api.com/v4";
|
|
15
|
-
readonly SPORTRADAR_KEY: string;
|
|
16
|
-
readonly SPORTRADAR_BASE: "https://api.sportradar.us/soccer/trial/v4";
|
|
17
13
|
readonly RATE_LIMITS: {
|
|
18
14
|
readonly API_FOOTBALL: 10;
|
|
19
15
|
readonly FOOTBALL_DATA: 10;
|
|
20
16
|
readonly SPORTS_DB: 30;
|
|
21
|
-
readonly ODDS_API: 20;
|
|
22
|
-
readonly SPORTRADAR: 100;
|
|
23
17
|
};
|
|
24
18
|
};
|
|
25
19
|
export declare const CACHE_CONFIG: {
|
|
26
20
|
readonly DEFAULT_TTL: number;
|
|
27
21
|
readonly TTL: {
|
|
28
22
|
readonly LIVE_SCORES: number;
|
|
29
|
-
readonly LIVE_EVENTS: number;
|
|
30
|
-
readonly ODDS: number;
|
|
31
23
|
readonly MATCH_DETAILS: number;
|
|
32
24
|
readonly STANDINGS: number;
|
|
33
25
|
readonly TEAM_STATS: number;
|
|
34
26
|
readonly PLAYER_STATS: number;
|
|
27
|
+
readonly ODDS: number;
|
|
35
28
|
readonly TRANSFER_NEWS: number;
|
|
36
|
-
readonly PREDICTIONS: number;
|
|
37
|
-
};
|
|
38
|
-
readonly STALE_MULTIPLIERS: {
|
|
39
|
-
readonly LIVE_SCORES: 2;
|
|
40
|
-
readonly ODDS: 2;
|
|
41
|
-
readonly MATCH_DETAILS: 2;
|
|
42
|
-
readonly STANDINGS: 1.5;
|
|
43
|
-
readonly TEAM_STATS: 1.5;
|
|
44
29
|
};
|
|
45
30
|
readonly CACHE_PATH: string;
|
|
46
|
-
readonly MAX_SIZE:
|
|
31
|
+
readonly MAX_SIZE: 1000;
|
|
47
32
|
};
|
|
48
33
|
export declare const SCRAPER_CONFIG: {
|
|
49
34
|
readonly PRIORITY_DOMAINS: readonly ["understat.com", "bbc.co.uk/sport", "sportsmole.co.uk", "skysports.com", "goal.com", "thesquareball.net", "fbref.com", "whoscored.com", "sofascore.com", "flashscore.com"];
|
|
@@ -187,53 +172,9 @@ export declare const ERRORS: {
|
|
|
187
172
|
readonly TIMEOUT: "Request timed out.";
|
|
188
173
|
readonly INVALID_RESPONSE: "Invalid response from API.";
|
|
189
174
|
readonly ALL_PROVIDERS_FAILED: "All data providers failed.";
|
|
190
|
-
readonly CIRCUIT_BREAKER_OPEN: "Service temporarily unavailable due to repeated failures.";
|
|
191
|
-
};
|
|
192
|
-
export declare const ALERT_CONFIG: {
|
|
193
|
-
readonly CHECK_INTERVAL: 10000;
|
|
194
|
-
readonly DEFAULT_COOLDOWN: 300000;
|
|
195
|
-
readonly MAX_ALERTS_PER_HOUR: 10;
|
|
196
|
-
readonly TYPES: {
|
|
197
|
-
readonly ODDS_DROP: "odds_drop";
|
|
198
|
-
readonly ODDS_VALUE: "odds_value";
|
|
199
|
-
readonly GOAL: "goal";
|
|
200
|
-
readonly RED_CARD: "red_card";
|
|
201
|
-
readonly LINEUP_CHANGE: "lineup_change";
|
|
202
|
-
readonly MATCH_START: "match_start";
|
|
203
|
-
readonly MATCH_END: "match_end";
|
|
204
|
-
readonly CUSTOM: "custom";
|
|
205
|
-
};
|
|
206
|
-
};
|
|
207
|
-
export declare const REALTIME_CONFIG: {
|
|
208
|
-
readonly WS_RECONNECT_INTERVAL: 5000;
|
|
209
|
-
readonly WS_MAX_RECONNECT_ATTEMPTS: 10;
|
|
210
|
-
readonly POLLING_INTERVALS: {
|
|
211
|
-
readonly LIVE_SCORES: 15000;
|
|
212
|
-
readonly ODDS: 30000;
|
|
213
|
-
readonly MATCH_EVENTS: 5000;
|
|
214
|
-
};
|
|
215
|
-
readonly EVENT_BATCH_SIZE: 10;
|
|
216
|
-
readonly EVENT_BATCH_TIMEOUT: 1000;
|
|
217
|
-
};
|
|
218
|
-
export declare const ML_CONFIG: {
|
|
219
|
-
readonly MIN_TRAINING_MATCHES: 50;
|
|
220
|
-
readonly FEATURE_WEIGHTS: {
|
|
221
|
-
readonly form: 0.25;
|
|
222
|
-
readonly h2h: 0.2;
|
|
223
|
-
readonly home_advantage: 0.15;
|
|
224
|
-
readonly xg: 0.15;
|
|
225
|
-
readonly injuries: 0.1;
|
|
226
|
-
readonly fatigue: 0.1;
|
|
227
|
-
readonly weather: 0.05;
|
|
228
|
-
};
|
|
229
|
-
readonly CONFIDENCE_THRESHOLDS: {
|
|
230
|
-
readonly high: 0.7;
|
|
231
|
-
readonly medium: 0.55;
|
|
232
|
-
readonly low: 0.4;
|
|
233
|
-
};
|
|
234
175
|
};
|
|
235
176
|
export declare const MODULE_INFO: {
|
|
236
177
|
readonly NAME: "sports-module";
|
|
237
|
-
readonly VERSION: "
|
|
238
|
-
readonly DESCRIPTION: "Football Intelligence System for MCP Server
|
|
178
|
+
readonly VERSION: "2.0.0";
|
|
179
|
+
readonly DESCRIPTION: "Football Intelligence System for MCP Server";
|
|
239
180
|
};
|
|
@@ -14,49 +14,31 @@ export const API_CONFIG = {
|
|
|
14
14
|
// TheSportsDB
|
|
15
15
|
SPORTS_DB_KEY: process.env.SPORTS_DB_KEY || '',
|
|
16
16
|
SPORTS_DB_BASE: 'https://www.thesportsdb.com/api/v1/json',
|
|
17
|
-
// Odds API
|
|
18
|
-
ODDS_API_KEY: process.env.ODDS_API_KEY || '',
|
|
19
|
-
ODDS_API_BASE: 'https://api.the-odds-api.com/v4',
|
|
20
|
-
// SportRadar (requires enterprise license)
|
|
21
|
-
SPORTRADAR_KEY: process.env.SPORTRADAR_KEY || '',
|
|
22
|
-
SPORTRADAR_BASE: 'https://api.sportradar.us/soccer/trial/v4',
|
|
23
17
|
// Rate limits (requests per minute)
|
|
24
18
|
RATE_LIMITS: {
|
|
25
19
|
API_FOOTBALL: 10,
|
|
26
20
|
FOOTBALL_DATA: 10,
|
|
27
21
|
SPORTS_DB: 30,
|
|
28
|
-
ODDS_API: 20,
|
|
29
|
-
SPORTRADAR: 100,
|
|
30
22
|
}
|
|
31
23
|
};
|
|
32
24
|
// ============= Cache Configuration =============
|
|
33
25
|
export const CACHE_CONFIG = {
|
|
34
26
|
// Default TTL in milliseconds
|
|
35
27
|
DEFAULT_TTL: parseInt(process.env.SPORTS_CACHE_TTL || '300000'), // 5 minutes
|
|
36
|
-
// Specific TTLs for different data types
|
|
28
|
+
// Specific TTLs for different data types
|
|
37
29
|
TTL: {
|
|
38
|
-
LIVE_SCORES:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
TRANSFER_NEWS: 10 * 60 * 1000, // 10 minutes (was 15 minutes)
|
|
46
|
-
PREDICTIONS: 60 * 60 * 1000, // 1 hour
|
|
47
|
-
},
|
|
48
|
-
// Stale-while-revalidate multipliers
|
|
49
|
-
STALE_MULTIPLIERS: {
|
|
50
|
-
LIVE_SCORES: 2, // Stale for 30 seconds (15s * 2)
|
|
51
|
-
ODDS: 2, // Stale for 1 minute (30s * 2)
|
|
52
|
-
MATCH_DETAILS: 2, // Stale for 4 minutes
|
|
53
|
-
STANDINGS: 1.5, // Stale for 22.5 minutes
|
|
54
|
-
TEAM_STATS: 1.5, // Stale for 45 minutes
|
|
30
|
+
LIVE_SCORES: 60 * 1000, // 1 minute
|
|
31
|
+
MATCH_DETAILS: 5 * 60 * 1000, // 5 minutes
|
|
32
|
+
STANDINGS: 30 * 60 * 1000, // 30 minutes
|
|
33
|
+
TEAM_STATS: 60 * 60 * 1000, // 1 hour
|
|
34
|
+
PLAYER_STATS: 60 * 60 * 1000, // 1 hour
|
|
35
|
+
ODDS: 2 * 60 * 1000, // 2 minutes
|
|
36
|
+
TRANSFER_NEWS: 15 * 60 * 1000, // 15 minutes
|
|
55
37
|
},
|
|
56
38
|
// Cache file path
|
|
57
39
|
CACHE_PATH: process.env.SPORTS_CACHE_PATH || '.sports_cache.json',
|
|
58
40
|
// Max cache size (number of entries)
|
|
59
|
-
MAX_SIZE:
|
|
41
|
+
MAX_SIZE: 1000,
|
|
60
42
|
};
|
|
61
43
|
// ============= Scraping Configuration =============
|
|
62
44
|
export const SCRAPER_CONFIG = {
|
|
@@ -170,67 +152,10 @@ export const ERRORS = {
|
|
|
170
152
|
TIMEOUT: 'Request timed out.',
|
|
171
153
|
INVALID_RESPONSE: 'Invalid response from API.',
|
|
172
154
|
ALL_PROVIDERS_FAILED: 'All data providers failed.',
|
|
173
|
-
CIRCUIT_BREAKER_OPEN: 'Service temporarily unavailable due to repeated failures.',
|
|
174
|
-
};
|
|
175
|
-
// ============= Alert Configuration =============
|
|
176
|
-
export const ALERT_CONFIG = {
|
|
177
|
-
// Check interval for alerts (milliseconds)
|
|
178
|
-
CHECK_INTERVAL: 10000, // 10 seconds
|
|
179
|
-
// Default cooldown between same alert (milliseconds)
|
|
180
|
-
DEFAULT_COOLDOWN: 300000, // 5 minutes
|
|
181
|
-
// Max alerts per hour per rule
|
|
182
|
-
MAX_ALERTS_PER_HOUR: 10,
|
|
183
|
-
// Alert types
|
|
184
|
-
TYPES: {
|
|
185
|
-
ODDS_DROP: 'odds_drop',
|
|
186
|
-
ODDS_VALUE: 'odds_value',
|
|
187
|
-
GOAL: 'goal',
|
|
188
|
-
RED_CARD: 'red_card',
|
|
189
|
-
LINEUP_CHANGE: 'lineup_change',
|
|
190
|
-
MATCH_START: 'match_start',
|
|
191
|
-
MATCH_END: 'match_end',
|
|
192
|
-
CUSTOM: 'custom',
|
|
193
|
-
},
|
|
194
|
-
};
|
|
195
|
-
// ============= Realtime Configuration =============
|
|
196
|
-
export const REALTIME_CONFIG = {
|
|
197
|
-
// WebSocket reconnection
|
|
198
|
-
WS_RECONNECT_INTERVAL: 5000,
|
|
199
|
-
WS_MAX_RECONNECT_ATTEMPTS: 10,
|
|
200
|
-
// Polling intervals (fallback when WebSocket unavailable)
|
|
201
|
-
POLLING_INTERVALS: {
|
|
202
|
-
LIVE_SCORES: 15000, // 15 seconds
|
|
203
|
-
ODDS: 30000, // 30 seconds
|
|
204
|
-
MATCH_EVENTS: 5000, // 5 seconds
|
|
205
|
-
},
|
|
206
|
-
// Event batching
|
|
207
|
-
EVENT_BATCH_SIZE: 10,
|
|
208
|
-
EVENT_BATCH_TIMEOUT: 1000,
|
|
209
|
-
};
|
|
210
|
-
// ============= ML Prediction Configuration =============
|
|
211
|
-
export const ML_CONFIG = {
|
|
212
|
-
// Minimum matches for training
|
|
213
|
-
MIN_TRAINING_MATCHES: 50,
|
|
214
|
-
// Feature weights
|
|
215
|
-
FEATURE_WEIGHTS: {
|
|
216
|
-
form: 0.25,
|
|
217
|
-
h2h: 0.20,
|
|
218
|
-
home_advantage: 0.15,
|
|
219
|
-
xg: 0.15,
|
|
220
|
-
injuries: 0.10,
|
|
221
|
-
fatigue: 0.10,
|
|
222
|
-
weather: 0.05,
|
|
223
|
-
},
|
|
224
|
-
// Confidence thresholds
|
|
225
|
-
CONFIDENCE_THRESHOLDS: {
|
|
226
|
-
high: 0.70,
|
|
227
|
-
medium: 0.55,
|
|
228
|
-
low: 0.40,
|
|
229
|
-
},
|
|
230
155
|
};
|
|
231
156
|
// ============= Version Info =============
|
|
232
157
|
export const MODULE_INFO = {
|
|
233
158
|
NAME: 'sports-module',
|
|
234
|
-
VERSION: '
|
|
235
|
-
DESCRIPTION: 'Football Intelligence System for MCP Server
|
|
159
|
+
VERSION: '2.0.0',
|
|
160
|
+
DESCRIPTION: 'Football Intelligence System for MCP Server',
|
|
236
161
|
};
|
|
@@ -7,7 +7,7 @@ export type MatchStatus = 'scheduled' | 'live' | 'finished' | 'postponed' | 'can
|
|
|
7
7
|
export type BetType = 'home' | 'draw' | 'away' | 'over' | 'under' | 'btts' | 'handicap';
|
|
8
8
|
export type KellyVariant = 'full' | 'half' | 'quarter';
|
|
9
9
|
export type QueryType = 'general' | 'h2h' | 'form' | 'news' | 'stats' | 'odds' | 'referee' | 'weather' | 'fatigue' | 'setpieces';
|
|
10
|
-
export type ProviderType = 'api-football' | 'football-data' | 'sports-db' | '
|
|
10
|
+
export type ProviderType = 'api-football' | 'football-data' | 'sports-db' | 'scraper';
|
|
11
11
|
export interface SearchQuery {
|
|
12
12
|
type: QueryType;
|
|
13
13
|
query: string;
|
|
@@ -175,8 +175,6 @@ export interface Match {
|
|
|
175
175
|
homeSubstitutes?: Player[];
|
|
176
176
|
awaySubstitutes?: Player[];
|
|
177
177
|
events?: MatchEvent[];
|
|
178
|
-
dataQuality?: number;
|
|
179
|
-
lastUpdated?: Date;
|
|
180
178
|
}
|
|
181
179
|
export interface MatchOdds {
|
|
182
180
|
homeWin: number;
|
|
@@ -346,7 +344,6 @@ export interface APIResponse<T = any> {
|
|
|
346
344
|
provider?: ProviderType;
|
|
347
345
|
cached?: boolean;
|
|
348
346
|
rateLimited?: boolean;
|
|
349
|
-
quality?: number;
|
|
350
347
|
}
|
|
351
348
|
export interface ProviderStatus {
|
|
352
349
|
name: ProviderType;
|
|
@@ -355,7 +352,6 @@ export interface ProviderStatus {
|
|
|
355
352
|
quotaLimit: number;
|
|
356
353
|
rateLimitUntil?: Date;
|
|
357
354
|
lastCall?: Date;
|
|
358
|
-
circuitBreakerState?: 'closed' | 'open' | 'half-open';
|
|
359
355
|
}
|
|
360
356
|
export interface ComparisonResult {
|
|
361
357
|
teamA: Team;
|
|
@@ -381,38 +377,3 @@ export interface LiveScoreUpdate {
|
|
|
381
377
|
events: MatchEvent[];
|
|
382
378
|
timestamp: Date;
|
|
383
379
|
}
|
|
384
|
-
export interface MLPrediction {
|
|
385
|
-
matchId: string;
|
|
386
|
-
homeWinProbability: number;
|
|
387
|
-
drawProbability: number;
|
|
388
|
-
awayWinProbability: number;
|
|
389
|
-
over25Probability?: number;
|
|
390
|
-
bttsProbability?: number;
|
|
391
|
-
confidence: number;
|
|
392
|
-
factors: PredictionFactor[];
|
|
393
|
-
timestamp: Date;
|
|
394
|
-
}
|
|
395
|
-
export interface PredictionFactor {
|
|
396
|
-
name: string;
|
|
397
|
-
weight: number;
|
|
398
|
-
impact: 'positive' | 'negative' | 'neutral';
|
|
399
|
-
description: string;
|
|
400
|
-
}
|
|
401
|
-
export interface HistoricalPattern {
|
|
402
|
-
pattern: string;
|
|
403
|
-
occurrence: number;
|
|
404
|
-
successRate: number;
|
|
405
|
-
avgOdds: number;
|
|
406
|
-
profit: number;
|
|
407
|
-
}
|
|
408
|
-
export interface TeamHistoricalPerformance {
|
|
409
|
-
team: Team;
|
|
410
|
-
totalMatches: number;
|
|
411
|
-
wins: number;
|
|
412
|
-
draws: number;
|
|
413
|
-
losses: number;
|
|
414
|
-
avgGoalsFor: number;
|
|
415
|
-
avgGoalsAgainst: number;
|
|
416
|
-
homeAdvantage: number;
|
|
417
|
-
patterns: HistoricalPattern[];
|
|
418
|
-
}
|