/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { TELEGRAM_BIND_RESULT_MESSAGE } from '@/features/auth/constants' interface TimerRuntime { schedule: (callback: () => void, delay: number) => unknown cancel: (handle: unknown) => void } const timeoutRuntime: TimerRuntime = { schedule: (callback, delay) => globalThis.setTimeout(callback, delay), cancel: (handle) => globalThis.clearTimeout(handle as ReturnType), } const intervalRuntime: TimerRuntime = { schedule: (callback, delay) => globalThis.setInterval(callback, delay), cancel: (handle) => globalThis.clearInterval( handle as ReturnType ), } interface TelegramBindCallbackSearch { telegram_bind?: string flow_token?: string error_code?: string } export type TelegramBindCallback = | { kind: 'result' flowToken: string success: boolean code?: string } | { kind: 'invalid' } | null export function parseTelegramBindCallback( search: TelegramBindCallbackSearch ): TelegramBindCallback { if (search.telegram_bind !== 'success' && search.telegram_bind !== 'error') { return null } if (!search.flow_token) return { kind: 'invalid' } if (search.telegram_bind === 'success') { return { kind: 'result', flowToken: search.flow_token, success: true, } } return { kind: 'result', flowToken: search.flow_token, success: false, code: search.error_code, } } export function postTelegramBindResult( callback: TelegramBindCallback, opener: Pick | null, targetOrigin: string ): boolean { if (callback?.kind !== 'result' || !opener || opener.closed) return false opener.postMessage( { type: TELEGRAM_BIND_RESULT_MESSAGE, flow_token: callback.flowToken, success: callback.success, code: callback.code, }, targetOrigin ) return true } export function startOAuthBindResponseDeadline( onTimeout: () => void, delay = 30_000, runtime: TimerRuntime = timeoutRuntime ): () => void { let active = true const handle = runtime.schedule(() => { if (!active) return active = false onTimeout() }, delay) return () => { if (!active) return active = false runtime.cancel(handle) } } export function watchOAuthPopupClosed( popup: Pick, onClosed: () => void, interval = 500, runtime: TimerRuntime = intervalRuntime ): () => void { let active = true const handle = runtime.schedule(() => { if (!active || !popup.closed) return active = false runtime.cancel(handle) onClosed() }, interval) return () => { if (!active) return active = false runtime.cancel(handle) } }