@kevisual/router 0.0.18 → 0.0.20
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 +29 -3
- package/dist/router-browser.js +89 -19
- package/dist/router-define.d.ts +29 -3
- package/dist/router-define.js +55 -14
- package/dist/router-simple.d.ts +3 -0
- package/dist/router-simple.js +49 -1
- package/dist/router.d.ts +29 -3
- package/dist/router.js +89 -19
- package/package.json +5 -4
- package/src/router-define.ts +60 -16
- package/src/router-simple.ts +2 -1
- package/src/server/parse-body.ts +33 -1
package/dist/router-browser.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { Schema } from 'zod';
|
|
|
3
3
|
import * as querystring from 'querystring';
|
|
4
4
|
import { IncomingMessage } from 'node:http';
|
|
5
5
|
import { RouteOpts as RouteOpts$1, QueryRouterServer as QueryRouterServer$1, RouteMiddleware as RouteMiddleware$1, Run as Run$1 } from '@kevisual/router';
|
|
6
|
+
import { Query, DataOpts, Result } from '@kevisual/query/query';
|
|
6
7
|
|
|
7
8
|
type BaseRule = {
|
|
8
9
|
value?: any;
|
|
@@ -467,18 +468,43 @@ declare class Chain {
|
|
|
467
468
|
define<U extends SimpleObject = {}>(run: Run$1<U>): this;
|
|
468
469
|
createRoute(): this;
|
|
469
470
|
}
|
|
471
|
+
type QueryChainOptions = {
|
|
472
|
+
query?: Query;
|
|
473
|
+
omitKeys?: string[];
|
|
474
|
+
};
|
|
475
|
+
declare class QueryChain {
|
|
476
|
+
obj: SimpleObject;
|
|
477
|
+
query: Query;
|
|
478
|
+
omitKeys: string[];
|
|
479
|
+
constructor(value?: SimpleObject, opts?: QueryChainOptions);
|
|
480
|
+
omit(obj: SimpleObject, key?: string[]): {
|
|
481
|
+
[x: string]: any;
|
|
482
|
+
};
|
|
483
|
+
/**
|
|
484
|
+
* 生成
|
|
485
|
+
* @param queryData
|
|
486
|
+
* @returns
|
|
487
|
+
*/
|
|
488
|
+
getKey(queryData?: SimpleObject): Pick<RouteOpts$1, 'path' | 'key' | 'metadata' | 'description' | 'validator'>;
|
|
489
|
+
post<R = SimpleObject, P = SimpleObject>(data: P, options?: DataOpts): Promise<Result<R>>;
|
|
490
|
+
get<R = SimpleObject, P = SimpleObject>(data: P, options?: DataOpts): Promise<Result<R>>;
|
|
491
|
+
}
|
|
470
492
|
declare const util: {
|
|
471
493
|
getChain: (obj: RouteOpts$1, opts?: ChainOptions) => Chain;
|
|
472
494
|
};
|
|
473
495
|
declare class QueryUtil<T extends RouteObject = RouteObject> {
|
|
474
|
-
|
|
496
|
+
obj: T;
|
|
475
497
|
app: QueryRouterServer$1;
|
|
476
|
-
|
|
498
|
+
query: Query;
|
|
499
|
+
constructor(object: T, opts?: ChainOptions & QueryChainOptions);
|
|
477
500
|
static createFormObj<U extends RouteObject>(object: U, opts?: ChainOptions): QueryUtil<U>;
|
|
478
501
|
static create<U extends Record<string, RouteOpts$1>>(value: U, opts?: ChainOptions): QueryUtil<U>;
|
|
479
502
|
get<K extends keyof T>(key: K): RouteOpts$1;
|
|
480
503
|
chain<K extends keyof T>(key: K, opts?: ChainOptions): Chain;
|
|
481
|
-
queryChain<K extends keyof T>(key: K
|
|
504
|
+
queryChain<K extends keyof T>(key: K, opts?: QueryChainOptions): QueryChain;
|
|
505
|
+
static Chain: typeof Chain;
|
|
506
|
+
static QueryChain: typeof QueryChain;
|
|
507
|
+
get routeObject(): T;
|
|
482
508
|
}
|
|
483
509
|
|
|
484
510
|
export { CustomError, QueryRouter, QueryRouterServer, QueryUtil, Route, createSchema, define, parseBody, parseSearch, parseSearchValue, util };
|
package/dist/router-browser.js
CHANGED
|
@@ -1054,15 +1054,15 @@ const base64urlRegex = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z
|
|
|
1054
1054
|
const dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
|
|
1055
1055
|
const dateRegex = new RegExp(`^${dateRegexSource}$`);
|
|
1056
1056
|
function timeRegexSource(args) {
|
|
1057
|
-
|
|
1058
|
-
let regex = `([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d`;
|
|
1057
|
+
let secondsRegexSource = `[0-5]\\d`;
|
|
1059
1058
|
if (args.precision) {
|
|
1060
|
-
|
|
1059
|
+
secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`;
|
|
1061
1060
|
}
|
|
1062
1061
|
else if (args.precision == null) {
|
|
1063
|
-
|
|
1062
|
+
secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`;
|
|
1064
1063
|
}
|
|
1065
|
-
|
|
1064
|
+
const secondsQuantifier = args.precision ? "+" : "?"; // require seconds if precision is nonzero
|
|
1065
|
+
return `([01]\\d|2[0-3]):[0-5]\\d(:${secondsRegexSource})${secondsQuantifier}`;
|
|
1066
1066
|
}
|
|
1067
1067
|
function timeRegex(args) {
|
|
1068
1068
|
return new RegExp(`^${timeRegexSource(args)}$`);
|
|
@@ -6268,7 +6268,36 @@ const parseBody = async (req) => {
|
|
|
6268
6268
|
req.on('end', () => {
|
|
6269
6269
|
try {
|
|
6270
6270
|
const body = Buffer.concat(arr).toString();
|
|
6271
|
-
|
|
6271
|
+
// 获取 Content-Type 头信息
|
|
6272
|
+
const contentType = req.headers['content-type'] || '';
|
|
6273
|
+
// 处理 application/json
|
|
6274
|
+
if (contentType.includes('application/json')) {
|
|
6275
|
+
resolve(JSON.parse(body));
|
|
6276
|
+
return;
|
|
6277
|
+
}
|
|
6278
|
+
// 处理 application/x-www-form-urlencoded
|
|
6279
|
+
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
6280
|
+
const formData = new URLSearchParams(body);
|
|
6281
|
+
const result = {};
|
|
6282
|
+
formData.forEach((value, key) => {
|
|
6283
|
+
// 尝试将值解析为 JSON,如果失败则保留原始字符串
|
|
6284
|
+
try {
|
|
6285
|
+
result[key] = JSON.parse(value);
|
|
6286
|
+
}
|
|
6287
|
+
catch {
|
|
6288
|
+
result[key] = value;
|
|
6289
|
+
}
|
|
6290
|
+
});
|
|
6291
|
+
resolve(result);
|
|
6292
|
+
return;
|
|
6293
|
+
}
|
|
6294
|
+
// 默认尝试 JSON 解析
|
|
6295
|
+
try {
|
|
6296
|
+
resolve(JSON.parse(body));
|
|
6297
|
+
}
|
|
6298
|
+
catch {
|
|
6299
|
+
resolve({});
|
|
6300
|
+
}
|
|
6272
6301
|
}
|
|
6273
6302
|
catch (e) {
|
|
6274
6303
|
resolve({});
|
|
@@ -6352,17 +6381,57 @@ class Chain {
|
|
|
6352
6381
|
return this;
|
|
6353
6382
|
}
|
|
6354
6383
|
}
|
|
6384
|
+
class QueryChain {
|
|
6385
|
+
obj = {};
|
|
6386
|
+
query;
|
|
6387
|
+
omitKeys = ['metadata', 'description', 'validator'];
|
|
6388
|
+
constructor(value, opts) {
|
|
6389
|
+
this.obj = value || {};
|
|
6390
|
+
this.query = opts?.query;
|
|
6391
|
+
if (opts?.omitKeys)
|
|
6392
|
+
this.omitKeys = opts.omitKeys;
|
|
6393
|
+
}
|
|
6394
|
+
omit(obj, key = []) {
|
|
6395
|
+
const newObj = { ...obj };
|
|
6396
|
+
key.forEach((k) => {
|
|
6397
|
+
delete newObj[k];
|
|
6398
|
+
});
|
|
6399
|
+
return newObj;
|
|
6400
|
+
}
|
|
6401
|
+
/**
|
|
6402
|
+
* 生成
|
|
6403
|
+
* @param queryData
|
|
6404
|
+
* @returns
|
|
6405
|
+
*/
|
|
6406
|
+
getKey(queryData) {
|
|
6407
|
+
const obj = this.omit(this.obj, this.omitKeys);
|
|
6408
|
+
return {
|
|
6409
|
+
...obj,
|
|
6410
|
+
...queryData,
|
|
6411
|
+
};
|
|
6412
|
+
}
|
|
6413
|
+
post(data, options) {
|
|
6414
|
+
const _queryData = this.getKey(data);
|
|
6415
|
+
return this.query.post(_queryData, options);
|
|
6416
|
+
}
|
|
6417
|
+
get(data, options) {
|
|
6418
|
+
const _queryData = this.getKey(data);
|
|
6419
|
+
return this.query.get(_queryData, options);
|
|
6420
|
+
}
|
|
6421
|
+
}
|
|
6355
6422
|
const util = {
|
|
6356
6423
|
getChain: (obj, opts) => {
|
|
6357
6424
|
return new Chain(obj, opts);
|
|
6358
6425
|
},
|
|
6359
6426
|
};
|
|
6360
6427
|
class QueryUtil {
|
|
6361
|
-
|
|
6428
|
+
obj;
|
|
6362
6429
|
app;
|
|
6430
|
+
query;
|
|
6363
6431
|
constructor(object, opts) {
|
|
6364
|
-
this.
|
|
6432
|
+
this.obj = object;
|
|
6365
6433
|
this.app = opts?.app;
|
|
6434
|
+
this.query = opts?.query;
|
|
6366
6435
|
}
|
|
6367
6436
|
static createFormObj(object, opts) {
|
|
6368
6437
|
return new QueryUtil(object, opts);
|
|
@@ -6372,21 +6441,22 @@ class QueryUtil {
|
|
|
6372
6441
|
return new QueryUtil(obj, opts);
|
|
6373
6442
|
}
|
|
6374
6443
|
get(key) {
|
|
6375
|
-
return this.
|
|
6444
|
+
return this.obj[key];
|
|
6376
6445
|
}
|
|
6377
6446
|
chain(key, opts) {
|
|
6378
|
-
const obj = this.
|
|
6447
|
+
const obj = this.obj[key];
|
|
6379
6448
|
let newOpts = { app: this.app, ...opts };
|
|
6380
|
-
return new Chain(obj, newOpts);
|
|
6449
|
+
return new QueryUtil.Chain(obj, newOpts);
|
|
6381
6450
|
}
|
|
6382
|
-
queryChain(key) {
|
|
6383
|
-
const value = this.
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6451
|
+
queryChain(key, opts) {
|
|
6452
|
+
const value = this.obj[key];
|
|
6453
|
+
let newOpts = { query: this.query, ...opts };
|
|
6454
|
+
return new QueryUtil.QueryChain(value, newOpts);
|
|
6455
|
+
}
|
|
6456
|
+
static Chain = Chain;
|
|
6457
|
+
static QueryChain = QueryChain;
|
|
6458
|
+
get routeObject() {
|
|
6459
|
+
return this.obj;
|
|
6390
6460
|
}
|
|
6391
6461
|
}
|
|
6392
6462
|
|
package/dist/router-define.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RouteOpts, QueryRouterServer, RouteMiddleware, Run } from '@kevisual/router';
|
|
2
2
|
export { RouteOpts } from '@kevisual/router';
|
|
3
|
+
import { Query, DataOpts, Result } from '@kevisual/query/query';
|
|
3
4
|
|
|
4
5
|
type RouteObject = {
|
|
5
6
|
[key: string]: RouteOpts;
|
|
@@ -30,18 +31,43 @@ declare class Chain {
|
|
|
30
31
|
define<U extends SimpleObject = {}>(run: Run<U>): this;
|
|
31
32
|
createRoute(): this;
|
|
32
33
|
}
|
|
34
|
+
type QueryChainOptions = {
|
|
35
|
+
query?: Query;
|
|
36
|
+
omitKeys?: string[];
|
|
37
|
+
};
|
|
38
|
+
declare class QueryChain {
|
|
39
|
+
obj: SimpleObject;
|
|
40
|
+
query: Query;
|
|
41
|
+
omitKeys: string[];
|
|
42
|
+
constructor(value?: SimpleObject, opts?: QueryChainOptions);
|
|
43
|
+
omit(obj: SimpleObject, key?: string[]): {
|
|
44
|
+
[x: string]: any;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* 生成
|
|
48
|
+
* @param queryData
|
|
49
|
+
* @returns
|
|
50
|
+
*/
|
|
51
|
+
getKey(queryData?: SimpleObject): Pick<RouteOpts, 'path' | 'key' | 'metadata' | 'description' | 'validator'>;
|
|
52
|
+
post<R = SimpleObject, P = SimpleObject>(data: P, options?: DataOpts): Promise<Result<R>>;
|
|
53
|
+
get<R = SimpleObject, P = SimpleObject>(data: P, options?: DataOpts): Promise<Result<R>>;
|
|
54
|
+
}
|
|
33
55
|
declare const util: {
|
|
34
56
|
getChain: (obj: RouteOpts, opts?: ChainOptions) => Chain;
|
|
35
57
|
};
|
|
36
58
|
declare class QueryUtil<T extends RouteObject = RouteObject> {
|
|
37
|
-
|
|
59
|
+
obj: T;
|
|
38
60
|
app: QueryRouterServer;
|
|
39
|
-
|
|
61
|
+
query: Query;
|
|
62
|
+
constructor(object: T, opts?: ChainOptions & QueryChainOptions);
|
|
40
63
|
static createFormObj<U extends RouteObject>(object: U, opts?: ChainOptions): QueryUtil<U>;
|
|
41
64
|
static create<U extends Record<string, RouteOpts>>(value: U, opts?: ChainOptions): QueryUtil<U>;
|
|
42
65
|
get<K extends keyof T>(key: K): RouteOpts;
|
|
43
66
|
chain<K extends keyof T>(key: K, opts?: ChainOptions): Chain;
|
|
44
|
-
queryChain<K extends keyof T>(key: K
|
|
67
|
+
queryChain<K extends keyof T>(key: K, opts?: QueryChainOptions): QueryChain;
|
|
68
|
+
static Chain: typeof Chain;
|
|
69
|
+
static QueryChain: typeof QueryChain;
|
|
70
|
+
get routeObject(): T;
|
|
45
71
|
}
|
|
46
72
|
|
|
47
73
|
export { QueryUtil, define, util };
|
package/dist/router-define.js
CHANGED
|
@@ -51,17 +51,57 @@ class Chain {
|
|
|
51
51
|
return this;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
+
class QueryChain {
|
|
55
|
+
obj = {};
|
|
56
|
+
query;
|
|
57
|
+
omitKeys = ['metadata', 'description', 'validator'];
|
|
58
|
+
constructor(value, opts) {
|
|
59
|
+
this.obj = value || {};
|
|
60
|
+
this.query = opts?.query;
|
|
61
|
+
if (opts?.omitKeys)
|
|
62
|
+
this.omitKeys = opts.omitKeys;
|
|
63
|
+
}
|
|
64
|
+
omit(obj, key = []) {
|
|
65
|
+
const newObj = { ...obj };
|
|
66
|
+
key.forEach((k) => {
|
|
67
|
+
delete newObj[k];
|
|
68
|
+
});
|
|
69
|
+
return newObj;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 生成
|
|
73
|
+
* @param queryData
|
|
74
|
+
* @returns
|
|
75
|
+
*/
|
|
76
|
+
getKey(queryData) {
|
|
77
|
+
const obj = this.omit(this.obj, this.omitKeys);
|
|
78
|
+
return {
|
|
79
|
+
...obj,
|
|
80
|
+
...queryData,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
post(data, options) {
|
|
84
|
+
const _queryData = this.getKey(data);
|
|
85
|
+
return this.query.post(_queryData, options);
|
|
86
|
+
}
|
|
87
|
+
get(data, options) {
|
|
88
|
+
const _queryData = this.getKey(data);
|
|
89
|
+
return this.query.get(_queryData, options);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
54
92
|
const util = {
|
|
55
93
|
getChain: (obj, opts) => {
|
|
56
94
|
return new Chain(obj, opts);
|
|
57
95
|
},
|
|
58
96
|
};
|
|
59
97
|
class QueryUtil {
|
|
60
|
-
|
|
98
|
+
obj;
|
|
61
99
|
app;
|
|
100
|
+
query;
|
|
62
101
|
constructor(object, opts) {
|
|
63
|
-
this.
|
|
102
|
+
this.obj = object;
|
|
64
103
|
this.app = opts?.app;
|
|
104
|
+
this.query = opts?.query;
|
|
65
105
|
}
|
|
66
106
|
static createFormObj(object, opts) {
|
|
67
107
|
return new QueryUtil(object, opts);
|
|
@@ -71,21 +111,22 @@ class QueryUtil {
|
|
|
71
111
|
return new QueryUtil(obj, opts);
|
|
72
112
|
}
|
|
73
113
|
get(key) {
|
|
74
|
-
return this.
|
|
114
|
+
return this.obj[key];
|
|
75
115
|
}
|
|
76
116
|
chain(key, opts) {
|
|
77
|
-
const obj = this.
|
|
117
|
+
const obj = this.obj[key];
|
|
78
118
|
let newOpts = { app: this.app, ...opts };
|
|
79
|
-
return new Chain(obj, newOpts);
|
|
80
|
-
}
|
|
81
|
-
queryChain(key) {
|
|
82
|
-
const value = this.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
119
|
+
return new QueryUtil.Chain(obj, newOpts);
|
|
120
|
+
}
|
|
121
|
+
queryChain(key, opts) {
|
|
122
|
+
const value = this.obj[key];
|
|
123
|
+
let newOpts = { query: this.query, ...opts };
|
|
124
|
+
return new QueryUtil.QueryChain(value, newOpts);
|
|
125
|
+
}
|
|
126
|
+
static Chain = Chain;
|
|
127
|
+
static QueryChain = QueryChain;
|
|
128
|
+
get routeObject() {
|
|
129
|
+
return this.obj;
|
|
89
130
|
}
|
|
90
131
|
}
|
|
91
132
|
|
package/dist/router-simple.d.ts
CHANGED
|
@@ -22,6 +22,9 @@ declare class SimpleRouter {
|
|
|
22
22
|
});
|
|
23
23
|
getBody(req: Req): Promise<Record<string, any>>;
|
|
24
24
|
getSearch(req: Req): querystring.ParsedUrlQuery;
|
|
25
|
+
parseSearchValue: (value?: string, opts?: {
|
|
26
|
+
decode?: boolean;
|
|
27
|
+
}) => any;
|
|
25
28
|
use(method: string, route: string, ...fns: Array<(req: Req, res: ServerResponse) => Promise<void> | void>): this;
|
|
26
29
|
get(route: string, ...fns: Array<(req: Req, res: ServerResponse) => Promise<void> | void>): this;
|
|
27
30
|
post(route: string, ...fns: Array<(req: Req, res: ServerResponse) => Promise<void> | void>): this;
|
package/dist/router-simple.js
CHANGED
|
@@ -423,7 +423,36 @@ const parseBody = async (req) => {
|
|
|
423
423
|
req.on('end', () => {
|
|
424
424
|
try {
|
|
425
425
|
const body = Buffer.concat(arr).toString();
|
|
426
|
-
|
|
426
|
+
// 获取 Content-Type 头信息
|
|
427
|
+
const contentType = req.headers['content-type'] || '';
|
|
428
|
+
// 处理 application/json
|
|
429
|
+
if (contentType.includes('application/json')) {
|
|
430
|
+
resolve(JSON.parse(body));
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
// 处理 application/x-www-form-urlencoded
|
|
434
|
+
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
435
|
+
const formData = new URLSearchParams(body);
|
|
436
|
+
const result = {};
|
|
437
|
+
formData.forEach((value, key) => {
|
|
438
|
+
// 尝试将值解析为 JSON,如果失败则保留原始字符串
|
|
439
|
+
try {
|
|
440
|
+
result[key] = JSON.parse(value);
|
|
441
|
+
}
|
|
442
|
+
catch {
|
|
443
|
+
result[key] = value;
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
resolve(result);
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
// 默认尝试 JSON 解析
|
|
450
|
+
try {
|
|
451
|
+
resolve(JSON.parse(body));
|
|
452
|
+
}
|
|
453
|
+
catch {
|
|
454
|
+
resolve({});
|
|
455
|
+
}
|
|
427
456
|
}
|
|
428
457
|
catch (e) {
|
|
429
458
|
resolve({});
|
|
@@ -435,6 +464,24 @@ const parseSearch = (req) => {
|
|
|
435
464
|
const parsedUrl = url.parse(req.url, true);
|
|
436
465
|
return parsedUrl.query;
|
|
437
466
|
};
|
|
467
|
+
/**
|
|
468
|
+
* 把url当个key 的 value 的字符串转成json
|
|
469
|
+
* @param value
|
|
470
|
+
*/
|
|
471
|
+
const parseSearchValue = (value, opts) => {
|
|
472
|
+
if (!value)
|
|
473
|
+
return {};
|
|
474
|
+
const decode = opts?.decode ?? false;
|
|
475
|
+
if (decode) {
|
|
476
|
+
value = decodeURIComponent(value);
|
|
477
|
+
}
|
|
478
|
+
try {
|
|
479
|
+
return JSON.parse(value);
|
|
480
|
+
}
|
|
481
|
+
catch (e) {
|
|
482
|
+
return {};
|
|
483
|
+
}
|
|
484
|
+
};
|
|
438
485
|
|
|
439
486
|
/**
|
|
440
487
|
* SimpleRouter
|
|
@@ -451,6 +498,7 @@ class SimpleRouter {
|
|
|
451
498
|
getSearch(req) {
|
|
452
499
|
return parseSearch(req);
|
|
453
500
|
}
|
|
501
|
+
parseSearchValue = parseSearchValue;
|
|
454
502
|
use(method, route, ...fns) {
|
|
455
503
|
const handlers = Array.isArray(fns) ? fns.flat() : [];
|
|
456
504
|
const pattern = distExports.pathToRegexp(route);
|
package/dist/router.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import http2 from 'node:http2';
|
|
|
6
6
|
import * as cookie from 'cookie';
|
|
7
7
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
8
8
|
import { RouteOpts as RouteOpts$1, QueryRouterServer as QueryRouterServer$1, RouteMiddleware as RouteMiddleware$1, Run as Run$1 } from '@kevisual/router';
|
|
9
|
+
import { Query, DataOpts, Result } from '@kevisual/query/query';
|
|
9
10
|
|
|
10
11
|
type BaseRule = {
|
|
11
12
|
value?: any;
|
|
@@ -608,18 +609,43 @@ declare class Chain {
|
|
|
608
609
|
define<U extends SimpleObject = {}>(run: Run$1<U>): this;
|
|
609
610
|
createRoute(): this;
|
|
610
611
|
}
|
|
612
|
+
type QueryChainOptions = {
|
|
613
|
+
query?: Query;
|
|
614
|
+
omitKeys?: string[];
|
|
615
|
+
};
|
|
616
|
+
declare class QueryChain {
|
|
617
|
+
obj: SimpleObject;
|
|
618
|
+
query: Query;
|
|
619
|
+
omitKeys: string[];
|
|
620
|
+
constructor(value?: SimpleObject, opts?: QueryChainOptions);
|
|
621
|
+
omit(obj: SimpleObject, key?: string[]): {
|
|
622
|
+
[x: string]: any;
|
|
623
|
+
};
|
|
624
|
+
/**
|
|
625
|
+
* 生成
|
|
626
|
+
* @param queryData
|
|
627
|
+
* @returns
|
|
628
|
+
*/
|
|
629
|
+
getKey(queryData?: SimpleObject): Pick<RouteOpts$1, 'path' | 'key' | 'metadata' | 'description' | 'validator'>;
|
|
630
|
+
post<R = SimpleObject, P = SimpleObject>(data: P, options?: DataOpts): Promise<Result<R>>;
|
|
631
|
+
get<R = SimpleObject, P = SimpleObject>(data: P, options?: DataOpts): Promise<Result<R>>;
|
|
632
|
+
}
|
|
611
633
|
declare const util: {
|
|
612
634
|
getChain: (obj: RouteOpts$1, opts?: ChainOptions) => Chain;
|
|
613
635
|
};
|
|
614
636
|
declare class QueryUtil<T extends RouteObject = RouteObject> {
|
|
615
|
-
|
|
637
|
+
obj: T;
|
|
616
638
|
app: QueryRouterServer$1;
|
|
617
|
-
|
|
639
|
+
query: Query;
|
|
640
|
+
constructor(object: T, opts?: ChainOptions & QueryChainOptions);
|
|
618
641
|
static createFormObj<U extends RouteObject>(object: U, opts?: ChainOptions): QueryUtil<U>;
|
|
619
642
|
static create<U extends Record<string, RouteOpts$1>>(value: U, opts?: ChainOptions): QueryUtil<U>;
|
|
620
643
|
get<K extends keyof T>(key: K): RouteOpts$1;
|
|
621
644
|
chain<K extends keyof T>(key: K, opts?: ChainOptions): Chain;
|
|
622
|
-
queryChain<K extends keyof T>(key: K
|
|
645
|
+
queryChain<K extends keyof T>(key: K, opts?: QueryChainOptions): QueryChain;
|
|
646
|
+
static Chain: typeof Chain;
|
|
647
|
+
static QueryChain: typeof QueryChain;
|
|
648
|
+
get routeObject(): T;
|
|
623
649
|
}
|
|
624
650
|
|
|
625
651
|
type RouterHandle = (msg: {
|
package/dist/router.js
CHANGED
|
@@ -1076,15 +1076,15 @@ const base64urlRegex = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z
|
|
|
1076
1076
|
const dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
|
|
1077
1077
|
const dateRegex = new RegExp(`^${dateRegexSource}$`);
|
|
1078
1078
|
function timeRegexSource(args) {
|
|
1079
|
-
|
|
1080
|
-
let regex = `([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d`;
|
|
1079
|
+
let secondsRegexSource = `[0-5]\\d`;
|
|
1081
1080
|
if (args.precision) {
|
|
1082
|
-
|
|
1081
|
+
secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`;
|
|
1083
1082
|
}
|
|
1084
1083
|
else if (args.precision == null) {
|
|
1085
|
-
|
|
1084
|
+
secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`;
|
|
1086
1085
|
}
|
|
1087
|
-
|
|
1086
|
+
const secondsQuantifier = args.precision ? "+" : "?"; // require seconds if precision is nonzero
|
|
1087
|
+
return `([01]\\d|2[0-3]):[0-5]\\d(:${secondsRegexSource})${secondsQuantifier}`;
|
|
1088
1088
|
}
|
|
1089
1089
|
function timeRegex(args) {
|
|
1090
1090
|
return new RegExp(`^${timeRegexSource(args)}$`);
|
|
@@ -6354,7 +6354,36 @@ const parseBody = async (req) => {
|
|
|
6354
6354
|
req.on('end', () => {
|
|
6355
6355
|
try {
|
|
6356
6356
|
const body = Buffer.concat(arr).toString();
|
|
6357
|
-
|
|
6357
|
+
// 获取 Content-Type 头信息
|
|
6358
|
+
const contentType = req.headers['content-type'] || '';
|
|
6359
|
+
// 处理 application/json
|
|
6360
|
+
if (contentType.includes('application/json')) {
|
|
6361
|
+
resolve(JSON.parse(body));
|
|
6362
|
+
return;
|
|
6363
|
+
}
|
|
6364
|
+
// 处理 application/x-www-form-urlencoded
|
|
6365
|
+
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
6366
|
+
const formData = new URLSearchParams(body);
|
|
6367
|
+
const result = {};
|
|
6368
|
+
formData.forEach((value, key) => {
|
|
6369
|
+
// 尝试将值解析为 JSON,如果失败则保留原始字符串
|
|
6370
|
+
try {
|
|
6371
|
+
result[key] = JSON.parse(value);
|
|
6372
|
+
}
|
|
6373
|
+
catch {
|
|
6374
|
+
result[key] = value;
|
|
6375
|
+
}
|
|
6376
|
+
});
|
|
6377
|
+
resolve(result);
|
|
6378
|
+
return;
|
|
6379
|
+
}
|
|
6380
|
+
// 默认尝试 JSON 解析
|
|
6381
|
+
try {
|
|
6382
|
+
resolve(JSON.parse(body));
|
|
6383
|
+
}
|
|
6384
|
+
catch {
|
|
6385
|
+
resolve({});
|
|
6386
|
+
}
|
|
6358
6387
|
}
|
|
6359
6388
|
catch (e) {
|
|
6360
6389
|
resolve({});
|
|
@@ -11991,17 +12020,57 @@ class Chain {
|
|
|
11991
12020
|
return this;
|
|
11992
12021
|
}
|
|
11993
12022
|
}
|
|
12023
|
+
class QueryChain {
|
|
12024
|
+
obj = {};
|
|
12025
|
+
query;
|
|
12026
|
+
omitKeys = ['metadata', 'description', 'validator'];
|
|
12027
|
+
constructor(value, opts) {
|
|
12028
|
+
this.obj = value || {};
|
|
12029
|
+
this.query = opts?.query;
|
|
12030
|
+
if (opts?.omitKeys)
|
|
12031
|
+
this.omitKeys = opts.omitKeys;
|
|
12032
|
+
}
|
|
12033
|
+
omit(obj, key = []) {
|
|
12034
|
+
const newObj = { ...obj };
|
|
12035
|
+
key.forEach((k) => {
|
|
12036
|
+
delete newObj[k];
|
|
12037
|
+
});
|
|
12038
|
+
return newObj;
|
|
12039
|
+
}
|
|
12040
|
+
/**
|
|
12041
|
+
* 生成
|
|
12042
|
+
* @param queryData
|
|
12043
|
+
* @returns
|
|
12044
|
+
*/
|
|
12045
|
+
getKey(queryData) {
|
|
12046
|
+
const obj = this.omit(this.obj, this.omitKeys);
|
|
12047
|
+
return {
|
|
12048
|
+
...obj,
|
|
12049
|
+
...queryData,
|
|
12050
|
+
};
|
|
12051
|
+
}
|
|
12052
|
+
post(data, options) {
|
|
12053
|
+
const _queryData = this.getKey(data);
|
|
12054
|
+
return this.query.post(_queryData, options);
|
|
12055
|
+
}
|
|
12056
|
+
get(data, options) {
|
|
12057
|
+
const _queryData = this.getKey(data);
|
|
12058
|
+
return this.query.get(_queryData, options);
|
|
12059
|
+
}
|
|
12060
|
+
}
|
|
11994
12061
|
const util = {
|
|
11995
12062
|
getChain: (obj, opts) => {
|
|
11996
12063
|
return new Chain(obj, opts);
|
|
11997
12064
|
},
|
|
11998
12065
|
};
|
|
11999
12066
|
class QueryUtil {
|
|
12000
|
-
|
|
12067
|
+
obj;
|
|
12001
12068
|
app;
|
|
12069
|
+
query;
|
|
12002
12070
|
constructor(object, opts) {
|
|
12003
|
-
this.
|
|
12071
|
+
this.obj = object;
|
|
12004
12072
|
this.app = opts?.app;
|
|
12073
|
+
this.query = opts?.query;
|
|
12005
12074
|
}
|
|
12006
12075
|
static createFormObj(object, opts) {
|
|
12007
12076
|
return new QueryUtil(object, opts);
|
|
@@ -12011,21 +12080,22 @@ class QueryUtil {
|
|
|
12011
12080
|
return new QueryUtil(obj, opts);
|
|
12012
12081
|
}
|
|
12013
12082
|
get(key) {
|
|
12014
|
-
return this.
|
|
12083
|
+
return this.obj[key];
|
|
12015
12084
|
}
|
|
12016
12085
|
chain(key, opts) {
|
|
12017
|
-
const obj = this.
|
|
12086
|
+
const obj = this.obj[key];
|
|
12018
12087
|
let newOpts = { app: this.app, ...opts };
|
|
12019
|
-
return new Chain(obj, newOpts);
|
|
12088
|
+
return new QueryUtil.Chain(obj, newOpts);
|
|
12020
12089
|
}
|
|
12021
|
-
queryChain(key) {
|
|
12022
|
-
const value = this.
|
|
12023
|
-
|
|
12024
|
-
|
|
12025
|
-
|
|
12026
|
-
|
|
12027
|
-
|
|
12028
|
-
|
|
12090
|
+
queryChain(key, opts) {
|
|
12091
|
+
const value = this.obj[key];
|
|
12092
|
+
let newOpts = { query: this.query, ...opts };
|
|
12093
|
+
return new QueryUtil.QueryChain(value, newOpts);
|
|
12094
|
+
}
|
|
12095
|
+
static Chain = Chain;
|
|
12096
|
+
static QueryChain = QueryChain;
|
|
12097
|
+
get routeObject() {
|
|
12098
|
+
return this.obj;
|
|
12029
12099
|
}
|
|
12030
12100
|
}
|
|
12031
12101
|
|
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.20",
|
|
5
5
|
"description": "",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/router.js",
|
|
@@ -21,18 +21,19 @@
|
|
|
21
21
|
"author": "abearxiong",
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"devDependencies": {
|
|
24
|
+
"@kevisual/query": "^0.0.18",
|
|
24
25
|
"@rollup/plugin-alias": "^5.1.1",
|
|
25
26
|
"@rollup/plugin-commonjs": "^28.0.3",
|
|
26
27
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
27
28
|
"@rollup/plugin-typescript": "^12.1.2",
|
|
28
29
|
"@types/lodash-es": "^4.17.12",
|
|
29
|
-
"@types/node": "^22.
|
|
30
|
+
"@types/node": "^22.15.18",
|
|
30
31
|
"@types/ws": "^8.18.1",
|
|
31
32
|
"@types/xml2js": "^0.4.14",
|
|
32
33
|
"cookie": "^1.0.2",
|
|
33
34
|
"lodash-es": "^4.17.21",
|
|
34
35
|
"nanoid": "^5.1.5",
|
|
35
|
-
"rollup": "^4.40.
|
|
36
|
+
"rollup": "^4.40.2",
|
|
36
37
|
"rollup-plugin-dts": "^6.2.1",
|
|
37
38
|
"ts-loader": "^9.5.2",
|
|
38
39
|
"ts-node": "^10.9.2",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
"typescript": "^5.8.3",
|
|
41
42
|
"ws": "npm:@kevisual/ws",
|
|
42
43
|
"xml2js": "^0.6.2",
|
|
43
|
-
"zod": "^3.24.
|
|
44
|
+
"zod": "^3.24.4"
|
|
44
45
|
},
|
|
45
46
|
"repository": {
|
|
46
47
|
"type": "git",
|
package/src/router-define.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { QueryRouterServer, RouteOpts, Run, RouteMiddleware } from '@kevisual/router';
|
|
2
|
-
|
|
2
|
+
import type { DataOpts, Query, Result } from '@kevisual/query/query';
|
|
3
3
|
// export type RouteObject<T extends readonly string[]> = {
|
|
4
4
|
// [K in T[number]]: RouteOpts;
|
|
5
5
|
// };
|
|
@@ -70,6 +70,47 @@ class Chain {
|
|
|
70
70
|
return this;
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
+
type QueryChainOptions = {
|
|
74
|
+
query?: Query;
|
|
75
|
+
omitKeys?: string[];
|
|
76
|
+
};
|
|
77
|
+
class QueryChain {
|
|
78
|
+
obj: SimpleObject = {};
|
|
79
|
+
query: Query;
|
|
80
|
+
omitKeys: string[] = ['metadata', 'description', 'validator'];
|
|
81
|
+
constructor(value?: SimpleObject, opts?: QueryChainOptions) {
|
|
82
|
+
this.obj = value || {};
|
|
83
|
+
this.query = opts?.query;
|
|
84
|
+
if (opts?.omitKeys) this.omitKeys = opts.omitKeys;
|
|
85
|
+
}
|
|
86
|
+
omit(obj: SimpleObject, key: string[] = []) {
|
|
87
|
+
const newObj = { ...obj };
|
|
88
|
+
key.forEach((k) => {
|
|
89
|
+
delete newObj[k];
|
|
90
|
+
});
|
|
91
|
+
return newObj;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 生成
|
|
95
|
+
* @param queryData
|
|
96
|
+
* @returns
|
|
97
|
+
*/
|
|
98
|
+
getKey(queryData?: SimpleObject): Pick<RouteOpts, 'path' | 'key' | 'metadata' | 'description' | 'validator'> {
|
|
99
|
+
const obj = this.omit(this.obj, this.omitKeys);
|
|
100
|
+
return {
|
|
101
|
+
...obj,
|
|
102
|
+
...queryData,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
post<R = SimpleObject, P = SimpleObject>(data: P, options?: DataOpts): Promise<Result<R>> {
|
|
106
|
+
const _queryData = this.getKey(data);
|
|
107
|
+
return this.query.post(_queryData, options);
|
|
108
|
+
}
|
|
109
|
+
get<R = SimpleObject, P = SimpleObject>(data: P, options?: DataOpts): Promise<Result<R>> {
|
|
110
|
+
const _queryData = this.getKey(data);
|
|
111
|
+
return this.query.get(_queryData, options);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
73
114
|
export const util = {
|
|
74
115
|
getChain: (obj: RouteOpts, opts?: ChainOptions) => {
|
|
75
116
|
return new Chain(obj, opts);
|
|
@@ -77,11 +118,13 @@ export const util = {
|
|
|
77
118
|
};
|
|
78
119
|
|
|
79
120
|
export class QueryUtil<T extends RouteObject = RouteObject> {
|
|
80
|
-
|
|
121
|
+
obj: T;
|
|
81
122
|
app: QueryRouterServer;
|
|
82
|
-
|
|
83
|
-
|
|
123
|
+
query: Query;
|
|
124
|
+
constructor(object: T, opts?: ChainOptions & QueryChainOptions) {
|
|
125
|
+
this.obj = object;
|
|
84
126
|
this.app = opts?.app;
|
|
127
|
+
this.query = opts?.query;
|
|
85
128
|
}
|
|
86
129
|
static createFormObj<U extends RouteObject>(object: U, opts?: ChainOptions) {
|
|
87
130
|
return new QueryUtil<U>(object, opts);
|
|
@@ -91,20 +134,21 @@ export class QueryUtil<T extends RouteObject = RouteObject> {
|
|
|
91
134
|
return new QueryUtil<U>(obj, opts);
|
|
92
135
|
}
|
|
93
136
|
get<K extends keyof T>(key: K): RouteOpts {
|
|
94
|
-
return this.
|
|
137
|
+
return this.obj[key] as RouteOpts;
|
|
95
138
|
}
|
|
96
139
|
chain<K extends keyof T>(key: K, opts?: ChainOptions) {
|
|
97
|
-
const obj = this.
|
|
140
|
+
const obj = this.obj[key];
|
|
98
141
|
let newOpts = { app: this.app, ...opts };
|
|
99
|
-
return new Chain(obj, newOpts);
|
|
100
|
-
}
|
|
101
|
-
queryChain<K extends keyof T>(key: K
|
|
102
|
-
const value = this.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
142
|
+
return new QueryUtil.Chain(obj, newOpts);
|
|
143
|
+
}
|
|
144
|
+
queryChain<K extends keyof T>(key: K, opts?: QueryChainOptions) {
|
|
145
|
+
const value = this.obj[key];
|
|
146
|
+
let newOpts = { query: this.query, ...opts };
|
|
147
|
+
return new QueryUtil.QueryChain(value, newOpts);
|
|
148
|
+
}
|
|
149
|
+
static Chain = Chain;
|
|
150
|
+
static QueryChain = QueryChain;
|
|
151
|
+
get routeObject() {
|
|
152
|
+
return this.obj;
|
|
109
153
|
}
|
|
110
154
|
}
|
package/src/router-simple.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { pathToRegexp, Key } from 'path-to-regexp';
|
|
2
2
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
|
-
import { parseBody, parseSearch } from './server/parse-body.ts';
|
|
3
|
+
import { parseBody, parseSearch, parseSearchValue } from './server/parse-body.ts';
|
|
4
4
|
|
|
5
5
|
type Req = IncomingMessage & { params?: Record<string, string> };
|
|
6
6
|
interface Route {
|
|
@@ -24,6 +24,7 @@ export class SimpleRouter {
|
|
|
24
24
|
getSearch(req: Req) {
|
|
25
25
|
return parseSearch(req);
|
|
26
26
|
}
|
|
27
|
+
parseSearchValue = parseSearchValue;
|
|
27
28
|
use(method: string, route: string, ...fns: Array<(req: Req, res: ServerResponse) => Promise<void> | void>) {
|
|
28
29
|
const handlers = Array.isArray(fns) ? fns.flat() : [];
|
|
29
30
|
const pattern = pathToRegexp(route);
|
package/src/server/parse-body.ts
CHANGED
|
@@ -10,7 +10,39 @@ export const parseBody = async <T = Record<string, any>>(req: IncomingMessage) =
|
|
|
10
10
|
req.on('end', () => {
|
|
11
11
|
try {
|
|
12
12
|
const body = Buffer.concat(arr).toString();
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
// 获取 Content-Type 头信息
|
|
15
|
+
const contentType = req.headers['content-type'] || '';
|
|
16
|
+
|
|
17
|
+
// 处理 application/json
|
|
18
|
+
if (contentType.includes('application/json')) {
|
|
19
|
+
resolve(JSON.parse(body) as T);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// 处理 application/x-www-form-urlencoded
|
|
23
|
+
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
24
|
+
const formData = new URLSearchParams(body);
|
|
25
|
+
const result: Record<string, any> = {};
|
|
26
|
+
|
|
27
|
+
formData.forEach((value, key) => {
|
|
28
|
+
// 尝试将值解析为 JSON,如果失败则保留原始字符串
|
|
29
|
+
try {
|
|
30
|
+
result[key] = JSON.parse(value);
|
|
31
|
+
} catch {
|
|
32
|
+
result[key] = value;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
resolve(result as T);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 默认尝试 JSON 解析
|
|
41
|
+
try {
|
|
42
|
+
resolve(JSON.parse(body) as T);
|
|
43
|
+
} catch {
|
|
44
|
+
resolve({} as T);
|
|
45
|
+
}
|
|
14
46
|
} catch (e) {
|
|
15
47
|
resolve({} as T);
|
|
16
48
|
}
|