diff --git a/background.js b/background.js
index 04fcd5a..2ae336c 100644
--- a/background.js
+++ b/background.js
@@ -719,8 +719,6 @@ const DEFAULT_FIVE_SIM_COUNTRY_ORDER = Object.freeze(['thailand']);
const DEFAULT_NEX_SMS_BASE_URL = 'https://api.nexsms.net';
const DEFAULT_NEX_SMS_SERVICE_CODE = 'ot';
const DEFAULT_NEX_SMS_COUNTRY_ORDER = Object.freeze([1]);
-const DEFAULT_SMS_BOWER_SERVICE_CODE = 'ot';
-const DEFAULT_SMS_BOWER_COUNTRY_ORDER = Object.freeze([52]);
const DEFAULT_MADAO_BASE_URL = 'http://127.0.0.1:7822';
const DEFAULT_MADAO_MODE = 'routing_plan';
const DEFAULT_HERO_SMS_REUSE_ENABLED = true;
@@ -1453,6 +1451,11 @@ const PERSISTED_SETTING_DEFAULTS = {
nexSmsCountryOrder: [...DEFAULT_NEX_SMS_COUNTRY_ORDER],
nexSmsServiceCode: DEFAULT_NEX_SMS_SERVICE_CODE,
smsBowerApiKey: '',
+ smsBowerCountryId: 6,
+ smsBowerCountryLabel: 'Indonesia',
+ smsBowerCountryOrder: [6],
+ smsBowerMinPrice: '',
+ smsBowerMaxPrice: '',
madaoBaseUrl: DEFAULT_MADAO_BASE_URL,
madaoHttpSecret: '',
madaoMode: DEFAULT_MADAO_MODE,
@@ -2205,6 +2208,59 @@ function normalizeNexSmsServiceCode(value = '', fallback = DEFAULT_NEX_SMS_SERVI
return fallbackNormalized || DEFAULT_NEX_SMS_SERVICE_CODE;
}
+function normalizeSmsBowerCountryId(value, fallback = 6) {
+ const parsed = Math.floor(Number(value));
+ if (Number.isFinite(parsed) && parsed >= 0) {
+ return parsed;
+ }
+ const fallbackParsed = Math.floor(Number(fallback));
+ if (Number.isFinite(fallbackParsed) && fallbackParsed >= 0) {
+ return fallbackParsed;
+ }
+ return 6;
+}
+
+function normalizeSmsBowerCountryLabel(value = '', fallback = 'Indonesia') {
+ return String(value || '').trim() || fallback;
+}
+
+function normalizeSmsBowerCountryOrder(value = []) {
+ const source = Array.isArray(value)
+ ? value
+ : String(value || '')
+ .split(/[\r\n,,;;]+/)
+ .map((entry) => String(entry || '').trim())
+ .filter(Boolean);
+ const normalized = [];
+ const seen = new Set();
+ source.forEach((entry) => {
+ const id = normalizeSmsBowerCountryId(
+ entry && typeof entry === 'object' && !Array.isArray(entry)
+ ? (entry.id ?? entry.countryId ?? entry.country ?? '')
+ : entry,
+ -1
+ );
+ if (id < 0 || seen.has(id)) {
+ return;
+ }
+ seen.add(id);
+ normalized.push(id);
+ });
+ return normalized.length ? normalized.slice(0, 10) : [6];
+}
+
+function normalizeSmsBowerMaxPrice(value = '') {
+ const normalized = String(value || '').trim();
+ if (!normalized) {
+ return '';
+ }
+ const numeric = Number(normalized.replace(',', '.'));
+ if (!Number.isFinite(numeric) || numeric < 0) {
+ return '';
+ }
+ return String(Number(numeric.toFixed(4))).replace(/\.0+$/, '');
+}
+
function normalizeMaDaoBaseUrl(value = '') {
const normalized = normalizeLocalHttpBaseUrl(value, DEFAULT_MADAO_BASE_URL);
try {
@@ -3600,6 +3656,17 @@ function normalizePersistentSettingValue(key, value) {
return normalizeNexSmsCountryOrder(value);
case 'nexSmsServiceCode':
return normalizeNexSmsServiceCode(value);
+ case 'smsBowerApiKey':
+ return String(value || '');
+ case 'smsBowerCountryId':
+ return normalizeSmsBowerCountryId(value);
+ case 'smsBowerCountryLabel':
+ return normalizeSmsBowerCountryLabel(value);
+ case 'smsBowerCountryOrder':
+ return normalizeSmsBowerCountryOrder(value);
+ case 'smsBowerMinPrice':
+ case 'smsBowerMaxPrice':
+ return normalizeSmsBowerMaxPrice(value);
case 'madaoBaseUrl':
return normalizeMaDaoBaseUrl(value);
case 'madaoHttpSecret':
diff --git a/phone-sms/providers/sms-bower.js b/phone-sms/providers/sms-bower.js
index 85666bf..64e5a63 100644
--- a/phone-sms/providers/sms-bower.js
+++ b/phone-sms/providers/sms-bower.js
@@ -292,9 +292,6 @@
country: normalizeSmsBowerCountryId(countryConfig.id, DEFAULT_COUNTRY_ID),
maxPrice: range.maxPriceLimit,
minPrice: range.minPriceLimit,
- providerIds: normalizeCsvIds(state.smsBowerProviderIds),
- exceptProviderIds: normalizeCsvIds(state.smsBowerExceptProviderIds),
- phoneException: normalizeCsvIds(state.smsBowerPhoneException),
};
}
diff --git a/sidepanel/sidepanel.html b/sidepanel/sidepanel.html
index 21a6475..652b6b2 100644
--- a/sidepanel/sidepanel.html
+++ b/sidepanel/sidepanel.html
@@ -1546,6 +1546,26 @@
data-hide-label="隐藏 SMS Bower Token" aria-label="显示 SMS Bower Token" title="显示 SMS Bower Token">
+
+
地区选择
+
+
+ 可多选,按列表顺序作为购买重试顺序。
+
+
+
+
生效顺序
+
+ Indonesia #6
+
+
+
MaDao 地址
normalizeNexSmsCountryIdForPayload(country.id, -1))
.filter((countryId) => countryId >= 0)
: normalizeNexSmsCountryOrderForPayload(latestState?.nexSmsCountryOrder || []);
+ const normalizeSmsBowerCountryIdForPayload = typeof normalizeSmsBowerCountryIdValue === 'function'
+ ? normalizeSmsBowerCountryIdValue
+ : ((value, fallback = 6) => {
+ const parsed = Math.floor(Number(value));
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
+ });
+ const normalizeSmsBowerCountryLabelForPayload = typeof normalizeSmsBowerCountryLabelValue === 'function'
+ ? normalizeSmsBowerCountryLabelValue
+ : ((value = '', fallback = 'Indonesia') => String(value || '').trim() || fallback);
+ const normalizeSmsBowerCountryOrderForPayload = typeof normalizeSmsBowerCountryOrderValue === 'function'
+ ? normalizeSmsBowerCountryOrderValue
+ : ((value = []) => {
+ const values = Array.isArray(value) ? value : [value];
+ const mapped = values
+ .map((entry) => normalizeSmsBowerCountryIdForPayload(entry && typeof entry === 'object' ? entry.id : entry, -1))
+ .filter((entry) => entry >= 0);
+ return mapped.length > 0
+ ? mapped.map((id) => ({ id, label: id === 6 ? 'Indonesia' : `Country #${id}` }))
+ : [{ id: 6, label: 'Indonesia' }];
+ });
+ const smsBowerSelectedCountries = phoneSmsProviderValue === smsBowerProviderConstant && typeof getSelectedSmsBowerCountries === 'function'
+ ? getSelectedSmsBowerCountries()
+ : normalizeSmsBowerCountryOrderForPayload(latestState?.smsBowerCountryOrder || []);
+ const smsBowerCountry = smsBowerSelectedCountries[0] || {
+ id: normalizeSmsBowerCountryIdForPayload(latestState?.smsBowerCountryId),
+ label: normalizeSmsBowerCountryLabelForPayload(latestState?.smsBowerCountryLabel),
+ };
+ const smsBowerCountryOrderValue = smsBowerSelectedCountries.map((country) => country.id);
const heroSmsCountryFallback = phoneSmsProviderValue === PHONE_SMS_PROVIDER_HERO_SMS
? selectedPhoneSmsCountryFallback
: normalizeHeroSmsCountryFallbackList(latestState?.heroSmsCountryFallback || []);
@@ -5304,6 +5349,11 @@ function collectSettingsPayload() {
nexSmsCountryOrder: nexSmsCountryOrderValue,
nexSmsServiceCode: nexSmsServiceCodeValue,
smsBowerApiKey: smsBowerApiKeyValue,
+ smsBowerCountryId: smsBowerCountry.id,
+ smsBowerCountryLabel: smsBowerCountry.label,
+ smsBowerCountryOrder: smsBowerCountryOrderValue,
+ smsBowerMinPrice: smsBowerMinPriceValue,
+ smsBowerMaxPrice: smsBowerMaxPriceValue,
madaoBaseUrl: maDaoBaseUrlValue,
madaoHttpSecret: maDaoHttpSecretValue,
madaoMode: maDaoModeValue,
@@ -5544,6 +5594,9 @@ function normalizePhoneSmsMaxPriceValue(value = '', provider = getSelectedPhoneS
if (normalizedProvider === PHONE_SMS_PROVIDER_MADAO) {
return normalizeMaDaoPriceValue(value);
}
+ if (normalizedProvider === PHONE_SMS_PROVIDER_SMS_BOWER && typeof window !== 'undefined' && window.PhoneSmsBowerProvider?.normalizeSmsBowerMaxPrice) {
+ return window.PhoneSmsBowerProvider.normalizeSmsBowerMaxPrice(value);
+ }
return normalizeHeroSmsMaxPriceValue(value);
}
@@ -5555,9 +5608,54 @@ function normalizePhoneSmsMinPriceValue(value = '', provider = getSelectedPhoneS
if (normalizedProvider === PHONE_SMS_PROVIDER_MADAO) {
return normalizeMaDaoPriceValue(value);
}
+ if (normalizedProvider === PHONE_SMS_PROVIDER_SMS_BOWER && typeof window !== 'undefined' && window.PhoneSmsBowerProvider?.normalizeSmsBowerMaxPrice) {
+ return window.PhoneSmsBowerProvider.normalizeSmsBowerMaxPrice(value);
+ }
return normalizeHeroSmsMaxPriceValue(value);
}
+function normalizeSmsBowerCountryIdValue(value, fallback = 6) {
+ if (typeof window !== 'undefined' && window.PhoneSmsBowerProvider?.normalizeSmsBowerCountryId) {
+ return window.PhoneSmsBowerProvider.normalizeSmsBowerCountryId(value, fallback);
+ }
+ const parsed = Math.floor(Number(value));
+ if (Number.isFinite(parsed) && parsed >= 0) {
+ return parsed;
+ }
+ const fallbackParsed = Math.floor(Number(fallback));
+ return Number.isFinite(fallbackParsed) && fallbackParsed >= 0 ? fallbackParsed : 6;
+}
+
+function normalizeSmsBowerCountryLabelValue(value = '', fallback = 'Indonesia') {
+ if (typeof window !== 'undefined' && window.PhoneSmsBowerProvider?.normalizeSmsBowerCountryLabel) {
+ return window.PhoneSmsBowerProvider.normalizeSmsBowerCountryLabel(value, fallback);
+ }
+ return String(value || '').trim() || fallback;
+}
+
+function normalizeSmsBowerCountryOrderValue(value = []) {
+ const source = Array.isArray(value)
+ ? value
+ : String(value || '').split(/[\r\n,,;;]+/).map((entry) => String(entry || '').trim()).filter(Boolean);
+ const seen = new Set();
+ const normalized = [];
+ source.forEach((entry) => {
+ const rawId = entry && typeof entry === 'object' && !Array.isArray(entry)
+ ? (entry.id ?? entry.countryId)
+ : String(entry || '').trim().match(/^(\d+)/)?.[1];
+ const id = normalizeSmsBowerCountryIdValue(rawId, -1);
+ if (id < 0 || seen.has(id)) {
+ return;
+ }
+ seen.add(id);
+ const rawLabel = entry && typeof entry === 'object' && !Array.isArray(entry)
+ ? (entry.label ?? entry.countryLabel)
+ : String(entry || '').trim().replace(/^\d+\s*(?:[:|/-]\s*)?/, '');
+ normalized.push({ id, label: normalizeSmsBowerCountryLabelValue(rawLabel, id === 6 ? 'Indonesia' : `Country #${id}`) });
+ });
+ return normalized;
+}
+
function getPhoneSmsProviderCount() {
const rootScope = typeof window !== 'undefined' ? window : globalThis;
const registryIds = rootScope.PhoneSmsProviderRegistry?.getProviderIds?.();
@@ -7624,6 +7722,27 @@ function getSelectedNexSmsCountries() {
});
}
+function getSelectedSmsBowerCountries() {
+ const selected = Array.from(selectSmsBowerCountry?.options || [])
+ .filter((option) => option.selected)
+ .map((option) => ({
+ id: normalizeSmsBowerCountryIdValue(option.value, -1),
+ label: normalizeSmsBowerCountryLabelValue(option.textContent, `Country #${option.value}`),
+ }))
+ .filter((country) => country.id >= 0);
+ return selected.length ? selected : [{ id: 6, label: 'Indonesia' }];
+}
+
+function renderSmsBowerCountryFallbackOrder(countries = getSelectedSmsBowerCountries()) {
+ if (!displaySmsBowerCountryFallbackOrder) {
+ return;
+ }
+ const normalized = normalizeSmsBowerCountryOrderValue(countries);
+ displaySmsBowerCountryFallbackOrder.textContent = normalized.length
+ ? normalized.map((country, index) => `${index + 1}. ${country.label}(${country.id})`).join(' → ')
+ : 'Indonesia #6';
+}
+
function updateHeroSmsPlatformDisplay() {
if (!displayHeroSmsPlatform) {
return;
@@ -7633,9 +7752,11 @@ function updateHeroSmsPlatformDisplay() {
? (getSelectedFiveSimCountries()[0] || { id: DEFAULT_FIVE_SIM_COUNTRY_ID, label: DEFAULT_FIVE_SIM_COUNTRY_LABEL })
: (provider === PHONE_SMS_PROVIDER_NEXSMS
? (getSelectedNexSmsCountries()[0] || { id: DEFAULT_NEX_SMS_COUNTRY_ORDER[0], label: `Country #${DEFAULT_NEX_SMS_COUNTRY_ORDER[0]}` })
- : (provider === PHONE_SMS_PROVIDER_MADAO
- ? { id: '', label: normalizeMaDaoModeValue(selectMaDaoMode?.value || latestState?.madaoMode) === MADAO_MODE_DIRECT ? 'direct' : getSelectedMaDaoRoutingPlanLabel() }
- : getSelectedHeroSmsCountryOption()));
+ : (provider === PHONE_SMS_PROVIDER_SMS_BOWER
+ ? (getSelectedSmsBowerCountries()[0] || { id: 6, label: 'Indonesia' })
+ : (provider === PHONE_SMS_PROVIDER_MADAO
+ ? { id: '', label: normalizeMaDaoModeValue(selectMaDaoMode?.value || latestState?.madaoMode) === MADAO_MODE_DIRECT ? 'direct' : getSelectedMaDaoRoutingPlanLabel() }
+ : getSelectedHeroSmsCountryOption())));
const countryText = selected?.label ? ` / ${selected.label}` : '';
displayHeroSmsPlatform.textContent = `${getPhoneSmsProviderLabel(provider)} / OpenAI${countryText}`;
if (inputHeroSmsApiKey) {
@@ -12419,6 +12540,22 @@ function applySettingsState(state) {
? normalizeNexSmsServiceCodeValue(state?.nexSmsServiceCode || defaultNexSmsServiceCode)
: String(state?.nexSmsServiceCode || defaultNexSmsServiceCode).trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '') || defaultNexSmsServiceCode;
}
+ if (typeof inputSmsBowerApiKey !== 'undefined' && inputSmsBowerApiKey) {
+ inputSmsBowerApiKey.value = String(state?.smsBowerApiKey || '');
+ }
+ if (typeof selectSmsBowerCountry !== 'undefined' && selectSmsBowerCountry) {
+ const selectedIds = new Set(
+ normalizeSmsBowerCountryOrderValue(state?.smsBowerCountryOrder || [state?.smsBowerCountryId || 6])
+ .map((country) => String(country.id))
+ );
+ if (!selectedIds.size) {
+ selectedIds.add('6');
+ }
+ Array.from(selectSmsBowerCountry.options || []).forEach((option) => {
+ option.selected = selectedIds.has(String(option.value));
+ });
+ renderSmsBowerCountryFallbackOrder();
+ }
if (typeof inputMaDaoBaseUrl !== 'undefined' && inputMaDaoBaseUrl) {
inputMaDaoBaseUrl.value = normalizeMaDaoBaseUrlValue(state?.madaoBaseUrl);
}
@@ -12474,15 +12611,22 @@ function applySettingsState(state) {
if (typeof selectHeroSmsOperator !== 'undefined' && selectHeroSmsOperator) {
setHeroSmsOperatorSelectValue(state?.heroSmsOperator);
}
+ const smsBowerProviderConstant = typeof PHONE_SMS_PROVIDER_SMS_BOWER !== 'undefined'
+ ? PHONE_SMS_PROVIDER_SMS_BOWER
+ : 'sms-bower';
if (inputHeroSmsMaxPrice) {
inputHeroSmsMaxPrice.value = restoredPhoneSmsProvider === PHONE_SMS_PROVIDER_FIVE_SIM
? normalizeFiveSimMaxPriceValue(state?.fiveSimMaxPrice || '')
- : normalizeHeroSmsMaxPriceValue(state?.heroSmsMaxPrice || '');
+ : (restoredPhoneSmsProvider === smsBowerProviderConstant
+ ? normalizePhoneSmsMaxPriceValue(state?.smsBowerMaxPrice || '', smsBowerProviderConstant)
+ : normalizeHeroSmsMaxPriceValue(state?.heroSmsMaxPrice || ''));
}
if (typeof inputHeroSmsMinPrice !== 'undefined' && inputHeroSmsMinPrice) {
inputHeroSmsMinPrice.value = restoredPhoneSmsProvider === PHONE_SMS_PROVIDER_FIVE_SIM
? normalizePhoneSmsMinPriceValue(state?.fiveSimMinPrice || '', PHONE_SMS_PROVIDER_FIVE_SIM)
- : normalizePhoneSmsMinPriceValue(state?.heroSmsMinPrice || '', restoredPhoneSmsProvider);
+ : (restoredPhoneSmsProvider === smsBowerProviderConstant
+ ? normalizePhoneSmsMinPriceValue(state?.smsBowerMinPrice || '', smsBowerProviderConstant)
+ : normalizePhoneSmsMinPriceValue(state?.heroSmsMinPrice || '', restoredPhoneSmsProvider));
}
if (inputFiveSimOperator) {
inputFiveSimOperator.value = normalizeFiveSimOperator(state?.fiveSimOperator);
@@ -17735,6 +17879,23 @@ function buildPhoneSmsProviderStatePatch(provider = getSelectedPhoneSmsProvider(
nexSmsServiceCode: normalizeNexSmsServiceCodeValue(inputNexSmsServiceCode?.value || latestState?.nexSmsServiceCode || DEFAULT_NEX_SMS_SERVICE_CODE),
};
}
+ if (normalizedProvider === PHONE_SMS_PROVIDER_SMS_BOWER) {
+ const smsBowerCountries = typeof getSelectedSmsBowerCountries === 'function'
+ ? getSelectedSmsBowerCountries()
+ : normalizeSmsBowerCountryOrderValue(latestState?.smsBowerCountryOrder || []);
+ const currentPrimary = smsBowerCountries[0] || {
+ id: normalizeSmsBowerCountryIdValue(latestState?.smsBowerCountryId || 6),
+ label: normalizeSmsBowerCountryLabelValue(latestState?.smsBowerCountryLabel || 'Indonesia'),
+ };
+ return {
+ smsBowerApiKey: String(inputSmsBowerApiKey?.value || ''),
+ smsBowerCountryId: currentPrimary.id,
+ smsBowerCountryLabel: currentPrimary.label,
+ smsBowerCountryOrder: smsBowerCountries.map((country) => country.id),
+ smsBowerMinPrice: normalizePhoneSmsMinPriceValue(inputHeroSmsMinPrice?.value || '', PHONE_SMS_PROVIDER_SMS_BOWER),
+ smsBowerMaxPrice: normalizePhoneSmsMaxPriceValue(inputHeroSmsMaxPrice?.value || '', PHONE_SMS_PROVIDER_SMS_BOWER),
+ };
+ }
if (normalizedProvider === PHONE_SMS_PROVIDER_MADAO) {
const maDaoMode = normalizeMaDaoModeValue(selectMaDaoMode?.value || latestState?.madaoMode);
const maDaoDirectModeValue = typeof MADAO_MODE_DIRECT !== 'undefined'
@@ -17801,6 +17962,17 @@ function applyPhoneSmsProviderFieldsToInputs(provider = getSelectedPhoneSmsProvi
if (typeof inputSmsBowerApiKey !== 'undefined' && inputSmsBowerApiKey) {
inputSmsBowerApiKey.value = String(state?.smsBowerApiKey || '');
}
+ if (typeof selectSmsBowerCountry !== 'undefined' && selectSmsBowerCountry) {
+ const selectedIds = new Set(
+ normalizeSmsBowerCountryOrderValue(state?.smsBowerCountryOrder || [state?.smsBowerCountryId || 6])
+ .map((country) => String(country.id))
+ );
+ if (!selectedIds.size) selectedIds.add('6');
+ Array.from(selectSmsBowerCountry.options || []).forEach((option) => {
+ option.selected = selectedIds.has(String(option.value));
+ });
+ renderSmsBowerCountryFallbackOrder();
+ }
if (typeof inputMaDaoBaseUrl !== 'undefined' && inputMaDaoBaseUrl) {
inputMaDaoBaseUrl.value = normalizeMaDaoBaseUrlValue(state?.madaoBaseUrl);
}
@@ -17841,12 +18013,16 @@ function applyPhoneSmsProviderFieldsToInputs(provider = getSelectedPhoneSmsProvi
if (inputHeroSmsMaxPrice) {
inputHeroSmsMaxPrice.value = normalizedProvider === PHONE_SMS_PROVIDER_FIVE_SIM
? normalizeFiveSimMaxPriceValue(state?.fiveSimMaxPrice || '')
- : normalizeHeroSmsMaxPriceValue(state?.heroSmsMaxPrice || '');
+ : (normalizedProvider === PHONE_SMS_PROVIDER_SMS_BOWER
+ ? normalizePhoneSmsMaxPriceValue(state?.smsBowerMaxPrice || '', PHONE_SMS_PROVIDER_SMS_BOWER)
+ : normalizeHeroSmsMaxPriceValue(state?.heroSmsMaxPrice || ''));
}
if (typeof inputHeroSmsMinPrice !== 'undefined' && inputHeroSmsMinPrice) {
inputHeroSmsMinPrice.value = normalizedProvider === PHONE_SMS_PROVIDER_FIVE_SIM
? normalizePhoneSmsMinPriceValue(state?.fiveSimMinPrice || '', PHONE_SMS_PROVIDER_FIVE_SIM)
- : normalizePhoneSmsMinPriceValue(state?.heroSmsMinPrice || '', PHONE_SMS_PROVIDER_HERO_SMS);
+ : (normalizedProvider === PHONE_SMS_PROVIDER_SMS_BOWER
+ ? normalizePhoneSmsMinPriceValue(state?.smsBowerMinPrice || '', PHONE_SMS_PROVIDER_SMS_BOWER)
+ : normalizePhoneSmsMinPriceValue(state?.heroSmsMinPrice || '', PHONE_SMS_PROVIDER_HERO_SMS));
}
if (typeof inputHeroSmsPreferredPrice !== 'undefined' && inputHeroSmsPreferredPrice) {
inputHeroSmsPreferredPrice.value = normalizeHeroSmsMaxPriceValue(state?.heroSmsPreferredPrice || '');
@@ -18379,6 +18555,23 @@ selectNexSmsCountry?.addEventListener('change', () => {
saveSettings({ silent: true }).catch(() => { });
});
+selectSmsBowerCountry?.addEventListener('change', () => {
+ renderSmsBowerCountryFallbackOrder();
+ updateHeroSmsPlatformDisplay();
+ markSettingsDirty(true);
+ saveSettings({ silent: true }).catch(() => { });
+});
+
+btnSmsBowerCountryClear?.addEventListener('click', () => {
+ Array.from(selectSmsBowerCountry?.options || []).forEach((option) => {
+ option.selected = String(option.value) === '6';
+ });
+ renderSmsBowerCountryFallbackOrder();
+ updateHeroSmsPlatformDisplay();
+ markSettingsDirty(true);
+ saveSettings({ silent: true }).catch(() => { });
+});
+
btnHeroSmsPricePreview?.addEventListener('click', async () => {
try {
await previewHeroSmsPriceTiers();
diff --git a/tests/sidepanel-phone-verification-settings.test.js b/tests/sidepanel-phone-verification-settings.test.js
index 0a27319..643d140 100644
--- a/tests/sidepanel-phone-verification-settings.test.js
+++ b/tests/sidepanel-phone-verification-settings.test.js
@@ -149,6 +149,14 @@ test('sidepanel html exposes phone verification toggle and multi-provider SMS ro
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.match(html, /id="row-sms-bower-api-key"/);
+ assert.match(html, /id="input-sms-bower-api-key"/);
+ assert.match(html, /id="row-sms-bower-country"/);
+ assert.match(html, /id="select-sms-bower-country"/);
+ assert.match(html, /id="row-sms-bower-country-fallback"/);
+ assert.doesNotMatch(html, /id="row-sms-bower-max-price"/);
+ assert.doesNotMatch(html, /id="input-sms-bower-min-price"/);
+ assert.doesNotMatch(html, /id="input-sms-bower-max-price"/);
assert.match(html, /id="row-madao-base-url"/);
assert.match(html, /id="input-madao-base-url"/);
assert.match(html, /id="row-madao-http-secret"/);
@@ -185,6 +193,30 @@ test('sidepanel html exposes phone verification toggle and multi-provider SMS ro
assert.doesNotMatch(html, /id="input-account-run-history-text-enabled"/);
});
+
+test('SMS Bower sidepanel exposes HeroSMS-like user controls while hiding internal IDs', () => {
+ assert.match(sidepanelSource, /smsBowerApiKey:/);
+ assert.match(sidepanelSource, /rowSmsBowerApiKey/);
+ assert.match(sidepanelSource, /\[PHONE_SMS_PROVIDER_SMS_BOWER\]: Object\.freeze\(\{\s*rowKeys: Object\.freeze\(\[\s*'rowSmsBowerApiKey',\s*'rowSmsBowerCountry',\s*'rowSmsBowerCountryFallback',\s*'rowHeroSmsMaxPrice',\s*\]\),\s*\}\)/);
+ assert.match(sidepanelSource, /smsBowerApiKey:\s*smsBowerApiKeyValue/);
+ assert.match(sidepanelSource, /smsBowerCountryId:/);
+ assert.match(sidepanelSource, /smsBowerCountryLabel:/);
+ assert.match(sidepanelSource, /smsBowerCountryOrder:/);
+ assert.match(sidepanelSource, /smsBowerMinPrice:/);
+ assert.match(sidepanelSource, /smsBowerMaxPrice:/);
+ assert.match(sidepanelSource, /inputVerificationResendCount/);
+ assert.match(sidepanelSource, /rowPhoneVerificationResendCount/);
+ assert.match(sidepanelHtml, /id="row-sms-bower-country"/);
+ assert.match(sidepanelHtml, /id="select-sms-bower-country"/);
+ assert.match(sidepanelHtml, /id="row-sms-bower-country-fallback"/);
+ assert.doesNotMatch(sidepanelSource, /smsBowerProviderIds:/);
+ assert.doesNotMatch(sidepanelSource, /smsBowerExceptProviderIds:/);
+ assert.doesNotMatch(sidepanelSource, /case 'smsBowerProviderIds':/);
+ assert.doesNotMatch(sidepanelHtml, /id="input-sms-bower-country-id"/);
+ assert.doesNotMatch(sidepanelHtml, /id="input-sms-bower-provider-ids"/);
+ assert.doesNotMatch(sidepanelHtml, /id="input-sms-bower-except-provider-ids"/);
+});
+
test('sidepanel loads live SMS country lists silently during startup', () => {
const heroLoader = extractFunction('loadHeroSmsCountries');
const fiveSimLoader = extractFunction('loadFiveSimCountries');
@@ -934,6 +966,8 @@ const rowNexSmsCountry = { style: { display: 'none' } };
const rowNexSmsCountryFallback = { style: { display: 'none' } };
const rowNexSmsServiceCode = { style: { display: 'none' } };
const rowSmsBowerApiKey = { style: { display: 'none' } };
+const rowSmsBowerCountry = { style: { display: 'none' } };
+const rowSmsBowerCountryFallback = { style: { display: 'none' } };
const rowMaDaoBaseUrl = { style: { display: 'none' } };
const rowMaDaoHttpSecret = { style: { display: 'none' } };
const rowMaDaoMode = { style: { display: 'none' } };
@@ -973,6 +1007,7 @@ const PHONE_SMS_PROVIDER_HERO_SMS = 'hero-sms';
const PHONE_SMS_PROVIDER_HERO = PHONE_SMS_PROVIDER_HERO_SMS;
const PHONE_SMS_PROVIDER_FIVE_SIM = '5sim';
const PHONE_SMS_PROVIDER_NEXSMS = 'nexsms';
+const PHONE_SMS_PROVIDER_SMS_BOWER = 'sms-bower';
const PHONE_SMS_PROVIDER_MADAO = 'madao';
const MADAO_MODE_ROUTING_PLAN = 'routing_plan';
const MADAO_MODE_DIRECT = 'direct';
@@ -1013,6 +1048,9 @@ const PHONE_SMS_PROVIDER_UI_DESCRIPTORS = ${JSON.stringify({
'sms-bower': {
rowKeys: [
'rowSmsBowerApiKey',
+ 'rowSmsBowerCountry',
+ 'rowSmsBowerCountryFallback',
+ 'rowHeroSmsMaxPrice',
],
},
madao: {
@@ -1464,6 +1502,7 @@ const PHONE_SMS_PROVIDER_HERO_SMS = 'hero-sms';
const PHONE_SMS_PROVIDER_HERO = PHONE_SMS_PROVIDER_HERO_SMS;
const PHONE_SMS_PROVIDER_FIVE_SIM = '5sim';
const PHONE_SMS_PROVIDER_NEXSMS = 'nexsms';
+const PHONE_SMS_PROVIDER_SMS_BOWER = 'sms-bower';
const PHONE_SMS_PROVIDER_MADAO = 'madao';
const DEFAULT_PHONE_SMS_PROVIDER = PHONE_SMS_PROVIDER_HERO_SMS;
const DEFAULT_MADAO_BASE_URL = 'http://127.0.0.1:7822';
@@ -1523,6 +1562,9 @@ ${extractFunction('normalizeFiveSimProductValue')}
${extractFunction('normalizeNexSmsCountryIdValue')}
${extractFunction('normalizeNexSmsCountryOrderValue')}
${extractFunction('normalizeNexSmsServiceCodeValue')}
+${extractFunction('normalizeSmsBowerCountryIdValue')}
+${extractFunction('normalizeSmsBowerCountryLabelValue')}
+${extractFunction('normalizeSmsBowerCountryOrderValue')}
function getSelectedPhoneSmsProvider() { return normalizePhoneSmsProvider(selectPhoneSmsProvider?.value || latestState?.phoneSmsProvider); }
function getSelectedPhoneSmsProviderOrder() { return ['nexsms', '5sim']; }
${extractFunction('normalizeFiveSimCountryId')}
@@ -1660,6 +1702,7 @@ const PHONE_SMS_PROVIDER_HERO_SMS = 'hero-sms';
const PHONE_SMS_PROVIDER_HERO = PHONE_SMS_PROVIDER_HERO_SMS;
const PHONE_SMS_PROVIDER_FIVE_SIM = '5sim';
const PHONE_SMS_PROVIDER_NEXSMS = 'nexsms';
+const PHONE_SMS_PROVIDER_SMS_BOWER = 'sms-bower';
const PHONE_SMS_PROVIDER_MADAO = 'madao';
const DEFAULT_PHONE_SMS_PROVIDER = PHONE_SMS_PROVIDER_HERO_SMS;
const DEFAULT_PHONE_SMS_PROVIDER_ORDER = ['hero-sms', '5sim', 'nexsms', 'madao'];
@@ -1877,6 +1920,7 @@ const PHONE_SMS_PROVIDER_HERO_SMS = 'hero-sms';
const PHONE_SMS_PROVIDER_HERO = PHONE_SMS_PROVIDER_HERO_SMS;
const PHONE_SMS_PROVIDER_FIVE_SIM = '5sim';
const PHONE_SMS_PROVIDER_NEXSMS = 'nexsms';
+const PHONE_SMS_PROVIDER_SMS_BOWER = 'sms-bower';
const PHONE_SMS_PROVIDER_MADAO = 'madao';
const DEFAULT_PHONE_SMS_PROVIDER = PHONE_SMS_PROVIDER_HERO_SMS;
const DEFAULT_FIVE_SIM_COUNTRY_ID = 'vietnam';
diff --git a/tests/sms-bower-provider.test.js b/tests/sms-bower-provider.test.js
index 8d23122..86fdb4f 100644
--- a/tests/sms-bower-provider.test.js
+++ b/tests/sms-bower-provider.test.js
@@ -91,9 +91,8 @@ test('SMS Bower provider acquires number, polls code, and updates activation sta
smsBowerServiceCode: 'ot',
smsBowerCountryId: 16,
smsBowerCountryLabel: 'United Kingdom',
- smsBowerMaxPrice: '0.3',
smsBowerMinPrice: '0.1',
- smsBowerProviderIds: '3170,3180',
+ smsBowerMaxPrice: '0.3',
};
const activation = await provider.requestActivation(state);
@@ -116,7 +115,9 @@ test('SMS Bower provider acquires number, polls code, and updates activation sta
assert.equal(acquireUrl.searchParams.get('country'), '16');
assert.equal(acquireUrl.searchParams.get('maxPrice'), '0.3');
assert.equal(acquireUrl.searchParams.get('minPrice'), '0.1');
- assert.equal(acquireUrl.searchParams.get('providerIds'), '3170,3180');
+ assert.equal(acquireUrl.searchParams.get('providerIds'), null);
+ assert.equal(acquireUrl.searchParams.get('exceptProviderIds'), null);
+ assert.equal(acquireUrl.searchParams.get('phoneException'), null);
assert.deepStrictEqual(
requests.map((entry) => [entry.url.searchParams.get('action'), entry.url.searchParams.get('status')]),
[