coze-studio/frontend/infra/idl/idl2ts-cli/src/mock-dev.ts

106 lines
3.2 KiB
TypeScript

/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import path from 'path';
import { type ApiConfig } from './types';
let hasShowHint = false;
function requiredWithoutCache(src, onError?) {
let data;
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { Module } = require('module');
try {
// Disable the required cache so that you can change the mock data without restarting the service.
const originCache = Module._cache;
Module._cache = {};
// eslint-disable-next-line security/detect-non-literal-require, @typescript-eslint/no-require-imports
data = require(src);
Module._cache = originCache;
} catch (error) {
console.error(error);
if (onError) {
onError(error);
} else {
console.error(error);
}
}
return data;
}
export function createProxy({
root,
handleResponseData,
}: {
root: string;
handleResponseData?: (service: string, method: string, data: any) => any;
}) {
// eslint-disable-next-line security/detect-non-literal-require, @typescript-eslint/no-require-imports
const apiConfig = require(path.resolve(root, 'api.config.js')) as ApiConfig[];
// eslint-disable-next-line max-params
return async function proxyResWithMock(_, __, req, resp) {
if (!req.headers['x-svc-method']) {
return Promise.resolve();
}
const config = requiredWithoutCache(
path.resolve(root, './api.dev.local.js'),
() => {
if (!hasShowHint) {
console.warn(
'can not find mock config, please run "gen-api" command if you want to mock',
);
hasShowHint = true;
}
},
);
if (
config &&
config.mock.includes(req.headers['x-svc-method'].split('_').join('.'))
) {
const [svc, method] = req.headers['x-svc-method'].split('_');
const target = apiConfig.find(i => i.entries[svc].length > 0);
if (!target) {
return Promise.resolve();
}
const src = path.resolve(
root,
target.output,
target.entries[svc].replace(/\.(thrift|proto)$/, '.mock.js'),
);
const data = requiredWithoutCache(src);
if (data) {
try {
if (resp) {
resp.statusCode = 200;
resp.setHeader('Content-Type', 'application/json');
} else {
console.warn('resp is not defined');
}
const res = await data[svc][method].res(req);
if (handleResponseData) {
return await handleResponseData(svc, method, res);
}
return res;
} catch (error) {
return error;
}
}
}
return Promise.resolve();
};
}