apitally 0.9.5 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +1 -2
  2. package/dist/common/client.cjs +398 -12
  3. package/dist/common/client.cjs.map +1 -1
  4. package/dist/common/client.d.cts +8 -1
  5. package/dist/common/client.d.ts +8 -1
  6. package/dist/common/client.js +394 -8
  7. package/dist/common/client.js.map +1 -1
  8. package/dist/common/consumerRegistry.d.cts +4 -0
  9. package/dist/common/consumerRegistry.d.ts +4 -0
  10. package/dist/common/requestCounter.d.cts +4 -0
  11. package/dist/common/requestCounter.d.ts +4 -0
  12. package/dist/common/requestLogger.cjs +419 -0
  13. package/dist/common/requestLogger.cjs.map +1 -0
  14. package/dist/common/requestLogger.d.cts +63 -0
  15. package/dist/common/requestLogger.d.ts +63 -0
  16. package/dist/common/requestLogger.js +395 -0
  17. package/dist/common/requestLogger.js.map +1 -0
  18. package/dist/common/serverErrorCounter.d.cts +4 -0
  19. package/dist/common/serverErrorCounter.d.ts +4 -0
  20. package/dist/common/tempGzipFile.cjs +93 -0
  21. package/dist/common/tempGzipFile.cjs.map +1 -0
  22. package/dist/common/tempGzipFile.d.cts +17 -0
  23. package/dist/common/tempGzipFile.d.ts +17 -0
  24. package/dist/common/tempGzipFile.js +74 -0
  25. package/dist/common/tempGzipFile.js.map +1 -0
  26. package/dist/common/types.cjs.map +1 -1
  27. package/dist/common/types.d.cts +5 -0
  28. package/dist/common/types.d.ts +5 -0
  29. package/dist/common/validationErrorCounter.d.cts +4 -0
  30. package/dist/common/validationErrorCounter.d.ts +4 -0
  31. package/dist/express/index.cjs +500 -34
  32. package/dist/express/index.cjs.map +1 -1
  33. package/dist/express/index.d.cts +4 -0
  34. package/dist/express/index.d.ts +4 -0
  35. package/dist/express/index.js +496 -30
  36. package/dist/express/index.js.map +1 -1
  37. package/dist/express/middleware.cjs +500 -34
  38. package/dist/express/middleware.cjs.map +1 -1
  39. package/dist/express/middleware.d.cts +4 -0
  40. package/dist/express/middleware.d.ts +4 -0
  41. package/dist/express/middleware.js +496 -30
  42. package/dist/express/middleware.js.map +1 -1
  43. package/dist/fastify/index.cjs +491 -27
  44. package/dist/fastify/index.cjs.map +1 -1
  45. package/dist/fastify/index.d.cts +4 -0
  46. package/dist/fastify/index.d.ts +4 -0
  47. package/dist/fastify/index.js +487 -23
  48. package/dist/fastify/index.js.map +1 -1
  49. package/dist/fastify/plugin.cjs +491 -27
  50. package/dist/fastify/plugin.cjs.map +1 -1
  51. package/dist/fastify/plugin.d.cts +4 -0
  52. package/dist/fastify/plugin.d.ts +4 -0
  53. package/dist/fastify/plugin.js +487 -23
  54. package/dist/fastify/plugin.js.map +1 -1
  55. package/dist/hono/index.cjs +460 -15
  56. package/dist/hono/index.cjs.map +1 -1
  57. package/dist/hono/index.d.cts +4 -0
  58. package/dist/hono/index.d.ts +4 -0
  59. package/dist/hono/index.js +456 -11
  60. package/dist/hono/index.js.map +1 -1
  61. package/dist/hono/middleware.cjs +460 -15
  62. package/dist/hono/middleware.cjs.map +1 -1
  63. package/dist/hono/middleware.d.cts +4 -0
  64. package/dist/hono/middleware.d.ts +4 -0
  65. package/dist/hono/middleware.js +456 -11
  66. package/dist/hono/middleware.js.map +1 -1
  67. package/dist/koa/index.cjs +475 -15
  68. package/dist/koa/index.cjs.map +1 -1
  69. package/dist/koa/index.d.cts +4 -0
  70. package/dist/koa/index.d.ts +4 -0
  71. package/dist/koa/index.js +471 -11
  72. package/dist/koa/index.js.map +1 -1
  73. package/dist/koa/middleware.cjs +475 -15
  74. package/dist/koa/middleware.cjs.map +1 -1
  75. package/dist/koa/middleware.d.cts +4 -0
  76. package/dist/koa/middleware.d.ts +4 -0
  77. package/dist/koa/middleware.js +471 -11
  78. package/dist/koa/middleware.js.map +1 -1
  79. package/dist/nestjs/index.cjs +536 -41
  80. package/dist/nestjs/index.cjs.map +1 -1
  81. package/dist/nestjs/index.d.cts +10 -2
  82. package/dist/nestjs/index.d.ts +10 -2
  83. package/dist/nestjs/index.js +534 -37
  84. package/dist/nestjs/index.js.map +1 -1
  85. package/package.json +8 -2
