142 lines
4.2 KiB
JavaScript
142 lines
4.2 KiB
JavaScript
(function authPageRecoveryModule(root, factory) {
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = factory();
|
|
return;
|
|
}
|
|
|
|
root.MultiPageAuthPageRecovery = factory();
|
|
})(typeof self !== 'undefined' ? self : globalThis, function createAuthPageRecoveryModule() {
|
|
function createAuthPageRecovery(deps = {}) {
|
|
const {
|
|
detailPattern = null,
|
|
getActionText,
|
|
getPageTextSnapshot,
|
|
humanPause,
|
|
isActionEnabled,
|
|
isVisibleElement,
|
|
log,
|
|
simulateClick,
|
|
sleep,
|
|
throwIfStopped,
|
|
titlePattern = null,
|
|
} = deps;
|
|
|
|
function matchesPathPatterns(pathname, pathPatterns = []) {
|
|
if (!Array.isArray(pathPatterns) || !pathPatterns.length) {
|
|
return true;
|
|
}
|
|
return pathPatterns.some((pattern) => pattern instanceof RegExp && pattern.test(pathname));
|
|
}
|
|
|
|
function getAuthRetryButton(options = {}) {
|
|
const { allowDisabled = false } = options;
|
|
const direct = document.querySelector('button[data-dd-action-name="Try again"]');
|
|
if (direct && isVisibleElement(direct) && (allowDisabled || isActionEnabled(direct))) {
|
|
return direct;
|
|
}
|
|
|
|
const candidates = document.querySelectorAll('button, [role="button"]');
|
|
return Array.from(candidates).find((element) => {
|
|
if (!isVisibleElement(element) || (!allowDisabled && !isActionEnabled(element))) {
|
|
return false;
|
|
}
|
|
const text = typeof getActionText === 'function' ? getActionText(element) : '';
|
|
return /重试|try\s+again/i.test(text);
|
|
}) || null;
|
|
}
|
|
|
|
function getAuthTimeoutErrorPageState(options = {}) {
|
|
const { pathPatterns = [] } = options;
|
|
const pathname = location.pathname || '';
|
|
if (!matchesPathPatterns(pathname, pathPatterns)) {
|
|
return null;
|
|
}
|
|
|
|
const retryButton = getAuthRetryButton({ allowDisabled: true });
|
|
if (!retryButton) {
|
|
return null;
|
|
}
|
|
|
|
const text = typeof getPageTextSnapshot === 'function' ? getPageTextSnapshot() : '';
|
|
const title = typeof document !== 'undefined' ? String(document.title || '') : '';
|
|
const titleMatched = titlePattern instanceof RegExp
|
|
? titlePattern.test(text) || titlePattern.test(title)
|
|
: false;
|
|
const detailMatched = detailPattern instanceof RegExp
|
|
? detailPattern.test(text)
|
|
: false;
|
|
|
|
if (!titleMatched && !detailMatched) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
path: pathname,
|
|
url: location.href,
|
|
retryButton,
|
|
retryEnabled: isActionEnabled(retryButton),
|
|
titleMatched,
|
|
detailMatched,
|
|
};
|
|
}
|
|
|
|
async function recoverAuthRetryPage(options = {}) {
|
|
const {
|
|
logLabel = '',
|
|
pathPatterns = [],
|
|
pollIntervalMs = 250,
|
|
step = null,
|
|
timeoutMs = 12000,
|
|
waitAfterClickMs = 1200,
|
|
} = options;
|
|
const start = Date.now();
|
|
let clickCount = 0;
|
|
|
|
while (Date.now() - start < timeoutMs) {
|
|
if (typeof throwIfStopped === 'function') {
|
|
throwIfStopped();
|
|
}
|
|
|
|
const retryState = getAuthTimeoutErrorPageState({ pathPatterns });
|
|
if (!retryState) {
|
|
return {
|
|
recovered: clickCount > 0,
|
|
clickCount,
|
|
url: location.href,
|
|
};
|
|
}
|
|
|
|
if (retryState.retryButton && retryState.retryEnabled) {
|
|
clickCount += 1;
|
|
if (typeof log === 'function') {
|
|
const prefix = logLabel || `步骤 ${step || '?'}:检测到重试页,正在点击“重试”恢复`;
|
|
log(`${prefix}(第 ${clickCount} 次)...`, 'warn');
|
|
}
|
|
if (typeof humanPause === 'function') {
|
|
await humanPause(300, 800);
|
|
}
|
|
simulateClick(retryState.retryButton);
|
|
await sleep(waitAfterClickMs);
|
|
continue;
|
|
}
|
|
|
|
await sleep(pollIntervalMs);
|
|
}
|
|
|
|
throw new Error(
|
|
`${logLabel || `步骤 ${step || '?'}:重试页恢复`}超时。URL: ${location.href}`
|
|
);
|
|
}
|
|
|
|
return {
|
|
getAuthRetryButton,
|
|
getAuthTimeoutErrorPageState,
|
|
recoverAuthRetryPage,
|
|
};
|
|
}
|
|
|
|
return {
|
|
createAuthPageRecovery,
|
|
};
|
|
});
|