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
@@ -191,6 +191,108 @@ import { unlinkSync as unlinkSync2, writeFileSync } from "fs";
191
191
  import { tmpdir as tmpdir2 } from "os";
192
192
  import { join as join2 } from "path";
193
193
 
194
+ // src/common/sentry.ts
195
+ var sentry;
196
+ (async () => {
197
+ try {
198
+ sentry = await import("@sentry/node");
199
+ } catch (e) {
200
+ }
201
+ })();
202
+ function getSentryEventId() {
203
+ if (sentry && sentry.lastEventId) {
204
+ return sentry.lastEventId();
205
+ }
206
+ return void 0;
207
+ }
208
+ __name(getSentryEventId, "getSentryEventId");
209
+
210
+ // src/common/serverErrorCounter.ts
211
+ import { createHash } from "crypto";
212
+ var MAX_MSG_LENGTH = 2048;
213
+ var MAX_STACKTRACE_LENGTH = 65536;
214
+ var _ServerErrorCounter = class _ServerErrorCounter {
215
+ errorCounts;
216
+ errorDetails;
217
+ sentryEventIds;
218
+ constructor() {
219
+ this.errorCounts = /* @__PURE__ */ new Map();
220
+ this.errorDetails = /* @__PURE__ */ new Map();
221
+ this.sentryEventIds = /* @__PURE__ */ new Map();
222
+ }
223
+ addServerError(serverError) {
224
+ const key = this.getKey(serverError);
225
+ if (!this.errorDetails.has(key)) {
226
+ this.errorDetails.set(key, serverError);
227
+ }
228
+ this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
229
+ const sentryEventId = getSentryEventId();
230
+ if (sentryEventId) {
231
+ this.sentryEventIds.set(key, sentryEventId);
232
+ }
233
+ }
234
+ getAndResetServerErrors() {
235
+ const data = [];
236
+ this.errorCounts.forEach((count, key) => {
237
+ const serverError = this.errorDetails.get(key);
238
+ if (serverError) {
239
+ data.push({
240
+ consumer: serverError.consumer || null,
241
+ method: serverError.method,
242
+ path: serverError.path,
243
+ type: serverError.type,
244
+ msg: truncateExceptionMessage(serverError.msg),
245
+ traceback: truncateExceptionStackTrace(serverError.traceback),
246
+ sentry_event_id: this.sentryEventIds.get(key) || null,
247
+ error_count: count
248
+ });
249
+ }
250
+ });
251
+ this.errorCounts.clear();
252
+ this.errorDetails.clear();
253
+ return data;
254
+ }
255
+ getKey(serverError) {
256
+ const hashInput = [
257
+ serverError.consumer || "",
258
+ serverError.method.toUpperCase(),
259
+ serverError.path,
260
+ serverError.type,
261
+ serverError.msg.trim(),
262
+ serverError.traceback.trim()
263
+ ].join("|");
264
+ return createHash("md5").update(hashInput).digest("hex");
265
+ }
266
+ };
267
+ __name(_ServerErrorCounter, "ServerErrorCounter");
268
+ var ServerErrorCounter = _ServerErrorCounter;
269
+ function truncateExceptionMessage(msg) {
270
+ if (msg.length <= MAX_MSG_LENGTH) {
271
+ return msg;
272
+ }
273
+ const suffix = "... (truncated)";
274
+ const cutoff = MAX_MSG_LENGTH - suffix.length;
275
+ return msg.substring(0, cutoff) + suffix;
276
+ }
277
+ __name(truncateExceptionMessage, "truncateExceptionMessage");
278
+ function truncateExceptionStackTrace(stack) {
279
+ const suffix = "... (truncated) ...";
280
+ const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
281
+ const lines = stack.trim().split("\n");
282
+ const truncatedLines = [];
283
+ let length = 0;
284
+ for (const line of lines) {
285
+ if (length + line.length + 1 > cutoff) {
286
+ truncatedLines.push(suffix);
287
+ break;
288
+ }
289
+ truncatedLines.push(line);
290
+ length += line.length + 1;
291
+ }
292
+ return truncatedLines.join("\n");
293
+ }
294
+ __name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
295
+
194
296
  // src/common/tempGzipFile.ts
