@imessaging/telegram-mtproto 0.1.0 → 0.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imessaging/telegram-mtproto",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
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.1.0",
34
+ "@imessaging/core": "0.2.0",
35
35
  "big-integer": "^1.6.52"
36
36
  },
37
37
  "peerDependencies": {
@@ -1,6 +1,8 @@
1
1
  import type {
2
+ EditableMessage,
3
+ EditableMessageTransport,
4
+ EditResult,
2
5
  MessageRecipient,
3
- MessageTransport,
4
6
  OutboundMessage,
5
7
  ResolvedPeer,
6
8
  SendResult,
@@ -52,7 +54,7 @@ function isChannel(chat: Api.TypeChat): chat is Api.Channel {
52
54
  return chat.className === "Channel";
53
55
  }
54
56
 
55
- export class TelegramMtprotoTransport implements MessageTransport {
57
+ export class TelegramMtprotoTransport implements EditableMessageTransport {
56
58
  readonly id: string;
57
59
  private readonly client: TelegramClient;
58
60
  private readonly peerStore: TelegramPeerStore;
@@ -96,6 +98,22 @@ export class TelegramMtprotoTransport implements MessageTransport {
96
98
  return this.sendWithRetry(message, false);
97
99
  }
98
100
 
101
+ /**
102
+ * Правка отправленного сообщения.
103
+ *
104
+ * Зачем она есть. Карточка в рабочем чате живёт долго и по ходу дела меняет состояние: слать на
105
+ * каждое изменение новое сообщение значит закапывать чат и заставлять человека искать, какое из
106
+ * них последнее. Правится то же самое.
107
+ *
108
+ * Идентификатор сообщения в Telegram нумеруется В ПРЕДЕЛАХ чата, поэтому получатель обязателен
109
+ * и адрес разрешается тем же путём, что при отправке, — включая сброс кеша и повтор на протухшем
110
+ * адресе.
111
+ */
112
+ async edit(message: EditableMessage): Promise<EditResult> {
113
+ this.assertConnected();
114
+ return this.editWithRetry(message, false);
115
+ }
116
+
99
117
  async getStatus(): Promise<TransportStatus> {
100
118
  return {
101
119
  connected: this.connected && Boolean(this.client.connected),
@@ -227,6 +245,35 @@ export class TelegramMtprotoTransport implements MessageTransport {
227
245
  }
228
246
  }
229
247
 
248
+ private async editWithRetry(message: EditableMessage, retried: boolean): Promise<EditResult> {
249
+ const messageId = Number(message.messageId);
250
+ if (!Number.isSafeInteger(messageId) || messageId <= 0) {
251
+ throw new Error(`Telegram message id must be a positive integer: ${message.messageId}`);
252
+ }
253
+
254
+ let peer: Api.TypeInputPeer | null = null;
255
+ try {
256
+ peer = await this.getInputPeer(message.recipient);
257
+ // Кнопки здесь не передаются — ровно как и при отправке этим транспортом: inline-клавиатуру
258
+ // MTProto-аккаунт не рисует. Передать их сюда значило бы обещать разметку, которой не будет.
259
+ await this.client.editMessage(peer, {
260
+ message: messageId,
261
+ text: message.text,
262
+ parseMode: message.parseMode?.toLowerCase(),
263
+ });
264
+ this.lastActivityAt = new Date();
265
+ return {
266
+ transportId: this.id,
267
+ messageId: message.messageId,
268
+ recipientId: this.getPeerId(peer),
269
+ };
270
+ } catch (error: unknown) {
271
+ if (retried || !this.isInvalidPeerError(error)) throw error;
272
+ await this.peerStore.delete(this.options.accountId, message.recipient);
273
+ return this.editWithRetry(message, true);
274
+ }
275
+ }
276
+
230
277
  private isInvalidPeerError(error: unknown): boolean {
231
278
  if (typeof error !== "object" || error === null) return false;
232
279
  const telegramError = error as TelegramRpcError;