k99 0.6.1 → 0.7.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 +301 -181
- package/index.d.ts +76 -76
- package/index.js +301 -181
- package/index.min.js +2 -2
- package/index.min.mjs +2 -2
- package/index.mjs +301 -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.0
|
|
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,101 @@ 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
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
const last = paths.pop() || '';
|
|
951
|
+
const strings = paths.map((v, i) => [v, values[i]]).flat();
|
|
952
|
+
strings.push(last);
|
|
953
|
+
const p = strings.join('');
|
|
954
|
+
if (!p || /^\.+$/.test(p)) { continue; }
|
|
955
|
+
list.push(parse(p));
|
|
956
|
+
continue;
|
|
957
|
+
}
|
|
958
|
+
|
|
880
959
|
}
|
|
881
960
|
if (!list.length) { return; }
|
|
882
961
|
return path => exec(list, path, end);
|
|
883
962
|
}
|
|
884
963
|
|
|
964
|
+
/** @import { Handler, Method } from '../main/types' */
|
|
965
|
+
/** @import { Binder, Match, Route, RouterRoute } from './index.mjs' */
|
|
966
|
+
|
|
885
967
|
/**
|
|
886
968
|
*
|
|
887
|
-
* @param {(
|
|
888
|
-
* @param {
|
|
889
|
-
* @param {
|
|
890
|
-
* @param {
|
|
969
|
+
* @param {(Route | RouterRoute)[]} routes
|
|
970
|
+
* @param {Set<Method>} methods
|
|
971
|
+
* @param {Match | undefined} match
|
|
972
|
+
* @param {Handler[]} handlers
|
|
891
973
|
* @returns {() => void}
|
|
892
974
|
*/
|
|
893
|
-
function bind(routes, methods,
|
|
894
|
-
/** @type {
|
|
895
|
-
const route = {
|
|
896
|
-
match: toMatch(path || '', true),
|
|
897
|
-
methods: new Set(methods),
|
|
898
|
-
handler,
|
|
899
|
-
};
|
|
975
|
+
function bind(routes, methods, match, handlers) {
|
|
976
|
+
/** @type {Route} */
|
|
977
|
+
const route = { match, methods, handler: ctx => runHandles(ctx, handlers) };
|
|
900
978
|
routes.push(route);
|
|
901
979
|
let removed = false;
|
|
902
980
|
return () => {
|
|
@@ -907,43 +985,49 @@ function bind(routes, methods, path, handler) {
|
|
|
907
985
|
routes.splice(index, 1);
|
|
908
986
|
};
|
|
909
987
|
}
|
|
910
|
-
/** @type {(v: any) => v is
|
|
988
|
+
/** @type {(v: any) => v is Handler} */
|
|
911
989
|
const findHandler = v => typeof v === 'function';
|
|
912
990
|
/**
|
|
913
991
|
*
|
|
914
|
-
* @param {(
|
|
915
|
-
* @param {
|
|
992
|
+
* @param {(Route | RouterRoute)[]} routes
|
|
993
|
+
* @param {Iterable<Method>} methods
|
|
916
994
|
* @param {any[]} p
|
|
917
|
-
* @returns {
|
|
995
|
+
* @returns {Binder | (() => void)}
|
|
918
996
|
*/
|
|
919
997
|
function verb(routes, methods, p) {
|
|
998
|
+
const methodSet = new Set(methods);
|
|
920
999
|
if (!p.length) {
|
|
921
|
-
|
|
1000
|
+
const match = undefined;
|
|
1001
|
+
/** @type {Binder} */
|
|
1002
|
+
return (...handlers) => bind(routes, methodSet, match, handlers);
|
|
922
1003
|
}
|
|
923
|
-
const [
|
|
924
|
-
if (
|
|
925
|
-
const
|
|
926
|
-
|
|
1004
|
+
const [path] = p;
|
|
1005
|
+
if (path && typeof path === 'object') {
|
|
1006
|
+
const match = toMatch([path, p.slice(1)], true);
|
|
1007
|
+
/** @type {Binder} */
|
|
1008
|
+
return (...handlers) => bind(routes, methodSet, match, handlers);
|
|
927
1009
|
}
|
|
928
|
-
const
|
|
929
|
-
const
|
|
930
|
-
if (!
|
|
931
|
-
|
|
1010
|
+
const match = toMatch(typeof path === 'string' ? path : '', true);
|
|
1011
|
+
const handlers = p.filter(findHandler);
|
|
1012
|
+
if (!handlers.length) {
|
|
1013
|
+
/** @type {Binder} */
|
|
1014
|
+
return (...handlers) => bind(routes, methodSet, match, handlers);
|
|
932
1015
|
}
|
|
933
|
-
return bind(routes,
|
|
1016
|
+
return bind(routes, methodSet, match, handlers);
|
|
934
1017
|
}
|
|
935
1018
|
|
|
1019
|
+
/** @import { Method } from '../main/types' */
|
|
936
1020
|
const methods = new Set(['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS']);
|
|
937
1021
|
/**
|
|
938
1022
|
*
|
|
939
1023
|
* @param {any} v
|
|
940
|
-
* @returns {v is
|
|
1024
|
+
* @returns {v is Method}
|
|
941
1025
|
*/
|
|
942
1026
|
function isMethod(v) { return methods.has(v); }
|
|
943
1027
|
/**
|
|
944
1028
|
*
|
|
945
|
-
* @param {
|
|
946
|
-
* @returns {
|
|
1029
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} [methods]
|
|
1030
|
+
* @returns {Method[]}
|
|
947
1031
|
*/
|
|
948
1032
|
function getMethods(methods) {
|
|
949
1033
|
if (!methods) {
|
|
@@ -957,25 +1041,24 @@ function getMethods(methods) {
|
|
|
957
1041
|
.filter(isMethod);
|
|
958
1042
|
}
|
|
959
1043
|
|
|
1044
|
+
/** @import { Context, Handler, Method, Params } from '../main/types' */
|
|
1045
|
+
/** @import { Finder, FindItem } from '../Router.mjs' */
|
|
1046
|
+
|
|
960
1047
|
/**
|
|
961
1048
|
* @callback Match
|
|
962
1049
|
* @param {string[]} paths
|
|
963
|
-
* @returns {[
|
|
1050
|
+
* @returns {[Params, string[]] | undefined}
|
|
964
1051
|
*/
|
|
965
1052
|
|
|
966
|
-
/**
|
|
967
|
-
* @callback Binder
|
|
968
|
-
* @param {import('../main/types').Handler} handler
|
|
969
|
-
* @returns {() => void}
|
|
970
|
-
*/
|
|
1053
|
+
/** @typedef {(handler: Handler, ...handlers: Handler[]) => () => void} Binder */
|
|
971
1054
|
|
|
972
1055
|
/**
|
|
973
1056
|
* @typedef {object} Route
|
|
974
1057
|
* @property {Match} [match] 路径匹配
|
|
975
1058
|
* @property {null} [router]
|
|
976
1059
|
* @property {string} [plugin] 所属插件
|
|
977
|
-
* @property {
|
|
978
|
-
* @property {Set<
|
|
1060
|
+
* @property {Handler} handler 处理函数
|
|
1061
|
+
* @property {Set<Method>} methods 方法列表
|
|
979
1062
|
*/
|
|
980
1063
|
|
|
981
1064
|
/**
|
|
@@ -986,16 +1069,16 @@ function getMethods(methods) {
|
|
|
986
1069
|
|
|
987
1070
|
|
|
988
1071
|
/**
|
|
989
|
-
* @template {Router |
|
|
1072
|
+
* @template {Router | Finder} [T=ApiRouter]
|
|
990
1073
|
* @callback RouteBinder
|
|
991
1074
|
* @param {T} [router] 要注册的子路由或子路由的 Finder
|
|
992
|
-
* @returns {T extends
|
|
1075
|
+
* @returns {T extends Finder ? Router : T}
|
|
993
1076
|
*/
|
|
994
1077
|
/**
|
|
995
1078
|
*
|
|
996
1079
|
* @param {(Route | RouterRoute)[]} routes
|
|
997
|
-
* @param {string} path
|
|
998
|
-
* @param {Router |
|
|
1080
|
+
* @param {string | [string[], any[]]} path
|
|
1081
|
+
* @param {Router | Finder} [r]
|
|
999
1082
|
* @returns {Router}
|
|
1000
1083
|
*/
|
|
1001
1084
|
function bindRouter(routes, path, r) {
|
|
@@ -1010,18 +1093,18 @@ class ApiRouter extends Router {
|
|
|
1010
1093
|
#routes = [];
|
|
1011
1094
|
/**
|
|
1012
1095
|
* 添加子路由
|
|
1013
|
-
* @template {Router |
|
|
1096
|
+
* @template {Router | Finder} [T=ApiRouter]
|
|
1014
1097
|
* @overload
|
|
1015
1098
|
* @param {T} [router] 要注册的子路由或子路由的 Finder
|
|
1016
|
-
* @returns {T extends
|
|
1099
|
+
* @returns {T extends Finder ? Router : T}
|
|
1017
1100
|
*/
|
|
1018
1101
|
/**
|
|
1019
1102
|
* 添加子路由
|
|
1020
|
-
* @template {Router |
|
|
1103
|
+
* @template {Router | Finder} [T=ApiRouter]
|
|
1021
1104
|
* @overload
|
|
1022
1105
|
* @param {string} path 要注册的路径
|
|
1023
1106
|
* @param {T} [router] 要注册的子路由或子路由的 Finder
|
|
1024
|
-
* @returns {T extends
|
|
1107
|
+
* @returns {T extends Finder ? Router : T}
|
|
1025
1108
|
*/
|
|
1026
1109
|
/**
|
|
1027
1110
|
* 添加子路由
|
|
@@ -1038,12 +1121,11 @@ class ApiRouter extends Router {
|
|
|
1038
1121
|
route(...p) {
|
|
1039
1122
|
const [a] = p;
|
|
1040
1123
|
if (a && typeof a === 'object' && !(a instanceof Router)) {
|
|
1041
|
-
const path = String.raw(a, ...p.slice(1));
|
|
1042
1124
|
/**
|
|
1043
|
-
* @param {
|
|
1125
|
+
* @param { Finder | Router} [r];
|
|
1044
1126
|
* @returns {any}
|
|
1045
1127
|
*/
|
|
1046
|
-
return r => bindRouter(this.#routes,
|
|
1128
|
+
return r => bindRouter(this.#routes, [a, p.slice(1)], r);
|
|
1047
1129
|
}
|
|
1048
1130
|
const path = typeof a === 'string' ? a : '';
|
|
1049
1131
|
const r = typeof a === 'string' ? p[1] : a;
|
|
@@ -1051,10 +1133,10 @@ class ApiRouter extends Router {
|
|
|
1051
1133
|
}
|
|
1052
1134
|
/**
|
|
1053
1135
|
*
|
|
1054
|
-
* @param {
|
|
1136
|
+
* @param {Method} method
|
|
1055
1137
|
* @param {string[]} path
|
|
1056
|
-
* @param {
|
|
1057
|
-
* @returns {Iterable<
|
|
1138
|
+
* @param {Context} ctx
|
|
1139
|
+
* @returns {Iterable<FindItem>}
|
|
1058
1140
|
*/
|
|
1059
1141
|
*find(method, path, ctx) {
|
|
1060
1142
|
for (const route of Array.from(this.#routes)) {
|
|
@@ -1075,29 +1157,29 @@ class ApiRouter extends Router {
|
|
|
1075
1157
|
/**
|
|
1076
1158
|
* 注册处理函数
|
|
1077
1159
|
* @overload
|
|
1078
|
-
* @param {
|
|
1079
|
-
* @param {
|
|
1160
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
|
|
1161
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1080
1162
|
* @returns {() => void}
|
|
1081
1163
|
*/
|
|
1082
1164
|
/**
|
|
1083
1165
|
* 注册处理函数
|
|
1084
1166
|
* @overload
|
|
1085
|
-
* @param {
|
|
1167
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
|
|
1086
1168
|
* @param {string} path 要注册的路径
|
|
1087
|
-
* @param {
|
|
1169
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1088
1170
|
* @returns {() => void}
|
|
1089
1171
|
*/
|
|
1090
1172
|
/**
|
|
1091
1173
|
* 注册处理函数
|
|
1092
1174
|
* @overload
|
|
1093
|
-
* @param {
|
|
1175
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
|
|
1094
1176
|
* @param {string} path 要注册的路径
|
|
1095
1177
|
* @returns {Binder}
|
|
1096
1178
|
*/
|
|
1097
1179
|
/**
|
|
1098
|
-
* @param {
|
|
1099
|
-
* @param {string|
|
|
1100
|
-
* @param {
|
|
1180
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} methods
|
|
1181
|
+
* @param {string| Handler} [path]
|
|
1182
|
+
* @param {Handler} [handler]
|
|
1101
1183
|
* @returns {Binder | (() => void)}
|
|
1102
1184
|
*/
|
|
1103
1185
|
verb(methods, path, handler) {
|
|
@@ -1108,14 +1190,14 @@ class ApiRouter extends Router {
|
|
|
1108
1190
|
/**
|
|
1109
1191
|
* 注册 HTTP GET/POST/PUT/DELETE 处理函数
|
|
1110
1192
|
* @overload
|
|
1111
|
-
* @param {
|
|
1193
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1112
1194
|
* @returns {() => void}
|
|
1113
1195
|
*/
|
|
1114
1196
|
/**
|
|
1115
1197
|
* 注册处理函数
|
|
1116
1198
|
* @overload
|
|
1117
1199
|
* @param {string} path 要注册的路径
|
|
1118
|
-
* @param {
|
|
1200
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1119
1201
|
* @returns {() => void}
|
|
1120
1202
|
*/
|
|
1121
1203
|
/**
|
|
@@ -1141,14 +1223,14 @@ class ApiRouter extends Router {
|
|
|
1141
1223
|
/**
|
|
1142
1224
|
* 注册 HTTP GET 处理函数
|
|
1143
1225
|
* @overload
|
|
1144
|
-
* @param {
|
|
1226
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1145
1227
|
* @returns {() => void}
|
|
1146
1228
|
*/
|
|
1147
1229
|
/**
|
|
1148
1230
|
* 注册 HTTP GET 处理函数
|
|
1149
1231
|
* @overload
|
|
1150
1232
|
* @param {string} path 要注册的路径
|
|
1151
|
-
* @param {
|
|
1233
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1152
1234
|
* @returns {() => void}
|
|
1153
1235
|
*/
|
|
1154
1236
|
/**
|
|
@@ -1172,14 +1254,14 @@ class ApiRouter extends Router {
|
|
|
1172
1254
|
/**
|
|
1173
1255
|
* 注册 HTTP POST 处理函数
|
|
1174
1256
|
* @overload
|
|
1175
|
-
* @param {
|
|
1257
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1176
1258
|
* @returns {() => void}
|
|
1177
1259
|
*/
|
|
1178
1260
|
/**
|
|
1179
1261
|
* 注册 HTTP POST 处理函数
|
|
1180
1262
|
* @overload
|
|
1181
1263
|
* @param {string} path 要注册的路径
|
|
1182
|
-
* @param {
|
|
1264
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1183
1265
|
* @returns {() => void}
|
|
1184
1266
|
*/
|
|
1185
1267
|
/**
|
|
@@ -1203,14 +1285,14 @@ class ApiRouter extends Router {
|
|
|
1203
1285
|
/**
|
|
1204
1286
|
* 注册 HTTP PUT 处理函数
|
|
1205
1287
|
* @overload
|
|
1206
|
-
* @param {
|
|
1288
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1207
1289
|
* @returns {() => void}
|
|
1208
1290
|
*/
|
|
1209
1291
|
/**
|
|
1210
1292
|
* 注册 HTTP PUT 处理函数
|
|
1211
1293
|
* @overload
|
|
1212
1294
|
* @param {string} path 要注册的路径
|
|
1213
|
-
* @param {
|
|
1295
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1214
1296
|
* @returns {() => void}
|
|
1215
1297
|
*/
|
|
1216
1298
|
/**
|
|
@@ -1234,14 +1316,14 @@ class ApiRouter extends Router {
|
|
|
1234
1316
|
/**
|
|
1235
1317
|
* 注册 HTTP DELETE 处理函数
|
|
1236
1318
|
* @overload
|
|
1237
|
-
* @param {
|
|
1319
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1238
1320
|
* @returns {() => void}
|
|
1239
1321
|
*/
|
|
1240
1322
|
/**
|
|
1241
1323
|
* 注册 HTTP DELETE 处理函数
|
|
1242
1324
|
* @overload
|
|
1243
1325
|
* @param {string} path 要注册的路径
|
|
1244
|
-
* @param {
|
|
1326
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1245
1327
|
* @returns {() => void}
|
|
1246
1328
|
*/
|
|
1247
1329
|
/**
|
|
@@ -1265,14 +1347,14 @@ class ApiRouter extends Router {
|
|
|
1265
1347
|
/**
|
|
1266
1348
|
* 注册 HTTP HEAD 处理函数
|
|
1267
1349
|
* @overload
|
|
1268
|
-
* @param {
|
|
1350
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1269
1351
|
* @returns {() => void}
|
|
1270
1352
|
*/
|
|
1271
1353
|
/**
|
|
1272
1354
|
* 注册 HTTP HEAD 处理函数
|
|
1273
1355
|
* @overload
|
|
1274
1356
|
* @param {string} path 要注册的路径
|
|
1275
|
-
* @param {
|
|
1357
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1276
1358
|
* @returns {() => void}
|
|
1277
1359
|
*/
|
|
1278
1360
|
/**
|
|
@@ -1296,14 +1378,14 @@ class ApiRouter extends Router {
|
|
|
1296
1378
|
/**
|
|
1297
1379
|
* 注册 HTTP OPTIONS 处理函数
|
|
1298
1380
|
* @overload
|
|
1299
|
-
* @param {
|
|
1381
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1300
1382
|
* @returns {() => void}
|
|
1301
1383
|
*/
|
|
1302
1384
|
/**
|
|
1303
1385
|
* 注册 HTTP OPTIONS 处理函数
|
|
1304
1386
|
* @overload
|
|
1305
1387
|
* @param {string} path 要注册的路径
|
|
1306
|
-
* @param {
|
|
1388
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1307
1389
|
* @returns {() => void}
|
|
1308
1390
|
*/
|
|
1309
1391
|
/**
|
|
@@ -1349,21 +1431,22 @@ function createFetch(run, notFound) {
|
|
|
1349
1431
|
};
|
|
1350
1432
|
}
|
|
1351
1433
|
|
|
1434
|
+
/** @import { Context, Handler, HandlerResult } from './main/types' */
|
|
1352
1435
|
/**
|
|
1353
1436
|
* @callback Onionskin
|
|
1354
|
-
* @param {
|
|
1355
|
-
* @param {() => Promise<
|
|
1356
|
-
* @returns {PromiseLike<
|
|
1437
|
+
* @param {Context} ctx
|
|
1438
|
+
* @param {() => Promise<HandlerResult>} next
|
|
1439
|
+
* @returns {PromiseLike<HandlerResult> | HandlerResult}
|
|
1357
1440
|
*/
|
|
1358
1441
|
|
|
1359
1442
|
const noop = () => {};
|
|
1360
1443
|
/**
|
|
1361
1444
|
*
|
|
1362
1445
|
* @param {...(Onionskin | Onionskin[])} handlers
|
|
1363
|
-
* @returns {
|
|
1446
|
+
* @returns {Handler}
|
|
1364
1447
|
*/
|
|
1365
1448
|
function onionskin(...handlers) {
|
|
1366
|
-
/** @type {
|
|
1449
|
+
/** @type {Handler} */
|
|
1367
1450
|
let handler = noop;
|
|
1368
1451
|
for (const os of handlers.flat()) {
|
|
1369
1452
|
const currentHandler = handler;
|
|
@@ -1372,7 +1455,44 @@ function onionskin(...handlers) {
|
|
|
1372
1455
|
return handler;
|
|
1373
1456
|
}
|
|
1374
1457
|
|
|
1458
|
+
/** @import { Context } from './main/types.js' */
|
|
1459
|
+
class Param {
|
|
1460
|
+
#symbol = Symbol();
|
|
1461
|
+
get name() { return this.#symbol}
|
|
1462
|
+
#pattern
|
|
1463
|
+
get pattern() { return this.#pattern; }
|
|
1464
|
+
/**
|
|
1465
|
+
*
|
|
1466
|
+
* @param {RegExp} pattern
|
|
1467
|
+
*/
|
|
1468
|
+
constructor(pattern) {
|
|
1469
|
+
this.#pattern = pattern;
|
|
1470
|
+
}
|
|
1471
|
+
/**
|
|
1472
|
+
*
|
|
1473
|
+
* @param {Context} ctx
|
|
1474
|
+
* @returns {string?}
|
|
1475
|
+
*/
|
|
1476
|
+
param(ctx) {
|
|
1477
|
+
const param = ctx.params[this.#symbol];
|
|
1478
|
+
if (Array.isArray(param)) { return param[0] ?? null; }
|
|
1479
|
+
return param ?? null;
|
|
1480
|
+
}
|
|
1481
|
+
/**
|
|
1482
|
+
*
|
|
1483
|
+
* @param {Context} ctx
|
|
1484
|
+
* @returns {string[]?}
|
|
1485
|
+
*/
|
|
1486
|
+
params(ctx) {
|
|
1487
|
+
const param = ctx.params[this.#symbol];
|
|
1488
|
+
if (typeof param === 'string') { return [param]; }
|
|
1489
|
+
if (Array.isArray(param)) { return param; }
|
|
1490
|
+
return null;
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1375
1494
|
exports.ApiRouter = ApiRouter;
|
|
1495
|
+
exports.Param = Param;
|
|
1376
1496
|
exports.Router = Router;
|
|
1377
1497
|
exports.createFetch = createFetch;
|
|
1378
1498
|
exports.main = main;
|