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/fastify/plugin.cjs
CHANGED
|
@@ -42,6 +42,62 @@ var import_fastify_plugin = __toESM(require("fastify-plugin"), 1);
|
|
|
42
42
|
var import_crypto3 = require("crypto");
|
|
43
43
|
var import_fetch_retry = __toESM(require("fetch-retry"), 1);
|
|
44
44
|
|
|
45
|
+
// src/common/consumerRegistry.ts
|
|
46
|
+
var consumerFromStringOrObject = /* @__PURE__ */ __name((consumer) => {
|
|
47
|
+
var _a2, _b;
|
|
48
|
+
if (typeof consumer === "string") {
|
|
49
|
+
consumer = String(consumer).trim().substring(0, 128);
|
|
50
|
+
return consumer ? {
|
|
51
|
+
identifier: consumer
|
|
52
|
+
} : null;
|
|
53
|
+
} else {
|
|
54
|
+
consumer.identifier = String(consumer.identifier).trim().substring(0, 128);
|
|
55
|
+
consumer.name = (_a2 = consumer.name) == null ? void 0 : _a2.trim().substring(0, 64);
|
|
56
|
+
consumer.group = (_b = consumer.group) == null ? void 0 : _b.trim().substring(0, 64);
|
|
57
|
+
return consumer.identifier ? consumer : null;
|
|
58
|
+
}
|
|
59
|
+
}, "consumerFromStringOrObject");
|
|
60
|
+
var _ConsumerRegistry = class _ConsumerRegistry {
|
|
61
|
+
consumers;
|
|
62
|
+
updated;
|
|
63
|
+
constructor() {
|
|
64
|
+
this.consumers = /* @__PURE__ */ new Map();
|
|
65
|
+
this.updated = /* @__PURE__ */ new Set();
|
|
66
|
+
}
|
|
67
|
+
addOrUpdateConsumer(consumer) {
|
|
68
|
+
if (!consumer || !consumer.name && !consumer.group) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const existing = this.consumers.get(consumer.identifier);
|
|
72
|
+
if (!existing) {
|
|
73
|
+
this.consumers.set(consumer.identifier, consumer);
|
|
74
|
+
this.updated.add(consumer.identifier);
|
|
75
|
+
} else {
|
|
76
|
+
if (consumer.name && consumer.name !== existing.name) {
|
|
77
|
+
existing.name = consumer.name;
|
|
78
|
+
this.updated.add(consumer.identifier);
|
|
79
|
+
}
|
|
80
|
+
if (consumer.group && consumer.group !== existing.group) {
|
|
81
|
+
existing.group = consumer.group;
|
|
82
|
+
this.updated.add(consumer.identifier);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
getAndResetUpdatedConsumers() {
|
|
87
|
+
const data = [];
|
|
88
|
+
this.updated.forEach((identifier) => {
|
|
89
|
+
const consumer = this.consumers.get(identifier);
|
|
90
|
+
if (consumer) {
|
|
91
|
+
data.push(consumer);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
this.updated.clear();
|
|
95
|
+
return data;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
__name(_ConsumerRegistry, "ConsumerRegistry");
|
|
99
|
+
var ConsumerRegistry = _ConsumerRegistry;
|
|
100
|
+
|
|
45
101
|
// src/common/logging.ts
|
|
46
102
|
var import_winston = require("winston");
|
|
47
103
|
var getLogger = /* @__PURE__ */ __name(() => {
|
|
@@ -319,13 +375,14 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
319
375
|
clientId;
|
|
320
376
|
env;
|
|
321
377
|
instanceUuid;
|
|
322
|
-
|
|
378
|
+
syncDataQueue;
|
|
323
379
|
syncIntervalId;
|
|
324
|
-
|
|
325
|
-
|
|
380
|
+
startupData;
|
|
381
|
+
startupDataSent = false;
|
|
326
382
|
requestCounter;
|
|
327
383
|
validationErrorCounter;
|
|
328
384
|
serverErrorCounter;
|
|
385
|
+
consumerRegistry;
|
|
329
386
|
logger;
|
|
330
387
|
constructor({ clientId, env = "dev", logger }) {
|
|
331
388
|
if (_ApitallyClient.instance) {
|
|
@@ -341,10 +398,11 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
341
398
|
this.clientId = clientId;
|
|
342
399
|
this.env = env;
|
|
343
400
|
this.instanceUuid = (0, import_crypto3.randomUUID)();
|
|
344
|
-
this.
|
|
401
|
+
this.syncDataQueue = [];
|
|
345
402
|
this.requestCounter = new RequestCounter();
|
|
346
403
|
this.validationErrorCounter = new ValidationErrorCounter();
|
|
347
404
|
this.serverErrorCounter = new ServerErrorCounter();
|
|
405
|
+
this.consumerRegistry = new ConsumerRegistry();
|
|
348
406
|
this.logger = logger || getLogger();
|
|
349
407
|
this.startSync();
|
|
350
408
|
this.handleShutdown = this.handleShutdown.bind(this);
|
|
@@ -362,15 +420,15 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
362
420
|
}
|
|
363
421
|
async handleShutdown() {
|
|
364
422
|
this.stopSync();
|
|
365
|
-
await this.
|
|
423
|
+
await this.sendSyncData();
|
|
366
424
|
_ApitallyClient.instance = void 0;
|
|
367
425
|
}
|
|
368
426
|
getHubUrlPrefix() {
|
|
369
427
|
const baseURL = process.env.APITALLY_HUB_BASE_URL || "https://hub.apitally.io";
|
|
370
|
-
const version = "
|
|
428
|
+
const version = "v2";
|
|
371
429
|
return `${baseURL}/${version}/${this.clientId}/${this.env}/`;
|
|
372
430
|
}
|
|
373
|
-
async
|
|
431
|
+
async sendData(url, payload) {
|
|
374
432
|
const fetchWithRetry = (0, import_fetch_retry.default)(fetch, {
|
|
375
433
|
retries: 3,
|
|
376
434
|
retryDelay: 1e3,
|
|
@@ -409,10 +467,10 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
409
467
|
async sync() {
|
|
410
468
|
try {
|
|
411
469
|
const promises = [
|
|
412
|
-
this.
|
|
470
|
+
this.sendSyncData()
|
|
413
471
|
];
|
|
414
|
-
if (!this.
|
|
415
|
-
promises.push(this.
|
|
472
|
+
if (!this.startupDataSent) {
|
|
473
|
+
promises.push(this.sendStartupData());
|
|
416
474
|
}
|
|
417
475
|
await Promise.all(promises);
|
|
418
476
|
} catch (error) {
|
|
@@ -427,62 +485,63 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
427
485
|
this.syncIntervalId = void 0;
|
|
428
486
|
}
|
|
429
487
|
}
|
|
430
|
-
|
|
431
|
-
this.
|
|
432
|
-
this.
|
|
433
|
-
this.
|
|
488
|
+
setStartupData(data) {
|
|
489
|
+
this.startupData = data;
|
|
490
|
+
this.startupDataSent = false;
|
|
491
|
+
this.sendStartupData();
|
|
434
492
|
}
|
|
435
|
-
async
|
|
436
|
-
if (this.
|
|
437
|
-
this.logger.debug("Sending
|
|
493
|
+
async sendStartupData() {
|
|
494
|
+
if (this.startupData) {
|
|
495
|
+
this.logger.debug("Sending startup data to Apitally Hub");
|
|
438
496
|
const payload = {
|
|
439
497
|
instance_uuid: this.instanceUuid,
|
|
440
498
|
message_uuid: (0, import_crypto3.randomUUID)(),
|
|
441
|
-
...this.
|
|
499
|
+
...this.startupData
|
|
442
500
|
};
|
|
443
501
|
try {
|
|
444
|
-
await this.
|
|
445
|
-
this.
|
|
502
|
+
await this.sendData("startup", payload);
|
|
503
|
+
this.startupDataSent = true;
|
|
446
504
|
} catch (error) {
|
|
447
505
|
const handled = this.handleHubError(error);
|
|
448
506
|
if (!handled) {
|
|
449
507
|
this.logger.error(error.message);
|
|
450
|
-
this.logger.debug("Error while sending
|
|
508
|
+
this.logger.debug("Error while sending startup data to Apitally Hub (will retry)", {
|
|
451
509
|
error
|
|
452
510
|
});
|
|
453
511
|
}
|
|
454
512
|
}
|
|
455
513
|
}
|
|
456
514
|
}
|
|
457
|
-
async
|
|
458
|
-
this.logger.debug("
|
|
515
|
+
async sendSyncData() {
|
|
516
|
+
this.logger.debug("Synchronizing data with Apitally Hub");
|
|
459
517
|
const newPayload = {
|
|
460
518
|
time_offset: 0,
|
|
461
519
|
instance_uuid: this.instanceUuid,
|
|
462
520
|
message_uuid: (0, import_crypto3.randomUUID)(),
|
|
463
521
|
requests: this.requestCounter.getAndResetRequests(),
|
|
464
522
|
validation_errors: this.validationErrorCounter.getAndResetValidationErrors(),
|
|
465
|
-
server_errors: this.serverErrorCounter.getAndResetServerErrors()
|
|
523
|
+
server_errors: this.serverErrorCounter.getAndResetServerErrors(),
|
|
524
|
+
consumers: this.consumerRegistry.getAndResetUpdatedConsumers()
|
|
466
525
|
};
|
|
467
|
-
this.
|
|
526
|
+
this.syncDataQueue.push([
|
|
468
527
|
Date.now(),
|
|
469
528
|
newPayload
|
|
470
529
|
]);
|
|
471
530
|
const failedItems = [];
|
|
472
|
-
while (this.
|
|
473
|
-
const queueItem = this.
|
|
531
|
+
while (this.syncDataQueue.length > 0) {
|
|
532
|
+
const queueItem = this.syncDataQueue.shift();
|
|
474
533
|
if (queueItem) {
|
|
475
534
|
const [time, payload] = queueItem;
|
|
476
535
|
try {
|
|
477
536
|
const timeOffset = Date.now() - time;
|
|
478
537
|
if (timeOffset <= MAX_QUEUE_TIME) {
|
|
479
538
|
payload.time_offset = timeOffset / 1e3;
|
|
480
|
-
await this.
|
|
539
|
+
await this.sendData("sync", payload);
|
|
481
540
|
}
|
|
482
541
|
} catch (error) {
|
|
483
542
|
const handled = this.handleHubError(error);
|
|
484
543
|
if (!handled) {
|
|
485
|
-
this.logger.debug("Error while
|
|
544
|
+
this.logger.debug("Error while synchronizing data with Apitally Hub (will retry)", {
|
|
486
545
|
error
|
|
487
546
|
});
|
|
488
547
|
failedItems.push(queueItem);
|
|
@@ -490,7 +549,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
490
549
|
}
|
|
491
550
|
}
|
|
492
551
|
}
|
|
493
|
-
this.
|
|
552
|
+
this.syncDataQueue = failedItems;
|
|
494
553
|
}
|
|
495
554
|
handleHubError(error) {
|
|
496
555
|
if (error instanceof HTTPError) {
|
|
@@ -548,7 +607,7 @@ var apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
|
|
|
548
607
|
});
|
|
549
608
|
});
|
|
550
609
|
fastify.addHook("onReady", () => {
|
|
551
|
-
client.
|
|
610
|
+
client.setStartupData(getAppInfo(routes, config.appVersion));
|
|
552
611
|
});
|
|
553
612
|
fastify.addHook("onClose", async () => {
|
|
554
613
|
await client.handleShutdown();
|
|
@@ -575,12 +634,13 @@ var apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
|
|
|
575
634
|
if (Array.isArray(responseSize)) {
|
|
576
635
|
responseSize = responseSize[0];
|
|
577
636
|
}
|
|
637
|
+
client.consumerRegistry.addOrUpdateConsumer(consumer);
|
|
578
638
|
client.requestCounter.addRequest({
|
|
579
|
-
consumer,
|
|
639
|
+
consumer: consumer == null ? void 0 : consumer.identifier,
|
|
580
640
|
method: request.method,
|
|
581
641
|
path,
|
|
582
642
|
statusCode: reply.statusCode,
|
|
583
|
-
responseTime:
|
|
643
|
+
responseTime: getResponseTime(reply),
|
|
584
644
|
requestSize,
|
|
585
645
|
responseSize
|
|
586
646
|
});
|
|
@@ -588,7 +648,7 @@ var apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
|
|
|
588
648
|
const validationErrors = extractAjvErrors(reply.payload.message);
|
|
589
649
|
validationErrors.forEach((error) => {
|
|
590
650
|
client.validationErrorCounter.addValidationError({
|
|
591
|
-
consumer,
|
|
651
|
+
consumer: consumer == null ? void 0 : consumer.identifier,
|
|
592
652
|
method: request.method,
|
|
593
653
|
path,
|
|
594
654
|
...error
|
|
@@ -597,7 +657,7 @@ var apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
|
|
|
597
657
|
}
|
|
598
658
|
if (reply.statusCode === 500 && reply.serverError) {
|
|
599
659
|
client.serverErrorCounter.addServerError({
|
|
600
|
-
consumer,
|
|
660
|
+
consumer: consumer == null ? void 0 : consumer.identifier,
|
|
601
661
|
method: request.method,
|
|
602
662
|
path,
|
|
603
663
|
type: reply.serverError.name,
|
|
@@ -644,12 +704,21 @@ var getAppInfo = /* @__PURE__ */ __name((routes, appVersion) => {
|
|
|
644
704
|
}, "getAppInfo");
|
|
645
705
|
var getConsumer = /* @__PURE__ */ __name((request) => {
|
|
646
706
|
if (request.apitallyConsumer) {
|
|
647
|
-
return
|
|
707
|
+
return consumerFromStringOrObject(request.apitallyConsumer);
|
|
648
708
|
} else if (request.consumerIdentifier) {
|
|
649
|
-
|
|
709
|
+
process.emitWarning("The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.", "DeprecationWarning");
|
|
710
|
+
return consumerFromStringOrObject(request.consumerIdentifier);
|
|
650
711
|
}
|
|
651
712
|
return null;
|
|
652
713
|
}, "getConsumer");
|
|
714
|
+
var getResponseTime = /* @__PURE__ */ __name((reply) => {
|
|
715
|
+
if (reply.elapsedTime !== void 0) {
|
|
716
|
+
return reply.elapsedTime;
|
|
717
|
+
} else if (reply.getResponseTime !== void 0) {
|
|
718
|
+
return reply.getResponseTime();
|
|
719
|
+
}
|
|
720
|
+
return 0;
|
|
721
|
+
}, "getResponseTime");
|
|
653
722
|
var extractAjvErrors = /* @__PURE__ */ __name((message) => {
|
|
654
723
|
const regex = /(?<=^|, )((?:headers|params|query|querystring|body)[/.][^ ]+)(?= )/g;
|
|
655
724
|
const matches = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/fastify/plugin.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"],"sourcesContent":["import type { FastifyError, FastifyPluginAsync, FastifyRequest } from \"fastify\";\nimport fp from \"fastify-plugin\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport { ApitallyConfig, PathInfo, ValidationError } from \"../common/types.js\";\n\ndeclare module \"fastify\" {\n interface FastifyReply {\n payload: any;\n serverError?: FastifyError;\n }\n\n interface FastifyRequest {\n apitallyConsumer?: string;\n consumerIdentifier?: string; // For backwards compatibility\n }\n}\n\nconst apitallyPlugin: FastifyPluginAsync<ApitallyConfig> = async (\n fastify,\n config,\n) => {\n const client = new ApitallyClient(config);\n const routes: PathInfo[] = [];\n\n fastify.decorateRequest(\"apitallyConsumer\", null);\n fastify.decorateRequest(\"consumerIdentifier\", null); // For backwards compatibility\n fastify.decorateReply(\"payload\", null);\n\n fastify.addHook(\"onRoute\", (routeOptions) => {\n const methods = Array.isArray(routeOptions.method)\n ? routeOptions.method\n : [routeOptions.method];\n methods.forEach((method) => {\n if (![\"HEAD\", \"OPTIONS\"].includes(method.toUpperCase())) {\n routes.push({\n method: method.toUpperCase(),\n path: routeOptions.url,\n });\n }\n });\n });\n\n fastify.addHook(\"onReady\", () => {\n client.setAppInfo(getAppInfo(routes, config.appVersion));\n });\n\n fastify.addHook(\"onClose\", async () => {\n await client.handleShutdown();\n });\n\n fastify.addHook(\"onSend\", (request, reply, payload: any, done) => {\n try {\n reply.payload = JSON.parse(payload);\n } catch (error) {} // eslint-disable-line no-empty\n done();\n });\n\n fastify.addHook(\"onError\", (request, reply, error, done) => {\n if (!error.statusCode || error.statusCode === 500) {\n reply.serverError = error;\n }\n done();\n });\n\n fastify.addHook(\"onResponse\", (request, reply, done) => {\n if (request.method.toUpperCase() !== \"OPTIONS\") {\n // Get path from routeOptions if available (from v4), otherwise fallback to deprecated routerPath\n const consumer = getConsumer(request);\n const path =\n \"routeOptions\" in request\n ? (request as any).routeOptions.url\n : (request as any).routerPath;\n const requestSize = request.headers[\"content-length\"];\n let responseSize = reply.getHeader(\"content-length\");\n if (Array.isArray(responseSize)) {\n responseSize = responseSize[0];\n }\n client.requestCounter.addRequest({\n consumer: consumer,\n method: request.method,\n path: path,\n statusCode: reply.statusCode,\n responseTime: reply.getResponseTime(),\n requestSize: requestSize,\n responseSize: responseSize,\n });\n if (\n (reply.statusCode === 400 || reply.statusCode === 422) &&\n reply.payload &&\n (!reply.payload.code || reply.payload.code === \"FST_ERR_VALIDATION\") &&\n typeof reply.payload.message === \"string\"\n ) {\n const validationErrors = extractAjvErrors(reply.payload.message);\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer,\n method: request.method,\n path: path,\n ...error,\n });\n });\n }\n if (reply.statusCode === 500 && reply.serverError) {\n client.serverErrorCounter.addServerError({\n consumer: consumer,\n method: request.method,\n path: path,\n type: reply.serverError.name,\n msg: reply.serverError.message,\n traceback: reply.serverError.stack || \"\",\n });\n }\n }\n done();\n });\n};\n\nconst getAppInfo = (routes: PathInfo[], appVersion?: string) => {\n const versions: Array<[string, string]> = [\n [\"nodejs\", process.version.replace(/^v/, \"\")],\n ];\n const fastifyVersion = getPackageVersion(\"fastify\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (fastifyVersion) {\n versions.push([\"fastify\", fastifyVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: routes,\n versions: Object.fromEntries(versions),\n client: \"js:fastify\",\n };\n};\n\nconst getConsumer = (request: FastifyRequest) => {\n if (request.apitallyConsumer) {\n return String(request.apitallyConsumer);\n } else if (request.consumerIdentifier) {\n // For backwards compatibility\n return String(request.consumerIdentifier);\n }\n return null;\n};\n\nconst extractAjvErrors = (message: string): ValidationError[] => {\n const regex =\n /(?<=^|, )((?:headers|params|query|querystring|body)[/.][^ ]+)(?= )/g;\n const matches: { match: string; index: number }[] = [];\n let match: RegExpExecArray | null;\n while ((match = regex.exec(message)) !== null) {\n matches.push({ match: match[0], index: match.index });\n }\n\n return matches.map((m, i) => {\n const endIndex =\n i + 1 < matches.length ? matches[i + 1].index - 2 : message.length;\n const matchSplit = m.match.split(/[/.]/);\n if (matchSplit[0] === \"querystring\") {\n matchSplit[0] = \"query\";\n }\n return {\n loc: matchSplit.join(\".\"),\n msg: message.substring(m.index, endIndex),\n type: \"\",\n };\n });\n};\n\nexport default fp(apitallyPlugin, {\n name: \"apitally\",\n});\n","import { randomUUID } from \"crypto\";\nimport fetchRetry from \"fetch-retry\";\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"],"mappings":"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","names":["import_crypto","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","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","import_crypto","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","getPackageVersion","name","_require","createRequire","url","version","error","apitallyPlugin","fastify","config","client","ApitallyClient","routes","decorateRequest","decorateReply","addHook","routeOptions","methods","Array","isArray","method","forEach","includes","toUpperCase","push","path","url","setAppInfo","getAppInfo","appVersion","handleShutdown","request","reply","payload","done","JSON","parse","error","statusCode","serverError","consumer","getConsumer","routerPath","requestSize","headers","responseSize","getHeader","requestCounter","addRequest","responseTime","getResponseTime","code","message","validationErrors","extractAjvErrors","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","traceback","stack","versions","process","version","replace","fastifyVersion","getPackageVersion","apitallyVersion","paths","Object","fromEntries","apitallyConsumer","String","consumerIdentifier","regex","matches","match","exec","index","map","m","i","endIndex","length","matchSplit","split","loc","join","substring","fp"]}
|
|
1
|
+
{"version":3,"sources":["../../src/fastify/plugin.ts","../../src/common/client.ts","../../src/common/consumerRegistry.ts","../../src/common/logging.ts","../../src/common/paramValidation.ts","../../src/common/requestCounter.ts","../../src/common/serverErrorCounter.ts","../../src/common/validationErrorCounter.ts","../../src/common/packageVersions.ts"],"sourcesContent":["import type {\n FastifyError,\n FastifyPluginAsync,\n FastifyReply,\n FastifyRequest,\n} from \"fastify\";\nimport fp from \"fastify-plugin\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n PathInfo,\n ValidationError,\n} from \"../common/types.js\";\n\ndeclare module \"fastify\" {\n interface FastifyReply {\n payload: any;\n serverError?: FastifyError;\n }\n\n interface FastifyRequest {\n apitallyConsumer?: ApitallyConsumer | string | null;\n consumerIdentifier?: ApitallyConsumer | string | null; // For backwards compatibility\n }\n}\n\nconst apitallyPlugin: FastifyPluginAsync<ApitallyConfig> = async (\n fastify,\n config,\n) => {\n const client = new ApitallyClient(config);\n const routes: PathInfo[] = [];\n\n fastify.decorateRequest(\"apitallyConsumer\", null);\n fastify.decorateRequest(\"consumerIdentifier\", null); // For backwards compatibility\n fastify.decorateReply(\"payload\", null);\n\n fastify.addHook(\"onRoute\", (routeOptions) => {\n const methods = Array.isArray(routeOptions.method)\n ? routeOptions.method\n : [routeOptions.method];\n methods.forEach((method) => {\n if (![\"HEAD\", \"OPTIONS\"].includes(method.toUpperCase())) {\n routes.push({\n method: method.toUpperCase(),\n path: routeOptions.url,\n });\n }\n });\n });\n\n fastify.addHook(\"onReady\", () => {\n client.setStartupData(getAppInfo(routes, config.appVersion));\n });\n\n fastify.addHook(\"onClose\", async () => {\n await client.handleShutdown();\n });\n\n fastify.addHook(\"onSend\", (request, reply, payload: any, done) => {\n try {\n reply.payload = JSON.parse(payload);\n } catch (error) {} // eslint-disable-line no-empty\n done();\n });\n\n fastify.addHook(\"onError\", (request, reply, error, done) => {\n if (!error.statusCode || error.statusCode === 500) {\n reply.serverError = error;\n }\n done();\n });\n\n fastify.addHook(\"onResponse\", (request, reply, done) => {\n if (request.method.toUpperCase() !== \"OPTIONS\") {\n // Get path from routeOptions if available (from v4), otherwise fallback to deprecated routerPath\n const consumer = getConsumer(request);\n const path =\n \"routeOptions\" in request\n ? (request as any).routeOptions.url\n : (request as any).routerPath;\n const requestSize = request.headers[\"content-length\"];\n let responseSize = reply.getHeader(\"content-length\");\n if (Array.isArray(responseSize)) {\n responseSize = responseSize[0];\n }\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n statusCode: reply.statusCode,\n responseTime: getResponseTime(reply),\n requestSize: requestSize,\n responseSize: responseSize,\n });\n if (\n (reply.statusCode === 400 || reply.statusCode === 422) &&\n reply.payload &&\n (!reply.payload.code || reply.payload.code === \"FST_ERR_VALIDATION\") &&\n typeof reply.payload.message === \"string\"\n ) {\n const validationErrors = extractAjvErrors(reply.payload.message);\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n ...error,\n });\n });\n }\n if (reply.statusCode === 500 && reply.serverError) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: path,\n type: reply.serverError.name,\n msg: reply.serverError.message,\n traceback: reply.serverError.stack || \"\",\n });\n }\n }\n done();\n });\n};\n\nconst getAppInfo = (routes: PathInfo[], appVersion?: string) => {\n const versions: Array<[string, string]> = [\n [\"nodejs\", process.version.replace(/^v/, \"\")],\n ];\n const fastifyVersion = getPackageVersion(\"fastify\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (fastifyVersion) {\n versions.push([\"fastify\", fastifyVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: routes,\n versions: Object.fromEntries(versions),\n client: \"js:fastify\",\n };\n};\n\nconst getConsumer = (request: FastifyRequest) => {\n if (request.apitallyConsumer) {\n return consumerFromStringOrObject(request.apitallyConsumer);\n } else if (request.consumerIdentifier) {\n // For backwards compatibility\n process.emitWarning(\n \"The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.\",\n \"DeprecationWarning\",\n );\n return consumerFromStringOrObject(request.consumerIdentifier);\n }\n return null;\n};\n\nconst getResponseTime = (reply: FastifyReply) => {\n if (reply.elapsedTime !== undefined) {\n return reply.elapsedTime;\n } else if (reply.getResponseTime !== undefined) {\n return reply.getResponseTime();\n }\n return 0;\n};\n\nconst extractAjvErrors = (message: string): ValidationError[] => {\n const regex =\n /(?<=^|, )((?:headers|params|query|querystring|body)[/.][^ ]+)(?= )/g;\n const matches: { match: string; index: number }[] = [];\n let match: RegExpExecArray | null;\n while ((match = regex.exec(message)) !== null) {\n matches.push({ match: match[0], index: match.index });\n }\n\n return matches.map((m, i) => {\n const endIndex =\n i + 1 < matches.length ? matches[i + 1].index - 2 : message.length;\n const matchSplit = m.match.split(/[/.]/);\n if (matchSplit[0] === \"querystring\") {\n matchSplit[0] = \"query\";\n }\n return {\n loc: matchSplit.join(\".\"),\n msg: message.substring(m.index, endIndex),\n type: \"\",\n };\n });\n};\n\nexport default fp(apitallyPlugin, {\n name: \"apitally\",\n});\n","import { randomUUID } from \"crypto\";\nimport fetchRetry from \"fetch-retry\";\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"],"mappings":"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","names":["import_crypto","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","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","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","import_crypto","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","getPackageVersion","name","_require","createRequire","url","version","error","apitallyPlugin","fastify","config","client","ApitallyClient","routes","decorateRequest","decorateReply","addHook","routeOptions","methods","Array","isArray","method","forEach","includes","toUpperCase","push","path","url","setStartupData","getAppInfo","appVersion","handleShutdown","request","reply","payload","done","JSON","parse","error","statusCode","serverError","consumer","getConsumer","routerPath","requestSize","headers","responseSize","getHeader","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","responseTime","getResponseTime","code","message","validationErrors","extractAjvErrors","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","traceback","stack","versions","process","version","replace","fastifyVersion","getPackageVersion","apitallyVersion","paths","Object","fromEntries","apitallyConsumer","consumerFromStringOrObject","consumerIdentifier","emitWarning","elapsedTime","undefined","regex","matches","match","exec","index","map","m","i","endIndex","length","matchSplit","split","loc","join","substring","fp"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { ApitallyConsumer, ApitallyConfig } from '../common/types.cjs';
|
|
1
2
|
import { FastifyError, FastifyPluginAsync } from 'fastify';
|
|
2
|
-
import { ApitallyConfig } from '../common/types.cjs';
|
|
3
3
|
import '../common/logging.cjs';
|
|
4
4
|
import 'winston';
|
|
5
5
|
|
|
@@ -9,8 +9,8 @@ declare module "fastify" {
|
|
|
9
9
|
serverError?: FastifyError;
|
|
10
10
|
}
|
|
11
11
|
interface FastifyRequest {
|
|
12
|
-
apitallyConsumer?: string;
|
|
13
|
-
consumerIdentifier?: string;
|
|
12
|
+
apitallyConsumer?: ApitallyConsumer | string | null;
|
|
13
|
+
consumerIdentifier?: ApitallyConsumer | string | null;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
declare const _default: FastifyPluginAsync<ApitallyConfig>;
|
package/dist/fastify/plugin.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { ApitallyConsumer, ApitallyConfig } from '../common/types.js';
|
|
1
2
|
import { FastifyError, FastifyPluginAsync } from 'fastify';
|
|
2
|
-
import { ApitallyConfig } from '../common/types.js';
|
|
3
3
|
import '../common/logging.js';
|
|
4
4
|
import 'winston';
|
|
5
5
|
|
|
@@ -9,8 +9,8 @@ declare module "fastify" {
|
|
|
9
9
|
serverError?: FastifyError;
|
|
10
10
|
}
|
|
11
11
|
interface FastifyRequest {
|
|
12
|
-
apitallyConsumer?: string;
|
|
13
|
-
consumerIdentifier?: string;
|
|
12
|
+
apitallyConsumer?: ApitallyConsumer | string | null;
|
|
13
|
+
consumerIdentifier?: ApitallyConsumer | string | null;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
declare const _default: FastifyPluginAsync<ApitallyConfig>;
|