k99 0.6.1 → 0.7.1
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 +302 -181
- package/index.d.ts +101 -77
- package/index.js +302 -181
- package/index.min.js +2 -2
- package/index.min.mjs +2 -2
- package/index.mjs +302 -182
- package/package.json +2 -3
- package/services.cjs +5 -3
- package/services.d.ts +7 -6
- package/services.js +5 -3
- package/services.min.js +1 -1
- package/services.min.mjs +1 -1
- package/services.mjs +5 -3
- package/node/index.cjs +0 -149
- package/node/index.d.cts +0 -49
package/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* k99 v0.
|
|
2
|
+
* k99 v0.7.1
|
|
3
3
|
* (c) 2019-2025 猛火Fierflame
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
@@ -106,8 +106,7 @@ function toBodyData(result, aborted) {
|
|
|
106
106
|
if (!data) { continue; }
|
|
107
107
|
await write(writer, data);
|
|
108
108
|
}
|
|
109
|
-
|
|
110
|
-
})().catch(() => {});
|
|
109
|
+
})().then(() => writable.close(), r => writable.abort(r)).catch(() => {});
|
|
111
110
|
return [readable, 0, ''];
|
|
112
111
|
}
|
|
113
112
|
/**
|
|
@@ -130,11 +129,12 @@ function toBody(result, headers, aborted) {
|
|
|
130
129
|
return body;
|
|
131
130
|
}
|
|
132
131
|
|
|
132
|
+
/** @import { Cookie, CookieOption } from './types' */
|
|
133
133
|
/**
|
|
134
134
|
*
|
|
135
|
-
* @param {
|
|
135
|
+
* @param {Cookie[]} sentCookies
|
|
136
136
|
* @param {string} [name]
|
|
137
|
-
* @returns {Iterable<
|
|
137
|
+
* @returns {Iterable<Cookie>}
|
|
138
138
|
*/
|
|
139
139
|
function *getCookie(sentCookies, name) {
|
|
140
140
|
const list = sentCookies;
|
|
@@ -147,7 +147,7 @@ function *getCookie(sentCookies, name) {
|
|
|
147
147
|
/**
|
|
148
148
|
*
|
|
149
149
|
* @param {Headers} headers
|
|
150
|
-
* @param {
|
|
150
|
+
* @param {Cookie[]} cookies
|
|
151
151
|
* @returns {void}
|
|
152
152
|
*/
|
|
153
153
|
function setCookiesHeader(headers, cookies) {
|
|
@@ -181,10 +181,10 @@ function getRequestCookies(cookie) {
|
|
|
181
181
|
}
|
|
182
182
|
/**
|
|
183
183
|
*
|
|
184
|
-
* @param {
|
|
184
|
+
* @param {Cookie[]} sentCookies
|
|
185
185
|
* @param {Record<string, string>} cookies
|
|
186
|
-
* @param {string |
|
|
187
|
-
* @param {
|
|
186
|
+
* @param {string | CookieOption} [name]
|
|
187
|
+
* @param {CookieOption | boolean} [opt]
|
|
188
188
|
* @returns {void}
|
|
189
189
|
*/
|
|
190
190
|
function clearCookie(
|
|
@@ -196,11 +196,11 @@ function clearCookie(
|
|
|
196
196
|
let expire = 'Fri, 31 Dec 1999 16:00:00 GMT';
|
|
197
197
|
if (typeof name === 'string') {
|
|
198
198
|
if (!name) { return; }
|
|
199
|
-
/** @type {
|
|
199
|
+
/** @type {CookieOption} */
|
|
200
200
|
const { domain, path, secure, httpOnly } = opt !== true && opt || {};
|
|
201
201
|
sentCookies.push({ name, value: 'delete', expire, domain, path, secure, httpOnly });
|
|
202
202
|
} else {
|
|
203
|
-
/** @type {
|
|
203
|
+
/** @type {CookieOption} */
|
|
204
204
|
const { domain, path, secure, httpOnly } = name || {};
|
|
205
205
|
sentCookies.length = 0;
|
|
206
206
|
if (opt) {
|
|
@@ -211,6 +211,9 @@ function clearCookie(
|
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
/** @import { Context, Cookie, CookieOption, FindHandler, Method, Options, Params, Service } from './types' */
|
|
215
|
+
|
|
216
|
+
|
|
214
217
|
const noBodyMethods = new Set(['GET', 'OPTIONS']);
|
|
215
218
|
/**
|
|
216
219
|
*
|
|
@@ -247,7 +250,7 @@ function setHeader(headers, name, value) {
|
|
|
247
250
|
*
|
|
248
251
|
* @param {Request} request
|
|
249
252
|
* @param {string | ((request: Request) => string)} [toMethod]
|
|
250
|
-
* @returns {
|
|
253
|
+
* @returns {Method}
|
|
251
254
|
*/
|
|
252
255
|
function getMethod(request, toMethod) {
|
|
253
256
|
let methodStr = '';
|
|
@@ -259,13 +262,13 @@ function getMethod(request, toMethod) {
|
|
|
259
262
|
if (!methodStr || typeof methodStr !== 'string') {
|
|
260
263
|
methodStr = request.method || 'GET';
|
|
261
264
|
}
|
|
262
|
-
return /** @type {
|
|
265
|
+
return /** @type {Method} */(methodStr.toUpperCase());
|
|
263
266
|
}
|
|
264
267
|
/**
|
|
265
268
|
*
|
|
266
269
|
* @param {Request} request
|
|
267
|
-
* @param {
|
|
268
|
-
* @param {
|
|
270
|
+
* @param {FindHandler} getHandler
|
|
271
|
+
* @param {Options} [options]
|
|
269
272
|
* @returns {Promise<Response | null>}
|
|
270
273
|
*/
|
|
271
274
|
function main(
|
|
@@ -275,7 +278,7 @@ function main(
|
|
|
275
278
|
/**
|
|
276
279
|
*
|
|
277
280
|
* @param {Request} request
|
|
278
|
-
* @param {
|
|
281
|
+
* @param {Context} [parent]
|
|
279
282
|
* @returns {Promise<Response | null>}
|
|
280
283
|
*/
|
|
281
284
|
function exec(request, parent) {
|
|
@@ -283,10 +286,10 @@ function main(
|
|
|
283
286
|
const url = new URL(request.url);
|
|
284
287
|
const { signal, headers } = request;
|
|
285
288
|
const aborted = signal2promise(signal);
|
|
286
|
-
/** @type {Map<
|
|
289
|
+
/** @type {Map<Service<any, any>, Function>} */
|
|
287
290
|
const services = new Map();
|
|
288
291
|
const cookies = getRequestCookies(headers.get('cookie') || '');
|
|
289
|
-
/** @type {
|
|
292
|
+
/** @type {Cookie[]} */
|
|
290
293
|
const sentCookies = [];
|
|
291
294
|
const responseHeaders = new Headers();
|
|
292
295
|
const root = parent?.root;
|
|
@@ -302,9 +305,9 @@ function main(
|
|
|
302
305
|
const donePromise = new Promise((a, b) => { resolve = a; reject = b; });
|
|
303
306
|
donePromise.catch(() => {});
|
|
304
307
|
|
|
305
|
-
/** @type {
|
|
308
|
+
/** @type {Params} */
|
|
306
309
|
let params = {};
|
|
307
|
-
/** @type {
|
|
310
|
+
/** @type {Context} */
|
|
308
311
|
const context = {
|
|
309
312
|
environment,
|
|
310
313
|
parent,
|
|
@@ -368,8 +371,8 @@ function main(
|
|
|
368
371
|
},
|
|
369
372
|
/**
|
|
370
373
|
*
|
|
371
|
-
* @param {string |
|
|
372
|
-
* @param {
|
|
374
|
+
* @param {string | CookieOption} [name]
|
|
375
|
+
* @param {CookieOption | boolean} [opt]
|
|
373
376
|
* @returns {void}
|
|
374
377
|
*/
|
|
375
378
|
clearCookie(name, opt) {
|
|
@@ -406,69 +409,72 @@ function main(
|
|
|
406
409
|
return exec(request);
|
|
407
410
|
}
|
|
408
411
|
|
|
412
|
+
/** @import { FindHandler, Options } from './main/types' */
|
|
413
|
+
|
|
409
414
|
/**
|
|
410
415
|
*
|
|
411
|
-
* @param {
|
|
412
|
-
* @param {
|
|
416
|
+
* @param {FindHandler} getHandler
|
|
417
|
+
* @param {Options} options
|
|
413
418
|
* @returns {(request: Request) => Promise<Response | null>}
|
|
414
419
|
*/
|
|
415
420
|
function make(getHandler, options) {
|
|
416
421
|
return r => main(r, getHandler, options);
|
|
417
422
|
}
|
|
418
423
|
|
|
424
|
+
/** @import { Context, Handler } from './main/types' */
|
|
419
425
|
/**
|
|
420
426
|
*
|
|
421
|
-
* @param {
|
|
422
|
-
* @param {
|
|
427
|
+
* @param {Context} context
|
|
428
|
+
* @param {Handler[]} handlers
|
|
423
429
|
* @returns {Promise<string | boolean | object | undefined>}
|
|
424
430
|
*/
|
|
425
431
|
async function runHandles(context, handlers) {
|
|
426
432
|
for (const handle of handlers) {
|
|
427
433
|
const result = await handle(context);
|
|
428
|
-
if (
|
|
429
|
-
if (!result) { continue; }
|
|
434
|
+
if (result === undefined) { continue; }
|
|
430
435
|
return result;
|
|
431
436
|
}
|
|
432
437
|
}
|
|
433
438
|
|
|
434
439
|
/**
|
|
435
440
|
*
|
|
436
|
-
* @param {...(
|
|
437
|
-
* @returns {
|
|
441
|
+
* @param {...(Handler | Handler[])} handlers
|
|
442
|
+
* @returns {Handler}
|
|
438
443
|
*/
|
|
439
444
|
function merge(...handlers) {
|
|
440
445
|
return ctx => runHandles(ctx, handlers.flat());
|
|
441
446
|
}
|
|
442
447
|
|
|
448
|
+
/** @import { Context, Service } from './main/types' */
|
|
443
449
|
/**
|
|
444
450
|
*
|
|
445
451
|
* @template T
|
|
446
452
|
* @template {any[]} P
|
|
447
453
|
* @overload
|
|
448
|
-
* @param {(ctx:
|
|
449
|
-
* @param {((ctx:
|
|
450
|
-
* @param {
|
|
451
|
-
* @returns {
|
|
454
|
+
* @param {(ctx: Context, ...p: P) => T} exec
|
|
455
|
+
* @param {((ctx: Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
|
|
456
|
+
* @param {Service.Options?} [options]
|
|
457
|
+
* @returns {Service<T, P>}
|
|
452
458
|
*/
|
|
453
459
|
/**
|
|
454
460
|
*
|
|
455
461
|
* @template T
|
|
456
462
|
* @template {any[]} P
|
|
457
463
|
* @overload
|
|
458
|
-
* @param {(ctx:
|
|
459
|
-
* @param {
|
|
460
|
-
* @returns {
|
|
464
|
+
* @param {(ctx: Context, ...p: P) => T} exec
|
|
465
|
+
* @param {Service.Options?} [options]
|
|
466
|
+
* @returns {Service<T, P>}
|
|
461
467
|
*/
|
|
462
468
|
/**
|
|
463
469
|
* @template T
|
|
464
470
|
* @template {any[]} P
|
|
465
|
-
* @param {(ctx:
|
|
466
|
-
* @param {((ctx:
|
|
467
|
-
* @param {
|
|
468
|
-
* @returns {
|
|
471
|
+
* @param {(ctx: Context, ...p: P) => T} exec
|
|
472
|
+
* @param {((ctx: Context, error?: unknown) => PromiseLike<void> | void) | Service.Options | null} [destroy]
|
|
473
|
+
* @param {Service.Options?} [options]
|
|
474
|
+
* @returns {Service<T, P>}
|
|
469
475
|
*/
|
|
470
476
|
function service(exec, destroy, options) {
|
|
471
|
-
/** @type {
|
|
477
|
+
/** @type {Service<T, P>} */
|
|
472
478
|
const service = function (ctx) {
|
|
473
479
|
if (typeof destroy === 'function') {
|
|
474
480
|
ctx.done(() => destroy(ctx), error => destroy(ctx, error));
|
|
@@ -487,43 +493,44 @@ function service(exec, destroy, options) {
|
|
|
487
493
|
return service;
|
|
488
494
|
}
|
|
489
495
|
|
|
496
|
+
/** @import { Context, Service, StateService } from './main/types' */
|
|
490
497
|
/**
|
|
491
498
|
*
|
|
492
499
|
* @template T
|
|
493
500
|
* @overload
|
|
494
|
-
* @param {(ctx:
|
|
495
|
-
* @param {
|
|
496
|
-
* @returns {
|
|
501
|
+
* @param {(ctx: Context) => T} init
|
|
502
|
+
* @param {Service.Options} [options]
|
|
503
|
+
* @returns {StateService<T>}
|
|
497
504
|
*/
|
|
498
505
|
/**
|
|
499
506
|
*
|
|
500
507
|
* @template T
|
|
501
508
|
* @overload
|
|
502
|
-
* @param {(ctx:
|
|
503
|
-
* @param {((state: T | undefined, ctx:
|
|
504
|
-
* @param {
|
|
505
|
-
* @returns {
|
|
509
|
+
* @param {(ctx: Context) => T} init
|
|
510
|
+
* @param {((state: T | undefined, ctx: Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
|
|
511
|
+
* @param {Service.Options?} [options]
|
|
512
|
+
* @returns {StateService<T>}
|
|
506
513
|
*/
|
|
507
514
|
/**
|
|
508
515
|
*
|
|
509
516
|
* @template T
|
|
510
517
|
* @overload
|
|
511
|
-
* @param {(ctx:
|
|
512
|
-
* @param {((state: T | undefined, ctx:
|
|
513
|
-
* @param {((state: T, ctx:
|
|
514
|
-
* @param {
|
|
515
|
-
* @returns {
|
|
518
|
+
* @param {(ctx: Context) => T} init
|
|
519
|
+
* @param {((state: T | undefined, ctx: Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
|
|
520
|
+
* @param {((state: T, ctx: Context) => any)?} [exec]
|
|
521
|
+
* @param {Service.Options?} [options]
|
|
522
|
+
* @returns {StateService<T>}
|
|
516
523
|
*/
|
|
517
524
|
/**
|
|
518
525
|
* @template T
|
|
519
|
-
* @param {(ctx:
|
|
520
|
-
* @param {((state: T | undefined, ctx:
|
|
521
|
-
* @param {((state: T, ctx:
|
|
522
|
-
* @param {
|
|
523
|
-
* @returns {
|
|
526
|
+
* @param {(ctx: Context) => T} init
|
|
527
|
+
* @param {((state: T | undefined, ctx: Context, error?: unknown) => PromiseLike<void> | void) | Service.Options | null} [destroy]
|
|
528
|
+
* @param {((state: T, ctx: Context) => any) | Service.Options | null} [exec]
|
|
529
|
+
* @param {Service.Options?} [options]
|
|
530
|
+
* @returns {StateService<T>}
|
|
524
531
|
*/
|
|
525
532
|
function stateService(init, destroy, exec, options) {
|
|
526
|
-
/** @type {
|
|
533
|
+
/** @type {StateService<T>} */
|
|
527
534
|
const service = function (ctx) {
|
|
528
535
|
const state = init(ctx) || /** @type {T} */({});
|
|
529
536
|
if (typeof destroy === 'function') {
|
|
@@ -547,39 +554,40 @@ function stateService(init, destroy, exec, options) {
|
|
|
547
554
|
return service;
|
|
548
555
|
}
|
|
549
556
|
|
|
557
|
+
/** @import { Context, Service, StoreService } from './main/types' */
|
|
550
558
|
/**
|
|
551
559
|
*
|
|
552
560
|
* @template T
|
|
553
561
|
* @overload
|
|
554
|
-
* @param {
|
|
555
|
-
* @returns {
|
|
562
|
+
* @param {Service.Options?} [options]
|
|
563
|
+
* @returns {StoreService<T>}
|
|
556
564
|
*/
|
|
557
565
|
/**
|
|
558
566
|
*
|
|
559
567
|
* @template T
|
|
560
568
|
* @overload
|
|
561
|
-
* @param {((state: T | undefined, ctx:
|
|
562
|
-
* @param {
|
|
563
|
-
* @returns {
|
|
569
|
+
* @param {((state: T | undefined, ctx: Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
|
|
570
|
+
* @param {Service.Options?} [options]
|
|
571
|
+
* @returns {StoreService<T>}
|
|
564
572
|
*/
|
|
565
573
|
/**
|
|
566
574
|
*
|
|
567
575
|
* @template T
|
|
568
576
|
* @overload
|
|
569
|
-
* @param {((state: T | undefined, ctx:
|
|
570
|
-
* @param {((state: T | undefined, ctx:
|
|
571
|
-
* @param {
|
|
572
|
-
* @returns {
|
|
577
|
+
* @param {((state: T | undefined, ctx: Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
|
|
578
|
+
* @param {((state: T | undefined, ctx: Context) => any)?} [exec]
|
|
579
|
+
* @param {Service.Options?} [options]
|
|
580
|
+
* @returns {StoreService<T>}
|
|
573
581
|
*/
|
|
574
582
|
/**
|
|
575
583
|
* @template T
|
|
576
|
-
* @param {((state: T | undefined, ctx:
|
|
577
|
-
* @param {((state: T | undefined, ctx:
|
|
578
|
-
* @param {
|
|
579
|
-
* @returns {
|
|
584
|
+
* @param {((state: T | undefined, ctx: Context, error?: unknown) => PromiseLike<void> | void) | Service.Options | null} [destroy]
|
|
585
|
+
* @param {((state: T | undefined, ctx: Context) => any) | Service.Options | null} [exec]
|
|
586
|
+
* @param {Service.Options?} [options]
|
|
587
|
+
* @returns {StoreService<T>}
|
|
580
588
|
*/
|
|
581
589
|
function storeService(destroy, exec, options) {
|
|
582
|
-
/** @type {
|
|
590
|
+
/** @type {StoreService<T>} */
|
|
583
591
|
const service = function (ctx) {
|
|
584
592
|
/** @type {T | undefined} */
|
|
585
593
|
let state;
|
|
@@ -616,16 +624,18 @@ function storeService(destroy, exec, options) {
|
|
|
616
624
|
return service;
|
|
617
625
|
}
|
|
618
626
|
|
|
627
|
+
/** @import { Handler } from './main/types' */
|
|
628
|
+
/** @import { Onionskin } from './onionskin.mjs' */
|
|
619
629
|
/**
|
|
620
630
|
* @callback Packer
|
|
621
|
-
* @param {
|
|
622
|
-
* @returns {
|
|
631
|
+
* @param {Handler} handler
|
|
632
|
+
* @returns {Handler}
|
|
623
633
|
*/
|
|
624
634
|
/** @type {Packer} */
|
|
625
635
|
const noop$1 = h => h;
|
|
626
636
|
/**
|
|
627
637
|
*
|
|
628
|
-
* @param {
|
|
638
|
+
* @param {Onionskin} onionskin
|
|
629
639
|
* @param {Packer} [packer]
|
|
630
640
|
* @returns {Packer}
|
|
631
641
|
*/
|
|
@@ -636,30 +646,33 @@ function packer(onionskin, packer = noop$1) {
|
|
|
636
646
|
};
|
|
637
647
|
}
|
|
638
648
|
|
|
649
|
+
/** @import { Context, FindHandler, Handler, Method, Params } from './main/types' */
|
|
650
|
+
/** @import { Onionskin } from './onionskin.mjs' */
|
|
651
|
+
|
|
639
652
|
/**
|
|
640
653
|
* @callback Guard
|
|
641
|
-
* @param {
|
|
642
|
-
* @returns {PromiseLike<boolean |
|
|
654
|
+
* @param {Context} ctx
|
|
655
|
+
* @returns {PromiseLike<boolean | Handler | void> | boolean | Handler | void}
|
|
643
656
|
*/
|
|
644
657
|
/**
|
|
645
|
-
* @typedef {[
|
|
658
|
+
* @typedef {[Handler | Router, Record<string | symbol, any>, string[]]} FindItem
|
|
646
659
|
*/
|
|
647
660
|
/**
|
|
648
661
|
* @callback Finder
|
|
649
662
|
* @this {Router}
|
|
650
|
-
* @param {
|
|
663
|
+
* @param {Method} method
|
|
651
664
|
* @param {string[]} path
|
|
652
|
-
* @param {
|
|
665
|
+
* @param {Context} ctx
|
|
653
666
|
* @returns {AsyncIterable<FindItem> | Iterable<FindItem>}
|
|
654
667
|
*/
|
|
655
668
|
|
|
656
669
|
/**
|
|
657
670
|
*
|
|
658
671
|
* @param {Set<Guard>} guards
|
|
659
|
-
* @param {
|
|
672
|
+
* @param {Context} ctx
|
|
660
673
|
* @param {(v: any) => void} setParams
|
|
661
674
|
* @param {object} params
|
|
662
|
-
* @returns {Promise<boolean |
|
|
675
|
+
* @returns {Promise<boolean | Handler>}
|
|
663
676
|
*/
|
|
664
677
|
async function execGuard(guards, ctx, setParams, params) {
|
|
665
678
|
if (!guards.size) { return true; }
|
|
@@ -678,12 +691,12 @@ async function execGuard(guards, ctx, setParams, params) {
|
|
|
678
691
|
|
|
679
692
|
/**
|
|
680
693
|
*
|
|
681
|
-
* @param {Router |
|
|
694
|
+
* @param {Router | Handler} route
|
|
682
695
|
* @param {string[]} path
|
|
683
|
-
* @param {
|
|
684
|
-
* @param {(v:
|
|
685
|
-
* @param {
|
|
686
|
-
* @returns {Promise<
|
|
696
|
+
* @param {Context} ctx
|
|
697
|
+
* @param {(v: Params) => void} setParams
|
|
698
|
+
* @param {Params} params
|
|
699
|
+
* @returns {Promise<Handler | null>}
|
|
687
700
|
*/
|
|
688
701
|
async function find(route, path, ctx, setParams, params) {
|
|
689
702
|
if (!(route instanceof Router)) {
|
|
@@ -722,16 +735,16 @@ class Router {
|
|
|
722
735
|
disabled = false;
|
|
723
736
|
/**
|
|
724
737
|
* @abstract
|
|
725
|
-
* @param {
|
|
738
|
+
* @param {Method} method
|
|
726
739
|
* @param {string[]} path
|
|
727
|
-
* @param {
|
|
740
|
+
* @param {Context} ctx
|
|
728
741
|
* @returns {AsyncIterable<FindItem> | Iterable<FindItem>}
|
|
729
742
|
*/
|
|
730
743
|
find(method, path, ctx) { return []; }
|
|
731
744
|
/**
|
|
732
745
|
*
|
|
733
746
|
* @param {Router[]} routers
|
|
734
|
-
* @returns {
|
|
747
|
+
* @returns {FindHandler}
|
|
735
748
|
*/
|
|
736
749
|
static make(routers) {
|
|
737
750
|
return async (ctx, setParams) => {
|
|
@@ -759,19 +772,21 @@ class Router {
|
|
|
759
772
|
guards = new Set();
|
|
760
773
|
/**
|
|
761
774
|
*
|
|
762
|
-
* @param {
|
|
763
|
-
* @returns {
|
|
775
|
+
* @param {Handler} h
|
|
776
|
+
* @returns {Handler}
|
|
764
777
|
*/
|
|
765
778
|
__onionskin = (h) => h;
|
|
766
|
-
/** @param {
|
|
779
|
+
/** @param {Onionskin} os */
|
|
767
780
|
onionskin(os) { this.__onionskin = packer(os, this.__onionskin); }
|
|
768
781
|
}
|
|
769
782
|
|
|
783
|
+
/** @import { Match } from './index.mjs' */
|
|
784
|
+
/** @import { Params } from '../main/types.js' */
|
|
770
785
|
/**
|
|
771
786
|
* @typedef {object} Pattern
|
|
772
|
-
* @property {string} name
|
|
773
|
-
* @property {boolean} optional
|
|
774
|
-
* @property {boolean} many
|
|
787
|
+
* @property {string | symbol} name
|
|
788
|
+
* @property {boolean} [optional]
|
|
789
|
+
* @property {boolean} [many]
|
|
775
790
|
* @property {RegExp} pattern
|
|
776
791
|
*/
|
|
777
792
|
|
|
@@ -842,7 +857,7 @@ function parse(p) {
|
|
|
842
857
|
* @returns {[Record<string, string | string[]>, string[]] | undefined}
|
|
843
858
|
*/
|
|
844
859
|
function exec(match, path, end) {
|
|
845
|
-
/** @type {
|
|
860
|
+
/** @type {Params} */
|
|
846
861
|
const params = {};
|
|
847
862
|
for (let i = 0; i < match.length; i++) {
|
|
848
863
|
const m = match[i];
|
|
@@ -865,38 +880,102 @@ function exec(match, path, end) {
|
|
|
865
880
|
return [params, []];
|
|
866
881
|
|
|
867
882
|
}
|
|
883
|
+
/**
|
|
884
|
+
*
|
|
885
|
+
* @param {string[]} paths
|
|
886
|
+
* @param {*} values
|
|
887
|
+
* @returns {Iterable<[string[], any[]]>}
|
|
888
|
+
*/
|
|
889
|
+
function* split([...paths], [...values]) {
|
|
890
|
+
let els = (paths.shift() || '').split('/');
|
|
891
|
+
let list = [els.pop() || ''];
|
|
892
|
+
for (const f of els) {
|
|
893
|
+
yield [[f], []];
|
|
894
|
+
}
|
|
895
|
+
for (const path of paths) {
|
|
896
|
+
const els = path.split('/');
|
|
897
|
+
if (els.length <= 1) {
|
|
898
|
+
list.push(path);
|
|
899
|
+
continue;
|
|
900
|
+
}
|
|
901
|
+
const pathValue = values.splice(0, list.length);
|
|
902
|
+
list.push(els.shift() || '');
|
|
903
|
+
yield [list, pathValue];
|
|
904
|
+
list = [els.pop() || ''];
|
|
905
|
+
for (const f of els) {
|
|
906
|
+
yield [[f], []];
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
yield [list, values];
|
|
910
|
+
}
|
|
868
911
|
/**
|
|
869
912
|
*
|
|
870
|
-
* @param {string} path
|
|
913
|
+
* @param {string | [string[], any[]]} path
|
|
871
914
|
* @param {boolean} end
|
|
872
|
-
* @returns {
|
|
915
|
+
* @returns {Match | undefined}
|
|
873
916
|
*/
|
|
874
917
|
function toMatch(path, end) {
|
|
875
918
|
/** @type {(Pattern | string)[]} */
|
|
876
919
|
const list = [];
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
920
|
+
if (typeof path === 'string') {
|
|
921
|
+
for (const p of path.split('/')) {
|
|
922
|
+
if (!p || /^\.+$/.test(p)) { continue; }
|
|
923
|
+
list.push(parse(p));
|
|
924
|
+
}
|
|
925
|
+
} else {
|
|
926
|
+
for (const [paths, values] of split(...path)) {
|
|
927
|
+
if (paths.length === 2 && !paths[0]) {
|
|
928
|
+
const modifier = paths[1];
|
|
929
|
+
if (['', '?', '+', '*'].includes(modifier)) {
|
|
930
|
+
const value = values[0];
|
|
931
|
+
if (typeof value === 'symbol') {
|
|
932
|
+
list.push({
|
|
933
|
+
name: value, pattern: /^.*$/,
|
|
934
|
+
optional: modifier === '?' || modifier === '*',
|
|
935
|
+
many: modifier === '+' || modifier === '*',
|
|
936
|
+
});
|
|
937
|
+
continue;
|
|
938
|
+
} else if (value && typeof value === 'object') {
|
|
939
|
+
const {name, pattern} = value;
|
|
940
|
+
if (typeof name === 'symbol') {
|
|
941
|
+
list.push({
|
|
942
|
+
name, pattern: pattern instanceof RegExp ? pattern : /^.*$/,
|
|
943
|
+
optional: modifier === '?' || modifier === '*',
|
|
944
|
+
many: modifier === '+' || modifier === '*',
|
|
945
|
+
});
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
const last = paths.pop() || '';
|
|
952
|
+
const strings = paths.map((v, i) => [v, values[i]]).flat();
|
|
953
|
+
strings.push(last);
|
|
954
|
+
const p = strings.join('');
|
|
955
|
+
if (!p || /^\.+$/.test(p)) { continue; }
|
|
956
|
+
list.push(parse(p));
|
|
957
|
+
continue;
|
|
958
|
+
}
|
|
959
|
+
|
|
880
960
|
}
|
|
881
961
|
if (!list.length) { return; }
|
|
882
962
|
return path => exec(list, path, end);
|
|
883
963
|
}
|
|
884
964
|
|
|
965
|
+
/** @import { Handler, Method } from '../main/types' */
|
|
966
|
+
/** @import { Binder, Match, Route, RouterRoute } from './index.mjs' */
|
|
967
|
+
|
|
885
968
|
/**
|
|
886
969
|
*
|
|
887
|
-
* @param {(
|
|
888
|
-
* @param {
|
|
889
|
-
* @param {
|
|
890
|
-
* @param {
|
|
970
|
+
* @param {(Route | RouterRoute)[]} routes
|
|
971
|
+
* @param {Set<Method>} methods
|
|
972
|
+
* @param {Match | undefined} match
|
|
973
|
+
* @param {Handler[]} handlers
|
|
891
974
|
* @returns {() => void}
|
|
892
975
|
*/
|
|
893
|
-
function bind(routes, methods,
|
|
894
|
-
/** @type {
|
|
895
|
-
const route = {
|
|
896
|
-
match: toMatch(path || '', true),
|
|
897
|
-
methods: new Set(methods),
|
|
898
|
-
handler,
|
|
899
|
-
};
|
|
976
|
+
function bind(routes, methods, match, handlers) {
|
|
977
|
+
/** @type {Route} */
|
|
978
|
+
const route = { match, methods, handler: ctx => runHandles(ctx, handlers) };
|
|
900
979
|
routes.push(route);
|
|
901
980
|
let removed = false;
|
|
902
981
|
return () => {
|
|
@@ -907,43 +986,49 @@ function bind(routes, methods, path, handler) {
|
|
|
907
986
|
routes.splice(index, 1);
|
|
908
987
|
};
|
|
909
988
|
}
|
|
910
|
-
/** @type {(v: any) => v is
|
|
989
|
+
/** @type {(v: any) => v is Handler} */
|
|
911
990
|
const findHandler = v => typeof v === 'function';
|
|
912
991
|
/**
|
|
913
992
|
*
|
|
914
|
-
* @param {(
|
|
915
|
-
* @param {
|
|
993
|
+
* @param {(Route | RouterRoute)[]} routes
|
|
994
|
+
* @param {Iterable<Method>} methods
|
|
916
995
|
* @param {any[]} p
|
|
917
|
-
* @returns {
|
|
996
|
+
* @returns {Binder | (() => void)}
|
|
918
997
|
*/
|
|
919
998
|
function verb(routes, methods, p) {
|
|
999
|
+
const methodSet = new Set(methods);
|
|
920
1000
|
if (!p.length) {
|
|
921
|
-
|
|
1001
|
+
const match = undefined;
|
|
1002
|
+
/** @type {Binder} */
|
|
1003
|
+
return (...handlers) => bind(routes, methodSet, match, handlers);
|
|
922
1004
|
}
|
|
923
|
-
const [
|
|
924
|
-
if (
|
|
925
|
-
const
|
|
926
|
-
|
|
1005
|
+
const [path] = p;
|
|
1006
|
+
if (path && typeof path === 'object') {
|
|
1007
|
+
const match = toMatch([path, p.slice(1)], true);
|
|
1008
|
+
/** @type {Binder} */
|
|
1009
|
+
return (...handlers) => bind(routes, methodSet, match, handlers);
|
|
927
1010
|
}
|
|
928
|
-
const
|
|
929
|
-
const
|
|
930
|
-
if (!
|
|
931
|
-
|
|
1011
|
+
const match = toMatch(typeof path === 'string' ? path : '', true);
|
|
1012
|
+
const handlers = p.filter(findHandler);
|
|
1013
|
+
if (!handlers.length) {
|
|
1014
|
+
/** @type {Binder} */
|
|
1015
|
+
return (...handlers) => bind(routes, methodSet, match, handlers);
|
|
932
1016
|
}
|
|
933
|
-
return bind(routes,
|
|
1017
|
+
return bind(routes, methodSet, match, handlers);
|
|
934
1018
|
}
|
|
935
1019
|
|
|
1020
|
+
/** @import { Method } from '../main/types' */
|
|
936
1021
|
const methods = new Set(['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS']);
|
|
937
1022
|
/**
|
|
938
1023
|
*
|
|
939
1024
|
* @param {any} v
|
|
940
|
-
* @returns {v is
|
|
1025
|
+
* @returns {v is Method}
|
|
941
1026
|
*/
|
|
942
1027
|
function isMethod(v) { return methods.has(v); }
|
|
943
1028
|
/**
|
|
944
1029
|
*
|
|
945
|
-
* @param {
|
|
946
|
-
* @returns {
|
|
1030
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} [methods]
|
|
1031
|
+
* @returns {Method[]}
|
|
947
1032
|
*/
|
|
948
1033
|
function getMethods(methods) {
|
|
949
1034
|
if (!methods) {
|
|
@@ -957,25 +1042,24 @@ function getMethods(methods) {
|
|
|
957
1042
|
.filter(isMethod);
|
|
958
1043
|
}
|
|
959
1044
|
|
|
1045
|
+
/** @import { Context, Handler, Method, Params } from '../main/types' */
|
|
1046
|
+
/** @import { Finder, FindItem } from '../Router.mjs' */
|
|
1047
|
+
|
|
960
1048
|
/**
|
|
961
1049
|
* @callback Match
|
|
962
1050
|
* @param {string[]} paths
|
|
963
|
-
* @returns {[
|
|
1051
|
+
* @returns {[Params, string[]] | undefined}
|
|
964
1052
|
*/
|
|
965
1053
|
|
|
966
|
-
/**
|
|
967
|
-
* @callback Binder
|
|
968
|
-
* @param {import('../main/types').Handler} handler
|
|
969
|
-
* @returns {() => void}
|
|
970
|
-
*/
|
|
1054
|
+
/** @typedef {(handler: Handler, ...handlers: Handler[]) => () => void} Binder */
|
|
971
1055
|
|
|
972
1056
|
/**
|
|
973
1057
|
* @typedef {object} Route
|
|
974
1058
|
* @property {Match} [match] 路径匹配
|
|
975
1059
|
* @property {null} [router]
|
|
976
1060
|
* @property {string} [plugin] 所属插件
|
|
977
|
-
* @property {
|
|
978
|
-
* @property {Set<
|
|
1061
|
+
* @property {Handler} handler 处理函数
|
|
1062
|
+
* @property {Set<Method>} methods 方法列表
|
|
979
1063
|
*/
|
|
980
1064
|
|
|
981
1065
|
/**
|
|
@@ -986,16 +1070,16 @@ function getMethods(methods) {
|
|
|
986
1070
|
|
|
987
1071
|
|
|
988
1072
|
/**
|
|
989
|
-
* @template {Router |
|
|
1073
|
+
* @template {Router | Finder} [T=ApiRouter]
|
|
990
1074
|
* @callback RouteBinder
|
|
991
1075
|
* @param {T} [router] 要注册的子路由或子路由的 Finder
|
|
992
|
-
* @returns {T extends
|
|
1076
|
+
* @returns {T extends Finder ? Router : T}
|
|
993
1077
|
*/
|
|
994
1078
|
/**
|
|
995
1079
|
*
|
|
996
1080
|
* @param {(Route | RouterRoute)[]} routes
|
|
997
|
-
* @param {string} path
|
|
998
|
-
* @param {Router |
|
|
1081
|
+
* @param {string | [string[], any[]]} path
|
|
1082
|
+
* @param {Router | Finder} [r]
|
|
999
1083
|
* @returns {Router}
|
|
1000
1084
|
*/
|
|
1001
1085
|
function bindRouter(routes, path, r) {
|
|
@@ -1010,18 +1094,18 @@ class ApiRouter extends Router {
|
|
|
1010
1094
|
#routes = [];
|
|
1011
1095
|
/**
|
|
1012
1096
|
* 添加子路由
|
|
1013
|
-
* @template {Router |
|
|
1097
|
+
* @template {Router | Finder} [T=ApiRouter]
|
|
1014
1098
|
* @overload
|
|
1015
1099
|
* @param {T} [router] 要注册的子路由或子路由的 Finder
|
|
1016
|
-
* @returns {T extends
|
|
1100
|
+
* @returns {T extends Finder ? Router : T}
|
|
1017
1101
|
*/
|
|
1018
1102
|
/**
|
|
1019
1103
|
* 添加子路由
|
|
1020
|
-
* @template {Router |
|
|
1104
|
+
* @template {Router | Finder} [T=ApiRouter]
|
|
1021
1105
|
* @overload
|
|
1022
1106
|
* @param {string} path 要注册的路径
|
|
1023
1107
|
* @param {T} [router] 要注册的子路由或子路由的 Finder
|
|
1024
|
-
* @returns {T extends
|
|
1108
|
+
* @returns {T extends Finder ? Router : T}
|
|
1025
1109
|
*/
|
|
1026
1110
|
/**
|
|
1027
1111
|
* 添加子路由
|
|
@@ -1038,12 +1122,11 @@ class ApiRouter extends Router {
|
|
|
1038
1122
|
route(...p) {
|
|
1039
1123
|
const [a] = p;
|
|
1040
1124
|
if (a && typeof a === 'object' && !(a instanceof Router)) {
|
|
1041
|
-
const path = String.raw(a, ...p.slice(1));
|
|
1042
1125
|
/**
|
|
1043
|
-
* @param {
|
|
1126
|
+
* @param { Finder | Router} [r];
|
|
1044
1127
|
* @returns {any}
|
|
1045
1128
|
*/
|
|
1046
|
-
return r => bindRouter(this.#routes,
|
|
1129
|
+
return r => bindRouter(this.#routes, [a, p.slice(1)], r);
|
|
1047
1130
|
}
|
|
1048
1131
|
const path = typeof a === 'string' ? a : '';
|
|
1049
1132
|
const r = typeof a === 'string' ? p[1] : a;
|
|
@@ -1051,10 +1134,10 @@ class ApiRouter extends Router {
|
|
|
1051
1134
|
}
|
|
1052
1135
|
/**
|
|
1053
1136
|
*
|
|
1054
|
-
* @param {
|
|
1137
|
+
* @param {Method} method
|
|
1055
1138
|
* @param {string[]} path
|
|
1056
|
-
* @param {
|
|
1057
|
-
* @returns {Iterable<
|
|
1139
|
+
* @param {Context} ctx
|
|
1140
|
+
* @returns {Iterable<FindItem>}
|
|
1058
1141
|
*/
|
|
1059
1142
|
*find(method, path, ctx) {
|
|
1060
1143
|
for (const route of Array.from(this.#routes)) {
|
|
@@ -1075,29 +1158,29 @@ class ApiRouter extends Router {
|
|
|
1075
1158
|
/**
|
|
1076
1159
|
* 注册处理函数
|
|
1077
1160
|
* @overload
|
|
1078
|
-
* @param {
|
|
1079
|
-
* @param {
|
|
1161
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
|
|
1162
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1080
1163
|
* @returns {() => void}
|
|
1081
1164
|
*/
|
|
1082
1165
|
/**
|
|
1083
1166
|
* 注册处理函数
|
|
1084
1167
|
* @overload
|
|
1085
|
-
* @param {
|
|
1168
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
|
|
1086
1169
|
* @param {string} path 要注册的路径
|
|
1087
|
-
* @param {
|
|
1170
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1088
1171
|
* @returns {() => void}
|
|
1089
1172
|
*/
|
|
1090
1173
|
/**
|
|
1091
1174
|
* 注册处理函数
|
|
1092
1175
|
* @overload
|
|
1093
|
-
* @param {
|
|
1176
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
|
|
1094
1177
|
* @param {string} path 要注册的路径
|
|
1095
1178
|
* @returns {Binder}
|
|
1096
1179
|
*/
|
|
1097
1180
|
/**
|
|
1098
|
-
* @param {
|
|
1099
|
-
* @param {string|
|
|
1100
|
-
* @param {
|
|
1181
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} methods
|
|
1182
|
+
* @param {string| Handler} [path]
|
|
1183
|
+
* @param {Handler} [handler]
|
|
1101
1184
|
* @returns {Binder | (() => void)}
|
|
1102
1185
|
*/
|
|
1103
1186
|
verb(methods, path, handler) {
|
|
@@ -1108,14 +1191,14 @@ class ApiRouter extends Router {
|
|
|
1108
1191
|
/**
|
|
1109
1192
|
* 注册 HTTP GET/POST/PUT/DELETE 处理函数
|
|
1110
1193
|
* @overload
|
|
1111
|
-
* @param {
|
|
1194
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1112
1195
|
* @returns {() => void}
|
|
1113
1196
|
*/
|
|
1114
1197
|
/**
|
|
1115
1198
|
* 注册处理函数
|
|
1116
1199
|
* @overload
|
|
1117
1200
|
* @param {string} path 要注册的路径
|
|
1118
|
-
* @param {
|
|
1201
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1119
1202
|
* @returns {() => void}
|
|
1120
1203
|
*/
|
|
1121
1204
|
/**
|
|
@@ -1141,14 +1224,14 @@ class ApiRouter extends Router {
|
|
|
1141
1224
|
/**
|
|
1142
1225
|
* 注册 HTTP GET 处理函数
|
|
1143
1226
|
* @overload
|
|
1144
|
-
* @param {
|
|
1227
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1145
1228
|
* @returns {() => void}
|
|
1146
1229
|
*/
|
|
1147
1230
|
/**
|
|
1148
1231
|
* 注册 HTTP GET 处理函数
|
|
1149
1232
|
* @overload
|
|
1150
1233
|
* @param {string} path 要注册的路径
|
|
1151
|
-
* @param {
|
|
1234
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1152
1235
|
* @returns {() => void}
|
|
1153
1236
|
*/
|
|
1154
1237
|
/**
|
|
@@ -1172,14 +1255,14 @@ class ApiRouter extends Router {
|
|
|
1172
1255
|
/**
|
|
1173
1256
|
* 注册 HTTP POST 处理函数
|
|
1174
1257
|
* @overload
|
|
1175
|
-
* @param {
|
|
1258
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1176
1259
|
* @returns {() => void}
|
|
1177
1260
|
*/
|
|
1178
1261
|
/**
|
|
1179
1262
|
* 注册 HTTP POST 处理函数
|
|
1180
1263
|
* @overload
|
|
1181
1264
|
* @param {string} path 要注册的路径
|
|
1182
|
-
* @param {
|
|
1265
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1183
1266
|
* @returns {() => void}
|
|
1184
1267
|
*/
|
|
1185
1268
|
/**
|
|
@@ -1203,14 +1286,14 @@ class ApiRouter extends Router {
|
|
|
1203
1286
|
/**
|
|
1204
1287
|
* 注册 HTTP PUT 处理函数
|
|
1205
1288
|
* @overload
|
|
1206
|
-
* @param {
|
|
1289
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1207
1290
|
* @returns {() => void}
|
|
1208
1291
|
*/
|
|
1209
1292
|
/**
|
|
1210
1293
|
* 注册 HTTP PUT 处理函数
|
|
1211
1294
|
* @overload
|
|
1212
1295
|
* @param {string} path 要注册的路径
|
|
1213
|
-
* @param {
|
|
1296
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1214
1297
|
* @returns {() => void}
|
|
1215
1298
|
*/
|
|
1216
1299
|
/**
|
|
@@ -1234,14 +1317,14 @@ class ApiRouter extends Router {
|
|
|
1234
1317
|
/**
|
|
1235
1318
|
* 注册 HTTP DELETE 处理函数
|
|
1236
1319
|
* @overload
|
|
1237
|
-
* @param {
|
|
1320
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1238
1321
|
* @returns {() => void}
|
|
1239
1322
|
*/
|
|
1240
1323
|
/**
|
|
1241
1324
|
* 注册 HTTP DELETE 处理函数
|
|
1242
1325
|
* @overload
|
|
1243
1326
|
* @param {string} path 要注册的路径
|
|
1244
|
-
* @param {
|
|
1327
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1245
1328
|
* @returns {() => void}
|
|
1246
1329
|
*/
|
|
1247
1330
|
/**
|
|
@@ -1265,14 +1348,14 @@ class ApiRouter extends Router {
|
|
|
1265
1348
|
/**
|
|
1266
1349
|
* 注册 HTTP HEAD 处理函数
|
|
1267
1350
|
* @overload
|
|
1268
|
-
* @param {
|
|
1351
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1269
1352
|
* @returns {() => void}
|
|
1270
1353
|
*/
|
|
1271
1354
|
/**
|
|
1272
1355
|
* 注册 HTTP HEAD 处理函数
|
|
1273
1356
|
* @overload
|
|
1274
1357
|
* @param {string} path 要注册的路径
|
|
1275
|
-
* @param {
|
|
1358
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1276
1359
|
* @returns {() => void}
|
|
1277
1360
|
*/
|
|
1278
1361
|
/**
|
|
@@ -1296,14 +1379,14 @@ class ApiRouter extends Router {
|
|
|
1296
1379
|
/**
|
|
1297
1380
|
* 注册 HTTP OPTIONS 处理函数
|
|
1298
1381
|
* @overload
|
|
1299
|
-
* @param {
|
|
1382
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1300
1383
|
* @returns {() => void}
|
|
1301
1384
|
*/
|
|
1302
1385
|
/**
|
|
1303
1386
|
* 注册 HTTP OPTIONS 处理函数
|
|
1304
1387
|
* @overload
|
|
1305
1388
|
* @param {string} path 要注册的路径
|
|
1306
|
-
* @param {
|
|
1389
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1307
1390
|
* @returns {() => void}
|
|
1308
1391
|
*/
|
|
1309
1392
|
/**
|
|
@@ -1349,21 +1432,22 @@ function createFetch(run, notFound) {
|
|
|
1349
1432
|
};
|
|
1350
1433
|
}
|
|
1351
1434
|
|
|
1435
|
+
/** @import { Context, Handler, HandlerResult } from './main/types' */
|
|
1352
1436
|
/**
|
|
1353
1437
|
* @callback Onionskin
|
|
1354
|
-
* @param {
|
|
1355
|
-
* @param {() => Promise<
|
|
1356
|
-
* @returns {PromiseLike<
|
|
1438
|
+
* @param {Context} ctx
|
|
1439
|
+
* @param {() => Promise<HandlerResult>} next
|
|
1440
|
+
* @returns {PromiseLike<HandlerResult> | HandlerResult}
|
|
1357
1441
|
*/
|
|
1358
1442
|
|
|
1359
1443
|
const noop = () => {};
|
|
1360
1444
|
/**
|
|
1361
1445
|
*
|
|
1362
1446
|
* @param {...(Onionskin | Onionskin[])} handlers
|
|
1363
|
-
* @returns {
|
|
1447
|
+
* @returns {Handler}
|
|
1364
1448
|
*/
|
|
1365
1449
|
function onionskin(...handlers) {
|
|
1366
|
-
/** @type {
|
|
1450
|
+
/** @type {Handler} */
|
|
1367
1451
|
let handler = noop;
|
|
1368
1452
|
for (const os of handlers.flat()) {
|
|
1369
1453
|
const currentHandler = handler;
|
|
@@ -1372,7 +1456,44 @@ function onionskin(...handlers) {
|
|
|
1372
1456
|
return handler;
|
|
1373
1457
|
}
|
|
1374
1458
|
|
|
1459
|
+
/** @import { Context } from './main/types.js' */
|
|
1460
|
+
class Param {
|
|
1461
|
+
#symbol = Symbol();
|
|
1462
|
+
get name() { return this.#symbol}
|
|
1463
|
+
#pattern
|
|
1464
|
+
get pattern() { return this.#pattern; }
|
|
1465
|
+
/**
|
|
1466
|
+
*
|
|
1467
|
+
* @param {RegExp?} [pattern]
|
|
1468
|
+
*/
|
|
1469
|
+
constructor(pattern) {
|
|
1470
|
+
this.#pattern = pattern;
|
|
1471
|
+
}
|
|
1472
|
+
/**
|
|
1473
|
+
*
|
|
1474
|
+
* @param {Context} ctx
|
|
1475
|
+
* @returns {string?}
|
|
1476
|
+
*/
|
|
1477
|
+
param(ctx) {
|
|
1478
|
+
const param = ctx.params[this.#symbol];
|
|
1479
|
+
if (Array.isArray(param)) { return param[0] ?? null; }
|
|
1480
|
+
return param ?? null;
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
*
|
|
1484
|
+
* @param {Context} ctx
|
|
1485
|
+
* @returns {string[]?}
|
|
1486
|
+
*/
|
|
1487
|
+
params(ctx) {
|
|
1488
|
+
const param = ctx.params[this.#symbol];
|
|
1489
|
+
if (typeof param === 'string') { return [param]; }
|
|
1490
|
+
if (Array.isArray(param)) { return param; }
|
|
1491
|
+
return null;
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1375
1495
|
exports.ApiRouter = ApiRouter;
|
|
1496
|
+
exports.Param = Param;
|
|
1376
1497
|
exports.Router = Router;
|
|
1377
1498
|
exports.createFetch = createFetch;
|
|
1378
1499
|
exports.main = main;
|