diff --git a/background.js b/background.js index 1e9d277..51cc9cb 100644 --- a/background.js +++ b/background.js @@ -2775,7 +2775,7 @@ function normalizePersistentSettingValue(key, value) { || 'https://kiro.leftcode.xyz/admin' ).trim() || 'https://kiro.leftcode.xyz/admin'; case 'kiroRsKey': - return String(value || ''); + return String(value || '').trim(); case 'vpsUrl': return String(value || '').trim(); case 'vpsPassword': @@ -13351,6 +13351,16 @@ const messageRouter = self.MultiPageBackgroundMessageRouter?.createMessageRouter fetchGeneratedEmail, refreshGpcCardBalance, 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 () => { const currentState = await getState(); const signupTabId = await getTabId('signup-page'); diff --git a/background/kiro/publisher-kiro-rs.js b/background/kiro/publisher-kiro-rs.js index 7cd7724..dc02afc 100644 --- a/background/kiro/publisher-kiro-rs.js +++ b/background/kiro/publisher-kiro-rs.js @@ -47,6 +47,25 @@ 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 = '') { const normalized = cleanString(value).replace(/\/+$/, ''); if (!normalized) { @@ -116,7 +135,7 @@ || {}; return { 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) { const normalizedBaseUrl = normalizeKiroRsBaseUrl(baseUrl); + const normalizedApiKey = normalizeKiroRsApiKey(apiKey); const response = await fetchImpl(`${normalizedBaseUrl}/api/admin/credentials`, { method: 'GET', - headers: { + headers: buildKiroRsAdminHeaders(normalizedApiKey, { Accept: 'application/json', - 'x-api-key': String(apiKey || ''), - }, + }), }); const body = await readResponse(response); + const detail = readKiroRsResponseMessage(body, response.statusText); if (response.ok) { return { ok: true, + status: response.status, message: `kiro.rs 连接正常(HTTP ${response.status})`, }; } if (response.status === 405) { return { ok: true, + status: response.status, message: 'kiro.rs 上传接口可访问。', }; } if (response.status === 401 || response.status === 403) { return { 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) { return { ok: false, - message: '未找到 kiro.rs 管理接口。', + status: response.status, + message: `未找到 kiro.rs 管理接口(HTTP 404${detail ? `:${detail}` : ''})`, }; } return { ok: false, - message: cleanString(body.json?.error?.message || body.json?.message || body.text || response.statusText) - || `kiro.rs 连接失败(HTTP ${response.status})`, + status: response.status, + message: detail || `kiro.rs 连接失败(HTTP ${response.status})`, }; } async function uploadBuilderIdCredential(baseUrl, apiKey, payload, fetchImpl) { const normalizedBaseUrl = normalizeKiroRsBaseUrl(baseUrl); + const normalizedApiKey = normalizeKiroRsApiKey(apiKey); const response = await fetchImpl(`${normalizedBaseUrl}/api/admin/credentials`, { method: 'POST', - headers: { + headers: buildKiroRsAdminHeaders(normalizedApiKey, { 'Content-Type': 'application/json', Accept: 'application/json', - 'x-api-key': String(apiKey || ''), - }, + }), body: JSON.stringify(payload), }); const body = await readResponse(response); if (!response.ok) { - const message = cleanString(body.json?.error?.message || body.json?.message || body.text || response.statusText) - || `HTTP ${response.status}`; + const message = readKiroRsResponseMessage(body, response.statusText) || `HTTP ${response.status}`; throw new Error(`kiro.rs 凭据上传失败:${message}`); } diff --git a/background/message-router.js b/background/message-router.js index c45f0b9..ed6f4f4 100644 --- a/background/message-router.js +++ b/background/message-router.js @@ -37,6 +37,7 @@ exportSettingsBundle, fetchGeneratedEmail, refreshGpcCardBalance, + testKiroRsConnection, finalizePhoneActivationAfterSuccessfulFlow, finalizeStep3Completion, finalizeIcloudAliasAfterSuccessfulFlow, @@ -1543,6 +1544,44 @@ 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': { if (typeof runIpProxyAutoSync !== 'function') { throw new Error('IP 代理自动同步能力尚未接入。'); diff --git a/shared/flow-registry.js b/shared/flow-registry.js index 60b90ae..136ec20 100644 --- a/shared/flow-registry.js +++ b/shared/flow-registry.js @@ -357,7 +357,7 @@ 'kiro-target-kiro-rs': { id: 'kiro-target-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': { id: 'kiro-runtime-status', diff --git a/sidepanel/sidepanel.html b/sidepanel/sidepanel.html index 8d57e9d..7d73a75 100644 --- a/sidepanel/sidepanel.html +++ b/sidepanel/sidepanel.html @@ -248,15 +248,22 @@