apitally 0.11.5 → 0.12.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 (60) hide show
  1. package/README.md +2 -2
  2. package/dist/common/client.cjs +116 -105
  3. package/dist/common/client.cjs.map +1 -1
  4. package/dist/common/client.js +111 -100
  5. package/dist/common/client.js.map +1 -1
  6. package/dist/common/requestLogger.cjs +55 -2
  7. package/dist/common/requestLogger.cjs.map +1 -1
  8. package/dist/common/requestLogger.d.cts +2 -1
  9. package/dist/common/requestLogger.d.ts +2 -1
  10. package/dist/common/requestLogger.js +55 -2
  11. package/dist/common/requestLogger.js.map +1 -1
  12. package/dist/common/sentry.cjs +55 -0
  13. package/dist/common/sentry.cjs.map +1 -0
  14. package/dist/common/sentry.d.cts +6 -0
  15. package/dist/common/sentry.d.ts +6 -0
  16. package/dist/common/sentry.js +22 -0
  17. package/dist/common/sentry.js.map +1 -0
  18. package/dist/common/serverErrorCounter.cjs +58 -45
  19. package/dist/common/serverErrorCounter.cjs.map +1 -1
  20. package/dist/common/serverErrorCounter.d.cts +3 -6
  21. package/dist/common/serverErrorCounter.d.ts +3 -6
  22. package/dist/common/serverErrorCounter.js +53 -45
  23. package/dist/common/serverErrorCounter.js.map +1 -1
  24. package/dist/express/index.cjs +117 -106
  25. package/dist/express/index.cjs.map +1 -1
  26. package/dist/express/index.js +112 -101
  27. package/dist/express/index.js.map +1 -1
  28. package/dist/express/middleware.cjs +117 -106
  29. package/dist/express/middleware.cjs.map +1 -1
  30. package/dist/express/middleware.js +112 -101
  31. package/dist/express/middleware.js.map +1 -1
  32. package/dist/fastify/index.cjs +117 -106
  33. package/dist/fastify/index.cjs.map +1 -1
  34. package/dist/fastify/index.js +112 -101
  35. package/dist/fastify/index.js.map +1 -1
  36. package/dist/fastify/plugin.cjs +117 -106
  37. package/dist/fastify/plugin.cjs.map +1 -1
  38. package/dist/fastify/plugin.js +112 -101
  39. package/dist/fastify/plugin.js.map +1 -1
  40. package/dist/hono/index.cjs +117 -106
  41. package/dist/hono/index.cjs.map +1 -1
  42. package/dist/hono/index.js +112 -101
  43. package/dist/hono/index.js.map +1 -1
  44. package/dist/hono/middleware.cjs +117 -106
  45. package/dist/hono/middleware.cjs.map +1 -1
  46. package/dist/hono/middleware.js +112 -101
  47. package/dist/hono/middleware.js.map +1 -1
  48. package/dist/koa/index.cjs +119 -106
  49. package/dist/koa/index.cjs.map +1 -1
  50. package/dist/koa/index.js +114 -101
  51. package/dist/koa/index.js.map +1 -1
  52. package/dist/koa/middleware.cjs +119 -106
  53. package/dist/koa/middleware.cjs.map +1 -1
  54. package/dist/koa/middleware.js +114 -101
  55. package/dist/koa/middleware.js.map +1 -1
  56. package/dist/nestjs/index.cjs +117 -106
  57. package/dist/nestjs/index.cjs.map +1 -1
  58. package/dist/nestjs/index.js +112 -101
  59. package/dist/nestjs/index.js.map +1 -1
  60. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["serverErrorCounter.ts"],"sourcesContent":["import type * as Sentry from \"@sentry/node\";\nimport { createHash } from \"crypto\";\n\nimport { ConsumerMethodPath, ServerError, ServerErrorsItem } from \"./types.js\";\n\nconst MAX_MSG_LENGTH = 2048;\nconst MAX_STACKTRACE_LENGTH = 65536;\n\nexport default class ServerErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ServerError>;\n private sentryEventIds: Map<string, string>;\n private sentry: typeof Sentry | undefined;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n this.sentryEventIds = new Map();\n this.tryImportSentry();\n }\n\n public addServerError(serverError: ConsumerMethodPath & ServerError) {\n const key = this.getKey(serverError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, serverError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n this.captureSentryEventId(key);\n }\n\n public getAndResetServerErrors() {\n const data: Array<ServerErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const serverError = this.errorDetails.get(key);\n if (serverError) {\n data.push({\n consumer: serverError.consumer || null,\n method: serverError.method,\n path: serverError.path,\n type: serverError.type,\n msg: this.getTruncatedMessage(serverError.msg),\n traceback: this.getTruncatedStack(serverError.traceback),\n sentry_event_id: this.sentryEventIds.get(key) || null,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(serverError: ConsumerMethodPath & ServerError) {\n const hashInput = [\n serverError.consumer || \"\",\n serverError.method.toUpperCase(),\n serverError.path,\n serverError.type,\n serverError.msg.trim(),\n serverError.traceback.trim(),\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n\n private getTruncatedMessage(msg: string) {\n msg = msg.trim();\n if (msg.length <= MAX_MSG_LENGTH) {\n return msg;\n }\n const suffix = \"... (truncated)\";\n const cutoff = MAX_MSG_LENGTH - suffix.length;\n return msg.substring(0, cutoff) + suffix;\n }\n\n private getTruncatedStack(stack: string) {\n const suffix = \"... (truncated) ...\";\n const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;\n const lines = stack.trim().split(\"\\n\");\n const truncatedLines: string[] = [];\n let length = 0;\n for (const line of lines) {\n if (length + line.length + 1 > cutoff) {\n truncatedLines.push(suffix);\n break;\n }\n truncatedLines.push(line);\n length += line.length + 1;\n }\n return truncatedLines.join(\"\\n\");\n }\n\n private captureSentryEventId(serverErrorKey: string) {\n if (this.sentry && this.sentry.lastEventId) {\n const eventId = this.sentry.lastEventId();\n if (eventId) {\n this.sentryEventIds.set(serverErrorKey, eventId);\n }\n }\n }\n\n private async tryImportSentry() {\n try {\n this.sentry = await import(\"@sentry/node\");\n } catch (e) {\n // Sentry SDK is not installed, ignore\n }\n }\n}\n"],"mappings":"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","names":["MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","sentry","constructor","Map","tryImportSentry","addServerError","serverError","key","getKey","has","set","get","captureSentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","getTruncatedMessage","traceback","getTruncatedStack","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line","serverErrorKey","lastEventId","eventId","e"]}
