(options: {
sessionKey: string;
timeoutMs?: number;
accountId?: string;
onQrRefresh?: (payload: { qrcodeUrl: string }) => void | Promise<void>;
})
| 371 | } |
| 372 | |
| 373 | export async function waitForWeChatLoginSession(options: { |
| 374 | sessionKey: string; |
| 375 | timeoutMs?: number; |
| 376 | accountId?: string; |
| 377 | onQrRefresh?: (payload: { qrcodeUrl: string }) => void | Promise<void>; |
| 378 | }): Promise<WeChatLoginWaitResult> { |
| 379 | const login = activeLogins.get(options.sessionKey); |
| 380 | if (!login) { |
| 381 | return { |
| 382 | connected: false, |
| 383 | message: 'No active WeChat login session. Generate a new QR code and try again.', |
| 384 | }; |
| 385 | } |
| 386 | |
| 387 | if (!isLoginFresh(login)) { |
| 388 | activeLogins.delete(options.sessionKey); |
| 389 | return { |
| 390 | connected: false, |
| 391 | message: 'The QR code has expired. Generate a new QR code and try again.', |
| 392 | }; |
| 393 | } |
| 394 | |
| 395 | const timeoutMs = Math.max(options.timeoutMs ?? 480_000, 1000); |
| 396 | const deadline = Date.now() + timeoutMs; |
| 397 | let qrRefreshCount = 1; |
| 398 | |
| 399 | while (Date.now() < deadline) { |
| 400 | const current = activeLogins.get(options.sessionKey); |
| 401 | if (!current) { |
| 402 | return { |
| 403 | connected: false, |
| 404 | message: 'The WeChat login session was cancelled.', |
| 405 | }; |
| 406 | } |
| 407 | |
| 408 | const statusResponse = await pollWeChatQrStatus(current.apiBaseUrl, current.qrcode, options.accountId); |
| 409 | switch (statusResponse.status) { |
| 410 | case 'wait': |
| 411 | case 'scaned': |
| 412 | break; |
| 413 | case 'expired': { |
| 414 | qrRefreshCount += 1; |
| 415 | if (qrRefreshCount > MAX_QR_REFRESH_COUNT) { |
| 416 | activeLogins.delete(options.sessionKey); |
| 417 | return { |
| 418 | connected: false, |
| 419 | message: 'The QR code expired too many times. Generate a new QR code and try again.', |
| 420 | }; |
| 421 | } |
| 422 | const refreshedQr = await fetchWeChatQrCode(current.apiBaseUrl, options.accountId); |
| 423 | const refreshedQrDataUrl = await renderQrPngDataUrl(refreshedQr.qrcode_img_content); |
| 424 | activeLogins.set(options.sessionKey, { |
| 425 | ...current, |
| 426 | qrcode: refreshedQr.qrcode, |
| 427 | qrcodeUrl: refreshedQrDataUrl, |
| 428 | startedAt: Date.now(), |
| 429 | }); |
| 430 | await options.onQrRefresh?.({ qrcodeUrl: refreshedQrDataUrl }); |
no test coverage detected