apitally 0.11.5 → 0.13.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 (101) hide show
  1. package/README.md +43 -2
  2. package/dist/adonisjs/index.cjs +41 -0
  3. package/dist/adonisjs/index.cjs.map +1 -0
  4. package/dist/adonisjs/index.d.cts +14 -0
  5. package/dist/adonisjs/index.d.ts +14 -0
  6. package/dist/adonisjs/index.js +17 -0
  7. package/dist/adonisjs/index.js.map +1 -0
  8. package/dist/adonisjs/middleware.cjs +214 -0
  9. package/dist/adonisjs/middleware.cjs.map +1 -0
  10. package/dist/adonisjs/middleware.d.cts +21 -0
  11. package/dist/adonisjs/middleware.d.ts +21 -0
  12. package/dist/adonisjs/middleware.js +185 -0
  13. package/dist/adonisjs/middleware.js.map +1 -0
  14. package/dist/adonisjs/provider.cjs +1083 -0
  15. package/dist/adonisjs/provider.cjs.map +1 -0
  16. package/dist/adonisjs/provider.d.cts +28 -0
  17. package/dist/adonisjs/provider.d.ts +28 -0
  18. package/dist/adonisjs/provider.js +1057 -0
  19. package/dist/adonisjs/provider.js.map +1 -0
  20. package/dist/common/client.cjs +117 -106
  21. package/dist/common/client.cjs.map +1 -1
  22. package/dist/common/client.js +112 -101
  23. package/dist/common/client.js.map +1 -1
  24. package/dist/common/consumerRegistry.cjs.map +1 -1
  25. package/dist/common/consumerRegistry.js.map +1 -1
  26. package/dist/common/logging.cjs.map +1 -1
  27. package/dist/common/logging.js.map +1 -1
  28. package/dist/common/packageVersions.cjs.map +1 -1
  29. package/dist/common/packageVersions.js.map +1 -1
  30. package/dist/common/paramValidation.cjs.map +1 -1
  31. package/dist/common/paramValidation.js.map +1 -1
  32. package/dist/common/requestCounter.cjs.map +1 -1
  33. package/dist/common/requestCounter.js.map +1 -1
  34. package/dist/common/requestLogger.cjs +55 -2
  35. package/dist/common/requestLogger.cjs.map +1 -1
  36. package/dist/common/requestLogger.d.cts +2 -1
  37. package/dist/common/requestLogger.d.ts +2 -1
  38. package/dist/common/requestLogger.js +55 -2
  39. package/dist/common/requestLogger.js.map +1 -1
  40. package/dist/common/sentry.cjs +55 -0
  41. package/dist/common/sentry.cjs.map +1 -0
  42. package/dist/common/sentry.d.cts +6 -0
  43. package/dist/common/sentry.d.ts +6 -0
  44. package/dist/common/sentry.js +22 -0
  45. package/dist/common/sentry.js.map +1 -0
  46. package/dist/common/serverErrorCounter.cjs +58 -45
  47. package/dist/common/serverErrorCounter.cjs.map +1 -1
  48. package/dist/common/serverErrorCounter.d.cts +3 -6
  49. package/dist/common/serverErrorCounter.d.ts +3 -6
  50. package/dist/common/serverErrorCounter.js +53 -45
  51. package/dist/common/serverErrorCounter.js.map +1 -1
  52. package/dist/common/tempGzipFile.cjs.map +1 -1
  53. package/dist/common/tempGzipFile.js.map +1 -1
  54. package/dist/common/types.cjs.map +1 -1
  55. package/dist/common/utils.cjs +48 -0
  56. package/dist/common/utils.cjs.map +1 -0
  57. package/dist/common/utils.d.cts +5 -0
  58. package/dist/common/utils.d.ts +5 -0
  59. package/dist/common/utils.js +25 -0
  60. package/dist/common/utils.js.map +1 -0
  61. package/dist/common/validationErrorCounter.cjs.map +1 -1
  62. package/dist/common/validationErrorCounter.js.map +1 -1
  63. package/dist/express/index.cjs +143 -111
  64. package/dist/express/index.cjs.map +1 -1
  65. package/dist/express/index.js +138 -106
  66. package/dist/express/index.js.map +1 -1
  67. package/dist/express/middleware.cjs +143 -111
  68. package/dist/express/middleware.cjs.map +1 -1
  69. package/dist/express/middleware.js +138 -106
  70. package/dist/express/middleware.js.map +1 -1
  71. package/dist/express/utils.cjs.map +1 -1
  72. package/dist/express/utils.js.map +1 -1
  73. package/dist/fastify/index.cjs +139 -112
  74. package/dist/fastify/index.cjs.map +1 -1
  75. package/dist/fastify/index.js +134 -107
  76. package/dist/fastify/index.js.map +1 -1
  77. package/dist/fastify/plugin.cjs +139 -112
  78. package/dist/fastify/plugin.cjs.map +1 -1
  79. package/dist/fastify/plugin.js +134 -107
  80. package/dist/fastify/plugin.js.map +1 -1
  81. package/dist/hono/index.cjs +138 -108
  82. package/dist/hono/index.cjs.map +1 -1
  83. package/dist/hono/index.js +133 -103
  84. package/dist/hono/index.js.map +1 -1
  85. package/dist/hono/middleware.cjs +138 -108
  86. package/dist/hono/middleware.cjs.map +1 -1
  87. package/dist/hono/middleware.js +133 -103
  88. package/dist/hono/middleware.js.map +1 -1
  89. package/dist/koa/index.cjs +122 -109
  90. package/dist/koa/index.cjs.map +1 -1
  91. package/dist/koa/index.js +117 -104
  92. package/dist/koa/index.js.map +1 -1
  93. package/dist/koa/middleware.cjs +122 -109
  94. package/dist/koa/middleware.cjs.map +1 -1
  95. package/dist/koa/middleware.js +117 -104
  96. package/dist/koa/middleware.js.map +1 -1
  97. package/dist/nestjs/index.cjs +143 -111
  98. package/dist/nestjs/index.cjs.map +1 -1
  99. package/dist/nestjs/index.js +138 -106
  100. package/dist/nestjs/index.js.map +1 -1
  101. package/package.json +46 -1
