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/express/utils.js
1036
1066
  var regExpToParseExpressPathRegExp = /^\/\^\\?\/?(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\\?\/?\([^)]+\)\)))\\\/.*/;
1037
1067
  var regExpToReplaceExpressPathRegExpParams = /\(\?:\\?\/?\([^)]+\)\)/;
@@ -1197,6 +1227,8 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
1197
1227
  const path = getRoutePath(req);
1198
1228
  const consumer = getConsumer(req);
1199
1229
  client.consumerRegistry.addOrUpdateConsumer(consumer);
1230
+ const requestSize = parseContentLength(req.get("content-length"));
1231
+ const responseSize = parseContentLength(res.get("content-length"));
1200
1232
  if (path) {
1201
1233
  client.requestCounter.addRequest({
1202
1234
  consumer: consumer == null ? void 0 : consumer.identifier,
@@ -1204,8 +1236,8 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
1204
1236
  path,
1205
1237
  statusCode: res.statusCode,
1206
1238
  responseTime,
1207
- requestSize: req.get("content-length"),
1208
- responseSize: res.get("content-length")
1239
+ requestSize,
1240
+ responseSize
1209
1241
  });
1210
1242
  if ((res.statusCode === 400 || res.statusCode === 422) && res.locals.body) {
1211
1243
  let jsonBody;
@@ -1253,16 +1285,16 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
1253
1285
  path,
1254
1286
  url: `${req.protocol}://${req.host}${req.originalUrl}`,
1255
1287
  headers: convertHeaders(req.headers),
1256
- size: Number(req.get("content-length")),
1288
+ size: requestSize,
1257
1289
  consumer: consumer == null ? void 0 : consumer.identifier,
1258
1290
  body: convertBody(req.body, req.get("content-type"))
1259
1291
  }, {
1260
1292
  statusCode: res.statusCode,
1261
1293
  responseTime: responseTime / 1e3,
1262
1294
  headers: convertHeaders(res.getHeaders()),
1263
- size: Number(res.get("content-length")),
1295
+ size: responseSize,
1264
1296
  body: convertBody(res.locals.body, res.get("content-type"))
1265
- });
1297
+ }, res.locals.serverError);
1266
1298
  }
1267
1299
  } catch (error) {
1268
1300
  client.logger.error("Error while logging request in Apitally middleware.", {