apitally 0.21.2 → 0.21.4
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/dist/adonisjs/configure.cjs +6 -21
- package/dist/adonisjs/configure.cjs.map +1 -1
- package/dist/adonisjs/configure.js +3 -18
- package/dist/adonisjs/configure.js.map +1 -1
- package/dist/adonisjs/index.cjs +2 -70
- package/dist/adonisjs/index.cjs.map +1 -1
- package/dist/adonisjs/index.js +1 -66
- package/dist/adonisjs/index.js.map +1 -1
- package/dist/adonisjs/middleware.cjs +11 -116
- package/dist/adonisjs/middleware.cjs.map +1 -1
- package/dist/adonisjs/middleware.js +6 -101
- package/dist/adonisjs/middleware.js.map +1 -1
- package/dist/adonisjs/provider.cjs +15 -5663
- package/dist/adonisjs/provider.cjs.map +1 -1
- package/dist/adonisjs/provider.js +7 -5671
- package/dist/adonisjs/provider.js.map +1 -1
- package/dist/common/client.cjs +39 -800
- package/dist/common/client.cjs.map +1 -1
- package/dist/common/client.d.cts +1 -1
- package/dist/common/client.d.ts +1 -1
- package/dist/common/client.js +33 -794
- package/dist/common/client.js.map +1 -1
- package/dist/common/consumerRegistry.cjs +3 -5
- package/dist/common/consumerRegistry.cjs.map +1 -1
- package/dist/common/consumerRegistry.js +3 -5
- package/dist/common/consumerRegistry.js.map +1 -1
- package/dist/common/headers.cjs +0 -2
- package/dist/common/headers.cjs.map +1 -1
- package/dist/common/headers.js +0 -2
- package/dist/common/headers.js.map +1 -1
- package/dist/common/logging.cjs +0 -2
- package/dist/common/logging.cjs.map +1 -1
- package/dist/common/logging.js +0 -2
- package/dist/common/logging.js.map +1 -1
- package/dist/common/packageVersions.cjs +2 -4
- package/dist/common/packageVersions.cjs.map +1 -1
- package/dist/common/packageVersions.js +2 -10
- package/dist/common/packageVersions.js.map +1 -1
- package/dist/common/paramValidation.cjs +0 -2
- package/dist/common/paramValidation.cjs.map +1 -1
- package/dist/common/paramValidation.js +0 -2
- package/dist/common/paramValidation.js.map +1 -1
- package/dist/common/requestCounter.cjs +2 -4
- package/dist/common/requestCounter.cjs.map +1 -1
- package/dist/common/requestCounter.js +2 -4
- package/dist/common/requestCounter.js.map +1 -1
- package/dist/common/requestLogger.cjs +39 -162
- package/dist/common/requestLogger.cjs.map +1 -1
- package/dist/common/requestLogger.js +33 -156
- package/dist/common/requestLogger.js.map +1 -1
- package/dist/common/response.cjs +21 -4
- package/dist/common/response.cjs.map +1 -1
- package/dist/common/response.d.cts +2 -1
- package/dist/common/response.d.ts +2 -1
- package/dist/common/response.js +19 -3
- package/dist/common/response.js.map +1 -1
- package/dist/common/sentry.cjs +1 -3
- package/dist/common/sentry.cjs.map +1 -1
- package/dist/common/sentry.js +1 -3
- package/dist/common/sentry.js.map +1 -1
- package/dist/common/serverErrorCounter.cjs +7 -36
- package/dist/common/serverErrorCounter.cjs.map +1 -1
- package/dist/common/serverErrorCounter.js +6 -25
- package/dist/common/serverErrorCounter.js.map +1 -1
- package/dist/common/tempGzipFile.cjs +9 -11
- package/dist/common/tempGzipFile.cjs.map +1 -1
- package/dist/common/tempGzipFile.js +9 -11
- package/dist/common/tempGzipFile.js.map +1 -1
- package/dist/common/types.cjs +0 -2
- package/dist/common/types.cjs.map +1 -1
- package/dist/common/validationErrorCounter.cjs +3 -5
- package/dist/common/validationErrorCounter.cjs.map +1 -1
- package/dist/common/validationErrorCounter.js +3 -5
- package/dist/common/validationErrorCounter.js.map +1 -1
- package/dist/elysia/index.cjs +2 -1549
- package/dist/elysia/index.cjs.map +1 -1
- package/dist/elysia/index.js +2 -1553
- package/dist/elysia/index.js.map +1 -1
- package/dist/elysia/plugin.cjs +33 -1415
- package/dist/elysia/plugin.cjs.map +1 -1
- package/dist/elysia/plugin.js +22 -1399
- package/dist/elysia/plugin.js.map +1 -1
- package/dist/elysia/utils.cjs +3 -24
- package/dist/elysia/utils.cjs.map +1 -1
- package/dist/elysia/utils.js +1 -25
- package/dist/elysia/utils.js.map +1 -1
- package/dist/express/index.cjs +3 -6348
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.js +1 -6361
- package/dist/express/index.js.map +1 -1
- package/dist/express/middleware.cjs +39 -6065
- package/dist/express/middleware.cjs.map +1 -1
- package/dist/express/middleware.js +14 -6056
- package/dist/express/middleware.js.map +1 -1
- package/dist/express/utils.cjs +17 -19
- package/dist/express/utils.cjs.map +1 -1
- package/dist/express/utils.js +17 -19
- package/dist/express/utils.js.map +1 -1
- package/dist/fastify/index.cjs +3 -6118
- package/dist/fastify/index.cjs.map +1 -1
- package/dist/fastify/index.js +2 -6142
- package/dist/fastify/index.js.map +1 -1
- package/dist/fastify/plugin.cjs +36 -5884
- package/dist/fastify/plugin.cjs.map +1 -1
- package/dist/fastify/plugin.js +14 -5888
- package/dist/fastify/plugin.js.map +1 -1
- package/dist/h3/index.cjs +3 -1539
- package/dist/h3/index.cjs.map +1 -1
- package/dist/h3/index.js +1 -1531
- package/dist/h3/index.js.map +1 -1
- package/dist/h3/plugin.cjs +28 -1418
- package/dist/h3/plugin.cjs.map +1 -1
- package/dist/h3/plugin.js +16 -1401
- package/dist/h3/plugin.js.map +1 -1
- package/dist/h3/utils.cjs +3 -24
- package/dist/h3/utils.cjs.map +1 -1
- package/dist/h3/utils.js +1 -25
- package/dist/h3/utils.js.map +1 -1
- package/dist/hapi/index.cjs +3 -5982
- package/dist/hapi/index.cjs.map +1 -1
- package/dist/hapi/index.js +2 -6006
- package/dist/hapi/index.js.map +1 -1
- package/dist/hapi/plugin.cjs +28 -5842
- package/dist/hapi/plugin.cjs.map +1 -1
- package/dist/hapi/plugin.js +16 -5846
- package/dist/hapi/plugin.js.map +1 -1
- package/dist/hapi/utils.cjs +3 -24
- package/dist/hapi/utils.cjs.map +1 -1
- package/dist/hapi/utils.js +1 -25
- package/dist/hapi/utils.js.map +1 -1
- package/dist/hono/index.cjs +3 -1565
- package/dist/hono/index.cjs.map +1 -1
- package/dist/hono/index.js +1 -1557
- package/dist/hono/index.js.map +1 -1
- package/dist/hono/middleware.cjs +22 -1455
- package/dist/hono/middleware.cjs.map +1 -1
- package/dist/hono/middleware.js +10 -1438
- package/dist/hono/middleware.js.map +1 -1
- package/dist/hono/utils.cjs +3 -24
- package/dist/hono/utils.cjs.map +1 -1
- package/dist/hono/utils.js +1 -27
- package/dist/hono/utils.js.map +1 -1
- package/dist/koa/index.cjs +3 -1478
- package/dist/koa/index.cjs.map +1 -1
- package/dist/koa/index.js +1 -1470
- package/dist/koa/index.js.map +1 -1
- package/dist/koa/middleware.cjs +20 -1308
- package/dist/koa/middleware.cjs.map +1 -1
- package/dist/koa/middleware.js +9 -1292
- package/dist/koa/middleware.js.map +1 -1
- package/dist/loggers/console.cjs +4 -6
- package/dist/loggers/console.cjs.map +1 -1
- package/dist/loggers/console.js +4 -6
- package/dist/loggers/console.js.map +1 -1
- package/dist/loggers/hapi.cjs +3 -5
- package/dist/loggers/hapi.cjs.map +1 -1
- package/dist/loggers/hapi.js +3 -5
- package/dist/loggers/hapi.js.map +1 -1
- package/dist/loggers/index.cjs +10 -4732
- package/dist/loggers/index.cjs.map +1 -1
- package/dist/loggers/index.js +5 -4743
- package/dist/loggers/index.js.map +1 -1
- package/dist/loggers/nestjs.cjs +5 -39
- package/dist/loggers/nestjs.cjs.map +1 -1
- package/dist/loggers/nestjs.js +4 -36
- package/dist/loggers/nestjs.js.map +1 -1
- package/dist/loggers/pino.cjs +29 -4448
- package/dist/loggers/pino.cjs.map +1 -1
- package/dist/loggers/pino.js +7 -4451
- package/dist/loggers/pino.js.map +1 -1
- package/dist/loggers/utils.cjs +1 -3
- package/dist/loggers/utils.cjs.map +1 -1
- package/dist/loggers/utils.js +1 -3
- package/dist/loggers/utils.js.map +1 -1
- package/dist/loggers/winston.cjs +6 -44
- package/dist/loggers/winston.cjs.map +1 -1
- package/dist/loggers/winston.js +4 -40
- package/dist/loggers/winston.js.map +1 -1
- package/dist/nestjs/index.cjs +17 -17779
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.js +20 -17807
- package/dist/nestjs/index.js.map +1 -1
- package/package.json +1 -1
package/dist/elysia/plugin.cjs
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
6
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
10
7
|
var __export = (target, all) => {
|
|
11
8
|
for (var name in all)
|
|
@@ -19,1446 +16,67 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
19
16
|
}
|
|
20
17
|
return to;
|
|
21
18
|
};
|
|
22
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
23
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
24
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
25
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
26
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
27
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
28
|
-
mod
|
|
29
|
-
));
|
|
30
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
31
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
32
|
-
|
|
33
|
-
// src/elysia/plugin.ts
|
|
34
20
|
var plugin_exports = {};
|
|
35
21
|
__export(plugin_exports, {
|
|
36
22
|
default: () => apitallyPlugin
|
|
37
23
|
});
|
|
38
24
|
module.exports = __toCommonJS(plugin_exports);
|
|
39
25
|
var import_elysia = require("elysia");
|
|
40
|
-
var import_node_async_hooks = require("async_hooks");
|
|
41
|
-
var import_node_perf_hooks = require("perf_hooks");
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
var
|
|
45
|
-
var
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
var
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
identifier: consumer
|
|
54
|
-
} : null;
|
|
55
|
-
} else {
|
|
56
|
-
consumer.identifier = String(consumer.identifier).trim().substring(0, 128);
|
|
57
|
-
consumer.name = (_a2 = consumer.name) == null ? void 0 : _a2.trim().substring(0, 64);
|
|
58
|
-
consumer.group = (_b = consumer.group) == null ? void 0 : _b.trim().substring(0, 64);
|
|
59
|
-
return consumer.identifier ? consumer : null;
|
|
60
|
-
}
|
|
61
|
-
}, "consumerFromStringOrObject");
|
|
62
|
-
var _ConsumerRegistry = class _ConsumerRegistry {
|
|
63
|
-
consumers;
|
|
64
|
-
updated;
|
|
65
|
-
constructor() {
|
|
66
|
-
this.consumers = /* @__PURE__ */ new Map();
|
|
67
|
-
this.updated = /* @__PURE__ */ new Set();
|
|
68
|
-
}
|
|
69
|
-
addOrUpdateConsumer(consumer) {
|
|
70
|
-
if (!consumer || !consumer.name && !consumer.group) {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
const existing = this.consumers.get(consumer.identifier);
|
|
74
|
-
if (!existing) {
|
|
75
|
-
this.consumers.set(consumer.identifier, consumer);
|
|
76
|
-
this.updated.add(consumer.identifier);
|
|
77
|
-
} else {
|
|
78
|
-
if (consumer.name && consumer.name !== existing.name) {
|
|
79
|
-
existing.name = consumer.name;
|
|
80
|
-
this.updated.add(consumer.identifier);
|
|
81
|
-
}
|
|
82
|
-
if (consumer.group && consumer.group !== existing.group) {
|
|
83
|
-
existing.group = consumer.group;
|
|
84
|
-
this.updated.add(consumer.identifier);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
getAndResetUpdatedConsumers() {
|
|
89
|
-
const data = [];
|
|
90
|
-
this.updated.forEach((identifier) => {
|
|
91
|
-
const consumer = this.consumers.get(identifier);
|
|
92
|
-
if (consumer) {
|
|
93
|
-
data.push(consumer);
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
this.updated.clear();
|
|
97
|
-
return data;
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
__name(_ConsumerRegistry, "ConsumerRegistry");
|
|
101
|
-
var ConsumerRegistry = _ConsumerRegistry;
|
|
102
|
-
|
|
103
|
-
// src/common/logging.ts
|
|
104
|
-
var import_winston = require("winston");
|
|
105
|
-
function getLogger() {
|
|
106
|
-
return (0, import_winston.createLogger)({
|
|
107
|
-
level: process.env.APITALLY_DEBUG ? "debug" : "warn",
|
|
108
|
-
format: import_winston.format.combine(import_winston.format.colorize(), import_winston.format.timestamp(), import_winston.format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`)),
|
|
109
|
-
transports: [
|
|
110
|
-
new import_winston.transports.Console()
|
|
111
|
-
]
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
__name(getLogger, "getLogger");
|
|
115
|
-
|
|
116
|
-
// src/common/paramValidation.ts
|
|
117
|
-
function isValidClientId(clientId) {
|
|
118
|
-
const regexExp = /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
119
|
-
return regexExp.test(clientId);
|
|
120
|
-
}
|
|
121
|
-
__name(isValidClientId, "isValidClientId");
|
|
122
|
-
function isValidEnv(env) {
|
|
123
|
-
const regexExp = /^[\w-]{1,32}$/;
|
|
124
|
-
return regexExp.test(env);
|
|
125
|
-
}
|
|
126
|
-
__name(isValidEnv, "isValidEnv");
|
|
127
|
-
|
|
128
|
-
// src/common/requestCounter.ts
|
|
129
|
-
var _RequestCounter = class _RequestCounter {
|
|
130
|
-
requestCounts;
|
|
131
|
-
requestSizeSums;
|
|
132
|
-
responseSizeSums;
|
|
133
|
-
responseTimes;
|
|
134
|
-
requestSizes;
|
|
135
|
-
responseSizes;
|
|
136
|
-
constructor() {
|
|
137
|
-
this.requestCounts = /* @__PURE__ */ new Map();
|
|
138
|
-
this.requestSizeSums = /* @__PURE__ */ new Map();
|
|
139
|
-
this.responseSizeSums = /* @__PURE__ */ new Map();
|
|
140
|
-
this.responseTimes = /* @__PURE__ */ new Map();
|
|
141
|
-
this.requestSizes = /* @__PURE__ */ new Map();
|
|
142
|
-
this.responseSizes = /* @__PURE__ */ new Map();
|
|
143
|
-
}
|
|
144
|
-
getKey(requestInfo) {
|
|
145
|
-
return [
|
|
146
|
-
requestInfo.consumer || "",
|
|
147
|
-
requestInfo.method.toUpperCase(),
|
|
148
|
-
requestInfo.path,
|
|
149
|
-
requestInfo.statusCode
|
|
150
|
-
].join("|");
|
|
151
|
-
}
|
|
152
|
-
addRequest(requestInfo) {
|
|
153
|
-
const key = this.getKey(requestInfo);
|
|
154
|
-
this.requestCounts.set(key, (this.requestCounts.get(key) || 0) + 1);
|
|
155
|
-
if (!this.responseTimes.has(key)) {
|
|
156
|
-
this.responseTimes.set(key, /* @__PURE__ */ new Map());
|
|
157
|
-
}
|
|
158
|
-
const responseTimeMap = this.responseTimes.get(key);
|
|
159
|
-
const responseTimeMsBin = Math.floor(requestInfo.responseTime / 10) * 10;
|
|
160
|
-
responseTimeMap.set(responseTimeMsBin, (responseTimeMap.get(responseTimeMsBin) || 0) + 1);
|
|
161
|
-
if (requestInfo.requestSize !== void 0) {
|
|
162
|
-
requestInfo.requestSize = Number(requestInfo.requestSize);
|
|
163
|
-
this.requestSizeSums.set(key, (this.requestSizeSums.get(key) || 0) + requestInfo.requestSize);
|
|
164
|
-
if (!this.requestSizes.has(key)) {
|
|
165
|
-
this.requestSizes.set(key, /* @__PURE__ */ new Map());
|
|
166
|
-
}
|
|
167
|
-
const requestSizeMap = this.requestSizes.get(key);
|
|
168
|
-
const requestSizeKbBin = Math.floor(requestInfo.requestSize / 1e3);
|
|
169
|
-
requestSizeMap.set(requestSizeKbBin, (requestSizeMap.get(requestSizeKbBin) || 0) + 1);
|
|
170
|
-
}
|
|
171
|
-
if (requestInfo.responseSize !== void 0) {
|
|
172
|
-
requestInfo.responseSize = Number(requestInfo.responseSize);
|
|
173
|
-
this.responseSizeSums.set(key, (this.responseSizeSums.get(key) || 0) + requestInfo.responseSize);
|
|
174
|
-
if (!this.responseSizes.has(key)) {
|
|
175
|
-
this.responseSizes.set(key, /* @__PURE__ */ new Map());
|
|
176
|
-
}
|
|
177
|
-
const responseSizeMap = this.responseSizes.get(key);
|
|
178
|
-
const responseSizeKbBin = Math.floor(requestInfo.responseSize / 1e3);
|
|
179
|
-
responseSizeMap.set(responseSizeKbBin, (responseSizeMap.get(responseSizeKbBin) || 0) + 1);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
getAndResetRequests() {
|
|
183
|
-
const data = [];
|
|
184
|
-
this.requestCounts.forEach((count, key) => {
|
|
185
|
-
const [consumer, method, path, statusCodeStr] = key.split("|");
|
|
186
|
-
const responseTimes = this.responseTimes.get(key) || /* @__PURE__ */ new Map();
|
|
187
|
-
const requestSizes = this.requestSizes.get(key) || /* @__PURE__ */ new Map();
|
|
188
|
-
const responseSizes = this.responseSizes.get(key) || /* @__PURE__ */ new Map();
|
|
189
|
-
data.push({
|
|
190
|
-
consumer: consumer || null,
|
|
191
|
-
method,
|
|
192
|
-
path,
|
|
193
|
-
status_code: parseInt(statusCodeStr),
|
|
194
|
-
request_count: count,
|
|
195
|
-
request_size_sum: this.requestSizeSums.get(key) || 0,
|
|
196
|
-
response_size_sum: this.responseSizeSums.get(key) || 0,
|
|
197
|
-
response_times: Object.fromEntries(responseTimes),
|
|
198
|
-
request_sizes: Object.fromEntries(requestSizes),
|
|
199
|
-
response_sizes: Object.fromEntries(responseSizes)
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
this.requestCounts.clear();
|
|
203
|
-
this.requestSizeSums.clear();
|
|
204
|
-
this.responseSizeSums.clear();
|
|
205
|
-
this.responseTimes.clear();
|
|
206
|
-
this.requestSizes.clear();
|
|
207
|
-
this.responseSizes.clear();
|
|
208
|
-
return data;
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
__name(_RequestCounter, "RequestCounter");
|
|
212
|
-
var RequestCounter = _RequestCounter;
|
|
213
|
-
|
|
214
|
-
// src/common/requestLogger.ts
|
|
215
|
-
var import_async_lock = __toESM(require("async-lock"), 1);
|
|
216
|
-
var import_node_buffer2 = require("buffer");
|
|
217
|
-
var import_node_crypto3 = require("crypto");
|
|
218
|
-
var import_node_fs2 = require("fs");
|
|
219
|
-
var import_node_os2 = require("os");
|
|
220
|
-
var import_node_path2 = require("path");
|
|
221
|
-
|
|
222
|
-
// src/common/sentry.ts
|
|
223
|
-
var sentry;
|
|
224
|
-
(async () => {
|
|
225
|
-
try {
|
|
226
|
-
sentry = await import("@sentry/node");
|
|
227
|
-
} catch (e) {
|
|
228
|
-
}
|
|
229
|
-
})();
|
|
230
|
-
function getSentryEventId() {
|
|
231
|
-
if (sentry && sentry.lastEventId) {
|
|
232
|
-
return sentry.lastEventId();
|
|
233
|
-
}
|
|
234
|
-
return void 0;
|
|
235
|
-
}
|
|
236
|
-
__name(getSentryEventId, "getSentryEventId");
|
|
237
|
-
|
|
238
|
-
// src/common/serverErrorCounter.ts
|
|
239
|
-
var import_node_crypto = require("crypto");
|
|
240
|
-
var MAX_MSG_LENGTH = 2048;
|
|
241
|
-
var MAX_STACKTRACE_LENGTH = 65536;
|
|
242
|
-
var _ServerErrorCounter = class _ServerErrorCounter {
|
|
243
|
-
errorCounts;
|
|
244
|
-
errorDetails;
|
|
245
|
-
sentryEventIds;
|
|
246
|
-
constructor() {
|
|
247
|
-
this.errorCounts = /* @__PURE__ */ new Map();
|
|
248
|
-
this.errorDetails = /* @__PURE__ */ new Map();
|
|
249
|
-
this.sentryEventIds = /* @__PURE__ */ new Map();
|
|
250
|
-
}
|
|
251
|
-
addServerError(serverError) {
|
|
252
|
-
const key = this.getKey(serverError);
|
|
253
|
-
if (!this.errorDetails.has(key)) {
|
|
254
|
-
this.errorDetails.set(key, serverError);
|
|
255
|
-
}
|
|
256
|
-
this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
|
|
257
|
-
const sentryEventId = getSentryEventId();
|
|
258
|
-
if (sentryEventId) {
|
|
259
|
-
this.sentryEventIds.set(key, sentryEventId);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
getAndResetServerErrors() {
|
|
263
|
-
const data = [];
|
|
264
|
-
this.errorCounts.forEach((count, key) => {
|
|
265
|
-
const serverError = this.errorDetails.get(key);
|
|
266
|
-
if (serverError) {
|
|
267
|
-
data.push({
|
|
268
|
-
consumer: serverError.consumer || null,
|
|
269
|
-
method: serverError.method,
|
|
270
|
-
path: serverError.path,
|
|
271
|
-
type: serverError.type,
|
|
272
|
-
msg: truncateExceptionMessage(serverError.msg),
|
|
273
|
-
traceback: truncateExceptionStackTrace(serverError.traceback),
|
|
274
|
-
sentry_event_id: this.sentryEventIds.get(key) || null,
|
|
275
|
-
error_count: count
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
this.errorCounts.clear();
|
|
280
|
-
this.errorDetails.clear();
|
|
281
|
-
this.sentryEventIds.clear();
|
|
282
|
-
return data;
|
|
283
|
-
}
|
|
284
|
-
getKey(serverError) {
|
|
285
|
-
const hashInput = [
|
|
286
|
-
serverError.consumer || "",
|
|
287
|
-
serverError.method.toUpperCase(),
|
|
288
|
-
serverError.path,
|
|
289
|
-
serverError.type,
|
|
290
|
-
serverError.msg.trim(),
|
|
291
|
-
serverError.traceback.trim()
|
|
292
|
-
].join("|");
|
|
293
|
-
return (0, import_node_crypto.createHash)("md5").update(hashInput).digest("hex");
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
__name(_ServerErrorCounter, "ServerErrorCounter");
|
|
297
|
-
var ServerErrorCounter = _ServerErrorCounter;
|
|
298
|
-
function truncateExceptionMessage(msg) {
|
|
299
|
-
if (msg.length <= MAX_MSG_LENGTH) {
|
|
300
|
-
return msg;
|
|
301
|
-
}
|
|
302
|
-
const suffix = "... (truncated)";
|
|
303
|
-
const cutoff = MAX_MSG_LENGTH - suffix.length;
|
|
304
|
-
return msg.substring(0, cutoff) + suffix;
|
|
305
|
-
}
|
|
306
|
-
__name(truncateExceptionMessage, "truncateExceptionMessage");
|
|
307
|
-
function truncateExceptionStackTrace(stack) {
|
|
308
|
-
const suffix = "... (truncated) ...";
|
|
309
|
-
const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
|
|
310
|
-
const lines = stack.trim().split("\n");
|
|
311
|
-
const truncatedLines = [];
|
|
312
|
-
let length = 0;
|
|
313
|
-
for (const line of lines) {
|
|
314
|
-
if (length + line.length + 1 > cutoff) {
|
|
315
|
-
truncatedLines.push(suffix);
|
|
316
|
-
break;
|
|
317
|
-
}
|
|
318
|
-
truncatedLines.push(line);
|
|
319
|
-
length += line.length + 1;
|
|
320
|
-
}
|
|
321
|
-
return truncatedLines.join("\n");
|
|
322
|
-
}
|
|
323
|
-
__name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
|
|
324
|
-
|
|
325
|
-
// src/common/tempGzipFile.ts
|
|
326
|
-
var import_node_buffer = require("buffer");
|
|
327
|
-
var import_node_crypto2 = require("crypto");
|
|
328
|
-
var import_node_fs = require("fs");
|
|
329
|
-
var import_promises = require("fs/promises");
|
|
330
|
-
var import_node_os = require("os");
|
|
331
|
-
var import_node_path = require("path");
|
|
332
|
-
var import_node_zlib = require("zlib");
|
|
333
|
-
var _TempGzipFile = class _TempGzipFile {
|
|
334
|
-
uuid;
|
|
335
|
-
filePath;
|
|
336
|
-
gzip;
|
|
337
|
-
writeStream;
|
|
338
|
-
readyPromise;
|
|
339
|
-
closedPromise;
|
|
340
|
-
constructor() {
|
|
341
|
-
this.uuid = (0, import_node_crypto2.randomUUID)();
|
|
342
|
-
this.filePath = (0, import_node_path.join)((0, import_node_os.tmpdir)(), `apitally-${this.uuid}.gz`);
|
|
343
|
-
this.writeStream = (0, import_node_fs.createWriteStream)(this.filePath);
|
|
344
|
-
this.readyPromise = new Promise((resolve, reject) => {
|
|
345
|
-
this.writeStream.once("ready", resolve);
|
|
346
|
-
this.writeStream.once("error", reject);
|
|
347
|
-
});
|
|
348
|
-
this.closedPromise = new Promise((resolve, reject) => {
|
|
349
|
-
this.writeStream.once("close", resolve);
|
|
350
|
-
this.writeStream.once("error", reject);
|
|
351
|
-
});
|
|
352
|
-
this.gzip = (0, import_node_zlib.createGzip)();
|
|
353
|
-
this.gzip.pipe(this.writeStream);
|
|
354
|
-
}
|
|
355
|
-
get size() {
|
|
356
|
-
return this.writeStream.bytesWritten;
|
|
357
|
-
}
|
|
358
|
-
async writeLine(data) {
|
|
359
|
-
await this.readyPromise;
|
|
360
|
-
return new Promise((resolve, reject) => {
|
|
361
|
-
this.gzip.write(import_node_buffer.Buffer.concat([
|
|
362
|
-
data,
|
|
363
|
-
import_node_buffer.Buffer.from("\n")
|
|
364
|
-
]), (error) => {
|
|
365
|
-
if (error) {
|
|
366
|
-
reject(error);
|
|
367
|
-
} else {
|
|
368
|
-
resolve();
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
async getContent() {
|
|
374
|
-
return new Promise((resolve, reject) => {
|
|
375
|
-
(0, import_node_fs.readFile)(this.filePath, (error, data) => {
|
|
376
|
-
if (error) {
|
|
377
|
-
reject(error);
|
|
378
|
-
} else {
|
|
379
|
-
resolve(data);
|
|
380
|
-
}
|
|
381
|
-
});
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
async close() {
|
|
385
|
-
await new Promise((resolve) => {
|
|
386
|
-
this.gzip.end(() => {
|
|
387
|
-
resolve();
|
|
388
|
-
});
|
|
389
|
-
});
|
|
390
|
-
await this.closedPromise;
|
|
391
|
-
}
|
|
392
|
-
async delete() {
|
|
393
|
-
await this.close();
|
|
394
|
-
await (0, import_promises.unlink)(this.filePath);
|
|
395
|
-
}
|
|
396
|
-
};
|
|
397
|
-
__name(_TempGzipFile, "TempGzipFile");
|
|
398
|
-
var TempGzipFile = _TempGzipFile;
|
|
399
|
-
|
|
400
|
-
// src/common/requestLogger.ts
|
|
401
|
-
var MAX_BODY_SIZE = 5e4;
|
|
402
|
-
var MAX_FILE_SIZE = 1e6;
|
|
403
|
-
var MAX_FILES = 50;
|
|
404
|
-
var MAX_PENDING_WRITES = 100;
|
|
405
|
-
var MAX_LOG_MSG_LENGTH = 2048;
|
|
406
|
-
var BODY_TOO_LARGE = import_node_buffer2.Buffer.from("<body too large>");
|
|
407
|
-
var BODY_MASKED = import_node_buffer2.Buffer.from("<masked>");
|
|
408
|
-
var MASKED = "******";
|
|
409
|
-
var ALLOWED_CONTENT_TYPES = [
|
|
410
|
-
"application/json",
|
|
411
|
-
"application/problem+json",
|
|
412
|
-
"application/vnd.api+json",
|
|
413
|
-
"text/plain",
|
|
414
|
-
"text/html"
|
|
415
|
-
];
|
|
416
|
-
var EXCLUDE_PATH_PATTERNS = [
|
|
417
|
-
/\/_?healthz?$/i,
|
|
418
|
-
/\/_?health[_-]?checks?$/i,
|
|
419
|
-
/\/_?heart[_-]?beats?$/i,
|
|
420
|
-
/\/ping$/i,
|
|
421
|
-
/\/ready$/i,
|
|
422
|
-
/\/live$/i
|
|
423
|
-
];
|
|
424
|
-
var EXCLUDE_USER_AGENT_PATTERNS = [
|
|
425
|
-
/health[-_ ]?check/i,
|
|
426
|
-
/microsoft-azure-application-lb/i,
|
|
427
|
-
/googlehc/i,
|
|
428
|
-
/kube-probe/i
|
|
429
|
-
];
|
|
430
|
-
var MASK_QUERY_PARAM_PATTERNS = [
|
|
431
|
-
/auth/i,
|
|
432
|
-
/api-?key/i,
|
|
433
|
-
/secret/i,
|
|
434
|
-
/token/i,
|
|
435
|
-
/password/i,
|
|
436
|
-
/pwd/i
|
|
437
|
-
];
|
|
438
|
-
var MASK_HEADER_PATTERNS = [
|
|
439
|
-
/auth/i,
|
|
440
|
-
/api-?key/i,
|
|
441
|
-
/secret/i,
|
|
442
|
-
/token/i,
|
|
443
|
-
/cookie/i
|
|
444
|
-
];
|
|
445
|
-
var MASK_BODY_FIELD_PATTERNS = [
|
|
446
|
-
/password/i,
|
|
447
|
-
/pwd/i,
|
|
448
|
-
/token/i,
|
|
449
|
-
/secret/i,
|
|
450
|
-
/auth/i,
|
|
451
|
-
/card[-_ ]?number/i,
|
|
452
|
-
/ccv/i,
|
|
453
|
-
/ssn/i
|
|
454
|
-
];
|
|
455
|
-
var DEFAULT_CONFIG = {
|
|
456
|
-
enabled: false,
|
|
457
|
-
logQueryParams: true,
|
|
458
|
-
logRequestHeaders: false,
|
|
459
|
-
logRequestBody: false,
|
|
460
|
-
logResponseHeaders: true,
|
|
461
|
-
logResponseBody: false,
|
|
462
|
-
logException: true,
|
|
463
|
-
captureLogs: false,
|
|
464
|
-
maskQueryParams: [],
|
|
465
|
-
maskHeaders: [],
|
|
466
|
-
maskBodyFields: [],
|
|
467
|
-
excludePaths: []
|
|
468
|
-
};
|
|
469
|
-
var _RequestLogger = class _RequestLogger {
|
|
470
|
-
config;
|
|
471
|
-
enabled;
|
|
472
|
-
suspendUntil = null;
|
|
473
|
-
pendingWrites = [];
|
|
474
|
-
currentFile = null;
|
|
475
|
-
files = [];
|
|
476
|
-
maintainIntervalId;
|
|
477
|
-
lock = new import_async_lock.default();
|
|
478
|
-
constructor(config) {
|
|
479
|
-
this.config = {
|
|
480
|
-
...DEFAULT_CONFIG,
|
|
481
|
-
...config
|
|
482
|
-
};
|
|
483
|
-
this.enabled = this.config.enabled && checkWritableFs();
|
|
484
|
-
if (this.enabled) {
|
|
485
|
-
this.maintainIntervalId = setInterval(() => {
|
|
486
|
-
this.maintain();
|
|
487
|
-
}, 1e3);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
get maxBodySize() {
|
|
491
|
-
return MAX_BODY_SIZE;
|
|
492
|
-
}
|
|
493
|
-
shouldExcludePath(urlPath) {
|
|
494
|
-
const patterns = [
|
|
495
|
-
...this.config.excludePaths,
|
|
496
|
-
...EXCLUDE_PATH_PATTERNS
|
|
497
|
-
];
|
|
498
|
-
return matchPatterns(urlPath, patterns);
|
|
499
|
-
}
|
|
500
|
-
shouldExcludeUserAgent(userAgent) {
|
|
501
|
-
return userAgent ? matchPatterns(userAgent, EXCLUDE_USER_AGENT_PATTERNS) : false;
|
|
502
|
-
}
|
|
503
|
-
shouldMaskQueryParam(name) {
|
|
504
|
-
const patterns = [
|
|
505
|
-
...this.config.maskQueryParams,
|
|
506
|
-
...MASK_QUERY_PARAM_PATTERNS
|
|
507
|
-
];
|
|
508
|
-
return matchPatterns(name, patterns);
|
|
509
|
-
}
|
|
510
|
-
shouldMaskHeader(name) {
|
|
511
|
-
const patterns = [
|
|
512
|
-
...this.config.maskHeaders,
|
|
513
|
-
...MASK_HEADER_PATTERNS
|
|
514
|
-
];
|
|
515
|
-
return matchPatterns(name, patterns);
|
|
516
|
-
}
|
|
517
|
-
shouldMaskBodyField(name) {
|
|
518
|
-
const patterns = [
|
|
519
|
-
...this.config.maskBodyFields,
|
|
520
|
-
...MASK_BODY_FIELD_PATTERNS
|
|
521
|
-
];
|
|
522
|
-
return matchPatterns(name, patterns);
|
|
523
|
-
}
|
|
524
|
-
hasSupportedContentType(headers) {
|
|
525
|
-
var _a2;
|
|
526
|
-
const contentType = (_a2 = headers.find(([k]) => k.toLowerCase() === "content-type")) == null ? void 0 : _a2[1];
|
|
527
|
-
return this.isSupportedContentType(contentType);
|
|
528
|
-
}
|
|
529
|
-
hasJsonContentType(headers) {
|
|
530
|
-
var _a2;
|
|
531
|
-
const contentType = (_a2 = headers.find(([k]) => k.toLowerCase() === "content-type")) == null ? void 0 : _a2[1];
|
|
532
|
-
return contentType ? /\bjson\b/i.test(contentType) : null;
|
|
533
|
-
}
|
|
534
|
-
isSupportedContentType(contentType) {
|
|
535
|
-
return typeof contentType === "string" && ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t));
|
|
536
|
-
}
|
|
537
|
-
maskQueryParams(search) {
|
|
538
|
-
const params = new URLSearchParams(search);
|
|
539
|
-
for (const [key] of params) {
|
|
540
|
-
if (this.shouldMaskQueryParam(key)) {
|
|
541
|
-
params.set(key, MASKED);
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
return params.toString();
|
|
545
|
-
}
|
|
546
|
-
maskHeaders(headers) {
|
|
547
|
-
return headers.map(([k, v]) => [
|
|
548
|
-
k,
|
|
549
|
-
this.shouldMaskHeader(k) ? MASKED : v
|
|
550
|
-
]);
|
|
551
|
-
}
|
|
552
|
-
maskBody(data) {
|
|
553
|
-
if (typeof data === "object" && data !== null && !Array.isArray(data)) {
|
|
554
|
-
const result = {};
|
|
555
|
-
for (const [key, value] of Object.entries(data)) {
|
|
556
|
-
if (typeof value === "string" && this.shouldMaskBodyField(key)) {
|
|
557
|
-
result[key] = MASKED;
|
|
558
|
-
} else {
|
|
559
|
-
result[key] = this.maskBody(value);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
return result;
|
|
563
|
-
}
|
|
564
|
-
if (Array.isArray(data)) {
|
|
565
|
-
return data.map((item) => this.maskBody(item));
|
|
566
|
-
}
|
|
567
|
-
return data;
|
|
568
|
-
}
|
|
569
|
-
applyMasking(item) {
|
|
570
|
-
if (this.config.maskRequestBodyCallback && item.request.body && item.request.body !== BODY_TOO_LARGE) {
|
|
571
|
-
try {
|
|
572
|
-
const maskedBody = this.config.maskRequestBodyCallback(item.request);
|
|
573
|
-
item.request.body = maskedBody ?? BODY_MASKED;
|
|
574
|
-
} catch {
|
|
575
|
-
item.request.body = void 0;
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
if (this.config.maskResponseBodyCallback && item.response.body && item.response.body !== BODY_TOO_LARGE) {
|
|
579
|
-
try {
|
|
580
|
-
const maskedBody = this.config.maskResponseBodyCallback(item.request, item.response);
|
|
581
|
-
item.response.body = maskedBody ?? BODY_MASKED;
|
|
582
|
-
} catch {
|
|
583
|
-
item.response.body = void 0;
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
if (item.request.body && item.request.body.length > MAX_BODY_SIZE) {
|
|
587
|
-
item.request.body = BODY_TOO_LARGE;
|
|
588
|
-
}
|
|
589
|
-
if (item.response.body && item.response.body.length > MAX_BODY_SIZE) {
|
|
590
|
-
item.response.body = BODY_TOO_LARGE;
|
|
591
|
-
}
|
|
592
|
-
for (const key of [
|
|
593
|
-
"request",
|
|
594
|
-
"response"
|
|
595
|
-
]) {
|
|
596
|
-
const bodyData = item[key].body;
|
|
597
|
-
if (!bodyData || bodyData === BODY_TOO_LARGE || bodyData === BODY_MASKED) {
|
|
598
|
-
continue;
|
|
599
|
-
}
|
|
600
|
-
const headers = item[key].headers;
|
|
601
|
-
const hasJsonContent = this.hasJsonContentType(headers);
|
|
602
|
-
if (hasJsonContent === null || hasJsonContent) {
|
|
603
|
-
try {
|
|
604
|
-
const parsedBody = JSON.parse(bodyData.toString());
|
|
605
|
-
const maskedBody = this.maskBody(parsedBody);
|
|
606
|
-
item[key].body = import_node_buffer2.Buffer.from(JSON.stringify(maskedBody));
|
|
607
|
-
} catch {
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
item.request.headers = this.config.logRequestHeaders ? this.maskHeaders(item.request.headers) : [];
|
|
612
|
-
item.response.headers = this.config.logResponseHeaders ? this.maskHeaders(item.response.headers) : [];
|
|
613
|
-
const url = new URL(item.request.url);
|
|
614
|
-
url.search = this.config.logQueryParams ? this.maskQueryParams(url.search) : "";
|
|
615
|
-
item.request.url = url.toString();
|
|
616
|
-
return item;
|
|
617
|
-
}
|
|
618
|
-
logRequest(request, response, error, logs) {
|
|
619
|
-
var _a2, _b, _c;
|
|
620
|
-
if (!this.enabled || this.suspendUntil !== null) return;
|
|
621
|
-
const url = new URL(request.url);
|
|
622
|
-
const path = request.path ?? url.pathname;
|
|
623
|
-
const userAgent = (_a2 = request.headers.find(([k]) => k.toLowerCase() === "user-agent")) == null ? void 0 : _a2[1];
|
|
624
|
-
if (this.shouldExcludePath(path) || this.shouldExcludeUserAgent(userAgent) || (((_c = (_b = this.config).excludeCallback) == null ? void 0 : _c.call(_b, request, response)) ?? false)) {
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
if (!this.config.logRequestBody || !this.hasSupportedContentType(request.headers)) {
|
|
628
|
-
request.body = void 0;
|
|
629
|
-
}
|
|
630
|
-
if (!this.config.logResponseBody || !this.hasSupportedContentType(response.headers)) {
|
|
631
|
-
response.body = void 0;
|
|
632
|
-
}
|
|
633
|
-
if (request.size !== void 0 && request.size < 0) {
|
|
634
|
-
request.size = void 0;
|
|
635
|
-
}
|
|
636
|
-
if (response.size !== void 0 && response.size < 0) {
|
|
637
|
-
response.size = void 0;
|
|
638
|
-
}
|
|
639
|
-
const item = {
|
|
640
|
-
uuid: (0, import_node_crypto3.randomUUID)(),
|
|
641
|
-
request,
|
|
642
|
-
response,
|
|
643
|
-
exception: error && this.config.logException ? {
|
|
644
|
-
type: error.name,
|
|
645
|
-
message: truncateExceptionMessage(error.message),
|
|
646
|
-
stacktrace: truncateExceptionStackTrace(error.stack || ""),
|
|
647
|
-
sentryEventId: getSentryEventId()
|
|
648
|
-
} : void 0
|
|
649
|
-
};
|
|
650
|
-
if (logs && logs.length > 0) {
|
|
651
|
-
item.logs = logs.map((log) => ({
|
|
652
|
-
timestamp: log.timestamp,
|
|
653
|
-
logger: log.logger,
|
|
654
|
-
level: log.level,
|
|
655
|
-
message: truncateLogMessage(log.message)
|
|
656
|
-
}));
|
|
657
|
-
}
|
|
658
|
-
this.pendingWrites.push(item);
|
|
659
|
-
if (this.pendingWrites.length > MAX_PENDING_WRITES) {
|
|
660
|
-
this.pendingWrites.shift();
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
async writeToFile() {
|
|
664
|
-
if (!this.enabled || this.pendingWrites.length === 0) {
|
|
665
|
-
return;
|
|
666
|
-
}
|
|
667
|
-
return this.lock.acquire("file", async () => {
|
|
668
|
-
if (!this.currentFile) {
|
|
669
|
-
this.currentFile = new TempGzipFile();
|
|
670
|
-
}
|
|
671
|
-
while (this.pendingWrites.length > 0) {
|
|
672
|
-
let item = this.pendingWrites.shift();
|
|
673
|
-
if (item) {
|
|
674
|
-
item = this.applyMasking(item);
|
|
675
|
-
const finalItem = {
|
|
676
|
-
uuid: item.uuid,
|
|
677
|
-
request: skipEmptyValues(item.request),
|
|
678
|
-
response: skipEmptyValues(item.response),
|
|
679
|
-
exception: item.exception,
|
|
680
|
-
logs: item.logs
|
|
681
|
-
};
|
|
682
|
-
[
|
|
683
|
-
finalItem.request.body,
|
|
684
|
-
finalItem.response.body
|
|
685
|
-
].forEach((body) => {
|
|
686
|
-
if (body) {
|
|
687
|
-
body.toJSON = function() {
|
|
688
|
-
return this.toString("base64");
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
});
|
|
692
|
-
await this.currentFile.writeLine(import_node_buffer2.Buffer.from(JSON.stringify(finalItem)));
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
});
|
|
696
|
-
}
|
|
697
|
-
getFile() {
|
|
698
|
-
return this.files.shift();
|
|
699
|
-
}
|
|
700
|
-
retryFileLater(file) {
|
|
701
|
-
this.files.unshift(file);
|
|
702
|
-
}
|
|
703
|
-
async rotateFile() {
|
|
704
|
-
return this.lock.acquire("file", async () => {
|
|
705
|
-
if (this.currentFile) {
|
|
706
|
-
await this.currentFile.close();
|
|
707
|
-
this.files.push(this.currentFile);
|
|
708
|
-
this.currentFile = null;
|
|
709
|
-
}
|
|
710
|
-
});
|
|
711
|
-
}
|
|
712
|
-
async maintain() {
|
|
713
|
-
await this.writeToFile();
|
|
714
|
-
if (this.currentFile && this.currentFile.size > MAX_FILE_SIZE) {
|
|
715
|
-
await this.rotateFile();
|
|
716
|
-
}
|
|
717
|
-
while (this.files.length > MAX_FILES) {
|
|
718
|
-
const file = this.files.shift();
|
|
719
|
-
file == null ? void 0 : file.delete();
|
|
720
|
-
}
|
|
721
|
-
if (this.suspendUntil !== null && this.suspendUntil < Date.now()) {
|
|
722
|
-
this.suspendUntil = null;
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
async clear() {
|
|
726
|
-
this.pendingWrites = [];
|
|
727
|
-
await this.rotateFile();
|
|
728
|
-
this.files.forEach((file) => {
|
|
729
|
-
file.delete();
|
|
730
|
-
});
|
|
731
|
-
this.files = [];
|
|
732
|
-
}
|
|
733
|
-
async close() {
|
|
734
|
-
this.enabled = false;
|
|
735
|
-
await this.clear();
|
|
736
|
-
if (this.maintainIntervalId) {
|
|
737
|
-
clearInterval(this.maintainIntervalId);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
};
|
|
741
|
-
__name(_RequestLogger, "RequestLogger");
|
|
742
|
-
var RequestLogger = _RequestLogger;
|
|
743
|
-
function convertHeaders(headers) {
|
|
744
|
-
if (!headers) {
|
|
745
|
-
return [];
|
|
746
|
-
}
|
|
747
|
-
if (headers instanceof Headers) {
|
|
748
|
-
return Array.from(headers.entries());
|
|
749
|
-
}
|
|
750
|
-
return Object.entries(headers).flatMap(([key, value]) => {
|
|
751
|
-
if (value === void 0) {
|
|
752
|
-
return [];
|
|
753
|
-
}
|
|
754
|
-
if (Array.isArray(value)) {
|
|
755
|
-
return value.map((v) => [
|
|
756
|
-
key,
|
|
757
|
-
v
|
|
758
|
-
]);
|
|
759
|
-
}
|
|
760
|
-
return [
|
|
761
|
-
[
|
|
762
|
-
key,
|
|
763
|
-
value.toString()
|
|
764
|
-
]
|
|
765
|
-
];
|
|
766
|
-
});
|
|
767
|
-
}
|
|
768
|
-
__name(convertHeaders, "convertHeaders");
|
|
769
|
-
function matchPatterns(value, patterns) {
|
|
770
|
-
return patterns.some((pattern) => {
|
|
771
|
-
return pattern.test(value);
|
|
772
|
-
});
|
|
773
|
-
}
|
|
774
|
-
__name(matchPatterns, "matchPatterns");
|
|
775
|
-
function skipEmptyValues(data) {
|
|
776
|
-
return Object.fromEntries(Object.entries(data).filter(([_, v]) => {
|
|
777
|
-
if (v == null || Number.isNaN(v)) return false;
|
|
778
|
-
if (Array.isArray(v) || import_node_buffer2.Buffer.isBuffer(v) || typeof v === "string") {
|
|
779
|
-
return v.length > 0;
|
|
780
|
-
}
|
|
781
|
-
return true;
|
|
782
|
-
}));
|
|
783
|
-
}
|
|
784
|
-
__name(skipEmptyValues, "skipEmptyValues");
|
|
785
|
-
function truncateLogMessage(msg) {
|
|
786
|
-
if (msg.length > MAX_LOG_MSG_LENGTH) {
|
|
787
|
-
const suffix = "... (truncated)";
|
|
788
|
-
return msg.slice(0, MAX_LOG_MSG_LENGTH - suffix.length) + suffix;
|
|
789
|
-
}
|
|
790
|
-
return msg;
|
|
791
|
-
}
|
|
792
|
-
__name(truncateLogMessage, "truncateLogMessage");
|
|
793
|
-
function checkWritableFs() {
|
|
794
|
-
try {
|
|
795
|
-
const testPath = (0, import_node_path2.join)((0, import_node_os2.tmpdir)(), `apitally-${(0, import_node_crypto3.randomUUID)()}`);
|
|
796
|
-
(0, import_node_fs2.writeFileSync)(testPath, "test");
|
|
797
|
-
(0, import_node_fs2.unlinkSync)(testPath);
|
|
798
|
-
return true;
|
|
799
|
-
} catch (error) {
|
|
800
|
-
return false;
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
__name(checkWritableFs, "checkWritableFs");
|
|
804
|
-
|
|
805
|
-
// src/common/validationErrorCounter.ts
|
|
806
|
-
var import_node_crypto4 = require("crypto");
|
|
807
|
-
var _ValidationErrorCounter = class _ValidationErrorCounter {
|
|
808
|
-
errorCounts;
|
|
809
|
-
errorDetails;
|
|
810
|
-
constructor() {
|
|
811
|
-
this.errorCounts = /* @__PURE__ */ new Map();
|
|
812
|
-
this.errorDetails = /* @__PURE__ */ new Map();
|
|
813
|
-
}
|
|
814
|
-
addValidationError(validationError) {
|
|
815
|
-
const key = this.getKey(validationError);
|
|
816
|
-
if (!this.errorDetails.has(key)) {
|
|
817
|
-
this.errorDetails.set(key, validationError);
|
|
818
|
-
}
|
|
819
|
-
this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
|
|
820
|
-
}
|
|
821
|
-
getAndResetValidationErrors() {
|
|
822
|
-
const data = [];
|
|
823
|
-
this.errorCounts.forEach((count, key) => {
|
|
824
|
-
const validationError = this.errorDetails.get(key);
|
|
825
|
-
if (validationError) {
|
|
826
|
-
data.push({
|
|
827
|
-
consumer: validationError.consumer || null,
|
|
828
|
-
method: validationError.method,
|
|
829
|
-
path: validationError.path,
|
|
830
|
-
loc: validationError.loc.split(".").filter(Boolean),
|
|
831
|
-
msg: validationError.msg,
|
|
832
|
-
type: validationError.type,
|
|
833
|
-
error_count: count
|
|
834
|
-
});
|
|
835
|
-
}
|
|
836
|
-
});
|
|
837
|
-
this.errorCounts.clear();
|
|
838
|
-
this.errorDetails.clear();
|
|
839
|
-
return data;
|
|
840
|
-
}
|
|
841
|
-
getKey(validationError) {
|
|
842
|
-
const hashInput = [
|
|
843
|
-
validationError.consumer || "",
|
|
844
|
-
validationError.method.toUpperCase(),
|
|
845
|
-
validationError.path,
|
|
846
|
-
validationError.loc.split(".").filter(Boolean),
|
|
847
|
-
validationError.msg.trim(),
|
|
848
|
-
validationError.type
|
|
849
|
-
].join("|");
|
|
850
|
-
return (0, import_node_crypto4.createHash)("md5").update(hashInput).digest("hex");
|
|
851
|
-
}
|
|
852
|
-
};
|
|
853
|
-
__name(_ValidationErrorCounter, "ValidationErrorCounter");
|
|
854
|
-
var ValidationErrorCounter = _ValidationErrorCounter;
|
|
855
|
-
|
|
856
|
-
// src/common/client.ts
|
|
857
|
-
var SYNC_INTERVAL = 6e4;
|
|
858
|
-
var INITIAL_SYNC_INTERVAL = 1e4;
|
|
859
|
-
var INITIAL_SYNC_INTERVAL_DURATION = 36e5;
|
|
860
|
-
var MAX_QUEUE_TIME = 36e5;
|
|
861
|
-
var _a;
|
|
862
|
-
var HTTPError = (_a = class extends Error {
|
|
863
|
-
response;
|
|
864
|
-
constructor(response) {
|
|
865
|
-
const reason = response.status ? `status code ${response.status}` : "an unknown error";
|
|
866
|
-
super(`Request failed with ${reason}`);
|
|
867
|
-
this.response = response;
|
|
868
|
-
}
|
|
869
|
-
}, __name(_a, "HTTPError"), _a);
|
|
870
|
-
var _ApitallyClient = class _ApitallyClient {
|
|
871
|
-
clientId;
|
|
872
|
-
env;
|
|
873
|
-
instanceUuid;
|
|
874
|
-
syncDataQueue;
|
|
875
|
-
syncIntervalId;
|
|
876
|
-
startupData;
|
|
877
|
-
startupDataSent = false;
|
|
878
|
-
enabled = true;
|
|
879
|
-
requestCounter;
|
|
880
|
-
requestLogger;
|
|
881
|
-
validationErrorCounter;
|
|
882
|
-
serverErrorCounter;
|
|
883
|
-
consumerRegistry;
|
|
884
|
-
logger;
|
|
885
|
-
constructor({ clientId, env = "dev", requestLogging, requestLoggingConfig, logger }) {
|
|
886
|
-
if (_ApitallyClient.instance) {
|
|
887
|
-
throw new Error("Apitally client is already initialized");
|
|
888
|
-
}
|
|
889
|
-
if (!isValidClientId(clientId)) {
|
|
890
|
-
throw new Error(`Invalid Apitally client ID '${clientId}' (expecting hexadecimal UUID format)`);
|
|
891
|
-
}
|
|
892
|
-
if (!isValidEnv(env)) {
|
|
893
|
-
throw new Error(`Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`);
|
|
894
|
-
}
|
|
895
|
-
if (requestLoggingConfig && !requestLogging) {
|
|
896
|
-
console.warn("requestLoggingConfig is deprecated, use requestLogging instead.");
|
|
897
|
-
}
|
|
898
|
-
_ApitallyClient.instance = this;
|
|
899
|
-
this.clientId = clientId;
|
|
900
|
-
this.env = env;
|
|
901
|
-
this.instanceUuid = (0, import_node_crypto5.randomUUID)();
|
|
902
|
-
this.syncDataQueue = [];
|
|
903
|
-
this.requestCounter = new RequestCounter();
|
|
904
|
-
this.requestLogger = new RequestLogger(requestLogging ?? requestLoggingConfig);
|
|
905
|
-
this.validationErrorCounter = new ValidationErrorCounter();
|
|
906
|
-
this.serverErrorCounter = new ServerErrorCounter();
|
|
907
|
-
this.consumerRegistry = new ConsumerRegistry();
|
|
908
|
-
this.logger = logger ?? getLogger();
|
|
909
|
-
this.startSync();
|
|
910
|
-
this.handleShutdown = this.handleShutdown.bind(this);
|
|
911
|
-
}
|
|
912
|
-
static getInstance() {
|
|
913
|
-
if (!_ApitallyClient.instance) {
|
|
914
|
-
throw new Error("Apitally client is not initialized");
|
|
915
|
-
}
|
|
916
|
-
return _ApitallyClient.instance;
|
|
917
|
-
}
|
|
918
|
-
isEnabled() {
|
|
919
|
-
return this.enabled;
|
|
920
|
-
}
|
|
921
|
-
static async shutdown() {
|
|
922
|
-
if (_ApitallyClient.instance) {
|
|
923
|
-
await _ApitallyClient.instance.handleShutdown();
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
async handleShutdown() {
|
|
927
|
-
this.enabled = false;
|
|
928
|
-
this.stopSync();
|
|
929
|
-
await this.sendSyncData();
|
|
930
|
-
await this.sendLogData();
|
|
931
|
-
await this.requestLogger.close();
|
|
932
|
-
_ApitallyClient.instance = void 0;
|
|
933
|
-
}
|
|
934
|
-
getHubUrlPrefix() {
|
|
935
|
-
const baseURL = process.env.APITALLY_HUB_BASE_URL || "https://hub.apitally.io";
|
|
936
|
-
const version = "v2";
|
|
937
|
-
return `${baseURL}/${version}/${this.clientId}/${this.env}/`;
|
|
938
|
-
}
|
|
939
|
-
async sendData(url, payload) {
|
|
940
|
-
const fetchWithRetry = (0, import_fetch_retry.default)(fetch, {
|
|
941
|
-
retries: 3,
|
|
942
|
-
retryDelay: 1e3,
|
|
943
|
-
retryOn: [
|
|
944
|
-
408,
|
|
945
|
-
429,
|
|
946
|
-
500,
|
|
947
|
-
502,
|
|
948
|
-
503,
|
|
949
|
-
504
|
|
950
|
-
]
|
|
951
|
-
});
|
|
952
|
-
const response = await fetchWithRetry(this.getHubUrlPrefix() + url, {
|
|
953
|
-
method: "POST",
|
|
954
|
-
body: JSON.stringify(payload),
|
|
955
|
-
headers: {
|
|
956
|
-
"Content-Type": "application/json"
|
|
957
|
-
}
|
|
958
|
-
});
|
|
959
|
-
if (!response.ok) {
|
|
960
|
-
throw new HTTPError(response);
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
startSync() {
|
|
964
|
-
this.sync();
|
|
965
|
-
this.syncIntervalId = setInterval(() => {
|
|
966
|
-
this.sync();
|
|
967
|
-
}, INITIAL_SYNC_INTERVAL);
|
|
968
|
-
setTimeout(() => {
|
|
969
|
-
clearInterval(this.syncIntervalId);
|
|
970
|
-
this.syncIntervalId = setInterval(() => {
|
|
971
|
-
this.sync();
|
|
972
|
-
}, SYNC_INTERVAL);
|
|
973
|
-
}, INITIAL_SYNC_INTERVAL_DURATION);
|
|
974
|
-
}
|
|
975
|
-
async sync() {
|
|
976
|
-
try {
|
|
977
|
-
const promises = [
|
|
978
|
-
this.sendSyncData(),
|
|
979
|
-
this.sendLogData()
|
|
980
|
-
];
|
|
981
|
-
if (!this.startupDataSent) {
|
|
982
|
-
promises.push(this.sendStartupData());
|
|
983
|
-
}
|
|
984
|
-
await Promise.all(promises);
|
|
985
|
-
} catch (error) {
|
|
986
|
-
this.logger.error("Error while syncing with Apitally Hub", {
|
|
987
|
-
error
|
|
988
|
-
});
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
stopSync() {
|
|
992
|
-
if (this.syncIntervalId) {
|
|
993
|
-
clearInterval(this.syncIntervalId);
|
|
994
|
-
this.syncIntervalId = void 0;
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
setStartupData(data) {
|
|
998
|
-
this.startupData = data;
|
|
999
|
-
this.startupDataSent = false;
|
|
1000
|
-
this.sendStartupData();
|
|
1001
|
-
}
|
|
1002
|
-
async sendStartupData() {
|
|
1003
|
-
if (this.startupData) {
|
|
1004
|
-
this.logger.debug("Sending startup data to Apitally Hub");
|
|
1005
|
-
const payload = {
|
|
1006
|
-
instance_uuid: this.instanceUuid,
|
|
1007
|
-
message_uuid: (0, import_node_crypto5.randomUUID)(),
|
|
1008
|
-
...this.startupData
|
|
1009
|
-
};
|
|
1010
|
-
try {
|
|
1011
|
-
await this.sendData("startup", payload);
|
|
1012
|
-
this.startupDataSent = true;
|
|
1013
|
-
} catch (error) {
|
|
1014
|
-
const handled = this.handleHubError(error);
|
|
1015
|
-
if (!handled) {
|
|
1016
|
-
this.logger.error(error.message);
|
|
1017
|
-
this.logger.debug("Error while sending startup data to Apitally Hub (will retry)", {
|
|
1018
|
-
error
|
|
1019
|
-
});
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
async sendSyncData() {
|
|
1025
|
-
this.logger.debug("Synchronizing data with Apitally Hub");
|
|
1026
|
-
const newPayload = {
|
|
1027
|
-
timestamp: Date.now() / 1e3,
|
|
1028
|
-
instance_uuid: this.instanceUuid,
|
|
1029
|
-
message_uuid: (0, import_node_crypto5.randomUUID)(),
|
|
1030
|
-
requests: this.requestCounter.getAndResetRequests(),
|
|
1031
|
-
validation_errors: this.validationErrorCounter.getAndResetValidationErrors(),
|
|
1032
|
-
server_errors: this.serverErrorCounter.getAndResetServerErrors(),
|
|
1033
|
-
consumers: this.consumerRegistry.getAndResetUpdatedConsumers()
|
|
1034
|
-
};
|
|
1035
|
-
this.syncDataQueue.push(newPayload);
|
|
1036
|
-
let i = 0;
|
|
1037
|
-
while (this.syncDataQueue.length > 0) {
|
|
1038
|
-
const payload = this.syncDataQueue.shift();
|
|
1039
|
-
if (payload) {
|
|
1040
|
-
try {
|
|
1041
|
-
if (Date.now() - payload.timestamp * 1e3 <= MAX_QUEUE_TIME) {
|
|
1042
|
-
if (i > 0) {
|
|
1043
|
-
await this.randomDelay();
|
|
1044
|
-
}
|
|
1045
|
-
await this.sendData("sync", payload);
|
|
1046
|
-
i += 1;
|
|
1047
|
-
}
|
|
1048
|
-
} catch (error) {
|
|
1049
|
-
const handled = this.handleHubError(error);
|
|
1050
|
-
if (!handled) {
|
|
1051
|
-
this.logger.debug("Error while synchronizing data with Apitally Hub (will retry)", {
|
|
1052
|
-
error
|
|
1053
|
-
});
|
|
1054
|
-
this.syncDataQueue.push(payload);
|
|
1055
|
-
break;
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
async sendLogData() {
|
|
1062
|
-
this.logger.debug("Sending request log data to Apitally Hub");
|
|
1063
|
-
await this.requestLogger.rotateFile();
|
|
1064
|
-
const fetchWithRetry = (0, import_fetch_retry.default)(fetch, {
|
|
1065
|
-
retries: 3,
|
|
1066
|
-
retryDelay: 1e3,
|
|
1067
|
-
retryOn: [
|
|
1068
|
-
408,
|
|
1069
|
-
429,
|
|
1070
|
-
500,
|
|
1071
|
-
502,
|
|
1072
|
-
503,
|
|
1073
|
-
504
|
|
1074
|
-
]
|
|
1075
|
-
});
|
|
1076
|
-
let i = 0;
|
|
1077
|
-
let logFile;
|
|
1078
|
-
while (logFile = this.requestLogger.getFile()) {
|
|
1079
|
-
if (i > 0) {
|
|
1080
|
-
await this.randomDelay();
|
|
1081
|
-
}
|
|
1082
|
-
try {
|
|
1083
|
-
const response = await fetchWithRetry(`${this.getHubUrlPrefix()}log?uuid=${logFile.uuid}`, {
|
|
1084
|
-
method: "POST",
|
|
1085
|
-
body: await logFile.getContent()
|
|
1086
|
-
});
|
|
1087
|
-
if (response.status === 402 && response.headers.has("Retry-After")) {
|
|
1088
|
-
const retryAfter = parseInt(response.headers.get("Retry-After") ?? "0");
|
|
1089
|
-
if (retryAfter > 0) {
|
|
1090
|
-
this.requestLogger.suspendUntil = Date.now() + retryAfter * 1e3;
|
|
1091
|
-
this.requestLogger.clear();
|
|
1092
|
-
return;
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
if (!response.ok) {
|
|
1096
|
-
throw new HTTPError(response);
|
|
1097
|
-
}
|
|
1098
|
-
logFile.delete();
|
|
1099
|
-
} catch (error) {
|
|
1100
|
-
this.requestLogger.retryFileLater(logFile);
|
|
1101
|
-
break;
|
|
1102
|
-
}
|
|
1103
|
-
i++;
|
|
1104
|
-
if (i >= 10) break;
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
handleHubError(error) {
|
|
1108
|
-
if (error instanceof HTTPError) {
|
|
1109
|
-
if (error.response.status === 404) {
|
|
1110
|
-
this.logger.error(`Invalid Apitally client ID: '${this.clientId}'`);
|
|
1111
|
-
this.enabled = false;
|
|
1112
|
-
this.stopSync();
|
|
1113
|
-
return true;
|
|
1114
|
-
}
|
|
1115
|
-
if (error.response.status === 422) {
|
|
1116
|
-
this.logger.error("Received validation error from Apitally Hub");
|
|
1117
|
-
return true;
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
return false;
|
|
1121
|
-
}
|
|
1122
|
-
async randomDelay() {
|
|
1123
|
-
const delay = 100 + Math.random() * 400;
|
|
1124
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1125
|
-
}
|
|
1126
|
-
};
|
|
1127
|
-
__name(_ApitallyClient, "ApitallyClient");
|
|
1128
|
-
__publicField(_ApitallyClient, "instance");
|
|
1129
|
-
var ApitallyClient = _ApitallyClient;
|
|
1130
|
-
|
|
1131
|
-
// src/common/headers.ts
|
|
1132
|
-
function parseContentLength(contentLength) {
|
|
1133
|
-
if (contentLength === void 0 || contentLength === null) {
|
|
1134
|
-
return void 0;
|
|
1135
|
-
}
|
|
1136
|
-
if (typeof contentLength === "number") {
|
|
1137
|
-
return contentLength;
|
|
1138
|
-
}
|
|
1139
|
-
if (typeof contentLength === "string") {
|
|
1140
|
-
const parsed = parseInt(contentLength);
|
|
1141
|
-
return isNaN(parsed) ? void 0 : parsed;
|
|
1142
|
-
}
|
|
1143
|
-
if (Array.isArray(contentLength)) {
|
|
1144
|
-
return parseContentLength(contentLength[0]);
|
|
1145
|
-
}
|
|
1146
|
-
return void 0;
|
|
1147
|
-
}
|
|
1148
|
-
__name(parseContentLength, "parseContentLength");
|
|
1149
|
-
|
|
1150
|
-
// src/common/response.ts
|
|
1151
|
-
async function measureResponseSize(response, tee = true) {
|
|
1152
|
-
const [newResponse1, newResponse2] = tee ? teeResponse(response) : [
|
|
1153
|
-
response,
|
|
1154
|
-
response
|
|
1155
|
-
];
|
|
1156
|
-
let size = 0;
|
|
1157
|
-
if (newResponse2.body) {
|
|
1158
|
-
let done = false;
|
|
1159
|
-
const reader = newResponse2.body.getReader();
|
|
1160
|
-
while (!done) {
|
|
1161
|
-
const result = await reader.read();
|
|
1162
|
-
done = result.done;
|
|
1163
|
-
if (!done && result.value) {
|
|
1164
|
-
size += result.value.byteLength;
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
return [
|
|
1169
|
-
size,
|
|
1170
|
-
newResponse1
|
|
1171
|
-
];
|
|
1172
|
-
}
|
|
1173
|
-
__name(measureResponseSize, "measureResponseSize");
|
|
1174
|
-
async function getResponseBody(response, tee = true) {
|
|
1175
|
-
const [newResponse1, newResponse2] = tee ? teeResponse(response) : [
|
|
1176
|
-
response,
|
|
1177
|
-
response
|
|
1178
|
-
];
|
|
1179
|
-
const responseBuffer = Buffer.from(await newResponse2.arrayBuffer());
|
|
1180
|
-
return [
|
|
1181
|
-
responseBuffer,
|
|
1182
|
-
newResponse1
|
|
1183
|
-
];
|
|
1184
|
-
}
|
|
1185
|
-
__name(getResponseBody, "getResponseBody");
|
|
1186
|
-
function teeResponse(response) {
|
|
1187
|
-
if (!response.body) {
|
|
1188
|
-
return [
|
|
1189
|
-
response,
|
|
1190
|
-
response
|
|
1191
|
-
];
|
|
1192
|
-
}
|
|
1193
|
-
const [stream1, stream2] = response.body.tee();
|
|
1194
|
-
const newResponse1 = new Response(stream1, {
|
|
1195
|
-
status: response.status,
|
|
1196
|
-
statusText: response.statusText,
|
|
1197
|
-
headers: response.headers
|
|
1198
|
-
});
|
|
1199
|
-
const newResponse2 = new Response(stream2, {
|
|
1200
|
-
status: response.status,
|
|
1201
|
-
statusText: response.statusText,
|
|
1202
|
-
headers: response.headers
|
|
1203
|
-
});
|
|
1204
|
-
return [
|
|
1205
|
-
newResponse1,
|
|
1206
|
-
newResponse2
|
|
1207
|
-
];
|
|
1208
|
-
}
|
|
1209
|
-
__name(teeResponse, "teeResponse");
|
|
1210
|
-
|
|
1211
|
-
// src/loggers/console.ts
|
|
1212
|
-
var import_node_util = require("util");
|
|
1213
|
-
var MAX_BUFFER_SIZE = 1e3;
|
|
1214
|
-
var isPatched = false;
|
|
1215
|
-
var globalLogsContext;
|
|
1216
|
-
function patchConsole(logsContext) {
|
|
1217
|
-
globalLogsContext = logsContext;
|
|
1218
|
-
if (isPatched) {
|
|
1219
|
-
return;
|
|
1220
|
-
}
|
|
1221
|
-
const logMethods = [
|
|
1222
|
-
"log",
|
|
1223
|
-
"warn",
|
|
1224
|
-
"error",
|
|
1225
|
-
"info",
|
|
1226
|
-
"debug"
|
|
1227
|
-
];
|
|
1228
|
-
logMethods.forEach((method) => {
|
|
1229
|
-
const originalMethod = console[method];
|
|
1230
|
-
console[method] = function(...args) {
|
|
1231
|
-
captureLog(method, args);
|
|
1232
|
-
return originalMethod.apply(console, args);
|
|
1233
|
-
};
|
|
1234
|
-
});
|
|
1235
|
-
isPatched = true;
|
|
1236
|
-
}
|
|
1237
|
-
__name(patchConsole, "patchConsole");
|
|
1238
|
-
function captureLog(level, args) {
|
|
1239
|
-
const logs = globalLogsContext == null ? void 0 : globalLogsContext.getStore();
|
|
1240
|
-
if (logs && logs.length < MAX_BUFFER_SIZE) {
|
|
1241
|
-
logs.push({
|
|
1242
|
-
timestamp: Date.now() / 1e3,
|
|
1243
|
-
logger: "console",
|
|
1244
|
-
level,
|
|
1245
|
-
message: (0, import_node_util.format)(...args)
|
|
1246
|
-
});
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
__name(captureLog, "captureLog");
|
|
1250
|
-
|
|
1251
|
-
// src/loggers/hapi.ts
|
|
1252
|
-
var import_node_util2 = require("util");
|
|
1253
|
-
|
|
1254
|
-
// src/loggers/utils.ts
|
|
1255
|
-
var import_node_util3 = require("util");
|
|
1256
|
-
function formatMessage(message, ...args) {
|
|
1257
|
-
return [
|
|
1258
|
-
message,
|
|
1259
|
-
...args
|
|
1260
|
-
].map(formatArg).filter((arg) => arg !== "").join("\n");
|
|
1261
|
-
}
|
|
1262
|
-
__name(formatMessage, "formatMessage");
|
|
1263
|
-
function removeKeys(obj, keys) {
|
|
1264
|
-
return Object.fromEntries(Object.entries(obj).filter(([key]) => !keys.includes(key)));
|
|
1265
|
-
}
|
|
1266
|
-
__name(removeKeys, "removeKeys");
|
|
1267
|
-
function formatArg(arg) {
|
|
1268
|
-
if (typeof arg === "string") {
|
|
1269
|
-
return arg.trim();
|
|
1270
|
-
}
|
|
1271
|
-
if (arg instanceof Error) {
|
|
1272
|
-
return (0, import_node_util3.format)(arg).trim();
|
|
1273
|
-
}
|
|
1274
|
-
if (arg === void 0 || arg === null || isEmptyObject(arg)) {
|
|
1275
|
-
return "";
|
|
1276
|
-
}
|
|
1277
|
-
try {
|
|
1278
|
-
return JSON.stringify(arg);
|
|
1279
|
-
} catch {
|
|
1280
|
-
return (0, import_node_util3.format)(arg).trim();
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1283
|
-
__name(formatArg, "formatArg");
|
|
1284
|
-
function isEmptyObject(obj) {
|
|
1285
|
-
return obj !== null && typeof obj === "object" && Object.getPrototypeOf(obj) === Object.prototype && Object.keys(obj).length === 0;
|
|
1286
|
-
}
|
|
1287
|
-
__name(isEmptyObject, "isEmptyObject");
|
|
1288
|
-
|
|
1289
|
-
// src/loggers/pino.ts
|
|
1290
|
-
var originalStreamSym = Symbol.for("apitally.originalStream");
|
|
1291
|
-
|
|
1292
|
-
// src/loggers/winston.ts
|
|
1293
|
-
var MAX_BUFFER_SIZE2 = 1e3;
|
|
1294
|
-
var isPatched2 = false;
|
|
1295
|
-
var globalLogsContext2;
|
|
1296
|
-
async function patchWinston(logsContext) {
|
|
1297
|
-
var _a2, _b;
|
|
1298
|
-
globalLogsContext2 = logsContext;
|
|
1299
|
-
if (isPatched2) {
|
|
1300
|
-
return;
|
|
1301
|
-
}
|
|
1302
|
-
try {
|
|
1303
|
-
const loggerModule = await import("winston/lib/winston/logger.js");
|
|
1304
|
-
if ((_b = (_a2 = loggerModule.default) == null ? void 0 : _a2.prototype) == null ? void 0 : _b.write) {
|
|
1305
|
-
const originalWrite = loggerModule.default.prototype.write;
|
|
1306
|
-
loggerModule.default.prototype.write = function(info) {
|
|
1307
|
-
captureLog2(info);
|
|
1308
|
-
return originalWrite.call(this, info);
|
|
1309
|
-
};
|
|
1310
|
-
}
|
|
1311
|
-
} catch {
|
|
1312
|
-
}
|
|
1313
|
-
isPatched2 = true;
|
|
1314
|
-
}
|
|
1315
|
-
__name(patchWinston, "patchWinston");
|
|
1316
|
-
function captureLog2(info) {
|
|
1317
|
-
const logs = globalLogsContext2 == null ? void 0 : globalLogsContext2.getStore();
|
|
1318
|
-
if (!logs || !info || logs.length >= MAX_BUFFER_SIZE2) {
|
|
1319
|
-
return;
|
|
1320
|
-
}
|
|
1321
|
-
try {
|
|
1322
|
-
const rest = removeKeys(info, [
|
|
1323
|
-
"timestamp",
|
|
1324
|
-
"level",
|
|
1325
|
-
"message",
|
|
1326
|
-
"splat"
|
|
1327
|
-
]);
|
|
1328
|
-
const formattedMessage = formatMessage(info.message, rest);
|
|
1329
|
-
if (formattedMessage) {
|
|
1330
|
-
logs.push({
|
|
1331
|
-
timestamp: parseTimestamp(info.timestamp),
|
|
1332
|
-
level: info.level || "info",
|
|
1333
|
-
message: formattedMessage.trim()
|
|
1334
|
-
});
|
|
1335
|
-
}
|
|
1336
|
-
} catch (e) {
|
|
1337
|
-
}
|
|
1338
|
-
}
|
|
1339
|
-
__name(captureLog2, "captureLog");
|
|
1340
|
-
function parseTimestamp(timestamp) {
|
|
1341
|
-
if (timestamp) {
|
|
1342
|
-
const ts = new Date(timestamp).getTime();
|
|
1343
|
-
if (!isNaN(ts)) {
|
|
1344
|
-
return ts / 1e3;
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
return Date.now() / 1e3;
|
|
1348
|
-
}
|
|
1349
|
-
__name(parseTimestamp, "parseTimestamp");
|
|
1350
|
-
|
|
1351
|
-
// src/common/packageVersions.ts
|
|
1352
|
-
var import_node_module = require("module");
|
|
1353
|
-
var import_meta = {};
|
|
1354
|
-
function getPackageVersion(name) {
|
|
1355
|
-
const packageJsonPath = `${name}/package.json`;
|
|
1356
|
-
try {
|
|
1357
|
-
return require(packageJsonPath).version || null;
|
|
1358
|
-
} catch (error) {
|
|
1359
|
-
try {
|
|
1360
|
-
const _require = (0, import_node_module.createRequire)(import_meta.url);
|
|
1361
|
-
return _require(packageJsonPath).version || null;
|
|
1362
|
-
} catch (error2) {
|
|
1363
|
-
return null;
|
|
1364
|
-
}
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
__name(getPackageVersion, "getPackageVersion");
|
|
1368
|
-
|
|
1369
|
-
// src/elysia/utils.ts
|
|
1370
|
-
function getAppInfo(app, appVersion) {
|
|
1371
|
-
const versions = [];
|
|
1372
|
-
if (process.versions.node) {
|
|
1373
|
-
versions.push([
|
|
1374
|
-
"nodejs",
|
|
1375
|
-
process.versions.node
|
|
1376
|
-
]);
|
|
1377
|
-
}
|
|
1378
|
-
if (process.versions.bun) {
|
|
1379
|
-
versions.push([
|
|
1380
|
-
"bun",
|
|
1381
|
-
process.versions.bun
|
|
1382
|
-
]);
|
|
1383
|
-
}
|
|
1384
|
-
const elysiaVersion = getPackageVersion("elysia");
|
|
1385
|
-
const apitallyVersion = getPackageVersion("../..");
|
|
1386
|
-
if (elysiaVersion) {
|
|
1387
|
-
versions.push([
|
|
1388
|
-
"elysia",
|
|
1389
|
-
elysiaVersion
|
|
1390
|
-
]);
|
|
1391
|
-
}
|
|
1392
|
-
if (apitallyVersion) {
|
|
1393
|
-
versions.push([
|
|
1394
|
-
"apitally",
|
|
1395
|
-
apitallyVersion
|
|
1396
|
-
]);
|
|
1397
|
-
}
|
|
1398
|
-
if (appVersion) {
|
|
1399
|
-
versions.push([
|
|
1400
|
-
"app",
|
|
1401
|
-
appVersion
|
|
1402
|
-
]);
|
|
1403
|
-
}
|
|
1404
|
-
return {
|
|
1405
|
-
paths: app.routes.map((route) => ({
|
|
1406
|
-
method: route.method.toUpperCase(),
|
|
1407
|
-
path: route.path
|
|
1408
|
-
})).filter((route) => route.method && route.path && ![
|
|
1409
|
-
"HEAD",
|
|
1410
|
-
"OPTIONS"
|
|
1411
|
-
].includes(route.method)),
|
|
1412
|
-
versions: Object.fromEntries(versions),
|
|
1413
|
-
client: "js:elysia"
|
|
1414
|
-
};
|
|
1415
|
-
}
|
|
1416
|
-
__name(getAppInfo, "getAppInfo");
|
|
1417
|
-
|
|
1418
|
-
// src/elysia/plugin.ts
|
|
1419
|
-
var START_TIME_SYMBOL = Symbol("apitally.startTime");
|
|
1420
|
-
var REQUEST_BODY_SYMBOL = Symbol("apitally.requestBody");
|
|
1421
|
-
var RESPONSE_SYMBOL = Symbol("apitally.response");
|
|
1422
|
-
var ERROR_SYMBOL = Symbol("apitally.error");
|
|
26
|
+
var import_node_async_hooks = require("node:async_hooks");
|
|
27
|
+
var import_node_perf_hooks = require("node:perf_hooks");
|
|
28
|
+
var import_client = require("../common/client.js");
|
|
29
|
+
var import_consumerRegistry = require("../common/consumerRegistry.js");
|
|
30
|
+
var import_headers = require("../common/headers.js");
|
|
31
|
+
var import_requestLogger = require("../common/requestLogger.js");
|
|
32
|
+
var import_response = require("../common/response.js");
|
|
33
|
+
var import_loggers = require("../loggers/index.js");
|
|
34
|
+
var import_utils = require("./utils.js");
|
|
35
|
+
const START_TIME_SYMBOL = Symbol("apitally.startTime");
|
|
36
|
+
const REQUEST_BODY_SYMBOL = Symbol("apitally.requestBody");
|
|
37
|
+
const RESPONSE_SYMBOL = Symbol("apitally.response");
|
|
38
|
+
const ERROR_SYMBOL = Symbol("apitally.error");
|
|
1423
39
|
function apitallyPlugin(config) {
|
|
1424
|
-
const client = new ApitallyClient(config);
|
|
40
|
+
const client = new import_client.ApitallyClient(config);
|
|
1425
41
|
const logsContext = new import_node_async_hooks.AsyncLocalStorage();
|
|
1426
42
|
if (client.requestLogger.enabled && client.requestLogger.config.captureLogs) {
|
|
1427
|
-
patchConsole(logsContext);
|
|
1428
|
-
patchWinston(logsContext);
|
|
43
|
+
(0, import_loggers.patchConsole)(logsContext);
|
|
44
|
+
(0, import_loggers.patchWinston)(logsContext);
|
|
1429
45
|
}
|
|
1430
46
|
return (app) => {
|
|
1431
47
|
const handler = app["~adapter"].handler;
|
|
1432
48
|
const originalMapResponse = handler.mapResponse;
|
|
1433
49
|
const originalMapCompactResponse = handler.mapCompactResponse;
|
|
1434
50
|
const originalMapEarlyResponse = handler.mapEarlyResponse;
|
|
1435
|
-
const captureResponse = /* @__PURE__ */ __name((
|
|
1436
|
-
|
|
1437
|
-
|
|
51
|
+
const captureResponse = /* @__PURE__ */ __name((originalResponse, mappedResponse, request) => {
|
|
52
|
+
var _a;
|
|
53
|
+
if (request instanceof Request && mappedResponse instanceof Response && !(RESPONSE_SYMBOL in request)) {
|
|
54
|
+
const [newResponse1, newResponse2] = ((_a = originalResponse == null ? void 0 : originalResponse.constructor) == null ? void 0 : _a.name) === "String" ? (0, import_response.teeResponseBlob)(mappedResponse, originalResponse) : (0, import_response.teeResponse)(mappedResponse);
|
|
1438
55
|
request[RESPONSE_SYMBOL] = newResponse2;
|
|
1439
56
|
return newResponse1;
|
|
1440
57
|
} else {
|
|
1441
|
-
return
|
|
58
|
+
return mappedResponse;
|
|
1442
59
|
}
|
|
1443
60
|
}, "captureResponse");
|
|
1444
61
|
handler.mapResponse = /* @__PURE__ */ __name(function wrappedMapResponse(response, set, request) {
|
|
1445
62
|
const mappedResponse = originalMapResponse(response, set, request);
|
|
1446
|
-
const newResponse = captureResponse(mappedResponse, request);
|
|
63
|
+
const newResponse = captureResponse(response, mappedResponse, request);
|
|
1447
64
|
return newResponse;
|
|
1448
65
|
}, "wrappedMapResponse");
|
|
1449
66
|
handler.mapCompactResponse = /* @__PURE__ */ __name(function wrappedMapCompactResponse(response, request) {
|
|
1450
67
|
const mappedResponse = originalMapCompactResponse(response, request);
|
|
1451
|
-
const newResponse = captureResponse(mappedResponse, request);
|
|
68
|
+
const newResponse = captureResponse(response, mappedResponse, request);
|
|
1452
69
|
return newResponse;
|
|
1453
70
|
}, "wrappedMapCompactResponse");
|
|
1454
71
|
handler.mapEarlyResponse = /* @__PURE__ */ __name(function wrappedMapEarlyResponse(response, set, request) {
|
|
1455
72
|
const mappedResponse = originalMapEarlyResponse(response, set, request);
|
|
1456
|
-
const newResponse = captureResponse(mappedResponse, request);
|
|
73
|
+
const newResponse = captureResponse(response, mappedResponse, request);
|
|
1457
74
|
return newResponse;
|
|
1458
75
|
}, "wrappedMapEarlyResponse");
|
|
1459
76
|
return app.decorate("apitally", {}).onStart(() => {
|
|
1460
|
-
const appInfo = getAppInfo(app, config.appVersion);
|
|
77
|
+
const appInfo = (0, import_utils.getAppInfo)(app, config.appVersion);
|
|
1461
78
|
client.setStartupData(appInfo);
|
|
79
|
+
client.startSync();
|
|
1462
80
|
}).onStop(async () => {
|
|
1463
81
|
await client.handleShutdown();
|
|
1464
82
|
}).onRequest(async ({ request }) => {
|
|
@@ -1469,7 +87,7 @@ function apitallyPlugin(config) {
|
|
|
1469
87
|
request[START_TIME_SYMBOL] = import_node_perf_hooks.performance.now();
|
|
1470
88
|
if (client.requestLogger.enabled && client.requestLogger.config.logRequestBody) {
|
|
1471
89
|
const contentType = request.headers.get("content-type");
|
|
1472
|
-
const requestSize = parseContentLength(request.headers.get("content-length")) ?? 0;
|
|
90
|
+
const requestSize = (0, import_headers.parseContentLength)(request.headers.get("content-length")) ?? 0;
|
|
1473
91
|
if (client.requestLogger.isSupportedContentType(contentType) && requestSize <= client.requestLogger.maxBodySize) {
|
|
1474
92
|
try {
|
|
1475
93
|
request[REQUEST_BODY_SYMBOL] = Buffer.from(await request.clone().arrayBuffer());
|
|
@@ -1484,7 +102,7 @@ function apitallyPlugin(config) {
|
|
|
1484
102
|
const startTime = request[START_TIME_SYMBOL];
|
|
1485
103
|
const responseTime = startTime ? import_node_perf_hooks.performance.now() - startTime : 0;
|
|
1486
104
|
const requestBody = request[REQUEST_BODY_SYMBOL];
|
|
1487
|
-
const requestSize = parseContentLength(request.headers.get("content-length")) ?? (requestBody == null ? void 0 : requestBody.length);
|
|
105
|
+
const requestSize = (0, import_headers.parseContentLength)(request.headers.get("content-length")) ?? (requestBody == null ? void 0 : requestBody.length);
|
|
1488
106
|
const error = request[ERROR_SYMBOL];
|
|
1489
107
|
let response = request[RESPONSE_SYMBOL];
|
|
1490
108
|
let responseBody;
|
|
@@ -1497,15 +115,15 @@ function apitallyPlugin(config) {
|
|
|
1497
115
|
}
|
|
1498
116
|
if (response instanceof Response) {
|
|
1499
117
|
if (client.requestLogger.enabled && client.requestLogger.config.logResponseBody && client.requestLogger.isSupportedContentType(response.headers.get("content-type"))) {
|
|
1500
|
-
responseBody = (await getResponseBody(response, false))[0];
|
|
118
|
+
responseBody = (await (0, import_response.getResponseBody)(response, false))[0];
|
|
1501
119
|
responseSize = responseBody.length;
|
|
1502
120
|
} else {
|
|
1503
|
-
responseSize = (await measureResponseSize(response, false))[0];
|
|
121
|
+
responseSize = (await (0, import_response.measureResponseSize)(response, false))[0];
|
|
1504
122
|
}
|
|
1505
123
|
}
|
|
1506
124
|
const statusCode = (response == null ? void 0 : response.status) ?? getStatusCode(set) ?? 200;
|
|
1507
125
|
const responseHeaders = (response == null ? void 0 : response.headers) ?? set.headers;
|
|
1508
|
-
const consumer = apitally.consumer ? consumerFromStringOrObject(apitally.consumer) : null;
|
|
126
|
+
const consumer = apitally.consumer ? (0, import_consumerRegistry.consumerFromStringOrObject)(apitally.consumer) : null;
|
|
1509
127
|
client.consumerRegistry.addOrUpdateConsumer(consumer);
|
|
1510
128
|
if (route) {
|
|
1511
129
|
client.requestCounter.addRequest({
|
|
@@ -1549,14 +167,14 @@ function apitallyPlugin(config) {
|
|
|
1549
167
|
method: request.method,
|
|
1550
168
|
path: route,
|
|
1551
169
|
url: request.url,
|
|
1552
|
-
headers: convertHeaders(Object.fromEntries(request.headers.entries())),
|
|
170
|
+
headers: (0, import_requestLogger.convertHeaders)(Object.fromEntries(request.headers.entries())),
|
|
1553
171
|
size: requestSize,
|
|
1554
172
|
consumer: consumer == null ? void 0 : consumer.identifier,
|
|
1555
173
|
body: requestBody
|
|
1556
174
|
}, {
|
|
1557
175
|
statusCode,
|
|
1558
176
|
responseTime: responseTime / 1e3,
|
|
1559
|
-
headers: convertHeaders(responseHeaders),
|
|
177
|
+
headers: (0, import_requestLogger.convertHeaders)(responseHeaders),
|
|
1560
178
|
size: responseSize,
|
|
1561
179
|
body: responseBody
|
|
1562
180
|
}, error, logs);
|