@imessaging/telegram-mtproto 0.6.1 → 0.6.3
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 +1 -1
- package/src/incoming.ts +29 -2
- package/src/index.ts +1 -0
- package/src/telegram-mtproto-transport.ts +16 -8
package/package.json
CHANGED
package/src/incoming.ts
CHANGED
|
@@ -25,6 +25,15 @@ export type MtprotoMessageLike = {
|
|
|
25
25
|
* `accessHash` живёт только здесь. Поле необязательное: в обновлении его может не быть.
|
|
26
26
|
*/
|
|
27
27
|
sender?: { username?: string; accessHash?: { toString(): string } | string | number };
|
|
28
|
+
/**
|
|
29
|
+
* Пир отправителя ВМЕСТЕ с `accessHash` — так его отдаёт само обновление.
|
|
30
|
+
*
|
|
31
|
+
* Без него ответить по одному номеру нельзя: клиент знает только тех, кого уже разрешал, а
|
|
32
|
+
* `accessHash` из обновления больше нигде не хранится.
|
|
33
|
+
*/
|
|
34
|
+
getInputSender?: () => Promise<{ userId?: { toString(): string }; accessHash?: { toString(): string } } | undefined>;
|
|
35
|
+
/** Отправитель целиком. Обращение к сущностям обновления, а не поход в сеть. */
|
|
36
|
+
getSender?: () => Promise<{ username?: string } | undefined>;
|
|
28
37
|
};
|
|
29
38
|
|
|
30
39
|
export type MtprotoMediaLike = {
|
|
@@ -42,18 +51,36 @@ export type MtprotoMediaLike = {
|
|
|
42
51
|
*
|
|
43
52
|
* `chatId` берётся из пира, а НЕ из отправителя: в группе они разные, и перепутав их, ответ уехал
|
|
44
53
|
* бы в личку тому, кто написал в общий чат.
|
|
54
|
+
*
|
|
55
|
+
* ИДЕНТИФИКАТОР ОТДАЁТСЯ МАРКИРОВАННЫМ — тем самым, что знают Bot API, люди и соседние продукты:
|
|
56
|
+
* `-100…` у каналов и супергрупп, `-…` у обычных групп. Внутри MTProto он положительный, и если
|
|
57
|
+
* отдавать его как есть, один и тот же чат в разных системах называется двумя разными числами:
|
|
58
|
+
* замер 06.09.2026 — продукт хранит `-5386451338`, шлюз присылает `5386451338`, и предъявитель
|
|
59
|
+
* не находится. Тот же класс ошибки уже стоил продукту чата-призрака с потерянным знаком.
|
|
45
60
|
*/
|
|
46
61
|
export function peerToChat(peer: MtprotoPeerLike | undefined): {
|
|
47
62
|
chatId: string;
|
|
48
63
|
chatType: IncomingMessage["chatType"];
|
|
49
64
|
} {
|
|
50
65
|
if (peer?.channelId !== undefined)
|
|
51
|
-
return { chatId: peer.channelId.toString()
|
|
52
|
-
if (peer?.chatId !== undefined) return { chatId: peer.chatId.toString()
|
|
66
|
+
return { chatId: `-100${peer.channelId.toString()}`, chatType: "channel" };
|
|
67
|
+
if (peer?.chatId !== undefined) return { chatId: `-${peer.chatId.toString()}`, chatType: "group" };
|
|
53
68
|
if (peer?.userId !== undefined) return { chatId: peer.userId.toString(), chatType: "user" };
|
|
54
69
|
throw new Error("MTProto peer without userId, chatId or channelId");
|
|
55
70
|
}
|
|
56
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Маркированный идентификатор → тот, которым чат зовётся ВНУТРИ MTProto.
|
|
74
|
+
*
|
|
75
|
+
* Нужен на отправке: `InputPeerChat` и `InputPeerChannel` принимают положительное число, а снаружи
|
|
76
|
+
* ходит маркированное. Немаркированное число тоже принимается — тогда вид берётся из вызова.
|
|
77
|
+
*/
|
|
78
|
+
export function unmarkPeerId(chatId: string): string {
|
|
79
|
+
if (chatId.startsWith("-100")) return chatId.slice(4);
|
|
80
|
+
if (chatId.startsWith("-")) return chatId.slice(1);
|
|
81
|
+
return chatId;
|
|
82
|
+
}
|
|
83
|
+
|
|
57
84
|
/**
|
|
58
85
|
* Что приехало файлом.
|
|
59
86
|
*
|
package/src/index.ts
CHANGED
|
@@ -17,7 +17,7 @@ import type {
|
|
|
17
17
|
TypingTransport,
|
|
18
18
|
} from "@imessaging/core";
|
|
19
19
|
import { isTelegramRecipient, MemoryPeerStore } from "@imessaging/core";
|
|
20
|
-
import { peerToChat } from "./incoming";
|
|
20
|
+
import { peerToChat, unmarkPeerId } from "./incoming";
|
|
21
21
|
import bigInt from "big-integer";
|
|
22
22
|
import { Api, TelegramClient } from "telegram";
|
|
23
23
|
import { CustomFile } from "telegram/client/uploads";
|
|
@@ -185,9 +185,12 @@ export class TelegramMtprotoTransport
|
|
|
185
185
|
*/
|
|
186
186
|
private async rememberSender(message: MtprotoMessageLike): Promise<void> {
|
|
187
187
|
try {
|
|
188
|
-
const hash = message.sender?.accessHash;
|
|
189
|
-
if (hash === undefined || hash === null) return;
|
|
190
188
|
const { chatId, chatType } = peerToChat(message.peerId);
|
|
189
|
+
// Спрашиваем ПИР ОБНОВЛЕНИЯ, а не поле `sender`: у живого сообщения gramJS оно ленивое и
|
|
190
|
+
// чаще всего пустое, а `getInputSender` берёт собеседника из карты сущностей обновления.
|
|
191
|
+
const input = await message.getInputSender?.();
|
|
192
|
+
const hash = input?.accessHash ?? message.sender?.accessHash;
|
|
193
|
+
if (hash === undefined || hash === null) return;
|
|
191
194
|
// В группе отправитель и чат — разные пиры, и запись сложила бы одно вместо другого.
|
|
192
195
|
if (chatType !== "user") return;
|
|
193
196
|
const recipient = { type: "user", id: chatId } as const;
|
|
@@ -198,7 +201,7 @@ export class TelegramMtprotoTransport
|
|
|
198
201
|
type: "user",
|
|
199
202
|
id: chatId,
|
|
200
203
|
accessHash: String(hash),
|
|
201
|
-
username: message.sender?.username,
|
|
204
|
+
username: message.sender?.username ?? (await message.getSender?.())?.username,
|
|
202
205
|
resolvedAt: new Date().toISOString(),
|
|
203
206
|
},
|
|
204
207
|
this.options.peerTtlSeconds,
|
|
@@ -333,8 +336,12 @@ export class TelegramMtprotoTransport
|
|
|
333
336
|
*/
|
|
334
337
|
private async knownInputPeer(recipient: MessageRecipient): Promise<Api.TypeInputPeer | null> {
|
|
335
338
|
if (recipient.type === "email" || recipient.type === "username") return null;
|
|
339
|
+
// Обычной группе ни клиент, ни хранилище не нужны: `InputPeerChat` строится из одного номера.
|
|
340
|
+
if (recipient.type === "group") {
|
|
341
|
+
return new Api.InputPeerChat({ chatId: bigInt(unmarkPeerId(recipient.id)) });
|
|
342
|
+
}
|
|
336
343
|
try {
|
|
337
|
-
return await this.client.getInputEntity(bigInt(recipient.id));
|
|
344
|
+
return await this.client.getInputEntity(bigInt(unmarkPeerId(recipient.id)));
|
|
338
345
|
} catch {
|
|
339
346
|
return null;
|
|
340
347
|
}
|
|
@@ -396,17 +403,18 @@ export class TelegramMtprotoTransport
|
|
|
396
403
|
|
|
397
404
|
private toInputPeer(peer: ResolvedPeer): Api.TypeInputPeer {
|
|
398
405
|
if (peer.type === "group") {
|
|
399
|
-
|
|
406
|
+
// У обычной группы access hash не бывает вовсе — ей довольно номера.
|
|
407
|
+
return new Api.InputPeerChat({ chatId: bigInt(unmarkPeerId(peer.id)) });
|
|
400
408
|
}
|
|
401
409
|
if (!peer.accessHash) throw new Error(`Cached ${peer.type} peer has no accessHash`);
|
|
402
410
|
if (peer.type === "user") {
|
|
403
411
|
return new Api.InputPeerUser({
|
|
404
|
-
userId: bigInt(peer.id),
|
|
412
|
+
userId: bigInt(unmarkPeerId(peer.id)),
|
|
405
413
|
accessHash: bigInt(peer.accessHash),
|
|
406
414
|
});
|
|
407
415
|
}
|
|
408
416
|
return new Api.InputPeerChannel({
|
|
409
|
-
channelId: bigInt(peer.id),
|
|
417
|
+
channelId: bigInt(unmarkPeerId(peer.id)),
|
|
410
418
|
accessHash: bigInt(peer.accessHash),
|
|
411
419
|
});
|
|
412
420
|
}
|