k99 0.6.0-beta.4 → 0.6.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,21 +1,21 @@
1
1
  /*!
2
- * k99 v0.6.0-beta.4
2
+ * k99 v0.6.0
3
3
  * (c) 2019-2024 猛火Fierflame
4
4
  * @license MIT
5
5
  */
6
6
  'use strict';
7
7
 
8
8
  /**
9
- *
10
- * @param {string} str
9
+ *
10
+ * @param {string} str
11
11
  * @returns {Uint8Array}
12
12
  */
13
13
  function str2utf8bin(str) {
14
14
  return new TextEncoder().encode(str);
15
15
  }
16
16
  /**
17
- *
18
- * @param {unknown} chunk
17
+ *
18
+ * @param {unknown} chunk
19
19
  * @returns {chunk is ArrayBuffer | SharedArrayBuffer}
20
20
  */
21
21
  function isBufferSource(chunk) {
@@ -28,9 +28,9 @@ function isBufferSource(chunk) {
28
28
  return false;
29
29
  }
30
30
  /**
31
- *
31
+ *
32
32
  * @template T
33
- * @param {any} result
33
+ * @param {any} result
34
34
  * @returns {result is Iterable<T> | AsyncIterable<T>}
35
35
  */
36
36
  function isIterable(result) {
@@ -39,7 +39,7 @@ function isIterable(result) {
39
39
  }
40
40
  /**
41
41
  * 向可写流中写入数据
42
- * @param {WritableStreamDefaultWriter<Uint8Array>} writer
42
+ * @param {WritableStreamDefaultWriter<Uint8Array>} writer
43
43
  * @param {unknown} chunk 要写入的数据
44
44
  * @returns {Promise<void>}
45
45
  */
@@ -64,9 +64,9 @@ async function write(writer, chunk) {
64
64
  }
65
65
 
66
66
  /**
67
- *
68
- * @param {any} k
69
- * @param {any} v
67
+ *
68
+ * @param {any} k
69
+ * @param {any} v
70
70
  * @returns {any}
71
71
  */
72
72
  function replacer(k, v) {
@@ -77,9 +77,9 @@ function replacer(k, v) {
77
77
  }
78
78
 
79
79
  /**
80
- *
81
- * @param {any} result
82
- * @param {Promise<never>} [aborted]
80
+ *
81
+ * @param {any} result
82
+ * @param {Promise<never>} [aborted]
83
83
  * @returns {[BodyInit, number, string] | null}
84
84
  */
85
85
  function toBodyData(result, aborted) {
@@ -112,7 +112,7 @@ function toBodyData(result, aborted) {
112
112
  /** @type {TransformStream<Uint8Array, Uint8Array>} */
113
113
  const { writable, readable } = new TransformStream();
114
114
  const writer = writable.getWriter();
115
- aborted?.catch((e) => {
115
+ aborted?.catch(e => {
116
116
  writable.abort(e || new DOMException('The user aborted a request.')).catch(() => {});
117
117
  });
118
118
  (async () => {
@@ -125,11 +125,11 @@ function toBodyData(result, aborted) {
125
125
  return [readable, 0, ''];
126
126
  }
127
127
  /**
128
- *
129
- * @param {any} result
130
- * @param {Headers} headers
131
- * @param {Promise<never>} [aborted]
132
- * @returns
128
+ *
129
+ * @param {any} result
130
+ * @param {Headers} headers
131
+ * @param {Promise<never>} [aborted]
132
+ * @returns
133
133
  */
134
134
  function toBody(result, headers, aborted) {
135
135
  const bodyData = toBodyData(result, aborted);
@@ -145,9 +145,9 @@ function toBody(result, headers, aborted) {
145
145
  }
146
146
 
147
147
  /**
148
- *
149
- * @param {import('./types').Cookie[]} sentCookies
150
- * @param {string} [name]
148
+ *
149
+ * @param {import('./types').Cookie[]} sentCookies
150
+ * @param {string} [name]
151
151
  * @returns {Iterable<import('./types').Cookie>}
152
152
  */
153
153
  function *getCookie(sentCookies, name) {
@@ -159,9 +159,9 @@ function *getCookie(sentCookies, name) {
159
159
  }
160
160
 
161
161
  /**
162
- *
163
- * @param {Headers} headers
164
- * @param {import('./types').Cookie[]} cookies
162
+ *
163
+ * @param {Headers} headers
164
+ * @param {import('./types').Cookie[]} cookies
165
165
  * @returns {void}
166
166
  */
167
167
  function setCookiesHeader(headers, cookies) {
@@ -179,8 +179,8 @@ function setCookiesHeader(headers, cookies) {
179
179
  }
180
180
  }
181
181
  /**
182
- *
183
- * @param {string} cookie
182
+ *
183
+ * @param {string} cookie
184
184
  * @returns {Record<string, string>}
185
185
  */
186
186
  function getRequestCookies(cookie) {
@@ -194,11 +194,11 @@ function getRequestCookies(cookie) {
194
194
  return cookies;
195
195
  }
196
196
  /**
197
- *
198
- * @param {import('./types').Cookie[]} sentCookies
199
- * @param {Record<string, string>} cookies
200
- * @param {string | import('./types').CookieOption} [name]
201
- * @param {import('./types').CookieOption | boolean} [opt]
197
+ *
198
+ * @param {import('./types').Cookie[]} sentCookies
199
+ * @param {Record<string, string>} cookies
200
+ * @param {string | import('./types').CookieOption} [name]
201
+ * @param {import('./types').CookieOption | boolean} [opt]
202
202
  * @returns {void}
203
203
  */
204
204
  function clearCookie(
@@ -227,8 +227,8 @@ function clearCookie(
227
227
 
228
228
  const noBodyMethods = new Set(['GET', 'OPTIONS']);
229
229
  /**
230
- *
231
- * @param {AbortSignal} signal
230
+ *
231
+ * @param {AbortSignal} signal
232
232
  * @returns {Promise<never>}
233
233
  */
234
234
  function signal2promise(signal) {
@@ -245,10 +245,10 @@ function signal2promise(signal) {
245
245
  }
246
246
 
247
247
  /**
248
- *
249
- * @param {Headers} headers
250
- * @param {string} name
251
- * @param {string} [value]
248
+ *
249
+ * @param {Headers} headers
250
+ * @param {string} name
251
+ * @param {string} [value]
252
252
  */
253
253
  function setHeader(headers, name, value) {
254
254
  if (value) {
@@ -258,9 +258,9 @@ function setHeader(headers, name, value) {
258
258
  }
259
259
  }
260
260
  /**
261
- *
262
- * @param {Request} request
263
- * @param {string | ((request: Request) => string)} [toMethod]
261
+ *
262
+ * @param {Request} request
263
+ * @param {string | ((request: Request) => string)} [toMethod]
264
264
  * @returns {import('./types').Method}
265
265
  */
266
266
  function getMethod(request, toMethod) {
@@ -276,20 +276,20 @@ function getMethod(request, toMethod) {
276
276
  return /** @type {import('./types').Method} */(methodStr.toUpperCase());
277
277
  }
278
278
  /**
279
- *
280
- * @param {Request} request
281
- * @param {import('./types').FindHandler} getHandler
279
+ *
280
+ * @param {Request} request
281
+ * @param {import('./types').FindHandler} getHandler
282
282
  * @param {import('./types').Options} [options]
283
283
  * @returns {Promise<Response | null>}
284
284
  */
285
285
  function main(
286
286
  request, getHandler,
287
- { runner, error: echoError, method: toMethod, environment } = {},
287
+ { runner, error: echoError, catch: catchError, method: toMethod, environment } = {},
288
288
  ) {
289
289
  /**
290
- *
291
- * @param {Request} request
292
- * @param {import('./types').Context} [parent]
290
+ *
291
+ * @param {Request} request
292
+ * @param {import('./types').Context} [parent]
293
293
  * @returns {Promise<Response | null>}
294
294
  */
295
295
  function exec(request, parent) {
@@ -311,7 +311,7 @@ function main(
311
311
 
312
312
  let resolve = () => {};
313
313
  /** @type {(error: unknown) => void} */
314
- let reject = (error) => {};
314
+ let reject = () => {};
315
315
  /** @type {Promise<void>} */
316
316
  const donePromise = new Promise((a, b) => { resolve = a; reject = b; });
317
317
  donePromise.catch(() => {});
@@ -381,9 +381,9 @@ function main(
381
381
  setCookiesHeader(responseHeaders, sentCookies);
382
382
  },
383
383
  /**
384
- *
385
- * @param {string | import('./types').CookieOption} [name]
386
- * @param {import('./types').CookieOption | boolean} [opt]
384
+ *
385
+ * @param {string | import('./types').CookieOption} [name]
386
+ * @param {import('./types').CookieOption | boolean} [opt]
387
387
  * @returns {void}
388
388
  */
389
389
  clearCookie(name, opt) {
@@ -413,7 +413,7 @@ function main(
413
413
  error = e || true;
414
414
  reject(error);
415
415
  return Promise.reject(e);
416
- });
416
+ }).catch(catchError);
417
417
  }
418
418
  return runner ? runner(context, run) : run();
419
419
  }
@@ -421,19 +421,19 @@ function main(
421
421
  }
422
422
 
423
423
  /**
424
- *
425
- * @param {import('./main/types').FindHandler} getHandler
426
- * @param {import('./main/types').Options} options
424
+ *
425
+ * @param {import('./main/types').FindHandler} getHandler
426
+ * @param {import('./main/types').Options} options
427
427
  * @returns {(request: Request) => Promise<Response | null>}
428
428
  */
429
429
  function make(getHandler, options) {
430
- return (r) => main(r, getHandler, options);
430
+ return r => main(r, getHandler, options);
431
431
  }
432
432
 
433
433
  /**
434
- *
435
- * @param {import('./main/types').Context} context
436
- * @param {import('./main/types').Handler[]} handlers
434
+ *
435
+ * @param {import('./main/types').Context} context
436
+ * @param {import('./main/types').Handler[]} handlers
437
437
  * @returns {Promise<string | boolean | object | undefined>}
438
438
  */
439
439
  async function runHandles(context, handlers) {
@@ -446,8 +446,8 @@ async function runHandles(context, handlers) {
446
446
  }
447
447
 
448
448
  /**
449
- *
450
- * @param {...(import('./main/types').Handler | import('./main/types').Handler[])} handlers
449
+ *
450
+ * @param {...(import('./main/types').Handler | import('./main/types').Handler[])} handlers
451
451
  * @returns {import('./main/types').Handler}
452
452
  */
453
453
  function merge(...handlers) {
@@ -455,30 +455,30 @@ function merge(...handlers) {
455
455
  }
456
456
 
457
457
  /**
458
- *
458
+ *
459
459
  * @template T
460
460
  * @template {any[]} P
461
461
  * @overload
462
- * @param {(ctx: import('./main/types').Context, ...p: P) => T} exec
463
- * @param {((ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
464
- * @param {import('./main/types').Service.Options?} [options]
462
+ * @param {(ctx: import('./main/types').Context, ...p: P) => T} exec
463
+ * @param {((ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
464
+ * @param {import('./main/types').Service.Options?} [options]
465
465
  * @returns {import('./main/types').Service<T, P>}
466
466
  */
467
467
  /**
468
- *
468
+ *
469
469
  * @template T
470
470
  * @template {any[]} P
471
471
  * @overload
472
- * @param {(ctx: import('./main/types').Context, ...p: P) => T} exec
473
- * @param {import('./main/types').Service.Options?} [options]
472
+ * @param {(ctx: import('./main/types').Context, ...p: P) => T} exec
473
+ * @param {import('./main/types').Service.Options?} [options]
474
474
  * @returns {import('./main/types').Service<T, P>}
475
475
  */
476
476
  /**
477
477
  * @template T
478
478
  * @template {any[]} P
479
- * @param {(ctx: import('./main/types').Context, ...p: P) => T} exec
480
- * @param {((ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void) | import('./main/types').Service.Options | null} [destroy]
481
- * @param {import('./main/types').Service.Options?} [options]
479
+ * @param {(ctx: import('./main/types').Context, ...p: P) => T} exec
480
+ * @param {((ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void) | import('./main/types').Service.Options | null} [destroy]
481
+ * @param {import('./main/types').Service.Options?} [options]
482
482
  * @returns {import('./main/types').Service<T, P>}
483
483
  */
484
484
  function service(exec, destroy, options) {
@@ -502,38 +502,38 @@ function service(exec, destroy, options) {
502
502
  }
503
503
 
504
504
  /**
505
- *
505
+ *
506
506
  * @template T
507
507
  * @overload
508
- * @param {(ctx: import('./main/types').Context) => T} init
509
- * @param {import('./main/types').Service.Options} [options]
508
+ * @param {(ctx: import('./main/types').Context) => T} init
509
+ * @param {import('./main/types').Service.Options} [options]
510
510
  * @returns {import('./main/types').StateService<T>}
511
511
  */
512
512
  /**
513
- *
513
+ *
514
514
  * @template T
515
515
  * @overload
516
- * @param {(ctx: import('./main/types').Context) => T} init
517
- * @param {((state: T | undefined, ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
518
- * @param {import('./main/types').Service.Options?} [options]
516
+ * @param {(ctx: import('./main/types').Context) => T} init
517
+ * @param {((state: T | undefined, ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
518
+ * @param {import('./main/types').Service.Options?} [options]
519
519
  * @returns {import('./main/types').StateService<T>}
520
520
  */
521
521
  /**
522
- *
522
+ *
523
523
  * @template T
524
524
  * @overload
525
- * @param {(ctx: import('./main/types').Context) => T} init
526
- * @param {((state: T | undefined, ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
527
- * @param {((state: T, ctx: import('./main/types').Context) => any)?} [exec]
528
- * @param {import('./main/types').Service.Options?} [options]
525
+ * @param {(ctx: import('./main/types').Context) => T} init
526
+ * @param {((state: T | undefined, ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
527
+ * @param {((state: T, ctx: import('./main/types').Context) => any)?} [exec]
528
+ * @param {import('./main/types').Service.Options?} [options]
529
529
  * @returns {import('./main/types').StateService<T>}
530
530
  */
531
531
  /**
532
532
  * @template T
533
- * @param {(ctx: import('./main/types').Context) => T} init
534
- * @param {((state: T | undefined, ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void) | import('./main/types').Service.Options | null} [destroy]
535
- * @param {((state: T, ctx: import('./main/types').Context) => any) | import('./main/types').Service.Options | null} [exec]
536
- * @param {import('./main/types').Service.Options?} [options]
533
+ * @param {(ctx: import('./main/types').Context) => T} init
534
+ * @param {((state: T | undefined, ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void) | import('./main/types').Service.Options | null} [destroy]
535
+ * @param {((state: T, ctx: import('./main/types').Context) => any) | import('./main/types').Service.Options | null} [exec]
536
+ * @param {import('./main/types').Service.Options?} [options]
537
537
  * @returns {import('./main/types').StateService<T>}
538
538
  */
539
539
  function stateService(init, destroy, exec, options) {
@@ -562,34 +562,34 @@ function stateService(init, destroy, exec, options) {
562
562
  }
563
563
 
564
564
  /**
565
- *
565
+ *
566
566
  * @template T
567
567
  * @overload
568
- * @param {import('./main/types').Service.Options?} [options]
568
+ * @param {import('./main/types').Service.Options?} [options]
569
569
  * @returns {import('./main/types').StoreService<T>}
570
570
  */
571
571
  /**
572
- *
572
+ *
573
573
  * @template T
574
574
  * @overload
575
- * @param {((state: T | undefined, ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
576
- * @param {import('./main/types').Service.Options?} [options]
575
+ * @param {((state: T | undefined, ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
576
+ * @param {import('./main/types').Service.Options?} [options]
577
577
  * @returns {import('./main/types').StoreService<T>}
578
578
  */
579
579
  /**
580
- *
580
+ *
581
581
  * @template T
582
582
  * @overload
583
- * @param {((state: T | undefined, ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
584
- * @param {((state: T | undefined, ctx: import('./main/types').Context) => any)?} [exec]
585
- * @param {import('./main/types').Service.Options?} [options]
583
+ * @param {((state: T | undefined, ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
584
+ * @param {((state: T | undefined, ctx: import('./main/types').Context) => any)?} [exec]
585
+ * @param {import('./main/types').Service.Options?} [options]
586
586
  * @returns {import('./main/types').StoreService<T>}
587
587
  */
588
588
  /**
589
589
  * @template T
590
- * @param {((state: T | undefined, ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void) | import('./main/types').Service.Options | null} [destroy]
591
- * @param {((state: T | undefined, ctx: import('./main/types').Context) => any) | import('./main/types').Service.Options | null} [exec]
592
- * @param {import('./main/types').Service.Options?} [options]
590
+ * @param {((state: T | undefined, ctx: import('./main/types').Context, error?: unknown) => PromiseLike<void> | void) | import('./main/types').Service.Options | null} [destroy]
591
+ * @param {((state: T | undefined, ctx: import('./main/types').Context) => any) | import('./main/types').Service.Options | null} [exec]
592
+ * @param {import('./main/types').Service.Options?} [options]
593
593
  * @returns {import('./main/types').StoreService<T>}
594
594
  */
595
595
  function storeService(destroy, exec, options) {
@@ -631,18 +631,30 @@ function storeService(destroy, exec, options) {
631
631
  }
632
632
 
633
633
  /**
634
- * @callback Guard
635
- * @param {import('./main/types').Context} ctx
636
- * @returns {PromiseLike<boolean | import('./main/types').Handler | void> | boolean | import('./main/types').Handler | void}
634
+ * @callback Packer
635
+ * @param {import('./main/types').Handler} handler
636
+ * @returns {import('./main/types').Handler}
637
637
  */
638
+ /** @type {Packer} */
639
+ const noop$1 = h => h;
640
+ /**
641
+ *
642
+ * @param {import('./onionskin.mjs').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
+ }
638
652
 
639
653
  /**
640
- * @callback Onionskin
654
+ * @callback Guard
641
655
  * @param {import('./main/types').Context} ctx
642
- * @param {() => Promise<import('./main/types').HandlerResult>} next
643
- * @returns {PromiseLike<import('./main/types').HandlerResult> | import('./main/types').HandlerResult}
656
+ * @returns {PromiseLike<boolean | import('./main/types').Handler | void> | boolean | import('./main/types').Handler | void}
644
657
  */
645
-
646
658
  /**
647
659
  * @typedef {[import('./main/types').Handler | Router, Record<string, any>, string[]]} FindItem
648
660
  */
@@ -753,7 +765,7 @@ class Router {
753
765
  * @returns {Router}
754
766
  */
755
767
  static create(find) {
756
- return Object.create(Router.prototype, {
768
+ return Object.defineProperties(new Router(), {
757
769
  'find': { configurable: true, value: find, writable: true },
758
770
  });
759
771
  }
@@ -765,14 +777,8 @@ class Router {
765
777
  * @returns {import('./main/types').Handler}
766
778
  */
767
779
  __onionskin = (h) => h;
768
- /** @param {Onionskin} os */
769
- onionskin(os) {
770
- let run = this.__onionskin;
771
- this.__onionskin = h => {
772
- const h2 = run(h);
773
- return async (ctx) => os(ctx, async () => h2(ctx));
774
- };
775
- }
780
+ /** @param {import('./onionskin.mjs').Onionskin} os */
781
+ onionskin(os) { this.__onionskin = packer(os, this.__onionskin); }
776
782
  }
777
783
 
778
784
  /**
@@ -785,8 +791,8 @@ class Router {
785
791
 
786
792
  const regex = /^:([a-zA-Z][a-zA-Z0-9]*)(?:\((.+)\))?([ius]+)?([?+*]?)$/;
787
793
  /**
788
- *
789
- * @param {string} p
794
+ *
795
+ * @param {string} p
790
796
  * @returns {Pattern | string}
791
797
  */
792
798
  function parse(p) {
@@ -843,10 +849,10 @@ function parse(p) {
843
849
 
844
850
  }
845
851
  /**
846
- *
847
- * @param {(Pattern | string)[]} match
848
- * @param {string[]} path
849
- * @param {boolean} end
852
+ *
853
+ * @param {(Pattern | string)[]} match
854
+ * @param {string[]} path
855
+ * @param {boolean} end
850
856
  * @returns {[Record<string, string | string[]>, string[]] | undefined}
851
857
  */
852
858
  function exec(match, path, end) {
@@ -874,9 +880,9 @@ function exec(match, path, end) {
874
880
 
875
881
  }
876
882
  /**
877
- *
878
- * @param {string} path
879
- * @param {boolean} end
883
+ *
884
+ * @param {string} path
885
+ * @param {boolean} end
880
886
  * @returns {import('./index.mjs').Match | undefined}
881
887
  */
882
888
  function toMatch(path, end) {
@@ -891,11 +897,11 @@ function toMatch(path, end) {
891
897
  }
892
898
 
893
899
  /**
894
- *
895
- * @param {(import('./index.mjs').Route | import('./index.mjs').RouterRoute)[]} routes
896
- * @param {import('../main/types').Method[]} methods
897
- * @param {string} path
898
- * @param {import('../main/types').Handler} handler
900
+ *
901
+ * @param {(import('./index.mjs').Route | import('./index.mjs').RouterRoute)[]} routes
902
+ * @param {import('../main/types').Method[]} methods
903
+ * @param {string} path
904
+ * @param {import('../main/types').Handler} handler
899
905
  * @returns {() => void}
900
906
  */
901
907
  function bind(routes, methods, path, handler) {
@@ -918,10 +924,10 @@ function bind(routes, methods, path, handler) {
918
924
  /** @type {(v: any) => v is import('../main/types').Handler} */
919
925
  const findHandler = v => typeof v === 'function';
920
926
  /**
921
- *
922
- * @param {(import('./index.mjs').Route | import('./index.mjs').RouterRoute)[]} routes
923
- * @param {import('../main/types').Method[]} methods
924
- * @param {any[]} p
927
+ *
928
+ * @param {(import('./index.mjs').Route | import('./index.mjs').RouterRoute)[]} routes
929
+ * @param {import('../main/types').Method[]} methods
930
+ * @param {any[]} p
925
931
  * @returns {import('./index.mjs').Binder | (() => void)}
926
932
  */
927
933
  function verb(routes, methods, p) {
@@ -943,14 +949,14 @@ function verb(routes, methods, p) {
943
949
 
944
950
  const methods = new Set(['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS']);
945
951
  /**
946
- *
947
- * @param {any} v
952
+ *
953
+ * @param {any} v
948
954
  * @returns {v is import('../main/types').Method}
949
955
  */
950
956
  function isMethod(v) { return methods.has(v); }
951
957
  /**
952
- *
953
- * @param {import('../main/types').Method | Iterable<import('../main/types').Method> | ArrayLike<import('../main/types').Method>} [methods]
958
+ *
959
+ * @param {import('../main/types').Method | Iterable<import('../main/types').Method> | ArrayLike<import('../main/types').Method>} [methods]
954
960
  * @returns {import('../main/types').Method[]}
955
961
  */
956
962
  function getMethods(methods) {
@@ -1000,10 +1006,10 @@ function getMethods(methods) {
1000
1006
  * @returns {T extends import('../Router.mjs').Finder ? Router : T}
1001
1007
  */
1002
1008
  /**
1003
- *
1004
- * @param {(Route | RouterRoute)[]} routes
1005
- * @param {string} path
1006
- * @param {Router | import('../Router.mjs').Finder} [r]
1009
+ *
1010
+ * @param {(Route | RouterRoute)[]} routes
1011
+ * @param {string} path
1012
+ * @param {Router | import('../Router.mjs').Finder} [r]
1007
1013
  * @returns {Router}
1008
1014
  */
1009
1015
  function bindRouter(routes, path, r) {
@@ -1058,10 +1064,10 @@ class ApiRouter extends Router {
1058
1064
  return bindRouter(this.#routes, path, r);
1059
1065
  }
1060
1066
  /**
1061
- *
1062
- * @param {import('../main/types').Method} method
1063
- * @param {string[]} path
1064
- * @param {import('../main/types').Context} ctx
1067
+ *
1068
+ * @param {import('../main/types').Method} method
1069
+ * @param {string[]} path
1070
+ * @param {import('../main/types').Context} ctx
1065
1071
  * @returns {Iterable<import('../Router.mjs').FindItem>}
1066
1072
  */
1067
1073
  *find(method, path, ctx) {
@@ -1103,7 +1109,7 @@ class ApiRouter extends Router {
1103
1109
  * @returns {Binder}
1104
1110
  */
1105
1111
  /**
1106
- * @param {import('../main/types').Method | Iterable<import('../main/types').Method> | ArrayLike<import('../main/types').Method>} methods
1112
+ * @param {import('../main/types').Method | Iterable<import('../main/types').Method> | ArrayLike<import('../main/types').Method>} methods
1107
1113
  * @param {string| import('../main/types').Handler} [path]
1108
1114
  * @param {import('../main/types').Handler} [handler]
1109
1115
  * @returns {Binder | (() => void)}
@@ -1335,9 +1341,9 @@ class ApiRouter extends Router {
1335
1341
  }
1336
1342
 
1337
1343
  /**
1338
- *
1339
- * @param {(request: Request) => Promise<Response | null>} run
1340
- * @param {((request: Request) => Response | Promise<Response>)?} [notFound]
1344
+ *
1345
+ * @param {(request: Request) => Promise<Response | null>} run
1346
+ * @param {((request: Request) => Response | Promise<Response>)?} [notFound]
1341
1347
  * @returns {(input: RequestInfo, init?: RequestInit) => Promise<Response>}
1342
1348
  */
1343
1349
  function createFetch(run, notFound) {
@@ -1357,12 +1363,37 @@ function createFetch(run, notFound) {
1357
1363
  };
1358
1364
  }
1359
1365
 
1366
+ /**
1367
+ * @callback Onionskin
1368
+ * @param {import('./main/types').Context} ctx
1369
+ * @param {() => Promise<import('./main/types').HandlerResult>} next
1370
+ * @returns {PromiseLike<import('./main/types').HandlerResult> | import('./main/types').HandlerResult}
1371
+ */
1372
+
1373
+ const noop = () => {};
1374
+ /**
1375
+ *
1376
+ * @param {...(Onionskin | Onionskin[])} handlers
1377
+ * @returns {import('./main/types').Handler}
1378
+ */
1379
+ function onionskin(...handlers) {
1380
+ /** @type {import('./main/types').Handler} */
1381
+ let handler = noop;
1382
+ for (const os of handlers.flat()) {
1383
+ const currentHandler = handler;
1384
+ handler = async ctx => os(ctx, async () => currentHandler(ctx));
1385
+ }
1386
+ return handler;
1387
+ }
1388
+
1360
1389
  exports.ApiRouter = ApiRouter;
1361
1390
  exports.Router = Router;
1362
1391
  exports.createFetch = createFetch;
1363
1392
  exports.main = main;
1364
1393
  exports.make = make;
1365
1394
  exports.merge = merge;
1395
+ exports.onionskin = onionskin;
1396
+ exports.packer = packer;
1366
1397
  exports.service = service;
1367
1398
  exports.stateService = stateService;
1368
1399
  exports.storeService = storeService;