@@ -0,0 +1,395 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/common/requestLogger.ts
5
+ import { Buffer as Buffer3 } from "buffer";
6
+ import { randomUUID as randomUUID2 } from "crypto";
7
+ import { unlinkSync as unlinkSync2, writeFileSync } from "fs";
8
+ import { tmpdir as tmpdir2 } from "os";
9
+ import { join as join2 } from "path";
10
+
11
+ // src/common/tempGzipFile.ts
12
+ import { Buffer as Buffer2 } from "buffer";
13
+ import { randomUUID } from "crypto";
14
+ import { createWriteStream, readFile, unlinkSync } from "fs";
15
+ import { tmpdir } from "os";
16
+ import { join } from "path";
17
+ import { createGzip } from "zlib";
18
+ var _TempGzipFile = class _TempGzipFile {
19
+ uuid;
20
+ filePath;
21
+ gzip;
22
+ writeStream;
23
+ readyPromise;
24
+ constructor() {
25
+ this.uuid = randomUUID();
26
+ this.filePath = join(tmpdir(), `apitally-${this.uuid}.gz`);
27
+ this.writeStream = createWriteStream(this.filePath);
28
+ this.readyPromise = new Promise((resolve, reject) => {
29
+ this.writeStream.once("ready", resolve);
30
+ this.writeStream.once("error", reject);
31
+ });
32
+ this.gzip = createGzip();
33
+ this.gzip.pipe(this.writeStream);
34
+ }
35
+ get size() {
36
+ return this.writeStream.bytesWritten;
37
+ }
38
+ async writeLine(data) {
39
+ await this.readyPromise;
40
+ return new Promise((resolve, reject) => {
41
+ this.gzip.write(Buffer2.concat([
42
+ data,
43
+ Buffer2.from("\n")
44
+ ]), (error) => {
45
+ if (error) {
46
+ reject(error);
47
+ } else {
48
+ resolve();
49
+ }
50
+ });
51
+ });
52
+ }
53
+ async getContent() {
54
+ return new Promise((resolve, reject) => {
55
+ readFile(this.filePath, (error, data) => {
56
+ if (error) {
57
+ reject(error);
58
+ } else {
59
+ resolve(data);
60
+ }
61
+ });
62
+ });
63
+ }
64
+ async close() {
65
+ return new Promise((resolve) => {
66
+ this.gzip.end(() => {
67
+ resolve();
68
+ });
69
+ });
70
+ }
71
+ async delete() {
72
+ await this.close();
73
+ unlinkSync(this.filePath);
74
+ }
75
+ };
76
+ __name(_TempGzipFile, "TempGzipFile");
77
+ var TempGzipFile = _TempGzipFile;
78
+
79
+ // src/common/requestLogger.ts
80
+ var MAX_BODY_SIZE = 5e4;
81
+ var MAX_FILE_SIZE = 1e6;
82
+ var MAX_FILES = 50;
83
+ var MAX_PENDING_WRITES = 100;
84
+ var BODY_TOO_LARGE = Buffer3.from("<body too large>");
85
+ var BODY_MASKED = Buffer3.from("<masked>");
86
+ var MASKED = "******";
87
+ var ALLOWED_CONTENT_TYPES = [
88
+ "application/json",
89
+ "text/plain"
90
+ ];
91
+ var EXCLUDE_PATH_PATTERNS = [
92
+ /\/_?healthz?$/,
93
+ /\/_?health[_-]?checks?$/,
94
+ /\/_?heart[_-]?beats?$/,
95
+ /\/ping$/,
96
+ /\/ready$/,
97
+ /\/live$/
98
+ ];
99
+ var MASK_QUERY_PARAM_PATTERNS = [
100
+ /auth/i,
101
+ /api-?key/i,
102
+ /secret/i,
103
+ /token/i,
104
+ /password/i,
105
+ /pwd/i
106
+ ];
107
+ var MASK_HEADER_PATTERNS = [
108
+ /auth/i,
109
+ /api-?key/i,
110
+ /secret/i,
111
+ /token/i,
112
+ /cookie/i
113
+ ];
114
+ var DEFAULT_CONFIG = {
115
+ enabled: false,
116
+ logQueryParams: true,
117
+ logRequestHeaders: false,
118
+ logRequestBody: false,
119
+ logResponseHeaders: true,
120
+ logResponseBody: false,
121
+ maskQueryParams: [],
122
+ maskHeaders: [],
123
+ excludePaths: []
124
+ };
125
+ var _RequestLogger = class _RequestLogger {
126
+ config;
127
+ enabled;
128
+ suspendUntil = null;
129
+ pendingWrites = [];
130
+ currentFile = null;
131
+ files = [];
132
+ maintainIntervalId;
133
+ constructor(config) {
134
+ this.config = {
135
+ ...DEFAULT_CONFIG,
136
+ ...config
137
+ };
138
+ this.enabled = this.config.enabled && checkWritableFs();
139
+ if (this.enabled) {
140
+ this.maintainIntervalId = setInterval(() => {
141
+ this.maintain();
142
+ }, 1e3);
143
+ }
144
+ }
145
+ shouldExcludePath(urlPath) {
146
+ const patterns = [
147
+ ...this.config.excludePaths,
148
+ ...EXCLUDE_PATH_PATTERNS
149
+ ];
150
+ return matchPatterns(urlPath, patterns);
151
+ }
152
+ shouldMaskQueryParam(name) {
153
+ const patterns = [
154
+ ...this.config.maskQueryParams,
155
+ ...MASK_QUERY_PARAM_PATTERNS
156
+ ];
157
+ return matchPatterns(name, patterns);
158
+ }
159
+ shouldMaskHeader(name) {
160
+ const patterns = [
161
+ ...this.config.maskHeaders,
162
+ ...MASK_HEADER_PATTERNS
163
+ ];
164
+ return matchPatterns(name, patterns);
165
+ }
166
+ hasSupportedContentType(headers) {
167
+ var _a;
168
+ const contentType = (_a = headers.find(([k]) => k.toLowerCase() === "content-type")) == null ? void 0 : _a[1];
169
+ return contentType !== void 0 && ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t));
170
+ }
171
+ maskQueryParams(search) {
172
+ const params = new URLSearchParams(search);
173
+ for (const [key] of params) {
174
+ if (this.shouldMaskQueryParam(key)) {
175
+ params.set(key, MASKED);
176
+ }
177
+ }
178
+ return params.toString();
179
+ }
180
+ maskHeaders(headers) {
181
+ return headers.map(([k, v]) => [
182
+ k,
183
+ this.shouldMaskHeader(k) ? MASKED : v
184
+ ]);
185
+ }
186
+ logRequest(request, response) {
187
+ var _a, _b;
188
+ if (!this.enabled || this.suspendUntil !== null) return;
189
+ const url = new URL(request.url);
190
+ const path = request.path ?? url.pathname;
191
+ if (this.shouldExcludePath(path) || (((_b = (_a = this.config).excludeCallback) == null ? void 0 : _b.call(_a, request, response)) ?? false)) {
192
+ return;
193
+ }
194
+ url.search = this.config.logQueryParams ? this.maskQueryParams(url.search) : "";
195
+ request.url = url.toString();
196
+ request.headers = this.config.logRequestHeaders ? this.maskHeaders(request.headers) : [];
197
+ response.headers = this.config.logResponseHeaders ? this.maskHeaders(response.headers) : [];
198
+ if (!this.config.logRequestBody || !this.hasSupportedContentType(request.headers)) {
199
+ request.body = void 0;
200
+ } else if (request.body) {
201
+ if (request.body.length > MAX_BODY_SIZE) {
202
+ request.body = BODY_TOO_LARGE;
203
+ } else if (this.config.maskRequestBodyCallback) {
204
+ try {
205
+ request.body = this.config.maskRequestBodyCallback(request) ?? BODY_MASKED;
206
+ if (request.body.length > MAX_BODY_SIZE) {
207
+ request.body = BODY_TOO_LARGE;
208
+ }
209
+ } catch {
210
+ request.body = void 0;
211
+ }
212
+ }
213
+ }
214
+ if (!this.config.logResponseBody || !this.hasSupportedContentType(response.headers)) {
215
+ response.body = void 0;
216
+ } else if (response.body) {
217
+ if (response.body.length > MAX_BODY_SIZE) {
218
+ response.body = BODY_TOO_LARGE;
219
+ } else if (this.config.maskResponseBodyCallback) {
220
+ try {
221
+ response.body = this.config.maskResponseBodyCallback(request, response) ?? BODY_MASKED;
222
+ if (response.body.length > MAX_BODY_SIZE) {
223
+ response.body = BODY_TOO_LARGE;
224
+ }
225
+ } catch {
226
+ response.body = void 0;
227
+ }
228
+ }
229
+ }
230
+ const item = {
231
+ uuid: randomUUID2(),
232
+ request: skipEmptyValues(request),
233
+ response: skipEmptyValues(response)
234
+ };
235
+ [
236
+ item.request.body,
237
+ item.response.body
238
+ ].forEach((body) => {
239
+ if (body) {
240
+ body.toJSON = function() {
241
+ return this.toString("base64");
242
+ };
243
+ }
244
+ });
245
+ this.pendingWrites.push(JSON.stringify(item));
246
+ if (this.pendingWrites.length > MAX_PENDING_WRITES) {
247
+ this.pendingWrites.shift();
248
+ }
249
+ }
250
+ async writeToFile() {
251
+ if (!this.enabled || this.pendingWrites.length === 0) {
252
+ return;
253
+ }
254
+ if (!this.currentFile) {
255
+ this.currentFile = new TempGzipFile();
256
+ }
257
+ while (this.pendingWrites.length > 0) {
258
+ const item = this.pendingWrites.shift();
259
+ if (item) {
260
+ await this.currentFile.writeLine(Buffer3.from(item));
261
+ }
262
+ }
263
+ }
264
+ getFile() {
265
+ return this.files.shift();
266
+ }
267
+ retryFileLater(file) {
268
+ this.files.unshift(file);
269
+ }
270
+ async rotateFile() {
271
+ if (this.currentFile) {
272
+ await this.currentFile.close();
273
+ this.files.push(this.currentFile);
274
+ this.currentFile = null;
275
+ }
276
+ }
277
+ async maintain() {
278
+ await this.writeToFile();
279
+ if (this.currentFile && this.currentFile.size > MAX_FILE_SIZE) {
280
+ await this.rotateFile();
281
+ }
282
+ while (this.files.length > MAX_FILES) {
283
+ const file = this.files.shift();
284
+ file == null ? void 0 : file.delete();
285
+ }
286
+ if (this.suspendUntil !== null && this.suspendUntil < Date.now()) {
287
+ this.suspendUntil = null;
288
+ }
289
+ }
290
+ async clear() {
291
+ this.pendingWrites = [];
292
+ await this.rotateFile();
293
+ this.files.forEach((file) => {
294
+ file.delete();
295
+ });
296
+ this.files = [];
297
+ }
298
+ async close() {
299
+ this.enabled = false;
300
+ await this.clear();
301
+ if (this.maintainIntervalId) {
302
+ clearInterval(this.maintainIntervalId);
303
+ }
304
+ }
305
+ };
306
+ __name(_RequestLogger, "RequestLogger");
307
+ var RequestLogger = _RequestLogger;
308
+ function convertHeaders(headers) {
309
+ if (headers instanceof Headers) {
310
+ return Array.from(headers.entries());
311
+ }
312
+ return Object.entries(headers).flatMap(([key, value]) => {
313
+ if (value === void 0) {
314
+ return [];
315
+ }
316
+ if (Array.isArray(value)) {
317
+ return value.map((v) => [
318
+ key,
319
+ v
320
+ ]);
321
+ }
322
+ return [
323
+ [
324
+ key,
325
+ value.toString()
326
+ ]
327
+ ];
328
+ });
329
+ }
330
+ __name(convertHeaders, "convertHeaders");
331
+ function convertBody(body, contentType) {
332
+ if (!body || !contentType) {
333
+ return;
334
+ }
335
+ try {
336
+ if (contentType.startsWith("application/json")) {
337
+ if (isValidJsonString(body)) {
338
+ return Buffer3.from(body);
339
+ } else {
340
+ return Buffer3.from(JSON.stringify(body));
341
+ }
342
+ }
343
+ if (contentType.startsWith("text/") && typeof body === "string") {
344
+ return Buffer3.from(body);
345
+ }
346
+ } catch (error) {
347
+ return;
348
+ }
349
+ }
350
+ __name(convertBody, "convertBody");
351
+ function isValidJsonString(body) {
352
+ if (typeof body !== "string") {
353
+ return false;
354
+ }
355
+ try {
356
+ JSON.parse(body);
357
+ return true;
358
+ } catch {
359
+ return false;
360
+ }
361
+ }
362
+ __name(isValidJsonString, "isValidJsonString");
363
+ function matchPatterns(value, patterns) {
364
+ return patterns.some((pattern) => {
365
+ return pattern.test(value);
366
+ });
367
+ }
368
+ __name(matchPatterns, "matchPatterns");
369
+ function skipEmptyValues(data) {
370
+ return Object.fromEntries(Object.entries(data).filter(([_, v]) => {
371
+ if (v == null || Number.isNaN(v)) return false;
372
+ if (Array.isArray(v) || Buffer3.isBuffer(v) || typeof v === "string") {
373
+ return v.length > 0;
374
+ }
375
+ return true;
376
+ }));
377
+ }
378
+ __name(skipEmptyValues, "skipEmptyValues");
379
+ function checkWritableFs() {
380
+ try {
381
+ const testPath = join2(tmpdir2(), `apitally-${randomUUID2()}`);
382
+ writeFileSync(testPath, "test");
383
+ unlinkSync2(testPath);
384
+ return true;
385
+ } catch (error) {
386
+ return false;
387
+ }
388
+ }
389
+ __name(checkWritableFs, "checkWritableFs");
390
+ export {
391
+ convertBody,
392
+ convertHeaders,
393
+ RequestLogger as default
394
+ };
395
+ //# sourceMappingURL=requestLogger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/common/requestLogger.ts","../../src/common/tempGzipFile.ts"],"sourcesContent":["import { Buffer } from \"buffer\";\nimport { randomUUID } from \"crypto\";\nimport { unlinkSync, writeFileSync } from \"fs\";\nimport { IncomingHttpHeaders, OutgoingHttpHeaders } from \"http\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\n\nimport TempGzipFile from \"./tempGzipFile.js\";\n\nconst MAX_BODY_SIZE = 50_000; // 50 KB (uncompressed)\nconst MAX_FILE_SIZE = 1_000_000; // 1 MB (compressed)\nconst MAX_FILES = 50;\nconst MAX_PENDING_WRITES = 100;\nconst BODY_TOO_LARGE = Buffer.from(\"<body too large>\");\nconst BODY_MASKED = Buffer.from(\"<masked>\");\nconst MASKED = \"******\";\nconst ALLOWED_CONTENT_TYPES = [\"application/json\", \"text/plain\"];\nconst EXCLUDE_PATH_PATTERNS = [\n /\\/_?healthz?$/,\n /\\/_?health[_-]?checks?$/,\n /\\/_?heart[_-]?beats?$/,\n /\\/ping$/,\n /\\/ready$/,\n /\\/live$/,\n];\nconst MASK_QUERY_PARAM_PATTERNS = [\n /auth/i,\n /api-?key/i,\n /secret/i,\n /token/i,\n /password/i,\n /pwd/i,\n];\nconst MASK_HEADER_PATTERNS = [\n /auth/i,\n /api-?key/i,\n /secret/i,\n /token/i,\n /cookie/i,\n];\n\nexport type Request = {\n timestamp: number;\n method: string;\n path?: string;\n url: string;\n headers: [string, string][];\n size?: number;\n consumer?: string;\n body?: Buffer;\n};\n\nexport type Response = {\n statusCode: number;\n responseTime: number;\n headers: [string, string][];\n size?: number;\n body?: Buffer;\n};\n\nexport type RequestLoggingConfig = {\n enabled: boolean;\n logQueryParams: boolean;\n logRequestHeaders: boolean;\n logRequestBody: boolean;\n logResponseHeaders: boolean;\n logResponseBody: boolean;\n maskQueryParams: RegExp[];\n maskHeaders: RegExp[];\n maskRequestBodyCallback?: (request: Request) => Buffer | null | undefined;\n maskResponseBodyCallback?: (\n request: Request,\n response: Response,\n ) => Buffer | null | undefined;\n excludePaths: RegExp[];\n excludeCallback?: (request: Request, response: Response) => boolean;\n};\n\nconst DEFAULT_CONFIG: RequestLoggingConfig = {\n enabled: false,\n logQueryParams: true,\n logRequestHeaders: false,\n logRequestBody: false,\n logResponseHeaders: true,\n logResponseBody: false,\n maskQueryParams: [],\n maskHeaders: [],\n excludePaths: [],\n};\n\nexport default class RequestLogger {\n public config: RequestLoggingConfig;\n public enabled: boolean;\n public suspendUntil: number | null = null;\n private pendingWrites: string[] = [];\n private currentFile: TempGzipFile | null = null;\n private files: TempGzipFile[] = [];\n private maintainIntervalId?: NodeJS.Timeout;\n\n constructor(config?: Partial<RequestLoggingConfig>) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.enabled = this.config.enabled && checkWritableFs();\n\n if (this.enabled) {\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 1000);\n }\n }\n\n private shouldExcludePath(urlPath: string) {\n const patterns = [...this.config.excludePaths, ...EXCLUDE_PATH_PATTERNS];\n return matchPatterns(urlPath, patterns);\n }\n\n private shouldMaskQueryParam(name: string) {\n const patterns = [\n ...this.config.maskQueryParams,\n ...MASK_QUERY_PARAM_PATTERNS,\n ];\n return matchPatterns(name, patterns);\n }\n\n private shouldMaskHeader(name: string) {\n const patterns = [...this.config.maskHeaders, ...MASK_HEADER_PATTERNS];\n return matchPatterns(name, patterns);\n }\n\n private hasSupportedContentType(headers: [string, string][]) {\n const contentType = headers.find(\n ([k]) => k.toLowerCase() === \"content-type\",\n )?.[1];\n return (\n contentType !== undefined &&\n ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t))\n );\n }\n\n private maskQueryParams(search: string) {\n const params = new URLSearchParams(search);\n for (const [key] of params) {\n if (this.shouldMaskQueryParam(key)) {\n params.set(key, MASKED);\n }\n }\n return params.toString();\n }\n\n private maskHeaders(headers: [string, string][]): [string, string][] {\n return headers.map(([k, v]) => [k, this.shouldMaskHeader(k) ? MASKED : v]);\n }\n\n logRequest(request: Request, response: Response) {\n if (!this.enabled || this.suspendUntil !== null) return;\n\n const url = new URL(request.url);\n const path = request.path ?? url.pathname;\n\n if (\n this.shouldExcludePath(path) ||\n (this.config.excludeCallback?.(request, response) ?? false)\n ) {\n return;\n }\n\n // Process query params\n url.search = this.config.logQueryParams\n ? this.maskQueryParams(url.search)\n : \"\";\n request.url = url.toString();\n\n // Process headers\n request.headers = this.config.logRequestHeaders\n ? this.maskHeaders(request.headers)\n : [];\n response.headers = this.config.logResponseHeaders\n ? this.maskHeaders(response.headers)\n : [];\n\n // Process request body\n if (\n !this.config.logRequestBody ||\n !this.hasSupportedContentType(request.headers)\n ) {\n request.body = undefined;\n } else if (request.body) {\n if (request.body.length > MAX_BODY_SIZE) {\n request.body = BODY_TOO_LARGE;\n } else if (this.config.maskRequestBodyCallback) {\n try {\n request.body =\n this.config.maskRequestBodyCallback(request) ?? BODY_MASKED;\n if (request.body.length > MAX_BODY_SIZE) {\n request.body = BODY_TOO_LARGE;\n }\n } catch {\n request.body = undefined;\n }\n }\n }\n\n // Process response body\n if (\n !this.config.logResponseBody ||\n !this.hasSupportedContentType(response.headers)\n ) {\n response.body = undefined;\n } else if (response.body) {\n if (response.body.length > MAX_BODY_SIZE) {\n response.body = BODY_TOO_LARGE;\n } else if (this.config.maskResponseBodyCallback) {\n try {\n response.body =\n this.config.maskResponseBodyCallback(request, response) ??\n BODY_MASKED;\n if (response.body.length > MAX_BODY_SIZE) {\n response.body = BODY_TOO_LARGE;\n }\n } catch {\n response.body = undefined;\n }\n }\n }\n\n const item = {\n uuid: randomUUID(),\n request: skipEmptyValues(request),\n response: skipEmptyValues(response),\n };\n [item.request.body, item.response.body].forEach((body) => {\n if (body) {\n // @ts-expect-error Different return type\n body.toJSON = function () {\n return this.toString(\"base64\");\n };\n }\n });\n this.pendingWrites.push(JSON.stringify(item));\n\n if (this.pendingWrites.length > MAX_PENDING_WRITES) {\n this.pendingWrites.shift();\n }\n }\n\n async writeToFile() {\n if (!this.enabled || this.pendingWrites.length === 0) {\n return;\n }\n if (!this.currentFile) {\n this.currentFile = new TempGzipFile();\n }\n while (this.pendingWrites.length > 0) {\n const item = this.pendingWrites.shift();\n if (item) {\n await this.currentFile.writeLine(Buffer.from(item));\n }\n }\n }\n\n getFile() {\n return this.files.shift();\n }\n\n retryFileLater(file: TempGzipFile) {\n this.files.unshift(file);\n }\n\n async rotateFile() {\n if (this.currentFile) {\n await this.currentFile.close();\n this.files.push(this.currentFile);\n this.currentFile = null;\n }\n }\n\n async maintain() {\n await this.writeToFile();\n if (this.currentFile && this.currentFile.size > MAX_FILE_SIZE) {\n await this.rotateFile();\n }\n while (this.files.length > MAX_FILES) {\n const file = this.files.shift();\n file?.delete();\n }\n if (this.suspendUntil !== null && this.suspendUntil < Date.now()) {\n this.suspendUntil = null;\n }\n }\n\n async clear() {\n this.pendingWrites = [];\n await this.rotateFile();\n this.files.forEach((file) => {\n file.delete();\n });\n this.files = [];\n }\n\n async close() {\n this.enabled = false;\n await this.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n}\n\nexport function convertHeaders(\n headers:\n | Headers\n | IncomingHttpHeaders\n | OutgoingHttpHeaders\n | Record<string, string | string[] | number | undefined>,\n) {\n if (headers instanceof Headers) {\n return Array.from(headers.entries());\n }\n return Object.entries(headers).flatMap(([key, value]) => {\n if (value === undefined) {\n return [];\n }\n if (Array.isArray(value)) {\n return value.map((v) => [key, v]);\n }\n return [[key, value.toString()]];\n }) as [string, string][];\n}\n\nexport function convertBody(body: any, contentType?: string | null) {\n if (!body || !contentType) {\n return;\n }\n try {\n if (contentType.startsWith(\"application/json\")) {\n if (isValidJsonString(body)) {\n return Buffer.from(body);\n } else {\n return Buffer.from(JSON.stringify(body));\n }\n }\n if (contentType.startsWith(\"text/\") && typeof body === \"string\") {\n return Buffer.from(body);\n }\n } catch (error) {\n return;\n }\n}\n\nfunction isValidJsonString(body: any) {\n if (typeof body !== \"string\") {\n return false;\n }\n try {\n JSON.parse(body);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction matchPatterns(value: string, patterns: RegExp[]) {\n return patterns.some((pattern) => {\n return pattern.test(value);\n });\n}\n\nfunction skipEmptyValues<T extends Record<string, any>>(data: T) {\n return Object.fromEntries(\n Object.entries(data).filter(([_, v]) => {\n if (v == null || Number.isNaN(v)) return false;\n if (Array.isArray(v) || Buffer.isBuffer(v) || typeof v === \"string\") {\n return v.length > 0;\n }\n return true;\n }),\n ) as Partial<T>;\n}\n\nfunction checkWritableFs() {\n try {\n const testPath = join(tmpdir(), `apitally-${randomUUID()}`);\n writeFileSync(testPath, \"test\");\n unlinkSync(testPath);\n return true;\n } catch (error) {\n return false;\n }\n}\n","import { Buffer } from \"buffer\";\nimport { randomUUID } from \"crypto\";\nimport { createWriteStream, readFile, unlinkSync, WriteStream } from \"fs\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\n\nimport { createGzip, Gzip } from \"zlib\";\n\nexport default class TempGzipFile {\n public uuid: string;\n private filePath: string;\n private gzip: Gzip;\n private writeStream: WriteStream;\n private readyPromise: Promise<void>;\n\n constructor() {\n this.uuid = randomUUID();\n this.filePath = join(tmpdir(), `apitally-${this.uuid}.gz`);\n this.writeStream = createWriteStream(this.filePath);\n this.readyPromise = new Promise<void>((resolve, reject) => {\n this.writeStream.once(\"ready\", resolve);\n this.writeStream.once(\"error\", reject);\n });\n this.gzip = createGzip();\n this.gzip.pipe(this.writeStream);\n }\n\n get size() {\n return this.writeStream.bytesWritten;\n }\n\n async writeLine(data: Buffer) {\n await this.readyPromise;\n return new Promise<void>((resolve, reject) => {\n this.gzip.write(Buffer.concat([data, Buffer.from(\"\\n\")]), (error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n }\n\n async getContent() {\n return new Promise<Buffer>((resolve, reject) => {\n readFile(this.filePath, (error, data) => {\n if (error) {\n reject(error);\n } else {\n resolve(data);\n }\n });\n });\n }\n\n async close() {\n return new Promise<void>((resolve) => {\n this.gzip.end(() => {\n resolve();\n });\n });\n }\n\n async delete() {\n await this.close();\n unlinkSync(this.filePath);\n }\n}\n"],"mappings":"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","names":["Buffer","randomUUID","unlinkSync","writeFileSync","tmpdir","join","Buffer","randomUUID","createWriteStream","readFile","unlinkSync","tmpdir","join","createGzip","TempGzipFile","uuid","filePath","gzip","writeStream","readyPromise","constructor","randomUUID","join","tmpdir","createWriteStream","Promise","resolve","reject","once","createGzip","pipe","size","bytesWritten","writeLine","data","write","Buffer","concat","from","error","getContent","readFile","close","end","delete","unlinkSync","MAX_BODY_SIZE","MAX_FILE_SIZE","MAX_FILES","MAX_PENDING_WRITES","BODY_TOO_LARGE","Buffer","from","BODY_MASKED","MASKED","ALLOWED_CONTENT_TYPES","EXCLUDE_PATH_PATTERNS","MASK_QUERY_PARAM_PATTERNS","MASK_HEADER_PATTERNS","DEFAULT_CONFIG","enabled","logQueryParams","logRequestHeaders","logRequestBody","logResponseHeaders","logResponseBody","maskQueryParams","maskHeaders","excludePaths","RequestLogger","config","suspendUntil","pendingWrites","currentFile","files","maintainIntervalId","constructor","checkWritableFs","setInterval","maintain","shouldExcludePath","urlPath","patterns","matchPatterns","shouldMaskQueryParam","name","shouldMaskHeader","hasSupportedContentType","headers","contentType","find","k","toLowerCase","undefined","some","t","startsWith","search","params","URLSearchParams","key","set","toString","map","v","logRequest","request","response","url","URL","path","pathname","excludeCallback","body","length","maskRequestBodyCallback","maskResponseBodyCallback","item","uuid","randomUUID","skipEmptyValues","forEach","toJSON","push","JSON","stringify","shift","writeToFile","TempGzipFile","writeLine","getFile","retryFileLater","file","unshift","rotateFile","close","size","delete","Date","now","clear","clearInterval","convertHeaders","Headers","Array","entries","Object","flatMap","value","isArray","convertBody","isValidJsonString","error","parse","pattern","test","data","fromEntries","filter","_","Number","isNaN","isBuffer","testPath","join","tmpdir","writeFileSync","unlinkSync"]}
@@ -1,6 +1,10 @@
1
1
  import { ConsumerMethodPath, ServerError, ServerErrorsItem } from './types.cjs';
