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'; } var REQUEST_MAPPING_TARGET_PREFIXES = [ 'path', 'query', 'headers', '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 normalizeInputTarget(target) { if (!target) return mappingRootForProtocol(wizardProtocol); if (target.indexOf('$.request.') === 0) return target; if (target.indexOf('request.') === 0) return '$.' + target; var normalized = target.replace(/^\$\./, ''); var prefix = normalized.split('.')[0]; if (REQUEST_MAPPING_TARGET_PREFIXES.indexOf(prefix) >= 0) { return '$.request.' + normalized; } return mappingRootForProtocol(wizardProtocol) + '.' + normalized; } function normalizeOutputSource(path) { if (!path) return '$.response.body'; if (path.indexOf('$.') === 0) return path; return '$.' + path.replace(/^\$\./, ''); } function normalizeOutputTarget(target) { if (!target) return '$.output'; if (target.indexOf('$.output') === 0) return target; if (target.indexOf('output') === 0) return '$.' + target; return '$.output.' + target.replace(/^\$\./, ''); } function currentOperationSnapshot() { return wizardCurrentVersion && wizardCurrentVersion.snapshot ? wizardCurrentVersion.snapshot : wizardCurrentVersion; } function existingMappingRuleByTarget(mode, target) { var snapshot = currentOperationSnapshot(); var mapping = mode === 'input' ? snapshot && snapshot.input_mapping : snapshot && snapshot.output_mapping; var rules = mapping && Array.isArray(mapping.rules) ? mapping.rules : []; return rules.find(function(rule) { return rule.target === target; }) || null; } function preserveMappingRuleMetadata(rule, existingRule) { if (!existingRule) { rule.required = true; return rule; } rule.required = existingRule.required !== undefined ? existingRule.required : true; ['default_value', 'transform', 'condition', 'notes'].forEach(function(field) { if (existingRule[field] !== undefined && existingRule[field] !== null) { rule[field] = existingRule[field]; } }); return rule; } function buildMappingSet(rawValue, mode) { var value = rawValue || {}; var rules = []; Object.keys(value).forEach(function(target) { var source = value[target]; if (mode === 'input') { var inputTarget = normalizeInputTarget(target); rules.push(preserveMappingRuleMetadata({ source: normalizeInputSource(source), target: inputTarget, }, existingMappingRuleByTarget(mode, inputTarget))); return; } var outputTarget = normalizeOutputTarget(target); rules.push(preserveMappingRuleMetadata({ source: normalizeOutputSource(source), target: outputTarget, }, existingMappingRuleByTarget(mode, outputTarget))); }); 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 exampleValueForSchema(schema) { if (!schema) return {}; if (schema.default_value !== null && schema.default_value !== undefined) { return schema.default_value; } if (schema.enum_values && schema.enum_values.length) { return schema.enum_values[0]; } if (schema.type === 'object') { var object = {}; Object.keys(schema.fields || {}).forEach(function(fieldName) { object[fieldName] = exampleValueForSchema(schema.fields[fieldName]); }); return object; } if (schema.type === 'array') { return [exampleValueForSchema(schema.items)]; } if (schema.type === 'integer') return 1; if (schema.type === 'number') return 1.23; if (schema.type === 'boolean') return true; if (schema.type === 'null') return null; return 'string'; } function firstToolExampleValue(toolDescription, fieldName) { var examples = toolDescription && Array.isArray(toolDescription.examples) ? toolDescription.examples : []; if (!examples.length) return null; var value = examples[0] && examples[0][fieldName]; return value === undefined ? null : value; } function prefillWizardSamples(snapshot) { var state = snapshot.wizard_state || {}; var inputExample = firstToolExampleValue(snapshot.tool_description, 'input'); var inputSample = state.input_sample !== undefined && state.input_sample !== null ? state.input_sample : inputExample !== null ? inputExample : exampleValueForSchema(snapshot.input_schema); var outputSample = state.output_sample !== undefined && state.output_sample !== null ? state.output_sample : exampleValueForSchema(snapshot.output_schema); var testInput = state.test_input !== undefined && state.test_input !== null ? state.test_input : inputSample; setValue('wizard-input-sample', JSON.stringify(inputSample, null, 2)); setValue('wizard-test-input', JSON.stringify(testInput, null, 2)); setValue('wizard-output-sample', JSON.stringify(outputSample, null, 2)); } 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.indexOf(mappingRootForProtocol(protocol) + '.') === 0 ? rule.target.replace(mappingRootForProtocol(protocol) + '.', '') : rule.target.replace('$.request.', ''); 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 operationSnapshot(versionDocument) { if (!versionDocument) return {}; return versionDocument.snapshot || versionDocument; } 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; var snapshot = operationSnapshot(versionDocument); setEditModePresentation(); selectProtocol(snapshot.protocol || detail.protocol); var target = snapshot.target || {}; if (target.kind === 'rest') { prefillUpstream(target.base_url, target.static_headers, snapshot.execution_config ? snapshot.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', snapshot.name || detail.name); setValue('tool-display-name', snapshot.display_name || detail.display_name); setValue('tool-title', snapshot.tool_description ? snapshot.tool_description.title : (snapshot.display_name || detail.display_name)); setValue('tool-description', snapshot.tool_description ? snapshot.tool_description.description : ''); setValue('tool-input-schema', JSON.stringify(crankSchemaToJsonSchema(snapshot.input_schema), null, 2)); setValue('tool-output-schema', JSON.stringify(crankSchemaToJsonSchema(snapshot.output_schema), null, 2)); setValue('tool-input-mapping', mappingSetToEditorValue(snapshot.input_mapping, 'input', snapshot.protocol || detail.protocol)); setValue('tool-output-mapping', mappingSetToEditorValue(snapshot.output_mapping, 'output', snapshot.protocol || detail.protocol)); setValue('tool-exec-config', executionConfigToEditorValue(snapshot.execution_config || {})); prefillWizardSamples(snapshot); var toolNameInput = document.getElementById('tool-name'); if (toolNameInput) toolNameInput.disabled = true; updateWizardProtocolVisibility(); }