@gotza02/sequential-thinking 10000.1.0 → 10000.1.2

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.
@@ -1,10 +1,16 @@
1
1
  /**
2
2
  * ALERT MANAGER
3
- * Real-time alert system with rule engine and notifications
3
+ * Real-time alert system with rule engine
4
4
  */
5
5
  import { EventEmitter } from 'events';
6
- import { logger } from '../../../utils.js';
7
6
  import { ALERT_CONFIG } from './constants.js';
7
+ // Simple logger fallback
8
+ const logger = {
9
+ info: (...args) => console.error('[INFO]', ...args),
10
+ warn: (...args) => console.warn('[WARN]', ...args),
11
+ error: (...args) => console.error('[ERROR]', ...args),
12
+ debug: (...args) => { }
13
+ };
8
14
  export class AlertManager extends EventEmitter {
9
15
  rules = new Map();
10
16
  checkInterval;
@@ -14,9 +20,6 @@ export class AlertManager extends EventEmitter {
14
20
  super();
15
21
  this.setMaxListeners(100);
16
22
  }
17
- /**
18
- * Start the alert manager
19
- */
20
23
  start() {
21
24
  if (this.checkInterval)
22
25
  return;
@@ -25,9 +28,6 @@ export class AlertManager extends EventEmitter {
25
28
  }, ALERT_CONFIG.CHECK_INTERVAL);
26
29
  logger.info('[AlertManager] Started');
27
30
  }