1
+ {"version":3,"sources":["serverErrorCounter.ts","sentry.ts"],"sourcesContent":["import { createHash } from \"crypto\";\n\nimport { getSentryEventId } from \"./sentry.js\";\nimport { ConsumerMethodPath, ServerError, ServerErrorsItem } from \"./types.js\";\n\nconst MAX_MSG_LENGTH = 2048;\nconst MAX_STACKTRACE_LENGTH = 65536;\n\nexport default class ServerErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ServerError>;\n private sentryEventIds: Map<string, string>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n this.sentryEventIds = new Map();\n }\n\n public addServerError(serverError: ConsumerMethodPath & ServerError) {\n const key = this.getKey(serverError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, serverError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n\n const sentryEventId = getSentryEventId();\n if (sentryEventId) {\n this.sentryEventIds.set(key, sentryEventId);\n }\n }\n\n public getAndResetServerErrors() {\n const data: Array<ServerErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const serverError = this.errorDetails.get(key);\n if (serverError) {\n data.push({\n consumer: serverError.consumer || null,\n method: serverError.method,\n path: serverError.path,\n type: serverError.type,\n msg: truncateExceptionMessage(serverError.msg),\n traceback: truncateExceptionStackTrace(serverError.traceback),\n sentry_event_id: this.sentryEventIds.get(key) || null,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(serverError: ConsumerMethodPath & ServerError) {\n const hashInput = [\n serverError.consumer || \"\",\n serverError.method.toUpperCase(),\n serverError.path,\n serverError.type,\n serverError.msg.trim(),\n serverError.traceback.trim(),\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n\nexport function truncateExceptionMessage(msg: string) {\n if (msg.length <= MAX_MSG_LENGTH) {\n return msg;\n }\n const suffix = \"... (truncated)\";\n const cutoff = MAX_MSG_LENGTH - suffix.length;\n return msg.substring(0, cutoff) + suffix;\n}\n\nexport function truncateExceptionStackTrace(stack: string) {\n const suffix = \"... (truncated) ...\";\n const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;\n const lines = stack.trim().split(\"\\n\");\n const truncatedLines: string[] = [];\n let length = 0;\n for (const line of lines) {\n if (length + line.length + 1 > cutoff) {\n truncatedLines.push(suffix);\n break;\n }\n truncatedLines.push(line);\n length += line.length + 1;\n }\n return truncatedLines.join(\"\\n\");\n}\n","import type * as Sentry from \"@sentry/node\";\n\nlet sentry: typeof Sentry | undefined;\n\n// Initialize Sentry when the module is loaded\n(async () => {\n try {\n sentry = await import(\"@sentry/node\");\n } catch (e) {\n // Sentry SDK is not installed, ignore\n }\n})();\n\n/**\n * Returns the last Sentry event ID if available\n */\nexport function getSentryEventId(): string | undefined {\n if (sentry && sentry.lastEventId) {\n return sentry.lastEventId();\n }\n return undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;oBAA2B;;;ACE3B,IAAIA;CAGH,YAAA;AACC,MAAI;AACFA,aAAS,MAAM,OAAO,cAAA;EACxB,SAASC,GAAG;EAEZ;AACF,GAAA;AAKO,SAASC,mBAAAA;AACd,MAAIF,UAAUA,OAAOG,aAAa;AAChC,WAAOH,OAAOG,YAAW;EAC3B;AACA,SAAOC;AACT;AALgBF;;;ADXhB,IAAMG,iBAAiB;AACvB,IAAMC,wBAAwB;AAE9B,IAAqBC,sBAArB,MAAqBA,oBAAAA;EACXC;EACAC;EACAC;EAERC,cAAc;AACZ,SAAKH,cAAc,oBAAII,IAAAA;AACvB,SAAKH,eAAe,oBAAIG,IAAAA;AACxB,SAAKF,iBAAiB,oBAAIE,IAAAA;EAC5B;EAEOC,eAAeC,aAA+C;AACnE,UAAMC,MAAM,KAAKC,OAAOF,WAAAA;AACxB,QAAI,CAAC,KAAKL,aAAaQ,IAAIF,GAAAA,GAAM;AAC/B,WAAKN,aAAaS,IAAIH,KAAKD,WAAAA;IAC7B;AACA,SAAKN,YAAYU,IAAIH,MAAM,KAAKP,YAAYW,IAAIJ,GAAAA,KAAQ,KAAK,CAAA;AAE7D,UAAMK,gBAAgBC,iBAAAA;AACtB,QAAID,eAAe;AACjB,WAAKV,eAAeQ,IAAIH,KAAKK,aAAAA;IAC/B;EACF;EAEOE,0BAA0B;AAC/B,UAAMC,OAAgC,CAAA;AACtC,SAAKf,YAAYgB,QAAQ,CAACC,OAAOV,QAAAA;AAC/B,YAAMD,cAAc,KAAKL,aAAaU,IAAIJ,GAAAA;AAC1C,UAAID,aAAa;AACfS,aAAKG,KAAK;UACRC,UAAUb,YAAYa,YAAY;UAClCC,QAAQd,YAAYc;UACpBC,MAAMf,YAAYe;UAClBC,MAAMhB,YAAYgB;UAClBC,KAAKC,yBAAyBlB,YAAYiB,GAAG;UAC7CE,WAAWC,4BAA4BpB,YAAYmB,SAAS;UAC5DE,iBAAiB,KAAKzB,eAAeS,IAAIJ,GAAAA,KAAQ;UACjDqB,aAAaX;QACf,CAAA;MACF;IACF,CAAA;AACA,SAAKjB,YAAY6B,MAAK;AACtB,SAAK5B,aAAa4B,MAAK;AACvB,WAAOd;EACT;EAEQP,OAAOF,aAA+C;AAC5D,UAAMwB,YAAY;MAChBxB,YAAYa,YAAY;MACxBb,YAAYc,OAAOW,YAAW;MAC9BzB,YAAYe;MACZf,YAAYgB;MACZhB,YAAYiB,IAAIS,KAAI;MACpB1B,YAAYmB,UAAUO,KAAI;MAC1BC,KAAK,GAAA;AACP,eAAOC,0BAAW,KAAA,EAAOC,OAAOL,SAAAA,EAAWM,OAAO,KAAA;EACpD;AACF;AAzDqBrC;AAArB,IAAqBA,qBAArB;AA2DO,SAASyB,yBAAyBD,KAAW;AAClD,MAAIA,IAAIc,UAAUxC,gBAAgB;AAChC,WAAO0B;EACT;AACA,QAAMe,SAAS;AACf,QAAMC,SAAS1C,iBAAiByC,OAAOD;AACvC,SAAOd,IAAIiB,UAAU,GAAGD,MAAAA,IAAUD;AACpC;AAPgBd;AAST,SAASE,4BAA4Be,OAAa;AACvD,QAAMH,SAAS;AACf,QAAMC,SAASzC,wBAAwBwC,OAAOD;AAC9C,QAAMK,QAAQD,MAAMT,KAAI,EAAGW,MAAM,IAAA;AACjC,QAAMC,iBAA2B,CAAA;AACjC,MAAIP,SAAS;AACb,aAAWQ,QAAQH,OAAO;AACxB,QAAIL,SAASQ,KAAKR,SAAS,IAAIE,QAAQ;AACrCK,qBAAe1B,KAAKoB,MAAAA;AACpB;IACF;AACAM,mBAAe1B,KAAK2B,IAAAA;AACpBR,cAAUQ,KAAKR,SAAS;EAC1B;AACA,SAAOO,eAAeX,KAAK,IAAA;AAC7B;AAfgBP;","names":["sentry","e","getSentryEventId","lastEventId","undefined","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","constructor","Map","addServerError","serverError","key","getKey","has","set","get","sentryEventId","getSentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","truncateExceptionMessage","traceback","truncateExceptionStackTrace","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line"]}
@@ -10,15 +10,12 @@ declare class ServerErrorCounter {
10
10
  private errorCounts;
11
11
  private errorDetails;
12
12
  private sentryEventIds;
13
- private sentry;
14
13
  constructor();
15
14
  addServerError(serverError: ConsumerMethodPath & ServerError): void;
16
15
  getAndResetServerErrors(): ServerErrorsItem[];
17
16
  private getKey;
18
- private getTruncatedMessage;
19
- private getTruncatedStack;
20
- private captureSentryEventId;
21
- private tryImportSentry;
22
17
  }
18
+ declare function truncateExceptionMessage(msg: string): string;
19
+ declare function truncateExceptionStackTrace(stack: string): string;
23
20
 
24
- export { ServerErrorCounter as default };
21
+ export { ServerErrorCounter as default, truncateExceptionMessage, truncateExceptionStackTrace };
@@ -10,15 +10,12 @@ declare class ServerErrorCounter {
10
10
  private errorCounts;
11
11
  private errorDetails;
12
12
  private sentryEventIds;
13
- private sentry;
14
13
  constructor();
15
14
  addServerError(serverError: ConsumerMethodPath & ServerError): void;
16
15
  getAndResetServerErrors(): ServerErrorsItem[];
17
16
  private getKey;
18
- private getTruncatedMessage;
19
- private getTruncatedStack;
20
- private captureSentryEventId;
21
- private tryImportSentry;
22
17
  }
18
+ declare function truncateExceptionMessage(msg: string): string;
19
+ declare function truncateExceptionStackTrace(stack: string): string;
23
20
 
24
- export { ServerErrorCounter as default };
21
+ export { ServerErrorCounter as default, truncateExceptionMessage, truncateExceptionStackTrace };
@@ -3,18 +3,34 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
3
3
 
4
4
  // src/common/serverErrorCounter.ts
5
5
  import { createHash } from "crypto";
6
+
7
+ // src/common/sentry.ts
8
+ var sentry;
9
+ (async () => {
10
+ try {
11
+ sentry = await import("@sentry/node");
12
+ } catch (e) {
13
+ }
14
+ })();
15
+ function getSentryEventId() {
16
+ if (sentry && sentry.lastEventId) {
17
+ return sentry.lastEventId();
18
+ }
19
+ return void 0;
20
+ }
21
+ __name(getSentryEventId, "getSentryEventId");
22
+
23
+ // src/common/serverErrorCounter.ts
6
24
  var MAX_MSG_LENGTH = 2048;
7
25
  var MAX_STACKTRACE_LENGTH = 65536;
8
26
  var _ServerErrorCounter = class _ServerErrorCounter {
9
27
  errorCounts;
10
28
  errorDetails;
11
29
  sentryEventIds;
12
- sentry;
13
30
  constructor() {
14
31
  this.errorCounts = /* @__PURE__ */ new Map();
15
32
  this.errorDetails = /* @__PURE__ */ new Map();
16
33
  this.sentryEventIds = /* @__PURE__ */ new Map();
17
- this.tryImportSentry();
18
34
  }
19
35
  addServerError(serverError) {
20
36
  const key = this.getKey(serverError);
@@ -22,7 +38,10 @@ var _ServerErrorCounter = class _ServerErrorCounter {
22
38
  this.errorDetails.set(key, serverError);
23
39
  }
24
40
  this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
25
- this.captureSentryEventId(key);
41
+ const sentryEventId = getSentryEventId();
42
+ if (sentryEventId) {
43
+ this.sentryEventIds.set(key, sentryEventId);
44
+ }
26
45
  }
27
46
  getAndResetServerErrors() {
28
47
  const data = [];
@@ -34,8 +53,8 @@ var _ServerErrorCounter = class _ServerErrorCounter {
34
53
  method: serverError.method,
35
54
  path: serverError.path,
36
55
  type: serverError.type,
37
- msg: this.getTruncatedMessage(serverError.msg),
38
- traceback: this.getTruncatedStack(serverError.traceback),
56
+ msg: truncateExceptionMessage(serverError.msg),
57
+ traceback: truncateExceptionStackTrace(serverError.traceback),
39
58
  sentry_event_id: this.sentryEventIds.get(key) || null,
40
59
  error_count: count
41
60
  });
@@ -56,49 +75,38 @@ var _ServerErrorCounter = class _ServerErrorCounter {
56
75
  ].join("|");
57
76
  return createHash("md5").update(hashInput).digest("hex");
58
77
  }
59
- getTruncatedMessage(msg) {
60
- msg = msg.trim();
61
- if (msg.length <= MAX_MSG_LENGTH) {
62
- return msg;
63
- }
64
- const suffix = "... (truncated)";
65
- const cutoff = MAX_MSG_LENGTH - suffix.length;
66
- return msg.substring(0, cutoff) + suffix;
67
- }
68
- getTruncatedStack(stack) {
69
- const suffix = "... (truncated) ...";
70
- const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
71
- const lines = stack.trim().split("\n");
72
- const truncatedLines = [];
73
- let length = 0;
74
- for (const line of lines) {
75
- if (length + line.length + 1 > cutoff) {
76
- truncatedLines.push(suffix);
77
- break;
78
- }
79
- truncatedLines.push(line);
80
- length += line.length + 1;
81
- }
82
- return truncatedLines.join("\n");
83
- }
84
- captureSentryEventId(serverErrorKey) {
85
- if (this.sentry && this.sentry.lastEventId) {
86
- const eventId = this.sentry.lastEventId();
87
- if (eventId) {
88
- this.sentryEventIds.set(serverErrorKey, eventId);
89
- }
90
- }
91
- }
92
- async tryImportSentry() {
93
- try {
94
- this.sentry = await import("@sentry/node");
95
- } catch (e) {
96
- }
97
- }
98
78
  };
