chore: 更新版本号并添加 runAction 方法及其类型推断支持
This commit is contained in:
36
src/route.ts
36
src/route.ts
@@ -779,8 +779,44 @@ export class QueryRouterServer<C extends SimpleObject = SimpleObject> extends Qu
|
||||
}
|
||||
return super.run(msg, ctx as RouteContext<C>);
|
||||
}
|
||||
|
||||
async runAction<T extends { id?: string; path?: string; key?: string; metadata?: { args?: any } } = {}>(
|
||||
api: T,
|
||||
payload: RunActionPayload<T>,
|
||||
ctx?: RouteContext<C>
|
||||
) {
|
||||
const { path, key, id } = api as any;
|
||||
return this.run({ path, key, id, payload }, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class Mini extends QueryRouterServer { }
|
||||
|
||||
/** JSON Schema 基本类型映射到 TypeScript 类型 */
|
||||
type JsonSchemaTypeToTS<T> =
|
||||
T extends { type: "string" } ? string :
|
||||
T extends { type: "boolean" } ? boolean :
|
||||
T extends { type: "number" } ? number :
|
||||
T extends { type: "integer" } ? number :
|
||||
T extends { type: "object" } ? object :
|
||||
T extends { type: "array" } ? any[] :
|
||||
any;
|
||||
|
||||
/** 将 args shape(key -> JSON Schema 类型)转换为 payload 类型,支持 optional: true 的字段为可选 */
|
||||
type ArgsShapeToPayload<T> =
|
||||
{ [K in keyof T as T[K] extends { optional: true } ? never : K]: JsonSchemaTypeToTS<T[K]> } &
|
||||
{ [K in keyof T as T[K] extends { optional: true } ? K : never]?: JsonSchemaTypeToTS<T[K]> };
|
||||
|
||||
/** 处理两种 args 格式:完整 JSON Schema(含 properties)或简单 key->type 映射 */
|
||||
type ArgsToPayload<T> =
|
||||
T extends { type: "object"; properties: infer P }
|
||||
? ArgsShapeToPayload<P>
|
||||
: ArgsShapeToPayload<T>;
|
||||
|
||||
/** 从 API 定义中提取 metadata.args */
|
||||
type ExtractArgs<T> =
|
||||
T extends { metadata: { args: infer A } } ? A : {};
|
||||
|
||||
/** runAction 第二个参数的类型,根据第一个参数的 metadata.args 推断 */
|
||||
export type RunActionPayload<T> = ArgsToPayload<ExtractArgs<T>>;
|
||||
87
src/test/run-schema.ts
Normal file
87
src/test/run-schema.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import z from "zod";
|
||||
import { App } from "../index.ts";
|
||||
|
||||
const app = new App();
|
||||
const api = {
|
||||
"app_domain_manager": {
|
||||
/**
|
||||
* 获取域名信息,可以通过id或者domain进行查询
|
||||
*
|
||||
* @param data - Request parameters
|
||||
* @param data.data - {object}
|
||||
*/
|
||||
"get": {
|
||||
"path": "app_domain_manager",
|
||||
"key": "get",
|
||||
"description": "获取域名信息,可以通过id或者domain进行查询",
|
||||
"metadata": {
|
||||
"args": {
|
||||
"data": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["id",]
|
||||
}
|
||||
},
|
||||
"viewItem": {
|
||||
"api": {
|
||||
"url": "/api/router"
|
||||
},
|
||||
"type": "api",
|
||||
"title": "路由"
|
||||
},
|
||||
"url": "/api/router",
|
||||
"source": "query-proxy-api"
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"path": "app_domain_manager",
|
||||
"key": "delete",
|
||||
"description": "删除域名",
|
||||
"metadata": {
|
||||
"args": {
|
||||
"domainId": {
|
||||
"type": "string",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_manager": {
|
||||
"getUser": {
|
||||
"path": "user_manager",
|
||||
"key": "getUser",
|
||||
"description": "获取用户信息",
|
||||
"metadata": {
|
||||
"args": {
|
||||
"userId": {
|
||||
"type": "string"
|
||||
},
|
||||
"includeProfile": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} as const;
|
||||
type API = typeof api;
|
||||
|
||||
// 类型推断生效:payload 根据 metadata.args 自动推断
|
||||
// get 的 args.data 是 type:"object",所以 payload 需要 { data: object }
|
||||
app.runAction(api.app_domain_manager.get, { data: { id: "1" } })
|
||||
|
||||
// delete 的 args 是 { domainId: { type: "string" } },所以 payload 需要 { domainId: string }
|
||||
app.runAction(api.app_domain_manager.delete, { domainId: "d1" })
|
||||
|
||||
// getUser 的 args 是 { userId: string, includeProfile: boolean }
|
||||
app.runAction(api.user_manager.getUser, { userId: "u1", includeProfile: true })
|
||||
Reference in New Issue
Block a user