@@ -212,14 +212,116 @@ var RequestCounter = _RequestCounter;
212
212
  // src/common/requestLogger.ts
213
213
  var import_async_lock = __toESM(require("async-lock"), 1);
214
214
  var import_buffer2 = require("buffer");
215
- var import_crypto2 = require("crypto");
215
+ var import_crypto3 = require("crypto");
216
216
  var import_fs2 = require("fs");
217
217
  var import_os2 = require("os");
218
218
  var import_path2 = require("path");
219
219
 
220
+ // src/common/sentry.ts
221
+ var sentry;
222
+ (async () => {
223
+ try {
224
+ sentry = await import("@sentry/node");
225
+ } catch (e) {
226
+ }
227
+ })();
228
+ function getSentryEventId() {
229
+ if (sentry && sentry.lastEventId) {
230
+ return sentry.lastEventId();
231
+ }
232
+ return void 0;
233
+ }
234
+ __name(getSentryEventId, "getSentryEventId");
235
+
236
+ // src/common/serverErrorCounter.ts
237
+ var import_crypto = require("crypto");
238
+ var MAX_MSG_LENGTH = 2048;
239
+ var MAX_STACKTRACE_LENGTH = 65536;
240
+ var _ServerErrorCounter = class _ServerErrorCounter {
241
+ errorCounts;
242
+ errorDetails;
243
+ sentryEventIds;
244
+ constructor() {
245
+ this.errorCounts = /* @__PURE__ */ new Map();
246
+ this.errorDetails = /* @__PURE__ */ new Map();
247
+ this.sentryEventIds = /* @__PURE__ */ new Map();
248
+ }
249
+ addServerError(serverError) {
250
+ const key = this.getKey(serverError);
251
+ if (!this.errorDetails.has(key)) {
252
+ this.errorDetails.set(key, serverError);
253
+ }
254
+ this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
255
+ const sentryEventId = getSentryEventId();
256
+ if (sentryEventId) {
257
+ this.sentryEventIds.set(key, sentryEventId);
258
+ }
259
+ }
260
+ getAndResetServerErrors() {
261
+ const data = [];
262
+ this.errorCounts.forEach((count, key) => {
263
+ const serverError = this.errorDetails.get(key);
264
+ if (serverError) {
265
+ data.push({
266
+ consumer: serverError.consumer || null,
267
+ method: serverError.method,
268
+ path: serverError.path,
269
+ type: serverError.type,
270
+ msg: truncateExceptionMessage(serverError.msg),
271
+ traceback: truncateExceptionStackTrace(serverError.traceback),
272
+ sentry_event_id: this.sentryEventIds.get(key) || null,
273
+ error_count: count
274
+ });
275
+ }
276
+ });
277
+ this.errorCounts.clear();
278
+ this.errorDetails.clear();
279
+ return data;
280
+ }
281
+ getKey(serverError) {
282
+ const hashInput = [
283
+ serverError.consumer || "",
284
+ serverError.method.toUpperCase(),
285
+ serverError.path,
286
+ serverError.type,
287
+ serverError.msg.trim(),
288
+ serverError.traceback.trim()
289
+ ].join("|");
290
+ return (0, import_crypto.createHash)("md5").update(hashInput).digest("hex");
291
+ }
292
+ };
293
+ __name(_ServerErrorCounter, "ServerErrorCounter");
294
+ var ServerErrorCounter = _ServerErrorCounter;
295
+ function truncateExceptionMessage(msg) {
296
+ if (msg.length <= MAX_MSG_LENGTH) {
297
+ return msg;
298
+ }
299
+ const suffix = "... (truncated)";
300
+ const cutoff = MAX_MSG_LENGTH - suffix.length;
301
+ return msg.substring(0, cutoff) + suffix;
302
+ }
303
+ __name(truncateExceptionMessage, "truncateExceptionMessage");
304
+ function truncateExceptionStackTrace(stack) {
305
+ const suffix = "... (truncated) ...";
306
+ const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
307
+ const lines = stack.trim().split("\n");
308
+ const truncatedLines = [];
309
+ let length = 0;
310
+ for (const line of lines) {
311
+ if (length + line.length + 1 > cutoff) {
312
+ truncatedLines.push(suffix);
313
+ break;
314
+ }
315
+ truncatedLines.push(line);
316
+ length += line.length + 1;
317
+ }
318
+ return truncatedLines.join("\n");
319
+ }
320
+ __name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
321
+
220
322
  // src/common/tempGzipFile.ts