99
79
  __name(_ServerErrorCounter, "ServerErrorCounter");
100
80
  var ServerErrorCounter = _ServerErrorCounter;
81
+ function truncateExceptionMessage(msg) {
82
+ if (msg.length <= MAX_MSG_LENGTH) {
83
+ return msg;
84
+ }
85
+ const suffix = "... (truncated)";
86
+ const cutoff = MAX_MSG_LENGTH - suffix.length;
87
+ return msg.substring(0, cutoff) + suffix;
88
+ }
89
+ __name(truncateExceptionMessage, "truncateExceptionMessage");
90
+ function truncateExceptionStackTrace(stack) {
91
+ const suffix = "... (truncated) ...";
92
+ const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
93
+ const lines = stack.trim().split("\n");
94
+ const truncatedLines = [];
95
+ let length = 0;
96
+ for (const line of lines) {
97
+ if (length + line.length + 1 > cutoff) {
98
+ truncatedLines.push(suffix);
99
+ break;
100
+ }
101
+ truncatedLines.push(line);
102
+ length += line.length + 1;
103
+ }
104
+ return truncatedLines.join("\n");
105
+ }
106
+ __name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
101
107
  export {
102
- ServerErrorCounter as default
108
+ ServerErrorCounter as default,
109
+ truncateExceptionMessage,
110
+ truncateExceptionStackTrace
103
111
  };
