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
@@ -190,6 +190,108 @@ import { unlinkSync as unlinkSync2, writeFileSync } from "fs";
190
190
  import { tmpdir as tmpdir2 } from "os";
191
191
  import { join as join2 } from "path";
192
192
 
193
+ // src/common/sentry.ts
194
+ var sentry;
195
+ (async () => {
196
+ try {
197
+ sentry = await import("@sentry/node");
198
+ } catch (e) {
199
+ }
200
+ })();
201
+ function getSentryEventId() {
202
+ if (sentry && sentry.lastEventId) {
203
+ return sentry.lastEventId();
204
+ }
205
+ return void 0;
206
+ }
207
+ __name(getSentryEventId, "getSentryEventId");
208
+
209
+ // src/common/serverErrorCounter.ts
210
+ import { createHash } from "crypto";
211
+ var MAX_MSG_LENGTH = 2048;
212
+ var MAX_STACKTRACE_LENGTH = 65536;
213
+ var _ServerErrorCounter = class _ServerErrorCounter {
214
+ errorCounts;
215
+ errorDetails;
216
+ sentryEventIds;
217
+ constructor() {
218
+ this.errorCounts = /* @__PURE__ */ new Map();
219
+ this.errorDetails = /* @__PURE__ */ new Map();
220
+ this.sentryEventIds = /* @__PURE__ */ new Map();
221
+ }
222
+ addServerError(serverError) {
223
+ const key = this.getKey(serverError);
224
+ if (!this.errorDetails.has(key)) {
225
+ this.errorDetails.set(key, serverError);
226
+ }
227
+ this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
228
+ const sentryEventId = getSentryEventId();
229
+ if (sentryEventId) {
230
+ this.sentryEventIds.set(key, sentryEventId);
231
+ }
232
+ }
233
+ getAndResetServerErrors() {
234
+ const data = [];
235
+ this.errorCounts.forEach((count, key) => {
236
+ const serverError = this.errorDetails.get(key);
237
+ if (serverError) {
238
+ data.push({
239
+ consumer: serverError.consumer || null,
240
+ method: serverError.method,
241
+ path: serverError.path,
242
+ type: serverError.type,
243
+ msg: truncateExceptionMessage(serverError.msg),
244
+ traceback: truncateExceptionStackTrace(serverError.traceback),
245
+ sentry_event_id: this.sentryEventIds.get(key) || null,
246
+ error_count: count
247
+ });
248
+ }
249
+ });
250
+ this.errorCounts.clear();
251
+ this.errorDetails.clear();
252
+ return data;
253
+ }
254
+ getKey(serverError) {
255
+ const hashInput = [
256
+ serverError.consumer || "",
257
+ serverError.method.toUpperCase(),
258
+ serverError.path,
259
+ serverError.type,
260
+ serverError.msg.trim(),
261
+ serverError.traceback.trim()
262
+ ].join("|");
263
+ return createHash("md5").update(hashInput).digest("hex");
264
+ }
265
+ };
266
+ __name(_ServerErrorCounter, "ServerErrorCounter");
267
+ var ServerErrorCounter = _ServerErrorCounter;
268
+ function truncateExceptionMessage(msg) {
269
+ if (msg.length <= MAX_MSG_LENGTH) {
270
+ return msg;
271
+ }
272
+ const suffix = "... (truncated)";
273
+ const cutoff = MAX_MSG_LENGTH - suffix.length;
274
+ return msg.substring(0, cutoff) + suffix;
275
+ }
276
+ __name(truncateExceptionMessage, "truncateExceptionMessage");
277
+ function truncateExceptionStackTrace(stack) {
278
+ const suffix = "... (truncated) ...";
279
+ const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
280
+ const lines = stack.trim().split("\n");
281
+ const truncatedLines = [];
282
+ let length = 0;
283
+ for (const line of lines) {
284
+ if (length + line.length + 1 > cutoff) {
285
+ truncatedLines.push(suffix);
286
+ break;
287
+ }
288
+ truncatedLines.push(line);
289
+ length += line.length + 1;
290
+ }
291
+ return truncatedLines.join("\n");
292
+ }
293
+ __name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
294
+
193
295
  // src/common/tempGzipFile.ts
