@kevisual/router 0.0.79 → 0.0.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +122 -120
- package/dist/opencode.d.ts +6 -1
- package/dist/opencode.js +16 -13
- package/dist/router-browser.d.ts +18 -11
- package/dist/router-browser.js +103 -104
- package/dist/router-define.d.ts +6 -1
- package/dist/router.d.ts +18 -11
- package/dist/router.js +103 -104
- package/dist/ws.d.ts +6 -1
- package/package.json +6 -6
- package/src/result/error.ts +14 -15
- package/src/route.ts +5 -103
- package/src/validator/schema.ts +100 -0
package/src/result/error.ts
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
+
type CustomErrorOptions = {
|
|
2
|
+
cause?: Error | string;
|
|
3
|
+
code?: number;
|
|
4
|
+
message?: string;
|
|
5
|
+
}
|
|
1
6
|
/** 自定义错误 */
|
|
2
7
|
export class CustomError extends Error {
|
|
3
8
|
code?: number;
|
|
4
9
|
data?: any;
|
|
5
10
|
message: string;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
this.code = 500;
|
|
15
|
-
this.message = code!;
|
|
16
|
-
}
|
|
17
|
-
this.tips = tips;
|
|
11
|
+
constructor(code?: number | string, opts?: CustomErrorOptions) {
|
|
12
|
+
let message = opts?.message || String(code);
|
|
13
|
+
const cause = opts?.cause;
|
|
14
|
+
super(message, { cause });
|
|
15
|
+
this.name = 'RouterError';
|
|
16
|
+
let codeNum = opts?.code || (typeof code === 'number' ? code : undefined);
|
|
17
|
+
this.code = codeNum ?? 500;
|
|
18
|
+
this.message = message!;
|
|
18
19
|
// 这一步可不写,默认会保存堆栈追踪信息到自定义错误构造函数之前,
|
|
19
20
|
// 而如果写成 `Error.captureStackTrace(this)` 则自定义错误的构造函数也会被保存到堆栈追踪信息
|
|
20
21
|
Error.captureStackTrace(this, this.constructor);
|
|
@@ -31,8 +32,7 @@ export class CustomError extends Error {
|
|
|
31
32
|
return {
|
|
32
33
|
code: e?.code,
|
|
33
34
|
data: e?.data,
|
|
34
|
-
message: e?.message
|
|
35
|
-
tips: e?.tips,
|
|
35
|
+
message: e?.message
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
@@ -52,7 +52,6 @@ export class CustomError extends Error {
|
|
|
52
52
|
code: e?.code,
|
|
53
53
|
data: e?.data,
|
|
54
54
|
message: e?.message,
|
|
55
|
-
tips: e?.tips,
|
|
56
55
|
};
|
|
57
56
|
}
|
|
58
57
|
}
|
package/src/route.ts
CHANGED
|
@@ -3,7 +3,8 @@ import { pick } from './utils/pick.ts';
|
|
|
3
3
|
import { listenProcess, MockProcess } from './utils/listen-process.ts';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { randomId } from './utils/random.ts';
|
|
6
|
-
import
|
|
6
|
+
import * as schema from './validator/schema.ts';
|
|
7
|
+
|
|
7
8
|
export type RouterContextT = { code?: number;[key: string]: any };
|
|
8
9
|
export type RouteContext<T = { code?: number }, S = any> = {
|
|
9
10
|
/**
|
|
@@ -246,101 +247,17 @@ export class Route<U = { [key: string]: any }, T extends SimpleObject = SimpleOb
|
|
|
246
247
|
throw new CustomError(...args);
|
|
247
248
|
}
|
|
248
249
|
}
|
|
249
|
-
const extractArgs = (args: any) => {
|
|
250
|
-
if (args && typeof args === 'object' && typeof args.shape === 'object') {
|
|
251
|
-
return args.shape as z.ZodRawShape;
|
|
252
|
-
}
|
|
253
|
-
return args || {};
|
|
254
|
-
};
|
|
255
250
|
|
|
256
251
|
const toJSONSchemaRoute = (route: RouteInfo) => {
|
|
257
252
|
const pickValues = pick(route, pickValue as any);
|
|
258
253
|
if (pickValues?.metadata?.args) {
|
|
259
|
-
|
|
260
|
-
// 如果 args 本身是一个 zod object schema,先提取 shape
|
|
261
|
-
args = extractArgs(args);
|
|
262
|
-
|
|
263
|
-
const keys = Object.keys(args);
|
|
264
|
-
const newArgs: { [key: string]: any } = {};
|
|
265
|
-
for (let key of keys) {
|
|
266
|
-
const item = args[key] as z.ZodAny;
|
|
267
|
-
if (item && typeof item === 'object' && typeof item.toJSONSchema === 'function') {
|
|
268
|
-
newArgs[key] = item.toJSONSchema();
|
|
269
|
-
} else {
|
|
270
|
-
newArgs[key] = args[key]; // 可能不是schema
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
pickValues.metadata.args = newArgs;
|
|
254
|
+
pickValues.metadata.args = toJSONSchema(pickValues?.metadata?.args, { mergeObject: false });
|
|
274
255
|
}
|
|
275
256
|
return pickValues;
|
|
276
257
|
}
|
|
277
|
-
const fromJSONSchemaRoute = (route: RouteInfo): RouteInfo => {
|
|
278
|
-
const args = route?.metadata?.args;
|
|
279
|
-
if (!args) return route;
|
|
280
|
-
const newArgs = fromJSONSchema(args);
|
|
281
|
-
route.metadata.args = newArgs;
|
|
282
|
-
return route;
|
|
283
|
-
}
|
|
284
258
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
* @param args
|
|
288
|
-
* @returns
|
|
289
|
-
*/
|
|
290
|
-
export const toJSONSchema = (args: any, opts?: { mergeObject?: boolean }): { [key: string]: any } => {
|
|
291
|
-
const mergeObject = opts?.mergeObject ?? true;
|
|
292
|
-
if (!args) return {};
|
|
293
|
-
if (mergeObject) {
|
|
294
|
-
if (typeof args === 'object' && typeof args.toJSONSchema === 'function') {
|
|
295
|
-
return args.toJSONSchema();
|
|
296
|
-
}
|
|
297
|
-
const schema = z.object(args);
|
|
298
|
-
return schema.toJSONSchema();
|
|
299
|
-
}
|
|
300
|
-
// 如果 args 本身是一个 zod object schema,先提取 shape
|
|
301
|
-
args = extractArgs(args);
|
|
302
|
-
const keys = Object.keys(args);
|
|
303
|
-
let newArgs: { [key: string]: any } = {};
|
|
304
|
-
for (let key of keys) {
|
|
305
|
-
const item = args[key] as z.ZodAny;
|
|
306
|
-
if (item && typeof item === 'object' && typeof item.toJSONSchema === 'function') {
|
|
307
|
-
newArgs[key] = item.toJSONSchema();
|
|
308
|
-
} else {
|
|
309
|
-
newArgs[key] = args[key]; // 可能不是schema
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
return newArgs;
|
|
313
|
-
}
|
|
314
|
-
export const fromJSONSchema = <Merge extends boolean = true>(args: any = {}, opts?: { mergeObject?: boolean }) => {
|
|
315
|
-
let resultArgs: any = null;
|
|
316
|
-
const mergeObject = opts?.mergeObject ?? true;
|
|
317
|
-
if (args["$schema"] || (args.type === 'object' && args.properties && typeof args.properties === 'object')) {
|
|
318
|
-
// 可能是整个schema
|
|
319
|
-
const objectSchema = z.fromJSONSchema(args);
|
|
320
|
-
const extract = extractArgs(objectSchema);
|
|
321
|
-
const keys = Object.keys(extract);
|
|
322
|
-
const newArgs: { [key: string]: any } = {};
|
|
323
|
-
for (let key of keys) {
|
|
324
|
-
newArgs[key] = extract[key];
|
|
325
|
-
}
|
|
326
|
-
resultArgs = newArgs;
|
|
327
|
-
}
|
|
328
|
-
if (!resultArgs) {
|
|
329
|
-
const keys = Object.keys(args);
|
|
330
|
-
const newArgs: { [key: string]: any } = {};
|
|
331
|
-
for (let key of keys) {
|
|
332
|
-
const item = args[key];
|
|
333
|
-
// fromJSONSchema 可能会失败,所以先 optional,等使用的时候再验证
|
|
334
|
-
newArgs[key] = z.fromJSONSchema(item).optional();
|
|
335
|
-
}
|
|
336
|
-
resultArgs = newArgs;
|
|
337
|
-
}
|
|
338
|
-
if (mergeObject) {
|
|
339
|
-
resultArgs = z.object(resultArgs);
|
|
340
|
-
}
|
|
341
|
-
type ResultArgs = Merge extends true ? z.ZodObject<{ [key: string]: any }> : { [key: string]: z.ZodTypeAny };
|
|
342
|
-
return resultArgs as unknown as ResultArgs;
|
|
343
|
-
}
|
|
259
|
+
export const toJSONSchema = schema.toJSONSchema;
|
|
260
|
+
export const fromJSONSchema = schema.fromJSONSchema;
|
|
344
261
|
|
|
345
262
|
/**
|
|
346
263
|
* @parmas overwrite 是否覆盖已存在的route,默认true
|
|
@@ -658,21 +575,6 @@ export class QueryRouter {
|
|
|
658
575
|
getList(filter?: (route: Route) => boolean): RouteInfo[] {
|
|
659
576
|
return this.routes.filter(filter || (() => true)).map((r) => {
|
|
660
577
|
const pickValues = pick(r, pickValue as any);
|
|
661
|
-
if (pickValues?.metadata?.args) {
|
|
662
|
-
// const demoArgs = { k: tool.schema.string().describe('示例参数') };
|
|
663
|
-
const args = pickValues.metadata.args;
|
|
664
|
-
const keys = Object.keys(args);
|
|
665
|
-
const newArgs: { [key: string]: any } = {};
|
|
666
|
-
for (let key of keys) {
|
|
667
|
-
const item = args[key] as z.ZodAny;
|
|
668
|
-
if (item && typeof item === 'object' && typeof item.toJSONSchema === 'function') {
|
|
669
|
-
newArgs[key] = item.toJSONSchema();
|
|
670
|
-
} else {
|
|
671
|
-
newArgs[key] = args[key]; // 可能不是schema
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
pickValues.metadata.args = newArgs;
|
|
675
|
-
}
|
|
676
578
|
return pickValues;
|
|
677
579
|
});
|
|
678
580
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const extractArgs = (args: any) => {
|
|
3
|
+
if (args && typeof args === 'object' && typeof args.shape === 'object') {
|
|
4
|
+
return args.shape as z.ZodRawShape;
|
|
5
|
+
}
|
|
6
|
+
return args || {};
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type ZodOverride = (opts: { jsonSchema: any; path: string[]; zodSchema: z.ZodTypeAny }) => void;
|
|
10
|
+
/**
|
|
11
|
+
* 剥离第一层schema,转换为JSON Schema,无论是skill还是其他的infer比纯粹的zod object schema更合适,因为它可能包含其他的字段,而不仅仅是schema
|
|
12
|
+
* @param args
|
|
13
|
+
* @returns
|
|
14
|
+
*/
|
|
15
|
+
export const toJSONSchema = (args: any, opts?: { mergeObject?: boolean, override?: ZodOverride }): { [key: string]: any } => {
|
|
16
|
+
const mergeObject = opts?.mergeObject ?? false;
|
|
17
|
+
if (!args) return {};
|
|
18
|
+
const _override = ({ jsonSchema, path, zodSchema }) => {
|
|
19
|
+
if (Array.isArray(path) && path.length > 0) {
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
const isOptional = (zodSchema as any).isOptional?.();
|
|
23
|
+
if (isOptional) {
|
|
24
|
+
// 添加自定义属性
|
|
25
|
+
jsonSchema.optional = true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const isError = (keys: string[]) => {
|
|
29
|
+
const errorKeys: string[] = ["toJSONSchema", "def", "type", "parse"]
|
|
30
|
+
const hasErrorKeys = errorKeys.every(key => keys.includes(key));
|
|
31
|
+
return hasErrorKeys;
|
|
32
|
+
}
|
|
33
|
+
const override: any = opts?.override || _override;
|
|
34
|
+
if (mergeObject) {
|
|
35
|
+
if (typeof args === 'object' && typeof args.toJSONSchema === 'function') {
|
|
36
|
+
return args.toJSONSchema();
|
|
37
|
+
}
|
|
38
|
+
if (isError(Object.keys(args))) {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
// 如果 mergeObject 为 true,直接将整个对象转换为 JSON Schema
|
|
42
|
+
// 先检测是否是一个错误的 schema
|
|
43
|
+
const schema = z.object(args);
|
|
44
|
+
return schema.toJSONSchema();
|
|
45
|
+
}
|
|
46
|
+
// 如果 args 本身是一个 zod object schema,先提取 shape
|
|
47
|
+
args = extractArgs(args);
|
|
48
|
+
let keys = Object.keys(args);
|
|
49
|
+
if (isError(keys)) {
|
|
50
|
+
console.error(`[toJSONSchema error]: 解析到的 schema 可能不正确,包含了zod默认的value的schema. 请检查输入的 schema 是否正确。`);
|
|
51
|
+
args = {};
|
|
52
|
+
keys = [];
|
|
53
|
+
}
|
|
54
|
+
if (mergeObject) {
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
let newArgs: { [key: string]: any } = {};
|
|
58
|
+
for (let key of keys) {
|
|
59
|
+
const item = args[key] as z.ZodAny;
|
|
60
|
+
if (item && typeof item === 'object' && typeof item.toJSONSchema === 'function') {
|
|
61
|
+
newArgs[key] = item.toJSONSchema({ override });
|
|
62
|
+
} else {
|
|
63
|
+
newArgs[key] = args[key]; // 可能不是schema
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return newArgs;
|
|
67
|
+
}
|
|
68
|
+
export const fromJSONSchema = <Merge extends boolean = false>(args: any = {}, opts?: { mergeObject?: boolean }) => {
|
|
69
|
+
let resultArgs: any = null;
|
|
70
|
+
const mergeObject = opts?.mergeObject ?? false;
|
|
71
|
+
if (args["$schema"] || (args.type === 'object' && args.properties && typeof args.properties === 'object')) {
|
|
72
|
+
// 可能是整个schema
|
|
73
|
+
const objectSchema = z.fromJSONSchema(args);
|
|
74
|
+
const extract = extractArgs(objectSchema);
|
|
75
|
+
const keys = Object.keys(extract);
|
|
76
|
+
const newArgs: { [key: string]: any } = {};
|
|
77
|
+
for (let key of keys) {
|
|
78
|
+
newArgs[key] = extract[key];
|
|
79
|
+
}
|
|
80
|
+
resultArgs = newArgs;
|
|
81
|
+
}
|
|
82
|
+
if (!resultArgs) {
|
|
83
|
+
const keys = Object.keys(args);
|
|
84
|
+
const newArgs: { [key: string]: any } = {};
|
|
85
|
+
for (let key of keys) {
|
|
86
|
+
const item = args[key];
|
|
87
|
+
// fromJSONSchema 可能会失败,所以先 optional,等使用的时候再验证
|
|
88
|
+
newArgs[key] = z.fromJSONSchema(item)
|
|
89
|
+
if (item.optional) {
|
|
90
|
+
newArgs[key] = newArgs[key].optional();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
resultArgs = newArgs;
|
|
94
|
+
}
|
|
95
|
+
if (mergeObject) {
|
|
96
|
+
resultArgs = z.object(resultArgs);
|
|
97
|
+
}
|
|
98
|
+
type ResultArgs = Merge extends true ? z.ZodObject<{ [key: string]: any }> : { [key: string]: z.ZodTypeAny };
|
|
99
|
+
return resultArgs as unknown as ResultArgs;
|
|
100
|
+
}
|