@duplojs/http 0.7.4 → 0.8.5
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/client/getBody.cjs +3 -3
- package/dist/client/getBody.mjs +3 -3
- package/dist/client/hooks.cjs +45 -0
- package/dist/client/hooks.d.ts +6 -1
- package/dist/client/hooks.mjs +41 -1
- package/dist/client/httpClient.cjs +25 -1
- package/dist/client/httpClient.d.ts +8 -3
- package/dist/client/httpClient.mjs +25 -1
- package/dist/client/index.cjs +7 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.mjs +2 -1
- package/dist/client/insertParamsInPath.cjs +1 -1
- package/dist/client/insertParamsInPath.mjs +1 -1
- package/dist/client/promiseRequest.cjs +83 -26
- package/dist/client/promiseRequest.d.ts +46 -29
- package/dist/client/promiseRequest.mjs +83 -26
- package/dist/client/queryToString.cjs +1 -1
- package/dist/client/queryToString.mjs +1 -1
- package/dist/client/serverSentEvents.cjs +231 -0
- package/dist/client/serverSentEvents.d.ts +2 -0
- package/dist/client/serverSentEvents.mjs +208 -0
- package/dist/client/types/clientRequestParams.d.ts +2 -0
- package/dist/client/types/clientResponse.d.ts +34 -3
- package/dist/client/types/hooks.d.ts +17 -7
- package/dist/client/types/promiseRequestParams.d.ts +1 -0
- package/dist/client/types/serverRoute.d.ts +2 -0
- package/dist/core/builders/route/handler.d.ts +5 -2
- package/dist/core/defaultHooks/index.cjs +8 -0
- package/dist/core/defaultHooks/index.d.ts +1 -1
- package/dist/core/defaultHooks/index.mjs +8 -0
- package/dist/core/functionsBuilders/route/default.cjs +9 -13
- package/dist/core/functionsBuilders/route/default.mjs +2 -6
- package/dist/core/functionsBuilders/steps/create.d.ts +2 -2
- package/dist/core/functionsBuilders/steps/defaults/cutStep.cjs +1 -1
- package/dist/core/functionsBuilders/steps/defaults/cutStep.mjs +1 -1
- package/dist/core/functionsBuilders/steps/defaults/handlerStep.cjs +37 -17
- package/dist/core/functionsBuilders/steps/defaults/handlerStep.mjs +37 -17
- package/dist/core/functionsBuilders/steps/defaults/processStep.cjs +3 -3
- package/dist/core/functionsBuilders/steps/defaults/processStep.mjs +3 -3
- package/dist/core/hub/defaultEmptyReaderImplementation.cjs +9 -0
- package/dist/core/hub/defaultEmptyReaderImplementation.d.ts +1 -0
- package/dist/core/hub/defaultEmptyReaderImplementation.mjs +7 -0
- package/dist/core/hub/defaultMalformedUrlHandler.cjs +14 -0
- package/dist/core/hub/defaultMalformedUrlHandler.d.ts +10 -0
- package/dist/core/hub/defaultMalformedUrlHandler.mjs +12 -0
- package/dist/core/hub/defaultNotfoundHandler.d.ts +1 -1
- package/dist/core/hub/index.cjs +14 -1
- package/dist/core/hub/index.d.ts +4 -0
- package/dist/core/hub/index.mjs +13 -2
- package/dist/core/implementHttpServer.cjs +7 -2
- package/dist/core/implementHttpServer.d.ts +7 -1
- package/dist/core/implementHttpServer.mjs +5 -0
- package/dist/core/index.cjs +18 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.mjs +8 -2
- package/dist/core/request/bodyController/base.cjs +24 -6
- package/dist/core/request/bodyController/base.d.ts +9 -0
- package/dist/core/request/bodyController/base.mjs +25 -8
- package/dist/core/request/bodyController/empty.cjs +11 -0
- package/dist/core/request/bodyController/empty.d.ts +3 -0
- package/dist/core/request/bodyController/empty.mjs +8 -0
- package/dist/core/request/bodyController/formData.cjs +1 -0
- package/dist/core/request/bodyController/formData.d.ts +4 -2
- package/dist/core/request/bodyController/formData.mjs +1 -0
- package/dist/core/request/bodyController/index.cjs +4 -0
- package/dist/core/request/bodyController/index.d.ts +1 -0
- package/dist/core/request/bodyController/index.mjs +2 -1
- package/dist/core/request/index.cjs +5 -0
- package/dist/core/request/index.d.ts +1 -1
- package/dist/core/request/index.mjs +6 -1
- package/dist/core/response/contract.cjs +17 -4
- package/dist/core/response/contract.d.ts +19 -4
- package/dist/core/response/contract.mjs +17 -4
- package/dist/core/response/index.cjs +2 -0
- package/dist/core/response/index.d.ts +1 -0
- package/dist/core/response/index.mjs +1 -0
- package/dist/core/response/serverSentEventsPredicted.cjs +23 -0
- package/dist/core/response/serverSentEventsPredicted.d.ts +14 -0
- package/dist/core/response/serverSentEventsPredicted.mjs +21 -0
- package/dist/core/route/hooks.cjs +9 -0
- package/dist/core/route/hooks.d.ts +10 -9
- package/dist/core/route/hooks.mjs +9 -1
- package/dist/core/route/index.cjs +1 -0
- package/dist/core/route/index.mjs +1 -1
- package/dist/core/router/buildSystemRoute.cjs +33 -0
- package/dist/core/router/buildSystemRoute.d.ts +11 -0
- package/dist/core/router/buildSystemRoute.mjs +31 -0
- package/dist/core/router/decodeUrl.cjs +5 -4
- package/dist/core/router/decodeUrl.d.ts +1 -1
- package/dist/core/router/decodeUrl.mjs +5 -4
- package/dist/core/router/index.cjs +24 -23
- package/dist/core/router/index.d.ts +1 -0
- package/dist/core/router/index.mjs +25 -25
- package/dist/core/serverSentEvents.cjs +96 -0
- package/dist/core/serverSentEvents.d.ts +33 -0
- package/dist/core/serverSentEvents.mjs +96 -0
- package/dist/core/steps/cut.d.ts +2 -2
- package/dist/core/steps/handler.d.ts +10 -5
- package/dist/interfaces/node/bodyReaders/formData/index.cjs +34 -14
- package/dist/interfaces/node/bodyReaders/formData/index.mjs +35 -15
- package/dist/interfaces/node/bodyReaders/formData/readRequestFormData.cjs +18 -12
- package/dist/interfaces/node/bodyReaders/formData/readRequestFormData.d.ts +2 -1
- package/dist/interfaces/node/bodyReaders/formData/readRequestFormData.mjs +18 -12
- package/dist/interfaces/node/createHttpServer.cjs +2 -3
- package/dist/interfaces/node/createHttpServer.mjs +2 -3
- package/dist/interfaces/node/hooks/index.cjs +61 -38
- package/dist/interfaces/node/hooks/index.d.ts +6 -4
- package/dist/interfaces/node/hooks/index.mjs +61 -38
- package/dist/interfaces/node/index.cjs +1 -1
- package/dist/interfaces/node/index.mjs +1 -1
- package/dist/plugins/cacheController/createResponseHeader.cjs +43 -0
- package/dist/plugins/cacheController/createResponseHeader.d.ts +2 -0
- package/dist/plugins/cacheController/createResponseHeader.mjs +41 -0
- package/dist/plugins/cacheController/hooks.cjs +23 -0
- package/dist/plugins/cacheController/hooks.d.ts +4 -0
- package/dist/plugins/cacheController/hooks.mjs +21 -0
- package/dist/plugins/cacheController/index.cjs +10 -0
- package/dist/plugins/cacheController/index.d.ts +3 -0
- package/dist/plugins/cacheController/index.mjs +3 -0
- package/dist/plugins/cacheController/types/cacheControlDirectives.cjs +2 -0
- package/dist/plugins/cacheController/types/cacheControlDirectives.d.ts +16 -0
- package/dist/plugins/cacheController/types/cacheControlDirectives.mjs +1 -0
- package/dist/plugins/cacheController/types/index.cjs +4 -0
- package/dist/plugins/cacheController/types/index.d.ts +1 -0
- package/dist/plugins/cacheController/types/index.mjs +1 -0
- package/dist/plugins/codeGenerator/aggregateStepContract.cjs +9 -2
- package/dist/plugins/codeGenerator/aggregateStepContract.d.ts +1 -1
- package/dist/plugins/codeGenerator/aggregateStepContract.mjs +10 -3
- package/dist/plugins/codeGenerator/plugin.cjs +4 -4
- package/dist/plugins/codeGenerator/plugin.mjs +1 -1
- package/dist/plugins/openApiGenerator/aggregateStepContract.d.ts +2 -7
- package/dist/plugins/openApiGenerator/routeToOpenApi.cjs +46 -8
- package/dist/plugins/openApiGenerator/routeToOpenApi.d.ts +2 -2
- package/dist/plugins/openApiGenerator/routeToOpenApi.mjs +46 -8
- package/dist/plugins/openApiGenerator/types/endpointResponse.d.ts +7 -3
- package/dist/plugins/static/index.cjs +14 -0
- package/dist/plugins/static/index.d.ts +3 -0
- package/dist/plugins/static/index.mjs +3 -0
- package/dist/plugins/static/kind.cjs +9 -0
- package/dist/plugins/static/kind.d.ts +6 -0
- package/dist/plugins/static/kind.mjs +7 -0
- package/dist/plugins/static/makeRouteFile.cjs +62 -0
- package/dist/plugins/static/makeRouteFile.d.ts +48 -0
- package/dist/plugins/static/makeRouteFile.mjs +58 -0
- package/dist/plugins/static/makeRouteFolder.cjs +67 -0
- package/dist/plugins/static/makeRouteFolder.d.ts +39 -0
- package/dist/plugins/static/makeRouteFolder.mjs +65 -0
- package/dist/plugins/static/plugin.cjs +53 -0
- package/dist/plugins/static/plugin.d.ts +26 -0
- package/dist/plugins/static/plugin.mjs +50 -0
- package/package.json +18 -7
- /package/dist/plugins/codeGenerator/{typescriptTransfomer.cjs → typescriptTransformer.cjs} +0 -0
- /package/dist/plugins/codeGenerator/{typescriptTransfomer.d.ts → typescriptTransformer.d.ts} +0 -0
- /package/dist/plugins/codeGenerator/{typescriptTransfomer.mjs → typescriptTransformer.mjs} +0 -0
|
@@ -24,14 +24,15 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
24
24
|
return utils.E.error(new error.BodyParseFormDataError("Wrong boundary."));
|
|
25
25
|
}
|
|
26
26
|
let valueAccumulator = firstValueAccumulator;
|
|
27
|
-
const startPart = Buffer.from(`\r\n--${boundary}`);
|
|
28
|
-
const endMultiPart = Buffer.from(`\r\n--${boundary}
|
|
27
|
+
const startPart = Buffer.from(`\r\n--${boundary}\r\n`);
|
|
28
|
+
const endMultiPart = Buffer.from(`\r\n--${boundary}--\r\n`);
|
|
29
29
|
let currentBuffer = bufferStart;
|
|
30
30
|
let size = 0;
|
|
31
|
-
const keep = endMultiPart.length
|
|
31
|
+
const keep = endMultiPart.length;
|
|
32
32
|
let currentStream = undefined;
|
|
33
33
|
let fileQuantity = 0;
|
|
34
34
|
let currentFileSize = undefined;
|
|
35
|
+
let currentTextFieldSize = undefined;
|
|
35
36
|
const checkSize = (receivedChunk) => {
|
|
36
37
|
size += receivedChunk.length;
|
|
37
38
|
return size > params.maxBodySize
|
|
@@ -61,6 +62,7 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
61
62
|
}
|
|
62
63
|
if (header.filename !== undefined) {
|
|
63
64
|
currentFileSize = 0;
|
|
65
|
+
currentTextFieldSize = undefined;
|
|
64
66
|
fileQuantity++;
|
|
65
67
|
if (fileQuantity > params.maxFileQuantity) {
|
|
66
68
|
return new error.BodyParseFormDataError("File quantity exceeds limit.");
|
|
@@ -72,6 +74,7 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
72
74
|
}
|
|
73
75
|
else {
|
|
74
76
|
currentFileSize = undefined;
|
|
77
|
+
currentTextFieldSize = 0;
|
|
75
78
|
}
|
|
76
79
|
const newStream = await onReceiveHeader(header);
|
|
77
80
|
if (newStream instanceof Error) {
|
|
@@ -93,10 +96,16 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
93
96
|
}
|
|
94
97
|
if (typeof currentFileSize === "number") {
|
|
95
98
|
currentFileSize += chunk.length;
|
|
96
|
-
if (
|
|
99
|
+
if (currentFileSize > params.fileMaxSize) {
|
|
97
100
|
return new error.BodyParseFormDataError("File size exceeds limit.");
|
|
98
101
|
}
|
|
99
102
|
}
|
|
103
|
+
if (typeof currentTextFieldSize === "number") {
|
|
104
|
+
currentTextFieldSize += chunk.length;
|
|
105
|
+
if (currentTextFieldSize > params.textFieldMaxSize) {
|
|
106
|
+
return new error.BodyParseFormDataError("Text field size exceeds limit.");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
100
109
|
await currentStream.onReceiveChunk(chunk);
|
|
101
110
|
return true;
|
|
102
111
|
};
|
|
@@ -114,11 +123,6 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
114
123
|
return await treatError(new error.BodyParseFormDataError("Buffer size exceeds limit."));
|
|
115
124
|
}
|
|
116
125
|
while (true) {
|
|
117
|
-
const endMultiPartIndex = currentBuffer.indexOf(endMultiPart);
|
|
118
|
-
if (endMultiPartIndex !== -1) {
|
|
119
|
-
// check if buffer contain end of transmissions
|
|
120
|
-
currentBuffer = currentBuffer.subarray(0, endMultiPartIndex);
|
|
121
|
-
}
|
|
122
126
|
const startPartIndex = currentBuffer.indexOf(startPart);
|
|
123
127
|
const endHeaderPartIndex = currentBuffer.indexOf(endHeaderPart);
|
|
124
128
|
if (startPartIndex !== -1 && endHeaderPartIndex !== -1) {
|
|
@@ -156,9 +160,11 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
156
160
|
}
|
|
157
161
|
}
|
|
158
162
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
if (currentBuffer.indexOf(endMultiPart) === -1) {
|
|
164
|
+
const resultChunk = await flushReceiveChunk(currentBuffer.subarray(0, 2));
|
|
165
|
+
if (resultChunk !== true) {
|
|
166
|
+
return await treatError(resultChunk);
|
|
167
|
+
}
|
|
162
168
|
}
|
|
163
169
|
valueAccumulator = await currentStream?.onEndPart(valueAccumulator) ?? valueAccumulator;
|
|
164
170
|
return valueAccumulator;
|
|
@@ -14,7 +14,8 @@ export interface ReadRequestFormDataParams {
|
|
|
14
14
|
maxFileQuantity: number;
|
|
15
15
|
maxBufferSize: number;
|
|
16
16
|
maxKeyLength: number;
|
|
17
|
-
fileMaxSize
|
|
17
|
+
fileMaxSize: number;
|
|
18
|
+
textFieldMaxSize: number;
|
|
18
19
|
mimeType?: RegExp;
|
|
19
20
|
}
|
|
20
21
|
export declare function readRequestFormData<GenericValueAccumulator extends unknown, GenericOutputHeader extends E.Left = never>(request: http.IncomingMessage, firstValueAccumulator: GenericValueAccumulator, params: ReadRequestFormDataParams, onReceiveHeader: (header: HeaderPartInformation) => MaybePromise<ReadRequestFormDataStreamChunkEvent<GenericValueAccumulator> | Error>): Promise<E.Left<"server-error", unknown> | GenericOutputHeader | E.Error<Error> | GenericValueAccumulator>;
|
|
@@ -22,14 +22,15 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
22
22
|
return E.error(new BodyParseFormDataError("Wrong boundary."));
|
|
23
23
|
}
|
|
24
24
|
let valueAccumulator = firstValueAccumulator;
|
|
25
|
-
const startPart = Buffer.from(`\r\n--${boundary}`);
|
|
26
|
-
const endMultiPart = Buffer.from(`\r\n--${boundary}
|
|
25
|
+
const startPart = Buffer.from(`\r\n--${boundary}\r\n`);
|
|
26
|
+
const endMultiPart = Buffer.from(`\r\n--${boundary}--\r\n`);
|
|
27
27
|
let currentBuffer = bufferStart;
|
|
28
28
|
let size = 0;
|
|
29
|
-
const keep = endMultiPart.length
|
|
29
|
+
const keep = endMultiPart.length;
|
|
30
30
|
let currentStream = undefined;
|
|
31
31
|
let fileQuantity = 0;
|
|
32
32
|
let currentFileSize = undefined;
|
|
33
|
+
let currentTextFieldSize = undefined;
|
|
33
34
|
const checkSize = (receivedChunk) => {
|
|
34
35
|
size += receivedChunk.length;
|
|
35
36
|
return size > params.maxBodySize
|
|
@@ -59,6 +60,7 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
59
60
|
}
|
|
60
61
|
if (header.filename !== undefined) {
|
|
61
62
|
currentFileSize = 0;
|
|
63
|
+
currentTextFieldSize = undefined;
|
|
62
64
|
fileQuantity++;
|
|
63
65
|
if (fileQuantity > params.maxFileQuantity) {
|
|
64
66
|
return new BodyParseFormDataError("File quantity exceeds limit.");
|
|
@@ -70,6 +72,7 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
70
72
|
}
|
|
71
73
|
else {
|
|
72
74
|
currentFileSize = undefined;
|
|
75
|
+
currentTextFieldSize = 0;
|
|
73
76
|
}
|
|
74
77
|
const newStream = await onReceiveHeader(header);
|
|
75
78
|
if (newStream instanceof Error) {
|
|
@@ -91,10 +94,16 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
91
94
|
}
|
|
92
95
|
if (typeof currentFileSize === "number") {
|
|
93
96
|
currentFileSize += chunk.length;
|
|
94
|
-
if (
|
|
97
|
+
if (currentFileSize > params.fileMaxSize) {
|
|
95
98
|
return new BodyParseFormDataError("File size exceeds limit.");
|
|
96
99
|
}
|
|
97
100
|
}
|
|
101
|
+
if (typeof currentTextFieldSize === "number") {
|
|
102
|
+
currentTextFieldSize += chunk.length;
|
|
103
|
+
if (currentTextFieldSize > params.textFieldMaxSize) {
|
|
104
|
+
return new BodyParseFormDataError("Text field size exceeds limit.");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
98
107
|
await currentStream.onReceiveChunk(chunk);
|
|
99
108
|
return true;
|
|
100
109
|
};
|
|
@@ -112,11 +121,6 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
112
121
|
return await treatError(new BodyParseFormDataError("Buffer size exceeds limit."));
|
|
113
122
|
}
|
|
114
123
|
while (true) {
|
|
115
|
-
const endMultiPartIndex = currentBuffer.indexOf(endMultiPart);
|
|
116
|
-
if (endMultiPartIndex !== -1) {
|
|
117
|
-
// check if buffer contain end of transmissions
|
|
118
|
-
currentBuffer = currentBuffer.subarray(0, endMultiPartIndex);
|
|
119
|
-
}
|
|
120
124
|
const startPartIndex = currentBuffer.indexOf(startPart);
|
|
121
125
|
const endHeaderPartIndex = currentBuffer.indexOf(endHeaderPart);
|
|
122
126
|
if (startPartIndex !== -1 && endHeaderPartIndex !== -1) {
|
|
@@ -154,9 +158,11 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
154
158
|
}
|
|
155
159
|
}
|
|
156
160
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
161
|
+
if (currentBuffer.indexOf(endMultiPart) === -1) {
|
|
162
|
+
const resultChunk = await flushReceiveChunk(currentBuffer.subarray(0, 2));
|
|
163
|
+
if (resultChunk !== true) {
|
|
164
|
+
return await treatError(resultChunk);
|
|
165
|
+
}
|
|
160
166
|
}
|
|
161
167
|
valueAccumulator = await currentStream?.onEndPart(valueAccumulator) ?? valueAccumulator;
|
|
162
168
|
return valueAccumulator;
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
var http = require('http');
|
|
4
4
|
var https = require('https');
|
|
5
|
-
var index$
|
|
5
|
+
var index$2 = require('./hooks/index.cjs');
|
|
6
6
|
var implementHttpServer = require('../../core/implementHttpServer.cjs');
|
|
7
7
|
var utils = require('@duplojs/utils');
|
|
8
|
-
var index$2 = require('../../core/defaultHooks/index.cjs');
|
|
9
8
|
require('./bodyReaders/index.cjs');
|
|
10
9
|
var index = require('./bodyReaders/text/index.cjs');
|
|
11
10
|
var index$1 = require('./bodyReaders/formData/index.cjs');
|
|
@@ -25,7 +24,6 @@ function createHttpServer(hub, params) {
|
|
|
25
24
|
index.createTextBodyReaderImplementation(httpServerParams),
|
|
26
25
|
index$1.createFormDataBodyReaderImplementation(httpServerParams),
|
|
27
26
|
]);
|
|
28
|
-
hub.addRouteHooks([index$2.initDefaultHook(hub, httpServerParams), index$3.nodeHook]);
|
|
29
27
|
function whenUncaughtError(error, routerInitializationData) {
|
|
30
28
|
const serverResponse = routerInitializationData.raw.response;
|
|
31
29
|
if (!serverResponse.headersSent && !serverResponse.writableEnded) {
|
|
@@ -44,6 +42,7 @@ function createHttpServer(hub, params) {
|
|
|
44
42
|
return implementHttpServer.implementHttpServer({
|
|
45
43
|
hub,
|
|
46
44
|
httpServerParams,
|
|
45
|
+
getInterfaceHooks: ({ hub, httpServerParams }) => [index$2.initNodeHook(hub, httpServerParams)],
|
|
47
46
|
}, ({ httpServerParams, execRouteSystem }) => {
|
|
48
47
|
const server = httpServerParams.https
|
|
49
48
|
? https.createServer(httpServerParams.https)
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
2
|
import https from 'https';
|
|
3
|
-
import {
|
|
3
|
+
import { initNodeHook } from './hooks/index.mjs';
|
|
4
4
|
import { implementHttpServer } from '../../core/implementHttpServer.mjs';
|
|
5
5
|
import { O } from '@duplojs/utils';
|
|
6
|
-
import { initDefaultHook } from '../../core/defaultHooks/index.mjs';
|
|
7
6
|
import './bodyReaders/index.mjs';
|
|
8
7
|
import { createTextBodyReaderImplementation } from './bodyReaders/text/index.mjs';
|
|
9
8
|
import { createFormDataBodyReaderImplementation } from './bodyReaders/formData/index.mjs';
|
|
@@ -23,7 +22,6 @@ function createHttpServer(hub, params) {
|
|
|
23
22
|
createTextBodyReaderImplementation(httpServerParams),
|
|
24
23
|
createFormDataBodyReaderImplementation(httpServerParams),
|
|
25
24
|
]);
|
|
26
|
-
hub.addRouteHooks([initDefaultHook(hub, httpServerParams), nodeHook]);
|
|
27
25
|
function whenUncaughtError(error, routerInitializationData) {
|
|
28
26
|
const serverResponse = routerInitializationData.raw.response;
|
|
29
27
|
if (!serverResponse.headersSent && !serverResponse.writableEnded) {
|
|
@@ -42,6 +40,7 @@ function createHttpServer(hub, params) {
|
|
|
42
40
|
return implementHttpServer({
|
|
43
41
|
hub,
|
|
44
42
|
httpServerParams,
|
|
43
|
+
getInterfaceHooks: ({ hub, httpServerParams }) => [initNodeHook(hub, httpServerParams)],
|
|
45
44
|
}, ({ httpServerParams, execRouteSystem }) => {
|
|
46
45
|
const server = httpServerParams.https
|
|
47
46
|
? https.createServer(httpServerParams.https)
|
|
@@ -1,47 +1,70 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
require('../../../core/response/index.cjs');
|
|
3
4
|
require('../../../core/route/index.cjs');
|
|
5
|
+
var serverSentEvents = require('../../../core/serverSentEvents.cjs');
|
|
4
6
|
var serverUtils = require('@duplojs/server-utils');
|
|
5
7
|
var utils = require('@duplojs/utils');
|
|
6
8
|
var node_fs = require('node:fs');
|
|
7
9
|
var hooks = require('../../../core/route/hooks.cjs');
|
|
10
|
+
var serverSentEventsPredicted = require('../../../core/response/serverSentEventsPredicted.cjs');
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
});
|
|
12
|
+
function initNodeHook(hub, serverParams) {
|
|
13
|
+
const isDev = hub.config.environment === "DEV";
|
|
14
|
+
return hooks.createHookRouteLifeCycle({
|
|
15
|
+
beforeSendResponse({ request, currentResponse, exit }) {
|
|
16
|
+
request.raw.response.writeHead(Number(currentResponse.code), currentResponse.headers);
|
|
17
|
+
return exit();
|
|
18
|
+
},
|
|
19
|
+
async sendResponse({ request, currentResponse, exit }) {
|
|
20
|
+
const { response: rawResponse, request: rawRequest } = request.raw;
|
|
21
|
+
if (currentResponse instanceof serverSentEventsPredicted.ServerSentEventsPredictedResponse) {
|
|
22
|
+
const handler = serverSentEvents.ServerSentEvents.init(currentResponse, {
|
|
23
|
+
lastId: typeof request.headers["last-event-id"] === "string"
|
|
24
|
+
? request.headers["last-event-id"]
|
|
25
|
+
: null,
|
|
26
|
+
});
|
|
27
|
+
rawRequest.on("close", handler.abort);
|
|
28
|
+
void handler.start((value) => new Promise((resolve) => {
|
|
29
|
+
if (!rawResponse.write(value)) {
|
|
30
|
+
rawResponse.once("drain", resolve);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
resolve();
|
|
34
|
+
}
|
|
35
|
+
}), () => void rawResponse.end());
|
|
36
|
+
return exit();
|
|
37
|
+
}
|
|
38
|
+
const body = currentResponse.body;
|
|
39
|
+
if (body instanceof Error) {
|
|
40
|
+
rawResponse.write(body.toString());
|
|
41
|
+
}
|
|
42
|
+
else if (serverUtils.SF.isFileInterface(body)) {
|
|
43
|
+
await new Promise((resolve, reject) => {
|
|
44
|
+
node_fs.createReadStream(body.path)
|
|
45
|
+
.pipe(request.raw.response
|
|
46
|
+
.once("error", reject)
|
|
47
|
+
.once("close", resolve));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
else if (typeof body === "object"
|
|
51
|
+
|| typeof body === "number"
|
|
52
|
+
|| typeof body === "boolean") {
|
|
53
|
+
rawResponse.write(JSON.stringify(body));
|
|
54
|
+
}
|
|
55
|
+
else if (typeof body === "string") {
|
|
56
|
+
rawResponse.write(body);
|
|
57
|
+
}
|
|
58
|
+
rawResponse.end();
|
|
59
|
+
return exit();
|
|
60
|
+
},
|
|
61
|
+
async afterSendResponse({ request, next }) {
|
|
62
|
+
if (request.filesAttache) {
|
|
63
|
+
await Promise.all(utils.A.map(request.filesAttache, (path) => serverUtils.SF.remove(path)));
|
|
64
|
+
}
|
|
65
|
+
return next();
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
}
|
|
46
69
|
|
|
47
|
-
exports.
|
|
70
|
+
exports.initNodeHook = initNodeHook;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { type Hub } from "../../../core/hub";
|
|
2
|
+
import { type HttpServerParams } from "../../../core/types";
|
|
3
|
+
export declare function initNodeHook(hub: Hub, serverParams: HttpServerParams): {
|
|
4
|
+
readonly beforeSendResponse: ({ request, currentResponse, exit }: import("../../../core/route").RouteHookParamsAfter<import("../../../core/request").Request>) => import("../../../core/route").RouteHookExit;
|
|
5
|
+
readonly sendResponse: ({ request, currentResponse, exit }: import("../../../core/route").RouteHookParamsAfter<import("../../../core/request").Request>) => Promise<import("../../../core/route").RouteHookExit>;
|
|
6
|
+
readonly afterSendResponse: ({ request, next }: import("../../../core/route").RouteHookParamsAfter<import("../../../core/request").Request>) => Promise<import("../../../core/route").RouteHookNext>;
|
|
5
7
|
};
|
|
@@ -1,45 +1,68 @@
|
|
|
1
|
+
import '../../../core/response/index.mjs';
|
|
1
2
|
import '../../../core/route/index.mjs';
|
|
3
|
+
import { ServerSentEvents } from '../../../core/serverSentEvents.mjs';
|
|
2
4
|
import { SF } from '@duplojs/server-utils';
|
|
3
5
|
import { A } from '@duplojs/utils';
|
|
4
6
|
import { createReadStream } from 'node:fs';
|
|
5
7
|
import { createHookRouteLifeCycle } from '../../../core/route/hooks.mjs';
|
|
8
|
+
import { ServerSentEventsPredictedResponse } from '../../../core/response/serverSentEventsPredicted.mjs';
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
});
|
|
10
|
+
function initNodeHook(hub, serverParams) {
|
|
11
|
+
const isDev = hub.config.environment === "DEV";
|
|
12
|
+
return createHookRouteLifeCycle({
|
|
13
|
+
beforeSendResponse({ request, currentResponse, exit }) {
|
|
14
|
+
request.raw.response.writeHead(Number(currentResponse.code), currentResponse.headers);
|
|
15
|
+
return exit();
|
|
16
|
+
},
|
|
17
|
+
async sendResponse({ request, currentResponse, exit }) {
|
|
18
|
+
const { response: rawResponse, request: rawRequest } = request.raw;
|
|
19
|
+
if (currentResponse instanceof ServerSentEventsPredictedResponse) {
|
|
20
|
+
const handler = ServerSentEvents.init(currentResponse, {
|
|
21
|
+
lastId: typeof request.headers["last-event-id"] === "string"
|
|
22
|
+
? request.headers["last-event-id"]
|
|
23
|
+
: null,
|
|
24
|
+
});
|
|
25
|
+
rawRequest.on("close", handler.abort);
|
|
26
|
+
void handler.start((value) => new Promise((resolve) => {
|
|
27
|
+
if (!rawResponse.write(value)) {
|
|
28
|
+
rawResponse.once("drain", resolve);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
resolve();
|
|
32
|
+
}
|
|
33
|
+
}), () => void rawResponse.end());
|
|
34
|
+
return exit();
|
|
35
|
+
}
|
|
36
|
+
const body = currentResponse.body;
|
|
37
|
+
if (body instanceof Error) {
|
|
38
|
+
rawResponse.write(body.toString());
|
|
39
|
+
}
|
|
40
|
+
else if (SF.isFileInterface(body)) {
|
|
41
|
+
await new Promise((resolve, reject) => {
|
|
42
|
+
createReadStream(body.path)
|
|
43
|
+
.pipe(request.raw.response
|
|
44
|
+
.once("error", reject)
|
|
45
|
+
.once("close", resolve));
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else if (typeof body === "object"
|
|
49
|
+
|| typeof body === "number"
|
|
50
|
+
|| typeof body === "boolean") {
|
|
51
|
+
rawResponse.write(JSON.stringify(body));
|
|
52
|
+
}
|
|
53
|
+
else if (typeof body === "string") {
|
|
54
|
+
rawResponse.write(body);
|
|
55
|
+
}
|
|
56
|
+
rawResponse.end();
|
|
57
|
+
return exit();
|
|
58
|
+
},
|
|
59
|
+
async afterSendResponse({ request, next }) {
|
|
60
|
+
if (request.filesAttache) {
|
|
61
|
+
await Promise.all(A.map(request.filesAttache, (path) => SF.remove(path)));
|
|
62
|
+
}
|
|
63
|
+
return next();
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
44
67
|
|
|
45
|
-
export {
|
|
68
|
+
export { initNodeHook };
|
|
@@ -15,7 +15,7 @@ var index$2 = require('./bodyReaders/text/index.cjs');
|
|
|
15
15
|
|
|
16
16
|
exports.createInterfacesNodeLibKind = kind.createInterfacesNodeLibKind;
|
|
17
17
|
exports.createHttpServer = createHttpServer.createHttpServer;
|
|
18
|
-
exports.
|
|
18
|
+
exports.initNodeHook = index.initNodeHook;
|
|
19
19
|
exports.BodyParseFormDataError = error.BodyParseFormDataError;
|
|
20
20
|
exports.readRequestFormData = readRequestFormData.readRequestFormData;
|
|
21
21
|
exports.createFormDataBodyReaderImplementation = index$1.createFormDataBodyReaderImplementation;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import './types/index.mjs';
|
|
2
2
|
export { createInterfacesNodeLibKind } from './kind.mjs';
|
|
3
3
|
export { createHttpServer } from './createHttpServer.mjs';
|
|
4
|
-
export {
|
|
4
|
+
export { initNodeHook } from './hooks/index.mjs';
|
|
5
5
|
import './bodyReaders/index.mjs';
|
|
6
6
|
export { BodyParseFormDataError } from './bodyReaders/formData/error.mjs';
|
|
7
7
|
export { readRequestFormData } from './bodyReaders/formData/readRequestFormData.mjs';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var utils = require('@duplojs/utils');
|
|
4
|
+
|
|
5
|
+
function createCacheControlResponseHeader(directives) {
|
|
6
|
+
return utils.pipe([
|
|
7
|
+
utils.O.entry("max-age", directives.maxAge),
|
|
8
|
+
utils.O.entry("s-maxage", directives.sMaxAge),
|
|
9
|
+
utils.O.entry("public", directives.public),
|
|
10
|
+
utils.O.entry("private", directives.private),
|
|
11
|
+
utils.O.entry("no-cache", directives.noCache),
|
|
12
|
+
utils.O.entry("no-store", directives.noStore),
|
|
13
|
+
utils.O.entry("no-transform", directives.noTransform),
|
|
14
|
+
utils.O.entry("must-revalidate", directives.mustRevalidate),
|
|
15
|
+
utils.O.entry("proxy-revalidate", directives.proxyRevalidate),
|
|
16
|
+
utils.O.entry("immutable", directives.immutable),
|
|
17
|
+
utils.O.entry("stale-while-revalidate", directives.staleWhileRevalidate),
|
|
18
|
+
utils.O.entry("stale-if-error", directives.staleIfError),
|
|
19
|
+
utils.O.entry("must-understand", directives.mustUnderstand),
|
|
20
|
+
], utils.A.concat(directives.extensions ? utils.O.entries(directives.extensions) : []), utils.A.reduce(utils.A.reduceFrom([]), ({ element: [key, value], lastValue, nextPush, next }) => {
|
|
21
|
+
if (value === true) {
|
|
22
|
+
return nextPush(lastValue, key);
|
|
23
|
+
}
|
|
24
|
+
else if (typeof value === "number"
|
|
25
|
+
&& Number.isFinite(value)
|
|
26
|
+
&& value >= 0) {
|
|
27
|
+
return nextPush(lastValue, `${key}=${Math.trunc(value)}`);
|
|
28
|
+
}
|
|
29
|
+
else if (value instanceof Array
|
|
30
|
+
&& utils.A.minElements(value, 1)) {
|
|
31
|
+
return nextPush(lastValue, `${key}="${utils.A.join(value, ",")}"`);
|
|
32
|
+
}
|
|
33
|
+
else if (value !== ""
|
|
34
|
+
&& typeof value === "string") {
|
|
35
|
+
return nextPush(lastValue, `${key}="${value}"`);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
return next(lastValue);
|
|
39
|
+
}
|
|
40
|
+
}), utils.A.join(","));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
exports.createCacheControlResponseHeader = createCacheControlResponseHeader;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { pipe, O, A } from '@duplojs/utils';
|
|
2
|
+
|
|
3
|
+
function createCacheControlResponseHeader(directives) {
|
|
4
|
+
return pipe([
|
|
5
|
+
O.entry("max-age", directives.maxAge),
|
|
6
|
+
O.entry("s-maxage", directives.sMaxAge),
|
|
7
|
+
O.entry("public", directives.public),
|
|
8
|
+
O.entry("private", directives.private),
|
|
9
|
+
O.entry("no-cache", directives.noCache),
|
|
10
|
+
O.entry("no-store", directives.noStore),
|
|
11
|
+
O.entry("no-transform", directives.noTransform),
|
|
12
|
+
O.entry("must-revalidate", directives.mustRevalidate),
|
|
13
|
+
O.entry("proxy-revalidate", directives.proxyRevalidate),
|
|
14
|
+
O.entry("immutable", directives.immutable),
|
|
15
|
+
O.entry("stale-while-revalidate", directives.staleWhileRevalidate),
|
|
16
|
+
O.entry("stale-if-error", directives.staleIfError),
|
|
17
|
+
O.entry("must-understand", directives.mustUnderstand),
|
|
18
|
+
], A.concat(directives.extensions ? O.entries(directives.extensions) : []), A.reduce(A.reduceFrom([]), ({ element: [key, value], lastValue, nextPush, next }) => {
|
|
19
|
+
if (value === true) {
|
|
20
|
+
return nextPush(lastValue, key);
|
|
21
|
+
}
|
|
22
|
+
else if (typeof value === "number"
|
|
23
|
+
&& Number.isFinite(value)
|
|
24
|
+
&& value >= 0) {
|
|
25
|
+
return nextPush(lastValue, `${key}=${Math.trunc(value)}`);
|
|
26
|
+
}
|
|
27
|
+
else if (value instanceof Array
|
|
28
|
+
&& A.minElements(value, 1)) {
|
|
29
|
+
return nextPush(lastValue, `${key}="${A.join(value, ",")}"`);
|
|
30
|
+
}
|
|
31
|
+
else if (value !== ""
|
|
32
|
+
&& typeof value === "string") {
|
|
33
|
+
return nextPush(lastValue, `${key}="${value}"`);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return next(lastValue);
|
|
37
|
+
}
|
|
38
|
+
}), A.join(","));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { createCacheControlResponseHeader };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var createResponseHeader = require('./createResponseHeader.cjs');
|
|
4
|
+
require('../../core/route/index.cjs');
|
|
5
|
+
var hooks = require('../../core/route/hooks.cjs');
|
|
6
|
+
|
|
7
|
+
const eligibleCodeRegex = /^(?:2|3)/;
|
|
8
|
+
function createCacheControllerHooks(params) {
|
|
9
|
+
const cacheControl = params
|
|
10
|
+
? createResponseHeader.createCacheControlResponseHeader(params)
|
|
11
|
+
: null;
|
|
12
|
+
return hooks.createHookRouteLifeCycle({
|
|
13
|
+
beforeSendResponse: ({ currentResponse, next }) => {
|
|
14
|
+
if (cacheControl
|
|
15
|
+
&& eligibleCodeRegex.test(currentResponse.code)) {
|
|
16
|
+
currentResponse.setHeader("cache-control", cacheControl);
|
|
17
|
+
}
|
|
18
|
+
return next();
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
exports.createCacheControllerHooks = createCacheControllerHooks;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CacheControlDirectives } from "./types";
|
|
2
|
+
export declare function createCacheControllerHooks(params?: CacheControlDirectives): {
|
|
3
|
+
readonly beforeSendResponse: ({ currentResponse, next }: import("../../core/route").RouteHookParamsAfter<import("../../core/request").Request>) => import("../../core/route").RouteHookNext;
|
|
4
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createCacheControlResponseHeader } from './createResponseHeader.mjs';
|
|
2
|
+
import '../../core/route/index.mjs';
|
|
3
|
+
import { createHookRouteLifeCycle } from '../../core/route/hooks.mjs';
|
|
4
|
+
|
|
5
|
+
const eligibleCodeRegex = /^(?:2|3)/;
|
|
6
|
+
function createCacheControllerHooks(params) {
|
|
7
|
+
const cacheControl = params
|
|
8
|
+
? createCacheControlResponseHeader(params)
|
|
9
|
+
: null;
|
|
10
|
+
return createHookRouteLifeCycle({
|
|
11
|
+
beforeSendResponse: ({ currentResponse, next }) => {
|
|
12
|
+
if (cacheControl
|
|
13
|
+
&& eligibleCodeRegex.test(currentResponse.code)) {
|
|
14
|
+
currentResponse.setHeader("cache-control", cacheControl);
|
|
15
|
+
}
|
|
16
|
+
return next();
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { createCacheControllerHooks };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var hooks = require('./hooks.cjs');
|
|
4
|
+
require('./types/index.cjs');
|
|
5
|
+
var createResponseHeader = require('./createResponseHeader.cjs');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
exports.createCacheControllerHooks = hooks.createCacheControllerHooks;
|
|
10
|
+
exports.createCacheControlResponseHeader = createResponseHeader.createCacheControlResponseHeader;
|