104
112
  //# sourceMappingURL=serverErrorCounter.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["serverErrorCounter.ts"],"sourcesContent":["import type * as Sentry from \"@sentry/node\";\nimport { createHash } from \"crypto\";\n\nimport { ConsumerMethodPath, ServerError, ServerErrorsItem } from \"./types.js\";\n\nconst MAX_MSG_LENGTH = 2048;\nconst MAX_STACKTRACE_LENGTH = 65536;\n\nexport default class ServerErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ServerError>;\n private sentryEventIds: Map<string, string>;\n private sentry: typeof Sentry | undefined;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n this.sentryEventIds = new Map();\n this.tryImportSentry();\n }\n\n public addServerError(serverError: ConsumerMethodPath & ServerError) {\n const key = this.getKey(serverError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, serverError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n this.captureSentryEventId(key);\n }\n\n public getAndResetServerErrors() {\n const data: Array<ServerErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const serverError = this.errorDetails.get(key);\n if (serverError) {\n data.push({\n consumer: serverError.consumer || null,\n method: serverError.method,\n path: serverError.path,\n type: serverError.type,\n msg: this.getTruncatedMessage(serverError.msg),\n traceback: this.getTruncatedStack(serverError.traceback),\n sentry_event_id: this.sentryEventIds.get(key) || null,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(serverError: ConsumerMethodPath & ServerError) {\n const hashInput = [\n serverError.consumer || \"\",\n serverError.method.toUpperCase(),\n serverError.path,\n serverError.type,\n serverError.msg.trim(),\n serverError.traceback.trim(),\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n\n private getTruncatedMessage(msg: string) {\n msg = msg.trim();\n if (msg.length <= MAX_MSG_LENGTH) {\n return msg;\n }\n const suffix = \"... (truncated)\";\n const cutoff = MAX_MSG_LENGTH - suffix.length;\n return msg.substring(0, cutoff) + suffix;\n }\n\n private getTruncatedStack(stack: string) {\n const suffix = \"... (truncated) ...\";\n const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;\n const lines = stack.trim().split(\"\\n\");\n const truncatedLines: string[] = [];\n let length = 0;\n for (const line of lines) {\n if (length + line.length + 1 > cutoff) {\n truncatedLines.push(suffix);\n break;\n }\n truncatedLines.push(line);\n length += line.length + 1;\n }\n return truncatedLines.join(\"\\n\");\n }\n\n private captureSentryEventId(serverErrorKey: string) {\n if (this.sentry && this.sentry.lastEventId) {\n const eventId = this.sentry.lastEventId();\n if (eventId) {\n this.sentryEventIds.set(serverErrorKey, eventId);\n }\n }\n }\n\n private async tryImportSentry() {\n try {\n this.sentry = await import(\"@sentry/node\");\n } catch (e) {\n // Sentry SDK is not installed, ignore\n }\n }\n}\n"],"mappings":"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","names":["createHash","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","sentry","constructor","Map","tryImportSentry","addServerError","serverError","key","getKey","has","set","get","captureSentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","getTruncatedMessage","traceback","getTruncatedStack","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line","serverErrorKey","lastEventId","eventId","e"]}
