feat(flow): unify sms multi-provider fallback and stabilize proxy/auth retries

This commit is contained in:
daniellee2015
2026-05-03 01:20:10 +08:00
parent 99313843c1
commit 2437e6e67d
37 changed files with 12254 additions and 1142 deletions
@@ -59,6 +59,13 @@ test('sidepanel html exposes phone verification toggle and dedicated HeroSMS row
assert.match(html, /id="btn-toggle-phone-verification-section"/);
assert.match(html, /id="row-phone-verification-fold"/);
assert.match(html, /id="input-phone-verification-enabled"/);
assert.match(html, /id="row-phone-sms-provider"/);
assert.match(html, /id="select-phone-sms-provider"/);
assert.match(html, /id="row-phone-sms-provider-order"/);
assert.match(html, /id="select-phone-sms-provider-order"[^>]*multiple/);
assert.match(html, /id="btn-phone-sms-provider-order-menu"/);
assert.match(html, /id="row-phone-sms-provider-order-actions"/);
assert.match(html, /id="btn-phone-sms-provider-order-reset"/);
assert.match(html, /id="row-hero-sms-platform"/);
assert.match(html, /id="row-hero-sms-country"/);
assert.match(html, /id="row-hero-sms-country-fallback"/);
@@ -69,32 +76,83 @@ test('sidepanel html exposes phone verification toggle and dedicated HeroSMS row
assert.match(html, /id="row-hero-sms-api-key"/);
assert.match(html, /id="row-hero-sms-max-price"/);
assert.match(html, /id="row-hero-sms-current-number"/);
assert.match(html, /id="row-hero-sms-current-countdown"/);
assert.match(html, /id="row-hero-sms-price-tiers"/);
assert.match(html, /id="row-hero-sms-current-code"/);
assert.match(html, /id="row-hero-sms-preferred-activation"/);
assert.match(html, /id="select-hero-sms-preferred-activation"/);
assert.match(html, /id="row-phone-replacement-limit"/);
assert.match(html, /id="row-phone-verification-resend-count"/);
assert.match(html, /id="row-phone-code-wait-seconds"/);
assert.match(html, /id="row-phone-code-timeout-windows"/);
assert.match(html, /id="row-phone-code-poll-interval-seconds"/);
assert.match(html, /id="row-phone-code-poll-max-rounds"/);
assert.match(html, /id="row-oauth-flow-timeout"/);
assert.match(html, /id="input-oauth-flow-timeout-enabled"/);
assert.match(html, /只取消 Step 7 后链总预算/);
assert.match(html, /id="row-five-sim-api-key"/);
assert.match(html, /id="input-five-sim-api-key"/);
assert.match(html, /id="row-five-sim-country"/);
assert.match(html, /id="select-five-sim-country"[^>]*multiple/);
assert.match(html, /id="row-five-sim-country-fallback"/);
assert.match(html, /id="row-five-sim-operator"/);
assert.match(html, /id="input-five-sim-operator"/);
assert.match(html, /id="row-five-sim-product"/);
assert.match(html, /id="input-five-sim-product"/);
assert.match(html, /<option value="nexsms">/);
assert.match(html, /id="row-nex-sms-api-key"/);
assert.match(html, /id="input-nex-sms-api-key"/);
assert.match(html, /id="row-nex-sms-country"/);
assert.match(html, /id="select-nex-sms-country"[^>]*multiple/);
assert.match(html, /id="row-nex-sms-country-fallback"/);
assert.match(html, /id="row-nex-sms-service-code"/);
assert.match(html, /id="input-nex-sms-service-code"/);
assert.doesNotMatch(html, /id="input-account-run-history-text-enabled"/);
});
test('updatePhoneVerificationSettingsUI toggles HeroSMS rows from the sms switch', () => {
const api = new Function(`
const phoneVerificationSectionExpanded = true;
let latestState = {};
const inputPhoneVerificationEnabled = { checked: false };
const rowPhoneVerificationEnabled = { style: { display: 'none' } };
const rowPhoneVerificationFold = { style: { display: 'none' } };
const rowPhoneSmsProvider = { style: { display: 'none' } };
const rowPhoneSmsProviderOrder = { style: { display: 'none' } };
const rowPhoneSmsProviderOrderActions = { style: { display: 'none' } };
const selectPhoneSmsProvider = { value: 'hero-sms' };
const btnTogglePhoneVerificationSection = {
disabled: false,
textContent: '',
title: '',
setAttribute: () => {},
};
const DEFAULT_PHONE_SMS_PROVIDER_ORDER = ['hero-sms', '5sim', 'nexsms'];
const phoneSmsProviderOrderSelection = [];
function normalizePhoneSmsProviderOrderValue(value = [], fallbackOrder = DEFAULT_PHONE_SMS_PROVIDER_ORDER) {
const source = Array.isArray(value) ? value : [];
const normalized = [...source];
if (normalized.length) {
return normalized.slice(0, 3);
}
if (!Array.isArray(fallbackOrder) || !fallbackOrder.length) {
return [];
}
const fallbackNormalized = [];
for (const provider of fallbackOrder) {
if (!fallbackNormalized.includes(provider)) {
fallbackNormalized.push(provider);
}
}
return fallbackNormalized.slice(0, 3);
}
function resolveNormalizedProviderOrderForRuntime(state = {}) {
const rawOrder = Array.isArray(state?.phoneSmsProviderOrder) ? state.phoneSmsProviderOrder : [];
const normalizedOrder = normalizePhoneSmsProviderOrderValue(rawOrder, []);
if (normalizedOrder.length) {
return normalizedOrder;
}
const fallbackProvider = String(state?.phoneSmsProvider || selectPhoneSmsProvider?.value || 'hero-sms').trim().toLowerCase() || 'hero-sms';
return [fallbackProvider];
}
function updatePhoneSmsProviderOrderSummary() {}
const rowHeroSmsPlatform = { style: { display: 'none' } };
const rowHeroSmsCountry = { style: { display: 'none' } };
const rowHeroSmsCountryFallback = { style: { display: 'none' } };
@@ -102,20 +160,36 @@ const rowHeroSmsAcquirePriority = { style: { display: 'none' } };
const rowHeroSmsApiKey = { style: { display: 'none' } };
const rowHeroSmsMaxPrice = { style: { display: 'none' } };
const rowHeroSmsCurrentNumber = { style: { display: 'none' } };
const rowHeroSmsCurrentCountdown = { style: { display: 'none' } };
const rowHeroSmsPriceTiers = { style: { display: 'none' } };
const rowHeroSmsCurrentCode = { style: { display: 'none' } };
const rowHeroSmsPreferredActivation = { style: { display: 'none' } };
const rowPhoneVerificationResendCount = { style: { display: 'none' } };
const rowPhoneReplacementLimit = { style: { display: 'none' } };
const rowPhoneCodeWaitSeconds = { style: { display: 'none' } };
const rowPhoneCodeTimeoutWindows = { style: { display: 'none' } };
const rowPhoneCodePollIntervalSeconds = { style: { display: 'none' } };
const rowPhoneCodePollMaxRounds = { style: { display: 'none' } };
const rowFiveSimApiKey = { style: { display: 'none' } };
const rowFiveSimCountry = { style: { display: 'none' } };
const rowFiveSimCountryFallback = { style: { display: 'none' } };
const rowFiveSimOperator = { style: { display: 'none' } };
const rowFiveSimProduct = { style: { display: 'none' } };
const rowNexSmsApiKey = { style: { display: 'none' } };
const rowNexSmsCountry = { style: { display: 'none' } };
const rowNexSmsCountryFallback = { style: { display: 'none' } };
const rowNexSmsServiceCode = { style: { display: 'none' } };
${extractFunction('updatePhoneVerificationSettingsUI')}
return {
setLatestState: (state) => { latestState = state || {}; },
rowPhoneVerificationEnabled,
rowPhoneVerificationFold,
rowPhoneSmsProvider,
rowPhoneSmsProviderOrder,
rowPhoneSmsProviderOrderActions,
selectPhoneSmsProvider,
btnTogglePhoneVerificationSection,
inputPhoneVerificationEnabled,
rowHeroSmsPlatform,
@@ -125,14 +199,25 @@ return {
rowHeroSmsApiKey,
rowHeroSmsMaxPrice,
rowHeroSmsCurrentNumber,
rowHeroSmsCurrentCountdown,
rowHeroSmsPriceTiers,
rowHeroSmsCurrentCode,
rowHeroSmsPreferredActivation,
rowPhoneVerificationResendCount,
rowPhoneReplacementLimit,
rowPhoneCodeWaitSeconds,
rowPhoneCodeTimeoutWindows,
rowPhoneCodePollIntervalSeconds,
rowPhoneCodePollMaxRounds,
rowFiveSimApiKey,
rowFiveSimCountry,
rowFiveSimCountryFallback,
rowFiveSimOperator,
rowFiveSimProduct,
rowNexSmsApiKey,
rowNexSmsCountry,
rowNexSmsCountryFallback,
rowNexSmsServiceCode,
updatePhoneVerificationSettingsUI,
};
`)();
@@ -140,6 +225,9 @@ return {
api.updatePhoneVerificationSettingsUI();
assert.equal(api.rowPhoneVerificationEnabled.style.display, '');
assert.equal(api.rowPhoneVerificationFold.style.display, 'none');
assert.equal(api.rowPhoneSmsProvider.style.display, 'none');
assert.equal(api.rowPhoneSmsProviderOrder.style.display, 'none');
assert.equal(api.rowPhoneSmsProviderOrderActions.style.display, 'none');
assert.equal(api.btnTogglePhoneVerificationSection.disabled, true);
assert.equal(api.btnTogglePhoneVerificationSection.textContent, '展开设置');
assert.equal(api.rowHeroSmsPlatform.style.display, 'none');
@@ -149,18 +237,32 @@ return {
assert.equal(api.rowHeroSmsApiKey.style.display, 'none');
assert.equal(api.rowHeroSmsMaxPrice.style.display, 'none');
assert.equal(api.rowHeroSmsCurrentNumber.style.display, 'none');
assert.equal(api.rowHeroSmsCurrentCountdown.style.display, 'none');
assert.equal(api.rowHeroSmsPriceTiers.style.display, 'none');
assert.equal(api.rowHeroSmsCurrentCode.style.display, 'none');
assert.equal(api.rowHeroSmsPreferredActivation.style.display, 'none');
assert.equal(api.rowPhoneVerificationResendCount.style.display, 'none');
assert.equal(api.rowPhoneReplacementLimit.style.display, 'none');
assert.equal(api.rowPhoneCodeWaitSeconds.style.display, 'none');
assert.equal(api.rowPhoneCodeTimeoutWindows.style.display, 'none');
assert.equal(api.rowPhoneCodePollIntervalSeconds.style.display, 'none');
assert.equal(api.rowPhoneCodePollMaxRounds.style.display, 'none');
assert.equal(api.rowFiveSimApiKey.style.display, 'none');
assert.equal(api.rowFiveSimCountry.style.display, 'none');
assert.equal(api.rowFiveSimCountryFallback.style.display, 'none');
assert.equal(api.rowFiveSimOperator.style.display, 'none');
assert.equal(api.rowFiveSimProduct.style.display, 'none');
assert.equal(api.rowNexSmsApiKey.style.display, 'none');
assert.equal(api.rowNexSmsCountry.style.display, 'none');
assert.equal(api.rowNexSmsCountryFallback.style.display, 'none');
assert.equal(api.rowNexSmsServiceCode.style.display, 'none');
api.inputPhoneVerificationEnabled.checked = true;
api.updatePhoneVerificationSettingsUI();
assert.equal(api.rowPhoneVerificationFold.style.display, '');
assert.equal(api.rowPhoneSmsProvider.style.display, '');
assert.equal(api.rowPhoneSmsProviderOrder.style.display, '');
assert.equal(api.rowPhoneSmsProviderOrderActions.style.display, '');
assert.equal(api.btnTogglePhoneVerificationSection.disabled, false);
assert.equal(api.btnTogglePhoneVerificationSection.textContent, '收起设置');
assert.equal(api.rowHeroSmsPlatform.style.display, '');
@@ -170,14 +272,51 @@ return {
assert.equal(api.rowHeroSmsApiKey.style.display, '');
assert.equal(api.rowHeroSmsMaxPrice.style.display, '');
assert.equal(api.rowHeroSmsCurrentNumber.style.display, '');
assert.equal(api.rowHeroSmsCurrentCountdown.style.display, '');
assert.equal(api.rowHeroSmsPriceTiers.style.display, 'none');
assert.equal(api.rowHeroSmsCurrentCode.style.display, '');
assert.equal(api.rowHeroSmsPreferredActivation.style.display, '');
assert.equal(api.rowPhoneVerificationResendCount.style.display, '');
assert.equal(api.rowPhoneReplacementLimit.style.display, '');
assert.equal(api.rowPhoneCodeWaitSeconds.style.display, '');
assert.equal(api.rowPhoneCodeTimeoutWindows.style.display, '');
assert.equal(api.rowPhoneCodePollIntervalSeconds.style.display, '');
assert.equal(api.rowPhoneCodePollMaxRounds.style.display, '');
assert.equal(api.rowFiveSimApiKey.style.display, 'none');
assert.equal(api.rowFiveSimCountry.style.display, 'none');
assert.equal(api.rowFiveSimCountryFallback.style.display, 'none');
assert.equal(api.rowFiveSimOperator.style.display, 'none');
assert.equal(api.rowFiveSimProduct.style.display, 'none');
assert.equal(api.rowNexSmsApiKey.style.display, 'none');
assert.equal(api.rowNexSmsCountry.style.display, 'none');
assert.equal(api.rowNexSmsCountryFallback.style.display, 'none');
assert.equal(api.rowNexSmsServiceCode.style.display, 'none');
api.selectPhoneSmsProvider.value = '5sim';
api.setLatestState({ phoneSmsProviderOrder: ['5sim'] });
api.updatePhoneVerificationSettingsUI();
assert.equal(api.rowHeroSmsCountry.style.display, 'none');
assert.equal(api.rowHeroSmsApiKey.style.display, 'none');
assert.equal(api.rowFiveSimApiKey.style.display, '');
assert.equal(api.rowFiveSimCountry.style.display, '');
assert.equal(api.rowFiveSimCountryFallback.style.display, '');
assert.equal(api.rowFiveSimOperator.style.display, '');
assert.equal(api.rowFiveSimProduct.style.display, '');
assert.equal(api.rowNexSmsApiKey.style.display, 'none');
assert.equal(api.rowNexSmsCountry.style.display, 'none');
assert.equal(api.rowNexSmsCountryFallback.style.display, 'none');
assert.equal(api.rowNexSmsServiceCode.style.display, 'none');
api.selectPhoneSmsProvider.value = 'nexsms';
api.setLatestState({ phoneSmsProviderOrder: ['nexsms'] });
api.updatePhoneVerificationSettingsUI();
assert.equal(api.rowHeroSmsCountry.style.display, 'none');
assert.equal(api.rowFiveSimApiKey.style.display, 'none');
assert.equal(api.rowFiveSimCountry.style.display, 'none');
assert.equal(api.rowNexSmsApiKey.style.display, '');
assert.equal(api.rowNexSmsCountry.style.display, '');
assert.equal(api.rowNexSmsCountryFallback.style.display, '');
assert.equal(api.rowNexSmsServiceCode.style.display, '');
});
test('collectSettingsPayload keeps local helper sync enabled while persisting sms toggle state', () => {
@@ -186,6 +325,7 @@ let latestState = {
contributionMode: false,
mail2925UseAccountPool: false,
currentMail2925AccountId: '',
fiveSimCountryOrder: ['thailand', 'england'],
};
let cloudflareDomainEditMode = false;
let cloudflareTempEmailDomainEditMode = false;
@@ -225,12 +365,26 @@ const inputAutoSkipFailuresThreadIntervalMinutes = { value: '0' };
const inputAutoDelayEnabled = { checked: false };
const inputAutoDelayMinutes = { value: '30' };
const inputAutoStepDelaySeconds = { value: '' };
const inputOAuthFlowTimeoutEnabled = { checked: false };
const inputPhoneVerificationEnabled = { checked: true };
const selectPhoneSmsProvider = { value: 'hero-sms' };
const inputVerificationResendCount = { value: '4' };
const inputHeroSmsApiKey = { value: 'demo-key' };
const inputFiveSimApiKey = { value: 'five-sim-key' };
const inputFiveSimOperator = { value: 'any' };
const inputFiveSimProduct = { value: 'openai' };
const inputHeroSmsReuseEnabled = { checked: true };
const selectHeroSmsAcquirePriority = { value: 'price' };
function getSelectedPhonePreferredActivation() {
return {
provider: 'hero-sms',
activationId: 'demo-activation',
phoneNumber: '66958889999',
countryId: 52,
countryLabel: 'Thailand',
successfulUses: 0,
maxUses: 3,
};
}
const inputHeroSmsMaxPrice = { value: '0.12' };
const inputPhoneReplacementLimit = { value: '5' };
const inputPhoneCodeWaitSeconds = { value: '75' };
@@ -303,13 +457,26 @@ return { collectSettingsPayload };
const payload = api.collectSettingsPayload();
assert.equal(payload.phoneVerificationEnabled, true);
assert.equal(payload.oauthFlowTimeoutEnabled, false);
assert.equal(payload.phoneSmsProvider, 'hero-sms');
assert.equal(payload.accountRunHistoryTextEnabled, true);
assert.equal(payload.accountRunHistoryHelperBaseUrl, 'http://127.0.0.1:17373');
assert.equal(payload.heroSmsApiKey, 'demo-key');
assert.equal(payload.fiveSimApiKey, 'five-sim-key');
assert.deepStrictEqual(payload.fiveSimCountryOrder, ['thailand', 'england']);
assert.equal(payload.fiveSimOperator, 'any');
assert.equal(payload.fiveSimProduct, 'openai');
assert.equal(payload.heroSmsReuseEnabled, true);
assert.equal(payload.heroSmsAcquirePriority, 'price');
assert.equal(payload.heroSmsMaxPrice, '0.12');
assert.deepStrictEqual(payload.phonePreferredActivation, {
provider: 'hero-sms',
activationId: 'demo-activation',
phoneNumber: '66958889999',
countryId: 52,
countryLabel: 'Thailand',
successfulUses: 0,
maxUses: 3,
});
assert.equal(payload.phoneVerificationReplacementLimit, 5);
assert.equal(payload.phoneCodeWaitSeconds, 75);
assert.equal(payload.phoneCodeTimeoutWindows, 3);