routup 3.1.0 → 3.3.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/dist/constants.d.ts +2 -0
- package/dist/index.cjs +195 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +193 -98
- package/dist/index.mjs.map +1 -1
- package/dist/request/helpers/http2.d.ts +2 -0
- package/dist/request/helpers/index.d.ts +1 -0
- package/dist/response/helpers/event-stream/factory.d.ts +3 -0
- package/dist/response/helpers/event-stream/index.d.ts +2 -0
- package/dist/response/helpers/event-stream/module.d.ts +17 -0
- package/dist/response/helpers/event-stream/types.d.ts +24 -0
- package/dist/response/helpers/event-stream/utils.d.ts +2 -0
- package/dist/response/helpers/gone.d.ts +1 -0
- package/dist/response/helpers/index.d.ts +1 -0
- package/package.json +20 -20
package/dist/constants.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export declare enum HeaderName {
|
|
|
20
20
|
CONTENT_LENGTH = "content-length",
|
|
21
21
|
CONTENT_RANGE = "content-range",
|
|
22
22
|
CONTENT_TYPE = "content-type",
|
|
23
|
+
CONNECTION = "connection",
|
|
23
24
|
COOKIE = "cookie",
|
|
24
25
|
ETag = "etag",
|
|
25
26
|
HOST = "host",
|
|
@@ -34,6 +35,7 @@ export declare enum HeaderName {
|
|
|
34
35
|
RETRY_AFTER = "retry-after",
|
|
35
36
|
SET_COOKIE = "set-cookie",
|
|
36
37
|
TRANSFER_ENCODING = "transfer-encoding",
|
|
38
|
+
X_ACCEL_BUFFERING = "x-accel-buffering",
|
|
37
39
|
X_FORWARDED_HOST = "x-forwarded-host",
|
|
38
40
|
X_FORWARDED_FOR = "x-forwarded-for",
|
|
39
41
|
X_FORWARDED_PROTO = "x-forwarded-proto"
|
package/dist/index.cjs
CHANGED
|
@@ -34,6 +34,7 @@ exports.HeaderName = void 0;
|
|
|
34
34
|
HeaderName["CONTENT_LENGTH"] = "content-length";
|
|
35
35
|
HeaderName["CONTENT_RANGE"] = "content-range";
|
|
36
36
|
HeaderName["CONTENT_TYPE"] = "content-type";
|
|
37
|
+
HeaderName["CONNECTION"] = "connection";
|
|
37
38
|
HeaderName["COOKIE"] = "cookie";
|
|
38
39
|
HeaderName["ETag"] = "etag";
|
|
39
40
|
HeaderName["HOST"] = "host";
|
|
@@ -48,6 +49,7 @@ exports.HeaderName = void 0;
|
|
|
48
49
|
HeaderName["RETRY_AFTER"] = "retry-after";
|
|
49
50
|
HeaderName["SET_COOKIE"] = "set-cookie";
|
|
50
51
|
HeaderName["TRANSFER_ENCODING"] = "transfer-encoding";
|
|
52
|
+
HeaderName["X_ACCEL_BUFFERING"] = "x-accel-buffering";
|
|
51
53
|
HeaderName["X_FORWARDED_HOST"] = "x-forwarded-host";
|
|
52
54
|
HeaderName["X_FORWARDED_FOR"] = "x-forwarded-for";
|
|
53
55
|
HeaderName["X_FORWARDED_PROTO"] = "x-forwarded-proto";
|
|
@@ -546,6 +548,10 @@ function getRequestHostName(req, options) {
|
|
|
546
548
|
return index !== -1 ? hostname.substring(0, index) : hostname;
|
|
547
549
|
}
|
|
548
550
|
|
|
551
|
+
function isRequestHTTP2(req) {
|
|
552
|
+
return typeof getRequestHeader(req, ':path') !== 'undefined' && typeof getRequestHeader(req, ':method') !== 'undefined';
|
|
553
|
+
}
|
|
554
|
+
|
|
549
555
|
function getRequestIP(req, options) {
|
|
550
556
|
options = options || {};
|
|
551
557
|
let trustProxy;
|
|
@@ -761,6 +767,96 @@ function isResponseGone(res) {
|
|
|
761
767
|
}
|
|
762
768
|
return false;
|
|
763
769
|
}
|
|
770
|
+
function setResponseGone(res, value) {
|
|
771
|
+
res[GoneSymbol] = value;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
function serializeEventStreamMessage(message) {
|
|
775
|
+
let result = '';
|
|
776
|
+
if (message.id) {
|
|
777
|
+
result += `id: ${message.id}\n`;
|
|
778
|
+
}
|
|
779
|
+
if (message.event) {
|
|
780
|
+
result += `event: ${message.event}\n`;
|
|
781
|
+
}
|
|
782
|
+
if (typeof message.retry === 'number' && Number.isInteger(message.retry)) {
|
|
783
|
+
result += `retry: ${message.retry}\n`;
|
|
784
|
+
}
|
|
785
|
+
result += `data: ${message.data}\n\n`;
|
|
786
|
+
return result;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
class EventStream {
|
|
790
|
+
open() {
|
|
791
|
+
this.response.req.on('close', ()=>this.end());
|
|
792
|
+
this.response.req.on('error', (err)=>{
|
|
793
|
+
this.emit('error', err);
|
|
794
|
+
this.end();
|
|
795
|
+
});
|
|
796
|
+
this.passThrough.on('data', (chunk)=>this.response.write(chunk));
|
|
797
|
+
this.passThrough.on('error', (err)=>{
|
|
798
|
+
this.emit('error', err);
|
|
799
|
+
this.end();
|
|
800
|
+
});
|
|
801
|
+
this.passThrough.on('close', ()=>this.end());
|
|
802
|
+
this.response.setHeader(exports.HeaderName.CONTENT_TYPE, 'text/event-stream');
|
|
803
|
+
this.response.setHeader(exports.HeaderName.CACHE_CONTROL, 'private, no-cache, no-store, no-transform, must-revalidate, max-age=0');
|
|
804
|
+
this.response.setHeader(exports.HeaderName.X_ACCEL_BUFFERING, 'no');
|
|
805
|
+
if (!isRequestHTTP2(this.response.req)) {
|
|
806
|
+
this.response.setHeader(exports.HeaderName.CONNECTION, 'keep-alive');
|
|
807
|
+
}
|
|
808
|
+
this.response.statusCode = 200;
|
|
809
|
+
}
|
|
810
|
+
write(message) {
|
|
811
|
+
if (typeof message === 'string') {
|
|
812
|
+
this.write({
|
|
813
|
+
data: message
|
|
814
|
+
});
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
if (!this.passThrough.closed && this.passThrough.writable) {
|
|
818
|
+
this.passThrough.write(serializeEventStreamMessage(message));
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
end() {
|
|
822
|
+
if (this.flushed) return;
|
|
823
|
+
this.flushed = true;
|
|
824
|
+
if (!this.passThrough.closed) {
|
|
825
|
+
this.passThrough.end();
|
|
826
|
+
}
|
|
827
|
+
this.emit('close');
|
|
828
|
+
setResponseGone(this.response, true);
|
|
829
|
+
this.response.end();
|
|
830
|
+
}
|
|
831
|
+
on(event, listener) {
|
|
832
|
+
if (typeof this.eventHandlers[event] === 'undefined') {
|
|
833
|
+
this.eventHandlers[event] = [];
|
|
834
|
+
}
|
|
835
|
+
this.eventHandlers[event].push(listener);
|
|
836
|
+
}
|
|
837
|
+
emit(event, ...args) {
|
|
838
|
+
if (typeof this.eventHandlers[event] === 'undefined') {
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
const listeners = this.eventHandlers[event].slice();
|
|
842
|
+
for(let i = 0; i < listeners.length; i++){
|
|
843
|
+
listeners[i].apply(this, args);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
constructor(response){
|
|
847
|
+
this.response = response;
|
|
848
|
+
this.passThrough = new readableStream.PassThrough({
|
|
849
|
+
encoding: 'utf-8'
|
|
850
|
+
});
|
|
851
|
+
this.flushed = false;
|
|
852
|
+
this.eventHandlers = {};
|
|
853
|
+
this.open();
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
function createEventStream(response) {
|
|
858
|
+
return new EventStream(response);
|
|
859
|
+
}
|
|
764
860
|
|
|
765
861
|
function appendResponseHeader(res, name, value) {
|
|
766
862
|
let header = res.getHeader(name);
|
|
@@ -844,6 +940,78 @@ function setResponseHeaderContentType(res, input, ifNotExists) {
|
|
|
844
940
|
}
|
|
845
941
|
}
|
|
846
942
|
|
|
943
|
+
async function sendStream(res, stream, next) {
|
|
944
|
+
if (isWebStream(stream)) {
|
|
945
|
+
return stream.pipeTo(new WritableStream({
|
|
946
|
+
write (chunk) {
|
|
947
|
+
res.write(chunk);
|
|
948
|
+
}
|
|
949
|
+
})).then(()=>{
|
|
950
|
+
if (next) {
|
|
951
|
+
return next();
|
|
952
|
+
}
|
|
953
|
+
res.end();
|
|
954
|
+
return Promise.resolve();
|
|
955
|
+
}).catch((err)=>{
|
|
956
|
+
if (next) {
|
|
957
|
+
return next(err);
|
|
958
|
+
}
|
|
959
|
+
return Promise.reject(err);
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
return new Promise((resolve, reject)=>{
|
|
963
|
+
stream.on('open', ()=>{
|
|
964
|
+
stream.pipe(res);
|
|
965
|
+
});
|
|
966
|
+
/* istanbul ignore next */ stream.on('error', (err)=>{
|
|
967
|
+
if (next) {
|
|
968
|
+
Promise.resolve().then(()=>next(err)).then(()=>resolve()).catch((e)=>reject(e));
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
res.end();
|
|
972
|
+
reject(err);
|
|
973
|
+
});
|
|
974
|
+
stream.on('close', ()=>{
|
|
975
|
+
if (next) {
|
|
976
|
+
Promise.resolve().then(()=>next()).then(()=>resolve()).catch((e)=>reject(e));
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
res.end();
|
|
980
|
+
resolve();
|
|
981
|
+
});
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
async function sendWebBlob(res, blob) {
|
|
986
|
+
setResponseHeaderContentType(res, blob.type);
|
|
987
|
+
await sendStream(res, blob.stream());
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
async function sendWebResponse(res, webResponse) {
|
|
991
|
+
if (webResponse.redirected) {
|
|
992
|
+
res.setHeader(exports.HeaderName.LOCATION, webResponse.url);
|
|
993
|
+
}
|
|
994
|
+
if (webResponse.status) {
|
|
995
|
+
res.statusCode = webResponse.status;
|
|
996
|
+
}
|
|
997
|
+
if (webResponse.statusText) {
|
|
998
|
+
res.statusMessage = webResponse.statusText;
|
|
999
|
+
}
|
|
1000
|
+
webResponse.headers.forEach((value, key)=>{
|
|
1001
|
+
if (key === exports.HeaderName.SET_COOKIE) {
|
|
1002
|
+
res.appendHeader(key, splitCookiesString(value));
|
|
1003
|
+
} else {
|
|
1004
|
+
res.setHeader(key, value);
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
if (webResponse.body) {
|
|
1008
|
+
await sendStream(res, webResponse.body);
|
|
1009
|
+
return Promise.resolve();
|
|
1010
|
+
}
|
|
1011
|
+
res.end();
|
|
1012
|
+
return Promise.resolve();
|
|
1013
|
+
}
|
|
1014
|
+
|
|
847
1015
|
async function send(res, chunk) {
|
|
848
1016
|
switch(typeof chunk){
|
|
849
1017
|
case 'string':
|
|
@@ -855,11 +1023,28 @@ async function send(res, chunk) {
|
|
|
855
1023
|
case 'number':
|
|
856
1024
|
case 'object':
|
|
857
1025
|
{
|
|
858
|
-
if (
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1026
|
+
if (chunk !== null) {
|
|
1027
|
+
if (chunk instanceof Error) {
|
|
1028
|
+
throw chunk;
|
|
1029
|
+
}
|
|
1030
|
+
if (isStream(chunk)) {
|
|
1031
|
+
await sendStream(res, chunk);
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
if (isWebBlob(chunk)) {
|
|
1035
|
+
await sendWebBlob(res, chunk);
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
if (isWebResponse(chunk)) {
|
|
1039
|
+
await sendWebResponse(res, chunk);
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
if (buffer.Buffer.isBuffer(chunk)) {
|
|
1043
|
+
setResponseHeaderContentType(res, 'bin', true);
|
|
1044
|
+
} else {
|
|
1045
|
+
chunk = JSON.stringify(chunk);
|
|
1046
|
+
setResponseHeaderContentType(res, 'application/json', true);
|
|
1047
|
+
}
|
|
863
1048
|
}
|
|
864
1049
|
break;
|
|
865
1050
|
}
|
|
@@ -942,48 +1127,6 @@ function sendCreated(res, chunk) {
|
|
|
942
1127
|
return send(res, chunk);
|
|
943
1128
|
}
|
|
944
1129
|
|
|
945
|
-
async function sendStream(res, stream, next) {
|
|
946
|
-
if (isWebStream(stream)) {
|
|
947
|
-
return stream.pipeTo(new WritableStream({
|
|
948
|
-
write (chunk) {
|
|
949
|
-
res.write(chunk);
|
|
950
|
-
}
|
|
951
|
-
})).then(()=>{
|
|
952
|
-
if (next) {
|
|
953
|
-
return next();
|
|
954
|
-
}
|
|
955
|
-
res.end();
|
|
956
|
-
return Promise.resolve();
|
|
957
|
-
}).catch((err)=>{
|
|
958
|
-
if (next) {
|
|
959
|
-
return next(err);
|
|
960
|
-
}
|
|
961
|
-
return Promise.reject(err);
|
|
962
|
-
});
|
|
963
|
-
}
|
|
964
|
-
return new Promise((resolve, reject)=>{
|
|
965
|
-
stream.on('open', ()=>{
|
|
966
|
-
stream.pipe(res);
|
|
967
|
-
});
|
|
968
|
-
/* istanbul ignore next */ stream.on('error', (err)=>{
|
|
969
|
-
if (next) {
|
|
970
|
-
Promise.resolve().then(()=>next(err)).then(()=>resolve()).catch((e)=>reject(e));
|
|
971
|
-
return;
|
|
972
|
-
}
|
|
973
|
-
res.end();
|
|
974
|
-
reject(err);
|
|
975
|
-
});
|
|
976
|
-
stream.on('close', ()=>{
|
|
977
|
-
if (next) {
|
|
978
|
-
Promise.resolve().then(()=>next()).then(()=>resolve()).catch((e)=>reject(e));
|
|
979
|
-
return;
|
|
980
|
-
}
|
|
981
|
-
res.end();
|
|
982
|
-
resolve();
|
|
983
|
-
});
|
|
984
|
-
});
|
|
985
|
-
}
|
|
986
|
-
|
|
987
1130
|
async function sendFile(res, options, next) {
|
|
988
1131
|
let stats;
|
|
989
1132
|
try {
|
|
@@ -1073,36 +1216,6 @@ function sendRedirect(res, location, statusCode = 302) {
|
|
|
1073
1216
|
return send(res, html);
|
|
1074
1217
|
}
|
|
1075
1218
|
|
|
1076
|
-
async function sendWebResponse(res, webResponse) {
|
|
1077
|
-
if (webResponse.redirected) {
|
|
1078
|
-
res.setHeader(exports.HeaderName.LOCATION, webResponse.url);
|
|
1079
|
-
}
|
|
1080
|
-
if (webResponse.status) {
|
|
1081
|
-
res.statusCode = webResponse.status;
|
|
1082
|
-
}
|
|
1083
|
-
if (webResponse.statusText) {
|
|
1084
|
-
res.statusMessage = webResponse.statusText;
|
|
1085
|
-
}
|
|
1086
|
-
webResponse.headers.forEach((value, key)=>{
|
|
1087
|
-
if (key === exports.HeaderName.SET_COOKIE) {
|
|
1088
|
-
res.appendHeader(key, splitCookiesString(value));
|
|
1089
|
-
} else {
|
|
1090
|
-
res.setHeader(key, value);
|
|
1091
|
-
}
|
|
1092
|
-
});
|
|
1093
|
-
if (webResponse.body) {
|
|
1094
|
-
await sendStream(res, webResponse.body);
|
|
1095
|
-
return Promise.resolve();
|
|
1096
|
-
}
|
|
1097
|
-
res.end();
|
|
1098
|
-
return Promise.resolve();
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
async function sendWebBlob(res, blob) {
|
|
1102
|
-
setResponseHeaderContentType(res, blob.type);
|
|
1103
|
-
await sendStream(res, blob.stream());
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
1219
|
function createResponse(request) {
|
|
1107
1220
|
let output;
|
|
1108
1221
|
let encoding;
|
|
@@ -1248,24 +1361,6 @@ function createResponse(request) {
|
|
|
1248
1361
|
return writable;
|
|
1249
1362
|
}
|
|
1250
1363
|
|
|
1251
|
-
async function sendData(event, chunk) {
|
|
1252
|
-
if (chunk instanceof Error) {
|
|
1253
|
-
return Promise.reject(createError(chunk));
|
|
1254
|
-
}
|
|
1255
|
-
if (isStream(chunk)) {
|
|
1256
|
-
await sendStream(event.response, chunk);
|
|
1257
|
-
return Promise.resolve();
|
|
1258
|
-
}
|
|
1259
|
-
if (isWebBlob(chunk)) {
|
|
1260
|
-
await sendWebBlob(event.response, chunk);
|
|
1261
|
-
return Promise.resolve();
|
|
1262
|
-
}
|
|
1263
|
-
if (isWebResponse(chunk)) {
|
|
1264
|
-
await sendWebResponse(event.response, chunk);
|
|
1265
|
-
return Promise.resolve();
|
|
1266
|
-
}
|
|
1267
|
-
return send(event.response, chunk);
|
|
1268
|
-
}
|
|
1269
1364
|
function dispatch(event, target) {
|
|
1270
1365
|
setRequestParams(event.request, event.params);
|
|
1271
1366
|
setRequestMountPath(event.request, event.mountPath);
|
|
@@ -1299,7 +1394,7 @@ function dispatch(event, target) {
|
|
|
1299
1394
|
handled = true;
|
|
1300
1395
|
unsubscribe();
|
|
1301
1396
|
if (!event.dispatched) {
|
|
1302
|
-
await
|
|
1397
|
+
await send(event.response, data);
|
|
1303
1398
|
}
|
|
1304
1399
|
return true;
|
|
1305
1400
|
};
|
|
@@ -2142,6 +2237,7 @@ class Router {
|
|
|
2142
2237
|
|
|
2143
2238
|
exports.DispatchErrorEvent = DispatchErrorEvent;
|
|
2144
2239
|
exports.DispatchEvent = DispatchEvent;
|
|
2240
|
+
exports.EventStream = EventStream;
|
|
2145
2241
|
exports.Handler = Handler;
|
|
2146
2242
|
exports.HandlerSymbol = HandlerSymbol;
|
|
2147
2243
|
exports.PathMatcher = PathMatcher;
|
|
@@ -2151,6 +2247,7 @@ exports.appendResponseHeader = appendResponseHeader;
|
|
|
2151
2247
|
exports.appendResponseHeaderDirective = appendResponseHeaderDirective;
|
|
2152
2248
|
exports.coreHandler = coreHandler;
|
|
2153
2249
|
exports.createError = createError;
|
|
2250
|
+
exports.createEventStream = createEventStream;
|
|
2154
2251
|
exports.createNodeDispatcher = createNodeDispatcher;
|
|
2155
2252
|
exports.createRawDispatcher = createRawDispatcher;
|
|
2156
2253
|
exports.createRequest = createRequest;
|
|
@@ -2180,6 +2277,7 @@ exports.isHandlerConfig = isHandlerConfig;
|
|
|
2180
2277
|
exports.isPath = isPath;
|
|
2181
2278
|
exports.isPlugin = isPlugin;
|
|
2182
2279
|
exports.isRequestCacheable = isRequestCacheable;
|
|
2280
|
+
exports.isRequestHTTP2 = isRequestHTTP2;
|
|
2183
2281
|
exports.isResponseGone = isResponseGone;
|
|
2184
2282
|
exports.matchRequestContentType = matchRequestContentType;
|
|
2185
2283
|
exports.send = send;
|
|
@@ -2199,6 +2297,7 @@ exports.setRequestParams = setRequestParams;
|
|
|
2199
2297
|
exports.setRequestRouterPath = setRequestRouterPath;
|
|
2200
2298
|
exports.setResponseCacheHeaders = setResponseCacheHeaders;
|
|
2201
2299
|
exports.setResponseContentTypeByFileName = setResponseContentTypeByFileName;
|
|
2300
|
+
exports.setResponseGone = setResponseGone;
|
|
2202
2301
|
exports.setResponseHeaderAttachment = setResponseHeaderAttachment;
|
|
2203
2302
|
exports.setResponseHeaderContentType = setResponseHeaderContentType;
|
|
2204
2303
|
exports.transformHeaderToTuples = transformHeaderToTuples;
|