apitally 0.9.5 → 0.11.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 +1 -2
- package/dist/common/client.cjs +398 -12
- package/dist/common/client.cjs.map +1 -1
- package/dist/common/client.d.cts +8 -1
- package/dist/common/client.d.ts +8 -1
- package/dist/common/client.js +394 -8
- package/dist/common/client.js.map +1 -1
- package/dist/common/consumerRegistry.d.cts +4 -0
- package/dist/common/consumerRegistry.d.ts +4 -0
- package/dist/common/requestCounter.d.cts +4 -0
- package/dist/common/requestCounter.d.ts +4 -0
- package/dist/common/requestLogger.cjs +419 -0
- package/dist/common/requestLogger.cjs.map +1 -0
- package/dist/common/requestLogger.d.cts +63 -0
- package/dist/common/requestLogger.d.ts +63 -0
- package/dist/common/requestLogger.js +395 -0
- package/dist/common/requestLogger.js.map +1 -0
- package/dist/common/serverErrorCounter.d.cts +4 -0
- package/dist/common/serverErrorCounter.d.ts +4 -0
- package/dist/common/tempGzipFile.cjs +93 -0
- package/dist/common/tempGzipFile.cjs.map +1 -0
- package/dist/common/tempGzipFile.d.cts +17 -0
- package/dist/common/tempGzipFile.d.ts +17 -0
- package/dist/common/tempGzipFile.js +74 -0
- package/dist/common/tempGzipFile.js.map +1 -0
- package/dist/common/types.cjs.map +1 -1
- package/dist/common/types.d.cts +5 -0
- package/dist/common/types.d.ts +5 -0
- package/dist/common/validationErrorCounter.d.cts +4 -0
- package/dist/common/validationErrorCounter.d.ts +4 -0
- package/dist/express/index.cjs +500 -34
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.d.cts +4 -0
- package/dist/express/index.d.ts +4 -0
- package/dist/express/index.js +496 -30
- package/dist/express/index.js.map +1 -1
- package/dist/express/middleware.cjs +500 -34
- package/dist/express/middleware.cjs.map +1 -1
- package/dist/express/middleware.d.cts +4 -0
- package/dist/express/middleware.d.ts +4 -0
- package/dist/express/middleware.js +496 -30
- package/dist/express/middleware.js.map +1 -1
- package/dist/fastify/index.cjs +491 -27
- package/dist/fastify/index.cjs.map +1 -1
- package/dist/fastify/index.d.cts +4 -0
- package/dist/fastify/index.d.ts +4 -0
- package/dist/fastify/index.js +487 -23
- package/dist/fastify/index.js.map +1 -1
- package/dist/fastify/plugin.cjs +491 -27
- package/dist/fastify/plugin.cjs.map +1 -1
- package/dist/fastify/plugin.d.cts +4 -0
- package/dist/fastify/plugin.d.ts +4 -0
- package/dist/fastify/plugin.js +487 -23
- package/dist/fastify/plugin.js.map +1 -1
- package/dist/hono/index.cjs +460 -15
- package/dist/hono/index.cjs.map +1 -1
- package/dist/hono/index.d.cts +4 -0
- package/dist/hono/index.d.ts +4 -0
- package/dist/hono/index.js +456 -11
- package/dist/hono/index.js.map +1 -1
- package/dist/hono/middleware.cjs +460 -15
- package/dist/hono/middleware.cjs.map +1 -1
- package/dist/hono/middleware.d.cts +4 -0
- package/dist/hono/middleware.d.ts +4 -0
- package/dist/hono/middleware.js +456 -11
- package/dist/hono/middleware.js.map +1 -1
- package/dist/koa/index.cjs +475 -15
- package/dist/koa/index.cjs.map +1 -1
- package/dist/koa/index.d.cts +4 -0
- package/dist/koa/index.d.ts +4 -0
- package/dist/koa/index.js +471 -11
- package/dist/koa/index.js.map +1 -1
- package/dist/koa/middleware.cjs +475 -15
- package/dist/koa/middleware.cjs.map +1 -1
- package/dist/koa/middleware.d.cts +4 -0
- package/dist/koa/middleware.d.ts +4 -0
- package/dist/koa/middleware.js +471 -11
- package/dist/koa/middleware.js.map +1 -1
- package/dist/nestjs/index.cjs +536 -41
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.d.cts +10 -2
- package/dist/nestjs/index.d.ts +10 -2
- package/dist/nestjs/index.js +534 -37
- package/dist/nestjs/index.js.map +1 -1
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -93,9 +93,8 @@ const { useApitally } = require("apitally/nestjs");
|
|
|
93
93
|
const { AppModule } = require("./app.module");
|
|
94
94
|
|
|
95
95
|
const app = await NestFactory.create(AppModule);
|
|
96
|
-
const expressInstance = app.getHttpAdapter().getInstance();
|
|
97
96
|
|
|
98
|
-
useApitally(
|
|
97
|
+
useApitally(app, {
|
|
99
98
|
clientId: "your-client-id",
|
|
100
99
|
env: "dev", // or "prod" etc.
|
|
101
100
|
});
|
package/dist/common/client.cjs
CHANGED
|
@@ -36,7 +36,7 @@ __export(client_exports, {
|
|
|
36
36
|
ApitallyClient: () => ApitallyClient
|
|
37
37
|
});
|
|
38
38
|
module.exports = __toCommonJS(client_exports);
|
|
39
|
-
var
|
|
39
|
+
var import_crypto5 = require("crypto");
|
|
40
40
|
var import_fetch_retry = __toESM(require("fetch-retry"), 1);
|
|
41
41
|
|
|
42
42
|
// src/common/consumerRegistry.ts
|
|
@@ -191,8 +191,340 @@ var _RequestCounter = class _RequestCounter {
|
|
|
191
191
|
__name(_RequestCounter, "RequestCounter");
|
|
192
192
|
var RequestCounter = _RequestCounter;
|
|
193
193
|
|
|
194
|
-
// src/common/
|
|
194
|
+
// src/common/requestLogger.ts
|
|
195
|
+
var import_buffer2 = require("buffer");
|
|
196
|
+
var import_crypto2 = require("crypto");
|
|
197
|
+
var import_fs2 = require("fs");
|
|
198
|
+
var import_os2 = require("os");
|
|
199
|
+
var import_path2 = require("path");
|
|
200
|
+
|
|
201
|
+
// src/common/tempGzipFile.ts
|
|
202
|
+
var import_buffer = require("buffer");
|
|
195
203
|
var import_crypto = require("crypto");
|
|
204
|
+
var import_fs = require("fs");
|
|
205
|
+
var import_os = require("os");
|
|
206
|
+
var import_path = require("path");
|
|
207
|
+
var import_zlib = require("zlib");
|
|
208
|
+
var _TempGzipFile = class _TempGzipFile {
|
|
209
|
+
uuid;
|
|
210
|
+
filePath;
|
|
211
|
+
gzip;
|
|
212
|
+
writeStream;
|
|
213
|
+
readyPromise;
|
|
214
|
+
constructor() {
|
|
215
|
+
this.uuid = (0, import_crypto.randomUUID)();
|
|
216
|
+
this.filePath = (0, import_path.join)((0, import_os.tmpdir)(), `apitally-${this.uuid}.gz`);
|
|
217
|
+
this.writeStream = (0, import_fs.createWriteStream)(this.filePath);
|
|
218
|
+
this.readyPromise = new Promise((resolve, reject) => {
|
|
219
|
+
this.writeStream.once("ready", resolve);
|
|
220
|
+
this.writeStream.once("error", reject);
|
|
221
|
+
});
|
|
222
|
+
this.gzip = (0, import_zlib.createGzip)();
|
|
223
|
+
this.gzip.pipe(this.writeStream);
|
|
224
|
+
}
|
|
225
|
+
get size() {
|
|
226
|
+
return this.writeStream.bytesWritten;
|
|
227
|
+
}
|
|
228
|
+
async writeLine(data) {
|
|
229
|
+
await this.readyPromise;
|
|
230
|
+
return new Promise((resolve, reject) => {
|
|
231
|
+
this.gzip.write(import_buffer.Buffer.concat([
|
|
232
|
+
data,
|
|
233
|
+
import_buffer.Buffer.from("\n")
|
|
234
|
+
]), (error) => {
|
|
235
|
+
if (error) {
|
|
236
|
+
reject(error);
|
|
237
|
+
} else {
|
|
238
|
+
resolve();
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
async getContent() {
|
|
244
|
+
return new Promise((resolve, reject) => {
|
|
245
|
+
(0, import_fs.readFile)(this.filePath, (error, data) => {
|
|
246
|
+
if (error) {
|
|
247
|
+
reject(error);
|
|
248
|
+
} else {
|
|
249
|
+
resolve(data);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
async close() {
|
|
255
|
+
return new Promise((resolve) => {
|
|
256
|
+
this.gzip.end(() => {
|
|
257
|
+
resolve();
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
async delete() {
|
|
262
|
+
await this.close();
|
|
263
|
+
(0, import_fs.unlinkSync)(this.filePath);
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
__name(_TempGzipFile, "TempGzipFile");
|
|
267
|
+
var TempGzipFile = _TempGzipFile;
|
|
268
|
+
|
|
269
|
+
// src/common/requestLogger.ts
|
|
270
|
+
var MAX_BODY_SIZE = 5e4;
|
|
271
|
+
var MAX_FILE_SIZE = 1e6;
|
|
272
|
+
var MAX_FILES = 50;
|
|
273
|
+
var MAX_PENDING_WRITES = 100;
|
|
274
|
+
var BODY_TOO_LARGE = import_buffer2.Buffer.from("<body too large>");
|
|
275
|
+
var BODY_MASKED = import_buffer2.Buffer.from("<masked>");
|
|
276
|
+
var MASKED = "******";
|
|
277
|
+
var ALLOWED_CONTENT_TYPES = [
|
|
278
|
+
"application/json",
|
|
279
|
+
"text/plain"
|
|
280
|
+
];
|
|
281
|
+
var EXCLUDE_PATH_PATTERNS = [
|
|
282
|
+
/\/_?healthz?$/,
|
|
283
|
+
/\/_?health[_-]?checks?$/,
|
|
284
|
+
/\/_?heart[_-]?beats?$/,
|
|
285
|
+
/\/ping$/,
|
|
286
|
+
/\/ready$/,
|
|
287
|
+
/\/live$/
|
|
288
|
+
];
|
|
289
|
+
var MASK_QUERY_PARAM_PATTERNS = [
|
|
290
|
+
/auth/i,
|
|
291
|
+
/api-?key/i,
|
|
292
|
+
/secret/i,
|
|
293
|
+
/token/i,
|
|
294
|
+
/password/i,
|
|
295
|
+
/pwd/i
|
|
296
|
+
];
|
|
297
|
+
var MASK_HEADER_PATTERNS = [
|
|
298
|
+
/auth/i,
|
|
299
|
+
/api-?key/i,
|
|
300
|
+
/secret/i,
|
|
301
|
+
/token/i,
|
|
302
|
+
/cookie/i
|
|
303
|
+
];
|
|
304
|
+
var DEFAULT_CONFIG = {
|
|
305
|
+
enabled: false,
|
|
306
|
+
logQueryParams: true,
|
|
307
|
+
logRequestHeaders: false,
|
|
308
|
+
logRequestBody: false,
|
|
309
|
+
logResponseHeaders: true,
|
|
310
|
+
logResponseBody: false,
|
|
311
|
+
maskQueryParams: [],
|
|
312
|
+
maskHeaders: [],
|
|
313
|
+
excludePaths: []
|
|
314
|
+
};
|
|
315
|
+
var _RequestLogger = class _RequestLogger {
|
|
316
|
+
config;
|
|
317
|
+
enabled;
|
|
318
|
+
suspendUntil = null;
|
|
319
|
+
pendingWrites = [];
|
|
320
|
+
currentFile = null;
|
|
321
|
+
files = [];
|
|
322
|
+
maintainIntervalId;
|
|
323
|
+
constructor(config) {
|
|
324
|
+
this.config = {
|
|
325
|
+
...DEFAULT_CONFIG,
|
|
326
|
+
...config
|
|
327
|
+
};
|
|
328
|
+
this.enabled = this.config.enabled && checkWritableFs();
|
|
329
|
+
if (this.enabled) {
|
|
330
|
+
this.maintainIntervalId = setInterval(() => {
|
|
331
|
+
this.maintain();
|
|
332
|
+
}, 1e3);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
shouldExcludePath(urlPath) {
|
|
336
|
+
const patterns = [
|
|
337
|
+
...this.config.excludePaths,
|
|
338
|
+
...EXCLUDE_PATH_PATTERNS
|
|
339
|
+
];
|
|
340
|
+
return matchPatterns(urlPath, patterns);
|
|
341
|
+
}
|
|
342
|
+
shouldMaskQueryParam(name) {
|
|
343
|
+
const patterns = [
|
|
344
|
+
...this.config.maskQueryParams,
|
|
345
|
+
...MASK_QUERY_PARAM_PATTERNS
|
|
346
|
+
];
|
|
347
|
+
return matchPatterns(name, patterns);
|
|
348
|
+
}
|
|
349
|
+
shouldMaskHeader(name) {
|
|
350
|
+
const patterns = [
|
|
351
|
+
...this.config.maskHeaders,
|
|
352
|
+
...MASK_HEADER_PATTERNS
|
|
353
|
+
];
|
|
354
|
+
return matchPatterns(name, patterns);
|
|
355
|
+
}
|
|
356
|
+
hasSupportedContentType(headers) {
|
|
357
|
+
var _a2;
|
|
358
|
+
const contentType = (_a2 = headers.find(([k]) => k.toLowerCase() === "content-type")) == null ? void 0 : _a2[1];
|
|
359
|
+
return contentType !== void 0 && ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t));
|
|
360
|
+
}
|
|
361
|
+
maskQueryParams(search) {
|
|
362
|
+
const params = new URLSearchParams(search);
|
|
363
|
+
for (const [key] of params) {
|
|
364
|
+
if (this.shouldMaskQueryParam(key)) {
|
|
365
|
+
params.set(key, MASKED);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return params.toString();
|
|
369
|
+
}
|
|
370
|
+
maskHeaders(headers) {
|
|
371
|
+
return headers.map(([k, v]) => [
|
|
372
|
+
k,
|
|
373
|
+
this.shouldMaskHeader(k) ? MASKED : v
|
|
374
|
+
]);
|
|
375
|
+
}
|
|
376
|
+
logRequest(request, response) {
|
|
377
|
+
var _a2, _b;
|
|
378
|
+
if (!this.enabled || this.suspendUntil !== null) return;
|
|
379
|
+
const url = new URL(request.url);
|
|
380
|
+
const path = request.path ?? url.pathname;
|
|
381
|
+
if (this.shouldExcludePath(path) || (((_b = (_a2 = this.config).excludeCallback) == null ? void 0 : _b.call(_a2, request, response)) ?? false)) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
url.search = this.config.logQueryParams ? this.maskQueryParams(url.search) : "";
|
|
385
|
+
request.url = url.toString();
|
|
386
|
+
request.headers = this.config.logRequestHeaders ? this.maskHeaders(request.headers) : [];
|
|
387
|
+
response.headers = this.config.logResponseHeaders ? this.maskHeaders(response.headers) : [];
|
|
388
|
+
if (!this.config.logRequestBody || !this.hasSupportedContentType(request.headers)) {
|
|
389
|
+
request.body = void 0;
|
|
390
|
+
} else if (request.body) {
|
|
391
|
+
if (request.body.length > MAX_BODY_SIZE) {
|
|
392
|
+
request.body = BODY_TOO_LARGE;
|
|
393
|
+
} else if (this.config.maskRequestBodyCallback) {
|
|
394
|
+
try {
|
|
395
|
+
request.body = this.config.maskRequestBodyCallback(request) ?? BODY_MASKED;
|
|
396
|
+
if (request.body.length > MAX_BODY_SIZE) {
|
|
397
|
+
request.body = BODY_TOO_LARGE;
|
|
398
|
+
}
|
|
399
|
+
} catch {
|
|
400
|
+
request.body = void 0;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (!this.config.logResponseBody || !this.hasSupportedContentType(response.headers)) {
|
|
405
|
+
response.body = void 0;
|
|
406
|
+
} else if (response.body) {
|
|
407
|
+
if (response.body.length > MAX_BODY_SIZE) {
|
|
408
|
+
response.body = BODY_TOO_LARGE;
|
|
409
|
+
} else if (this.config.maskResponseBodyCallback) {
|
|
410
|
+
try {
|
|
411
|
+
response.body = this.config.maskResponseBodyCallback(request, response) ?? BODY_MASKED;
|
|
412
|
+
if (response.body.length > MAX_BODY_SIZE) {
|
|
413
|
+
response.body = BODY_TOO_LARGE;
|
|
414
|
+
}
|
|
415
|
+
} catch {
|
|
416
|
+
response.body = void 0;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
const item = {
|
|
421
|
+
uuid: (0, import_crypto2.randomUUID)(),
|
|
422
|
+
request: skipEmptyValues(request),
|
|
423
|
+
response: skipEmptyValues(response)
|
|
424
|
+
};
|
|
425
|
+
[
|
|
426
|
+
item.request.body,
|
|
427
|
+
item.response.body
|
|
428
|
+
].forEach((body) => {
|
|
429
|
+
if (body) {
|
|
430
|
+
body.toJSON = function() {
|
|
431
|
+
return this.toString("base64");
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
this.pendingWrites.push(JSON.stringify(item));
|
|
436
|
+
if (this.pendingWrites.length > MAX_PENDING_WRITES) {
|
|
437
|
+
this.pendingWrites.shift();
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
async writeToFile() {
|
|
441
|
+
if (!this.enabled || this.pendingWrites.length === 0) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
if (!this.currentFile) {
|
|
445
|
+
this.currentFile = new TempGzipFile();
|
|
446
|
+
}
|
|
447
|
+
while (this.pendingWrites.length > 0) {
|
|
448
|
+
const item = this.pendingWrites.shift();
|
|
449
|
+
if (item) {
|
|
450
|
+
await this.currentFile.writeLine(import_buffer2.Buffer.from(item));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
getFile() {
|
|
455
|
+
return this.files.shift();
|
|
456
|
+
}
|
|
457
|
+
retryFileLater(file) {
|
|
458
|
+
this.files.unshift(file);
|
|
459
|
+
}
|
|
460
|
+
async rotateFile() {
|
|
461
|
+
if (this.currentFile) {
|
|
462
|
+
await this.currentFile.close();
|
|
463
|
+
this.files.push(this.currentFile);
|
|
464
|
+
this.currentFile = null;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
async maintain() {
|
|
468
|
+
await this.writeToFile();
|
|
469
|
+
if (this.currentFile && this.currentFile.size > MAX_FILE_SIZE) {
|
|
470
|
+
await this.rotateFile();
|
|
471
|
+
}
|
|
472
|
+
while (this.files.length > MAX_FILES) {
|
|
473
|
+
const file = this.files.shift();
|
|
474
|
+
file == null ? void 0 : file.delete();
|
|
475
|
+
}
|
|
476
|
+
if (this.suspendUntil !== null && this.suspendUntil < Date.now()) {
|
|
477
|
+
this.suspendUntil = null;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
async clear() {
|
|
481
|
+
this.pendingWrites = [];
|
|
482
|
+
await this.rotateFile();
|
|
483
|
+
this.files.forEach((file) => {
|
|
484
|
+
file.delete();
|
|
485
|
+
});
|
|
486
|
+
this.files = [];
|
|
487
|
+
}
|
|
488
|
+
async close() {
|
|
489
|
+
this.enabled = false;
|
|
490
|
+
await this.clear();
|
|
491
|
+
if (this.maintainIntervalId) {
|
|
492
|
+
clearInterval(this.maintainIntervalId);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
__name(_RequestLogger, "RequestLogger");
|
|
497
|
+
var RequestLogger = _RequestLogger;
|
|
498
|
+
function matchPatterns(value, patterns) {
|
|
499
|
+
return patterns.some((pattern) => {
|
|
500
|
+
return pattern.test(value);
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
__name(matchPatterns, "matchPatterns");
|
|
504
|
+
function skipEmptyValues(data) {
|
|
505
|
+
return Object.fromEntries(Object.entries(data).filter(([_, v]) => {
|
|
506
|
+
if (v == null || Number.isNaN(v)) return false;
|
|
507
|
+
if (Array.isArray(v) || import_buffer2.Buffer.isBuffer(v) || typeof v === "string") {
|
|
508
|
+
return v.length > 0;
|
|
509
|
+
}
|
|
510
|
+
return true;
|
|
511
|
+
}));
|
|
512
|
+
}
|
|
513
|
+
__name(skipEmptyValues, "skipEmptyValues");
|
|
514
|
+
function checkWritableFs() {
|
|
515
|
+
try {
|
|
516
|
+
const testPath = (0, import_path2.join)((0, import_os2.tmpdir)(), `apitally-${(0, import_crypto2.randomUUID)()}`);
|
|
517
|
+
(0, import_fs2.writeFileSync)(testPath, "test");
|
|
518
|
+
(0, import_fs2.unlinkSync)(testPath);
|
|
519
|
+
return true;
|
|
520
|
+
} catch (error) {
|
|
521
|
+
return false;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
__name(checkWritableFs, "checkWritableFs");
|
|
525
|
+
|
|
526
|
+
// src/common/serverErrorCounter.ts
|
|
527
|
+
var import_crypto3 = require("crypto");
|
|
196
528
|
var MAX_MSG_LENGTH = 2048;
|
|
197
529
|
var MAX_STACKTRACE_LENGTH = 65536;
|
|
198
530
|
var _ServerErrorCounter = class _ServerErrorCounter {
|
|
@@ -244,7 +576,7 @@ var _ServerErrorCounter = class _ServerErrorCounter {
|
|
|
244
576
|
serverError.msg.trim(),
|
|
245
577
|
serverError.traceback.trim()
|
|
246
578
|
].join("|");
|
|
247
|
-
return (0,
|
|
579
|
+
return (0, import_crypto3.createHash)("md5").update(hashInput).digest("hex");
|
|
248
580
|
}
|
|
249
581
|
getTruncatedMessage(msg) {
|
|
250
582
|
msg = msg.trim();
|
|
@@ -290,7 +622,7 @@ __name(_ServerErrorCounter, "ServerErrorCounter");
|
|
|
290
622
|
var ServerErrorCounter = _ServerErrorCounter;
|
|
291
623
|
|
|
292
624
|
// src/common/validationErrorCounter.ts
|
|
293
|
-
var
|
|
625
|
+
var import_crypto4 = require("crypto");
|
|
294
626
|
var _ValidationErrorCounter = class _ValidationErrorCounter {
|
|
295
627
|
errorCounts;
|
|
296
628
|
errorDetails;
|
|
@@ -334,7 +666,7 @@ var _ValidationErrorCounter = class _ValidationErrorCounter {
|
|
|
334
666
|
validationError.msg.trim(),
|
|
335
667
|
validationError.type
|
|
336
668
|
].join("|");
|
|
337
|
-
return (0,
|
|
669
|
+
return (0, import_crypto4.createHash)("md5").update(hashInput).digest("hex");
|
|
338
670
|
}
|
|
339
671
|
};
|
|
340
672
|
__name(_ValidationErrorCounter, "ValidationErrorCounter");
|
|
@@ -363,11 +695,12 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
363
695
|
startupData;
|
|
364
696
|
startupDataSent = false;
|
|
365
697
|
requestCounter;
|
|
698
|
+
requestLogger;
|
|
366
699
|
validationErrorCounter;
|
|
367
700
|
serverErrorCounter;
|
|
368
701
|
consumerRegistry;
|
|
369
702
|
logger;
|
|
370
|
-
constructor({ clientId, env = "dev", logger }) {
|
|
703
|
+
constructor({ clientId, env = "dev", requestLoggingConfig, logger }) {
|
|
371
704
|
if (_ApitallyClient.instance) {
|
|
372
705
|
throw new Error("Apitally client is already initialized");
|
|
373
706
|
}
|
|
@@ -380,9 +713,10 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
380
713
|
_ApitallyClient.instance = this;
|
|
381
714
|
this.clientId = clientId;
|
|
382
715
|
this.env = env;
|
|
383
|
-
this.instanceUuid = (0,
|
|
716
|
+
this.instanceUuid = (0, import_crypto5.randomUUID)();
|
|
384
717
|
this.syncDataQueue = [];
|
|
385
718
|
this.requestCounter = new RequestCounter();
|
|
719
|
+
this.requestLogger = new RequestLogger(requestLoggingConfig);
|
|
386
720
|
this.validationErrorCounter = new ValidationErrorCounter();
|
|
387
721
|
this.serverErrorCounter = new ServerErrorCounter();
|
|
388
722
|
this.consumerRegistry = new ConsumerRegistry();
|
|
@@ -404,6 +738,8 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
404
738
|
async handleShutdown() {
|
|
405
739
|
this.stopSync();
|
|
406
740
|
await this.sendSyncData();
|
|
741
|
+
await this.sendLogData();
|
|
742
|
+
await this.requestLogger.close();
|
|
407
743
|
_ApitallyClient.instance = void 0;
|
|
408
744
|
}
|
|
409
745
|
getHubUrlPrefix() {
|
|
@@ -450,7 +786,8 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
450
786
|
async sync() {
|
|
451
787
|
try {
|
|
452
788
|
const promises = [
|
|
453
|
-
this.sendSyncData()
|
|
789
|
+
this.sendSyncData(),
|
|
790
|
+
this.sendLogData()
|
|
454
791
|
];
|
|
455
792
|
if (!this.startupDataSent) {
|
|
456
793
|
promises.push(this.sendStartupData());
|
|
@@ -478,7 +815,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
478
815
|
this.logger.debug("Sending startup data to Apitally Hub");
|
|
479
816
|
const payload = {
|
|
480
817
|
instance_uuid: this.instanceUuid,
|
|
481
|
-
message_uuid: (0,
|
|
818
|
+
message_uuid: (0, import_crypto5.randomUUID)(),
|
|
482
819
|
...this.startupData
|
|
483
820
|
};
|
|
484
821
|
try {
|
|
@@ -500,7 +837,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
500
837
|
const newPayload = {
|
|
501
838
|
time_offset: 0,
|
|
502
839
|
instance_uuid: this.instanceUuid,
|
|
503
|
-
message_uuid: (0,
|
|
840
|
+
message_uuid: (0, import_crypto5.randomUUID)(),
|
|
504
841
|
requests: this.requestCounter.getAndResetRequests(),
|
|
505
842
|
validation_errors: this.validationErrorCounter.getAndResetValidationErrors(),
|
|
506
843
|
server_errors: this.serverErrorCounter.getAndResetServerErrors(),
|
|
@@ -519,8 +856,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
519
856
|
const timeOffset = Date.now() - time;
|
|
520
857
|
if (timeOffset <= MAX_QUEUE_TIME) {
|
|
521
858
|
if (i > 0) {
|
|
522
|
-
|
|
523
|
-
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
859
|
+
await this.randomDelay();
|
|
524
860
|
}
|
|
525
861
|
payload.time_offset = timeOffset / 1e3;
|
|
526
862
|
await this.sendData("sync", payload);
|
|
@@ -539,6 +875,52 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
539
875
|
}
|
|
540
876
|
}
|
|
541
877
|
}
|
|
878
|
+
async sendLogData() {
|
|
879
|
+
this.logger.debug("Sending request log data to Apitally Hub");
|
|
880
|
+
await this.requestLogger.rotateFile();
|
|
881
|
+
const fetchWithRetry = (0, import_fetch_retry.default)(fetch, {
|
|
882
|
+
retries: 3,
|
|
883
|
+
retryDelay: 1e3,
|
|
884
|
+
retryOn: [
|
|
885
|
+
408,
|
|
886
|
+
429,
|
|
887
|
+
500,
|
|
888
|
+
502,
|
|
889
|
+
503,
|
|
890
|
+
504
|
|
891
|
+
]
|
|
892
|
+
});
|
|
893
|
+
let i = 0;
|
|
894
|
+
let logFile;
|
|
895
|
+
while (logFile = this.requestLogger.getFile()) {
|
|
896
|
+
if (i > 0) {
|
|
897
|
+
await this.randomDelay();
|
|
898
|
+
}
|
|
899
|
+
try {
|
|
900
|
+
const response = await fetchWithRetry(`${this.getHubUrlPrefix()}log?uuid=${logFile.uuid}`, {
|
|
901
|
+
method: "POST",
|
|
902
|
+
body: await logFile.getContent()
|
|
903
|
+
});
|
|
904
|
+
if (response.status === 402 && response.headers.has("Retry-After")) {
|
|
905
|
+
const retryAfter = parseInt(response.headers.get("Retry-After") ?? "0");
|
|
906
|
+
if (retryAfter > 0) {
|
|
907
|
+
this.requestLogger.suspendUntil = Date.now() + retryAfter * 1e3;
|
|
908
|
+
this.requestLogger.clear();
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
if (!response.ok) {
|
|
913
|
+
throw new HTTPError(response);
|
|
914
|
+
}
|
|
915
|
+
logFile.delete();
|
|
916
|
+
} catch (error) {
|
|
917
|
+
this.requestLogger.retryFileLater(logFile);
|
|
918
|
+
break;
|
|
919
|
+
}
|
|
920
|
+
i++;
|
|
921
|
+
if (i >= 10) break;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
542
924
|
handleHubError(error) {
|
|
543
925
|
if (error instanceof HTTPError) {
|
|
544
926
|
if (error.response.status === 404) {
|
|
@@ -553,6 +935,10 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
553
935
|
}
|
|
554
936
|
return false;
|
|
555
937
|
}
|
|
938
|
+
async randomDelay() {
|
|
939
|
+
const delay = 100 + Math.random() * 200;
|
|
940
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
941
|
+
}
|
|
556
942
|
};
|
|
557
943
|
__name(_ApitallyClient, "ApitallyClient");
|
|
558
944
|
__publicField(_ApitallyClient, "instance");
|