fix(flow): harden proxy phone and checkout recovery paths

This commit is contained in:
朴圣佑
2026-05-03 13:58:33 +08:00
committed by QLHazyCoder
parent d851cc4d36
commit 29093e08db
34 changed files with 2958 additions and 293 deletions
+20 -12
View File
@@ -1164,9 +1164,13 @@ function formatIpProxyRuntimeStatus(state = latestState) {
}
if (reason === 'connectivity_failed') {
const prefix = endpointSummary ? `当前代理:${endpointSummary}${accountSourceTag}` : '当前代理:未知';
const targetUnreachable = /真实目标|chatgpt\.com 不可达|target:page_context/i.test(errorText || details);
const exitPart = exitIp ? `;当前出口:${exitSummary}` : '';
return {
stateClass: 'state-error',
text: `${prefix};连通性失败,请切换节点或重试。`,
text: targetUnreachable && exitIp
? `${prefix}${exitPart};ChatGPT 目标不可达,请切换支持 ChatGPT 的节点。`
: `${prefix}${exitPart};连通性失败,请切换节点或重试。`,
details: errorText || details,
hideCurrentDisplay: true,
};
@@ -1303,11 +1307,13 @@ function updateIpProxyUI(state = latestState) {
if (rowIpProxyPoolTargetCount) {
rowIpProxyPoolTargetCount.style.display = showSettings ? '' : 'none';
}
if (rowIpProxyAutoSyncEnabled) {
rowIpProxyAutoSyncEnabled.style.display = showSettings ? '' : 'none';
const autoSyncEnabledRow = typeof rowIpProxyAutoSyncEnabled !== 'undefined' ? rowIpProxyAutoSyncEnabled : null;
const autoSyncIntervalRow = typeof rowIpProxyAutoSyncInterval !== 'undefined' ? rowIpProxyAutoSyncInterval : null;
if (autoSyncEnabledRow) {
autoSyncEnabledRow.style.display = showSettings ? '' : 'none';
}
if (rowIpProxyAutoSyncInterval) {
rowIpProxyAutoSyncInterval.style.display = showSettings ? '' : 'none';
if (autoSyncIntervalRow) {
autoSyncIntervalRow.style.display = showSettings ? '' : 'none';
}
if (rowIpProxyHost) {
rowIpProxyHost.style.display = showSettings && isAccountMode ? '' : 'none';
@@ -1402,15 +1408,17 @@ function updateIpProxyUI(state = latestState) {
if (inputIpProxyAccountList) {
inputIpProxyAccountList.disabled = !enabled || !isAccountMode || !accountListAvailable;
}
if (inputIpProxyAutoSyncEnabled) {
inputIpProxyAutoSyncEnabled.disabled = !enabled;
const autoSyncEnabledInput = typeof inputIpProxyAutoSyncEnabled !== 'undefined' ? inputIpProxyAutoSyncEnabled : null;
const autoSyncIntervalInput = typeof inputIpProxyAutoSyncIntervalMinutes !== 'undefined' ? inputIpProxyAutoSyncIntervalMinutes : null;
if (autoSyncEnabledInput) {
autoSyncEnabledInput.disabled = !enabled;
}
if (inputIpProxyAutoSyncIntervalMinutes) {
const autoSyncEnabled = Boolean(inputIpProxyAutoSyncEnabled?.checked);
if (!Number.isFinite(Number.parseInt(String(inputIpProxyAutoSyncIntervalMinutes.value || '').trim(), 10))) {
inputIpProxyAutoSyncIntervalMinutes.value = '15';
if (autoSyncIntervalInput) {
const autoSyncEnabled = Boolean(autoSyncEnabledInput?.checked);
if (!Number.isFinite(Number.parseInt(String(autoSyncIntervalInput.value || '').trim(), 10))) {
autoSyncIntervalInput.value = '15';
}
inputIpProxyAutoSyncIntervalMinutes.disabled = !enabled || !autoSyncEnabled;
autoSyncIntervalInput.disabled = !enabled || !autoSyncEnabled;
}
const runtimeStatus = formatIpProxyRuntimeStatus(runtimeState);
+331 -61
View File
@@ -424,8 +424,13 @@ const btnAutoStartRestart = document.getElementById('btn-auto-start-restart');
const btnAutoStartContinue = document.getElementById('btn-auto-start-continue');
const autoHintText = document.querySelector('.auto-hint');
const stepsList = document.querySelector('.steps-list');
const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal';
const PLUS_PAYMENT_METHOD_GOPAY = 'gopay';
const DEFAULT_PLUS_PAYMENT_METHOD = PLUS_PAYMENT_METHOD_PAYPAL;
let currentPlusModeEnabled = false;
let currentPlusPaymentMethod = 'paypal';
let currentPlusPaymentMethod = DEFAULT_PLUS_PAYMENT_METHOD;
let activePlusManualConfirmationRequestId = '';
let plusManualConfirmationDialogInFlight = false;
let heroSmsCountrySelectionOrder = [];
let phoneSmsProviderOrderSelection = [];
let heroSmsCountryMenuSearchKeyword = '';
@@ -492,14 +497,13 @@ const HERO_SMS_ACQUIRE_PRIORITY_COUNTRY = 'country';
const HERO_SMS_ACQUIRE_PRIORITY_PRICE = 'price';
const HERO_SMS_ACQUIRE_PRIORITY_PRICE_HIGH = 'price_high';
const DEFAULT_HERO_SMS_ACQUIRE_PRIORITY = HERO_SMS_ACQUIRE_PRIORITY_COUNTRY;
const HERO_SMS_FALLBACK_COUNTRY_ITEMS = Object.freeze([
const HERO_SMS_SUPPORTED_COUNTRY_ITEMS = Object.freeze([
{ id: 6, chn: '印度尼西亚', eng: 'Indonesia' },
{ id: 52, chn: '泰国', eng: 'Thailand' },
{ id: 187, chn: '美国(物理)', eng: 'USA' },
{ id: 16, chn: '英国', eng: 'United Kingdom' },
{ id: 151, chn: '日本', eng: 'Japan' },
{ id: 43, chn: '德国', eng: 'Germany' },
{ id: 73, chn: '法国', eng: 'France' },
{ id: 10, chn: '越南', eng: 'Vietnam' },
]);
const HERO_SMS_SUPPORTED_COUNTRY_ID_SET = new Set(HERO_SMS_SUPPORTED_COUNTRY_ITEMS.map((item) => String(item.id)));
const HERO_SMS_FALLBACK_COUNTRY_ITEMS = HERO_SMS_SUPPORTED_COUNTRY_ITEMS;
const FIVE_SIM_COUNTRY_CN_BY_ID = Object.freeze({
afghanistan: '阿富汗',
albania: '阿尔巴尼亚',
@@ -645,9 +649,13 @@ const PLUS_CONTRIBUTION_PROMPT_LEDGER_STORAGE_KEY = 'multipage-plus-contribution
const PHONE_VERIFICATION_SECTION_EXPANDED_STORAGE_KEY = 'multipage-phone-verification-section-expanded';
function getStepDefinitionsForMode(plusModeEnabled = false, options = {}) {
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : 'paypal';
const rawPaymentMethod = typeof options === 'string'
? options
: (options.plusPaymentMethod || currentPlusPaymentMethod || defaultMethod);
return (window.MultiPageStepDefinitions?.getSteps?.({
plusModeEnabled,
plusPaymentMethod: options.plusPaymentMethod || selectPlusPaymentMethod?.value || 'paypal',
plusPaymentMethod: normalizePlusPaymentMethod(rawPaymentMethod),
}) || [])
.sort((left, right) => {
const leftOrder = Number.isFinite(left.order) ? left.order : left.id;
@@ -659,7 +667,12 @@ function getStepDefinitionsForMode(plusModeEnabled = false, options = {}) {
function rebuildStepDefinitionState(plusModeEnabled = false, options = {}) {
currentPlusModeEnabled = Boolean(plusModeEnabled);
stepDefinitions = getStepDefinitionsForMode(currentPlusModeEnabled, options);
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : 'paypal';
const rawPaymentMethod = typeof options === 'string'
? options
: (options.plusPaymentMethod || currentPlusPaymentMethod || defaultMethod);
currentPlusPaymentMethod = normalizePlusPaymentMethod(rawPaymentMethod);
stepDefinitions = getStepDefinitionsForMode(currentPlusModeEnabled, currentPlusPaymentMethod);
STEP_IDS = stepDefinitions.map((step) => Number(step.id)).filter(Number.isFinite);
STEP_DEFAULT_STATUSES = Object.fromEntries(STEP_IDS.map((stepId) => [stepId, 'pending']));
SKIPPABLE_STEPS = new Set(STEP_IDS);
@@ -688,12 +701,15 @@ const DEFAULT_HERO_SMS_COUNTRY_LABEL = 'Thailand';
const PHONE_SMS_PROVIDER_HERO_SMS = 'hero-sms';
const PHONE_SMS_PROVIDER_FIVE_SIM = '5sim';
const DEFAULT_PHONE_SMS_PROVIDER = PHONE_SMS_PROVIDER_HERO_SMS;
const DEFAULT_FIVE_SIM_COUNTRY_ID = 'england';
const DEFAULT_FIVE_SIM_COUNTRY_LABEL = '英国 (England)';
const DEFAULT_FIVE_SIM_COUNTRY_ID = 'vietnam';
const DEFAULT_FIVE_SIM_COUNTRY_LABEL = '越南 (Vietnam)';
const FIVE_SIM_SUPPORTED_COUNTRY_ITEMS = Object.freeze([
{ id: 'indonesia', chn: '印度尼西亚', eng: 'Indonesia', searchText: 'indonesia 印度尼西亚 印尼 Indonesia ID +62' },
{ id: 'thailand', chn: '泰国', eng: 'Thailand', searchText: 'thailand 泰国 Thailand TH +66' },
{ id: 'vietnam', chn: '越南', eng: 'Vietnam', searchText: 'vietnam 越南 Vietnam VN +84' },
]);
const FIVE_SIM_SUPPORTED_COUNTRY_ID_SET = new Set(FIVE_SIM_SUPPORTED_COUNTRY_ITEMS.map((item) => item.id));
const DEFAULT_FIVE_SIM_OPERATOR = 'any';
const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal';
const PLUS_PAYMENT_METHOD_GOPAY = 'gopay';
const DEFAULT_PLUS_PAYMENT_METHOD = PLUS_PAYMENT_METHOD_PAYPAL;
const DEFAULT_IP_PROXY_SERVICE = '711proxy';
const SUPPORTED_IP_PROXY_SERVICES = ['711proxy', 'lumiproxy', 'iproyal', 'omegaproxy'];
const IP_PROXY_ENABLED_SERVICES = ['711proxy'];
@@ -1897,19 +1913,23 @@ function syncLatestState(nextState) {
}
function normalizePlusPaymentMethod(value = '') {
if (window.GoPayUtils?.normalizePlusPaymentMethod) {
return window.GoPayUtils.normalizePlusPaymentMethod(value);
const rootScope = typeof window !== 'undefined' ? window : globalThis;
if (rootScope.GoPayUtils?.normalizePlusPaymentMethod) {
return rootScope.GoPayUtils.normalizePlusPaymentMethod(value);
}
return String(value || '').trim().toLowerCase() === PLUS_PAYMENT_METHOD_GOPAY
? PLUS_PAYMENT_METHOD_GOPAY
: PLUS_PAYMENT_METHOD_PAYPAL;
const gopayValue = typeof PLUS_PAYMENT_METHOD_GOPAY !== 'undefined' ? PLUS_PAYMENT_METHOD_GOPAY : 'gopay';
const paypalValue = typeof PLUS_PAYMENT_METHOD_PAYPAL !== 'undefined' ? PLUS_PAYMENT_METHOD_PAYPAL : 'paypal';
return String(value || '').trim().toLowerCase() === gopayValue
? gopayValue
: paypalValue;
}
function getSelectedPlusPaymentMethod(state = latestState) {
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : 'paypal';
if (typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod?.value) {
return normalizePlusPaymentMethod(selectPlusPaymentMethod.value);
}
return normalizePlusPaymentMethod(state?.plusPaymentMethod || DEFAULT_PLUS_PAYMENT_METHOD);
return normalizePlusPaymentMethod(state?.plusPaymentMethod || currentPlusPaymentMethod || defaultMethod);
}
function hasOwnStateValue(source, key) {
@@ -1979,6 +1999,18 @@ function isAutoRunScheduledPhase() {
return currentAutoRun.phase === 'scheduled';
}
function isAutoRunSourceSyncPhase(phase) {
return ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
}
function shouldSyncRunCountFromAutoRunSource(source = {}) {
const phase = source.autoRunPhase ?? source.phase ?? currentAutoRun.phase;
const autoRunning = source.autoRunning !== undefined
? Boolean(source.autoRunning)
: isAutoRunSourceSyncPhase(phase);
return autoRunning || isAutoRunSourceSyncPhase(phase);
}
function getAutoRunLabel(payload = currentAutoRun) {
if ((payload.phase ?? currentAutoRun.phase) === 'scheduled') {
return (payload.totalRuns || 1) > 1 ? ` (${payload.totalRuns}轮)` : '';
@@ -2174,7 +2206,7 @@ function getLockedRunCountFromEmailPool(provider = selectMailProvider.value) {
return 0;
}
function shouldLockRunCountToEmailPool(provider = selectMailProvider.value) {
function shouldLockRunCountToEmailPool(provider = (typeof selectMailProvider !== 'undefined' ? selectMailProvider?.value : undefined)) {
return getLockedRunCountFromEmailPool(provider) > 0;
}
@@ -3007,6 +3039,12 @@ function collectSettingsPayload() {
fiveSimCountryId: fiveSimCountry.id,
fiveSimCountryLabel: fiveSimCountry.label,
fiveSimCountryFallback,
fiveSimCountryOrder: [
fiveSimCountry,
...fiveSimCountryFallback,
]
.map((country) => normalizeFiveSimCountryId(country?.id, ''))
.filter(Boolean),
fiveSimMaxPrice: fiveSimMaxPriceValue,
fiveSimOperator: fiveSimOperatorValue,
};
@@ -3124,11 +3162,22 @@ function normalizePhoneSmsMaxPriceValue(value = '', provider = getSelectedPhoneS
}
function normalizeFiveSimCountryId(value, fallback = DEFAULT_FIVE_SIM_COUNTRY_ID) {
if (typeof window !== 'undefined' && window.PhoneSmsFiveSimProvider?.normalizeFiveSimCountryId) {
return window.PhoneSmsFiveSimProvider.normalizeFiveSimCountryId(value, fallback);
const supportedCountryIds = typeof FIVE_SIM_SUPPORTED_COUNTRY_ID_SET !== 'undefined'
? FIVE_SIM_SUPPORTED_COUNTRY_ID_SET
: new Set(['indonesia', 'thailand', 'vietnam']);
const fallbackSource = fallback === undefined || fallback === null ? DEFAULT_FIVE_SIM_COUNTRY_ID : fallback;
const normalizedFallback = String(fallbackSource).trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '');
const rawNormalized = typeof window !== 'undefined' && window.PhoneSmsFiveSimProvider?.normalizeFiveSimCountryId
? window.PhoneSmsFiveSimProvider.normalizeFiveSimCountryId(value, '')
: String(value || '').trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '');
const normalized = String(rawNormalized || '').trim().toLowerCase();
if (supportedCountryIds.has(normalized)) {
return normalized;
}
const normalized = String(value || '').trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '');
return normalized || fallback;
if (!normalizedFallback) {
return '';
}
return supportedCountryIds.has(normalizedFallback) ? normalizedFallback : DEFAULT_FIVE_SIM_COUNTRY_ID;
}
function normalizeFiveSimCountryLabel(value = '', fallback = DEFAULT_FIVE_SIM_COUNTRY_LABEL) {
@@ -3145,8 +3194,13 @@ function formatFiveSimCountryDisplayLabel(id = '', englishValue = '', fallback =
const countryId = normalizeFiveSimCountryId(id, '');
const english = normalizeFiveSimCountryLabel(englishValue || countryId || fallback, fallback);
const chinese = FIVE_SIM_COUNTRY_CN_BY_ID[countryId] || '';
if (chinese && english && chinese.toLowerCase() !== english.toLowerCase() && !String(english).includes(chinese)) {
return `${chinese} (${english})`;
if (chinese && english) {
if (String(english).includes(chinese)) {
return english;
}
if (chinese.toLowerCase() !== english.toLowerCase()) {
return `${chinese} (${english})`;
}
}
return chinese || english;
}
@@ -3211,8 +3265,16 @@ function normalizeFiveSimCountryFallbackList(value = []) {
return normalized;
}
function normalizeHeroSmsCountryId(value) {
return Math.max(1, Math.floor(Number(value) || DEFAULT_HERO_SMS_COUNTRY_ID));
function normalizeHeroSmsCountryId(value, fallback = DEFAULT_HERO_SMS_COUNTRY_ID) {
const supportedCountryIds = typeof HERO_SMS_SUPPORTED_COUNTRY_ID_SET !== 'undefined'
? HERO_SMS_SUPPORTED_COUNTRY_ID_SET
: new Set(['6', '52', '10']);
const parsed = Math.floor(Number(value));
if (Number.isFinite(parsed) && supportedCountryIds.has(String(parsed))) {
return parsed;
}
const fallbackParsed = Math.floor(Number(fallback));
return supportedCountryIds.has(String(fallbackParsed)) ? fallbackParsed : DEFAULT_HERO_SMS_COUNTRY_ID;
}
function normalizeHeroSmsCountryLabel(value = '') {
@@ -3831,7 +3893,10 @@ function normalizeHeroSmsCountryFallbackList(value = []) {
}
}
if (!id || seen.has(id)) {
const supportedCountryIds = typeof HERO_SMS_SUPPORTED_COUNTRY_ID_SET !== 'undefined'
? HERO_SMS_SUPPORTED_COUNTRY_ID_SET
: new Set(['6', '52', '10']);
if (!id || !supportedCountryIds.has(String(id)) || seen.has(id)) {
return;
}
seen.add(id);
@@ -4005,7 +4070,9 @@ function collectHeroSmsPriceEntriesForPreview(payload, entries = []) {
const physicalCount = Number(payload.physicalCount);
const hasCount = Number.isFinite(count);
const hasPhysicalCount = Number.isFinite(physicalCount);
const stockCount = Math.max(hasCount ? count : 0, hasPhysicalCount ? physicalCount : 0);
const stockCount = hasPhysicalCount
? physicalCount
: (hasCount ? count : 0);
const hasStockField = hasCount || hasPhysicalCount;
entries.push({
cost: directPrice,
@@ -4963,8 +5030,12 @@ async function loadHeroSmsCountries() {
].filter(Boolean).join(' '),
};
})
.filter((entry) => entry.id)
.sort((left, right) => left.label.localeCompare(right.label));
.filter((entry) => entry.id && FIVE_SIM_SUPPORTED_COUNTRY_ID_SET.has(String(entry.id)))
.sort((left, right) => {
const leftIndex = FIVE_SIM_SUPPORTED_COUNTRY_ITEMS.findIndex((item) => item.id === String(left.id));
const rightIndex = FIVE_SIM_SUPPORTED_COUNTRY_ITEMS.findIndex((item) => item.id === String(right.id));
return leftIndex - rightIndex;
});
if (!optionItems.length) {
throw new Error('empty country list');
}
@@ -4974,12 +5045,11 @@ async function loadHeroSmsCountries() {
applyOptions(optionItems, selectHeroSmsCountryFallback);
} catch (error) {
console.warn('Failed to load 5sim countries:', error);
const fallbackItems = [
{ id: 'england', label: formatFiveSimCountryDisplayLabel('england', 'England'), searchText: 'england 英国 England uk gb united kingdom' },
{ id: 'usa', label: formatFiveSimCountryDisplayLabel('usa', 'USA'), searchText: 'usa 美国 US United States' },
{ id: 'thailand', label: formatFiveSimCountryDisplayLabel('thailand', 'Thailand'), searchText: 'thailand 泰国 TH' },
{ id: 'japan', label: formatFiveSimCountryDisplayLabel('japan', 'Japan'), searchText: 'japan 日本 JP' },
];
const fallbackItems = FIVE_SIM_SUPPORTED_COUNTRY_ITEMS.map((item) => ({
id: item.id,
label: formatFiveSimCountryDisplayLabel(item.id, item.eng),
searchText: item.searchText,
}));
applyOptions(fallbackItems, selectHeroSmsCountry);
applyOptions(fallbackItems, selectHeroSmsCountryFallback);
heroSmsCountrySearchTextById.clear();
@@ -5002,8 +5072,12 @@ async function loadHeroSmsCountries() {
throw new Error('empty country list');
}
const optionItems = countries
.filter((item) => Number(item?.id) > 0 && (String(item?.eng || '').trim() || String(item?.chn || '').trim()))
.sort((left, right) => String(left.eng || '').localeCompare(String(right.eng || '')))
.filter((item) => HERO_SMS_SUPPORTED_COUNTRY_ID_SET.has(String(Math.floor(Number(item?.id)))) && (String(item?.eng || '').trim() || String(item?.chn || '').trim()))
.sort((left, right) => {
const leftIndex = HERO_SMS_SUPPORTED_COUNTRY_ITEMS.findIndex((item) => String(item.id) === String(Math.floor(Number(left?.id))));
const rightIndex = HERO_SMS_SUPPORTED_COUNTRY_ITEMS.findIndex((item) => String(item.id) === String(Math.floor(Number(right?.id))));
return leftIndex - rightIndex;
})
.map((item) => {
const id = normalizeHeroSmsCountryId(item.id);
const label = buildHeroSmsCountryDisplayLabel(item);
@@ -6049,15 +6123,21 @@ function updatePhoneVerificationSettingsUI() {
}
function updatePlusModeUI() {
const paypalValue = typeof PLUS_PAYMENT_METHOD_PAYPAL !== 'undefined' ? PLUS_PAYMENT_METHOD_PAYPAL : 'paypal';
const gopayValue = typeof PLUS_PAYMENT_METHOD_GOPAY !== 'undefined' ? PLUS_PAYMENT_METHOD_GOPAY : 'gopay';
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : paypalValue;
const enabled = typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled
? Boolean(inputPlusModeEnabled.checked)
: false;
const method = enabled ? getSelectedPlusPaymentMethod() : DEFAULT_PLUS_PAYMENT_METHOD;
const method = enabled ? getSelectedPlusPaymentMethod() : defaultMethod;
if (typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod) {
selectPlusPaymentMethod.value = method;
if (selectPlusPaymentMethod.style) {
selectPlusPaymentMethod.style.display = enabled ? '' : 'none';
}
}
if (typeof plusPaymentMethodCaption !== 'undefined' && plusPaymentMethodCaption) {
plusPaymentMethodCaption.textContent = method === PLUS_PAYMENT_METHOD_GOPAY
plusPaymentMethodCaption.textContent = method === gopayValue
? 'GoPay 印尼订阅链路'
: 'PayPal 订阅链路';
}
@@ -6075,7 +6155,10 @@ function updatePlusModeUI() {
if (!row) {
return;
}
row.style.display = enabled && method === PLUS_PAYMENT_METHOD_PAYPAL ? '' : 'none';
const selectedMethod = typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod?.value
? normalizePlusPaymentMethod(selectPlusPaymentMethod.value)
: method;
row.style.display = enabled && selectedMethod === paypalValue ? '' : 'none';
});
[
typeof rowGoPayCountryCode !== 'undefined' ? rowGoPayCountryCode : null,
@@ -6086,7 +6169,10 @@ function updatePlusModeUI() {
if (!row) {
return;
}
row.style.display = enabled && method === PLUS_PAYMENT_METHOD_GOPAY ? '' : 'none';
const selectedMethod = typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod?.value
? normalizePlusPaymentMethod(selectPlusPaymentMethod.value)
: method;
row.style.display = enabled && selectedMethod === gopayValue ? '' : 'none';
});
}
@@ -6117,6 +6203,97 @@ async function setRuntimeEmailState(email) {
return normalizedEmail;
}
async function openPlusManualConfirmationDialog(options = {}) {
const method = String(options.method || '').trim().toLowerCase();
const gopayValue = typeof PLUS_PAYMENT_METHOD_GOPAY !== 'undefined' ? PLUS_PAYMENT_METHOD_GOPAY : 'gopay';
const title = String(options.title || '').trim() || (method === gopayValue ? 'GoPay 订阅确认' : '手动确认');
const message = String(options.message || '').trim()
|| (method === gopayValue
? '请在当前订阅页中手动完成 GoPay 订阅,完成后点击“我已完成订阅”继续。'
: '请先在页面中完成当前手动操作,完成后点击确认继续。');
return openActionModal({
title,
message,
actions: [
{ id: 'cancel', label: '取消等待', variant: 'btn-ghost' },
{ id: 'confirm', label: '我已完成订阅', variant: 'btn-primary' },
],
alert: method === gopayValue
? { text: '确认后流程会直接继续到 Plus 模式第 10 步 OAuth 登录。', tone: 'info' }
: null,
});
}
async function syncPlusManualConfirmationDialog() {
const gopayValue = typeof PLUS_PAYMENT_METHOD_GOPAY !== 'undefined' ? PLUS_PAYMENT_METHOD_GOPAY : 'gopay';
const requestId = String(latestState?.plusManualConfirmationRequestId || '').trim();
const pending = Boolean(latestState?.plusManualConfirmationPending);
if (!pending || !requestId || plusManualConfirmationDialogInFlight || activePlusManualConfirmationRequestId === requestId) {
return;
}
const step = Number(latestState?.plusManualConfirmationStep) || 0;
const method = String(latestState?.plusManualConfirmationMethod || '').trim().toLowerCase();
const title = latestState?.plusManualConfirmationTitle;
const message = latestState?.plusManualConfirmationMessage;
activePlusManualConfirmationRequestId = requestId;
plusManualConfirmationDialogInFlight = true;
let shouldReopenDialog = false;
try {
const choice = await openPlusManualConfirmationDialog({
method,
title,
message,
});
const currentRequestId = String(latestState?.plusManualConfirmationRequestId || '').trim();
const stillPending = Boolean(latestState?.plusManualConfirmationPending);
if (!stillPending || currentRequestId !== requestId) {
return;
}
if (choice == null) {
shouldReopenDialog = true;
showToast('当前订阅确认仍在等待中,将重新弹出确认窗口。', 'info', 1800);
return;
}
const confirmed = choice === 'confirm';
const response = await chrome.runtime.sendMessage({
type: 'RESOLVE_PLUS_MANUAL_CONFIRMATION',
source: 'sidepanel',
payload: {
step,
requestId,
confirmed,
},
});
if (response?.error) {
throw new Error(response.error);
}
if (confirmed) {
showToast(method === gopayValue ? 'GoPay 订阅已确认,正在继续 OAuth 登录...' : '已确认,流程继续执行中...', 'info', 2200);
} else {
showToast(method === gopayValue ? '已取消 GoPay 订阅等待。' : '已取消当前手动确认。', 'warn', 2200);
}
} catch (error) {
showToast(error?.message || String(error || '未知错误'), 'error');
} finally {
if (activePlusManualConfirmationRequestId === requestId) {
activePlusManualConfirmationRequestId = '';
}
plusManualConfirmationDialogInFlight = false;
if (
shouldReopenDialog
&& latestState?.plusManualConfirmationPending
&& String(latestState?.plusManualConfirmationRequestId || '').trim() === requestId
) {
setTimeout(() => {
void syncPlusManualConfirmationDialog();
}, 0);
}
}
}
async function clearRegistrationEmail(options = {}) {
const { silent = false } = options;
if (!inputEmail.value.trim() && !latestState?.email) {
@@ -6223,13 +6400,11 @@ function applyAutoRunStatus(payload = currentAutoRun) {
setSettingsCardLocked(settingsCardLocked);
const lockedRunCount = getLockedRunCountFromEmailPool();
const shouldSyncAutoRunTotalRuns = currentAutoRun.autoRunning
|| locked
|| paused
|| scheduled;
inputRunCount.disabled = currentAutoRun.autoRunning || lockedRunCount > 0;
inputRunCount.disabled = currentAutoRun.autoRunning || (
typeof shouldLockRunCountToEmailPool === 'function'
? shouldLockRunCountToEmailPool()
: getLockedRunCountFromEmailPool() > 0
);
btnAutoRun.disabled = currentAutoRun.autoRunning;
btnFetchEmail.disabled = locked
|| isCustomMailProvider()
@@ -6237,9 +6412,18 @@ function applyAutoRunStatus(payload = currentAutoRun) {
inputEmail.disabled = locked;
inputAutoSkipFailures.disabled = scheduled;
const lockedRunCount = typeof getLockedRunCountFromEmailPool === 'function'
? getLockedRunCountFromEmailPool()
: 0;
const isSyncPhase = typeof isAutoRunSourceSyncPhase === 'function'
? isAutoRunSourceSyncPhase
: (phase) => ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
const shouldSyncRunCount = typeof shouldSyncRunCountFromAutoRunSource === 'function'
? shouldSyncRunCountFromAutoRunSource(currentAutoRun)
: (currentAutoRun.autoRunning || isSyncPhase(currentAutoRun.phase));
if (lockedRunCount > 0) {
inputRunCount.value = String(lockedRunCount);
} else if (shouldSyncAutoRunTotalRuns && currentAutoRun.totalRuns > 0) {
} else if (shouldSyncRunCount && currentAutoRun.totalRuns > 0) {
inputRunCount.value = String(currentAutoRun.totalRuns);
}
@@ -6340,21 +6524,31 @@ function renderStepsList() {
updateButtonStates();
}
function syncStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethod = 'paypal', options = {}) {
function syncStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethodOrOptions = {}, maybeOptions = {}) {
const nextPlusModeEnabled = Boolean(plusModeEnabled);
const nextPaymentMethod = normalizePlusPaymentMethod(options.plusPaymentMethod || getSelectedPlusPaymentMethod(latestState));
const options = typeof plusPaymentMethodOrOptions === 'string'
? maybeOptions
: (plusPaymentMethodOrOptions || {});
const rawPaymentMethod = typeof plusPaymentMethodOrOptions === 'string'
? plusPaymentMethodOrOptions
: (options.plusPaymentMethod || getSelectedPlusPaymentMethod(latestState));
const nextPaymentMethod = normalizePlusPaymentMethod(rawPaymentMethod);
const rootScope = typeof window !== 'undefined' ? window : globalThis;
const currentPaymentStep = stepDefinitions.find((step) => step.key === 'paypal-approve');
const nextPaymentTitle = window.MultiPageStepDefinitions?.getPlusPaymentStepTitle?.({
const nextPaymentTitle = rootScope.MultiPageStepDefinitions?.getPlusPaymentStepTitle?.({
plusModeEnabled: nextPlusModeEnabled,
plusPaymentMethod: nextPaymentMethod,
});
const paymentTitleChanged = Boolean(nextPlusModeEnabled && currentPaymentStep && nextPaymentTitle && currentPaymentStep.title !== nextPaymentTitle);
const shouldRender = Boolean(options.render) || nextPlusModeEnabled !== currentPlusModeEnabled || paymentTitleChanged;
const shouldRender = Boolean(options.render)
|| nextPlusModeEnabled !== currentPlusModeEnabled
|| nextPaymentMethod !== currentPlusPaymentMethod
|| paymentTitleChanged;
if (!shouldRender) {
return;
}
rebuildStepDefinitionState(nextPlusModeEnabled, { plusPaymentMethod: nextPaymentMethod });
rebuildStepDefinitionState(nextPlusModeEnabled, nextPaymentMethod);
renderStepsList();
}
@@ -6755,7 +6949,13 @@ function applySettingsState(state) {
if (typeof updateHeroSmsRuntimeDisplay === 'function') {
updateHeroSmsRuntimeDisplay(state);
}
if (state?.autoRunTotalRuns) {
const isSyncPhase = typeof isAutoRunSourceSyncPhase === 'function'
? isAutoRunSourceSyncPhase
: (phase) => ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
const shouldSyncInitialRunCount = typeof shouldSyncRunCountFromAutoRunSource === 'function'
? shouldSyncRunCountFromAutoRunSource(state)
: (Boolean(state?.autoRunning) || isSyncPhase(state?.autoRunPhase ?? state?.phase));
if (state?.autoRunTotalRuns && shouldSyncInitialRunCount) {
inputRunCount.value = String(state.autoRunTotalRuns);
}
@@ -10418,14 +10618,68 @@ inputAutoDelayMinutes.addEventListener('blur', () => {
});
function getPhoneSmsCountrySelectionForProvider(provider = getSelectedPhoneSmsProvider(), options = {}) {
const normalizedProvider = normalizePhoneSmsProvider(provider);
const countrySelect = selectHeroSmsCountry || selectHeroSmsCountryFallback;
const selectionLimit = Math.max(1, Math.floor(Number(options.maxSelection) || HERO_SMS_COUNTRY_SELECTION_MAX));
const ensureDefault = options.ensureDefault !== false;
const defaultCountry = normalizedProvider === PHONE_SMS_PROVIDER_FIVE_SIM
? { id: DEFAULT_FIVE_SIM_COUNTRY_ID, label: DEFAULT_FIVE_SIM_COUNTRY_LABEL }
: { id: DEFAULT_HERO_SMS_COUNTRY_ID, label: DEFAULT_HERO_SMS_COUNTRY_LABEL };
if (!countrySelect) {
return ensureDefault ? [defaultCountry] : [];
}
const optionByValue = new Map(
Array.from(countrySelect.options || []).map((option) => [String(option.value), option])
);
const selectedIds = Array.from(countrySelect.options || [])
.filter((option) => option.selected)
.map((option) => normalizePhoneSmsCountryId(option.value, normalizedProvider))
.filter(Boolean);
if (!selectedIds.length && !countrySelect.multiple) {
const fallbackId = normalizePhoneSmsCountryId(countrySelect.value, normalizedProvider);
if (fallbackId) {
selectedIds.push(fallbackId);
}
}
const selectedSet = new Set(selectedIds.map((id) => String(id)));
let orderedIds = heroSmsCountrySelectionOrder
.map((id) => normalizePhoneSmsCountryId(id, normalizedProvider))
.filter((id) => id && selectedSet.has(String(id)));
selectedIds.forEach((id) => {
if (!orderedIds.some((existing) => String(existing) === String(id))) {
orderedIds.push(id);
}
});
if (!orderedIds.length && ensureDefault) {
orderedIds = [defaultCountry.id];
}
return orderedIds.slice(0, selectionLimit).map((id) => {
const option = optionByValue.get(String(id));
const optionLabel = String(option?.textContent || '').trim();
return {
id,
label: optionLabel || normalizePhoneSmsCountryLabel(defaultCountry.id === id ? defaultCountry.label : '', normalizedProvider),
};
});
}
async function switchPhoneSmsProvider(nextProvider) {
const previousProvider = getLastAppliedPhoneSmsProvider();
const normalizedNextProvider = normalizePhoneSmsProvider(nextProvider);
const currentApiKey = String(inputHeroSmsApiKey?.value || '');
const currentMaxPrice = normalizePhoneSmsMaxPriceValue(inputHeroSmsMaxPrice?.value || '', previousProvider);
const currentSelection = typeof syncHeroSmsFallbackSelectionOrderFromSelect === 'function'
? syncHeroSmsFallbackSelectionOrderFromSelect({ enforceMax: true, ensureDefault: true, showLimitToast: false })
const currentSelection = typeof getPhoneSmsCountrySelectionForProvider === 'function'
? getPhoneSmsCountrySelectionForProvider(previousProvider, { ensureDefault: true })
: [];
const currentPrimary = currentSelection[0] || getSelectedHeroSmsCountryOption();
const currentFallback = currentSelection.slice(1);
@@ -10439,6 +10693,9 @@ async function switchPhoneSmsProvider(nextProvider) {
patch.fiveSimCountryId = currentPrimary.id;
patch.fiveSimCountryLabel = currentPrimary.label;
patch.fiveSimCountryFallback = currentFallback;
patch.fiveSimCountryOrder = [currentPrimary, ...currentFallback]
.map((country) => normalizeFiveSimCountryId(country?.id, ''))
.filter(Boolean);
patch.fiveSimOperator = normalizeFiveSimOperator(inputFiveSimOperator?.value || latestState?.fiveSimOperator);
} else {
patch.heroSmsApiKey = currentApiKey;
@@ -11260,6 +11517,16 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
);
updatePlusModeUI();
}
if (
message.payload.plusManualConfirmationPending !== undefined
|| message.payload.plusManualConfirmationRequestId !== undefined
|| message.payload.plusManualConfirmationStep !== undefined
|| message.payload.plusManualConfirmationMethod !== undefined
|| message.payload.plusManualConfirmationTitle !== undefined
|| message.payload.plusManualConfirmationMessage !== undefined
) {
void syncPlusManualConfirmationDialog();
}
if (message.payload.currentHotmailAccountId !== undefined || message.payload.hotmailAccounts !== undefined) {
renderHotmailAccounts();
if (selectMailProvider.value === 'hotmail-api') {
@@ -11511,6 +11778,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|| message.payload.fiveSimCountryId !== undefined
|| message.payload.fiveSimCountryLabel !== undefined
|| message.payload.fiveSimCountryFallback !== undefined
|| message.payload.fiveSimCountryOrder !== undefined
) {
const activeProvider = getSelectedPhoneSmsProvider();
const nextPrimary = activeProvider === PHONE_SMS_PROVIDER_FIVE_SIM
@@ -11542,6 +11810,8 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
? normalizeFiveSimCountryFallbackList(
message.payload.fiveSimCountryFallback !== undefined
? message.payload.fiveSimCountryFallback
: message.payload.fiveSimCountryOrder !== undefined
? message.payload.fiveSimCountryOrder
: latestState?.fiveSimCountryFallback
)
: normalizeHeroSmsCountryFallbackList(