(function attachBackgroundGrokPublisherWebchat2Api(root, factory) { root.MultiPageBackgroundGrokPublisherWebchat2Api = factory(root); })(typeof self !== 'undefined' ? self : globalThis, function createBackgroundGrokPublisherWebchat2ApiModule(root) { const grokStateApi = root?.MultiPageBackgroundGrokState || null; const WEBCHAT2API_INJECT_PATH = '/api/remote-account/inject'; const DEFAULT_SOURCE_ID = 'flowpilot-grok-sso'; const DEFAULT_SOURCE_NAME = 'FlowPilot Grok SSO'; 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 getErrorMessage(error) { return error instanceof Error ? error.message : cleanString(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 readWebchat2ApiResponseMessage(body = {}, fallback = '') { return cleanString( body?.json?.error?.message || body?.json?.error || body?.json?.message || fallback ); } function normalizeWebchat2ApiBaseUrl(value = '') { const rawUrl = cleanString(value); if (!rawUrl) { throw new Error('缺少 webchat2api 地址。'); } const withProtocol = /^https?:\/\//i.test(rawUrl) ? rawUrl : `http://${rawUrl}`; let parsed = null; try { parsed = new URL(withProtocol); } catch (_error) { throw new Error('webchat2api 地址格式无效,请检查配置。'); } if (!/^https?:$/.test(parsed.protocol)) { throw new Error('webchat2api 地址只支持 http 或 https。'); } return parsed.origin; } function buildWebchat2ApiInjectUrl(value = '') { return `${normalizeWebchat2ApiBaseUrl(value)}${WEBCHAT2API_INJECT_PATH}`; } function normalizeWebchat2ApiAdminKey(value = '') { return cleanString(value); } function readGrokRuntime(state = {}) { return grokStateApi?.ensureRuntimeState ? grokStateApi.ensureRuntimeState(state) : (isPlainObject(state?.runtimeState?.flowState?.grok) ? state.runtimeState.flowState.grok : (isPlainObject(state?.flowState?.grok) ? state.flowState.grok : {})); } function buildCanonicalRuntimePatch(currentState = {}, nextRuntimeState = {}) { if (typeof grokStateApi?.buildRuntimeStatePatch === 'function') { return grokStateApi.buildRuntimeStatePatch(currentState, nextRuntimeState); } const baseRuntimeState = isPlainObject(currentState?.runtimeState) ? cloneValue(currentState.runtimeState) : {}; const baseFlowState = isPlainObject(baseRuntimeState.flowState) ? cloneValue(baseRuntimeState.flowState) : {}; return { runtimeState: { ...baseRuntimeState, flowState: { ...baseFlowState, grok: deepMerge(readGrokRuntime(currentState), nextRuntimeState), }, }, }; } function mergeRuntimePatch(currentState = {}, patch = {}) { return buildCanonicalRuntimePatch( currentState, deepMerge(readGrokRuntime(currentState), patch) ); } function resolveGrokWebchat2ApiConfig(state = {}) { const nestedConfig = state?.settingsState?.flows?.grok?.targets?.webchat2api || {}; return { baseUrl: cleanString(nestedConfig.baseUrl || state?.grokWebchat2ApiUrl), apiKey: normalizeWebchat2ApiAdminKey(nestedConfig.apiKey ?? state?.grokWebchat2ApiAdminKey ?? ''), }; } function resolveGrokSsoCookie(state = {}) { const runtimeState = readGrokRuntime(state); return cleanString(runtimeState?.sso?.currentCookie || state?.grokSsoCookie); } function buildGrokSsoInjectPayload(ssoCookie = '') { const normalizedCookie = cleanString(ssoCookie); if (!normalizedCookie) { throw new Error('缺少 Grok SSO Cookie,请先完成步骤 5。'); } return { accounts: [{ token: normalizedCookie, provider: 'grok', type: 'sso', }], strategy: 'merge', source_id: DEFAULT_SOURCE_ID, source_name: DEFAULT_SOURCE_NAME, provider: 'grok', }; } async function uploadGrokSsoToWebchat2Api(baseUrl, apiKey, ssoCookie, fetchImpl) { const endpointUrl = buildWebchat2ApiInjectUrl(baseUrl); const normalizedApiKey = normalizeWebchat2ApiAdminKey(apiKey); if (!normalizedApiKey) { throw new Error('缺少 webchat2api 管理密钥。'); } const response = await fetchImpl(endpointUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', Authorization: `Bearer ${normalizedApiKey}`, }, body: JSON.stringify(buildGrokSsoInjectPayload(ssoCookie)), }); const body = await readResponse(response); if (!response.ok) { const message = readWebchat2ApiResponseMessage(body, response.statusText) || `HTTP ${response.status}`; throw new Error(`webchat2api SSO 上传失败:${message}`); } if (isPlainObject(body.json) && Object.prototype.hasOwnProperty.call(body.json, 'code') && Number(body.json.code) !== 0) { const message = readWebchat2ApiResponseMessage(body, `code=${body.json.code}`); throw new Error(`webchat2api SSO 上传失败:${message}`); } return { endpointUrl, message: readWebchat2ApiResponseMessage(body, '') || '上传成功', raw: body.json, }; } function createGrokWebchat2ApiPublisher(deps = {}) { const { addLog = async () => {}, completeNodeFromBackground, fetchImpl = typeof fetch === 'function' ? fetch.bind(globalThis) : null, getState = async () => ({}), setState = async () => {}, } = deps; if (typeof completeNodeFromBackground !== 'function') { throw new Error('Grok webchat2api publisher requires completeNodeFromBackground.'); } if (typeof fetchImpl !== 'function') { throw new Error('Grok webchat2api 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 = '', targetUrl = '') { const uploadPatch = { status: 'error', uploadedAt: 0, message, }; const normalizedTargetUrl = cleanString(targetUrl); if (normalizedTargetUrl) { uploadPatch.targetUrl = normalizedTargetUrl; } const nextPatch = mergeRuntimePatch(currentState, { session: { lastError: message, }, upload: uploadPatch, }); await setState(nextPatch); } async function executeGrokUploadSsoToWebchat2Api(state = {}) { const nodeId = cleanString(state?.nodeId) || 'grok-upload-sso-to-webchat2api'; const currentState = await getState(); let failureTargetUrl = ''; try { const targetConfig = resolveGrokWebchat2ApiConfig(currentState); const endpointUrl = buildWebchat2ApiInjectUrl(targetConfig.baseUrl); failureTargetUrl = endpointUrl; const apiKey = normalizeWebchat2ApiAdminKey(targetConfig.apiKey); if (!apiKey) { throw new Error('缺少 webchat2api 管理密钥。'); } const ssoCookie = resolveGrokSsoCookie(currentState); if (!ssoCookie) { throw new Error('缺少 Grok SSO Cookie,请先完成步骤 5。'); } await applyRuntimeState(currentState, { session: { lastError: '', }, upload: { status: 'uploading', uploadedAt: 0, message: '', targetUrl: endpointUrl, }, }); await log('步骤 6:正在上传 Grok SSO 到 webchat2api...', 'info', nodeId); const uploadResult = await uploadGrokSsoToWebchat2Api( targetConfig.baseUrl, apiKey, ssoCookie, fetchImpl ); const uploadedAt = Date.now(); const payload = await applyRuntimeState(currentState, { session: { lastError: '', }, upload: { status: 'uploaded', uploadedAt, message: uploadResult.message || '上传成功', targetUrl: uploadResult.endpointUrl, }, }); await log(`步骤 6:Grok SSO 已上传到 webchat2api,状态:${uploadResult.message || '上传成功'}。`, 'ok', nodeId); await completeNodeFromBackground(nodeId, payload); } catch (error) { const message = getErrorMessage(error); await persistFailure(currentState, message, failureTargetUrl); await log(`步骤 6:${message}`, 'error', nodeId); throw error; } } return { executeGrokUploadSsoToWebchat2Api, }; } return { buildGrokSsoInjectPayload, buildWebchat2ApiInjectUrl, createGrokWebchat2ApiPublisher, normalizeWebchat2ApiBaseUrl, uploadGrokSsoToWebchat2Api, }; });