diff --git a/background.js b/background.js index 0f5aea1..8c8eb1c 100644 --- a/background.js +++ b/background.js @@ -269,6 +269,7 @@ const PERSISTED_SETTING_DEFAULTS = { accountRunHistoryHelperBaseUrl: DEFAULT_ACCOUNT_RUN_HISTORY_HELPER_BASE_URL, gmailBaseEmail: '', mail2925BaseEmail: '', + currentMail2925AccountId: '', emailPrefix: '', inbucketHost: '', inbucketMailbox: '', @@ -903,6 +904,7 @@ function normalizePersistentSettingValue(key, value) { return normalizeAccountRunHistoryHelperBaseUrl(value); case 'gmailBaseEmail': case 'mail2925BaseEmail': + case 'currentMail2925AccountId': case 'emailPrefix': return String(value || '').trim(); case 'inbucketHost': diff --git a/background/mail-2925-session.js b/background/mail-2925-session.js index c78a350..07ab952 100644 --- a/background/mail-2925-session.js +++ b/background/mail-2925-session.js @@ -186,6 +186,7 @@ await syncMail2925Accounts(accounts.map((item) => (item.id === account.id ? nextAccount : item))); } + await setPersistentSettings({ currentMail2925AccountId: nextAccount.id }); await setState({ currentMail2925AccountId: nextAccount.id }); broadcastDataUpdate({ currentMail2925AccountId: nextAccount.id }); if (logMessage) { @@ -210,6 +211,7 @@ await syncMail2925Accounts(accounts.map((item) => (item.id === account.id ? nextAccount : item))); if (state.currentMail2925AccountId === account.id && nextAccount.enabled === false) { + await setPersistentSettings({ currentMail2925AccountId: '' }); await setState({ currentMail2925AccountId: null }); broadcastDataUpdate({ currentMail2925AccountId: null }); } @@ -224,6 +226,7 @@ await syncMail2925Accounts(nextAccounts); if (state.currentMail2925AccountId === accountId) { + await setPersistentSettings({ currentMail2925AccountId: '' }); await setState({ currentMail2925AccountId: null }); broadcastDataUpdate({ currentMail2925AccountId: null }); } @@ -239,6 +242,7 @@ await syncMail2925Accounts(nextAccounts); if (state.currentMail2925AccountId && !findMail2925Account(nextAccounts, state.currentMail2925AccountId)) { + await setPersistentSettings({ currentMail2925AccountId: '' }); await setState({ currentMail2925AccountId: null }); broadcastDataUpdate({ currentMail2925AccountId: null }); } @@ -613,6 +617,7 @@ }); if (!nextAccount) { + await setPersistentSettings({ currentMail2925AccountId: '' }); await setState({ currentMail2925AccountId: null }); broadcastDataUpdate({ currentMail2925AccountId: null }); if (typeof requestStop === 'function') { diff --git a/sidepanel/sidepanel.js b/sidepanel/sidepanel.js index 37a6d3e..430444d 100644 --- a/sidepanel/sidepanel.js +++ b/sidepanel/sidepanel.js @@ -1485,6 +1485,7 @@ function collectSettingsPayload() { mailProvider: selectMailProvider.value, mail2925Mode: getSelectedMail2925Mode(), mail2925UseAccountPool, + currentMail2925AccountId: String(latestState?.currentMail2925AccountId || '').trim(), emailGenerator: selectEmailGenerator.value, autoDeleteUsedIcloudAlias: checkboxAutoDeleteIcloud?.checked, icloudHostPreference: selectIcloudHostPreference?.value || 'auto', diff --git a/tests/background-mail2925-session-module.test.js b/tests/background-mail2925-session-module.test.js index 19188a7..331bf45 100644 --- a/tests/background-mail2925-session-module.test.js +++ b/tests/background-mail2925-session-module.test.js @@ -294,3 +294,46 @@ test('handleMail2925LimitReachedError stops immediately when account pool is off assert.equal(events.stopCalls.length, 1); assert.equal(currentState.currentMail2925AccountId, 'current'); }); + +test('setCurrentMail2925Account persists currentMail2925AccountId for browser restart restore', async () => { + const source = fs.readFileSync('background/mail-2925-session.js', 'utf8'); + const globalScope = {}; + const api = new Function('self', `${source}; return self.MultiPageBackgroundMail2925Session;`)(globalScope); + + let currentState = { + mail2925Accounts: mail2925Utils.normalizeMail2925Accounts([ + { id: 'acc-1', email: 'acc1@2925.com', password: 'p1', enabled: true, lastUsedAt: 10 }, + ]), + currentMail2925AccountId: null, + }; + const persistedUpdates = []; + + const manager = api.createMail2925SessionManager({ + addLog: async () => {}, + broadcastDataUpdate: () => {}, + chrome: {}, + findMail2925Account: mail2925Utils.findMail2925Account, + getMail2925AccountStatus: mail2925Utils.getMail2925AccountStatus, + getState: async () => currentState, + isMail2925AccountAvailable: mail2925Utils.isMail2925AccountAvailable, + MAIL2925_LIMIT_COOLDOWN_MS: mail2925Utils.MAIL2925_LIMIT_COOLDOWN_MS, + normalizeMail2925Account: mail2925Utils.normalizeMail2925Account, + normalizeMail2925Accounts: mail2925Utils.normalizeMail2925Accounts, + pickMail2925AccountForRun: mail2925Utils.pickMail2925AccountForRun, + setPersistentSettings: async (payload) => { + persistedUpdates.push(payload); + }, + setState: async (updates) => { + currentState = { ...currentState, ...updates }; + }, + throwIfStopped: () => {}, + upsertMail2925AccountInList: mail2925Utils.upsertMail2925AccountInList, + }); + + await manager.setCurrentMail2925Account('acc-1'); + + assert.equal(currentState.currentMail2925AccountId, 'acc-1'); + assert.deepStrictEqual(persistedUpdates, [ + { currentMail2925AccountId: 'acc-1' }, + ]); +}); diff --git a/tests/sidepanel-mail2925-base-email.test.js b/tests/sidepanel-mail2925-base-email.test.js index 340534d..5e24210 100644 --- a/tests/sidepanel-mail2925-base-email.test.js +++ b/tests/sidepanel-mail2925-base-email.test.js @@ -142,3 +142,73 @@ return { assert.equal(api.getLatestState().mail2925BaseEmail, 'new@2925.com'); assert.equal(api.getSaveCalls(), 1); }); + +test('collectSettingsPayload persists currentMail2925AccountId for 2925 account pool restore', () => { + const bundle = [ + extractFunction('collectSettingsPayload'), + ].join('\n'); + + const api = new Function(` +let latestState = { + contributionMode: false, + mail2925UseAccountPool: true, + currentMail2925AccountId: 'acc-2', +}; +let cloudflareDomainEditMode = false; +let cloudflareTempEmailDomainEditMode = false; +const selectCfDomain = { value: 'example.com' }; +const selectTempEmailDomain = { value: 'mail.example.com' }; +const selectPanelMode = { value: 'cpa' }; +const inputVpsUrl = { value: '' }; +const inputVpsPassword = { value: '' }; +const inputSub2ApiUrl = { value: '' }; +const inputSub2ApiEmail = { value: '' }; +const inputSub2ApiPassword = { value: '' }; +const inputSub2ApiGroup = { value: '' }; +const inputSub2ApiDefaultProxy = { value: '' }; +const inputPassword = { value: '' }; +const selectMailProvider = { value: '2925' }; +const selectEmailGenerator = { value: 'duck' }; +const checkboxAutoDeleteIcloud = { checked: false }; +const selectIcloudHostPreference = { value: 'auto' }; +const inputAccountRunHistoryTextEnabled = { checked: false }; +const inputAccountRunHistoryHelperBaseUrl = { value: '' }; +const inputMail2925UseAccountPool = { checked: true }; +const inputInbucketHost = { value: '' }; +const inputInbucketMailbox = { value: '' }; +const inputLuckmailApiKey = { value: '' }; +const inputLuckmailBaseUrl = { value: '' }; +const selectLuckmailEmailType = { value: 'ms_graph' }; +const inputLuckmailDomain = { value: '' }; +const inputTempEmailBaseUrl = { value: '' }; +const inputTempEmailAdminAuth = { value: '' }; +const inputTempEmailCustomAuth = { value: '' }; +const inputTempEmailReceiveMailbox = { value: '' }; +function getCloudflareDomainsFromState() { + return { domains: [], activeDomain: '' }; +} +function normalizeCloudflareDomainValue(value) { return String(value || '').trim(); } +function getCloudflareTempEmailDomainsFromState() { + return { domains: [], activeDomain: '' }; +} +function normalizeCloudflareTempEmailDomainValue(value) { return String(value || '').trim(); } +function getSelectedLocalCpaStep9Mode() { return 'submit'; } +function getSelectedMail2925Mode() { return 'provide'; } +function getSelectedHotmailServiceMode() { return 'local'; } +function buildManagedAliasBaseEmailPayload() { + return { gmailBaseEmail: '', mail2925BaseEmail: 'demo@2925.com', emailPrefix: '' }; +} +function normalizeLuckmailBaseUrl(value) { return String(value || '').trim(); } +function normalizeLuckmailEmailType(value) { return String(value || '').trim() || 'ms_graph'; } +function normalizeCloudflareTempEmailBaseUrlValue(value) { return String(value || '').trim(); } +function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); } +function normalizeAccountRunHistoryHelperBaseUrlValue(value) { return String(value || '').trim(); } +${bundle} +return { collectSettingsPayload }; +`)(); + + const payload = api.collectSettingsPayload(); + + assert.equal(payload.currentMail2925AccountId, 'acc-2'); + assert.equal(payload.mail2925UseAccountPool, true); +}); diff --git a/项目完整链路说明.md b/项目完整链路说明.md index 3fa355c..6183c2d 100644 --- a/项目完整链路说明.md +++ b/项目完整链路说明.md @@ -141,7 +141,7 @@ - 标签注册表 - 最近打开的来源地址 - LuckMail 当前运行时选择 -- 2925 当前运行时账号选择 `currentMail2925AccountId` +- 2925 当前选中的账号 ID `currentMail2925AccountId`(运行时会同步到持久配置,用于重开浏览器后恢复同一个号池账号) 补充: @@ -156,6 +156,7 @@ - Hotmail 账号池 - 2925 账号池 - 2925 是否启用号池模式 `mail2925UseAccountPool` +- 2925 当前选中的号池账号 ID `currentMail2925AccountId` - Cloudflare / Temp Email 设置 - iCloud 相关偏好 - LuckMail API 配置