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
@@ -210,14 +210,116 @@ var RequestCounter = _RequestCounter;
210
210
  // src/common/requestLogger.ts
211
211
  var import_async_lock = __toESM(require("async-lock"), 1);
212
212
  var import_buffer2 = require("buffer");
213
- var import_crypto2 = require("crypto");
213
+ var import_crypto3 = require("crypto");
214
214
  var import_fs2 = require("fs");
215
215
  var import_os2 = require("os");
216
216
  var import_path2 = require("path");
217
217
 
218
+ // src/common/sentry.ts
219
+ var sentry;
220
+ (async () => {
221
+ try {
222
+ sentry = await import("@sentry/node");
223
+ } catch (e) {
224
+ }
225
+ })();
226
+ function getSentryEventId() {
227
+ if (sentry && sentry.lastEventId) {
228
+ return sentry.lastEventId();
229
+ }
230
+ return void 0;
231
+ }
232
+ __name(getSentryEventId, "getSentryEventId");
233
+
234
+ // src/common/serverErrorCounter.ts
235
+ var import_crypto = require("crypto");
236
+ var MAX_MSG_LENGTH = 2048;
237
+ var MAX_STACKTRACE_LENGTH = 65536;
238
+ var _ServerErrorCounter = class _ServerErrorCounter {
239
+ errorCounts;
240
+ errorDetails;
241
+ sentryEventIds;
242
+ constructor() {
243
+ this.errorCounts = /* @__PURE__ */ new Map();
244
+ this.errorDetails = /* @__PURE__ */ new Map();
245
+ this.sentryEventIds = /* @__PURE__ */ new Map();
246
+ }
247
+ addServerError(serverError) {
248
+ const key = this.getKey(serverError);
249
+ if (!this.errorDetails.has(key)) {
250
+ this.errorDetails.set(key, serverError);
251
+ }
252
+ this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
253
+ const sentryEventId = getSentryEventId();
254
+ if (sentryEventId) {
255
+ this.sentryEventIds.set(key, sentryEventId);
256
+ }
257
+ }
258
+ getAndResetServerErrors() {
259
+ const data = [];
260
+ this.errorCounts.forEach((count, key) => {
261
+ const serverError = this.errorDetails.get(key);
262
+ if (serverError) {
263
+ data.push({
264
+ consumer: serverError.consumer || null,
265
+ method: serverError.method,
266
+ path: serverError.path,
267
+ type: serverError.type,
268
+ msg: truncateExceptionMessage(serverError.msg),
269
+ traceback: truncateExceptionStackTrace(serverError.traceback),
270
+ sentry_event_id: this.sentryEventIds.get(key) || null,
271
+ error_count: count
272
+ });
273
+ }
274
+ });
275
+ this.errorCounts.clear();
276
+ this.errorDetails.clear();
277
+ return data;
278
+ }
279
+ getKey(serverError) {
280
+ const hashInput = [
281
+ serverError.consumer || "",
282
+ serverError.method.toUpperCase(),
283
+ serverError.path,
284
+ serverError.type,
285
+ serverError.msg.trim(),
286
+ serverError.traceback.trim()
287
+ ].join("|");
288
+ return (0, import_crypto.createHash)("md5").update(hashInput).digest("hex");
289
+ }
290
+ };
291
+ __name(_ServerErrorCounter, "ServerErrorCounter");
292
+ var ServerErrorCounter = _ServerErrorCounter;
293
+ function truncateExceptionMessage(msg) {
294
+ if (msg.length <= MAX_MSG_LENGTH) {
295
+ return msg;
296
+ }
297
+ const suffix = "... (truncated)";
298
+ const cutoff = MAX_MSG_LENGTH - suffix.length;
299
+ return msg.substring(0, cutoff) + suffix;
300
+ }
301
+ __name(truncateExceptionMessage, "truncateExceptionMessage");
302
+ function truncateExceptionStackTrace(stack) {
303
+ const suffix = "... (truncated) ...";
304
+ const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
305
+ const lines = stack.trim().split("\n");
306
+ const truncatedLines = [];
307
+ let length = 0;
308
+ for (const line of lines) {
309
+ if (length + line.length + 1 > cutoff) {
310
+ truncatedLines.push(suffix);
311
+ break;
312
+ }
313
+ truncatedLines.push(line);
314
+ length += line.length + 1;
315
+ }
316
+ return truncatedLines.join("\n");
317
+ }
318
+ __name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
319
+
218
320
  // src/common/tempGzipFile.ts
219
321
  var import_buffer = require("buffer");
220
- var import_crypto = require("crypto");
322
+ var import_crypto2 = require("crypto");
221
323
  var import_fs = require("fs");
