easyoref 1.5.0 → 1.7.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/package.json +12 -2
- package/dist/bin.d.ts +0 -17
- package/dist/bin.d.ts.map +0 -1
- package/dist/bin.js +0 -82
- package/dist/bin.js.map +0 -1
- package/dist/bot.d.ts +0 -16
- package/dist/bot.d.ts.map +0 -1
- package/dist/bot.js +0 -477
- package/dist/bot.js.map +0 -1
- package/dist/config.d.ts +0 -75
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -122
- package/dist/config.js.map +0 -1
- package/dist/gif-state.d.ts +0 -17
- package/dist/gif-state.d.ts.map +0 -1
- package/dist/gif-state.js +0 -67
- package/dist/gif-state.js.map +0 -1
- package/dist/i18n.d.ts +0 -49
- package/dist/i18n.d.ts.map +0 -1
- package/dist/i18n.js +0 -229
- package/dist/i18n.js.map +0 -1
- package/dist/init.d.ts +0 -7
- package/dist/init.d.ts.map +0 -1
- package/dist/init.js +0 -163
- package/dist/init.js.map +0 -1
- package/dist/logger.d.ts +0 -14
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -45
- package/dist/logger.js.map +0 -1
- package/dist/service.d.ts +0 -19
- package/dist/service.d.ts.map +0 -1
- package/dist/service.js +0 -165
- package/dist/service.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "easyoref",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Real-time Israeli civil defense alerts → Telegram, filtered by your location",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -32,14 +32,24 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@inquirer/prompts": "^7.0.0",
|
|
35
|
+
"@langchain/core": "^0.3.0",
|
|
36
|
+
"@langchain/google-genai": "^0.1.12",
|
|
37
|
+
"@langchain/langgraph": "^0.2.0",
|
|
35
38
|
"@logtail/node": "^0.5.6",
|
|
39
|
+
"bullmq": "^5.0.0",
|
|
36
40
|
"chalk": "^5.3.0",
|
|
37
41
|
"grammy": "^1.35.0",
|
|
38
|
-
"
|
|
42
|
+
"input": "^1.0.1",
|
|
43
|
+
"ioredis": "^5.3.0",
|
|
44
|
+
"js-yaml": "^4.1.1",
|
|
45
|
+
"qrcode-terminal": "^0.12.0",
|
|
46
|
+
"telegram": "^2.26.0"
|
|
39
47
|
},
|
|
40
48
|
"devDependencies": {
|
|
49
|
+
"@types/ioredis": "^4.28.10",
|
|
41
50
|
"@types/js-yaml": "^4.0.9",
|
|
42
51
|
"@types/node": "^22.0.0",
|
|
52
|
+
"@types/qrcode-terminal": "^0.12.2",
|
|
43
53
|
"eslint": "^9.0.0",
|
|
44
54
|
"tsx": "^4.19.0",
|
|
45
55
|
"typescript": "^5.7.0"
|
package/dist/bin.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* EasyOref CLI entrypoint.
|
|
4
|
-
*
|
|
5
|
-
* easyoref — run the bot (foreground)
|
|
6
|
-
* easyoref run — same as above
|
|
7
|
-
* easyoref init — interactive setup wizard
|
|
8
|
-
* easyoref install — create systemd service + start
|
|
9
|
-
* easyoref uninstall — remove systemd service
|
|
10
|
-
* easyoref start — start service (install if needed)
|
|
11
|
-
* easyoref stop — stop service
|
|
12
|
-
* easyoref restart — restart service
|
|
13
|
-
* easyoref status — show service status
|
|
14
|
-
* easyoref logs — follow service logs
|
|
15
|
-
*/
|
|
16
|
-
export {};
|
|
17
|
-
//# sourceMappingURL=bin.d.ts.map
|
package/dist/bin.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG"}
|
package/dist/bin.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* EasyOref CLI entrypoint.
|
|
4
|
-
*
|
|
5
|
-
* easyoref — run the bot (foreground)
|
|
6
|
-
* easyoref run — same as above
|
|
7
|
-
* easyoref init — interactive setup wizard
|
|
8
|
-
* easyoref install — create systemd service + start
|
|
9
|
-
* easyoref uninstall — remove systemd service
|
|
10
|
-
* easyoref start — start service (install if needed)
|
|
11
|
-
* easyoref stop — stop service
|
|
12
|
-
* easyoref restart — restart service
|
|
13
|
-
* easyoref status — show service status
|
|
14
|
-
* easyoref logs — follow service logs
|
|
15
|
-
*/
|
|
16
|
-
const command = process.argv[2];
|
|
17
|
-
switch (command) {
|
|
18
|
-
case "init": {
|
|
19
|
-
const { init } = await import("./init.js");
|
|
20
|
-
await init();
|
|
21
|
-
break;
|
|
22
|
-
}
|
|
23
|
-
case "install": {
|
|
24
|
-
const svc = await import("./service.js");
|
|
25
|
-
svc.install();
|
|
26
|
-
break;
|
|
27
|
-
}
|
|
28
|
-
case "uninstall": {
|
|
29
|
-
const svc = await import("./service.js");
|
|
30
|
-
svc.uninstall();
|
|
31
|
-
break;
|
|
32
|
-
}
|
|
33
|
-
case "start": {
|
|
34
|
-
const svc = await import("./service.js");
|
|
35
|
-
svc.start();
|
|
36
|
-
break;
|
|
37
|
-
}
|
|
38
|
-
case "stop": {
|
|
39
|
-
const svc = await import("./service.js");
|
|
40
|
-
svc.stop();
|
|
41
|
-
break;
|
|
42
|
-
}
|
|
43
|
-
case "restart": {
|
|
44
|
-
const svc = await import("./service.js");
|
|
45
|
-
svc.restart();
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
48
|
-
case "status": {
|
|
49
|
-
const svc = await import("./service.js");
|
|
50
|
-
svc.status();
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
53
|
-
case "logs": {
|
|
54
|
-
const svc = await import("./service.js");
|
|
55
|
-
svc.logs();
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
case "--help":
|
|
59
|
-
case "-h":
|
|
60
|
-
console.log(`
|
|
61
|
-
EasyOref — Telegram alert bot for Israeli civil defense
|
|
62
|
-
|
|
63
|
-
Usage:
|
|
64
|
-
easyoref Run the bot (foreground)
|
|
65
|
-
easyoref init Interactive setup wizard
|
|
66
|
-
|
|
67
|
-
Service management:
|
|
68
|
-
easyoref install Create systemd service & start
|
|
69
|
-
easyoref uninstall Remove systemd service
|
|
70
|
-
easyoref start Start service (auto-install if needed)
|
|
71
|
-
easyoref stop Stop service
|
|
72
|
-
easyoref restart Restart service
|
|
73
|
-
easyoref status Show service status
|
|
74
|
-
easyoref logs Follow service logs
|
|
75
|
-
`);
|
|
76
|
-
break;
|
|
77
|
-
case "run":
|
|
78
|
-
default:
|
|
79
|
-
await import("./bot.js");
|
|
80
|
-
}
|
|
81
|
-
export {};
|
|
82
|
-
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG;AAEH,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEhC,QAAQ,OAAO,EAAE,CAAC;IAChB,KAAK,MAAM,CAAC,CAAC,CAAC;QACZ,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAC3C,MAAM,IAAI,EAAE,CAAC;QACb,MAAM;IACR,CAAC;IAED,KAAK,SAAS,CAAC,CAAC,CAAC;QACf,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACzC,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,MAAM;IACR,CAAC;IAED,KAAK,WAAW,CAAC,CAAC,CAAC;QACjB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACzC,GAAG,CAAC,SAAS,EAAE,CAAC;QAChB,MAAM;IACR,CAAC;IAED,KAAK,OAAO,CAAC,CAAC,CAAC;QACb,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACzC,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM;IACR,CAAC;IAED,KAAK,MAAM,CAAC,CAAC,CAAC;QACZ,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACzC,GAAG,CAAC,IAAI,EAAE,CAAC;QACX,MAAM;IACR,CAAC;IAED,KAAK,SAAS,CAAC,CAAC,CAAC;QACf,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACzC,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,MAAM;IACR,CAAC;IAED,KAAK,QAAQ,CAAC,CAAC,CAAC;QACd,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACzC,GAAG,CAAC,MAAM,EAAE,CAAC;QACb,MAAM;IACR,CAAC;IAED,KAAK,MAAM,CAAC,CAAC,CAAC;QACZ,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACzC,GAAG,CAAC,IAAI,EAAE,CAAC;QACX,MAAM;IACR,CAAC;IAED,KAAK,QAAQ,CAAC;IACd,KAAK,IAAI;QACP,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;CAef,CAAC,CAAC;QACC,MAAM;IAER,KAAK,KAAK,CAAC;IACX;QACE,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;AAC7B,CAAC"}
|
package/dist/bot.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
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
|
-
export {};
|
|
16
|
-
//# sourceMappingURL=bot.d.ts.map
|
package/dist/bot.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
|
package/dist/bot.js
DELETED
|
@@ -1,477 +0,0 @@
|
|
|
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 { getLanguagePack, initTranslations, resolveCityIds, translateAreas, } from "./i18n.js";
|
|
20
|
-
import * as logger from "./logger.js";
|
|
21
|
-
const langPack = getLanguagePack(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: "resolved",
|
|
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 defaults = langPack.alerts[cfgKey];
|
|
264
|
-
const labels = langPack.labels;
|
|
265
|
-
const emoji = config.emojiOverride[cfgKey] ?? defaults.emoji;
|
|
266
|
-
const title = config.titleOverride[cfgKey] ?? defaults.title;
|
|
267
|
-
const desc = config.descriptionOverride[cfgKey] ?? defaults.description;
|
|
268
|
-
const lines = [`<b>${emoji} ${title}</b>`];
|
|
269
|
-
if (desc)
|
|
270
|
-
lines.push(desc);
|
|
271
|
-
lines.push("");
|
|
272
|
-
lines.push(`<b>${labels.area}:</b> ${localAreas}`);
|
|
273
|
-
if (alertType === "early_warning") {
|
|
274
|
-
lines.push(`<b>${labels.timeToImpact}:</b> ${labels.earlyEta}`);
|
|
275
|
-
lines.push(`<b>${labels.time}:</b> ${time}`);
|
|
276
|
-
}
|
|
277
|
-
else if (alertType === "siren") {
|
|
278
|
-
lines.push(`<b>${labels.timeToImpact}:</b> ${labels.sirenEta}`);
|
|
279
|
-
lines.push(`<b>${labels.time}:</b> ${time}`);
|
|
280
|
-
}
|
|
281
|
-
else if (alertType === "resolved") {
|
|
282
|
-
lines.push(`<b>${labels.time}:</b> ${time}`);
|
|
283
|
-
}
|
|
284
|
-
return lines.join("\n");
|
|
285
|
-
}
|
|
286
|
-
async function sendTelegram(alertType, text) {
|
|
287
|
-
if (!bot || !config.chatId) {
|
|
288
|
-
logger.error("Telegram unavailable", {
|
|
289
|
-
bot_exists: !!bot,
|
|
290
|
-
chat_id: config.chatId,
|
|
291
|
-
});
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
const gifUrl = getGifUrl(alertType);
|
|
295
|
-
// No GIF mode → send text only
|
|
296
|
-
if (!gifUrl) {
|
|
297
|
-
try {
|
|
298
|
-
await bot.api.sendMessage(config.chatId, text, { parse_mode: "HTML" });
|
|
299
|
-
logger.info("Alert sent via Telegram (text)", { type: alertType });
|
|
300
|
-
}
|
|
301
|
-
catch (err) {
|
|
302
|
-
logger.error("Telegram send failed", {
|
|
303
|
-
error: String(err),
|
|
304
|
-
type: alertType,
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
// GIF mode → try animation, fall back to text
|
|
310
|
-
try {
|
|
311
|
-
await bot.api.sendAnimation(config.chatId, gifUrl, {
|
|
312
|
-
caption: text,
|
|
313
|
-
parse_mode: "HTML",
|
|
314
|
-
});
|
|
315
|
-
logger.info("Alert sent via Telegram (GIF)", {
|
|
316
|
-
type: alertType,
|
|
317
|
-
gif_url: gifUrl,
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
catch (err) {
|
|
321
|
-
logger.warn("GIF send failed, falling back to text", {
|
|
322
|
-
error: String(err),
|
|
323
|
-
gif_url: gifUrl,
|
|
324
|
-
});
|
|
325
|
-
try {
|
|
326
|
-
await bot.api.sendMessage(config.chatId, text, { parse_mode: "HTML" });
|
|
327
|
-
logger.info("Alert sent via Telegram (text fallback)", {
|
|
328
|
-
type: alertType,
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
catch (err2) {
|
|
332
|
-
logger.error("Telegram send failed completely", {
|
|
333
|
-
error: String(err2),
|
|
334
|
-
type: alertType,
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
340
|
-
// Alert Processing
|
|
341
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
342
|
-
function processAlert(alert) {
|
|
343
|
-
if (!isRelevantArea(alert.data)) {
|
|
344
|
-
logger.info("Alert — not in our area", {
|
|
345
|
-
alert_id: alert.id,
|
|
346
|
-
areas_he: alert.data,
|
|
347
|
-
});
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
const alertType = classifyAlertType(alert.title);
|
|
351
|
-
// Filter by configured alert types
|
|
352
|
-
const cfgKey = ALERT_TYPE_TO_CONFIG[alertType];
|
|
353
|
-
if (!config.alertTypes.includes(cfgKey)) {
|
|
354
|
-
logger.info("Alert type filtered out by config", {
|
|
355
|
-
alert_id: alert.id,
|
|
356
|
-
type: alertType,
|
|
357
|
-
config_key: cfgKey,
|
|
358
|
-
});
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
const areas = matchedAreaLabel(alert.data);
|
|
362
|
-
logger.info("Alert — RELEVANT", {
|
|
363
|
-
alert_id: alert.id,
|
|
364
|
-
type: alertType,
|
|
365
|
-
areas_he: alert.data,
|
|
366
|
-
});
|
|
367
|
-
if (!shouldSend(alertType)) {
|
|
368
|
-
logger.info("Cooldown active, skipping Telegram", {
|
|
369
|
-
alert_id: alert.id,
|
|
370
|
-
type: alertType,
|
|
371
|
-
});
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
markSent(alertType);
|
|
375
|
-
const message = formatMessage(alertType, areas);
|
|
376
|
-
sendTelegram(alertType, message).catch((err) => logger.error("Telegram send failed", {
|
|
377
|
-
error: String(err),
|
|
378
|
-
alert_id: alert.id,
|
|
379
|
-
}));
|
|
380
|
-
}
|
|
381
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
382
|
-
// Health Server
|
|
383
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
384
|
-
function startHealthServer() {
|
|
385
|
-
const server = createServer((req, res) => {
|
|
386
|
-
if (req.url === "/health") {
|
|
387
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
388
|
-
res.end(JSON.stringify({
|
|
389
|
-
status: "ok",
|
|
390
|
-
service: "easyoref",
|
|
391
|
-
uptime: process.uptime(),
|
|
392
|
-
seen_alerts: seenAlerts.size,
|
|
393
|
-
language: config.language,
|
|
394
|
-
gif_mode: config.gifMode,
|
|
395
|
-
areas: config.areas,
|
|
396
|
-
}));
|
|
397
|
-
}
|
|
398
|
-
else {
|
|
399
|
-
res.writeHead(404);
|
|
400
|
-
res.end("Not Found");
|
|
401
|
-
}
|
|
402
|
-
});
|
|
403
|
-
server.listen(config.healthPort, () => {
|
|
404
|
-
logger.info("Health server started", { port: config.healthPort });
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
408
|
-
// Main
|
|
409
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
410
|
-
async function main() {
|
|
411
|
-
logger.info("EasyOref starting", {
|
|
412
|
-
poll_interval_ms: config.pollIntervalMs,
|
|
413
|
-
telegram: config.botToken ? "enabled" : "disabled",
|
|
414
|
-
language: config.language,
|
|
415
|
-
gif_mode: config.gifMode,
|
|
416
|
-
areas: config.areas,
|
|
417
|
-
});
|
|
418
|
-
await initTranslations();
|
|
419
|
-
// Resolve YAML city_ids → Hebrew area names for Oref API matching
|
|
420
|
-
if (config.cityIds.length > 0) {
|
|
421
|
-
config.areas = resolveCityIds(config.cityIds);
|
|
422
|
-
logger.info("Resolved city IDs to area names", {
|
|
423
|
-
city_ids: config.cityIds,
|
|
424
|
-
areas: config.areas,
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
else if (process.env.AREAS) {
|
|
428
|
-
// Legacy fallback: AREAS env var (comma-separated Hebrew names)
|
|
429
|
-
config.areas = process.env.AREAS.split(",")
|
|
430
|
-
.map((s) => s.trim())
|
|
431
|
-
.filter(Boolean);
|
|
432
|
-
logger.info("Using legacy AREAS env var", { areas: config.areas });
|
|
433
|
-
}
|
|
434
|
-
if (config.areas.length === 0) {
|
|
435
|
-
logger.warn("No areas configured — bot will not filter alerts by area");
|
|
436
|
-
}
|
|
437
|
-
initGifState(config.dataDir);
|
|
438
|
-
bot = initBot();
|
|
439
|
-
startHealthServer();
|
|
440
|
-
// Poll loop
|
|
441
|
-
setInterval(async () => {
|
|
442
|
-
try {
|
|
443
|
-
const alerts = await fetchAlerts();
|
|
444
|
-
for (const alert of alerts) {
|
|
445
|
-
if (seenAlerts.has(alert.id))
|
|
446
|
-
continue;
|
|
447
|
-
seenAlerts.add(alert.id);
|
|
448
|
-
processAlert(alert);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
catch (err) {
|
|
452
|
-
logger.error("Poll error", { error: String(err) });
|
|
453
|
-
}
|
|
454
|
-
}, config.pollIntervalMs);
|
|
455
|
-
// Heartbeat — flush Logtail buffer every 30s
|
|
456
|
-
setInterval(async () => {
|
|
457
|
-
logger.debug("heartbeat", {
|
|
458
|
-
uptime_s: Math.round(process.uptime()),
|
|
459
|
-
seen_alerts: seenAlerts.size,
|
|
460
|
-
});
|
|
461
|
-
await logger.flush();
|
|
462
|
-
}, 30_000);
|
|
463
|
-
// Graceful shutdown
|
|
464
|
-
for (const sig of ["SIGINT", "SIGTERM"]) {
|
|
465
|
-
process.on(sig, async () => {
|
|
466
|
-
logger.info(`Shutting down (${sig})`);
|
|
467
|
-
await logger.flush();
|
|
468
|
-
process.exit(0);
|
|
469
|
-
});
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
main().catch(async (err) => {
|
|
473
|
-
logger.error("Fatal error", { error: String(err) });
|
|
474
|
-
await logger.flush();
|
|
475
|
-
process.exit(1);
|
|
476
|
-
});
|
|
477
|
-
//# sourceMappingURL=bot.js.map
|
package/dist/bot.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bot.js","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"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"}
|