easyoref 1.13.0 → 1.13.1

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.
Files changed (77) hide show
  1. package/dist/agent/auth.d.ts +11 -0
  2. package/dist/agent/auth.d.ts.map +1 -0
  3. package/dist/agent/auth.js +54 -0
  4. package/dist/agent/auth.js.map +1 -0
  5. package/dist/agent/clarify.d.ts +43 -0
  6. package/dist/agent/clarify.d.ts.map +1 -0
  7. package/dist/agent/clarify.js +263 -0
  8. package/dist/agent/clarify.js.map +1 -0
  9. package/dist/agent/dry-run.d.ts +12 -0
  10. package/dist/agent/dry-run.d.ts.map +1 -0
  11. package/dist/agent/dry-run.js +229 -0
  12. package/dist/agent/dry-run.js.map +1 -0
  13. package/dist/agent/gramjs-monitor.d.ts +26 -0
  14. package/dist/agent/gramjs-monitor.d.ts.map +1 -0
  15. package/dist/agent/gramjs-monitor.js +320 -0
  16. package/dist/agent/gramjs-monitor.js.map +1 -0
  17. package/dist/agent/graph.d.ts +50 -0
  18. package/dist/agent/graph.d.ts.map +1 -0
  19. package/dist/agent/graph.js +803 -0
  20. package/dist/agent/graph.js.map +1 -0
  21. package/dist/agent/queue.d.ts +15 -0
  22. package/dist/agent/queue.d.ts.map +1 -0
  23. package/dist/agent/queue.js +41 -0
  24. package/dist/agent/queue.js.map +1 -0
  25. package/dist/agent/redis.d.ts +8 -0
  26. package/dist/agent/redis.d.ts.map +1 -0
  27. package/dist/agent/redis.js +33 -0
  28. package/dist/agent/redis.js.map +1 -0
  29. package/dist/agent/store.d.ts +67 -0
  30. package/dist/agent/store.d.ts.map +1 -0
  31. package/dist/agent/store.js +83 -0
  32. package/dist/agent/store.js.map +1 -0
  33. package/dist/agent/tools.d.ts +159 -0
  34. package/dist/agent/tools.d.ts.map +1 -0
  35. package/dist/agent/tools.js +439 -0
  36. package/dist/agent/tools.js.map +1 -0
  37. package/dist/agent/types.d.ts +102 -0
  38. package/dist/agent/types.d.ts.map +1 -0
  39. package/dist/agent/types.js +3 -0
  40. package/dist/agent/types.js.map +1 -0
  41. package/dist/agent/worker.d.ts +14 -0
  42. package/dist/agent/worker.d.ts.map +1 -0
  43. package/dist/agent/worker.js +90 -0
  44. package/dist/agent/worker.js.map +1 -0
  45. package/dist/bin.d.ts +17 -0
  46. package/dist/bin.d.ts.map +1 -0
  47. package/dist/bin.js +82 -0
  48. package/dist/bin.js.map +1 -0
  49. package/dist/bot.d.ts +16 -0
  50. package/dist/bot.d.ts.map +1 -0
  51. package/dist/bot.js +600 -0
  52. package/dist/bot.js.map +1 -0
  53. package/dist/config.d.ts +125 -0
  54. package/dist/config.d.ts.map +1 -0
  55. package/dist/config.js +145 -0
  56. package/dist/config.js.map +1 -0
  57. package/dist/gif-state.d.ts +17 -0
  58. package/dist/gif-state.d.ts.map +1 -0
  59. package/dist/gif-state.js +67 -0
  60. package/dist/gif-state.js.map +1 -0
  61. package/dist/i18n.d.ts +49 -0
  62. package/dist/i18n.d.ts.map +1 -0
  63. package/dist/i18n.js +229 -0
  64. package/dist/i18n.js.map +1 -0
  65. package/dist/init.d.ts +7 -0
  66. package/dist/init.d.ts.map +1 -0
  67. package/dist/init.js +163 -0
  68. package/dist/init.js.map +1 -0
  69. package/dist/logger.d.ts +14 -0
  70. package/dist/logger.d.ts.map +1 -0
  71. package/dist/logger.js +45 -0
  72. package/dist/logger.js.map +1 -0
  73. package/dist/service.d.ts +19 -0
  74. package/dist/service.d.ts.map +1 -0
  75. package/dist/service.js +165 -0
  76. package/dist/service.js.map +1 -0
  77. package/package.json +1 -1
