@tracekit/node-apm 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 TraceKit
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,373 @@
1
+ # TraceKit APM for Node.js
2
+
3
+ Zero-config distributed tracing and performance monitoring for Express and NestJS applications.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@tracekit/node-apm.svg)](https://www.npmjs.com/package/@tracekit/node-apm)
6
+ [![Downloads](https://img.shields.io/npm/dm/@tracekit/node-apm.svg)](https://www.npmjs.com/package/@tracekit/node-apm)
7
+ [![License](https://img.shields.io/npm/l/@tracekit/node-apm.svg)](https://www.npmjs.com/package/@tracekit/node-apm)
8
+
9
+ ## Features
10
+
11
+ - **Zero Configuration** - Works out of the box with sensible defaults
12
+ - **Automatic Instrumentation** - No code changes needed
13
+ - **Express Support** - Simple middleware integration
14
+ - **NestJS Support** - Module and interceptor-based tracing
15
+ - **TypeScript First** - Full type definitions included
16
+ - **HTTP Request Tracing** - Track every request, route, and handler
17
+ - **Error Tracking** - Capture exceptions with full context
18
+ - **Low Overhead** - < 5% performance impact
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install @tracekit/node-apm
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ### Express
29
+
30
+ ```javascript
31
+ const express = require('express');
32
+ const tracekit = require('@tracekit/node-apm');
33
+
34
+ const app = express();
35
+
36
+ // Initialize TraceKit
37
+ tracekit.init({
38
+ apiKey: process.env.TRACEKIT_API_KEY,
39
+ serviceName: 'my-express-app',
40
+ });
41
+
42
+ // Add middleware (must be before routes)
43
+ app.use(tracekit.middleware());
44
+
45
+ // Your routes
46
+ app.get('/', (req, res) => {
47
+ res.send('Hello World!');
48
+ });
49
+
50
+ app.listen(3000);
51
+ ```
52
+
53
+ ### Express (TypeScript)
54
+
55
+ ```typescript
56
+ import express from 'express';
57
+ import * as tracekit from '@tracekit/node-apm';
58
+
59
+ const app = express();
60
+
61
+ // Initialize TraceKit
62
+ tracekit.init({
63
+ apiKey: process.env.TRACEKIT_API_KEY!,
64
+ serviceName: 'my-express-app',
65
+ });
66
+
67
+ // Add middleware
68
+ app.use(tracekit.middleware());
69
+
70
+ // Your routes
71
+ app.get('/', (req, res) => {
72
+ res.send('Hello World!');
73
+ });
74
+
75
+ app.listen(3000);
76
+ ```
77
+
78
+ ### NestJS
79
+
80
+ ```typescript
81
+ // app.module.ts
82
+ import { Module } from '@nestjs/common';
83
+ import { TracekitModule } from '@tracekit/node-apm/nestjs';
84
+
85
+ @Module({
86
+ imports: [
87
+ TracekitModule.forRoot({
88
+ apiKey: process.env.TRACEKIT_API_KEY!,
89
+ serviceName: 'my-nestjs-app',
90
+ }),
91
+ ],
92
+ })
93
+ export class AppModule {}
94
+ ```
95
+
96
+ That's it! Your app is now automatically traced.
97
+
98
+ Get your API key at [https://app.tracekit.dev](https://app.tracekit.dev)
99
+
100
+ ## Configuration
101
+
102
+ ### Basic Configuration
103
+
104
+ ```typescript
105
+ import * as tracekit from '@tracekit/node-apm';
106
+
107
+ tracekit.init({
108
+ // Required: Your TraceKit API key
109
+ apiKey: process.env.TRACEKIT_API_KEY,
110
+
111
+ // Optional: Service name (default: 'node-app')
112
+ serviceName: 'my-service',
113
+
114
+ // Optional: TraceKit endpoint (default: 'https://app.tracekit.dev/v1/traces')
115
+ endpoint: 'https://app.tracekit.dev/v1/traces',
116
+
117
+ // Optional: Enable/disable tracing (default: true)
118
+ enabled: process.env.NODE_ENV !== 'development',
119
+
120
+ // Optional: Sample rate 0.0-1.0 (default: 1.0 = 100%)
121
+ sampleRate: 0.5, // Trace 50% of requests
122
+ });
123
+ ```
124
+
125
+ ### NestJS Async Configuration
126
+
127
+ ```typescript
128
+ import { Module } from '@nestjs/common';
129
+ import { ConfigModule, ConfigService } from '@nestjs/config';
130
+ import { TracekitModule } from '@tracekit/node-apm/nestjs';
131
+
132
+ @Module({
133
+ imports: [
134
+ ConfigModule.forRoot(),
135
+ TracekitModule.forRootAsync({
136
+ inject: [ConfigService],
137
+ useFactory: (config: ConfigService) => ({
138
+ apiKey: config.get('TRACEKIT_API_KEY')!,
139
+ serviceName: config.get('APP_NAME', 'my-app'),
140
+ enabled: config.get('NODE_ENV') !== 'development',
141
+ }),
142
+ }),
143
+ ],
144
+ })
145
+ export class AppModule {}
146
+ ```
147
+
148
+ ## What Gets Traced?
149
+
150
+ ### HTTP Requests
151
+
152
+ Every HTTP request is automatically traced with:
153
+
154
+ - Route path and HTTP method
155
+ - Request URL and query parameters
156
+ - HTTP status code
157
+ - Request duration
158
+ - User agent and client IP
159
+ - Controller and handler names (NestJS)
160
+
161
+ ### Errors and Exceptions
162
+
163
+ All exceptions are automatically captured with:
164
+
165
+ - Exception type and message
166
+ - Full stack trace
167
+ - Request context
168
+ - Handler information
169
+
170
+ ## Advanced Usage
171
+
172
+ ### Manual Tracing (Express)
173
+
174
+ ```typescript
175
+ import { getClient } from '@tracekit/node-apm';
176
+
177
+ app.get('/custom', async (req, res) => {
178
+ const client = getClient();
179
+
180
+ const span = client.startSpan('my-operation', null, {
181
+ 'user.id': req.user?.id,
182
+ 'custom.attribute': 'value',
183
+ });
184
+
185
+ try {
186
+ const result = await doSomething();
187
+
188
+ client.endSpan(span, {
189
+ 'result.count': result.length,
190
+ });
191
+
192
+ res.json(result);
193
+ } catch (error) {
194
+ client.recordException(span, error as Error);
195
+ client.endSpan(span, {}, 'ERROR');
196
+ throw error;
197
+ }
198
+ });
199
+ ```
200
+
201
+ ### Manual Tracing (NestJS)
202
+
203
+ ```typescript
204
+ import { Injectable, Inject } from '@nestjs/common';
205
+ import { TracekitClient } from '@tracekit/node-apm/nestjs';
206
+
207
+ @Injectable()
208
+ export class MyService {
209
+ constructor(
210
+ @Inject('TRACEKIT_CLIENT') private tracekit: TracekitClient
211
+ ) {}
212
+
213
+ async doSomething() {
214
+ const span = this.tracekit.startSpan('custom-operation', null, {
215
+ 'operation.type': 'database',
216
+ });
217
+
218
+ try {
219
+ const result = await this.database.query();
220
+
221
+ this.tracekit.endSpan(span, {
222
+ 'rows.count': result.length,
223
+ });
224
+
225
+ return result;
226
+ } catch (error) {
227
+ this.tracekit.recordException(span, error as Error);
228
+ this.tracekit.endSpan(span, {}, 'ERROR');
229
+ throw error;
230
+ }
231
+ }
232
+ }
233
+ ```
234
+
235
+ ## Environment-Based Configuration
236
+
237
+ ### Disable tracing in development
238
+
239
+ ```typescript
240
+ tracekit.init({
241
+ apiKey: process.env.TRACEKIT_API_KEY!,
242
+ enabled: process.env.NODE_ENV === 'production',
243
+ });
244
+ ```
245
+
246
+ ### Sample only 10% of requests
247
+
248
+ ```typescript
249
+ tracekit.init({
250
+ apiKey: process.env.TRACEKIT_API_KEY!,
251
+ sampleRate: 0.1, // Trace 10% of requests
252
+ });
253
+ ```
254
+
255
+ ## Performance
256
+
257
+ TraceKit APM is designed to have minimal performance impact:
258
+
259
+ - **< 5% overhead** on average request time
260
+ - Asynchronous trace sending (doesn't block responses)
261
+ - Automatic batching and compression
262
+ - Configurable sampling for high-traffic apps
263
+
264
+ ## TypeScript Support
265
+
266
+ Full TypeScript support with type definitions included:
267
+
268
+ ```typescript
269
+ import { TracekitClient, TracekitConfig, Span } from '@tracekit/node-apm';
270
+
271
+ const config: TracekitConfig = {
272
+ apiKey: 'your-key',
273
+ serviceName: 'my-app',
274
+ };
275
+
276
+ const attributes: Record<string, any> = {
277
+ 'user.id': 123,
278
+ 'request.path': '/api/users',
279
+ };
280
+
281
+ // Using the client
282
+ const client = new TracekitClient(config);
283
+ const span: Span = client.startSpan('my-operation', null, attributes);
284
+ ```
285
+
286
+ ## Requirements
287
+
288
+ - Node.js 16.x or higher
289
+ - Express 4.x or 5.x (for Express support)
290
+ - NestJS 10.x (for NestJS support)
291
+
292
+ ## Examples
293
+
294
+ ### Express Example
295
+
296
+ ```javascript
297
+ const express = require('express');
298
+ const tracekit = require('@tracekit/node-apm');
299
+
300
+ const app = express();
301
+
302
+ tracekit.init({
303
+ apiKey: process.env.TRACEKIT_API_KEY,
304
+ serviceName: 'express-example',
305
+ });
306
+
307
+ app.use(tracekit.middleware());
308
+
309
+ app.get('/users', async (req, res) => {
310
+ const users = await db.getUsers();
311
+ res.json(users);
312
+ });
313
+
314
+ app.listen(3000);
315
+ ```
316
+
317
+ ### NestJS Example
318
+
319
+ ```typescript
320
+ // main.ts
321
+ import { NestFactory } from '@nestjs/core';
322
+ import { AppModule } from './app.module';
323
+
324
+ async function bootstrap() {
325
+ const app = await NestFactory.create(AppModule);
326
+ await app.listen(3000);
327
+ }
328
+ bootstrap();
329
+
330
+ // app.module.ts
331
+ import { Module } from '@nestjs/common';
332
+ import { TracekitModule } from '@tracekit/node-apm/nestjs';
333
+ import { UsersModule } from './users/users.module';
334
+
335
+ @Module({
336
+ imports: [
337
+ TracekitModule.forRoot({
338
+ apiKey: process.env.TRACEKIT_API_KEY!,
339
+ serviceName: 'nestjs-example',
340
+ }),
341
+ UsersModule,
342
+ ],
343
+ })
344
+ export class AppModule {}
345
+
346
+ // users.controller.ts
347
+ import { Controller, Get } from '@nestjs/common';
348
+ import { UsersService } from './users.service';
349
+
350
+ @Controller('users')
351
+ export class UsersController {
352
+ constructor(private usersService: UsersService) {}
353
+
354
+ @Get()
355
+ findAll() {
356
+ return this.usersService.findAll();
357
+ }
358
+ }
359
+ ```
360
+
361
+ ## Support
362
+
363
+ - Documentation: [https://app.tracekit.dev/docs](https://app.tracekit.dev/docs)
364
+ - Issues: [https://github.com/Tracekit-Dev/node-apm/issues](https://github.com/Tracekit-Dev/node-apm/issues)
365
+ - Email: support@tracekit.dev
366
+
367
+ ## License
368
+
369
+ MIT License. See [LICENSE](LICENSE) for details.
370
+
371
+ ## Credits
372
+
373
+ Built with ❤️ by the TraceKit team.
@@ -0,0 +1,26 @@
1
+ import * as api from '@opentelemetry/api';
2
+ export interface TracekitConfig {
3
+ apiKey: string;
4
+ endpoint?: string;
5
+ serviceName?: string;
6
+ enabled?: boolean;
7
+ sampleRate?: number;
8
+ }
9
+ export declare class TracekitClient {
10
+ private provider;
11
+ private tracer;
12
+ private config;
13
+ constructor(config: TracekitConfig);
14
+ startTrace(operationName: string, attributes?: Record<string, any>): api.Span;
15
+ startSpan(operationName: string, parentSpan?: api.Span | null, attributes?: Record<string, any>): api.Span;
16
+ endSpan(span: api.Span, finalAttributes?: Record<string, any>, status?: string): void;
17
+ addEvent(span: api.Span, name: string, attributes?: Record<string, any>): void;
18
+ recordException(span: api.Span, error: Error): void;
19
+ flush(): Promise<void>;
20
+ shutdown(): Promise<void>;
21
+ isEnabled(): boolean;
22
+ shouldSample(): boolean;
23
+ getTracer(): api.Tracer;
24
+ private normalizeAttributes;
25
+ }
26
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,GAAG,MAAM,oBAAoB,CAAC;AAE1C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,MAAM,CAA2B;gBAE7B,MAAM,EAAE,cAAc;IAsClC,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GAAG,GAAG,CAAC,IAAI;IAOjF,SAAS,CACP,aAAa,EAAE,MAAM,EACrB,UAAU,CAAC,EAAE,GAAG,CAAC,IAAI,GAAG,IAAI,EAC5B,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GACnC,GAAG,CAAC,IAAI;IAcX,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,eAAe,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAgBzF,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GAAG,IAAI;IAIlF,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAQ7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,SAAS,IAAI,OAAO;IAIpB,YAAY,IAAI,OAAO;IAIvB,SAAS,IAAI,GAAG,CAAC,MAAM;IAIvB,OAAO,CAAC,mBAAmB;CAiB5B"}
package/dist/client.js ADDED
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.TracekitClient = void 0;
37
+ const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node");
38
+ const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
39
+ const resources_1 = require("@opentelemetry/resources");
40
+ const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
41
+ const sdk_trace_node_2 = require("@opentelemetry/sdk-trace-node");
42
+ const api = __importStar(require("@opentelemetry/api"));
43
+ class TracekitClient {
44
+ constructor(config) {
45
+ this.config = {
46
+ endpoint: config.endpoint || 'https://app.tracekit.dev/v1/traces',
47
+ serviceName: config.serviceName || 'node-app',
48
+ enabled: config.enabled ?? true,
49
+ sampleRate: config.sampleRate ?? 1.0,
50
+ apiKey: config.apiKey,
51
+ };
52
+ const resource = new resources_1.Resource({
53
+ [semantic_conventions_1.SemanticResourceAttributes.SERVICE_NAME]: this.config.serviceName,
54
+ });
55
+ this.provider = new sdk_trace_node_1.NodeTracerProvider({
56
+ resource,
57
+ });
58
+ if (this.config.enabled) {
59
+ const exporter = new exporter_trace_otlp_http_1.OTLPTraceExporter({
60
+ url: this.config.endpoint,
61
+ headers: {
62
+ 'X-API-Key': this.config.apiKey,
63
+ },
64
+ });
65
+ this.provider.addSpanProcessor(new sdk_trace_node_2.BatchSpanProcessor(exporter));
66
+ this.provider.register();
67
+ }
68
+ this.tracer = api.trace.getTracer('@tracekit/node-apm', '1.0.0');
69
+ }
70
+ startTrace(operationName, attributes = {}) {
71
+ return this.tracer.startSpan(operationName, {
72
+ kind: api.SpanKind.SERVER,
73
+ attributes: this.normalizeAttributes(attributes),
74
+ });
75
+ }
76
+ startSpan(operationName, parentSpan, attributes = {}) {
77
+ const options = {
78
+ kind: api.SpanKind.INTERNAL,
79
+ attributes: this.normalizeAttributes(attributes),
80
+ };
81
+ if (parentSpan) {
82
+ const ctx = api.trace.setSpan(api.context.active(), parentSpan);
83
+ return this.tracer.startSpan(operationName, options, ctx);
84
+ }
85
+ return this.tracer.startSpan(operationName, options);
86
+ }
87
+ endSpan(span, finalAttributes = {}, status) {
88
+ if (Object.keys(finalAttributes).length > 0) {
89
+ span.setAttributes(this.normalizeAttributes(finalAttributes));
90
+ }
91
+ if (status === 'ERROR') {
92
+ span.setStatus({ code: api.SpanStatusCode.ERROR });
93
+ }
94
+ else if (status === 'OK') {
95
+ span.setStatus({ code: api.SpanStatusCode.OK });
96
+ }
97
+ span.end();
98
+ }
99
+ addEvent(span, name, attributes = {}) {
100
+ span.addEvent(name, this.normalizeAttributes(attributes));
101
+ }
102
+ recordException(span, error) {
103
+ span.recordException(error);
104
+ span.setStatus({
105
+ code: api.SpanStatusCode.ERROR,
106
+ message: error.message,
107
+ });
108
+ }
109
+ async flush() {
110
+ await this.provider.forceFlush();
111
+ }
112
+ async shutdown() {
113
+ await this.provider.shutdown();
114
+ }
115
+ isEnabled() {
116
+ return this.config.enabled && !!this.config.apiKey;
117
+ }
118
+ shouldSample() {
119
+ return Math.random() < this.config.sampleRate;
120
+ }
121
+ getTracer() {
122
+ return this.tracer;
123
+ }
124
+ normalizeAttributes(attributes) {
125
+ const normalized = {};
126
+ for (const [key, value] of Object.entries(attributes)) {
127
+ if (typeof value === 'string' ||
128
+ typeof value === 'number' ||
129
+ typeof value === 'boolean') {
130
+ normalized[key] = value;
131
+ }
132
+ else if (Array.isArray(value)) {
133
+ normalized[key] = value.map(String);
134
+ }
135
+ else {
136
+ normalized[key] = String(value);
137
+ }
138
+ }
139
+ return normalized;
140
+ }
141
+ }
142
+ exports.TracekitClient = TracekitClient;
143
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { TracekitClient, TracekitConfig } from './client';
2
+ export declare function init(config: TracekitConfig): TracekitClient;
3
+ export declare function middleware(): (req: import("express").Request, res: import("express").Response, next: import("express").NextFunction) => Promise<void>;
4
+ export declare function getClient(): TracekitClient;
5
+ export { TracekitClient, TracekitConfig } from './client';
6
+ export { createExpressMiddleware, getCurrentSpan } from './middleware/express';
7
+ export { Span, Context } from '@opentelemetry/api';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAQ1D,wBAAgB,IAAI,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAG3D;AAKD,wBAAgB,UAAU,6HAOzB;AAKD,wBAAgB,SAAS,IAAI,cAAc,CAO1C;AAGD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG/E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCurrentSpan = exports.createExpressMiddleware = exports.TracekitClient = void 0;
4
+ exports.init = init;
5
+ exports.middleware = middleware;
6
+ exports.getClient = getClient;
7
+ const client_1 = require("./client");
8
+ const express_1 = require("./middleware/express");
9
+ let globalClient = null;
10
+ function init(config) {
11
+ globalClient = new client_1.TracekitClient(config);
12
+ return globalClient;
13
+ }
14
+ function middleware() {
15
+ if (!globalClient) {
16
+ throw new Error('TraceKit not initialized. Call tracekit.init() first.');
17
+ }
18
+ return (0, express_1.createExpressMiddleware)(globalClient);
19
+ }
20
+ function getClient() {
21
+ if (!globalClient) {
22
+ throw new Error('TraceKit not initialized. Call tracekit.init() first.');
23
+ }
24
+ return globalClient;
25
+ }
26
+ var client_2 = require("./client");
27
+ Object.defineProperty(exports, "TracekitClient", { enumerable: true, get: function () { return client_2.TracekitClient; } });
28
+ var express_2 = require("./middleware/express");
29
+ Object.defineProperty(exports, "createExpressMiddleware", { enumerable: true, get: function () { return express_2.createExpressMiddleware; } });
30
+ Object.defineProperty(exports, "getCurrentSpan", { enumerable: true, get: function () { return express_2.getCurrentSpan; } });
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAQA,oBAGC;AAKD,gCAOC;AAKD,8BAOC;AAnCD,qCAA0D;AAC1D,kDAA+D;AAE/D,IAAI,YAAY,GAA0B,IAAI,CAAC;AAK/C,SAAgB,IAAI,CAAC,MAAsB;IACzC,YAAY,GAAG,IAAI,uBAAc,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,YAAY,CAAC;AACtB,CAAC;AAKD,SAAgB,UAAU;IACxB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,uDAAuD,CACxD,CAAC;IACJ,CAAC;IACD,OAAO,IAAA,iCAAuB,EAAC,YAAY,CAAC,CAAC;AAC/C,CAAC;AAKD,SAAgB,SAAS;IACvB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,uDAAuD,CACxD,CAAC;IACJ,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAGD,mCAA0D;AAAjD,wGAAA,cAAc,OAAA;AACvB,gDAA+E;AAAtE,kHAAA,uBAAuB,OAAA;AAAE,yGAAA,cAAc,OAAA"}
@@ -0,0 +1,6 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ import { TracekitClient } from '../client';
3
+ import * as api from '@opentelemetry/api';
4
+ export declare function createExpressMiddleware(client: TracekitClient): (req: Request, res: Response, next: NextFunction) => Promise<void>;
5
+ export declare function getCurrentSpan(req: Request): api.Span | null;
6
+ //# sourceMappingURL=express.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,GAAG,MAAM,oBAAoB,CAAC;AAE1C,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,cAAc,IAC9C,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,mBAwD9D;AAGD,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,CAE5D"}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createExpressMiddleware = createExpressMiddleware;
4
+ exports.getCurrentSpan = getCurrentSpan;
5
+ function createExpressMiddleware(client) {
6
+ return async (req, res, next) => {
7
+ if (!client.isEnabled() || !client.shouldSample()) {
8
+ return next();
9
+ }
10
+ const startTime = Date.now();
11
+ const operationName = getOperationName(req);
12
+ const span = client.startTrace(operationName, {
13
+ 'http.method': req.method,
14
+ 'http.url': req.originalUrl || req.url,
15
+ 'http.route': req.route?.path || req.path,
16
+ 'http.user_agent': req.get('user-agent') || '',
17
+ 'http.client_ip': getClientIp(req),
18
+ });
19
+ req.__tracekitSpan = span;
20
+ const originalSend = res.send;
21
+ let responseSent = false;
22
+ res.send = function (body) {
23
+ if (!responseSent) {
24
+ responseSent = true;
25
+ const durationMs = Date.now() - startTime;
26
+ client.endSpan(span, {
27
+ 'http.status_code': res.statusCode,
28
+ 'http.duration_ms': durationMs,
29
+ }, res.statusCode >= 400 ? 'ERROR' : 'OK');
30
+ }
31
+ return originalSend.call(this, body);
32
+ };
33
+ try {
34
+ next();
35
+ }
36
+ catch (error) {
37
+ if (error instanceof Error) {
38
+ client.recordException(span, error);
39
+ client.endSpan(span, {}, 'ERROR');
40
+ }
41
+ throw error;
42
+ }
43
+ };
44
+ }
45
+ function getCurrentSpan(req) {
46
+ return req.__tracekitSpan || null;
47
+ }
48
+ function getOperationName(req) {
49
+ if (req.route?.path) {
50
+ return `${req.method} ${req.route.path}`;
51
+ }
52
+ return `${req.method} ${req.path}`;
53
+ }
54
+ function getClientIp(req) {
55
+ return (req.headers['x-forwarded-for']?.split(',')[0]?.trim() ||
56
+ req.headers['x-real-ip'] ||
57
+ req.socket.remoteAddress ||
58
+ '');
59
+ }
60
+ //# sourceMappingURL=express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":";;AAIA,0DAyDC;AAGD,wCAEC;AA9DD,SAAgB,uBAAuB,CAAC,MAAsB;IAC5D,OAAO,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QAE/D,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,CAAC;YAClD,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAG7B,MAAM,aAAa,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAG5C,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,aAAa,EAAE;YAC5C,aAAa,EAAE,GAAG,CAAC,MAAM;YACzB,UAAU,EAAE,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,GAAG;YACtC,YAAY,EAAG,GAAG,CAAC,KAAK,EAAE,IAAe,IAAI,GAAG,CAAC,IAAI;YACrD,iBAAiB,EAAE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE;YAC9C,gBAAgB,EAAE,WAAW,CAAC,GAAG,CAAC;SACnC,CAAC,CAAC;QAGF,GAAW,CAAC,cAAc,GAAG,IAAI,CAAC;QAGnC,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC;QAC9B,IAAI,YAAY,GAAG,KAAK,CAAC;QAEzB,GAAG,CAAC,IAAI,GAAG,UAAU,IAAS;YAC5B,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,YAAY,GAAG,IAAI,CAAC;gBACpB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;gBAE1C,MAAM,CAAC,OAAO,CACZ,IAAI,EACJ;oBACE,kBAAkB,EAAE,GAAG,CAAC,UAAU;oBAClC,kBAAkB,EAAE,UAAU;iBAC/B,EACD,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CACvC,CAAC;YACJ,CAAC;YAED,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC;QAGF,IAAI,CAAC;YACH,IAAI,EAAE,CAAC;QACT,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC3B,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBACpC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YACpC,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAGD,SAAgB,cAAc,CAAC,GAAY;IACzC,OAAQ,GAAW,CAAC,cAAc,IAAI,IAAI,CAAC;AAC7C,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAY;IAEpC,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;QACpB,OAAO,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC3C,CAAC;IAGD,OAAO,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,WAAW,CAAC,GAAY;IAC/B,OAAO,CACJ,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE;QAChE,GAAG,CAAC,OAAO,CAAC,WAAW,CAAY;QACpC,GAAG,CAAC,MAAM,CAAC,aAAa;QACxB,EAAE,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { TracekitModule } from './tracekit.module';
2
+ export { TracekitInterceptor } from './tracekit.interceptor';
3
+ export { TracekitClient, TracekitConfig } from '../client';
4
+ export { Span } from '@opentelemetry/api';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/nestjs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TracekitClient = exports.TracekitInterceptor = exports.TracekitModule = void 0;
4
+ var tracekit_module_1 = require("./tracekit.module");
5
+ Object.defineProperty(exports, "TracekitModule", { enumerable: true, get: function () { return tracekit_module_1.TracekitModule; } });
6
+ var tracekit_interceptor_1 = require("./tracekit.interceptor");
7
+ Object.defineProperty(exports, "TracekitInterceptor", { enumerable: true, get: function () { return tracekit_interceptor_1.TracekitInterceptor; } });
8
+ var client_1 = require("../client");
9
+ Object.defineProperty(exports, "TracekitClient", { enumerable: true, get: function () { return client_1.TracekitClient; } });
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/nestjs/index.ts"],"names":[],"mappings":";;;AAAA,qDAAmD;AAA1C,iHAAA,cAAc,OAAA;AACvB,+DAA6D;AAApD,2HAAA,mBAAmB,OAAA;AAC5B,oCAA2D;AAAlD,wGAAA,cAAc,OAAA"}
@@ -0,0 +1,10 @@
1
+ import { NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
2
+ import { Observable } from 'rxjs';
3
+ import { TracekitClient } from '../client';
4
+ export declare class TracekitInterceptor implements NestInterceptor {
5
+ private readonly client;
6
+ constructor(client: TracekitClient);
7
+ intercept(context: ExecutionContext, next: CallHandler): Observable<any>;
8
+ private getClientIp;
9
+ }
10
+ //# sourceMappingURL=tracekit.interceptor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracekit.interceptor.d.ts","sourceRoot":"","sources":["../../src/nestjs/tracekit.interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,gBAAgB,EAChB,WAAW,EAEZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAc,MAAM,MAAM,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,qBACa,mBAAoB,YAAW,eAAe;IAE5B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,cAAc;IAGpE,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC;IAyExE,OAAO,CAAC,WAAW;CAQpB"}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.TracekitInterceptor = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const rxjs_1 = require("rxjs");
18
+ const operators_1 = require("rxjs/operators");
19
+ const client_1 = require("../client");
20
+ let TracekitInterceptor = class TracekitInterceptor {
21
+ constructor(client) {
22
+ this.client = client;
23
+ }
24
+ intercept(context, next) {
25
+ if (context.getType() !== 'http') {
26
+ return next.handle();
27
+ }
28
+ if (!this.client.isEnabled() || !this.client.shouldSample()) {
29
+ return next.handle();
30
+ }
31
+ const request = context.switchToHttp().getRequest();
32
+ const response = context.switchToHttp().getResponse();
33
+ const startTime = process.hrtime();
34
+ const handler = context.getHandler().name;
35
+ const controller = context.getClass().name;
36
+ const operationName = `${controller}.${handler}`;
37
+ const spanId = this.client.startTrace(operationName, {
38
+ 'http.method': request.method,
39
+ 'http.url': request.url,
40
+ 'http.route': request.route?.path || request.url,
41
+ 'http.user_agent': request.get('user-agent') || '',
42
+ 'http.client_ip': this.getClientIp(request),
43
+ 'nestjs.controller': controller,
44
+ 'nestjs.handler': handler,
45
+ });
46
+ return next.handle().pipe((0, operators_1.tap)(() => {
47
+ const [seconds, nanos] = process.hrtime(startTime);
48
+ const durationMs = seconds * 1000 + nanos / 1000000;
49
+ this.client.endSpan(spanId, {
50
+ 'http.status_code': response.statusCode,
51
+ 'http.duration_ms': Math.round(durationMs),
52
+ }, response.statusCode >= 400 ? 'ERROR' : 'OK');
53
+ this.client.flush().catch((err) => {
54
+ console.warn('TraceKit: Failed to flush traces', err);
55
+ });
56
+ }), (0, operators_1.catchError)((error) => {
57
+ const [seconds, nanos] = process.hrtime(startTime);
58
+ const durationMs = seconds * 1000 + nanos / 1000000;
59
+ this.client.recordException(spanId, error);
60
+ this.client.endSpan(spanId, {
61
+ 'http.duration_ms': Math.round(durationMs),
62
+ }, 'ERROR');
63
+ this.client.flush().catch(() => { });
64
+ return (0, rxjs_1.throwError)(() => error);
65
+ }));
66
+ }
67
+ getClientIp(request) {
68
+ return (request.headers['x-forwarded-for']?.split(',')[0]?.trim() ||
69
+ request.headers['x-real-ip'] ||
70
+ request.socket.remoteAddress ||
71
+ '');
72
+ }
73
+ };
74
+ exports.TracekitInterceptor = TracekitInterceptor;
75
+ exports.TracekitInterceptor = TracekitInterceptor = __decorate([
76
+ (0, common_1.Injectable)(),
77
+ __param(0, (0, common_1.Inject)('TRACEKIT_CLIENT')),
78
+ __metadata("design:paramtypes", [client_1.TracekitClient])
79
+ ], TracekitInterceptor);
80
+ //# sourceMappingURL=tracekit.interceptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracekit.interceptor.js","sourceRoot":"","sources":["../../src/nestjs/tracekit.interceptor.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAMwB;AACxB,+BAA8C;AAC9C,8CAAiD;AACjD,sCAA2C;AAGpC,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAC9B,YAC8C,MAAsB;QAAtB,WAAM,GAAN,MAAM,CAAgB;IACjE,CAAC;IAEJ,SAAS,CAAC,OAAyB,EAAE,IAAiB;QAEpD,IAAI,OAAO,CAAC,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,CAAC;QAGD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,CAAC;YAC5D,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,WAAW,EAAE,CAAC;QAEtD,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAGnC,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC;QAC1C,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC;QAC3C,MAAM,aAAa,GAAG,GAAG,UAAU,IAAI,OAAO,EAAE,CAAC;QAGjD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,aAAa,EAAE;YACnD,aAAa,EAAE,OAAO,CAAC,MAAM;YAC7B,UAAU,EAAE,OAAO,CAAC,GAAG;YACvB,YAAY,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,IAAI,OAAO,CAAC,GAAG;YAChD,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE;YAClD,gBAAgB,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;YAC3C,mBAAmB,EAAE,UAAU;YAC/B,gBAAgB,EAAE,OAAO;SAC1B,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CACvB,IAAA,eAAG,EAAC,GAAG,EAAE;YAEP,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACnD,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG,OAAS,CAAC;YAEtD,IAAI,CAAC,MAAM,CAAC,OAAO,CACjB,MAAM,EACN;gBACE,kBAAkB,EAAE,QAAQ,CAAC,UAAU;gBACvC,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;aAC3C,EACD,QAAQ,CAAC,UAAU,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAC5C,CAAC;YAGF,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBAChC,OAAO,CAAC,IAAI,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;YACxD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,EACF,IAAA,sBAAU,EAAC,CAAC,KAAK,EAAE,EAAE;YAEnB,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACnD,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG,OAAS,CAAC;YAEtD,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM,CAAC,OAAO,CACjB,MAAM,EACN;gBACE,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;aAC3C,EACD,OAAO,CACR,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAEpC,OAAO,IAAA,iBAAU,EAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;IAEO,WAAW,CAAC,OAAY;QAC9B,OAAO,CACL,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE;YACzD,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC;YAC5B,OAAO,CAAC,MAAM,CAAC,aAAa;YAC5B,EAAE,CACH,CAAC;IACJ,CAAC;CACF,CAAA;AAtFY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;IAGR,WAAA,IAAA,eAAM,EAAC,iBAAiB,CAAC,CAAA;qCAA0B,uBAAc;GAFzD,mBAAmB,CAsF/B"}
@@ -0,0 +1,10 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { TracekitConfig } from '../client';
3
+ export declare class TracekitModule {
4
+ static forRoot(config: TracekitConfig): DynamicModule;
5
+ static forRootAsync(options: {
6
+ useFactory: (...args: any[]) => Promise<TracekitConfig> | TracekitConfig;
7
+ inject?: any[];
8
+ }): DynamicModule;
9
+ }
10
+ //# sourceMappingURL=tracekit.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracekit.module.d.ts","sourceRoot":"","sources":["../../src/nestjs/tracekit.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAE/D,OAAO,EAAkB,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3D,qBAEa,cAAc;IACzB,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,aAAa;IAoBrD,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE;QAC3B,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,cAAc,CAAC,GAAG,cAAc,CAAC;QACzE,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAChB,GAAG,aAAa;CAqBlB"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var TracekitModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.TracekitModule = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const core_1 = require("@nestjs/core");
13
+ const client_1 = require("../client");
14
+ const tracekit_interceptor_1 = require("./tracekit.interceptor");
15
+ let TracekitModule = TracekitModule_1 = class TracekitModule {
16
+ static forRoot(config) {
17
+ const clientProvider = {
18
+ provide: 'TRACEKIT_CLIENT',
19
+ useFactory: () => {
20
+ return new client_1.TracekitClient(config);
21
+ },
22
+ };
23
+ const interceptorProvider = {
24
+ provide: core_1.APP_INTERCEPTOR,
25
+ useClass: tracekit_interceptor_1.TracekitInterceptor,
26
+ };
27
+ return {
28
+ module: TracekitModule_1,
29
+ providers: [clientProvider, interceptorProvider, tracekit_interceptor_1.TracekitInterceptor],
30
+ exports: ['TRACEKIT_CLIENT'],
31
+ };
32
+ }
33
+ static forRootAsync(options) {
34
+ const clientProvider = {
35
+ provide: 'TRACEKIT_CLIENT',
36
+ useFactory: async (...args) => {
37
+ const config = await options.useFactory(...args);
38
+ return new client_1.TracekitClient(config);
39
+ },
40
+ inject: options.inject || [],
41
+ };
42
+ const interceptorProvider = {
43
+ provide: core_1.APP_INTERCEPTOR,
44
+ useClass: tracekit_interceptor_1.TracekitInterceptor,
45
+ };
46
+ return {
47
+ module: TracekitModule_1,
48
+ providers: [clientProvider, interceptorProvider, tracekit_interceptor_1.TracekitInterceptor],
49
+ exports: ['TRACEKIT_CLIENT'],
50
+ };
51
+ }
52
+ };
53
+ exports.TracekitModule = TracekitModule;
54
+ exports.TracekitModule = TracekitModule = TracekitModule_1 = __decorate([
55
+ (0, common_1.Global)(),
56
+ (0, common_1.Module)({})
57
+ ], TracekitModule);
58
+ //# sourceMappingURL=tracekit.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracekit.module.js","sourceRoot":"","sources":["../../src/nestjs/tracekit.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAA+D;AAC/D,uCAA+C;AAC/C,sCAA2D;AAC3D,iEAA6D;AAItD,IAAM,cAAc,sBAApB,MAAM,cAAc;IACzB,MAAM,CAAC,OAAO,CAAC,MAAsB;QACnC,MAAM,cAAc,GAAG;YACrB,OAAO,EAAE,iBAAiB;YAC1B,UAAU,EAAE,GAAG,EAAE;gBACf,OAAO,IAAI,uBAAc,CAAC,MAAM,CAAC,CAAC;YACpC,CAAC;SACF,CAAC;QAEF,MAAM,mBAAmB,GAAG;YAC1B,OAAO,EAAE,sBAAe;YACxB,QAAQ,EAAE,0CAAmB;SAC9B,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,gBAAc;YACtB,SAAS,EAAE,CAAC,cAAc,EAAE,mBAAmB,EAAE,0CAAmB,CAAC;YACrE,OAAO,EAAE,CAAC,iBAAiB,CAAC;SAC7B,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,OAGnB;QACC,MAAM,cAAc,GAAG;YACrB,OAAO,EAAE,iBAAiB;YAC1B,UAAU,EAAE,KAAK,EAAE,GAAG,IAAW,EAAE,EAAE;gBACnC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;gBACjD,OAAO,IAAI,uBAAc,CAAC,MAAM,CAAC,CAAC;YACpC,CAAC;YACD,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;SAC7B,CAAC;QAEF,MAAM,mBAAmB,GAAG;YAC1B,OAAO,EAAE,sBAAe;YACxB,QAAQ,EAAE,0CAAmB;SAC9B,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,gBAAc;YACtB,SAAS,EAAE,CAAC,cAAc,EAAE,mBAAmB,EAAE,0CAAmB,CAAC;YACrE,OAAO,EAAE,CAAC,iBAAiB,CAAC;SAC7B,CAAC;IACJ,CAAC;CACF,CAAA;AA7CY,wCAAc;yBAAd,cAAc;IAF1B,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,cAAc,CA6C1B"}
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@tracekit/node-apm",
3
+ "version": "1.0.0",
4
+ "description": "TraceKit APM for Node.js - Zero-config distributed tracing for Express and NestJS",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "README.md",
10
+ "LICENSE"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "prepublishOnly": "npm run build",
15
+ "test": "jest",
16
+ "lint": "eslint src --ext .ts"
17
+ },
18
+ "keywords": [
19
+ "tracekit",
20
+ "apm",
21
+ "tracing",
22
+ "monitoring",
23
+ "opentelemetry",
24
+ "express",
25
+ "nestjs",
26
+ "performance",
27
+ "observability"
28
+ ],
29
+ "author": "TraceKit <support@tracekit.dev>",
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/Tracekit-Dev/node-apm.git"
34
+ },
35
+ "bugs": {
36
+ "url": "https://github.com/Tracekit-Dev/node-apm/issues"
37
+ },
38
+ "homepage": "https://tracekit.dev",
39
+ "dependencies": {
40
+ "@opentelemetry/api": "^1.7.0",
41
+ "@opentelemetry/sdk-trace-node": "^1.19.0",
42
+ "@opentelemetry/exporter-trace-otlp-http": "^0.46.0",
43
+ "@opentelemetry/resources": "^1.19.0",
44
+ "@opentelemetry/semantic-conventions": "^1.19.0"
45
+ },
46
+ "peerDependencies": {
47
+ "express": "^4.18.0 || ^5.0.0",
48
+ "@nestjs/common": "^10.0.0",
49
+ "@nestjs/core": "^10.0.0"
50
+ },
51
+ "peerDependenciesMeta": {
52
+ "express": {
53
+ "optional": true
54
+ },
55
+ "@nestjs/common": {
56
+ "optional": true
57
+ },
58
+ "@nestjs/core": {
59
+ "optional": true
60
+ }
61
+ },
62
+ "devDependencies": {
63
+ "@types/express": "^4.17.21",
64
+ "@types/node": "^20.10.0",
65
+ "@nestjs/common": "^10.0.0",
66
+ "@nestjs/core": "^10.0.0",
67
+ "typescript": "^5.3.0",
68
+ "express": "^4.18.0"
69
+ },
70
+ "engines": {
71
+ "node": ">=16.0.0"
72
+ }
73
+ }