194
296
  import { Buffer as Buffer2 } from "buffer";
195
297
  import { randomUUID } from "crypto";
@@ -312,6 +414,7 @@ var DEFAULT_CONFIG = {
312
414
  logRequestBody: false,
313
415
  logResponseHeaders: true,
314
416
  logResponseBody: false,
417
+ logException: true,
315
418
  maskQueryParams: [],
316
419
  maskHeaders: [],
317
420
  excludePaths: []
@@ -384,7 +487,7 @@ var _RequestLogger = class _RequestLogger {
384
487
  this.shouldMaskHeader(k) ? MASKED : v
385
488
  ]);
386
489
  }
387
- logRequest(request, response) {
490
+ logRequest(request, response, error) {
388
491
  var _a2, _b, _c;
389
492
  if (!this.enabled || this.suspendUntil !== null) return;
390
493
  const url = new URL(request.url);
@@ -432,7 +535,13 @@ var _RequestLogger = class _RequestLogger {
432
535
  const item = {
433
536
  uuid: randomUUID2(),
434
537
  request: skipEmptyValues(request),
435
- response: skipEmptyValues(response)
538
+ response: skipEmptyValues(response),
539
+ exception: error && this.config.logException ? {
540
+ type: error.name,
541
+ message: truncateExceptionMessage(error.message),
542
+ stacktrace: truncateExceptionStackTrace(error.stack || ""),
543
+ sentryEventId: getSentryEventId()
544
+ } : null
436
545
  };
437
546
  [
438
547
  item.request.body,
@@ -594,104 +703,6 @@ function checkWritableFs() {
594
703
  }
595
704
  __name(checkWritableFs, "checkWritableFs");
596
705
 
597
- // src/common/serverErrorCounter.ts
598
- import { createHash } from "crypto";
599
- var MAX_MSG_LENGTH = 2048;
600
- var MAX_STACKTRACE_LENGTH = 65536;
601
- var _ServerErrorCounter = class _ServerErrorCounter {
602
- errorCounts;
603
- errorDetails;
604
- sentryEventIds;
605
- sentry;
606
- constructor() {
607
- this.errorCounts = /* @__PURE__ */ new Map();
608
- this.errorDetails = /* @__PURE__ */ new Map();
609
- this.sentryEventIds = /* @__PURE__ */ new Map();
610
- this.tryImportSentry();
611
- }
612
- addServerError(serverError) {
613
- const key = this.getKey(serverError);
614
- if (!this.errorDetails.has(key)) {
615
- this.errorDetails.set(key, serverError);
616
- }
617
- this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
618
- this.captureSentryEventId(key);
619
- }
620
- getAndResetServerErrors() {
621
- const data = [];
622
- this.errorCounts.forEach((count, key) => {
623
- const serverError = this.errorDetails.get(key);
624
- if (serverError) {
625
- data.push({
626
- consumer: serverError.consumer || null,
627
- method: serverError.method,
628
- path: serverError.path,
629
- type: serverError.type,
630
- msg: this.getTruncatedMessage(serverError.msg),
631
- traceback: this.getTruncatedStack(serverError.traceback),
632
- sentry_event_id: this.sentryEventIds.get(key) || null,
633
- error_count: count
634
- });
635
- }
636
- });
637
- this.errorCounts.clear();
638
- this.errorDetails.clear();
639
- return data;
640
- }
641
- getKey(serverError) {
642
- const hashInput = [
643
- serverError.consumer || "",
644
- serverError.method.toUpperCase(),
645
- serverError.path,
646
- serverError.type,
647
- serverError.msg.trim(),
648
- serverError.traceback.trim()
649
- ].join("|");
650
- return createHash("md5").update(hashInput).digest("hex");
651
- }
652
- getTruncatedMessage(msg) {
653
- msg = msg.trim();
654
- if (msg.length <= MAX_MSG_LENGTH) {
655
- return msg;
656
- }
657
- const suffix = "... (truncated)";
658
- const cutoff = MAX_MSG_LENGTH - suffix.length;
659
- return msg.substring(0, cutoff) + suffix;
660
- }
661
- getTruncatedStack(stack) {
662
- const suffix = "... (truncated) ...";
663
- const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
664
- const lines = stack.trim().split("\n");
665
- const truncatedLines = [];
666
- let length = 0;
667
- for (const line of lines) {
668
- if (length + line.length + 1 > cutoff) {
669
- truncatedLines.push(suffix);
670
- break;
671
- }
672
- truncatedLines.push(line);
673
- length += line.length + 1;
674
- }
675
- return truncatedLines.join("\n");
676
- }
677
- captureSentryEventId(serverErrorKey) {
678
- if (this.sentry && this.sentry.lastEventId) {
679
- const eventId = this.sentry.lastEventId();
680
- if (eventId) {
681
- this.sentryEventIds.set(serverErrorKey, eventId);
682
- }
683
- }
684
- }
685
- async tryImportSentry() {
686
- try {
687
- this.sentry = await import("@sentry/node");
688
- } catch (e) {
689
- }
690
- }
691
- };
692
- __name(_ServerErrorCounter, "ServerErrorCounter");
693
- var ServerErrorCounter = _ServerErrorCounter;
694
-
695
706
  // src/common/validationErrorCounter.ts
696
707
  import { createHash as createHash2 } from "crypto";
697
708
  var _ValidationErrorCounter = class _ValidationErrorCounter {
@@ -777,7 +788,7 @@ var _ApitallyClient = class _ApitallyClient {
777
788
  throw new Error("Apitally client is already initialized");
778
789
  }
779
790
  if (!isValidClientId(clientId)) {
780
- throw new Error(`Invalid client ID '${clientId}' (expecting hexadeciaml UUID format)`);
791
+ throw new Error(`Invalid Apitally client ID '${clientId}' (expecting hexadecimal UUID format)`);
781
792
  }
782
793
  if (!isValidEnv(env)) {
783
794
  throw new Error(`Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`);
@@ -1032,6 +1043,25 @@ function getPackageVersion(name) {
1032
1043
  }
1033
1044
  __name(getPackageVersion, "getPackageVersion");
1034
1045
 
1046
+ // src/common/utils.ts
1047
+ function parseContentLength(contentLength) {
1048
+ if (contentLength === void 0 || contentLength === null) {
1049
+ return void 0;
1050
+ }
1051
+ if (typeof contentLength === "number") {
1052
+ return contentLength;
1053
+ }
1054
+ if (typeof contentLength === "string") {
1055
+ const parsed = parseInt(contentLength);
1056
+ return isNaN(parsed) ? void 0 : parsed;
1057
+ }
1058
+ if (Array.isArray(contentLength)) {
1059
+ return parseContentLength(contentLength[0]);
1060
+ }
1061
+ return void 0;
1062
+ }
1063
+ __name(parseContentLength, "parseContentLength");
1064
+
1035
1065
  // src/fastify/plugin.ts
1036
1066
  var apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
1037
1067
  const client = new ApitallyClient(config);
@@ -1079,11 +1109,8 @@ var apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
1079
1109
  if (client.isEnabled() && request.method.toUpperCase() !== "OPTIONS") {
1080
1110
  const consumer = getConsumer(request);
1081
1111
  const path = "routeOptions" in request ? request.routeOptions.url : request.routerPath;
1082
- const requestSize = request.headers["content-length"];
1083
- let responseSize = reply.getHeader("content-length");
1084
- if (Array.isArray(responseSize)) {
1085
- responseSize = responseSize[0];
1086
- }
1112
+ const requestSize = parseContentLength(request.headers["content-length"]);
1113
+ const responseSize = parseContentLength(reply.getHeader("content-length"));
1087
1114
  const responseTime = getResponseTime(reply);
1088
1115
  client.consumerRegistry.addOrUpdateConsumer(consumer);
1089
1116
  client.requestCounter.addRequest({
@@ -1138,7 +1165,7 @@ var apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
1138
1165
  headers: convertHeaders(reply.getHeaders()),
1139
1166
  size: Number(responseSize),
1140
1167
  body: convertBody(reply.payload, (_a2 = reply.getHeader("content-type")) == null ? void 0 : _a2.toString())
1141
- });
1168
+ }, reply.serverError);
1142
1169
  }
1143
1170
  }
1144
1171
  done();