apitally 0.21.4 → 0.22.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.
@@ -61,77 +61,77 @@ const apitallyPlugin = (0, import_h3.definePlugin)((app, config) => {
61
61
  return response;
62
62
  }
63
63
  const startTime = event.context[REQUEST_TIMESTAMP_SYMBOL];
64
- const responseTime = startTime ? import_node_perf_hooks.performance.now() - startTime : 0;
65
64
  const path = (_a = event.context.matchedRoute) == null ? void 0 : _a.route;
66
- const statusCode = (response == null ? void 0 : response.status) || (error == null ? void 0 : error.status) || 500;
67
- const requestSize = (0, import_headers.parseContentLength)(event.req.headers.get("content-length"));
68
- let responseSize = 0;
69
- let newResponse = response;
70
- if (response) {
71
- [responseSize, newResponse] = await (0, import_response.measureResponseSize)(response);
72
- }
73
65
  const consumer = getConsumer(event);
74
66
  client.consumerRegistry.addOrUpdateConsumer(consumer);
75
- if (path) {
76
- client.requestCounter.addRequest({
77
- consumer: consumer == null ? void 0 : consumer.identifier,
78
- method: event.req.method,
79
- path,
80
- statusCode,
81
- responseTime,
82
- requestSize,
83
- responseSize
67
+ if (!response) {
68
+ response = new Response(null, {
69
+ status: (error == null ? void 0 : error.status) || 500,
70
+ statusText: (error == null ? void 0 : error.statusText) || "Internal Server Error",
71
+ headers: (error == null ? void 0 : error.headers) ? (0, import_headers.mergeHeaders)(jsonHeaders, error.headers) : jsonHeaders
84
72
  });
85
- if ((error == null ? void 0 : error.status) === 400 && error.data.name === "ZodError") {
86
- const zodError = error.data;
87
- (_b = zodError.issues) == null ? void 0 : _b.forEach((issue) => {
88
- client.validationErrorCounter.addValidationError({
89
- consumer: consumer == null ? void 0 : consumer.identifier,
90
- method: event.req.method,
91
- path,
92
- loc: issue.path.join("."),
93
- msg: issue.message,
94
- type: issue.code
95
- });
73
+ }
74
+ const [newResponse, responsePromise] = (0, import_response.captureResponse)(response, {
75
+ captureBody: client.requestLogger.enabled && client.requestLogger.config.logResponseBody,
76
+ maxBodySize: client.requestLogger.maxBodySize
77
+ });
78
+ responsePromise.then(async (capturedResponse) => {
79
+ const responseTime = startTime ? import_node_perf_hooks.performance.now() - startTime : 0;
80
+ const responseSize = capturedResponse.completed ? capturedResponse.size : void 0;
81
+ const requestSize = (0, import_headers.parseContentLength)(event.req.headers.get("content-length"));
82
+ if (path) {
83
+ client.requestCounter.addRequest({
84
+ consumer: consumer == null ? void 0 : consumer.identifier,
85
+ method: event.req.method,
86
+ path,
87
+ statusCode: response.status,
88
+ responseTime,
89
+ requestSize,
90
+ responseSize
96
91
  });
97
92
  }
98
- if ((error == null ? void 0 : error.status) === 500 && error.cause instanceof Error) {
99
- client.serverErrorCounter.addServerError({
93
+ if (client.requestLogger.enabled) {
94
+ const logs = logsContext.getStore();
95
+ client.requestLogger.logRequest({
96
+ timestamp: (Date.now() - responseTime) / 1e3,
97
+ method: event.req.method,
98
+ path,
99
+ url: event.req.url,
100
+ headers: (0, import_requestLogger.convertHeaders)(Object.fromEntries(event.req.headers.entries())),
101
+ size: requestSize,
102
+ consumer: consumer == null ? void 0 : consumer.identifier,
103
+ body: event.context[REQUEST_BODY_SYMBOL]
104
+ }, {
105
+ statusCode: response.status,
106
+ responseTime: responseTime / 1e3,
107
+ headers: (0, import_requestLogger.convertHeaders)(Object.fromEntries(response.headers.entries())),
108
+ size: responseSize,
109
+ body: capturedResponse.body
110
+ }, (error == null ? void 0 : error.cause) instanceof Error ? error.cause : void 0, logs);
111
+ }
112
+ });
113
+ if (path && (error == null ? void 0 : error.status) === 400 && error.data && error.data.name === "ZodError") {
114
+ const zodError = error.data;
115
+ (_b = zodError.issues) == null ? void 0 : _b.forEach((issue) => {
116
+ client.validationErrorCounter.addValidationError({
100
117
  consumer: consumer == null ? void 0 : consumer.identifier,
101
118
  method: event.req.method,
102
119
  path,
103
- type: error.cause.name,
104
- msg: error.cause.message,
105
- traceback: error.cause.stack || ""
120
+ loc: issue.path.join("."),
121
+ msg: issue.message,
122
+ type: issue.code
106
123
  });
107
- }
124
+ });
108
125
  }
109
- if (client.requestLogger.enabled) {
110
- const responseHeaders = response ? response.headers : (error == null ? void 0 : error.headers) ? (0, import_headers.mergeHeaders)(jsonHeaders, error.headers) : jsonHeaders;
111
- const responseContentType = responseHeaders.get("content-type");
112
- let responseBody;
113
- if (newResponse && client.requestLogger.config.logResponseBody && client.requestLogger.isSupportedContentType(responseContentType)) {
114
- [responseBody, newResponse] = await (0, import_response.getResponseBody)(newResponse);
115
- } else if (error && client.requestLogger.config.logResponseBody) {
116
- responseBody = Buffer.from(JSON.stringify(error.toJSON()));
117
- }
118
- const logs = logsContext.getStore();
119
- client.requestLogger.logRequest({
120
- timestamp: (Date.now() - responseTime) / 1e3,
126
+ if (path && (error == null ? void 0 : error.status) === 500 && error.cause instanceof Error) {
127
+ client.serverErrorCounter.addServerError({
128
+ consumer: consumer == null ? void 0 : consumer.identifier,
121
129
  method: event.req.method,
122
130
  path,
123
- url: event.req.url,
124
- headers: (0, import_requestLogger.convertHeaders)(Object.fromEntries(event.req.headers.entries())),
125
- size: requestSize,
126
- consumer: consumer == null ? void 0 : consumer.identifier,
127
- body: event.context[REQUEST_BODY_SYMBOL]
128
- }, {
129
- statusCode,
130
- responseTime: responseTime / 1e3,
131
- headers: (0, import_requestLogger.convertHeaders)(Object.fromEntries(responseHeaders.entries())),
132
- size: responseSize,
133
- body: responseBody
134
- }, (error == null ? void 0 : error.cause) instanceof Error ? error.cause : void 0, logs);
131
+ type: error.cause.name,
132
+ msg: error.cause.message,
133
+ traceback: error.cause.stack || ""
134
+ });
135
135
  }
136
136
  return newResponse;
137
137
  }, "handleResponse");
@@ -151,7 +151,7 @@ const apitallyPlugin = (0, import_h3.definePlugin)((app, config) => {
151
151
  }
152
152
  })).use((0, import_h3.onError)((error, event) => {
153
153
  if (client.isEnabled()) {
154
- return handleResponse(event, void 0, error);
154
+ handleResponse(event, void 0, error);
155
155
  }
156
156
  }));
157
157
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/h3/plugin.ts"],"sourcesContent":["import type { H3Event, HTTPError } from \"h3\";\nimport { definePlugin, onError, onRequest, onResponse } from \"h3\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\nimport type { ZodError } from \"zod\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { mergeHeaders, parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { getResponseBody, measureResponseSize } 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 REQUEST_TIMESTAMP_SYMBOL = Symbol(\"apitally.requestTimestamp\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\n\ndeclare module \"h3\" {\n interface H3EventContext {\n apitallyConsumer?: ApitallyConsumer | string;\n\n [REQUEST_TIMESTAMP_SYMBOL]?: number;\n [REQUEST_BODY_SYMBOL]?: Buffer;\n }\n}\n\nconst jsonHeaders = new Headers({\n \"content-type\": \"application/json;charset=UTF-8\",\n});\n\nexport const apitallyPlugin = definePlugin<ApitallyConfig>((app, config) => {\n const client = new ApitallyClient(config);\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n const setStartupData = (attempt: number = 1) => {\n const appInfo = getAppInfo(app, config.appVersion);\n if (appInfo.paths.length > 0 || attempt >= 10) {\n client.setStartupData(appInfo);\n client.startSync();\n } else {\n setTimeout(() => setStartupData(attempt + 1), 500);\n }\n };\n setTimeout(() => setStartupData(), 500);\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n const handleResponse = async (\n event: H3Event,\n response?: Response,\n error?: HTTPError,\n ) => {\n if (event.req.method.toUpperCase() === \"OPTIONS\") {\n return response;\n }\n\n const startTime = event.context[REQUEST_TIMESTAMP_SYMBOL];\n const responseTime = startTime ? performance.now() - startTime : 0;\n const path = event.context.matchedRoute?.route;\n const statusCode = response?.status || error?.status || 500;\n\n const requestSize = parseContentLength(\n event.req.headers.get(\"content-length\"),\n );\n let responseSize = 0;\n let newResponse = response;\n if (response) {\n [responseSize, newResponse] = await measureResponseSize(response);\n }\n\n const consumer = getConsumer(event);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n if (path) {\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: event.req.method,\n path,\n statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (error?.status === 400 && (error.data as any).name === \"ZodError\") {\n const zodError = error.data as ZodError;\n zodError.issues?.forEach((issue) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: event.req.method,\n path,\n loc: issue.path.join(\".\"),\n msg: issue.message,\n type: issue.code,\n });\n });\n }\n\n if (error?.status === 500 && error.cause instanceof Error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: event.req.method,\n path,\n type: error.cause.name,\n msg: error.cause.message,\n traceback: error.cause.stack || \"\",\n });\n }\n }\n\n if (client.requestLogger.enabled) {\n const responseHeaders = response\n ? response.headers\n : error?.headers\n ? mergeHeaders(jsonHeaders, error.headers)\n : jsonHeaders;\n const responseContentType = responseHeaders.get(\"content-type\");\n let responseBody;\n\n if (\n newResponse &&\n client.requestLogger.config.logResponseBody &&\n client.requestLogger.isSupportedContentType(responseContentType)\n ) {\n [responseBody, newResponse] = await getResponseBody(newResponse);\n } else if (error && client.requestLogger.config.logResponseBody) {\n responseBody = Buffer.from(JSON.stringify(error.toJSON()));\n }\n\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: (Date.now() - responseTime) / 1000,\n method: event.req.method,\n path,\n url: event.req.url,\n headers: convertHeaders(\n Object.fromEntries(event.req.headers.entries()),\n ),\n size: requestSize,\n consumer: consumer?.identifier,\n body: event.context[REQUEST_BODY_SYMBOL],\n },\n {\n statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(\n Object.fromEntries(responseHeaders.entries()),\n ),\n size: responseSize,\n body: responseBody,\n },\n error?.cause instanceof Error ? error.cause : undefined,\n logs,\n );\n }\n\n return newResponse;\n };\n\n app\n .use(\n onRequest(async (event) => {\n logsContext.enterWith([]);\n event.context[REQUEST_TIMESTAMP_SYMBOL] = performance.now();\n const requestContentType = event.req.headers.get(\"content-type\");\n const requestSize =\n parseContentLength(event.req.headers.get(\"content-length\")) ?? 0;\n\n if (\n client.requestLogger.enabled &&\n client.requestLogger.config.logRequestBody &&\n client.requestLogger.isSupportedContentType(requestContentType) &&\n requestSize <= client.requestLogger.maxBodySize\n ) {\n const clonedRequest = event.req.clone();\n const requestBody = Buffer.from(await clonedRequest.arrayBuffer());\n event.context[REQUEST_BODY_SYMBOL] = requestBody;\n }\n }),\n )\n .use(\n onResponse((response, event) => {\n if (client.isEnabled()) {\n return handleResponse(event, response, undefined);\n }\n }),\n )\n .use(\n onError((error, event) => {\n if (client.isEnabled()) {\n return handleResponse(event, undefined, error);\n }\n }),\n );\n});\n\nexport function setConsumer(\n event: H3Event,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n event.context.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(event: H3Event) {\n const consumer = event.context.apitallyConsumer;\n if (consumer) {\n return consumerFromStringOrObject(consumer);\n }\n return null;\n}\n"],"mappings":"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","names":["REQUEST_TIMESTAMP_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","jsonHeaders","Headers","apitallyPlugin","definePlugin","app","config","client","ApitallyClient","logsContext","AsyncLocalStorage","setStartupData","attempt","appInfo","getAppInfo","appVersion","paths","length","startSync","setTimeout","requestLogger","captureLogs","patchConsole","patchWinston","handleResponse","event","response","error","req","method","toUpperCase","startTime","context","responseTime","performance","now","path","matchedRoute","route","statusCode","status","requestSize","parseContentLength","headers","get","responseSize","newResponse","measureResponseSize","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","data","name","zodError","issues","forEach","issue","validationErrorCounter","addValidationError","loc","join","msg","message","type","code","cause","Error","serverErrorCounter","addServerError","traceback","stack","enabled","responseHeaders","mergeHeaders","responseContentType","responseBody","logResponseBody","isSupportedContentType","getResponseBody","Buffer","from","JSON","stringify","toJSON","logs","getStore","logRequest","timestamp","Date","url","convertHeaders","Object","fromEntries","entries","size","body","undefined","use","onRequest","enterWith","requestContentType","logRequestBody","maxBodySize","clonedRequest","clone","requestBody","arrayBuffer","onResponse","isEnabled","onError","setConsumer","apitallyConsumer","consumerFromStringOrObject"]}
1
+ {"version":3,"sources":["../../src/h3/plugin.ts"],"sourcesContent":["import type { H3Event, HTTPError } from \"h3\";\nimport { definePlugin, onError, onRequest, onResponse } from \"h3\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\nimport type { ZodError } from \"zod\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { mergeHeaders, parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { 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 REQUEST_TIMESTAMP_SYMBOL = Symbol(\"apitally.requestTimestamp\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\n\ndeclare module \"h3\" {\n interface H3EventContext {\n apitallyConsumer?: ApitallyConsumer | string;\n\n [REQUEST_TIMESTAMP_SYMBOL]?: number;\n [REQUEST_BODY_SYMBOL]?: Buffer;\n }\n}\n\nconst jsonHeaders = new Headers({\n \"content-type\": \"application/json;charset=UTF-8\",\n});\n\nexport const apitallyPlugin = definePlugin<ApitallyConfig>((app, config) => {\n const client = new ApitallyClient(config);\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n const setStartupData = (attempt: number = 1) => {\n const appInfo = getAppInfo(app, config.appVersion);\n if (appInfo.paths.length > 0 || attempt >= 10) {\n client.setStartupData(appInfo);\n client.startSync();\n } else {\n setTimeout(() => setStartupData(attempt + 1), 500);\n }\n };\n setTimeout(() => setStartupData(), 500);\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n const handleResponse = async (\n event: H3Event,\n response?: Response,\n error?: HTTPError,\n ) => {\n if (event.req.method.toUpperCase() === \"OPTIONS\") {\n return response;\n }\n\n const startTime = event.context[REQUEST_TIMESTAMP_SYMBOL];\n const path = event.context.matchedRoute?.route;\n\n const consumer = getConsumer(event);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n if (!response) {\n response = new Response(null, {\n status: error?.status || 500,\n statusText: error?.statusText || \"Internal Server Error\",\n headers: error?.headers\n ? mergeHeaders(jsonHeaders, error.headers)\n : jsonHeaders,\n });\n }\n\n const [newResponse, responsePromise] = captureResponse(response, {\n captureBody:\n client.requestLogger.enabled &&\n client.requestLogger.config.logResponseBody,\n maxBodySize: client.requestLogger.maxBodySize,\n });\n\n responsePromise.then(async (capturedResponse) => {\n const responseTime = startTime ? performance.now() - startTime : 0;\n const responseSize = capturedResponse.completed\n ? capturedResponse.size\n : undefined;\n const requestSize = parseContentLength(\n event.req.headers.get(\"content-length\"),\n );\n\n if (path) {\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: event.req.method,\n path,\n statusCode: response.status,\n responseTime,\n requestSize,\n responseSize,\n });\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: event.req.method,\n path,\n url: event.req.url,\n headers: convertHeaders(\n Object.fromEntries(event.req.headers.entries()),\n ),\n size: requestSize,\n consumer: consumer?.identifier,\n body: event.context[REQUEST_BODY_SYMBOL],\n },\n {\n statusCode: response.status,\n responseTime: responseTime / 1000,\n headers: convertHeaders(\n Object.fromEntries(response.headers.entries()),\n ),\n size: responseSize,\n body: capturedResponse.body,\n },\n error?.cause instanceof Error ? error.cause : undefined,\n logs,\n );\n }\n });\n\n if (\n path &&\n error?.status === 400 &&\n error.data &&\n (error.data as any).name === \"ZodError\"\n ) {\n const zodError = error.data as ZodError;\n zodError.issues?.forEach((issue) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: event.req.method,\n path,\n loc: issue.path.join(\".\"),\n msg: issue.message,\n type: issue.code,\n });\n });\n }\n\n if (path && error?.status === 500 && error.cause instanceof Error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: event.req.method,\n path,\n type: error.cause.name,\n msg: error.cause.message,\n traceback: error.cause.stack || \"\",\n });\n }\n\n return newResponse;\n };\n\n app\n .use(\n onRequest(async (event) => {\n logsContext.enterWith([]);\n event.context[REQUEST_TIMESTAMP_SYMBOL] = performance.now();\n const requestContentType = event.req.headers.get(\"content-type\");\n const requestSize =\n parseContentLength(event.req.headers.get(\"content-length\")) ?? 0;\n\n if (\n client.requestLogger.enabled &&\n client.requestLogger.config.logRequestBody &&\n client.requestLogger.isSupportedContentType(requestContentType) &&\n requestSize <= client.requestLogger.maxBodySize\n ) {\n const clonedRequest = event.req.clone();\n const requestBody = Buffer.from(await clonedRequest.arrayBuffer());\n event.context[REQUEST_BODY_SYMBOL] = requestBody;\n }\n }),\n )\n .use(\n onResponse((response, event) => {\n if (client.isEnabled()) {\n return handleResponse(event, response, undefined);\n }\n }),\n )\n .use(\n onError((error, event) => {\n if (client.isEnabled()) {\n handleResponse(event, undefined, error);\n }\n }),\n );\n});\n\nexport function setConsumer(\n event: H3Event,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n event.context.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(event: H3Event) {\n const consumer = event.context.apitallyConsumer;\n if (consumer) {\n return consumerFromStringOrObject(consumer);\n }\n return null;\n}\n"],"mappings":"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","names":["REQUEST_TIMESTAMP_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","jsonHeaders","Headers","apitallyPlugin","definePlugin","app","config","client","ApitallyClient","logsContext","AsyncLocalStorage","setStartupData","attempt","appInfo","getAppInfo","appVersion","paths","length","startSync","setTimeout","requestLogger","captureLogs","patchConsole","patchWinston","handleResponse","event","response","error","req","method","toUpperCase","startTime","context","path","matchedRoute","route","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","Response","status","statusText","headers","mergeHeaders","newResponse","responsePromise","captureResponse","captureBody","enabled","logResponseBody","maxBodySize","then","capturedResponse","responseTime","performance","now","responseSize","completed","size","undefined","requestSize","parseContentLength","get","requestCounter","addRequest","identifier","statusCode","logs","getStore","logRequest","timestamp","Date","url","convertHeaders","Object","fromEntries","entries","body","cause","Error","data","name","zodError","issues","forEach","issue","validationErrorCounter","addValidationError","loc","join","msg","message","type","code","serverErrorCounter","addServerError","traceback","stack","use","onRequest","enterWith","requestContentType","logRequestBody","isSupportedContentType","clonedRequest","clone","requestBody","Buffer","from","arrayBuffer","onResponse","isEnabled","onError","setConsumer","apitallyConsumer","consumerFromStringOrObject"]}
package/dist/h3/plugin.js CHANGED
@@ -7,7 +7,7 @@ import { ApitallyClient } from "../common/client.js";
7
7
  import { consumerFromStringOrObject } from "../common/consumerRegistry.js";
8
8
  import { mergeHeaders, parseContentLength } from "../common/headers.js";
9
9
  import { convertHeaders } from "../common/requestLogger.js";
10
- import { getResponseBody, measureResponseSize } from "../common/response.js";
10
+ import { captureResponse } from "../common/response.js";
11
11
  import { patchConsole, patchWinston } from "../loggers/index.js";
12
12
  import { getAppInfo } from "./utils.js";
13
13
  const REQUEST_TIMESTAMP_SYMBOL = Symbol("apitally.requestTimestamp");
@@ -38,77 +38,77 @@ const apitallyPlugin = definePlugin((app, config) => {
38
38
  return response;
39
39
  }
40
40
  const startTime = event.context[REQUEST_TIMESTAMP_SYMBOL];
41
- const responseTime = startTime ? performance.now() - startTime : 0;
42
41
  const path = (_a = event.context.matchedRoute) == null ? void 0 : _a.route;
43
- const statusCode = (response == null ? void 0 : response.status) || (error == null ? void 0 : error.status) || 500;
44
- const requestSize = parseContentLength(event.req.headers.get("content-length"));
45
- let responseSize = 0;
46
- let newResponse = response;
47
- if (response) {
48
- [responseSize, newResponse] = await measureResponseSize(response);
49
- }
50
42
  const consumer = getConsumer(event);
51
43
  client.consumerRegistry.addOrUpdateConsumer(consumer);
52
- if (path) {
53
- client.requestCounter.addRequest({
54
- consumer: consumer == null ? void 0 : consumer.identifier,
55
- method: event.req.method,
56
- path,
57
- statusCode,
58
- responseTime,
59
- requestSize,
60
- responseSize
44
+ if (!response) {
45
+ response = new Response(null, {
46
+ status: (error == null ? void 0 : error.status) || 500,
47
+ statusText: (error == null ? void 0 : error.statusText) || "Internal Server Error",
48
+ headers: (error == null ? void 0 : error.headers) ? mergeHeaders(jsonHeaders, error.headers) : jsonHeaders
61
49
  });
62
- if ((error == null ? void 0 : error.status) === 400 && error.data.name === "ZodError") {
63
- const zodError = error.data;
64
- (_b = zodError.issues) == null ? void 0 : _b.forEach((issue) => {
65
- client.validationErrorCounter.addValidationError({
66
- consumer: consumer == null ? void 0 : consumer.identifier,
67
- method: event.req.method,
68
- path,
69
- loc: issue.path.join("."),
70
- msg: issue.message,
71
- type: issue.code
72
- });
50
+ }
51
+ const [newResponse, responsePromise] = captureResponse(response, {
52
+ captureBody: client.requestLogger.enabled && client.requestLogger.config.logResponseBody,
53
+ maxBodySize: client.requestLogger.maxBodySize
54
+ });
55
+ responsePromise.then(async (capturedResponse) => {
56
+ const responseTime = startTime ? performance.now() - startTime : 0;
57
+ const responseSize = capturedResponse.completed ? capturedResponse.size : void 0;
58
+ const requestSize = parseContentLength(event.req.headers.get("content-length"));
59
+ if (path) {
60
+ client.requestCounter.addRequest({
61
+ consumer: consumer == null ? void 0 : consumer.identifier,
62
+ method: event.req.method,
63
+ path,
64
+ statusCode: response.status,
65
+ responseTime,
66
+ requestSize,
67
+ responseSize
73
68
  });
74
69
  }
75
- if ((error == null ? void 0 : error.status) === 500 && error.cause instanceof Error) {
76
- client.serverErrorCounter.addServerError({
70
+ if (client.requestLogger.enabled) {
71
+ const logs = logsContext.getStore();
72
+ client.requestLogger.logRequest({
73
+ timestamp: (Date.now() - responseTime) / 1e3,
74
+ method: event.req.method,
75
+ path,
76
+ url: event.req.url,
77
+ headers: convertHeaders(Object.fromEntries(event.req.headers.entries())),
78
+ size: requestSize,
79
+ consumer: consumer == null ? void 0 : consumer.identifier,
80
+ body: event.context[REQUEST_BODY_SYMBOL]
81
+ }, {
82
+ statusCode: response.status,
83
+ responseTime: responseTime / 1e3,
84
+ headers: convertHeaders(Object.fromEntries(response.headers.entries())),
85
+ size: responseSize,
86
+ body: capturedResponse.body
87
+ }, (error == null ? void 0 : error.cause) instanceof Error ? error.cause : void 0, logs);
88
+ }
89
+ });
90
+ if (path && (error == null ? void 0 : error.status) === 400 && error.data && error.data.name === "ZodError") {
91
+ const zodError = error.data;
92
+ (_b = zodError.issues) == null ? void 0 : _b.forEach((issue) => {
93
+ client.validationErrorCounter.addValidationError({
77
94
  consumer: consumer == null ? void 0 : consumer.identifier,
78
95
  method: event.req.method,
79
96
  path,
80
- type: error.cause.name,
81
- msg: error.cause.message,
82
- traceback: error.cause.stack || ""
97
+ loc: issue.path.join("."),
98
+ msg: issue.message,
99
+ type: issue.code
83
100
  });
84
- }
101
+ });
85
102
  }
86
- if (client.requestLogger.enabled) {
87
- const responseHeaders = response ? response.headers : (error == null ? void 0 : error.headers) ? mergeHeaders(jsonHeaders, error.headers) : jsonHeaders;
88
- const responseContentType = responseHeaders.get("content-type");
89
- let responseBody;
90
- if (newResponse && client.requestLogger.config.logResponseBody && client.requestLogger.isSupportedContentType(responseContentType)) {
91
- [responseBody, newResponse] = await getResponseBody(newResponse);
92
- } else if (error && client.requestLogger.config.logResponseBody) {
93
- responseBody = Buffer.from(JSON.stringify(error.toJSON()));
94
- }
95
- const logs = logsContext.getStore();
96
- client.requestLogger.logRequest({
97
- timestamp: (Date.now() - responseTime) / 1e3,
103
+ if (path && (error == null ? void 0 : error.status) === 500 && error.cause instanceof Error) {
104
+ client.serverErrorCounter.addServerError({
105
+ consumer: consumer == null ? void 0 : consumer.identifier,
98
106
  method: event.req.method,
99
107
  path,
100
- url: event.req.url,
101
- headers: convertHeaders(Object.fromEntries(event.req.headers.entries())),
102
- size: requestSize,
103
- consumer: consumer == null ? void 0 : consumer.identifier,
104
- body: event.context[REQUEST_BODY_SYMBOL]
105
- }, {
106
- statusCode,
107
- responseTime: responseTime / 1e3,
108
- headers: convertHeaders(Object.fromEntries(responseHeaders.entries())),
109
- size: responseSize,
110
- body: responseBody
111
- }, (error == null ? void 0 : error.cause) instanceof Error ? error.cause : void 0, logs);
108
+ type: error.cause.name,
109
+ msg: error.cause.message,
110
+ traceback: error.cause.stack || ""
111
+ });
112
112
  }
113
113
  return newResponse;
114
114
  }, "handleResponse");
@@ -128,7 +128,7 @@ const apitallyPlugin = definePlugin((app, config) => {
128
128
  }
129
129
  })).use(onError((error, event) => {
130
130
  if (client.isEnabled()) {
131
- return handleResponse(event, void 0, error);
131
+ handleResponse(event, void 0, error);
132
132
  }
133
133
  }));
134
134
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/h3/plugin.ts"],"sourcesContent":["import type { H3Event, HTTPError } from \"h3\";\nimport { definePlugin, onError, onRequest, onResponse } from \"h3\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\nimport type { ZodError } from \"zod\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { mergeHeaders, parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { getResponseBody, measureResponseSize } 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 REQUEST_TIMESTAMP_SYMBOL = Symbol(\"apitally.requestTimestamp\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\n\ndeclare module \"h3\" {\n interface H3EventContext {\n apitallyConsumer?: ApitallyConsumer | string;\n\n [REQUEST_TIMESTAMP_SYMBOL]?: number;\n [REQUEST_BODY_SYMBOL]?: Buffer;\n }\n}\n\nconst jsonHeaders = new Headers({\n \"content-type\": \"application/json;charset=UTF-8\",\n});\n\nexport const apitallyPlugin = definePlugin<ApitallyConfig>((app, config) => {\n const client = new ApitallyClient(config);\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n const setStartupData = (attempt: number = 1) => {\n const appInfo = getAppInfo(app, config.appVersion);\n if (appInfo.paths.length > 0 || attempt >= 10) {\n client.setStartupData(appInfo);\n client.startSync();\n } else {\n setTimeout(() => setStartupData(attempt + 1), 500);\n }\n };\n setTimeout(() => setStartupData(), 500);\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n const handleResponse = async (\n event: H3Event,\n response?: Response,\n error?: HTTPError,\n ) => {\n if (event.req.method.toUpperCase() === \"OPTIONS\") {\n return response;\n }\n\n const startTime = event.context[REQUEST_TIMESTAMP_SYMBOL];\n const responseTime = startTime ? performance.now() - startTime : 0;\n const path = event.context.matchedRoute?.route;\n const statusCode = response?.status || error?.status || 500;\n\n const requestSize = parseContentLength(\n event.req.headers.get(\"content-length\"),\n );\n let responseSize = 0;\n let newResponse = response;\n if (response) {\n [responseSize, newResponse] = await measureResponseSize(response);\n }\n\n const consumer = getConsumer(event);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n if (path) {\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: event.req.method,\n path,\n statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (error?.status === 400 && (error.data as any).name === \"ZodError\") {\n const zodError = error.data as ZodError;\n zodError.issues?.forEach((issue) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: event.req.method,\n path,\n loc: issue.path.join(\".\"),\n msg: issue.message,\n type: issue.code,\n });\n });\n }\n\n if (error?.status === 500 && error.cause instanceof Error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: event.req.method,\n path,\n type: error.cause.name,\n msg: error.cause.message,\n traceback: error.cause.stack || \"\",\n });\n }\n }\n\n if (client.requestLogger.enabled) {\n const responseHeaders = response\n ? response.headers\n : error?.headers\n ? mergeHeaders(jsonHeaders, error.headers)\n : jsonHeaders;\n const responseContentType = responseHeaders.get(\"content-type\");\n let responseBody;\n\n if (\n newResponse &&\n client.requestLogger.config.logResponseBody &&\n client.requestLogger.isSupportedContentType(responseContentType)\n ) {\n [responseBody, newResponse] = await getResponseBody(newResponse);\n } else if (error && client.requestLogger.config.logResponseBody) {\n responseBody = Buffer.from(JSON.stringify(error.toJSON()));\n }\n\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: (Date.now() - responseTime) / 1000,\n method: event.req.method,\n path,\n url: event.req.url,\n headers: convertHeaders(\n Object.fromEntries(event.req.headers.entries()),\n ),\n size: requestSize,\n consumer: consumer?.identifier,\n body: event.context[REQUEST_BODY_SYMBOL],\n },\n {\n statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(\n Object.fromEntries(responseHeaders.entries()),\n ),\n size: responseSize,\n body: responseBody,\n },\n error?.cause instanceof Error ? error.cause : undefined,\n logs,\n );\n }\n\n return newResponse;\n };\n\n app\n .use(\n onRequest(async (event) => {\n logsContext.enterWith([]);\n event.context[REQUEST_TIMESTAMP_SYMBOL] = performance.now();\n const requestContentType = event.req.headers.get(\"content-type\");\n const requestSize =\n parseContentLength(event.req.headers.get(\"content-length\")) ?? 0;\n\n if (\n client.requestLogger.enabled &&\n client.requestLogger.config.logRequestBody &&\n client.requestLogger.isSupportedContentType(requestContentType) &&\n requestSize <= client.requestLogger.maxBodySize\n ) {\n const clonedRequest = event.req.clone();\n const requestBody = Buffer.from(await clonedRequest.arrayBuffer());\n event.context[REQUEST_BODY_SYMBOL] = requestBody;\n }\n }),\n )\n .use(\n onResponse((response, event) => {\n if (client.isEnabled()) {\n return handleResponse(event, response, undefined);\n }\n }),\n )\n .use(\n onError((error, event) => {\n if (client.isEnabled()) {\n return handleResponse(event, undefined, error);\n }\n }),\n );\n});\n\nexport function setConsumer(\n event: H3Event,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n event.context.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(event: H3Event) {\n const consumer = event.context.apitallyConsumer;\n if (consumer) {\n return consumerFromStringOrObject(consumer);\n }\n return null;\n}\n"],"mappings":"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","names":["definePlugin","onError","onRequest","onResponse","AsyncLocalStorage","performance","ApitallyClient","consumerFromStringOrObject","mergeHeaders","parseContentLength","convertHeaders","getResponseBody","measureResponseSize","patchConsole","patchWinston","getAppInfo","REQUEST_TIMESTAMP_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","jsonHeaders","Headers","apitallyPlugin","app","config","client","logsContext","setStartupData","attempt","appInfo","appVersion","paths","length","startSync","setTimeout","requestLogger","captureLogs","handleResponse","event","response","error","req","method","toUpperCase","startTime","context","responseTime","now","path","matchedRoute","route","statusCode","status","requestSize","headers","get","responseSize","newResponse","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","data","name","zodError","issues","forEach","issue","validationErrorCounter","addValidationError","loc","join","msg","message","type","code","cause","Error","serverErrorCounter","addServerError","traceback","stack","enabled","responseHeaders","responseContentType","responseBody","logResponseBody","isSupportedContentType","Buffer","from","JSON","stringify","toJSON","logs","getStore","logRequest","timestamp","Date","url","Object","fromEntries","entries","size","body","undefined","use","enterWith","requestContentType","logRequestBody","maxBodySize","clonedRequest","clone","requestBody","arrayBuffer","isEnabled","setConsumer","apitallyConsumer"]}
1
+ {"version":3,"sources":["../../src/h3/plugin.ts"],"sourcesContent":["import type { H3Event, HTTPError } from \"h3\";\nimport { definePlugin, onError, onRequest, onResponse } from \"h3\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\nimport type { ZodError } from \"zod\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { mergeHeaders, parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { 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 REQUEST_TIMESTAMP_SYMBOL = Symbol(\"apitally.requestTimestamp\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\n\ndeclare module \"h3\" {\n interface H3EventContext {\n apitallyConsumer?: ApitallyConsumer | string;\n\n [REQUEST_TIMESTAMP_SYMBOL]?: number;\n [REQUEST_BODY_SYMBOL]?: Buffer;\n }\n}\n\nconst jsonHeaders = new Headers({\n \"content-type\": \"application/json;charset=UTF-8\",\n});\n\nexport const apitallyPlugin = definePlugin<ApitallyConfig>((app, config) => {\n const client = new ApitallyClient(config);\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n const setStartupData = (attempt: number = 1) => {\n const appInfo = getAppInfo(app, config.appVersion);\n if (appInfo.paths.length > 0 || attempt >= 10) {\n client.setStartupData(appInfo);\n client.startSync();\n } else {\n setTimeout(() => setStartupData(attempt + 1), 500);\n }\n };\n setTimeout(() => setStartupData(), 500);\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n const handleResponse = async (\n event: H3Event,\n response?: Response,\n error?: HTTPError,\n ) => {\n if (event.req.method.toUpperCase() === \"OPTIONS\") {\n return response;\n }\n\n const startTime = event.context[REQUEST_TIMESTAMP_SYMBOL];\n const path = event.context.matchedRoute?.route;\n\n const consumer = getConsumer(event);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n if (!response) {\n response = new Response(null, {\n status: error?.status || 500,\n statusText: error?.statusText || \"Internal Server Error\",\n headers: error?.headers\n ? mergeHeaders(jsonHeaders, error.headers)\n : jsonHeaders,\n });\n }\n\n const [newResponse, responsePromise] = captureResponse(response, {\n captureBody:\n client.requestLogger.enabled &&\n client.requestLogger.config.logResponseBody,\n maxBodySize: client.requestLogger.maxBodySize,\n });\n\n responsePromise.then(async (capturedResponse) => {\n const responseTime = startTime ? performance.now() - startTime : 0;\n const responseSize = capturedResponse.completed\n ? capturedResponse.size\n : undefined;\n const requestSize = parseContentLength(\n event.req.headers.get(\"content-length\"),\n );\n\n if (path) {\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: event.req.method,\n path,\n statusCode: response.status,\n responseTime,\n requestSize,\n responseSize,\n });\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: event.req.method,\n path,\n url: event.req.url,\n headers: convertHeaders(\n Object.fromEntries(event.req.headers.entries()),\n ),\n size: requestSize,\n consumer: consumer?.identifier,\n body: event.context[REQUEST_BODY_SYMBOL],\n },\n {\n statusCode: response.status,\n responseTime: responseTime / 1000,\n headers: convertHeaders(\n Object.fromEntries(response.headers.entries()),\n ),\n size: responseSize,\n body: capturedResponse.body,\n },\n error?.cause instanceof Error ? error.cause : undefined,\n logs,\n );\n }\n });\n\n if (\n path &&\n error?.status === 400 &&\n error.data &&\n (error.data as any).name === \"ZodError\"\n ) {\n const zodError = error.data as ZodError;\n zodError.issues?.forEach((issue) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: event.req.method,\n path,\n loc: issue.path.join(\".\"),\n msg: issue.message,\n type: issue.code,\n });\n });\n }\n\n if (path && error?.status === 500 && error.cause instanceof Error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: event.req.method,\n path,\n type: error.cause.name,\n msg: error.cause.message,\n traceback: error.cause.stack || \"\",\n });\n }\n\n return newResponse;\n };\n\n app\n .use(\n onRequest(async (event) => {\n logsContext.enterWith([]);\n event.context[REQUEST_TIMESTAMP_SYMBOL] = performance.now();\n const requestContentType = event.req.headers.get(\"content-type\");\n const requestSize =\n parseContentLength(event.req.headers.get(\"content-length\")) ?? 0;\n\n if (\n client.requestLogger.enabled &&\n client.requestLogger.config.logRequestBody &&\n client.requestLogger.isSupportedContentType(requestContentType) &&\n requestSize <= client.requestLogger.maxBodySize\n ) {\n const clonedRequest = event.req.clone();\n const requestBody = Buffer.from(await clonedRequest.arrayBuffer());\n event.context[REQUEST_BODY_SYMBOL] = requestBody;\n }\n }),\n )\n .use(\n onResponse((response, event) => {\n if (client.isEnabled()) {\n return handleResponse(event, response, undefined);\n }\n }),\n )\n .use(\n onError((error, event) => {\n if (client.isEnabled()) {\n handleResponse(event, undefined, error);\n }\n }),\n );\n});\n\nexport function setConsumer(\n event: H3Event,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n event.context.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(event: H3Event) {\n const consumer = event.context.apitallyConsumer;\n if (consumer) {\n return consumerFromStringOrObject(consumer);\n }\n return null;\n}\n"],"mappings":"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","names":["definePlugin","onError","onRequest","onResponse","AsyncLocalStorage","performance","ApitallyClient","consumerFromStringOrObject","mergeHeaders","parseContentLength","convertHeaders","captureResponse","patchConsole","patchWinston","getAppInfo","REQUEST_TIMESTAMP_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","jsonHeaders","Headers","apitallyPlugin","app","config","client","logsContext","setStartupData","attempt","appInfo","appVersion","paths","length","startSync","setTimeout","requestLogger","captureLogs","handleResponse","event","response","error","req","method","toUpperCase","startTime","context","path","matchedRoute","route","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","Response","status","statusText","headers","newResponse","responsePromise","captureBody","enabled","logResponseBody","maxBodySize","then","capturedResponse","responseTime","now","responseSize","completed","size","undefined","requestSize","get","requestCounter","addRequest","identifier","statusCode","logs","getStore","logRequest","timestamp","Date","url","Object","fromEntries","entries","body","cause","Error","data","name","zodError","issues","forEach","issue","validationErrorCounter","addValidationError","loc","join","msg","message","type","code","serverErrorCounter","addServerError","traceback","stack","use","enterWith","requestContentType","logRequestBody","isSupportedContentType","clonedRequest","clone","requestBody","Buffer","from","arrayBuffer","isEnabled","setConsumer","apitallyConsumer"]}
package/dist/h3/utils.cjs CHANGED
@@ -58,7 +58,7 @@ function getAppInfo(h3, appVersion) {
58
58
  ]);
59
59
  }
60
60
  return {
61
- paths: h3._routes.map((route) => ({
61
+ paths: h3["~routes"].map((route) => ({
62
62
  method: route.method || "",
63
63
  path: route.route || ""
64
64
  })).filter((route) => route.method && route.path && ![
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/h3/utils.ts"],"sourcesContent":["import { H3Core } from \"h3\";\n\nimport { getPackageVersion } from \"../common/packageVersions.js\";\n\nexport function getAppInfo(h3: H3Core, appVersion?: string) {\n const versions: Array<[string, string]> = [];\n if (process.versions.node) {\n versions.push([\"nodejs\", process.versions.node]);\n }\n if (process.versions.bun) {\n versions.push([\"bun\", process.versions.bun]);\n }\n const h3Version = getPackageVersion(\"h3\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (h3Version) {\n versions.push([\"h3\", h3Version]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n\n return {\n paths: h3._routes\n .map((route) => ({\n method: route.method || \"\",\n path: route.route || \"\",\n }))\n .filter(\n (route) =>\n route.method &&\n route.path &&\n ![\"HEAD\", \"OPTIONS\"].includes(route.method.toUpperCase()),\n ),\n versions: Object.fromEntries(versions),\n client: \"js:h3\",\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAEA;;;;;AAAA,6BAAkC;AAE3B,SAASA,WAAWC,IAAYC,YAAmB;AACxD,QAAMC,WAAoC,CAAA;AAC1C,MAAIC,QAAQD,SAASE,MAAM;AACzBF,aAASG,KAAK;MAAC;MAAUF,QAAQD,SAASE;KAAK;EACjD;AACA,MAAID,QAAQD,SAASI,KAAK;AACxBJ,aAASG,KAAK;MAAC;MAAOF,QAAQD,SAASI;KAAI;EAC7C;AACA,QAAMC,gBAAYC,0CAAkB,IAAA;AACpC,QAAMC,sBAAkBD,0CAAkB,OAAA;AAC1C,MAAID,WAAW;AACbL,aAASG,KAAK;MAAC;MAAME;KAAU;EACjC;AACA,MAAIE,iBAAiB;AACnBP,aAASG,KAAK;MAAC;MAAYI;KAAgB;EAC7C;AACA,MAAIR,YAAY;AACdC,aAASG,KAAK;MAAC;MAAOJ;KAAW;EACnC;AAEA,SAAO;IACLS,OAAOV,GAAGW,QACPC,IAAI,CAACC,WAAW;MACfC,QAAQD,MAAMC,UAAU;MACxBC,MAAMF,MAAMA,SAAS;IACvB,EAAA,EACCG,OACC,CAACH,UACCA,MAAMC,UACND,MAAME,QACN,CAAC;MAAC;MAAQ;MAAWE,SAASJ,MAAMC,OAAOI,YAAW,CAAA,CAAA;IAE5DhB,UAAUiB,OAAOC,YAAYlB,QAAAA;IAC7BmB,QAAQ;EACV;AACF;AAnCgBtB;","names":["getAppInfo","h3","appVersion","versions","process","node","push","bun","h3Version","getPackageVersion","apitallyVersion","paths","_routes","map","route","method","path","filter","includes","toUpperCase","Object","fromEntries","client"]}
1
+ {"version":3,"sources":["../../src/h3/utils.ts"],"sourcesContent":["import { H3Core } from \"h3\";\n\nimport { getPackageVersion } from \"../common/packageVersions.js\";\n\nexport function getAppInfo(h3: H3Core, appVersion?: string) {\n const versions: Array<[string, string]> = [];\n if (process.versions.node) {\n versions.push([\"nodejs\", process.versions.node]);\n }\n if (process.versions.bun) {\n versions.push([\"bun\", process.versions.bun]);\n }\n const h3Version = getPackageVersion(\"h3\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (h3Version) {\n versions.push([\"h3\", h3Version]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n\n return {\n paths: h3[\"~routes\"]\n .map((route) => ({\n method: route.method || \"\",\n path: route.route || \"\",\n }))\n .filter(\n (route) =>\n route.method &&\n route.path &&\n ![\"HEAD\", \"OPTIONS\"].includes(route.method.toUpperCase()),\n ),\n versions: Object.fromEntries(versions),\n client: \"js:h3\",\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAEA;;;;;AAAA,6BAAkC;AAE3B,SAASA,WAAWC,IAAYC,YAAmB;AACxD,QAAMC,WAAoC,CAAA;AAC1C,MAAIC,QAAQD,SAASE,MAAM;AACzBF,aAASG,KAAK;MAAC;MAAUF,QAAQD,SAASE;KAAK;EACjD;AACA,MAAID,QAAQD,SAASI,KAAK;AACxBJ,aAASG,KAAK;MAAC;MAAOF,QAAQD,SAASI;KAAI;EAC7C;AACA,QAAMC,gBAAYC,0CAAkB,IAAA;AACpC,QAAMC,sBAAkBD,0CAAkB,OAAA;AAC1C,MAAID,WAAW;AACbL,aAASG,KAAK;MAAC;MAAME;KAAU;EACjC;AACA,MAAIE,iBAAiB;AACnBP,aAASG,KAAK;MAAC;MAAYI;KAAgB;EAC7C;AACA,MAAIR,YAAY;AACdC,aAASG,KAAK;MAAC;MAAOJ;KAAW;EACnC;AAEA,SAAO;IACLS,OAAOV,GAAG,SAAA,EACPW,IAAI,CAACC,WAAW;MACfC,QAAQD,MAAMC,UAAU;MACxBC,MAAMF,MAAMA,SAAS;IACvB,EAAA,EACCG,OACC,CAACH,UACCA,MAAMC,UACND,MAAME,QACN,CAAC;MAAC;MAAQ;MAAWE,SAASJ,MAAMC,OAAOI,YAAW,CAAA,CAAA;IAE5Df,UAAUgB,OAAOC,YAAYjB,QAAAA;IAC7BkB,QAAQ;EACV;AACF;AAnCgBrB;","names":["getAppInfo","h3","appVersion","versions","process","node","push","bun","h3Version","getPackageVersion","apitallyVersion","paths","map","route","method","path","filter","includes","toUpperCase","Object","fromEntries","client"]}
package/dist/h3/utils.js CHANGED
@@ -36,7 +36,7 @@ function getAppInfo(h3, appVersion) {
36
36
  ]);
37
37
  }
38
38
  return {
39
- paths: h3._routes.map((route) => ({
39
+ paths: h3["~routes"].map((route) => ({
40
40
  method: route.method || "",
41
41
  path: route.route || ""
42
42
  })).filter((route) => route.method && route.path && ![
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/h3/utils.ts"],"sourcesContent":["import { H3Core } from \"h3\";\n\nimport { getPackageVersion } from \"../common/packageVersions.js\";\n\nexport function getAppInfo(h3: H3Core, appVersion?: string) {\n const versions: Array<[string, string]> = [];\n if (process.versions.node) {\n versions.push([\"nodejs\", process.versions.node]);\n }\n if (process.versions.bun) {\n versions.push([\"bun\", process.versions.bun]);\n }\n const h3Version = getPackageVersion(\"h3\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (h3Version) {\n versions.push([\"h3\", h3Version]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n\n return {\n paths: h3._routes\n .map((route) => ({\n method: route.method || \"\",\n path: route.route || \"\",\n }))\n .filter(\n (route) =>\n route.method &&\n route.path &&\n ![\"HEAD\", \"OPTIONS\"].includes(route.method.toUpperCase()),\n ),\n versions: Object.fromEntries(versions),\n client: \"js:h3\",\n };\n}\n"],"mappings":";;AAEA,SAASA,yBAAyB;AAE3B,SAASC,WAAWC,IAAYC,YAAmB;AACxD,QAAMC,WAAoC,CAAA;AAC1C,MAAIC,QAAQD,SAASE,MAAM;AACzBF,aAASG,KAAK;MAAC;MAAUF,QAAQD,SAASE;KAAK;EACjD;AACA,MAAID,QAAQD,SAASI,KAAK;AACxBJ,aAASG,KAAK;MAAC;MAAOF,QAAQD,SAASI;KAAI;EAC7C;AACA,QAAMC,YAAYT,kBAAkB,IAAA;AACpC,QAAMU,kBAAkBV,kBAAkB,OAAA;AAC1C,MAAIS,WAAW;AACbL,aAASG,KAAK;MAAC;MAAME;KAAU;EACjC;AACA,MAAIC,iBAAiB;AACnBN,aAASG,KAAK;MAAC;MAAYG;KAAgB;EAC7C;AACA,MAAIP,YAAY;AACdC,aAASG,KAAK;MAAC;MAAOJ;KAAW;EACnC;AAEA,SAAO;IACLQ,OAAOT,GAAGU,QACPC,IAAI,CAACC,WAAW;MACfC,QAAQD,MAAMC,UAAU;MACxBC,MAAMF,MAAMA,SAAS;IACvB,EAAA,EACCG,OACC,CAACH,UACCA,MAAMC,UACND,MAAME,QACN,CAAC;MAAC;MAAQ;MAAWE,SAASJ,MAAMC,OAAOI,YAAW,CAAA,CAAA;IAE5Df,UAAUgB,OAAOC,YAAYjB,QAAAA;IAC7BkB,QAAQ;EACV;AACF;AAnCgBrB;","names":["getPackageVersion","getAppInfo","h3","appVersion","versions","process","node","push","bun","h3Version","apitallyVersion","paths","_routes","map","route","method","path","filter","includes","toUpperCase","Object","fromEntries","client"]}
1
+ {"version":3,"sources":["../../src/h3/utils.ts"],"sourcesContent":["import { H3Core } from \"h3\";\n\nimport { getPackageVersion } from \"../common/packageVersions.js\";\n\nexport function getAppInfo(h3: H3Core, appVersion?: string) {\n const versions: Array<[string, string]> = [];\n if (process.versions.node) {\n versions.push([\"nodejs\", process.versions.node]);\n }\n if (process.versions.bun) {\n versions.push([\"bun\", process.versions.bun]);\n }\n const h3Version = getPackageVersion(\"h3\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (h3Version) {\n versions.push([\"h3\", h3Version]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n\n return {\n paths: h3[\"~routes\"]\n .map((route) => ({\n method: route.method || \"\",\n path: route.route || \"\",\n }))\n .filter(\n (route) =>\n route.method &&\n route.path &&\n ![\"HEAD\", \"OPTIONS\"].includes(route.method.toUpperCase()),\n ),\n versions: Object.fromEntries(versions),\n client: \"js:h3\",\n };\n}\n"],"mappings":";;AAEA,SAASA,yBAAyB;AAE3B,SAASC,WAAWC,IAAYC,YAAmB;AACxD,QAAMC,WAAoC,CAAA;AAC1C,MAAIC,QAAQD,SAASE,MAAM;AACzBF,aAASG,KAAK;MAAC;MAAUF,QAAQD,SAASE;KAAK;EACjD;AACA,MAAID,QAAQD,SAASI,KAAK;AACxBJ,aAASG,KAAK;MAAC;MAAOF,QAAQD,SAASI;KAAI;EAC7C;AACA,QAAMC,YAAYT,kBAAkB,IAAA;AACpC,QAAMU,kBAAkBV,kBAAkB,OAAA;AAC1C,MAAIS,WAAW;AACbL,aAASG,KAAK;MAAC;MAAME;KAAU;EACjC;AACA,MAAIC,iBAAiB;AACnBN,aAASG,KAAK;MAAC;MAAYG;KAAgB;EAC7C;AACA,MAAIP,YAAY;AACdC,aAASG,KAAK;MAAC;MAAOJ;KAAW;EACnC;AAEA,SAAO;IACLQ,OAAOT,GAAG,SAAA,EACPU,IAAI,CAACC,WAAW;MACfC,QAAQD,MAAMC,UAAU;MACxBC,MAAMF,MAAMA,SAAS;IACvB,EAAA,EACCG,OACC,CAACH,UACCA,MAAMC,UACND,MAAME,QACN,CAAC;MAAC;MAAQ;MAAWE,SAASJ,MAAMC,OAAOI,YAAW,CAAA,CAAA;IAE5Dd,UAAUe,OAAOC,YAAYhB,QAAAA;IAC7BiB,QAAQ;EACV;AACF;AAnCgBpB;","names":["getPackageVersion","getAppInfo","h3","appVersion","versions","process","node","push","bun","h3Version","apitallyVersion","paths","map","route","method","path","filter","includes","toUpperCase","Object","fromEntries","client"]}
@@ -63,77 +63,76 @@ function getMiddleware(client) {
63
63
  const timestamp = Date.now() / 1e3;
64
64
  const startTime = import_node_perf_hooks.performance.now();
65
65
  await next();
66
- let response;
67
- const responseTime = import_node_perf_hooks.performance.now() - startTime;
68
- const [responseSize, newResponse] = await (0, import_response.measureResponseSize)(c.res);
69
- const requestSize = (0, import_headers.parseContentLength)(c.req.header("content-length"));
70
- const consumer = getConsumer(c);
71
- client.consumerRegistry.addOrUpdateConsumer(consumer);
72
- client.requestCounter.addRequest({
73
- consumer: consumer == null ? void 0 : consumer.identifier,
74
- method: c.req.method,
75
- path: c.req.routePath,
76
- statusCode: c.res.status,
77
- responseTime,
78
- requestSize,
79
- responseSize
66
+ const [newResponse, responsePromise] = (0, import_response.captureResponse)(c.res, {
67
+ captureBody: client.requestLogger.enabled && client.requestLogger.config.logResponseBody && client.requestLogger.isSupportedContentType(c.res.headers.get("content-type")) || c.res.status === 400 && c.res.headers.get("content-type") === "application/json",
68
+ maxBodySize: client.requestLogger.maxBodySize
80
69
  });
81
- response = newResponse;
82
- if (c.res.status === 400) {
83
- const [responseJson, newResponse2] = await (0, import_response.getResponseJson)(response);
84
- const validationErrors = (0, import_utils.extractZodErrors)(responseJson);
85
- validationErrors.forEach((error) => {
86
- client.validationErrorCounter.addValidationError({
87
- consumer: consumer == null ? void 0 : consumer.identifier,
88
- method: c.req.method,
89
- path: c.req.routePath,
90
- ...error
91
- });
92
- });
93
- response = newResponse2;
94
- }
95
- if (c.error) {
96
- client.serverErrorCounter.addServerError({
70
+ c.res = newResponse;
71
+ const statusCode = c.res.status;
72
+ const responseHeaders = c.res.headers;
73
+ responsePromise.then(async (capturedResponse) => {
74
+ const responseTime = import_node_perf_hooks.performance.now() - startTime;
75
+ const requestSize = (0, import_headers.parseContentLength)(c.req.header("content-length"));
76
+ const responseSize = capturedResponse.completed ? capturedResponse.size : void 0;
77
+ const consumer = getConsumer(c);
78
+ client.consumerRegistry.addOrUpdateConsumer(consumer);
79
+ client.requestCounter.addRequest({
97
80
  consumer: consumer == null ? void 0 : consumer.identifier,
98
81
  method: c.req.method,
99
82
  path: c.req.routePath,
100
- type: c.error.name,
101
- msg: c.error.message,
102
- traceback: c.error.stack || ""
83
+ statusCode,
84
+ responseTime,
85
+ requestSize,
86
+ responseSize
103
87
  });
104
- }
105
- if (client.requestLogger.enabled) {
106
- let requestBody;
107
- let responseBody;
108
- let newResponse2 = response;
109
- const requestContentType = c.req.header("content-type");
110
- const responseContentType = c.res.headers.get("content-type");
111
- if (client.requestLogger.config.logRequestBody && client.requestLogger.isSupportedContentType(requestContentType)) {
112
- requestBody = Buffer.from(await c.req.arrayBuffer());
88
+ if (statusCode === 400 && capturedResponse.body) {
89
+ const responseJson = (0, import_response.getResponseJson)(capturedResponse.body);
90
+ const validationErrors = (0, import_utils.extractZodErrors)(responseJson);
91
+ validationErrors.forEach((error) => {
92
+ client.validationErrorCounter.addValidationError({
93
+ consumer: consumer == null ? void 0 : consumer.identifier,
94
+ method: c.req.method,
95
+ path: c.req.routePath,
96
+ ...error
97
+ });
98
+ });
99
+ }
100
+ if (c.error) {
101
+ client.serverErrorCounter.addServerError({
102
+ consumer: consumer == null ? void 0 : consumer.identifier,
103
+ method: c.req.method,
104
+ path: c.req.routePath,
105
+ type: c.error.name,
106
+ msg: c.error.message,
107
+ traceback: c.error.stack || ""
108
+ });
113
109
  }
114
- if (client.requestLogger.config.logResponseBody && client.requestLogger.isSupportedContentType(responseContentType)) {
115
- [responseBody, newResponse2] = await (0, import_response.getResponseBody)(response);
116
- response = newResponse2;
110
+ if (client.requestLogger.enabled) {
111
+ let requestBody;
112
+ const responseBody = capturedResponse.body;
113
+ const requestContentType = c.req.header("content-type");
114
+ if (client.requestLogger.config.logRequestBody && client.requestLogger.isSupportedContentType(requestContentType)) {
115
+ requestBody = Buffer.from(await c.req.arrayBuffer());
116
+ }
117
+ const logs = logsContext.getStore();
118
+ client.requestLogger.logRequest({
119
+ timestamp,
120
+ method: c.req.method,
121
+ path: c.req.routePath,
122
+ url: c.req.url,
123
+ headers: (0, import_requestLogger.convertHeaders)(c.req.header()),
124
+ size: requestSize,
125
+ consumer: consumer == null ? void 0 : consumer.identifier,
126
+ body: requestBody
127
+ }, {
128
+ statusCode,
129
+ responseTime: responseTime / 1e3,
130
+ headers: (0, import_requestLogger.convertHeaders)(responseHeaders),
131
+ size: responseSize,
132
+ body: responseBody
133
+ }, c.error, logs);
117
134
  }
118
- const logs = logsContext.getStore();
119
- client.requestLogger.logRequest({
120
- timestamp,
121
- method: c.req.method,
122
- path: c.req.routePath,
123
- url: c.req.url,
124
- headers: (0, import_requestLogger.convertHeaders)(c.req.header()),
125
- size: requestSize,
126
- consumer: consumer == null ? void 0 : consumer.identifier,
127
- body: requestBody
128
- }, {
129
- statusCode: c.res.status,
130
- responseTime: responseTime / 1e3,
131
- headers: (0, import_requestLogger.convertHeaders)(c.res.headers),
132
- size: responseSize,
133
- body: responseBody
134
- }, c.error, logs);
135
- }
136
- c.res = response;
135
+ });
137
136
  });
138
137
  };
139
138
  }