feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
68
frontend/infra/idl/idl2ts-runtime/README.md
Normal file
68
frontend/infra/idl/idl2ts-runtime/README.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# @coze-arch/idl2ts-runtime
|
||||
|
||||
A architecture package for the Coze Studio monorepo
|
||||
|
||||
## Overview
|
||||
|
||||
This package is part of the Coze Studio monorepo and provides architecture functionality. It includes api.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Installation
|
||||
|
||||
Add this package to your `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@coze-arch/idl2ts-runtime": "workspace:*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
rush update
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```typescript
|
||||
import { /* exported functions/components */ } from '@coze-arch/idl2ts-runtime';
|
||||
|
||||
// Example usage
|
||||
// TODO: Add specific usage examples
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Api
|
||||
|
||||
## API Reference
|
||||
|
||||
### Exports
|
||||
|
||||
- `*`
|
||||
- `*`
|
||||
- `type IMeta`
|
||||
|
||||
|
||||
For detailed API documentation, please refer to the TypeScript definitions.
|
||||
|
||||
## Development
|
||||
|
||||
This package is built with:
|
||||
|
||||
- TypeScript
|
||||
- Modern JavaScript
|
||||
- Vitest for testing
|
||||
- ESLint for code quality
|
||||
|
||||
## Contributing
|
||||
|
||||
This package is part of the Coze Studio monorepo. Please follow the monorepo contribution guidelines.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
12
frontend/infra/idl/idl2ts-runtime/config/rush-project.json
Normal file
12
frontend/infra/idl/idl2ts-runtime/config/rush-project.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"operationSettings": [
|
||||
{
|
||||
"operationName": "test:cov",
|
||||
"outputFolderNames": ["coverage"]
|
||||
},
|
||||
{
|
||||
"operationName": "ts-check",
|
||||
"outputFolderNames": ["dist"]
|
||||
}
|
||||
]
|
||||
}
|
||||
15
frontend/infra/idl/idl2ts-runtime/eslint.config.js
Normal file
15
frontend/infra/idl/idl2ts-runtime/eslint.config.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const { defineConfig } = require('@coze-arch/eslint-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
packageRoot: __dirname,
|
||||
preset: 'node',
|
||||
rules: {
|
||||
'@typescript-eslint/naming-convention': 'off',
|
||||
'unicorn/filename-case': 'off',
|
||||
'@coze-arch/no-batch-import-or-export': 'off',
|
||||
'max-statements-per-line': 'off',
|
||||
'max-lines': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@coze-arch/max-line-per-function': 'off',
|
||||
},
|
||||
});
|
||||
28
frontend/infra/idl/idl2ts-runtime/package.json
Normal file
28
frontend/infra/idl/idl2ts-runtime/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@coze-arch/idl2ts-runtime",
|
||||
"version": "0.1.0",
|
||||
"homepage": "",
|
||||
"license": "Apache-2.0",
|
||||
"author": "zhaorujun@bytedance.com",
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "exit 0",
|
||||
"lint": "eslint ./ --cache",
|
||||
"test": "vitest --run --passWithNoTests",
|
||||
"test:cov": "npm run test -- --coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@coze-arch/eslint-config": "workspace:*",
|
||||
"@coze-arch/ts-config": "workspace:*",
|
||||
"@coze-arch/vitest-config": "workspace:*",
|
||||
"@types/node": "^18",
|
||||
"@vitest/coverage-v8": "~3.0.5",
|
||||
"qs": "^6.11.2",
|
||||
"tsx": "^4.19.2",
|
||||
"vitest": "~3.0.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"qs": "^6.11.2"
|
||||
}
|
||||
}
|
||||
|
||||
36
frontend/infra/idl/idl2ts-runtime/src/config-center.ts
Normal file
36
frontend/infra/idl/idl2ts-runtime/src/config-center.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 type { IdlConfig } from './utils';
|
||||
|
||||
class ConfigCenter {
|
||||
private config: Map<string, IdlConfig> = new Map();
|
||||
register(service: string, config: IdlConfig): void {
|
||||
this.config.set(service, config);
|
||||
}
|
||||
getConfig(service: string): IdlConfig | undefined {
|
||||
return this.config.get(service);
|
||||
}
|
||||
}
|
||||
|
||||
export const configCenter = new ConfigCenter();
|
||||
|
||||
export function registerConfig(service: string, config: IdlConfig): void {
|
||||
if (configCenter.getConfig(service)) {
|
||||
console.warn(`${service} api config has already been set,make sure they are the same`);
|
||||
}
|
||||
configCenter.register(service, config);
|
||||
}
|
||||
155
frontend/infra/idl/idl2ts-runtime/src/create-api.ts
Normal file
155
frontend/infra/idl/idl2ts-runtime/src/create-api.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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 { type IOptions, normalizeRequest } from './utils';
|
||||
import type { IMeta, CustomAPIMeta } from './types';
|
||||
|
||||
export interface ApiLike<T, K, O = unknown, B extends boolean = false> {
|
||||
(req: T, option?: O extends object ? IOptions & O : IOptions): Promise<K>;
|
||||
meta: IMeta;
|
||||
/** fork 一份实例,该实例具有可中止请求的能力 */
|
||||
withAbort: () => CancelAbleApi<T, K, O, B>;
|
||||
}
|
||||
|
||||
export interface CancelAbleApi<T, K, O = unknown, B extends boolean = false>
|
||||
extends ApiLike<T, K, O, B> {
|
||||
// 中止请求
|
||||
abort: () => void;
|
||||
// 是否是取消
|
||||
isAborted: () => boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义构建 api 方法
|
||||
* @param meta
|
||||
* @param cancelable
|
||||
* @param useCustom
|
||||
* @returns
|
||||
*/
|
||||
// eslint-disable-next-line max-params
|
||||
export function createAPI<T extends {}, K, O = unknown, B extends boolean = false>(
|
||||
meta: IMeta,
|
||||
cancelable?: B,
|
||||
useCustom = false,
|
||||
customOption?: O extends object ? IOptions & O : IOptions,
|
||||
): B extends false ? ApiLike<T, K, O, B> : CancelAbleApi<T, K, O, B> {
|
||||
let abortController: AbortController | undefined;
|
||||
let pending: undefined | boolean;
|
||||
async function api(
|
||||
req: T,
|
||||
option: O extends object ? IOptions & O : IOptions,
|
||||
): Promise<K> {
|
||||
pending = true;
|
||||
|
||||
option = { ...(option || {}), ...customOption };
|
||||
|
||||
// 这里可以使用传进来的 req 作为默认映射,减少需要在 customAPI 中,需要手动绑定的情况
|
||||
if (useCustom) {
|
||||
const mappingKeys: string[] = Object.keys(meta.reqMapping)
|
||||
.map(key => meta.reqMapping[key])
|
||||
.reduce((a, b) => [...a, ...b], []);
|
||||
const defaultFiled = Object.keys(req).filter(
|
||||
field => !mappingKeys.includes(field),
|
||||
);
|
||||
|
||||
if (['POST', 'PUT', 'PATCH'].includes(meta.method)) {
|
||||
meta.reqMapping.body = [
|
||||
...defaultFiled,
|
||||
...(meta.reqMapping.body || []),
|
||||
];
|
||||
}
|
||||
if (['GET', 'DELETE'].includes(meta.method)) {
|
||||
meta.reqMapping.query = [
|
||||
...defaultFiled,
|
||||
...(meta.reqMapping.query || []),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
const { client, uri, requestOption } = normalizeRequest(req, meta, option);
|
||||
|
||||
if (!abortController && cancelable) {
|
||||
abortController = new AbortController();
|
||||
}
|
||||
if (abortController) {
|
||||
requestOption.signal = abortController.signal;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await client(uri, requestOption, option);
|
||||
return res;
|
||||
} finally {
|
||||
pending = false;
|
||||
}
|
||||
}
|
||||
|
||||
function abort() {
|
||||
/**
|
||||
* 这里加上 pending 状态的原因是,abortController.signal 的状态值只受控于 abortController.abort() 方法;
|
||||
* 不管请求是否完成或者异常,只要调用 abortController.abort(), abortController.signal.aborted 必定为 true,
|
||||
* 这样不好判断请求是否真 aborted;
|
||||
*
|
||||
* 这里改为,只有在请求 pending 的情况下,可执行 abort(),
|
||||
* isAborted === true 时,请求异常必定是因为手动 abort 导致的
|
||||
*/
|
||||
if (pending === true && cancelable && abortController) {
|
||||
abortController.abort();
|
||||
}
|
||||
}
|
||||
|
||||
function isAborted() {
|
||||
return !!abortController?.signal.aborted;
|
||||
}
|
||||
|
||||
function withAbort() {
|
||||
return createAPI<T, K, O, true>(meta, true, useCustom, customOption);
|
||||
}
|
||||
|
||||
api.meta = meta;
|
||||
api.withAbort = withAbort;
|
||||
if (cancelable) {
|
||||
api.abort = abort;
|
||||
api.isAborted = isAborted;
|
||||
}
|
||||
return api as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 一些非泛化的接口,可以使用改方法构建,方便统一管理接口
|
||||
* @param customAPIMeta
|
||||
* @param cancelable
|
||||
* @returns
|
||||
* @example
|
||||
*
|
||||
*/
|
||||
export function createCustomAPI<
|
||||
T extends {},
|
||||
K,
|
||||
O = unknown,
|
||||
B extends boolean = false,
|
||||
>(customAPIMeta: CustomAPIMeta, cancelable?: B) {
|
||||
const name = `${customAPIMeta.method}_${customAPIMeta.url}`;
|
||||
const meta: IMeta = {
|
||||
...customAPIMeta,
|
||||
reqMapping: customAPIMeta.reqMapping || {},
|
||||
name,
|
||||
service: 'CustomAPI',
|
||||
schemaRoot: '',
|
||||
reqType: `${name}_req`,
|
||||
resType: `${name}_res`,
|
||||
};
|
||||
return createAPI<T, K, O, B>(meta, cancelable, true);
|
||||
}
|
||||
19
frontend/infra/idl/idl2ts-runtime/src/index.ts
Normal file
19
frontend/infra/idl/idl2ts-runtime/src/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './create-api';
|
||||
export * from './config-center';
|
||||
export { type IMeta } from './types';
|
||||
47
frontend/infra/idl/idl2ts-runtime/src/types.ts
Normal file
47
frontend/infra/idl/idl2ts-runtime/src/types.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export interface IMeta {
|
||||
reqType: string;
|
||||
resType: string;
|
||||
url: string;
|
||||
method: string;
|
||||
reqMapping: IHttpRpcMapping;
|
||||
resMapping?: IHttpRpcMapping; // res mapping
|
||||
name: string;
|
||||
service: string;
|
||||
schemaRoot: string;
|
||||
serializer?: string;
|
||||
}
|
||||
|
||||
type Fields = string[];
|
||||
|
||||
export interface IHttpRpcMapping {
|
||||
path?: Fields; // path参数
|
||||
query?: Fields; // query参数
|
||||
body?: Fields; // body 参数
|
||||
header?: Fields; // header 参数
|
||||
status_code?: Fields; // http状态码
|
||||
cookie?: Fields; // cookie
|
||||
entire_body?: Fields;
|
||||
raw_body?: Fields;
|
||||
}
|
||||
|
||||
export interface CustomAPIMeta {
|
||||
url: string;
|
||||
method: 'POST' | 'GET' | 'PUT' | 'DELETE' | 'PATCH';
|
||||
reqMapping?: IHttpRpcMapping;
|
||||
}
|
||||
218
frontend/infra/idl/idl2ts-runtime/src/utils.ts
Normal file
218
frontend/infra/idl/idl2ts-runtime/src/utils.ts
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* 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 qs from 'qs';
|
||||
|
||||
import type { IMeta } from './types';
|
||||
import { configCenter } from './config-center';
|
||||
|
||||
export interface ServiceConfig {
|
||||
[key: string]: {
|
||||
methods?: {
|
||||
[key: string]: Omit<IdlConfig, 'clientFactory'>;
|
||||
};
|
||||
} & Omit<IdlConfig, 'clientFactory'>;
|
||||
}
|
||||
export interface IdlConfig {
|
||||
// client 工厂方法,要求返回一个 fetchClient 函数,使用 meta 总的信息,可实现灵活的 client 配置
|
||||
clientFactory?: (
|
||||
meta: IMeta,
|
||||
) => (uri: string, init: RequestInit, opt: any) => any;
|
||||
// uri 前缀,如果 client 中设置了,这里可以不设置
|
||||
uriPrefix?: string;
|
||||
getParams?: (key: string) => string;
|
||||
// 服务级别的配置
|
||||
services?: ServiceConfig;
|
||||
// 开发时,如果本地校验失败,这里可回调,通常是弹 toast
|
||||
onVerifyReqError?: (message: string, ctx: any) => void;
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
config?: IdlConfig;
|
||||
// 透传 request options 的选项
|
||||
requestOptions?: Record<string, any>;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface PathPrams<T> {
|
||||
pathParams?: T;
|
||||
}
|
||||
|
||||
export function getConfig(service: string, method: string): IdlConfig {
|
||||
// 手动注册的配置优先级比全局变量高
|
||||
let config: IdlConfig | undefined = configCenter.getConfig(service);
|
||||
if (!config) {
|
||||
config = {};
|
||||
if (config.services && config.services[service]) {
|
||||
const serviceConfig = config.services[service];
|
||||
const { methods, ...rest } = serviceConfig;
|
||||
Object.assign(config, rest);
|
||||
if (methods && methods[method]) {
|
||||
Object.assign(config, methods[method]);
|
||||
}
|
||||
}
|
||||
delete config.services;
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
function getValue(origin: any, fields: string[]) {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
const res = {} as Record<string, any>;
|
||||
fields.forEach(i => {
|
||||
res[i] = origin[i];
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-params
|
||||
export function unifyUrl(
|
||||
uri: string,
|
||||
pathParams: string[],
|
||||
option: IdlConfig & PathPrams<any>,
|
||||
req: Record<string, any>,
|
||||
): { apiUri: string; unmappedParams: string[] } {
|
||||
let apiUri = uri;
|
||||
pathParams = pathParams || [];
|
||||
const unmappedParams = [] as string[];
|
||||
const matches = apiUri.match(/:([^/]+)/g) || [];
|
||||
if (matches.length === 0) {
|
||||
return { apiUri, unmappedParams };
|
||||
}
|
||||
|
||||
matches.forEach(item => {
|
||||
const target = item.slice(1);
|
||||
if (!pathParams.includes(target)) {
|
||||
const param =
|
||||
option.pathParams?.[target] ||
|
||||
(option.getParams && option.getParams(target));
|
||||
apiUri = apiUri.replace(item, param || '');
|
||||
unmappedParams.push(target);
|
||||
} else {
|
||||
const param =
|
||||
req[target] ||
|
||||
option.pathParams?.[target] ||
|
||||
option.pathParams?.[target] ||
|
||||
(option.getParams && option.getParams(target));
|
||||
apiUri = apiUri.replace(item, param);
|
||||
}
|
||||
});
|
||||
return { apiUri, unmappedParams };
|
||||
}
|
||||
|
||||
const ContentTypeMap = {
|
||||
json: 'application/json',
|
||||
urlencoded: 'application/x-www-form-urlencoded',
|
||||
form: 'multipart/form-data',
|
||||
};
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
export function normalizeRequest(
|
||||
req: Record<string, any>,
|
||||
meta: IMeta,
|
||||
option?: IOptions & PathPrams<any>,
|
||||
) {
|
||||
const config = {
|
||||
...getConfig(meta.service, meta.method),
|
||||
...(option?.config ?? {}),
|
||||
};
|
||||
const { apiUri } = unifyUrl(
|
||||
meta.url,
|
||||
meta.reqMapping.path || [],
|
||||
{ ...config, pathParams: option?.pathParams ?? {} },
|
||||
req,
|
||||
);
|
||||
const { uriPrefix = '', clientFactory } = config;
|
||||
if (!clientFactory) {
|
||||
// todo 这里考虑给个默认的 client,防止某些公共 package 在一些异常情况下使用
|
||||
throw new Error('Lack of clientFactory config');
|
||||
}
|
||||
let uri = uriPrefix + apiUri;
|
||||
let headers: Record<string, string> = {};
|
||||
|
||||
headers['Content-Type'] =
|
||||
meta.serializer && ContentTypeMap[meta.serializer]
|
||||
? ContentTypeMap[meta.serializer]
|
||||
: 'application/json';
|
||||
if (option?.requestOptions?.headers) {
|
||||
headers = { ...headers, ...option.requestOptions.headers };
|
||||
// 合并了 header,可删除
|
||||
delete option.requestOptions.headers;
|
||||
}
|
||||
if (meta.reqMapping.query && meta.reqMapping.query.length > 0) {
|
||||
// 这里默认 skipNulls,网关后端需要忽略 null
|
||||
uri = `${uri}?${qs.stringify(getValue(req, meta.reqMapping.query), {
|
||||
skipNulls: true,
|
||||
arrayFormat: 'comma',
|
||||
})}`;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
const requestOption = {
|
||||
method: meta.method,
|
||||
headers,
|
||||
credentials: 'same-origin',
|
||||
} as RequestInit;
|
||||
|
||||
if (meta.reqMapping.entire_body && meta.reqMapping.entire_body.length > 0) {
|
||||
if (meta.reqMapping.entire_body.length === 1) {
|
||||
// 默认处理为 json ,如有其他场景需要支持,后需要再支持
|
||||
requestOption.body = req[meta.reqMapping.entire_body[0]];
|
||||
} else {
|
||||
throw new Error('idl invalid entire_body should be only one filed');
|
||||
}
|
||||
} else if (meta.reqMapping.body && meta.reqMapping.body.length > 0) {
|
||||
const body = getValue(req, meta.reqMapping.body);
|
||||
requestOption.body = body as BodyInit;
|
||||
if (meta.serializer === 'form') {
|
||||
const formData = new FormData();
|
||||
Object.keys(body).forEach(key => {
|
||||
const formItemValue =
|
||||
body[key] instanceof File
|
||||
? new Blob([body[key]], { type: body[key].type })
|
||||
: body[key];
|
||||
|
||||
formData.append(key, formItemValue);
|
||||
});
|
||||
requestOption.body = formData;
|
||||
}
|
||||
if (meta.serializer === 'urlencoded') {
|
||||
requestOption.body = qs.stringify(body, {
|
||||
skipNulls: true,
|
||||
arrayFormat: 'comma',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (meta.reqMapping.header && meta.reqMapping.header.length > 0) {
|
||||
requestOption.headers = {
|
||||
...headers,
|
||||
...getValue(req, meta.reqMapping.header),
|
||||
};
|
||||
}
|
||||
|
||||
// 旧版的 ferry 中,即使 idl 没有声明body,也需要加一个 空的 body
|
||||
if (
|
||||
!requestOption.body &&
|
||||
['POST', 'PUT', 'PATCH'].includes(
|
||||
(requestOption.method || '').toUpperCase(),
|
||||
)
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
requestOption.body = {} as BodyInit;
|
||||
}
|
||||
|
||||
return { uri, requestOption, client: clientFactory(meta) };
|
||||
}
|
||||
25
frontend/infra/idl/idl2ts-runtime/tsconfig.build.json
Normal file
25
frontend/infra/idl/idl2ts-runtime/tsconfig.build.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"extends": "@coze-arch/ts-config/tsconfig.node.json",
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"module": "CommonJS",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../config/eslint-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/ts-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/vitest-config/tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
15
frontend/infra/idl/idl2ts-runtime/tsconfig.json
Normal file
15
frontend/infra/idl/idl2ts-runtime/tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"exclude": ["**/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.misc.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
19
frontend/infra/idl/idl2ts-runtime/tsconfig.misc.json
Normal file
19
frontend/infra/idl/idl2ts-runtime/tsconfig.misc.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "@coze-arch/ts-config/tsconfig.node.json",
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./",
|
||||
"outDir": "./dist",
|
||||
"module": "CommonJS",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"types": ["vitest/globals"]
|
||||
},
|
||||
"include": ["__tests__", "vitest.config.ts"],
|
||||
"exclude": ["./dist"],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
22
frontend/infra/idl/idl2ts-runtime/vitest.config.ts
Normal file
22
frontend/infra/idl/idl2ts-runtime/vitest.config.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 { defineConfig } from '@coze-arch/vitest-config';
|
||||
|
||||
export default defineConfig({
|
||||
dirname: __dirname,
|
||||
preset: 'node',
|
||||
});
|
||||
Reference in New Issue
Block a user