221
323
  var import_buffer = require("buffer");
222
- var import_crypto = require("crypto");
324
+ var import_crypto2 = require("crypto");
223
325
  var import_fs = require("fs");
224
326
  var import_os = require("os");
225
327
  var import_path = require("path");
@@ -232,7 +334,7 @@ var _TempGzipFile = class _TempGzipFile {
232
334
  readyPromise;
233
335
  closedPromise;
234
336
  constructor() {
235
- this.uuid = (0, import_crypto.randomUUID)();
337
+ this.uuid = (0, import_crypto2.randomUUID)();
236
338
  this.filePath = (0, import_path.join)((0, import_os.tmpdir)(), `apitally-${this.uuid}.gz`);
237
339
  this.writeStream = (0, import_fs.createWriteStream)(this.filePath);
238
340
  this.readyPromise = new Promise((resolve, reject) => {
@@ -339,6 +441,7 @@ var DEFAULT_CONFIG = {
339
441
  logRequestBody: false,
340
442
  logResponseHeaders: true,
341
443
  logResponseBody: false,
444
+ logException: true,
342
445
  maskQueryParams: [],
343
446
  maskHeaders: [],
344
447
  excludePaths: []
@@ -411,7 +514,7 @@ var _RequestLogger = class _RequestLogger {
411
514
  this.shouldMaskHeader(k) ? MASKED : v
412
515
  ]);
413
516
  }
414
- logRequest(request, response) {
517
+ logRequest(request, response, error) {
415
518
  var _a2, _b, _c;
416
519
  if (!this.enabled || this.suspendUntil !== null) return;
417
520
  const url = new URL(request.url);
@@ -457,9 +560,15 @@ var _RequestLogger = class _RequestLogger {
457
560
  request.headers = this.config.logRequestHeaders ? this.maskHeaders(request.headers) : [];
458
561
  response.headers = this.config.logResponseHeaders ? this.maskHeaders(response.headers) : [];
459
562
  const item = {
460
- uuid: (0, import_crypto2.randomUUID)(),
563
+ uuid: (0, import_crypto3.randomUUID)(),
461
564
  request: skipEmptyValues(request),
462
- response: skipEmptyValues(response)
565
+ response: skipEmptyValues(response),
566
+ exception: error && this.config.logException ? {
567
+ type: error.name,
568
+ message: truncateExceptionMessage(error.message),
569
+ stacktrace: truncateExceptionStackTrace(error.stack || ""),
570
+ sentryEventId: getSentryEventId()
571
+ } : null
463
572
  };
464
573
  [
465
574
  item.request.body,
@@ -579,7 +688,7 @@ function skipEmptyValues(data) {
579
688
  __name(skipEmptyValues, "skipEmptyValues");
580
689
  function checkWritableFs() {
581
690
  try {
582
- const testPath = (0, import_path2.join)((0, import_os2.tmpdir)(), `apitally-${(0, import_crypto2.randomUUID)()}`);
691
+ const testPath = (0, import_path2.join)((0, import_os2.tmpdir)(), `apitally-${(0, import_crypto3.randomUUID)()}`);
583
692
  (0, import_fs2.writeFileSync)(testPath, "test");
584
693
  (0, import_fs2.unlinkSync)(testPath);
585
694
  return true;
@@ -589,104 +698,6 @@ function checkWritableFs() {
589
698
  }
590
699
  __name(checkWritableFs, "checkWritableFs");
591
700
 
592
- // src/common/serverErrorCounter.ts
593
- var import_crypto3 = require("crypto");
594
- var MAX_MSG_LENGTH = 2048;
595
- var MAX_STACKTRACE_LENGTH = 65536;
596
- var _ServerErrorCounter = class _ServerErrorCounter {
597
- errorCounts;
598
- errorDetails;
599
- sentryEventIds;
600
- sentry;
601
- constructor() {
602
- this.errorCounts = /* @__PURE__ */ new Map();
603
- this.errorDetails = /* @__PURE__ */ new Map();
604
- this.sentryEventIds = /* @__PURE__ */ new Map();
605
- this.tryImportSentry();
606
- }
607
- addServerError(serverError) {
608
- const key = this.getKey(serverError);
609
- if (!this.errorDetails.has(key)) {
610
- this.errorDetails.set(key, serverError);
611
- }
612
- this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
613
- this.captureSentryEventId(key);
614
- }
615
- getAndResetServerErrors() {
616
- const data = [];
617
- this.errorCounts.forEach((count, key) => {
618
- const serverError = this.errorDetails.get(key);
619
- if (serverError) {
620
- data.push({
621
- consumer: serverError.consumer || null,
622
- method: serverError.method,
623
- path: serverError.path,
624
- type: serverError.type,
625
- msg: this.getTruncatedMessage(serverError.msg),
626
- traceback: this.getTruncatedStack(serverError.traceback),
627
- sentry_event_id: this.sentryEventIds.get(key) || null,
628
- error_count: count
629
- });
630
- }
631
- });
632
- this.errorCounts.clear();
633
- this.errorDetails.clear();
634
- return data;
635
- }
636
- getKey(serverError) {
637
- const hashInput = [
638
- serverError.consumer || "",
639
- serverError.method.toUpperCase(),
640
- serverError.path,
641
- serverError.type,
642
- serverError.msg.trim(),
643
- serverError.traceback.trim()
644
- ].join("|");
645
- return (0, import_crypto3.createHash)("md5").update(hashInput).digest("hex");
646
- }
647
- getTruncatedMessage(msg) {
648
- msg = msg.trim();
649
- if (msg.length <= MAX_MSG_LENGTH) {
650
- return msg;
651
- }
652
- const suffix = "... (truncated)";
653
- const cutoff = MAX_MSG_LENGTH - suffix.length;
654
- return msg.substring(0, cutoff) + suffix;
655
- }
656
- getTruncatedStack(stack) {
657
- const suffix = "... (truncated) ...";
658
- const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
659
- const lines = stack.trim().split("\n");
660
- const truncatedLines = [];
661
- let length = 0;
662
- for (const line of lines) {
663
- if (length + line.length + 1 > cutoff) {
664
- truncatedLines.push(suffix);
665
- break;
666
- }
667
- truncatedLines.push(line);
668
- length += line.length + 1;
669
- }
670
- return truncatedLines.join("\n");
671
- }
672
- captureSentryEventId(serverErrorKey) {
673
- if (this.sentry && this.sentry.lastEventId) {
674
- const eventId = this.sentry.lastEventId();
675
- if (eventId) {
676
- this.sentryEventIds.set(serverErrorKey, eventId);
677
- }
678
- }
679
- }
680
- async tryImportSentry() {
681
- try {
682
- this.sentry = await import("@sentry/node");
683
- } catch (e) {
684
- }
685
- }
686
- };
687
- __name(_ServerErrorCounter, "ServerErrorCounter");
688
- var ServerErrorCounter = _ServerErrorCounter;
689
-
690
701
  // src/common/validationErrorCounter.ts
691
702
  var import_crypto4 = require("crypto");
692
703
  var _ValidationErrorCounter = class _ValidationErrorCounter {
@@ -772,7 +783,7 @@ var _ApitallyClient = class _ApitallyClient {
772
783
  throw new Error("Apitally client is already initialized");
773
784
  }
774
785
  if (!isValidClientId(clientId)) {
775
- throw new Error(`Invalid client ID '${clientId}' (expecting hexadeciaml UUID format)`);
786
+ throw new Error(`Invalid Apitally client ID '${clientId}' (expecting hexadecimal UUID format)`);
776
787
  }
777
788
  if (!isValidEnv(env)) {
778
789
  throw new Error(`Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`);
@@ -1028,6 +1039,25 @@ function getPackageVersion(name) {
1028
1039
  }
1029
1040
  __name(getPackageVersion, "getPackageVersion");
1030
1041
 
1042
+ // src/common/utils.ts
1043
+ function parseContentLength(contentLength) {
1044
+ if (contentLength === void 0 || contentLength === null) {
1045
+ return void 0;
1046
+ }
1047
+ if (typeof contentLength === "number") {
1048
+ return contentLength;
1049
+ }
1050
+ if (typeof contentLength === "string") {
1051
+ const parsed = parseInt(contentLength);
1052
+ return isNaN(parsed) ? void 0 : parsed;
1053
+ }
1054
+ if (Array.isArray(contentLength)) {
1055
+ return parseContentLength(contentLength[0]);
1056
+ }
1057
+ return void 0;
1058
+ }
1059
+ __name(parseContentLength, "parseContentLength");
1060
+
1031
1061
  // src/hono/middleware.ts
1032
1062
  var useApitally = /* @__PURE__ */ __name((app, config) => {
1033
1063
  const client = new ApitallyClient(config);
@@ -1048,7 +1078,7 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
1048
1078
  let response;
1049
1079
  const responseTime = import_perf_hooks.performance.now() - startTime;
1050
1080
  const [responseSize, newResponse] = await measureResponseSize(c.res);
1051
- const requestSize = c.req.header("Content-Length");
1081
+ const requestSize = parseContentLength(c.req.header("content-length"));
1052
1082
  const consumer = getConsumer(c);
1053
1083
  client.consumerRegistry.addOrUpdateConsumer(consumer);
1054
1084
  client.requestCounter.addRequest({
@@ -1111,7 +1141,7 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
1111
1141
  headers: convertHeaders(c.res.headers),
1112
1142
  size: responseSize,
1113
1143
  body: responseBody
1114
- });
1144
+ }, c.error);
1115
1145
  }
1116
1146
  c.res = response;
1117
1147
  };