function inferSchemaKind(typeName) { if (typeName === 'object') return 'object'; if (typeName === 'array') return 'array'; if (typeName === 'string') return 'string'; if (typeName === 'integer') return 'integer'; if (typeName === 'number') return 'number'; if (typeName === 'boolean') return 'boolean'; if (typeName === 'null') return 'null'; return 'string'; } function convertJsonSchemaToCrankSchema(node, requiredNames) { var schemaNode = node || {}; var typeName = Array.isArray(schemaNode.type) ? schemaNode.type.find(function(value) { return value !== 'null'; }) || 'string' : schemaNode.type || (schemaNode.properties ? 'object' : 'string'); var nullable = Array.isArray(schemaNode.type) && schemaNode.type.indexOf('null') >= 0; var kind = schemaNode.enum ? 'enum' : inferSchemaKind(typeName); var schema = { type: kind, description: schemaNode.description || null, required: false, nullable: nullable, default_value: Object.prototype.hasOwnProperty.call(schemaNode, 'default') ? schemaNode.default : null, fields: {}, items: null, enum_values: schemaNode.enum || [], variants: [], }; if (kind === 'object') { var requiredSet = new Set(schemaNode.required || requiredNames || []); Object.keys(schemaNode.properties || {}).forEach(function(fieldName) { var field = convertJsonSchemaToCrankSchema(schemaNode.properties[fieldName], []); field.required = requiredSet.has(fieldName); schema.fields[fieldName] = field; }); } if (kind === 'array' && schemaNode.items) { schema.items = convertJsonSchemaToCrankSchema(schemaNode.items, []); } return schema; } function mappingRootForProtocol(protocol) { return '$.request.body'; } function normalizeInputSource(path) { if (!path) return '$.mcp'; if (path === '$') return '$.mcp'; if (path.indexOf('$.mcp') === 0) return path; if (path.indexOf('$.input') === 0) return '$.mcp' + path.slice('$.input'.length); return '$.mcp.' + path.replace(/^\$\./, ''); } function normalizeOutputSource(path) { if (!path) return '$.response.body'; if (path.indexOf('$.') === 0) return path; return '$.' + path.replace(/^\$\./, ''); } function buildMappingSet(rawValue, mode) { var value = rawValue || {}; var root = mappingRootForProtocol(wizardProtocol); var rules = []; Object.keys(value).forEach(function(target) { var source = value[target]; if (mode === 'input') { rules.push({ source: normalizeInputSource(source), target: root + '.' + target, }); return; } rules.push({ source: normalizeOutputSource(source), target: '$.output.' + target, }); }); return { rules: rules }; } function parseExecutionConfig(text) { var value = parseStructuredText(text); var retry = value.retry || {}; var headers = value.headers && typeof value.headers === 'object' ? value.headers : {}; var selectedUpstream = currentUpstream(); if (!selectedUpstream && wizardMode !== 'edit') { throw new Error(tKey('wizard.error.save_upstream_first')); } var authProfileRef = selectedUpstream && selectedUpstream.authProfileId ? selectedUpstream.authProfileId : (value.auth && value.auth.profile ? value.auth.profile : null); var config = { timeout_ms: Number(value.timeout_ms || 10000), retry_policy: retry && retry.max_attempts ? { max_attempts: Number(retry.max_attempts) } : null, auth_profile_ref: authProfileRef, headers: headers, protocol_options: null, streaming: null, }; return config; } function currentUpstream() { var selected = upstreams.find(function(item) { return item.id === selectedUpstreamId; }); if (selected) return selected; var customName = textValue('new-upstream-name'); var customUrl = textValue('new-upstream-url'); if (!customUrl) return null; var authMode = textValue('new-upstream-auth-mode') || 'none'; var authProfileId = authMode === 'existing' ? textValue('new-upstream-auth-profile') : null; var authProfile = authProfileById(authProfileId); return { id: 'custom', name: customName || 'custom-upstream', url: customUrl, staticHeaders: textValue('new-upstream-static-headers') || '{\n}', authMode: authMode, authProfileId: authProfileId || null, authProfileName: authProfile ? authProfile.name : '', authKind: authProfile ? authProfile.kind : null, }; } function joinUrl(baseUrl, path) { if (!baseUrl) return path || ''; if (!path) return baseUrl; return baseUrl.replace(/\/+$/, '') + '/' + path.replace(/^\/+/, ''); } function parseHeaderMap(text) { if (!text || !text.trim()) return {}; var value = parseStructuredText(text); return value && typeof value === 'object' ? value : {}; } function buildTarget() { var upstream = currentUpstream(); if (!upstream || !upstream.url) { throw new Error(tKey('wizard.error.select_upstream')); } var pathTemplate = textValue('endpoint-path') || '/'; var activeMethod = document.querySelector('.method-card.active'); return { kind: 'rest', base_url: upstream.url, method: activeMethod ? activeMethod.dataset.method : 'POST', path_template: pathTemplate, static_headers: parseHeaderMap(upstream.staticHeaders), }; } function crankSchemaToJsonSchema(schema) { var result = {}; var typeName = schema.type === 'enum' ? 'string' : schema.type; result.type = schema.nullable ? [typeName, 'null'] : typeName; if (schema.description) result.description = schema.description; if (schema.default_value !== null && schema.default_value !== undefined) result.default = schema.default_value; if (schema.enum_values && schema.enum_values.length) result.enum = schema.enum_values.slice(); if (schema.type === 'object') { result.type = schema.nullable ? ['object', 'null'] : 'object'; result.properties = {}; var required = []; Object.keys(schema.fields || {}).forEach(function(fieldName) { var field = schema.fields[fieldName]; result.properties[fieldName] = crankSchemaToJsonSchema(field); if (field.required) required.push(fieldName); }); if (required.length) result.required = required; result.additionalProperties = false; } if (schema.type === 'array' && schema.items) { result.items = crankSchemaToJsonSchema(schema.items); } return result; } function mappingSetToEditorValue(mappingSet, mode, protocol) { var rules = mappingSet && mappingSet.rules ? mappingSet.rules : []; var object = {}; rules.forEach(function(rule) { if (mode === 'input') { var key = rule.target.replace(mappingRootForProtocol(protocol) + '.', ''); object[key] = rule.source.replace('$.mcp.', '$.input.'); return; } var outputKey = rule.target.replace('$.output.', ''); object[outputKey] = rule.source; }); return window.jsyaml ? window.jsyaml.dump(object, { lineWidth: -1 }) : JSON.stringify(object, null, 2); } function executionConfigToEditorValue(config) { var value = { timeout_ms: config.timeout_ms, }; if (config.retry_policy) { value.retry = { max_attempts: config.retry_policy.max_attempts }; } if (config.auth_profile_ref) { value.auth = { profile: config.auth_profile_ref }; } if (config.headers && Object.keys(config.headers).length) { value.headers = config.headers; } return window.jsyaml ? window.jsyaml.dump(value, { lineWidth: -1 }) : JSON.stringify(value, null, 2); } function prefillUpstream(baseUrl, headers, authProfileRef) { var known = upstreams.find(function(item) { return item.url === baseUrl && (item.authProfileId || null) === (authProfileRef || null); }); if (known) { pickUpstream(known.id); return; } selectedUpstreamId = null; var trigger = document.getElementById('upstream-new-trigger'); var form = document.getElementById('upstream-new-form'); if (trigger) trigger.classList.add('active'); if (form) form.hidden = false; setValue('new-upstream-name', 'imported-upstream'); setValue('new-upstream-url', baseUrl); setValue('new-upstream-static-headers', headers && Object.keys(headers).length ? JSON.stringify(headers, null, 2) : '{\n}'); setValue('new-upstream-auth-mode', authProfileRef ? 'existing' : 'none'); setValue('new-upstream-auth-profile', authProfileRef || ''); updateUpstreamAuthUi(); var valueEl = document.getElementById('upstream-combobox-value'); if (valueEl) { valueEl.innerHTML = ''; valueEl.appendChild(buildUpstreamTriggerContent('imported-upstream', baseUrl)); } } function prefillWizardFromEdit(detail, versionDocument) { if (!detail || !versionDocument) return; setEditModePresentation(); selectProtocol(detail.protocol); var target = versionDocument.target || {}; if (target.kind === 'rest') { prefillUpstream(target.base_url, target.static_headers, versionDocument.execution_config ? versionDocument.execution_config.auth_profile_ref : null); setValue('endpoint-path', target.path_template); document.querySelectorAll('.method-card').forEach(function(card) { card.classList.toggle('active', card.dataset.method === target.method); }); } setValue('tool-name', detail.name); setValue('tool-display-name', detail.display_name); setValue('tool-title', versionDocument.tool_description ? versionDocument.tool_description.title : detail.display_name); setValue('tool-description', versionDocument.tool_description ? versionDocument.tool_description.description : ''); setValue('tool-input-schema', JSON.stringify(crankSchemaToJsonSchema(versionDocument.input_schema), null, 2)); setValue('tool-output-schema', JSON.stringify(crankSchemaToJsonSchema(versionDocument.output_schema), null, 2)); setValue('tool-input-mapping', mappingSetToEditorValue(versionDocument.input_mapping, 'input', detail.protocol)); setValue('tool-output-mapping', mappingSetToEditorValue(versionDocument.output_mapping, 'output', detail.protocol)); setValue('tool-exec-config', executionConfigToEditorValue(versionDocument.execution_config)); var toolNameInput = document.getElementById('tool-name'); if (toolNameInput) toolNameInput.disabled = true; updateWizardProtocolVisibility(); }