apitally 0.7.0 → 0.8.1
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/common/client.cjs +75 -30
- package/dist/common/client.cjs.map +1 -1
- package/dist/common/client.d.cts +10 -8
- package/dist/common/client.d.ts +10 -8
- package/dist/common/client.js +75 -30
- package/dist/common/client.js.map +1 -1
- package/dist/common/consumerRegistry.cjs +86 -0
- package/dist/common/consumerRegistry.cjs.map +1 -0
- package/dist/common/consumerRegistry.d.cts +14 -0
- package/dist/common/consumerRegistry.d.ts +14 -0
- package/dist/common/consumerRegistry.js +63 -0
- package/dist/common/consumerRegistry.js.map +1 -0
- package/dist/common/types.cjs.map +1 -1
- package/dist/common/types.d.cts +12 -5
- package/dist/common/types.d.ts +12 -5
- package/dist/express/index.cjs +113 -49
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.d.cts +2 -2
- package/dist/express/index.d.ts +2 -2
- package/dist/express/index.js +113 -49
- package/dist/express/index.js.map +1 -1
- package/dist/express/listEndpoints.cjs +16 -13
- package/dist/express/listEndpoints.cjs.map +1 -1
- package/dist/express/listEndpoints.d.cts +33 -2
- package/dist/express/listEndpoints.d.ts +33 -2
- package/dist/express/listEndpoints.js +16 -13
- package/dist/express/listEndpoints.js.map +1 -1
- package/dist/express/middleware.cjs +113 -49
- package/dist/express/middleware.cjs.map +1 -1
- package/dist/express/middleware.d.cts +5 -5
- package/dist/express/middleware.d.ts +5 -5
- package/dist/express/middleware.js +113 -49
- package/dist/express/middleware.js.map +1 -1
- package/dist/fastify/index.cjs +106 -37
- package/dist/fastify/index.cjs.map +1 -1
- package/dist/fastify/index.d.cts +2 -2
- package/dist/fastify/index.d.ts +2 -2
- package/dist/fastify/index.js +106 -37
- package/dist/fastify/index.js.map +1 -1
- package/dist/fastify/plugin.cjs +106 -37
- package/dist/fastify/plugin.cjs.map +1 -1
- package/dist/fastify/plugin.d.cts +3 -3
- package/dist/fastify/plugin.d.ts +3 -3
- package/dist/fastify/plugin.js +106 -37
- package/dist/fastify/plugin.js.map +1 -1
- package/dist/koa/index.cjs +98 -35
- package/dist/koa/index.cjs.map +1 -1
- package/dist/koa/index.d.cts +2 -2
- package/dist/koa/index.d.ts +2 -2
- package/dist/koa/index.js +98 -35
- package/dist/koa/index.js.map +1 -1
- package/dist/koa/middleware.cjs +98 -35
- package/dist/koa/middleware.cjs.map +1 -1
- package/dist/koa/middleware.d.cts +1 -1
- package/dist/koa/middleware.d.ts +1 -1
- package/dist/koa/middleware.js +98 -35
- package/dist/koa/middleware.js.map +1 -1
- package/dist/nestjs/index.cjs +113 -49
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.d.cts +2 -2
- package/dist/nestjs/index.d.ts +2 -2
- package/dist/nestjs/index.js +113 -49
- package/dist/nestjs/index.js.map +1 -1
- package/package.json +2 -2
package/dist/express/index.js
CHANGED
|
@@ -10,6 +10,62 @@ import { performance } from "perf_hooks";
|
|
|
10
10
|
import { randomUUID } from "crypto";
|
|
11
11
|
import fetchRetry from "fetch-retry";
|
|
12
12
|
|
|
13
|
+
// src/common/consumerRegistry.ts
|
|
14
|
+
var consumerFromStringOrObject = /* @__PURE__ */ __name((consumer) => {
|
|
15
|
+
var _a2, _b;
|
|
16
|
+
if (typeof consumer === "string") {
|
|
17
|
+
consumer = String(consumer).trim().substring(0, 128);
|
|
18
|
+
return consumer ? {
|
|
19
|
+
identifier: consumer
|
|
20
|
+
} : null;
|
|
21
|
+
} else {
|
|
22
|
+
consumer.identifier = String(consumer.identifier).trim().substring(0, 128);
|
|
23
|
+
consumer.name = (_a2 = consumer.name) == null ? void 0 : _a2.trim().substring(0, 64);
|
|
24
|
+
consumer.group = (_b = consumer.group) == null ? void 0 : _b.trim().substring(0, 64);
|
|
25
|
+
return consumer.identifier ? consumer : null;
|
|
26
|
+
}
|
|
27
|
+
}, "consumerFromStringOrObject");
|
|
28
|
+
var _ConsumerRegistry = class _ConsumerRegistry {
|
|
29
|
+
consumers;
|
|
30
|
+
updated;
|
|
31
|
+
constructor() {
|
|
32
|
+
this.consumers = /* @__PURE__ */ new Map();
|
|
33
|
+
this.updated = /* @__PURE__ */ new Set();
|
|
34
|
+
}
|
|
35
|
+
addOrUpdateConsumer(consumer) {
|
|
36
|
+
if (!consumer || !consumer.name && !consumer.group) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const existing = this.consumers.get(consumer.identifier);
|
|
40
|
+
if (!existing) {
|
|
41
|
+
this.consumers.set(consumer.identifier, consumer);
|
|
42
|
+
this.updated.add(consumer.identifier);
|
|
43
|
+
} else {
|
|
44
|
+
if (consumer.name && consumer.name !== existing.name) {
|
|
45
|
+
existing.name = consumer.name;
|
|
46
|
+
this.updated.add(consumer.identifier);
|
|
47
|
+
}
|
|
48
|
+
if (consumer.group && consumer.group !== existing.group) {
|
|
49
|
+
existing.group = consumer.group;
|
|
50
|
+
this.updated.add(consumer.identifier);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
getAndResetUpdatedConsumers() {
|
|
55
|
+
const data = [];
|
|
56
|
+
this.updated.forEach((identifier) => {
|
|
57
|
+
const consumer = this.consumers.get(identifier);
|
|
58
|
+
if (consumer) {
|
|
59
|
+
data.push(consumer);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
this.updated.clear();
|
|
63
|
+
return data;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
__name(_ConsumerRegistry, "ConsumerRegistry");
|
|
67
|
+
var ConsumerRegistry = _ConsumerRegistry;
|
|
68
|
+
|
|
13
69
|
// src/common/logging.ts
|
|
14
70
|
import { createLogger, format, transports } from "winston";
|
|
15
71
|
var getLogger = /* @__PURE__ */ __name(() => {
|
|
@@ -287,13 +343,14 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
287
343
|
clientId;
|
|
288
344
|
env;
|
|
289
345
|
instanceUuid;
|
|
290
|
-
|
|
346
|
+
syncDataQueue;
|
|
291
347
|
syncIntervalId;
|
|
292
|
-
|
|
293
|
-
|
|
348
|
+
startupData;
|
|
349
|
+
startupDataSent = false;
|
|
294
350
|
requestCounter;
|
|
295
351
|
validationErrorCounter;
|
|
296
352
|
serverErrorCounter;
|
|
353
|
+
consumerRegistry;
|
|
297
354
|
logger;
|
|
298
355
|
constructor({ clientId, env = "dev", logger }) {
|
|
299
356
|
if (_ApitallyClient.instance) {
|
|
@@ -309,10 +366,11 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
309
366
|
this.clientId = clientId;
|
|
310
367
|
this.env = env;
|
|
311
368
|
this.instanceUuid = randomUUID();
|
|
312
|
-
this.
|
|
369
|
+
this.syncDataQueue = [];
|
|
313
370
|
this.requestCounter = new RequestCounter();
|
|
314
371
|
this.validationErrorCounter = new ValidationErrorCounter();
|
|
315
372
|
this.serverErrorCounter = new ServerErrorCounter();
|
|
373
|
+
this.consumerRegistry = new ConsumerRegistry();
|
|
316
374
|
this.logger = logger || getLogger();
|
|
317
375
|
this.startSync();
|
|
318
376
|
this.handleShutdown = this.handleShutdown.bind(this);
|
|
@@ -330,15 +388,15 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
330
388
|
}
|
|
331
389
|
async handleShutdown() {
|
|
332
390
|
this.stopSync();
|
|
333
|
-
await this.
|
|
391
|
+
await this.sendSyncData();
|
|
334
392
|
_ApitallyClient.instance = void 0;
|
|
335
393
|
}
|
|
336
394
|
getHubUrlPrefix() {
|
|
337
395
|
const baseURL = process.env.APITALLY_HUB_BASE_URL || "https://hub.apitally.io";
|
|
338
|
-
const version = "
|
|
396
|
+
const version = "v2";
|
|
339
397
|
return `${baseURL}/${version}/${this.clientId}/${this.env}/`;
|
|
340
398
|
}
|
|
341
|
-
async
|
|
399
|
+
async sendData(url, payload) {
|
|
342
400
|
const fetchWithRetry = fetchRetry(fetch, {
|
|
343
401
|
retries: 3,
|
|
344
402
|
retryDelay: 1e3,
|
|
@@ -377,10 +435,10 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
377
435
|
async sync() {
|
|
378
436
|
try {
|
|
379
437
|
const promises = [
|
|
380
|
-
this.
|
|
438
|
+
this.sendSyncData()
|
|
381
439
|
];
|
|
382
|
-
if (!this.
|
|
383
|
-
promises.push(this.
|
|
440
|
+
if (!this.startupDataSent) {
|
|
441
|
+
promises.push(this.sendStartupData());
|
|
384
442
|
}
|
|
385
443
|
await Promise.all(promises);
|
|
386
444
|
} catch (error) {
|
|
@@ -395,62 +453,63 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
395
453
|
this.syncIntervalId = void 0;
|
|
396
454
|
}
|
|
397
455
|
}
|
|
398
|
-
|
|
399
|
-
this.
|
|
400
|
-
this.
|
|
401
|
-
this.
|
|
456
|
+
setStartupData(data) {
|
|
457
|
+
this.startupData = data;
|
|
458
|
+
this.startupDataSent = false;
|
|
459
|
+
this.sendStartupData();
|
|
402
460
|
}
|
|
403
|
-
async
|
|
404
|
-
if (this.
|
|
405
|
-
this.logger.debug("Sending
|
|
461
|
+
async sendStartupData() {
|
|
462
|
+
if (this.startupData) {
|
|
463
|
+
this.logger.debug("Sending startup data to Apitally Hub");
|
|
406
464
|
const payload = {
|
|
407
465
|
instance_uuid: this.instanceUuid,
|
|
408
466
|
message_uuid: randomUUID(),
|
|
409
|
-
...this.
|
|
467
|
+
...this.startupData
|
|
410
468
|
};
|
|
411
469
|
try {
|
|
412
|
-
await this.
|
|
413
|
-
this.
|
|
470
|
+
await this.sendData("startup", payload);
|
|
471
|
+
this.startupDataSent = true;
|
|
414
472
|
} catch (error) {
|
|
415
473
|
const handled = this.handleHubError(error);
|
|
416
474
|
if (!handled) {
|
|
417
475
|
this.logger.error(error.message);
|
|
418
|
-
this.logger.debug("Error while sending
|
|
476
|
+
this.logger.debug("Error while sending startup data to Apitally Hub (will retry)", {
|
|
419
477
|
error
|
|
420
478
|
});
|
|
421
479
|
}
|
|
422
480
|
}
|
|
423
481
|
}
|
|
424
482
|
}
|
|
425
|
-
async
|
|
426
|
-
this.logger.debug("
|
|
483
|
+
async sendSyncData() {
|
|
484
|
+
this.logger.debug("Synchronizing data with Apitally Hub");
|
|
427
485
|
const newPayload = {
|
|
428
486
|
time_offset: 0,
|
|
429
487
|
instance_uuid: this.instanceUuid,
|
|
430
488
|
message_uuid: randomUUID(),
|
|
431
489
|
requests: this.requestCounter.getAndResetRequests(),
|
|
432
490
|
validation_errors: this.validationErrorCounter.getAndResetValidationErrors(),
|
|
433
|
-
server_errors: this.serverErrorCounter.getAndResetServerErrors()
|
|
491
|
+
server_errors: this.serverErrorCounter.getAndResetServerErrors(),
|
|
492
|
+
consumers: this.consumerRegistry.getAndResetUpdatedConsumers()
|
|
434
493
|
};
|
|
435
|
-
this.
|
|
494
|
+
this.syncDataQueue.push([
|
|
436
495
|
Date.now(),
|
|
437
496
|
newPayload
|
|
438
497
|
]);
|
|
439
498
|
const failedItems = [];
|
|
440
|
-
while (this.
|
|
441
|
-
const queueItem = this.
|
|
499
|
+
while (this.syncDataQueue.length > 0) {
|
|
500
|
+
const queueItem = this.syncDataQueue.shift();
|
|
442
501
|
if (queueItem) {
|
|
443
502
|
const [time, payload] = queueItem;
|
|
444
503
|
try {
|
|
445
504
|
const timeOffset = Date.now() - time;
|
|
446
505
|
if (timeOffset <= MAX_QUEUE_TIME) {
|
|
447
506
|
payload.time_offset = timeOffset / 1e3;
|
|
448
|
-
await this.
|
|
507
|
+
await this.sendData("sync", payload);
|
|
449
508
|
}
|
|
450
509
|
} catch (error) {
|
|
451
510
|
const handled = this.handleHubError(error);
|
|
452
511
|
if (!handled) {
|
|
453
|
-
this.logger.debug("Error while
|
|
512
|
+
this.logger.debug("Error while synchronizing data with Apitally Hub (will retry)", {
|
|
454
513
|
error
|
|
455
514
|
});
|
|
456
515
|
failedItems.push(queueItem);
|
|
@@ -458,7 +517,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
458
517
|
}
|
|
459
518
|
}
|
|
460
519
|
}
|
|
461
|
-
this.
|
|
520
|
+
this.syncDataQueue = failedItems;
|
|
462
521
|
}
|
|
463
522
|
handleHubError(error) {
|
|
464
523
|
if (error instanceof HTTPError) {
|
|
@@ -492,9 +551,10 @@ function getPackageVersion(name) {
|
|
|
492
551
|
__name(getPackageVersion, "getPackageVersion");
|
|
493
552
|
|
|
494
553
|
// src/express/listEndpoints.js
|
|
495
|
-
var regExpToParseExpressPathRegExp = /^\/\^\\\/(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\(
|
|
496
|
-
var regExpToReplaceExpressPathRegExpParams = /\(\?:\(
|
|
497
|
-
var regexpExpressParamRegexp = /\(\?:\(
|
|
554
|
+
var regExpToParseExpressPathRegExp = /^\/\^\\\/(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\([^)]+\)\)))\\\/.*/;
|
|
555
|
+
var regExpToReplaceExpressPathRegExpParams = /\(\?:\([^)]+\)\)/;
|
|
556
|
+
var regexpExpressParamRegexp = /\(\?:\([^)]+\)\)/g;
|
|
557
|
+
var regexpExpressPathParamRegexp = /(:[^)]+)\([^)]+\)/g;
|
|
498
558
|
var EXPRESS_ROOT_PATH_REGEXP_VALUE = "/^\\/?(?=\\/|$)/i";
|
|
499
559
|
var STACK_ITEM_VALID_NAMES = [
|
|
500
560
|
"router",
|
|
@@ -525,7 +585,7 @@ var parseExpressRoute = /* @__PURE__ */ __name(function(route, basePath) {
|
|
|
525
585
|
const endpoints = paths.map((path) => {
|
|
526
586
|
const completePath = basePath && path === "/" ? basePath : `${basePath}${path}`;
|
|
527
587
|
const endpoint = {
|
|
528
|
-
path: completePath,
|
|
588
|
+
path: completePath.replace(regexpExpressPathParamRegexp, "$1"),
|
|
529
589
|
methods: getRouteMethods(route),
|
|
530
590
|
middlewares: getRouteMiddlewares(route)
|
|
531
591
|
};
|
|
@@ -534,8 +594,8 @@ var parseExpressRoute = /* @__PURE__ */ __name(function(route, basePath) {
|
|
|
534
594
|
return endpoints;
|
|
535
595
|
}, "parseExpressRoute");
|
|
536
596
|
var parseExpressPath = /* @__PURE__ */ __name(function(expressPathRegExp, params) {
|
|
537
|
-
let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(expressPathRegExp);
|
|
538
597
|
let parsedRegExp = expressPathRegExp.toString();
|
|
598
|
+
let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);
|
|
539
599
|
let paramIndex = 0;
|
|
540
600
|
while (hasParams(parsedRegExp)) {
|
|
541
601
|
const paramName = params[paramIndex].name;
|
|
@@ -554,13 +614,15 @@ var parseEndpoints = /* @__PURE__ */ __name(function(app, basePath, endpoints) {
|
|
|
554
614
|
endpoints = endpoints || [];
|
|
555
615
|
basePath = basePath || "";
|
|
556
616
|
if (!stack) {
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
617
|
+
if (endpoints.length) {
|
|
618
|
+
endpoints = addEndpoints(endpoints, [
|
|
619
|
+
{
|
|
620
|
+
path: basePath,
|
|
621
|
+
methods: [],
|
|
622
|
+
middlewares: []
|
|
623
|
+
}
|
|
624
|
+
]);
|
|
625
|
+
}
|
|
564
626
|
} else {
|
|
565
627
|
endpoints = parseStack(stack, basePath, endpoints);
|
|
566
628
|
}
|
|
@@ -568,7 +630,7 @@ var parseEndpoints = /* @__PURE__ */ __name(function(app, basePath, endpoints) {
|
|
|
568
630
|
}, "parseEndpoints");
|
|
569
631
|
var addEndpoints = /* @__PURE__ */ __name(function(currentEndpoints, endpointsToAdd) {
|
|
570
632
|
endpointsToAdd.forEach((newEndpoint) => {
|
|
571
|
-
const existingEndpoint = currentEndpoints.find((
|
|
633
|
+
const existingEndpoint = currentEndpoints.find((endpoint) => endpoint.path === newEndpoint.path);
|
|
572
634
|
if (existingEndpoint !== void 0) {
|
|
573
635
|
const newMethods = newEndpoint.methods.filter((method) => !existingEndpoint.methods.includes(method));
|
|
574
636
|
existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);
|
|
@@ -616,7 +678,7 @@ var useApitally = /* @__PURE__ */ __name((app, config) => {
|
|
|
616
678
|
const middleware = getMiddleware(app, client);
|
|
617
679
|
app.use(middleware);
|
|
618
680
|
setTimeout(() => {
|
|
619
|
-
client.
|
|
681
|
+
client.setStartupData(getAppInfo(app, config.appVersion));
|
|
620
682
|
}, 1e3);
|
|
621
683
|
}, "useApitally");
|
|
622
684
|
var getMiddleware = /* @__PURE__ */ __name((app, client) => {
|
|
@@ -645,8 +707,9 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
|
|
|
645
707
|
if (req.route) {
|
|
646
708
|
const responseTime = performance.now() - startTime;
|
|
647
709
|
const consumer = getConsumer(req);
|
|
710
|
+
client.consumerRegistry.addOrUpdateConsumer(consumer);
|
|
648
711
|
client.requestCounter.addRequest({
|
|
649
|
-
consumer,
|
|
712
|
+
consumer: consumer == null ? void 0 : consumer.identifier,
|
|
650
713
|
method: req.method,
|
|
651
714
|
path: req.route.path,
|
|
652
715
|
statusCode: res.statusCode,
|
|
@@ -667,7 +730,7 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
|
|
|
667
730
|
}
|
|
668
731
|
validationErrors.forEach((error) => {
|
|
669
732
|
client.validationErrorCounter.addValidationError({
|
|
670
|
-
consumer,
|
|
733
|
+
consumer: consumer == null ? void 0 : consumer.identifier,
|
|
671
734
|
method: req.method,
|
|
672
735
|
path: req.route.path,
|
|
673
736
|
...error
|
|
@@ -677,7 +740,7 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
|
|
|
677
740
|
if (res.statusCode === 500 && res.locals.serverError) {
|
|
678
741
|
const serverError = res.locals.serverError;
|
|
679
742
|
client.serverErrorCounter.addServerError({
|
|
680
|
-
consumer,
|
|
743
|
+
consumer: consumer == null ? void 0 : consumer.identifier,
|
|
681
744
|
method: req.method,
|
|
682
745
|
path: req.route.path,
|
|
683
746
|
type: serverError.name,
|
|
@@ -707,9 +770,10 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
|
|
|
707
770
|
}, "getMiddleware");
|
|
708
771
|
var getConsumer = /* @__PURE__ */ __name((req) => {
|
|
709
772
|
if (req.apitallyConsumer) {
|
|
710
|
-
return
|
|
773
|
+
return consumerFromStringOrObject(req.apitallyConsumer);
|
|
711
774
|
} else if (req.consumerIdentifier) {
|
|
712
|
-
|
|
775
|
+
process.emitWarning("The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.", "DeprecationWarning");
|
|
776
|
+
return consumerFromStringOrObject(req.consumerIdentifier);
|
|
713
777
|
}
|
|
714
778
|
return null;
|
|
715
779
|
}, "getConsumer");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/express/middleware.ts","../../src/common/client.ts","../../src/common/logging.ts","../../src/common/paramValidation.ts","../../src/common/requestCounter.ts","../../src/common/serverErrorCounter.ts","../../src/common/validationErrorCounter.ts","../../src/common/packageVersions.ts","../../src/express/listEndpoints.js"],"sourcesContent":["import type { Express, NextFunction, Request, Response } from \"express\";\nimport { performance } from \"perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport { ApitallyConfig, AppInfo, ValidationError } from \"../common/types.js\";\nimport listEndpoints from \"./listEndpoints.js\";\n\ndeclare module \"express\" {\n interface Request {\n apitallyConsumer?: string;\n consumerIdentifier?: string; // For backwards compatibility\n }\n}\n\nexport const useApitally = (app: Express, config: ApitallyConfig) => {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(app, client);\n app.use(middleware);\n setTimeout(() => {\n client.setAppInfo(getAppInfo(app, config.appVersion));\n }, 1000);\n};\n\nconst getMiddleware = (app: Express, client: ApitallyClient) => {\n const validatorInstalled = getPackageVersion(\"express-validator\") !== null;\n const celebrateInstalled = getPackageVersion(\"celebrate\") !== null;\n const nestInstalled = getPackageVersion(\"@nestjs/core\") !== null;\n const classValidatorInstalled = getPackageVersion(\"class-validator\") !== null;\n let errorHandlerConfigured = false;\n\n return (req: Request, res: Response, next: NextFunction) => {\n if (!errorHandlerConfigured) {\n // Add error handling middleware to the bottom of the stack when handling the first request\n app.use(\n (err: Error, req: Request, res: Response, next: NextFunction): void => {\n res.locals.serverError = err;\n next(err);\n },\n );\n errorHandlerConfigured = true;\n }\n try {\n const startTime = performance.now();\n const originalJson = res.json;\n res.json = (body) => {\n res.locals.body = body;\n return originalJson.call(res, body);\n };\n res.on(\"finish\", () => {\n try {\n if (req.route) {\n const responseTime = performance.now() - startTime;\n const consumer = getConsumer(req);\n client.requestCounter.addRequest({\n consumer: consumer,\n method: req.method,\n path: req.route.path,\n statusCode: res.statusCode,\n responseTime: responseTime,\n requestSize: req.get(\"content-length\"),\n responseSize: res.get(\"content-length\"),\n });\n if (\n (res.statusCode === 400 || res.statusCode === 422) &&\n res.locals.body\n ) {\n const validationErrors: ValidationError[] = [];\n if (validatorInstalled) {\n validationErrors.push(\n ...extractExpressValidatorErrors(res.locals.body),\n );\n }\n if (celebrateInstalled) {\n validationErrors.push(\n ...extractCelebrateErrors(res.locals.body),\n );\n }\n if (nestInstalled && classValidatorInstalled) {\n validationErrors.push(\n ...extractNestValidationErrors(res.locals.body),\n );\n }\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer,\n method: req.method,\n path: req.route.path,\n ...error,\n });\n });\n }\n if (res.statusCode === 500 && res.locals.serverError) {\n const serverError = res.locals.serverError as Error;\n client.serverErrorCounter.addServerError({\n consumer: consumer,\n method: req.method,\n path: req.route.path,\n type: serverError.name,\n msg: serverError.message,\n traceback: serverError.stack || \"\",\n });\n }\n }\n } catch (error) {\n client.logger.error(\n \"Error while logging request in Apitally middleware.\",\n { request: req, response: res, error },\n );\n }\n });\n } catch (error) {\n client.logger.error(\"Error in Apitally middleware.\", {\n request: req,\n response: res,\n error,\n });\n } finally {\n next();\n }\n };\n};\n\nconst getConsumer = (req: Request) => {\n if (req.apitallyConsumer) {\n return String(req.apitallyConsumer);\n } else if (req.consumerIdentifier) {\n // For backwards compatibility\n return String(req.consumerIdentifier);\n }\n return null;\n};\n\nconst extractExpressValidatorErrors = (responseBody: any) => {\n const errors: ValidationError[] = [];\n if (\n responseBody &&\n responseBody.errors &&\n Array.isArray(responseBody.errors)\n ) {\n responseBody.errors.forEach((error: any) => {\n if (error.location && error.path && error.msg && error.type) {\n errors.push({\n loc: `${error.location}.${error.path}`,\n msg: error.msg,\n type: error.type,\n });\n }\n });\n }\n return errors;\n};\n\nconst extractCelebrateErrors = (responseBody: any) => {\n const errors: ValidationError[] = [];\n if (responseBody && responseBody.validation) {\n Object.values(responseBody.validation).forEach((error: any) => {\n if (\n error.source &&\n error.keys &&\n Array.isArray(error.keys) &&\n error.message\n ) {\n error.keys.forEach((key: string) => {\n errors.push({\n loc: `${error.source}.${key}`,\n msg: subsetJoiMessage(error.message, key),\n type: \"\",\n });\n });\n }\n });\n }\n return errors;\n};\n\nconst extractNestValidationErrors = (responseBody: any) => {\n const errors: ValidationError[] = [];\n if (responseBody && Array.isArray(responseBody.message)) {\n responseBody.message.forEach((message: any) => {\n errors.push({\n loc: \"\",\n msg: message,\n type: \"\",\n });\n });\n }\n return errors;\n};\n\nconst subsetJoiMessage = (message: string, key: string) => {\n const messageWithKey = message\n .split(\". \")\n .find((message) => message.includes(`\"${key}\"`));\n return messageWithKey ? messageWithKey : message;\n};\n\nconst getAppInfo = (app: Express, appVersion?: string): AppInfo => {\n const versions: Array<[string, string]> = [\n [\"nodejs\", process.version.replace(/^v/, \"\")],\n ];\n const expressVersion = getPackageVersion(\"express\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (expressVersion) {\n versions.push([\"express\", expressVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: listEndpoints(app),\n versions: Object.fromEntries(versions),\n client: \"js:express\",\n };\n};\n","import { randomUUID } from \"crypto\";\nimport fetchRetry from \"fetch-retry\";\nimport { Logger, getLogger } from \"./logging.js\";\nimport { isValidClientId, isValidEnv } from \"./paramValidation.js\";\nimport RequestCounter from \"./requestCounter.js\";\nimport ServerErrorCounter from \"./serverErrorCounter.js\";\nimport {\n ApitallyConfig,\n AppInfo,\n AppInfoPayload,\n RequestsDataPayload,\n} from \"./types.js\";\nimport ValidationErrorCounter from \"./validationErrorCounter.js\";\n\nconst SYNC_INTERVAL = 60000; // 60 seconds\nconst INITIAL_SYNC_INTERVAL = 10000; // 10 seconds\nconst INITIAL_SYNC_INTERVAL_DURATION = 3600000; // 1 hour\nconst MAX_QUEUE_TIME = 3.6e6; // 1 hour\n\nclass HTTPError extends Error {\n public response: Response;\n\n constructor(response: Response) {\n const reason = response.status\n ? `status code ${response.status}`\n : \"an unknown error\";\n super(`Request failed with ${reason}`);\n this.response = response;\n }\n}\n\nexport class ApitallyClient {\n private clientId: string;\n private env: string;\n\n private static instance?: ApitallyClient;\n private instanceUuid: string;\n private requestsDataQueue: Array<[number, RequestsDataPayload]>;\n private syncIntervalId?: NodeJS.Timeout;\n public appInfo?: AppInfo;\n private appInfoSent: boolean = false;\n\n public requestCounter: RequestCounter;\n public validationErrorCounter: ValidationErrorCounter;\n public serverErrorCounter: ServerErrorCounter;\n public logger: Logger;\n\n constructor({ clientId, env = \"dev\", logger }: ApitallyConfig) {\n if (ApitallyClient.instance) {\n throw new Error(\"Apitally client is already initialized\");\n }\n if (!isValidClientId(clientId)) {\n throw new Error(\n `Invalid client ID '${clientId}' (expecting hexadeciaml UUID format)`,\n );\n }\n if (!isValidEnv(env)) {\n throw new Error(\n `Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`,\n );\n }\n\n ApitallyClient.instance = this;\n this.clientId = clientId;\n this.env = env;\n this.instanceUuid = randomUUID();\n this.requestsDataQueue = [];\n this.requestCounter = new RequestCounter();\n this.validationErrorCounter = new ValidationErrorCounter();\n this.serverErrorCounter = new ServerErrorCounter();\n this.logger = logger || getLogger();\n\n this.startSync();\n this.handleShutdown = this.handleShutdown.bind(this);\n }\n\n public static getInstance() {\n if (!ApitallyClient.instance) {\n throw new Error(\"Apitally client is not initialized\");\n }\n return ApitallyClient.instance;\n }\n\n public static async shutdown() {\n if (ApitallyClient.instance) {\n await ApitallyClient.instance.handleShutdown();\n }\n }\n\n public async handleShutdown() {\n this.stopSync();\n await this.sendRequestsData();\n ApitallyClient.instance = undefined;\n }\n\n private getHubUrlPrefix() {\n const baseURL =\n process.env.APITALLY_HUB_BASE_URL || \"https://hub.apitally.io\";\n const version = \"v1\";\n return `${baseURL}/${version}/${this.clientId}/${this.env}/`;\n }\n\n private async makeHubRequest(url: string, payload: any) {\n const fetchWithRetry = fetchRetry(fetch, {\n retries: 3,\n retryDelay: 1000,\n retryOn: [408, 429, 500, 502, 503, 504],\n });\n const response = await fetchWithRetry(this.getHubUrlPrefix() + url, {\n method: \"POST\",\n body: JSON.stringify(payload),\n headers: { \"Content-Type\": \"application/json\" },\n });\n if (!response.ok) {\n throw new HTTPError(response);\n }\n }\n\n private startSync() {\n this.sync();\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, INITIAL_SYNC_INTERVAL);\n setTimeout(() => {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, SYNC_INTERVAL);\n }, INITIAL_SYNC_INTERVAL_DURATION);\n }\n\n private async sync() {\n try {\n const promises = [this.sendRequestsData()];\n if (!this.appInfoSent) {\n promises.push(this.sendAppInfo());\n }\n await Promise.all(promises);\n } catch (error) {\n this.logger.error(\"Error while syncing with Apitally Hub\", {\n error,\n });\n }\n }\n\n private stopSync() {\n if (this.syncIntervalId) {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = undefined;\n }\n }\n\n public setAppInfo(appInfo: AppInfo) {\n this.appInfo = appInfo;\n this.appInfoSent = false;\n this.sendAppInfo();\n }\n\n private async sendAppInfo() {\n if (this.appInfo) {\n this.logger.debug(\"Sending app info to Apitally Hub\");\n const payload: AppInfoPayload = {\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n ...this.appInfo,\n };\n try {\n await this.makeHubRequest(\"info\", payload);\n this.appInfoSent = true;\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.error((error as Error).message);\n this.logger.debug(\n \"Error while sending app info to Apitally Hub (will retry)\",\n { error },\n );\n }\n }\n }\n }\n\n private async sendRequestsData() {\n this.logger.debug(\"Sending requests data to Apitally Hub\");\n const newPayload: RequestsDataPayload = {\n time_offset: 0,\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n requests: this.requestCounter.getAndResetRequests(),\n validation_errors:\n this.validationErrorCounter.getAndResetValidationErrors(),\n server_errors: this.serverErrorCounter.getAndResetServerErrors(),\n };\n this.requestsDataQueue.push([Date.now(), newPayload]);\n\n const failedItems: [number, RequestsDataPayload][] = [];\n while (this.requestsDataQueue.length > 0) {\n const queueItem = this.requestsDataQueue.shift();\n if (queueItem) {\n const [time, payload] = queueItem;\n try {\n const timeOffset = Date.now() - time;\n if (timeOffset <= MAX_QUEUE_TIME) {\n payload.time_offset = timeOffset / 1000.0; // In seconds\n await this.makeHubRequest(\"requests\", payload);\n }\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.debug(\n \"Error while sending requests data to Apitally Hub (will retry)\",\n { error },\n );\n failedItems.push(queueItem);\n }\n }\n }\n }\n this.requestsDataQueue = failedItems;\n }\n\n private handleHubError(error: unknown) {\n if (error instanceof HTTPError) {\n if (error.response.status === 404) {\n this.logger.error(`Invalid Apitally client ID: '${this.clientId}'`);\n this.stopSync();\n return true;\n }\n if (error.response.status === 422) {\n this.logger.error(\"Received validation error from Apitally Hub\");\n return true;\n }\n }\n return false;\n }\n}\n","import { createLogger, format, transports } from \"winston\";\n\nexport interface Logger {\n debug: (message: string, meta?: object) => void;\n info: (message: string, meta?: object) => void;\n warn: (message: string, meta?: object) => void;\n error: (message: string, meta?: object) => void;\n}\n\nexport const getLogger = () => {\n return createLogger({\n level: process.env.APITALLY_DEBUG ? \"debug\" : \"warn\",\n format: format.combine(\n format.colorize(),\n format.timestamp(),\n format.printf(\n (info) => `${info.timestamp} ${info.level}: ${info.message}`,\n ),\n ),\n transports: [new transports.Console()],\n });\n};\n","export function isValidClientId(clientId: string): boolean {\n const regexExp =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n return regexExp.test(clientId);\n}\n\nexport function isValidEnv(env: string): boolean {\n const regexExp = /^[\\w-]{1,32}$/;\n return regexExp.test(env);\n}\n","import { RequestInfo, RequestsItem } from \"./types.js\";\n\nexport default class RequestCounter {\n private requestCounts: Map<string, number>;\n private requestSizeSums: Map<string, number>;\n private responseSizeSums: Map<string, number>;\n private responseTimes: Map<string, Map<number, number>>;\n private requestSizes: Map<string, Map<number, number>>;\n private responseSizes: Map<string, Map<number, number>>;\n\n constructor() {\n this.requestCounts = new Map<string, number>();\n this.requestSizeSums = new Map<string, number>();\n this.responseSizeSums = new Map<string, number>();\n this.responseTimes = new Map<string, Map<number, number>>();\n this.requestSizes = new Map<string, Map<number, number>>();\n this.responseSizes = new Map<string, Map<number, number>>();\n }\n\n private getKey(requestInfo: RequestInfo) {\n return [\n requestInfo.consumer || \"\",\n requestInfo.method.toUpperCase(),\n requestInfo.path,\n requestInfo.statusCode,\n ].join(\"|\");\n }\n\n addRequest(requestInfo: RequestInfo) {\n const key = this.getKey(requestInfo);\n\n // Increment request count\n this.requestCounts.set(key, (this.requestCounts.get(key) || 0) + 1);\n\n // Add response time\n if (!this.responseTimes.has(key)) {\n this.responseTimes.set(key, new Map<number, number>());\n }\n const responseTimeMap = this.responseTimes.get(key)!;\n const responseTimeMsBin = Math.floor(requestInfo.responseTime / 10) * 10; // Rounded to nearest 10ms\n responseTimeMap.set(\n responseTimeMsBin,\n (responseTimeMap.get(responseTimeMsBin) || 0) + 1,\n );\n\n // Add request size\n if (requestInfo.requestSize !== undefined) {\n requestInfo.requestSize = Number(requestInfo.requestSize);\n this.requestSizeSums.set(\n key,\n (this.requestSizeSums.get(key) || 0) + requestInfo.requestSize,\n );\n if (!this.requestSizes.has(key)) {\n this.requestSizes.set(key, new Map<number, number>());\n }\n const requestSizeMap = this.requestSizes.get(key)!;\n const requestSizeKbBin = Math.floor(requestInfo.requestSize / 1000); // Rounded down to nearest KB\n requestSizeMap.set(\n requestSizeKbBin,\n (requestSizeMap.get(requestSizeKbBin) || 0) + 1,\n );\n }\n\n // Add response size\n if (requestInfo.responseSize !== undefined) {\n requestInfo.responseSize = Number(requestInfo.responseSize);\n this.responseSizeSums.set(\n key,\n (this.responseSizeSums.get(key) || 0) + requestInfo.responseSize,\n );\n if (!this.responseSizes.has(key)) {\n this.responseSizes.set(key, new Map<number, number>());\n }\n const responseSizeMap = this.responseSizes.get(key)!;\n const responseSizeKbBin = Math.floor(requestInfo.responseSize / 1000); // Rounded down to nearest KB\n responseSizeMap.set(\n responseSizeKbBin,\n (responseSizeMap.get(responseSizeKbBin) || 0) + 1,\n );\n }\n }\n\n getAndResetRequests() {\n const data: Array<RequestsItem> = [];\n this.requestCounts.forEach((count, key) => {\n const [consumer, method, path, statusCodeStr] = key.split(\"|\");\n const responseTimes =\n this.responseTimes.get(key) || new Map<number, number>();\n const requestSizes =\n this.requestSizes.get(key) || new Map<number, number>();\n const responseSizes =\n this.responseSizes.get(key) || new Map<number, number>();\n data.push({\n consumer: consumer || null,\n method,\n path,\n status_code: parseInt(statusCodeStr),\n request_count: count,\n request_size_sum: this.requestSizeSums.get(key) || 0,\n response_size_sum: this.responseSizeSums.get(key) || 0,\n response_times: Object.fromEntries(responseTimes),\n request_sizes: Object.fromEntries(requestSizes),\n response_sizes: Object.fromEntries(responseSizes),\n });\n });\n\n // Reset the counts and times\n this.requestCounts.clear();\n this.requestSizeSums.clear();\n this.responseSizeSums.clear();\n this.responseTimes.clear();\n this.requestSizes.clear();\n this.responseSizes.clear();\n\n return data;\n }\n}\n","import type * as Sentry from \"@sentry/node\";\nimport { createHash } from \"crypto\";\n\nimport { ConsumerMethodPath, ServerError, ServerErrorsItem } from \"./types.js\";\n\nconst MAX_MSG_LENGTH = 2048;\nconst MAX_STACKTRACE_LENGTH = 65536;\n\nexport default class ServerErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ServerError>;\n private sentryEventIds: Map<string, string>;\n private sentry: typeof Sentry | undefined;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n this.sentryEventIds = new Map();\n this.tryImportSentry();\n }\n\n public addServerError(serverError: ConsumerMethodPath & ServerError) {\n const key = this.getKey(serverError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, serverError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n this.captureSentryEventId(key);\n }\n\n public getAndResetServerErrors() {\n const data: Array<ServerErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const serverError = this.errorDetails.get(key);\n if (serverError) {\n data.push({\n consumer: serverError.consumer || null,\n method: serverError.method,\n path: serverError.path,\n type: serverError.type,\n msg: this.getTruncatedMessage(serverError.msg),\n traceback: this.getTruncatedStack(serverError.traceback),\n sentry_event_id: this.sentryEventIds.get(key) || null,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(serverError: ConsumerMethodPath & ServerError) {\n const hashInput = [\n serverError.consumer || \"\",\n serverError.method.toUpperCase(),\n serverError.path,\n serverError.type,\n serverError.msg.trim(),\n serverError.traceback.trim(),\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n\n private getTruncatedMessage(msg: string) {\n msg = msg.trim();\n if (msg.length <= MAX_MSG_LENGTH) {\n return msg;\n }\n const suffix = \"... (truncated)\";\n const cutoff = MAX_MSG_LENGTH - suffix.length;\n return msg.substring(0, cutoff) + suffix;\n }\n\n private getTruncatedStack(stack: string) {\n const suffix = \"... (truncated) ...\";\n const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;\n const lines = stack.trim().split(\"\\n\");\n const truncatedLines: string[] = [];\n let length = 0;\n for (const line of lines) {\n if (length + line.length + 1 > cutoff) {\n truncatedLines.push(suffix);\n break;\n }\n truncatedLines.push(line);\n length += line.length + 1;\n }\n return truncatedLines.join(\"\\n\");\n }\n\n private captureSentryEventId(serverErrorKey: string) {\n if (this.sentry && this.sentry.lastEventId) {\n const eventId = this.sentry.lastEventId();\n if (eventId) {\n this.sentryEventIds.set(serverErrorKey, eventId);\n }\n }\n }\n\n private async tryImportSentry() {\n try {\n this.sentry = await import(\"@sentry/node\");\n } catch (e) {\n // Sentry SDK is not installed, ignore\n }\n }\n}\n","import { createHash } from \"crypto\";\n\nimport {\n ConsumerMethodPath,\n ValidationError,\n ValidationErrorsItem,\n} from \"./types.js\";\n\nexport default class ValidationErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ValidationError>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n }\n\n public addValidationError(\n validationError: ConsumerMethodPath & ValidationError,\n ) {\n const key = this.getKey(validationError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, validationError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n }\n\n public getAndResetValidationErrors() {\n const data: Array<ValidationErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const validationError = this.errorDetails.get(key);\n if (validationError) {\n data.push({\n consumer: validationError.consumer || null,\n method: validationError.method,\n path: validationError.path,\n loc: validationError.loc.split(\".\"),\n msg: validationError.msg,\n type: validationError.type,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(validationError: ConsumerMethodPath & ValidationError) {\n const hashInput = [\n validationError.consumer || \"\",\n validationError.method.toUpperCase(),\n validationError.path,\n validationError.loc,\n validationError.msg.trim(),\n validationError.type,\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n","import { createRequire } from \"module\";\n\nexport function getPackageVersion(name: string): string | null {\n try {\n const _require = createRequire(import.meta.url);\n return _require(`${name}/package.json`).version || null;\n } catch (error) {\n return null;\n }\n}\n","// Adapted from https://github.com/AlbertoFdzM/express-list-endpoints/blob/ed926dd5186761e7b721ad20938ce6eb52d104d3/src/index.js\n\nconst regExpToParseExpressPathRegExp =\n /^\\/\\^\\\\\\/(?:(:?[\\w\\\\.-]*(?:\\\\\\/:?[\\w\\\\.-]*)*)|(\\(\\?:\\(\\[\\^\\\\\\/]\\+\\?\\)\\)))\\\\\\/.*/;\nconst regExpToReplaceExpressPathRegExpParams = /\\(\\?:\\(\\[\\^\\\\\\/]\\+\\?\\)\\)/;\nconst regexpExpressParamRegexp = /\\(\\?:\\(\\[\\^\\\\\\/]\\+\\?\\)\\)/g;\n\nconst EXPRESS_ROOT_PATH_REGEXP_VALUE = \"/^\\\\/?(?=\\\\/|$)/i\";\nconst STACK_ITEM_VALID_NAMES = [\"router\", \"bound dispatch\", \"mounted_app\"];\n\n/**\n * Returns all the verbs detected for the passed route\n */\nconst getRouteMethods = function (route) {\n let methods = Object.keys(route.methods);\n\n methods = methods.filter((method) => method !== \"_all\");\n methods = methods.map((method) => method.toUpperCase());\n\n return methods;\n};\n\n/**\n * Returns the names (or anonymous) of all the middlewares attached to the\n * passed route\n * @param {Object} route\n * @returns {string[]}\n */\nconst getRouteMiddlewares = function (route) {\n return route.stack.map((item) => {\n return item.handle.name || \"anonymous\";\n });\n};\n\n/**\n * Returns true if found regexp related with express params\n * @param {string} expressPathRegExp\n * @returns {boolean}\n */\nconst hasParams = function (expressPathRegExp) {\n return regexpExpressParamRegexp.test(expressPathRegExp);\n};\n\n/**\n * @param {Object} route Express route object to be parsed\n * @param {string} basePath The basePath the route is on\n * @return {Object[]} Endpoints info\n */\nconst parseExpressRoute = function (route, basePath) {\n const paths = [];\n\n if (Array.isArray(route.path)) {\n paths.push(...route.path);\n } else {\n paths.push(route.path);\n }\n\n const endpoints = paths.map((path) => {\n const completePath =\n basePath && path === \"/\" ? basePath : `${basePath}${path}`;\n\n const endpoint = {\n path: completePath,\n methods: getRouteMethods(route),\n middlewares: getRouteMiddlewares(route),\n };\n\n return endpoint;\n });\n\n return endpoints;\n};\n\n/**\n * @param {RegExp} expressPathRegExp\n * @param {Object[]} params\n * @returns {string}\n */\nconst parseExpressPath = function (expressPathRegExp, params) {\n let expressPathRegExpExec =\n regExpToParseExpressPathRegExp.exec(expressPathRegExp);\n let parsedRegExp = expressPathRegExp.toString();\n let paramIndex = 0;\n\n while (hasParams(parsedRegExp)) {\n const paramName = params[paramIndex].name;\n const paramId = `:${paramName}`;\n\n parsedRegExp = parsedRegExp.replace(\n regExpToReplaceExpressPathRegExpParams,\n paramId,\n );\n\n paramIndex++;\n }\n\n if (parsedRegExp !== expressPathRegExp.toString()) {\n expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n }\n\n const parsedPath = expressPathRegExpExec[1].replace(/\\\\\\//g, \"/\");\n\n return parsedPath;\n};\n\n/**\n * @param {Object} app\n * @param {string} [basePath]\n * @param {Object[]} [endpoints]\n * @returns {Object[]}\n */\nconst parseEndpoints = function (app, basePath, endpoints) {\n const stack = app.stack || (app._router && app._router.stack);\n\n endpoints = endpoints || [];\n basePath = basePath || \"\";\n\n if (!stack) {\n endpoints = addEndpoints(endpoints, [\n {\n path: basePath,\n methods: [],\n middlewares: [],\n },\n ]);\n } else {\n endpoints = parseStack(stack, basePath, endpoints);\n }\n\n return endpoints;\n};\n\n/**\n * Ensures the path of the new endpoints isn't yet in the array.\n * If the path is already in the array merges the endpoints with the existing\n * one, if not, it adds them to the array.\n *\n * @param {Object[]} currentEndpoints Array of current endpoints\n * @param {Object[]} endpointsToAdd New endpoints to be added to the array\n * @returns {Object[]} Updated endpoints array\n */\nconst addEndpoints = function (currentEndpoints, endpointsToAdd) {\n endpointsToAdd.forEach((newEndpoint) => {\n const existingEndpoint = currentEndpoints.find(\n (item) => item.path === newEndpoint.path,\n );\n\n if (existingEndpoint !== undefined) {\n const newMethods = newEndpoint.methods.filter(\n (method) => !existingEndpoint.methods.includes(method),\n );\n\n existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);\n } else {\n currentEndpoints.push(newEndpoint);\n }\n });\n\n return currentEndpoints;\n};\n\n/**\n * @param {Object} stack\n * @param {string} basePath\n * @param {Object[]} endpoints\n * @returns {Object[]}\n */\nconst parseStack = function (stack, basePath, endpoints) {\n stack.forEach((stackItem) => {\n if (stackItem.route) {\n const newEndpoints = parseExpressRoute(stackItem.route, basePath);\n\n endpoints = addEndpoints(endpoints, newEndpoints);\n } else if (STACK_ITEM_VALID_NAMES.includes(stackItem.name)) {\n const isExpressPathRegexp = regExpToParseExpressPathRegExp.test(\n stackItem.regexp,\n );\n\n let newBasePath = basePath;\n\n if (isExpressPathRegexp) {\n const parsedPath = parseExpressPath(stackItem.regexp, stackItem.keys);\n\n newBasePath += `/${parsedPath}`;\n } else if (\n !stackItem.path &&\n stackItem.regexp &&\n stackItem.regexp.toString() !== EXPRESS_ROOT_PATH_REGEXP_VALUE\n ) {\n const regExpPath = ` RegExp(${stackItem.regexp}) `;\n\n newBasePath += `/${regExpPath}`;\n }\n\n endpoints = parseEndpoints(stackItem.handle, newBasePath, endpoints);\n }\n });\n\n return endpoints;\n};\n\nconst getEndpoints = function (app) {\n const endpoints = parseEndpoints(app);\n return endpoints.flatMap((route) =>\n route.methods\n .filter((method) => ![\"HEAD\", \"OPTIONS\"].includes(method.toUpperCase()))\n .map((method) => ({\n method,\n path: route.path,\n })),\n );\n};\n\nexport default getEndpoints;\n"],"mappings":"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","names":["performance","randomUUID","fetchRetry","createLogger","format","transports","getLogger","createLogger","level","process","env","APITALLY_DEBUG","format","combine","colorize","timestamp","printf","info","message","transports","Console","isValidClientId","clientId","regexExp","test","isValidEnv","env","RequestCounter","requestCounts","requestSizeSums","responseSizeSums","responseTimes","requestSizes","responseSizes","constructor","Map","getKey","requestInfo","consumer","method","toUpperCase","path","statusCode","join","addRequest","key","set","get","has","responseTimeMap","responseTimeMsBin","Math","floor","responseTime","requestSize","undefined","Number","requestSizeMap","requestSizeKbBin","responseSize","responseSizeMap","responseSizeKbBin","getAndResetRequests","data","forEach","count","statusCodeStr","split","push","status_code","parseInt","request_count","request_size_sum","response_size_sum","response_times","Object","fromEntries","request_sizes","response_sizes","clear","createHash","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","sentry","constructor","Map","tryImportSentry","addServerError","serverError","key","getKey","has","set","get","captureSentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","getTruncatedMessage","traceback","getTruncatedStack","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line","serverErrorKey","lastEventId","eventId","e","createHash","ValidationErrorCounter","errorCounts","errorDetails","constructor","Map","addValidationError","validationError","key","getKey","has","set","get","getAndResetValidationErrors","data","forEach","count","push","consumer","method","path","loc","split","msg","type","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","SYNC_INTERVAL","INITIAL_SYNC_INTERVAL","INITIAL_SYNC_INTERVAL_DURATION","MAX_QUEUE_TIME","HTTPError","Error","response","constructor","reason","status","ApitallyClient","clientId","env","instanceUuid","requestsDataQueue","syncIntervalId","appInfo","appInfoSent","requestCounter","validationErrorCounter","serverErrorCounter","logger","instance","isValidClientId","isValidEnv","randomUUID","RequestCounter","ValidationErrorCounter","ServerErrorCounter","getLogger","startSync","handleShutdown","bind","getInstance","shutdown","stopSync","sendRequestsData","undefined","getHubUrlPrefix","baseURL","process","APITALLY_HUB_BASE_URL","version","makeHubRequest","url","payload","fetchWithRetry","fetchRetry","fetch","retries","retryDelay","retryOn","method","body","JSON","stringify","headers","ok","sync","setInterval","setTimeout","clearInterval","promises","push","sendAppInfo","Promise","all","error","setAppInfo","debug","instance_uuid","message_uuid","handled","handleHubError","message","newPayload","time_offset","requests","getAndResetRequests","validation_errors","getAndResetValidationErrors","server_errors","getAndResetServerErrors","Date","now","failedItems","length","queueItem","shift","time","timeOffset","createRequire","getPackageVersion","name","_require","createRequire","url","version","error","regExpToParseExpressPathRegExp","regExpToReplaceExpressPathRegExpParams","regexpExpressParamRegexp","EXPRESS_ROOT_PATH_REGEXP_VALUE","STACK_ITEM_VALID_NAMES","getRouteMethods","route","methods","Object","keys","filter","method","map","toUpperCase","getRouteMiddlewares","stack","item","handle","name","hasParams","expressPathRegExp","test","parseExpressRoute","basePath","paths","Array","isArray","path","push","endpoints","completePath","endpoint","middlewares","parseExpressPath","params","expressPathRegExpExec","exec","parsedRegExp","toString","paramIndex","paramName","paramId","replace","parsedPath","parseEndpoints","app","_router","addEndpoints","parseStack","currentEndpoints","endpointsToAdd","forEach","newEndpoint","existingEndpoint","find","undefined","newMethods","includes","concat","stackItem","newEndpoints","isExpressPathRegexp","regexp","newBasePath","regExpPath","getEndpoints","flatMap","useApitally","app","config","client","ApitallyClient","middleware","getMiddleware","use","setTimeout","setAppInfo","getAppInfo","appVersion","validatorInstalled","getPackageVersion","celebrateInstalled","nestInstalled","classValidatorInstalled","errorHandlerConfigured","req","res","next","err","locals","serverError","startTime","performance","now","originalJson","json","body","call","on","route","responseTime","consumer","getConsumer","requestCounter","addRequest","method","path","statusCode","requestSize","get","responseSize","validationErrors","push","extractExpressValidatorErrors","extractCelebrateErrors","extractNestValidationErrors","forEach","error","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","logger","request","response","apitallyConsumer","String","consumerIdentifier","responseBody","errors","Array","isArray","location","loc","validation","Object","values","source","keys","key","subsetJoiMessage","messageWithKey","split","find","includes","versions","process","version","replace","expressVersion","apitallyVersion","paths","listEndpoints","fromEntries"]}
|
|
1
|
+
{"version":3,"sources":["../../src/express/middleware.ts","../../src/common/client.ts","../../src/common/consumerRegistry.ts","../../src/common/logging.ts","../../src/common/paramValidation.ts","../../src/common/requestCounter.ts","../../src/common/serverErrorCounter.ts","../../src/common/validationErrorCounter.ts","../../src/common/packageVersions.ts","../../src/express/listEndpoints.js"],"sourcesContent":["import type { Express, NextFunction, Request, Response, Router } from \"express\";\nimport { performance } from \"perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n StartupData,\n ValidationError,\n} from \"../common/types.js\";\nimport listEndpoints from \"./listEndpoints.js\";\n\ndeclare module \"express\" {\n interface Request {\n apitallyConsumer?: ApitallyConsumer | string | null;\n consumerIdentifier?: ApitallyConsumer | string | null; // For backwards compatibility\n }\n}\n\nexport const useApitally = (app: Express | Router, config: ApitallyConfig) => {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(app, client);\n app.use(middleware);\n setTimeout(() => {\n client.setStartupData(getAppInfo(app, config.appVersion));\n }, 1000);\n};\n\nconst getMiddleware = (app: Express | Router, client: ApitallyClient) => {\n const validatorInstalled = getPackageVersion(\"express-validator\") !== null;\n const celebrateInstalled = getPackageVersion(\"celebrate\") !== null;\n const nestInstalled = getPackageVersion(\"@nestjs/core\") !== null;\n const classValidatorInstalled = getPackageVersion(\"class-validator\") !== null;\n let errorHandlerConfigured = false;\n\n return (req: Request, res: Response, next: NextFunction) => {\n if (!errorHandlerConfigured) {\n // Add error handling middleware to the bottom of the stack when handling the first request\n app.use(\n (err: Error, req: Request, res: Response, next: NextFunction): void => {\n res.locals.serverError = err;\n next(err);\n },\n );\n errorHandlerConfigured = true;\n }\n try {\n const startTime = performance.now();\n const originalJson = res.json;\n res.json = (body) => {\n res.locals.body = body;\n return originalJson.call(res, body);\n };\n res.on(\"finish\", () => {\n try {\n if (req.route) {\n const responseTime = performance.now() - startTime;\n const consumer = getConsumer(req);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: req.method,\n path: req.route.path,\n statusCode: res.statusCode,\n responseTime: responseTime,\n requestSize: req.get(\"content-length\"),\n responseSize: res.get(\"content-length\"),\n });\n if (\n (res.statusCode === 400 || res.statusCode === 422) &&\n res.locals.body\n ) {\n const validationErrors: ValidationError[] = [];\n if (validatorInstalled) {\n validationErrors.push(\n ...extractExpressValidatorErrors(res.locals.body),\n );\n }\n if (celebrateInstalled) {\n validationErrors.push(\n ...extractCelebrateErrors(res.locals.body),\n );\n }\n if (nestInstalled && classValidatorInstalled) {\n validationErrors.push(\n ...extractNestValidationErrors(res.locals.body),\n );\n }\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: req.method,\n path: req.route.path,\n ...error,\n });\n });\n }\n if (res.statusCode === 500 && res.locals.serverError) {\n const serverError = res.locals.serverError as Error;\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: req.method,\n path: req.route.path,\n type: serverError.name,\n msg: serverError.message,\n traceback: serverError.stack || \"\",\n });\n }\n }\n } catch (error) {\n client.logger.error(\n \"Error while logging request in Apitally middleware.\",\n { request: req, response: res, error },\n );\n }\n });\n } catch (error) {\n client.logger.error(\"Error in Apitally middleware.\", {\n request: req,\n response: res,\n error,\n });\n } finally {\n next();\n }\n };\n};\n\nconst getConsumer = (req: Request) => {\n if (req.apitallyConsumer) {\n return consumerFromStringOrObject(req.apitallyConsumer);\n } else if (req.consumerIdentifier) {\n // For backwards compatibility\n process.emitWarning(\n \"The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.\",\n \"DeprecationWarning\",\n );\n return consumerFromStringOrObject(req.consumerIdentifier);\n }\n return null;\n};\n\nconst extractExpressValidatorErrors = (responseBody: any) => {\n const errors: ValidationError[] = [];\n if (\n responseBody &&\n responseBody.errors &&\n Array.isArray(responseBody.errors)\n ) {\n responseBody.errors.forEach((error: any) => {\n if (error.location && error.path && error.msg && error.type) {\n errors.push({\n loc: `${error.location}.${error.path}`,\n msg: error.msg,\n type: error.type,\n });\n }\n });\n }\n return errors;\n};\n\nconst extractCelebrateErrors = (responseBody: any) => {\n const errors: ValidationError[] = [];\n if (responseBody && responseBody.validation) {\n Object.values(responseBody.validation).forEach((error: any) => {\n if (\n error.source &&\n error.keys &&\n Array.isArray(error.keys) &&\n error.message\n ) {\n error.keys.forEach((key: string) => {\n errors.push({\n loc: `${error.source}.${key}`,\n msg: subsetJoiMessage(error.message, key),\n type: \"\",\n });\n });\n }\n });\n }\n return errors;\n};\n\nconst extractNestValidationErrors = (responseBody: any) => {\n const errors: ValidationError[] = [];\n if (responseBody && Array.isArray(responseBody.message)) {\n responseBody.message.forEach((message: any) => {\n errors.push({\n loc: \"\",\n msg: message,\n type: \"\",\n });\n });\n }\n return errors;\n};\n\nconst subsetJoiMessage = (message: string, key: string) => {\n const messageWithKey = message\n .split(\". \")\n .find((message) => message.includes(`\"${key}\"`));\n return messageWithKey ? messageWithKey : message;\n};\n\nconst getAppInfo = (\n app: Express | Router,\n appVersion?: string,\n): StartupData => {\n const versions: Array<[string, string]> = [\n [\"nodejs\", process.version.replace(/^v/, \"\")],\n ];\n const expressVersion = getPackageVersion(\"express\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (expressVersion) {\n versions.push([\"express\", expressVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: listEndpoints(app),\n versions: Object.fromEntries(versions),\n client: \"js:express\",\n };\n};\n","import { randomUUID } from \"crypto\";\nimport fetchRetry from \"fetch-retry\";\nimport ConsumerRegistry from \"./consumerRegistry.js\";\nimport { Logger, getLogger } from \"./logging.js\";\nimport { isValidClientId, isValidEnv } from \"./paramValidation.js\";\nimport RequestCounter from \"./requestCounter.js\";\nimport ServerErrorCounter from \"./serverErrorCounter.js\";\nimport {\n ApitallyConfig,\n StartupData,\n StartupPayload,\n SyncPayload,\n} from \"./types.js\";\nimport ValidationErrorCounter from \"./validationErrorCounter.js\";\n\nconst SYNC_INTERVAL = 60000; // 60 seconds\nconst INITIAL_SYNC_INTERVAL = 10000; // 10 seconds\nconst INITIAL_SYNC_INTERVAL_DURATION = 3600000; // 1 hour\nconst MAX_QUEUE_TIME = 3.6e6; // 1 hour\n\nclass HTTPError extends Error {\n public response: Response;\n\n constructor(response: Response) {\n const reason = response.status\n ? `status code ${response.status}`\n : \"an unknown error\";\n super(`Request failed with ${reason}`);\n this.response = response;\n }\n}\n\nexport class ApitallyClient {\n private clientId: string;\n private env: string;\n\n private static instance?: ApitallyClient;\n private instanceUuid: string;\n private syncDataQueue: Array<[number, SyncPayload]>;\n private syncIntervalId?: NodeJS.Timeout;\n public startupData?: StartupData;\n private startupDataSent: boolean = false;\n\n public requestCounter: RequestCounter;\n public validationErrorCounter: ValidationErrorCounter;\n public serverErrorCounter: ServerErrorCounter;\n public consumerRegistry: ConsumerRegistry;\n public logger: Logger;\n\n constructor({ clientId, env = \"dev\", logger }: ApitallyConfig) {\n if (ApitallyClient.instance) {\n throw new Error(\"Apitally client is already initialized\");\n }\n if (!isValidClientId(clientId)) {\n throw new Error(\n `Invalid client ID '${clientId}' (expecting hexadeciaml UUID format)`,\n );\n }\n if (!isValidEnv(env)) {\n throw new Error(\n `Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`,\n );\n }\n\n ApitallyClient.instance = this;\n this.clientId = clientId;\n this.env = env;\n this.instanceUuid = randomUUID();\n this.syncDataQueue = [];\n this.requestCounter = new RequestCounter();\n this.validationErrorCounter = new ValidationErrorCounter();\n this.serverErrorCounter = new ServerErrorCounter();\n this.consumerRegistry = new ConsumerRegistry();\n this.logger = logger || getLogger();\n\n this.startSync();\n this.handleShutdown = this.handleShutdown.bind(this);\n }\n\n public static getInstance() {\n if (!ApitallyClient.instance) {\n throw new Error(\"Apitally client is not initialized\");\n }\n return ApitallyClient.instance;\n }\n\n public static async shutdown() {\n if (ApitallyClient.instance) {\n await ApitallyClient.instance.handleShutdown();\n }\n }\n\n public async handleShutdown() {\n this.stopSync();\n await this.sendSyncData();\n ApitallyClient.instance = undefined;\n }\n\n private getHubUrlPrefix() {\n const baseURL =\n process.env.APITALLY_HUB_BASE_URL || \"https://hub.apitally.io\";\n const version = \"v2\";\n return `${baseURL}/${version}/${this.clientId}/${this.env}/`;\n }\n\n private async sendData(url: string, payload: any) {\n const fetchWithRetry = fetchRetry(fetch, {\n retries: 3,\n retryDelay: 1000,\n retryOn: [408, 429, 500, 502, 503, 504],\n });\n const response = await fetchWithRetry(this.getHubUrlPrefix() + url, {\n method: \"POST\",\n body: JSON.stringify(payload),\n headers: { \"Content-Type\": \"application/json\" },\n });\n if (!response.ok) {\n throw new HTTPError(response);\n }\n }\n\n private startSync() {\n this.sync();\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, INITIAL_SYNC_INTERVAL);\n setTimeout(() => {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, SYNC_INTERVAL);\n }, INITIAL_SYNC_INTERVAL_DURATION);\n }\n\n private async sync() {\n try {\n const promises = [this.sendSyncData()];\n if (!this.startupDataSent) {\n promises.push(this.sendStartupData());\n }\n await Promise.all(promises);\n } catch (error) {\n this.logger.error(\"Error while syncing with Apitally Hub\", {\n error,\n });\n }\n }\n\n private stopSync() {\n if (this.syncIntervalId) {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = undefined;\n }\n }\n\n public setStartupData(data: StartupData) {\n this.startupData = data;\n this.startupDataSent = false;\n this.sendStartupData();\n }\n\n private async sendStartupData() {\n if (this.startupData) {\n this.logger.debug(\"Sending startup data to Apitally Hub\");\n const payload: StartupPayload = {\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n ...this.startupData,\n };\n try {\n await this.sendData(\"startup\", payload);\n this.startupDataSent = true;\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.error((error as Error).message);\n this.logger.debug(\n \"Error while sending startup data to Apitally Hub (will retry)\",\n { error },\n );\n }\n }\n }\n }\n\n private async sendSyncData() {\n this.logger.debug(\"Synchronizing data with Apitally Hub\");\n const newPayload: SyncPayload = {\n time_offset: 0,\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n requests: this.requestCounter.getAndResetRequests(),\n validation_errors:\n this.validationErrorCounter.getAndResetValidationErrors(),\n server_errors: this.serverErrorCounter.getAndResetServerErrors(),\n consumers: this.consumerRegistry.getAndResetUpdatedConsumers(),\n };\n this.syncDataQueue.push([Date.now(), newPayload]);\n\n const failedItems: [number, SyncPayload][] = [];\n while (this.syncDataQueue.length > 0) {\n const queueItem = this.syncDataQueue.shift();\n if (queueItem) {\n const [time, payload] = queueItem;\n try {\n const timeOffset = Date.now() - time;\n if (timeOffset <= MAX_QUEUE_TIME) {\n payload.time_offset = timeOffset / 1000.0; // In seconds\n await this.sendData(\"sync\", payload);\n }\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.debug(\n \"Error while synchronizing data with Apitally Hub (will retry)\",\n { error },\n );\n failedItems.push(queueItem);\n }\n }\n }\n }\n this.syncDataQueue = failedItems;\n }\n\n private handleHubError(error: unknown) {\n if (error instanceof HTTPError) {\n if (error.response.status === 404) {\n this.logger.error(`Invalid Apitally client ID: '${this.clientId}'`);\n this.stopSync();\n return true;\n }\n if (error.response.status === 422) {\n this.logger.error(\"Received validation error from Apitally Hub\");\n return true;\n }\n }\n return false;\n }\n}\n","import { ApitallyConsumer } from \"./types.js\";\n\nexport const consumerFromStringOrObject = (\n consumer: ApitallyConsumer | string,\n) => {\n if (typeof consumer === \"string\") {\n consumer = String(consumer).trim().substring(0, 128);\n return consumer ? { identifier: consumer } : null;\n } else {\n consumer.identifier = String(consumer.identifier).trim().substring(0, 128);\n consumer.name = consumer.name?.trim().substring(0, 64);\n consumer.group = consumer.group?.trim().substring(0, 64);\n return consumer.identifier ? consumer : null;\n }\n};\n\nexport default class ConsumerRegistry {\n private consumers: Map<string, ApitallyConsumer>;\n private updated: Set<string>;\n\n constructor() {\n this.consumers = new Map();\n this.updated = new Set();\n }\n\n public addOrUpdateConsumer(consumer?: ApitallyConsumer | null) {\n if (!consumer || (!consumer.name && !consumer.group)) {\n return;\n }\n const existing = this.consumers.get(consumer.identifier);\n if (!existing) {\n this.consumers.set(consumer.identifier, consumer);\n this.updated.add(consumer.identifier);\n } else {\n if (consumer.name && consumer.name !== existing.name) {\n existing.name = consumer.name;\n this.updated.add(consumer.identifier);\n }\n if (consumer.group && consumer.group !== existing.group) {\n existing.group = consumer.group;\n this.updated.add(consumer.identifier);\n }\n }\n }\n\n public getAndResetUpdatedConsumers() {\n const data: Array<ApitallyConsumer> = [];\n this.updated.forEach((identifier) => {\n const consumer = this.consumers.get(identifier);\n if (consumer) {\n data.push(consumer);\n }\n });\n this.updated.clear();\n return data;\n }\n}\n","import { createLogger, format, transports } from \"winston\";\n\nexport interface Logger {\n debug: (message: string, meta?: object) => void;\n info: (message: string, meta?: object) => void;\n warn: (message: string, meta?: object) => void;\n error: (message: string, meta?: object) => void;\n}\n\nexport const getLogger = () => {\n return createLogger({\n level: process.env.APITALLY_DEBUG ? \"debug\" : \"warn\",\n format: format.combine(\n format.colorize(),\n format.timestamp(),\n format.printf(\n (info) => `${info.timestamp} ${info.level}: ${info.message}`,\n ),\n ),\n transports: [new transports.Console()],\n });\n};\n","export function isValidClientId(clientId: string): boolean {\n const regexExp =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n return regexExp.test(clientId);\n}\n\nexport function isValidEnv(env: string): boolean {\n const regexExp = /^[\\w-]{1,32}$/;\n return regexExp.test(env);\n}\n","import { RequestInfo, RequestsItem } from \"./types.js\";\n\nexport default class RequestCounter {\n private requestCounts: Map<string, number>;\n private requestSizeSums: Map<string, number>;\n private responseSizeSums: Map<string, number>;\n private responseTimes: Map<string, Map<number, number>>;\n private requestSizes: Map<string, Map<number, number>>;\n private responseSizes: Map<string, Map<number, number>>;\n\n constructor() {\n this.requestCounts = new Map<string, number>();\n this.requestSizeSums = new Map<string, number>();\n this.responseSizeSums = new Map<string, number>();\n this.responseTimes = new Map<string, Map<number, number>>();\n this.requestSizes = new Map<string, Map<number, number>>();\n this.responseSizes = new Map<string, Map<number, number>>();\n }\n\n private getKey(requestInfo: RequestInfo) {\n return [\n requestInfo.consumer || \"\",\n requestInfo.method.toUpperCase(),\n requestInfo.path,\n requestInfo.statusCode,\n ].join(\"|\");\n }\n\n addRequest(requestInfo: RequestInfo) {\n const key = this.getKey(requestInfo);\n\n // Increment request count\n this.requestCounts.set(key, (this.requestCounts.get(key) || 0) + 1);\n\n // Add response time\n if (!this.responseTimes.has(key)) {\n this.responseTimes.set(key, new Map<number, number>());\n }\n const responseTimeMap = this.responseTimes.get(key)!;\n const responseTimeMsBin = Math.floor(requestInfo.responseTime / 10) * 10; // Rounded to nearest 10ms\n responseTimeMap.set(\n responseTimeMsBin,\n (responseTimeMap.get(responseTimeMsBin) || 0) + 1,\n );\n\n // Add request size\n if (requestInfo.requestSize !== undefined) {\n requestInfo.requestSize = Number(requestInfo.requestSize);\n this.requestSizeSums.set(\n key,\n (this.requestSizeSums.get(key) || 0) + requestInfo.requestSize,\n );\n if (!this.requestSizes.has(key)) {\n this.requestSizes.set(key, new Map<number, number>());\n }\n const requestSizeMap = this.requestSizes.get(key)!;\n const requestSizeKbBin = Math.floor(requestInfo.requestSize / 1000); // Rounded down to nearest KB\n requestSizeMap.set(\n requestSizeKbBin,\n (requestSizeMap.get(requestSizeKbBin) || 0) + 1,\n );\n }\n\n // Add response size\n if (requestInfo.responseSize !== undefined) {\n requestInfo.responseSize = Number(requestInfo.responseSize);\n this.responseSizeSums.set(\n key,\n (this.responseSizeSums.get(key) || 0) + requestInfo.responseSize,\n );\n if (!this.responseSizes.has(key)) {\n this.responseSizes.set(key, new Map<number, number>());\n }\n const responseSizeMap = this.responseSizes.get(key)!;\n const responseSizeKbBin = Math.floor(requestInfo.responseSize / 1000); // Rounded down to nearest KB\n responseSizeMap.set(\n responseSizeKbBin,\n (responseSizeMap.get(responseSizeKbBin) || 0) + 1,\n );\n }\n }\n\n getAndResetRequests() {\n const data: Array<RequestsItem> = [];\n this.requestCounts.forEach((count, key) => {\n const [consumer, method, path, statusCodeStr] = key.split(\"|\");\n const responseTimes =\n this.responseTimes.get(key) || new Map<number, number>();\n const requestSizes =\n this.requestSizes.get(key) || new Map<number, number>();\n const responseSizes =\n this.responseSizes.get(key) || new Map<number, number>();\n data.push({\n consumer: consumer || null,\n method,\n path,\n status_code: parseInt(statusCodeStr),\n request_count: count,\n request_size_sum: this.requestSizeSums.get(key) || 0,\n response_size_sum: this.responseSizeSums.get(key) || 0,\n response_times: Object.fromEntries(responseTimes),\n request_sizes: Object.fromEntries(requestSizes),\n response_sizes: Object.fromEntries(responseSizes),\n });\n });\n\n // Reset the counts and times\n this.requestCounts.clear();\n this.requestSizeSums.clear();\n this.responseSizeSums.clear();\n this.responseTimes.clear();\n this.requestSizes.clear();\n this.responseSizes.clear();\n\n return data;\n }\n}\n","import type * as Sentry from \"@sentry/node\";\nimport { createHash } from \"crypto\";\n\nimport { ConsumerMethodPath, ServerError, ServerErrorsItem } from \"./types.js\";\n\nconst MAX_MSG_LENGTH = 2048;\nconst MAX_STACKTRACE_LENGTH = 65536;\n\nexport default class ServerErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ServerError>;\n private sentryEventIds: Map<string, string>;\n private sentry: typeof Sentry | undefined;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n this.sentryEventIds = new Map();\n this.tryImportSentry();\n }\n\n public addServerError(serverError: ConsumerMethodPath & ServerError) {\n const key = this.getKey(serverError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, serverError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n this.captureSentryEventId(key);\n }\n\n public getAndResetServerErrors() {\n const data: Array<ServerErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const serverError = this.errorDetails.get(key);\n if (serverError) {\n data.push({\n consumer: serverError.consumer || null,\n method: serverError.method,\n path: serverError.path,\n type: serverError.type,\n msg: this.getTruncatedMessage(serverError.msg),\n traceback: this.getTruncatedStack(serverError.traceback),\n sentry_event_id: this.sentryEventIds.get(key) || null,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(serverError: ConsumerMethodPath & ServerError) {\n const hashInput = [\n serverError.consumer || \"\",\n serverError.method.toUpperCase(),\n serverError.path,\n serverError.type,\n serverError.msg.trim(),\n serverError.traceback.trim(),\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n\n private getTruncatedMessage(msg: string) {\n msg = msg.trim();\n if (msg.length <= MAX_MSG_LENGTH) {\n return msg;\n }\n const suffix = \"... (truncated)\";\n const cutoff = MAX_MSG_LENGTH - suffix.length;\n return msg.substring(0, cutoff) + suffix;\n }\n\n private getTruncatedStack(stack: string) {\n const suffix = \"... (truncated) ...\";\n const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;\n const lines = stack.trim().split(\"\\n\");\n const truncatedLines: string[] = [];\n let length = 0;\n for (const line of lines) {\n if (length + line.length + 1 > cutoff) {\n truncatedLines.push(suffix);\n break;\n }\n truncatedLines.push(line);\n length += line.length + 1;\n }\n return truncatedLines.join(\"\\n\");\n }\n\n private captureSentryEventId(serverErrorKey: string) {\n if (this.sentry && this.sentry.lastEventId) {\n const eventId = this.sentry.lastEventId();\n if (eventId) {\n this.sentryEventIds.set(serverErrorKey, eventId);\n }\n }\n }\n\n private async tryImportSentry() {\n try {\n this.sentry = await import(\"@sentry/node\");\n } catch (e) {\n // Sentry SDK is not installed, ignore\n }\n }\n}\n","import { createHash } from \"crypto\";\n\nimport {\n ConsumerMethodPath,\n ValidationError,\n ValidationErrorsItem,\n} from \"./types.js\";\n\nexport default class ValidationErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ValidationError>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n }\n\n public addValidationError(\n validationError: ConsumerMethodPath & ValidationError,\n ) {\n const key = this.getKey(validationError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, validationError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n }\n\n public getAndResetValidationErrors() {\n const data: Array<ValidationErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const validationError = this.errorDetails.get(key);\n if (validationError) {\n data.push({\n consumer: validationError.consumer || null,\n method: validationError.method,\n path: validationError.path,\n loc: validationError.loc.split(\".\"),\n msg: validationError.msg,\n type: validationError.type,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(validationError: ConsumerMethodPath & ValidationError) {\n const hashInput = [\n validationError.consumer || \"\",\n validationError.method.toUpperCase(),\n validationError.path,\n validationError.loc,\n validationError.msg.trim(),\n validationError.type,\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n","import { createRequire } from \"module\";\n\nexport function getPackageVersion(name: string): string | null {\n try {\n const _require = createRequire(import.meta.url);\n return _require(`${name}/package.json`).version || null;\n } catch (error) {\n return null;\n }\n}\n","// Adapted from https://github.com/AlbertoFdzM/express-list-endpoints/blob/305535d43008b46f34e18b01947762e039af6d2d/src/index.js\n\n/**\n * @typedef {Object} Route\n * @property {Object} methods\n * @property {string | string[]} path\n * @property {any[]} stack\n *\n * @typedef {Object} Endpoint\n * @property {string} path Path name\n * @property {string[]} methods Methods handled\n * @property {string[]} middlewares Mounted middlewares\n */\n\nconst regExpToParseExpressPathRegExp =\n /^\\/\\^\\\\\\/(?:(:?[\\w\\\\.-]*(?:\\\\\\/:?[\\w\\\\.-]*)*)|(\\(\\?:\\([^)]+\\)\\)))\\\\\\/.*/;\nconst regExpToReplaceExpressPathRegExpParams = /\\(\\?:\\([^)]+\\)\\)/;\nconst regexpExpressParamRegexp = /\\(\\?:\\([^)]+\\)\\)/g;\nconst regexpExpressPathParamRegexp = /(:[^)]+)\\([^)]+\\)/g;\n\nconst EXPRESS_ROOT_PATH_REGEXP_VALUE = \"/^\\\\/?(?=\\\\/|$)/i\";\nconst STACK_ITEM_VALID_NAMES = [\"router\", \"bound dispatch\", \"mounted_app\"];\n\n/**\n * Returns all the verbs detected for the passed route\n * @param {Route} route\n */\nconst getRouteMethods = function (route) {\n let methods = Object.keys(route.methods);\n\n methods = methods.filter((method) => method !== \"_all\");\n methods = methods.map((method) => method.toUpperCase());\n\n return methods;\n};\n\n/**\n * Returns the names (or anonymous) of all the middlewares attached to the\n * passed route\n * @param {Route} route\n * @returns {string[]}\n */\nconst getRouteMiddlewares = function (route) {\n return route.stack.map((item) => {\n return item.handle.name || \"anonymous\";\n });\n};\n\n/**\n * Returns true if found regexp related with express params\n * @param {string} expressPathRegExp\n * @returns {boolean}\n */\nconst hasParams = function (expressPathRegExp) {\n return regexpExpressParamRegexp.test(expressPathRegExp);\n};\n\n/**\n * @param {Route} route Express route object to be parsed\n * @param {string} basePath The basePath the route is on\n * @return {Endpoint[]} Endpoints info\n */\nconst parseExpressRoute = function (route, basePath) {\n const paths = [];\n\n if (Array.isArray(route.path)) {\n paths.push(...route.path);\n } else {\n paths.push(route.path);\n }\n\n /** @type {Endpoint[]} */\n const endpoints = paths.map((path) => {\n const completePath =\n basePath && path === \"/\" ? basePath : `${basePath}${path}`;\n\n /** @type {Endpoint} */\n const endpoint = {\n path: completePath.replace(regexpExpressPathParamRegexp, \"$1\"),\n methods: getRouteMethods(route),\n middlewares: getRouteMiddlewares(route),\n };\n\n return endpoint;\n });\n\n return endpoints;\n};\n\n/**\n * @param {RegExp} expressPathRegExp\n * @param {any[]} params\n * @returns {string}\n */\nconst parseExpressPath = function (expressPathRegExp, params) {\n let parsedRegExp = expressPathRegExp.toString();\n let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n let paramIndex = 0;\n\n while (hasParams(parsedRegExp)) {\n const paramName = params[paramIndex].name;\n const paramId = `:${paramName}`;\n\n parsedRegExp = parsedRegExp.replace(\n regExpToReplaceExpressPathRegExpParams,\n paramId,\n );\n\n paramIndex++;\n }\n\n if (parsedRegExp !== expressPathRegExp.toString()) {\n expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n }\n\n const parsedPath = expressPathRegExpExec[1].replace(/\\\\\\//g, \"/\");\n\n return parsedPath;\n};\n\n/**\n * @param {import('express').Express | import('express').Router | any} app\n * @param {string} [basePath]\n * @param {Endpoint[]} [endpoints]\n * @returns {Endpoint[]}\n */\nconst parseEndpoints = function (app, basePath, endpoints) {\n const stack = app.stack || (app._router && app._router.stack);\n\n endpoints = endpoints || [];\n basePath = basePath || \"\";\n\n if (!stack) {\n if (endpoints.length) {\n endpoints = addEndpoints(endpoints, [\n {\n path: basePath,\n methods: [],\n middlewares: [],\n },\n ]);\n }\n } else {\n endpoints = parseStack(stack, basePath, endpoints);\n }\n\n return endpoints;\n};\n\n/**\n * Ensures the path of the new endpoints isn't yet in the array.\n * If the path is already in the array merges the endpoints with the existing\n * one, if not, it adds them to the array.\n *\n * @param {Endpoint[]} currentEndpoints Array of current endpoints\n * @param {Endpoint[]} endpointsToAdd New endpoints to be added to the array\n * @returns {Endpoint[]} Updated endpoints array\n */\nconst addEndpoints = function (currentEndpoints, endpointsToAdd) {\n endpointsToAdd.forEach((newEndpoint) => {\n const existingEndpoint = currentEndpoints.find(\n (endpoint) => endpoint.path === newEndpoint.path,\n );\n\n if (existingEndpoint !== undefined) {\n const newMethods = newEndpoint.methods.filter(\n (method) => !existingEndpoint.methods.includes(method),\n );\n\n existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);\n } else {\n currentEndpoints.push(newEndpoint);\n }\n });\n\n return currentEndpoints;\n};\n\n/**\n * @param {any[]} stack\n * @param {string} basePath\n * @param {Endpoint[]} endpoints\n * @returns {Endpoint[]}\n */\nconst parseStack = function (stack, basePath, endpoints) {\n stack.forEach((stackItem) => {\n if (stackItem.route) {\n const newEndpoints = parseExpressRoute(stackItem.route, basePath);\n\n endpoints = addEndpoints(endpoints, newEndpoints);\n } else if (STACK_ITEM_VALID_NAMES.includes(stackItem.name)) {\n const isExpressPathRegexp = regExpToParseExpressPathRegExp.test(\n stackItem.regexp,\n );\n\n let newBasePath = basePath;\n\n if (isExpressPathRegexp) {\n const parsedPath = parseExpressPath(stackItem.regexp, stackItem.keys);\n\n newBasePath += `/${parsedPath}`;\n } else if (\n !stackItem.path &&\n stackItem.regexp &&\n stackItem.regexp.toString() !== EXPRESS_ROOT_PATH_REGEXP_VALUE\n ) {\n const regExpPath = ` RegExp(${stackItem.regexp}) `;\n\n newBasePath += `/${regExpPath}`;\n }\n\n endpoints = parseEndpoints(stackItem.handle, newBasePath, endpoints);\n }\n });\n\n return endpoints;\n};\n\nconst getEndpoints = function (app) {\n const endpoints = parseEndpoints(app);\n return endpoints.flatMap((route) =>\n route.methods\n .filter((method) => ![\"HEAD\", \"OPTIONS\"].includes(method.toUpperCase()))\n .map((method) => ({\n method,\n path: route.path,\n })),\n );\n};\n\nexport default getEndpoints;\n"],"mappings":";;;;;;AACA,SAASA,mBAAmB;;;ACD5B,SAASC,kBAAkB;AAC3B,OAAOC,gBAAgB;;;ACChB,IAAMC,6BAA6B,wBACxCC,aAAAA;AADF,MAAAC,KAAA;AAGE,MAAI,OAAOD,aAAa,UAAU;AAChCA,eAAWE,OAAOF,QAAAA,EAAUG,KAAI,EAAGC,UAAU,GAAG,GAAA;AAChD,WAAOJ,WAAW;MAAEK,YAAYL;IAAS,IAAI;EAC/C,OAAO;AACLA,aAASK,aAAaH,OAAOF,SAASK,UAAU,EAAEF,KAAI,EAAGC,UAAU,GAAG,GAAA;AACtEJ,aAASM,QAAON,MAAAA,SAASM,SAATN,gBAAAA,IAAeG,OAAOC,UAAU,GAAG;AACnDJ,aAASO,SAAQP,cAASO,UAATP,mBAAgBG,OAAOC,UAAU,GAAG;AACrD,WAAOJ,SAASK,aAAaL,WAAW;EAC1C;AACF,GAZ0C;AAc1C,IAAqBQ,oBAArB,MAAqBA,kBAAAA;EACXC;EACAC;EAERC,cAAc;AACZ,SAAKF,YAAY,oBAAIG,IAAAA;AACrB,SAAKF,UAAU,oBAAIG,IAAAA;EACrB;EAEOC,oBAAoBd,UAAoC;AAC7D,QAAI,CAACA,YAAa,CAACA,SAASM,QAAQ,CAACN,SAASO,OAAQ;AACpD;IACF;AACA,UAAMQ,WAAW,KAAKN,UAAUO,IAAIhB,SAASK,UAAU;AACvD,QAAI,CAACU,UAAU;AACb,WAAKN,UAAUQ,IAAIjB,SAASK,YAAYL,QAAAA;AACxC,WAAKU,QAAQQ,IAAIlB,SAASK,UAAU;IACtC,OAAO;AACL,UAAIL,SAASM,QAAQN,SAASM,SAASS,SAAST,MAAM;AACpDS,iBAAST,OAAON,SAASM;AACzB,aAAKI,QAAQQ,IAAIlB,SAASK,UAAU;MACtC;AACA,UAAIL,SAASO,SAASP,SAASO,UAAUQ,SAASR,OAAO;AACvDQ,iBAASR,QAAQP,SAASO;AAC1B,aAAKG,QAAQQ,IAAIlB,SAASK,UAAU;MACtC;IACF;EACF;EAEOc,8BAA8B;AACnC,UAAMC,OAAgC,CAAA;AACtC,SAAKV,QAAQW,QAAQ,CAAChB,eAAAA;AACpB,YAAML,WAAW,KAAKS,UAAUO,IAAIX,UAAAA;AACpC,UAAIL,UAAU;AACZoB,aAAKE,KAAKtB,QAAAA;MACZ;IACF,CAAA;AACA,SAAKU,QAAQa,MAAK;AAClB,WAAOH;EACT;AACF;AAxCqBZ;AAArB,IAAqBA,mBAArB;;;AChBA,SAASgB,cAAcC,QAAQC,kBAAkB;AAS1C,IAAMC,YAAY,6BAAA;AACvB,SAAOC,aAAa;IAClBC,OAAOC,QAAQC,IAAIC,iBAAiB,UAAU;IAC9CC,QAAQA,OAAOC,QACbD,OAAOE,SAAQ,GACfF,OAAOG,UAAS,GAChBH,OAAOI,OACL,CAACC,SAAS,GAAGA,KAAKF,SAAS,IAAIE,KAAKT,KAAK,KAAKS,KAAKC,OAAO,EAAE,CAAA;IAGhEC,YAAY;MAAC,IAAIA,WAAWC,QAAO;;EACrC,CAAA;AACF,GAZyB;;;ACTlB,SAASC,gBAAgBC,UAAgB;AAC9C,QAAMC,WACJ;AACF,SAAOA,SAASC,KAAKF,QAAAA;AACvB;AAJgBD;AAMT,SAASI,WAAWC,KAAW;AACpC,QAAMH,WAAW;AACjB,SAAOA,SAASC,KAAKE,GAAAA;AACvB;AAHgBD;;;ACJhB,IAAqBE,kBAArB,MAAqBA,gBAAAA;EACXC;EACAC;EACAC;EACAC;EACAC;EACAC;EAERC,cAAc;AACZ,SAAKN,gBAAgB,oBAAIO,IAAAA;AACzB,SAAKN,kBAAkB,oBAAIM,IAAAA;AAC3B,SAAKL,mBAAmB,oBAAIK,IAAAA;AAC5B,SAAKJ,gBAAgB,oBAAII,IAAAA;AACzB,SAAKH,eAAe,oBAAIG,IAAAA;AACxB,SAAKF,gBAAgB,oBAAIE,IAAAA;EAC3B;EAEQC,OAAOC,aAA0B;AACvC,WAAO;MACLA,YAAYC,YAAY;MACxBD,YAAYE,OAAOC,YAAW;MAC9BH,YAAYI;MACZJ,YAAYK;MACZC,KAAK,GAAA;EACT;EAEAC,WAAWP,aAA0B;AACnC,UAAMQ,MAAM,KAAKT,OAAOC,WAAAA;AAGxB,SAAKT,cAAckB,IAAID,MAAM,KAAKjB,cAAcmB,IAAIF,GAAAA,KAAQ,KAAK,CAAA;AAGjE,QAAI,CAAC,KAAKd,cAAciB,IAAIH,GAAAA,GAAM;AAChC,WAAKd,cAAce,IAAID,KAAK,oBAAIV,IAAAA,CAAAA;IAClC;AACA,UAAMc,kBAAkB,KAAKlB,cAAcgB,IAAIF,GAAAA;AAC/C,UAAMK,oBAAoBC,KAAKC,MAAMf,YAAYgB,eAAe,EAAA,IAAM;AACtEJ,oBAAgBH,IACdI,oBACCD,gBAAgBF,IAAIG,iBAAAA,KAAsB,KAAK,CAAA;AAIlD,QAAIb,YAAYiB,gBAAgBC,QAAW;AACzClB,kBAAYiB,cAAcE,OAAOnB,YAAYiB,WAAW;AACxD,WAAKzB,gBAAgBiB,IACnBD,MACC,KAAKhB,gBAAgBkB,IAAIF,GAAAA,KAAQ,KAAKR,YAAYiB,WAAW;AAEhE,UAAI,CAAC,KAAKtB,aAAagB,IAAIH,GAAAA,GAAM;AAC/B,aAAKb,aAAac,IAAID,KAAK,oBAAIV,IAAAA,CAAAA;MACjC;AACA,YAAMsB,iBAAiB,KAAKzB,aAAae,IAAIF,GAAAA;AAC7C,YAAMa,mBAAmBP,KAAKC,MAAMf,YAAYiB,cAAc,GAAA;AAC9DG,qBAAeX,IACbY,mBACCD,eAAeV,IAAIW,gBAAAA,KAAqB,KAAK,CAAA;IAElD;AAGA,QAAIrB,YAAYsB,iBAAiBJ,QAAW;AAC1ClB,kBAAYsB,eAAeH,OAAOnB,YAAYsB,YAAY;AAC1D,WAAK7B,iBAAiBgB,IACpBD,MACC,KAAKf,iBAAiBiB,IAAIF,GAAAA,KAAQ,KAAKR,YAAYsB,YAAY;AAElE,UAAI,CAAC,KAAK1B,cAAce,IAAIH,GAAAA,GAAM;AAChC,aAAKZ,cAAca,IAAID,KAAK,oBAAIV,IAAAA,CAAAA;MAClC;AACA,YAAMyB,kBAAkB,KAAK3B,cAAcc,IAAIF,GAAAA;AAC/C,YAAMgB,oBAAoBV,KAAKC,MAAMf,YAAYsB,eAAe,GAAA;AAChEC,sBAAgBd,IACde,oBACCD,gBAAgBb,IAAIc,iBAAAA,KAAsB,KAAK,CAAA;IAEpD;EACF;EAEAC,sBAAsB;AACpB,UAAMC,OAA4B,CAAA;AAClC,SAAKnC,cAAcoC,QAAQ,CAACC,OAAOpB,QAAAA;AACjC,YAAM,CAACP,UAAUC,QAAQE,MAAMyB,aAAAA,IAAiBrB,IAAIsB,MAAM,GAAA;AAC1D,YAAMpC,gBACJ,KAAKA,cAAcgB,IAAIF,GAAAA,KAAQ,oBAAIV,IAAAA;AACrC,YAAMH,eACJ,KAAKA,aAAae,IAAIF,GAAAA,KAAQ,oBAAIV,IAAAA;AACpC,YAAMF,gBACJ,KAAKA,cAAcc,IAAIF,GAAAA,KAAQ,oBAAIV,IAAAA;AACrC4B,WAAKK,KAAK;QACR9B,UAAUA,YAAY;QACtBC;QACAE;QACA4B,aAAaC,SAASJ,aAAAA;QACtBK,eAAeN;QACfO,kBAAkB,KAAK3C,gBAAgBkB,IAAIF,GAAAA,KAAQ;QACnD4B,mBAAmB,KAAK3C,iBAAiBiB,IAAIF,GAAAA,KAAQ;QACrD6B,gBAAgBC,OAAOC,YAAY7C,aAAAA;QACnC8C,eAAeF,OAAOC,YAAY5C,YAAAA;QAClC8C,gBAAgBH,OAAOC,YAAY3C,aAAAA;MACrC,CAAA;IACF,CAAA;AAGA,SAAKL,cAAcmD,MAAK;AACxB,SAAKlD,gBAAgBkD,MAAK;AAC1B,SAAKjD,iBAAiBiD,MAAK;AAC3B,SAAKhD,cAAcgD,MAAK;AACxB,SAAK/C,aAAa+C,MAAK;AACvB,SAAK9C,cAAc8C,MAAK;AAExB,WAAOhB;EACT;AACF;AAlHqBpC;AAArB,IAAqBA,iBAArB;;;ACDA,SAASqD,kBAAkB;AAI3B,IAAMC,iBAAiB;AACvB,IAAMC,wBAAwB;AAE9B,IAAqBC,sBAArB,MAAqBA,oBAAAA;EACXC;EACAC;EACAC;EACAC;EAERC,cAAc;AACZ,SAAKJ,cAAc,oBAAIK,IAAAA;AACvB,SAAKJ,eAAe,oBAAII,IAAAA;AACxB,SAAKH,iBAAiB,oBAAIG,IAAAA;AAC1B,SAAKC,gBAAe;EACtB;EAEOC,eAAeC,aAA+C;AACnE,UAAMC,MAAM,KAAKC,OAAOF,WAAAA;AACxB,QAAI,CAAC,KAAKP,aAAaU,IAAIF,GAAAA,GAAM;AAC/B,WAAKR,aAAaW,IAAIH,KAAKD,WAAAA;IAC7B;AACA,SAAKR,YAAYY,IAAIH,MAAM,KAAKT,YAAYa,IAAIJ,GAAAA,KAAQ,KAAK,CAAA;AAC7D,SAAKK,qBAAqBL,GAAAA;EAC5B;EAEOM,0BAA0B;AAC/B,UAAMC,OAAgC,CAAA;AACtC,SAAKhB,YAAYiB,QAAQ,CAACC,OAAOT,QAAAA;AAC/B,YAAMD,cAAc,KAAKP,aAAaY,IAAIJ,GAAAA;AAC1C,UAAID,aAAa;AACfQ,aAAKG,KAAK;UACRC,UAAUZ,YAAYY,YAAY;UAClCC,QAAQb,YAAYa;UACpBC,MAAMd,YAAYc;UAClBC,MAAMf,YAAYe;UAClBC,KAAK,KAAKC,oBAAoBjB,YAAYgB,GAAG;UAC7CE,WAAW,KAAKC,kBAAkBnB,YAAYkB,SAAS;UACvDE,iBAAiB,KAAK1B,eAAeW,IAAIJ,GAAAA,KAAQ;UACjDoB,aAAaX;QACf,CAAA;MACF;IACF,CAAA;AACA,SAAKlB,YAAY8B,MAAK;AACtB,SAAK7B,aAAa6B,MAAK;AACvB,WAAOd;EACT;EAEQN,OAAOF,aAA+C;AAC5D,UAAMuB,YAAY;MAChBvB,YAAYY,YAAY;MACxBZ,YAAYa,OAAOW,YAAW;MAC9BxB,YAAYc;MACZd,YAAYe;MACZf,YAAYgB,IAAIS,KAAI;MACpBzB,YAAYkB,UAAUO,KAAI;MAC1BC,KAAK,GAAA;AACP,WAAOC,WAAW,KAAA,EAAOC,OAAOL,SAAAA,EAAWM,OAAO,KAAA;EACpD;EAEQZ,oBAAoBD,KAAa;AACvCA,UAAMA,IAAIS,KAAI;AACd,QAAIT,IAAIc,UAAUzC,gBAAgB;AAChC,aAAO2B;IACT;AACA,UAAMe,SAAS;AACf,UAAMC,SAAS3C,iBAAiB0C,OAAOD;AACvC,WAAOd,IAAIiB,UAAU,GAAGD,MAAAA,IAAUD;EACpC;EAEQZ,kBAAkBe,OAAe;AACvC,UAAMH,SAAS;AACf,UAAMC,SAAS1C,wBAAwByC,OAAOD;AAC9C,UAAMK,QAAQD,MAAMT,KAAI,EAAGW,MAAM,IAAA;AACjC,UAAMC,iBAA2B,CAAA;AACjC,QAAIP,SAAS;AACb,eAAWQ,QAAQH,OAAO;AACxB,UAAIL,SAASQ,KAAKR,SAAS,IAAIE,QAAQ;AACrCK,uBAAe1B,KAAKoB,MAAAA;AACpB;MACF;AACAM,qBAAe1B,KAAK2B,IAAAA;AACpBR,gBAAUQ,KAAKR,SAAS;IAC1B;AACA,WAAOO,eAAeX,KAAK,IAAA;EAC7B;EAEQpB,qBAAqBiC,gBAAwB;AACnD,QAAI,KAAK5C,UAAU,KAAKA,OAAO6C,aAAa;AAC1C,YAAMC,UAAU,KAAK9C,OAAO6C,YAAW;AACvC,UAAIC,SAAS;AACX,aAAK/C,eAAeU,IAAImC,gBAAgBE,OAAAA;MAC1C;IACF;EACF;EAEA,MAAc3C,kBAAkB;AAC9B,QAAI;AACF,WAAKH,SAAS,MAAM,OAAO,cAAA;IAC7B,SAAS+C,GAAG;IAEZ;EACF;AACF;AAnGqBnD;AAArB,IAAqBA,qBAArB;;;ACRA,SAASoD,cAAAA,mBAAkB;AAQ3B,IAAqBC,0BAArB,MAAqBA,wBAAAA;EACXC;EACAC;EAERC,cAAc;AACZ,SAAKF,cAAc,oBAAIG,IAAAA;AACvB,SAAKF,eAAe,oBAAIE,IAAAA;EAC1B;EAEOC,mBACLC,iBACA;AACA,UAAMC,MAAM,KAAKC,OAAOF,eAAAA;AACxB,QAAI,CAAC,KAAKJ,aAAaO,IAAIF,GAAAA,GAAM;AAC/B,WAAKL,aAAaQ,IAAIH,KAAKD,eAAAA;IAC7B;AACA,SAAKL,YAAYS,IAAIH,MAAM,KAAKN,YAAYU,IAAIJ,GAAAA,KAAQ,KAAK,CAAA;EAC/D;EAEOK,8BAA8B;AACnC,UAAMC,OAAoC,CAAA;AAC1C,SAAKZ,YAAYa,QAAQ,CAACC,OAAOR,QAAAA;AAC/B,YAAMD,kBAAkB,KAAKJ,aAAaS,IAAIJ,GAAAA;AAC9C,UAAID,iBAAiB;AACnBO,aAAKG,KAAK;UACRC,UAAUX,gBAAgBW,YAAY;UACtCC,QAAQZ,gBAAgBY;UACxBC,MAAMb,gBAAgBa;UACtBC,KAAKd,gBAAgBc,IAAIC,MAAM,GAAA;UAC/BC,KAAKhB,gBAAgBgB;UACrBC,MAAMjB,gBAAgBiB;UACtBC,aAAaT;QACf,CAAA;MACF;IACF,CAAA;AACA,SAAKd,YAAYwB,MAAK;AACtB,SAAKvB,aAAauB,MAAK;AACvB,WAAOZ;EACT;EAEQL,OAAOF,iBAAuD;AACpE,UAAMoB,YAAY;MAChBpB,gBAAgBW,YAAY;MAC5BX,gBAAgBY,OAAOS,YAAW;MAClCrB,gBAAgBa;MAChBb,gBAAgBc;MAChBd,gBAAgBgB,IAAIM,KAAI;MACxBtB,gBAAgBiB;MAChBM,KAAK,GAAA;AACP,WAAOC,YAAW,KAAA,EAAOC,OAAOL,SAAAA,EAAWM,OAAO,KAAA;EACpD;AACF;AAnDqBhC;AAArB,IAAqBA,yBAArB;;;ANOA,IAAMiC,gBAAgB;AACtB,IAAMC,wBAAwB;AAC9B,IAAMC,iCAAiC;AACvC,IAAMC,iBAAiB;AAlBvB;AAoBA,IAAMC,aAAN,mBAAwBC,MAAAA;EACfC;EAEPC,YAAYD,UAAoB;AAC9B,UAAME,SAASF,SAASG,SACpB,eAAeH,SAASG,MAAM,KAC9B;AACJ,UAAM,uBAAuBD,MAAAA,EAAQ;AACrC,SAAKF,WAAWA;EAClB;AACF,GAVwBD,yBAAxB;AAYO,IAAMK,kBAAN,MAAMA,gBAAAA;EACHC;EACAC;EAGAC;EACAC;EACAC;EACDC;EACCC,kBAA2B;EAE5BC;EACAC;EACAC;EACAC;EACAC;EAEPf,YAAY,EAAEI,UAAUC,MAAM,OAAOU,OAAM,GAAoB;AAC7D,QAAIZ,gBAAea,UAAU;AAC3B,YAAM,IAAIlB,MAAM,wCAAA;IAClB;AACA,QAAI,CAACmB,gBAAgBb,QAAAA,GAAW;AAC9B,YAAM,IAAIN,MACR,sBAAsBM,QAAAA,uCAA+C;IAEzE;AACA,QAAI,CAACc,WAAWb,GAAAA,GAAM;AACpB,YAAM,IAAIP,MACR,gBAAgBO,GAAAA,uEAA0E;IAE9F;AAEAF,oBAAea,WAAW;AAC1B,SAAKZ,WAAWA;AAChB,SAAKC,MAAMA;AACX,SAAKC,eAAea,WAAAA;AACpB,SAAKZ,gBAAgB,CAAA;AACrB,SAAKI,iBAAiB,IAAIS,eAAAA;AAC1B,SAAKR,yBAAyB,IAAIS,uBAAAA;AAClC,SAAKR,qBAAqB,IAAIS,mBAAAA;AAC9B,SAAKR,mBAAmB,IAAIS,iBAAAA;AAC5B,SAAKR,SAASA,UAAUS,UAAAA;AAExB,SAAKC,UAAS;AACd,SAAKC,iBAAiB,KAAKA,eAAeC,KAAK,IAAI;EACrD;EAEA,OAAcC,cAAc;AAC1B,QAAI,CAACzB,gBAAea,UAAU;AAC5B,YAAM,IAAIlB,MAAM,oCAAA;IAClB;AACA,WAAOK,gBAAea;EACxB;EAEA,aAAoBa,WAAW;AAC7B,QAAI1B,gBAAea,UAAU;AAC3B,YAAMb,gBAAea,SAASU,eAAc;IAC9C;EACF;EAEA,MAAaA,iBAAiB;AAC5B,SAAKI,SAAQ;AACb,UAAM,KAAKC,aAAY;AACvB5B,oBAAea,WAAWgB;EAC5B;EAEQC,kBAAkB;AACxB,UAAMC,UACJC,QAAQ9B,IAAI+B,yBAAyB;AACvC,UAAMC,UAAU;AAChB,WAAO,GAAGH,OAAAA,IAAWG,OAAAA,IAAW,KAAKjC,QAAQ,IAAI,KAAKC,GAAG;EAC3D;EAEA,MAAciC,SAASC,KAAaC,SAAc;AAChD,UAAMC,iBAAiBC,WAAWC,OAAO;MACvCC,SAAS;MACTC,YAAY;MACZC,SAAS;QAAC;QAAK;QAAK;QAAK;QAAK;QAAK;;IACrC,CAAA;AACA,UAAM/C,WAAW,MAAM0C,eAAe,KAAKR,gBAAe,IAAKM,KAAK;MAClEQ,QAAQ;MACRC,MAAMC,KAAKC,UAAUV,OAAAA;MACrBW,SAAS;QAAE,gBAAgB;MAAmB;IAChD,CAAA;AACA,QAAI,CAACpD,SAASqD,IAAI;AAChB,YAAM,IAAIvD,UAAUE,QAAAA;IACtB;EACF;EAEQ0B,YAAY;AAClB,SAAK4B,KAAI;AACT,SAAK7C,iBAAiB8C,YAAY,MAAA;AAChC,WAAKD,KAAI;IACX,GAAG3D,qBAAAA;AACH6D,eAAW,MAAA;AACTC,oBAAc,KAAKhD,cAAc;AACjC,WAAKA,iBAAiB8C,YAAY,MAAA;AAChC,aAAKD,KAAI;MACX,GAAG5D,aAAAA;IACL,GAAGE,8BAAAA;EACL;EAEA,MAAc0D,OAAO;AACnB,QAAI;AACF,YAAMI,WAAW;QAAC,KAAK1B,aAAY;;AACnC,UAAI,CAAC,KAAKrB,iBAAiB;AACzB+C,iBAASC,KAAK,KAAKC,gBAAe,CAAA;MACpC;AACA,YAAMC,QAAQC,IAAIJ,QAAAA;IACpB,SAASK,OAAO;AACd,WAAK/C,OAAO+C,MAAM,yCAAyC;QACzDA;MACF,CAAA;IACF;EACF;EAEQhC,WAAW;AACjB,QAAI,KAAKtB,gBAAgB;AACvBgD,oBAAc,KAAKhD,cAAc;AACjC,WAAKA,iBAAiBwB;IACxB;EACF;EAEO+B,eAAeC,MAAmB;AACvC,SAAKvD,cAAcuD;AACnB,SAAKtD,kBAAkB;AACvB,SAAKiD,gBAAe;EACtB;EAEA,MAAcA,kBAAkB;AAC9B,QAAI,KAAKlD,aAAa;AACpB,WAAKM,OAAOkD,MAAM,sCAAA;AAClB,YAAMzB,UAA0B;QAC9B0B,eAAe,KAAK5D;QACpB6D,cAAchD,WAAAA;QACd,GAAG,KAAKV;MACV;AACA,UAAI;AACF,cAAM,KAAK6B,SAAS,WAAWE,OAAAA;AAC/B,aAAK9B,kBAAkB;MACzB,SAASoD,OAAO;AACd,cAAMM,UAAU,KAAKC,eAAeP,KAAAA;AACpC,YAAI,CAACM,SAAS;AACZ,eAAKrD,OAAO+C,MAAOA,MAAgBQ,OAAO;AAC1C,eAAKvD,OAAOkD,MACV,iEACA;YAAEH;UAAM,CAAA;QAEZ;MACF;IACF;EACF;EAEA,MAAc/B,eAAe;AAC3B,SAAKhB,OAAOkD,MAAM,sCAAA;AAClB,UAAMM,aAA0B;MAC9BC,aAAa;MACbN,eAAe,KAAK5D;MACpB6D,cAAchD,WAAAA;MACdsD,UAAU,KAAK9D,eAAe+D,oBAAmB;MACjDC,mBACE,KAAK/D,uBAAuBgE,4BAA2B;MACzDC,eAAe,KAAKhE,mBAAmBiE,wBAAuB;MAC9DC,WAAW,KAAKjE,iBAAiBkE,4BAA2B;IAC9D;AACA,SAAKzE,cAAcmD,KAAK;MAACuB,KAAKC,IAAG;MAAIX;KAAW;AAEhD,UAAMY,cAAuC,CAAA;AAC7C,WAAO,KAAK5E,cAAc6E,SAAS,GAAG;AACpC,YAAMC,YAAY,KAAK9E,cAAc+E,MAAK;AAC1C,UAAID,WAAW;AACb,cAAM,CAACE,MAAM/C,OAAAA,IAAW6C;AACxB,YAAI;AACF,gBAAMG,aAAaP,KAAKC,IAAG,IAAKK;AAChC,cAAIC,cAAc5F,gBAAgB;AAChC4C,oBAAQgC,cAAcgB,aAAa;AACnC,kBAAM,KAAKlD,SAAS,QAAQE,OAAAA;UAC9B;QACF,SAASsB,OAAO;AACd,gBAAMM,UAAU,KAAKC,eAAeP,KAAAA;AACpC,cAAI,CAACM,SAAS;AACZ,iBAAKrD,OAAOkD,MACV,iEACA;cAAEH;YAAM,CAAA;AAEVqB,wBAAYzB,KAAK2B,SAAAA;UACnB;QACF;MACF;IACF;AACA,SAAK9E,gBAAgB4E;EACvB;EAEQd,eAAeP,OAAgB;AACrC,QAAIA,iBAAiBjE,WAAW;AAC9B,UAAIiE,MAAM/D,SAASG,WAAW,KAAK;AACjC,aAAKa,OAAO+C,MAAM,gCAAgC,KAAK1D,QAAQ,GAAG;AAClE,aAAK0B,SAAQ;AACb,eAAO;MACT;AACA,UAAIgC,MAAM/D,SAASG,WAAW,KAAK;AACjC,aAAKa,OAAO+C,MAAM,6CAAA;AAClB,eAAO;MACT;IACF;AACA,WAAO;EACT;AACF;AA/Ma3D;AAIX,cAJWA,iBAIIa;AAJV,IAAMb,iBAAN;;;AOhCP,SAASsF,qBAAqB;AAEvB,SAASC,kBAAkBC,MAAY;AAC5C,MAAI;AACF,UAAMC,WAAWC,cAAc,YAAYC,GAAG;AAC9C,WAAOF,SAAS,GAAGD,IAAAA,eAAmB,EAAEI,WAAW;EACrD,SAASC,OAAO;AACd,WAAO;EACT;AACF;AAPgBN;;;ACYhB,IAAMO,iCACJ;AACF,IAAMC,yCAAyC;AAC/C,IAAMC,2BAA2B;AACjC,IAAMC,+BAA+B;AAErC,IAAMC,iCAAiC;AACvC,IAAMC,yBAAyB;EAAC;EAAU;EAAkB;;AAM5D,IAAMC,kBAAkB,gCAAUC,OAAK;AACrC,MAAIC,UAAUC,OAAOC,KAAKH,MAAMC,OAAO;AAEvCA,YAAUA,QAAQG,OAAO,CAACC,WAAWA,WAAW,MAAA;AAChDJ,YAAUA,QAAQK,IAAI,CAACD,WAAWA,OAAOE,YAAW,CAAA;AAEpD,SAAON;AACT,GAPwB;AAexB,IAAMO,sBAAsB,gCAAUR,OAAK;AACzC,SAAOA,MAAMS,MAAMH,IAAI,CAACI,SAAAA;AACtB,WAAOA,KAAKC,OAAOC,QAAQ;EAC7B,CAAA;AACF,GAJ4B;AAW5B,IAAMC,YAAY,gCAAUC,mBAAiB;AAC3C,SAAOnB,yBAAyBoB,KAAKD,iBAAAA;AACvC,GAFkB;AASlB,IAAME,oBAAoB,gCAAUhB,OAAOiB,UAAQ;AACjD,QAAMC,QAAQ,CAAA;AAEd,MAAIC,MAAMC,QAAQpB,MAAMqB,IAAI,GAAG;AAC7BH,UAAMI,KAAI,GAAItB,MAAMqB,IAAI;EAC1B,OAAO;AACLH,UAAMI,KAAKtB,MAAMqB,IAAI;EACvB;AAGA,QAAME,YAAYL,MAAMZ,IAAI,CAACe,SAAAA;AAC3B,UAAMG,eACJP,YAAYI,SAAS,MAAMJ,WAAW,GAAGA,QAAAA,GAAWI,IAAAA;AAGtD,UAAMI,WAAW;MACfJ,MAAMG,aAAaE,QAAQ9B,8BAA8B,IAAA;MACzDK,SAASF,gBAAgBC,KAAAA;MACzB2B,aAAanB,oBAAoBR,KAAAA;IACnC;AAEA,WAAOyB;EACT,CAAA;AAEA,SAAOF;AACT,GAzB0B;AAgC1B,IAAMK,mBAAmB,gCAAUd,mBAAmBe,QAAM;AAC1D,MAAIC,eAAehB,kBAAkBiB,SAAQ;AAC7C,MAAIC,wBAAwBvC,+BAA+BwC,KAAKH,YAAAA;AAChE,MAAII,aAAa;AAEjB,SAAOrB,UAAUiB,YAAAA,GAAe;AAC9B,UAAMK,YAAYN,OAAOK,UAAAA,EAAYtB;AACrC,UAAMwB,UAAU,IAAID,SAAAA;AAEpBL,mBAAeA,aAAaJ,QAC1BhC,wCACA0C,OAAAA;AAGFF;EACF;AAEA,MAAIJ,iBAAiBhB,kBAAkBiB,SAAQ,GAAI;AACjDC,4BAAwBvC,+BAA+BwC,KAAKH,YAAAA;EAC9D;AAEA,QAAMO,aAAaL,sBAAsB,CAAA,EAAGN,QAAQ,SAAS,GAAA;AAE7D,SAAOW;AACT,GAxByB;AAgCzB,IAAMC,iBAAiB,gCAAUC,KAAKtB,UAAUM,WAAS;AACvD,QAAMd,QAAQ8B,IAAI9B,SAAU8B,IAAIC,WAAWD,IAAIC,QAAQ/B;AAEvDc,cAAYA,aAAa,CAAA;AACzBN,aAAWA,YAAY;AAEvB,MAAI,CAACR,OAAO;AACV,QAAIc,UAAUkB,QAAQ;AACpBlB,kBAAYmB,aAAanB,WAAW;QAClC;UACEF,MAAMJ;UACNhB,SAAS,CAAA;UACT0B,aAAa,CAAA;QACf;OACD;IACH;EACF,OAAO;AACLJ,gBAAYoB,WAAWlC,OAAOQ,UAAUM,SAAAA;EAC1C;AAEA,SAAOA;AACT,GArBuB;AAgCvB,IAAMmB,eAAe,gCAAUE,kBAAkBC,gBAAc;AAC7DA,iBAAeC,QAAQ,CAACC,gBAAAA;AACtB,UAAMC,mBAAmBJ,iBAAiBK,KACxC,CAACxB,aAAaA,SAASJ,SAAS0B,YAAY1B,IAAI;AAGlD,QAAI2B,qBAAqBE,QAAW;AAClC,YAAMC,aAAaJ,YAAY9C,QAAQG,OACrC,CAACC,WAAW,CAAC2C,iBAAiB/C,QAAQmD,SAAS/C,MAAAA,CAAAA;AAGjD2C,uBAAiB/C,UAAU+C,iBAAiB/C,QAAQoD,OAAOF,UAAAA;IAC7D,OAAO;AACLP,uBAAiBtB,KAAKyB,WAAAA;IACxB;EACF,CAAA;AAEA,SAAOH;AACT,GAlBqB;AA0BrB,IAAMD,aAAa,gCAAUlC,OAAOQ,UAAUM,WAAS;AACrDd,QAAMqC,QAAQ,CAACQ,cAAAA;AACb,QAAIA,UAAUtD,OAAO;AACnB,YAAMuD,eAAevC,kBAAkBsC,UAAUtD,OAAOiB,QAAAA;AAExDM,kBAAYmB,aAAanB,WAAWgC,YAAAA;IACtC,WAAWzD,uBAAuBsD,SAASE,UAAU1C,IAAI,GAAG;AAC1D,YAAM4C,sBAAsB/D,+BAA+BsB,KACzDuC,UAAUG,MAAM;AAGlB,UAAIC,cAAczC;AAElB,UAAIuC,qBAAqB;AACvB,cAAMnB,aAAaT,iBAAiB0B,UAAUG,QAAQH,UAAUnD,IAAI;AAEpEuD,uBAAe,IAAIrB,UAAAA;MACrB,WACE,CAACiB,UAAUjC,QACXiC,UAAUG,UACVH,UAAUG,OAAO1B,SAAQ,MAAOlC,gCAChC;AACA,cAAM8D,aAAa,WAAWL,UAAUG,MAAM;AAE9CC,uBAAe,IAAIC,UAAAA;MACrB;AAEApC,kBAAYe,eAAegB,UAAU3C,QAAQ+C,aAAanC,SAAAA;IAC5D;EACF,CAAA;AAEA,SAAOA;AACT,GAhCmB;AAkCnB,IAAMqC,eAAe,gCAAUrB,KAAG;AAChC,QAAMhB,YAAYe,eAAeC,GAAAA;AACjC,SAAOhB,UAAUsC,QAAQ,CAAC7D,UACxBA,MAAMC,QACHG,OAAO,CAACC,WAAW,CAAC;IAAC;IAAQ;IAAW+C,SAAS/C,OAAOE,YAAW,CAAA,CAAA,EACnED,IAAI,CAACD,YAAY;IAChBA;IACAgB,MAAMrB,MAAMqB;EACd,EAAA,CAAA;AAEN,GAVqB;AAYrB,IAAA,wBAAeuC;;;ATjNR,IAAME,cAAc,wBAACC,KAAuBC,WAAAA;AACjD,QAAMC,SAAS,IAAIC,eAAeF,MAAAA;AAClC,QAAMG,aAAaC,cAAcL,KAAKE,MAAAA;AACtCF,MAAIM,IAAIF,UAAAA;AACRG,aAAW,MAAA;AACTL,WAAOM,eAAeC,WAAWT,KAAKC,OAAOS,UAAU,CAAA;EACzD,GAAG,GAAA;AACL,GAP2B;AAS3B,IAAML,gBAAgB,wBAACL,KAAuBE,WAAAA;AAC5C,QAAMS,qBAAqBC,kBAAkB,mBAAA,MAAyB;AACtE,QAAMC,qBAAqBD,kBAAkB,WAAA,MAAiB;AAC9D,QAAME,gBAAgBF,kBAAkB,cAAA,MAAoB;AAC5D,QAAMG,0BAA0BH,kBAAkB,iBAAA,MAAuB;AACzE,MAAII,yBAAyB;AAE7B,SAAO,CAACC,KAAcC,KAAeC,SAAAA;AACnC,QAAI,CAACH,wBAAwB;AAE3BhB,UAAIM,IACF,CAACc,KAAYH,MAAcC,MAAeC,UAAAA;AACxCD,QAAAA,KAAIG,OAAOC,cAAcF;AACzBD,QAAAA,MAAKC,GAAAA;MACP,CAAA;AAEFJ,+BAAyB;IAC3B;AACA,QAAI;AACF,YAAMO,YAAYC,YAAYC,IAAG;AACjC,YAAMC,eAAeR,IAAIS;AACzBT,UAAIS,OAAO,CAACC,SAAAA;AACVV,YAAIG,OAAOO,OAAOA;AAClB,eAAOF,aAAaG,KAAKX,KAAKU,IAAAA;MAChC;AACAV,UAAIY,GAAG,UAAU,MAAA;AACf,YAAI;AACF,cAAIb,IAAIc,OAAO;AACb,kBAAMC,eAAeR,YAAYC,IAAG,IAAKF;AACzC,kBAAMU,WAAWC,YAAYjB,GAAAA;AAC7Bf,mBAAOiC,iBAAiBC,oBAAoBH,QAAAA;AAC5C/B,mBAAOmC,eAAeC,WAAW;cAC/BL,UAAUA,qCAAUM;cACpBC,QAAQvB,IAAIuB;cACZC,MAAMxB,IAAIc,MAAMU;cAChBC,YAAYxB,IAAIwB;cAChBV;cACAW,aAAa1B,IAAI2B,IAAI,gBAAA;cACrBC,cAAc3B,IAAI0B,IAAI,gBAAA;YACxB,CAAA;AACA,iBACG1B,IAAIwB,eAAe,OAAOxB,IAAIwB,eAAe,QAC9CxB,IAAIG,OAAOO,MACX;AACA,oBAAMkB,mBAAsC,CAAA;AAC5C,kBAAInC,oBAAoB;AACtBmC,iCAAiBC,KAAI,GAChBC,8BAA8B9B,IAAIG,OAAOO,IAAI,CAAA;cAEpD;AACA,kBAAIf,oBAAoB;AACtBiC,iCAAiBC,KAAI,GAChBE,uBAAuB/B,IAAIG,OAAOO,IAAI,CAAA;cAE7C;AACA,kBAAId,iBAAiBC,yBAAyB;AAC5C+B,iCAAiBC,KAAI,GAChBG,4BAA4BhC,IAAIG,OAAOO,IAAI,CAAA;cAElD;AACAkB,+BAAiBK,QAAQ,CAACC,UAAAA;AACxBlD,uBAAOmD,uBAAuBC,mBAAmB;kBAC/CrB,UAAUA,qCAAUM;kBACpBC,QAAQvB,IAAIuB;kBACZC,MAAMxB,IAAIc,MAAMU;kBAChB,GAAGW;gBACL,CAAA;cACF,CAAA;YACF;AACA,gBAAIlC,IAAIwB,eAAe,OAAOxB,IAAIG,OAAOC,aAAa;AACpD,oBAAMA,cAAcJ,IAAIG,OAAOC;AAC/BpB,qBAAOqD,mBAAmBC,eAAe;gBACvCvB,UAAUA,qCAAUM;gBACpBC,QAAQvB,IAAIuB;gBACZC,MAAMxB,IAAIc,MAAMU;gBAChBgB,MAAMnC,YAAYoC;gBAClBC,KAAKrC,YAAYsC;gBACjBC,WAAWvC,YAAYwC,SAAS;cAClC,CAAA;YACF;UACF;QACF,SAASV,OAAO;AACdlD,iBAAO6D,OAAOX,MACZ,uDACA;YAAEY,SAAS/C;YAAKgD,UAAU/C;YAAKkC;UAAM,CAAA;QAEzC;MACF,CAAA;IACF,SAASA,OAAO;AACdlD,aAAO6D,OAAOX,MAAM,iCAAiC;QACnDY,SAAS/C;QACTgD,UAAU/C;QACVkC;MACF,CAAA;IACF,UAAA;AACEjC,WAAAA;IACF;EACF;AACF,GAlGsB;AAoGtB,IAAMe,cAAc,wBAACjB,QAAAA;AACnB,MAAIA,IAAIiD,kBAAkB;AACxB,WAAOC,2BAA2BlD,IAAIiD,gBAAgB;EACxD,WAAWjD,IAAImD,oBAAoB;AAEjCC,YAAQC,YACN,sGACA,oBAAA;AAEF,WAAOH,2BAA2BlD,IAAImD,kBAAkB;EAC1D;AACA,SAAO;AACT,GAZoB;AAcpB,IAAMpB,gCAAgC,wBAACuB,iBAAAA;AACrC,QAAMC,SAA4B,CAAA;AAClC,MACED,gBACAA,aAAaC,UACbC,MAAMC,QAAQH,aAAaC,MAAM,GACjC;AACAD,iBAAaC,OAAOrB,QAAQ,CAACC,UAAAA;AAC3B,UAAIA,MAAMuB,YAAYvB,MAAMX,QAAQW,MAAMO,OAAOP,MAAMK,MAAM;AAC3De,eAAOzB,KAAK;UACV6B,KAAK,GAAGxB,MAAMuB,QAAQ,IAAIvB,MAAMX,IAAI;UACpCkB,KAAKP,MAAMO;UACXF,MAAML,MAAMK;QACd,CAAA;MACF;IACF,CAAA;EACF;AACA,SAAOe;AACT,GAlBsC;AAoBtC,IAAMvB,yBAAyB,wBAACsB,iBAAAA;AAC9B,QAAMC,SAA4B,CAAA;AAClC,MAAID,gBAAgBA,aAAaM,YAAY;AAC3CC,WAAOC,OAAOR,aAAaM,UAAU,EAAE1B,QAAQ,CAACC,UAAAA;AAC9C,UACEA,MAAM4B,UACN5B,MAAM6B,QACNR,MAAMC,QAAQtB,MAAM6B,IAAI,KACxB7B,MAAMQ,SACN;AACAR,cAAM6B,KAAK9B,QAAQ,CAAC+B,QAAAA;AAClBV,iBAAOzB,KAAK;YACV6B,KAAK,GAAGxB,MAAM4B,MAAM,IAAIE,GAAAA;YACxBvB,KAAKwB,iBAAiB/B,MAAMQ,SAASsB,GAAAA;YACrCzB,MAAM;UACR,CAAA;QACF,CAAA;MACF;IACF,CAAA;EACF;AACA,SAAOe;AACT,GArB+B;AAuB/B,IAAMtB,8BAA8B,wBAACqB,iBAAAA;AACnC,QAAMC,SAA4B,CAAA;AAClC,MAAID,gBAAgBE,MAAMC,QAAQH,aAAaX,OAAO,GAAG;AACvDW,iBAAaX,QAAQT,QAAQ,CAACS,YAAAA;AAC5BY,aAAOzB,KAAK;QACV6B,KAAK;QACLjB,KAAKC;QACLH,MAAM;MACR,CAAA;IACF,CAAA;EACF;AACA,SAAOe;AACT,GAZoC;AAcpC,IAAMW,mBAAmB,wBAACvB,SAAiBsB,QAAAA;AACzC,QAAME,iBAAiBxB,QACpByB,MAAM,IAAA,EACNC,KAAK,CAAC1B,aAAYA,SAAQ2B,SAAS,IAAIL,GAAAA,GAAM,CAAA;AAChD,SAAOE,iBAAiBA,iBAAiBxB;AAC3C,GALyB;AAOzB,IAAMnD,aAAa,wBACjBT,KACAU,eAAAA;AAEA,QAAM8E,WAAoC;IACxC;MAAC;MAAUnB,QAAQoB,QAAQC,QAAQ,MAAM,EAAA;;;AAE3C,QAAMC,iBAAiB/E,kBAAkB,SAAA;AACzC,QAAMgF,kBAAkBhF,kBAAkB,OAAA;AAC1C,MAAI+E,gBAAgB;AAClBH,aAASzC,KAAK;MAAC;MAAW4C;KAAe;EAC3C;AACA,MAAIC,iBAAiB;AACnBJ,aAASzC,KAAK;MAAC;MAAY6C;KAAgB;EAC7C;AACA,MAAIlF,YAAY;AACd8E,aAASzC,KAAK;MAAC;MAAOrC;KAAW;EACnC;AACA,SAAO;IACLmF,OAAOC,sBAAc9F,GAAAA;IACrBwF,UAAUV,OAAOiB,YAAYP,QAAAA;IAC7BtF,QAAQ;EACV;AACF,GAvBmB;","names":["performance","randomUUID","fetchRetry","consumerFromStringOrObject","consumer","_a","String","trim","substring","identifier","name","group","ConsumerRegistry","consumers","updated","constructor","Map","Set","addOrUpdateConsumer","existing","get","set","add","getAndResetUpdatedConsumers","data","forEach","push","clear","createLogger","format","transports","getLogger","createLogger","level","process","env","APITALLY_DEBUG","format","combine","colorize","timestamp","printf","info","message","transports","Console","isValidClientId","clientId","regexExp","test","isValidEnv","env","RequestCounter","requestCounts","requestSizeSums","responseSizeSums","responseTimes","requestSizes","responseSizes","constructor","Map","getKey","requestInfo","consumer","method","toUpperCase","path","statusCode","join","addRequest","key","set","get","has","responseTimeMap","responseTimeMsBin","Math","floor","responseTime","requestSize","undefined","Number","requestSizeMap","requestSizeKbBin","responseSize","responseSizeMap","responseSizeKbBin","getAndResetRequests","data","forEach","count","statusCodeStr","split","push","status_code","parseInt","request_count","request_size_sum","response_size_sum","response_times","Object","fromEntries","request_sizes","response_sizes","clear","createHash","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","sentry","constructor","Map","tryImportSentry","addServerError","serverError","key","getKey","has","set","get","captureSentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","getTruncatedMessage","traceback","getTruncatedStack","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line","serverErrorKey","lastEventId","eventId","e","createHash","ValidationErrorCounter","errorCounts","errorDetails","constructor","Map","addValidationError","validationError","key","getKey","has","set","get","getAndResetValidationErrors","data","forEach","count","push","consumer","method","path","loc","split","msg","type","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","SYNC_INTERVAL","INITIAL_SYNC_INTERVAL","INITIAL_SYNC_INTERVAL_DURATION","MAX_QUEUE_TIME","HTTPError","Error","response","constructor","reason","status","ApitallyClient","clientId","env","instanceUuid","syncDataQueue","syncIntervalId","startupData","startupDataSent","requestCounter","validationErrorCounter","serverErrorCounter","consumerRegistry","logger","instance","isValidClientId","isValidEnv","randomUUID","RequestCounter","ValidationErrorCounter","ServerErrorCounter","ConsumerRegistry","getLogger","startSync","handleShutdown","bind","getInstance","shutdown","stopSync","sendSyncData","undefined","getHubUrlPrefix","baseURL","process","APITALLY_HUB_BASE_URL","version","sendData","url","payload","fetchWithRetry","fetchRetry","fetch","retries","retryDelay","retryOn","method","body","JSON","stringify","headers","ok","sync","setInterval","setTimeout","clearInterval","promises","push","sendStartupData","Promise","all","error","setStartupData","data","debug","instance_uuid","message_uuid","handled","handleHubError","message","newPayload","time_offset","requests","getAndResetRequests","validation_errors","getAndResetValidationErrors","server_errors","getAndResetServerErrors","consumers","getAndResetUpdatedConsumers","Date","now","failedItems","length","queueItem","shift","time","timeOffset","createRequire","getPackageVersion","name","_require","createRequire","url","version","error","regExpToParseExpressPathRegExp","regExpToReplaceExpressPathRegExpParams","regexpExpressParamRegexp","regexpExpressPathParamRegexp","EXPRESS_ROOT_PATH_REGEXP_VALUE","STACK_ITEM_VALID_NAMES","getRouteMethods","route","methods","Object","keys","filter","method","map","toUpperCase","getRouteMiddlewares","stack","item","handle","name","hasParams","expressPathRegExp","test","parseExpressRoute","basePath","paths","Array","isArray","path","push","endpoints","completePath","endpoint","replace","middlewares","parseExpressPath","params","parsedRegExp","toString","expressPathRegExpExec","exec","paramIndex","paramName","paramId","parsedPath","parseEndpoints","app","_router","length","addEndpoints","parseStack","currentEndpoints","endpointsToAdd","forEach","newEndpoint","existingEndpoint","find","undefined","newMethods","includes","concat","stackItem","newEndpoints","isExpressPathRegexp","regexp","newBasePath","regExpPath","getEndpoints","flatMap","useApitally","app","config","client","ApitallyClient","middleware","getMiddleware","use","setTimeout","setStartupData","getAppInfo","appVersion","validatorInstalled","getPackageVersion","celebrateInstalled","nestInstalled","classValidatorInstalled","errorHandlerConfigured","req","res","next","err","locals","serverError","startTime","performance","now","originalJson","json","body","call","on","route","responseTime","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","method","path","statusCode","requestSize","get","responseSize","validationErrors","push","extractExpressValidatorErrors","extractCelebrateErrors","extractNestValidationErrors","forEach","error","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","logger","request","response","apitallyConsumer","consumerFromStringOrObject","consumerIdentifier","process","emitWarning","responseBody","errors","Array","isArray","location","loc","validation","Object","values","source","keys","key","subsetJoiMessage","messageWithKey","split","find","includes","versions","version","replace","expressVersion","apitallyVersion","paths","listEndpoints","fromEntries"]}
|