package/dist/bot.js ADDED
@@ -0,0 +1,600 @@
1
+ /**
2
+ * EasyOref — Real-time Israeli Red Alert Filter Bot
3
+ *
4
+ * Architecture:
5
+ * oref.org.il API → local filter (area map) → Telegram (grammY)
6
+ *
7
+ * Flow:
8
+ * 1. Poll oref.org.il every 2 seconds for active alerts
9
+ * 2. Match areas against configured regions (Hebrew names)
10
+ * 3. Classify alert type: early warning / siren / incident over
11
+ * 4. If relevant → send calm message to family Telegram chat
12
+ *
13
+ * No LLM needed — purely deterministic matching for <1s latency.
14
+ */
15
+ import { Bot } from "grammy";
16
+ import { createServer } from "node:http";
17
+ import { startMonitor, stopMonitor } from "./agent/gramjs-monitor.js";
18
+ import { enqueueEnrich } from "./agent/queue.js";
19
+ import { closeRedis } from "./agent/redis.js";
20
+ import { clearSession, getActiveSession, PHASE_ENRICH_DELAY_MS, saveAlertMeta, setActiveSession, } from "./agent/store.js";
21
+ import { startEnrichWorker, stopEnrichWorker } from "./agent/worker.js";
22
+ import { config } from "./config.js";
23
+ import { initGifState, pickGif } from "./gif-state.js";
24
+ import { getLanguagePack, initTranslations, resolveCityIds, translateAreas, } from "./i18n.js";
25
+ import * as logger from "./logger.js";
26
+ const langPack = getLanguagePack(config.language);
27
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
28
+ // Area Filter (configurable via AREAS env var)
29
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
30
+ /** Check if alert data contains any of our monitored areas. */
31
+ function isRelevantArea(alertAreas) {
32
+ for (const monitored of config.areas) {
33
+ if (alertAreas.includes(monitored))
34
+ return true;
35
+ if (alertAreas.some((a) => a.startsWith(monitored) || monitored.startsWith(a)))
36
+ return true;
37
+ }
38
+ return false;
39
+ }
40
+ /** Return human-readable area label for messages */
41
+ function matchedAreaLabel(alertAreas) {
42
+ const matched = alertAreas.filter((a) => config.areas.some((m) => a.startsWith(m) || m.startsWith(a) || a === m));
43
+ return matched.length > 0
44
+ ? matched.join(", ")
45
+ : alertAreas.slice(0, 3).join(", ");
46
+ }
47
+ /** Map internal AlertType → YAML config key */
48
+ const ALERT_TYPE_TO_CONFIG = {
49
+ early_warning: "early",
50
+ siren: "siren",
51
+ resolved: "resolved",
52
+ };
53
+ function classifyAlertType(title) {
54
+ if (title.includes("האירוע הסתיים"))
55
+ return "resolved";
56
+ if (title.includes("בדקות הקרובות") || title.includes("צפויות להתקבל"))
57
+ return "early_warning";
58
+ return "siren";
59
+ }
60
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
61
+ // Cooldown / Dedup
62
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
63
+ const COOLDOWN_EARLY_MS = 2 * 60 * 1000; // 2 min (Oref sends multiple IDs per wave)
64
+ const COOLDOWN_SIREN_MS = 90 * 1000; // 1.5 min (no prior early warning)
65
+ const COOLDOWN_SIREN_AFTER_EARLY_MS = 3 * 60 * 1000; // 3 min (early warning already sent)
66
+ const COOLDOWN_RESOLVED_MS = 5 * 60 * 1000; // 5 min
67
+ const lastSent = {
68
+ early_warning: 0,
69
+ siren: 0,
70
+ resolved: 0,
71
+ };
72
+ function shouldSend(type) {
73
+ const elapsed = Date.now() - lastSent[type];
74
+ switch (type) {
75
+ case "early_warning":
76
+ return elapsed >= COOLDOWN_EARLY_MS;
77
+ case "resolved":
78
+ return elapsed >= COOLDOWN_RESOLVED_MS;
79
+ case "siren": {
80
+ // If early warning was already sent this cycle → longer cooldown (user already informed)
81
+ const sirenCd = lastSent.early_warning > 0
82
+ ? COOLDOWN_SIREN_AFTER_EARLY_MS
83
+ : COOLDOWN_SIREN_MS;
84
+ return elapsed >= sirenCd;
85
+ }
86
+ }
87
+ }
88
+ function markSent(type) {
89
+ const now = Date.now();
90
+ lastSent[type] = now;
91
+ // After resolved → reset ALL others (new attack cycle)
92
+ if (type === "resolved") {
93
+ lastSent.early_warning = 0;
94
+ lastSent.siren = 0;
95
+ }
96
+ // After siren → allow new early_warning (next wave) and resolved
97
+ if (type === "siren") {
98
+ lastSent.early_warning = 0;
99
+ lastSent.resolved = 0;
100
+ }
101
+ // After early_warning → allow resolved
102
+ if (type === "early_warning")
103
+ lastSent.resolved = 0;
104
+ }
105
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
106
+ // Oref Poller
107
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
108
+ const seenAlerts = new Set();
109
+ async function fetchAlerts() {
110
+ const t0 = Date.now();
111
+ try {
112
+ const res = await fetch(config.orefApiUrl, {
113
+ headers: {
114
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
115
+ "X-Requested-With": "XMLHttpRequest",
116
+ Referer: "https://www.oref.org.il/",
117
+ Accept: "application/json, text/plain, */*",
118
+ },
119
+ });
120
+ const ms = Date.now() - t0;
121
+ if (!res.ok) {
122
+ logger.warn("Oref API error", { status: res.status, ms });
123
+ return [];
124
+ }
125
+ const text = await res.text();
126
+ if (!text.trim()) {
127
+ logger.debug("Oref poll — quiet", { status: res.status, ms, raw: text });
128
+ return [];
129
+ }
130
+ const parsed = JSON.parse(text);
131
+ if (Array.isArray(parsed)) {
132
+ logger.info("Oref poll — alerts received", {
133
+ count: parsed.length,
134
+ ms,
135
+ raw: text.slice(0, 2000),
136
+ });
137
+ return parsed;
138
+ }
139
+ if (parsed && typeof parsed === "object" && "id" in parsed) {
140
+ logger.info("Oref poll — single alert", {
141
+ ms,
142
+ raw: text.slice(0, 2000),
143
+ });
144
+ return [parsed];
145
+ }
146
+ logger.warn("Oref unexpected response", { raw: text.slice(0, 500), ms });
147
+ return [];
148
+ }
149
+ catch (err) {
150
+ logger.warn("Oref fetch failed", {
151
+ error: String(err),
152
+ ms: Date.now() - t0,
153
+ });
154
+ return [];
155
+ }
156
+ }
157
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
158
+ // GIF Pools by Mode
159
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
160
+ // ── funny_cats ────────────────────────────────────────
161
+ const CATS_EARLY_WARNING = [
162
+ "https://media.giphy.com/media/wQI5H4jtqZEPK/giphy.gif",
163
+ "https://media.giphy.com/media/pD83kYQkhuhgY/giphy.gif",
164
+ "https://media.giphy.com/media/W2FXGIVejFptc6CSxY/giphy.gif",
165
+ "https://media1.tenor.com/m/iM6XLBMUKNcAAAAd/cat-kitty.mp4",
166
+ "https://media1.tenor.com/m/fZ-SvpmkgSUAAAAd/uni-unico.mp4",
167
+ "https://media1.tenor.com/m/1KwzId7qyyQAAAAd/bye-goodbye.gif",
168
+ "https://media1.tenor.com/m/jXHAct5B8uwAAAAd/cat-hiding-in-the-box-cat.gif",
169
+ "https://media1.tenor.com/m/GjeodmMXY2AAAAAd/cat-shy.gif",
170
+ "https://media1.tenor.com/m/yz_7VcX0WjYAAAAd/cat-changing-the-clock-changing-the-time.gif",
171
+ ];
172
+ const CATS_EARLY_WARNING_NIGHT = [
173
+ "https://media.giphy.com/media/5UH2PJ8VIEuMqN8V6R/giphy.gif",
174
+ "https://media.tenor.com/4gH8RagrsjAAAAPo/wake-up-viralhog.mp4",
175
+ "https://media1.tenor.com/m/4NJKe0rdz9AAAAAd/cat-kitty.mp4",
176
+ "https://media1.tenor.com/m/nsbw7SM-rYMAAAAd/wake-up-cat-tapping.gif",
177
+ "https://media1.tenor.com/m/S5N8d-OpyNEAAAAC/extasyxx.gif",
178
+ "https://media1.tenor.com/m/-1dJGIwOFo8AAAAC/wake-up-hooman-husky.gif",
179
+ ];
180
+ const CATS_SIREN = [
181
+ "https://media1.tenor.com/m/9vcHsGLyJmgAAAAd/cat-alarm-alarm.mp4",
182
+ "https://media.tenor.com/Wx3bGh80AWkAAAPo/siren-cat.mp4",
183
+ "https://media.giphy.com/media/WLGJGG9JjpUrmUWkYf/giphy.gif",
184
+ "https://media1.tenor.com/m/0XHXUdzJ9KIAAAAd/cat-meme.mp4",
185
+ "https://media1.tenor.com/m/J3sih0hnKLwAAAAC/borzoi-siren.mp4",
186
+ "https://media1.tenor.com/m/JhrBK6zYao0AAAAC/cat-orange.gif",
187
+ ];
188
+ const CATS_RESOLVED = [
189
+ "https://media.tenor.com/eRGgvoRJNqAAAAPo/cat-silly.mp4",
190
+ "https://media.tenor.com/aePEdx5RyFcAAAPo/cat-petsure.mp4",
191
+ "https://media.tenor.com/wP_lARteJosAAAPo/cat-box.mp4",
192
+ "https://media1.tenor.com/m/Td6hJ6AayEgAAAAd/cats-leave.mp4",
193
+ "https://media1.tenor.com/m/eaLwOMoptpcAAAAd/rexi-im-out.mp4",
194
+ "https://media1.tenor.com/m/MkyiUsAp8t8AAAAd/tom-and-jerry-tom-the-cat.gif",
195
+ "https://media1.tenor.com/m/imeu4GvhB2sAAAAC/cat-kitten.gif",
196
+ "https://media1.tenor.com/m/swIMdJZK8F0AAAAd/kitten-relaxing-paws.gif",
197
+ ];
198
+ const GIF_POOLS = {
199
+ funny_cats: {
200
+ early: CATS_EARLY_WARNING,
201
+ earlyNight: [...CATS_EARLY_WARNING, ...CATS_EARLY_WARNING_NIGHT],
202
+ siren: CATS_SIREN,
203
+ resolved: CATS_RESOLVED,
204
+ },
205
+ };
206
+ /** Is it nighttime in Israel? (03:00–10:59) */
207
+ function isNightInIsrael() {
208
+ const h = Number(new Date().toLocaleTimeString("en-US", {
209
+ hour: "numeric",
210
+ hour12: false,
211
+ timeZone: "Asia/Jerusalem",
212
+ }));
213
+ return h >= 3 && h < 11;
214
+ }
215
+ function getGifUrl(alertType) {
216
+ const mode = config.gifMode;
217
+ if (mode === "none")
218
+ return null;
219
+ const pools = GIF_POOLS[mode];
220
+ if (!pools)
221
+ return null;
222
+ switch (alertType) {
223
+ case "early_warning": {
224
+ const pool = isNightInIsrael() ? pools.earlyNight : pools.early;
225
+ return pickGif(pool, isNightInIsrael() ? `${mode}_early_night` : `${mode}_early`);
226
+ }
227
+ case "siren":
228
+ return pickGif(pools.siren, `${mode}_siren`);
229
+ case "resolved":
230
+ return pickGif(pools.resolved, `${mode}_resolved`);
231
+ }
232
+ }
233
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
234
+ // Telegram
235
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
236
+ let bot = null;
237
+ function initBot() {
238
+ if (!config.botToken) {
239
+ logger.error("BOT_TOKEN not set — Telegram DISABLED");
240
+ return null;
241
+ }
242
+ if (!config.chatId) {
243
+ logger.error("CHAT_ID not set — Telegram DISABLED");
244
+ return null;
245
+ }
246
+ logger.info("Bot initialized", {
247
+ chat_id: config.chatId.slice(0, -4) + "****",
248
+ language: config.language,
249
+ areas: config.areas,
250
+ gif_mode: config.gifMode,
251
+ });
252
+ return new Bot(config.botToken);
253
+ }
254
+ function nowHHMM() {
255
+ return new Date().toLocaleTimeString("he-IL", {
256
+ hour: "2-digit",
257
+ minute: "2-digit",
258
+ timeZone: "Asia/Jerusalem",
259
+ });
260
+ }
261
+ function formatMessage(alertType, areas) {
262
+ const time = nowHHMM();
263
+ const localAreas = translateAreas(areas, config.language);
264
+ const cfgKey = ALERT_TYPE_TO_CONFIG[alertType];
265
+ const defaults = langPack.alerts[cfgKey];
266
+ const labels = langPack.labels;
267
+ const emoji = config.emojiOverride[cfgKey] ?? defaults.emoji;
268
+ const title = config.titleOverride[cfgKey] ?? defaults.title;
269
+ const desc = config.descriptionOverride[cfgKey] ?? defaults.description;
270
+ const lines = [`<b>${emoji} ${title}</b>`];
271
+ if (desc)
272
+ lines.push(desc);
273
+ lines.push("");
274
+ lines.push(`<b>${labels.area}:</b> ${localAreas}`);
275
+ if (alertType === "early_warning") {
276
+ lines.push(`<b>${labels.timeToImpact}:</b> ${labels.earlyEta}`);
277
+ lines.push(`<b>${labels.time}:</b> ${time}`);
278
+ }
279
+ else if (alertType === "siren") {
280
+ lines.push(`<b>${labels.timeToImpact}:</b> ${labels.sirenEta}`);
281
+ lines.push(`<b>${labels.time}:</b> ${time}`);
282
+ }
283
+ else if (alertType === "resolved") {
284
+ lines.push(`<b>${labels.time}:</b> ${time}`);
285
+ }
286
+ return lines.join("\n");
287
+ }
288
+ /** Send message and return {messageId, isCaption} for agent editing */
289
+ async function sendTelegram(alertType, text) {
290
+ if (!bot || !config.chatId) {
291
+ logger.error("Telegram unavailable", {
292
+ bot_exists: !!bot,
293
+ chat_id: config.chatId,
294
+ });
295
+ return null;
296
+ }
297
+ const gifUrl = getGifUrl(alertType);
298
+ // No GIF mode → send text only
299
+ if (!gifUrl) {
300
+ try {
301
+ const msg = await bot.api.sendMessage(config.chatId, text, {
302
+ parse_mode: "HTML",
303
+ });
304
+ logger.info("Alert sent via Telegram (text)", { type: alertType });
305
+ return { messageId: msg.message_id, isCaption: false };
306
+ }
307
+ catch (err) {
308
+ logger.error("Telegram send failed", {
309
+ error: String(err),
310
+ type: alertType,
311
+ });
312
+ return null;
313
+ }
314
+ }
315
+ // GIF mode → try animation, fall back to text
316
+ try {
317
+ const msg = await bot.api.sendAnimation(config.chatId, gifUrl, {
318
+ caption: text,
319
+ parse_mode: "HTML",
320
+ });
321
+ logger.info("Alert sent via Telegram (GIF)", {
322
+ type: alertType,
323
+ gif_url: gifUrl,
324
+ });
325
+ return { messageId: msg.message_id, isCaption: true };
326
+ }
327
+ catch (err) {
328
+ logger.warn("GIF send failed, falling back to text", {
329
+ error: String(err),
330
+ gif_url: gifUrl,
331
+ });
332
+ try {
333
+ const msg = await bot.api.sendMessage(config.chatId, text, {
334
+ parse_mode: "HTML",
335
+ });
336
+ logger.info("Alert sent via Telegram (text fallback)", {
337
+ type: alertType,
338
+ });
339
+ return { messageId: msg.message_id, isCaption: false };
340
+ }
341
+ catch (err2) {
342
+ logger.error("Telegram send failed completely", {
343
+ error: String(err2),
344
+ type: alertType,
345
+ });
346
+ return null;
347
+ }
348
+ }
349
+ }
350
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
351
+ // Alert Processing
352
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
353
+ async function processAlert(alert) {
354
+ if (!isRelevantArea(alert.data)) {
355
+ logger.info("Alert — not in our area", {
356
+ alert_id: alert.id,
357
+ areas_he: alert.data,
358
+ });
359
+ return;
360
+ }
361
+ const alertType = classifyAlertType(alert.title);
362
+ // Filter by configured alert types
363
+ const cfgKey = ALERT_TYPE_TO_CONFIG[alertType];
364
+ if (!config.alertTypes.includes(cfgKey)) {
365
+ logger.info("Alert type filtered out by config", {
366
+ alert_id: alert.id,
367
+ type: alertType,
368
+ config_key: cfgKey,
369
+ });
370
+ return;
371
+ }
372
+ const areas = matchedAreaLabel(alert.data);
373
+ logger.info("Alert — RELEVANT", {
374
+ alert_id: alert.id,
375
+ type: alertType,
376
+ areas_he: alert.data,
377
+ });
378
+ if (!shouldSend(alertType)) {
379
+ logger.info("Cooldown active, skipping Telegram", {
380
+ alert_id: alert.id,
381
+ type: alertType,
382
+ });
383
+ return;
384
+ }
385
+ markSent(alertType);
386
+ const message = formatMessage(alertType, areas);
387
+ try {
388
+ const sent = await sendTelegram(alertType, message);
389
+ // ── Session-based enrichment lifecycle ──
390
+ if (sent && config.agent.enabled && config.chatId) {
391
+ const alertTs = Date.now();
392
+ const existingSession = await getActiveSession();
393
+ // Save meta for this alert (always)
394
+ await saveAlertMeta({
395
+ alertId: alert.id,
396
+ messageId: sent.messageId,
397
+ chatId: config.chatId,
398
+ isCaption: sent.isCaption,
399
+ alertTs,
400
+ alertType,
401
+ alertAreas: alert.data,
402
+ currentText: message,
403
+ });
404
+ if (alertType === "resolved") {
405
+ // ── Resolved: switch existing session to resolved phase ──
406
+ if (existingSession) {
407
+ const updated = {
408
+ ...existingSession,
409
+ phase: "resolved",
410
+ phaseStartTs: Date.now(),
411
+ latestAlertId: alert.id,
412
+ latestMessageId: sent.messageId,
413
+ latestAlertTs: alertTs,
414
+ isCaption: sent.isCaption,
415
+ currentText: message,
416
+ };
417
+ await setActiveSession(updated);
418
+ const delay = PHASE_ENRICH_DELAY_MS.resolved;
419
+ await enqueueEnrich(alert.id, alertTs, delay);
420
+ logger.info("Session: entered resolved phase", {
421
+ sessionId: existingSession.sessionId,
422
+ alertId: alert.id,
423
+ });
424
+ }
425
+ else {
426
+ logger.info("Resolved alert without active session — no enrichment", {
427
+ alert_id: alert.id,
428
+ });
429
+ }
430
+ }
431
+ else {
432
+ // ── Early warning / Siren ──
433
+ if (existingSession && existingSession.phase !== "resolved") {
434
+ // Upgrade session phase (early → siren, or same-type refresh)
435
+ const updated = {
436
+ ...existingSession,
437
+ phase: alertType,
438
+ phaseStartTs: Date.now(),
439
+ latestAlertId: alert.id,
440
+ latestMessageId: sent.messageId,
441
+ latestAlertTs: alertTs,
442
+ isCaption: sent.isCaption,
443
+ currentText: message,
444
+ alertAreas: alert.data,
445
+ };
446
+ await setActiveSession(updated);
447
+ logger.info("Session: upgraded phase", {
448
+ sessionId: existingSession.sessionId,
449
+ from: existingSession.phase,
450
+ to: alertType,
451
+ alertId: alert.id,
452
+ });
453
+ }
454
+ else {
455
+ // New session (or previous one was in resolved — start fresh)
456
+ if (existingSession) {
457
+ await clearSession();
458
+ }
459
+ const session = {
460
+ sessionId: alert.id,
461
+ sessionStartTs: alertTs,
462
+ phase: alertType,
463
+ phaseStartTs: alertTs,
464
+ latestAlertId: alert.id,
465
+ latestMessageId: sent.messageId,
466
+ latestAlertTs: alertTs,
467
+ chatId: config.chatId,
468
+ isCaption: sent.isCaption,
469
+ currentText: message,
470
+ alertAreas: alert.data,
471
+ };
472
+ await setActiveSession(session);
473
+ logger.info("Session: started", {
474
+ sessionId: alert.id,
475
+ phase: alertType,
476
+ });
477
+ }
478
+ const delay = PHASE_ENRICH_DELAY_MS[alertType];
479
+ await enqueueEnrich(alert.id, alertTs, delay);
480
+ }
481
+ }
482
+ }
483
+ catch (err) {
484
+ logger.error("Alert send/store failed", {
485
+ error: String(err),
486
+ alert_id: alert.id,
487
+ });
488
+ }
489
+ }
490
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
491
+ // Health Server
492
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
493
+ function startHealthServer() {
494
+ const server = createServer((req, res) => {
495
+ if (req.url === "/health") {
496
+ res.writeHead(200, { "Content-Type": "application/json" });
497
+ res.end(JSON.stringify({
498
+ status: "ok",
499
+ service: "easyoref",
500
+ uptime: process.uptime(),
501
+ seen_alerts: seenAlerts.size,
502
+ language: config.language,
503
+ gif_mode: config.gifMode,
504
+ areas: config.areas,
505
+ }));
506
+ }
507
+ else {
508
+ res.writeHead(404);
509
+ res.end("Not Found");
510
+ }
511
+ });
512
+ server.listen(config.healthPort, () => {
513
+ logger.info("Health server started", { port: config.healthPort });
514
+ });
515
+ }
516
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
517
+ // Main
518
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
519
+ async function main() {
520
+ logger.info("EasyOref starting", {
521
+ poll_interval_ms: config.pollIntervalMs,
522
+ telegram: config.botToken ? "enabled" : "disabled",
523
+ language: config.language,
524
+ gif_mode: config.gifMode,
525
+ areas: config.areas,
526
+ });
527
+ await initTranslations();
528
+ // Resolve YAML city_ids → Hebrew area names for Oref API matching
529
+ if (config.cityIds.length > 0) {
530
+ config.areas = resolveCityIds(config.cityIds);
531
+ logger.info("Resolved city IDs to area names", {
532
+ city_ids: config.cityIds,
533
+ areas: config.areas,
534
+ });
535
+ }
536
+ else if (process.env.AREAS) {
537
+ // Legacy fallback: AREAS env var (comma-separated Hebrew names)
538
+ config.areas = process.env.AREAS.split(",")
539
+ .map((s) => s.trim())
540
+ .filter(Boolean);
541
+ logger.info("Using legacy AREAS env var", { areas: config.areas });
542
+ }
543
+ if (config.areas.length === 0) {
544
+ logger.warn("No areas configured — bot will not filter alerts by area");
545
+ }
546
+ initGifState(config.dataDir);
547
+ bot = initBot();
548
+ startHealthServer();
549
+ // Start agent subsystems if enabled
550
+ if (config.agent.enabled) {
551
+ startEnrichWorker();
552
+ await startMonitor();
553
+ logger.info("Agent subsystems started", {
554
+ model: config.agent.model,
555
+ provider: "openrouter.ai",
556
+ channels: 14, // MONITORED_CHANNELS length (hardcoded)
557
+ enrich_delay_ms: config.agent.enrichDelayMs,
558
+ });
559
+ }
560
+ // Poll loop
561
+ setInterval(async () => {
562
+ try {
563
+ const alerts = await fetchAlerts();
564
+ for (const alert of alerts) {
565
+ if (seenAlerts.has(alert.id))
566
+ continue;
567
+ seenAlerts.add(alert.id);
568
+ await processAlert(alert);
569
+ }
570
+ }
571
+ catch (err) {
572
+ logger.error("Poll error", { error: String(err) });
573
+ }
574
+ }, config.pollIntervalMs);
575
+ // Heartbeat — flush Logtail buffer every 30s
576
+ setInterval(async () => {
577
+ logger.debug("heartbeat", {
578
+ uptime_s: Math.round(process.uptime()),
579
+ seen_alerts: seenAlerts.size,
580
+ });
581
+ await logger.flush();
582
+ }, 30_000);
583
+ // Graceful shutdown
584
+ for (const sig of ["SIGINT", "SIGTERM"]) {
585
+ process.on(sig, async () => {
586
+ logger.info(`Shutting down (${sig})`);
587
+ await stopMonitor();
588
+ await stopEnrichWorker();
589
+ await closeRedis();
590
+ await logger.flush();
591
+ process.exit(0);
592
+ });
593
+ }
594
+ }
595
+ main().catch(async (err) => {
596
+ logger.error("Fatal error", { error: String(err) });
597
+ await logger.flush();
598
+ process.exit(1);
599
+ });
600
+ //# sourceMappingURL=bot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot.js","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"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"}