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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hono/middleware.ts"],"sourcesContent":["import { Context, Hono } from \"hono\";\nimport { MiddlewareHandler } from \"hono/types\";\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 {\n getResponseBody,\n getResponseJson,\n measureResponseSize,\n} from \"../common/response.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { extractZodErrors, getAppInfo } from \"./utils.js\";\n\ndeclare module \"hono\" {\n interface ContextVariableMap {\n apitallyConsumer?: ApitallyConsumer | string;\n }\n}\n\nexport function useApitally(app: Hono, config: ApitallyConfig) {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(client);\n app.use(middleware);\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\nfunction getMiddleware(client: ApitallyClient): MiddlewareHandler {\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n return async (c, next) => {\n if (!client.isEnabled() || c.req.method.toUpperCase() === \"OPTIONS\") {\n await next();\n return;\n }\n\n await logsContext.run([], async () => {\n const timestamp = Date.now() / 1000;\n const startTime = performance.now();\n\n await next();\n\n let response;\n const responseTime = performance.now() - startTime;\n const [responseSize, newResponse] = await measureResponseSize(c.res);\n const requestSize = parseContentLength(c.req.header(\"content-length\"));\n\n const consumer = getConsumer(c);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: c.req.method,\n path: c.req.routePath,\n statusCode: c.res.status,\n responseTime,\n requestSize,\n responseSize,\n });\n\n response = newResponse;\n\n if (c.res.status === 400) {\n const [responseJson, newResponse] = await getResponseJson(response);\n const validationErrors = extractZodErrors(responseJson);\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: c.req.method,\n path: c.req.routePath,\n ...error,\n });\n });\n response = newResponse;\n }\n\n if (c.error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: c.req.method,\n path: c.req.routePath,\n type: c.error.name,\n msg: c.error.message,\n traceback: c.error.stack || \"\",\n });\n }\n\n if (client.requestLogger.enabled) {\n let requestBody;\n let responseBody;\n let newResponse = response;\n const requestContentType = c.req.header(\"content-type\");\n const responseContentType = c.res.headers.get(\"content-type\");\n if (\n client.requestLogger.config.logRequestBody &&\n client.requestLogger.isSupportedContentType(requestContentType)\n ) {\n requestBody = Buffer.from(await c.req.arrayBuffer());\n }\n if (\n client.requestLogger.config.logResponseBody &&\n client.requestLogger.isSupportedContentType(responseContentType)\n ) {\n [responseBody, newResponse] = await getResponseBody(response);\n response = newResponse;\n }\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp,\n method: c.req.method,\n path: c.req.routePath,\n url: c.req.url,\n headers: convertHeaders(c.req.header()),\n size: requestSize,\n consumer: consumer?.identifier,\n body: requestBody,\n },\n {\n statusCode: c.res.status,\n responseTime: responseTime / 1000,\n headers: convertHeaders(c.res.headers),\n size: responseSize,\n body: responseBody,\n },\n c.error,\n logs,\n );\n }\n c.res = response;\n });\n };\n}\n\nexport function setConsumer(\n c: Context,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n c.set(\"apitallyConsumer\", consumer || undefined);\n}\n\nfunction getConsumer(c: Context) {\n const consumer = c.get(\"apitallyConsumer\");\n if (consumer) {\n return consumerFromStringOrObject(consumer);\n }\n return null;\n}\n"],"mappings":"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","names":["useApitally","app","config","client","ApitallyClient","middleware","getMiddleware","use","setStartupData","attempt","appInfo","getAppInfo","appVersion","paths","length","startSync","setTimeout","logsContext","AsyncLocalStorage","requestLogger","captureLogs","patchConsole","patchWinston","c","next","isEnabled","req","method","toUpperCase","run","timestamp","Date","now","startTime","performance","response","responseTime","responseSize","newResponse","measureResponseSize","res","requestSize","parseContentLength","header","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","path","routePath","statusCode","status","responseJson","getResponseJson","validationErrors","extractZodErrors","forEach","error","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","enabled","requestBody","responseBody","requestContentType","responseContentType","headers","get","logRequestBody","isSupportedContentType","Buffer","from","arrayBuffer","logResponseBody","getResponseBody","logs","getStore","logRequest","url","convertHeaders","size","body","setConsumer","set","undefined","consumerFromStringOrObject"]}
1
+ {"version":3,"sources":["../../src/hono/middleware.ts"],"sourcesContent":["import { Context, Hono } from \"hono\";\nimport { MiddlewareHandler } from \"hono/types\";\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 { captureResponse, getResponseJson } from \"../common/response.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { extractZodErrors, getAppInfo } from \"./utils.js\";\n\ndeclare module \"hono\" {\n interface ContextVariableMap {\n apitallyConsumer?: ApitallyConsumer | string;\n }\n}\n\nexport function useApitally(app: Hono, config: ApitallyConfig) {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(client);\n app.use(middleware);\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\nfunction getMiddleware(client: ApitallyClient): MiddlewareHandler {\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n return async (c, next) => {\n if (!client.isEnabled() || c.req.method.toUpperCase() === \"OPTIONS\") {\n await next();\n return;\n }\n\n await logsContext.run([], async () => {\n const timestamp = Date.now() / 1000;\n const startTime = performance.now();\n\n await next();\n\n const [newResponse, responsePromise] = captureResponse(c.res, {\n captureBody:\n (client.requestLogger.enabled &&\n client.requestLogger.config.logResponseBody &&\n client.requestLogger.isSupportedContentType(\n c.res.headers.get(\"content-type\"),\n )) ||\n (c.res.status === 400 &&\n c.res.headers.get(\"content-type\") === \"application/json\"),\n maxBodySize: client.requestLogger.maxBodySize,\n });\n c.res = newResponse;\n\n const statusCode = c.res.status;\n const responseHeaders = c.res.headers;\n\n responsePromise.then(async (capturedResponse) => {\n const responseTime = performance.now() - startTime;\n const requestSize = parseContentLength(c.req.header(\"content-length\"));\n const responseSize = capturedResponse.completed\n ? capturedResponse.size\n : undefined;\n\n const consumer = getConsumer(c);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: c.req.method,\n path: c.req.routePath,\n statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (statusCode === 400 && capturedResponse.body) {\n const responseJson = getResponseJson(capturedResponse.body);\n const validationErrors = extractZodErrors(responseJson);\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: c.req.method,\n path: c.req.routePath,\n ...error,\n });\n });\n }\n\n if (c.error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: c.req.method,\n path: c.req.routePath,\n type: c.error.name,\n msg: c.error.message,\n traceback: c.error.stack || \"\",\n });\n }\n\n if (client.requestLogger.enabled) {\n let requestBody;\n const responseBody = capturedResponse.body;\n const requestContentType = c.req.header(\"content-type\");\n if (\n client.requestLogger.config.logRequestBody &&\n client.requestLogger.isSupportedContentType(requestContentType)\n ) {\n requestBody = Buffer.from(await c.req.arrayBuffer());\n }\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp,\n method: c.req.method,\n path: c.req.routePath,\n url: c.req.url,\n headers: convertHeaders(c.req.header()),\n size: requestSize,\n consumer: consumer?.identifier,\n body: requestBody,\n },\n {\n statusCode: statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(responseHeaders),\n size: responseSize,\n body: responseBody,\n },\n c.error,\n logs,\n );\n }\n });\n });\n };\n}\n\nexport function setConsumer(\n c: Context,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n c.set(\"apitallyConsumer\", consumer || undefined);\n}\n\nfunction getConsumer(c: Context) {\n const consumer = c.get(\"apitallyConsumer\");\n if (consumer) {\n return consumerFromStringOrObject(consumer);\n }\n return null;\n}\n"],"mappings":"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","names":["useApitally","app","config","client","ApitallyClient","middleware","getMiddleware","use","setStartupData","attempt","appInfo","getAppInfo","appVersion","paths","length","startSync","setTimeout","logsContext","AsyncLocalStorage","requestLogger","captureLogs","patchConsole","patchWinston","c","next","isEnabled","req","method","toUpperCase","run","timestamp","Date","now","startTime","performance","newResponse","responsePromise","captureResponse","res","captureBody","enabled","logResponseBody","isSupportedContentType","headers","get","status","maxBodySize","statusCode","responseHeaders","then","capturedResponse","responseTime","requestSize","parseContentLength","header","responseSize","completed","size","undefined","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","path","routePath","body","responseJson","getResponseJson","validationErrors","extractZodErrors","forEach","error","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","requestBody","responseBody","requestContentType","logRequestBody","Buffer","from","arrayBuffer","logs","getStore","logRequest","url","convertHeaders","setConsumer","set","consumerFromStringOrObject"]}
@@ -6,7 +6,7 @@ import { ApitallyClient } from "../common/client.js";
6
6
  import { consumerFromStringOrObject } from "../common/consumerRegistry.js";
