feat: 添加共享 Kiro 超时模块并更新相关文件以使用统一的页面加载超时预算
This commit is contained in:
+3
-2
@@ -5,6 +5,7 @@ importScripts(
|
|||||||
'shared/settings-schema.js',
|
'shared/settings-schema.js',
|
||||||
'shared/source-registry.js',
|
'shared/source-registry.js',
|
||||||
'shared/flow-capabilities.js',
|
'shared/flow-capabilities.js',
|
||||||
|
'shared/kiro-timeouts.js',
|
||||||
'managed-alias-utils.js',
|
'managed-alias-utils.js',
|
||||||
'mail2925-utils.js',
|
'mail2925-utils.js',
|
||||||
'paypal-utils.js',
|
'paypal-utils.js',
|
||||||
@@ -12744,8 +12745,8 @@ async function resumeAutoRun() {
|
|||||||
|
|
||||||
const SIGNUP_ENTRY_URL = 'https://chatgpt.com/';
|
const SIGNUP_ENTRY_URL = 'https://chatgpt.com/';
|
||||||
const SIGNUP_PAGE_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'content/auth-page-recovery.js', 'content/phone-country-utils.js', 'content/phone-auth.js', 'content/signup-page.js'];
|
const SIGNUP_PAGE_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'content/auth-page-recovery.js', 'content/phone-country-utils.js', 'content/phone-auth.js', 'content/signup-page.js'];
|
||||||
const KIRO_REGISTER_INJECT_FILES = ['shared/source-registry.js', 'content/utils.js', 'content/kiro/register-page.js'];
|
const KIRO_REGISTER_INJECT_FILES = ['shared/source-registry.js', 'shared/kiro-timeouts.js', 'content/utils.js', 'content/kiro/register-page.js'];
|
||||||
const KIRO_DESKTOP_AUTHORIZE_INJECT_FILES = ['shared/source-registry.js', 'content/utils.js', 'content/kiro/desktop-authorize-page.js'];
|
const KIRO_DESKTOP_AUTHORIZE_INJECT_FILES = ['shared/source-registry.js', 'shared/kiro-timeouts.js', 'content/utils.js', 'content/kiro/desktop-authorize-page.js'];
|
||||||
const panelBridge = self.MultiPageBackgroundPanelBridge?.createPanelBridge({
|
const panelBridge = self.MultiPageBackgroundPanelBridge?.createPanelBridge({
|
||||||
chrome,
|
chrome,
|
||||||
addLog,
|
addLog,
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundKiroDesktopAuthorizeRunnerModule(root) {
|
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundKiroDesktopAuthorizeRunnerModule(root) {
|
||||||
const kiroStateApi = root.MultiPageBackgroundKiroState || null;
|
const kiroStateApi = root.MultiPageBackgroundKiroState || null;
|
||||||
const desktopClientApi = root.MultiPageBackgroundKiroDesktopClient || null;
|
const desktopClientApi = root.MultiPageBackgroundKiroDesktopClient || null;
|
||||||
|
const kiroTimeoutApi = root.MultiPageKiroTimeouts || null;
|
||||||
const DEFAULT_REGION = kiroStateApi?.DEFAULT_REGION || desktopClientApi?.DEFAULT_REGION || 'us-east-1';
|
const DEFAULT_REGION = kiroStateApi?.DEFAULT_REGION || desktopClientApi?.DEFAULT_REGION || 'us-east-1';
|
||||||
|
const DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS = kiroTimeoutApi?.DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS || (3 * 60 * 1000);
|
||||||
const MAIL_2925_FILTER_LOOKBACK_MS = 10 * 60 * 1000;
|
const MAIL_2925_FILTER_LOOKBACK_MS = 10 * 60 * 1000;
|
||||||
const KIRO_DESKTOP_SOURCE_ID = 'kiro-desktop-authorize';
|
const KIRO_DESKTOP_SOURCE_ID = 'kiro-desktop-authorize';
|
||||||
const KIRO_AWS_VERIFICATION_CODE_PATTERNS = Object.freeze([
|
const KIRO_AWS_VERIFICATION_CODE_PATTERNS = Object.freeze([
|
||||||
@@ -107,6 +109,36 @@
|
|||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeKiroPageLoadTimeoutMs(value, fallback = DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS) {
|
||||||
|
if (typeof kiroTimeoutApi?.normalizeKiroPageLoadTimeoutMs === 'function') {
|
||||||
|
return kiroTimeoutApi.normalizeKiroPageLoadTimeoutMs(value, fallback);
|
||||||
|
}
|
||||||
|
return normalizePositiveInteger(value, normalizePositiveInteger(fallback, DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS));
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTimeoutBudget(timeoutMs = DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS) {
|
||||||
|
const totalTimeoutMs = normalizeKiroPageLoadTimeoutMs(timeoutMs, DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS);
|
||||||
|
const startedAt = Date.now();
|
||||||
|
return {
|
||||||
|
totalTimeoutMs,
|
||||||
|
getRemainingMs(minimumMs = 1) {
|
||||||
|
const normalizedMinimumMs = normalizePositiveInteger(minimumMs, 1);
|
||||||
|
return Math.max(normalizedMinimumMs, totalTimeoutMs - (Date.now() - startedAt));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveTimeoutBudget(options = {}, fallbackTimeoutMs = DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS) {
|
||||||
|
if (options?.timeoutBudget && typeof options.timeoutBudget.getRemainingMs === 'function') {
|
||||||
|
return options.timeoutBudget;
|
||||||
|
}
|
||||||
|
return createTimeoutBudget(
|
||||||
|
options?.pageTimeoutMs
|
||||||
|
?? options?.timeoutMs
|
||||||
|
?? fallbackTimeoutMs
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function getErrorMessage(error) {
|
function getErrorMessage(error) {
|
||||||
return error instanceof Error ? error.message : String(error ?? '未知错误');
|
return error instanceof Error ? error.message : String(error ?? '未知错误');
|
||||||
}
|
}
|
||||||
@@ -418,9 +450,10 @@
|
|||||||
if (!Number.isInteger(tabId)) {
|
if (!Number.isInteger(tabId)) {
|
||||||
throw new Error('缺少 Kiro 桌面授权页标签页,无法重新连接内容脚本。');
|
throw new Error('缺少 Kiro 桌面授权页标签页,无法重新连接内容脚本。');
|
||||||
}
|
}
|
||||||
|
const timeoutBudget = resolveTimeoutBudget(options);
|
||||||
if (typeof waitForTabStableComplete === 'function') {
|
if (typeof waitForTabStableComplete === 'function') {
|
||||||
await waitForTabStableComplete(tabId, {
|
await waitForTabStableComplete(tabId, {
|
||||||
timeoutMs: 45000,
|
timeoutMs: timeoutBudget.getRemainingMs(1000),
|
||||||
retryDelayMs: 300,
|
retryDelayMs: 300,
|
||||||
stableMs: Number(options.stableMs) || 1200,
|
stableMs: Number(options.stableMs) || 1200,
|
||||||
initialDelayMs: Number(options.initialDelayMs) || 120,
|
initialDelayMs: Number(options.initialDelayMs) || 120,
|
||||||
@@ -430,7 +463,7 @@
|
|||||||
await ensureContentScriptReadyOnTab(KIRO_DESKTOP_SOURCE_ID, tabId, {
|
await ensureContentScriptReadyOnTab(KIRO_DESKTOP_SOURCE_ID, tabId, {
|
||||||
inject: Array.isArray(KIRO_DESKTOP_AUTHORIZE_INJECT_FILES) ? KIRO_DESKTOP_AUTHORIZE_INJECT_FILES : null,
|
inject: Array.isArray(KIRO_DESKTOP_AUTHORIZE_INJECT_FILES) ? KIRO_DESKTOP_AUTHORIZE_INJECT_FILES : null,
|
||||||
injectSource: KIRO_DESKTOP_SOURCE_ID,
|
injectSource: KIRO_DESKTOP_SOURCE_ID,
|
||||||
timeoutMs: 45000,
|
timeoutMs: timeoutBudget.getRemainingMs(1000),
|
||||||
retryDelayMs: 800,
|
retryDelayMs: 800,
|
||||||
logMessage: options.injectLogMessage || 'Kiro 桌面授权页已跳转,正在重新连接内容脚本...',
|
logMessage: options.injectLogMessage || 'Kiro 桌面授权页已跳转,正在重新连接内容脚本...',
|
||||||
});
|
});
|
||||||
@@ -438,8 +471,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildDesktopRetryRecovery(tabId, options = {}) {
|
function buildDesktopRetryRecovery(tabId, options = {}) {
|
||||||
return async () => {
|
return async (_error, context = {}) => {
|
||||||
|
const remainingTimeoutMs = normalizeKiroPageLoadTimeoutMs(
|
||||||
|
options?.timeoutBudget?.getRemainingMs?.(1000)
|
||||||
|
?? context?.remainingTimeoutMs,
|
||||||
|
DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS
|
||||||
|
);
|
||||||
await reattachDesktopAuthorizePage(tabId, {
|
await reattachDesktopAuthorizePage(tabId, {
|
||||||
|
timeoutMs: remainingTimeoutMs,
|
||||||
|
timeoutBudget: createTimeoutBudget(remainingTimeoutMs),
|
||||||
stableMs: Number(options.recoveryStableMs) || Number(options.stableMs) || 1200,
|
stableMs: Number(options.recoveryStableMs) || Number(options.stableMs) || 1200,
|
||||||
initialDelayMs: Number(options.recoveryInitialDelayMs) || 120,
|
initialDelayMs: Number(options.recoveryInitialDelayMs) || 120,
|
||||||
injectLogMessage: options.recoveryInjectLogMessage || options.injectLogMessage || 'Kiro 桌面授权页已跳转,正在重新连接内容脚本...',
|
injectLogMessage: options.recoveryInjectLogMessage || options.injectLogMessage || 'Kiro 桌面授权页已跳转,正在重新连接内容脚本...',
|
||||||
@@ -451,9 +491,14 @@
|
|||||||
if (!Number.isInteger(tabId)) {
|
if (!Number.isInteger(tabId)) {
|
||||||
throw new Error('缺少 Kiro 桌面授权页标签页,无法继续执行。');
|
throw new Error('缺少 Kiro 桌面授权页标签页,无法继续执行。');
|
||||||
}
|
}
|
||||||
|
const pageLoadTimeoutMs = normalizeKiroPageLoadTimeoutMs(
|
||||||
|
options.pageTimeoutMs,
|
||||||
|
DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS
|
||||||
|
);
|
||||||
|
const timeoutBudget = resolveTimeoutBudget(options, pageLoadTimeoutMs);
|
||||||
if (typeof waitForTabStableComplete === 'function') {
|
if (typeof waitForTabStableComplete === 'function') {
|
||||||
await waitForTabStableComplete(tabId, {
|
await waitForTabStableComplete(tabId, {
|
||||||
timeoutMs: 45000,
|
timeoutMs: timeoutBudget.getRemainingMs(1000),
|
||||||
retryDelayMs: 300,
|
retryDelayMs: 300,
|
||||||
stableMs: Number(options.stableMs) || 1200,
|
stableMs: Number(options.stableMs) || 1200,
|
||||||
initialDelayMs: Number(options.initialDelayMs) || 120,
|
initialDelayMs: Number(options.initialDelayMs) || 120,
|
||||||
@@ -463,19 +508,23 @@
|
|||||||
await ensureContentScriptReadyOnTab(KIRO_DESKTOP_SOURCE_ID, tabId, {
|
await ensureContentScriptReadyOnTab(KIRO_DESKTOP_SOURCE_ID, tabId, {
|
||||||
inject: Array.isArray(KIRO_DESKTOP_AUTHORIZE_INJECT_FILES) ? KIRO_DESKTOP_AUTHORIZE_INJECT_FILES : null,
|
inject: Array.isArray(KIRO_DESKTOP_AUTHORIZE_INJECT_FILES) ? KIRO_DESKTOP_AUTHORIZE_INJECT_FILES : null,
|
||||||
injectSource: KIRO_DESKTOP_SOURCE_ID,
|
injectSource: KIRO_DESKTOP_SOURCE_ID,
|
||||||
timeoutMs: 45000,
|
timeoutMs: timeoutBudget.getRemainingMs(1000),
|
||||||
retryDelayMs: 800,
|
retryDelayMs: 800,
|
||||||
logMessage: options.injectLogMessage || 'Kiro 桌面授权页内容脚本未就绪,正在等待页面恢复...',
|
logMessage: options.injectLogMessage || 'Kiro 桌面授权页内容脚本未就绪,正在等待页面恢复...',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const stateWaitTimeoutMs = timeoutBudget.getRemainingMs(1000);
|
||||||
const result = await sendToContentScriptResilient(KIRO_DESKTOP_SOURCE_ID, {
|
const result = await sendToContentScriptResilient(KIRO_DESKTOP_SOURCE_ID, {
|
||||||
type: 'GET_KIRO_DESKTOP_AUTHORIZE_STATE',
|
type: 'GET_KIRO_DESKTOP_AUTHORIZE_STATE',
|
||||||
step: options.step || 0,
|
step: options.step || 0,
|
||||||
source: 'background',
|
source: 'background',
|
||||||
}, {
|
}, {
|
||||||
timeoutMs: 30000,
|
timeoutMs: stateWaitTimeoutMs,
|
||||||
retryDelayMs: 700,
|
retryDelayMs: 700,
|
||||||
onRetryableError: buildDesktopRetryRecovery(tabId, options),
|
onRetryableError: buildDesktopRetryRecovery(tabId, {
|
||||||
|
...options,
|
||||||
|
timeoutBudget,
|
||||||
|
}),
|
||||||
logMessage: options.readyLogMessage || '正在读取 Kiro 桌面授权页状态...',
|
logMessage: options.readyLogMessage || '正在读取 Kiro 桌面授权页状态...',
|
||||||
});
|
});
|
||||||
if (result?.error) {
|
if (result?.error) {
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
root.MultiPageBackgroundKiroRegisterRunner = factory(root);
|
root.MultiPageBackgroundKiroRegisterRunner = factory(root);
|
||||||
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundKiroRegisterRunnerModule(root) {
|
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundKiroRegisterRunnerModule(root) {
|
||||||
const kiroStateApi = root.MultiPageBackgroundKiroState || null;
|
const kiroStateApi = root.MultiPageBackgroundKiroState || null;
|
||||||
|
const kiroTimeoutApi = root.MultiPageKiroTimeouts || null;
|
||||||
const DEFAULT_REGION = kiroStateApi?.DEFAULT_REGION || 'us-east-1';
|
const DEFAULT_REGION = kiroStateApi?.DEFAULT_REGION || 'us-east-1';
|
||||||
const DEFAULT_TARGET_ID = kiroStateApi?.DEFAULT_TARGET_ID || 'kiro-rs';
|
const DEFAULT_TARGET_ID = kiroStateApi?.DEFAULT_TARGET_ID || 'kiro-rs';
|
||||||
|
const DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS = kiroTimeoutApi?.DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS || (3 * 60 * 1000);
|
||||||
const DEVICE_LOGIN_START_URL = 'https://view.awsapps.com/start';
|
const DEVICE_LOGIN_START_URL = 'https://view.awsapps.com/start';
|
||||||
const DEFAULT_SCOPES = Object.freeze([
|
const DEFAULT_SCOPES = Object.freeze([
|
||||||
'codewhisperer:completions',
|
'codewhisperer:completions',
|
||||||
@@ -120,6 +122,36 @@
|
|||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeKiroPageLoadTimeoutMs(value, fallback = DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS) {
|
||||||
|
if (typeof kiroTimeoutApi?.normalizeKiroPageLoadTimeoutMs === 'function') {
|
||||||
|
return kiroTimeoutApi.normalizeKiroPageLoadTimeoutMs(value, fallback);
|
||||||
|
}
|
||||||
|
return normalizePositiveInteger(value, normalizePositiveInteger(fallback, DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS));
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTimeoutBudget(timeoutMs = DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS) {
|
||||||
|
const totalTimeoutMs = normalizeKiroPageLoadTimeoutMs(timeoutMs, DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS);
|
||||||
|
const startedAt = Date.now();
|
||||||
|
return {
|
||||||
|
totalTimeoutMs,
|
||||||
|
getRemainingMs(minimumMs = 1) {
|
||||||
|
const normalizedMinimumMs = normalizePositiveInteger(minimumMs, 1);
|
||||||
|
return Math.max(normalizedMinimumMs, totalTimeoutMs - (Date.now() - startedAt));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveTimeoutBudget(options = {}, fallbackTimeoutMs = DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS) {
|
||||||
|
if (options?.timeoutBudget && typeof options.timeoutBudget.getRemainingMs === 'function') {
|
||||||
|
return options.timeoutBudget;
|
||||||
|
}
|
||||||
|
return createTimeoutBudget(
|
||||||
|
options?.pageTimeoutMs
|
||||||
|
?? options?.timeoutMs
|
||||||
|
?? fallbackTimeoutMs
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function buildOidcBaseUrl(region = DEFAULT_REGION) {
|
function buildOidcBaseUrl(region = DEFAULT_REGION) {
|
||||||
return `https://oidc.${normalizeRegion(region)}.amazonaws.com`;
|
return `https://oidc.${normalizeRegion(region)}.amazonaws.com`;
|
||||||
}
|
}
|
||||||
@@ -485,9 +517,10 @@
|
|||||||
if (!Number.isInteger(tabId)) {
|
if (!Number.isInteger(tabId)) {
|
||||||
throw new Error('缺少 Kiro 注册页标签页,无法重新连接内容脚本。');
|
throw new Error('缺少 Kiro 注册页标签页,无法重新连接内容脚本。');
|
||||||
}
|
}
|
||||||
|
const timeoutBudget = resolveTimeoutBudget(options);
|
||||||
if (typeof waitForTabStableComplete === 'function') {
|
if (typeof waitForTabStableComplete === 'function') {
|
||||||
await waitForTabStableComplete(tabId, {
|
await waitForTabStableComplete(tabId, {
|
||||||
timeoutMs: 45000,
|
timeoutMs: timeoutBudget.getRemainingMs(1000),
|
||||||
retryDelayMs: 300,
|
retryDelayMs: 300,
|
||||||
stableMs: Number(options.stableMs) || 1200,
|
stableMs: Number(options.stableMs) || 1200,
|
||||||
initialDelayMs: Number(options.initialDelayMs) || 120,
|
initialDelayMs: Number(options.initialDelayMs) || 120,
|
||||||
@@ -497,7 +530,7 @@
|
|||||||
await ensureContentScriptReadyOnTab(KIRO_REGISTER_PAGE_SOURCE_ID, tabId, {
|
await ensureContentScriptReadyOnTab(KIRO_REGISTER_PAGE_SOURCE_ID, tabId, {
|
||||||
inject: Array.isArray(KIRO_REGISTER_INJECT_FILES) ? KIRO_REGISTER_INJECT_FILES : null,
|
inject: Array.isArray(KIRO_REGISTER_INJECT_FILES) ? KIRO_REGISTER_INJECT_FILES : null,
|
||||||
injectSource: KIRO_REGISTER_PAGE_SOURCE_ID,
|
injectSource: KIRO_REGISTER_PAGE_SOURCE_ID,
|
||||||
timeoutMs: 45000,
|
timeoutMs: timeoutBudget.getRemainingMs(1000),
|
||||||
retryDelayMs: 800,
|
retryDelayMs: 800,
|
||||||
logMessage: options.injectLogMessage || 'Kiro 注册页已跳转,正在重新连接内容脚本...',
|
logMessage: options.injectLogMessage || 'Kiro 注册页已跳转,正在重新连接内容脚本...',
|
||||||
});
|
});
|
||||||
@@ -505,8 +538,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildKiroRetryRecovery(tabId, options = {}) {
|
function buildKiroRetryRecovery(tabId, options = {}) {
|
||||||
return async () => {
|
return async (_error, context = {}) => {
|
||||||
|
const remainingTimeoutMs = normalizeKiroPageLoadTimeoutMs(
|
||||||
|
options?.timeoutBudget?.getRemainingMs?.(1000)
|
||||||
|
?? context?.remainingTimeoutMs,
|
||||||
|
DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS
|
||||||
|
);
|
||||||
await reattachKiroRegisterPage(tabId, {
|
await reattachKiroRegisterPage(tabId, {
|
||||||
|
timeoutMs: remainingTimeoutMs,
|
||||||
|
timeoutBudget: createTimeoutBudget(remainingTimeoutMs),
|
||||||
stableMs: Number(options.recoveryStableMs) || Number(options.stableMs) || 1200,
|
stableMs: Number(options.recoveryStableMs) || Number(options.stableMs) || 1200,
|
||||||
initialDelayMs: Number(options.recoveryInitialDelayMs) || 120,
|
initialDelayMs: Number(options.recoveryInitialDelayMs) || 120,
|
||||||
injectLogMessage: options.recoveryInjectLogMessage || options.injectLogMessage || 'Kiro 注册页已跳转,正在重新连接内容脚本...',
|
injectLogMessage: options.recoveryInjectLogMessage || options.injectLogMessage || 'Kiro 注册页已跳转,正在重新连接内容脚本...',
|
||||||
@@ -518,9 +558,14 @@
|
|||||||
if (!Number.isInteger(tabId)) {
|
if (!Number.isInteger(tabId)) {
|
||||||
throw new Error('缺少 Kiro 注册页标签页,无法继续执行。');
|
throw new Error('缺少 Kiro 注册页标签页,无法继续执行。');
|
||||||
}
|
}
|
||||||
|
const pageLoadTimeoutMs = normalizeKiroPageLoadTimeoutMs(
|
||||||
|
options.pageTimeoutMs,
|
||||||
|
DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS
|
||||||
|
);
|
||||||
|
const timeoutBudget = resolveTimeoutBudget(options, pageLoadTimeoutMs);
|
||||||
if (typeof waitForTabStableComplete === 'function') {
|
if (typeof waitForTabStableComplete === 'function') {
|
||||||
await waitForTabStableComplete(tabId, {
|
await waitForTabStableComplete(tabId, {
|
||||||
timeoutMs: 45000,
|
timeoutMs: timeoutBudget.getRemainingMs(1000),
|
||||||
retryDelayMs: 300,
|
retryDelayMs: 300,
|
||||||
stableMs: Number(options.stableMs) || 1500,
|
stableMs: Number(options.stableMs) || 1500,
|
||||||
initialDelayMs: Number(options.initialDelayMs) || 150,
|
initialDelayMs: Number(options.initialDelayMs) || 150,
|
||||||
@@ -530,7 +575,7 @@
|
|||||||
await ensureContentScriptReadyOnTab(KIRO_REGISTER_PAGE_SOURCE_ID, tabId, {
|
await ensureContentScriptReadyOnTab(KIRO_REGISTER_PAGE_SOURCE_ID, tabId, {
|
||||||
inject: Array.isArray(KIRO_REGISTER_INJECT_FILES) ? KIRO_REGISTER_INJECT_FILES : null,
|
inject: Array.isArray(KIRO_REGISTER_INJECT_FILES) ? KIRO_REGISTER_INJECT_FILES : null,
|
||||||
injectSource: KIRO_REGISTER_PAGE_SOURCE_ID,
|
injectSource: KIRO_REGISTER_PAGE_SOURCE_ID,
|
||||||
timeoutMs: 45000,
|
timeoutMs: timeoutBudget.getRemainingMs(1000),
|
||||||
retryDelayMs: 800,
|
retryDelayMs: 800,
|
||||||
logMessage: options.injectLogMessage || 'Kiro 注册页内容脚本未就绪,正在等待页面恢复...',
|
logMessage: options.injectLogMessage || 'Kiro 注册页内容脚本未就绪,正在等待页面恢复...',
|
||||||
});
|
});
|
||||||
@@ -541,20 +586,24 @@
|
|||||||
url: '',
|
url: '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
const stateWaitTimeoutMs = timeoutBudget.getRemainingMs(1000);
|
||||||
const result = await sendToContentScriptResilient(KIRO_REGISTER_PAGE_SOURCE_ID, {
|
const result = await sendToContentScriptResilient(KIRO_REGISTER_PAGE_SOURCE_ID, {
|
||||||
type: 'ENSURE_KIRO_PAGE_STATE',
|
type: 'ENSURE_KIRO_PAGE_STATE',
|
||||||
step: options.step || 0,
|
step: options.step || 0,
|
||||||
source: 'background',
|
source: 'background',
|
||||||
payload: {
|
payload: {
|
||||||
targetStates: Array.isArray(options.targetStates) ? options.targetStates : [],
|
targetStates: Array.isArray(options.targetStates) ? options.targetStates : [],
|
||||||
timeoutMs: Number(options.pageTimeoutMs) || 30000,
|
timeoutMs: stateWaitTimeoutMs,
|
||||||
retryDelayMs: Number(options.pageRetryDelayMs) || 250,
|
retryDelayMs: Number(options.pageRetryDelayMs) || 250,
|
||||||
timeoutMessage: options.timeoutMessage || '',
|
timeoutMessage: options.timeoutMessage || '',
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
timeoutMs: Math.max(30000, Number(options.pageTimeoutMs) || 30000),
|
timeoutMs: stateWaitTimeoutMs,
|
||||||
retryDelayMs: 700,
|
retryDelayMs: 700,
|
||||||
onRetryableError: buildKiroRetryRecovery(tabId, options),
|
onRetryableError: buildKiroRetryRecovery(tabId, {
|
||||||
|
...options,
|
||||||
|
timeoutBudget,
|
||||||
|
}),
|
||||||
logMessage: options.readyLogMessage || '正在等待 Kiro 页面进入下一状态...',
|
logMessage: options.readyLogMessage || '正在等待 Kiro 页面进入下一状态...',
|
||||||
});
|
});
|
||||||
if (result?.error) {
|
if (result?.error) {
|
||||||
@@ -567,9 +616,14 @@
|
|||||||
if (!Number.isInteger(tabId)) {
|
if (!Number.isInteger(tabId)) {
|
||||||
throw new Error('缺少 Kiro 注册页标签页,无法继续执行。');
|
throw new Error('缺少 Kiro 注册页标签页,无法继续执行。');
|
||||||
}
|
}
|
||||||
|
const pageLoadTimeoutMs = normalizeKiroPageLoadTimeoutMs(
|
||||||
|
options.pageTimeoutMs,
|
||||||
|
DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS
|
||||||
|
);
|
||||||
|
const timeoutBudget = resolveTimeoutBudget(options, pageLoadTimeoutMs);
|
||||||
if (typeof waitForTabStableComplete === 'function') {
|
if (typeof waitForTabStableComplete === 'function') {
|
||||||
await waitForTabStableComplete(tabId, {
|
await waitForTabStableComplete(tabId, {
|
||||||
timeoutMs: 45000,
|
timeoutMs: timeoutBudget.getRemainingMs(1000),
|
||||||
retryDelayMs: 300,
|
retryDelayMs: 300,
|
||||||
stableMs: Number(options.stableMs) || 1200,
|
stableMs: Number(options.stableMs) || 1200,
|
||||||
initialDelayMs: Number(options.initialDelayMs) || 120,
|
initialDelayMs: Number(options.initialDelayMs) || 120,
|
||||||
@@ -579,7 +633,7 @@
|
|||||||
await ensureContentScriptReadyOnTab(KIRO_REGISTER_PAGE_SOURCE_ID, tabId, {
|
await ensureContentScriptReadyOnTab(KIRO_REGISTER_PAGE_SOURCE_ID, tabId, {
|
||||||
inject: Array.isArray(KIRO_REGISTER_INJECT_FILES) ? KIRO_REGISTER_INJECT_FILES : null,
|
inject: Array.isArray(KIRO_REGISTER_INJECT_FILES) ? KIRO_REGISTER_INJECT_FILES : null,
|
||||||
injectSource: KIRO_REGISTER_PAGE_SOURCE_ID,
|
injectSource: KIRO_REGISTER_PAGE_SOURCE_ID,
|
||||||
timeoutMs: 45000,
|
timeoutMs: timeoutBudget.getRemainingMs(1000),
|
||||||
retryDelayMs: 800,
|
retryDelayMs: 800,
|
||||||
logMessage: options.injectLogMessage || 'Kiro 注册页切换中,正在等待页面恢复...',
|
logMessage: options.injectLogMessage || 'Kiro 注册页切换中,正在等待页面恢复...',
|
||||||
});
|
});
|
||||||
@@ -587,20 +641,24 @@
|
|||||||
if (typeof sendToContentScriptResilient !== 'function') {
|
if (typeof sendToContentScriptResilient !== 'function') {
|
||||||
return { state: '', url: '' };
|
return { state: '', url: '' };
|
||||||
}
|
}
|
||||||
|
const stateWaitTimeoutMs = timeoutBudget.getRemainingMs(1000);
|
||||||
const result = await sendToContentScriptResilient(KIRO_REGISTER_PAGE_SOURCE_ID, {
|
const result = await sendToContentScriptResilient(KIRO_REGISTER_PAGE_SOURCE_ID, {
|
||||||
type: 'ENSURE_KIRO_STATE_CHANGE',
|
type: 'ENSURE_KIRO_STATE_CHANGE',
|
||||||
step: options.step || 0,
|
step: options.step || 0,
|
||||||
source: 'background',
|
source: 'background',
|
||||||
payload: {
|
payload: {
|
||||||
fromStates: Array.isArray(options.fromStates) ? options.fromStates : [],
|
fromStates: Array.isArray(options.fromStates) ? options.fromStates : [],
|
||||||
timeoutMs: Number(options.pageTimeoutMs) || 30000,
|
timeoutMs: stateWaitTimeoutMs,
|
||||||
retryDelayMs: Number(options.pageRetryDelayMs) || 250,
|
retryDelayMs: Number(options.pageRetryDelayMs) || 250,
|
||||||
timeoutMessage: options.timeoutMessage || '',
|
timeoutMessage: options.timeoutMessage || '',
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
timeoutMs: Math.max(30000, Number(options.pageTimeoutMs) || 30000),
|
timeoutMs: stateWaitTimeoutMs,
|
||||||
retryDelayMs: 700,
|
retryDelayMs: 700,
|
||||||
onRetryableError: buildKiroRetryRecovery(tabId, options),
|
onRetryableError: buildKiroRetryRecovery(tabId, {
|
||||||
|
...options,
|
||||||
|
timeoutBudget,
|
||||||
|
}),
|
||||||
logMessage: options.readyLogMessage || '正在等待 Kiro 页面完成跳转...',
|
logMessage: options.readyLogMessage || '正在等待 Kiro 页面完成跳转...',
|
||||||
});
|
});
|
||||||
if (result?.error) {
|
if (result?.error) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
console.log('[MultiPage:kiro-register-page] Content script loaded on', location.href);
|
console.log('[MultiPage:kiro-register-page] Content script loaded on', location.href);
|
||||||
|
|
||||||
const KIRO_REGISTER_PAGE_LISTENER_SENTINEL = 'data-multipage-kiro-register-page-listener';
|
const KIRO_REGISTER_PAGE_LISTENER_SENTINEL = 'data-multipage-kiro-register-page-listener';
|
||||||
|
const DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS = globalThis.MultiPageKiroTimeouts?.DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS || (3 * 60 * 1000);
|
||||||
const KIRO_CONTINUE_TEXT_PATTERN = /continue|继续/i;
|
const KIRO_CONTINUE_TEXT_PATTERN = /continue|继续/i;
|
||||||
const KIRO_CONFIRM_CONTINUE_TEXT_PATTERN = /confirm and continue|确认并继续/i;
|
const KIRO_CONFIRM_CONTINUE_TEXT_PATTERN = /confirm and continue|确认并继续/i;
|
||||||
const KIRO_ALLOW_ACCESS_TEXT_PATTERN = /allow access|允许访问/i;
|
const KIRO_ALLOW_ACCESS_TEXT_PATTERN = /allow access|允许访问/i;
|
||||||
@@ -312,7 +313,7 @@ function detectKiroRegisterPageState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function waitForKiroState(predicate, options = {}) {
|
async function waitForKiroState(predicate, options = {}) {
|
||||||
const timeoutMs = Math.max(1000, Math.floor(Number(options.timeoutMs) || 30000));
|
const timeoutMs = Math.max(1000, Math.floor(Number(options.timeoutMs) || DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS));
|
||||||
const retryDelayMs = Math.max(100, Math.floor(Number(options.retryDelayMs) || 250));
|
const retryDelayMs = Math.max(100, Math.floor(Number(options.retryDelayMs) || 250));
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
|
|
||||||
@@ -405,7 +406,7 @@ async function submitKiroEmail(payload = {}) {
|
|||||||
|
|
||||||
const readyState = await ensureKiroRegisterPageState({
|
const readyState = await ensureKiroRegisterPageState({
|
||||||
targetStates: ['email_entry'],
|
targetStates: ['email_entry'],
|
||||||
timeoutMs: payload?.timeoutMs || 30000,
|
timeoutMs: payload?.timeoutMs || DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS,
|
||||||
retryDelayMs: payload?.retryDelayMs || 250,
|
retryDelayMs: payload?.retryDelayMs || 250,
|
||||||
});
|
});
|
||||||
if (!readyState.emailInput || !readyState.continueButton) {
|
if (!readyState.emailInput || !readyState.continueButton) {
|
||||||
@@ -430,7 +431,7 @@ async function submitKiroName(payload = {}) {
|
|||||||
|
|
||||||
const readyState = await ensureKiroRegisterPageState({
|
const readyState = await ensureKiroRegisterPageState({
|
||||||
targetStates: ['name_entry'],
|
targetStates: ['name_entry'],
|
||||||
timeoutMs: payload?.timeoutMs || 30000,
|
timeoutMs: payload?.timeoutMs || DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS,
|
||||||
retryDelayMs: payload?.retryDelayMs || 250,
|
retryDelayMs: payload?.retryDelayMs || 250,
|
||||||
});
|
});
|
||||||
if (!readyState.nameInput || !readyState.continueButton) {
|
if (!readyState.nameInput || !readyState.continueButton) {
|
||||||
@@ -455,7 +456,7 @@ async function submitKiroVerificationCode(payload = {}) {
|
|||||||
|
|
||||||
const readyState = await ensureKiroRegisterPageState({
|
const readyState = await ensureKiroRegisterPageState({
|
||||||
targetStates: ['otp_page'],
|
targetStates: ['otp_page'],
|
||||||
timeoutMs: payload?.timeoutMs || 30000,
|
timeoutMs: payload?.timeoutMs || DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS,
|
||||||
retryDelayMs: payload?.retryDelayMs || 250,
|
retryDelayMs: payload?.retryDelayMs || 250,
|
||||||
});
|
});
|
||||||
if (!readyState.otpInput || !readyState.verifyButton) {
|
if (!readyState.otpInput || !readyState.verifyButton) {
|
||||||
@@ -480,7 +481,7 @@ async function submitKiroPassword(payload = {}) {
|
|||||||
|
|
||||||
const readyState = await ensureKiroRegisterPageState({
|
const readyState = await ensureKiroRegisterPageState({
|
||||||
targetStates: ['password_page'],
|
targetStates: ['password_page'],
|
||||||
timeoutMs: payload?.timeoutMs || 30000,
|
timeoutMs: payload?.timeoutMs || DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS,
|
||||||
retryDelayMs: payload?.retryDelayMs || 250,
|
retryDelayMs: payload?.retryDelayMs || 250,
|
||||||
});
|
});
|
||||||
if (!readyState.passwordInput || !readyState.continueButton) {
|
if (!readyState.passwordInput || !readyState.continueButton) {
|
||||||
@@ -511,7 +512,7 @@ async function submitKiroPassword(payload = {}) {
|
|||||||
async function confirmKiroRegisterConsent(payload = {}) {
|
async function confirmKiroRegisterConsent(payload = {}) {
|
||||||
let currentState = await ensureKiroRegisterPageState({
|
let currentState = await ensureKiroRegisterPageState({
|
||||||
targetStates: ['authorization_page', 'success_page'],
|
targetStates: ['authorization_page', 'success_page'],
|
||||||
timeoutMs: payload?.timeoutMs || 45000,
|
timeoutMs: payload?.timeoutMs || DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS,
|
||||||
retryDelayMs: payload?.retryDelayMs || 250,
|
retryDelayMs: payload?.retryDelayMs || 250,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -528,7 +529,7 @@ async function confirmKiroRegisterConsent(payload = {}) {
|
|||||||
});
|
});
|
||||||
simulateClick(currentState.actionButton);
|
simulateClick(currentState.actionButton);
|
||||||
currentState = await waitForKiroAuthorizationAdvance(currentState, {
|
currentState = await waitForKiroAuthorizationAdvance(currentState, {
|
||||||
timeoutMs: payload?.timeoutMs || 45000,
|
timeoutMs: payload?.timeoutMs || DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS,
|
||||||
retryDelayMs: payload?.retryDelayMs || 250,
|
retryDelayMs: payload?.retryDelayMs || 250,
|
||||||
timeoutMessage: 'Kiro 授权按钮点击后页面未继续,请检查当前授权页状态。',
|
timeoutMessage: 'Kiro 授权按钮点击后页面未继续,请检查当前授权页状态。',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
(function attachKiroTimeouts(root, factory) {
|
||||||
|
root.MultiPageKiroTimeouts = factory();
|
||||||
|
})(typeof self !== 'undefined' ? self : globalThis, function createKiroTimeoutsModule() {
|
||||||
|
const DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS = 3 * 60 * 1000;
|
||||||
|
|
||||||
|
function normalizePositiveInteger(value, fallback) {
|
||||||
|
const numeric = Math.floor(Number(value));
|
||||||
|
if (Number.isInteger(numeric) && numeric > 0) {
|
||||||
|
return numeric;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeKiroPageLoadTimeoutMs(value, fallback = DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS) {
|
||||||
|
return normalizePositiveInteger(
|
||||||
|
value,
|
||||||
|
normalizePositiveInteger(fallback, DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS,
|
||||||
|
normalizeKiroPageLoadTimeoutMs,
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -46,3 +46,12 @@ test('parseDesktopCallbackUrl validates state and redirect port', () => {
|
|||||||
);
|
);
|
||||||
assert.equal(badPort, null);
|
assert.equal(badPort, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('kiro desktop authorize runner uses a shared 3-minute page-load timeout budget', () => {
|
||||||
|
const source = fs.readFileSync('background/kiro/desktop-authorize-runner.js', 'utf8');
|
||||||
|
assert.match(source, /DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS/);
|
||||||
|
assert.match(source, /createTimeoutBudget/);
|
||||||
|
assert.match(source, /resolveTimeoutBudget/);
|
||||||
|
assert.match(source, /timeoutBudget\.getRemainingMs\(1000\)/);
|
||||||
|
assert.match(source, /onRetryableError: buildDesktopRetryRecovery\(tabId, \{\s*\.\.\.options,\s*timeoutBudget,/);
|
||||||
|
});
|
||||||
|
|||||||
@@ -57,3 +57,12 @@ test('startBuilderIdDeviceLogin registers Builder ID client and returns login bo
|
|||||||
assert.equal(result.interval, 7);
|
assert.equal(result.interval, 7);
|
||||||
assert.equal(result.region, 'us-east-1');
|
assert.equal(result.region, 'us-east-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('kiro register runner uses a shared 3-minute page-load timeout budget', () => {
|
||||||
|
const source = fs.readFileSync('background/kiro/register-runner.js', 'utf8');
|
||||||
|
assert.match(source, /DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS/);
|
||||||
|
assert.match(source, /createTimeoutBudget/);
|
||||||
|
assert.match(source, /resolveTimeoutBudget/);
|
||||||
|
assert.match(source, /timeoutBudget\.getRemainingMs\(1000\)/);
|
||||||
|
assert.match(source, /onRetryableError: buildKiroRetryRecovery\(tabId, \{\s*\.\.\.options,\s*timeoutBudget,/);
|
||||||
|
});
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ test('background imports workflow step modules including rebuilt Kiro modules',
|
|||||||
'background/steps/fetch-login-code.js',
|
'background/steps/fetch-login-code.js',
|
||||||
'background/steps/confirm-oauth.js',
|
'background/steps/confirm-oauth.js',
|
||||||
'background/steps/platform-verify.js',
|
'background/steps/platform-verify.js',
|
||||||
|
'shared/kiro-timeouts.js',
|
||||||
'background/kiro/state.js',
|
'background/kiro/state.js',
|
||||||
'background/kiro/register-runner.js',
|
'background/kiro/register-runner.js',
|
||||||
'background/kiro/desktop-client.js',
|
'background/kiro/desktop-client.js',
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ test('background imports shared source registry module', () => {
|
|||||||
assert.match(source, /shared\/flow-registry\.js/);
|
assert.match(source, /shared\/flow-registry\.js/);
|
||||||
assert.match(source, /shared\/settings-schema\.js/);
|
assert.match(source, /shared\/settings-schema\.js/);
|
||||||
assert.match(source, /shared\/source-registry\.js/);
|
assert.match(source, /shared\/source-registry\.js/);
|
||||||
|
assert.match(source, /shared\/kiro-timeouts\.js/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('manifest loads shared source registry before content utils in static bundles', () => {
|
test('manifest loads shared source registry before content utils in static bundles', () => {
|
||||||
@@ -41,6 +42,18 @@ test('manifest no longer ships a static Kiro content bundle', () => {
|
|||||||
assert.equal(hasStaticKiroBundle, false);
|
assert.equal(hasStaticKiroBundle, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('background injects shared Kiro timeout module before Kiro content scripts', () => {
|
||||||
|
const source = fs.readFileSync('background.js', 'utf8');
|
||||||
|
assert.match(
|
||||||
|
source,
|
||||||
|
/const KIRO_REGISTER_INJECT_FILES = \['shared\/source-registry\.js', 'shared\/kiro-timeouts\.js', 'content\/utils\.js', 'content\/kiro\/register-page\.js'\];/
|
||||||
|
);
|
||||||
|
assert.match(
|
||||||
|
source,
|
||||||
|
/const KIRO_DESKTOP_AUTHORIZE_INJECT_FILES = \['shared\/source-registry\.js', 'shared\/kiro-timeouts\.js', 'content\/utils\.js', 'content\/kiro\/desktop-authorize-page\.js'\];/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test('shared source registry exposes canonical Kiro sources and drivers', () => {
|
test('shared source registry exposes canonical Kiro sources and drivers', () => {
|
||||||
const registry = loadSourceRegistry();
|
const registry = loadSourceRegistry();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user