apitally 0.14.0 → 0.15.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.
- package/README.md +24 -1
- package/dist/adonisjs/index.cjs +6 -4
- package/dist/adonisjs/index.cjs.map +1 -1
- package/dist/adonisjs/index.d.cts +2 -2
- package/dist/adonisjs/index.d.ts +2 -2
- package/dist/adonisjs/index.js +6 -4
- package/dist/adonisjs/index.js.map +1 -1
- package/dist/adonisjs/middleware.cjs +19 -19
- package/dist/adonisjs/middleware.cjs.map +1 -1
- package/dist/adonisjs/middleware.js +19 -19
- package/dist/adonisjs/middleware.js.map +1 -1
- package/dist/adonisjs/provider.cjs +11 -4
- package/dist/adonisjs/provider.cjs.map +1 -1
- package/dist/adonisjs/provider.js +11 -4
- package/dist/adonisjs/provider.js.map +1 -1
- package/dist/common/client.cjs +5 -0
- package/dist/common/client.cjs.map +1 -1
- package/dist/common/client.js +5 -0
- package/dist/common/client.js.map +1 -1
- package/dist/common/{utils.cjs → headers.cjs} +14 -5
- package/dist/common/headers.cjs.map +1 -0
- package/dist/common/{utils.d.cts → headers.d.cts} +2 -1
- package/dist/common/{utils.d.ts → headers.d.ts} +2 -1
- package/dist/common/{utils.js → headers.js} +10 -2
- package/dist/common/headers.js.map +1 -0
- package/dist/common/requestLogger.cjs +5 -0
- package/dist/common/requestLogger.cjs.map +1 -1
- package/dist/common/requestLogger.d.cts +1 -0
- package/dist/common/requestLogger.d.ts +1 -0
- package/dist/common/requestLogger.js +5 -0
- package/dist/common/requestLogger.js.map +1 -1
- package/dist/common/response.cjs +106 -0
- package/dist/common/response.cjs.map +1 -0
- package/dist/common/response.d.cts +6 -0
- package/dist/common/response.d.ts +6 -0
- package/dist/common/response.js +80 -0
- package/dist/common/response.js.map +1 -0
- package/dist/express/index.cjs +69 -42
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.d.cts +2 -2
- package/dist/express/index.d.ts +2 -2
- package/dist/express/index.js +67 -41
- package/dist/express/index.js.map +1 -1
- package/dist/express/middleware.cjs +69 -42
- package/dist/express/middleware.cjs.map +1 -1
- package/dist/express/middleware.d.cts +5 -4
- package/dist/express/middleware.d.ts +5 -4
- package/dist/express/middleware.js +67 -41
- package/dist/express/middleware.js.map +1 -1
- package/dist/fastify/index.cjs +44 -29
- package/dist/fastify/index.cjs.map +1 -1
- package/dist/fastify/index.d.cts +2 -2
- package/dist/fastify/index.d.ts +2 -2
- package/dist/fastify/index.js +41 -27
- package/dist/fastify/index.js.map +1 -1
- package/dist/fastify/plugin.cjs +46 -28
- package/dist/fastify/plugin.cjs.map +1 -1
- package/dist/fastify/plugin.d.cts +3 -2
- package/dist/fastify/plugin.d.ts +3 -2
- package/dist/fastify/plugin.js +41 -27
- package/dist/fastify/plugin.js.map +1 -1
- package/dist/h3/index.cjs +1336 -0
- package/dist/h3/index.cjs.map +1 -0
- package/dist/h3/index.d.cts +9 -0
- package/dist/h3/index.d.ts +9 -0
- package/dist/h3/index.js +1305 -0
- package/dist/h3/index.js.map +1 -0
- package/dist/h3/plugin.cjs +1334 -0
- package/dist/h3/plugin.cjs.map +1 -0
- package/dist/h3/plugin.d.cts +21 -0
- package/dist/h3/plugin.d.ts +21 -0
- package/dist/h3/plugin.js +1305 -0
- package/dist/h3/plugin.js.map +1 -0
- package/dist/h3/utils.cjs +127 -0
- package/dist/h3/utils.cjs.map +1 -0
- package/dist/h3/utils.d.cts +14 -0
- package/dist/h3/utils.d.ts +14 -0
- package/dist/h3/utils.js +107 -0
- package/dist/h3/utils.js.map +1 -0
- package/dist/hono/index.cjs +177 -141
- package/dist/hono/index.cjs.map +1 -1
- package/dist/hono/index.d.cts +2 -2
- package/dist/hono/index.d.ts +2 -2
- package/dist/hono/index.js +175 -140
- package/dist/hono/index.js.map +1 -1
- package/dist/hono/middleware.cjs +177 -141
- package/dist/hono/middleware.cjs.map +1 -1
- package/dist/hono/middleware.d.cts +4 -3
- package/dist/hono/middleware.d.ts +4 -3
- package/dist/hono/middleware.js +175 -140
- package/dist/hono/middleware.js.map +1 -1
- package/dist/hono/utils.cjs +126 -0
- package/dist/hono/utils.cjs.map +1 -0
- package/dist/hono/utils.d.cts +14 -0
- package/dist/hono/utils.d.ts +14 -0
- package/dist/hono/utils.js +106 -0
- package/dist/hono/utils.js.map +1 -0
- package/dist/koa/index.cjs +41 -17
- package/dist/koa/index.cjs.map +1 -1
- package/dist/koa/index.d.cts +2 -2
- package/dist/koa/index.d.ts +2 -2
- package/dist/koa/index.js +40 -17
- package/dist/koa/index.js.map +1 -1
- package/dist/koa/middleware.cjs +41 -17
- package/dist/koa/middleware.cjs.map +1 -1
- package/dist/koa/middleware.d.cts +4 -3
- package/dist/koa/middleware.d.ts +4 -3
- package/dist/koa/middleware.js +40 -17
- package/dist/koa/middleware.js.map +1 -1
- package/dist/nestjs/index.cjs +66 -44
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.d.cts +2 -2
- package/dist/nestjs/index.d.ts +2 -2
- package/dist/nestjs/index.js +65 -43
- package/dist/nestjs/index.js.map +1 -1
- package/package.json +21 -2
- package/dist/common/utils.cjs.map +0 -1
- package/dist/common/utils.js.map +0 -1
package/dist/fastify/index.cjs
CHANGED
|
@@ -33,7 +33,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
33
33
|
// src/fastify/index.ts
|
|
34
34
|
var fastify_exports = {};
|
|
35
35
|
__export(fastify_exports, {
|
|
36
|
-
apitallyPlugin: () => plugin_default
|
|
36
|
+
apitallyPlugin: () => plugin_default,
|
|
37
|
+
setConsumer: () => setConsumer
|
|
37
38
|
});
|
|
38
39
|
module.exports = __toCommonJS(fastify_exports);
|
|
39
40
|
|
|
@@ -404,6 +405,8 @@ var BODY_MASKED = import_buffer2.Buffer.from("<masked>");
|
|
|
404
405
|
var MASKED = "******";
|
|
405
406
|
var ALLOWED_CONTENT_TYPES = [
|
|
406
407
|
"application/json",
|
|
408
|
+
"application/problem+json",
|
|
409
|
+
"application/vnd.api+json",
|
|
407
410
|
"text/plain"
|
|
408
411
|
];
|
|
409
412
|
var EXCLUDE_PATH_PATTERNS = [
|
|
@@ -468,6 +471,9 @@ var _RequestLogger = class _RequestLogger {
|
|
|
468
471
|
}, 1e3);
|
|
469
472
|
}
|
|
470
473
|
}
|
|
474
|
+
get maxBodySize() {
|
|
475
|
+
return MAX_BODY_SIZE;
|
|
476
|
+
}
|
|
471
477
|
shouldExcludePath(urlPath) {
|
|
472
478
|
const patterns = [
|
|
473
479
|
...this.config.excludePaths,
|
|
@@ -1054,25 +1060,7 @@ __name(_ApitallyClient, "ApitallyClient");
|
|
|
1054
1060
|
__publicField(_ApitallyClient, "instance");
|
|
1055
1061
|
var ApitallyClient = _ApitallyClient;
|
|
1056
1062
|
|
|
1057
|
-
// src/common/
|
|
1058
|
-
var import_module = require("module");
|
|
1059
|
-
var import_meta = {};
|
|
1060
|
-
function getPackageVersion(name) {
|
|
1061
|
-
const packageJsonPath = `${name}/package.json`;
|
|
1062
|
-
try {
|
|
1063
|
-
return require(packageJsonPath).version || null;
|
|
1064
|
-
} catch (error) {
|
|
1065
|
-
try {
|
|
1066
|
-
const _require = (0, import_module.createRequire)(import_meta.url);
|
|
1067
|
-
return _require(packageJsonPath).version || null;
|
|
1068
|
-
} catch (error2) {
|
|
1069
|
-
return null;
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
__name(getPackageVersion, "getPackageVersion");
|
|
1074
|
-
|
|
1075
|
-
// src/common/utils.ts
|
|
1063
|
+
// src/common/headers.ts
|
|
1076
1064
|
function parseContentLength(contentLength) {
|
|
1077
1065
|
if (contentLength === void 0 || contentLength === null) {
|
|
1078
1066
|
return void 0;
|
|
@@ -1091,6 +1079,24 @@ function parseContentLength(contentLength) {
|
|
|
1091
1079
|
}
|
|
1092
1080
|
__name(parseContentLength, "parseContentLength");
|
|
1093
1081
|
|
|
1082
|
+
// src/common/packageVersions.ts
|
|
1083
|
+
var import_module = require("module");
|
|
1084
|
+
var import_meta = {};
|
|
1085
|
+
function getPackageVersion(name) {
|
|
1086
|
+
const packageJsonPath = `${name}/package.json`;
|
|
1087
|
+
try {
|
|
1088
|
+
return require(packageJsonPath).version || null;
|
|
1089
|
+
} catch (error) {
|
|
1090
|
+
try {
|
|
1091
|
+
const _require = (0, import_module.createRequire)(import_meta.url);
|
|
1092
|
+
return _require(packageJsonPath).version || null;
|
|
1093
|
+
} catch (error2) {
|
|
1094
|
+
return null;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
__name(getPackageVersion, "getPackageVersion");
|
|
1099
|
+
|
|
1094
1100
|
// src/fastify/plugin.ts
|
|
1095
1101
|
var apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
|
|
1096
1102
|
const client = new ApitallyClient(config);
|
|
@@ -1200,7 +1206,7 @@ var apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
|
|
|
1200
1206
|
done();
|
|
1201
1207
|
});
|
|
1202
1208
|
}, "apitallyPlugin");
|
|
1203
|
-
|
|
1209
|
+
function getAppInfo(routes, appVersion) {
|
|
1204
1210
|
const versions = [
|
|
1205
1211
|
[
|
|
1206
1212
|
"nodejs",
|
|
@@ -1232,8 +1238,13 @@ var getAppInfo = /* @__PURE__ */ __name((routes, appVersion) => {
|
|
|
1232
1238
|
versions: Object.fromEntries(versions),
|
|
1233
1239
|
client: "js:fastify"
|
|
1234
1240
|
};
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1241
|
+
}
|
|
1242
|
+
__name(getAppInfo, "getAppInfo");
|
|
1243
|
+
function setConsumer(request, consumer) {
|
|
1244
|
+
request.apitallyConsumer = consumer || void 0;
|
|
1245
|
+
}
|
|
1246
|
+
__name(setConsumer, "setConsumer");
|
|
1247
|
+
function getConsumer(request) {
|
|
1237
1248
|
if (request.apitallyConsumer) {
|
|
1238
1249
|
return consumerFromStringOrObject(request.apitallyConsumer);
|
|
1239
1250
|
} else if (request.consumerIdentifier) {
|
|
@@ -1241,16 +1252,18 @@ var getConsumer = /* @__PURE__ */ __name((request) => {
|
|
|
1241
1252
|
return consumerFromStringOrObject(request.consumerIdentifier);
|
|
1242
1253
|
}
|
|
1243
1254
|
return null;
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1255
|
+
}
|
|
1256
|
+
__name(getConsumer, "getConsumer");
|
|
1257
|
+
function getResponseTime(reply) {
|
|
1246
1258
|
if (reply.elapsedTime !== void 0) {
|
|
1247
1259
|
return reply.elapsedTime;
|
|
1248
1260
|
} else if (reply.getResponseTime !== void 0) {
|
|
1249
1261
|
return reply.getResponseTime();
|
|
1250
1262
|
}
|
|
1251
1263
|
return 0;
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1264
|
+
}
|
|
1265
|
+
__name(getResponseTime, "getResponseTime");
|
|
1266
|
+
function extractAjvErrors(message) {
|
|
1254
1267
|
const regex = /(?<=^|, )((?:headers|params|query|querystring|body)[/.][^ ]+)(?= )/g;
|
|
1255
1268
|
const matches = [];
|
|
1256
1269
|
let match;
|
|
@@ -1272,12 +1285,14 @@ var extractAjvErrors = /* @__PURE__ */ __name((message) => {
|
|
|
1272
1285
|
type: ""
|
|
1273
1286
|
};
|
|
1274
1287
|
});
|
|
1275
|
-
}
|
|
1288
|
+
}
|
|
1289
|
+
__name(extractAjvErrors, "extractAjvErrors");
|
|
1276
1290
|
var plugin_default = (0, import_fastify_plugin.default)(apitallyPlugin, {
|
|
1277
1291
|
name: "apitally"
|
|
1278
1292
|
});
|
|
1279
1293
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1280
1294
|
0 && (module.exports = {
|
|
1281
|
-
apitallyPlugin
|
|
1295
|
+
apitallyPlugin,
|
|
1296
|
+
setConsumer
|
|
1282
1297
|
});
|
|
1283
1298
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/fastify/index.ts","../../src/fastify/plugin.ts","../../src/common/client.ts","../../src/common/consumerRegistry.ts","../../src/common/logging.ts","../../src/common/paramValidation.ts","../../src/common/requestCounter.ts","../../src/common/requestLogger.ts","../../src/common/sentry.ts","../../src/common/serverErrorCounter.ts","../../src/common/tempGzipFile.ts","../../src/common/validationErrorCounter.ts","../../src/common/packageVersions.ts","../../src/common/utils.ts"],"sourcesContent":["export type { ApitallyConsumer } from \"../common/types.js\";\nexport { default as apitallyPlugin } from \"./plugin.js\";\n","import type {\n FastifyError,\n FastifyPluginAsync,\n FastifyReply,\n FastifyRequest,\n} from \"fastify\";\nimport fp from \"fastify-plugin\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport { convertBody, convertHeaders } from \"../common/requestLogger.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n PathInfo,\n ValidationError,\n} from \"../common/types.js\";\nimport { parseContentLength } from \"../common/utils.js\";\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}\n\nconst apitallyPlugin: FastifyPluginAsync<ApitallyConfig> = async (\n fastify,\n config,\n) => {\n const client = new ApitallyClient(config);\n const routes: PathInfo[] = [];\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 });\n\n fastify.addHook(\"onClose\", async () => {\n await client.handleShutdown();\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: requestSize,\n responseSize: responseSize,\n });\n if (\n (reply.statusCode === 400 || reply.statusCode === 422) &&\n reply.payload\n ) {\n try {\n const parsedPayload = JSON.parse(reply.payload);\n if (\n (!parsedPayload.code ||\n parsedPayload.code === \"FST_ERR_VALIDATION\") &&\n typeof parsedPayload.message === \"string\"\n ) {\n const validationErrors = extractAjvErrors(parsedPayload.message);\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n ...error,\n });\n });\n }\n } catch (error) {} // eslint-disable-line no-empty\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 if (client.requestLogger.enabled) {\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: Number(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: Number(responseSize),\n body: convertBody(\n reply.payload,\n reply.getHeader(\"content-type\")?.toString(),\n ),\n },\n reply.serverError,\n );\n }\n }\n done();\n });\n};\n\nconst getAppInfo = (routes: PathInfo[], appVersion?: string) => {\n const versions = [[\"nodejs\", process.version.replace(/^v/, \"\")]];\n const fastifyVersion = getPackageVersion(\"fastify\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (fastifyVersion) {\n versions.push([\"fastify\", fastifyVersion]);\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\nconst 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\nconst 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\nconst extractAjvErrors = (message: string): ValidationError[] => {\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};\n\nexport default fp(apitallyPlugin, {\n name: \"apitally\",\n});\n","import { randomUUID } from \"crypto\";\nimport fetchRetry from \"fetch-retry\";\n\nimport ConsumerRegistry from \"./consumerRegistry.js\";\nimport { Logger, getLogger } from \"./logging.js\";\nimport { isValidClientId, isValidEnv } from \"./paramValidation.js\";\nimport RequestCounter from \"./requestCounter.js\";\nimport RequestLogger from \"./requestLogger.js\";\nimport ServerErrorCounter from \"./serverErrorCounter.js\";\nimport {\n ApitallyConfig,\n StartupData,\n StartupPayload,\n SyncPayload,\n} from \"./types.js\";\nimport ValidationErrorCounter from \"./validationErrorCounter.js\";\n\nconst SYNC_INTERVAL = 60000; // 60 seconds\nconst INITIAL_SYNC_INTERVAL = 10000; // 10 seconds\nconst INITIAL_SYNC_INTERVAL_DURATION = 3600000; // 1 hour\nconst MAX_QUEUE_TIME = 3.6e6; // 1 hour\n\nclass HTTPError extends Error {\n public response: Response;\n\n constructor(response: Response) {\n const reason = response.status\n ? `status code ${response.status}`\n : \"an unknown error\";\n super(`Request failed with ${reason}`);\n this.response = response;\n }\n}\n\nexport class ApitallyClient {\n private clientId: string;\n private env: string;\n\n private static instance?: ApitallyClient;\n private instanceUuid: string;\n private syncDataQueue: SyncPayload[];\n private syncIntervalId?: NodeJS.Timeout;\n public startupData?: StartupData;\n private startupDataSent: boolean = false;\n private enabled: boolean = true;\n\n public requestCounter: RequestCounter;\n public requestLogger: RequestLogger;\n public validationErrorCounter: ValidationErrorCounter;\n public serverErrorCounter: ServerErrorCounter;\n public consumerRegistry: ConsumerRegistry;\n public logger: Logger;\n\n constructor({\n clientId,\n env = \"dev\",\n requestLoggingConfig,\n logger,\n }: ApitallyConfig) {\n if (ApitallyClient.instance) {\n throw new Error(\"Apitally client is already initialized\");\n }\n if (!isValidClientId(clientId)) {\n throw new Error(\n `Invalid Apitally client ID '${clientId}' (expecting hexadecimal UUID format)`,\n );\n }\n if (!isValidEnv(env)) {\n throw new Error(\n `Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`,\n );\n }\n\n ApitallyClient.instance = this;\n this.clientId = clientId;\n this.env = env;\n this.instanceUuid = randomUUID();\n this.syncDataQueue = [];\n this.requestCounter = new RequestCounter();\n this.requestLogger = new RequestLogger(requestLoggingConfig);\n this.validationErrorCounter = new ValidationErrorCounter();\n this.serverErrorCounter = new ServerErrorCounter();\n this.consumerRegistry = new ConsumerRegistry();\n this.logger = logger || getLogger();\n\n this.startSync();\n this.handleShutdown = this.handleShutdown.bind(this);\n }\n\n public static getInstance() {\n if (!ApitallyClient.instance) {\n throw new Error(\"Apitally client is not initialized\");\n }\n return ApitallyClient.instance;\n }\n\n public isEnabled() {\n return this.enabled;\n }\n\n public static async shutdown() {\n if (ApitallyClient.instance) {\n await ApitallyClient.instance.handleShutdown();\n }\n }\n\n public async handleShutdown() {\n this.enabled = false;\n this.stopSync();\n await this.sendSyncData();\n await this.sendLogData();\n await this.requestLogger.close();\n ApitallyClient.instance = undefined;\n }\n\n private getHubUrlPrefix() {\n const baseURL =\n process.env.APITALLY_HUB_BASE_URL || \"https://hub.apitally.io\";\n const version = \"v2\";\n return `${baseURL}/${version}/${this.clientId}/${this.env}/`;\n }\n\n private async sendData(url: string, payload: any) {\n const fetchWithRetry = fetchRetry(fetch, {\n retries: 3,\n retryDelay: 1000,\n retryOn: [408, 429, 500, 502, 503, 504],\n });\n const response = await fetchWithRetry(this.getHubUrlPrefix() + url, {\n method: \"POST\",\n body: JSON.stringify(payload),\n headers: { \"Content-Type\": \"application/json\" },\n });\n if (!response.ok) {\n throw new HTTPError(response);\n }\n }\n\n private startSync() {\n this.sync();\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, INITIAL_SYNC_INTERVAL);\n setTimeout(() => {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, SYNC_INTERVAL);\n }, INITIAL_SYNC_INTERVAL_DURATION);\n }\n\n private async sync() {\n try {\n const promises = [this.sendSyncData(), this.sendLogData()];\n if (!this.startupDataSent) {\n promises.push(this.sendStartupData());\n }\n await Promise.all(promises);\n } catch (error) {\n this.logger.error(\"Error while syncing with Apitally Hub\", {\n error,\n });\n }\n }\n\n private stopSync() {\n if (this.syncIntervalId) {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = undefined;\n }\n }\n\n public setStartupData(data: StartupData) {\n this.startupData = data;\n this.startupDataSent = false;\n this.sendStartupData();\n }\n\n private async sendStartupData() {\n if (this.startupData) {\n this.logger.debug(\"Sending startup data to Apitally Hub\");\n const payload: StartupPayload = {\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n ...this.startupData,\n };\n try {\n await this.sendData(\"startup\", payload);\n this.startupDataSent = true;\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.error((error as Error).message);\n this.logger.debug(\n \"Error while sending startup data to Apitally Hub (will retry)\",\n { error },\n );\n }\n }\n }\n }\n\n private async sendSyncData() {\n this.logger.debug(\"Synchronizing data with Apitally Hub\");\n const newPayload: SyncPayload = {\n timestamp: Date.now() / 1000,\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n requests: this.requestCounter.getAndResetRequests(),\n validation_errors:\n this.validationErrorCounter.getAndResetValidationErrors(),\n server_errors: this.serverErrorCounter.getAndResetServerErrors(),\n consumers: this.consumerRegistry.getAndResetUpdatedConsumers(),\n };\n this.syncDataQueue.push(newPayload);\n\n let i = 0;\n while (this.syncDataQueue.length > 0) {\n const payload = this.syncDataQueue.shift();\n if (payload) {\n try {\n if (Date.now() - payload.timestamp * 1000 <= MAX_QUEUE_TIME) {\n if (i > 0) {\n await this.randomDelay();\n }\n await this.sendData(\"sync\", payload);\n i += 1;\n }\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.debug(\n \"Error while synchronizing data with Apitally Hub (will retry)\",\n { error },\n );\n this.syncDataQueue.push(payload);\n break;\n }\n }\n }\n }\n }\n\n private async sendLogData() {\n this.logger.debug(\"Sending request log data to Apitally Hub\");\n await this.requestLogger.rotateFile();\n\n const fetchWithRetry = fetchRetry(fetch, {\n retries: 3,\n retryDelay: 1000,\n retryOn: [408, 429, 500, 502, 503, 504],\n });\n\n let i = 0;\n let logFile;\n while ((logFile = this.requestLogger.getFile())) {\n if (i > 0) {\n await this.randomDelay();\n }\n\n try {\n const response = await fetchWithRetry(\n `${this.getHubUrlPrefix()}log?uuid=${logFile.uuid}`,\n {\n method: \"POST\",\n body: await logFile.getContent(),\n },\n );\n\n if (response.status === 402 && response.headers.has(\"Retry-After\")) {\n const retryAfter = parseInt(\n response.headers.get(\"Retry-After\") ?? \"0\",\n );\n if (retryAfter > 0) {\n this.requestLogger.suspendUntil = Date.now() + retryAfter * 1000;\n this.requestLogger.clear();\n return;\n }\n }\n\n if (!response.ok) {\n throw new HTTPError(response);\n }\n\n logFile.delete();\n } catch (error) {\n this.requestLogger.retryFileLater(logFile);\n break;\n }\n\n i++;\n if (i >= 10) break;\n }\n }\n\n private handleHubError(error: unknown) {\n if (error instanceof HTTPError) {\n if (error.response.status === 404) {\n this.logger.error(`Invalid Apitally client ID: '${this.clientId}'`);\n this.enabled = false;\n this.stopSync();\n return true;\n }\n if (error.response.status === 422) {\n this.logger.error(\"Received validation error from Apitally Hub\");\n return true;\n }\n }\n return false;\n }\n\n private async randomDelay() {\n const delay = 100 + Math.random() * 400;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n}\n","import { ApitallyConsumer } from \"./types.js\";\n\nexport const consumerFromStringOrObject = (\n consumer: ApitallyConsumer | string,\n) => {\n if (typeof consumer === \"string\") {\n consumer = String(consumer).trim().substring(0, 128);\n return consumer ? { identifier: consumer } : null;\n } else {\n consumer.identifier = String(consumer.identifier).trim().substring(0, 128);\n consumer.name = consumer.name?.trim().substring(0, 64);\n consumer.group = consumer.group?.trim().substring(0, 64);\n return consumer.identifier ? consumer : null;\n }\n};\n\nexport default class ConsumerRegistry {\n private consumers: Map<string, ApitallyConsumer>;\n private updated: Set<string>;\n\n constructor() {\n this.consumers = new Map();\n this.updated = new Set();\n }\n\n public addOrUpdateConsumer(consumer?: ApitallyConsumer | null) {\n if (!consumer || (!consumer.name && !consumer.group)) {\n return;\n }\n const existing = this.consumers.get(consumer.identifier);\n if (!existing) {\n this.consumers.set(consumer.identifier, consumer);\n this.updated.add(consumer.identifier);\n } else {\n if (consumer.name && consumer.name !== existing.name) {\n existing.name = consumer.name;\n this.updated.add(consumer.identifier);\n }\n if (consumer.group && consumer.group !== existing.group) {\n existing.group = consumer.group;\n this.updated.add(consumer.identifier);\n }\n }\n }\n\n public getAndResetUpdatedConsumers() {\n const data: Array<ApitallyConsumer> = [];\n this.updated.forEach((identifier) => {\n const consumer = this.consumers.get(identifier);\n if (consumer) {\n data.push(consumer);\n }\n });\n this.updated.clear();\n return data;\n }\n}\n","import { createLogger, format, transports } from \"winston\";\n\nexport interface Logger {\n debug: (message: string, meta?: object) => void;\n info: (message: string, meta?: object) => void;\n warn: (message: string, meta?: object) => void;\n error: (message: string, meta?: object) => void;\n}\n\nexport const getLogger = () => {\n return createLogger({\n level: process.env.APITALLY_DEBUG ? \"debug\" : \"warn\",\n format: format.combine(\n format.colorize(),\n format.timestamp(),\n format.printf(\n (info) => `${info.timestamp} ${info.level}: ${info.message}`,\n ),\n ),\n transports: [new transports.Console()],\n });\n};\n","export function isValidClientId(clientId: string): boolean {\n const regexExp =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n return regexExp.test(clientId);\n}\n\nexport function isValidEnv(env: string): boolean {\n const regexExp = /^[\\w-]{1,32}$/;\n return regexExp.test(env);\n}\n","import { RequestInfo, RequestsItem } from \"./types.js\";\n\nexport default class RequestCounter {\n private requestCounts: Map<string, number>;\n private requestSizeSums: Map<string, number>;\n private responseSizeSums: Map<string, number>;\n private responseTimes: Map<string, Map<number, number>>;\n private requestSizes: Map<string, Map<number, number>>;\n private responseSizes: Map<string, Map<number, number>>;\n\n constructor() {\n this.requestCounts = new Map<string, number>();\n this.requestSizeSums = new Map<string, number>();\n this.responseSizeSums = new Map<string, number>();\n this.responseTimes = new Map<string, Map<number, number>>();\n this.requestSizes = new Map<string, Map<number, number>>();\n this.responseSizes = new Map<string, Map<number, number>>();\n }\n\n private getKey(requestInfo: RequestInfo) {\n return [\n requestInfo.consumer || \"\",\n requestInfo.method.toUpperCase(),\n requestInfo.path,\n requestInfo.statusCode,\n ].join(\"|\");\n }\n\n addRequest(requestInfo: RequestInfo) {\n const key = this.getKey(requestInfo);\n\n // Increment request count\n this.requestCounts.set(key, (this.requestCounts.get(key) || 0) + 1);\n\n // Add response time\n if (!this.responseTimes.has(key)) {\n this.responseTimes.set(key, new Map<number, number>());\n }\n const responseTimeMap = this.responseTimes.get(key)!;\n const responseTimeMsBin = Math.floor(requestInfo.responseTime / 10) * 10; // Rounded to nearest 10ms\n responseTimeMap.set(\n responseTimeMsBin,\n (responseTimeMap.get(responseTimeMsBin) || 0) + 1,\n );\n\n // Add request size\n if (requestInfo.requestSize !== undefined) {\n requestInfo.requestSize = Number(requestInfo.requestSize);\n this.requestSizeSums.set(\n key,\n (this.requestSizeSums.get(key) || 0) + requestInfo.requestSize,\n );\n if (!this.requestSizes.has(key)) {\n this.requestSizes.set(key, new Map<number, number>());\n }\n const requestSizeMap = this.requestSizes.get(key)!;\n const requestSizeKbBin = Math.floor(requestInfo.requestSize / 1000); // Rounded down to nearest KB\n requestSizeMap.set(\n requestSizeKbBin,\n (requestSizeMap.get(requestSizeKbBin) || 0) + 1,\n );\n }\n\n // Add response size\n if (requestInfo.responseSize !== undefined) {\n requestInfo.responseSize = Number(requestInfo.responseSize);\n this.responseSizeSums.set(\n key,\n (this.responseSizeSums.get(key) || 0) + requestInfo.responseSize,\n );\n if (!this.responseSizes.has(key)) {\n this.responseSizes.set(key, new Map<number, number>());\n }\n const responseSizeMap = this.responseSizes.get(key)!;\n const responseSizeKbBin = Math.floor(requestInfo.responseSize / 1000); // Rounded down to nearest KB\n responseSizeMap.set(\n responseSizeKbBin,\n (responseSizeMap.get(responseSizeKbBin) || 0) + 1,\n );\n }\n }\n\n getAndResetRequests() {\n const data: Array<RequestsItem> = [];\n this.requestCounts.forEach((count, key) => {\n const [consumer, method, path, statusCodeStr] = key.split(\"|\");\n const responseTimes =\n this.responseTimes.get(key) || new Map<number, number>();\n const requestSizes =\n this.requestSizes.get(key) || new Map<number, number>();\n const responseSizes =\n this.responseSizes.get(key) || new Map<number, number>();\n data.push({\n consumer: consumer || null,\n method,\n path,\n status_code: parseInt(statusCodeStr),\n request_count: count,\n request_size_sum: this.requestSizeSums.get(key) || 0,\n response_size_sum: this.responseSizeSums.get(key) || 0,\n response_times: Object.fromEntries(responseTimes),\n request_sizes: Object.fromEntries(requestSizes),\n response_sizes: Object.fromEntries(responseSizes),\n });\n });\n\n // Reset the counts and times\n this.requestCounts.clear();\n this.requestSizeSums.clear();\n this.responseSizeSums.clear();\n this.responseTimes.clear();\n this.requestSizes.clear();\n this.responseSizes.clear();\n\n return data;\n }\n}\n","import AsyncLock from \"async-lock\";\nimport { Buffer } from \"buffer\";\nimport { randomUUID } from \"crypto\";\nimport { unlinkSync, writeFileSync } from \"fs\";\nimport { IncomingHttpHeaders, OutgoingHttpHeaders } from \"http\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\n\nimport { getSentryEventId } from \"./sentry.js\";\nimport {\n truncateExceptionMessage,\n truncateExceptionStackTrace,\n} from \"./serverErrorCounter.js\";\nimport TempGzipFile from \"./tempGzipFile.js\";\n\nconst MAX_BODY_SIZE = 50_000; // 50 KB (uncompressed)\nconst MAX_FILE_SIZE = 1_000_000; // 1 MB (compressed)\nconst MAX_FILES = 50;\nconst MAX_PENDING_WRITES = 100;\nconst BODY_TOO_LARGE = Buffer.from(\"<body too large>\");\nconst BODY_MASKED = Buffer.from(\"<masked>\");\nconst MASKED = \"******\";\nconst ALLOWED_CONTENT_TYPES = [\"application/json\", \"text/plain\"];\nconst EXCLUDE_PATH_PATTERNS = [\n /\\/_?healthz?$/i,\n /\\/_?health[_-]?checks?$/i,\n /\\/_?heart[_-]?beats?$/i,\n /\\/ping$/i,\n /\\/ready$/i,\n /\\/live$/i,\n];\nconst EXCLUDE_USER_AGENT_PATTERNS = [\n /health[-_ ]?check/i,\n /microsoft-azure-application-lb/i,\n /googlehc/i,\n /kube-probe/i,\n];\nconst MASK_QUERY_PARAM_PATTERNS = [\n /auth/i,\n /api-?key/i,\n /secret/i,\n /token/i,\n /password/i,\n /pwd/i,\n];\nconst MASK_HEADER_PATTERNS = [\n /auth/i,\n /api-?key/i,\n /secret/i,\n /token/i,\n /cookie/i,\n];\n\nexport type Request = {\n timestamp: number;\n method: string;\n path?: string;\n url: string;\n headers: [string, string][];\n size?: number;\n consumer?: string;\n body?: Buffer;\n};\n\nexport type Response = {\n statusCode: number;\n responseTime: number;\n headers: [string, string][];\n size?: number;\n body?: Buffer;\n};\n\nexport type RequestLoggingConfig = {\n enabled: boolean;\n logQueryParams: boolean;\n logRequestHeaders: boolean;\n logRequestBody: boolean;\n logResponseHeaders: boolean;\n logResponseBody: boolean;\n logException: boolean;\n maskQueryParams: RegExp[];\n maskHeaders: RegExp[];\n maskRequestBodyCallback?: (request: Request) => Buffer | null | undefined;\n maskResponseBodyCallback?: (\n request: Request,\n response: Response,\n ) => Buffer | null | undefined;\n excludePaths: RegExp[];\n excludeCallback?: (request: Request, response: Response) => boolean;\n};\n\nconst DEFAULT_CONFIG: RequestLoggingConfig = {\n enabled: false,\n logQueryParams: true,\n logRequestHeaders: false,\n logRequestBody: false,\n logResponseHeaders: true,\n logResponseBody: false,\n logException: true,\n maskQueryParams: [],\n maskHeaders: [],\n excludePaths: [],\n};\n\nexport default class RequestLogger {\n public config: RequestLoggingConfig;\n public enabled: boolean;\n public suspendUntil: number | null = null;\n private pendingWrites: string[] = [];\n private currentFile: TempGzipFile | null = null;\n private files: TempGzipFile[] = [];\n private maintainIntervalId?: NodeJS.Timeout;\n private lock = new AsyncLock();\n\n constructor(config?: Partial<RequestLoggingConfig>) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.enabled = this.config.enabled && checkWritableFs();\n\n if (this.enabled) {\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 1000);\n }\n }\n\n private shouldExcludePath(urlPath: string) {\n const patterns = [...this.config.excludePaths, ...EXCLUDE_PATH_PATTERNS];\n return matchPatterns(urlPath, patterns);\n }\n\n private shouldExcludeUserAgent(userAgent?: string) {\n return userAgent\n ? matchPatterns(userAgent, EXCLUDE_USER_AGENT_PATTERNS)\n : false;\n }\n\n private shouldMaskQueryParam(name: string) {\n const patterns = [\n ...this.config.maskQueryParams,\n ...MASK_QUERY_PARAM_PATTERNS,\n ];\n return matchPatterns(name, patterns);\n }\n\n private shouldMaskHeader(name: string) {\n const patterns = [...this.config.maskHeaders, ...MASK_HEADER_PATTERNS];\n return matchPatterns(name, patterns);\n }\n\n private hasSupportedContentType(headers: [string, string][]) {\n const contentType = headers.find(\n ([k]) => k.toLowerCase() === \"content-type\",\n )?.[1];\n return this.isSupportedContentType(contentType);\n }\n\n public isSupportedContentType(contentType?: string | null) {\n return (\n typeof contentType === \"string\" &&\n ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t))\n );\n }\n\n private maskQueryParams(search: string) {\n const params = new URLSearchParams(search);\n for (const [key] of params) {\n if (this.shouldMaskQueryParam(key)) {\n params.set(key, MASKED);\n }\n }\n return params.toString();\n }\n\n private maskHeaders(headers: [string, string][]): [string, string][] {\n return headers.map(([k, v]) => [k, this.shouldMaskHeader(k) ? MASKED : v]);\n }\n\n logRequest(request: Request, response: Response, error?: Error) {\n if (!this.enabled || this.suspendUntil !== null) return;\n\n const url = new URL(request.url);\n const path = request.path ?? url.pathname;\n const userAgent = request.headers.find(\n ([k]) => k.toLowerCase() === \"user-agent\",\n )?.[1];\n\n if (\n this.shouldExcludePath(path) ||\n this.shouldExcludeUserAgent(userAgent) ||\n (this.config.excludeCallback?.(request, response) ?? false)\n ) {\n return;\n }\n\n // Process query params\n url.search = this.config.logQueryParams\n ? this.maskQueryParams(url.search)\n : \"\";\n request.url = url.toString();\n\n // Process request body\n if (\n !this.config.logRequestBody ||\n !this.hasSupportedContentType(request.headers)\n ) {\n request.body = undefined;\n } else if (request.body) {\n if (request.body.length > MAX_BODY_SIZE) {\n request.body = BODY_TOO_LARGE;\n } else if (this.config.maskRequestBodyCallback) {\n try {\n request.body =\n this.config.maskRequestBodyCallback(request) ?? BODY_MASKED;\n if (request.body.length > MAX_BODY_SIZE) {\n request.body = BODY_TOO_LARGE;\n }\n } catch {\n request.body = undefined;\n }\n }\n }\n\n // Process response body\n if (\n !this.config.logResponseBody ||\n !this.hasSupportedContentType(response.headers)\n ) {\n response.body = undefined;\n } else if (response.body) {\n if (response.body.length > MAX_BODY_SIZE) {\n response.body = BODY_TOO_LARGE;\n } else if (this.config.maskResponseBodyCallback) {\n try {\n response.body =\n this.config.maskResponseBodyCallback(request, response) ??\n BODY_MASKED;\n if (response.body.length > MAX_BODY_SIZE) {\n response.body = BODY_TOO_LARGE;\n }\n } catch {\n response.body = undefined;\n }\n }\n }\n\n // Process headers\n request.headers = this.config.logRequestHeaders\n ? this.maskHeaders(request.headers)\n : [];\n response.headers = this.config.logResponseHeaders\n ? this.maskHeaders(response.headers)\n : [];\n\n const item = {\n uuid: randomUUID(),\n request: skipEmptyValues(request),\n response: skipEmptyValues(response),\n exception:\n error && this.config.logException\n ? {\n type: error.name,\n message: truncateExceptionMessage(error.message),\n stacktrace: truncateExceptionStackTrace(error.stack || \"\"),\n sentryEventId: getSentryEventId(),\n }\n : null,\n };\n [item.request.body, item.response.body].forEach((body) => {\n if (body) {\n // @ts-expect-error Different return type\n body.toJSON = function () {\n return this.toString(\"base64\");\n };\n }\n });\n this.pendingWrites.push(JSON.stringify(item));\n\n if (this.pendingWrites.length > MAX_PENDING_WRITES) {\n this.pendingWrites.shift();\n }\n }\n\n async writeToFile() {\n if (!this.enabled || this.pendingWrites.length === 0) {\n return;\n }\n return this.lock.acquire(\"file\", async () => {\n if (!this.currentFile) {\n this.currentFile = new TempGzipFile();\n }\n while (this.pendingWrites.length > 0) {\n const item = this.pendingWrites.shift();\n if (item) {\n await this.currentFile.writeLine(Buffer.from(item));\n }\n }\n });\n }\n\n getFile() {\n return this.files.shift();\n }\n\n retryFileLater(file: TempGzipFile) {\n this.files.unshift(file);\n }\n\n async rotateFile() {\n return this.lock.acquire(\"file\", async () => {\n if (this.currentFile) {\n await this.currentFile.close();\n this.files.push(this.currentFile);\n this.currentFile = null;\n }\n });\n }\n\n async maintain() {\n await this.writeToFile();\n if (this.currentFile && this.currentFile.size > MAX_FILE_SIZE) {\n await this.rotateFile();\n }\n while (this.files.length > MAX_FILES) {\n const file = this.files.shift();\n file?.delete();\n }\n if (this.suspendUntil !== null && this.suspendUntil < Date.now()) {\n this.suspendUntil = null;\n }\n }\n\n async clear() {\n this.pendingWrites = [];\n await this.rotateFile();\n this.files.forEach((file) => {\n file.delete();\n });\n this.files = [];\n }\n\n async close() {\n this.enabled = false;\n await this.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n}\n\nexport function convertHeaders(\n headers:\n | Headers\n | IncomingHttpHeaders\n | OutgoingHttpHeaders\n | Record<string, string | string[] | number | undefined>,\n) {\n if (headers instanceof Headers) {\n return Array.from(headers.entries());\n }\n return Object.entries(headers).flatMap(([key, value]) => {\n if (value === undefined) {\n return [];\n }\n if (Array.isArray(value)) {\n return value.map((v) => [key, v]);\n }\n return [[key, value.toString()]];\n }) as [string, string][];\n}\n\nexport function convertBody(body: any, contentType?: string | null) {\n if (!body || !contentType) {\n return;\n }\n try {\n if (contentType.startsWith(\"application/json\")) {\n if (isValidJsonString(body)) {\n return Buffer.from(body);\n } else {\n return Buffer.from(JSON.stringify(body));\n }\n }\n if (contentType.startsWith(\"text/\") && typeof body === \"string\") {\n return Buffer.from(body);\n }\n } catch (error) {\n return;\n }\n}\n\nfunction isValidJsonString(body: any) {\n if (typeof body !== \"string\") {\n return false;\n }\n try {\n JSON.parse(body);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction matchPatterns(value: string, patterns: RegExp[]) {\n return patterns.some((pattern) => {\n return pattern.test(value);\n });\n}\n\nfunction skipEmptyValues<T extends Record<string, any>>(data: T) {\n return Object.fromEntries(\n Object.entries(data).filter(([_, v]) => {\n if (v == null || Number.isNaN(v)) return false;\n if (Array.isArray(v) || Buffer.isBuffer(v) || typeof v === \"string\") {\n return v.length > 0;\n }\n return true;\n }),\n ) as Partial<T>;\n}\n\nfunction checkWritableFs() {\n try {\n const testPath = join(tmpdir(), `apitally-${randomUUID()}`);\n writeFileSync(testPath, \"test\");\n unlinkSync(testPath);\n return true;\n } catch (error) {\n return false;\n }\n}\n","import type * as Sentry from \"@sentry/node\";\n\nlet sentry: typeof Sentry | undefined;\n\n// Initialize Sentry when the module is loaded\n(async () => {\n try {\n sentry = await import(\"@sentry/node\");\n } catch (e) {\n // Sentry SDK is not installed, ignore\n }\n})();\n\n/**\n * Returns the last Sentry event ID if available\n */\nexport function getSentryEventId(): string | undefined {\n if (sentry && sentry.lastEventId) {\n return sentry.lastEventId();\n }\n return undefined;\n}\n","import { createHash } from \"crypto\";\n\nimport { getSentryEventId } from \"./sentry.js\";\nimport { ConsumerMethodPath, ServerError, ServerErrorsItem } from \"./types.js\";\n\nconst MAX_MSG_LENGTH = 2048;\nconst MAX_STACKTRACE_LENGTH = 65536;\n\nexport default class ServerErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ServerError>;\n private sentryEventIds: Map<string, string>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n this.sentryEventIds = new Map();\n }\n\n public addServerError(serverError: ConsumerMethodPath & ServerError) {\n const key = this.getKey(serverError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, serverError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n\n const sentryEventId = getSentryEventId();\n if (sentryEventId) {\n this.sentryEventIds.set(key, sentryEventId);\n }\n }\n\n public getAndResetServerErrors() {\n const data: Array<ServerErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const serverError = this.errorDetails.get(key);\n if (serverError) {\n data.push({\n consumer: serverError.consumer || null,\n method: serverError.method,\n path: serverError.path,\n type: serverError.type,\n msg: truncateExceptionMessage(serverError.msg),\n traceback: truncateExceptionStackTrace(serverError.traceback),\n sentry_event_id: this.sentryEventIds.get(key) || null,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(serverError: ConsumerMethodPath & ServerError) {\n const hashInput = [\n serverError.consumer || \"\",\n serverError.method.toUpperCase(),\n serverError.path,\n serverError.type,\n serverError.msg.trim(),\n serverError.traceback.trim(),\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n\nexport function truncateExceptionMessage(msg: string) {\n if (msg.length <= MAX_MSG_LENGTH) {\n return msg;\n }\n const suffix = \"... (truncated)\";\n const cutoff = MAX_MSG_LENGTH - suffix.length;\n return msg.substring(0, cutoff) + suffix;\n}\n\nexport function truncateExceptionStackTrace(stack: string) {\n const suffix = \"... (truncated) ...\";\n const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;\n const lines = stack.trim().split(\"\\n\");\n const truncatedLines: string[] = [];\n let length = 0;\n for (const line of lines) {\n if (length + line.length + 1 > cutoff) {\n truncatedLines.push(suffix);\n break;\n }\n truncatedLines.push(line);\n length += line.length + 1;\n }\n return truncatedLines.join(\"\\n\");\n}\n","import { Buffer } from \"buffer\";\nimport { randomUUID } from \"crypto\";\nimport { createWriteStream, readFile, unlinkSync, WriteStream } from \"fs\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\nimport { createGzip, Gzip } from \"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 unlinkSync(this.filePath);\n }\n}\n","import { createHash } from \"crypto\";\n\nimport {\n ConsumerMethodPath,\n ValidationError,\n ValidationErrorsItem,\n} from \"./types.js\";\n\nexport default class ValidationErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ValidationError>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n }\n\n public addValidationError(\n validationError: ConsumerMethodPath & ValidationError,\n ) {\n const key = this.getKey(validationError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, validationError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n }\n\n public getAndResetValidationErrors() {\n const data: Array<ValidationErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const validationError = this.errorDetails.get(key);\n if (validationError) {\n data.push({\n consumer: validationError.consumer || null,\n method: validationError.method,\n path: validationError.path,\n loc: validationError.loc.split(\".\"),\n msg: validationError.msg,\n type: validationError.type,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(validationError: ConsumerMethodPath & ValidationError) {\n const hashInput = [\n validationError.consumer || \"\",\n validationError.method.toUpperCase(),\n validationError.path,\n validationError.loc,\n validationError.msg.trim(),\n validationError.type,\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n","import { createRequire } from \"module\";\n\nexport function getPackageVersion(name: string): string | null {\n const packageJsonPath = `${name}/package.json`;\n try {\n return require(packageJsonPath).version || null;\n } catch (error) {\n try {\n const _require = createRequire(import.meta.url);\n return _require(packageJsonPath).version || null;\n } catch (error) {\n return null;\n }\n }\n}\n","import { OutgoingHttpHeader } from \"http\";\n\nexport function parseContentLength(\n contentLength: OutgoingHttpHeader | undefined | null,\n): number | undefined {\n if (contentLength === undefined || contentLength === null) {\n return undefined;\n }\n if (typeof contentLength === \"number\") {\n return contentLength;\n }\n if (typeof contentLength === \"string\") {\n const parsed = parseInt(contentLength);\n return isNaN(parsed) ? undefined : parsed;\n }\n if (Array.isArray(contentLength)) {\n return parseContentLength(contentLength[0]);\n }\n return undefined;\n}\n"],"mappings":"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","names":["import_crypto","consumerFromStringOrObject","consumer","_a","String","trim","substring","identifier","name","group","ConsumerRegistry","consumers","updated","Map","Set","addOrUpdateConsumer","existing","get","set","add","getAndResetUpdatedConsumers","data","forEach","push","clear","getLogger","createLogger","level","process","env","APITALLY_DEBUG","format","combine","colorize","timestamp","printf","info","message","transports","Console","isValidClientId","clientId","regexExp","test","isValidEnv","env","RequestCounter","requestCounts","requestSizeSums","responseSizeSums","responseTimes","requestSizes","responseSizes","Map","getKey","requestInfo","consumer","method","toUpperCase","path","statusCode","join","addRequest","key","set","get","has","responseTimeMap","responseTimeMsBin","Math","floor","responseTime","requestSize","undefined","Number","requestSizeMap","requestSizeKbBin","responseSize","responseSizeMap","responseSizeKbBin","getAndResetRequests","data","forEach","count","statusCodeStr","split","push","status_code","parseInt","request_count","request_size_sum","response_size_sum","response_times","Object","fromEntries","request_sizes","response_sizes","clear","import_buffer","import_crypto","import_fs","import_os","import_path","sentry","e","getSentryEventId","lastEventId","undefined","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","Map","addServerError","serverError","key","getKey","has","set","get","sentryEventId","getSentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","truncateExceptionMessage","traceback","truncateExceptionStackTrace","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line","import_crypto","TempGzipFile","uuid","filePath","gzip","writeStream","readyPromise","closedPromise","randomUUID","join","tmpdir","createWriteStream","Promise","resolve","reject","once","createGzip","pipe","size","bytesWritten","writeLine","data","write","Buffer","concat","from","error","getContent","readFile","close","end","delete","unlinkSync","MAX_BODY_SIZE","MAX_FILE_SIZE","MAX_FILES","MAX_PENDING_WRITES","BODY_TOO_LARGE","Buffer","from","BODY_MASKED","MASKED","ALLOWED_CONTENT_TYPES","EXCLUDE_PATH_PATTERNS","EXCLUDE_USER_AGENT_PATTERNS","MASK_QUERY_PARAM_PATTERNS","MASK_HEADER_PATTERNS","DEFAULT_CONFIG","enabled","logQueryParams","logRequestHeaders","logRequestBody","logResponseHeaders","logResponseBody","logException","maskQueryParams","maskHeaders","excludePaths","RequestLogger","config","suspendUntil","pendingWrites","currentFile","files","maintainIntervalId","lock","AsyncLock","checkWritableFs","setInterval","maintain","shouldExcludePath","urlPath","patterns","matchPatterns","shouldExcludeUserAgent","userAgent","shouldMaskQueryParam","name","shouldMaskHeader","hasSupportedContentType","headers","_a","contentType","find","k","toLowerCase","isSupportedContentType","some","t","startsWith","search","params","URLSearchParams","key","set","toString","map","v","logRequest","request","response","error","url","URL","path","pathname","excludeCallback","body","undefined","length","maskRequestBodyCallback","maskResponseBodyCallback","item","uuid","randomUUID","skipEmptyValues","exception","type","message","truncateExceptionMessage","stacktrace","truncateExceptionStackTrace","stack","sentryEventId","getSentryEventId","forEach","toJSON","push","JSON","stringify","shift","writeToFile","acquire","TempGzipFile","writeLine","getFile","retryFileLater","file","unshift","rotateFile","close","size","delete","Date","now","clear","clearInterval","convertHeaders","Headers","Array","entries","Object","flatMap","value","isArray","convertBody","isValidJsonString","parse","pattern","test","data","fromEntries","filter","_","Number","isNaN","isBuffer","testPath","join","tmpdir","writeFileSync","unlinkSync","import_crypto","ValidationErrorCounter","errorCounts","errorDetails","Map","addValidationError","validationError","key","getKey","has","set","get","getAndResetValidationErrors","data","forEach","count","push","consumer","method","path","loc","split","msg","type","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","SYNC_INTERVAL","INITIAL_SYNC_INTERVAL","INITIAL_SYNC_INTERVAL_DURATION","MAX_QUEUE_TIME","HTTPError","Error","response","reason","status","ApitallyClient","clientId","env","instanceUuid","syncDataQueue","syncIntervalId","startupData","startupDataSent","enabled","requestCounter","requestLogger","validationErrorCounter","serverErrorCounter","consumerRegistry","logger","requestLoggingConfig","instance","isValidClientId","isValidEnv","randomUUID","RequestCounter","RequestLogger","ValidationErrorCounter","ServerErrorCounter","ConsumerRegistry","getLogger","startSync","handleShutdown","bind","getInstance","isEnabled","shutdown","stopSync","sendSyncData","sendLogData","close","undefined","getHubUrlPrefix","baseURL","process","APITALLY_HUB_BASE_URL","version","sendData","url","payload","fetchWithRetry","fetchRetry","fetch","retries","retryDelay","retryOn","method","body","JSON","stringify","headers","ok","sync","setInterval","setTimeout","clearInterval","promises","push","sendStartupData","Promise","all","error","setStartupData","data","debug","instance_uuid","message_uuid","handled","handleHubError","message","newPayload","timestamp","Date","now","requests","getAndResetRequests","validation_errors","getAndResetValidationErrors","server_errors","getAndResetServerErrors","consumers","getAndResetUpdatedConsumers","i","length","shift","randomDelay","rotateFile","logFile","getFile","uuid","getContent","has","retryAfter","parseInt","get","suspendUntil","clear","delete","retryFileLater","delay","Math","random","resolve","getPackageVersion","name","packageJsonPath","require","version","error","_require","createRequire","url","parseContentLength","contentLength","undefined","parsed","parseInt","isNaN","Array","isArray","apitallyPlugin","fastify","config","client","ApitallyClient","routes","decorateRequest","decorateReply","addHook","routeOptions","methods","Array","isArray","method","forEach","includes","toUpperCase","push","path","url","setStartupData","getAppInfo","appVersion","handleShutdown","request","reply","payload","done","contentType","getHeader","requestLogger","isSupportedContentType","error","statusCode","serverError","_a","isEnabled","consumer","getConsumer","routerPath","requestSize","parseContentLength","headers","responseSize","responseTime","getResponseTime","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","parsedPayload","JSON","parse","code","message","validationErrors","extractAjvErrors","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","traceback","stack","enabled","logRequest","timestamp","Date","now","protocol","host","hostname","originalUrl","convertHeaders","size","Number","body","convertBody","getHeaders","toString","versions","process","version","replace","fastifyVersion","getPackageVersion","apitallyVersion","paths","Object","fromEntries","apitallyConsumer","consumerFromStringOrObject","consumerIdentifier","emitWarning","elapsedTime","undefined","regex","matches","match","exec","index","map","m","i","endIndex","length","matchSplit","split","loc","join","substring","fp"]}
|
|
1
|
+
{"version":3,"sources":["../../src/fastify/index.ts","../../src/fastify/plugin.ts","../../src/common/client.ts","../../src/common/consumerRegistry.ts","../../src/common/logging.ts","../../src/common/paramValidation.ts","../../src/common/requestCounter.ts","../../src/common/requestLogger.ts","../../src/common/sentry.ts","../../src/common/serverErrorCounter.ts","../../src/common/tempGzipFile.ts","../../src/common/validationErrorCounter.ts","../../src/common/headers.ts","../../src/common/packageVersions.ts"],"sourcesContent":["export type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { default as apitallyPlugin, setConsumer } from \"./plugin.js\";\n","import type {\n FastifyError,\n FastifyPluginAsync,\n FastifyReply,\n FastifyRequest,\n} from \"fastify\";\nimport fp from \"fastify-plugin\";\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 { convertBody, convertHeaders } from \"../common/requestLogger.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n PathInfo,\n ValidationError,\n} from \"../common/types.js\";\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}\n\nconst apitallyPlugin: FastifyPluginAsync<ApitallyConfig> = async (\n fastify,\n config,\n) => {\n const client = new ApitallyClient(config);\n const routes: PathInfo[] = [];\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 });\n\n fastify.addHook(\"onClose\", async () => {\n await client.handleShutdown();\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: requestSize,\n responseSize: responseSize,\n });\n if (\n (reply.statusCode === 400 || reply.statusCode === 422) &&\n reply.payload\n ) {\n try {\n const parsedPayload = JSON.parse(reply.payload);\n if (\n (!parsedPayload.code ||\n parsedPayload.code === \"FST_ERR_VALIDATION\") &&\n typeof parsedPayload.message === \"string\"\n ) {\n const validationErrors = extractAjvErrors(parsedPayload.message);\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n ...error,\n });\n });\n }\n } catch (error) {} // eslint-disable-line no-empty\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 if (client.requestLogger.enabled) {\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: Number(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: Number(responseSize),\n body: convertBody(\n reply.payload,\n reply.getHeader(\"content-type\")?.toString(),\n ),\n },\n reply.serverError,\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 apitallyVersion = getPackageVersion(\"../..\");\n if (fastifyVersion) {\n versions.push([\"fastify\", fastifyVersion]);\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 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}\n\nexport default fp(apitallyPlugin, {\n name: \"apitally\",\n});\n","import { randomUUID } from \"crypto\";\nimport fetchRetry from \"fetch-retry\";\n\nimport ConsumerRegistry from \"./consumerRegistry.js\";\nimport { Logger, getLogger } from \"./logging.js\";\nimport { isValidClientId, isValidEnv } from \"./paramValidation.js\";\nimport RequestCounter from \"./requestCounter.js\";\nimport RequestLogger from \"./requestLogger.js\";\nimport ServerErrorCounter from \"./serverErrorCounter.js\";\nimport {\n ApitallyConfig,\n StartupData,\n StartupPayload,\n SyncPayload,\n} from \"./types.js\";\nimport ValidationErrorCounter from \"./validationErrorCounter.js\";\n\nconst SYNC_INTERVAL = 60000; // 60 seconds\nconst INITIAL_SYNC_INTERVAL = 10000; // 10 seconds\nconst INITIAL_SYNC_INTERVAL_DURATION = 3600000; // 1 hour\nconst MAX_QUEUE_TIME = 3.6e6; // 1 hour\n\nclass HTTPError extends Error {\n public response: Response;\n\n constructor(response: Response) {\n const reason = response.status\n ? `status code ${response.status}`\n : \"an unknown error\";\n super(`Request failed with ${reason}`);\n this.response = response;\n }\n}\n\nexport class ApitallyClient {\n private clientId: string;\n private env: string;\n\n private static instance?: ApitallyClient;\n private instanceUuid: string;\n private syncDataQueue: SyncPayload[];\n private syncIntervalId?: NodeJS.Timeout;\n public startupData?: StartupData;\n private startupDataSent: boolean = false;\n private enabled: boolean = true;\n\n public requestCounter: RequestCounter;\n public requestLogger: RequestLogger;\n public validationErrorCounter: ValidationErrorCounter;\n public serverErrorCounter: ServerErrorCounter;\n public consumerRegistry: ConsumerRegistry;\n public logger: Logger;\n\n constructor({\n clientId,\n env = \"dev\",\n requestLoggingConfig,\n logger,\n }: ApitallyConfig) {\n if (ApitallyClient.instance) {\n throw new Error(\"Apitally client is already initialized\");\n }\n if (!isValidClientId(clientId)) {\n throw new Error(\n `Invalid Apitally client ID '${clientId}' (expecting hexadecimal UUID format)`,\n );\n }\n if (!isValidEnv(env)) {\n throw new Error(\n `Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`,\n );\n }\n\n ApitallyClient.instance = this;\n this.clientId = clientId;\n this.env = env;\n this.instanceUuid = randomUUID();\n this.syncDataQueue = [];\n this.requestCounter = new RequestCounter();\n this.requestLogger = new RequestLogger(requestLoggingConfig);\n this.validationErrorCounter = new ValidationErrorCounter();\n this.serverErrorCounter = new ServerErrorCounter();\n this.consumerRegistry = new ConsumerRegistry();\n this.logger = logger || getLogger();\n\n this.startSync();\n this.handleShutdown = this.handleShutdown.bind(this);\n }\n\n public static getInstance() {\n if (!ApitallyClient.instance) {\n throw new Error(\"Apitally client is not initialized\");\n }\n return ApitallyClient.instance;\n }\n\n public isEnabled() {\n return this.enabled;\n }\n\n public static async shutdown() {\n if (ApitallyClient.instance) {\n await ApitallyClient.instance.handleShutdown();\n }\n }\n\n public async handleShutdown() {\n this.enabled = false;\n this.stopSync();\n await this.sendSyncData();\n await this.sendLogData();\n await this.requestLogger.close();\n ApitallyClient.instance = undefined;\n }\n\n private getHubUrlPrefix() {\n const baseURL =\n process.env.APITALLY_HUB_BASE_URL || \"https://hub.apitally.io\";\n const version = \"v2\";\n return `${baseURL}/${version}/${this.clientId}/${this.env}/`;\n }\n\n private async sendData(url: string, payload: any) {\n const fetchWithRetry = fetchRetry(fetch, {\n retries: 3,\n retryDelay: 1000,\n retryOn: [408, 429, 500, 502, 503, 504],\n });\n const response = await fetchWithRetry(this.getHubUrlPrefix() + url, {\n method: \"POST\",\n body: JSON.stringify(payload),\n headers: { \"Content-Type\": \"application/json\" },\n });\n if (!response.ok) {\n throw new HTTPError(response);\n }\n }\n\n private startSync() {\n this.sync();\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, INITIAL_SYNC_INTERVAL);\n setTimeout(() => {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, SYNC_INTERVAL);\n }, INITIAL_SYNC_INTERVAL_DURATION);\n }\n\n private async sync() {\n try {\n const promises = [this.sendSyncData(), this.sendLogData()];\n if (!this.startupDataSent) {\n promises.push(this.sendStartupData());\n }\n await Promise.all(promises);\n } catch (error) {\n this.logger.error(\"Error while syncing with Apitally Hub\", {\n error,\n });\n }\n }\n\n private stopSync() {\n if (this.syncIntervalId) {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = undefined;\n }\n }\n\n public setStartupData(data: StartupData) {\n this.startupData = data;\n this.startupDataSent = false;\n this.sendStartupData();\n }\n\n private async sendStartupData() {\n if (this.startupData) {\n this.logger.debug(\"Sending startup data to Apitally Hub\");\n const payload: StartupPayload = {\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n ...this.startupData,\n };\n try {\n await this.sendData(\"startup\", payload);\n this.startupDataSent = true;\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.error((error as Error).message);\n this.logger.debug(\n \"Error while sending startup data to Apitally Hub (will retry)\",\n { error },\n );\n }\n }\n }\n }\n\n private async sendSyncData() {\n this.logger.debug(\"Synchronizing data with Apitally Hub\");\n const newPayload: SyncPayload = {\n timestamp: Date.now() / 1000,\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n requests: this.requestCounter.getAndResetRequests(),\n validation_errors:\n this.validationErrorCounter.getAndResetValidationErrors(),\n server_errors: this.serverErrorCounter.getAndResetServerErrors(),\n consumers: this.consumerRegistry.getAndResetUpdatedConsumers(),\n };\n this.syncDataQueue.push(newPayload);\n\n let i = 0;\n while (this.syncDataQueue.length > 0) {\n const payload = this.syncDataQueue.shift();\n if (payload) {\n try {\n if (Date.now() - payload.timestamp * 1000 <= MAX_QUEUE_TIME) {\n if (i > 0) {\n await this.randomDelay();\n }\n await this.sendData(\"sync\", payload);\n i += 1;\n }\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.debug(\n \"Error while synchronizing data with Apitally Hub (will retry)\",\n { error },\n );\n this.syncDataQueue.push(payload);\n break;\n }\n }\n }\n }\n }\n\n private async sendLogData() {\n this.logger.debug(\"Sending request log data to Apitally Hub\");\n await this.requestLogger.rotateFile();\n\n const fetchWithRetry = fetchRetry(fetch, {\n retries: 3,\n retryDelay: 1000,\n retryOn: [408, 429, 500, 502, 503, 504],\n });\n\n let i = 0;\n let logFile;\n while ((logFile = this.requestLogger.getFile())) {\n if (i > 0) {\n await this.randomDelay();\n }\n\n try {\n const response = await fetchWithRetry(\n `${this.getHubUrlPrefix()}log?uuid=${logFile.uuid}`,\n {\n method: \"POST\",\n body: await logFile.getContent(),\n },\n );\n\n if (response.status === 402 && response.headers.has(\"Retry-After\")) {\n const retryAfter = parseInt(\n response.headers.get(\"Retry-After\") ?? \"0\",\n );\n if (retryAfter > 0) {\n this.requestLogger.suspendUntil = Date.now() + retryAfter * 1000;\n this.requestLogger.clear();\n return;\n }\n }\n\n if (!response.ok) {\n throw new HTTPError(response);\n }\n\n logFile.delete();\n } catch (error) {\n this.requestLogger.retryFileLater(logFile);\n break;\n }\n\n i++;\n if (i >= 10) break;\n }\n }\n\n private handleHubError(error: unknown) {\n if (error instanceof HTTPError) {\n if (error.response.status === 404) {\n this.logger.error(`Invalid Apitally client ID: '${this.clientId}'`);\n this.enabled = false;\n this.stopSync();\n return true;\n }\n if (error.response.status === 422) {\n this.logger.error(\"Received validation error from Apitally Hub\");\n return true;\n }\n }\n return false;\n }\n\n private async randomDelay() {\n const delay = 100 + Math.random() * 400;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n}\n","import { ApitallyConsumer } from \"./types.js\";\n\nexport const consumerFromStringOrObject = (\n consumer: ApitallyConsumer | string,\n) => {\n if (typeof consumer === \"string\") {\n consumer = String(consumer).trim().substring(0, 128);\n return consumer ? { identifier: consumer } : null;\n } else {\n consumer.identifier = String(consumer.identifier).trim().substring(0, 128);\n consumer.name = consumer.name?.trim().substring(0, 64);\n consumer.group = consumer.group?.trim().substring(0, 64);\n return consumer.identifier ? consumer : null;\n }\n};\n\nexport default class ConsumerRegistry {\n private consumers: Map<string, ApitallyConsumer>;\n private updated: Set<string>;\n\n constructor() {\n this.consumers = new Map();\n this.updated = new Set();\n }\n\n public addOrUpdateConsumer(consumer?: ApitallyConsumer | null) {\n if (!consumer || (!consumer.name && !consumer.group)) {\n return;\n }\n const existing = this.consumers.get(consumer.identifier);\n if (!existing) {\n this.consumers.set(consumer.identifier, consumer);\n this.updated.add(consumer.identifier);\n } else {\n if (consumer.name && consumer.name !== existing.name) {\n existing.name = consumer.name;\n this.updated.add(consumer.identifier);\n }\n if (consumer.group && consumer.group !== existing.group) {\n existing.group = consumer.group;\n this.updated.add(consumer.identifier);\n }\n }\n }\n\n public getAndResetUpdatedConsumers() {\n const data: Array<ApitallyConsumer> = [];\n this.updated.forEach((identifier) => {\n const consumer = this.consumers.get(identifier);\n if (consumer) {\n data.push(consumer);\n }\n });\n this.updated.clear();\n return data;\n }\n}\n","import { createLogger, format, transports } from \"winston\";\n\nexport interface Logger {\n debug: (message: string, meta?: object) => void;\n info: (message: string, meta?: object) => void;\n warn: (message: string, meta?: object) => void;\n error: (message: string, meta?: object) => void;\n}\n\nexport const getLogger = () => {\n return createLogger({\n level: process.env.APITALLY_DEBUG ? \"debug\" : \"warn\",\n format: format.combine(\n format.colorize(),\n format.timestamp(),\n format.printf(\n (info) => `${info.timestamp} ${info.level}: ${info.message}`,\n ),\n ),\n transports: [new transports.Console()],\n });\n};\n","export function isValidClientId(clientId: string): boolean {\n const regexExp =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n return regexExp.test(clientId);\n}\n\nexport function isValidEnv(env: string): boolean {\n const regexExp = /^[\\w-]{1,32}$/;\n return regexExp.test(env);\n}\n","import { RequestInfo, RequestsItem } from \"./types.js\";\n\nexport default class RequestCounter {\n private requestCounts: Map<string, number>;\n private requestSizeSums: Map<string, number>;\n private responseSizeSums: Map<string, number>;\n private responseTimes: Map<string, Map<number, number>>;\n private requestSizes: Map<string, Map<number, number>>;\n private responseSizes: Map<string, Map<number, number>>;\n\n constructor() {\n this.requestCounts = new Map<string, number>();\n this.requestSizeSums = new Map<string, number>();\n this.responseSizeSums = new Map<string, number>();\n this.responseTimes = new Map<string, Map<number, number>>();\n this.requestSizes = new Map<string, Map<number, number>>();\n this.responseSizes = new Map<string, Map<number, number>>();\n }\n\n private getKey(requestInfo: RequestInfo) {\n return [\n requestInfo.consumer || \"\",\n requestInfo.method.toUpperCase(),\n requestInfo.path,\n requestInfo.statusCode,\n ].join(\"|\");\n }\n\n addRequest(requestInfo: RequestInfo) {\n const key = this.getKey(requestInfo);\n\n // Increment request count\n this.requestCounts.set(key, (this.requestCounts.get(key) || 0) + 1);\n\n // Add response time\n if (!this.responseTimes.has(key)) {\n this.responseTimes.set(key, new Map<number, number>());\n }\n const responseTimeMap = this.responseTimes.get(key)!;\n const responseTimeMsBin = Math.floor(requestInfo.responseTime / 10) * 10; // Rounded to nearest 10ms\n responseTimeMap.set(\n responseTimeMsBin,\n (responseTimeMap.get(responseTimeMsBin) || 0) + 1,\n );\n\n // Add request size\n if (requestInfo.requestSize !== undefined) {\n requestInfo.requestSize = Number(requestInfo.requestSize);\n this.requestSizeSums.set(\n key,\n (this.requestSizeSums.get(key) || 0) + requestInfo.requestSize,\n );\n if (!this.requestSizes.has(key)) {\n this.requestSizes.set(key, new Map<number, number>());\n }\n const requestSizeMap = this.requestSizes.get(key)!;\n const requestSizeKbBin = Math.floor(requestInfo.requestSize / 1000); // Rounded down to nearest KB\n requestSizeMap.set(\n requestSizeKbBin,\n (requestSizeMap.get(requestSizeKbBin) || 0) + 1,\n );\n }\n\n // Add response size\n if (requestInfo.responseSize !== undefined) {\n requestInfo.responseSize = Number(requestInfo.responseSize);\n this.responseSizeSums.set(\n key,\n (this.responseSizeSums.get(key) || 0) + requestInfo.responseSize,\n );\n if (!this.responseSizes.has(key)) {\n this.responseSizes.set(key, new Map<number, number>());\n }\n const responseSizeMap = this.responseSizes.get(key)!;\n const responseSizeKbBin = Math.floor(requestInfo.responseSize / 1000); // Rounded down to nearest KB\n responseSizeMap.set(\n responseSizeKbBin,\n (responseSizeMap.get(responseSizeKbBin) || 0) + 1,\n );\n }\n }\n\n getAndResetRequests() {\n const data: Array<RequestsItem> = [];\n this.requestCounts.forEach((count, key) => {\n const [consumer, method, path, statusCodeStr] = key.split(\"|\");\n const responseTimes =\n this.responseTimes.get(key) || new Map<number, number>();\n const requestSizes =\n this.requestSizes.get(key) || new Map<number, number>();\n const responseSizes =\n this.responseSizes.get(key) || new Map<number, number>();\n data.push({\n consumer: consumer || null,\n method,\n path,\n status_code: parseInt(statusCodeStr),\n request_count: count,\n request_size_sum: this.requestSizeSums.get(key) || 0,\n response_size_sum: this.responseSizeSums.get(key) || 0,\n response_times: Object.fromEntries(responseTimes),\n request_sizes: Object.fromEntries(requestSizes),\n response_sizes: Object.fromEntries(responseSizes),\n });\n });\n\n // Reset the counts and times\n this.requestCounts.clear();\n this.requestSizeSums.clear();\n this.responseSizeSums.clear();\n this.responseTimes.clear();\n this.requestSizes.clear();\n this.responseSizes.clear();\n\n return data;\n }\n}\n","import AsyncLock from \"async-lock\";\nimport { Buffer } from \"buffer\";\nimport { randomUUID } from \"crypto\";\nimport { unlinkSync, writeFileSync } from \"fs\";\nimport { IncomingHttpHeaders, OutgoingHttpHeaders } from \"http\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\n\nimport { getSentryEventId } from \"./sentry.js\";\nimport {\n truncateExceptionMessage,\n truncateExceptionStackTrace,\n} from \"./serverErrorCounter.js\";\nimport TempGzipFile from \"./tempGzipFile.js\";\n\nconst MAX_BODY_SIZE = 50_000; // 50 KB (uncompressed)\nconst MAX_FILE_SIZE = 1_000_000; // 1 MB (compressed)\nconst MAX_FILES = 50;\nconst MAX_PENDING_WRITES = 100;\nconst BODY_TOO_LARGE = Buffer.from(\"<body too large>\");\nconst BODY_MASKED = Buffer.from(\"<masked>\");\nconst MASKED = \"******\";\nconst ALLOWED_CONTENT_TYPES = [\n \"application/json\",\n \"application/problem+json\",\n \"application/vnd.api+json\",\n \"text/plain\",\n];\nconst EXCLUDE_PATH_PATTERNS = [\n /\\/_?healthz?$/i,\n /\\/_?health[_-]?checks?$/i,\n /\\/_?heart[_-]?beats?$/i,\n /\\/ping$/i,\n /\\/ready$/i,\n /\\/live$/i,\n];\nconst EXCLUDE_USER_AGENT_PATTERNS = [\n /health[-_ ]?check/i,\n /microsoft-azure-application-lb/i,\n /googlehc/i,\n /kube-probe/i,\n];\nconst MASK_QUERY_PARAM_PATTERNS = [\n /auth/i,\n /api-?key/i,\n /secret/i,\n /token/i,\n /password/i,\n /pwd/i,\n];\nconst MASK_HEADER_PATTERNS = [\n /auth/i,\n /api-?key/i,\n /secret/i,\n /token/i,\n /cookie/i,\n];\n\nexport type Request = {\n timestamp: number;\n method: string;\n path?: string;\n url: string;\n headers: [string, string][];\n size?: number;\n consumer?: string;\n body?: Buffer;\n};\n\nexport type Response = {\n statusCode: number;\n responseTime: number;\n headers: [string, string][];\n size?: number;\n body?: Buffer;\n};\n\nexport type RequestLoggingConfig = {\n enabled: boolean;\n logQueryParams: boolean;\n logRequestHeaders: boolean;\n logRequestBody: boolean;\n logResponseHeaders: boolean;\n logResponseBody: boolean;\n logException: boolean;\n maskQueryParams: RegExp[];\n maskHeaders: RegExp[];\n maskRequestBodyCallback?: (request: Request) => Buffer | null | undefined;\n maskResponseBodyCallback?: (\n request: Request,\n response: Response,\n ) => Buffer | null | undefined;\n excludePaths: RegExp[];\n excludeCallback?: (request: Request, response: Response) => boolean;\n};\n\nconst DEFAULT_CONFIG: RequestLoggingConfig = {\n enabled: false,\n logQueryParams: true,\n logRequestHeaders: false,\n logRequestBody: false,\n logResponseHeaders: true,\n logResponseBody: false,\n logException: true,\n maskQueryParams: [],\n maskHeaders: [],\n excludePaths: [],\n};\n\nexport default class RequestLogger {\n public config: RequestLoggingConfig;\n public enabled: boolean;\n public suspendUntil: number | null = null;\n private pendingWrites: string[] = [];\n private currentFile: TempGzipFile | null = null;\n private files: TempGzipFile[] = [];\n private maintainIntervalId?: NodeJS.Timeout;\n private lock = new AsyncLock();\n\n constructor(config?: Partial<RequestLoggingConfig>) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.enabled = this.config.enabled && checkWritableFs();\n\n if (this.enabled) {\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 1000);\n }\n }\n\n get maxBodySize() {\n return MAX_BODY_SIZE;\n }\n\n private shouldExcludePath(urlPath: string) {\n const patterns = [...this.config.excludePaths, ...EXCLUDE_PATH_PATTERNS];\n return matchPatterns(urlPath, patterns);\n }\n\n private shouldExcludeUserAgent(userAgent?: string) {\n return userAgent\n ? matchPatterns(userAgent, EXCLUDE_USER_AGENT_PATTERNS)\n : false;\n }\n\n private shouldMaskQueryParam(name: string) {\n const patterns = [\n ...this.config.maskQueryParams,\n ...MASK_QUERY_PARAM_PATTERNS,\n ];\n return matchPatterns(name, patterns);\n }\n\n private shouldMaskHeader(name: string) {\n const patterns = [...this.config.maskHeaders, ...MASK_HEADER_PATTERNS];\n return matchPatterns(name, patterns);\n }\n\n private hasSupportedContentType(headers: [string, string][]) {\n const contentType = headers.find(\n ([k]) => k.toLowerCase() === \"content-type\",\n )?.[1];\n return this.isSupportedContentType(contentType);\n }\n\n public isSupportedContentType(contentType?: string | null) {\n return (\n typeof contentType === \"string\" &&\n ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t))\n );\n }\n\n private maskQueryParams(search: string) {\n const params = new URLSearchParams(search);\n for (const [key] of params) {\n if (this.shouldMaskQueryParam(key)) {\n params.set(key, MASKED);\n }\n }\n return params.toString();\n }\n\n private maskHeaders(headers: [string, string][]): [string, string][] {\n return headers.map(([k, v]) => [k, this.shouldMaskHeader(k) ? MASKED : v]);\n }\n\n logRequest(request: Request, response: Response, error?: Error) {\n if (!this.enabled || this.suspendUntil !== null) return;\n\n const url = new URL(request.url);\n const path = request.path ?? url.pathname;\n const userAgent = request.headers.find(\n ([k]) => k.toLowerCase() === \"user-agent\",\n )?.[1];\n\n if (\n this.shouldExcludePath(path) ||\n this.shouldExcludeUserAgent(userAgent) ||\n (this.config.excludeCallback?.(request, response) ?? false)\n ) {\n return;\n }\n\n // Process query params\n url.search = this.config.logQueryParams\n ? this.maskQueryParams(url.search)\n : \"\";\n request.url = url.toString();\n\n // Process request body\n if (\n !this.config.logRequestBody ||\n !this.hasSupportedContentType(request.headers)\n ) {\n request.body = undefined;\n } else if (request.body) {\n if (request.body.length > MAX_BODY_SIZE) {\n request.body = BODY_TOO_LARGE;\n } else if (this.config.maskRequestBodyCallback) {\n try {\n request.body =\n this.config.maskRequestBodyCallback(request) ?? BODY_MASKED;\n if (request.body.length > MAX_BODY_SIZE) {\n request.body = BODY_TOO_LARGE;\n }\n } catch {\n request.body = undefined;\n }\n }\n }\n\n // Process response body\n if (\n !this.config.logResponseBody ||\n !this.hasSupportedContentType(response.headers)\n ) {\n response.body = undefined;\n } else if (response.body) {\n if (response.body.length > MAX_BODY_SIZE) {\n response.body = BODY_TOO_LARGE;\n } else if (this.config.maskResponseBodyCallback) {\n try {\n response.body =\n this.config.maskResponseBodyCallback(request, response) ??\n BODY_MASKED;\n if (response.body.length > MAX_BODY_SIZE) {\n response.body = BODY_TOO_LARGE;\n }\n } catch {\n response.body = undefined;\n }\n }\n }\n\n // Process headers\n request.headers = this.config.logRequestHeaders\n ? this.maskHeaders(request.headers)\n : [];\n response.headers = this.config.logResponseHeaders\n ? this.maskHeaders(response.headers)\n : [];\n\n const item = {\n uuid: randomUUID(),\n request: skipEmptyValues(request),\n response: skipEmptyValues(response),\n exception:\n error && this.config.logException\n ? {\n type: error.name,\n message: truncateExceptionMessage(error.message),\n stacktrace: truncateExceptionStackTrace(error.stack || \"\"),\n sentryEventId: getSentryEventId(),\n }\n : null,\n };\n [item.request.body, item.response.body].forEach((body) => {\n if (body) {\n // @ts-expect-error Different return type\n body.toJSON = function () {\n return this.toString(\"base64\");\n };\n }\n });\n this.pendingWrites.push(JSON.stringify(item));\n\n if (this.pendingWrites.length > MAX_PENDING_WRITES) {\n this.pendingWrites.shift();\n }\n }\n\n async writeToFile() {\n if (!this.enabled || this.pendingWrites.length === 0) {\n return;\n }\n return this.lock.acquire(\"file\", async () => {\n if (!this.currentFile) {\n this.currentFile = new TempGzipFile();\n }\n while (this.pendingWrites.length > 0) {\n const item = this.pendingWrites.shift();\n if (item) {\n await this.currentFile.writeLine(Buffer.from(item));\n }\n }\n });\n }\n\n getFile() {\n return this.files.shift();\n }\n\n retryFileLater(file: TempGzipFile) {\n this.files.unshift(file);\n }\n\n async rotateFile() {\n return this.lock.acquire(\"file\", async () => {\n if (this.currentFile) {\n await this.currentFile.close();\n this.files.push(this.currentFile);\n this.currentFile = null;\n }\n });\n }\n\n async maintain() {\n await this.writeToFile();\n if (this.currentFile && this.currentFile.size > MAX_FILE_SIZE) {\n await this.rotateFile();\n }\n while (this.files.length > MAX_FILES) {\n const file = this.files.shift();\n file?.delete();\n }\n if (this.suspendUntil !== null && this.suspendUntil < Date.now()) {\n this.suspendUntil = null;\n }\n }\n\n async clear() {\n this.pendingWrites = [];\n await this.rotateFile();\n this.files.forEach((file) => {\n file.delete();\n });\n this.files = [];\n }\n\n async close() {\n this.enabled = false;\n await this.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n}\n\nexport function convertHeaders(\n headers:\n | Headers\n | IncomingHttpHeaders\n | OutgoingHttpHeaders\n | Record<string, string | string[] | number | undefined>,\n) {\n if (headers instanceof Headers) {\n return Array.from(headers.entries());\n }\n return Object.entries(headers).flatMap(([key, value]) => {\n if (value === undefined) {\n return [];\n }\n if (Array.isArray(value)) {\n return value.map((v) => [key, v]);\n }\n return [[key, value.toString()]];\n }) as [string, string][];\n}\n\nexport function convertBody(body: any, contentType?: string | null) {\n if (!body || !contentType) {\n return;\n }\n try {\n if (contentType.startsWith(\"application/json\")) {\n if (isValidJsonString(body)) {\n return Buffer.from(body);\n } else {\n return Buffer.from(JSON.stringify(body));\n }\n }\n if (contentType.startsWith(\"text/\") && typeof body === \"string\") {\n return Buffer.from(body);\n }\n } catch (error) {\n return;\n }\n}\n\nfunction isValidJsonString(body: any) {\n if (typeof body !== \"string\") {\n return false;\n }\n try {\n JSON.parse(body);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction matchPatterns(value: string, patterns: RegExp[]) {\n return patterns.some((pattern) => {\n return pattern.test(value);\n });\n}\n\nfunction skipEmptyValues<T extends Record<string, any>>(data: T) {\n return Object.fromEntries(\n Object.entries(data).filter(([_, v]) => {\n if (v == null || Number.isNaN(v)) return false;\n if (Array.isArray(v) || Buffer.isBuffer(v) || typeof v === \"string\") {\n return v.length > 0;\n }\n return true;\n }),\n ) as Partial<T>;\n}\n\nfunction checkWritableFs() {\n try {\n const testPath = join(tmpdir(), `apitally-${randomUUID()}`);\n writeFileSync(testPath, \"test\");\n unlinkSync(testPath);\n return true;\n } catch (error) {\n return false;\n }\n}\n","import type * as Sentry from \"@sentry/node\";\n\nlet sentry: typeof Sentry | undefined;\n\n// Initialize Sentry when the module is loaded\n(async () => {\n try {\n sentry = await import(\"@sentry/node\");\n } catch (e) {\n // Sentry SDK is not installed, ignore\n }\n})();\n\n/**\n * Returns the last Sentry event ID if available\n */\nexport function getSentryEventId(): string | undefined {\n if (sentry && sentry.lastEventId) {\n return sentry.lastEventId();\n }\n return undefined;\n}\n","import { createHash } from \"crypto\";\n\nimport { getSentryEventId } from \"./sentry.js\";\nimport { ConsumerMethodPath, ServerError, ServerErrorsItem } from \"./types.js\";\n\nconst MAX_MSG_LENGTH = 2048;\nconst MAX_STACKTRACE_LENGTH = 65536;\n\nexport default class ServerErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ServerError>;\n private sentryEventIds: Map<string, string>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n this.sentryEventIds = new Map();\n }\n\n public addServerError(serverError: ConsumerMethodPath & ServerError) {\n const key = this.getKey(serverError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, serverError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n\n const sentryEventId = getSentryEventId();\n if (sentryEventId) {\n this.sentryEventIds.set(key, sentryEventId);\n }\n }\n\n public getAndResetServerErrors() {\n const data: Array<ServerErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const serverError = this.errorDetails.get(key);\n if (serverError) {\n data.push({\n consumer: serverError.consumer || null,\n method: serverError.method,\n path: serverError.path,\n type: serverError.type,\n msg: truncateExceptionMessage(serverError.msg),\n traceback: truncateExceptionStackTrace(serverError.traceback),\n sentry_event_id: this.sentryEventIds.get(key) || null,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(serverError: ConsumerMethodPath & ServerError) {\n const hashInput = [\n serverError.consumer || \"\",\n serverError.method.toUpperCase(),\n serverError.path,\n serverError.type,\n serverError.msg.trim(),\n serverError.traceback.trim(),\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n\nexport function truncateExceptionMessage(msg: string) {\n if (msg.length <= MAX_MSG_LENGTH) {\n return msg;\n }\n const suffix = \"... (truncated)\";\n const cutoff = MAX_MSG_LENGTH - suffix.length;\n return msg.substring(0, cutoff) + suffix;\n}\n\nexport function truncateExceptionStackTrace(stack: string) {\n const suffix = \"... (truncated) ...\";\n const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;\n const lines = stack.trim().split(\"\\n\");\n const truncatedLines: string[] = [];\n let length = 0;\n for (const line of lines) {\n if (length + line.length + 1 > cutoff) {\n truncatedLines.push(suffix);\n break;\n }\n truncatedLines.push(line);\n length += line.length + 1;\n }\n return truncatedLines.join(\"\\n\");\n}\n","import { Buffer } from \"buffer\";\nimport { randomUUID } from \"crypto\";\nimport { createWriteStream, readFile, unlinkSync, WriteStream } from \"fs\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\nimport { createGzip, Gzip } from \"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 unlinkSync(this.filePath);\n }\n}\n","import { createHash } from \"crypto\";\n\nimport {\n ConsumerMethodPath,\n ValidationError,\n ValidationErrorsItem,\n} from \"./types.js\";\n\nexport default class ValidationErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ValidationError>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n }\n\n public addValidationError(\n validationError: ConsumerMethodPath & ValidationError,\n ) {\n const key = this.getKey(validationError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, validationError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n }\n\n public getAndResetValidationErrors() {\n const data: Array<ValidationErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const validationError = this.errorDetails.get(key);\n if (validationError) {\n data.push({\n consumer: validationError.consumer || null,\n method: validationError.method,\n path: validationError.path,\n loc: validationError.loc.split(\".\"),\n msg: validationError.msg,\n type: validationError.type,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(validationError: ConsumerMethodPath & ValidationError) {\n const hashInput = [\n validationError.consumer || \"\",\n validationError.method.toUpperCase(),\n validationError.path,\n validationError.loc,\n validationError.msg.trim(),\n validationError.type,\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n","import { OutgoingHttpHeader } from \"http\";\n\nexport function parseContentLength(\n contentLength: OutgoingHttpHeader | undefined | null,\n): number | undefined {\n if (contentLength === undefined || contentLength === null) {\n return undefined;\n }\n if (typeof contentLength === \"number\") {\n return contentLength;\n }\n if (typeof contentLength === \"string\") {\n const parsed = parseInt(contentLength);\n return isNaN(parsed) ? undefined : parsed;\n }\n if (Array.isArray(contentLength)) {\n return parseContentLength(contentLength[0]);\n }\n return undefined;\n}\n\nexport function mergeHeaders(base: Headers, merge: Headers) {\n const mergedHeaders = new Headers(base);\n for (const [name, value] of merge)\n if (name === \"set-cookie\") mergedHeaders.append(name, value);\n else mergedHeaders.set(name, value);\n return mergedHeaders;\n}\n","import { createRequire } from \"module\";\n\nexport function getPackageVersion(name: string): string | null {\n const packageJsonPath = `${name}/package.json`;\n try {\n return require(packageJsonPath).version || null;\n } catch (error) {\n try {\n const _require = createRequire(import.meta.url);\n return _require(packageJsonPath).version || null;\n } catch (error) {\n return null;\n }\n }\n}\n"],"mappings":"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","names":["import_crypto","consumerFromStringOrObject","consumer","_a","String","trim","substring","identifier","name","group","ConsumerRegistry","consumers","updated","Map","Set","addOrUpdateConsumer","existing","get","set","add","getAndResetUpdatedConsumers","data","forEach","push","clear","getLogger","createLogger","level","process","env","APITALLY_DEBUG","format","combine","colorize","timestamp","printf","info","message","transports","Console","isValidClientId","clientId","regexExp","test","isValidEnv","env","RequestCounter","requestCounts","requestSizeSums","responseSizeSums","responseTimes","requestSizes","responseSizes","Map","getKey","requestInfo","consumer","method","toUpperCase","path","statusCode","join","addRequest","key","set","get","has","responseTimeMap","responseTimeMsBin","Math","floor","responseTime","requestSize","undefined","Number","requestSizeMap","requestSizeKbBin","responseSize","responseSizeMap","responseSizeKbBin","getAndResetRequests","data","forEach","count","statusCodeStr","split","push","status_code","parseInt","request_count","request_size_sum","response_size_sum","response_times","Object","fromEntries","request_sizes","response_sizes","clear","import_buffer","import_crypto","import_fs","import_os","import_path","sentry","e","getSentryEventId","lastEventId","undefined","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","Map","addServerError","serverError","key","getKey","has","set","get","sentryEventId","getSentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","truncateExceptionMessage","traceback","truncateExceptionStackTrace","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line","import_crypto","TempGzipFile","uuid","filePath","gzip","writeStream","readyPromise","closedPromise","randomUUID","join","tmpdir","createWriteStream","Promise","resolve","reject","once","createGzip","pipe","size","bytesWritten","writeLine","data","write","Buffer","concat","from","error","getContent","readFile","close","end","delete","unlinkSync","MAX_BODY_SIZE","MAX_FILE_SIZE","MAX_FILES","MAX_PENDING_WRITES","BODY_TOO_LARGE","Buffer","from","BODY_MASKED","MASKED","ALLOWED_CONTENT_TYPES","EXCLUDE_PATH_PATTERNS","EXCLUDE_USER_AGENT_PATTERNS","MASK_QUERY_PARAM_PATTERNS","MASK_HEADER_PATTERNS","DEFAULT_CONFIG","enabled","logQueryParams","logRequestHeaders","logRequestBody","logResponseHeaders","logResponseBody","logException","maskQueryParams","maskHeaders","excludePaths","RequestLogger","config","suspendUntil","pendingWrites","currentFile","files","maintainIntervalId","lock","AsyncLock","checkWritableFs","setInterval","maintain","maxBodySize","shouldExcludePath","urlPath","patterns","matchPatterns","shouldExcludeUserAgent","userAgent","shouldMaskQueryParam","name","shouldMaskHeader","hasSupportedContentType","headers","_a","contentType","find","k","toLowerCase","isSupportedContentType","some","t","startsWith","search","params","URLSearchParams","key","set","toString","map","v","logRequest","request","response","error","url","URL","path","pathname","excludeCallback","body","undefined","length","maskRequestBodyCallback","maskResponseBodyCallback","item","uuid","randomUUID","skipEmptyValues","exception","type","message","truncateExceptionMessage","stacktrace","truncateExceptionStackTrace","stack","sentryEventId","getSentryEventId","forEach","toJSON","push","JSON","stringify","shift","writeToFile","acquire","TempGzipFile","writeLine","getFile","retryFileLater","file","unshift","rotateFile","close","size","delete","Date","now","clear","clearInterval","convertHeaders","Headers","Array","entries","Object","flatMap","value","isArray","convertBody","isValidJsonString","parse","pattern","test","data","fromEntries","filter","_","Number","isNaN","isBuffer","testPath","join","tmpdir","writeFileSync","unlinkSync","import_crypto","ValidationErrorCounter","errorCounts","errorDetails","Map","addValidationError","validationError","key","getKey","has","set","get","getAndResetValidationErrors","data","forEach","count","push","consumer","method","path","loc","split","msg","type","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","SYNC_INTERVAL","INITIAL_SYNC_INTERVAL","INITIAL_SYNC_INTERVAL_DURATION","MAX_QUEUE_TIME","HTTPError","Error","response","reason","status","ApitallyClient","clientId","env","instanceUuid","syncDataQueue","syncIntervalId","startupData","startupDataSent","enabled","requestCounter","requestLogger","validationErrorCounter","serverErrorCounter","consumerRegistry","logger","requestLoggingConfig","instance","isValidClientId","isValidEnv","randomUUID","RequestCounter","RequestLogger","ValidationErrorCounter","ServerErrorCounter","ConsumerRegistry","getLogger","startSync","handleShutdown","bind","getInstance","isEnabled","shutdown","stopSync","sendSyncData","sendLogData","close","undefined","getHubUrlPrefix","baseURL","process","APITALLY_HUB_BASE_URL","version","sendData","url","payload","fetchWithRetry","fetchRetry","fetch","retries","retryDelay","retryOn","method","body","JSON","stringify","headers","ok","sync","setInterval","setTimeout","clearInterval","promises","push","sendStartupData","Promise","all","error","setStartupData","data","debug","instance_uuid","message_uuid","handled","handleHubError","message","newPayload","timestamp","Date","now","requests","getAndResetRequests","validation_errors","getAndResetValidationErrors","server_errors","getAndResetServerErrors","consumers","getAndResetUpdatedConsumers","i","length","shift","randomDelay","rotateFile","logFile","getFile","uuid","getContent","has","retryAfter","parseInt","get","suspendUntil","clear","delete","retryFileLater","delay","Math","random","resolve","parseContentLength","contentLength","undefined","parsed","parseInt","isNaN","Array","isArray","getPackageVersion","name","packageJsonPath","require","version","error","_require","createRequire","url","apitallyPlugin","fastify","config","client","ApitallyClient","routes","decorateRequest","decorateReply","addHook","routeOptions","methods","Array","isArray","method","forEach","includes","toUpperCase","push","path","url","setStartupData","getAppInfo","appVersion","handleShutdown","request","reply","payload","done","contentType","getHeader","requestLogger","isSupportedContentType","error","statusCode","serverError","_a","isEnabled","consumer","getConsumer","routerPath","requestSize","parseContentLength","headers","responseSize","responseTime","getResponseTime","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","parsedPayload","JSON","parse","code","message","validationErrors","extractAjvErrors","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","traceback","stack","enabled","logRequest","timestamp","Date","now","protocol","host","hostname","originalUrl","convertHeaders","size","Number","body","convertBody","getHeaders","toString","versions","process","version","replace","fastifyVersion","getPackageVersion","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","fp"]}
|
package/dist/fastify/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { ApitallyConsumer } from '../common/types.cjs';
|
|
2
|
-
export { default as apitallyPlugin } from './plugin.cjs';
|
|
1
|
+
export { ApitallyConfig, ApitallyConsumer } from '../common/types.cjs';
|
|
2
|
+
export { default as apitallyPlugin, setConsumer } from './plugin.cjs';
|
|
3
3
|
import '../common/logging.cjs';
|
|
4
4
|
import 'winston';
|
|
5
5
|
import '../common/requestLogger.cjs';
|
package/dist/fastify/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { ApitallyConsumer } from '../common/types.js';
|
|
2
|
-
export { default as apitallyPlugin } from './plugin.js';
|
|
1
|
+
export { ApitallyConfig, ApitallyConsumer } from '../common/types.js';
|
|
2
|
+
export { default as apitallyPlugin, setConsumer } from './plugin.js';
|
|
3
3
|
import '../common/logging.js';
|
|
4
4
|
import 'winston';
|
|
5
5
|
import '../common/requestLogger.js';
|