@kevisual/router 0.2.12 → 0.2.14
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/README.md +169 -12
- package/package.json +8 -8
- package/src/result/error.ts +4 -0
- package/src/route.ts +49 -6
- package/src/test/route-ts.ts +17 -3
package/README.md
CHANGED
|
@@ -60,10 +60,10 @@ import { App } from '@kevisual/router/browser';
|
|
|
60
60
|
|
|
61
61
|
| 方法 | 参数 | 说明 |
|
|
62
62
|
| ----------------------------------- | ----------------------------------------- | -------------------------------------------- |
|
|
63
|
-
| `ctx.
|
|
64
|
-
| `ctx.run(msg, ctx?)` | `{ path, key?, payload? }` | 调用其他路由,返回 `{ code, data, message }` |
|
|
63
|
+
| `ctx.run(msg, ctx?)` | `{ path, key?, payload?, ... } \| { rid }` | 调用其他路由,返回 `{ code, data, message }` |
|
|
65
64
|
| `ctx.forward(res)` | `{ code, data?, message? }` | 设置响应结果 |
|
|
66
65
|
| `ctx.throw(code?, message?, tips?)` | - | 抛出自定义错误 |
|
|
66
|
+
| `ctx.safeParseAsync(data?, opts?)` | `{ schema?, zodOptions?, stop? }` | 校验路由参数,失败时返回 issues 或自动抛出 422 错误 |
|
|
67
67
|
|
|
68
68
|
## 完整示例
|
|
69
69
|
|
|
@@ -162,18 +162,26 @@ app
|
|
|
162
162
|
|
|
163
163
|
```ts
|
|
164
164
|
import { App } from '@kevisual/router';
|
|
165
|
+
import { z } from 'zod';
|
|
165
166
|
const app = new App();
|
|
166
167
|
|
|
167
168
|
app
|
|
168
|
-
.
|
|
169
|
+
.route({
|
|
169
170
|
path: 'dog',
|
|
170
171
|
key: 'info',
|
|
171
172
|
description: '获取小狗的信息',
|
|
172
173
|
metadata: {
|
|
174
|
+
// args: 定义请求参数的 zod schema,用于参数校验和类型推断
|
|
173
175
|
args: {
|
|
174
176
|
name: z.string().describe('小狗的姓名'),
|
|
175
177
|
age: z.number().describe('小狗的年龄'),
|
|
176
178
|
},
|
|
179
|
+
// returns: 定义响应数据的 zod schema,用于返回结果类型推断
|
|
180
|
+
returns: {
|
|
181
|
+
content: z.string().describe('小狗的信息描述'),
|
|
182
|
+
},
|
|
183
|
+
// check: true 会在路由执行前自动校验 args,失败时返回 422
|
|
184
|
+
check: true,
|
|
177
185
|
},
|
|
178
186
|
})
|
|
179
187
|
.define(async (ctx) => {
|
|
@@ -185,20 +193,169 @@ app
|
|
|
185
193
|
.addTo(app);
|
|
186
194
|
```
|
|
187
195
|
|
|
188
|
-
|
|
196
|
+
### metadata 字段说明
|
|
189
197
|
|
|
190
|
-
|
|
198
|
+
| 字段 | 类型 | 说明 |
|
|
199
|
+
|------|------|------|
|
|
200
|
+
| `args` | `Record<string, z.ZodTypeAny> \| z.ZodObject` | 请求参数的 zod schema,用于参数校验和类型推断 |
|
|
201
|
+
| `returns` | `Record<string, z.ZodTypeAny> \| z.ZodObject` | 响应数据的 zod schema,用于返回值类型推断 |
|
|
202
|
+
| `check` | `boolean` | 设为 `true` 时,路由执行前自动校验 `args`,校验失败返回 422 |
|
|
191
203
|
|
|
192
|
-
|
|
204
|
+
### metadata.args 参数说明
|
|
193
205
|
|
|
194
|
-
|
|
206
|
+
`args` 是一个 zod schema 对象,用于定义路由的请求参数结构。每个字段的 key 对应请求时传入的参数名,value 为 zod 的类型定义。
|
|
195
207
|
|
|
196
|
-
|
|
208
|
+
| 参数名 | 类型 | 必填 | 说明 |
|
|
209
|
+
|--------|------|------|------|
|
|
210
|
+
| `name` | `z.string()` | 是 | 小狗的姓名,字符串类型 |
|
|
211
|
+
| `age` | `z.number()` | 是 | 小狗的年龄,数字类型 |
|
|
212
|
+
|
|
213
|
+
**调用示例:**
|
|
214
|
+
```ts
|
|
215
|
+
// 调用 dog/info 路由
|
|
216
|
+
const res = await app.run({
|
|
217
|
+
path: 'dog',
|
|
218
|
+
key: 'info',
|
|
219
|
+
payload: { name: '旺财', age: 3 }
|
|
220
|
+
});
|
|
221
|
+
// res.data.content => "这是一只3岁的小狗,名字是旺财"
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### metadata.returns 返回值说明
|
|
225
|
+
|
|
226
|
+
`returns` 是一个 zod schema 对象,用于定义路由响应的数据结构。主要用于:
|
|
227
|
+
1. 类型安全:配合 `runAction` 方法进行返回值的类型推断
|
|
228
|
+
2. 文档化:自动生成 API 文档
|
|
229
|
+
|
|
230
|
+
| 返回字段 | 类型 | 说明 |
|
|
231
|
+
|----------|------|------|
|
|
232
|
+
| `content` | `z.string()` | 小狗的信息描述,字符串类型 |
|
|
233
|
+
|
|
234
|
+
**返回结构:**
|
|
235
|
+
```ts
|
|
236
|
+
{
|
|
237
|
+
code: 200, // HTTP 状态码
|
|
238
|
+
data: { // 返回的数据,类型由 returns schema 推断
|
|
239
|
+
content: "这是一只3岁的小狗,名字是旺财"
|
|
240
|
+
},
|
|
241
|
+
message: "success" // 响应消息
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### 配合 runAction 使用
|
|
246
|
+
|
|
247
|
+
当你使用 `runAction` 方法调用路由时,`args` 和 `returns` 会参与类型推断:
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
import { App } from '@kevisual/router';
|
|
251
|
+
import { z } from 'zod';
|
|
252
|
+
|
|
253
|
+
const app = new App();
|
|
254
|
+
|
|
255
|
+
// 定义 API 结构
|
|
256
|
+
const dogAPI = {
|
|
257
|
+
path: 'dog',
|
|
258
|
+
key: 'info',
|
|
259
|
+
metadata: {
|
|
260
|
+
args: {
|
|
261
|
+
name: z.string(),
|
|
262
|
+
age: z.number(),
|
|
263
|
+
},
|
|
264
|
+
returns: {
|
|
265
|
+
content: z.string(),
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
} as const;
|
|
269
|
+
|
|
270
|
+
// runAction 会根据 metadata.args 推断 payload 类型
|
|
271
|
+
// 根据 metadata.returns 推断返回数据的类型
|
|
272
|
+
const res = await app.runAction(dogAPI, { name: '旺财', age: 3 });
|
|
273
|
+
// res.data.content 会被正确推断为 string 类型
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## 参数校验
|
|
277
|
+
|
|
278
|
+
框架集成了 [Zod](https://zod.dev/) v4 进行参数校验,提供两种使用方式。
|
|
197
279
|
|
|
198
|
-
|
|
280
|
+
### 自动校验(metadata.check)
|
|
199
281
|
|
|
200
|
-
|
|
282
|
+
在路由定义中设置 `metadata.check: true`,框架会在路由函数执行前自动校验 `metadata.args` 中定义的参数。校验失败时自动返回 HTTP 422,`body` 为 zod issues 数组。
|
|
201
283
|
|
|
202
|
-
|
|
284
|
+
```ts
|
|
285
|
+
app
|
|
286
|
+
.route({
|
|
287
|
+
path: 'user',
|
|
288
|
+
key: 'create',
|
|
289
|
+
metadata: {
|
|
290
|
+
args: {
|
|
291
|
+
name: z.string(),
|
|
292
|
+
age: z.number(),
|
|
293
|
+
},
|
|
294
|
+
check: true, // 开启自动校验
|
|
295
|
+
},
|
|
296
|
+
})
|
|
297
|
+
.define(async (ctx) => {
|
|
298
|
+
// 走到这里时参数已通过校验
|
|
299
|
+
const { name, age } = ctx.query;
|
|
300
|
+
ctx.body = { name, age };
|
|
301
|
+
})
|
|
302
|
+
.addTo(app);
|
|
303
|
+
|
|
304
|
+
// 校验失败时响应示例:
|
|
305
|
+
// { code: 422, message: 'Validation Error:...', data: [{ code: 'invalid_type', path: ['age'], message: '...' }] }
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### 手动校验(ctx.safeParseAsync)
|
|
309
|
+
|
|
310
|
+
在路由函数内部手动调用 `ctx.safeParseAsync()` 进行校验,可以更灵活地处理校验结果。
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
app
|
|
314
|
+
.route({
|
|
315
|
+
path: 'user',
|
|
316
|
+
key: 'update',
|
|
317
|
+
metadata: {
|
|
318
|
+
args: {
|
|
319
|
+
id: z.string(),
|
|
320
|
+
name: z.string().optional(),
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
})
|
|
324
|
+
.define(async (ctx) => {
|
|
325
|
+
// stop: true(默认)时校验失败会自动 throw 422
|
|
326
|
+
// stop: false 时返回结果由你自行处理
|
|
327
|
+
const res = await ctx.safeParseAsync(null, { stop: false });
|
|
328
|
+
if (!res.success) {
|
|
329
|
+
// res.error.issues 为 zod v4 的错误列表(注意:zod v4 用 issues,不再是 errors)
|
|
330
|
+
const { fieldErrors } = res.error.flatten();
|
|
331
|
+
ctx.code = 422;
|
|
332
|
+
ctx.body = { fieldErrors };
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
ctx.body = { ok: true };
|
|
336
|
+
})
|
|
337
|
+
.addTo(app);
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**`ctx.safeParseAsync` 参数说明:**
|
|
341
|
+
|
|
342
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
343
|
+
|------|------|--------|------|
|
|
344
|
+
| `data` | `any` | `null` | 额外合并到校验数据中(会与 `ctx.query` 合并) |
|
|
345
|
+
| `opts.schema` | `Record<string, z.ZodTypeAny>` | - | 额外追加的 zod schema 字段 |
|
|
346
|
+
| `opts.zodOptions` | `any` | - | 透传给 zod `safeParseAsync` 的选项 |
|
|
347
|
+
| `opts.stop` | `boolean` | `true` | 校验失败时是否自动 throw 422,`false` 时由调用方自行处理 |
|
|
348
|
+
|
|
349
|
+
> **注意:** 项目使用 Zod v4,错误信息字段为 `res.error.issues`
|
|
350
|
+
|
|
351
|
+
## 注意事项
|
|
352
|
+
|
|
353
|
+
1. **path 和 key 的组合是路由的唯一标识**,同一个 path+key 只能添加一个路由,后添加的会覆盖之前的。
|
|
354
|
+
|
|
355
|
+
2. `ctx.run` 返回 `{ code, data, message }` 格式,data 即 body。
|
|
356
|
+
|
|
357
|
+
3. **ctx.throw 会自动结束执行**,抛出自定义错误。支持传入 `data` 字段,错误时 `ctx.body` 会被设为该值。
|
|
358
|
+
|
|
359
|
+
4. **payload 会自动合并到 query**,调用 `ctx.run({ path, key, payload })` 时,payload 会合并到 query。
|
|
203
360
|
|
|
204
|
-
|
|
361
|
+
5. **校验失败响应**:`metadata.check: true` 或 `ctx.safeParseAsync` 默认 stop 模式下,校验失败返回 `code: 422`,`body` 为 zod issues 数组,可直接用于前端表单错误展示。
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@kevisual/router",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.14",
|
|
5
5
|
"description": "",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/router.js",
|
|
@@ -27,19 +27,19 @@
|
|
|
27
27
|
"@kevisual/dts": "^0.0.4",
|
|
28
28
|
"@kevisual/js-filter": "^0.0.6",
|
|
29
29
|
"@kevisual/local-proxy": "^0.0.8",
|
|
30
|
-
"@kevisual/query": "^0.0.
|
|
30
|
+
"@kevisual/query": "^0.0.58",
|
|
31
31
|
"@kevisual/remote-app": "^0.0.7",
|
|
32
32
|
"@kevisual/use-config": "^1.0.30",
|
|
33
|
-
"@opencode-ai/plugin": "^1.
|
|
34
|
-
"@types/bun": "^1.3.
|
|
33
|
+
"@opencode-ai/plugin": "^1.15.13",
|
|
34
|
+
"@types/bun": "^1.3.14",
|
|
35
35
|
"@types/crypto-js": "^4.2.2",
|
|
36
|
-
"@types/node": "^25.
|
|
36
|
+
"@types/node": "^25.9.1",
|
|
37
37
|
"@types/send": "^1.2.1",
|
|
38
38
|
"@types/ws": "^8.18.1",
|
|
39
39
|
"@types/xml2js": "^0.4.14",
|
|
40
|
-
"commander": "^
|
|
40
|
+
"commander": "^15.0.0",
|
|
41
41
|
"crypto-js": "^4.2.0",
|
|
42
|
-
"es-toolkit": "^1.
|
|
42
|
+
"es-toolkit": "^1.47.0",
|
|
43
43
|
"eventemitter3": "^5.0.4",
|
|
44
44
|
"fast-glob": "^3.3.3",
|
|
45
45
|
"nanoid": "^5.1.11",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"url": "git+https://github.com/abearxiong/kevisual-router.git"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"zod": "^4.4.
|
|
57
|
+
"zod": "^4.4.3"
|
|
58
58
|
},
|
|
59
59
|
"publishConfig": {
|
|
60
60
|
"access": "public"
|
package/src/result/error.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type CustomErrorOptions = {
|
|
2
2
|
cause?: Error | string;
|
|
3
3
|
code?: number;
|
|
4
|
+
data?: any;
|
|
4
5
|
message?: string;
|
|
5
6
|
}
|
|
6
7
|
/** 自定义错误 */
|
|
@@ -19,6 +20,9 @@ export class CustomError extends Error {
|
|
|
19
20
|
this.name = 'RouterError';
|
|
20
21
|
let codeNum = opts?.code || (typeof code === 'number' ? code : undefined);
|
|
21
22
|
this.code = codeNum ?? 500;
|
|
23
|
+
if (opts.data) {
|
|
24
|
+
this.data = opts.data;
|
|
25
|
+
}
|
|
22
26
|
this.message = message!;
|
|
23
27
|
// 这一步可不写,默认会保存堆栈追踪信息到自定义错误构造函数之前,
|
|
24
28
|
// 而如果写成 `Error.captureStackTrace(this)` 则自定义错误的构造函数也会被保存到堆栈追踪信息
|
package/src/route.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CustomError, throwError } from './result/error.ts';
|
|
2
2
|
import { pick } from './utils/pick.ts';
|
|
3
3
|
import { listenProcess, MockProcess } from './utils/listen-process.ts';
|
|
4
|
-
import { z } from 'zod';
|
|
4
|
+
import { z, ZodError } from 'zod';
|
|
5
5
|
import { hashIdMd5Sync, randomId } from './utils/random.ts';
|
|
6
6
|
import * as schema from './validator/schema.ts';
|
|
7
7
|
import type { RunActionPayload, RunActionReturns } from './types/index.ts'
|
|
@@ -57,6 +57,11 @@ export type RouteContext<T = { code?: number }, U extends SimpleObject = {}, S =
|
|
|
57
57
|
* 进度
|
|
58
58
|
*/
|
|
59
59
|
progress?: [string, string][];
|
|
60
|
+
safeParseAsync?: (data?: any, opts?: {
|
|
61
|
+
schema?: { [key: string]: z.ZodTypeAny },
|
|
62
|
+
zodOptions?: any,
|
|
63
|
+
stop?: boolean, // 如果验证失败,是否停止后续的 route 执行,默认 true
|
|
64
|
+
}) => Promise<{ success: boolean; data?: any; error?: any }>;
|
|
60
65
|
// onlyForNextRoute will be clear after next route
|
|
61
66
|
nextQuery?: { [key: string]: any };
|
|
62
67
|
// end
|
|
@@ -93,7 +98,7 @@ export type RouteOpts<U = {}, T = SimpleObject> = {
|
|
|
93
98
|
run?: Run<U>;
|
|
94
99
|
nextRoute?: NextRoute; // route to run after this route
|
|
95
100
|
description?: string;
|
|
96
|
-
metadata?: T
|
|
101
|
+
metadata?: Metadata<T>;
|
|
97
102
|
middleware?: RouteMiddleware[]; // middleware
|
|
98
103
|
type?: 'route' | 'middleware' | 'compound'; // compound表示这个 route 作为一个聚合体,没有实际的 run,而是一个 router 的聚合列表
|
|
99
104
|
isDebug?: boolean;
|
|
@@ -129,12 +134,16 @@ export const createSkill = <T = SimpleObject>(skill: Skill<T>): Skill<T> => {
|
|
|
129
134
|
}
|
|
130
135
|
|
|
131
136
|
export type RouteInfo = Pick<Route, (typeof pickValue)[number]>;
|
|
132
|
-
|
|
137
|
+
export type Metadata<T = SimpleObject> = {
|
|
138
|
+
args?: Record<string, z.ZodTypeAny> | z.ZodObject<any>;
|
|
139
|
+
returns?: Record<string, z.ZodTypeAny> | z.ZodObject<any>;
|
|
140
|
+
check?: boolean;
|
|
141
|
+
} & T;
|
|
133
142
|
/**
|
|
134
143
|
* @M 是 route的 metadate的类型,默认是 SimpleObject
|
|
135
144
|
* @U 是 RouteContext 里 state的类型
|
|
136
145
|
*/
|
|
137
|
-
export class Route<M extends
|
|
146
|
+
export class Route<M extends Metadata = Metadata, U extends SimpleObject = SimpleObject> implements throwError {
|
|
138
147
|
/**
|
|
139
148
|
* 一级路径
|
|
140
149
|
*/
|
|
@@ -315,6 +324,21 @@ export class QueryRouter<T extends SimpleObject = SimpleObject> implements throw
|
|
|
315
324
|
removeById(uniqueId: string) {
|
|
316
325
|
this.routes = this.routes.filter((r) => r.rid !== uniqueId);
|
|
317
326
|
}
|
|
327
|
+
safeParseAsyncRoute(data: any, opts: { route: RouteInfo, schema?: { [key: string]: z.ZodTypeAny }, zodOptions?: any }): Promise<{ success: boolean; data?: any; error?: any }> {
|
|
328
|
+
const route = opts.route;
|
|
329
|
+
const argZod = route.metadata?.args as Record<string, z.ZodTypeAny>;
|
|
330
|
+
const schemaZod = opts.schema || {};
|
|
331
|
+
const zodOptions = opts.zodOptions;
|
|
332
|
+
const keys = Object.keys(argZod || {});
|
|
333
|
+
if (argZod && keys.length > 0) {
|
|
334
|
+
const mgZod = z.object({
|
|
335
|
+
...argZod,
|
|
336
|
+
...schemaZod
|
|
337
|
+
});
|
|
338
|
+
return mgZod.safeParseAsync(data, zodOptions);
|
|
339
|
+
}
|
|
340
|
+
return Promise.resolve({ success: true, data });
|
|
341
|
+
}
|
|
318
342
|
/**
|
|
319
343
|
* 执行route
|
|
320
344
|
* @param path
|
|
@@ -332,6 +356,21 @@ export class QueryRouter<T extends SimpleObject = SimpleObject> implements throw
|
|
|
332
356
|
ctx.currentRoute = route;
|
|
333
357
|
ctx.index = (ctx.index || 0) + 1;
|
|
334
358
|
const progress = [path, key] as [string, string];
|
|
359
|
+
ctx.safeParseAsync = async (data?: any, opts?: { schema?: { [key: string]: z.ZodTypeAny }, zodOptions?: any, stop?: boolean }) => {
|
|
360
|
+
const stop = opts?.stop ?? true;
|
|
361
|
+
const _query = { ...ctx.query, ...data };
|
|
362
|
+
const res = await this.safeParseAsyncRoute(_query, { route: route, ...opts });
|
|
363
|
+
if (!res.success && stop) {
|
|
364
|
+
const issues = res.error.issues;
|
|
365
|
+
ctx.throw({
|
|
366
|
+
// Unprocessable Entity
|
|
367
|
+
code: 422,
|
|
368
|
+
data: issues,
|
|
369
|
+
message: 'Validation Error:' + JSON.stringify(issues, null, 2),
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
return res;
|
|
373
|
+
}
|
|
335
374
|
if (ctx.progress) {
|
|
336
375
|
ctx.progress.push(progress);
|
|
337
376
|
} else {
|
|
@@ -406,7 +445,7 @@ export class QueryRouter<T extends SimpleObject = SimpleObject> implements throw
|
|
|
406
445
|
if (e instanceof CustomError || e?.code) {
|
|
407
446
|
ctx.code = e.code;
|
|
408
447
|
ctx.message = e.message;
|
|
409
|
-
ctx.body =
|
|
448
|
+
ctx.body = e.data;
|
|
410
449
|
} else {
|
|
411
450
|
console.error(`[router error] fn:${route.path}-${route.key}:${route.rid}`);
|
|
412
451
|
console.error(`[router error] middleware:${middleware.path}-${middleware.key}:${middleware.rid}`);
|
|
@@ -427,6 +466,9 @@ export class QueryRouter<T extends SimpleObject = SimpleObject> implements throw
|
|
|
427
466
|
if (route) {
|
|
428
467
|
if (route.run) {
|
|
429
468
|
try {
|
|
469
|
+
if (route.metadata?.check) {
|
|
470
|
+
await ctx.safeParseAsync(null, { stop: true });
|
|
471
|
+
}
|
|
430
472
|
await route.run(ctx as Required<RouteContext<T>>);
|
|
431
473
|
} catch (e) {
|
|
432
474
|
if (route?.isDebug) {
|
|
@@ -437,13 +479,14 @@ export class QueryRouter<T extends SimpleObject = SimpleObject> implements throw
|
|
|
437
479
|
if (e instanceof CustomError || e?.code) {
|
|
438
480
|
ctx.code = e.code;
|
|
439
481
|
ctx.message = e.message;
|
|
482
|
+
ctx.body = e.data;
|
|
440
483
|
} else {
|
|
441
484
|
console.error(`[router error] fn:${route.path}-${route.key}:${route.rid}`);
|
|
442
485
|
console.error(`[router error] error`, e);
|
|
443
486
|
ctx.code = 500;
|
|
444
487
|
ctx.message = 'Internal Server Error';
|
|
488
|
+
ctx.body = null;
|
|
445
489
|
}
|
|
446
|
-
ctx.body = null;
|
|
447
490
|
return ctx;
|
|
448
491
|
}
|
|
449
492
|
if (ctx.end) {
|
package/src/test/route-ts.ts
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
import { QueryRouterServer } from "@/route.ts";
|
|
2
2
|
import z from "zod";
|
|
3
|
+
import { tr } from "zod/v4/locales";
|
|
3
4
|
|
|
4
5
|
const router = new QueryRouterServer()
|
|
5
6
|
|
|
6
7
|
router.route({
|
|
8
|
+
path: 'test',
|
|
7
9
|
metadata: {
|
|
8
10
|
args: {
|
|
9
11
|
a: z.string(),
|
|
10
|
-
}
|
|
12
|
+
},
|
|
13
|
+
check: true,
|
|
11
14
|
},
|
|
12
15
|
}).define(async (ctx) => {
|
|
13
|
-
const
|
|
16
|
+
const argZod = ctx.currentRoute.metadata.args as Record<string, z.ZodTypeAny>;
|
|
17
|
+
const mgZod = z.object(argZod);
|
|
18
|
+
// console.log('argZod', argZod);
|
|
19
|
+
// const argA: string = ctx.args.a;
|
|
20
|
+
// const res = await ctx.safeParseAsync(null, { stop: true });
|
|
21
|
+
// // console.log('argA', argA);
|
|
22
|
+
// if (!res.success) {
|
|
23
|
+
// console.log('res===', res.error.issues);
|
|
24
|
+
// }
|
|
14
25
|
ctx.body = '1';
|
|
15
|
-
}).addTo(router);
|
|
26
|
+
}).addTo(router);
|
|
27
|
+
|
|
28
|
+
const res = await router.run({ path: 'test', payload: { a: 'abc' } });
|
|
29
|
+
console.log('res', res);
|