apitally 0.23.1 → 0.24.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 (49) hide show
  1. package/dist/common/client.cjs +2 -1
  2. package/dist/common/client.cjs.map +1 -1
  3. package/dist/common/client.js +2 -1
  4. package/dist/common/client.js.map +1 -1
  5. package/dist/common/instance.cjs +158 -0
  6. package/dist/common/instance.cjs.map +1 -0
  7. package/dist/common/instance.d.cts +4 -0
  8. package/dist/common/instance.d.ts +4 -0
  9. package/dist/common/instance.js +134 -0
  10. package/dist/common/instance.js.map +1 -0
  11. package/dist/common/requestLogger.cjs +12 -17
  12. package/dist/common/requestLogger.cjs.map +1 -1
  13. package/dist/common/requestLogger.js +12 -17
  14. package/dist/common/requestLogger.js.map +1 -1
  15. package/dist/common/response.cjs +2 -2
  16. package/dist/common/response.cjs.map +1 -1
  17. package/dist/common/response.js +2 -2
  18. package/dist/common/response.js.map +1 -1
  19. package/dist/common/serverErrorCounter.cjs +3 -0
  20. package/dist/common/serverErrorCounter.cjs.map +1 -1
  21. package/dist/common/serverErrorCounter.js +3 -0
  22. package/dist/common/serverErrorCounter.js.map +1 -1
  23. package/dist/common/tempGzipFile.cjs +25 -2
  24. package/dist/common/tempGzipFile.cjs.map +1 -1
  25. package/dist/common/tempGzipFile.d.cts +3 -2
  26. package/dist/common/tempGzipFile.d.ts +3 -2
  27. package/dist/common/tempGzipFile.js +22 -3
  28. package/dist/common/tempGzipFile.js.map +1 -1
  29. package/dist/elysia/plugin.cjs +7 -7
  30. package/dist/elysia/plugin.cjs.map +1 -1
  31. package/dist/elysia/plugin.js +7 -7
  32. package/dist/elysia/plugin.js.map +1 -1
  33. package/dist/fastify/plugin.cjs +2 -2
  34. package/dist/fastify/plugin.cjs.map +1 -1
  35. package/dist/fastify/plugin.js +2 -2
  36. package/dist/fastify/plugin.js.map +1 -1
  37. package/dist/h3/plugin.cjs +2 -2
  38. package/dist/h3/plugin.cjs.map +1 -1
  39. package/dist/h3/plugin.js +2 -2
  40. package/dist/h3/plugin.js.map +1 -1
  41. package/dist/hapi/plugin.cjs +6 -6
  42. package/dist/hapi/plugin.cjs.map +1 -1
  43. package/dist/hapi/plugin.js +6 -6
  44. package/dist/hapi/plugin.js.map +1 -1
  45. package/dist/loggers/pino.cjs +1 -1
  46. package/dist/loggers/pino.cjs.map +1 -1
  47. package/dist/loggers/pino.js +1 -1
  48. package/dist/loggers/pino.js.map +1 -1
  49. package/package.json +3 -3
@@ -1,5 +1,6 @@
1
1
  import { Buffer } from 'node:buffer';
2
2
 
