@imessaging/telegram-mtproto 0.8.0 → 0.8.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imessaging/telegram-mtproto",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Telegram MTProto user-account transport for imessaging",
5
5
  "keywords": [
6
6
  "messaging",
@@ -31,7 +31,7 @@
31
31
  "test": "bun test"
32
32
  },
33
33
  "dependencies": {
34
- "@imessaging/core": "^0.8.0",
34
+ "@imessaging/core": "^0.8.2",
35
35
  "big-integer": "^1.6.52"
36
36
  },
37
37
  "peerDependencies": {
package/src/incoming.ts CHANGED
@@ -18,6 +18,7 @@ export type MtprotoMessageLike = {
18
18
  date?: number | null;
19
19
  editDate?: number | null;
20
20
  groupedId?: { toString(): string } | null;
21
+ mentioned?: boolean | null;
21
22
  peerId?: MtprotoPeerLike;
22
23
  fromId?: MtprotoPeerLike;
23
24
  media?: MtprotoMediaLike;
@@ -298,6 +299,7 @@ export function toIncomingMessage(
298
299
  editedAt: message.editDate ? new Date(message.editDate * 1000) : undefined,
299
300
  attachments: collectAttachments(message, chatId),
300
301
  links: collectLinks(message),
302
+ mentionsMe: typeof message.mentioned === "boolean" ? message.mentioned : undefined,
301
303
  replyToMessageId,
302
304
  threadId,
303
305
  forwardedFrom: toForwardedFrom(message.fwdFrom),
@@ -8,8 +8,10 @@ import type {
8
8
  EditableMessage,
9
9
  EditableMessageTransport,
10
10
  EditResult,
11
+ MessageReaction,
11
12
  MessageRecipient,
12
13
  OutboundMessage,
14
+ ReactionTransport,
13
15
  ResolvedPeer,
14
16
  SendResult,
15
17
  TelegramPeerStore,
@@ -43,6 +45,7 @@ export type TelegramChatSummary = {
43
45
  title: string;
44
46
  username?: string;
45
47
  unreadCount: number;
48
+ unreadMentions: number;
46
49
  };
47
50
 
48
51
  export type TelegramMtprotoTransportOptions = {
@@ -88,6 +91,7 @@ export class TelegramMtprotoTransport
88
91
  EditableMessageTransport,
89
92
  ButtonPressTransport,
90
93
  IncomingMessageTransport,
94
+ ReactionTransport,
91
95
  ReadReceiptTransport,
92
96
  TypingTransport
93
97
  {
@@ -325,6 +329,29 @@ export class TelegramMtprotoTransport
325
329
  );
326
330
  }
327
331
 
332
+ async react(reaction: MessageReaction): Promise<void> {
333
+ this.assertConnected();
334
+ if (!isTelegramRecipient(reaction.recipient)) {
335
+ if (reaction.recipient.type === "email") {
336
+ throw new Error("Telegram MTProto cannot react to an email");
337
+ }
338
+ throw new Error(`Telegram MTProto cannot react to ${reaction.recipient.type}`);
339
+ }
340
+ const messageId = Number(reaction.messageId);
341
+ if (!Number.isSafeInteger(messageId) || messageId <= 0) {
342
+ throw new Error(`Telegram message id must be a positive integer: ${reaction.messageId}`);
343
+ }
344
+ const peer = await this.getInputPeer(reaction.recipient);
345
+ await this.client.invoke(
346
+ new Api.messages.SendReaction({
347
+ peer,
348
+ msgId: messageId,
349
+ reaction: reaction.emoji ? [new Api.ReactionEmoji({ emoticon: reaction.emoji })] : [],
350
+ }),
351
+ );
352
+ this.lastActivityAt = new Date();
353
+ }
354
+
328
355
  async disconnect(): Promise<void> {
329
356
  await this.client.disconnect();
330
357
  this.connected = false;
@@ -408,7 +435,14 @@ export class TelegramMtprotoTransport
408
435
  );
409
436
  }
410
437
 
411
- summaries.push({ chatId, chatType, title, username, unreadCount: dialog.unreadCount });
438
+ summaries.push({
439
+ chatId,
440
+ chatType,
441
+ title,
442
+ username,
443
+ unreadCount: dialog.unreadCount,
444
+ unreadMentions: dialog.unreadMentionsCount ?? 0,
445
+ });
412
446
  if (summaries.length >= limit) break;
413
447
  }
414
448
  return summaries;
@@ -417,16 +451,21 @@ export class TelegramMtprotoTransport
417
451
  /**
418
452
  * Последние `limit` сообщений чата, от старых к новым, ВКЛЮЧАЯ свои — это чтение истории, а не приём.
419
453
  * Служебные события (вход в группу, закреп) пропускаются: текста и вложений у них нет.
454
+ *
455
+ * @param options.mentionsOnly Только упоминания аккаунта. Фильтр работает на уровне всего чата;
456
+ * вызывающий код должен сам отфильтровать результат по `threadId`.
420
457
  */
421
458
  async history(
422
459
  recipient: TelegramRecipient,
423
- options?: { limit?: number; threadId?: number },
460
+ options?: { limit?: number; threadId?: number; mentionsOnly?: boolean },
424
461
  ): Promise<IncomingMessage[]> {
425
462
  this.assertConnected();
426
463
  const peer = await this.getInputPeer(recipient);
464
+ // gramjs игнорирует filter, если передан replyTo, поэтому для mentionsOnly replyTo не передаём
427
465
  const messages = await this.client.getMessages(peer, {
428
466
  limit: options?.limit ?? 30,
429
- replyTo: options?.threadId,
467
+ replyTo: options?.mentionsOnly ? undefined : options?.threadId,
468
+ filter: options?.mentionsOnly ? new Api.InputMessagesFilterMyMentions() : undefined,
430
469
  });
431
470
  return [...messages]
432
471
  .reverse()
@@ -440,6 +479,28 @@ export class TelegramMtprotoTransport
440
479
  );
441
480
  }
442
481
 
482
+ /**
483
+ * Запросить конкретные сообщения по их номерам.
484
+ * Контекст для упоминаний, то есть сообщение, на которое кто-то ответил.
485
+ * Если запросить пустой список, вернёт `[]` без сетевых вызовов (но после проверки соединения).
486
+ */
487
+ async messagesByIds(recipient: TelegramRecipient, ids: number[]): Promise<IncomingMessage[]> {
488
+ this.assertConnected();
489
+ if (ids.length === 0) return [];
490
+ const peer = await this.getInputPeer(recipient);
491
+ const messages = await this.client.getMessages(peer, { ids });
492
+ return messages
493
+ .filter((message) => message && message.className === "Message")
494
+ .map((message) =>
495
+ toIncomingMessage(
496
+ message as unknown as MtprotoMessageLike,
497
+ this.id,
498
+ this.options.accountId,
499
+ ),
500
+ )
501
+ .sort((a, b) => Number(a.messageId) - Number(b.messageId));
502
+ }
503
+
443
504
  private async sendWithRetry(message: OutboundMessage, retried: boolean): Promise<SendResult> {
444
505
  try {
445
506
  const peer = await this.getInputPeer(message.recipient);