@overpod/mcp-telegram 1.26.0 → 1.26.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/index.js +4 -1
- package/dist/rate-limiter.d.ts +1 -1
- package/dist/rate-limiter.js +8 -8
- package/dist/telegram-client.d.ts +6 -470
- package/dist/telegram-client.js +17 -874
- package/dist/telegram-helpers.d.ts +470 -0
- package/dist/telegram-helpers.js +870 -0
- package/dist/tools/account.js +7 -7
- package/dist/tools/boosts.js +4 -4
- package/dist/tools/chats.js +7 -7
- package/dist/tools/contacts.js +3 -3
- package/dist/tools/extras.js +3 -3
- package/dist/tools/group-calls.js +3 -3
- package/dist/tools/messages.js +17 -17
- package/dist/tools/quick-replies.js +3 -3
- package/dist/tools/reactions.js +2 -2
- package/dist/tools/shared.d.ts +3 -3
- package/dist/tools/shared.js +8 -7
- package/dist/tools/stars.js +3 -3
- package/dist/tools/stickers.js +5 -5
- package/dist/tools/stories.js +5 -5
- package/package.json +1 -1
- package/dist/__tests__/admin-log.test.d.ts +0 -1
- package/dist/__tests__/admin-log.test.js +0 -41
- package/dist/__tests__/approve-join-request.test.d.ts +0 -1
- package/dist/__tests__/approve-join-request.test.js +0 -107
- package/dist/__tests__/boosts.test.d.ts +0 -1
- package/dist/__tests__/boosts.test.js +0 -310
- package/dist/__tests__/broadcast-stats.test.d.ts +0 -1
- package/dist/__tests__/broadcast-stats.test.js +0 -172
- package/dist/__tests__/business-chat-links.test.d.ts +0 -1
- package/dist/__tests__/business-chat-links.test.js +0 -102
- package/dist/__tests__/get-message-buttons.test.d.ts +0 -1
- package/dist/__tests__/get-message-buttons.test.js +0 -122
- package/dist/__tests__/group-calls.test.d.ts +0 -1
- package/dist/__tests__/group-calls.test.js +0 -503
- package/dist/__tests__/inline-query-send.test.d.ts +0 -1
- package/dist/__tests__/inline-query-send.test.js +0 -94
- package/dist/__tests__/inline-query.test.d.ts +0 -1
- package/dist/__tests__/inline-query.test.js +0 -115
- package/dist/__tests__/megagroup-stats.test.d.ts +0 -1
- package/dist/__tests__/megagroup-stats.test.js +0 -166
- package/dist/__tests__/press-button.test.d.ts +0 -1
- package/dist/__tests__/press-button.test.js +0 -123
- package/dist/__tests__/quick-replies.test.d.ts +0 -1
- package/dist/__tests__/quick-replies.test.js +0 -245
- package/dist/__tests__/rate-limiter.test.d.ts +0 -1
- package/dist/__tests__/rate-limiter.test.js +0 -81
- package/dist/__tests__/reactions.test.d.ts +0 -1
- package/dist/__tests__/reactions.test.js +0 -23
- package/dist/__tests__/set-chat-permissions-merge.test.d.ts +0 -1
- package/dist/__tests__/set-chat-permissions-merge.test.js +0 -107
- package/dist/__tests__/set-chat-reactions.test.d.ts +0 -1
- package/dist/__tests__/set-chat-reactions.test.js +0 -129
- package/dist/__tests__/stars-status.test.d.ts +0 -1
- package/dist/__tests__/stars-status.test.js +0 -205
- package/dist/__tests__/stars-transactions.test.d.ts +0 -1
- package/dist/__tests__/stars-transactions.test.js +0 -82
- package/dist/__tests__/stories.test.d.ts +0 -1
- package/dist/__tests__/stories.test.js +0 -361
- package/dist/__tests__/toggle-anti-spam.test.d.ts +0 -1
- package/dist/__tests__/toggle-anti-spam.test.js +0 -80
- package/dist/__tests__/toggle-channel-signatures.test.d.ts +0 -1
- package/dist/__tests__/toggle-channel-signatures.test.js +0 -80
- package/dist/__tests__/toggle-forum-mode.test.d.ts +0 -1
- package/dist/__tests__/toggle-forum-mode.test.js +0 -80
- package/dist/__tests__/toggle-prehistory-hidden.test.d.ts +0 -1
- package/dist/__tests__/toggle-prehistory-hidden.test.js +0 -80
- package/dist/__tests__/tools/shared.test.d.ts +0 -1
- package/dist/__tests__/tools/shared.test.js +0 -110
- package/dist/__tests__/updates.test.d.ts +0 -1
- package/dist/__tests__/updates.test.js +0 -221
package/dist/telegram-client.js
CHANGED
|
@@ -10,6 +10,8 @@ import { CustomFile } from "telegram/client/uploads.js";
|
|
|
10
10
|
import { StringSession } from "telegram/sessions/index.js";
|
|
11
11
|
import { Api } from "telegram/tl/index.js";
|
|
12
12
|
import { RateLimiter } from "./rate-limiter.js";
|
|
13
|
+
import { describeAdminLogAction, describeAdminLogDetails, describeKeyboardButton, mergeBannedRights, reactionToEmoji, summarizeAllStories, summarizeBoostsList, summarizeBoostsStatus, summarizeBroadcastStats, summarizeBusinessChatLinks, summarizeChannelDifference, summarizeGroupCall, summarizeGroupCallParticipants, summarizeMegagroupStats, summarizeMyBoosts, summarizePeerStories, summarizeQuickReplies, summarizeQuickReplyMessages, summarizeStarsStatus, summarizeStoriesById, summarizeStoryViewsList, summarizeUpdatesDifference, } from "./telegram-helpers.js";
|
|
14
|
+
export { describeAdminLogAction, describeAdminLogDetails, describeKeyboardButton, mergeBannedRights, peerToCompact, reactionToEmoji, summarizeAllStories, summarizeBoost, summarizeBoostsList, summarizeBoostsStatus, summarizeBroadcastStats, summarizeBusinessChatLink, summarizeBusinessChatLinks, summarizeChannelDifference, summarizeGroupCall, summarizeGroupCallInfo, summarizeGroupCallParticipant, summarizeGroupCallParticipants, summarizeMegagroupStats, summarizeMyBoost, summarizeMyBoosts, summarizePeerStories, summarizePrepaidGiveaway, summarizeQuickReplies, summarizeQuickReply, summarizeQuickReplyMessage, summarizeQuickReplyMessages, summarizeStarsAmount, summarizeStarsStatus, summarizeStarsSubscription, summarizeStarsTransaction, summarizeStarsTransactionPeer, summarizeStoriesById, summarizeStoryItem, summarizeStoryView, summarizeStoryViewsList, summarizeUpdatesDifference, } from "./telegram-helpers.js";
|
|
13
15
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
16
|
const LEGACY_SESSION_FILE = join(__dirname, "..", ".telegram-session");
|
|
15
17
|
const DEFAULT_SESSION_DIR = join(homedir(), ".mcp-telegram");
|
|
@@ -44,875 +46,6 @@ function ensureSessionDir(filePath) {
|
|
|
44
46
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
|
-
export function describeAdminLogAction(action) {
|
|
48
|
-
const prefix = "ChannelAdminLogEventAction";
|
|
49
|
-
const raw = action.className.startsWith(prefix) ? action.className.slice(prefix.length) : action.className;
|
|
50
|
-
return raw
|
|
51
|
-
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
|
|
52
|
-
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
53
|
-
.toLowerCase();
|
|
54
|
-
}
|
|
55
|
-
export function describeAdminLogDetails(action, describeUser) {
|
|
56
|
-
if (action instanceof Api.ChannelAdminLogEventActionChangeTitle) {
|
|
57
|
-
return `"${action.prevValue}" → "${action.newValue}"`;
|
|
58
|
-
}
|
|
59
|
-
if (action instanceof Api.ChannelAdminLogEventActionChangeAbout) {
|
|
60
|
-
return `description changed`;
|
|
61
|
-
}
|
|
62
|
-
if (action instanceof Api.ChannelAdminLogEventActionChangeUsername) {
|
|
63
|
-
return `@${action.prevValue || "-"} → @${action.newValue || "-"}`;
|
|
64
|
-
}
|
|
65
|
-
if (action instanceof Api.ChannelAdminLogEventActionUpdatePinned) {
|
|
66
|
-
return `message #${action.message instanceof Api.Message ? action.message.id : "?"}`;
|
|
67
|
-
}
|
|
68
|
-
if (action instanceof Api.ChannelAdminLogEventActionEditMessage) {
|
|
69
|
-
return `message #${action.newMessage instanceof Api.Message ? action.newMessage.id : "?"}`;
|
|
70
|
-
}
|
|
71
|
-
if (action instanceof Api.ChannelAdminLogEventActionDeleteMessage) {
|
|
72
|
-
return `message #${action.message instanceof Api.Message ? action.message.id : "?"}`;
|
|
73
|
-
}
|
|
74
|
-
if (action instanceof Api.ChannelAdminLogEventActionParticipantInvite) {
|
|
75
|
-
const p = action.participant;
|
|
76
|
-
return `invited user ${"userId" in p ? describeUser(p.userId) : "?"}`;
|
|
77
|
-
}
|
|
78
|
-
if (action instanceof Api.ChannelAdminLogEventActionParticipantToggleBan) {
|
|
79
|
-
const p = action.newParticipant;
|
|
80
|
-
if (p instanceof Api.ChannelParticipantBanned) {
|
|
81
|
-
const uid = p.peer instanceof Api.PeerUser ? p.peer.userId : undefined;
|
|
82
|
-
return `banned user ${uid ? describeUser(uid) : "?"}`;
|
|
83
|
-
}
|
|
84
|
-
return `unbanned user ${"userId" in p ? describeUser(p.userId) : "?"}`;
|
|
85
|
-
}
|
|
86
|
-
if (action instanceof Api.ChannelAdminLogEventActionParticipantToggleAdmin) {
|
|
87
|
-
const p = action.newParticipant;
|
|
88
|
-
return `admin rights changed for ${"userId" in p ? describeUser(p.userId) : "?"}`;
|
|
89
|
-
}
|
|
90
|
-
if (action instanceof Api.ChannelAdminLogEventActionToggleSlowMode) {
|
|
91
|
-
return `${action.prevValue}s → ${action.newValue}s`;
|
|
92
|
-
}
|
|
93
|
-
if (action instanceof Api.ChannelAdminLogEventActionToggleInvites) {
|
|
94
|
-
return `invites ${action.newValue ? "enabled" : "disabled"}`;
|
|
95
|
-
}
|
|
96
|
-
if (action instanceof Api.ChannelAdminLogEventActionToggleSignatures) {
|
|
97
|
-
return `signatures ${action.newValue ? "enabled" : "disabled"}`;
|
|
98
|
-
}
|
|
99
|
-
if (action instanceof Api.ChannelAdminLogEventActionTogglePreHistoryHidden) {
|
|
100
|
-
return `pre-history hidden: ${action.newValue}`;
|
|
101
|
-
}
|
|
102
|
-
if (action instanceof Api.ChannelAdminLogEventActionChangeHistoryTTL) {
|
|
103
|
-
return `${action.prevValue}s → ${action.newValue}s`;
|
|
104
|
-
}
|
|
105
|
-
if (action instanceof Api.ChannelAdminLogEventActionChangeStickerSet) {
|
|
106
|
-
return `sticker set changed`;
|
|
107
|
-
}
|
|
108
|
-
if (action instanceof Api.ChannelAdminLogEventActionChangeLinkedChat) {
|
|
109
|
-
return `${action.prevValue.toString()} → ${action.newValue.toString()}`;
|
|
110
|
-
}
|
|
111
|
-
if (action instanceof Api.ChannelAdminLogEventActionStopPoll) {
|
|
112
|
-
return `poll in message #${action.message instanceof Api.Message ? action.message.id : "?"}`;
|
|
113
|
-
}
|
|
114
|
-
if (action instanceof Api.ChannelAdminLogEventActionSendMessage) {
|
|
115
|
-
return `message #${action.message instanceof Api.Message ? action.message.id : "?"}`;
|
|
116
|
-
}
|
|
117
|
-
if (action instanceof Api.ChannelAdminLogEventActionCreateTopic) {
|
|
118
|
-
return `topic "${action.topic instanceof Api.ForumTopic ? action.topic.title : "?"}"`;
|
|
119
|
-
}
|
|
120
|
-
if (action instanceof Api.ChannelAdminLogEventActionDeleteTopic) {
|
|
121
|
-
return `topic "${action.topic instanceof Api.ForumTopic ? action.topic.title : "?"}"`;
|
|
122
|
-
}
|
|
123
|
-
if (action instanceof Api.ChannelAdminLogEventActionEditTopic) {
|
|
124
|
-
return `topic "${action.newTopic instanceof Api.ForumTopic ? action.newTopic.title : "?"}"`;
|
|
125
|
-
}
|
|
126
|
-
return "";
|
|
127
|
-
}
|
|
128
|
-
export function reactionToEmoji(reaction) {
|
|
129
|
-
if (reaction instanceof Api.ReactionEmoji)
|
|
130
|
-
return reaction.emoticon;
|
|
131
|
-
if (reaction instanceof Api.ReactionCustomEmoji)
|
|
132
|
-
return `custom:${reaction.documentId.toString()}`;
|
|
133
|
-
if (reaction instanceof Api.ReactionPaid)
|
|
134
|
-
return "⭐";
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
function absValue(v) {
|
|
138
|
-
return { current: v?.current ?? 0, previous: v?.previous ?? 0 };
|
|
139
|
-
}
|
|
140
|
-
function compactGraph(g) {
|
|
141
|
-
if (g instanceof Api.StatsGraphAsync)
|
|
142
|
-
return { type: "async", token: g.token };
|
|
143
|
-
if (g instanceof Api.StatsGraphError)
|
|
144
|
-
return { type: "error", error: g.error };
|
|
145
|
-
if (g instanceof Api.StatsGraph) {
|
|
146
|
-
let parsed = g.json?.data;
|
|
147
|
-
if (typeof parsed === "string") {
|
|
148
|
-
try {
|
|
149
|
-
parsed = JSON.parse(parsed);
|
|
150
|
-
}
|
|
151
|
-
catch {
|
|
152
|
-
// leave raw string
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return { type: "data", data: parsed, zoomToken: g.zoomToken };
|
|
156
|
-
}
|
|
157
|
-
const any = g;
|
|
158
|
-
if (typeof any.token === "string")
|
|
159
|
-
return { type: "async", token: any.token };
|
|
160
|
-
if (typeof any.error === "string")
|
|
161
|
-
return { type: "error", error: any.error };
|
|
162
|
-
return { type: "data", data: any.json?.data, zoomToken: any.zoomToken };
|
|
163
|
-
}
|
|
164
|
-
export function summarizeMegagroupStats(stats, includeGraphs) {
|
|
165
|
-
const summary = {
|
|
166
|
-
period: {
|
|
167
|
-
minDate: stats.period?.minDate ?? 0,
|
|
168
|
-
maxDate: stats.period?.maxDate ?? 0,
|
|
169
|
-
},
|
|
170
|
-
members: absValue(stats.members),
|
|
171
|
-
messages: absValue(stats.messages),
|
|
172
|
-
viewers: absValue(stats.viewers),
|
|
173
|
-
posters: absValue(stats.posters),
|
|
174
|
-
topPosters: (stats.topPosters ?? []).map((p) => ({
|
|
175
|
-
userId: p.userId?.toString() ?? "",
|
|
176
|
-
messages: p.messages,
|
|
177
|
-
avgChars: p.avgChars,
|
|
178
|
-
})),
|
|
179
|
-
topAdmins: (stats.topAdmins ?? []).map((a) => ({
|
|
180
|
-
userId: a.userId?.toString() ?? "",
|
|
181
|
-
deleted: a.deleted,
|
|
182
|
-
kicked: a.kicked,
|
|
183
|
-
banned: a.banned,
|
|
184
|
-
})),
|
|
185
|
-
topInviters: (stats.topInviters ?? []).map((i) => ({
|
|
186
|
-
userId: i.userId?.toString() ?? "",
|
|
187
|
-
invitations: i.invitations,
|
|
188
|
-
})),
|
|
189
|
-
};
|
|
190
|
-
if (includeGraphs) {
|
|
191
|
-
summary.graphs = {
|
|
192
|
-
growth: compactGraph(stats.growthGraph),
|
|
193
|
-
members: compactGraph(stats.membersGraph),
|
|
194
|
-
newMembersBySource: compactGraph(stats.newMembersBySourceGraph),
|
|
195
|
-
languages: compactGraph(stats.languagesGraph),
|
|
196
|
-
messages: compactGraph(stats.messagesGraph),
|
|
197
|
-
actions: compactGraph(stats.actionsGraph),
|
|
198
|
-
topHours: compactGraph(stats.topHoursGraph),
|
|
199
|
-
weekdays: compactGraph(stats.weekdaysGraph),
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
return summary;
|
|
203
|
-
}
|
|
204
|
-
export function summarizeBroadcastStats(stats, includeGraphs) {
|
|
205
|
-
const enabled = stats.enabledNotifications;
|
|
206
|
-
const part = enabled?.part ?? 0;
|
|
207
|
-
const total = enabled?.total ?? 0;
|
|
208
|
-
const percent = total > 0 ? (part / total) * 100 : 0;
|
|
209
|
-
const summary = {
|
|
210
|
-
period: {
|
|
211
|
-
minDate: stats.period?.minDate ?? 0,
|
|
212
|
-
maxDate: stats.period?.maxDate ?? 0,
|
|
213
|
-
},
|
|
214
|
-
followers: absValue(stats.followers),
|
|
215
|
-
viewsPerPost: absValue(stats.viewsPerPost),
|
|
216
|
-
sharesPerPost: absValue(stats.sharesPerPost),
|
|
217
|
-
reactionsPerPost: absValue(stats.reactionsPerPost),
|
|
218
|
-
viewsPerStory: absValue(stats.viewsPerStory),
|
|
219
|
-
sharesPerStory: absValue(stats.sharesPerStory),
|
|
220
|
-
reactionsPerStory: absValue(stats.reactionsPerStory),
|
|
221
|
-
enabledNotifications: { part, total, percent },
|
|
222
|
-
recentPostsInteractions: (stats.recentPostsInteractions ?? []).map((p) => {
|
|
223
|
-
if (p instanceof Api.PostInteractionCountersStory) {
|
|
224
|
-
return {
|
|
225
|
-
kind: "story",
|
|
226
|
-
storyId: p.storyId,
|
|
227
|
-
views: p.views,
|
|
228
|
-
forwards: p.forwards,
|
|
229
|
-
reactions: p.reactions,
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
const m = p;
|
|
233
|
-
return {
|
|
234
|
-
kind: "message",
|
|
235
|
-
msgId: m.msgId,
|
|
236
|
-
views: m.views,
|
|
237
|
-
forwards: m.forwards,
|
|
238
|
-
reactions: m.reactions,
|
|
239
|
-
};
|
|
240
|
-
}),
|
|
241
|
-
};
|
|
242
|
-
if (includeGraphs) {
|
|
243
|
-
summary.graphs = {
|
|
244
|
-
growth: compactGraph(stats.growthGraph),
|
|
245
|
-
followers: compactGraph(stats.followersGraph),
|
|
246
|
-
mute: compactGraph(stats.muteGraph),
|
|
247
|
-
topHours: compactGraph(stats.topHoursGraph),
|
|
248
|
-
interactions: compactGraph(stats.interactionsGraph),
|
|
249
|
-
ivInteractions: compactGraph(stats.ivInteractionsGraph),
|
|
250
|
-
viewsBySource: compactGraph(stats.viewsBySourceGraph),
|
|
251
|
-
newFollowersBySource: compactGraph(stats.newFollowersBySourceGraph),
|
|
252
|
-
languages: compactGraph(stats.languagesGraph),
|
|
253
|
-
reactionsByEmotion: compactGraph(stats.reactionsByEmotionGraph),
|
|
254
|
-
storyInteractions: compactGraph(stats.storyInteractionsGraph),
|
|
255
|
-
storyReactionsByEmotion: compactGraph(stats.storyReactionsByEmotionGraph),
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
return summary;
|
|
259
|
-
}
|
|
260
|
-
const BANNED_RIGHT_FLAGS = [
|
|
261
|
-
"sendMessages",
|
|
262
|
-
"sendMedia",
|
|
263
|
-
"sendStickers",
|
|
264
|
-
"sendGifs",
|
|
265
|
-
"sendPolls",
|
|
266
|
-
"sendInline",
|
|
267
|
-
"embedLinks",
|
|
268
|
-
"changeInfo",
|
|
269
|
-
"inviteUsers",
|
|
270
|
-
"pinMessages",
|
|
271
|
-
];
|
|
272
|
-
// Newer granular flags not exposed in ChatPermissions input but must be preserved from currentRights
|
|
273
|
-
const EXTRA_BANNED_RIGHT_FLAGS = [
|
|
274
|
-
"sendGames",
|
|
275
|
-
"manageTopics",
|
|
276
|
-
"sendPhotos",
|
|
277
|
-
"sendVideos",
|
|
278
|
-
"sendRoundvideos",
|
|
279
|
-
"sendAudios",
|
|
280
|
-
"sendVoices",
|
|
281
|
-
"sendDocs",
|
|
282
|
-
"sendPlain",
|
|
283
|
-
];
|
|
284
|
-
export function mergeBannedRights(current, permissions) {
|
|
285
|
-
const result = {};
|
|
286
|
-
for (const flag of BANNED_RIGHT_FLAGS) {
|
|
287
|
-
const userValue = permissions[flag];
|
|
288
|
-
if (userValue !== undefined) {
|
|
289
|
-
result[flag] = !userValue;
|
|
290
|
-
}
|
|
291
|
-
else {
|
|
292
|
-
result[flag] = Boolean(current?.[flag]);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
// Preserve newer granular flags from existing rights so they are not silently cleared
|
|
296
|
-
for (const flag of EXTRA_BANNED_RIGHT_FLAGS) {
|
|
297
|
-
result[flag] = Boolean(current?.[flag]);
|
|
298
|
-
}
|
|
299
|
-
return result;
|
|
300
|
-
}
|
|
301
|
-
export function describeKeyboardButton(button, row, col) {
|
|
302
|
-
const base = {
|
|
303
|
-
row,
|
|
304
|
-
col,
|
|
305
|
-
type: button.className,
|
|
306
|
-
label: "text" in button && typeof button.text === "string" ? button.text : "",
|
|
307
|
-
};
|
|
308
|
-
if (button instanceof Api.KeyboardButtonCallback) {
|
|
309
|
-
base.data = Buffer.from(button.data).toString("base64");
|
|
310
|
-
if (button.requiresPassword)
|
|
311
|
-
base.requiresPassword = true;
|
|
312
|
-
return base;
|
|
313
|
-
}
|
|
314
|
-
if (button instanceof Api.KeyboardButtonUrl) {
|
|
315
|
-
base.url = button.url;
|
|
316
|
-
return base;
|
|
317
|
-
}
|
|
318
|
-
if (button instanceof Api.KeyboardButtonUrlAuth) {
|
|
319
|
-
base.url = button.url;
|
|
320
|
-
base.buttonId = button.buttonId;
|
|
321
|
-
return base;
|
|
322
|
-
}
|
|
323
|
-
if (button instanceof Api.KeyboardButtonSwitchInline) {
|
|
324
|
-
base.switchQuery = button.query;
|
|
325
|
-
base.samePeer = Boolean(button.samePeer);
|
|
326
|
-
return base;
|
|
327
|
-
}
|
|
328
|
-
if (button instanceof Api.KeyboardButtonWebView || button instanceof Api.KeyboardButtonSimpleWebView) {
|
|
329
|
-
base.url = button.url;
|
|
330
|
-
return base;
|
|
331
|
-
}
|
|
332
|
-
if (button instanceof Api.KeyboardButtonUserProfile) {
|
|
333
|
-
base.userId = button.userId?.toString();
|
|
334
|
-
return base;
|
|
335
|
-
}
|
|
336
|
-
if (button instanceof Api.KeyboardButtonRequestPoll) {
|
|
337
|
-
if (button.quiz)
|
|
338
|
-
base.quiz = true;
|
|
339
|
-
return base;
|
|
340
|
-
}
|
|
341
|
-
if (button instanceof Api.KeyboardButtonRequestPeer) {
|
|
342
|
-
base.buttonId = button.buttonId;
|
|
343
|
-
return base;
|
|
344
|
-
}
|
|
345
|
-
if (button instanceof Api.KeyboardButtonCopy) {
|
|
346
|
-
base.copyText = button.copyText;
|
|
347
|
-
return base;
|
|
348
|
-
}
|
|
349
|
-
return base;
|
|
350
|
-
}
|
|
351
|
-
export function peerToCompact(peer) {
|
|
352
|
-
if (!peer)
|
|
353
|
-
return undefined;
|
|
354
|
-
if (peer instanceof Api.PeerUser)
|
|
355
|
-
return { kind: "user", id: peer.userId.toString() };
|
|
356
|
-
if (peer instanceof Api.PeerChat)
|
|
357
|
-
return { kind: "chat", id: peer.chatId.toString() };
|
|
358
|
-
if (peer instanceof Api.PeerChannel)
|
|
359
|
-
return { kind: "channel", id: peer.channelId.toString() };
|
|
360
|
-
return undefined;
|
|
361
|
-
}
|
|
362
|
-
function summarizeMessageForUpdates(msg) {
|
|
363
|
-
if (msg instanceof Api.MessageEmpty)
|
|
364
|
-
return null;
|
|
365
|
-
const peer = peerToCompact(msg.peerId);
|
|
366
|
-
if (!peer)
|
|
367
|
-
return null;
|
|
368
|
-
const fromId = peerToCompact(msg.fromId);
|
|
369
|
-
const date = msg.date ?? 0;
|
|
370
|
-
if (msg instanceof Api.Message) {
|
|
371
|
-
return { id: msg.id, peer, fromId, date, text: msg.message ?? "", isService: false };
|
|
372
|
-
}
|
|
373
|
-
if (msg instanceof Api.MessageService) {
|
|
374
|
-
return {
|
|
375
|
-
id: msg.id,
|
|
376
|
-
peer,
|
|
377
|
-
fromId,
|
|
378
|
-
date,
|
|
379
|
-
text: `[${msg.action?.className ?? "service"}]`,
|
|
380
|
-
isService: true,
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
return null;
|
|
384
|
-
}
|
|
385
|
-
function collectDeletedMessageIds(updates) {
|
|
386
|
-
const out = [];
|
|
387
|
-
for (const u of updates) {
|
|
388
|
-
if (u instanceof Api.UpdateDeleteMessages) {
|
|
389
|
-
out.push({ messageIds: u.messages });
|
|
390
|
-
}
|
|
391
|
-
else if (u instanceof Api.UpdateDeleteChannelMessages) {
|
|
392
|
-
out.push({
|
|
393
|
-
peer: { kind: "channel", id: u.channelId.toString() },
|
|
394
|
-
messageIds: u.messages,
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
return out;
|
|
399
|
-
}
|
|
400
|
-
export function summarizeUpdatesDifference(diff, cursor) {
|
|
401
|
-
if (diff instanceof Api.updates.DifferenceEmpty) {
|
|
402
|
-
return {
|
|
403
|
-
state: { pts: cursor.pts, qts: cursor.qts, date: diff.date, seq: diff.seq },
|
|
404
|
-
isFinal: true,
|
|
405
|
-
newMessages: [],
|
|
406
|
-
deletedMessageIds: [],
|
|
407
|
-
otherUpdates: [],
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
if (diff instanceof Api.updates.DifferenceTooLong) {
|
|
411
|
-
return {
|
|
412
|
-
state: { pts: diff.pts, qts: cursor.qts, date: cursor.date, seq: 0 },
|
|
413
|
-
isFinal: true,
|
|
414
|
-
newMessages: [],
|
|
415
|
-
deletedMessageIds: [],
|
|
416
|
-
otherUpdates: [],
|
|
417
|
-
fallback: {
|
|
418
|
-
kind: "tooLong",
|
|
419
|
-
suggestedAction: "gap too large — call telegram-read-messages per chat or telegram-get-state to resync",
|
|
420
|
-
},
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
const isFinal = diff instanceof Api.updates.Difference;
|
|
424
|
-
const state = isFinal
|
|
425
|
-
? diff.state
|
|
426
|
-
: diff.intermediateState;
|
|
427
|
-
const newMessages = (diff.newMessages ?? [])
|
|
428
|
-
.map(summarizeMessageForUpdates)
|
|
429
|
-
.filter((m) => m !== null);
|
|
430
|
-
const otherUpdates = diff.otherUpdates ?? [];
|
|
431
|
-
return {
|
|
432
|
-
state: {
|
|
433
|
-
pts: state.pts,
|
|
434
|
-
qts: state.qts,
|
|
435
|
-
date: state.date,
|
|
436
|
-
seq: state.seq,
|
|
437
|
-
unreadCount: state.unreadCount,
|
|
438
|
-
},
|
|
439
|
-
isFinal,
|
|
440
|
-
newMessages,
|
|
441
|
-
deletedMessageIds: collectDeletedMessageIds(otherUpdates),
|
|
442
|
-
otherUpdates: otherUpdates.map((u) => ({ type: u.className })),
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
export function summarizeChannelDifference(diff, channelId, fallbackPts) {
|
|
446
|
-
if (diff instanceof Api.updates.ChannelDifferenceEmpty) {
|
|
447
|
-
return {
|
|
448
|
-
channelId,
|
|
449
|
-
pts: diff.pts,
|
|
450
|
-
isFinal: Boolean(diff.final),
|
|
451
|
-
timeout: diff.timeout,
|
|
452
|
-
newMessages: [],
|
|
453
|
-
otherUpdates: [],
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
if (diff instanceof Api.updates.ChannelDifferenceTooLong) {
|
|
457
|
-
const freshPts = diff.dialog instanceof Api.Dialog ? (diff.dialog.pts ?? fallbackPts) : fallbackPts;
|
|
458
|
-
return {
|
|
459
|
-
channelId,
|
|
460
|
-
pts: freshPts,
|
|
461
|
-
isFinal: Boolean(diff.final),
|
|
462
|
-
timeout: diff.timeout,
|
|
463
|
-
newMessages: (diff.messages ?? [])
|
|
464
|
-
.map(summarizeMessageForUpdates)
|
|
465
|
-
.filter((m) => m !== null),
|
|
466
|
-
otherUpdates: [],
|
|
467
|
-
fallback: {
|
|
468
|
-
kind: "tooLong",
|
|
469
|
-
suggestedAction: "channel gap too large — dialog snapshot returned; call telegram-read-messages for full history",
|
|
470
|
-
},
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
if (diff instanceof Api.updates.ChannelDifference) {
|
|
474
|
-
return {
|
|
475
|
-
channelId,
|
|
476
|
-
pts: diff.pts,
|
|
477
|
-
isFinal: Boolean(diff.final),
|
|
478
|
-
timeout: diff.timeout,
|
|
479
|
-
newMessages: (diff.newMessages ?? [])
|
|
480
|
-
.map(summarizeMessageForUpdates)
|
|
481
|
-
.filter((m) => m !== null),
|
|
482
|
-
otherUpdates: (diff.otherUpdates ?? []).map((u) => ({ type: u.className })),
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
return {
|
|
486
|
-
channelId,
|
|
487
|
-
pts: fallbackPts,
|
|
488
|
-
isFinal: false,
|
|
489
|
-
newMessages: [],
|
|
490
|
-
otherUpdates: [],
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
export function summarizeMyBoost(boost) {
|
|
494
|
-
const b = boost;
|
|
495
|
-
return {
|
|
496
|
-
slot: b.slot,
|
|
497
|
-
peer: peerToCompact(b.peer),
|
|
498
|
-
date: b.date,
|
|
499
|
-
expires: b.expires,
|
|
500
|
-
cooldownUntilDate: b.cooldownUntilDate,
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
export function summarizeMyBoosts(result) {
|
|
504
|
-
const boosts = result.myBoosts ?? [];
|
|
505
|
-
return {
|
|
506
|
-
count: boosts.length,
|
|
507
|
-
myBoosts: boosts.map(summarizeMyBoost),
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
export function summarizePrepaidGiveaway(g) {
|
|
511
|
-
if (g instanceof Api.PrepaidStarsGiveaway) {
|
|
512
|
-
return {
|
|
513
|
-
kind: "stars",
|
|
514
|
-
id: g.id.toString(),
|
|
515
|
-
quantity: g.quantity,
|
|
516
|
-
date: g.date,
|
|
517
|
-
stars: g.stars.toString(),
|
|
518
|
-
boosts: g.boosts,
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
const p = g;
|
|
522
|
-
return {
|
|
523
|
-
kind: "premium",
|
|
524
|
-
id: p.id.toString(),
|
|
525
|
-
quantity: p.quantity,
|
|
526
|
-
date: p.date,
|
|
527
|
-
months: p.months,
|
|
528
|
-
};
|
|
529
|
-
}
|
|
530
|
-
export function summarizeBoostsStatus(result) {
|
|
531
|
-
const r = result;
|
|
532
|
-
const out = {
|
|
533
|
-
level: r.level,
|
|
534
|
-
boosts: r.boosts,
|
|
535
|
-
currentLevelBoosts: r.currentLevelBoosts,
|
|
536
|
-
nextLevelBoosts: r.nextLevelBoosts,
|
|
537
|
-
giftBoosts: r.giftBoosts,
|
|
538
|
-
boostUrl: r.boostUrl,
|
|
539
|
-
myBoost: r.myBoost,
|
|
540
|
-
myBoostSlots: r.myBoostSlots,
|
|
541
|
-
};
|
|
542
|
-
if (r.premiumAudience) {
|
|
543
|
-
out.premiumAudience = { part: r.premiumAudience.part, total: r.premiumAudience.total };
|
|
544
|
-
}
|
|
545
|
-
if (r.prepaidGiveaways && r.prepaidGiveaways.length > 0) {
|
|
546
|
-
out.prepaidGiveaways = r.prepaidGiveaways.map(summarizePrepaidGiveaway);
|
|
547
|
-
}
|
|
548
|
-
return out;
|
|
549
|
-
}
|
|
550
|
-
export function summarizeBoost(boost) {
|
|
551
|
-
const b = boost;
|
|
552
|
-
return {
|
|
553
|
-
id: b.id,
|
|
554
|
-
userId: b.userId?.toString(),
|
|
555
|
-
date: b.date,
|
|
556
|
-
expires: b.expires,
|
|
557
|
-
gift: b.gift,
|
|
558
|
-
giveaway: b.giveaway,
|
|
559
|
-
unclaimed: b.unclaimed,
|
|
560
|
-
giveawayMsgId: b.giveawayMsgId,
|
|
561
|
-
usedGiftSlug: b.usedGiftSlug,
|
|
562
|
-
multiplier: b.multiplier,
|
|
563
|
-
stars: b.stars?.toString(),
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
export function summarizeBoostsList(result) {
|
|
567
|
-
const r = result;
|
|
568
|
-
return {
|
|
569
|
-
count: r.count,
|
|
570
|
-
boosts: (r.boosts ?? []).map(summarizeBoost),
|
|
571
|
-
nextOffset: r.nextOffset,
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
export function summarizeBusinessChatLink(link) {
|
|
575
|
-
const l = link;
|
|
576
|
-
return {
|
|
577
|
-
link: l.link,
|
|
578
|
-
message: l.message,
|
|
579
|
-
title: l.title,
|
|
580
|
-
views: l.views,
|
|
581
|
-
entityCount: l.entities?.length ?? 0,
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
export function summarizeBusinessChatLinks(result) {
|
|
585
|
-
const r = result;
|
|
586
|
-
const links = r.links ?? [];
|
|
587
|
-
return {
|
|
588
|
-
count: links.length,
|
|
589
|
-
links: links.map(summarizeBusinessChatLink),
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
export function summarizeGroupCallInfo(call) {
|
|
593
|
-
if (call instanceof Api.GroupCallDiscarded) {
|
|
594
|
-
return {
|
|
595
|
-
kind: "discarded",
|
|
596
|
-
id: call.id.toString(),
|
|
597
|
-
accessHash: call.accessHash.toString(),
|
|
598
|
-
duration: call.duration,
|
|
599
|
-
};
|
|
600
|
-
}
|
|
601
|
-
const c = call;
|
|
602
|
-
return {
|
|
603
|
-
kind: "active",
|
|
604
|
-
id: c.id.toString(),
|
|
605
|
-
accessHash: c.accessHash.toString(),
|
|
606
|
-
participantsCount: c.participantsCount,
|
|
607
|
-
title: c.title,
|
|
608
|
-
scheduleDate: c.scheduleDate,
|
|
609
|
-
recordStartDate: c.recordStartDate,
|
|
610
|
-
streamDcId: c.streamDcId,
|
|
611
|
-
unmutedVideoCount: c.unmutedVideoCount,
|
|
612
|
-
unmutedVideoLimit: c.unmutedVideoLimit,
|
|
613
|
-
version: c.version,
|
|
614
|
-
joinMuted: c.joinMuted,
|
|
615
|
-
canChangeJoinMuted: c.canChangeJoinMuted,
|
|
616
|
-
joinDateAsc: c.joinDateAsc,
|
|
617
|
-
scheduleStartSubscribed: c.scheduleStartSubscribed,
|
|
618
|
-
canStartVideo: c.canStartVideo,
|
|
619
|
-
recordVideoActive: c.recordVideoActive,
|
|
620
|
-
rtmpStream: c.rtmpStream,
|
|
621
|
-
listenersHidden: c.listenersHidden,
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
|
-
export function summarizeGroupCallParticipant(p) {
|
|
625
|
-
const gp = p;
|
|
626
|
-
return {
|
|
627
|
-
peer: peerToCompact(gp.peer),
|
|
628
|
-
date: gp.date,
|
|
629
|
-
activeDate: gp.activeDate,
|
|
630
|
-
source: gp.source,
|
|
631
|
-
volume: gp.volume,
|
|
632
|
-
muted: gp.muted,
|
|
633
|
-
left: gp.left,
|
|
634
|
-
canSelfUnmute: gp.canSelfUnmute,
|
|
635
|
-
justJoined: gp.justJoined,
|
|
636
|
-
self: gp.self,
|
|
637
|
-
mutedByYou: gp.mutedByYou,
|
|
638
|
-
volumeByAdmin: gp.volumeByAdmin,
|
|
639
|
-
videoJoined: gp.videoJoined,
|
|
640
|
-
about: gp.about,
|
|
641
|
-
raiseHandRating: gp.raiseHandRating?.toString(),
|
|
642
|
-
hasVideo: gp.video ? true : undefined,
|
|
643
|
-
hasPresentation: gp.presentation ? true : undefined,
|
|
644
|
-
};
|
|
645
|
-
}
|
|
646
|
-
export function summarizeGroupCall(result) {
|
|
647
|
-
const r = result;
|
|
648
|
-
return {
|
|
649
|
-
call: summarizeGroupCallInfo(r.call),
|
|
650
|
-
participants: (r.participants ?? []).map(summarizeGroupCallParticipant),
|
|
651
|
-
participantsNextOffset: r.participantsNextOffset || undefined,
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
|
-
export function summarizeGroupCallParticipants(result) {
|
|
655
|
-
const r = result;
|
|
656
|
-
return {
|
|
657
|
-
count: r.count,
|
|
658
|
-
participants: (r.participants ?? []).map(summarizeGroupCallParticipant),
|
|
659
|
-
nextOffset: r.nextOffset || undefined,
|
|
660
|
-
version: r.version,
|
|
661
|
-
};
|
|
662
|
-
}
|
|
663
|
-
export function summarizeStarsAmount(amount) {
|
|
664
|
-
const a = amount;
|
|
665
|
-
return { amount: a.amount.toString(), nanos: a.nanos };
|
|
666
|
-
}
|
|
667
|
-
export function summarizeStarsTransactionPeer(peer) {
|
|
668
|
-
if (peer instanceof Api.StarsTransactionPeerAppStore)
|
|
669
|
-
return { kind: "appStore" };
|
|
670
|
-
if (peer instanceof Api.StarsTransactionPeerPlayMarket)
|
|
671
|
-
return { kind: "playMarket" };
|
|
672
|
-
if (peer instanceof Api.StarsTransactionPeerPremiumBot)
|
|
673
|
-
return { kind: "premiumBot" };
|
|
674
|
-
if (peer instanceof Api.StarsTransactionPeerFragment)
|
|
675
|
-
return { kind: "fragment" };
|
|
676
|
-
if (peer instanceof Api.StarsTransactionPeerAds)
|
|
677
|
-
return { kind: "ads" };
|
|
678
|
-
if (peer instanceof Api.StarsTransactionPeerAPI)
|
|
679
|
-
return { kind: "api" };
|
|
680
|
-
if (peer instanceof Api.StarsTransactionPeer)
|
|
681
|
-
return { kind: "peer", peer: peerToCompact(peer.peer) };
|
|
682
|
-
return { kind: "unsupported" };
|
|
683
|
-
}
|
|
684
|
-
export function summarizeStarsTransaction(tx) {
|
|
685
|
-
const t = tx;
|
|
686
|
-
return {
|
|
687
|
-
id: t.id,
|
|
688
|
-
stars: summarizeStarsAmount(t.stars),
|
|
689
|
-
date: t.date,
|
|
690
|
-
peer: summarizeStarsTransactionPeer(t.peer),
|
|
691
|
-
refund: t.refund,
|
|
692
|
-
pending: t.pending,
|
|
693
|
-
failed: t.failed,
|
|
694
|
-
gift: t.gift,
|
|
695
|
-
reaction: t.reaction,
|
|
696
|
-
title: t.title,
|
|
697
|
-
description: t.description,
|
|
698
|
-
msgId: t.msgId,
|
|
699
|
-
subscriptionPeriod: t.subscriptionPeriod,
|
|
700
|
-
giveawayPostId: t.giveawayPostId,
|
|
701
|
-
transactionDate: t.transactionDate,
|
|
702
|
-
transactionUrl: t.transactionUrl,
|
|
703
|
-
};
|
|
704
|
-
}
|
|
705
|
-
export function summarizeStarsSubscription(sub) {
|
|
706
|
-
const s = sub;
|
|
707
|
-
const pricing = s.pricing;
|
|
708
|
-
return {
|
|
709
|
-
id: s.id,
|
|
710
|
-
peer: peerToCompact(s.peer),
|
|
711
|
-
untilDate: s.untilDate,
|
|
712
|
-
pricing: { period: pricing.period, amount: pricing.amount.toString() },
|
|
713
|
-
canceled: s.canceled,
|
|
714
|
-
canRefulfill: s.canRefulfill,
|
|
715
|
-
missingBalance: s.missingBalance,
|
|
716
|
-
botCanceled: s.botCanceled,
|
|
717
|
-
chatInviteHash: s.chatInviteHash,
|
|
718
|
-
title: s.title,
|
|
719
|
-
invoiceSlug: s.invoiceSlug,
|
|
720
|
-
};
|
|
721
|
-
}
|
|
722
|
-
export function summarizeQuickReply(reply) {
|
|
723
|
-
const r = reply;
|
|
724
|
-
return {
|
|
725
|
-
shortcutId: r.shortcutId,
|
|
726
|
-
shortcut: r.shortcut,
|
|
727
|
-
topMessage: r.topMessage,
|
|
728
|
-
count: r.count,
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
|
-
export function summarizeQuickReplies(result) {
|
|
732
|
-
if (result instanceof Api.messages.QuickRepliesNotModified) {
|
|
733
|
-
return { notModified: true };
|
|
734
|
-
}
|
|
735
|
-
const r = result;
|
|
736
|
-
return { quickReplies: r.quickReplies.map(summarizeQuickReply) };
|
|
737
|
-
}
|
|
738
|
-
export function summarizeQuickReplyMessage(msg) {
|
|
739
|
-
if (msg instanceof Api.MessageEmpty)
|
|
740
|
-
return null;
|
|
741
|
-
const base = msg;
|
|
742
|
-
const fromId = peerToCompact(base.fromId);
|
|
743
|
-
const replyHeader = base.replyTo;
|
|
744
|
-
const replyToMsgId = replyHeader instanceof Api.MessageReplyHeader ? replyHeader.replyToMsgId : undefined;
|
|
745
|
-
if (msg instanceof Api.Message) {
|
|
746
|
-
return {
|
|
747
|
-
id: msg.id,
|
|
748
|
-
date: msg.date,
|
|
749
|
-
text: msg.message ?? "",
|
|
750
|
-
isService: false,
|
|
751
|
-
fromId,
|
|
752
|
-
replyToMsgId,
|
|
753
|
-
};
|
|
754
|
-
}
|
|
755
|
-
if (msg instanceof Api.MessageService) {
|
|
756
|
-
return {
|
|
757
|
-
id: msg.id,
|
|
758
|
-
date: msg.date,
|
|
759
|
-
text: `[${msg.action?.className ?? "service"}]`,
|
|
760
|
-
isService: true,
|
|
761
|
-
fromId,
|
|
762
|
-
};
|
|
763
|
-
}
|
|
764
|
-
return null;
|
|
765
|
-
}
|
|
766
|
-
export function summarizeQuickReplyMessages(result) {
|
|
767
|
-
if (result instanceof Api.messages.MessagesNotModified) {
|
|
768
|
-
return { notModified: true, count: result.count };
|
|
769
|
-
}
|
|
770
|
-
const rawMessages = result
|
|
771
|
-
.messages;
|
|
772
|
-
const messages = rawMessages.map(summarizeQuickReplyMessage).filter((m) => m !== null);
|
|
773
|
-
const count = result instanceof Api.messages.Messages
|
|
774
|
-
? messages.length
|
|
775
|
-
: result.count;
|
|
776
|
-
return { count, messages };
|
|
777
|
-
}
|
|
778
|
-
export function summarizeStarsStatus(result) {
|
|
779
|
-
const r = result;
|
|
780
|
-
const out = {
|
|
781
|
-
balance: summarizeStarsAmount(r.balance),
|
|
782
|
-
subscriptionsNextOffset: r.subscriptionsNextOffset || undefined,
|
|
783
|
-
subscriptionsMissingBalance: r.subscriptionsMissingBalance?.toString(),
|
|
784
|
-
nextOffset: r.nextOffset || undefined,
|
|
785
|
-
};
|
|
786
|
-
if (r.subscriptions && r.subscriptions.length > 0) {
|
|
787
|
-
out.subscriptions = r.subscriptions.map(summarizeStarsSubscription);
|
|
788
|
-
}
|
|
789
|
-
if (r.history && r.history.length > 0) {
|
|
790
|
-
out.history = r.history.map(summarizeStarsTransaction);
|
|
791
|
-
}
|
|
792
|
-
return out;
|
|
793
|
-
}
|
|
794
|
-
export function summarizeStoryItem(item) {
|
|
795
|
-
if (item instanceof Api.StoryItemDeleted) {
|
|
796
|
-
return { id: item.id, kind: "deleted" };
|
|
797
|
-
}
|
|
798
|
-
if (item instanceof Api.StoryItemSkipped) {
|
|
799
|
-
return {
|
|
800
|
-
id: item.id,
|
|
801
|
-
kind: "skipped",
|
|
802
|
-
date: item.date,
|
|
803
|
-
expireDate: item.expireDate,
|
|
804
|
-
closeFriends: item.closeFriends,
|
|
805
|
-
};
|
|
806
|
-
}
|
|
807
|
-
const story = item;
|
|
808
|
-
return {
|
|
809
|
-
id: story.id,
|
|
810
|
-
kind: "active",
|
|
811
|
-
date: story.date,
|
|
812
|
-
expireDate: story.expireDate,
|
|
813
|
-
caption: story.caption,
|
|
814
|
-
mediaType: story.media?.className,
|
|
815
|
-
pinned: story.pinned,
|
|
816
|
-
public: story.public,
|
|
817
|
-
closeFriends: story.closeFriends,
|
|
818
|
-
edited: story.edited,
|
|
819
|
-
noforwards: story.noforwards,
|
|
820
|
-
fromId: peerToCompact(story.fromId),
|
|
821
|
-
viewsCount: story.views?.viewsCount,
|
|
822
|
-
reactionsCount: story.views?.reactionsCount,
|
|
823
|
-
};
|
|
824
|
-
}
|
|
825
|
-
export function summarizePeerStories(ps) {
|
|
826
|
-
const peer = peerToCompact(ps.peer);
|
|
827
|
-
if (!peer)
|
|
828
|
-
return null;
|
|
829
|
-
return {
|
|
830
|
-
peer,
|
|
831
|
-
maxReadId: ps.maxReadId,
|
|
832
|
-
stories: (ps.stories ?? []).map(summarizeStoryItem),
|
|
833
|
-
};
|
|
834
|
-
}
|
|
835
|
-
export function summarizeStoriesById(result) {
|
|
836
|
-
return {
|
|
837
|
-
count: result.count,
|
|
838
|
-
stories: (result.stories ?? []).map(summarizeStoryItem),
|
|
839
|
-
pinnedToTop: result.pinnedToTop,
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
export function summarizeStoryView(view) {
|
|
843
|
-
if (view instanceof Api.StoryViewPublicForward) {
|
|
844
|
-
const msg = view.message;
|
|
845
|
-
const messageId = msg instanceof Api.MessageEmpty ? undefined : msg?.id;
|
|
846
|
-
const peer = msg instanceof Api.MessageEmpty
|
|
847
|
-
? undefined
|
|
848
|
-
: peerToCompact(msg?.peerId);
|
|
849
|
-
return {
|
|
850
|
-
kind: "publicForward",
|
|
851
|
-
messageId,
|
|
852
|
-
peer,
|
|
853
|
-
blocked: view.blocked,
|
|
854
|
-
blockedMyStoriesFrom: view.blockedMyStoriesFrom,
|
|
855
|
-
};
|
|
856
|
-
}
|
|
857
|
-
if (view instanceof Api.StoryViewPublicRepost) {
|
|
858
|
-
const story = view.story;
|
|
859
|
-
return {
|
|
860
|
-
kind: "publicRepost",
|
|
861
|
-
peer: peerToCompact(view.peerId),
|
|
862
|
-
storyId: story?.id,
|
|
863
|
-
blocked: view.blocked,
|
|
864
|
-
blockedMyStoriesFrom: view.blockedMyStoriesFrom,
|
|
865
|
-
};
|
|
866
|
-
}
|
|
867
|
-
const v = view;
|
|
868
|
-
return {
|
|
869
|
-
kind: "user",
|
|
870
|
-
userId: v.userId.toString(),
|
|
871
|
-
date: v.date,
|
|
872
|
-
reaction: v.reaction ? reactionToEmoji(v.reaction) : undefined,
|
|
873
|
-
blocked: v.blocked,
|
|
874
|
-
blockedMyStoriesFrom: v.blockedMyStoriesFrom,
|
|
875
|
-
};
|
|
876
|
-
}
|
|
877
|
-
export function summarizeStoryViewsList(result) {
|
|
878
|
-
const list = result;
|
|
879
|
-
return {
|
|
880
|
-
count: list.count,
|
|
881
|
-
viewsCount: list.viewsCount,
|
|
882
|
-
forwardsCount: list.forwardsCount,
|
|
883
|
-
reactionsCount: list.reactionsCount,
|
|
884
|
-
views: (list.views ?? []).map(summarizeStoryView),
|
|
885
|
-
nextOffset: list.nextOffset,
|
|
886
|
-
};
|
|
887
|
-
}
|
|
888
|
-
export function summarizeAllStories(result) {
|
|
889
|
-
const stealthMode = result.stealthMode
|
|
890
|
-
? {
|
|
891
|
-
activeUntilDate: result.stealthMode.activeUntilDate,
|
|
892
|
-
cooldownUntilDate: result.stealthMode.cooldownUntilDate,
|
|
893
|
-
}
|
|
894
|
-
: undefined;
|
|
895
|
-
if (result instanceof Api.stories.AllStoriesNotModified) {
|
|
896
|
-
return {
|
|
897
|
-
modified: false,
|
|
898
|
-
state: result.state,
|
|
899
|
-
peerStories: [],
|
|
900
|
-
stealthMode,
|
|
901
|
-
};
|
|
902
|
-
}
|
|
903
|
-
const all = result;
|
|
904
|
-
const peerStories = (all.peerStories ?? [])
|
|
905
|
-
.map(summarizePeerStories)
|
|
906
|
-
.filter((p) => p !== null);
|
|
907
|
-
return {
|
|
908
|
-
modified: true,
|
|
909
|
-
state: all.state,
|
|
910
|
-
hasMore: all.hasMore,
|
|
911
|
-
count: all.count,
|
|
912
|
-
peerStories,
|
|
913
|
-
stealthMode,
|
|
914
|
-
};
|
|
915
|
-
}
|
|
916
49
|
export class TelegramService {
|
|
917
50
|
client = null;
|
|
918
51
|
apiId;
|
|
@@ -922,6 +55,7 @@ export class TelegramService {
|
|
|
922
55
|
sessionPath;
|
|
923
56
|
rateLimiter = new RateLimiter();
|
|
924
57
|
lastTypingAt = new Map();
|
|
58
|
+
entityCache = new Map();
|
|
925
59
|
lastError = "";
|
|
926
60
|
get sessionDir() {
|
|
927
61
|
return dirname(this.sessionPath);
|
|
@@ -1038,6 +172,7 @@ export class TelegramService {
|
|
|
1038
172
|
this.connected = false;
|
|
1039
173
|
this.sessionString = "";
|
|
1040
174
|
this.client = null;
|
|
175
|
+
this.entityCache.clear();
|
|
1041
176
|
if (existsSync(this.sessionPath)) {
|
|
1042
177
|
await unlink(this.sessionPath);
|
|
1043
178
|
}
|
|
@@ -1055,6 +190,7 @@ export class TelegramService {
|
|
|
1055
190
|
await this.client.destroy();
|
|
1056
191
|
this.connected = false;
|
|
1057
192
|
this.client = null;
|
|
193
|
+
this.entityCache.clear();
|
|
1058
194
|
}
|
|
1059
195
|
}
|
|
1060
196
|
/**
|
|
@@ -1654,13 +790,17 @@ export class TelegramService {
|
|
|
1654
790
|
* Resolve a chat by ID, username, or display name.
|
|
1655
791
|
* Falls back to searching user's dialogs if getEntity() fails.
|
|
1656
792
|
*/
|
|
1657
|
-
// biome-ignore lint: GramJS has no proper entity union type
|
|
1658
793
|
async resolveChat(chatId) {
|
|
1659
794
|
if (!this.client)
|
|
1660
795
|
throw new Error(NOT_CONNECTED_ERROR);
|
|
796
|
+
const cached = this.entityCache.get(chatId);
|
|
797
|
+
if (cached)
|
|
798
|
+
return cached;
|
|
1661
799
|
// First try direct resolve (numeric ID, username, phone)
|
|
1662
800
|
try {
|
|
1663
|
-
|
|
801
|
+
const entity = await this.client.getEntity(chatId);
|
|
802
|
+
this.entityCache.set(chatId, entity);
|
|
803
|
+
return entity;
|
|
1664
804
|
}
|
|
1665
805
|
catch {
|
|
1666
806
|
// Fall through to dialog search
|
|
@@ -1670,12 +810,16 @@ export class TelegramService {
|
|
|
1670
810
|
const query = chatId.toLowerCase();
|
|
1671
811
|
// Exact match first
|
|
1672
812
|
const exact = dialogs.find((d) => d.title?.toLowerCase() === query);
|
|
1673
|
-
if (exact?.entity)
|
|
813
|
+
if (exact?.entity) {
|
|
814
|
+
this.entityCache.set(chatId, exact.entity);
|
|
1674
815
|
return exact.entity;
|
|
816
|
+
}
|
|
1675
817
|
// Partial match
|
|
1676
818
|
const partial = dialogs.filter((d) => d.title?.toLowerCase().includes(query));
|
|
1677
|
-
if (partial.length === 1 && partial[0].entity)
|
|
819
|
+
if (partial.length === 1 && partial[0].entity) {
|
|
820
|
+
this.entityCache.set(chatId, partial[0].entity);
|
|
1678
821
|
return partial[0].entity;
|
|
822
|
+
}
|
|
1679
823
|
if (partial.length > 1) {
|
|
1680
824
|
const matches = partial.map((d) => ` ${d.title} (${d.entity?.id?.toString() ?? "?"})`).join("\n");
|
|
1681
825
|
throw new Error(`Multiple chats match "${chatId}". Use the numeric ID instead:\n${matches}`);
|
|
@@ -1686,7 +830,6 @@ export class TelegramService {
|
|
|
1686
830
|
* Resolve chatId to a peer string that GramJS methods accept.
|
|
1687
831
|
* Handles display names by searching dialogs.
|
|
1688
832
|
*/
|
|
1689
|
-
// biome-ignore lint: GramJS has no proper entity union type
|
|
1690
833
|
async resolvePeer(chatId) {
|
|
1691
834
|
// Normalize '@me' — GramJS only intercepts the plain 'me' string as InputPeerSelf
|
|
1692
835
|
if (chatId === "@me")
|