easyoref 1.0.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/LICENSE +21 -0
- package/README.md +127 -0
- package/dist/bin.d.ts +9 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +25 -0
- package/dist/bin.js.map +1 -0
- package/dist/bot.d.ts +16 -0
- package/dist/bot.d.ts.map +1 -0
- package/dist/bot.js +481 -0
- package/dist/bot.js.map +1 -0
- package/dist/config.d.ts +72 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +120 -0
- package/dist/config.js.map +1 -0
- package/dist/gif-state.d.ts +17 -0
- package/dist/gif-state.d.ts.map +1 -0
- package/dist/gif-state.js +67 -0
- package/dist/gif-state.js.map +1 -0
- package/dist/i18n.d.ts +37 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +240 -0
- package/dist/i18n.js.map +1 -0
- package/dist/init.d.ts +7 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +163 -0
- package/dist/init.js.map +1 -0
- package/dist/logger.d.ts +14 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +45 -0
- package/dist/logger.js.map +1 -0
- package/package.json +60 -0
package/dist/bot.js
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
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 { config } from "./config.js";
|
|
18
|
+
import { initGifState, pickGif } from "./gif-state.js";
|
|
19
|
+
import { getTemplates, initTranslations, resolveCityIds, translateAreas, } from "./i18n.js";
|
|
20
|
+
import * as logger from "./logger.js";
|
|
21
|
+
const templates = getTemplates(config.language);
|
|
22
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
23
|
+
// Area Filter (configurable via AREAS env var)
|
|
24
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
25
|
+
/** Check if alert data contains any of our monitored areas. */
|
|
26
|
+
function isRelevantArea(alertAreas) {
|
|
27
|
+
for (const monitored of config.areas) {
|
|
28
|
+
if (alertAreas.includes(monitored))
|
|
29
|
+
return true;
|
|
30
|
+
if (alertAreas.some((a) => a.startsWith(monitored) || monitored.startsWith(a)))
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
/** Return human-readable area label for messages */
|
|
36
|
+
function matchedAreaLabel(alertAreas) {
|
|
37
|
+
const matched = alertAreas.filter((a) => config.areas.some((m) => a.startsWith(m) || m.startsWith(a) || a === m));
|
|
38
|
+
return matched.length > 0
|
|
39
|
+
? matched.join(", ")
|
|
40
|
+
: alertAreas.slice(0, 3).join(", ");
|
|
41
|
+
}
|
|
42
|
+
/** Map internal AlertType → YAML config key */
|
|
43
|
+
const ALERT_TYPE_TO_CONFIG = {
|
|
44
|
+
early_warning: "early",
|
|
45
|
+
siren: "siren",
|
|
46
|
+
resolved: "incident_over",
|
|
47
|
+
};
|
|
48
|
+
function classifyAlertType(title) {
|
|
49
|
+
if (title.includes("האירוע הסתיים"))
|
|
50
|
+
return "resolved";
|
|
51
|
+
if (title.includes("בדקות הקרובות") || title.includes("צפויות להתקבל"))
|
|
52
|
+
return "early_warning";
|
|
53
|
+
return "siren";
|
|
54
|
+
}
|
|
55
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
56
|
+
// Cooldown / Dedup
|
|
57
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
58
|
+
const COOLDOWN_EARLY_MS = 2 * 60 * 1000; // 2 min (Oref sends multiple IDs per wave)
|
|
59
|
+
const COOLDOWN_SIREN_MS = 90 * 1000; // 1.5 min
|
|
60
|
+
const COOLDOWN_RESOLVED_MS = 5 * 60 * 1000; // 5 min
|
|
61
|
+
const lastSent = {
|
|
62
|
+
early_warning: 0,
|
|
63
|
+
siren: 0,
|
|
64
|
+
resolved: 0,
|
|
65
|
+
};
|
|
66
|
+
function shouldSend(type) {
|
|
67
|
+
const elapsed = Date.now() - lastSent[type];
|
|
68
|
+
switch (type) {
|
|
69
|
+
case "early_warning":
|
|
70
|
+
return elapsed >= COOLDOWN_EARLY_MS;
|
|
71
|
+
case "resolved":
|
|
72
|
+
return elapsed >= COOLDOWN_RESOLVED_MS;
|
|
73
|
+
case "siren":
|
|
74
|
+
return elapsed >= COOLDOWN_SIREN_MS;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function markSent(type) {
|
|
78
|
+
const now = Date.now();
|
|
79
|
+
lastSent[type] = now;
|
|
80
|
+
// After resolved → reset ALL others (new attack cycle)
|
|
81
|
+
if (type === "resolved") {
|
|
82
|
+
lastSent.early_warning = 0;
|
|
83
|
+
lastSent.siren = 0;
|
|
84
|
+
}
|
|
85
|
+
// After siren → allow new early_warning (next wave) and resolved
|
|
86
|
+
if (type === "siren") {
|
|
87
|
+
lastSent.early_warning = 0;
|
|
88
|
+
lastSent.resolved = 0;
|
|
89
|
+
}
|
|
90
|
+
// After early_warning → allow resolved
|
|
91
|
+
if (type === "early_warning")
|
|
92
|
+
lastSent.resolved = 0;
|
|
93
|
+
}
|
|
94
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
95
|
+
// Oref Poller
|
|
96
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
97
|
+
const seenAlerts = new Set();
|
|
98
|
+
async function fetchAlerts() {
|
|
99
|
+
const t0 = Date.now();
|
|
100
|
+
try {
|
|
101
|
+
const res = await fetch(config.orefApiUrl, {
|
|
102
|
+
headers: {
|
|
103
|
+
"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",
|
|
104
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
105
|
+
Referer: "https://www.oref.org.il/",
|
|
106
|
+
Accept: "application/json, text/plain, */*",
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
const ms = Date.now() - t0;
|
|
110
|
+
if (!res.ok) {
|
|
111
|
+
logger.warn("Oref API error", { status: res.status, ms });
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
const text = await res.text();
|
|
115
|
+
if (!text.trim()) {
|
|
116
|
+
logger.debug("Oref poll — quiet", { status: res.status, ms, raw: text });
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
const parsed = JSON.parse(text);
|
|
120
|
+
if (Array.isArray(parsed)) {
|
|
121
|
+
logger.info("Oref poll — alerts received", {
|
|
122
|
+
count: parsed.length,
|
|
123
|
+
ms,
|
|
124
|
+
raw: text.slice(0, 2000),
|
|
125
|
+
});
|
|
126
|
+
return parsed;
|
|
127
|
+
}
|
|
128
|
+
if (parsed && typeof parsed === "object" && "id" in parsed) {
|
|
129
|
+
logger.info("Oref poll — single alert", {
|
|
130
|
+
ms,
|
|
131
|
+
raw: text.slice(0, 2000),
|
|
132
|
+
});
|
|
133
|
+
return [parsed];
|
|
134
|
+
}
|
|
135
|
+
logger.warn("Oref unexpected response", { raw: text.slice(0, 500), ms });
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
logger.warn("Oref fetch failed", {
|
|
140
|
+
error: String(err),
|
|
141
|
+
ms: Date.now() - t0,
|
|
142
|
+
});
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
147
|
+
// GIF Pools by Mode
|
|
148
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
149
|
+
// ── funny_cats ────────────────────────────────────────
|
|
150
|
+
const CATS_EARLY_WARNING = [
|
|
151
|
+
"https://media.giphy.com/media/wQI5H4jtqZEPK/giphy.gif",
|
|
152
|
+
"https://media.giphy.com/media/pD83kYQkhuhgY/giphy.gif",
|
|
153
|
+
"https://media.giphy.com/media/W2FXGIVejFptc6CSxY/giphy.gif",
|
|
154
|
+
"https://media1.tenor.com/m/iM6XLBMUKNcAAAAd/cat-kitty.mp4",
|
|
155
|
+
"https://media1.tenor.com/m/fZ-SvpmkgSUAAAAd/uni-unico.mp4",
|
|
156
|
+
];
|
|
157
|
+
const CATS_EARLY_WARNING_NIGHT = [
|
|
158
|
+
"https://media.giphy.com/media/5UH2PJ8VIEuMqN8V6R/giphy.gif",
|
|
159
|
+
"https://media.tenor.com/4gH8RagrsjAAAAPo/wake-up-viralhog.mp4",
|
|
160
|
+
"https://media1.tenor.com/m/4NJKe0rdz9AAAAAd/cat-kitty.mp4",
|
|
161
|
+
];
|
|
162
|
+
const CATS_SIREN = [
|
|
163
|
+
"https://media1.tenor.com/m/9vcHsGLyJmgAAAAd/cat-alarm-alarm.mp4",
|
|
164
|
+
"https://media.tenor.com/Wx3bGh80AWkAAAPo/siren-cat.mp4",
|
|
165
|
+
"https://media.giphy.com/media/WLGJGG9JjpUrmUWkYf/giphy.gif",
|
|
166
|
+
"https://media1.tenor.com/m/0XHXUdzJ9KIAAAAd/cat-meme.mp4",
|
|
167
|
+
"https://media1.tenor.com/m/J3sih0hnKLwAAAAC/borzoi-siren.mp4",
|
|
168
|
+
];
|
|
169
|
+
const CATS_RESOLVED = [
|
|
170
|
+
"https://media.tenor.com/eRGgvoRJNqAAAAPo/cat-silly.mp4",
|
|
171
|
+
"https://media.tenor.com/aePEdx5RyFcAAAPo/cat-petsure.mp4",
|
|
172
|
+
"https://media.tenor.com/wP_lARteJosAAAPo/cat-box.mp4",
|
|
173
|
+
"https://media1.tenor.com/m/Td6hJ6AayEgAAAAd/cats-leave.mp4",
|
|
174
|
+
"https://media1.tenor.com/m/eaLwOMoptpcAAAAd/rexi-im-out.mp4",
|
|
175
|
+
];
|
|
176
|
+
// ── assertive ─────────────────────────────────────────
|
|
177
|
+
const ASSERTIVE_EARLY_WARNING = [
|
|
178
|
+
"https://media.giphy.com/media/3o7TKxOhkp8gO0LXMI/giphy.gif", // radar
|
|
179
|
+
"https://media.giphy.com/media/l0HlQXlQ3nHyLMvte/giphy.gif", // alert screen
|
|
180
|
+
];
|
|
181
|
+
const ASSERTIVE_SIREN = [
|
|
182
|
+
"https://media.giphy.com/media/3o7TKVfu4JSwmSqiMo/giphy.gif", // flashing red
|
|
183
|
+
"https://media.giphy.com/media/l0MYt5jPR6QX5APm0/giphy.gif", // warning sign
|
|
184
|
+
];
|
|
185
|
+
const ASSERTIVE_RESOLVED = [
|
|
186
|
+
"https://media.giphy.com/media/XreQmk7ETCak0/giphy.gif", // thumbs up
|
|
187
|
+
"https://media.giphy.com/media/3oKIPf3C7HGx1NWIJ2/giphy.gif", // all clear
|
|
188
|
+
];
|
|
189
|
+
const GIF_POOLS = {
|
|
190
|
+
funny_cats: {
|
|
191
|
+
early: CATS_EARLY_WARNING,
|
|
192
|
+
earlyNight: [...CATS_EARLY_WARNING, ...CATS_EARLY_WARNING_NIGHT],
|
|
193
|
+
siren: CATS_SIREN,
|
|
194
|
+
resolved: CATS_RESOLVED,
|
|
195
|
+
},
|
|
196
|
+
assertive: {
|
|
197
|
+
early: ASSERTIVE_EARLY_WARNING,
|
|
198
|
+
earlyNight: ASSERTIVE_EARLY_WARNING,
|
|
199
|
+
siren: ASSERTIVE_SIREN,
|
|
200
|
+
resolved: ASSERTIVE_RESOLVED,
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
/** Is it nighttime in Israel? (03:00–10:59) */
|
|
204
|
+
function isNightInIsrael() {
|
|
205
|
+
const h = Number(new Date().toLocaleTimeString("en-US", {
|
|
206
|
+
hour: "numeric",
|
|
207
|
+
hour12: false,
|
|
208
|
+
timeZone: "Asia/Jerusalem",
|
|
209
|
+
}));
|
|
210
|
+
return h >= 3 && h < 11;
|
|
211
|
+
}
|
|
212
|
+
function getGifUrl(alertType) {
|
|
213
|
+
const mode = config.gifMode;
|
|
214
|
+
// pikud_haoref and none → no GIFs
|
|
215
|
+
if (mode === "none" || mode === "pikud_haoref")
|
|
216
|
+
return null;
|
|
217
|
+
const pools = GIF_POOLS[mode];
|
|
218
|
+
if (!pools)
|
|
219
|
+
return null;
|
|
220
|
+
switch (alertType) {
|
|
221
|
+
case "early_warning": {
|
|
222
|
+
const pool = isNightInIsrael() ? pools.earlyNight : pools.early;
|
|
223
|
+
return pickGif(pool, isNightInIsrael() ? `${mode}_early_night` : `${mode}_early`);
|
|
224
|
+
}
|
|
225
|
+
case "siren":
|
|
226
|
+
return pickGif(pools.siren, `${mode}_siren`);
|
|
227
|
+
case "resolved":
|
|
228
|
+
return pickGif(pools.resolved, `${mode}_resolved`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
232
|
+
// Telegram
|
|
233
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
234
|
+
let bot = null;
|
|
235
|
+
function initBot() {
|
|
236
|
+
if (!config.botToken) {
|
|
237
|
+
logger.error("BOT_TOKEN not set — Telegram DISABLED");
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
if (!config.chatId) {
|
|
241
|
+
logger.error("CHAT_ID not set — Telegram DISABLED");
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
logger.info("Bot initialized", {
|
|
245
|
+
chat_id: config.chatId.slice(0, -4) + "****",
|
|
246
|
+
language: config.language,
|
|
247
|
+
areas: config.areas,
|
|
248
|
+
gif_mode: config.gifMode,
|
|
249
|
+
});
|
|
250
|
+
return new Bot(config.botToken);
|
|
251
|
+
}
|
|
252
|
+
function nowHHMM() {
|
|
253
|
+
return new Date().toLocaleTimeString("he-IL", {
|
|
254
|
+
hour: "2-digit",
|
|
255
|
+
minute: "2-digit",
|
|
256
|
+
timeZone: "Asia/Jerusalem",
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
function formatMessage(alertType, areas) {
|
|
260
|
+
const time = nowHHMM();
|
|
261
|
+
const localAreas = translateAreas(areas, config.language);
|
|
262
|
+
const cfgKey = ALERT_TYPE_TO_CONFIG[alertType];
|
|
263
|
+
const titleOvr = config.titleOverride[cfgKey];
|
|
264
|
+
const descOvr = config.descriptionOverride[cfgKey];
|
|
265
|
+
// If user provided both title and description overrides → fully custom message
|
|
266
|
+
if (titleOvr && descOvr) {
|
|
267
|
+
return [
|
|
268
|
+
`<b>${titleOvr}</b>`,
|
|
269
|
+
descOvr,
|
|
270
|
+
"",
|
|
271
|
+
"<blockquote>",
|
|
272
|
+
`<b>${config.language === "he" ? "אזור" : config.language === "ar" ? "المنطقة" : config.language === "en" ? "Area" : "Район"}:</b> ${localAreas}`,
|
|
273
|
+
alertType !== "resolved"
|
|
274
|
+
? `<b>${config.language === "he" ? "שעה" : config.language === "ar" ? "الوقت" : config.language === "en" ? "Time" : "Время"}:</b> ${time}`
|
|
275
|
+
: "",
|
|
276
|
+
"</blockquote>",
|
|
277
|
+
]
|
|
278
|
+
.filter(Boolean)
|
|
279
|
+
.join("\n");
|
|
280
|
+
}
|
|
281
|
+
switch (alertType) {
|
|
282
|
+
case "early_warning":
|
|
283
|
+
return templates.earlyWarning(localAreas, time);
|
|
284
|
+
case "siren":
|
|
285
|
+
return templates.siren(localAreas, time);
|
|
286
|
+
case "resolved":
|
|
287
|
+
return templates.resolved(localAreas);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
async function sendTelegram(alertType, text) {
|
|
291
|
+
if (!bot || !config.chatId) {
|
|
292
|
+
logger.error("Telegram unavailable", {
|
|
293
|
+
bot_exists: !!bot,
|
|
294
|
+
chat_id: config.chatId,
|
|
295
|
+
});
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const gifUrl = getGifUrl(alertType);
|
|
299
|
+
// No GIF mode → send text only
|
|
300
|
+
if (!gifUrl) {
|
|
301
|
+
try {
|
|
302
|
+
await bot.api.sendMessage(config.chatId, text, { parse_mode: "HTML" });
|
|
303
|
+
logger.info("Alert sent via Telegram (text)", { type: alertType });
|
|
304
|
+
}
|
|
305
|
+
catch (err) {
|
|
306
|
+
logger.error("Telegram send failed", {
|
|
307
|
+
error: String(err),
|
|
308
|
+
type: alertType,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
// GIF mode → try animation, fall back to text
|
|
314
|
+
try {
|
|
315
|
+
await bot.api.sendAnimation(config.chatId, gifUrl, {
|
|
316
|
+
caption: text,
|
|
317
|
+
parse_mode: "HTML",
|
|
318
|
+
});
|
|
319
|
+
logger.info("Alert sent via Telegram (GIF)", {
|
|
320
|
+
type: alertType,
|
|
321
|
+
gif_url: gifUrl,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
logger.warn("GIF send failed, falling back to text", {
|
|
326
|
+
error: String(err),
|
|
327
|
+
gif_url: gifUrl,
|
|
328
|
+
});
|
|
329
|
+
try {
|
|
330
|
+
await bot.api.sendMessage(config.chatId, text, { parse_mode: "HTML" });
|
|
331
|
+
logger.info("Alert sent via Telegram (text fallback)", {
|
|
332
|
+
type: alertType,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
catch (err2) {
|
|
336
|
+
logger.error("Telegram send failed completely", {
|
|
337
|
+
error: String(err2),
|
|
338
|
+
type: alertType,
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
344
|
+
// Alert Processing
|
|
345
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
346
|
+
function processAlert(alert) {
|
|
347
|
+
if (!isRelevantArea(alert.data)) {
|
|
348
|
+
logger.info("Alert — not in our area", {
|
|
349
|
+
alert_id: alert.id,
|
|
350
|
+
areas_he: alert.data,
|
|
351
|
+
});
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const alertType = classifyAlertType(alert.title);
|
|
355
|
+
// Filter by configured alert types
|
|
356
|
+
const cfgKey = ALERT_TYPE_TO_CONFIG[alertType];
|
|
357
|
+
if (!config.alertTypes.includes(cfgKey)) {
|
|
358
|
+
logger.info("Alert type filtered out by config", {
|
|
359
|
+
alert_id: alert.id,
|
|
360
|
+
type: alertType,
|
|
361
|
+
config_key: cfgKey,
|
|
362
|
+
});
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const areas = matchedAreaLabel(alert.data);
|
|
366
|
+
logger.info("Alert — RELEVANT", {
|
|
367
|
+
alert_id: alert.id,
|
|
368
|
+
type: alertType,
|
|
369
|
+
areas_he: alert.data,
|
|
370
|
+
});
|
|
371
|
+
if (!shouldSend(alertType)) {
|
|
372
|
+
logger.info("Cooldown active, skipping Telegram", {
|
|
373
|
+
alert_id: alert.id,
|
|
374
|
+
type: alertType,
|
|
375
|
+
});
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
markSent(alertType);
|
|
379
|
+
const message = formatMessage(alertType, areas);
|
|
380
|
+
sendTelegram(alertType, message).catch((err) => logger.error("Telegram send failed", {
|
|
381
|
+
error: String(err),
|
|
382
|
+
alert_id: alert.id,
|
|
383
|
+
}));
|
|
384
|
+
}
|
|
385
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
386
|
+
// Health Server
|
|
387
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
388
|
+
function startHealthServer() {
|
|
389
|
+
const server = createServer((req, res) => {
|
|
390
|
+
if (req.url === "/health") {
|
|
391
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
392
|
+
res.end(JSON.stringify({
|
|
393
|
+
status: "ok",
|
|
394
|
+
service: "easyoref",
|
|
395
|
+
uptime: process.uptime(),
|
|
396
|
+
seen_alerts: seenAlerts.size,
|
|
397
|
+
language: config.language,
|
|
398
|
+
gif_mode: config.gifMode,
|
|
399
|
+
areas: config.areas,
|
|
400
|
+
}));
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
res.writeHead(404);
|
|
404
|
+
res.end("Not Found");
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
server.listen(config.healthPort, () => {
|
|
408
|
+
logger.info("Health server started", { port: config.healthPort });
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
412
|
+
// Main
|
|
413
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
414
|
+
async function main() {
|
|
415
|
+
logger.info("EasyOref starting", {
|
|
416
|
+
poll_interval_ms: config.pollIntervalMs,
|
|
417
|
+
telegram: config.botToken ? "enabled" : "disabled",
|
|
418
|
+
language: config.language,
|
|
419
|
+
gif_mode: config.gifMode,
|
|
420
|
+
areas: config.areas,
|
|
421
|
+
});
|
|
422
|
+
await initTranslations();
|
|
423
|
+
// Resolve YAML city_ids → Hebrew area names for Oref API matching
|
|
424
|
+
if (config.cityIds.length > 0) {
|
|
425
|
+
config.areas = resolveCityIds(config.cityIds);
|
|
426
|
+
logger.info("Resolved city IDs to area names", {
|
|
427
|
+
city_ids: config.cityIds,
|
|
428
|
+
areas: config.areas,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
else if (process.env.AREAS) {
|
|
432
|
+
// Legacy fallback: AREAS env var (comma-separated Hebrew names)
|
|
433
|
+
config.areas = process.env.AREAS.split(",")
|
|
434
|
+
.map((s) => s.trim())
|
|
435
|
+
.filter(Boolean);
|
|
436
|
+
logger.info("Using legacy AREAS env var", { areas: config.areas });
|
|
437
|
+
}
|
|
438
|
+
if (config.areas.length === 0) {
|
|
439
|
+
logger.warn("No areas configured — bot will not filter alerts by area");
|
|
440
|
+
}
|
|
441
|
+
initGifState(config.dataDir);
|
|
442
|
+
bot = initBot();
|
|
443
|
+
startHealthServer();
|
|
444
|
+
// Poll loop
|
|
445
|
+
setInterval(async () => {
|
|
446
|
+
try {
|
|
447
|
+
const alerts = await fetchAlerts();
|
|
448
|
+
for (const alert of alerts) {
|
|
449
|
+
if (seenAlerts.has(alert.id))
|
|
450
|
+
continue;
|
|
451
|
+
seenAlerts.add(alert.id);
|
|
452
|
+
processAlert(alert);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
catch (err) {
|
|
456
|
+
logger.error("Poll error", { error: String(err) });
|
|
457
|
+
}
|
|
458
|
+
}, config.pollIntervalMs);
|
|
459
|
+
// Heartbeat — flush Logtail buffer every 30s
|
|
460
|
+
setInterval(async () => {
|
|
461
|
+
logger.debug("heartbeat", {
|
|
462
|
+
uptime_s: Math.round(process.uptime()),
|
|
463
|
+
seen_alerts: seenAlerts.size,
|
|
464
|
+
});
|
|
465
|
+
await logger.flush();
|
|
466
|
+
}, 30_000);
|
|
467
|
+
// Graceful shutdown
|
|
468
|
+
for (const sig of ["SIGINT", "SIGTERM"]) {
|
|
469
|
+
process.on(sig, async () => {
|
|
470
|
+
logger.info(`Shutting down (${sig})`);
|
|
471
|
+
await logger.flush();
|
|
472
|
+
process.exit(0);
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
main().catch(async (err) => {
|
|
477
|
+
logger.error("Fatal error", { error: String(err) });
|
|
478
|
+
await logger.flush();
|
|
479
|
+
process.exit(1);
|
|
480
|
+
});
|
|
481
|
+
//# sourceMappingURL=bot.js.map
|
package/dist/bot.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot.js","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,MAAM,EAAwB,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEhD,wDAAwD;AACxD,+CAA+C;AAC/C,wDAAwD;AAExD,+DAA+D;AAC/D,SAAS,cAAc,CAAC,UAAoB;IAC1C,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACrC,IAAI,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,OAAO,IAAI,CAAC;QAChD,IACE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAE1E,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,oDAAoD;AACpD,SAAS,gBAAgB,CAAC,UAAoB;IAC5C,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACtC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CACxE,CAAC;IACF,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC;QACvB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QACpB,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAQD,+CAA+C;AAC/C,MAAM,oBAAoB,GAAuC;IAC/D,aAAa,EAAE,OAAO;IACtB,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,eAAe;CAC1B,CAAC;AAEF,SAAS,iBAAiB,CAAC,KAAa;IACtC,IAAI,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC;QAAE,OAAO,UAAU,CAAC;IACvD,IAAI,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC;QACpE,OAAO,eAAe,CAAC;IACzB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,wDAAwD;AACxD,mBAAmB;AACnB,wDAAwD;AAExD,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,2CAA2C;AACpF,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,UAAU;AAC/C,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,QAAQ;AAEpD,MAAM,QAAQ,GAA8B;IAC1C,aAAa,EAAE,CAAC;IAChB,KAAK,EAAE,CAAC;IACR,QAAQ,EAAE,CAAC;CACZ,CAAC;AAEF,SAAS,UAAU,CAAC,IAAe;IACjC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5C,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,eAAe;YAClB,OAAO,OAAO,IAAI,iBAAiB,CAAC;QACtC,KAAK,UAAU;YACb,OAAO,OAAO,IAAI,oBAAoB,CAAC;QACzC,KAAK,OAAO;YACV,OAAO,OAAO,IAAI,iBAAiB,CAAC;IACxC,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,IAAe;IAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC;IACrB,uDAAuD;IACvD,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,QAAQ,CAAC,aAAa,GAAG,CAAC,CAAC;QAC3B,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC;IACrB,CAAC;IACD,iEAAiE;IACjE,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,QAAQ,CAAC,aAAa,GAAG,CAAC,CAAC;QAC3B,QAAQ,CAAC,QAAQ,GAAG,CAAC,CAAC;IACxB,CAAC;IACD,uCAAuC;IACvC,IAAI,IAAI,KAAK,eAAe;QAAE,QAAQ,CAAC,QAAQ,GAAG,CAAC,CAAC;AACtD,CAAC;AAcD,wDAAwD;AACxD,cAAc;AACd,wDAAwD;AAExD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;AAErC,KAAK,UAAU,WAAW;IACxB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE;YACzC,OAAO,EAAE;gBACP,YAAY,EACV,uHAAuH;gBACzH,kBAAkB,EAAE,gBAAgB;gBACpC,OAAO,EAAE,0BAA0B;gBACnC,MAAM,EAAE,mCAAmC;aAC5C;SACF,CAAC,CAAC;QAEH,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;QAE3B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;YAC1D,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YACjB,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YACzE,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAEzC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,6BAA6B,EAAE;gBACzC,KAAK,EAAE,MAAM,CAAC,MAAM;gBACpB,EAAE;gBACF,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;aACzB,CAAC,CAAC;YACH,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;YAC3D,MAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE;gBACtC,EAAE;gBACF,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;aACzB,CAAC,CAAC;YACH,OAAO,CAAC,MAAmB,CAAC,CAAC;QAC/B,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACzE,OAAO,EAAE,CAAC;IACZ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE;YAC/B,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;YAClB,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;SACpB,CAAC,CAAC;QACH,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,wDAAwD;AACxD,oBAAoB;AACpB,wDAAwD;AAExD,yDAAyD;AAEzD,MAAM,kBAAkB,GAAG;IACzB,uDAAuD;IACvD,uDAAuD;IACvD,4DAA4D;IAC5D,2DAA2D;IAC3D,2DAA2D;CAC5D,CAAC;AAEF,MAAM,wBAAwB,GAAG;IAC/B,4DAA4D;IAC5D,+DAA+D;IAC/D,2DAA2D;CAC5D,CAAC;AAEF,MAAM,UAAU,GAAG;IACjB,iEAAiE;IACjE,wDAAwD;IACxD,4DAA4D;IAC5D,0DAA0D;IAC1D,8DAA8D;CAC/D,CAAC;AAEF,MAAM,aAAa,GAAG;IACpB,wDAAwD;IACxD,0DAA0D;IAC1D,sDAAsD;IACtD,4DAA4D;IAC5D,6DAA6D;CAC9D,CAAC;AAEF,yDAAyD;AAEzD,MAAM,uBAAuB,GAAG;IAC9B,4DAA4D,EAAE,QAAQ;IACtE,2DAA2D,EAAE,eAAe;CAC7E,CAAC;AAEF,MAAM,eAAe,GAAG;IACtB,4DAA4D,EAAE,eAAe;IAC7E,2DAA2D,EAAE,eAAe;CAC7E,CAAC;AAEF,MAAM,kBAAkB,GAAG;IACzB,uDAAuD,EAAE,YAAY;IACrE,4DAA4D,EAAE,YAAY;CAC3E,CAAC;AAWF,MAAM,SAAS,GAA6B;IAC1C,UAAU,EAAE;QACV,KAAK,EAAE,kBAAkB;QACzB,UAAU,EAAE,CAAC,GAAG,kBAAkB,EAAE,GAAG,wBAAwB,CAAC;QAChE,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,aAAa;KACxB;IACD,SAAS,EAAE;QACT,KAAK,EAAE,uBAAuB;QAC9B,UAAU,EAAE,uBAAuB;QACnC,KAAK,EAAE,eAAe;QACtB,QAAQ,EAAE,kBAAkB;KAC7B;CACF,CAAC;AAEF,+CAA+C;AAC/C,SAAS,eAAe;IACtB,MAAM,CAAC,GAAG,MAAM,CACd,IAAI,IAAI,EAAE,CAAC,kBAAkB,CAAC,OAAO,EAAE;QACrC,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,gBAAgB;KAC3B,CAAC,CACH,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,SAAS,CAAC,SAAoB;IACrC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC;IAE5B,kCAAkC;IAClC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,cAAc;QAAE,OAAO,IAAI,CAAC;IAE5D,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,eAAe,CAAC,CAAC,CAAC;YACrB,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;YAChE,OAAO,OAAO,CACZ,IAAI,EACJ,eAAe,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI,QAAQ,CAC5D,CAAC;QACJ,CAAC;QACD,KAAK,OAAO;YACV,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,IAAI,QAAQ,CAAC,CAAC;QAC/C,KAAK,UAAU;YACb,OAAO,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,IAAI,WAAW,CAAC,CAAC;IACvD,CAAC;AACH,CAAC;AAED,wDAAwD;AACxD,WAAW;AACX,wDAAwD;AAExD,IAAI,GAAG,GAAe,IAAI,CAAC;AAE3B,SAAS,OAAO;IACd,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACpD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;QAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM;QAC5C,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,QAAQ,EAAE,MAAM,CAAC,OAAO;KACzB,CAAC,CAAC;IACH,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,OAAO;IACd,OAAO,IAAI,IAAI,EAAE,CAAC,kBAAkB,CAAC,OAAO,EAAE;QAC5C,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,QAAQ,EAAE,gBAAgB;KAC3B,CAAC,CAAC;AACL,CAAC;AAED,SAAS,aAAa,CAAC,SAAoB,EAAE,KAAa;IACxD,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAEnD,+EAA+E;IAC/E,IAAI,QAAQ,IAAI,OAAO,EAAE,CAAC;QACxB,OAAO;YACL,MAAM,QAAQ,MAAM;YACpB,OAAO;YACP,EAAE;YACF,cAAc;YACd,MAAM,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,SAAS,UAAU,EAAE;YACjJ,SAAS,KAAK,UAAU;gBACtB,CAAC,CAAC,MAAM,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,SAAS,IAAI,EAAE;gBAC1I,CAAC,CAAC,EAAE;YACN,eAAe;SAChB;aACE,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IAED,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,eAAe;YAClB,OAAO,SAAS,CAAC,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAClD,KAAK,OAAO;YACV,OAAO,SAAS,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC3C,KAAK,UAAU;YACb,OAAO,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,SAAoB,EAAE,IAAY;IAC5D,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE;YACnC,UAAU,EAAE,CAAC,CAAC,GAAG;YACjB,OAAO,EAAE,MAAM,CAAC,MAAM;SACvB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IAEpC,+BAA+B;IAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;YACvE,MAAM,CAAC,IAAI,CAAC,gCAAgC,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QACrE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE;gBACnC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;gBAClB,IAAI,EAAE,SAAS;aAChB,CAAC,CAAC;QACL,CAAC;QACD,OAAO;IACT,CAAC;IAED,8CAA8C;IAC9C,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE;YACjD,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,MAAM;SACnB,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,+BAA+B,EAAE;YAC3C,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,uCAAuC,EAAE;YACnD,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;YAClB,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;QACH,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;YACvE,MAAM,CAAC,IAAI,CAAC,yCAAyC,EAAE;gBACrD,IAAI,EAAE,SAAS;aAChB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,IAAI,EAAE,CAAC;YACd,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE;gBAC9C,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC;gBACnB,IAAI,EAAE,SAAS;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,wDAAwD;AACxD,mBAAmB;AACnB,wDAAwD;AAExD,SAAS,YAAY,CAAC,KAAgB;IACpC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE;YACrC,QAAQ,EAAE,KAAK,CAAC,EAAE;YAClB,QAAQ,EAAE,KAAK,CAAC,IAAI;SACrB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAEjD,mCAAmC;IACnC,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAC/C,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,mCAAmC,EAAE;YAC/C,QAAQ,EAAE,KAAK,CAAC,EAAE;YAClB,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,MAAM;SACnB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAE3C,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE;QAC9B,QAAQ,EAAE,KAAK,CAAC,EAAE;QAClB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,KAAK,CAAC,IAAI;KACrB,CAAC,CAAC;IAEH,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,MAAM,CAAC,IAAI,CAAC,oCAAoC,EAAE;YAChD,QAAQ,EAAE,KAAK,CAAC,EAAE;YAClB,IAAI,EAAE,SAAS;SAChB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,SAAS,CAAC,CAAC;IAEpB,MAAM,OAAO,GAAG,aAAa,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAChD,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAC7C,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE;QACnC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;QAClB,QAAQ,EAAE,KAAK,CAAC,EAAE;KACnB,CAAC,CACH,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,gBAAgB;AAChB,wDAAwD;AAExD,SAAS,iBAAiB;IACxB,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACvC,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YAC1B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAC3D,GAAG,CAAC,GAAG,CACL,IAAI,CAAC,SAAS,CAAC;gBACb,MAAM,EAAE,IAAI;gBACZ,OAAO,EAAE,UAAU;gBACnB,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;gBACxB,WAAW,EAAE,UAAU,CAAC,IAAI;gBAC5B,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,QAAQ,EAAE,MAAM,CAAC,OAAO;gBACxB,KAAK,EAAE,MAAM,CAAC,KAAK;aACpB,CAAC,CACH,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,wDAAwD;AACxD,OAAO;AACP,wDAAwD;AAExD,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE;QAC/B,gBAAgB,EAAE,MAAM,CAAC,cAAc;QACvC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU;QAClD,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,OAAO;QACxB,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC,CAAC;IAEH,MAAM,gBAAgB,EAAE,CAAC;IAEzB,kEAAkE;IAClE,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,CAAC,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,iCAAiC,EAAE;YAC7C,QAAQ,EAAE,MAAM,CAAC,OAAO;YACxB,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,gEAAgE;QAChE,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;aACxC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC,CAAC;QACnB,MAAM,CAAC,IAAI,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;IAC1E,CAAC;IAED,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7B,GAAG,GAAG,OAAO,EAAE,CAAC;IAChB,iBAAiB,EAAE,CAAC;IAEpB,YAAY;IACZ,WAAW,CAAC,KAAK,IAAI,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;YACnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBAAE,SAAS;gBACvC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACzB,YAAY,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;IAE1B,6CAA6C;IAC7C,WAAW,CAAC,KAAK,IAAI,EAAE;QACrB,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE;YACxB,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACtC,WAAW,EAAE,UAAU,CAAC,IAAI;SAC7B,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,EAAE,MAAM,CAAC,CAAC;IAEX,oBAAoB;IACpB,KAAK,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAU,EAAE,CAAC;QACjD,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;YACzB,MAAM,CAAC,IAAI,CAAC,kBAAkB,GAAG,GAAG,CAAC,CAAC;YACtC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IACzB,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpD,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EasyOref — Centralized Configuration
|
|
3
|
+
*
|
|
4
|
+
* Primary: config.yaml (searched in cwd, /app, /etc/easyoref)
|
|
5
|
+
* Fallback: environment variables + Docker secrets (for backward compat)
|
|
6
|
+
*
|
|
7
|
+
* See config.yaml.example for all available options.
|
|
8
|
+
*/
|
|
9
|
+
import { type Language } from "./i18n.js";
|
|
10
|
+
export type AlertTypeConfig = "early" | "siren" | "incident_over";
|
|
11
|
+
export type GifMode = "funny_cats" | "assertive" | "pikud_haoref" | "none";
|
|
12
|
+
/** Raw YAML schema */
|
|
13
|
+
interface ConfigYaml {
|
|
14
|
+
alert_types?: AlertTypeConfig[];
|
|
15
|
+
city_ids?: number[];
|
|
16
|
+
language?: string;
|
|
17
|
+
gif_mode?: string;
|
|
18
|
+
title_override?: Partial<Record<AlertTypeConfig, string>>;
|
|
19
|
+
description_override?: Partial<Record<AlertTypeConfig, string>>;
|
|
20
|
+
observability?: {
|
|
21
|
+
betterstack_token?: string;
|
|
22
|
+
};
|
|
23
|
+
telegram?: {
|
|
24
|
+
bot_token?: string;
|
|
25
|
+
chat_id?: string;
|
|
26
|
+
};
|
|
27
|
+
health_port?: number;
|
|
28
|
+
poll_interval_ms?: number;
|
|
29
|
+
data_dir?: string;
|
|
30
|
+
oref_api_url?: string;
|
|
31
|
+
}
|
|
32
|
+
/** Config dir in user home — ~/.easyoref/ */
|
|
33
|
+
export declare const CONFIG_DIR: string;
|
|
34
|
+
export declare const HOME_CONFIG_PATH: string;
|
|
35
|
+
declare function loadYaml(): ConfigYaml;
|
|
36
|
+
declare function parseAlertTypes(raw?: AlertTypeConfig[]): AlertTypeConfig[];
|
|
37
|
+
export declare const config: {
|
|
38
|
+
/** Telegram bot token */
|
|
39
|
+
botToken: string;
|
|
40
|
+
/** Telegram chat ID */
|
|
41
|
+
chatId: string;
|
|
42
|
+
/** City IDs to monitor (resolved to Hebrew names at startup via cities.json) */
|
|
43
|
+
cityIds: number[];
|
|
44
|
+
/**
|
|
45
|
+
* Hebrew area names — legacy fallback for AREAS env var.
|
|
46
|
+
* Populated at startup from cityIds OR from AREAS env if no cityIds.
|
|
47
|
+
*/
|
|
48
|
+
areas: string[];
|
|
49
|
+
/** Which alert types to send */
|
|
50
|
+
alertTypes: AlertTypeConfig[];
|
|
51
|
+
/** Message language */
|
|
52
|
+
language: Language;
|
|
53
|
+
/** Title overrides per alert type */
|
|
54
|
+
titleOverride: Partial<Record<AlertTypeConfig, string>>;
|
|
55
|
+
/** Description overrides per alert type */
|
|
56
|
+
descriptionOverride: Partial<Record<AlertTypeConfig, string>>;
|
|
57
|
+
/** Oref API polling interval (ms) */
|
|
58
|
+
pollIntervalMs: number;
|
|
59
|
+
/** Health endpoint port */
|
|
60
|
+
healthPort: number;
|
|
61
|
+
/** Oref API URL */
|
|
62
|
+
orefApiUrl: string;
|
|
63
|
+
/** Better Stack Logtail token */
|
|
64
|
+
logtailToken: string;
|
|
65
|
+
/** GIF mode */
|
|
66
|
+
gifMode: GifMode;
|
|
67
|
+
/** Path for persistent data */
|
|
68
|
+
dataDir: string;
|
|
69
|
+
};
|
|
70
|
+
/** Exported for testing */
|
|
71
|
+
export { loadYaml as _loadYaml, parseAlertTypes as _parseAlertTypes, type ConfigYaml, };
|
|
72
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAI3D,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,GAAG,eAAe,CAAC;AAClE,MAAM,MAAM,OAAO,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,GAAG,MAAM,CAAC;AAW3E,sBAAsB;AACtB,UAAU,UAAU;IAClB,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,oBAAoB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE;QACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAID,6CAA6C;AAC7C,eAAO,MAAM,UAAU,QAA+B,CAAC;AACvD,eAAO,MAAM,gBAAgB,QAAkC,CAAC;AAoBhE,iBAAS,QAAQ,IAAI,UAAU,CAe9B;AAgBD,iBAAS,eAAe,CAAC,GAAG,CAAC,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAGnE;AAMD,eAAO,MAAM,MAAM;IACjB,yBAAyB;;IAKzB,uBAAuB;;IAGvB,gFAAgF;;IAGhF;;;OAGG;WACU,MAAM,EAAE;IAErB,gCAAgC;;IAGhC,uBAAuB;;IAMvB,qCAAqC;;IAGrC,2CAA2C;;IAG3C,qCAAqC;;IAIrC,2BAA2B;;IAG3B,mBAAmB;;IAMnB,iCAAiC;;IAIjC,eAAe;;IAGf,+BAA+B;;CAEhC,CAAC;AAEF,2BAA2B;AAC3B,OAAO,EACL,QAAQ,IAAI,SAAS,EACrB,eAAe,IAAI,gBAAgB,EACnC,KAAK,UAAU,GAChB,CAAC"}
|