完善手机接码逻辑
This commit is contained in:
+30
-5
@@ -809,6 +809,7 @@ const PERSISTED_SETTING_DEFAULTS = {
|
|||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
step6CookieCleanupEnabled: false,
|
step6CookieCleanupEnabled: false,
|
||||||
phoneVerificationEnabled: false,
|
phoneVerificationEnabled: false,
|
||||||
|
phoneSmsReuseEnabled: DEFAULT_HERO_SMS_REUSE_ENABLED,
|
||||||
freePhoneReuseEnabled: true,
|
freePhoneReuseEnabled: true,
|
||||||
freePhoneReuseAutoEnabled: true,
|
freePhoneReuseAutoEnabled: true,
|
||||||
signupMethod: DEFAULT_SIGNUP_METHOD,
|
signupMethod: DEFAULT_SIGNUP_METHOD,
|
||||||
@@ -1329,12 +1330,15 @@ function normalizePhoneSmsProvider(value = '') {
|
|||||||
}
|
}
|
||||||
return PHONE_SMS_PROVIDER_HERO_SMS;
|
return PHONE_SMS_PROVIDER_HERO_SMS;
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizePhoneSmsProviderOrder(value = [], fallbackOrder = []) {
|
function normalizePhoneSmsProviderOrder(value = [], fallbackOrder = []) {
|
||||||
|
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
||||||
|
if (rootScope.PhoneSmsProviderRegistry?.normalizeProviderOrder) {
|
||||||
|
return rootScope.PhoneSmsProviderRegistry.normalizeProviderOrder(value, fallbackOrder);
|
||||||
|
}
|
||||||
const source = Array.isArray(value)
|
const source = Array.isArray(value)
|
||||||
? value
|
? value
|
||||||
: String(value || '')
|
: String(value || '')
|
||||||
.split(/[\r\n,,;;]+/)
|
.split(/[\r\n,]+/)
|
||||||
.map((entry) => String(entry || '').trim())
|
.map((entry) => String(entry || '').trim())
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
const normalized = [];
|
const normalized = [];
|
||||||
@@ -1373,7 +1377,6 @@ function normalizePhoneSmsProviderOrder(value = [], fallbackOrder = []) {
|
|||||||
|
|
||||||
return normalized.slice(0, DEFAULT_PHONE_SMS_PROVIDER_ORDER.length);
|
return normalized.slice(0, DEFAULT_PHONE_SMS_PROVIDER_ORDER.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeSignupMethod(value = '') {
|
function normalizeSignupMethod(value = '') {
|
||||||
return String(value || '').trim().toLowerCase() === 'phone'
|
return String(value || '').trim().toLowerCase() === 'phone'
|
||||||
? 'phone'
|
? 'phone'
|
||||||
@@ -2668,6 +2671,7 @@ function normalizePersistentSettingValue(key, value) {
|
|||||||
return typeof value === 'boolean' ? value : true;
|
return typeof value === 'boolean' ? value : true;
|
||||||
case 'step6CookieCleanupEnabled':
|
case 'step6CookieCleanupEnabled':
|
||||||
case 'phoneVerificationEnabled':
|
case 'phoneVerificationEnabled':
|
||||||
|
case 'phoneSmsReuseEnabled':
|
||||||
case 'freePhoneReuseEnabled':
|
case 'freePhoneReuseEnabled':
|
||||||
case 'freePhoneReuseAutoEnabled':
|
case 'freePhoneReuseAutoEnabled':
|
||||||
case 'plusModeEnabled':
|
case 'plusModeEnabled':
|
||||||
@@ -2842,6 +2846,13 @@ function buildPersistentSettingsPayload(input = {}, options = {}) {
|
|||||||
throw new Error('\u914d\u7f6e\u5185\u5bb9\u683c\u5f0f\u65e0\u6548\u3002');
|
throw new Error('\u914d\u7f6e\u5185\u5bb9\u683c\u5f0f\u65e0\u6548\u3002');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const persistedSettingDefaults = typeof PERSISTED_SETTING_DEFAULTS !== 'undefined' && PERSISTED_SETTING_DEFAULTS
|
||||||
|
? PERSISTED_SETTING_DEFAULTS
|
||||||
|
: {};
|
||||||
|
const persistedSettingKeys = Array.isArray(typeof PERSISTED_SETTING_KEYS !== 'undefined' ? PERSISTED_SETTING_KEYS : null)
|
||||||
|
? PERSISTED_SETTING_KEYS
|
||||||
|
: Object.keys(persistedSettingDefaults);
|
||||||
|
|
||||||
const normalizedInput = { ...input };
|
const normalizedInput = { ...input };
|
||||||
if (normalizedInput.autoStepDelaySeconds === undefined) {
|
if (normalizedInput.autoStepDelaySeconds === undefined) {
|
||||||
const legacyAutoStepDelaySeconds = resolveLegacyAutoStepDelaySeconds(normalizedInput);
|
const legacyAutoStepDelaySeconds = resolveLegacyAutoStepDelaySeconds(normalizedInput);
|
||||||
@@ -2860,15 +2871,29 @@ function buildPersistentSettingsPayload(input = {}, options = {}) {
|
|||||||
|
|
||||||
const payload = {};
|
const payload = {};
|
||||||
let matchedKeyCount = 0;
|
let matchedKeyCount = 0;
|
||||||
for (const key of PERSISTED_SETTING_KEYS) {
|
for (const key of persistedSettingKeys) {
|
||||||
if (normalizedInput[key] !== undefined) {
|
if (normalizedInput[key] !== undefined) {
|
||||||
payload[key] = normalizePersistentSettingValue(key, normalizedInput[key]);
|
payload[key] = normalizePersistentSettingValue(key, normalizedInput[key]);
|
||||||
matchedKeyCount += 1;
|
matchedKeyCount += 1;
|
||||||
} else if (fillDefaults) {
|
} else if (fillDefaults) {
|
||||||
payload[key] = normalizePersistentSettingValue(key, PERSISTED_SETTING_DEFAULTS[key]);
|
payload[key] = normalizePersistentSettingValue(key, persistedSettingDefaults[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasPhoneSmsReuseEnabled = Object.prototype.hasOwnProperty.call(normalizedInput, 'phoneSmsReuseEnabled');
|
||||||
|
const hasHeroSmsReuseEnabled = Object.prototype.hasOwnProperty.call(normalizedInput, 'heroSmsReuseEnabled');
|
||||||
|
const hasFiveSimReuseEnabled = Object.prototype.hasOwnProperty.call(normalizedInput, 'fiveSimReuseEnabled');
|
||||||
|
if (hasPhoneSmsReuseEnabled || hasHeroSmsReuseEnabled || hasFiveSimReuseEnabled) {
|
||||||
|
const reuseSource = hasPhoneSmsReuseEnabled
|
||||||
|
? normalizedInput.phoneSmsReuseEnabled
|
||||||
|
: (hasHeroSmsReuseEnabled
|
||||||
|
? normalizedInput.heroSmsReuseEnabled
|
||||||
|
: normalizedInput.fiveSimReuseEnabled);
|
||||||
|
const normalizedReuseEnabled = normalizePersistentSettingValue('phoneSmsReuseEnabled', reuseSource);
|
||||||
|
payload.phoneSmsReuseEnabled = normalizedReuseEnabled;
|
||||||
|
payload.heroSmsReuseEnabled = normalizedReuseEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
if (requireKnownKeys && matchedKeyCount === 0) {
|
if (requireKnownKeys && matchedKeyCount === 0) {
|
||||||
throw new Error('\u914d\u7f6e\u6587\u4ef6\u4e2d\u6ca1\u6709\u53ef\u8bc6\u522b\u7684\u914d\u7f6e\u5185\u5bb9\u3002');
|
throw new Error('\u914d\u7f6e\u6587\u4ef6\u4e2d\u6ca1\u6709\u53ef\u8bc6\u522b\u7684\u914d\u7f6e\u5185\u5bb9\u3002');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,6 +180,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizePhoneSmsProvider(value = '') {
|
function normalizePhoneSmsProvider(value = '') {
|
||||||
|
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
||||||
|
if (rootScope.PhoneSmsProviderRegistry?.normalizeProviderId) {
|
||||||
|
return rootScope.PhoneSmsProviderRegistry.normalizeProviderId(value);
|
||||||
|
}
|
||||||
const normalized = String(value || '').trim().toLowerCase();
|
const normalized = String(value || '').trim().toLowerCase();
|
||||||
if (normalized === PHONE_SMS_PROVIDER_5SIM) {
|
if (normalized === PHONE_SMS_PROVIDER_5SIM) {
|
||||||
return PHONE_SMS_PROVIDER_5SIM;
|
return PHONE_SMS_PROVIDER_5SIM;
|
||||||
@@ -189,7 +193,6 @@
|
|||||||
}
|
}
|
||||||
return PHONE_SMS_PROVIDER_HERO;
|
return PHONE_SMS_PROVIDER_HERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFiveSimProvider(state = {}) {
|
function isFiveSimProvider(state = {}) {
|
||||||
return normalizePhoneSmsProvider(state?.phoneSmsProvider || DEFAULT_PHONE_SMS_PROVIDER) === PHONE_SMS_PROVIDER_5SIM;
|
return normalizePhoneSmsProvider(state?.phoneSmsProvider || DEFAULT_PHONE_SMS_PROVIDER) === PHONE_SMS_PROVIDER_5SIM;
|
||||||
}
|
}
|
||||||
@@ -515,6 +518,13 @@
|
|||||||
return Boolean(value);
|
return Boolean(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizePhoneSmsReuseEnabled(state = {}) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(state, 'phoneSmsReuseEnabled')) {
|
||||||
|
return Boolean(state.phoneSmsReuseEnabled);
|
||||||
|
}
|
||||||
|
return normalizeHeroSmsReuseEnabled(state?.heroSmsReuseEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeFreePhoneReuseEnabled(value) {
|
function normalizeFreePhoneReuseEnabled(value) {
|
||||||
return Boolean(value);
|
return Boolean(value);
|
||||||
}
|
}
|
||||||
@@ -536,10 +546,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizePhoneSmsProviderOrder(value = [], fallbackOrder = []) {
|
function normalizePhoneSmsProviderOrder(value = [], fallbackOrder = []) {
|
||||||
|
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
||||||
|
if (rootScope.PhoneSmsProviderRegistry?.normalizeProviderOrder) {
|
||||||
|
return rootScope.PhoneSmsProviderRegistry.normalizeProviderOrder(value, fallbackOrder);
|
||||||
|
}
|
||||||
const source = Array.isArray(value)
|
const source = Array.isArray(value)
|
||||||
? value
|
? value
|
||||||
: String(value || '')
|
: String(value || '')
|
||||||
.split(/[\r\n,,;;|/]+/)
|
.split(/[\r\n,]+/)
|
||||||
.map((entry) => String(entry || '').trim())
|
.map((entry) => String(entry || '').trim())
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
const normalized = [];
|
const normalized = [];
|
||||||
@@ -573,7 +587,6 @@
|
|||||||
|
|
||||||
return fallbackNormalized.slice(0, 3);
|
return fallbackNormalized.slice(0, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolvePhoneProviderOrder(state = {}, preferredProvider = '') {
|
function resolvePhoneProviderOrder(state = {}, preferredProvider = '') {
|
||||||
const currentProvider = normalizePhoneSmsProvider(
|
const currentProvider = normalizePhoneSmsProvider(
|
||||||
preferredProvider || state?.phoneSmsProvider || DEFAULT_PHONE_SMS_PROVIDER
|
preferredProvider || state?.phoneSmsProvider || DEFAULT_PHONE_SMS_PROVIDER
|
||||||
@@ -856,10 +869,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isPhoneSmsReuseEnabled(state = {}) {
|
function isPhoneSmsReuseEnabled(state = {}) {
|
||||||
if (normalizePhoneSmsProvider(state?.phoneSmsProvider) === PHONE_SMS_PROVIDER_FIVE_SIM) {
|
return normalizePhoneSmsReuseEnabled(state);
|
||||||
return state?.fiveSimReuseEnabled !== false;
|
|
||||||
}
|
|
||||||
return normalizeHeroSmsReuseEnabled(state?.heroSmsReuseEnabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createResolvedFiveSimProvider() {
|
function createResolvedFiveSimProvider() {
|
||||||
@@ -2658,7 +2668,7 @@
|
|||||||
{
|
{
|
||||||
query: {
|
query: {
|
||||||
...(candidatePrice !== null && candidatePrice !== undefined ? { maxPrice: candidatePrice } : {}),
|
...(candidatePrice !== null && candidatePrice !== undefined ? { maxPrice: candidatePrice } : {}),
|
||||||
...(normalizeHeroSmsReuseEnabled(state.heroSmsReuseEnabled) ? { reuse: 1 } : {}),
|
...(normalizePhoneSmsReuseEnabled(state) ? { reuse: 1 } : {}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -4850,7 +4860,7 @@
|
|||||||
delete nextReusableActivation.phoneCodeReceived;
|
delete nextReusableActivation.phoneCodeReceived;
|
||||||
delete nextReusableActivation.phoneCodeReceivedAt;
|
delete nextReusableActivation.phoneCodeReceivedAt;
|
||||||
await upsertReusableActivationPool(nextReusableActivation, { state });
|
await upsertReusableActivationPool(nextReusableActivation, { state });
|
||||||
if (!normalizeHeroSmsReuseEnabled(state?.heroSmsReuseEnabled)) {
|
if (!normalizePhoneSmsReuseEnabled(state)) {
|
||||||
await clearReusableActivation();
|
await clearReusableActivation();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -574,22 +574,32 @@
|
|||||||
return /not\s+enough\s+(?:user\s+)?balance|not\s+enough\s+rating|unauthorized|invalid\s+token|banned|bad\s+(?:country|operator)|no\s+product|server\s+offline/i.test(text);
|
return /not\s+enough\s+(?:user\s+)?balance|not\s+enough\s+rating|unauthorized|invalid\s+token|banned|bad\s+(?:country|operator)|no\s+product|server\s+offline/i.test(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
function assertMaxPriceCompatibleWithOperator(state = {}) {
|
function assertMaxPriceCompatibleWithOperator(state = {}) {
|
||||||
const maxPrice = normalizeFiveSimMaxPrice(state.fiveSimMaxPrice);
|
const maxPrice = normalizeFiveSimMaxPrice(state.fiveSimMaxPrice);
|
||||||
const operator = normalizeFiveSimOperator(state.fiveSimOperator);
|
const operator = normalizeFiveSimOperator(state.fiveSimOperator);
|
||||||
if (maxPrice && operator !== DEFAULT_OPERATOR) {
|
if (maxPrice && operator !== DEFAULT_OPERATOR) {
|
||||||
throw new Error('5sim maxPrice only works when operator is "any"; clear the price limit or switch operator to any before buying a number.');
|
throw new Error('5sim maxPrice only works when operator is "any"; clear the price limit or switch operator to any before buying a number.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buyActivationWithPrice(state = {}, countryConfig, maxPrice, deps = {}) {
|
function normalizeReuseEnabled(state = {}) {
|
||||||
const config = resolveConfig(state, deps);
|
if (Object.prototype.hasOwnProperty.call(state, 'phoneSmsReuseEnabled')) {
|
||||||
const operator = normalizeFiveSimOperator(state.fiveSimOperator);
|
return state.phoneSmsReuseEnabled !== false;
|
||||||
|
}
|
||||||
|
if (Object.prototype.hasOwnProperty.call(state, 'heroSmsReuseEnabled')) {
|
||||||
|
return state.heroSmsReuseEnabled !== false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buyActivationWithPrice(state = {}, countryConfig, maxPrice, deps = {}) {
|
||||||
|
const config = resolveConfig(state, deps);
|
||||||
|
const operator = normalizeFiveSimOperator(state.fiveSimOperator);
|
||||||
const query = {};
|
const query = {};
|
||||||
if (maxPrice !== null && maxPrice !== undefined) {
|
if (maxPrice !== null && maxPrice !== undefined) {
|
||||||
query.maxPrice = maxPrice;
|
query.maxPrice = maxPrice;
|
||||||
}
|
}
|
||||||
if (state.fiveSimReuseEnabled !== false) {
|
if (normalizeReuseEnabled(state)) {
|
||||||
query.reuse = 1;
|
query.reuse = 1;
|
||||||
}
|
}
|
||||||
const payload = await fetchJson(
|
const payload = await fetchJson(
|
||||||
|
|||||||
+106
-10
@@ -1,41 +1,137 @@
|
|||||||
// phone-sms/providers/registry.js — 接码平台注册表
|
// phone-sms/providers/registry.js - phone SMS provider registry
|
||||||
(function attachPhoneSmsProviderRegistry(root, factory) {
|
(function attachPhoneSmsProviderRegistry(root, factory) {
|
||||||
root.PhoneSmsProviderRegistry = factory(root);
|
root.PhoneSmsProviderRegistry = factory(root);
|
||||||
})(typeof self !== 'undefined' ? self : globalThis, function createPhoneSmsProviderRegistry(root) {
|
})(typeof self !== 'undefined' ? self : globalThis, function createPhoneSmsProviderRegistry(root) {
|
||||||
const PROVIDER_HERO_SMS = 'hero-sms';
|
const PROVIDER_HERO_SMS = 'hero-sms';
|
||||||
const PROVIDER_FIVE_SIM = '5sim';
|
const PROVIDER_FIVE_SIM = '5sim';
|
||||||
|
const PROVIDER_NEXSMS = 'nexsms';
|
||||||
const DEFAULT_PROVIDER = PROVIDER_HERO_SMS;
|
const DEFAULT_PROVIDER = PROVIDER_HERO_SMS;
|
||||||
|
const DEFAULT_PROVIDER_ORDER = Object.freeze([
|
||||||
|
PROVIDER_HERO_SMS,
|
||||||
|
PROVIDER_FIVE_SIM,
|
||||||
|
PROVIDER_NEXSMS,
|
||||||
|
]);
|
||||||
|
const PROVIDER_DEFINITIONS = Object.freeze({
|
||||||
|
[PROVIDER_HERO_SMS]: Object.freeze({
|
||||||
|
id: PROVIDER_HERO_SMS,
|
||||||
|
label: 'HeroSMS',
|
||||||
|
moduleKey: 'PhoneSmsHeroSmsProvider',
|
||||||
|
}),
|
||||||
|
[PROVIDER_FIVE_SIM]: Object.freeze({
|
||||||
|
id: PROVIDER_FIVE_SIM,
|
||||||
|
label: '5sim',
|
||||||
|
moduleKey: 'PhoneSmsFiveSimProvider',
|
||||||
|
}),
|
||||||
|
[PROVIDER_NEXSMS]: Object.freeze({
|
||||||
|
id: PROVIDER_NEXSMS,
|
||||||
|
label: 'NexSMS',
|
||||||
|
moduleKey: 'PhoneSmsNexSmsProvider',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
function normalizeProviderId(value = '') {
|
function resolveProviderKey(value = '') {
|
||||||
const normalized = String(value || '').trim().toLowerCase();
|
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
||||||
return normalized === PROVIDER_FIVE_SIM ? PROVIDER_FIVE_SIM : PROVIDER_HERO_SMS;
|
return String(value.provider || value.id || value.value || '').trim().toLowerCase();
|
||||||
|
}
|
||||||
|
return String(value || '').trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function isKnownProviderId(providerId = '') {
|
||||||
|
return Boolean(PROVIDER_DEFINITIONS[providerId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeProviderId(value = '', fallback = DEFAULT_PROVIDER) {
|
||||||
|
const normalized = resolveProviderKey(value);
|
||||||
|
if (isKnownProviderId(normalized)) {
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
const fallbackNormalized = resolveProviderKey(fallback);
|
||||||
|
if (isKnownProviderId(fallbackNormalized)) {
|
||||||
|
return fallbackNormalized;
|
||||||
|
}
|
||||||
|
return DEFAULT_PROVIDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeProviderOrder(value = [], fallbackOrder = DEFAULT_PROVIDER_ORDER) {
|
||||||
|
const source = Array.isArray(value)
|
||||||
|
? value
|
||||||
|
: String(value || '')
|
||||||
|
.split(/[\r\n,,;;]+/)
|
||||||
|
.map((entry) => String(entry || '').trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
const normalized = [];
|
||||||
|
const seen = new Set();
|
||||||
|
|
||||||
|
const pushProvider = (entry) => {
|
||||||
|
const provider = normalizeProviderId(entry, DEFAULT_PROVIDER);
|
||||||
|
if (!provider || seen.has(provider)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seen.add(provider);
|
||||||
|
normalized.push(provider);
|
||||||
|
};
|
||||||
|
|
||||||
|
source.forEach((entry) => {
|
||||||
|
pushProvider(entry && typeof entry === 'object' && !Array.isArray(entry)
|
||||||
|
? (entry.provider || entry.id || entry.value || '')
|
||||||
|
: entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (normalized.length) {
|
||||||
|
return normalized.slice(0, DEFAULT_PROVIDER_ORDER.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fallback = Array.isArray(fallbackOrder) ? fallbackOrder : [];
|
||||||
|
fallback.forEach((entry) => {
|
||||||
|
pushProvider(entry && typeof entry === 'object' && !Array.isArray(entry)
|
||||||
|
? (entry.provider || entry.id || entry.value || '')
|
||||||
|
: entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
return normalized.slice(0, DEFAULT_PROVIDER_ORDER.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProviderIds() {
|
||||||
|
return DEFAULT_PROVIDER_ORDER.slice();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProviderDefinition(providerId = DEFAULT_PROVIDER) {
|
||||||
|
return PROVIDER_DEFINITIONS[normalizeProviderId(providerId)] || PROVIDER_DEFINITIONS[DEFAULT_PROVIDER];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProviderModule(providerId = DEFAULT_PROVIDER) {
|
function getProviderModule(providerId = DEFAULT_PROVIDER) {
|
||||||
const normalized = normalizeProviderId(providerId);
|
const definition = getProviderDefinition(providerId);
|
||||||
if (normalized === PROVIDER_FIVE_SIM) {
|
const moduleKey = definition?.moduleKey;
|
||||||
return root.PhoneSmsFiveSimProvider || null;
|
if (!moduleKey) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return root.PhoneSmsHeroSmsProvider || null;
|
return root?.[moduleKey] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createProvider(providerId = DEFAULT_PROVIDER, deps = {}) {
|
function createProvider(providerId = DEFAULT_PROVIDER, deps = {}) {
|
||||||
|
const definition = getProviderDefinition(providerId);
|
||||||
const module = getProviderModule(providerId);
|
const module = getProviderModule(providerId);
|
||||||
if (!module || typeof module.createProvider !== 'function') {
|
if (!module || typeof module.createProvider !== 'function') {
|
||||||
throw new Error(`Phone SMS provider is not loaded: ${normalizeProviderId(providerId)}`);
|
throw new Error(`Phone SMS provider module is not loaded: ${definition.id}`);
|
||||||
}
|
}
|
||||||
return module.createProvider(deps);
|
return module.createProvider(deps);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProviderLabel(providerId = DEFAULT_PROVIDER) {
|
function getProviderLabel(providerId = DEFAULT_PROVIDER) {
|
||||||
return normalizeProviderId(providerId) === PROVIDER_FIVE_SIM ? '5sim' : 'HeroSMS';
|
return getProviderDefinition(providerId)?.label || 'HeroSMS';
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
PROVIDER_HERO_SMS,
|
PROVIDER_HERO_SMS,
|
||||||
PROVIDER_FIVE_SIM,
|
PROVIDER_FIVE_SIM,
|
||||||
|
PROVIDER_NEXSMS,
|
||||||
DEFAULT_PROVIDER,
|
DEFAULT_PROVIDER,
|
||||||
|
DEFAULT_PROVIDER_ORDER,
|
||||||
|
PROVIDER_DEFINITIONS,
|
||||||
normalizeProviderId,
|
normalizeProviderId,
|
||||||
|
normalizeProviderOrder,
|
||||||
|
getProviderIds,
|
||||||
|
getProviderDefinition,
|
||||||
getProviderModule,
|
getProviderModule,
|
||||||
createProvider,
|
createProvider,
|
||||||
getProviderLabel,
|
getProviderLabel,
|
||||||
|
|||||||
+46
-22
@@ -3333,9 +3333,13 @@ function collectSettingsPayload() {
|
|||||||
const defaultPhoneCodePollMaxRounds = typeof DEFAULT_PHONE_CODE_POLL_MAX_ROUNDS !== 'undefined'
|
const defaultPhoneCodePollMaxRounds = typeof DEFAULT_PHONE_CODE_POLL_MAX_ROUNDS !== 'undefined'
|
||||||
? DEFAULT_PHONE_CODE_POLL_MAX_ROUNDS
|
? DEFAULT_PHONE_CODE_POLL_MAX_ROUNDS
|
||||||
: 12;
|
: 12;
|
||||||
const heroSmsReuseEnabledValue = typeof inputHeroSmsReuseEnabled !== 'undefined' && inputHeroSmsReuseEnabled
|
const phoneSmsReuseEnabledValue = typeof inputHeroSmsReuseEnabled !== 'undefined' && inputHeroSmsReuseEnabled
|
||||||
? normalizeHeroSmsReuseEnabledValue(inputHeroSmsReuseEnabled.checked)
|
? normalizeHeroSmsReuseEnabledValue(inputHeroSmsReuseEnabled.checked)
|
||||||
: defaultHeroSmsReuseEnabled;
|
: normalizeHeroSmsReuseEnabledValue(
|
||||||
|
latestState?.phoneSmsReuseEnabled,
|
||||||
|
latestState?.heroSmsReuseEnabled
|
||||||
|
);
|
||||||
|
const heroSmsReuseEnabledValue = phoneSmsReuseEnabledValue;
|
||||||
const freePhoneReuseEnabledValue = typeof inputFreePhoneReuseEnabled !== 'undefined' && inputFreePhoneReuseEnabled
|
const freePhoneReuseEnabledValue = typeof inputFreePhoneReuseEnabled !== 'undefined' && inputFreePhoneReuseEnabled
|
||||||
? Boolean(inputFreePhoneReuseEnabled.checked)
|
? Boolean(inputFreePhoneReuseEnabled.checked)
|
||||||
: Boolean(latestState?.freePhoneReuseEnabled);
|
: Boolean(latestState?.freePhoneReuseEnabled);
|
||||||
@@ -3782,6 +3786,7 @@ function collectSettingsPayload() {
|
|||||||
nexSmsApiKey: nexSmsApiKeyValue,
|
nexSmsApiKey: nexSmsApiKeyValue,
|
||||||
nexSmsCountryOrder: nexSmsCountryOrderValue,
|
nexSmsCountryOrder: nexSmsCountryOrderValue,
|
||||||
nexSmsServiceCode: nexSmsServiceCodeValue,
|
nexSmsServiceCode: nexSmsServiceCodeValue,
|
||||||
|
phoneSmsReuseEnabled: phoneSmsReuseEnabledValue,
|
||||||
heroSmsReuseEnabled: heroSmsReuseEnabledValue,
|
heroSmsReuseEnabled: heroSmsReuseEnabledValue,
|
||||||
freePhoneReuseEnabled: freePhoneReuseEnabledValue,
|
freePhoneReuseEnabled: freePhoneReuseEnabledValue,
|
||||||
freePhoneReuseAutoEnabled: freePhoneReuseAutoEnabledValue,
|
freePhoneReuseAutoEnabled: freePhoneReuseAutoEnabledValue,
|
||||||
@@ -3851,15 +3856,22 @@ function normalizeAccountRunHistoryHelperBaseUrlValue(value = '') {
|
|||||||
|
|
||||||
|
|
||||||
function normalizePhoneSmsProvider(value = '') {
|
function normalizePhoneSmsProvider(value = '') {
|
||||||
if (typeof window !== 'undefined' && window.PhoneSmsProviderRegistry?.normalizeProviderId) {
|
const rootScope = typeof window !== 'undefined' ? window : globalThis;
|
||||||
return window.PhoneSmsProviderRegistry.normalizeProviderId(value);
|
if (rootScope.PhoneSmsProviderRegistry?.normalizeProviderId) {
|
||||||
|
return rootScope.PhoneSmsProviderRegistry.normalizeProviderId(value);
|
||||||
}
|
}
|
||||||
|
const nexSmsProvider = typeof PHONE_SMS_PROVIDER_NEXSMS !== 'undefined'
|
||||||
|
? PHONE_SMS_PROVIDER_NEXSMS
|
||||||
|
: 'nexsms';
|
||||||
const normalized = String(value || '').trim().toLowerCase();
|
const normalized = String(value || '').trim().toLowerCase();
|
||||||
return normalized === PHONE_SMS_PROVIDER_FIVE_SIM
|
if (normalized === PHONE_SMS_PROVIDER_FIVE_SIM) {
|
||||||
? PHONE_SMS_PROVIDER_FIVE_SIM
|
return PHONE_SMS_PROVIDER_FIVE_SIM;
|
||||||
: PHONE_SMS_PROVIDER_HERO_SMS;
|
}
|
||||||
|
if (normalized === nexSmsProvider) {
|
||||||
|
return nexSmsProvider;
|
||||||
|
}
|
||||||
|
return PHONE_SMS_PROVIDER_HERO_SMS;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setPhoneSmsProviderSelectValue(provider) {
|
function setPhoneSmsProviderSelectValue(provider) {
|
||||||
const normalizedProvider = normalizePhoneSmsProvider(provider);
|
const normalizedProvider = normalizePhoneSmsProvider(provider);
|
||||||
if (selectPhoneSmsProvider) {
|
if (selectPhoneSmsProvider) {
|
||||||
@@ -4042,21 +4054,21 @@ function normalizeHeroSmsMaxPriceValue(value = '') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizePhoneSmsProviderValue(value = '') {
|
function normalizePhoneSmsProviderValue(value = '') {
|
||||||
const normalized = String(value || '').trim().toLowerCase();
|
const rootScope = typeof window !== 'undefined' ? window : globalThis;
|
||||||
if (normalized === PHONE_SMS_PROVIDER_FIVE_SIM) {
|
if (rootScope.PhoneSmsProviderRegistry?.normalizeProviderId) {
|
||||||
return PHONE_SMS_PROVIDER_FIVE_SIM;
|
return rootScope.PhoneSmsProviderRegistry.normalizeProviderId(value);
|
||||||
}
|
}
|
||||||
if (normalized === PHONE_SMS_PROVIDER_NEXSMS) {
|
return normalizePhoneSmsProvider(value);
|
||||||
return PHONE_SMS_PROVIDER_NEXSMS;
|
|
||||||
}
|
|
||||||
return PHONE_SMS_PROVIDER_HERO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizePhoneSmsProviderOrderValue(value = [], fallbackOrder = []) {
|
function normalizePhoneSmsProviderOrderValue(value = [], fallbackOrder = []) {
|
||||||
|
const rootScope = typeof window !== 'undefined' ? window : globalThis;
|
||||||
|
if (rootScope.PhoneSmsProviderRegistry?.normalizeProviderOrder) {
|
||||||
|
return rootScope.PhoneSmsProviderRegistry.normalizeProviderOrder(value, fallbackOrder);
|
||||||
|
}
|
||||||
const source = Array.isArray(value)
|
const source = Array.isArray(value)
|
||||||
? value
|
? value
|
||||||
: String(value || '')
|
: String(value || '')
|
||||||
.split(/[\r\n,,;;|/]+/)
|
.split(/[\r\n,]+/)
|
||||||
.map((entry) => String(entry || '').trim())
|
.map((entry) => String(entry || '').trim())
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
const normalized = [];
|
const normalized = [];
|
||||||
@@ -4089,7 +4101,6 @@ function normalizePhoneSmsProviderOrderValue(value = [], fallbackOrder = []) {
|
|||||||
});
|
});
|
||||||
return fallbackNormalized.slice(0, 3);
|
return fallbackNormalized.slice(0, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatPhoneSmsProviderOrderSummary(order = []) {
|
function formatPhoneSmsProviderOrderSummary(order = []) {
|
||||||
const normalized = normalizePhoneSmsProviderOrderValue(order, []);
|
const normalized = normalizePhoneSmsProviderOrderValue(order, []);
|
||||||
if (!normalized.length) {
|
if (!normalized.length) {
|
||||||
@@ -4593,8 +4604,11 @@ function normalizePhoneCodePollMaxRoundsValue(value, fallback = DEFAULT_PHONE_CO
|
|||||||
return Math.max(PHONE_CODE_POLL_MAX_ROUNDS_MIN, Math.min(PHONE_CODE_POLL_MAX_ROUNDS_MAX, parsed));
|
return Math.max(PHONE_CODE_POLL_MAX_ROUNDS_MIN, Math.min(PHONE_CODE_POLL_MAX_ROUNDS_MAX, parsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeHeroSmsReuseEnabledValue(value) {
|
function normalizeHeroSmsReuseEnabledValue(value, fallbackValue = undefined) {
|
||||||
if (value === undefined || value === null) {
|
if (value === undefined || value === null) {
|
||||||
|
if (fallbackValue !== undefined && fallbackValue !== null) {
|
||||||
|
return Boolean(fallbackValue);
|
||||||
|
}
|
||||||
return DEFAULT_HERO_SMS_REUSE_ENABLED;
|
return DEFAULT_HERO_SMS_REUSE_ENABLED;
|
||||||
}
|
}
|
||||||
return Boolean(value);
|
return Boolean(value);
|
||||||
@@ -8983,7 +8997,10 @@ function applySettingsState(state) {
|
|||||||
: String(state?.nexSmsServiceCode || defaultNexSmsServiceCode).trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '') || defaultNexSmsServiceCode;
|
: String(state?.nexSmsServiceCode || defaultNexSmsServiceCode).trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '') || defaultNexSmsServiceCode;
|
||||||
}
|
}
|
||||||
if (typeof inputHeroSmsReuseEnabled !== 'undefined' && inputHeroSmsReuseEnabled) {
|
if (typeof inputHeroSmsReuseEnabled !== 'undefined' && inputHeroSmsReuseEnabled) {
|
||||||
inputHeroSmsReuseEnabled.checked = normalizeHeroSmsReuseEnabledValue(state?.heroSmsReuseEnabled);
|
inputHeroSmsReuseEnabled.checked = normalizeHeroSmsReuseEnabledValue(
|
||||||
|
state?.phoneSmsReuseEnabled,
|
||||||
|
state?.heroSmsReuseEnabled
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (typeof inputFreePhoneReuseEnabled !== 'undefined' && inputFreePhoneReuseEnabled) {
|
if (typeof inputFreePhoneReuseEnabled !== 'undefined' && inputFreePhoneReuseEnabled) {
|
||||||
inputFreePhoneReuseEnabled.checked = Boolean(state?.freePhoneReuseEnabled);
|
inputFreePhoneReuseEnabled.checked = Boolean(state?.freePhoneReuseEnabled);
|
||||||
@@ -14582,8 +14599,15 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|||||||
if (message.payload.nexSmsServiceCode !== undefined && inputNexSmsServiceCode) {
|
if (message.payload.nexSmsServiceCode !== undefined && inputNexSmsServiceCode) {
|
||||||
inputNexSmsServiceCode.value = normalizeNexSmsServiceCodeValue(message.payload.nexSmsServiceCode);
|
inputNexSmsServiceCode.value = normalizeNexSmsServiceCodeValue(message.payload.nexSmsServiceCode);
|
||||||
}
|
}
|
||||||
if (message.payload.heroSmsReuseEnabled !== undefined && inputHeroSmsReuseEnabled) {
|
if (
|
||||||
inputHeroSmsReuseEnabled.checked = normalizeHeroSmsReuseEnabledValue(message.payload.heroSmsReuseEnabled);
|
(message.payload.phoneSmsReuseEnabled !== undefined
|
||||||
|
|| message.payload.heroSmsReuseEnabled !== undefined)
|
||||||
|
&& inputHeroSmsReuseEnabled
|
||||||
|
) {
|
||||||
|
inputHeroSmsReuseEnabled.checked = normalizeHeroSmsReuseEnabledValue(
|
||||||
|
message.payload.phoneSmsReuseEnabled,
|
||||||
|
message.payload.heroSmsReuseEnabled
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (message.payload.freePhoneReuseEnabled !== undefined && inputFreePhoneReuseEnabled) {
|
if (message.payload.freePhoneReuseEnabled !== undefined && inputFreePhoneReuseEnabled) {
|
||||||
inputFreePhoneReuseEnabled.checked = Boolean(message.payload.freePhoneReuseEnabled);
|
inputFreePhoneReuseEnabled.checked = Boolean(message.payload.freePhoneReuseEnabled);
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ test('background account history settings are normalized independently from hotm
|
|||||||
extractFunction('normalizeSub2ApiGroupNames'),
|
extractFunction('normalizeSub2ApiGroupNames'),
|
||||||
extractFunction('normalizeBoundedIntegerSetting'),
|
extractFunction('normalizeBoundedIntegerSetting'),
|
||||||
extractFunction('normalizeLocalHttpBaseUrl'),
|
extractFunction('normalizeLocalHttpBaseUrl'),
|
||||||
|
extractFunction('buildPersistentSettingsPayload'),
|
||||||
extractFunction('normalizePersistentSettingValue'),
|
extractFunction('normalizePersistentSettingValue'),
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
@@ -181,10 +182,16 @@ function normalizeCloudflareTempEmailReceiveMailbox(value) { return String(value
|
|||||||
function normalizeCloudflareTempEmailDomain(value) { return String(value || '').trim(); }
|
function normalizeCloudflareTempEmailDomain(value) { return String(value || '').trim(); }
|
||||||
function normalizeCloudflareTempEmailDomains(value) { return Array.isArray(value) ? value : []; }
|
function normalizeCloudflareTempEmailDomains(value) { return Array.isArray(value) ? value : []; }
|
||||||
function normalizeHotmailAccounts(value) { return Array.isArray(value) ? value : []; }
|
function normalizeHotmailAccounts(value) { return Array.isArray(value) ? value : []; }
|
||||||
|
function resolveLegacyAutoStepDelaySeconds(value) {
|
||||||
|
return value && Object.prototype.hasOwnProperty.call(value, 'autoStepDelaySeconds')
|
||||||
|
? value.autoStepDelaySeconds
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
${bundle}
|
${bundle}
|
||||||
return {
|
return {
|
||||||
normalizeAccountRunHistoryHelperBaseUrl,
|
normalizeAccountRunHistoryHelperBaseUrl,
|
||||||
normalizePersistentSettingValue,
|
normalizePersistentSettingValue,
|
||||||
|
buildPersistentSettingsPayload,
|
||||||
};
|
};
|
||||||
`)();
|
`)();
|
||||||
|
|
||||||
@@ -243,6 +250,8 @@ return {
|
|||||||
assert.equal(api.normalizePersistentSettingValue('phoneSmsProvider', 'NEXSMS'), 'nexsms');
|
assert.equal(api.normalizePersistentSettingValue('phoneSmsProvider', 'NEXSMS'), 'nexsms');
|
||||||
assert.equal(api.normalizePersistentSettingValue('phoneSmsProvider', 'unknown'), 'hero-sms');
|
assert.equal(api.normalizePersistentSettingValue('phoneSmsProvider', 'unknown'), 'hero-sms');
|
||||||
assert.deepStrictEqual(api.normalizePersistentSettingValue('phoneSmsProviderOrder', ['nexsms', '5sim', 'nexsms']), ['nexsms', '5sim']);
|
assert.deepStrictEqual(api.normalizePersistentSettingValue('phoneSmsProviderOrder', ['nexsms', '5sim', 'nexsms']), ['nexsms', '5sim']);
|
||||||
|
assert.equal(api.normalizePersistentSettingValue('phoneSmsReuseEnabled', false), false);
|
||||||
|
assert.equal(api.normalizePersistentSettingValue('phoneSmsReuseEnabled', true), true);
|
||||||
assert.equal(api.normalizePersistentSettingValue('fiveSimApiKey', ' demo-five '), ' demo-five ');
|
assert.equal(api.normalizePersistentSettingValue('fiveSimApiKey', ' demo-five '), ' demo-five ');
|
||||||
assert.equal(api.normalizePersistentSettingValue('fiveSimProduct', ' OpenAI! '), 'openai');
|
assert.equal(api.normalizePersistentSettingValue('fiveSimProduct', ' OpenAI! '), 'openai');
|
||||||
assert.equal(api.normalizePersistentSettingValue('fiveSimCountryId', ' England! '), 'england');
|
assert.equal(api.normalizePersistentSettingValue('fiveSimCountryId', ' England! '), 'england');
|
||||||
@@ -335,4 +344,26 @@ return {
|
|||||||
countryLabel: '',
|
countryLabel: '',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
const legacyReusePayload = api.buildPersistentSettingsPayload({
|
||||||
|
heroSmsReuseEnabled: false,
|
||||||
|
});
|
||||||
|
assert.equal(legacyReusePayload.phoneSmsReuseEnabled, false);
|
||||||
|
assert.equal(legacyReusePayload.heroSmsReuseEnabled, false);
|
||||||
|
const fiveSimReusePayload = api.buildPersistentSettingsPayload({
|
||||||
|
fiveSimReuseEnabled: false,
|
||||||
|
});
|
||||||
|
assert.equal(fiveSimReusePayload.phoneSmsReuseEnabled, false);
|
||||||
|
assert.equal(fiveSimReusePayload.heroSmsReuseEnabled, false);
|
||||||
|
const conflictingReusePayload = api.buildPersistentSettingsPayload({
|
||||||
|
heroSmsReuseEnabled: true,
|
||||||
|
fiveSimReuseEnabled: false,
|
||||||
|
});
|
||||||
|
assert.equal(conflictingReusePayload.phoneSmsReuseEnabled, true);
|
||||||
|
assert.equal(conflictingReusePayload.heroSmsReuseEnabled, true);
|
||||||
|
const newReusePayload = api.buildPersistentSettingsPayload({
|
||||||
|
phoneSmsReuseEnabled: false,
|
||||||
|
heroSmsReuseEnabled: true,
|
||||||
|
});
|
||||||
|
assert.equal(newReusePayload.phoneSmsReuseEnabled, false);
|
||||||
|
assert.equal(newReusePayload.heroSmsReuseEnabled, false);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ test('background defaults enable free phone reuse switches', () => {
|
|||||||
|
|
||||||
assert.match(defaultsBlock, /freePhoneReuseEnabled:\s*true/);
|
assert.match(defaultsBlock, /freePhoneReuseEnabled:\s*true/);
|
||||||
assert.match(defaultsBlock, /freePhoneReuseAutoEnabled:\s*true/);
|
assert.match(defaultsBlock, /freePhoneReuseAutoEnabled:\s*true/);
|
||||||
|
assert.match(defaultsBlock, /phoneSmsReuseEnabled:\s*DEFAULT_HERO_SMS_REUSE_ENABLED/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('background free reusable phone setter does not depend on module-scoped phone flow constants', () => {
|
test('background free reusable phone setter does not depend on module-scoped phone flow constants', () => {
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
|
||||||
|
const source = fs.readFileSync('phone-sms/providers/registry.js', 'utf8');
|
||||||
|
|
||||||
|
function loadRegistry(root = {}) {
|
||||||
|
return new Function('self', `${source}; return self.PhoneSmsProviderRegistry;`)(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
test('phone sms provider registry normalizes ids, order and labels consistently', () => {
|
||||||
|
const registry = loadRegistry({
|
||||||
|
PhoneSmsHeroSmsProvider: {
|
||||||
|
createProvider: (deps = {}) => ({ provider: 'hero-sms', deps }),
|
||||||
|
},
|
||||||
|
PhoneSmsFiveSimProvider: {
|
||||||
|
createProvider: (deps = {}) => ({ provider: '5sim', deps }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepStrictEqual(registry.getProviderIds(), ['hero-sms', '5sim', 'nexsms']);
|
||||||
|
assert.equal(registry.normalizeProviderId(' NEXSMS '), 'nexsms');
|
||||||
|
assert.equal(registry.normalizeProviderId('unknown-provider'), 'hero-sms');
|
||||||
|
assert.equal(registry.getProviderLabel('nexsms'), 'NexSMS');
|
||||||
|
assert.equal(registry.getProviderDefinition('nexsms').moduleKey, 'PhoneSmsNexSmsProvider');
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
registry.normalizeProviderOrder([
|
||||||
|
{ provider: 'nexsms' },
|
||||||
|
{ id: '5sim' },
|
||||||
|
{ value: 'hero-sms' },
|
||||||
|
'NEXSMS',
|
||||||
|
]),
|
||||||
|
['nexsms', '5sim', 'hero-sms']
|
||||||
|
);
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
registry.normalizeProviderOrder([], ['nexsms', '5sim', 'nexsms']),
|
||||||
|
['nexsms', '5sim']
|
||||||
|
);
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
registry.createProvider('5sim', { foo: 1 }),
|
||||||
|
{ provider: '5sim', deps: { foo: 1 } }
|
||||||
|
);
|
||||||
|
assert.throws(() => registry.createProvider('nexsms'), /Phone SMS provider module is not loaded: nexsms/);
|
||||||
|
});
|
||||||
@@ -1948,9 +1948,181 @@ test('phone verification helper acquires a number from 5sim with fallback countr
|
|||||||
assert.equal(requests[3].pathname, '/v1/user/buy/activation/england/any/openai');
|
assert.equal(requests[3].pathname, '/v1/user/buy/activation/england/any/openai');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('phone verification helper rejects 5sim maxPrice with custom operator before buying', async () => {
|
test('phone verification helper prefers phoneSmsReuseEnabled over legacy heroSmsReuseEnabled for 5sim acquisition', async () => {
|
||||||
const requests = [];
|
const requests = [];
|
||||||
const helpers = api.createPhoneVerificationHelpers({
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
|
addLog: async () => {},
|
||||||
|
ensureStep8SignupPageReady: async () => {},
|
||||||
|
fetchImpl: async (url, options = {}) => {
|
||||||
|
const parsedUrl = new URL(url);
|
||||||
|
requests.push({
|
||||||
|
pathname: parsedUrl.pathname,
|
||||||
|
search: parsedUrl.searchParams,
|
||||||
|
headers: options?.headers || {},
|
||||||
|
});
|
||||||
|
if (parsedUrl.pathname === '/v1/guest/prices') {
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
text: async () => JSON.stringify({
|
||||||
|
openai: {
|
||||||
|
thailand: {
|
||||||
|
any: {
|
||||||
|
cost: 0.08,
|
||||||
|
count: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (parsedUrl.pathname === '/v1/user/buy/activation/thailand/any/openai') {
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
text: async () => JSON.stringify({
|
||||||
|
id: 1234567,
|
||||||
|
phone: '+66880000000',
|
||||||
|
country: 'thailand',
|
||||||
|
country_name: 'Thailand',
|
||||||
|
product: 'openai',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw new Error(`Unexpected 5sim request: ${parsedUrl.pathname}`);
|
||||||
|
},
|
||||||
|
getState: async () => ({
|
||||||
|
phoneSmsProvider: '5sim',
|
||||||
|
fiveSimApiKey: 'five-token',
|
||||||
|
fiveSimCountryOrder: ['thailand'],
|
||||||
|
fiveSimOperator: 'any',
|
||||||
|
fiveSimProduct: 'openai',
|
||||||
|
phoneSmsReuseEnabled: false,
|
||||||
|
heroSmsReuseEnabled: true,
|
||||||
|
heroSmsActivationRetryRounds: 1,
|
||||||
|
}),
|
||||||
|
sendToContentScriptResilient: async () => ({}),
|
||||||
|
setState: async () => {},
|
||||||
|
sleepWithStop: async () => {},
|
||||||
|
throwIfStopped: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const activation = await helpers.requestPhoneActivation({
|
||||||
|
phoneSmsProvider: '5sim',
|
||||||
|
fiveSimApiKey: 'five-token',
|
||||||
|
fiveSimCountryOrder: ['thailand'],
|
||||||
|
fiveSimOperator: 'any',
|
||||||
|
fiveSimProduct: 'openai',
|
||||||
|
phoneSmsReuseEnabled: false,
|
||||||
|
heroSmsReuseEnabled: true,
|
||||||
|
heroSmsActivationRetryRounds: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepStrictEqual(activation, {
|
||||||
|
activationId: '1234567',
|
||||||
|
phoneNumber: '+66880000000',
|
||||||
|
provider: '5sim',
|
||||||
|
serviceCode: 'openai',
|
||||||
|
countryId: 'thailand',
|
||||||
|
countryCode: 'thailand',
|
||||||
|
countryLabel: 'Thailand',
|
||||||
|
successfulUses: 0,
|
||||||
|
maxUses: 3,
|
||||||
|
});
|
||||||
|
assert.equal(requests[0].pathname, '/v1/guest/prices');
|
||||||
|
assert.equal(requests[1].pathname, '/v1/user/buy/activation/thailand/any/openai');
|
||||||
|
assert.equal(requests[1].search.get('reuse'), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('phone verification helper treats fiveSimReuseEnabled as legacy-only when phoneSmsReuseEnabled is absent', async () => {
|
||||||
|
const requests = [];
|
||||||
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
|
addLog: async () => {},
|
||||||
|
ensureStep8SignupPageReady: async () => {},
|
||||||
|
fetchImpl: async (url, options = {}) => {
|
||||||
|
const parsedUrl = new URL(url);
|
||||||
|
requests.push({
|
||||||
|
pathname: parsedUrl.pathname,
|
||||||
|
search: parsedUrl.searchParams,
|
||||||
|
headers: options?.headers || {},
|
||||||
|
});
|
||||||
|
if (parsedUrl.pathname === '/v1/guest/prices') {
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
text: async () => JSON.stringify({
|
||||||
|
openai: {
|
||||||
|
thailand: {
|
||||||
|
any: {
|
||||||
|
cost: 0.08,
|
||||||
|
count: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (parsedUrl.pathname === '/v1/user/buy/activation/thailand/any/openai') {
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
text: async () => JSON.stringify({
|
||||||
|
id: 1234568,
|
||||||
|
phone: '+66880000001',
|
||||||
|
country: 'thailand',
|
||||||
|
country_name: 'Thailand',
|
||||||
|
product: 'openai',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw new Error(`Unexpected 5sim request: ${parsedUrl.pathname}`);
|
||||||
|
},
|
||||||
|
getState: async () => ({
|
||||||
|
phoneSmsProvider: '5sim',
|
||||||
|
fiveSimApiKey: 'five-token',
|
||||||
|
fiveSimCountryOrder: ['thailand'],
|
||||||
|
fiveSimOperator: 'any',
|
||||||
|
fiveSimProduct: 'openai',
|
||||||
|
heroSmsReuseEnabled: true,
|
||||||
|
fiveSimReuseEnabled: false,
|
||||||
|
heroSmsActivationRetryRounds: 1,
|
||||||
|
}),
|
||||||
|
sendToContentScriptResilient: async () => ({}),
|
||||||
|
setState: async () => {},
|
||||||
|
sleepWithStop: async () => {},
|
||||||
|
throwIfStopped: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const activation = await helpers.requestPhoneActivation({
|
||||||
|
phoneSmsProvider: '5sim',
|
||||||
|
fiveSimApiKey: 'five-token',
|
||||||
|
fiveSimCountryOrder: ['thailand'],
|
||||||
|
fiveSimOperator: 'any',
|
||||||
|
fiveSimProduct: 'openai',
|
||||||
|
heroSmsReuseEnabled: true,
|
||||||
|
fiveSimReuseEnabled: false,
|
||||||
|
heroSmsActivationRetryRounds: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepStrictEqual(activation, {
|
||||||
|
activationId: '1234568',
|
||||||
|
phoneNumber: '+66880000001',
|
||||||
|
provider: '5sim',
|
||||||
|
serviceCode: 'openai',
|
||||||
|
countryId: 'thailand',
|
||||||
|
countryCode: 'thailand',
|
||||||
|
countryLabel: 'Thailand',
|
||||||
|
successfulUses: 0,
|
||||||
|
maxUses: 3,
|
||||||
|
});
|
||||||
|
assert.equal(requests[0].pathname, '/v1/guest/prices');
|
||||||
|
assert.equal(requests[1].pathname, '/v1/user/buy/activation/thailand/any/openai');
|
||||||
|
assert.equal(requests[1].search.get('reuse'), '1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('phone verification helper rejects 5sim maxPrice with custom operator before buying', async () => {
|
||||||
|
const requests = [];
|
||||||
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
addLog: async () => {},
|
addLog: async () => {},
|
||||||
ensureStep8SignupPageReady: async () => {},
|
ensureStep8SignupPageReady: async () => {},
|
||||||
fetchImpl: async (url) => {
|
fetchImpl: async (url) => {
|
||||||
|
|||||||
@@ -943,6 +943,7 @@ return { collectSettingsPayload };
|
|||||||
assert.equal(payload.nexSmsApiKey, 'nex-key');
|
assert.equal(payload.nexSmsApiKey, 'nex-key');
|
||||||
assert.deepStrictEqual(payload.nexSmsCountryOrder, [1]);
|
assert.deepStrictEqual(payload.nexSmsCountryOrder, [1]);
|
||||||
assert.equal(payload.nexSmsServiceCode, 'ot');
|
assert.equal(payload.nexSmsServiceCode, 'ot');
|
||||||
|
assert.equal(payload.phoneSmsReuseEnabled, true);
|
||||||
assert.equal(payload.heroSmsReuseEnabled, true);
|
assert.equal(payload.heroSmsReuseEnabled, true);
|
||||||
assert.equal(payload.freePhoneReuseEnabled, true);
|
assert.equal(payload.freePhoneReuseEnabled, true);
|
||||||
assert.equal(payload.freePhoneReuseAutoEnabled, true);
|
assert.equal(payload.freePhoneReuseAutoEnabled, true);
|
||||||
|
|||||||
Reference in New Issue
Block a user