222
324
  var import_os = require("os");
223
325
  var import_path = require("path");
@@ -230,7 +332,7 @@ var _TempGzipFile = class _TempGzipFile {
230
332
  readyPromise;
231
333
  closedPromise;
232
334
  constructor() {
233
- this.uuid = (0, import_crypto.randomUUID)();
335
+ this.uuid = (0, import_crypto2.randomUUID)();
234
336
  this.filePath = (0, import_path.join)((0, import_os.tmpdir)(), `apitally-${this.uuid}.gz`);
235
337
  this.writeStream = (0, import_fs.createWriteStream)(this.filePath);
236
338
  this.readyPromise = new Promise((resolve, reject) => {
@@ -337,6 +439,7 @@ var DEFAULT_CONFIG = {
337
439
  logRequestBody: false,
338
440
  logResponseHeaders: true,
339
441
  logResponseBody: false,
442
+ logException: true,
340
443
  maskQueryParams: [],
341
444
  maskHeaders: [],
342
445
  excludePaths: []
@@ -409,7 +512,7 @@ var _RequestLogger = class _RequestLogger {
409
512
  this.shouldMaskHeader(k) ? MASKED : v
410
513
  ]);
411
514
  }
412
- logRequest(request, response) {
515
+ logRequest(request, response, error) {
413
516
  var _a2, _b, _c;
414
517
  if (!this.enabled || this.suspendUntil !== null) return;
415
518
  const url = new URL(request.url);
@@ -455,9 +558,15 @@ var _RequestLogger = class _RequestLogger {
455
558
  request.headers = this.config.logRequestHeaders ? this.maskHeaders(request.headers) : [];
456
559
  response.headers = this.config.logResponseHeaders ? this.maskHeaders(response.headers) : [];
457
560
  const item = {
458
- uuid: (0, import_crypto2.randomUUID)(),
561
+ uuid: (0, import_crypto3.randomUUID)(),
459
562
  request: skipEmptyValues(request),
460
- response: skipEmptyValues(response)
563
+ response: skipEmptyValues(response),
564
+ exception: error && this.config.logException ? {
565
+ type: error.name,
566
+ message: truncateExceptionMessage(error.message),
567
+ stacktrace: truncateExceptionStackTrace(error.stack || ""),
568
+ sentryEventId: getSentryEventId()
569
+ } : null
461
570
  };
462
571
  [
463
572
  item.request.body,
@@ -609,7 +718,7 @@ function skipEmptyValues(data) {
609
718
  __name(skipEmptyValues, "skipEmptyValues");
610
719
  function checkWritableFs() {
611
720
  try {
612
- const testPath = (0, import_path2.join)((0, import_os2.tmpdir)(), `apitally-${(0, import_crypto2.randomUUID)()}`);
721
+ const testPath = (0, import_path2.join)((0, import_os2.tmpdir)(), `apitally-${(0, import_crypto3.randomUUID)()}`);
613
722
  (0, import_fs2.writeFileSync)(testPath, "test");
614
723
  (0, import_fs2.unlinkSync)(testPath);
615
724
  return true;
@@ -619,104 +728,6 @@ function checkWritableFs() {
619
728
  }
620
729
  __name(checkWritableFs, "checkWritableFs");
621
730
 
622
- // src/common/serverErrorCounter.ts
623
- var import_crypto3 = require("crypto");
624
- var MAX_MSG_LENGTH = 2048;
625
- var MAX_STACKTRACE_LENGTH = 65536;
626
- var _ServerErrorCounter = class _ServerErrorCounter {
627
- errorCounts;
628
- errorDetails;
629
- sentryEventIds;
630
- sentry;
631
- constructor() {
632
- this.errorCounts = /* @__PURE__ */ new Map();
633
- this.errorDetails = /* @__PURE__ */ new Map();
634
- this.sentryEventIds = /* @__PURE__ */ new Map();
635
- this.tryImportSentry();
636
- }
637
- addServerError(serverError) {
638
- const key = this.getKey(serverError);
639
- if (!this.errorDetails.has(key)) {
640
- this.errorDetails.set(key, serverError);
641
- }
642
- this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
643
- this.captureSentryEventId(key);
644
- }
645
- getAndResetServerErrors() {
646
- const data = [];
647
- this.errorCounts.forEach((count, key) => {
648
- const serverError = this.errorDetails.get(key);
649
- if (serverError) {
650
- data.push({
651
- consumer: serverError.consumer || null,
652
- method: serverError.method,
653
- path: serverError.path,
654
- type: serverError.type,
655
- msg: this.getTruncatedMessage(serverError.msg),
656
- traceback: this.getTruncatedStack(serverError.traceback),
657
- sentry_event_id: this.sentryEventIds.get(key) || null,
658
- error_count: count
659
- });
660
- }
661
- });
662
- this.errorCounts.clear();
663
- this.errorDetails.clear();
664
- return data;
665
- }
666
- getKey(serverError) {
667
- const hashInput = [
668
- serverError.consumer || "",
669
- serverError.method.toUpperCase(),
670
- serverError.path,
671
- serverError.type,
672
- serverError.msg.trim(),
673
- serverError.traceback.trim()
674
- ].join("|");
675
- return (0, import_crypto3.createHash)("md5").update(hashInput).digest("hex");
676
- }
677
- getTruncatedMessage(msg) {
678
- msg = msg.trim();
679
- if (msg.length <= MAX_MSG_LENGTH) {
680
- return msg;
681
- }
682
- const suffix = "... (truncated)";
683
- const cutoff = MAX_MSG_LENGTH - suffix.length;
684
- return msg.substring(0, cutoff) + suffix;
685
- }
686
- getTruncatedStack(stack) {
687
- const suffix = "... (truncated) ...";
688
- const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
689
- const lines = stack.trim().split("\n");
690
- const truncatedLines = [];
691
- let length = 0;
692
- for (const line of lines) {
693
- if (length + line.length + 1 > cutoff) {
694
- truncatedLines.push(suffix);
695
- break;
696
- }
697
- truncatedLines.push(line);
698
- length += line.length + 1;
699
- }
700
- return truncatedLines.join("\n");
701
- }
702
- captureSentryEventId(serverErrorKey) {
703
- if (this.sentry && this.sentry.lastEventId) {
704
- const eventId = this.sentry.lastEventId();
705
- if (eventId) {
706
- this.sentryEventIds.set(serverErrorKey, eventId);
707
- }
708
- }
709
- }
710
- async tryImportSentry() {
711
- try {
712
- this.sentry = await import("@sentry/node");
713
- } catch (e) {
714
- }
715
- }
716
- };
717
- __name(_ServerErrorCounter, "ServerErrorCounter");
718
- var ServerErrorCounter = _ServerErrorCounter;
719
-
720
731
  // src/common/validationErrorCounter.ts
721
732
  var import_crypto4 = require("crypto");
722
733
  var _ValidationErrorCounter = class _ValidationErrorCounter {
@@ -802,7 +813,7 @@ var _ApitallyClient = class _ApitallyClient {
802
813
  throw new Error("Apitally client is already initialized");
803
814
  }
804
815
  if (!isValidClientId(clientId)) {
805
- throw new Error(`Invalid client ID '${clientId}' (expecting hexadeciaml UUID format)`);
816
+ throw new Error(`Invalid Apitally client ID '${clientId}' (expecting hexadecimal UUID format)`);
806
817
  }
807
818
  if (!isValidEnv(env)) {
808
819
  throw new Error(`Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`);
@@ -1076,6 +1087,7 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
1076
1087
  }
1077
1088
  let path;
1078
1089
  let statusCode;
1090
+ let serverError;
1079
1091
  const startTime = performance.now();
1080
1092
  try {
1081
1093
  await next();
@@ -1083,6 +1095,7 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
1083
1095
  path = getPath(ctx);
1084
1096
  statusCode = error.statusCode || error.status || 500;
1085
1097
  if (path && statusCode === 500 && error instanceof Error) {
1098
+ serverError = error;
1086
1099
  client.serverErrorCounter.addServerError({
1087
1100
  consumer: (_a2 = getConsumer(ctx)) == null ? void 0 : _a2.identifier,
1088
1101
  method: ctx.request.method,
@@ -1125,16 +1138,16 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
1125
1138
  path,
1126
1139
  url: ctx.request.href,
1127
1140
  headers: convertHeaders(ctx.request.headers),
1128
- size: Number(ctx.request.headers["content-length"]),
1141
+ size: ctx.request.length,
1129
1142
  consumer: consumer == null ? void 0 : consumer.identifier,
1130
1143
  body: convertBody(ctx.request.body, ctx.request.get("content-type"))
1131
1144
  }, {
1132
1145
  statusCode: statusCode || ctx.response.status,
1133
1146
  responseTime: responseTime / 1e3,
1134
1147
  headers: convertHeaders(ctx.response.headers),
1135
- size: Number(ctx.response.headers["content-length"]),
1148
+ size: ctx.response.length,
1136
1149
  body: convertBody(ctx.response.body, ctx.response.get("content-type"))
1137
- });
1150
+ }, serverError);
1138
1151
  }
1139
1152
  }
1140
1153
  };