feat: add kiro.rs connection preflight test
This commit is contained in:
+11
-1
@@ -2775,7 +2775,7 @@ function normalizePersistentSettingValue(key, value) {
|
|||||||
|| 'https://kiro.leftcode.xyz/admin'
|
|| 'https://kiro.leftcode.xyz/admin'
|
||||||
).trim() || 'https://kiro.leftcode.xyz/admin';
|
).trim() || 'https://kiro.leftcode.xyz/admin';
|
||||||
case 'kiroRsKey':
|
case 'kiroRsKey':
|
||||||
return String(value || '');
|
return String(value || '').trim();
|
||||||
case 'vpsUrl':
|
case 'vpsUrl':
|
||||||
return String(value || '').trim();
|
return String(value || '').trim();
|
||||||
case 'vpsPassword':
|
case 'vpsPassword':
|
||||||
@@ -13351,6 +13351,16 @@ const messageRouter = self.MultiPageBackgroundMessageRouter?.createMessageRouter
|
|||||||
fetchGeneratedEmail,
|
fetchGeneratedEmail,
|
||||||
refreshGpcCardBalance,
|
refreshGpcCardBalance,
|
||||||
finalizePhoneActivationAfterSuccessfulFlow,
|
finalizePhoneActivationAfterSuccessfulFlow,
|
||||||
|
testKiroRsConnection: async (baseUrl, apiKey) => {
|
||||||
|
if (typeof self.MultiPageBackgroundKiroPublisherKiroRs?.checkKiroRsConnection !== 'function') {
|
||||||
|
throw new Error('kiro.rs 连接测试能力尚未接入。');
|
||||||
|
}
|
||||||
|
return self.MultiPageBackgroundKiroPublisherKiroRs.checkKiroRsConnection(
|
||||||
|
baseUrl,
|
||||||
|
apiKey,
|
||||||
|
typeof fetch === 'function' ? fetch.bind(globalThis) : null
|
||||||
|
);
|
||||||
|
},
|
||||||
finalizeStep3Completion: async () => {
|
finalizeStep3Completion: async () => {
|
||||||
const currentState = await getState();
|
const currentState = await getState();
|
||||||
const signupTabId = await getTabId('signup-page');
|
const signupTabId = await getTabId('signup-page');
|
||||||
|
|||||||
@@ -47,6 +47,25 @@
|
|||||||
return cleanString(value) || fallback;
|
return cleanString(value) || fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeKiroRsApiKey(value = '') {
|
||||||
|
return cleanString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildKiroRsAdminHeaders(apiKey = '', extraHeaders = {}) {
|
||||||
|
const normalizedApiKey = normalizeKiroRsApiKey(apiKey);
|
||||||
|
return {
|
||||||
|
...extraHeaders,
|
||||||
|
...(normalizedApiKey ? {
|
||||||
|
'x-api-key': normalizedApiKey,
|
||||||
|
Authorization: `Bearer ${normalizedApiKey}`,
|
||||||
|
} : {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function readKiroRsResponseMessage(body = {}, fallback = '') {
|
||||||
|
return cleanString(body?.json?.error?.message || body?.json?.message || body?.text || fallback);
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeKiroRsBaseUrl(value = '') {
|
function normalizeKiroRsBaseUrl(value = '') {
|
||||||
const normalized = cleanString(value).replace(/\/+$/, '');
|
const normalized = cleanString(value).replace(/\/+$/, '');
|
||||||
if (!normalized) {
|
if (!normalized) {
|
||||||
@@ -116,7 +135,7 @@
|
|||||||
|| {};
|
|| {};
|
||||||
return {
|
return {
|
||||||
baseUrl: cleanString(nestedConfig.baseUrl || state?.kiroRsUrl),
|
baseUrl: cleanString(nestedConfig.baseUrl || state?.kiroRsUrl),
|
||||||
apiKey: String(nestedConfig.apiKey ?? state?.kiroRsKey ?? ''),
|
apiKey: normalizeKiroRsApiKey(nestedConfig.apiKey ?? state?.kiroRsKey ?? ''),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,60 +218,64 @@
|
|||||||
|
|
||||||
async function checkKiroRsConnection(baseUrl, apiKey, fetchImpl) {
|
async function checkKiroRsConnection(baseUrl, apiKey, fetchImpl) {
|
||||||
const normalizedBaseUrl = normalizeKiroRsBaseUrl(baseUrl);
|
const normalizedBaseUrl = normalizeKiroRsBaseUrl(baseUrl);
|
||||||
|
const normalizedApiKey = normalizeKiroRsApiKey(apiKey);
|
||||||
const response = await fetchImpl(`${normalizedBaseUrl}/api/admin/credentials`, {
|
const response = await fetchImpl(`${normalizedBaseUrl}/api/admin/credentials`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: buildKiroRsAdminHeaders(normalizedApiKey, {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
'x-api-key': String(apiKey || ''),
|
}),
|
||||||
},
|
|
||||||
});
|
});
|
||||||
const body = await readResponse(response);
|
const body = await readResponse(response);
|
||||||
|
const detail = readKiroRsResponseMessage(body, response.statusText);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return {
|
return {
|
||||||
ok: true,
|
ok: true,
|
||||||
|
status: response.status,
|
||||||
message: `kiro.rs 连接正常(HTTP ${response.status})`,
|
message: `kiro.rs 连接正常(HTTP ${response.status})`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (response.status === 405) {
|
if (response.status === 405) {
|
||||||
return {
|
return {
|
||||||
ok: true,
|
ok: true,
|
||||||
|
status: response.status,
|
||||||
message: 'kiro.rs 上传接口可访问。',
|
message: 'kiro.rs 上传接口可访问。',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (response.status === 401 || response.status === 403) {
|
if (response.status === 401 || response.status === 403) {
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
message: `kiro.rs API Key 被拒绝(HTTP ${response.status})`,
|
status: response.status,
|
||||||
|
message: `kiro.rs API Key 被拒绝(HTTP ${response.status}${detail ? `:${detail}` : ''})`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (response.status === 404) {
|
if (response.status === 404) {
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
message: '未找到 kiro.rs 管理接口。',
|
status: response.status,
|
||||||
|
message: `未找到 kiro.rs 管理接口(HTTP 404${detail ? `:${detail}` : ''})`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
message: cleanString(body.json?.error?.message || body.json?.message || body.text || response.statusText)
|
status: response.status,
|
||||||
|| `kiro.rs 连接失败(HTTP ${response.status})`,
|
message: detail || `kiro.rs 连接失败(HTTP ${response.status})`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uploadBuilderIdCredential(baseUrl, apiKey, payload, fetchImpl) {
|
async function uploadBuilderIdCredential(baseUrl, apiKey, payload, fetchImpl) {
|
||||||
const normalizedBaseUrl = normalizeKiroRsBaseUrl(baseUrl);
|
const normalizedBaseUrl = normalizeKiroRsBaseUrl(baseUrl);
|
||||||
|
const normalizedApiKey = normalizeKiroRsApiKey(apiKey);
|
||||||
const response = await fetchImpl(`${normalizedBaseUrl}/api/admin/credentials`, {
|
const response = await fetchImpl(`${normalizedBaseUrl}/api/admin/credentials`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: buildKiroRsAdminHeaders(normalizedApiKey, {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
'x-api-key': String(apiKey || ''),
|
}),
|
||||||
},
|
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
});
|
});
|
||||||
const body = await readResponse(response);
|
const body = await readResponse(response);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const message = cleanString(body.json?.error?.message || body.json?.message || body.text || response.statusText)
|
const message = readKiroRsResponseMessage(body, response.statusText) || `HTTP ${response.status}`;
|
||||||
|| `HTTP ${response.status}`;
|
|
||||||
throw new Error(`kiro.rs 凭据上传失败:${message}`);
|
throw new Error(`kiro.rs 凭据上传失败:${message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
exportSettingsBundle,
|
exportSettingsBundle,
|
||||||
fetchGeneratedEmail,
|
fetchGeneratedEmail,
|
||||||
refreshGpcCardBalance,
|
refreshGpcCardBalance,
|
||||||
|
testKiroRsConnection,
|
||||||
finalizePhoneActivationAfterSuccessfulFlow,
|
finalizePhoneActivationAfterSuccessfulFlow,
|
||||||
finalizeStep3Completion,
|
finalizeStep3Completion,
|
||||||
finalizeIcloudAliasAfterSuccessfulFlow,
|
finalizeIcloudAliasAfterSuccessfulFlow,
|
||||||
@@ -1543,6 +1544,44 @@
|
|||||||
return { ok: true, ...result };
|
return { ok: true, ...result };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'CHECK_KIRO_RS_CONNECTION': {
|
||||||
|
if (typeof testKiroRsConnection !== 'function') {
|
||||||
|
throw new Error('kiro.rs 连接测试能力尚未接入。');
|
||||||
|
}
|
||||||
|
const currentState = await getState();
|
||||||
|
const activeFlowId = normalizeMessageFlowId(
|
||||||
|
message.payload?.activeFlowId || currentState?.activeFlowId || 'kiro',
|
||||||
|
'kiro'
|
||||||
|
);
|
||||||
|
const targetId = normalizeMessageTargetId(
|
||||||
|
activeFlowId,
|
||||||
|
message.payload?.targetId || currentState?.kiroTargetId || 'kiro-rs',
|
||||||
|
'kiro-rs'
|
||||||
|
);
|
||||||
|
const nestedTargetConfig = currentState?.settingsState?.flows?.kiro?.targets?.[targetId]
|
||||||
|
|| currentState?.flows?.kiro?.targets?.[targetId]
|
||||||
|
|| {};
|
||||||
|
const baseUrl = String(
|
||||||
|
message.payload?.baseUrl
|
||||||
|
?? nestedTargetConfig.baseUrl
|
||||||
|
?? currentState?.kiroRsUrl
|
||||||
|
?? ''
|
||||||
|
).trim();
|
||||||
|
const apiKey = String(
|
||||||
|
message.payload?.apiKey
|
||||||
|
?? nestedTargetConfig.apiKey
|
||||||
|
?? currentState?.kiroRsKey
|
||||||
|
?? ''
|
||||||
|
);
|
||||||
|
const result = await testKiroRsConnection(baseUrl, apiKey);
|
||||||
|
return {
|
||||||
|
ok: Boolean(result?.ok),
|
||||||
|
targetId,
|
||||||
|
status: Number(result?.status) || 0,
|
||||||
|
message: String(result?.message || '').trim(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
case 'RUN_IP_PROXY_AUTO_SYNC_NOW': {
|
case 'RUN_IP_PROXY_AUTO_SYNC_NOW': {
|
||||||
if (typeof runIpProxyAutoSync !== 'function') {
|
if (typeof runIpProxyAutoSync !== 'function') {
|
||||||
throw new Error('IP 代理自动同步能力尚未接入。');
|
throw new Error('IP 代理自动同步能力尚未接入。');
|
||||||
|
|||||||
@@ -357,7 +357,7 @@
|
|||||||
'kiro-target-kiro-rs': {
|
'kiro-target-kiro-rs': {
|
||||||
id: 'kiro-target-kiro-rs',
|
id: 'kiro-target-kiro-rs',
|
||||||
label: 'kiro.rs 配置',
|
label: 'kiro.rs 配置',
|
||||||
rowIds: ['row-kiro-rs-url', 'row-kiro-rs-key'],
|
rowIds: ['row-kiro-rs-url', 'row-kiro-rs-key', 'row-kiro-rs-test-status'],
|
||||||
},
|
},
|
||||||
'kiro-runtime-status': {
|
'kiro-runtime-status': {
|
||||||
id: 'kiro-runtime-status',
|
id: 'kiro-runtime-status',
|
||||||
|
|||||||
@@ -248,15 +248,22 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="data-row" id="row-kiro-rs-key" style="display:none;">
|
<div class="data-row" id="row-kiro-rs-key" style="display:none;">
|
||||||
<span class="data-label">API Key</span>
|
<span class="data-label">API Key</span>
|
||||||
<div class="input-with-icon">
|
<div class="data-inline">
|
||||||
<input type="password" id="input-kiro-rs-key" class="data-input data-input-with-icon"
|
<div class="input-with-icon">
|
||||||
placeholder="请输入 kiro.rs API Key" />
|
<input type="password" id="input-kiro-rs-key" class="data-input data-input-with-icon"
|
||||||
<button id="btn-toggle-kiro-rs-key" class="input-icon-btn" type="button"
|
placeholder="请输入 kiro.rs API Key" />
|
||||||
data-password-toggle="input-kiro-rs-key" data-show-label="显示 kiro.rs API Key"
|
<button id="btn-toggle-kiro-rs-key" class="input-icon-btn" type="button"
|
||||||
data-hide-label="隐藏 kiro.rs API Key" aria-label="显示 kiro.rs API Key"
|
data-password-toggle="input-kiro-rs-key" data-show-label="显示 kiro.rs API Key"
|
||||||
title="显示 kiro.rs API Key"></button>
|
data-hide-label="隐藏 kiro.rs API Key" aria-label="显示 kiro.rs API Key"
|
||||||
|
title="显示 kiro.rs API Key"></button>
|
||||||
|
</div>
|
||||||
|
<button id="btn-test-kiro-rs" class="btn btn-ghost btn-xs data-inline-btn" type="button">测试</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="data-row" id="row-kiro-rs-test-status" style="display:none;">
|
||||||
|
<span class="data-label">连接测试</span>
|
||||||
|
<span id="display-kiro-rs-test-status" class="data-value mono">未测试</span>
|
||||||
|
</div>
|
||||||
<div class="data-row" id="row-kiro-device-code" style="display:none;">
|
<div class="data-row" id="row-kiro-device-code" style="display:none;">
|
||||||
<span class="data-label">授权码</span>
|
<span class="data-label">授权码</span>
|
||||||
<span id="display-kiro-device-code" class="data-value mono">未生成</span>
|
<span id="display-kiro-device-code" class="data-value mono">未生成</span>
|
||||||
|
|||||||
+67
-10
@@ -175,6 +175,9 @@ const rowKiroRsUrl = document.getElementById('row-kiro-rs-url');
|
|||||||
const inputKiroRsUrl = document.getElementById('input-kiro-rs-url');
|
const inputKiroRsUrl = document.getElementById('input-kiro-rs-url');
|
||||||
const rowKiroRsKey = document.getElementById('row-kiro-rs-key');
|
const rowKiroRsKey = document.getElementById('row-kiro-rs-key');
|
||||||
const inputKiroRsKey = document.getElementById('input-kiro-rs-key');
|
const inputKiroRsKey = document.getElementById('input-kiro-rs-key');
|
||||||
|
const btnTestKiroRs = document.getElementById('btn-test-kiro-rs');
|
||||||
|
const rowKiroRsTestStatus = document.getElementById('row-kiro-rs-test-status');
|
||||||
|
const displayKiroRsTestStatus = document.getElementById('display-kiro-rs-test-status');
|
||||||
const rowKiroDeviceCode = document.getElementById('row-kiro-device-code');
|
const rowKiroDeviceCode = document.getElementById('row-kiro-device-code');
|
||||||
const displayKiroDeviceCode = document.getElementById('display-kiro-device-code');
|
const displayKiroDeviceCode = document.getElementById('display-kiro-device-code');
|
||||||
const rowKiroLoginUrl = document.getElementById('row-kiro-login-url');
|
const rowKiroLoginUrl = document.getElementById('row-kiro-login-url');
|
||||||
@@ -551,6 +554,7 @@ let currentSignupMethod = DEFAULT_SIGNUP_METHOD;
|
|||||||
let currentPhoneSignupReloginAfterBindEmailEnabled = DEFAULT_PHONE_SIGNUP_RELOGIN_AFTER_BIND_EMAIL_ENABLED;
|
let currentPhoneSignupReloginAfterBindEmailEnabled = DEFAULT_PHONE_SIGNUP_RELOGIN_AFTER_BIND_EMAIL_ENABLED;
|
||||||
let currentStepDefinitionFlowId = DEFAULT_ACTIVE_FLOW_ID;
|
let currentStepDefinitionFlowId = DEFAULT_ACTIVE_FLOW_ID;
|
||||||
let phoneSignupReuseUiWasLocked = false;
|
let phoneSignupReuseUiWasLocked = false;
|
||||||
|
let kiroRsConnectionTestStatusText = '未测试';
|
||||||
let heroSmsCountrySelectionOrder = [];
|
let heroSmsCountrySelectionOrder = [];
|
||||||
let phoneSmsProviderOrderSelection = [];
|
let phoneSmsProviderOrderSelection = [];
|
||||||
let heroSmsCountryMenuSearchKeyword = '';
|
let heroSmsCountryMenuSearchKeyword = '';
|
||||||
@@ -2401,6 +2405,14 @@ function getKiroUploadStatusLabel(value = '') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setKiroRsConnectionTestStatus(message = '') {
|
||||||
|
const nextText = String(message || '').trim() || '未测试';
|
||||||
|
kiroRsConnectionTestStatusText = nextText;
|
||||||
|
if (typeof displayKiroRsTestStatus !== 'undefined' && displayKiroRsTestStatus) {
|
||||||
|
displayKiroRsTestStatus.textContent = nextText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeStepExecutionRangeByFlow(value = {}) {
|
function normalizeStepExecutionRangeByFlow(value = {}) {
|
||||||
const source = isPlainObjectValue(value) ? value : {};
|
const source = isPlainObjectValue(value) ? value : {};
|
||||||
const next = {};
|
const next = {};
|
||||||
@@ -4253,6 +4265,12 @@ function collectSettingsPayload() {
|
|||||||
const normalized = String(targetId || '').trim().toLowerCase();
|
const normalized = String(targetId || '').trim().toLowerCase();
|
||||||
return normalized || String(fallback || '').trim().toLowerCase() || 'kiro-rs';
|
return normalized || String(fallback || '').trim().toLowerCase() || 'kiro-rs';
|
||||||
});
|
});
|
||||||
|
const currentKiroRsUrlValue = typeof inputKiroRsUrl !== 'undefined' && inputKiroRsUrl
|
||||||
|
? String(inputKiroRsUrl.value ?? '').trim()
|
||||||
|
: null;
|
||||||
|
const currentKiroRsKeyValue = typeof inputKiroRsKey !== 'undefined' && inputKiroRsKey
|
||||||
|
? String(inputKiroRsKey.value ?? '').trim()
|
||||||
|
: null;
|
||||||
return {
|
return {
|
||||||
activeFlowId,
|
activeFlowId,
|
||||||
...(contributionModeEnabled ? {} : {
|
...(contributionModeEnabled ? {} : {
|
||||||
@@ -4265,16 +4283,12 @@ function collectSettingsPayload() {
|
|||||||
: (latestState?.kiroTargetId || 'kiro-rs'),
|
: (latestState?.kiroTargetId || 'kiro-rs'),
|
||||||
'kiro-rs'
|
'kiro-rs'
|
||||||
),
|
),
|
||||||
kiroRsUrl: String(
|
kiroRsUrl: currentKiroRsUrlValue !== null
|
||||||
(typeof inputKiroRsUrl !== 'undefined' && inputKiroRsUrl ? inputKiroRsUrl.value : '')
|
? (currentKiroRsUrlValue || defaultKiroRsUrl)
|
||||||
|| latestState?.kiroRsUrl
|
: (String(latestState?.kiroRsUrl || defaultKiroRsUrl).trim() || defaultKiroRsUrl),
|
||||||
|| defaultKiroRsUrl
|
kiroRsKey: currentKiroRsKeyValue !== null
|
||||||
).trim() || defaultKiroRsUrl,
|
? currentKiroRsKeyValue
|
||||||
kiroRsKey: String(
|
: String(latestState?.kiroRsKey || '').trim(),
|
||||||
(typeof inputKiroRsKey !== 'undefined' && inputKiroRsKey ? inputKiroRsKey.value : '')
|
|
||||||
|| latestState?.kiroRsKey
|
|
||||||
|| ''
|
|
||||||
),
|
|
||||||
vpsUrl: inputVpsUrl.value.trim(),
|
vpsUrl: inputVpsUrl.value.trim(),
|
||||||
vpsPassword: inputVpsPassword.value,
|
vpsPassword: inputVpsPassword.value,
|
||||||
localCpaStep9Mode: getSelectedLocalCpaStep9Mode(),
|
localCpaStep9Mode: getSelectedLocalCpaStep9Mode(),
|
||||||
@@ -10029,6 +10043,9 @@ function applySettingsState(state) {
|
|||||||
if (typeof inputKiroRsKey !== 'undefined' && inputKiroRsKey) {
|
if (typeof inputKiroRsKey !== 'undefined' && inputKiroRsKey) {
|
||||||
inputKiroRsKey.value = String(state?.kiroRsKey || '');
|
inputKiroRsKey.value = String(state?.kiroRsKey || '');
|
||||||
}
|
}
|
||||||
|
if (typeof displayKiroRsTestStatus !== 'undefined' && displayKiroRsTestStatus) {
|
||||||
|
displayKiroRsTestStatus.textContent = kiroRsConnectionTestStatusText;
|
||||||
|
}
|
||||||
if (typeof displayKiroDeviceCode !== 'undefined' && displayKiroDeviceCode) {
|
if (typeof displayKiroDeviceCode !== 'undefined' && displayKiroDeviceCode) {
|
||||||
const kiroDeviceCode = String(
|
const kiroDeviceCode = String(
|
||||||
state?.kiroRuntime?.register?.userCode
|
state?.kiroRuntime?.register?.userCode
|
||||||
@@ -13679,6 +13696,7 @@ btnReset.addEventListener('click', async () => {
|
|||||||
displayOauthUrl.classList.remove('has-value');
|
displayOauthUrl.classList.remove('has-value');
|
||||||
displayLocalhostUrl.textContent = '等待中...';
|
displayLocalhostUrl.textContent = '等待中...';
|
||||||
displayLocalhostUrl.classList.remove('has-value');
|
displayLocalhostUrl.classList.remove('has-value');
|
||||||
|
setKiroRsConnectionTestStatus('未测试');
|
||||||
inputEmail.value = '';
|
inputEmail.value = '';
|
||||||
if (typeof inputSignupPhone !== 'undefined' && inputSignupPhone) {
|
if (typeof inputSignupPhone !== 'undefined' && inputSignupPhone) {
|
||||||
inputSignupPhone.value = '';
|
inputSignupPhone.value = '';
|
||||||
@@ -13922,6 +13940,44 @@ btnGpcHelperBalance?.addEventListener('click', async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
btnTestKiroRs?.addEventListener('click', async () => {
|
||||||
|
const defaultLabel = btnTestKiroRs.textContent || '测试';
|
||||||
|
btnTestKiroRs.disabled = true;
|
||||||
|
btnTestKiroRs.textContent = '测试中';
|
||||||
|
setKiroRsConnectionTestStatus('测试中...');
|
||||||
|
try {
|
||||||
|
await persistCurrentSettingsForAction();
|
||||||
|
const activeFlowId = typeof getSelectedFlowId === 'function'
|
||||||
|
? getSelectedFlowId(latestState)
|
||||||
|
: 'kiro';
|
||||||
|
const targetId = typeof getSelectedTargetId === 'function'
|
||||||
|
? getSelectedTargetId(activeFlowId)
|
||||||
|
: 'kiro-rs';
|
||||||
|
const response = await sendSidepanelMessage({
|
||||||
|
type: 'CHECK_KIRO_RS_CONNECTION',
|
||||||
|
payload: {
|
||||||
|
activeFlowId,
|
||||||
|
targetId,
|
||||||
|
baseUrl: String(inputKiroRsUrl?.value || '').trim(),
|
||||||
|
apiKey: String(inputKiroRsKey?.value || ''),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (response?.error) {
|
||||||
|
throw new Error(response.error);
|
||||||
|
}
|
||||||
|
const message = String(response?.message || '').trim() || 'kiro.rs 测试完成。';
|
||||||
|
setKiroRsConnectionTestStatus(message);
|
||||||
|
showToast(message, response?.ok ? 'success' : 'error', response?.ok ? 2200 : 4200);
|
||||||
|
} catch (error) {
|
||||||
|
const message = error?.message || 'kiro.rs 测试失败。';
|
||||||
|
setKiroRsConnectionTestStatus(message);
|
||||||
|
showToast(message, 'error', 4200);
|
||||||
|
} finally {
|
||||||
|
btnTestKiroRs.disabled = false;
|
||||||
|
btnTestKiroRs.textContent = defaultLabel;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
selectPlusPaymentMethod?.addEventListener('change', () => {
|
selectPlusPaymentMethod?.addEventListener('change', () => {
|
||||||
updatePlusModeUI();
|
updatePlusModeUI();
|
||||||
const stepDefinitionState = typeof resolveStepDefinitionCapabilityState === 'function'
|
const stepDefinitionState = typeof resolveStepDefinitionCapabilityState === 'function'
|
||||||
@@ -14161,6 +14217,7 @@ selectPanelMode.addEventListener('change', async () => {
|
|||||||
[inputKiroRsUrl, inputKiroRsKey].forEach((input) => {
|
[inputKiroRsUrl, inputKiroRsKey].forEach((input) => {
|
||||||
input?.addEventListener('input', () => {
|
input?.addEventListener('input', () => {
|
||||||
markSettingsDirty(true);
|
markSettingsDirty(true);
|
||||||
|
setKiroRsConnectionTestStatus('未测试');
|
||||||
scheduleSettingsAutoSave();
|
scheduleSettingsAutoSave();
|
||||||
});
|
});
|
||||||
input?.addEventListener('blur', () => {
|
input?.addEventListener('blur', () => {
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ return {
|
|||||||
assert.equal(api.normalizePersistentSettingValue('activeFlowId', 'kiro'), 'kiro');
|
assert.equal(api.normalizePersistentSettingValue('activeFlowId', 'kiro'), 'kiro');
|
||||||
assert.equal(api.normalizePersistentSettingValue('kiroTargetId', 'unknown'), 'kiro-rs');
|
assert.equal(api.normalizePersistentSettingValue('kiroTargetId', 'unknown'), 'kiro-rs');
|
||||||
assert.equal(api.normalizePersistentSettingValue('kiroRsUrl', ''), 'https://kiro.leftcode.xyz/admin');
|
assert.equal(api.normalizePersistentSettingValue('kiroRsUrl', ''), 'https://kiro.leftcode.xyz/admin');
|
||||||
assert.equal(api.normalizePersistentSettingValue('kiroRsKey', ' key-1 '), ' key-1 ');
|
assert.equal(api.normalizePersistentSettingValue('kiroRsKey', ' key-1 '), 'key-1');
|
||||||
assert.equal(api.normalizePersistentSettingValue('phoneSmsProvider', '5SIM'), '5sim');
|
assert.equal(api.normalizePersistentSettingValue('phoneSmsProvider', '5SIM'), '5sim');
|
||||||
assert.equal(api.normalizePersistentSettingValue('phoneSmsProvider', 'NEXSMS'), 'nexsms');
|
assert.equal(api.normalizePersistentSettingValue('phoneSmsProvider', 'NEXSMS'), 'nexsms');
|
||||||
assert.equal(api.normalizePersistentSettingValue('phoneSmsProvider', 'unknown'), 'hero-sms');
|
assert.equal(api.normalizePersistentSettingValue('phoneSmsProvider', 'unknown'), 'hero-sms');
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ test('kiro publisher reads latest kiro.rs key from background state instead of s
|
|||||||
url,
|
url,
|
||||||
method: options.method || 'GET',
|
method: options.method || 'GET',
|
||||||
apiKey: options.headers?.['x-api-key'],
|
apiKey: options.headers?.['x-api-key'],
|
||||||
|
authorization: options.headers?.Authorization,
|
||||||
});
|
});
|
||||||
if ((options.method || 'GET') === 'GET') {
|
if ((options.method || 'GET') === 'GET') {
|
||||||
return {
|
return {
|
||||||
@@ -158,7 +159,45 @@ test('kiro publisher reads latest kiro.rs key from background state instead of s
|
|||||||
|
|
||||||
assert.equal(requests.length, 2);
|
assert.equal(requests.length, 2);
|
||||||
assert.equal(requests[0].apiKey, 'live-key');
|
assert.equal(requests[0].apiKey, 'live-key');
|
||||||
|
assert.equal(requests[0].authorization, 'Bearer live-key');
|
||||||
assert.equal(requests[1].apiKey, 'live-key');
|
assert.equal(requests[1].apiKey, 'live-key');
|
||||||
|
assert.equal(requests[1].authorization, 'Bearer live-key');
|
||||||
assert.equal(completed.length, 1);
|
assert.equal(completed.length, 1);
|
||||||
assert.equal(completed[0].nodeId, 'kiro-upload-credential');
|
assert.equal(completed[0].nodeId, 'kiro-upload-credential');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('kiro publisher trims api key and includes fallback Authorization header during connection check', async () => {
|
||||||
|
const api = loadPublisherApi();
|
||||||
|
const requests = [];
|
||||||
|
|
||||||
|
const result = await api.checkKiroRsConnection(
|
||||||
|
'https://kiro.example.com/admin',
|
||||||
|
' live-key ',
|
||||||
|
async (url, options = {}) => {
|
||||||
|
requests.push({
|
||||||
|
url,
|
||||||
|
method: options.method || 'GET',
|
||||||
|
apiKey: options.headers?.['x-api-key'],
|
||||||
|
authorization: options.headers?.Authorization,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
status: 401,
|
||||||
|
statusText: 'Unauthorized',
|
||||||
|
text: async () => JSON.stringify({
|
||||||
|
error: {
|
||||||
|
message: 'Invalid or missing admin API key',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(requests.length, 1);
|
||||||
|
assert.equal(requests[0].method, 'GET');
|
||||||
|
assert.equal(requests[0].apiKey, 'live-key');
|
||||||
|
assert.equal(requests[0].authorization, 'Bearer live-key');
|
||||||
|
assert.equal(result.ok, false);
|
||||||
|
assert.equal(result.status, 401);
|
||||||
|
assert.equal(result.message, 'kiro.rs API Key 被拒绝(HTTP 401:Invalid or missing admin API key)');
|
||||||
|
});
|
||||||
|
|||||||
@@ -449,6 +449,63 @@ test('SAVE_SETTING syncs canonical kiro settingsState back into session state',
|
|||||||
assert.equal(state.settingsState.flows.kiro.targets['kiro-rs'].apiKey, 'live-key');
|
assert.equal(state.settingsState.flows.kiro.targets['kiro-rs'].apiKey, 'live-key');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('CHECK_KIRO_RS_CONNECTION prefers current sidepanel payload over stale saved kiro.rs config', async () => {
|
||||||
|
const source = fs.readFileSync('background/message-router.js', 'utf8');
|
||||||
|
const globalScope = { console };
|
||||||
|
const api = new Function('self', `${source}; return self.MultiPageBackgroundMessageRouter;`)(globalScope);
|
||||||
|
const calls = [];
|
||||||
|
const router = api.createMessageRouter({
|
||||||
|
getState: async () => ({
|
||||||
|
activeFlowId: 'kiro',
|
||||||
|
flowId: 'kiro',
|
||||||
|
kiroTargetId: 'kiro-rs',
|
||||||
|
kiroRsUrl: 'https://old.example.com/admin',
|
||||||
|
kiroRsKey: 'old-key',
|
||||||
|
settingsState: {
|
||||||
|
flows: {
|
||||||
|
kiro: {
|
||||||
|
targetId: 'kiro-rs',
|
||||||
|
targets: {
|
||||||
|
'kiro-rs': {
|
||||||
|
baseUrl: 'https://old.example.com/admin',
|
||||||
|
apiKey: 'old-key',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
testKiroRsConnection: async (baseUrl, apiKey) => {
|
||||||
|
calls.push({ baseUrl, apiKey });
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
status: 401,
|
||||||
|
message: 'kiro.rs API Key 被拒绝(HTTP 401:Invalid or missing admin API key)',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await router.handleMessage({
|
||||||
|
type: 'CHECK_KIRO_RS_CONNECTION',
|
||||||
|
payload: {
|
||||||
|
activeFlowId: 'kiro',
|
||||||
|
targetId: 'kiro-rs',
|
||||||
|
baseUrl: ' https://new.example.com/admin/ ',
|
||||||
|
apiKey: ' new-key ',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(response.ok, false);
|
||||||
|
assert.equal(response.status, 401);
|
||||||
|
assert.equal(response.message, 'kiro.rs API Key 被拒绝(HTTP 401:Invalid or missing admin API key)');
|
||||||
|
assert.deepStrictEqual(calls, [
|
||||||
|
{
|
||||||
|
baseUrl: 'https://new.example.com/admin/',
|
||||||
|
apiKey: ' new-key ',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
test('AUTO_RUN applies current flow selection from payload before starting loop', async () => {
|
test('AUTO_RUN applies current flow selection from payload before starting loop', async () => {
|
||||||
const source = fs.readFileSync('background/message-router.js', 'utf8');
|
const source = fs.readFileSync('background/message-router.js', 'utf8');
|
||||||
const globalScope = { console };
|
const globalScope = { console };
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ test('sidepanel html exposes flow selector and kiro source fields', () => {
|
|||||||
'id="row-step6-cookie-settings"',
|
'id="row-step6-cookie-settings"',
|
||||||
'id="row-kiro-rs-url"',
|
'id="row-kiro-rs-url"',
|
||||||
'id="row-kiro-rs-key"',
|
'id="row-kiro-rs-key"',
|
||||||
|
'id="btn-test-kiro-rs"',
|
||||||
|
'id="row-kiro-rs-test-status"',
|
||||||
'id="row-kiro-device-code"',
|
'id="row-kiro-device-code"',
|
||||||
'id="row-kiro-login-url"',
|
'id="row-kiro-login-url"',
|
||||||
'id="row-kiro-upload-status"',
|
'id="row-kiro-upload-status"',
|
||||||
|
|||||||
Reference in New Issue
Block a user