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
@@ -194,6 +194,108 @@ import { unlinkSync as unlinkSync2, writeFileSync } from "fs";
194
194
  import { tmpdir as tmpdir2 } from "os";
195
195
  import { join as join2 } from "path";
196
196
 
197
+ // src/common/sentry.ts
198
+ var sentry;
199
+ (async () => {
200
+ try {
201
+ sentry = await import("@sentry/node");
202
+ } catch (e) {
203
+ }
204
+ })();
205
+ function getSentryEventId() {
206
+ if (sentry && sentry.lastEventId) {
207
+ return sentry.lastEventId();
208
+ }
209
+ return void 0;
210
+ }
211
+ __name(getSentryEventId, "getSentryEventId");
212
+
213
+ // src/common/serverErrorCounter.ts
214
+ import { createHash } from "crypto";
215
+ var MAX_MSG_LENGTH = 2048;
216
+ var MAX_STACKTRACE_LENGTH = 65536;
217
+ var _ServerErrorCounter = class _ServerErrorCounter {
218
+ errorCounts;
219
+ errorDetails;
220
+ sentryEventIds;
221
+ constructor() {
222
+ this.errorCounts = /* @__PURE__ */ new Map();
223
+ this.errorDetails = /* @__PURE__ */ new Map();
224
+ this.sentryEventIds = /* @__PURE__ */ new Map();
225
+ }
226
+ addServerError(serverError) {
227
+ const key = this.getKey(serverError);
228
+ if (!this.errorDetails.has(key)) {
229
+ this.errorDetails.set(key, serverError);
230
+ }
231
+ this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
232
+ const sentryEventId = getSentryEventId();
233
+ if (sentryEventId) {
234
+ this.sentryEventIds.set(key, sentryEventId);
235
+ }
236
+ }
237
+ getAndResetServerErrors() {
238
+ const data = [];
239
+ this.errorCounts.forEach((count, key) => {
240
+ const serverError = this.errorDetails.get(key);
241
+ if (serverError) {
242
+ data.push({
243
+ consumer: serverError.consumer || null,
244
+ method: serverError.method,
245
+ path: serverError.path,
246
+ type: serverError.type,
247
+ msg: truncateExceptionMessage(serverError.msg),
248
+ traceback: truncateExceptionStackTrace(serverError.traceback),
249
+ sentry_event_id: this.sentryEventIds.get(key) || null,
250
+ error_count: count
251
+ });
252
+ }
253
+ });
254
+ this.errorCounts.clear();
255
+ this.errorDetails.clear();
256
+ return data;
257
+ }
258
+ getKey(serverError) {
259
+ const hashInput = [
260
+ serverError.consumer || "",
261
+ serverError.method.toUpperCase(),
262
+ serverError.path,
263
+ serverError.type,
264
+ serverError.msg.trim(),
265
+ serverError.traceback.trim()
266
+ ].join("|");
267
+ return createHash("md5").update(hashInput).digest("hex");
268
+ }
269
+ };
270
+ __name(_ServerErrorCounter, "ServerErrorCounter");
271
+ var ServerErrorCounter = _ServerErrorCounter;
272
+ function truncateExceptionMessage(msg) {
273
+ if (msg.length <= MAX_MSG_LENGTH) {
274
+ return msg;
275
+ }
276
+ const suffix = "... (truncated)";
277
+ const cutoff = MAX_MSG_LENGTH - suffix.length;
278
+ return msg.substring(0, cutoff) + suffix;
279
+ }
280
+ __name(truncateExceptionMessage, "truncateExceptionMessage");
281
+ function truncateExceptionStackTrace(stack) {
282
+ const suffix = "... (truncated) ...";
283
+ const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
284
+ const lines = stack.trim().split("\n");
285
+ const truncatedLines = [];
286
+ let length = 0;
287
+ for (const line of lines) {
288
+ if (length + line.length + 1 > cutoff) {
289
+ truncatedLines.push(suffix);
290
+ break;
291
+ }
292
+ truncatedLines.push(line);
293
+ length += line.length + 1;
294
+ }
295
+ return truncatedLines.join("\n");
296
+ }
297
+ __name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
298
+
197
299
  // src/common/tempGzipFile.ts
198
300
  import { Buffer as Buffer2 } from "buffer";
199
301
  import { randomUUID } from "crypto";
