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
@@ -14,7 +14,7 @@ import { isMiddleware } from "hono/utils/handler";
14
14
  import { performance } from "perf_hooks";
15
15
 
16
16
  // src/common/client.ts
17
- import { randomUUID } from "crypto";
17
+ import { randomUUID as randomUUID3 } from "crypto";
18
18
  import fetchRetry from "fetch-retry";
19
19
 
20
20
  // src/common/consumerRegistry.ts
@@ -183,6 +183,361 @@ var _RequestCounter = class _RequestCounter {
183
183
  __name(_RequestCounter, "RequestCounter");
184
184
  var RequestCounter = _RequestCounter;
185
185
 
186
+ // src/common/requestLogger.ts
187
+ import { Buffer as Buffer3 } from "buffer";
188
+ import { randomUUID as randomUUID2 } from "crypto";
189
+ import { unlinkSync as unlinkSync2, writeFileSync } from "fs";
190
+ import { tmpdir as tmpdir2 } from "os";
191
+ import { join as join2 } from "path";
192
+
193
+ // src/common/tempGzipFile.ts
194
+ import { Buffer as Buffer2 } from "buffer";
195
+ import { randomUUID } from "crypto";
196
+ import { createWriteStream, readFile, unlinkSync } from "fs";
197
+ import { tmpdir } from "os";
198
+ import { join } from "path";
199
+ import { createGzip } from "zlib";
200
+ var _TempGzipFile = class _TempGzipFile {
201
+ uuid;
202
+ filePath;
203
+ gzip;
204
+ writeStream;
205
+ readyPromise;
206
+ constructor() {
207
+ this.uuid = randomUUID();
208
+ this.filePath = join(tmpdir(), `apitally-${this.uuid}.gz`);
209
+ this.writeStream = createWriteStream(this.filePath);
210
+ this.readyPromise = new Promise((resolve, reject) => {
211
+ this.writeStream.once("ready", resolve);
212
+ this.writeStream.once("error", reject);
213
+ });
214
+ this.gzip = createGzip();
215
+ this.gzip.pipe(this.writeStream);
216
+ }
217
+ get size() {
218
+ return this.writeStream.bytesWritten;
219
+ }
220
+ async writeLine(data) {
221
+ await this.readyPromise;
222
+ return new Promise((resolve, reject) => {
223
+ this.gzip.write(Buffer2.concat([
224
+ data,
225
+ Buffer2.from("\n")
226
+ ]), (error) => {
227
+ if (error) {
228
+ reject(error);
229
+ } else {
230
+ resolve();
231
+ }
232
+ });
233
+ });
234
+ }
235
+ async getContent() {
236
+ return new Promise((resolve, reject) => {
237
+ readFile(this.filePath, (error, data) => {
238
+ if (error) {
239
+ reject(error);
240
+ } else {
241
+ resolve(data);
242
+ }
243
+ });
244
+ });
245
+ }
246
+ async close() {
247
+ return new Promise((resolve) => {
248
+ this.gzip.end(() => {
249
+ resolve();
250
+ });
251
+ });
252
+ }
253
+ async delete() {
254
+ await this.close();
255
+ unlinkSync(this.filePath);
256
+ }
257
+ };
258
+ __name(_TempGzipFile, "TempGzipFile");
259
+ var TempGzipFile = _TempGzipFile;
260
+
261
+ // src/common/requestLogger.ts
262
+ var MAX_BODY_SIZE = 5e4;
263
+ var MAX_FILE_SIZE = 1e6;
264
+ var MAX_FILES = 50;
265
+ var MAX_PENDING_WRITES = 100;
266
+ var BODY_TOO_LARGE = Buffer3.from("<body too large>");
267
+ var BODY_MASKED = Buffer3.from("<masked>");
268
+ var MASKED = "******";
269
+ var ALLOWED_CONTENT_TYPES = [
270
+ "application/json",
271
+ "text/plain"
272
+ ];
273
+ var EXCLUDE_PATH_PATTERNS = [
274
+ /\/_?healthz?$/,
275
+ /\/_?health[_-]?checks?$/,
276
+ /\/_?heart[_-]?beats?$/,
277
+ /\/ping$/,
278
+ /\/ready$/,
279
+ /\/live$/
280
+ ];
281
+ var MASK_QUERY_PARAM_PATTERNS = [
282
+ /auth/i,
283
+ /api-?key/i,
284
+ /secret/i,
285
+ /token/i,
286
+ /password/i,
287
+ /pwd/i
288
+ ];
289
+ var MASK_HEADER_PATTERNS = [
290
+ /auth/i,
291
+ /api-?key/i,
292
+ /secret/i,
293
+ /token/i,
294
+ /cookie/i
295
+ ];
296
+ var DEFAULT_CONFIG = {
297
+ enabled: false,
298
+ logQueryParams: true,
299
+ logRequestHeaders: false,
300
+ logRequestBody: false,
301
+ logResponseHeaders: true,
302
+ logResponseBody: false,
303
+ maskQueryParams: [],
304
+ maskHeaders: [],
305
+ excludePaths: []
306
+ };
307
+ var _RequestLogger = class _RequestLogger {
308
+ config;
309
+ enabled;
310
+ suspendUntil = null;
311
+ pendingWrites = [];
312
+ currentFile = null;
313
+ files = [];
314
+ maintainIntervalId;
315
+ constructor(config) {
316
+ this.config = {
317
+ ...DEFAULT_CONFIG,
318
+ ...config
319
+ };
320
+ this.enabled = this.config.enabled && checkWritableFs();
321
+ if (this.enabled) {
322
+ this.maintainIntervalId = setInterval(() => {
323
+ this.maintain();
324
+ }, 1e3);
325
+ }
326
+ }
327
+ shouldExcludePath(urlPath) {
328
+ const patterns = [
329
+ ...this.config.excludePaths,
330
+ ...EXCLUDE_PATH_PATTERNS
331
+ ];
332
+ return matchPatterns(urlPath, patterns);
333
+ }
334
+ shouldMaskQueryParam(name) {
335
+ const patterns = [
336
+ ...this.config.maskQueryParams,
337
+ ...MASK_QUERY_PARAM_PATTERNS
338
+ ];
339
+ return matchPatterns(name, patterns);
340
+ }
341
+ shouldMaskHeader(name) {
342
+ const patterns = [
343
+ ...this.config.maskHeaders,
344
+ ...MASK_HEADER_PATTERNS
345
+ ];
346
+ return matchPatterns(name, patterns);
347
+ }
348
+ hasSupportedContentType(headers) {
349
+ var _a2;
350
+ const contentType = (_a2 = headers.find(([k]) => k.toLowerCase() === "content-type")) == null ? void 0 : _a2[1];
351
+ return contentType !== void 0 && ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t));
352
+ }
353
+ maskQueryParams(search) {
354
+ const params = new URLSearchParams(search);
355
+ for (const [key] of params) {
356
+ if (this.shouldMaskQueryParam(key)) {
357
+ params.set(key, MASKED);
358
+ }
359
+ }
360
+ return params.toString();
361
+ }
362
+ maskHeaders(headers) {
363
+ return headers.map(([k, v]) => [
364
+ k,
365
+ this.shouldMaskHeader(k) ? MASKED : v
366
+ ]);
367
+ }
368
+ logRequest(request, response) {
369
+ var _a2, _b;
370
+ if (!this.enabled || this.suspendUntil !== null) return;
371
+ const url = new URL(request.url);
372
+ const path = request.path ?? url.pathname;
373
+ if (this.shouldExcludePath(path) || (((_b = (_a2 = this.config).excludeCallback) == null ? void 0 : _b.call(_a2, request, response)) ?? false)) {
374
+ return;
375
+ }
376
+ url.search = this.config.logQueryParams ? this.maskQueryParams(url.search) : "";
377
+ request.url = url.toString();
378
+ request.headers = this.config.logRequestHeaders ? this.maskHeaders(request.headers) : [];
379
+ response.headers = this.config.logResponseHeaders ? this.maskHeaders(response.headers) : [];
380
+ if (!this.config.logRequestBody || !this.hasSupportedContentType(request.headers)) {
381
+ request.body = void 0;
382
+ } else if (request.body) {
383
+ if (request.body.length > MAX_BODY_SIZE) {
384
+ request.body = BODY_TOO_LARGE;
385
+ } else if (this.config.maskRequestBodyCallback) {
386
+ try {
387
+ request.body = this.config.maskRequestBodyCallback(request) ?? BODY_MASKED;
388
+ if (request.body.length > MAX_BODY_SIZE) {
389
+ request.body = BODY_TOO_LARGE;
390
+ }
391
+ } catch {
392
+ request.body = void 0;
393
+ }
394
+ }
395
+ }
396
+ if (!this.config.logResponseBody || !this.hasSupportedContentType(response.headers)) {
397
+ response.body = void 0;
398
+ } else if (response.body) {
399
+ if (response.body.length > MAX_BODY_SIZE) {
400
+ response.body = BODY_TOO_LARGE;
401
+ } else if (this.config.maskResponseBodyCallback) {
402
+ try {
403
+ response.body = this.config.maskResponseBodyCallback(request, response) ?? BODY_MASKED;
404
+ if (response.body.length > MAX_BODY_SIZE) {
405
+ response.body = BODY_TOO_LARGE;
406
+ }
407
+ } catch {
408
+ response.body = void 0;
409
+ }
410
+ }
411
+ }
412
+ const item = {
413
+ uuid: randomUUID2(),
414
+ request: skipEmptyValues(request),
415
+ response: skipEmptyValues(response)
416
+ };
417
+ [
418
+ item.request.body,
419
+ item.response.body
420
+ ].forEach((body) => {
421
+ if (body) {
422
+ body.toJSON = function() {
423
+ return this.toString("base64");
424
+ };
425
+ }
426
+ });
427
+ this.pendingWrites.push(JSON.stringify(item));
428
+ if (this.pendingWrites.length > MAX_PENDING_WRITES) {
429
+ this.pendingWrites.shift();
430
+ }
431
+ }
432
+ async writeToFile() {
433
+ if (!this.enabled || this.pendingWrites.length === 0) {
434
+ return;
435
+ }
436
+ if (!this.currentFile) {
437
+ this.currentFile = new TempGzipFile();
438
+ }
439
+ while (this.pendingWrites.length > 0) {
440
+ const item = this.pendingWrites.shift();
441
+ if (item) {
442
+ await this.currentFile.writeLine(Buffer3.from(item));
443
+ }
444
+ }
445
+ }
446
+ getFile() {
447
+ return this.files.shift();
448
+ }
449
+ retryFileLater(file) {
450
+ this.files.unshift(file);
451
+ }
452
+ async rotateFile() {
453
+ if (this.currentFile) {
454
+ await this.currentFile.close();
455
+ this.files.push(this.currentFile);
456
+ this.currentFile = null;
457
+ }
458
+ }
459
+ async maintain() {
460
+ await this.writeToFile();
461
+ if (this.currentFile && this.currentFile.size > MAX_FILE_SIZE) {
462
+ await this.rotateFile();
463
+ }
464
+ while (this.files.length > MAX_FILES) {
465
+ const file = this.files.shift();
466
+ file == null ? void 0 : file.delete();
467
+ }
468
+ if (this.suspendUntil !== null && this.suspendUntil < Date.now()) {
469
+ this.suspendUntil = null;
470
+ }
471
+ }
472
+ async clear() {
473
+ this.pendingWrites = [];
474
+ await this.rotateFile();
475
+ this.files.forEach((file) => {
476
+ file.delete();
477
+ });
478
+ this.files = [];
479
+ }
480
+ async close() {
481
+ this.enabled = false;
482
+ await this.clear();
483
+ if (this.maintainIntervalId) {
484
+ clearInterval(this.maintainIntervalId);
485
+ }
486
+ }
487
+ };
488
+ __name(_RequestLogger, "RequestLogger");
489
+ var RequestLogger = _RequestLogger;
490
+ function convertHeaders(headers) {
491
+ if (headers instanceof Headers) {
492
+ return Array.from(headers.entries());
493
+ }
494
+ return Object.entries(headers).flatMap(([key, value]) => {
495
+ if (value === void 0) {
496
+ return [];
497
+ }
498
+ if (Array.isArray(value)) {
499
+ return value.map((v) => [
500
+ key,
501
+ v
502
+ ]);
503
+ }
504
+ return [
505
+ [
506
+ key,
507
+ value.toString()
508
+ ]
509
+ ];
510
+ });
511
+ }
512
+ __name(convertHeaders, "convertHeaders");
513
+ function matchPatterns(value, patterns) {
514
+ return patterns.some((pattern) => {
515
+ return pattern.test(value);
516
+ });
517
+ }
518
+ __name(matchPatterns, "matchPatterns");
519
+ function skipEmptyValues(data) {
520
+ return Object.fromEntries(Object.entries(data).filter(([_, v]) => {
521
+ if (v == null || Number.isNaN(v)) return false;
522
+ if (Array.isArray(v) || Buffer3.isBuffer(v) || typeof v === "string") {
523
+ return v.length > 0;
524
+ }
525
+ return true;
526
+ }));
527
+ }
528
+ __name(skipEmptyValues, "skipEmptyValues");
529
+ function checkWritableFs() {
530
+ try {
531
+ const testPath = join2(tmpdir2(), `apitally-${randomUUID2()}`);
532
+ writeFileSync(testPath, "test");
533
+ unlinkSync2(testPath);
534
+ return true;
535
+ } catch (error) {
536
+ return false;
537
+ }
538
+ }
539
+ __name(checkWritableFs, "checkWritableFs");
540
+
186
541
  // src/common/serverErrorCounter.ts