3
+ declare function checkWritableFs(): boolean;
3
4
  declare class TempGzipFile {
4
5
  uuid: string;
5
6
  private filePath;
@@ -7,7 +8,7 @@ declare class TempGzipFile {
7
8
  private writeStream;
8
9
  private readyPromise;
9
10
  private closedPromise;
10
- constructor();
11
+ constructor(name: string);
11
12
  get size(): number;
12
13
  writeLine(data: Buffer): Promise<void>;
13
14
  getContent(): Promise<Buffer<ArrayBufferLike>>;
@@ -15,4 +16,4 @@ declare class TempGzipFile {
15
16
  delete(): Promise<void>;
16
17
  }
17
18
 
18
- export { TempGzipFile as default };
19
+ export { checkWritableFs, TempGzipFile as default };
@@ -1,5 +1,6 @@
1
1
  import { Buffer } from 'node:buffer';
2
2
 
3
+ declare function checkWritableFs(): boolean;
3
4
  declare class TempGzipFile {
4
5
  uuid: string;
5
6
  private filePath;
@@ -7,7 +8,7 @@ declare class TempGzipFile {
7
8
  private writeStream;
8
9
  private readyPromise;
9
10
  private closedPromise;
10
- constructor();
11
+ constructor(name: string);
11
12
  get size(): number;
12
13
  writeLine(data: Buffer): Promise<void>;
13
14
  getContent(): Promise<Buffer<ArrayBufferLike>>;
@@ -15,4 +16,4 @@ declare class TempGzipFile {
15
16
  delete(): Promise<void>;
16
17
  }
17
18
 
18
- export { TempGzipFile as default };
19
+ export { checkWritableFs, TempGzipFile as default };
@@ -2,11 +2,26 @@ var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
  import { Buffer as Buffer2 } from "node:buffer";
4
4
  import { randomUUID } from "node:crypto";
5
- import { createWriteStream, readFile } from "node:fs";
5
+ import { createWriteStream, mkdirSync, readFile, unlinkSync, writeFileSync } from "node:fs";
6
6
  import { unlink } from "node:fs/promises";
7
7
  import { tmpdir } from "node:os";
8
8
  import { join } from "node:path";
9
9
  import { createGzip } from "node:zlib";
10
+ const TEMP_DIR = join(tmpdir(), "apitally");
11
+ function checkWritableFs() {
12
+ try {
13
+ mkdirSync(TEMP_DIR, {
14
+ recursive: true
15
+ });
16
+ const testPath = join(TEMP_DIR, `test_${randomUUID()}`);
17
+ writeFileSync(testPath, "test");
18
+ unlinkSync(testPath);
19
+ return true;
20
+ } catch (error) {
21
+ return false;
22
+ }
23
+ }
24
+ __name(checkWritableFs, "checkWritableFs");
10
25
  const _TempGzipFile = class _TempGzipFile {
11
26
  uuid;
12
27
  filePath;
@@ -14,9 +29,12 @@ const _TempGzipFile = class _TempGzipFile {
14
29
  writeStream;
15
30
  readyPromise;
16
31
  closedPromise;
17
- constructor() {
32
+ constructor(name) {
33
+ mkdirSync(TEMP_DIR, {
34
+ recursive: true
35
+ });
18
36
  this.uuid = randomUUID();
19
- this.filePath = join(tmpdir(), `apitally-${this.uuid}.gz`);
37
+ this.filePath = join(TEMP_DIR, `${name}_${this.uuid}.gz`);
20
38
  this.writeStream = createWriteStream(this.filePath);
21
39
  this.readyPromise = new Promise((resolve, reject) => {
22
40
  this.writeStream.once("ready", resolve);
@@ -74,6 +92,7 @@ const _TempGzipFile = class _TempGzipFile {
74
92
  __name(_TempGzipFile, "TempGzipFile");
75
93
  let TempGzipFile = _TempGzipFile;
76
94
  export {
95
+ checkWritableFs,
77
96
  TempGzipFile as default
78
97
  };
79
98
  //# sourceMappingURL=tempGzipFile.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/common/tempGzipFile.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\nimport { randomUUID } from \"node:crypto\";\nimport { createWriteStream, readFile, WriteStream } from \"node:fs\";\nimport { unlink } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createGzip, Gzip } from \"node:zlib\";\n\nexport default class TempGzipFile {\n public uuid: string;\n private filePath: string;\n private gzip: Gzip;\n private writeStream: WriteStream;\n private readyPromise: Promise<void>;\n private closedPromise: Promise<void>;\n\n constructor() {\n this.uuid = randomUUID();\n this.filePath = join(tmpdir(), `apitally-${this.uuid}.gz`);\n this.writeStream = createWriteStream(this.filePath);\n this.readyPromise = new Promise<void>((resolve, reject) => {\n this.writeStream.once(\"ready\", resolve);\n this.writeStream.once(\"error\", reject);\n });\n this.closedPromise = new Promise<void>((resolve, reject) => {\n this.writeStream.once(\"close\", resolve);\n this.writeStream.once(\"error\", reject);\n });\n this.gzip = createGzip();\n this.gzip.pipe(this.writeStream);\n }\n\n get size() {\n return this.writeStream.bytesWritten;\n }\n\n async writeLine(data: Buffer) {\n await this.readyPromise;\n return new Promise<void>((resolve, reject) => {\n this.gzip.write(Buffer.concat([data, Buffer.from(\"\\n\")]), (error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n }\n\n async getContent() {\n return new Promise<Buffer>((resolve, reject) => {\n readFile(this.filePath, (error, data) => {\n if (error) {\n reject(error);\n } else {\n resolve(data);\n }\n });\n });\n }\n\n async close() {\n await new Promise<void>((resolve) => {\n this.gzip.end(() => {\n resolve();\n });\n });\n await this.closedPromise;\n }\n\n async delete() {\n await this.close();\n await unlink(this.filePath);\n }\n}\n"],"mappings":";;AAAA,SAASA,UAAAA,eAAc;AACvB,SAASC,kBAAkB;AAC3B,SAASC,mBAAmBC,gBAA6B;AACzD,SAASC,cAAc;AACvB,SAASC,cAAc;AACvB,SAASC,YAAY;AACrB,SAASC,kBAAwB;AAEjC,MAAqBC,gBAArB,MAAqBA,cAAAA;EACZC;EACCC;EACAC;EACAC;EACAC;EACAC;EAER,cAAc;AACZ,SAAKL,OAAOR,WAAAA;AACZ,SAAKS,WAAWJ,KAAKD,OAAAA,GAAU,YAAY,KAAKI,IAAI,KAAK;AACzD,SAAKG,cAAcV,kBAAkB,KAAKQ,QAAQ;AAClD,SAAKG,eAAe,IAAIE,QAAc,CAACC,SAASC,WAAAA;AAC9C,WAAKL,YAAYM,KAAK,SAASF,OAAAA;AAC/B,WAAKJ,YAAYM,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKH,gBAAgB,IAAIC,QAAc,CAACC,SAASC,WAAAA;AAC/C,WAAKL,YAAYM,KAAK,SAASF,OAAAA;AAC/B,WAAKJ,YAAYM,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKN,OAAOJ,WAAAA;AACZ,SAAKI,KAAKQ,KAAK,KAAKP,WAAW;EACjC;EAEA,IAAIQ,OAAO;AACT,WAAO,KAAKR,YAAYS;EAC1B;EAEA,MAAMC,UAAUC,MAAc;AAC5B,UAAM,KAAKV;AACX,WAAO,IAAIE,QAAc,CAACC,SAASC,WAAAA;AACjC,WAAKN,KAAKa,MAAMxB,QAAOyB,OAAO;QAACF;QAAMvB,QAAO0B,KAAK,IAAA;OAAM,GAAG,CAACC,UAAAA;AACzD,YAAIA,OAAO;AACTV,iBAAOU,KAAAA;QACT,OAAO;AACLX,kBAAAA;QACF;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMY,aAAa;AACjB,WAAO,IAAIb,QAAgB,CAACC,SAASC,WAAAA;AACnCd,eAAS,KAAKO,UAAU,CAACiB,OAAOJ,SAAAA;AAC9B,YAAII,OAAO;AACTV,iBAAOU,KAAAA;QACT,OAAO;AACLX,kBAAQO,IAAAA;QACV;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMM,QAAQ;AACZ,UAAM,IAAId,QAAc,CAACC,YAAAA;AACvB,WAAKL,KAAKmB,IAAI,MAAA;AACZd,gBAAAA;MACF,CAAA;IACF,CAAA;AACA,UAAM,KAAKF;EACb;EAEA,MAAMiB,SAAS;AACb,UAAM,KAAKF,MAAK;AAChB,UAAMzB,OAAO,KAAKM,QAAQ;EAC5B;AACF;AAlEqBF;AAArB,IAAqBA,eAArB;","names":["Buffer","randomUUID","createWriteStream","readFile","unlink","tmpdir","join","createGzip","TempGzipFile","uuid","filePath","gzip","writeStream","readyPromise","closedPromise","Promise","resolve","reject","once","pipe","size","bytesWritten","writeLine","data","write","concat","from","error","getContent","close","end","delete"]}
1
+ {"version":3,"sources":["../../src/common/tempGzipFile.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\nimport { randomUUID } from \"node:crypto\";\nimport {\n createWriteStream,\n mkdirSync,\n readFile,\n unlinkSync,\n writeFileSync,\n WriteStream,\n} from \"node:fs\";\nimport { unlink } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createGzip, Gzip } from \"node:zlib\";\n\nconst TEMP_DIR = join(tmpdir(), \"apitally\");\n\nexport function checkWritableFs() {\n try {\n mkdirSync(TEMP_DIR, { recursive: true });\n const testPath = join(TEMP_DIR, `test_${randomUUID()}`);\n writeFileSync(testPath, \"test\");\n unlinkSync(testPath);\n return true;\n } catch (error) {\n return false;\n }\n}\n\nexport default class TempGzipFile {\n public uuid: string;\n private filePath: string;\n private gzip: Gzip;\n private writeStream: WriteStream;\n private readyPromise: Promise<void>;\n private closedPromise: Promise<void>;\n\n constructor(name: string) {\n mkdirSync(TEMP_DIR, { recursive: true });\n this.uuid = randomUUID();\n this.filePath = join(TEMP_DIR, `${name}_${this.uuid}.gz`);\n this.writeStream = createWriteStream(this.filePath);\n this.readyPromise = new Promise<void>((resolve, reject) => {\n this.writeStream.once(\"ready\", resolve);\n this.writeStream.once(\"error\", reject);\n });\n this.closedPromise = new Promise<void>((resolve, reject) => {\n this.writeStream.once(\"close\", resolve);\n this.writeStream.once(\"error\", reject);\n });\n this.gzip = createGzip();\n this.gzip.pipe(this.writeStream);\n }\n\n get size() {\n return this.writeStream.bytesWritten;\n }\n\n async writeLine(data: Buffer) {\n await this.readyPromise;\n return new Promise<void>((resolve, reject) => {\n this.gzip.write(Buffer.concat([data, Buffer.from(\"\\n\")]), (error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n }\n\n async getContent() {\n return new Promise<Buffer>((resolve, reject) => {\n readFile(this.filePath, (error, data) => {\n if (error) {\n reject(error);\n } else {\n resolve(data);\n }\n });\n });\n }\n\n async close() {\n await new Promise<void>((resolve) => {\n this.gzip.end(() => {\n resolve();\n });\n });\n await this.closedPromise;\n }\n\n async delete() {\n await this.close();\n await unlink(this.filePath);\n }\n}\n"],"mappings":";;AAAA,SAASA,UAAAA,eAAc;AACvB,SAASC,kBAAkB;AAC3B,SACEC,mBACAC,WACAC,UACAC,YACAC,qBAEK;AACP,SAASC,cAAc;AACvB,SAASC,cAAc;AACvB,SAASC,YAAY;AACrB,SAASC,kBAAwB;AAEjC,MAAMC,WAAWF,KAAKD,OAAAA,GAAU,UAAA;AAEzB,SAASI,kBAAAA;AACd,MAAI;AACFT,cAAUQ,UAAU;MAAEE,WAAW;IAAK,CAAA;AACtC,UAAMC,WAAWL,KAAKE,UAAU,QAAQV,WAAAA,CAAAA,EAAc;AACtDK,kBAAcQ,UAAU,MAAA;AACxBT,eAAWS,QAAAA;AACX,WAAO;EACT,SAASC,OAAO;AACd,WAAO;EACT;AACF;AAVgBH;AAYhB,MAAqBI,gBAArB,MAAqBA,cAAAA;EACZC;EACCC;EACAC;EACAC;EACAC;EACAC;EAER,YAAYC,MAAc;AACxBpB,cAAUQ,UAAU;MAAEE,WAAW;IAAK,CAAA;AACtC,SAAKI,OAAOhB,WAAAA;AACZ,SAAKiB,WAAWT,KAAKE,UAAU,GAAGY,IAAAA,IAAQ,KAAKN,IAAI,KAAK;AACxD,SAAKG,cAAclB,kBAAkB,KAAKgB,QAAQ;AAClD,SAAKG,eAAe,IAAIG,QAAc,CAACC,SAASC,WAAAA;AAC9C,WAAKN,YAAYO,KAAK,SAASF,OAAAA;AAC/B,WAAKL,YAAYO,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKJ,gBAAgB,IAAIE,QAAc,CAACC,SAASC,WAAAA;AAC/C,WAAKN,YAAYO,KAAK,SAASF,OAAAA;AAC/B,WAAKL,YAAYO,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKP,OAAOT,WAAAA;AACZ,SAAKS,KAAKS,KAAK,KAAKR,WAAW;EACjC;EAEA,IAAIS,OAAO;AACT,WAAO,KAAKT,YAAYU;EAC1B;EAEA,MAAMC,UAAUC,MAAc;AAC5B,UAAM,KAAKX;AACX,WAAO,IAAIG,QAAc,CAACC,SAASC,WAAAA;AACjC,WAAKP,KAAKc,MAAMjC,QAAOkC,OAAO;QAACF;QAAMhC,QAAOmC,KAAK,IAAA;OAAM,GAAG,CAACpB,UAAAA;AACzD,YAAIA,OAAO;AACTW,iBAAOX,KAAAA;QACT,OAAO;AACLU,kBAAAA;QACF;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMW,aAAa;AACjB,WAAO,IAAIZ,QAAgB,CAACC,SAASC,WAAAA;AACnCtB,eAAS,KAAKc,UAAU,CAACH,OAAOiB,SAAAA;AAC9B,YAAIjB,OAAO;AACTW,iBAAOX,KAAAA;QACT,OAAO;AACLU,kBAAQO,IAAAA;QACV;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMK,QAAQ;AACZ,UAAM,IAAIb,QAAc,CAACC,YAAAA;AACvB,WAAKN,KAAKmB,IAAI,MAAA;AACZb,gBAAAA;MACF,CAAA;IACF,CAAA;AACA,UAAM,KAAKH;EACb;EAEA,MAAMiB,SAAS;AACb,UAAM,KAAKF,MAAK;AAChB,UAAM9B,OAAO,KAAKW,QAAQ;EAC5B;AACF;AAnEqBF;AAArB,IAAqBA,eAArB;","names":["Buffer","randomUUID","createWriteStream","mkdirSync","readFile","unlinkSync","writeFileSync","unlink","tmpdir","join","createGzip","TEMP_DIR","checkWritableFs","recursive","testPath","error","TempGzipFile","uuid","filePath","gzip","writeStream","readyPromise","closedPromise","name","Promise","resolve","reject","once","pipe","size","bytesWritten","writeLine","data","write","concat","from","getContent","close","end","delete"]}
@@ -32,13 +32,13 @@ var import_requestLogger = require("../common/requestLogger.js");
32
32
  var import_response = require("../common/response.js");
33
33
  var import_loggers = require("../loggers/index.js");
34
34
  var import_utils = require("./utils.js");
35
- const START_TIME_SYMBOL = Symbol("apitally.startTime");
36
- const REQUEST_BODY_SYMBOL = Symbol("apitally.requestBody");
37
- const RESPONSE_SYMBOL = Symbol("apitally.response");
38
- const RESPONSE_PROMISE_SYMBOL = Symbol("apitally.responsePromise");
39
- const ERROR_SYMBOL = Symbol("apitally.error");
40
- const CLIENT_SYMBOL = Symbol("apitally.client");
41
- const REQUEST_SYMBOL = Symbol("apitally.request");
35
+ const START_TIME_SYMBOL = /* @__PURE__ */ Symbol("apitally.startTime");
36
+ const REQUEST_BODY_SYMBOL = /* @__PURE__ */ Symbol("apitally.requestBody");
37
+ const RESPONSE_SYMBOL = /* @__PURE__ */ Symbol("apitally.response");
38
+ const RESPONSE_PROMISE_SYMBOL = /* @__PURE__ */ Symbol("apitally.responsePromise");
39
+ const ERROR_SYMBOL = /* @__PURE__ */ Symbol("apitally.error");
40
+ const CLIENT_SYMBOL = /* @__PURE__ */ Symbol("apitally.client");
41
+ const REQUEST_SYMBOL = /* @__PURE__ */ Symbol("apitally.request");
42
42
  function apitallyPlugin(config) {
43
43
  const client = new import_client.ApitallyClient(config);
44
44
  const logsContext = new import_node_async_hooks.AsyncLocalStorage();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/elysia/plugin.ts"],"sourcesContent":["import { Context, Elysia, StatusMap, ValidationError } from \"elysia\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { CapturedResponse, captureResponse } from \"../common/response.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { getAppInfo } from \"./utils.js\";\n\nconst START_TIME_SYMBOL = Symbol(\"apitally.startTime\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\nconst RESPONSE_SYMBOL = Symbol(\"apitally.response\");\nconst RESPONSE_PROMISE_SYMBOL = Symbol(\"apitally.responsePromise\");\nconst ERROR_SYMBOL = Symbol(\"apitally.error\");\nconst CLIENT_SYMBOL = Symbol(\"apitally.client\");\nconst REQUEST_SYMBOL = Symbol(\"apitally.request\");\n\ndeclare global {\n interface Request {\n [START_TIME_SYMBOL]?: number;\n [REQUEST_BODY_SYMBOL]?: Buffer;\n [RESPONSE_SYMBOL]?: Response;\n [RESPONSE_PROMISE_SYMBOL]?: Promise<CapturedResponse>;\n [ERROR_SYMBOL]?: Readonly<Error>;\n [CLIENT_SYMBOL]?: ApitallyClient;\n }\n}\n\ntype ContextSet = Context[\"set\"] & {\n [REQUEST_SYMBOL]?: Request;\n};\n\ninterface ApitallyContext {\n consumer?: ApitallyConsumer | string;\n}\n\nexport default function apitallyPlugin(config: ApitallyConfig) {\n const client = new ApitallyClient(config);\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.enabled && client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n return (app: Elysia) => {\n const handler = app[\"~adapter\"].handler;\n\n if (!handler.mapResponse.name.startsWith(\"wrapped\")) {\n const originalMapResponse = handler.mapResponse;\n const originalMapCompactResponse = handler.mapCompactResponse;\n const originalMapEarlyResponse = handler.mapEarlyResponse;\n\n const captureMappedResponse = (\n originalResponse: unknown,\n mappedResponse: unknown,\n set?: ContextSet,\n ) => {\n const request = set?.[REQUEST_SYMBOL];\n if (\n request instanceof Request &&\n mappedResponse instanceof Response &&\n !(RESPONSE_SYMBOL in request) &&\n CLIENT_SYMBOL in request\n ) {\n if (typeof originalResponse === \"string\") {\n // Preserve the response body value as Blob if the original response is a string,\n // so that Bun adds a Content-Type header.\n const responseBody = Buffer.from(originalResponse as string);\n request[RESPONSE_SYMBOL] = mappedResponse;\n request[RESPONSE_PROMISE_SYMBOL] = Promise.resolve({\n body: responseBody,\n size: responseBody.length,\n completed: true,\n });\n } else {\n // Otherwise capture the response using streaming\n const client = request[CLIENT_SYMBOL]!;\n const [newResponse, responsePromise] = captureResponse(\n mappedResponse,\n {\n captureBody:\n client.requestLogger.enabled &&\n client.requestLogger.config.logResponseBody,\n maxBodySize: client.requestLogger.maxBodySize,\n },\n );\n request[RESPONSE_SYMBOL] = newResponse;\n request[RESPONSE_PROMISE_SYMBOL] = responsePromise;\n return newResponse;\n }\n }\n return mappedResponse;\n };\n\n handler.mapResponse = function wrappedMapResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n handler.mapCompactResponse = function wrappedMapCompactResponse(\n response: unknown,\n ) {\n const mappedResponse = originalMapCompactResponse(response);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n undefined,\n );\n return newResponse;\n };\n handler.mapEarlyResponse = function wrappedMapEarlyResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapEarlyResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n }\n\n return app\n .decorate(\"apitally\", {} as ApitallyContext)\n .onStart(() => {\n const appInfo = getAppInfo(app, config.appVersion);\n client.setStartupData(appInfo);\n client.startSync();\n })\n .onStop(async () => {\n await client.handleShutdown();\n })\n .onRequest(async ({ request, set }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n request[CLIENT_SYMBOL] = client;\n request[START_TIME_SYMBOL] = performance.now();\n (set as ContextSet)[REQUEST_SYMBOL] = request;\n logsContext.enterWith([]);\n\n // Capture request body\n if (\n client.requestLogger.enabled &&\n client.requestLogger.config.logRequestBody\n ) {\n const contentType = request.headers.get(\"content-type\");\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ?? 0;\n\n if (\n client.requestLogger.isSupportedContentType(contentType) &&\n requestSize <= client.requestLogger.maxBodySize\n ) {\n try {\n request[REQUEST_BODY_SYMBOL] = Buffer.from(\n await request.clone().arrayBuffer(),\n );\n } catch (error) {\n // ignore\n }\n }\n }\n })\n .onAfterResponse(async ({ request, set, route, apitally }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n const startTime = request[START_TIME_SYMBOL];\n const responseTime = startTime ? performance.now() - startTime : 0;\n\n const requestBody = request[REQUEST_BODY_SYMBOL];\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ??\n requestBody?.length;\n\n let responsePromise = request[RESPONSE_PROMISE_SYMBOL];\n let response = request[RESPONSE_SYMBOL];\n const error = request[ERROR_SYMBOL];\n\n if (\n !response &&\n error &&\n \"toResponse\" in error &&\n typeof error.toResponse === \"function\"\n ) {\n // Convert error to response\n try {\n response = error.toResponse() as Response;\n const errorResponseBody = Buffer.from(await response.arrayBuffer());\n responsePromise = Promise.resolve({\n body: errorResponseBody,\n size: errorResponseBody.length,\n completed: true,\n });\n } catch (error) {\n // ignore\n }\n }\n\n const statusCode = response?.status ?? getStatusCode(set) ?? 200;\n\n if (!response) {\n // Create empty fake response for errors without the toResponse method\n response = new Response(null, {\n status: statusCode,\n statusText: \"\",\n headers: new Headers(),\n });\n responsePromise = Promise.resolve({\n body: undefined,\n size: 0,\n completed: true,\n });\n }\n\n const consumer = apitally.consumer\n ? consumerFromStringOrObject(apitally.consumer)\n : null;\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n // Log request when response has been fully captured\n responsePromise?.then(async (capturedResponse) => {\n const responseHeaders = response?.headers ?? set.headers;\n const responseSize = capturedResponse.completed\n ? capturedResponse.size\n : undefined;\n\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (client.requestLogger.enabled) {\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: (Date.now() - responseTime) / 1000,\n method: request.method,\n path: route,\n url: request.url,\n headers: convertHeaders(\n Object.fromEntries(request.headers.entries()),\n ),\n size: requestSize,\n consumer: consumer?.identifier,\n body: requestBody,\n },\n {\n statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(responseHeaders),\n size: responseSize,\n body: capturedResponse.body,\n },\n error,\n logs,\n );\n }\n });\n\n // Handle validation errors\n if (\n (statusCode === 400 || statusCode === 422) &&\n error instanceof ValidationError\n ) {\n try {\n const parsedMessage = JSON.parse(error.message);\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n loc:\n (parsedMessage.on ?? \"\") + \".\" + (parsedMessage.property ?? \"\"),\n msg: parsedMessage.message,\n type: \"\",\n });\n } catch (error) {\n // ignore\n }\n }\n\n // Handle server errors\n if (statusCode === 500 && error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n type: error.name,\n msg: error.message,\n traceback: error.stack || \"\",\n });\n }\n })\n .onError(({ request, error }) => {\n if (client.isEnabled() && error instanceof Error) {\n request[ERROR_SYMBOL] = error;\n }\n });\n };\n}\n\nfunction getStatusCode(set: Context[\"set\"]) {\n if (typeof set.status === \"number\") {\n return set.status;\n } else if (typeof set.status === \"string\") {\n return StatusMap[set.status];\n }\n}\n"],"mappings":"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","names":["START_TIME_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","RESPONSE_SYMBOL","RESPONSE_PROMISE_SYMBOL","ERROR_SYMBOL","CLIENT_SYMBOL","REQUEST_SYMBOL","config","client","ApitallyClient","logsContext","AsyncLocalStorage","requestLogger","enabled","captureLogs","patchConsole","patchWinston","app","handler","mapResponse","name","startsWith","originalMapResponse","originalMapCompactResponse","mapCompactResponse","originalMapEarlyResponse","mapEarlyResponse","captureMappedResponse","originalResponse","mappedResponse","set","request","Request","Response","responseBody","Buffer","from","Promise","resolve","body","size","length","completed","newResponse","responsePromise","captureResponse","captureBody","logResponseBody","maxBodySize","wrappedMapResponse","response","wrappedMapCompactResponse","undefined","wrappedMapEarlyResponse","decorate","onStart","appInfo","getAppInfo","appVersion","setStartupData","startSync","onStop","handleShutdown","onRequest","isEnabled","method","toUpperCase","performance","now","enterWith","logRequestBody","contentType","headers","get","requestSize","parseContentLength","isSupportedContentType","clone","arrayBuffer","error","onAfterResponse","route","apitally","startTime","responseTime","requestBody","toResponse","errorResponseBody","statusCode","status","getStatusCode","statusText","Headers","consumer","consumerFromStringOrObject","consumerRegistry","addOrUpdateConsumer","then","capturedResponse","responseHeaders","responseSize","requestCounter","addRequest","identifier","path","logs","getStore","logRequest","timestamp","Date","url","convertHeaders","Object","fromEntries","entries","ValidationError","parsedMessage","JSON","parse","message","validationErrorCounter","addValidationError","loc","on","property","msg","type","serverErrorCounter","addServerError","traceback","stack","onError","Error","apitallyPlugin","StatusMap"]}
1
+ {"version":3,"sources":["../../src/elysia/plugin.ts"],"sourcesContent":["import { Context, Elysia, StatusMap, ValidationError } from \"elysia\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { CapturedResponse, captureResponse } from \"../common/response.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { getAppInfo } from \"./utils.js\";\n\nconst START_TIME_SYMBOL = Symbol(\"apitally.startTime\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\nconst RESPONSE_SYMBOL = Symbol(\"apitally.response\");\nconst RESPONSE_PROMISE_SYMBOL = Symbol(\"apitally.responsePromise\");\nconst ERROR_SYMBOL = Symbol(\"apitally.error\");\nconst CLIENT_SYMBOL = Symbol(\"apitally.client\");\nconst REQUEST_SYMBOL = Symbol(\"apitally.request\");\n\ndeclare global {\n interface Request {\n [START_TIME_SYMBOL]?: number;\n [REQUEST_BODY_SYMBOL]?: Buffer;\n [RESPONSE_SYMBOL]?: Response;\n [RESPONSE_PROMISE_SYMBOL]?: Promise<CapturedResponse>;\n [ERROR_SYMBOL]?: Readonly<Error>;\n [CLIENT_SYMBOL]?: ApitallyClient;\n }\n}\n\ntype ContextSet = Context[\"set\"] & {\n [REQUEST_SYMBOL]?: Request;\n};\n\ninterface ApitallyContext {\n consumer?: ApitallyConsumer | string;\n}\n\nexport default function apitallyPlugin(config: ApitallyConfig) {\n const client = new ApitallyClient(config);\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.enabled && client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n return (app: Elysia) => {\n const handler = app[\"~adapter\"].handler;\n\n if (!handler.mapResponse.name.startsWith(\"wrapped\")) {\n const originalMapResponse = handler.mapResponse;\n const originalMapCompactResponse = handler.mapCompactResponse;\n const originalMapEarlyResponse = handler.mapEarlyResponse;\n\n const captureMappedResponse = (\n originalResponse: unknown,\n mappedResponse: unknown,\n set?: ContextSet,\n ) => {\n const request = set?.[REQUEST_SYMBOL];\n if (\n request instanceof Request &&\n mappedResponse instanceof Response &&\n !(RESPONSE_SYMBOL in request) &&\n CLIENT_SYMBOL in request\n ) {\n if (typeof originalResponse === \"string\") {\n // Preserve the response body value as Blob if the original response is a string,\n // so that Bun adds a Content-Type header.\n const responseBody = Buffer.from(originalResponse as string);\n request[RESPONSE_SYMBOL] = mappedResponse;\n request[RESPONSE_PROMISE_SYMBOL] = Promise.resolve({\n body: responseBody,\n size: responseBody.length,\n completed: true,\n });\n } else {\n // Otherwise capture the response using streaming\n const client = request[CLIENT_SYMBOL]!;\n const [newResponse, responsePromise] = captureResponse(\n mappedResponse,\n {\n captureBody:\n client.requestLogger.enabled &&\n client.requestLogger.config.logResponseBody,\n maxBodySize: client.requestLogger.maxBodySize,\n },\n );\n request[RESPONSE_SYMBOL] = newResponse;\n request[RESPONSE_PROMISE_SYMBOL] = responsePromise;\n return newResponse;\n }\n }\n return mappedResponse;\n };\n\n handler.mapResponse = function wrappedMapResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n handler.mapCompactResponse = function wrappedMapCompactResponse(\n response: unknown,\n ) {\n const mappedResponse = originalMapCompactResponse(response);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n undefined,\n );\n return newResponse;\n };\n handler.mapEarlyResponse = function wrappedMapEarlyResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapEarlyResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n }\n\n return app\n .decorate(\"apitally\", {} as ApitallyContext)\n .onStart(() => {\n const appInfo = getAppInfo(app, config.appVersion);\n client.setStartupData(appInfo);\n client.startSync();\n })\n .onStop(async () => {\n await client.handleShutdown();\n })\n .onRequest(async ({ request, set }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n request[CLIENT_SYMBOL] = client;\n request[START_TIME_SYMBOL] = performance.now();\n (set as ContextSet)[REQUEST_SYMBOL] = request;\n logsContext.enterWith([]);\n\n // Capture request body\n if (\n client.requestLogger.enabled &&\n client.requestLogger.config.logRequestBody\n ) {\n const contentType = request.headers.get(\"content-type\");\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ?? 0;\n\n if (\n client.requestLogger.isSupportedContentType(contentType) &&\n requestSize <= client.requestLogger.maxBodySize\n ) {\n try {\n request[REQUEST_BODY_SYMBOL] = Buffer.from(\n await request.clone().arrayBuffer(),\n );\n } catch (error) {\n // ignore\n }\n }\n }\n })\n .onAfterResponse(async ({ request, set, route, apitally }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n const startTime = request[START_TIME_SYMBOL];\n const responseTime = startTime ? performance.now() - startTime : 0;\n\n const requestBody = request[REQUEST_BODY_SYMBOL];\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ??\n requestBody?.length;\n\n let responsePromise = request[RESPONSE_PROMISE_SYMBOL];\n let response = request[RESPONSE_SYMBOL];\n const error = request[ERROR_SYMBOL];\n\n if (\n !response &&\n error &&\n \"toResponse\" in error &&\n typeof error.toResponse === \"function\"\n ) {\n // Convert error to response\n try {\n response = error.toResponse() as Response;\n const errorResponseBody = Buffer.from(await response.arrayBuffer());\n responsePromise = Promise.resolve({\n body: errorResponseBody,\n size: errorResponseBody.length,\n completed: true,\n });\n } catch (error) {\n // ignore\n }\n }\n\n const statusCode = response?.status ?? getStatusCode(set) ?? 200;\n\n if (!response) {\n // Create empty fake response for errors without the toResponse method\n response = new Response(null, {\n status: statusCode,\n statusText: \"\",\n headers: new Headers(),\n });\n responsePromise = Promise.resolve({\n body: undefined,\n size: 0,\n completed: true,\n });\n }\n\n const consumer = apitally.consumer\n ? consumerFromStringOrObject(apitally.consumer)\n : null;\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n // Log request when response has been fully captured\n responsePromise?.then(async (capturedResponse) => {\n const responseHeaders = response?.headers ?? set.headers;\n const responseSize = capturedResponse.completed\n ? capturedResponse.size\n : undefined;\n\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (client.requestLogger.enabled) {\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: (Date.now() - responseTime) / 1000,\n method: request.method,\n path: route,\n url: request.url,\n headers: convertHeaders(\n Object.fromEntries(request.headers.entries()),\n ),\n size: requestSize,\n consumer: consumer?.identifier,\n body: requestBody,\n },\n {\n statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(responseHeaders),\n size: responseSize,\n body: capturedResponse.body,\n },\n error,\n logs,\n );\n }\n });\n\n // Handle validation errors\n if (\n (statusCode === 400 || statusCode === 422) &&\n error instanceof ValidationError\n ) {\n try {\n const parsedMessage = JSON.parse(error.message);\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n loc:\n (parsedMessage.on ?? \"\") + \".\" + (parsedMessage.property ?? \"\"),\n msg: parsedMessage.message,\n type: \"\",\n });\n } catch (error) {\n // ignore\n }\n }\n\n // Handle server errors\n if (statusCode === 500 && error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n type: error.name,\n msg: error.message,\n traceback: error.stack || \"\",\n });\n }\n })\n .onError(({ request, error }) => {\n if (client.isEnabled() && error instanceof Error) {\n request[ERROR_SYMBOL] = error;\n }\n });\n };\n}\n\nfunction getStatusCode(set: Context[\"set\"]) {\n if (typeof set.status === \"number\") {\n return set.status;\n } else if (typeof set.status === \"string\") {\n return StatusMap[set.status];\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;;;;;AAAA,oBAA4D;AAC5D,8BAAkC;AAClC,6BAA4B;AAE5B,oBAA+B;AAC/B,8BAA2C;AAC3C,qBAAmC;AAEnC,2BAA+B;AAC/B,sBAAkD;AAElD,qBAA2C;AAC3C,mBAA2B;AAE3B,MAAMA,oBAAoBC,uBAAO,oBAAA;AACjC,MAAMC,sBAAsBD,uBAAO,sBAAA;AACnC,MAAME,kBAAkBF,uBAAO,mBAAA;AAC/B,MAAMG,0BAA0BH,uBAAO,0BAAA;AACvC,MAAMI,eAAeJ,uBAAO,gBAAA;AAC5B,MAAMK,gBAAgBL,uBAAO,iBAAA;AAC7B,MAAMM,iBAAiBN,uBAAO,kBAAA;AAqBf,SAAf,eAAuCO,QAAsB;AAC3D,QAAMC,SAAS,IAAIC,6BAAeF,MAAAA;AAClC,QAAMG,cAAc,IAAIC,0CAAAA;AAExB,MAAIH,OAAOI,cAAcC,WAAWL,OAAOI,cAAcL,OAAOO,aAAa;AAC3EC,qCAAaL,WAAAA;AACbM,qCAAaN,WAAAA;EACf;AAEA,SAAO,CAACO,QAAAA;AACN,UAAMC,UAAUD,IAAI,UAAA,EAAYC;AAEhC,QAAI,CAACA,QAAQC,YAAYC,KAAKC,WAAW,SAAA,GAAY;AACnD,YAAMC,sBAAsBJ,QAAQC;AACpC,YAAMI,6BAA6BL,QAAQM;AAC3C,YAAMC,2BAA2BP,QAAQQ;AAEzC,YAAMC,wBAAwB,wBAC5BC,kBACAC,gBACAC,QAAAA;AAEA,cAAMC,UAAUD,2BAAMxB;AACtB,YACEyB,mBAAmBC,WACnBH,0BAA0BI,YAC1B,EAAE/B,mBAAmB6B,YACrB1B,iBAAiB0B,SACjB;AACA,cAAI,OAAOH,qBAAqB,UAAU;AAGxC,kBAAMM,eAAeC,OAAOC,KAAKR,gBAAAA;AACjCG,oBAAQ7B,eAAAA,IAAmB2B;AAC3BE,oBAAQ5B,uBAAAA,IAA2BkC,QAAQC,QAAQ;cACjDC,MAAML;cACNM,MAAMN,aAAaO;cACnBC,WAAW;YACb,CAAA;UACF,OAAO;AAEL,kBAAMlC,UAASuB,QAAQ1B,aAAAA;AACvB,kBAAM,CAACsC,aAAaC,eAAAA,QAAmBC,iCACrChB,gBACA;cACEiB,aACEtC,QAAOI,cAAcC,WACrBL,QAAOI,cAAcL,OAAOwC;cAC9BC,aAAaxC,QAAOI,cAAcoC;YACpC,CAAA;AAEFjB,oBAAQ7B,eAAAA,IAAmByC;AAC3BZ,oBAAQ5B,uBAAAA,IAA2ByC;AACnC,mBAAOD;UACT;QACF;AACA,eAAOd;MACT,GAxC8B;AA0C9BX,cAAQC,cAAc,gCAAS8B,mBAC7BC,UACApB,KAAe;AAEf,cAAMD,iBAAiBP,oBAAoB4B,UAAUpB,GAAAA;AACrD,cAAMa,cAAchB,sBAClBuB,UACArB,gBACAC,GAAAA;AAEF,eAAOa;MACT,GAXsB;AAYtBzB,cAAQM,qBAAqB,gCAAS2B,0BACpCD,UAAiB;AAEjB,cAAMrB,iBAAiBN,2BAA2B2B,QAAAA;AAClD,cAAMP,cAAchB,sBAClBuB,UACArB,gBACAuB,MAAAA;AAEF,eAAOT;MACT,GAV6B;AAW7BzB,cAAQQ,mBAAmB,gCAAS2B,wBAClCH,UACApB,KAAe;AAEf,cAAMD,iBAAiBJ,yBAAyByB,UAAUpB,GAAAA;AAC1D,cAAMa,cAAchB,sBAClBuB,UACArB,gBACAC,GAAAA;AAEF,eAAOa;MACT,GAX2B;IAY7B;AAEA,WAAO1B,IACJqC,SAAS,YAAY,CAAC,CAAA,EACtBC,QAAQ,MAAA;AACP,YAAMC,cAAUC,yBAAWxC,KAAKV,OAAOmD,UAAU;AACjDlD,aAAOmD,eAAeH,OAAAA;AACtBhD,aAAOoD,UAAS;IAClB,CAAA,EACCC,OAAO,YAAA;AACN,YAAMrD,OAAOsD,eAAc;IAC7B,CAAA,EACCC,UAAU,OAAO,EAAEhC,SAASD,IAAG,MAAE;AAChC,UAAI,CAACtB,OAAOwD,UAAS,KAAMjC,QAAQkC,OAAOC,YAAW,MAAO,WAAW;AACrE;MACF;AAEAnC,cAAQ1B,aAAAA,IAAiBG;AACzBuB,cAAQhC,iBAAAA,IAAqBoE,mCAAYC,IAAG;AAC3CtC,UAAmBxB,cAAAA,IAAkByB;AACtCrB,kBAAY2D,UAAU,CAAA,CAAE;AAGxB,UACE7D,OAAOI,cAAcC,WACrBL,OAAOI,cAAcL,OAAO+D,gBAC5B;AACA,cAAMC,cAAcxC,QAAQyC,QAAQC,IAAI,cAAA;AACxC,cAAMC,kBACJC,mCAAmB5C,QAAQyC,QAAQC,IAAI,gBAAA,CAAA,KAAsB;AAE/D,YACEjE,OAAOI,cAAcgE,uBAAuBL,WAAAA,KAC5CG,eAAelE,OAAOI,cAAcoC,aACpC;AACA,cAAI;AACFjB,oBAAQ9B,mBAAAA,IAAuBkC,OAAOC,KACpC,MAAML,QAAQ8C,MAAK,EAAGC,YAAW,CAAA;UAErC,SAASC,OAAO;UAEhB;QACF;MACF;IACF,CAAA,EACCC,gBAAgB,OAAO,EAAEjD,SAASD,KAAKmD,OAAOC,SAAQ,MAAE;AACvD,UAAI,CAAC1E,OAAOwD,UAAS,KAAMjC,QAAQkC,OAAOC,YAAW,MAAO,WAAW;AACrE;MACF;AAEA,YAAMiB,YAAYpD,QAAQhC,iBAAAA;AAC1B,YAAMqF,eAAeD,YAAYhB,mCAAYC,IAAG,IAAKe,YAAY;AAEjE,YAAME,cAActD,QAAQ9B,mBAAAA;AAC5B,YAAMyE,kBACJC,mCAAmB5C,QAAQyC,QAAQC,IAAI,gBAAA,CAAA,MACvCY,2CAAa5C;AAEf,UAAIG,kBAAkBb,QAAQ5B,uBAAAA;AAC9B,UAAI+C,WAAWnB,QAAQ7B,eAAAA;AACvB,YAAM6E,QAAQhD,QAAQ3B,YAAAA;AAEtB,UACE,CAAC8C,YACD6B,SACA,gBAAgBA,SAChB,OAAOA,MAAMO,eAAe,YAC5B;AAEA,YAAI;AACFpC,qBAAW6B,MAAMO,WAAU;AAC3B,gBAAMC,oBAAoBpD,OAAOC,KAAK,MAAMc,SAAS4B,YAAW,CAAA;AAChElC,4BAAkBP,QAAQC,QAAQ;YAChCC,MAAMgD;YACN/C,MAAM+C,kBAAkB9C;YACxBC,WAAW;UACb,CAAA;QACF,SAASqC,QAAO;QAEhB;MACF;AAEA,YAAMS,cAAatC,qCAAUuC,WAAUC,cAAc5D,GAAAA,KAAQ;AAE7D,UAAI,CAACoB,UAAU;AAEbA,mBAAW,IAAIjB,SAAS,MAAM;UAC5BwD,QAAQD;UACRG,YAAY;UACZnB,SAAS,IAAIoB,QAAAA;QACf,CAAA;AACAhD,0BAAkBP,QAAQC,QAAQ;UAChCC,MAAMa;UACNZ,MAAM;UACNE,WAAW;QACb,CAAA;MACF;AAEA,YAAMmD,WAAWX,SAASW,eACtBC,oDAA2BZ,SAASW,QAAQ,IAC5C;AACJrF,aAAOuF,iBAAiBC,oBAAoBH,QAAAA;AAG5CjD,yDAAiBqD,KAAK,OAAOC,qBAAAA;AAC3B,cAAMC,mBAAkBjD,qCAAUsB,YAAW1C,IAAI0C;AACjD,cAAM4B,eAAeF,iBAAiBxD,YAClCwD,iBAAiB1D,OACjBY;AAEJ5C,eAAO6F,eAAeC,WAAW;UAC/BT,UAAUA,qCAAUU;UACpBtC,QAAQlC,QAAQkC;UAChBuC,MAAMvB;UACNO;UACAJ;UACAV;UACA0B;QACF,CAAA;AAEA,YAAI5F,OAAOI,cAAcC,SAAS;AAChC,gBAAM4F,OAAO/F,YAAYgG,SAAQ;AACjClG,iBAAOI,cAAc+F,WACnB;YACEC,YAAYC,KAAKzC,IAAG,IAAKgB,gBAAgB;YACzCnB,QAAQlC,QAAQkC;YAChBuC,MAAMvB;YACN6B,KAAK/E,QAAQ+E;YACbtC,aAASuC,qCACPC,OAAOC,YAAYlF,QAAQyC,QAAQ0C,QAAO,CAAA,CAAA;YAE5C1E,MAAMkC;YACNmB,UAAUA,qCAAUU;YACpBhE,MAAM8C;UACR,GACA;YACEG;YACAJ,cAAcA,eAAe;YAC7BZ,aAASuC,qCAAeZ,eAAAA;YACxB3D,MAAM4D;YACN7D,MAAM2D,iBAAiB3D;UACzB,GACAwC,OACA0B,IAAAA;QAEJ;MACF;AAGA,WACGjB,eAAe,OAAOA,eAAe,QACtCT,iBAAiBoC,+BACjB;AACA,YAAI;AACF,gBAAMC,gBAAgBC,KAAKC,MAAMvC,MAAMwC,OAAO;AAC9C/G,iBAAOgH,uBAAuBC,mBAAmB;YAC/C5B,UAAUA,qCAAUU;YACpBtC,QAAQlC,QAAQkC;YAChBuC,MAAMvB;YACNyC,MACGN,cAAcO,MAAM,MAAM,OAAOP,cAAcQ,YAAY;YAC9DC,KAAKT,cAAcG;YACnBO,MAAM;UACR,CAAA;QACF,SAAS/C,QAAO;QAEhB;MACF;AAGA,UAAIS,eAAe,OAAOT,OAAO;AAC/BvE,eAAOuH,mBAAmBC,eAAe;UACvCnC,UAAUA,qCAAUU;UACpBtC,QAAQlC,QAAQkC;UAChBuC,MAAMvB;UACN6C,MAAM/C,MAAM3D;UACZyG,KAAK9C,MAAMwC;UACXU,WAAWlD,MAAMmD,SAAS;QAC5B,CAAA;MACF;IACF,CAAA,EACCC,QAAQ,CAAC,EAAEpG,SAASgD,MAAK,MAAE;AAC1B,UAAIvE,OAAOwD,UAAS,KAAMe,iBAAiBqD,OAAO;AAChDrG,gBAAQ3B,YAAAA,IAAgB2E;MAC1B;IACF,CAAA;EACJ;AACF;AAzRwBsD;AA2RxB,SAAS3C,cAAc5D,KAAmB;AACxC,MAAI,OAAOA,IAAI2D,WAAW,UAAU;AAClC,WAAO3D,IAAI2D;EACb,WAAW,OAAO3D,IAAI2D,WAAW,UAAU;AACzC,WAAO6C,wBAAUxG,IAAI2D,MAAM;EAC7B;AACF;AANSC;","names":["START_TIME_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","RESPONSE_SYMBOL","RESPONSE_PROMISE_SYMBOL","ERROR_SYMBOL","CLIENT_SYMBOL","REQUEST_SYMBOL","config","client","ApitallyClient","logsContext","AsyncLocalStorage","requestLogger","enabled","captureLogs","patchConsole","patchWinston","app","handler","mapResponse","name","startsWith","originalMapResponse","originalMapCompactResponse","mapCompactResponse","originalMapEarlyResponse","mapEarlyResponse","captureMappedResponse","originalResponse","mappedResponse","set","request","Request","Response","responseBody","Buffer","from","Promise","resolve","body","size","length","completed","newResponse","responsePromise","captureResponse","captureBody","logResponseBody","maxBodySize","wrappedMapResponse","response","wrappedMapCompactResponse","undefined","wrappedMapEarlyResponse","decorate","onStart","appInfo","getAppInfo","appVersion","setStartupData","startSync","onStop","handleShutdown","onRequest","isEnabled","method","toUpperCase","performance","now","enterWith","logRequestBody","contentType","headers","get","requestSize","parseContentLength","isSupportedContentType","clone","arrayBuffer","error","onAfterResponse","route","apitally","startTime","responseTime","requestBody","toResponse","errorResponseBody","statusCode","status","getStatusCode","statusText","Headers","consumer","consumerFromStringOrObject","consumerRegistry","addOrUpdateConsumer","then","capturedResponse","responseHeaders","responseSize","requestCounter","addRequest","identifier","path","logs","getStore","logRequest","timestamp","Date","url","convertHeaders","Object","fromEntries","entries","ValidationError","parsedMessage","JSON","parse","message","validationErrorCounter","addValidationError","loc","on","property","msg","type","serverErrorCounter","addServerError","traceback","stack","onError","Error","apitallyPlugin","StatusMap"]}
@@ -10,13 +10,13 @@ import { convertHeaders } from "../common/requestLogger.js";
10
10
  import { captureResponse } from "../common/response.js";
11
11
  import { patchConsole, patchWinston } from "../loggers/index.js";
12
12
  import { getAppInfo } from "./utils.js";
13
- const START_TIME_SYMBOL = Symbol("apitally.startTime");
14
- const REQUEST_BODY_SYMBOL = Symbol("apitally.requestBody");
15
- const RESPONSE_SYMBOL = Symbol("apitally.response");
16
- const RESPONSE_PROMISE_SYMBOL = Symbol("apitally.responsePromise");
17
- const ERROR_SYMBOL = Symbol("apitally.error");
18
- const CLIENT_SYMBOL = Symbol("apitally.client");
19
- const REQUEST_SYMBOL = Symbol("apitally.request");
13
+ const START_TIME_SYMBOL = /* @__PURE__ */ Symbol("apitally.startTime");
14
+ const REQUEST_BODY_SYMBOL = /* @__PURE__ */ Symbol("apitally.requestBody");
15
+ const RESPONSE_SYMBOL = /* @__PURE__ */ Symbol("apitally.response");
16
+ const RESPONSE_PROMISE_SYMBOL = /* @__PURE__ */ Symbol("apitally.responsePromise");
17
+ const ERROR_SYMBOL = /* @__PURE__ */ Symbol("apitally.error");
18
+ const CLIENT_SYMBOL = /* @__PURE__ */ Symbol("apitally.client");
19
+ const REQUEST_SYMBOL = /* @__PURE__ */ Symbol("apitally.request");
20
20
  function apitallyPlugin(config) {
21
21
  const client = new ApitallyClient(config);
22
22
  const logsContext = new AsyncLocalStorage();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/elysia/plugin.ts"],"sourcesContent":["import { Context, Elysia, StatusMap, ValidationError } from \"elysia\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { CapturedResponse, captureResponse } from \"../common/response.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { getAppInfo } from \"./utils.js\";\n\nconst START_TIME_SYMBOL = Symbol(\"apitally.startTime\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\nconst RESPONSE_SYMBOL = Symbol(\"apitally.response\");\nconst RESPONSE_PROMISE_SYMBOL = Symbol(\"apitally.responsePromise\");\nconst ERROR_SYMBOL = Symbol(\"apitally.error\");\nconst CLIENT_SYMBOL = Symbol(\"apitally.client\");\nconst REQUEST_SYMBOL = Symbol(\"apitally.request\");\n\ndeclare global {\n interface Request {\n [START_TIME_SYMBOL]?: number;\n [REQUEST_BODY_SYMBOL]?: Buffer;\n [RESPONSE_SYMBOL]?: Response;\n [RESPONSE_PROMISE_SYMBOL]?: Promise<CapturedResponse>;\n [ERROR_SYMBOL]?: Readonly<Error>;\n [CLIENT_SYMBOL]?: ApitallyClient;\n }\n}\n\ntype ContextSet = Context[\"set\"] & {\n [REQUEST_SYMBOL]?: Request;\n};\n\ninterface ApitallyContext {\n consumer?: ApitallyConsumer | string;\n}\n\nexport default function apitallyPlugin(config: ApitallyConfig) {\n const client = new ApitallyClient(config);\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.enabled && client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n return (app: Elysia) => {\n const handler = app[\"~adapter\"].handler;\n\n if (!handler.mapResponse.name.startsWith(\"wrapped\")) {\n const originalMapResponse = handler.mapResponse;\n const originalMapCompactResponse = handler.mapCompactResponse;\n const originalMapEarlyResponse = handler.mapEarlyResponse;\n\n const captureMappedResponse = (\n originalResponse: unknown,\n mappedResponse: unknown,\n set?: ContextSet,\n ) => {\n const request = set?.[REQUEST_SYMBOL];\n if (\n request instanceof Request &&\n mappedResponse instanceof Response &&\n !(RESPONSE_SYMBOL in request) &&\n CLIENT_SYMBOL in request\n ) {\n if (typeof originalResponse === \"string\") {\n // Preserve the response body value as Blob if the original response is a string,\n // so that Bun adds a Content-Type header.\n const responseBody = Buffer.from(originalResponse as string);\n request[RESPONSE_SYMBOL] = mappedResponse;\n request[RESPONSE_PROMISE_SYMBOL] = Promise.resolve({\n body: responseBody,\n size: responseBody.length,\n completed: true,\n });\n } else {\n // Otherwise capture the response using streaming\n const client = request[CLIENT_SYMBOL]!;\n const [newResponse, responsePromise] = captureResponse(\n mappedResponse,\n {\n captureBody:\n client.requestLogger.enabled &&\n client.requestLogger.config.logResponseBody,\n maxBodySize: client.requestLogger.maxBodySize,\n },\n );\n request[RESPONSE_SYMBOL] = newResponse;\n request[RESPONSE_PROMISE_SYMBOL] = responsePromise;\n return newResponse;\n }\n }\n return mappedResponse;\n };\n\n handler.mapResponse = function wrappedMapResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n handler.mapCompactResponse = function wrappedMapCompactResponse(\n response: unknown,\n ) {\n const mappedResponse = originalMapCompactResponse(response);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n undefined,\n );\n return newResponse;\n };\n handler.mapEarlyResponse = function wrappedMapEarlyResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapEarlyResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n }\n\n return app\n .decorate(\"apitally\", {} as ApitallyContext)\n .onStart(() => {\n const appInfo = getAppInfo(app, config.appVersion);\n client.setStartupData(appInfo);\n client.startSync();\n })\n .onStop(async () => {\n await client.handleShutdown();\n })\n .onRequest(async ({ request, set }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n request[CLIENT_SYMBOL] = client;\n request[START_TIME_SYMBOL] = performance.now();\n (set as ContextSet)[REQUEST_SYMBOL] = request;\n logsContext.enterWith([]);\n\n // Capture request body\n if (\n client.requestLogger.enabled &&\n client.requestLogger.config.logRequestBody\n ) {\n const contentType = request.headers.get(\"content-type\");\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ?? 0;\n\n if (\n client.requestLogger.isSupportedContentType(contentType) &&\n requestSize <= client.requestLogger.maxBodySize\n ) {\n try {\n request[REQUEST_BODY_SYMBOL] = Buffer.from(\n await request.clone().arrayBuffer(),\n );\n } catch (error) {\n // ignore\n }\n }\n }\n })\n .onAfterResponse(async ({ request, set, route, apitally }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n const startTime = request[START_TIME_SYMBOL];\n const responseTime = startTime ? performance.now() - startTime : 0;\n\n const requestBody = request[REQUEST_BODY_SYMBOL];\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ??\n requestBody?.length;\n\n let responsePromise = request[RESPONSE_PROMISE_SYMBOL];\n let response = request[RESPONSE_SYMBOL];\n const error = request[ERROR_SYMBOL];\n\n if (\n !response &&\n error &&\n \"toResponse\" in error &&\n typeof error.toResponse === \"function\"\n ) {\n // Convert error to response\n try {\n response = error.toResponse() as Response;\n const errorResponseBody = Buffer.from(await response.arrayBuffer());\n responsePromise = Promise.resolve({\n body: errorResponseBody,\n size: errorResponseBody.length,\n completed: true,\n });\n } catch (error) {\n // ignore\n }\n }\n\n const statusCode = response?.status ?? getStatusCode(set) ?? 200;\n\n if (!response) {\n // Create empty fake response for errors without the toResponse method\n response = new Response(null, {\n status: statusCode,\n statusText: \"\",\n headers: new Headers(),\n });\n responsePromise = Promise.resolve({\n body: undefined,\n size: 0,\n completed: true,\n });\n }\n\n const consumer = apitally.consumer\n ? consumerFromStringOrObject(apitally.consumer)\n : null;\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n // Log request when response has been fully captured\n responsePromise?.then(async (capturedResponse) => {\n const responseHeaders = response?.headers ?? set.headers;\n const responseSize = capturedResponse.completed\n ? capturedResponse.size\n : undefined;\n\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (client.requestLogger.enabled) {\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: (Date.now() - responseTime) / 1000,\n method: request.method,\n path: route,\n url: request.url,\n headers: convertHeaders(\n Object.fromEntries(request.headers.entries()),\n ),\n size: requestSize,\n consumer: consumer?.identifier,\n body: requestBody,\n },\n {\n statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(responseHeaders),\n size: responseSize,\n body: capturedResponse.body,\n },\n error,\n logs,\n );\n }\n });\n\n // Handle validation errors\n if (\n (statusCode === 400 || statusCode === 422) &&\n error instanceof ValidationError\n ) {\n try {\n const parsedMessage = JSON.parse(error.message);\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n loc:\n (parsedMessage.on ?? \"\") + \".\" + (parsedMessage.property ?? \"\"),\n msg: parsedMessage.message,\n type: \"\",\n });\n } catch (error) {\n // ignore\n }\n }\n\n // Handle server errors\n if (statusCode === 500 && error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n type: error.name,\n msg: error.message,\n traceback: error.stack || \"\",\n });\n }\n })\n .onError(({ request, error }) => {\n if (client.isEnabled() && error instanceof Error) {\n request[ERROR_SYMBOL] = error;\n }\n });\n };\n}\n\nfunction getStatusCode(set: Context[\"set\"]) {\n if (typeof set.status === \"number\") {\n return set.status;\n } else if (typeof set.status === \"string\") {\n return StatusMap[set.status];\n }\n}\n"],"mappings":"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","names":["StatusMap","ValidationError","AsyncLocalStorage","performance","ApitallyClient","consumerFromStringOrObject","parseContentLength","convertHeaders","captureResponse","patchConsole","patchWinston","getAppInfo","START_TIME_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","RESPONSE_SYMBOL","RESPONSE_PROMISE_SYMBOL","ERROR_SYMBOL","CLIENT_SYMBOL","REQUEST_SYMBOL","config","client","logsContext","requestLogger","enabled","captureLogs","app","handler","mapResponse","name","startsWith","originalMapResponse","originalMapCompactResponse","mapCompactResponse","originalMapEarlyResponse","mapEarlyResponse","captureMappedResponse","originalResponse","mappedResponse","set","request","Request","Response","responseBody","Buffer","from","Promise","resolve","body","size","length","completed","newResponse","responsePromise","captureBody","logResponseBody","maxBodySize","wrappedMapResponse","response","wrappedMapCompactResponse","undefined","wrappedMapEarlyResponse","decorate","onStart","appInfo","appVersion","setStartupData","startSync","onStop","handleShutdown","onRequest","isEnabled","method","toUpperCase","now","enterWith","logRequestBody","contentType","headers","get","requestSize","isSupportedContentType","clone","arrayBuffer","error","onAfterResponse","route","apitally","startTime","responseTime","requestBody","toResponse","errorResponseBody","statusCode","status","getStatusCode","statusText","Headers","consumer","consumerRegistry","addOrUpdateConsumer","then","capturedResponse","responseHeaders","responseSize","requestCounter","addRequest","identifier","path","logs","getStore","logRequest","timestamp","Date","url","Object","fromEntries","entries","parsedMessage","JSON","parse","message","validationErrorCounter","addValidationError","loc","on","property","msg","type","serverErrorCounter","addServerError","traceback","stack","onError","Error","apitallyPlugin"]}
1
+ {"version":3,"sources":["../../src/elysia/plugin.ts"],"sourcesContent":["import { Context, Elysia, StatusMap, ValidationError } from \"elysia\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { CapturedResponse, captureResponse } from \"../common/response.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { getAppInfo } from \"./utils.js\";\n\nconst START_TIME_SYMBOL = Symbol(\"apitally.startTime\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\nconst RESPONSE_SYMBOL = Symbol(\"apitally.response\");\nconst RESPONSE_PROMISE_SYMBOL = Symbol(\"apitally.responsePromise\");\nconst ERROR_SYMBOL = Symbol(\"apitally.error\");\nconst CLIENT_SYMBOL = Symbol(\"apitally.client\");\nconst REQUEST_SYMBOL = Symbol(\"apitally.request\");\n\ndeclare global {\n interface Request {\n [START_TIME_SYMBOL]?: number;\n [REQUEST_BODY_SYMBOL]?: Buffer;\n [RESPONSE_SYMBOL]?: Response;\n [RESPONSE_PROMISE_SYMBOL]?: Promise<CapturedResponse>;\n [ERROR_SYMBOL]?: Readonly<Error>;\n [CLIENT_SYMBOL]?: ApitallyClient;\n }\n}\n\ntype ContextSet = Context[\"set\"] & {\n [REQUEST_SYMBOL]?: Request;\n};\n\ninterface ApitallyContext {\n consumer?: ApitallyConsumer | string;\n}\n\nexport default function apitallyPlugin(config: ApitallyConfig) {\n const client = new ApitallyClient(config);\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.enabled && client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n return (app: Elysia) => {\n const handler = app[\"~adapter\"].handler;\n\n if (!handler.mapResponse.name.startsWith(\"wrapped\")) {\n const originalMapResponse = handler.mapResponse;\n const originalMapCompactResponse = handler.mapCompactResponse;\n const originalMapEarlyResponse = handler.mapEarlyResponse;\n\n const captureMappedResponse = (\n originalResponse: unknown,\n mappedResponse: unknown,\n set?: ContextSet,\n ) => {\n const request = set?.[REQUEST_SYMBOL];\n if (\n request instanceof Request &&\n mappedResponse instanceof Response &&\n !(RESPONSE_SYMBOL in request) &&\n CLIENT_SYMBOL in request\n ) {\n if (typeof originalResponse === \"string\") {\n // Preserve the response body value as Blob if the original response is a string,\n // so that Bun adds a Content-Type header.\n const responseBody = Buffer.from(originalResponse as string);\n request[RESPONSE_SYMBOL] = mappedResponse;\n request[RESPONSE_PROMISE_SYMBOL] = Promise.resolve({\n body: responseBody,\n size: responseBody.length,\n completed: true,\n });\n } else {\n // Otherwise capture the response using streaming\n const client = request[CLIENT_SYMBOL]!;\n const [newResponse, responsePromise] = captureResponse(\n mappedResponse,\n {\n captureBody:\n client.requestLogger.enabled &&\n client.requestLogger.config.logResponseBody,\n maxBodySize: client.requestLogger.maxBodySize,\n },\n );\n request[RESPONSE_SYMBOL] = newResponse;\n request[RESPONSE_PROMISE_SYMBOL] = responsePromise;\n return newResponse;\n }\n }\n return mappedResponse;\n };\n\n handler.mapResponse = function wrappedMapResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n handler.mapCompactResponse = function wrappedMapCompactResponse(\n response: unknown,\n ) {\n const mappedResponse = originalMapCompactResponse(response);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n undefined,\n );\n return newResponse;\n };\n handler.mapEarlyResponse = function wrappedMapEarlyResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapEarlyResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n }\n\n return app\n .decorate(\"apitally\", {} as ApitallyContext)\n .onStart(() => {\n const appInfo = getAppInfo(app, config.appVersion);\n client.setStartupData(appInfo);\n client.startSync();\n })\n .onStop(async () => {\n await client.handleShutdown();\n })\n .onRequest(async ({ request, set }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n request[CLIENT_SYMBOL] = client;\n request[START_TIME_SYMBOL] = performance.now();\n (set as ContextSet)[REQUEST_SYMBOL] = request;\n logsContext.enterWith([]);\n\n // Capture request body\n if (\n client.requestLogger.enabled &&\n client.requestLogger.config.logRequestBody\n ) {\n const contentType = request.headers.get(\"content-type\");\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ?? 0;\n\n if (\n client.requestLogger.isSupportedContentType(contentType) &&\n requestSize <= client.requestLogger.maxBodySize\n ) {\n try {\n request[REQUEST_BODY_SYMBOL] = Buffer.from(\n await request.clone().arrayBuffer(),\n );\n } catch (error) {\n // ignore\n }\n }\n }\n })\n .onAfterResponse(async ({ request, set, route, apitally }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n const startTime = request[START_TIME_SYMBOL];\n const responseTime = startTime ? performance.now() - startTime : 0;\n\n const requestBody = request[REQUEST_BODY_SYMBOL];\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ??\n requestBody?.length;\n\n let responsePromise = request[RESPONSE_PROMISE_SYMBOL];\n let response = request[RESPONSE_SYMBOL];\n const error = request[ERROR_SYMBOL];\n\n if (\n !response &&\n error &&\n \"toResponse\" in error &&\n typeof error.toResponse === \"function\"\n ) {\n // Convert error to response\n try {\n response = error.toResponse() as Response;\n const errorResponseBody = Buffer.from(await response.arrayBuffer());\n responsePromise = Promise.resolve({\n body: errorResponseBody,\n size: errorResponseBody.length,\n completed: true,\n });\n } catch (error) {\n // ignore\n }\n }\n\n const statusCode = response?.status ?? getStatusCode(set) ?? 200;\n\n if (!response) {\n // Create empty fake response for errors without the toResponse method\n response = new Response(null, {\n status: statusCode,\n statusText: \"\",\n headers: new Headers(),\n });\n responsePromise = Promise.resolve({\n body: undefined,\n size: 0,\n completed: true,\n });\n }\n\n const consumer = apitally.consumer\n ? consumerFromStringOrObject(apitally.consumer)\n : null;\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n // Log request when response has been fully captured\n responsePromise?.then(async (capturedResponse) => {\n const responseHeaders = response?.headers ?? set.headers;\n const responseSize = capturedResponse.completed\n ? capturedResponse.size\n : undefined;\n\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (client.requestLogger.enabled) {\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: (Date.now() - responseTime) / 1000,\n method: request.method,\n path: route,\n url: request.url,\n headers: convertHeaders(\n Object.fromEntries(request.headers.entries()),\n ),\n size: requestSize,\n consumer: consumer?.identifier,\n body: requestBody,\n },\n {\n statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(responseHeaders),\n size: responseSize,\n body: capturedResponse.body,\n },\n error,\n logs,\n );\n }\n });\n\n // Handle validation errors\n if (\n (statusCode === 400 || statusCode === 422) &&\n error instanceof ValidationError\n ) {\n try {\n const parsedMessage = JSON.parse(error.message);\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n loc:\n (parsedMessage.on ?? \"\") + \".\" + (parsedMessage.property ?? \"\"),\n msg: parsedMessage.message,\n type: \"\",\n });\n } catch (error) {\n // ignore\n }\n }\n\n // Handle server errors\n if (statusCode === 500 && error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n type: error.name,\n msg: error.message,\n traceback: error.stack || \"\",\n });\n }\n })\n .onError(({ request, error }) => {\n if (client.isEnabled() && error instanceof Error) {\n request[ERROR_SYMBOL] = error;\n }\n });\n };\n}\n\nfunction getStatusCode(set: Context[\"set\"]) {\n if (typeof set.status === \"number\") {\n return set.status;\n } else if (typeof set.status === \"string\") {\n return StatusMap[set.status];\n }\n}\n"],"mappings":"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","names":["StatusMap","ValidationError","AsyncLocalStorage","performance","ApitallyClient","consumerFromStringOrObject","parseContentLength","convertHeaders","captureResponse","patchConsole","patchWinston","getAppInfo","START_TIME_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","RESPONSE_SYMBOL","RESPONSE_PROMISE_SYMBOL","ERROR_SYMBOL","CLIENT_SYMBOL","REQUEST_SYMBOL","config","client","logsContext","requestLogger","enabled","captureLogs","app","handler","mapResponse","name","startsWith","originalMapResponse","originalMapCompactResponse","mapCompactResponse","originalMapEarlyResponse","mapEarlyResponse","captureMappedResponse","originalResponse","mappedResponse","set","request","Request","Response","responseBody","Buffer","from","Promise","resolve","body","size","length","completed","newResponse","responsePromise","captureBody","logResponseBody","maxBodySize","wrappedMapResponse","response","wrappedMapCompactResponse","undefined","wrappedMapEarlyResponse","decorate","onStart","appInfo","appVersion","setStartupData","startSync","onStop","handleShutdown","onRequest","isEnabled","method","toUpperCase","now","enterWith","logRequestBody","contentType","headers","get","requestSize","isSupportedContentType","clone","arrayBuffer","error","onAfterResponse","route","apitally","startTime","responseTime","requestBody","toResponse","errorResponseBody","statusCode","status","getStatusCode","statusText","Headers","consumer","consumerRegistry","addOrUpdateConsumer","then","capturedResponse","responseHeaders","responseSize","requestCounter","addRequest","identifier","path","logs","getStore","logRequest","timestamp","Date","url","Object","fromEntries","entries","parsedMessage","JSON","parse","message","validationErrorCounter","addValidationError","loc","on","property","msg","type","serverErrorCounter","addServerError","traceback","stack","onError","Error","apitallyPlugin"]}
@@ -42,8 +42,8 @@ var import_headers = require("../common/headers.js");
42
42
  var import_packageVersions = require("../common/packageVersions.js");
43
43
  var import_requestLogger = require("../common/requestLogger.js");
44
44
  var import_loggers = require("../loggers/index.js");
45
- const LOGS_SYMBOL = Symbol("apitally.logs");
46
- const ASYNC_RESOURCE_SYMBOL = Symbol("apitally.logsContextAsyncResource");
45
+ const LOGS_SYMBOL = /* @__PURE__ */ Symbol("apitally.logs");
46
+ const ASYNC_RESOURCE_SYMBOL = /* @__PURE__ */ Symbol("apitally.logsContextAsyncResource");
47
47
  const apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
48
48
  const client = new import_client.ApitallyClient(config);
49
49
  const routes = [];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fastify/plugin.ts"],"sourcesContent":["import type {\n FastifyError,\n FastifyPluginAsync,\n FastifyReply,\n FastifyRequest,\n} from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { AsyncLocalStorage, AsyncResource } from \"node:async_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertBody, convertHeaders } from \"../common/requestLogger.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n PathInfo,\n ValidationError,\n} from \"../common/types.js\";\nimport {\n patchConsole,\n patchNestLogger,\n patchPinoLogger,\n patchWinston,\n} from \"../loggers/index.js\";\n\nconst LOGS_SYMBOL = Symbol(\"apitally.logs\");\nconst ASYNC_RESOURCE_SYMBOL = Symbol(\"apitally.logsContextAsyncResource\");\n\ndeclare module \"fastify\" {\n interface FastifyReply {\n payload: any;\n serverError?: FastifyError;\n }\n\n interface FastifyRequest {\n apitallyConsumer?: ApitallyConsumer | string | null;\n consumerIdentifier?: ApitallyConsumer | string | null; // For backwards compatibility\n\n [LOGS_SYMBOL]?: LogRecord[];\n [ASYNC_RESOURCE_SYMBOL]?: AsyncResource;\n }\n}\n\nconst apitallyPlugin: FastifyPluginAsync<ApitallyConfig> = async (\n fastify,\n config,\n) => {\n const client = new ApitallyClient(config);\n const routes: PathInfo[] = [];\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n patchPinoLogger(fastify.log, logsContext);\n patchNestLogger(logsContext);\n }\n\n fastify.decorateRequest(\"apitallyConsumer\", null);\n fastify.decorateRequest(\"consumerIdentifier\", null); // For backwards compatibility\n fastify.decorateReply(\"payload\", null);\n\n fastify.addHook(\"onRoute\", (routeOptions) => {\n const methods = Array.isArray(routeOptions.method)\n ? routeOptions.method\n : [routeOptions.method];\n methods.forEach((method) => {\n if (![\"HEAD\", \"OPTIONS\"].includes(method.toUpperCase())) {\n routes.push({\n method: method.toUpperCase(),\n path: routeOptions.url,\n });\n }\n });\n });\n\n fastify.addHook(\"onReady\", () => {\n client.setStartupData(getAppInfo(routes, config.appVersion));\n client.startSync();\n });\n\n fastify.addHook(\"onClose\", async () => {\n await client.handleShutdown();\n });\n\n // Establish logs context for each request\n fastify.addHook(\"onRequest\", (request, reply, done) => {\n if (client.isEnabled()) {\n const logs: LogRecord[] = [];\n request[LOGS_SYMBOL] = logs;\n logsContext.run(logs, () => {\n const asyncResource = new AsyncResource(\"ApitallyLogsContext\");\n request[ASYNC_RESOURCE_SYMBOL] = asyncResource;\n asyncResource.runInAsyncScope(done, request.raw);\n });\n } else {\n done();\n }\n });\n\n // Restore async context for later hooks and route handlers\n fastify.addHook(\"preValidation\", (request, reply, done) => {\n if (client.isEnabled() && request[ASYNC_RESOURCE_SYMBOL]) {\n const asyncResource = request[ASYNC_RESOURCE_SYMBOL];\n asyncResource.runInAsyncScope(done, request.raw);\n } else {\n done();\n }\n });\n\n fastify.addHook(\"onSend\", (request, reply, payload: any, done) => {\n const contentType = reply.getHeader(\"content-type\") as string | undefined;\n if (client.requestLogger.isSupportedContentType(contentType)) {\n reply.payload = payload;\n }\n done();\n });\n\n fastify.addHook(\"onError\", (request, reply, error, done) => {\n if (!error.statusCode || error.statusCode === 500) {\n reply.serverError = error;\n }\n done();\n });\n\n fastify.addHook(\"onResponse\", (request, reply, done) => {\n if (client.isEnabled() && request.method.toUpperCase() !== \"OPTIONS\") {\n // Get path from routeOptions if available (from v4), otherwise fallback to deprecated routerPath\n const consumer = getConsumer(request);\n const path =\n \"routeOptions\" in request\n ? (request as any).routeOptions.url\n : (request as any).routerPath;\n const requestSize = parseContentLength(request.headers[\"content-length\"]);\n const responseSize = parseContentLength(\n reply.getHeader(\"content-length\"),\n );\n const responseTime = getResponseTime(reply);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path,\n statusCode: reply.statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (\n (reply.statusCode === 400 || reply.statusCode === 422) &&\n reply.payload\n ) {\n try {\n const parsedPayload = JSON.parse(reply.payload);\n const validationErrors: ValidationError[] = [];\n\n if (\n (!parsedPayload.code ||\n parsedPayload.code === \"FST_ERR_VALIDATION\") &&\n typeof parsedPayload.message === \"string\"\n ) {\n validationErrors.push(...extractAjvErrors(parsedPayload.message));\n } else if (Array.isArray(parsedPayload.message)) {\n validationErrors.push(\n ...extractNestValidationErrors(parsedPayload.message),\n );\n }\n\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n ...error,\n });\n });\n } catch (error) {} // eslint-disable-line no-empty\n }\n\n if (reply.statusCode === 500 && reply.serverError) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n type: reply.serverError.name,\n msg: reply.serverError.message,\n traceback: reply.serverError.stack || \"\",\n });\n }\n\n if (client.requestLogger.enabled) {\n const logs = request[LOGS_SYMBOL];\n client.requestLogger.logRequest(\n {\n timestamp: Date.now() / 1000,\n method: request.method,\n path,\n url: `${request.protocol}://${request.host ?? request.hostname}${request.originalUrl ?? request.url}`,\n headers: convertHeaders(request.headers),\n size: requestSize,\n consumer: consumer?.identifier,\n body: convertBody(request.body, request.headers[\"content-type\"]),\n },\n {\n statusCode: reply.statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(reply.getHeaders()),\n size: responseSize,\n body: convertBody(\n reply.payload,\n reply.getHeader(\"content-type\")?.toString(),\n ),\n },\n reply.serverError,\n logs,\n );\n }\n }\n\n done();\n });\n};\n\nfunction getAppInfo(routes: PathInfo[], appVersion?: string) {\n const versions = [[\"nodejs\", process.version.replace(/^v/, \"\")]];\n const fastifyVersion = getPackageVersion(\"fastify\");\n const pinoVersion = getPackageVersion(\"pino\");\n const nestjsVersion = getPackageVersion(\"@nestjs/core\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (fastifyVersion) {\n versions.push([\"fastify\", fastifyVersion]);\n }\n if (pinoVersion) {\n versions.push([\"pino\", pinoVersion]);\n }\n if (nestjsVersion) {\n versions.push([\"nestjs\", nestjsVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: routes,\n versions: Object.fromEntries(versions),\n client: \"js:fastify\",\n };\n}\n\nexport function setConsumer(\n request: FastifyRequest,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n request.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(request: FastifyRequest) {\n if (request.apitallyConsumer) {\n return consumerFromStringOrObject(request.apitallyConsumer);\n } else if (request.consumerIdentifier) {\n // For backwards compatibility\n process.emitWarning(\n \"The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.\",\n \"DeprecationWarning\",\n );\n return consumerFromStringOrObject(request.consumerIdentifier);\n }\n return null;\n}\n\nfunction getResponseTime(reply: FastifyReply) {\n if (reply.elapsedTime !== undefined) {\n return reply.elapsedTime;\n } else if ((reply as any).getResponseTime !== undefined) {\n return (reply as any).getResponseTime();\n }\n return 0;\n}\n\nfunction extractAjvErrors(message: string): ValidationError[] {\n try {\n const regex =\n /(?<=^|, )((?:headers|params|query|querystring|body)[/.][^ ]+)(?= )/g;\n const matches: { match: string; index: number }[] = [];\n let match: RegExpExecArray | null;\n while ((match = regex.exec(message)) !== null) {\n matches.push({ match: match[0], index: match.index });\n }\n\n return matches.map((m, i) => {\n const endIndex =\n i + 1 < matches.length ? matches[i + 1].index - 2 : message.length;\n const matchSplit = m.match.split(/[/.]/);\n if (matchSplit[0] === \"querystring\") {\n matchSplit[0] = \"query\";\n }\n return {\n loc: matchSplit.join(\".\"),\n msg: message.substring(m.index, endIndex),\n type: \"\",\n };\n });\n } catch (error) {\n return [];\n }\n}\n\nfunction extractNestValidationErrors(message: any[]): ValidationError[] {\n try {\n return message\n .filter((msg: any) => typeof msg === \"string\")\n .map((msg: any) => ({\n loc: \"\",\n msg,\n type: \"\",\n }));\n } catch (error) {\n return [];\n }\n}\n\nexport { apitallyPlugin };\n\nexport default fp(apitallyPlugin, {\n name: \"apitally\",\n});\n"],"mappings":"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","names":["LOGS_SYMBOL","Symbol","ASYNC_RESOURCE_SYMBOL","apitallyPlugin","fastify","config","client","ApitallyClient","routes","logsContext","AsyncLocalStorage","requestLogger","captureLogs","patchConsole","patchWinston","patchPinoLogger","log","patchNestLogger","decorateRequest","decorateReply","addHook","routeOptions","methods","Array","isArray","method","forEach","includes","toUpperCase","push","path","url","setStartupData","getAppInfo","appVersion","startSync","handleShutdown","request","reply","done","isEnabled","logs","run","asyncResource","AsyncResource","runInAsyncScope","raw","payload","contentType","getHeader","isSupportedContentType","error","statusCode","serverError","consumer","getConsumer","routerPath","requestSize","parseContentLength","headers","responseSize","responseTime","getResponseTime","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","parsedPayload","JSON","parse","validationErrors","code","message","extractAjvErrors","extractNestValidationErrors","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","traceback","stack","enabled","logRequest","timestamp","Date","now","protocol","host","hostname","originalUrl","convertHeaders","size","body","convertBody","getHeaders","toString","versions","process","version","replace","fastifyVersion","getPackageVersion","pinoVersion","nestjsVersion","apitallyVersion","paths","Object","fromEntries","setConsumer","apitallyConsumer","undefined","consumerFromStringOrObject","consumerIdentifier","emitWarning","elapsedTime","regex","matches","match","exec","index","map","m","i","endIndex","length","matchSplit","split","loc","join","substring","filter","fp"]}
1
+ {"version":3,"sources":["../../src/fastify/plugin.ts"],"sourcesContent":["import type {\n FastifyError,\n FastifyPluginAsync,\n FastifyReply,\n FastifyRequest,\n} from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { AsyncLocalStorage, AsyncResource } from \"node:async_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertBody, convertHeaders } from \"../common/requestLogger.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n PathInfo,\n ValidationError,\n} from \"../common/types.js\";\nimport {\n patchConsole,\n patchNestLogger,\n patchPinoLogger,\n patchWinston,\n} from \"../loggers/index.js\";\n\nconst LOGS_SYMBOL = Symbol(\"apitally.logs\");\nconst ASYNC_RESOURCE_SYMBOL = Symbol(\"apitally.logsContextAsyncResource\");\n\ndeclare module \"fastify\" {\n interface FastifyReply {\n payload: any;\n serverError?: FastifyError;\n }\n\n interface FastifyRequest {\n apitallyConsumer?: ApitallyConsumer | string | null;\n consumerIdentifier?: ApitallyConsumer | string | null; // For backwards compatibility\n\n [LOGS_SYMBOL]?: LogRecord[];\n [ASYNC_RESOURCE_SYMBOL]?: AsyncResource;\n }\n}\n\nconst apitallyPlugin: FastifyPluginAsync<ApitallyConfig> = async (\n fastify,\n config,\n) => {\n const client = new ApitallyClient(config);\n const routes: PathInfo[] = [];\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n patchPinoLogger(fastify.log, logsContext);\n patchNestLogger(logsContext);\n }\n\n fastify.decorateRequest(\"apitallyConsumer\", null);\n fastify.decorateRequest(\"consumerIdentifier\", null); // For backwards compatibility\n fastify.decorateReply(\"payload\", null);\n\n fastify.addHook(\"onRoute\", (routeOptions) => {\n const methods = Array.isArray(routeOptions.method)\n ? routeOptions.method\n : [routeOptions.method];\n methods.forEach((method) => {\n if (![\"HEAD\", \"OPTIONS\"].includes(method.toUpperCase())) {\n routes.push({\n method: method.toUpperCase(),\n path: routeOptions.url,\n });\n }\n });\n });\n\n fastify.addHook(\"onReady\", () => {\n client.setStartupData(getAppInfo(routes, config.appVersion));\n client.startSync();\n });\n\n fastify.addHook(\"onClose\", async () => {\n await client.handleShutdown();\n });\n\n // Establish logs context for each request\n fastify.addHook(\"onRequest\", (request, reply, done) => {\n if (client.isEnabled()) {\n const logs: LogRecord[] = [];\n request[LOGS_SYMBOL] = logs;\n logsContext.run(logs, () => {\n const asyncResource = new AsyncResource(\"ApitallyLogsContext\");\n request[ASYNC_RESOURCE_SYMBOL] = asyncResource;\n asyncResource.runInAsyncScope(done, request.raw);\n });\n } else {\n done();\n }\n });\n\n // Restore async context for later hooks and route handlers\n fastify.addHook(\"preValidation\", (request, reply, done) => {\n if (client.isEnabled() && request[ASYNC_RESOURCE_SYMBOL]) {\n const asyncResource = request[ASYNC_RESOURCE_SYMBOL];\n asyncResource.runInAsyncScope(done, request.raw);\n } else {\n done();\n }\n });\n\n fastify.addHook(\"onSend\", (request, reply, payload: any, done) => {\n const contentType = reply.getHeader(\"content-type\") as string | undefined;\n if (client.requestLogger.isSupportedContentType(contentType)) {\n reply.payload = payload;\n }\n done();\n });\n\n fastify.addHook(\"onError\", (request, reply, error, done) => {\n if (!error.statusCode || error.statusCode === 500) {\n reply.serverError = error;\n }\n done();\n });\n\n fastify.addHook(\"onResponse\", (request, reply, done) => {\n if (client.isEnabled() && request.method.toUpperCase() !== \"OPTIONS\") {\n // Get path from routeOptions if available (from v4), otherwise fallback to deprecated routerPath\n const consumer = getConsumer(request);\n const path =\n \"routeOptions\" in request\n ? (request as any).routeOptions.url\n : (request as any).routerPath;\n const requestSize = parseContentLength(request.headers[\"content-length\"]);\n const responseSize = parseContentLength(\n reply.getHeader(\"content-length\"),\n );\n const responseTime = getResponseTime(reply);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path,\n statusCode: reply.statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (\n (reply.statusCode === 400 || reply.statusCode === 422) &&\n reply.payload\n ) {\n try {\n const parsedPayload = JSON.parse(reply.payload);\n const validationErrors: ValidationError[] = [];\n\n if (\n (!parsedPayload.code ||\n parsedPayload.code === \"FST_ERR_VALIDATION\") &&\n typeof parsedPayload.message === \"string\"\n ) {\n validationErrors.push(...extractAjvErrors(parsedPayload.message));\n } else if (Array.isArray(parsedPayload.message)) {\n validationErrors.push(\n ...extractNestValidationErrors(parsedPayload.message),\n );\n }\n\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n ...error,\n });\n });\n } catch (error) {} // eslint-disable-line no-empty\n }\n\n if (reply.statusCode === 500 && reply.serverError) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n type: reply.serverError.name,\n msg: reply.serverError.message,\n traceback: reply.serverError.stack || \"\",\n });\n }\n\n if (client.requestLogger.enabled) {\n const logs = request[LOGS_SYMBOL];\n client.requestLogger.logRequest(\n {\n timestamp: Date.now() / 1000,\n method: request.method,\n path,\n url: `${request.protocol}://${request.host ?? request.hostname}${request.originalUrl ?? request.url}`,\n headers: convertHeaders(request.headers),\n size: requestSize,\n consumer: consumer?.identifier,\n body: convertBody(request.body, request.headers[\"content-type\"]),\n },\n {\n statusCode: reply.statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(reply.getHeaders()),\n size: responseSize,\n body: convertBody(\n reply.payload,\n reply.getHeader(\"content-type\")?.toString(),\n ),\n },\n reply.serverError,\n logs,\n );\n }\n }\n\n done();\n });\n};\n\nfunction getAppInfo(routes: PathInfo[], appVersion?: string) {\n const versions = [[\"nodejs\", process.version.replace(/^v/, \"\")]];\n const fastifyVersion = getPackageVersion(\"fastify\");\n const pinoVersion = getPackageVersion(\"pino\");\n const nestjsVersion = getPackageVersion(\"@nestjs/core\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (fastifyVersion) {\n versions.push([\"fastify\", fastifyVersion]);\n }\n if (pinoVersion) {\n versions.push([\"pino\", pinoVersion]);\n }\n if (nestjsVersion) {\n versions.push([\"nestjs\", nestjsVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: routes,\n versions: Object.fromEntries(versions),\n client: \"js:fastify\",\n };\n}\n\nexport function setConsumer(\n request: FastifyRequest,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n request.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(request: FastifyRequest) {\n if (request.apitallyConsumer) {\n return consumerFromStringOrObject(request.apitallyConsumer);\n } else if (request.consumerIdentifier) {\n // For backwards compatibility\n process.emitWarning(\n \"The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.\",\n \"DeprecationWarning\",\n );\n return consumerFromStringOrObject(request.consumerIdentifier);\n }\n return null;\n}\n\nfunction getResponseTime(reply: FastifyReply) {\n if (reply.elapsedTime !== undefined) {\n return reply.elapsedTime;\n } else if ((reply as any).getResponseTime !== undefined) {\n return (reply as any).getResponseTime();\n }\n return 0;\n}\n\nfunction extractAjvErrors(message: string): ValidationError[] {\n try {\n const regex =\n /(?<=^|, )((?:headers|params|query|querystring|body)[/.][^ ]+)(?= )/g;\n const matches: { match: string; index: number }[] = [];\n let match: RegExpExecArray | null;\n while ((match = regex.exec(message)) !== null) {\n matches.push({ match: match[0], index: match.index });\n }\n\n return matches.map((m, i) => {\n const endIndex =\n i + 1 < matches.length ? matches[i + 1].index - 2 : message.length;\n const matchSplit = m.match.split(/[/.]/);\n if (matchSplit[0] === \"querystring\") {\n matchSplit[0] = \"query\";\n }\n return {\n loc: matchSplit.join(\".\"),\n msg: message.substring(m.index, endIndex),\n type: \"\",\n };\n });\n } catch (error) {\n return [];\n }\n}\n\nfunction extractNestValidationErrors(message: any[]): ValidationError[] {\n try {\n return message\n .filter((msg: any) => typeof msg === \"string\")\n .map((msg: any) => ({\n loc: \"\",\n msg,\n type: \"\",\n }));\n } catch (error) {\n return [];\n }\n}\n\nexport { apitallyPlugin };\n\nexport default fp(apitallyPlugin, {\n name: \"apitally\",\n});\n"],"mappings":"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","names":["LOGS_SYMBOL","Symbol","ASYNC_RESOURCE_SYMBOL","apitallyPlugin","fastify","config","client","ApitallyClient","routes","logsContext","AsyncLocalStorage","requestLogger","captureLogs","patchConsole","patchWinston","patchPinoLogger","log","patchNestLogger","decorateRequest","decorateReply","addHook","routeOptions","methods","Array","isArray","method","forEach","includes","toUpperCase","push","path","url","setStartupData","getAppInfo","appVersion","startSync","handleShutdown","request","reply","done","isEnabled","logs","run","asyncResource","AsyncResource","runInAsyncScope","raw","payload","contentType","getHeader","isSupportedContentType","error","statusCode","serverError","consumer","getConsumer","routerPath","requestSize","parseContentLength","headers","responseSize","responseTime","getResponseTime","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","parsedPayload","JSON","parse","validationErrors","code","message","extractAjvErrors","extractNestValidationErrors","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","traceback","stack","enabled","logRequest","timestamp","Date","now","protocol","host","hostname","originalUrl","convertHeaders","size","body","convertBody","getHeaders","toString","versions","process","version","replace","fastifyVersion","getPackageVersion","pinoVersion","nestjsVersion","apitallyVersion","paths","Object","fromEntries","setConsumer","apitallyConsumer","undefined","consumerFromStringOrObject","consumerIdentifier","emitWarning","elapsedTime","regex","matches","match","exec","index","map","m","i","endIndex","length","matchSplit","split","loc","join","substring","filter","fp"]}
@@ -8,8 +8,8 @@ import { parseContentLength } from "../common/headers.js";
8
8
  import { getPackageVersion } from "../common/packageVersions.js";
9
9
  import { convertBody, convertHeaders } from "../common/requestLogger.js";
10
10
  import { patchConsole, patchNestLogger, patchPinoLogger, patchWinston } from "../loggers/index.js";
11
- const LOGS_SYMBOL = Symbol("apitally.logs");
12
- const ASYNC_RESOURCE_SYMBOL = Symbol("apitally.logsContextAsyncResource");
11
+ const LOGS_SYMBOL = /* @__PURE__ */ Symbol("apitally.logs");
12
+ const ASYNC_RESOURCE_SYMBOL = /* @__PURE__ */ Symbol("apitally.logsContextAsyncResource");
13
13
  const apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
14
14
  const client = new ApitallyClient(config);
15
15
  const routes = [];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fastify/plugin.ts"],"sourcesContent":["import type {\n FastifyError,\n FastifyPluginAsync,\n FastifyReply,\n FastifyRequest,\n} from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { AsyncLocalStorage, AsyncResource } from \"node:async_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertBody, convertHeaders } from \"../common/requestLogger.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n PathInfo,\n ValidationError,\n} from \"../common/types.js\";\nimport {\n patchConsole,\n patchNestLogger,\n patchPinoLogger,\n patchWinston,\n} from \"../loggers/index.js\";\n\nconst LOGS_SYMBOL = Symbol(\"apitally.logs\");\nconst ASYNC_RESOURCE_SYMBOL = Symbol(\"apitally.logsContextAsyncResource\");\n\ndeclare module \"fastify\" {\n interface FastifyReply {\n payload: any;\n serverError?: FastifyError;\n }\n\n interface FastifyRequest {\n apitallyConsumer?: ApitallyConsumer | string | null;\n consumerIdentifier?: ApitallyConsumer | string | null; // For backwards compatibility\n\n [LOGS_SYMBOL]?: LogRecord[];\n [ASYNC_RESOURCE_SYMBOL]?: AsyncResource;\n }\n}\n\nconst apitallyPlugin: FastifyPluginAsync<ApitallyConfig> = async (\n fastify,\n config,\n) => {\n const client = new ApitallyClient(config);\n const routes: PathInfo[] = [];\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n patchPinoLogger(fastify.log, logsContext);\n patchNestLogger(logsContext);\n }\n\n fastify.decorateRequest(\"apitallyConsumer\", null);\n fastify.decorateRequest(\"consumerIdentifier\", null); // For backwards compatibility\n fastify.decorateReply(\"payload\", null);\n\n fastify.addHook(\"onRoute\", (routeOptions) => {\n const methods = Array.isArray(routeOptions.method)\n ? routeOptions.method\n : [routeOptions.method];\n methods.forEach((method) => {\n if (![\"HEAD\", \"OPTIONS\"].includes(method.toUpperCase())) {\n routes.push({\n method: method.toUpperCase(),\n path: routeOptions.url,\n });\n }\n });\n });\n\n fastify.addHook(\"onReady\", () => {\n client.setStartupData(getAppInfo(routes, config.appVersion));\n client.startSync();\n });\n\n fastify.addHook(\"onClose\", async () => {\n await client.handleShutdown();\n });\n\n // Establish logs context for each request\n fastify.addHook(\"onRequest\", (request, reply, done) => {\n if (client.isEnabled()) {\n const logs: LogRecord[] = [];\n request[LOGS_SYMBOL] = logs;\n logsContext.run(logs, () => {\n const asyncResource = new AsyncResource(\"ApitallyLogsContext\");\n request[ASYNC_RESOURCE_SYMBOL] = asyncResource;\n asyncResource.runInAsyncScope(done, request.raw);\n });\n } else {\n done();\n }\n });\n\n // Restore async context for later hooks and route handlers\n fastify.addHook(\"preValidation\", (request, reply, done) => {\n if (client.isEnabled() && request[ASYNC_RESOURCE_SYMBOL]) {\n const asyncResource = request[ASYNC_RESOURCE_SYMBOL];\n asyncResource.runInAsyncScope(done, request.raw);\n } else {\n done();\n }\n });\n\n fastify.addHook(\"onSend\", (request, reply, payload: any, done) => {\n const contentType = reply.getHeader(\"content-type\") as string | undefined;\n if (client.requestLogger.isSupportedContentType(contentType)) {\n reply.payload = payload;\n }\n done();\n });\n\n fastify.addHook(\"onError\", (request, reply, error, done) => {\n if (!error.statusCode || error.statusCode === 500) {\n reply.serverError = error;\n }\n done();\n });\n\n fastify.addHook(\"onResponse\", (request, reply, done) => {\n if (client.isEnabled() && request.method.toUpperCase() !== \"OPTIONS\") {\n // Get path from routeOptions if available (from v4), otherwise fallback to deprecated routerPath\n const consumer = getConsumer(request);\n const path =\n \"routeOptions\" in request\n ? (request as any).routeOptions.url\n : (request as any).routerPath;\n const requestSize = parseContentLength(request.headers[\"content-length\"]);\n const responseSize = parseContentLength(\n reply.getHeader(\"content-length\"),\n );\n const responseTime = getResponseTime(reply);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path,\n statusCode: reply.statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (\n (reply.statusCode === 400 || reply.statusCode === 422) &&\n reply.payload\n ) {\n try {\n const parsedPayload = JSON.parse(reply.payload);\n const validationErrors: ValidationError[] = [];\n\n if (\n (!parsedPayload.code ||\n parsedPayload.code === \"FST_ERR_VALIDATION\") &&\n typeof parsedPayload.message === \"string\"\n ) {\n validationErrors.push(...extractAjvErrors(parsedPayload.message));\n } else if (Array.isArray(parsedPayload.message)) {\n validationErrors.push(\n ...extractNestValidationErrors(parsedPayload.message),\n );\n }\n\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n ...error,\n });\n });\n } catch (error) {} // eslint-disable-line no-empty\n }\n\n if (reply.statusCode === 500 && reply.serverError) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n type: reply.serverError.name,\n msg: reply.serverError.message,\n traceback: reply.serverError.stack || \"\",\n });\n }\n\n if (client.requestLogger.enabled) {\n const logs = request[LOGS_SYMBOL];\n client.requestLogger.logRequest(\n {\n timestamp: Date.now() / 1000,\n method: request.method,\n path,\n url: `${request.protocol}://${request.host ?? request.hostname}${request.originalUrl ?? request.url}`,\n headers: convertHeaders(request.headers),\n size: requestSize,\n consumer: consumer?.identifier,\n body: convertBody(request.body, request.headers[\"content-type\"]),\n },\n {\n statusCode: reply.statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(reply.getHeaders()),\n size: responseSize,\n body: convertBody(\n reply.payload,\n reply.getHeader(\"content-type\")?.toString(),\n ),\n },\n reply.serverError,\n logs,\n );\n }\n }\n\n done();\n });\n};\n\nfunction getAppInfo(routes: PathInfo[], appVersion?: string) {\n const versions = [[\"nodejs\", process.version.replace(/^v/, \"\")]];\n const fastifyVersion = getPackageVersion(\"fastify\");\n const pinoVersion = getPackageVersion(\"pino\");\n const nestjsVersion = getPackageVersion(\"@nestjs/core\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (fastifyVersion) {\n versions.push([\"fastify\", fastifyVersion]);\n }\n if (pinoVersion) {\n versions.push([\"pino\", pinoVersion]);\n }\n if (nestjsVersion) {\n versions.push([\"nestjs\", nestjsVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: routes,\n versions: Object.fromEntries(versions),\n client: \"js:fastify\",\n };\n}\n\nexport function setConsumer(\n request: FastifyRequest,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n request.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(request: FastifyRequest) {\n if (request.apitallyConsumer) {\n return consumerFromStringOrObject(request.apitallyConsumer);\n } else if (request.consumerIdentifier) {\n // For backwards compatibility\n process.emitWarning(\n \"The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.\",\n \"DeprecationWarning\",\n );\n return consumerFromStringOrObject(request.consumerIdentifier);\n }\n return null;\n}\n\nfunction getResponseTime(reply: FastifyReply) {\n if (reply.elapsedTime !== undefined) {\n return reply.elapsedTime;\n } else if ((reply as any).getResponseTime !== undefined) {\n return (reply as any).getResponseTime();\n }\n return 0;\n}\n\nfunction extractAjvErrors(message: string): ValidationError[] {\n try {\n const regex =\n /(?<=^|, )((?:headers|params|query|querystring|body)[/.][^ ]+)(?= )/g;\n const matches: { match: string; index: number }[] = [];\n let match: RegExpExecArray | null;\n while ((match = regex.exec(message)) !== null) {\n matches.push({ match: match[0], index: match.index });\n }\n\n return matches.map((m, i) => {\n const endIndex =\n i + 1 < matches.length ? matches[i + 1].index - 2 : message.length;\n const matchSplit = m.match.split(/[/.]/);\n if (matchSplit[0] === \"querystring\") {\n matchSplit[0] = \"query\";\n }\n return {\n loc: matchSplit.join(\".\"),\n msg: message.substring(m.index, endIndex),\n type: \"\",\n };\n });\n } catch (error) {\n return [];\n }\n}\n\nfunction extractNestValidationErrors(message: any[]): ValidationError[] {\n try {\n return message\n .filter((msg: any) => typeof msg === \"string\")\n .map((msg: any) => ({\n loc: \"\",\n msg,\n type: \"\",\n }));\n } catch (error) {\n return [];\n }\n}\n\nexport { apitallyPlugin };\n\nexport default fp(apitallyPlugin, {\n name: \"apitally\",\n});\n"],"mappings":"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","names":["fp","AsyncLocalStorage","AsyncResource","ApitallyClient","consumerFromStringOrObject","parseContentLength","getPackageVersion","convertBody","convertHeaders","patchConsole","patchNestLogger","patchPinoLogger","patchWinston","LOGS_SYMBOL","Symbol","ASYNC_RESOURCE_SYMBOL","apitallyPlugin","fastify","config","client","routes","logsContext","requestLogger","captureLogs","log","decorateRequest","decorateReply","addHook","routeOptions","methods","Array","isArray","method","forEach","includes","toUpperCase","push","path","url","setStartupData","getAppInfo","appVersion","startSync","handleShutdown","request","reply","done","isEnabled","logs","run","asyncResource","runInAsyncScope","raw","payload","contentType","getHeader","isSupportedContentType","error","statusCode","serverError","consumer","getConsumer","routerPath","requestSize","headers","responseSize","responseTime","getResponseTime","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","parsedPayload","JSON","parse","validationErrors","code","message","extractAjvErrors","extractNestValidationErrors","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","traceback","stack","enabled","logRequest","timestamp","Date","now","protocol","host","hostname","originalUrl","size","body","getHeaders","toString","versions","process","version","replace","fastifyVersion","pinoVersion","nestjsVersion","apitallyVersion","paths","Object","fromEntries","setConsumer","apitallyConsumer","undefined","consumerIdentifier","emitWarning","elapsedTime","regex","matches","match","exec","index","map","m","i","endIndex","length","matchSplit","split","loc","join","substring","filter"]}
1
+ {"version":3,"sources":["../../src/fastify/plugin.ts"],"sourcesContent":["import type {\n FastifyError,\n FastifyPluginAsync,\n FastifyReply,\n FastifyRequest,\n} from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { AsyncLocalStorage, AsyncResource } from \"node:async_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertBody, convertHeaders } from \"../common/requestLogger.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n PathInfo,\n ValidationError,\n} from \"../common/types.js\";\nimport {\n patchConsole,\n patchNestLogger,\n patchPinoLogger,\n patchWinston,\n} from \"../loggers/index.js\";\n\nconst LOGS_SYMBOL = Symbol(\"apitally.logs\");\nconst ASYNC_RESOURCE_SYMBOL = Symbol(\"apitally.logsContextAsyncResource\");\n\ndeclare module \"fastify\" {\n interface FastifyReply {\n payload: any;\n serverError?: FastifyError;\n }\n\n interface FastifyRequest {\n apitallyConsumer?: ApitallyConsumer | string | null;\n consumerIdentifier?: ApitallyConsumer | string | null; // For backwards compatibility\n\n [LOGS_SYMBOL]?: LogRecord[];\n [ASYNC_RESOURCE_SYMBOL]?: AsyncResource;\n }\n}\n\nconst apitallyPlugin: FastifyPluginAsync<ApitallyConfig> = async (\n fastify,\n config,\n) => {\n const client = new ApitallyClient(config);\n const routes: PathInfo[] = [];\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n patchPinoLogger(fastify.log, logsContext);\n patchNestLogger(logsContext);\n }\n\n fastify.decorateRequest(\"apitallyConsumer\", null);\n fastify.decorateRequest(\"consumerIdentifier\", null); // For backwards compatibility\n fastify.decorateReply(\"payload\", null);\n\n fastify.addHook(\"onRoute\", (routeOptions) => {\n const methods = Array.isArray(routeOptions.method)\n ? routeOptions.method\n : [routeOptions.method];\n methods.forEach((method) => {\n if (![\"HEAD\", \"OPTIONS\"].includes(method.toUpperCase())) {\n routes.push({\n method: method.toUpperCase(),\n path: routeOptions.url,\n });\n }\n });\n });\n\n fastify.addHook(\"onReady\", () => {\n client.setStartupData(getAppInfo(routes, config.appVersion));\n client.startSync();\n });\n\n fastify.addHook(\"onClose\", async () => {\n await client.handleShutdown();\n });\n\n // Establish logs context for each request\n fastify.addHook(\"onRequest\", (request, reply, done) => {\n if (client.isEnabled()) {\n const logs: LogRecord[] = [];\n request[LOGS_SYMBOL] = logs;\n logsContext.run(logs, () => {\n const asyncResource = new AsyncResource(\"ApitallyLogsContext\");\n request[ASYNC_RESOURCE_SYMBOL] = asyncResource;\n asyncResource.runInAsyncScope(done, request.raw);\n });\n } else {\n done();\n }\n });\n\n // Restore async context for later hooks and route handlers\n fastify.addHook(\"preValidation\", (request, reply, done) => {\n if (client.isEnabled() && request[ASYNC_RESOURCE_SYMBOL]) {\n const asyncResource = request[ASYNC_RESOURCE_SYMBOL];\n asyncResource.runInAsyncScope(done, request.raw);\n } else {\n done();\n }\n });\n\n fastify.addHook(\"onSend\", (request, reply, payload: any, done) => {\n const contentType = reply.getHeader(\"content-type\") as string | undefined;\n if (client.requestLogger.isSupportedContentType(contentType)) {\n reply.payload = payload;\n }\n done();\n });\n\n fastify.addHook(\"onError\", (request, reply, error, done) => {\n if (!error.statusCode || error.statusCode === 500) {\n reply.serverError = error;\n }\n done();\n });\n\n fastify.addHook(\"onResponse\", (request, reply, done) => {\n if (client.isEnabled() && request.method.toUpperCase() !== \"OPTIONS\") {\n // Get path from routeOptions if available (from v4), otherwise fallback to deprecated routerPath\n const consumer = getConsumer(request);\n const path =\n \"routeOptions\" in request\n ? (request as any).routeOptions.url\n : (request as any).routerPath;\n const requestSize = parseContentLength(request.headers[\"content-length\"]);\n const responseSize = parseContentLength(\n reply.getHeader(\"content-length\"),\n );\n const responseTime = getResponseTime(reply);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path,\n statusCode: reply.statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (\n (reply.statusCode === 400 || reply.statusCode === 422) &&\n reply.payload\n ) {\n try {\n const parsedPayload = JSON.parse(reply.payload);\n const validationErrors: ValidationError[] = [];\n\n if (\n (!parsedPayload.code ||\n parsedPayload.code === \"FST_ERR_VALIDATION\") &&\n typeof parsedPayload.message === \"string\"\n ) {\n validationErrors.push(...extractAjvErrors(parsedPayload.message));\n } else if (Array.isArray(parsedPayload.message)) {\n validationErrors.push(\n ...extractNestValidationErrors(parsedPayload.message),\n );\n }\n\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n ...error,\n });\n });\n } catch (error) {} // eslint-disable-line no-empty\n }\n\n if (reply.statusCode === 500 && reply.serverError) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n type: reply.serverError.name,\n msg: reply.serverError.message,\n traceback: reply.serverError.stack || \"\",\n });\n }\n\n if (client.requestLogger.enabled) {\n const logs = request[LOGS_SYMBOL];\n client.requestLogger.logRequest(\n {\n timestamp: Date.now() / 1000,\n method: request.method,\n path,\n url: `${request.protocol}://${request.host ?? request.hostname}${request.originalUrl ?? request.url}`,\n headers: convertHeaders(request.headers),\n size: requestSize,\n consumer: consumer?.identifier,\n body: convertBody(request.body, request.headers[\"content-type\"]),\n },\n {\n statusCode: reply.statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(reply.getHeaders()),\n size: responseSize,\n body: convertBody(\n reply.payload,\n reply.getHeader(\"content-type\")?.toString(),\n ),\n },\n reply.serverError,\n logs,\n );\n }\n }\n\n done();\n });\n};\n\nfunction getAppInfo(routes: PathInfo[], appVersion?: string) {\n const versions = [[\"nodejs\", process.version.replace(/^v/, \"\")]];\n const fastifyVersion = getPackageVersion(\"fastify\");\n const pinoVersion = getPackageVersion(\"pino\");\n const nestjsVersion = getPackageVersion(\"@nestjs/core\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (fastifyVersion) {\n versions.push([\"fastify\", fastifyVersion]);\n }\n if (pinoVersion) {\n versions.push([\"pino\", pinoVersion]);\n }\n if (nestjsVersion) {\n versions.push([\"nestjs\", nestjsVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: routes,\n versions: Object.fromEntries(versions),\n client: \"js:fastify\",\n };\n}\n\nexport function setConsumer(\n request: FastifyRequest,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n request.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(request: FastifyRequest) {\n if (request.apitallyConsumer) {\n return consumerFromStringOrObject(request.apitallyConsumer);\n } else if (request.consumerIdentifier) {\n // For backwards compatibility\n process.emitWarning(\n \"The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.\",\n \"DeprecationWarning\",\n );\n return consumerFromStringOrObject(request.consumerIdentifier);\n }\n return null;\n}\n\nfunction getResponseTime(reply: FastifyReply) {\n if (reply.elapsedTime !== undefined) {\n return reply.elapsedTime;\n } else if ((reply as any).getResponseTime !== undefined) {\n return (reply as any).getResponseTime();\n }\n return 0;\n}\n\nfunction extractAjvErrors(message: string): ValidationError[] {\n try {\n const regex =\n /(?<=^|, )((?:headers|params|query|querystring|body)[/.][^ ]+)(?= )/g;\n const matches: { match: string; index: number }[] = [];\n let match: RegExpExecArray | null;\n while ((match = regex.exec(message)) !== null) {\n matches.push({ match: match[0], index: match.index });\n }\n\n return matches.map((m, i) => {\n const endIndex =\n i + 1 < matches.length ? matches[i + 1].index - 2 : message.length;\n const matchSplit = m.match.split(/[/.]/);\n if (matchSplit[0] === \"querystring\") {\n matchSplit[0] = \"query\";\n }\n return {\n loc: matchSplit.join(\".\"),\n msg: message.substring(m.index, endIndex),\n type: \"\",\n };\n });\n } catch (error) {\n return [];\n }\n}\n\nfunction extractNestValidationErrors(message: any[]): ValidationError[] {\n try {\n return message\n .filter((msg: any) => typeof msg === \"string\")\n .map((msg: any) => ({\n loc: \"\",\n msg,\n type: \"\",\n }));\n } catch (error) {\n return [];\n }\n}\n\nexport { apitallyPlugin };\n\nexport default fp(apitallyPlugin, {\n name: \"apitally\",\n});\n"],"mappings":"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","names":["fp","AsyncLocalStorage","AsyncResource","ApitallyClient","consumerFromStringOrObject","parseContentLength","getPackageVersion","convertBody","convertHeaders","patchConsole","patchNestLogger","patchPinoLogger","patchWinston","LOGS_SYMBOL","Symbol","ASYNC_RESOURCE_SYMBOL","apitallyPlugin","fastify","config","client","routes","logsContext","requestLogger","captureLogs","log","decorateRequest","decorateReply","addHook","routeOptions","methods","Array","isArray","method","forEach","includes","toUpperCase","push","path","url","setStartupData","getAppInfo","appVersion","startSync","handleShutdown","request","reply","done","isEnabled","logs","run","asyncResource","runInAsyncScope","raw","payload","contentType","getHeader","isSupportedContentType","error","statusCode","serverError","consumer","getConsumer","routerPath","requestSize","headers","responseSize","responseTime","getResponseTime","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","parsedPayload","JSON","parse","validationErrors","code","message","extractAjvErrors","extractNestValidationErrors","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","traceback","stack","enabled","logRequest","timestamp","Date","now","protocol","host","hostname","originalUrl","size","body","getHeaders","toString","versions","process","version","replace","fastifyVersion","pinoVersion","nestjsVersion","apitallyVersion","paths","Object","fromEntries","setConsumer","apitallyConsumer","undefined","consumerIdentifier","emitWarning","elapsedTime","regex","matches","match","exec","index","map","m","i","endIndex","length","matchSplit","split","loc","join","substring","filter"]}
@@ -33,8 +33,8 @@ var import_requestLogger = require("../common/requestLogger.js");
33
33
  var import_response = require("../common/response.js");
34
34
  var import_loggers = require("../loggers/index.js");
35
35
  var import_utils = require("./utils.js");
36
- const REQUEST_TIMESTAMP_SYMBOL = Symbol("apitally.requestTimestamp");
37
- const REQUEST_BODY_SYMBOL = Symbol("apitally.requestBody");
36
+ const REQUEST_TIMESTAMP_SYMBOL = /* @__PURE__ */ Symbol("apitally.requestTimestamp");
37
+ const REQUEST_BODY_SYMBOL = /* @__PURE__ */ Symbol("apitally.requestBody");
38
38
  const jsonHeaders = new Headers({
39
39
  "content-type": "application/json;charset=UTF-8"
40
40
  });