feat(contribution): 增强贡献模式逻辑,支持 SUB2API 和 CPA 源,优化状态处理和界面显示

This commit is contained in:
QLHazycoder
2026-04-26 00:28:25 +00:00
parent d9ae1c42cf
commit 596bf38d5c
9 changed files with 334 additions and 40 deletions
+50 -13
View File
@@ -183,6 +183,10 @@ const DEFAULT_SUB2API_URL = 'https://sub2api.hisence.fun/admin/accounts';
const DEFAULT_CODEX2API_URL = 'http://localhost:8080/admin/accounts';
const DEFAULT_SUB2API_GROUP_NAME = 'codex';
const DEFAULT_SUB2API_PROXY_NAME = '';
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 DEFAULT_SUB2API_REDIRECT_URI = 'http://localhost:1455/auth/callback';
const AUTO_RUN_TIMER_ALARM_NAME = 'auto-run-timer';
const AUTO_RUN_TIMER_KIND_SCHEDULED_START = 'scheduled_start';
@@ -222,6 +226,8 @@ const ACCOUNT_RUN_HISTORY_STORAGE_KEY = 'accountRunHistory';
const CONTRIBUTION_RUNTIME_DEFAULTS = self.MultiPageBackgroundContributionOAuth?.RUNTIME_DEFAULTS || {
contributionMode: false,
contributionModeExpected: false,
contributionSource: CONTRIBUTION_SOURCE_SUB2API,
contributionTargetGroupName: CONTRIBUTION_SUB2API_DEFAULT_GROUP_NAME,
contributionNickname: '',
contributionQq: '',
contributionSessionId: '',
@@ -243,6 +249,40 @@ function isPlusModeState(state = {}) {
return Boolean(state?.plusModeEnabled);
}
function normalizeContributionModeSource(value = '') {
const normalized = String(value || '').trim().toLowerCase();
return normalized === CONTRIBUTION_SOURCE_SUB2API
? CONTRIBUTION_SOURCE_SUB2API
: CONTRIBUTION_SOURCE_CPA;
}
function resolveContributionModeRoutingState(state = {}) {
const currentStatus = String(state?.contributionStatus || '').trim().toLowerCase();
const currentSource = normalizeContributionModeSource(state?.contributionSource);
const hasActiveSession = Boolean(
String(state?.contributionSessionId || '').trim()
&& currentStatus
&& !['auto_approved', 'auto_rejected', 'expired', 'error'].includes(currentStatus)
);
if (hasActiveSession) {
return {
source: currentSource,
targetGroupName: currentSource === CONTRIBUTION_SOURCE_SUB2API
? (String(state?.contributionTargetGroupName || '').trim() || CONTRIBUTION_SUB2API_DEFAULT_GROUP_NAME)
: '',
};
}
const source = CONTRIBUTION_SOURCE_SUB2API;
return {
source,
targetGroupName: isPlusModeState(state)
? CONTRIBUTION_SUB2API_PLUS_GROUP_NAME
: (String(state?.contributionTargetGroupName || '').trim() || CONTRIBUTION_SUB2API_DEFAULT_GROUP_NAME),
};
}
function getStepDefinitionsForState(state = {}) {
return isPlusModeState(state) ? PLUS_STEP_DEFINITIONS : NORMAL_STEP_DEFINITIONS;
}
@@ -1343,11 +1383,18 @@ function buildContributionModeState(enabled, persistedSettings = {}, currentStat
}
if (enabled) {
const routing = resolveContributionModeRoutingState({
...persistedSettings,
...currentState,
...currentContributionState,
});
return {
...currentContributionState,
contributionMode: true,
contributionModeExpected: true,
panelMode: 'cpa',
contributionSource: routing.source,
contributionTargetGroupName: routing.targetGroupName,
panelMode: routing.source,
customPassword: '',
accountRunHistoryTextEnabled: false,
};
@@ -1370,14 +1417,7 @@ async function setContributionMode(enabled) {
getState(),
]);
if (normalizedEnabled) {
await setPersistentSettings({ panelMode: 'cpa' });
}
const updates = buildContributionModeState(normalizedEnabled, {
...persistedSettings,
...(normalizedEnabled ? { panelMode: 'cpa' } : {}),
}, currentState);
const updates = buildContributionModeState(normalizedEnabled, persistedSettings, currentState);
await setState(updates);
const nextState = await getState();
@@ -1550,10 +1590,7 @@ async function resetState() {
getPersistedSettings(),
getPersistedAliasState(),
]);
const contributionModeState = buildContributionModeState(Boolean(prev.contributionMode), {
...persistedSettings,
...(prev.contributionMode ? { panelMode: 'cpa' } : {}),
}, prev);
const contributionModeState = buildContributionModeState(Boolean(prev.contributionMode), persistedSettings, prev);
await chrome.storage.session.clear();
await chrome.storage.session.set({
...DEFAULT_STATE,
+61 -3
View File
@@ -6,10 +6,16 @@
const FINAL_STATUSES = new Set(['auto_approved', 'auto_rejected', '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,
contributionNickname: '',
contributionQq: '',
contributionSessionId: '',
@@ -104,6 +110,40 @@
return FINAL_STATUSES.has(normalizeContributionStatus(status));
}
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':
@@ -111,9 +151,9 @@
case 'waiting':
return '等待提交回调';
case 'processing':
return '已提交回调,等待 CPA 确认';
return '已提交回调,等待服务端确认';
case 'auto_approved':
return '贡献成功,CPA 已确认';
return '贡献成功,服务端已确认';
case 'auto_rejected':
return '贡献未通过确认';
case 'expired':
@@ -531,6 +571,16 @@
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,
@@ -572,6 +622,7 @@
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('请先进入贡献模式。');
}
@@ -595,7 +646,8 @@
nickname: buildNickname(currentState, options.nickname),
qq: buildContributionQq(currentState, options.qq),
email: normalizeString(currentState.email),
source: 'cpa',
source: routing.source,
target_group_name: routing.targetGroupName,
channel: 'codex-extension',
},
});
@@ -608,6 +660,12 @@
}
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,
+3
View File
@@ -644,6 +644,9 @@
stateUpdates.currentStep = 0;
}
await setState(stateUpdates);
if (Boolean(currentState?.contributionMode) && typeof setContributionMode === 'function') {
await setContributionMode(true);
}
if (modeChanged) {
await addLog(
Boolean(updates.plusModeEnabled)
+5 -3
View File
@@ -509,9 +509,6 @@ async function step9_submitOpenAiCallback(payload = {}) {
const sessionId = String(payload.sub2apiSessionId || backgroundState.sub2apiSessionId || '').trim();
const expectedState = String(payload.sub2apiOAuthState || backgroundState.sub2apiOAuthState || '').trim();
const accountName = flowEmail
|| String(payload.sub2apiDraftName || backgroundState.sub2apiDraftName || '').trim()
|| buildDraftAccountName(payload.sub2apiGroupName || backgroundState.sub2apiGroupName || SUB2API_DEFAULT_GROUP_NAME);
const { origin, token } = await loginSub2Api(payload);
const proxyPreference = resolveSub2ApiProxyPreference(payload, backgroundState);
@@ -552,10 +549,15 @@ async function step9_submitOpenAiCallback(payload = {}) {
const credentials = buildOpenAiCredentials(exchangeData);
const extra = buildOpenAiExtra(exchangeData);
const resolvedEmail = String(exchangeData?.email || credentials?.email || '').trim();
const groupId = Number(group.id);
if (!Number.isFinite(groupId) || groupId <= 0) {
throw new Error('SUB2API 返回的目标分组 ID 无效。');
}
const accountName = resolvedEmail
|| flowEmail
|| String(payload.sub2apiDraftName || backgroundState.sub2apiDraftName || '').trim()
|| buildDraftAccountName(payload.sub2apiGroupName || backgroundState.sub2apiGroupName || SUB2API_DEFAULT_GROUP_NAME);
const createPayload = {
name: accountName,
notes: '',
+40 -7
View File
@@ -1,7 +1,10 @@
(function attachSidepanelContributionMode(globalScope) {
const ACTIVE_STATUSES = new Set(['started', 'waiting', 'processing']);
const FINAL_STATUSES = new Set(['auto_approved', 'auto_rejected', 'expired', 'error']);
const DEFAULT_COPY = '当前账号将用于支持项目维护。扩展会自动申请贡献登录地址并持续跟踪授权状态;如检测到回调地址,会自动提交,并继续等待 CPA 最终确认。';
(function attachSidepanelContributionMode(globalScope) {
const ACTIVE_STATUSES = new Set(['started', 'waiting', 'processing']);
const FINAL_STATUSES = new Set(['auto_approved', 'auto_rejected', 'expired', 'error']);
const DEFAULT_COPY = '当前账号将用于支持项目维护。扩展会自动申请贡献登录地址并持续跟踪授权状态;如检测到回调地址,会自动提交,并继续等待服务端确认。';
const CONTRIBUTION_SOURCE_CPA = 'cpa';
const CONTRIBUTION_SOURCE_SUB2API = 'sub2api';
const CONTRIBUTION_SUB2API_DEFAULT_GROUP_NAME = 'codex号池';
function createContributionModeManager(context = {}) {
const {
@@ -66,6 +69,21 @@
}
}
function normalizeContributionSource(value = '') {
const normalized = normalizeString(value).toLowerCase();
return normalized === CONTRIBUTION_SOURCE_SUB2API
? CONTRIBUTION_SOURCE_SUB2API
: CONTRIBUTION_SOURCE_CPA;
}
function getContributionSource(currentState = getLatestState()) {
return normalizeContributionSource(currentState.contributionSource || currentState.panelMode);
}
function getContributionSourceLabel(currentState = getLatestState()) {
return getContributionSource(currentState) === CONTRIBUTION_SOURCE_SUB2API ? 'SUB2API' : 'CPA';
}
function isContributionModeEnabled(currentState = getLatestState()) {
return Boolean(currentState.contributionMode);
}
@@ -173,7 +191,15 @@
}
function getSummaryText(currentState = getLatestState()) {
return normalizeString(currentState.contributionStatusMessage) || DEFAULT_COPY;
const statusMessage = normalizeString(currentState.contributionStatusMessage);
if (statusMessage) {
return statusMessage;
}
if (getContributionSource(currentState) === CONTRIBUTION_SOURCE_SUB2API) {
const groupName = normalizeString(currentState.contributionTargetGroupName) || CONTRIBUTION_SUB2API_DEFAULT_GROUP_NAME;
return `当前账号将用于支持项目维护。贡献会通过 SUB2API 完成,并固定写入 ${groupName} 分组;如检测到回调地址,扩展会自动提交并等待服务端确认。`;
}
return DEFAULT_COPY;
}
function getContributionPortalPageUrl() {
@@ -310,9 +336,10 @@
const enabled = isContributionModeEnabled(currentState);
const blocked = isModeSwitchBlocked();
const activeElement = typeof document !== 'undefined' ? document.activeElement : null;
const sourceLabel = getContributionSourceLabel(currentState);
if (enabled && dom.selectPanelMode) {
dom.selectPanelMode.value = 'cpa';
dom.selectPanelMode.value = getContributionSource(currentState);
}
helpers.updatePanelModeUI?.();
@@ -322,7 +349,13 @@
dom.contributionModePanel.hidden = !enabled;
}
if (dom.contributionModeText) {
dom.contributionModeText.textContent = DEFAULT_COPY;
dom.contributionModeText.textContent = getSummaryText({
contributionSource: currentState.contributionSource,
contributionTargetGroupName: currentState.contributionTargetGroupName,
});
}
if (dom.contributionModeBadge) {
dom.contributionModeBadge.textContent = enabled ? sourceLabel : '';
}
if (dom.inputContributionNickname && activeElement !== dom.inputContributionNickname) {
const nextNickname = normalizeString(currentState.contributionNickname);
+5 -5
View File
@@ -115,11 +115,11 @@
<option value="codex2api">Codex2API</option>
</select>
</div>
<div id="contribution-mode-panel" class="contribution-mode-panel" hidden>
<div class="contribution-mode-panel-header">
<span class="section-label">贡献模式</span>
<span class="contribution-mode-badge">CPA</span>
</div>
<div id="contribution-mode-panel" class="contribution-mode-panel" hidden>
<div class="contribution-mode-panel-header">
<span class="section-label">贡献模式</span>
<span id="contribution-mode-badge" class="contribution-mode-badge">CPA</span>
</div>
<p id="contribution-mode-text" class="contribution-mode-text">
当前账号将用于支持项目维护。扩展会自动申请贡献登录地址并持续跟踪授权状态;如检测到回调地址,会自动提交,无需手动复制。</p>
<div class="data-row contribution-mode-field">
+5 -1
View File
@@ -34,6 +34,7 @@ const updateReleaseList = document.getElementById('update-release-list');
const btnOpenRelease = document.getElementById('btn-open-release');
const settingsCard = document.getElementById('settings-card');
const contributionModePanel = document.getElementById('contribution-mode-panel');
const contributionModeBadge = document.getElementById('contribution-mode-badge');
const contributionModeText = document.getElementById('contribution-mode-text');
const inputContributionNickname = document.getElementById('input-contribution-nickname');
const inputContributionQq = document.getElementById('input-contribution-qq');
@@ -1733,7 +1734,9 @@ function collectSettingsPayload() {
label: typeof DEFAULT_HERO_SMS_COUNTRY_LABEL !== 'undefined' ? DEFAULT_HERO_SMS_COUNTRY_LABEL : 'Thailand',
};
return {
panelMode: selectPanelMode.value,
...(contributionModeEnabled ? {} : {
panelMode: selectPanelMode.value,
}),
vpsUrl: inputVpsUrl.value.trim(),
vpsPassword: inputVpsPassword.value,
localCpaStep9Mode: getSelectedLocalCpaStep9Mode(),
@@ -4070,6 +4073,7 @@ const contributionModeManager = window.SidepanelContributionMode?.createContribu
btnOpenAccountRecords,
btnOpenContributionUpload,
btnStartContribution,
contributionModeBadge,
contributionModePanel,
contributionModeSummary,
contributionModeText,
+145 -3
View File
@@ -84,14 +84,16 @@ test('contribution oauth module exposes a factory', () => {
assert.equal(Array.isArray(api?.RUNTIME_KEYS), true);
});
test('buildContributionModeState preserves active contribution runtime while forcing CPA mode', () => {
test('buildContributionModeState preserves active contribution runtime while keeping contribution on sub2api', () => {
const bundle = extractFunction(backgroundSource, 'buildContributionModeState');
const api = new Function(`
const api = new Function(`
const DEFAULT_STATE = { panelMode: 'cpa' };
const CONTRIBUTION_RUNTIME_DEFAULTS = {
contributionMode: false,
contributionModeExpected: false,
contributionSource: 'sub2api',
contributionTargetGroupName: 'codex号池',
contributionNickname: '',
contributionQq: '',
contributionSessionId: '',
@@ -107,6 +109,35 @@ const CONTRIBUTION_RUNTIME_DEFAULTS = {
contributionAuthTabId: 0,
};
const CONTRIBUTION_RUNTIME_KEYS = Object.keys(CONTRIBUTION_RUNTIME_DEFAULTS);
function isPlusModeState(state = {}) { return Boolean(state?.plusModeEnabled); }
function normalizeContributionModeSource(value = '') {
const normalized = String(value || '').trim().toLowerCase();
return normalized === 'sub2api' ? 'sub2api' : 'cpa';
}
function resolveContributionModeRoutingState(state = {}) {
const currentStatus = String(state?.contributionStatus || '').trim().toLowerCase();
const currentSource = normalizeContributionModeSource(state?.contributionSource);
const hasActiveSession = Boolean(
String(state?.contributionSessionId || '').trim()
&& currentStatus
&& !['auto_approved', 'auto_rejected', 'expired', 'error'].includes(currentStatus)
);
if (hasActiveSession) {
return {
source: currentSource,
targetGroupName: currentSource === 'sub2api'
? (String(state?.contributionTargetGroupName || '').trim() || 'codex号池')
: '',
};
}
const source = 'sub2api';
return {
source,
targetGroupName: isPlusModeState(state)
? 'openai-plus'
: (String(state?.contributionTargetGroupName || '').trim() || 'codex号池'),
};
}
${bundle}
return { buildContributionModeState };
`)();
@@ -125,6 +156,8 @@ return { buildContributionModeState };
{
contributionMode: true,
contributionModeExpected: true,
contributionSource: 'sub2api',
contributionTargetGroupName: 'codex号池',
contributionNickname: '',
contributionQq: '',
contributionSessionId: 'session-001',
@@ -138,7 +171,7 @@ return { buildContributionModeState };
contributionCallbackMessage: '',
contributionAuthOpenedAt: 0,
contributionAuthTabId: 0,
panelMode: 'cpa',
panelMode: 'sub2api',
customPassword: '',
accountRunHistoryTextEnabled: false,
}
@@ -157,6 +190,8 @@ return { buildContributionModeState };
{
contributionMode: false,
contributionModeExpected: false,
contributionSource: 'sub2api',
contributionTargetGroupName: 'codex号池',
contributionNickname: '',
contributionQq: '',
contributionSessionId: '',
@@ -175,6 +210,37 @@ return { buildContributionModeState };
accountRunHistoryTextEnabled: true,
}
);
assert.deepStrictEqual(
api.buildContributionModeState(true, {
panelMode: 'cpa',
plusModeEnabled: true,
customPassword: 'Secret123!',
accountRunHistoryTextEnabled: true,
}, {}),
{
contributionMode: true,
contributionModeExpected: true,
contributionSource: 'sub2api',
contributionTargetGroupName: 'openai-plus',
contributionNickname: '',
contributionQq: '',
contributionSessionId: '',
contributionAuthUrl: '',
contributionAuthState: '',
contributionCallbackUrl: '',
contributionStatus: '',
contributionStatusMessage: '',
contributionLastPollAt: 0,
contributionCallbackStatus: 'idle',
contributionCallbackMessage: '',
contributionAuthOpenedAt: 0,
contributionAuthTabId: 0,
panelMode: 'sub2api',
customPassword: '',
accountRunHistoryTextEnabled: false,
}
);
});
test('resetState preserves contribution runtime across reset', () => {
@@ -334,6 +400,8 @@ test('contribution oauth manager starts session, opens auth url, submits callbac
let statusPollCount = 0;
let currentState = {
contributionMode: true,
contributionSource: 'sub2api',
contributionTargetGroupName: 'codex号池',
email: 'user@example.com',
contributionSessionId: '',
contributionStatus: '',
@@ -424,6 +492,8 @@ test('contribution oauth manager starts session, opens auth url, submits callbac
assert.match(String(fetchCalls[0].options.body || ''), /"nickname":""/);
assert.match(String(fetchCalls[0].options.body || ''), /"qq":""/);
assert.match(String(fetchCalls[0].options.body || ''), /"email":"user@example\.com"/);
assert.match(String(fetchCalls[0].options.body || ''), /"source":"sub2api"/);
assert.match(String(fetchCalls[0].options.body || ''), /"target_group_name":"codex号池"/);
assert.match(fetchCalls[1].url, /\/status\?/);
const callbackState = await manager.handleCapturedCallback(
@@ -471,6 +541,78 @@ test('contribution oauth manager accepts localhost callback urls that contain er
);
});
test('contribution oauth manager switches Plus contribution traffic to sub2api openai-plus', async () => {
const source = fs.readFileSync('background/contribution-oauth.js', 'utf8');
const globalScope = {};
const fetchCalls = [];
let currentState = {
contributionMode: true,
plusModeEnabled: true,
contributionSource: 'sub2api',
contributionTargetGroupName: 'openai-plus',
contributionSessionId: '',
contributionStatus: '',
contributionCallbackStatus: 'idle',
};
const api = new Function('self', 'fetch', `${source}; return self.MultiPageBackgroundContributionOAuth;`)(
globalScope,
async (url, options = {}) => {
fetchCalls.push({ url, options });
if (String(url).endsWith('/start')) {
return createMockResponse(true, 200, {
ok: true,
session_id: 'session-plus-001',
state: 'oauth-state-plus-001',
source: 'sub2api',
target_group_name: 'openai-plus',
auth_url: 'https://auth.example.com/oauth?state=oauth-state-plus-001',
});
}
if (String(url).includes('/status?')) {
return createMockResponse(true, 200, {
ok: true,
session_id: 'session-plus-001',
status: 'waiting',
source: 'sub2api',
target_group_name: 'openai-plus',
});
}
return createMockResponse(true, 200, { ok: true });
}
);
const manager = api.createContributionOAuthManager({
chrome: {
tabs: {
async create(payload) {
return { id: 91, url: payload.url };
},
async update() {
return null;
},
onUpdated: { addListener() {} },
},
webNavigation: {
onCommitted: { addListener() {} },
onHistoryStateUpdated: { addListener() {} },
},
},
getState: async () => currentState,
setState: async (updates) => {
currentState = { ...currentState, ...updates };
},
broadcastDataUpdate: (updates) => {
currentState = { ...currentState, ...updates };
},
});
await manager.startContributionFlow();
assert.match(String(fetchCalls[0].options.body || ''), /"source":"sub2api"/);
assert.match(String(fetchCalls[0].options.body || ''), /"target_group_name":"openai-plus"/);
});
test('refreshOAuthUrlBeforeStep6 uses contribution oauth session instead of panel bridge in contribution mode', async () => {
const bundle = extractFunction(backgroundSource, 'refreshOAuthUrlBeforeStep6');
const calls = [];
+20 -5
View File
@@ -191,6 +191,7 @@ return {
`)();
const contributionPayload = api.collectSettingsPayload();
assert.equal('panelMode' in contributionPayload, false);
assert.equal('customPassword' in contributionPayload, false);
assert.equal('accountRunHistoryTextEnabled' in contributionPayload, false);
assert.equal('accountRunHistoryHelperBaseUrl' in contributionPayload, false);
@@ -199,6 +200,7 @@ return {
api.setLatestState({ contributionMode: false });
const normalPayload = api.collectSettingsPayload();
assert.equal(normalPayload.panelMode, 'cpa');
assert.equal(normalPayload.customPassword, 'Secret123!');
assert.equal(normalPayload.accountRunHistoryTextEnabled, true);
assert.equal(normalPayload.accountRunHistoryHelperBaseUrl, 'http://127.0.0.1:17373');
@@ -231,6 +233,8 @@ test('contribution mode manager enters mode, starts main auto flow, polls contri
let latestState = {
contributionMode: false,
panelMode: 'sub2api',
contributionSource: 'sub2api',
contributionTargetGroupName: 'codex号池',
contributionSessionId: '',
contributionStatus: '',
contributionStatusMessage: '',
@@ -258,6 +262,7 @@ test('contribution mode manager enters mode, starts main auto flow, polls contri
btnOpenAccountRecords: createElement(),
btnOpenContributionUpload: createElement(),
btnStartContribution: createElement(),
contributionModeBadge: createElement(),
inputContributionNickname: createElement({ value: '贡献者昵称' }),
inputContributionQq: createElement({ value: '123456' }),
contributionCallbackStatus: createElement(),
@@ -353,7 +358,9 @@ test('contribution mode manager enters mode, starts main auto flow, polls contri
state: message.payload.enabled
? {
contributionMode: true,
panelMode: 'cpa',
panelMode: 'sub2api',
contributionSource: 'sub2api',
contributionTargetGroupName: 'codex号池',
contributionNickname: '',
contributionQq: '',
contributionSessionId: '',
@@ -368,6 +375,8 @@ test('contribution mode manager enters mode, starts main auto flow, polls contri
: {
contributionMode: false,
panelMode: 'cpa',
contributionSource: 'cpa',
contributionTargetGroupName: '',
contributionNickname: '',
contributionQq: '',
contributionSessionId: '',
@@ -387,7 +396,7 @@ test('contribution mode manager enters mode, starts main auto flow, polls contri
state: {
...latestState,
contributionStatus: 'processing',
contributionStatusMessage: '已提交回调,等待 CPA 确认',
contributionStatusMessage: '已提交回调,等待服务端确认',
contributionCallbackStatus: 'submitted',
contributionCallbackMessage: '已提交回调',
},
@@ -414,13 +423,15 @@ test('contribution mode manager enters mode, starts main auto flow, polls contri
manager.render();
assert.equal(dom.contributionModePanel.hidden, true);
assert.equal(dom.btnContributionMode.disabled, false);
assert.equal(dom.contributionModeBadge.textContent, '');
manager.bindEvents();
await dom.btnContributionMode.listeners.click();
assert.equal(dom.contributionModePanel.hidden, false);
assert.equal(dom.selectPanelMode.value, 'cpa');
assert.equal(dom.selectPanelMode.value, 'sub2api');
assert.equal(dom.selectPanelMode.disabled, true);
assert.equal(dom.contributionModeBadge.textContent, 'SUB2API');
assert.equal(dom.btnOpenAccountRecords.disabled, true);
assert.equal(dom.contributionOauthStatus.textContent, '\u672a\u751f\u6210\u767b\u5f55\u5730\u5740');
assert.equal(dom.contributionCallbackStatus.textContent, '\u7b49\u5f85\u56de\u8c03');
@@ -453,7 +464,7 @@ test('contribution mode manager enters mode, starts main auto flow, polls contri
assert.equal(statusState.contributionStatus, 'processing');
assert.equal(dom.contributionOauthStatus.textContent, '\u5df2\u63d0\u4ea4\u56de\u8c03');
assert.equal(dom.contributionCallbackStatus.textContent, '\u5df2\u63d0\u4ea4\u56de\u8c03');
assert.equal(dom.contributionModeSummary.textContent, '\u5df2\u63d0\u4ea4\u56de\u8c03\uff0c\u7b49\u5f85 CPA \u786e\u8ba4');
assert.equal(dom.contributionModeSummary.textContent, '\u5df2\u63d0\u4ea4\u56de\u8c03\uff0c\u7b49\u5f85\u670d\u52a1\u7aef\u786e\u8ba4');
dom.btnOpenContributionUpload.listeners.click();
assert.deepStrictEqual(openedUrls, ['https://apikey.qzz.io', 'https://apikey.qzz.io/upload']);
@@ -476,7 +487,9 @@ test('contribution mode manager enters mode, starts main auto flow, polls contri
blocked = true;
latestState = {
contributionMode: true,
panelMode: 'cpa',
panelMode: 'sub2api',
contributionSource: 'sub2api',
contributionTargetGroupName: 'codex号池',
contributionNickname: '贡献者昵称',
contributionQq: '123456',
contributionSessionId: 'session-002',
@@ -487,6 +500,8 @@ test('contribution mode manager enters mode, starts main auto flow, polls contri
contributionCallbackMessage: '\u7b49\u5f85\u56de\u8c03',
};
manager.render();
assert.equal(dom.selectPanelMode.value, 'sub2api');
assert.equal(dom.contributionModeBadge.textContent, 'SUB2API');
assert.equal(dom.btnExitContributionMode.disabled, true);
manager.stopPolling();
});