Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions background.js
Original file line number Diff line number Diff line change
Expand Up @@ -10934,6 +10934,72 @@ async function reportCompletedStepSideEffectError(step, error) {
return reportCompletedNodeSideEffectError(getNodeIdByStepForState(step, state), error);
}

function getSignupPhoneIdentityValue(state = {}) {
const accountIdentifierType = String(state?.accountIdentifierType || '').trim().toLowerCase();
return String(
state?.signupPhoneNumber
|| state?.signupPhoneCompletedActivation?.phoneNumber
|| state?.signupPhoneActivation?.phoneNumber
|| (accountIdentifierType === 'phone' ? state?.accountIdentifier : '')
|| ''
).trim();
}

function signupPhoneIdentityValuesMatch(left = '', right = '') {
const leftRaw = String(left || '').trim();
const rightRaw = String(right || '').trim();
if (!leftRaw || !rightRaw) {
return false;
}
if (leftRaw === rightRaw) {
return true;
}
const leftDigits = leftRaw.replace(/\D+/g, '');
const rightDigits = rightRaw.replace(/\D+/g, '');
return Boolean(leftDigits && rightDigits && leftDigits === rightDigits);
}

async function clearSignupPhoneIdentityAfterSuccessfulFlow(completionState = {}, options = {}) {
const completedPhone = getSignupPhoneIdentityValue(completionState);
const latestState = await getState();
const currentPhone = getSignupPhoneIdentityValue(latestState);
const currentIdentifierType = String(latestState?.accountIdentifierType || '').trim().toLowerCase();
const hasCurrentPhoneIdentity = Boolean(
currentPhone
|| latestState?.signupPhoneActivation
|| latestState?.signupPhoneCompletedActivation
|| currentIdentifierType === 'phone'
);

if (!hasCurrentPhoneIdentity) {
return { cleared: false, reason: 'empty' };
}

if (completedPhone && currentPhone && !signupPhoneIdentityValuesMatch(completedPhone, currentPhone)) {
return { cleared: false, reason: 'changed' };
}

const updates = {
phoneNumber: '',
signupPhoneNumber: '',
signupPhoneActivation: null,
signupPhoneCompletedActivation: null,
signupPhoneVerificationRequestedAt: null,
signupPhoneVerificationPurpose: '',
};
if (currentIdentifierType === 'phone') {
updates.accountIdentifierType = null;
updates.accountIdentifier = '';
}

await setState(updates);
broadcastDataUpdate(updates);
await addLog('手机号注册:流程成功后已清空本轮注册手机号,避免下一轮复用。', 'ok', {
nodeId: options?.nodeId || 'platform-verify',
});
return { cleared: true, phoneNumber: currentPhone || completedPhone };
}

async function runCompletedNodeSideEffects(nodeId, payload, completionState, lastNodeId) {
await handleNodeData(nodeId, payload);
if (nodeId === lastNodeId) {
Expand Down Expand Up @@ -10966,6 +11032,11 @@ async function completeNodeFromBackground(nodeId, payload = {}) {
await addLog('已完成', 'ok', { nodeId: normalizedNodeId });

if (normalizedNodeId === lastNodeId) {
if (typeof clearSignupPhoneIdentityAfterSuccessfulFlow === 'function') {
await clearSignupPhoneIdentityAfterSuccessfulFlow(latestState, {
nodeId: normalizedNodeId,
});
}
notifyNodeComplete(normalizedNodeId, payload);
void runCompletedNodeSideEffects(normalizedNodeId, payload, completionState, lastNodeId)
.catch((error) => reportCompletedNodeSideEffectError(normalizedNodeId, error));
Expand Down
45 changes: 40 additions & 5 deletions tests/background-step-completion.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,24 +51,32 @@ function extractFunction(name) {
return source.slice(start, end);
}

function createApi(events, lastNodeId = 'platform-verify') {
return new Function('events', 'lastNodeId', `
function createApi(events, lastNodeId = 'platform-verify', initialState = {}) {
return new Function('events', 'lastNodeId', 'initialState', `
let stopRequested = false;
const LOG_PREFIX = '[test]';
let currentState = { nodeStatuses: {}, accountContributionEnabled: true, ...initialState };
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
function getErrorMessage(error) {
return error?.message || String(error || '');
}
async function getState() {
events.push({ type: 'getState' });
return { nodeStatuses: {}, accountContributionEnabled: true };
return currentState;
}
function getLastNodeIdForState() {
return lastNodeId;
}
async function setNodeStatus(nodeId, status) {
events.push({ type: 'status', nodeId, status });
}
async function setState(updates) {
currentState = { ...currentState, ...updates };
events.push({ type: 'setState', updates });
}
function broadcastDataUpdate(updates) {
events.push({ type: 'broadcast', updates });
}
async function addLog(message, level, options = {}) {
events.push({ type: 'log', message, level, options });
}
Expand All @@ -89,11 +97,14 @@ async function handleNodeData(nodeId, payload) {
async function appendAndBroadcastAccountRunRecord(status, state) {
events.push({ type: 'record', status, state });
}
${extractFunction('getSignupPhoneIdentityValue')}
${extractFunction('signupPhoneIdentityValuesMatch')}
${extractFunction('clearSignupPhoneIdentityAfterSuccessfulFlow')}
${extractFunction('runCompletedNodeSideEffects')}
${extractFunction('reportCompletedNodeSideEffectError')}
${extractFunction('completeNodeFromBackground')}
return { completeNodeFromBackground };
`)(events, lastNodeId);
return { completeNodeFromBackground, getCurrentState: () => currentState };
`)(events, lastNodeId, initialState);
}

test('completeNodeFromBackground releases final node before slow post-completion side effects', async () => {
Expand Down Expand Up @@ -124,3 +135,27 @@ test('completeNodeFromBackground keeps non-final node data handling before compl
assert.equal(types.indexOf('handle-done') < types.indexOf('notify'), true);
assert.equal(types.includes('record'), false);
});

test('completeNodeFromBackground clears signup phone identity before releasing final node', async () => {
const events = [];
const api = createApi(events, 'platform-verify', {
accountIdentifierType: 'phone',
accountIdentifier: '+56979206303',
signupPhoneNumber: '+56979206303',
signupPhoneActivation: { activationId: 'active', phoneNumber: '+56979206303' },
signupPhoneCompletedActivation: { activationId: 'done', phoneNumber: '+56979206303' },
signupPhoneVerificationRequestedAt: 123,
signupPhoneVerificationPurpose: 'login',
});

await api.completeNodeFromBackground('platform-verify', { localhostUrl: 'http://localhost:1455/auth/callback?code=ok' });

const types = events.map((event) => event.type);
assert.equal(types.indexOf('setState') < types.indexOf('notify'), true);
assert.equal(types.indexOf('broadcast') < types.indexOf('notify'), true);
assert.equal(api.getCurrentState().signupPhoneNumber, '');
assert.equal(api.getCurrentState().signupPhoneActivation, null);
assert.equal(api.getCurrentState().signupPhoneCompletedActivation, null);
assert.equal(api.getCurrentState().accountIdentifierType, null);
assert.equal(api.getCurrentState().accountIdentifier, '');
});