@vtvlive/interactive-apm 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +201 -123
- package/dist/factories/tracing-provider.factory.d.ts +8 -3
- package/dist/factories/tracing-provider.factory.d.ts.map +1 -1
- package/dist/factories/tracing-provider.factory.js +17 -13
- package/dist/index.d.ts +12 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/init/elastic-apm-init.d.ts +25 -3
- package/dist/init/elastic-apm-init.d.ts.map +1 -1
- package/dist/init/elastic-apm-init.js +29 -12
- package/dist/init/opentelemetry-init.d.ts +8 -1
- package/dist/init/opentelemetry-init.d.ts.map +1 -1
- package/dist/init/opentelemetry-init.js +145 -44
- package/dist/interfaces/tracing-provider.interface.d.ts +13 -3
- package/dist/interfaces/tracing-provider.interface.d.ts.map +1 -1
- package/dist/modules/tracing.module.d.ts +5 -5
- package/dist/modules/tracing.module.d.ts.map +1 -1
- package/dist/modules/tracing.module.js +2 -1
- package/dist/providers/elastic-apm.tracing-provider.d.ts +23 -5
- package/dist/providers/elastic-apm.tracing-provider.d.ts.map +1 -1
- package/dist/providers/elastic-apm.tracing-provider.js +127 -28
- package/dist/providers/opentelemetry.tracing-provider.d.ts +12 -4
- package/dist/providers/opentelemetry.tracing-provider.d.ts.map +1 -1
- package/dist/providers/opentelemetry.tracing-provider.js +328 -67
- package/dist/services/tracing.service.d.ts +6 -5
- package/dist/services/tracing.service.d.ts.map +1 -1
- package/dist/services/tracing.service.js +2 -2
- package/dist/types/apm.types.d.ts +162 -0
- package/dist/types/apm.types.d.ts.map +1 -0
- package/dist/types/apm.types.js +37 -0
- package/dist/types/otlp-transport.type.d.ts +14 -0
- package/dist/types/otlp-transport.type.d.ts.map +1 -0
- package/dist/types/otlp-transport.type.js +17 -0
- package/dist/utils/debug-exporter-wrapper.d.ts +36 -0
- package/dist/utils/debug-exporter-wrapper.d.ts.map +1 -0
- package/dist/utils/debug-exporter-wrapper.js +247 -0
- package/dist/utils/debug-logger.d.ts +81 -0
- package/dist/utils/debug-logger.d.ts.map +1 -0
- package/dist/utils/debug-logger.js +236 -0
- package/dist/utils/tracing.helper.d.ts +2 -2
- package/dist/utils/tracing.helper.d.ts.map +1 -1
- package/dist/utils/tracing.helper.js +8 -4
- package/package.json +24 -3
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Debug Logger for APM Package
|
|
4
|
+
*
|
|
5
|
+
* Provides centralized debug logging that only outputs when APM_DEBUG=true.
|
|
6
|
+
* Used by both Elastic APM and OpenTelemetry providers.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.isDebugEnabled = isDebugEnabled;
|
|
10
|
+
exports.sanitizeHeaders = sanitizeHeaders;
|
|
11
|
+
exports.sanitizeConfig = sanitizeConfig;
|
|
12
|
+
exports.debugLog = debugLog;
|
|
13
|
+
exports.infoLog = infoLog;
|
|
14
|
+
exports.errorLog = errorLog;
|
|
15
|
+
exports.logInitialization = logInitialization;
|
|
16
|
+
exports.logExportSuccess = logExportSuccess;
|
|
17
|
+
exports.logExportFailure = logExportFailure;
|
|
18
|
+
exports.logRequest = logRequest;
|
|
19
|
+
exports.logResponse = logResponse;
|
|
20
|
+
exports.logSpan = logSpan;
|
|
21
|
+
/**
|
|
22
|
+
* Check if debug mode is enabled via environment variable
|
|
23
|
+
*/
|
|
24
|
+
function isDebugEnabled() {
|
|
25
|
+
return process.env.APM_DEBUG === "true";
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Mask sensitive values in headers and config for logging
|
|
29
|
+
*/
|
|
30
|
+
function maskSensitive(value, key) {
|
|
31
|
+
const sensitiveKeys = [
|
|
32
|
+
"authorization",
|
|
33
|
+
"token",
|
|
34
|
+
"secret",
|
|
35
|
+
"password",
|
|
36
|
+
"apikey",
|
|
37
|
+
"api-key",
|
|
38
|
+
"x-api-key",
|
|
39
|
+
];
|
|
40
|
+
const lowerKey = key.toLowerCase();
|
|
41
|
+
if (sensitiveKeys.some(k => lowerKey.includes(k))) {
|
|
42
|
+
return "[REDACTED]";
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Sanitize headers for logging (mask sensitive values)
|
|
48
|
+
*/
|
|
49
|
+
function sanitizeHeaders(headers) {
|
|
50
|
+
const sanitized = {};
|
|
51
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
52
|
+
sanitized[key] = maskSensitive(value, key);
|
|
53
|
+
}
|
|
54
|
+
return sanitized;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Sanitize config object for logging (mask sensitive values)
|
|
58
|
+
* Handles arrays and circular references safely
|
|
59
|
+
*/
|
|
60
|
+
function sanitizeConfig(config, seen = new WeakMap()) {
|
|
61
|
+
// Handle primitives and null
|
|
62
|
+
if (config === null || typeof config !== "object") {
|
|
63
|
+
return config;
|
|
64
|
+
}
|
|
65
|
+
// Handle circular references
|
|
66
|
+
if (seen.has(config)) {
|
|
67
|
+
return "[Circular]";
|
|
68
|
+
}
|
|
69
|
+
seen.set(config, "[Circular]");
|
|
70
|
+
// Handle arrays
|
|
71
|
+
if (Array.isArray(config)) {
|
|
72
|
+
return config.map(item => {
|
|
73
|
+
if (typeof item === "string") {
|
|
74
|
+
return maskSensitive(item, "");
|
|
75
|
+
}
|
|
76
|
+
else if (typeof item === "object" && item !== null) {
|
|
77
|
+
return sanitizeConfig(item, seen);
|
|
78
|
+
}
|
|
79
|
+
return item;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// Handle objects
|
|
83
|
+
const sanitized = {};
|
|
84
|
+
for (const [key, value] of Object.entries(config)) {
|
|
85
|
+
if (typeof value === "string") {
|
|
86
|
+
sanitized[key] = maskSensitive(value, key);
|
|
87
|
+
}
|
|
88
|
+
else if (Array.isArray(value)) {
|
|
89
|
+
sanitized[key] = value.map(item => {
|
|
90
|
+
if (typeof item === "string") {
|
|
91
|
+
return maskSensitive(item, key);
|
|
92
|
+
}
|
|
93
|
+
else if (typeof item === "object" && item !== null) {
|
|
94
|
+
return sanitizeConfig(item, seen);
|
|
95
|
+
}
|
|
96
|
+
return item;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
else if (typeof value === "object" && value !== null) {
|
|
100
|
+
sanitized[key] = sanitizeConfig(value, seen);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
sanitized[key] = value;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return sanitized;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Debug log - only outputs when APM_DEBUG=true
|
|
110
|
+
*/
|
|
111
|
+
function debugLog(message, ...args) {
|
|
112
|
+
if (isDebugEnabled()) {
|
|
113
|
+
console.log(`[APM-DEBUG] ${message}`, ...args);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Info log - always outputs
|
|
118
|
+
*/
|
|
119
|
+
function infoLog(message, ...args) {
|
|
120
|
+
console.log(`[APM] ${message}`, ...args);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Error log - always outputs
|
|
124
|
+
*/
|
|
125
|
+
function errorLog(message, ...args) {
|
|
126
|
+
console.error(`[APM-ERROR] ${message}`, ...args);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Log initialization details
|
|
130
|
+
*/
|
|
131
|
+
function logInitialization(provider, config) {
|
|
132
|
+
if (!isDebugEnabled()) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
debugLog(`=== ${provider} Initialization ===`);
|
|
136
|
+
debugLog("Configuration:", sanitizeConfig(config));
|
|
137
|
+
debugLog("Environment Variables:", {
|
|
138
|
+
APM_PROVIDER: process.env.APM_PROVIDER,
|
|
139
|
+
ELASTIC_APM_SERVICE_NAME: process.env.ELASTIC_APM_SERVICE_NAME,
|
|
140
|
+
ELASTIC_APM_ENVIRONMENT: process.env.ELASTIC_APM_ENVIRONMENT,
|
|
141
|
+
ELASTIC_OTLP_ENDPOINT: process.env.ELASTIC_OTLP_ENDPOINT,
|
|
142
|
+
ELASTIC_APM_SERVER_URL: process.env.ELASTIC_APM_SERVER_URL,
|
|
143
|
+
APM_DEBUG: process.env.APM_DEBUG,
|
|
144
|
+
});
|
|
145
|
+
debugLog("System Info:", {
|
|
146
|
+
nodeVersion: process.version,
|
|
147
|
+
platform: process.platform,
|
|
148
|
+
arch: process.arch,
|
|
149
|
+
pid: process.pid,
|
|
150
|
+
hostname: require("os").hostname(),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Log span export success (debug mode only)
|
|
155
|
+
*/
|
|
156
|
+
function logExportSuccess(provider, spanCount) {
|
|
157
|
+
if (isDebugEnabled()) {
|
|
158
|
+
debugLog(`[${provider}] Exported ${spanCount} span(s)`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Log span export failure - ALWAYS logs regardless of debug mode
|
|
163
|
+
*/
|
|
164
|
+
function logExportFailure(provider, error, requestDetails) {
|
|
165
|
+
// Always log export failures as errors
|
|
166
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
167
|
+
errorLog(`[${provider}] Export failed:`, errorMessage);
|
|
168
|
+
// Log additional details only in debug mode
|
|
169
|
+
if (isDebugEnabled() && requestDetails) {
|
|
170
|
+
debugLog("Request details:", sanitizeConfig(requestDetails));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Log outgoing HTTP request (for debugging APM communication)
|
|
175
|
+
*/
|
|
176
|
+
function logRequest(provider, url, headers, body) {
|
|
177
|
+
if (!isDebugEnabled()) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
debugLog(`[${provider}] → Sending request to: ${url}`);
|
|
181
|
+
debugLog("Headers:", sanitizeHeaders(headers));
|
|
182
|
+
// Sanitize request body for sensitive data before logging
|
|
183
|
+
if (body) {
|
|
184
|
+
// WARNING: Request bodies may contain sensitive data - we sanitize common patterns
|
|
185
|
+
let sanitizedBody;
|
|
186
|
+
if (typeof body === "string") {
|
|
187
|
+
// Redact common auth/token patterns in strings
|
|
188
|
+
sanitizedBody = body.replace(/"(password|pass|pwd|token|access_token|auth|authorization|cookie|ssn|creditCard|cardNumber|cvv|secret)"\s*:\s*"[^"]*"/gi, '"$1": "[REDACTED]"');
|
|
189
|
+
sanitizedBody = sanitizedBody.replace(/Bearer\s+[A-Za-z0-9\-._~+/=]*/gi, "Bearer [REDACTED]");
|
|
190
|
+
}
|
|
191
|
+
else if (typeof body === "object" && body !== null) {
|
|
192
|
+
// Deep clone and sanitize object
|
|
193
|
+
sanitizedBody = sanitizeConfig(body);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
sanitizedBody = String(body);
|
|
197
|
+
}
|
|
198
|
+
debugLog("Body:", typeof sanitizedBody === "string" ? sanitizedBody : JSON.stringify(sanitizedBody, null, 2));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Log incoming HTTP response (for debugging APM communication)
|
|
203
|
+
*/
|
|
204
|
+
function logResponse(provider, statusCode, headers, body) {
|
|
205
|
+
if (!isDebugEnabled()) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
debugLog(`[${provider}] ← Received response: ${statusCode}`);
|
|
209
|
+
debugLog("Response Headers:", sanitizeHeaders(headers));
|
|
210
|
+
if (body) {
|
|
211
|
+
debugLog("Response Body:", typeof body === "string" ? body : JSON.stringify(body, null, 2));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Log span details (when debug mode is on)
|
|
216
|
+
*/
|
|
217
|
+
function logSpan(provider, span) {
|
|
218
|
+
if (!isDebugEnabled()) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
const spanDetails = {
|
|
223
|
+
name: span.name,
|
|
224
|
+
kind: span.kind,
|
|
225
|
+
startTime: span.startTime,
|
|
226
|
+
endTime: span.endTime,
|
|
227
|
+
duration: span.endTime - span.startTime,
|
|
228
|
+
attributes: span.attributes,
|
|
229
|
+
status: span.status,
|
|
230
|
+
};
|
|
231
|
+
debugLog(`[${provider}] Span details:`, JSON.stringify(spanDetails, null, 2));
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
debugLog(`[${provider}] Could not serialize span:`, error);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Span, SpanKind } from
|
|
1
|
+
import { Span, SpanKind } from "@opentelemetry/api";
|
|
2
2
|
/**
|
|
3
3
|
* TracingHelper - Static utility class for direct OpenTelemetry usage
|
|
4
4
|
*
|
|
@@ -37,7 +37,7 @@ export declare class TracingHelper {
|
|
|
37
37
|
* @param attributes Các attributes metadata
|
|
38
38
|
* @returns Kết quả của function
|
|
39
39
|
*/
|
|
40
|
-
static startSpanWithParent<T>(name: string, fn: (span: Span) => Promise<T>, attributes?: Record<string, string | number>): Promise<T>;
|
|
40
|
+
static startSpanWithParent<T>(name: string, fn: (span: Span | undefined) => Promise<T>, attributes?: Record<string, string | number>): Promise<T>;
|
|
41
41
|
/**
|
|
42
42
|
* Capture error vào active span hiện tại
|
|
43
43
|
* @param error Error object
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing.helper.d.ts","sourceRoot":"","sources":["../../src/utils/tracing.helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,IAAI,EAAkB,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAsC;IAE3D;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"tracing.helper.d.ts","sourceRoot":"","sources":["../../src/utils/tracing.helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,IAAI,EAAkB,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAsC;IAE3D;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,CACd,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAC5C,QAAQ,GAAE,QAA4B,GACrC,IAAI;IAaP;;;;;;OAMG;IACH,MAAM,CAAC,mBAAmB,CAAC,CAAC,EAC1B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,EAC1C,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAC3C,OAAO,CAAC,CAAC,CAAC;IA2Bb;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAQvC;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAO9D;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI;IAOjC;;;OAGG;IACH,MAAM,CAAC,aAAa,IAAI,IAAI,GAAG,SAAS;IAIxC;;;OAGG;IACH,MAAM,CAAC,UAAU,IAAI,MAAM,GAAG,SAAS;CAIxC"}
|
|
@@ -49,17 +49,21 @@ class TracingHelper {
|
|
|
49
49
|
static startSpanWithParent(name, fn, attributes) {
|
|
50
50
|
return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), TracingHelper.startSpan(name, attributes)), async () => {
|
|
51
51
|
const span = api_1.trace.getActiveSpan();
|
|
52
|
+
// If no active span, throw an error - this should not happen if the span was just started
|
|
53
|
+
if (!span) {
|
|
54
|
+
throw new Error(`Failed to get active span for "${name}". The OpenTelemetry context may not be properly initialized.`);
|
|
55
|
+
}
|
|
52
56
|
try {
|
|
53
57
|
const result = await fn(span);
|
|
54
58
|
return result;
|
|
55
59
|
}
|
|
56
60
|
catch (error) {
|
|
57
|
-
span
|
|
58
|
-
span
|
|
61
|
+
span.recordException(error);
|
|
62
|
+
span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: error.message });
|
|
59
63
|
throw error;
|
|
60
64
|
}
|
|
61
65
|
finally {
|
|
62
|
-
span
|
|
66
|
+
span.end();
|
|
63
67
|
}
|
|
64
68
|
});
|
|
65
69
|
}
|
|
@@ -112,4 +116,4 @@ class TracingHelper {
|
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
118
|
exports.TracingHelper = TracingHelper;
|
|
115
|
-
TracingHelper.tracer = api_1.trace.getTracer(
|
|
119
|
+
TracingHelper.tracer = api_1.trace.getTracer("interactive-apm");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vtvlive/interactive-apm",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "APM integration package supporting both Elastic APM and OpenTelemetry with NestJS integration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -28,13 +28,20 @@
|
|
|
28
28
|
"test:watch": "jest --watch",
|
|
29
29
|
"test:coverage": "jest --coverage",
|
|
30
30
|
"test:unit": "jest __tests__/unit",
|
|
31
|
-
"test:integration": "jest __tests__/integration"
|
|
31
|
+
"test:integration": "jest __tests__/integration",
|
|
32
|
+
"lint": "eslint src",
|
|
33
|
+
"lint:fix": "eslint src --fix",
|
|
34
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
35
|
+
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
36
|
+
"typecheck": "tsc --noEmit"
|
|
32
37
|
},
|
|
33
38
|
"peerDependencies": {
|
|
34
39
|
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0",
|
|
35
40
|
"@nestjs/config": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0",
|
|
36
41
|
"@opentelemetry/api": "^1.0.0",
|
|
37
42
|
"@opentelemetry/exporter-trace-otlp-http": ">=0.200.0",
|
|
43
|
+
"@opentelemetry/exporter-trace-otlp-grpc": ">=0.200.0",
|
|
44
|
+
"@opentelemetry/exporter-trace-otlp-proto": ">=0.200.0",
|
|
38
45
|
"@opentelemetry/instrumentation-express": ">=0.50.0",
|
|
39
46
|
"@opentelemetry/instrumentation-http": ">=0.200.0",
|
|
40
47
|
"@opentelemetry/resources": ">=1.0.0",
|
|
@@ -56,6 +63,12 @@
|
|
|
56
63
|
"@opentelemetry/exporter-trace-otlp-http": {
|
|
57
64
|
"optional": true
|
|
58
65
|
},
|
|
66
|
+
"@opentelemetry/exporter-trace-otlp-grpc": {
|
|
67
|
+
"optional": true
|
|
68
|
+
},
|
|
69
|
+
"@opentelemetry/exporter-trace-otlp-proto": {
|
|
70
|
+
"optional": true
|
|
71
|
+
},
|
|
59
72
|
"@opentelemetry/instrumentation-express": {
|
|
60
73
|
"optional": true
|
|
61
74
|
},
|
|
@@ -83,6 +96,8 @@
|
|
|
83
96
|
"@nestjs/config": "^4.0.3",
|
|
84
97
|
"@opentelemetry/api": "^1.9.0",
|
|
85
98
|
"@opentelemetry/exporter-trace-otlp-http": "^0.213.0",
|
|
99
|
+
"@opentelemetry/exporter-trace-otlp-grpc": "^0.213.0",
|
|
100
|
+
"@opentelemetry/exporter-trace-otlp-proto": "^0.213.0",
|
|
86
101
|
"@opentelemetry/instrumentation-express": "^0.61.0",
|
|
87
102
|
"@opentelemetry/instrumentation-http": "^0.213.0",
|
|
88
103
|
"@opentelemetry/resources": "^2.6.0",
|
|
@@ -92,9 +107,15 @@
|
|
|
92
107
|
"@types/jest": "^29.5.0",
|
|
93
108
|
"@types/node": "^20.0.0",
|
|
94
109
|
"elastic-apm-node": "^4.15.0",
|
|
110
|
+
"eslint": "^9.18.0",
|
|
111
|
+
"eslint-config-prettier": "^9.1.0",
|
|
112
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
95
113
|
"jest": "^29.7.0",
|
|
114
|
+
"prettier": "^3.4.2",
|
|
96
115
|
"ts-jest": "^29.1.0",
|
|
97
|
-
"typescript": "^5.3.0"
|
|
116
|
+
"typescript": "^5.3.0",
|
|
117
|
+
"@typescript-eslint/eslint-plugin": "^8.19.1",
|
|
118
|
+
"@typescript-eslint/parser": "^8.19.1"
|
|
98
119
|
},
|
|
99
120
|
"engines": {
|
|
100
121
|
"node": ">=14.0.0"
|