k99 0.6.0 → 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 +304 -198
- package/index.d.ts +82 -81
- package/index.js +304 -198
- package/index.min.js +3 -3
- package/index.min.mjs +3 -3
- package/index.mjs +304 -199
- package/package.json +2 -3
- package/services.cjs +6 -4
- package/services.d.ts +8 -7
- package/services.js +6 -4
- package/services.min.js +2 -2
- package/services.min.mjs +2 -2
- package/services.mjs +6 -4
- package/node/index.cjs +0 -140
- package/node/index.d.cts +0 -52
package/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* k99 v0.
|
|
3
|
-
* (c) 2019-
|
|
2
|
+
* k99 v0.7.0
|
|
3
|
+
* (c) 2019-2025 猛火Fierflame
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
6
6
|
'use strict';
|
|
@@ -13,20 +13,6 @@
|
|
|
13
13
|
function str2utf8bin(str) {
|
|
14
14
|
return new TextEncoder().encode(str);
|
|
15
15
|
}
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
* @param {unknown} chunk
|
|
19
|
-
* @returns {chunk is ArrayBuffer | SharedArrayBuffer}
|
|
20
|
-
*/
|
|
21
|
-
function isBufferSource(chunk) {
|
|
22
|
-
if (chunk instanceof ArrayBuffer) { return true; }
|
|
23
|
-
try {
|
|
24
|
-
if (chunk instanceof SharedArrayBuffer) { return true; }
|
|
25
|
-
} catch {
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
16
|
/**
|
|
31
17
|
*
|
|
32
18
|
* @template T
|
|
@@ -51,7 +37,7 @@ async function write(writer, chunk) {
|
|
|
51
37
|
if (ArrayBuffer.isView(chunk)) {
|
|
52
38
|
return writer.write(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength));
|
|
53
39
|
}
|
|
54
|
-
if (
|
|
40
|
+
if (chunk instanceof ArrayBuffer) {
|
|
55
41
|
return writer.write(new Uint8Array(chunk));
|
|
56
42
|
}
|
|
57
43
|
if (!isIterable(chunk)) {
|
|
@@ -95,7 +81,7 @@ function toBodyData(result, aborted) {
|
|
|
95
81
|
if (result instanceof FormData) {
|
|
96
82
|
return [result, 0, ''];
|
|
97
83
|
}
|
|
98
|
-
if (ArrayBuffer.isView(result) ||
|
|
84
|
+
if (ArrayBuffer.isView(result) || result instanceof ArrayBuffer) {
|
|
99
85
|
return [result, result.byteLength, ''];
|
|
100
86
|
}
|
|
101
87
|
if (typeof result === 'string') {
|
|
@@ -120,8 +106,7 @@ function toBodyData(result, aborted) {
|
|
|
120
106
|
if (!data) { continue; }
|
|
121
107
|
await write(writer, data);
|
|
122
108
|
}
|
|
123
|
-
|
|
124
|
-
})().catch(() => {});
|
|
109
|
+
})().then(() => writable.close(), r => writable.abort(r)).catch(() => {});
|
|
125
110
|
return [readable, 0, ''];
|
|
126
111
|
}
|
|
127
112
|
/**
|
|
@@ -144,11 +129,12 @@ function toBody(result, headers, aborted) {
|
|
|
144
129
|
return body;
|
|
145
130
|
}
|
|
146
131
|
|
|
132
|
+
/** @import { Cookie, CookieOption } from './types' */
|
|
147
133
|
/**
|
|
148
134
|
*
|
|
149
|
-
* @param {
|
|
135
|
+
* @param {Cookie[]} sentCookies
|
|
150
136
|
* @param {string} [name]
|
|
151
|
-
* @returns {Iterable<
|
|
137
|
+
* @returns {Iterable<Cookie>}
|
|
152
138
|
*/
|
|
153
139
|
function *getCookie(sentCookies, name) {
|
|
154
140
|
const list = sentCookies;
|
|
@@ -161,7 +147,7 @@ function *getCookie(sentCookies, name) {
|
|
|
161
147
|
/**
|
|
162
148
|
*
|
|
163
149
|
* @param {Headers} headers
|
|
164
|
-
* @param {
|
|
150
|
+
* @param {Cookie[]} cookies
|
|
165
151
|
* @returns {void}
|
|
166
152
|
*/
|
|
167
153
|
function setCookiesHeader(headers, cookies) {
|
|
@@ -195,10 +181,10 @@ function getRequestCookies(cookie) {
|
|
|
195
181
|
}
|
|
196
182
|
/**
|
|
197
183
|
*
|
|
198
|
-
* @param {
|
|
184
|
+
* @param {Cookie[]} sentCookies
|
|
199
185
|
* @param {Record<string, string>} cookies
|
|
200
|
-
* @param {string |
|
|
201
|
-
* @param {
|
|
186
|
+
* @param {string | CookieOption} [name]
|
|
187
|
+
* @param {CookieOption | boolean} [opt]
|
|
202
188
|
* @returns {void}
|
|
203
189
|
*/
|
|
204
190
|
function clearCookie(
|
|
@@ -210,11 +196,11 @@ function clearCookie(
|
|
|
210
196
|
let expire = 'Fri, 31 Dec 1999 16:00:00 GMT';
|
|
211
197
|
if (typeof name === 'string') {
|
|
212
198
|
if (!name) { return; }
|
|
213
|
-
/** @type {
|
|
199
|
+
/** @type {CookieOption} */
|
|
214
200
|
const { domain, path, secure, httpOnly } = opt !== true && opt || {};
|
|
215
201
|
sentCookies.push({ name, value: 'delete', expire, domain, path, secure, httpOnly });
|
|
216
202
|
} else {
|
|
217
|
-
/** @type {
|
|
203
|
+
/** @type {CookieOption} */
|
|
218
204
|
const { domain, path, secure, httpOnly } = name || {};
|
|
219
205
|
sentCookies.length = 0;
|
|
220
206
|
if (opt) {
|
|
@@ -225,6 +211,9 @@ function clearCookie(
|
|
|
225
211
|
}
|
|
226
212
|
}
|
|
227
213
|
|
|
214
|
+
/** @import { Context, Cookie, CookieOption, FindHandler, Method, Options, Params, Service } from './types' */
|
|
215
|
+
|
|
216
|
+
|
|
228
217
|
const noBodyMethods = new Set(['GET', 'OPTIONS']);
|
|
229
218
|
/**
|
|
230
219
|
*
|
|
@@ -261,7 +250,7 @@ function setHeader(headers, name, value) {
|
|
|
261
250
|
*
|
|
262
251
|
* @param {Request} request
|
|
263
252
|
* @param {string | ((request: Request) => string)} [toMethod]
|
|
264
|
-
* @returns {
|
|
253
|
+
* @returns {Method}
|
|
265
254
|
*/
|
|
266
255
|
function getMethod(request, toMethod) {
|
|
267
256
|
let methodStr = '';
|
|
@@ -273,13 +262,13 @@ function getMethod(request, toMethod) {
|
|
|
273
262
|
if (!methodStr || typeof methodStr !== 'string') {
|
|
274
263
|
methodStr = request.method || 'GET';
|
|
275
264
|
}
|
|
276
|
-
return /** @type {
|
|
265
|
+
return /** @type {Method} */(methodStr.toUpperCase());
|
|
277
266
|
}
|
|
278
267
|
/**
|
|
279
268
|
*
|
|
280
269
|
* @param {Request} request
|
|
281
|
-
* @param {
|
|
282
|
-
* @param {
|
|
270
|
+
* @param {FindHandler} getHandler
|
|
271
|
+
* @param {Options} [options]
|
|
283
272
|
* @returns {Promise<Response | null>}
|
|
284
273
|
*/
|
|
285
274
|
function main(
|
|
@@ -289,7 +278,7 @@ function main(
|
|
|
289
278
|
/**
|
|
290
279
|
*
|
|
291
280
|
* @param {Request} request
|
|
292
|
-
* @param {
|
|
281
|
+
* @param {Context} [parent]
|
|
293
282
|
* @returns {Promise<Response | null>}
|
|
294
283
|
*/
|
|
295
284
|
function exec(request, parent) {
|
|
@@ -297,10 +286,10 @@ function main(
|
|
|
297
286
|
const url = new URL(request.url);
|
|
298
287
|
const { signal, headers } = request;
|
|
299
288
|
const aborted = signal2promise(signal);
|
|
300
|
-
/** @type {Map<
|
|
289
|
+
/** @type {Map<Service<any, any>, Function>} */
|
|
301
290
|
const services = new Map();
|
|
302
291
|
const cookies = getRequestCookies(headers.get('cookie') || '');
|
|
303
|
-
/** @type {
|
|
292
|
+
/** @type {Cookie[]} */
|
|
304
293
|
const sentCookies = [];
|
|
305
294
|
const responseHeaders = new Headers();
|
|
306
295
|
const root = parent?.root;
|
|
@@ -316,9 +305,9 @@ function main(
|
|
|
316
305
|
const donePromise = new Promise((a, b) => { resolve = a; reject = b; });
|
|
317
306
|
donePromise.catch(() => {});
|
|
318
307
|
|
|
319
|
-
/** @type {
|
|
308
|
+
/** @type {Params} */
|
|
320
309
|
let params = {};
|
|
321
|
-
/** @type {
|
|
310
|
+
/** @type {Context} */
|
|
322
311
|
const context = {
|
|
323
312
|
environment,
|
|
324
313
|
parent,
|
|
@@ -382,8 +371,8 @@ function main(
|
|
|
382
371
|
},
|
|
383
372
|
/**
|
|
384
373
|
*
|
|
385
|
-
* @param {string |
|
|
386
|
-
* @param {
|
|
374
|
+
* @param {string | CookieOption} [name]
|
|
375
|
+
* @param {CookieOption | boolean} [opt]
|
|
387
376
|
* @returns {void}
|
|
388
377
|
*/
|
|
389
378
|
clearCookie(name, opt) {
|
|
@@ -420,69 +409,72 @@ function main(
|
|
|
420
409
|
return exec(request);
|
|
421
410
|
}
|
|
422
411
|
|
|
412
|
+
/** @import { FindHandler, Options } from './main/types' */
|
|
413
|
+
|
|
423
414
|
/**
|
|
424
415
|
*
|
|
425
|
-
* @param {
|
|
426
|
-
* @param {
|
|
416
|
+
* @param {FindHandler} getHandler
|
|
417
|
+
* @param {Options} options
|
|
427
418
|
* @returns {(request: Request) => Promise<Response | null>}
|
|
428
419
|
*/
|
|
429
420
|
function make(getHandler, options) {
|
|
430
421
|
return r => main(r, getHandler, options);
|
|
431
422
|
}
|
|
432
423
|
|
|
424
|
+
/** @import { Context, Handler } from './main/types' */
|
|
433
425
|
/**
|
|
434
426
|
*
|
|
435
|
-
* @param {
|
|
436
|
-
* @param {
|
|
427
|
+
* @param {Context} context
|
|
428
|
+
* @param {Handler[]} handlers
|
|
437
429
|
* @returns {Promise<string | boolean | object | undefined>}
|
|
438
430
|
*/
|
|
439
431
|
async function runHandles(context, handlers) {
|
|
440
432
|
for (const handle of handlers) {
|
|
441
433
|
const result = await handle(context);
|
|
442
|
-
if (
|
|
443
|
-
if (!result) { continue; }
|
|
434
|
+
if (result === undefined) { continue; }
|
|
444
435
|
return result;
|
|
445
436
|
}
|
|
446
437
|
}
|
|
447
438
|
|
|
448
439
|
/**
|
|
449
440
|
*
|
|
450
|
-
* @param {...(
|
|
451
|
-
* @returns {
|
|
441
|
+
* @param {...(Handler | Handler[])} handlers
|
|
442
|
+
* @returns {Handler}
|
|
452
443
|
*/
|
|
453
444
|
function merge(...handlers) {
|
|
454
445
|
return ctx => runHandles(ctx, handlers.flat());
|
|
455
446
|
}
|
|
456
447
|
|
|
448
|
+
/** @import { Context, Service } from './main/types' */
|
|
457
449
|
/**
|
|
458
450
|
*
|
|
459
451
|
* @template T
|
|
460
452
|
* @template {any[]} P
|
|
461
453
|
* @overload
|
|
462
|
-
* @param {(ctx:
|
|
463
|
-
* @param {((ctx:
|
|
464
|
-
* @param {
|
|
465
|
-
* @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>}
|
|
466
458
|
*/
|
|
467
459
|
/**
|
|
468
460
|
*
|
|
469
461
|
* @template T
|
|
470
462
|
* @template {any[]} P
|
|
471
463
|
* @overload
|
|
472
|
-
* @param {(ctx:
|
|
473
|
-
* @param {
|
|
474
|
-
* @returns {
|
|
464
|
+
* @param {(ctx: Context, ...p: P) => T} exec
|
|
465
|
+
* @param {Service.Options?} [options]
|
|
466
|
+
* @returns {Service<T, P>}
|
|
475
467
|
*/
|
|
476
468
|
/**
|
|
477
469
|
* @template T
|
|
478
470
|
* @template {any[]} P
|
|
479
|
-
* @param {(ctx:
|
|
480
|
-
* @param {((ctx:
|
|
481
|
-
* @param {
|
|
482
|
-
* @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>}
|
|
483
475
|
*/
|
|
484
476
|
function service(exec, destroy, options) {
|
|
485
|
-
/** @type {
|
|
477
|
+
/** @type {Service<T, P>} */
|
|
486
478
|
const service = function (ctx) {
|
|
487
479
|
if (typeof destroy === 'function') {
|
|
488
480
|
ctx.done(() => destroy(ctx), error => destroy(ctx, error));
|
|
@@ -501,43 +493,44 @@ function service(exec, destroy, options) {
|
|
|
501
493
|
return service;
|
|
502
494
|
}
|
|
503
495
|
|
|
496
|
+
/** @import { Context, Service, StateService } from './main/types' */
|
|
504
497
|
/**
|
|
505
498
|
*
|
|
506
499
|
* @template T
|
|
507
500
|
* @overload
|
|
508
|
-
* @param {(ctx:
|
|
509
|
-
* @param {
|
|
510
|
-
* @returns {
|
|
501
|
+
* @param {(ctx: Context) => T} init
|
|
502
|
+
* @param {Service.Options} [options]
|
|
503
|
+
* @returns {StateService<T>}
|
|
511
504
|
*/
|
|
512
505
|
/**
|
|
513
506
|
*
|
|
514
507
|
* @template T
|
|
515
508
|
* @overload
|
|
516
|
-
* @param {(ctx:
|
|
517
|
-
* @param {((state: T | undefined, ctx:
|
|
518
|
-
* @param {
|
|
519
|
-
* @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>}
|
|
520
513
|
*/
|
|
521
514
|
/**
|
|
522
515
|
*
|
|
523
516
|
* @template T
|
|
524
517
|
* @overload
|
|
525
|
-
* @param {(ctx:
|
|
526
|
-
* @param {((state: T | undefined, ctx:
|
|
527
|
-
* @param {((state: T, ctx:
|
|
528
|
-
* @param {
|
|
529
|
-
* @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>}
|
|
530
523
|
*/
|
|
531
524
|
/**
|
|
532
525
|
* @template T
|
|
533
|
-
* @param {(ctx:
|
|
534
|
-
* @param {((state: T | undefined, ctx:
|
|
535
|
-
* @param {((state: T, ctx:
|
|
536
|
-
* @param {
|
|
537
|
-
* @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>}
|
|
538
531
|
*/
|
|
539
532
|
function stateService(init, destroy, exec, options) {
|
|
540
|
-
/** @type {
|
|
533
|
+
/** @type {StateService<T>} */
|
|
541
534
|
const service = function (ctx) {
|
|
542
535
|
const state = init(ctx) || /** @type {T} */({});
|
|
543
536
|
if (typeof destroy === 'function') {
|
|
@@ -561,39 +554,40 @@ function stateService(init, destroy, exec, options) {
|
|
|
561
554
|
return service;
|
|
562
555
|
}
|
|
563
556
|
|
|
557
|
+
/** @import { Context, Service, StoreService } from './main/types' */
|
|
564
558
|
/**
|
|
565
559
|
*
|
|
566
560
|
* @template T
|
|
567
561
|
* @overload
|
|
568
|
-
* @param {
|
|
569
|
-
* @returns {
|
|
562
|
+
* @param {Service.Options?} [options]
|
|
563
|
+
* @returns {StoreService<T>}
|
|
570
564
|
*/
|
|
571
565
|
/**
|
|
572
566
|
*
|
|
573
567
|
* @template T
|
|
574
568
|
* @overload
|
|
575
|
-
* @param {((state: T | undefined, ctx:
|
|
576
|
-
* @param {
|
|
577
|
-
* @returns {
|
|
569
|
+
* @param {((state: T | undefined, ctx: Context, error?: unknown) => PromiseLike<void> | void)?} [destroy]
|
|
570
|
+
* @param {Service.Options?} [options]
|
|
571
|
+
* @returns {StoreService<T>}
|
|
578
572
|
*/
|
|
579
573
|
/**
|
|
580
574
|
*
|
|
581
575
|
* @template T
|
|
582
576
|
* @overload
|
|
583
|
-
* @param {((state: T | undefined, ctx:
|
|
584
|
-
* @param {((state: T | undefined, ctx:
|
|
585
|
-
* @param {
|
|
586
|
-
* @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>}
|
|
587
581
|
*/
|
|
588
582
|
/**
|
|
589
583
|
* @template T
|
|
590
|
-
* @param {((state: T | undefined, ctx:
|
|
591
|
-
* @param {((state: T | undefined, ctx:
|
|
592
|
-
* @param {
|
|
593
|
-
* @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>}
|
|
594
588
|
*/
|
|
595
589
|
function storeService(destroy, exec, options) {
|
|
596
|
-
/** @type {
|
|
590
|
+
/** @type {StoreService<T>} */
|
|
597
591
|
const service = function (ctx) {
|
|
598
592
|
/** @type {T | undefined} */
|
|
599
593
|
let state;
|
|
@@ -630,16 +624,18 @@ function storeService(destroy, exec, options) {
|
|
|
630
624
|
return service;
|
|
631
625
|
}
|
|
632
626
|
|
|
627
|
+
/** @import { Handler } from './main/types' */
|
|
628
|
+
/** @import { Onionskin } from './onionskin.mjs' */
|
|
633
629
|
/**
|
|
634
630
|
* @callback Packer
|
|
635
|
-
* @param {
|
|
636
|
-
* @returns {
|
|
631
|
+
* @param {Handler} handler
|
|
632
|
+
* @returns {Handler}
|
|
637
633
|
*/
|
|
638
634
|
/** @type {Packer} */
|
|
639
635
|
const noop$1 = h => h;
|
|
640
636
|
/**
|
|
641
637
|
*
|
|
642
|
-
* @param {
|
|
638
|
+
* @param {Onionskin} onionskin
|
|
643
639
|
* @param {Packer} [packer]
|
|
644
640
|
* @returns {Packer}
|
|
645
641
|
*/
|
|
@@ -650,30 +646,33 @@ function packer(onionskin, packer = noop$1) {
|
|
|
650
646
|
};
|
|
651
647
|
}
|
|
652
648
|
|
|
649
|
+
/** @import { Context, FindHandler, Handler, Method, Params } from './main/types' */
|
|
650
|
+
/** @import { Onionskin } from './onionskin.mjs' */
|
|
651
|
+
|
|
653
652
|
/**
|
|
654
653
|
* @callback Guard
|
|
655
|
-
* @param {
|
|
656
|
-
* @returns {PromiseLike<boolean |
|
|
654
|
+
* @param {Context} ctx
|
|
655
|
+
* @returns {PromiseLike<boolean | Handler | void> | boolean | Handler | void}
|
|
657
656
|
*/
|
|
658
657
|
/**
|
|
659
|
-
* @typedef {[
|
|
658
|
+
* @typedef {[Handler | Router, Record<string | symbol, any>, string[]]} FindItem
|
|
660
659
|
*/
|
|
661
660
|
/**
|
|
662
661
|
* @callback Finder
|
|
663
662
|
* @this {Router}
|
|
664
|
-
* @param {
|
|
663
|
+
* @param {Method} method
|
|
665
664
|
* @param {string[]} path
|
|
666
|
-
* @param {
|
|
665
|
+
* @param {Context} ctx
|
|
667
666
|
* @returns {AsyncIterable<FindItem> | Iterable<FindItem>}
|
|
668
667
|
*/
|
|
669
668
|
|
|
670
669
|
/**
|
|
671
670
|
*
|
|
672
671
|
* @param {Set<Guard>} guards
|
|
673
|
-
* @param {
|
|
672
|
+
* @param {Context} ctx
|
|
674
673
|
* @param {(v: any) => void} setParams
|
|
675
674
|
* @param {object} params
|
|
676
|
-
* @returns {Promise<boolean |
|
|
675
|
+
* @returns {Promise<boolean | Handler>}
|
|
677
676
|
*/
|
|
678
677
|
async function execGuard(guards, ctx, setParams, params) {
|
|
679
678
|
if (!guards.size) { return true; }
|
|
@@ -692,12 +691,12 @@ async function execGuard(guards, ctx, setParams, params) {
|
|
|
692
691
|
|
|
693
692
|
/**
|
|
694
693
|
*
|
|
695
|
-
* @param {Router |
|
|
694
|
+
* @param {Router | Handler} route
|
|
696
695
|
* @param {string[]} path
|
|
697
|
-
* @param {
|
|
698
|
-
* @param {(v:
|
|
699
|
-
* @param {
|
|
700
|
-
* @returns {Promise<
|
|
696
|
+
* @param {Context} ctx
|
|
697
|
+
* @param {(v: Params) => void} setParams
|
|
698
|
+
* @param {Params} params
|
|
699
|
+
* @returns {Promise<Handler | null>}
|
|
701
700
|
*/
|
|
702
701
|
async function find(route, path, ctx, setParams, params) {
|
|
703
702
|
if (!(route instanceof Router)) {
|
|
@@ -736,16 +735,16 @@ class Router {
|
|
|
736
735
|
disabled = false;
|
|
737
736
|
/**
|
|
738
737
|
* @abstract
|
|
739
|
-
* @param {
|
|
738
|
+
* @param {Method} method
|
|
740
739
|
* @param {string[]} path
|
|
741
|
-
* @param {
|
|
740
|
+
* @param {Context} ctx
|
|
742
741
|
* @returns {AsyncIterable<FindItem> | Iterable<FindItem>}
|
|
743
742
|
*/
|
|
744
743
|
find(method, path, ctx) { return []; }
|
|
745
744
|
/**
|
|
746
745
|
*
|
|
747
746
|
* @param {Router[]} routers
|
|
748
|
-
* @returns {
|
|
747
|
+
* @returns {FindHandler}
|
|
749
748
|
*/
|
|
750
749
|
static make(routers) {
|
|
751
750
|
return async (ctx, setParams) => {
|
|
@@ -773,19 +772,21 @@ class Router {
|
|
|
773
772
|
guards = new Set();
|
|
774
773
|
/**
|
|
775
774
|
*
|
|
776
|
-
* @param {
|
|
777
|
-
* @returns {
|
|
775
|
+
* @param {Handler} h
|
|
776
|
+
* @returns {Handler}
|
|
778
777
|
*/
|
|
779
778
|
__onionskin = (h) => h;
|
|
780
|
-
/** @param {
|
|
779
|
+
/** @param {Onionskin} os */
|
|
781
780
|
onionskin(os) { this.__onionskin = packer(os, this.__onionskin); }
|
|
782
781
|
}
|
|
783
782
|
|
|
783
|
+
/** @import { Match } from './index.mjs' */
|
|
784
|
+
/** @import { Params } from '../main/types.js' */
|
|
784
785
|
/**
|
|
785
786
|
* @typedef {object} Pattern
|
|
786
|
-
* @property {string} name
|
|
787
|
-
* @property {boolean} optional
|
|
788
|
-
* @property {boolean} many
|
|
787
|
+
* @property {string | symbol} name
|
|
788
|
+
* @property {boolean} [optional]
|
|
789
|
+
* @property {boolean} [many]
|
|
789
790
|
* @property {RegExp} pattern
|
|
790
791
|
*/
|
|
791
792
|
|
|
@@ -856,7 +857,7 @@ function parse(p) {
|
|
|
856
857
|
* @returns {[Record<string, string | string[]>, string[]] | undefined}
|
|
857
858
|
*/
|
|
858
859
|
function exec(match, path, end) {
|
|
859
|
-
/** @type {
|
|
860
|
+
/** @type {Params} */
|
|
860
861
|
const params = {};
|
|
861
862
|
for (let i = 0; i < match.length; i++) {
|
|
862
863
|
const m = match[i];
|
|
@@ -879,38 +880,101 @@ function exec(match, path, end) {
|
|
|
879
880
|
return [params, []];
|
|
880
881
|
|
|
881
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
|
+
}
|
|
882
911
|
/**
|
|
883
912
|
*
|
|
884
|
-
* @param {string} path
|
|
913
|
+
* @param {string | [string[], any[]]} path
|
|
885
914
|
* @param {boolean} end
|
|
886
|
-
* @returns {
|
|
915
|
+
* @returns {Match | undefined}
|
|
887
916
|
*/
|
|
888
917
|
function toMatch(path, end) {
|
|
889
918
|
/** @type {(Pattern | string)[]} */
|
|
890
919
|
const list = [];
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
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
|
+
|
|
894
959
|
}
|
|
895
960
|
if (!list.length) { return; }
|
|
896
961
|
return path => exec(list, path, end);
|
|
897
962
|
}
|
|
898
963
|
|
|
964
|
+
/** @import { Handler, Method } from '../main/types' */
|
|
965
|
+
/** @import { Binder, Match, Route, RouterRoute } from './index.mjs' */
|
|
966
|
+
|
|
899
967
|
/**
|
|
900
968
|
*
|
|
901
|
-
* @param {(
|
|
902
|
-
* @param {
|
|
903
|
-
* @param {
|
|
904
|
-
* @param {
|
|
969
|
+
* @param {(Route | RouterRoute)[]} routes
|
|
970
|
+
* @param {Set<Method>} methods
|
|
971
|
+
* @param {Match | undefined} match
|
|
972
|
+
* @param {Handler[]} handlers
|
|
905
973
|
* @returns {() => void}
|
|
906
974
|
*/
|
|
907
|
-
function bind(routes, methods,
|
|
908
|
-
/** @type {
|
|
909
|
-
const route = {
|
|
910
|
-
match: toMatch(path || '', true),
|
|
911
|
-
methods: new Set(methods),
|
|
912
|
-
handler,
|
|
913
|
-
};
|
|
975
|
+
function bind(routes, methods, match, handlers) {
|
|
976
|
+
/** @type {Route} */
|
|
977
|
+
const route = { match, methods, handler: ctx => runHandles(ctx, handlers) };
|
|
914
978
|
routes.push(route);
|
|
915
979
|
let removed = false;
|
|
916
980
|
return () => {
|
|
@@ -921,43 +985,49 @@ function bind(routes, methods, path, handler) {
|
|
|
921
985
|
routes.splice(index, 1);
|
|
922
986
|
};
|
|
923
987
|
}
|
|
924
|
-
/** @type {(v: any) => v is
|
|
988
|
+
/** @type {(v: any) => v is Handler} */
|
|
925
989
|
const findHandler = v => typeof v === 'function';
|
|
926
990
|
/**
|
|
927
991
|
*
|
|
928
|
-
* @param {(
|
|
929
|
-
* @param {
|
|
992
|
+
* @param {(Route | RouterRoute)[]} routes
|
|
993
|
+
* @param {Iterable<Method>} methods
|
|
930
994
|
* @param {any[]} p
|
|
931
|
-
* @returns {
|
|
995
|
+
* @returns {Binder | (() => void)}
|
|
932
996
|
*/
|
|
933
997
|
function verb(routes, methods, p) {
|
|
998
|
+
const methodSet = new Set(methods);
|
|
934
999
|
if (!p.length) {
|
|
935
|
-
|
|
1000
|
+
const match = undefined;
|
|
1001
|
+
/** @type {Binder} */
|
|
1002
|
+
return (...handlers) => bind(routes, methodSet, match, handlers);
|
|
936
1003
|
}
|
|
937
|
-
const [
|
|
938
|
-
if (
|
|
939
|
-
const
|
|
940
|
-
|
|
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);
|
|
941
1009
|
}
|
|
942
|
-
const
|
|
943
|
-
const
|
|
944
|
-
if (!
|
|
945
|
-
|
|
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);
|
|
946
1015
|
}
|
|
947
|
-
return bind(routes,
|
|
1016
|
+
return bind(routes, methodSet, match, handlers);
|
|
948
1017
|
}
|
|
949
1018
|
|
|
1019
|
+
/** @import { Method } from '../main/types' */
|
|
950
1020
|
const methods = new Set(['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS']);
|
|
951
1021
|
/**
|
|
952
1022
|
*
|
|
953
1023
|
* @param {any} v
|
|
954
|
-
* @returns {v is
|
|
1024
|
+
* @returns {v is Method}
|
|
955
1025
|
*/
|
|
956
1026
|
function isMethod(v) { return methods.has(v); }
|
|
957
1027
|
/**
|
|
958
1028
|
*
|
|
959
|
-
* @param {
|
|
960
|
-
* @returns {
|
|
1029
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} [methods]
|
|
1030
|
+
* @returns {Method[]}
|
|
961
1031
|
*/
|
|
962
1032
|
function getMethods(methods) {
|
|
963
1033
|
if (!methods) {
|
|
@@ -971,25 +1041,24 @@ function getMethods(methods) {
|
|
|
971
1041
|
.filter(isMethod);
|
|
972
1042
|
}
|
|
973
1043
|
|
|
1044
|
+
/** @import { Context, Handler, Method, Params } from '../main/types' */
|
|
1045
|
+
/** @import { Finder, FindItem } from '../Router.mjs' */
|
|
1046
|
+
|
|
974
1047
|
/**
|
|
975
1048
|
* @callback Match
|
|
976
1049
|
* @param {string[]} paths
|
|
977
|
-
* @returns {[
|
|
1050
|
+
* @returns {[Params, string[]] | undefined}
|
|
978
1051
|
*/
|
|
979
1052
|
|
|
980
|
-
/**
|
|
981
|
-
* @callback Binder
|
|
982
|
-
* @param {import('../main/types').Handler} handler
|
|
983
|
-
* @returns {() => void}
|
|
984
|
-
*/
|
|
1053
|
+
/** @typedef {(handler: Handler, ...handlers: Handler[]) => () => void} Binder */
|
|
985
1054
|
|
|
986
1055
|
/**
|
|
987
1056
|
* @typedef {object} Route
|
|
988
1057
|
* @property {Match} [match] 路径匹配
|
|
989
1058
|
* @property {null} [router]
|
|
990
1059
|
* @property {string} [plugin] 所属插件
|
|
991
|
-
* @property {
|
|
992
|
-
* @property {Set<
|
|
1060
|
+
* @property {Handler} handler 处理函数
|
|
1061
|
+
* @property {Set<Method>} methods 方法列表
|
|
993
1062
|
*/
|
|
994
1063
|
|
|
995
1064
|
/**
|
|
@@ -1000,16 +1069,16 @@ function getMethods(methods) {
|
|
|
1000
1069
|
|
|
1001
1070
|
|
|
1002
1071
|
/**
|
|
1003
|
-
* @template {Router |
|
|
1072
|
+
* @template {Router | Finder} [T=ApiRouter]
|
|
1004
1073
|
* @callback RouteBinder
|
|
1005
1074
|
* @param {T} [router] 要注册的子路由或子路由的 Finder
|
|
1006
|
-
* @returns {T extends
|
|
1075
|
+
* @returns {T extends Finder ? Router : T}
|
|
1007
1076
|
*/
|
|
1008
1077
|
/**
|
|
1009
1078
|
*
|
|
1010
1079
|
* @param {(Route | RouterRoute)[]} routes
|
|
1011
|
-
* @param {string} path
|
|
1012
|
-
* @param {Router |
|
|
1080
|
+
* @param {string | [string[], any[]]} path
|
|
1081
|
+
* @param {Router | Finder} [r]
|
|
1013
1082
|
* @returns {Router}
|
|
1014
1083
|
*/
|
|
1015
1084
|
function bindRouter(routes, path, r) {
|
|
@@ -1024,18 +1093,18 @@ class ApiRouter extends Router {
|
|
|
1024
1093
|
#routes = [];
|
|
1025
1094
|
/**
|
|
1026
1095
|
* 添加子路由
|
|
1027
|
-
* @template {Router |
|
|
1096
|
+
* @template {Router | Finder} [T=ApiRouter]
|
|
1028
1097
|
* @overload
|
|
1029
1098
|
* @param {T} [router] 要注册的子路由或子路由的 Finder
|
|
1030
|
-
* @returns {T extends
|
|
1099
|
+
* @returns {T extends Finder ? Router : T}
|
|
1031
1100
|
*/
|
|
1032
1101
|
/**
|
|
1033
1102
|
* 添加子路由
|
|
1034
|
-
* @template {Router |
|
|
1103
|
+
* @template {Router | Finder} [T=ApiRouter]
|
|
1035
1104
|
* @overload
|
|
1036
1105
|
* @param {string} path 要注册的路径
|
|
1037
1106
|
* @param {T} [router] 要注册的子路由或子路由的 Finder
|
|
1038
|
-
* @returns {T extends
|
|
1107
|
+
* @returns {T extends Finder ? Router : T}
|
|
1039
1108
|
*/
|
|
1040
1109
|
/**
|
|
1041
1110
|
* 添加子路由
|
|
@@ -1052,12 +1121,11 @@ class ApiRouter extends Router {
|
|
|
1052
1121
|
route(...p) {
|
|
1053
1122
|
const [a] = p;
|
|
1054
1123
|
if (a && typeof a === 'object' && !(a instanceof Router)) {
|
|
1055
|
-
const path = String.raw(a, ...p.slice(1));
|
|
1056
1124
|
/**
|
|
1057
|
-
* @param {
|
|
1125
|
+
* @param { Finder | Router} [r];
|
|
1058
1126
|
* @returns {any}
|
|
1059
1127
|
*/
|
|
1060
|
-
return r => bindRouter(this.#routes,
|
|
1128
|
+
return r => bindRouter(this.#routes, [a, p.slice(1)], r);
|
|
1061
1129
|
}
|
|
1062
1130
|
const path = typeof a === 'string' ? a : '';
|
|
1063
1131
|
const r = typeof a === 'string' ? p[1] : a;
|
|
@@ -1065,10 +1133,10 @@ class ApiRouter extends Router {
|
|
|
1065
1133
|
}
|
|
1066
1134
|
/**
|
|
1067
1135
|
*
|
|
1068
|
-
* @param {
|
|
1136
|
+
* @param {Method} method
|
|
1069
1137
|
* @param {string[]} path
|
|
1070
|
-
* @param {
|
|
1071
|
-
* @returns {Iterable<
|
|
1138
|
+
* @param {Context} ctx
|
|
1139
|
+
* @returns {Iterable<FindItem>}
|
|
1072
1140
|
*/
|
|
1073
1141
|
*find(method, path, ctx) {
|
|
1074
1142
|
for (const route of Array.from(this.#routes)) {
|
|
@@ -1089,29 +1157,29 @@ class ApiRouter extends Router {
|
|
|
1089
1157
|
/**
|
|
1090
1158
|
* 注册处理函数
|
|
1091
1159
|
* @overload
|
|
1092
|
-
* @param {
|
|
1093
|
-
* @param {
|
|
1160
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
|
|
1161
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1094
1162
|
* @returns {() => void}
|
|
1095
1163
|
*/
|
|
1096
1164
|
/**
|
|
1097
1165
|
* 注册处理函数
|
|
1098
1166
|
* @overload
|
|
1099
|
-
* @param {
|
|
1167
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
|
|
1100
1168
|
* @param {string} path 要注册的路径
|
|
1101
|
-
* @param {
|
|
1169
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1102
1170
|
* @returns {() => void}
|
|
1103
1171
|
*/
|
|
1104
1172
|
/**
|
|
1105
1173
|
* 注册处理函数
|
|
1106
1174
|
* @overload
|
|
1107
|
-
* @param {
|
|
1175
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} method 要注册的方法
|
|
1108
1176
|
* @param {string} path 要注册的路径
|
|
1109
1177
|
* @returns {Binder}
|
|
1110
1178
|
*/
|
|
1111
1179
|
/**
|
|
1112
|
-
* @param {
|
|
1113
|
-
* @param {string|
|
|
1114
|
-
* @param {
|
|
1180
|
+
* @param {Method | Iterable<Method> | ArrayLike<Method>} methods
|
|
1181
|
+
* @param {string| Handler} [path]
|
|
1182
|
+
* @param {Handler} [handler]
|
|
1115
1183
|
* @returns {Binder | (() => void)}
|
|
1116
1184
|
*/
|
|
1117
1185
|
verb(methods, path, handler) {
|
|
@@ -1122,14 +1190,14 @@ class ApiRouter extends Router {
|
|
|
1122
1190
|
/**
|
|
1123
1191
|
* 注册 HTTP GET/POST/PUT/DELETE 处理函数
|
|
1124
1192
|
* @overload
|
|
1125
|
-
* @param {
|
|
1193
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1126
1194
|
* @returns {() => void}
|
|
1127
1195
|
*/
|
|
1128
1196
|
/**
|
|
1129
1197
|
* 注册处理函数
|
|
1130
1198
|
* @overload
|
|
1131
1199
|
* @param {string} path 要注册的路径
|
|
1132
|
-
* @param {
|
|
1200
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1133
1201
|
* @returns {() => void}
|
|
1134
1202
|
*/
|
|
1135
1203
|
/**
|
|
@@ -1155,14 +1223,14 @@ class ApiRouter extends Router {
|
|
|
1155
1223
|
/**
|
|
1156
1224
|
* 注册 HTTP GET 处理函数
|
|
1157
1225
|
* @overload
|
|
1158
|
-
* @param {
|
|
1226
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1159
1227
|
* @returns {() => void}
|
|
1160
1228
|
*/
|
|
1161
1229
|
/**
|
|
1162
1230
|
* 注册 HTTP GET 处理函数
|
|
1163
1231
|
* @overload
|
|
1164
1232
|
* @param {string} path 要注册的路径
|
|
1165
|
-
* @param {
|
|
1233
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1166
1234
|
* @returns {() => void}
|
|
1167
1235
|
*/
|
|
1168
1236
|
/**
|
|
@@ -1186,14 +1254,14 @@ class ApiRouter extends Router {
|
|
|
1186
1254
|
/**
|
|
1187
1255
|
* 注册 HTTP POST 处理函数
|
|
1188
1256
|
* @overload
|
|
1189
|
-
* @param {
|
|
1257
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1190
1258
|
* @returns {() => void}
|
|
1191
1259
|
*/
|
|
1192
1260
|
/**
|
|
1193
1261
|
* 注册 HTTP POST 处理函数
|
|
1194
1262
|
* @overload
|
|
1195
1263
|
* @param {string} path 要注册的路径
|
|
1196
|
-
* @param {
|
|
1264
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1197
1265
|
* @returns {() => void}
|
|
1198
1266
|
*/
|
|
1199
1267
|
/**
|
|
@@ -1217,14 +1285,14 @@ class ApiRouter extends Router {
|
|
|
1217
1285
|
/**
|
|
1218
1286
|
* 注册 HTTP PUT 处理函数
|
|
1219
1287
|
* @overload
|
|
1220
|
-
* @param {
|
|
1288
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1221
1289
|
* @returns {() => void}
|
|
1222
1290
|
*/
|
|
1223
1291
|
/**
|
|
1224
1292
|
* 注册 HTTP PUT 处理函数
|
|
1225
1293
|
* @overload
|
|
1226
1294
|
* @param {string} path 要注册的路径
|
|
1227
|
-
* @param {
|
|
1295
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1228
1296
|
* @returns {() => void}
|
|
1229
1297
|
*/
|
|
1230
1298
|
/**
|
|
@@ -1248,14 +1316,14 @@ class ApiRouter extends Router {
|
|
|
1248
1316
|
/**
|
|
1249
1317
|
* 注册 HTTP DELETE 处理函数
|
|
1250
1318
|
* @overload
|
|
1251
|
-
* @param {
|
|
1319
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1252
1320
|
* @returns {() => void}
|
|
1253
1321
|
*/
|
|
1254
1322
|
/**
|
|
1255
1323
|
* 注册 HTTP DELETE 处理函数
|
|
1256
1324
|
* @overload
|
|
1257
1325
|
* @param {string} path 要注册的路径
|
|
1258
|
-
* @param {
|
|
1326
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1259
1327
|
* @returns {() => void}
|
|
1260
1328
|
*/
|
|
1261
1329
|
/**
|
|
@@ -1279,14 +1347,14 @@ class ApiRouter extends Router {
|
|
|
1279
1347
|
/**
|
|
1280
1348
|
* 注册 HTTP HEAD 处理函数
|
|
1281
1349
|
* @overload
|
|
1282
|
-
* @param {
|
|
1350
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1283
1351
|
* @returns {() => void}
|
|
1284
1352
|
*/
|
|
1285
1353
|
/**
|
|
1286
1354
|
* 注册 HTTP HEAD 处理函数
|
|
1287
1355
|
* @overload
|
|
1288
1356
|
* @param {string} path 要注册的路径
|
|
1289
|
-
* @param {
|
|
1357
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1290
1358
|
* @returns {() => void}
|
|
1291
1359
|
*/
|
|
1292
1360
|
/**
|
|
@@ -1310,14 +1378,14 @@ class ApiRouter extends Router {
|
|
|
1310
1378
|
/**
|
|
1311
1379
|
* 注册 HTTP OPTIONS 处理函数
|
|
1312
1380
|
* @overload
|
|
1313
|
-
* @param {
|
|
1381
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1314
1382
|
* @returns {() => void}
|
|
1315
1383
|
*/
|
|
1316
1384
|
/**
|
|
1317
1385
|
* 注册 HTTP OPTIONS 处理函数
|
|
1318
1386
|
* @overload
|
|
1319
1387
|
* @param {string} path 要注册的路径
|
|
1320
|
-
* @param {
|
|
1388
|
+
* @param {Handler} handler 要注册的处理函数
|
|
1321
1389
|
* @returns {() => void}
|
|
1322
1390
|
*/
|
|
1323
1391
|
/**
|
|
@@ -1363,21 +1431,22 @@ function createFetch(run, notFound) {
|
|
|
1363
1431
|
};
|
|
1364
1432
|
}
|
|
1365
1433
|
|
|
1434
|
+
/** @import { Context, Handler, HandlerResult } from './main/types' */
|
|
1366
1435
|
/**
|
|
1367
1436
|
* @callback Onionskin
|
|
1368
|
-
* @param {
|
|
1369
|
-
* @param {() => Promise<
|
|
1370
|
-
* @returns {PromiseLike<
|
|
1437
|
+
* @param {Context} ctx
|
|
1438
|
+
* @param {() => Promise<HandlerResult>} next
|
|
1439
|
+
* @returns {PromiseLike<HandlerResult> | HandlerResult}
|
|
1371
1440
|
*/
|
|
1372
1441
|
|
|
1373
1442
|
const noop = () => {};
|
|
1374
1443
|
/**
|
|
1375
1444
|
*
|
|
1376
1445
|
* @param {...(Onionskin | Onionskin[])} handlers
|
|
1377
|
-
* @returns {
|
|
1446
|
+
* @returns {Handler}
|
|
1378
1447
|
*/
|
|
1379
1448
|
function onionskin(...handlers) {
|
|
1380
|
-
/** @type {
|
|
1449
|
+
/** @type {Handler} */
|
|
1381
1450
|
let handler = noop;
|
|
1382
1451
|
for (const os of handlers.flat()) {
|
|
1383
1452
|
const currentHandler = handler;
|
|
@@ -1386,7 +1455,44 @@ function onionskin(...handlers) {
|
|
|
1386
1455
|
return handler;
|
|
1387
1456
|
}
|
|
1388
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
|
+
|
|
1389
1494
|
exports.ApiRouter = ApiRouter;
|
|
1495
|
+
exports.Param = Param;
|
|
1390
1496
|
exports.Router = Router;
|
|
1391
1497
|
exports.createFetch = createFetch;
|
|
1392
1498
|
exports.main = main;
|