@kevisual/router 0.0.83 → 0.0.84
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/agent/routes/index.ts +16 -10
- package/agent/routes/route-create.ts +3 -3
- package/dist/app.js +84 -58
- package/dist/opencode.d.ts +81 -81
- package/dist/opencode.js +10 -5
- package/dist/router-browser.d.ts +76 -50
- package/dist/router-browser.js +12 -13
- package/dist/router-define.d.ts +76 -50
- package/dist/router.d.ts +81 -81
- package/dist/router.js +14 -51
- package/dist/ws.d.ts +104 -68
- package/package.json +2 -2
- package/readme.md +78 -63
- package/src/app.ts +7 -50
- package/src/opencode.ts +12 -5
- package/src/route.ts +88 -60
- package/src/test/app-type.ts +66 -10
- package/src/test/chat.ts +1 -1
- package/src/test/route-ts.ts +15 -0
package/dist/ws.d.ts
CHANGED
|
@@ -80,9 +80,20 @@ type RouterContextT = {
|
|
|
80
80
|
code?: number;
|
|
81
81
|
[key: string]: any;
|
|
82
82
|
};
|
|
83
|
+
type BuildRouteContext<M, U> = M extends {
|
|
84
|
+
args?: infer A;
|
|
85
|
+
} ? A extends z.ZodObject<any> ? RouteContext<{
|
|
86
|
+
args?: z.infer<A>;
|
|
87
|
+
}, U> : A extends Record<string, z.ZodTypeAny> ? RouteContext<{
|
|
88
|
+
args?: {
|
|
89
|
+
[K in keyof A]: z.infer<A[K]>;
|
|
90
|
+
};
|
|
91
|
+
}, U> : RouteContext<U> : RouteContext<U>;
|
|
83
92
|
type RouteContext<T = {
|
|
84
93
|
code?: number;
|
|
85
|
-
},
|
|
94
|
+
}, U extends SimpleObject = {}, S = {
|
|
95
|
+
[key: string]: any;
|
|
96
|
+
}> = {
|
|
86
97
|
/**
|
|
87
98
|
* 本地自己调用的时候使用,可以标识为当前自调用,那么 auth 就不许重复的校验
|
|
88
99
|
* 或者不需要登录的,直接调用
|
|
@@ -105,7 +116,14 @@ type RouteContext<T = {
|
|
|
105
116
|
code?: number;
|
|
106
117
|
/** return msg */
|
|
107
118
|
message?: string;
|
|
119
|
+
/**
|
|
120
|
+
* 传递状态
|
|
121
|
+
*/
|
|
108
122
|
state?: S;
|
|
123
|
+
/**
|
|
124
|
+
* 当前routerId
|
|
125
|
+
*/
|
|
126
|
+
currentId?: string;
|
|
109
127
|
/**
|
|
110
128
|
* 当前路径
|
|
111
129
|
*/
|
|
@@ -146,14 +164,12 @@ type RouteContext<T = {
|
|
|
146
164
|
path: string;
|
|
147
165
|
key?: string;
|
|
148
166
|
payload?: any;
|
|
149
|
-
}, ctx?: RouteContext
|
|
150
|
-
[key: string]: any;
|
|
151
|
-
}) => Promise<any>;
|
|
167
|
+
}, ctx?: RouteContext) => Promise<any>;
|
|
152
168
|
index?: number;
|
|
153
169
|
throw?: throwError['throw'];
|
|
154
170
|
/** 是否需要序列化, 使用JSON.stringify和JSON.parse */
|
|
155
171
|
needSerialize?: boolean;
|
|
156
|
-
} & T;
|
|
172
|
+
} & T & U;
|
|
157
173
|
type SimpleObject = Record<string, any>;
|
|
158
174
|
type Run<T extends SimpleObject = {}> = (ctx: Required<RouteContext<T>>) => Promise<typeof ctx | null | void>;
|
|
159
175
|
type RunMessage = {
|
|
@@ -164,7 +180,7 @@ type RunMessage = {
|
|
|
164
180
|
};
|
|
165
181
|
type NextRoute = Pick<Route, 'id' | 'path' | 'key'>;
|
|
166
182
|
type RouteMiddleware = {
|
|
167
|
-
path
|
|
183
|
+
path?: string;
|
|
168
184
|
key?: string;
|
|
169
185
|
id?: string;
|
|
170
186
|
} | string;
|
|
@@ -191,9 +207,11 @@ type RouteOpts<U = {}, T = SimpleObject> = {
|
|
|
191
207
|
type DefineRouteOpts = Omit<RouteOpts, 'idUsePath' | 'nextRoute'>;
|
|
192
208
|
declare const pickValue: readonly ["path", "key", "id", "description", "type", "middleware", "metadata"];
|
|
193
209
|
type RouteInfo = Pick<Route, (typeof pickValue)[number]>;
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
210
|
+
/**
|
|
211
|
+
* @M 是 route的 metadate的类型,默认是 SimpleObject
|
|
212
|
+
* @U 是 RouteContext 里 state的类型
|
|
213
|
+
*/
|
|
214
|
+
declare class Route<M extends SimpleObject = SimpleObject, U extends SimpleObject = SimpleObject> implements throwError {
|
|
197
215
|
/**
|
|
198
216
|
* 一级路径
|
|
199
217
|
*/
|
|
@@ -203,10 +221,10 @@ declare class Route<U = {
|
|
|
203
221
|
*/
|
|
204
222
|
key?: string;
|
|
205
223
|
id?: string;
|
|
206
|
-
run?: Run
|
|
224
|
+
run?: Run<BuildRouteContext<M, U>>;
|
|
207
225
|
nextRoute?: NextRoute;
|
|
208
226
|
description?: string;
|
|
209
|
-
metadata?:
|
|
227
|
+
metadata?: M;
|
|
210
228
|
middleware?: RouteMiddleware[];
|
|
211
229
|
type?: string;
|
|
212
230
|
/**
|
|
@@ -221,13 +239,13 @@ declare class Route<U = {
|
|
|
221
239
|
} = RouterContextT>(opts: DefineRouteOpts): this;
|
|
222
240
|
define<T extends {
|
|
223
241
|
[key: string]: any;
|
|
224
|
-
} = RouterContextT>(fn: Run<T & U
|
|
242
|
+
} = RouterContextT>(fn: Run<T & BuildRouteContext<M, U>>): this;
|
|
225
243
|
define<T extends {
|
|
226
244
|
[key: string]: any;
|
|
227
|
-
} = RouterContextT>(key: string, fn: Run<T & U
|
|
245
|
+
} = RouterContextT>(key: string, fn: Run<T & BuildRouteContext<M, U>>): this;
|
|
228
246
|
define<T extends {
|
|
229
247
|
[key: string]: any;
|
|
230
|
-
} = RouterContextT>(path: string, key: string, fn: Run<T & U
|
|
248
|
+
} = RouterContextT>(path: string, key: string, fn: Run<T & BuildRouteContext<M, U>>): this;
|
|
231
249
|
update(opts: DefineRouteOpts, onlyUpdateList?: string[]): this;
|
|
232
250
|
addTo(router: QueryRouter | {
|
|
233
251
|
add: (route: Route) => void;
|
|
@@ -241,11 +259,11 @@ declare class Route<U = {
|
|
|
241
259
|
type AddOpts = {
|
|
242
260
|
overwrite?: boolean;
|
|
243
261
|
};
|
|
244
|
-
declare class QueryRouter implements throwError {
|
|
262
|
+
declare class QueryRouter<T extends SimpleObject = SimpleObject> implements throwError {
|
|
245
263
|
appId: string;
|
|
246
264
|
routes: Route[];
|
|
247
265
|
maxNextRoute: number;
|
|
248
|
-
context?: RouteContext
|
|
266
|
+
context?: RouteContext<T>;
|
|
249
267
|
constructor();
|
|
250
268
|
/**
|
|
251
269
|
* add route
|
|
@@ -273,7 +291,7 @@ declare class QueryRouter implements throwError {
|
|
|
273
291
|
* @param ctx
|
|
274
292
|
* @returns
|
|
275
293
|
*/
|
|
276
|
-
runRoute(path: string, key: string, ctx?: RouteContext):
|
|
294
|
+
runRoute(path: string, key: string, ctx?: RouteContext<T>): Promise<RouteContext<T>>;
|
|
277
295
|
/**
|
|
278
296
|
* 第一次执行
|
|
279
297
|
* @param message
|
|
@@ -284,9 +302,11 @@ declare class QueryRouter implements throwError {
|
|
|
284
302
|
path: string;
|
|
285
303
|
key?: string;
|
|
286
304
|
payload?: any;
|
|
287
|
-
}, ctx?: RouteContext & {
|
|
305
|
+
}, ctx?: RouteContext<T> & {
|
|
306
|
+
[key: string]: any;
|
|
307
|
+
}): Promise<RouteContext<T, {}, {
|
|
288
308
|
[key: string]: any;
|
|
289
|
-
}
|
|
309
|
+
}>>;
|
|
290
310
|
/**
|
|
291
311
|
* 返回的数据包含所有的context的请求返回的内容,可做其他处理
|
|
292
312
|
* @param message
|
|
@@ -298,9 +318,15 @@ declare class QueryRouter implements throwError {
|
|
|
298
318
|
path?: string;
|
|
299
319
|
key?: string;
|
|
300
320
|
payload?: any;
|
|
301
|
-
}, ctx?: RouteContext & {
|
|
321
|
+
}, ctx?: RouteContext<T> & {
|
|
322
|
+
[key: string]: any;
|
|
323
|
+
}): Promise<RouteContext<T, {}, {
|
|
302
324
|
[key: string]: any;
|
|
303
|
-
}
|
|
325
|
+
}> | {
|
|
326
|
+
code: number;
|
|
327
|
+
body: any;
|
|
328
|
+
message: string;
|
|
329
|
+
}>;
|
|
304
330
|
/**
|
|
305
331
|
* 请求 result 的数据
|
|
306
332
|
* @param message
|
|
@@ -316,9 +342,9 @@ declare class QueryRouter implements throwError {
|
|
|
316
342
|
}, ctx?: RouteContext & {
|
|
317
343
|
[key: string]: any;
|
|
318
344
|
}): Promise<{
|
|
319
|
-
code:
|
|
345
|
+
code: number;
|
|
320
346
|
data: any;
|
|
321
|
-
message:
|
|
347
|
+
message: string;
|
|
322
348
|
}>;
|
|
323
349
|
/**
|
|
324
350
|
* Router Run获取数据
|
|
@@ -331,12 +357,12 @@ declare class QueryRouter implements throwError {
|
|
|
331
357
|
path?: string;
|
|
332
358
|
key?: string;
|
|
333
359
|
payload?: any;
|
|
334
|
-
}, ctx?: RouteContext & {
|
|
360
|
+
}, ctx?: RouteContext<T> & {
|
|
335
361
|
[key: string]: any;
|
|
336
362
|
}): Promise<{
|
|
337
|
-
code:
|
|
363
|
+
code: number;
|
|
338
364
|
data: any;
|
|
339
|
-
message:
|
|
365
|
+
message: string;
|
|
340
366
|
}>;
|
|
341
367
|
/**
|
|
342
368
|
* 设置上下文
|
|
@@ -348,12 +374,12 @@ declare class QueryRouter implements throwError {
|
|
|
348
374
|
/**
|
|
349
375
|
* 获取handle函数, 这里会去执行parse函数
|
|
350
376
|
*/
|
|
351
|
-
getHandle<T = any>(router: QueryRouter, wrapperFn?: HandleFn
|
|
377
|
+
getHandle<T = any>(router: QueryRouter, wrapperFn?: HandleFn, ctx?: RouteContext): (msg: {
|
|
352
378
|
id?: string;
|
|
353
379
|
path?: string;
|
|
354
380
|
key?: string;
|
|
355
381
|
[key: string]: any;
|
|
356
|
-
}, handleContext?: RouteContext) => Promise<{
|
|
382
|
+
}, handleContext?: RouteContext<T>) => Promise<{
|
|
357
383
|
[key: string]: any;
|
|
358
384
|
code: string;
|
|
359
385
|
data?: any;
|
|
@@ -367,22 +393,16 @@ declare class QueryRouter implements throwError {
|
|
|
367
393
|
message: any;
|
|
368
394
|
data?: undefined;
|
|
369
395
|
}>;
|
|
370
|
-
exportRoutes(): Route<
|
|
371
|
-
[key: string]: any;
|
|
372
|
-
}, SimpleObject>[];
|
|
396
|
+
exportRoutes(): Route<SimpleObject, SimpleObject>[];
|
|
373
397
|
importRoutes(routes: Route[]): void;
|
|
374
398
|
importRouter(router: QueryRouter): void;
|
|
375
399
|
throw(...args: any[]): void;
|
|
376
|
-
hasRoute(path: string, key?: string): Route<
|
|
377
|
-
[key: string]: any;
|
|
378
|
-
}, SimpleObject>;
|
|
400
|
+
hasRoute(path: string, key?: string): Route<SimpleObject, SimpleObject>;
|
|
379
401
|
findRoute(opts?: {
|
|
380
402
|
path?: string;
|
|
381
403
|
key?: string;
|
|
382
404
|
id?: string;
|
|
383
|
-
}): Route<
|
|
384
|
-
[key: string]: any;
|
|
385
|
-
}, SimpleObject>;
|
|
405
|
+
}): Route<SimpleObject, SimpleObject>;
|
|
386
406
|
createRouteList(opts?: {
|
|
387
407
|
force?: boolean;
|
|
388
408
|
filter?: (route: Route) => boolean;
|
|
@@ -424,6 +444,12 @@ declare class QueryRouter implements throwError {
|
|
|
424
444
|
[key: string]: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
425
445
|
};
|
|
426
446
|
}
|
|
447
|
+
type QueryRouterServerOpts<C extends SimpleObject = SimpleObject> = {
|
|
448
|
+
handleFn?: HandleFn;
|
|
449
|
+
context?: RouteContext<C>;
|
|
450
|
+
appId?: string;
|
|
451
|
+
initHandle?: boolean;
|
|
452
|
+
};
|
|
427
453
|
interface HandleFn<T = any> {
|
|
428
454
|
(msg: {
|
|
429
455
|
path: string;
|
|
@@ -436,6 +462,42 @@ interface HandleFn<T = any> {
|
|
|
436
462
|
};
|
|
437
463
|
(res: RouteContext<T>): any;
|
|
438
464
|
}
|
|
465
|
+
/**
|
|
466
|
+
* QueryRouterServer
|
|
467
|
+
* @description 移除server相关的功能,只保留router相关的功能,和http.createServer不相关,独立
|
|
468
|
+
* @template C 自定义 RouteContext 类型
|
|
469
|
+
*/
|
|
470
|
+
declare class QueryRouterServer<C extends SimpleObject = SimpleObject> extends QueryRouter<C> {
|
|
471
|
+
appId: string;
|
|
472
|
+
handle: any;
|
|
473
|
+
context: RouteContext<C>;
|
|
474
|
+
constructor(opts?: QueryRouterServerOpts<C>);
|
|
475
|
+
setHandle(wrapperFn?: HandleFn, ctx?: RouteContext): void;
|
|
476
|
+
addRoute(route: Route, opts?: AddOpts): void;
|
|
477
|
+
Route: typeof Route;
|
|
478
|
+
route<M extends SimpleObject = SimpleObject>(opts: RouteOpts & {
|
|
479
|
+
metadata?: M;
|
|
480
|
+
}): Route<M, Required<RouteContext<C>>>;
|
|
481
|
+
route<M extends SimpleObject = SimpleObject>(path: string, opts?: RouteOpts & {
|
|
482
|
+
metadata?: M;
|
|
483
|
+
}): Route<M, Required<RouteContext<C>>>;
|
|
484
|
+
route<M extends SimpleObject = SimpleObject>(path: string, key?: string): Route<M, Required<RouteContext<C>>>;
|
|
485
|
+
route<M extends SimpleObject = SimpleObject>(path: string, key?: string, opts?: RouteOpts & {
|
|
486
|
+
metadata?: M;
|
|
487
|
+
}): Route<M, Required<RouteContext<C>>>;
|
|
488
|
+
prompt(description: string): Route<SimpleObject, SimpleObject>;
|
|
489
|
+
/**
|
|
490
|
+
* 调用了handle
|
|
491
|
+
* @param param0
|
|
492
|
+
* @returns
|
|
493
|
+
*/
|
|
494
|
+
run(msg: {
|
|
495
|
+
id?: string;
|
|
496
|
+
path?: string;
|
|
497
|
+
key?: string;
|
|
498
|
+
payload?: any;
|
|
499
|
+
}, ctx?: Partial<RouteContext<C>>): Promise<any>;
|
|
500
|
+
}
|
|
439
501
|
|
|
440
502
|
type Cors = {
|
|
441
503
|
/**
|
|
@@ -685,7 +747,7 @@ type RouterHandle = (msg: {
|
|
|
685
747
|
[key: string]: any;
|
|
686
748
|
};
|
|
687
749
|
type AppOptions<T = {}> = {
|
|
688
|
-
router?:
|
|
750
|
+
router?: QueryRouterServer;
|
|
689
751
|
server?: ServerType;
|
|
690
752
|
/** handle msg 关联 */
|
|
691
753
|
routerHandle?: RouterHandle;
|
|
@@ -693,17 +755,18 @@ type AppOptions<T = {}> = {
|
|
|
693
755
|
serverOptions?: ServerNodeOpts;
|
|
694
756
|
appId?: string;
|
|
695
757
|
};
|
|
696
|
-
type AppRouteContext<T
|
|
758
|
+
type AppRouteContext<T> = HandleCtx & RouteContext<T> & {
|
|
697
759
|
app: App<T>;
|
|
698
760
|
};
|
|
699
761
|
/**
|
|
700
762
|
* 封装了 Router 和 Server 的 App 模块,处理http的请求和响应,内置了 Cookie 和 Token 和 res 的处理
|
|
701
763
|
* U - Route Context的扩展类型
|
|
702
764
|
*/
|
|
703
|
-
declare class App<U = {}> extends
|
|
765
|
+
declare class App<U = {}> extends QueryRouterServer<AppRouteContext<U>> {
|
|
704
766
|
appId: string;
|
|
705
|
-
router:
|
|
767
|
+
router: QueryRouterServer;
|
|
706
768
|
server: ServerType;
|
|
769
|
+
context: AppRouteContext<U>;
|
|
707
770
|
constructor(opts?: AppOptions<U>);
|
|
708
771
|
listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): void;
|
|
709
772
|
listen(port: number, hostname?: string, listeningListener?: () => void): void;
|
|
@@ -713,34 +776,7 @@ declare class App<U = {}> extends QueryRouter {
|
|
|
713
776
|
listen(path: string, listeningListener?: () => void): void;
|
|
714
777
|
listen(handle: any, backlog?: number, listeningListener?: () => void): void;
|
|
715
778
|
listen(handle: any, listeningListener?: () => void): void;
|
|
716
|
-
addRoute(route: Route, opts?: AddOpts): void;
|
|
717
779
|
Route: typeof Route;
|
|
718
|
-
route(opts: RouteOpts<AppRouteContext<U>>): Route<AppRouteContext<U>>;
|
|
719
|
-
route(path: string, key?: string): Route<AppRouteContext<U>>;
|
|
720
|
-
route(path: string, opts?: RouteOpts<AppRouteContext<U>>): Route<AppRouteContext<U>>;
|
|
721
|
-
route(path: string, key?: string, opts?: RouteOpts<AppRouteContext<U>>): Route<AppRouteContext<U>>;
|
|
722
|
-
prompt(description: string): Route<AppRouteContext<U>>;
|
|
723
|
-
prompt(description: Function): Route<AppRouteContext<U>>;
|
|
724
|
-
call(message: {
|
|
725
|
-
id?: string;
|
|
726
|
-
path?: string;
|
|
727
|
-
key?: string;
|
|
728
|
-
payload?: any;
|
|
729
|
-
}, ctx?: AppRouteContext<U> & {
|
|
730
|
-
[key: string]: any;
|
|
731
|
-
}): Promise<any>;
|
|
732
|
-
run(msg: {
|
|
733
|
-
id?: string;
|
|
734
|
-
path?: string;
|
|
735
|
-
key?: string;
|
|
736
|
-
payload?: any;
|
|
737
|
-
}, ctx?: Partial<AppRouteContext<U>> & {
|
|
738
|
-
[key: string]: any;
|
|
739
|
-
}): Promise<{
|
|
740
|
-
code: any;
|
|
741
|
-
data: any;
|
|
742
|
-
message: any;
|
|
743
|
-
}>;
|
|
744
780
|
static handleRequest(req: IncomingMessage$1, res: ServerResponse$1): Promise<{
|
|
745
781
|
cookies: Record<string, string>;
|
|
746
782
|
token: string;
|
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.0.
|
|
4
|
+
"version": "0.0.84",
|
|
5
5
|
"description": "",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/router.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@types/xml2js": "^0.4.14",
|
|
38
38
|
"eventemitter3": "^5.0.4",
|
|
39
39
|
"fast-glob": "^3.3.3",
|
|
40
|
-
"hono": "^4.12.
|
|
40
|
+
"hono": "^4.12.2",
|
|
41
41
|
"nanoid": "^5.1.6",
|
|
42
42
|
"path-to-regexp": "^8.3.0",
|
|
43
43
|
"send": "^1.2.1",
|
package/readme.md
CHANGED
|
@@ -31,63 +31,58 @@ app
|
|
|
31
31
|
|
|
32
32
|
在 route handler 中,你可以通过 `ctx` 访问以下属性:
|
|
33
33
|
|
|
34
|
-
| 属性
|
|
35
|
-
|
|
36
|
-
| `query`
|
|
37
|
-
| `body`
|
|
38
|
-
| `code`
|
|
39
|
-
| `message`
|
|
40
|
-
| `state`
|
|
41
|
-
| `appId`
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
| `
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
34
|
+
| 属性 | 类型 | 说明 |
|
|
35
|
+
| --------------- | ---------------------------- | ---------------------------- |
|
|
36
|
+
| `query` | `object` | 请求参数,会自动合并 payload |
|
|
37
|
+
| `body` | `number \| string \| Object` | 响应内容 |
|
|
38
|
+
| `code` | `number` | 响应状态码,默认为 200 |
|
|
39
|
+
| `message` | `string` | 响应消息 |
|
|
40
|
+
| `state` | `any` | 状态数据,可在路由间传递 |
|
|
41
|
+
| `appId` | `string` | 应用标识 |
|
|
42
|
+
| `currentId` | `string` | 当前路由ID |
|
|
43
|
+
| `currentPath` | `string` | 当前路由路径 |
|
|
44
|
+
| `currentKey` | `string` | 当前路由 key |
|
|
45
|
+
| `currentRoute` | `Route` | 当前 Route 实例 |
|
|
46
|
+
| `progress` | `[string, string][]` | 路由执行路径记录 |
|
|
47
|
+
| `nextQuery` | `object` | 传递给下一个路由的参数 |
|
|
48
|
+
| `end` | `boolean` | 是否提前结束路由执行 |
|
|
49
|
+
| `app` | `QueryRouter` | 路由实例引用 |
|
|
50
|
+
| `error` | `any` | 错误信息 |
|
|
51
|
+
| `index` | `number` | 当前路由执行深度 |
|
|
52
|
+
| `needSerialize` | `boolean` | 是否需要序列化响应数据 |
|
|
52
53
|
|
|
53
54
|
### 上下文方法
|
|
54
55
|
|
|
55
|
-
| 方法
|
|
56
|
-
|
|
57
|
-
| `ctx.call(msg, ctx?)`
|
|
58
|
-
| `ctx.run(msg, ctx?)`
|
|
59
|
-
| `ctx.forward(res)`
|
|
60
|
-
| `ctx.throw(code?, message?, tips?)` | -
|
|
56
|
+
| 方法 | 参数 | 说明 |
|
|
57
|
+
| ----------------------------------- | ----------------------------------------- | -------------------------------------------- |
|
|
58
|
+
| `ctx.call(msg, ctx?)` | `{ path, key?, payload?, ... } \| { id }` | 调用其他路由,返回完整 context |
|
|
59
|
+
| `ctx.run(msg, ctx?)` | `{ path, key?, payload? }` | 调用其他路由,返回 `{ code, data, message }` |
|
|
60
|
+
| `ctx.forward(res)` | `{ code, data?, message? }` | 设置响应结果 |
|
|
61
|
+
| `ctx.throw(code?, message?, tips?)` | - | 抛出自定义错误 |
|
|
61
62
|
|
|
62
63
|
## 完整示例
|
|
63
64
|
|
|
64
65
|
```ts
|
|
65
66
|
import { App } from '@kevisual/router';
|
|
66
|
-
|
|
67
|
+
import z from 'zod';
|
|
67
68
|
const app = new App();
|
|
68
69
|
app.listen(4002);
|
|
69
70
|
|
|
70
71
|
// 基本路由
|
|
71
72
|
app
|
|
72
|
-
.route({ path: 'user', key: 'info' })
|
|
73
|
+
.route({ path: 'user', key: 'info', id: 'user-info' })
|
|
73
74
|
.define(async (ctx) => {
|
|
74
75
|
// ctx.query 包含请求参数
|
|
75
76
|
const { id } = ctx.query;
|
|
77
|
+
// 使用 state 在路由间传递数据
|
|
78
|
+
ctx.state.orderId = '12345';
|
|
76
79
|
ctx.body = { id, name: '张三' };
|
|
77
80
|
ctx.code = 200;
|
|
78
81
|
})
|
|
79
82
|
.addTo(app);
|
|
80
83
|
|
|
81
|
-
// 使用 state 在路由间传递数据
|
|
82
|
-
app
|
|
83
|
-
.route({ path: 'order', key: 'create' })
|
|
84
|
-
.define(async (ctx) => {
|
|
85
|
-
ctx.state = { orderId: '12345' };
|
|
86
|
-
})
|
|
87
|
-
.addTo(app);
|
|
88
|
-
|
|
89
84
|
app
|
|
90
|
-
.route({ path: 'order', key: 'pay' })
|
|
85
|
+
.route({ path: 'order', key: 'pay', middleware: ['user-info'] })
|
|
91
86
|
.define(async (ctx) => {
|
|
92
87
|
// 可以获取前一个路由设置的 state
|
|
93
88
|
const { orderId } = ctx.state;
|
|
@@ -95,14 +90,6 @@ app
|
|
|
95
90
|
})
|
|
96
91
|
.addTo(app);
|
|
97
92
|
|
|
98
|
-
// 链式调用
|
|
99
|
-
app
|
|
100
|
-
.route({ path: 'product', key: 'list' })
|
|
101
|
-
.define(async (ctx) => {
|
|
102
|
-
ctx.body = [{ id: 1, name: '商品A' }];
|
|
103
|
-
})
|
|
104
|
-
.addTo(app);
|
|
105
|
-
|
|
106
93
|
// 调用其他路由
|
|
107
94
|
app
|
|
108
95
|
.route({ path: 'dashboard', key: 'stats' })
|
|
@@ -114,7 +101,7 @@ app
|
|
|
114
101
|
|
|
115
102
|
ctx.body = {
|
|
116
103
|
user: userRes.data,
|
|
117
|
-
products: productRes.data
|
|
104
|
+
products: productRes.data,
|
|
118
105
|
};
|
|
119
106
|
})
|
|
120
107
|
.addTo(app);
|
|
@@ -140,17 +127,20 @@ import { App, Route } from '@kevisual/router';
|
|
|
140
127
|
const app = new App();
|
|
141
128
|
|
|
142
129
|
// 定义中间件
|
|
143
|
-
app
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
130
|
+
app
|
|
131
|
+
.route({
|
|
132
|
+
id: 'auth-example',
|
|
133
|
+
description: '权限校验中间件',
|
|
134
|
+
})
|
|
135
|
+
.define(async (ctx) => {
|
|
136
|
+
const token = ctx.query.token;
|
|
137
|
+
if (!token) {
|
|
138
|
+
ctx.throw(401, '未登录', '需要 token');
|
|
139
|
+
}
|
|
140
|
+
// 验证通过,设置用户信息到 state
|
|
141
|
+
ctx.state.tokenUser = { id: 1, name: '用户A' };
|
|
142
|
+
})
|
|
143
|
+
.addTo(app);
|
|
154
144
|
|
|
155
145
|
// 使用中间件(通过 id 引用)
|
|
156
146
|
app
|
|
@@ -163,6 +153,33 @@ app
|
|
|
163
153
|
.addTo(app);
|
|
164
154
|
```
|
|
165
155
|
|
|
156
|
+
## 一个丰富的router示例
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { App } from '@kevisual/router';
|
|
160
|
+
const app = new App();
|
|
161
|
+
|
|
162
|
+
app
|
|
163
|
+
.router({
|
|
164
|
+
path: 'dog',
|
|
165
|
+
key: 'info',
|
|
166
|
+
description: '获取狗的信息',
|
|
167
|
+
metedata: {
|
|
168
|
+
args: {
|
|
169
|
+
owner: z.string().describe('狗主人姓名'),
|
|
170
|
+
age: z.number().describe('狗的年龄'),
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
})
|
|
174
|
+
.define(async (ctx) => {
|
|
175
|
+
const { owner, age } = ctx.query;
|
|
176
|
+
ctx.body = {
|
|
177
|
+
content: `这是一只${age}岁的狗,主人是${owner}`,
|
|
178
|
+
};
|
|
179
|
+
})
|
|
180
|
+
.addTo(app);
|
|
181
|
+
```
|
|
182
|
+
|
|
166
183
|
## 注意事项
|
|
167
184
|
|
|
168
185
|
1. **path 和 key 的组合是路由的唯一标识**,同一个 path+key 只能添加一个路由,后添加的会覆盖之前的。
|
|
@@ -173,16 +190,14 @@ app
|
|
|
173
190
|
|
|
174
191
|
3. **ctx.throw 会自动结束执行**,抛出自定义错误。
|
|
175
192
|
|
|
176
|
-
4. **
|
|
177
|
-
|
|
178
|
-
5. **payload 会自动合并到 query**,调用 `ctx.run({ path, key, payload })` 时,payload 会合并到 query。
|
|
193
|
+
4. **payload 会自动合并到 query**,调用 `ctx.run({ path, key, payload })` 时,payload 会合并到 query。
|
|
179
194
|
|
|
180
|
-
|
|
195
|
+
5. **nextQuery 用于传递给 nextRoute**,在当前路由中设置 `ctx.nextQuery`,会在执行 nextRoute 时合并到 query。
|
|
181
196
|
|
|
182
|
-
|
|
197
|
+
6. **避免 nextRoute 循环调用**,默认最大深度为 40 次,超过会返回 500 错误。
|
|
183
198
|
|
|
184
|
-
|
|
199
|
+
7. **needSerialize 默认为 true**,会自动对 body 进行 JSON 序列化和反序列化。
|
|
185
200
|
|
|
186
|
-
|
|
201
|
+
8. **progress 记录执行路径**,可用于调试和追踪路由调用链。
|
|
187
202
|
|
|
188
|
-
|
|
203
|
+
9. **中间件找不到会返回 404**,错误信息中会包含找不到的中间件列表。
|
package/src/app.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AddOpts, QueryRouter, Route, RouteContext, RouteOpts } from './route.ts';
|
|
1
|
+
import { AddOpts, QueryRouter, QueryRouterServer, Route, RouteContext, RouteOpts } from './route.ts';
|
|
2
2
|
import { ServerNode, ServerNodeOpts } from './server/server.ts';
|
|
3
3
|
import { HandleCtx } from './server/server-base.ts';
|
|
4
4
|
import { ServerType } from './server/server-type.ts';
|
|
@@ -10,7 +10,7 @@ import { randomId } from './utils/random.ts';
|
|
|
10
10
|
|
|
11
11
|
type RouterHandle = (msg: { path: string;[key: string]: any }) => { code: string; data?: any; message?: string;[key: string]: any };
|
|
12
12
|
type AppOptions<T = {}> = {
|
|
13
|
-
router?:
|
|
13
|
+
router?: QueryRouterServer;
|
|
14
14
|
server?: ServerType;
|
|
15
15
|
/** handle msg 关联 */
|
|
16
16
|
routerHandle?: RouterHandle;
|
|
@@ -19,18 +19,19 @@ type AppOptions<T = {}> = {
|
|
|
19
19
|
appId?: string;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
export type AppRouteContext<T
|
|
22
|
+
export type AppRouteContext<T> = HandleCtx & RouteContext<T> & { app: App<T> };
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* 封装了 Router 和 Server 的 App 模块,处理http的请求和响应,内置了 Cookie 和 Token 和 res 的处理
|
|
26
26
|
* U - Route Context的扩展类型
|
|
27
27
|
*/
|
|
28
|
-
export class App<U = {}> extends
|
|
28
|
+
export class App<U = {}> extends QueryRouterServer<AppRouteContext<U>> {
|
|
29
29
|
declare appId: string;
|
|
30
|
-
router:
|
|
30
|
+
router: QueryRouterServer;
|
|
31
31
|
server: ServerType;
|
|
32
|
+
declare context: AppRouteContext<U>;
|
|
32
33
|
constructor(opts?: AppOptions<U>) {
|
|
33
|
-
super();
|
|
34
|
+
super({ initHandle: false, context: { needSerialize: true, ...opts?.routerContext } as any });
|
|
34
35
|
const router = this;
|
|
35
36
|
let server = opts?.server;
|
|
36
37
|
if (!server) {
|
|
@@ -42,7 +43,6 @@ export class App<U = {}> extends QueryRouter {
|
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
server.setHandle(router.getHandle(router, opts?.routerHandle, opts?.routerContext));
|
|
45
|
-
router.setContext({ needSerialize: true, ...opts?.routerContext });
|
|
46
46
|
this.router = router;
|
|
47
47
|
this.server = server;
|
|
48
48
|
if (opts?.appId) {
|
|
@@ -64,50 +64,7 @@ export class App<U = {}> extends QueryRouter {
|
|
|
64
64
|
// @ts-ignore
|
|
65
65
|
this.server.listen(...args);
|
|
66
66
|
}
|
|
67
|
-
addRoute(route: Route, opts?: AddOpts) {
|
|
68
|
-
super.add(route, opts);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
67
|
Route = Route;
|
|
72
|
-
route(opts: RouteOpts<AppRouteContext<U>>): Route<AppRouteContext<U>>;
|
|
73
|
-
route(path: string, key?: string): Route<AppRouteContext<U>>;
|
|
74
|
-
route(path: string, opts?: RouteOpts<AppRouteContext<U>>): Route<AppRouteContext<U>>;
|
|
75
|
-
route(path: string, key?: string, opts?: RouteOpts<AppRouteContext<U>>): Route<AppRouteContext<U>>;
|
|
76
|
-
route(...args: any[]) {
|
|
77
|
-
const [path, key, opts] = args;
|
|
78
|
-
if (typeof path === 'object') {
|
|
79
|
-
return new Route(path.path, path.key, path);
|
|
80
|
-
}
|
|
81
|
-
if (typeof path === 'string') {
|
|
82
|
-
if (opts) {
|
|
83
|
-
return new Route(path, key, opts);
|
|
84
|
-
}
|
|
85
|
-
if (key && typeof key === 'object') {
|
|
86
|
-
return new Route(path, key?.key || '', key);
|
|
87
|
-
}
|
|
88
|
-
return new Route(path, key);
|
|
89
|
-
}
|
|
90
|
-
return new Route(path, key, opts);
|
|
91
|
-
}
|
|
92
|
-
prompt(description: string): Route<AppRouteContext<U>>
|
|
93
|
-
prompt(description: Function): Route<AppRouteContext<U>>
|
|
94
|
-
prompt(...args: any[]) {
|
|
95
|
-
const [desc] = args;
|
|
96
|
-
let description = ''
|
|
97
|
-
if (typeof desc === 'string') {
|
|
98
|
-
description = desc;
|
|
99
|
-
} else if (typeof desc === 'function') {
|
|
100
|
-
description = desc() || ''; // 如果是Promise,需要addTo App之前就要获取应有的函数了。
|
|
101
|
-
}
|
|
102
|
-
return new Route('', '', { description });
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async call(message: { id?: string, path?: string; key?: string; payload?: any }, ctx?: AppRouteContext<U> & { [key: string]: any }) {
|
|
106
|
-
return await super.call(message, ctx);
|
|
107
|
-
}
|
|
108
|
-
async run(msg: { id?: string, path?: string; key?: string; payload?: any }, ctx?: Partial<AppRouteContext<U>> & { [key: string]: any }) {
|
|
109
|
-
return await super.run(msg, ctx);
|
|
110
|
-
}
|
|
111
68
|
static handleRequest(req: IncomingMessage, res: ServerResponse) {
|
|
112
69
|
return handleServer(req, res);
|
|
113
70
|
}
|