k99 0.7.1 → 0.9.0

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/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * k99 v0.7.1
3
- * (c) 2019-2025 猛火Fierflame
2
+ * k99 v0.9.0
3
+ * (c) 2019-2026 猛火Fierflame
4
4
  * @license MIT
5
5
  */
6
6
  (function (global, factory) {
@@ -12,9 +12,10 @@
12
12
  /**
13
13
  *
14
14
  * @param {string} str
15
- * @returns {Uint8Array}
15
+ * @returns {Uint8Array<ArrayBuffer>}
16
16
  */
17
17
  function str2utf8bin(str) {
18
+ // @ts-ignore
18
19
  return new TextEncoder().encode(str);
19
20
  }
20
21
  /**
@@ -53,26 +54,15 @@
53
54
  }
54
55
  }
55
56
 
56
- /**
57
- *
58
- * @param {any} k
59
- * @param {any} v
60
- * @returns {any}
61
- */
62
- function replacer(k, v) {
63
- if (typeof v === 'bigint') {
64
- return String(v);
65
- }
66
- return v;
67
- }
68
57
 
69
58
  /**
70
59
  *
71
60
  * @param {any} result
61
+ * @param {(this: any, key: string, value: any) => any} replacer
72
62
  * @param {Promise<never>} [aborted]
73
63
  * @returns {[BodyInit, number, string] | null}
74
64
  */
75
- function toBodyData(result, aborted) {
65
+ function toBodyData(result, replacer, aborted) {
76
66
  if (result instanceof ReadableStream) {
77
67
  return [result, 0, ''];
78
68
  }
@@ -86,11 +76,16 @@
86
76
  return [result, 0, ''];
87
77
  }
88
78
  if (ArrayBuffer.isView(result) || result instanceof ArrayBuffer) {
79
+ // @ts-ignore
89
80
  return [result, result.byteLength, ''];
90
81
  }
91
82
  if (typeof result === 'string') {
92
83
  const body = str2utf8bin(result);
93
- return [body, body.byteLength, ''];
84
+ return [body, body.byteLength, 'text/plain'];
85
+ }
86
+ if (['bigint', 'boolean', 'number'].includes(typeof result)) {
87
+ const body = str2utf8bin(JSON.stringify(result, replacer));
88
+ return [body, body.byteLength, 'application/json'];
94
89
  }
95
90
  if (typeof result !== 'object') {
96
91
  return null;
@@ -117,11 +112,12 @@
117
112
  *
118
113
  * @param {any} result
119
114
  * @param {Headers} headers
115
+ * @param {(this: any, key: string, value: any) => any} replacer
120
116
  * @param {Promise<never>} [aborted]
121
117
  * @returns
122
118
  */
123
- function toBody(result, headers, aborted) {
124
- const bodyData = toBodyData(result, aborted);
119
+ function toBody(result, headers, replacer, aborted) {
120
+ const bodyData = toBodyData(result, replacer, aborted);
125
121
  if (!bodyData) { return null; }
126
122
  const [body, size, type] = bodyData;
127
123
  if (type && !headers.get('Content-Type')) {
@@ -215,7 +211,7 @@
215
211
  }
216
212
  }
217
213
 
218
- /** @import { Context, Cookie, CookieOption, FindHandler, Method, Options, Params, Service } from './types' */
214
+ /** @import { Context, Cookie, CookieOption, FindHandler, HandlerResult, Method, Options, Params, Service } from './types' */
219
215
 
220
216
 
221
217
  const noBodyMethods = new Set(['GET', 'OPTIONS']);
@@ -268,6 +264,18 @@
268
264
  }
269
265
  return /** @type {Method} */(methodStr.toUpperCase());
270
266
  }
267
+ /**
268
+ *
269
+ * @param {any} k
270
+ * @param {any} v
271
+ * @returns {any}
272
+ */
273
+ function defaultReplacer(k, v) {
274
+ if (typeof v === 'bigint') {
275
+ return String(v);
276
+ }
277
+ return v;
278
+ }
271
279
  /**
272
280
  *
273
281
  * @param {Request} request
@@ -275,10 +283,15 @@
275
283
  * @param {Options} [options]
276
284
  * @returns {Promise<Response | null>}
277
285
  */
278
- function main(
279
- request, getHandler,
280
- { runner, error: echoError, catch: catchError, method: toMethod, environment } = {},
281
- ) {
286
+ function main(request, getHandler, {
287
+ runner,
288
+ error: echoError,
289
+ catch: catchError,
290
+ method: toMethod,
291
+ environment,
292
+ replacer: JSONReplacer,
293
+ } = {}) {
294
+ const replacer = typeof JSONReplacer === 'function' ? JSONReplacer : defaultReplacer;
282
295
  /**
283
296
  *
284
297
  * @param {Request} request
@@ -302,12 +315,12 @@
302
315
  /** @type {any} */
303
316
  let error = null;
304
317
 
305
- let resolve = () => {};
318
+ let resolve = () => { };
306
319
  /** @type {(error: unknown) => void} */
307
- let reject = () => {};
320
+ let reject = () => { };
308
321
  /** @type {Promise<void>} */
309
322
  const donePromise = new Promise((a, b) => { resolve = a; reject = b; });
310
- donePromise.catch(() => {});
323
+ donePromise.catch(() => { });
311
324
 
312
325
  /** @type {Params} */
313
326
  let params = {};
@@ -325,7 +338,7 @@
325
338
  if (!data || noBodyMethods.has(method.toUpperCase())) {
326
339
  return exec(new Request(fetchUrl, { method, headers, signal }), context);
327
340
  }
328
- const body = toBody(data, headers);
341
+ const body = toBody(data, headers, replacer);
329
342
  return exec(new Request(fetchUrl, { method, headers, signal, body }), context);
330
343
  },
331
344
  done(onfulfilled, onrejected) {
@@ -370,7 +383,7 @@
370
383
  set responseType(type) { setHeader(responseHeaders, 'content-type', type); },
371
384
  getCookie(name) { return getCookie(sentCookies, name); },
372
385
  setCookie(name, value, { expire, domain, path, secure, httpOnly } = {}) {
373
- sentCookies.push({name, value, expire, domain, path, secure, httpOnly});
386
+ sentCookies.push({ name, value, expire, domain, path, secure, httpOnly });
374
387
  setCookiesHeader(responseHeaders, sentCookies);
375
388
  },
376
389
  /**
@@ -388,16 +401,22 @@
388
401
  return Promise.race([
389
402
  aborted,
390
403
  Promise.resolve().then(() => getHandler(context, v => { params = v; })),
391
- ]).then(handler => handler ? Promise.race([aborted, handler(context)]).then(result => {
392
- if (result instanceof Response) {
393
- return result;
404
+ ]).then(async handlers => {
405
+ const allHandlers = [handlers].flat().filter(h => typeof h === 'function');
406
+ if (!allHandlers.length) { return null; }
407
+ /** @type {HandlerResult?} */
408
+ let result;
409
+ for (const handle of allHandlers) {
410
+ result = await Promise.race([aborted, handle(context)]);
411
+ if (result !== undefined) { break; }
394
412
  }
413
+ if (result instanceof Response) { return result; }
395
414
  const headers = new Headers(context.responseHeaders);
396
415
  const { status } = context;
397
- if (!result) { return new Response(null, { status, headers }); }
398
- const body = toBody(result, headers, aborted);
416
+ if (!result == null) { return new Response(null, { status, headers }); }
417
+ const body = toBody(result, headers, replacer, aborted);
399
418
  return new Response(body, { status, headers });
400
- }) : null).then(response => {
419
+ }).then(response => {
401
420
  destroyed = true;
402
421
  resolve();
403
422
  return response;
@@ -413,40 +432,151 @@
413
432
  return exec(request);
414
433
  }
415
434
 
416
- /** @import { FindHandler, Options } from './main/types' */
435
+ /** @import { Method, Params } from './main/types' */
417
436
 
418
437
  /**
419
- *
420
- * @param {FindHandler} getHandler
421
- * @param {Options} options
422
- * @returns {(request: Request) => Promise<Response | null>}
438
+ * @template {Function} T
439
+ * @typedef {[T | T[] | Router<T>, Record<string | symbol, any>, string[]]} FindItem
423
440
  */
424
- function make(getHandler, options) {
425
- return r => main(r, getHandler, options);
441
+ /**
442
+ * @template {Function} T
443
+ * @callback Finder
444
+ * @this {Router<T>}
445
+ * @param {Method} method
446
+ * @param {string[]} path
447
+ * @returns {AsyncIterable<FindItem<T>> | Iterable<FindItem<T>>}
448
+ */
449
+
450
+ /**
451
+ * @abstract
452
+ * @template {Function} T
453
+ */
454
+ class Router {
455
+ disabled = false;
456
+ /**
457
+ *
458
+ * @template {Function} T
459
+ * @param {Router<T> | T[] | T} route
460
+ * @param {Method} method
461
+ * @param {string[]} path
462
+ * @param {Params} params
463
+ * @param {AbortSignal?} [signal]
464
+ * @param {((v: Params) => void)?} [setParams]
465
+ * @returns {Promise<T[] | null>}
466
+ */
467
+ static async #find(route, method, path, params, signal, setParams) {
468
+ if (!(route instanceof Router)) {
469
+ if (typeof setParams === 'function') { setParams(params); }
470
+ // @ts-ignore
471
+ return [route].flat();
472
+ }
473
+ if (route.disabled) { return null; }
474
+ if (signal?.aborted) { return null; }
475
+ for await (const [r, result, p] of route.find(method, path)) {
476
+ if (signal?.aborted) { return null; }
477
+ const res = await Router.#find(r, method, p, { ...params, ...result }, signal, setParams);
478
+ if (res) { return [...route.#guards, ...res]; }
479
+ }
480
+ return null;
481
+ }
482
+ /**
483
+ *
484
+ * @template {Function} T
485
+ * @param {Router<T>[]} routers
486
+ * @param {Method} method
487
+ * @param {string[]} path
488
+ * @param {AbortSignal?} [signal]
489
+ * @param {((v: Params) => void)?} [setParams]
490
+ * @returns {Promise<T[] | null>}
491
+ */
492
+ static async find(routers, method, path, signal, setParams) {
493
+ const m = `${method}`.toLowerCase();
494
+ for (const route of routers.flat()) {
495
+ const res = await Router.#find(route, m, path, {}, signal, setParams);
496
+ if (res) { return res; }
497
+ }
498
+ return null;
499
+ }
500
+ /**
501
+ * @abstract
502
+ * @param {Method} method
503
+ * @param {string[]} path
504
+ * @returns {AsyncIterable<FindItem<T>> | Iterable<FindItem<T>>}
505
+ */
506
+ find(method, path) { return []; }
507
+
508
+
509
+ /** @type {T[]} */
510
+ #guards = [];
511
+ /**
512
+ *
513
+ * @param {...T | T[]} guards
514
+ */
515
+ guard(...guards) {
516
+ const list = this.#guards;
517
+ for (const guard of guards.flat()) {
518
+ if (typeof guard !== 'function') { continue; }
519
+ // @ts-ignore
520
+ list.push(guard);
521
+ }
522
+ }
523
+
524
+ /**
525
+ *
526
+ * @template {Function} T
527
+ * @param {Finder<T>} find
528
+ * @returns {Router<T>}
529
+ */
530
+ static create(find) {
531
+ return Object.defineProperties(new Router(), {
532
+ 'find': { configurable: true, value: find, writable: true },
533
+ });
534
+ }
426
535
  }
427
536
 
428
- /** @import { Context, Handler } from './main/types' */
537
+ /** @import { FindHandler, Handler, Options } from './main/types' */
538
+
539
+ /**
540
+ *
541
+ * @param {string} t
542
+ * @returns
543
+ */
544
+ function uriDecode(t) {
545
+ try {
546
+ return decodeURIComponent(t);
547
+ } catch {
548
+ return t;
549
+ }
550
+ }
429
551
  /**
430
552
  *
431
- * @param {Context} context
432
- * @param {Handler[]} handlers
433
- * @returns {Promise<string | boolean | object | undefined>}
553
+ * @param {Router<Handler> | Router<Handler>[] | FindHandler} routers
554
+ * @param {Options} options
555
+ * @returns {(request: Request) => Promise<Response | null>}
434
556
  */
435
- async function runHandles(context, handlers) {
436
- for (const handle of handlers) {
437
- const result = await handle(context);
438
- if (result === undefined) { continue; }
439
- return result;
557
+ function make(routers, options) {
558
+ if (typeof routers === 'function') {
559
+ return r => main(r, routers, options);
440
560
  }
561
+ const list = [routers].flat();
562
+ /** @type {FindHandler} */
563
+ const getHandler = (ctx, setParams) => {
564
+ const path = ctx.url.pathname.split('/').filter(Boolean).map(uriDecode);
565
+ return Router.find(list, ctx.method, path, ctx.signal, setParams);
566
+ };
567
+ return r => main(r, getHandler, options);
441
568
  }
442
569
 
570
+ /** @import { FindHandler, Options } from './main/types' */
571
+
443
572
  /**
444
573
  *
445
- * @param {...(Handler | Handler[])} handlers
446
- * @returns {Handler}
574
+ * @param {FindHandler} getHandler
575
+ * @param {Options} options
576
+ * @returns {(request: Request) => Promise<Response | null>}
447
577
  */
448
- function merge(...handlers) {
449
- return ctx => runHandles(ctx, handlers.flat());
578
+ function bind$1(getHandler, options) {
579
+ return r => main(r, getHandler, options);
450
580
  }
451
581
 
452
582
  /** @import { Context, Service } from './main/types' */
@@ -628,162 +758,6 @@
628
758
  return service;
629
759
  }
630
760
 
631
- /** @import { Handler } from './main/types' */
632
- /** @import { Onionskin } from './onionskin.mjs' */
633
- /**
634
- * @callback Packer
635
- * @param {Handler} handler
636
- * @returns {Handler}
637
- */
638
- /** @type {Packer} */
639
- const noop$1 = h => h;
640
- /**
641
- *
642
- * @param {Onionskin} onionskin
643
- * @param {Packer} [packer]
644
- * @returns {Packer}
645
- */
646
- function packer(onionskin, packer = noop$1) {
647
- return h => {
648
- const handler = packer(h);
649
- return async (ctx) => onionskin(ctx, async () => handler(ctx));
650
- };
651
- }
652
-
653
- /** @import { Context, FindHandler, Handler, Method, Params } from './main/types' */
654
- /** @import { Onionskin } from './onionskin.mjs' */
655
-
656
- /**
657
- * @callback Guard
658
- * @param {Context} ctx
659
- * @returns {PromiseLike<boolean | Handler | void> | boolean | Handler | void}
660
- */
661
- /**
662
- * @typedef {[Handler | Router, Record<string | symbol, any>, string[]]} FindItem
663
- */
664
- /**
665
- * @callback Finder
666
- * @this {Router}
667
- * @param {Method} method
668
- * @param {string[]} path
669
- * @param {Context} ctx
670
- * @returns {AsyncIterable<FindItem> | Iterable<FindItem>}
671
- */
672
-
673
- /**
674
- *
675
- * @param {Set<Guard>} guards
676
- * @param {Context} ctx
677
- * @param {(v: any) => void} setParams
678
- * @param {object} params
679
- * @returns {Promise<boolean | Handler>}
680
- */
681
- async function execGuard(guards, ctx, setParams, params) {
682
- if (!guards.size) { return true; }
683
- setParams(params);
684
- for (const guard of guards) {
685
- if (ctx.destroyed) { return false; }
686
- const ret = await guard(Object.create(ctx, {
687
- params: { value: { ...params } },
688
- }));
689
- if (ret === false) { return false; }
690
- // @ts-ignore
691
- if (typeof ret === 'function') { return ret; }
692
- }
693
- return true;
694
- }
695
-
696
- /**
697
- *
698
- * @param {Router | Handler} route
699
- * @param {string[]} path
700
- * @param {Context} ctx
701
- * @param {(v: Params) => void} setParams
702
- * @param {Params} params
703
- * @returns {Promise<Handler | null>}
704
- */
705
- async function find(route, path, ctx, setParams, params) {
706
- if (!(route instanceof Router)) {
707
- setParams(params);
708
- return route;
709
- }
710
- if (route.disabled) { return null; }
711
- const guardResult = await execGuard(route.guards, ctx, setParams, params);
712
- if (!guardResult) { return null; }
713
- if (typeof guardResult === 'function') { return guardResult; }
714
- if (ctx.destroyed) { return null; }
715
- for await (const [r, result, p] of route.find(ctx.method, path, ctx)) {
716
- if (ctx.destroyed) { return null; }
717
- const res = await find(r, p, ctx, setParams, { ...params, ...result });
718
- if (res) { return route.__onionskin(res); }
719
- }
720
- return null;
721
- }
722
-
723
- /**
724
- *
725
- * @param {string} t
726
- * @returns
727
- */
728
- function uriDecode(t) {
729
- try {
730
- return decodeURIComponent(t);
731
- } catch {
732
- return t;
733
- }
734
- }
735
- /**
736
- * @abstract
737
- */
738
- class Router {
739
- disabled = false;
740
- /**
741
- * @abstract
742
- * @param {Method} method
743
- * @param {string[]} path
744
- * @param {Context} ctx
745
- * @returns {AsyncIterable<FindItem> | Iterable<FindItem>}
746
- */
747
- find(method, path, ctx) { return []; }
748
- /**
749
- *
750
- * @param {Router[]} routers
751
- * @returns {FindHandler}
752
- */
753
- static make(routers) {
754
- return async (ctx, setParams) => {
755
- const list = routers.flat();
756
- const path = ctx.url.pathname.split('/').filter(Boolean).map(uriDecode);
757
- for (const route of list) {
758
- const res = await find(route, path, ctx, setParams, {});
759
- if (res) { return res; }
760
- }
761
- return null;
762
- };
763
- }
764
-
765
- /**
766
- *
767
- * @param {Finder} find
768
- * @returns {Router}
769
- */
770
- static create(find) {
771
- return Object.defineProperties(new Router(), {
772
- 'find': { configurable: true, value: find, writable: true },
773
- });
774
- }
775
- /** @readonly @type {Set<Guard>} */
776
- guards = new Set();
777
- /**
778
- *
779
- * @param {Handler} h
780
- * @returns {Handler}
781
- */
782
- __onionskin = (h) => h;
783
- /** @param {Onionskin} os */
784
- onionskin(os) { this.__onionskin = packer(os, this.__onionskin); }
785
- }
786
-
787
761
  /** @import { Match } from './index.mjs' */
788
762
  /** @import { Params } from '../main/types.js' */
789
763
  /**
@@ -966,20 +940,21 @@
966
940
  return path => exec(list, path, end);
967
941
  }
968
942
 
969
- /** @import { Handler, Method } from '../main/types' */
943
+ /** @import { Method } from '../main/types' */
970
944
  /** @import { Binder, Match, Route, RouterRoute } from './index.mjs' */
971
945
 
972
946
  /**
973
947
  *
974
- * @param {(Route | RouterRoute)[]} routes
948
+ * @template {Function} T
949
+ * @param {(Route<T> | RouterRoute<T>)[]} routes
975
950
  * @param {Set<Method>} methods
976
951
  * @param {Match | undefined} match
977
- * @param {Handler[]} handlers
952
+ * @param {T[]} handlers
978
953
  * @returns {() => void}
979
954
  */
980
955
  function bind(routes, methods, match, handlers) {
981
- /** @type {Route} */
982
- const route = { match, methods, handler: ctx => runHandles(ctx, handlers) };
956
+ /** @type {Route<T>} */
957
+ const route = { match, methods, handlers: handlers };
983
958
  routes.push(route);
984
959
  let removed = false;
985
960
  return () => {
@@ -990,45 +965,45 @@
990
965
  routes.splice(index, 1);
991
966
  };
992
967
  }
993
- /** @type {(v: any) => v is Handler} */
968
+ /** @type {(v: any) => v is Function} */
994
969
  const findHandler = v => typeof v === 'function';
995
970
  /**
996
971
  *
997
- * @param {(Route | RouterRoute)[]} routes
972
+ * @template {Function} T
973
+ * @param {(Route<T> | RouterRoute<T>)[]} routes
998
974
  * @param {Iterable<Method>} methods
999
975
  * @param {any[]} p
1000
- * @returns {Binder | (() => void)}
976
+ * @returns {Binder<T> | (() => void)}
1001
977
  */
1002
978
  function verb(routes, methods, p) {
1003
979
  const methodSet = new Set(methods);
1004
980
  if (!p.length) {
1005
981
  const match = undefined;
1006
- /** @type {Binder} */
982
+ /** @type {Binder<T>} */
1007
983
  return (...handlers) => bind(routes, methodSet, match, handlers);
1008
984
  }
1009
985
  const [path] = p;
1010
986
  if (path && typeof path === 'object') {
1011
987
  const match = toMatch([path, p.slice(1)], true);
1012
- /** @type {Binder} */
988
+ /** @type {Binder<T>} */
1013
989
  return (...handlers) => bind(routes, methodSet, match, handlers);
1014
990
  }
1015
991
  const match = toMatch(typeof path === 'string' ? path : '', true);
1016
992
  const handlers = p.filter(findHandler);
1017
993
  if (!handlers.length) {
1018
- /** @type {Binder} */
994
+ /** @type {Binder<T>} */
1019
995
  return (...handlers) => bind(routes, methodSet, match, handlers);
1020
996
  }
1021
997
  return bind(routes, methodSet, match, handlers);
1022
998
  }
1023
999
 
1024
1000
  /** @import { Method } from '../main/types' */
1025
- const methods = new Set(['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS']);
1026
1001
  /**
1027
1002
  *
1028
1003
  * @param {any} v
1029
1004
  * @returns {v is Method}
1030
1005
  */
1031
- function isMethod(v) { return methods.has(v); }
1006
+ function isMethod(v) { return Boolean(v); }
1032
1007
  /**
1033
1008
  *
1034
1009
  * @param {Method | Iterable<Method> | ArrayLike<Method>} [methods]
@@ -1046,7 +1021,7 @@
1046
1021
  .filter(isMethod);
1047
1022
  }
1048
1023
 
1049
- /** @import { Context, Handler, Method, Params } from '../main/types' */
1024
+ /** @import { Handler, Method, Params } from '../main/types' */
1050
1025
  /** @import { Finder, FindItem } from '../Router.mjs' */
1051
1026
 
1052
1027
  /**
@@ -1055,79 +1030,125 @@
1055
1030
  * @returns {[Params, string[]] | undefined}
1056
1031
  */
1057
1032
 
1058
- /** @typedef {(handler: Handler, ...handlers: Handler[]) => () => void} Binder */
1033
+ /**
1034
+ * @template {Function} T
1035
+ * @typedef {(handler: T, ...handlers: T[]) => () => void} Binder
1036
+ */
1037
+
1038
+
1039
+ /**
1040
+ * @template {Function} T
1041
+ * @callback Verb1
1042
+ * @param {T} handler 要注册的处理函数
1043
+ * @param {...T} handlers 要注册的处理函数
1044
+ * @returns {() => void}
1045
+ */
1046
+ /**
1047
+ * @template {Function} T
1048
+ * @callback Verb2
1049
+ * @param {string} path 要注册的路径
1050
+ * @param {T} handler 要注册的处理函数
1051
+ * @param {...T} handlers 要注册的处理函数
1052
+ * @returns {() => void}
1053
+ */
1054
+ /**
1055
+ * @template {Function} T
1056
+ * @callback Verb3
1057
+ * @param {string} path 要注册的路径
1058
+ * @returns {Binder<T>}
1059
+ */
1060
+ /**
1061
+ * @template {Function} T
1062
+ * @callback Verb4
1063
+ * @param {TemplateStringsArray} template 要注册的路径模板
1064
+ * @param {...any} substitutions 要注册的路径模板代替内容
1065
+ * @returns {Binder<T>}
1066
+ */
1067
+ /**
1068
+ * @template {Function} T
1069
+ * @typedef {Verb1<T> & Verb2<T> & Verb3<T> & Verb4<T>} Verb
1070
+ */
1059
1071
 
1060
1072
  /**
1073
+ * @template {Function} T
1061
1074
  * @typedef {object} Route
1062
1075
  * @property {Match} [match] 路径匹配
1063
1076
  * @property {null} [router]
1064
- * @property {string} [plugin] 所属插件
1065
- * @property {Handler} handler 处理函数
1077
+ * @property {T[]} handlers 处理函数
1066
1078
  * @property {Set<Method>} methods 方法列表
1067
1079
  */
1068
1080
 
1069
1081
  /**
1082
+ * @template {Function} T
1070
1083
  * @typedef {object} RouterRoute
1071
1084
  * @property {Match} [match] 路径匹配
1072
- * @property {Router} router
1085
+ * @property {Router<T>} router
1073
1086
  */
1074
1087
 
1075
1088
 
1076
1089
  /**
1077
- * @template {Router | Finder} [T=ApiRouter]
1090
+ * @template {Function} T
1091
+ * @template {Router<T> | Finder<T>} [P=MapRouter<T>]
1078
1092
  * @callback RouteBinder
1079
- * @param {T} [router] 要注册的子路由或子路由的 Finder
1080
- * @returns {T extends Finder ? Router : T}
1093
+ * @param {P} [router] 要注册的子路由或子路由的 Finder<T>
1094
+ * @returns {P extends Finder<T> ? Router<T> : P}
1081
1095
  */
1082
1096
  /**
1083
1097
  *
1084
- * @param {(Route | RouterRoute)[]} routes
1098
+ * @template {Function} T
1099
+ * @param {(Route<T> | RouterRoute<T>)[]} routes
1085
1100
  * @param {string | [string[], any[]]} path
1086
- * @param {Router | Finder} [r]
1087
- * @returns {Router}
1101
+ * @param {Router<T> | Finder<T>} [r]
1102
+ * @returns {Router<T>}
1088
1103
  */
1089
1104
  function bindRouter(routes, path, r) {
1105
+ /** @type {Router<T>} */
1090
1106
  const router = r instanceof Router ? r
1091
1107
  : typeof r === 'function' ? Router.create(r)
1092
- : new ApiRouter();
1108
+ : new MapRouter();
1093
1109
  routes.push({ match: toMatch(path, false), router });
1094
1110
  return router;
1095
1111
  }
1096
- class ApiRouter extends Router {
1097
- /** @readonly @type {(Route | RouterRoute)[]} 路由列表 */
1112
+ /**
1113
+ *
1114
+ * @template {Function} T
1115
+ * @extends {Router<T>}
1116
+ */
1117
+ class MapRouter extends Router {
1118
+ /** @readonly @type {(Route<T> | RouterRoute<T>)[]} 路由列表 */
1098
1119
  #routes = [];
1099
1120
  /**
1100
1121
  * 添加子路由
1101
- * @template {Router | Finder} [T=ApiRouter]
1122
+ * @template {Router<T> | Finder<T>} [P=MapRouter<T>]
1102
1123
  * @overload
1103
- * @param {T} [router] 要注册的子路由或子路由的 Finder
1104
- * @returns {T extends Finder ? Router : T}
1124
+ * @param {P} [router] 要注册的子路由或子路由的 Finder<T>
1125
+ * @returns {P extends Finder<T> ? Router<T> : P}
1105
1126
  */
1106
1127
  /**
1107
1128
  * 添加子路由
1108
- * @template {Router | Finder} [T=ApiRouter]
1129
+ * @template {Router<T> | Finder<T>} [P=MapRouter<T>]
1109
1130
  * @overload
1110
1131
  * @param {string} path 要注册的路径
1111
- * @param {T} [router] 要注册的子路由或子路由的 Finder
1112
- * @returns {T extends Finder ? Router : T}
1132
+ * @param {P} [router] 要注册的子路由或子路由的 Finder<T>
1133
+ * @returns {P extends Finder<T> ? Router<T> : P}
1113
1134
  */
1114
1135
  /**
1115
1136
  * 添加子路由
1116
1137
  * @overload
1117
1138
  * @param {TemplateStringsArray} template 要注册的路径模板
1118
1139
  * @param {...any} substitutions 要注册的路径模板代替内容
1119
- * @returns {RouteBinder}
1140
+ * @returns {RouteBinder<T>}
1120
1141
  */
1121
1142
  /**
1122
1143
  * 添加子路由
1123
1144
  * @param {...any} p 要注册的路径
1124
- * @returns {Router | RouteBinder}
1145
+ * @returns {Router<T> | RouteBinder<T>}
1125
1146
  */
1126
1147
  route(...p) {
1127
1148
  const [a] = p;
1128
1149
  if (a && typeof a === 'object' && !(a instanceof Router)) {
1129
1150
  /**
1130
- * @param { Finder | Router} [r];
1151
+ * @param { Finder<T> | Router<T>} [r];
1131
1152
  * @returns {any}
1132
1153
  */
1133
1154
  return r => bindRouter(this.#routes, [a, p.slice(1)], r);
@@ -1140,30 +1161,29 @@
1140
1161
  *
1141
1162
  * @param {Method} method
1142
1163
  * @param {string[]} path
1143
- * @param {Context} ctx
1144
- * @returns {Iterable<FindItem>}
1164
+ * @returns {Iterable<FindItem<T>>}
1145
1165
  */
1146
- *find(method, path, ctx) {
1166
+ *find(method, path) {
1147
1167
  for (const route of Array.from(this.#routes)) {
1148
1168
  if (!route.router && !route.methods.has(method)) { continue; }
1149
1169
  const {match} = route;
1150
1170
  if (!match) {
1151
1171
  if (route.router || !path.length) {
1152
- yield [route.router || route.handler, {}, path];
1172
+ yield [route.router || route.handlers, {}, path];
1153
1173
  }
1154
1174
  continue;
1155
1175
  }
1156
1176
  if (!path.length) { continue; }
1157
1177
  const result = match(path);
1158
1178
  if (!result) { continue; }
1159
- yield [route.router || route.handler, ...result];
1179
+ yield [route.router || route.handlers, ...result];
1160
1180
  }
1161
1181
  }
1162
1182
  /**
1163
1183
  * 注册处理函数
1164
1184
  * @overload
1165
1185
  * @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
1166
- * @param {Handler} handler 要注册的处理函数
1186
+ * @param {T} handler 要注册的处理函数
1167
1187
  * @returns {() => void}
1168
1188
  */
1169
1189
  /**
@@ -1171,7 +1191,7 @@
1171
1191
  * @overload
1172
1192
  * @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
1173
1193
  * @param {string} path 要注册的路径
1174
- * @param {Handler} handler 要注册的处理函数
1194
+ * @param {T} handler 要注册的处理函数
1175
1195
  * @returns {() => void}
1176
1196
  */
1177
1197
  /**
@@ -1179,48 +1199,58 @@
1179
1199
  * @overload
1180
1200
  * @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
1181
1201
  * @param {string} path 要注册的路径
1182
- * @returns {Binder}
1202
+ * @returns {Binder<T>}
1183
1203
  */
1184
1204
  /**
1185
1205
  * @param {Method | Iterable<Method> | ArrayLike<Method>} methods
1186
- * @param {string| Handler} [path]
1187
- * @param {Handler} [handler]
1188
- * @returns {Binder | (() => void)}
1206
+ * @param {string| T} [path]
1207
+ * @param {...T} handler
1208
+ * @returns {Binder<T> | (() => void)}
1189
1209
  */
1190
- verb(methods, path, handler) {
1210
+ verb(methods, path, ...handler) {
1191
1211
  const allMethods = getMethods(methods);
1192
1212
  if (!allMethods.length) { return () => {}; }
1193
- return verb(this.#routes, allMethods, [path, handler]);
1213
+ return verb(this.#routes, allMethods, [path, ...handler]);
1214
+ }
1215
+
1216
+ /**
1217
+ * @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
1218
+ * @returns {Verb<T>}
1219
+ */
1220
+ method(method) {
1221
+ const methods = getMethods(method);
1222
+ // @ts-ignore
1223
+ return (...p) => verb(this.#routes, methods, p);
1194
1224
  }
1195
1225
  /**
1196
1226
  * 注册 HTTP GET/POST/PUT/DELETE 处理函数
1197
1227
  * @overload
1198
- * @param {Handler} handler 要注册的处理函数
1228
+ * @param {...T} handlers 要注册的处理函数
1199
1229
  * @returns {() => void}
1200
1230
  */
1201
1231
  /**
1202
1232
  * 注册处理函数
1203
1233
  * @overload
1204
1234
  * @param {string} path 要注册的路径
1205
- * @param {Handler} handler 要注册的处理函数
1235
+ * @param {...T} handlers 要注册的处理函数
1206
1236
  * @returns {() => void}
1207
1237
  */
1208
1238
  /**
1209
1239
  * 注册 HTTP GET/POST/PUT/DELETE 处理函数
1210
1240
  * @overload
1211
1241
  * @param {string} path 要注册的路径
1212
- * @returns {Binder}
1242
+ * @returns {Binder<T>}
1213
1243
  */
1214
1244
  /**
1215
1245
  * 注册 HTTP GET/POST/PUT/DELETE 处理函数
1216
1246
  * @overload
1217
1247
  * @param {TemplateStringsArray} template 要注册的路径模板
1218
1248
  * @param {...any} substitutions 要注册的路径模板代替内容
1219
- * @returns {Binder}
1249
+ * @returns {Binder<T>}
1220
1250
  */
1221
1251
  /**
1222
1252
  * @param {...any} p 要注册的路径
1223
- * @returns {Binder | (() => void)}
1253
+ * @returns {Binder<T> | (() => void)}
1224
1254
  */
1225
1255
  match(...p) {
1226
1256
  return verb(this.#routes, ['GET', 'POST', 'PUT', 'DELETE'], p);
@@ -1228,187 +1258,187 @@
1228
1258
  /**
1229
1259
  * 注册 HTTP GET 处理函数
1230
1260
  * @overload
1231
- * @param {Handler} handler 要注册的处理函数
1261
+ * @param {...Handler} handlers 要注册的处理函数
1232
1262
  * @returns {() => void}
1233
1263
  */
1234
1264
  /**
1235
1265
  * 注册 HTTP GET 处理函数
1236
1266
  * @overload
1237
1267
  * @param {string} path 要注册的路径
1238
- * @param {Handler} handler 要注册的处理函数
1268
+ * @param {...Handler} handlers 要注册的处理函数
1239
1269
  * @returns {() => void}
1240
1270
  */
1241
1271
  /**
1242
1272
  * 注册 HTTP GET 处理函数
1243
1273
  * @overload
1244
1274
  * @param {string} path 要注册的路径
1245
- * @returns {Binder}
1275
+ * @returns {Binder<T>}
1246
1276
  */
1247
1277
  /**
1248
1278
  * 注册 HTTP GET 处理函数
1249
1279
  * @overload
1250
1280
  * @param {TemplateStringsArray} template 要注册的路径模板
1251
1281
  * @param {...any} substitutions 要注册的路径模板代替内容
1252
- * @returns {Binder}
1282
+ * @returns {Binder<T>}
1253
1283
  */
1254
1284
  /**
1255
1285
  * @param {...any} p 要注册的路径
1256
- * @returns {Binder | (() => void)}
1286
+ * @returns {Binder<T> | (() => void)}
1257
1287
  */
1258
1288
  get(...p) { return verb(this.#routes, ['GET'], p); }
1259
1289
  /**
1260
1290
  * 注册 HTTP POST 处理函数
1261
1291
  * @overload
1262
- * @param {Handler} handler 要注册的处理函数
1292
+ * @param {...Handler} handlers 要注册的处理函数
1263
1293
  * @returns {() => void}
1264
1294
  */
1265
1295
  /**
1266
1296
  * 注册 HTTP POST 处理函数
1267
1297
  * @overload
1268
1298
  * @param {string} path 要注册的路径
1269
- * @param {Handler} handler 要注册的处理函数
1299
+ * @param {...Handler} handlers 要注册的处理函数
1270
1300
  * @returns {() => void}
1271
1301
  */
1272
1302
  /**
1273
1303
  * 注册 HTTP POST 处理函数
1274
1304
  * @overload
1275
1305
  * @param {string} path 要注册的路径
1276
- * @returns {Binder}
1306
+ * @returns {Binder<T>}
1277
1307
  */
1278
1308
  /**
1279
1309
  * 注册 HTTP POST 处理函数
1280
1310
  * @overload
1281
1311
  * @param {TemplateStringsArray} template 要注册的路径模板
1282
1312
  * @param {...any} substitutions 要注册的路径模板代替内容
1283
- * @returns {Binder}
1313
+ * @returns {Binder<T>}
1284
1314
  */
1285
1315
  /**
1286
1316
  * @param {...any} p 要注册的路径
1287
- * @returns {Binder | (() => void)}
1317
+ * @returns {Binder<T> | (() => void)}
1288
1318
  */
1289
1319
  post(...p) { return verb(this.#routes, ['POST'], p); }
1290
1320
  /**
1291
1321
  * 注册 HTTP PUT 处理函数
1292
1322
  * @overload
1293
- * @param {Handler} handler 要注册的处理函数
1323
+ * @param {...Handler} handlers 要注册的处理函数
1294
1324
  * @returns {() => void}
1295
1325
  */
1296
1326
  /**
1297
1327
  * 注册 HTTP PUT 处理函数
1298
1328
  * @overload
1299
1329
  * @param {string} path 要注册的路径
1300
- * @param {Handler} handler 要注册的处理函数
1330
+ * @param {...Handler} handlers 要注册的处理函数
1301
1331
  * @returns {() => void}
1302
1332
  */
1303
1333
  /**
1304
1334
  * 注册 HTTP PUT 处理函数
1305
1335
  * @overload
1306
1336
  * @param {string} path 要注册的路径
1307
- * @returns {Binder}
1337
+ * @returns {Binder<T>}
1308
1338
  */
1309
1339
  /**
1310
1340
  * 注册 HTTP PUT 处理函数
1311
1341
  * @overload
1312
1342
  * @param {TemplateStringsArray} template 要注册的路径模板
1313
1343
  * @param {...any} substitutions 要注册的路径模板代替内容
1314
- * @returns {Binder}
1344
+ * @returns {Binder<T>}
1315
1345
  */
1316
1346
  /**
1317
1347
  * @param {...any} p 要注册的路径
1318
- * @returns {Binder | (() => void)}
1348
+ * @returns {Binder<T> | (() => void)}
1319
1349
  */
1320
1350
  put(...p) { return verb(this.#routes, ['PUT'], p); }
1321
1351
  /**
1322
1352
  * 注册 HTTP DELETE 处理函数
1323
1353
  * @overload
1324
- * @param {Handler} handler 要注册的处理函数
1354
+ * @param {...Handler} handlers 要注册的处理函数
1325
1355
  * @returns {() => void}
1326
1356
  */
1327
1357
  /**
1328
1358
  * 注册 HTTP DELETE 处理函数
1329
1359
  * @overload
1330
1360
  * @param {string} path 要注册的路径
1331
- * @param {Handler} handler 要注册的处理函数
1361
+ * @param {...Handler} handlers 要注册的处理函数
1332
1362
  * @returns {() => void}
1333
1363
  */
1334
1364
  /**
1335
1365
  * 注册 HTTP DELETE 处理函数
1336
1366
  * @overload
1337
1367
  * @param {string} path 要注册的路径
1338
- * @returns {Binder}
1368
+ * @returns {Binder<T>}
1339
1369
  */
1340
1370
  /**
1341
1371
  * 注册 HTTP DELETE 处理函数
1342
1372
  * @overload
1343
1373
  * @param {TemplateStringsArray} template 要注册的路径模板
1344
1374
  * @param {...any} substitutions 要注册的路径模板代替内容
1345
- * @returns {Binder}
1375
+ * @returns {Binder<T>}
1346
1376
  */
1347
1377
  /**
1348
1378
  * @param {...any} p 要注册的路径
1349
- * @returns {Binder | (() => void)}
1379
+ * @returns {Binder<T> | (() => void)}
1350
1380
  */
1351
1381
  delete(...p) { return verb(this.#routes, ['DELETE'], p); }
1352
1382
  /**
1353
1383
  * 注册 HTTP HEAD 处理函数
1354
1384
  * @overload
1355
- * @param {Handler} handler 要注册的处理函数
1385
+ * @param {...Handler} handlers 要注册的处理函数
1356
1386
  * @returns {() => void}
1357
1387
  */
1358
1388
  /**
1359
1389
  * 注册 HTTP HEAD 处理函数
1360
1390
  * @overload
1361
1391
  * @param {string} path 要注册的路径
1362
- * @param {Handler} handler 要注册的处理函数
1392
+ * @param {...Handler} handlers 要注册的处理函数
1363
1393
  * @returns {() => void}
1364
1394
  */
1365
1395
  /**
1366
1396
  * 注册 HTTP HEAD 处理函数
1367
1397
  * @overload
1368
1398
  * @param {string} path 要注册的路径
1369
- * @returns {Binder}
1399
+ * @returns {Binder<T>}
1370
1400
  */
1371
1401
  /**
1372
1402
  * 注册 HTTP HEAD 处理函数
1373
1403
  * @overload
1374
1404
  * @param {TemplateStringsArray} template 要注册的路径模板
1375
1405
  * @param {...any} substitutions 要注册的路径模板代替内容
1376
- * @returns {Binder}
1406
+ * @returns {Binder<T>}
1377
1407
  */
1378
1408
  /**
1379
1409
  * @param {...any} p 要注册的路径
1380
- * @returns {Binder | (() => void)}
1410
+ * @returns {Binder<T> | (() => void)}
1381
1411
  */
1382
1412
  head(...p) { return verb(this.#routes, ['HEAD'], p); }
1383
1413
  /**
1384
1414
  * 注册 HTTP OPTIONS 处理函数
1385
1415
  * @overload
1386
- * @param {Handler} handler 要注册的处理函数
1416
+ * @param {...Handler} handlers 要注册的处理函数
1387
1417
  * @returns {() => void}
1388
1418
  */
1389
1419
  /**
1390
1420
  * 注册 HTTP OPTIONS 处理函数
1391
1421
  * @overload
1392
1422
  * @param {string} path 要注册的路径
1393
- * @param {Handler} handler 要注册的处理函数
1423
+ * @param {...Handler} handlers 要注册的处理函数
1394
1424
  * @returns {() => void}
1395
1425
  */
1396
1426
  /**
1397
1427
  * 注册 HTTP OPTIONS 处理函数
1398
1428
  * @overload
1399
1429
  * @param {string} path 要注册的路径
1400
- * @returns {Binder}
1430
+ * @returns {Binder<T>}
1401
1431
  */
1402
1432
  /**
1403
1433
  * 注册 HTTP OPTIONS 处理函数
1404
1434
  * @overload
1405
1435
  * @param {TemplateStringsArray} template 要注册的路径模板
1406
1436
  * @param {...any} substitutions 要注册的路径模板代替内容
1407
- * @returns {Binder}
1437
+ * @returns {Binder<T>}
1408
1438
  */
1409
1439
  /**
1410
1440
  * @param {...any} p 要注册的路径
1411
- * @returns {Binder | (() => void)}
1441
+ * @returns {Binder<T> | (() => void)}
1412
1442
  */
1413
1443
  options(...p) { return verb(this.#routes, ['OPTIONS'], p); }
1414
1444
  }
@@ -1436,30 +1466,6 @@
1436
1466
  };
1437
1467
  }
1438
1468
 
1439
- /** @import { Context, Handler, HandlerResult } from './main/types' */
1440
- /**
1441
- * @callback Onionskin
1442
- * @param {Context} ctx
1443
- * @param {() => Promise<HandlerResult>} next
1444
- * @returns {PromiseLike<HandlerResult> | HandlerResult}
1445
- */
1446
-
1447
- const noop = () => {};
1448
- /**
1449
- *
1450
- * @param {...(Onionskin | Onionskin[])} handlers
1451
- * @returns {Handler}
1452
- */
1453
- function onionskin(...handlers) {
1454
- /** @type {Handler} */
1455
- let handler = noop;
1456
- for (const os of handlers.flat()) {
1457
- const currentHandler = handler;
1458
- handler = async ctx => os(ctx, async () => currentHandler(ctx));
1459
- }
1460
- return handler;
1461
- }
1462
-
1463
1469
  /** @import { Context } from './main/types.js' */
1464
1470
  class Param {
1465
1471
  #symbol = Symbol();
@@ -1496,15 +1502,13 @@
1496
1502
  }
1497
1503
  }
1498
1504
 
1499
- exports.ApiRouter = ApiRouter;
1505
+ exports.MapRouter = MapRouter;
1500
1506
  exports.Param = Param;
1501
1507
  exports.Router = Router;
1508
+ exports.bind = bind$1;
1502
1509
  exports.createFetch = createFetch;
1503
1510
  exports.main = main;
1504
1511
  exports.make = make;
1505
- exports.merge = merge;
1506
- exports.onionskin = onionskin;
1507
- exports.packer = packer;
1508
1512
  exports.service = service;
1509
1513
  exports.stateService = stateService;
1510
1514
  exports.storeService = storeService;