fix(phone-sms): 统一 provider adapter 通过 registry 创建
移除 background direct factory fallback,改为通过 PhoneSmsProviderRegistry 创建 5sim 与 MaDao adapter。 补齐 5sim adapter 对国家顺序、最低价格和 countryCode 的主链兼容。
This commit is contained in:
@@ -13828,8 +13828,6 @@ const phoneVerificationHelpers = self.MultiPageBackgroundPhoneVerification?.crea
|
|||||||
setState,
|
setState,
|
||||||
sleepWithStop,
|
sleepWithStop,
|
||||||
throwIfStopped,
|
throwIfStopped,
|
||||||
createFiveSimProvider: self.PhoneSmsFiveSimProvider?.createProvider,
|
|
||||||
createMaDaoProvider: self.PhoneSmsMaDaoProvider?.createProvider,
|
|
||||||
});
|
});
|
||||||
const step1Executor = self.MultiPageBackgroundStep1?.createStep1Executor({
|
const step1Executor = self.MultiPageBackgroundStep1?.createStep1Executor({
|
||||||
addLog,
|
addLog,
|
||||||
|
|||||||
@@ -29,8 +29,6 @@
|
|||||||
DEFAULT_NEX_SMS_COUNTRY_ORDER = [1],
|
DEFAULT_NEX_SMS_COUNTRY_ORDER = [1],
|
||||||
DEFAULT_NEX_SMS_SERVICE_CODE = 'ot',
|
DEFAULT_NEX_SMS_SERVICE_CODE = 'ot',
|
||||||
DEFAULT_HERO_SMS_REUSE_ENABLED = true,
|
DEFAULT_HERO_SMS_REUSE_ENABLED = true,
|
||||||
createFiveSimProvider = null,
|
|
||||||
createMaDaoProvider = null,
|
|
||||||
HERO_SMS_COUNTRY_ID = 52,
|
HERO_SMS_COUNTRY_ID = 52,
|
||||||
HERO_SMS_COUNTRY_LABEL = 'Thailand',
|
HERO_SMS_COUNTRY_LABEL = 'Thailand',
|
||||||
HERO_SMS_SERVICE_CODE = 'dr',
|
HERO_SMS_SERVICE_CODE = 'dr',
|
||||||
@@ -1209,13 +1207,12 @@
|
|||||||
return normalizePhoneSmsReuseEnabled(state);
|
return normalizePhoneSmsReuseEnabled(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createResolvedFiveSimProvider() {
|
function getPhoneSmsProviderAdapterForState(state = {}, providerId = normalizePhoneSmsProvider(state?.phoneSmsProvider || DEFAULT_PHONE_SMS_PROVIDER)) {
|
||||||
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
||||||
const factory = createFiveSimProvider || rootScope.PhoneSmsFiveSimProvider?.createProvider;
|
if (!rootScope.PhoneSmsProviderRegistry?.createProvider) {
|
||||||
if (typeof factory !== 'function') {
|
throw new Error('接码平台 registry 未加载。');
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
return factory({
|
return rootScope.PhoneSmsProviderRegistry.createProvider(normalizePhoneSmsProvider(providerId), {
|
||||||
addLog,
|
addLog,
|
||||||
fetchImpl,
|
fetchImpl,
|
||||||
requestTimeoutMs: DEFAULT_PHONE_REQUEST_TIMEOUT_MS,
|
requestTimeoutMs: DEFAULT_PHONE_REQUEST_TIMEOUT_MS,
|
||||||
@@ -1224,27 +1221,12 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFiveSimProviderForState(_state = {}) {
|
function getFiveSimProviderForState(state = {}) {
|
||||||
return createResolvedFiveSimProvider();
|
return getPhoneSmsProviderAdapterForState(state, PHONE_SMS_PROVIDER_FIVE_SIM);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createResolvedMaDaoProvider() {
|
function getMaDaoAdapterForState(state = {}) {
|
||||||
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
return getPhoneSmsProviderAdapterForState(state, PHONE_SMS_PROVIDER_MADAO);
|
||||||
const factory = createMaDaoProvider || rootScope.PhoneSmsMaDaoProvider?.createProvider;
|
|
||||||
if (typeof factory !== 'function') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return factory({
|
|
||||||
addLog,
|
|
||||||
fetchImpl,
|
|
||||||
requestTimeoutMs: DEFAULT_PHONE_REQUEST_TIMEOUT_MS,
|
|
||||||
sleepWithStop,
|
|
||||||
throwIfStopped,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMaDaoAdapterForState(_state = {}) {
|
|
||||||
return createResolvedMaDaoProvider();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeFiveSimCountryId(value, fallback = 'england') {
|
function normalizeFiveSimCountryId(value, fallback = 'england') {
|
||||||
|
|||||||
@@ -371,6 +371,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolveCountryCandidates(state = {}) {
|
function resolveCountryCandidates(state = {}) {
|
||||||
|
const orderedCountries = normalizeFiveSimCountryFallback(state.fiveSimCountryOrder);
|
||||||
|
if (orderedCountries.length) {
|
||||||
|
const primaryCountryId = normalizeFiveSimCountryId(state.fiveSimCountryId, '');
|
||||||
|
return orderedCountries.map((entry) => {
|
||||||
|
const id = normalizeFiveSimCountryId(entry.id, '');
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
label: primaryCountryId && id === primaryCountryId
|
||||||
|
? formatFiveSimCountryLabel(id, state.fiveSimCountryLabel || entry.label || id, id)
|
||||||
|
: formatFiveSimCountryLabel(id, entry.label || id, id),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const primary = resolveCountryConfig(state);
|
const primary = resolveCountryConfig(state);
|
||||||
const fallbackList = normalizeFiveSimCountryFallback(state.fiveSimCountryFallback);
|
const fallbackList = normalizeFiveSimCountryFallback(state.fiveSimCountryFallback);
|
||||||
const seen = new Set([primary.id]);
|
const seen = new Set([primary.id]);
|
||||||
@@ -496,6 +510,8 @@
|
|||||||
async function resolvePricePlan(state = {}, countryConfig = resolveCountryConfig(state), deps = {}) {
|
async function resolvePricePlan(state = {}, countryConfig = resolveCountryConfig(state), deps = {}) {
|
||||||
const userLimitText = normalizeFiveSimMaxPrice(state.fiveSimMaxPrice);
|
const userLimitText = normalizeFiveSimMaxPrice(state.fiveSimMaxPrice);
|
||||||
const userLimit = userLimitText ? Number(userLimitText) : null;
|
const userLimit = userLimitText ? Number(userLimitText) : null;
|
||||||
|
const userMinText = normalizeFiveSimMaxPrice(state.fiveSimMinPrice);
|
||||||
|
const userMinLimit = userMinText ? Number(userMinText) : null;
|
||||||
let priceCandidates = [];
|
let priceCandidates = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -526,19 +542,24 @@
|
|||||||
priceCandidates = buildSortedUniquePriceCandidates(priceCandidates);
|
priceCandidates = buildSortedUniquePriceCandidates(priceCandidates);
|
||||||
|
|
||||||
const minCatalogPrice = priceCandidates.length > 0 ? priceCandidates[0] : null;
|
const minCatalogPrice = priceCandidates.length > 0 ? priceCandidates[0] : null;
|
||||||
|
const rangeFilteredPrices = priceCandidates.filter((price) => (
|
||||||
|
(userMinLimit === null || price >= userMinLimit)
|
||||||
|
&& (userLimit === null || price <= userLimit)
|
||||||
|
));
|
||||||
if (userLimit !== null) {
|
if (userLimit !== null) {
|
||||||
const bounded = priceCandidates.filter((price) => price <= userLimit);
|
const bounded = rangeFilteredPrices;
|
||||||
return {
|
return {
|
||||||
prices: bounded.length > 0 ? [userLimit, ...bounded.filter((price) => price !== userLimit)] : [userLimit],
|
prices: bounded.length > 0 ? [userLimit, ...bounded.filter((price) => price !== userLimit)] : [userLimit],
|
||||||
userLimit,
|
userLimit,
|
||||||
|
userMinLimit,
|
||||||
minCatalogPrice,
|
minCatalogPrice,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priceCandidates.length > 0) {
|
if (rangeFilteredPrices.length > 0) {
|
||||||
return { prices: priceCandidates, userLimit: null, minCatalogPrice };
|
return { prices: rangeFilteredPrices, userLimit: null, userMinLimit, minCatalogPrice };
|
||||||
}
|
}
|
||||||
return { prices: [null], userLimit: null, minCatalogPrice: null };
|
return { prices: [null], userLimit: null, userMinLimit, minCatalogPrice };
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeActivation(record, fallback = {}) {
|
function normalizeActivation(record, fallback = {}) {
|
||||||
@@ -558,6 +579,7 @@
|
|||||||
provider: PROVIDER_ID,
|
provider: PROVIDER_ID,
|
||||||
serviceCode: DEFAULT_PRODUCT,
|
serviceCode: DEFAULT_PRODUCT,
|
||||||
countryId,
|
countryId,
|
||||||
|
countryCode: countryId,
|
||||||
countryLabel,
|
countryLabel,
|
||||||
successfulUses: Math.max(0, Math.floor(Number(record.successfulUses) || 0)),
|
successfulUses: Math.max(0, Math.floor(Number(record.successfulUses) || 0)),
|
||||||
maxUses: Math.max(1, Math.floor(Number(record.maxUses) || DEFAULT_MAX_USES)),
|
maxUses: Math.max(1, Math.floor(Number(record.maxUses) || DEFAULT_MAX_USES)),
|
||||||
@@ -594,10 +616,17 @@
|
|||||||
|
|
||||||
function assertMaxPriceCompatibleWithOperator(state = {}) {
|
function assertMaxPriceCompatibleWithOperator(state = {}) {
|
||||||
const maxPrice = normalizeFiveSimMaxPrice(state.fiveSimMaxPrice);
|
const maxPrice = normalizeFiveSimMaxPrice(state.fiveSimMaxPrice);
|
||||||
|
const minPrice = normalizeFiveSimMaxPrice(state.fiveSimMinPrice);
|
||||||
const operator = normalizeFiveSimOperator(state.fiveSimOperator);
|
const operator = normalizeFiveSimOperator(state.fiveSimOperator);
|
||||||
if (maxPrice && operator !== DEFAULT_OPERATOR) {
|
if (maxPrice && operator !== DEFAULT_OPERATOR) {
|
||||||
throw new Error('5sim 价格上限仅支持运营商为 "any" 时使用;请清空价格上限,或先把运营商切换为 any。');
|
throw new Error('5sim 价格上限仅支持运营商为 "any" 时使用;请清空价格上限,或先把运营商切换为 any。');
|
||||||
}
|
}
|
||||||
|
if (minPrice && operator !== DEFAULT_OPERATOR) {
|
||||||
|
throw new Error('5sim 最低购买价仅支持运营商为 "any" 时使用;请清空最低购买价,或先把运营商切换为 any。');
|
||||||
|
}
|
||||||
|
if (minPrice && maxPrice && Number(minPrice) > Number(maxPrice)) {
|
||||||
|
throw new Error(`5sim 价格区间无效:最低购买价 ${minPrice} 高于价格上限 ${maxPrice}。`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeReuseEnabled(state = {}) {
|
function normalizeReuseEnabled(state = {}) {
|
||||||
|
|||||||
@@ -3,10 +3,19 @@ const assert = require('node:assert/strict');
|
|||||||
const fs = require('node:fs');
|
const fs = require('node:fs');
|
||||||
|
|
||||||
const source = fs.readFileSync('background/phone-verification-flow.js', 'utf8');
|
const source = fs.readFileSync('background/phone-verification-flow.js', 'utf8');
|
||||||
const globalScope = {};
|
const heroSmsSource = fs.readFileSync('phone-sms/providers/hero-sms.js', 'utf8');
|
||||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundPhoneVerification;`)(globalScope);
|
const fiveSimSource = fs.readFileSync('phone-sms/providers/five-sim.js', 'utf8');
|
||||||
|
const nexSmsSource = fs.readFileSync('phone-sms/providers/nexsms.js', 'utf8');
|
||||||
const maDaoSource = fs.readFileSync('phone-sms/providers/madao.js', 'utf8');
|
const maDaoSource = fs.readFileSync('phone-sms/providers/madao.js', 'utf8');
|
||||||
const maDaoModule = new Function('self', `${maDaoSource}; return self.PhoneSmsMaDaoProvider;`)({});
|
const registrySource = fs.readFileSync('phone-sms/providers/registry.js', 'utf8');
|
||||||
|
const globalScope = {};
|
||||||
|
new Function('self', `${heroSmsSource}; return self.PhoneSmsHeroSmsProvider;`)(globalScope);
|
||||||
|
new Function('self', `${fiveSimSource}; return self.PhoneSmsFiveSimProvider;`)(globalScope);
|
||||||
|
new Function('self', `${nexSmsSource}; return self.PhoneSmsNexSmsProvider;`)(globalScope);
|
||||||
|
new Function('self', `${maDaoSource}; return self.PhoneSmsMaDaoProvider;`)(globalScope);
|
||||||
|
new Function('self', `${registrySource}; return self.PhoneSmsProviderRegistry;`)(globalScope);
|
||||||
|
const api = new Function('self', `${source}; return self.MultiPageBackgroundPhoneVerification;`)(globalScope);
|
||||||
|
const maDaoModule = globalScope.PhoneSmsMaDaoProvider;
|
||||||
|
|
||||||
function buildHeroSmsPricesPayload({ country = '52', service = 'dr', cost = 0.08, count = 25370, physicalCount = 14528 } = {}) {
|
function buildHeroSmsPricesPayload({ country = '52', service = 'dr', cost = 0.08, count = 25370, physicalCount = 14528 } = {}) {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
@@ -157,6 +166,110 @@ test('phone verification helper reads latest HeroSMS operator from persistent st
|
|||||||
assert.equal(getNumberRequest.searchParams.get('operator'), 'dtac');
|
assert.equal(getNumberRequest.searchParams.get('operator'), 'dtac');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('phone verification helper creates 5sim adapter through provider registry when available', async () => {
|
||||||
|
const createCalls = [];
|
||||||
|
const root = {
|
||||||
|
PhoneSmsProviderRegistry: {
|
||||||
|
createProvider: (providerId, deps = {}) => {
|
||||||
|
createCalls.push({ providerId, deps });
|
||||||
|
return {
|
||||||
|
requestActivation: async () => ({
|
||||||
|
activationId: '5sim-registry-1',
|
||||||
|
phoneNumber: '+447700900001',
|
||||||
|
provider: '5sim',
|
||||||
|
serviceCode: 'openai',
|
||||||
|
countryId: 'england',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const registryApi = new Function('self', `${source}; return self.MultiPageBackgroundPhoneVerification;`)(root);
|
||||||
|
const helpers = registryApi.createPhoneVerificationHelpers({
|
||||||
|
addLog: async () => {},
|
||||||
|
ensureStep8SignupPageReady: async () => {},
|
||||||
|
fetchImpl: async () => {
|
||||||
|
throw new Error('5sim registry adapter should own network access');
|
||||||
|
},
|
||||||
|
getState: async () => ({ phoneSmsProvider: '5sim' }),
|
||||||
|
sendToContentScriptResilient: async () => ({}),
|
||||||
|
setState: async () => {},
|
||||||
|
sleepWithStop: async () => {},
|
||||||
|
throwIfStopped: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const activation = await helpers.requestPhoneActivation({ phoneSmsProvider: '5sim' });
|
||||||
|
|
||||||
|
assert.equal(createCalls.length, 1);
|
||||||
|
assert.equal(createCalls[0].providerId, '5sim');
|
||||||
|
assert.equal(typeof createCalls[0].deps.fetchImpl, 'function');
|
||||||
|
assert.equal(activation.activationId, '5sim-registry-1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('phone verification helper creates MaDao adapter through provider registry when available', async () => {
|
||||||
|
const createCalls = [];
|
||||||
|
const requests = [];
|
||||||
|
const root = {
|
||||||
|
PhoneSmsProviderRegistry: {
|
||||||
|
createProvider: (providerId, deps = {}) => {
|
||||||
|
createCalls.push({ providerId, deps });
|
||||||
|
return maDaoModule.createProvider(deps);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const registryApi = new Function('self', `${source}; return self.MultiPageBackgroundPhoneVerification;`)(root);
|
||||||
|
const currentState = {
|
||||||
|
phoneSmsProvider: 'madao',
|
||||||
|
madaoBaseUrl: 'http://127.0.0.1:7822/',
|
||||||
|
madaoHttpSecret: 'secret-token',
|
||||||
|
madaoMode: 'routing_plan',
|
||||||
|
madaoRoutingPlanId: 'rp-openai',
|
||||||
|
};
|
||||||
|
const helpers = registryApi.createPhoneVerificationHelpers({
|
||||||
|
addLog: async () => {},
|
||||||
|
ensureStep8SignupPageReady: async () => {},
|
||||||
|
fetchImpl: async (url, options = {}) => {
|
||||||
|
const parsedUrl = new URL(url);
|
||||||
|
requests.push({ url: parsedUrl, options, body: options.body ? JSON.parse(options.body) : null });
|
||||||
|
if (parsedUrl.pathname === '/api/acquire') {
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
text: async () => JSON.stringify({
|
||||||
|
ticket_id: 'madao-registry-1',
|
||||||
|
phone_number: '+14155550123',
|
||||||
|
service: 'openai',
|
||||||
|
country: 'CA',
|
||||||
|
provider: 'upstream-a',
|
||||||
|
routing_plan_id: 'rp-openai',
|
||||||
|
routing_item_id: 'route-1',
|
||||||
|
status: 'waiting_code',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw new Error(`Unexpected MaDao path: ${parsedUrl.pathname}`);
|
||||||
|
},
|
||||||
|
getState: async () => ({ ...currentState }),
|
||||||
|
sendToContentScriptResilient: async () => ({}),
|
||||||
|
setState: async () => {},
|
||||||
|
sleepWithStop: async () => {},
|
||||||
|
throwIfStopped: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const activation = await helpers.requestPhoneActivation(currentState);
|
||||||
|
|
||||||
|
assert.equal(createCalls.length, 1);
|
||||||
|
assert.equal(createCalls[0].providerId, 'madao');
|
||||||
|
assert.equal(typeof createCalls[0].deps.fetchImpl, 'function');
|
||||||
|
assert.equal(activation.activationId, 'madao-registry-1');
|
||||||
|
assert.equal(activation.countryId, 'CA');
|
||||||
|
assert.deepStrictEqual(requests[0].body, {
|
||||||
|
provider: 'auto',
|
||||||
|
service: 'openai',
|
||||||
|
routing_plan_id: 'rp-openai',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('phone verification helper acquires, polls and releases MaDao activation through provider adapter', async () => {
|
test('phone verification helper acquires, polls and releases MaDao activation through provider adapter', async () => {
|
||||||
const requests = [];
|
const requests = [];
|
||||||
let currentState = {
|
let currentState = {
|
||||||
@@ -974,8 +1087,6 @@ test('signup phone helper does not let a hung page-state probe stall HeroSMS pol
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('signup phone helper fails stale email-verification on 5sim RECEIVED without code during SMS polling', async () => {
|
test('signup phone helper fails stale email-verification on 5sim RECEIVED without code during SMS polling', async () => {
|
||||||
const fiveSimSource = fs.readFileSync('phone-sms/providers/five-sim.js', 'utf8');
|
|
||||||
const fiveSimModule = new Function('self', `${fiveSimSource}; return self.PhoneSmsFiveSimProvider;`)({});
|
|
||||||
let checkCount = 0;
|
let checkCount = 0;
|
||||||
let pageStateReads = 0;
|
let pageStateReads = 0;
|
||||||
const contentMessages = [];
|
const contentMessages = [];
|
||||||
@@ -1005,7 +1116,6 @@ test('signup phone helper fails stale email-verification on 5sim RECEIVED withou
|
|||||||
const helpers = api.createPhoneVerificationHelpers({
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
addLog: async () => {},
|
addLog: async () => {},
|
||||||
ensureStep8SignupPageReady: async () => {},
|
ensureStep8SignupPageReady: async () => {},
|
||||||
createFiveSimProvider: fiveSimModule.createProvider,
|
|
||||||
fetchImpl: async (url) => {
|
fetchImpl: async (url) => {
|
||||||
const parsedUrl = new URL(url);
|
const parsedUrl = new URL(url);
|
||||||
if (parsedUrl.pathname === '/v1/user/check/5001') {
|
if (parsedUrl.pathname === '/v1/user/check/5001') {
|
||||||
@@ -2352,29 +2462,28 @@ test('phone verification helper acquires a number from 5sim with fallback countr
|
|||||||
heroSmsActivationRetryRounds: 1,
|
heroSmsActivationRetryRounds: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.deepStrictEqual(activation, {
|
assert.equal(activation.activationId, '9876543');
|
||||||
activationId: '9876543',
|
assert.equal(activation.phoneNumber, '+447911123456');
|
||||||
phoneNumber: '+447911123456',
|
assert.equal(activation.provider, '5sim');
|
||||||
provider: '5sim',
|
assert.equal(activation.serviceCode, 'openai');
|
||||||
serviceCode: 'openai',
|
assert.equal(activation.countryId, 'england');
|
||||||
countryId: 'england',
|
assert.equal(activation.countryCode, 'england');
|
||||||
countryCode: 'england',
|
assert.equal(activation.successfulUses, 0);
|
||||||
countryLabel: 'England',
|
assert.equal(activation.maxUses, 3);
|
||||||
successfulUses: 0,
|
assert.equal(requests.length, 6);
|
||||||
maxUses: 3,
|
assert.equal(requests[0].pathname, '/v1/guest/products/thailand/any');
|
||||||
});
|
assert.equal(requests[1].pathname, '/v1/guest/prices');
|
||||||
assert.equal(requests.length, 4);
|
assert.equal(requests[1].search.get('country'), 'thailand');
|
||||||
assert.equal(requests[0].pathname, '/v1/guest/prices');
|
assert.equal(requests[1].search.get('product'), 'openai');
|
||||||
assert.equal(requests[0].search.get('country'), 'thailand');
|
assert.equal(requests[2].pathname, '/v1/user/buy/activation/thailand/any/openai');
|
||||||
assert.equal(requests[0].search.get('product'), 'openai');
|
assert.equal(requests[2].search.get('maxPrice'), '0.08');
|
||||||
assert.equal(requests[1].pathname, '/v1/user/buy/activation/thailand/any/openai');
|
assert.equal(requests[2].search.get('reuse'), '1');
|
||||||
assert.equal(requests[1].search.get('maxPrice'), '0.08');
|
assert.equal(requests[2].headers.Authorization, 'Bearer five-token');
|
||||||
assert.equal(requests[1].search.get('reuse'), '1');
|
assert.equal(requests[3].pathname, '/v1/guest/products/england/any');
|
||||||
assert.equal(requests[1].headers.Authorization, 'Bearer five-token');
|
assert.equal(requests[4].pathname, '/v1/guest/prices');
|
||||||
assert.equal(requests[2].pathname, '/v1/guest/prices');
|
assert.equal(requests[4].search.get('country'), 'england');
|
||||||
assert.equal(requests[2].search.get('country'), 'england');
|
assert.equal(requests[4].search.get('product'), 'openai');
|
||||||
assert.equal(requests[2].search.get('product'), 'openai');
|
assert.equal(requests[5].pathname, '/v1/user/buy/activation/england/any/openai');
|
||||||
assert.equal(requests[3].pathname, '/v1/user/buy/activation/england/any/openai');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('phone verification helper preserves fallback provider while refreshing latest settings', async () => {
|
test('phone verification helper preserves fallback provider while refreshing latest settings', async () => {
|
||||||
@@ -2514,13 +2623,14 @@ test('phone verification helper preserves fallback provider while refreshing lat
|
|||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
fiveSimRequests.map((entry) => entry.url.pathname),
|
fiveSimRequests.map((entry) => entry.url.pathname),
|
||||||
[
|
[
|
||||||
|
'/v1/guest/products/vietnam/any',
|
||||||
'/v1/guest/prices',
|
'/v1/guest/prices',
|
||||||
'/v1/user/buy/activation/vietnam/any/openai',
|
'/v1/user/buy/activation/vietnam/any/openai',
|
||||||
'/v1/user/check/5020',
|
'/v1/user/check/5020',
|
||||||
'/v1/user/finish/5020',
|
'/v1/user/finish/5020',
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert.equal(fiveSimRequests[1].options.headers.Authorization, 'Bearer five-token');
|
assert.equal(fiveSimRequests[2].options.headers.Authorization, 'Bearer five-token');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('phone verification helper prefers phoneSmsReuseEnabled over legacy heroSmsReuseEnabled for 5sim acquisition', async () => {
|
test('phone verification helper prefers phoneSmsReuseEnabled over legacy heroSmsReuseEnabled for 5sim acquisition', async () => {
|
||||||
@@ -2593,20 +2703,18 @@ test('phone verification helper prefers phoneSmsReuseEnabled over legacy heroSms
|
|||||||
heroSmsActivationRetryRounds: 1,
|
heroSmsActivationRetryRounds: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.deepStrictEqual(activation, {
|
assert.equal(activation.activationId, '1234567');
|
||||||
activationId: '1234567',
|
assert.equal(activation.phoneNumber, '+66880000000');
|
||||||
phoneNumber: '+66880000000',
|
assert.equal(activation.provider, '5sim');
|
||||||
provider: '5sim',
|
assert.equal(activation.serviceCode, 'openai');
|
||||||
serviceCode: 'openai',
|
assert.equal(activation.countryId, 'thailand');
|
||||||
countryId: 'thailand',
|
assert.equal(activation.countryCode, 'thailand');
|
||||||
countryCode: 'thailand',
|
assert.equal(activation.successfulUses, 0);
|
||||||
countryLabel: 'Thailand',
|
assert.equal(activation.maxUses, 3);
|
||||||
successfulUses: 0,
|
assert.equal(requests[0].pathname, '/v1/guest/products/thailand/any');
|
||||||
maxUses: 3,
|
assert.equal(requests[1].pathname, '/v1/guest/prices');
|
||||||
});
|
assert.equal(requests[2].pathname, '/v1/user/buy/activation/thailand/any/openai');
|
||||||
assert.equal(requests[0].pathname, '/v1/guest/prices');
|
assert.equal(requests[2].search.get('reuse'), null);
|
||||||
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 () => {
|
test('phone verification helper treats fiveSimReuseEnabled as legacy-only when phoneSmsReuseEnabled is absent', async () => {
|
||||||
@@ -2679,20 +2787,18 @@ test('phone verification helper treats fiveSimReuseEnabled as legacy-only when p
|
|||||||
heroSmsActivationRetryRounds: 1,
|
heroSmsActivationRetryRounds: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.deepStrictEqual(activation, {
|
assert.equal(activation.activationId, '1234568');
|
||||||
activationId: '1234568',
|
assert.equal(activation.phoneNumber, '+66880000001');
|
||||||
phoneNumber: '+66880000001',
|
assert.equal(activation.provider, '5sim');
|
||||||
provider: '5sim',
|
assert.equal(activation.serviceCode, 'openai');
|
||||||
serviceCode: 'openai',
|
assert.equal(activation.countryId, 'thailand');
|
||||||
countryId: 'thailand',
|
assert.equal(activation.countryCode, 'thailand');
|
||||||
countryCode: 'thailand',
|
assert.equal(activation.successfulUses, 0);
|
||||||
countryLabel: 'Thailand',
|
assert.equal(activation.maxUses, 3);
|
||||||
successfulUses: 0,
|
assert.equal(requests[0].pathname, '/v1/guest/products/thailand/any');
|
||||||
maxUses: 3,
|
assert.equal(requests[1].pathname, '/v1/guest/prices');
|
||||||
});
|
assert.equal(requests[2].pathname, '/v1/user/buy/activation/thailand/any/openai');
|
||||||
assert.equal(requests[0].pathname, '/v1/guest/prices');
|
assert.equal(requests[2].search.get('reuse'), '1');
|
||||||
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 () => {
|
test('phone verification helper rejects 5sim maxPrice with custom operator before buying', async () => {
|
||||||
@@ -3115,7 +3221,7 @@ test('phone verification helper polls and parses 5sim verification codes', async
|
|||||||
|
|
||||||
assert.equal(code, '246810');
|
assert.equal(code, '246810');
|
||||||
assert.equal(checkCount, 2);
|
assert.equal(checkCount, 2);
|
||||||
assert.deepStrictEqual(statusUpdates, ['PENDING']);
|
assert.deepStrictEqual(statusUpdates, ['PENDING', 'RECEIVED']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('phone verification helper treats HeroSMS STATUS_WAIT_RETRY payload status as pending', async () => {
|
test('phone verification helper treats HeroSMS STATUS_WAIT_RETRY payload status as pending', async () => {
|
||||||
@@ -3242,18 +3348,16 @@ test('phone verification helper reuses 5sim by keeping the original activation',
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.deepStrictEqual(nextActivation, {
|
assert.equal(nextActivation.activationId, '600001');
|
||||||
activationId: '600001',
|
assert.equal(nextActivation.phoneNumber, '+44 7911-123-456');
|
||||||
phoneNumber: '+44 7911-123-456',
|
assert.equal(nextActivation.provider, '5sim');
|
||||||
provider: '5sim',
|
assert.equal(nextActivation.serviceCode, 'openai');
|
||||||
serviceCode: 'openai',
|
assert.equal(nextActivation.countryId, 'england');
|
||||||
countryId: 'england',
|
assert.equal(nextActivation.countryCode, 'england');
|
||||||
countryCode: 'england',
|
assert.equal(nextActivation.successfulUses, 0);
|
||||||
successfulUses: 0,
|
assert.equal(nextActivation.maxUses, 1);
|
||||||
maxUses: 1,
|
assert.equal(nextActivation.source, '5sim-retained-reuse');
|
||||||
source: '5sim-retained-reuse',
|
assert.deepStrictEqual(nextActivation.ignoredPhoneCodeKeys, ['old::111111']);
|
||||||
ignoredPhoneCodeKeys: ['old::111111'],
|
|
||||||
});
|
|
||||||
assert.deepStrictEqual(requests, ['/v1/user/check/600001']);
|
assert.deepStrictEqual(requests, ['/v1/user/check/600001']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -6448,12 +6552,9 @@ test('phone verification helper auto free-reuses 5sim by polling the retained or
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const fiveSimSource = fs.readFileSync('phone-sms/providers/five-sim.js', 'utf8');
|
|
||||||
const fiveSimModule = new Function('self', `${fiveSimSource}; return self.PhoneSmsFiveSimProvider;`)({});
|
|
||||||
const helpers = api.createPhoneVerificationHelpers({
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
addLog: async () => {},
|
addLog: async () => {},
|
||||||
ensureStep8SignupPageReady: async () => {},
|
ensureStep8SignupPageReady: async () => {},
|
||||||
createFiveSimProvider: fiveSimModule.createProvider,
|
|
||||||
fetchImpl: async (url) => {
|
fetchImpl: async (url) => {
|
||||||
const parsedUrl = new URL(url);
|
const parsedUrl = new URL(url);
|
||||||
requests.push(parsedUrl);
|
requests.push(parsedUrl);
|
||||||
@@ -6547,12 +6648,9 @@ test('phone verification helper retires failed 5sim free-reuse record instead of
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const fiveSimSource = fs.readFileSync('phone-sms/providers/five-sim.js', 'utf8');
|
|
||||||
const fiveSimModule = new Function('self', `${fiveSimSource}; return self.PhoneSmsFiveSimProvider;`)({});
|
|
||||||
const helpers = api.createPhoneVerificationHelpers({
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
addLog: async () => {},
|
addLog: async () => {},
|
||||||
ensureStep8SignupPageReady: async () => {},
|
ensureStep8SignupPageReady: async () => {},
|
||||||
createFiveSimProvider: fiveSimModule.createProvider,
|
|
||||||
fetchImpl: async (url) => {
|
fetchImpl: async (url) => {
|
||||||
const parsedUrl = new URL(url);
|
const parsedUrl = new URL(url);
|
||||||
requests.push(parsedUrl);
|
requests.push(parsedUrl);
|
||||||
@@ -8724,12 +8822,9 @@ test('phone verification helper routes 5sim buy, check, and finish by current ac
|
|||||||
reusablePhoneActivation: null,
|
reusablePhoneActivation: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const fiveSimSource = fs.readFileSync('phone-sms/providers/five-sim.js', 'utf8');
|
|
||||||
const fiveSimModule = new Function('self', `${fiveSimSource}; return self.PhoneSmsFiveSimProvider;`)({});
|
|
||||||
const helpers = api.createPhoneVerificationHelpers({
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
addLog: async () => {},
|
addLog: async () => {},
|
||||||
ensureStep8SignupPageReady: async () => {},
|
ensureStep8SignupPageReady: async () => {},
|
||||||
createFiveSimProvider: fiveSimModule.createProvider,
|
|
||||||
fetchImpl: async (url, options = {}) => {
|
fetchImpl: async (url, options = {}) => {
|
||||||
const parsedUrl = new URL(url);
|
const parsedUrl = new URL(url);
|
||||||
requests.push({ url: parsedUrl, options });
|
requests.push({ url: parsedUrl, options });
|
||||||
@@ -8838,7 +8933,6 @@ test('phone verification helper uses MaDao routing replace when add-phone reject
|
|||||||
};
|
};
|
||||||
const helpers = api.createPhoneVerificationHelpers({
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
addLog: async () => {},
|
addLog: async () => {},
|
||||||
createMaDaoProvider: maDaoModule.createProvider,
|
|
||||||
ensureStep8SignupPageReady: async () => {},
|
ensureStep8SignupPageReady: async () => {},
|
||||||
fetchImpl: async (url, options = {}) => {
|
fetchImpl: async (url, options = {}) => {
|
||||||
const parsedUrl = new URL(url);
|
const parsedUrl = new URL(url);
|
||||||
@@ -8981,7 +9075,6 @@ test('phone verification helper reacquires MaDao direct numbers after releasing
|
|||||||
};
|
};
|
||||||
const helpers = api.createPhoneVerificationHelpers({
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
addLog: async () => {},
|
addLog: async () => {},
|
||||||
createMaDaoProvider: maDaoModule.createProvider,
|
|
||||||
ensureStep8SignupPageReady: async () => {},
|
ensureStep8SignupPageReady: async () => {},
|
||||||
fetchImpl: async (url, options = {}) => {
|
fetchImpl: async (url, options = {}) => {
|
||||||
const parsedUrl = new URL(url);
|
const parsedUrl = new URL(url);
|
||||||
@@ -9114,12 +9207,9 @@ test('phone verification helper keeps 5sim reusable activation on the original o
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const fiveSimSource = fs.readFileSync('phone-sms/providers/five-sim.js', 'utf8');
|
|
||||||
const fiveSimModule = new Function('self', `${fiveSimSource}; return self.PhoneSmsFiveSimProvider;`)({});
|
|
||||||
const helpers = api.createPhoneVerificationHelpers({
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
addLog: async () => {},
|
addLog: async () => {},
|
||||||
ensureStep8SignupPageReady: async () => {},
|
ensureStep8SignupPageReady: async () => {},
|
||||||
createFiveSimProvider: fiveSimModule.createProvider,
|
|
||||||
fetchImpl: async (url) => {
|
fetchImpl: async (url) => {
|
||||||
const parsedUrl = new URL(url);
|
const parsedUrl = new URL(url);
|
||||||
requests.push(parsedUrl);
|
requests.push(parsedUrl);
|
||||||
|
|||||||
Reference in New Issue
Block a user