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