@koeroesi86/node-webserver 26.10.36916718511-master → 26.10.37633705232-master

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.
Files changed (38) hide show
  1. package/README.md +105 -0
  2. package/dist/configuration.example.d.ts +2 -0
  3. package/dist/configuration.example.js +2 -0
  4. package/dist/configuration.example.js.map +1 -1
  5. package/dist/constants/index.d.ts +7 -0
  6. package/dist/constants/index.js +8 -1
  7. package/dist/constants/index.js.map +1 -1
  8. package/dist/middlewares/accessLogs.js +42 -35
  9. package/dist/middlewares/accessLogs.js.map +1 -1
  10. package/dist/middlewares/compression.d.ts +10 -0
  11. package/dist/middlewares/compression.js +135 -0
  12. package/dist/middlewares/compression.js.map +1 -0
  13. package/dist/middlewares/lambda.js +8 -12
  14. package/dist/middlewares/lambda.js.map +1 -1
  15. package/dist/middlewares/staticWorker.js +9 -3
  16. package/dist/middlewares/staticWorker.js.map +1 -1
  17. package/dist/types.d.ts +28 -0
  18. package/dist/utils/configureServer.d.ts +9 -0
  19. package/dist/utils/configureServer.js +29 -0
  20. package/dist/utils/configureServer.js.map +1 -0
  21. package/dist/utils/exitHandler.js +2 -0
  22. package/dist/utils/exitHandler.js.map +1 -1
  23. package/dist/utils/getDate.d.ts +1 -0
  24. package/dist/utils/getDate.js +15 -5
  25. package/dist/utils/getDate.js.map +1 -1
  26. package/dist/utils/logger.d.ts +5 -0
  27. package/dist/utils/logger.js +74 -5
  28. package/dist/utils/logger.js.map +1 -1
  29. package/dist/utils/setupVirtualHosts.js +11 -2
  30. package/dist/utils/setupVirtualHosts.js.map +1 -1
  31. package/dist/utils/startServer.js +6 -0
  32. package/dist/utils/startServer.js.map +1 -1
  33. package/examples/cpu/exampleWorker.js +22 -0
  34. package/examples/exampleWorker.js +8 -1
  35. package/examples/health/exampleWorker.js +18 -0
  36. package/examples/stream/exampleWorker.js +17 -0
  37. package/examples/upload/exampleWorker.js +20 -0
  38. package/package.json +8 -4
package/README.md CHANGED
@@ -25,6 +25,111 @@ Please enter in a console/terminal:
25
25
  `pnpm start` compiles the TypeScript sources in `src/` to `dist/` and restarts on changes. `pnpm build` creates the published `dist/` output once, `pnpm test` runs the Jest suite and `pnpm lint` checks formatting.
26
26
 
27
27
 
28
+ ### Compression
29
+
30
+ Compression is off. Switch it on for a server with `compression` in its definition:
31
+
32
+ ```javascript
33
+ {
34
+ hostname: 'web.localhost',
35
+ protocol: 'http',
36
+ type: 'worker',
37
+ compression: true, // or { threshold: 512, level: 6, brotliQuality: 4, encodings: ['br', 'gzip'] }
38
+ options: { root: '/path/to/files' },
39
+ }
40
+ ```
41
+
42
+ Responses of text like types (text, JSON, JavaScript, XML, SVG, some fonts) are compressed with brotli, gzip or deflate, whichever the client accepts and likes most,
43
+ when they are at least `threshold` bytes (1024 by default) or of unknown size. Streamed responses stay streamed, as every part is flushed. The compression runs on the
44
+ threads of node, not on the one that serves the requests, but it still takes CPU: leave it to a reverse proxy or CDN if there is one in front of the server.
45
+
46
+ ### Request bodies
47
+
48
+ The body of a request is not part of the event a worker is called with. The worker is called as soon as the request arrives, and reads the body from `event.bodyStream`, a Readable, while it comes in.
49
+ Every request has one, it is empty when the request has no body. The body goes to the worker in parts, and only a few ahead of what the worker has read, so a slow worker, or a fast client, does not fill the memory:
50
+ uploads of any size need a flat amount of it.
51
+
52
+ ```javascript
53
+ module.exports = async (event, callback) => {
54
+ let size = 0;
55
+ for await (const chunk of event.bodyStream) size += chunk.length;
56
+ callback({ statusCode: 200, headers: {}, body: String(size), isBase64Encoded: false });
57
+ };
58
+ ```
59
+
60
+ A worker that needs the whole body reads it into memory itself, with what node has for it (`stream/consumers`):
61
+
62
+ ```javascript
63
+ const { buffer, json, text } = require('stream/consumers');
64
+
65
+ module.exports = async (event, callback) => {
66
+ const payload = await json(event.bodyStream); // or text(...), or buffer(...) for the bytes
67
+ callback({ statusCode: 200, headers: {}, body: JSON.stringify({ received: payload }), isBase64Encoded: false });
68
+ };
69
+ ```
70
+
71
+ A body that has already arrived with the request and is small (up to `inlineRequestBody` bytes, 65536 by default, 0 to turn it off) is not sent in parts: it goes along with the request, which saves the messages of a stream. The worker reads it from
72
+ `event.bodyStream` all the same. Bigger bodies, and ones that arrive after the request, are streamed as described. A body is one or the other, never both.
73
+
74
+ Things to know:
75
+ - **`event.body` is gone.** Workers that read it get `undefined` and have to read `event.bodyStream` instead, as above. The server does not read bodies into memory any more, nor stop at 1 MB:
76
+ `limitRequestBody` in the options of the server is the largest body in bytes that is let through (413 above it), 0 for no limit, which is the default.
77
+ - Read the body before you answer. Once the response is complete the rest of the body is dropped and the stream is destroyed.
78
+ - The stream is destroyed with an error when the client goes away during the upload, `for await` throws it.
79
+ - Requests that have no body (GET, HEAD, DELETE, OPTIONS), websockets and the static worker never get one.
80
+ - The worker holds a request for as long as the upload takes. `limitResponseTimeout` counts from the last part that moved, a stalled upload is answered with 504 after it.
81
+ - The `lambda` server type still reads the whole body first.
82
+
83
+ ### Metrics for workers
84
+
85
+ A worker can ask the server how it is doing with `event.getMetrics()`, which makes it easy to add a health or metrics endpoint. The server is one process and the workers are others, so this is a question over the channel to the server,
86
+ answered with a snapshot:
87
+
88
+ ```javascript
89
+ module.exports = async (event, callback) => {
90
+ const metrics = await event.getMetrics();
91
+ callback({ statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(metrics), isBase64Encoded: false });
92
+ };
93
+ ```
94
+
95
+ | | |
96
+ | --- | --- |
97
+ | `uptimeSeconds`, `memory` | of the server process: `rss`, `heapTotal`, `heapUsed`, `external` |
98
+ | `eventLoopDelayMs` | `mean`, `p99` and `max` of how late the event loop ran since the metrics were read the last time (all zero the first time): the best sign that the server is too busy |
99
+ | `requests` | `total`, `active` (no complete response yet) and `status`, the responses by class (`2xx` ... `5xx`) |
100
+ | `sources` | `workers:<host name>` for each worker server (`workers`, `active` requests, `waiting` requests, `refused`, `failing`, the worker files that crashed in a row, and the same per worker file under `paths`), `lambdas` (`lambdas`, `busy`, `starting`, per file), `connections:http` and `connections:https` (`open`, `dropped`, the settings) |
101
+
102
+ `examples/health/exampleWorker.js` is a worker with `/health` (200, or 503 while requests wait for a worker) and `/metrics`. Mind that a health endpoint is a worker like the others: it is reachable by anyone who can reach its host name.
103
+ Part of the numbers are counted since the server started, a scraper computes rates from them. The existing stats domain (`statsDomain`) reports CPU and memory per process.
104
+ `getServerMetrics()` and `registerMetricsSource(name, read)` are exported by `@koeroesi86/node-worker-express`, to read the same numbers in the server process or add your own.
105
+
106
+ ### Logging
107
+
108
+ The access logs and everything else that is logged go to the console in one write at the end of every turn of the event loop, and to the files in one write per file every 100 milliseconds (`fileLogFlushInterval`), as every write is a system call
109
+ on the thread that serves the requests. Lines of other code that write to the console directly can come out before the lines of the turn, by at most that turn. A level that is switched off costs nothing, its lines are not even built.
110
+
111
+ ### Waiting for a worker
112
+
113
+ A request is handed a worker of its worker file at once, also when all of them are busy: workers handle several requests at a time, and a request waits only when its file has no worker and no more can be started, because the limit for all
114
+ workers (`limit`) is used up by other files. Those requests wait in line, the one that came first is served first, and are woken as soon as there is room (a request is finished and a worker of another file can make room, a worker stops),
115
+ nothing polls. A request that has waited for `limitRequestTimeout` (5 seconds by default), or that finds `limitQueue` requests waiting already (1000 by default, 0 for no limit), is answered with 503 and `Retry-After: 1` at once,
116
+ instead of piling up. `refused` in the metrics of the worker pool counts both.
117
+
118
+ ### Workers that crash
119
+
120
+ A worker that stops with an error, or at all within 5 seconds of starting, has crashed. The first crash is answered by starting another worker for the next request, as before.
121
+ After the second one in a row the server stops starting workers for that path for a while, 100 milliseconds at first and twice as long after every further crash up to 10 seconds, instead of starting a process for every request.
122
+ Requests that arrive in the meantime are answered with 503 and a `Retry-After`, unless a worker for the path is still running, which takes them. A worker that stays up for 5 seconds clears the count.
123
+ `failing` in the metrics lists the paths that are held back, with their crashes and the time left. Workers the server stops itself (an idle one that makes room, the shutdown) are no crash.
124
+
125
+ What a worker writes to its stdout and stderr is handed to `onStdout` and `onStderr` from the moment it starts.
126
+
127
+ ### Connections
128
+
129
+ `keepAliveTimeout` (milliseconds, default 65000) is how long the server keeps an idle connection of a client open. Node closes them after 5 seconds, which is shorter than what load balancers and proxies keep theirs for (60 seconds is common),
130
+ and a request that was sent over a connection that has just been closed fails. `maxConnections` (default 10000, 0 for no limit) is the number of open connections per server (http and https each) after which new ones are dropped,
131
+ which the `connections:*` metrics count. Both are in the top level of the configuration, next to the ports.
132
+
28
133
  ### Build
