chore: 更新版本号并添加 runAction 方法及其类型推断支持
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package",
|
"$schema": "https://json.schemastore.org/package",
|
||||||
"name": "@kevisual/router",
|
"name": "@kevisual/router",
|
||||||
"version": "0.0.85",
|
"version": "0.0.86",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/router.js",
|
"main": "./dist/router.js",
|
||||||
@@ -27,11 +27,11 @@
|
|||||||
"@kevisual/dts": "^0.0.4",
|
"@kevisual/dts": "^0.0.4",
|
||||||
"@kevisual/js-filter": "^0.0.5",
|
"@kevisual/js-filter": "^0.0.5",
|
||||||
"@kevisual/local-proxy": "^0.0.8",
|
"@kevisual/local-proxy": "^0.0.8",
|
||||||
"@kevisual/query": "^0.0.52",
|
"@kevisual/query": "^0.0.53",
|
||||||
"@kevisual/use-config": "^1.0.30",
|
"@kevisual/use-config": "^1.0.30",
|
||||||
"@opencode-ai/plugin": "^1.2.16",
|
"@opencode-ai/plugin": "^1.2.20",
|
||||||
"@types/bun": "^1.3.10",
|
"@types/bun": "^1.3.10",
|
||||||
"@types/node": "^25.3.3",
|
"@types/node": "^25.3.5",
|
||||||
"@types/send": "^1.2.1",
|
"@types/send": "^1.2.1",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"@types/xml2js": "^0.4.14",
|
"@types/xml2js": "^0.4.14",
|
||||||
|
|||||||
46
pnpm-lock.yaml
generated
46
pnpm-lock.yaml
generated
@@ -28,20 +28,20 @@ importers:
|
|||||||
specifier: ^0.0.8
|
specifier: ^0.0.8
|
||||||
version: 0.0.8
|
version: 0.0.8
|
||||||
'@kevisual/query':
|
'@kevisual/query':
|
||||||
specifier: ^0.0.52
|
specifier: ^0.0.53
|
||||||
version: 0.0.52
|
version: 0.0.53
|
||||||
'@kevisual/use-config':
|
'@kevisual/use-config':
|
||||||
specifier: ^1.0.30
|
specifier: ^1.0.30
|
||||||
version: 1.0.30(dotenv@17.2.3)
|
version: 1.0.30(dotenv@17.2.3)
|
||||||
'@opencode-ai/plugin':
|
'@opencode-ai/plugin':
|
||||||
specifier: ^1.2.16
|
specifier: ^1.2.20
|
||||||
version: 1.2.16
|
version: 1.2.20
|
||||||
'@types/bun':
|
'@types/bun':
|
||||||
specifier: ^1.3.10
|
specifier: ^1.3.10
|
||||||
version: 1.3.10
|
version: 1.3.10
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^25.3.3
|
specifier: ^25.3.5
|
||||||
version: 25.3.3
|
version: 25.3.5
|
||||||
'@types/send':
|
'@types/send':
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
@@ -142,8 +142,8 @@ packages:
|
|||||||
'@kevisual/local-proxy@0.0.8':
|
'@kevisual/local-proxy@0.0.8':
|
||||||
resolution: {integrity: sha512-VX/P+6/Cc8ruqp34ag6gVX073BchUmf5VNZcTV/6MJtjrNE76G8V6TLpBE8bywLnrqyRtFLIspk4QlH8up9B5Q==}
|
resolution: {integrity: sha512-VX/P+6/Cc8ruqp34ag6gVX073BchUmf5VNZcTV/6MJtjrNE76G8V6TLpBE8bywLnrqyRtFLIspk4QlH8up9B5Q==}
|
||||||
|
|
||||||
'@kevisual/query@0.0.52':
|
'@kevisual/query@0.0.53':
|
||||||
resolution: {integrity: sha512-m1UbyDTIxtfAQXM+EqhXA4ytE2V8rV8mXTZVBwzfW9O6+gtvAcRY7K1YYxfewTSXLVh9nwvfHe0KQ8MDL5ukyw==}
|
resolution: {integrity: sha512-PAhpCLBr0emz0lGNlTVHMbJiC5wrtGLbInPddRzgKE35fiyNt+SWSsUWABiD0DeNrLN/OxWyAFobt880Z/e5MQ==}
|
||||||
|
|
||||||
'@kevisual/use-config@1.0.30':
|
'@kevisual/use-config@1.0.30':
|
||||||
resolution: {integrity: sha512-kPdna0FW/X7D600aMdiZ5UTjbCo6d8d4jjauSc8RMmBwUU6WliFDSPUNKVpzm2BsDX5Nth1IXFPYMqH+wxqAmw==}
|
resolution: {integrity: sha512-kPdna0FW/X7D600aMdiZ5UTjbCo6d8d4jjauSc8RMmBwUU6WliFDSPUNKVpzm2BsDX5Nth1IXFPYMqH+wxqAmw==}
|
||||||
@@ -166,11 +166,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
'@opencode-ai/plugin@1.2.16':
|
'@opencode-ai/plugin@1.2.20':
|
||||||
resolution: {integrity: sha512-9Kb7BQIC2P3oKCvI8K3thP5YP0vE7yLvcmBmgyACUIqc3e5UL6U+4umLpTvgQa2eQdjxtOXznuGTNwgcGMHUHg==}
|
resolution: {integrity: sha512-BE6TOXVxgF24g5QgtlogSY5B+/AmZJ3cYaVjHZhUVuAli9JEg4RblrbrK2rfgbyZBoZDpjBLGTYtIRTVmOccEA==}
|
||||||
|
|
||||||
'@opencode-ai/sdk@1.2.16':
|
'@opencode-ai/sdk@1.2.20':
|
||||||
resolution: {integrity: sha512-y9ae9VnCcuog0GaI4DveX1HB6DBoZgGN3EuJVlRFbBCPwhzkls6fCfHSb5+VnTS6Fy0OWFUL28VBCmixL/D+/Q==}
|
resolution: {integrity: sha512-U5ROpG21D8jg9rkc1IgKAk1g5dn6X/rkOBfveupd0peSDO9n6VM9aikYccVLaMObxVqdjtG08IeQOFTPVS8ySQ==}
|
||||||
|
|
||||||
'@rollup/plugin-commonjs@29.0.0':
|
'@rollup/plugin-commonjs@29.0.0':
|
||||||
resolution: {integrity: sha512-U2YHaxR2cU/yAiwKJtJRhnyLk7cifnQw0zUpISsocBDoHDJn+HTV74ABqnwr5bEgWUwFZC9oFL6wLe21lHu5eQ==}
|
resolution: {integrity: sha512-U2YHaxR2cU/yAiwKJtJRhnyLk7cifnQw0zUpISsocBDoHDJn+HTV74ABqnwr5bEgWUwFZC9oFL6wLe21lHu5eQ==}
|
||||||
@@ -371,8 +371,8 @@ packages:
|
|||||||
'@types/node@25.2.3':
|
'@types/node@25.2.3':
|
||||||
resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==}
|
resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==}
|
||||||
|
|
||||||
'@types/node@25.3.3':
|
'@types/node@25.3.5':
|
||||||
resolution: {integrity: sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==}
|
resolution: {integrity: sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==}
|
||||||
|
|
||||||
'@types/resolve@1.20.2':
|
'@types/resolve@1.20.2':
|
||||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||||
@@ -744,7 +744,7 @@ snapshots:
|
|||||||
|
|
||||||
'@kevisual/local-proxy@0.0.8': {}
|
'@kevisual/local-proxy@0.0.8': {}
|
||||||
|
|
||||||
'@kevisual/query@0.0.52': {}
|
'@kevisual/query@0.0.53': {}
|
||||||
|
|
||||||
'@kevisual/use-config@1.0.30(dotenv@17.2.3)':
|
'@kevisual/use-config@1.0.30(dotenv@17.2.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -765,12 +765,12 @@ snapshots:
|
|||||||
'@nodelib/fs.scandir': 2.1.5
|
'@nodelib/fs.scandir': 2.1.5
|
||||||
fastq: 1.20.1
|
fastq: 1.20.1
|
||||||
|
|
||||||
'@opencode-ai/plugin@1.2.16':
|
'@opencode-ai/plugin@1.2.20':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opencode-ai/sdk': 1.2.16
|
'@opencode-ai/sdk': 1.2.20
|
||||||
zod: 4.1.8
|
zod: 4.1.8
|
||||||
|
|
||||||
'@opencode-ai/sdk@1.2.16': {}
|
'@opencode-ai/sdk@1.2.20': {}
|
||||||
|
|
||||||
'@rollup/plugin-commonjs@29.0.0(rollup@4.57.1)':
|
'@rollup/plugin-commonjs@29.0.0(rollup@4.57.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -904,7 +904,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.16.0
|
undici-types: 7.16.0
|
||||||
|
|
||||||
'@types/node@25.3.3':
|
'@types/node@25.3.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.18.2
|
undici-types: 7.18.2
|
||||||
|
|
||||||
@@ -912,15 +912,15 @@ snapshots:
|
|||||||
|
|
||||||
'@types/send@1.2.1':
|
'@types/send@1.2.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.3.3
|
'@types/node': 25.3.5
|
||||||
|
|
||||||
'@types/ws@8.18.1':
|
'@types/ws@8.18.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.3.3
|
'@types/node': 25.3.5
|
||||||
|
|
||||||
'@types/xml2js@0.4.14':
|
'@types/xml2js@0.4.14':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.3.3
|
'@types/node': 25.3.5
|
||||||
|
|
||||||
acorn-walk@8.3.4:
|
acorn-walk@8.3.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -936,7 +936,7 @@ snapshots:
|
|||||||
|
|
||||||
bun-types@1.3.10:
|
bun-types@1.3.10:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.3.3
|
'@types/node': 25.3.5
|
||||||
|
|
||||||
commondir@1.0.1: {}
|
commondir@1.0.1: {}
|
||||||
|
|
||||||
|
|||||||
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>);
|
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 { }
|
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