(function attachBackgroundStep9(root, factory) { root.MultiPageBackgroundStep9 = factory(); })(typeof self !== 'undefined' ? self : globalThis, function createBackgroundStep9Module() { function createStep9Executor(deps = {}) { const { addLog, chrome, cleanupStep8NavigationListeners, clickWithDebugger, completeNodeFromBackground, ensureStep8SignupPageReady, getOAuthFlowRemainingMs, getOAuthFlowStepTimeoutMs, getStep8CallbackUrlFromNavigation, getStep8CallbackUrlFromTabUpdate, getStep8EffectLabel, getTabId, isTabAlive, prepareStep8DebuggerClick, recoverOAuthLocalhostTimeout, reloadStep8ConsentPage, reuseOrCreateTab, sleepWithStop, STEP8_CLICK_RETRY_DELAY_MS, STEP8_MAX_ROUNDS, STEP8_READY_WAIT_TIMEOUT_MS, STEP8_STRATEGIES, throwIfStep8SettledOrStopped, triggerStep8ContentStrategy, waitForStep8ClickEffect, waitForStep8Ready, setWebNavListener, setWebNavCommittedListener, setStep8PendingReject, setStep8TabUpdatedListener, shouldDeferStep9CallbackTimeout, getStepIdByKeyForState = null, } = deps; const LOCALHOST_CALLBACK_LOCAL_TIMEOUT_MS = 240000; const CALLBACK_TIMEOUT_CHECK_INTERVAL_MS = 1000; function getVisibleStep(state, fallback = 9) { const visibleStep = Math.floor(Number(state?.visibleStep) || 0); return visibleStep > 0 ? visibleStep : fallback; } function getAuthLoginStepForVisibleStep(visibleStep) { return visibleStep >= 12 ? Math.max(1, visibleStep - 3) : 7; } function getAuthLoginStepForState(state = {}, visibleStep = 9) { const authStep = typeof getStepIdByKeyForState === 'function' ? Number(getStepIdByKeyForState('oauth-login', state)) : 0; if (Number.isInteger(authStep) && authStep > 0) { return authStep; } return getAuthLoginStepForVisibleStep(visibleStep); } function addStepLog(step, message, level = 'info') { return addLog(message, level, { step, stepKey: 'confirm-oauth' }); } async function executeStep9(state) { const visibleStep = getVisibleStep(state, 9); let activeState = state; if (!activeState.oauthUrl) { const authLoginStep = getAuthLoginStepForState(activeState, visibleStep); throw new Error(`缺少登录用 OAuth 链接,请先完成步骤 ${authLoginStep}。`); } await addStepLog(visibleStep, '正在监听 localhost 回调地址...'); let callbackTimeoutMs = LOCALHOST_CALLBACK_LOCAL_TIMEOUT_MS; let timeoutRecoveryAttempted = false; while (true) { try { callbackTimeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function' ? await getOAuthFlowStepTimeoutMs(LOCALHOST_CALLBACK_LOCAL_TIMEOUT_MS, { step: visibleStep, actionLabel: 'OAuth localhost 回调', oauthUrl: activeState?.oauthUrl || '', }) : LOCALHOST_CALLBACK_LOCAL_TIMEOUT_MS; break; } catch (error) { if (timeoutRecoveryAttempted || typeof recoverOAuthLocalhostTimeout !== 'function') { throw error; } const recoveredState = await recoverOAuthLocalhostTimeout({ error, state: activeState, visibleStep, }); if (!recoveredState) { throw error; } activeState = recoveredState; timeoutRecoveryAttempted = true; } } return new Promise((resolve, reject) => { let resolved = false; let signupTabId = null; const callbackWaitStartedAt = Date.now(); let timeoutCheckTimer = null; let timeoutDeferredLogged = false; const cleanupListener = () => { if (timeoutCheckTimer) { clearTimeout(timeoutCheckTimer); timeoutCheckTimer = null; } cleanupStep8NavigationListeners(); setStep8PendingReject(null); }; const rejectStep9 = (error) => { if (resolved) return; resolved = true; cleanupListener(); reject(error); }; const finalizeStep9Callback = (callbackUrl) => { if (resolved || !callbackUrl) return; resolved = true; cleanupListener(); addStepLog(visibleStep, `已捕获 localhost 地址:${callbackUrl}`, 'ok').then(() => { return completeNodeFromBackground(state?.nodeId || 'confirm-oauth', { localhostUrl: callbackUrl }); }).then(() => { resolve(); }).catch((err) => { reject(err); }); }; const isCallbackTimeoutDeferred = async (elapsedMs) => { if (typeof shouldDeferStep9CallbackTimeout !== 'function') { return false; } try { const deferred = await shouldDeferStep9CallbackTimeout({ tabId: signupTabId, visibleStep, elapsedMs, oauthUrl: activeState?.oauthUrl || '', }); if (deferred && !timeoutDeferredLogged) { timeoutDeferredLogged = true; await addStepLog( visibleStep, '检测到认证页仍在安全验证/授权跳转中,暂停本地回调超时判定,继续等待 localhost 回调...', 'info' ); } return Boolean(deferred); } catch (error) { await addStepLog( visibleStep, `复核认证页跳转状态失败(${error?.message || error}),继续按原超时规则等待回调。`, 'warn' ); return false; } }; const checkCallbackTimeout = async () => { if (resolved) { return; } const elapsedMs = Date.now() - callbackWaitStartedAt; if (await isCallbackTimeoutDeferred(elapsedMs)) { timeoutCheckTimer = setTimeout(checkCallbackTimeout, CALLBACK_TIMEOUT_CHECK_INTERVAL_MS); return; } if (elapsedMs >= LOCALHOST_CALLBACK_LOCAL_TIMEOUT_MS) { rejectStep9(new Error(`${Math.round(LOCALHOST_CALLBACK_LOCAL_TIMEOUT_MS / 1000)} 秒内未捕获到 localhost 回调跳转,步骤 ${visibleStep} 的点击可能被拦截了。`)); return; } if (typeof getOAuthFlowRemainingMs === 'function') { try { await getOAuthFlowRemainingMs({ step: visibleStep, actionLabel: 'OAuth localhost 回调', oauthUrl: activeState?.oauthUrl || '', }); } catch (error) { rejectStep9(error); return; } } else if (elapsedMs >= callbackTimeoutMs) { rejectStep9(new Error(`${Math.round(callbackTimeoutMs / 1000)} 秒内未捕获到 localhost 回调跳转,步骤 ${visibleStep} 的点击可能被拦截了。`)); return; } timeoutCheckTimer = setTimeout(checkCallbackTimeout, CALLBACK_TIMEOUT_CHECK_INTERVAL_MS); }; timeoutCheckTimer = setTimeout( checkCallbackTimeout, Math.min(CALLBACK_TIMEOUT_CHECK_INTERVAL_MS, Math.max(1, callbackTimeoutMs)) ); setStep8PendingReject((error) => { rejectStep9(error); }); setWebNavListener((details) => { const callbackUrl = getStep8CallbackUrlFromNavigation(details, signupTabId); finalizeStep9Callback(callbackUrl); }); setWebNavCommittedListener((details) => { const callbackUrl = getStep8CallbackUrlFromNavigation(details, signupTabId); finalizeStep9Callback(callbackUrl); }); setStep8TabUpdatedListener((tabId, changeInfo, tab) => { const callbackUrl = getStep8CallbackUrlFromTabUpdate(tabId, changeInfo, tab, signupTabId); finalizeStep9Callback(callbackUrl); }); (async () => { try { throwIfStep8SettledOrStopped(resolved); signupTabId = await getTabId('openai-auth'); throwIfStep8SettledOrStopped(resolved); if (signupTabId && await isTabAlive('openai-auth')) { await chrome.tabs.update(signupTabId, { active: true }); await addStepLog(visibleStep, '已切回认证页,正在准备调试器点击...'); } else { signupTabId = await reuseOrCreateTab('openai-auth', activeState.oauthUrl); await addStepLog(visibleStep, '已重新打开认证页,正在准备调试器点击...'); } throwIfStep8SettledOrStopped(resolved); chrome.webNavigation.onBeforeNavigate.addListener(deps.getWebNavListener()); chrome.webNavigation.onCommitted.addListener(deps.getWebNavCommittedListener()); chrome.tabs.onUpdated.addListener(deps.getStep8TabUpdatedListener()); await ensureStep8SignupPageReady(signupTabId, { timeoutMs: typeof getOAuthFlowStepTimeoutMs === 'function' ? await getOAuthFlowStepTimeoutMs(15000, { step: visibleStep, actionLabel: '等待 OAuth 同意页内容脚本就绪', }) : 15000, visibleStep, logStepKey: 'confirm-oauth', logMessage: '认证页内容脚本尚未就绪,正在等待页面恢复...', }); for (let round = 1; round <= STEP8_MAX_ROUNDS && !resolved; round++) { throwIfStep8SettledOrStopped(resolved); const pageState = await waitForStep8Ready( signupTabId, typeof getOAuthFlowStepTimeoutMs === 'function' ? await getOAuthFlowStepTimeoutMs(STEP8_READY_WAIT_TIMEOUT_MS, { step: visibleStep, actionLabel: '等待 OAuth 同意页出现', }) : STEP8_READY_WAIT_TIMEOUT_MS, { visibleStep } ); if (!pageState?.consentReady) { await sleepWithStop(STEP8_CLICK_RETRY_DELAY_MS); continue; } const strategy = STEP8_STRATEGIES[Math.min(round - 1, STEP8_STRATEGIES.length - 1)]; await addStepLog(visibleStep, `第 ${round}/${STEP8_MAX_ROUNDS} 轮尝试点击“继续”(${strategy.label})...`); if (strategy.mode === 'debugger') { const clickActionTimeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function' ? await getOAuthFlowStepTimeoutMs(15000, { step: visibleStep, actionLabel: '定位 OAuth 同意页继续按钮', }) : 15000; const clickTarget = await prepareStep8DebuggerClick(signupTabId, { timeoutMs: clickActionTimeoutMs, responseTimeoutMs: clickActionTimeoutMs, visibleStep, }); throwIfStep8SettledOrStopped(resolved); await clickWithDebugger(signupTabId, clickTarget?.rect, { visibleStep }); } else { const clickActionTimeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function' ? await getOAuthFlowStepTimeoutMs(15000, { step: visibleStep, actionLabel: '点击 OAuth 同意页继续按钮', }) : 15000; await triggerStep8ContentStrategy(signupTabId, strategy.strategy, { timeoutMs: clickActionTimeoutMs, responseTimeoutMs: clickActionTimeoutMs, visibleStep, }); } if (resolved) { return; } const effect = await waitForStep8ClickEffect( signupTabId, pageState.url, typeof getOAuthFlowStepTimeoutMs === 'function' ? await getOAuthFlowStepTimeoutMs(15000, { step: visibleStep, actionLabel: '等待 OAuth 同意页点击生效', }) : 15000, { visibleStep } ); if (resolved) { return; } if (effect.progressed) { await addStepLog(visibleStep, `检测到本次点击已生效,${getStep8EffectLabel(effect)},继续等待 localhost 回调...`, 'info'); break; } if (round >= STEP8_MAX_ROUNDS) { throw new Error(`步骤 ${visibleStep}:连续 ${STEP8_MAX_ROUNDS} 轮点击“继续”后页面仍无反应。`); } await addStepLog(visibleStep, `${strategy.label} 本轮点击后页面无反应,正在刷新认证页后重试(下一轮 ${round + 1}/${STEP8_MAX_ROUNDS})...`, 'warn'); await reloadStep8ConsentPage( signupTabId, typeof getOAuthFlowStepTimeoutMs === 'function' ? await getOAuthFlowStepTimeoutMs(30000, { step: visibleStep, actionLabel: '刷新 OAuth 同意页', }) : 30000, { visibleStep } ); await sleepWithStop(STEP8_CLICK_RETRY_DELAY_MS); } } catch (err) { rejectStep9(err); } })(); }); } return { executeStep9 }; } return { createStep9Executor }; });