29
134
 
30
135
  TODO: Set up tests for build
@@ -9,6 +9,8 @@ declare const configuration: {
9
9
  };
10
10
  portHttp: number;
11
11
  portHttps: number;
12
+ keepAliveTimeout: number;
13
+ maxConnections: number;
12
14
  portLookup: {
13
15
  from: number;
14
16
  to: number;
@@ -12,6 +12,8 @@ const configuration = {
12
12
  },
13
13
  portHttp: 80,
14
14
  portHttps: 443,
15
+ keepAliveTimeout: constants_1.DEFAULT_KEEP_ALIVE_TIMEOUT, // milliseconds an idle connection stays open
16
+ maxConnections: constants_1.DEFAULT_MAX_CONNECTIONS, // per server, 0 for no limit
15
17
  portLookup: {
16
18
  from: 3000,
17
19
  to: 3010,
@@ -1 +1 @@
1
- {"version":3,"file":"configuration.example.js","sourceRoot":"","sources":["../src/configuration.example.ts"],"names":[],"mappings":";AAAA,+BAA+B;AAC/B,2CAA2C;AAG3C,MAAM,aAAa,GAAG;IACpB,WAAW,EAAE,IAAA,cAAO,EAAC,wBAAY,EAAE,SAAS,CAAC;IAC7C,SAAS,EAAE;QACT,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,IAAI;KACd;IACD,QAAQ,EAAE,EAAE;IACZ,SAAS,EAAE,GAAG;IACd,UAAU,EAAE;QACV,IAAI,EAAE,IAAI;QACV,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,WAAW;KACrB;IACD,WAAW,EAAE,iBAAiB,EAAE,0BAA0B;IAC1D,oBAAoB,EAAE,KAAK;IAC3B,OAAO,EAAE;QACP;YACE,QAAQ,EAAE,eAAe;YACzB,QAAQ,EAAE,MAAM;YAChB,qEAAqE;YACrE,mEAAmE;YACnE,IAAI,EAAE,QAAQ,EAAE,4BAA4B;YAC5C,OAAO,EAAE;gBACP,IAAI,EAAE,IAAA,cAAO,EAAC,wBAAY,EAAE,UAAU,CAAC;gBACvC,KAAK,EAAE,CAAC,kBAAkB,CAAC;aAC5B;SACF;KACF;CACsB,CAAC;AAE1B,iBAAS,aAAa,CAAC"}
1
+ {"version":3,"file":"configuration.example.js","sourceRoot":"","sources":["../src/configuration.example.ts"],"names":[],"mappings":";AAAA,+BAA+B;AAC/B,2CAAgG;AAGhG,MAAM,aAAa,GAAG;IACpB,WAAW,EAAE,IAAA,cAAO,EAAC,wBAAY,EAAE,SAAS,CAAC;IAC7C,SAAS,EAAE;QACT,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,IAAI;KACd;IACD,QAAQ,EAAE,EAAE;IACZ,SAAS,EAAE,GAAG;IACd,gBAAgB,EAAE,sCAA0B,EAAE,6CAA6C;IAC3F,cAAc,EAAE,mCAAuB,EAAE,6BAA6B;IACtE,UAAU,EAAE;QACV,IAAI,EAAE,IAAI;QACV,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,WAAW;KACrB;IACD,WAAW,EAAE,iBAAiB,EAAE,0BAA0B;IAC1D,oBAAoB,EAAE,KAAK;IAC3B,OAAO,EAAE;QACP;YACE,QAAQ,EAAE,eAAe;YACzB,QAAQ,EAAE,MAAM;YAChB,qEAAqE;YACrE,mEAAmE;YACnE,IAAI,EAAE,QAAQ,EAAE,4BAA4B;YAC5C,OAAO,EAAE;gBACP,IAAI,EAAE,IAAA,cAAO,EAAC,wBAAY,EAAE,UAAU,CAAC;gBACvC,KAAK,EAAE,CAAC,kBAAkB,CAAC;aAC5B;SACF;KACF;CACsB,CAAC;AAE1B,iBAAS,aAAa,CAAC"}
@@ -2,3 +2,10 @@
2
2
  export declare const PACKAGE_ROOT: string;
3
3
  export declare const DEFAULT_PORTS: Record<string, number>;
4
4
  export declare const PROXY_PROTOCOLS: Record<string, string>;
5
+ /**
6
+ * Node closes an idle keep-alive connection after 5 seconds, which is shorter than what load balancers and proxies keep theirs for (60 seconds is common),
7
+ * and they then send a request on a connection that has just been closed. Longer than their timeout avoids that.
8
+ */
9
+ export declare const DEFAULT_KEEP_ALIVE_TIMEOUT = 65000;
10
+ /** the open connections of a server after which new ones are dropped, 0 for no limit */
11
+ export declare const DEFAULT_MAX_CONNECTIONS = 10000;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PROXY_PROTOCOLS = exports.DEFAULT_PORTS = exports.PACKAGE_ROOT = void 0;
3
+ exports.DEFAULT_MAX_CONNECTIONS = exports.DEFAULT_KEEP_ALIVE_TIMEOUT = exports.PROXY_PROTOCOLS = exports.DEFAULT_PORTS = exports.PACKAGE_ROOT = void 0;
4
4
  const path_1 = require("path");
5
5
  /** folder of the package, both from src/ and dist/ */
6
6
  exports.PACKAGE_ROOT = (0, path_1.resolve)(__dirname, '../..');
@@ -14,4 +14,11 @@ exports.PROXY_PROTOCOLS = {
14
14
  ws: 'ws',
15
15
  wss: 'ws',
16
16
  };
17
+ /**
18
+ * Node closes an idle keep-alive connection after 5 seconds, which is shorter than what load balancers and proxies keep theirs for (60 seconds is common),
19
+ * and they then send a request on a connection that has just been closed. Longer than their timeout avoids that.
20
+ */
21
+ exports.DEFAULT_KEEP_ALIVE_TIMEOUT = 65000;
22
+ /** the open connections of a server after which new ones are dropped, 0 for no limit */
23
+ exports.DEFAULT_MAX_CONNECTIONS = 10000;
17
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":";;;AAAA,+BAA+B;AAE/B,sDAAsD;AACzC,QAAA,YAAY,GAAG,IAAA,cAAO,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAE3C,QAAA,aAAa,GAA2B;IACnD,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,GAAG;CACX,CAAC;AAEW,QAAA,eAAe,GAA2B;IACrD,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,MAAM;IACb,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,IAAI;CACV,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":";;;AAAA,+BAA+B;AAE/B,sDAAsD;AACzC,QAAA,YAAY,GAAG,IAAA,cAAO,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAE3C,QAAA,aAAa,GAA2B;IACnD,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,GAAG;CACX,CAAC;AAEW,QAAA,eAAe,GAA2B;IACrD,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,MAAM;IACb,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,IAAI;CACV,CAAC;AAEF;;;GAGG;AACU,QAAA,0BAA0B,GAAG,KAAK,CAAC;AAEhD,wFAAwF;AAC3E,QAAA,uBAAuB,GAAG,KAAK,CAAC"}
@@ -9,41 +9,48 @@ const fullUrl = (request) => `${request.protocol}://${request.get('host')}${requ
9
9
  const serialiseHeaders = (request) => JSON.stringify(Object.fromEntries(Object.keys(request.headers)
10
10
  .sort()
11
11
  .map((key) => [key, request.headers[key]])));
12
- const getResponseLogger = (statusCode) => {
13
- if (statusCode < 400)
14
- return logger_1.default.success;
15
- if (statusCode >= 400)
16
- return logger_1.default.error;
17
- return logger_1.default.info;
18
- };
19
- const accessLogsMiddleware = ({ alias = 'APP' }) => (request, response, next) => {
20
- setTimeout(() => {
21
- const timePrefix = `[${(0, getDate_1.default)()}]`;
22
- logger_1.default.success([
23
- timePrefix,
24
- `[${alias}]`,
25
- 'REQUEST',
26
- (request.method || '!no-method!').toUpperCase(),
27
- fullUrl(request),
28
- 'HEADERS',
29
- `${serialiseHeaders(request)}`,
30
- ].join(' '));
31
- }, 0);
32
- response.on('finish', () => {
33
- const timePrefix = `[${(0, getDate_1.default)()}]`;
34
- const logLine = [
35
- timePrefix,
36
- `[${alias}]`,
37
- 'RESPONSE',
38
- (request.method || '!no-method!').toUpperCase(),
39
- fullUrl(request),
40
- response.statusCode,
41
- response.statusMessage,
42
- `${response.get('Content-Length') || 0}b sent`,
43
- ].join(' ');
44
- getResponseLogger(response.statusCode)(logLine);
45
- });
46
- next();
12
+ const getResponseLevel = (statusCode) => (statusCode < 400 ? 'success' : 'error');
13
+ const accessLogsMiddleware = ({ alias = 'APP' }) => {
14
+ // the levels do not change while the server runs, and a line that is not logged must not be built: that takes a sorted copy of the headers and a string
15
+ const logsRequests = logger_1.default.isEnabled('success');
16
+ const logsResponses = logger_1.default.isEnabled('success') || logger_1.default.isEnabled('error');
17
+ return (request, response, next) => {
18
+ if (logsRequests) {
19
+ // after the request was handed on, with the cheapest way to wait for that
20
+ setImmediate(() => {
21
+ const timePrefix = `[${(0, getDate_1.default)()}]`;
22
+ logger_1.default.success([
23
+ timePrefix,
24
+ `[${alias}]`,
25
+ 'REQUEST',
26
+ (request.method || '!no-method!').toUpperCase(),
27
+ fullUrl(request),
28
+ 'HEADERS',
29
+ `${serialiseHeaders(request)}`,
30
+ ].join(' '));
31
+ });
32
+ }
33
+ if (logsResponses) {
34
+ response.on('finish', () => {
35
+ const level = getResponseLevel(response.statusCode);
36
+ if (!logger_1.default.isEnabled(level))
37
+ return;
38
+ const timePrefix = `[${(0, getDate_1.default)()}]`;
39
+ const logLine = [
40
+ timePrefix,
41
+ `[${alias}]`,
42
+ 'RESPONSE',
43
+ (request.method || '!no-method!').toUpperCase(),
44
+ fullUrl(request),
45
+ response.statusCode,
46
+ response.statusMessage,
47
+ `${response.get('Content-Length') || 0}b sent`,
48
+ ].join(' ');
49
+ logger_1.default[level](logLine);
50
+ });
51
+ }
52
+ next();
53
+ };
47
54
  };
48
55
  exports.default = accessLogsMiddleware;
49
56
  //# sourceMappingURL=accessLogs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"accessLogs.js","sourceRoot":"","sources":["../../src/middlewares/accessLogs.ts"],"names":[],"mappings":";;;;;AACA,+DAAuC;AACvC,6DAAqC;AAErC,MAAM,OAAO,GAAG,CAAC,OAAgB,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,QAAQ,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;AAE3G,MAAM,gBAAgB,GAAG,CAAC,OAAgB,EAAE,EAAE,CAC5C,IAAI,CAAC,SAAS,CACZ,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;KACzB,IAAI,EAAE;KACN,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAC7C,CACF,CAAC;AAEJ,MAAM,iBAAiB,GAAG,CAAC,UAAkB,EAAE,EAAE;IAC/C,IAAI,UAAU,GAAG,GAAG;QAAE,OAAO,gBAAM,CAAC,OAAO,CAAC;IAC5C,IAAI,UAAU,IAAI,GAAG;QAAE,OAAO,gBAAM,CAAC,KAAK,CAAC;IAC3C,OAAO,gBAAM,CAAC,IAAI,CAAC;AACrB,CAAC,CAAC;AAEF,MAAM,oBAAoB,GACxB,CAAC,EAAE,KAAK,GAAG,KAAK,EAAsB,EAAE,EAAE,CAC1C,CAAC,OAAgB,EAAE,QAAkB,EAAE,IAAkB,EAAE,EAAE;IAC3D,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,UAAU,GAAG,IAAI,IAAA,iBAAO,GAAE,GAAG,CAAC;QACpC,gBAAM,CAAC,OAAO,CACZ;YACE,UAAU;YACV,IAAI,KAAK,GAAG;YACZ,SAAS;YACT,CAAC,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC,WAAW,EAAE;YAC/C,OAAO,CAAC,OAAO,CAAC;YAChB,SAAS;YACT,GAAG,gBAAgB,CAAC,OAAO,CAAC,EAAE;SAC/B,CAAC,IAAI,CAAC,GAAG,CAAC,CACZ,CAAC;IACJ,CAAC,EAAE,CAAC,CAAC,CAAC;IACN,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACzB,MAAM,UAAU,GAAG,IAAI,IAAA,iBAAO,GAAE,GAAG,CAAC;QACpC,MAAM,OAAO,GAAG;YACd,UAAU;YACV,IAAI,KAAK,GAAG;YACZ,UAAU;YACV,CAAC,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC,WAAW,EAAE;YAC/C,OAAO,CAAC,OAAO,CAAC;YAChB,QAAQ,CAAC,UAAU;YACnB,QAAQ,CAAC,aAAa;YACtB,GAAG,QAAQ,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ;SAC/C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,iBAAiB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IACH,IAAI,EAAE,CAAC;AACT,CAAC,CAAC;AAEJ,kBAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"accessLogs.js","sourceRoot":"","sources":["../../src/middlewares/accessLogs.ts"],"names":[],"mappings":";;;;;AACA,+DAAuC;AACvC,6DAAqC;AAGrC,MAAM,OAAO,GAAG,CAAC,OAAgB,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,QAAQ,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;AAE3G,MAAM,gBAAgB,GAAG,CAAC,OAAgB,EAAE,EAAE,CAC5C,IAAI,CAAC,SAAS,CACZ,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;KACzB,IAAI,EAAE;KACN,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAC7C,CACF,CAAC;AAEJ,MAAM,gBAAgB,GAAG,CAAC,UAAkB,EAAmB,EAAE,CAAC,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AAE3G,MAAM,oBAAoB,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,EAAsB,EAAE,EAAE;IACrE,wJAAwJ;IACxJ,MAAM,YAAY,GAAG,gBAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACjD,MAAM,aAAa,GAAG,gBAAM,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,gBAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAE/E,OAAO,CAAC,OAAgB,EAAE,QAAkB,EAAE,IAAkB,EAAE,EAAE;QAClE,IAAI,YAAY,EAAE,CAAC;YACjB,0EAA0E;YAC1E,YAAY,CAAC,GAAG,EAAE;gBAChB,MAAM,UAAU,GAAG,IAAI,IAAA,iBAAO,GAAE,GAAG,CAAC;gBACpC,gBAAM,CAAC,OAAO,CACZ;oBACE,UAAU;oBACV,IAAI,KAAK,GAAG;oBACZ,SAAS;oBACT,CAAC,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC,WAAW,EAAE;oBAC/C,OAAO,CAAC,OAAO,CAAC;oBAChB,SAAS;oBACT,GAAG,gBAAgB,CAAC,OAAO,CAAC,EAAE;iBAC/B,CAAC,IAAI,CAAC,GAAG,CAAC,CACZ,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,aAAa,EAAE,CAAC;YAClB,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;gBACzB,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;gBACpD,IAAI,CAAC,gBAAM,CAAC,SAAS,CAAC,KAAK,CAAC;oBAAE,OAAO;gBAErC,MAAM,UAAU,GAAG,IAAI,IAAA,iBAAO,GAAE,GAAG,CAAC;gBACpC,MAAM,OAAO,GAAG;oBACd,UAAU;oBACV,IAAI,KAAK,GAAG;oBACZ,UAAU;oBACV,CAAC,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC,WAAW,EAAE;oBAC/C,OAAO,CAAC,OAAO,CAAC;oBAChB,QAAQ,CAAC,UAAU;oBACnB,QAAQ,CAAC,aAAa;oBACtB,GAAG,QAAQ,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ;iBAC/C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACZ,gBAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC;QACL,CAAC;QACD,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,kBAAe,oBAAoB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { RequestHandler } from 'express';
2
+ import type { CompressionEncoding, CompressionOptions } from '../types';
3
+ /** The encoding to use: what the client accepts with the highest weight, the order of the options settles ties. */
4
+ export declare function chooseEncoding(acceptEncoding: string, supported: CompressionEncoding[]): CompressionEncoding | undefined;
5
+ /**
6
+ * Compresses the responses that are worth it for the clients that accept it, with the zlib of node: the work runs on the threads of node, not on the one
7
+ * that serves the requests. It takes the decision when the headers are written: text like types, no encoding yet, and a size above the threshold if it is known.
8
+ */
9
+ declare const compression: (options?: CompressionOptions) => RequestHandler;
10
+ export default compression;
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.chooseEncoding = chooseEncoding;
7
+ const zlib_1 = __importDefault(require("zlib"));
8
+ const defaultEncodings = ['br', 'gzip', 'deflate'];
9
+ const compressibleTypes = /^(text\/|application\/(json|(x-)?javascript|xml|wasm|manifest\+json|.+\+(json|xml))|image\/svg\+xml|font\/(ttf|otf)|application\/vnd\.ms-fontobject)/i;
10
+ const bodylessStatuses = [204, 205, 304];
11
+ const lowerCased = (headers) => Object.fromEntries(Object.entries(headers).map(([name, value]) => [name.toLowerCase(), value]));
12
+ const asString = (value) => (Array.isArray(value) ? value.join(', ') : `${value ?? ''}`);
13
+ /** The encoding to use: what the client accepts with the highest weight, the order of the options settles ties. */
14
+ function chooseEncoding(acceptEncoding, supported) {
15
+ const weights = new Map(acceptEncoding
16
+ .toLowerCase()
17
+ .split(',')
18
+ .map((part) => part.trim())
19
+ .filter(Boolean)
20
+ .map((part) => {
21
+ const [name, ...parameters] = part.split(';').map((piece) => piece.trim());
22
+ const weight = parameters.find((parameter) => parameter.startsWith('q='))?.slice(2);
23
+ return [name, weight === undefined ? 1 : Number(weight) || 0];
24
+ }));
25
+ const weightOf = (encoding) => weights.get(encoding) ?? weights.get('*') ?? 0;
26
+ return supported
27
+ .filter((encoding) => weightOf(encoding) > 0)
28
+ .map((encoding, index) => ({ encoding, index }))
29
+ .sort((a, b) => weightOf(b.encoding) - weightOf(a.encoding) || a.index - b.index)[0]?.encoding;
30
+ }
31
+ const createStream = (encoding, { level = 6, brotliQuality = 4 }, size) => {
32
+ // every write is flushed, so a response that is streamed reaches the client while it is produced instead of when a buffer fills
33
+ if (encoding === 'br') {
34
+ return zlib_1.default.createBrotliCompress({
35
+ flush: zlib_1.default.constants.BROTLI_OPERATION_FLUSH,
36
+ params: { [zlib_1.default.constants.BROTLI_PARAM_QUALITY]: brotliQuality, ...(size !== undefined && { [zlib_1.default.constants.BROTLI_PARAM_SIZE_HINT]: size }) },
37
+ });
38
+ }
39
+ return (encoding === 'gzip' ? zlib_1.default.createGzip : zlib_1.default.createDeflate)({ level, flush: zlib_1.default.constants.Z_SYNC_FLUSH });
40
+ };
41
+ /**
42
+ * Compresses the responses that are worth it for the clients that accept it, with the zlib of node: the work runs on the threads of node, not on the one
43
+ * that serves the requests. It takes the decision when the headers are written: text like types, no encoding yet, and a size above the threshold if it is known.
44
+ */
45
+ const compression = (options = {}) => (request, response, next) => {
46
+ const { threshold = 1024, encodings = defaultEncodings } = options;
47
+ const encoding = chooseEncoding(asString(request.headers['accept-encoding']), encodings);
48
+ const { writeHead, write, end } = response;
49
+ const original = {
50
+ writeHead: (...args) => Reflect.apply(writeHead, response, args),
51
+ write: (...args) => Reflect.apply(write, response, args),
52
+ end: (...args) => Reflect.apply(end, response, args),
53
+ };
54
+ let decided = false;
55
+ let stream;
56
+ const startCompressing = (compressionEncoding, length) => {
57
+ const compressor = createStream(compressionEncoding, options, length);
58
+ // the compressed data goes out through the original write, and the source waits when the client does not keep up
59
+ compressor.on('data', (chunk) => {
60
+ if (original.write(chunk) === false)
61
+ compressor.pause();
62
+ });
63
+ compressor.on('end', () => original.end());
64
+ compressor.on('error', () => response.destroy());
65
+ response.on('drain', () => compressor.resume());
66
+ response.on('close', () => compressor.destroy());
67
+ stream = compressor;
68
+ };
69
+ /** the response head after the decision, `headers` are what is about to be sent: the ones given to writeHead on top of the ones set before */
70
+ const decide = (statusCode, headers, bodySize) => {
71
+ decided = true;
72
+ const type = asString(headers['content-type']).split(';')[0].trim();
73
+ const length = headers['content-length'] === undefined ? bodySize : Number(headers['content-length']);
74
+ const isCompressible = compressibleTypes.test(type);
75
+ const vary = asString(headers.vary);
76
+ // caches have to know that the answer depends on what the client accepts, also when this one is not compressed
77
+ const varied = isCompressible && !/(^|,)\s*(\*|accept-encoding)\s*(,|$)/i.test(vary) ? { Vary: vary ? `${vary}, Accept-Encoding` : 'Accept-Encoding' } : {};
78
+ const mayCompress = encoding !== undefined &&
79
+ isCompressible &&
80
+ request.method !== 'HEAD' &&
81
+ statusCode >= 200 &&
82
+ !bodylessStatuses.includes(statusCode) &&
83
+ (headers['content-encoding'] === undefined || headers['content-encoding'] === 'identity') &&
84
+ !/(^|,)\s*no-transform\s*(,|$)/i.test(asString(headers['cache-control'])) &&
85
+ (length === undefined || Number.isNaN(length) || length >= threshold);
86
+ if (!mayCompress)
87
+ return varied;
88
+ startCompressing(encoding, Number.isNaN(length) ? undefined : length);
89
+ const etag = asString(headers.etag);
90
+ // the size is not known any more, and a strong validator would promise the same bytes as the uncompressed answer
91
+ return { ...varied, 'Content-Encoding': encoding, 'Content-Length': undefined, ...(etag && !etag.startsWith('W/') && { ETag: `W/${etag}` }) };
92
+ };
93
+ /** the head to write: the given headers without the ones that are to be replaced, and the replacements */
94
+ const applyHead = (given, changes) => {
95
+ const replaced = new Set(Object.keys(changes).map((name) => name.toLowerCase()));
96
+ const kept = Object.entries(given ?? {}).filter(([name]) => !replaced.has(name.toLowerCase()));
97
+ return { ...Object.fromEntries(kept), ...Object.fromEntries(Object.entries(changes).filter(([, value]) => value !== undefined)) };
98
+ };
99
+ /** what was set before with setHeader is changed there */
100
+ const applyChanges = (changes) => Object.entries(changes).forEach(([name, value]) => (value === undefined ? response.removeHeader(name) : response.setHeader(name, value)));
101
+ /** for the first write or end without writeHead: the head is made of what was set before, then written */
102
+ const writeImplicitHead = (bodySize) => {
103
+ applyChanges(decide(response.statusCode, lowerCased(response.getHeaders()), bodySize));
104
+ response.writeHead(response.statusCode);
105
+ };
106
+ Object.assign(response, {
107
+ writeHead: (statusCode, ...rest) => {
108
+ const given = rest.find((argument) => typeof argument === 'object' && argument !== null && !Array.isArray(argument));
109
+ // a list of header names and values is rare and cannot be changed in place
110
+ if (decided || rest.some(Array.isArray)) {
111
+ decided = true;
112
+ return original.writeHead(statusCode, ...rest);
113
+ }
114
+ const changes = decide(statusCode, { ...lowerCased(response.getHeaders()), ...lowerCased(given ?? {}) });
115
+ applyChanges(changes);
116
+ // what was given to writeHead takes precedence over what was set before, so it is changed there as well
117
+ return original.writeHead(statusCode, ...rest.filter((argument) => argument !== given), applyHead(given, changes));
118
+ },
119
+ write: (chunk, ...rest) => {
120
+ if (!decided)
121
+ writeImplicitHead();
122
+ return stream ? Reflect.apply(stream.write, stream, [chunk, ...rest]) : original.write(chunk, ...rest);
123
+ },
124
+ end: (chunk, ...rest) => {
125
+ if (!decided)
126
+ writeImplicitHead(typeof chunk === 'string' || Buffer.isBuffer(chunk) ? Buffer.byteLength(chunk) : undefined);
127
+ if (!stream)
128
+ return original.end(chunk, ...rest);
129
+ return Reflect.apply(stream.end, stream, chunk === undefined || typeof chunk === 'function' ? [chunk] : [chunk, ...rest]);
130
+ },
131
+ });
132
+ next();
133
+ };
134
+ exports.default = compression;
135
+ //# sourceMappingURL=compression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compression.js","sourceRoot":"","sources":["../../src/middlewares/compression.ts"],"names":[],"mappings":"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"}
@@ -3,22 +3,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const path_1 = require("path");
7
- const rimraf_1 = __importDefault(require("rimraf"));
8
6
  const node_lambda_invoke_1 = require("@koeroesi86/node-lambda-invoke");
9
7
  const logger_1 = __importDefault(require("../utils/logger"));
10
- const constants_1 = require("../constants");
11
8
  const lambdaMiddleware = (instance) => {
12
9
  const { lambdaOptions: config } = instance;
13
- const storageDriver = (0, path_1.resolve)(__dirname, '../utils/storage').replace(/\\/g, '/');
14
- const lambdaToInvoke = (config?.lambda || '').replace(/\\/g, '/');
15
- const handlerKey = config?.handler || 'handler';
16
- rimraf_1.default.sync((0, path_1.resolve)(constants_1.PACKAGE_ROOT, 'requests/*'), { glob: { silent: true } });
17
- rimraf_1.default.sync((0, path_1.resolve)(constants_1.PACKAGE_ROOT, 'responses/*'), { glob: { silent: true } });
18
- // The installed @koeroesi86/node-lambda-invoke takes a single options object, while this call still uses the older positional
19
- // signature, which makes the middleware a no-op at runtime. Behaviour is kept as it was until the call is migrated.
20
- // @ts-expect-error positional arguments are not part of the current signature
21
- return (0, node_lambda_invoke_1.httpMiddleware)(lambdaToInvoke, handlerKey, logger_1.default.info, storageDriver);
10
+ return (0, node_lambda_invoke_1.httpMiddleware)({
11
+ lambdaPath: (config?.lambda || '').replace(/\\/g, '/'),
12
+ handlerKey: config?.handler || 'handler',
13
+ logger: logger_1.default.info,
14
+ communication: { type: config?.communication || 'ipc' },
15
+ limit: config?.limit,
16
+ acquireTimeout: config?.acquireTimeout,
17
+ });
22
18
  };
23
19
  exports.default = lambdaMiddleware;
24
20
  //# sourceMappingURL=lambda.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lambda.js","sourceRoot":"","sources":["../../src/middlewares/lambda.ts"],"names":[],"mappings":";;;;;AAAA,+BAA+B;AAE/B,oDAA4B;AAC5B,uEAAgE;AAChE,6DAAqC;AACrC,4CAA4C;AAG5C,MAAM,gBAAgB,GAAG,CAAC,QAAwB,EAAkB,EAAE;IACpE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IAC3C,MAAM,aAAa,GAAG,IAAA,cAAO,EAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACjF,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAClE,MAAM,UAAU,GAAG,MAAM,EAAE,OAAO,IAAI,SAAS,CAAC;IAEhD,gBAAM,CAAC,IAAI,CAAC,IAAA,cAAO,EAAC,wBAAY,EAAE,YAAY,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC7E,gBAAM,CAAC,IAAI,CAAC,IAAA,cAAO,EAAC,wBAAY,EAAE,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAE9E,8HAA8H;IAC9H,oHAAoH;IACpH,8EAA8E;IAC9E,OAAO,IAAA,mCAAc,EAAC,cAAc,EAAE,UAAU,EAAE,gBAAM,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AAChF,CAAC,CAAC;AAEF,kBAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"lambda.js","sourceRoot":"","sources":["../../src/middlewares/lambda.ts"],"names":[],"mappings":";;;;;AACA,uEAAgE;AAChE,6DAAqC;AAGrC,MAAM,gBAAgB,GAAG,CAAC,QAAwB,EAAkB,EAAE;IACpE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IAE3C,OAAO,IAAA,mCAAc,EAAC;QACpB,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;QACtD,UAAU,EAAE,MAAM,EAAE,OAAO,IAAI,SAAS;QACxC,MAAM,EAAE,gBAAM,CAAC,IAAI;QACnB,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,IAAI,KAAK,EAAE;QACvD,KAAK,EAAE,MAAM,EAAE,KAAK;QACpB,cAAc,EAAE,MAAM,EAAE,cAAc;KACvC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,kBAAe,gBAAgB,CAAC"}
@@ -110,13 +110,19 @@ function etag(body) {
110
110
  function getCharset(body) {
111
111
  return false;
112
112
  }
113
+ const isInside = (folder, target) => {
114
+ const relative = path_1.default.relative(path_1.default.resolve(folder), path_1.default.resolve(target));
115
+ return !relative.startsWith('..') && !path_1.default.isAbsolute(relative);
116
+ };
117
+ const isFile = (fileName) => fs_1.default.statSync(fileName, { throwIfNoEntry: false })?.isFile() === true;
113
118
  const staticWorker = (event, callback = () => { }) => {
114
119
  debounce(() => {
115
120
  // console.log('Exiting static worker.')
116
121
  }, 5000);
117
- const currentPath = `${event.path.replace(/\.{2,}/, '')}${/\/$/.test(event.path) ? 'index.html' : ''}`;
122
+ const currentPath = `${event.path}${/\/$/.test(event.path) ? 'index.html' : ''}`;
118
123
  const fileName = path_1.default.resolve(event.rootPath, `.${currentPath}`);
119
- if (fs_1.default.existsSync(fileName)) {
124
+ // only files below the root are served, a directory or anything outside of it is answered as missing
125
+ if (isInside(event.rootPath, fileName) && isFile(fileName)) {
120
126
  // TODO: range request
121
127
  const bodyBuffer = fs_1.default.readFileSync(fileName);
122
128
  const stats = fs_1.default.statSync(fileName);
@@ -155,7 +161,7 @@ const staticWorker = (event, callback = () => { }) => {
155
161
  'Content-Type': 'text/plain',
156
162
  'Cache-Control': 'public, max-age=0',
157
163
  },
158
- body: `${fileName} does not exist`,
164
+ body: `${event.path} does not exist`,
159
165
  isBase64Encoded: false,
160
166
  });
161
167
  }
@@ -1 +1 @@
1
- {"version":3,"file":"staticWorker.js","sourceRoot":"","sources":["../../src/middlewares/staticWorker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"staticWorker.js","sourceRoot":"","sources":["../../src/middlewares/staticWorker.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -32,6 +32,23 @@ export interface InstanceServerOptions {
32
32
  export interface LambdaOptions {
33
33
  lambda?: string;
34
34
  handler?: string;
35
+ /** how requests and responses reach the lambda process: `ipc` (default) or through files */
36
+ communication?: 'ipc' | 'file';
37
+ /** how many lambdas may run in total. Defaults to the number of CPU cores, 0 means no limit. */
38
+ limit?: number;
39
+ /** how long a request waits for a lambda when the limit is reached before it is answered with 503, in milliseconds. Defaults to 10000. */
40
+ acquireTimeout?: number;
41
+ }
42
+ export type CompressionEncoding = 'br' | 'gzip' | 'deflate';
43
+ export interface CompressionOptions {
44
+ /** responses of a known size below this many bytes are sent as they are. Defaults to 1024. */
45
+ threshold?: number;
46
+ /** level of gzip and deflate, 1 (fast) to 9 (small). Defaults to 6. */
47
+ level?: number;
48
+ /** quality of brotli, 0 (fast) to 11 (small). Defaults to 4, as higher qualities are slow. */
49
+ brotliQuality?: number;
50
+ /** what may be used, in the order of preference when the client likes them the same. Defaults to all of them: br, gzip, deflate. */
51
+ encodings?: CompressionEncoding[];
35
52
  }
36
53
  export interface ServerInstance {
37
54
  hostname: string;
@@ -41,6 +58,8 @@ export interface ServerInstance {
41
58
  cert?: string;
42
59
  ca?: string;
43
60
  options?: WorkerOptions;
61
+ /** compress the responses of this server for the clients that accept it. Off by default. `true` uses the defaults, an object tunes them. */
62
+ compression?: boolean | CompressionOptions;
44
63
  childOptions?: ChildOptions;
45
64
  proxyOptions?: ProxyOptions;
46
65
  serverOptions?: InstanceServerOptions;
@@ -57,9 +76,18 @@ export interface ServerInstance {
57
76
  export interface Configuration {
58
77
  /** set to false to disable file logging */
59
78
  fileLogPath: string | false;
79
+ /** how long log lines are collected before they are written to the files, in milliseconds. 0 writes every line right away. Defaults to 100. */
80
+ fileLogFlushInterval?: number;
60
81
  logLevels?: LogLevels;
61
82
  portHttp: number;
62
83
  portHttps: number;
84
+ /**
85
+ * how long an idle connection of a client is kept open, in milliseconds, for both the http and the https server. Defaults to 65000, longer than what load balancers keep theirs for.
86
+ * Node itself closes them after 5 seconds.
87
+ */
88
+ keepAliveTimeout?: number;
89
+ /** the number of open connections per server after which new ones are dropped, 0 for no limit. Defaults to 10000. */
90
+ maxConnections?: number;
63
91
  portLookup?: PortLookup;
64
92
  /** set to false to disable */
65
93
  statsDomain: string | false;
@@ -0,0 +1,9 @@
1
+ import type http from 'http';
2
+ import type https from 'https';
3
+ import type { Configuration } from '../types';
4
+ /**
5
+ * Applies the connection settings to a server, and lists its connections in the metrics under `connections:<name>`: how many are open,
6
+ * how many were dropped for the limit, and the settings.
7
+ */
8
+ declare const configureServer: (server: http.Server | https.Server, name: string, { keepAliveTimeout, maxConnections }: Pick<Configuration, "keepAliveTimeout" | "maxConnections">) => void;
9
+ export default configureServer;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_worker_express_1 = require("@koeroesi86/node-worker-express");
4
+ const constants_1 = require("../constants");
5
+ /**
6
+ * Applies the connection settings to a server, and lists its connections in the metrics under `connections:<name>`: how many are open,
7
+ * how many were dropped for the limit, and the settings.
8
+ */
9
+ const configureServer = (server, name, { keepAliveTimeout = constants_1.DEFAULT_KEEP_ALIVE_TIMEOUT, maxConnections = constants_1.DEFAULT_MAX_CONNECTIONS }) => {
10
+ server.keepAliveTimeout = keepAliveTimeout;
11
+ // node wants the time for the headers to be longer than the keep-alive time, otherwise it may close a connection that a client is just reusing
12
+ server.headersTimeout = Math.max(server.headersTimeout, keepAliveTimeout + 1000);
13
+ // node counts 0 as a limit that no connection fits under
14
+ server.maxConnections = maxConnections > 0 ? maxConnections : Infinity;
15
+ let open = 0;
16
+ let dropped = 0;
17
+ server.on('connection', (socket) => {
18
+ open += 1;
19
+ socket.once('close', () => {
20
+ open -= 1;
21
+ });
22
+ });
23
+ server.on('drop', () => {
24
+ dropped += 1;
25
+ });
26
+ (0, node_worker_express_1.registerMetricsSource)(`connections:${name}`, () => ({ open, dropped, maxConnections, keepAliveTimeout }));
27
+ };
28
+ exports.default = configureServer;
29
+ //# sourceMappingURL=configureServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configureServer.js","sourceRoot":"","sources":["../../src/utils/configureServer.ts"],"names":[],"mappings":";;AAAA,yEAAwE;AACxE,4CAAmF;AAKnF;;;GAGG;AACH,MAAM,eAAe,GAAG,CACtB,MAAkC,EAClC,IAAY,EACZ,EAAE,gBAAgB,GAAG,sCAA0B,EAAE,cAAc,GAAG,mCAAuB,EAA8D,EACvJ,EAAE;IACF,MAAM,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IAC3C,+IAA+I;IAC/I,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACjF,yDAAyD;IACzD,MAAM,CAAC,cAAc,GAAG,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEvE,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;QACjC,IAAI,IAAI,CAAC,CAAC;QACV,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;YACxB,IAAI,IAAI,CAAC,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;QACrB,OAAO,IAAI,CAAC,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,IAAA,2CAAqB,EAAC,eAAe,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC;AAC5G,CAAC,CAAC;AAEF,kBAAe,eAAe,CAAC"}
@@ -25,6 +25,8 @@ function exitHandler(instances) {
25
25
  }
26
26
  function exitListener(instances, reason, event) {
27
27
  logger_1.default.error(`${reason} triggered:\n`, event);
28
+ // the signal is raised again below, and a process ended by a signal does not run its exit handlers
29
+ logger_1.default.flush();
28
30
  exitHandler(instances);
29
31
  cleanTmp();
30
32
  // the process is already exiting, there is nothing left to signal ('exit' is not a signal)
@@ -1 +1 @@
1
- {"version":3,"file":"exitHandler.js","sourceRoot":"","sources":["../../src/utils/exitHandler.ts"],"names":[],"mappings":";;;;;AAAA,oDAA4B;AAC5B,+BAA+B;AAC/B,2BAA6C;AAC7C,sDAA8B;AAC9B,4CAA4C;AAK5C,SAAS,QAAQ;IACf,MAAM,WAAW,GAAG,IAAA,cAAO,EAAC,wBAAY,EAAE,KAAK,CAAC,CAAC;IACjD,IAAI,IAAA,eAAU,EAAC,WAAW,CAAC,IAAI,IAAA,gBAAW,EAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnE,gBAAM,CAAC,IAAI,CAAC,GAAG,WAAW,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QAC5D,gBAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACrC,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,SAA2B;IAC9C,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC7B,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC;QAE3B,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,SAA2B,EAAE,MAAkB,EAAE,KAAc;IACnF,gBAAM,CAAC,KAAK,CAAC,GAAG,MAAM,eAAe,EAAE,KAAK,CAAC,CAAC;IAE9C,WAAW,CAAC,SAAS,CAAC,CAAC;IAEvB,QAAQ,EAAE,CAAC;IAEX,2FAA2F;IAC3F,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO;IAE9B,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,KAAK,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,gBAAgB,CAAC,SAA2B;IACnD,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IAEvB,QAAQ,EAAE,CAAC;IAEX,mCAAmC;IACnC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IAEhE,uBAAuB;IACvB,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IAEpE,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IACpE,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IAEtE,oDAAoD;IACpD,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IAEtE,6BAA6B;IAC7B,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED,kBAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"exitHandler.js","sourceRoot":"","sources":["../../src/utils/exitHandler.ts"],"names":[],"mappings":";;;;;AAAA,oDAA4B;AAC5B,+BAA+B;AAC/B,2BAA6C;AAC7C,sDAA8B;AAC9B,4CAA4C;AAK5C,SAAS,QAAQ;IACf,MAAM,WAAW,GAAG,IAAA,cAAO,EAAC,wBAAY,EAAE,KAAK,CAAC,CAAC;IACjD,IAAI,IAAA,eAAU,EAAC,WAAW,CAAC,IAAI,IAAA,gBAAW,EAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnE,gBAAM,CAAC,IAAI,CAAC,GAAG,WAAW,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QAC5D,gBAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACrC,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,SAA2B;IAC9C,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC7B,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC;QAE3B,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,SAA2B,EAAE,MAAkB,EAAE,KAAc;IACnF,gBAAM,CAAC,KAAK,CAAC,GAAG,MAAM,eAAe,EAAE,KAAK,CAAC,CAAC;IAC9C,mGAAmG;IACnG,gBAAM,CAAC,KAAK,EAAE,CAAC;IAEf,WAAW,CAAC,SAAS,CAAC,CAAC;IAEvB,QAAQ,EAAE,CAAC;IAEX,2FAA2F;IAC3F,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO;IAE9B,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,KAAK,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,gBAAgB,CAAC,SAA2B;IACnD,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IAEvB,QAAQ,EAAE,CAAC;IAEX,mCAAmC;IACnC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IAEhE,uBAAuB;IACvB,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IAEpE,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IACpE,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IAEtE,oDAAoD;IACpD,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IAEtE,6BAA6B;IAC7B,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED,kBAAe,gBAAgB,CAAC"}
@@ -1,2 +1,3 @@
1
+ /** the local time as `YYYY-MM-DD HH:mm:ss.SS`, with hundredths of a second */
1
2
  declare const getDate: () => string;
2
3
  export default getDate;
@@ -1,9 +1,19 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const moment_1 = __importDefault(require("moment"));
7
- const getDate = () => (0, moment_1.default)().format('YYYY-MM-DD HH:mm:ss.SS');
3
+ const pad = (value, length = 2) => String(value).padStart(length, '0');
4
+ /** the date and time down to the second, kept for as long as the second lasts: it is the same for all the lines that are logged in it */
5
+ let cachedSecond = -1;
6
+ let cachedPrefix = '';
7
+ /** the local time as `YYYY-MM-DD HH:mm:ss.SS`, with hundredths of a second */
8
+ const getDate = () => {
9
+ const now = Date.now();
10
+ const second = Math.floor(now / 1000);
11
+ if (second !== cachedSecond) {
12
+ const date = new Date(now);
13
+ cachedSecond = second;
14
+ cachedPrefix = `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
15
+ }
16
+ return `${cachedPrefix}.${pad(Math.floor((now % 1000) / 10))}`;
17
+ };
8
18
  exports.default = getDate;