1
+ {"version":3,"sources":["serverErrorCounter.ts","sentry.ts"],"sourcesContent":["import { createHash } from \"crypto\";\n\nimport { getSentryEventId } from \"./sentry.js\";\nimport { ConsumerMethodPath, ServerError, ServerErrorsItem } from \"./types.js\";\n\nconst MAX_MSG_LENGTH = 2048;\nconst MAX_STACKTRACE_LENGTH = 65536;\n\nexport default class ServerErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ServerError>;\n private sentryEventIds: Map<string, string>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n this.sentryEventIds = new Map();\n }\n\n public addServerError(serverError: ConsumerMethodPath & ServerError) {\n const key = this.getKey(serverError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, serverError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n\n const sentryEventId = getSentryEventId();\n if (sentryEventId) {\n this.sentryEventIds.set(key, sentryEventId);\n }\n }\n\n public getAndResetServerErrors() {\n const data: Array<ServerErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const serverError = this.errorDetails.get(key);\n if (serverError) {\n data.push({\n consumer: serverError.consumer || null,\n method: serverError.method,\n path: serverError.path,\n type: serverError.type,\n msg: truncateExceptionMessage(serverError.msg),\n traceback: truncateExceptionStackTrace(serverError.traceback),\n sentry_event_id: this.sentryEventIds.get(key) || null,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(serverError: ConsumerMethodPath & ServerError) {\n const hashInput = [\n serverError.consumer || \"\",\n serverError.method.toUpperCase(),\n serverError.path,\n serverError.type,\n serverError.msg.trim(),\n serverError.traceback.trim(),\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n\nexport function truncateExceptionMessage(msg: string) {\n if (msg.length <= MAX_MSG_LENGTH) {\n return msg;\n }\n const suffix = \"... (truncated)\";\n const cutoff = MAX_MSG_LENGTH - suffix.length;\n return msg.substring(0, cutoff) + suffix;\n}\n\nexport function truncateExceptionStackTrace(stack: string) {\n const suffix = \"... (truncated) ...\";\n const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;\n const lines = stack.trim().split(\"\\n\");\n const truncatedLines: string[] = [];\n let length = 0;\n for (const line of lines) {\n if (length + line.length + 1 > cutoff) {\n truncatedLines.push(suffix);\n break;\n }\n truncatedLines.push(line);\n length += line.length + 1;\n }\n return truncatedLines.join(\"\\n\");\n}\n","import type * as Sentry from \"@sentry/node\";\n\nlet sentry: typeof Sentry | undefined;\n\n// Initialize Sentry when the module is loaded\n(async () => {\n try {\n sentry = await import(\"@sentry/node\");\n } catch (e) {\n // Sentry SDK is not installed, ignore\n }\n})();\n\n/**\n * Returns the last Sentry event ID if available\n */\nexport function getSentryEventId(): string | undefined {\n if (sentry && sentry.lastEventId) {\n return sentry.lastEventId();\n }\n return undefined;\n}\n"],"mappings":";;;;AAAA,SAASA,kBAAkB;;;ACE3B,IAAIC;CAGH,YAAA;AACC,MAAI;AACFA,aAAS,MAAM,OAAO,cAAA;EACxB,SAASC,GAAG;EAEZ;AACF,GAAA;AAKO,SAASC,mBAAAA;AACd,MAAIF,UAAUA,OAAOG,aAAa;AAChC,WAAOH,OAAOG,YAAW;EAC3B;AACA,SAAOC;AACT;AALgBF;;;ADXhB,IAAMG,iBAAiB;AACvB,IAAMC,wBAAwB;AAE9B,IAAqBC,sBAArB,MAAqBA,oBAAAA;EACXC;EACAC;EACAC;EAERC,cAAc;AACZ,SAAKH,cAAc,oBAAII,IAAAA;AACvB,SAAKH,eAAe,oBAAIG,IAAAA;AACxB,SAAKF,iBAAiB,oBAAIE,IAAAA;EAC5B;EAEOC,eAAeC,aAA+C;AACnE,UAAMC,MAAM,KAAKC,OAAOF,WAAAA;AACxB,QAAI,CAAC,KAAKL,aAAaQ,IAAIF,GAAAA,GAAM;AAC/B,WAAKN,aAAaS,IAAIH,KAAKD,WAAAA;IAC7B;AACA,SAAKN,YAAYU,IAAIH,MAAM,KAAKP,YAAYW,IAAIJ,GAAAA,KAAQ,KAAK,CAAA;AAE7D,UAAMK,gBAAgBC,iBAAAA;AACtB,QAAID,eAAe;AACjB,WAAKV,eAAeQ,IAAIH,KAAKK,aAAAA;IAC/B;EACF;EAEOE,0BAA0B;AAC/B,UAAMC,OAAgC,CAAA;AACtC,SAAKf,YAAYgB,QAAQ,CAACC,OAAOV,QAAAA;AAC/B,YAAMD,cAAc,KAAKL,aAAaU,IAAIJ,GAAAA;AAC1C,UAAID,aAAa;AACfS,aAAKG,KAAK;UACRC,UAAUb,YAAYa,YAAY;UAClCC,QAAQd,YAAYc;UACpBC,MAAMf,YAAYe;UAClBC,MAAMhB,YAAYgB;UAClBC,KAAKC,yBAAyBlB,YAAYiB,GAAG;UAC7CE,WAAWC,4BAA4BpB,YAAYmB,SAAS;UAC5DE,iBAAiB,KAAKzB,eAAeS,IAAIJ,GAAAA,KAAQ;UACjDqB,aAAaX;QACf,CAAA;MACF;IACF,CAAA;AACA,SAAKjB,YAAY6B,MAAK;AACtB,SAAK5B,aAAa4B,MAAK;AACvB,WAAOd;EACT;EAEQP,OAAOF,aAA+C;AAC5D,UAAMwB,YAAY;MAChBxB,YAAYa,YAAY;MACxBb,YAAYc,OAAOW,YAAW;MAC9BzB,YAAYe;MACZf,YAAYgB;MACZhB,YAAYiB,IAAIS,KAAI;MACpB1B,YAAYmB,UAAUO,KAAI;MAC1BC,KAAK,GAAA;AACP,WAAOC,WAAW,KAAA,EAAOC,OAAOL,SAAAA,EAAWM,OAAO,KAAA;EACpD;AACF;AAzDqBrC;AAArB,IAAqBA,qBAArB;AA2DO,SAASyB,yBAAyBD,KAAW;AAClD,MAAIA,IAAIc,UAAUxC,gBAAgB;AAChC,WAAO0B;EACT;AACA,QAAMe,SAAS;AACf,QAAMC,SAAS1C,iBAAiByC,OAAOD;AACvC,SAAOd,IAAIiB,UAAU,GAAGD,MAAAA,IAAUD;AACpC;AAPgBd;AAST,SAASE,4BAA4Be,OAAa;AACvD,QAAMH,SAAS;AACf,QAAMC,SAASzC,wBAAwBwC,OAAOD;AAC9C,QAAMK,QAAQD,MAAMT,KAAI,EAAGW,MAAM,IAAA;AACjC,QAAMC,iBAA2B,CAAA;AACjC,MAAIP,SAAS;AACb,aAAWQ,QAAQH,OAAO;AACxB,QAAIL,SAASQ,KAAKR,SAAS,IAAIE,QAAQ;AACrCK,qBAAe1B,KAAKoB,MAAAA;AACpB;IACF;AACAM,mBAAe1B,KAAK2B,IAAAA;AACpBR,cAAUQ,KAAKR,SAAS;EAC1B;AACA,SAAOO,eAAeX,KAAK,IAAA;AAC7B;AAfgBP;","names":["createHash","sentry","e","getSentryEventId","lastEventId","undefined","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","constructor","Map","addServerError","serverError","key","getKey","has","set","get","sentryEventId","getSentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","truncateExceptionMessage","traceback","truncateExceptionStackTrace","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line"]}
@@ -213,14 +213,116 @@ var RequestCounter = _RequestCounter;
213
213
  // src/common/requestLogger.ts
