Refactor workflow auto-run to node graph
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
chrome,
|
||||
cleanupStep8NavigationListeners,
|
||||
clickWithDebugger,
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
ensureStep8SignupPageReady,
|
||||
getOAuthFlowRemainingMs,
|
||||
getOAuthFlowStepTimeoutMs,
|
||||
@@ -122,7 +122,7 @@
|
||||
cleanupListener();
|
||||
|
||||
addStepLog(visibleStep, `已捕获 localhost 地址:${callbackUrl}`, 'ok').then(() => {
|
||||
return completeStepFromBackground(visibleStep, { localhostUrl: callbackUrl });
|
||||
return completeNodeFromBackground(state?.nodeId || 'confirm-oauth', { localhostUrl: callbackUrl });
|
||||
}).then(() => {
|
||||
resolve();
|
||||
}).catch((err) => {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
const {
|
||||
addLog: rawAddLog = async () => {},
|
||||
chrome,
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
createAutomationTab = null,
|
||||
ensureContentScriptReadyOnTabUntilStopped,
|
||||
fetch: fetchImpl = null,
|
||||
@@ -457,7 +457,7 @@
|
||||
gopayHelperOrderCreatedAt: result.orderCreatedAt || Date.now(),
|
||||
});
|
||||
await addLog(`步骤 6:GPC ${result.phoneMode === GPC_HELPER_PHONE_MODE_AUTO ? '自动' : '手动'}模式任务已创建(task_id: ${result.taskId}),准备继续下一步。`, 'info');
|
||||
await completeStepFromBackground(6, {
|
||||
await completeNodeFromBackground('plus-checkout-create', {
|
||||
plusCheckoutCountry: result.country || 'ID',
|
||||
plusCheckoutCurrency: result.currency || 'IDR',
|
||||
plusCheckoutSource: result.checkoutSource,
|
||||
@@ -517,7 +517,7 @@
|
||||
|
||||
await addLog(`步骤 6:Plus Checkout 页面已就绪(${paymentMethodLabel} / ${result.country || 'DE'} ${result.currency || 'EUR'}),准备继续下一步。`, 'info');
|
||||
|
||||
await completeStepFromBackground(6, {
|
||||
await completeNodeFromBackground('plus-checkout-create', {
|
||||
plusCheckoutCountry: result.country || 'DE',
|
||||
plusCheckoutCurrency: result.currency || 'EUR',
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
chrome,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER = 'cloudmail',
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
confirmCustomVerificationStepBypass,
|
||||
ensureMail2925MailboxSession,
|
||||
ensureIcloudMailSession,
|
||||
@@ -225,8 +225,8 @@
|
||||
`步骤 ${visibleStep}:当前认证页已进入 OAuth 授权页${fromRecovery ? '(轮询失败后复核)' : ''},跳过登录验证码拉取并继续后续流程。`,
|
||||
'warn'
|
||||
);
|
||||
if (typeof completeStepFromBackground === 'function') {
|
||||
await completeStepFromBackground(visibleStep, {
|
||||
if (typeof completeNodeFromBackground === 'function') {
|
||||
await completeNodeFromBackground(options.nodeId || 'fetch-login-code', {
|
||||
loginVerificationRequestedAt: null,
|
||||
skipLoginVerificationStep: true,
|
||||
directOAuthConsentPage: true,
|
||||
@@ -316,7 +316,7 @@
|
||||
),
|
||||
});
|
||||
if (pageState?.state === 'oauth_consent_page') {
|
||||
await completeStep8WhenAuthAlreadyOnOauthConsent(visibleStep, { fromRecovery: true });
|
||||
await completeStep8WhenAuthAlreadyOnOauthConsent(visibleStep, { fromRecovery: true, nodeId: currentState?.nodeId });
|
||||
return { outcome: 'completed' };
|
||||
}
|
||||
if (pageState?.state === 'verification_page' || pageState?.state === 'phone_verification_page' || pageState?.state === 'add_email_page') {
|
||||
@@ -401,7 +401,7 @@
|
||||
visibleStep,
|
||||
});
|
||||
|
||||
await completeStepFromBackground(visibleStep, {
|
||||
await completeNodeFromBackground(state?.nodeId || 'fetch-login-code', {
|
||||
phoneVerification: true,
|
||||
loginPhoneVerification: true,
|
||||
code: result?.code || '',
|
||||
@@ -438,7 +438,7 @@
|
||||
timeoutMs: await getStep8ReadyTimeoutMs('确认登录验证码页已就绪', state?.oauthUrl || '', visibleStep),
|
||||
});
|
||||
if (pageState?.state === 'oauth_consent_page') {
|
||||
await completeStep8WhenAuthAlreadyOnOauthConsent(visibleStep);
|
||||
await completeStep8WhenAuthAlreadyOnOauthConsent(visibleStep, { nodeId: state?.nodeId });
|
||||
return;
|
||||
}
|
||||
if (pageState?.state === 'phone_verification_page') {
|
||||
@@ -450,7 +450,7 @@
|
||||
preparedState = addEmailPreparation?.state || preparedState;
|
||||
pageState = addEmailPreparation?.pageState || pageState;
|
||||
if (pageState?.state === 'oauth_consent_page') {
|
||||
await completeStep8WhenAuthAlreadyOnOauthConsent(visibleStep);
|
||||
await completeStep8WhenAuthAlreadyOnOauthConsent(visibleStep, { nodeId: preparedState?.nodeId || state?.nodeId });
|
||||
return;
|
||||
}
|
||||
if (pageState?.state === 'phone_verification_page') {
|
||||
@@ -576,7 +576,7 @@
|
||||
let stickyLastResendAt = Number(state?.loginVerificationRequestedAt) || 0;
|
||||
let retryWithoutStep7Streak = 0;
|
||||
const maxRetryWithoutStep7Streak = 3;
|
||||
let currentStepRecoveryAttempt = 0;
|
||||
let currentNodeRecoveryAttempt = 0;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
@@ -601,8 +601,8 @@
|
||||
let retryWithoutStep7 = false;
|
||||
|
||||
if (isStep8EmailInUseError(currentError) || isStep8MaxCheckAttemptsError(currentError)) {
|
||||
currentStepRecoveryAttempt += 1;
|
||||
if (currentStepRecoveryAttempt > STEP8_CURRENT_STEP_RECOVERY_MAX_ATTEMPTS) {
|
||||
currentNodeRecoveryAttempt += 1;
|
||||
if (currentNodeRecoveryAttempt > STEP8_CURRENT_STEP_RECOVERY_MAX_ATTEMPTS) {
|
||||
throw currentError;
|
||||
}
|
||||
if (isStep8EmailInUseError(currentError)) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
const {
|
||||
addLog,
|
||||
chrome,
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
confirmCustomVerificationStepBypass,
|
||||
generateRandomBirthday,
|
||||
generateRandomName,
|
||||
@@ -83,7 +83,7 @@
|
||||
return result || {};
|
||||
}
|
||||
|
||||
await completeStepFromBackground(4, {
|
||||
await completeNodeFromBackground('fetch-signup-code', {
|
||||
phoneVerification: true,
|
||||
code: result?.code || '',
|
||||
...(result?.skipProfileStep ? { skipProfileStep: true } : {}),
|
||||
@@ -280,7 +280,7 @@
|
||||
throw new Error(prepareResult.error);
|
||||
}
|
||||
if (prepareResult?.alreadyVerified) {
|
||||
await completeStepFromBackground(4, prepareResult?.skipProfileStep ? { skipProfileStep: true } : {});
|
||||
await completeNodeFromBackground('fetch-signup-code', prepareResult?.skipProfileStep ? { skipProfileStep: true } : {});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,8 @@
|
||||
`步骤 3:正在填写密码,${identityLabel},密码为${state.customPassword ? '自定义' : '自动生成'}(${password.length} 位)`
|
||||
);
|
||||
await sendToContentScript('signup-page', {
|
||||
type: 'EXECUTE_STEP',
|
||||
type: 'EXECUTE_NODE',
|
||||
nodeId: 'fill-password',
|
||||
step: 3,
|
||||
source: 'background',
|
||||
payload: {
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
addLog: rawAddLog = async () => {},
|
||||
broadcastDataUpdate,
|
||||
chrome,
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
ensureContentScriptReadyOnTabUntilStopped,
|
||||
fetch: fetchImpl = null,
|
||||
generateRandomName,
|
||||
@@ -1018,7 +1018,7 @@
|
||||
plusCheckoutSource: PLUS_PAYMENT_METHOD_GPC_HELPER,
|
||||
});
|
||||
await addLog('步骤 7:GPC 任务已完成,准备继续下一步。', 'ok');
|
||||
await completeStepFromBackground(7, {
|
||||
await completeNodeFromBackground('plus-checkout-billing', {
|
||||
plusCheckoutSource: PLUS_PAYMENT_METHOD_GPC_HELPER,
|
||||
});
|
||||
return;
|
||||
@@ -1920,7 +1920,7 @@
|
||||
throw new Error(`步骤 7:多次提交账单地址后仍未跳转到 ${paymentConfig.label}。${lastSubmitError}`);
|
||||
}
|
||||
|
||||
await completeStepFromBackground(7, {
|
||||
await completeNodeFromBackground('plus-checkout-billing', {
|
||||
plusBillingCountryText: result?.countryText || '',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,10 +16,17 @@
|
||||
await addLog(`步骤 5:已生成姓名 ${firstName} ${lastName},生日 ${year}-${month}-${day}`);
|
||||
|
||||
await sendToContentScript('signup-page', {
|
||||
type: 'EXECUTE_STEP',
|
||||
type: 'EXECUTE_NODE',
|
||||
nodeId: 'fill-profile',
|
||||
step: 5,
|
||||
source: 'background',
|
||||
payload: { firstName, lastName, year, month, day },
|
||||
payload: {
|
||||
firstName,
|
||||
lastName,
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
const {
|
||||
addLog,
|
||||
chrome,
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
ensureContentScriptReadyOnTabUntilStopped,
|
||||
getTabId,
|
||||
isTabAlive,
|
||||
@@ -1433,7 +1433,7 @@
|
||||
}
|
||||
|
||||
await setState({ plusGoPayApprovedAt: Date.now() });
|
||||
await completeStepFromBackground(8, {
|
||||
await completeNodeFromBackground('paypal-approve', {
|
||||
plusGoPayApprovedAt: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
function createStep7Executor(deps = {}) {
|
||||
const {
|
||||
addLog,
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
getErrorMessage,
|
||||
getLoginAuthStateLabel,
|
||||
getOAuthFlowStepTimeoutMs,
|
||||
@@ -131,7 +131,7 @@
|
||||
step: completionStep,
|
||||
visibleStep: completionStep,
|
||||
});
|
||||
await completeStepFromBackground(completionStep, {
|
||||
await completeNodeFromBackground(state?.nodeId || 'oauth-login', {
|
||||
loginVerificationRequestedAt: null,
|
||||
skipLoginVerificationStep: true,
|
||||
directOAuthConsentPage: true,
|
||||
@@ -225,7 +225,8 @@
|
||||
const result = await sendToContentScriptResilient(
|
||||
'signup-page',
|
||||
{
|
||||
type: 'EXECUTE_STEP',
|
||||
type: 'EXECUTE_NODE',
|
||||
nodeId: 'oauth-login',
|
||||
step: 7,
|
||||
source: 'background',
|
||||
payload: {
|
||||
@@ -277,7 +278,7 @@
|
||||
completionPayload.directOAuthConsentPage = Boolean(result.directOAuthConsentPage);
|
||||
}
|
||||
|
||||
await completeStepFromBackground(completionStep, completionPayload);
|
||||
await completeNodeFromBackground(state?.nodeId || 'oauth-login', completionPayload);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
const {
|
||||
addLog,
|
||||
chrome: chromeApi = globalThis.chrome,
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
openSignupEntryTab,
|
||||
} = deps;
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
await clearOpenAiCookiesBeforeStep1();
|
||||
await addLog('步骤 1:正在打开 ChatGPT 官网...');
|
||||
await openSignupEntryTab(1);
|
||||
await completeStepFromBackground(1, {});
|
||||
await completeNodeFromBackground('open-chatgpt', {});
|
||||
}
|
||||
|
||||
return { executeStep1 };
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
const {
|
||||
addLog,
|
||||
chrome,
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
ensureContentScriptReadyOnTabUntilStopped,
|
||||
getTabId,
|
||||
isTabAlive,
|
||||
@@ -294,7 +294,7 @@
|
||||
await sleepWithStop(500);
|
||||
}
|
||||
|
||||
await completeStepFromBackground(8, {
|
||||
await completeNodeFromBackground('paypal-approve', {
|
||||
plusPaypalApprovedAt: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
addLog,
|
||||
chrome,
|
||||
closeConflictingTabsForSource,
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
ensureContentScriptReadyOnTab,
|
||||
getPanelMode,
|
||||
getTabId,
|
||||
@@ -253,7 +253,7 @@
|
||||
|
||||
if (shouldBypassStep9ForLocalCpa(state)) {
|
||||
await addStepLog(platformVerifyStep, '检测到本地 CPA,且当前策略为“跳过平台回调验证”,本轮不再重复提交回调地址。', 'info');
|
||||
await completeStepFromBackground(platformVerifyStep, {
|
||||
await completeNodeFromBackground(state?.nodeId || 'platform-verify', {
|
||||
localhostUrl: state.localhostUrl,
|
||||
verifiedStatus: 'local-auto',
|
||||
});
|
||||
@@ -286,7 +286,7 @@
|
||||
|| normalizeString(result?.status_message)
|
||||
|| 'CPA 已通过接口提交回调';
|
||||
await addStepLog(platformVerifyStep, verifiedStatus, 'ok');
|
||||
await completeStepFromBackground(platformVerifyStep, {
|
||||
await completeNodeFromBackground(state?.nodeId || 'platform-verify', {
|
||||
localhostUrl: callback.url,
|
||||
verifiedStatus,
|
||||
});
|
||||
@@ -336,7 +336,7 @@
|
||||
|
||||
const verifiedStatus = normalizeString(result?.message) || 'Codex2API OAuth 账号添加成功';
|
||||
await addStepLog(platformVerifyStep, verifiedStatus, 'ok');
|
||||
await completeStepFromBackground(platformVerifyStep, {
|
||||
await completeNodeFromBackground(state?.nodeId || 'platform-verify', {
|
||||
localhostUrl: callback.url,
|
||||
verifiedStatus,
|
||||
});
|
||||
@@ -381,7 +381,7 @@
|
||||
logOptions: { step: visibleStep, stepKey: 'platform-verify' },
|
||||
timeoutMs: SUB2API_STEP9_RESPONSE_TIMEOUT_MS,
|
||||
});
|
||||
await completeStepFromBackground(platformVerifyStep, result);
|
||||
await completeNodeFromBackground(state?.nodeId || 'platform-verify', result);
|
||||
return;
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
function createPlusReturnConfirmExecutor(deps = {}) {
|
||||
const {
|
||||
addLog,
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
getTabId,
|
||||
isTabAlive,
|
||||
setState,
|
||||
@@ -53,7 +53,7 @@
|
||||
plusCheckoutTabId: tabId,
|
||||
plusReturnUrl: tab?.url || '',
|
||||
});
|
||||
await completeStepFromBackground(9, {
|
||||
await completeNodeFromBackground('plus-checkout-return', {
|
||||
plusReturnUrl: tab?.url || '',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,48 +1,49 @@
|
||||
(function attachBackgroundStepRegistry(root, factory) {
|
||||
root.MultiPageBackgroundStepRegistry = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundStepRegistryModule() {
|
||||
function createStepRegistry(definitions = []) {
|
||||
function createNodeRegistry(definitions = []) {
|
||||
const ordered = (Array.isArray(definitions) ? definitions : [])
|
||||
.map((definition) => ({
|
||||
id: Number(definition?.id),
|
||||
order: Number(definition?.order),
|
||||
key: String(definition?.key || '').trim(),
|
||||
nodeId: String(definition?.nodeId || definition?.key || '').trim(),
|
||||
displayOrder: Number(definition?.displayOrder ?? definition?.order),
|
||||
executeKey: String(definition?.executeKey || definition?.key || definition?.nodeId || '').trim(),
|
||||
title: String(definition?.title || '').trim(),
|
||||
execute: definition?.execute,
|
||||
}))
|
||||
.filter((definition) => Number.isFinite(definition.id) && typeof definition.execute === 'function')
|
||||
.filter((definition) => definition.nodeId && typeof definition.execute === 'function')
|
||||
.sort((left, right) => {
|
||||
const leftOrder = Number.isFinite(left.order) ? left.order : left.id;
|
||||
const rightOrder = Number.isFinite(right.order) ? right.order : right.id;
|
||||
return leftOrder - rightOrder;
|
||||
const leftOrder = Number.isFinite(left.displayOrder) ? left.displayOrder : 0;
|
||||
const rightOrder = Number.isFinite(right.displayOrder) ? right.displayOrder : 0;
|
||||
if (leftOrder !== rightOrder) return leftOrder - rightOrder;
|
||||
return left.nodeId.localeCompare(right.nodeId);
|
||||
});
|
||||
|
||||
const byId = new Map(ordered.map((definition) => [definition.id, definition]));
|
||||
const byId = new Map(ordered.map((definition) => [definition.nodeId, definition]));
|
||||
|
||||
function getStepDefinition(step) {
|
||||
return byId.get(Number(step)) || null;
|
||||
function getNodeDefinition(nodeId) {
|
||||
return byId.get(String(nodeId || '').trim()) || null;
|
||||
}
|
||||
|
||||
function getOrderedSteps() {
|
||||
function getOrderedNodes() {
|
||||
return ordered.slice();
|
||||
}
|
||||
|
||||
function executeStep(step, state) {
|
||||
const definition = getStepDefinition(step);
|
||||
function executeNode(nodeId, state) {
|
||||
const definition = getNodeDefinition(nodeId);
|
||||
if (!definition) {
|
||||
throw new Error(`未知步骤:${step}`);
|
||||
throw new Error(`未知节点:${nodeId}`);
|
||||
}
|
||||
return definition.execute(state);
|
||||
}
|
||||
|
||||
return {
|
||||
executeStep,
|
||||
getOrderedSteps,
|
||||
getStepDefinition,
|
||||
executeNode,
|
||||
getNodeDefinition,
|
||||
getOrderedNodes,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
createStepRegistry,
|
||||
createNodeRegistry,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
const {
|
||||
addLog,
|
||||
chrome,
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
ensureContentScriptReadyOnTab,
|
||||
ensureSignupAuthEntryPageReady,
|
||||
ensureSignupEntryPageReady,
|
||||
@@ -152,7 +152,8 @@
|
||||
|
||||
try {
|
||||
return await sendToContentScriptResilient('signup-page', {
|
||||
type: 'EXECUTE_STEP',
|
||||
type: 'EXECUTE_NODE',
|
||||
nodeId: 'submit-signup-email',
|
||||
step: 2,
|
||||
source: 'background',
|
||||
payload,
|
||||
@@ -391,7 +392,7 @@
|
||||
skipUrlWait: Boolean(step2Result?.alreadyOnPasswordPage),
|
||||
});
|
||||
|
||||
await completeStepFromBackground(2, {
|
||||
await completeNodeFromBackground('submit-signup-email', {
|
||||
accountIdentifierType: 'phone',
|
||||
accountIdentifier: phoneNumber,
|
||||
signupPhoneNumber: phoneNumber,
|
||||
@@ -484,7 +485,7 @@
|
||||
skipUrlWait: Boolean(step2Result?.alreadyOnPasswordPage),
|
||||
});
|
||||
|
||||
await completeStepFromBackground(2, {
|
||||
await completeNodeFromBackground('submit-signup-email', {
|
||||
email: resolvedEmail,
|
||||
accountIdentifierType: 'email',
|
||||
accountIdentifier: resolvedEmail,
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
const {
|
||||
addLog = async () => {},
|
||||
chrome: chromeApi = globalThis.chrome,
|
||||
completeStepFromBackground,
|
||||
completeNodeFromBackground,
|
||||
getErrorMessage = (error) => error?.message || String(error || '未知错误'),
|
||||
registrationSuccessWaitMs = DEFAULT_REGISTRATION_SUCCESS_WAIT_MS,
|
||||
sleepWithStop = async (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, Number(ms) || 0))),
|
||||
@@ -149,7 +149,7 @@
|
||||
}
|
||||
await clearCookiesIfEnabled(state);
|
||||
await addLog('步骤 6:注册成功等待完成,准备继续获取 OAuth 链接并登录。', 'ok');
|
||||
await completeStepFromBackground(6);
|
||||
await completeNodeFromBackground('wait-registration-success');
|
||||
}
|
||||
|
||||
return { executeStep6 };
|
||||
|
||||
Reference in New Issue
Block a user