28
- /**
29
- * Stop the alert manager
30
- */
31
31
  stop() {
32
32
  if (this.checkInterval) {
33
33
  clearInterval(this.checkInterval);
@@ -35,9 +35,6 @@ export class AlertManager extends EventEmitter {
35
35
  }
36
36
  logger.info('[AlertManager] Stopped');
37
37
  }
38
- /**
39
- * Add a new alert rule
40
- */
41
38
  addRule(rule) {
42
39
  const newRule = {
43
40
  ...rule,
@@ -50,9 +47,6 @@ export class AlertManager extends EventEmitter {
50
47
  this.emit('rule_added', newRule);
51
48
  return newRule;
52
49
  }
53
- /**
54
- * Remove an alert rule
55
- */
56
50
  removeRule(ruleId) {
57
51
  const removed = this.rules.delete(ruleId);
58
52
  if (removed) {
@@ -61,21 +55,12 @@ export class AlertManager extends EventEmitter {
61
55
  }
62
56
  return removed;
63
57
  }
64
- /**
65
- * Get all rules
66
- */
67
58
  getRules() {
68
59
  return Array.from(this.rules.values());
69
60
  }
70
- /**
71
- * Get a specific rule
72
- */
73
61
  getRule(ruleId) {
74
62
  return this.rules.get(ruleId);
75
63
  }
76
- /**
77
- * Enable/disable a rule
78
- */
79
64
  toggleRule(ruleId, enabled) {
80
65
  const rule = this.rules.get(ruleId);
81
66
  if (rule) {
@@ -85,29 +70,19 @@ export class AlertManager extends EventEmitter {
85
70
  }
86
71
  return false;
87
72
  }
88
- /**
89
- * Process a live event and check for alerts
90
- */
91
73
  processEvent(event) {
92
74
  for (const rule of this.rules.values()) {
93
75
  if (!rule.enabled)
94
76
  continue;
95
- // Check cooldown
96
- if (rule.lastTriggered && Date.now() - rule.lastTriggered < rule.cooldown) {
77
+ if (rule.lastTriggered && Date.now() - rule.lastTriggered < rule.cooldown)
97
78
  continue;
98
- }
99
- // Check rate limit
100
- if (rule.triggerCount && rule.triggerCount >= ALERT_CONFIG.MAX_ALERTS_PER_HOUR) {
79
+ if (rule.triggerCount && rule.triggerCount >= ALERT_CONFIG.MAX_ALERTS_PER_HOUR)
101
80
  continue;
102
- }
103
81
  if (this.evaluateCondition(rule.condition, event)) {
104
82
  this.triggerAlert(rule, event);
105
83
  }
106
84
  }
107
85
  }
108
- /**
109
- * Evaluate an alert condition against an event
110
- */
111
86
  evaluateCondition(condition, event) {
112
87
  switch (condition.type) {
113
88
  case 'odds_drop':
@@ -127,13 +102,10 @@ export class AlertManager extends EventEmitter {
127
102
  return false;
128
103
  const oddsEvent = event;
129
104
  const { newOdds, change } = oddsEvent.data;
130
- // Check match filter
131
105
  if (condition.matchId && event.matchId !== condition.matchId)
132
106
  return false;
133
- // Check threshold
134
107
  if (newOdds > condition.threshold)
135
108
  return false;
136
- // Check percentage drop
137
109
  return Math.abs(change) >= condition.percentage;
138
110
  }
139
111
  evaluateOddsValue(condition, event) {
@@ -141,21 +113,15 @@ export class AlertManager extends EventEmitter {
141
113
  return false;
142
114
  const oddsEvent = event;
143
115
  const { newOdds } = oddsEvent.data;
144
- // Check match filter
145
116
  if (condition.matchId && event.matchId !== condition.matchId)
146
117
  return false;
147
- // Check max odds
148
118
  if (condition.maxOdds && newOdds > condition.maxOdds)
149
119
  return false;
150
- // Calculate value (would need probability data)
151
- // For now, simplified check
152
120
  return true;
153
121
  }
154
122
  evaluateEventCondition(condition, event) {
155
- // Check match filter
156
123
  if (condition.matchId && event.matchId !== condition.matchId)
157
124
  return false;
158
- // Check event type
159
125
  return condition.eventTypes.includes(event.type);
160
126
  }
161
127
  evaluateCompositeCondition(condition, event) {
@@ -164,19 +130,14 @@ export class AlertManager extends EventEmitter {
164
130
  ? results.every(r => r)
165
131
  : results.some(r => r);
166
132
  }
167
- /**
168
- * Trigger an alert
169
- */
170
133
  async triggerAlert(rule, event) {
171
134
  rule.lastTriggered = Date.now();
172
135
  rule.triggerCount = (rule.triggerCount || 0) + 1;
173
136
  const message = this.createAlertMessage(rule, event);
174
- // Store in history
175
137
  this.alertHistory.push(message);
176
138
  if (this.alertHistory.length > this.maxHistorySize) {
177
139
  this.alertHistory.shift();
178
140
  }
179
- // Send notifications
180
141
  for (const channel of rule.channels) {
181
142
  try {
182
143
  await this.sendNotification(channel, message);
@@ -185,13 +146,9 @@ export class AlertManager extends EventEmitter {
185
146
  logger.error(`[AlertManager] Failed to send notification: ${error}`);
186
147
  }
187
148
  }
188
- // Emit event
189
149
  this.emit('alert', message);
190
150
  logger.info(`[AlertManager] Alert triggered: ${rule.name} (${rule.id})`);
191
151
  }
192
- /**
193
- * Create an alert message
194
- */
195
152
  createAlertMessage(rule, event) {
196
153
  const severity = this.determineSeverity(rule.type, event);
197
154
  return {
@@ -201,10 +158,7 @@ export class AlertManager extends EventEmitter {
201
158
  severity,
202
159
  title: this.formatAlertTitle(rule, event),
203
160
  body: this.formatAlertBody(rule, event),
204
- data: {
205
- event,
206
- rule,
207
- },
161
+ data: { event, rule },
208
162
  timestamp: Date.now(),
209
163
  };
210
164
  }
@@ -223,15 +177,15 @@ export class AlertManager extends EventEmitter {
223
177
  formatAlertTitle(rule, event) {
224
178
  switch (rule.type) {
225
179
  case 'odds_drop':
226
- return `🚨 Odds Drop Alert: ${event.matchId}`;
180
+ return `Odds Drop Alert: ${event.matchId}`;
227
181
  case 'odds_value':
228
- return `💰 Value Bet Alert: ${event.matchId}`;
182
+ return `Value Bet Alert: ${event.matchId}`;
229
183
  case 'goal':
230
- return `⚽ GOAL! ${event.matchId}`;
184
+ return `GOAL! ${event.matchId}`;
231
185
  case 'red_card':
232
- return `🔴 RED CARD! ${event.matchId}`;
186
+ return `RED CARD! ${event.matchId}`;
233
187
  default:
234
- return `📢 ${rule.name}`;
188
+ return rule.name;
235
189
  }
236
190
  }
237
191
  formatAlertBody(rule, event) {
@@ -240,9 +194,8 @@ export class AlertManager extends EventEmitter {
240
194
  lines.push(`Type: ${rule.type}`);
241
195
  lines.push(`Match: ${event.matchId}`);
242
196
  lines.push(`Time: ${new Date(event.timestamp).toLocaleString()}`);
243
- if (event.minute) {
197
+ if (event.minute)
244
198
  lines.push(`Minute: ${event.minute}'`);
245
- }
246
199
  if (event.data) {
247
200
  lines.push('');
248
201
  lines.push('Details:');
@@ -250,9 +203,6 @@ export class AlertManager extends EventEmitter {
250
203
  }
251
204
  return lines.join('\n');
252
205
  }
253
- /**
254
- * Send notification to a channel
255
- */
256
206
  async sendNotification(channel, message) {
257
207
  switch (channel.type) {
258
208
  case 'webhook':
@@ -265,52 +215,57 @@ export class AlertManager extends EventEmitter {
265
215
  await this.sendDiscord(channel.config.webhook, message);
266
216
  break;
267
217
  case 'email':
268
- await this.sendEmail(channel.config, message);
218
+ logger.info(`[AlertManager] Would send email to ${channel.config.to}: ${message.title}`);
269
219
  break;
270
220
  case 'console':
271
- console.log(`\n${'='.repeat(50)}`);
272
- console.log(`ALERT: ${message.title}`);
273
- console.log(`${'='.repeat(50)}`);
274
- console.log(message.body);
275
- console.log(`${'='.repeat(50)}\n`);
221
+ console.error(`\n${'='.repeat(50)}`);
222
+ console.error(`ALERT: ${message.title}`);
223
+ console.error(`${'='.repeat(50)}`);
224
+ console.error(message.body);
225
+ console.error(`${'='.repeat(50)}\n`);
276
226
  break;
277
227
  }
278
228
  }
279
229
  async sendWebhook(url, message) {
280
- const response = await fetch(url, {
281
- method: 'POST',
282
- headers: { 'Content-Type': 'application/json' },
283
- body: JSON.stringify(message),
284
- });
285
- if (!response.ok) {
286
- throw new Error(`Webhook failed: ${response.status}`);
230
+ try {
231
+ const response = await fetch(url, {
232
+ method: 'POST',
233
+ headers: { 'Content-Type': 'application/json' },
234
+ body: JSON.stringify(message),
235
+ });
236
+ if (!response.ok)
237
+ throw new Error(`Webhook failed: ${response.status}`);
238
+ }
239
+ catch (error) {
240
+ logger.error('[AlertManager] Webhook failed:', error);
287
241
  }
288
242
  }
289
243
  async sendSlack(webhook, message) {
290
- const emoji = message.severity === 'critical' ? '🚨' :
291
- message.severity === 'warning' ? '⚠️' : 'ℹ️';
244
+ const emoji = message.severity === 'critical' ? '' : message.severity === 'warning' ? '⚠️' : 'ℹ️';
292
245
  const payload = {
293
246
  text: `${emoji} *${message.title}*`,
294
247
  attachments: [{
295
- color: message.severity === 'critical' ? 'danger' :
296
- message.severity === 'warning' ? 'warning' : 'good',
248
+ color: message.severity === 'critical' ? 'danger' : message.severity === 'warning' ? 'warning' : 'good',
297
249
  text: message.body,
298
250
  footer: 'Football Alert System',
299
251
  ts: Math.floor(message.timestamp / 1000),
300
252
  }],
301
253
  };
302
- const response = await fetch(webhook, {
303
- method: 'POST',
304
- headers: { 'Content-Type': 'application/json' },
305
- body: JSON.stringify(payload),
306
- });
307
- if (!response.ok) {
308
- throw new Error(`Slack webhook failed: ${response.status}`);
254
+ try {
255
+ const response = await fetch(webhook, {
256
+ method: 'POST',
257
+ headers: { 'Content-Type': 'application/json' },
258
+ body: JSON.stringify(payload),
259
+ });
260
+ if (!response.ok)
261
+ throw new Error(`Slack webhook failed: ${response.status}`);
262
+ }
263
+ catch (error) {
264
+ logger.error('[AlertManager] Slack webhook failed:', error);
309
265
  }
310
266
  }
311
267
  async sendDiscord(webhook, message) {
312
- const color = message.severity === 'critical' ? 0xff0000 :
313
- message.severity === 'warning' ? 0xffa500 : 0x00ff00;
268
+ const color = message.severity === 'critical' ? 0xff0000 : message.severity === 'warning' ? 0xffa500 : 0x00ff00;
314
269
  const payload = {
315
270
  embeds: [{
316
271
  title: message.title,
@@ -319,42 +274,29 @@ export class AlertManager extends EventEmitter {
319
274
  timestamp: new Date(message.timestamp).toISOString(),
320
275
  }],
321
276
  };
322
- const response = await fetch(webhook, {
323
- method: 'POST',
324
- headers: { 'Content-Type': 'application/json' },
325
- body: JSON.stringify(payload),
326
- });
327
- if (!response.ok) {
328
- throw new Error(`Discord webhook failed: ${response.status}`);
277
+ try {
278
+ const response = await fetch(webhook, {
279
+ method: 'POST',
280
+ headers: { 'Content-Type': 'application/json' },
281
+ body: JSON.stringify(payload),
282
+ });
283
+ if (!response.ok)
284
+ throw new Error(`Discord webhook failed: ${response.status}`);
285
+ }
286
+ catch (error) {
287
+ logger.error('[AlertManager] Discord webhook failed:', error);
329
288
  }
330
289
  }
331
- async sendEmail(config, message) {
332
- // Would integrate with email service like SendGrid, AWS SES, etc.
333
- logger.info(`[AlertManager] Would send email to ${config.to}: ${message.title}`);
334
- }
335
- /**
336
- * Check scheduled alerts (for time-based alerts)
337
- */
338
290
  checkScheduledAlerts() {
339
- // Implement time-based alert checking
340
- // e.g., check for upcoming matches, etc.
291
+ // Time-based alerts
341
292
  }
342
- /**
343
- * Get alert history
344
- */
345
293
  getAlertHistory(limit) {
346
294
  const history = [...this.alertHistory].reverse();
347
295
  return limit ? history.slice(0, limit) : history;
348
296
  }
349
- /**
350
- * Clear alert history
351
- */
352
297
  clearHistory() {
353
298
  this.alertHistory = [];
354
299
  }
355
- /**
356
- * Get statistics
357
- */
358
300
  getStats() {
359
301
  const rules = Array.from(this.rules.values());
360
302
  return {
@@ -364,17 +306,14 @@ export class AlertManager extends EventEmitter {
364
306
  };
365
307
  }
366
308
  }
367
- // Singleton instance
368
309
  let globalAlertManager = null;
369
310
  export function getAlertManager() {
370
- if (!globalAlertManager) {
311
+ if (!globalAlertManager)
371
312
  globalAlertManager = new AlertManager();
372
- }
373
313
  return globalAlertManager;
374
314
  }
375
315
  export function resetAlertManager() {
376
- if (globalAlertManager) {
316
+ if (globalAlertManager)
377
317
  globalAlertManager.stop();
378
- }
379
318
  globalAlertManager = null;
380
319
  }
@@ -1,6 +1,5 @@
1
1
  /**
2
2
  * DATA QUALITY VALIDATOR
3
- * Validates and scores data quality for football matches
4
3
  */
5
4
  import type { Match, Team, MatchOdds } from './types.js';
6
5
  export interface DataQualityReport {
@@ -21,60 +20,17 @@ export interface DataQualityIssue {
21
20
  value?: any;
22
21
  }
23
22
  export declare class DataQualityValidator {
24
- private knownTeams;
25
- private knownLeagues;
26
- constructor();
27
- /**
28
- * Validate match data and return quality report
29
- */
30
23
  validateMatchData(data: Partial<Match>): DataQualityReport;
31
- /**
32
- * Validate team data
33
- */
34
24
  validateTeamData(data: Partial<Team>): DataQualityReport;
35
- /**
36
- * Validate odds data
37
- */
38
25
  validateOddsData(odds: MatchOdds): DataQualityReport;
39
- /**
40
- * Check data completeness
41
- */
42
26
  private checkCompleteness;
43
- /**
44
- * Check data accuracy
45
- */
46
27
  private checkAccuracy;
47
- /**
48
- * Check data freshness
49
- */
50
28
  private checkFreshness;
51
- /**
52
- * Check data consistency
53
- */
54
29
  private checkConsistency;
55
- /**
56
- * Validate team stats
57
- */
58
- private validateTeamStats;
59
- /**
60
- * Generate improvement suggestions
61
- */
62
30
  private generateSuggestions;
63
- /**
64
- * Calculate freshness score from timestamp
65
- */
66
31
  private calculateFreshness;
67
- /**
68
- * Calculate overall score from issues and warnings
69
- */
70
32
  private calculateScore;
71
- /**
72
- * Quick validation - returns true if data passes basic checks
73
- */
74
33
  isValid(data: Partial<Match>): boolean;
75
- /**
76
- * Get quality grade (A-F)
77
- */
78
34
  getGrade(score: number): string;
79
35
  }
80
36
  export declare function getDataQualityValidator(): DataQualityValidator;