easyoref 1.27.9 → 2.0.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.
- package/dist/agent/types.d.ts +1 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/bot.js +153 -71
- package/dist/bot.js.map +1 -1
- package/dist/gif-state.js +1 -1
- package/dist/gif-state.js.map +1 -1
- package/dist/handlers/admin.d.ts +3 -0
- package/dist/handlers/admin.d.ts.map +1 -0
- package/dist/handlers/admin.js +119 -0
- package/dist/handlers/admin.js.map +1 -0
- package/dist/handlers/inline.d.ts +3 -0
- package/dist/handlers/inline.d.ts.map +1 -0
- package/dist/handlers/inline.js +88 -0
- package/dist/handlers/inline.js.map +1 -0
- package/dist/handlers/qa.d.ts +3 -0
- package/dist/handlers/qa.d.ts.map +1 -0
- package/dist/handlers/qa.js +47 -0
- package/dist/handlers/qa.js.map +1 -0
- package/dist/handlers/settings.d.ts +3 -0
- package/dist/handlers/settings.d.ts.map +1 -0
- package/dist/handlers/settings.js +110 -0
- package/dist/handlers/settings.js.map +1 -0
- package/dist/handlers/shelter.d.ts +7 -0
- package/dist/handlers/shelter.d.ts.map +1 -0
- package/dist/handlers/shelter.js +60 -0
- package/dist/handlers/shelter.js.map +1 -0
- package/dist/handlers/start.d.ts +18 -0
- package/dist/handlers/start.d.ts.map +1 -0
- package/dist/handlers/start.js +182 -0
- package/dist/handlers/start.js.map +1 -0
- package/dist/middleware/tier.d.ts +7 -0
- package/dist/middleware/tier.d.ts.map +1 -0
- package/dist/middleware/tier.js +17 -0
- package/dist/middleware/tier.js.map +1 -0
- package/package.json +1 -2
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { config, findAreaByLocation, getBotStrings, getUser, isValidLanguage, resolveCityIds, saveUser, translateAreas, } from "@easyoref/shared";
|
|
2
|
+
import * as logger from "@easyoref/shared/logger";
|
|
3
|
+
import { InlineKeyboard, Keyboard } from "grammy";
|
|
4
|
+
/** Default areas from config city_ids (resolved at startup via initTranslations) */
|
|
5
|
+
let defaultAreas = [];
|
|
6
|
+
export function initDefaultAreas() {
|
|
7
|
+
if (config.cityIds.length > 0) {
|
|
8
|
+
defaultAreas = resolveCityIds(config.cityIds);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function getDefaultAreas() {
|
|
12
|
+
return defaultAreas.length > 0
|
|
13
|
+
? defaultAreas
|
|
14
|
+
: ["תל אביב - דרום העיר ויפו"];
|
|
15
|
+
}
|
|
16
|
+
/** Persistent reply keyboard shown after registration */
|
|
17
|
+
export function mainMenuKeyboard(lang) {
|
|
18
|
+
const s = getBotStrings(lang);
|
|
19
|
+
return new Keyboard()
|
|
20
|
+
.text(s.btnShelter)
|
|
21
|
+
.text(s.btnSettings)
|
|
22
|
+
.resized()
|
|
23
|
+
.persistent();
|
|
24
|
+
}
|
|
25
|
+
/** Track users who are currently in the "send location for area" flow */
|
|
26
|
+
const awaitingLocation = new Set();
|
|
27
|
+
/** Mark a chatId as awaiting location (used by settings handler too) */
|
|
28
|
+
export function setAwaitingLocation(chatId) {
|
|
29
|
+
awaitingLocation.add(chatId);
|
|
30
|
+
}
|
|
31
|
+
const langKeyboard = new InlineKeyboard()
|
|
32
|
+
.text("🇷🇺 Русский", "lang:ru")
|
|
33
|
+
.text("🇬🇧 English", "lang:en")
|
|
34
|
+
.row()
|
|
35
|
+
.text("🇮🇱 עברית", "lang:he")
|
|
36
|
+
.text("🇸🇦 العربية", "lang:ar");
|
|
37
|
+
/**
|
|
38
|
+
* Interactive /start onboarding:
|
|
39
|
+
* 1. Show welcome + language inline keyboard
|
|
40
|
+
* 2. User picks language → ask for location (reply keyboard with 📍)
|
|
41
|
+
* 3. User sends location → detect area via polygon → save → confirm
|
|
42
|
+
* 4. Or user skips → use default area → save → confirm
|
|
43
|
+
*
|
|
44
|
+
* In groups: /start [lang] — simple registration (no interactive flow).
|
|
45
|
+
*/
|
|
46
|
+
export function registerStartHandler(bot) {
|
|
47
|
+
// ── /start command ──────────────────────────────────
|
|
48
|
+
bot.command("start", async (ctx) => {
|
|
49
|
+
const chatId = String(ctx.chat.id);
|
|
50
|
+
// Groups: simple registration with optional lang arg
|
|
51
|
+
if (ctx.chat.type !== "private") {
|
|
52
|
+
const args = ctx.match?.trim();
|
|
53
|
+
let lang = "ru";
|
|
54
|
+
if (args && isValidLanguage(args))
|
|
55
|
+
lang = args;
|
|
56
|
+
const areas = getDefaultAreas();
|
|
57
|
+
const existing = await getUser(chatId);
|
|
58
|
+
const user = {
|
|
59
|
+
chatId,
|
|
60
|
+
language: lang,
|
|
61
|
+
areas,
|
|
62
|
+
tier: existing?.tier ?? "free",
|
|
63
|
+
registeredAt: existing?.registeredAt ?? Date.now(),
|
|
64
|
+
lastActiveAt: Date.now(),
|
|
65
|
+
};
|
|
66
|
+
await saveUser(user);
|
|
67
|
+
const s = getBotStrings(lang);
|
|
68
|
+
const translatedAreas = translateAreas(areas.join(", "), lang);
|
|
69
|
+
await ctx.reply(s.registered
|
|
70
|
+
.replace("{lang}", lang)
|
|
71
|
+
.replace("{areas}", translatedAreas), { parse_mode: "HTML" });
|
|
72
|
+
logger.info("Group registered via /start", { chatId, lang });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Private: interactive flow — show language picker
|
|
76
|
+
await ctx.reply(getBotStrings("ru").welcome, {
|
|
77
|
+
reply_markup: langKeyboard,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
// ── Language selection callback ─────────────────────
|
|
81
|
+
bot.callbackQuery(/^lang:/, async (ctx) => {
|
|
82
|
+
const lang = ctx.callbackQuery.data.slice(5);
|
|
83
|
+
if (!isValidLanguage(lang)) {
|
|
84
|
+
await ctx.answerCallbackQuery("Invalid language");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const chatId = String(ctx.from.id);
|
|
88
|
+
await ctx.answerCallbackQuery();
|
|
89
|
+
// Save language choice temporarily — full save after location
|
|
90
|
+
const existing = await getUser(chatId);
|
|
91
|
+
const s = getBotStrings(lang);
|
|
92
|
+
if (existing) {
|
|
93
|
+
// Returning user changing language via /start
|
|
94
|
+
await saveUser({ ...existing, language: lang, lastActiveAt: Date.now() });
|
|
95
|
+
}
|
|
96
|
+
// Remove inline keyboard from welcome message
|
|
97
|
+
await ctx.editMessageReplyMarkup({ reply_markup: undefined }).catch(() => { });
|
|
98
|
+
// Ask for location
|
|
99
|
+
const locationKb = new Keyboard()
|
|
100
|
+
.requestLocation(s.shareLocationBtn)
|
|
101
|
+
.row()
|
|
102
|
+
.text(s.skipLocationBtn)
|
|
103
|
+
.resized()
|
|
104
|
+
.oneTime();
|
|
105
|
+
await ctx.reply(s.askLocation, { reply_markup: locationKb });
|
|
106
|
+
// Mark user as awaiting location for area detection
|
|
107
|
+
awaitingLocation.add(chatId);
|
|
108
|
+
// Store pending language in a lightweight way (callback data prefix)
|
|
109
|
+
// We'll read it back from the user record or fallback to what we just set
|
|
110
|
+
if (!existing) {
|
|
111
|
+
// Pre-create user with default areas, will update on location
|
|
112
|
+
const user = {
|
|
113
|
+
chatId,
|
|
114
|
+
language: lang,
|
|
115
|
+
areas: getDefaultAreas(),
|
|
116
|
+
tier: "free",
|
|
117
|
+
registeredAt: Date.now(),
|
|
118
|
+
lastActiveAt: Date.now(),
|
|
119
|
+
};
|
|
120
|
+
await saveUser(user);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
// ── Location received (onboarding or settings) ─────
|
|
124
|
+
bot.on("message:location", async (ctx, next) => {
|
|
125
|
+
const chatId = String(ctx.chat.id);
|
|
126
|
+
// Only handle if user is in "awaiting location for area" flow
|
|
127
|
+
if (!awaitingLocation.has(chatId)) {
|
|
128
|
+
await next();
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
awaitingLocation.delete(chatId);
|
|
132
|
+
const user = await getUser(chatId);
|
|
133
|
+
if (!user) {
|
|
134
|
+
await next();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const { latitude, longitude } = ctx.message.location;
|
|
138
|
+
const detectedArea = findAreaByLocation(latitude, longitude);
|
|
139
|
+
const lang = user.language;
|
|
140
|
+
const s = getBotStrings(lang);
|
|
141
|
+
let areas;
|
|
142
|
+
if (detectedArea) {
|
|
143
|
+
areas = [detectedArea];
|
|
144
|
+
const translatedArea = translateAreas(detectedArea, lang);
|
|
145
|
+
await ctx.reply(s.areaDetected.replace("{area}", translatedArea));
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
areas = getDefaultAreas();
|
|
149
|
+
await ctx.reply(s.areaNotDetected);
|
|
150
|
+
}
|
|
151
|
+
await saveUser({ ...user, areas, lastActiveAt: Date.now() });
|
|
152
|
+
const translatedAreas = translateAreas(areas.join(", "), lang);
|
|
153
|
+
await ctx.reply(s.registered.replace("{lang}", lang).replace("{areas}", translatedAreas), { parse_mode: "HTML", reply_markup: mainMenuKeyboard(lang) });
|
|
154
|
+
logger.info("User area updated via location", {
|
|
155
|
+
chatId,
|
|
156
|
+
areas,
|
|
157
|
+
detected: !!detectedArea,
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
// ── "Skip" button handler ──────────────────────────
|
|
161
|
+
bot.hears([
|
|
162
|
+
getBotStrings("ru").skipLocationBtn,
|
|
163
|
+
getBotStrings("en").skipLocationBtn,
|
|
164
|
+
getBotStrings("he").skipLocationBtn,
|
|
165
|
+
getBotStrings("ar").skipLocationBtn,
|
|
166
|
+
], async (ctx) => {
|
|
167
|
+
const chatId = String(ctx.chat.id);
|
|
168
|
+
const user = await getUser(chatId);
|
|
169
|
+
if (!user)
|
|
170
|
+
return;
|
|
171
|
+
const lang = user.language;
|
|
172
|
+
const s = getBotStrings(lang);
|
|
173
|
+
const areas = getDefaultAreas();
|
|
174
|
+
await saveUser({ ...user, areas, lastActiveAt: Date.now() });
|
|
175
|
+
const translatedAreas = translateAreas(areas.join(", "), lang);
|
|
176
|
+
await ctx.reply(s.registered
|
|
177
|
+
.replace("{lang}", lang)
|
|
178
|
+
.replace("{areas}", translatedAreas), { parse_mode: "HTML", reply_markup: mainMenuKeyboard(lang) });
|
|
179
|
+
logger.info("User skipped location, using defaults", { chatId, areas });
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/handlers/start.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Context, NextFunction } from "grammy";
|
|
2
|
+
/**
|
|
3
|
+
* Middleware that requires the user to have a "pro" tier.
|
|
4
|
+
* Replies with an upgrade prompt and stops the handler chain for free users.
|
|
5
|
+
*/
|
|
6
|
+
export declare function requirePro(ctx: Context, next: NextFunction): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=tier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tier.d.ts","sourceRoot":"","sources":["../../src/middleware/tier.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEpD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CASf"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getUser } from "@easyoref/shared";
|
|
2
|
+
/**
|
|
3
|
+
* Middleware that requires the user to have a "pro" tier.
|
|
4
|
+
* Replies with an upgrade prompt and stops the handler chain for free users.
|
|
5
|
+
*/
|
|
6
|
+
export async function requirePro(ctx, next) {
|
|
7
|
+
const chatId = String(ctx.chat?.id ?? "");
|
|
8
|
+
if (!chatId)
|
|
9
|
+
return;
|
|
10
|
+
const user = await getUser(chatId);
|
|
11
|
+
if (user?.tier !== "pro") {
|
|
12
|
+
await ctx.reply("This feature requires Pro tier. Contact the bot admin.");
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
return next();
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=tier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tier.js","sourceRoot":"","sources":["../../src/middleware/tier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAG3C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,GAAY,EACZ,IAAkB;IAElB,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,IAAI,EAAE,IAAI,KAAK,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;QAC1E,OAAO;IACT,CAAC;IACD,OAAO,IAAI,EAAE,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "easyoref",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Real-time Israeli civil defense alerts → Telegram, filtered by your location",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
"js-yaml": "^4.1.1",
|
|
38
38
|
"qrcode-terminal": "^0.12.0",
|
|
39
39
|
"@easyoref/shared": "*",
|
|
40
|
-
"@easyoref/monitoring": "*",
|
|
41
40
|
"@easyoref/agent": "*",
|
|
42
41
|
"@easyoref/gramjs": "*"
|
|
43
42
|
},
|