214
214
  var import_async_lock = __toESM(require("async-lock"), 1);
215
215
  var import_buffer2 = require("buffer");
216
- var import_crypto2 = require("crypto");
216
+ var import_crypto3 = require("crypto");
217
217
  var import_fs2 = require("fs");
218
218
  var import_os2 = require("os");
219
219
  var import_path2 = require("path");
220
220
 
221
+ // src/common/sentry.ts
222
+ var sentry;
223
+ (async () => {
224
+ try {
225
+ sentry = await import("@sentry/node");
226
+ } catch (e) {
227
+ }
228
+ })();
229
+ function getSentryEventId() {
230
+ if (sentry && sentry.lastEventId) {
231
+ return sentry.lastEventId();
232
+ }
233
+ return void 0;
234
+ }
235
+ __name(getSentryEventId, "getSentryEventId");
236
+
237
+ // src/common/serverErrorCounter.ts
238
+ var import_crypto = require("crypto");
239
+ var MAX_MSG_LENGTH = 2048;
240
+ var MAX_STACKTRACE_LENGTH = 65536;
241
+ var _ServerErrorCounter = class _ServerErrorCounter {
242
+ errorCounts;
243
+ errorDetails;
244
+ sentryEventIds;
245
+ constructor() {
246
+ this.errorCounts = /* @__PURE__ */ new Map();
247
+ this.errorDetails = /* @__PURE__ */ new Map();
248
+ this.sentryEventIds = /* @__PURE__ */ new Map();
249
+ }
250
+ addServerError(serverError) {
251
+ const key = this.getKey(serverError);
252
+ if (!this.errorDetails.has(key)) {
253
+ this.errorDetails.set(key, serverError);
254
+ }
255
+ this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
256
+ const sentryEventId = getSentryEventId();
257
+ if (sentryEventId) {
258
+ this.sentryEventIds.set(key, sentryEventId);
259
+ }
260
+ }
261
+ getAndResetServerErrors() {
262
+ const data = [];
263
+ this.errorCounts.forEach((count, key) => {
264
+ const serverError = this.errorDetails.get(key);
265
+ if (serverError) {
266
+ data.push({
267
+ consumer: serverError.consumer || null,
268
+ method: serverError.method,
269
+ path: serverError.path,
270
+ type: serverError.type,
271
+ msg: truncateExceptionMessage(serverError.msg),
272
+ traceback: truncateExceptionStackTrace(serverError.traceback),
273
+ sentry_event_id: this.sentryEventIds.get(key) || null,
274
+ error_count: count
275
+ });
276
+ }
277
+ });
278
+ this.errorCounts.clear();
279
+ this.errorDetails.clear();
280
+ return data;
281
+ }
282
+ getKey(serverError) {
283
+ const hashInput = [
284
+ serverError.consumer || "",
285
+ serverError.method.toUpperCase(),
286
+ serverError.path,
287
+ serverError.type,
288
+ serverError.msg.trim(),
289
+ serverError.traceback.trim()
290
+ ].join("|");
291
+ return (0, import_crypto.createHash)("md5").update(hashInput).digest("hex");
292
+ }
293
+ };
294
+ __name(_ServerErrorCounter, "ServerErrorCounter");
295
+ var ServerErrorCounter = _ServerErrorCounter;
296
+ function truncateExceptionMessage(msg) {
297
+ if (msg.length <= MAX_MSG_LENGTH) {
298
+ return msg;
299
+ }
300
+ const suffix = "... (truncated)";
301
+ const cutoff = MAX_MSG_LENGTH - suffix.length;
302
+ return msg.substring(0, cutoff) + suffix;
303
+ }
304
+ __name(truncateExceptionMessage, "truncateExceptionMessage");
305
+ function truncateExceptionStackTrace(stack) {
306
+ const suffix = "... (truncated) ...";
307
+ const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
308
+ const lines = stack.trim().split("\n");
309
+ const truncatedLines = [];
310
+ let length = 0;
311
+ for (const line of lines) {
312
+ if (length + line.length + 1 > cutoff) {
313
+ truncatedLines.push(suffix);
314
+ break;
315
+ }
316
+ truncatedLines.push(line);
317
+ length += line.length + 1;
318
+ }
319
+ return truncatedLines.join("\n");
320
+ }
321
+ __name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
322
+
221
323
  // src/common/tempGzipFile.ts
