@kevisual/router 0.0.18 → 0.0.19

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.
@@ -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,42 @@ 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
- routeObject: T;
496
+ obj: T;
475
497
  app: QueryRouterServer$1;
476
498
  constructor(object: T, opts?: ChainOptions);
477
499
  static createFormObj<U extends RouteObject>(object: U, opts?: ChainOptions): QueryUtil<U>;
478
500
  static create<U extends Record<string, RouteOpts$1>>(value: U, opts?: ChainOptions): QueryUtil<U>;
479
501
  get<K extends keyof T>(key: K): RouteOpts$1;
480
502
  chain<K extends keyof T>(key: K, opts?: ChainOptions): Chain;
481
- queryChain<K extends keyof T>(key: K): (queryData?: Record<string, any>) => RouteOpts$1;
503
+ queryChain<K extends keyof T>(key: K, opts?: QueryChainOptions): QueryChain;
504
+ static Chain: typeof Chain;
505
+ static QueryChain: typeof QueryChain;
506
+ get routeObject(): T;
482
507
  }
483
508
 
484
509
  export { CustomError, QueryRouter, QueryRouterServer, QueryUtil, Route, createSchema, define, parseBody, parseSearch, parseSearchValue, util };
@@ -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
- // let regex = `\\d{2}:\\d{2}:\\d{2}`;
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
- regex = `${regex}\\.\\d{${args.precision}}`;
1059
+ secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`;
1061
1060
  }
1062
1061
  else if (args.precision == null) {
1063
- regex = `${regex}(\\.\\d+)?`;
1062
+ secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`;
1064
1063
  }
1065
- return regex;
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
- resolve(JSON.parse(body));
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,16 +6381,54 @@ 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
- routeObject;
6428
+ obj;
6362
6429
  app;
6363
6430
  constructor(object, opts) {
6364
- this.routeObject = object;
6431
+ this.obj = object;
6365
6432
  this.app = opts?.app;
6366
6433
  }
6367
6434
  static createFormObj(object, opts) {
@@ -6372,21 +6439,21 @@ class QueryUtil {
6372
6439
  return new QueryUtil(obj, opts);
6373
6440
  }
6374
6441
  get(key) {
6375
- return this.routeObject[key];
6442
+ return this.obj[key];
6376
6443
  }
6377
6444
  chain(key, opts) {
6378
- const obj = this.routeObject[key];
6445
+ const obj = this.obj[key];
6379
6446
  let newOpts = { app: this.app, ...opts };
6380
- return new Chain(obj, newOpts);
6447
+ return new QueryUtil.Chain(obj, newOpts);
6381
6448
  }
6382
- queryChain(key) {
6383
- const value = this.routeObject[key];
6384
- return (queryData) => {
6385
- return {
6386
- ...value,
6387
- ...queryData,
6388
- };
6389
- };
6449
+ queryChain(key, opts) {
6450
+ const value = this.obj[key];
6451
+ return new QueryUtil.QueryChain(value, opts);
6452
+ }
6453
+ static Chain = Chain;
6454
+ static QueryChain = QueryChain;
6455
+ get routeObject() {
6456
+ return this.obj;
6390
6457
  }
6391
6458
  }
6392
6459
 
@@ -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,42 @@ 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
- routeObject: T;
59
+ obj: T;
38
60
  app: QueryRouterServer;
39
61
  constructor(object: T, opts?: ChainOptions);
40
62
  static createFormObj<U extends RouteObject>(object: U, opts?: ChainOptions): QueryUtil<U>;
41
63
  static create<U extends Record<string, RouteOpts>>(value: U, opts?: ChainOptions): QueryUtil<U>;
42
64
  get<K extends keyof T>(key: K): RouteOpts;
43
65
  chain<K extends keyof T>(key: K, opts?: ChainOptions): Chain;
44
- queryChain<K extends keyof T>(key: K): (queryData?: Record<string, any>) => RouteOpts;
66
+ queryChain<K extends keyof T>(key: K, opts?: QueryChainOptions): QueryChain;
67
+ static Chain: typeof Chain;
68
+ static QueryChain: typeof QueryChain;
69
+ get routeObject(): T;
45
70
  }
46
71
 
47
72
  export { QueryUtil, define, util };
@@ -51,16 +51,54 @@ 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
- routeObject;
98
+ obj;
61
99
  app;
62
100
  constructor(object, opts) {
63
- this.routeObject = object;
101
+ this.obj = object;
64
102
  this.app = opts?.app;
65
103
  }
66
104
  static createFormObj(object, opts) {
@@ -71,21 +109,21 @@ class QueryUtil {
71
109
  return new QueryUtil(obj, opts);
72
110
  }
73
111
  get(key) {
74
- return this.routeObject[key];
112
+ return this.obj[key];
75
113
  }
76
114
  chain(key, opts) {
77
- const obj = this.routeObject[key];
115
+ const obj = this.obj[key];
78
116
  let newOpts = { app: this.app, ...opts };
79
- return new Chain(obj, newOpts);
80
- }
81
- queryChain(key) {
82
- const value = this.routeObject[key];
83
- return (queryData) => {
84
- return {
85
- ...value,
86
- ...queryData,
87
- };
88
- };
117
+ return new QueryUtil.Chain(obj, newOpts);
118
+ }
119
+ queryChain(key, opts) {
120
+ const value = this.obj[key];
121
+ return new QueryUtil.QueryChain(value, opts);
122
+ }
123
+ static Chain = Chain;
124
+ static QueryChain = QueryChain;
125
+ get routeObject() {
126
+ return this.obj;
89
127
  }
90
128
  }
