refactor shared flow settings and runtime cleanup
This commit is contained in:
+5
-231
@@ -638,14 +638,11 @@ const IP_PROXY_TARGET_HOST_PATTERNS = [
|
|||||||
];
|
];
|
||||||
const AUTO_RUN_TIMER_ALARM_NAME = 'auto-run-timer';
|
const AUTO_RUN_TIMER_ALARM_NAME = 'auto-run-timer';
|
||||||
const IP_PROXY_AUTO_SYNC_ALARM_NAME = 'ip-proxy-auto-sync';
|
const IP_PROXY_AUTO_SYNC_ALARM_NAME = 'ip-proxy-auto-sync';
|
||||||
const AUTO_RUN_TIMER_KIND_SCHEDULED_START = 'scheduled_start';
|
|
||||||
const AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS = 'between_rounds';
|
const AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS = 'between_rounds';
|
||||||
const AUTO_RUN_TIMER_KIND_BEFORE_RETRY = 'before_retry';
|
const AUTO_RUN_TIMER_KIND_BEFORE_RETRY = 'before_retry';
|
||||||
const IP_PROXY_AUTO_SYNC_INTERVAL_MIN_MINUTES = 1;
|
const IP_PROXY_AUTO_SYNC_INTERVAL_MIN_MINUTES = 1;
|
||||||
const IP_PROXY_AUTO_SYNC_INTERVAL_MAX_MINUTES = 1440;
|
const IP_PROXY_AUTO_SYNC_INTERVAL_MAX_MINUTES = 1440;
|
||||||
const IP_PROXY_AUTO_SYNC_DEFAULT_INTERVAL_MINUTES = 15;
|
const IP_PROXY_AUTO_SYNC_DEFAULT_INTERVAL_MINUTES = 15;
|
||||||
const AUTO_RUN_DELAY_MIN_MINUTES = 1;
|
|
||||||
const AUTO_RUN_DELAY_MAX_MINUTES = 1440;
|
|
||||||
const AUTO_RUN_RETRY_DELAY_MS = 3000;
|
const AUTO_RUN_RETRY_DELAY_MS = 3000;
|
||||||
const AUTO_RUN_MAX_RETRIES_PER_ROUND = 3;
|
const AUTO_RUN_MAX_RETRIES_PER_ROUND = 3;
|
||||||
const AUTO_STEP_DELAY_MIN_ALLOWED_SECONDS = 0;
|
const AUTO_STEP_DELAY_MIN_ALLOWED_SECONDS = 0;
|
||||||
@@ -1354,9 +1351,7 @@ const PERSISTED_SETTING_DEFAULTS = {
|
|||||||
autoRunSkipFailures: false,
|
autoRunSkipFailures: false,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
oauthFlowTimeoutEnabled: true,
|
oauthFlowTimeoutEnabled: true,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
operationDelayEnabled: true,
|
operationDelayEnabled: true,
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
step6CookieCleanupEnabled: false,
|
step6CookieCleanupEnabled: false,
|
||||||
stepExecutionRangeByFlow: {},
|
stepExecutionRangeByFlow: {},
|
||||||
@@ -1530,7 +1525,6 @@ const DEFAULT_STATE = {
|
|||||||
autoRunAttemptRun: 0, // 当前轮次的重试序号。
|
autoRunAttemptRun: 0, // 当前轮次的重试序号。
|
||||||
autoRunSessionId: 0,
|
autoRunSessionId: 0,
|
||||||
autoRunRoundSummaries: [], // 自动运行轮次摘要。
|
autoRunRoundSummaries: [], // 自动运行轮次摘要。
|
||||||
scheduledAutoRunAt: null, // 自动运行计划启动时间戳。
|
|
||||||
autoRunTimerPlan: null, // 自动运行可恢复计时计划快照。
|
autoRunTimerPlan: null, // 自动运行可恢复计时计划快照。
|
||||||
autoRunCountdownAt: null,
|
autoRunCountdownAt: null,
|
||||||
autoRunCountdownTitle: '',
|
autoRunCountdownTitle: '',
|
||||||
@@ -1560,17 +1554,6 @@ const DEFAULT_STATE = {
|
|||||||
ipProxyAppliedExitSource: '',
|
ipProxyAppliedExitSource: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
function normalizeAutoRunDelayMinutes(value) {
|
|
||||||
const numeric = Number(value);
|
|
||||||
if (!Number.isFinite(numeric)) {
|
|
||||||
return PERSISTED_SETTING_DEFAULTS.autoRunDelayMinutes;
|
|
||||||
}
|
|
||||||
return Math.min(
|
|
||||||
AUTO_RUN_DELAY_MAX_MINUTES,
|
|
||||||
Math.max(AUTO_RUN_DELAY_MIN_MINUTES, Math.floor(numeric))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeAutoRunFallbackThreadIntervalMinutes(value) {
|
function normalizeAutoRunFallbackThreadIntervalMinutes(value) {
|
||||||
const rawValue = String(value ?? '').trim();
|
const rawValue = String(value ?? '').trim();
|
||||||
if (!rawValue) {
|
if (!rawValue) {
|
||||||
@@ -1583,7 +1566,7 @@ function normalizeAutoRunFallbackThreadIntervalMinutes(value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Math.min(
|
return Math.min(
|
||||||
AUTO_RUN_DELAY_MAX_MINUTES,
|
1440,
|
||||||
Math.max(0, Math.floor(numeric))
|
Math.max(0, Math.floor(numeric))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2009,7 +1992,6 @@ function isPhoneSignupIdentityStateForReuse(state = {}) {
|
|||||||
const runtimeActive = (
|
const runtimeActive = (
|
||||||
(typeof isAutoRunLockedState === 'function' && isAutoRunLockedState(state))
|
(typeof isAutoRunLockedState === 'function' && isAutoRunLockedState(state))
|
||||||
|| (typeof isAutoRunPausedState === 'function' && isAutoRunPausedState(state))
|
|| (typeof isAutoRunPausedState === 'function' && isAutoRunPausedState(state))
|
||||||
|| (typeof isAutoRunScheduledState === 'function' && isAutoRunScheduledState(state))
|
|
||||||
|| Boolean(state?.autoRunning)
|
|| Boolean(state?.autoRunning)
|
||||||
);
|
);
|
||||||
if (!runtimeActive) {
|
if (!runtimeActive) {
|
||||||
@@ -2311,9 +2293,6 @@ function normalizeRunCount(value) {
|
|||||||
|
|
||||||
function normalizeAutoRunTimerKind(value = '') {
|
function normalizeAutoRunTimerKind(value = '') {
|
||||||
const normalized = String(value || '').trim().toLowerCase();
|
const normalized = String(value || '').trim().toLowerCase();
|
||||||
if (normalized === AUTO_RUN_TIMER_KIND_SCHEDULED_START) {
|
|
||||||
return AUTO_RUN_TIMER_KIND_SCHEDULED_START;
|
|
||||||
}
|
|
||||||
if (normalized === AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS) {
|
if (normalized === AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS) {
|
||||||
return AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS;
|
return AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS;
|
||||||
}
|
}
|
||||||
@@ -2393,22 +2372,6 @@ function normalizeAutoRunTimerPlan(plan) {
|
|||||||
const countdownTitle = String(plan.countdownTitle || '').trim();
|
const countdownTitle = String(plan.countdownTitle || '').trim();
|
||||||
const countdownNote = String(plan.countdownNote || '').trim();
|
const countdownNote = String(plan.countdownNote || '').trim();
|
||||||
|
|
||||||
if (kind === AUTO_RUN_TIMER_KIND_SCHEDULED_START) {
|
|
||||||
return {
|
|
||||||
kind,
|
|
||||||
fireAt,
|
|
||||||
totalRuns,
|
|
||||||
autoRunSkipFailures,
|
|
||||||
mode,
|
|
||||||
currentRun: 0,
|
|
||||||
attemptRun: 0,
|
|
||||||
autoRunSessionId,
|
|
||||||
roundSummaries: [],
|
|
||||||
countdownTitle: countdownTitle || '已计划自动运行',
|
|
||||||
countdownNote: countdownNote || `计划于 ${formatAutoRunScheduleTime(fireAt)} 开始`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kind === AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS) {
|
if (kind === AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS) {
|
||||||
const normalizedCurrentRun = Math.max(1, Math.min(totalRuns, currentRun));
|
const normalizedCurrentRun = Math.max(1, Math.min(totalRuns, currentRun));
|
||||||
const normalizedAttemptRun = Math.max(1, attemptRun);
|
const normalizedAttemptRun = Math.max(1, attemptRun);
|
||||||
@@ -2449,28 +2412,11 @@ function normalizeAutoRunTimerPlanFromState(state = {}) {
|
|||||||
if (directPlan) {
|
if (directPlan) {
|
||||||
return directPlan;
|
return directPlan;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
if (state.autoRunPhase !== 'scheduled') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const legacyScheduledAt = Number(state.scheduledAutoRunAt);
|
|
||||||
if (!Number.isFinite(legacyScheduledAt)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalizeAutoRunTimerPlan({
|
|
||||||
kind: AUTO_RUN_TIMER_KIND_SCHEDULED_START,
|
|
||||||
fireAt: legacyScheduledAt,
|
|
||||||
totalRuns: state.scheduledAutoRunPlan?.totalRuns ?? state.autoRunTotalRuns,
|
|
||||||
autoRunSkipFailures: state.scheduledAutoRunPlan?.autoRunSkipFailures ?? state.autoRunSkipFailures,
|
|
||||||
autoRunSessionId: state.autoRunSessionId,
|
|
||||||
mode: state.scheduledAutoRunPlan?.mode,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAutoRunTimerPlanPhase(kind = '') {
|
function getAutoRunTimerPlanPhase(kind = '') {
|
||||||
return kind === AUTO_RUN_TIMER_KIND_SCHEDULED_START ? 'scheduled' : 'waiting_interval';
|
return 'waiting_interval';
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAutoRunTimerStatusPayload(plan) {
|
function getAutoRunTimerStatusPayload(plan) {
|
||||||
@@ -2486,7 +2432,6 @@ function getAutoRunTimerStatusPayload(plan) {
|
|||||||
totalRuns: normalizedPlan.totalRuns,
|
totalRuns: normalizedPlan.totalRuns,
|
||||||
attemptRun: normalizedPlan.attemptRun,
|
attemptRun: normalizedPlan.attemptRun,
|
||||||
sessionId: normalizedPlan.autoRunSessionId,
|
sessionId: normalizedPlan.autoRunSessionId,
|
||||||
scheduledAt: phase === 'scheduled' ? normalizedPlan.fireAt : null,
|
|
||||||
countdownAt: normalizedPlan.fireAt,
|
countdownAt: normalizedPlan.fireAt,
|
||||||
countdownTitle: normalizedPlan.countdownTitle,
|
countdownTitle: normalizedPlan.countdownTitle,
|
||||||
countdownNote: normalizedPlan.countdownNote,
|
countdownNote: normalizedPlan.countdownNote,
|
||||||
@@ -3387,7 +3332,6 @@ function normalizePersistentSettingValue(key, value) {
|
|||||||
case 'oauthFlowTimeoutEnabled':
|
case 'oauthFlowTimeoutEnabled':
|
||||||
case 'gopayHelperLocalSmsHelperEnabled':
|
case 'gopayHelperLocalSmsHelperEnabled':
|
||||||
case 'gopayHelperAutoModeEnabled':
|
case 'gopayHelperAutoModeEnabled':
|
||||||
case 'autoRunDelayEnabled':
|
|
||||||
return Boolean(value);
|
return Boolean(value);
|
||||||
case 'operationDelayEnabled':
|
case 'operationDelayEnabled':
|
||||||
return true;
|
return true;
|
||||||
@@ -3408,8 +3352,6 @@ function normalizePersistentSettingValue(key, value) {
|
|||||||
return normalizePhoneSmsProviderOrder(value);
|
return normalizePhoneSmsProviderOrder(value);
|
||||||
case 'autoRunFallbackThreadIntervalMinutes':
|
case 'autoRunFallbackThreadIntervalMinutes':
|
||||||
return normalizeAutoRunFallbackThreadIntervalMinutes(value);
|
return normalizeAutoRunFallbackThreadIntervalMinutes(value);
|
||||||
case 'autoRunDelayMinutes':
|
|
||||||
return normalizeAutoRunDelayMinutes(value);
|
|
||||||
case 'autoStepDelaySeconds':
|
case 'autoStepDelaySeconds':
|
||||||
return normalizeAutoStepDelaySeconds(value, PERSISTED_SETTING_DEFAULTS.autoStepDelaySeconds);
|
return normalizeAutoStepDelaySeconds(value, PERSISTED_SETTING_DEFAULTS.autoStepDelaySeconds);
|
||||||
case 'verificationResendCount':
|
case 'verificationResendCount':
|
||||||
@@ -10090,8 +10032,7 @@ function getAutoRunStatusPayload(phase, payload = {}) {
|
|||||||
return loggingStatus.getAutoRunStatusPayload(phase, normalizedPayload);
|
return loggingStatus.getAutoRunStatusPayload(phase, normalizedPayload);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
autoRunning: phase === 'scheduled'
|
autoRunning: phase === 'running'
|
||||||
|| phase === 'running'
|
|
||||||
|| phase === 'waiting_step'
|
|| phase === 'waiting_step'
|
||||||
|| phase === 'waiting_email'
|
|| phase === 'waiting_email'
|
||||||
|| phase === 'retrying'
|
|| phase === 'retrying'
|
||||||
@@ -10101,7 +10042,6 @@ function getAutoRunStatusPayload(phase, payload = {}) {
|
|||||||
autoRunTotalRuns: normalizedPayload.totalRuns ?? 1,
|
autoRunTotalRuns: normalizedPayload.totalRuns ?? 1,
|
||||||
autoRunAttemptRun: normalizedPayload.attemptRun ?? 0,
|
autoRunAttemptRun: normalizedPayload.attemptRun ?? 0,
|
||||||
autoRunSessionId: normalizeAutoRunSessionId(normalizedPayload.sessionId),
|
autoRunSessionId: normalizeAutoRunSessionId(normalizedPayload.sessionId),
|
||||||
scheduledAutoRunAt: Number.isFinite(Number(normalizedPayload.scheduledAt)) ? Number(normalizedPayload.scheduledAt) : null,
|
|
||||||
autoRunCountdownAt: Number.isFinite(Number(normalizedPayload.countdownAt)) ? Number(normalizedPayload.countdownAt) : null,
|
autoRunCountdownAt: Number.isFinite(Number(normalizedPayload.countdownAt)) ? Number(normalizedPayload.countdownAt) : null,
|
||||||
autoRunCountdownTitle: normalizedPayload.countdownTitle === undefined ? '' : String(normalizedPayload.countdownTitle || ''),
|
autoRunCountdownTitle: normalizedPayload.countdownTitle === undefined ? '' : String(normalizedPayload.countdownTitle || ''),
|
||||||
autoRunCountdownNote: normalizedPayload.countdownNote === undefined ? '' : String(normalizedPayload.countdownNote || ''),
|
autoRunCountdownNote: normalizedPayload.countdownNote === undefined ? '' : String(normalizedPayload.countdownNote || ''),
|
||||||
@@ -10109,9 +10049,6 @@ function getAutoRunStatusPayload(phase, payload = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function broadcastAutoRunStatus(phase, payload = {}, extraState = {}) {
|
async function broadcastAutoRunStatus(phase, payload = {}, extraState = {}) {
|
||||||
const rawScheduledAt = phase === 'scheduled'
|
|
||||||
? (payload.scheduledAt ?? payload.scheduledAutoRunAt ?? null)
|
|
||||||
: null;
|
|
||||||
const rawCountdownAt = payload.countdownAt ?? payload.autoRunCountdownAt ?? null;
|
const rawCountdownAt = payload.countdownAt ?? payload.autoRunCountdownAt ?? null;
|
||||||
const statusPayload = {
|
const statusPayload = {
|
||||||
phase,
|
phase,
|
||||||
@@ -10119,7 +10056,6 @@ async function broadcastAutoRunStatus(phase, payload = {}, extraState = {}) {
|
|||||||
totalRuns: payload.totalRuns ?? autoRunTotalRuns,
|
totalRuns: payload.totalRuns ?? autoRunTotalRuns,
|
||||||
attemptRun: payload.attemptRun ?? autoRunAttemptRun,
|
attemptRun: payload.attemptRun ?? autoRunAttemptRun,
|
||||||
sessionId: payload.sessionId ?? payload.autoRunSessionId ?? autoRunSessionId,
|
sessionId: payload.sessionId ?? payload.autoRunSessionId ?? autoRunSessionId,
|
||||||
scheduledAt: rawScheduledAt === null ? null : Number(rawScheduledAt),
|
|
||||||
countdownAt: rawCountdownAt === null ? null : Number(rawCountdownAt),
|
countdownAt: rawCountdownAt === null ? null : Number(rawCountdownAt),
|
||||||
countdownTitle: payload.countdownTitle === undefined ? '' : String(payload.countdownTitle || ''),
|
countdownTitle: payload.countdownTitle === undefined ? '' : String(payload.countdownTitle || ''),
|
||||||
countdownNote: payload.countdownNote === undefined ? '' : String(payload.countdownNote || ''),
|
countdownNote: payload.countdownNote === undefined ? '' : String(payload.countdownNote || ''),
|
||||||
@@ -10149,38 +10085,10 @@ function isAutoRunPausedState(state) {
|
|||||||
return Boolean(state.autoRunning) && state.autoRunPhase === 'waiting_email';
|
return Boolean(state.autoRunning) && state.autoRunPhase === 'waiting_email';
|
||||||
}
|
}
|
||||||
|
|
||||||
function isAutoRunScheduledState(state) {
|
|
||||||
const plan = normalizeAutoRunTimerPlanFromState(state);
|
|
||||||
const scheduledAt = state.scheduledAutoRunAt === null ? null : Number(state.scheduledAutoRunAt);
|
|
||||||
return Boolean(state.autoRunning)
|
|
||||||
&& state.autoRunPhase === 'scheduled'
|
|
||||||
&& Number.isFinite(scheduledAt)
|
|
||||||
&& plan?.kind === AUTO_RUN_TIMER_KIND_SCHEDULED_START;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPendingAutoRunTimerPlan(state = {}) {
|
function getPendingAutoRunTimerPlan(state = {}) {
|
||||||
return normalizeAutoRunTimerPlanFromState(state);
|
return normalizeAutoRunTimerPlanFromState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatAutoRunScheduleTime(timestamp) {
|
|
||||||
return new Date(timestamp).toLocaleString('zh-CN', {
|
|
||||||
hour12: false,
|
|
||||||
timeZone: DISPLAY_TIMEZONE,
|
|
||||||
month: '2-digit',
|
|
||||||
day: '2-digit',
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit',
|
|
||||||
second: '2-digit',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function setAutoRunDelayEnabledState(enabled) {
|
|
||||||
const normalized = Boolean(enabled);
|
|
||||||
await setPersistentSettings({ autoRunDelayEnabled: normalized });
|
|
||||||
await setState({ autoRunDelayEnabled: normalized });
|
|
||||||
broadcastDataUpdate({ autoRunDelayEnabled: normalized });
|
|
||||||
}
|
|
||||||
|
|
||||||
async function ensureAutoRunTimerAlarm(fireAt) {
|
async function ensureAutoRunTimerAlarm(fireAt) {
|
||||||
if (!Number.isFinite(fireAt) || fireAt <= Date.now()) {
|
if (!Number.isFinite(fireAt) || fireAt <= Date.now()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -10212,7 +10120,6 @@ async function persistAutoRunTimerPlan(plan, extraState = {}) {
|
|||||||
{
|
{
|
||||||
...extraState,
|
...extraState,
|
||||||
autoRunTimerPlan: normalizedPlan,
|
autoRunTimerPlan: normalizedPlan,
|
||||||
scheduledAutoRunPlan: null,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
await ensureAutoRunTimerAlarm(normalizedPlan.fireAt);
|
await ensureAutoRunTimerAlarm(normalizedPlan.fireAt);
|
||||||
@@ -10225,22 +10132,6 @@ function getAutoRunTimerResumeOptions(plan) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedPlan.kind === AUTO_RUN_TIMER_KIND_SCHEDULED_START) {
|
|
||||||
return {
|
|
||||||
loopOptions: {
|
|
||||||
autoRunSessionId: normalizedPlan.autoRunSessionId,
|
|
||||||
autoRunSkipFailures: normalizedPlan.autoRunSkipFailures,
|
|
||||||
mode: normalizedPlan.mode,
|
|
||||||
},
|
|
||||||
statusPayload: {
|
|
||||||
currentRun: 0,
|
|
||||||
totalRuns: normalizedPlan.totalRuns,
|
|
||||||
attemptRun: 0,
|
|
||||||
sessionId: normalizedPlan.autoRunSessionId,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (normalizedPlan.kind === AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS) {
|
if (normalizedPlan.kind === AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS) {
|
||||||
const nextRun = Math.min(normalizedPlan.currentRun + 1, normalizedPlan.totalRuns);
|
const nextRun = Math.min(normalizedPlan.currentRun + 1, normalizedPlan.totalRuns);
|
||||||
return {
|
return {
|
||||||
@@ -10314,35 +10205,10 @@ async function launchAutoRunTimerPlan(trigger = 'alarm', options = {}) {
|
|||||||
}, {
|
}, {
|
||||||
autoRunRoundSummaries: [],
|
autoRunRoundSummaries: [],
|
||||||
autoRunTimerPlan: null,
|
autoRunTimerPlan: null,
|
||||||
scheduledAutoRunPlan: null,
|
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plan.kind === AUTO_RUN_TIMER_KIND_SCHEDULED_START) {
|
|
||||||
const autoRunStartValidation = typeof validateAutoRunStartState === 'function'
|
|
||||||
? validateAutoRunStartState(state, { state })
|
|
||||||
: { ok: true, errors: [] };
|
|
||||||
if (autoRunStartValidation?.ok === false) {
|
|
||||||
const validationMessage = autoRunStartValidation.errors?.[0]?.message || '当前设置不支持启动自动流程。';
|
|
||||||
await clearAutoRunTimerAlarm();
|
|
||||||
await broadcastAutoRunStatus('idle', {
|
|
||||||
currentRun: 0,
|
|
||||||
totalRuns: 1,
|
|
||||||
attemptRun: 0,
|
|
||||||
}, {
|
|
||||||
autoRunRoundSummaries: [],
|
|
||||||
autoRunTimerPlan: null,
|
|
||||||
scheduledAutoRunPlan: null,
|
|
||||||
});
|
|
||||||
await addLog(`自动运行计划已取消:${validationMessage}`, 'error');
|
|
||||||
if (trigger === 'manual') {
|
|
||||||
throw new Error(validationMessage);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await clearAutoRunTimerAlarm();
|
await clearAutoRunTimerAlarm();
|
||||||
if (plan.autoRunSessionId && !isCurrentAutoRunSessionId(plan.autoRunSessionId)) {
|
if (plan.autoRunSessionId && !isCurrentAutoRunSessionId(plan.autoRunSessionId)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -10351,9 +10217,6 @@ async function launchAutoRunTimerPlan(trigger = 'alarm', options = {}) {
|
|||||||
autoRunTotalRuns = plan.totalRuns;
|
autoRunTotalRuns = plan.totalRuns;
|
||||||
autoRunAttemptRun = resumeOptions.statusPayload.attemptRun;
|
autoRunAttemptRun = resumeOptions.statusPayload.attemptRun;
|
||||||
autoRunSessionId = normalizeAutoRunSessionId(plan.autoRunSessionId);
|
autoRunSessionId = normalizeAutoRunSessionId(plan.autoRunSessionId);
|
||||||
if (plan.kind === AUTO_RUN_TIMER_KIND_SCHEDULED_START && trigger !== 'manual' && state.autoRunDelayEnabled) {
|
|
||||||
await setAutoRunDelayEnabledState(false);
|
|
||||||
}
|
|
||||||
await broadcastAutoRunStatus(
|
await broadcastAutoRunStatus(
|
||||||
'running',
|
'running',
|
||||||
resumeOptions.statusPayload,
|
resumeOptions.statusPayload,
|
||||||
@@ -10361,7 +10224,6 @@ async function launchAutoRunTimerPlan(trigger = 'alarm', options = {}) {
|
|||||||
autoRunSkipFailures: plan.autoRunSkipFailures,
|
autoRunSkipFailures: plan.autoRunSkipFailures,
|
||||||
autoRunRoundSummaries: serializeAutoRunRoundSummaries(plan.totalRuns, plan.roundSummaries),
|
autoRunRoundSummaries: serializeAutoRunRoundSummaries(plan.totalRuns, plan.roundSummaries),
|
||||||
autoRunTimerPlan: null,
|
autoRunTimerPlan: null,
|
||||||
scheduledAutoRunPlan: null,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -10393,81 +10255,12 @@ async function launchAutoRunTimerPlan(trigger = 'alarm', options = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function scheduleAutoRun(totalRuns, options = {}) {
|
|
||||||
const state = await getState();
|
|
||||||
if (isAutoRunLockedState(state) || isAutoRunPausedState(state) || autoRunActive) {
|
|
||||||
throw new Error('自动运行已在进行中,请先停止后再重新计划。');
|
|
||||||
}
|
|
||||||
if (getPendingAutoRunTimerPlan(state)) {
|
|
||||||
throw new Error('已有自动运行倒计时计划,请先取消或立即开始。');
|
|
||||||
}
|
|
||||||
|
|
||||||
const delayMinutes = normalizeAutoRunDelayMinutes(options.delayMinutes);
|
|
||||||
const sessionId = createAutoRunSessionId();
|
|
||||||
const timerPlan = normalizeAutoRunTimerPlan({
|
|
||||||
kind: AUTO_RUN_TIMER_KIND_SCHEDULED_START,
|
|
||||||
fireAt: Date.now() + delayMinutes * 60 * 1000,
|
|
||||||
totalRuns,
|
|
||||||
autoRunSkipFailures: options.autoRunSkipFailures,
|
|
||||||
autoRunSessionId: sessionId,
|
|
||||||
mode: options.mode,
|
|
||||||
});
|
|
||||||
|
|
||||||
autoRunCurrentRun = 0;
|
|
||||||
autoRunTotalRuns = timerPlan.totalRuns;
|
|
||||||
autoRunAttemptRun = 0;
|
|
||||||
autoRunSessionId = sessionId;
|
|
||||||
|
|
||||||
await persistAutoRunTimerPlan(timerPlan, {
|
|
||||||
autoRunSkipFailures: timerPlan.autoRunSkipFailures,
|
|
||||||
autoRunRoundSummaries: serializeAutoRunRoundSummaries(timerPlan.totalRuns, []),
|
|
||||||
});
|
|
||||||
await addLog(
|
|
||||||
`自动运行已计划:${delayMinutes} 分钟后启动(${formatAutoRunScheduleTime(timerPlan.fireAt)}),目标 ${timerPlan.totalRuns} 轮。`,
|
|
||||||
'info'
|
|
||||||
);
|
|
||||||
return { ok: true, scheduledAt: timerPlan.fireAt };
|
|
||||||
}
|
|
||||||
|
|
||||||
async function cancelScheduledAutoRun(options = {}) {
|
|
||||||
const state = await getState();
|
|
||||||
const plan = getPendingAutoRunTimerPlan(state);
|
|
||||||
if (!plan || plan.kind !== AUTO_RUN_TIMER_KIND_SCHEDULED_START) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
autoRunCurrentRun = 0;
|
|
||||||
autoRunTotalRuns = plan.totalRuns;
|
|
||||||
autoRunAttemptRun = 0;
|
|
||||||
clearCurrentAutoRunSessionId(plan.autoRunSessionId);
|
|
||||||
await broadcastAutoRunStatus(
|
|
||||||
'idle',
|
|
||||||
{
|
|
||||||
currentRun: 0,
|
|
||||||
totalRuns: plan.totalRuns,
|
|
||||||
attemptRun: 0,
|
|
||||||
sessionId: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
autoRunSessionId: 0,
|
|
||||||
autoRunRoundSummaries: [],
|
|
||||||
autoRunTimerPlan: null,
|
|
||||||
scheduledAutoRunPlan: null,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
await clearAutoRunTimerAlarm();
|
|
||||||
if (options.logMessage !== false) {
|
|
||||||
await addLog(options.logMessage || '已取消自动运行倒计时计划。', 'warn');
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function restoreAutoRunTimerIfNeeded() {
|
async function restoreAutoRunTimerIfNeeded() {
|
||||||
const state = await getState();
|
const state = await getState();
|
||||||
let plan = getPendingAutoRunTimerPlan(state);
|
let plan = getPendingAutoRunTimerPlan(state);
|
||||||
if (!plan) {
|
if (!plan) {
|
||||||
clearCurrentAutoRunSessionId();
|
clearCurrentAutoRunSessionId();
|
||||||
if (state.autoRunPhase === 'scheduled' || state.autoRunPhase === 'waiting_interval') {
|
if (state.autoRunPhase === 'waiting_interval') {
|
||||||
await clearAutoRunTimerAlarm();
|
await clearAutoRunTimerAlarm();
|
||||||
await broadcastAutoRunStatus('idle', {
|
await broadcastAutoRunStatus('idle', {
|
||||||
currentRun: 0,
|
currentRun: 0,
|
||||||
@@ -10478,7 +10271,6 @@ async function restoreAutoRunTimerIfNeeded() {
|
|||||||
autoRunSessionId: 0,
|
autoRunSessionId: 0,
|
||||||
autoRunRoundSummaries: [],
|
autoRunRoundSummaries: [],
|
||||||
autoRunTimerPlan: null,
|
autoRunTimerPlan: null,
|
||||||
scheduledAutoRunPlan: null,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -10511,7 +10303,6 @@ async function restoreAutoRunTimerIfNeeded() {
|
|||||||
autoRunSkipFailures: plan.autoRunSkipFailures,
|
autoRunSkipFailures: plan.autoRunSkipFailures,
|
||||||
autoRunRoundSummaries: serializeAutoRunRoundSummaries(plan.totalRuns, plan.roundSummaries),
|
autoRunRoundSummaries: serializeAutoRunRoundSummaries(plan.totalRuns, plan.roundSummaries),
|
||||||
autoRunTimerPlan: plan,
|
autoRunTimerPlan: plan,
|
||||||
scheduledAutoRunPlan: null,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
await ensureAutoRunTimerAlarm(plan.fireAt);
|
await ensureAutoRunTimerAlarm(plan.fireAt);
|
||||||
@@ -10526,9 +10317,6 @@ async function ensureManualInteractionAllowed(actionLabel) {
|
|||||||
if (isAutoRunPausedState(state)) {
|
if (isAutoRunPausedState(state)) {
|
||||||
throw new Error(`自动流程当前已暂停。请点击“继续”,或先确认接管自动流程后再${actionLabel}。`);
|
throw new Error(`自动流程当前已暂停。请点击“继续”,或先确认接管自动流程后再${actionLabel}。`);
|
||||||
}
|
}
|
||||||
if (isAutoRunScheduledState(state)) {
|
|
||||||
throw new Error(`自动流程已计划启动。请先取消计划,或立即开始后再${actionLabel}。`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@@ -11495,15 +11283,6 @@ async function requestStop(options = {}) {
|
|||||||
const inferredStopNode = inferStoppedRecordNode(state);
|
const inferredStopNode = inferStoppedRecordNode(state);
|
||||||
const timerPlan = getPendingAutoRunTimerPlan(state);
|
const timerPlan = getPendingAutoRunTimerPlan(state);
|
||||||
|
|
||||||
if (timerPlan?.kind === AUTO_RUN_TIMER_KIND_SCHEDULED_START && !autoRunActive) {
|
|
||||||
await cancelScheduledAutoRun({
|
|
||||||
logMessage: options.logMessage === false
|
|
||||||
? false
|
|
||||||
: (options.logMessage || '已取消自动运行倒计时计划。'),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timerPlan && !autoRunActive) {
|
if (timerPlan && !autoRunActive) {
|
||||||
autoRunCurrentRun = timerPlan.currentRun;
|
autoRunCurrentRun = timerPlan.currentRun;
|
||||||
autoRunTotalRuns = timerPlan.totalRuns;
|
autoRunTotalRuns = timerPlan.totalRuns;
|
||||||
@@ -11522,7 +11301,6 @@ async function requestStop(options = {}) {
|
|||||||
autoRunSkipFailures: timerPlan.autoRunSkipFailures,
|
autoRunSkipFailures: timerPlan.autoRunSkipFailures,
|
||||||
autoRunRoundSummaries: serializeAutoRunRoundSummaries(timerPlan.totalRuns, timerPlan.roundSummaries),
|
autoRunRoundSummaries: serializeAutoRunRoundSummaries(timerPlan.totalRuns, timerPlan.roundSummaries),
|
||||||
autoRunTimerPlan: null,
|
autoRunTimerPlan: null,
|
||||||
scheduledAutoRunPlan: null,
|
|
||||||
});
|
});
|
||||||
await clearAutoRunTimerAlarm();
|
await clearAutoRunTimerAlarm();
|
||||||
clearStopRequest();
|
clearStopRequest();
|
||||||
@@ -11582,7 +11360,6 @@ async function requestStop(options = {}) {
|
|||||||
}, {
|
}, {
|
||||||
autoRunSessionId: 0,
|
autoRunSessionId: 0,
|
||||||
autoRunTimerPlan: null,
|
autoRunTimerPlan: null,
|
||||||
scheduledAutoRunPlan: null,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14153,7 +13930,6 @@ const messageRouter = self.MultiPageBackgroundMessageRouter?.createMessageRouter
|
|||||||
buildPersistentSettingsPayload,
|
buildPersistentSettingsPayload,
|
||||||
broadcastDataUpdate,
|
broadcastDataUpdate,
|
||||||
applyIpProxySettingsFromState,
|
applyIpProxySettingsFromState,
|
||||||
cancelScheduledAutoRun,
|
|
||||||
checkIcloudSession,
|
checkIcloudSession,
|
||||||
clearAccountRunHistory: (...args) => clearAndBroadcastAccountRunHistory(...args),
|
clearAccountRunHistory: (...args) => clearAndBroadcastAccountRunHistory(...args),
|
||||||
deleteAccountRunHistoryRecords: (...args) => deleteAndBroadcastAccountRunHistoryRecords(...args),
|
deleteAccountRunHistoryRecords: (...args) => deleteAndBroadcastAccountRunHistoryRecords(...args),
|
||||||
@@ -14260,7 +14036,6 @@ const messageRouter = self.MultiPageBackgroundMessageRouter?.createMessageRouter
|
|||||||
normalizeMail2925Accounts,
|
normalizeMail2925Accounts,
|
||||||
normalizePayPalAccounts,
|
normalizePayPalAccounts,
|
||||||
normalizeRunCount,
|
normalizeRunCount,
|
||||||
AUTO_RUN_TIMER_KIND_SCHEDULED_START,
|
|
||||||
notifyNodeComplete,
|
notifyNodeComplete,
|
||||||
notifyNodeError,
|
notifyNodeError,
|
||||||
patchHotmailAccount,
|
patchHotmailAccount,
|
||||||
@@ -14270,7 +14045,6 @@ const messageRouter = self.MultiPageBackgroundMessageRouter?.createMessageRouter
|
|||||||
probeIpProxyExit,
|
probeIpProxyExit,
|
||||||
resetState,
|
resetState,
|
||||||
resumeAutoRun,
|
resumeAutoRun,
|
||||||
scheduleAutoRun,
|
|
||||||
selectLuckmailPurchase,
|
selectLuckmailPurchase,
|
||||||
switchIpProxy,
|
switchIpProxy,
|
||||||
changeIpProxyExit,
|
changeIpProxyExit,
|
||||||
|
|||||||
@@ -158,8 +158,6 @@
|
|||||||
kiroRsKey: state.kiroRsKey,
|
kiroRsKey: state.kiroRsKey,
|
||||||
autoRunSkipFailures: state.autoRunSkipFailures,
|
autoRunSkipFailures: state.autoRunSkipFailures,
|
||||||
autoRunFallbackThreadIntervalMinutes: state.autoRunFallbackThreadIntervalMinutes,
|
autoRunFallbackThreadIntervalMinutes: state.autoRunFallbackThreadIntervalMinutes,
|
||||||
autoRunDelayEnabled: state.autoRunDelayEnabled,
|
|
||||||
autoRunDelayMinutes: state.autoRunDelayMinutes,
|
|
||||||
autoStepDelaySeconds: state.autoStepDelaySeconds,
|
autoStepDelaySeconds: state.autoStepDelaySeconds,
|
||||||
stepExecutionRangeByFlow: state.stepExecutionRangeByFlow,
|
stepExecutionRangeByFlow: state.stepExecutionRangeByFlow,
|
||||||
signupMethod: state.signupMethod,
|
signupMethod: state.signupMethod,
|
||||||
@@ -502,7 +500,6 @@
|
|||||||
}, {
|
}, {
|
||||||
autoRunSessionId: 0,
|
autoRunSessionId: 0,
|
||||||
autoRunTimerPlan: null,
|
autoRunTimerPlan: null,
|
||||||
scheduledAutoRunPlan: null,
|
|
||||||
});
|
});
|
||||||
clearStopRequest();
|
clearStopRequest();
|
||||||
}
|
}
|
||||||
@@ -1159,7 +1156,6 @@
|
|||||||
autoRunSessionId: 0,
|
autoRunSessionId: 0,
|
||||||
autoRunRoundSummaries: serializeAutoRunRoundSummaries(totalRuns, roundSummaries),
|
autoRunRoundSummaries: serializeAutoRunRoundSummaries(totalRuns, roundSummaries),
|
||||||
autoRunTimerPlan: null,
|
autoRunTimerPlan: null,
|
||||||
scheduledAutoRunPlan: null,
|
|
||||||
...getAutoRunStatusPayload(deps.getStopRequested() || stoppedEarly ? 'stopped' : 'complete', {
|
...getAutoRunStatusPayload(deps.getStopRequested() || stoppedEarly ? 'stopped' : 'complete', {
|
||||||
currentRun: deps.getStopRequested() || stoppedEarly ? afterRuntime.autoRunCurrentRun : afterRuntime.autoRunTotalRuns,
|
currentRun: deps.getStopRequested() || stoppedEarly ? afterRuntime.autoRunCurrentRun : afterRuntime.autoRunTotalRuns,
|
||||||
totalRuns: afterRuntime.autoRunTotalRuns,
|
totalRuns: afterRuntime.autoRunTotalRuns,
|
||||||
|
|||||||
@@ -209,8 +209,7 @@
|
|||||||
|
|
||||||
function getAutoRunStatusPayload(phase, payload = {}) {
|
function getAutoRunStatusPayload(phase, payload = {}) {
|
||||||
return {
|
return {
|
||||||
autoRunning: phase === 'scheduled'
|
autoRunning: phase === 'running'
|
||||||
|| phase === 'running'
|
|
||||||
|| phase === 'waiting_step'
|
|| phase === 'waiting_step'
|
||||||
|| phase === 'waiting_email'
|
|| phase === 'waiting_email'
|
||||||
|| phase === 'retrying'
|
|| phase === 'retrying'
|
||||||
@@ -220,7 +219,6 @@
|
|||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
autoRunAttemptRun: payload.attemptRun ?? 0,
|
autoRunAttemptRun: payload.attemptRun ?? 0,
|
||||||
autoRunSessionId: Math.max(0, Math.floor(Number(payload.sessionId ?? payload.autoRunSessionId) || 0)),
|
autoRunSessionId: Math.max(0, Math.floor(Number(payload.sessionId ?? payload.autoRunSessionId) || 0)),
|
||||||
scheduledAutoRunAt: Number.isFinite(Number(payload.scheduledAt)) ? Number(payload.scheduledAt) : null,
|
|
||||||
autoRunCountdownAt: Number.isFinite(Number(payload.countdownAt)) ? Number(payload.countdownAt) : null,
|
autoRunCountdownAt: Number.isFinite(Number(payload.countdownAt)) ? Number(payload.countdownAt) : null,
|
||||||
autoRunCountdownTitle: payload.countdownTitle === undefined ? '' : String(payload.countdownTitle || ''),
|
autoRunCountdownTitle: payload.countdownTitle === undefined ? '' : String(payload.countdownTitle || ''),
|
||||||
autoRunCountdownNote: payload.countdownNote === undefined ? '' : String(payload.countdownNote || ''),
|
autoRunCountdownNote: payload.countdownNote === undefined ? '' : String(payload.countdownNote || ''),
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
buildPersistentSettingsPayload,
|
buildPersistentSettingsPayload,
|
||||||
broadcastDataUpdate,
|
broadcastDataUpdate,
|
||||||
applyIpProxySettingsFromState,
|
applyIpProxySettingsFromState,
|
||||||
cancelScheduledAutoRun,
|
|
||||||
checkIcloudSession,
|
checkIcloudSession,
|
||||||
clearAccountRunHistory,
|
clearAccountRunHistory,
|
||||||
deleteAccountRunHistoryRecords,
|
deleteAccountRunHistoryRecords,
|
||||||
@@ -145,7 +144,6 @@
|
|||||||
normalizeMail2925Accounts,
|
normalizeMail2925Accounts,
|
||||||
normalizePayPalAccounts,
|
normalizePayPalAccounts,
|
||||||
normalizeRunCount,
|
normalizeRunCount,
|
||||||
AUTO_RUN_TIMER_KIND_SCHEDULED_START,
|
|
||||||
notifyNodeComplete,
|
notifyNodeComplete,
|
||||||
notifyNodeError,
|
notifyNodeError,
|
||||||
patchMail2925Account,
|
patchMail2925Account,
|
||||||
@@ -158,7 +156,6 @@
|
|||||||
handleCloudflareSecurityBlocked,
|
handleCloudflareSecurityBlocked,
|
||||||
resetState,
|
resetState,
|
||||||
resumeAutoRun,
|
resumeAutoRun,
|
||||||
scheduleAutoRun,
|
|
||||||
selectLuckmailPurchase,
|
selectLuckmailPurchase,
|
||||||
switchIpProxy,
|
switchIpProxy,
|
||||||
changeIpProxyExit,
|
changeIpProxyExit,
|
||||||
@@ -1324,7 +1321,7 @@
|
|||||||
throw new Error(autoRunStartValidation.errors?.[0]?.message || '当前设置不支持启动自动流程。');
|
throw new Error(autoRunStartValidation.errors?.[0]?.message || '当前设置不支持启动自动流程。');
|
||||||
}
|
}
|
||||||
if (getPendingAutoRunTimerPlan(state)) {
|
if (getPendingAutoRunTimerPlan(state)) {
|
||||||
throw new Error('已有自动运行倒计时计划,请先取消或立即开始。');
|
throw new Error('已有线程间隔等待,请先停止或立即继续。');
|
||||||
}
|
}
|
||||||
const totalRuns = normalizeRunCount(message.payload?.totalRuns || 1);
|
const totalRuns = normalizeRunCount(message.payload?.totalRuns || 1);
|
||||||
const autoRunSkipFailures = Boolean(message.payload?.autoRunSkipFailures);
|
const autoRunSkipFailures = Boolean(message.payload?.autoRunSkipFailures);
|
||||||
@@ -1334,68 +1331,6 @@
|
|||||||
return { ok: true };
|
return { ok: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'SCHEDULE_AUTO_RUN': {
|
|
||||||
clearStopRequest();
|
|
||||||
if (message.source === 'sidepanel') {
|
|
||||||
await lockAutomationWindowFromMessage(message, sender);
|
|
||||||
}
|
|
||||||
if (Boolean(message.payload?.accountContributionEnabled) && typeof setAccountContributionMode === 'function') {
|
|
||||||
await setAccountContributionMode(true, {
|
|
||||||
adapterId: message.payload?.contributionAdapterId,
|
|
||||||
flowId: message.payload?.activeFlowId || message.payload?.flowId,
|
|
||||||
});
|
|
||||||
if (typeof setState === 'function') {
|
|
||||||
const contributionNickname = String(message.payload?.contributionNickname || '').trim();
|
|
||||||
const contributionQq = String(message.payload?.contributionQq || '').trim();
|
|
||||||
await setState({
|
|
||||||
contributionNickname,
|
|
||||||
contributionQq,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const autoRunFlowStateUpdates = buildAutoRunFlowStateUpdates(message.payload || {});
|
|
||||||
if (Object.keys(autoRunFlowStateUpdates).length > 0 && typeof setState === 'function') {
|
|
||||||
await setState(autoRunFlowStateUpdates);
|
|
||||||
}
|
|
||||||
const state = await getState();
|
|
||||||
const autoRunStartValidation = validateAutoRunStart(state, {
|
|
||||||
activeFlowId: autoRunFlowStateUpdates.activeFlowId ?? state?.activeFlowId,
|
|
||||||
targetId: autoRunFlowStateUpdates.targetId ?? state?.targetId,
|
|
||||||
state,
|
|
||||||
});
|
|
||||||
if (autoRunStartValidation?.ok === false) {
|
|
||||||
throw new Error(autoRunStartValidation.errors?.[0]?.message || '当前设置不支持启动自动流程。');
|
|
||||||
}
|
|
||||||
const totalRuns = normalizeRunCount(message.payload?.totalRuns || 1);
|
|
||||||
return await scheduleAutoRun(totalRuns, {
|
|
||||||
delayMinutes: message.payload?.delayMinutes,
|
|
||||||
autoRunSkipFailures: Boolean(message.payload?.autoRunSkipFailures),
|
|
||||||
mode: message.payload?.mode,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'START_SCHEDULED_AUTO_RUN_NOW': {
|
|
||||||
clearStopRequest();
|
|
||||||
if (message.source === 'sidepanel') {
|
|
||||||
await lockAutomationWindowFromMessage(message, sender);
|
|
||||||
}
|
|
||||||
const started = await launchAutoRunTimerPlan('manual', {
|
|
||||||
expectedKinds: [AUTO_RUN_TIMER_KIND_SCHEDULED_START],
|
|
||||||
});
|
|
||||||
if (!started) {
|
|
||||||
throw new Error('当前没有可立即开始的倒计时计划。');
|
|
||||||
}
|
|
||||||
return { ok: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'CANCEL_SCHEDULED_AUTO_RUN': {
|
|
||||||
const cancelled = await cancelScheduledAutoRun();
|
|
||||||
if (!cancelled) {
|
|
||||||
throw new Error('当前没有可取消的倒计时计划。');
|
|
||||||
}
|
|
||||||
return { ok: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'SKIP_AUTO_RUN_COUNTDOWN': {
|
case 'SKIP_AUTO_RUN_COUNTDOWN': {
|
||||||
clearStopRequest();
|
clearStopRequest();
|
||||||
if (message.source === 'sidepanel') {
|
if (message.source === 'sidepanel') {
|
||||||
|
|||||||
@@ -49,6 +49,20 @@
|
|||||||
label: 'IP \u4ee3\u7406',
|
label: 'IP \u4ee3\u7406',
|
||||||
sectionIds: ['ip-proxy-section'],
|
sectionIds: ['ip-proxy-section'],
|
||||||
},
|
},
|
||||||
|
'shared-auto-run': {
|
||||||
|
id: 'shared-auto-run',
|
||||||
|
label: '\u81ea\u52a8\u8fd0\u884c',
|
||||||
|
rowIds: [
|
||||||
|
'row-shared-auto-run',
|
||||||
|
'row-auto-run-thread-interval',
|
||||||
|
'row-step-execution-range',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'shared-settings-actions': {
|
||||||
|
id: 'shared-settings-actions',
|
||||||
|
label: '\u8bbe\u7f6e\u64cd\u4f5c',
|
||||||
|
rowIds: ['row-settings-actions'],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function buildFlowDefinitions() {
|
function buildFlowDefinitions() {
|
||||||
|
|||||||
@@ -209,8 +209,7 @@
|
|||||||
|
|
||||||
function getAutoRunStatusPayload(phase, payload = {}) {
|
function getAutoRunStatusPayload(phase, payload = {}) {
|
||||||
return {
|
return {
|
||||||
autoRunning: phase === 'scheduled'
|
autoRunning: phase === 'running'
|
||||||
|| phase === 'running'
|
|
||||||
|| phase === 'waiting_step'
|
|| phase === 'waiting_step'
|
||||||
|| phase === 'waiting_email'
|
|| phase === 'waiting_email'
|
||||||
|| phase === 'retrying'
|
|| phase === 'retrying'
|
||||||
@@ -220,7 +219,6 @@
|
|||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
autoRunAttemptRun: payload.attemptRun ?? 0,
|
autoRunAttemptRun: payload.attemptRun ?? 0,
|
||||||
autoRunSessionId: Math.max(0, Math.floor(Number(payload.sessionId ?? payload.autoRunSessionId) || 0)),
|
autoRunSessionId: Math.max(0, Math.floor(Number(payload.sessionId ?? payload.autoRunSessionId) || 0)),
|
||||||
scheduledAutoRunAt: Number.isFinite(Number(payload.scheduledAt)) ? Number(payload.scheduledAt) : null,
|
|
||||||
autoRunCountdownAt: Number.isFinite(Number(payload.countdownAt)) ? Number(payload.countdownAt) : null,
|
autoRunCountdownAt: Number.isFinite(Number(payload.countdownAt)) ? Number(payload.countdownAt) : null,
|
||||||
autoRunCountdownTitle: payload.countdownTitle === undefined ? '' : String(payload.countdownTitle || ''),
|
autoRunCountdownTitle: payload.countdownTitle === undefined ? '' : String(payload.countdownTitle || ''),
|
||||||
autoRunCountdownNote: payload.countdownNote === undefined ? '' : String(payload.countdownNote || ''),
|
autoRunCountdownNote: payload.countdownNote === undefined ? '' : String(payload.countdownNote || ''),
|
||||||
|
|||||||
@@ -115,48 +115,11 @@
|
|||||||
if (isPlainObject(range)) {
|
if (isPlainObject(range)) {
|
||||||
return normalizeStepExecutionRangeEntry(range, { enabled: false, fromStep: 1, toStep: 1 });
|
return normalizeStepExecutionRangeEntry(range, { enabled: false, fromStep: 1, toStep: 1 });
|
||||||
}
|
}
|
||||||
if (flowId === 'openai') {
|
|
||||||
return { enabled: false, fromStep: 1, toStep: 11 };
|
|
||||||
}
|
|
||||||
if (flowId === 'kiro') {
|
|
||||||
return { enabled: false, fromStep: 1, toStep: 9 };
|
|
||||||
}
|
|
||||||
const lastStep = Math.max(1, Number(getFlowDefinition(flowId)?.workflowStepCount) || 1);
|
const lastStep = Math.max(1, Number(getFlowDefinition(flowId)?.workflowStepCount) || 1);
|
||||||
return { enabled: false, fromStep: 1, toStep: lastStep };
|
return { enabled: false, fromStep: 1, toStep: lastStep };
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildDefaultTargetState(flowId, targetId) {
|
function buildDefaultTargetState(flowId, targetId) {
|
||||||
if (flowId === 'openai' && targetId === 'cpa') {
|
|
||||||
return {
|
|
||||||
vpsUrl: '',
|
|
||||||
vpsPassword: '',
|
|
||||||
localCpaStep9Mode: 'submit',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (flowId === 'openai' && targetId === 'sub2api') {
|
|
||||||
return {
|
|
||||||
sub2apiUrl: '',
|
|
||||||
sub2apiEmail: '',
|
|
||||||
sub2apiPassword: '',
|
|
||||||
sub2apiGroupName: 'codex',
|
|
||||||
sub2apiGroupNames: ['codex', 'openai-plus'],
|
|
||||||
sub2apiAccountPriority: 1,
|
|
||||||
sub2apiDefaultProxyName: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (flowId === 'openai' && targetId === 'codex2api') {
|
|
||||||
return {
|
|
||||||
codex2apiUrl: '',
|
|
||||||
codex2apiAdminKey: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (flowId === 'kiro' && targetId === 'kiro-rs') {
|
|
||||||
return {
|
|
||||||
baseUrl: defaultKiroRsUrl,
|
|
||||||
apiKey: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const definition = getFlowDefinition(flowId) || {};
|
const definition = getFlowDefinition(flowId) || {};
|
||||||
const flowDefaults = getFlowSettingsDefaults(flowId);
|
const flowDefaults = getFlowSettingsDefaults(flowId);
|
||||||
const targetDefaults = isPlainObject(flowDefaults?.targets?.[targetId])
|
const targetDefaults = isPlainObject(flowDefaults?.targets?.[targetId])
|
||||||
@@ -200,24 +163,7 @@
|
|||||||
stepExecutionRange: getDefaultStepExecutionRange(flowId),
|
stepExecutionRange: getDefaultStepExecutionRange(flowId),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if (flowId === 'openai') {
|
return mergePlainObjects(base, getFlowSettingsDefaults(flowId));
|
||||||
return mergePlainObjects(base, {
|
|
||||||
signup: {
|
|
||||||
signupMethod: 'email',
|
|
||||||
phoneVerificationEnabled: false,
|
|
||||||
phoneSignupReloginAfterBindEmailEnabled: false,
|
|
||||||
},
|
|
||||||
plus: {
|
|
||||||
plusModeEnabled: false,
|
|
||||||
plusPaymentMethod: 'paypal-hosted',
|
|
||||||
plusAccountAccessStrategy: 'oauth',
|
|
||||||
hostedCheckoutVerificationUrl: '',
|
|
||||||
hostedCheckoutPhoneNumber: '',
|
|
||||||
plusHostedCheckoutOauthDelaySeconds: 3,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildDefaultFlows() {
|
function buildDefaultFlows() {
|
||||||
@@ -364,6 +310,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizeOpenAiSettings(input = {}, nested = {}, defaults = {}, currentFlow = {}) {
|
function normalizeOpenAiSettings(input = {}, nested = {}, defaults = {}, currentFlow = {}) {
|
||||||
|
const defaultOpenAiFlow = isPlainObject(defaults?.flows?.openai)
|
||||||
|
? defaults.flows.openai
|
||||||
|
: {};
|
||||||
|
const defaultOpenAiTargets = isPlainObject(defaultOpenAiFlow.targets)
|
||||||
|
? defaultOpenAiFlow.targets
|
||||||
|
: {};
|
||||||
|
const defaultOpenAiSignup = isPlainObject(defaultOpenAiFlow.signup)
|
||||||
|
? defaultOpenAiFlow.signup
|
||||||
|
: {};
|
||||||
|
const defaultOpenAiPlus = isPlainObject(defaultOpenAiFlow.plus)
|
||||||
|
? defaultOpenAiFlow.plus
|
||||||
|
: {};
|
||||||
const cpaSource = {
|
const cpaSource = {
|
||||||
...currentFlow.targets.cpa,
|
...currentFlow.targets.cpa,
|
||||||
...getTargetValue(
|
...getTargetValue(
|
||||||
@@ -407,66 +365,82 @@
|
|||||||
...currentFlow,
|
...currentFlow,
|
||||||
targets: {
|
targets: {
|
||||||
...currentFlow.targets,
|
...currentFlow.targets,
|
||||||
cpa: normalizeFlowTargetState('openai', 'cpa', cpaSource, defaults.flows.openai.targets.cpa),
|
cpa: normalizeFlowTargetState('openai', 'cpa', cpaSource, defaultOpenAiTargets.cpa || {}),
|
||||||
sub2api: normalizeFlowTargetState('openai', 'sub2api', sub2apiSource, defaults.flows.openai.targets.sub2api),
|
sub2api: normalizeFlowTargetState('openai', 'sub2api', sub2apiSource, defaultOpenAiTargets.sub2api || {}),
|
||||||
codex2api: normalizeFlowTargetState('openai', 'codex2api', codex2apiSource, defaults.flows.openai.targets.codex2api),
|
codex2api: normalizeFlowTargetState('openai', 'codex2api', codex2apiSource, defaultOpenAiTargets.codex2api || {}),
|
||||||
},
|
},
|
||||||
signup: {
|
signup: {
|
||||||
signupMethod: String(
|
signupMethod: String(
|
||||||
input?.signupMethod
|
input?.signupMethod
|
||||||
?? currentFlow.signup?.signupMethod
|
?? currentFlow.signup?.signupMethod
|
||||||
?? defaults.flows.openai.signup.signupMethod
|
?? defaultOpenAiSignup.signupMethod
|
||||||
|
?? 'email'
|
||||||
).trim().toLowerCase() === 'phone' ? 'phone' : 'email',
|
).trim().toLowerCase() === 'phone' ? 'phone' : 'email',
|
||||||
phoneVerificationEnabled: Boolean(
|
phoneVerificationEnabled: Boolean(
|
||||||
input?.phoneVerificationEnabled
|
input?.phoneVerificationEnabled
|
||||||
?? currentFlow.signup?.phoneVerificationEnabled
|
?? currentFlow.signup?.phoneVerificationEnabled
|
||||||
?? defaults.flows.openai.signup.phoneVerificationEnabled
|
?? defaultOpenAiSignup.phoneVerificationEnabled
|
||||||
|
?? false
|
||||||
),
|
),
|
||||||
phoneSignupReloginAfterBindEmailEnabled: Boolean(
|
phoneSignupReloginAfterBindEmailEnabled: Boolean(
|
||||||
input?.phoneSignupReloginAfterBindEmailEnabled
|
input?.phoneSignupReloginAfterBindEmailEnabled
|
||||||
?? currentFlow.signup?.phoneSignupReloginAfterBindEmailEnabled
|
?? currentFlow.signup?.phoneSignupReloginAfterBindEmailEnabled
|
||||||
?? defaults.flows.openai.signup.phoneSignupReloginAfterBindEmailEnabled
|
?? defaultOpenAiSignup.phoneSignupReloginAfterBindEmailEnabled
|
||||||
|
?? false
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
plus: {
|
plus: {
|
||||||
plusModeEnabled: Boolean(
|
plusModeEnabled: Boolean(
|
||||||
input?.plusModeEnabled
|
input?.plusModeEnabled
|
||||||
?? currentFlow.plus?.plusModeEnabled
|
?? currentFlow.plus?.plusModeEnabled
|
||||||
?? defaults.flows.openai.plus.plusModeEnabled
|
?? defaultOpenAiPlus.plusModeEnabled
|
||||||
|
?? false
|
||||||
),
|
),
|
||||||
plusPaymentMethod: String(
|
plusPaymentMethod: String(
|
||||||
input?.plusPaymentMethod
|
input?.plusPaymentMethod
|
||||||
?? currentFlow.plus?.plusPaymentMethod
|
?? currentFlow.plus?.plusPaymentMethod
|
||||||
?? defaults.flows.openai.plus.plusPaymentMethod
|
?? defaultOpenAiPlus.plusPaymentMethod
|
||||||
).trim() || defaults.flows.openai.plus.plusPaymentMethod,
|
?? 'paypal-hosted'
|
||||||
|
).trim() || defaultOpenAiPlus.plusPaymentMethod || 'paypal-hosted',
|
||||||
plusAccountAccessStrategy: normalizePlusAccountAccessStrategy(
|
plusAccountAccessStrategy: normalizePlusAccountAccessStrategy(
|
||||||
input?.plusAccountAccessStrategy
|
input?.plusAccountAccessStrategy
|
||||||
?? currentFlow.plus?.plusAccountAccessStrategy
|
?? currentFlow.plus?.plusAccountAccessStrategy
|
||||||
?? defaults.flows.openai.plus.plusAccountAccessStrategy
|
?? defaultOpenAiPlus.plusAccountAccessStrategy
|
||||||
|
?? 'oauth'
|
||||||
),
|
),
|
||||||
hostedCheckoutVerificationUrl: String(
|
hostedCheckoutVerificationUrl: String(
|
||||||
input?.hostedCheckoutVerificationUrl
|
input?.hostedCheckoutVerificationUrl
|
||||||
?? currentFlow.plus?.hostedCheckoutVerificationUrl
|
?? currentFlow.plus?.hostedCheckoutVerificationUrl
|
||||||
?? defaults.flows.openai.plus.hostedCheckoutVerificationUrl
|
?? defaultOpenAiPlus.hostedCheckoutVerificationUrl
|
||||||
|
?? ''
|
||||||
).trim(),
|
).trim(),
|
||||||
hostedCheckoutPhoneNumber: String(
|
hostedCheckoutPhoneNumber: String(
|
||||||
input?.hostedCheckoutPhoneNumber
|
input?.hostedCheckoutPhoneNumber
|
||||||
?? currentFlow.plus?.hostedCheckoutPhoneNumber
|
?? currentFlow.plus?.hostedCheckoutPhoneNumber
|
||||||
?? defaults.flows.openai.plus.hostedCheckoutPhoneNumber
|
?? defaultOpenAiPlus.hostedCheckoutPhoneNumber
|
||||||
|
?? ''
|
||||||
).trim(),
|
).trim(),
|
||||||
plusHostedCheckoutOauthDelaySeconds: (() => {
|
plusHostedCheckoutOauthDelaySeconds: (() => {
|
||||||
const numeric = Number(
|
const numeric = Number(
|
||||||
input?.plusHostedCheckoutOauthDelaySeconds
|
input?.plusHostedCheckoutOauthDelaySeconds
|
||||||
?? currentFlow.plus?.plusHostedCheckoutOauthDelaySeconds
|
?? currentFlow.plus?.plusHostedCheckoutOauthDelaySeconds
|
||||||
?? defaults.flows.openai.plus.plusHostedCheckoutOauthDelaySeconds
|
?? defaultOpenAiPlus.plusHostedCheckoutOauthDelaySeconds
|
||||||
|
?? 3
|
||||||
);
|
);
|
||||||
return Math.min(120, Math.max(0, Math.floor(Number.isFinite(numeric) ? numeric : defaults.flows.openai.plus.plusHostedCheckoutOauthDelaySeconds)));
|
const fallback = Number(defaultOpenAiPlus.plusHostedCheckoutOauthDelaySeconds ?? 3) || 3;
|
||||||
|
return Math.min(120, Math.max(0, Math.floor(Number.isFinite(numeric) ? numeric : fallback)));
|
||||||
})(),
|
})(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeKiroSettings(input = {}, defaults = {}, currentFlow = {}) {
|
function normalizeKiroSettings(input = {}, defaults = {}, currentFlow = {}) {
|
||||||
|
const defaultKiroFlow = isPlainObject(defaults?.flows?.kiro)
|
||||||
|
? defaults.flows.kiro
|
||||||
|
: {};
|
||||||
|
const defaultKiroTargets = isPlainObject(defaultKiroFlow.targets)
|
||||||
|
? defaultKiroFlow.targets
|
||||||
|
: {};
|
||||||
const targetSource = {
|
const targetSource = {
|
||||||
...currentFlow.targets['kiro-rs'],
|
...currentFlow.targets['kiro-rs'],
|
||||||
baseUrl: input?.kiroRsUrl ?? input?.kiroRsBaseUrl ?? currentFlow.targets['kiro-rs'].baseUrl,
|
baseUrl: input?.kiroRsUrl ?? input?.kiroRsBaseUrl ?? currentFlow.targets['kiro-rs'].baseUrl,
|
||||||
@@ -476,7 +450,7 @@
|
|||||||
...currentFlow,
|
...currentFlow,
|
||||||
targets: {
|
targets: {
|
||||||
...currentFlow.targets,
|
...currentFlow.targets,
|
||||||
'kiro-rs': normalizeFlowTargetState('kiro', 'kiro-rs', targetSource, defaults.flows.kiro.targets['kiro-rs']),
|
'kiro-rs': normalizeFlowTargetState('kiro', 'kiro-rs', targetSource, defaultKiroTargets['kiro-rs'] || {}),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
const GROK_SIGNUP_URL = 'https://accounts.x.ai/sign-up?redirect=grok-com';
|
const GROK_SIGNUP_URL = 'https://accounts.x.ai/sign-up?redirect=grok-com';
|
||||||
const GROK_REGISTER_PAGE_SOURCE_ID = 'grok-register-page';
|
const GROK_REGISTER_PAGE_SOURCE_ID = 'grok-register-page';
|
||||||
const DEFAULT_GROK_PAGE_TIMEOUT_MS = 90 * 1000;
|
const DEFAULT_GROK_PAGE_TIMEOUT_MS = 90 * 1000;
|
||||||
|
const GROK_VERIFICATION_PAGE_STATE = 'verification_code_entry';
|
||||||
|
const GROK_VERIFICATION_READY_TIMEOUT_MS = 90 * 1000;
|
||||||
const GROK_POST_PROFILE_CF_WAIT_MS = 20 * 1000;
|
const GROK_POST_PROFILE_CF_WAIT_MS = 20 * 1000;
|
||||||
const GROK_PRE_SSO_EXTRACT_WAIT_MS = 10 * 1000;
|
const GROK_PRE_SSO_EXTRACT_WAIT_MS = 10 * 1000;
|
||||||
const MAIL_2925_FILTER_LOOKBACK_MS = 10 * 60 * 1000;
|
const MAIL_2925_FILTER_LOOKBACK_MS = 10 * 60 * 1000;
|
||||||
@@ -191,6 +193,50 @@
|
|||||||
return result || {};
|
return result || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getGrokRegisterPageState(options = {}) {
|
||||||
|
return sendGrokCommand('GET_PAGE_STATE', {}, {
|
||||||
|
step: options.step || 0,
|
||||||
|
timeoutMs: options.timeoutMs || 15000,
|
||||||
|
logMessage: options.logMessage || '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function waitForGrokVerificationPageReady(tabId, options = {}) {
|
||||||
|
const timeoutMs = Math.max(1000, Number(options.timeoutMs) || GROK_VERIFICATION_READY_TIMEOUT_MS);
|
||||||
|
const intervalMs = Math.max(250, Number(options.intervalMs) || 1000);
|
||||||
|
const deadline = Date.now() + timeoutMs;
|
||||||
|
let lastState = null;
|
||||||
|
let lastError = '';
|
||||||
|
|
||||||
|
while (Date.now() <= deadline) {
|
||||||
|
throwIfStopped();
|
||||||
|
try {
|
||||||
|
await ensureContentReady(tabId, {
|
||||||
|
timeoutMs: Math.min(DEFAULT_GROK_PAGE_TIMEOUT_MS, Math.max(5000, intervalMs + 3000)),
|
||||||
|
stableMs: 500,
|
||||||
|
initialDelayMs: 0,
|
||||||
|
logMessage: options.logMessage || '',
|
||||||
|
});
|
||||||
|
lastState = await getGrokRegisterPageState({
|
||||||
|
step: options.step || 0,
|
||||||
|
timeoutMs: Math.max(5000, intervalMs + 3000),
|
||||||
|
});
|
||||||
|
lastError = '';
|
||||||
|
if (lastState?.state === GROK_VERIFICATION_PAGE_STATE) {
|
||||||
|
return lastState;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
lastError = getErrorMessage(error);
|
||||||
|
}
|
||||||
|
await sleepWithStop(Math.min(intervalMs, Math.max(0, deadline - Date.now())));
|
||||||
|
}
|
||||||
|
|
||||||
|
const stateLabel = cleanString(lastState?.state) || 'unknown';
|
||||||
|
const urlLabel = cleanString(lastState?.url);
|
||||||
|
const errorLabel = lastError ? `,最后通信错误:${lastError}` : '';
|
||||||
|
throw new Error(`Grok 邮箱提交后尚未进入验证码页面,当前状态:${stateLabel}${urlLabel ? `,URL:${urlLabel}` : ''}${errorLabel}。`);
|
||||||
|
}
|
||||||
|
|
||||||
function shouldClearGrokCookie(cookie = {}) {
|
function shouldClearGrokCookie(cookie = {}) {
|
||||||
const domain = cleanString(cookie.domain).replace(/^\.+/, '').toLowerCase();
|
const domain = cleanString(cookie.domain).replace(/^\.+/, '').toLowerCase();
|
||||||
return GROK_COOKIE_CLEAR_DOMAINS.some((target) => (
|
return GROK_COOKIE_CLEAR_DOMAINS.some((target) => (
|
||||||
@@ -395,8 +441,12 @@
|
|||||||
});
|
});
|
||||||
const result = await sendGrokCommand(nodeId, { email }, {
|
const result = await sendGrokCommand(nodeId, { email }, {
|
||||||
step: 2,
|
step: 2,
|
||||||
|
timeoutMs: GROK_VERIFICATION_READY_TIMEOUT_MS + 15000,
|
||||||
logMessage: '步骤 2:正在提交 Grok 注册邮箱...',
|
logMessage: '步骤 2:正在提交 Grok 注册邮箱...',
|
||||||
});
|
});
|
||||||
|
if (result.state !== GROK_VERIFICATION_PAGE_STATE) {
|
||||||
|
throw new Error(`Grok 邮箱提交后尚未进入验证码页面,当前状态:${cleanString(result.state) || 'unknown'}${cleanString(result.url) ? `,URL:${cleanString(result.url)}` : ''}。`);
|
||||||
|
}
|
||||||
await log(`步骤 2:已提交 Grok 注册邮箱 ${email}。`, 'ok', nodeId);
|
await log(`步骤 2:已提交 Grok 注册邮箱 ${email}。`, 'ok', nodeId);
|
||||||
await completeNode(nodeId, {
|
await completeNode(nodeId, {
|
||||||
grokEmail: email,
|
grokEmail: email,
|
||||||
@@ -456,6 +506,23 @@
|
|||||||
|| currentState.runtimeState?.flowState?.grok?.register?.email
|
|| currentState.runtimeState?.flowState?.grok?.register?.email
|
||||||
|| currentState.email
|
|| currentState.email
|
||||||
).toLowerCase();
|
).toLowerCase();
|
||||||
|
const tabId = await ensureGrokRegisterTab(currentState, { openIfMissing: false });
|
||||||
|
await activateTab(tabId);
|
||||||
|
const readyState = await waitForGrokVerificationPageReady(tabId, {
|
||||||
|
step: 3,
|
||||||
|
logMessage: '步骤 3:正在等待 Grok 验证码页面就绪...',
|
||||||
|
});
|
||||||
|
await persistState({
|
||||||
|
grokPageState: readyState.state || '',
|
||||||
|
grokPageUrl: readyState.url || '',
|
||||||
|
...buildGrokRuntimePatch({
|
||||||
|
session: {
|
||||||
|
pageState: readyState.state || '',
|
||||||
|
pageUrl: readyState.url || '',
|
||||||
|
lastError: '',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
const pollResult = await pollFlowVerificationCode({
|
const pollResult = await pollFlowVerificationCode({
|
||||||
actionLabel: 'Grok 验证码',
|
actionLabel: 'Grok 验证码',
|
||||||
filterAfterTimestamp,
|
filterAfterTimestamp,
|
||||||
@@ -478,7 +545,6 @@
|
|||||||
if (!code) {
|
if (!code) {
|
||||||
throw new Error('未能获取到 xAI 邮箱验证码。');
|
throw new Error('未能获取到 xAI 邮箱验证码。');
|
||||||
}
|
}
|
||||||
const tabId = await ensureGrokRegisterTab(currentState, { openIfMissing: false });
|
|
||||||
await activateTab(tabId);
|
await activateTab(tabId);
|
||||||
await ensureContentReady(tabId);
|
await ensureContentReady(tabId);
|
||||||
const result = await sendGrokCommand(nodeId, { code }, {
|
const result = await sendGrokCommand(nodeId, { code }, {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const GROK_SIGNUP_URL = 'https://accounts.x.ai/sign-up?redirect=grok-com';
|
|||||||
const GROK_EMAIL_SIGNUP_TEXT_PATTERN = /使用邮箱注册|sign\s*up\s*with\s*email|continue\s*with\s*email|email/i;
|
const GROK_EMAIL_SIGNUP_TEXT_PATTERN = /使用邮箱注册|sign\s*up\s*with\s*email|continue\s*with\s*email|email/i;
|
||||||
const GROK_CONTINUE_TEXT_PATTERN = /continue|next|sign\s*up|submit|verify|继续|下一步|注册|提交|验证/i;
|
const GROK_CONTINUE_TEXT_PATTERN = /continue|next|sign\s*up|submit|verify|继续|下一步|注册|提交|验证/i;
|
||||||
const GROK_PROFILE_TEXT_PATTERN = /given\s*name|family\s*name|first\s*name|last\s*name|password|名字|姓氏|密码/i;
|
const GROK_PROFILE_TEXT_PATTERN = /given\s*name|family\s*name|first\s*name|last\s*name|password|名字|姓氏|密码/i;
|
||||||
|
const GROK_EMAIL_VERIFICATION_READY_TIMEOUT_MS = 90 * 1000;
|
||||||
const GROK_PROFILE_SUBMIT_PRE_CLICK_DELAY_MS = 2000;
|
const GROK_PROFILE_SUBMIT_PRE_CLICK_DELAY_MS = 2000;
|
||||||
|
|
||||||
function isVisibleGrokElement(element) {
|
function isVisibleGrokElement(element) {
|
||||||
@@ -174,6 +175,29 @@ function getGrokEmailErrorText() {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function waitForGrokVerificationPageAfterEmailSubmit() {
|
||||||
|
const settledState = await waitForGrok(() => {
|
||||||
|
const errorText = getGrokEmailErrorText();
|
||||||
|
if (errorText) return { state: 'email_error', error: errorText, url: location.href };
|
||||||
|
const state = getGrokPageState();
|
||||||
|
return state === 'verification_code_entry' ? { state, url: location.href } : null;
|
||||||
|
}, { timeoutMs: GROK_EMAIL_VERIFICATION_READY_TIMEOUT_MS, intervalMs: 500 });
|
||||||
|
|
||||||
|
if (settledState?.error) {
|
||||||
|
throw new Error(settledState.error);
|
||||||
|
}
|
||||||
|
if (settledState?.state === 'verification_code_entry') {
|
||||||
|
return settledState;
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorText = getGrokEmailErrorText();
|
||||||
|
if (errorText) {
|
||||||
|
throw new Error(errorText);
|
||||||
|
}
|
||||||
|
const finalState = getGrokPageState();
|
||||||
|
throw new Error(`提交 Grok 注册邮箱后未进入验证码页面,当前页面状态:${finalState || 'unknown'}。请确认页面已跳转到“验证您的邮箱”后再继续。`);
|
||||||
|
}
|
||||||
|
|
||||||
async function submitGrokEmail(payload = {}) {
|
async function submitGrokEmail(payload = {}) {
|
||||||
const email = String(payload.email || '').trim();
|
const email = String(payload.email || '').trim();
|
||||||
if (!email) throw new Error('缺少 Grok 注册邮箱。');
|
if (!email) throw new Error('缺少 Grok 注册邮箱。');
|
||||||
@@ -189,7 +213,8 @@ async function submitGrokEmail(payload = {}) {
|
|||||||
if (errorText) {
|
if (errorText) {
|
||||||
throw new Error(errorText);
|
throw new Error(errorText);
|
||||||
}
|
}
|
||||||
return { submitted: true, state: getGrokPageState(), url: location.href };
|
const readyState = await waitForGrokVerificationPageAfterEmailSubmit();
|
||||||
|
return { submitted: true, state: readyState.state, url: readyState.url || location.href };
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGrokVerificationErrorText() {
|
function getGrokVerificationErrorText() {
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@
|
|||||||
stepDefinitionMode: 'grok',
|
stepDefinitionMode: 'grok',
|
||||||
targetSelectorLabel: '来源',
|
targetSelectorLabel: '来源',
|
||||||
},
|
},
|
||||||
baseGroups: ['grok-runtime-status'],
|
baseGroups: ['grok-runtime-status', 'shared-auto-run', 'shared-settings-actions'],
|
||||||
targets: {
|
targets: {
|
||||||
webchat2api: {
|
webchat2api: {
|
||||||
id: 'webchat2api',
|
id: 'webchat2api',
|
||||||
|
|||||||
+7
-1
@@ -40,12 +40,18 @@
|
|||||||
"targetSelectorLabel": "来源"
|
"targetSelectorLabel": "来源"
|
||||||
},
|
},
|
||||||
"baseGroups": [
|
"baseGroups": [
|
||||||
"kiro-runtime-status"
|
"kiro-runtime-status",
|
||||||
|
"shared-auto-run",
|
||||||
|
"shared-settings-actions"
|
||||||
],
|
],
|
||||||
"targets": {
|
"targets": {
|
||||||
"kiro-rs": {
|
"kiro-rs": {
|
||||||
"id": "kiro-rs",
|
"id": "kiro-rs",
|
||||||
"label": "kiro.rs",
|
"label": "kiro.rs",
|
||||||
|
"defaultState": {
|
||||||
|
"baseUrl": "",
|
||||||
|
"apiKey": ""
|
||||||
|
},
|
||||||
"groups": [
|
"groups": [
|
||||||
"kiro-target-kiro-rs"
|
"kiro-target-kiro-rs"
|
||||||
]
|
]
|
||||||
|
|||||||
+48
-2
@@ -46,13 +46,20 @@
|
|||||||
"baseGroups": [
|
"baseGroups": [
|
||||||
"openai-plus",
|
"openai-plus",
|
||||||
"openai-phone",
|
"openai-phone",
|
||||||
|
"shared-auto-run",
|
||||||
"openai-oauth",
|
"openai-oauth",
|
||||||
"openai-step6"
|
"openai-step6",
|
||||||
|
"shared-settings-actions"
|
||||||
],
|
],
|
||||||
"targets": {
|
"targets": {
|
||||||
"cpa": {
|
"cpa": {
|
||||||
"id": "cpa",
|
"id": "cpa",
|
||||||
"label": "CPA 面板",
|
"label": "CPA 面板",
|
||||||
|
"defaultState": {
|
||||||
|
"vpsUrl": "",
|
||||||
|
"vpsPassword": "",
|
||||||
|
"localCpaStep9Mode": "submit"
|
||||||
|
},
|
||||||
"groups": [
|
"groups": [
|
||||||
"openai-target-cpa"
|
"openai-target-cpa"
|
||||||
]
|
]
|
||||||
@@ -60,6 +67,18 @@
|
|||||||
"sub2api": {
|
"sub2api": {
|
||||||
"id": "sub2api",
|
"id": "sub2api",
|
||||||
"label": "SUB2API",
|
"label": "SUB2API",
|
||||||
|
"defaultState": {
|
||||||
|
"sub2apiUrl": "",
|
||||||
|
"sub2apiEmail": "",
|
||||||
|
"sub2apiPassword": "",
|
||||||
|
"sub2apiGroupName": "codex",
|
||||||
|
"sub2apiGroupNames": [
|
||||||
|
"codex",
|
||||||
|
"openai-plus"
|
||||||
|
],
|
||||||
|
"sub2apiAccountPriority": 1,
|
||||||
|
"sub2apiDefaultProxyName": ""
|
||||||
|
},
|
||||||
"groups": [
|
"groups": [
|
||||||
"openai-target-sub2api"
|
"openai-target-sub2api"
|
||||||
]
|
]
|
||||||
@@ -67,11 +86,37 @@
|
|||||||
"codex2api": {
|
"codex2api": {
|
||||||
"id": "codex2api",
|
"id": "codex2api",
|
||||||
"label": "Codex2API",
|
"label": "Codex2API",
|
||||||
|
"defaultState": {
|
||||||
|
"codex2apiUrl": "",
|
||||||
|
"codex2apiAdminKey": ""
|
||||||
|
},
|
||||||
"groups": [
|
"groups": [
|
||||||
"openai-target-codex2api"
|
"openai-target-codex2api"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"settingsDefaults": {
|
||||||
|
"signup": {
|
||||||
|
"signupMethod": "email",
|
||||||
|
"phoneVerificationEnabled": false,
|
||||||
|
"phoneSignupReloginAfterBindEmailEnabled": false
|
||||||
|
},
|
||||||
|
"plus": {
|
||||||
|
"plusModeEnabled": false,
|
||||||
|
"plusPaymentMethod": "paypal-hosted",
|
||||||
|
"plusAccountAccessStrategy": "oauth",
|
||||||
|
"hostedCheckoutVerificationUrl": "",
|
||||||
|
"hostedCheckoutPhoneNumber": "",
|
||||||
|
"plusHostedCheckoutOauthDelaySeconds": 3
|
||||||
|
},
|
||||||
|
"autoRun": {
|
||||||
|
"stepExecutionRange": {
|
||||||
|
"enabled": false,
|
||||||
|
"fromStep": 1,
|
||||||
|
"toStep": 11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"runtimeSources": {
|
"runtimeSources": {
|
||||||
"openai-auth": {
|
"openai-auth": {
|
||||||
"flowId": "openai",
|
"flowId": "openai",
|
||||||
@@ -383,7 +428,8 @@
|
|||||||
"label": "OAuth",
|
"label": "OAuth",
|
||||||
"rowIds": [
|
"rowIds": [
|
||||||
"row-oauth-flow-timeout",
|
"row-oauth-flow-timeout",
|
||||||
"row-oauth-display"
|
"row-oauth-display",
|
||||||
|
"row-oauth-callback"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"openai-step6": {
|
"openai-step6": {
|
||||||
|
|||||||
@@ -1263,7 +1263,7 @@ function updateIpProxyUI(state = latestState) {
|
|||||||
const isAccountMode = mode === 'account';
|
const isAccountMode = mode === 'account';
|
||||||
const showSessionOptions = isAccountMode && service === '711proxy';
|
const showSessionOptions = isAccountMode && service === '711proxy';
|
||||||
const hasAccountListConfigured = accountListAvailable && isAccountMode && hasCurrentInputAccountListEntries();
|
const hasAccountListConfigured = accountListAvailable && isAccountMode && hasCurrentInputAccountListEntries();
|
||||||
const canOperate = !isAutoRunLockedPhase() && !isAutoRunScheduledPhase();
|
const canOperate = !isAutoRunLockedPhase();
|
||||||
const actionState = getIpProxyActionState();
|
const actionState = getIpProxyActionState();
|
||||||
const actionBusy = Boolean(actionState.busy);
|
const actionBusy = Boolean(actionState.busy);
|
||||||
const busyAction = normalizeIpProxyActionType(actionState.action);
|
const busyAction = normalizeIpProxyActionType(actionState.action);
|
||||||
|
|||||||
+19
-23
@@ -1268,6 +1268,19 @@ header {
|
|||||||
width: 76px;
|
width: 76px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#row-flow-selector .data-label,
|
||||||
|
#row-source-selector .data-label,
|
||||||
|
#row-grok-webchat2api-url .data-label,
|
||||||
|
#row-grok-webchat2api-key .data-label,
|
||||||
|
#row-grok-register-status .data-label,
|
||||||
|
#row-grok-sso-status .data-label,
|
||||||
|
#row-grok-webchat2api-upload-status .data-label,
|
||||||
|
#row-grok-sso-settings .data-label {
|
||||||
|
width: 76px;
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
#row-codex2api-url .data-label {
|
#row-codex2api-url .data-label {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
letter-spacing: 0.02em;
|
letter-spacing: 0.02em;
|
||||||
@@ -2197,15 +2210,6 @@ header {
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auto-delay-setting-pair {
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
#row-auto-delay-settings .setting-group-secondary {
|
|
||||||
margin-left: auto;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step6-cookie-cleanup-setting {
|
.step6-cookie-cleanup-setting {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
@@ -2227,10 +2231,6 @@ header {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auto-run-delay-setting {
|
|
||||||
margin-left: auto !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-flow-timeout-setting {
|
.oauth-flow-timeout-setting {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
@@ -2242,10 +2242,6 @@ header {
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
#row-auto-delay-settings .setting-caption {
|
|
||||||
min-width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.setting-caption-left {
|
.setting-caption-left {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
@@ -2720,7 +2716,7 @@ header {
|
|||||||
.auto-continue-bar svg { color: var(--orange); flex-shrink: 0; }
|
.auto-continue-bar svg { color: var(--orange); flex-shrink: 0; }
|
||||||
.auto-hint { font-size: 13px; color: var(--orange); flex: 1; font-weight: 500; }
|
.auto-hint { font-size: 13px; color: var(--orange); flex: 1; font-weight: 500; }
|
||||||
|
|
||||||
.auto-schedule-bar {
|
.auto-countdown-bar {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background: var(--blue-soft);
|
background: var(--blue-soft);
|
||||||
@@ -2732,12 +2728,12 @@ header {
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auto-schedule-bar svg {
|
.auto-countdown-bar svg {
|
||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auto-schedule-copy {
|
.auto-countdown-copy {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
@@ -2745,19 +2741,19 @@ header {
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auto-schedule-title {
|
.auto-countdown-title {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auto-schedule-meta {
|
.auto-countdown-meta {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auto-schedule-actions {
|
.auto-countdown-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
+45
-54
@@ -121,7 +121,7 @@
|
|||||||
|
|
||||||
<section id="data-section">
|
<section id="data-section">
|
||||||
<div id="settings-card" class="data-card">
|
<div id="settings-card" class="data-card">
|
||||||
<div class="data-row">
|
<div class="data-row" id="row-flow-selector">
|
||||||
<span class="data-label">注册</span>
|
<span class="data-label">注册</span>
|
||||||
<select id="select-flow" class="data-select" aria-label="Flow 选择">
|
<select id="select-flow" class="data-select" aria-label="Flow 选择">
|
||||||
<option value="openai" selected>Codex / OpenAI</option>
|
<option value="openai" selected>Codex / OpenAI</option>
|
||||||
@@ -129,13 +129,16 @@
|
|||||||
<option value="grok">Grok</option>
|
<option value="grok">Grok</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="data-row">
|
<div class="data-row" id="row-source-selector">
|
||||||
<span id="label-source-selector" class="data-label">来源</span>
|
<span id="label-source-selector" class="data-label">来源</span>
|
||||||
<select id="select-panel-mode" class="data-select">
|
<div class="data-inline">
|
||||||
<option value="cpa">CPA 面板</option>
|
<select id="select-panel-mode" class="data-select">
|
||||||
<option value="sub2api">SUB2API</option>
|
<option value="cpa">CPA 面板</option>
|
||||||
<option value="codex2api">Codex2API</option>
|
<option value="sub2api">SUB2API</option>
|
||||||
</select>
|
<option value="codex2api">Codex2API</option>
|
||||||
|
</select>
|
||||||
|
<button id="btn-open-webchat2api-github" class="btn btn-ghost btn-xs data-inline-btn" type="button">GitHub</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="contribution-mode-panel" class="contribution-mode-panel" hidden>
|
<div id="contribution-mode-panel" class="contribution-mode-panel" hidden>
|
||||||
<div class="contribution-mode-panel-header">
|
<div class="contribution-mode-panel-header">
|
||||||
@@ -291,20 +294,8 @@
|
|||||||
<span class="data-label">上传状态</span>
|
<span class="data-label">上传状态</span>
|
||||||
<span id="display-kiro-upload-status" class="data-value mono">未开始</span>
|
<span id="display-kiro-upload-status" class="data-value mono">未开始</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="data-row" id="row-grok-register-status" style="display:none;">
|
|
||||||
<span class="data-label">Grok 注册</span>
|
|
||||||
<span id="display-grok-register-status" class="data-value mono">未开始</span>
|
|
||||||
</div>
|
|
||||||
<div class="data-row" id="row-grok-sso-status" style="display:none;">
|
|
||||||
<span class="data-label">SSO 状态</span>
|
|
||||||
<span id="display-grok-sso-status" class="data-value mono">未提取</span>
|
|
||||||
</div>
|
|
||||||
<div class="data-row" id="row-grok-webchat2api-upload-status" style="display:none;">
|
|
||||||
<span class="data-label">上传状态</span>
|
|
||||||
<span id="display-grok-webchat2api-upload-status" class="data-value mono">未开始</span>
|
|
||||||
</div>
|
|
||||||
<div class="data-row" id="row-grok-webchat2api-url" style="display:none;">
|
<div class="data-row" id="row-grok-webchat2api-url" style="display:none;">
|
||||||
<span class="data-label">webchat2api</span>
|
<span class="data-label">webchat</span>
|
||||||
<input type="text" id="input-grok-webchat2api-url" class="data-input"
|
<input type="text" id="input-grok-webchat2api-url" class="data-input"
|
||||||
placeholder="请输入 webchat2api 地址,例如 http://localhost:83" />
|
placeholder="请输入 webchat2api 地址,例如 http://localhost:83" />
|
||||||
</div>
|
</div>
|
||||||
@@ -319,6 +310,18 @@
|
|||||||
title="显示 webchat2api 管理密钥"></button>
|
title="显示 webchat2api 管理密钥"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="data-row" id="row-grok-register-status" style="display:none;">
|
||||||
|
<span class="data-label">Grok 注册</span>
|
||||||
|
<span id="display-grok-register-status" class="data-value mono">未开始</span>
|
||||||
|
</div>
|
||||||
|
<div class="data-row" id="row-grok-sso-status" style="display:none;">
|
||||||
|
<span class="data-label">SSO 状态</span>
|
||||||
|
<span id="display-grok-sso-status" class="data-value mono">未提取</span>
|
||||||
|
</div>
|
||||||
|
<div class="data-row" id="row-grok-webchat2api-upload-status" style="display:none;">
|
||||||
|
<span class="data-label">上传状态</span>
|
||||||
|
<span id="display-grok-webchat2api-upload-status" class="data-value mono">未开始</span>
|
||||||
|
</div>
|
||||||
<div class="data-row" id="row-grok-sso-settings" style="display:none;">
|
<div class="data-row" id="row-grok-sso-settings" style="display:none;">
|
||||||
<span class="data-label">SSO Cookie</span>
|
<span class="data-label">SSO Cookie</span>
|
||||||
<div class="data-inline">
|
<div class="data-inline">
|
||||||
@@ -694,26 +697,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="data-row module-divider-start" id="row-auto-delay-settings">
|
<div class="data-row module-divider-start" id="row-shared-auto-run">
|
||||||
<span class="data-label">启动前</span>
|
|
||||||
<div class="data-inline setting-pair auto-delay-setting-pair">
|
|
||||||
<div class="setting-group setting-group-secondary auto-run-delay-setting">
|
|
||||||
<span class="setting-caption">延迟</span>
|
|
||||||
<label class="toggle-switch" for="input-auto-delay-enabled">
|
|
||||||
<input type="checkbox" id="input-auto-delay-enabled" />
|
|
||||||
<span class="toggle-switch-track" aria-hidden="true">
|
|
||||||
<span class="toggle-switch-thumb"></span>
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
<div class="setting-controls">
|
|
||||||
<input type="number" id="input-auto-delay-minutes" class="data-input auto-delay-input" value="30" min="1"
|
|
||||||
max="1440" step="1" title="启动前倒计时分钟数" />
|
|
||||||
<span class="data-unit">分钟</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="data-row">
|
|
||||||
<span class="data-label">自动重试</span>
|
<span class="data-label">自动重试</span>
|
||||||
<div class="data-inline setting-pair">
|
<div class="data-inline setting-pair">
|
||||||
<div class="setting-group setting-group-primary">
|
<div class="setting-group setting-group-primary">
|
||||||
@@ -734,6 +718,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="data-row" id="row-auto-run-thread-interval">
|
||||||
|
<span class="data-label">线程间隔</span>
|
||||||
|
<div class="data-inline">
|
||||||
|
<div class="setting-controls">
|
||||||
|
<input type="number" id="input-auto-skip-failures-thread-interval-minutes"
|
||||||
|
class="data-input auto-delay-input" value="0" min="0" max="1440" step="1" title="兜底模式下,两轮线程之间的等待分钟数" />
|
||||||
|
<span class="data-unit">分钟</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="data-row" id="row-oauth-flow-timeout">
|
<div class="data-row" id="row-oauth-flow-timeout">
|
||||||
<span class="data-label">授权总超时</span>
|
<span class="data-label">授权总超时</span>
|
||||||
<div class="data-inline setting-pair">
|
<div class="data-inline setting-pair">
|
||||||
@@ -748,14 +742,6 @@
|
|||||||
</label>
|
</label>
|
||||||
<span class="setting-caption oauth-flow-timeout-caption">关闭后只取消 Step 7 后链总预算</span>
|
<span class="setting-caption oauth-flow-timeout-caption">关闭后只取消 Step 7 后链总预算</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-group setting-group-secondary">
|
|
||||||
<span class="setting-caption">线程间隔</span>
|
|
||||||
<div class="setting-controls">
|
|
||||||
<input type="number" id="input-auto-skip-failures-thread-interval-minutes"
|
|
||||||
class="data-input auto-delay-input" value="0" min="0" max="1440" step="1" title="兜底模式下,两轮线程之间的等待分钟数" />
|
|
||||||
<span class="data-unit">分钟</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="data-row" id="row-step-execution-range">
|
<div class="data-row" id="row-step-execution-range">
|
||||||
@@ -782,10 +768,15 @@
|
|||||||
<span class="data-label">OAuth</span>
|
<span class="data-label">OAuth</span>
|
||||||
<span id="display-oauth-url" class="data-value mono truncate">等待中...</span>
|
<span id="display-oauth-url" class="data-value mono truncate">等待中...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="data-row">
|
<div class="data-row" id="row-oauth-callback">
|
||||||
<span class="data-label">回调</span>
|
<span class="data-label">回调</span>
|
||||||
<div class="data-inline data-value-actions">
|
<div class="data-inline data-value-actions">
|
||||||
<span id="display-localhost-url" class="data-value data-value-fill mono truncate">等待中...</span>
|
<span id="display-localhost-url" class="data-value data-value-fill mono truncate">等待中...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="data-row module-divider-start" id="row-settings-actions">
|
||||||
|
<span class="data-label">设置</span>
|
||||||
|
<div class="data-inline data-value-actions">
|
||||||
<button id="btn-save-settings" class="btn btn-outline btn-sm data-inline-btn" type="button">保存</button>
|
<button id="btn-save-settings" class="btn btn-outline btn-sm data-inline-btn" type="button">保存</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1798,16 +1789,16 @@
|
|||||||
<span class="auto-hint">先自动获取邮箱,或手动粘贴邮箱后再继续</span>
|
<span class="auto-hint">先自动获取邮箱,或手动粘贴邮箱后再继续</span>
|
||||||
<button id="btn-auto-continue" class="btn btn-primary btn-sm">继续</button>
|
<button id="btn-auto-continue" class="btn btn-primary btn-sm">继续</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="auto-schedule-bar" class="auto-schedule-bar" style="display:none;">
|
<div id="auto-countdown-bar" class="auto-countdown-bar" style="display:none;">
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<circle cx="12" cy="12" r="10" />
|
<circle cx="12" cy="12" r="10" />
|
||||||
<polyline points="12 6 12 12 16 14" />
|
<polyline points="12 6 12 12 16 14" />
|
||||||
</svg>
|
</svg>
|
||||||
<div class="auto-schedule-copy">
|
<div class="auto-countdown-copy">
|
||||||
<span id="auto-schedule-title" class="auto-schedule-title">已计划自动运行</span>
|
<span id="auto-countdown-title" class="auto-countdown-title">等待继续</span>
|
||||||
<span id="auto-schedule-meta" class="auto-schedule-meta">等待倒计时开始...</span>
|
<span id="auto-countdown-meta" class="auto-countdown-meta">等待倒计时开始...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="auto-schedule-actions">
|
<div class="auto-countdown-actions">
|
||||||
<button id="btn-auto-run-now" class="btn btn-primary btn-sm" type="button">立即开始</button>
|
<button id="btn-auto-run-now" class="btn btn-primary btn-sm" type="button">立即开始</button>
|
||||||
<button id="btn-auto-cancel-schedule" class="btn btn-outline btn-sm" type="button">取消</button>
|
<button id="btn-auto-cancel-schedule" class="btn btn-outline btn-sm" type="button">取消</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+51
-160
@@ -77,11 +77,10 @@ const stepsProgress = document.getElementById('steps-progress');
|
|||||||
const btnAutoRun = document.getElementById('btn-auto-run');
|
const btnAutoRun = document.getElementById('btn-auto-run');
|
||||||
const btnAutoContinue = document.getElementById('btn-auto-continue');
|
const btnAutoContinue = document.getElementById('btn-auto-continue');
|
||||||
const autoContinueBar = document.getElementById('auto-continue-bar');
|
const autoContinueBar = document.getElementById('auto-continue-bar');
|
||||||
const autoScheduleBar = document.getElementById('auto-schedule-bar');
|
const autoCountdownBar = document.getElementById('auto-countdown-bar');
|
||||||
const autoScheduleTitle = document.getElementById('auto-schedule-title');
|
const autoCountdownTitle = document.getElementById('auto-countdown-title');
|
||||||
const autoScheduleMeta = document.getElementById('auto-schedule-meta');
|
const autoCountdownMeta = document.getElementById('auto-countdown-meta');
|
||||||
const btnAutoRunNow = document.getElementById('btn-auto-run-now');
|
const btnAutoRunNow = document.getElementById('btn-auto-run-now');
|
||||||
const btnAutoCancelSchedule = document.getElementById('btn-auto-cancel-schedule');
|
|
||||||
const btnClearLog = document.getElementById('btn-clear-log');
|
const btnClearLog = document.getElementById('btn-clear-log');
|
||||||
const configMenuShell = document.getElementById('config-menu-shell');
|
const configMenuShell = document.getElementById('config-menu-shell');
|
||||||
const btnConfigMenu = document.getElementById('btn-config-menu');
|
const btnConfigMenu = document.getElementById('btn-config-menu');
|
||||||
@@ -91,6 +90,7 @@ const btnImportSettings = document.getElementById('btn-import-settings');
|
|||||||
const inputImportSettingsFile = document.getElementById('input-import-settings-file');
|
const inputImportSettingsFile = document.getElementById('input-import-settings-file');
|
||||||
const labelSourceSelector = document.getElementById('label-source-selector');
|
const labelSourceSelector = document.getElementById('label-source-selector');
|
||||||
const selectPanelMode = document.getElementById('select-panel-mode');
|
const selectPanelMode = document.getElementById('select-panel-mode');
|
||||||
|
const btnOpenWebchat2ApiGithub = document.getElementById('btn-open-webchat2api-github');
|
||||||
const rowVpsUrl = document.getElementById('row-vps-url');
|
const rowVpsUrl = document.getElementById('row-vps-url');
|
||||||
const inputVpsUrl = document.getElementById('input-vps-url');
|
const inputVpsUrl = document.getElementById('input-vps-url');
|
||||||
const rowVpsPassword = document.getElementById('row-vps-password');
|
const rowVpsPassword = document.getElementById('row-vps-password');
|
||||||
@@ -428,8 +428,6 @@ const inputRunCount = document.getElementById('input-run-count');
|
|||||||
const inputAutoSkipFailures = document.getElementById('input-auto-skip-failures');
|
const inputAutoSkipFailures = document.getElementById('input-auto-skip-failures');
|
||||||
const inputAutoSkipFailuresThreadIntervalMinutes = document.getElementById('input-auto-skip-failures-thread-interval-minutes');
|
const inputAutoSkipFailuresThreadIntervalMinutes = document.getElementById('input-auto-skip-failures-thread-interval-minutes');
|
||||||
const inputStep6CookieCleanupEnabled = document.getElementById('input-step6-cookie-cleanup-enabled');
|
const inputStep6CookieCleanupEnabled = document.getElementById('input-step6-cookie-cleanup-enabled');
|
||||||
const inputAutoDelayEnabled = document.getElementById('input-auto-delay-enabled');
|
|
||||||
const inputAutoDelayMinutes = document.getElementById('input-auto-delay-minutes');
|
|
||||||
const inputAutoStepDelaySeconds = document.getElementById('input-auto-step-delay-seconds');
|
const inputAutoStepDelaySeconds = document.getElementById('input-auto-step-delay-seconds');
|
||||||
const inputOAuthFlowTimeoutEnabled = document.getElementById('input-oauth-flow-timeout-enabled');
|
const inputOAuthFlowTimeoutEnabled = document.getElementById('input-oauth-flow-timeout-enabled');
|
||||||
const rowStepExecutionRange = document.getElementById('row-step-execution-range');
|
const rowStepExecutionRange = document.getElementById('row-step-execution-range');
|
||||||
@@ -628,9 +626,6 @@ let SKIPPABLE_STEPS = new Set(STEP_IDS);
|
|||||||
let NODE_IDS = workflowNodes.map((node) => String(node.nodeId || '').trim()).filter(Boolean);
|
let NODE_IDS = workflowNodes.map((node) => String(node.nodeId || '').trim()).filter(Boolean);
|
||||||
let NODE_DEFAULT_STATUSES = Object.fromEntries(NODE_IDS.map((nodeId) => [nodeId, 'pending']));
|
let NODE_DEFAULT_STATUSES = Object.fromEntries(NODE_IDS.map((nodeId) => [nodeId, 'pending']));
|
||||||
let SKIPPABLE_NODES = new Set(NODE_IDS);
|
let SKIPPABLE_NODES = new Set(NODE_IDS);
|
||||||
const AUTO_DELAY_MIN_MINUTES = 1;
|
|
||||||
const AUTO_DELAY_MAX_MINUTES = 1440;
|
|
||||||
const AUTO_DELAY_DEFAULT_MINUTES = 30;
|
|
||||||
const AUTO_FALLBACK_THREAD_INTERVAL_MIN_MINUTES = 0;
|
const AUTO_FALLBACK_THREAD_INTERVAL_MIN_MINUTES = 0;
|
||||||
const AUTO_FALLBACK_THREAD_INTERVAL_MAX_MINUTES = 1440;
|
const AUTO_FALLBACK_THREAD_INTERVAL_MAX_MINUTES = 1440;
|
||||||
const AUTO_FALLBACK_THREAD_INTERVAL_DEFAULT_MINUTES = 0;
|
const AUTO_FALLBACK_THREAD_INTERVAL_DEFAULT_MINUTES = 0;
|
||||||
@@ -1365,7 +1360,6 @@ let currentAutoRun = {
|
|||||||
currentRun: 0,
|
currentRun: 0,
|
||||||
totalRuns: 1,
|
totalRuns: 1,
|
||||||
attemptRun: 0,
|
attemptRun: 0,
|
||||||
scheduledAt: null,
|
|
||||||
countdownAt: null,
|
countdownAt: null,
|
||||||
countdownTitle: '',
|
countdownTitle: '',
|
||||||
countdownNote: '',
|
countdownNote: '',
|
||||||
@@ -1386,7 +1380,7 @@ let currentModalActions = [];
|
|||||||
let modalResultBuilder = null;
|
let modalResultBuilder = null;
|
||||||
let activePlusManualConfirmationRequestId = '';
|
let activePlusManualConfirmationRequestId = '';
|
||||||
let plusManualConfirmationDialogInFlight = false;
|
let plusManualConfirmationDialogInFlight = false;
|
||||||
let scheduledCountdownTimer = null;
|
let autoRunCountdownTimer = null;
|
||||||
let configMenuOpen = false;
|
let configMenuOpen = false;
|
||||||
let configActionInFlight = false;
|
let configActionInFlight = false;
|
||||||
let currentReleaseSnapshot = null;
|
let currentReleaseSnapshot = null;
|
||||||
@@ -1426,9 +1420,7 @@ function shouldAttachAutomationWindow(message = {}) {
|
|||||||
return [
|
return [
|
||||||
'EXECUTE_NODE',
|
'EXECUTE_NODE',
|
||||||
'AUTO_RUN',
|
'AUTO_RUN',
|
||||||
'SCHEDULE_AUTO_RUN',
|
|
||||||
'RESUME_AUTO_RUN',
|
'RESUME_AUTO_RUN',
|
||||||
'START_SCHEDULED_AUTO_RUN_NOW',
|
|
||||||
'SKIP_AUTO_RUN_COUNTDOWN',
|
'SKIP_AUTO_RUN_COUNTDOWN',
|
||||||
'PROBE_IP_PROXY_EXIT',
|
'PROBE_IP_PROXY_EXIT',
|
||||||
].includes(String(message?.type || '').trim());
|
].includes(String(message?.type || '').trim());
|
||||||
@@ -1680,7 +1672,6 @@ const ICLOUD_FORWARD_MAIL_PROVIDER_LABELS = Object.fromEntries(
|
|||||||
const getIcloudLoginUrlForHost = window.IcloudUtils?.getIcloudLoginUrlForHost
|
const getIcloudLoginUrlForHost = window.IcloudUtils?.getIcloudLoginUrlForHost
|
||||||
|| ((host) => host === 'icloud.com.cn' ? 'https://www.icloud.com.cn/' : (host === 'icloud.com' ? 'https://www.icloud.com/' : ''));
|
|| ((host) => host === 'icloud.com.cn' ? 'https://www.icloud.com.cn/' : (host === 'icloud.com' ? 'https://www.icloud.com/' : ''));
|
||||||
|
|
||||||
btnAutoCancelSchedule?.remove();
|
|
||||||
const MAIL_PROVIDER_LOGIN_CONFIGS = {
|
const MAIL_PROVIDER_LOGIN_CONFIGS = {
|
||||||
[ICLOUD_PROVIDER]: {
|
[ICLOUD_PROVIDER]: {
|
||||||
label: 'iCloud 邮箱',
|
label: 'iCloud 邮箱',
|
||||||
@@ -2982,7 +2973,7 @@ function applyStepExecutionRangeState(state = latestState) {
|
|||||||
if (inputStepExecutionRangeEnabled) {
|
if (inputStepExecutionRangeEnabled) {
|
||||||
inputStepExecutionRangeEnabled.checked = Boolean(range.enabled);
|
inputStepExecutionRangeEnabled.checked = Boolean(range.enabled);
|
||||||
}
|
}
|
||||||
const controlsDisabled = !available || isAutoRunLockedPhase() || isAutoRunScheduledPhase();
|
const controlsDisabled = !available || isAutoRunLockedPhase();
|
||||||
if (inputStepExecutionRangeEnabled) inputStepExecutionRangeEnabled.disabled = controlsDisabled;
|
if (inputStepExecutionRangeEnabled) inputStepExecutionRangeEnabled.disabled = controlsDisabled;
|
||||||
if (inputStepExecutionRangeFrom) inputStepExecutionRangeFrom.disabled = controlsDisabled || !inputStepExecutionRangeEnabled?.checked;
|
if (inputStepExecutionRangeFrom) inputStepExecutionRangeFrom.disabled = controlsDisabled || !inputStepExecutionRangeEnabled?.checked;
|
||||||
if (inputStepExecutionRangeTo) inputStepExecutionRangeTo.disabled = controlsDisabled || !inputStepExecutionRangeEnabled?.checked;
|
if (inputStepExecutionRangeTo) inputStepExecutionRangeTo.disabled = controlsDisabled || !inputStepExecutionRangeEnabled?.checked;
|
||||||
@@ -3083,7 +3074,7 @@ function hasSavedProgress(state = latestState) {
|
|||||||
function isContributionModeSwitchBlocked(state = latestState) {
|
function isContributionModeSwitchBlocked(state = latestState) {
|
||||||
const statuses = getStepStatuses(state);
|
const statuses = getStepStatuses(state);
|
||||||
const anyRunning = Object.values(statuses).some((status) => status === 'running');
|
const anyRunning = Object.values(statuses).some((status) => status === 'running');
|
||||||
return anyRunning || isAutoRunLockedPhase() || isAutoRunPausedPhase() || isAutoRunScheduledPhase();
|
return anyRunning || isAutoRunLockedPhase() || isAutoRunPausedPhase();
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldOfferAutoModeChoice(state = latestState) {
|
function shouldOfferAutoModeChoice(state = latestState) {
|
||||||
@@ -3630,7 +3621,7 @@ function syncAutoRunState(source = {}) {
|
|||||||
const autoRunning = source.autoRunning !== undefined
|
const autoRunning = source.autoRunning !== undefined
|
||||||
? Boolean(source.autoRunning)
|
? Boolean(source.autoRunning)
|
||||||
: (source.autoRunPhase !== undefined || source.phase !== undefined
|
: (source.autoRunPhase !== undefined || source.phase !== undefined
|
||||||
? ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase)
|
? ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase)
|
||||||
: currentAutoRun.autoRunning);
|
: currentAutoRun.autoRunning);
|
||||||
|
|
||||||
currentAutoRun = {
|
currentAutoRun = {
|
||||||
@@ -3639,7 +3630,6 @@ function syncAutoRunState(source = {}) {
|
|||||||
currentRun: readAutoRunStateValue(source, ['autoRunCurrentRun', 'currentRun'], currentAutoRun.currentRun),
|
currentRun: readAutoRunStateValue(source, ['autoRunCurrentRun', 'currentRun'], currentAutoRun.currentRun),
|
||||||
totalRuns: readAutoRunStateValue(source, ['autoRunTotalRuns', 'totalRuns'], currentAutoRun.totalRuns),
|
totalRuns: readAutoRunStateValue(source, ['autoRunTotalRuns', 'totalRuns'], currentAutoRun.totalRuns),
|
||||||
attemptRun: readAutoRunStateValue(source, ['autoRunAttemptRun', 'attemptRun'], currentAutoRun.attemptRun),
|
attemptRun: readAutoRunStateValue(source, ['autoRunAttemptRun', 'attemptRun'], currentAutoRun.attemptRun),
|
||||||
scheduledAt: readAutoRunStateValue(source, ['scheduledAutoRunAt', 'scheduledAt'], currentAutoRun.scheduledAt),
|
|
||||||
countdownAt: readAutoRunStateValue(source, ['autoRunCountdownAt', 'countdownAt'], currentAutoRun.countdownAt),
|
countdownAt: readAutoRunStateValue(source, ['autoRunCountdownAt', 'countdownAt'], currentAutoRun.countdownAt),
|
||||||
countdownTitle: readAutoRunStateValue(source, ['autoRunCountdownTitle', 'countdownTitle'], currentAutoRun.countdownTitle),
|
countdownTitle: readAutoRunStateValue(source, ['autoRunCountdownTitle', 'countdownTitle'], currentAutoRun.countdownTitle),
|
||||||
countdownNote: readAutoRunStateValue(source, ['autoRunCountdownNote', 'countdownNote'], currentAutoRun.countdownNote),
|
countdownNote: readAutoRunStateValue(source, ['autoRunCountdownNote', 'countdownNote'], currentAutoRun.countdownNote),
|
||||||
@@ -3649,8 +3639,7 @@ function syncAutoRunState(source = {}) {
|
|||||||
function isContributionButtonLocked() {
|
function isContributionButtonLocked() {
|
||||||
const autoActive = currentAutoRun.autoRunning
|
const autoActive = currentAutoRun.autoRunning
|
||||||
|| isAutoRunLockedPhase()
|
|| isAutoRunLockedPhase()
|
||||||
|| isAutoRunPausedPhase()
|
|| isAutoRunPausedPhase();
|
||||||
|| isAutoRunScheduledPhase();
|
|
||||||
if (autoActive) {
|
if (autoActive) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -3675,12 +3664,8 @@ function isAutoRunWaitingStepPhase() {
|
|||||||
return currentAutoRun.phase === 'waiting_step';
|
return currentAutoRun.phase === 'waiting_step';
|
||||||
}
|
}
|
||||||
|
|
||||||
function isAutoRunScheduledPhase() {
|
|
||||||
return currentAutoRun.phase === 'scheduled';
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAutoRunSourceSyncPhase(phase) {
|
function isAutoRunSourceSyncPhase(phase) {
|
||||||
return ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
|
return ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldSyncRunCountFromAutoRunSource(source = {}) {
|
function shouldSyncRunCountFromAutoRunSource(source = {}) {
|
||||||
@@ -3717,14 +3702,6 @@ function getAutoRunLabel(payload = currentAutoRun) {
|
|||||||
return attemptLabel ? ` (${attemptLabel.slice(3)})` : '';
|
return attemptLabel ? ` (${attemptLabel.slice(3)})` : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeAutoDelayMinutes(value) {
|
|
||||||
const numeric = Number(value);
|
|
||||||
if (!Number.isFinite(numeric)) {
|
|
||||||
return AUTO_DELAY_DEFAULT_MINUTES;
|
|
||||||
}
|
|
||||||
return Math.min(AUTO_DELAY_MAX_MINUTES, Math.max(AUTO_DELAY_MIN_MINUTES, Math.floor(numeric)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeAutoRunThreadIntervalMinutes(value) {
|
function normalizeAutoRunThreadIntervalMinutes(value) {
|
||||||
const rawValue = String(value ?? '').trim();
|
const rawValue = String(value ?? '').trim();
|
||||||
if (!rawValue) {
|
if (!rawValue) {
|
||||||
@@ -3948,12 +3925,6 @@ function updateFallbackThreadIntervalInputState() {
|
|||||||
inputAutoSkipFailuresThreadIntervalMinutes.disabled = Boolean(inputAutoSkipFailures.disabled);
|
inputAutoSkipFailuresThreadIntervalMinutes.disabled = Boolean(inputAutoSkipFailures.disabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAutoDelayInputState() {
|
|
||||||
const scheduled = isAutoRunScheduledPhase();
|
|
||||||
inputAutoDelayEnabled.disabled = scheduled;
|
|
||||||
inputAutoDelayMinutes.disabled = scheduled || !inputAutoDelayEnabled.checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatCountdown(remainingMs) {
|
function formatCountdown(remainingMs) {
|
||||||
const totalSeconds = Math.max(0, Math.ceil(remainingMs / 1000));
|
const totalSeconds = Math.max(0, Math.ceil(remainingMs / 1000));
|
||||||
const hours = Math.floor(totalSeconds / 3600);
|
const hours = Math.floor(totalSeconds / 3600);
|
||||||
@@ -3974,21 +3945,12 @@ function formatScheduleTime(timestamp) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopScheduledCountdownTicker() {
|
function stopAutoRunCountdownTicker() {
|
||||||
clearInterval(scheduledCountdownTimer);
|
clearInterval(autoRunCountdownTimer);
|
||||||
scheduledCountdownTimer = null;
|
autoRunCountdownTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveAutoRunCountdown() {
|
function getActiveAutoRunCountdown() {
|
||||||
if (isAutoRunScheduledPhase() && Number.isFinite(currentAutoRun.scheduledAt)) {
|
|
||||||
return {
|
|
||||||
at: currentAutoRun.scheduledAt,
|
|
||||||
title: '已计划自动运行',
|
|
||||||
note: `计划于 ${formatScheduleTime(currentAutoRun.scheduledAt)} 开始`,
|
|
||||||
tone: 'scheduled',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentAutoRun.phase !== 'waiting_interval') {
|
if (currentAutoRun.phase !== 'waiting_interval') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -4005,48 +3967,45 @@ function getActiveAutoRunCountdown() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderScheduledAutoRunInfo() {
|
function renderAutoRunCountdownInfo() {
|
||||||
if (!autoScheduleBar) {
|
if (!autoCountdownBar) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const countdown = getActiveAutoRunCountdown();
|
const countdown = getActiveAutoRunCountdown();
|
||||||
if (!countdown) {
|
if (!countdown) {
|
||||||
autoScheduleBar.style.display = 'none';
|
autoCountdownBar.style.display = 'none';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const remainingMs = countdown.at - Date.now();
|
const remainingMs = countdown.at - Date.now();
|
||||||
autoScheduleBar.style.display = 'flex';
|
autoCountdownBar.style.display = 'flex';
|
||||||
if (btnAutoRunNow) {
|
if (btnAutoRunNow) {
|
||||||
btnAutoRunNow.hidden = false;
|
btnAutoRunNow.hidden = false;
|
||||||
btnAutoRunNow.textContent = currentAutoRun.phase === 'waiting_interval' ? '立即继续' : '立即开始';
|
btnAutoRunNow.textContent = '立即继续';
|
||||||
}
|
}
|
||||||
if (btnAutoCancelSchedule) {
|
autoCountdownTitle.textContent = countdown.title;
|
||||||
btnAutoCancelSchedule.hidden = true;
|
autoCountdownMeta.textContent = remainingMs > 0
|
||||||
}
|
|
||||||
autoScheduleTitle.textContent = countdown.title;
|
|
||||||
autoScheduleMeta.textContent = remainingMs > 0
|
|
||||||
? `${countdown.note ? `${countdown.note},` : ''}剩余 ${formatCountdown(remainingMs)}`
|
? `${countdown.note ? `${countdown.note},` : ''}剩余 ${formatCountdown(remainingMs)}`
|
||||||
: '倒计时即将结束,正在准备继续...';
|
: '倒计时即将结束,正在准备继续...';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncScheduledCountdownTicker() {
|
function syncAutoRunCountdownTicker() {
|
||||||
renderScheduledAutoRunInfo();
|
renderAutoRunCountdownInfo();
|
||||||
if (getActiveAutoRunCountdown()) {
|
if (getActiveAutoRunCountdown()) {
|
||||||
if (scheduledCountdownTimer) {
|
if (autoRunCountdownTimer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduledCountdownTimer = setInterval(() => {
|
autoRunCountdownTimer = setInterval(() => {
|
||||||
renderScheduledAutoRunInfo();
|
renderAutoRunCountdownInfo();
|
||||||
updateStatusDisplay(latestState);
|
updateStatusDisplay(latestState);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stopScheduledCountdownTicker();
|
stopAutoRunCountdownTicker();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5159,8 +5118,6 @@ function collectSettingsPayload() {
|
|||||||
stepExecutionRangeByFlow: typeof buildStepExecutionRangeByFlowPayload === 'function'
|
stepExecutionRangeByFlow: typeof buildStepExecutionRangeByFlowPayload === 'function'
|
||||||
? buildStepExecutionRangeByFlowPayload(latestState?.stepExecutionRangeByFlow)
|
? buildStepExecutionRangeByFlowPayload(latestState?.stepExecutionRangeByFlow)
|
||||||
: (latestState?.stepExecutionRangeByFlow || {}),
|
: (latestState?.stepExecutionRangeByFlow || {}),
|
||||||
autoRunDelayEnabled: inputAutoDelayEnabled.checked,
|
|
||||||
autoRunDelayMinutes: normalizeAutoDelayMinutes(inputAutoDelayMinutes.value),
|
|
||||||
autoStepDelaySeconds: normalizeAutoStepDelaySeconds(inputAutoStepDelaySeconds.value),
|
autoStepDelaySeconds: normalizeAutoStepDelaySeconds(inputAutoStepDelaySeconds.value),
|
||||||
oauthFlowTimeoutEnabled: typeof inputOAuthFlowTimeoutEnabled !== 'undefined' && inputOAuthFlowTimeoutEnabled
|
oauthFlowTimeoutEnabled: typeof inputOAuthFlowTimeoutEnabled !== 'undefined' && inputOAuthFlowTimeoutEnabled
|
||||||
? Boolean(inputOAuthFlowTimeoutEnabled.checked)
|
? Boolean(inputOAuthFlowTimeoutEnabled.checked)
|
||||||
@@ -9337,7 +9294,7 @@ function canSelectPhoneSignupMethod() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isSignupMethodSwitchLocked() {
|
function isSignupMethodSwitchLocked() {
|
||||||
return isAutoRunLockedPhase() || isAutoRunPausedPhase() || isAutoRunScheduledPhase();
|
return isAutoRunLockedPhase() || isAutoRunPausedPhase();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSignupMethodUI(options = {}) {
|
function updateSignupMethodUI(options = {}) {
|
||||||
@@ -9581,7 +9538,7 @@ function updatePhoneVerificationSettingsUI() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
phoneSignupReuseUiWasLocked = phoneSignupReuseLocked;
|
phoneSignupReuseUiWasLocked = phoneSignupReuseLocked;
|
||||||
const settingsLocked = isAutoRunLockedPhase() || isAutoRunScheduledPhase();
|
const settingsLocked = isAutoRunLockedPhase();
|
||||||
if (typeof inputPhoneSignupReloginAfterBindEmail !== 'undefined' && inputPhoneSignupReloginAfterBindEmail) {
|
if (typeof inputPhoneSignupReloginAfterBindEmail !== 'undefined' && inputPhoneSignupReloginAfterBindEmail) {
|
||||||
inputPhoneSignupReloginAfterBindEmail.disabled = settingsLocked || !showPhoneSignupReloginAfterBindEmail;
|
inputPhoneSignupReloginAfterBindEmail.disabled = settingsLocked || !showPhoneSignupReloginAfterBindEmail;
|
||||||
}
|
}
|
||||||
@@ -10744,8 +10701,7 @@ function applyAutoRunStatus(payload = currentAutoRun) {
|
|||||||
const runLabel = getAutoRunLabel(currentAutoRun);
|
const runLabel = getAutoRunLabel(currentAutoRun);
|
||||||
const locked = isAutoRunLockedPhase();
|
const locked = isAutoRunLockedPhase();
|
||||||
const paused = isAutoRunPausedPhase();
|
const paused = isAutoRunPausedPhase();
|
||||||
const scheduled = isAutoRunScheduledPhase();
|
const settingsCardLocked = locked;
|
||||||
const settingsCardLocked = scheduled || locked;
|
|
||||||
|
|
||||||
setSettingsCardLocked(settingsCardLocked);
|
setSettingsCardLocked(settingsCardLocked);
|
||||||
setFreePhoneReuseControlsLocked(settingsCardLocked);
|
setFreePhoneReuseControlsLocked(settingsCardLocked);
|
||||||
@@ -10766,14 +10722,14 @@ function applyAutoRunStatus(payload = currentAutoRun) {
|
|||||||
if (typeof inputSub2ApiAccountPriority !== 'undefined' && inputSub2ApiAccountPriority) {
|
if (typeof inputSub2ApiAccountPriority !== 'undefined' && inputSub2ApiAccountPriority) {
|
||||||
inputSub2ApiAccountPriority.disabled = locked;
|
inputSub2ApiAccountPriority.disabled = locked;
|
||||||
}
|
}
|
||||||
inputAutoSkipFailures.disabled = scheduled;
|
inputAutoSkipFailures.disabled = locked;
|
||||||
|
|
||||||
const lockedRunCount = typeof getLockedRunCountFromEmailPool === 'function'
|
const lockedRunCount = typeof getLockedRunCountFromEmailPool === 'function'
|
||||||
? getLockedRunCountFromEmailPool()
|
? getLockedRunCountFromEmailPool()
|
||||||
: 0;
|
: 0;
|
||||||
const isSyncPhase = typeof isAutoRunSourceSyncPhase === 'function'
|
const isSyncPhase = typeof isAutoRunSourceSyncPhase === 'function'
|
||||||
? isAutoRunSourceSyncPhase
|
? isAutoRunSourceSyncPhase
|
||||||
: (phase) => ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
|
: (phase) => ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
|
||||||
const shouldSyncRunCount = typeof shouldSyncRunCountFromAutoRunSource === 'function'
|
const shouldSyncRunCount = typeof shouldSyncRunCountFromAutoRunSource === 'function'
|
||||||
? shouldSyncRunCountFromAutoRunSource(currentAutoRun)
|
? shouldSyncRunCountFromAutoRunSource(currentAutoRun)
|
||||||
: (currentAutoRun.autoRunning || isSyncPhase(currentAutoRun.phase));
|
: (currentAutoRun.autoRunning || isSyncPhase(currentAutoRun.phase));
|
||||||
@@ -10784,10 +10740,6 @@ function applyAutoRunStatus(payload = currentAutoRun) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (currentAutoRun.phase) {
|
switch (currentAutoRun.phase) {
|
||||||
case 'scheduled':
|
|
||||||
autoContinueBar.style.display = 'none';
|
|
||||||
btnAutoRun.innerHTML = `已计划${runLabel}`;
|
|
||||||
break;
|
|
||||||
case 'waiting_step':
|
case 'waiting_step':
|
||||||
autoContinueBar.style.display = 'none';
|
autoContinueBar.style.display = 'none';
|
||||||
btnAutoRun.innerHTML = `等待中${runLabel}`;
|
btnAutoRun.innerHTML = `等待中${runLabel}`;
|
||||||
@@ -10818,10 +10770,9 @@ function applyAutoRunStatus(payload = currentAutoRun) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAutoDelayInputState();
|
|
||||||
updateFallbackThreadIntervalInputState();
|
updateFallbackThreadIntervalInputState();
|
||||||
syncScheduledCountdownTicker();
|
syncAutoRunCountdownTicker();
|
||||||
updateStopButtonState(scheduled || paused || locked || Object.values(getStepStatuses()).some(status => status === 'running'));
|
updateStopButtonState(paused || locked || Object.values(getStepStatuses()).some(status => status === 'running'));
|
||||||
updateConfigMenuControls();
|
updateConfigMenuControls();
|
||||||
renderContributionMode();
|
renderContributionMode();
|
||||||
}
|
}
|
||||||
@@ -11422,8 +11373,6 @@ function applySettingsState(state) {
|
|||||||
if (typeof inputStep6CookieCleanupEnabled !== 'undefined' && inputStep6CookieCleanupEnabled) {
|
if (typeof inputStep6CookieCleanupEnabled !== 'undefined' && inputStep6CookieCleanupEnabled) {
|
||||||
inputStep6CookieCleanupEnabled.checked = Boolean(state?.step6CookieCleanupEnabled);
|
inputStep6CookieCleanupEnabled.checked = Boolean(state?.step6CookieCleanupEnabled);
|
||||||
}
|
}
|
||||||
inputAutoDelayEnabled.checked = Boolean(state?.autoRunDelayEnabled);
|
|
||||||
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(state?.autoRunDelayMinutes));
|
|
||||||
inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(state?.autoStepDelaySeconds);
|
inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(state?.autoStepDelaySeconds);
|
||||||
if (typeof inputOAuthFlowTimeoutEnabled !== 'undefined' && inputOAuthFlowTimeoutEnabled) {
|
if (typeof inputOAuthFlowTimeoutEnabled !== 'undefined' && inputOAuthFlowTimeoutEnabled) {
|
||||||
inputOAuthFlowTimeoutEnabled.checked = state?.oauthFlowTimeoutEnabled !== undefined
|
inputOAuthFlowTimeoutEnabled.checked = state?.oauthFlowTimeoutEnabled !== undefined
|
||||||
@@ -11598,7 +11547,7 @@ function applySettingsState(state) {
|
|||||||
}
|
}
|
||||||
const isSyncPhase = typeof isAutoRunSourceSyncPhase === 'function'
|
const isSyncPhase = typeof isAutoRunSourceSyncPhase === 'function'
|
||||||
? isAutoRunSourceSyncPhase
|
? isAutoRunSourceSyncPhase
|
||||||
: (phase) => ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
|
: (phase) => ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase);
|
||||||
const shouldSyncInitialRunCount = typeof shouldSyncRunCountFromAutoRunSource === 'function'
|
const shouldSyncInitialRunCount = typeof shouldSyncRunCountFromAutoRunSource === 'function'
|
||||||
? shouldSyncRunCountFromAutoRunSource(state)
|
? shouldSyncRunCountFromAutoRunSource(state)
|
||||||
: (Boolean(state?.autoRunning) || isSyncPhase(state?.autoRunPhase ?? state?.phase));
|
: (Boolean(state?.autoRunning) || isSyncPhase(state?.autoRunPhase ?? state?.phase));
|
||||||
@@ -11608,7 +11557,6 @@ function applySettingsState(state) {
|
|||||||
|
|
||||||
applyAutoRunStatus(state);
|
applyAutoRunStatus(state);
|
||||||
markSettingsDirty(false);
|
markSettingsDirty(false);
|
||||||
updateAutoDelayInputState();
|
|
||||||
updateFallbackThreadIntervalInputState();
|
updateFallbackThreadIntervalInputState();
|
||||||
updateAccountRunHistorySettingsUI();
|
updateAccountRunHistorySettingsUI();
|
||||||
updatePhoneVerificationSettingsUI();
|
updatePhoneVerificationSettingsUI();
|
||||||
@@ -13657,7 +13605,6 @@ function updateButtonStates() {
|
|||||||
const statuses = getNodeStatuses();
|
const statuses = getNodeStatuses();
|
||||||
const anyRunning = Object.values(statuses).some(s => s === 'running');
|
const anyRunning = Object.values(statuses).some(s => s === 'running');
|
||||||
const autoLocked = isAutoRunLockedPhase();
|
const autoLocked = isAutoRunLockedPhase();
|
||||||
const autoScheduled = isAutoRunScheduledPhase();
|
|
||||||
const enabledNodeIds = getEnabledNodeIdsForStepExecutionRange(latestState);
|
const enabledNodeIds = getEnabledNodeIdsForStepExecutionRange(latestState);
|
||||||
const icloudTargetMailboxTypeValue = typeof selectIcloudTargetMailboxType !== 'undefined'
|
const icloudTargetMailboxTypeValue = typeof selectIcloudTargetMailboxType !== 'undefined'
|
||||||
? selectIcloudTargetMailboxType?.value
|
? selectIcloudTargetMailboxType?.value
|
||||||
@@ -13671,7 +13618,7 @@ function updateButtonStates() {
|
|||||||
|
|
||||||
if (currentStatus === 'disabled') {
|
if (currentStatus === 'disabled') {
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
} else if (anyRunning || autoLocked || autoScheduled) {
|
} else if (anyRunning || autoLocked) {
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
} else if (enabledNodeIds.indexOf(nodeId) === 0) {
|
} else if (enabledNodeIds.indexOf(nodeId) === 0) {
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
@@ -13691,7 +13638,7 @@ function updateButtonStates() {
|
|||||||
const prevNodeId = currentIndex > 0 ? enabledNodeIds[currentIndex - 1] : null;
|
const prevNodeId = currentIndex > 0 ? enabledNodeIds[currentIndex - 1] : null;
|
||||||
const prevStatus = prevNodeId === null ? 'completed' : statuses[prevNodeId];
|
const prevStatus = prevNodeId === null ? 'completed' : statuses[prevNodeId];
|
||||||
|
|
||||||
if (!SKIPPABLE_NODES.has(nodeId) || currentStatus === 'disabled' || anyRunning || autoLocked || autoScheduled || currentStatus === 'running' || isDoneStatus(currentStatus)) {
|
if (!SKIPPABLE_NODES.has(nodeId) || currentStatus === 'disabled' || anyRunning || autoLocked || currentStatus === 'running' || isDoneStatus(currentStatus)) {
|
||||||
btn.style.display = 'none';
|
btn.style.display = 'none';
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.title = '当前不可跳过';
|
btn.title = '当前不可跳过';
|
||||||
@@ -13710,8 +13657,8 @@ function updateButtonStates() {
|
|||||||
btn.title = `跳过节点 ${nodeId}`;
|
btn.title = `跳过节点 ${nodeId}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
btnReset.disabled = anyRunning || autoScheduled || isAutoRunPausedPhase() || autoLocked;
|
btnReset.disabled = anyRunning || isAutoRunPausedPhase() || autoLocked;
|
||||||
const disableIcloudControls = anyRunning || autoScheduled || autoLocked;
|
const disableIcloudControls = anyRunning || autoLocked;
|
||||||
if (btnIcloudRefresh) btnIcloudRefresh.disabled = disableIcloudControls;
|
if (btnIcloudRefresh) btnIcloudRefresh.disabled = disableIcloudControls;
|
||||||
if (btnIcloudDeleteUsed) btnIcloudDeleteUsed.disabled = disableIcloudControls || !hasDeletableUsedIcloudAliases();
|
if (btnIcloudDeleteUsed) btnIcloudDeleteUsed.disabled = disableIcloudControls || !hasDeletableUsedIcloudAliases();
|
||||||
if (selectIcloudHostPreference) selectIcloudHostPreference.disabled = disableIcloudControls;
|
if (selectIcloudHostPreference) selectIcloudHostPreference.disabled = disableIcloudControls;
|
||||||
@@ -13733,7 +13680,7 @@ function updateButtonStates() {
|
|||||||
if (checkboxAutoDeleteIcloud) checkboxAutoDeleteIcloud.disabled = disableIcloudControls;
|
if (checkboxAutoDeleteIcloud) checkboxAutoDeleteIcloud.disabled = disableIcloudControls;
|
||||||
if (btnContributionMode) btnContributionMode.disabled = isContributionButtonLocked();
|
if (btnContributionMode) btnContributionMode.disabled = isContributionButtonLocked();
|
||||||
applyStepExecutionRangeState(latestState);
|
applyStepExecutionRangeState(latestState);
|
||||||
updateStopButtonState(anyRunning || autoScheduled || isAutoRunPausedPhase() || autoLocked);
|
updateStopButtonState(anyRunning || isAutoRunPausedPhase() || autoLocked);
|
||||||
renderContributionMode();
|
renderContributionMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13753,18 +13700,7 @@ function updateStatusDisplay(state) {
|
|||||||
displayStatus.textContent = remainingMs > 0
|
displayStatus.textContent = remainingMs > 0
|
||||||
? `${countdown.title},剩余 ${formatCountdown(remainingMs)}`
|
? `${countdown.title},剩余 ${formatCountdown(remainingMs)}`
|
||||||
: `${countdown.title},即将结束...`;
|
: `${countdown.title},即将结束...`;
|
||||||
statusBar.classList.add(countdown.tone === 'scheduled' ? 'scheduled' : 'running');
|
statusBar.classList.add('running');
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAutoRunScheduledPhase()) {
|
|
||||||
const remainingMs = Number.isFinite(currentAutoRun.scheduledAt)
|
|
||||||
? currentAutoRun.scheduledAt - Date.now()
|
|
||||||
: 0;
|
|
||||||
displayStatus.textContent = remainingMs > 0
|
|
||||||
? `自动计划中,剩余 ${formatCountdown(remainingMs)}`
|
|
||||||
: '倒计时即将结束,正在准备启动...';
|
|
||||||
statusBar.classList.add('scheduled');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14973,7 +14909,7 @@ btnSaveSettings.addEventListener('click', async () => {
|
|||||||
btnStop.addEventListener('click', async () => {
|
btnStop.addEventListener('click', async () => {
|
||||||
btnStop.disabled = true;
|
btnStop.disabled = true;
|
||||||
await chrome.runtime.sendMessage({ type: 'STOP_FLOW', source: 'sidepanel', payload: {} });
|
await chrome.runtime.sendMessage({ type: 'STOP_FLOW', source: 'sidepanel', payload: {} });
|
||||||
showToast(isAutoRunScheduledPhase() ? '正在取消倒计时计划...' : '正在停止当前流程...', 'warn', 2000);
|
showToast(currentAutoRun.phase === 'waiting_interval' ? '正在取消等待中的倒计时...' : '正在停止当前流程...', 'warn', 2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
btnConfigMenu?.addEventListener('click', (event) => {
|
btnConfigMenu?.addEventListener('click', (event) => {
|
||||||
@@ -15150,24 +15086,18 @@ async function startAutoRunFromCurrentSettings() {
|
|||||||
|
|
||||||
btnAutoRun.disabled = true;
|
btnAutoRun.disabled = true;
|
||||||
inputRunCount.disabled = true;
|
inputRunCount.disabled = true;
|
||||||
const delayEnabled = inputAutoDelayEnabled.checked;
|
|
||||||
const delayMinutes = normalizeAutoDelayMinutes(inputAutoDelayMinutes.value);
|
|
||||||
const activeFlowId = typeof getSelectedFlowId === 'function'
|
const activeFlowId = typeof getSelectedFlowId === 'function'
|
||||||
? getSelectedFlowId(latestState)
|
? getSelectedFlowId(latestState)
|
||||||
: (String(latestState?.activeFlowId || latestState?.flowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID);
|
: (String(latestState?.activeFlowId || latestState?.flowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID);
|
||||||
const targetId = typeof getSelectedTargetId === 'function'
|
const targetId = typeof getSelectedTargetId === 'function'
|
||||||
? getSelectedTargetId(activeFlowId)
|
? getSelectedTargetId(activeFlowId)
|
||||||
: normalizeTargetIdForFlow(activeFlowId, latestState?.targetId || '', getDefaultTargetIdForFlow(activeFlowId));
|
: normalizeTargetIdForFlow(activeFlowId, latestState?.targetId || '', getDefaultTargetIdForFlow(activeFlowId));
|
||||||
inputAutoDelayMinutes.value = String(delayMinutes);
|
btnAutoRun.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg> 运行中...';
|
||||||
btnAutoRun.innerHTML = delayEnabled
|
|
||||||
? '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg> 计划中...'
|
|
||||||
: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg> 运行中...';
|
|
||||||
const response = await sendSidepanelMessage({
|
const response = await sendSidepanelMessage({
|
||||||
type: delayEnabled ? 'SCHEDULE_AUTO_RUN' : 'AUTO_RUN',
|
type: 'AUTO_RUN',
|
||||||
source: 'sidepanel',
|
source: 'sidepanel',
|
||||||
payload: {
|
payload: {
|
||||||
totalRuns,
|
totalRuns,
|
||||||
delayMinutes,
|
|
||||||
activeFlowId,
|
activeFlowId,
|
||||||
targetId,
|
targetId,
|
||||||
autoRunSkipFailures,
|
autoRunSkipFailures,
|
||||||
@@ -15213,15 +15143,12 @@ btnAutoContinue.addEventListener('click', async () => {
|
|||||||
btnAutoRunNow?.addEventListener('click', async () => {
|
btnAutoRunNow?.addEventListener('click', async () => {
|
||||||
try {
|
try {
|
||||||
btnAutoRunNow.disabled = true;
|
btnAutoRunNow.disabled = true;
|
||||||
const waitingInterval = currentAutoRun.phase === 'waiting_interval';
|
|
||||||
await sendSidepanelMessage({
|
await sendSidepanelMessage({
|
||||||
type: waitingInterval ? 'SKIP_AUTO_RUN_COUNTDOWN' : 'START_SCHEDULED_AUTO_RUN_NOW',
|
type: 'SKIP_AUTO_RUN_COUNTDOWN',
|
||||||
source: 'sidepanel',
|
source: 'sidepanel',
|
||||||
payload: {},
|
payload: {},
|
||||||
});
|
});
|
||||||
if (waitingInterval) {
|
showToast('已跳过当前倒计时,自动流程将立即继续。', 'info', 1800);
|
||||||
showToast('已跳过当前倒计时,自动流程将立即继续。', 'info', 1800);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showToast(err.message, 'error');
|
showToast(err.message, 'error');
|
||||||
} finally {
|
} finally {
|
||||||
@@ -15229,18 +15156,6 @@ btnAutoRunNow?.addEventListener('click', async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
btnAutoCancelSchedule?.addEventListener('click', async () => {
|
|
||||||
try {
|
|
||||||
btnAutoCancelSchedule.disabled = true;
|
|
||||||
await chrome.runtime.sendMessage({ type: 'CANCEL_SCHEDULED_AUTO_RUN', source: 'sidepanel', payload: {} });
|
|
||||||
showToast('已取消倒计时计划。', 'info', 1800);
|
|
||||||
} catch (err) {
|
|
||||||
showToast(err.message, 'error');
|
|
||||||
} finally {
|
|
||||||
btnAutoCancelSchedule.disabled = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Reset
|
// Reset
|
||||||
btnReset.addEventListener('click', async () => {
|
btnReset.addEventListener('click', async () => {
|
||||||
const confirmed = await openConfirmModal({
|
const confirmed = await openConfirmModal({
|
||||||
@@ -15270,7 +15185,6 @@ btnReset.addEventListener('click', async () => {
|
|||||||
autoRunCurrentRun: 0,
|
autoRunCurrentRun: 0,
|
||||||
autoRunTotalRuns: 1,
|
autoRunTotalRuns: 1,
|
||||||
autoRunAttemptRun: 0,
|
autoRunAttemptRun: 0,
|
||||||
scheduledAutoRunAt: null,
|
|
||||||
autoRunCountdownAt: null,
|
autoRunCountdownAt: null,
|
||||||
autoRunCountdownTitle: '',
|
autoRunCountdownTitle: '',
|
||||||
autoRunCountdownNote: '',
|
autoRunCountdownNote: '',
|
||||||
@@ -15460,6 +15374,10 @@ btnOpenKiroRsGithub?.addEventListener('click', () => {
|
|||||||
openExternalUrl('https://github.com/QLHazyCoder/kiro.rs');
|
openExternalUrl('https://github.com/QLHazyCoder/kiro.rs');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
btnOpenWebchat2ApiGithub?.addEventListener('click', () => {
|
||||||
|
openExternalUrl('https://github.com/zqbxdev/webchat2api');
|
||||||
|
});
|
||||||
|
|
||||||
btnGpcHelperBalance?.addEventListener('click', async () => {
|
btnGpcHelperBalance?.addEventListener('click', async () => {
|
||||||
try {
|
try {
|
||||||
const response = await chrome.runtime.sendMessage({
|
const response = await chrome.runtime.sendMessage({
|
||||||
@@ -16576,12 +16494,6 @@ inputAutoSkipFailuresThreadIntervalMinutes.addEventListener('blur', () => {
|
|||||||
saveSettings({ silent: true }).catch(() => { });
|
saveSettings({ silent: true }).catch(() => { });
|
||||||
});
|
});
|
||||||
|
|
||||||
inputAutoDelayEnabled.addEventListener('change', () => {
|
|
||||||
updateAutoDelayInputState();
|
|
||||||
markSettingsDirty(true);
|
|
||||||
saveSettings({ silent: true }).catch(() => { });
|
|
||||||
});
|
|
||||||
|
|
||||||
inputStep6CookieCleanupEnabled?.addEventListener('change', () => {
|
inputStep6CookieCleanupEnabled?.addEventListener('change', () => {
|
||||||
markSettingsDirty(true);
|
markSettingsDirty(true);
|
||||||
saveSettings({ silent: true }).catch(() => { });
|
saveSettings({ silent: true }).catch(() => { });
|
||||||
@@ -16655,17 +16567,6 @@ selectFlow?.addEventListener('change', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
inputAutoDelayMinutes.addEventListener('input', () => {
|
|
||||||
markSettingsDirty(true);
|
|
||||||
scheduleSettingsAutoSave();
|
|
||||||
});
|
|
||||||
inputAutoDelayMinutes.addEventListener('blur', () => {
|
|
||||||
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(inputAutoDelayMinutes.value));
|
|
||||||
saveSettings({ silent: true }).catch(() => { });
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function getPhoneSmsCountrySelectionForProvider(provider = getSelectedPhoneSmsProvider(), options = {}) {
|
function getPhoneSmsCountrySelectionForProvider(provider = getSelectedPhoneSmsProvider(), options = {}) {
|
||||||
const normalizedProvider = normalizePhoneSmsProvider(provider);
|
const normalizedProvider = normalizePhoneSmsProvider(provider);
|
||||||
const countrySelect = selectHeroSmsCountry || selectHeroSmsCountryFallback;
|
const countrySelect = selectHeroSmsCountry || selectHeroSmsCountryFallback;
|
||||||
@@ -17457,7 +17358,6 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|||||||
password: null,
|
password: null,
|
||||||
nodeStatuses: NODE_DEFAULT_STATUSES,
|
nodeStatuses: NODE_DEFAULT_STATUSES,
|
||||||
logs: [],
|
logs: [],
|
||||||
scheduledAutoRunAt: null,
|
|
||||||
autoRunCountdownAt: null,
|
autoRunCountdownAt: null,
|
||||||
autoRunCountdownTitle: '',
|
autoRunCountdownTitle: '',
|
||||||
autoRunCountdownNote: '',
|
autoRunCountdownNote: '',
|
||||||
@@ -17492,7 +17392,6 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|||||||
autoRunCurrentRun: 0,
|
autoRunCurrentRun: 0,
|
||||||
autoRunTotalRuns: 1,
|
autoRunTotalRuns: 1,
|
||||||
autoRunAttemptRun: 0,
|
autoRunAttemptRun: 0,
|
||||||
scheduledAutoRunAt: null,
|
|
||||||
autoRunCountdownAt: null,
|
autoRunCountdownAt: null,
|
||||||
autoRunCountdownTitle: '',
|
autoRunCountdownTitle: '',
|
||||||
autoRunCountdownNote: '',
|
autoRunCountdownNote: '',
|
||||||
@@ -17926,10 +17825,6 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|||||||
inputAutoSkipFailures.checked = Boolean(message.payload.autoRunSkipFailures);
|
inputAutoSkipFailures.checked = Boolean(message.payload.autoRunSkipFailures);
|
||||||
updateFallbackThreadIntervalInputState();
|
updateFallbackThreadIntervalInputState();
|
||||||
}
|
}
|
||||||
if (message.payload.autoRunDelayEnabled !== undefined) {
|
|
||||||
inputAutoDelayEnabled.checked = Boolean(message.payload.autoRunDelayEnabled);
|
|
||||||
updateAutoDelayInputState();
|
|
||||||
}
|
|
||||||
if (
|
if (
|
||||||
message.payload.step6CookieCleanupEnabled !== undefined
|
message.payload.step6CookieCleanupEnabled !== undefined
|
||||||
&& typeof inputStep6CookieCleanupEnabled !== 'undefined'
|
&& typeof inputStep6CookieCleanupEnabled !== 'undefined'
|
||||||
@@ -17945,9 +17840,6 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|||||||
renderStepStatuses(latestState);
|
renderStepStatuses(latestState);
|
||||||
updateButtonStates();
|
updateButtonStates();
|
||||||
}
|
}
|
||||||
if (message.payload.autoRunDelayMinutes !== undefined) {
|
|
||||||
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(message.payload.autoRunDelayMinutes));
|
|
||||||
}
|
|
||||||
if (message.payload.autoRunFallbackThreadIntervalMinutes !== undefined) {
|
if (message.payload.autoRunFallbackThreadIntervalMinutes !== undefined) {
|
||||||
inputAutoSkipFailuresThreadIntervalMinutes.value = String(
|
inputAutoSkipFailuresThreadIntervalMinutes.value = String(
|
||||||
normalizeAutoRunThreadIntervalMinutes(message.payload.autoRunFallbackThreadIntervalMinutes)
|
normalizeAutoRunThreadIntervalMinutes(message.payload.autoRunFallbackThreadIntervalMinutes)
|
||||||
@@ -18239,12 +18131,11 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|||||||
|
|
||||||
case 'AUTO_RUN_STATUS': {
|
case 'AUTO_RUN_STATUS': {
|
||||||
syncLatestState({
|
syncLatestState({
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(message.payload.phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(message.payload.phase),
|
||||||
autoRunPhase: message.payload.phase,
|
autoRunPhase: message.payload.phase,
|
||||||
autoRunCurrentRun: message.payload.currentRun,
|
autoRunCurrentRun: message.payload.currentRun,
|
||||||
autoRunTotalRuns: message.payload.totalRuns,
|
autoRunTotalRuns: message.payload.totalRuns,
|
||||||
autoRunAttemptRun: message.payload.attemptRun,
|
autoRunAttemptRun: message.payload.attemptRun,
|
||||||
scheduledAutoRunAt: message.payload.scheduledAt ?? null,
|
|
||||||
autoRunCountdownAt: message.payload.countdownAt ?? null,
|
autoRunCountdownAt: message.payload.countdownAt ?? null,
|
||||||
autoRunCountdownTitle: message.payload.countdownTitle ?? '',
|
autoRunCountdownTitle: message.payload.countdownTitle ?? '',
|
||||||
autoRunCountdownNote: message.payload.countdownNote ?? '',
|
autoRunCountdownNote: message.payload.countdownNote ?? '',
|
||||||
@@ -18252,7 +18143,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|||||||
applyAutoRunStatus(message.payload);
|
applyAutoRunStatus(message.payload);
|
||||||
updateStatusDisplay(latestState);
|
updateStatusDisplay(latestState);
|
||||||
updateButtonStates();
|
updateButtonStates();
|
||||||
if (!['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(message.payload.phase)) {
|
if (!['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(message.payload.phase)) {
|
||||||
scheduleAccountRunHistoryRefresh();
|
scheduleAccountRunHistoryRefresh();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -134,8 +134,6 @@ test('auto-run controller skips add-phone failures to the next round instead of
|
|||||||
customPassword: '',
|
customPassword: '',
|
||||||
autoRunSkipFailures: true,
|
autoRunSkipFailures: true,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
mailProvider: '163',
|
mailProvider: '163',
|
||||||
emailGenerator: 'duck',
|
emailGenerator: 'duck',
|
||||||
@@ -185,7 +183,7 @@ test('auto-run controller skips add-phone failures to the next round instead of
|
|||||||
events.broadcasts.push({ phase, ...payload });
|
events.broadcasts.push({ phase, ...payload });
|
||||||
currentState = {
|
currentState = {
|
||||||
...currentState,
|
...currentState,
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||||
@@ -201,7 +199,7 @@ test('auto-run controller skips add-phone failures to the next round instead of
|
|||||||
return sessionSeed;
|
return sessionSeed;
|
||||||
},
|
},
|
||||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
@@ -297,8 +295,6 @@ test('auto-run controller treats phone-number supply exhaustion as round-fatal a
|
|||||||
customPassword: '',
|
customPassword: '',
|
||||||
autoRunSkipFailures: true,
|
autoRunSkipFailures: true,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
mailProvider: '163',
|
mailProvider: '163',
|
||||||
emailGenerator: 'duck',
|
emailGenerator: 'duck',
|
||||||
@@ -348,7 +344,7 @@ test('auto-run controller treats phone-number supply exhaustion as round-fatal a
|
|||||||
events.broadcasts.push({ phase, ...payload });
|
events.broadcasts.push({ phase, ...payload });
|
||||||
currentState = {
|
currentState = {
|
||||||
...currentState,
|
...currentState,
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||||
@@ -364,7 +360,7 @@ test('auto-run controller treats phone-number supply exhaustion as round-fatal a
|
|||||||
return sessionSeed;
|
return sessionSeed;
|
||||||
},
|
},
|
||||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
@@ -460,8 +456,6 @@ test('auto-run controller treats ended GPC task as round-fatal and skips same-ro
|
|||||||
customPassword: '',
|
customPassword: '',
|
||||||
autoRunSkipFailures: true,
|
autoRunSkipFailures: true,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
mailProvider: '163',
|
mailProvider: '163',
|
||||||
emailGenerator: 'duck',
|
emailGenerator: 'duck',
|
||||||
@@ -511,7 +505,7 @@ test('auto-run controller treats ended GPC task as round-fatal and skips same-ro
|
|||||||
events.broadcasts.push({ phase, ...payload });
|
events.broadcasts.push({ phase, ...payload });
|
||||||
currentState = {
|
currentState = {
|
||||||
...currentState,
|
...currentState,
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||||
@@ -527,7 +521,7 @@ test('auto-run controller treats ended GPC task as round-fatal and skips same-ro
|
|||||||
return sessionSeed;
|
return sessionSeed;
|
||||||
},
|
},
|
||||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
@@ -621,8 +615,6 @@ test('auto-run controller keeps same-round retrying for step9 local replacement
|
|||||||
customPassword: '',
|
customPassword: '',
|
||||||
autoRunSkipFailures: true,
|
autoRunSkipFailures: true,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
mailProvider: '163',
|
mailProvider: '163',
|
||||||
emailGenerator: 'duck',
|
emailGenerator: 'duck',
|
||||||
@@ -672,7 +664,7 @@ test('auto-run controller keeps same-round retrying for step9 local replacement
|
|||||||
events.broadcasts.push({ phase, ...payload });
|
events.broadcasts.push({ phase, ...payload });
|
||||||
currentState = {
|
currentState = {
|
||||||
...currentState,
|
...currentState,
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||||
@@ -688,7 +680,7 @@ test('auto-run controller keeps same-round retrying for step9 local replacement
|
|||||||
return sessionSeed;
|
return sessionSeed;
|
||||||
},
|
},
|
||||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
@@ -779,8 +771,6 @@ test('auto-run controller skips user_already_exists failures to the next round i
|
|||||||
customPassword: '',
|
customPassword: '',
|
||||||
autoRunSkipFailures: true,
|
autoRunSkipFailures: true,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
mailProvider: '163',
|
mailProvider: '163',
|
||||||
emailGenerator: 'duck',
|
emailGenerator: 'duck',
|
||||||
@@ -830,7 +820,7 @@ test('auto-run controller skips user_already_exists failures to the next round i
|
|||||||
events.broadcasts.push({ phase, ...payload });
|
events.broadcasts.push({ phase, ...payload });
|
||||||
currentState = {
|
currentState = {
|
||||||
...currentState,
|
...currentState,
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||||
@@ -846,7 +836,7 @@ test('auto-run controller skips user_already_exists failures to the next round i
|
|||||||
return sessionSeed;
|
return sessionSeed;
|
||||||
},
|
},
|
||||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
@@ -943,8 +933,6 @@ test('auto-run controller skips step 4 repeated 405 recovery failures to the nex
|
|||||||
customPassword: '',
|
customPassword: '',
|
||||||
autoRunSkipFailures: true,
|
autoRunSkipFailures: true,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
mailProvider: '163',
|
mailProvider: '163',
|
||||||
emailGenerator: 'duck',
|
emailGenerator: 'duck',
|
||||||
@@ -994,7 +982,7 @@ test('auto-run controller skips step 4 repeated 405 recovery failures to the nex
|
|||||||
events.broadcasts.push({ phase, ...payload });
|
events.broadcasts.push({ phase, ...payload });
|
||||||
currentState = {
|
currentState = {
|
||||||
...currentState,
|
...currentState,
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||||
@@ -1010,7 +998,7 @@ test('auto-run controller skips step 4 repeated 405 recovery failures to the nex
|
|||||||
return sessionSeed;
|
return sessionSeed;
|
||||||
},
|
},
|
||||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
@@ -1108,8 +1096,6 @@ test('auto-run controller keeps retrying the same custom mail provider pool emai
|
|||||||
customPassword: '',
|
customPassword: '',
|
||||||
autoRunSkipFailures: true,
|
autoRunSkipFailures: true,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
mailProvider: 'custom',
|
mailProvider: 'custom',
|
||||||
customMailProviderPool: ['first@example.com'],
|
customMailProviderPool: ['first@example.com'],
|
||||||
@@ -1160,7 +1146,7 @@ test('auto-run controller keeps retrying the same custom mail provider pool emai
|
|||||||
events.broadcasts.push({ phase, ...payload });
|
events.broadcasts.push({ phase, ...payload });
|
||||||
currentState = {
|
currentState = {
|
||||||
...currentState,
|
...currentState,
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||||
@@ -1176,7 +1162,7 @@ test('auto-run controller keeps retrying the same custom mail provider pool emai
|
|||||||
return sessionSeed;
|
return sessionSeed;
|
||||||
},
|
},
|
||||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
@@ -1274,8 +1260,6 @@ test('auto-run controller retries 5sim rate limit failures instead of treating c
|
|||||||
customPassword: '',
|
customPassword: '',
|
||||||
autoRunSkipFailures: true,
|
autoRunSkipFailures: true,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
mailProvider: '163',
|
mailProvider: '163',
|
||||||
emailGenerator: 'duck',
|
emailGenerator: 'duck',
|
||||||
@@ -1325,7 +1309,7 @@ test('auto-run controller retries 5sim rate limit failures instead of treating c
|
|||||||
events.broadcasts.push({ phase, ...payload });
|
events.broadcasts.push({ phase, ...payload });
|
||||||
currentState = {
|
currentState = {
|
||||||
...currentState,
|
...currentState,
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||||
@@ -1341,7 +1325,7 @@ test('auto-run controller retries 5sim rate limit failures instead of treating c
|
|||||||
return sessionSeed;
|
return sessionSeed;
|
||||||
},
|
},
|
||||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
|
|||||||
@@ -130,8 +130,6 @@ let currentState = {
|
|||||||
customPassword: '',
|
customPassword: '',
|
||||||
autoRunSkipFailures: false,
|
autoRunSkipFailures: false,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
signupMethod: 'phone',
|
signupMethod: 'phone',
|
||||||
resolvedSignupMethod: 'phone',
|
resolvedSignupMethod: 'phone',
|
||||||
@@ -204,8 +202,6 @@ async function resetState() {
|
|||||||
customPassword: prev.customPassword,
|
customPassword: prev.customPassword,
|
||||||
autoRunSkipFailures: prev.autoRunSkipFailures,
|
autoRunSkipFailures: prev.autoRunSkipFailures,
|
||||||
autoRunFallbackThreadIntervalMinutes: prev.autoRunFallbackThreadIntervalMinutes,
|
autoRunFallbackThreadIntervalMinutes: prev.autoRunFallbackThreadIntervalMinutes,
|
||||||
autoRunDelayEnabled: prev.autoRunDelayEnabled,
|
|
||||||
autoRunDelayMinutes: prev.autoRunDelayMinutes,
|
|
||||||
autoStepDelaySeconds: prev.autoStepDelaySeconds,
|
autoStepDelaySeconds: prev.autoStepDelaySeconds,
|
||||||
signupMethod: prev.signupMethod,
|
signupMethod: prev.signupMethod,
|
||||||
resolvedSignupMethod: null,
|
resolvedSignupMethod: null,
|
||||||
|
|||||||
@@ -104,8 +104,6 @@ test('auto-run controller verifies hotmail mailbox before each fresh attempt sta
|
|||||||
customPassword: '',
|
customPassword: '',
|
||||||
autoRunSkipFailures: false,
|
autoRunSkipFailures: false,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
mailProvider: 'hotmail-api',
|
mailProvider: 'hotmail-api',
|
||||||
emailGenerator: 'duck',
|
emailGenerator: 'duck',
|
||||||
@@ -149,7 +147,7 @@ test('auto-run controller verifies hotmail mailbox before each fresh attempt sta
|
|||||||
broadcastAutoRunStatus: async (phase, payload = {}) => {
|
broadcastAutoRunStatus: async (phase, payload = {}) => {
|
||||||
currentState = {
|
currentState = {
|
||||||
...currentState,
|
...currentState,
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
autoRunCurrentRun: payload.currentRun ?? runtime.state.autoRunCurrentRun,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
autoRunTotalRuns: payload.totalRuns ?? runtime.state.autoRunTotalRuns,
|
||||||
@@ -169,7 +167,7 @@ test('auto-run controller verifies hotmail mailbox before each fresh attempt sta
|
|||||||
events.preflightCalls.push({ ...payload });
|
events.preflightCalls.push({ ...payload });
|
||||||
},
|
},
|
||||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ test('auto-run controller preserves kiro flow across fresh reset and starts from
|
|||||||
phoneSignupReloginAfterBindEmailEnabled: false,
|
phoneSignupReloginAfterBindEmailEnabled: false,
|
||||||
autoRunSkipFailures: false,
|
autoRunSkipFailures: false,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
signupMethod: 'email',
|
signupMethod: 'email',
|
||||||
stepExecutionRangeByFlow: {
|
stepExecutionRangeByFlow: {
|
||||||
@@ -94,7 +92,7 @@ test('auto-run controller preserves kiro flow across fresh reset and starts from
|
|||||||
currentState = {
|
currentState = {
|
||||||
...currentState,
|
...currentState,
|
||||||
...extraState,
|
...extraState,
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? currentState.autoRunCurrentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? currentState.autoRunCurrentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? currentState.autoRunTotalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? currentState.autoRunTotalRuns ?? 1,
|
||||||
@@ -124,7 +122,7 @@ test('auto-run controller preserves kiro flow across fresh reset and starts from
|
|||||||
},
|
},
|
||||||
ensureHotmailMailboxReadyForAutoRunRound: async () => {},
|
ensureHotmailMailboxReadyForAutoRunRound: async () => {},
|
||||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
@@ -179,8 +177,6 @@ test('auto-run controller preserves kiro flow across fresh reset and starts from
|
|||||||
phoneSignupReloginAfterBindEmailEnabled: false,
|
phoneSignupReloginAfterBindEmailEnabled: false,
|
||||||
autoRunSkipFailures: false,
|
autoRunSkipFailures: false,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
signupMethod: 'email',
|
signupMethod: 'email',
|
||||||
stepExecutionRangeByFlow: {
|
stepExecutionRangeByFlow: {
|
||||||
@@ -445,8 +441,6 @@ test('auto-run controller stops immediately on kiro proxy failures even when ski
|
|||||||
flowId: 'kiro',
|
flowId: 'kiro',
|
||||||
autoRunSkipFailures: true,
|
autoRunSkipFailures: true,
|
||||||
autoRunFallbackThreadIntervalMinutes: 0,
|
autoRunFallbackThreadIntervalMinutes: 0,
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunDelayMinutes: 30,
|
|
||||||
autoStepDelaySeconds: null,
|
autoStepDelaySeconds: null,
|
||||||
nodeStatuses: {
|
nodeStatuses: {
|
||||||
'kiro-open-register-page': 'pending',
|
'kiro-open-register-page': 'pending',
|
||||||
@@ -496,7 +490,7 @@ test('auto-run controller stops immediately on kiro proxy failures even when ski
|
|||||||
events.phases.push({ phase, ...payload });
|
events.phases.push({ phase, ...payload });
|
||||||
currentState = {
|
currentState = {
|
||||||
...currentState,
|
...currentState,
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? currentState.autoRunCurrentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? currentState.autoRunCurrentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? currentState.autoRunTotalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? currentState.autoRunTotalRuns ?? 1,
|
||||||
@@ -514,7 +508,7 @@ test('auto-run controller stops immediately on kiro proxy failures even when ski
|
|||||||
},
|
},
|
||||||
ensureHotmailMailboxReadyForAutoRunRound: async () => {},
|
ensureHotmailMailboxReadyForAutoRunRound: async () => {},
|
||||||
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
getAutoRunStatusPayload: (phase, payload = {}) => ({
|
||||||
autoRunning: ['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
autoRunning: ['running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(phase),
|
||||||
autoRunPhase: phase,
|
autoRunPhase: phase,
|
||||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ const helperBundle = [
|
|||||||
|
|
||||||
test('launchAutoRunTimerPlan ignores stale timer plans after stop invalidates the session', async () => {
|
test('launchAutoRunTimerPlan ignores stale timer plans after stop invalidates the session', async () => {
|
||||||
const api = new Function(`
|
const api = new Function(`
|
||||||
const AUTO_RUN_TIMER_KIND_SCHEDULED_START = 'scheduled_start';
|
|
||||||
const AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS = 'between_rounds';
|
const AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS = 'between_rounds';
|
||||||
const AUTO_RUN_TIMER_KIND_BEFORE_RETRY = 'before_retry';
|
const AUTO_RUN_TIMER_KIND_BEFORE_RETRY = 'before_retry';
|
||||||
const AUTO_RUN_MAX_RETRIES_PER_ROUND = 3;
|
const AUTO_RUN_MAX_RETRIES_PER_ROUND = 3;
|
||||||
@@ -76,14 +75,15 @@ let autoRunAttemptRun = 0;
|
|||||||
let autoRunSessionId = 0;
|
let autoRunSessionId = 0;
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunTimerPlan: {
|
autoRunTimerPlan: {
|
||||||
kind: AUTO_RUN_TIMER_KIND_SCHEDULED_START,
|
kind: AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS,
|
||||||
fireAt: Date.now() + 60_000,
|
fireAt: Date.now() + 60_000,
|
||||||
totalRuns: 2,
|
totalRuns: 2,
|
||||||
autoRunSkipFailures: false,
|
autoRunSkipFailures: false,
|
||||||
autoRunSessionId: 42,
|
autoRunSessionId: 42,
|
||||||
countdownTitle: '已计划自动运行',
|
currentRun: 1,
|
||||||
|
attemptRun: 1,
|
||||||
|
countdownTitle: '等待继续',
|
||||||
countdownNote: '等待启动',
|
countdownNote: '等待启动',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -106,7 +106,6 @@ async function clearAutoRunTimerAlarm() {
|
|||||||
|
|
||||||
async function broadcastAutoRunStatus() {}
|
async function broadcastAutoRunStatus() {}
|
||||||
async function addLog() {}
|
async function addLog() {}
|
||||||
async function setAutoRunDelayEnabledState() {}
|
|
||||||
function serializeAutoRunRoundSummaries(totalRuns, summaries = []) {
|
function serializeAutoRunRoundSummaries(totalRuns, summaries = []) {
|
||||||
return Array.isArray(summaries) ? summaries : [];
|
return Array.isArray(summaries) ? summaries : [];
|
||||||
}
|
}
|
||||||
@@ -137,116 +136,10 @@ return {
|
|||||||
const started = await api.launchAutoRunTimerPlan('alarm');
|
const started = await api.launchAutoRunTimerPlan('alarm');
|
||||||
const snapshot = api.snapshot();
|
const snapshot = api.snapshot();
|
||||||
|
|
||||||
assert.equal(started, false);
|
|
||||||
assert.equal(snapshot.startCalls, 0, 'stale timer plan should not restart auto-run');
|
|
||||||
assert.equal(snapshot.clearStopCalls, 0, 'stale timer plan should not clear the stop flag for a cancelled run');
|
|
||||||
assert.equal(snapshot.clearAlarmCalls, 0, 'stale timer plan should not clear a potentially newer alarm');
|
|
||||||
assert.equal(snapshot.autoRunCurrentRun, 0);
|
|
||||||
assert.equal(snapshot.autoRunTotalRuns, 1);
|
|
||||||
assert.equal(snapshot.autoRunAttemptRun, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('launchAutoRunTimerPlan cancels an invalid scheduled start before restarting auto-run', async () => {
|
|
||||||
const api = new Function(`
|
|
||||||
const AUTO_RUN_TIMER_KIND_SCHEDULED_START = 'scheduled_start';
|
|
||||||
const AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS = 'between_rounds';
|
|
||||||
const AUTO_RUN_TIMER_KIND_BEFORE_RETRY = 'before_retry';
|
|
||||||
const AUTO_RUN_MAX_RETRIES_PER_ROUND = 3;
|
|
||||||
|
|
||||||
let autoRunTimerLaunching = false;
|
|
||||||
let autoRunActive = false;
|
|
||||||
let autoRunCurrentRun = 0;
|
|
||||||
let autoRunTotalRuns = 1;
|
|
||||||
let autoRunAttemptRun = 0;
|
|
||||||
let autoRunSessionId = 0;
|
|
||||||
|
|
||||||
const state = {
|
|
||||||
activeFlowId: 'site-a',
|
|
||||||
panelMode: 'cpa',
|
|
||||||
signupMethod: 'phone',
|
|
||||||
autoRunDelayEnabled: false,
|
|
||||||
autoRunTimerPlan: {
|
|
||||||
kind: AUTO_RUN_TIMER_KIND_SCHEDULED_START,
|
|
||||||
fireAt: Date.now() + 60_000,
|
|
||||||
totalRuns: 2,
|
|
||||||
autoRunSkipFailures: false,
|
|
||||||
autoRunSessionId: 0,
|
|
||||||
countdownTitle: '已计划自动运行',
|
|
||||||
countdownNote: '等待启动',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let startCalls = 0;
|
|
||||||
let clearStopCalls = 0;
|
|
||||||
let clearAlarmCalls = 0;
|
|
||||||
const broadcasts = [];
|
|
||||||
const logs = [];
|
|
||||||
|
|
||||||
async function getState() {
|
|
||||||
return { ...state };
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPendingAutoRunTimerPlan() {
|
|
||||||
return state.autoRunTimerPlan;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function clearAutoRunTimerAlarm() {
|
|
||||||
clearAlarmCalls += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function broadcastAutoRunStatus(phase, statusPayload, statePayload) {
|
|
||||||
broadcasts.push({ phase, statusPayload, statePayload });
|
|
||||||
}
|
|
||||||
async function addLog(message, level) {
|
|
||||||
logs.push({ message, level });
|
|
||||||
}
|
|
||||||
async function setAutoRunDelayEnabledState() {}
|
|
||||||
function serializeAutoRunRoundSummaries(totalRuns, summaries = []) {
|
|
||||||
return Array.isArray(summaries) ? summaries : [];
|
|
||||||
}
|
|
||||||
function clearStopRequest() {
|
|
||||||
clearStopCalls += 1;
|
|
||||||
}
|
|
||||||
function startAutoRunLoop() {
|
|
||||||
startCalls += 1;
|
|
||||||
}
|
|
||||||
function validateAutoRunStartState() {
|
|
||||||
return {
|
|
||||||
ok: false,
|
|
||||||
errors: [{ message: '当前 flow 不支持手机号注册。' }],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
${helperBundle}
|
|
||||||
|
|
||||||
return {
|
|
||||||
launchAutoRunTimerPlan,
|
|
||||||
snapshot() {
|
|
||||||
return {
|
|
||||||
startCalls,
|
|
||||||
clearStopCalls,
|
|
||||||
clearAlarmCalls,
|
|
||||||
broadcasts,
|
|
||||||
logs,
|
|
||||||
autoRunCurrentRun,
|
|
||||||
autoRunTotalRuns,
|
|
||||||
autoRunAttemptRun,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
`)();
|
|
||||||
|
|
||||||
const started = await api.launchAutoRunTimerPlan('alarm');
|
|
||||||
const snapshot = api.snapshot();
|
|
||||||
|
|
||||||
assert.equal(started, false);
|
assert.equal(started, false);
|
||||||
assert.equal(snapshot.startCalls, 0);
|
assert.equal(snapshot.startCalls, 0);
|
||||||
assert.equal(snapshot.clearStopCalls, 0);
|
assert.equal(snapshot.clearStopCalls, 0);
|
||||||
assert.equal(snapshot.clearAlarmCalls, 1);
|
assert.equal(snapshot.clearAlarmCalls, 0);
|
||||||
assert.equal(snapshot.broadcasts.length, 1);
|
|
||||||
assert.equal(snapshot.broadcasts[0].phase, 'idle');
|
|
||||||
assert.match(snapshot.logs[0].message, /自动运行计划已取消:当前 flow 不支持手机号注册。/);
|
|
||||||
assert.equal(snapshot.logs[0].level, 'error');
|
|
||||||
assert.equal(snapshot.autoRunCurrentRun, 0);
|
assert.equal(snapshot.autoRunCurrentRun, 0);
|
||||||
assert.equal(snapshot.autoRunTotalRuns, 1);
|
assert.equal(snapshot.autoRunTotalRuns, 1);
|
||||||
assert.equal(snapshot.autoRunAttemptRun, 0);
|
assert.equal(snapshot.autoRunAttemptRun, 0);
|
||||||
|
|||||||
@@ -196,7 +196,6 @@ const PERSISTED_SETTING_DEFAULTS = {
|
|||||||
function normalizePanelMode(value) { return value === 'sub2api' ? 'sub2api' : (value === 'codex2api' ? 'codex2api' : 'cpa'); }
|
function normalizePanelMode(value) { return value === 'sub2api' ? 'sub2api' : (value === 'codex2api' ? 'codex2api' : 'cpa'); }
|
||||||
function normalizeLocalCpaStep9Mode(value) { return value === 'bypass' ? 'bypass' : 'submit'; }
|
function normalizeLocalCpaStep9Mode(value) { return value === 'bypass' ? 'bypass' : 'submit'; }
|
||||||
function normalizeAutoRunFallbackThreadIntervalMinutes(value) { return Number(value) || 0; }
|
function normalizeAutoRunFallbackThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||||
function normalizeAutoRunDelayMinutes(value) { return Number(value) || 30; }
|
|
||||||
function normalizeAutoStepDelaySeconds(value) { return value == null || value === '' ? null : Number(value); }
|
function normalizeAutoStepDelaySeconds(value) { return value == null || value === '' ? null : Number(value); }
|
||||||
function normalizeMailProvider(value) { return String(value || '').trim().toLowerCase() || '163'; }
|
function normalizeMailProvider(value) { return String(value || '').trim().toLowerCase() || '163'; }
|
||||||
function normalizeMail2925Mode(value) { return String(value || '').trim().toLowerCase() === 'receive' ? 'receive' : 'provide'; }
|
function normalizeMail2925Mode(value) { return String(value || '').trim().toLowerCase() === 'receive' ? 'receive' : 'provide'; }
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ function normalizeSignupMethod(value = '') { return String(value || '').trim().t
|
|||||||
function resolveSignupMethod(state = {}) { return normalizeSignupMethod(state?.signupMethod); }
|
function resolveSignupMethod(state = {}) { return normalizeSignupMethod(state?.signupMethod); }
|
||||||
function normalizeLocalCpaStep9Mode(value) { return value === 'bypass' ? 'bypass' : 'submit'; }
|
function normalizeLocalCpaStep9Mode(value) { return value === 'bypass' ? 'bypass' : 'submit'; }
|
||||||
function normalizeAutoRunFallbackThreadIntervalMinutes(value) { return Number(value) || 0; }
|
function normalizeAutoRunFallbackThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||||
function normalizeAutoRunDelayMinutes(value) { return Number(value) || 30; }
|
|
||||||
function normalizeAutoStepDelaySeconds(value, fallback = null) { return value == null || value === '' ? fallback : Number(value); }
|
function normalizeAutoStepDelaySeconds(value, fallback = null) { return value == null || value === '' ? fallback : Number(value); }
|
||||||
function normalizeVerificationResendCount(value, fallback) { return Number.isFinite(Number(value)) ? Number(value) : fallback; }
|
function normalizeVerificationResendCount(value, fallback) { return Number.isFinite(Number(value)) ? Number(value) : fallback; }
|
||||||
function normalizeMailProvider(value) { return String(value || '').trim().toLowerCase() || '163'; }
|
function normalizeMailProvider(value) { return String(value || '').trim().toLowerCase() || '163'; }
|
||||||
@@ -180,7 +179,6 @@ function normalizeSignupMethod(value = '') { return String(value || '').trim().t
|
|||||||
function resolveSignupMethod(state = {}) { return normalizeSignupMethod(state?.signupMethod); }
|
function resolveSignupMethod(state = {}) { return normalizeSignupMethod(state?.signupMethod); }
|
||||||
function normalizeLocalCpaStep9Mode(value) { return value === 'bypass' ? 'bypass' : 'submit'; }
|
function normalizeLocalCpaStep9Mode(value) { return value === 'bypass' ? 'bypass' : 'submit'; }
|
||||||
function normalizeAutoRunFallbackThreadIntervalMinutes(value) { return Number(value) || 0; }
|
function normalizeAutoRunFallbackThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||||
function normalizeAutoRunDelayMinutes(value) { return Number(value) || 30; }
|
|
||||||
function normalizeAutoStepDelaySeconds(value, fallback = null) { return value == null || value === '' ? fallback : Number(value); }
|
function normalizeAutoStepDelaySeconds(value, fallback = null) { return value == null || value === '' ? fallback : Number(value); }
|
||||||
function normalizeVerificationResendCount(value, fallback) { return Number.isFinite(Number(value)) ? Number(value) : fallback; }
|
function normalizeVerificationResendCount(value, fallback) { return Number.isFinite(Number(value)) ? Number(value) : fallback; }
|
||||||
function normalizeMailProvider(value) { return String(value || '').trim().toLowerCase() || '163'; }
|
function normalizeMailProvider(value) { return String(value || '').trim().toLowerCase() || '163'; }
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ test('message router re-syncs contribution mode before AUTO_RUN when sidepanel p
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('message router blocks AUTO_RUN and SCHEDULE_AUTO_RUN when shared auto-run validation fails', async () => {
|
test('message router blocks AUTO_RUN when shared auto-run validation fails', async () => {
|
||||||
const source = fs.readFileSync('background/message-router.js', 'utf8');
|
const source = fs.readFileSync('background/message-router.js', 'utf8');
|
||||||
const globalScope = {};
|
const globalScope = {};
|
||||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundMessageRouter;`)(globalScope);
|
const api = new Function('self', `${source}; return self.MultiPageBackgroundMessageRouter;`)(globalScope);
|
||||||
@@ -388,10 +388,6 @@ test('message router blocks AUTO_RUN and SCHEDULE_AUTO_RUN when shared auto-run
|
|||||||
stepStatuses: {},
|
stepStatuses: {},
|
||||||
}),
|
}),
|
||||||
normalizeRunCount: (value) => Number(value) || 1,
|
normalizeRunCount: (value) => Number(value) || 1,
|
||||||
scheduleAutoRun: async () => {
|
|
||||||
calls.push({ type: 'scheduleAutoRun' });
|
|
||||||
return { ok: true };
|
|
||||||
},
|
|
||||||
setState: async (updates) => {
|
setState: async (updates) => {
|
||||||
calls.push({ type: 'setState', updates });
|
calls.push({ type: 'setState', updates });
|
||||||
},
|
},
|
||||||
@@ -415,19 +411,6 @@ test('message router blocks AUTO_RUN and SCHEDULE_AUTO_RUN when shared auto-run
|
|||||||
}),
|
}),
|
||||||
/当前 flow 不支持手机号注册。/
|
/当前 flow 不支持手机号注册。/
|
||||||
);
|
);
|
||||||
|
|
||||||
await assert.rejects(
|
|
||||||
() => router.handleMessage({
|
|
||||||
type: 'SCHEDULE_AUTO_RUN',
|
|
||||||
payload: {
|
|
||||||
totalRuns: 2,
|
|
||||||
delayMinutes: 5,
|
|
||||||
autoRunSkipFailures: false,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
/当前 flow 不支持手机号注册。/
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.deepStrictEqual(calls, []);
|
assert.deepStrictEqual(calls, []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -99,9 +99,6 @@ function normalizeMailProvider(value = '') {
|
|||||||
function normalizeAutoRunFallbackThreadIntervalMinutes(value) {
|
function normalizeAutoRunFallbackThreadIntervalMinutes(value) {
|
||||||
return Math.max(0, Math.floor(Number(value) || 0));
|
return Math.max(0, Math.floor(Number(value) || 0));
|
||||||
}
|
}
|
||||||
function normalizeAutoRunDelayMinutes(value) {
|
|
||||||
return Math.max(1, Math.floor(Number(value) || 30));
|
|
||||||
}
|
|
||||||
function normalizeAutoStepDelaySeconds(value, fallback = null) {
|
function normalizeAutoStepDelaySeconds(value, fallback = null) {
|
||||||
const numeric = Number(value);
|
const numeric = Number(value);
|
||||||
return Number.isFinite(numeric) ? Math.max(0, Math.floor(numeric)) : fallback;
|
return Number.isFinite(numeric) ? Math.max(0, Math.floor(numeric)) : fallback;
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ function createRouterWithFinalNode(options = {}) {
|
|||||||
buildLuckmailSessionSettingsPayload: () => ({}),
|
buildLuckmailSessionSettingsPayload: () => ({}),
|
||||||
buildPersistentSettingsPayload: () => ({}),
|
buildPersistentSettingsPayload: () => ({}),
|
||||||
broadcastDataUpdate: () => {},
|
broadcastDataUpdate: () => {},
|
||||||
cancelScheduledAutoRun: async () => {},
|
|
||||||
checkIcloudSession: async () => {},
|
checkIcloudSession: async () => {},
|
||||||
clearAutoRunTimerAlarm: async () => {},
|
clearAutoRunTimerAlarm: async () => {},
|
||||||
clearLuckmailRuntimeState: async () => {},
|
clearLuckmailRuntimeState: async () => {},
|
||||||
@@ -87,7 +86,6 @@ function createRouterWithFinalNode(options = {}) {
|
|||||||
listLuckmailPurchasesForManagement: async () => [],
|
listLuckmailPurchasesForManagement: async () => [],
|
||||||
normalizeHotmailAccounts: (items) => items,
|
normalizeHotmailAccounts: (items) => items,
|
||||||
normalizeRunCount: (value) => value,
|
normalizeRunCount: (value) => value,
|
||||||
AUTO_RUN_TIMER_KIND_SCHEDULED_START: 'scheduled',
|
|
||||||
notifyNodeComplete: () => {},
|
notifyNodeComplete: () => {},
|
||||||
notifyNodeError: () => {},
|
notifyNodeError: () => {},
|
||||||
patchHotmailAccount: async () => {},
|
patchHotmailAccount: async () => {},
|
||||||
@@ -96,7 +94,6 @@ function createRouterWithFinalNode(options = {}) {
|
|||||||
requestStop: async () => {},
|
requestStop: async () => {},
|
||||||
resetState: async () => {},
|
resetState: async () => {},
|
||||||
resumeAutoRun: async () => {},
|
resumeAutoRun: async () => {},
|
||||||
scheduleAutoRun: async () => {},
|
|
||||||
selectLuckmailPurchase: async () => {},
|
selectLuckmailPurchase: async () => {},
|
||||||
setCurrentHotmailAccount: async () => {},
|
setCurrentHotmailAccount: async () => {},
|
||||||
setCurrentMail2925Account: async () => {},
|
setCurrentMail2925Account: async () => {},
|
||||||
|
|||||||
@@ -103,7 +103,6 @@ function createRouter(overrides = {}) {
|
|||||||
broadcastDataUpdate: (updates) => {
|
broadcastDataUpdate: (updates) => {
|
||||||
events.broadcasts.push(updates);
|
events.broadcasts.push(updates);
|
||||||
},
|
},
|
||||||
cancelScheduledAutoRun: async () => {},
|
|
||||||
checkIcloudSession: async () => {},
|
checkIcloudSession: async () => {},
|
||||||
clearAutoRunTimerAlarm: async () => {},
|
clearAutoRunTimerAlarm: async () => {},
|
||||||
clearLuckmailRuntimeState: async () => {},
|
clearLuckmailRuntimeState: async () => {},
|
||||||
@@ -171,7 +170,6 @@ function createRouter(overrides = {}) {
|
|||||||
listLuckmailPurchasesForManagement: async () => [],
|
listLuckmailPurchasesForManagement: async () => [],
|
||||||
normalizeHotmailAccounts: (items) => items,
|
normalizeHotmailAccounts: (items) => items,
|
||||||
normalizeRunCount: (value) => value,
|
normalizeRunCount: (value) => value,
|
||||||
AUTO_RUN_TIMER_KIND_SCHEDULED_START: 'scheduled',
|
|
||||||
notifyNodeComplete: (nodeId, payload) => {
|
notifyNodeComplete: (nodeId, payload) => {
|
||||||
events.notifyCompletions.push({ step: getStepForNode(nodeId), nodeId, payload });
|
events.notifyCompletions.push({ step: getStepForNode(nodeId), nodeId, payload });
|
||||||
},
|
},
|
||||||
@@ -183,7 +181,6 @@ function createRouter(overrides = {}) {
|
|||||||
requestStop: async () => {},
|
requestStop: async () => {},
|
||||||
resetState: async () => {},
|
resetState: async () => {},
|
||||||
resumeAutoRun: async () => {},
|
resumeAutoRun: async () => {},
|
||||||
scheduleAutoRun: async () => {},
|
|
||||||
selectLuckmailPurchase: async () => {},
|
selectLuckmailPurchase: async () => {},
|
||||||
setCurrentHotmailAccount: async () => {},
|
setCurrentHotmailAccount: async () => {},
|
||||||
setEmailState: async (email) => {
|
setEmailState: async (email) => {
|
||||||
|
|||||||
@@ -195,7 +195,6 @@ let step8TabUpdatedListener = null;
|
|||||||
let step8PendingReject = null;
|
let step8PendingReject = null;
|
||||||
let resumeWaiter = null;
|
let resumeWaiter = null;
|
||||||
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
|
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
|
||||||
const AUTO_RUN_TIMER_KIND_SCHEDULED_START = 'scheduled_start';
|
|
||||||
const DEFAULT_STATE = {
|
const DEFAULT_STATE = {
|
||||||
stepStatuses: Object.fromEntries([1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((step) => [step, 'pending'])),
|
stepStatuses: Object.fromEntries([1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((step) => [step, 'pending'])),
|
||||||
};
|
};
|
||||||
@@ -218,7 +217,6 @@ function abortActiveIcloudRequests() {}
|
|||||||
function getPendingAutoRunTimerPlan() {
|
function getPendingAutoRunTimerPlan() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
async function cancelScheduledAutoRun() {}
|
|
||||||
async function clearAutoRunTimerAlarm() {}
|
async function clearAutoRunTimerAlarm() {}
|
||||||
function clearStopRequest() {
|
function clearStopRequest() {
|
||||||
stopRequested = false;
|
stopRequested = false;
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ test('flow capability registry exposes Kiro as an independent flow with its own
|
|||||||
assert.deepEqual(capabilityState.flowCapabilities.contributionAdapterIds, ['kiro-builder-id']);
|
assert.deepEqual(capabilityState.flowCapabilities.contributionAdapterIds, ['kiro-builder-id']);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
capabilityState.visibleGroupIds,
|
capabilityState.visibleGroupIds,
|
||||||
['kiro-runtime-status', 'kiro-target-kiro-rs', 'service-account', 'service-email', 'service-proxy']
|
['kiro-runtime-status', 'shared-auto-run', 'shared-settings-actions', 'kiro-target-kiro-rs', 'service-account', 'service-email', 'service-proxy']
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ test('flow capability registry exposes Grok as an independent SSO flow without O
|
|||||||
assert.deepEqual(capabilityState.flowCapabilities.contributionAdapterIds, []);
|
assert.deepEqual(capabilityState.flowCapabilities.contributionAdapterIds, []);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
capabilityState.visibleGroupIds,
|
capabilityState.visibleGroupIds,
|
||||||
['grok-runtime-status', 'grok-target-webchat2api', 'service-account', 'service-email', 'service-proxy']
|
['grok-runtime-status', 'shared-auto-run', 'shared-settings-actions', 'grok-target-webchat2api', 'service-account', 'service-email', 'service-proxy']
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -21,20 +21,32 @@ test('flow registry exposes canonical flow and target metadata', () => {
|
|||||||
assert.equal(flowRegistry.normalizeFlowId('grok'), 'grok');
|
assert.equal(flowRegistry.normalizeFlowId('grok'), 'grok');
|
||||||
assert.equal(flowRegistry.normalizeFlowId('unknown'), 'openai');
|
assert.equal(flowRegistry.normalizeFlowId('unknown'), 'openai');
|
||||||
assert.equal(flowRegistry.getFlowLabel('openai'), 'Codex / OpenAI');
|
assert.equal(flowRegistry.getFlowLabel('openai'), 'Codex / OpenAI');
|
||||||
|
assert.deepEqual(
|
||||||
|
flowRegistry.getFlowDefinition('openai')?.settingsDefaults?.autoRun?.stepExecutionRange,
|
||||||
|
{ enabled: false, fromStep: 1, toStep: 11 }
|
||||||
|
);
|
||||||
|
assert.deepEqual(
|
||||||
|
flowRegistry.getFlowDefinition('openai')?.targets?.cpa?.defaultState,
|
||||||
|
{ vpsUrl: '', vpsPassword: '', localCpaStep9Mode: 'submit' }
|
||||||
|
);
|
||||||
|
assert.deepEqual(
|
||||||
|
flowRegistry.getFlowDefinition('kiro')?.targets?.['kiro-rs']?.defaultState,
|
||||||
|
{ baseUrl: '', apiKey: '' }
|
||||||
|
);
|
||||||
assert.equal(flowRegistry.normalizeTargetId('openai', 'sub2api'), 'sub2api');
|
assert.equal(flowRegistry.normalizeTargetId('openai', 'sub2api'), 'sub2api');
|
||||||
assert.equal(flowRegistry.normalizeTargetId('kiro', 'anything-else'), 'kiro-rs');
|
assert.equal(flowRegistry.normalizeTargetId('kiro', 'anything-else'), 'kiro-rs');
|
||||||
assert.equal(flowRegistry.normalizeTargetId('grok', 'anything-else'), 'webchat2api');
|
assert.equal(flowRegistry.normalizeTargetId('grok', 'anything-else'), 'webchat2api');
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
flowRegistry.getVisibleGroupIds('openai', 'cpa'),
|
flowRegistry.getVisibleGroupIds('openai', 'cpa'),
|
||||||
['openai-plus', 'openai-phone', 'openai-oauth', 'openai-step6', 'openai-target-cpa', 'service-account', 'service-email', 'service-proxy']
|
['openai-plus', 'openai-phone', 'shared-auto-run', 'openai-oauth', 'openai-step6', 'shared-settings-actions', 'openai-target-cpa', 'service-account', 'service-email', 'service-proxy']
|
||||||
);
|
);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
flowRegistry.getVisibleGroupIds('kiro', 'kiro-rs'),
|
flowRegistry.getVisibleGroupIds('kiro', 'kiro-rs'),
|
||||||
['kiro-runtime-status', 'kiro-target-kiro-rs', 'service-account', 'service-email', 'service-proxy']
|
['kiro-runtime-status', 'shared-auto-run', 'shared-settings-actions', 'kiro-target-kiro-rs', 'service-account', 'service-email', 'service-proxy']
|
||||||
);
|
);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
flowRegistry.getVisibleGroupIds('grok', 'webchat2api'),
|
flowRegistry.getVisibleGroupIds('grok', 'webchat2api'),
|
||||||
['grok-runtime-status', 'grok-target-webchat2api', 'service-account', 'service-email', 'service-proxy']
|
['grok-runtime-status', 'shared-auto-run', 'shared-settings-actions', 'grok-target-webchat2api', 'service-account', 'service-email', 'service-proxy']
|
||||||
);
|
);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
flowRegistry.getTargetOptions('openai').map((entry) => entry.id),
|
flowRegistry.getTargetOptions('openai').map((entry) => entry.id),
|
||||||
@@ -48,6 +60,14 @@ test('flow registry exposes canonical flow and target metadata', () => {
|
|||||||
flowRegistry.getSettingsGroupDefinition('openai-plus')?.rowIds,
|
flowRegistry.getSettingsGroupDefinition('openai-plus')?.rowIds,
|
||||||
['row-plus-mode', 'row-plus-account-access-strategy', 'row-plus-payment-method']
|
['row-plus-mode', 'row-plus-account-access-strategy', 'row-plus-payment-method']
|
||||||
);
|
);
|
||||||
|
assert.deepEqual(
|
||||||
|
flowRegistry.getSettingsGroupDefinition('shared-auto-run')?.rowIds,
|
||||||
|
['row-shared-auto-run', 'row-auto-run-thread-interval', 'row-step-execution-range']
|
||||||
|
);
|
||||||
|
assert.deepEqual(
|
||||||
|
flowRegistry.getSettingsGroupDefinition('shared-settings-actions')?.rowIds,
|
||||||
|
['row-settings-actions']
|
||||||
|
);
|
||||||
assert.equal(flowRegistry.getPublicationTargetDefinition('kiro', 'kiro-rs')?.label, 'kiro.rs');
|
assert.equal(flowRegistry.getPublicationTargetDefinition('kiro', 'kiro-rs')?.label, 'kiro.rs');
|
||||||
assert.equal(flowRegistry.getFlowCapabilities('openai').supportsAccountContribution, true);
|
assert.equal(flowRegistry.getFlowCapabilities('openai').supportsAccountContribution, true);
|
||||||
assert.equal(flowRegistry.getFlowCapabilities('kiro').supportsAccountContribution, true);
|
assert.equal(flowRegistry.getFlowCapabilities('kiro').supportsAccountContribution, true);
|
||||||
|
|||||||
@@ -78,6 +78,9 @@ test('grok verification runner polls by flow node and submits normalized code',
|
|||||||
registerTab: async () => {},
|
registerTab: async () => {},
|
||||||
sendToContentScriptResilient: async (sourceId, message) => {
|
sendToContentScriptResilient: async (sourceId, message) => {
|
||||||
calls.push({ type: 'send', sourceId, message });
|
calls.push({ type: 'send', sourceId, message });
|
||||||
|
if (message.nodeId === 'GET_PAGE_STATE') {
|
||||||
|
return { submitted: true, state: 'verification_code_entry', url: 'https://accounts.x.ai/verify' };
|
||||||
|
}
|
||||||
return { submitted: true, state: 'profile_entry', url: 'https://accounts.x.ai/profile' };
|
return { submitted: true, state: 'profile_entry', url: 'https://accounts.x.ai/profile' };
|
||||||
},
|
},
|
||||||
setState: async (patch) => {
|
setState: async (patch) => {
|
||||||
@@ -97,7 +100,9 @@ test('grok verification runner polls by flow node and submits normalized code',
|
|||||||
assert.equal(pollCall.options.state.activeFlowId, 'grok');
|
assert.equal(pollCall.options.state.activeFlowId, 'grok');
|
||||||
assert.equal(pollCall.options.state.visibleStep, 3);
|
assert.equal(pollCall.options.state.visibleStep, 3);
|
||||||
|
|
||||||
const sendCall = calls.find((entry) => entry.type === 'send');
|
const sendCall = calls.find((entry) => (
|
||||||
|
entry.type === 'send' && entry.message.nodeId === 'grok-submit-verification-code'
|
||||||
|
));
|
||||||
assert.equal(sendCall.sourceId, 'grok-register-page');
|
assert.equal(sendCall.sourceId, 'grok-register-page');
|
||||||
assert.equal(sendCall.message.type, 'EXECUTE_NODE');
|
assert.equal(sendCall.message.type, 'EXECUTE_NODE');
|
||||||
assert.equal(sendCall.message.nodeId, 'grok-submit-verification-code');
|
assert.equal(sendCall.message.nodeId, 'grok-submit-verification-code');
|
||||||
@@ -110,6 +115,75 @@ test('grok verification runner polls by flow node and submits normalized code',
|
|||||||
assert.equal(getGrokRuntime(completedPayload).register.status, 'verified');
|
assert.equal(getGrokRuntime(completedPayload).register.status, 'verified');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('grok verification runner waits for verification page before polling mail', async () => {
|
||||||
|
const api = loadGrokRunnerApi();
|
||||||
|
let pollCalled = false;
|
||||||
|
let currentState = {
|
||||||
|
activeFlowId: 'grok',
|
||||||
|
grokRegisterTabId: 102,
|
||||||
|
grokEmail: 'grok-user@example.com',
|
||||||
|
grokVerificationRequestedAt: 1000000,
|
||||||
|
runtimeState: {
|
||||||
|
flowState: {
|
||||||
|
grok: {
|
||||||
|
session: {
|
||||||
|
registerTabId: 102,
|
||||||
|
},
|
||||||
|
register: {
|
||||||
|
email: 'grok-user@example.com',
|
||||||
|
verificationRequestedAt: 1000000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const originalDateNow = Date.now;
|
||||||
|
let fakeNow = 1000000;
|
||||||
|
const runner = api.createGrokRegisterRunner({
|
||||||
|
addLog: async () => {},
|
||||||
|
chrome: {
|
||||||
|
tabs: {
|
||||||
|
get: async (tabId) => ({ id: tabId }),
|
||||||
|
update: async () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
completeNodeFromBackground: async () => {},
|
||||||
|
ensureContentScriptReadyOnTab: async () => {},
|
||||||
|
getState: async () => currentState,
|
||||||
|
getTabId: async () => 102,
|
||||||
|
isTabAlive: async () => true,
|
||||||
|
pollFlowVerificationCode: async () => {
|
||||||
|
pollCalled = true;
|
||||||
|
return { code: 'ABC-123', messageId: 'mail-001' };
|
||||||
|
},
|
||||||
|
registerTab: async () => {},
|
||||||
|
sendToContentScriptResilient: async (_sourceId, message) => {
|
||||||
|
if (message.nodeId === 'GET_PAGE_STATE') {
|
||||||
|
return { submitted: true, state: 'email_entry', url: 'https://accounts.x.ai/sign-up' };
|
||||||
|
}
|
||||||
|
return { submitted: true, state: 'profile_entry', url: 'https://accounts.x.ai/profile' };
|
||||||
|
},
|
||||||
|
setState: async (patch) => {
|
||||||
|
currentState = { ...currentState, ...patch };
|
||||||
|
},
|
||||||
|
sleepWithStop: async (ms = 0) => {
|
||||||
|
fakeNow += Number(ms) || 1000;
|
||||||
|
},
|
||||||
|
waitForTabStableComplete: async () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
Date.now = () => fakeNow;
|
||||||
|
try {
|
||||||
|
await assert.rejects(
|
||||||
|
() => runner.executeGrokSubmitVerificationCode({ nodeId: 'grok-submit-verification-code', ...currentState }),
|
||||||
|
/尚未进入验证码页面/
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
Date.now = originalDateNow;
|
||||||
|
}
|
||||||
|
assert.equal(pollCalled, false);
|
||||||
|
});
|
||||||
|
|
||||||
test('grok SSO extraction stores only the current cookie without logging the secret value', async () => {
|
test('grok SSO extraction stores only the current cookie without logging the secret value', async () => {
|
||||||
const api = loadGrokRunnerApi();
|
const api = loadGrokRunnerApi();
|
||||||
const logs = [];
|
const logs = [];
|
||||||
|
|||||||
@@ -85,7 +85,6 @@ test('sidepanel idle auto-run status does not reset manual run count input', ()
|
|||||||
extractFunction(source, 'syncAutoRunState'),
|
extractFunction(source, 'syncAutoRunState'),
|
||||||
extractFunction(source, 'isAutoRunLockedPhase'),
|
extractFunction(source, 'isAutoRunLockedPhase'),
|
||||||
extractFunction(source, 'isAutoRunPausedPhase'),
|
extractFunction(source, 'isAutoRunPausedPhase'),
|
||||||
extractFunction(source, 'isAutoRunScheduledPhase'),
|
|
||||||
extractFunction(source, 'applyAutoRunStatus'),
|
extractFunction(source, 'applyAutoRunStatus'),
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
@@ -96,7 +95,6 @@ let currentAutoRun = {
|
|||||||
currentRun: 0,
|
currentRun: 0,
|
||||||
totalRuns: 1,
|
totalRuns: 1,
|
||||||
attemptRun: 0,
|
attemptRun: 0,
|
||||||
scheduledAt: null,
|
|
||||||
countdownAt: null,
|
countdownAt: null,
|
||||||
countdownTitle: '',
|
countdownTitle: '',
|
||||||
countdownNote: '',
|
countdownNote: '',
|
||||||
@@ -116,9 +114,8 @@ function getLockedRunCountFromEmailPool() { return lockedRunCount; }
|
|||||||
function isCustomMailProvider() { return false; }
|
function isCustomMailProvider() { return false; }
|
||||||
function usesCustomEmailPoolGenerator() { return false; }
|
function usesCustomEmailPoolGenerator() { return false; }
|
||||||
function setDefaultAutoRunButton() {}
|
function setDefaultAutoRunButton() {}
|
||||||
function updateAutoDelayInputState() {}
|
|
||||||
function updateFallbackThreadIntervalInputState() {}
|
function updateFallbackThreadIntervalInputState() {}
|
||||||
function syncScheduledCountdownTicker() {}
|
function syncAutoRunCountdownTicker() {}
|
||||||
function updateStopButtonState() {}
|
function updateStopButtonState() {}
|
||||||
function getStepStatuses() { return {}; }
|
function getStepStatuses() { return {}; }
|
||||||
function updateConfigMenuControls() {}
|
function updateConfigMenuControls() {}
|
||||||
@@ -171,7 +168,6 @@ test('sidepanel pending auto-run start ignores stale active run count sync', ()
|
|||||||
extractFunction(source, 'syncAutoRunState'),
|
extractFunction(source, 'syncAutoRunState'),
|
||||||
extractFunction(source, 'isAutoRunLockedPhase'),
|
extractFunction(source, 'isAutoRunLockedPhase'),
|
||||||
extractFunction(source, 'isAutoRunPausedPhase'),
|
extractFunction(source, 'isAutoRunPausedPhase'),
|
||||||
extractFunction(source, 'isAutoRunScheduledPhase'),
|
|
||||||
extractFunction(source, 'isAutoRunSourceSyncPhase'),
|
extractFunction(source, 'isAutoRunSourceSyncPhase'),
|
||||||
extractFunction(source, 'shouldSyncRunCountFromAutoRunSource'),
|
extractFunction(source, 'shouldSyncRunCountFromAutoRunSource'),
|
||||||
extractFunction(source, 'applyAutoRunStatus'),
|
extractFunction(source, 'applyAutoRunStatus'),
|
||||||
@@ -184,7 +180,6 @@ let currentAutoRun = {
|
|||||||
currentRun: 0,
|
currentRun: 0,
|
||||||
totalRuns: 1,
|
totalRuns: 1,
|
||||||
attemptRun: 0,
|
attemptRun: 0,
|
||||||
scheduledAt: null,
|
|
||||||
countdownAt: null,
|
countdownAt: null,
|
||||||
countdownTitle: '',
|
countdownTitle: '',
|
||||||
countdownNote: '',
|
countdownNote: '',
|
||||||
@@ -205,9 +200,8 @@ function getLockedRunCountFromEmailPool() { return 0; }
|
|||||||
function isCustomMailProvider() { return false; }
|
function isCustomMailProvider() { return false; }
|
||||||
function usesCustomEmailPoolGenerator() { return false; }
|
function usesCustomEmailPoolGenerator() { return false; }
|
||||||
function setDefaultAutoRunButton() {}
|
function setDefaultAutoRunButton() {}
|
||||||
function updateAutoDelayInputState() {}
|
|
||||||
function updateFallbackThreadIntervalInputState() {}
|
function updateFallbackThreadIntervalInputState() {}
|
||||||
function syncScheduledCountdownTicker() {}
|
function syncAutoRunCountdownTicker() {}
|
||||||
function updateStopButtonState() {}
|
function updateStopButtonState() {}
|
||||||
function getStepStatuses() { return {}; }
|
function getStepStatuses() { return {}; }
|
||||||
function updateConfigMenuControls() {}
|
function updateConfigMenuControls() {}
|
||||||
|
|||||||
@@ -73,8 +73,6 @@ const inputAutoSkipFailures = { checked: false };
|
|||||||
const inputContributionNickname = { value: 'tester' };
|
const inputContributionNickname = { value: 'tester' };
|
||||||
const inputContributionQq = { value: '123456' };
|
const inputContributionQq = { value: '123456' };
|
||||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '5' };
|
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '5' };
|
||||||
const inputAutoDelayEnabled = { checked: false };
|
|
||||||
const inputAutoDelayMinutes = { value: '30' };
|
|
||||||
const btnAutoRun = { disabled: false, innerHTML: '' };
|
const btnAutoRun = { disabled: false, innerHTML: '' };
|
||||||
const inputRunCount = { disabled: false };
|
const inputRunCount = { disabled: false };
|
||||||
const selectFlow = { value: latestState.activeFlowId };
|
const selectFlow = { value: latestState.activeFlowId };
|
||||||
@@ -132,7 +130,6 @@ function shouldWarnAutoRunFallbackRisk() { return false; }
|
|||||||
function isAutoRunFallbackRiskPromptDismissed() { return false; }
|
function isAutoRunFallbackRiskPromptDismissed() { return false; }
|
||||||
async function openAutoRunFallbackRiskConfirmModal() { throw new Error('should not be called'); }
|
async function openAutoRunFallbackRiskConfirmModal() { throw new Error('should not be called'); }
|
||||||
function setAutoRunFallbackRiskPromptDismissed() {}
|
function setAutoRunFallbackRiskPromptDismissed() {}
|
||||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
|
||||||
async function refreshContributionContentHint() {
|
async function refreshContributionContentHint() {
|
||||||
events.push({ type: 'refresh' });
|
events.push({ type: 'refresh' });
|
||||||
${refreshImpl ? 'return (' + refreshImpl + ')();' : 'return null;'}
|
${refreshImpl ? 'return (' + refreshImpl + ')();' : 'return null;'}
|
||||||
@@ -272,8 +269,6 @@ const inputAutoSkipFailures = { checked: false };
|
|||||||
const inputContributionNickname = { value: 'tester' };
|
const inputContributionNickname = { value: 'tester' };
|
||||||
const inputContributionQq = { value: '123456' };
|
const inputContributionQq = { value: '123456' };
|
||||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '5' };
|
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '5' };
|
||||||
const inputAutoDelayEnabled = { checked: false };
|
|
||||||
const inputAutoDelayMinutes = { value: '30' };
|
|
||||||
const btnAutoRun = { disabled: false, innerHTML: '' };
|
const btnAutoRun = { disabled: false, innerHTML: '' };
|
||||||
const inputRunCount = { disabled: false, value: '1' };
|
const inputRunCount = { disabled: false, value: '1' };
|
||||||
const inputPhoneVerificationEnabled = { checked: true };
|
const inputPhoneVerificationEnabled = { checked: true };
|
||||||
@@ -324,7 +319,6 @@ function shouldWarnAutoRunFallbackRisk() { return false; }
|
|||||||
function isAutoRunFallbackRiskPromptDismissed() { return false; }
|
function isAutoRunFallbackRiskPromptDismissed() { return false; }
|
||||||
async function openAutoRunFallbackRiskConfirmModal() { throw new Error('should not be called'); }
|
async function openAutoRunFallbackRiskConfirmModal() { throw new Error('should not be called'); }
|
||||||
function setAutoRunFallbackRiskPromptDismissed() {}
|
function setAutoRunFallbackRiskPromptDismissed() {}
|
||||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
|
||||||
async function refreshContributionContentHint() {
|
async function refreshContributionContentHint() {
|
||||||
events.push({ type: 'refresh' });
|
events.push({ type: 'refresh' });
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -247,8 +247,6 @@ const inputTempEmailReceiveMailbox = { value: 'relay@example.com' };
|
|||||||
const inputTempEmailUseRandomSubdomain = { checked: true };
|
const inputTempEmailUseRandomSubdomain = { checked: true };
|
||||||
const inputAutoSkipFailures = { checked: false };
|
const inputAutoSkipFailures = { checked: false };
|
||||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '5' };
|
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '5' };
|
||||||
const inputAutoDelayEnabled = { checked: true };
|
|
||||||
const inputAutoDelayMinutes = { value: '30' };
|
|
||||||
const inputAutoStepDelaySeconds = { value: '10' };
|
const inputAutoStepDelaySeconds = { value: '10' };
|
||||||
const inputOAuthFlowTimeoutEnabled = { checked: true };
|
const inputOAuthFlowTimeoutEnabled = { checked: true };
|
||||||
const inputVerificationResendCount = { value: '6' };
|
const inputVerificationResendCount = { value: '6' };
|
||||||
@@ -297,7 +295,6 @@ function normalizeLuckmailEmailType(value) { return String(value || '').trim();
|
|||||||
function normalizeCloudflareTempEmailBaseUrlValue(value) { return String(value || '').trim(); }
|
function normalizeCloudflareTempEmailBaseUrlValue(value) { return String(value || '').trim(); }
|
||||||
function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); }
|
function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); }
|
||||||
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
|
||||||
function normalizeAutoStepDelaySeconds(value) { return value === '' ? null : Number(value); }
|
function normalizeAutoStepDelaySeconds(value) { return value === '' ? null : Number(value); }
|
||||||
function normalizeVerificationResendCount(value, fallback) { return Number.isFinite(Number(value)) ? Number(value) : fallback; }
|
function normalizeVerificationResendCount(value, fallback) { return Number.isFinite(Number(value)) ? Number(value) : fallback; }
|
||||||
function normalizePlusAccountAccessStrategy(value = '') { return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION ? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION : PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH; }
|
function normalizePlusAccountAccessStrategy(value = '') { return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION ? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION : PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH; }
|
||||||
|
|||||||
@@ -38,7 +38,12 @@ test('sidepanel html exposes flow selector and kiro source fields', () => {
|
|||||||
'id="select-flow"',
|
'id="select-flow"',
|
||||||
'<option value="grok">Grok</option>',
|
'<option value="grok">Grok</option>',
|
||||||
'id="label-source-selector"',
|
'id="label-source-selector"',
|
||||||
|
'id="btn-open-webchat2api-github"',
|
||||||
'id="row-step6-cookie-settings"',
|
'id="row-step6-cookie-settings"',
|
||||||
|
'id="row-shared-auto-run"',
|
||||||
|
'id="row-auto-run-thread-interval"',
|
||||||
|
'id="row-oauth-callback"',
|
||||||
|
'id="row-settings-actions"',
|
||||||
'id="row-kiro-rs-url"',
|
'id="row-kiro-rs-url"',
|
||||||
'id="btn-open-kiro-rs-github"',
|
'id="btn-open-kiro-rs-github"',
|
||||||
'id="row-kiro-rs-key"',
|
'id="row-kiro-rs-key"',
|
||||||
@@ -148,6 +153,10 @@ test('sidepanel Kiro GitHub button opens the configured fork', () => {
|
|||||||
assert.doesNotMatch(sidepanelSource, /github\.com\/hank9999\/kiro\.rs/);
|
assert.doesNotMatch(sidepanelSource, /github\.com\/hank9999\/kiro\.rs/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('sidepanel webchat2api GitHub button opens the configured repository', () => {
|
||||||
|
assert.match(sidepanelSource, /openExternalUrl\('https:\/\/github\.com\/zqbxdev\/webchat2api'\)/);
|
||||||
|
});
|
||||||
|
|
||||||
test('sidepanel step definitions rerender when active flow changes even if plus/signup settings stay the same', () => {
|
test('sidepanel step definitions rerender when active flow changes even if plus/signup settings stay the same', () => {
|
||||||
const bundle = [
|
const bundle = [
|
||||||
extractFunction(sidepanelSource, 'normalizeSignupMethod'),
|
extractFunction(sidepanelSource, 'normalizeSignupMethod'),
|
||||||
|
|||||||
@@ -132,8 +132,6 @@ const inputTempEmailReceiveMailbox = { value: '' };
|
|||||||
const inputTempEmailUseRandomSubdomain = { checked: false };
|
const inputTempEmailUseRandomSubdomain = { checked: false };
|
||||||
const inputAutoSkipFailures = { checked: false };
|
const inputAutoSkipFailures = { checked: false };
|
||||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '0' };
|
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '0' };
|
||||||
const inputAutoDelayEnabled = { checked: false };
|
|
||||||
const inputAutoDelayMinutes = { value: '30' };
|
|
||||||
const inputAutoStepDelaySeconds = { value: '' };
|
const inputAutoStepDelaySeconds = { value: '' };
|
||||||
const inputOAuthFlowTimeoutEnabled = { checked: true };
|
const inputOAuthFlowTimeoutEnabled = { checked: true };
|
||||||
const inputVerificationResendCount = { value: '4' };
|
const inputVerificationResendCount = { value: '4' };
|
||||||
@@ -220,7 +218,6 @@ function normalizeCloudflareTempEmailBaseUrlValue(value) { return String(value |
|
|||||||
function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); }
|
function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); }
|
||||||
function normalizeAccountRunHistoryHelperBaseUrlValue(value) { return String(value || '').trim(); }
|
function normalizeAccountRunHistoryHelperBaseUrlValue(value) { return String(value || '').trim(); }
|
||||||
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
|
||||||
function normalizeAutoStepDelaySeconds(value) { return value === '' ? null : Number(value); }
|
function normalizeAutoStepDelaySeconds(value) { return value === '' ? null : Number(value); }
|
||||||
function normalizeVerificationResendCount(value, fallback) { return Number(value) || fallback; }
|
function normalizeVerificationResendCount(value, fallback) { return Number(value) || fallback; }
|
||||||
function normalizePlusAccountAccessStrategy(value = '') { return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION ? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION : PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH; }
|
function normalizePlusAccountAccessStrategy(value = '') { return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION ? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION : PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH; }
|
||||||
@@ -408,8 +405,6 @@ const selectLuckmailEmailType = { value: 'ms_graph' };
|
|||||||
const inputLuckmailDomain = { value: '' };
|
const inputLuckmailDomain = { value: '' };
|
||||||
const inputAutoSkipFailures = { checked: false };
|
const inputAutoSkipFailures = { checked: false };
|
||||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '' };
|
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '' };
|
||||||
const inputAutoDelayEnabled = { checked: false };
|
|
||||||
const inputAutoDelayMinutes = { value: '' };
|
|
||||||
const inputAutoStepDelaySeconds = { value: '' };
|
const inputAutoStepDelaySeconds = { value: '' };
|
||||||
const inputOAuthFlowTimeoutEnabled = { checked: true };
|
const inputOAuthFlowTimeoutEnabled = { checked: true };
|
||||||
const inputVerificationResendCount = { value: '' };
|
const inputVerificationResendCount = { value: '' };
|
||||||
@@ -483,7 +478,6 @@ function applyCloudflareTempEmailSettingsState() {}
|
|||||||
function renderCloudflareDomainOptions() {}
|
function renderCloudflareDomainOptions() {}
|
||||||
function setCloudflareDomainEditMode() {}
|
function setCloudflareDomainEditMode() {}
|
||||||
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
|
||||||
function formatAutoStepDelayInputValue(value) { return value == null ? '' : String(value); }
|
function formatAutoStepDelayInputValue(value) { return value == null ? '' : String(value); }
|
||||||
function normalizeVerificationResendCount(value, fallback) { return Number(value) || fallback; }
|
function normalizeVerificationResendCount(value, fallback) { return Number(value) || fallback; }
|
||||||
function normalizeHeroSmsMaxPriceValue(value = '') { return String(value || '').trim(); }
|
function normalizeHeroSmsMaxPriceValue(value = '') { return String(value || '').trim(); }
|
||||||
@@ -519,7 +513,6 @@ function updateHeroSmsPlatformDisplay() {}
|
|||||||
function updatePhoneSmsProviderOrderSummary() {}
|
function updatePhoneSmsProviderOrderSummary() {}
|
||||||
function applyAutoRunStatus() {}
|
function applyAutoRunStatus() {}
|
||||||
function markSettingsDirty() {}
|
function markSettingsDirty() {}
|
||||||
function updateAutoDelayInputState() {}
|
|
||||||
function updateFallbackThreadIntervalInputState() {}
|
function updateFallbackThreadIntervalInputState() {}
|
||||||
function updateAccountRunHistorySettingsUI() {}
|
function updateAccountRunHistorySettingsUI() {}
|
||||||
function updatePhoneVerificationSettingsUI() {}
|
function updatePhoneVerificationSettingsUI() {}
|
||||||
|
|||||||
@@ -203,8 +203,6 @@ const inputTempEmailReceiveMailbox = { value: '' };
|
|||||||
const inputTempEmailUseRandomSubdomain = { checked: false };
|
const inputTempEmailUseRandomSubdomain = { checked: false };
|
||||||
const inputAutoSkipFailures = { checked: false };
|
const inputAutoSkipFailures = { checked: false };
|
||||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '0' };
|
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '0' };
|
||||||
const inputAutoDelayEnabled = { checked: false };
|
|
||||||
const inputAutoDelayMinutes = { value: '30' };
|
|
||||||
const inputAutoStepDelaySeconds = { value: '' };
|
const inputAutoStepDelaySeconds = { value: '' };
|
||||||
const inputOAuthFlowTimeoutEnabled = { checked: true };
|
const inputOAuthFlowTimeoutEnabled = { checked: true };
|
||||||
const inputVerificationResendCount = { value: '4' };
|
const inputVerificationResendCount = { value: '4' };
|
||||||
@@ -258,7 +256,6 @@ function normalizeCloudflareTempEmailBaseUrlValue(value) { return String(value |
|
|||||||
function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); }
|
function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); }
|
||||||
function normalizeAccountRunHistoryHelperBaseUrlValue(value) { return String(value || '').trim(); }
|
function normalizeAccountRunHistoryHelperBaseUrlValue(value) { return String(value || '').trim(); }
|
||||||
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
|
||||||
function normalizeAutoStepDelaySeconds(value) { return value === '' ? null : Number(value); }
|
function normalizeAutoStepDelaySeconds(value) { return value === '' ? null : Number(value); }
|
||||||
function normalizeVerificationResendCount(value, fallback) { return Number(value) || fallback; }
|
function normalizeVerificationResendCount(value, fallback) { return Number(value) || fallback; }
|
||||||
function normalizePlusAccountAccessStrategy(value = '') { return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION ? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION : PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH; }
|
function normalizePlusAccountAccessStrategy(value = '') { return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION ? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION : PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH; }
|
||||||
|
|||||||
@@ -38,25 +38,37 @@ function extractFunction(name) {
|
|||||||
throw new Error(`unterminated ${name}`);
|
throw new Error(`unterminated ${name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
test('sidepanel no longer exposes operation delay switch and places step execution range below oauth timeout', () => {
|
test('sidepanel splits shared auto-run controls from openai oauth controls', () => {
|
||||||
assert.doesNotMatch(html, /id="row-operation-delay-settings"/);
|
assert.doesNotMatch(html, /id="row-operation-delay-settings"/);
|
||||||
assert.doesNotMatch(html, /id="input-operation-delay-enabled"/);
|
assert.doesNotMatch(html, /id="input-operation-delay-enabled"/);
|
||||||
|
assert.doesNotMatch(html, /id="row-auto-delay-settings"/);
|
||||||
|
assert.doesNotMatch(html, /id="input-auto-delay-enabled"/);
|
||||||
|
assert.doesNotMatch(html, /id="input-auto-delay-minutes"/);
|
||||||
|
|
||||||
const step6CookieIndex = html.indexOf('id="row-step6-cookie-settings"');
|
const step6CookieIndex = html.indexOf('id="row-step6-cookie-settings"');
|
||||||
const autoDelayIndex = html.indexOf('id="row-auto-delay-settings"');
|
const sharedAutoRunIndex = html.indexOf('id="row-shared-auto-run"');
|
||||||
|
const threadIntervalIndex = html.indexOf('id="row-auto-run-thread-interval"');
|
||||||
const oauthTimeoutIndex = html.indexOf('id="row-oauth-flow-timeout"');
|
const oauthTimeoutIndex = html.indexOf('id="row-oauth-flow-timeout"');
|
||||||
const stepRangeIndex = html.indexOf('id="row-step-execution-range"');
|
const stepRangeIndex = html.indexOf('id="row-step-execution-range"');
|
||||||
const oauthDisplayIndex = html.indexOf('id="row-oauth-display"');
|
const oauthDisplayIndex = html.indexOf('id="row-oauth-display"');
|
||||||
|
const oauthCallbackIndex = html.indexOf('id="row-oauth-callback"');
|
||||||
|
const settingsActionsIndex = html.indexOf('id="row-settings-actions"');
|
||||||
|
|
||||||
assert.notEqual(step6CookieIndex, -1);
|
assert.notEqual(step6CookieIndex, -1);
|
||||||
assert.notEqual(autoDelayIndex, -1);
|
assert.notEqual(sharedAutoRunIndex, -1);
|
||||||
|
assert.notEqual(threadIntervalIndex, -1);
|
||||||
assert.notEqual(oauthTimeoutIndex, -1);
|
assert.notEqual(oauthTimeoutIndex, -1);
|
||||||
assert.notEqual(stepRangeIndex, -1);
|
assert.notEqual(stepRangeIndex, -1);
|
||||||
assert.notEqual(oauthDisplayIndex, -1);
|
assert.notEqual(oauthDisplayIndex, -1);
|
||||||
assert.ok(autoDelayIndex > step6CookieIndex, 'startup delay row should render below the openai step6 cookie row');
|
assert.notEqual(oauthCallbackIndex, -1);
|
||||||
assert.ok(stepRangeIndex > autoDelayIndex, 'step execution range should still remain below the startup delay row');
|
assert.notEqual(settingsActionsIndex, -1);
|
||||||
|
assert.ok(sharedAutoRunIndex > step6CookieIndex, 'shared auto-run should render below the openai step6 cookie row');
|
||||||
|
assert.ok(threadIntervalIndex > sharedAutoRunIndex, 'thread interval should be part of the shared auto-run block');
|
||||||
|
assert.ok(threadIntervalIndex < oauthTimeoutIndex, 'thread interval should stay outside openai oauth controls');
|
||||||
assert.ok(stepRangeIndex > oauthTimeoutIndex, 'step execution range should render below oauth timeout');
|
assert.ok(stepRangeIndex > oauthTimeoutIndex, 'step execution range should render below oauth timeout');
|
||||||
assert.ok(stepRangeIndex < oauthDisplayIndex, 'step execution range should stay above oauth runtime display');
|
assert.ok(stepRangeIndex < oauthDisplayIndex, 'step execution range should stay above oauth runtime display');
|
||||||
|
assert.ok(oauthCallbackIndex > oauthDisplayIndex, 'openai callback row should follow the oauth display');
|
||||||
|
assert.ok(settingsActionsIndex > oauthCallbackIndex, 'save settings action should live outside the callback row');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('sidepanel operation delay state is always normalized back to enabled', () => {
|
test('sidepanel operation delay state is always normalized back to enabled', () => {
|
||||||
|
|||||||
@@ -713,7 +713,6 @@ function setFreePhoneReuseControlsLocked(locked) {
|
|||||||
|| !Boolean(inputPhoneVerificationEnabled.checked && phoneVerificationSectionExpanded);
|
|| !Boolean(inputPhoneVerificationEnabled.checked && phoneVerificationSectionExpanded);
|
||||||
}
|
}
|
||||||
function isAutoRunLockedPhase() { return false; }
|
function isAutoRunLockedPhase() { return false; }
|
||||||
function isAutoRunScheduledPhase() { return false; }
|
|
||||||
|
|
||||||
${extractFunction('normalizeSignupMethod')}
|
${extractFunction('normalizeSignupMethod')}
|
||||||
${extractFunction('normalizeHeroSmsReuseEnabledValue')}
|
${extractFunction('normalizeHeroSmsReuseEnabledValue')}
|
||||||
@@ -979,8 +978,6 @@ const inputTempEmailReceiveMailbox = { value: '' };
|
|||||||
const inputTempEmailUseRandomSubdomain = { checked: false };
|
const inputTempEmailUseRandomSubdomain = { checked: false };
|
||||||
const inputAutoSkipFailures = { checked: false };
|
const inputAutoSkipFailures = { checked: false };
|
||||||
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '0' };
|
const inputAutoSkipFailuresThreadIntervalMinutes = { value: '0' };
|
||||||
const inputAutoDelayEnabled = { checked: false };
|
|
||||||
const inputAutoDelayMinutes = { value: '30' };
|
|
||||||
const inputAutoStepDelaySeconds = { value: '' };
|
const inputAutoStepDelaySeconds = { value: '' };
|
||||||
const inputPhoneVerificationEnabled = { checked: true };
|
const inputPhoneVerificationEnabled = { checked: true };
|
||||||
const inputFreePhoneReuseEnabled = { checked: true };
|
const inputFreePhoneReuseEnabled = { checked: true };
|
||||||
@@ -1072,7 +1069,6 @@ function normalizeCloudflareTempEmailBaseUrlValue(value) { return String(value |
|
|||||||
function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); }
|
function normalizeCloudflareTempEmailReceiveMailboxValue(value) { return String(value || '').trim(); }
|
||||||
function normalizeAccountRunHistoryHelperBaseUrlValue(value) { return String(value || '').trim(); }
|
function normalizeAccountRunHistoryHelperBaseUrlValue(value) { return String(value || '').trim(); }
|
||||||
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
function normalizeAutoRunThreadIntervalMinutes(value) { return Number(value) || 0; }
|
||||||
function normalizeAutoDelayMinutes(value) { return Number(value) || 30; }
|
|
||||||
function normalizeAutoStepDelaySeconds(value) { return value === '' ? null : Number(value); }
|
function normalizeAutoStepDelaySeconds(value) { return value === '' ? null : Number(value); }
|
||||||
function normalizeVerificationResendCount(value, fallback) { return Number(value) || fallback; }
|
function normalizeVerificationResendCount(value, fallback) { return Number(value) || fallback; }
|
||||||
function normalizePlusAccountAccessStrategy(value = '') { return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION ? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION : PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH; }
|
function normalizePlusAccountAccessStrategy(value = '') { return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION ? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION : PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH; }
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ let autoRunCurrentRun = 2;
|
|||||||
let autoRunTotalRuns = 3;
|
let autoRunTotalRuns = 3;
|
||||||
let autoRunAttemptRun = 4;
|
let autoRunAttemptRun = 4;
|
||||||
let autoRunSessionId = 99;
|
let autoRunSessionId = 99;
|
||||||
const AUTO_RUN_TIMER_KIND_SCHEDULED_START = 'scheduled_start';
|
|
||||||
const DEFAULT_STATE = {
|
const DEFAULT_STATE = {
|
||||||
nodeStatuses: {},
|
nodeStatuses: {},
|
||||||
};
|
};
|
||||||
@@ -158,9 +157,6 @@ async function getState() {
|
|||||||
function getPendingAutoRunTimerPlan() {
|
function getPendingAutoRunTimerPlan() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
function isAutoRunScheduledState() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
function getStep8CallbackUrlFromNavigation() { return ''; }
|
function getStep8CallbackUrlFromNavigation() { return ''; }
|
||||||
function getStep8CallbackUrlFromTabUpdate() { return ''; }
|
function getStep8CallbackUrlFromTabUpdate() { return ''; }
|
||||||
function getStep8EffectLabel() { return 'no_effect'; }
|
function getStep8EffectLabel() { return 'no_effect'; }
|
||||||
|
|||||||
Reference in New Issue
Block a user