@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.
@@ -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
- tips?: string;
7
- constructor(code?: number | string, message?: string, tips?: string) {
8
- super(message || String(code));
9
- this.name = 'CustomError';
10
- if (typeof code === 'number') {
11
- this.code = code;
12
- this.message = message!;
13
- } else {
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 { ar } from 'zod/v4/locales';
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
- let args = pickValues.metadata.args;
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
- * 剥离第一层schema,转换为JSON Schema,无论是skill还是其他的infer比纯粹的zod object schema更合适,因为它可能包含其他的字段,而不仅仅是schema
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
+ }