91
129
 
@@ -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;
@@ -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
- resolve(JSON.parse(body));
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,42 @@ 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
- routeObject: T;
637
+ obj: T;
616
638
  app: QueryRouterServer$1;
617
639
  constructor(object: T, opts?: ChainOptions);
618
640
  static createFormObj<U extends RouteObject>(object: U, opts?: ChainOptions): QueryUtil<U>;
619
641
  static create<U extends Record<string, RouteOpts$1>>(value: U, opts?: ChainOptions): QueryUtil<U>;
620
642
  get<K extends keyof T>(key: K): RouteOpts$1;
621
643
  chain<K extends keyof T>(key: K, opts?: ChainOptions): Chain;
622
- queryChain<K extends keyof T>(key: K): (queryData?: Record<string, any>) => RouteOpts$1;
644
+ queryChain<K extends keyof T>(key: K, opts?: QueryChainOptions): QueryChain;
645
+ static Chain: typeof Chain;
646
+ static QueryChain: typeof QueryChain;
647
+ get routeObject(): T;
623
648
  }
624
649
 
625
650
  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
- // let regex = `\\d{2}:\\d{2}:\\d{2}`;
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
- regex = `${regex}\\.\\d{${args.precision}}`;
1081
+ secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`;
1083
1082
  }
1084
1083
  else if (args.precision == null) {
1085
- regex = `${regex}(\\.\\d+)?`;
1084
+ secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`;
1086
1085
  }
1087
- return regex;
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
- resolve(JSON.parse(body));
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,16 +12020,54 @@ 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
- routeObject;
12067
+ obj;
12001
12068
  app;
12002
12069
  constructor(object, opts) {
12003
- this.routeObject = object;
12070
+ this.obj = object;
12004
12071
  this.app = opts?.app;
12005
12072
  }
12006
12073
  static createFormObj(object, opts) {
@@ -12011,21 +12078,21 @@ class QueryUtil {
12011
12078
  return new QueryUtil(obj, opts);
12012
12079
  }
12013
12080
  get(key) {
12014
- return this.routeObject[key];
12081
+ return this.obj[key];
12015
12082
  }
12016
12083
  chain(key, opts) {
12017
- const obj = this.routeObject[key];
12084
+ const obj = this.obj[key];
12018
12085
  let newOpts = { app: this.app, ...opts };
12019
- return new Chain(obj, newOpts);
12086
+ return new QueryUtil.Chain(obj, newOpts);
12020
12087
  }
12021
- queryChain(key) {
12022
- const value = this.routeObject[key];
12023
- return (queryData) => {
12024
- return {
12025
- ...value,
12026
- ...queryData,
12027
- };
12028
- };
12088
+ queryChain(key, opts) {
12089
+ const value = this.obj[key];
12090
+ return new QueryUtil.QueryChain(value, opts);
12091
+ }
12092
+ static Chain = Chain;
12093
+ static QueryChain = QueryChain;
12094
+ get routeObject() {
12095
+ return this.obj;
12029
12096
  }
12030
12097
  }
12031
12098
 
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.18",
4
+ "version": "0.0.19",
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.14.1",
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.0",
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.3"
44
+ "zod": "^3.24.4"
44
45
  },
45
46
  "repository": {
46
47
  "type": "git",
@@ -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,10 +118,10 @@ export const util = {
77
118
  };
78
119
 
79
120
  export class QueryUtil<T extends RouteObject = RouteObject> {
80
- routeObject: T;
121
+ obj: T;
81
122
  app: QueryRouterServer;
82
123
  constructor(object: T, opts?: ChainOptions) {
83
- this.routeObject = object;
124
+ this.obj = object;
84
125
  this.app = opts?.app;
85
126
  }
86
127
  static createFormObj<U extends RouteObject>(object: U, opts?: ChainOptions) {
@@ -91,20 +132,20 @@ export class QueryUtil<T extends RouteObject = RouteObject> {
91
132
  return new QueryUtil<U>(obj, opts);
92
133
  }
93
134
  get<K extends keyof T>(key: K): RouteOpts {
94
- return this.routeObject[key] as RouteOpts;
135
+ return this.obj[key] as RouteOpts;
95
136
  }
96
137
  chain<K extends keyof T>(key: K, opts?: ChainOptions) {
97
- const obj = this.routeObject[key];
138
+ const obj = this.obj[key];
98
139
  let newOpts = { app: this.app, ...opts };
99
- return new Chain(obj, newOpts);
100
- }
101
- queryChain<K extends keyof T>(key: K): (queryData?: Record<string, any>) => RouteOpts {
102
- const value = this.routeObject[key];
103
- return (queryData?: Record<string, any>) => {
104
- return {
105
- ...value,
106
- ...queryData,
107
- };
108
- };
140
+ return new QueryUtil.Chain(obj, newOpts);
141
+ }
142
+ queryChain<K extends keyof T>(key: K, opts?: QueryChainOptions) {
143
+ const value = this.obj[key];
144
+ return new QueryUtil.QueryChain(value, opts);
145
+ }
146
+ static Chain = Chain;
147
+ static QueryChain = QueryChain;
148
+ get routeObject() {
149
+ return this.obj;
109
150
  }
110
151
  }
@@ -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);
@@ -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
- resolve(JSON.parse(body));
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
  }