refactor flows into canonical runtime architecture

This commit is contained in:
QLHazyCoder
2026-05-21 07:21:34 +08:00
parent e2485d2e64
commit a7b35ee11a
167 changed files with 9034 additions and 3032 deletions
@@ -0,0 +1,138 @@
(function attachBackgroundKiroCredentialArtifact(root, factory) {
root.MultiPageBackgroundKiroCredentialArtifact = factory(root);
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundKiroCredentialArtifactModule(root) {
const kiroStateApi = root?.MultiPageBackgroundKiroState || null;
const FLOW_ID = 'kiro';
const ADAPTER_ID = 'kiro-builder-id';
const ARTIFACT_KIND = 'kiro-builder-id';
const DEFAULT_REGION = kiroStateApi?.DEFAULT_REGION || 'us-east-1';
const DEFAULT_TARGET_ID = kiroStateApi?.DEFAULT_TARGET_ID || 'kiro-rs';
const BUILDER_ID_PROFILE_ARN = 'arn:aws:codewhisperer:us-east-1:638616132270:profile/AAAACCCCXXXX';
function isPlainObject(value) {
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}
function cleanString(value = '') {
return String(value ?? '').trim();
}
function readKiroRuntime(state = {}) {
return kiroStateApi?.ensureRuntimeState
? kiroStateApi.ensureRuntimeState(state)
: (isPlainObject(state?.runtimeState?.flowState?.kiro)
? state.runtimeState.flowState.kiro
: (isPlainObject(state?.flowState?.kiro) ? state.flowState.kiro : {}));
}
function resolveKiroTargetId(state = {}, runtimeState = readKiroRuntime(state)) {
return cleanString(
state?.settingsState?.flows?.kiro?.selectedTargetId
|| state?.targetId
|| runtimeState?.upload?.targetId
|| DEFAULT_TARGET_ID
) || DEFAULT_TARGET_ID;
}
function resolveEmail(state = {}, runtimeState = readKiroRuntime(state)) {
return cleanString(
runtimeState?.register?.email
|| state?.email
|| state?.registrationEmailState?.current
|| state?.accountIdentifier
);
}
function resolveRegion(state = {}, runtimeState = readKiroRuntime(state), targetId = DEFAULT_TARGET_ID) {
return cleanString(
runtimeState?.desktopAuth?.region
|| state?.settingsState?.flows?.kiro?.targets?.[targetId]?.region
|| DEFAULT_REGION
) || DEFAULT_REGION;
}
function assertRequiredField(name, value, message) {
if (!cleanString(value)) {
const error = new Error(message);
error.code = `missing_${name}`;
throw error;
}
}
function redactSecret(value = '') {
const normalized = cleanString(value);
if (!normalized) {
return '';
}
if (normalized.length <= 10) {
return `${normalized.slice(0, 2)}***`;
}
return `${normalized.slice(0, 6)}...${normalized.slice(-4)}`;
}
function buildKiroBuilderIdArtifact(state = {}, options = {}) {
const runtimeState = readKiroRuntime(state);
const desktopAuth = runtimeState?.desktopAuth || {};
const targetId = resolveKiroTargetId(state, runtimeState);
const region = resolveRegion(state, runtimeState, targetId);
const email = resolveEmail(state, runtimeState);
const refreshToken = String(desktopAuth.refreshToken || '');
const clientId = cleanString(desktopAuth.clientId);
const clientSecret = String(desktopAuth.clientSecret || '');
assertRequiredField('refreshToken', refreshToken, '缺少桌面授权 refreshToken,无法提交 Kiro Builder ID 贡献。');
assertRequiredField('clientId', clientId, '缺少桌面授权 clientId,无法提交 Kiro Builder ID 贡献。');
assertRequiredField('clientSecret', clientSecret, '缺少桌面授权 clientSecret,无法提交 Kiro Builder ID 贡献。');
assertRequiredField('email', email, '缺少注册邮箱,无法提交 Kiro Builder ID 贡献。');
return {
schemaVersion: 1,
flow: FLOW_ID,
adapter: ADAPTER_ID,
artifact: ARTIFACT_KIND,
account: {
email,
},
credentials: {
refreshToken,
clientId,
clientSecret,
profileArn: cleanString(options.profileArn) || BUILDER_ID_PROFILE_ARN,
authMethod: 'idc',
region,
authRegion: region,
apiRegion: region,
tokenSource: cleanString(desktopAuth.tokenSource) || 'desktop_authorization_code_pkce',
},
metadata: {
targetId,
authorizedAt: Math.max(0, Number(desktopAuth.authorizedAt) || 0),
generatedAt: new Date().toISOString(),
source: 'flowpilot-extension',
},
};
}
function buildSafeArtifactSummary(artifact = {}) {
return {
flow: cleanString(artifact.flow),
adapter: cleanString(artifact.adapter),
artifact: cleanString(artifact.artifact),
email: cleanString(artifact.account?.email),
clientId: cleanString(artifact.credentials?.clientId),
refreshToken: redactSecret(artifact.credentials?.refreshToken),
clientSecret: redactSecret(artifact.credentials?.clientSecret),
region: cleanString(artifact.credentials?.region),
};
}
return {
ADAPTER_ID,
ARTIFACT_KIND,
BUILDER_ID_PROFILE_ARN,
FLOW_ID,
buildKiroBuilderIdArtifact,
buildSafeArtifactSummary,
redactSecret,
};
});
File diff suppressed because it is too large Load Diff
+196
View File
@@ -0,0 +1,196 @@
(function attachBackgroundKiroDesktopClient(root, factory) {
root.MultiPageBackgroundKiroDesktopClient = factory();
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundKiroDesktopClientModule() {
const DEFAULT_REGION = 'us-east-1';
const DEFAULT_START_URL = 'https://view.awsapps.com/start';
const DEFAULT_SCOPES = Object.freeze([
'codewhisperer:completions',
'codewhisperer:analysis',
'codewhisperer:conversations',
'codewhisperer:transformations',
'codewhisperer:taskassist',
]);
function cleanString(value = '') {
return String(value ?? '').trim();
}
function normalizeRegion(value = '', fallback = DEFAULT_REGION) {
return cleanString(value) || fallback;
}
function buildOidcBaseUrl(region = DEFAULT_REGION) {
return `https://oidc.${normalizeRegion(region)}.amazonaws.com`;
}
async function readResponse(response) {
const text = await response.text();
let json = null;
try {
json = text ? JSON.parse(text) : null;
} catch (_error) {
json = null;
}
return { text, json };
}
async function sha256Bytes(input) {
const encoder = new TextEncoder();
return new Uint8Array(await crypto.subtle.digest('SHA-256', encoder.encode(String(input || ''))));
}
function base64UrlEncode(bytes) {
let binary = '';
for (const byte of bytes) {
binary += String.fromCharCode(byte);
}
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
}
async function sha256Hex(input) {
const bytes = await sha256Bytes(input);
return Array.from(bytes).map((byte) => byte.toString(16).padStart(2, '0')).join('');
}
function randomUrlSafeString(length = 64) {
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
const size = Math.max(32, Math.floor(Number(length) || 64));
const bytes = new Uint8Array(size);
crypto.getRandomValues(bytes);
let output = '';
for (let index = 0; index < size; index += 1) {
output += alphabet[bytes[index] % alphabet.length];
}
return output;
}
async function generatePkcePair() {
const codeVerifier = randomUrlSafeString(64);
const codeChallenge = base64UrlEncode(await sha256Bytes(codeVerifier));
return {
codeVerifier,
codeChallenge,
};
}
function chooseRedirectPort() {
return 49152 + Math.floor(Math.random() * 16384);
}
function buildRedirectUri(port) {
const normalizedPort = Math.max(1, Math.floor(Number(port) || 0));
if (!normalizedPort) {
throw new Error('缺少桌面授权回调端口。');
}
return `http://127.0.0.1:${normalizedPort}/oauth/callback`;
}
async function registerDesktopClient(params = {}, fetchImpl) {
if (typeof fetchImpl !== 'function') {
throw new Error('registerDesktopClient requires fetch support.');
}
const region = normalizeRegion(params.region);
const oidcBaseUrl = buildOidcBaseUrl(region);
const response = await fetchImpl(`${oidcBaseUrl}/client/register`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
clientName: cleanString(params.clientName) || 'Kiro IDE',
clientType: 'public',
scopes: Array.isArray(params.scopes) && params.scopes.length ? params.scopes : DEFAULT_SCOPES,
grantTypes: ['authorization_code', 'refresh_token'],
redirectUris: ['http://127.0.0.1/oauth/callback'],
issuerUrl: cleanString(params.issuerUrl) || DEFAULT_START_URL,
}),
});
const body = await readResponse(response);
if (!response.ok) {
throw new Error(`Kiro 桌面客户端注册失败:${cleanString(body.text || response.statusText) || response.status}`);
}
const clientId = cleanString(body.json?.clientId);
const clientSecret = String(body.json?.clientSecret || '');
if (!clientId || !clientSecret) {
throw new Error('Kiro 桌面客户端注册响应缺少 clientId 或 clientSecret。');
}
return {
region,
clientId,
clientSecret,
clientSecretExpiresAt: Number(body.json?.clientSecretExpiresAt || 0) || 0,
clientIdHash: await sha256Hex(JSON.stringify({
startUrl: cleanString(params.issuerUrl) || DEFAULT_START_URL,
clientId,
})),
};
}
function buildAuthorizeUrl(params = {}) {
const region = normalizeRegion(params.region);
const search = new URLSearchParams();
search.set('response_type', 'code');
search.set('client_id', cleanString(params.clientId));
search.set('redirect_uri', cleanString(params.redirectUri));
search.set('scopes', Array.isArray(params.scopes) && params.scopes.length
? params.scopes.join(',')
: DEFAULT_SCOPES.join(','));
search.set('state', cleanString(params.state));
search.set('code_challenge', cleanString(params.codeChallenge));
search.set('code_challenge_method', 'S256');
return `${buildOidcBaseUrl(region)}/authorize?${search.toString()}`;
}
async function exchangeDesktopAuthorizationCode(params = {}, fetchImpl) {
if (typeof fetchImpl !== 'function') {
throw new Error('exchangeDesktopAuthorizationCode requires fetch support.');
}
const region = normalizeRegion(params.region);
const response = await fetchImpl(`${buildOidcBaseUrl(region)}/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
clientId: cleanString(params.clientId),
clientSecret: String(params.clientSecret || ''),
grantType: 'authorization_code',
code: cleanString(params.code),
redirectUri: cleanString(params.redirectUri),
codeVerifier: cleanString(params.codeVerifier),
}),
});
const body = await readResponse(response);
if (!response.ok) {
throw new Error(`Kiro 桌面授权换取 Token 失败:${cleanString(body.text || response.statusText) || response.status}`);
}
const accessToken = String(body.json?.accessToken || '');
const refreshToken = String(body.json?.refreshToken || '');
if (!accessToken || !refreshToken) {
throw new Error('Kiro 桌面授权换取 Token 响应缺少 accessToken 或 refreshToken。');
}
return {
accessToken,
refreshToken,
expiresIn: Number(body.json?.expiresIn || 0) || 0,
tokenType: cleanString(body.json?.tokenType),
region,
};
}
return {
DEFAULT_REGION,
DEFAULT_SCOPES,
DEFAULT_START_URL,
buildAuthorizeUrl,
buildRedirectUri,
chooseRedirectPort,
exchangeDesktopAuthorizationCode,
generatePkcePair,
registerDesktopClient,
};
});
+491
View File
@@ -0,0 +1,491 @@
(function attachBackgroundKiroPublisherKiroRs(root, factory) {
root.MultiPageBackgroundKiroPublisherKiroRs = factory(root);
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundKiroPublisherKiroRsModule(root) {
const kiroStateApi = root?.MultiPageBackgroundKiroState || null;
const DEFAULT_REGION = kiroStateApi?.DEFAULT_REGION || 'us-east-1';
const DEFAULT_TARGET_ID = kiroStateApi?.DEFAULT_TARGET_ID || 'kiro-rs';
const BUILDER_ID_PROFILE_ARN = 'arn:aws:codewhisperer:us-east-1:638616132270:profile/AAAACCCCXXXX';
function isPlainObject(value) {
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}
function cloneValue(value) {
if (Array.isArray(value)) {
return value.map((entry) => cloneValue(entry));
}
if (isPlainObject(value)) {
return Object.fromEntries(
Object.entries(value).map(([key, entryValue]) => [key, cloneValue(entryValue)])
);
}
return value;
}
function deepMerge(baseValue, patchValue) {
if (Array.isArray(patchValue)) {
return patchValue.map((entry) => cloneValue(entry));
}
if (!isPlainObject(patchValue)) {
return patchValue === undefined ? cloneValue(baseValue) : patchValue;
}
const baseObject = isPlainObject(baseValue) ? baseValue : {};
const next = {
...cloneValue(baseObject),
};
Object.entries(patchValue).forEach(([key, value]) => {
next[key] = deepMerge(baseObject[key], value);
});
return next;
}
function cleanString(value = '') {
return String(value ?? '').trim();
}
function normalizeRegion(value = '', fallback = DEFAULT_REGION) {
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) {
throw new Error('缺少 kiro.rs 管理后台地址。');
}
return normalized.endsWith('/admin')
? normalized.slice(0, -'/admin'.length)
: normalized;
}
function normalizeKiroUploadMessage(value = '') {
const rawValue = cleanString(value);
if (!rawValue) {
return '上传成功';
}
const normalizedValue = rawValue.toLowerCase();
if (normalizedValue === 'uploaded' || normalizedValue === 'credential uploaded.') {
return '上传成功';
}
return rawValue;
}
function getErrorMessage(error) {
return error instanceof Error ? error.message : String(error ?? '未知错误');
}
async function readResponse(response) {
const text = await response.text();
let json = null;
try {
json = text ? JSON.parse(text) : null;
} catch (_error) {
json = null;
}
return { text, json };
}
function readKiroRuntime(state = {}) {
return kiroStateApi?.ensureRuntimeState
? kiroStateApi.ensureRuntimeState(state)
: (isPlainObject(state?.runtimeState?.flowState?.kiro)
? state.runtimeState.flowState.kiro
: (isPlainObject(state?.flowState?.kiro) ? state.flowState.kiro : {}));
}
function buildCanonicalRuntimePatch(currentState = {}, nextRuntimeState = {}) {
if (typeof kiroStateApi?.buildRuntimeStatePatch === 'function') {
return kiroStateApi.buildRuntimeStatePatch(currentState, nextRuntimeState);
}
const baseRuntimeState = isPlainObject(currentState?.runtimeState)
? cloneValue(currentState.runtimeState)
: {};
const baseFlowState = isPlainObject(baseRuntimeState.flowState)
? cloneValue(baseRuntimeState.flowState)
: {};
return {
runtimeState: {
...baseRuntimeState,
flowState: {
...baseFlowState,
kiro: deepMerge(readKiroRuntime(currentState), nextRuntimeState),
},
},
};
}
function mergeRuntimePatch(currentState = {}, patch = {}) {
return buildCanonicalRuntimePatch(
currentState,
deepMerge(readKiroRuntime(currentState), patch)
);
}
function resolveKiroTargetId(state = {}) {
return cleanString(
state?.settingsState?.flows?.kiro?.selectedTargetId
|| state?.targetId
|| readKiroRuntime(state).upload?.targetId
|| DEFAULT_TARGET_ID
) || DEFAULT_TARGET_ID;
}
function resolveKiroTargetConfig(state = {}, targetId = DEFAULT_TARGET_ID) {
if (targetId !== DEFAULT_TARGET_ID) {
throw new Error(`暂不支持 Kiro 发布目标:${targetId}`);
}
const nestedConfig = state?.settingsState?.flows?.kiro?.targets?.[targetId] || {};
return {
baseUrl: cleanString(nestedConfig.baseUrl || state?.kiroRsUrl),
apiKey: normalizeKiroRsApiKey(nestedConfig.apiKey ?? state?.kiroRsKey ?? ''),
};
}
function buildProxyPayload(state = {}) {
if (!state?.ipProxyEnabled) {
return {};
}
const apiProxyUrl = cleanString(state?.ipProxyApiUrl);
const host = cleanString(state?.ipProxyHost);
const port = cleanString(state?.ipProxyPort);
const protocol = cleanString(state?.ipProxyProtocol) || 'http';
const proxyUrl = apiProxyUrl || (host && port ? `${protocol}://${host}:${port}` : '');
const proxyUsername = cleanString(state?.ipProxyUsername);
const proxyPassword = String(state?.ipProxyPassword || '');
return {
...(proxyUrl ? { proxyUrl } : {}),
...(proxyUsername ? { proxyUsername } : {}),
...(proxyPassword ? { proxyPassword } : {}),
};
}
async function sha256Hex(input = '') {
const encoder = new TextEncoder();
const bytes = encoder.encode(String(input ?? ''));
const digest = await globalThis.crypto.subtle.digest('SHA-256', bytes);
return Array.from(new Uint8Array(digest))
.map((value) => value.toString(16).padStart(2, '0'))
.join('');
}
async function buildMachineId(refreshToken = '') {
const normalizedRefreshToken = cleanString(refreshToken);
if (!normalizedRefreshToken) {
throw new Error('缺少 refreshToken,无法生成 machineId。');
}
return sha256Hex(`KotlinNativeAPI/${normalizedRefreshToken}`);
}
function buildUploadPayload(state = {}) {
const runtimeState = readKiroRuntime(state);
const targetId = resolveKiroTargetId(state);
const desktopAuth = runtimeState.desktopAuth || {};
const register = runtimeState.register || {};
const refreshToken = String(desktopAuth.refreshToken || '');
const clientId = cleanString(desktopAuth.clientId);
const clientSecret = String(desktopAuth.clientSecret || '');
const region = normalizeRegion(
desktopAuth.region
|| state?.settingsState?.flows?.kiro?.targets?.[targetId]?.region
|| DEFAULT_REGION
);
const email = cleanString(register.email || state?.email);
if (!refreshToken) {
throw new Error('缺少桌面授权 refreshToken,请先完成步骤 8。');
}
if (!clientId || !clientSecret) {
throw new Error('缺少桌面授权 clientId 或 clientSecret,请先完成步骤 7-8。');
}
if (!email) {
throw new Error('缺少注册邮箱,无法上传到 kiro.rs。');
}
return {
targetId,
region,
email,
refreshToken,
profileArn: BUILDER_ID_PROFILE_ARN,
clientId,
clientSecret,
authMethod: 'idc',
authRegion: region,
apiRegion: region,
...buildProxyPayload(state),
};
}
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: buildKiroRsAdminHeaders(normalizedApiKey, {
Accept: 'application/json',
}),
});
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,
status: response.status,
message: `kiro.rs API Key 被拒绝(HTTP ${response.status}${detail ? `${detail}` : ''}`,
};
}
if (response.status === 404) {
return {
ok: false,
status: response.status,
message: `未找到 kiro.rs 管理接口(HTTP 404${detail ? `${detail}` : ''}`,
};
}
return {
ok: false,
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: buildKiroRsAdminHeaders(normalizedApiKey, {
'Content-Type': 'application/json',
Accept: 'application/json',
}),
body: JSON.stringify(payload),
});
const body = await readResponse(response);
if (!response.ok) {
const message = readKiroRsResponseMessage(body, response.statusText) || `HTTP ${response.status}`;
throw new Error(`kiro.rs 凭据上传失败:${message}`);
}
return {
credentialId: Number(body.json?.credentialId || body.json?.credential_id || 0) || null,
email: cleanString(body.json?.email),
message: normalizeKiroUploadMessage(body.json?.message),
raw: body.json,
};
}
function createKiroRsPublisher(deps = {}) {
const {
addLog = async () => {},
completeNodeFromBackground,
fetchImpl = typeof fetch === 'function' ? fetch.bind(globalThis) : null,
getState = async () => ({}),
maybeSubmitFlowContribution = async () => ({ ok: true, skipped: true, reason: 'not_configured' }),
setState = async () => {},
} = deps;
if (typeof completeNodeFromBackground !== 'function') {
throw new Error('Kiro kiro.rs publisher requires completeNodeFromBackground.');
}
if (typeof fetchImpl !== 'function') {
throw new Error('Kiro kiro.rs publisher requires fetch support.');
}
async function log(message, level = 'info', nodeId = '') {
await addLog(message, level, nodeId ? { nodeId } : {});
}
async function applyRuntimeState(currentState = {}, patch = {}) {
const nextPatch = mergeRuntimePatch(currentState, patch);
await setState(nextPatch);
return nextPatch;
}
async function persistFailure(currentState = {}, message = '') {
const nextPatch = mergeRuntimePatch(currentState, {
session: {
currentStage: 'upload',
lastError: message,
},
upload: {
status: 'error',
error: message,
},
});
await setState(nextPatch);
}
function shouldUseContributionUpload(state = {}) {
return Boolean(state?.accountContributionEnabled)
&& cleanString(state?.activeFlowId || state?.flowId).toLowerCase() === 'kiro'
&& cleanString(state?.contributionAdapterId).toLowerCase() === 'kiro-builder-id';
}
async function executeKiroUploadCredential(state = {}) {
const nodeId = String(state?.nodeId || 'kiro-upload-credential').trim();
const currentState = await getState();
try {
if (shouldUseContributionUpload(currentState)) {
await applyRuntimeState(currentState, {
session: {
currentStage: 'upload',
lastError: '',
lastWarning: '',
},
upload: {
targetId: 'contribution',
status: 'uploading',
error: '',
},
});
await log('步骤 9:正在上传 Builder ID 到贡献池...', 'info', nodeId);
const contributionResult = await maybeSubmitFlowContribution(currentState, {
nodeId,
trigger: 'kiro-step-9',
});
if (!contributionResult?.ok || contributionResult?.skipped) {
throw new Error(contributionResult?.message || 'Kiro 贡献上传失败。');
}
const uploadedAt = Date.now();
const payload = await applyRuntimeState(currentState, {
session: {
currentStage: 'upload',
lastError: '',
},
upload: {
targetId: 'contribution',
status: 'uploaded',
error: '',
credentialId: contributionResult.contributionId || '',
lastMessage: contributionResult.message || '贡献上传成功',
lastUploadedAt: uploadedAt,
},
});
await log(`步骤 9:贡献上传完成,状态:${contributionResult.message || '贡献上传成功'}`, 'ok', nodeId);
await completeNodeFromBackground(nodeId, payload);
return;
}
const targetId = resolveKiroTargetId(currentState);
const targetConfig = resolveKiroTargetConfig(currentState, targetId);
const baseUrl = normalizeKiroRsBaseUrl(targetConfig.baseUrl);
const apiKey = String(targetConfig.apiKey || '');
if (!apiKey) {
throw new Error('缺少 kiro.rs API Key。');
}
const uploadInput = buildUploadPayload(currentState);
const machineId = await buildMachineId(uploadInput.refreshToken);
await applyRuntimeState(currentState, {
session: {
currentStage: 'upload',
lastError: '',
lastWarning: '',
},
upload: {
targetId,
status: 'uploading',
error: '',
},
});
await log('步骤 9:正在上传 Builder ID 凭据到 kiro.rs...', 'info', nodeId);
const connection = await checkKiroRsConnection(baseUrl, apiKey, fetchImpl);
if (!connection.ok) {
throw new Error(connection.message);
}
const uploadResult = await uploadBuilderIdCredential(baseUrl, apiKey, {
refreshToken: uploadInput.refreshToken,
profileArn: uploadInput.profileArn,
authMethod: uploadInput.authMethod,
clientId: uploadInput.clientId,
clientSecret: uploadInput.clientSecret,
region: uploadInput.region,
authRegion: uploadInput.authRegion,
apiRegion: uploadInput.apiRegion,
machineId,
email: uploadInput.email,
...(uploadInput.proxyUrl ? { proxyUrl: uploadInput.proxyUrl } : {}),
...(uploadInput.proxyUsername ? { proxyUsername: uploadInput.proxyUsername } : {}),
...(uploadInput.proxyPassword ? { proxyPassword: uploadInput.proxyPassword } : {}),
}, fetchImpl);
const uploadedAt = Date.now();
const payload = await applyRuntimeState(currentState, {
session: {
currentStage: 'upload',
lastError: '',
},
upload: {
targetId,
status: 'uploaded',
error: '',
credentialId: uploadResult.credentialId,
lastMessage: uploadResult.message || '上传成功',
lastUploadedAt: uploadedAt,
},
});
await log(`步骤 9:kiro.rs 上传完成,状态:${uploadResult.message || '上传成功'}`, 'ok', nodeId);
await completeNodeFromBackground(nodeId, payload);
} catch (error) {
const message = getErrorMessage(error);
await persistFailure(currentState, message);
throw error;
}
}
return {
executeKiroUploadCredential,
};
}
return {
buildKiroRsPayload: buildUploadPayload,
buildMachineId,
checkKiroRsConnection,
createKiroRsPublisher,
normalizeKiroRsBaseUrl,
normalizeKiroUploadMessage,
uploadBuilderIdCredential,
};
});
File diff suppressed because it is too large Load Diff
+424
View File
@@ -0,0 +1,424 @@
(function attachBackgroundKiroState(root, factory) {
root.MultiPageBackgroundKiroState = factory();
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundKiroStateModule() {
const DEFAULT_TARGET_ID = 'kiro-rs';
const DEFAULT_REGION = 'us-east-1';
const FLAT_FIELD_DEFINITIONS = Object.freeze([]);
const FLAT_FIELD_KEYS = Object.freeze([]);
function isPlainObject(value) {
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}
function cloneValue(value) {
if (Array.isArray(value)) {
return value.map((entry) => cloneValue(entry));
}
if (isPlainObject(value)) {
return Object.fromEntries(
Object.entries(value).map(([key, entryValue]) => [key, cloneValue(entryValue)])
);
}
return value;
}
function deepMerge(baseValue, patchValue) {
if (Array.isArray(patchValue)) {
return patchValue.map((entry) => cloneValue(entry));
}
if (!isPlainObject(patchValue)) {
return patchValue === undefined ? cloneValue(baseValue) : patchValue;
}
const baseObject = isPlainObject(baseValue) ? baseValue : {};
const next = {
...cloneValue(baseObject),
};
Object.entries(patchValue).forEach(([key, value]) => {
next[key] = deepMerge(baseObject[key], value);
});
return next;
}
function normalizeString(value = '', fallback = '') {
const normalized = String(value ?? '').trim();
return normalized || fallback;
}
function normalizeInteger(value, fallback = 0) {
const numeric = Math.floor(Number(value));
return Number.isInteger(numeric) ? numeric : fallback;
}
function normalizeNullableInteger(value, fallback = null) {
if (value === null || value === undefined || value === '') {
return fallback;
}
const numeric = Math.floor(Number(value));
return Number.isInteger(numeric) ? numeric : fallback;
}
function normalizeNullableIdentifier(value, fallback = null) {
if (value === null || value === undefined || value === '') {
return fallback;
}
if (typeof value === 'number') {
const numeric = Math.floor(value);
return Number.isInteger(numeric) ? numeric : fallback;
}
const normalized = String(value ?? '').trim();
if (!normalized) {
return fallback;
}
const numeric = Math.floor(Number(normalized));
return Number.isInteger(numeric) && String(numeric) === normalized
? numeric
: normalized;
}
function normalizeBoolean(value, fallback = false) {
if (value === true || value === false) {
return value;
}
return fallback;
}
function buildDefaultRuntimeState() {
return {
session: {
currentStage: '',
registerTabId: null,
desktopTabId: null,
startedAt: 0,
pageState: '',
pageUrl: '',
lastError: '',
lastWarning: '',
},
register: {
email: '',
fullName: '',
verificationRequestedAt: 0,
loginUrl: '',
status: '',
completedAt: 0,
},
webAuth: {
status: '',
completedAt: 0,
hasAccessToken: false,
hasSessionToken: false,
},
desktopAuth: {
region: DEFAULT_REGION,
clientId: '',
clientSecret: '',
clientIdHash: '',
state: '',
codeVerifier: '',
codeChallenge: '',
redirectUri: '',
redirectPort: 0,
authorizeUrl: '',
authorizationCode: '',
accessToken: '',
refreshToken: '',
status: '',
authorizedAt: 0,
otpRequestedAt: 0,
tokenSource: 'desktop_authorization_code_pkce',
},
upload: {
targetId: DEFAULT_TARGET_ID,
status: '',
error: '',
credentialId: null,
lastMessage: '',
lastUploadedAt: 0,
},
};
}
function normalizeRuntimeState(runtimeState = {}) {
const merged = deepMerge(buildDefaultRuntimeState(), runtimeState);
return {
session: {
currentStage: normalizeString(merged.session?.currentStage),
registerTabId: normalizeNullableInteger(merged.session?.registerTabId),
desktopTabId: normalizeNullableInteger(merged.session?.desktopTabId),
startedAt: Math.max(0, normalizeInteger(merged.session?.startedAt)),
pageState: normalizeString(merged.session?.pageState),
pageUrl: normalizeString(merged.session?.pageUrl),
lastError: normalizeString(merged.session?.lastError),
lastWarning: normalizeString(merged.session?.lastWarning),
},
register: {
email: normalizeString(merged.register?.email),
fullName: normalizeString(merged.register?.fullName),
verificationRequestedAt: Math.max(0, normalizeInteger(merged.register?.verificationRequestedAt)),
loginUrl: normalizeString(merged.register?.loginUrl),
status: normalizeString(merged.register?.status),
completedAt: Math.max(0, normalizeInteger(merged.register?.completedAt)),
},
webAuth: {
status: normalizeString(merged.webAuth?.status),
completedAt: Math.max(0, normalizeInteger(merged.webAuth?.completedAt)),
hasAccessToken: normalizeBoolean(merged.webAuth?.hasAccessToken),
hasSessionToken: normalizeBoolean(merged.webAuth?.hasSessionToken),
},
desktopAuth: {
region: normalizeString(merged.desktopAuth?.region, DEFAULT_REGION),
clientId: normalizeString(merged.desktopAuth?.clientId),
clientSecret: normalizeString(merged.desktopAuth?.clientSecret),
clientIdHash: normalizeString(merged.desktopAuth?.clientIdHash),
state: normalizeString(merged.desktopAuth?.state),
codeVerifier: normalizeString(merged.desktopAuth?.codeVerifier),
codeChallenge: normalizeString(merged.desktopAuth?.codeChallenge),
redirectUri: normalizeString(merged.desktopAuth?.redirectUri),
redirectPort: Math.max(0, normalizeInteger(merged.desktopAuth?.redirectPort)),
authorizeUrl: normalizeString(merged.desktopAuth?.authorizeUrl),
authorizationCode: normalizeString(merged.desktopAuth?.authorizationCode),
accessToken: normalizeString(merged.desktopAuth?.accessToken),
refreshToken: normalizeString(merged.desktopAuth?.refreshToken),
status: normalizeString(merged.desktopAuth?.status),
authorizedAt: Math.max(0, normalizeInteger(merged.desktopAuth?.authorizedAt)),
otpRequestedAt: Math.max(0, normalizeInteger(merged.desktopAuth?.otpRequestedAt)),
tokenSource: normalizeString(
merged.desktopAuth?.tokenSource,
'desktop_authorization_code_pkce'
),
},
upload: {
targetId: normalizeString(merged.upload?.targetId, DEFAULT_TARGET_ID),
status: normalizeString(merged.upload?.status),
error: normalizeString(merged.upload?.error),
credentialId: normalizeNullableIdentifier(merged.upload?.credentialId),
lastMessage: normalizeString(merged.upload?.lastMessage),
lastUploadedAt: Math.max(0, normalizeInteger(merged.upload?.lastUploadedAt)),
},
};
}
function buildCanonicalRuntimeStatePatch(state = {}, runtimeState = {}) {
const normalizedRuntimeState = normalizeRuntimeState(runtimeState);
const baseRuntimeState = isPlainObject(state?.runtimeState)
? cloneValue(state.runtimeState)
: {};
const baseFlowState = isPlainObject(baseRuntimeState.flowState)
? cloneValue(baseRuntimeState.flowState)
: {};
return {
...baseRuntimeState,
flowState: {
...baseFlowState,
kiro: normalizedRuntimeState,
},
};
}
function buildRuntimeStateView(runtimeState = {}) {
const normalizedFlowState = isPlainObject(runtimeState?.flowState)
? runtimeState.flowState
: {};
return {
flowState: cloneValue(normalizedFlowState),
flows: cloneValue(normalizedFlowState),
};
}
function buildRuntimeStatePatch(currentState = {}, patch = {}) {
if (!isPlainObject(patch)) {
return {};
}
const nextRuntimeState = normalizeRuntimeState(
deepMerge(ensureRuntimeState(currentState), patch)
);
return {
runtimeState: buildCanonicalRuntimeStatePatch(currentState, nextRuntimeState),
};
}
function ensureRuntimeState(state = {}) {
const runtimeFlowState = isPlainObject(state?.runtimeState?.flowState)
? state.runtimeState.flowState
: {};
if (isPlainObject(runtimeFlowState.kiro)) {
return normalizeRuntimeState(runtimeFlowState.kiro);
}
if (isPlainObject(state?.flowState?.kiro)) {
return normalizeRuntimeState(state.flowState.kiro);
}
return buildDefaultRuntimeState();
}
function projectRuntimeFields() {
return {};
}
function buildStateView(state = {}) {
const nextRuntimeState = ensureRuntimeState(state);
const runtimeState = buildCanonicalRuntimeStatePatch(state, nextRuntimeState);
return {
...state,
runtimeState,
...buildRuntimeStateView(runtimeState),
};
}
function buildSessionStatePatch(currentState = {}, updates = {}) {
const runtimePatch = isPlainObject(updates?.runtimeState?.flowState?.kiro)
? updates.runtimeState.flowState.kiro
: (isPlainObject(updates?.flowState?.kiro)
? updates.flowState.kiro
: null);
if (!runtimePatch) {
return {};
}
return buildRuntimeStatePatch(currentState, runtimePatch);
}
function buildRuntimeResetPatch(currentState = {}, patch = {}) {
return buildRuntimeStatePatch(currentState, patch);
}
function buildStartRegisterResetPatch(currentState = {}) {
const currentRuntimeState = ensureRuntimeState(currentState);
const nextRuntimeState = buildDefaultRuntimeState();
nextRuntimeState.upload.targetId = currentRuntimeState.upload?.targetId || DEFAULT_TARGET_ID;
return {
runtimeState: buildCanonicalRuntimeStatePatch(currentState, nextRuntimeState),
};
}
function buildRegisterOnlyResetPatch(currentState = {}, registerPatch = {}) {
const currentRuntimeState = ensureRuntimeState(currentState);
const nextRuntimeState = normalizeRuntimeState({
...buildDefaultRuntimeState(),
session: {
...currentRuntimeState.session,
currentStage: 'register',
desktopTabId: null,
pageState: '',
pageUrl: '',
lastError: '',
lastWarning: '',
},
register: {
...currentRuntimeState.register,
completedAt: 0,
status: '',
...registerPatch,
},
upload: {
...buildDefaultRuntimeState().upload,
targetId: currentRuntimeState.upload?.targetId || DEFAULT_TARGET_ID,
},
});
return {
runtimeState: buildCanonicalRuntimeStatePatch(currentState, nextRuntimeState),
};
}
function buildDesktopResetPatch(currentState = {}) {
const currentRuntimeState = ensureRuntimeState(currentState);
const nextRuntimeState = normalizeRuntimeState({
...currentRuntimeState,
session: {
...currentRuntimeState.session,
currentStage: 'desktop-authorize',
desktopTabId: null,
pageState: '',
pageUrl: '',
lastError: '',
lastWarning: '',
},
desktopAuth: buildDefaultRuntimeState().desktopAuth,
upload: {
...buildDefaultRuntimeState().upload,
targetId: currentRuntimeState.upload?.targetId || DEFAULT_TARGET_ID,
},
});
return {
runtimeState: buildCanonicalRuntimeStatePatch(currentState, nextRuntimeState),
};
}
function buildUploadResetPatch(currentState = {}) {
const currentRuntimeState = ensureRuntimeState(currentState);
const nextRuntimeState = normalizeRuntimeState({
...currentRuntimeState,
upload: {
...buildDefaultRuntimeState().upload,
targetId: currentRuntimeState.upload?.targetId || DEFAULT_TARGET_ID,
},
});
return {
runtimeState: buildCanonicalRuntimeStatePatch(currentState, nextRuntimeState),
};
}
function buildDownstreamResetPatch(stepKey = '', currentState = {}) {
switch (normalizeString(stepKey)) {
case 'kiro-open-register-page':
return buildStartRegisterResetPatch(currentState);
case 'kiro-submit-email':
return buildRegisterOnlyResetPatch(currentState, {
email: '',
fullName: '',
verificationRequestedAt: 0,
});
case 'kiro-submit-name':
return buildRegisterOnlyResetPatch(currentState, {
fullName: '',
verificationRequestedAt: 0,
});
case 'kiro-submit-verification-code':
return buildRegisterOnlyResetPatch(currentState, {});
case 'kiro-submit-password':
return buildRegisterOnlyResetPatch(currentState, {});
case 'kiro-complete-register-consent':
return buildDesktopResetPatch(currentState);
case 'kiro-start-desktop-authorize':
return buildDesktopResetPatch(currentState);
case 'kiro-complete-desktop-authorize':
return buildUploadResetPatch(currentState);
case 'kiro-upload-credential':
return buildUploadResetPatch(currentState);
default:
return {};
}
}
function applyNodeCompletionPayload(currentState = {}, payload = {}) {
return buildSessionStatePatch(currentState, payload);
}
function buildFreshKeepState(currentState = {}) {
const currentRuntimeState = ensureRuntimeState(currentState);
const nextRuntimeState = buildDefaultRuntimeState();
nextRuntimeState.upload.targetId = currentRuntimeState.upload?.targetId || DEFAULT_TARGET_ID;
return {
runtimeState: buildCanonicalRuntimeStatePatch(currentState, nextRuntimeState),
...(Object.prototype.hasOwnProperty.call(currentState, 'targetId')
? { targetId: normalizeString(currentState.targetId, DEFAULT_TARGET_ID).toLowerCase() }
: {}),
};
}
return {
DEFAULT_REGION,
DEFAULT_TARGET_ID,
FLAT_FIELD_DEFINITIONS,
FLAT_FIELD_KEYS,
applyNodeCompletionPayload,
buildDefaultRuntimeState,
buildDownstreamResetPatch,
buildFreshKeepState,
buildRuntimeStatePatch,
buildSessionStatePatch,
buildStateView,
ensureRuntimeState,
projectRuntimeFields,
};
});