9
19
  //# sourceMappingURL=getDate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getDate.js","sourceRoot":"","sources":["../../src/utils/getDate.ts"],"names":[],"mappings":";;;;;AAAA,oDAA4B;AAE5B,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,IAAA,gBAAM,GAAE,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC;AAEhE,kBAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"getDate.js","sourceRoot":"","sources":["../../src/utils/getDate.ts"],"names":[],"mappings":";;AAAA,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAE/E,yIAAyI;AACzI,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC;AACtB,IAAI,YAAY,GAAG,EAAE,CAAC;AAEtB,8EAA8E;AAC9E,MAAM,OAAO,GAAG,GAAG,EAAE;IACnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IAEtC,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3B,YAAY,GAAG,MAAM,CAAC;QACtB,YAAY,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,GAAG,CACtJ,IAAI,CAAC,UAAU,EAAE,CAClB,EAAE,CAAC;IACN,CAAC;IAED,OAAO,GAAG,YAAY,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;AACjE,CAAC,CAAC;AAEF,kBAAe,OAAO,CAAC"}
@@ -1,8 +1,13 @@
1
+ import type { LogLevels } from '../types';
2
+ /** Writes what is buffered, one write per file and one for the console. Safe to call at any time, also when nothing is waiting. */
3
+ declare function flush(): void;
1
4
  declare const logger: {
2
5
  system: (...args: unknown[]) => void;
3
6
  info: (...args: unknown[]) => void;
4
7
  success: (...args: unknown[]) => void;
5
8
  error: (...args: unknown[]) => void;
6
9
  warning: (...args: unknown[]) => void;
10
+ flush: typeof flush;
11
+ isEnabled: (level: keyof LogLevels) => boolean;
7
12
  };
