@kevisual/router 0.0.6-alpha-1 → 0.0.6-alpha-3

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.
@@ -118,7 +118,9 @@ type RouteOpts = {
118
118
  type DefineRouteOpts = Omit<RouteOpts, 'idUsePath' | 'verify' | 'verifyKey' | 'nextRoute'>;
119
119
  declare const pickValue: readonly ["path", "key", "id", "description", "type", "validator", "middleware"];
120
120
  type RouteInfo = Pick<Route, (typeof pickValue)[number]>;
121
- declare class Route {
121
+ declare class Route<U = {
122
+ [key: string]: any;
123
+ }> {
122
124
  path?: string;
123
125
  key?: string;
124
126
  id?: string;
@@ -180,13 +182,13 @@ declare class Route {
180
182
  } = RouterContextT>(opts: DefineRouteOpts): this;
181
183
  define<T extends {
182
184
  [key: string]: any;
183
- } = RouterContextT>(fn: Run<T>): this;
185
+ } = RouterContextT>(fn: Run<T & U>): this;
184
186
  define<T extends {
185
187
  [key: string]: any;
186
- } = RouterContextT>(key: string, fn: Run<T>): this;
188
+ } = RouterContextT>(key: string, fn: Run<T & U>): this;
187
189
  define<T extends {
188
190
  [key: string]: any;
189
- } = RouterContextT>(path: string, key: string, fn: Run<T>): this;
191
+ } = RouterContextT>(path: string, key: string, fn: Run<T & U>): this;
190
192
  addTo(router: QueryRouter | {
191
193
  add: (route: Route) => void;
192
194
  [key: string]: any;
@@ -270,7 +272,7 @@ declare class QueryRouter {
270
272
  path: string;
271
273
  key?: string;
272
274
  [key: string]: any;
273
- }) => Promise<{
275
+ }, handleContext?: RouteContext) => Promise<{
274
276
  [key: string]: any;
275
277
  code: string;
276
278
  data?: any;
@@ -279,8 +281,14 @@ declare class QueryRouter {
279
281
  code: any;
280
282
  data: any;
281
283
  message: any;
284
+ } | {
285
+ code: number;
286
+ message: any;
287
+ data?: undefined;
282
288
  }>;
283
- exportRoutes(): Route[];
289
+ exportRoutes(): Route<{
290
+ [key: string]: any;
291
+ }>[];
284
292
  importRoutes(routes: Route[]): void;
285
293
  importRouter(router: QueryRouter): void;
286
294
  throw(code?: number | string, message?: string, tips?: string): void;
@@ -3,7 +3,7 @@ const urlAlphabet =
3
3
 
4
4
  let nanoid = (size = 21) => {
5
5
  let id = '';
6
- let bytes = crypto.getRandomValues(new Uint8Array(size));
6
+ let bytes = crypto.getRandomValues(new Uint8Array((size |= 0)));
7
7
  while (size--) {
8
8
  id += urlAlphabet[bytes[size] & 63];
9
9
  }
@@ -5901,15 +5901,20 @@ class QueryRouter {
5901
5901
  });
5902
5902
  }
