apitally 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +97 -36
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.js +97 -36
- package/dist/express/index.js.map +1 -1
- package/dist/express/middleware.cjs +97 -36
- package/dist/express/middleware.cjs.map +1 -1
- package/dist/express/middleware.d.cts +3 -3
- package/dist/express/middleware.d.ts +3 -3
- package/dist/express/middleware.js +97 -36
- 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.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.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.js +98 -35
- package/dist/koa/middleware.js.map +1 -1
- package/dist/nestjs/index.cjs +97 -36
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.js +97 -36
- package/dist/nestjs/index.js.map +1 -1
- package/package.json +2 -2
package/dist/common/client.js
CHANGED
|
@@ -7,6 +7,48 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
7
7
|
import { randomUUID } from "crypto";
|
|
8
8
|
import fetchRetry from "fetch-retry";
|
|
9
9
|
|
|
10
|
+
// src/common/consumerRegistry.ts
|
|
11
|
+
var _ConsumerRegistry = class _ConsumerRegistry {
|
|
12
|
+
consumers;
|
|
13
|
+
updated;
|
|
14
|
+
constructor() {
|
|
15
|
+
this.consumers = /* @__PURE__ */ new Map();
|
|
16
|
+
this.updated = /* @__PURE__ */ new Set();
|
|
17
|
+
}
|
|
18
|
+
addOrUpdateConsumer(consumer) {
|
|
19
|
+
if (!consumer || !consumer.name && !consumer.group) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const existing = this.consumers.get(consumer.identifier);
|
|
23
|
+
if (!existing) {
|
|
24
|
+
this.consumers.set(consumer.identifier, consumer);
|
|
25
|
+
this.updated.add(consumer.identifier);
|
|
26
|
+
} else {
|
|
27
|
+
if (consumer.name && consumer.name !== existing.name) {
|
|
28
|
+
existing.name = consumer.name;
|
|
29
|
+
this.updated.add(consumer.identifier);
|
|
30
|
+
}
|
|
31
|
+
if (consumer.group && consumer.group !== existing.group) {
|
|
32
|
+
existing.group = consumer.group;
|
|
33
|
+
this.updated.add(consumer.identifier);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
getAndResetUpdatedConsumers() {
|
|
38
|
+
const data = [];
|
|
39
|
+
this.updated.forEach((identifier) => {
|
|
40
|
+
const consumer = this.consumers.get(identifier);
|
|
41
|
+
if (consumer) {
|
|
42
|
+
data.push(consumer);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
this.updated.clear();
|
|
46
|
+
return data;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
__name(_ConsumerRegistry, "ConsumerRegistry");
|
|
50
|
+
var ConsumerRegistry = _ConsumerRegistry;
|
|
51
|
+
|
|
10
52
|
// src/common/logging.ts
|
|
11
53
|
import { createLogger, format, transports } from "winston";
|
|
12
54
|
var getLogger = /* @__PURE__ */ __name(() => {
|
|
@@ -284,13 +326,14 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
284
326
|
clientId;
|
|
285
327
|
env;
|
|
286
328
|
instanceUuid;
|
|
287
|
-
|
|
329
|
+
syncDataQueue;
|
|
288
330
|
syncIntervalId;
|
|
289
|
-
|
|
290
|
-
|
|
331
|
+
startupData;
|
|
332
|
+
startupDataSent = false;
|
|
291
333
|
requestCounter;
|
|
292
334
|
validationErrorCounter;
|
|
293
335
|
serverErrorCounter;
|
|
336
|
+
consumerRegistry;
|
|
294
337
|
logger;
|
|
295
338
|
constructor({ clientId, env = "dev", logger }) {
|
|
296
339
|
if (_ApitallyClient.instance) {
|
|
@@ -306,10 +349,11 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
306
349
|
this.clientId = clientId;
|
|
307
350
|
this.env = env;
|
|
308
351
|
this.instanceUuid = randomUUID();
|
|
309
|
-
this.
|
|
352
|
+
this.syncDataQueue = [];
|
|
310
353
|
this.requestCounter = new RequestCounter();
|
|
311
354
|
this.validationErrorCounter = new ValidationErrorCounter();
|
|
312
355
|
this.serverErrorCounter = new ServerErrorCounter();
|
|
356
|
+
this.consumerRegistry = new ConsumerRegistry();
|
|
313
357
|
this.logger = logger || getLogger();
|
|
314
358
|
this.startSync();
|
|
315
359
|
this.handleShutdown = this.handleShutdown.bind(this);
|
|
@@ -327,15 +371,15 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
327
371
|
}
|
|
328
372
|
async handleShutdown() {
|
|
329
373
|
this.stopSync();
|
|
330
|
-
await this.
|
|
374
|
+
await this.sendSyncData();
|
|
331
375
|
_ApitallyClient.instance = void 0;
|
|
332
376
|
}
|
|
333
377
|
getHubUrlPrefix() {
|
|
334
378
|
const baseURL = process.env.APITALLY_HUB_BASE_URL || "https://hub.apitally.io";
|
|
335
|
-
const version = "
|
|
379
|
+
const version = "v2";
|
|
336
380
|
return `${baseURL}/${version}/${this.clientId}/${this.env}/`;
|
|
337
381
|
}
|
|
338
|
-
async
|
|
382
|
+
async sendData(url, payload) {
|
|
339
383
|
const fetchWithRetry = fetchRetry(fetch, {
|
|
340
384
|
retries: 3,
|
|
341
385
|
retryDelay: 1e3,
|
|
@@ -374,10 +418,10 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
374
418
|
async sync() {
|
|
375
419
|
try {
|
|
376
420
|
const promises = [
|
|
377
|
-
this.
|
|
421
|
+
this.sendSyncData()
|
|
378
422
|
];
|
|
379
|
-
if (!this.
|
|
380
|
-
promises.push(this.
|
|
423
|
+
if (!this.startupDataSent) {
|
|
424
|
+
promises.push(this.sendStartupData());
|
|
381
425
|
}
|
|
382
426
|
await Promise.all(promises);
|
|
383
427
|
} catch (error) {
|
|
@@ -392,62 +436,63 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
392
436
|
this.syncIntervalId = void 0;
|
|
393
437
|
}
|
|
394
438
|
}
|
|
395
|
-
|
|
396
|
-
this.
|
|
397
|
-
this.
|
|
398
|
-
this.
|
|
439
|
+
setStartupData(data) {
|
|
440
|
+
this.startupData = data;
|
|
441
|
+
this.startupDataSent = false;
|
|
442
|
+
this.sendStartupData();
|
|
399
443
|
}
|
|
400
|
-
async
|
|
401
|
-
if (this.
|
|
402
|
-
this.logger.debug("Sending
|
|
444
|
+
async sendStartupData() {
|
|
445
|
+
if (this.startupData) {
|
|
446
|
+
this.logger.debug("Sending startup data to Apitally Hub");
|
|
403
447
|
const payload = {
|
|
404
448
|
instance_uuid: this.instanceUuid,
|
|
405
449
|
message_uuid: randomUUID(),
|
|
406
|
-
...this.
|
|
450
|
+
...this.startupData
|
|
407
451
|
};
|
|
408
452
|
try {
|
|
409
|
-
await this.
|
|
410
|
-
this.
|
|
453
|
+
await this.sendData("startup", payload);
|
|
454
|
+
this.startupDataSent = true;
|
|
411
455
|
} catch (error) {
|
|
412
456
|
const handled = this.handleHubError(error);
|
|
413
457
|
if (!handled) {
|
|
414
458
|
this.logger.error(error.message);
|
|
415
|
-
this.logger.debug("Error while sending
|
|
459
|
+
this.logger.debug("Error while sending startup data to Apitally Hub (will retry)", {
|
|
416
460
|
error
|
|
417
461
|
});
|
|
418
462
|
}
|
|
419
463
|
}
|
|
420
464
|
}
|
|
421
465
|
}
|
|
422
|
-
async
|
|
423
|
-
this.logger.debug("
|
|
466
|
+
async sendSyncData() {
|
|
467
|
+
this.logger.debug("Synchronizing data with Apitally Hub");
|
|
424
468
|
const newPayload = {
|
|
425
469
|
time_offset: 0,
|
|
426
470
|
instance_uuid: this.instanceUuid,
|
|
427
471
|
message_uuid: randomUUID(),
|
|
428
472
|
requests: this.requestCounter.getAndResetRequests(),
|
|
429
473
|
validation_errors: this.validationErrorCounter.getAndResetValidationErrors(),
|
|
430
|
-
server_errors: this.serverErrorCounter.getAndResetServerErrors()
|
|
474
|
+
server_errors: this.serverErrorCounter.getAndResetServerErrors(),
|
|
475
|
+
consumers: this.consumerRegistry.getAndResetUpdatedConsumers()
|
|
431
476
|
};
|
|
432
|
-
this.
|
|
477
|
+
this.syncDataQueue.push([
|
|
433
478
|
Date.now(),
|
|
434
479
|
newPayload
|
|
435
480
|
]);
|
|
436
481
|
const failedItems = [];
|
|
437
|
-
while (this.
|
|
438
|
-
const queueItem = this.
|
|
482
|
+
while (this.syncDataQueue.length > 0) {
|
|
483
|
+
const queueItem = this.syncDataQueue.shift();
|
|
439
484
|
if (queueItem) {
|
|
440
485
|
const [time, payload] = queueItem;
|
|
441
486
|
try {
|
|
442
487
|
const timeOffset = Date.now() - time;
|
|
443
488
|
if (timeOffset <= MAX_QUEUE_TIME) {
|
|
444
489
|
payload.time_offset = timeOffset / 1e3;
|
|
445
|
-
await this.
|
|
490
|
+
await this.sendData("sync", payload);
|
|
446
491
|
}
|
|
447
492
|
} catch (error) {
|
|
448
493
|
const handled = this.handleHubError(error);
|
|
449
494
|
if (!handled) {
|
|
450
|
-
this.logger.debug("Error while
|
|
495
|
+
this.logger.debug("Error while synchronizing data with Apitally Hub (will retry)", {
|
|
451
496
|
error
|
|
452
497
|
});
|
|
453
498
|
failedItems.push(queueItem);
|
|
@@ -455,7 +500,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
455
500
|
}
|
|
456
501
|
}
|
|
457
502
|
}
|
|
458
|
-
this.
|
|
503
|
+
this.syncDataQueue = failedItems;
|
|
459
504
|
}
|
|
460
505
|
handleHubError(error) {
|
|
461
506
|
if (error instanceof HTTPError) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/common/client.ts","../../src/common/logging.ts","../../src/common/paramValidation.ts","../../src/common/requestCounter.ts","../../src/common/serverErrorCounter.ts","../../src/common/validationErrorCounter.ts"],"sourcesContent":["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"],"mappings":"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","names":["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"]}
|
|
1
|
+
{"version":3,"sources":["../../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"],"sourcesContent":["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"],"mappings":"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","names":["randomUUID","fetchRetry","ConsumerRegistry","consumers","updated","constructor","Map","Set","addOrUpdateConsumer","consumer","name","group","existing","get","identifier","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"]}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/common/consumerRegistry.ts
|
|
22
|
+
var consumerRegistry_exports = {};
|
|
23
|
+
__export(consumerRegistry_exports, {
|
|
24
|
+
consumerFromStringOrObject: () => consumerFromStringOrObject,
|
|
25
|
+
default: () => ConsumerRegistry
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(consumerRegistry_exports);
|
|
28
|
+
var consumerFromStringOrObject = /* @__PURE__ */ __name((consumer) => {
|
|
29
|
+
var _a, _b;
|
|
30
|
+
if (typeof consumer === "string") {
|
|
31
|
+
consumer = String(consumer).trim().substring(0, 128);
|
|
32
|
+
return consumer ? {
|
|
33
|
+
identifier: consumer
|
|
34
|
+
} : null;
|
|
35
|
+
} else {
|
|
36
|
+
consumer.identifier = String(consumer.identifier).trim().substring(0, 128);
|
|
37
|
+
consumer.name = (_a = consumer.name) == null ? void 0 : _a.trim().substring(0, 64);
|
|
38
|
+
consumer.group = (_b = consumer.group) == null ? void 0 : _b.trim().substring(0, 64);
|
|
39
|
+
return consumer.identifier ? consumer : null;
|
|
40
|
+
}
|
|
41
|
+
}, "consumerFromStringOrObject");
|
|
42
|
+
var _ConsumerRegistry = class _ConsumerRegistry {
|
|
43
|
+
consumers;
|
|
44
|
+
updated;
|
|
45
|
+
constructor() {
|
|
46
|
+
this.consumers = /* @__PURE__ */ new Map();
|
|
47
|
+
this.updated = /* @__PURE__ */ new Set();
|
|
48
|
+
}
|
|
49
|
+
addOrUpdateConsumer(consumer) {
|
|
50
|
+
if (!consumer || !consumer.name && !consumer.group) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const existing = this.consumers.get(consumer.identifier);
|
|
54
|
+
if (!existing) {
|
|
55
|
+
this.consumers.set(consumer.identifier, consumer);
|
|
56
|
+
this.updated.add(consumer.identifier);
|
|
57
|
+
} else {
|
|
58
|
+
if (consumer.name && consumer.name !== existing.name) {
|
|
59
|
+
existing.name = consumer.name;
|
|
60
|
+
this.updated.add(consumer.identifier);
|
|
61
|
+
}
|
|
62
|
+
if (consumer.group && consumer.group !== existing.group) {
|
|
63
|
+
existing.group = consumer.group;
|
|
64
|
+
this.updated.add(consumer.identifier);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
getAndResetUpdatedConsumers() {
|
|
69
|
+
const data = [];
|
|
70
|
+
this.updated.forEach((identifier) => {
|
|
71
|
+
const consumer = this.consumers.get(identifier);
|
|
72
|
+
if (consumer) {
|
|
73
|
+
data.push(consumer);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
this.updated.clear();
|
|
77
|
+
return data;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
__name(_ConsumerRegistry, "ConsumerRegistry");
|
|
81
|
+
var ConsumerRegistry = _ConsumerRegistry;
|
|
82
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
83
|
+
0 && (module.exports = {
|
|
84
|
+
consumerFromStringOrObject
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=consumerRegistry.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/common/consumerRegistry.ts"],"sourcesContent":["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"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAEA;;;;;;AAAO,IAAMA,6BAA6B,wBACxCC,aAAAA;AADF;AAGE,MAAI,OAAOA,aAAa,UAAU;AAChCA,eAAWC,OAAOD,QAAAA,EAAUE,KAAI,EAAGC,UAAU,GAAG,GAAA;AAChD,WAAOH,WAAW;MAAEI,YAAYJ;IAAS,IAAI;EAC/C,OAAO;AACLA,aAASI,aAAaH,OAAOD,SAASI,UAAU,EAAEF,KAAI,EAAGC,UAAU,GAAG,GAAA;AACtEH,aAASK,QAAOL,cAASK,SAATL,mBAAeE,OAAOC,UAAU,GAAG;AACnDH,aAASM,SAAQN,cAASM,UAATN,mBAAgBE,OAAOC,UAAU,GAAG;AACrD,WAAOH,SAASI,aAAaJ,WAAW;EAC1C;AACF,GAZ0C;AAc1C,IAAqBO,oBAArB,MAAqBA,kBAAAA;EACXC;EACAC;EAERC,cAAc;AACZ,SAAKF,YAAY,oBAAIG,IAAAA;AACrB,SAAKF,UAAU,oBAAIG,IAAAA;EACrB;EAEOC,oBAAoBb,UAAoC;AAC7D,QAAI,CAACA,YAAa,CAACA,SAASK,QAAQ,CAACL,SAASM,OAAQ;AACpD;IACF;AACA,UAAMQ,WAAW,KAAKN,UAAUO,IAAIf,SAASI,UAAU;AACvD,QAAI,CAACU,UAAU;AACb,WAAKN,UAAUQ,IAAIhB,SAASI,YAAYJ,QAAAA;AACxC,WAAKS,QAAQQ,IAAIjB,SAASI,UAAU;IACtC,OAAO;AACL,UAAIJ,SAASK,QAAQL,SAASK,SAASS,SAAST,MAAM;AACpDS,iBAAST,OAAOL,SAASK;AACzB,aAAKI,QAAQQ,IAAIjB,SAASI,UAAU;MACtC;AACA,UAAIJ,SAASM,SAASN,SAASM,UAAUQ,SAASR,OAAO;AACvDQ,iBAASR,QAAQN,SAASM;AAC1B,aAAKG,QAAQQ,IAAIjB,SAASI,UAAU;MACtC;IACF;EACF;EAEOc,8BAA8B;AACnC,UAAMC,OAAgC,CAAA;AACtC,SAAKV,QAAQW,QAAQ,CAAChB,eAAAA;AACpB,YAAMJ,WAAW,KAAKQ,UAAUO,IAAIX,UAAAA;AACpC,UAAIJ,UAAU;AACZmB,aAAKE,KAAKrB,QAAAA;MACZ;IACF,CAAA;AACA,SAAKS,QAAQa,MAAK;AAClB,WAAOH;EACT;AACF;AAxCqBZ;AAArB,IAAqBA,mBAArB;","names":["consumerFromStringOrObject","consumer","String","trim","substring","identifier","name","group","ConsumerRegistry","consumers","updated","constructor","Map","Set","addOrUpdateConsumer","existing","get","set","add","getAndResetUpdatedConsumers","data","forEach","push","clear"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ApitallyConsumer } from './types.cjs';
|
|
2
|
+
import './logging.cjs';
|
|
3
|
+
import 'winston';
|
|
4
|
+
|
|
5
|
+
declare const consumerFromStringOrObject: (consumer: ApitallyConsumer | string) => ApitallyConsumer | null;
|
|
6
|
+
declare class ConsumerRegistry {
|
|
7
|
+
private consumers;
|
|
8
|
+
private updated;
|
|
9
|
+
constructor();
|
|
10
|
+
addOrUpdateConsumer(consumer?: ApitallyConsumer | null): void;
|
|
11
|
+
getAndResetUpdatedConsumers(): ApitallyConsumer[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { consumerFromStringOrObject, ConsumerRegistry as default };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ApitallyConsumer } from './types.js';
|
|
2
|
+
import './logging.js';
|
|
3
|
+
import 'winston';
|
|
4
|
+
|
|
5
|
+
declare const consumerFromStringOrObject: (consumer: ApitallyConsumer | string) => ApitallyConsumer | null;
|
|
6
|
+
declare class ConsumerRegistry {
|
|
7
|
+
private consumers;
|
|
8
|
+
private updated;
|
|
9
|
+
constructor();
|
|
10
|
+
addOrUpdateConsumer(consumer?: ApitallyConsumer | null): void;
|
|
11
|
+
getAndResetUpdatedConsumers(): ApitallyConsumer[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { consumerFromStringOrObject, ConsumerRegistry as default };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/common/consumerRegistry.ts
|
|
5
|
+
var consumerFromStringOrObject = /* @__PURE__ */ __name((consumer) => {
|
|
6
|
+
var _a, _b;
|
|
7
|
+
if (typeof consumer === "string") {
|
|
8
|
+
consumer = String(consumer).trim().substring(0, 128);
|
|
9
|
+
return consumer ? {
|
|
10
|
+
identifier: consumer
|
|
11
|
+
} : null;
|
|
12
|
+
} else {
|
|
13
|
+
consumer.identifier = String(consumer.identifier).trim().substring(0, 128);
|
|
14
|
+
consumer.name = (_a = consumer.name) == null ? void 0 : _a.trim().substring(0, 64);
|
|
15
|
+
consumer.group = (_b = consumer.group) == null ? void 0 : _b.trim().substring(0, 64);
|
|
16
|
+
return consumer.identifier ? consumer : null;
|
|
17
|
+
}
|
|
18
|
+
}, "consumerFromStringOrObject");
|
|
19
|
+
var _ConsumerRegistry = class _ConsumerRegistry {
|
|
20
|
+
consumers;
|
|
21
|
+
updated;
|
|
22
|
+
constructor() {
|
|
23
|
+
this.consumers = /* @__PURE__ */ new Map();
|
|
24
|
+
this.updated = /* @__PURE__ */ new Set();
|
|
25
|
+
}
|
|
26
|
+
addOrUpdateConsumer(consumer) {
|
|
27
|
+
if (!consumer || !consumer.name && !consumer.group) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const existing = this.consumers.get(consumer.identifier);
|
|
31
|
+
if (!existing) {
|
|
32
|
+
this.consumers.set(consumer.identifier, consumer);
|
|
33
|
+
this.updated.add(consumer.identifier);
|
|
34
|
+
} else {
|
|
35
|
+
if (consumer.name && consumer.name !== existing.name) {
|
|
36
|
+
existing.name = consumer.name;
|
|
37
|
+
this.updated.add(consumer.identifier);
|
|
38
|
+
}
|
|
39
|
+
if (consumer.group && consumer.group !== existing.group) {
|
|
40
|
+
existing.group = consumer.group;
|
|
41
|
+
this.updated.add(consumer.identifier);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
getAndResetUpdatedConsumers() {
|
|
46
|
+
const data = [];
|
|
47
|
+
this.updated.forEach((identifier) => {
|
|
48
|
+
const consumer = this.consumers.get(identifier);
|
|
49
|
+
if (consumer) {
|
|
50
|
+
data.push(consumer);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
this.updated.clear();
|
|
54
|
+
return data;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
__name(_ConsumerRegistry, "ConsumerRegistry");
|
|
58
|
+
var ConsumerRegistry = _ConsumerRegistry;
|
|
59
|
+
export {
|
|
60
|
+
consumerFromStringOrObject,
|
|
61
|
+
ConsumerRegistry as default
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=consumerRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/common/consumerRegistry.ts"],"sourcesContent":["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"],"mappings":";;;;AAEO,IAAMA,6BAA6B,wBACxCC,aAAAA;AADF;AAGE,MAAI,OAAOA,aAAa,UAAU;AAChCA,eAAWC,OAAOD,QAAAA,EAAUE,KAAI,EAAGC,UAAU,GAAG,GAAA;AAChD,WAAOH,WAAW;MAAEI,YAAYJ;IAAS,IAAI;EAC/C,OAAO;AACLA,aAASI,aAAaH,OAAOD,SAASI,UAAU,EAAEF,KAAI,EAAGC,UAAU,GAAG,GAAA;AACtEH,aAASK,QAAOL,cAASK,SAATL,mBAAeE,OAAOC,UAAU,GAAG;AACnDH,aAASM,SAAQN,cAASM,UAATN,mBAAgBE,OAAOC,UAAU,GAAG;AACrD,WAAOH,SAASI,aAAaJ,WAAW;EAC1C;AACF,GAZ0C;AAc1C,IAAqBO,oBAArB,MAAqBA,kBAAAA;EACXC;EACAC;EAERC,cAAc;AACZ,SAAKF,YAAY,oBAAIG,IAAAA;AACrB,SAAKF,UAAU,oBAAIG,IAAAA;EACrB;EAEOC,oBAAoBb,UAAoC;AAC7D,QAAI,CAACA,YAAa,CAACA,SAASK,QAAQ,CAACL,SAASM,OAAQ;AACpD;IACF;AACA,UAAMQ,WAAW,KAAKN,UAAUO,IAAIf,SAASI,UAAU;AACvD,QAAI,CAACU,UAAU;AACb,WAAKN,UAAUQ,IAAIhB,SAASI,YAAYJ,QAAAA;AACxC,WAAKS,QAAQQ,IAAIjB,SAASI,UAAU;IACtC,OAAO;AACL,UAAIJ,SAASK,QAAQL,SAASK,SAASS,SAAST,MAAM;AACpDS,iBAAST,OAAOL,SAASK;AACzB,aAAKI,QAAQQ,IAAIjB,SAASI,UAAU;MACtC;AACA,UAAIJ,SAASM,SAASN,SAASM,UAAUQ,SAASR,OAAO;AACvDQ,iBAASR,QAAQN,SAASM;AAC1B,aAAKG,QAAQQ,IAAIjB,SAASI,UAAU;MACtC;IACF;EACF;EAEOc,8BAA8B;AACnC,UAAMC,OAAgC,CAAA;AACtC,SAAKV,QAAQW,QAAQ,CAAChB,eAAAA;AACpB,YAAMJ,WAAW,KAAKQ,UAAUO,IAAIX,UAAAA;AACpC,UAAIJ,UAAU;AACZmB,aAAKE,KAAKrB,QAAAA;MACZ;IACF,CAAA;AACA,SAAKS,QAAQa,MAAK;AAClB,WAAOH;EACT;AACF;AAxCqBZ;AAArB,IAAqBA,mBAArB;","names":["consumerFromStringOrObject","consumer","String","trim","substring","identifier","name","group","ConsumerRegistry","consumers","updated","constructor","Map","Set","addOrUpdateConsumer","existing","get","set","add","getAndResetUpdatedConsumers","data","forEach","push","clear"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/common/types.ts"],"sourcesContent":["import { Logger } from \"./logging.js\";\n\nexport type ApitallyConfig = {\n clientId: string;\n env?: string;\n openApiUrl?: string;\n appVersion?: string;\n logger?: Logger;\n};\n\nexport type PathInfo = {\n method: string;\n path: string;\n};\n\nexport type
|
|
1
|
+
{"version":3,"sources":["../../src/common/types.ts"],"sourcesContent":["import { Logger } from \"./logging.js\";\n\nexport type ApitallyConfig = {\n clientId: string;\n env?: string;\n openApiUrl?: string;\n appVersion?: string;\n logger?: Logger;\n};\n\nexport type ApitallyConsumer = {\n identifier: string;\n name?: string | null;\n group?: string | null;\n};\n\nexport type PathInfo = {\n method: string;\n path: string;\n};\n\nexport type StartupData = {\n paths: PathInfo[];\n versions: Record<string, string>;\n client: string;\n};\n\nexport type StartupPayload = {\n instance_uuid: string;\n message_uuid: string;\n} & StartupData;\n\nexport type ConsumerMethodPath = {\n consumer?: string | null;\n method: string;\n path: string;\n};\n\nexport type RequestInfo = ConsumerMethodPath & {\n statusCode: number;\n responseTime: number;\n requestSize?: string | number;\n responseSize?: string | number;\n};\n\nexport type RequestsItem = ConsumerMethodPath & {\n status_code: number;\n request_count: number;\n request_size_sum: number;\n response_size_sum: number;\n response_times: Record<number, number>;\n request_sizes: Record<number, number>;\n response_sizes: Record<number, number>;\n};\n\nexport type ValidationError = {\n loc: string;\n msg: string;\n type: string;\n};\n\nexport type ValidationErrorsItem = ConsumerMethodPath & {\n loc: Array<string>;\n msg: string;\n type: string;\n error_count: number;\n};\n\nexport type ServerError = {\n type: string;\n msg: string;\n traceback: string;\n};\n\nexport type ServerErrorsItem = ConsumerMethodPath & {\n type: string;\n msg: string;\n traceback: string;\n sentry_event_id: string | null;\n error_count: number;\n};\n\nexport type ConsumerItem = ApitallyConsumer;\n\nexport type SyncPayload = {\n time_offset: number;\n instance_uuid: string;\n message_uuid: string;\n requests: Array<RequestsItem>;\n validation_errors: Array<ValidationErrorsItem>;\n server_errors: Array<ServerErrorsItem>;\n consumers: Array<ConsumerItem>;\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAoFA;;","names":[]}
|
package/dist/common/types.d.cts
CHANGED
|
@@ -8,19 +8,24 @@ type ApitallyConfig = {
|
|
|
8
8
|
appVersion?: string;
|
|
9
9
|
logger?: Logger;
|
|
10
10
|
};
|
|
11
|
+
type ApitallyConsumer = {
|
|
12
|
+
identifier: string;
|
|
13
|
+
name?: string | null;
|
|
14
|
+
group?: string | null;
|
|
15
|
+
};
|
|
11
16
|
type PathInfo = {
|
|
12
17
|
method: string;
|
|
13
18
|
path: string;
|
|
14
19
|
};
|
|
15
|
-
type
|
|
20
|
+
type StartupData = {
|
|
16
21
|
paths: PathInfo[];
|
|
17
22
|
versions: Record<string, string>;
|
|
18
23
|
client: string;
|
|
19
24
|
};
|
|
20
|
-
type
|
|
25
|
+
type StartupPayload = {
|
|
21
26
|
instance_uuid: string;
|
|
22
27
|
message_uuid: string;
|
|
23
|
-
} &
|
|
28
|
+
} & StartupData;
|
|
24
29
|
type ConsumerMethodPath = {
|
|
25
30
|
consumer?: string | null;
|
|
26
31
|
method: string;
|
|
@@ -64,13 +69,15 @@ type ServerErrorsItem = ConsumerMethodPath & {
|
|
|
64
69
|
sentry_event_id: string | null;
|
|
65
70
|
error_count: number;
|
|
66
71
|
};
|
|
67
|
-
type
|
|
72
|
+
type ConsumerItem = ApitallyConsumer;
|
|
73
|
+
type SyncPayload = {
|
|
68
74
|
time_offset: number;
|
|
69
75
|
instance_uuid: string;
|
|
70
76
|
message_uuid: string;
|
|
71
77
|
requests: Array<RequestsItem>;
|
|
72
78
|
validation_errors: Array<ValidationErrorsItem>;
|
|
73
79
|
server_errors: Array<ServerErrorsItem>;
|
|
80
|
+
consumers: Array<ConsumerItem>;
|
|
74
81
|
};
|
|
75
82
|
|
|
76
|
-
export type { ApitallyConfig,
|
|
83
|
+
export type { ApitallyConfig, ApitallyConsumer, ConsumerItem, ConsumerMethodPath, PathInfo, RequestInfo, RequestsItem, ServerError, ServerErrorsItem, StartupData, StartupPayload, SyncPayload, ValidationError, ValidationErrorsItem };
|