修复手机号注册登录密码页与成功清理

This commit is contained in:
QLHazyCoder
2026-05-28 06:52:35 +08:00
parent 2992cc88ac
commit fae7b9bffd
9 changed files with 797 additions and 12 deletions
+73
View File
@@ -19,6 +19,7 @@
getAutoRunStatusPayload,
getErrorMessage,
getFirstUnfinishedNodeId,
getNodeIdsForState,
getPendingAutoRunTimerPlan,
getRunningNodeIds,
getState,
@@ -65,6 +66,77 @@
return false;
}
const EMPTY_REGISTRATION_EMAIL_STATE = Object.freeze({
current: '',
previous: '',
source: '',
updatedAt: 0,
});
const DONE_NODE_STATUSES = new Set(['completed', 'manual_completed', 'skipped']);
function isPhoneSignupFlow(state = {}) {
const resolvedSignupMethod = String(state?.resolvedSignupMethod || '').trim().toLowerCase();
if (resolvedSignupMethod === 'phone' || resolvedSignupMethod === 'email') {
return resolvedSignupMethod === 'phone';
}
const signupMethod = String(state?.signupMethod || '').trim().toLowerCase();
return signupMethod === 'phone';
}
function getFullWorkflowNodeIds(state = {}) {
if (typeof getNodeIdsForState === 'function') {
const nodeIds = getNodeIdsForState(state);
if (Array.isArray(nodeIds) && nodeIds.length) {
return Array.from(new Set(
nodeIds
.map((nodeId) => String(nodeId || '').trim())
.filter(Boolean)
));
}
}
return getKnownNodeIdsFromState(state);
}
function isFullWorkflowDone(state = {}) {
const nodeIds = getFullWorkflowNodeIds(state);
if (!nodeIds.length) {
return false;
}
const nodeStatuses = state?.nodeStatuses || {};
return nodeIds.every((nodeId) => DONE_NODE_STATUSES.has(String(nodeStatuses[nodeId] || 'pending').trim()));
}
async function clearPhoneSignupRuntimeAfterRoundSuccess() {
const currentState = await getState();
if (!isPhoneSignupFlow(currentState) || !isFullWorkflowDone(currentState)) {
return false;
}
await setState({
accountIdentifierType: null,
accountIdentifier: '',
currentPhoneActivation: null,
phoneNumber: '',
signupPhoneNumber: '',
signupPhoneActivation: null,
signupPhoneCompletedActivation: null,
signupPhoneVerificationRequestedAt: null,
signupPhoneVerificationPurpose: '',
currentPhoneVerificationCode: '',
currentPhoneVerificationCountdownEndsAt: 0,
currentPhoneVerificationCountdownWindowIndex: 0,
currentPhoneVerificationCountdownWindowTotal: 0,
email: null,
registrationEmailState: { ...EMPTY_REGISTRATION_EMAIL_STATE },
step8VerificationTargetEmail: '',
lastEmailTimestamp: null,
lastSignupCode: '',
lastLoginCode: '',
bindEmailSubmitted: false,
});
return true;
}
async function waitForRunningWorkflowNodesToFinish(payload = {}) {
if (typeof waitForRunningNodesToFinish === 'function') {
return waitForRunningNodesToFinish(payload);
@@ -698,6 +770,7 @@
attemptRuns: attemptRun,
continued: useExistingProgress,
});
await clearPhoneSignupRuntimeAfterRoundSuccess();
roundSummary.status = 'success';
roundSummary.finalFailureReason = '';
+120 -3
View File
@@ -523,6 +523,109 @@
|| status === 'skipped';
}
function isPhoneSignupStepPayload(payload = {}, state = {}) {
const payloadIdentifierType = String(payload?.accountIdentifierType || '').trim().toLowerCase();
if (payloadIdentifierType === 'email') {
return false;
}
const stateIdentifierType = String(state?.accountIdentifierType || '').trim().toLowerCase();
return payloadIdentifierType === 'phone'
|| Boolean(resolveSignupPhonePayload(payload))
|| stateIdentifierType === 'phone'
|| Boolean(String(state?.signupPhoneNumber || '').trim())
|| Boolean(state?.signupPhoneActivation)
|| Boolean(state?.signupPhoneCompletedActivation);
}
function isLoginPasswordPagePayload(payload = {}) {
const mode = String(payload?.passwordPageMode || '').trim().toLowerCase();
if (mode === 'login') {
return true;
}
const path = String(payload?.passwordPagePath || '').trim();
if (/\/log-in\/password(?:[/?#]|$)/i.test(path)) {
return true;
}
const rawUrl = String(payload?.passwordPageUrl || '').trim();
if (!rawUrl) {
return false;
}
try {
return /\/log-in\/password(?:[/?#]|$)/i.test(new URL(rawUrl).pathname || '');
} catch {
return /\/log-in\/password(?:[/?#]|$)/i.test(rawUrl);
}
}
function isSignupPasswordPagePayload(payload = {}) {
const mode = String(payload?.passwordPageMode || '').trim().toLowerCase();
if (mode === 'signup') {
return true;
}
const path = String(payload?.passwordPagePath || '').trim();
if (/\/(?:create-account|u\/signup|signup)\/password(?:[/?#]|$)/i.test(path)) {
return true;
}
const rawUrl = String(payload?.passwordPageUrl || '').trim();
if (!rawUrl) {
return false;
}
try {
return /\/(?:create-account|u\/signup|signup)\/password(?:[/?#]|$)/i.test(new URL(rawUrl).pathname || '');
} catch {
return /\/(?:create-account|u\/signup|signup)\/password(?:[/?#]|$)/i.test(rawUrl);
}
}
function shouldSkipPhoneSignupRegistrationTailAfterPassword(payload = {}, state = {}) {
if (!isPhoneSignupStepPayload(payload, state) || isSignupPasswordPagePayload(payload) || !isLoginPasswordPagePayload(payload)) {
return false;
}
const nextState = String(payload?.state || payload?.successState || '').trim().toLowerCase();
return Boolean(payload?.ready)
|| Boolean(payload?.alreadyVerified)
|| nextState === 'verification'
|| nextState === 'verification_page'
|| nextState === 'phone_verification_page'
|| nextState === 'oauth_consent_page'
|| nextState === 'logged_in_home';
}
async function skipPhoneSignupRegistrationTailAfterPassword(currentStep, payload = {}) {
const latestState = await getState();
const skippedSteps = [];
for (const stepKey of ['fetch-signup-code', 'fill-profile', 'wait-registration-success']) {
const skippedStep = findStepByKeyAfter(currentStep, stepKey, latestState);
if (!skippedStep) {
continue;
}
const status = getNodeStatusByStep(skippedStep, latestState);
if (isStepProtectedFromAutoSkip(status)) {
continue;
}
await setNodeStatusByStep(skippedStep, 'skipped', latestState);
skippedSteps.push(skippedStep);
}
await setState({ signupVerificationRequestedAt: null });
if (skippedSteps.length) {
await addLog(
`步骤 ${currentStep}:手机号密码提交后已确认账号进入登录后续状态,已自动跳过步骤 ${skippedSteps.join('/')},流程将直接进入 OAuth 后续节点。`,
'warn',
{ step: currentStep, stepKey: 'fill-password' }
);
}
payload.signupVerificationRequestedAt = null;
payload.passwordLoginFlow = true;
payload.skipRegistrationFlow = true;
return {
...payload,
signupVerificationRequestedAt: null,
passwordLoginFlow: true,
skipRegistrationFlow: true,
};
}
function findStepByKeyAfter(currentOrder, targetKey, state = {}) {
const activeStepIds = typeof getStepIdsForState === 'function'
? getStepIdsForState(state)
@@ -847,6 +950,13 @@
break;
case 3:
await syncStepAccountIdentityFromPayload(payload);
{
const latestState = await getState();
if (shouldSkipPhoneSignupRegistrationTailAfterPassword(payload, latestState)) {
await skipPhoneSignupRegistrationTailAfterPassword(step, payload);
break;
}
}
if (payload.signupVerificationRequestedAt) {
await setState({ signupVerificationRequestedAt: payload.signupVerificationRequestedAt });
}
@@ -967,9 +1077,16 @@
notifyNodeError(nodeId, '流程已被用户停止。');
return { ok: true };
}
let completionPayload = message.payload || {};
try {
if (nodeId === 'fill-password' && typeof finalizeStep3Completion === 'function') {
await finalizeStep3Completion(message.payload || {});
const finalizedPayload = await finalizeStep3Completion(message.payload || {});
if (finalizedPayload && typeof finalizedPayload === 'object') {
completionPayload = {
...completionPayload,
...finalizedPayload,
};
}
}
} catch (error) {
if (typeof isCloudflareSecurityBlockedError === 'function' && isCloudflareSecurityBlockedError(error)) {
@@ -1004,11 +1121,11 @@
stepKey: nodeId,
});
}
await handleStepData(resolvedStep, message.payload);
await handleStepData(resolvedStep, completionPayload);
if (isFinalNode && typeof appendAccountRunRecord === 'function') {
await appendAccountRunRecord('success', completionState);
}
notifyNodeComplete(nodeId, message.payload);
notifyNodeComplete(nodeId, completionPayload);
return { ok: true };
}