5903
5903
  getHandle(router, wrapperFn, ctx) {
5904
- return async (msg) => {
5905
- const context = { ...ctx };
5906
- const res = await router.parse(msg, context);
5907
- if (wrapperFn) {
5908
- res.data = res.body;
5909
- return wrapperFn(res, context);
5910
- }
5911
- const { code, body, message } = res;
5912
- return { code, data: body, message };
5904
+ return async (msg, handleContext) => {
5905
+ try {
5906
+ const context = { ...ctx, ...handleContext };
5907
+ const res = await router.parse(msg, context);
5908
+ if (wrapperFn) {
5909
+ res.data = res.body;
5910
+ return wrapperFn(res, context);
5911
+ }
5912
+ const { code, body, message } = res;
5913
+ return { code, data: body, message };
5914
+ }
5915
+ catch (e) {
5916
+ return { code: 500, message: e.message };
5917
+ }
5913
5918
  };
5914
5919
  }
5915
5920
  exportRoutes() {
package/dist/router.d.ts CHANGED
@@ -2,6 +2,8 @@ import { Schema } from 'zod';
2
2
  export { Schema } from 'zod';
3
3
  import http, { IncomingMessage, ServerResponse } from 'http';
4
4
  import https from 'https';
5
+ import http2 from 'http2';
6
+ import * as cookie from 'cookie';
5
7
  import { WebSocketServer, WebSocket } from 'ws';
6
8
 
7
9
  type BaseRule = {
@@ -121,7 +123,9 @@ type RouteOpts = {
121
123
  type DefineRouteOpts = Omit<RouteOpts, 'idUsePath' | 'verify' | 'verifyKey' | 'nextRoute'>;
122
124
  declare const pickValue: readonly ["path", "key", "id", "description", "type", "validator", "middleware"];
123
125
  type RouteInfo = Pick<Route, (typeof pickValue)[number]>;
124
- declare class Route {
126
+ declare class Route<U = {
127
+ [key: string]: any;
128
+ }> {
125
129
  path?: string;
126
130
  key?: string;
127
131
  id?: string;
@@ -183,13 +187,13 @@ declare class Route {
183
187
  } = RouterContextT>(opts: DefineRouteOpts): this;
184
188
  define<T extends {
185
189
  [key: string]: any;
186
- } = RouterContextT>(fn: Run<T>): this;
190
+ } = RouterContextT>(fn: Run<T & U>): this;
187
191
  define<T extends {
188
192
  [key: string]: any;
189
- } = RouterContextT>(key: string, fn: Run<T>): this;
193
+ } = RouterContextT>(key: string, fn: Run<T & U>): this;
190
194
  define<T extends {
191
195
  [key: string]: any;
192
- } = RouterContextT>(path: string, key: string, fn: Run<T>): this;
196
+ } = RouterContextT>(path: string, key: string, fn: Run<T & U>): this;
193
197
  addTo(router: QueryRouter | {
194
198
  add: (route: Route) => void;
195
199
  [key: string]: any;
@@ -273,7 +277,7 @@ declare class QueryRouter {
273
277
  path: string;
274
278
  key?: string;
275
279
  [key: string]: any;
276
- }) => Promise<{
280
+ }, handleContext?: RouteContext) => Promise<{
277
281
  [key: string]: any;
278
282
  code: string;
279
283
  data?: any;
@@ -282,8 +286,14 @@ declare class QueryRouter {
282
286
  code: any;
283
287
  data: any;
284
288
  message: any;
289
+ } | {
290
+ code: number;
291
+ message: any;
292
+ data?: undefined;
285
293
  }>;
286
- exportRoutes(): Route[];
294
+ exportRoutes(): Route<{
295
+ [key: string]: any;
296
+ }>[];
287
297
  importRoutes(routes: Route[]): void;
288
298
  importRouter(router: QueryRouter): void;
289
299
  throw(code?: number | string, message?: string, tips?: string): void;
@@ -362,6 +372,18 @@ declare class QueryConnect {
362
372
  }
363
373
 
364
374
  type Listener = (...args: any[]) => void;
375
+ type CookieFn = (name: string, value: string, options?: cookie.SerializeOptions, end?: boolean) => void;
376
+ type HandleCtx = {
377
+ req: IncomingMessage & {
378
+ cookies: Record<string, string>;
379
+ };
380
+ res: ServerResponse & {
381
+ /**
382
+ * cookie 函数, end 参数用于设置是否立即设置到响应头,设置了后面的cookie再设置会覆盖前面的
383
+ */
384
+ cookie: CookieFn;
385
+ };
386
+ };
365
387
  type Cors = {
366
388
  /**
367
389
  * @default '*''
@@ -376,9 +398,12 @@ type ServerOpts = {
376
398
  path: string;
377
399
  key?: string;
378
400
  [key: string]: any;
401
+ }, ctx?: {
402
+ req: http.IncomingMessage;
403
+ res: http.ServerResponse;
379
404
  }) => any;
380
405
  cors?: Cors;
381
- isHTTPS?: boolean;
406
+ httpType?: 'http' | 'https' | 'http2';
382
407
  httpsKey?: string;
383
408
  httpsCert?: string;
384
409
  };
@@ -389,7 +414,7 @@ declare class Server {
389
414
  private _callback;
390
415
  private cors;
391
416
  private hasOn;
392
- private isHTTPS;
417
+ private httpType;
393
418
  private options;
394
419
  constructor(opts?: ServerOpts);
395
420
  listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): void;
@@ -400,7 +425,7 @@ declare class Server {
400
425
  listen(path: string, listeningListener?: () => void): void;
401
426
  listen(handle: any, backlog?: number, listeningListener?: () => void): void;
402
427
  listen(handle: any, listeningListener?: () => void): void;
403
- createServer(): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | https.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
428
+ createServer(): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | https.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | http2.Http2SecureServer<typeof http.IncomingMessage, typeof http.ServerResponse, typeof http2.Http2ServerRequest, typeof http2.Http2ServerResponse>;
404
429
  setHandle(handle?: any): void;
405
430
  /**
406
431
  * get callback
@@ -416,7 +441,7 @@ declare class Server {
416
441
  */
417
442
  on(listener: Listener | Listener[]): void;
418
443
  get callback(): any;
419
- get server(): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
444
+ get server(): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | https.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | http2.Http2SecureServer<typeof http.IncomingMessage, typeof http.ServerResponse, typeof http2.Http2ServerRequest, typeof http2.Http2ServerResponse>;
420
445
  }
421
446
 
422
447
  /**
@@ -426,6 +451,7 @@ declare class Server {
426
451
  * @returns
427
452
  */
428
453
  declare const handleServer: (req: IncomingMessage, res: ServerResponse) => Promise<{
454
+ cookies: Record<string, string>;
429
455
  token: string;
430
456
  }>;
431
457
 
@@ -497,14 +523,7 @@ type AppOptions<T = {}> = {
497
523
  /** handle msg 关联 */
498
524
  routerHandle?: RouterHandle;
499
525
  routerContext?: RouteContext<T>;
500
- serverOptions?: {
501
- path?: string;
502
- cors?: Cors;
503
- handle?: any;
504
- isHTTPS?: boolean;
505
- httpsKey?: string;
506
- httpsCert?: string;
507
- };
526
+ serverOptions?: ServerOpts;
508
527
  io?: boolean;
509
528
  ioOpts?: {
510
529
  routerHandle?: RouterHandle;
@@ -512,7 +531,11 @@ type AppOptions<T = {}> = {
512
531
  path?: string;
513
532
  };
514
533
  };
515
- declare class App<T = {}> {
534
+ type AppReqRes = HandleCtx;
535
+ /**
536
+ * 封装了 Router 和 Server 的 App 模块,处理http的请求和响应,内置了 Cookie 和 Token 和 res 的处理
537
+ */
538
+ declare class App<T = {}, U = AppReqRes> {
516
539
  router: QueryRouter;
517
540
  server: Server;
518
541
  io: WsServer;
@@ -529,7 +552,7 @@ declare class App<T = {}> {
529
552
  addRoute(route: Route): void;
530
553
  add: (route: Route) => void;
531
554
  Route: typeof Route;
532
- route(opts: RouteOpts): Route;
555
+ route(opts: RouteOpts): Route<U>;
533
556
  route(path: string, key?: string): Route;
534
557
  route(path: string, opts?: RouteOpts): Route;
535
558
  route(path: string, key?: string, opts?: RouteOpts): Route;
@@ -547,7 +570,9 @@ declare class App<T = {}> {
547
570
  data: any;
548
571
  message: any;
549
572
  }>;
550
- exportRoutes(): Route[];
573
+ exportRoutes(): Route<{
574
+ [key: string]: any;
575
+ }>[];
551
576
  importRoutes(routes: any[]): void;
552
577
  importApp(app: App): void;
553
578
  throw(code?: number | string, message?: string, tips?: string): void;
package/dist/router.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { webcrypto } from 'node:crypto';
2
2
  import http from 'http';
3
3
  import https from 'https';
4
+ import http2 from 'http2';
4
5
  import url from 'url';
5
6
  import { WebSocketServer } from 'ws';
6
7
 
@@ -21,7 +22,7 @@ function fillPool(bytes) {
21
22
  poolOffset += bytes;
22
23
  }
23
24
  function nanoid(size = 21) {
24
- fillPool((size -= 0));
25
+ fillPool((size |= 0));
25
26
  let id = '';
26
27
  for (let i = poolOffset - size; i < poolOffset; i++) {
27
28
  id += urlAlphabet[pool[i] & 63];
@@ -5920,15 +5921,20 @@ class QueryRouter {
5920
5921
  });
5921
5922
  }
5922
5923
  getHandle(router, wrapperFn, ctx) {
5923
- return async (msg) => {
5924
- const context = { ...ctx };
5925
- const res = await router.parse(msg, context);
5926
- if (wrapperFn) {
5927
- res.data = res.body;
5928
- return wrapperFn(res, context);
5929
- }
5930
- const { code, body, message } = res;
5931
- return { code, data: body, message };
5924
+ return async (msg, handleContext) => {
5925
+ try {
5926
+ const context = { ...ctx, ...handleContext };
5927
+ const res = await router.parse(msg, context);
5928
+ if (wrapperFn) {
5929
+ res.data = res.body;
5930
+ return wrapperFn(res, context);
5931
+ }
5932
+ const { code, body, message } = res;
5933
+ return { code, data: body, message };
5934
+ }
5935
+ catch (e) {
5936
+ return { code: 500, message: e.message };
5937
+ }
5932
5938
  };
5933
5939
  }
5934
5940
  exportRoutes() {
@@ -6119,9 +6125,16 @@ const handleServer = async (req, res) => {
6119
6125
  const parsedUrl = url.parse(req.url, true);
6120
6126
  // 获取token
6121
6127
  let token = req.headers['authorization'] || '';
6128
+ const handle = createHandleCtx(req, res);
6129
+ const cookies = handle.req.cookies;
6130
+ if (!token) {
6131
+ token = cookies.token;
6132
+ }
6122
6133
  if (token) {
6123
6134
  token = token.replace('Bearer ', '');
6124
6135
  }
6136
+ //@ts-ignore
6137
+ console.log('token', req.cookies, res.cookie);
6125
6138
  // 获取查询参数
6126
6139
  const param = parsedUrl.query;
6127
6140
  let body;
@@ -6141,10 +6154,287 @@ const handleServer = async (req, res) => {
6141
6154
  token,
6142
6155
  ...param,
6143
6156
  ...body,
6157
+ cookies,
6144
6158
  };
6145
6159
  return data;
6146
6160
  };
6147
6161
 
6162
+ var dist = {};
6163
+
6164
+ var hasRequiredDist;
6165
+
6166
+ function requireDist () {
6167
+ if (hasRequiredDist) return dist;
6168
+ hasRequiredDist = 1;
6169
+ Object.defineProperty(dist, "__esModule", { value: true });
6170
+ dist.parse = parse;
6171
+ dist.serialize = serialize;
6172
+ /**
6173
+ * RegExp to match cookie-name in RFC 6265 sec 4.1.1
6174
+ * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2
6175
+ * which has been replaced by the token definition in RFC 7230 appendix B.
6176
+ *
6177
+ * cookie-name = token
6178
+ * token = 1*tchar
6179
+ * tchar = "!" / "#" / "$" / "%" / "&" / "'" /
6180
+ * "*" / "+" / "-" / "." / "^" / "_" /
6181
+ * "`" / "|" / "~" / DIGIT / ALPHA
6182
+ *
6183
+ * Note: Allowing more characters - https://github.com/jshttp/cookie/issues/191
6184
+ * Allow same range as cookie value, except `=`, which delimits end of name.
6185
+ */
6186
+ const cookieNameRegExp = /^[\u0021-\u003A\u003C\u003E-\u007E]+$/;
6187
+ /**
6188
+ * RegExp to match cookie-value in RFC 6265 sec 4.1.1
6189
+ *
6190
+ * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
6191
+ * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
6192
+ * ; US-ASCII characters excluding CTLs,
6193
+ * ; whitespace DQUOTE, comma, semicolon,
6194
+ * ; and backslash
6195
+ *
6196
+ * Allowing more characters: https://github.com/jshttp/cookie/issues/191
6197
+ * Comma, backslash, and DQUOTE are not part of the parsing algorithm.
6198
+ */
6199
+ const cookieValueRegExp = /^[\u0021-\u003A\u003C-\u007E]*$/;
6200
+ /**
6201
+ * RegExp to match domain-value in RFC 6265 sec 4.1.1
6202
+ *
6203
+ * domain-value = <subdomain>
6204
+ * ; defined in [RFC1034], Section 3.5, as
6205
+ * ; enhanced by [RFC1123], Section 2.1
6206
+ * <subdomain> = <label> | <subdomain> "." <label>
6207
+ * <label> = <let-dig> [ [ <ldh-str> ] <let-dig> ]
6208
+ * Labels must be 63 characters or less.
6209
+ * 'let-dig' not 'letter' in the first char, per RFC1123
6210
+ * <ldh-str> = <let-dig-hyp> | <let-dig-hyp> <ldh-str>
6211
+ * <let-dig-hyp> = <let-dig> | "-"
6212
+ * <let-dig> = <letter> | <digit>
6213
+ * <letter> = any one of the 52 alphabetic characters A through Z in
6214
+ * upper case and a through z in lower case
6215
+ * <digit> = any one of the ten digits 0 through 9
6216
+ *
6217
+ * Keep support for leading dot: https://github.com/jshttp/cookie/issues/173
6218
+ *
6219
+ * > (Note that a leading %x2E ("."), if present, is ignored even though that
6220
+ * character is not permitted, but a trailing %x2E ("."), if present, will
6221
+ * cause the user agent to ignore the attribute.)
6222
+ */
6223
+ const domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
6224
+ /**
6225
+ * RegExp to match path-value in RFC 6265 sec 4.1.1
6226
+ *
6227
+ * path-value = <any CHAR except CTLs or ";">
6228
+ * CHAR = %x01-7F
6229
+ * ; defined in RFC 5234 appendix B.1
6230
+ */
6231
+ const pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/;
6232
+ const __toString = Object.prototype.toString;
6233
+ const NullObject = /* @__PURE__ */ (() => {
6234
+ const C = function () { };
6235
+ C.prototype = Object.create(null);
6236
+ return C;
6237
+ })();
6238
+ /**
6239
+ * Parse a cookie header.
6240
+ *
6241
+ * Parse the given cookie header string into an object
6242
+ * The object has the various cookies as keys(names) => values
6243
+ */
6244
+ function parse(str, options) {
6245
+ const obj = new NullObject();
6246
+ const len = str.length;
6247
+ // RFC 6265 sec 4.1.1, RFC 2616 2.2 defines a cookie name consists of one char minimum, plus '='.
6248
+ if (len < 2)
6249
+ return obj;
6250
+ const dec = options?.decode || decode;
6251
+ let index = 0;
6252
+ do {
6253
+ const eqIdx = str.indexOf("=", index);
6254
+ if (eqIdx === -1)
6255
+ break; // No more cookie pairs.
6256
+ const colonIdx = str.indexOf(";", index);
6257
+ const endIdx = colonIdx === -1 ? len : colonIdx;
6258
+ if (eqIdx > endIdx) {
6259
+ // backtrack on prior semicolon
6260
+ index = str.lastIndexOf(";", eqIdx - 1) + 1;
6261
+ continue;
6262
+ }
6263
+ const keyStartIdx = startIndex(str, index, eqIdx);
6264
+ const keyEndIdx = endIndex(str, eqIdx, keyStartIdx);
6265
+ const key = str.slice(keyStartIdx, keyEndIdx);
6266
+ // only assign once
6267
+ if (obj[key] === undefined) {
6268
+ let valStartIdx = startIndex(str, eqIdx + 1, endIdx);
6269
+ let valEndIdx = endIndex(str, endIdx, valStartIdx);
6270
+ const value = dec(str.slice(valStartIdx, valEndIdx));
6271
+ obj[key] = value;
6272
+ }
6273
+ index = endIdx + 1;
6274
+ } while (index < len);
6275
+ return obj;
6276
+ }
6277
+ function startIndex(str, index, max) {
6278
+ do {
6279
+ const code = str.charCodeAt(index);
6280
+ if (code !== 0x20 /* */ && code !== 0x09 /* \t */)
6281
+ return index;
6282
+ } while (++index < max);
6283
+ return max;
6284
+ }
6285
+ function endIndex(str, index, min) {
6286
+ while (index > min) {
6287
+ const code = str.charCodeAt(--index);
6288
+ if (code !== 0x20 /* */ && code !== 0x09 /* \t */)
6289
+ return index + 1;
6290
+ }
6291
+ return min;
6292
+ }
6293
+ /**
6294
+ * Serialize data into a cookie header.
6295
+ *
6296
+ * Serialize a name value pair into a cookie string suitable for
6297
+ * http headers. An optional options object specifies cookie parameters.
6298
+ *
6299
+ * serialize('foo', 'bar', { httpOnly: true })
6300
+ * => "foo=bar; httpOnly"
6301
+ */
6302
+ function serialize(name, val, options) {
6303
+ const enc = options?.encode || encodeURIComponent;
6304
+ if (!cookieNameRegExp.test(name)) {
6305
+ throw new TypeError(`argument name is invalid: ${name}`);
6306
+ }
6307
+ const value = enc(val);
6308
+ if (!cookieValueRegExp.test(value)) {
6309
+ throw new TypeError(`argument val is invalid: ${val}`);
6310
+ }
6311
+ let str = name + "=" + value;
6312
+ if (!options)
6313
+ return str;
6314
+ if (options.maxAge !== undefined) {
6315
+ if (!Number.isInteger(options.maxAge)) {
6316
+ throw new TypeError(`option maxAge is invalid: ${options.maxAge}`);
6317
+ }
6318
+ str += "; Max-Age=" + options.maxAge;
6319
+ }
6320
+ if (options.domain) {
6321
+ if (!domainValueRegExp.test(options.domain)) {
6322
+ throw new TypeError(`option domain is invalid: ${options.domain}`);
6323
+ }
6324
+ str += "; Domain=" + options.domain;
6325
+ }
6326
+ if (options.path) {
6327
+ if (!pathValueRegExp.test(options.path)) {
6328
+ throw new TypeError(`option path is invalid: ${options.path}`);
6329
+ }
6330
+ str += "; Path=" + options.path;
6331
+ }
6332
+ if (options.expires) {
6333
+ if (!isDate(options.expires) ||
6334
+ !Number.isFinite(options.expires.valueOf())) {
6335
+ throw new TypeError(`option expires is invalid: ${options.expires}`);
6336
+ }
6337
+ str += "; Expires=" + options.expires.toUTCString();
6338
+ }
6339
+ if (options.httpOnly) {
6340
+ str += "; HttpOnly";
6341
+ }
6342
+ if (options.secure) {
6343
+ str += "; Secure";
6344
+ }
6345
+ if (options.partitioned) {
6346
+ str += "; Partitioned";
6347
+ }
6348
+ if (options.priority) {
6349
+ const priority = typeof options.priority === "string"
6350
+ ? options.priority.toLowerCase()
6351
+ : undefined;
6352
+ switch (priority) {
6353
+ case "low":
6354
+ str += "; Priority=Low";
6355
+ break;
6356
+ case "medium":
6357
+ str += "; Priority=Medium";
6358
+ break;
6359
+ case "high":
6360
+ str += "; Priority=High";
6361
+ break;
6362
+ default:
6363
+ throw new TypeError(`option priority is invalid: ${options.priority}`);
6364
+ }
6365
+ }
6366
+ if (options.sameSite) {
6367
+ const sameSite = typeof options.sameSite === "string"
6368
+ ? options.sameSite.toLowerCase()
6369
+ : options.sameSite;
6370
+ switch (sameSite) {
6371
+ case true:
6372
+ case "strict":
6373
+ str += "; SameSite=Strict";
6374
+ break;
6375
+ case "lax":
6376
+ str += "; SameSite=Lax";
6377
+ break;
6378
+ case "none":
6379
+ str += "; SameSite=None";
6380
+ break;
6381
+ default:
6382
+ throw new TypeError(`option sameSite is invalid: ${options.sameSite}`);
6383
+ }
6384
+ }
6385
+ return str;
6386
+ }
6387
+ /**
6388
+ * URL-decode string value. Optimized to skip native call when no %.
6389
+ */
6390
+ function decode(str) {
6391
+ if (str.indexOf("%") === -1)
6392
+ return str;
6393
+ try {
6394
+ return decodeURIComponent(str);
6395
+ }
6396
+ catch (e) {
6397
+ return str;
6398
+ }
6399
+ }
6400
+ /**
6401
+ * Determine if value is a Date.
6402
+ */
6403
+ function isDate(val) {
6404
+ return __toString.call(val) === "[object Date]";
6405
+ }
6406
+
6407
+ return dist;
6408
+ }
6409
+
6410
+ var distExports = requireDist();
6411
+
6412
+ // 实现函数
6413
+ function createHandleCtx(req, res) {
6414
+ // 用于存储所有的 Set-Cookie 字符串
6415
+ const cookies = [];
6416
+ let handReq = req;
6417
+ let handRes = res;
6418
+ // 扩展 res.cookie 方法
6419
+ const cookieFn = (name, value, options = {}, end = true) => {
6420
+ // 序列化新的 Cookie
6421
+ const serializedCookie = distExports.serialize(name, value, options);
6422
+ cookies.push(serializedCookie); // 将新的 Cookie 添加到数组
6423
+ if (end) {
6424
+ // 如果设置了 end 参数,则立即设置到响应头
6425
+ res.setHeader('Set-Cookie', cookies);
6426
+ }
6427
+ };
6428
+ // 解析请求中的现有 Cookie
6429
+ const parsedCookies = distExports.parse(req.headers.cookie || '');
6430
+ handReq.cookies = parsedCookies;
6431
+ handRes.cookie = cookieFn;
6432
+ // 返回扩展的上下文
6433
+ return {
6434
+ req: handReq,
6435
+ res: handRes,
6436
+ };
6437
+ }
6148
6438
  const resultError = (error, code = 500) => {
6149
6439
  const r = {
6150
6440
  code: code,
@@ -6159,7 +6449,7 @@ class Server {
6159
6449
  _callback;
6160
6450
  cors;
6161
6451
  hasOn = false;
6162
- isHTTPS = false;
6452
+ httpType = 'http';
6163
6453
  options = {
6164
6454
  key: '',
6165
6455
  cert: '',
@@ -6168,7 +6458,7 @@ class Server {
6168
6458
  this.path = opts?.path || '/api/router';
6169
6459
  this.handle = opts?.handle;
6170
6460
  this.cors = opts?.cors;
6171
- this.isHTTPS = opts?.isHTTPS || false;
6461
+ this.httpType = opts?.httpType || 'http';
6172
6462
  this.options = {
6173
6463
  key: opts?.httpsKey || '',
6174
6464
  cert: opts?.httpsCert || '',
@@ -6182,13 +6472,26 @@ class Server {
6182
6472
  }
6183
6473
  createServer() {
6184
6474
  let server;
6185
- if (this.isHTTPS) {
6475
+ const httpType = this.httpType;
6476
+ if (httpType === 'https') {
6186
6477
  if (this.options.key && this.options.cert) {
6187
6478
  server = https.createServer({
6188
6479
  key: this.options.key,
6189
6480
  cert: this.options.cert,
6190
6481
  });
6191
- console.log('https server');
6482
+ return server;
6483
+ }
6484
+ else {
6485
+ console.error('https key and cert is required');
6486
+ console.log('downgrade to http');
6487
+ }
6488
+ }
6489
+ else if (httpType === 'http2') {
6490
+ if (this.options.key && this.options.cert) {
6491
+ server = http2.createSecureServer({
6492
+ key: this.options.key,
6493
+ cert: this.options.cert,
6494
+ });
6192
6495
  return server;
6193
6496
  }
6194
6497
  else {
@@ -6211,6 +6514,7 @@ class Server {
6211
6514
  const handle = this.handle;
6212
6515
  const cors = this.cors;
6213
6516
  const _callback = async (req, res) => {
6517
+ // only handle /api/router
6214
6518
  if (req.url === '/favicon.ico') {
6215
6519
  return;
6216
6520
  }
@@ -6235,19 +6539,22 @@ class Server {
6235
6539
  return;
6236
6540
  }
6237
6541
  }
6238
- res.writeHead(200); // 设置响应头,给予其他api知道headersSent,它已经被响应了
6542
+ // res.writeHead(200); // 设置响应头,给予其他任何listen 知道headersSent,它已经被响应了
6239
6543
  const url = req.url;
6240
6544
  if (!url.startsWith(path)) {
6241
6545
  res.end(resultError(`not path:[${path}]`));
6242
6546
  return;
6243
6547
  }
6244
- const messages = await handleServer(req);
6548
+ const messages = await handleServer(req, res);
6245
6549
  if (!handle) {
6246
6550
  res.end(resultError('no handle'));
6247
6551
  return;
6248
6552
  }
6249
6553
  try {
6250
- const end = await handle(messages);
6554
+ const end = await handle(messages, { req, res });
6555
+ if (res.writableEnded) {
6556
+ return;
6557
+ }
6251
6558
  if (typeof end === 'string') {
6252
6559
  res.end(end);
6253
6560
  }
@@ -6453,6 +6760,9 @@ class WsServer extends WsServerBase {
6453
6760
  }
6454
6761
  }
6455
6762
 
6763
+ /**
6764
+ * 封装了 Router 和 Server 的 App 模块,处理http的请求和响应,内置了 Cookie 和 Token 和 res 的处理
6765
+ */
6456
6766
  class App {
6457
6767
  router;
6458
6768
  server;
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.6-alpha-1",
4
+ "version": "0.0.6-alpha-3",
5
5
  "description": "",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -26,6 +26,7 @@
26
26
  "@types/lodash-es": "^4.17.12",
27
27
  "@types/node": "^22.8.6",
28
28
  "@types/ws": "^8.5.13",
29
+ "cookie": "^1.0.2",
29
30
  "lodash-es": "^4.17.21",
30
31
  "nanoid": "^5.0.8",
31
32
  "rollup": "^4.24.3",