@kevisual/router 0.0.17 → 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;
@@ -109,7 +110,8 @@ type RouteContext<T = {
109
110
  /** 是否需要序列化 */
110
111
  needSerialize?: boolean;
111
112
  } & T;
112
- type Run<T = any> = (ctx: RouteContext<T>) => Promise<typeof ctx | null | void>;
113
+ type SimpleObject$1 = Record<string, any>;
114
+ type Run<T extends SimpleObject$1 = {}> = (ctx: RouteContext<T>) => Promise<typeof ctx | null | void>;
113
115
  type NextRoute = Pick<Route, 'id' | 'path' | 'key'>;
114
116
  type RouteMiddleware = {
115
117
  path: string;
@@ -440,6 +442,7 @@ declare const parseSearchValue: (value?: string, opts?: {
440
442
  type RouteObject = {
441
443
  [key: string]: RouteOpts$1;
442
444
  };
445
+ type SimpleObject = Record<string, any>;
443
446
  declare function define<T extends Record<string, RouteOpts$1>>(value: T): {
444
447
  [K in keyof T]: T[K] & RouteOpts$1;
445
448
  };
@@ -461,22 +464,46 @@ declare class Chain {
461
464
  setMiddleware(middleware: RouteMiddleware$1[]): this;
462
465
  setKey(key: string): this;
463
466
  setId(key: string): this;
464
- setRun(run: Run$1): this;
465
- define(run: Run$1): this;
467
+ setRun<U extends SimpleObject = {}>(run: Run$1<U>): this;
468
+ define<U extends SimpleObject = {}>(run: Run$1<U>): this;
466
469
  createRoute(): this;
467
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
+ }
468
492
  declare const util: {
469
493
  getChain: (obj: RouteOpts$1, opts?: ChainOptions) => Chain;
470
494
  };
471
495
  declare class QueryUtil<T extends RouteObject = RouteObject> {
472
- routeObject: T;
496
+ obj: T;
473
497
  app: QueryRouterServer$1;
474
498
  constructor(object: T, opts?: ChainOptions);
475
499
  static createFormObj<U extends RouteObject>(object: U, opts?: ChainOptions): QueryUtil<U>;
476
500
  static create<U extends Record<string, RouteOpts$1>>(value: U, opts?: ChainOptions): QueryUtil<U>;
477
501
  get<K extends keyof T>(key: K): RouteOpts$1;
478
502
  chain<K extends keyof T>(key: K, opts?: ChainOptions): Chain;
479
- 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;
480
507
  }
481
508
 
482
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,9 +1,11 @@
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;
6
7
  };
8
+ type SimpleObject = Record<string, any>;
7
9
  declare function define<T extends Record<string, RouteOpts>>(value: T): {
8
10
  [K in keyof T]: T[K] & RouteOpts;
9
11
  };
@@ -25,22 +27,46 @@ declare class Chain {
25
27
  setMiddleware(middleware: RouteMiddleware[]): this;
26
28
  setKey(key: string): this;
27
29
  setId(key: string): this;
28
- setRun(run: Run): this;
29
- define(run: Run): this;
30
+ setRun<U extends SimpleObject = {}>(run: Run<U>): this;
31
+ define<U extends SimpleObject = {}>(run: Run<U>): this;
30
32
  createRoute(): this;
31
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
+ }
32
55
  declare const util: {
33
56
  getChain: (obj: RouteOpts, opts?: ChainOptions) => Chain;
34
57
  };
35
58
  declare class QueryUtil<T extends RouteObject = RouteObject> {
36
- routeObject: T;
59
+ obj: T;
37
60
  app: QueryRouterServer;
38
61
  constructor(object: T, opts?: ChainOptions);
39
62
  static createFormObj<U extends RouteObject>(object: U, opts?: ChainOptions): QueryUtil<U>;
40
63
  static create<U extends Record<string, RouteOpts>>(value: U, opts?: ChainOptions): QueryUtil<U>;
41
64
  get<K extends keyof T>(key: K): RouteOpts;
42
65
  chain<K extends keyof T>(key: K, opts?: ChainOptions): Chain;
43
- 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;
44
70
  }
45
71
 
46
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;
@@ -112,7 +113,8 @@ type RouteContext<T = {
112
113
  /** 是否需要序列化 */
113
114
  needSerialize?: boolean;
114
115
  } & T;
115
- type Run<T = any> = (ctx: RouteContext<T>) => Promise<typeof ctx | null | void>;
116
+ type SimpleObject$1 = Record<string, any>;
117
+ type Run<T extends SimpleObject$1 = {}> = (ctx: RouteContext<T>) => Promise<typeof ctx | null | void>;
116
118
  type NextRoute = Pick<Route, 'id' | 'path' | 'key'>;
117
119
  type RouteMiddleware = {
118
120
  path: string;
@@ -581,6 +583,7 @@ declare class WsServer extends WsServerBase {
581
583
  type RouteObject = {
582
584
  [key: string]: RouteOpts$1;
583
585
  };
586
+ type SimpleObject = Record<string, any>;
584
587
  declare function define<T extends Record<string, RouteOpts$1>>(value: T): {
585
588
  [K in keyof T]: T[K] & RouteOpts$1;
586
589
  };
@@ -602,22 +605,46 @@ declare class Chain {
602
605
  setMiddleware(middleware: RouteMiddleware$1[]): this;
603
606
  setKey(key: string): this;
604
607
  setId(key: string): this;
605
- setRun(run: Run$1): this;
606
- define(run: Run$1): this;
608
+ setRun<U extends SimpleObject = {}>(run: Run$1<U>): this;
609
+ define<U extends SimpleObject = {}>(run: Run$1<U>): this;
607
610
  createRoute(): this;
608
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
+ }
609
633
  declare const util: {
610
634
  getChain: (obj: RouteOpts$1, opts?: ChainOptions) => Chain;
611
635
  };
612
636
  declare class QueryUtil<T extends RouteObject = RouteObject> {
613
- routeObject: T;
637
+ obj: T;
614
638
  app: QueryRouterServer$1;
615
639
  constructor(object: T, opts?: ChainOptions);
616
640
  static createFormObj<U extends RouteObject>(object: U, opts?: ChainOptions): QueryUtil<U>;
617
641
  static create<U extends Record<string, RouteOpts$1>>(value: U, opts?: ChainOptions): QueryUtil<U>;
618
642
  get<K extends keyof T>(key: K): RouteOpts$1;
619
643
  chain<K extends keyof T>(key: K, opts?: ChainOptions): Chain;
620
- 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;
621
648
  }
622
649
 
623
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.17",
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",
package/src/route.ts CHANGED
@@ -57,8 +57,8 @@ export type RouteContext<T = { code?: number }, S = any> = {
57
57
  /** 是否需要序列化 */
58
58
  needSerialize?: boolean;
59
59
  } & T;
60
-
61
- export type Run<T = any> = (ctx: RouteContext<T>) => Promise<typeof ctx | null | void>;
60
+ export type SimpleObject = Record<string, any>;
61
+ export type Run<T extends SimpleObject = {}> = (ctx: RouteContext<T>) => Promise<typeof ctx | null | void>;
62
62
 
63
63
  export type NextRoute = Pick<Route, 'id' | 'path' | 'key'>;
64
64
  export type RouteMiddleware =
@@ -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
  // };
@@ -7,7 +7,7 @@ export type { RouteOpts };
7
7
  export type RouteObject = {
8
8
  [key: string]: RouteOpts;
9
9
  };
10
-
10
+ type SimpleObject = Record<string, any>;
11
11
  export function define<T extends Record<string, RouteOpts>>(
12
12
  value: T,
13
13
  ): {
@@ -57,11 +57,11 @@ class Chain {
57
57
  this.object.id = key;
58
58
  return this;
59
59
  }
60
- setRun(run: Run) {
60
+ setRun<U extends SimpleObject = {}>(run: Run<U>) {
61
61
  this.object.run = run;
62
62
  return this;
63
63
  }
64
- define(run: Run) {
64
+ define<U extends SimpleObject = {}>(run: Run<U>) {
65
65
  this.object.run = run;
66
66
  return this;
67
67
  }
@@ -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
  }
@@ -8,3 +8,7 @@ const v = QueryUtil.create({
8
8
  });
9
9
  const app = new App();
10
10
  app.route(v.get('a'));
11
+
12
+ v.chain('a').define<{ f: () => {} }>(async (ctx) => {
13
+ // ctx.f = 'sdf';
14
+ });