195
297
  import { Buffer as Buffer2 } from "buffer";
196
298
  import { randomUUID } from "crypto";
@@ -313,6 +415,7 @@ var DEFAULT_CONFIG = {
313
415
  logRequestBody: false,
314
416
  logResponseHeaders: true,
315
417
  logResponseBody: false,
418
+ logException: true,
316
419
  maskQueryParams: [],
317
420
  maskHeaders: [],
318
421
  excludePaths: []
@@ -385,7 +488,7 @@ var _RequestLogger = class _RequestLogger {
385
488
  this.shouldMaskHeader(k) ? MASKED : v
386
489
  ]);
387
490
  }
388
- logRequest(request, response) {
491
+ logRequest(request, response, error) {
389
492
  var _a2, _b, _c;
390
493
  if (!this.enabled || this.suspendUntil !== null) return;
391
494
  const url = new URL(request.url);
@@ -433,7 +536,13 @@ var _RequestLogger = class _RequestLogger {
433
536
  const item = {
434
537
  uuid: randomUUID2(),
435
538
  request: skipEmptyValues(request),
436
- response: skipEmptyValues(response)
539
+ response: skipEmptyValues(response),
540
+ exception: error && this.config.logException ? {
541
+ type: error.name,
542
+ message: truncateExceptionMessage(error.message),
543
+ stacktrace: truncateExceptionStackTrace(error.stack || ""),
544
+ sentryEventId: getSentryEventId()
545
+ } : null
437
546
  };
438
547
  [
439
548
  item.request.body,
@@ -563,104 +672,6 @@ function checkWritableFs() {
563
672
  }
564
673
  __name(checkWritableFs, "checkWritableFs");
565
674
 
566
- // src/common/serverErrorCounter.ts
567
- import { createHash } from "crypto";
568
- var MAX_MSG_LENGTH = 2048;
569
- var MAX_STACKTRACE_LENGTH = 65536;
570
- var _ServerErrorCounter = class _ServerErrorCounter {
571
- errorCounts;
572
- errorDetails;
573
- sentryEventIds;
574
- sentry;
575
- constructor() {
576
- this.errorCounts = /* @__PURE__ */ new Map();
577
- this.errorDetails = /* @__PURE__ */ new Map();
578
- this.sentryEventIds = /* @__PURE__ */ new Map();
579
- this.tryImportSentry();
580
- }
581
- addServerError(serverError) {
582
- const key = this.getKey(serverError);
583
- if (!this.errorDetails.has(key)) {
584
- this.errorDetails.set(key, serverError);
585
- }
586
- this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
587
- this.captureSentryEventId(key);
588
- }
589
- getAndResetServerErrors() {
590
- const data = [];
591
- this.errorCounts.forEach((count, key) => {
592
- const serverError = this.errorDetails.get(key);
593
- if (serverError) {
594
- data.push({
595
- consumer: serverError.consumer || null,
596
- method: serverError.method,
597
- path: serverError.path,
598
- type: serverError.type,
599
- msg: this.getTruncatedMessage(serverError.msg),
600
- traceback: this.getTruncatedStack(serverError.traceback),
601
- sentry_event_id: this.sentryEventIds.get(key) || null,
602
- error_count: count
603
- });
604
- }
605
- });
606
- this.errorCounts.clear();
607
- this.errorDetails.clear();
608
- return data;
609
- }
610
- getKey(serverError) {
611
- const hashInput = [
612
- serverError.consumer || "",
613
- serverError.method.toUpperCase(),
614
- serverError.path,
615
- serverError.type,
616
- serverError.msg.trim(),
617
- serverError.traceback.trim()
618
- ].join("|");
619
- return createHash("md5").update(hashInput).digest("hex");
620
- }
621
- getTruncatedMessage(msg) {
622
- msg = msg.trim();
623
- if (msg.length <= MAX_MSG_LENGTH) {
624
- return msg;
625
- }
626
- const suffix = "... (truncated)";
627
- const cutoff = MAX_MSG_LENGTH - suffix.length;
628
- return msg.substring(0, cutoff) + suffix;
629
- }
630
- getTruncatedStack(stack) {
631
- const suffix = "... (truncated) ...";
632
- const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
633
- const lines = stack.trim().split("\n");
634
- const truncatedLines = [];
635
- let length = 0;
636
- for (const line of lines) {
637
- if (length + line.length + 1 > cutoff) {
638
- truncatedLines.push(suffix);
639
- break;
640
- }
641
- truncatedLines.push(line);
642
- length += line.length + 1;
643
- }
644
- return truncatedLines.join("\n");
645
- }
646
- captureSentryEventId(serverErrorKey) {
647
- if (this.sentry && this.sentry.lastEventId) {
648
- const eventId = this.sentry.lastEventId();
649
- if (eventId) {
650
- this.sentryEventIds.set(serverErrorKey, eventId);
651
- }
652
- }
653
- }
654
- async tryImportSentry() {
655
- try {
656
- this.sentry = await import("@sentry/node");
657
- } catch (e) {
658
- }
659
- }
660
- };
661
- __name(_ServerErrorCounter, "ServerErrorCounter");
662
- var ServerErrorCounter = _ServerErrorCounter;
663
-
664
675
  // src/common/validationErrorCounter.ts
665
676
  import { createHash as createHash2 } from "crypto";
666
677
  var _ValidationErrorCounter = class _ValidationErrorCounter {
@@ -746,7 +757,7 @@ var _ApitallyClient = class _ApitallyClient {
746
757
  throw new Error("Apitally client is already initialized");
747
758
  }
748
759
  if (!isValidClientId(clientId)) {
749
- throw new Error(`Invalid client ID '${clientId}' (expecting hexadeciaml UUID format)`);
760
+ throw new Error(`Invalid Apitally client ID '${clientId}' (expecting hexadecimal UUID format)`);
750
761
  }
751
762
  if (!isValidEnv(env)) {
752
763
  throw new Error(`Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`);
@@ -1001,6 +1012,25 @@ function getPackageVersion(name) {
1001
1012
  }
1002
1013
  __name(getPackageVersion, "getPackageVersion");
1003
1014
 
1015
+ // src/common/utils.ts
1016
+ function parseContentLength(contentLength) {
1017
+ if (contentLength === void 0 || contentLength === null) {
1018
+ return void 0;
1019
+ }
1020
+ if (typeof contentLength === "number") {
1021
+ return contentLength;
1022
+ }
1023
+ if (typeof contentLength === "string") {
1024
+ const parsed = parseInt(contentLength);
1025
+ return isNaN(parsed) ? void 0 : parsed;
1026
+ }
1027
+ if (Array.isArray(contentLength)) {
1028
+ return parseContentLength(contentLength[0]);
1029
+ }
1030
+ return void 0;
1031
+ }
1032
+ __name(parseContentLength, "parseContentLength");
1033
+
1004
1034
  // src/hono/middleware.ts
1005
1035
  var useApitally = /* @__PURE__ */ __name((app, config) => {
1006
1036
  const client = new ApitallyClient(config);
@@ -1021,7 +1051,7 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
1021
1051
  let response;
1022
1052
  const responseTime = performance.now() - startTime;
1023
1053
  const [responseSize, newResponse] = await measureResponseSize(c.res);
1024
- const requestSize = c.req.header("Content-Length");
1054
+ const requestSize = parseContentLength(c.req.header("content-length"));
1025
1055
  const consumer = getConsumer(c);
1026
1056
  client.consumerRegistry.addOrUpdateConsumer(consumer);
1027
1057
  client.requestCounter.addRequest({
@@ -1084,7 +1114,7 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
1084
1114
  headers: convertHeaders(c.res.headers),
1085
1115
  size: responseSize,
1086
1116
  body: responseBody
1087
- });
1117
+ }, c.error);
1088
1118
  }
1089
1119
  c.res = response;
1090
1120
  };