8
13
  export default logger;
@@ -6,24 +6,91 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const moment_1 = __importDefault(require("moment"));
7
7
  const path_1 = require("path");
8
8
  const fs_1 = require("fs");
9
- const { logLevels, fileLogPath } = require(process.env.NODE_WEBSERVER_CONFIG || '../configuration.example');
9
+ const util_1 = require("util");
10
+ const { logLevels, fileLogPath, fileLogFlushInterval = 100 } = require(process.env
11
+ .NODE_WEBSERVER_CONFIG || '../configuration.example');
10
12
  const startedAt = (0, moment_1.default)();
13
+ /** a buffer that grows beyond this many characters is written right away */
14
+ const maxBufferSize = 64 * 1024;
11
15
  if (fileLogPath === undefined) {
12
16
  throw new Error('Please define fileLogPath in configuration.');
13
17
  }
14
18
  if (fileLogPath && !(0, fs_1.existsSync)(fileLogPath)) {
15
19
  (0, fs_1.mkdirSync)(fileLogPath, { recursive: true });
16
20
  }
21
+ /** the lines waiting to be written, per file */
22
+ const buffers = new Map();
23
+ let bufferSize = 0;
24
+ let flushTimer;
25
+ /**
26
+ * The lines for the console, which wait until the turn of the event loop is over and leave in one write. Every write is a system call on the thread that
27
+ * serves the requests, and a request logs two lines. Lines of other code that writes to the console directly can come out before them, by at most that turn.
28
+ */
29
+ let consoleLines = [];
30
+ let consoleFlushScheduled = false;
31
+ function flushConsole() {
32
+ consoleFlushScheduled = false;
33
+ if (consoleLines.length === 0)
34
+ return;
35
+ const text = consoleLines.join('\n');
36
+ consoleLines = [];
37
+ console.log(text);
38
+ }
39
+ function consoleLog(args) {
40
+ // formatted like console.log does it, with colors when the console is a terminal, as the lines are joined into a single string
41
+ consoleLines.push((0, util_1.formatWithOptions)({ colors: Boolean(process.stdout.isTTY) }, ...args));
42
+ if (!consoleFlushScheduled) {
43
+ consoleFlushScheduled = true;
44
+ setImmediate(flushConsole);
45
+ }
46
+ }
47
+ /** Writes what is buffered, one write per file and one for the console. Safe to call at any time, also when nothing is waiting. */
48
+ function flush() {
49
+ flushConsole();
50
+ clearTimeout(flushTimer);
51
+ flushTimer = undefined;
52
+ const pending = Array.from(buffers.entries());
53
+ buffers.clear();
54
+ bufferSize = 0;
55
+ pending.forEach(([file, lines]) => {
56
+ try {
57
+ (0, fs_1.appendFileSync)(file, lines.join(''), 'utf8');
58
+ }
59
+ catch (error) {
60
+ // a log that cannot be written must not take the server down, nor is it kept until the memory is full
61
+ console.error(`Could not write ${file}:`, error);
62
+ }
63
+ });
64
+ }
17
65
  function fileLog(level, args) {
18
- if (fileLogPath) {
19
- (0, fs_1.appendFileSync)((0, path_1.resolve)(fileLogPath, `./${startedAt.valueOf()}.${level}.log`), `${args.join(', ')}\n`, 'utf8');
66
+ if (!fileLogPath)
67
+ return;
68
+ const file = (0, path_1.resolve)(fileLogPath, `./${startedAt.valueOf()}.${level}.log`);
69
+ const line = `${args.join(', ')}\n`;
70
+ if (!fileLogFlushInterval) {
71
+ (0, fs_1.appendFileSync)(file, line, 'utf8');
72
+ return;
73
+ }
74
+ const lines = buffers.get(file) ?? [];
75
+ lines.push(line);
76
+ buffers.set(file, lines);
77
+ bufferSize += line.length;
78
+ if (bufferSize > maxBufferSize) {
79
+ flush();
80
+ }
81
+ else if (!flushTimer) {
82
+ // the timer must not keep the process alive
83
+ flushTimer = setTimeout(flush, fileLogFlushInterval).unref();
20
84
  }
21
85
  }
86
+ process.on('exit', flush);
87
+ /** whether lines of the level are logged, to spare building the lines that would be dropped. The levels do not change while the server runs. */
88
+ const isEnabled = (level) => !(logLevels && logLevels[level] === false);
22
89
  const createLog = (level) => (...args) => {
23
- if (logLevels && logLevels[level] === false)
90
+ if (!isEnabled(level))
24
91
  return;
25
92
  fileLog(level, args);
26
- return console.log(...args);
93
+ consoleLog(args);
27
94
  };
28
95
  const logger = {
29
96
  system: createLog('system'),
@@ -31,6 +98,8 @@ const logger = {
31
98
  success: createLog('success'),
32
99
  error: createLog('error'),
33
100
  warning: createLog('warning'),
101
+ flush,
102
+ isEnabled,
34
103
  };
35
104
  exports.default = logger;
36
105
  //# sourceMappingURL=logger.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":";;;;;AAAA,oDAA4B;AAC5B,+BAA+B;AAC/B,2BAA2D;AAG3D,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAqD,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,0BAA0B,CAAC,CAAC;AAE9J,MAAM,SAAS,GAAG,IAAA,gBAAM,GAAE,CAAC;AAE3B,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;IAC9B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;AACjE,CAAC;AAED,IAAI,WAAW,IAAI,CAAC,IAAA,eAAU,EAAC,WAAW,CAAC,EAAE,CAAC;IAC5C,IAAA,cAAS,EAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,OAAO,CAAC,KAAsB,EAAE,IAAe;IACtD,IAAI,WAAW,EAAE,CAAC;QAChB,IAAA,mBAAc,EAAC,IAAA,cAAO,EAAC,WAAW,EAAE,KAAK,SAAS,CAAC,OAAO,EAAE,IAAI,KAAK,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChH,CAAC;AACH,CAAC;AAED,MAAM,SAAS,GACb,CAAC,KAAsB,EAAE,EAAE,CAC3B,CAAC,GAAG,IAAe,EAAE,EAAE;IACrB,IAAI,SAAS,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,KAAK;QAAE,OAAO;IACpD,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACrB,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;AAC9B,CAAC,CAAC;AAEJ,MAAM,MAAM,GAAG;IACb,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC;IAC3B,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC;IACvB,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC;IAC7B,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC;IACzB,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC;CAC9B,CAAC;AAEF,kBAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const vhost_1 = __importDefault(require("vhost"));
7
7
  const node_worker_express_1 = require("@koeroesi86/node-worker-express");
8
8
  const getURL_1 = __importDefault(require("./getURL"));
9
+ const compression_1 = __importDefault(require("../middlewares/compression"));
9
10
  const proxy_1 = __importDefault(require("../middlewares/proxy"));
10
11
  const lambda_1 = __importDefault(require("../middlewares/lambda"));
11
12
  const getDate_1 = __importDefault(require("./getDate"));
@@ -16,6 +17,7 @@ function getWorkerMiddleware(instance) {
16
17
  throw new Error(`options are required for worker server ${instance.hostname}.`);
17
18
  }
18
19
  return (0, node_worker_express_1.middleware)({
20
+ name: instance.hostname,
19
21
  ...options,
20
22
  onStdout(data) {
21
23
  logger_1.default.info(`[${(0, getDate_1.default)()}] ${data.toString().trim()}`);
@@ -45,17 +47,24 @@ function getMiddleware(instance) {
45
47
  next();
46
48
  };
47
49
  }
50
+ /** the handlers one after the other, like `use` on an app does */
51
+ const compose = (first, second) => (request, response, next) => first(request, response, (error) => (error ? next(error) : second(request, response, next)));
52
+ function getHandler(instance) {
53
+ const { compression } = instance;
54
+ const middleware = getMiddleware(instance);
55
+ return compression ? compose((0, compression_1.default)(compression === true ? {} : compression), middleware) : middleware;
56
+ }
48
57
  function setupVirtualHost(instance, httpApp, httpsApp, Configuration) {
49
58
  const { portHttp, portHttps } = Configuration;
50
59
  const { hostname, protocol } = instance;
51
60
  switch (protocol) {
52
61
  case 'http':
53
- httpApp.use((0, vhost_1.default)(hostname, getMiddleware(instance)));
62
+ httpApp.use((0, vhost_1.default)(hostname, getHandler(instance)));
54
63
  instance.url = (0, getURL_1.default)(protocol, hostname, portHttp);
55
64
  logger_1.default.system(`[${(0, getDate_1.default)()}] Server started for ${instance.url}`);
56
65
  break;
57
66
  case 'https':
58
- httpsApp.use((0, vhost_1.default)(hostname, getMiddleware(instance)));
67
+ httpsApp.use((0, vhost_1.default)(hostname, getHandler(instance)));
59
68
  instance.url = (0, getURL_1.default)(protocol, hostname, portHttps);
60
69
  logger_1.default.system(`[${(0, getDate_1.default)()}] Server started for ${instance.url}`);
61
70
  break;
@@ -1 +1 @@
1
- {"version":3,"file":"setupVirtualHosts.js","sourceRoot":"","sources":["../../src/utils/setupVirtualHosts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setupVirtualHosts.js","sourceRoot":"","sources":["../../src/utils/setupVirtualHosts.ts"],"names":[],"mappings":"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"}
@@ -8,9 +8,12 @@ const http_1 = __importDefault(require("http"));
8
8
  const https_1 = __importDefault(require("https"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const fs_1 = __importDefault(require("fs"));
11
+ const node_lambda_invoke_1 = require("@koeroesi86/node-lambda-invoke");
12
+ const node_worker_express_1 = require("@koeroesi86/node-worker-express");
11
13
  const configuration_example_1 = __importDefault(require("../configuration.example"));
12
14
  const accessLogs_1 = __importDefault(require("../middlewares/accessLogs"));
13
15
  const exitHandler_1 = __importDefault(require("./exitHandler"));
16
+ const configureServer_1 = __importDefault(require("./configureServer"));
14
17
  const setupSecureContexts_1 = __importDefault(require("./setupSecureContexts"));
15
18
  const setupStatsHandler_1 = __importDefault(require("./setupStatsHandler"));
16
19
  const setupVirtualHosts_1 = __importDefault(require("./setupVirtualHosts"));
@@ -50,6 +53,9 @@ const startServer = async (configuration) => {
50
53
  }
51
54
  },
52
55
  }, httpsApp);
56
+ (0, configureServer_1.default)(httpServer, 'http', hydratedConfiguration);
57
+ (0, configureServer_1.default)(httpsServer, 'https', hydratedConfiguration);
58
+ (0, node_worker_express_1.registerMetricsSource)('lambdas', node_lambda_invoke_1.getLambdaStats);
53
59
  await listen(httpServer, hydratedConfiguration.portHttp);
54
60
  await listen(httpsServer, hydratedConfiguration.portHttps);
55
61
  (0, exitHandler_1.default)(instances);
@@ -1 +1 @@
1
- {"version":3,"file":"startServer.js","sourceRoot":"","sources":["../../src/utils/startServer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"startServer.js","sourceRoot":"","sources":["../../src/utils/startServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ const { createHash } = require('crypto');
2
+
3
+ const defaultRounds = 8000;
4
+ const maxRounds = 500000;
5
+
6
+ // a worker that keeps its process busy, to see how requests are spread over the workers: it hashes the digest of the previous round
7
+ module.exports = (event, callback) => {
8
+ const requested = Number(event.queryStringParameters.rounds);
9
+ const rounds = Math.min(Number.isInteger(requested) && requested > 0 ? requested : defaultRounds, maxRounds);
10
+ let digest = Buffer.from('node-webserver');
11
+
12
+ for (let round = 0; round < rounds; round += 1) {
13
+ digest = createHash('sha256').update(digest).digest();
14
+ }
15
+
16
+ callback({
17
+ statusCode: 200,
18
+ headers: { 'Content-Type': 'application/json' },
19
+ body: JSON.stringify({ rounds, digest: digest.toString('hex') }),
20
+ isBase64Encoded: false,
21
+ });
22
+ };
@@ -1,9 +1,16 @@
1
- module.exports = (event, callback) => {
1
+ const { buffer } = require('stream/consumers');
2
+
3
+ module.exports = async (event, callback) => {
4
+ // the body of the request is a stream, read it before answering
5
+ const body = await buffer(event.bodyStream);
6
+
2
7
  callback({
3
8
  statusCode: 200,
4
9
  headers: {
5
10
  'Content-Type': 'text/html',
6
11
  'Cache-Control': 'public, max-age=0',
12
+ // lets clients verify that the request body arrived
13
+ 'X-Request-Body-Length': String(body.length),
7
14
  },
8
15
  body: `
9
16
  <html>
@@ -0,0 +1,18 @@
1
+ // a health and a metrics endpoint: the worker asks the server for its metrics, as it lives in a process of its own
2
+ // /health answers 200, or 503 when requests wait for workers that cannot be started, /metrics gives everything the server knows
3
+ module.exports = async (event, callback) => {
4
+ const metrics = await event.getMetrics();
5
+ const json = (statusCode, body) => callback({ statusCode, headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' }, body: JSON.stringify(body), isBase64Encoded: false });
6
+
7
+ if (event.path === '/metrics') {
8
+ return json(200, metrics);
9
+ }
10
+
11
+ if (event.path === '/health') {
12
+ const waiting = Object.values(metrics.sources).reduce((total, source) => total + (source && typeof source.waiting === 'number' ? source.waiting : 0), 0);
13
+
14
+ return waiting > 0 ? json(503, { status: 'busy', waiting }) : json(200, { status: 'ok', uptimeSeconds: metrics.uptimeSeconds });
15
+ }
16
+
17
+ return json(404, { error: `${event.path} does not exist` });
18
+ };
@@ -0,0 +1,17 @@
1
+ const streamResponse = require('@koeroesi86/node-worker-express/dist/streamResponse');
2
+
3
+ const clamp = (value, fallback, max) => Math.min(Number.isInteger(value) && value > 0 ? value : fallback, max);
4
+
5
+ // a response that is generated while it is sent: `chunks` parts of `size` bytes, the bytes of the part with the number n all have the value n % 256
6
+ module.exports = async (event, callback) => {
7
+ const chunks = clamp(Number(event.queryStringParameters.chunks), 8, 4096);
8
+ const size = clamp(Number(event.queryStringParameters.size), 4096, 1024 * 1024);
9
+
10
+ async function* generate() {
11
+ for (let index = 0; index < chunks; index += 1) {
12
+ yield Buffer.alloc(size, index % 256);
13
+ }
14
+ }
15
+
16
+ await streamResponse(callback, { headers: { 'Content-Type': 'application/octet-stream', 'X-Chunks': String(chunks) } }, generate());
17
+ };
@@ -0,0 +1,20 @@
1
+ const crypto = require('crypto');
2
+
3
+ // takes the body of a request as a stream, it never holds more than a few parts in memory, whatever the size of the upload
4
+ // answers with the size and the sha256 of what it received
5
+ module.exports = async (event, callback) => {
6
+ const hash = crypto.createHash('sha256');
7
+ let size = 0;
8
+
9
+ for await (const chunk of event.bodyStream) {
10
+ hash.update(chunk);
11
+ size += chunk.length;
12
+ }
13
+
14
+ callback({
15
+ statusCode: 200,
16
+ headers: { 'Content-Type': 'application/json' },
17
+ body: JSON.stringify({ size, sha256: hash.digest('hex') }),
18
+ isBase64Encoded: false,
19
+ });
20
+ };
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "@koeroesi86/node-webserver",
3
- "version": "26.10.36916718511-master",
3
+ "version": "26.10.37633705232-master",
4
4
  "description": "A local Lambda implementation",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
7
7
  "files": [
8
8
  "dist",
9
+ "!dist/scripts/load-test-server.*",
10
+ "!dist/scripts/load-test-env.*",
11
+ "!dist/configuration.load-test.*",
9
12
  "examples",
10
13
  "logs/.gitkeep",
11
14
  "requests/.gitkeep",
@@ -26,8 +29,8 @@
26
29
  },
27
30
  "license": "MIT",
28
31
  "dependencies": {
29
- "@koeroesi86/node-lambda-invoke": "26.10.36916718511-master",
30
- "@koeroesi86/node-worker-express": "26.10.36916718511-master",
32
+ "@koeroesi86/node-lambda-invoke": "26.10.37633705232-master",
33
+ "@koeroesi86/node-worker-express": "26.10.37633705232-master",
31
34
  "@types/express": "^4.17.21",
32
35
  "express": "^4.17.3",
33
36
  "find-free-port": "^2.0.0",
@@ -50,10 +53,11 @@
50
53
  "ts-jest": "^29.0.5",
51
54
  "typescript": "^5.9.3"
52
55
  },
53
- "gitHead": "5761ac838f626fb2b35390b63d4130a9cd2d6197",
56
+ "gitHead": "df44146d25ab202ad04461024c6f67930c0e7026",
54
57
  "scripts": {
55
58
  "build": "rimraf dist && tsc -p tsconfig.build.json",
56
59
  "test": "jest",
60
+ "start:load-test": "node dist/scripts/load-test-server.js",
57
61
  "start": "nodemon --watch src --ext ts --exec \"npm run build --silent && node dist/scripts/server.js\""
58
62
  }
59
63
  }