@lobehub/chat-plugin-sdk
Version:
Lobe Chat Plugin SDK, help you to build an amazing chat plugin for Lobe Chat
332 lines (325 loc) • 13.5 kB
JavaScript
import _typeof from "@babel/runtime/helpers/esm/typeof";
import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _createForOfIteratorHelper from "@babel/runtime/helpers/esm/createForOfIteratorHelper";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import SwaggerParser from '@apidevtools/swagger-parser';
import { convertParametersToJSONSchema } from 'openapi-jsonschema-parameters';
import { pluginApiSchema } from "../schema/manifest";
export var OPENAPI_REQUEST_BODY_KEY = '_requestBody';
export var OpenAPIConvertor = /*#__PURE__*/function () {
function OpenAPIConvertor(openapi) {
var _this = this;
_classCallCheck(this, OpenAPIConvertor);
_defineProperty(this, "openapi", void 0);
_defineProperty(this, "convertOpenAPIToPluginSchema", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
var api, paths, methods, plugins, _i, _Object$entries, _Object$entries$_i, path, operations, _iterator, _step, method, operation, parametersSchema, requestBodySchema, parameters, _parameters$required, name, description, plugin, res;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return SwaggerParser.dereference(_this.openapi);
case 2:
api = _context.sent;
paths = api.paths;
methods = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'];
plugins = [];
_i = 0, _Object$entries = Object.entries(paths);
case 7:
if (!(_i < _Object$entries.length)) {
_context.next = 42;
break;
}
_Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), path = _Object$entries$_i[0], operations = _Object$entries$_i[1];
_iterator = _createForOfIteratorHelper(methods);
_context.prev = 10;
_iterator.s();
case 12:
if ((_step = _iterator.n()).done) {
_context.next = 31;
break;
}
method = _step.value;
operation = operations[method];
if (!operation) {
_context.next = 29;
break;
}
parametersSchema = convertParametersToJSONSchema(operation.parameters || []);
requestBodySchema = _this.convertRequestBodyToSchema(operation.requestBody);
parameters = _this.mergeSchemas.apply(_this, _toConsumableArray(Object.values(parametersSchema)));
if (requestBodySchema && requestBodySchema.properties && Object.keys(requestBodySchema.properties).length > 0) {
parameters.properties[OPENAPI_REQUEST_BODY_KEY] = requestBodySchema;
(_parameters$required = parameters.required) === null || _parameters$required === void 0 || _parameters$required.push('_requestBody');
}
// 保留原始逻辑作为备选
name = operation.operationId || "".concat(method.toUpperCase(), " ").concat(path);
description = operation.summary || operation.description || name;
plugin = {
description: description,
name: name,
parameters: parameters
};
res = pluginApiSchema.safeParse(plugin);
if (!res.success) {
_context.next = 28;
break;
}
plugins.push(plugin);
_context.next = 29;
break;
case 28:
throw res.error;
case 29:
_context.next = 12;
break;
case 31:
_context.next = 36;
break;
case 33:
_context.prev = 33;
_context.t0 = _context["catch"](10);
_iterator.e(_context.t0);
case 36:
_context.prev = 36;
_iterator.f();
return _context.finish(36);
case 39:
_i++;
_context.next = 7;
break;
case 42:
return _context.abrupt("return", plugins);
case 43:
case "end":
return _context.stop();
}
}, _callee, null, [[10, 33, 36, 39]]);
})));
_defineProperty(this, "convertAuthToSettingsSchema", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
var rawSettingsSchema,
settingsSchema,
_yield$import,
SwaggerClient,
openAPI,
api,
_i2,
_Object$entries2,
_api$components,
entry,
authSchema,
_ref3,
_ref4,
key,
value,
_args2 = arguments;
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
rawSettingsSchema = _args2.length > 0 && _args2[0] !== undefined ? _args2[0] : {
properties: {},
type: 'object'
};
settingsSchema = rawSettingsSchema; // @ts-ignore
_context2.next = 4;
return import('swagger-client');
case 4:
_yield$import = _context2.sent;
SwaggerClient = _yield$import.default;
_context2.next = 8;
return SwaggerClient.resolve({
spec: _this.openapi
});
case 8:
openAPI = _context2.sent;
api = openAPI.spec;
_i2 = 0, _Object$entries2 = Object.entries(((_api$components = api.components) === null || _api$components === void 0 ? void 0 : _api$components.securitySchemes) || {});
case 11:
if (!(_i2 < _Object$entries2.length)) {
_context2.next = 29;
break;
}
entry = _Object$entries2[_i2];
authSchema = {};
_ref3 = entry, _ref4 = _slicedToArray(_ref3, 2), key = _ref4[0], value = _ref4[1];
_context2.t0 = value.type;
_context2.next = _context2.t0 === 'apiKey' ? 18 : _context2.t0 === 'http' ? 20 : _context2.t0 === 'oauth2' ? 22 : 24;
break;
case 18:
authSchema = {
properties: _defineProperty({}, key, {
description: value.description || "".concat(key, " API Key"),
format: 'password',
title: value.name,
type: 'string'
}),
required: [key],
type: 'object'
};
return _context2.abrupt("break", 24);
case 20:
if (value.scheme === 'basic') {
authSchema = {
properties: _defineProperty({}, key, {
description: 'Basic authentication credentials',
format: 'password',
type: 'string'
}),
required: [key],
type: 'object'
};
} else if (value.scheme === 'bearer') {
authSchema = {
properties: _defineProperty({}, key, {
description: value.description || "".concat(key, " Bearer token"),
format: 'password',
title: key,
type: 'string'
}),
required: [key],
type: 'object'
};
}
return _context2.abrupt("break", 24);
case 22:
authSchema = {
properties: _defineProperty(_defineProperty(_defineProperty({}, "".concat(key, "_clientId"), {
description: 'Client ID for OAuth2',
type: 'string'
}), "".concat(key, "_clientSecret"), {
description: 'Client Secret for OAuth2',
format: 'password',
type: 'string'
}), "".concat(key, "_accessToken"), {
description: 'Access token for OAuth2',
format: 'password',
type: 'string'
}),
required: ["".concat(key, "_clientId"), "".concat(key, "_clientSecret"), "".concat(key, "_accessToken")],
type: 'object'
};
return _context2.abrupt("break", 24);
case 24:
// 合并当前鉴权机制的 schema 到 settingsSchema
Object.assign(settingsSchema.properties, authSchema.properties);
if (authSchema.required) {
settingsSchema.required = _toConsumableArray(new Set([].concat(_toConsumableArray(settingsSchema.required || []), _toConsumableArray(authSchema.required))));
}
case 26:
_i2++;
_context2.next = 11;
break;
case 29:
return _context2.abrupt("return", settingsSchema);
case 30:
case "end":
return _context2.stop();
}
}, _callee2);
})));
this.openapi = openapi;
}
_createClass(OpenAPIConvertor, [{
key: "convertRequestBodyToSchema",
value: function convertRequestBodyToSchema(requestBody) {
if (!requestBody || !requestBody.content) {
return null;
}
var requestBodySchema = {};
// 遍历所有的 content-type
for (var _i3 = 0, _Object$entries3 = Object.entries(requestBody.content); _i3 < _Object$entries3.length; _i3++) {
var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
contentType = _Object$entries3$_i[0],
mediaType = _Object$entries3$_i[1];
if (mediaType.schema) {
// 直接使用已解析的 Schema
var resolvedSchema = this.removeRequiredFields(mediaType.schema);
// 根据不同的 content-type,可以在这里添加特定的处理逻辑
switch (contentType) {
case 'application/json':
{
// 直接使用解析后的 Schema 作为 JSON 的请求体定义
requestBodySchema = resolvedSchema;
break;
}
case 'application/x-www-form-urlencoded':
case 'multipart/form-data':
{
// 这些类型通常用于文件上传和表单数据,可能需要特别处理
requestBodySchema = resolvedSchema;
break;
}
// 其他 MIME 类型...
default:
{
// 如果遇到未知的 content-type,可以选择忽略或抛出错误
console.warn("Unsupported content-type: ".concat(contentType));
break;
}
}
}
}
return requestBodySchema;
}
}, {
key: "removeRequiredFields",
value: function removeRequiredFields(schema) {
if (schema && _typeof(schema) === 'object') {
// 如果是对象类型,遍历它的每个属性
for (var key in schema) {
// eslint-disable-next-line no-prototype-builtins
if (schema.hasOwnProperty(key)) {
var value = schema[key];
// 如果属性是 required 并且值为 true,则删除该属性
if (key === 'required' && value === true) {
delete schema[key];
} else {
// 否则,如果属性是对象或数组,则递归处理
schema[key] = this.removeRequiredFields(value);
}
}
}
} else if (Array.isArray(schema)) {
// 如果是数组类型,遍历每个元素
return schema.map(this.removeRequiredFields.bind(this));
}
return schema;
}
}, {
key: "mergeSchemas",
value: function mergeSchemas() {
var _mergedSchema$require;
// 初始化合并后的 Schema
var mergedSchema = {
properties: {},
required: [],
type: 'object'
};
// 遍历每个参数的 Schema
for (var _len = arguments.length, schemas = new Array(_len), _key = 0; _key < _len; _key++) {
schemas[_key] = arguments[_key];
}
for (var _i4 = 0, _schemas = schemas; _i4 < _schemas.length; _i4++) {
var schema = _schemas[_i4];
if (schema && schema.properties) {
// 合并属性
Object.assign(mergedSchema.properties, schema.properties);
// 合并必需字段
if (Array.isArray(schema.required)) {
mergedSchema.required = _toConsumableArray(new Set([].concat(_toConsumableArray(mergedSchema.required || []), _toConsumableArray(schema.required))));
}
}
}
// 如果没有任何必需字段,则删除 required 属性
if (((_mergedSchema$require = mergedSchema.required) === null || _mergedSchema$require === void 0 ? void 0 : _mergedSchema$require.length) === 0) {
delete mergedSchema.required;
}
return mergedSchema;
}
}]);
return OpenAPIConvertor;
}();