fix: resolve HeroSMS Plus dev sync conflicts
This commit is contained in:
+132
-144
@@ -3,19 +3,15 @@
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundContributionOAuthModule() {
|
||||
const API_BASE_URL = 'https://apikey.qzz.io/oauth/api';
|
||||
const ACTIVE_STATUSES = new Set(['started', 'waiting', 'processing']);
|
||||
const FINAL_STATUSES = new Set(['auto_approved', 'auto_rejected', 'expired', 'error']);
|
||||
const FINAL_STATUSES = new Set(['auto_approved', 'auto_rejected', 'manual_review_required', 'expired', 'error']);
|
||||
const CALLBACK_FINAL_STATUSES = new Set(['submitted']);
|
||||
const CALLBACK_WAITING_STATUSES = new Set(['idle', 'waiting', 'captured', 'failed', 'submitting']);
|
||||
const CONTRIBUTION_SOURCE_CPA = 'cpa';
|
||||
const CONTRIBUTION_SOURCE_SUB2API = 'sub2api';
|
||||
const CONTRIBUTION_SUB2API_DEFAULT_GROUP_NAME = 'codex号池';
|
||||
const CONTRIBUTION_SUB2API_PLUS_GROUP_NAME = 'openai-plus';
|
||||
|
||||
const RUNTIME_DEFAULTS = {
|
||||
contributionMode: false,
|
||||
contributionModeExpected: false,
|
||||
contributionSource: CONTRIBUTION_SOURCE_SUB2API,
|
||||
contributionTargetGroupName: CONTRIBUTION_SUB2API_DEFAULT_GROUP_NAME,
|
||||
contributionSource: 'sub2api',
|
||||
contributionTargetGroupName: 'codex号池',
|
||||
contributionNickname: '',
|
||||
contributionQq: '',
|
||||
contributionSessionId: '',
|
||||
@@ -44,7 +40,8 @@
|
||||
} = deps;
|
||||
|
||||
let listenersBound = false;
|
||||
const inFlightCapturedCallbackTasks = new Map();
|
||||
const pendingCallbackSubmissions = new Map();
|
||||
const pendingCapturedCallbacks = new Map();
|
||||
|
||||
function normalizeString(value = '') {
|
||||
return String(value || '').trim();
|
||||
@@ -71,6 +68,9 @@
|
||||
case 'auto_rejected':
|
||||
case 'rejected':
|
||||
return 'auto_rejected';
|
||||
case 'manual_review_required':
|
||||
case 'manual_review':
|
||||
return 'manual_review_required';
|
||||
case 'expired':
|
||||
case 'timeout':
|
||||
return 'expired';
|
||||
@@ -111,63 +111,6 @@
|
||||
return FINAL_STATUSES.has(normalizeContributionStatus(status));
|
||||
}
|
||||
|
||||
function runCapturedCallbackOnce(callbackUrl, executor) {
|
||||
const normalizedUrl = normalizeString(callbackUrl);
|
||||
if (!normalizedUrl) {
|
||||
return Promise.resolve().then(executor);
|
||||
}
|
||||
|
||||
const existingTask = inFlightCapturedCallbackTasks.get(normalizedUrl);
|
||||
if (existingTask) {
|
||||
return existingTask;
|
||||
}
|
||||
|
||||
let task = null;
|
||||
task = Promise.resolve()
|
||||
.then(executor)
|
||||
.finally(() => {
|
||||
if (inFlightCapturedCallbackTasks.get(normalizedUrl) === task) {
|
||||
inFlightCapturedCallbackTasks.delete(normalizedUrl);
|
||||
}
|
||||
});
|
||||
inFlightCapturedCallbackTasks.set(normalizedUrl, task);
|
||||
return task;
|
||||
}
|
||||
|
||||
function normalizeContributionSource(value = '') {
|
||||
const normalized = normalizeString(value).toLowerCase();
|
||||
return normalized === CONTRIBUTION_SOURCE_SUB2API
|
||||
? CONTRIBUTION_SOURCE_SUB2API
|
||||
: CONTRIBUTION_SOURCE_CPA;
|
||||
}
|
||||
|
||||
function resolveContributionRouting(state = {}) {
|
||||
const currentStatus = normalizeContributionStatus(state.contributionStatus);
|
||||
const currentSource = normalizeContributionSource(state.contributionSource);
|
||||
const hasActiveSession = Boolean(
|
||||
normalizeString(state.contributionSessionId)
|
||||
&& currentStatus
|
||||
&& !FINAL_STATUSES.has(currentStatus)
|
||||
);
|
||||
|
||||
if (hasActiveSession) {
|
||||
return {
|
||||
source: currentSource,
|
||||
targetGroupName: currentSource === CONTRIBUTION_SOURCE_SUB2API
|
||||
? (normalizeString(state.contributionTargetGroupName) || CONTRIBUTION_SUB2API_DEFAULT_GROUP_NAME)
|
||||
: '',
|
||||
};
|
||||
}
|
||||
|
||||
const source = CONTRIBUTION_SOURCE_SUB2API;
|
||||
return {
|
||||
source,
|
||||
targetGroupName: Boolean(state.plusModeEnabled)
|
||||
? CONTRIBUTION_SUB2API_PLUS_GROUP_NAME
|
||||
: (normalizeString(state.contributionTargetGroupName) || CONTRIBUTION_SUB2API_DEFAULT_GROUP_NAME),
|
||||
};
|
||||
}
|
||||
|
||||
function getStatusLabel(status = '') {
|
||||
switch (normalizeContributionStatus(status)) {
|
||||
case 'started':
|
||||
@@ -175,11 +118,13 @@
|
||||
case 'waiting':
|
||||
return '等待提交回调';
|
||||
case 'processing':
|
||||
return '已提交回调,等待服务端确认';
|
||||
return '已提交回调,等待 CPA 确认';
|
||||
case 'auto_approved':
|
||||
return '贡献成功,服务端已确认';
|
||||
return '贡献成功,CPA 已确认';
|
||||
case 'auto_rejected':
|
||||
return '贡献未通过确认';
|
||||
case 'manual_review_required':
|
||||
return '已提交,等待人工处理';
|
||||
case 'expired':
|
||||
return '贡献会话已超时';
|
||||
case 'error':
|
||||
@@ -315,6 +260,41 @@
|
||||
return qq;
|
||||
}
|
||||
|
||||
function isPlusModeState(state = {}) {
|
||||
return Boolean(state?.plusModeEnabled);
|
||||
}
|
||||
|
||||
function normalizeContributionModeSource(value = '') {
|
||||
const normalized = normalizeString(value).toLowerCase();
|
||||
return normalized === 'sub2api' ? 'sub2api' : 'cpa';
|
||||
}
|
||||
|
||||
function resolveContributionModeRoutingState(state = {}) {
|
||||
const currentStatus = normalizeString(state?.contributionStatus).toLowerCase();
|
||||
const currentSource = normalizeContributionModeSource(state?.contributionSource);
|
||||
const hasActiveSession = Boolean(
|
||||
normalizeString(state?.contributionSessionId)
|
||||
&& currentStatus
|
||||
&& !FINAL_STATUSES.has(currentStatus)
|
||||
);
|
||||
|
||||
if (hasActiveSession) {
|
||||
return {
|
||||
source: currentSource,
|
||||
targetGroupName: currentSource === 'sub2api'
|
||||
? (normalizeString(state?.contributionTargetGroupName) || 'codex号池')
|
||||
: '',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
source: 'sub2api',
|
||||
targetGroupName: isPlusModeState(state)
|
||||
? 'openai-plus'
|
||||
: (normalizeString(state?.contributionTargetGroupName) || 'codex号池'),
|
||||
};
|
||||
}
|
||||
|
||||
function buildStatusMessage(status, payload = {}) {
|
||||
const label = getStatusLabel(status);
|
||||
const details = [
|
||||
@@ -494,68 +474,87 @@
|
||||
return currentState;
|
||||
}
|
||||
|
||||
await applyRuntimeUpdates({
|
||||
contributionCallbackUrl: normalizedUrl,
|
||||
contributionCallbackStatus: 'submitting',
|
||||
contributionCallbackMessage: buildCallbackMessage('submitting'),
|
||||
});
|
||||
|
||||
try {
|
||||
const payload = await fetchContributionJson('/submit-callback', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
session_id: sessionId,
|
||||
callback_url: normalizedUrl,
|
||||
},
|
||||
});
|
||||
|
||||
const nextStatus = 'submitted';
|
||||
await applyRuntimeUpdates({
|
||||
contributionCallbackUrl: normalizedUrl,
|
||||
contributionCallbackStatus: nextStatus,
|
||||
contributionCallbackMessage: buildCallbackMessage(nextStatus, payload),
|
||||
});
|
||||
|
||||
if (typeof closeLocalhostCallbackTabs === 'function') {
|
||||
await closeLocalhostCallbackTabs(normalizedUrl).catch(() => {});
|
||||
}
|
||||
|
||||
return await pollContributionStatus({ reason: options.reason || 'submit_callback' });
|
||||
} catch (error) {
|
||||
await applyRuntimeUpdates({
|
||||
contributionCallbackUrl: normalizedUrl,
|
||||
contributionCallbackStatus: 'failed',
|
||||
contributionCallbackMessage: `回调提交失败:${error.message}`,
|
||||
});
|
||||
|
||||
if (typeof addLog === 'function') {
|
||||
await addLog(`贡献模式:回调提交失败:${error.message}`, 'warn');
|
||||
}
|
||||
|
||||
throw error;
|
||||
const dedupeKey = `${sessionId}::${normalizedUrl}`;
|
||||
if (pendingCallbackSubmissions.has(dedupeKey)) {
|
||||
return pendingCallbackSubmissions.get(dedupeKey);
|
||||
}
|
||||
|
||||
const task = (async () => {
|
||||
await applyRuntimeUpdates({
|
||||
contributionCallbackUrl: normalizedUrl,
|
||||
contributionCallbackStatus: 'submitting',
|
||||
contributionCallbackMessage: buildCallbackMessage('submitting'),
|
||||
});
|
||||
|
||||
try {
|
||||
const payload = await fetchContributionJson('/submit-callback', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
session_id: sessionId,
|
||||
callback_url: normalizedUrl,
|
||||
},
|
||||
});
|
||||
|
||||
const nextStatus = 'submitted';
|
||||
await applyRuntimeUpdates({
|
||||
contributionCallbackUrl: normalizedUrl,
|
||||
contributionCallbackStatus: nextStatus,
|
||||
contributionCallbackMessage: buildCallbackMessage(nextStatus, payload),
|
||||
});
|
||||
|
||||
if (typeof closeLocalhostCallbackTabs === 'function') {
|
||||
await closeLocalhostCallbackTabs(normalizedUrl).catch(() => {});
|
||||
}
|
||||
|
||||
return await pollContributionStatus({ reason: options.reason || 'submit_callback' });
|
||||
} catch (error) {
|
||||
await applyRuntimeUpdates({
|
||||
contributionCallbackUrl: normalizedUrl,
|
||||
contributionCallbackStatus: 'failed',
|
||||
contributionCallbackMessage: `回调提交失败:${error.message}`,
|
||||
});
|
||||
|
||||
if (typeof addLog === 'function') {
|
||||
await addLog(`贡献模式:回调提交失败:${error.message}`, 'warn');
|
||||
}
|
||||
|
||||
throw error;
|
||||
} finally {
|
||||
pendingCallbackSubmissions.delete(dedupeKey);
|
||||
}
|
||||
})();
|
||||
|
||||
pendingCallbackSubmissions.set(dedupeKey, task);
|
||||
return task;
|
||||
}
|
||||
|
||||
async function handleCapturedCallback(rawUrl, metadata = {}) {
|
||||
const currentState = await getState();
|
||||
if (!normalizeString(currentState.contributionSessionId) || !currentState.contributionMode) {
|
||||
return currentState;
|
||||
}
|
||||
if (!isContributionCallbackUrl(rawUrl, currentState)) {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
const normalizedUrl = normalizeString(rawUrl);
|
||||
return runCapturedCallbackOnce(normalizedUrl, async () => {
|
||||
const currentState = await getState();
|
||||
if (!normalizeString(currentState.contributionSessionId) || !currentState.contributionMode) {
|
||||
return currentState;
|
||||
}
|
||||
if (!isContributionCallbackUrl(normalizedUrl, currentState)) {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
const currentCallbackStatus = normalizeContributionCallbackStatus(currentState.contributionCallbackStatus);
|
||||
if (
|
||||
normalizedUrl
|
||||
&& normalizeString(currentState.contributionCallbackUrl) === normalizedUrl
|
||||
&& (CALLBACK_FINAL_STATUSES.has(currentCallbackStatus) || currentCallbackStatus === 'submitting')
|
||||
) {
|
||||
return currentState;
|
||||
}
|
||||
const callbackDedupeKey = `${normalizeString(currentState.contributionSessionId)}::${normalizedUrl}`;
|
||||
if (pendingCapturedCallbacks.has(callbackDedupeKey)) {
|
||||
return pendingCapturedCallbacks.get(callbackDedupeKey);
|
||||
}
|
||||
if (pendingCallbackSubmissions.has(callbackDedupeKey)) {
|
||||
return pendingCallbackSubmissions.get(callbackDedupeKey);
|
||||
}
|
||||
const currentCallbackStatus = normalizeContributionCallbackStatus(currentState.contributionCallbackStatus);
|
||||
if (
|
||||
normalizedUrl
|
||||
&& normalizeString(currentState.contributionCallbackUrl) === normalizedUrl
|
||||
&& (CALLBACK_FINAL_STATUSES.has(currentCallbackStatus) || currentCallbackStatus === 'submitting')
|
||||
) {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
const task = (async () => {
|
||||
await applyRuntimeUpdates({
|
||||
contributionCallbackUrl: normalizedUrl,
|
||||
contributionCallbackStatus: 'captured',
|
||||
@@ -573,8 +572,13 @@
|
||||
});
|
||||
} catch {
|
||||
return getState();
|
||||
} finally {
|
||||
pendingCapturedCallbacks.delete(callbackDedupeKey);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
pendingCapturedCallbacks.set(callbackDedupeKey, task);
|
||||
return task;
|
||||
}
|
||||
|
||||
async function pollContributionStatus(options = {}) {
|
||||
@@ -597,16 +601,6 @@
|
||||
const callbackState = deriveCallbackState(mergedPayload, currentState);
|
||||
const updates = {
|
||||
contributionLastPollAt: Date.now(),
|
||||
contributionSource: normalizeContributionSource(
|
||||
mergedPayload.source
|
||||
|| mergedPayload.source_kind
|
||||
|| currentState.contributionSource
|
||||
),
|
||||
contributionTargetGroupName: normalizeString(
|
||||
mergedPayload.target_group_name
|
||||
|| mergedPayload.group_name
|
||||
|| currentState.contributionTargetGroupName
|
||||
),
|
||||
contributionStatus: normalizedStatus,
|
||||
contributionStatusMessage: buildStatusMessage(normalizedStatus, mergedPayload),
|
||||
contributionCallbackUrl: callbackState.callbackUrl,
|
||||
@@ -648,7 +642,6 @@
|
||||
async function startContributionFlow(options = {}) {
|
||||
const currentState = options.stateOverride || await getState();
|
||||
const shouldOpenAuthTab = options.openAuthTab !== false;
|
||||
const routing = resolveContributionRouting(currentState);
|
||||
if (!currentState.contributionMode) {
|
||||
throw new Error('请先进入贡献模式。');
|
||||
}
|
||||
@@ -666,14 +659,15 @@
|
||||
return pollContributionStatus({ reason: 'resume_existing' });
|
||||
}
|
||||
|
||||
const routingState = resolveContributionModeRoutingState(currentState);
|
||||
const payload = await fetchContributionJson('/start', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
nickname: buildNickname(currentState, options.nickname),
|
||||
qq: buildContributionQq(currentState, options.qq),
|
||||
email: normalizeString(currentState.email),
|
||||
source: routing.source,
|
||||
target_group_name: routing.targetGroupName,
|
||||
source: routingState.source,
|
||||
target_group_name: routingState.targetGroupName,
|
||||
channel: 'codex-extension',
|
||||
},
|
||||
});
|
||||
@@ -686,12 +680,6 @@
|
||||
}
|
||||
|
||||
await applyRuntimeUpdates({
|
||||
contributionSource: normalizeContributionSource(payload.source || routing.source),
|
||||
contributionTargetGroupName: normalizeString(
|
||||
payload.target_group_name
|
||||
|| payload.group_name
|
||||
|| routing.targetGroupName
|
||||
),
|
||||
contributionSessionId: sessionId,
|
||||
contributionAuthUrl: authUrl,
|
||||
contributionAuthState: authState,
|
||||
@@ -722,7 +710,7 @@
|
||||
}
|
||||
|
||||
function onTabUpdated(tabId, changeInfo, tab) {
|
||||
const candidateUrl = normalizeString(changeInfo?.url);
|
||||
const candidateUrl = normalizeString(changeInfo?.url || tab?.url);
|
||||
if (!candidateUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -216,6 +216,27 @@
|
||||
}
|
||||
|
||||
async function handleStepData(step, payload) {
|
||||
if (step === 1) {
|
||||
const updates = {};
|
||||
if (payload.oauthUrl) {
|
||||
updates.oauthUrl = payload.oauthUrl;
|
||||
broadcastDataUpdate({ oauthUrl: payload.oauthUrl });
|
||||
}
|
||||
if (payload.sub2apiSessionId !== undefined) updates.sub2apiSessionId = payload.sub2apiSessionId || null;
|
||||
if (payload.sub2apiOAuthState !== undefined) updates.sub2apiOAuthState = payload.sub2apiOAuthState || null;
|
||||
if (payload.sub2apiGroupId !== undefined) updates.sub2apiGroupId = payload.sub2apiGroupId || null;
|
||||
if (payload.sub2apiDraftName !== undefined) updates.sub2apiDraftName = payload.sub2apiDraftName || null;
|
||||
if (payload.sub2apiProxyId !== undefined) updates.sub2apiProxyId = payload.sub2apiProxyId || null;
|
||||
if (payload.cpaOAuthState !== undefined) updates.cpaOAuthState = payload.cpaOAuthState || null;
|
||||
if (payload.cpaManagementOrigin !== undefined) updates.cpaManagementOrigin = payload.cpaManagementOrigin || null;
|
||||
if (payload.codex2apiSessionId !== undefined) updates.codex2apiSessionId = payload.codex2apiSessionId || null;
|
||||
if (payload.codex2apiOAuthState !== undefined) updates.codex2apiOAuthState = payload.codex2apiOAuthState || null;
|
||||
if (Object.keys(updates).length) {
|
||||
await setState(updates);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const stateForStep = await getState();
|
||||
const stepKey = getStepKeyForState(step, stateForStep);
|
||||
|
||||
@@ -262,24 +283,6 @@
|
||||
}
|
||||
|
||||
switch (step) {
|
||||
case 1: {
|
||||
const updates = {};
|
||||
if (payload.oauthUrl) {
|
||||
updates.oauthUrl = payload.oauthUrl;
|
||||
broadcastDataUpdate({ oauthUrl: payload.oauthUrl });
|
||||
}
|
||||
if (payload.sub2apiSessionId !== undefined) updates.sub2apiSessionId = payload.sub2apiSessionId || null;
|
||||
if (payload.sub2apiOAuthState !== undefined) updates.sub2apiOAuthState = payload.sub2apiOAuthState || null;
|
||||
if (payload.sub2apiGroupId !== undefined) updates.sub2apiGroupId = payload.sub2apiGroupId || null;
|
||||
if (payload.sub2apiDraftName !== undefined) updates.sub2apiDraftName = payload.sub2apiDraftName || null;
|
||||
if (payload.sub2apiProxyId !== undefined) updates.sub2apiProxyId = payload.sub2apiProxyId || null;
|
||||
if (payload.codex2apiSessionId !== undefined) updates.codex2apiSessionId = payload.codex2apiSessionId || null;
|
||||
if (payload.codex2apiOAuthState !== undefined) updates.codex2apiOAuthState = payload.codex2apiOAuthState || null;
|
||||
if (Object.keys(updates).length) {
|
||||
await setState(updates);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
if (payload.email) {
|
||||
await setEmailState(payload.email);
|
||||
|
||||
+108
-37
@@ -43,6 +43,78 @@
|
||||
return message || `Codex2API 请求失败(HTTP ${responseStatus})。`;
|
||||
}
|
||||
|
||||
function deriveCpaManagementOrigin(vpsUrl) {
|
||||
const normalizedUrl = String(vpsUrl || '').trim();
|
||||
if (!normalizedUrl) {
|
||||
throw new Error('尚未配置 CPA 地址,请先在侧边栏填写。');
|
||||
}
|
||||
let parsed;
|
||||
try {
|
||||
parsed = new URL(normalizedUrl);
|
||||
} catch {
|
||||
throw new Error('CPA 地址格式无效,请先在侧边栏检查。');
|
||||
}
|
||||
return parsed.origin;
|
||||
}
|
||||
|
||||
function getCpaApiErrorMessage(payload, responseStatus = 500) {
|
||||
const candidates = [
|
||||
payload?.error,
|
||||
payload?.message,
|
||||
payload?.detail,
|
||||
payload?.reason,
|
||||
];
|
||||
const message = candidates
|
||||
.map((value) => String(value || '').trim())
|
||||
.find(Boolean);
|
||||
return message || `CPA 管理接口请求失败(HTTP ${responseStatus})。`;
|
||||
}
|
||||
|
||||
async function fetchCpaManagementJson(origin, path, options = {}) {
|
||||
const timeoutMs = Math.max(1000, Math.floor(Number(options.timeoutMs) || 20000));
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
||||
|
||||
try {
|
||||
const managementKey = String(options.managementKey || '').trim();
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
if (managementKey) {
|
||||
headers.Authorization = `Bearer ${managementKey}`;
|
||||
headers['X-Management-Key'] = managementKey;
|
||||
}
|
||||
|
||||
const response = await fetch(`${origin}${path}`, {
|
||||
method: options.method || 'POST',
|
||||
headers,
|
||||
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
let payload = {};
|
||||
try {
|
||||
payload = await response.json();
|
||||
} catch {
|
||||
payload = {};
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(getCpaApiErrorMessage(payload, response.status));
|
||||
}
|
||||
|
||||
return payload;
|
||||
} catch (error) {
|
||||
if (error?.name === 'AbortError') {
|
||||
throw new Error('CPA 管理接口请求超时,请稍后重试。');
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchCodex2ApiJson(origin, path, options = {}) {
|
||||
const timeoutMs = Math.max(1000, Math.floor(Number(options.timeoutMs) || 30000));
|
||||
const controller = new AbortController();
|
||||
@@ -97,49 +169,48 @@
|
||||
if (!state.vpsUrl) {
|
||||
throw new Error('尚未配置 CPA 地址,请先在侧边栏填写。');
|
||||
}
|
||||
|
||||
await addLog(`${logLabel}:正在打开 CPA 面板...`);
|
||||
|
||||
const injectFiles = ['content/activation-utils.js', 'content/utils.js', 'content/vps-panel.js'];
|
||||
await closeConflictingTabsForSource('vps-panel', state.vpsUrl);
|
||||
|
||||
const tab = await chrome.tabs.create({ url: state.vpsUrl, active: true });
|
||||
const tabId = tab.id;
|
||||
await rememberSourceLastUrl('vps-panel', state.vpsUrl);
|
||||
|
||||
await addLog(`${logLabel}:CPA 面板已打开,正在等待页面进入目标地址...`);
|
||||
const matchedTab = await waitForTabUrlFamily('vps-panel', tabId, state.vpsUrl, {
|
||||
timeoutMs: 15000,
|
||||
retryDelayMs: 400,
|
||||
});
|
||||
if (!matchedTab) {
|
||||
await addLog(`${logLabel}:CPA 页面尚未完全进入目标地址,继续尝试连接内容脚本...`, 'warn');
|
||||
const managementKey = String(state.vpsPassword || '').trim();
|
||||
if (!managementKey) {
|
||||
throw new Error('尚未配置 CPA 管理密钥,请先在侧边栏填写。');
|
||||
}
|
||||
|
||||
await ensureContentScriptReadyOnTab('vps-panel', tabId, {
|
||||
inject: injectFiles,
|
||||
timeoutMs: 45000,
|
||||
retryDelayMs: 900,
|
||||
logMessage: `${logLabel}:CPA 面板仍在加载,正在重试连接内容脚本...`,
|
||||
const origin = deriveCpaManagementOrigin(state.vpsUrl);
|
||||
|
||||
await addLog(`${logLabel}:正在通过 CPA 管理接口获取 OAuth 授权链接...`);
|
||||
const result = await fetchCpaManagementJson(origin, '/v0/management/codex-auth-url', {
|
||||
method: 'GET',
|
||||
managementKey,
|
||||
});
|
||||
|
||||
const result = await sendToContentScriptResilient('vps-panel', {
|
||||
type: 'REQUEST_OAUTH_URL',
|
||||
source: 'background',
|
||||
payload: {
|
||||
vpsPassword: state.vpsPassword,
|
||||
logStep: 7,
|
||||
},
|
||||
}, {
|
||||
timeoutMs: 30000,
|
||||
retryDelayMs: 700,
|
||||
logMessage: `${logLabel}:CPA 面板通信未就绪,正在等待页面恢复...`,
|
||||
});
|
||||
const oauthUrl = String(
|
||||
result?.url
|
||||
|| result?.auth_url
|
||||
|| result?.authUrl
|
||||
|| result?.data?.url
|
||||
|| result?.data?.auth_url
|
||||
|| result?.data?.authUrl
|
||||
|| ''
|
||||
).trim();
|
||||
const oauthState = String(
|
||||
result?.state
|
||||
|| result?.auth_state
|
||||
|| result?.authState
|
||||
|| result?.data?.state
|
||||
|| result?.data?.auth_state
|
||||
|| result?.data?.authState
|
||||
|| ''
|
||||
).trim()
|
||||
|| extractStateFromAuthUrl(oauthUrl);
|
||||
|
||||
if (result?.error) {
|
||||
throw new Error(result.error);
|
||||
if (!oauthUrl || !oauthUrl.startsWith('http')) {
|
||||
throw new Error('CPA 管理接口未返回有效的 auth_url。');
|
||||
}
|
||||
return result || {};
|
||||
|
||||
return {
|
||||
oauthUrl,
|
||||
cpaOAuthState: oauthState || null,
|
||||
cpaManagementOrigin: origin,
|
||||
};
|
||||
}
|
||||
|
||||
async function requestCodex2ApiOAuthUrl(state, options = {}) {
|
||||
|
||||
@@ -40,17 +40,14 @@
|
||||
return /缺少|未配置|请输入|无效|错误|失败|401|认证失败|未授权|unauthorized|invalid/i.test(message);
|
||||
}
|
||||
|
||||
function getVisibleStep(state, fallback = 7) {
|
||||
const visibleStep = Math.floor(Number(state?.visibleStep) || 0);
|
||||
return visibleStep > 0 ? visibleStep : fallback;
|
||||
}
|
||||
|
||||
async function executeStep7(state) {
|
||||
const visibleStep = getVisibleStep(state, 7);
|
||||
if (!state.email) {
|
||||
throw new Error('缺少邮箱地址,请先完成步骤 3。');
|
||||
}
|
||||
|
||||
const visibleStep = Math.floor(Number(state?.visibleStep) || 0);
|
||||
const completionStep = visibleStep > 0 ? visibleStep : 7;
|
||||
|
||||
let attempt = 0;
|
||||
let lastError = null;
|
||||
|
||||
@@ -60,22 +57,22 @@
|
||||
try {
|
||||
const currentState = attempt === 1 ? state : await getState();
|
||||
const password = currentState.password || currentState.customPassword || '';
|
||||
const oauthUrl = await refreshOAuthUrlBeforeStep6(currentState, { visibleStep });
|
||||
const oauthUrl = await refreshOAuthUrlBeforeStep6(currentState);
|
||||
if (typeof startOAuthFlowTimeoutWindow === 'function') {
|
||||
await startOAuthFlowTimeoutWindow({ step: visibleStep, oauthUrl });
|
||||
await startOAuthFlowTimeoutWindow({ step: 7, oauthUrl });
|
||||
}
|
||||
const loginTimeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
|
||||
? await getOAuthFlowStepTimeoutMs(180000, {
|
||||
step: visibleStep,
|
||||
step: 7,
|
||||
actionLabel: 'OAuth 登录并进入验证码页',
|
||||
oauthUrl,
|
||||
})
|
||||
: 180000;
|
||||
|
||||
if (attempt === 1) {
|
||||
await addLog(`步骤 ${visibleStep}:正在打开最新 OAuth 链接并登录...`);
|
||||
await addLog('步骤 7:正在打开最新 OAuth 链接并登录...');
|
||||
} else {
|
||||
await addLog(`步骤 ${visibleStep}:上一轮失败后,正在进行第 ${attempt} 次尝试(最多 ${STEP6_MAX_ATTEMPTS} 次)...`, 'warn');
|
||||
await addLog(`步骤 7:上一轮失败后,正在进行第 ${attempt} 次尝试(最多 ${STEP6_MAX_ATTEMPTS} 次)...`, 'warn');
|
||||
}
|
||||
|
||||
await reuseOrCreateTab('signup-page', oauthUrl);
|
||||
@@ -89,14 +86,13 @@
|
||||
payload: {
|
||||
email: currentState.email,
|
||||
password,
|
||||
visibleStep,
|
||||
},
|
||||
},
|
||||
{
|
||||
timeoutMs: loginTimeoutMs,
|
||||
responseTimeoutMs: loginTimeoutMs,
|
||||
retryDelayMs: 700,
|
||||
logMessage: `步骤 ${visibleStep}:认证页正在切换,等待页面重新就绪后继续登录...`,
|
||||
logMessage: '步骤 7:认证页正在切换,等待页面重新就绪后继续登录...',
|
||||
}
|
||||
);
|
||||
|
||||
@@ -108,13 +104,14 @@
|
||||
const completionPayload = {
|
||||
loginVerificationRequestedAt: result.loginVerificationRequestedAt || null,
|
||||
};
|
||||
if (result.skipLoginVerificationStep) {
|
||||
completionPayload.skipLoginVerificationStep = true;
|
||||
if (Object.prototype.hasOwnProperty.call(result || {}, 'skipLoginVerificationStep')) {
|
||||
completionPayload.skipLoginVerificationStep = Boolean(result.skipLoginVerificationStep);
|
||||
}
|
||||
if (result.directOAuthConsentPage) {
|
||||
completionPayload.directOAuthConsentPage = true;
|
||||
if (Object.prototype.hasOwnProperty.call(result || {}, 'directOAuthConsentPage')) {
|
||||
completionPayload.directOAuthConsentPage = Boolean(result.directOAuthConsentPage);
|
||||
}
|
||||
await completeStepFromBackground(visibleStep, completionPayload);
|
||||
|
||||
await completeStepFromBackground(completionStep, completionPayload);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -132,7 +129,7 @@
|
||||
}
|
||||
if (isManagementSecretConfigError(err)) {
|
||||
await addLog(
|
||||
`步骤 ${visibleStep}:检测到来源后台管理密钥缺失或错误,不再重试,当前流程停止。原因:${getErrorMessage(err)}`,
|
||||
`步骤 7:检测到来源后台管理密钥缺失或错误,不再重试,当前流程停止。原因:${getErrorMessage(err)}`,
|
||||
'error'
|
||||
);
|
||||
throw err;
|
||||
@@ -142,11 +139,11 @@
|
||||
break;
|
||||
}
|
||||
|
||||
await addLog(`步骤 ${visibleStep}:第 ${attempt} 次尝试失败,原因:${getErrorMessage(err)};准备重试...`, 'warn');
|
||||
await addLog(`步骤 7:第 ${attempt} 次尝试失败,原因:${getErrorMessage(err)};准备重试...`, 'warn');
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`步骤 ${visibleStep}:判断失败后已重试 ${STEP6_MAX_ATTEMPTS - 1} 次,仍未成功。最后原因:${getErrorMessage(lastError)}`);
|
||||
throw new Error(`步骤 7:判断失败后已重试 ${STEP6_MAX_ATTEMPTS - 1} 次,仍未成功。最后原因:${getErrorMessage(lastError)}`);
|
||||
}
|
||||
|
||||
return { executeStep7 };
|
||||
|
||||
@@ -26,31 +26,23 @@
|
||||
return String(value || '').trim();
|
||||
}
|
||||
|
||||
function getVisibleStep(state, fallback = 10) {
|
||||
function resolvePlatformVerifyStep(state = {}) {
|
||||
const visibleStep = Math.floor(Number(state?.visibleStep) || 0);
|
||||
return visibleStep > 0 ? visibleStep : fallback;
|
||||
return visibleStep >= 10 ? visibleStep : 10;
|
||||
}
|
||||
|
||||
function getConfirmStepForVisibleStep(visibleStep) {
|
||||
return visibleStep >= 13 ? 12 : 9;
|
||||
}
|
||||
|
||||
function getAuthLoginStepForVisibleStep(visibleStep) {
|
||||
return visibleStep >= 13 ? 10 : 7;
|
||||
}
|
||||
|
||||
function parseLocalhostCallback(rawUrl, visibleStep = 10, confirmStep = 9) {
|
||||
function parseLocalhostCallback(rawUrl) {
|
||||
let parsed;
|
||||
try {
|
||||
parsed = new URL(rawUrl);
|
||||
} catch {
|
||||
throw new Error(`步骤 ${visibleStep} 捕获到的 localhost OAuth 回调地址格式无效,请重新执行步骤 ${confirmStep}。`);
|
||||
throw new Error('步骤 10 捕获到的 localhost OAuth 回调地址格式无效,请重新执行步骤 9。');
|
||||
}
|
||||
|
||||
const code = normalizeString(parsed.searchParams.get('code'));
|
||||
const state = normalizeString(parsed.searchParams.get('state'));
|
||||
if (!code || !state) {
|
||||
throw new Error(`步骤 ${visibleStep} 捕获到的 localhost OAuth 回调地址缺少 code 或 state,请重新执行步骤 ${confirmStep}。`);
|
||||
throw new Error('步骤 10 捕获到的 localhost OAuth 回调地址缺少 code 或 state,请重新执行步骤 9。');
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -72,6 +64,77 @@
|
||||
return details || `Codex2API 请求失败(HTTP ${responseStatus})。`;
|
||||
}
|
||||
|
||||
function deriveCpaManagementOrigin(vpsUrl) {
|
||||
const normalizedUrl = normalizeString(vpsUrl);
|
||||
if (!normalizedUrl) {
|
||||
throw new Error('尚未填写 CPA 地址,请先在侧边栏输入。');
|
||||
}
|
||||
let parsed;
|
||||
try {
|
||||
parsed = new URL(normalizedUrl);
|
||||
} catch {
|
||||
throw new Error('CPA 地址格式无效,请先在侧边栏检查。');
|
||||
}
|
||||
return parsed.origin;
|
||||
}
|
||||
|
||||
function getCpaApiErrorMessage(payload, responseStatus = 500) {
|
||||
const details = [
|
||||
payload?.error,
|
||||
payload?.message,
|
||||
payload?.detail,
|
||||
payload?.reason,
|
||||
]
|
||||
.map((value) => normalizeString(value))
|
||||
.find(Boolean);
|
||||
return details || `CPA 管理接口请求失败(HTTP ${responseStatus})。`;
|
||||
}
|
||||
|
||||
async function fetchCpaManagementJson(origin, path, options = {}) {
|
||||
const controller = new AbortController();
|
||||
const timeoutMs = Math.max(1000, Math.floor(Number(options.timeoutMs) || 20000));
|
||||
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
||||
|
||||
try {
|
||||
const managementKey = normalizeString(options.managementKey);
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
if (managementKey) {
|
||||
headers.Authorization = `Bearer ${managementKey}`;
|
||||
headers['X-Management-Key'] = managementKey;
|
||||
}
|
||||
|
||||
const response = await fetch(`${origin}${path}`, {
|
||||
method: options.method || 'POST',
|
||||
headers,
|
||||
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
let payload = {};
|
||||
try {
|
||||
payload = await response.json();
|
||||
} catch {
|
||||
payload = {};
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(getCpaApiErrorMessage(payload, response.status));
|
||||
}
|
||||
|
||||
return payload;
|
||||
} catch (error) {
|
||||
if (error?.name === 'AbortError') {
|
||||
throw new Error('CPA 管理接口请求超时,请稍后重试。');
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchCodex2ApiJson(origin, path, options = {}) {
|
||||
const controller = new AbortController();
|
||||
const timeoutMs = Math.max(1000, Math.floor(Number(options.timeoutMs) || 30000));
|
||||
@@ -122,95 +185,88 @@
|
||||
}
|
||||
|
||||
async function executeCpaStep10(state) {
|
||||
const visibleStep = getVisibleStep(state, 10);
|
||||
const confirmStep = getConfirmStepForVisibleStep(visibleStep);
|
||||
const platformVerifyStep = resolvePlatformVerifyStep(state);
|
||||
if (state.localhostUrl && !isLocalhostOAuthCallbackUrl(state.localhostUrl)) {
|
||||
throw new Error(`步骤 ${confirmStep} 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 ${confirmStep}。`);
|
||||
throw new Error('步骤 9 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 9。');
|
||||
}
|
||||
if (!state.localhostUrl) {
|
||||
throw new Error(`缺少 localhost 回调地址,请先完成步骤 ${confirmStep}。`);
|
||||
throw new Error('缺少 localhost 回调地址,请先完成步骤 9。');
|
||||
}
|
||||
if (!state.vpsUrl) {
|
||||
throw new Error('尚未填写 CPA 地址,请先在侧边栏输入。');
|
||||
}
|
||||
|
||||
if (shouldBypassStep9ForLocalCpa(state)) {
|
||||
await addLog(`步骤 ${visibleStep}:检测到本地 CPA,且当前策略为“跳过第10步”,本轮不再重复提交回调地址。`, 'info');
|
||||
await completeStepFromBackground(visibleStep, {
|
||||
await addLog('步骤 10:检测到本地 CPA,且当前策略为“跳过第10步”,本轮不再重复提交回调地址。', 'info');
|
||||
await completeStepFromBackground(platformVerifyStep, {
|
||||
localhostUrl: state.localhostUrl,
|
||||
verifiedStatus: 'local-auto',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await addLog(`步骤 ${visibleStep}:正在打开 CPA 面板...`);
|
||||
|
||||
const injectFiles = ['content/activation-utils.js', 'content/utils.js', 'content/vps-panel.js'];
|
||||
let tabId = await getTabId('vps-panel');
|
||||
const alive = tabId && await isTabAlive('vps-panel');
|
||||
|
||||
if (!alive) {
|
||||
tabId = await reuseOrCreateTab('vps-panel', state.vpsUrl, {
|
||||
inject: injectFiles,
|
||||
reloadIfSameUrl: true,
|
||||
});
|
||||
} else {
|
||||
await closeConflictingTabsForSource('vps-panel', state.vpsUrl, { excludeTabIds: [tabId] });
|
||||
await chrome.tabs.update(tabId, { active: true });
|
||||
await rememberSourceLastUrl('vps-panel', state.vpsUrl);
|
||||
const callback = parseLocalhostCallback(state.localhostUrl);
|
||||
const expectedState = normalizeString(state.cpaOAuthState);
|
||||
if (expectedState && expectedState !== callback.state) {
|
||||
throw new Error('CPA 回调 state 与当前授权会话不匹配,请重新执行步骤 7。');
|
||||
}
|
||||
const managementKey = normalizeString(state.vpsPassword);
|
||||
if (!managementKey) {
|
||||
throw new Error('尚未配置 CPA 管理密钥,请先在侧边栏填写。');
|
||||
}
|
||||
|
||||
await ensureContentScriptReadyOnTab('vps-panel', tabId, {
|
||||
inject: injectFiles,
|
||||
timeoutMs: 45000,
|
||||
retryDelayMs: 900,
|
||||
logMessage: `步骤 ${visibleStep}:CPA 面板仍在加载,正在重试连接...`,
|
||||
});
|
||||
await addLog('步骤 10:正在通过 CPA 管理接口提交回调地址...');
|
||||
try {
|
||||
const origin = normalizeString(state.cpaManagementOrigin) || deriveCpaManagementOrigin(state.vpsUrl);
|
||||
const result = await fetchCpaManagementJson(origin, '/v0/management/oauth-callback', {
|
||||
method: 'POST',
|
||||
managementKey,
|
||||
body: {
|
||||
provider: 'codex',
|
||||
redirect_url: callback.url,
|
||||
},
|
||||
});
|
||||
|
||||
await addLog(`步骤 ${visibleStep}:正在填写回调地址...`);
|
||||
const result = await sendToContentScriptResilient('vps-panel', {
|
||||
type: 'EXECUTE_STEP',
|
||||
step: visibleStep,
|
||||
source: 'background',
|
||||
payload: { localhostUrl: state.localhostUrl, vpsPassword: state.vpsPassword, visibleStep },
|
||||
}, {
|
||||
timeoutMs: 125000,
|
||||
responseTimeoutMs: 125000,
|
||||
retryDelayMs: 700,
|
||||
logMessage: `步骤 ${visibleStep}:CPA 面板通信未就绪,正在等待页面恢复...`,
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
throw new Error(result.error);
|
||||
const verifiedStatus = normalizeString(result?.message)
|
||||
|| normalizeString(result?.status_message)
|
||||
|| 'CPA 已通过接口提交回调';
|
||||
await addLog(`步骤 10:${verifiedStatus}`, 'ok');
|
||||
await completeStepFromBackground(platformVerifyStep, {
|
||||
localhostUrl: callback.url,
|
||||
verifiedStatus,
|
||||
});
|
||||
} catch (error) {
|
||||
const reason = normalizeString(error?.message) || 'unknown error';
|
||||
await addLog(`步骤 10:CPA 接口提交失败:${reason}`, 'error');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function executeCodex2ApiStep10(state) {
|
||||
const visibleStep = getVisibleStep(state, 10);
|
||||
const confirmStep = getConfirmStepForVisibleStep(visibleStep);
|
||||
const platformVerifyStep = resolvePlatformVerifyStep(state);
|
||||
if (state.localhostUrl && !isLocalhostOAuthCallbackUrl(state.localhostUrl)) {
|
||||
throw new Error(`步骤 ${confirmStep} 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 ${confirmStep}。`);
|
||||
throw new Error('步骤 9 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 9。');
|
||||
}
|
||||
if (!state.localhostUrl) {
|
||||
throw new Error(`缺少 localhost 回调地址,请先完成步骤 ${confirmStep}。`);
|
||||
throw new Error('缺少 localhost 回调地址,请先完成步骤 9。');
|
||||
}
|
||||
if (!state.codex2apiSessionId) {
|
||||
throw new Error(`缺少 Codex2API 会话信息,请重新执行步骤 ${getAuthLoginStepForVisibleStep(visibleStep)}。`);
|
||||
throw new Error('缺少 Codex2API 会话信息,请重新执行步骤 7。');
|
||||
}
|
||||
if (!normalizeString(state.codex2apiAdminKey)) {
|
||||
throw new Error('尚未配置 Codex2API 管理密钥,请先在侧边栏填写。');
|
||||
}
|
||||
|
||||
const callback = parseLocalhostCallback(state.localhostUrl, visibleStep, confirmStep);
|
||||
const callback = parseLocalhostCallback(state.localhostUrl);
|
||||
const expectedState = normalizeString(state.codex2apiOAuthState);
|
||||
if (expectedState && expectedState !== callback.state) {
|
||||
throw new Error(`Codex2API 回调 state 与当前授权会话不匹配,请重新执行步骤 ${getAuthLoginStepForVisibleStep(visibleStep)}。`);
|
||||
throw new Error('Codex2API 回调 state 与当前授权会话不匹配,请重新执行步骤 7。');
|
||||
}
|
||||
|
||||
const codex2apiUrl = normalizeCodex2ApiUrl(state.codex2apiUrl);
|
||||
const origin = new URL(codex2apiUrl).origin;
|
||||
|
||||
await addLog(`步骤 ${visibleStep}:正在向 Codex2API 提交回调并创建账号...`);
|
||||
await addLog('步骤 10:正在向 Codex2API 提交回调并创建账号...');
|
||||
const result = await fetchCodex2ApiJson(origin, '/api/admin/oauth/exchange-code', {
|
||||
adminKey: state.codex2apiAdminKey,
|
||||
method: 'POST',
|
||||
@@ -222,21 +278,19 @@
|
||||
});
|
||||
|
||||
const verifiedStatus = normalizeString(result?.message) || 'Codex2API OAuth 账号添加成功';
|
||||
await addLog(`步骤 ${visibleStep}:${verifiedStatus}`, 'ok');
|
||||
await completeStepFromBackground(visibleStep, {
|
||||
await addLog(`步骤 10:${verifiedStatus}`, 'ok');
|
||||
await completeStepFromBackground(platformVerifyStep, {
|
||||
localhostUrl: callback.url,
|
||||
verifiedStatus,
|
||||
});
|
||||
}
|
||||
|
||||
async function executeSub2ApiStep10(state) {
|
||||
const visibleStep = getVisibleStep(state, 10);
|
||||
const confirmStep = getConfirmStepForVisibleStep(visibleStep);
|
||||
if (state.localhostUrl && !isLocalhostOAuthCallbackUrl(state.localhostUrl)) {
|
||||
throw new Error(`步骤 ${confirmStep} 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 ${confirmStep}。`);
|
||||
throw new Error('步骤 9 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 9。');
|
||||
}
|
||||
if (!state.localhostUrl) {
|
||||
throw new Error(`缺少 localhost 回调地址,请先完成步骤 ${confirmStep}。`);
|
||||
throw new Error('缺少 localhost 回调地址,请先完成步骤 9。');
|
||||
}
|
||||
if (!state.sub2apiSessionId) {
|
||||
throw new Error('缺少 SUB2API 会话信息,请重新执行步骤 1。');
|
||||
@@ -251,7 +305,7 @@
|
||||
const sub2apiUrl = normalizeSub2ApiUrl(state.sub2apiUrl);
|
||||
const injectFiles = ['content/utils.js', 'content/sub2api-panel.js'];
|
||||
|
||||
await addLog(`步骤 ${visibleStep}:正在打开 SUB2API 后台...`);
|
||||
await addLog('步骤 10:正在打开 SUB2API 后台...');
|
||||
|
||||
let tabId = await getTabId('sub2api-panel');
|
||||
const alive = tabId && await isTabAlive('sub2api-panel');
|
||||
@@ -273,13 +327,12 @@
|
||||
injectSource: 'sub2api-panel',
|
||||
});
|
||||
|
||||
await addLog(`步骤 ${visibleStep}:正在向 SUB2API 提交回调并创建账号...`);
|
||||
await addLog('步骤 10:正在向 SUB2API 提交回调并创建账号...');
|
||||
const result = await sendToContentScript('sub2api-panel', {
|
||||
type: 'EXECUTE_STEP',
|
||||
step: visibleStep,
|
||||
step: 10,
|
||||
source: 'background',
|
||||
payload: {
|
||||
visibleStep,
|
||||
localhostUrl: state.localhostUrl,
|
||||
sub2apiUrl,
|
||||
sub2apiEmail: state.sub2apiEmail,
|
||||
|
||||
Reference in New Issue
Block a user