@@ -316,6 +418,7 @@ var DEFAULT_CONFIG = {
316
418
  logRequestBody: false,
317
419
  logResponseHeaders: true,
318
420
  logResponseBody: false,
421
+ logException: true,
319
422
  maskQueryParams: [],
320
423
  maskHeaders: [],
321
424
  excludePaths: []
@@ -388,7 +491,7 @@ var _RequestLogger = class _RequestLogger {
388
491
  this.shouldMaskHeader(k) ? MASKED : v
389
492
  ]);
390
493
  }
391
- logRequest(request, response) {
494
+ logRequest(request, response, error) {
392
495
  var _a3, _b, _c;
393
496
  if (!this.enabled || this.suspendUntil !== null) return;
394
497
  const url = new URL(request.url);
@@ -436,7 +539,13 @@ var _RequestLogger = class _RequestLogger {
436
539
  const item = {
437
540
  uuid: randomUUID2(),
438
541
  request: skipEmptyValues(request),
439
- response: skipEmptyValues(response)
542
+ response: skipEmptyValues(response),
543
+ exception: error && this.config.logException ? {
544
+ type: error.name,
545
+ message: truncateExceptionMessage(error.message),
546
+ stacktrace: truncateExceptionStackTrace(error.stack || ""),
547
+ sentryEventId: getSentryEventId()
548
+ } : null
440
549
  };
441
550
  [
442
551
  item.request.body,
@@ -598,104 +707,6 @@ function checkWritableFs() {
598
707
  }
599
708
  __name(checkWritableFs, "checkWritableFs");
600
709
 
601
- // src/common/serverErrorCounter.ts
602
- import { createHash } from "crypto";
603
- var MAX_MSG_LENGTH = 2048;
604
- var MAX_STACKTRACE_LENGTH = 65536;
605
- var _ServerErrorCounter = class _ServerErrorCounter {
606
- errorCounts;
607
- errorDetails;
608
- sentryEventIds;
609
- sentry;
610
- constructor() {
611
- this.errorCounts = /* @__PURE__ */ new Map();
612
- this.errorDetails = /* @__PURE__ */ new Map();
613
- this.sentryEventIds = /* @__PURE__ */ new Map();
614
- this.tryImportSentry();
615
- }
616
- addServerError(serverError) {
617
- const key = this.getKey(serverError);
618
- if (!this.errorDetails.has(key)) {
619
- this.errorDetails.set(key, serverError);
620
- }
621
- this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
622
- this.captureSentryEventId(key);
623
- }
624
- getAndResetServerErrors() {
625
- const data = [];
626
- this.errorCounts.forEach((count, key) => {
627
- const serverError = this.errorDetails.get(key);
628
- if (serverError) {
629
- data.push({
630
- consumer: serverError.consumer || null,
631
- method: serverError.method,
632
- path: serverError.path,
633
- type: serverError.type,
634
- msg: this.getTruncatedMessage(serverError.msg),
635
- traceback: this.getTruncatedStack(serverError.traceback),
636
- sentry_event_id: this.sentryEventIds.get(key) || null,
637
- error_count: count
638
- });
639
- }
640
- });
641
- this.errorCounts.clear();
642
- this.errorDetails.clear();
643
- return data;
644
- }
645
- getKey(serverError) {
646
- const hashInput = [
647
- serverError.consumer || "",
648
- serverError.method.toUpperCase(),
649
- serverError.path,
650
- serverError.type,
651
- serverError.msg.trim(),
652
- serverError.traceback.trim()
653
- ].join("|");
654
- return createHash("md5").update(hashInput).digest("hex");
655
- }
656
- getTruncatedMessage(msg) {
657
- msg = msg.trim();
658
- if (msg.length <= MAX_MSG_LENGTH) {
659
- return msg;
660
- }
661
- const suffix = "... (truncated)";
662
- const cutoff = MAX_MSG_LENGTH - suffix.length;
663
- return msg.substring(0, cutoff) + suffix;
664
- }
665
- getTruncatedStack(stack) {
666
- const suffix = "... (truncated) ...";
667
- const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
668
- const lines = stack.trim().split("\n");
669
- const truncatedLines = [];
670
- let length = 0;
671
- for (const line of lines) {
672
- if (length + line.length + 1 > cutoff) {
673
- truncatedLines.push(suffix);
674
- break;
675
- }
676
- truncatedLines.push(line);
677
- length += line.length + 1;
678
- }
679
- return truncatedLines.join("\n");
680
- }
681
- captureSentryEventId(serverErrorKey) {
682
- if (this.sentry && this.sentry.lastEventId) {
683
- const eventId = this.sentry.lastEventId();
684
- if (eventId) {
685
- this.sentryEventIds.set(serverErrorKey, eventId);
686
- }
687
- }
688
- }
689
- async tryImportSentry() {
690
- try {
691
- this.sentry = await import("@sentry/node");
692
- } catch (e) {
693
- }
694
- }
695
- };
696
- __name(_ServerErrorCounter, "ServerErrorCounter");
697
- var ServerErrorCounter = _ServerErrorCounter;
698
-
699
710
  // src/common/validationErrorCounter.ts
700
711
  import { createHash as createHash2 } from "crypto";
701
712
  var _ValidationErrorCounter = class _ValidationErrorCounter {
@@ -781,7 +792,7 @@ var _ApitallyClient = class _ApitallyClient {
781
792
  throw new Error("Apitally client is already initialized");
782
793
  }
783
794
  if (!isValidClientId(clientId)) {
784
- throw new Error(`Invalid client ID '${clientId}' (expecting hexadeciaml UUID format)`);
795
+ throw new Error(`Invalid Apitally client ID '${clientId}' (expecting hexadecimal UUID format)`);
785
796
  }
786
797
  if (!isValidEnv(env)) {
787
798
  throw new Error(`Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`);
@@ -1036,6 +1047,25 @@ function getPackageVersion(name) {
1036
1047
  }
1037
1048
  __name(getPackageVersion, "getPackageVersion");
1038
1049
 
1050
+ // src/common/utils.ts
1051
+ function parseContentLength(contentLength) {
1052
+ if (contentLength === void 0 || contentLength === null) {
1053
+ return void 0;
1054
+ }
1055
+ if (typeof contentLength === "number") {
1056
+ return contentLength;
1057
+ }
1058
+ if (typeof contentLength === "string") {
1059
+ const parsed = parseInt(contentLength);
1060
+ return isNaN(parsed) ? void 0 : parsed;
1061
+ }
1062
+ if (Array.isArray(contentLength)) {
1063
+ return parseContentLength(contentLength[0]);
1064
+ }
1065
+ return void 0;
1066
+ }
1067
+ __name(parseContentLength, "parseContentLength");
1068
+
1039
1069
  // src/express/utils.js
1040
1070
  var regExpToParseExpressPathRegExp = /^\/\^\\?\/?(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\\?\/?\([^)]+\)\)))\\\/.*/;
1041
1071
  var regExpToReplaceExpressPathRegExpParams = /\(\?:\\?\/?\([^)]+\)\)/;
@@ -1201,6 +1231,8 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
1201
1231
  const path = getRoutePath(req);
1202
1232
  const consumer = getConsumer(req);
1203
1233
  client.consumerRegistry.addOrUpdateConsumer(consumer);
1234
+ const requestSize = parseContentLength(req.get("content-length"));
1235
+ const responseSize = parseContentLength(res.get("content-length"));
1204
1236
  if (path) {
1205
1237
  client.requestCounter.addRequest({
1206
1238
  consumer: consumer == null ? void 0 : consumer.identifier,
@@ -1208,8 +1240,8 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
1208
1240
  path,
1209
1241
  statusCode: res.statusCode,
1210
1242
  responseTime,
1211
- requestSize: req.get("content-length"),
1212
- responseSize: res.get("content-length")
1243
+ requestSize,
1244
+ responseSize
1213
1245
  });
1214
1246
  if ((res.statusCode === 400 || res.statusCode === 422) && res.locals.body) {
1215
1247
  let jsonBody;
@@ -1257,16 +1289,16 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
1257
1289
  path,
1258
1290
  url: `${req.protocol}://${req.host}${req.originalUrl}`,
1259
1291
  headers: convertHeaders(req.headers),
1260
- size: Number(req.get("content-length")),
1292
+ size: requestSize,
1261
1293
  consumer: consumer == null ? void 0 : consumer.identifier,
1262
1294
  body: convertBody(req.body, req.get("content-type"))
1263
1295
  }, {
1264
1296
  statusCode: res.statusCode,
1265
1297
  responseTime: responseTime / 1e3,
1266
1298
  headers: convertHeaders(res.getHeaders()),
1267
- size: Number(res.get("content-length")),
1299
+ size: responseSize,
1268
1300
  body: convertBody(res.locals.body, res.get("content-type"))
1269
- });
1301
+ }, res.locals.serverError);
1270
1302
  }
1271
1303
  } catch (error) {
1272
1304
  client.logger.error("Error while logging request in Apitally middleware.", {