@kevisual/router 0.2.11 → 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/dist/app.js +1271 -550
- package/dist/commander.d.ts +53 -38
- package/dist/commander.js +1211 -492
- package/dist/opencode.d.ts +53 -38
- package/dist/opencode.js +1209 -488
- package/dist/router-browser.d.ts +53 -38
- package/dist/router-browser.js +1238 -519
- package/dist/router-define.d.ts +53 -38
- package/dist/router-simple.js +1 -1
- package/dist/router.d.ts +53 -38
- package/dist/router.js +1261 -540
- package/dist/ws.d.ts +53 -38
- package/dist/ws.js +14 -14
- package/package.json +11 -10
- package/src/result/error.ts +4 -0
- package/src/route.ts +52 -36
- package/src/test/app-type.ts +1 -1
- package/src/test/route-ts.ts +17 -3
- package/src/test/run-schema.ts +15 -1
- package/src/types/index.ts +39 -0
- package/src/test/chat.ts +0 -17
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 数组,可直接用于前端表单错误展示。
|