From ff8b86a03bb4fde18880ad219060b2eb4a245531 Mon Sep 17 00:00:00 2001 From: QLHazyCoder Date: Mon, 4 May 2026 04:54:21 +0800 Subject: [PATCH] refactor: route platform verification completion by step key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除平台验证完成后的 step 10/13 数字兜底收尾逻辑,统一由 platform-verify stepKey 入口处理。 - 调整 LuckMail 与 localhost 清理测试,改为验证 message-router 的语义路由入口。 - 保留平台验证成功后的账号、邮箱、手机号接码收尾能力,但不再依赖硬编码步骤号。 --- background.js | 50 ----- background/message-router.js | 58 ------ tests/background-luckmail.test.js | 194 +++++++------------- tests/step9-localhost-cleanup-scope.test.js | 25 ++- 4 files changed, 89 insertions(+), 238 deletions(-) diff --git a/background.js b/background.js index bf40315..4e15300 100644 --- a/background.js +++ b/background.js @@ -7816,56 +7816,6 @@ async function handleStepData(step, payload) { broadcastDataUpdate({ localhostUrl: payload.localhostUrl }); } break; - case 10: - case 13: { - if (payload.localhostUrl) { - await closeLocalhostCallbackTabs(payload.localhostUrl); - } - const latestState = await getState(); - const lastStepId = typeof getLastStepIdForState === 'function' - ? getLastStepIdForState(latestState) - : 10; - if (Number(step) !== Number(lastStepId)) { - break; - } - if (latestState.currentHotmailAccountId && isHotmailProvider(latestState)) { - await patchHotmailAccount(latestState.currentHotmailAccountId, { - used: true, - lastUsedAt: Date.now(), - }); - await addLog('当前 Hotmail 账号已自动标记为已用。', 'ok'); - } - if (isLuckmailProvider(latestState)) { - const currentPurchase = getCurrentLuckmailPurchase(latestState); - if (currentPurchase?.id) { - await setLuckmailPurchaseUsedState(currentPurchase.id, true); - await addLog(`当前 LuckMail 邮箱 ${currentPurchase.email_address} 已在本地标记为已用。`, 'ok'); - } - await clearLuckmailRuntimeState({ clearEmail: true }); - await addLog('当前 LuckMail 邮箱运行态已清空,下轮将优先复用未用邮箱或重新购买邮箱。', 'ok'); - } - const localhostPrefix = buildLocalhostCleanupPrefix(payload.localhostUrl); - if (localhostPrefix) { - await closeTabsByUrlPrefix(localhostPrefix, { - excludeUrls: [payload.localhostUrl], - excludeLocalhostCallbacks: true, - }); - } - await finalizeIcloudAliasAfterSuccessfulFlow(latestState); - if (typeof markCurrentCustomEmailPoolEntryUsed === 'function') { - await markCurrentCustomEmailPoolEntryUsed(latestState); - } - const shouldClearCustomPoolEmail = String(latestState?.emailGenerator || '').trim().toLowerCase() === ( - typeof CUSTOM_EMAIL_POOL_GENERATOR === 'string' - ? CUSTOM_EMAIL_POOL_GENERATOR - : 'custom-pool' - ); - if ((shouldUseCustomRegistrationEmail(latestState) || shouldClearCustomPoolEmail) && latestState.email) { - await setEmailStateSilently(null); - } - await finalizePhoneActivationAfterSuccessfulFlow(latestState); - break; - } } } diff --git a/background/message-router.js b/background/message-router.js index 4faa8d9..b829f90 100644 --- a/background/message-router.js +++ b/background/message-router.js @@ -386,64 +386,6 @@ broadcastDataUpdate({ localhostUrl: payload.localhostUrl }); } break; - case 10: - case 13: { - if (payload.localhostUrl) { - await closeLocalhostCallbackTabs(payload.localhostUrl); - } - const latestState = await getState(); - const lastStepId = typeof getLastStepIdForState === 'function' - ? getLastStepIdForState(latestState) - : 10; - if (Number(step) !== Number(lastStepId)) { - break; - } - if (typeof markCurrentRegistrationAccountUsed === 'function') { - await markCurrentRegistrationAccountUsed(latestState, { - logPrefix: '流程完成', - level: 'ok', - }); - } else if (latestState.currentHotmailAccountId && isHotmailProvider(latestState)) { - await patchHotmailAccount(latestState.currentHotmailAccountId, { - used: true, - lastUsedAt: Date.now(), - }); - await addLog('当前 Hotmail 账号已自动标记为已用。', 'ok'); - } - if (typeof markCurrentRegistrationAccountUsed !== 'function' && String(latestState.mailProvider || '').trim().toLowerCase() === '2925' && latestState.currentMail2925AccountId) { - await patchMail2925Account(latestState.currentMail2925AccountId, { - lastUsedAt: Date.now(), - lastError: '', - }); - await addLog('当前 2925 账号已记录最近使用时间。', 'ok'); - } - if (typeof markCurrentRegistrationAccountUsed !== 'function' && isLuckmailProvider(latestState)) { - const currentPurchase = getCurrentLuckmailPurchase(latestState); - if (currentPurchase?.id) { - await setLuckmailPurchaseUsedState(currentPurchase.id, true); - await addLog(`当前 LuckMail 邮箱 ${currentPurchase.email_address} 已在本地标记为已用。`, 'ok'); - } - await clearLuckmailRuntimeState({ clearEmail: true }); - await addLog('当前 LuckMail 邮箱运行态已清空,下轮将优先复用未用邮箱或重新购买邮箱。', 'ok'); - } - const localhostPrefix = buildLocalhostCleanupPrefix(payload.localhostUrl); - if (localhostPrefix) { - await closeTabsByUrlPrefix(localhostPrefix, { - excludeUrls: [payload.localhostUrl], - excludeLocalhostCallbacks: true, - }); - } - if (typeof markCurrentRegistrationAccountUsed !== 'function') { - await finalizeIcloudAliasAfterSuccessfulFlow(latestState); - } - if (typeof markCurrentRegistrationAccountUsed !== 'function' && typeof markCurrentCustomEmailPoolEntryUsed === 'function') { - await markCurrentCustomEmailPoolEntryUsed(latestState); - } - if (typeof finalizePhoneActivationAfterSuccessfulFlow === 'function') { - await finalizePhoneActivationAfterSuccessfulFlow(latestState); - } - break; - } default: break; } diff --git a/tests/background-luckmail.test.js b/tests/background-luckmail.test.js index 6f10a74..669cd28 100644 --- a/tests/background-luckmail.test.js +++ b/tests/background-luckmail.test.js @@ -3,6 +3,11 @@ const assert = require('node:assert/strict'); const fs = require('node:fs'); const source = fs.readFileSync('background.js', 'utf8'); +const messageRouterSource = fs.readFileSync('background/message-router.js', 'utf8'); +const messageRouterApi = new Function( + 'self', + `${messageRouterSource}; return self.MultiPageBackgroundMessageRouter;` +)({}); function extractFunction(name) { const markers = [`async function ${name}(`, `function ${name}(`]; @@ -52,6 +57,44 @@ function extractFunction(name) { return source.slice(start, end); } +function createLuckmailPlatformVerifyRouter({ + state, + stepKeyByStep = { 10: 'platform-verify' }, +} = {}) { + let clearedOptions = null; + let usedMarker = null; + const logs = []; + const router = messageRouterApi.createMessageRouter({ + addLog: async (message, level) => { + logs.push({ message, level }); + }, + buildLocalhostCleanupPrefix: () => '', + clearLuckmailRuntimeState: async (options) => { + clearedOptions = options; + }, + closeLocalhostCallbackTabs: async () => {}, + closeTabsByUrlPrefix: async () => {}, + finalizeIcloudAliasAfterSuccessfulFlow: async () => {}, + finalizePhoneActivationAfterSuccessfulFlow: async () => {}, + getCurrentLuckmailPurchase: (latestState) => latestState.currentLuckmailPurchase, + getState: async () => state, + getStepDefinitionForState: (step) => ({ id: step, key: stepKeyByStep[step] || '' }), + isHotmailProvider: () => false, + isLocalhostOAuthCallbackUrl: () => true, + isLuckmailProvider: (latestState) => latestState.mailProvider === 'luckmail-api', + patchHotmailAccount: async () => {}, + setLuckmailPurchaseUsedState: async (purchaseId, used) => { + usedMarker = { purchaseId, used }; + }, + }); + return { + router, + snapshot() { + return { clearedOptions, usedMarker, logs }; + }, + }; +} + test('ensureLuckmailPurchaseForFlow buys openai mailbox and defaults email type to ms_graph', async () => { const bundle = [ extractFunction('getLuckmailSessionConfig'), @@ -752,17 +795,9 @@ test('resetState preserves LuckMail session config, used map, and preserve tag c assert.equal(snapshot.storedPayload.currentPhoneActivation, null); }); -test('handleStepData step 10 marks current LuckMail purchase as used and clears runtime state', async () => { - const bundle = extractFunction('handleStepData'); - - const factory = new Function(` -let clearedOptions = null; -let usedMarker = null; -const logs = []; - -async function closeLocalhostCallbackTabs() {} -async function getState() { - return { +test('message router platform verify marks current LuckMail purchase as used and clears runtime state', async () => { + const { router, snapshot } = createLuckmailPlatformVerifyRouter({ + state: { mailProvider: 'luckmail-api', currentHotmailAccountId: null, currentLuckmailPurchase: { @@ -770,74 +805,22 @@ async function getState() { email_address: 'demo@outlook.com', }, email: 'demo@outlook.com', - }; -} -function getCurrentLuckmailPurchase(state) { - return state.currentLuckmailPurchase; -} -function isHotmailProvider() { - return false; -} -async function patchHotmailAccount() {} -function isLuckmailProvider(state) { - return state.mailProvider === 'luckmail-api'; -} -async function setLuckmailPurchaseUsedState(purchaseId, used) { - usedMarker = { purchaseId, used }; -} -async function clearLuckmailRuntimeState(options) { - clearedOptions = options; -} -async function addLog(message, level) { - logs.push({ message, level }); -} -function buildLocalhostCleanupPrefix() { - return ''; -} -async function closeTabsByUrlPrefix() {} -function shouldUseCustomRegistrationEmail() { - return false; -} -async function setEmailStateSilently() {} -async function setState() {} -function broadcastDataUpdate() {} -function isLocalhostOAuthCallbackUrl() { - return true; -} -async function finalizePhoneActivationAfterSuccessfulFlow() {} -async function finalizeIcloudAliasAfterSuccessfulFlow() {} + }, + }); -${bundle} - -return { - handleStepData, - snapshot() { - return { clearedOptions, usedMarker, logs }; - }, -}; -`); - - const api = factory(); - await api.handleStepData(10, { + await router.handleStepData(10, { localhostUrl: 'http://localhost:1455/auth/callback?code=abc&state=xyz', }); - const snapshot = api.snapshot(); - assert.deepStrictEqual(snapshot.usedMarker, { purchaseId: 123, used: true }); - assert.deepStrictEqual(snapshot.clearedOptions, { clearEmail: true }); - assert.equal(snapshot.logs.at(-1).message, '当前 LuckMail 邮箱运行态已清空,下轮将优先复用未用邮箱或重新购买邮箱。'); + const result = snapshot(); + assert.deepStrictEqual(result.usedMarker, { purchaseId: 123, used: true }); + assert.deepStrictEqual(result.clearedOptions, { clearEmail: true }); + assert.equal(result.logs.at(-1).message, '当前 LuckMail 邮箱运行态已清空,下轮将优先复用未用邮箱或重新购买邮箱。'); }); -test('handleStepData marks current LuckMail purchase as used on Plus final step 13', async () => { - const bundle = extractFunction('handleStepData'); - - const factory = new Function(` -let usedMarker = null; -const logs = []; - -async function closeLocalhostCallbackTabs() {} -async function getState() { - return { +test('message router marks current LuckMail purchase as used on Plus platform verify step 13', async () => { + const { router, snapshot } = createLuckmailPlatformVerifyRouter({ + state: { plusModeEnabled: true, mailProvider: 'luckmail-api', currentHotmailAccountId: null, @@ -846,64 +829,23 @@ async function getState() { email_address: 'plus@outlook.com', }, email: 'plus@outlook.com', - }; -} -function getLastStepIdForState(state) { - return state.plusModeEnabled ? 13 : 10; -} -function getCurrentLuckmailPurchase(state) { - return state.currentLuckmailPurchase; -} -function isHotmailProvider() { - return false; -} -async function patchHotmailAccount() {} -function isLuckmailProvider(state) { - return state.mailProvider === 'luckmail-api'; -} -async function setLuckmailPurchaseUsedState(purchaseId, used) { - usedMarker = { purchaseId, used }; -} -async function clearLuckmailRuntimeState() {} -async function addLog(message, level) { - logs.push({ message, level }); -} -function buildLocalhostCleanupPrefix() { - return ''; -} -async function closeTabsByUrlPrefix() {} -function shouldUseCustomRegistrationEmail() { - return false; -} -async function setEmailStateSilently() {} -async function setState() {} -function broadcastDataUpdate() {} -function isLocalhostOAuthCallbackUrl() { - return true; -} -async function finalizeIcloudAliasAfterSuccessfulFlow() {} + }, + stepKeyByStep: { + 10: 'oauth-login', + 13: 'platform-verify', + }, + }); -${bundle} + await router.handleStepData(10, {}); + assert.equal(snapshot().usedMarker, null); -return { - handleStepData, - snapshot() { - return { usedMarker, logs }; - }, -}; -`); - - const api = factory(); - await api.handleStepData(10, {}); - assert.equal(api.snapshot().usedMarker, null); - - await api.handleStepData(13, { + await router.handleStepData(13, { localhostUrl: 'http://localhost:1455/auth/callback?code=abc&state=xyz', }); - const snapshot = api.snapshot(); - assert.deepStrictEqual(snapshot.usedMarker, { purchaseId: 456, used: true }); - assert.equal(snapshot.logs.some((entry) => /已在本地标记为已用/.test(entry.message)), true); + const result = snapshot(); + assert.deepStrictEqual(result.usedMarker, { purchaseId: 456, used: true }); + assert.equal(result.logs.some((entry) => /已在本地标记为已用/.test(entry.message)), true); }); test('setLuckmailPurchaseUsedState persists used map to storage.local so reload keeps it non-reusable', async () => { diff --git a/tests/step9-localhost-cleanup-scope.test.js b/tests/step9-localhost-cleanup-scope.test.js index 9abcc1d..55d5bfd 100644 --- a/tests/step9-localhost-cleanup-scope.test.js +++ b/tests/step9-localhost-cleanup-scope.test.js @@ -2,6 +2,7 @@ const assert = require('assert'); const fs = require('fs'); const helperSource = fs.readFileSync('background.js', 'utf8'); +const messageRouterSource = fs.readFileSync('background/message-router.js', 'utf8'); const tabRuntimeSource = fs.readFileSync('background/tab-runtime.js', 'utf8'); function extractFunction(source, name) { @@ -54,10 +55,9 @@ const helperBundle = [ extractFunction(helperSource, 'isGeneratedAliasProvider'), extractFunction(helperSource, 'shouldUseCustomRegistrationEmail'), extractFunction(helperSource, 'isLocalhostOAuthCallbackUrl'), - extractFunction(helperSource, 'handleStepData'), ].join('\n'); -const api = new Function('tabRuntimeSource', ` +const api = new Function('messageRouterSource', 'tabRuntimeSource', ` const self = {}; const HOTMAIL_PROVIDER = 'hotmail-api'; const CLOUDFLARE_TEMP_EMAIL_PROVIDER = 'cloudflare-temp-email'; @@ -116,6 +116,7 @@ async function addLog(message) { } async function finalizePhoneActivationAfterSuccessfulFlow() {} async function finalizeIcloudAliasAfterSuccessfulFlow() {} +async function markCurrentRegistrationAccountUsed() {} function matchesSourceUrlFamily() { return false; } @@ -149,9 +150,25 @@ const closeLocalhostCallbackTabs = tabRuntime.closeLocalhostCallbackTabs; const isLocalhostOAuthCallbackTabMatch = tabRuntime.isLocalhostOAuthCallbackTabMatch; const buildLocalhostCleanupPrefix = tabRuntime.buildLocalhostCleanupPrefix; const closeTabsByUrlPrefix = tabRuntime.closeTabsByUrlPrefix; +${messageRouterSource} +const messageRouter = self.MultiPageBackgroundMessageRouter.createMessageRouter({ + addLog, + buildLocalhostCleanupPrefix, + closeLocalhostCallbackTabs, + closeTabsByUrlPrefix, + finalizeIcloudAliasAfterSuccessfulFlow, + finalizePhoneActivationAfterSuccessfulFlow, + getCurrentLuckmailPurchase: () => null, + getState, + getStepDefinitionForState: (step) => ({ id: step, key: step === 10 ? 'platform-verify' : '' }), + isHotmailProvider: () => false, + isLuckmailProvider, + markCurrentRegistrationAccountUsed, + patchHotmailAccount: async () => {}, +}); return { - handleStepData, + handleStepData: messageRouter.handleStepData, closeLocalhostCallbackTabs, isLocalhostOAuthCallbackTabMatch, reset({ tabs, tabRegistry }) { @@ -170,7 +187,7 @@ return { }; }, }; -`)(tabRuntimeSource); +`)(messageRouterSource, tabRuntimeSource); (async () => { const codexCallbackUrl = 'http://127.0.0.1:8317/codex/callback?code=abc&state=xyz';