@wooksjs/event-http 0.7.4 → 0.7.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/dist/index.cjs +609 -422
- package/dist/index.d.ts +59 -19
- package/dist/index.mjs +610 -424
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { EventContext, cached, cachedBy, createEventContext, current, defineEventKind, defineWook, routeParamsKey, run, slot, useEventId, useLogger, useRouteParams } from "@wooksjs/event-core";
|
|
1
|
+
import { EventContext, cached, cachedBy, createEventContext, current, defineEventKind, defineWook, routeParamsKey, run, slot, tryGetCurrent, useEventId, useLogger, useRouteParams } from "@wooksjs/event-core";
|
|
2
2
|
import { Buffer as Buffer$1 } from "buffer";
|
|
3
3
|
import { Readable, pipeline } from "node:stream";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
5
|
import { createBrotliCompress, createBrotliDecompress, createDeflate, createGunzip, createGzip, createInflate } from "node:zlib";
|
|
6
6
|
import { URLSearchParams } from "url";
|
|
7
7
|
import http, { IncomingMessage, ServerResponse } from "http";
|
|
8
|
+
import { Socket } from "net";
|
|
8
9
|
import { WooksAdapterBase } from "wooks";
|
|
9
10
|
import { Readable as Readable$1 } from "stream";
|
|
10
|
-
import { Socket } from "net";
|
|
11
11
|
|
|
12
12
|
//#region packages/event-http/src/http-kind.ts
|
|
13
13
|
/** Event kind definition for HTTP requests. Provides typed context slots for `req`, `response`, and `requestLimits`. */
|
|
@@ -646,430 +646,80 @@ function useHttpContext(ctx) {
|
|
|
646
646
|
}
|
|
647
647
|
|
|
648
648
|
//#endregion
|
|
649
|
-
//#region packages/event-http/src/
|
|
650
|
-
function
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
<path d="M61.5395 46.0812H38.4604C37.1061 46.0812 36.0083 47.1791 36.0083 48.5333V65.075C36.0083 66.4292 37.1061 67.5271 38.4604 67.5271H61.5395C62.8938 67.5271 63.9916 66.4292 63.9916 65.075V48.5333C63.9916 47.1791 62.8938 46.0812 61.5395 46.0812Z" />
|
|
658
|
-
|
|
659
|
-
<path d="M41.7834 46.0834V39.6813C41.7834 37.5021 42.6491 35.4121 44.1901 33.8712C45.731 32.3303 47.8209 31.4646 50.0001 31.4646C52.1793 31.4646 54.2693 32.3303 55.8102 33.8712C57.3511 35.4121 58.2168 37.5021 58.2168 39.6813V46.0813" />
|
|
660
|
-
</svg>
|
|
661
|
-
`;
|
|
649
|
+
//#region packages/event-http/src/utils/time.ts
|
|
650
|
+
function convertTime(time, unit = "ms") {
|
|
651
|
+
if (typeof time === "number") return time / units[unit];
|
|
652
|
+
const rg = /(\d+)(\w+)/gu;
|
|
653
|
+
let t = 0;
|
|
654
|
+
let r;
|
|
655
|
+
while (r = rg.exec(time)) t += Number(r[1]) * (units[r[2]] || 0);
|
|
656
|
+
return t / units[unit];
|
|
662
657
|
}
|
|
658
|
+
const units = {
|
|
659
|
+
ms: 1,
|
|
660
|
+
s: 1e3,
|
|
661
|
+
m: 1e3 * 60,
|
|
662
|
+
h: 1e3 * 60 * 60,
|
|
663
|
+
d: 1e3 * 60 * 60 * 24,
|
|
664
|
+
w: 1e3 * 60 * 60 * 24 * 7,
|
|
665
|
+
M: 1e3 * 60 * 60 * 24 * 30,
|
|
666
|
+
Y: 1e3 * 60 * 60 * 24 * 365
|
|
667
|
+
};
|
|
663
668
|
|
|
664
669
|
//#endregion
|
|
665
|
-
//#region packages/event-http/src/
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
<animate attributeName="opacity"
|
|
679
|
-
dur="3s" repeatCount="indefinite"
|
|
680
|
-
keyTimes="0;0.1;0.32;0.42;1"
|
|
681
|
-
values="0;1;1;0;0" />
|
|
682
|
-
</use>
|
|
683
|
-
|
|
684
|
-
<use href="#sheet" opacity="0">
|
|
685
|
-
<animateTransform attributeName="transform" type="translate"
|
|
686
|
-
dur="3s" begin="1s" repeatCount="indefinite"
|
|
687
|
-
keyTimes="0;0.1;0.32;0.42;1"
|
|
688
|
-
values="30 0; -20 0; -20 0; -70 0; -70 0" />
|
|
689
|
-
<animate attributeName="opacity"
|
|
690
|
-
dur="3s" begin="1s" repeatCount="indefinite"
|
|
691
|
-
keyTimes="0;0.1;0.32;0.42;1"
|
|
692
|
-
values="0;1;1;0;0" />
|
|
693
|
-
</use>
|
|
694
|
-
|
|
695
|
-
<use href="#sheet" opacity="0">
|
|
696
|
-
<animateTransform attributeName="transform" type="translate"
|
|
697
|
-
dur="3s" begin="2s" repeatCount="indefinite"
|
|
698
|
-
keyTimes="0;0.1;0.32;0.42;1"
|
|
699
|
-
values="30 0; -20 0; -20 0; -70 0; -70 0" />
|
|
700
|
-
<animate attributeName="opacity"
|
|
701
|
-
dur="3s" begin="2s" repeatCount="indefinite"
|
|
702
|
-
keyTimes="0;0.1;0.32;0.42;1"
|
|
703
|
-
values="0;1;1;0;0" />
|
|
704
|
-
</use>
|
|
705
|
-
</g>
|
|
706
|
-
|
|
707
|
-
<g>
|
|
708
|
-
<path d="M49.5 32.5C58.3366 32.5 65.5 39.6634 65.5 48.5C65.5 54.4781 62.222 59.6923 57.3584 62.4404C55.0386 63.7512 52.3591 64.5 49.5 64.5C40.6634 64.5 33.5 57.3366 33.5 48.5C33.5 39.6634 40.6634 32.5 49.5 32.5Z" fill="#ffffff50" stroke="#888888" stroke-width="3"/>
|
|
709
|
-
|
|
710
|
-
<path d="M62.7101 74.5691C63.117 75.2907 64.0318 75.5459 64.7534 75.139C65.4751 74.7321 65.7302 73.8173 65.3233 73.0957L62.7101 74.5691ZM58.05 63.25L56.7434 63.9867L62.7101 74.5691L64.0167 73.8324L65.3233 73.0957L59.3567 62.5133L58.05 63.25Z" fill="#888888"/>
|
|
711
|
-
</g>
|
|
712
|
-
</svg>
|
|
713
|
-
|
|
714
|
-
`;
|
|
670
|
+
//#region packages/event-http/src/utils/cache-control.ts
|
|
671
|
+
/** Renders a `TCacheControl` object into a `Cache-Control` header string. */
|
|
672
|
+
function renderCacheControl(data) {
|
|
673
|
+
let attrs = "";
|
|
674
|
+
for (const [a, v] of Object.entries(data)) {
|
|
675
|
+
if (v === void 0) continue;
|
|
676
|
+
const func = cacheControlFunc[a];
|
|
677
|
+
if (typeof func === "function") {
|
|
678
|
+
const val = func(v);
|
|
679
|
+
if (val) attrs += attrs ? `, ${val}` : val;
|
|
680
|
+
} else throw new TypeError(`Unknown Cache-Control attribute ${a}`);
|
|
681
|
+
}
|
|
682
|
+
return attrs;
|
|
715
683
|
}
|
|
684
|
+
const cacheControlFunc = {
|
|
685
|
+
mustRevalidate: (v) => v ? "must-revalidate" : "",
|
|
686
|
+
noCache: (v) => v ? typeof v === "string" ? `no-cache="${v}"` : "no-cache" : "",
|
|
687
|
+
noStore: (v) => v ? "no-store" : "",
|
|
688
|
+
noTransform: (v) => v ? "no-transform" : "",
|
|
689
|
+
public: (v) => v ? "public" : "",
|
|
690
|
+
private: (v) => v ? typeof v === "string" ? `private="${v}"` : "private" : "",
|
|
691
|
+
proxyRevalidate: (v) => v ? "proxy-revalidate" : "",
|
|
692
|
+
maxAge: (v) => `max-age=${convertTime(v, "s").toString()}`,
|
|
693
|
+
sMaxage: (v) => `s-maxage=${convertTime(v, "s").toString()}`
|
|
694
|
+
};
|
|
716
695
|
|
|
717
696
|
//#endregion
|
|
718
|
-
//#region packages/event-http/src/
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
<g id="server">
|
|
723
|
-
|
|
724
|
-
<g fill="#88888888" stroke="#88888888" stroke-width="2" >
|
|
725
|
-
<path d="M18 90C13.5817 90 10 86.4182 10 82V38C10 33.5817 13.5817 30 18 30H50.5L58 43L52.5 53L56 68.5L49.0098 89.97L61.2141 71.4358L58.363 54.315L64.7769 43.5511L58.2763 30.2943L104.243 32.0434C108.658 32.2114 112.101 35.9267 111.933 40.3418L110.26 84.31C110.092 88.725 106.377 92.168 101.962 92L49 90H18Z" />
|
|
726
|
-
</g>
|
|
727
|
-
<circle cx="30" cy="60" r="6" fill="red">
|
|
728
|
-
<animate attributeName="fill" dur="0.8s"
|
|
729
|
-
values="red;#2d0000;red" repeatCount="indefinite"/>
|
|
730
|
-
</circle>
|
|
731
|
-
|
|
732
|
-
</g>
|
|
733
|
-
|
|
734
|
-
<g fill="lightgray" opacity="0.75">
|
|
735
|
-
<circle cx="50" cy="35" r="6">
|
|
736
|
-
<animate attributeName="cy" from="35" to="15" dur="2s"
|
|
737
|
-
repeatCount="indefinite"/>
|
|
738
|
-
<animate attributeName="opacity" values="0.75;0" dur="2s"
|
|
739
|
-
repeatCount="indefinite"/>
|
|
740
|
-
</circle>
|
|
741
|
-
<circle cx="60" cy="40" r="4">
|
|
742
|
-
<animate attributeName="cy" from="40" to="20" dur="2s"
|
|
743
|
-
begin="0.4s" repeatCount="indefinite"/>
|
|
744
|
-
<animate attributeName="opacity" values="0.75;0" dur="2s"
|
|
745
|
-
begin="0.4s" repeatCount="indefinite"/>
|
|
746
|
-
</circle>
|
|
747
|
-
</g>
|
|
748
|
-
|
|
749
|
-
</svg>
|
|
750
|
-
`;
|
|
697
|
+
//#region packages/event-http/src/utils/set-cookie.ts
|
|
698
|
+
const COOKIE_NAME_RE = /^[\w!#$%&'*+\-.^`|~]+$/;
|
|
699
|
+
function sanitizeCookieAttrValue(v) {
|
|
700
|
+
return v.replace(/[;\r\n]/g, "");
|
|
751
701
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
padding: 0 20px;
|
|
774
|
-
box-sizing: border-box;
|
|
775
|
-
transition:
|
|
776
|
-
background-color 0.3s ease,
|
|
777
|
-
color 0.3s ease;
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
.error-container {
|
|
781
|
-
padding: 48px;
|
|
782
|
-
padding-bottom: 12px !important;
|
|
783
|
-
background-color: #ffffff;
|
|
784
|
-
border-radius: 0 0 12px 12px;
|
|
785
|
-
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
|
|
786
|
-
text-align: center;
|
|
787
|
-
max-width: 650px;
|
|
788
|
-
width: 100%;
|
|
789
|
-
transition:
|
|
790
|
-
background-color 0.3s ease,
|
|
791
|
-
border-color 0.3s ease,
|
|
792
|
-
box-shadow 0.3s ease;
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
.status-code {
|
|
796
|
-
font-size: 5rem;
|
|
797
|
-
font-weight: 900;
|
|
798
|
-
margin-bottom: 5px;
|
|
799
|
-
line-height: 1;
|
|
800
|
-
transition: color 0.3s ease;
|
|
801
|
-
display: flex;
|
|
802
|
-
align-items: center;
|
|
803
|
-
justify-content: center;
|
|
804
|
-
gap: 1rem;
|
|
805
|
-
position: relative;
|
|
806
|
-
margin-right: 24px;
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
.status-text {
|
|
810
|
-
font-size: 2.25rem;
|
|
811
|
-
font-weight: 700;
|
|
812
|
-
margin-bottom: 25px;
|
|
813
|
-
transition: color 0.3s ease;
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
.error-message {
|
|
817
|
-
font-size: 1.25rem;
|
|
818
|
-
margin-bottom: 40px;
|
|
819
|
-
line-height: 1.7;
|
|
820
|
-
transition: color 0.3s ease;
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
.json-details-container {
|
|
824
|
-
padding: 20px;
|
|
825
|
-
border-radius: 8px;
|
|
826
|
-
text-align: left;
|
|
827
|
-
overflow-x: auto;
|
|
828
|
-
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
|
829
|
-
font-size: 0.9rem;
|
|
830
|
-
border: 1px solid;
|
|
831
|
-
transition:
|
|
832
|
-
background-color 0.3s ease,
|
|
833
|
-
color 0.3s ease,
|
|
834
|
-
border-color 0.3s ease;
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
.json-details-container pre {
|
|
838
|
-
margin: 0;
|
|
839
|
-
white-space: pre-wrap;
|
|
840
|
-
word-break: break-all;
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
.json-details-container code {
|
|
844
|
-
display: block;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
body {
|
|
848
|
-
background-color: #f8fafc;
|
|
849
|
-
color: #1f2937;
|
|
850
|
-
}
|
|
851
|
-
.error-container {
|
|
852
|
-
background-color: #ffffff;
|
|
853
|
-
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
|
|
854
|
-
}
|
|
855
|
-
.status-code {
|
|
856
|
-
color: #dc2626;
|
|
857
|
-
}
|
|
858
|
-
.status-text {
|
|
859
|
-
color: #1f2937;
|
|
860
|
-
}
|
|
861
|
-
.error-message {
|
|
862
|
-
color: #4b5563;
|
|
863
|
-
}
|
|
864
|
-
.json-details-container {
|
|
865
|
-
background-color: #f0f4f8;
|
|
866
|
-
color: #374151;
|
|
867
|
-
border-color: #d1d5db;
|
|
868
|
-
}
|
|
869
|
-
.json-details-container p {
|
|
870
|
-
color: #6b7280;
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
@media (prefers-color-scheme: dark) {
|
|
874
|
-
body {
|
|
875
|
-
background-color: #2d3748;
|
|
876
|
-
color: #e2e8f0;
|
|
877
|
-
}
|
|
878
|
-
.error-container {
|
|
879
|
-
background-color: #1a202c;
|
|
880
|
-
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
|
|
881
|
-
}
|
|
882
|
-
.status-code {
|
|
883
|
-
color: #f56565;
|
|
884
|
-
}
|
|
885
|
-
.status-text {
|
|
886
|
-
color: #cbd5e1;
|
|
887
|
-
}
|
|
888
|
-
.error-message {
|
|
889
|
-
color: #a0aec0;
|
|
890
|
-
}
|
|
891
|
-
.json-details-container {
|
|
892
|
-
background-color: #2d3748;
|
|
893
|
-
color: #e2e8f0;
|
|
894
|
-
border-color: #4a5568;
|
|
895
|
-
}
|
|
896
|
-
.json-details-container p {
|
|
897
|
-
color: #a0aec0;
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
.footer {
|
|
902
|
-
display: flex;
|
|
903
|
-
gap: 0.25rem;
|
|
904
|
-
font-size: 0.6em;
|
|
905
|
-
justify-content: flex-end;
|
|
906
|
-
align-items: center;
|
|
907
|
-
margin-top: 12px;
|
|
908
|
-
opacity: 0.5;
|
|
909
|
-
transition: 0.25s ease-in-out;
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
.footer img {
|
|
913
|
-
filter: grayscale(0.5);
|
|
914
|
-
transition: 0.25s ease-in-out;
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
.footer:hover {
|
|
918
|
-
opacity: 1;
|
|
919
|
-
}
|
|
920
|
-
.footer:hover img {
|
|
921
|
-
filter: grayscale(0);
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
@media (max-width: 768px) {
|
|
925
|
-
body {
|
|
926
|
-
padding: 15px;
|
|
927
|
-
}
|
|
928
|
-
.error-container {
|
|
929
|
-
padding: 32px;
|
|
930
|
-
}
|
|
931
|
-
.status-code {
|
|
932
|
-
font-size: 4rem;
|
|
933
|
-
}
|
|
934
|
-
.status-text {
|
|
935
|
-
font-size: 1.8rem;
|
|
936
|
-
}
|
|
937
|
-
.error-message {
|
|
938
|
-
font-size: 1.1rem;
|
|
939
|
-
margin-bottom: 30px;
|
|
940
|
-
}
|
|
941
|
-
.json-details-container {
|
|
942
|
-
font-size: 0.85rem;
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
@media (max-width: 480px) {
|
|
947
|
-
body {
|
|
948
|
-
padding: 10px;
|
|
949
|
-
}
|
|
950
|
-
.error-container {
|
|
951
|
-
padding: 24px;
|
|
952
|
-
border-radius: 8px;
|
|
953
|
-
}
|
|
954
|
-
.status-code {
|
|
955
|
-
font-size: 3rem;
|
|
956
|
-
}
|
|
957
|
-
.status-text {
|
|
958
|
-
font-size: 1.5rem;
|
|
959
|
-
margin-bottom: 20px;
|
|
960
|
-
}
|
|
961
|
-
.error-message {
|
|
962
|
-
font-size: 1rem;
|
|
963
|
-
margin-bottom: 25px;
|
|
964
|
-
}
|
|
965
|
-
.json-details-container {
|
|
966
|
-
padding: 15px;
|
|
967
|
-
font-size: 0.8rem;
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
</style>
|
|
971
|
-
</head>
|
|
972
|
-
<body>
|
|
973
|
-
<div class="error-container">
|
|
974
|
-
<div id="statusCode" class="status-code">${icon} ${statusCode}</div>
|
|
975
|
-
|
|
976
|
-
<div id="statusText" class="status-text">${statusMessage}</div>
|
|
977
|
-
|
|
978
|
-
<p id="errorMessage" class="error-message">${message}</p>
|
|
979
|
-
|
|
980
|
-
<!-- prettier-ignore -->
|
|
981
|
-
<div class="json-details-container"style="display: ${details ? "block" : "none"};">
|
|
982
|
-
<p class="text-sm">Technical Details:</p>
|
|
983
|
-
<pre><code id="jsonDetails">${details}</code></pre>
|
|
984
|
-
</div>
|
|
985
|
-
<div class="footer">
|
|
986
|
-
Powered by
|
|
987
|
-
<a href="${link}" target="_blank">
|
|
988
|
-
<img height="20" alt="%{poweredBy}" src="${image}" />
|
|
989
|
-
</a>
|
|
990
|
-
v${version}
|
|
991
|
-
</div>
|
|
992
|
-
</div>
|
|
993
|
-
</body>
|
|
994
|
-
</html>
|
|
995
|
-
`;
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
//#endregion
|
|
999
|
-
//#region packages/event-http/src/utils/time.ts
|
|
1000
|
-
function convertTime(time, unit = "ms") {
|
|
1001
|
-
if (typeof time === "number") return time / units[unit];
|
|
1002
|
-
const rg = /(\d+)(\w+)/gu;
|
|
1003
|
-
let t = 0;
|
|
1004
|
-
let r;
|
|
1005
|
-
while (r = rg.exec(time)) t += Number(r[1]) * (units[r[2]] || 0);
|
|
1006
|
-
return t / units[unit];
|
|
1007
|
-
}
|
|
1008
|
-
const units = {
|
|
1009
|
-
ms: 1,
|
|
1010
|
-
s: 1e3,
|
|
1011
|
-
m: 1e3 * 60,
|
|
1012
|
-
h: 1e3 * 60 * 60,
|
|
1013
|
-
d: 1e3 * 60 * 60 * 24,
|
|
1014
|
-
w: 1e3 * 60 * 60 * 24 * 7,
|
|
1015
|
-
M: 1e3 * 60 * 60 * 24 * 30,
|
|
1016
|
-
Y: 1e3 * 60 * 60 * 24 * 365
|
|
1017
|
-
};
|
|
1018
|
-
|
|
1019
|
-
//#endregion
|
|
1020
|
-
//#region packages/event-http/src/utils/cache-control.ts
|
|
1021
|
-
/** Renders a `TCacheControl` object into a `Cache-Control` header string. */
|
|
1022
|
-
function renderCacheControl(data) {
|
|
1023
|
-
let attrs = "";
|
|
1024
|
-
for (const [a, v] of Object.entries(data)) {
|
|
1025
|
-
if (v === void 0) continue;
|
|
1026
|
-
const func = cacheControlFunc[a];
|
|
1027
|
-
if (typeof func === "function") {
|
|
1028
|
-
const val = func(v);
|
|
1029
|
-
if (val) attrs += attrs ? `, ${val}` : val;
|
|
1030
|
-
} else throw new TypeError(`Unknown Cache-Control attribute ${a}`);
|
|
1031
|
-
}
|
|
1032
|
-
return attrs;
|
|
1033
|
-
}
|
|
1034
|
-
const cacheControlFunc = {
|
|
1035
|
-
mustRevalidate: (v) => v ? "must-revalidate" : "",
|
|
1036
|
-
noCache: (v) => v ? typeof v === "string" ? `no-cache="${v}"` : "no-cache" : "",
|
|
1037
|
-
noStore: (v) => v ? "no-store" : "",
|
|
1038
|
-
noTransform: (v) => v ? "no-transform" : "",
|
|
1039
|
-
public: (v) => v ? "public" : "",
|
|
1040
|
-
private: (v) => v ? typeof v === "string" ? `private="${v}"` : "private" : "",
|
|
1041
|
-
proxyRevalidate: (v) => v ? "proxy-revalidate" : "",
|
|
1042
|
-
maxAge: (v) => `max-age=${convertTime(v, "s").toString()}`,
|
|
1043
|
-
sMaxage: (v) => `s-maxage=${convertTime(v, "s").toString()}`
|
|
1044
|
-
};
|
|
1045
|
-
|
|
1046
|
-
//#endregion
|
|
1047
|
-
//#region packages/event-http/src/utils/set-cookie.ts
|
|
1048
|
-
const COOKIE_NAME_RE = /^[\w!#$%&'*+\-.^`|~]+$/;
|
|
1049
|
-
function sanitizeCookieAttrValue(v) {
|
|
1050
|
-
return v.replace(/[;\r\n]/g, "");
|
|
1051
|
-
}
|
|
1052
|
-
function renderCookie(key, data) {
|
|
1053
|
-
if (!COOKIE_NAME_RE.test(key)) throw new TypeError(`Invalid cookie name "${key}"`);
|
|
1054
|
-
let attrs = "";
|
|
1055
|
-
for (const [a, v] of Object.entries(data.attrs)) {
|
|
1056
|
-
const func = cookieAttrFunc[a];
|
|
1057
|
-
if (typeof func === "function") {
|
|
1058
|
-
const val = func(v);
|
|
1059
|
-
attrs += val ? `; ${val}` : "";
|
|
1060
|
-
} else throw new TypeError(`Unknown Set-Cookie attribute ${a}`);
|
|
1061
|
-
}
|
|
1062
|
-
return `${key}=${encodeURIComponent(data.value)}${attrs}`;
|
|
1063
|
-
}
|
|
1064
|
-
const cookieAttrFunc = {
|
|
1065
|
-
expires: (v) => `Expires=${typeof v === "string" || typeof v === "number" ? new Date(v).toUTCString() : v.toUTCString()}`,
|
|
1066
|
-
maxAge: (v) => `Max-Age=${convertTime(v, "s").toString()}`,
|
|
1067
|
-
domain: (v) => `Domain=${sanitizeCookieAttrValue(String(v))}`,
|
|
1068
|
-
path: (v) => `Path=${sanitizeCookieAttrValue(String(v))}`,
|
|
1069
|
-
secure: (v) => v ? "Secure" : "",
|
|
1070
|
-
httpOnly: (v) => v ? "HttpOnly" : "",
|
|
1071
|
-
sameSite: (v) => v ? `SameSite=${typeof v === "string" ? v : "Strict"}` : ""
|
|
1072
|
-
};
|
|
702
|
+
function renderCookie(key, data) {
|
|
703
|
+
if (!COOKIE_NAME_RE.test(key)) throw new TypeError(`Invalid cookie name "${key}"`);
|
|
704
|
+
let attrs = "";
|
|
705
|
+
for (const [a, v] of Object.entries(data.attrs)) {
|
|
706
|
+
const func = cookieAttrFunc[a];
|
|
707
|
+
if (typeof func === "function") {
|
|
708
|
+
const val = func(v);
|
|
709
|
+
attrs += val ? `; ${val}` : "";
|
|
710
|
+
} else throw new TypeError(`Unknown Set-Cookie attribute ${a}`);
|
|
711
|
+
}
|
|
712
|
+
return `${key}=${encodeURIComponent(data.value)}${attrs}`;
|
|
713
|
+
}
|
|
714
|
+
const cookieAttrFunc = {
|
|
715
|
+
expires: (v) => `Expires=${typeof v === "string" || typeof v === "number" ? new Date(v).toUTCString() : v.toUTCString()}`,
|
|
716
|
+
maxAge: (v) => `Max-Age=${convertTime(v, "s").toString()}`,
|
|
717
|
+
domain: (v) => `Domain=${sanitizeCookieAttrValue(String(v))}`,
|
|
718
|
+
path: (v) => `Path=${sanitizeCookieAttrValue(String(v))}`,
|
|
719
|
+
secure: (v) => v ? "Secure" : "",
|
|
720
|
+
httpOnly: (v) => v ? "HttpOnly" : "",
|
|
721
|
+
sameSite: (v) => v ? `SameSite=${typeof v === "string" ? v : "Strict"}` : ""
|
|
722
|
+
};
|
|
1073
723
|
|
|
1074
724
|
//#endregion
|
|
1075
725
|
//#region packages/event-http/src/response/http-response.ts
|
|
@@ -1101,10 +751,11 @@ var HttpResponse = class {
|
|
|
1101
751
|
* @param _logger - Logger instance for error reporting.
|
|
1102
752
|
* @param defaultHeaders - Optional headers to pre-populate on this response (e.g. from `securityHeaders()`).
|
|
1103
753
|
*/
|
|
1104
|
-
constructor(_res, _req, _logger, defaultHeaders) {
|
|
754
|
+
constructor(_res, _req, _logger, defaultHeaders, _captureMode = false) {
|
|
1105
755
|
this._res = _res;
|
|
1106
756
|
this._req = _req;
|
|
1107
757
|
this._logger = _logger;
|
|
758
|
+
this._captureMode = _captureMode;
|
|
1108
759
|
if (defaultHeaders) for (const key in defaultHeaders) this._headers[key] = defaultHeaders[key];
|
|
1109
760
|
}
|
|
1110
761
|
_status = 0;
|
|
@@ -1238,6 +889,54 @@ var HttpResponse = class {
|
|
|
1238
889
|
get responded() {
|
|
1239
890
|
return this._responded || !this._res.writable || this._res.writableEnded;
|
|
1240
891
|
}
|
|
892
|
+
/**
|
|
893
|
+
* Builds a Web Standard `Response` from the accumulated response state
|
|
894
|
+
* (status, headers, cookies, body) without writing to the underlying `ServerResponse`.
|
|
895
|
+
*
|
|
896
|
+
* Used by `WooksHttp.fetch()` for programmatic invocation.
|
|
897
|
+
*/
|
|
898
|
+
toWebResponse() {
|
|
899
|
+
this.finalizeCookies();
|
|
900
|
+
const body = this._body;
|
|
901
|
+
const method = this._req.method;
|
|
902
|
+
if (body instanceof Readable$1) {
|
|
903
|
+
this.autoStatus(true);
|
|
904
|
+
return new globalThis.Response(method === "HEAD" ? null : Readable$1.toWeb(body), {
|
|
905
|
+
status: this._status,
|
|
906
|
+
headers: this._buildWebHeaders()
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
if (hasFetchResponse && body instanceof globalThis.Response) {
|
|
910
|
+
this._status = this._status || body.status;
|
|
911
|
+
body.headers.forEach((v, k) => {
|
|
912
|
+
if (!this._headers[k]) this._headers[k] = v;
|
|
913
|
+
});
|
|
914
|
+
return new globalThis.Response(method === "HEAD" ? null : body.body, {
|
|
915
|
+
status: this._status,
|
|
916
|
+
headers: this._buildWebHeaders()
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
const rendered = this.renderBody();
|
|
920
|
+
this.autoStatus(!!rendered);
|
|
921
|
+
if (rendered) {
|
|
922
|
+
const contentLength = typeof rendered === "string" ? Buffer.byteLength(rendered) : rendered.byteLength;
|
|
923
|
+
this._headers["content-length"] = contentLength.toString();
|
|
924
|
+
}
|
|
925
|
+
const webBody = method === "HEAD" ? null : rendered instanceof Uint8Array ? rendered.buffer : rendered || null;
|
|
926
|
+
const webResponse = new globalThis.Response(webBody, {
|
|
927
|
+
status: this._status,
|
|
928
|
+
headers: this._buildWebHeaders()
|
|
929
|
+
});
|
|
930
|
+
if (typeof rendered === "string" && rendered) webResponse.text = () => Promise.resolve(rendered);
|
|
931
|
+
if (typeof body === "object" && body !== null && !(body instanceof Uint8Array) && !(body instanceof Readable$1) && !(hasFetchResponse && body instanceof globalThis.Response)) {
|
|
932
|
+
const original = body;
|
|
933
|
+
webResponse.json = () => Promise.resolve(original);
|
|
934
|
+
}
|
|
935
|
+
return webResponse;
|
|
936
|
+
}
|
|
937
|
+
_buildWebHeaders() {
|
|
938
|
+
return recordToWebHeaders(this._headers);
|
|
939
|
+
}
|
|
1241
940
|
renderBody() {
|
|
1242
941
|
const body = this._body;
|
|
1243
942
|
if (body === void 0 || body === null) return "";
|
|
@@ -1282,6 +981,10 @@ var HttpResponse = class {
|
|
|
1282
981
|
throw err;
|
|
1283
982
|
}
|
|
1284
983
|
this._responded = true;
|
|
984
|
+
if (this._captureMode) {
|
|
985
|
+
this.finalizeCookies();
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
1285
988
|
this.finalizeCookies();
|
|
1286
989
|
const body = this._body;
|
|
1287
990
|
const method = this._req.method;
|
|
@@ -1300,6 +1003,7 @@ var HttpResponse = class {
|
|
|
1300
1003
|
if (existing) this._headers["set-cookie"] = [...Array.isArray(existing) ? existing : [existing], ...rendered];
|
|
1301
1004
|
else this._headers["set-cookie"] = rendered;
|
|
1302
1005
|
}
|
|
1006
|
+
this._hasCookies = false;
|
|
1303
1007
|
}
|
|
1304
1008
|
autoStatus(hasBody) {
|
|
1305
1009
|
if (this._status) return;
|
|
@@ -1361,11 +1065,368 @@ var HttpResponse = class {
|
|
|
1361
1065
|
this._res.writeHead(this._status, this._headers).end(method === "HEAD" ? "" : renderedBody);
|
|
1362
1066
|
}
|
|
1363
1067
|
};
|
|
1068
|
+
/** Converts a Record of headers to a Web Standard `Headers` object. */
|
|
1069
|
+
function recordToWebHeaders(record) {
|
|
1070
|
+
const headers = new Headers();
|
|
1071
|
+
for (const [key, value] of Object.entries(record)) if (Array.isArray(value)) for (const v of value) headers.append(key, v);
|
|
1072
|
+
else if (value) headers.set(key, value);
|
|
1073
|
+
return headers;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
//#endregion
|
|
1077
|
+
//#region packages/event-http/src/errors/403.tl.svg
|
|
1078
|
+
function _403_tl_default(ctx) {
|
|
1079
|
+
return `<svg height="64" viewBox="0 4 100 96" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="#888888" stroke-width="2">
|
|
1080
|
+
<path d="M50 90.625C64.4042 87.1875 83.5751 69.8667 83.5751 48.6937V24.0854L50 9.375L16.425 24.0833V48.6937C16.425 69.8667 35.5959 87.1875 50 90.625Z" fill="#ff000050">
|
|
1081
|
+
<animate attributeName="fill" dur="2s" repeatCount="indefinite"
|
|
1082
|
+
values="#ff000000;#ff000050;#ff000000" />
|
|
1083
|
+
</path>
|
|
1084
|
+
|
|
1085
|
+
<path d="M61.5395 46.0812H38.4604C37.1061 46.0812 36.0083 47.1791 36.0083 48.5333V65.075C36.0083 66.4292 37.1061 67.5271 38.4604 67.5271H61.5395C62.8938 67.5271 63.9916 66.4292 63.9916 65.075V48.5333C63.9916 47.1791 62.8938 46.0812 61.5395 46.0812Z" />
|
|
1086
|
+
|
|
1087
|
+
<path d="M41.7834 46.0834V39.6813C41.7834 37.5021 42.6491 35.4121 44.1901 33.8712C45.731 32.3303 47.8209 31.4646 50.0001 31.4646C52.1793 31.4646 54.2693 32.3303 55.8102 33.8712C57.3511 35.4121 58.2168 37.5021 58.2168 39.6813V46.0813" />
|
|
1088
|
+
</svg>
|
|
1089
|
+
`;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
//#endregion
|
|
1093
|
+
//#region packages/event-http/src/errors/404.tl.svg
|
|
1094
|
+
function _404_tl_default(ctx) {
|
|
1095
|
+
return `<svg height="64" viewBox="0 20 100 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
1096
|
+
<defs>
|
|
1097
|
+
<path id="sheet" d="M86.5 36.5V47.5H97.5V92.5H52.5V36.5H86.5ZM63 68.5H87V67.5H63V68.5ZM63 63.5H87V62.5H63V63.5ZM63 58.5H87V57.5H63V58.5ZM96.793 46.5H87.5V37.207L96.793 46.5Z" fill="#88888833" stroke="#888888aa"/>
|
|
1098
|
+
</defs>
|
|
1099
|
+
|
|
1100
|
+
<g id="queue" transform="translate(-5 -10)">
|
|
1101
|
+
<use href="#sheet" opacity="0">
|
|
1102
|
+
<animateTransform attributeName="transform" type="translate"
|
|
1103
|
+
dur="3s" repeatCount="indefinite"
|
|
1104
|
+
keyTimes="0;0.1;0.32;0.42;1"
|
|
1105
|
+
values="30 0; -20 0; -20 0; -70 0; -70 0" />
|
|
1106
|
+
<animate attributeName="opacity"
|
|
1107
|
+
dur="3s" repeatCount="indefinite"
|
|
1108
|
+
keyTimes="0;0.1;0.32;0.42;1"
|
|
1109
|
+
values="0;1;1;0;0" />
|
|
1110
|
+
</use>
|
|
1111
|
+
|
|
1112
|
+
<use href="#sheet" opacity="0">
|
|
1113
|
+
<animateTransform attributeName="transform" type="translate"
|
|
1114
|
+
dur="3s" begin="1s" repeatCount="indefinite"
|
|
1115
|
+
keyTimes="0;0.1;0.32;0.42;1"
|
|
1116
|
+
values="30 0; -20 0; -20 0; -70 0; -70 0" />
|
|
1117
|
+
<animate attributeName="opacity"
|
|
1118
|
+
dur="3s" begin="1s" repeatCount="indefinite"
|
|
1119
|
+
keyTimes="0;0.1;0.32;0.42;1"
|
|
1120
|
+
values="0;1;1;0;0" />
|
|
1121
|
+
</use>
|
|
1122
|
+
|
|
1123
|
+
<use href="#sheet" opacity="0">
|
|
1124
|
+
<animateTransform attributeName="transform" type="translate"
|
|
1125
|
+
dur="3s" begin="2s" repeatCount="indefinite"
|
|
1126
|
+
keyTimes="0;0.1;0.32;0.42;1"
|
|
1127
|
+
values="30 0; -20 0; -20 0; -70 0; -70 0" />
|
|
1128
|
+
<animate attributeName="opacity"
|
|
1129
|
+
dur="3s" begin="2s" repeatCount="indefinite"
|
|
1130
|
+
keyTimes="0;0.1;0.32;0.42;1"
|
|
1131
|
+
values="0;1;1;0;0" />
|
|
1132
|
+
</use>
|
|
1133
|
+
</g>
|
|
1134
|
+
|
|
1135
|
+
<g>
|
|
1136
|
+
<path d="M49.5 32.5C58.3366 32.5 65.5 39.6634 65.5 48.5C65.5 54.4781 62.222 59.6923 57.3584 62.4404C55.0386 63.7512 52.3591 64.5 49.5 64.5C40.6634 64.5 33.5 57.3366 33.5 48.5C33.5 39.6634 40.6634 32.5 49.5 32.5Z" fill="#ffffff50" stroke="#888888" stroke-width="3"/>
|
|
1137
|
+
|
|
1138
|
+
<path d="M62.7101 74.5691C63.117 75.2907 64.0318 75.5459 64.7534 75.139C65.4751 74.7321 65.7302 73.8173 65.3233 73.0957L62.7101 74.5691ZM58.05 63.25L56.7434 63.9867L62.7101 74.5691L64.0167 73.8324L65.3233 73.0957L59.3567 62.5133L58.05 63.25Z" fill="#888888"/>
|
|
1139
|
+
</g>
|
|
1140
|
+
</svg>
|
|
1141
|
+
|
|
1142
|
+
`;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
//#endregion
|
|
1146
|
+
//#region packages/event-http/src/errors/500.tl.svg
|
|
1147
|
+
function _500_tl_default(ctx) {
|
|
1148
|
+
return `<svg height="64" viewBox="0 0 120 100" xmlns="http://www.w3.org/2000/svg">
|
|
1149
|
+
|
|
1150
|
+
<g id="server">
|
|
1151
|
+
|
|
1152
|
+
<g fill="#88888888" stroke="#88888888" stroke-width="2" >
|
|
1153
|
+
<path d="M18 90C13.5817 90 10 86.4182 10 82V38C10 33.5817 13.5817 30 18 30H50.5L58 43L52.5 53L56 68.5L49.0098 89.97L61.2141 71.4358L58.363 54.315L64.7769 43.5511L58.2763 30.2943L104.243 32.0434C108.658 32.2114 112.101 35.9267 111.933 40.3418L110.26 84.31C110.092 88.725 106.377 92.168 101.962 92L49 90H18Z" />
|
|
1154
|
+
</g>
|
|
1155
|
+
<circle cx="30" cy="60" r="6" fill="red">
|
|
1156
|
+
<animate attributeName="fill" dur="0.8s"
|
|
1157
|
+
values="red;#2d0000;red" repeatCount="indefinite"/>
|
|
1158
|
+
</circle>
|
|
1159
|
+
|
|
1160
|
+
</g>
|
|
1161
|
+
|
|
1162
|
+
<g fill="lightgray" opacity="0.75">
|
|
1163
|
+
<circle cx="50" cy="35" r="6">
|
|
1164
|
+
<animate attributeName="cy" from="35" to="15" dur="2s"
|
|
1165
|
+
repeatCount="indefinite"/>
|
|
1166
|
+
<animate attributeName="opacity" values="0.75;0" dur="2s"
|
|
1167
|
+
repeatCount="indefinite"/>
|
|
1168
|
+
</circle>
|
|
1169
|
+
<circle cx="60" cy="40" r="4">
|
|
1170
|
+
<animate attributeName="cy" from="40" to="20" dur="2s"
|
|
1171
|
+
begin="0.4s" repeatCount="indefinite"/>
|
|
1172
|
+
<animate attributeName="opacity" values="0.75;0" dur="2s"
|
|
1173
|
+
begin="0.4s" repeatCount="indefinite"/>
|
|
1174
|
+
</circle>
|
|
1175
|
+
</g>
|
|
1176
|
+
|
|
1177
|
+
</svg>
|
|
1178
|
+
`;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
//#endregion
|
|
1182
|
+
//#region packages/event-http/src/errors/error.tl.html
|
|
1183
|
+
function error_tl_default(ctx) {
|
|
1184
|
+
const { statusCode, statusMessage, icon, message, details, link, image, version } = ctx;
|
|
1185
|
+
return `<!doctype html>
|
|
1186
|
+
<html lang="en">
|
|
1187
|
+
<head>
|
|
1188
|
+
<meta charset="UTF-8" />
|
|
1189
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1190
|
+
<title>${statusCode} ${statusMessage}</title>
|
|
1191
|
+
<style>
|
|
1192
|
+
body {
|
|
1193
|
+
font-family:
|
|
1194
|
+
-apple-system, BlinkMacMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,
|
|
1195
|
+
'Open Sans', 'Helvetica Neue', sans-serif;
|
|
1196
|
+
display: flex;
|
|
1197
|
+
justify-content: center;
|
|
1198
|
+
align-items: flex-start;
|
|
1199
|
+
min-height: 100vh;
|
|
1200
|
+
margin: 0;
|
|
1201
|
+
padding: 0 20px;
|
|
1202
|
+
box-sizing: border-box;
|
|
1203
|
+
transition:
|
|
1204
|
+
background-color 0.3s ease,
|
|
1205
|
+
color 0.3s ease;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
.error-container {
|
|
1209
|
+
padding: 48px;
|
|
1210
|
+
padding-bottom: 12px !important;
|
|
1211
|
+
background-color: #ffffff;
|
|
1212
|
+
border-radius: 0 0 12px 12px;
|
|
1213
|
+
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
|
|
1214
|
+
text-align: center;
|
|
1215
|
+
max-width: 650px;
|
|
1216
|
+
width: 100%;
|
|
1217
|
+
transition:
|
|
1218
|
+
background-color 0.3s ease,
|
|
1219
|
+
border-color 0.3s ease,
|
|
1220
|
+
box-shadow 0.3s ease;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
.status-code {
|
|
1224
|
+
font-size: 5rem;
|
|
1225
|
+
font-weight: 900;
|
|
1226
|
+
margin-bottom: 5px;
|
|
1227
|
+
line-height: 1;
|
|
1228
|
+
transition: color 0.3s ease;
|
|
1229
|
+
display: flex;
|
|
1230
|
+
align-items: center;
|
|
1231
|
+
justify-content: center;
|
|
1232
|
+
gap: 1rem;
|
|
1233
|
+
position: relative;
|
|
1234
|
+
margin-right: 24px;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
.status-text {
|
|
1238
|
+
font-size: 2.25rem;
|
|
1239
|
+
font-weight: 700;
|
|
1240
|
+
margin-bottom: 25px;
|
|
1241
|
+
transition: color 0.3s ease;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
.error-message {
|
|
1245
|
+
font-size: 1.25rem;
|
|
1246
|
+
margin-bottom: 40px;
|
|
1247
|
+
line-height: 1.7;
|
|
1248
|
+
transition: color 0.3s ease;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
.json-details-container {
|
|
1252
|
+
padding: 20px;
|
|
1253
|
+
border-radius: 8px;
|
|
1254
|
+
text-align: left;
|
|
1255
|
+
overflow-x: auto;
|
|
1256
|
+
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
|
1257
|
+
font-size: 0.9rem;
|
|
1258
|
+
border: 1px solid;
|
|
1259
|
+
transition:
|
|
1260
|
+
background-color 0.3s ease,
|
|
1261
|
+
color 0.3s ease,
|
|
1262
|
+
border-color 0.3s ease;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
.json-details-container pre {
|
|
1266
|
+
margin: 0;
|
|
1267
|
+
white-space: pre-wrap;
|
|
1268
|
+
word-break: break-all;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
.json-details-container code {
|
|
1272
|
+
display: block;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
body {
|
|
1276
|
+
background-color: #f8fafc;
|
|
1277
|
+
color: #1f2937;
|
|
1278
|
+
}
|
|
1279
|
+
.error-container {
|
|
1280
|
+
background-color: #ffffff;
|
|
1281
|
+
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
|
|
1282
|
+
}
|
|
1283
|
+
.status-code {
|
|
1284
|
+
color: #dc2626;
|
|
1285
|
+
}
|
|
1286
|
+
.status-text {
|
|
1287
|
+
color: #1f2937;
|
|
1288
|
+
}
|
|
1289
|
+
.error-message {
|
|
1290
|
+
color: #4b5563;
|
|
1291
|
+
}
|
|
1292
|
+
.json-details-container {
|
|
1293
|
+
background-color: #f0f4f8;
|
|
1294
|
+
color: #374151;
|
|
1295
|
+
border-color: #d1d5db;
|
|
1296
|
+
}
|
|
1297
|
+
.json-details-container p {
|
|
1298
|
+
color: #6b7280;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
@media (prefers-color-scheme: dark) {
|
|
1302
|
+
body {
|
|
1303
|
+
background-color: #2d3748;
|
|
1304
|
+
color: #e2e8f0;
|
|
1305
|
+
}
|
|
1306
|
+
.error-container {
|
|
1307
|
+
background-color: #1a202c;
|
|
1308
|
+
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
|
|
1309
|
+
}
|
|
1310
|
+
.status-code {
|
|
1311
|
+
color: #f56565;
|
|
1312
|
+
}
|
|
1313
|
+
.status-text {
|
|
1314
|
+
color: #cbd5e1;
|
|
1315
|
+
}
|
|
1316
|
+
.error-message {
|
|
1317
|
+
color: #a0aec0;
|
|
1318
|
+
}
|
|
1319
|
+
.json-details-container {
|
|
1320
|
+
background-color: #2d3748;
|
|
1321
|
+
color: #e2e8f0;
|
|
1322
|
+
border-color: #4a5568;
|
|
1323
|
+
}
|
|
1324
|
+
.json-details-container p {
|
|
1325
|
+
color: #a0aec0;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
.footer {
|
|
1330
|
+
display: flex;
|
|
1331
|
+
gap: 0.25rem;
|
|
1332
|
+
font-size: 0.6em;
|
|
1333
|
+
justify-content: flex-end;
|
|
1334
|
+
align-items: center;
|
|
1335
|
+
margin-top: 12px;
|
|
1336
|
+
opacity: 0.5;
|
|
1337
|
+
transition: 0.25s ease-in-out;
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
.footer img {
|
|
1341
|
+
filter: grayscale(0.5);
|
|
1342
|
+
transition: 0.25s ease-in-out;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
.footer:hover {
|
|
1346
|
+
opacity: 1;
|
|
1347
|
+
}
|
|
1348
|
+
.footer:hover img {
|
|
1349
|
+
filter: grayscale(0);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
@media (max-width: 768px) {
|
|
1353
|
+
body {
|
|
1354
|
+
padding: 15px;
|
|
1355
|
+
}
|
|
1356
|
+
.error-container {
|
|
1357
|
+
padding: 32px;
|
|
1358
|
+
}
|
|
1359
|
+
.status-code {
|
|
1360
|
+
font-size: 4rem;
|
|
1361
|
+
}
|
|
1362
|
+
.status-text {
|
|
1363
|
+
font-size: 1.8rem;
|
|
1364
|
+
}
|
|
1365
|
+
.error-message {
|
|
1366
|
+
font-size: 1.1rem;
|
|
1367
|
+
margin-bottom: 30px;
|
|
1368
|
+
}
|
|
1369
|
+
.json-details-container {
|
|
1370
|
+
font-size: 0.85rem;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
@media (max-width: 480px) {
|
|
1375
|
+
body {
|
|
1376
|
+
padding: 10px;
|
|
1377
|
+
}
|
|
1378
|
+
.error-container {
|
|
1379
|
+
padding: 24px;
|
|
1380
|
+
border-radius: 8px;
|
|
1381
|
+
}
|
|
1382
|
+
.status-code {
|
|
1383
|
+
font-size: 3rem;
|
|
1384
|
+
}
|
|
1385
|
+
.status-text {
|
|
1386
|
+
font-size: 1.5rem;
|
|
1387
|
+
margin-bottom: 20px;
|
|
1388
|
+
}
|
|
1389
|
+
.error-message {
|
|
1390
|
+
font-size: 1rem;
|
|
1391
|
+
margin-bottom: 25px;
|
|
1392
|
+
}
|
|
1393
|
+
.json-details-container {
|
|
1394
|
+
padding: 15px;
|
|
1395
|
+
font-size: 0.8rem;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
</style>
|
|
1399
|
+
</head>
|
|
1400
|
+
<body>
|
|
1401
|
+
<div class="error-container">
|
|
1402
|
+
<div id="statusCode" class="status-code">${icon} ${statusCode}</div>
|
|
1403
|
+
|
|
1404
|
+
<div id="statusText" class="status-text">${statusMessage}</div>
|
|
1405
|
+
|
|
1406
|
+
<p id="errorMessage" class="error-message">${message}</p>
|
|
1407
|
+
|
|
1408
|
+
<!-- prettier-ignore -->
|
|
1409
|
+
<div class="json-details-container"style="display: ${details ? "block" : "none"};">
|
|
1410
|
+
<p class="text-sm">Technical Details:</p>
|
|
1411
|
+
<pre><code id="jsonDetails">${details}</code></pre>
|
|
1412
|
+
</div>
|
|
1413
|
+
<div class="footer">
|
|
1414
|
+
Powered by
|
|
1415
|
+
<a href="${link}" target="_blank">
|
|
1416
|
+
<img height="20" alt="%{poweredBy}" src="${image}" />
|
|
1417
|
+
</a>
|
|
1418
|
+
v${version}
|
|
1419
|
+
</div>
|
|
1420
|
+
</div>
|
|
1421
|
+
</body>
|
|
1422
|
+
</html>
|
|
1423
|
+
`;
|
|
1424
|
+
}
|
|
1364
1425
|
|
|
1365
1426
|
//#endregion
|
|
1366
1427
|
//#region packages/event-http/src/response/wooks-http-response.ts
|
|
1367
1428
|
let framework = {
|
|
1368
|
-
version: "0.7.
|
|
1429
|
+
version: "0.7.5",
|
|
1369
1430
|
poweredBy: "wooksjs",
|
|
1370
1431
|
link: "https://wooks.moost.org/",
|
|
1371
1432
|
image: "https://wooks.moost.org/wooks-full-logo.svg"
|
|
@@ -1436,6 +1497,13 @@ function renderErrorText(data) {
|
|
|
1436
1497
|
|
|
1437
1498
|
//#endregion
|
|
1438
1499
|
//#region packages/event-http/src/http-adapter.ts
|
|
1500
|
+
const DEFAULT_FORWARD_HEADERS = [
|
|
1501
|
+
"authorization",
|
|
1502
|
+
"cookie",
|
|
1503
|
+
"accept-language",
|
|
1504
|
+
"x-forwarded-for",
|
|
1505
|
+
"x-request-id"
|
|
1506
|
+
];
|
|
1439
1507
|
/** HTTP adapter for Wooks that provides route registration, server lifecycle, and request handling. */
|
|
1440
1508
|
var WooksHttp = class extends WooksAdapterBase {
|
|
1441
1509
|
logger;
|
|
@@ -1566,7 +1634,7 @@ var WooksHttp = class extends WooksAdapterBase {
|
|
|
1566
1634
|
* server.listen(3000)
|
|
1567
1635
|
* ```
|
|
1568
1636
|
*/
|
|
1569
|
-
getServerCb() {
|
|
1637
|
+
getServerCb(onNoMatch) {
|
|
1570
1638
|
const ctxOptions = this.eventContextOptions;
|
|
1571
1639
|
const RequestLimits = this.opts?.requestLimits;
|
|
1572
1640
|
const notFoundHandler = this.opts?.onNotFound;
|
|
@@ -1589,7 +1657,8 @@ var WooksHttp = class extends WooksAdapterBase {
|
|
|
1589
1657
|
this.respond(error, response, ctx);
|
|
1590
1658
|
});
|
|
1591
1659
|
return result;
|
|
1592
|
-
} else
|
|
1660
|
+
} else if (onNoMatch) onNoMatch(req, res);
|
|
1661
|
+
else {
|
|
1593
1662
|
this.logger.debug(`404 Not found (${method})${url}`);
|
|
1594
1663
|
const error = new HttpError(404);
|
|
1595
1664
|
this.respond(error, response, ctx);
|
|
@@ -1697,7 +1766,124 @@ var WooksHttp = class extends WooksAdapterBase {
|
|
|
1697
1766
|
}
|
|
1698
1767
|
}
|
|
1699
1768
|
}
|
|
1769
|
+
/**
|
|
1770
|
+
* Programmatic route invocation using the Web Standard fetch API.
|
|
1771
|
+
* Goes through the full dispatch pipeline: context creation, route matching,
|
|
1772
|
+
* handler execution, response finalization.
|
|
1773
|
+
*
|
|
1774
|
+
* When called from within an existing HTTP context (e.g. during SSR),
|
|
1775
|
+
* identity headers (authorization, cookie) are automatically forwarded
|
|
1776
|
+
* from the calling request unless already present on the given Request.
|
|
1777
|
+
*
|
|
1778
|
+
* @param request - A Web Standard Request object.
|
|
1779
|
+
* @returns A Web Standard Response, or `null` if no route matched (and no `onNotFound` handler is set).
|
|
1780
|
+
*/
|
|
1781
|
+
async fetch(request) {
|
|
1782
|
+
const url = new URL(request.url);
|
|
1783
|
+
const method = request.method;
|
|
1784
|
+
const pathname = url.pathname + url.search;
|
|
1785
|
+
const callerCtx = tryGetCurrent();
|
|
1786
|
+
let callerReq;
|
|
1787
|
+
if (callerCtx) try {
|
|
1788
|
+
callerReq = callerCtx.get(httpKind.keys.req);
|
|
1789
|
+
} catch {}
|
|
1790
|
+
const fakeReq = createFakeIncomingMessage(request, pathname, callerReq, this.opts?.forwardHeaders);
|
|
1791
|
+
const fakeRes = new ServerResponse(fakeReq);
|
|
1792
|
+
const rawChunks = [];
|
|
1793
|
+
const rawHeaders = {};
|
|
1794
|
+
let rawStatusCode = 0;
|
|
1795
|
+
fakeRes.writeHead = (...args) => {
|
|
1796
|
+
rawStatusCode = args[0];
|
|
1797
|
+
for (const arg of args) if (typeof arg === "object" && arg !== null) for (const [k, v] of Object.entries(arg)) rawHeaders[k] = v;
|
|
1798
|
+
return fakeRes;
|
|
1799
|
+
};
|
|
1800
|
+
fakeRes.write = (chunk, ...args) => {
|
|
1801
|
+
if (chunk !== null && chunk !== void 0) rawChunks.push(typeof chunk === "string" ? Buffer$1.from(chunk) : chunk);
|
|
1802
|
+
const cb = args.find((a) => typeof a === "function");
|
|
1803
|
+
if (cb) cb();
|
|
1804
|
+
return true;
|
|
1805
|
+
};
|
|
1806
|
+
fakeRes.end = (chunk, ...args) => {
|
|
1807
|
+
if (chunk !== null && chunk !== void 0 && typeof chunk !== "function") rawChunks.push(typeof chunk === "string" ? Buffer$1.from(chunk) : chunk);
|
|
1808
|
+
const cb = args.find((a) => typeof a === "function");
|
|
1809
|
+
if (cb) cb();
|
|
1810
|
+
return fakeRes;
|
|
1811
|
+
};
|
|
1812
|
+
const response = new this.ResponseClass(fakeRes, fakeReq, this.logger, this.opts?.defaultHeaders, true);
|
|
1813
|
+
let bodyBuffer;
|
|
1814
|
+
if (request.body) bodyBuffer = Buffer$1.from(await request.bytes());
|
|
1815
|
+
const ctxOptions = this.eventContextOptions;
|
|
1816
|
+
const requestLimits = this.opts?.requestLimits;
|
|
1817
|
+
const notFoundHandler = this.opts?.onNotFound;
|
|
1818
|
+
return createHttpContext(ctxOptions, {
|
|
1819
|
+
req: fakeReq,
|
|
1820
|
+
response,
|
|
1821
|
+
requestLimits
|
|
1822
|
+
}, async () => {
|
|
1823
|
+
const ctx = current();
|
|
1824
|
+
if (bodyBuffer) ctx.set(rawBodySlot, Promise.resolve(bodyBuffer));
|
|
1825
|
+
try {
|
|
1826
|
+
const handlers = this.wooks.lookupHandlers(method, pathname, ctx);
|
|
1827
|
+
if (handlers || notFoundHandler) {
|
|
1828
|
+
const result = this.processHandlers(handlers || [notFoundHandler], ctx, response);
|
|
1829
|
+
if (result !== null && result !== void 0 && typeof result.then === "function") await result.catch((error) => {
|
|
1830
|
+
if (!response.responded) this.respond(error, response, ctx);
|
|
1831
|
+
});
|
|
1832
|
+
} else return null;
|
|
1833
|
+
} finally {
|
|
1834
|
+
fakeReq.emit("end");
|
|
1835
|
+
fakeReq.emit("close");
|
|
1836
|
+
fakeReq.destroy();
|
|
1837
|
+
fakeRes.destroy();
|
|
1838
|
+
}
|
|
1839
|
+
let webResponse;
|
|
1840
|
+
if (rawChunks.length > 0 || rawStatusCode > 0) {
|
|
1841
|
+
const body = Buffer$1.concat(rawChunks);
|
|
1842
|
+
webResponse = new Response(body.length > 0 ? body : null, {
|
|
1843
|
+
status: rawStatusCode || 200,
|
|
1844
|
+
headers: recordToWebHeaders(rawHeaders)
|
|
1845
|
+
});
|
|
1846
|
+
} else webResponse = response.toWebResponse();
|
|
1847
|
+
if (callerReq) try {
|
|
1848
|
+
const parentResponse = callerCtx?.get(httpKind.keys.response);
|
|
1849
|
+
if (parentResponse) for (const cookie of webResponse.headers.getSetCookie()) parentResponse.setCookieRaw(cookie);
|
|
1850
|
+
} catch {}
|
|
1851
|
+
return webResponse;
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1854
|
+
/**
|
|
1855
|
+
* Convenience wrapper for programmatic route invocation.
|
|
1856
|
+
* Accepts a URL string (relative paths auto-prefixed with `http://localhost`),
|
|
1857
|
+
* URL object, or Request, plus optional `RequestInit`.
|
|
1858
|
+
*
|
|
1859
|
+
* @param input - URL string, URL object, or Request.
|
|
1860
|
+
* @param init - Optional RequestInit (method, headers, body, etc.).
|
|
1861
|
+
* @returns A Web Standard Response.
|
|
1862
|
+
*/
|
|
1863
|
+
request(input, init) {
|
|
1864
|
+
if (typeof input === "string" && !input.startsWith("http://") && !input.startsWith("https://")) input = `http://localhost${input.startsWith("/") ? "" : "/"}${input}`;
|
|
1865
|
+
const req = input instanceof Request ? input : new Request(input, init);
|
|
1866
|
+
return this.fetch(req);
|
|
1867
|
+
}
|
|
1700
1868
|
};
|
|
1869
|
+
function createFakeIncomingMessage(request, pathname, forwardFrom, forwardHeaders) {
|
|
1870
|
+
const req = new IncomingMessage(new Socket({}));
|
|
1871
|
+
req.method = request.method;
|
|
1872
|
+
req.url = pathname;
|
|
1873
|
+
const headers = {};
|
|
1874
|
+
if (forwardFrom && forwardHeaders !== false) {
|
|
1875
|
+
const headerList = Array.isArray(forwardHeaders) ? forwardHeaders : DEFAULT_FORWARD_HEADERS;
|
|
1876
|
+
for (const h of headerList) {
|
|
1877
|
+
const val = forwardFrom.headers[h];
|
|
1878
|
+
if (typeof val === "string" && val) headers[h] = val;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
request.headers.forEach((value, key) => {
|
|
1882
|
+
headers[key] = value;
|
|
1883
|
+
});
|
|
1884
|
+
req.headers = headers;
|
|
1885
|
+
return req;
|
|
1886
|
+
}
|
|
1701
1887
|
/**
|
|
1702
1888
|
* Creates a new WooksHttp application instance.
|
|
1703
1889
|
* @example
|
|
@@ -1808,4 +1994,4 @@ function prepareTestHttpContext(options) {
|
|
|
1808
1994
|
}
|
|
1809
1995
|
|
|
1810
1996
|
//#endregion
|
|
1811
|
-
export { DEFAULT_LIMITS, EHttpStatusCode, HttpError, HttpResponse, WooksHttp, WooksHttpResponse, WooksURLSearchParams, createHttpApp, createHttpContext, httpKind, httpStatusCodes, prepareTestHttpContext, rawBodySlot, renderCacheControl, securityHeaders, useAccept, useAuthorization, useCookies, useHeaders, useHttpContext, useLogger, useRequest, useResponse, useRouteParams, useUrlParams };
|
|
1997
|
+
export { DEFAULT_LIMITS, EHttpStatusCode, HttpError, HttpResponse, WooksHttp, WooksHttpResponse, WooksURLSearchParams, createHttpApp, createHttpContext, httpKind, httpStatusCodes, prepareTestHttpContext, rawBodySlot, recordToWebHeaders, renderCacheControl, securityHeaders, useAccept, useAuthorization, useCookies, useHeaders, useHttpContext, useLogger, useRequest, useResponse, useRouteParams, useUrlParams };
|