@wirecat/tg-cli 0.0.0 → 0.43.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/LICENSE +204 -0
- package/README.md +527 -0
- package/THIRD_PARTY_NOTICES +55 -0
- package/dist/app.d.ts +11 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +16 -0
- package/dist/app.js.map +1 -0
- package/dist/bin/tg.d.ts +3 -0
- package/dist/bin/tg.d.ts.map +1 -0
- package/dist/bin/tg.js +18 -0
- package/dist/bin/tg.js.map +1 -0
- package/dist/bot/adapter.d.ts +9 -0
- package/dist/bot/adapter.d.ts.map +1 -0
- package/dist/bot/adapter.js +171 -0
- package/dist/bot/adapter.js.map +1 -0
- package/dist/bot/generated/definitions.d.ts +3 -0
- package/dist/bot/generated/definitions.d.ts.map +1 -0
- package/dist/bot/generated/definitions.js +19104 -0
- package/dist/bot/generated/definitions.js.map +1 -0
- package/dist/bot/generated/manifest.d.ts +3 -0
- package/dist/bot/generated/manifest.d.ts.map +1 -0
- package/dist/bot/generated/manifest.js +15354 -0
- package/dist/bot/generated/manifest.js.map +1 -0
- package/dist/bot/generated/schemas.d.ts +1407 -0
- package/dist/bot/generated/schemas.d.ts.map +1 -0
- package/dist/bot/generated/schemas.js +5118 -0
- package/dist/bot/generated/schemas.js.map +1 -0
- package/dist/bot/generated/types.d.ts +6884 -0
- package/dist/bot/generated/types.d.ts.map +1 -0
- package/dist/bot/generated/types.js +5 -0
- package/dist/bot/generated/types.js.map +1 -0
- package/dist/bot/map.d.ts +122 -0
- package/dist/bot/map.d.ts.map +1 -0
- package/dist/bot/map.js +193 -0
- package/dist/bot/map.js.map +1 -0
- package/dist/bot/proxy.d.ts +15 -0
- package/dist/bot/proxy.d.ts.map +1 -0
- package/dist/bot/proxy.js +64 -0
- package/dist/bot/proxy.js.map +1 -0
- package/dist/bot/transport.d.ts +42 -0
- package/dist/bot/transport.d.ts.map +1 -0
- package/dist/bot/transport.js +158 -0
- package/dist/bot/transport.js.map +1 -0
- package/dist/browser.d.ts +6 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +18 -0
- package/dist/browser.js.map +1 -0
- package/dist/commands/bot-api.d.ts +3 -0
- package/dist/commands/bot-api.d.ts.map +1 -0
- package/dist/commands/bot-api.js +112 -0
- package/dist/commands/bot-api.js.map +1 -0
- package/dist/commands/bot.d.ts +7 -0
- package/dist/commands/bot.d.ts.map +1 -0
- package/dist/commands/bot.js +99 -0
- package/dist/commands/bot.js.map +1 -0
- package/dist/commands/context.d.ts +59 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +176 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/proxy-config.d.ts +9 -0
- package/dist/commands/proxy-config.d.ts.map +1 -0
- package/dist/commands/proxy-config.js +63 -0
- package/dist/commands/proxy-config.js.map +1 -0
- package/dist/commands/session.d.ts +22 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +191 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/setup.d.ts +3 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +203 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +35 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/install/postinstall.d.ts +8 -0
- package/dist/install/postinstall.d.ts.map +1 -0
- package/dist/install/postinstall.js +62 -0
- package/dist/install/postinstall.js.map +1 -0
- package/dist/paths.d.ts +9 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +11 -0
- package/dist/paths.js.map +1 -0
- package/dist/program.d.ts +8 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +138 -0
- package/dist/program.js.map +1 -0
- package/dist/proxy.d.ts +31 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +99 -0
- package/dist/proxy.js.map +1 -0
- package/dist/telegram/adapter.d.ts +432 -0
- package/dist/telegram/adapter.d.ts.map +1 -0
- package/dist/telegram/adapter.js +1898 -0
- package/dist/telegram/adapter.js.map +1 -0
- package/dist/telegram/bot-history.d.ts +18 -0
- package/dist/telegram/bot-history.d.ts.map +1 -0
- package/dist/telegram/bot-history.js +145 -0
- package/dist/telegram/bot-history.js.map +1 -0
- package/dist/telegram/comments.d.ts +18 -0
- package/dist/telegram/comments.d.ts.map +1 -0
- package/dist/telegram/comments.js +48 -0
- package/dist/telegram/comments.js.map +1 -0
- package/dist/telegram/credentials.d.ts +22 -0
- package/dist/telegram/credentials.d.ts.map +1 -0
- package/dist/telegram/credentials.js +49 -0
- package/dist/telegram/credentials.js.map +1 -0
- package/dist/telegram/errors.d.ts +6 -0
- package/dist/telegram/errors.d.ts.map +1 -0
- package/dist/telegram/errors.js +186 -0
- package/dist/telegram/errors.js.map +1 -0
- package/dist/telegram/folder-rules.d.ts +14 -0
- package/dist/telegram/folder-rules.d.ts.map +1 -0
- package/dist/telegram/folder-rules.js +23 -0
- package/dist/telegram/folder-rules.js.map +1 -0
- package/dist/telegram/format-html.d.ts +4 -0
- package/dist/telegram/format-html.d.ts.map +1 -0
- package/dist/telegram/format-html.js +29 -0
- package/dist/telegram/format-html.js.map +1 -0
- package/dist/telegram/format-markdown.d.ts +3 -0
- package/dist/telegram/format-markdown.d.ts.map +1 -0
- package/dist/telegram/format-markdown.js +160 -0
- package/dist/telegram/format-markdown.js.map +1 -0
- package/dist/telegram/join-requests.d.ts +15 -0
- package/dist/telegram/join-requests.d.ts.map +1 -0
- package/dist/telegram/join-requests.js +35 -0
- package/dist/telegram/join-requests.js.map +1 -0
- package/dist/telegram/map.d.ts +92 -0
- package/dist/telegram/map.d.ts.map +1 -0
- package/dist/telegram/map.js +471 -0
- package/dist/telegram/map.js.map +1 -0
- package/dist/telegram/poll-voters.d.ts +15 -0
- package/dist/telegram/poll-voters.d.ts.map +1 -0
- package/dist/telegram/poll-voters.js +31 -0
- package/dist/telegram/poll-voters.js.map +1 -0
- package/dist/telegram/polls.d.ts +5 -0
- package/dist/telegram/polls.d.ts.map +1 -0
- package/dist/telegram/polls.js +20 -0
- package/dist/telegram/polls.js.map +1 -0
- package/dist/telegram/profile.d.ts +9 -0
- package/dist/telegram/profile.d.ts.map +1 -0
- package/dist/telegram/profile.js +175 -0
- package/dist/telegram/profile.js.map +1 -0
- package/dist/telegram/proxy.d.ts +48 -0
- package/dist/telegram/proxy.d.ts.map +1 -0
- package/dist/telegram/proxy.js +108 -0
- package/dist/telegram/proxy.js.map +1 -0
- package/dist/telegram/registration.d.ts +31 -0
- package/dist/telegram/registration.d.ts.map +1 -0
- package/dist/telegram/registration.js +95 -0
- package/dist/telegram/registration.js.map +1 -0
- package/dist/telegram/send-as.d.ts +17 -0
- package/dist/telegram/send-as.d.ts.map +1 -0
- package/dist/telegram/send-as.js +67 -0
- package/dist/telegram/send-as.js.map +1 -0
- package/dist/telegram/stats.d.ts +13 -0
- package/dist/telegram/stats.d.ts.map +1 -0
- package/dist/telegram/stats.js +135 -0
- package/dist/telegram/stats.js.map +1 -0
- package/dist/telegram/storage.d.ts +4 -0
- package/dist/telegram/storage.d.ts.map +1 -0
- package/dist/telegram/storage.js +68 -0
- package/dist/telegram/storage.js.map +1 -0
- package/dist/telegram/upload.d.ts +9 -0
- package/dist/telegram/upload.d.ts.map +1 -0
- package/dist/telegram/upload.js +29 -0
- package/dist/telegram/upload.js.map +1 -0
- package/dist/update.d.ts +28 -0
- package/dist/update.d.ts.map +1 -0
- package/dist/update.js +56 -0
- package/dist/update.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/install/postinstall.mjs +3 -0
- package/install/windows.ps1 +161 -0
- package/package.json +72 -3
- package/skills/tg-cli/SKILL.md +489 -0
- package/spec/bot/LICENSE +21 -0
- package/spec/bot/README.md +16 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { PeersIndex, parsePeer } from "@mtcute/node";
|
|
2
|
+
import { answerId, toMember } from "./map.js";
|
|
3
|
+
/**
|
|
4
|
+
* Newest first, as Telegram lists them. Asked for one answer, Telegram sends each vote without it
|
|
5
|
+
* (`messagePeerVoteInputOption`): it is the answer asked for.
|
|
6
|
+
*/
|
|
7
|
+
export const pollVotersOf = async (client, chatId, messageId, { limit, answerId: answer }) => {
|
|
8
|
+
const list = await client.call({
|
|
9
|
+
_: "messages.getPollVotes",
|
|
10
|
+
peer: await client.resolvePeer(chatId),
|
|
11
|
+
id: messageId,
|
|
12
|
+
limit,
|
|
13
|
+
...(answer === undefined ? {} : { option: Buffer.from(answer, "base64url") }),
|
|
14
|
+
});
|
|
15
|
+
const peers = PeersIndex.from(list);
|
|
16
|
+
const answersOf = (vote) => {
|
|
17
|
+
if (vote._ === "messagePeerVote")
|
|
18
|
+
return [answerId(vote.option)];
|
|
19
|
+
if (vote._ === "messagePeerVoteMultiple")
|
|
20
|
+
return vote.options.map(answerId);
|
|
21
|
+
return answer === undefined ? [] : [answer];
|
|
22
|
+
};
|
|
23
|
+
const items = list.votes.map((vote) => ({
|
|
24
|
+
person: toMember(parsePeer(vote.peer, peers)),
|
|
25
|
+
answers: answersOf(vote),
|
|
26
|
+
votedAt: new Date(vote.date * 1000).toISOString(),
|
|
27
|
+
}));
|
|
28
|
+
// Live 2026-10-08, Telegram sent a next offset with one vote of one; the count decides.
|
|
29
|
+
return { items, hasMore: Boolean(list.nextOffset) && items.length < list.count, total: list.count };
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=poll-voters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poll-voters.js","sourceRoot":"","sources":["../../src/telegram/poll-voters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAgC,MAAM,cAAc,CAAA;AAElF,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAI7C;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAC/B,MAAc,EACd,MAAc,EACd,SAAiB,EACjB,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAwC,EACpB,EAAE;IAC/C,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC;QAC7B,CAAC,EAAE,uBAAuB;QAC1B,IAAI,EAAE,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC;QACtC,EAAE,EAAE,SAAS;QACb,KAAK;QACL,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC;KAC9E,CAAC,CAAA;IACF,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnC,MAAM,SAAS,GAAG,CAAC,IAA4B,EAAE,EAAE;QACjD,IAAI,IAAI,CAAC,CAAC,KAAK,iBAAiB;YAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;QAChE,IAAI,IAAI,CAAC,CAAC,KAAK,yBAAyB;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAC3E,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;IAC7C,CAAC,CAAA;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACtC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC7C,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC;QACxB,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;KAClD,CAAC,CAAC,CAAA;IACH,wFAAwF;IACxF,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAA;AACrG,CAAC,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Poll as TgPoll } from "@mtcute/node";
|
|
2
|
+
/** What Telegram would refuse anyway, said before anything is sent — the same checks max-cli makes. */
|
|
3
|
+
export declare const refuseVote: (poll: TgPoll, answerIds: readonly string[]) => void;
|
|
4
|
+
export declare const refuseClose: (poll: TgPoll) => void;
|
|
5
|
+
//# sourceMappingURL=polls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polls.d.ts","sourceRoot":"","sources":["../../src/telegram/polls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,MAAM,EAAE,MAAM,cAAc,CAAA;AAGlD,uGAAuG;AACvG,eAAO,MAAM,UAAU,SAAU,MAAM,aAAa,SAAS,MAAM,EAAE,KAAG,IAQvE,CAAA;AAED,eAAO,MAAM,WAAW,SAAU,MAAM,KAAG,IAG1C,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CliError } from "@wirecat/cli-core";
|
|
2
|
+
/** What Telegram would refuse anyway, said before anything is sent — the same checks max-cli makes. */
|
|
3
|
+
export const refuseVote = (poll, answerIds) => {
|
|
4
|
+
if (poll.isClosed)
|
|
5
|
+
throw new CliError("validation_error", "this poll is closed; `tg polls show` has its result");
|
|
6
|
+
const voted = poll.answers.some((answer) => answer.chosen);
|
|
7
|
+
if (answerIds.length === 0 && !voted)
|
|
8
|
+
throw new CliError("validation_error", "you have not voted in this poll");
|
|
9
|
+
if (voted && poll.isRevotingDisabled)
|
|
10
|
+
throw new CliError("validation_error", "this poll takes one vote, and yours is final — it cannot be changed");
|
|
11
|
+
if (answerIds.length > 1 && !poll.isMultiple)
|
|
12
|
+
throw new CliError("validation_error", "this poll takes one answer; give one id");
|
|
13
|
+
};
|
|
14
|
+
export const refuseClose = (poll) => {
|
|
15
|
+
if (poll.isClosed)
|
|
16
|
+
throw new CliError("validation_error", "this poll is closed already");
|
|
17
|
+
if (!poll.isCreator)
|
|
18
|
+
throw new CliError("permission_error", "only whoever made a poll can close it");
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=polls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polls.js","sourceRoot":"","sources":["../../src/telegram/polls.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE5C,uGAAuG;AACvG,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,SAA4B,EAAQ,EAAE;IAC7E,IAAI,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,qDAAqD,CAAC,CAAA;IAChH,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAC1D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,iCAAiC,CAAC,CAAA;IAC/G,IAAI,KAAK,IAAI,IAAI,CAAC,kBAAkB;QAClC,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,qEAAqE,CAAC,CAAA;IAC/G,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU;QAC1C,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,yCAAyC,CAAC,CAAA;AACrF,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAQ,EAAE;IAChD,IAAI,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,6BAA6B,CAAC,CAAA;IACxF,IAAI,CAAC,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,uCAAuC,CAAC,CAAA;AACtG,CAAC,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FullUser, User } from "@mtcute/node";
|
|
2
|
+
import type { ProfileFacts, Registered, Seen } from "@wirecat/cli-messaging";
|
|
3
|
+
export declare const estimatedRegistration: (id: number) => Registered | null;
|
|
4
|
+
/** Telegram's own month, `MM.YYYY`, sent only when they first contact the owner; the estimate otherwise. */
|
|
5
|
+
export declare const registrationOf: (id: number, registrationMonth: string | undefined) => Registered | null;
|
|
6
|
+
/** mtcute folds the empty status into `long_time_ago`; that is the one Telegram shows as hidden. */
|
|
7
|
+
export declare const seenOf: (user: User) => Seen | undefined;
|
|
8
|
+
export declare const toProfileFacts: (full: FullUser, chats: ProfileFacts["chats"]) => ProfileFacts;
|
|
9
|
+
//# sourceMappingURL=profile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../src/telegram/profile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAA;AAuG5E,eAAO,MAAM,qBAAqB,OAAQ,MAAM,KAAG,UAAU,GAAG,IAI/D,CAAA;AAED,4GAA4G;AAC5G,eAAO,MAAM,cAAc,OAAQ,MAAM,qBAAqB,MAAM,GAAG,SAAS,KAAG,UAAU,GAAG,IAO/F,CAAA;AAED,oGAAoG;AACpG,eAAO,MAAM,MAAM,SAAU,IAAI,KAAG,IAAI,GAAG,SAiB1C,CAAA;AASD,eAAO,MAAM,cAAc,SAAU,QAAQ,SAAS,YAAY,CAAC,OAAO,CAAC,KAAG,YAmC7E,CAAA"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Id → month. A monotone best fit to 212 real sign-up dates (jobians/telegram-id-age, MIT, commit 86605dc,
|
|
3
|
+
* up to 2025-11), with tg-id-mcp's points (MIT, `REG_DATE_RANGES`) filling 2017–2021 where those are sparse
|
|
4
|
+
* and the 2021-12 start of 52-bit ids from the Bot API 5.5 changelog. Checked against points left out of the
|
|
5
|
+
* fit, 2022–2025 estimates are off by a median of 1–2 months and at most 4–6 for nine in ten. Ids are not
|
|
6
|
+
* promised to grow with time, so this is an estimate and is always labelled one.
|
|
7
|
+
*
|
|
8
|
+
* From 8.0e9 the same fit also takes 195 sign-up dates from the owner's own chats (2026-10-07; only these
|
|
9
|
+
* rounded bands are kept, no id), which carries the table into 2026. Checked on those dates left out of the fit:
|
|
10
|
+
* 2025 off by a median of 2 months and at most 3 for nine in ten, 2026 a median of 3 and at most 4 — the 2026
|
|
11
|
+
* rows rest on five dates, so read them as a season, not a month.
|
|
12
|
+
*/
|
|
13
|
+
const ID_MONTHS = [
|
|
14
|
+
[1, "2013-08"],
|
|
15
|
+
[2_000_000, "2013-11"],
|
|
16
|
+
[5_000_000, "2013-12"],
|
|
17
|
+
[10_000_000, "2014-02"],
|
|
18
|
+
[30_000_000, "2014-03"],
|
|
19
|
+
[40_000_000, "2014-05"],
|
|
20
|
+
[50_000_000, "2014-09"],
|
|
21
|
+
[60_000_000, "2014-10"],
|
|
22
|
+
[100_000_000, "2015-03"],
|
|
23
|
+
[102_000_000, "2015-05"],
|
|
24
|
+
[112_000_000, "2015-07"],
|
|
25
|
+
[124_000_000, "2015-08"],
|
|
26
|
+
[125_000_000, "2015-09"],
|
|
27
|
+
[132_000_000, "2015-10"],
|
|
28
|
+
[140_000_000, "2015-12"],
|
|
29
|
+
[145_000_000, "2016-01"],
|
|
30
|
+
[160_000_000, "2016-03"],
|
|
31
|
+
[180_000_000, "2016-04"],
|
|
32
|
+
[200_000_000, "2016-06"],
|
|
33
|
+
[250_000_000, "2016-09"],
|
|
34
|
+
[280_000_000, "2016-10"],
|
|
35
|
+
[290_000_000, "2016-11"],
|
|
36
|
+
[295_000_000, "2016-12"],
|
|
37
|
+
[300_000_000, "2017-01"],
|
|
38
|
+
[330_000_000, "2017-02"],
|
|
39
|
+
[360_000_000, "2017-03"],
|
|
40
|
+
[400_000_000, "2017-07"],
|
|
41
|
+
[500_000_000, "2018-01"],
|
|
42
|
+
[550_000_000, "2018-04"],
|
|
43
|
+
[600_000_000, "2018-06"],
|
|
44
|
+
[650_000_000, "2018-08"],
|
|
45
|
+
[700_000_000, "2018-09"],
|
|
46
|
+
[750_000_000, "2018-11"],
|
|
47
|
+
[800_000_000, "2019-01"],
|
|
48
|
+
[805_000_000, "2019-03"],
|
|
49
|
+
[900_000_000, "2019-05"],
|
|
50
|
+
[950_000_000, "2019-07"],
|
|
51
|
+
[1_000_000_000, "2019-09"],
|
|
52
|
+
[1_100_000_000, "2020-02"],
|
|
53
|
+
[1_200_000_000, "2020-06"],
|
|
54
|
+
[1_300_000_000, "2020-10"],
|
|
55
|
+
[1_400_000_000, "2021-01"],
|
|
56
|
+
[1_500_000_000, "2021-04"],
|
|
57
|
+
[1_600_000_000, "2021-06"],
|
|
58
|
+
[1_700_000_000, "2021-08"],
|
|
59
|
+
[1_800_000_000, "2021-10"],
|
|
60
|
+
[5_000_000_000, "2021-12"],
|
|
61
|
+
[5_040_000_000, "2022-01"],
|
|
62
|
+
[5_100_000_000, "2022-02"],
|
|
63
|
+
[5_150_000_000, "2022-03"],
|
|
64
|
+
[5_300_000_000, "2022-04"],
|
|
65
|
+
[5_350_000_000, "2022-05"],
|
|
66
|
+
[5_434_000_000, "2022-06"],
|
|
67
|
+
[5_440_000_000, "2022-07"],
|
|
68
|
+
[5_550_000_000, "2022-10"],
|
|
69
|
+
[5_780_000_000, "2022-11"],
|
|
70
|
+
[5_800_000_000, "2022-12"],
|
|
71
|
+
[5_865_000_000, "2023-01"],
|
|
72
|
+
[5_990_000_000, "2023-05"],
|
|
73
|
+
[6_300_000_000, "2023-07"],
|
|
74
|
+
[6_400_000_000, "2023-11"],
|
|
75
|
+
[6_530_000_000, "2023-12"],
|
|
76
|
+
[6_550_000_000, "2024-01"],
|
|
77
|
+
[7_000_000_000, "2024-04"],
|
|
78
|
+
[7_050_000_000, "2024-05"],
|
|
79
|
+
[7_243_000_000, "2024-06"],
|
|
80
|
+
[7_260_000_000, "2024-07"],
|
|
81
|
+
[7_450_000_000, "2024-08"],
|
|
82
|
+
[7_500_000_000, "2024-12"],
|
|
83
|
+
[7_800_000_000, "2025-01"],
|
|
84
|
+
[7_834_000_000, "2025-06"],
|
|
85
|
+
[7_900_000_000, "2025-07"],
|
|
86
|
+
[8_090_000_000, "2025-08"],
|
|
87
|
+
[8_200_000_000, "2025-10"],
|
|
88
|
+
[8_420_000_000, "2025-12"],
|
|
89
|
+
[8_580_000_000, "2026-01"],
|
|
90
|
+
[8_680_000_000, "2026-03"],
|
|
91
|
+
[8_760_000_000, "2026-04"],
|
|
92
|
+
[8_950_000_000, "2026-08"],
|
|
93
|
+
[8_960_000_000, "2026-08"],
|
|
94
|
+
];
|
|
95
|
+
/**
|
|
96
|
+
* The last point only marks where the table ends: the table cannot tell an id just above it made in
|
|
97
|
+
* 2025 from one made in 2026, so anything at or past it gets no estimate rather than a possibly wrong one.
|
|
98
|
+
*/
|
|
99
|
+
const TABLE_END = ID_MONTHS.at(-1)?.[0] ?? 0;
|
|
100
|
+
export const estimatedRegistration = (id) => {
|
|
101
|
+
if (id < 1 || id >= TABLE_END)
|
|
102
|
+
return null;
|
|
103
|
+
const month = ID_MONTHS.findLast(([from]) => id >= from)?.[1];
|
|
104
|
+
return month ? { at: `${month}-01T00:00:00.000Z`, source: "estimate", precision: "month" } : null;
|
|
105
|
+
};
|
|
106
|
+
/** Telegram's own month, `MM.YYYY`, sent only when they first contact the owner; the estimate otherwise. */
|
|
107
|
+
export const registrationOf = (id, registrationMonth) => {
|
|
108
|
+
const told = registrationMonth?.match(/^(\d{1,2})\.(\d{4})$/);
|
|
109
|
+
if (told) {
|
|
110
|
+
const [, month = "", year = ""] = told;
|
|
111
|
+
return { at: `${year}-${month.padStart(2, "0")}-01T00:00:00.000Z`, source: "telegram", precision: "month" };
|
|
112
|
+
}
|
|
113
|
+
return estimatedRegistration(id);
|
|
114
|
+
};
|
|
115
|
+
/** mtcute folds the empty status into `long_time_ago`; that is the one Telegram shows as hidden. */
|
|
116
|
+
export const seenOf = (user) => {
|
|
117
|
+
switch (user.status) {
|
|
118
|
+
case "online":
|
|
119
|
+
return "online";
|
|
120
|
+
case "offline":
|
|
121
|
+
return user.lastOnline?.toISOString() ?? "hidden";
|
|
122
|
+
case "recently":
|
|
123
|
+
return "recently";
|
|
124
|
+
case "within_week":
|
|
125
|
+
return "week";
|
|
126
|
+
case "within_month":
|
|
127
|
+
return "month";
|
|
128
|
+
case "bot":
|
|
129
|
+
return undefined;
|
|
130
|
+
default:
|
|
131
|
+
return "hidden";
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Their own photo, or the public one they show when privacy hides it — never the one the owner set
|
|
136
|
+
* for them. Read from Telegram's fields: mtcute's `realPhoto` answers that personal one (0.32.3).
|
|
137
|
+
*/
|
|
138
|
+
const hasOwnPhoto = ({ full }) => full._ === "userFull" && (full.profilePhoto?._ === "photo" || full.fallbackPhoto?._ === "photo");
|
|
139
|
+
export const toProfileFacts = (full, chats) => {
|
|
140
|
+
const settings = full.peerSettings;
|
|
141
|
+
const birthday = full.birthday;
|
|
142
|
+
const usernames = (full.usernames ?? []).filter(({ active }) => active).map(({ username }) => username);
|
|
143
|
+
const seen = seenOf(full);
|
|
144
|
+
return {
|
|
145
|
+
id: String(full.id),
|
|
146
|
+
name: full.displayName || null,
|
|
147
|
+
usernames: usernames.length > 0 ? usernames : full.username ? [full.username] : [],
|
|
148
|
+
bio: full.bio || null,
|
|
149
|
+
birthday: birthday
|
|
150
|
+
? [birthday.day, birthday.month, birthday.year]
|
|
151
|
+
.filter((part) => part !== undefined)
|
|
152
|
+
.map((part, index) => (index < 2 ? String(part).padStart(2, "0") : String(part)))
|
|
153
|
+
.join(".")
|
|
154
|
+
: null,
|
|
155
|
+
phone: full.phoneNumber,
|
|
156
|
+
flags: {
|
|
157
|
+
bot: full.isBot,
|
|
158
|
+
verified: full.isVerified,
|
|
159
|
+
premium: full.isPremium,
|
|
160
|
+
scam: full.isScam,
|
|
161
|
+
fake: full.isFake,
|
|
162
|
+
restricted: full.isRestricted,
|
|
163
|
+
deleted: full.isDeleted,
|
|
164
|
+
support: full.isSupport,
|
|
165
|
+
},
|
|
166
|
+
...(seen === undefined ? {} : { seen }),
|
|
167
|
+
contact: full.isContact,
|
|
168
|
+
mutualContact: full.isMutualContact,
|
|
169
|
+
commonChatsCount: full.commonChatsCount,
|
|
170
|
+
registered: registrationOf(full.id, settings?._ === "peerSettings" ? settings.registrationMonth : undefined),
|
|
171
|
+
hasPhoto: hasOwnPhoto(full),
|
|
172
|
+
chats,
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
//# sourceMappingURL=profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../../src/telegram/profile.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,MAAM,SAAS,GAAgC;IAC7C,CAAC,CAAC,EAAE,SAAS,CAAC;IACd,CAAC,SAAS,EAAE,SAAS,CAAC;IACtB,CAAC,SAAS,EAAE,SAAS,CAAC;IACtB,CAAC,UAAU,EAAE,SAAS,CAAC;IACvB,CAAC,UAAU,EAAE,SAAS,CAAC;IACvB,CAAC,UAAU,EAAE,SAAS,CAAC;IACvB,CAAC,UAAU,EAAE,SAAS,CAAC;IACvB,CAAC,UAAU,EAAE,SAAS,CAAC;IACvB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1B,CAAC,aAAa,EAAE,SAAS,CAAC;IAC1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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type proxyTransportFromUrl } from "@mtcute/node";
|
|
2
|
+
import { CliError, type KeyringStore } from "@wirecat/cli-core";
|
|
3
|
+
import { type Settings } from "@wirecat/cli-messaging/cli";
|
|
4
|
+
import { type ProxyServer } from "../proxy.js";
|
|
5
|
+
type TelegramTransport = ReturnType<typeof proxyTransportFromUrl>;
|
|
6
|
+
export declare const PROXY_ENV = "TG_PROXY";
|
|
7
|
+
/**
|
|
8
|
+
* A proxy's password or MTProxy secret in the OS keyring, one per profile and one for `--defaults`:
|
|
9
|
+
* a profile locked with `TG_PROFILE_LOCK` must not be able to change another profile's password.
|
|
10
|
+
* `undefined` is the defaults; the two namespaces keep a profile named "defaults" apart from them.
|
|
11
|
+
*/
|
|
12
|
+
export declare const proxySecrets: ({ env, keyring }: {
|
|
13
|
+
env?: NodeJS.ProcessEnv;
|
|
14
|
+
keyring?: KeyringStore;
|
|
15
|
+
}) => {
|
|
16
|
+
read: (profile: string | undefined) => string | undefined;
|
|
17
|
+
write: (profile: string | undefined, secret: string) => import("@wirecat/cli-core").CredentialSource;
|
|
18
|
+
remove: (profile: string | undefined) => import("@wirecat/cli-core").CredentialSource[];
|
|
19
|
+
};
|
|
20
|
+
export interface ProxyInUse {
|
|
21
|
+
proxy: ProxyServer;
|
|
22
|
+
/** `TG_PROXY`, `config file` or `config defaults`. */
|
|
23
|
+
from: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* `TG_PROXY` over the profile's `proxy` setting. `ALL_PROXY` and `HTTPS_PROXY` are not read: they
|
|
27
|
+
* are set for other tools, and a personal account sent through a work proxy nobody chose for it
|
|
28
|
+
* would be a surprise found late.
|
|
29
|
+
*/
|
|
30
|
+
export declare const resolveProxy: (settings: Pick<Settings, "profile" | "configured" | "shared">, { env, keyring }?: {
|
|
31
|
+
env?: NodeJS.ProcessEnv;
|
|
32
|
+
keyring?: KeyringStore;
|
|
33
|
+
}) => ProxyInUse | undefined;
|
|
34
|
+
/** Builds the transport once, so `config set` refuses an MTProxy secret the connection would refuse. */
|
|
35
|
+
export declare const checkProxy: (proxy: ProxyServer) => void;
|
|
36
|
+
/** Why a connection through the proxy failed, in words that never carry its password or secret. */
|
|
37
|
+
export declare const proxyFailure: (proxy: ProxyServer, error: unknown) => CliError;
|
|
38
|
+
/**
|
|
39
|
+
* mtcute reconnects through a dead proxy until the command's deadline, which reads as "Telegram did
|
|
40
|
+
* not answer" (measured 2026-10-04 against a closed port). The first failure before any connection
|
|
41
|
+
* worked ends the wait instead: by then the proxy, not Telegram, is the likely fault.
|
|
42
|
+
*/
|
|
43
|
+
export declare const proxiedTransport: (proxy: ProxyServer) => {
|
|
44
|
+
transport: TelegramTransport;
|
|
45
|
+
failed: Promise<never>;
|
|
46
|
+
};
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/telegram/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,qBAAqB,EAG3B,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,QAAQ,EAAe,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC5E,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AAEpE,OAAO,EAAE,KAAK,WAAW,EAAsC,MAAM,aAAa,CAAA;AAElF,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAEjE,eAAO,MAAM,SAAS,aAAa,CAAA;AAEnC;;;;GAIG;AACH,eAAO,MAAM,YAAY,qBAAoC;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,OAAO,CAAC,EAAE,YAAY,CAAA;CAAE;IAW5G,IAAI,YAAY,MAAM,GAAG,SAAS;IAClC,KAAK,YAAY,MAAM,GAAG,SAAS,UAAU,MAAM;IACnD,MAAM,YAAY,MAAM,GAAG,SAAS;CAEvC,CAAA;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,WAAW,CAAA;IAClB,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,aACb,IAAI,CAAC,QAAQ,EAAE,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC,qBAC7B;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,OAAO,CAAC,EAAE,YAAY,CAAA;CAAE,KAClF,UAAU,GAAG,SAcf,CAAA;AAsBD,wGAAwG;AACxG,eAAO,MAAM,UAAU,UAAW,WAAW,KAAG,IAE/C,CAAA;AAED,mGAAmG;AACnG,eAAO,MAAM,YAAY,UAAW,WAAW,SAAS,OAAO,KAAG,QAUjE,CAAA;AAID;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,UAAW,WAAW,KAAG;IAAE,SAAS,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;CAoB3G,CAAA"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { HttpProxyConnectionError, HttpProxyTcpTransport, MtProxyTcpTransport, SocksProxyConnectionError, SocksProxyTcpTransport, } from "@mtcute/node";
|
|
2
|
+
import { CliError, Credentials } from "@wirecat/cli-core";
|
|
3
|
+
import { fromFile } from "@wirecat/cli-messaging/cli";
|
|
4
|
+
import { APP, isolated, pathsFor } from "../paths.js";
|
|
5
|
+
import { parseProxy, proxyError, proxyLabel } from "../proxy.js";
|
|
6
|
+
export const PROXY_ENV = "TG_PROXY";
|
|
7
|
+
/**
|
|
8
|
+
* A proxy's password or MTProxy secret in the OS keyring, one per profile and one for `--defaults`:
|
|
9
|
+
* a profile locked with `TG_PROFILE_LOCK` must not be able to change another profile's password.
|
|
10
|
+
* `undefined` is the defaults; the two namespaces keep a profile named "defaults" apart from them.
|
|
11
|
+
*/
|
|
12
|
+
export const proxySecrets = ({ env = process.env, keyring }) => {
|
|
13
|
+
const store = new Credentials({
|
|
14
|
+
configDir: pathsFor(env).config,
|
|
15
|
+
service: APP,
|
|
16
|
+
isolated: isolated(env),
|
|
17
|
+
env,
|
|
18
|
+
...(keyring ? { keyring } : {}),
|
|
19
|
+
});
|
|
20
|
+
const account = (profile) => profile === undefined ? "proxy:defaults" : `proxy:profile:${profile}`;
|
|
21
|
+
return {
|
|
22
|
+
read: (profile) => store.read(account(profile))?.secret,
|
|
23
|
+
write: (profile, secret) => store.write(account(profile), secret),
|
|
24
|
+
remove: (profile) => store.remove(account(profile)),
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* `TG_PROXY` over the profile's `proxy` setting. `ALL_PROXY` and `HTTPS_PROXY` are not read: they
|
|
29
|
+
* are set for other tools, and a personal account sent through a work proxy nobody chose for it
|
|
30
|
+
* would be a surprise found late.
|
|
31
|
+
*/
|
|
32
|
+
export const resolveProxy = (settings, { env = process.env, keyring } = {}) => {
|
|
33
|
+
const given = env[PROXY_ENV]?.trim();
|
|
34
|
+
if (given)
|
|
35
|
+
return { proxy: parseProxy(given, PROXY_ENV), from: PROXY_ENV };
|
|
36
|
+
const { value, from } = fromFile(settings, "proxy", undefined);
|
|
37
|
+
if (value === undefined)
|
|
38
|
+
return undefined;
|
|
39
|
+
const proxy = parseProxy(value, "the proxy setting");
|
|
40
|
+
const secrets = proxySecrets({ env, ...(keyring ? { keyring } : {}) });
|
|
41
|
+
const secret = secrets.read(settings.profile) ?? (from === "config defaults" ? secrets.read(undefined) : undefined);
|
|
42
|
+
if (proxy.kind === "mtproxy" && !secret)
|
|
43
|
+
throw new CliError("configuration_error", `no secret is stored for the MTProxy ${proxyLabel(proxy)} — run \`tg config set proxy -\` again`);
|
|
44
|
+
return { proxy: secret ? { ...proxy, secret } : proxy, from };
|
|
45
|
+
};
|
|
46
|
+
const transportOf = (proxy) => {
|
|
47
|
+
const auth = {
|
|
48
|
+
...(proxy.user === undefined ? {} : { user: proxy.user }),
|
|
49
|
+
...(proxy.secret === undefined ? {} : { password: proxy.secret }),
|
|
50
|
+
};
|
|
51
|
+
switch (proxy.kind) {
|
|
52
|
+
case "socks5":
|
|
53
|
+
return new SocksProxyTcpTransport({ version: 5, host: proxy.host, port: proxy.port, ...auth });
|
|
54
|
+
case "http":
|
|
55
|
+
return new HttpProxyTcpTransport({ host: proxy.host, port: proxy.port, tls: proxy.tls, ...auth });
|
|
56
|
+
case "mtproxy":
|
|
57
|
+
try {
|
|
58
|
+
return new MtProxyTcpTransport({ host: proxy.host, port: proxy.port, secret: proxy.secret ?? "" });
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// mtcute's words would be "Telegram answered with something unexpected"; the secret is what was wrong.
|
|
62
|
+
throw new CliError("configuration_error", `the MTProxy ${proxyLabel(proxy)} has a secret tg cannot read`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
/** Builds the transport once, so `config set` refuses an MTProxy secret the connection would refuse. */
|
|
67
|
+
export const checkProxy = (proxy) => {
|
|
68
|
+
transportOf(proxy);
|
|
69
|
+
};
|
|
70
|
+
/** Why a connection through the proxy failed, in words that never carry its password or secret. */
|
|
71
|
+
export const proxyFailure = (proxy, error) => {
|
|
72
|
+
const code = error?.code;
|
|
73
|
+
return proxyError(proxy, error instanceof SocksProxyConnectionError || error instanceof HttpProxyConnectionError
|
|
74
|
+
? `refused: ${hidden(error.message.replace(/^Error while connecting to [^:]+:\d+: /, ""), proxy)}`
|
|
75
|
+
: typeof code === "string"
|
|
76
|
+
? `cannot be reached (${code})`
|
|
77
|
+
: "did not let tg through");
|
|
78
|
+
};
|
|
79
|
+
const hidden = (text, proxy) => (proxy.secret ? text.split(proxy.secret).join("[redacted]") : text);
|
|
80
|
+
/**
|
|
81
|
+
* mtcute reconnects through a dead proxy until the command's deadline, which reads as "Telegram did
|
|
82
|
+
* not answer" (measured 2026-10-04 against a closed port). The first failure before any connection
|
|
83
|
+
* worked ends the wait instead: by then the proxy, not Telegram, is the likely fault.
|
|
84
|
+
*/
|
|
85
|
+
export const proxiedTransport = (proxy) => {
|
|
86
|
+
const transport = transportOf(proxy);
|
|
87
|
+
const connect = transport.connect.bind(transport);
|
|
88
|
+
let worked = false;
|
|
89
|
+
let fail = () => { };
|
|
90
|
+
const failed = new Promise((_, reject) => {
|
|
91
|
+
fail = reject;
|
|
92
|
+
});
|
|
93
|
+
failed.catch(() => { });
|
|
94
|
+
transport.connect = async (dc, signal) => {
|
|
95
|
+
try {
|
|
96
|
+
const connection = await connect(dc, signal);
|
|
97
|
+
worked = true;
|
|
98
|
+
return connection;
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
if (!worked && !signal.aborted)
|
|
102
|
+
fail(proxyFailure(proxy, error));
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
return { transport, failed };
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/telegram/proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ApiCredentials } from "./credentials.js";
|
|
2
|
+
/**
|
|
3
|
+
* Registers the owner's app on my.telegram.org and reads its `api_id` and `api_hash` — the same
|
|
4
|
+
* page a person would fill in, driven without a browser.
|
|
5
|
+
*
|
|
6
|
+
* ⚠ The site has no API; this follows its web form. The login half is read from the page's own
|
|
7
|
+
* script (2026-09-27): `send_password {phone}` answers `{random_hash}`, `login {phone, random_hash,
|
|
8
|
+
* password}` answers `true` and sets the session cookie. The app half — the `/apps` page and
|
|
9
|
+
* `/apps/create` — is behind that login and was read from two clients that drive it the same way,
|
|
10
|
+
* MadelineProto (`src/MyTelegramOrgWrapper.php`) and gogram (`telegram/auth.go`). Not measured by
|
|
11
|
+
* us until the first real run.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MY_TELEGRAM = "https://my.telegram.org";
|
|
14
|
+
export interface RegistrationPrompts {
|
|
15
|
+
phone: () => Promise<string>;
|
|
16
|
+
/** The code my.telegram.org sends as a message from Telegram — not an SMS, not the login code. */
|
|
17
|
+
code: () => Promise<string>;
|
|
18
|
+
note: (message: string) => void;
|
|
19
|
+
}
|
|
20
|
+
type Fetch = (url: string, init: RequestInit) => Promise<Response>;
|
|
21
|
+
export declare const registerApp: (prompts: RegistrationPrompts, { fetch: request, shortName, signal, }?: {
|
|
22
|
+
fetch?: Fetch;
|
|
23
|
+
shortName?: string;
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}) => Promise<ApiCredentials & {
|
|
26
|
+
created: boolean;
|
|
27
|
+
}>;
|
|
28
|
+
/** The app's page, or `undefined` when the account has no app yet. */
|
|
29
|
+
export declare const readApp: (html: string) => ApiCredentials | undefined;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=registration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../../src/telegram/registration.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEtD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW,4BAA4B,CAAA;AAEpD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;IAC5B,kGAAkG;IAClG,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;IAC3B,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAED,KAAK,KAAK,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAElE,eAAO,MAAM,WAAW,YACb,mBAAmB,2CAKzB;IAAE,KAAK,CAAC,EAAE,KAAK,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,KAC7D,OAAO,CAAC,cAAc,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAsD/C,CAAA;AAWD,sEAAsE;AACtE,eAAO,MAAM,OAAO,SAAU,MAAM,KAAG,cAAc,GAAG,SAOvD,CAAA"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { CliError, singleLine } from "@wirecat/cli-core";
|
|
3
|
+
/**
|
|
4
|
+
* Registers the owner's app on my.telegram.org and reads its `api_id` and `api_hash` — the same
|
|
5
|
+
* page a person would fill in, driven without a browser.
|
|
6
|
+
*
|
|
7
|
+
* ⚠ The site has no API; this follows its web form. The login half is read from the page's own
|
|
8
|
+
* script (2026-09-27): `send_password {phone}` answers `{random_hash}`, `login {phone, random_hash,
|
|
9
|
+
* password}` answers `true` and sets the session cookie. The app half — the `/apps` page and
|
|
10
|
+
* `/apps/create` — is behind that login and was read from two clients that drive it the same way,
|
|
11
|
+
* MadelineProto (`src/MyTelegramOrgWrapper.php`) and gogram (`telegram/auth.go`). Not measured by
|
|
12
|
+
* us until the first real run.
|
|
13
|
+
*/
|
|
14
|
+
export const MY_TELEGRAM = "https://my.telegram.org";
|
|
15
|
+
export const registerApp = async (prompts, { fetch: request = fetch, shortName = randomShortName(), signal, } = {}) => {
|
|
16
|
+
const cookies = new Map();
|
|
17
|
+
const call = async (path, form) => {
|
|
18
|
+
const response = await request(`${MY_TELEGRAM}${path}`, {
|
|
19
|
+
method: form ? "POST" : "GET",
|
|
20
|
+
headers: {
|
|
21
|
+
...(form ? { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" } : {}),
|
|
22
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
23
|
+
Origin: MY_TELEGRAM,
|
|
24
|
+
Referer: `${MY_TELEGRAM}${path.startsWith("/apps") ? "/apps" : "/auth"}`,
|
|
25
|
+
...(cookies.size > 0 ? { Cookie: [...cookies].map(([name, value]) => `${name}=${value}`).join("; ") } : {}),
|
|
26
|
+
},
|
|
27
|
+
...(form ? { body: new URLSearchParams(form).toString() } : {}),
|
|
28
|
+
redirect: "manual",
|
|
29
|
+
...(signal === undefined ? {} : { signal }),
|
|
30
|
+
});
|
|
31
|
+
for (const line of response.headers.getSetCookie()) {
|
|
32
|
+
const [pair] = line.split(";");
|
|
33
|
+
const at = pair?.indexOf("=") ?? -1;
|
|
34
|
+
if (pair && at > 0)
|
|
35
|
+
cookies.set(pair.slice(0, at).trim(), pair.slice(at + 1).trim());
|
|
36
|
+
}
|
|
37
|
+
return { status: response.status, text: await response.text() };
|
|
38
|
+
};
|
|
39
|
+
const phone = (await prompts.phone()).trim();
|
|
40
|
+
const sent = await call("/auth/send_password", { phone });
|
|
41
|
+
const randomHash = parseRandomHash(sent.text);
|
|
42
|
+
prompts.note("my.telegram.org sent a code as a message from Telegram — open the Telegram app to read it");
|
|
43
|
+
const login = await call("/auth/login", { phone, random_hash: randomHash, password: (await prompts.code()).trim() });
|
|
44
|
+
if (login.text.trim() !== "true") {
|
|
45
|
+
throw new CliError("authentication_error", `my.telegram.org refused the code: ${siteSays(login.text)}`);
|
|
46
|
+
}
|
|
47
|
+
const page = await call("/apps");
|
|
48
|
+
const existing = readApp(page.text);
|
|
49
|
+
if (existing)
|
|
50
|
+
return { ...existing, created: false };
|
|
51
|
+
const hash = creationHash(page.text);
|
|
52
|
+
const created = await call("/apps/create", {
|
|
53
|
+
hash,
|
|
54
|
+
app_title: "tg-cli",
|
|
55
|
+
app_shortname: shortName,
|
|
56
|
+
app_url: "https://github.com/WireCatLabs/tg-cli",
|
|
57
|
+
app_platform: "desktop",
|
|
58
|
+
app_desc: "A command line interface for my own account",
|
|
59
|
+
});
|
|
60
|
+
if (created.text.trim() !== "") {
|
|
61
|
+
throw new CliError("provider_error", `my.telegram.org did not create the app: ${siteSays(created.text)}`);
|
|
62
|
+
}
|
|
63
|
+
const app = readApp((await call("/apps")).text);
|
|
64
|
+
if (!app)
|
|
65
|
+
throw new CliError("invalid_response", "my.telegram.org says the app was created, but its page shows none");
|
|
66
|
+
return { ...app, created: true };
|
|
67
|
+
};
|
|
68
|
+
const parseRandomHash = (text) => {
|
|
69
|
+
try {
|
|
70
|
+
const hash = JSON.parse(text).random_hash;
|
|
71
|
+
if (typeof hash === "string" && hash !== "")
|
|
72
|
+
return hash;
|
|
73
|
+
}
|
|
74
|
+
catch { }
|
|
75
|
+
const said = siteSays(text);
|
|
76
|
+
throw new CliError(/too many/i.test(said) ? "rate_limited" : "provider_error", `my.telegram.org: ${said}`);
|
|
77
|
+
};
|
|
78
|
+
/** The app's page, or `undefined` when the account has no app yet. */
|
|
79
|
+
export const readApp = (html) => {
|
|
80
|
+
const id = /<label for="app_id"[^>]*>[\s\S]*?<\/label>\s*<div[^>]*>\s*<span[^>]*><strong>(\d+)<\/strong><\/span>/.exec(html);
|
|
81
|
+
const hash = /<label for="app_hash"[^>]*>[\s\S]*?<\/label>\s*<div[^>]*>\s*<span[^>]*>([a-fA-F0-9]+)<\/span>/.exec(html);
|
|
82
|
+
return id?.[1] && hash?.[1] ? { id: Number(id[1]), hash: hash[1] } : undefined;
|
|
83
|
+
};
|
|
84
|
+
const creationHash = (html) => {
|
|
85
|
+
const hash = /<input type="hidden" name="hash" value="([a-fA-F0-9]+)"\s*\/?>/.exec(html)?.[1];
|
|
86
|
+
if (hash)
|
|
87
|
+
return hash;
|
|
88
|
+
const title = /<title>([^<]*)<\/title>/.exec(html)?.[1];
|
|
89
|
+
throw new CliError("invalid_response", `my.telegram.org showed a page this does not know (${singleLine(title ?? "no title")}) — create the app by hand with --app browser`);
|
|
90
|
+
};
|
|
91
|
+
/** App short names are letters and digits; a random tail keeps two profiles from colliding. */
|
|
92
|
+
const randomShortName = () => `tgcli${[...randomBytes(6)].map((byte) => "abcdefghijklmnopqrstuvwxyz0123456789"[byte % 36]).join("")}`;
|
|
93
|
+
/** The site answers errors as a short plain sentence; keep it one line and short. */
|
|
94
|
+
const siteSays = (text) => singleLine(text.replace(/<[^>]+>/g, " ").trim()).slice(0, 200) || "(empty answer)";
|
|
95
|
+
//# sourceMappingURL=registration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registration.js","sourceRoot":"","sources":["../../src/telegram/registration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type TelegramClient } from "@mtcute/node";
|
|
2
|
+
import type { SenderIdentity } from "@wirecat/cli-messaging";
|
|
3
|
+
type Client = Pick<TelegramClient, "getMe" | "getFullChat" | "resolvePeer" | "call">;
|
|
4
|
+
/**
|
|
5
|
+
* Reads only. `messages.saveDefaultSendAs` would change the chat's saved choice for every client of
|
|
6
|
+
* the account, so the choice is made per send instead.
|
|
7
|
+
*/
|
|
8
|
+
export declare const sendAsIdentities: (client: Client, chatId: string) => Promise<SenderIdentity[]>;
|
|
9
|
+
/**
|
|
10
|
+
* The group's saved default sender, when it is not the account: Telegram posts as it when a send names none
|
|
11
|
+
* (measured 2026-10-07: a comment went out as the linked channel). One request, a supergroup only.
|
|
12
|
+
*/
|
|
13
|
+
export declare const savedSenderOf: (client: Pick<TelegramClient, "getFullChat">, chatId: string, self: string | null) => Promise<string | null>;
|
|
14
|
+
/** Telegram takes `send_as` in channels and supergroups only; elsewhere the account is the one author. */
|
|
15
|
+
export declare const sendAsPeer: (chatId: string, sendAs: string, self: string | null) => number | undefined;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=send-as.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-as.d.ts","sourceRoot":"","sources":["../../src/telegram/send-as.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,KAAK,cAAc,EAAM,MAAM,cAAc,CAAA;AAErG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAE5D,KAAK,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,aAAa,GAAG,aAAa,GAAG,MAAM,CAAC,CAAA;AAEpF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,WAAkB,MAAM,UAAU,MAAM,KAAG,OAAO,CAAC,cAAc,EAAE,CA8B/F,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,WAChB,IAAI,CAAC,cAAc,EAAE,aAAa,CAAC,UACnC,MAAM,QACR,MAAM,GAAG,IAAI,KAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAMvB,CAAA;AAED,0GAA0G;AAC1G,eAAO,MAAM,UAAU,WAAY,MAAM,UAAU,MAAM,QAAQ,MAAM,GAAG,IAAI,KAAG,MAAM,GAAG,SAOzF,CAAA"}
|