feat: detect and persist Telegram Premium status after authentication

After TDLib login completes, calls getMe() to detect isPremium, persists
it to DB via updateAccountPremiumStatus, and returns { client, isPremium }
from createTdlibClient. All callers updated to destructure accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-02 23:02:46 +02:00
parent f454303352
commit 436a576085
7 changed files with 38 additions and 13 deletions

View File

@@ -110,7 +110,7 @@ export async function processExtractRequest(requestId: string): Promise<void> {
} }
const account = accounts[0]; const account = accounts[0];
const client = await createTdlibClient({ id: account.id, phone: account.phone }); const { client } = await createTdlibClient({ id: account.id, phone: account.phone });
try { try {
// Load chat list so TDLib can find the dest channel // Load chat list so TDLib can find the dest channel

View File

@@ -162,7 +162,7 @@ function handleGenerateInvite(channelId: string): void {
} }
const account = accounts[0]; const account = accounts[0];
const client = await createTdlibClient({ id: account.id, phone: account.phone }); const { client } = await createTdlibClient({ id: account.id, phone: account.phone });
try { try {
const link = await generateInviteLink(client, destChannel.telegramId); const link = await generateInviteLink(client, destChannel.telegramId);
@@ -203,7 +203,7 @@ function handleCreateDestination(payload: string): void {
} }
const account = accounts[0]; const account = accounts[0];
const client = await createTdlibClient({ id: account.id, phone: account.phone }); const { client } = await createTdlibClient({ id: account.id, phone: account.phone });
try { try {
// Create the supergroup via TDLib // Create the supergroup via TDLib
@@ -337,7 +337,7 @@ function handleJoinChannel(payload: string): void {
throw new Error("No authenticated accounts available"); throw new Error("No authenticated accounts available");
} }
const client = await createTdlibClient({ id: account.id, phone: account.phone }); const { client } = await createTdlibClient({ id: account.id, phone: account.phone });
try { try {
const linkInfo = parseTelegramInput(parsed.input); const linkInfo = parseTelegramInput(parsed.input);

View File

@@ -49,7 +49,7 @@ export async function processManualUpload(uploadId: string): Promise<void> {
const account = accounts[0]; const account = accounts[0];
if (!account) throw new Error("No authenticated Telegram account available"); if (!account) throw new Error("No authenticated Telegram account available");
const client = await createTdlibClient({ id: account.id, phone: account.phone }); const { client } = await createTdlibClient({ id: account.id, phone: account.phone });
try { try {
const packageIds: string[] = []; const packageIds: string[] = [];

View File

@@ -63,7 +63,7 @@ export async function rebuildPackageDatabase(
} }
const account = accounts[0]; const account = accounts[0];
const client = await createTdlibClient({ const { client } = await createTdlibClient({
id: account.id, id: account.id,
phone: account.phone, phone: account.phone,
}); });

View File

@@ -63,7 +63,7 @@ export async function recoverIncompleteUploads(): Promise<void> {
let client: Client | undefined; let client: Client | undefined;
try { try {
client = await createTdlibClient({ id: account.id, phone: account.phone }); ({ client } = await createTdlibClient({ id: account.id, phone: account.phone }));
// Load the chat list so TDLib can resolve chat IDs // Load the chat list so TDLib can resolve chat IDs
try { try {

View File

@@ -6,6 +6,7 @@ import { childLogger } from "../util/logger.js";
import { import {
updateAccountAuthState, updateAccountAuthState,
getAccountAuthCode, getAccountAuthCode,
updateAccountPremiumStatus,
} from "../db/queries.js"; } from "../db/queries.js";
const log = childLogger("tdlib-client"); const log = childLogger("tdlib-client");
@@ -27,7 +28,7 @@ interface AccountConfig {
*/ */
export async function createTdlibClient( export async function createTdlibClient(
account: AccountConfig account: AccountConfig
): Promise<Client> { ): Promise<{ client: Client; isPremium: boolean }> {
const dbPath = path.join(config.tdlibStateDir, account.id); const dbPath = path.join(config.tdlibStateDir, account.id);
const client = createClient({ const client = createClient({
@@ -78,7 +79,30 @@ export async function createTdlibClient(
await updateAccountAuthState(account.id, "AUTHENTICATED"); await updateAccountAuthState(account.id, "AUTHENTICATED");
log.info({ accountId: account.id }, "TDLib client authenticated"); log.info({ accountId: account.id }, "TDLib client authenticated");
return client;
let isPremium = false;
try {
const me = await client.invoke({ _: "getMe" }) as { is_premium?: boolean };
isPremium = me.is_premium ?? false;
await updateAccountPremiumStatus(account.id, isPremium);
log.info({ accountId: account.id, isPremium }, "Account Premium status detected");
} catch (err) {
log.warn({ err, accountId: account.id }, "Could not detect Premium status, defaulting to false");
}
client.on("update", (update: unknown) => {
const u = update as { _?: string; is_upload?: boolean };
if (u?._ === "updateSpeedLimitNotification") {
log.warn(
{ accountId: account.id, isUpload: u.is_upload },
u.is_upload
? "Upload speed limited by Telegram (account is not Premium)"
: "Download speed limited by Telegram (account is not Premium)"
);
}
});
return { client, isPremium };
} catch (err) { } catch (err) {
log.error({ err, accountId: account.id }, "TDLib authentication failed"); log.error({ err, accountId: account.id }, "TDLib authentication failed");
await updateAccountAuthState(account.id, "EXPIRED"); await updateAccountAuthState(account.id, "EXPIRED");

View File

@@ -73,10 +73,10 @@ export async function authenticateAccount(
let client: Client | undefined; let client: Client | undefined;
try { try {
client = await createTdlibClient({ client = (await createTdlibClient({
id: account.id, id: account.id,
phone: account.phone, phone: account.phone,
}); })).client;
aLog.info("Authentication successful"); aLog.info("Authentication successful");
// Auto-fetch channels and create a fetch request result // Auto-fetch channels and create a fetch request result
@@ -131,7 +131,7 @@ export async function processFetchRequest(requestId: string): Promise<void> {
await updateFetchRequestStatus(requestId, "IN_PROGRESS"); await updateFetchRequestStatus(requestId, "IN_PROGRESS");
aLog.info({ accountId: request.accountId }, "Processing fetch request"); aLog.info({ accountId: request.accountId }, "Processing fetch request");
const client = await createTdlibClient({ const { client } = await createTdlibClient({
id: request.account.id, id: request.account.id,
phone: request.account.phone, phone: request.account.phone,
}); });
@@ -336,10 +336,11 @@ export async function runWorkerForAccount(
currentStep: "connecting", currentStep: "connecting",
}); });
const client = await createTdlibClient({ const { client, isPremium } = await createTdlibClient({
id: account.id, id: account.id,
phone: account.phone, phone: account.phone,
}); });
void isPremium; // will be used in Task 6 for upload limits
// Load all chats into TDLib's local cache using loadChats (the recommended API). // Load all chats into TDLib's local cache using loadChats (the recommended API).
// Without this, getChat/searchChatMessages fail with "Chat not found". // Without this, getChat/searchChatMessages fail with "Chat not found".