187
542
  import { createHash } from "crypto";
188
543
  var MAX_MSG_LENGTH = 2048;
@@ -355,11 +710,12 @@ var _ApitallyClient = class _ApitallyClient {
355
710
  startupData;
356
711
  startupDataSent = false;
357
712
  requestCounter;
713
+ requestLogger;
358
714
  validationErrorCounter;
359
715
  serverErrorCounter;
360
716
  consumerRegistry;
361
717
  logger;
362
- constructor({ clientId, env = "dev", logger }) {
718
+ constructor({ clientId, env = "dev", requestLoggingConfig, logger }) {
363
719
  if (_ApitallyClient.instance) {
364
720
  throw new Error("Apitally client is already initialized");
365
721
  }
@@ -372,9 +728,10 @@ var _ApitallyClient = class _ApitallyClient {
372
728
  _ApitallyClient.instance = this;
373
729
  this.clientId = clientId;
374
730
  this.env = env;
375
- this.instanceUuid = randomUUID();
731
+ this.instanceUuid = randomUUID3();
376
732
  this.syncDataQueue = [];
377
733
  this.requestCounter = new RequestCounter();
734
+ this.requestLogger = new RequestLogger(requestLoggingConfig);
378
735
  this.validationErrorCounter = new ValidationErrorCounter();
379
736
  this.serverErrorCounter = new ServerErrorCounter();
380
737
  this.consumerRegistry = new ConsumerRegistry();
@@ -396,6 +753,8 @@ var _ApitallyClient = class _ApitallyClient {
396
753
  async handleShutdown() {
397
754
  this.stopSync();
398
755
  await this.sendSyncData();
756
+ await this.sendLogData();
757
+ await this.requestLogger.close();
399
758
  _ApitallyClient.instance = void 0;
400
759
  }
401
760
  getHubUrlPrefix() {
@@ -442,7 +801,8 @@ var _ApitallyClient = class _ApitallyClient {
442
801
  async sync() {
443
802
  try {
444
803
  const promises = [
445
- this.sendSyncData()
804
+ this.sendSyncData(),
805
+ this.sendLogData()
446
806
  ];
447
807
  if (!this.startupDataSent) {
448
808
  promises.push(this.sendStartupData());
@@ -470,7 +830,7 @@ var _ApitallyClient = class _ApitallyClient {
470
830
  this.logger.debug("Sending startup data to Apitally Hub");
471
831
  const payload = {
472
832
  instance_uuid: this.instanceUuid,
473
- message_uuid: randomUUID(),
833
+ message_uuid: randomUUID3(),
474
834
  ...this.startupData
475
835
  };
476
836
  try {
@@ -492,7 +852,7 @@ var _ApitallyClient = class _ApitallyClient {
492
852
  const newPayload = {
493
853
  time_offset: 0,
494
854
  instance_uuid: this.instanceUuid,
495
- message_uuid: randomUUID(),
855
+ message_uuid: randomUUID3(),
496
856
  requests: this.requestCounter.getAndResetRequests(),
497
857
  validation_errors: this.validationErrorCounter.getAndResetValidationErrors(),
498
858
  server_errors: this.serverErrorCounter.getAndResetServerErrors(),
@@ -511,8 +871,7 @@ var _ApitallyClient = class _ApitallyClient {
511
871
  const timeOffset = Date.now() - time;
512
872
  if (timeOffset <= MAX_QUEUE_TIME) {
513
873
  if (i > 0) {
514
- const waitMs = 100 + Math.random() * 200;
515
- await new Promise((resolve) => setTimeout(resolve, waitMs));
874
+ await this.randomDelay();
516
875
  }
517
876
  payload.time_offset = timeOffset / 1e3;
518
877
  await this.sendData("sync", payload);
@@ -531,6 +890,52 @@ var _ApitallyClient = class _ApitallyClient {
531
890
  }
532
891
  }
533
892
  }
893
+ async sendLogData() {
894
+ this.logger.debug("Sending request log data to Apitally Hub");
895
+ await this.requestLogger.rotateFile();
896
+ const fetchWithRetry = fetchRetry(fetch, {
897
+ retries: 3,
898
+ retryDelay: 1e3,
899
+ retryOn: [
900
+ 408,
901
+ 429,
902
+ 500,
903
+ 502,
904
+ 503,
905
+ 504
906
+ ]
907
+ });
908
+ let i = 0;
909
+ let logFile;
910
+ while (logFile = this.requestLogger.getFile()) {
911
+ if (i > 0) {
912
+ await this.randomDelay();
913
+ }
914
+ try {
915
+ const response = await fetchWithRetry(`${this.getHubUrlPrefix()}log?uuid=${logFile.uuid}`, {
916
+ method: "POST",
917
+ body: await logFile.getContent()
918
+ });
919
+ if (response.status === 402 && response.headers.has("Retry-After")) {
920
+ const retryAfter = parseInt(response.headers.get("Retry-After") ?? "0");
921
+ if (retryAfter > 0) {
922
+ this.requestLogger.suspendUntil = Date.now() + retryAfter * 1e3;
923
+ this.requestLogger.clear();
924
+ return;
925
+ }
926
+ }
927
+ if (!response.ok) {
928
+ throw new HTTPError(response);
929
+ }
930
+ logFile.delete();
931
+ } catch (error) {
932
+ this.requestLogger.retryFileLater(logFile);
933
+ break;
934
+ }
935
+ i++;
936
+ if (i >= 10) break;
937
+ }
938
+ }
534
939
  handleHubError(error) {
535
940
  if (error instanceof HTTPError) {
536
941
  if (error.response.status === 404) {
@@ -545,6 +950,10 @@ var _ApitallyClient = class _ApitallyClient {
545
950
  }
546
951
  return false;
547
952
  }
953
+ async randomDelay() {
954
+ const delay = 100 + Math.random() * 200;
955
+ await new Promise((resolve) => setTimeout(resolve, delay));
956
+ }
548
957
  };
549
958
  __name(_ApitallyClient, "ApitallyClient");
550
959
  __publicField(_ApitallyClient, "instance");
@@ -577,13 +986,13 @@ var useApitally = /* @__PURE__ */ __name((app, config) => {
577
986
  }, 1e3);
578
987
  }, "useApitally");
579
988
  var getMiddleware = /* @__PURE__ */ __name((client) => {
580
- const zodInstalled = getPackageVersion("zod") !== null;
581
989
  return async (c, next) => {
582
990
  const startTime = performance.now();
583
991
  await next();
584
992
  let response;
585
993
  const responseTime = performance.now() - startTime;
586
994
  const [responseSize, newResponse] = await measureResponseSize(c.res);
995
+ const requestSize = c.req.header("Content-Length");
587
996
  const consumer = getConsumer(c);
588
997
  client.consumerRegistry.addOrUpdateConsumer(consumer);
589
998
  client.requestCounter.addRequest({
@@ -592,11 +1001,11 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
592
1001
  path: c.req.routePath,
593
1002
  statusCode: c.res.status,
594
1003
  responseTime,
595
- requestSize: c.req.header("Content-Length"),
1004
+ requestSize,
596
1005
  responseSize
597
1006
  });
598
1007
  response = newResponse;
599
- if (c.res.status === 400 && zodInstalled) {
1008
+ if (c.res.status === 400) {
600
1009
  const [responseJson, newResponse2] = await getResponseJson(response);
601
1010
  const validationErrors = extractZodErrors(responseJson);
602
1011
  validationErrors.forEach((error) => {
@@ -619,6 +1028,34 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
619
1028
  traceback: c.error.stack || ""
620
1029
  });
621
1030
  }
1031
+ if (client.requestLogger.enabled) {
1032
+ let requestBody;
1033
+ let responseBody;
1034
+ let newResponse2 = response;
1035
+ if (client.requestLogger.config.logRequestBody) {
1036
+ requestBody = Buffer.from(await c.req.arrayBuffer());
1037
+ }
1038
+ if (client.requestLogger.config.logResponseBody) {
1039
+ [responseBody, newResponse2] = await getResponseBody(response);
1040
+ response = newResponse2;
1041
+ }
1042
+ client.requestLogger.logRequest({
1043
+ timestamp: Date.now() / 1e3,
1044
+ method: c.req.method,
1045
+ path: c.req.routePath,
1046
+ url: c.req.url,
1047
+ headers: convertHeaders(c.req.header()),
1048
+ size: Number(requestSize),
1049
+ consumer: consumer == null ? void 0 : consumer.identifier,
1050
+ body: requestBody
1051
+ }, {
1052
+ statusCode: c.res.status,
1053
+ responseTime: responseTime / 1e3,
1054
+ headers: convertHeaders(c.res.headers),
1055
+ size: responseSize,
1056
+ body: responseBody
1057
+ });
1058
+ }
622
1059
  c.res = response;
623
1060
  };
624
1061
  }, "getMiddleware");
@@ -648,6 +1085,14 @@ var measureResponseSize = /* @__PURE__ */ __name(async (response) => {
648
1085
  newResponse1
649
1086
  ];
650
1087
  }, "measureResponseSize");
1088
+ var getResponseBody = /* @__PURE__ */ __name(async (response) => {
1089
+ const [newResponse1, newResponse2] = await teeResponse(response);
1090
+ const responseBuffer = Buffer.from(await newResponse2.arrayBuffer());
1091
+ return [
1092
+ responseBuffer,
1093
+ newResponse1
1094
+ ];
1095
+ }, "getResponseBody");
651
1096
  var getResponseJson = /* @__PURE__ */ __name(async (response) => {
652
1097
  const contentType = response.headers.get("content-type");
653
1098
  if (contentType && contentType.includes("application/json")) {