@ozanarslan/corpus 0.1.4 → 0.1.6
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/README.md +24 -25
- package/dist/index.cjs +2014 -0
- package/dist/index.d.ts +389 -226
- package/dist/index.js +1012 -527
- package/package.json +19 -6
package/dist/index.js
CHANGED
|
@@ -14,23 +14,51 @@ var __export = (target, all) => {
|
|
|
14
14
|
});
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
// src/
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
// src/Store/StoreAbstract.ts
|
|
18
|
+
class StoreAbstract {
|
|
19
|
+
set(value) {
|
|
20
|
+
this.value = value;
|
|
21
|
+
}
|
|
22
|
+
get() {
|
|
23
|
+
return this.value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/Store/globals/GlobalPrefixStore.ts
|
|
28
|
+
class GlobalPrefixStore extends StoreAbstract {
|
|
29
|
+
value = "";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/Store/globals/GlobalRouterStore.ts
|
|
33
|
+
class GlobalRouterStore extends StoreAbstract {
|
|
34
|
+
value = null;
|
|
35
|
+
get() {
|
|
36
|
+
if (!this.value) {
|
|
37
|
+
console.error("Router instance is not set. Please instantiate your Server before your routes.");
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
return this.value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/Store/globals/GlobalCorsStore.ts
|
|
45
|
+
class GlobalCorsStore extends StoreAbstract {
|
|
46
|
+
value = null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/C.ts
|
|
50
|
+
var exports_C = {};
|
|
51
|
+
__export(exports_C, {
|
|
20
52
|
Status: () => Status,
|
|
21
53
|
StaticRoute: () => StaticRoute,
|
|
22
54
|
Server: () => Server,
|
|
23
55
|
Route: () => Route,
|
|
24
|
-
Response: () =>
|
|
25
|
-
Request: () =>
|
|
26
|
-
Repository: () => RepositoryAbstract,
|
|
27
|
-
Parser: () => Parser,
|
|
56
|
+
Response: () => CResponse,
|
|
57
|
+
Request: () => CRequest,
|
|
28
58
|
Middleware: () => Middleware,
|
|
29
59
|
Method: () => Method,
|
|
30
|
-
Headers: () =>
|
|
31
|
-
|
|
32
|
-
Error: () => HttpError,
|
|
33
|
-
DefaultStatusTexts: () => DefaultStatusTexts,
|
|
60
|
+
Headers: () => CHeaders,
|
|
61
|
+
Error: () => CError,
|
|
34
62
|
Cookies: () => Cookies,
|
|
35
63
|
Controller: () => ControllerAbstract,
|
|
36
64
|
Context: () => Context,
|
|
@@ -106,7 +134,7 @@ class Config {
|
|
|
106
134
|
this.env[key] = value;
|
|
107
135
|
}
|
|
108
136
|
}
|
|
109
|
-
// src/
|
|
137
|
+
// src/CResponse/enums/Status.ts
|
|
110
138
|
var Status = {
|
|
111
139
|
CONTINUE: 100,
|
|
112
140
|
SWITCHING_PROTOCOLS: 101,
|
|
@@ -172,7 +200,7 @@ var Status = {
|
|
|
172
200
|
NETWORK_AUTHENTICATION_REQUIRED: 511
|
|
173
201
|
};
|
|
174
202
|
|
|
175
|
-
// src/
|
|
203
|
+
// src/CResponse/enums/DefaultStatusTexts.ts
|
|
176
204
|
var DefaultStatusTexts = {
|
|
177
205
|
[Status.OK]: "OK",
|
|
178
206
|
[Status.CREATED]: "Created",
|
|
@@ -189,11 +217,12 @@ var DefaultStatusTexts = {
|
|
|
189
217
|
[Status.INTERNAL_SERVER_ERROR]: "Internal Server Error"
|
|
190
218
|
};
|
|
191
219
|
|
|
192
|
-
// src/
|
|
220
|
+
// src/CHeaders/enums/CommonHeaders.ts
|
|
193
221
|
var CommonHeaders = {
|
|
194
222
|
CacheControl: "Cache-Control",
|
|
195
223
|
ContentType: "Content-Type",
|
|
196
224
|
ContentLength: "Content-Length",
|
|
225
|
+
ContentDisposition: "Content-Disposition",
|
|
197
226
|
AcceptEncoding: "Accept-Encoding",
|
|
198
227
|
Accept: "Accept",
|
|
199
228
|
Authorization: "Authorization",
|
|
@@ -283,8 +312,8 @@ class CookiesUsingBun extends CookiesAbstract {
|
|
|
283
312
|
class Cookies extends CookiesUsingBun {
|
|
284
313
|
}
|
|
285
314
|
|
|
286
|
-
// src/
|
|
287
|
-
class
|
|
315
|
+
// src/CHeaders/CHeaders.ts
|
|
316
|
+
class CHeaders extends Headers {
|
|
288
317
|
constructor(init) {
|
|
289
318
|
super(init);
|
|
290
319
|
}
|
|
@@ -314,7 +343,7 @@ class HttpHeaders extends Headers {
|
|
|
314
343
|
return target;
|
|
315
344
|
}
|
|
316
345
|
innerCombine(source) {
|
|
317
|
-
|
|
346
|
+
CHeaders.combine(source, this);
|
|
318
347
|
}
|
|
319
348
|
setMany(init) {
|
|
320
349
|
const entries = Array.isArray(init) ? init : Object.entries(init);
|
|
@@ -325,7 +354,7 @@ class HttpHeaders extends Headers {
|
|
|
325
354
|
}
|
|
326
355
|
}
|
|
327
356
|
static findHeaderInInit(init, name) {
|
|
328
|
-
if (init instanceof
|
|
357
|
+
if (init instanceof CHeaders || init instanceof Headers) {
|
|
329
358
|
return init.get(name);
|
|
330
359
|
} else if (Array.isArray(init)) {
|
|
331
360
|
return init.find((entry) => entry[0] === name)?.[1] ?? null;
|
|
@@ -335,19 +364,139 @@ class HttpHeaders extends Headers {
|
|
|
335
364
|
}
|
|
336
365
|
}
|
|
337
366
|
|
|
338
|
-
// src/
|
|
339
|
-
|
|
340
|
-
|
|
367
|
+
// src/utils/isNil.ts
|
|
368
|
+
function isNil(input) {
|
|
369
|
+
return input === null || input === undefined;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// src/utils/isPrimitive.ts
|
|
373
|
+
function isPrimitive(input) {
|
|
374
|
+
return typeof input === "string" || typeof input === "number" || typeof input === "boolean" || typeof input === "bigint";
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/utils/isPlainObject.ts
|
|
378
|
+
function isPlainObject(input) {
|
|
379
|
+
return typeof input === "object" && input !== null && input.constructor === Object;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// src/CError/CError.ts
|
|
383
|
+
class CError extends Error {
|
|
384
|
+
message;
|
|
385
|
+
status;
|
|
386
|
+
data;
|
|
387
|
+
constructor(message, status, data) {
|
|
388
|
+
super(message);
|
|
389
|
+
this.message = message;
|
|
390
|
+
this.status = status;
|
|
391
|
+
this.data = data;
|
|
392
|
+
}
|
|
393
|
+
toResponse() {
|
|
394
|
+
return new CResponse(this.data ? { error: this.data, message: this.message } : { error: true, message: this.message }, { status: this.status });
|
|
395
|
+
}
|
|
396
|
+
isStatusOf(status) {
|
|
397
|
+
return this.status === status;
|
|
398
|
+
}
|
|
399
|
+
static internalServerError(msg) {
|
|
400
|
+
const status = Status.INTERNAL_SERVER_ERROR;
|
|
401
|
+
return new this(msg ?? status.toString(), status);
|
|
402
|
+
}
|
|
403
|
+
static badRequest(msg) {
|
|
404
|
+
const status = Status.BAD_REQUEST;
|
|
405
|
+
return new this(msg ?? status.toString(), status);
|
|
406
|
+
}
|
|
407
|
+
static notFound(msg) {
|
|
408
|
+
const status = Status.NOT_FOUND;
|
|
409
|
+
return new this(msg ?? status.toString(), status);
|
|
410
|
+
}
|
|
411
|
+
static methodNotAllowed(msg) {
|
|
412
|
+
const status = Status.METHOD_NOT_ALLOWED;
|
|
413
|
+
return new this(msg ?? status.toString(), status);
|
|
414
|
+
}
|
|
415
|
+
static unprocessableEntity(msg) {
|
|
416
|
+
const status = Status.UNPROCESSABLE_ENTITY;
|
|
417
|
+
return new this(msg ?? status.toString(), status);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// src/XFile/XFileAbstract.ts
|
|
422
|
+
class XFileAbstract {
|
|
423
|
+
path;
|
|
424
|
+
fallbackExtension;
|
|
425
|
+
constructor(path2, fallbackExtension) {
|
|
426
|
+
this.path = path2;
|
|
427
|
+
this.fallbackExtension = fallbackExtension;
|
|
428
|
+
}
|
|
429
|
+
get name() {
|
|
430
|
+
return this.path.split("/").pop() ?? this.path;
|
|
431
|
+
}
|
|
432
|
+
get extension() {
|
|
433
|
+
return this.path.split(".").pop() ?? this.fallbackExtension ?? "txt";
|
|
434
|
+
}
|
|
435
|
+
get mimeType() {
|
|
436
|
+
const mimeTypes = {
|
|
437
|
+
html: "text/html",
|
|
438
|
+
htm: "text/html",
|
|
439
|
+
css: "text/css",
|
|
440
|
+
js: "application/javascript",
|
|
441
|
+
ts: "application/javascript",
|
|
442
|
+
mjs: "application/javascript",
|
|
443
|
+
json: "application/json",
|
|
444
|
+
png: "image/png",
|
|
445
|
+
jpg: "image/jpeg",
|
|
446
|
+
jpeg: "image/jpeg",
|
|
447
|
+
gif: "image/gif",
|
|
448
|
+
svg: "image/svg+xml",
|
|
449
|
+
ico: "image/x-icon",
|
|
450
|
+
txt: "text/plain",
|
|
451
|
+
xml: "application/xml",
|
|
452
|
+
pdf: "application/pdf",
|
|
453
|
+
zip: "application/zip",
|
|
454
|
+
mp3: "audio/mpeg",
|
|
455
|
+
mp4: "video/mp4",
|
|
456
|
+
webm: "video/webm",
|
|
457
|
+
woff: "font/woff",
|
|
458
|
+
woff2: "font/woff2",
|
|
459
|
+
ttf: "font/ttf"
|
|
460
|
+
};
|
|
461
|
+
return mimeTypes[this.extension] ?? "application/octet-stream";
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// src/XFile/XFileUsingBun.ts
|
|
466
|
+
class XFileUsingBun extends XFileAbstract {
|
|
467
|
+
constructor(...args) {
|
|
468
|
+
super(...args);
|
|
469
|
+
this.file = Bun.file(args[0]);
|
|
470
|
+
}
|
|
471
|
+
file;
|
|
472
|
+
async exists() {
|
|
473
|
+
return await this.file.exists();
|
|
474
|
+
}
|
|
475
|
+
async text() {
|
|
476
|
+
return await this.file.text();
|
|
477
|
+
}
|
|
478
|
+
stream() {
|
|
479
|
+
return this.file.stream();
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/XFile/XFile.ts
|
|
484
|
+
class XFile extends XFileUsingBun {
|
|
485
|
+
}
|
|
486
|
+
// src/CResponse/CResponse.ts
|
|
487
|
+
class CResponse {
|
|
488
|
+
data;
|
|
341
489
|
init;
|
|
342
|
-
constructor(
|
|
343
|
-
this.
|
|
490
|
+
constructor(data, init) {
|
|
491
|
+
this.data = data;
|
|
344
492
|
this.init = init;
|
|
345
|
-
this.cookies = this.
|
|
346
|
-
this.headers = this.
|
|
347
|
-
this.body = this.
|
|
348
|
-
this.status = this.
|
|
493
|
+
this.cookies = this.resolveCookies();
|
|
494
|
+
this.headers = this.resolveHeaders();
|
|
495
|
+
this.body = this.resolveBody();
|
|
496
|
+
this.status = this.resolveStatus();
|
|
349
497
|
this.statusText = this.getDefaultStatusText();
|
|
350
498
|
}
|
|
499
|
+
body;
|
|
351
500
|
headers;
|
|
352
501
|
status;
|
|
353
502
|
statusText;
|
|
@@ -359,11 +508,126 @@ class HttpResponse {
|
|
|
359
508
|
headers: this.headers
|
|
360
509
|
});
|
|
361
510
|
}
|
|
362
|
-
|
|
511
|
+
static redirect(url, init) {
|
|
512
|
+
const res = new CResponse(undefined, {
|
|
513
|
+
...init,
|
|
514
|
+
status: init?.status ?? Status.FOUND,
|
|
515
|
+
statusText: init?.statusText ?? DefaultStatusTexts[Status.FOUND]
|
|
516
|
+
});
|
|
517
|
+
const urlString = url instanceof URL ? url.toString() : url;
|
|
518
|
+
res.headers.set(CommonHeaders.Location, urlString);
|
|
519
|
+
return res;
|
|
520
|
+
}
|
|
521
|
+
static permanentRedirect(url, init) {
|
|
522
|
+
return this.redirect(url, {
|
|
523
|
+
...init,
|
|
524
|
+
status: Status.MOVED_PERMANENTLY
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
static temporaryRedirect(url, init) {
|
|
528
|
+
return this.redirect(url, { ...init, status: Status.TEMPORARY_REDIRECT });
|
|
529
|
+
}
|
|
530
|
+
static seeOther(url, init) {
|
|
531
|
+
return this.redirect(url, { ...init, status: Status.SEE_OTHER });
|
|
532
|
+
}
|
|
533
|
+
static createStream(execute) {
|
|
534
|
+
let cancelled = false;
|
|
535
|
+
let cleanup;
|
|
536
|
+
return new ReadableStream({
|
|
537
|
+
start(controller) {
|
|
538
|
+
try {
|
|
539
|
+
cleanup = execute(controller, () => cancelled);
|
|
540
|
+
if (typeof cleanup !== "function") {
|
|
541
|
+
controller.close();
|
|
542
|
+
}
|
|
543
|
+
} catch (err) {
|
|
544
|
+
controller.error(err);
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
cancel() {
|
|
548
|
+
cancelled = true;
|
|
549
|
+
cleanup?.();
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
static sse(source, init, retry) {
|
|
554
|
+
const encoder = new TextEncoder;
|
|
555
|
+
const stream = CResponse.createStream((controller, isCancelled) => {
|
|
556
|
+
return source((event) => {
|
|
557
|
+
if (isCancelled())
|
|
558
|
+
return;
|
|
559
|
+
let chunk = "";
|
|
560
|
+
if (retry !== undefined)
|
|
561
|
+
chunk += `retry: ${retry}
|
|
562
|
+
`;
|
|
563
|
+
if (event.id)
|
|
564
|
+
chunk += `id: ${event.id}
|
|
565
|
+
`;
|
|
566
|
+
if (event.event)
|
|
567
|
+
chunk += `event: ${event.event}
|
|
568
|
+
`;
|
|
569
|
+
chunk += `data: ${JSON.stringify(event.data)}
|
|
570
|
+
|
|
571
|
+
`;
|
|
572
|
+
controller.enqueue(encoder.encode(chunk));
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
const res = new CResponse(stream, { ...init, status: Status.OK });
|
|
576
|
+
res.headers.setMany({
|
|
577
|
+
[CommonHeaders.ContentType]: "text/event-stream",
|
|
578
|
+
[CommonHeaders.CacheControl]: "no-cache",
|
|
579
|
+
[CommonHeaders.Connection]: "keep-alive"
|
|
580
|
+
});
|
|
581
|
+
return res;
|
|
582
|
+
}
|
|
583
|
+
static ndjson(source, init) {
|
|
584
|
+
const encoder = new TextEncoder;
|
|
585
|
+
const stream = CResponse.createStream((controller, isCancelled) => {
|
|
586
|
+
return source((item) => {
|
|
587
|
+
if (isCancelled())
|
|
588
|
+
return;
|
|
589
|
+
controller.enqueue(encoder.encode(`${JSON.stringify(item)}
|
|
590
|
+
`));
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
const res = new CResponse(stream, { ...init, status: Status.OK });
|
|
594
|
+
res.headers.setMany({
|
|
595
|
+
[CommonHeaders.ContentType]: "application/x-ndjson",
|
|
596
|
+
[CommonHeaders.CacheControl]: "no-cache"
|
|
597
|
+
});
|
|
598
|
+
return res;
|
|
599
|
+
}
|
|
600
|
+
static async streamFile(filePath, disposition = "attachment", init) {
|
|
601
|
+
const file = new XFile(filePath);
|
|
602
|
+
if (!file) {
|
|
603
|
+
throw CError.notFound();
|
|
604
|
+
}
|
|
605
|
+
const stream = file.stream();
|
|
606
|
+
const res = new CResponse(stream, { ...init, status: Status.OK });
|
|
607
|
+
res.headers.setMany({
|
|
608
|
+
[CommonHeaders.ContentType]: file.mimeType,
|
|
609
|
+
[CommonHeaders.ContentDisposition]: `${disposition}; filename="${file.name}"`
|
|
610
|
+
});
|
|
611
|
+
return res;
|
|
612
|
+
}
|
|
613
|
+
static async file(filePath, init) {
|
|
614
|
+
const file = new XFile(filePath);
|
|
615
|
+
if (!file) {
|
|
616
|
+
throw CError.notFound();
|
|
617
|
+
}
|
|
618
|
+
const content = await file.text();
|
|
619
|
+
const res = new CResponse(content, init);
|
|
620
|
+
res.headers.setMany({
|
|
621
|
+
[CommonHeaders.ContentType]: file.mimeType,
|
|
622
|
+
[CommonHeaders.ContentLength]: content.length.toString()
|
|
623
|
+
});
|
|
624
|
+
return res;
|
|
625
|
+
}
|
|
626
|
+
resolveCookies() {
|
|
363
627
|
return new Cookies(this.init?.cookies);
|
|
364
628
|
}
|
|
365
|
-
|
|
366
|
-
const headers = new
|
|
629
|
+
resolveHeaders() {
|
|
630
|
+
const headers = new CHeaders(this.init?.headers);
|
|
367
631
|
const setCookieHeaders = this.cookies.toSetCookieHeaders();
|
|
368
632
|
if (setCookieHeaders.length > 0) {
|
|
369
633
|
for (const header of setCookieHeaders) {
|
|
@@ -372,7 +636,7 @@ class HttpResponse {
|
|
|
372
636
|
}
|
|
373
637
|
return headers;
|
|
374
638
|
}
|
|
375
|
-
|
|
639
|
+
resolveStatus() {
|
|
376
640
|
if (this.init?.status)
|
|
377
641
|
return this.init.status;
|
|
378
642
|
if (this.headers.has(CommonHeaders.Location)) {
|
|
@@ -385,58 +649,53 @@ class HttpResponse {
|
|
|
385
649
|
this.headers.set(CommonHeaders.ContentType, value);
|
|
386
650
|
}
|
|
387
651
|
}
|
|
388
|
-
|
|
389
|
-
if (this.
|
|
652
|
+
resolveBody() {
|
|
653
|
+
if (isNil(this.data)) {
|
|
390
654
|
this.setContentType("text/plain");
|
|
391
655
|
return "";
|
|
392
656
|
}
|
|
393
|
-
if (
|
|
657
|
+
if (isPrimitive(this.data)) {
|
|
394
658
|
this.setContentType("text/plain");
|
|
395
|
-
return String(this.
|
|
659
|
+
return String(this.data);
|
|
660
|
+
}
|
|
661
|
+
if (this.data instanceof ArrayBuffer) {
|
|
662
|
+
this.setContentType("application/octet-stream");
|
|
663
|
+
return this.data;
|
|
664
|
+
}
|
|
665
|
+
if (this.data instanceof Blob) {
|
|
666
|
+
if (this.data.type)
|
|
667
|
+
this.setContentType(this.data.type);
|
|
668
|
+
return this.data;
|
|
669
|
+
}
|
|
670
|
+
if (this.data instanceof FormData) {
|
|
671
|
+
this.setContentType("multipart/form-data");
|
|
672
|
+
return this.data;
|
|
673
|
+
}
|
|
674
|
+
if (this.data instanceof URLSearchParams) {
|
|
675
|
+
this.setContentType("application/x-www-form-urlencoded");
|
|
676
|
+
return this.data;
|
|
396
677
|
}
|
|
397
|
-
if (this.
|
|
398
|
-
|
|
678
|
+
if (this.data instanceof ReadableStream) {
|
|
679
|
+
return this.data;
|
|
399
680
|
}
|
|
400
|
-
if (this.
|
|
681
|
+
if (this.data instanceof Date) {
|
|
401
682
|
this.setContentType("text/plain");
|
|
402
|
-
return this.
|
|
683
|
+
return this.data.toISOString();
|
|
403
684
|
}
|
|
404
|
-
if (Array.isArray(this.
|
|
685
|
+
if (Array.isArray(this.data) || isPlainObject(this.data)) {
|
|
405
686
|
this.setContentType("application/json");
|
|
406
|
-
return JSON.stringify(this.
|
|
687
|
+
return JSON.stringify(this.data);
|
|
407
688
|
}
|
|
408
689
|
this.setContentType("text/plain");
|
|
409
|
-
return String(this.
|
|
690
|
+
return String(this.data);
|
|
410
691
|
}
|
|
411
692
|
getDefaultStatusText() {
|
|
412
693
|
const key = this.status;
|
|
413
694
|
return DefaultStatusTexts[key] ?? "Unknown";
|
|
414
695
|
}
|
|
415
|
-
static redirect(url, init) {
|
|
416
|
-
const res = new HttpResponse(undefined, {
|
|
417
|
-
...init,
|
|
418
|
-
status: init?.status ?? Status.FOUND,
|
|
419
|
-
statusText: init?.statusText ?? DefaultStatusTexts[Status.FOUND]
|
|
420
|
-
});
|
|
421
|
-
const urlString = url instanceof URL ? url.toString() : url;
|
|
422
|
-
res.headers.set(CommonHeaders.Location, urlString);
|
|
423
|
-
return res;
|
|
424
|
-
}
|
|
425
|
-
static permanentRedirect(url, init) {
|
|
426
|
-
return this.redirect(url, {
|
|
427
|
-
...init,
|
|
428
|
-
status: Status.MOVED_PERMANENTLY
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
static temporaryRedirect(url, init) {
|
|
432
|
-
return this.redirect(url, { ...init, status: Status.TEMPORARY_REDIRECT });
|
|
433
|
-
}
|
|
434
|
-
static seeOther(url, init) {
|
|
435
|
-
return this.redirect(url, { ...init, status: Status.SEE_OTHER });
|
|
436
|
-
}
|
|
437
696
|
}
|
|
438
697
|
|
|
439
|
-
// src/
|
|
698
|
+
// src/CRequest/enums/Method.ts
|
|
440
699
|
var Method = {
|
|
441
700
|
GET: "GET",
|
|
442
701
|
POST: "POST",
|
|
@@ -449,45 +708,6 @@ var Method = {
|
|
|
449
708
|
TRACE: "TRACE"
|
|
450
709
|
};
|
|
451
710
|
|
|
452
|
-
// src/Error/HttpError.ts
|
|
453
|
-
class HttpError extends Error {
|
|
454
|
-
message;
|
|
455
|
-
status;
|
|
456
|
-
data;
|
|
457
|
-
constructor(message, status, data) {
|
|
458
|
-
super(message);
|
|
459
|
-
this.message = message;
|
|
460
|
-
this.status = status;
|
|
461
|
-
this.data = data;
|
|
462
|
-
}
|
|
463
|
-
toResponse() {
|
|
464
|
-
return new HttpResponse(this.data ? { error: this.data, message: this.message } : { error: true, message: this.message }, { status: this.status });
|
|
465
|
-
}
|
|
466
|
-
isStatusOf(status) {
|
|
467
|
-
return this.status === status;
|
|
468
|
-
}
|
|
469
|
-
static internalServerError(msg) {
|
|
470
|
-
const status = Status.INTERNAL_SERVER_ERROR;
|
|
471
|
-
return new this(msg ?? status.toString(), status);
|
|
472
|
-
}
|
|
473
|
-
static badRequest(msg) {
|
|
474
|
-
const status = Status.BAD_REQUEST;
|
|
475
|
-
return new this(msg ?? status.toString(), status);
|
|
476
|
-
}
|
|
477
|
-
static notFound(msg) {
|
|
478
|
-
const status = Status.NOT_FOUND;
|
|
479
|
-
return new this(msg ?? status.toString(), status);
|
|
480
|
-
}
|
|
481
|
-
static methodNotAllowed(msg) {
|
|
482
|
-
const status = Status.METHOD_NOT_ALLOWED;
|
|
483
|
-
return new this(msg ?? status.toString(), status);
|
|
484
|
-
}
|
|
485
|
-
static unprocessableEntity(msg) {
|
|
486
|
-
const status = Status.UNPROCESSABLE_ENTITY;
|
|
487
|
-
return new this(msg ?? status.toString(), status);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
711
|
// src/utils/arrIncludes.ts
|
|
492
712
|
function arrIncludes(input, array) {
|
|
493
713
|
return array.includes(input);
|
|
@@ -516,7 +736,7 @@ class Parser {
|
|
|
516
736
|
const result = await validate(data);
|
|
517
737
|
if (result.issues !== undefined) {
|
|
518
738
|
const msg = this.issuesToErrorMessage(result.issues);
|
|
519
|
-
throw
|
|
739
|
+
throw CError.unprocessableEntity(msg);
|
|
520
740
|
}
|
|
521
741
|
return result.value;
|
|
522
742
|
}
|
|
@@ -532,14 +752,14 @@ class Parser {
|
|
|
532
752
|
}).join(`
|
|
533
753
|
`);
|
|
534
754
|
}
|
|
535
|
-
static async
|
|
755
|
+
static async parseUrlData(params, validate) {
|
|
536
756
|
const data = {};
|
|
537
|
-
for (const [key, value] of
|
|
538
|
-
data[key] =
|
|
757
|
+
for (const [key, value] of Object.entries(params)) {
|
|
758
|
+
data[key] = decodeURIComponent(value);
|
|
539
759
|
}
|
|
540
760
|
return await this.parse(data, validate);
|
|
541
761
|
}
|
|
542
|
-
static async
|
|
762
|
+
static async parseBody(r, validate) {
|
|
543
763
|
let data;
|
|
544
764
|
const empty = {};
|
|
545
765
|
const input = r instanceof Request ? r : r instanceof Response ? r : r.response;
|
|
@@ -566,7 +786,7 @@ class Parser {
|
|
|
566
786
|
case "image":
|
|
567
787
|
case "audio":
|
|
568
788
|
case "video":
|
|
569
|
-
throw new
|
|
789
|
+
throw new CError("unprocessable.contentType", Status.UNPROCESSABLE_ENTITY);
|
|
570
790
|
case "no-body-allowed":
|
|
571
791
|
default:
|
|
572
792
|
return empty;
|
|
@@ -578,23 +798,6 @@ class Parser {
|
|
|
578
798
|
throw err;
|
|
579
799
|
}
|
|
580
800
|
}
|
|
581
|
-
static async getParams(endpoint, url, validate) {
|
|
582
|
-
const data = {};
|
|
583
|
-
if (!endpoint.includes(":")) {
|
|
584
|
-
return data;
|
|
585
|
-
}
|
|
586
|
-
const defParts = endpoint.split("/");
|
|
587
|
-
const reqParts = url.pathname.split("/");
|
|
588
|
-
for (const [i, defPart] of defParts.entries()) {
|
|
589
|
-
const reqPart = reqParts[i];
|
|
590
|
-
if (defPart.startsWith(":") && reqPart !== undefined) {
|
|
591
|
-
const key = defPart.slice(1);
|
|
592
|
-
const value = this.processString(decodeURIComponent(reqPart));
|
|
593
|
-
data[key] = value;
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
return await this.parse(data, validate);
|
|
597
|
-
}
|
|
598
801
|
static async getUnknownBody(input, validate) {
|
|
599
802
|
if (!validate) {
|
|
600
803
|
return await this.getTextBody(input);
|
|
@@ -616,7 +819,7 @@ class Parser {
|
|
|
616
819
|
const params = new URLSearchParams(text);
|
|
617
820
|
const body = {};
|
|
618
821
|
for (const [key, value] of params.entries()) {
|
|
619
|
-
objAppendEntry(body, key,
|
|
822
|
+
objAppendEntry(body, key, value);
|
|
620
823
|
}
|
|
621
824
|
return body;
|
|
622
825
|
}
|
|
@@ -628,7 +831,7 @@ class Parser {
|
|
|
628
831
|
if (value instanceof File) {
|
|
629
832
|
body[key] = value;
|
|
630
833
|
} else {
|
|
631
|
-
objAppendEntry(body, key,
|
|
834
|
+
objAppendEntry(body, key, value);
|
|
632
835
|
}
|
|
633
836
|
}
|
|
634
837
|
return body;
|
|
@@ -637,16 +840,14 @@ class Parser {
|
|
|
637
840
|
const contentLength = input.headers.get(CommonHeaders.ContentLength);
|
|
638
841
|
const length = contentLength ? parseInt(contentLength) : 0;
|
|
639
842
|
if (length > 0 && length < 1024 * 1024) {
|
|
640
|
-
|
|
641
|
-
return this.processString(text2);
|
|
843
|
+
return await input.text();
|
|
642
844
|
}
|
|
643
845
|
const buffer = await input.arrayBuffer();
|
|
644
846
|
const contentType = input.headers.get(CommonHeaders.ContentType) || "";
|
|
645
847
|
const match = contentType.match(/charset=([^;]+)/i);
|
|
646
848
|
const charset = match?.[1] ? match[1].trim() : null;
|
|
647
849
|
const decoder = new TextDecoder(charset || "utf-8");
|
|
648
|
-
|
|
649
|
-
return this.processString(text);
|
|
850
|
+
return decoder.decode(buffer);
|
|
650
851
|
}
|
|
651
852
|
static getNormalizedContentType(input) {
|
|
652
853
|
const contentTypeHeader = input.headers.get(CommonHeaders.ContentType) || "";
|
|
@@ -683,17 +884,6 @@ class Parser {
|
|
|
683
884
|
}
|
|
684
885
|
return "unknown";
|
|
685
886
|
}
|
|
686
|
-
static processString(value) {
|
|
687
|
-
let processedValue = value;
|
|
688
|
-
if (!strIsDefined(value))
|
|
689
|
-
return "";
|
|
690
|
-
if (/^-?\d+(\.\d+)?$/.test(value)) {
|
|
691
|
-
processedValue = Number(value);
|
|
692
|
-
} else if (value.toLowerCase() === "true" || value.toLowerCase() === "false") {
|
|
693
|
-
processedValue = value.toLowerCase() === "true";
|
|
694
|
-
}
|
|
695
|
-
return processedValue;
|
|
696
|
-
}
|
|
697
887
|
}
|
|
698
888
|
|
|
699
889
|
// src/Context/Context.ts
|
|
@@ -706,7 +896,7 @@ class Context {
|
|
|
706
896
|
this.body = body;
|
|
707
897
|
this.search = search;
|
|
708
898
|
this.params = params;
|
|
709
|
-
this.res = res ?? new
|
|
899
|
+
this.res = res ?? new CResponse;
|
|
710
900
|
}
|
|
711
901
|
req;
|
|
712
902
|
url;
|
|
@@ -720,10 +910,10 @@ class Context {
|
|
|
720
910
|
static makeFromRequest(req) {
|
|
721
911
|
return new Context(req, {}, {}, {});
|
|
722
912
|
}
|
|
723
|
-
static async appendParsedData(ctx, req,
|
|
724
|
-
ctx.body = await Parser.
|
|
725
|
-
ctx.
|
|
726
|
-
ctx.
|
|
913
|
+
static async appendParsedData(ctx, req, params, search, model) {
|
|
914
|
+
ctx.body = await Parser.parseBody(req, model?.body);
|
|
915
|
+
ctx.params = await Parser.parseUrlData(params, model?.params);
|
|
916
|
+
ctx.search = await Parser.parseUrlData(search, model?.search);
|
|
727
917
|
}
|
|
728
918
|
}
|
|
729
919
|
// src/Route/enums/RouteVariant.ts
|
|
@@ -738,15 +928,12 @@ function joinPathSegments(...segments) {
|
|
|
738
928
|
return `/${joined}`;
|
|
739
929
|
}
|
|
740
930
|
|
|
741
|
-
// src/Config/constants/_globalPrefixEnvKey.ts
|
|
742
|
-
var _globalPrefixEnvKey = "CORPUS_GLOBAL_PREFIX";
|
|
743
|
-
|
|
744
931
|
// src/Route/RouteAbstract.ts
|
|
745
932
|
class RouteAbstract {
|
|
746
933
|
resolveEndpoint(definition, variant) {
|
|
747
934
|
const endpoint = typeof definition === "string" ? definition : definition.path;
|
|
748
935
|
if (variant === RouteVariant.dynamic) {
|
|
749
|
-
return joinPathSegments(
|
|
936
|
+
return joinPathSegments(_prefixStore.get(), endpoint);
|
|
750
937
|
}
|
|
751
938
|
return endpoint;
|
|
752
939
|
}
|
|
@@ -754,8 +941,7 @@ class RouteAbstract {
|
|
|
754
941
|
return typeof definition === "string" ? Method.GET : definition.method;
|
|
755
942
|
}
|
|
756
943
|
resolvePattern(endpoint) {
|
|
757
|
-
|
|
758
|
-
return new RegExp(`^${regex}$`);
|
|
944
|
+
return Route.makeRoutePattern(endpoint);
|
|
759
945
|
}
|
|
760
946
|
resolveId(method, endpoint) {
|
|
761
947
|
return Route.makeRouteId(method, endpoint);
|
|
@@ -773,9 +959,9 @@ class Route extends RouteAbstract {
|
|
|
773
959
|
this.id = this.resolveId(this.method, this.endpoint);
|
|
774
960
|
this.model = model;
|
|
775
961
|
this.handler = handler;
|
|
776
|
-
|
|
962
|
+
_routerStore.get().addRoute(this);
|
|
777
963
|
if (model) {
|
|
778
|
-
|
|
964
|
+
_routerStore.get().addModel(this, model);
|
|
779
965
|
}
|
|
780
966
|
}
|
|
781
967
|
variant;
|
|
@@ -788,61 +974,25 @@ class Route extends RouteAbstract {
|
|
|
788
974
|
static makeRouteId(method, endpoint) {
|
|
789
975
|
return `${method.toUpperCase()} ${endpoint}`;
|
|
790
976
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
class FileWalkerUsingBun {
|
|
795
|
-
static async read(address) {
|
|
796
|
-
try {
|
|
797
|
-
const file = await this.find(address);
|
|
798
|
-
if (!file)
|
|
799
|
-
return null;
|
|
800
|
-
return await file.text();
|
|
801
|
-
} catch {
|
|
802
|
-
return null;
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
static async exists(address) {
|
|
806
|
-
return await this.find(address) !== null;
|
|
807
|
-
}
|
|
808
|
-
static getExtension(address) {
|
|
809
|
-
return address.split(".").pop() ?? "txt";
|
|
810
|
-
}
|
|
811
|
-
static async find(address) {
|
|
812
|
-
const file = Bun.file(address);
|
|
813
|
-
const exists = await file.exists();
|
|
814
|
-
if (exists) {
|
|
815
|
-
return { text: () => file.text() };
|
|
816
|
-
}
|
|
817
|
-
return null;
|
|
977
|
+
static makeRoutePattern(endpoint) {
|
|
978
|
+
const regex = endpoint.split("/").map((part) => part.startsWith(":") ? "([^\\/]+)" : part).join("/");
|
|
979
|
+
return new RegExp(`^${regex}$`);
|
|
818
980
|
}
|
|
819
981
|
}
|
|
820
982
|
|
|
821
|
-
// src/FileWalker/FileWalker.ts
|
|
822
|
-
class FileWalker extends FileWalkerUsingBun {
|
|
823
|
-
}
|
|
824
|
-
|
|
825
983
|
// src/Route/StaticRoute.ts
|
|
826
984
|
class StaticRoute extends RouteAbstract {
|
|
827
|
-
|
|
828
|
-
constructor(path2, filePath, handler, model) {
|
|
985
|
+
constructor(path2, definition, handler, model) {
|
|
829
986
|
super();
|
|
830
|
-
this.filePath = filePath;
|
|
831
987
|
this.variant = RouteVariant.static;
|
|
832
988
|
this.endpoint = this.resolveEndpoint(path2, this.variant);
|
|
833
989
|
this.method = Method.GET;
|
|
834
990
|
this.pattern = this.resolvePattern(this.endpoint);
|
|
835
991
|
this.id = this.resolveId(this.method, this.endpoint);
|
|
836
992
|
this.model = model;
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
return handler(c, content);
|
|
841
|
-
};
|
|
842
|
-
} else {
|
|
843
|
-
this.handler = this.defaultHandler;
|
|
844
|
-
}
|
|
845
|
-
getRouterInstance().addRoute(this);
|
|
993
|
+
this.filePath = this.resolveFilePath(definition);
|
|
994
|
+
this.handler = this.resolveHandler(definition, handler);
|
|
995
|
+
_routerStore.get().addRoute(this);
|
|
846
996
|
}
|
|
847
997
|
id;
|
|
848
998
|
variant;
|
|
@@ -851,73 +1001,30 @@ class StaticRoute extends RouteAbstract {
|
|
|
851
1001
|
pattern;
|
|
852
1002
|
model;
|
|
853
1003
|
handler;
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
1004
|
+
filePath;
|
|
1005
|
+
resolveFilePath(definition) {
|
|
1006
|
+
return typeof definition === "string" ? definition : definition.filePath;
|
|
1007
|
+
}
|
|
1008
|
+
resolveHandler(definition, customHandler) {
|
|
1009
|
+
if (customHandler !== undefined) {
|
|
1010
|
+
return async (c) => {
|
|
1011
|
+
const file = new XFile(this.filePath);
|
|
1012
|
+
if (!file) {
|
|
1013
|
+
console.error("File not found at:", this.filePath);
|
|
1014
|
+
throw CError.notFound();
|
|
1015
|
+
}
|
|
1016
|
+
const content = await file.text();
|
|
1017
|
+
c.res.headers.setMany({
|
|
1018
|
+
[CommonHeaders.ContentType]: file.mimeType,
|
|
1019
|
+
[CommonHeaders.ContentLength]: content.length.toString()
|
|
1020
|
+
});
|
|
1021
|
+
return customHandler(c, content);
|
|
1022
|
+
};
|
|
1023
|
+
} else if (typeof definition === "string") {
|
|
1024
|
+
return async () => await CResponse.file(this.filePath);
|
|
1025
|
+
} else {
|
|
1026
|
+
return async () => await CResponse.streamFile(this.filePath);
|
|
869
1027
|
}
|
|
870
|
-
c.res.headers.set(CommonHeaders.ContentType, this.mimeTypes[this.extension] || "application/octet-stream");
|
|
871
|
-
c.res.headers.set(CommonHeaders.ContentLength, content.length.toString());
|
|
872
|
-
return content;
|
|
873
|
-
};
|
|
874
|
-
get extension() {
|
|
875
|
-
return this.filePath.split(".").pop() || "txt";
|
|
876
|
-
}
|
|
877
|
-
async getContent() {
|
|
878
|
-
const content = await FileWalker.read(this.filePath);
|
|
879
|
-
if (!content) {
|
|
880
|
-
console.error("File not found at:", this.filePath);
|
|
881
|
-
throw HttpError.notFound();
|
|
882
|
-
}
|
|
883
|
-
return content;
|
|
884
|
-
}
|
|
885
|
-
mimeTypes = {
|
|
886
|
-
html: "text/html",
|
|
887
|
-
htm: "text/html",
|
|
888
|
-
css: "text/css",
|
|
889
|
-
js: "application/javascript",
|
|
890
|
-
ts: "application/javascript",
|
|
891
|
-
mjs: "application/javascript",
|
|
892
|
-
json: "application/json",
|
|
893
|
-
png: "image/png",
|
|
894
|
-
jpg: "image/jpeg",
|
|
895
|
-
jpeg: "image/jpeg",
|
|
896
|
-
gif: "image/gif",
|
|
897
|
-
svg: "image/svg+xml",
|
|
898
|
-
ico: "image/x-icon",
|
|
899
|
-
txt: "text/plain",
|
|
900
|
-
xml: "application/xml",
|
|
901
|
-
pdf: "application/pdf",
|
|
902
|
-
zip: "application/zip",
|
|
903
|
-
mp3: "audio/mpeg",
|
|
904
|
-
mp4: "video/mp4",
|
|
905
|
-
webm: "video/webm",
|
|
906
|
-
woff: "font/woff",
|
|
907
|
-
woff2: "font/woff2",
|
|
908
|
-
ttf: "font/ttf"
|
|
909
|
-
};
|
|
910
|
-
async handleHtml() {
|
|
911
|
-
return await this.getContent();
|
|
912
|
-
}
|
|
913
|
-
async handleCss() {
|
|
914
|
-
return await this.getContent();
|
|
915
|
-
}
|
|
916
|
-
async handleJs() {
|
|
917
|
-
return await this.getContent();
|
|
918
|
-
}
|
|
919
|
-
async handleFile() {
|
|
920
|
-
return await this.getContent();
|
|
921
1028
|
}
|
|
922
1029
|
}
|
|
923
1030
|
|
|
@@ -960,18 +1067,11 @@ class Middleware {
|
|
|
960
1067
|
constructor(opts) {
|
|
961
1068
|
this.useOn = opts.useOn;
|
|
962
1069
|
this.handler = opts.handler;
|
|
963
|
-
|
|
1070
|
+
_routerStore.get().addMiddleware(opts);
|
|
964
1071
|
}
|
|
965
1072
|
useOn;
|
|
966
1073
|
handler;
|
|
967
1074
|
}
|
|
968
|
-
// src/Repository/RepositoryAbstract.ts
|
|
969
|
-
class RepositoryAbstract {
|
|
970
|
-
db;
|
|
971
|
-
constructor(db) {
|
|
972
|
-
this.db = db;
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
1075
|
// src/utils/assert.ts
|
|
976
1076
|
function assert(condition, message) {
|
|
977
1077
|
const conditionName = String(condition);
|
|
@@ -995,8 +1095,8 @@ function strSplit(mark, input, minLength) {
|
|
|
995
1095
|
return parts;
|
|
996
1096
|
}
|
|
997
1097
|
|
|
998
|
-
// src/
|
|
999
|
-
class
|
|
1098
|
+
// src/CRequest/CRequest.ts
|
|
1099
|
+
class CRequest extends Request {
|
|
1000
1100
|
info;
|
|
1001
1101
|
init;
|
|
1002
1102
|
constructor(info, init) {
|
|
@@ -1018,7 +1118,7 @@ class HttpRequest extends Request {
|
|
|
1018
1118
|
case this.info instanceof URL:
|
|
1019
1119
|
urlObject = this.info;
|
|
1020
1120
|
break;
|
|
1021
|
-
case this.info instanceof
|
|
1121
|
+
case this.info instanceof CRequest:
|
|
1022
1122
|
urlObject = this.info.urlObject;
|
|
1023
1123
|
break;
|
|
1024
1124
|
case this.info instanceof Request:
|
|
@@ -1035,12 +1135,12 @@ class HttpRequest extends Request {
|
|
|
1035
1135
|
}
|
|
1036
1136
|
resolveHeaders() {
|
|
1037
1137
|
if (this.init?.headers !== undefined) {
|
|
1038
|
-
return new
|
|
1138
|
+
return new CHeaders(this.init.headers);
|
|
1039
1139
|
}
|
|
1040
|
-
if (this.info instanceof Request || this.info instanceof
|
|
1041
|
-
return new
|
|
1140
|
+
if (this.info instanceof Request || this.info instanceof CRequest) {
|
|
1141
|
+
return new CHeaders(this.info.headers);
|
|
1042
1142
|
}
|
|
1043
|
-
return new
|
|
1143
|
+
return new CHeaders;
|
|
1044
1144
|
}
|
|
1045
1145
|
resolveCookies() {
|
|
1046
1146
|
const jar = new Cookies;
|
|
@@ -1079,96 +1179,45 @@ function strIsEqual(source, target, modifier) {
|
|
|
1079
1179
|
return source === target;
|
|
1080
1180
|
}
|
|
1081
1181
|
|
|
1182
|
+
// src/Store/LazyMap.ts
|
|
1183
|
+
class LazyMap {
|
|
1184
|
+
constructor() {
|
|
1185
|
+
return new Proxy(this, {
|
|
1186
|
+
get(target, prop) {
|
|
1187
|
+
const val = Reflect.get(target.map, prop);
|
|
1188
|
+
return typeof val === "function" ? val.bind(target.map) : val;
|
|
1189
|
+
}
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
_map;
|
|
1193
|
+
get map() {
|
|
1194
|
+
if (!this._map) {
|
|
1195
|
+
this._map = new Map;
|
|
1196
|
+
}
|
|
1197
|
+
return this._map;
|
|
1198
|
+
}
|
|
1199
|
+
get [Symbol.toStringTag]() {
|
|
1200
|
+
return "LazyMap";
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1082
1204
|
// src/utils/strRemoveWhitespace.ts
|
|
1083
1205
|
function strRemoveWhitespace(str) {
|
|
1084
1206
|
return str.trim().replace(/\s+/g, "");
|
|
1085
1207
|
}
|
|
1086
1208
|
|
|
1087
|
-
// src/Router/
|
|
1088
|
-
class
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
}
|
|
1100
|
-
get models() {
|
|
1101
|
-
if (!this._models) {
|
|
1102
|
-
this._models = new Map;
|
|
1103
|
-
}
|
|
1104
|
-
return this._models;
|
|
1105
|
-
}
|
|
1106
|
-
get middlewares() {
|
|
1107
|
-
if (!this._middlewares) {
|
|
1108
|
-
this._middlewares = new Map;
|
|
1109
|
-
}
|
|
1110
|
-
return this._middlewares;
|
|
1111
|
-
}
|
|
1112
|
-
globalPrefix = "";
|
|
1113
|
-
setGlobalPrefix(value) {
|
|
1114
|
-
this.globalPrefix = value;
|
|
1115
|
-
}
|
|
1116
|
-
getRouteHandler(req) {
|
|
1117
|
-
const cached = this.cache.get(req);
|
|
1118
|
-
if (cached) {
|
|
1119
|
-
return cached;
|
|
1120
|
-
}
|
|
1121
|
-
const route = this.findRoute(req);
|
|
1122
|
-
const ctx = Context.makeFromRequest(req);
|
|
1123
|
-
const middleware = this.findRouterMiddlewareData(route.id);
|
|
1124
|
-
const model = this.findModel(route.id);
|
|
1125
|
-
const handler = async () => {
|
|
1126
|
-
await middleware?.(ctx);
|
|
1127
|
-
await Context.appendParsedData(ctx, req, route.endpoint, model);
|
|
1128
|
-
const result = await route.handler(ctx);
|
|
1129
|
-
return result instanceof HttpResponse ? result : new HttpResponse(result, {
|
|
1130
|
-
cookies: ctx.res.cookies,
|
|
1131
|
-
headers: ctx.res.headers,
|
|
1132
|
-
status: ctx.res.status,
|
|
1133
|
-
statusText: ctx.res.statusText
|
|
1134
|
-
});
|
|
1135
|
-
};
|
|
1136
|
-
this.cache.set(req, handler);
|
|
1137
|
-
return handler;
|
|
1138
|
-
}
|
|
1139
|
-
getRouteList() {
|
|
1140
|
-
return Array.from(this.routes.values()).map((r) => [r.method, r.endpoint]);
|
|
1141
|
-
}
|
|
1142
|
-
addRoute(r) {
|
|
1143
|
-
const handler = this.intern(r.handler, "route", r.id);
|
|
1144
|
-
this.checkPossibleCollision(r);
|
|
1145
|
-
this.routes.set(r.endpoint, {
|
|
1146
|
-
id: r.id,
|
|
1147
|
-
endpoint: r.endpoint,
|
|
1148
|
-
method: r.method,
|
|
1149
|
-
handler,
|
|
1150
|
-
pattern: r.pattern
|
|
1151
|
-
});
|
|
1152
|
-
}
|
|
1153
|
-
addMiddleware(m) {
|
|
1154
|
-
const useOn = m.useOn;
|
|
1155
|
-
const handler = this.intern(m.handler, "middleware", m.handler.toString());
|
|
1156
|
-
if (useOn === "*") {
|
|
1157
|
-
this.middlewares.set("*", this.compile([this.middlewares.get("*"), handler]));
|
|
1158
|
-
return;
|
|
1159
|
-
}
|
|
1160
|
-
for (const target of Array.isArray(useOn) ? useOn : [useOn]) {
|
|
1161
|
-
const routeIds = target instanceof Route ? [target.id] : target instanceof ControllerAbstract ? Array.from(target.routeIds) : [];
|
|
1162
|
-
for (const routeId of routeIds) {
|
|
1163
|
-
this.middlewares.set(routeId, this.compile([
|
|
1164
|
-
this.middlewares.get("*"),
|
|
1165
|
-
this.middlewares.get(routeId),
|
|
1166
|
-
handler
|
|
1167
|
-
]));
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
addModel(routeId, model) {
|
|
1209
|
+
// src/Router/registries/ModelRegistry.ts
|
|
1210
|
+
class ModelRegistry {
|
|
1211
|
+
map = new LazyMap;
|
|
1212
|
+
add(method, endpoint, model) {
|
|
1213
|
+
const entry = ModelRegistry.toRouterModelData(model);
|
|
1214
|
+
this.map.set(Route.makeRouteId(method, endpoint), entry);
|
|
1215
|
+
}
|
|
1216
|
+
find(routeId) {
|
|
1217
|
+
return this.map.get(routeId);
|
|
1218
|
+
}
|
|
1219
|
+
static internFuncMap = new LazyMap;
|
|
1220
|
+
static toRouterModelData(model) {
|
|
1172
1221
|
const entry = {};
|
|
1173
1222
|
for (const k of Object.keys(model)) {
|
|
1174
1223
|
const key = k;
|
|
@@ -1178,69 +1227,166 @@ class Router {
|
|
|
1178
1227
|
const handler = schema["~standard"].validate;
|
|
1179
1228
|
entry[key] = this.intern(handler, "model", strRemoveWhitespace(JSON.stringify(schema)));
|
|
1180
1229
|
}
|
|
1181
|
-
|
|
1230
|
+
return entry;
|
|
1182
1231
|
}
|
|
1183
|
-
|
|
1184
|
-
|
|
1232
|
+
static intern(value, ...namespace) {
|
|
1233
|
+
const key = namespace.join("::");
|
|
1234
|
+
const existing = this.internFuncMap.get(key);
|
|
1235
|
+
if (existing)
|
|
1236
|
+
return existing;
|
|
1237
|
+
this.internFuncMap.set(key, value);
|
|
1238
|
+
return value;
|
|
1185
1239
|
}
|
|
1186
|
-
|
|
1187
|
-
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// src/utils/compile.ts
|
|
1243
|
+
function compile(fns) {
|
|
1244
|
+
return async (...args) => {
|
|
1245
|
+
for (const fn of fns) {
|
|
1246
|
+
if (!fn)
|
|
1247
|
+
continue;
|
|
1248
|
+
await fn(...args);
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// src/Router/registries/MiddlewareRegistry.ts
|
|
1254
|
+
class MiddlewareRegistry {
|
|
1255
|
+
middlewares = new LazyMap;
|
|
1256
|
+
add(m) {
|
|
1257
|
+
const resolved = MiddlewareRegistry.resolveRouteIds(m);
|
|
1258
|
+
if (resolved.isGlobal) {
|
|
1259
|
+
const existing = this.middlewares.get("*") ?? [];
|
|
1260
|
+
this.middlewares.set("*", [...existing, m.handler]);
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
for (const routeId of resolved.routeIds) {
|
|
1264
|
+
const existing = this.middlewares.get(routeId) ?? [];
|
|
1265
|
+
this.middlewares.set(routeId, [...existing, m.handler]);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
find(routeId) {
|
|
1269
|
+
const globals = this.middlewares.get("*") ?? [];
|
|
1270
|
+
const locals = this.middlewares.get(routeId) ?? [];
|
|
1271
|
+
return compile([...globals, ...locals]);
|
|
1272
|
+
}
|
|
1273
|
+
static resolveRouteIds(m) {
|
|
1274
|
+
if (m.useOn === "*")
|
|
1275
|
+
return { isGlobal: true };
|
|
1276
|
+
const targets = Array.isArray(m.useOn) ? m.useOn : [m.useOn];
|
|
1277
|
+
const routeIds = [];
|
|
1278
|
+
for (const target of targets) {
|
|
1279
|
+
if (target instanceof Route) {
|
|
1280
|
+
routeIds.push(target.id);
|
|
1281
|
+
} else if (target instanceof ControllerAbstract) {
|
|
1282
|
+
routeIds.push(...target.routeIds);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
return { isGlobal: false, routeIds };
|
|
1188
1286
|
}
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// src/Router/adapters/CorpusAdapter.ts
|
|
1290
|
+
class CorpusAdapter {
|
|
1291
|
+
routes = new Map;
|
|
1292
|
+
modelRegistry = new ModelRegistry;
|
|
1293
|
+
middlewareRegistry = new MiddlewareRegistry;
|
|
1294
|
+
addRoute(data) {
|
|
1295
|
+
this.checkPossibleCollision(data);
|
|
1296
|
+
this.routes.set(data.id, data);
|
|
1297
|
+
}
|
|
1298
|
+
addModel(route, model) {
|
|
1299
|
+
this.modelRegistry.add(route.method, route.endpoint, model);
|
|
1300
|
+
}
|
|
1301
|
+
addMiddleware(middleware) {
|
|
1302
|
+
this.middlewareRegistry.add(middleware);
|
|
1303
|
+
}
|
|
1304
|
+
find(req) {
|
|
1305
|
+
const method = req.method;
|
|
1306
|
+
const pathname = req.urlObject.pathname;
|
|
1307
|
+
const searchParams = req.urlObject.searchParams;
|
|
1192
1308
|
let route = null;
|
|
1193
|
-
for (const
|
|
1194
|
-
if (
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
} else if (strIsEqual(endpoint, reqPath)) {
|
|
1309
|
+
for (const data of this.routes.values()) {
|
|
1310
|
+
if (this.hasAnyParam(data.endpoint) && isRegexMatch(pathname, data.pattern)) {
|
|
1311
|
+
route = data;
|
|
1312
|
+
break;
|
|
1313
|
+
}
|
|
1314
|
+
if (this.hasLastPartParam(data.endpoint) && strIsEqual(this.removeLastParam(data.endpoint), pathname, "lower")) {
|
|
1315
|
+
route = data;
|
|
1316
|
+
break;
|
|
1317
|
+
}
|
|
1318
|
+
if (strIsEqual(data.endpoint, pathname)) {
|
|
1204
1319
|
route = data;
|
|
1205
1320
|
break;
|
|
1206
1321
|
}
|
|
1207
1322
|
}
|
|
1208
1323
|
if (route === null) {
|
|
1209
|
-
throw
|
|
1324
|
+
throw CError.notFound();
|
|
1210
1325
|
}
|
|
1211
|
-
if (!strIsEqual(
|
|
1212
|
-
throw
|
|
1326
|
+
if (!strIsEqual(method, route.method, "upper")) {
|
|
1327
|
+
throw CError.methodNotAllowed();
|
|
1213
1328
|
}
|
|
1214
|
-
return
|
|
1329
|
+
return {
|
|
1330
|
+
route,
|
|
1331
|
+
model: this.modelRegistry.find(route.id),
|
|
1332
|
+
middleware: this.middlewareRegistry.find(route.id),
|
|
1333
|
+
params: this.extractParams(pathname, route.endpoint),
|
|
1334
|
+
search: Object.fromEntries(searchParams)
|
|
1335
|
+
};
|
|
1215
1336
|
}
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1337
|
+
list() {
|
|
1338
|
+
return Array.from(this.routes.values());
|
|
1339
|
+
}
|
|
1340
|
+
checkPossibleCollision(n) {
|
|
1341
|
+
const dupeMsg = (nId) => console.error(`Duplicate route detected. ${nId} has already been registered.`);
|
|
1342
|
+
const dynamicPatternMsg = (nId, oId) => console.error(`Ambiguous dynamic routes. ${nId} and ${oId} match the same URL patterns.`);
|
|
1343
|
+
const baseDupeMsg = (nId, oId) => console.error(`Dynamic route overlaps existing route. ${nId} \u2014 dropping the last param segment matches ${oId}.`);
|
|
1344
|
+
const shadowMsg = (nId, oId) => console.error(`Route shadowed by existing dynamic route. ${nId} will be unreachable \u2014 ${oId} captures the same URL space.`);
|
|
1345
|
+
const existing = this.routes.get(n.id);
|
|
1346
|
+
if (existing) {
|
|
1347
|
+
dupeMsg(n.id);
|
|
1348
|
+
return true;
|
|
1349
|
+
}
|
|
1350
|
+
const nHasAnyParam = this.hasAnyParam(n.endpoint);
|
|
1351
|
+
const nHasLastPartParam = this.hasLastPartParam(n.endpoint);
|
|
1352
|
+
for (const o of this.routes.values()) {
|
|
1353
|
+
if (o.method !== n.method)
|
|
1223
1354
|
continue;
|
|
1224
|
-
if (
|
|
1225
|
-
if (isRegexMatch(
|
|
1226
|
-
|
|
1355
|
+
if (nHasAnyParam) {
|
|
1356
|
+
if (isRegexMatch(n.endpoint, o.pattern) || isRegexMatch(o.endpoint, n.pattern)) {
|
|
1357
|
+
dynamicPatternMsg(n.id, o.id);
|
|
1358
|
+
return true;
|
|
1227
1359
|
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
} else {
|
|
1234
|
-
if (strIsEqual(r.endpoint, existing.endpoint, "lower")) {
|
|
1235
|
-
console.error(`\u26A0\uFE0F Collision: ${r.method} ${r.endpoint} already exists`);
|
|
1360
|
+
}
|
|
1361
|
+
if (nHasLastPartParam) {
|
|
1362
|
+
if (isRegexMatch(this.removeLastParam(n.endpoint), o.pattern)) {
|
|
1363
|
+
baseDupeMsg(n.id, o.id);
|
|
1364
|
+
return true;
|
|
1236
1365
|
}
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1366
|
+
}
|
|
1367
|
+
const oHasLastPartParam = this.hasLastPartParam(o.endpoint);
|
|
1368
|
+
if (oHasLastPartParam) {
|
|
1369
|
+
if (isRegexMatch(n.endpoint, Route.makeRoutePattern(this.removeLastParam(o.endpoint)))) {
|
|
1370
|
+
shadowMsg(n.id, o.id);
|
|
1371
|
+
return true;
|
|
1241
1372
|
}
|
|
1242
1373
|
}
|
|
1243
1374
|
}
|
|
1375
|
+
return false;
|
|
1376
|
+
}
|
|
1377
|
+
extractParams(pathname, endpoint) {
|
|
1378
|
+
const data = {};
|
|
1379
|
+
if (!this.hasAnyParam(endpoint))
|
|
1380
|
+
return data;
|
|
1381
|
+
const defParts = endpoint.split("/");
|
|
1382
|
+
const reqParts = pathname.split("/");
|
|
1383
|
+
for (const [i, defPart] of defParts.entries()) {
|
|
1384
|
+
const reqPart = reqParts[i];
|
|
1385
|
+
if (defPart.startsWith(":") && reqPart !== undefined) {
|
|
1386
|
+
data[defPart.slice(1)] = decodeURIComponent(reqPart);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
return data;
|
|
1244
1390
|
}
|
|
1245
1391
|
hasLastPartParam(endpoint) {
|
|
1246
1392
|
if (!this.hasAnyParam(endpoint))
|
|
@@ -1252,94 +1398,83 @@ class Router {
|
|
|
1252
1398
|
return endpoint.split("/").slice(0, -1).join("/");
|
|
1253
1399
|
}
|
|
1254
1400
|
hasAnyParam(endpoint) {
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
if (!fn)
|
|
1261
|
-
continue;
|
|
1262
|
-
await fn(...args);
|
|
1263
|
-
}
|
|
1264
|
-
};
|
|
1265
|
-
}
|
|
1266
|
-
intern(value, ...namespace) {
|
|
1267
|
-
const key = namespace.join("::");
|
|
1268
|
-
const existing = this.internFuncMap.get(key);
|
|
1269
|
-
if (existing)
|
|
1270
|
-
return existing;
|
|
1271
|
-
this.internFuncMap.set(key, value);
|
|
1272
|
-
return value;
|
|
1401
|
+
if (endpoint.includes("/:"))
|
|
1402
|
+
return true;
|
|
1403
|
+
if (!endpoint.includes(":"))
|
|
1404
|
+
return false;
|
|
1405
|
+
return endpoint.split("/").some((p) => p.startsWith(":"));
|
|
1273
1406
|
}
|
|
1274
1407
|
}
|
|
1275
1408
|
|
|
1276
|
-
// src/
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
// src/utils/isSomeArray.ts
|
|
1282
|
-
function isSomeArray(arg) {
|
|
1283
|
-
return arg !== undefined && Array.isArray(arg) && arg.length > 0 && arg.every((a) => a !== null && a !== undefined);
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
// src/Cors/Cors.ts
|
|
1287
|
-
class Cors {
|
|
1288
|
-
opts;
|
|
1289
|
-
constructor(opts) {
|
|
1290
|
-
this.opts = opts;
|
|
1409
|
+
// src/Router/Router.ts
|
|
1410
|
+
class Router {
|
|
1411
|
+
constructor(adapter) {
|
|
1412
|
+
this._adapter = adapter ?? new CorpusAdapter;
|
|
1291
1413
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
const { allowedOrigins, allowedMethods, allowedHeaders, credentials } = this.opts;
|
|
1299
|
-
if (isSomeArray(allowedOrigins) && allowedOrigins.includes(reqOrigin)) {
|
|
1300
|
-
res.headers.set(this.originKey, reqOrigin);
|
|
1301
|
-
}
|
|
1302
|
-
if (isSomeArray(allowedMethods)) {
|
|
1303
|
-
res.headers.set(this.methodsKey, allowedMethods.join(", "));
|
|
1304
|
-
}
|
|
1305
|
-
if (isSomeArray(allowedHeaders)) {
|
|
1306
|
-
res.headers.set(this.headersKey, allowedHeaders.join(", "));
|
|
1414
|
+
models = [];
|
|
1415
|
+
_adapter;
|
|
1416
|
+
cache = new WeakMap;
|
|
1417
|
+
checkPossibleCollision(n) {
|
|
1418
|
+
if (this._adapter instanceof CorpusAdapter) {
|
|
1419
|
+
return this._adapter.checkPossibleCollision(n);
|
|
1307
1420
|
}
|
|
1308
|
-
|
|
1309
|
-
return res.headers;
|
|
1421
|
+
return false;
|
|
1310
1422
|
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1423
|
+
addModel(route, model) {
|
|
1424
|
+
this.models.push(model);
|
|
1425
|
+
this._adapter.addModel(route, model);
|
|
1426
|
+
}
|
|
1427
|
+
addMiddleware(middleware) {
|
|
1428
|
+
this._adapter.addMiddleware(middleware);
|
|
1429
|
+
}
|
|
1430
|
+
addRoute(r) {
|
|
1431
|
+
this._adapter.addRoute({
|
|
1432
|
+
id: r.id,
|
|
1433
|
+
endpoint: r.endpoint,
|
|
1434
|
+
method: r.method,
|
|
1435
|
+
handler: r.handler,
|
|
1436
|
+
pattern: r.pattern
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
findRouteHandler(req) {
|
|
1440
|
+
const cached = this.cache.get(req);
|
|
1441
|
+
if (cached)
|
|
1442
|
+
return cached;
|
|
1443
|
+
const match = this._adapter.find(req);
|
|
1444
|
+
if (!match)
|
|
1445
|
+
throw CError.notFound();
|
|
1446
|
+
const ctx = Context.makeFromRequest(req);
|
|
1447
|
+
const handler = async () => {
|
|
1448
|
+
await match.middleware?.(ctx);
|
|
1449
|
+
await Context.appendParsedData(ctx, req, match.params, match.search, match.model);
|
|
1450
|
+
const res = await match.route.handler(ctx);
|
|
1451
|
+
return res instanceof CResponse ? res : new CResponse(res, {
|
|
1452
|
+
cookies: ctx.res.cookies,
|
|
1453
|
+
headers: ctx.res.headers,
|
|
1454
|
+
status: ctx.res.status,
|
|
1455
|
+
statusText: ctx.res.statusText
|
|
1456
|
+
});
|
|
1457
|
+
};
|
|
1458
|
+
this.cache.set(req, handler);
|
|
1459
|
+
return handler;
|
|
1460
|
+
}
|
|
1461
|
+
getRouteList() {
|
|
1462
|
+
return this._adapter.list().map((v) => [v.method, v.endpoint]);
|
|
1314
1463
|
}
|
|
1315
1464
|
}
|
|
1316
1465
|
|
|
1317
1466
|
// src/Server/ServerAbstract.ts
|
|
1318
1467
|
class ServerAbstract {
|
|
1319
|
-
|
|
1468
|
+
opts;
|
|
1469
|
+
constructor(opts) {
|
|
1470
|
+
this.opts = opts;
|
|
1471
|
+
_routerStore.set(new Router(opts?.adapter));
|
|
1472
|
+
}
|
|
1320
1473
|
get routes() {
|
|
1321
|
-
return
|
|
1474
|
+
return _routerStore.get().getRouteList();
|
|
1322
1475
|
}
|
|
1323
1476
|
setGlobalPrefix(value) {
|
|
1324
|
-
|
|
1325
|
-
}
|
|
1326
|
-
setCors(cors) {
|
|
1327
|
-
this.cors = new Cors(cors);
|
|
1328
|
-
}
|
|
1329
|
-
setOnError(handler) {
|
|
1330
|
-
this.handleError = handler;
|
|
1331
|
-
}
|
|
1332
|
-
setOnNotFound(handler) {
|
|
1333
|
-
this.handleNotFound = handler;
|
|
1334
|
-
}
|
|
1335
|
-
setOnBeforeListen(handler) {
|
|
1336
|
-
this.handleBeforeListen = handler;
|
|
1337
|
-
}
|
|
1338
|
-
setOnBeforeClose(handler) {
|
|
1339
|
-
this.handleBeforeClose = handler;
|
|
1340
|
-
}
|
|
1341
|
-
setOnAfterResponse(handler) {
|
|
1342
|
-
this.handleAfterResponse = handler;
|
|
1477
|
+
_prefixStore.set(value);
|
|
1343
1478
|
}
|
|
1344
1479
|
async listen(port, hostname = "0.0.0.0") {
|
|
1345
1480
|
try {
|
|
@@ -1358,10 +1493,11 @@ class ServerAbstract {
|
|
|
1358
1493
|
}
|
|
1359
1494
|
}
|
|
1360
1495
|
async handle(request) {
|
|
1361
|
-
const req = new
|
|
1496
|
+
const req = new CRequest(request);
|
|
1362
1497
|
let res = await this.getResponse(req);
|
|
1363
|
-
|
|
1364
|
-
|
|
1498
|
+
const cors = _corsStore.get();
|
|
1499
|
+
if (cors !== null) {
|
|
1500
|
+
cors.apply(req, res);
|
|
1365
1501
|
}
|
|
1366
1502
|
if (this.handleAfterResponse) {
|
|
1367
1503
|
res = await this.handleAfterResponse(res);
|
|
@@ -1371,12 +1507,12 @@ class ServerAbstract {
|
|
|
1371
1507
|
async getResponse(req) {
|
|
1372
1508
|
try {
|
|
1373
1509
|
if (req.isPreflight) {
|
|
1374
|
-
return new
|
|
1510
|
+
return new CResponse("Departed");
|
|
1375
1511
|
}
|
|
1376
|
-
const handler =
|
|
1512
|
+
const handler = _routerStore.get().findRouteHandler(req);
|
|
1377
1513
|
return await handler();
|
|
1378
1514
|
} catch (err) {
|
|
1379
|
-
if (err instanceof
|
|
1515
|
+
if (err instanceof CError) {
|
|
1380
1516
|
if (err.isStatusOf(Status.NOT_FOUND)) {
|
|
1381
1517
|
return await this.handleNotFound(req);
|
|
1382
1518
|
}
|
|
@@ -1388,39 +1524,56 @@ class ServerAbstract {
|
|
|
1388
1524
|
}
|
|
1389
1525
|
}
|
|
1390
1526
|
handleBeforeListen;
|
|
1527
|
+
setOnBeforeListen(handler) {
|
|
1528
|
+
this.handleBeforeListen = handler;
|
|
1529
|
+
}
|
|
1530
|
+
defaultOnBeforeListen = undefined;
|
|
1391
1531
|
handleBeforeClose;
|
|
1532
|
+
setOnBeforeClose(handler) {
|
|
1533
|
+
this.handleBeforeClose = handler;
|
|
1534
|
+
}
|
|
1535
|
+
defaultOnBeforeClose = undefined;
|
|
1392
1536
|
handleAfterResponse;
|
|
1393
|
-
|
|
1537
|
+
setOnAfterResponse(handler) {
|
|
1538
|
+
this.handleAfterResponse = handler;
|
|
1539
|
+
}
|
|
1540
|
+
defaultOnAfterResponse = undefined;
|
|
1541
|
+
handleError = (err) => this.defaultErrorHandler(err);
|
|
1542
|
+
setOnError(handler) {
|
|
1543
|
+
this.handleError = handler;
|
|
1544
|
+
}
|
|
1545
|
+
defaultErrorHandler = (err) => {
|
|
1394
1546
|
if (!(err instanceof Error)) {
|
|
1395
|
-
return new
|
|
1547
|
+
return new CResponse({ error: err, message: "Unknown" }, { status: Status.INTERNAL_SERVER_ERROR });
|
|
1396
1548
|
}
|
|
1397
|
-
if (err instanceof
|
|
1549
|
+
if (err instanceof CError) {
|
|
1398
1550
|
return err.toResponse();
|
|
1399
1551
|
}
|
|
1400
|
-
return new
|
|
1552
|
+
return new CResponse({ error: err, message: err.message }, { status: Status.INTERNAL_SERVER_ERROR });
|
|
1401
1553
|
};
|
|
1402
|
-
handleNotFound =
|
|
1403
|
-
|
|
1554
|
+
handleNotFound = (req) => this.defaultNotFoundHandler(req);
|
|
1555
|
+
setOnNotFound(handler) {
|
|
1556
|
+
this.handleNotFound = handler;
|
|
1557
|
+
}
|
|
1558
|
+
defaultNotFoundHandler = (req) => {
|
|
1559
|
+
return new CResponse({ error: true, message: `${req.method} on ${req.url} does not exist.` }, { status: Status.NOT_FOUND });
|
|
1404
1560
|
};
|
|
1405
|
-
handleMethodNotAllowed =
|
|
1406
|
-
|
|
1561
|
+
handleMethodNotAllowed = (req) => this.defaultMethodNotFoundHandler(req);
|
|
1562
|
+
defaultMethodNotFoundHandler = (req) => {
|
|
1563
|
+
return new CResponse({ error: `${req.method} ${req.url} does not exist.` }, { status: Status.METHOD_NOT_ALLOWED });
|
|
1407
1564
|
};
|
|
1408
1565
|
}
|
|
1409
1566
|
|
|
1410
1567
|
// src/Server/ServerUsingBun.ts
|
|
1411
1568
|
class ServerUsingBun extends ServerAbstract {
|
|
1412
1569
|
app;
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
setRouterInstance(new Router);
|
|
1416
|
-
}
|
|
1417
|
-
serve(options) {
|
|
1418
|
-
this.app = this.createApp(options);
|
|
1570
|
+
serve(args) {
|
|
1571
|
+
this.app = this.createApp(args);
|
|
1419
1572
|
}
|
|
1420
1573
|
async close() {
|
|
1421
1574
|
await this.handleBeforeClose?.();
|
|
1422
1575
|
console.log("Closing...");
|
|
1423
|
-
await this.app?.stop();
|
|
1576
|
+
await this.app?.stop(true);
|
|
1424
1577
|
if (Config.nodeEnv !== "test") {
|
|
1425
1578
|
process.exit(0);
|
|
1426
1579
|
}
|
|
@@ -1429,7 +1582,9 @@ class ServerUsingBun extends ServerAbstract {
|
|
|
1429
1582
|
return Bun.serve({
|
|
1430
1583
|
port: options.port,
|
|
1431
1584
|
hostname: options.hostname,
|
|
1432
|
-
fetch: options.fetch
|
|
1585
|
+
fetch: options.fetch,
|
|
1586
|
+
idleTimeout: this.opts?.idleTimeout,
|
|
1587
|
+
tls: this.opts?.tls
|
|
1433
1588
|
});
|
|
1434
1589
|
}
|
|
1435
1590
|
}
|
|
@@ -1437,41 +1592,371 @@ class ServerUsingBun extends ServerAbstract {
|
|
|
1437
1592
|
// src/Server/Server.ts
|
|
1438
1593
|
class Server extends ServerUsingBun {
|
|
1439
1594
|
}
|
|
1440
|
-
// src/
|
|
1441
|
-
var
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1595
|
+
// src/X.ts
|
|
1596
|
+
var exports_X = {};
|
|
1597
|
+
__export(exports_X, {
|
|
1598
|
+
Repository: () => RepositoryAbstract,
|
|
1599
|
+
Parser: () => Parser,
|
|
1600
|
+
MemoiristAdapter: () => MemoiristAdapter,
|
|
1601
|
+
File: () => XFile,
|
|
1602
|
+
Cors: () => Cors
|
|
1603
|
+
});
|
|
1604
|
+
// src/utils/boolToString.ts
|
|
1605
|
+
function boolToString(arg) {
|
|
1606
|
+
return arg ? "true" : "false";
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
// src/utils/isSomeArray.ts
|
|
1610
|
+
function isSomeArray(arg) {
|
|
1611
|
+
return arg !== undefined && Array.isArray(arg) && arg.length > 0 && arg.every((a) => a !== null && a !== undefined);
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
// src/Cors/Cors.ts
|
|
1615
|
+
class Cors {
|
|
1616
|
+
opts;
|
|
1617
|
+
constructor(opts) {
|
|
1618
|
+
this.opts = opts;
|
|
1619
|
+
if (opts === undefined) {
|
|
1620
|
+
_corsStore.set(null);
|
|
1621
|
+
} else {
|
|
1622
|
+
_corsStore.set(this);
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
originKey = "Access-Control-Allow-Origin";
|
|
1626
|
+
methodsKey = "Access-Control-Allow-Methods";
|
|
1627
|
+
headersKey = "Access-Control-Allow-Headers";
|
|
1628
|
+
credentialsKey = "Access-Control-Allow-Credentials";
|
|
1629
|
+
getCorsHeaders(req, res) {
|
|
1630
|
+
const reqOrigin = req.headers.get("origin") ?? "";
|
|
1631
|
+
const { allowedOrigins, allowedMethods, allowedHeaders, credentials } = this.opts ?? {};
|
|
1632
|
+
if (isSomeArray(allowedOrigins) && allowedOrigins.includes(reqOrigin)) {
|
|
1633
|
+
res.headers.set(this.originKey, reqOrigin);
|
|
1634
|
+
}
|
|
1635
|
+
if (isSomeArray(allowedMethods)) {
|
|
1636
|
+
res.headers.set(this.methodsKey, allowedMethods.join(", "));
|
|
1637
|
+
}
|
|
1638
|
+
if (isSomeArray(allowedHeaders)) {
|
|
1639
|
+
res.headers.set(this.headersKey, allowedHeaders.join(", "));
|
|
1640
|
+
}
|
|
1641
|
+
res.headers.set(this.credentialsKey, boolToString(credentials));
|
|
1642
|
+
return res.headers;
|
|
1643
|
+
}
|
|
1644
|
+
apply(req, res) {
|
|
1645
|
+
const headers = this.getCorsHeaders(req, res);
|
|
1646
|
+
res.headers.innerCombine(headers);
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
// src/Repository/RepositoryAbstract.ts
|
|
1650
|
+
class RepositoryAbstract {
|
|
1651
|
+
db;
|
|
1652
|
+
constructor(db) {
|
|
1653
|
+
this.db = db;
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
// node_modules/memoirist/dist/bun/index.js
|
|
1657
|
+
var Y = (v, b) => {
|
|
1658
|
+
let A = b?.length ? {} : null;
|
|
1659
|
+
if (A)
|
|
1660
|
+
for (let Q of b)
|
|
1661
|
+
A[Q.part.charCodeAt(0)] = Q;
|
|
1662
|
+
return { part: v, store: null, inert: A, params: null, wildcardStore: null };
|
|
1663
|
+
};
|
|
1664
|
+
var k = (v, b) => ({ ...v, part: b });
|
|
1665
|
+
var T = (v) => ({ name: v, store: null, inert: null });
|
|
1666
|
+
|
|
1667
|
+
class _ {
|
|
1668
|
+
config;
|
|
1669
|
+
root = {};
|
|
1670
|
+
history = [];
|
|
1671
|
+
deferred = [];
|
|
1672
|
+
constructor(v = {}) {
|
|
1673
|
+
this.config = v;
|
|
1674
|
+
if (v.lazy)
|
|
1675
|
+
this.find = this.lazyFind;
|
|
1676
|
+
if (v.onParam && !Array.isArray(v.onParam))
|
|
1677
|
+
this.config.onParam = [this.config.onParam];
|
|
1678
|
+
}
|
|
1679
|
+
static regex = { static: /:.+?(?=\/|$)/, params: /:.+?(?=\/|$)/g, optionalParams: /(\/:\w+\?)/g };
|
|
1680
|
+
lazyFind = (v, b) => {
|
|
1681
|
+
if (!this.config.lazy)
|
|
1682
|
+
return this.find;
|
|
1683
|
+
return this.build(), this.find(v, b);
|
|
1684
|
+
};
|
|
1685
|
+
build() {
|
|
1686
|
+
if (!this.config.lazy)
|
|
1687
|
+
return;
|
|
1688
|
+
for (let [v, b, A] of this.deferred)
|
|
1689
|
+
this.add(v, b, A, { lazy: false, ignoreHistory: true });
|
|
1690
|
+
this.deferred = [], this.find = (v, b) => {
|
|
1691
|
+
let A = this.root[v];
|
|
1692
|
+
if (!A)
|
|
1693
|
+
return null;
|
|
1694
|
+
return $(b, b.length, A, 0, this.config.onParam);
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
add(v, b, A, { ignoreError: Q = false, ignoreHistory: O = false, lazy: V = this.config.lazy } = {}) {
|
|
1698
|
+
if (V)
|
|
1699
|
+
return this.find = this.lazyFind, this.deferred.push([v, b, A]), A;
|
|
1700
|
+
if (typeof b !== "string")
|
|
1701
|
+
throw new TypeError("Route path must be a string");
|
|
1702
|
+
if (b === "")
|
|
1703
|
+
b = "/";
|
|
1704
|
+
else if (b[0] !== "/")
|
|
1705
|
+
b = `/${b}`;
|
|
1706
|
+
let X = b[b.length - 1] === "*", J = b.match(_.regex.optionalParams);
|
|
1707
|
+
if (J) {
|
|
1708
|
+
let F = b.replaceAll("?", "");
|
|
1709
|
+
this.add(v, F, A, { ignoreError: Q, ignoreHistory: O, lazy: V });
|
|
1710
|
+
for (let B = 0;B < J.length; B++) {
|
|
1711
|
+
let D = b.replace(J[B], "");
|
|
1712
|
+
this.add(v, D, A, { ignoreError: true, ignoreHistory: O, lazy: V });
|
|
1713
|
+
}
|
|
1714
|
+
return A;
|
|
1715
|
+
}
|
|
1716
|
+
if (J)
|
|
1717
|
+
b = b.replaceAll("?", "");
|
|
1718
|
+
if (this.history.find(([F, B, D]) => F === v && B === b))
|
|
1719
|
+
return A;
|
|
1720
|
+
if (X || J && b.charCodeAt(b.length - 1) === 63)
|
|
1721
|
+
b = b.slice(0, -1);
|
|
1722
|
+
if (!O)
|
|
1723
|
+
this.history.push([v, b, A]);
|
|
1724
|
+
let K = b.split(_.regex.static), G = b.match(_.regex.params) || [];
|
|
1725
|
+
if (K[K.length - 1] === "")
|
|
1726
|
+
K.pop();
|
|
1727
|
+
let q;
|
|
1728
|
+
if (!this.root[v])
|
|
1729
|
+
q = this.root[v] = Y("/");
|
|
1730
|
+
else
|
|
1731
|
+
q = this.root[v];
|
|
1732
|
+
let U = 0;
|
|
1733
|
+
for (let F = 0;F < K.length; ++F) {
|
|
1734
|
+
let B = K[F];
|
|
1735
|
+
if (F > 0) {
|
|
1736
|
+
let D = G[U++].slice(1);
|
|
1737
|
+
if (q.params === null)
|
|
1738
|
+
q.params = T(D);
|
|
1739
|
+
else if (q.params.name !== D)
|
|
1740
|
+
if (Q)
|
|
1741
|
+
return A;
|
|
1742
|
+
else
|
|
1743
|
+
throw new Error(`Cannot create route "${b}" with parameter "${D}" because a route already exists with a different parameter name ("${q.params.name}") in the same location`);
|
|
1744
|
+
let S = q.params;
|
|
1745
|
+
if (S.inert === null) {
|
|
1746
|
+
q = S.inert = Y(B);
|
|
1747
|
+
continue;
|
|
1748
|
+
}
|
|
1749
|
+
q = S.inert;
|
|
1750
|
+
}
|
|
1751
|
+
for (let D = 0;; ) {
|
|
1752
|
+
if (D === B.length) {
|
|
1753
|
+
if (D < q.part.length) {
|
|
1754
|
+
let S = k(q, q.part.slice(D));
|
|
1755
|
+
Object.assign(q, Y(B, [S]));
|
|
1756
|
+
}
|
|
1757
|
+
break;
|
|
1758
|
+
}
|
|
1759
|
+
if (D === q.part.length) {
|
|
1760
|
+
if (q.inert === null)
|
|
1761
|
+
q.inert = {};
|
|
1762
|
+
let S = q.inert[B.charCodeAt(D)];
|
|
1763
|
+
if (S) {
|
|
1764
|
+
q = S, B = B.slice(D), D = 0;
|
|
1765
|
+
continue;
|
|
1766
|
+
}
|
|
1767
|
+
let Z = Y(B.slice(D));
|
|
1768
|
+
q.inert[B.charCodeAt(D)] = Z, q = Z;
|
|
1769
|
+
break;
|
|
1770
|
+
}
|
|
1771
|
+
if (B[D] !== q.part[D]) {
|
|
1772
|
+
let S = k(q, q.part.slice(D)), Z = Y(B.slice(D));
|
|
1773
|
+
Object.assign(q, Y(q.part.slice(0, D), [S, Z])), q = Z;
|
|
1774
|
+
break;
|
|
1775
|
+
}
|
|
1776
|
+
++D;
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
if (U < G.length) {
|
|
1780
|
+
let B = G[U].slice(1);
|
|
1781
|
+
if (q.params === null)
|
|
1782
|
+
q.params = T(B);
|
|
1783
|
+
else if (q.params.name !== B)
|
|
1784
|
+
if (Q)
|
|
1785
|
+
return A;
|
|
1786
|
+
else
|
|
1787
|
+
throw new Error(`Cannot create route "${b}" with parameter "${B}" because a route already exists with a different parameter name ("${q.params.name}") in the same location`);
|
|
1788
|
+
if (q.params.store === null)
|
|
1789
|
+
q.params.store = A;
|
|
1790
|
+
return q.params.store;
|
|
1791
|
+
}
|
|
1792
|
+
if (X) {
|
|
1793
|
+
if (q.wildcardStore === null)
|
|
1794
|
+
q.wildcardStore = A;
|
|
1795
|
+
return q.wildcardStore;
|
|
1796
|
+
}
|
|
1797
|
+
if (q.store === null)
|
|
1798
|
+
q.store = A;
|
|
1799
|
+
return q.store;
|
|
1800
|
+
}
|
|
1801
|
+
find(v, b) {
|
|
1802
|
+
let A = this.root[v];
|
|
1803
|
+
if (!A)
|
|
1804
|
+
return null;
|
|
1805
|
+
return $(b, b.length, A, 0, this.config.onParam);
|
|
1446
1806
|
}
|
|
1447
|
-
return RouterInstance;
|
|
1448
1807
|
}
|
|
1449
|
-
|
|
1450
|
-
|
|
1808
|
+
var $ = (v, b, A, Q, O) => {
|
|
1809
|
+
let V = A.part, X = V.length, J = Q + X;
|
|
1810
|
+
if (X > 1) {
|
|
1811
|
+
if (J > b)
|
|
1812
|
+
return null;
|
|
1813
|
+
if (X < 15) {
|
|
1814
|
+
for (let K = 1, G = Q + 1;K < X; ++K, ++G)
|
|
1815
|
+
if (V.charCodeAt(K) !== v.charCodeAt(G))
|
|
1816
|
+
return null;
|
|
1817
|
+
} else if (v.slice(Q, J) !== V)
|
|
1818
|
+
return null;
|
|
1819
|
+
}
|
|
1820
|
+
if (J === b) {
|
|
1821
|
+
if (A.store !== null)
|
|
1822
|
+
return { store: A.store, params: {} };
|
|
1823
|
+
if (A.wildcardStore !== null)
|
|
1824
|
+
return { store: A.wildcardStore, params: { "*": "" } };
|
|
1825
|
+
return null;
|
|
1826
|
+
}
|
|
1827
|
+
if (A.inert !== null) {
|
|
1828
|
+
let K = A.inert[v.charCodeAt(J)];
|
|
1829
|
+
if (K !== undefined) {
|
|
1830
|
+
let G = $(v, b, K, J, O);
|
|
1831
|
+
if (G !== null)
|
|
1832
|
+
return G;
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
if (A.params !== null) {
|
|
1836
|
+
let { store: K, name: G, inert: q } = A.params, U = v.indexOf("/", J);
|
|
1837
|
+
if (U !== J) {
|
|
1838
|
+
if (U === -1 || U >= b) {
|
|
1839
|
+
if (K !== null) {
|
|
1840
|
+
let F = {};
|
|
1841
|
+
if (F[G] = v.substring(J, b), O)
|
|
1842
|
+
for (let B = 0;B < O.length; B++) {
|
|
1843
|
+
let D = O[B](F[G], G);
|
|
1844
|
+
if (D !== undefined)
|
|
1845
|
+
F[G] = D;
|
|
1846
|
+
}
|
|
1847
|
+
return { store: K, params: F };
|
|
1848
|
+
}
|
|
1849
|
+
} else if (q !== null) {
|
|
1850
|
+
let F = $(v, b, q, U, O);
|
|
1851
|
+
if (F !== null) {
|
|
1852
|
+
if (F.params[G] = v.substring(J, U), O)
|
|
1853
|
+
for (let B = 0;B < O.length; B++) {
|
|
1854
|
+
let D = O[B](F.params[G], G);
|
|
1855
|
+
if (D !== undefined)
|
|
1856
|
+
F.params[G] = D;
|
|
1857
|
+
}
|
|
1858
|
+
return F;
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
if (A.wildcardStore !== null)
|
|
1864
|
+
return { store: A.wildcardStore, params: { "*": v.substring(J, b) } };
|
|
1865
|
+
return null;
|
|
1866
|
+
};
|
|
1867
|
+
var w = _;
|
|
1868
|
+
|
|
1869
|
+
// src/Router/adapters/MemoiristAdapter.ts
|
|
1870
|
+
class MemoiristAdapter {
|
|
1871
|
+
router = new w;
|
|
1872
|
+
pendingMiddlewares = new Map;
|
|
1873
|
+
find(req) {
|
|
1874
|
+
const method = req.method;
|
|
1875
|
+
const pathname = req.urlObject.pathname;
|
|
1876
|
+
const searchParams = req.urlObject.searchParams;
|
|
1877
|
+
const result = this.router.find(method, pathname);
|
|
1878
|
+
if (!result)
|
|
1879
|
+
return null;
|
|
1880
|
+
return {
|
|
1881
|
+
route: result.store.route,
|
|
1882
|
+
model: result.store.model,
|
|
1883
|
+
params: result.params,
|
|
1884
|
+
search: Object.fromEntries(searchParams),
|
|
1885
|
+
middleware: compile(result.store.middlewares ?? [])
|
|
1886
|
+
};
|
|
1887
|
+
}
|
|
1888
|
+
list() {
|
|
1889
|
+
return this.router.history.map((v) => v[2].route);
|
|
1890
|
+
}
|
|
1891
|
+
addRoute(data) {
|
|
1892
|
+
this.router.add(data.method, data.endpoint, { route: data });
|
|
1893
|
+
const pending = this.pendingMiddlewares.get(data.id);
|
|
1894
|
+
if (pending) {
|
|
1895
|
+
const store = this.router.find(data.method, data.endpoint)?.store;
|
|
1896
|
+
if (store)
|
|
1897
|
+
store.middlewares = pending;
|
|
1898
|
+
this.pendingMiddlewares.delete(data.id);
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
addModel(route, model) {
|
|
1902
|
+
const result = this.router.find(route.method, route.endpoint);
|
|
1903
|
+
if (!result)
|
|
1904
|
+
return;
|
|
1905
|
+
result.store.model = ModelRegistry.toRouterModelData(model);
|
|
1906
|
+
}
|
|
1907
|
+
addMiddleware(middleware) {
|
|
1908
|
+
const resolved = MiddlewareRegistry.resolveRouteIds(middleware);
|
|
1909
|
+
if (resolved.isGlobal) {
|
|
1910
|
+
for (const [, , store] of this.router.history) {
|
|
1911
|
+
store.middlewares = [...store.middlewares ?? [], middleware.handler];
|
|
1912
|
+
}
|
|
1913
|
+
return;
|
|
1914
|
+
}
|
|
1915
|
+
for (const routeId of resolved.routeIds) {
|
|
1916
|
+
const [method, endpoint] = routeId.split(" ", 2);
|
|
1917
|
+
const result = this.router.find(method, endpoint);
|
|
1918
|
+
if (result) {
|
|
1919
|
+
result.store.middlewares = [
|
|
1920
|
+
...result.store.middlewares ?? [],
|
|
1921
|
+
middleware.handler
|
|
1922
|
+
];
|
|
1923
|
+
} else {
|
|
1924
|
+
const pending = this.pendingMiddlewares.get(routeId) ?? [];
|
|
1925
|
+
this.pendingMiddlewares.set(routeId, [...pending, middleware.handler]);
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1451
1929
|
}
|
|
1452
|
-
|
|
1930
|
+
// src/index.ts
|
|
1931
|
+
var _prefixStore = new GlobalPrefixStore;
|
|
1932
|
+
var _routerStore = new GlobalRouterStore;
|
|
1933
|
+
var _corsStore = new GlobalCorsStore;
|
|
1453
1934
|
export {
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1935
|
+
exports_C as default,
|
|
1936
|
+
_routerStore,
|
|
1937
|
+
_prefixStore,
|
|
1938
|
+
_corsStore,
|
|
1939
|
+
exports_X as X,
|
|
1457
1940
|
Status,
|
|
1458
1941
|
StaticRoute,
|
|
1459
1942
|
Server,
|
|
1460
1943
|
Route,
|
|
1461
|
-
|
|
1462
|
-
|
|
1944
|
+
CResponse as Response,
|
|
1945
|
+
CRequest as Request,
|
|
1463
1946
|
RepositoryAbstract as Repository,
|
|
1464
1947
|
Parser,
|
|
1465
1948
|
Middleware,
|
|
1466
1949
|
Method,
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1950
|
+
MemoiristAdapter,
|
|
1951
|
+
CHeaders as Headers,
|
|
1952
|
+
XFile as File,
|
|
1953
|
+
exports_X as Extra,
|
|
1954
|
+
CError as Error,
|
|
1955
|
+
Cors,
|
|
1471
1956
|
Cookies,
|
|
1472
1957
|
ControllerAbstract as Controller,
|
|
1473
1958
|
Context,
|
|
1474
1959
|
Config,
|
|
1475
1960
|
CommonHeaders,
|
|
1476
|
-
|
|
1961
|
+
exports_C as C
|
|
1477
1962
|
};
|