7
7
  import { parseContentLength } from "../common/headers.js";
8
8
  import { convertHeaders } from "../common/requestLogger.js";
9
- import { getResponseBody, getResponseJson, measureResponseSize } from "../common/response.js";
9
+ import { captureResponse, getResponseJson } from "../common/response.js";
10
10
  import { patchConsole, patchWinston } from "../loggers/index.js";
11
11
  import { extractZodErrors, getAppInfo } from "./utils.js";
12
12
  function useApitally(app, config) {
@@ -40,77 +40,76 @@ function getMiddleware(client) {
40
40
  const timestamp = Date.now() / 1e3;
41
41
  const startTime = performance.now();
42
42
  await next();
43
- let response;
44
- const responseTime = performance.now() - startTime;
45
- const [responseSize, newResponse] = await measureResponseSize(c.res);
46
- const requestSize = parseContentLength(c.req.header("content-length"));
47
- const consumer = getConsumer(c);
48
- client.consumerRegistry.addOrUpdateConsumer(consumer);
49
- client.requestCounter.addRequest({
50
- consumer: consumer == null ? void 0 : consumer.identifier,
51
- method: c.req.method,
52
- path: c.req.routePath,
53
- statusCode: c.res.status,
54
- responseTime,
55
- requestSize,
56
- responseSize
43
+ const [newResponse, responsePromise] = captureResponse(c.res, {
44
+ 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",
45
+ maxBodySize: client.requestLogger.maxBodySize
57
46
  });
58
- response = newResponse;
59
- if (c.res.status === 400) {
60
- const [responseJson, newResponse2] = await getResponseJson(response);
61
- const validationErrors = extractZodErrors(responseJson);
62
- validationErrors.forEach((error) => {
63
- client.validationErrorCounter.addValidationError({
64
- consumer: consumer == null ? void 0 : consumer.identifier,
65
- method: c.req.method,
66
- path: c.req.routePath,
67
- ...error
68
- });
69
- });
70
- response = newResponse2;
71
- }
72
- if (c.error) {
73
- client.serverErrorCounter.addServerError({
47
+ c.res = newResponse;
48
+ const statusCode = c.res.status;
49
+ const responseHeaders = c.res.headers;
50
+ responsePromise.then(async (capturedResponse) => {
51
+ const responseTime = performance.now() - startTime;
52
+ const requestSize = parseContentLength(c.req.header("content-length"));
53
+ const responseSize = capturedResponse.completed ? capturedResponse.size : void 0;
54
+ const consumer = getConsumer(c);
55
+ client.consumerRegistry.addOrUpdateConsumer(consumer);
56
+ client.requestCounter.addRequest({
74
57
  consumer: consumer == null ? void 0 : consumer.identifier,
75
58
  method: c.req.method,
76
59
  path: c.req.routePath,
77
- type: c.error.name,
78
- msg: c.error.message,
79
- traceback: c.error.stack || ""
60
+ statusCode,
61
+ responseTime,
62
+ requestSize,
63
+ responseSize
80
64
  });
81
- }
82
- if (client.requestLogger.enabled) {
83
- let requestBody;
84
- let responseBody;
85
- let newResponse2 = response;
86
- const requestContentType = c.req.header("content-type");
87
- const responseContentType = c.res.headers.get("content-type");
88
- if (client.requestLogger.config.logRequestBody && client.requestLogger.isSupportedContentType(requestContentType)) {
89
- requestBody = Buffer.from(await c.req.arrayBuffer());
65
+ if (statusCode === 400 && capturedResponse.body) {
66
+ const responseJson = getResponseJson(capturedResponse.body);
67
+ const validationErrors = extractZodErrors(responseJson);
68
+ validationErrors.forEach((error) => {
69
+ client.validationErrorCounter.addValidationError({
70
+ consumer: consumer == null ? void 0 : consumer.identifier,
71
+ method: c.req.method,
72
+ path: c.req.routePath,
73
+ ...error
74
+ });
75
+ });
76
+ }
77
+ if (c.error) {
78
+ client.serverErrorCounter.addServerError({
79
+ consumer: consumer == null ? void 0 : consumer.identifier,
80
+ method: c.req.method,
81
+ path: c.req.routePath,
82
+ type: c.error.name,
83
+ msg: c.error.message,
84
+ traceback: c.error.stack || ""
85
+ });
90
86
  }
91
- if (client.requestLogger.config.logResponseBody && client.requestLogger.isSupportedContentType(responseContentType)) {
92
- [responseBody, newResponse2] = await getResponseBody(response);
93
- response = newResponse2;
87
+ if (client.requestLogger.enabled) {
88
+ let requestBody;
89
+ const responseBody = capturedResponse.body;
90
+ const requestContentType = c.req.header("content-type");
91
+ if (client.requestLogger.config.logRequestBody && client.requestLogger.isSupportedContentType(requestContentType)) {
92
+ requestBody = Buffer.from(await c.req.arrayBuffer());
93
+ }
94
+ const logs = logsContext.getStore();
95
+ client.requestLogger.logRequest({
96
+ timestamp,
97
+ method: c.req.method,
98
+ path: c.req.routePath,
99
+ url: c.req.url,
100
+ headers: convertHeaders(c.req.header()),
101
+ size: requestSize,
102
+ consumer: consumer == null ? void 0 : consumer.identifier,
103
+ body: requestBody
104
+ }, {
105
+ statusCode,
106
+ responseTime: responseTime / 1e3,
107
+ headers: convertHeaders(responseHeaders),
108
+ size: responseSize,
109
+ body: responseBody
110
+ }, c.error, logs);
94
111
  }
95
- const logs = logsContext.getStore();
96
- client.requestLogger.logRequest({
97
- timestamp,
98
- method: c.req.method,
99
- path: c.req.routePath,
100
- url: c.req.url,
101
- headers: convertHeaders(c.req.header()),
102
- size: requestSize,
103
- consumer: consumer == null ? void 0 : consumer.identifier,
104
- body: requestBody
105
- }, {
106
- statusCode: c.res.status,
107
- responseTime: responseTime / 1e3,
108
- headers: convertHeaders(c.res.headers),
109
- size: responseSize,
110
- body: responseBody
111
- }, c.error, logs);
112
- }
113
- c.res = response;
112
+ });
114
113
  });
115
114
  };
116
115
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hono/middleware.ts"],"sourcesContent":["import { Context, Hono } from \"hono\";\nimport { MiddlewareHandler } from \"hono/types\";\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 {\n getResponseBody,\n getResponseJson,\n measureResponseSize,\n} from \"../common/response.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { extractZodErrors, getAppInfo } from \"./utils.js\";\n\ndeclare module \"hono\" {\n interface ContextVariableMap {\n apitallyConsumer?: ApitallyConsumer | string;\n }\n}\n\nexport function useApitally(app: Hono, config: ApitallyConfig) {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(client);\n app.use(middleware);\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\nfunction getMiddleware(client: ApitallyClient): MiddlewareHandler {\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n return async (c, next) => {\n if (!client.isEnabled() || c.req.method.toUpperCase() === \"OPTIONS\") {\n await next();\n return;\n }\n\n await logsContext.run([], async () => {\n const timestamp = Date.now() / 1000;\n const startTime = performance.now();\n\n await next();\n\n let response;\n const responseTime = performance.now() - startTime;\n const [responseSize, newResponse] = await measureResponseSize(c.res);\n const requestSize = parseContentLength(c.req.header(\"content-length\"));\n\n const consumer = getConsumer(c);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: c.req.method,\n path: c.req.routePath,\n statusCode: c.res.status,\n responseTime,\n requestSize,\n responseSize,\n });\n\n response = newResponse;\n\n if (c.res.status === 400) {\n const [responseJson, newResponse] = await getResponseJson(response);\n const validationErrors = extractZodErrors(responseJson);\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: c.req.method,\n path: c.req.routePath,\n ...error,\n });\n });\n response = newResponse;\n }\n\n if (c.error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: c.req.method,\n path: c.req.routePath,\n type: c.error.name,\n msg: c.error.message,\n traceback: c.error.stack || \"\",\n });\n }\n\n if (client.requestLogger.enabled) {\n let requestBody;\n let responseBody;\n let newResponse = response;\n const requestContentType = c.req.header(\"content-type\");\n const responseContentType = c.res.headers.get(\"content-type\");\n if (\n client.requestLogger.config.logRequestBody &&\n client.requestLogger.isSupportedContentType(requestContentType)\n ) {\n requestBody = Buffer.from(await c.req.arrayBuffer());\n }\n if (\n client.requestLogger.config.logResponseBody &&\n client.requestLogger.isSupportedContentType(responseContentType)\n ) {\n [responseBody, newResponse] = await getResponseBody(response);\n response = newResponse;\n }\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp,\n method: c.req.method,\n path: c.req.routePath,\n url: c.req.url,\n headers: convertHeaders(c.req.header()),\n size: requestSize,\n consumer: consumer?.identifier,\n body: requestBody,\n },\n {\n statusCode: c.res.status,\n responseTime: responseTime / 1000,\n headers: convertHeaders(c.res.headers),\n size: responseSize,\n body: responseBody,\n },\n c.error,\n logs,\n );\n }\n c.res = response;\n });\n };\n}\n\nexport function setConsumer(\n c: Context,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n c.set(\"apitallyConsumer\", consumer || undefined);\n}\n\nfunction getConsumer(c: Context) {\n const consumer = c.get(\"apitallyConsumer\");\n if (consumer) {\n return consumerFromStringOrObject(consumer);\n }\n return null;\n}\n"],"mappings":"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","names":["AsyncLocalStorage","performance","ApitallyClient","consumerFromStringOrObject","parseContentLength","convertHeaders","getResponseBody","getResponseJson","measureResponseSize","patchConsole","patchWinston","extractZodErrors","getAppInfo","useApitally","app","config","client","middleware","getMiddleware","use","setStartupData","attempt","appInfo","appVersion","paths","length","startSync","setTimeout","logsContext","requestLogger","captureLogs","c","next","isEnabled","req","method","toUpperCase","run","timestamp","Date","now","startTime","response","responseTime","responseSize","newResponse","res","requestSize","header","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","path","routePath","statusCode","status","responseJson","validationErrors","forEach","error","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","enabled","requestBody","responseBody","requestContentType","responseContentType","headers","get","logRequestBody","isSupportedContentType","Buffer","from","arrayBuffer","logResponseBody","logs","getStore","logRequest","url","size","body","setConsumer","set","undefined"]}
1
+ {"version":3,"sources":["../../src/hono/middleware.ts"],"sourcesContent":["import { Context, Hono } from \"hono\";\nimport { MiddlewareHandler } from \"hono/types\";\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 { captureResponse, getResponseJson } from \"../common/response.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { extractZodErrors, getAppInfo } from \"./utils.js\";\n\ndeclare module \"hono\" {\n interface ContextVariableMap {\n apitallyConsumer?: ApitallyConsumer | string;\n }\n}\n\nexport function useApitally(app: Hono, config: ApitallyConfig) {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(client);\n app.use(middleware);\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\nfunction getMiddleware(client: ApitallyClient): MiddlewareHandler {\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n return async (c, next) => {\n if (!client.isEnabled() || c.req.method.toUpperCase() === \"OPTIONS\") {\n await next();\n return;\n }\n\n await logsContext.run([], async () => {\n const timestamp = Date.now() / 1000;\n const startTime = performance.now();\n\n await next();\n\n const [newResponse, responsePromise] = captureResponse(c.res, {\n captureBody:\n (client.requestLogger.enabled &&\n client.requestLogger.config.logResponseBody &&\n client.requestLogger.isSupportedContentType(\n c.res.headers.get(\"content-type\"),\n )) ||\n (c.res.status === 400 &&\n c.res.headers.get(\"content-type\") === \"application/json\"),\n maxBodySize: client.requestLogger.maxBodySize,\n });\n c.res = newResponse;\n\n const statusCode = c.res.status;\n const responseHeaders = c.res.headers;\n\n responsePromise.then(async (capturedResponse) => {\n const responseTime = performance.now() - startTime;\n const requestSize = parseContentLength(c.req.header(\"content-length\"));\n const responseSize = capturedResponse.completed\n ? capturedResponse.size\n : undefined;\n\n const consumer = getConsumer(c);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: c.req.method,\n path: c.req.routePath,\n statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (statusCode === 400 && capturedResponse.body) {\n const responseJson = getResponseJson(capturedResponse.body);\n const validationErrors = extractZodErrors(responseJson);\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: c.req.method,\n path: c.req.routePath,\n ...error,\n });\n });\n }\n\n if (c.error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: c.req.method,\n path: c.req.routePath,\n type: c.error.name,\n msg: c.error.message,\n traceback: c.error.stack || \"\",\n });\n }\n\n if (client.requestLogger.enabled) {\n let requestBody;\n const responseBody = capturedResponse.body;\n const requestContentType = c.req.header(\"content-type\");\n if (\n client.requestLogger.config.logRequestBody &&\n client.requestLogger.isSupportedContentType(requestContentType)\n ) {\n requestBody = Buffer.from(await c.req.arrayBuffer());\n }\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp,\n method: c.req.method,\n path: c.req.routePath,\n url: c.req.url,\n headers: convertHeaders(c.req.header()),\n size: requestSize,\n consumer: consumer?.identifier,\n body: requestBody,\n },\n {\n statusCode: statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(responseHeaders),\n size: responseSize,\n body: responseBody,\n },\n c.error,\n logs,\n );\n }\n });\n });\n };\n}\n\nexport function setConsumer(\n c: Context,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n c.set(\"apitallyConsumer\", consumer || undefined);\n}\n\nfunction getConsumer(c: Context) {\n const consumer = c.get(\"apitallyConsumer\");\n if (consumer) {\n return consumerFromStringOrObject(consumer);\n }\n return null;\n}\n"],"mappings":"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","names":["AsyncLocalStorage","performance","ApitallyClient","consumerFromStringOrObject","parseContentLength","convertHeaders","captureResponse","getResponseJson","patchConsole","patchWinston","extractZodErrors","getAppInfo","useApitally","app","config","client","middleware","getMiddleware","use","setStartupData","attempt","appInfo","appVersion","paths","length","startSync","setTimeout","logsContext","requestLogger","captureLogs","c","next","isEnabled","req","method","toUpperCase","run","timestamp","Date","now","startTime","newResponse","responsePromise","res","captureBody","enabled","logResponseBody","isSupportedContentType","headers","get","status","maxBodySize","statusCode","responseHeaders","then","capturedResponse","responseTime","requestSize","header","responseSize","completed","size","undefined","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","path","routePath","body","responseJson","validationErrors","forEach","error","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","requestBody","responseBody","requestContentType","logRequestBody","Buffer","from","arrayBuffer","logs","getStore","logRequest","url","setConsumer","set"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apitally",
3
- "version": "0.21.4",
3
+ "version": "0.22.0",
4
4
  "description": "Simple API monitoring & analytics for REST APIs built with Express, Fastify, NestJS, AdonisJS, Hono, H3, Elysia, Hapi, and Koa.",
5
5
  "author": "Apitally <hello@apitally.io>",
6
6
  "license": "MIT",
@@ -302,7 +302,7 @@
302
302
  "fastify": "^5.0.0",
303
303
  "fastify-plugin": "^5.0.1",
304
304
  "globals": "^16.2.0",
305
- "h3": "2.0.0-rc.1",
305
+ "h3": "2.0.1-rc.5",
306
306
  "hono": "^4.6.5",
307
307
  "koa": "^3.0.0",
308
308
  "koa-bodyparser": "^4.4.1",