Feat: init mcp server

This commit is contained in:
AllenWriter
2025-05-24 14:02:31 +08:00
parent 1cd1b13cbc
commit 47398016ad
24 changed files with 2053 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
node_modules/
+1274
View File
File diff suppressed because it is too large Load Diff
+23
View File
@@ -0,0 +1,23 @@
{
"name": "dify-6c0370d8-mcp",
"version": "1.0.0",
"type": "module",
"description": "MCP server generated for the dify-6c0370d8 subdomain from Mintlify",
"engines": {
"node": ">=18.0.0"
},
"main": "src/index.js",
"scripts": {
"start": "node src/index.js"
},
"author": "Mintlify",
"dependencies": {
"@mintlify/openapi-types": "^0.0.0",
"@mintlify/validation": "^0.1.320",
"@modelcontextprotocol/sdk": "^1.6.1",
"axios": "^1.8.1",
"dashify": "^2.0.0",
"js-yaml": "^4.1.0",
"trieve-ts-sdk": "^0.0.62"
}
}
+2
View File
@@ -0,0 +1,2 @@
export declare const SERVER_NAME: string;
export declare const SERVER_VERSION: string;
+2
View File
@@ -0,0 +1,2 @@
export const SERVER_NAME = 'mintlify';
export const SERVER_VERSION = '1.0.0';
+2
View File
@@ -0,0 +1,2 @@
export declare const SUBDOMAIN: Readonly<string>;
export declare const SERVER_URL: Readonly<string>;
+3
View File
@@ -0,0 +1,3 @@
// read-only
export const SUBDOMAIN = 'dify-6c0370d8';
export const SERVER_URL = 'https://leaves.mintlify.com';
+2
View File
@@ -0,0 +1,2 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
export declare function connectServer(server: McpServer): Promise<void>;
+17
View File
@@ -0,0 +1,17 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
export function connectServer(server) {
return __awaiter(this, void 0, void 0, function* () {
const transport = new StdioServerTransport();
yield server.connect(transport);
console.error('MCP Server running on stdio');
});
}
+1
View File
@@ -0,0 +1 @@
export {};
+26
View File
@@ -0,0 +1,26 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { connectServer } from './connect.js';
import { initialize } from './initialize.js';
import { createSearchTool } from './search.js';
import { createTools } from './tools/index.js';
function main() {
return __awaiter(this, void 0, void 0, function* () {
const server = initialize();
const existingTools = new Set();
yield createSearchTool(server);
yield createTools(server, existingTools);
yield connectServer(server);
});
}
main().catch((error) => {
console.error('Fatal error in trying to initialize MCP server: ', error);
process.exit(1);
});
+2
View File
@@ -0,0 +1,2 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
export declare function initialize(): McpServer;
+10
View File
@@ -0,0 +1,10 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { SERVER_NAME, SERVER_VERSION } from '../settings.js';
export function initialize() {
console.error('Initializing MCP Server...');
const server = new McpServer({
name: SERVER_NAME,
version: SERVER_VERSION,
});
return server;
}
+4
View File
@@ -0,0 +1,4 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { InitializationConfiguration } from './types.js';
export declare function fetchSearchConfigurationAndTools(subdomain: string): Promise<InitializationConfiguration>;
export declare function createSearchTool(server: McpServer): Promise<void>;
+81
View File
@@ -0,0 +1,81 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import axios from 'axios';
import { TrieveSDK } from 'trieve-ts-sdk';
import { z } from 'zod';
import { SUBDOMAIN } from './config.readonly.js';
import { SERVER_URL } from './config.readonly.js';
import { formatErr, throwOnAxiosError } from './utils.js';
const DEFAULT_BASE_URL = 'https://api.mintlifytrieve.com';
export function fetchSearchConfigurationAndTools(subdomain) {
return __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios.get(`${SERVER_URL}/api/mcp/config/${subdomain}`, {
validateStatus() {
return true;
},
});
throwOnAxiosError(response, 'Failed to fetch MCP config');
return response.data;
}
catch (err) {
throw new Error(formatErr(err).replace('Request failed with status code 404', `${subdomain} not found`));
}
});
}
function search(query, config) {
return __awaiter(this, void 0, void 0, function* () {
const trieve = new TrieveSDK({
apiKey: config.trieveApiKey,
datasetId: config.trieveDatasetId,
baseUrl: DEFAULT_BASE_URL,
});
const data = yield trieve.autocomplete({
page_size: 10,
query,
search_type: 'fulltext',
extend_results: true,
score_threshold: 1,
});
if (data.chunks === undefined || data.chunks.length === 0) {
throw new Error('No results found');
}
return data.chunks.map((result) => {
const { chunk } = result;
// TODO: Append custom domain to the link
return {
title: chunk.metadata.title,
content: chunk.chunk_html,
link: chunk.link,
};
});
});
}
export function createSearchTool(server) {
return __awaiter(this, void 0, void 0, function* () {
const config = yield fetchSearchConfigurationAndTools(SUBDOMAIN);
server.tool('search', `Search across the ${config.name} documentation to fetch relevant context for a given query`, {
query: z.string(),
}, (_a) => __awaiter(this, [_a], void 0, function* ({ query }) {
const results = yield search(query, config);
const content = results.map((result) => {
const { title, content, link } = result;
const text = `Title: ${title}\nContent: ${content}\nLink: ${link}`;
return {
type: 'text',
text,
};
});
return {
content,
};
}));
});
}
+8
View File
@@ -0,0 +1,8 @@
[
{
"tool": {
"name": "search",
"description": "Search across the Dify Docs documentation to fetch relevant context for a given query"
}
}
]
+23
View File
@@ -0,0 +1,23 @@
import { OpenAPI } from '@mintlify/openapi-types';
import { HttpMethod } from '@mintlify/validation';
import { Endpoint } from '@mintlify/validation';
import { DataSchemaArray } from '@mintlify/validation';
import { Tool } from '@modelcontextprotocol/sdk/types.js';
import { ServerParams, ToolWithEndpoint } from '../types.js';
import { SimpleRecord } from '../utils.js';
export declare function convertStrToTitle(str: string): string;
export declare function findNextIteration(set: Set<string>, str: string): number;
export declare function getMcpEnabledEndpointsFromOpenApiSpec(spec: OpenAPI.Document): Endpoint<DataSchemaArray>[];
export declare function convertEndpointToTool(endpoint: Endpoint<DataSchemaArray>): Omit<Tool, 'inputSchema'>;
export declare function getMcpToolsAndEndpointsFromOpenApiSpec(spec: OpenAPI.Document): ToolWithEndpoint[];
export declare function getEndpointsFromOpenApi(specification: OpenAPI.Document): Endpoint<DataSchemaArray>[];
export declare function loadEnv(key: string): SimpleRecord;
export declare function convertEndpointToCategorizedZod(envKey: string, endpoint: Endpoint): {
url: string;
method: HttpMethod;
paths: ServerParams;
queries: ServerParams;
body: ServerParams | undefined;
headers: ServerParams;
cookies: ServerParams;
};
+176
View File
@@ -0,0 +1,176 @@
import { OpenApiToEndpointConverter, } from '@mintlify/validation';
import dashify from 'dashify';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { OpenAPIV3 } from 'openapi-types';
import { z } from 'zod';
import { initializeObject } from '../utils.js';
import { dataSchemaArrayToZod, dataSchemaToZod } from './zod.js';
export function convertStrToTitle(str) {
const spacedString = str.replace(/[-_]/g, ' ');
const words = spacedString.split(/(?=[A-Z])|\s+/);
const titleCasedWords = words.map((word) => {
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
});
return titleCasedWords.join(' ');
}
export function findNextIteration(set, str) {
let count = 1;
set.forEach((val) => {
if (val.startsWith(`${str}---`)) {
count = Number(val.replace(`${str}---`, ''));
}
});
return count + 1;
}
export function getMcpEnabledEndpointsFromOpenApiSpec(spec) {
var _a;
const mcpEnabledEndpoints = [];
const isMcpEnabledGloballyInSpec = ((_a = spec['x-mcp']) === null || _a === void 0 ? void 0 : _a.enabled) === true;
const endpoints = getEndpointsFromOpenApi(spec);
if (isMcpEnabledGloballyInSpec) {
const notDisabledEndpoints = endpoints.filter((endpoint) => { var _a; return ((_a = endpoint.xMcp) === null || _a === void 0 ? void 0 : _a.enabled) !== false; });
mcpEnabledEndpoints.push(...notDisabledEndpoints);
}
else {
const enabledEndpoints = endpoints.filter((endpoint) => { var _a; return ((_a = endpoint.xMcp) === null || _a === void 0 ? void 0 : _a.enabled) === true; });
mcpEnabledEndpoints.push(...enabledEndpoints);
}
return mcpEnabledEndpoints;
}
export function convertEndpointToTool(endpoint) {
var _a, _b;
let name;
if ((_a = endpoint.xMcp) === null || _a === void 0 ? void 0 : _a.name) {
name = endpoint.xMcp.name;
}
else if (endpoint.title) {
name = dashify(endpoint.title);
}
else {
name = convertStrToTitle(endpoint.path);
}
let description;
if ((_b = endpoint.xMcp) === null || _b === void 0 ? void 0 : _b.description) {
description = endpoint.xMcp.description;
}
else if (endpoint.description) {
description = endpoint.description;
}
else {
description = `${endpoint.method} ${endpoint.path}`;
}
return {
name,
description,
};
}
export function getMcpToolsAndEndpointsFromOpenApiSpec(spec) {
const endpoints = getMcpEnabledEndpointsFromOpenApiSpec(spec);
const toolsWithEndpoints = [];
endpoints.forEach((endpoint) => {
const tool = convertEndpointToTool(endpoint);
toolsWithEndpoints.push({
tool,
endpoint,
});
});
return toolsWithEndpoints;
}
export function getEndpointsFromOpenApi(specification) {
const endpoints = [];
const paths = specification.paths;
for (const path in paths) {
const pathObj = paths[path];
const httpMethods = Object.values(OpenAPIV3.HttpMethods);
for (const method of httpMethods) {
if (!pathObj || !(method in pathObj)) {
continue;
}
const endpoint = OpenApiToEndpointConverter.convert(specification, path, method, true);
endpoints.push(endpoint);
}
}
return endpoints;
}
export function loadEnv(key) {
var _a;
let envVars = {};
try {
const envPath = path.join(fileURLToPath(import.meta.url), '../../../../', '.env.json');
if (fs.existsSync(envPath)) {
envVars = JSON.parse(fs.readFileSync(envPath).toString());
return (_a = envVars[key]) !== null && _a !== void 0 ? _a : {};
}
}
catch (error) {
// if there's no env, the user will be prompted
// for their auth info at runtime if necessary
// (shouldn't happen either way)
}
return envVars;
}
function convertParameterSection(parameters, paramSection) {
Object.entries(parameters).forEach(([key, value]) => {
const schema = value.schema;
paramSection[key] = dataSchemaArrayToZod(schema);
});
}
function convertParametersAndAddToRelevantParamGroups(parameters, paths, queries, headers, cookies) {
convertParameterSection(parameters.path, paths);
convertParameterSection(parameters.query, queries);
convertParameterSection(parameters.header, headers);
convertParameterSection(parameters.cookie, cookies);
}
function convertSecurityParameterSection(securityParameters, securityParamSection, envVariables, location) {
Object.entries(securityParameters).forEach(([key, value]) => {
let envKeyList = [];
let targetKey = '';
switch (value.type) {
case 'apiKey':
envKeyList = [location, key];
targetKey = 'API_KEY';
break;
case 'http':
envKeyList = [location, key, 'HTTP'];
targetKey = value.scheme;
break;
case 'oauth2':
default:
break;
}
const target = initializeObject(Object.assign({}, envVariables), envKeyList);
if (envKeyList.length && !target[targetKey]) {
securityParamSection[key] = z.string();
}
});
}
function convertSecurityParametersAndAddToRelevantParamGroups(securityParameters, queries, headers, cookies, envVariables) {
convertSecurityParameterSection(securityParameters.query, queries, envVariables, 'query');
convertSecurityParameterSection(securityParameters.header, headers, envVariables, 'header');
convertSecurityParameterSection(securityParameters.cookie, cookies, envVariables, 'cookie');
}
export function convertEndpointToCategorizedZod(envKey, endpoint) {
var _a, _b, _c;
const envVariables = loadEnv(envKey);
const url = `${((_b = (_a = endpoint.servers) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.url) || ''}${endpoint.path}`;
const method = endpoint.method;
const paths = {};
const queries = {};
const headers = {};
const cookies = {};
let body = undefined;
convertParametersAndAddToRelevantParamGroups(endpoint.request.parameters, paths, queries, headers, cookies);
if ((_c = endpoint.request.security[0]) === null || _c === void 0 ? void 0 : _c.parameters) {
convertSecurityParametersAndAddToRelevantParamGroups(endpoint.request.security[0].parameters, queries, headers, cookies, envVariables);
}
const jsonBodySchema = endpoint.request.body['application/json'];
const bodySchemaArray = jsonBodySchema === null || jsonBodySchema === void 0 ? void 0 : jsonBodySchema.schemaArray;
const bodySchema = bodySchemaArray === null || bodySchemaArray === void 0 ? void 0 : bodySchemaArray[0];
if (bodySchema) {
const zodBodySchema = dataSchemaToZod(bodySchema);
body = { body: zodBodySchema };
}
return { url, method, paths, queries, body, headers, cookies };
}
+2
View File
@@ -0,0 +1,2 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
export declare function createTools(server: McpServer, existingTools: Set<string>): Promise<void>;
+138
View File
@@ -0,0 +1,138 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import axios, { isAxiosError } from 'axios';
import dashify from 'dashify';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { convertEndpointToCategorizedZod, convertStrToTitle, findNextIteration, loadEnv, } from './helpers.js';
export function createTools(server, existingTools) {
return __awaiter(this, void 0, void 0, function* () {
const toolsDir = path.join(fileURLToPath(import.meta.url), '..', '..');
let tools = JSON.parse(fs.readFileSync(path.join(toolsDir, 'tools.json'), 'utf-8'));
tools = tools.filter((tool) => tool.endpoint);
tools.forEach(({ uuid, endpoint }) => {
const envVars = loadEnv(uuid);
const { url: urlSchema, method: methodSchema, paths: pathsSchema, queries: queriesSchema, body: bodySchema, headers: headersSchema, cookies: cookiesSchema, } = convertEndpointToCategorizedZod(uuid, endpoint);
const serverArgumentsSchemas = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, pathsSchema), queriesSchema), bodySchema), headersSchema), cookiesSchema);
if (!endpoint.title) {
endpoint.title = `${endpoint.method} ${convertStrToTitle(endpoint.path)}`;
}
if (existingTools.has(endpoint.title)) {
const lastCount = findNextIteration(existingTools, endpoint.title);
endpoint.title = `${endpoint.title}---${lastCount}`;
}
if (endpoint.title.length > 64) {
endpoint.title = endpoint.title.slice(0, -64);
}
existingTools.add(endpoint.title);
server.tool(dashify(endpoint.title), endpoint.description || endpoint.title, serverArgumentsSchemas, (inputArgs) => __awaiter(this, void 0, void 0, function* () {
var _a;
const inputParams = {};
const inputHeaders = {};
const inputCookies = {};
let urlWithPathParams = urlSchema;
let inputBody = undefined;
if ('body' in inputArgs) {
inputBody = inputArgs.body;
delete inputArgs.body;
}
Object.entries(inputArgs).forEach(([key, value]) => {
if (key in pathsSchema) {
urlWithPathParams = urlWithPathParams.replace(`{${key}}`, value);
}
else if (key in queriesSchema) {
inputParams[key] = value;
}
else if (key in headersSchema) {
inputHeaders[key] = value;
}
else if (key in cookiesSchema) {
inputCookies[key] = value;
}
});
if (endpoint.request.security.length > 0) {
const securityParams = (_a = endpoint.request.security[0]) === null || _a === void 0 ? void 0 : _a.parameters;
if (securityParams) {
Object.entries(securityParams.query).forEach(([key, value]) => {
let envKey = '';
if (value.type === 'apiKey') {
envKey = `query_${key}_APIKEY`;
}
else if (value.type === 'http') {
envKey = `query_${key}_HTTP_${value.scheme}`;
}
if (envKey && envKey in envVars) {
inputParams[key] = envVars[envKey];
}
});
Object.entries(securityParams.header).forEach(([key, value]) => {
let envKey = '';
if (value.type === 'apiKey') {
envKey = `header_${key}_APIKEY`;
}
else if (value.type === 'http') {
envKey = `header_${key}_HTTP_${value.scheme}`;
if (value.scheme === 'bearer' && envKey in envVars) {
inputHeaders['Authorization'] = `Bearer ${envVars[envKey]}`;
return;
}
}
if (envKey && envKey in envVars) {
inputHeaders[key] = envVars[envKey];
}
});
Object.entries(securityParams.cookie).forEach(([key, value]) => {
let envKey = '';
if (value.type === 'apiKey') {
envKey = `cookie_${key}_APIKEY`;
}
else if (value.type === 'http') {
envKey = `cookie_${key}_HTTP_${value.scheme}`;
}
if (envKey && envKey in envVars) {
inputCookies[key] = envVars[envKey];
}
});
}
}
try {
const response = yield axios({
url: urlWithPathParams,
method: methodSchema,
params: inputParams,
data: inputBody,
headers: inputHeaders,
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, undefined, 2),
},
],
};
}
catch (error) {
const errMsg = JSON.stringify(error, undefined, 2);
return {
isError: true,
content: [
{
type: 'text',
text: isAxiosError(error) ? `${error.message}\n\n${errMsg}` : errMsg,
},
],
};
}
}));
});
});
}
+6
View File
@@ -0,0 +1,6 @@
import { DataSchema, DataSchemaArray, IncrementalDataSchema, IncrementalDataSchemaArray } from '@mintlify/validation';
import { z } from 'zod';
type SchemaInput = DataSchema | IncrementalDataSchema;
export declare function dataSchemaArrayToZod(schemas: DataSchemaArray | IncrementalDataSchemaArray): z.ZodTypeAny;
export declare function dataSchemaToZod(schema: SchemaInput): z.ZodTypeAny;
export {};
+185
View File
@@ -0,0 +1,185 @@
import { Blob } from 'node:buffer';
import { z } from 'zod';
function panic(error) {
throw error;
}
// WebFile polyfill implementation partly taken from the fetch-blob package:
// https://github.com/node-fetch/fetch-blob/blob/main/file.js - MIT License
const WebFile = class File extends Blob {
constructor(init, name = panic(new TypeError('File constructor requires name argument')), options = {}) {
if (arguments.length < 2) {
throw new TypeError(`Failed to construct 'File': 2 arguments required, but only ${arguments.length} present.`);
}
super(init, options);
this._lastModified = 0;
this._name = '';
// Simulate WebIDL type casting for NaN value in lastModified option.
const lastModified = options.lastModified === undefined ? Date.now() : Number(options.lastModified);
if (!Number.isNaN(lastModified)) {
this._lastModified = lastModified;
}
this._name = String(name);
}
get name() {
return this._name;
}
get lastModified() {
return this._lastModified;
}
get [Symbol.toStringTag]() {
return 'File';
}
static [Symbol.hasInstance](object) {
return (!!object && object instanceof Blob && /^(File)$/.test(String(object[Symbol.toStringTag])));
}
};
const File = typeof global.File === 'undefined' ? WebFile : global.File;
const ANY = z.any();
const ANY_OPT = ANY.optional();
const BOOLEAN = z.boolean();
const BOOLEAN_OPT = BOOLEAN.optional();
const DATE = z.coerce.date();
const DATE_OPT = DATE.optional();
const FILE = z.instanceof(File);
const FILE_OPT = FILE.optional();
const NULL = z.null();
const NULL_OPT = NULL.optional();
const RECORD = z.record(z.any());
const RECORD_WITH_DEFAULT = RECORD.default({});
const RECORD_OPT = RECORD.optional();
const STRING = z.string();
const NUMBER = z.number();
const INTEGER = z.number().int();
export function dataSchemaArrayToZod(schemas) {
const firstSchema = dataSchemaToZod(schemas[0]);
if (!schemas[1]) {
return firstSchema;
}
const secondSchema = dataSchemaToZod(schemas[1]);
const zodSchemas = [firstSchema, secondSchema];
for (const schema of schemas.slice(2)) {
zodSchemas.push(dataSchemaToZod(schema));
}
return z.union(zodSchemas).array();
}
function getEnumSchema(enumList, type) {
const zodSchema = z.enum(enumList.map(String));
if (type === 'string')
return zodSchema;
return zodSchema.transform(Number);
}
export function dataSchemaToZod(schema) {
if (!('type' in schema) || Object.keys(schema).length === 0) {
return schema.required ? ANY : ANY_OPT;
}
switch (schema.type) {
case 'null':
return schema.required ? NULL : NULL_OPT;
case 'boolean':
return schema.required ? BOOLEAN : BOOLEAN_OPT;
case 'enum<string>':
const strEnumSchema = getEnumSchema(schema.enum, 'string');
return schema.required ? strEnumSchema : strEnumSchema.optional();
case 'enum<number>':
case 'enum<integer>':
const numEnumSchema = getEnumSchema(schema.enum, 'number');
return schema.required ? numEnumSchema : numEnumSchema.optional();
case 'file':
return schema.required ? FILE : FILE_OPT;
case 'any':
return schema.required ? ANY : ANY_OPT;
case 'string':
if ('enum' in schema && Array.isArray(schema.enum)) {
return schema.required
? z.enum(schema.enum)
: z.enum(schema.enum).optional();
}
if (schema.format === 'binary') {
return schema.required ? FILE : FILE_OPT;
}
let stringSchema = STRING;
if (schema.minLength !== undefined) {
stringSchema = stringSchema.min(schema.minLength);
}
if (schema.maxLength !== undefined) {
stringSchema = stringSchema.max(schema.maxLength);
}
if (schema.pattern !== undefined) {
stringSchema = stringSchema.regex(new RegExp(schema.pattern));
}
switch (schema.format) {
case 'email':
stringSchema = stringSchema.email();
break;
case 'uri':
case 'url':
stringSchema = stringSchema.url();
break;
case 'uuid':
stringSchema = stringSchema.uuid();
break;
case 'date-time':
return schema.required ? DATE : DATE_OPT;
}
return schema.required ? stringSchema : stringSchema.optional();
case 'number':
case 'integer':
if ('enum' in schema && Array.isArray(schema.enum)) {
const numEnumSchema = getEnumSchema(schema.enum, schema.type);
return schema.required ? numEnumSchema : numEnumSchema.optional();
}
let numberSchema = schema.type === 'integer' ? INTEGER : NUMBER;
if (schema.minimum !== undefined) {
numberSchema = numberSchema.min(schema.minimum);
}
if (schema.maximum !== undefined) {
numberSchema = numberSchema.max(schema.maximum);
}
if (schema.exclusiveMinimum !== undefined && schema.minimum !== undefined) {
numberSchema = numberSchema.gt(schema.minimum);
}
if (schema.exclusiveMaximum !== undefined && schema.maximum !== undefined) {
numberSchema = numberSchema.lt(schema.maximum);
}
return schema.required ? numberSchema : numberSchema.optional();
case 'array':
let itemSchema;
let arraySchema = z.any().array();
if (Array.isArray(schema.items)) {
itemSchema = dataSchemaArrayToZod(schema.items);
if (schema.items.length > 1) {
arraySchema = itemSchema;
}
else {
arraySchema = itemSchema.array();
}
}
else {
itemSchema = dataSchemaToZod(schema.items);
arraySchema = itemSchema.array();
}
if (schema.minItems !== undefined) {
arraySchema = arraySchema.min(schema.minItems);
}
if (schema.maxItems !== undefined) {
arraySchema = arraySchema.max(schema.maxItems);
}
return schema.required ? arraySchema : arraySchema.optional();
case 'object':
const shape = {};
const requiredProperties = schema.requiredProperties;
const requiredPropertiesSet = new Set(requiredProperties !== null && requiredProperties !== void 0 ? requiredProperties : []);
for (const [key, propSchema] of Object.entries(schema.properties)) {
const zodPropSchema = Array.isArray(propSchema)
? dataSchemaArrayToZod(propSchema)
: dataSchemaToZod(propSchema);
shape[key] = requiredPropertiesSet.has(key) ? zodPropSchema : zodPropSchema.optional();
}
if (Object.keys(shape).length === 0) {
return schema.required ? RECORD_WITH_DEFAULT : RECORD_OPT;
}
return schema.required ? z.object(shape) : z.object(shape).optional();
default:
return ANY;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { OpenAPI } from '@mintlify/openapi-types';
import { AxiosResponse } from 'axios';
export type NestedRecord = string | {
[key: string]: NestedRecord;
};
export type SimpleRecord = Record<string, NestedRecord>;
export declare function initializeObject(obj: SimpleRecord, path: string[]): SimpleRecord;
export declare function getFileId(spec: OpenAPI.Document, index: number): string | number;
export declare function throwOnAxiosError(response: AxiosResponse<any, any>, errMsg: string): void;
export declare function formatErr(err: unknown): any;
+55
View File
@@ -0,0 +1,55 @@
import axios from 'axios';
export function initializeObject(obj, path) {
let current = obj;
for (const key of path) {
if (!current[key] || typeof current[key] !== 'object') {
current[key] = {};
}
current = current[key];
}
return current;
}
export function getFileId(spec, index) {
var _a;
return ((_a = spec.info) === null || _a === void 0 ? void 0 : _a.title) && spec.info.version
? `${spec.info.title} - ${spec.info.version}`
: index;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function throwOnAxiosError(response, errMsg) {
var _a, _b;
if (response.status !== 200) {
if (((_a = response.headers['content-type']) === null || _a === void 0 ? void 0 : _a.includes('application/json')) && ((_b = response.data) === null || _b === void 0 ? void 0 : _b.error)) {
throw new Error(`${errMsg}: ${response.data.error}`);
}
else {
throw new Error(`${errMsg}: ${response.status} ${response.statusText || ''}`);
}
}
if (!response.data) {
throw new Error(`${errMsg}: ${response.status} ${response.statusText}`);
}
}
export function formatErr(err) {
var _a, _b;
if (axios.isAxiosError(err)) {
if (err.message) {
return err.message;
}
else if (err.response) {
return (_b = (_a = err.response.data) === null || _a === void 0 ? void 0 : _a.error) !== null && _b !== void 0 ? _b : `${err.response.status} ${err.response.statusText}`;
}
else if (err.request) {
return 'No response received from server';
}
else {
err = 'An unknown error occurred';
}
}
else if (err instanceof Error) {
return err.message;
}
else {
return JSON.stringify(err, undefined, 2);
}
}