2
2
  import './logging.cjs';
3
3
  import 'winston';
4
+ import './requestLogger.cjs';
5
+ import 'buffer';
6
+ import 'http';
7
+ import './tempGzipFile.cjs';
4
8
 
5
9
  declare class ServerErrorCounter {
6
10
  private errorCounts;
@@ -1,6 +1,10 @@
1
1
  import { ConsumerMethodPath, ServerError, ServerErrorsItem } from './types.js';
2
2
  import './logging.js';
3
3
  import 'winston';
4
+ import './requestLogger.js';
5
+ import 'buffer';
6
+ import 'http';
7
+ import './tempGzipFile.js';
4
8
 
5
9
  declare class ServerErrorCounter {
6
10
  private errorCounts;
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/common/tempGzipFile.ts
22
+ var tempGzipFile_exports = {};
23
+ __export(tempGzipFile_exports, {
24
+ default: () => TempGzipFile
25
+ });
26
+ module.exports = __toCommonJS(tempGzipFile_exports);
27
+ var import_buffer = require("buffer");
28
+ var import_crypto = require("crypto");
29
+ var import_fs = require("fs");
30
+ var import_os = require("os");
31
+ var import_path = require("path");
32
+ var import_zlib = require("zlib");
33
+ var _TempGzipFile = class _TempGzipFile {
34
+ uuid;
35
+ filePath;
36
+ gzip;
37
+ writeStream;
38
+ readyPromise;
39
+ constructor() {
40
+ this.uuid = (0, import_crypto.randomUUID)();
41
+ this.filePath = (0, import_path.join)((0, import_os.tmpdir)(), `apitally-${this.uuid}.gz`);
42
+ this.writeStream = (0, import_fs.createWriteStream)(this.filePath);
43
+ this.readyPromise = new Promise((resolve, reject) => {
44
+ this.writeStream.once("ready", resolve);
45
+ this.writeStream.once("error", reject);
46
+ });
47
+ this.gzip = (0, import_zlib.createGzip)();
48
+ this.gzip.pipe(this.writeStream);
49
+ }
50
+ get size() {
51
+ return this.writeStream.bytesWritten;
52
+ }
53
+ async writeLine(data) {
54
+ await this.readyPromise;
55
+ return new Promise((resolve, reject) => {
56
+ this.gzip.write(import_buffer.Buffer.concat([
57
+ data,
58
+ import_buffer.Buffer.from("\n")
59
+ ]), (error) => {
60
+ if (error) {
61
+ reject(error);
62
+ } else {
63
+ resolve();
64
+ }
65
+ });
66
+ });
67
+ }
68
+ async getContent() {
69
+ return new Promise((resolve, reject) => {
70
+ (0, import_fs.readFile)(this.filePath, (error, data) => {
71
+ if (error) {
72
+ reject(error);
73
+ } else {
74
+ resolve(data);
75
+ }
76
+ });
77
+ });
78
+ }
79
+ async close() {
80
+ return new Promise((resolve) => {
81
+ this.gzip.end(() => {
82
+ resolve();
83
+ });
84
+ });
85
+ }
86
+ async delete() {
87
+ await this.close();
88
+ (0, import_fs.unlinkSync)(this.filePath);
89
+ }
90
+ };
91
+ __name(_TempGzipFile, "TempGzipFile");
92
+ var TempGzipFile = _TempGzipFile;
93
+ //# sourceMappingURL=tempGzipFile.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/common/tempGzipFile.ts"],"sourcesContent":["import { Buffer } from \"buffer\";\nimport { randomUUID } from \"crypto\";\nimport { createWriteStream, readFile, unlinkSync, WriteStream } from \"fs\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\n\nimport { createGzip, Gzip } from \"zlib\";\n\nexport default class TempGzipFile {\n public uuid: string;\n private filePath: string;\n private gzip: Gzip;\n private writeStream: WriteStream;\n private readyPromise: Promise<void>;\n\n constructor() {\n this.uuid = randomUUID();\n this.filePath = join(tmpdir(), `apitally-${this.uuid}.gz`);\n this.writeStream = createWriteStream(this.filePath);\n this.readyPromise = new Promise<void>((resolve, reject) => {\n this.writeStream.once(\"ready\", resolve);\n this.writeStream.once(\"error\", reject);\n });\n this.gzip = createGzip();\n this.gzip.pipe(this.writeStream);\n }\n\n get size() {\n return this.writeStream.bytesWritten;\n }\n\n async writeLine(data: Buffer) {\n await this.readyPromise;\n return new Promise<void>((resolve, reject) => {\n this.gzip.write(Buffer.concat([data, Buffer.from(\"\\n\")]), (error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n }\n\n async getContent() {\n return new Promise<Buffer>((resolve, reject) => {\n readFile(this.filePath, (error, data) => {\n if (error) {\n reject(error);\n } else {\n resolve(data);\n }\n });\n });\n }\n\n async close() {\n return new Promise<void>((resolve) => {\n this.gzip.end(() => {\n resolve();\n });\n });\n }\n\n async delete() {\n await this.close();\n unlinkSync(this.filePath);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;oBAAuB;AACvB,oBAA2B;AAC3B,gBAAqE;AACrE,gBAAuB;AACvB,kBAAqB;AAErB,kBAAiC;AAEjC,IAAqBA,gBAArB,MAAqBA,cAAAA;EACZC;EACCC;EACAC;EACAC;EACAC;EAERC,cAAc;AACZ,SAAKL,WAAOM,0BAAAA;AACZ,SAAKL,eAAWM,sBAAKC,kBAAAA,GAAU,YAAY,KAAKR,IAAI,KAAK;AACzD,SAAKG,kBAAcM,6BAAkB,KAAKR,QAAQ;AAClD,SAAKG,eAAe,IAAIM,QAAc,CAACC,SAASC,WAAAA;AAC9C,WAAKT,YAAYU,KAAK,SAASF,OAAAA;AAC/B,WAAKR,YAAYU,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKV,WAAOY,wBAAAA;AACZ,SAAKZ,KAAKa,KAAK,KAAKZ,WAAW;EACjC;EAEA,IAAIa,OAAO;AACT,WAAO,KAAKb,YAAYc;EAC1B;EAEA,MAAMC,UAAUC,MAAc;AAC5B,UAAM,KAAKf;AACX,WAAO,IAAIM,QAAc,CAACC,SAASC,WAAAA;AACjC,WAAKV,KAAKkB,MAAMC,qBAAOC,OAAO;QAACH;QAAME,qBAAOE,KAAK,IAAA;OAAM,GAAG,CAACC,UAAAA;AACzD,YAAIA,OAAO;AACTZ,iBAAOY,KAAAA;QACT,OAAO;AACLb,kBAAAA;QACF;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMc,aAAa;AACjB,WAAO,IAAIf,QAAgB,CAACC,SAASC,WAAAA;AACnCc,8BAAS,KAAKzB,UAAU,CAACuB,OAAOL,SAAAA;AAC9B,YAAIK,OAAO;AACTZ,iBAAOY,KAAAA;QACT,OAAO;AACLb,kBAAQQ,IAAAA;QACV;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMQ,QAAQ;AACZ,WAAO,IAAIjB,QAAc,CAACC,YAAAA;AACxB,WAAKT,KAAK0B,IAAI,MAAA;AACZjB,gBAAAA;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMkB,SAAS;AACb,UAAM,KAAKF,MAAK;AAChBG,8BAAW,KAAK7B,QAAQ;EAC1B;AACF;AA5DqBF;AAArB,IAAqBA,eAArB;","names":["TempGzipFile","uuid","filePath","gzip","writeStream","readyPromise","constructor","randomUUID","join","tmpdir","createWriteStream","Promise","resolve","reject","once","createGzip","pipe","size","bytesWritten","writeLine","data","write","Buffer","concat","from","error","getContent","readFile","close","end","delete","unlinkSync"]}
@@ -0,0 +1,17 @@
1
+ import { Buffer } from 'buffer';
2
+
3
+ declare class TempGzipFile {
4
+ uuid: string;
5
+ private filePath;
6
+ private gzip;
7
+ private writeStream;
8
+ private readyPromise;
9
+ constructor();
10
+ get size(): number;
11
+ writeLine(data: Buffer): Promise<void>;
12
+ getContent(): Promise<Buffer<ArrayBufferLike>>;
13
+ close(): Promise<void>;
14
+ delete(): Promise<void>;
15
+ }
16
+
17
+ export { TempGzipFile as default };
@@ -0,0 +1,17 @@
1
+ import { Buffer } from 'buffer';
2
+
3
+ declare class TempGzipFile {
4
+ uuid: string;
5
+ private filePath;
6
+ private gzip;
7
+ private writeStream;
8
+ private readyPromise;
9
+ constructor();
10
+ get size(): number;
11
+ writeLine(data: Buffer): Promise<void>;
12
+ getContent(): Promise<Buffer<ArrayBufferLike>>;
13
+ close(): Promise<void>;
14
+ delete(): Promise<void>;
15
+ }
16
+
17
+ export { TempGzipFile as default };
@@ -0,0 +1,74 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/common/tempGzipFile.ts
5
+ import { Buffer as Buffer2 } from "buffer";
6
+ import { randomUUID } from "crypto";
7
+ import { createWriteStream, readFile, unlinkSync } from "fs";
8
+ import { tmpdir } from "os";
9
+ import { join } from "path";
10
+ import { createGzip } from "zlib";
11
+ var _TempGzipFile = class _TempGzipFile {
12
+ uuid;
13
+ filePath;
14
+ gzip;
15
+ writeStream;
16
+ readyPromise;
17
+ constructor() {
18
+ this.uuid = randomUUID();
19
+ this.filePath = join(tmpdir(), `apitally-${this.uuid}.gz`);
20
+ this.writeStream = createWriteStream(this.filePath);
21
+ this.readyPromise = new Promise((resolve, reject) => {
22
+ this.writeStream.once("ready", resolve);
23
+ this.writeStream.once("error", reject);
24
+ });
25
+ this.gzip = createGzip();
26
+ this.gzip.pipe(this.writeStream);
27
+ }
28
+ get size() {
29
+ return this.writeStream.bytesWritten;
30
+ }
31
+ async writeLine(data) {
32
+ await this.readyPromise;
33
+ return new Promise((resolve, reject) => {
34
+ this.gzip.write(Buffer2.concat([
35
+ data,
36
+ Buffer2.from("\n")
37
+ ]), (error) => {
38
+ if (error) {
39
+ reject(error);
40
+ } else {
41
+ resolve();
42
+ }
43
+ });
44
+ });
45
+ }
46
+ async getContent() {
47
+ return new Promise((resolve, reject) => {
48
+ readFile(this.filePath, (error, data) => {
49
+ if (error) {
50
+ reject(error);
51
+ } else {
52
+ resolve(data);
53
+ }
54
+ });
55
+ });
56
+ }
57
+ async close() {
58
+ return new Promise((resolve) => {
59
+ this.gzip.end(() => {
60
+ resolve();
61
+ });
62
+ });
63
+ }
64
+ async delete() {
65
+ await this.close();
66
+ unlinkSync(this.filePath);
67
+ }
68
+ };
69
+ __name(_TempGzipFile, "TempGzipFile");
70
+ var TempGzipFile = _TempGzipFile;
71
+ export {
72
+ TempGzipFile as default
73
+ };
74
+ //# sourceMappingURL=tempGzipFile.js.map