fix kiro register driver readiness recovery
This commit is contained in:
@@ -601,6 +601,73 @@
|
|||||||
return tabId;
|
return tabId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function injectKiroRegisterContentScripts(tabId) {
|
||||||
|
if (
|
||||||
|
!Number.isInteger(tabId)
|
||||||
|
|| !chrome?.scripting?.executeScript
|
||||||
|
|| !Array.isArray(KIRO_REGISTER_INJECT_FILES)
|
||||||
|
|| !KIRO_REGISTER_INJECT_FILES.length
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await chrome.scripting.executeScript({
|
||||||
|
target: { tabId },
|
||||||
|
func: (injectedSource) => {
|
||||||
|
window.__MULTIPAGE_SOURCE = injectedSource;
|
||||||
|
},
|
||||||
|
args: [KIRO_REGISTER_PAGE_SOURCE_ID],
|
||||||
|
});
|
||||||
|
await chrome.scripting.executeScript({
|
||||||
|
target: { tabId },
|
||||||
|
files: KIRO_REGISTER_INJECT_FILES,
|
||||||
|
});
|
||||||
|
await sleepWithStop(250);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasKiroRegisterPageState(result = {}) {
|
||||||
|
return Boolean(result && typeof result === 'object' && cleanString(result.state));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendKiroStateDriverMessage(tabId, message, options = {}) {
|
||||||
|
const {
|
||||||
|
timeoutBudget,
|
||||||
|
timeoutMs = 30000,
|
||||||
|
} = options;
|
||||||
|
let result = await sendToContentScriptResilient(KIRO_REGISTER_PAGE_SOURCE_ID, message, {
|
||||||
|
timeoutMs,
|
||||||
|
retryDelayMs: 700,
|
||||||
|
onRetryableError: buildKiroRetryRecovery(tabId, {
|
||||||
|
...options,
|
||||||
|
timeoutBudget,
|
||||||
|
}),
|
||||||
|
logMessage: options.readyLogMessage || '正在等待 Kiro 页面进入下一状态...',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hasKiroRegisterPageState(result) && !result?.error) {
|
||||||
|
await log('Kiro 注册页通用脚本已响应,但专用页面识别脚本未返回状态,正在重新注入 Kiro 注册页识别脚本...', 'warn');
|
||||||
|
await injectKiroRegisterContentScripts(tabId);
|
||||||
|
result = await sendToContentScriptResilient(KIRO_REGISTER_PAGE_SOURCE_ID, message, {
|
||||||
|
timeoutMs: timeoutBudget?.getRemainingMs?.(1000) || timeoutMs,
|
||||||
|
retryDelayMs: 700,
|
||||||
|
onRetryableError: buildKiroRetryRecovery(tabId, {
|
||||||
|
...options,
|
||||||
|
timeoutBudget,
|
||||||
|
}),
|
||||||
|
logMessage: options.readyLogMessage || '正在等待 Kiro 页面进入下一状态...',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result?.error) {
|
||||||
|
throw new Error(result.error);
|
||||||
|
}
|
||||||
|
if (!hasKiroRegisterPageState(result)) {
|
||||||
|
throw new Error('Kiro 注册页专用页面识别脚本未返回页面状态,请刷新当前 AWS 页面或重新执行当前步骤。');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
async function reattachKiroRegisterPage(tabId, options = {}) {
|
async function reattachKiroRegisterPage(tabId, options = {}) {
|
||||||
if (!Number.isInteger(tabId)) {
|
if (!Number.isInteger(tabId)) {
|
||||||
throw new Error('缺少 Kiro 注册页标签页,无法重新连接内容脚本。');
|
throw new Error('缺少 Kiro 注册页标签页,无法重新连接内容脚本。');
|
||||||
@@ -675,7 +742,7 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const stateWaitTimeoutMs = timeoutBudget.getRemainingMs(1000);
|
const stateWaitTimeoutMs = timeoutBudget.getRemainingMs(1000);
|
||||||
const result = await sendToContentScriptResilient(KIRO_REGISTER_PAGE_SOURCE_ID, {
|
const message = {
|
||||||
type: 'ENSURE_KIRO_PAGE_STATE',
|
type: 'ENSURE_KIRO_PAGE_STATE',
|
||||||
step: options.step || 0,
|
step: options.step || 0,
|
||||||
source: 'background',
|
source: 'background',
|
||||||
@@ -685,19 +752,13 @@
|
|||||||
retryDelayMs: Number(options.pageRetryDelayMs) || 250,
|
retryDelayMs: Number(options.pageRetryDelayMs) || 250,
|
||||||
timeoutMessage: options.timeoutMessage || '',
|
timeoutMessage: options.timeoutMessage || '',
|
||||||
},
|
},
|
||||||
}, {
|
};
|
||||||
timeoutMs: stateWaitTimeoutMs,
|
|
||||||
retryDelayMs: 700,
|
return sendKiroStateDriverMessage(tabId, message, {
|
||||||
onRetryableError: buildKiroRetryRecovery(tabId, {
|
|
||||||
...options,
|
...options,
|
||||||
timeoutBudget,
|
timeoutBudget,
|
||||||
}),
|
timeoutMs: stateWaitTimeoutMs,
|
||||||
logMessage: options.readyLogMessage || '正在等待 Kiro 页面进入下一状态...',
|
|
||||||
});
|
});
|
||||||
if (result?.error) {
|
|
||||||
throw new Error(result.error);
|
|
||||||
}
|
|
||||||
return result || { state: '', url: '' };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function waitForKiroPageChange(tabId, options = {}) {
|
async function waitForKiroPageChange(tabId, options = {}) {
|
||||||
@@ -730,7 +791,7 @@
|
|||||||
return { state: '', url: '' };
|
return { state: '', url: '' };
|
||||||
}
|
}
|
||||||
const stateWaitTimeoutMs = timeoutBudget.getRemainingMs(1000);
|
const stateWaitTimeoutMs = timeoutBudget.getRemainingMs(1000);
|
||||||
const result = await sendToContentScriptResilient(KIRO_REGISTER_PAGE_SOURCE_ID, {
|
const message = {
|
||||||
type: 'ENSURE_KIRO_STATE_CHANGE',
|
type: 'ENSURE_KIRO_STATE_CHANGE',
|
||||||
step: options.step || 0,
|
step: options.step || 0,
|
||||||
source: 'background',
|
source: 'background',
|
||||||
@@ -741,19 +802,13 @@
|
|||||||
returnOnCodeInvalid: Boolean(options.returnOnCodeInvalid),
|
returnOnCodeInvalid: Boolean(options.returnOnCodeInvalid),
|
||||||
timeoutMessage: options.timeoutMessage || '',
|
timeoutMessage: options.timeoutMessage || '',
|
||||||
},
|
},
|
||||||
}, {
|
};
|
||||||
timeoutMs: stateWaitTimeoutMs,
|
return sendKiroStateDriverMessage(tabId, message, {
|
||||||
retryDelayMs: 700,
|
|
||||||
onRetryableError: buildKiroRetryRecovery(tabId, {
|
|
||||||
...options,
|
...options,
|
||||||
timeoutBudget,
|
timeoutBudget,
|
||||||
}),
|
timeoutMs: stateWaitTimeoutMs,
|
||||||
logMessage: options.readyLogMessage || '正在等待 Kiro 页面完成跳转...',
|
readyLogMessage: options.readyLogMessage || '正在等待 Kiro 页面完成跳转...',
|
||||||
});
|
});
|
||||||
if (result?.error) {
|
|
||||||
throw new Error(result.error);
|
|
||||||
}
|
|
||||||
return result || { state: '', url: '' };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readKiroRegisterPageState(tabId, options = {}) {
|
async function readKiroRegisterPageState(tabId, options = {}) {
|
||||||
|
|||||||
@@ -364,6 +364,110 @@ test('kiro verification step can adopt the active AWS verify-otp page without st
|
|||||||
assert.equal(getKiroRuntime(completedPayload).register?.email, 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech');
|
assert.equal(getKiroRuntime(completedPayload).register?.email, 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('kiro verification step reinjects the register driver when only the generic content script responds', async () => {
|
||||||
|
const api = loadRegisterRunnerApi();
|
||||||
|
const currentState = {
|
||||||
|
email: 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech',
|
||||||
|
registrationEmailState: {
|
||||||
|
current: 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech',
|
||||||
|
previous: 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech',
|
||||||
|
source: 'manual',
|
||||||
|
updatedAt: Date.now(),
|
||||||
|
},
|
||||||
|
runtimeState: {
|
||||||
|
flowState: {
|
||||||
|
kiro: {
|
||||||
|
session: {
|
||||||
|
registerTabId: 302,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const sentMessages = [];
|
||||||
|
const injectedScripts = [];
|
||||||
|
const pollPayloads = [];
|
||||||
|
let completedPayload = null;
|
||||||
|
const runner = api.createKiroRegisterRunner({
|
||||||
|
addLog: async () => {},
|
||||||
|
chrome: {
|
||||||
|
scripting: {
|
||||||
|
executeScript: async (payload) => {
|
||||||
|
injectedScripts.push(payload);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tabs: {
|
||||||
|
get: async (tabId) => ({
|
||||||
|
id: tabId,
|
||||||
|
url: 'https://profile.aws.amazon.com/?workflowID=b4e8f9ff-3d60-40ce-90ec-d2113d951b08#/signup/verify-otp',
|
||||||
|
}),
|
||||||
|
update: async () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
completeNodeFromBackground: async (_nodeId, payload) => {
|
||||||
|
completedPayload = payload;
|
||||||
|
},
|
||||||
|
getMailConfig: () => ({
|
||||||
|
provider: 'cloudflare-temp-email',
|
||||||
|
source: 'cloudflare-temp-email',
|
||||||
|
label: 'Cloudflare Temp Email',
|
||||||
|
}),
|
||||||
|
getState: async () => currentState,
|
||||||
|
getTabId: async () => 302,
|
||||||
|
isTabAlive: async () => true,
|
||||||
|
KIRO_REGISTER_INJECT_FILES: [
|
||||||
|
'content/utils.js',
|
||||||
|
'flows/kiro/content/register-page.js',
|
||||||
|
],
|
||||||
|
pollCloudflareTempEmailVerificationCode: async (_step, _state, payload) => {
|
||||||
|
pollPayloads.push(payload);
|
||||||
|
return { code: '248680', emailTimestamp: 2000, mailId: 'mail-reinject' };
|
||||||
|
},
|
||||||
|
sendToContentScriptResilient: async (_sourceId, message) => {
|
||||||
|
sentMessages.push(message);
|
||||||
|
const ensureCount = sentMessages.filter((entry) => entry.type === 'ENSURE_KIRO_PAGE_STATE').length;
|
||||||
|
if (message.type === 'ENSURE_KIRO_PAGE_STATE' && ensureCount === 1) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (message.type === 'ENSURE_KIRO_PAGE_STATE') {
|
||||||
|
return {
|
||||||
|
state: 'register_otp_page',
|
||||||
|
url: 'https://profile.aws.amazon.com/?workflowID=b4e8f9ff-3d60-40ce-90ec-d2113d951b08#/signup/verify-otp',
|
||||||
|
email: 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (message.type === 'EXECUTE_NODE') {
|
||||||
|
return { submitted: true, state: 'verification_submitted' };
|
||||||
|
}
|
||||||
|
if (message.type === 'ENSURE_KIRO_STATE_CHANGE') {
|
||||||
|
return {
|
||||||
|
state: 'create_password_page',
|
||||||
|
url: 'https://profile.aws.amazon.com/?workflowID=b4e8f9ff-3d60-40ce-90ec-d2113d951b08#/signup/create-password',
|
||||||
|
email: 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
setState: async () => {},
|
||||||
|
sleepWithStop: async () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
await runner.executeKiroSubmitVerificationCode({
|
||||||
|
nodeId: 'kiro-submit-verification-code',
|
||||||
|
...currentState,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(sentMessages.filter((message) => message.type === 'ENSURE_KIRO_PAGE_STATE').length, 2);
|
||||||
|
assert.equal(injectedScripts.length, 2);
|
||||||
|
assert.deepEqual(injectedScripts[0].args, ['kiro-register-page']);
|
||||||
|
assert.deepEqual(injectedScripts[1].files, [
|
||||||
|
'content/utils.js',
|
||||||
|
'flows/kiro/content/register-page.js',
|
||||||
|
]);
|
||||||
|
assert.equal(pollPayloads[0].targetEmail, 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech');
|
||||||
|
assert.equal(getKiroRuntime(completedPayload).register?.email, 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech');
|
||||||
|
});
|
||||||
|
|
||||||
test('kiro submit-email reuses the step 1 register tab even when the source registry was reset', async () => {
|
test('kiro submit-email reuses the step 1 register tab even when the source registry was reset', async () => {
|
||||||
const api = loadRegisterRunnerApi();
|
const api = loadRegisterRunnerApi();
|
||||||
const currentState = {
|
const currentState = {
|
||||||
|
|||||||
Reference in New Issue
Block a user