@duplojs/http 0.7.1 → 0.8.4
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/clean/entity.cjs +19 -28
- package/dist/core/clean/entity.d.ts +9 -9
- package/dist/core/clean/entity.mjs +20 -29
- 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.d.ts +2 -2
- 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 +33 -14
- package/dist/interfaces/node/bodyReaders/formData/index.mjs +34 -15
- package/dist/interfaces/node/bodyReaders/formData/readRequestFormData.cjs +8 -11
- package/dist/interfaces/node/bodyReaders/formData/readRequestFormData.mjs +8 -11
- 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
|
@@ -1,15 +1,40 @@
|
|
|
1
1
|
import '../../../../core/request/index.mjs';
|
|
2
2
|
import { SF } from '@duplojs/server-utils';
|
|
3
|
-
import { stringToBytes, A, E,
|
|
3
|
+
import { stringToBytes, Path, A, E, unwrap, TheFormData, O } from '@duplojs/utils';
|
|
4
4
|
import { readRequestFormData } from './readRequestFormData.mjs';
|
|
5
|
-
import {
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
6
6
|
import '../../../../core/errors/index.mjs';
|
|
7
|
+
import { open } from 'node:fs/promises';
|
|
7
8
|
export { BodyParseFormDataError } from './error.mjs';
|
|
8
9
|
import { FormDataBodyController } from '../../../../core/request/bodyController/formData.mjs';
|
|
9
10
|
import { WrongContentTypeError } from '../../../../core/errors/wrongContentTypeError.mjs';
|
|
10
11
|
|
|
11
12
|
function createFormDataBodyReaderImplementation(serverParams) {
|
|
12
13
|
const serverMaxBodySize = stringToBytes(serverParams.maxBodySize);
|
|
14
|
+
async function createUploadFile(extension, highWaterMark) {
|
|
15
|
+
let remainingAttempts = 5;
|
|
16
|
+
do {
|
|
17
|
+
const path = Path.resolveRelative([
|
|
18
|
+
serverParams.uploadFolder,
|
|
19
|
+
`${randomUUID()}${extension}`,
|
|
20
|
+
]);
|
|
21
|
+
try {
|
|
22
|
+
const handle = await open(path, "wx");
|
|
23
|
+
return {
|
|
24
|
+
path,
|
|
25
|
+
writeStream: handle.createWriteStream({
|
|
26
|
+
highWaterMark,
|
|
27
|
+
autoClose: true,
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (error.code !== "EEXIST" || --remainingAttempts === 0) {
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
} while (true);
|
|
37
|
+
}
|
|
13
38
|
function addValue(mapResult, fieldName, newValue) {
|
|
14
39
|
const value = mapResult.get(fieldName);
|
|
15
40
|
if (value === undefined) {
|
|
@@ -32,32 +57,26 @@ function createFormDataBodyReaderImplementation(serverParams) {
|
|
|
32
57
|
mimeType: params.mimeType,
|
|
33
58
|
maxBufferSize: params.maxBufferSize,
|
|
34
59
|
maxKeyLength: params.maxKeyLength,
|
|
35
|
-
}, (header) => {
|
|
60
|
+
}, async (header) => {
|
|
36
61
|
const fieldName = header.name;
|
|
37
62
|
if (header.filename) {
|
|
38
63
|
const extension = Path.getExtensionName(header.filename);
|
|
39
64
|
const displayExtension = extension ? `.${extension}` : "";
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
`${Math.random().toString(36).slice(2, 10)}-${Date.now()}${displayExtension}`,
|
|
43
|
-
]);
|
|
44
|
-
filesAttache.push(filePath);
|
|
45
|
-
const currentFile = createWriteStream(filePath, {
|
|
46
|
-
highWaterMark: request.raw.request.readableHighWaterMark,
|
|
47
|
-
});
|
|
65
|
+
const { path, writeStream } = await createUploadFile(displayExtension, request.raw.request.readableHighWaterMark);
|
|
66
|
+
filesAttache.push(path);
|
|
48
67
|
return {
|
|
49
|
-
onReceiveChunk: (chunk) => new Promise((resolve, reject) => void
|
|
68
|
+
onReceiveChunk: (chunk) => new Promise((resolve, reject) => void writeStream.write(chunk, (result) => {
|
|
50
69
|
if (result instanceof Error) {
|
|
51
70
|
return void reject(result);
|
|
52
71
|
}
|
|
53
72
|
return void resolve();
|
|
54
73
|
})),
|
|
55
74
|
onEndPart: (valueAccumulator) => {
|
|
56
|
-
|
|
57
|
-
addValue(valueAccumulator, fieldName, SF.createFileInterface(
|
|
75
|
+
writeStream.end();
|
|
76
|
+
addValue(valueAccumulator, fieldName, SF.createFileInterface(path));
|
|
58
77
|
return valueAccumulator;
|
|
59
78
|
},
|
|
60
|
-
onError: () => void
|
|
79
|
+
onError: () => void writeStream.end(),
|
|
61
80
|
};
|
|
62
81
|
}
|
|
63
82
|
let currentValue = "";
|
|
@@ -24,11 +24,11 @@ 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;
|
|
@@ -114,11 +114,6 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
114
114
|
return await treatError(new error.BodyParseFormDataError("Buffer size exceeds limit."));
|
|
115
115
|
}
|
|
116
116
|
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
117
|
const startPartIndex = currentBuffer.indexOf(startPart);
|
|
123
118
|
const endHeaderPartIndex = currentBuffer.indexOf(endHeaderPart);
|
|
124
119
|
if (startPartIndex !== -1 && endHeaderPartIndex !== -1) {
|
|
@@ -156,9 +151,11 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
156
151
|
}
|
|
157
152
|
}
|
|
158
153
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
154
|
+
if (currentBuffer.indexOf(endMultiPart) === -1) {
|
|
155
|
+
const resultChunk = await flushReceiveChunk(currentBuffer.subarray(0, 2));
|
|
156
|
+
if (resultChunk !== true) {
|
|
157
|
+
return await treatError(resultChunk);
|
|
158
|
+
}
|
|
162
159
|
}
|
|
163
160
|
valueAccumulator = await currentStream?.onEndPart(valueAccumulator) ?? valueAccumulator;
|
|
164
161
|
return valueAccumulator;
|
|
@@ -22,11 +22,11 @@ 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;
|
|
@@ -112,11 +112,6 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
112
112
|
return await treatError(new BodyParseFormDataError("Buffer size exceeds limit."));
|
|
113
113
|
}
|
|
114
114
|
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
115
|
const startPartIndex = currentBuffer.indexOf(startPart);
|
|
121
116
|
const endHeaderPartIndex = currentBuffer.indexOf(endHeaderPart);
|
|
122
117
|
if (startPartIndex !== -1 && endHeaderPartIndex !== -1) {
|
|
@@ -154,9 +149,11 @@ async function readRequestFormData(request, firstValueAccumulator, params, onRec
|
|
|
154
149
|
}
|
|
155
150
|
}
|
|
156
151
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
152
|
+
if (currentBuffer.indexOf(endMultiPart) === -1) {
|
|
153
|
+
const resultChunk = await flushReceiveChunk(currentBuffer.subarray(0, 2));
|
|
154
|
+
if (resultChunk !== true) {
|
|
155
|
+
return await treatError(resultChunk);
|
|
156
|
+
}
|
|
160
157
|
}
|
|
161
158
|
valueAccumulator = await currentStream?.onEndPart(valueAccumulator) ?? valueAccumulator;
|
|
162
159
|
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;
|