@tracewayapp/nestjs 0.3.0 → 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/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +32 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +37 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { ModuleMetadata, Type, InjectionToken, OptionalFactoryDependency, OnModuleDestroy, DynamicModule, NestMiddleware, ArgumentsHost } from '@nestjs/common';
|
|
1
|
+
import { ModuleMetadata, Type, InjectionToken, OptionalFactoryDependency, OnModuleDestroy, DynamicModule, NestMiddleware, ExceptionFilter, ArgumentsHost } from '@nestjs/common';
|
|
2
2
|
import * as _tracewayapp_backend from '@tracewayapp/backend';
|
|
3
3
|
import { SpanHandle, TraceContextOptions } from '@tracewayapp/backend';
|
|
4
4
|
import { Request, Response, NextFunction } from 'express';
|
|
5
|
-
import { BaseExceptionFilter } from '@nestjs/core';
|
|
6
5
|
|
|
7
6
|
type ErrorRecordingField = "url" | "query" | "body" | "headers";
|
|
8
7
|
interface TracewayModuleOptions {
|
|
@@ -61,10 +60,11 @@ declare class TracewayMiddleware implements NestMiddleware {
|
|
|
61
60
|
private getClientIP;
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
declare class TracewayExceptionFilter
|
|
63
|
+
declare class TracewayExceptionFilter implements ExceptionFilter {
|
|
65
64
|
private readonly options;
|
|
66
65
|
constructor(options: TracewayModuleOptions);
|
|
67
66
|
catch(exception: unknown, host: ArgumentsHost): void;
|
|
67
|
+
private asHttpException;
|
|
68
68
|
private captureError;
|
|
69
69
|
}
|
|
70
70
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { ModuleMetadata, Type, InjectionToken, OptionalFactoryDependency, OnModuleDestroy, DynamicModule, NestMiddleware, ArgumentsHost } from '@nestjs/common';
|
|
1
|
+
import { ModuleMetadata, Type, InjectionToken, OptionalFactoryDependency, OnModuleDestroy, DynamicModule, NestMiddleware, ExceptionFilter, ArgumentsHost } from '@nestjs/common';
|
|
2
2
|
import * as _tracewayapp_backend from '@tracewayapp/backend';
|
|
3
3
|
import { SpanHandle, TraceContextOptions } from '@tracewayapp/backend';
|
|
4
4
|
import { Request, Response, NextFunction } from 'express';
|
|
5
|
-
import { BaseExceptionFilter } from '@nestjs/core';
|
|
6
5
|
|
|
7
6
|
type ErrorRecordingField = "url" | "query" | "body" | "headers";
|
|
8
7
|
interface TracewayModuleOptions {
|
|
@@ -61,10 +60,11 @@ declare class TracewayMiddleware implements NestMiddleware {
|
|
|
61
60
|
private getClientIP;
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
declare class TracewayExceptionFilter
|
|
63
|
+
declare class TracewayExceptionFilter implements ExceptionFilter {
|
|
65
64
|
private readonly options;
|
|
66
65
|
constructor(options: TracewayModuleOptions);
|
|
67
66
|
catch(exception: unknown, host: ArgumentsHost): void;
|
|
67
|
+
private asHttpException;
|
|
68
68
|
private captureError;
|
|
69
69
|
}
|
|
70
70
|
|
package/dist/index.js
CHANGED
|
@@ -205,13 +205,17 @@ var TracewayMiddleware = class {
|
|
|
205
205
|
}
|
|
206
206
|
use(req, res, next) {
|
|
207
207
|
const routePath = req.route?.path || req.path;
|
|
208
|
-
if (this.options.ignoredRoutes?.includes(routePath)) {
|
|
208
|
+
if (this.options.ignoredRoutes?.includes(routePath) || (0, import_backend2.hasTraceContext)()) {
|
|
209
209
|
return next();
|
|
210
210
|
}
|
|
211
|
-
const endpoint = `${req.method} ${routePath}`;
|
|
212
211
|
const clientIP = this.getClientIP(req);
|
|
213
|
-
(0, import_backend2.withTraceContext)({ endpoint, clientIP }, () => {
|
|
212
|
+
(0, import_backend2.withTraceContext)({ endpoint: "", clientIP }, () => {
|
|
214
213
|
res.on("finish", () => {
|
|
214
|
+
const routePath2 = req.route?.path || req.path;
|
|
215
|
+
const ctx = (0, import_backend2.getTraceContext)();
|
|
216
|
+
if (ctx) {
|
|
217
|
+
ctx.endpoint = `${req.method} ${routePath2}`;
|
|
218
|
+
}
|
|
215
219
|
const bodySize = parseInt(res.get("content-length") || "0", 10);
|
|
216
220
|
(0, import_backend2.setTraceResponseInfo)(res.statusCode, bodySize);
|
|
217
221
|
(0, import_backend2.captureCurrentTrace)();
|
|
@@ -237,30 +241,43 @@ TracewayMiddleware = __decorateClass([
|
|
|
237
241
|
|
|
238
242
|
// src/traceway.filter.ts
|
|
239
243
|
var import_common4 = require("@nestjs/common");
|
|
240
|
-
var import_core = require("@nestjs/core");
|
|
241
244
|
var import_backend3 = require("@tracewayapp/backend");
|
|
242
245
|
var BODY_LIMIT = 64 * 1024;
|
|
243
|
-
var TracewayExceptionFilter = class
|
|
246
|
+
var TracewayExceptionFilter = class {
|
|
244
247
|
constructor(options) {
|
|
245
|
-
super();
|
|
246
248
|
this.options = options;
|
|
247
249
|
}
|
|
248
250
|
catch(exception, host) {
|
|
249
251
|
const ctx = host.switchToHttp();
|
|
250
252
|
const request = ctx.getRequest();
|
|
251
253
|
const response = ctx.getResponse();
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
+
const httpException = this.asHttpException(exception);
|
|
255
|
+
const status = httpException ? httpException.getStatus() : import_common4.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
256
|
+
if (status >= 500 || !httpException) {
|
|
254
257
|
this.captureError(exception, request);
|
|
255
258
|
}
|
|
256
|
-
if (
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
259
|
+
if (!response.headersSent) {
|
|
260
|
+
if (httpException) {
|
|
261
|
+
const body = httpException.getResponse();
|
|
262
|
+
response.status(status).json(
|
|
263
|
+
typeof body === "string" ? { statusCode: status, message: body } : body
|
|
264
|
+
);
|
|
265
|
+
} else {
|
|
266
|
+
response.status(status).json({
|
|
267
|
+
statusCode: status,
|
|
268
|
+
message: "Internal server error"
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
asHttpException(exception) {
|
|
274
|
+
if (exception instanceof import_common4.HttpException) {
|
|
275
|
+
return exception;
|
|
276
|
+
}
|
|
277
|
+
if (exception !== null && typeof exception === "object" && typeof exception.getStatus === "function" && typeof exception.getResponse === "function") {
|
|
278
|
+
return exception;
|
|
263
279
|
}
|
|
280
|
+
return null;
|
|
264
281
|
}
|
|
265
282
|
captureError(exception, request) {
|
|
266
283
|
const error = exception instanceof Error ? exception : new Error(String(exception));
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/traceway.module.ts","../src/traceway.constants.ts","../src/traceway.service.ts","../src/traceway.middleware.ts","../src/traceway.filter.ts","../src/traceway.decorators.ts"],"sourcesContent":["export { TracewayModule } from \"./traceway.module.js\";\nexport { TracewayService } from \"./traceway.service.js\";\nexport { TracewayMiddleware } from \"./traceway.middleware.js\";\nexport { TracewayExceptionFilter } from \"./traceway.filter.js\";\nexport { Span } from \"./traceway.decorators.js\";\nexport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nexport type {\n TracewayModuleOptions,\n TracewayModuleAsyncOptions,\n TracewayOptionsFactory,\n ErrorRecordingField,\n} from \"./traceway.interfaces.js\";\n","import {\n DynamicModule,\n Global,\n Module,\n OnModuleDestroy,\n Provider,\n} from \"@nestjs/common\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type {\n TracewayModuleOptions,\n TracewayModuleAsyncOptions,\n TracewayOptionsFactory,\n} from \"./traceway.interfaces.js\";\nimport { TracewayService } from \"./traceway.service.js\";\n\n@Global()\n@Module({})\nexport class TracewayModule implements OnModuleDestroy {\n constructor(private readonly tracewayService: TracewayService) {}\n\n static forRoot(options: TracewayModuleOptions): DynamicModule {\n const optionsProvider: Provider = {\n provide: TRACEWAY_MODULE_OPTIONS,\n useValue: options,\n };\n\n return {\n module: TracewayModule,\n providers: [\n optionsProvider,\n TracewayService,\n {\n provide: \"TRACEWAY_INIT\",\n useFactory: (service: TracewayService) => {\n service.initialize();\n return true;\n },\n inject: [TracewayService],\n },\n ],\n exports: [TracewayService, TRACEWAY_MODULE_OPTIONS],\n };\n }\n\n static forRootAsync(options: TracewayModuleAsyncOptions): DynamicModule {\n const asyncProviders = this.createAsyncProviders(options);\n\n return {\n module: TracewayModule,\n imports: options.imports || [],\n providers: [\n ...asyncProviders,\n TracewayService,\n {\n provide: \"TRACEWAY_INIT\",\n useFactory: (service: TracewayService) => {\n service.initialize();\n return true;\n },\n inject: [TracewayService],\n },\n ],\n exports: [TracewayService, TRACEWAY_MODULE_OPTIONS],\n };\n }\n\n private static createAsyncProviders(\n options: TracewayModuleAsyncOptions,\n ): Provider[] {\n if (options.useExisting || options.useFactory) {\n return [this.createAsyncOptionsProvider(options)];\n }\n\n if (options.useClass) {\n return [\n this.createAsyncOptionsProvider(options),\n {\n provide: options.useClass,\n useClass: options.useClass,\n },\n ];\n }\n\n return [];\n }\n\n private static createAsyncOptionsProvider(\n options: TracewayModuleAsyncOptions,\n ): Provider {\n if (options.useFactory) {\n return {\n provide: TRACEWAY_MODULE_OPTIONS,\n useFactory: options.useFactory,\n inject: options.inject || [],\n };\n }\n\n const inject = options.useExisting || options.useClass;\n if (!inject) {\n throw new Error(\n \"TracewayModule: useExisting, useClass, or useFactory must be provided\",\n );\n }\n\n return {\n provide: TRACEWAY_MODULE_OPTIONS,\n useFactory: async (optionsFactory: TracewayOptionsFactory) =>\n optionsFactory.createTracewayOptions(),\n inject: [inject],\n };\n }\n\n async onModuleDestroy(): Promise<void> {\n await this.tracewayService.shutdownAsync();\n }\n}\n","export const TRACEWAY_MODULE_OPTIONS = \"TRACEWAY_MODULE_OPTIONS\";\n","import { Inject, Injectable } from \"@nestjs/common\";\nimport {\n init,\n shutdown,\n captureException,\n captureExceptionWithAttributes,\n captureMessage,\n startSpan,\n endSpan,\n measureTask,\n setTraceAttribute,\n setTraceAttributes,\n getTraceId,\n getTraceContext,\n withTraceContext,\n type SpanHandle,\n type TraceContextOptions,\n} from \"@tracewayapp/backend\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type { TracewayModuleOptions } from \"./traceway.interfaces.js\";\n\n@Injectable()\nexport class TracewayService {\n constructor(\n @Inject(TRACEWAY_MODULE_OPTIONS)\n private readonly options: TracewayModuleOptions,\n ) {}\n\n initialize(): void {\n init(this.options.connectionString, {\n debug: this.options.debug,\n version: this.options.version,\n serverName: this.options.serverName,\n sampleRate: this.options.sampleRate,\n errorSampleRate: this.options.errorSampleRate,\n });\n }\n\n async shutdownAsync(): Promise<void> {\n await shutdown();\n }\n\n captureException(error: Error): void {\n captureException(error);\n }\n\n captureExceptionWithAttributes(\n error: Error,\n attributes?: Record<string, string>,\n traceId?: string,\n ): void {\n captureExceptionWithAttributes(error, attributes, traceId);\n }\n\n captureMessage(msg: string, attributes?: Record<string, string>): void {\n captureMessage(msg, attributes);\n }\n\n startSpan(name: string): SpanHandle {\n return startSpan(name);\n }\n\n endSpan(span: SpanHandle, addToContext: boolean = true): void {\n endSpan(span, addToContext);\n }\n\n measureTask(title: string, fn: () => void | Promise<void>): void {\n measureTask(title, fn);\n }\n\n setTraceAttribute(key: string, value: string): void {\n setTraceAttribute(key, value);\n }\n\n setTraceAttributes(attributes: Record<string, string>): void {\n setTraceAttributes(attributes);\n }\n\n getTraceId(): string | undefined {\n return getTraceId();\n }\n\n getTraceContext() {\n return getTraceContext();\n }\n\n withTraceContext<T>(options: TraceContextOptions, fn: () => T): T {\n return withTraceContext(options, fn);\n }\n\n getOptions(): TracewayModuleOptions {\n return this.options;\n }\n}\n","import { Inject, Injectable, NestMiddleware } from \"@nestjs/common\";\nimport type { Request, Response, NextFunction } from \"express\";\nimport {\n withTraceContext,\n setTraceResponseInfo,\n captureCurrentTrace,\n} from \"@tracewayapp/backend\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type { TracewayModuleOptions } from \"./traceway.interfaces.js\";\n\n@Injectable()\nexport class TracewayMiddleware implements NestMiddleware {\n constructor(\n @Inject(TRACEWAY_MODULE_OPTIONS)\n private readonly options: TracewayModuleOptions,\n ) {}\n\n use(req: Request, res: Response, next: NextFunction): void {\n const routePath = req.route?.path || req.path;\n\n if (this.options.ignoredRoutes?.includes(routePath)) {\n return next();\n }\n\n const endpoint = `${req.method} ${routePath}`;\n const clientIP = this.getClientIP(req);\n\n withTraceContext({ endpoint, clientIP }, () => {\n res.on(\"finish\", () => {\n const bodySize = parseInt(res.get(\"content-length\") || \"0\", 10);\n setTraceResponseInfo(res.statusCode, bodySize);\n captureCurrentTrace();\n });\n\n next();\n });\n }\n\n private getClientIP(req: Request): string {\n const forwarded = req.headers[\"x-forwarded-for\"];\n if (typeof forwarded === \"string\") {\n return forwarded.split(\",\")[0].trim();\n }\n if (Array.isArray(forwarded)) {\n return forwarded[0];\n }\n return req.ip || req.socket.remoteAddress || \"\";\n }\n}\n","import {\n Catch,\n ArgumentsHost,\n HttpException,\n HttpStatus,\n Inject,\n} from \"@nestjs/common\";\nimport { BaseExceptionFilter } from \"@nestjs/core\";\nimport type { Request, Response } from \"express\";\nimport {\n captureExceptionWithAttributes,\n getTraceId,\n getTraceContext,\n} from \"@tracewayapp/backend\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type { TracewayModuleOptions } from \"./traceway.interfaces.js\";\n\nconst BODY_LIMIT = 64 * 1024;\n\n@Catch()\nexport class TracewayExceptionFilter extends BaseExceptionFilter {\n constructor(\n @Inject(TRACEWAY_MODULE_OPTIONS)\n private readonly options: TracewayModuleOptions,\n ) {\n super();\n }\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n const request = ctx.getRequest<Request>();\n const response = ctx.getResponse<Response>();\n\n const status =\n exception instanceof HttpException\n ? exception.getStatus()\n : HttpStatus.INTERNAL_SERVER_ERROR;\n\n if (status >= 500 || !(exception instanceof HttpException)) {\n this.captureError(exception, request);\n }\n\n if (exception instanceof Error) {\n super.catch(exception, host);\n } else {\n response.status(status).json({\n statusCode: status,\n message: \"Internal server error\",\n });\n }\n }\n\n private captureError(exception: unknown, request: Request): void {\n const error =\n exception instanceof Error ? exception : new Error(String(exception));\n\n const attributes: Record<string, string> = {};\n const traceCtx = getTraceContext();\n\n if (traceCtx?.attributes) {\n Object.assign(attributes, traceCtx.attributes);\n }\n\n attributes[\"user agent\"] = request.get(\"user-agent\") || \"\";\n\n const recordingFields = this.options.onErrorRecording || [];\n\n if (recordingFields.includes(\"url\")) {\n attributes[\"url\"] = request.path;\n }\n\n if (recordingFields.includes(\"query\")) {\n const query = request.query;\n if (Object.keys(query).length > 0) {\n attributes[\"query\"] = JSON.stringify(query);\n }\n }\n\n if (recordingFields.includes(\"body\")) {\n const contentType = request.get(\"content-type\") || \"\";\n if (contentType.includes(\"application/json\") && request.body) {\n const bodyStr = JSON.stringify(request.body);\n attributes[\"body\"] = bodyStr.slice(0, BODY_LIMIT);\n }\n }\n\n if (recordingFields.includes(\"headers\")) {\n const headers = { ...request.headers };\n delete headers[\"authorization\"];\n delete headers[\"cookie\"];\n attributes[\"headers\"] = JSON.stringify(headers);\n }\n\n const traceId = getTraceId();\n captureExceptionWithAttributes(error, attributes, traceId);\n }\n}\n","import { startSpan, endSpan } from \"@tracewayapp/backend\";\n\nexport function Span(name?: string): MethodDecorator {\n return function (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n ) {\n const originalMethod = descriptor.value;\n const spanName = name || String(propertyKey);\n\n descriptor.value = function (...args: unknown[]) {\n const span = startSpan(spanName);\n\n try {\n const result = originalMethod.apply(this, args);\n\n if (result && typeof result.then === \"function\") {\n return result\n .then((value: unknown) => {\n endSpan(span);\n return value;\n })\n .catch((error: unknown) => {\n endSpan(span);\n throw error;\n });\n }\n\n endSpan(span);\n return result;\n } catch (error) {\n endSpan(span);\n throw error;\n }\n };\n\n return descriptor;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,iBAMO;;;ACNA,IAAM,0BAA0B;;;ACAvC,oBAAmC;AACnC,qBAgBO;AAKA,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YAEmB,SACjB;AADiB;AAAA,EAChB;AAAA,EAEH,aAAmB;AACjB,6BAAK,KAAK,QAAQ,kBAAkB;AAAA,MAClC,OAAO,KAAK,QAAQ;AAAA,MACpB,SAAS,KAAK,QAAQ;AAAA,MACtB,YAAY,KAAK,QAAQ;AAAA,MACzB,YAAY,KAAK,QAAQ;AAAA,MACzB,iBAAiB,KAAK,QAAQ;AAAA,IAChC,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,gBAA+B;AACnC,cAAM,yBAAS;AAAA,EACjB;AAAA,EAEA,iBAAiB,OAAoB;AACnC,yCAAiB,KAAK;AAAA,EACxB;AAAA,EAEA,+BACE,OACA,YACA,SACM;AACN,uDAA+B,OAAO,YAAY,OAAO;AAAA,EAC3D;AAAA,EAEA,eAAe,KAAa,YAA2C;AACrE,uCAAe,KAAK,UAAU;AAAA,EAChC;AAAA,EAEA,UAAU,MAA0B;AAClC,eAAO,0BAAU,IAAI;AAAA,EACvB;AAAA,EAEA,QAAQ,MAAkB,eAAwB,MAAY;AAC5D,gCAAQ,MAAM,YAAY;AAAA,EAC5B;AAAA,EAEA,YAAY,OAAe,IAAsC;AAC/D,oCAAY,OAAO,EAAE;AAAA,EACvB;AAAA,EAEA,kBAAkB,KAAa,OAAqB;AAClD,0CAAkB,KAAK,KAAK;AAAA,EAC9B;AAAA,EAEA,mBAAmB,YAA0C;AAC3D,2CAAmB,UAAU;AAAA,EAC/B;AAAA,EAEA,aAAiC;AAC/B,eAAO,2BAAW;AAAA,EACpB;AAAA,EAEA,kBAAkB;AAChB,eAAO,gCAAgB;AAAA,EACzB;AAAA,EAEA,iBAAoB,SAA8B,IAAgB;AAChE,eAAO,iCAAiB,SAAS,EAAE;AAAA,EACrC;AAAA,EAEA,aAAoC;AAClC,WAAO,KAAK;AAAA,EACd;AACF;AAvEa,kBAAN;AAAA,MADN,0BAAW;AAAA,EAGP,6CAAO,uBAAuB;AAAA,GAFtB;;;AFLN,IAAM,iBAAN,MAAgD;AAAA,EACrD,YAA6B,iBAAkC;AAAlC;AAAA,EAAmC;AAAA,EAEhE,OAAO,QAAQ,SAA+C;AAC5D,UAAM,kBAA4B;AAAA,MAChC,SAAS;AAAA,MACT,UAAU;AAAA,IACZ;AAEA,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,UACE,SAAS;AAAA,UACT,YAAY,CAAC,YAA6B;AACxC,oBAAQ,WAAW;AACnB,mBAAO;AAAA,UACT;AAAA,UACA,QAAQ,CAAC,eAAe;AAAA,QAC1B;AAAA,MACF;AAAA,MACA,SAAS,CAAC,iBAAiB,uBAAuB;AAAA,IACpD;AAAA,EACF;AAAA,EAEA,OAAO,aAAa,SAAoD;AACtE,UAAM,iBAAiB,KAAK,qBAAqB,OAAO;AAExD,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,SAAS,QAAQ,WAAW,CAAC;AAAA,MAC7B,WAAW;AAAA,QACT,GAAG;AAAA,QACH;AAAA,QACA;AAAA,UACE,SAAS;AAAA,UACT,YAAY,CAAC,YAA6B;AACxC,oBAAQ,WAAW;AACnB,mBAAO;AAAA,UACT;AAAA,UACA,QAAQ,CAAC,eAAe;AAAA,QAC1B;AAAA,MACF;AAAA,MACA,SAAS,CAAC,iBAAiB,uBAAuB;AAAA,IACpD;AAAA,EACF;AAAA,EAEA,OAAe,qBACb,SACY;AACZ,QAAI,QAAQ,eAAe,QAAQ,YAAY;AAC7C,aAAO,CAAC,KAAK,2BAA2B,OAAO,CAAC;AAAA,IAClD;AAEA,QAAI,QAAQ,UAAU;AACpB,aAAO;AAAA,QACL,KAAK,2BAA2B,OAAO;AAAA,QACvC;AAAA,UACE,SAAS,QAAQ;AAAA,UACjB,UAAU,QAAQ;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AAEA,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,OAAe,2BACb,SACU;AACV,QAAI,QAAQ,YAAY;AACtB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY,QAAQ;AAAA,QACpB,QAAQ,QAAQ,UAAU,CAAC;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,SAAS,QAAQ,eAAe,QAAQ;AAC9C,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,YAAY,OAAO,mBACjB,eAAe,sBAAsB;AAAA,MACvC,QAAQ,CAAC,MAAM;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,kBAAiC;AACrC,UAAM,KAAK,gBAAgB,cAAc;AAAA,EAC3C;AACF;AAlGa,iBAAN;AAAA,MAFN,uBAAO;AAAA,MACP,uBAAO,CAAC,CAAC;AAAA,GACG;;;AGjBb,IAAAC,iBAAmD;AAEnD,IAAAC,kBAIO;AAKA,IAAM,qBAAN,MAAmD;AAAA,EACxD,YAEmB,SACjB;AADiB;AAAA,EAChB;AAAA,EAEH,IAAI,KAAc,KAAe,MAA0B;AACzD,UAAM,YAAY,IAAI,OAAO,QAAQ,IAAI;AAEzC,QAAI,KAAK,QAAQ,eAAe,SAAS,SAAS,GAAG;AACnD,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,WAAW,GAAG,IAAI,MAAM,IAAI,SAAS;AAC3C,UAAM,WAAW,KAAK,YAAY,GAAG;AAErC,0CAAiB,EAAE,UAAU,SAAS,GAAG,MAAM;AAC7C,UAAI,GAAG,UAAU,MAAM;AACrB,cAAM,WAAW,SAAS,IAAI,IAAI,gBAAgB,KAAK,KAAK,EAAE;AAC9D,kDAAqB,IAAI,YAAY,QAAQ;AAC7C,iDAAoB;AAAA,MACtB,CAAC;AAED,WAAK;AAAA,IACP,CAAC;AAAA,EACH;AAAA,EAEQ,YAAY,KAAsB;AACxC,UAAM,YAAY,IAAI,QAAQ,iBAAiB;AAC/C,QAAI,OAAO,cAAc,UAAU;AACjC,aAAO,UAAU,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK;AAAA,IACtC;AACA,QAAI,MAAM,QAAQ,SAAS,GAAG;AAC5B,aAAO,UAAU,CAAC;AAAA,IACpB;AACA,WAAO,IAAI,MAAM,IAAI,OAAO,iBAAiB;AAAA,EAC/C;AACF;AArCa,qBAAN;AAAA,MADN,2BAAW;AAAA,EAGP,8CAAO,uBAAuB;AAAA,GAFtB;;;ACXb,IAAAC,iBAMO;AACP,kBAAoC;AAEpC,IAAAC,kBAIO;AAIP,IAAM,aAAa,KAAK;AAGjB,IAAM,0BAAN,cAAsC,gCAAoB;AAAA,EAC/D,YAEmB,SACjB;AACA,UAAM;AAFW;AAAA,EAGnB;AAAA,EAEA,MAAM,WAAoB,MAA2B;AACnD,UAAM,MAAM,KAAK,aAAa;AAC9B,UAAM,UAAU,IAAI,WAAoB;AACxC,UAAM,WAAW,IAAI,YAAsB;AAE3C,UAAM,SACJ,qBAAqB,+BACjB,UAAU,UAAU,IACpB,0BAAW;AAEjB,QAAI,UAAU,OAAO,EAAE,qBAAqB,+BAAgB;AAC1D,WAAK,aAAa,WAAW,OAAO;AAAA,IACtC;AAEA,QAAI,qBAAqB,OAAO;AAC9B,YAAM,MAAM,WAAW,IAAI;AAAA,IAC7B,OAAO;AACL,eAAS,OAAO,MAAM,EAAE,KAAK;AAAA,QAC3B,YAAY;AAAA,QACZ,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,aAAa,WAAoB,SAAwB;AAC/D,UAAM,QACJ,qBAAqB,QAAQ,YAAY,IAAI,MAAM,OAAO,SAAS,CAAC;AAEtE,UAAM,aAAqC,CAAC;AAC5C,UAAM,eAAW,iCAAgB;AAEjC,QAAI,UAAU,YAAY;AACxB,aAAO,OAAO,YAAY,SAAS,UAAU;AAAA,IAC/C;AAEA,eAAW,YAAY,IAAI,QAAQ,IAAI,YAAY,KAAK;AAExD,UAAM,kBAAkB,KAAK,QAAQ,oBAAoB,CAAC;AAE1D,QAAI,gBAAgB,SAAS,KAAK,GAAG;AACnC,iBAAW,KAAK,IAAI,QAAQ;AAAA,IAC9B;AAEA,QAAI,gBAAgB,SAAS,OAAO,GAAG;AACrC,YAAM,QAAQ,QAAQ;AACtB,UAAI,OAAO,KAAK,KAAK,EAAE,SAAS,GAAG;AACjC,mBAAW,OAAO,IAAI,KAAK,UAAU,KAAK;AAAA,MAC5C;AAAA,IACF;AAEA,QAAI,gBAAgB,SAAS,MAAM,GAAG;AACpC,YAAM,cAAc,QAAQ,IAAI,cAAc,KAAK;AACnD,UAAI,YAAY,SAAS,kBAAkB,KAAK,QAAQ,MAAM;AAC5D,cAAM,UAAU,KAAK,UAAU,QAAQ,IAAI;AAC3C,mBAAW,MAAM,IAAI,QAAQ,MAAM,GAAG,UAAU;AAAA,MAClD;AAAA,IACF;AAEA,QAAI,gBAAgB,SAAS,SAAS,GAAG;AACvC,YAAM,UAAU,EAAE,GAAG,QAAQ,QAAQ;AACrC,aAAO,QAAQ,eAAe;AAC9B,aAAO,QAAQ,QAAQ;AACvB,iBAAW,SAAS,IAAI,KAAK,UAAU,OAAO;AAAA,IAChD;AAEA,UAAM,cAAU,4BAAW;AAC3B,wDAA+B,OAAO,YAAY,OAAO;AAAA,EAC3D;AACF;AA5Ea,0BAAN;AAAA,MADN,sBAAM;AAAA,EAGF,8CAAO,uBAAuB;AAAA,GAFtB;;;ACpBb,IAAAC,kBAAmC;AAE5B,SAAS,KAAK,MAAgC;AACnD,SAAO,SACL,QACA,aACA,YACA;AACA,UAAM,iBAAiB,WAAW;AAClC,UAAM,WAAW,QAAQ,OAAO,WAAW;AAE3C,eAAW,QAAQ,YAAa,MAAiB;AAC/C,YAAM,WAAO,2BAAU,QAAQ;AAE/B,UAAI;AACF,cAAM,SAAS,eAAe,MAAM,MAAM,IAAI;AAE9C,YAAI,UAAU,OAAO,OAAO,SAAS,YAAY;AAC/C,iBAAO,OACJ,KAAK,CAAC,UAAmB;AACxB,yCAAQ,IAAI;AACZ,mBAAO;AAAA,UACT,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,yCAAQ,IAAI;AACZ,kBAAM;AAAA,UACR,CAAC;AAAA,QACL;AAEA,qCAAQ,IAAI;AACZ,eAAO;AAAA,MACT,SAAS,OAAO;AACd,qCAAQ,IAAI;AACZ,cAAM;AAAA,MACR;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;","names":["import_common","import_common","import_backend","import_common","import_backend","import_backend"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/traceway.module.ts","../src/traceway.constants.ts","../src/traceway.service.ts","../src/traceway.middleware.ts","../src/traceway.filter.ts","../src/traceway.decorators.ts"],"sourcesContent":["export { TracewayModule } from \"./traceway.module.js\";\nexport { TracewayService } from \"./traceway.service.js\";\nexport { TracewayMiddleware } from \"./traceway.middleware.js\";\nexport { TracewayExceptionFilter } from \"./traceway.filter.js\";\nexport { Span } from \"./traceway.decorators.js\";\nexport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nexport type {\n TracewayModuleOptions,\n TracewayModuleAsyncOptions,\n TracewayOptionsFactory,\n ErrorRecordingField,\n} from \"./traceway.interfaces.js\";\n","import {\n DynamicModule,\n Global,\n Module,\n OnModuleDestroy,\n Provider,\n} from \"@nestjs/common\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type {\n TracewayModuleOptions,\n TracewayModuleAsyncOptions,\n TracewayOptionsFactory,\n} from \"./traceway.interfaces.js\";\nimport { TracewayService } from \"./traceway.service.js\";\n\n@Global()\n@Module({})\nexport class TracewayModule implements OnModuleDestroy {\n constructor(private readonly tracewayService: TracewayService) {}\n\n static forRoot(options: TracewayModuleOptions): DynamicModule {\n const optionsProvider: Provider = {\n provide: TRACEWAY_MODULE_OPTIONS,\n useValue: options,\n };\n\n return {\n module: TracewayModule,\n providers: [\n optionsProvider,\n TracewayService,\n {\n provide: \"TRACEWAY_INIT\",\n useFactory: (service: TracewayService) => {\n service.initialize();\n return true;\n },\n inject: [TracewayService],\n },\n ],\n exports: [TracewayService, TRACEWAY_MODULE_OPTIONS],\n };\n }\n\n static forRootAsync(options: TracewayModuleAsyncOptions): DynamicModule {\n const asyncProviders = this.createAsyncProviders(options);\n\n return {\n module: TracewayModule,\n imports: options.imports || [],\n providers: [\n ...asyncProviders,\n TracewayService,\n {\n provide: \"TRACEWAY_INIT\",\n useFactory: (service: TracewayService) => {\n service.initialize();\n return true;\n },\n inject: [TracewayService],\n },\n ],\n exports: [TracewayService, TRACEWAY_MODULE_OPTIONS],\n };\n }\n\n private static createAsyncProviders(\n options: TracewayModuleAsyncOptions,\n ): Provider[] {\n if (options.useExisting || options.useFactory) {\n return [this.createAsyncOptionsProvider(options)];\n }\n\n if (options.useClass) {\n return [\n this.createAsyncOptionsProvider(options),\n {\n provide: options.useClass,\n useClass: options.useClass,\n },\n ];\n }\n\n return [];\n }\n\n private static createAsyncOptionsProvider(\n options: TracewayModuleAsyncOptions,\n ): Provider {\n if (options.useFactory) {\n return {\n provide: TRACEWAY_MODULE_OPTIONS,\n useFactory: options.useFactory,\n inject: options.inject || [],\n };\n }\n\n const inject = options.useExisting || options.useClass;\n if (!inject) {\n throw new Error(\n \"TracewayModule: useExisting, useClass, or useFactory must be provided\",\n );\n }\n\n return {\n provide: TRACEWAY_MODULE_OPTIONS,\n useFactory: async (optionsFactory: TracewayOptionsFactory) =>\n optionsFactory.createTracewayOptions(),\n inject: [inject],\n };\n }\n\n async onModuleDestroy(): Promise<void> {\n await this.tracewayService.shutdownAsync();\n }\n}\n","export const TRACEWAY_MODULE_OPTIONS = \"TRACEWAY_MODULE_OPTIONS\";\n","import { Inject, Injectable } from \"@nestjs/common\";\nimport {\n init,\n shutdown,\n captureException,\n captureExceptionWithAttributes,\n captureMessage,\n startSpan,\n endSpan,\n measureTask,\n setTraceAttribute,\n setTraceAttributes,\n getTraceId,\n getTraceContext,\n withTraceContext,\n type SpanHandle,\n type TraceContextOptions,\n} from \"@tracewayapp/backend\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type { TracewayModuleOptions } from \"./traceway.interfaces.js\";\n\n@Injectable()\nexport class TracewayService {\n constructor(\n @Inject(TRACEWAY_MODULE_OPTIONS)\n private readonly options: TracewayModuleOptions,\n ) {}\n\n initialize(): void {\n init(this.options.connectionString, {\n debug: this.options.debug,\n version: this.options.version,\n serverName: this.options.serverName,\n sampleRate: this.options.sampleRate,\n errorSampleRate: this.options.errorSampleRate,\n });\n }\n\n async shutdownAsync(): Promise<void> {\n await shutdown();\n }\n\n captureException(error: Error): void {\n captureException(error);\n }\n\n captureExceptionWithAttributes(\n error: Error,\n attributes?: Record<string, string>,\n traceId?: string,\n ): void {\n captureExceptionWithAttributes(error, attributes, traceId);\n }\n\n captureMessage(msg: string, attributes?: Record<string, string>): void {\n captureMessage(msg, attributes);\n }\n\n startSpan(name: string): SpanHandle {\n return startSpan(name);\n }\n\n endSpan(span: SpanHandle, addToContext: boolean = true): void {\n endSpan(span, addToContext);\n }\n\n measureTask(title: string, fn: () => void | Promise<void>): void {\n measureTask(title, fn);\n }\n\n setTraceAttribute(key: string, value: string): void {\n setTraceAttribute(key, value);\n }\n\n setTraceAttributes(attributes: Record<string, string>): void {\n setTraceAttributes(attributes);\n }\n\n getTraceId(): string | undefined {\n return getTraceId();\n }\n\n getTraceContext() {\n return getTraceContext();\n }\n\n withTraceContext<T>(options: TraceContextOptions, fn: () => T): T {\n return withTraceContext(options, fn);\n }\n\n getOptions(): TracewayModuleOptions {\n return this.options;\n }\n}\n","import { Inject, Injectable, NestMiddleware } from \"@nestjs/common\";\nimport type { Request, Response, NextFunction } from \"express\";\nimport {\n withTraceContext,\n getTraceContext,\n setTraceResponseInfo,\n captureCurrentTrace,\n hasTraceContext,\n} from \"@tracewayapp/backend\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type { TracewayModuleOptions } from \"./traceway.interfaces.js\";\n\n@Injectable()\nexport class TracewayMiddleware implements NestMiddleware {\n constructor(\n @Inject(TRACEWAY_MODULE_OPTIONS)\n private readonly options: TracewayModuleOptions,\n ) {}\n\n use(req: Request, res: Response, next: NextFunction): void {\n const routePath = req.route?.path || req.path;\n\n if (this.options.ignoredRoutes?.includes(routePath) || hasTraceContext()) {\n return next();\n }\n\n const clientIP = this.getClientIP(req);\n\n withTraceContext({ endpoint: \"\", clientIP }, () => {\n res.on(\"finish\", () => {\n const routePath = req.route?.path || req.path;\n const ctx = getTraceContext();\n if (ctx) {\n ctx.endpoint = `${req.method} ${routePath}`;\n }\n const bodySize = parseInt(res.get(\"content-length\") || \"0\", 10);\n setTraceResponseInfo(res.statusCode, bodySize);\n captureCurrentTrace();\n });\n\n next();\n });\n }\n\n private getClientIP(req: Request): string {\n const forwarded = req.headers[\"x-forwarded-for\"];\n if (typeof forwarded === \"string\") {\n return forwarded.split(\",\")[0].trim();\n }\n if (Array.isArray(forwarded)) {\n return forwarded[0];\n }\n return req.ip || req.socket.remoteAddress || \"\";\n }\n}\n","import {\n Catch,\n ArgumentsHost,\n HttpException,\n HttpStatus,\n Inject,\n ExceptionFilter,\n} from \"@nestjs/common\";\nimport type { Request, Response } from \"express\";\nimport {\n captureExceptionWithAttributes,\n getTraceId,\n getTraceContext,\n} from \"@tracewayapp/backend\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type { TracewayModuleOptions } from \"./traceway.interfaces.js\";\n\nconst BODY_LIMIT = 64 * 1024;\n\n@Catch()\nexport class TracewayExceptionFilter implements ExceptionFilter {\n constructor(\n @Inject(TRACEWAY_MODULE_OPTIONS)\n private readonly options: TracewayModuleOptions,\n ) {}\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n const request = ctx.getRequest<Request>();\n const response = ctx.getResponse<Response>();\n\n const httpException = this.asHttpException(exception);\n const status = httpException\n ? httpException.getStatus()\n : HttpStatus.INTERNAL_SERVER_ERROR;\n\n if (status >= 500 || !httpException) {\n this.captureError(exception, request);\n }\n\n if (!response.headersSent) {\n if (httpException) {\n const body = httpException.getResponse();\n response.status(status).json(\n typeof body === \"string\" ? { statusCode: status, message: body } : body,\n );\n } else {\n response.status(status).json({\n statusCode: status,\n message: \"Internal server error\",\n });\n }\n }\n }\n\n private asHttpException(exception: unknown): HttpException | null {\n if (exception instanceof HttpException) {\n return exception;\n }\n if (\n exception !== null &&\n typeof exception === \"object\" &&\n typeof (exception as HttpException).getStatus === \"function\" &&\n typeof (exception as HttpException).getResponse === \"function\"\n ) {\n return exception as HttpException;\n }\n return null;\n }\n\n private captureError(exception: unknown, request: Request): void {\n const error =\n exception instanceof Error ? exception : new Error(String(exception));\n\n const attributes: Record<string, string> = {};\n const traceCtx = getTraceContext();\n\n if (traceCtx?.attributes) {\n Object.assign(attributes, traceCtx.attributes);\n }\n\n attributes[\"user agent\"] = request.get(\"user-agent\") || \"\";\n\n const recordingFields = this.options.onErrorRecording || [];\n\n if (recordingFields.includes(\"url\")) {\n attributes[\"url\"] = request.path;\n }\n\n if (recordingFields.includes(\"query\")) {\n const query = request.query;\n if (Object.keys(query).length > 0) {\n attributes[\"query\"] = JSON.stringify(query);\n }\n }\n\n if (recordingFields.includes(\"body\")) {\n const contentType = request.get(\"content-type\") || \"\";\n if (contentType.includes(\"application/json\") && request.body) {\n const bodyStr = JSON.stringify(request.body);\n attributes[\"body\"] = bodyStr.slice(0, BODY_LIMIT);\n }\n }\n\n if (recordingFields.includes(\"headers\")) {\n const headers = { ...request.headers };\n delete headers[\"authorization\"];\n delete headers[\"cookie\"];\n attributes[\"headers\"] = JSON.stringify(headers);\n }\n\n const traceId = getTraceId();\n captureExceptionWithAttributes(error, attributes, traceId);\n }\n}\n","import { startSpan, endSpan } from \"@tracewayapp/backend\";\n\nexport function Span(name?: string): MethodDecorator {\n return function (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n ) {\n const originalMethod = descriptor.value;\n const spanName = name || String(propertyKey);\n\n descriptor.value = function (...args: unknown[]) {\n const span = startSpan(spanName);\n\n try {\n const result = originalMethod.apply(this, args);\n\n if (result && typeof result.then === \"function\") {\n return result\n .then((value: unknown) => {\n endSpan(span);\n return value;\n })\n .catch((error: unknown) => {\n endSpan(span);\n throw error;\n });\n }\n\n endSpan(span);\n return result;\n } catch (error) {\n endSpan(span);\n throw error;\n }\n };\n\n return descriptor;\n };\n}\n"],"mappings":"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","names":["import_common","import_common","import_backend","routePath","import_common","import_backend","import_backend"]}
|
package/dist/index.mjs
CHANGED
|
@@ -189,8 +189,10 @@ TracewayModule = __decorateClass([
|
|
|
189
189
|
import { Inject as Inject2, Injectable as Injectable2 } from "@nestjs/common";
|
|
190
190
|
import {
|
|
191
191
|
withTraceContext as withTraceContext2,
|
|
192
|
+
getTraceContext as getTraceContext2,
|
|
192
193
|
setTraceResponseInfo,
|
|
193
|
-
captureCurrentTrace
|
|
194
|
+
captureCurrentTrace,
|
|
195
|
+
hasTraceContext
|
|
194
196
|
} from "@tracewayapp/backend";
|
|
195
197
|
var TracewayMiddleware = class {
|
|
196
198
|
constructor(options) {
|
|
@@ -198,13 +200,17 @@ var TracewayMiddleware = class {
|
|
|
198
200
|
}
|
|
199
201
|
use(req, res, next) {
|
|
200
202
|
const routePath = req.route?.path || req.path;
|
|
201
|
-
if (this.options.ignoredRoutes?.includes(routePath)) {
|
|
203
|
+
if (this.options.ignoredRoutes?.includes(routePath) || hasTraceContext()) {
|
|
202
204
|
return next();
|
|
203
205
|
}
|
|
204
|
-
const endpoint = `${req.method} ${routePath}`;
|
|
205
206
|
const clientIP = this.getClientIP(req);
|
|
206
|
-
withTraceContext2({ endpoint, clientIP }, () => {
|
|
207
|
+
withTraceContext2({ endpoint: "", clientIP }, () => {
|
|
207
208
|
res.on("finish", () => {
|
|
209
|
+
const routePath2 = req.route?.path || req.path;
|
|
210
|
+
const ctx = getTraceContext2();
|
|
211
|
+
if (ctx) {
|
|
212
|
+
ctx.endpoint = `${req.method} ${routePath2}`;
|
|
213
|
+
}
|
|
208
214
|
const bodySize = parseInt(res.get("content-length") || "0", 10);
|
|
209
215
|
setTraceResponseInfo(res.statusCode, bodySize);
|
|
210
216
|
captureCurrentTrace();
|
|
@@ -235,39 +241,52 @@ import {
|
|
|
235
241
|
HttpStatus,
|
|
236
242
|
Inject as Inject3
|
|
237
243
|
} from "@nestjs/common";
|
|
238
|
-
import { BaseExceptionFilter } from "@nestjs/core";
|
|
239
244
|
import {
|
|
240
245
|
captureExceptionWithAttributes as captureExceptionWithAttributes2,
|
|
241
246
|
getTraceId as getTraceId2,
|
|
242
|
-
getTraceContext as
|
|
247
|
+
getTraceContext as getTraceContext3
|
|
243
248
|
} from "@tracewayapp/backend";
|
|
244
249
|
var BODY_LIMIT = 64 * 1024;
|
|
245
|
-
var TracewayExceptionFilter = class
|
|
250
|
+
var TracewayExceptionFilter = class {
|
|
246
251
|
constructor(options) {
|
|
247
|
-
super();
|
|
248
252
|
this.options = options;
|
|
249
253
|
}
|
|
250
254
|
catch(exception, host) {
|
|
251
255
|
const ctx = host.switchToHttp();
|
|
252
256
|
const request = ctx.getRequest();
|
|
253
257
|
const response = ctx.getResponse();
|
|
254
|
-
const
|
|
255
|
-
|
|
258
|
+
const httpException = this.asHttpException(exception);
|
|
259
|
+
const status = httpException ? httpException.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;
|
|
260
|
+
if (status >= 500 || !httpException) {
|
|
256
261
|
this.captureError(exception, request);
|
|
257
262
|
}
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
263
|
+
if (!response.headersSent) {
|
|
264
|
+
if (httpException) {
|
|
265
|
+
const body = httpException.getResponse();
|
|
266
|
+
response.status(status).json(
|
|
267
|
+
typeof body === "string" ? { statusCode: status, message: body } : body
|
|
268
|
+
);
|
|
269
|
+
} else {
|
|
270
|
+
response.status(status).json({
|
|
271
|
+
statusCode: status,
|
|
272
|
+
message: "Internal server error"
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
asHttpException(exception) {
|
|
278
|
+
if (exception instanceof HttpException) {
|
|
279
|
+
return exception;
|
|
280
|
+
}
|
|
281
|
+
if (exception !== null && typeof exception === "object" && typeof exception.getStatus === "function" && typeof exception.getResponse === "function") {
|
|
282
|
+
return exception;
|
|
265
283
|
}
|
|
284
|
+
return null;
|
|
266
285
|
}
|
|
267
286
|
captureError(exception, request) {
|
|
268
287
|
const error = exception instanceof Error ? exception : new Error(String(exception));
|
|
269
288
|
const attributes = {};
|
|
270
|
-
const traceCtx =
|
|
289
|
+
const traceCtx = getTraceContext3();
|
|
271
290
|
if (traceCtx?.attributes) {
|
|
272
291
|
Object.assign(attributes, traceCtx.attributes);
|
|
273
292
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/traceway.module.ts","../src/traceway.constants.ts","../src/traceway.service.ts","../src/traceway.middleware.ts","../src/traceway.filter.ts","../src/traceway.decorators.ts"],"sourcesContent":["import {\n DynamicModule,\n Global,\n Module,\n OnModuleDestroy,\n Provider,\n} from \"@nestjs/common\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type {\n TracewayModuleOptions,\n TracewayModuleAsyncOptions,\n TracewayOptionsFactory,\n} from \"./traceway.interfaces.js\";\nimport { TracewayService } from \"./traceway.service.js\";\n\n@Global()\n@Module({})\nexport class TracewayModule implements OnModuleDestroy {\n constructor(private readonly tracewayService: TracewayService) {}\n\n static forRoot(options: TracewayModuleOptions): DynamicModule {\n const optionsProvider: Provider = {\n provide: TRACEWAY_MODULE_OPTIONS,\n useValue: options,\n };\n\n return {\n module: TracewayModule,\n providers: [\n optionsProvider,\n TracewayService,\n {\n provide: \"TRACEWAY_INIT\",\n useFactory: (service: TracewayService) => {\n service.initialize();\n return true;\n },\n inject: [TracewayService],\n },\n ],\n exports: [TracewayService, TRACEWAY_MODULE_OPTIONS],\n };\n }\n\n static forRootAsync(options: TracewayModuleAsyncOptions): DynamicModule {\n const asyncProviders = this.createAsyncProviders(options);\n\n return {\n module: TracewayModule,\n imports: options.imports || [],\n providers: [\n ...asyncProviders,\n TracewayService,\n {\n provide: \"TRACEWAY_INIT\",\n useFactory: (service: TracewayService) => {\n service.initialize();\n return true;\n },\n inject: [TracewayService],\n },\n ],\n exports: [TracewayService, TRACEWAY_MODULE_OPTIONS],\n };\n }\n\n private static createAsyncProviders(\n options: TracewayModuleAsyncOptions,\n ): Provider[] {\n if (options.useExisting || options.useFactory) {\n return [this.createAsyncOptionsProvider(options)];\n }\n\n if (options.useClass) {\n return [\n this.createAsyncOptionsProvider(options),\n {\n provide: options.useClass,\n useClass: options.useClass,\n },\n ];\n }\n\n return [];\n }\n\n private static createAsyncOptionsProvider(\n options: TracewayModuleAsyncOptions,\n ): Provider {\n if (options.useFactory) {\n return {\n provide: TRACEWAY_MODULE_OPTIONS,\n useFactory: options.useFactory,\n inject: options.inject || [],\n };\n }\n\n const inject = options.useExisting || options.useClass;\n if (!inject) {\n throw new Error(\n \"TracewayModule: useExisting, useClass, or useFactory must be provided\",\n );\n }\n\n return {\n provide: TRACEWAY_MODULE_OPTIONS,\n useFactory: async (optionsFactory: TracewayOptionsFactory) =>\n optionsFactory.createTracewayOptions(),\n inject: [inject],\n };\n }\n\n async onModuleDestroy(): Promise<void> {\n await this.tracewayService.shutdownAsync();\n }\n}\n","export const TRACEWAY_MODULE_OPTIONS = \"TRACEWAY_MODULE_OPTIONS\";\n","import { Inject, Injectable } from \"@nestjs/common\";\nimport {\n init,\n shutdown,\n captureException,\n captureExceptionWithAttributes,\n captureMessage,\n startSpan,\n endSpan,\n measureTask,\n setTraceAttribute,\n setTraceAttributes,\n getTraceId,\n getTraceContext,\n withTraceContext,\n type SpanHandle,\n type TraceContextOptions,\n} from \"@tracewayapp/backend\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type { TracewayModuleOptions } from \"./traceway.interfaces.js\";\n\n@Injectable()\nexport class TracewayService {\n constructor(\n @Inject(TRACEWAY_MODULE_OPTIONS)\n private readonly options: TracewayModuleOptions,\n ) {}\n\n initialize(): void {\n init(this.options.connectionString, {\n debug: this.options.debug,\n version: this.options.version,\n serverName: this.options.serverName,\n sampleRate: this.options.sampleRate,\n errorSampleRate: this.options.errorSampleRate,\n });\n }\n\n async shutdownAsync(): Promise<void> {\n await shutdown();\n }\n\n captureException(error: Error): void {\n captureException(error);\n }\n\n captureExceptionWithAttributes(\n error: Error,\n attributes?: Record<string, string>,\n traceId?: string,\n ): void {\n captureExceptionWithAttributes(error, attributes, traceId);\n }\n\n captureMessage(msg: string, attributes?: Record<string, string>): void {\n captureMessage(msg, attributes);\n }\n\n startSpan(name: string): SpanHandle {\n return startSpan(name);\n }\n\n endSpan(span: SpanHandle, addToContext: boolean = true): void {\n endSpan(span, addToContext);\n }\n\n measureTask(title: string, fn: () => void | Promise<void>): void {\n measureTask(title, fn);\n }\n\n setTraceAttribute(key: string, value: string): void {\n setTraceAttribute(key, value);\n }\n\n setTraceAttributes(attributes: Record<string, string>): void {\n setTraceAttributes(attributes);\n }\n\n getTraceId(): string | undefined {\n return getTraceId();\n }\n\n getTraceContext() {\n return getTraceContext();\n }\n\n withTraceContext<T>(options: TraceContextOptions, fn: () => T): T {\n return withTraceContext(options, fn);\n }\n\n getOptions(): TracewayModuleOptions {\n return this.options;\n }\n}\n","import { Inject, Injectable, NestMiddleware } from \"@nestjs/common\";\nimport type { Request, Response, NextFunction } from \"express\";\nimport {\n withTraceContext,\n setTraceResponseInfo,\n captureCurrentTrace,\n} from \"@tracewayapp/backend\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type { TracewayModuleOptions } from \"./traceway.interfaces.js\";\n\n@Injectable()\nexport class TracewayMiddleware implements NestMiddleware {\n constructor(\n @Inject(TRACEWAY_MODULE_OPTIONS)\n private readonly options: TracewayModuleOptions,\n ) {}\n\n use(req: Request, res: Response, next: NextFunction): void {\n const routePath = req.route?.path || req.path;\n\n if (this.options.ignoredRoutes?.includes(routePath)) {\n return next();\n }\n\n const endpoint = `${req.method} ${routePath}`;\n const clientIP = this.getClientIP(req);\n\n withTraceContext({ endpoint, clientIP }, () => {\n res.on(\"finish\", () => {\n const bodySize = parseInt(res.get(\"content-length\") || \"0\", 10);\n setTraceResponseInfo(res.statusCode, bodySize);\n captureCurrentTrace();\n });\n\n next();\n });\n }\n\n private getClientIP(req: Request): string {\n const forwarded = req.headers[\"x-forwarded-for\"];\n if (typeof forwarded === \"string\") {\n return forwarded.split(\",\")[0].trim();\n }\n if (Array.isArray(forwarded)) {\n return forwarded[0];\n }\n return req.ip || req.socket.remoteAddress || \"\";\n }\n}\n","import {\n Catch,\n ArgumentsHost,\n HttpException,\n HttpStatus,\n Inject,\n} from \"@nestjs/common\";\nimport { BaseExceptionFilter } from \"@nestjs/core\";\nimport type { Request, Response } from \"express\";\nimport {\n captureExceptionWithAttributes,\n getTraceId,\n getTraceContext,\n} from \"@tracewayapp/backend\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type { TracewayModuleOptions } from \"./traceway.interfaces.js\";\n\nconst BODY_LIMIT = 64 * 1024;\n\n@Catch()\nexport class TracewayExceptionFilter extends BaseExceptionFilter {\n constructor(\n @Inject(TRACEWAY_MODULE_OPTIONS)\n private readonly options: TracewayModuleOptions,\n ) {\n super();\n }\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n const request = ctx.getRequest<Request>();\n const response = ctx.getResponse<Response>();\n\n const status =\n exception instanceof HttpException\n ? exception.getStatus()\n : HttpStatus.INTERNAL_SERVER_ERROR;\n\n if (status >= 500 || !(exception instanceof HttpException)) {\n this.captureError(exception, request);\n }\n\n if (exception instanceof Error) {\n super.catch(exception, host);\n } else {\n response.status(status).json({\n statusCode: status,\n message: \"Internal server error\",\n });\n }\n }\n\n private captureError(exception: unknown, request: Request): void {\n const error =\n exception instanceof Error ? exception : new Error(String(exception));\n\n const attributes: Record<string, string> = {};\n const traceCtx = getTraceContext();\n\n if (traceCtx?.attributes) {\n Object.assign(attributes, traceCtx.attributes);\n }\n\n attributes[\"user agent\"] = request.get(\"user-agent\") || \"\";\n\n const recordingFields = this.options.onErrorRecording || [];\n\n if (recordingFields.includes(\"url\")) {\n attributes[\"url\"] = request.path;\n }\n\n if (recordingFields.includes(\"query\")) {\n const query = request.query;\n if (Object.keys(query).length > 0) {\n attributes[\"query\"] = JSON.stringify(query);\n }\n }\n\n if (recordingFields.includes(\"body\")) {\n const contentType = request.get(\"content-type\") || \"\";\n if (contentType.includes(\"application/json\") && request.body) {\n const bodyStr = JSON.stringify(request.body);\n attributes[\"body\"] = bodyStr.slice(0, BODY_LIMIT);\n }\n }\n\n if (recordingFields.includes(\"headers\")) {\n const headers = { ...request.headers };\n delete headers[\"authorization\"];\n delete headers[\"cookie\"];\n attributes[\"headers\"] = JSON.stringify(headers);\n }\n\n const traceId = getTraceId();\n captureExceptionWithAttributes(error, attributes, traceId);\n }\n}\n","import { startSpan, endSpan } from \"@tracewayapp/backend\";\n\nexport function Span(name?: string): MethodDecorator {\n return function (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n ) {\n const originalMethod = descriptor.value;\n const spanName = name || String(propertyKey);\n\n descriptor.value = function (...args: unknown[]) {\n const span = startSpan(spanName);\n\n try {\n const result = originalMethod.apply(this, args);\n\n if (result && typeof result.then === \"function\") {\n return result\n .then((value: unknown) => {\n endSpan(span);\n return value;\n })\n .catch((error: unknown) => {\n endSpan(span);\n throw error;\n });\n }\n\n endSpan(span);\n return result;\n } catch (error) {\n endSpan(span);\n throw error;\n }\n };\n\n return descriptor;\n };\n}\n"],"mappings":"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","names":["Inject","Injectable","withTraceContext","withTraceContext","Injectable","Inject","Inject","captureExceptionWithAttributes","getTraceId","getTraceContext","getTraceContext","getTraceId","captureExceptionWithAttributes","Inject","startSpan","endSpan"]}
|
|
1
|
+
{"version":3,"sources":["../src/traceway.module.ts","../src/traceway.constants.ts","../src/traceway.service.ts","../src/traceway.middleware.ts","../src/traceway.filter.ts","../src/traceway.decorators.ts"],"sourcesContent":["import {\n DynamicModule,\n Global,\n Module,\n OnModuleDestroy,\n Provider,\n} from \"@nestjs/common\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type {\n TracewayModuleOptions,\n TracewayModuleAsyncOptions,\n TracewayOptionsFactory,\n} from \"./traceway.interfaces.js\";\nimport { TracewayService } from \"./traceway.service.js\";\n\n@Global()\n@Module({})\nexport class TracewayModule implements OnModuleDestroy {\n constructor(private readonly tracewayService: TracewayService) {}\n\n static forRoot(options: TracewayModuleOptions): DynamicModule {\n const optionsProvider: Provider = {\n provide: TRACEWAY_MODULE_OPTIONS,\n useValue: options,\n };\n\n return {\n module: TracewayModule,\n providers: [\n optionsProvider,\n TracewayService,\n {\n provide: \"TRACEWAY_INIT\",\n useFactory: (service: TracewayService) => {\n service.initialize();\n return true;\n },\n inject: [TracewayService],\n },\n ],\n exports: [TracewayService, TRACEWAY_MODULE_OPTIONS],\n };\n }\n\n static forRootAsync(options: TracewayModuleAsyncOptions): DynamicModule {\n const asyncProviders = this.createAsyncProviders(options);\n\n return {\n module: TracewayModule,\n imports: options.imports || [],\n providers: [\n ...asyncProviders,\n TracewayService,\n {\n provide: \"TRACEWAY_INIT\",\n useFactory: (service: TracewayService) => {\n service.initialize();\n return true;\n },\n inject: [TracewayService],\n },\n ],\n exports: [TracewayService, TRACEWAY_MODULE_OPTIONS],\n };\n }\n\n private static createAsyncProviders(\n options: TracewayModuleAsyncOptions,\n ): Provider[] {\n if (options.useExisting || options.useFactory) {\n return [this.createAsyncOptionsProvider(options)];\n }\n\n if (options.useClass) {\n return [\n this.createAsyncOptionsProvider(options),\n {\n provide: options.useClass,\n useClass: options.useClass,\n },\n ];\n }\n\n return [];\n }\n\n private static createAsyncOptionsProvider(\n options: TracewayModuleAsyncOptions,\n ): Provider {\n if (options.useFactory) {\n return {\n provide: TRACEWAY_MODULE_OPTIONS,\n useFactory: options.useFactory,\n inject: options.inject || [],\n };\n }\n\n const inject = options.useExisting || options.useClass;\n if (!inject) {\n throw new Error(\n \"TracewayModule: useExisting, useClass, or useFactory must be provided\",\n );\n }\n\n return {\n provide: TRACEWAY_MODULE_OPTIONS,\n useFactory: async (optionsFactory: TracewayOptionsFactory) =>\n optionsFactory.createTracewayOptions(),\n inject: [inject],\n };\n }\n\n async onModuleDestroy(): Promise<void> {\n await this.tracewayService.shutdownAsync();\n }\n}\n","export const TRACEWAY_MODULE_OPTIONS = \"TRACEWAY_MODULE_OPTIONS\";\n","import { Inject, Injectable } from \"@nestjs/common\";\nimport {\n init,\n shutdown,\n captureException,\n captureExceptionWithAttributes,\n captureMessage,\n startSpan,\n endSpan,\n measureTask,\n setTraceAttribute,\n setTraceAttributes,\n getTraceId,\n getTraceContext,\n withTraceContext,\n type SpanHandle,\n type TraceContextOptions,\n} from \"@tracewayapp/backend\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type { TracewayModuleOptions } from \"./traceway.interfaces.js\";\n\n@Injectable()\nexport class TracewayService {\n constructor(\n @Inject(TRACEWAY_MODULE_OPTIONS)\n private readonly options: TracewayModuleOptions,\n ) {}\n\n initialize(): void {\n init(this.options.connectionString, {\n debug: this.options.debug,\n version: this.options.version,\n serverName: this.options.serverName,\n sampleRate: this.options.sampleRate,\n errorSampleRate: this.options.errorSampleRate,\n });\n }\n\n async shutdownAsync(): Promise<void> {\n await shutdown();\n }\n\n captureException(error: Error): void {\n captureException(error);\n }\n\n captureExceptionWithAttributes(\n error: Error,\n attributes?: Record<string, string>,\n traceId?: string,\n ): void {\n captureExceptionWithAttributes(error, attributes, traceId);\n }\n\n captureMessage(msg: string, attributes?: Record<string, string>): void {\n captureMessage(msg, attributes);\n }\n\n startSpan(name: string): SpanHandle {\n return startSpan(name);\n }\n\n endSpan(span: SpanHandle, addToContext: boolean = true): void {\n endSpan(span, addToContext);\n }\n\n measureTask(title: string, fn: () => void | Promise<void>): void {\n measureTask(title, fn);\n }\n\n setTraceAttribute(key: string, value: string): void {\n setTraceAttribute(key, value);\n }\n\n setTraceAttributes(attributes: Record<string, string>): void {\n setTraceAttributes(attributes);\n }\n\n getTraceId(): string | undefined {\n return getTraceId();\n }\n\n getTraceContext() {\n return getTraceContext();\n }\n\n withTraceContext<T>(options: TraceContextOptions, fn: () => T): T {\n return withTraceContext(options, fn);\n }\n\n getOptions(): TracewayModuleOptions {\n return this.options;\n }\n}\n","import { Inject, Injectable, NestMiddleware } from \"@nestjs/common\";\nimport type { Request, Response, NextFunction } from \"express\";\nimport {\n withTraceContext,\n getTraceContext,\n setTraceResponseInfo,\n captureCurrentTrace,\n hasTraceContext,\n} from \"@tracewayapp/backend\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type { TracewayModuleOptions } from \"./traceway.interfaces.js\";\n\n@Injectable()\nexport class TracewayMiddleware implements NestMiddleware {\n constructor(\n @Inject(TRACEWAY_MODULE_OPTIONS)\n private readonly options: TracewayModuleOptions,\n ) {}\n\n use(req: Request, res: Response, next: NextFunction): void {\n const routePath = req.route?.path || req.path;\n\n if (this.options.ignoredRoutes?.includes(routePath) || hasTraceContext()) {\n return next();\n }\n\n const clientIP = this.getClientIP(req);\n\n withTraceContext({ endpoint: \"\", clientIP }, () => {\n res.on(\"finish\", () => {\n const routePath = req.route?.path || req.path;\n const ctx = getTraceContext();\n if (ctx) {\n ctx.endpoint = `${req.method} ${routePath}`;\n }\n const bodySize = parseInt(res.get(\"content-length\") || \"0\", 10);\n setTraceResponseInfo(res.statusCode, bodySize);\n captureCurrentTrace();\n });\n\n next();\n });\n }\n\n private getClientIP(req: Request): string {\n const forwarded = req.headers[\"x-forwarded-for\"];\n if (typeof forwarded === \"string\") {\n return forwarded.split(\",\")[0].trim();\n }\n if (Array.isArray(forwarded)) {\n return forwarded[0];\n }\n return req.ip || req.socket.remoteAddress || \"\";\n }\n}\n","import {\n Catch,\n ArgumentsHost,\n HttpException,\n HttpStatus,\n Inject,\n ExceptionFilter,\n} from \"@nestjs/common\";\nimport type { Request, Response } from \"express\";\nimport {\n captureExceptionWithAttributes,\n getTraceId,\n getTraceContext,\n} from \"@tracewayapp/backend\";\nimport { TRACEWAY_MODULE_OPTIONS } from \"./traceway.constants.js\";\nimport type { TracewayModuleOptions } from \"./traceway.interfaces.js\";\n\nconst BODY_LIMIT = 64 * 1024;\n\n@Catch()\nexport class TracewayExceptionFilter implements ExceptionFilter {\n constructor(\n @Inject(TRACEWAY_MODULE_OPTIONS)\n private readonly options: TracewayModuleOptions,\n ) {}\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n const request = ctx.getRequest<Request>();\n const response = ctx.getResponse<Response>();\n\n const httpException = this.asHttpException(exception);\n const status = httpException\n ? httpException.getStatus()\n : HttpStatus.INTERNAL_SERVER_ERROR;\n\n if (status >= 500 || !httpException) {\n this.captureError(exception, request);\n }\n\n if (!response.headersSent) {\n if (httpException) {\n const body = httpException.getResponse();\n response.status(status).json(\n typeof body === \"string\" ? { statusCode: status, message: body } : body,\n );\n } else {\n response.status(status).json({\n statusCode: status,\n message: \"Internal server error\",\n });\n }\n }\n }\n\n private asHttpException(exception: unknown): HttpException | null {\n if (exception instanceof HttpException) {\n return exception;\n }\n if (\n exception !== null &&\n typeof exception === \"object\" &&\n typeof (exception as HttpException).getStatus === \"function\" &&\n typeof (exception as HttpException).getResponse === \"function\"\n ) {\n return exception as HttpException;\n }\n return null;\n }\n\n private captureError(exception: unknown, request: Request): void {\n const error =\n exception instanceof Error ? exception : new Error(String(exception));\n\n const attributes: Record<string, string> = {};\n const traceCtx = getTraceContext();\n\n if (traceCtx?.attributes) {\n Object.assign(attributes, traceCtx.attributes);\n }\n\n attributes[\"user agent\"] = request.get(\"user-agent\") || \"\";\n\n const recordingFields = this.options.onErrorRecording || [];\n\n if (recordingFields.includes(\"url\")) {\n attributes[\"url\"] = request.path;\n }\n\n if (recordingFields.includes(\"query\")) {\n const query = request.query;\n if (Object.keys(query).length > 0) {\n attributes[\"query\"] = JSON.stringify(query);\n }\n }\n\n if (recordingFields.includes(\"body\")) {\n const contentType = request.get(\"content-type\") || \"\";\n if (contentType.includes(\"application/json\") && request.body) {\n const bodyStr = JSON.stringify(request.body);\n attributes[\"body\"] = bodyStr.slice(0, BODY_LIMIT);\n }\n }\n\n if (recordingFields.includes(\"headers\")) {\n const headers = { ...request.headers };\n delete headers[\"authorization\"];\n delete headers[\"cookie\"];\n attributes[\"headers\"] = JSON.stringify(headers);\n }\n\n const traceId = getTraceId();\n captureExceptionWithAttributes(error, attributes, traceId);\n }\n}\n","import { startSpan, endSpan } from \"@tracewayapp/backend\";\n\nexport function Span(name?: string): MethodDecorator {\n return function (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n ) {\n const originalMethod = descriptor.value;\n const spanName = name || String(propertyKey);\n\n descriptor.value = function (...args: unknown[]) {\n const span = startSpan(spanName);\n\n try {\n const result = originalMethod.apply(this, args);\n\n if (result && typeof result.then === \"function\") {\n return result\n .then((value: unknown) => {\n endSpan(span);\n return value;\n })\n .catch((error: unknown) => {\n endSpan(span);\n throw error;\n });\n }\n\n endSpan(span);\n return result;\n } catch (error) {\n endSpan(span);\n throw error;\n }\n };\n\n return descriptor;\n };\n}\n"],"mappings":"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","names":["Inject","Injectable","withTraceContext","getTraceContext","withTraceContext","routePath","getTraceContext","Injectable","Inject","Inject","captureExceptionWithAttributes","getTraceId","getTraceContext","getTraceContext","getTraceId","captureExceptionWithAttributes","Inject","startSpan","endSpan"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tracewayapp/nestjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Traceway NestJS integration with module, middleware, and decorators",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"dev": "tsup --watch"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@tracewayapp/backend": "0.
|
|
26
|
+
"@tracewayapp/backend": "1.0.0"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
29
|
"@nestjs/common": "^10.0.0",
|