222
324
  var import_buffer = require("buffer");
223
- var import_crypto = require("crypto");
325
+ var import_crypto2 = require("crypto");
224
326
  var import_fs = require("fs");
225
327
  var import_os = require("os");
226
328
  var import_path = require("path");
@@ -233,7 +335,7 @@ var _TempGzipFile = class _TempGzipFile {
233
335
  readyPromise;
234
336
  closedPromise;
235
337
  constructor() {
236
- this.uuid = (0, import_crypto.randomUUID)();
338
+ this.uuid = (0, import_crypto2.randomUUID)();
237
339
  this.filePath = (0, import_path.join)((0, import_os.tmpdir)(), `apitally-${this.uuid}.gz`);
238
340
  this.writeStream = (0, import_fs.createWriteStream)(this.filePath);
239
341
  this.readyPromise = new Promise((resolve, reject) => {
@@ -340,6 +442,7 @@ var DEFAULT_CONFIG = {
340
442
  logRequestBody: false,
341
443
  logResponseHeaders: true,
342
444
  logResponseBody: false,
445
+ logException: true,
343
446
  maskQueryParams: [],
344
447
  maskHeaders: [],
345
448
  excludePaths: []
@@ -412,7 +515,7 @@ var _RequestLogger = class _RequestLogger {
412
515
  this.shouldMaskHeader(k) ? MASKED : v
413
516
  ]);
414
517
  }
415
- logRequest(request, response) {
518
+ logRequest(request, response, error) {
416
519
  var _a2, _b, _c;
417
520
  if (!this.enabled || this.suspendUntil !== null) return;
418
521
  const url = new URL(request.url);
@@ -458,9 +561,15 @@ var _RequestLogger = class _RequestLogger {
458
561
  request.headers = this.config.logRequestHeaders ? this.maskHeaders(request.headers) : [];
459
562
  response.headers = this.config.logResponseHeaders ? this.maskHeaders(response.headers) : [];
460
563
  const item = {
461
- uuid: (0, import_crypto2.randomUUID)(),
564
+ uuid: (0, import_crypto3.randomUUID)(),
462
565
  request: skipEmptyValues(request),
463
- response: skipEmptyValues(response)
566
+ response: skipEmptyValues(response),
567
+ exception: error && this.config.logException ? {
568
+ type: error.name,
569
+ message: truncateExceptionMessage(error.message),
570
+ stacktrace: truncateExceptionStackTrace(error.stack || ""),
571
+ sentryEventId: getSentryEventId()
572
+ } : null
464
573
  };
465
574
  [
466
575
  item.request.body,
@@ -612,7 +721,7 @@ function skipEmptyValues(data) {
612
721
  __name(skipEmptyValues, "skipEmptyValues");
613
722
  function checkWritableFs() {
614
723
  try {
615
- const testPath = (0, import_path2.join)((0, import_os2.tmpdir)(), `apitally-${(0, import_crypto2.randomUUID)()}`);
724
+ const testPath = (0, import_path2.join)((0, import_os2.tmpdir)(), `apitally-${(0, import_crypto3.randomUUID)()}`);
616
725
  (0, import_fs2.writeFileSync)(testPath, "test");
617
726
  (0, import_fs2.unlinkSync)(testPath);
618
727
  return true;
@@ -622,104 +731,6 @@ function checkWritableFs() {
622
731
  }
623
732
  __name(checkWritableFs, "checkWritableFs");
624
733
 
625
- // src/common/serverErrorCounter.ts
626
- var import_crypto3 = require("crypto");
627
- var MAX_MSG_LENGTH = 2048;
628
- var MAX_STACKTRACE_LENGTH = 65536;
629
- var _ServerErrorCounter = class _ServerErrorCounter {
630
- errorCounts;
631
- errorDetails;
632
- sentryEventIds;
633
- sentry;
634
- constructor() {
635
- this.errorCounts = /* @__PURE__ */ new Map();
636
- this.errorDetails = /* @__PURE__ */ new Map();
637
- this.sentryEventIds = /* @__PURE__ */ new Map();
638
- this.tryImportSentry();
639
- }
640
- addServerError(serverError) {
641
- const key = this.getKey(serverError);
642
- if (!this.errorDetails.has(key)) {
643
- this.errorDetails.set(key, serverError);
644
- }
645
- this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
646
- this.captureSentryEventId(key);
647
- }
648
- getAndResetServerErrors() {
649
- const data = [];
650
- this.errorCounts.forEach((count, key) => {
651
- const serverError = this.errorDetails.get(key);
652
- if (serverError) {
653
- data.push({
654
- consumer: serverError.consumer || null,
655
- method: serverError.method,
656
- path: serverError.path,
657
- type: serverError.type,
658
- msg: this.getTruncatedMessage(serverError.msg),
659
- traceback: this.getTruncatedStack(serverError.traceback),
660
- sentry_event_id: this.sentryEventIds.get(key) || null,
661
- error_count: count
662
- });
663
- }
664
- });
665
- this.errorCounts.clear();
666
- this.errorDetails.clear();
667
- return data;
668
- }
669
- getKey(serverError) {
670
- const hashInput = [
671
- serverError.consumer || "",
672
- serverError.method.toUpperCase(),
673
- serverError.path,
674
- serverError.type,
675
- serverError.msg.trim(),
676
- serverError.traceback.trim()
677
- ].join("|");
678
- return (0, import_crypto3.createHash)("md5").update(hashInput).digest("hex");
679
- }
680
- getTruncatedMessage(msg) {
681
- msg = msg.trim();
682
- if (msg.length <= MAX_MSG_LENGTH) {
683
- return msg;
684
- }
685
- const suffix = "... (truncated)";
686
- const cutoff = MAX_MSG_LENGTH - suffix.length;
687
- return msg.substring(0, cutoff) + suffix;
688
- }
689
- getTruncatedStack(stack) {
690
- const suffix = "... (truncated) ...";
691
- const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
692
- const lines = stack.trim().split("\n");
693
- const truncatedLines = [];
694
- let length = 0;
695
- for (const line of lines) {
696
- if (length + line.length + 1 > cutoff) {
697
- truncatedLines.push(suffix);
698
- break;
699
- }
700
- truncatedLines.push(line);
701
- length += line.length + 1;
702
- }
703
- return truncatedLines.join("\n");
704
- }
705
- captureSentryEventId(serverErrorKey) {
706
- if (this.sentry && this.sentry.lastEventId) {
707
- const eventId = this.sentry.lastEventId();
708
- if (eventId) {
709
- this.sentryEventIds.set(serverErrorKey, eventId);
710
- }
711
- }
712
- }
713
- async tryImportSentry() {
714
- try {
715
- this.sentry = await import("@sentry/node");
716
- } catch (e) {
717
- }
718
- }
719
- };
720
- __name(_ServerErrorCounter, "ServerErrorCounter");
721
- var ServerErrorCounter = _ServerErrorCounter;
722
-
723
734
  // src/common/validationErrorCounter.ts
724
735
  var import_crypto4 = require("crypto");
725
736
  var _ValidationErrorCounter = class _ValidationErrorCounter {
@@ -1291,7 +1302,7 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
1291
1302
  headers: convertHeaders(res.getHeaders()),
1292
1303
  size: Number(res.get("content-length")),
1293
1304
  body: convertBody(res.locals.body, res.get("content-type"))
1294
- });
1305
+ }, res.locals.serverError);
1295
1306
  }
1296
1307
  } catch (error) {
1297
1308
  client.logger.error("Error while logging request in Apitally middleware.", {