@kevisual/router 0.0.10-beta.1 → 0.0.11
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/router-browser.d.ts +18 -2
- package/dist/router-browser.js +9 -1
- package/dist/router-simple.d.ts +6 -3
- package/dist/router-simple.js +7 -3
- package/dist/router.d.ts +27 -7
- package/dist/router.js +24 -9
- package/package.json +12 -10
- package/src/app.ts +103 -0
- package/src/browser.ts +9 -0
- package/src/connect.ts +67 -0
- package/src/index.ts +16 -0
- package/src/io.ts +6 -0
- package/src/mod.ts +13 -0
- package/src/result/error.ts +67 -0
- package/src/result/index.ts +1 -0
- package/src/route.ts +714 -0
- package/src/router-simple-lib.ts +3 -0
- package/src/router-simple.ts +76 -0
- package/src/server/deno-ws-server.ts +0 -0
- package/src/server/handle-server.ts +57 -0
- package/src/server/index.ts +2 -0
- package/src/server/parse-body.ts +24 -0
- package/src/server/parse-xml.ts +31 -0
- package/src/server/server.ts +233 -0
- package/src/server/ws-server.ts +160 -0
- package/src/sign.ts +46 -0
- package/src/static.ts +97 -0
- package/src/utils/parse.ts +13 -0
- package/src/utils/pick.ts +9 -0
- package/src/utils/route-map.ts +47 -0
- package/src/validator/index.ts +1 -0
- package/src/validator/rule.ts +95 -0
package/dist/router-browser.d.ts
CHANGED
|
@@ -55,14 +55,29 @@ type RouteContext<T = {
|
|
|
55
55
|
/** return msg */
|
|
56
56
|
message?: string;
|
|
57
57
|
state?: S;
|
|
58
|
+
/**
|
|
59
|
+
* 当前路径
|
|
60
|
+
*/
|
|
58
61
|
currentPath?: string;
|
|
62
|
+
/**
|
|
63
|
+
* 当前key
|
|
64
|
+
*/
|
|
59
65
|
currentKey?: string;
|
|
66
|
+
/**
|
|
67
|
+
* 当前route
|
|
68
|
+
*/
|
|
60
69
|
currentRoute?: Route;
|
|
61
|
-
|
|
70
|
+
/**
|
|
71
|
+
* 进度
|
|
72
|
+
*/
|
|
73
|
+
progress?: [string, string][];
|
|
62
74
|
nextQuery?: {
|
|
63
75
|
[key: string]: any;
|
|
64
76
|
};
|
|
65
77
|
end?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* 请求 route的返回结果,包函ctx
|
|
80
|
+
*/
|
|
66
81
|
queryRouter?: QueryRouter;
|
|
67
82
|
error?: any;
|
|
68
83
|
/** 请求 route的返回结果,包函ctx */
|
|
@@ -391,4 +406,5 @@ declare class CustomError extends Error {
|
|
|
391
406
|
};
|
|
392
407
|
}
|
|
393
408
|
|
|
394
|
-
export { CustomError, QueryRouter, QueryRouterServer, Route,
|
|
409
|
+
export { CustomError, QueryRouter, QueryRouterServer, Route, createSchema };
|
|
410
|
+
export type { RouteContext, RouteOpts, Rule, Run };
|
package/dist/router-browser.js
CHANGED
|
@@ -5868,6 +5868,13 @@ class QueryRouter {
|
|
|
5868
5868
|
ctx.currentKey = key;
|
|
5869
5869
|
ctx.currentRoute = route;
|
|
5870
5870
|
ctx.index = (ctx.index || 0) + 1;
|
|
5871
|
+
const progress = [path, key];
|
|
5872
|
+
if (ctx.progress) {
|
|
5873
|
+
ctx.progress.push(progress);
|
|
5874
|
+
}
|
|
5875
|
+
else {
|
|
5876
|
+
ctx.progress = [progress];
|
|
5877
|
+
}
|
|
5871
5878
|
if (ctx.index > maxNextRoute) {
|
|
5872
5879
|
ctx.code = 500;
|
|
5873
5880
|
ctx.message = 'Too many nextRoute';
|
|
@@ -6054,7 +6061,7 @@ class QueryRouter {
|
|
|
6054
6061
|
const { path, key = '', payload = {}, ...query } = message;
|
|
6055
6062
|
ctx = ctx || {};
|
|
6056
6063
|
ctx.query = { ...ctx.query, ...query, ...payload };
|
|
6057
|
-
ctx.state = {};
|
|
6064
|
+
ctx.state = { ...ctx?.state };
|
|
6058
6065
|
ctx.throw = this.throw;
|
|
6059
6066
|
// put queryRouter to ctx
|
|
6060
6067
|
// TODO: 是否需要queryRouter,函数内部处理router路由执行,这应该是避免去内部去包含的功能过
|
|
@@ -6062,6 +6069,7 @@ class QueryRouter {
|
|
|
6062
6069
|
ctx.call = this.call.bind(this);
|
|
6063
6070
|
ctx.queryRoute = this.queryRoute.bind(this);
|
|
6064
6071
|
ctx.index = 0;
|
|
6072
|
+
ctx.progress = ctx.progress || [];
|
|
6065
6073
|
const res = await this.runRoute(path, key, ctx);
|
|
6066
6074
|
const serialize = ctx.needSerialize ?? true; // 是否需要序列化
|
|
6067
6075
|
if (serialize) {
|
package/dist/router-simple.d.ts
CHANGED
|
@@ -16,8 +16,11 @@ interface Route {
|
|
|
16
16
|
*/
|
|
17
17
|
declare class SimpleRouter {
|
|
18
18
|
routes: Route[];
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
exclude: string[];
|
|
20
|
+
constructor(opts?: {
|
|
21
|
+
exclude?: string[];
|
|
22
|
+
});
|
|
23
|
+
getBody(req: Req): Promise<Record<string, any>>;
|
|
21
24
|
getSearch(req: Req): querystring.ParsedUrlQuery;
|
|
22
25
|
use(method: string, route: string, ...fns: Array<(req: Req, res: ServerResponse) => Promise<void> | void>): this;
|
|
23
26
|
get(route: string, ...fns: Array<(req: Req, res: ServerResponse) => Promise<void> | void>): this;
|
|
@@ -29,7 +32,7 @@ declare class SimpleRouter {
|
|
|
29
32
|
* @param res
|
|
30
33
|
* @returns
|
|
31
34
|
*/
|
|
32
|
-
parse(req: Req, res: ServerResponse): Promise<void> | "not_found";
|
|
35
|
+
parse(req: Req, res: ServerResponse): Promise<void> | "is_exclude" | "not_found";
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
export { SimpleRouter };
|
package/dist/router-simple.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import url from 'url';
|
|
1
|
+
import url from 'node:url';
|
|
2
2
|
|
|
3
3
|
var dist = {};
|
|
4
4
|
|
|
@@ -441,8 +441,9 @@ const parseSearch = (req) => {
|
|
|
441
441
|
*/
|
|
442
442
|
class SimpleRouter {
|
|
443
443
|
routes = [];
|
|
444
|
-
|
|
445
|
-
|
|
444
|
+
exclude = []; // 排除的请求
|
|
445
|
+
constructor(opts) {
|
|
446
|
+
this.exclude = opts?.exclude || ['/api/router'];
|
|
446
447
|
}
|
|
447
448
|
getBody(req) {
|
|
448
449
|
return parseBody(req);
|
|
@@ -476,6 +477,9 @@ class SimpleRouter {
|
|
|
476
477
|
parse(req, res) {
|
|
477
478
|
const { pathname } = new URL(req.url, 'http://localhost');
|
|
478
479
|
const method = req.method.toLowerCase();
|
|
480
|
+
if (this.exclude.includes(pathname)) {
|
|
481
|
+
return 'is_exclude';
|
|
482
|
+
}
|
|
479
483
|
const route = this.routes.find((route) => {
|
|
480
484
|
const matchResult = route.regexp.exec(pathname);
|
|
481
485
|
if (matchResult && route.method === method) {
|
package/dist/router.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Schema } from 'zod';
|
|
2
2
|
export { Schema } from 'zod';
|
|
3
|
-
import http, { IncomingMessage, ServerResponse } from 'http';
|
|
4
|
-
import https from 'https';
|
|
5
|
-
import http2 from 'http2';
|
|
3
|
+
import http, { IncomingMessage, ServerResponse } from 'node:http';
|
|
4
|
+
import https from 'node:https';
|
|
5
|
+
import http2 from 'node:http2';
|
|
6
6
|
import * as cookie from 'cookie';
|
|
7
7
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
8
8
|
|
|
@@ -60,14 +60,29 @@ type RouteContext<T = {
|
|
|
60
60
|
/** return msg */
|
|
61
61
|
message?: string;
|
|
62
62
|
state?: S;
|
|
63
|
+
/**
|
|
64
|
+
* 当前路径
|
|
65
|
+
*/
|
|
63
66
|
currentPath?: string;
|
|
67
|
+
/**
|
|
68
|
+
* 当前key
|
|
69
|
+
*/
|
|
64
70
|
currentKey?: string;
|
|
71
|
+
/**
|
|
72
|
+
* 当前route
|
|
73
|
+
*/
|
|
65
74
|
currentRoute?: Route;
|
|
66
|
-
|
|
75
|
+
/**
|
|
76
|
+
* 进度
|
|
77
|
+
*/
|
|
78
|
+
progress?: [string, string][];
|
|
67
79
|
nextQuery?: {
|
|
68
80
|
[key: string]: any;
|
|
69
81
|
};
|
|
70
82
|
end?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* 请求 route的返回结果,包函ctx
|
|
85
|
+
*/
|
|
71
86
|
queryRouter?: QueryRouter;
|
|
72
87
|
error?: any;
|
|
73
88
|
/** 请求 route的返回结果,包函ctx */
|
|
@@ -457,7 +472,7 @@ declare class Server {
|
|
|
457
472
|
listen(path: string, listeningListener?: () => void): void;
|
|
458
473
|
listen(handle: any, backlog?: number, listeningListener?: () => void): void;
|
|
459
474
|
listen(handle: any, listeningListener?: () => void): void;
|
|
460
|
-
createServer(): http.Server<typeof
|
|
475
|
+
createServer(): http.Server<typeof IncomingMessage, typeof ServerResponse> | https.Server<typeof IncomingMessage, typeof ServerResponse> | http2.Http2SecureServer<typeof IncomingMessage, typeof ServerResponse, typeof http2.Http2ServerRequest, typeof http2.Http2ServerResponse>;
|
|
461
476
|
setHandle(handle?: any): void;
|
|
462
477
|
/**
|
|
463
478
|
* get callback
|
|
@@ -473,11 +488,15 @@ declare class Server {
|
|
|
473
488
|
*/
|
|
474
489
|
on(listener: Listener | Listener[]): void;
|
|
475
490
|
get callback(): any;
|
|
476
|
-
get server(): http.Server<typeof
|
|
491
|
+
get server(): http.Server<typeof IncomingMessage, typeof ServerResponse> | https.Server<typeof IncomingMessage, typeof ServerResponse> | http2.Http2SecureServer<typeof IncomingMessage, typeof ServerResponse, typeof http2.Http2ServerRequest, typeof http2.Http2ServerResponse>;
|
|
477
492
|
}
|
|
478
493
|
|
|
479
494
|
/**
|
|
480
495
|
* get params and body
|
|
496
|
+
* 优先原则
|
|
497
|
+
* 1. 请求参数中的 payload 的token 优先
|
|
498
|
+
* 2. 请求头中的 authorization 优先
|
|
499
|
+
* 3. 请求头中的 cookie 优先
|
|
481
500
|
* @param req
|
|
482
501
|
* @param res
|
|
483
502
|
* @returns
|
|
@@ -610,4 +629,5 @@ declare class App<T = {}, U = AppReqRes> {
|
|
|
610
629
|
throw(code?: number | string, message?: string, tips?: string): void;
|
|
611
630
|
}
|
|
612
631
|
|
|
613
|
-
export { App, Connect, CustomError, QueryConnect, QueryRouter, QueryRouterServer, Route,
|
|
632
|
+
export { App, Connect, CustomError, QueryConnect, QueryRouter, QueryRouterServer, Route, Server, createSchema, handleServer };
|
|
633
|
+
export type { RouteContext, RouteOpts, Rule, Run };
|
package/dist/router.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { webcrypto } from 'node:crypto';
|
|
2
|
-
import http from 'http';
|
|
3
|
-
import https from 'https';
|
|
4
|
-
import http2 from 'http2';
|
|
5
|
-
import url from 'url';
|
|
2
|
+
import http from 'node:http';
|
|
3
|
+
import https from 'node:https';
|
|
4
|
+
import http2 from 'node:http2';
|
|
5
|
+
import url from 'node:url';
|
|
6
6
|
import { WebSocketServer } from 'ws';
|
|
7
7
|
|
|
8
8
|
const urlAlphabet =
|
|
@@ -5887,6 +5887,13 @@ class QueryRouter {
|
|
|
5887
5887
|
ctx.currentKey = key;
|
|
5888
5888
|
ctx.currentRoute = route;
|
|
5889
5889
|
ctx.index = (ctx.index || 0) + 1;
|
|
5890
|
+
const progress = [path, key];
|
|
5891
|
+
if (ctx.progress) {
|
|
5892
|
+
ctx.progress.push(progress);
|
|
5893
|
+
}
|
|
5894
|
+
else {
|
|
5895
|
+
ctx.progress = [progress];
|
|
5896
|
+
}
|
|
5890
5897
|
if (ctx.index > maxNextRoute) {
|
|
5891
5898
|
ctx.code = 500;
|
|
5892
5899
|
ctx.message = 'Too many nextRoute';
|
|
@@ -6073,7 +6080,7 @@ class QueryRouter {
|
|
|
6073
6080
|
const { path, key = '', payload = {}, ...query } = message;
|
|
6074
6081
|
ctx = ctx || {};
|
|
6075
6082
|
ctx.query = { ...ctx.query, ...query, ...payload };
|
|
6076
|
-
ctx.state = {};
|
|
6083
|
+
ctx.state = { ...ctx?.state };
|
|
6077
6084
|
ctx.throw = this.throw;
|
|
6078
6085
|
// put queryRouter to ctx
|
|
6079
6086
|
// TODO: 是否需要queryRouter,函数内部处理router路由执行,这应该是避免去内部去包含的功能过
|
|
@@ -6081,6 +6088,7 @@ class QueryRouter {
|
|
|
6081
6088
|
ctx.call = this.call.bind(this);
|
|
6082
6089
|
ctx.queryRoute = this.queryRoute.bind(this);
|
|
6083
6090
|
ctx.index = 0;
|
|
6091
|
+
ctx.progress = ctx.progress || [];
|
|
6084
6092
|
const res = await this.runRoute(path, key, ctx);
|
|
6085
6093
|
const serialize = ctx.needSerialize ?? true; // 是否需要序列化
|
|
6086
6094
|
if (serialize) {
|
|
@@ -6328,6 +6336,10 @@ const parseBody = async (req) => {
|
|
|
6328
6336
|
|
|
6329
6337
|
/**
|
|
6330
6338
|
* get params and body
|
|
6339
|
+
* 优先原则
|
|
6340
|
+
* 1. 请求参数中的 payload 的token 优先
|
|
6341
|
+
* 2. 请求头中的 authorization 优先
|
|
6342
|
+
* 3. 请求头中的 cookie 优先
|
|
6331
6343
|
* @param req
|
|
6332
6344
|
* @param res
|
|
6333
6345
|
* @returns
|
|
@@ -6745,8 +6757,6 @@ class Server {
|
|
|
6745
6757
|
// 交给其他监听处理
|
|
6746
6758
|
return;
|
|
6747
6759
|
}
|
|
6748
|
-
// res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
6749
|
-
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
6750
6760
|
if (cors) {
|
|
6751
6761
|
res.setHeader('Access-Control-Allow-Origin', cors?.origin || '*'); // 允许所有域名的请求访问,可以根据需要设置具体的域名
|
|
6752
6762
|
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
|
|
@@ -6756,7 +6766,6 @@ class Server {
|
|
|
6756
6766
|
return;
|
|
6757
6767
|
}
|
|
6758
6768
|
}
|
|
6759
|
-
// res.writeHead(200); // 设置响应头,给予其他任何listen 知道headersSent,它已经被响应了
|
|
6760
6769
|
const url = req.url;
|
|
6761
6770
|
if (!url.startsWith(path)) {
|
|
6762
6771
|
res.end(resultError(`not path:[${path}]`));
|
|
@@ -6770,8 +6779,10 @@ class Server {
|
|
|
6770
6779
|
try {
|
|
6771
6780
|
const end = await handle(messages, { req, res });
|
|
6772
6781
|
if (res.writableEnded) {
|
|
6782
|
+
// 如果响应已经结束,则不进行任何操作
|
|
6773
6783
|
return;
|
|
6774
6784
|
}
|
|
6785
|
+
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
6775
6786
|
if (typeof end === 'string') {
|
|
6776
6787
|
res.end(end);
|
|
6777
6788
|
}
|
|
@@ -6781,6 +6792,7 @@ class Server {
|
|
|
6781
6792
|
}
|
|
6782
6793
|
catch (e) {
|
|
6783
6794
|
console.error(e);
|
|
6795
|
+
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
6784
6796
|
if (e.code && typeof e.code === 'number') {
|
|
6785
6797
|
res.end(resultError(e.message || `Router Server error`, e.code));
|
|
6786
6798
|
}
|
|
@@ -6844,7 +6856,10 @@ class WsServerBase {
|
|
|
6844
6856
|
listeners = [];
|
|
6845
6857
|
listening = false;
|
|
6846
6858
|
constructor(opts) {
|
|
6847
|
-
this.wss = opts.wss
|
|
6859
|
+
this.wss = opts.wss;
|
|
6860
|
+
if (!this.wss) {
|
|
6861
|
+
throw new Error('wss is required');
|
|
6862
|
+
}
|
|
6848
6863
|
this.path = opts.path || '';
|
|
6849
6864
|
}
|
|
6850
6865
|
setPath(path) {
|
package/package.json
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@kevisual/router",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.11",
|
|
5
5
|
"description": "",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"module": "dist/index.js",
|
|
8
|
-
"types": "dist/index.d.ts",
|
|
9
6
|
"type": "module",
|
|
10
7
|
"scripts": {
|
|
11
8
|
"build": "npm run clean && rollup -c",
|
|
@@ -14,7 +11,8 @@
|
|
|
14
11
|
"clean": "rm -rf dist"
|
|
15
12
|
},
|
|
16
13
|
"files": [
|
|
17
|
-
"dist"
|
|
14
|
+
"dist",
|
|
15
|
+
"src"
|
|
18
16
|
],
|
|
19
17
|
"keywords": [],
|
|
20
18
|
"author": "abearxiong",
|
|
@@ -24,20 +22,20 @@
|
|
|
24
22
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
25
23
|
"@rollup/plugin-typescript": "^12.1.2",
|
|
26
24
|
"@types/lodash-es": "^4.17.12",
|
|
27
|
-
"@types/node": "^22.
|
|
28
|
-
"@types/ws": "^8.18.
|
|
25
|
+
"@types/node": "^22.14.1",
|
|
26
|
+
"@types/ws": "^8.18.1",
|
|
29
27
|
"@types/xml2js": "^0.4.14",
|
|
30
28
|
"cookie": "^1.0.2",
|
|
31
29
|
"lodash-es": "^4.17.21",
|
|
32
30
|
"nanoid": "^5.1.5",
|
|
33
|
-
"rollup": "^4.
|
|
31
|
+
"rollup": "^4.40.0",
|
|
34
32
|
"rollup-plugin-dts": "^6.2.1",
|
|
35
33
|
"ts-loader": "^9.5.2",
|
|
36
34
|
"ts-node": "^10.9.2",
|
|
37
35
|
"tslib": "^2.8.1",
|
|
38
|
-
"typescript": "^5.8.
|
|
36
|
+
"typescript": "^5.8.3",
|
|
39
37
|
"xml2js": "^0.6.2",
|
|
40
|
-
"zod": "^3.24.
|
|
38
|
+
"zod": "^3.24.3"
|
|
41
39
|
},
|
|
42
40
|
"repository": {
|
|
43
41
|
"type": "git",
|
|
@@ -71,6 +69,10 @@
|
|
|
71
69
|
"./simple-lib": {
|
|
72
70
|
"import": "./dist/router-simple-lib.js",
|
|
73
71
|
"require": "./dist/router-simple-lib.js"
|
|
72
|
+
},
|
|
73
|
+
"./mod.ts": {
|
|
74
|
+
"import": "./src/mod.ts",
|
|
75
|
+
"require": "./src/mod.ts"
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
78
|
}
|
package/src/app.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { QueryRouter, Route, RouteContext, RouteOpts } from './route.ts';
|
|
2
|
+
import { Server, ServerOpts, HandleCtx } from './server/server.ts';
|
|
3
|
+
import { WsServer } from './server/ws-server.ts';
|
|
4
|
+
import { CustomError } from './result/error.ts';
|
|
5
|
+
|
|
6
|
+
type RouterHandle = (msg: { path: string; [key: string]: any }) => { code: string; data?: any; message?: string; [key: string]: any };
|
|
7
|
+
type AppOptions<T = {}> = {
|
|
8
|
+
router?: QueryRouter;
|
|
9
|
+
server?: Server;
|
|
10
|
+
/** handle msg 关联 */
|
|
11
|
+
routerHandle?: RouterHandle;
|
|
12
|
+
routerContext?: RouteContext<T>;
|
|
13
|
+
serverOptions?: ServerOpts;
|
|
14
|
+
io?: boolean;
|
|
15
|
+
ioOpts?: { routerHandle?: RouterHandle; routerContext?: RouteContext<T>; path?: string };
|
|
16
|
+
};
|
|
17
|
+
export type AppReqRes = HandleCtx;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 封装了 Router 和 Server 的 App 模块,处理http的请求和响应,内置了 Cookie 和 Token 和 res 的处理
|
|
21
|
+
*/
|
|
22
|
+
export class App<T = {}, U = AppReqRes> {
|
|
23
|
+
router: QueryRouter;
|
|
24
|
+
server: Server;
|
|
25
|
+
io: WsServer;
|
|
26
|
+
constructor(opts?: AppOptions<T>) {
|
|
27
|
+
const router = opts?.router || new QueryRouter();
|
|
28
|
+
const server = opts?.server || new Server(opts?.serverOptions || {});
|
|
29
|
+
server.setHandle(router.getHandle(router, opts?.routerHandle, opts?.routerContext));
|
|
30
|
+
router.setContext({ needSerialize: true, ...opts?.routerContext });
|
|
31
|
+
this.router = router;
|
|
32
|
+
this.server = server;
|
|
33
|
+
if (opts?.io) {
|
|
34
|
+
this.io = new WsServer(server, opts?.ioOpts);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): void;
|
|
38
|
+
listen(port: number, hostname?: string, listeningListener?: () => void): void;
|
|
39
|
+
listen(port: number, backlog?: number, listeningListener?: () => void): void;
|
|
40
|
+
listen(port: number, listeningListener?: () => void): void;
|
|
41
|
+
listen(path: string, backlog?: number, listeningListener?: () => void): void;
|
|
42
|
+
listen(path: string, listeningListener?: () => void): void;
|
|
43
|
+
listen(handle: any, backlog?: number, listeningListener?: () => void): void;
|
|
44
|
+
listen(handle: any, listeningListener?: () => void): void;
|
|
45
|
+
listen(...args: any[]) {
|
|
46
|
+
// @ts-ignore
|
|
47
|
+
this.server.listen(...args);
|
|
48
|
+
if (this.io) {
|
|
49
|
+
this.io.listen();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
use(path: string, fn: (ctx: any) => any, opts?: RouteOpts) {
|
|
53
|
+
const route = new Route(path, '', opts);
|
|
54
|
+
route.run = fn;
|
|
55
|
+
this.router.add(route);
|
|
56
|
+
}
|
|
57
|
+
addRoute(route: Route) {
|
|
58
|
+
this.router.add(route);
|
|
59
|
+
}
|
|
60
|
+
add = this.addRoute;
|
|
61
|
+
|
|
62
|
+
Route = Route;
|
|
63
|
+
route(opts: RouteOpts): Route<U>;
|
|
64
|
+
route(path: string, key?: string): Route<U>;
|
|
65
|
+
route(path: string, opts?: RouteOpts): Route<U>;
|
|
66
|
+
route(path: string, key?: string, opts?: RouteOpts): Route<U>;
|
|
67
|
+
route(...args: any[]) {
|
|
68
|
+
const [path, key, opts] = args;
|
|
69
|
+
if (typeof path === 'object') {
|
|
70
|
+
return new Route(path.path, path.key, path);
|
|
71
|
+
}
|
|
72
|
+
if (typeof path === 'string') {
|
|
73
|
+
if (opts) {
|
|
74
|
+
return new Route(path, key, opts);
|
|
75
|
+
}
|
|
76
|
+
if (key && typeof key === 'object') {
|
|
77
|
+
return new Route(path, key?.key || '', key);
|
|
78
|
+
}
|
|
79
|
+
return new Route(path, key);
|
|
80
|
+
}
|
|
81
|
+
return new Route(path, key, opts);
|
|
82
|
+
}
|
|
83
|
+
async call(message: { path: string; key?: string; payload?: any }, ctx?: RouteContext & { [key: string]: any }) {
|
|
84
|
+
const router = this.router;
|
|
85
|
+
return await router.call(message, ctx);
|
|
86
|
+
}
|
|
87
|
+
async queryRoute(path: string, key?: string, payload?: any, ctx?: RouteContext & { [key: string]: any }) {
|
|
88
|
+
return await this.router.queryRoute({ path, key, payload }, ctx);
|
|
89
|
+
}
|
|
90
|
+
exportRoutes() {
|
|
91
|
+
return this.router.exportRoutes();
|
|
92
|
+
}
|
|
93
|
+
importRoutes(routes: any[]) {
|
|
94
|
+
this.router.importRoutes(routes);
|
|
95
|
+
}
|
|
96
|
+
importApp(app: App) {
|
|
97
|
+
this.importRoutes(app.exportRoutes());
|
|
98
|
+
}
|
|
99
|
+
throw(code?: number | string, message?: string, tips?: string): void;
|
|
100
|
+
throw(...args: any[]) {
|
|
101
|
+
throw new CustomError(...args);
|
|
102
|
+
}
|
|
103
|
+
}
|
package/src/browser.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { Route, QueryRouter, QueryRouterServer } from './route.ts';
|
|
2
|
+
|
|
3
|
+
export { Rule, Schema, createSchema } from './validator/index.ts';
|
|
4
|
+
|
|
5
|
+
export type { RouteContext, RouteOpts } from './route.ts';
|
|
6
|
+
|
|
7
|
+
export type { Run } from './route.ts';
|
|
8
|
+
|
|
9
|
+
export { CustomError } from './result/error.ts';
|
package/src/connect.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { nanoid } from 'nanoid';
|
|
2
|
+
import { RouteContext } from './route.ts';
|
|
3
|
+
|
|
4
|
+
export class Connect {
|
|
5
|
+
path: string;
|
|
6
|
+
key?: string;
|
|
7
|
+
_fn?: (ctx?: RouteContext) => Promise<RouteContext>;
|
|
8
|
+
description?: string;
|
|
9
|
+
connects: { path: string; key?: string }[];
|
|
10
|
+
share = false;
|
|
11
|
+
|
|
12
|
+
constructor(path: string) {
|
|
13
|
+
this.path = path;
|
|
14
|
+
this.key = nanoid();
|
|
15
|
+
}
|
|
16
|
+
use(path: string) {
|
|
17
|
+
this.connects.push({ path });
|
|
18
|
+
}
|
|
19
|
+
useList(paths: string[]) {
|
|
20
|
+
paths.forEach((path) => {
|
|
21
|
+
this.connects.push({ path });
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
useConnect(connect: Connect) {
|
|
25
|
+
this.connects.push({ path: connect.path, key: connect.key });
|
|
26
|
+
}
|
|
27
|
+
useConnectList(connects: Connect[]) {
|
|
28
|
+
connects.forEach((connect) => {
|
|
29
|
+
this.connects.push({ path: connect.path, key: connect.key });
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
getPathList() {
|
|
33
|
+
return this.connects.map((c) => c.path).filter(Boolean);
|
|
34
|
+
}
|
|
35
|
+
set fn(fn: (ctx?: RouteContext) => Promise<RouteContext>) {
|
|
36
|
+
this._fn = fn;
|
|
37
|
+
}
|
|
38
|
+
get fn() {
|
|
39
|
+
return this._fn;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export class QueryConnect {
|
|
43
|
+
connects: Connect[];
|
|
44
|
+
constructor() {
|
|
45
|
+
this.connects = [];
|
|
46
|
+
}
|
|
47
|
+
add(connect: Connect) {
|
|
48
|
+
const has = this.connects.find((c) => c.path === connect.path && c.key === connect.key);
|
|
49
|
+
if (has) {
|
|
50
|
+
// remove the old connect
|
|
51
|
+
console.log('[replace connect]:', connect.path, connect.key);
|
|
52
|
+
this.connects = this.connects.filter((c) => c.path !== connect.path && c.key !== connect.key);
|
|
53
|
+
}
|
|
54
|
+
this.connects.push(connect);
|
|
55
|
+
}
|
|
56
|
+
remove(connect: Connect) {
|
|
57
|
+
this.connects = this.connects.filter((c) => c.path !== connect.path && c.key !== connect.key);
|
|
58
|
+
}
|
|
59
|
+
getList() {
|
|
60
|
+
return this.connects.map((c) => {
|
|
61
|
+
return {
|
|
62
|
+
path: c.path,
|
|
63
|
+
key: c.key,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { Route, QueryRouter, QueryRouterServer } from './route.ts';
|
|
2
|
+
export { Connect, QueryConnect } from './connect.ts';
|
|
3
|
+
|
|
4
|
+
export type { RouteContext, RouteOpts } from './route.ts';
|
|
5
|
+
|
|
6
|
+
export type { Run } from './route.ts';
|
|
7
|
+
|
|
8
|
+
export { Server, handleServer } from './server/index.ts';
|
|
9
|
+
/**
|
|
10
|
+
* 自定义错误
|
|
11
|
+
*/
|
|
12
|
+
export { CustomError } from './result/error.ts';
|
|
13
|
+
|
|
14
|
+
export { Rule, Schema, createSchema } from './validator/index.ts';
|
|
15
|
+
|
|
16
|
+
export { App } from './app.ts';
|
package/src/io.ts
ADDED
package/src/mod.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Route, QueryRouter, QueryRouterServer } from './route.ts';
|
|
2
|
+
|
|
3
|
+
export { App } from './app.ts';
|
|
4
|
+
|
|
5
|
+
export { Route, QueryRouter, QueryRouterServer };
|
|
6
|
+
|
|
7
|
+
export { Rule, Schema, createSchema } from './validator/index.ts';
|
|
8
|
+
|
|
9
|
+
export type { RouteContext, RouteOpts } from './route.ts';
|
|
10
|
+
|
|
11
|
+
export type { Run } from './route.ts';
|
|
12
|
+
|
|
13
|
+
export { CustomError } from './result/error.ts';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** 自定义错误 */
|
|
2
|
+
export class CustomError extends Error {
|
|
3
|
+
code?: number;
|
|
4
|
+
data?: any;
|
|
5
|
+
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;
|
|
18
|
+
// 这一步可不写,默认会保存堆栈追踪信息到自定义错误构造函数之前,
|
|
19
|
+
// 而如果写成 `Error.captureStackTrace(this)` 则自定义错误的构造函数也会被保存到堆栈追踪信息
|
|
20
|
+
Error.captureStackTrace(this, this.constructor);
|
|
21
|
+
}
|
|
22
|
+
static fromCode(code?: number) {
|
|
23
|
+
return new this(code);
|
|
24
|
+
}
|
|
25
|
+
static fromErrorData(code?: number, data?: any) {
|
|
26
|
+
const error = new this(code);
|
|
27
|
+
error.data = data;
|
|
28
|
+
return error;
|
|
29
|
+
}
|
|
30
|
+
static parseError(e: CustomError) {
|
|
31
|
+
return {
|
|
32
|
+
code: e?.code,
|
|
33
|
+
data: e?.data,
|
|
34
|
+
message: e?.message,
|
|
35
|
+
tips: e?.tips,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
parse(e?: CustomError) {
|
|
39
|
+
if (e) {
|
|
40
|
+
return CustomError.parseError(e);
|
|
41
|
+
} else {
|
|
42
|
+
return {
|
|
43
|
+
code: e?.code,
|
|
44
|
+
data: e?.data,
|
|
45
|
+
message: e?.message,
|
|
46
|
+
tips: e?.tips,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/*
|
|
53
|
+
try {
|
|
54
|
+
//
|
|
55
|
+
} catch(e) {
|
|
56
|
+
if (e instanceof CustomError) {
|
|
57
|
+
const errorInfo = e.parse();
|
|
58
|
+
if (dev) {
|
|
59
|
+
return {
|
|
60
|
+
error: errorInfo,
|
|
61
|
+
};
|
|
62
|
+
} else {
|
|
63
|
+
return errorInfo;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './error.ts';
|