routup 6.0.0-beta.4 → 6.0.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/README.md +1 -2
- package/dist/bun.d.mts +2 -2
- package/dist/bun.mjs +2 -2
- package/dist/cloudflare.d.mts +2 -2
- package/dist/cloudflare.mjs +2 -2
- package/dist/deno.d.mts +2 -2
- package/dist/deno.mjs +2 -2
- package/dist/generic.d.mts +2 -2
- package/dist/generic.mjs +2 -2
- package/dist/{index-colifb1o.d.mts → index-lqadk4U6.d.mts} +2 -8
- package/dist/node.d.mts +2 -2
- package/dist/node.mjs +2 -2
- package/dist/service-worker.d.mts +2 -2
- package/dist/service-worker.mjs +2 -2
- package/dist/{src-DE8cCC5t.mjs → src-CA6xFXqy.mjs} +148 -160
- package/dist/src-CA6xFXqy.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/src-DE8cCC5t.mjs.map +0 -1
|
@@ -490,6 +490,152 @@ function setResponseHeaderContentType(event, input, ifNotExists) {
|
|
|
490
490
|
if (contentType) event.response.headers.set(HeaderName.CONTENT_TYPE, contentType);
|
|
491
491
|
}
|
|
492
492
|
//#endregion
|
|
493
|
+
//#region src/response/helpers/send-file.ts
|
|
494
|
+
async function sendFile(event, options) {
|
|
495
|
+
let stats;
|
|
496
|
+
if (typeof options.stats === "function") stats = await options.stats();
|
|
497
|
+
else stats = options.stats;
|
|
498
|
+
const name = options.name || stats.name;
|
|
499
|
+
const { headers } = event.response;
|
|
500
|
+
const disposition = options.disposition ?? (options.attachment ? "attachment" : void 0);
|
|
501
|
+
if (name) {
|
|
502
|
+
const fileName = basename(name);
|
|
503
|
+
if (disposition) {
|
|
504
|
+
if (!headers.get(HeaderName.CONTENT_DISPOSITION)) if (disposition === "inline") setResponseHeaderInline(event, fileName);
|
|
505
|
+
else setResponseHeaderAttachment(event, fileName);
|
|
506
|
+
} else setResponseContentTypeByFileName(event, fileName);
|
|
507
|
+
}
|
|
508
|
+
const contentOptions = {};
|
|
509
|
+
let statusCode = event.response.status;
|
|
510
|
+
if (stats.size) {
|
|
511
|
+
const rangeHeader = event.headers.get(HeaderName.RANGE);
|
|
512
|
+
if (rangeHeader) {
|
|
513
|
+
const [x, y] = rangeHeader.replace("bytes=", "").split("-");
|
|
514
|
+
const parsedStart = Number.parseInt(x, 10);
|
|
515
|
+
const parsedEnd = Number.parseInt(y, 10);
|
|
516
|
+
contentOptions.start = Number.isFinite(parsedStart) && parsedStart >= 0 ? parsedStart : 0;
|
|
517
|
+
contentOptions.end = Number.isFinite(parsedEnd) && parsedEnd >= 0 ? Math.min(parsedEnd, stats.size - 1) : stats.size - 1;
|
|
518
|
+
if (contentOptions.start >= stats.size || contentOptions.start > contentOptions.end) {
|
|
519
|
+
const rangeHeaders = new Headers(headers);
|
|
520
|
+
rangeHeaders.set(HeaderName.CONTENT_RANGE, `bytes */${stats.size}`);
|
|
521
|
+
return new Response(null, {
|
|
522
|
+
status: 416,
|
|
523
|
+
headers: rangeHeaders
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
headers.set(HeaderName.CONTENT_RANGE, `bytes ${contentOptions.start}-${contentOptions.end}/${stats.size}`);
|
|
527
|
+
headers.set(HeaderName.CONTENT_LENGTH, `${contentOptions.end - contentOptions.start + 1}`);
|
|
528
|
+
statusCode = 206;
|
|
529
|
+
} else headers.set(HeaderName.CONTENT_LENGTH, `${stats.size}`);
|
|
530
|
+
headers.set(HeaderName.ACCEPT_RANGES, "bytes");
|
|
531
|
+
if (stats.mtime) {
|
|
532
|
+
const mtime = new Date(stats.mtime);
|
|
533
|
+
headers.set(HeaderName.LAST_MODIFIED, mtime.toUTCString());
|
|
534
|
+
headers.set(HeaderName.ETag, `W/"${stats.size}-${mtime.getTime()}"`);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
const content = await options.content(contentOptions);
|
|
538
|
+
return new Response(content, {
|
|
539
|
+
status: statusCode,
|
|
540
|
+
headers
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
//#endregion
|
|
544
|
+
//#region src/request/helpers/header.ts
|
|
545
|
+
function getRequestHeader(event, name) {
|
|
546
|
+
return event.headers.get(name);
|
|
547
|
+
}
|
|
548
|
+
//#endregion
|
|
549
|
+
//#region src/request/helpers/negotiator.ts
|
|
550
|
+
const NEGOTIATOR_KEY = Symbol.for("routup:negotiator");
|
|
551
|
+
function headersToPlainObject(headers) {
|
|
552
|
+
const result = {};
|
|
553
|
+
headers.forEach((value, key) => {
|
|
554
|
+
result[key] = value;
|
|
555
|
+
});
|
|
556
|
+
return result;
|
|
557
|
+
}
|
|
558
|
+
function useRequestNegotiator(event) {
|
|
559
|
+
let value = event.store[NEGOTIATOR_KEY];
|
|
560
|
+
if (value) return value;
|
|
561
|
+
value = new Negotiator({ headers: headersToPlainObject(event.headers) });
|
|
562
|
+
event.store[NEGOTIATOR_KEY] = value;
|
|
563
|
+
return value;
|
|
564
|
+
}
|
|
565
|
+
//#endregion
|
|
566
|
+
//#region src/request/helpers/header-accept.ts
|
|
567
|
+
function getRequestAcceptableContentTypes(event) {
|
|
568
|
+
return useRequestNegotiator(event).mediaTypes();
|
|
569
|
+
}
|
|
570
|
+
function getRequestAcceptableContentType(event, input) {
|
|
571
|
+
input = input || [];
|
|
572
|
+
const items = Array.isArray(input) ? input : [input];
|
|
573
|
+
if (items.length === 0) return getRequestAcceptableContentTypes(event).shift();
|
|
574
|
+
if (!getRequestHeader(event, HeaderName.ACCEPT)) return items[0];
|
|
575
|
+
let polluted = false;
|
|
576
|
+
const mimeTypes = [];
|
|
577
|
+
for (const item of items) {
|
|
578
|
+
const mimeType = getMimeType(item);
|
|
579
|
+
if (mimeType) mimeTypes.push(mimeType);
|
|
580
|
+
else polluted = true;
|
|
581
|
+
}
|
|
582
|
+
const matches = useRequestNegotiator(event).mediaTypes(mimeTypes);
|
|
583
|
+
if (matches.length > 0) {
|
|
584
|
+
if (polluted) return items[0];
|
|
585
|
+
return items[mimeTypes.indexOf(matches[0])];
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
//#endregion
|
|
589
|
+
//#region src/response/helpers/send-format.ts
|
|
590
|
+
function sendFormat(event, input) {
|
|
591
|
+
const { default: formatDefault, ...formats } = input;
|
|
592
|
+
const contentTypes = Object.keys(formats);
|
|
593
|
+
if (contentTypes.length === 0) return formatDefault();
|
|
594
|
+
const contentType = getRequestAcceptableContentType(event, contentTypes);
|
|
595
|
+
if (contentType && formats[contentType]) return formats[contentType]();
|
|
596
|
+
return formatDefault();
|
|
597
|
+
}
|
|
598
|
+
//#endregion
|
|
599
|
+
//#region src/response/helpers/send-redirect.ts
|
|
600
|
+
function escapeHtml(str) {
|
|
601
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
602
|
+
}
|
|
603
|
+
function isAllowedRedirectUrl(location) {
|
|
604
|
+
if (location.startsWith("//")) return false;
|
|
605
|
+
if (location.startsWith("/") || location.startsWith(".")) return true;
|
|
606
|
+
try {
|
|
607
|
+
const url = new URL(location);
|
|
608
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
609
|
+
} catch {
|
|
610
|
+
return true;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
function sendRedirect(event, location, statusCode = 302) {
|
|
614
|
+
if (!isAllowedRedirectUrl(location)) throw new AppError({
|
|
615
|
+
status: 400,
|
|
616
|
+
message: "Invalid redirect URL scheme."
|
|
617
|
+
});
|
|
618
|
+
const sanitizedLocation = sanitizeHeaderValue(location);
|
|
619
|
+
const html = `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${escapeHtml(location)}"></head></html>`;
|
|
620
|
+
const headers = new Headers(event.response.headers);
|
|
621
|
+
headers.set("location", sanitizedLocation);
|
|
622
|
+
headers.set("content-type", "text/html; charset=utf-8");
|
|
623
|
+
headers.delete("content-length");
|
|
624
|
+
return new Response(html, {
|
|
625
|
+
status: statusCode,
|
|
626
|
+
headers
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
//#endregion
|
|
630
|
+
//#region src/response/helpers/send-stream.ts
|
|
631
|
+
function sendStream(event, stream) {
|
|
632
|
+
const { status, headers } = event.response;
|
|
633
|
+
return new Response(stream, {
|
|
634
|
+
status,
|
|
635
|
+
headers
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
//#endregion
|
|
493
639
|
//#region src/error/is.ts
|
|
494
640
|
function isError(input) {
|
|
495
641
|
return hasInstanceof(input, ErrorSymbol);
|
|
@@ -638,164 +784,6 @@ function toResponse(value, event) {
|
|
|
638
784
|
});
|
|
639
785
|
}
|
|
640
786
|
//#endregion
|
|
641
|
-
//#region src/response/helpers/send-accepted.ts
|
|
642
|
-
async function sendAccepted(event, data) {
|
|
643
|
-
event.response.status = 202;
|
|
644
|
-
return await toResponse(data ?? "", event);
|
|
645
|
-
}
|
|
646
|
-
//#endregion
|
|
647
|
-
//#region src/response/helpers/send-created.ts
|
|
648
|
-
async function sendCreated(event, data) {
|
|
649
|
-
event.response.status = 201;
|
|
650
|
-
return await toResponse(data ?? "", event);
|
|
651
|
-
}
|
|
652
|
-
//#endregion
|
|
653
|
-
//#region src/response/helpers/send-file.ts
|
|
654
|
-
async function sendFile(event, options) {
|
|
655
|
-
let stats;
|
|
656
|
-
if (typeof options.stats === "function") stats = await options.stats();
|
|
657
|
-
else stats = options.stats;
|
|
658
|
-
const name = options.name || stats.name;
|
|
659
|
-
const { headers } = event.response;
|
|
660
|
-
const disposition = options.disposition ?? (options.attachment ? "attachment" : void 0);
|
|
661
|
-
if (name) {
|
|
662
|
-
const fileName = basename(name);
|
|
663
|
-
if (disposition) {
|
|
664
|
-
if (!headers.get(HeaderName.CONTENT_DISPOSITION)) if (disposition === "inline") setResponseHeaderInline(event, fileName);
|
|
665
|
-
else setResponseHeaderAttachment(event, fileName);
|
|
666
|
-
} else setResponseContentTypeByFileName(event, fileName);
|
|
667
|
-
}
|
|
668
|
-
const contentOptions = {};
|
|
669
|
-
let statusCode = event.response.status;
|
|
670
|
-
if (stats.size) {
|
|
671
|
-
const rangeHeader = event.headers.get(HeaderName.RANGE);
|
|
672
|
-
if (rangeHeader) {
|
|
673
|
-
const [x, y] = rangeHeader.replace("bytes=", "").split("-");
|
|
674
|
-
const parsedStart = Number.parseInt(x, 10);
|
|
675
|
-
const parsedEnd = Number.parseInt(y, 10);
|
|
676
|
-
contentOptions.start = Number.isFinite(parsedStart) && parsedStart >= 0 ? parsedStart : 0;
|
|
677
|
-
contentOptions.end = Number.isFinite(parsedEnd) && parsedEnd >= 0 ? Math.min(parsedEnd, stats.size - 1) : stats.size - 1;
|
|
678
|
-
if (contentOptions.start >= stats.size || contentOptions.start > contentOptions.end) {
|
|
679
|
-
const rangeHeaders = new Headers(headers);
|
|
680
|
-
rangeHeaders.set(HeaderName.CONTENT_RANGE, `bytes */${stats.size}`);
|
|
681
|
-
return new Response(null, {
|
|
682
|
-
status: 416,
|
|
683
|
-
headers: rangeHeaders
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
headers.set(HeaderName.CONTENT_RANGE, `bytes ${contentOptions.start}-${contentOptions.end}/${stats.size}`);
|
|
687
|
-
headers.set(HeaderName.CONTENT_LENGTH, `${contentOptions.end - contentOptions.start + 1}`);
|
|
688
|
-
statusCode = 206;
|
|
689
|
-
} else headers.set(HeaderName.CONTENT_LENGTH, `${stats.size}`);
|
|
690
|
-
headers.set(HeaderName.ACCEPT_RANGES, "bytes");
|
|
691
|
-
if (stats.mtime) {
|
|
692
|
-
const mtime = new Date(stats.mtime);
|
|
693
|
-
headers.set(HeaderName.LAST_MODIFIED, mtime.toUTCString());
|
|
694
|
-
headers.set(HeaderName.ETag, `W/"${stats.size}-${mtime.getTime()}"`);
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
const content = await options.content(contentOptions);
|
|
698
|
-
return new Response(content, {
|
|
699
|
-
status: statusCode,
|
|
700
|
-
headers
|
|
701
|
-
});
|
|
702
|
-
}
|
|
703
|
-
//#endregion
|
|
704
|
-
//#region src/request/helpers/header.ts
|
|
705
|
-
function getRequestHeader(event, name) {
|
|
706
|
-
return event.headers.get(name);
|
|
707
|
-
}
|
|
708
|
-
//#endregion
|
|
709
|
-
//#region src/request/helpers/negotiator.ts
|
|
710
|
-
const NEGOTIATOR_KEY = Symbol.for("routup:negotiator");
|
|
711
|
-
function headersToPlainObject(headers) {
|
|
712
|
-
const result = {};
|
|
713
|
-
headers.forEach((value, key) => {
|
|
714
|
-
result[key] = value;
|
|
715
|
-
});
|
|
716
|
-
return result;
|
|
717
|
-
}
|
|
718
|
-
function useRequestNegotiator(event) {
|
|
719
|
-
let value = event.store[NEGOTIATOR_KEY];
|
|
720
|
-
if (value) return value;
|
|
721
|
-
value = new Negotiator({ headers: headersToPlainObject(event.headers) });
|
|
722
|
-
event.store[NEGOTIATOR_KEY] = value;
|
|
723
|
-
return value;
|
|
724
|
-
}
|
|
725
|
-
//#endregion
|
|
726
|
-
//#region src/request/helpers/header-accept.ts
|
|
727
|
-
function getRequestAcceptableContentTypes(event) {
|
|
728
|
-
return useRequestNegotiator(event).mediaTypes();
|
|
729
|
-
}
|
|
730
|
-
function getRequestAcceptableContentType(event, input) {
|
|
731
|
-
input = input || [];
|
|
732
|
-
const items = Array.isArray(input) ? input : [input];
|
|
733
|
-
if (items.length === 0) return getRequestAcceptableContentTypes(event).shift();
|
|
734
|
-
if (!getRequestHeader(event, HeaderName.ACCEPT)) return items[0];
|
|
735
|
-
let polluted = false;
|
|
736
|
-
const mimeTypes = [];
|
|
737
|
-
for (const item of items) {
|
|
738
|
-
const mimeType = getMimeType(item);
|
|
739
|
-
if (mimeType) mimeTypes.push(mimeType);
|
|
740
|
-
else polluted = true;
|
|
741
|
-
}
|
|
742
|
-
const matches = useRequestNegotiator(event).mediaTypes(mimeTypes);
|
|
743
|
-
if (matches.length > 0) {
|
|
744
|
-
if (polluted) return items[0];
|
|
745
|
-
return items[mimeTypes.indexOf(matches[0])];
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
//#endregion
|
|
749
|
-
//#region src/response/helpers/send-format.ts
|
|
750
|
-
function sendFormat(event, input) {
|
|
751
|
-
const { default: formatDefault, ...formats } = input;
|
|
752
|
-
const contentTypes = Object.keys(formats);
|
|
753
|
-
if (contentTypes.length === 0) return formatDefault();
|
|
754
|
-
const contentType = getRequestAcceptableContentType(event, contentTypes);
|
|
755
|
-
if (contentType && formats[contentType]) return formats[contentType]();
|
|
756
|
-
return formatDefault();
|
|
757
|
-
}
|
|
758
|
-
//#endregion
|
|
759
|
-
//#region src/response/helpers/send-redirect.ts
|
|
760
|
-
function escapeHtml(str) {
|
|
761
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
762
|
-
}
|
|
763
|
-
function isAllowedRedirectUrl(location) {
|
|
764
|
-
if (location.startsWith("//")) return false;
|
|
765
|
-
if (location.startsWith("/") || location.startsWith(".")) return true;
|
|
766
|
-
try {
|
|
767
|
-
const url = new URL(location);
|
|
768
|
-
return url.protocol === "http:" || url.protocol === "https:";
|
|
769
|
-
} catch {
|
|
770
|
-
return true;
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
function sendRedirect(event, location, statusCode = 302) {
|
|
774
|
-
if (!isAllowedRedirectUrl(location)) throw new AppError({
|
|
775
|
-
status: 400,
|
|
776
|
-
message: "Invalid redirect URL scheme."
|
|
777
|
-
});
|
|
778
|
-
const sanitizedLocation = sanitizeHeaderValue(location);
|
|
779
|
-
const html = `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${escapeHtml(location)}"></head></html>`;
|
|
780
|
-
const headers = new Headers(event.response.headers);
|
|
781
|
-
headers.set("location", sanitizedLocation);
|
|
782
|
-
headers.set("content-type", "text/html; charset=utf-8");
|
|
783
|
-
headers.delete("content-length");
|
|
784
|
-
return new Response(html, {
|
|
785
|
-
status: statusCode,
|
|
786
|
-
headers
|
|
787
|
-
});
|
|
788
|
-
}
|
|
789
|
-
//#endregion
|
|
790
|
-
//#region src/response/helpers/send-stream.ts
|
|
791
|
-
function sendStream(event, stream) {
|
|
792
|
-
const { status, headers } = event.response;
|
|
793
|
-
return new Response(stream, {
|
|
794
|
-
status,
|
|
795
|
-
headers
|
|
796
|
-
});
|
|
797
|
-
}
|
|
798
|
-
//#endregion
|
|
799
787
|
//#region src/dispatcher/module.ts
|
|
800
788
|
var DispatcherEvent = class {
|
|
801
789
|
request;
|
|
@@ -2758,6 +2746,6 @@ var App = class App {
|
|
|
2758
2746
|
}
|
|
2759
2747
|
};
|
|
2760
2748
|
//#endregion
|
|
2761
|
-
export {
|
|
2749
|
+
export { setResponseHeaderInline as $, isWebHandler as A, toResponse as B, getRequestAcceptableCharset as C, isHandler as D, matchHandlerMethod as E, defineCoreHandler as F, sendFormat as G, isError as H, Handler as I, useRequestNegotiator as J, getRequestAcceptableContentType as K, HandlerSymbol as L, fromNodeHandler as M, fromNodeMiddleware as N, isHandlerOptions as O, defineErrorHandler as P, setResponseHeaderAttachment as Q, HandlerType as R, getRequestAcceptableEncodings as S, isRequestCacheable as T, sendStream as U, createError as V, sendRedirect as W, sendFile as X, getRequestHeader as Y, setResponseHeaderContentType as Z, getRequestHostName as _, LinearRouter as a, AppError as at, getRequestAcceptableLanguages as b, PluginNotInstalledError as c, AppEvent as ct, isPluginError as d, LruCache as dt, setResponseContentTypeByFileName as et, PluginErrorCode as f, getRequestIP as g, getRequestProtocol as h, TrieRouter as i, serializeEventStreamMessage as it, isWebHandlerProvider as j, fromWebHandler as k, PluginInstallError as l, HeaderName as lt, PathMatcher as m, normalizeAppOptions as n, appendResponseHeaderDirective as nt, buildRoutePathMatcher as o, ErrorSymbol as ot, isPath as p, getRequestAcceptableContentTypes as q, SmartRouter as r, createEventStream as rt, isPlugin as s, setResponseCacheHeaders as st, App as t, appendResponseHeader as tt, PluginError as u, MethodName as ut, matchRequestContentType as v, getRequestAcceptableCharsets as w, getRequestAcceptableEncoding as x, getRequestAcceptableLanguage as y, DispatcherEvent as z };
|
|
2762
2750
|
|
|
2763
|
-
//# sourceMappingURL=src-
|
|
2751
|
+
//# sourceMappingURL=src-CA6xFXqy.mjs.map
|