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/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { subtle } from 'uncrypto';
|
|
|
4
4
|
import { compile, all } from 'proxy-addr';
|
|
5
5
|
import { getType, get } from 'mime-explorer';
|
|
6
6
|
import Negotiator from 'negotiator';
|
|
7
|
-
import { Readable, Writable } from 'readable-stream';
|
|
7
|
+
import { Readable, PassThrough, Writable } from 'readable-stream';
|
|
8
8
|
import { HTTPError } from '@ebec/http';
|
|
9
9
|
import { pathToRegexp } from 'path-to-regexp';
|
|
10
10
|
|
|
@@ -32,6 +32,7 @@ var HeaderName;
|
|
|
32
32
|
HeaderName["CONTENT_LENGTH"] = "content-length";
|
|
33
33
|
HeaderName["CONTENT_RANGE"] = "content-range";
|
|
34
34
|
HeaderName["CONTENT_TYPE"] = "content-type";
|
|
35
|
+
HeaderName["CONNECTION"] = "connection";
|
|
35
36
|
HeaderName["COOKIE"] = "cookie";
|
|
36
37
|
HeaderName["ETag"] = "etag";
|
|
37
38
|
HeaderName["HOST"] = "host";
|
|
@@ -46,6 +47,7 @@ var HeaderName;
|
|
|
46
47
|
HeaderName["RETRY_AFTER"] = "retry-after";
|
|
47
48
|
HeaderName["SET_COOKIE"] = "set-cookie";
|
|
48
49
|
HeaderName["TRANSFER_ENCODING"] = "transfer-encoding";
|
|
50
|
+
HeaderName["X_ACCEL_BUFFERING"] = "x-accel-buffering";
|
|
49
51
|
HeaderName["X_FORWARDED_HOST"] = "x-forwarded-host";
|
|
50
52
|
HeaderName["X_FORWARDED_FOR"] = "x-forwarded-for";
|
|
51
53
|
HeaderName["X_FORWARDED_PROTO"] = "x-forwarded-proto";
|
|
@@ -544,6 +546,10 @@ function getRequestHostName(req, options) {
|
|
|
544
546
|
return index !== -1 ? hostname.substring(0, index) : hostname;
|
|
545
547
|
}
|
|
546
548
|
|
|
549
|
+
function isRequestHTTP2(req) {
|
|
550
|
+
return typeof getRequestHeader(req, ':path') !== 'undefined' && typeof getRequestHeader(req, ':method') !== 'undefined';
|
|
551
|
+
}
|
|
552
|
+
|
|
547
553
|
function getRequestIP(req, options) {
|
|
548
554
|
options = options || {};
|
|
549
555
|
let trustProxy;
|
|
@@ -759,6 +765,96 @@ function isResponseGone(res) {
|
|
|
759
765
|
}
|
|
760
766
|
return false;
|
|
761
767
|
}
|
|
768
|
+
function setResponseGone(res, value) {
|
|
769
|
+
res[GoneSymbol] = value;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function serializeEventStreamMessage(message) {
|
|
773
|
+
let result = '';
|
|
774
|
+
if (message.id) {
|
|
775
|
+
result += `id: ${message.id}\n`;
|
|
776
|
+
}
|
|
777
|
+
if (message.event) {
|
|
778
|
+
result += `event: ${message.event}\n`;
|
|
779
|
+
}
|
|
780
|
+
if (typeof message.retry === 'number' && Number.isInteger(message.retry)) {
|
|
781
|
+
result += `retry: ${message.retry}\n`;
|
|
782
|
+
}
|
|
783
|
+
result += `data: ${message.data}\n\n`;
|
|
784
|
+
return result;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
class EventStream {
|
|
788
|
+
open() {
|
|
789
|
+
this.response.req.on('close', ()=>this.end());
|
|
790
|
+
this.response.req.on('error', (err)=>{
|
|
791
|
+
this.emit('error', err);
|
|
792
|
+
this.end();
|
|
793
|
+
});
|
|
794
|
+
this.passThrough.on('data', (chunk)=>this.response.write(chunk));
|
|
795
|
+
this.passThrough.on('error', (err)=>{
|
|
796
|
+
this.emit('error', err);
|
|
797
|
+
this.end();
|
|
798
|
+
});
|
|
799
|
+
this.passThrough.on('close', ()=>this.end());
|
|
800
|
+
this.response.setHeader(HeaderName.CONTENT_TYPE, 'text/event-stream');
|
|
801
|
+
this.response.setHeader(HeaderName.CACHE_CONTROL, 'private, no-cache, no-store, no-transform, must-revalidate, max-age=0');
|
|
802
|
+
this.response.setHeader(HeaderName.X_ACCEL_BUFFERING, 'no');
|
|
803
|
+
if (!isRequestHTTP2(this.response.req)) {
|
|
804
|
+
this.response.setHeader(HeaderName.CONNECTION, 'keep-alive');
|
|
805
|
+
}
|
|
806
|
+
this.response.statusCode = 200;
|
|
807
|
+
}
|
|
808
|
+
write(message) {
|
|
809
|
+
if (typeof message === 'string') {
|
|
810
|
+
this.write({
|
|
811
|
+
data: message
|
|
812
|
+
});
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
if (!this.passThrough.closed && this.passThrough.writable) {
|
|
816
|
+
this.passThrough.write(serializeEventStreamMessage(message));
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
end() {
|
|
820
|
+
if (this.flushed) return;
|
|
821
|
+
this.flushed = true;
|
|
822
|
+
if (!this.passThrough.closed) {
|
|
823
|
+
this.passThrough.end();
|
|
824
|
+
}
|
|
825
|
+
this.emit('close');
|
|
826
|
+
setResponseGone(this.response, true);
|
|
827
|
+
this.response.end();
|
|
828
|
+
}
|
|
829
|
+
on(event, listener) {
|
|
830
|
+
if (typeof this.eventHandlers[event] === 'undefined') {
|
|
831
|
+
this.eventHandlers[event] = [];
|
|
832
|
+
}
|
|
833
|
+
this.eventHandlers[event].push(listener);
|
|
834
|
+
}
|
|
835
|
+
emit(event, ...args) {
|
|
836
|
+
if (typeof this.eventHandlers[event] === 'undefined') {
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
const listeners = this.eventHandlers[event].slice();
|
|
840
|
+
for(let i = 0; i < listeners.length; i++){
|
|
841
|
+
listeners[i].apply(this, args);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
constructor(response){
|
|
845
|
+
this.response = response;
|
|
846
|
+
this.passThrough = new PassThrough({
|
|
847
|
+
encoding: 'utf-8'
|
|
848
|
+
});
|
|
849
|
+
this.flushed = false;
|
|
850
|
+
this.eventHandlers = {};
|
|
851
|
+
this.open();
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
function createEventStream(response) {
|
|
856
|
+
return new EventStream(response);
|
|
857
|
+
}
|
|
762
858
|
|
|
763
859
|
function appendResponseHeader(res, name, value) {
|
|
764
860
|
let header = res.getHeader(name);
|
|
@@ -842,6 +938,78 @@ function setResponseHeaderContentType(res, input, ifNotExists) {
|
|
|
842
938
|
}
|
|
843
939
|
}
|
|
844
940
|
|
|
941
|
+
async function sendStream(res, stream, next) {
|
|
942
|
+
if (isWebStream(stream)) {
|
|
943
|
+
return stream.pipeTo(new WritableStream({
|
|
944
|
+
write (chunk) {
|
|
945
|
+
res.write(chunk);
|
|
946
|
+
}
|
|
947
|
+
})).then(()=>{
|
|
948
|
+
if (next) {
|
|
949
|
+
return next();
|
|
950
|
+
}
|
|
951
|
+
res.end();
|
|
952
|
+
return Promise.resolve();
|
|
953
|
+
}).catch((err)=>{
|
|
954
|
+
if (next) {
|
|
955
|
+
return next(err);
|
|
956
|
+
}
|
|
957
|
+
return Promise.reject(err);
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
return new Promise((resolve, reject)=>{
|
|
961
|
+
stream.on('open', ()=>{
|
|
962
|
+
stream.pipe(res);
|
|
963
|
+
});
|
|
964
|
+
/* istanbul ignore next */ stream.on('error', (err)=>{
|
|
965
|
+
if (next) {
|
|
966
|
+
Promise.resolve().then(()=>next(err)).then(()=>resolve()).catch((e)=>reject(e));
|
|
967
|
+
return;
|
|
968
|
+
}
|
|
969
|
+
res.end();
|
|
970
|
+
reject(err);
|
|
971
|
+
});
|
|
972
|
+
stream.on('close', ()=>{
|
|
973
|
+
if (next) {
|
|
974
|
+
Promise.resolve().then(()=>next()).then(()=>resolve()).catch((e)=>reject(e));
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
res.end();
|
|
978
|
+
resolve();
|
|
979
|
+
});
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
async function sendWebBlob(res, blob) {
|
|
984
|
+
setResponseHeaderContentType(res, blob.type);
|
|
985
|
+
await sendStream(res, blob.stream());
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
async function sendWebResponse(res, webResponse) {
|
|
989
|
+
if (webResponse.redirected) {
|
|
990
|
+
res.setHeader(HeaderName.LOCATION, webResponse.url);
|
|
991
|
+
}
|
|
992
|
+
if (webResponse.status) {
|
|
993
|
+
res.statusCode = webResponse.status;
|
|
994
|
+
}
|
|
995
|
+
if (webResponse.statusText) {
|
|
996
|
+
res.statusMessage = webResponse.statusText;
|
|
997
|
+
}
|
|
998
|
+
webResponse.headers.forEach((value, key)=>{
|
|
999
|
+
if (key === HeaderName.SET_COOKIE) {
|
|
1000
|
+
res.appendHeader(key, splitCookiesString(value));
|
|
1001
|
+
} else {
|
|
1002
|
+
res.setHeader(key, value);
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
if (webResponse.body) {
|
|
1006
|
+
await sendStream(res, webResponse.body);
|
|
1007
|
+
return Promise.resolve();
|
|
1008
|
+
}
|
|
1009
|
+
res.end();
|
|
1010
|
+
return Promise.resolve();
|
|
1011
|
+
}
|
|
1012
|
+
|
|
845
1013
|
async function send(res, chunk) {
|
|
846
1014
|
switch(typeof chunk){
|
|
847
1015
|
case 'string':
|
|
@@ -853,11 +1021,28 @@ async function send(res, chunk) {
|
|
|
853
1021
|
case 'number':
|
|
854
1022
|
case 'object':
|
|
855
1023
|
{
|
|
856
|
-
if (
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
1024
|
+
if (chunk !== null) {
|
|
1025
|
+
if (chunk instanceof Error) {
|
|
1026
|
+
throw chunk;
|
|
1027
|
+
}
|
|
1028
|
+
if (isStream(chunk)) {
|
|
1029
|
+
await sendStream(res, chunk);
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1032
|
+
if (isWebBlob(chunk)) {
|
|
1033
|
+
await sendWebBlob(res, chunk);
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
if (isWebResponse(chunk)) {
|
|
1037
|
+
await sendWebResponse(res, chunk);
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
if (Buffer.isBuffer(chunk)) {
|
|
1041
|
+
setResponseHeaderContentType(res, 'bin', true);
|
|
1042
|
+
} else {
|
|
1043
|
+
chunk = JSON.stringify(chunk);
|
|
1044
|
+
setResponseHeaderContentType(res, 'application/json', true);
|
|
1045
|
+
}
|
|
861
1046
|
}
|
|
862
1047
|
break;
|
|
863
1048
|
}
|
|
@@ -940,48 +1125,6 @@ function sendCreated(res, chunk) {
|
|
|
940
1125
|
return send(res, chunk);
|
|
941
1126
|
}
|
|
942
1127
|
|
|
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
1128
|
async function sendFile(res, options, next) {
|
|
986
1129
|
let stats;
|
|
987
1130
|
try {
|
|
@@ -1071,36 +1214,6 @@ function sendRedirect(res, location, statusCode = 302) {
|
|
|
1071
1214
|
return send(res, html);
|
|
1072
1215
|
}
|
|
1073
1216
|
|
|
1074
|
-
async function sendWebResponse(res, webResponse) {
|
|
1075
|
-
if (webResponse.redirected) {
|
|
1076
|
-
res.setHeader(HeaderName.LOCATION, webResponse.url);
|
|
1077
|
-
}
|
|
1078
|
-
if (webResponse.status) {
|
|
1079
|
-
res.statusCode = webResponse.status;
|
|
1080
|
-
}
|
|
1081
|
-
if (webResponse.statusText) {
|
|
1082
|
-
res.statusMessage = webResponse.statusText;
|
|
1083
|
-
}
|
|
1084
|
-
webResponse.headers.forEach((value, key)=>{
|
|
1085
|
-
if (key === HeaderName.SET_COOKIE) {
|
|
1086
|
-
res.appendHeader(key, splitCookiesString(value));
|
|
1087
|
-
} else {
|
|
1088
|
-
res.setHeader(key, value);
|
|
1089
|
-
}
|
|
1090
|
-
});
|
|
1091
|
-
if (webResponse.body) {
|
|
1092
|
-
await sendStream(res, webResponse.body);
|
|
1093
|
-
return Promise.resolve();
|
|
1094
|
-
}
|
|
1095
|
-
res.end();
|
|
1096
|
-
return Promise.resolve();
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
async function sendWebBlob(res, blob) {
|
|
1100
|
-
setResponseHeaderContentType(res, blob.type);
|
|
1101
|
-
await sendStream(res, blob.stream());
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
1217
|
function createResponse(request) {
|
|
1105
1218
|
let output;
|
|
1106
1219
|
let encoding;
|
|
@@ -1246,24 +1359,6 @@ function createResponse(request) {
|
|
|
1246
1359
|
return writable;
|
|
1247
1360
|
}
|
|
1248
1361
|
|
|
1249
|
-
async function sendData(event, chunk) {
|
|
1250
|
-
if (chunk instanceof Error) {
|
|
1251
|
-
return Promise.reject(createError(chunk));
|
|
1252
|
-
}
|
|
1253
|
-
if (isStream(chunk)) {
|
|
1254
|
-
await sendStream(event.response, chunk);
|
|
1255
|
-
return Promise.resolve();
|
|
1256
|
-
}
|
|
1257
|
-
if (isWebBlob(chunk)) {
|
|
1258
|
-
await sendWebBlob(event.response, chunk);
|
|
1259
|
-
return Promise.resolve();
|
|
1260
|
-
}
|
|
1261
|
-
if (isWebResponse(chunk)) {
|
|
1262
|
-
await sendWebResponse(event.response, chunk);
|
|
1263
|
-
return Promise.resolve();
|
|
1264
|
-
}
|
|
1265
|
-
return send(event.response, chunk);
|
|
1266
|
-
}
|
|
1267
1362
|
function dispatch(event, target) {
|
|
1268
1363
|
setRequestParams(event.request, event.params);
|
|
1269
1364
|
setRequestMountPath(event.request, event.mountPath);
|
|
@@ -1297,7 +1392,7 @@ function dispatch(event, target) {
|
|
|
1297
1392
|
handled = true;
|
|
1298
1393
|
unsubscribe();
|
|
1299
1394
|
if (!event.dispatched) {
|
|
1300
|
-
await
|
|
1395
|
+
await send(event.response, data);
|
|
1301
1396
|
}
|
|
1302
1397
|
return true;
|
|
1303
1398
|
};
|
|
@@ -2138,5 +2233,5 @@ class Router {
|
|
|
2138
2233
|
}
|
|
2139
2234
|
}
|
|
2140
2235
|
|
|
2141
|
-
export { DispatchErrorEvent, DispatchEvent, Handler, HandlerSymbol, HandlerType, HeaderName, MethodName, PathMatcher, Router, RoutupError, appendResponseHeader, appendResponseHeaderDirective, coreHandler, createError, createNodeDispatcher, createRawDispatcher, createRequest, createResponse, createWebDispatcher, dispatch, dispatchNodeRequest, dispatchRawRequest, dispatchWebRequest, errorHandler, getRequestAcceptableCharset, getRequestAcceptableCharsets, getRequestAcceptableContentType, getRequestAcceptableContentTypes, getRequestAcceptableEncoding, getRequestAcceptableEncodings, getRequestAcceptableLanguage, getRequestAcceptableLanguages, getRequestHeader, getRequestHostName, getRequestIP, getRequestProtocol, isDispatcherErrorEvent, isError, isHandler, isHandlerConfig, isPath, isPlugin, isRequestCacheable, isResponseGone, matchRequestContentType, send, sendAccepted, sendCreated, sendFile, sendFormat, sendRedirect, sendStream, sendWebBlob, sendWebResponse, setRequestEnv, setRequestHeader, setRequestMountPath, setRequestParam, setRequestParams, setRequestRouterPath, setResponseCacheHeaders, setResponseContentTypeByFileName, setResponseHeaderAttachment, setResponseHeaderContentType, transformHeaderToTuples, transformHeadersToTuples, unsetRequestEnv, useRequestEnv, useRequestMountPath, useRequestNegotiator, useRequestParam, useRequestParams, useRequestPath, useRequestRouterPath };
|
|
2236
|
+
export { DispatchErrorEvent, DispatchEvent, EventStream, Handler, HandlerSymbol, HandlerType, HeaderName, MethodName, PathMatcher, Router, RoutupError, appendResponseHeader, appendResponseHeaderDirective, coreHandler, createError, createEventStream, createNodeDispatcher, createRawDispatcher, createRequest, createResponse, createWebDispatcher, dispatch, dispatchNodeRequest, dispatchRawRequest, dispatchWebRequest, errorHandler, getRequestAcceptableCharset, getRequestAcceptableCharsets, getRequestAcceptableContentType, getRequestAcceptableContentTypes, getRequestAcceptableEncoding, getRequestAcceptableEncodings, getRequestAcceptableLanguage, getRequestAcceptableLanguages, getRequestHeader, getRequestHostName, getRequestIP, getRequestProtocol, isDispatcherErrorEvent, isError, isHandler, isHandlerConfig, isPath, isPlugin, isRequestCacheable, isRequestHTTP2, isResponseGone, matchRequestContentType, send, sendAccepted, sendCreated, sendFile, sendFormat, sendRedirect, sendStream, sendWebBlob, sendWebResponse, setRequestEnv, setRequestHeader, setRequestMountPath, setRequestParam, setRequestParams, setRequestRouterPath, setResponseCacheHeaders, setResponseContentTypeByFileName, setResponseGone, setResponseHeaderAttachment, setResponseHeaderContentType, transformHeaderToTuples, transformHeadersToTuples, unsetRequestEnv, useRequestEnv, useRequestMountPath, useRequestNegotiator, useRequestParam, useRequestParams, useRequestPath, useRequestRouterPath };
|
|
2142
2237
|
//# sourceMappingURL=index.mjs.map
|