apitally 1.0.0-beta.2 → 1.0.0-beta.3

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.
Files changed (44) hide show
  1. package/README.md +7 -2
  2. package/dist/activation.cjs +1 -0
  3. package/dist/activation.cjs.map +1 -1
  4. package/dist/activation.d.cts +1 -0
  5. package/dist/activation.d.ts +1 -0
  6. package/dist/activation.js +1 -0
  7. package/dist/activation.js.map +1 -1
  8. package/dist/consumers.cjs +96 -0
  9. package/dist/consumers.cjs.map +1 -0
  10. package/dist/consumers.d.cts +13 -0
  11. package/dist/consumers.d.ts +13 -0
  12. package/dist/consumers.js +93 -0
  13. package/dist/consumers.js.map +1 -0
  14. package/dist/context.cjs +2 -8
  15. package/dist/context.cjs.map +1 -1
  16. package/dist/context.d.cts +5 -5
  17. package/dist/context.d.ts +5 -5
  18. package/dist/context.js +3 -7
  19. package/dist/context.js.map +1 -1
  20. package/dist/index.cjs +2 -2
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/nestjs/index.cjs +6 -0
  27. package/dist/nestjs/index.cjs.map +1 -1
  28. package/dist/nestjs/index.js +6 -0
  29. package/dist/nestjs/index.js.map +1 -1
  30. package/dist/requestObservation.cjs +6 -4
  31. package/dist/requestObservation.cjs.map +1 -1
  32. package/dist/requestObservation.js +7 -5
  33. package/dist/requestObservation.js.map +1 -1
  34. package/dist/spanProcessor.cjs +0 -2
  35. package/dist/spanProcessor.cjs.map +1 -1
  36. package/dist/spanProcessor.js +0 -2
  37. package/dist/spanProcessor.js.map +1 -1
  38. package/package.json +1 -1
  39. package/dist/consumer.cjs +0 -61
  40. package/dist/consumer.cjs.map +0 -1
  41. package/dist/consumer.d.cts +0 -12
  42. package/dist/consumer.d.ts +0 -12
  43. package/dist/consumer.js +0 -59
  44. package/dist/consumer.js.map +0 -1
@@ -6,10 +6,11 @@ export interface SpanHandle {
6
6
  span?: Span;
7
7
  ownSpan?: Span;
8
8
  }
9
- export interface ConsumerHolder {
10
- identifier?: string;
9
+ export interface RequestConsumer {
10
+ identifier: string;
11
11
  name?: string;
12
12
  group?: string;
13
+ attributes: Map<string, string | null>;
13
14
  }
14
15
  export type RequestDropReason = "excluded" | "method" | "scheme" | "sampled-out";
15
16
  export interface RequestRecord {
@@ -19,14 +20,13 @@ export interface RequestRecord {
19
20
  dropReason?: RequestDropReason;
20
21
  exception?: unknown;
21
22
  validationErrors?: ValidationErrorDetail[];
23
+ consumer?: RequestConsumer;
22
24
  }
23
25
  export declare const SPAN_HANDLE_KEY: symbol;
24
26
  export declare const REQUEST_RECORD_KEY: symbol;
25
- export declare const CONSUMER_HOLDER_KEY: symbol;
26
- export declare function withRequestHolders(baseContext: Context, spanHandle: SpanHandle, record: RequestRecord, consumerHolder: ConsumerHolder): Context;
27
+ export declare function withRequestHolders(baseContext: Context, spanHandle: SpanHandle, record: RequestRecord): Context;
27
28
  export declare function attachRequestRecordToRpcMetadata(rpcMetadata: RPCMetadata | undefined, record: RequestRecord): void;
28
29
  export declare function getServerSpan(activeContext?: Context): Span | undefined;
29
30
  export declare function getRequestRecord(activeContext?: Context): RequestRecord | undefined;
30
- export declare function getConsumerHolder(activeContext?: Context): ConsumerHolder | undefined;
31
31
  //#endregion
32
32
  //# sourceMappingURL=context.d.cts.map
package/dist/context.d.ts CHANGED
@@ -6,10 +6,11 @@ export interface SpanHandle {
6
6
  span?: Span;
7
7
  ownSpan?: Span;
8
8
  }
9
- export interface ConsumerHolder {
10
- identifier?: string;
9
+ export interface RequestConsumer {
10
+ identifier: string;
11
11
  name?: string;
12
12
  group?: string;
13
+ attributes: Map<string, string | null>;
13
14
  }
14
15
  export type RequestDropReason = "excluded" | "method" | "scheme" | "sampled-out";
15
16
  export interface RequestRecord {
@@ -19,14 +20,13 @@ export interface RequestRecord {
19
20
  dropReason?: RequestDropReason;
20
21
  exception?: unknown;
21
22
  validationErrors?: ValidationErrorDetail[];
23
+ consumer?: RequestConsumer;
22
24
  }
23
25
  export declare const SPAN_HANDLE_KEY: symbol;
24
26
  export declare const REQUEST_RECORD_KEY: symbol;
25
- export declare const CONSUMER_HOLDER_KEY: symbol;
26
- export declare function withRequestHolders(baseContext: Context, spanHandle: SpanHandle, record: RequestRecord, consumerHolder: ConsumerHolder): Context;
27
+ export declare function withRequestHolders(baseContext: Context, spanHandle: SpanHandle, record: RequestRecord): Context;
27
28
  export declare function attachRequestRecordToRpcMetadata(rpcMetadata: RPCMetadata | undefined, record: RequestRecord): void;
28
29
  export declare function getServerSpan(activeContext?: Context): Span | undefined;
29
30
  export declare function getRequestRecord(activeContext?: Context): RequestRecord | undefined;
30
- export declare function getConsumerHolder(activeContext?: Context): ConsumerHolder | undefined;
31
31
  //#endregion
32
32
  //# sourceMappingURL=context.d.ts.map
package/dist/context.js CHANGED
@@ -3,10 +3,9 @@ import { RPCType, getRPCMetadata } from "@opentelemetry/core";
3
3
  //#region src/context.ts
4
4
  const SPAN_HANDLE_KEY = createContextKey("apitally-span-handle");
5
5
  const REQUEST_RECORD_KEY = createContextKey("apitally-request-record");
6
- const CONSUMER_HOLDER_KEY = createContextKey("apitally-consumer-holder");
7
6
  const RPC_REQUEST_RECORD_KEY = Symbol.for("apitally.rpcRequestRecord");
8
- function withRequestHolders(baseContext, spanHandle, record, consumerHolder) {
9
- return baseContext.setValue(SPAN_HANDLE_KEY, spanHandle).setValue(REQUEST_RECORD_KEY, record).setValue(CONSUMER_HOLDER_KEY, consumerHolder);
7
+ function withRequestHolders(baseContext, spanHandle, record) {
8
+ return baseContext.setValue(SPAN_HANDLE_KEY, spanHandle).setValue(REQUEST_RECORD_KEY, record);
10
9
  }
11
10
  function attachRequestRecordToRpcMetadata(rpcMetadata, record) {
12
11
  if (rpcMetadata) rpcMetadata[RPC_REQUEST_RECORD_KEY] = record;
@@ -20,10 +19,7 @@ function getRequestRecord(activeContext = context.active()) {
20
19
  const rpcMetadata = getRPCMetadata(activeContext);
21
20
  return activeContext.getValue(REQUEST_RECORD_KEY) ?? rpcMetadata?.[RPC_REQUEST_RECORD_KEY];
22
21
  }
23
- function getConsumerHolder(activeContext = context.active()) {
24
- return activeContext.getValue(CONSUMER_HOLDER_KEY);
25
- }
26
22
  //#endregion
27
- export { CONSUMER_HOLDER_KEY, REQUEST_RECORD_KEY, SPAN_HANDLE_KEY, attachRequestRecordToRpcMetadata, getConsumerHolder, getRequestRecord, getServerSpan, withRequestHolders };
23
+ export { REQUEST_RECORD_KEY, SPAN_HANDLE_KEY, attachRequestRecordToRpcMetadata, getRequestRecord, getServerSpan, withRequestHolders };
28
24
 
29
25
  //# sourceMappingURL=context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["import {\n type Attributes,\n type Context,\n context,\n createContextKey,\n type Span,\n} from \"@opentelemetry/api\";\nimport { getRPCMetadata, type RPCMetadata, RPCType } from \"@opentelemetry/core\";\nimport type { ValidationErrorDetail } from \"./validationErrors.js\";\n\n// Write sites resolve the request's SERVER span through this handle: under a child\n// span, the active span is not the SERVER span, and OTel has no public upward walk.\nexport interface SpanHandle {\n span?: Span;\n // This set-once reference preserves lifecycle ownership if span later changes.\n ownSpan?: Span;\n}\n\nexport interface ConsumerHolder {\n identifier?: string;\n name?: string;\n group?: string;\n}\n\n// Requests dropped for these reasons are still counted in request metrics,\n// except preflight and websocket requests, which are never recorded.\nexport type RequestDropReason = \"excluded\" | \"method\" | \"scheme\" | \"sampled-out\";\n\n// Transport attributes are applied to exported spans last and used for metrics,\n// so transport values take precedence.\nexport interface RequestRecord {\n attributes: Attributes;\n serverSpanId?: string;\n // Transport-measured request duration, set at completion; the duration\n // histogram records it independent of span timing.\n durationSeconds?: number;\n dropReason?: RequestDropReason;\n // Error state for the validation and server error events; it exists\n // independently of the SERVER span and of the drop decision.\n exception?: unknown;\n validationErrors?: ValidationErrorDetail[];\n}\n\nexport const SPAN_HANDLE_KEY = createContextKey(\"apitally-span-handle\");\nexport const REQUEST_RECORD_KEY = createContextKey(\"apitally-request-record\");\nexport const CONSUMER_HOLDER_KEY = createContextKey(\"apitally-consumer-holder\");\n\nconst RPC_REQUEST_RECORD_KEY = Symbol.for(\"apitally.rpcRequestRecord\");\n\ntype RPCMetadataWithRequestRecord = RPCMetadata & {\n [RPC_REQUEST_RECORD_KEY]?: RequestRecord;\n};\n\n// Mutable holders carry changing request state because OTel contexts are immutable.\nexport function withRequestHolders(\n baseContext: Context,\n spanHandle: SpanHandle,\n record: RequestRecord,\n consumerHolder: ConsumerHolder,\n): Context {\n return baseContext\n .setValue(SPAN_HANDLE_KEY, spanHandle)\n .setValue(REQUEST_RECORD_KEY, record)\n .setValue(CONSUMER_HOLDER_KEY, consumerHolder);\n}\n\nexport function attachRequestRecordToRpcMetadata(\n rpcMetadata: RPCMetadata | undefined,\n record: RequestRecord,\n): void {\n if (rpcMetadata) {\n (rpcMetadata as RPCMetadataWithRequestRecord)[RPC_REQUEST_RECORD_KEY] = record;\n }\n}\n\nexport function getServerSpan(activeContext: Context = context.active()): Span | undefined {\n const spanHandle = activeContext.getValue(SPAN_HANDLE_KEY) as SpanHandle | undefined;\n const rpcMetadata = getRPCMetadata(activeContext) as RPCMetadataWithRequestRecord | undefined;\n return (\n spanHandle?.span ??\n (rpcMetadata?.type === RPCType.HTTP && rpcMetadata[RPC_REQUEST_RECORD_KEY]\n ? rpcMetadata.span\n : undefined)\n );\n}\n\nexport function getRequestRecord(\n activeContext: Context = context.active(),\n): RequestRecord | undefined {\n const rpcMetadata = getRPCMetadata(activeContext) as RPCMetadataWithRequestRecord | undefined;\n return (\n (activeContext.getValue(REQUEST_RECORD_KEY) as RequestRecord | undefined) ??\n rpcMetadata?.[RPC_REQUEST_RECORD_KEY]\n );\n}\n\nexport function getConsumerHolder(\n activeContext: Context = context.active(),\n): ConsumerHolder | undefined {\n return activeContext.getValue(CONSUMER_HOLDER_KEY) as ConsumerHolder | undefined;\n}\n"],"mappings":";;;AA2CA,MAAa,kBAAkB,iBAAiB,sBAAsB;AACtE,MAAa,qBAAqB,iBAAiB,yBAAyB;AAC5E,MAAa,sBAAsB,iBAAiB,0BAA0B;AAE9E,MAAM,yBAAyB,OAAO,IAAI,2BAA2B;AAOrE,SAAgB,mBACd,aACA,YACA,QACA,gBACS;CACT,OAAO,YACJ,SAAS,iBAAiB,UAAU,CAAC,CACrC,SAAS,oBAAoB,MAAM,CAAC,CACpC,SAAS,qBAAqB,cAAc;AACjD;AAEA,SAAgB,iCACd,aACA,QACM;CACN,IAAI,aACF,YAA8C,0BAA0B;AAE5E;AAEA,SAAgB,cAAc,gBAAyB,QAAQ,OAAO,GAAqB;CACzF,MAAM,aAAa,cAAc,SAAS,eAAe;CACzD,MAAM,cAAc,eAAe,aAAa;CAChD,OACE,YAAY,SACX,aAAa,SAAS,QAAQ,QAAQ,YAAY,0BAC/C,YAAY,OACZ,KAAA;AAER;AAEA,SAAgB,iBACd,gBAAyB,QAAQ,OAAO,GACb;CAC3B,MAAM,cAAc,eAAe,aAAa;CAChD,OACG,cAAc,SAAS,kBAAkB,KAC1C,cAAc;AAElB;AAEA,SAAgB,kBACd,gBAAyB,QAAQ,OAAO,GACZ;CAC5B,OAAO,cAAc,SAAS,mBAAmB;AACnD"}
1
+ {"version":3,"file":"context.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["import {\n type Attributes,\n type Context,\n context,\n createContextKey,\n type Span,\n} from \"@opentelemetry/api\";\nimport { getRPCMetadata, type RPCMetadata, RPCType } from \"@opentelemetry/core\";\nimport type { ValidationErrorDetail } from \"./validationErrors.js\";\n\n// Write sites resolve the request's SERVER span through this handle: under a child\n// span, the active span is not the SERVER span, and OTel has no public upward walk.\nexport interface SpanHandle {\n span?: Span;\n // This set-once reference preserves lifecycle ownership if span later changes.\n ownSpan?: Span;\n}\n\nexport interface RequestConsumer {\n identifier: string;\n name?: string;\n group?: string;\n attributes: Map<string, string | null>;\n}\n\n// Requests dropped for these reasons are still counted in request metrics,\n// except preflight and websocket requests, which are never recorded.\nexport type RequestDropReason = \"excluded\" | \"method\" | \"scheme\" | \"sampled-out\";\n\n// Transport attributes are applied to exported spans last and used for metrics,\n// so transport values take precedence.\nexport interface RequestRecord {\n attributes: Attributes;\n serverSpanId?: string;\n // Transport-measured request duration, set at completion; the duration\n // histogram records it independent of span timing.\n durationSeconds?: number;\n dropReason?: RequestDropReason;\n // Error state for the validation and server error events; it exists\n // independently of the SERVER span and of the drop decision.\n exception?: unknown;\n validationErrors?: ValidationErrorDetail[];\n // Consumer metadata for the consumer update event emitted at completion.\n consumer?: RequestConsumer;\n}\n\nexport const SPAN_HANDLE_KEY = createContextKey(\"apitally-span-handle\");\nexport const REQUEST_RECORD_KEY = createContextKey(\"apitally-request-record\");\n\nconst RPC_REQUEST_RECORD_KEY = Symbol.for(\"apitally.rpcRequestRecord\");\n\ntype RPCMetadataWithRequestRecord = RPCMetadata & {\n [RPC_REQUEST_RECORD_KEY]?: RequestRecord;\n};\n\n// Mutable holders carry changing request state because OTel contexts are immutable.\nexport function withRequestHolders(\n baseContext: Context,\n spanHandle: SpanHandle,\n record: RequestRecord,\n): Context {\n return baseContext.setValue(SPAN_HANDLE_KEY, spanHandle).setValue(REQUEST_RECORD_KEY, record);\n}\n\nexport function attachRequestRecordToRpcMetadata(\n rpcMetadata: RPCMetadata | undefined,\n record: RequestRecord,\n): void {\n if (rpcMetadata) {\n (rpcMetadata as RPCMetadataWithRequestRecord)[RPC_REQUEST_RECORD_KEY] = record;\n }\n}\n\nexport function getServerSpan(activeContext: Context = context.active()): Span | undefined {\n const spanHandle = activeContext.getValue(SPAN_HANDLE_KEY) as SpanHandle | undefined;\n const rpcMetadata = getRPCMetadata(activeContext) as RPCMetadataWithRequestRecord | undefined;\n return (\n spanHandle?.span ??\n (rpcMetadata?.type === RPCType.HTTP && rpcMetadata[RPC_REQUEST_RECORD_KEY]\n ? rpcMetadata.span\n : undefined)\n );\n}\n\nexport function getRequestRecord(\n activeContext: Context = context.active(),\n): RequestRecord | undefined {\n const rpcMetadata = getRPCMetadata(activeContext) as RPCMetadataWithRequestRecord | undefined;\n return (\n (activeContext.getValue(REQUEST_RECORD_KEY) as RequestRecord | undefined) ??\n rpcMetadata?.[RPC_REQUEST_RECORD_KEY]\n );\n}\n"],"mappings":";;;AA8CA,MAAa,kBAAkB,iBAAiB,sBAAsB;AACtE,MAAa,qBAAqB,iBAAiB,yBAAyB;AAE5E,MAAM,yBAAyB,OAAO,IAAI,2BAA2B;AAOrE,SAAgB,mBACd,aACA,YACA,QACS;CACT,OAAO,YAAY,SAAS,iBAAiB,UAAU,CAAC,CAAC,SAAS,oBAAoB,MAAM;AAC9F;AAEA,SAAgB,iCACd,aACA,QACM;CACN,IAAI,aACF,YAA8C,0BAA0B;AAE5E;AAEA,SAAgB,cAAc,gBAAyB,QAAQ,OAAO,GAAqB;CACzF,MAAM,aAAa,cAAc,SAAS,eAAe;CACzD,MAAM,cAAc,eAAe,aAAa;CAChD,OACE,YAAY,SACX,aAAa,SAAS,QAAQ,QAAQ,YAAY,0BAC/C,YAAY,OACZ,KAAA;AAER;AAEA,SAAgB,iBACd,gBAAyB,QAAQ,OAAO,GACb;CAC3B,MAAM,cAAc,eAAe,aAAa;CAChD,OACG,cAAc,SAAS,kBAAkB,KAC1C,cAAc;AAElB"}
package/dist/index.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_requestAttributes = require("./requestAttributes.cjs");
3
3
  const require_exceptions = require("./exceptions.cjs");
4
- const require_consumer = require("./consumer.cjs");
5
4
  const require_spanProcessor = require("./spanProcessor.cjs");
6
5
  const require_activation = require("./activation.cjs");
6
+ const require_consumers = require("./consumers.cjs");
7
7
  const require_adonisjs_configure = require("./adonisjs/configure.cjs");
8
8
  const require_elysia_middleware = require("./elysia/middleware.cjs");
9
9
  const require_express_index = require("./express/index.cjs");
@@ -61,7 +61,7 @@ exports.ApitallySpanProcessor = require_spanProcessor.ApitallySpanProcessor;
61
61
  exports.captureException = require_exceptions.captureException;
62
62
  exports.configure = configure;
63
63
  exports.instrument = require_tracing.instrument;
64
- exports.setConsumer = require_consumer.setConsumer;
64
+ exports.setConsumer = require_consumers.setConsumer;
65
65
  exports.setRequestAttribute = require_requestAttributes.setRequestAttribute;
66
66
  exports.shutdown = require_activation.shutdown;
67
67
  exports.span = require_tracing.span;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["configureAdonis"],"sources":["../src/index.ts"],"sourcesContent":["import { configure as configureAdonis } from \"./adonisjs/configure.js\";\nimport type { ApitallyOptions } from \"./config.js\";\nimport { installElysiaIntegration } from \"./elysia/middleware.js\";\nimport { useApitally as useApitallyExpress } from \"./express/index.js\";\nimport { useApitally as useApitallyFastify } from \"./fastify/index.js\";\nimport { useApitally as useApitallyH3 } from \"./h3/index.js\";\nimport { useApitally as useApitallyHapi } from \"./hapi/index.js\";\nimport { useApitally as useApitallyHono } from \"./hono/index.js\";\nimport { useApitally as useApitallyKoa } from \"./koa/index.js\";\n\nexport { shutdown } from \"./activation.js\";\nexport type {\n ApitallyOptions,\n BodyMaskingCallback,\n LogRecordMaskingCallback,\n SamplingCallback,\n} from \"./config.js\";\nexport type { ApitallyConsumer } from \"./consumer.js\";\nexport { setConsumer } from \"./consumer.js\";\nexport { captureException } from \"./exceptions.js\";\nexport { setRequestAttribute } from \"./requestAttributes.js\";\nexport { ApitallySpanProcessor } from \"./spanProcessor.js\";\nexport { instrument, span } from \"./tracing.js\";\n\n/** AdonisJS Ace configuration hook. */\nexport function configure(command: unknown): Promise<void> {\n return configureAdonis(command as Parameters<typeof configureAdonis>[0]);\n}\n\nexport function useApitally(app: unknown, options?: ApitallyOptions): void {\n if (isExpressApp(app)) {\n useApitallyExpress(app, options);\n } else if (isFastifyApp(app)) {\n useApitallyFastify(app, options);\n } else if (isHapiServer(app)) {\n useApitallyHapi(app, options);\n } else if (isH3App(app)) {\n useApitallyH3(app, options);\n } else if (isElysiaApp(app)) {\n installElysiaIntegration(app, options);\n } else if (isHonoApp(app)) {\n useApitallyHono(app, options);\n } else if (isKoaApp(app)) {\n useApitallyKoa(app, options);\n } else {\n throw new TypeError(\n \"useApitally() could not detect a supported framework from the app argument\",\n );\n }\n}\n\nfunction isExpressApp(app: unknown): app is Parameters<typeof useApitallyExpress>[0] {\n const candidate = app as {\n use?: unknown;\n handle?: unknown;\n };\n return (\n typeof app === \"function\" &&\n typeof candidate.use === \"function\" &&\n typeof candidate.handle === \"function\"\n );\n}\n\nfunction isFastifyApp(app: unknown): app is Parameters<typeof useApitallyFastify>[0] {\n const candidate = app as {\n version?: unknown;\n addHook?: unknown;\n register?: unknown;\n route?: unknown;\n ready?: unknown;\n close?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n typeof candidate.version === \"string\" &&\n typeof candidate.addHook === \"function\" &&\n typeof candidate.register === \"function\" &&\n typeof candidate.route === \"function\" &&\n typeof candidate.ready === \"function\" &&\n typeof candidate.close === \"function\"\n );\n}\n\nfunction isHapiServer(app: unknown): app is Parameters<typeof useApitallyHapi>[0] {\n const candidate = app as {\n ext?: unknown;\n register?: unknown;\n route?: unknown;\n table?: unknown;\n initialize?: unknown;\n start?: unknown;\n stop?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n typeof candidate.ext === \"function\" &&\n typeof candidate.register === \"function\" &&\n typeof candidate.route === \"function\" &&\n typeof candidate.table === \"function\" &&\n typeof candidate.initialize === \"function\" &&\n typeof candidate.start === \"function\" &&\n typeof candidate.stop === \"function\"\n );\n}\n\nfunction isH3App(app: unknown): app is Parameters<typeof useApitallyH3>[0] {\n const candidate = app as {\n constructor?: Record<string, unknown>;\n fetch?: unknown;\n request?: unknown;\n use?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n candidate.constructor?.[\"~h3\"] === true &&\n typeof candidate.fetch === \"function\" &&\n typeof candidate.request === \"function\" &&\n typeof candidate.use === \"function\"\n );\n}\n\nfunction isElysiaApp(app: unknown): app is Parameters<typeof installElysiaIntegration>[0] {\n const candidate = app as {\n routes?: unknown;\n handle?: unknown;\n route?: unknown;\n wrap?: unknown;\n onTransform?: unknown;\n onError?: unknown;\n };\n // Avoid reading app.fetch, as it compiles Elysia before the integration can be installed\n return (\n typeof app === \"object\" &&\n app !== null &&\n Array.isArray(candidate.routes) &&\n typeof candidate.handle === \"function\" &&\n typeof candidate.route === \"function\" &&\n typeof candidate.wrap === \"function\" &&\n typeof candidate.onTransform === \"function\" &&\n typeof candidate.onError === \"function\"\n );\n}\n\nfunction isKoaApp(app: unknown): app is Parameters<typeof useApitallyKoa>[0] {\n const candidate = app as {\n middleware?: unknown;\n use?: unknown;\n callback?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n Array.isArray(candidate.middleware) &&\n typeof candidate.use === \"function\" &&\n typeof candidate.callback === \"function\"\n );\n}\n\nfunction isHonoApp(app: unknown): app is Parameters<typeof useApitallyHono>[0] {\n const candidate = app as {\n routes?: unknown;\n fetch?: unknown;\n route?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n Array.isArray(candidate.routes) &&\n typeof candidate.fetch === \"function\" &&\n typeof candidate.route === \"function\"\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyBA,SAAgB,UAAU,SAAiC;CACzD,OAAOA,2BAAAA,UAAgB,OAAgD;AACzE;AAEA,SAAgB,YAAY,KAAc,SAAiC;CACzE,IAAI,aAAa,GAAG,GAClB,sBAAA,YAAmB,KAAK,OAAO;MAC1B,IAAI,aAAa,GAAG,GACzB,sBAAA,YAAmB,KAAK,OAAO;MAC1B,IAAI,aAAa,GAAG,GACzB,mBAAA,YAAgB,KAAK,OAAO;MACvB,IAAI,QAAQ,GAAG,GACpB,iBAAA,YAAc,KAAK,OAAO;MACrB,IAAI,YAAY,GAAG,GACxB,0BAAA,yBAAyB,KAAK,OAAO;MAChC,IAAI,UAAU,GAAG,GACtB,mBAAA,YAAgB,KAAK,OAAO;MACvB,IAAI,SAAS,GAAG,GACrB,kBAAA,YAAe,KAAK,OAAO;MAE3B,MAAM,IAAI,UACR,4EACF;AAEJ;AAEA,SAAS,aAAa,KAA+D;CACnF,MAAM,YAAY;CAIlB,OACE,OAAO,QAAQ,cACf,OAAO,UAAU,QAAQ,cACzB,OAAO,UAAU,WAAW;AAEhC;AAEA,SAAS,aAAa,KAA+D;CACnF,MAAM,YAAY;CAQlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,OAAO,UAAU,YAAY,YAC7B,OAAO,UAAU,YAAY,cAC7B,OAAO,UAAU,aAAa,cAC9B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU;AAE/B;AAEA,SAAS,aAAa,KAA4D;CAChF,MAAM,YAAY;CASlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,OAAO,UAAU,QAAQ,cACzB,OAAO,UAAU,aAAa,cAC9B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,eAAe,cAChC,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,SAAS;AAE9B;AAEA,SAAS,QAAQ,KAA0D;CACzE,MAAM,YAAY;CAMlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,UAAU,cAAc,WAAW,QACnC,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,YAAY,cAC7B,OAAO,UAAU,QAAQ;AAE7B;AAEA,SAAS,YAAY,KAAqE;CACxF,MAAM,YAAY;CASlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,MAAM,QAAQ,UAAU,MAAM,KAC9B,OAAO,UAAU,WAAW,cAC5B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,SAAS,cAC1B,OAAO,UAAU,gBAAgB,cACjC,OAAO,UAAU,YAAY;AAEjC;AAEA,SAAS,SAAS,KAA2D;CAC3E,MAAM,YAAY;CAKlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,MAAM,QAAQ,UAAU,UAAU,KAClC,OAAO,UAAU,QAAQ,cACzB,OAAO,UAAU,aAAa;AAElC;AAEA,SAAS,UAAU,KAA4D;CAC7E,MAAM,YAAY;CAKlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,MAAM,QAAQ,UAAU,MAAM,KAC9B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU;AAE/B"}
1
+ {"version":3,"file":"index.cjs","names":["configureAdonis"],"sources":["../src/index.ts"],"sourcesContent":["import { configure as configureAdonis } from \"./adonisjs/configure.js\";\nimport type { ApitallyOptions } from \"./config.js\";\nimport { installElysiaIntegration } from \"./elysia/middleware.js\";\nimport { useApitally as useApitallyExpress } from \"./express/index.js\";\nimport { useApitally as useApitallyFastify } from \"./fastify/index.js\";\nimport { useApitally as useApitallyH3 } from \"./h3/index.js\";\nimport { useApitally as useApitallyHapi } from \"./hapi/index.js\";\nimport { useApitally as useApitallyHono } from \"./hono/index.js\";\nimport { useApitally as useApitallyKoa } from \"./koa/index.js\";\n\nexport { shutdown } from \"./activation.js\";\nexport type {\n ApitallyOptions,\n BodyMaskingCallback,\n LogRecordMaskingCallback,\n SamplingCallback,\n} from \"./config.js\";\nexport type { ApitallyConsumer } from \"./consumers.js\";\nexport { setConsumer } from \"./consumers.js\";\nexport { captureException } from \"./exceptions.js\";\nexport { setRequestAttribute } from \"./requestAttributes.js\";\nexport { ApitallySpanProcessor } from \"./spanProcessor.js\";\nexport { instrument, span } from \"./tracing.js\";\n\n/** AdonisJS Ace configuration hook. */\nexport function configure(command: unknown): Promise<void> {\n return configureAdonis(command as Parameters<typeof configureAdonis>[0]);\n}\n\nexport function useApitally(app: unknown, options?: ApitallyOptions): void {\n if (isExpressApp(app)) {\n useApitallyExpress(app, options);\n } else if (isFastifyApp(app)) {\n useApitallyFastify(app, options);\n } else if (isHapiServer(app)) {\n useApitallyHapi(app, options);\n } else if (isH3App(app)) {\n useApitallyH3(app, options);\n } else if (isElysiaApp(app)) {\n installElysiaIntegration(app, options);\n } else if (isHonoApp(app)) {\n useApitallyHono(app, options);\n } else if (isKoaApp(app)) {\n useApitallyKoa(app, options);\n } else {\n throw new TypeError(\n \"useApitally() could not detect a supported framework from the app argument\",\n );\n }\n}\n\nfunction isExpressApp(app: unknown): app is Parameters<typeof useApitallyExpress>[0] {\n const candidate = app as {\n use?: unknown;\n handle?: unknown;\n };\n return (\n typeof app === \"function\" &&\n typeof candidate.use === \"function\" &&\n typeof candidate.handle === \"function\"\n );\n}\n\nfunction isFastifyApp(app: unknown): app is Parameters<typeof useApitallyFastify>[0] {\n const candidate = app as {\n version?: unknown;\n addHook?: unknown;\n register?: unknown;\n route?: unknown;\n ready?: unknown;\n close?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n typeof candidate.version === \"string\" &&\n typeof candidate.addHook === \"function\" &&\n typeof candidate.register === \"function\" &&\n typeof candidate.route === \"function\" &&\n typeof candidate.ready === \"function\" &&\n typeof candidate.close === \"function\"\n );\n}\n\nfunction isHapiServer(app: unknown): app is Parameters<typeof useApitallyHapi>[0] {\n const candidate = app as {\n ext?: unknown;\n register?: unknown;\n route?: unknown;\n table?: unknown;\n initialize?: unknown;\n start?: unknown;\n stop?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n typeof candidate.ext === \"function\" &&\n typeof candidate.register === \"function\" &&\n typeof candidate.route === \"function\" &&\n typeof candidate.table === \"function\" &&\n typeof candidate.initialize === \"function\" &&\n typeof candidate.start === \"function\" &&\n typeof candidate.stop === \"function\"\n );\n}\n\nfunction isH3App(app: unknown): app is Parameters<typeof useApitallyH3>[0] {\n const candidate = app as {\n constructor?: Record<string, unknown>;\n fetch?: unknown;\n request?: unknown;\n use?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n candidate.constructor?.[\"~h3\"] === true &&\n typeof candidate.fetch === \"function\" &&\n typeof candidate.request === \"function\" &&\n typeof candidate.use === \"function\"\n );\n}\n\nfunction isElysiaApp(app: unknown): app is Parameters<typeof installElysiaIntegration>[0] {\n const candidate = app as {\n routes?: unknown;\n handle?: unknown;\n route?: unknown;\n wrap?: unknown;\n onTransform?: unknown;\n onError?: unknown;\n };\n // Avoid reading app.fetch, as it compiles Elysia before the integration can be installed\n return (\n typeof app === \"object\" &&\n app !== null &&\n Array.isArray(candidate.routes) &&\n typeof candidate.handle === \"function\" &&\n typeof candidate.route === \"function\" &&\n typeof candidate.wrap === \"function\" &&\n typeof candidate.onTransform === \"function\" &&\n typeof candidate.onError === \"function\"\n );\n}\n\nfunction isKoaApp(app: unknown): app is Parameters<typeof useApitallyKoa>[0] {\n const candidate = app as {\n middleware?: unknown;\n use?: unknown;\n callback?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n Array.isArray(candidate.middleware) &&\n typeof candidate.use === \"function\" &&\n typeof candidate.callback === \"function\"\n );\n}\n\nfunction isHonoApp(app: unknown): app is Parameters<typeof useApitallyHono>[0] {\n const candidate = app as {\n routes?: unknown;\n fetch?: unknown;\n route?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n Array.isArray(candidate.routes) &&\n typeof candidate.fetch === \"function\" &&\n typeof candidate.route === \"function\"\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyBA,SAAgB,UAAU,SAAiC;CACzD,OAAOA,2BAAAA,UAAgB,OAAgD;AACzE;AAEA,SAAgB,YAAY,KAAc,SAAiC;CACzE,IAAI,aAAa,GAAG,GAClB,sBAAA,YAAmB,KAAK,OAAO;MAC1B,IAAI,aAAa,GAAG,GACzB,sBAAA,YAAmB,KAAK,OAAO;MAC1B,IAAI,aAAa,GAAG,GACzB,mBAAA,YAAgB,KAAK,OAAO;MACvB,IAAI,QAAQ,GAAG,GACpB,iBAAA,YAAc,KAAK,OAAO;MACrB,IAAI,YAAY,GAAG,GACxB,0BAAA,yBAAyB,KAAK,OAAO;MAChC,IAAI,UAAU,GAAG,GACtB,mBAAA,YAAgB,KAAK,OAAO;MACvB,IAAI,SAAS,GAAG,GACrB,kBAAA,YAAe,KAAK,OAAO;MAE3B,MAAM,IAAI,UACR,4EACF;AAEJ;AAEA,SAAS,aAAa,KAA+D;CACnF,MAAM,YAAY;CAIlB,OACE,OAAO,QAAQ,cACf,OAAO,UAAU,QAAQ,cACzB,OAAO,UAAU,WAAW;AAEhC;AAEA,SAAS,aAAa,KAA+D;CACnF,MAAM,YAAY;CAQlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,OAAO,UAAU,YAAY,YAC7B,OAAO,UAAU,YAAY,cAC7B,OAAO,UAAU,aAAa,cAC9B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU;AAE/B;AAEA,SAAS,aAAa,KAA4D;CAChF,MAAM,YAAY;CASlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,OAAO,UAAU,QAAQ,cACzB,OAAO,UAAU,aAAa,cAC9B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,eAAe,cAChC,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,SAAS;AAE9B;AAEA,SAAS,QAAQ,KAA0D;CACzE,MAAM,YAAY;CAMlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,UAAU,cAAc,WAAW,QACnC,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,YAAY,cAC7B,OAAO,UAAU,QAAQ;AAE7B;AAEA,SAAS,YAAY,KAAqE;CACxF,MAAM,YAAY;CASlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,MAAM,QAAQ,UAAU,MAAM,KAC9B,OAAO,UAAU,WAAW,cAC5B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,SAAS,cAC1B,OAAO,UAAU,gBAAgB,cACjC,OAAO,UAAU,YAAY;AAEjC;AAEA,SAAS,SAAS,KAA2D;CAC3E,MAAM,YAAY;CAKlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,MAAM,QAAQ,UAAU,UAAU,KAClC,OAAO,UAAU,QAAQ,cACzB,OAAO,UAAU,aAAa;AAElC;AAEA,SAAS,UAAU,KAA4D;CAC7E,MAAM,YAAY;CAKlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,MAAM,QAAQ,UAAU,MAAM,KAC9B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU;AAE/B"}
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ApitallyOptions, BodyMaskingCallback, LogRecordMaskingCallback, SamplingCallback } from "./config.cjs";
2
2
  import { ApitallySpanProcessor } from "./spanProcessor.cjs";
3
3
  import { shutdown } from "./activation.cjs";
4
- import { ApitallyConsumer, setConsumer } from "./consumer.cjs";
4
+ import { ApitallyConsumer, setConsumer } from "./consumers.cjs";
5
5
  import { captureException } from "./exceptions.cjs";
6
6
  import { setRequestAttribute } from "./requestAttributes.cjs";
7
7
  import { instrument, span } from "./tracing.cjs";
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ApitallyOptions, BodyMaskingCallback, LogRecordMaskingCallback, SamplingCallback } from "./config.js";
2
2
  import { ApitallySpanProcessor } from "./spanProcessor.js";
3
3
  import { shutdown } from "./activation.js";
4
- import { ApitallyConsumer, setConsumer } from "./consumer.js";
4
+ import { ApitallyConsumer, setConsumer } from "./consumers.js";
5
5
  import { captureException } from "./exceptions.js";
6
6
  import { setRequestAttribute } from "./requestAttributes.js";
7
7
  import { instrument, span } from "./tracing.js";
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { setRequestAttribute } from "./requestAttributes.js";
2
2
  import { captureException } from "./exceptions.js";
3
- import { setConsumer } from "./consumer.js";
4
3
  import { ApitallySpanProcessor } from "./spanProcessor.js";
5
4
  import { shutdown } from "./activation.js";
5
+ import { setConsumer } from "./consumers.js";
6
6
  import { configure as configure$1 } from "./adonisjs/configure.js";
7
7
  import { installElysiaIntegration } from "./elysia/middleware.js";
8
8
  import { useApitally as useApitally$1 } from "./express/index.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["configureAdonis"],"sources":["../src/index.ts"],"sourcesContent":["import { configure as configureAdonis } from \"./adonisjs/configure.js\";\nimport type { ApitallyOptions } from \"./config.js\";\nimport { installElysiaIntegration } from \"./elysia/middleware.js\";\nimport { useApitally as useApitallyExpress } from \"./express/index.js\";\nimport { useApitally as useApitallyFastify } from \"./fastify/index.js\";\nimport { useApitally as useApitallyH3 } from \"./h3/index.js\";\nimport { useApitally as useApitallyHapi } from \"./hapi/index.js\";\nimport { useApitally as useApitallyHono } from \"./hono/index.js\";\nimport { useApitally as useApitallyKoa } from \"./koa/index.js\";\n\nexport { shutdown } from \"./activation.js\";\nexport type {\n ApitallyOptions,\n BodyMaskingCallback,\n LogRecordMaskingCallback,\n SamplingCallback,\n} from \"./config.js\";\nexport type { ApitallyConsumer } from \"./consumer.js\";\nexport { setConsumer } from \"./consumer.js\";\nexport { captureException } from \"./exceptions.js\";\nexport { setRequestAttribute } from \"./requestAttributes.js\";\nexport { ApitallySpanProcessor } from \"./spanProcessor.js\";\nexport { instrument, span } from \"./tracing.js\";\n\n/** AdonisJS Ace configuration hook. */\nexport function configure(command: unknown): Promise<void> {\n return configureAdonis(command as Parameters<typeof configureAdonis>[0]);\n}\n\nexport function useApitally(app: unknown, options?: ApitallyOptions): void {\n if (isExpressApp(app)) {\n useApitallyExpress(app, options);\n } else if (isFastifyApp(app)) {\n useApitallyFastify(app, options);\n } else if (isHapiServer(app)) {\n useApitallyHapi(app, options);\n } else if (isH3App(app)) {\n useApitallyH3(app, options);\n } else if (isElysiaApp(app)) {\n installElysiaIntegration(app, options);\n } else if (isHonoApp(app)) {\n useApitallyHono(app, options);\n } else if (isKoaApp(app)) {\n useApitallyKoa(app, options);\n } else {\n throw new TypeError(\n \"useApitally() could not detect a supported framework from the app argument\",\n );\n }\n}\n\nfunction isExpressApp(app: unknown): app is Parameters<typeof useApitallyExpress>[0] {\n const candidate = app as {\n use?: unknown;\n handle?: unknown;\n };\n return (\n typeof app === \"function\" &&\n typeof candidate.use === \"function\" &&\n typeof candidate.handle === \"function\"\n );\n}\n\nfunction isFastifyApp(app: unknown): app is Parameters<typeof useApitallyFastify>[0] {\n const candidate = app as {\n version?: unknown;\n addHook?: unknown;\n register?: unknown;\n route?: unknown;\n ready?: unknown;\n close?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n typeof candidate.version === \"string\" &&\n typeof candidate.addHook === \"function\" &&\n typeof candidate.register === \"function\" &&\n typeof candidate.route === \"function\" &&\n typeof candidate.ready === \"function\" &&\n typeof candidate.close === \"function\"\n );\n}\n\nfunction isHapiServer(app: unknown): app is Parameters<typeof useApitallyHapi>[0] {\n const candidate = app as {\n ext?: unknown;\n register?: unknown;\n route?: unknown;\n table?: unknown;\n initialize?: unknown;\n start?: unknown;\n stop?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n typeof candidate.ext === \"function\" &&\n typeof candidate.register === \"function\" &&\n typeof candidate.route === \"function\" &&\n typeof candidate.table === \"function\" &&\n typeof candidate.initialize === \"function\" &&\n typeof candidate.start === \"function\" &&\n typeof candidate.stop === \"function\"\n );\n}\n\nfunction isH3App(app: unknown): app is Parameters<typeof useApitallyH3>[0] {\n const candidate = app as {\n constructor?: Record<string, unknown>;\n fetch?: unknown;\n request?: unknown;\n use?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n candidate.constructor?.[\"~h3\"] === true &&\n typeof candidate.fetch === \"function\" &&\n typeof candidate.request === \"function\" &&\n typeof candidate.use === \"function\"\n );\n}\n\nfunction isElysiaApp(app: unknown): app is Parameters<typeof installElysiaIntegration>[0] {\n const candidate = app as {\n routes?: unknown;\n handle?: unknown;\n route?: unknown;\n wrap?: unknown;\n onTransform?: unknown;\n onError?: unknown;\n };\n // Avoid reading app.fetch, as it compiles Elysia before the integration can be installed\n return (\n typeof app === \"object\" &&\n app !== null &&\n Array.isArray(candidate.routes) &&\n typeof candidate.handle === \"function\" &&\n typeof candidate.route === \"function\" &&\n typeof candidate.wrap === \"function\" &&\n typeof candidate.onTransform === \"function\" &&\n typeof candidate.onError === \"function\"\n );\n}\n\nfunction isKoaApp(app: unknown): app is Parameters<typeof useApitallyKoa>[0] {\n const candidate = app as {\n middleware?: unknown;\n use?: unknown;\n callback?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n Array.isArray(candidate.middleware) &&\n typeof candidate.use === \"function\" &&\n typeof candidate.callback === \"function\"\n );\n}\n\nfunction isHonoApp(app: unknown): app is Parameters<typeof useApitallyHono>[0] {\n const candidate = app as {\n routes?: unknown;\n fetch?: unknown;\n route?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n Array.isArray(candidate.routes) &&\n typeof candidate.fetch === \"function\" &&\n typeof candidate.route === \"function\"\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyBA,SAAgB,UAAU,SAAiC;CACzD,OAAOA,YAAgB,OAAgD;AACzE;AAEA,SAAgB,YAAY,KAAc,SAAiC;CACzE,IAAI,aAAa,GAAG,GAClB,cAAmB,KAAK,OAAO;MAC1B,IAAI,aAAa,GAAG,GACzB,cAAmB,KAAK,OAAO;MAC1B,IAAI,aAAa,GAAG,GACzB,cAAgB,KAAK,OAAO;MACvB,IAAI,QAAQ,GAAG,GACpB,cAAc,KAAK,OAAO;MACrB,IAAI,YAAY,GAAG,GACxB,yBAAyB,KAAK,OAAO;MAChC,IAAI,UAAU,GAAG,GACtB,cAAgB,KAAK,OAAO;MACvB,IAAI,SAAS,GAAG,GACrB,cAAe,KAAK,OAAO;MAE3B,MAAM,IAAI,UACR,4EACF;AAEJ;AAEA,SAAS,aAAa,KAA+D;CACnF,MAAM,YAAY;CAIlB,OACE,OAAO,QAAQ,cACf,OAAO,UAAU,QAAQ,cACzB,OAAO,UAAU,WAAW;AAEhC;AAEA,SAAS,aAAa,KAA+D;CACnF,MAAM,YAAY;CAQlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,OAAO,UAAU,YAAY,YAC7B,OAAO,UAAU,YAAY,cAC7B,OAAO,UAAU,aAAa,cAC9B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU;AAE/B;AAEA,SAAS,aAAa,KAA4D;CAChF,MAAM,YAAY;CASlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,OAAO,UAAU,QAAQ,cACzB,OAAO,UAAU,aAAa,cAC9B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,eAAe,cAChC,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,SAAS;AAE9B;AAEA,SAAS,QAAQ,KAA0D;CACzE,MAAM,YAAY;CAMlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,UAAU,cAAc,WAAW,QACnC,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,YAAY,cAC7B,OAAO,UAAU,QAAQ;AAE7B;AAEA,SAAS,YAAY,KAAqE;CACxF,MAAM,YAAY;CASlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,MAAM,QAAQ,UAAU,MAAM,KAC9B,OAAO,UAAU,WAAW,cAC5B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,SAAS,cAC1B,OAAO,UAAU,gBAAgB,cACjC,OAAO,UAAU,YAAY;AAEjC;AAEA,SAAS,SAAS,KAA2D;CAC3E,MAAM,YAAY;CAKlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,MAAM,QAAQ,UAAU,UAAU,KAClC,OAAO,UAAU,QAAQ,cACzB,OAAO,UAAU,aAAa;AAElC;AAEA,SAAS,UAAU,KAA4D;CAC7E,MAAM,YAAY;CAKlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,MAAM,QAAQ,UAAU,MAAM,KAC9B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU;AAE/B"}
1
+ {"version":3,"file":"index.js","names":["configureAdonis"],"sources":["../src/index.ts"],"sourcesContent":["import { configure as configureAdonis } from \"./adonisjs/configure.js\";\nimport type { ApitallyOptions } from \"./config.js\";\nimport { installElysiaIntegration } from \"./elysia/middleware.js\";\nimport { useApitally as useApitallyExpress } from \"./express/index.js\";\nimport { useApitally as useApitallyFastify } from \"./fastify/index.js\";\nimport { useApitally as useApitallyH3 } from \"./h3/index.js\";\nimport { useApitally as useApitallyHapi } from \"./hapi/index.js\";\nimport { useApitally as useApitallyHono } from \"./hono/index.js\";\nimport { useApitally as useApitallyKoa } from \"./koa/index.js\";\n\nexport { shutdown } from \"./activation.js\";\nexport type {\n ApitallyOptions,\n BodyMaskingCallback,\n LogRecordMaskingCallback,\n SamplingCallback,\n} from \"./config.js\";\nexport type { ApitallyConsumer } from \"./consumers.js\";\nexport { setConsumer } from \"./consumers.js\";\nexport { captureException } from \"./exceptions.js\";\nexport { setRequestAttribute } from \"./requestAttributes.js\";\nexport { ApitallySpanProcessor } from \"./spanProcessor.js\";\nexport { instrument, span } from \"./tracing.js\";\n\n/** AdonisJS Ace configuration hook. */\nexport function configure(command: unknown): Promise<void> {\n return configureAdonis(command as Parameters<typeof configureAdonis>[0]);\n}\n\nexport function useApitally(app: unknown, options?: ApitallyOptions): void {\n if (isExpressApp(app)) {\n useApitallyExpress(app, options);\n } else if (isFastifyApp(app)) {\n useApitallyFastify(app, options);\n } else if (isHapiServer(app)) {\n useApitallyHapi(app, options);\n } else if (isH3App(app)) {\n useApitallyH3(app, options);\n } else if (isElysiaApp(app)) {\n installElysiaIntegration(app, options);\n } else if (isHonoApp(app)) {\n useApitallyHono(app, options);\n } else if (isKoaApp(app)) {\n useApitallyKoa(app, options);\n } else {\n throw new TypeError(\n \"useApitally() could not detect a supported framework from the app argument\",\n );\n }\n}\n\nfunction isExpressApp(app: unknown): app is Parameters<typeof useApitallyExpress>[0] {\n const candidate = app as {\n use?: unknown;\n handle?: unknown;\n };\n return (\n typeof app === \"function\" &&\n typeof candidate.use === \"function\" &&\n typeof candidate.handle === \"function\"\n );\n}\n\nfunction isFastifyApp(app: unknown): app is Parameters<typeof useApitallyFastify>[0] {\n const candidate = app as {\n version?: unknown;\n addHook?: unknown;\n register?: unknown;\n route?: unknown;\n ready?: unknown;\n close?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n typeof candidate.version === \"string\" &&\n typeof candidate.addHook === \"function\" &&\n typeof candidate.register === \"function\" &&\n typeof candidate.route === \"function\" &&\n typeof candidate.ready === \"function\" &&\n typeof candidate.close === \"function\"\n );\n}\n\nfunction isHapiServer(app: unknown): app is Parameters<typeof useApitallyHapi>[0] {\n const candidate = app as {\n ext?: unknown;\n register?: unknown;\n route?: unknown;\n table?: unknown;\n initialize?: unknown;\n start?: unknown;\n stop?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n typeof candidate.ext === \"function\" &&\n typeof candidate.register === \"function\" &&\n typeof candidate.route === \"function\" &&\n typeof candidate.table === \"function\" &&\n typeof candidate.initialize === \"function\" &&\n typeof candidate.start === \"function\" &&\n typeof candidate.stop === \"function\"\n );\n}\n\nfunction isH3App(app: unknown): app is Parameters<typeof useApitallyH3>[0] {\n const candidate = app as {\n constructor?: Record<string, unknown>;\n fetch?: unknown;\n request?: unknown;\n use?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n candidate.constructor?.[\"~h3\"] === true &&\n typeof candidate.fetch === \"function\" &&\n typeof candidate.request === \"function\" &&\n typeof candidate.use === \"function\"\n );\n}\n\nfunction isElysiaApp(app: unknown): app is Parameters<typeof installElysiaIntegration>[0] {\n const candidate = app as {\n routes?: unknown;\n handle?: unknown;\n route?: unknown;\n wrap?: unknown;\n onTransform?: unknown;\n onError?: unknown;\n };\n // Avoid reading app.fetch, as it compiles Elysia before the integration can be installed\n return (\n typeof app === \"object\" &&\n app !== null &&\n Array.isArray(candidate.routes) &&\n typeof candidate.handle === \"function\" &&\n typeof candidate.route === \"function\" &&\n typeof candidate.wrap === \"function\" &&\n typeof candidate.onTransform === \"function\" &&\n typeof candidate.onError === \"function\"\n );\n}\n\nfunction isKoaApp(app: unknown): app is Parameters<typeof useApitallyKoa>[0] {\n const candidate = app as {\n middleware?: unknown;\n use?: unknown;\n callback?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n Array.isArray(candidate.middleware) &&\n typeof candidate.use === \"function\" &&\n typeof candidate.callback === \"function\"\n );\n}\n\nfunction isHonoApp(app: unknown): app is Parameters<typeof useApitallyHono>[0] {\n const candidate = app as {\n routes?: unknown;\n fetch?: unknown;\n route?: unknown;\n };\n return (\n typeof app === \"object\" &&\n app !== null &&\n Array.isArray(candidate.routes) &&\n typeof candidate.fetch === \"function\" &&\n typeof candidate.route === \"function\"\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyBA,SAAgB,UAAU,SAAiC;CACzD,OAAOA,YAAgB,OAAgD;AACzE;AAEA,SAAgB,YAAY,KAAc,SAAiC;CACzE,IAAI,aAAa,GAAG,GAClB,cAAmB,KAAK,OAAO;MAC1B,IAAI,aAAa,GAAG,GACzB,cAAmB,KAAK,OAAO;MAC1B,IAAI,aAAa,GAAG,GACzB,cAAgB,KAAK,OAAO;MACvB,IAAI,QAAQ,GAAG,GACpB,cAAc,KAAK,OAAO;MACrB,IAAI,YAAY,GAAG,GACxB,yBAAyB,KAAK,OAAO;MAChC,IAAI,UAAU,GAAG,GACtB,cAAgB,KAAK,OAAO;MACvB,IAAI,SAAS,GAAG,GACrB,cAAe,KAAK,OAAO;MAE3B,MAAM,IAAI,UACR,4EACF;AAEJ;AAEA,SAAS,aAAa,KAA+D;CACnF,MAAM,YAAY;CAIlB,OACE,OAAO,QAAQ,cACf,OAAO,UAAU,QAAQ,cACzB,OAAO,UAAU,WAAW;AAEhC;AAEA,SAAS,aAAa,KAA+D;CACnF,MAAM,YAAY;CAQlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,OAAO,UAAU,YAAY,YAC7B,OAAO,UAAU,YAAY,cAC7B,OAAO,UAAU,aAAa,cAC9B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU;AAE/B;AAEA,SAAS,aAAa,KAA4D;CAChF,MAAM,YAAY;CASlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,OAAO,UAAU,QAAQ,cACzB,OAAO,UAAU,aAAa,cAC9B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,eAAe,cAChC,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,SAAS;AAE9B;AAEA,SAAS,QAAQ,KAA0D;CACzE,MAAM,YAAY;CAMlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,UAAU,cAAc,WAAW,QACnC,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,YAAY,cAC7B,OAAO,UAAU,QAAQ;AAE7B;AAEA,SAAS,YAAY,KAAqE;CACxF,MAAM,YAAY;CASlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,MAAM,QAAQ,UAAU,MAAM,KAC9B,OAAO,UAAU,WAAW,cAC5B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,SAAS,cAC1B,OAAO,UAAU,gBAAgB,cACjC,OAAO,UAAU,YAAY;AAEjC;AAEA,SAAS,SAAS,KAA2D;CAC3E,MAAM,YAAY;CAKlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,MAAM,QAAQ,UAAU,UAAU,KAClC,OAAO,UAAU,QAAQ,cACzB,OAAO,UAAU,aAAa;AAElC;AAEA,SAAS,UAAU,KAA4D;CAC7E,MAAM,YAAY;CAKlB,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,MAAM,QAAQ,UAAU,MAAM,KAC9B,OAAO,UAAU,UAAU,cAC3B,OAAO,UAAU,UAAU;AAE/B"}
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_packageVersion = require("../packageVersion.cjs");
3
3
  const require_context = require("../context.cjs");
4
4
  const require_exceptions = require("../exceptions.cjs");
5
+ const require_activation = require("../activation.cjs");
5
6
  const require_express_install = require("../express/install.cjs");
6
7
  const require_fastify_install = require("../fastify/install.cjs");
7
8
  let node_module = require("node:module");
@@ -21,6 +22,11 @@ function useApitally(app, options) {
21
22
  const markedInstance = adapterInstance;
22
23
  if (markedInstance[INTERCEPTOR_MARKER] !== true) {
23
24
  app.useGlobalInterceptors(createExceptionInterceptor());
25
+ const close = httpAdapter.close.bind(httpAdapter);
26
+ httpAdapter.close = async () => {
27
+ await close();
28
+ await require_activation.shutdown();
29
+ };
24
30
  markedInstance[INTERCEPTOR_MARKER] = true;
25
31
  }
26
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["resolvePackageVersion","resolvePackageEntryPath","createRequire","getRequestRecord"],"sources":["../../src/nestjs/index.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport type {\n CallHandler,\n ExecutionContext,\n INestApplication,\n NestInterceptor,\n} from \"@nestjs/common\";\nimport type { Express } from \"express\";\nimport type { FastifyInstance } from \"fastify\";\nimport type * as rxjs from \"rxjs\";\nimport type { ApitallyOptions } from \"../config.js\";\nimport { getRequestRecord } from \"../context.js\";\nimport { captureException } from \"../exceptions.js\";\nimport { installExpressIntegration } from \"../express/install.js\";\nimport { installFastifyIntegration } from \"../fastify/install.js\";\nimport { resolvePackageEntryPath, resolvePackageVersion } from \"../packageVersion.js\";\n\nexport type { ApitallyOptions };\n\nconst INTERCEPTOR_MARKER = Symbol.for(\"apitally.nestInterceptor\");\n\nexport function useApitally(app: INestApplication, options?: ApitallyOptions): void {\n const httpAdapter = app.getHttpAdapter();\n const adapterType = httpAdapter.getType();\n const adapterInstance = httpAdapter.getInstance() as object;\n const frameworkInfo = {\n framework: \"nestjs\",\n frameworkVersion: resolvePackageVersion(\"@nestjs/core\"),\n };\n\n if (adapterType === \"express\") {\n installExpressIntegration(adapterInstance as Express, options, frameworkInfo);\n } else if (adapterType === \"fastify\") {\n installFastifyIntegration(adapterInstance as FastifyInstance, options, frameworkInfo);\n } else {\n throw new TypeError(\n `Unsupported NestJS HTTP adapter ${JSON.stringify(adapterType)}. Supported adapters: express and fastify.`,\n );\n }\n\n const markedInstance = adapterInstance as Record<symbol, boolean | undefined>;\n if (markedInstance[INTERCEPTOR_MARKER] !== true) {\n app.useGlobalInterceptors(createExceptionInterceptor());\n markedInstance[INTERCEPTOR_MARKER] = true;\n }\n}\n\nfunction createExceptionInterceptor(): NestInterceptor {\n const commonEntryPath = resolvePackageEntryPath(\"@nestjs/common\");\n const { catchError, throwError } = createRequire(commonEntryPath)(\"rxjs\") as Pick<\n typeof rxjs,\n \"catchError\" | \"throwError\"\n >;\n\n return {\n intercept(executionContext: ExecutionContext, next: CallHandler) {\n if (executionContext.getType() !== \"http\") {\n return next.handle();\n }\n return next.handle().pipe(\n catchError((exception: unknown) => {\n const status = getExceptionStatus(exception);\n if (status === undefined || status >= 500) {\n captureException(exception);\n }\n const requestRecord = getRequestRecord();\n const messages = getExceptionResponseMessages(exception);\n if (requestRecord && messages) {\n requestRecord.validationErrors = messages.map((message) => ({\n source: \"\",\n field: \"\",\n message,\n type: \"\",\n }));\n }\n return throwError(() => exception);\n }),\n );\n },\n };\n}\n\nfunction getExceptionStatus(exception: unknown): number | undefined {\n if ((typeof exception !== \"object\" && typeof exception !== \"function\") || exception === null) {\n return undefined;\n }\n try {\n const candidate = exception as {\n getStatus?: () => unknown;\n status?: unknown;\n statusCode?: unknown;\n };\n if (typeof candidate.getStatus === \"function\") {\n const status = candidate.getStatus();\n return typeof status === \"number\" ? status : undefined;\n }\n if (typeof candidate.status === \"number\") {\n return candidate.status;\n }\n return typeof candidate.statusCode === \"number\" ? candidate.statusCode : undefined;\n } catch {\n return undefined;\n }\n}\n\n// The ValidationPipe throws a BadRequestException whose response carries the\n// class-validator messages as an array of strings.\nfunction getExceptionResponseMessages(exception: unknown): string[] | undefined {\n const getResponse = (exception as { getResponse?: unknown } | null)?.getResponse;\n if (typeof getResponse !== \"function\") {\n return undefined;\n }\n const response = getResponse.call(exception) as { message?: unknown } | null;\n const messages = response?.message;\n return Array.isArray(messages) && messages.every((message) => typeof message === \"string\")\n ? messages\n : undefined;\n}\n"],"mappings":";;;;;;;;AAmBA,MAAM,qBAAqB,OAAO,IAAI,0BAA0B;AAEhE,SAAgB,YAAY,KAAuB,SAAiC;CAClF,MAAM,cAAc,IAAI,eAAe;CACvC,MAAM,cAAc,YAAY,QAAQ;CACxC,MAAM,kBAAkB,YAAY,YAAY;CAChD,MAAM,gBAAgB;EACpB,WAAW;EACX,kBAAkBA,uBAAAA,sBAAsB,cAAc;CACxD;CAEA,IAAI,gBAAgB,WAClB,wBAAA,0BAA0B,iBAA4B,SAAS,aAAa;MACvE,IAAI,gBAAgB,WACzB,wBAAA,0BAA0B,iBAAoC,SAAS,aAAa;MAEpF,MAAM,IAAI,UACR,mCAAmC,KAAK,UAAU,WAAW,EAAE,2CACjE;CAGF,MAAM,iBAAiB;CACvB,IAAI,eAAe,wBAAwB,MAAM;EAC/C,IAAI,sBAAsB,2BAA2B,CAAC;EACtD,eAAe,sBAAsB;CACvC;AACF;AAEA,SAAS,6BAA8C;CACrD,MAAM,kBAAkBC,uBAAAA,wBAAwB,gBAAgB;CAChE,MAAM,EAAE,YAAY,gBAAA,GAAeC,YAAAA,cAAAA,CAAc,eAAe,CAAC,CAAC,MAAM;CAKxE,OAAO,EACL,UAAU,kBAAoC,MAAmB;EAC/D,IAAI,iBAAiB,QAAQ,MAAM,QACjC,OAAO,KAAK,OAAO;EAErB,OAAO,KAAK,OAAO,CAAC,CAAC,KACnB,YAAY,cAAuB;GACjC,MAAM,SAAS,mBAAmB,SAAS;GAC3C,IAAI,WAAW,KAAA,KAAa,UAAU,KACpC,mBAAA,iBAAiB,SAAS;GAE5B,MAAM,gBAAgBC,gBAAAA,iBAAiB;GACvC,MAAM,WAAW,6BAA6B,SAAS;GACvD,IAAI,iBAAiB,UACnB,cAAc,mBAAmB,SAAS,KAAK,aAAa;IAC1D,QAAQ;IACR,OAAO;IACP;IACA,MAAM;GACR,EAAE;GAEJ,OAAO,iBAAiB,SAAS;EACnC,CAAC,CACH;CACF,EACF;AACF;AAEA,SAAS,mBAAmB,WAAwC;CAClE,IAAK,OAAO,cAAc,YAAY,OAAO,cAAc,cAAe,cAAc,MACtF;CAEF,IAAI;EACF,MAAM,YAAY;EAKlB,IAAI,OAAO,UAAU,cAAc,YAAY;GAC7C,MAAM,SAAS,UAAU,UAAU;GACnC,OAAO,OAAO,WAAW,WAAW,SAAS,KAAA;EAC/C;EACA,IAAI,OAAO,UAAU,WAAW,UAC9B,OAAO,UAAU;EAEnB,OAAO,OAAO,UAAU,eAAe,WAAW,UAAU,aAAa,KAAA;CAC3E,QAAQ;EACN;CACF;AACF;AAIA,SAAS,6BAA6B,WAA0C;CAC9E,MAAM,cAAe,WAAgD;CACrE,IAAI,OAAO,gBAAgB,YACzB;CAGF,MAAM,WADW,YAAY,KAAK,SACV,CAAC,EAAE;CAC3B,OAAO,MAAM,QAAQ,QAAQ,KAAK,SAAS,OAAO,YAAY,OAAO,YAAY,QAAQ,IACrF,WACA,KAAA;AACN"}
1
+ {"version":3,"file":"index.cjs","names":["resolvePackageVersion","shutdown","resolvePackageEntryPath","createRequire","getRequestRecord"],"sources":["../../src/nestjs/index.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport type {\n CallHandler,\n ExecutionContext,\n INestApplication,\n NestInterceptor,\n} from \"@nestjs/common\";\nimport type { Express } from \"express\";\nimport type { FastifyInstance } from \"fastify\";\nimport type * as rxjs from \"rxjs\";\nimport { shutdown } from \"../activation.js\";\nimport type { ApitallyOptions } from \"../config.js\";\nimport { getRequestRecord } from \"../context.js\";\nimport { captureException } from \"../exceptions.js\";\nimport { installExpressIntegration } from \"../express/install.js\";\nimport { installFastifyIntegration } from \"../fastify/install.js\";\nimport { resolvePackageEntryPath, resolvePackageVersion } from \"../packageVersion.js\";\n\nexport type { ApitallyOptions };\n\nconst INTERCEPTOR_MARKER = Symbol.for(\"apitally.nestInterceptor\");\n\nexport function useApitally(app: INestApplication, options?: ApitallyOptions): void {\n const httpAdapter = app.getHttpAdapter();\n const adapterType = httpAdapter.getType();\n const adapterInstance = httpAdapter.getInstance() as object;\n const frameworkInfo = {\n framework: \"nestjs\",\n frameworkVersion: resolvePackageVersion(\"@nestjs/core\"),\n };\n\n if (adapterType === \"express\") {\n installExpressIntegration(adapterInstance as Express, options, frameworkInfo);\n } else if (adapterType === \"fastify\") {\n installFastifyIntegration(adapterInstance as FastifyInstance, options, frameworkInfo);\n } else {\n throw new TypeError(\n `Unsupported NestJS HTTP adapter ${JSON.stringify(adapterType)}. Supported adapters: express and fastify.`,\n );\n }\n\n const markedInstance = adapterInstance as Record<symbol, boolean | undefined>;\n if (markedInstance[INTERCEPTOR_MARKER] !== true) {\n app.useGlobalInterceptors(createExceptionInterceptor());\n // Nest awaits adapter.close() before terminating the process on a shutdown signal.\n const close = httpAdapter.close.bind(httpAdapter);\n httpAdapter.close = async () => {\n await close();\n await shutdown();\n };\n markedInstance[INTERCEPTOR_MARKER] = true;\n }\n}\n\nfunction createExceptionInterceptor(): NestInterceptor {\n const commonEntryPath = resolvePackageEntryPath(\"@nestjs/common\");\n const { catchError, throwError } = createRequire(commonEntryPath)(\"rxjs\") as Pick<\n typeof rxjs,\n \"catchError\" | \"throwError\"\n >;\n\n return {\n intercept(executionContext: ExecutionContext, next: CallHandler) {\n if (executionContext.getType() !== \"http\") {\n return next.handle();\n }\n return next.handle().pipe(\n catchError((exception: unknown) => {\n const status = getExceptionStatus(exception);\n if (status === undefined || status >= 500) {\n captureException(exception);\n }\n const requestRecord = getRequestRecord();\n const messages = getExceptionResponseMessages(exception);\n if (requestRecord && messages) {\n requestRecord.validationErrors = messages.map((message) => ({\n source: \"\",\n field: \"\",\n message,\n type: \"\",\n }));\n }\n return throwError(() => exception);\n }),\n );\n },\n };\n}\n\nfunction getExceptionStatus(exception: unknown): number | undefined {\n if ((typeof exception !== \"object\" && typeof exception !== \"function\") || exception === null) {\n return undefined;\n }\n try {\n const candidate = exception as {\n getStatus?: () => unknown;\n status?: unknown;\n statusCode?: unknown;\n };\n if (typeof candidate.getStatus === \"function\") {\n const status = candidate.getStatus();\n return typeof status === \"number\" ? status : undefined;\n }\n if (typeof candidate.status === \"number\") {\n return candidate.status;\n }\n return typeof candidate.statusCode === \"number\" ? candidate.statusCode : undefined;\n } catch {\n return undefined;\n }\n}\n\n// The ValidationPipe throws a BadRequestException whose response carries the\n// class-validator messages as an array of strings.\nfunction getExceptionResponseMessages(exception: unknown): string[] | undefined {\n const getResponse = (exception as { getResponse?: unknown } | null)?.getResponse;\n if (typeof getResponse !== \"function\") {\n return undefined;\n }\n const response = getResponse.call(exception) as { message?: unknown } | null;\n const messages = response?.message;\n return Array.isArray(messages) && messages.every((message) => typeof message === \"string\")\n ? messages\n : undefined;\n}\n"],"mappings":";;;;;;;;;AAoBA,MAAM,qBAAqB,OAAO,IAAI,0BAA0B;AAEhE,SAAgB,YAAY,KAAuB,SAAiC;CAClF,MAAM,cAAc,IAAI,eAAe;CACvC,MAAM,cAAc,YAAY,QAAQ;CACxC,MAAM,kBAAkB,YAAY,YAAY;CAChD,MAAM,gBAAgB;EACpB,WAAW;EACX,kBAAkBA,uBAAAA,sBAAsB,cAAc;CACxD;CAEA,IAAI,gBAAgB,WAClB,wBAAA,0BAA0B,iBAA4B,SAAS,aAAa;MACvE,IAAI,gBAAgB,WACzB,wBAAA,0BAA0B,iBAAoC,SAAS,aAAa;MAEpF,MAAM,IAAI,UACR,mCAAmC,KAAK,UAAU,WAAW,EAAE,2CACjE;CAGF,MAAM,iBAAiB;CACvB,IAAI,eAAe,wBAAwB,MAAM;EAC/C,IAAI,sBAAsB,2BAA2B,CAAC;EAEtD,MAAM,QAAQ,YAAY,MAAM,KAAK,WAAW;EAChD,YAAY,QAAQ,YAAY;GAC9B,MAAM,MAAM;GACZ,MAAMC,mBAAAA,SAAS;EACjB;EACA,eAAe,sBAAsB;CACvC;AACF;AAEA,SAAS,6BAA8C;CACrD,MAAM,kBAAkBC,uBAAAA,wBAAwB,gBAAgB;CAChE,MAAM,EAAE,YAAY,gBAAA,GAAeC,YAAAA,cAAAA,CAAc,eAAe,CAAC,CAAC,MAAM;CAKxE,OAAO,EACL,UAAU,kBAAoC,MAAmB;EAC/D,IAAI,iBAAiB,QAAQ,MAAM,QACjC,OAAO,KAAK,OAAO;EAErB,OAAO,KAAK,OAAO,CAAC,CAAC,KACnB,YAAY,cAAuB;GACjC,MAAM,SAAS,mBAAmB,SAAS;GAC3C,IAAI,WAAW,KAAA,KAAa,UAAU,KACpC,mBAAA,iBAAiB,SAAS;GAE5B,MAAM,gBAAgBC,gBAAAA,iBAAiB;GACvC,MAAM,WAAW,6BAA6B,SAAS;GACvD,IAAI,iBAAiB,UACnB,cAAc,mBAAmB,SAAS,KAAK,aAAa;IAC1D,QAAQ;IACR,OAAO;IACP;IACA,MAAM;GACR,EAAE;GAEJ,OAAO,iBAAiB,SAAS;EACnC,CAAC,CACH;CACF,EACF;AACF;AAEA,SAAS,mBAAmB,WAAwC;CAClE,IAAK,OAAO,cAAc,YAAY,OAAO,cAAc,cAAe,cAAc,MACtF;CAEF,IAAI;EACF,MAAM,YAAY;EAKlB,IAAI,OAAO,UAAU,cAAc,YAAY;GAC7C,MAAM,SAAS,UAAU,UAAU;GACnC,OAAO,OAAO,WAAW,WAAW,SAAS,KAAA;EAC/C;EACA,IAAI,OAAO,UAAU,WAAW,UAC9B,OAAO,UAAU;EAEnB,OAAO,OAAO,UAAU,eAAe,WAAW,UAAU,aAAa,KAAA;CAC3E,QAAQ;EACN;CACF;AACF;AAIA,SAAS,6BAA6B,WAA0C;CAC9E,MAAM,cAAe,WAAgD;CACrE,IAAI,OAAO,gBAAgB,YACzB;CAGF,MAAM,WADW,YAAY,KAAK,SACV,CAAC,EAAE;CAC3B,OAAO,MAAM,QAAQ,QAAQ,KAAK,SAAS,OAAO,YAAY,OAAO,YAAY,QAAQ,IACrF,WACA,KAAA;AACN"}
@@ -1,6 +1,7 @@
1
1
  import { resolvePackageEntryPath, resolvePackageVersion } from "../packageVersion.js";
2
2
  import { getRequestRecord } from "../context.js";
3
3
  import { captureException } from "../exceptions.js";
4
+ import { shutdown } from "../activation.js";
4
5
  import { installExpressIntegration } from "../express/install.js";
5
6
  import { installFastifyIntegration } from "../fastify/install.js";
6
7
  import { createRequire } from "node:module";
@@ -20,6 +21,11 @@ function useApitally(app, options) {
20
21
  const markedInstance = adapterInstance;
21
22
  if (markedInstance[INTERCEPTOR_MARKER] !== true) {
22
23
  app.useGlobalInterceptors(createExceptionInterceptor());
24
+ const close = httpAdapter.close.bind(httpAdapter);
25
+ httpAdapter.close = async () => {
26
+ await close();
27
+ await shutdown();
28
+ };
23
29
  markedInstance[INTERCEPTOR_MARKER] = true;
24
30
  }
25
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/nestjs/index.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport type {\n CallHandler,\n ExecutionContext,\n INestApplication,\n NestInterceptor,\n} from \"@nestjs/common\";\nimport type { Express } from \"express\";\nimport type { FastifyInstance } from \"fastify\";\nimport type * as rxjs from \"rxjs\";\nimport type { ApitallyOptions } from \"../config.js\";\nimport { getRequestRecord } from \"../context.js\";\nimport { captureException } from \"../exceptions.js\";\nimport { installExpressIntegration } from \"../express/install.js\";\nimport { installFastifyIntegration } from \"../fastify/install.js\";\nimport { resolvePackageEntryPath, resolvePackageVersion } from \"../packageVersion.js\";\n\nexport type { ApitallyOptions };\n\nconst INTERCEPTOR_MARKER = Symbol.for(\"apitally.nestInterceptor\");\n\nexport function useApitally(app: INestApplication, options?: ApitallyOptions): void {\n const httpAdapter = app.getHttpAdapter();\n const adapterType = httpAdapter.getType();\n const adapterInstance = httpAdapter.getInstance() as object;\n const frameworkInfo = {\n framework: \"nestjs\",\n frameworkVersion: resolvePackageVersion(\"@nestjs/core\"),\n };\n\n if (adapterType === \"express\") {\n installExpressIntegration(adapterInstance as Express, options, frameworkInfo);\n } else if (adapterType === \"fastify\") {\n installFastifyIntegration(adapterInstance as FastifyInstance, options, frameworkInfo);\n } else {\n throw new TypeError(\n `Unsupported NestJS HTTP adapter ${JSON.stringify(adapterType)}. Supported adapters: express and fastify.`,\n );\n }\n\n const markedInstance = adapterInstance as Record<symbol, boolean | undefined>;\n if (markedInstance[INTERCEPTOR_MARKER] !== true) {\n app.useGlobalInterceptors(createExceptionInterceptor());\n markedInstance[INTERCEPTOR_MARKER] = true;\n }\n}\n\nfunction createExceptionInterceptor(): NestInterceptor {\n const commonEntryPath = resolvePackageEntryPath(\"@nestjs/common\");\n const { catchError, throwError } = createRequire(commonEntryPath)(\"rxjs\") as Pick<\n typeof rxjs,\n \"catchError\" | \"throwError\"\n >;\n\n return {\n intercept(executionContext: ExecutionContext, next: CallHandler) {\n if (executionContext.getType() !== \"http\") {\n return next.handle();\n }\n return next.handle().pipe(\n catchError((exception: unknown) => {\n const status = getExceptionStatus(exception);\n if (status === undefined || status >= 500) {\n captureException(exception);\n }\n const requestRecord = getRequestRecord();\n const messages = getExceptionResponseMessages(exception);\n if (requestRecord && messages) {\n requestRecord.validationErrors = messages.map((message) => ({\n source: \"\",\n field: \"\",\n message,\n type: \"\",\n }));\n }\n return throwError(() => exception);\n }),\n );\n },\n };\n}\n\nfunction getExceptionStatus(exception: unknown): number | undefined {\n if ((typeof exception !== \"object\" && typeof exception !== \"function\") || exception === null) {\n return undefined;\n }\n try {\n const candidate = exception as {\n getStatus?: () => unknown;\n status?: unknown;\n statusCode?: unknown;\n };\n if (typeof candidate.getStatus === \"function\") {\n const status = candidate.getStatus();\n return typeof status === \"number\" ? status : undefined;\n }\n if (typeof candidate.status === \"number\") {\n return candidate.status;\n }\n return typeof candidate.statusCode === \"number\" ? candidate.statusCode : undefined;\n } catch {\n return undefined;\n }\n}\n\n// The ValidationPipe throws a BadRequestException whose response carries the\n// class-validator messages as an array of strings.\nfunction getExceptionResponseMessages(exception: unknown): string[] | undefined {\n const getResponse = (exception as { getResponse?: unknown } | null)?.getResponse;\n if (typeof getResponse !== \"function\") {\n return undefined;\n }\n const response = getResponse.call(exception) as { message?: unknown } | null;\n const messages = response?.message;\n return Array.isArray(messages) && messages.every((message) => typeof message === \"string\")\n ? messages\n : undefined;\n}\n"],"mappings":";;;;;;;AAmBA,MAAM,qBAAqB,OAAO,IAAI,0BAA0B;AAEhE,SAAgB,YAAY,KAAuB,SAAiC;CAClF,MAAM,cAAc,IAAI,eAAe;CACvC,MAAM,cAAc,YAAY,QAAQ;CACxC,MAAM,kBAAkB,YAAY,YAAY;CAChD,MAAM,gBAAgB;EACpB,WAAW;EACX,kBAAkB,sBAAsB,cAAc;CACxD;CAEA,IAAI,gBAAgB,WAClB,0BAA0B,iBAA4B,SAAS,aAAa;MACvE,IAAI,gBAAgB,WACzB,0BAA0B,iBAAoC,SAAS,aAAa;MAEpF,MAAM,IAAI,UACR,mCAAmC,KAAK,UAAU,WAAW,EAAE,2CACjE;CAGF,MAAM,iBAAiB;CACvB,IAAI,eAAe,wBAAwB,MAAM;EAC/C,IAAI,sBAAsB,2BAA2B,CAAC;EACtD,eAAe,sBAAsB;CACvC;AACF;AAEA,SAAS,6BAA8C;CACrD,MAAM,kBAAkB,wBAAwB,gBAAgB;CAChE,MAAM,EAAE,YAAY,eAAe,cAAc,eAAe,CAAC,CAAC,MAAM;CAKxE,OAAO,EACL,UAAU,kBAAoC,MAAmB;EAC/D,IAAI,iBAAiB,QAAQ,MAAM,QACjC,OAAO,KAAK,OAAO;EAErB,OAAO,KAAK,OAAO,CAAC,CAAC,KACnB,YAAY,cAAuB;GACjC,MAAM,SAAS,mBAAmB,SAAS;GAC3C,IAAI,WAAW,KAAA,KAAa,UAAU,KACpC,iBAAiB,SAAS;GAE5B,MAAM,gBAAgB,iBAAiB;GACvC,MAAM,WAAW,6BAA6B,SAAS;GACvD,IAAI,iBAAiB,UACnB,cAAc,mBAAmB,SAAS,KAAK,aAAa;IAC1D,QAAQ;IACR,OAAO;IACP;IACA,MAAM;GACR,EAAE;GAEJ,OAAO,iBAAiB,SAAS;EACnC,CAAC,CACH;CACF,EACF;AACF;AAEA,SAAS,mBAAmB,WAAwC;CAClE,IAAK,OAAO,cAAc,YAAY,OAAO,cAAc,cAAe,cAAc,MACtF;CAEF,IAAI;EACF,MAAM,YAAY;EAKlB,IAAI,OAAO,UAAU,cAAc,YAAY;GAC7C,MAAM,SAAS,UAAU,UAAU;GACnC,OAAO,OAAO,WAAW,WAAW,SAAS,KAAA;EAC/C;EACA,IAAI,OAAO,UAAU,WAAW,UAC9B,OAAO,UAAU;EAEnB,OAAO,OAAO,UAAU,eAAe,WAAW,UAAU,aAAa,KAAA;CAC3E,QAAQ;EACN;CACF;AACF;AAIA,SAAS,6BAA6B,WAA0C;CAC9E,MAAM,cAAe,WAAgD;CACrE,IAAI,OAAO,gBAAgB,YACzB;CAGF,MAAM,WADW,YAAY,KAAK,SACV,CAAC,EAAE;CAC3B,OAAO,MAAM,QAAQ,QAAQ,KAAK,SAAS,OAAO,YAAY,OAAO,YAAY,QAAQ,IACrF,WACA,KAAA;AACN"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/nestjs/index.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport type {\n CallHandler,\n ExecutionContext,\n INestApplication,\n NestInterceptor,\n} from \"@nestjs/common\";\nimport type { Express } from \"express\";\nimport type { FastifyInstance } from \"fastify\";\nimport type * as rxjs from \"rxjs\";\nimport { shutdown } from \"../activation.js\";\nimport type { ApitallyOptions } from \"../config.js\";\nimport { getRequestRecord } from \"../context.js\";\nimport { captureException } from \"../exceptions.js\";\nimport { installExpressIntegration } from \"../express/install.js\";\nimport { installFastifyIntegration } from \"../fastify/install.js\";\nimport { resolvePackageEntryPath, resolvePackageVersion } from \"../packageVersion.js\";\n\nexport type { ApitallyOptions };\n\nconst INTERCEPTOR_MARKER = Symbol.for(\"apitally.nestInterceptor\");\n\nexport function useApitally(app: INestApplication, options?: ApitallyOptions): void {\n const httpAdapter = app.getHttpAdapter();\n const adapterType = httpAdapter.getType();\n const adapterInstance = httpAdapter.getInstance() as object;\n const frameworkInfo = {\n framework: \"nestjs\",\n frameworkVersion: resolvePackageVersion(\"@nestjs/core\"),\n };\n\n if (adapterType === \"express\") {\n installExpressIntegration(adapterInstance as Express, options, frameworkInfo);\n } else if (adapterType === \"fastify\") {\n installFastifyIntegration(adapterInstance as FastifyInstance, options, frameworkInfo);\n } else {\n throw new TypeError(\n `Unsupported NestJS HTTP adapter ${JSON.stringify(adapterType)}. Supported adapters: express and fastify.`,\n );\n }\n\n const markedInstance = adapterInstance as Record<symbol, boolean | undefined>;\n if (markedInstance[INTERCEPTOR_MARKER] !== true) {\n app.useGlobalInterceptors(createExceptionInterceptor());\n // Nest awaits adapter.close() before terminating the process on a shutdown signal.\n const close = httpAdapter.close.bind(httpAdapter);\n httpAdapter.close = async () => {\n await close();\n await shutdown();\n };\n markedInstance[INTERCEPTOR_MARKER] = true;\n }\n}\n\nfunction createExceptionInterceptor(): NestInterceptor {\n const commonEntryPath = resolvePackageEntryPath(\"@nestjs/common\");\n const { catchError, throwError } = createRequire(commonEntryPath)(\"rxjs\") as Pick<\n typeof rxjs,\n \"catchError\" | \"throwError\"\n >;\n\n return {\n intercept(executionContext: ExecutionContext, next: CallHandler) {\n if (executionContext.getType() !== \"http\") {\n return next.handle();\n }\n return next.handle().pipe(\n catchError((exception: unknown) => {\n const status = getExceptionStatus(exception);\n if (status === undefined || status >= 500) {\n captureException(exception);\n }\n const requestRecord = getRequestRecord();\n const messages = getExceptionResponseMessages(exception);\n if (requestRecord && messages) {\n requestRecord.validationErrors = messages.map((message) => ({\n source: \"\",\n field: \"\",\n message,\n type: \"\",\n }));\n }\n return throwError(() => exception);\n }),\n );\n },\n };\n}\n\nfunction getExceptionStatus(exception: unknown): number | undefined {\n if ((typeof exception !== \"object\" && typeof exception !== \"function\") || exception === null) {\n return undefined;\n }\n try {\n const candidate = exception as {\n getStatus?: () => unknown;\n status?: unknown;\n statusCode?: unknown;\n };\n if (typeof candidate.getStatus === \"function\") {\n const status = candidate.getStatus();\n return typeof status === \"number\" ? status : undefined;\n }\n if (typeof candidate.status === \"number\") {\n return candidate.status;\n }\n return typeof candidate.statusCode === \"number\" ? candidate.statusCode : undefined;\n } catch {\n return undefined;\n }\n}\n\n// The ValidationPipe throws a BadRequestException whose response carries the\n// class-validator messages as an array of strings.\nfunction getExceptionResponseMessages(exception: unknown): string[] | undefined {\n const getResponse = (exception as { getResponse?: unknown } | null)?.getResponse;\n if (typeof getResponse !== \"function\") {\n return undefined;\n }\n const response = getResponse.call(exception) as { message?: unknown } | null;\n const messages = response?.message;\n return Array.isArray(messages) && messages.every((message) => typeof message === \"string\")\n ? messages\n : undefined;\n}\n"],"mappings":";;;;;;;;AAoBA,MAAM,qBAAqB,OAAO,IAAI,0BAA0B;AAEhE,SAAgB,YAAY,KAAuB,SAAiC;CAClF,MAAM,cAAc,IAAI,eAAe;CACvC,MAAM,cAAc,YAAY,QAAQ;CACxC,MAAM,kBAAkB,YAAY,YAAY;CAChD,MAAM,gBAAgB;EACpB,WAAW;EACX,kBAAkB,sBAAsB,cAAc;CACxD;CAEA,IAAI,gBAAgB,WAClB,0BAA0B,iBAA4B,SAAS,aAAa;MACvE,IAAI,gBAAgB,WACzB,0BAA0B,iBAAoC,SAAS,aAAa;MAEpF,MAAM,IAAI,UACR,mCAAmC,KAAK,UAAU,WAAW,EAAE,2CACjE;CAGF,MAAM,iBAAiB;CACvB,IAAI,eAAe,wBAAwB,MAAM;EAC/C,IAAI,sBAAsB,2BAA2B,CAAC;EAEtD,MAAM,QAAQ,YAAY,MAAM,KAAK,WAAW;EAChD,YAAY,QAAQ,YAAY;GAC9B,MAAM,MAAM;GACZ,MAAM,SAAS;EACjB;EACA,eAAe,sBAAsB;CACvC;AACF;AAEA,SAAS,6BAA8C;CACrD,MAAM,kBAAkB,wBAAwB,gBAAgB;CAChE,MAAM,EAAE,YAAY,eAAe,cAAc,eAAe,CAAC,CAAC,MAAM;CAKxE,OAAO,EACL,UAAU,kBAAoC,MAAmB;EAC/D,IAAI,iBAAiB,QAAQ,MAAM,QACjC,OAAO,KAAK,OAAO;EAErB,OAAO,KAAK,OAAO,CAAC,CAAC,KACnB,YAAY,cAAuB;GACjC,MAAM,SAAS,mBAAmB,SAAS;GAC3C,IAAI,WAAW,KAAA,KAAa,UAAU,KACpC,iBAAiB,SAAS;GAE5B,MAAM,gBAAgB,iBAAiB;GACvC,MAAM,WAAW,6BAA6B,SAAS;GACvD,IAAI,iBAAiB,UACnB,cAAc,mBAAmB,SAAS,KAAK,aAAa;IAC1D,QAAQ;IACR,OAAO;IACP;IACA,MAAM;GACR,EAAE;GAEJ,OAAO,iBAAiB,SAAS;EACnC,CAAC,CACH;CACF,EACF;AACF;AAEA,SAAS,mBAAmB,WAAwC;CAClE,IAAK,OAAO,cAAc,YAAY,OAAO,cAAc,cAAe,cAAc,MACtF;CAEF,IAAI;EACF,MAAM,YAAY;EAKlB,IAAI,OAAO,UAAU,cAAc,YAAY;GAC7C,MAAM,SAAS,UAAU,UAAU;GACnC,OAAO,OAAO,WAAW,WAAW,SAAS,KAAA;EAC/C;EACA,IAAI,OAAO,UAAU,WAAW,UAC9B,OAAO,UAAU;EAEnB,OAAO,OAAO,UAAU,eAAe,WAAW,UAAU,aAAa,KAAA;CAC3E,QAAQ;EACN;CACF;AACF;AAIA,SAAS,6BAA6B,WAA0C;CAC9E,MAAM,cAAe,WAAgD;CACrE,IAAI,OAAO,gBAAgB,YACzB;CAGF,MAAM,WADW,YAAY,KAAK,SACV,CAAC,EAAE;CAC3B,OAAO,MAAM,QAAQ,QAAQ,KAAK,SAAS,OAAO,YAAY,OAAO,YAAY,QAAQ,IACrF,WACA,KAAA;AACN"}
@@ -7,6 +7,7 @@ const require_exceptions = require("./exceptions.cjs");
7
7
  const require_serverErrors = require("./serverErrors.cjs");
8
8
  const require_spanProcessor = require("./spanProcessor.cjs");
9
9
  const require_validationErrors = require("./validationErrors.cjs");
10
+ const require_consumers = require("./consumers.cjs");
10
11
  let _opentelemetry_api = require("@opentelemetry/api");
11
12
  let _opentelemetry_core = require("@opentelemetry/core");
12
13
  //#region src/requestObservation.ts
@@ -29,7 +30,6 @@ function startRequestObservation(options) {
29
30
  const { activeContext, extractedContext, tracerName, method, startAttributes, requestBodyCapture } = options;
30
31
  const requestRecord = { attributes: {} };
31
32
  const spanHandle = {};
32
- const consumerHolder = require_context.getConsumerHolder(activeContext) ?? {};
33
33
  Object.assign(requestRecord.attributes, startAttributes);
34
34
  const activeSpan = _opentelemetry_api.trace.getSpan(activeContext);
35
35
  const resolveUnavailableSpanDropReason = () => require_spanProcessor.getActiveSpanPipeline()?.resolveRequestDropReasonBeforeSampling(startAttributes) ?? "sampled-out";
@@ -39,13 +39,13 @@ function startRequestObservation(options) {
39
39
  requestRecord.serverSpanId = activeSpan.spanContext().spanId;
40
40
  require_spanProcessor.getActiveSpanPipeline()?.attachRequestRecord(requestRecord.serverSpanId, requestRecord);
41
41
  if (require_spanProcessor.getActiveSpanPipeline()?.isRequestInFlight(requestRecord.serverSpanId) !== true) requestRecord.dropReason = resolveUnavailableSpanDropReason();
42
- requestContext = require_context.withRequestHolders(activeContext, spanHandle, requestRecord, consumerHolder);
42
+ requestContext = require_context.withRequestHolders(activeContext, spanHandle, requestRecord);
43
43
  } else if (activeSpan && !activeSpan.isRecording() && !activeSpan.spanContext().isRemote) {
44
44
  requestRecord.dropReason = resolveUnavailableSpanDropReason();
45
45
  if (requestRecord.dropReason === "sampled-out") warnAboutNonRecordingServerSpan();
46
- requestContext = require_context.withRequestHolders(activeContext, spanHandle, requestRecord, consumerHolder);
46
+ requestContext = require_context.withRequestHolders(activeContext, spanHandle, requestRecord);
47
47
  } else {
48
- requestContext = require_context.withRequestHolders(extractedContext, spanHandle, requestRecord, consumerHolder);
48
+ requestContext = require_context.withRequestHolders(extractedContext, spanHandle, requestRecord);
49
49
  const ownSpan = _opentelemetry_api.trace.getTracer(tracerName).startSpan(method, {
50
50
  kind: _opentelemetry_api.SpanKind.SERVER,
51
51
  attributes: startAttributes
@@ -122,6 +122,7 @@ function finalizeRequestObservation(options) {
122
122
  if (Object.keys(stash).length > 0) require_spanProcessor.getActiveSpanPipeline()?.updateStash(requestRecord.serverSpanId, stash);
123
123
  }
124
124
  ownSpan?.end(options.completedAtMillis);
125
+ require_consumers.emitConsumerUpdateIfChanged(requestRecord);
125
126
  require_spanProcessor.getActiveSpanPipeline()?.handleTransportCompletion(requestRecord);
126
127
  }
127
128
  function finalizeRequestObservationWithError(options) {
@@ -132,6 +133,7 @@ function finalizeRequestObservationWithError(options) {
132
133
  spanHandle.ownSpan.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
133
134
  spanHandle.ownSpan.end();
134
135
  }
136
+ require_consumers.emitConsumerUpdateIfChanged(requestRecord);
135
137
  require_spanProcessor.getActiveSpanPipeline()?.handleTransportCompletion(requestRecord);
136
138
  }
137
139
  function getHeaderValue(headers, name) {
@@ -1 +1 @@
1
- {"version":3,"file":"requestObservation.cjs","names":["getConsumerHolder","trace","getActiveSpanPipeline","SpanKind","withRequestHolders","isApitallySpanProcessorDeclared","getRPCMetadata","RPCType","setRPCMetadata","SpanStatusCode","isValidationResponseStatus","getConfig","coerceToException"],"sources":["../src/requestObservation.ts"],"sourcesContent":["import { type Attributes, type Context, SpanKind, SpanStatusCode, trace } from \"@opentelemetry/api\";\nimport { getRPCMetadata, type RPCMetadata, RPCType, setRPCMetadata } from \"@opentelemetry/core\";\nimport type { BodyCapture, CapturedBody } from \"./bodyCapture.js\";\nimport { getConfig } from \"./config.js\";\nimport {\n attachRequestRecordToRpcMetadata,\n getConsumerHolder,\n type RequestRecord,\n type SpanHandle,\n withRequestHolders,\n} from \"./context.js\";\nimport { coerceToException } from \"./exceptions.js\";\nimport { logWarning } from \"./logger.js\";\nimport { writeRequestAttribute } from \"./requestAttributes.js\";\nimport { addServerError } from \"./serverErrors.js\";\nimport {\n getActiveSpanPipeline,\n isApitallySpanProcessorDeclared,\n type RequestStash,\n} from \"./spanProcessor.js\";\nimport { addValidationErrors, isValidationResponseStatus } from \"./validationErrors.js\";\n\ninterface StartRequestObservationOptions {\n activeContext: Context;\n extractedContext: Context;\n tracerName: string;\n method: string;\n startAttributes: Attributes;\n requestBodyCapture: BodyCapture;\n}\n\nexport interface StartedRequestObservation {\n requestRecord: RequestRecord;\n requestContext: Context;\n spanHandle: SpanHandle;\n rpcMetadata?: RPCMetadata;\n}\n\nexport interface HttpRequestStartAttributeInput {\n method: string;\n path?: string;\n query?: string;\n scheme?: string;\n serverAddress?: string;\n fullUrl?: string;\n clientAddress?: string;\n userAgent?: string;\n requestBodySize?: number;\n}\n\nexport function resolveHttpRequestStartAttributes(\n input: HttpRequestStartAttributeInput,\n): Attributes {\n const attributes: Attributes = { \"http.request.method\": input.method };\n const optionalAttributes: [string, string | number | undefined][] = [\n [\"url.path\", input.path],\n [\"url.query\", input.query],\n [\"url.scheme\", input.scheme],\n [\"url.full\", input.fullUrl],\n [\"server.address\", input.serverAddress],\n [\"client.address\", input.clientAddress],\n [\"user_agent.original\", input.userAgent],\n [\"http.request.body.size\", input.requestBodySize],\n ];\n for (const [name, value] of optionalAttributes) {\n if (value !== undefined) {\n attributes[name] = value;\n }\n }\n return attributes;\n}\n\nexport function startRequestObservation(\n options: StartRequestObservationOptions,\n): StartedRequestObservation {\n const {\n activeContext,\n extractedContext,\n tracerName,\n method,\n startAttributes,\n requestBodyCapture,\n } = options;\n const requestRecord: RequestRecord = { attributes: {} };\n const spanHandle: SpanHandle = {};\n const consumerHolder = getConsumerHolder(activeContext) ?? {};\n // Metrics and the exported span copy read from the request record, so the\n // start attributes are mirrored into it on every path, span or no span.\n Object.assign(requestRecord.attributes, startAttributes);\n const activeSpan = trace.getSpan(activeContext);\n const resolveUnavailableSpanDropReason = (): RequestRecord[\"dropReason\"] =>\n getActiveSpanPipeline()?.resolveRequestDropReasonBeforeSampling(startAttributes) ??\n \"sampled-out\";\n let requestContext: Context;\n // Span kind is not part of the OTel API surface, so read the SDK-level\n // property from whichever package copy produced the span.\n if (activeSpan?.isRecording() && (activeSpan as { kind?: unknown }).kind === SpanKind.SERVER) {\n // A SERVER span produced by the user's own instrumentation is adopted:\n // no second span, and the request runs under the user's context.\n spanHandle.span = activeSpan;\n requestRecord.serverSpanId = activeSpan.spanContext().spanId;\n getActiveSpanPipeline()?.attachRequestRecord(requestRecord.serverSpanId, requestRecord);\n if (getActiveSpanPipeline()?.isRequestInFlight(requestRecord.serverSpanId) !== true) {\n requestRecord.dropReason = resolveUnavailableSpanDropReason();\n }\n requestContext = withRequestHolders(activeContext, spanHandle, requestRecord, consumerHolder);\n } else if (activeSpan && !activeSpan.isRecording() && !activeSpan.spanContext().isRemote) {\n requestRecord.dropReason = resolveUnavailableSpanDropReason();\n if (requestRecord.dropReason === \"sampled-out\") {\n warnAboutNonRecordingServerSpan();\n }\n requestContext = withRequestHolders(activeContext, spanHandle, requestRecord, consumerHolder);\n } else {\n requestContext = withRequestHolders(\n extractedContext,\n spanHandle,\n requestRecord,\n consumerHolder,\n );\n const ownSpan = trace\n .getTracer(tracerName)\n .startSpan(method, { kind: SpanKind.SERVER, attributes: startAttributes }, requestContext);\n if (!ownSpan.isRecording()) {\n requestRecord.dropReason = resolveUnavailableSpanDropReason();\n if (requestRecord.dropReason === \"sampled-out\") {\n warnAboutNonRecordingServerSpan();\n }\n } else {\n spanHandle.span = ownSpan;\n spanHandle.ownSpan = ownSpan;\n if (isApitallySpanProcessorDeclared() && requestRecord.serverSpanId === undefined) {\n requestRecord.dropReason = resolveUnavailableSpanDropReason();\n if (requestRecord.dropReason === \"sampled-out\") {\n warnAboutUnattachedSpanProcessor();\n }\n }\n }\n // A non-recording span still carries a valid span context, so user child\n // spans parent to it and parent-based samplers drop them consistently.\n requestContext = trace.setSpan(requestContext, ownSpan);\n }\n\n // Middleware-based span producers inspect OTel RPC metadata to demote duplicate\n // transport spans; completion adds the route.\n let rpcMetadata = getRPCMetadata(requestContext);\n if (!rpcMetadata && spanHandle.span) {\n rpcMetadata = { type: RPCType.HTTP, span: spanHandle.span };\n requestContext = setRPCMetadata(requestContext, rpcMetadata);\n }\n attachRequestRecordToRpcMetadata(rpcMetadata, requestRecord);\n if (requestRecord.dropReason !== undefined) {\n requestBodyCapture.stopBuffering();\n }\n return { requestRecord, requestContext, spanHandle, rpcMetadata };\n}\n\nexport interface RequestObservation {\n requestRecord: RequestRecord;\n spanHandle: SpanHandle;\n rpcMetadata?: RPCMetadata;\n method: string;\n startTimeMillis: number;\n}\n\nexport interface FinalizeRequestObservationOptions {\n observation: RequestObservation;\n completedAtMillis: number;\n statusCode: number;\n route?: string;\n clientAddress?: string;\n requestHeaders: Headers | Record<string, string | string[] | undefined>;\n responseHeaders: Headers | Record<string, string | number | string[] | undefined>;\n capturedRequestBody?: CapturedBody;\n capturedResponseBody?: CapturedBody;\n}\n\nexport function finalizeRequestObservation(options: FinalizeRequestObservationOptions): void {\n const { observation, statusCode, route } = options;\n const { requestRecord, spanHandle, rpcMetadata, method } = observation;\n requestRecord.durationSeconds = (options.completedAtMillis - observation.startTimeMillis) / 1000;\n const { span, ownSpan } = spanHandle;\n if (options.clientAddress !== undefined) {\n writeRequestAttribute(span, requestRecord, \"client.address\", options.clientAddress);\n }\n writeRequestAttribute(span, requestRecord, \"http.response.status_code\", statusCode);\n const requestBodySize = options.capturedRequestBody?.size;\n if (requestBodySize !== undefined) {\n writeRequestAttribute(span, requestRecord, \"http.request.body.size\", requestBodySize);\n }\n const responseBodySize = options.capturedResponseBody?.size;\n if (responseBodySize !== undefined) {\n writeRequestAttribute(span, requestRecord, \"http.response.body.size\", responseBodySize);\n }\n if (route !== undefined) {\n writeRequestAttribute(span, requestRecord, \"http.route\", route);\n if (rpcMetadata) {\n rpcMetadata.route = route;\n }\n if (ownSpan?.isRecording()) {\n ownSpan.updateName(`${method} ${route}`);\n }\n } else {\n // An empty route clears one set by the producing instrumentation; request\n // metrics omit empty routes.\n requestRecord.attributes[\"http.route\"] = \"\";\n }\n if (ownSpan && statusCode >= 500) {\n ownSpan.setStatus({ code: SpanStatusCode.ERROR });\n }\n // Validation and server errors are counted for every routed request,\n // including requests dropped from tracing.\n const consumer = requestRecord.attributes[\"apitally.consumer.identifier\"];\n const consumerIdentifier = typeof consumer === \"string\" ? consumer : undefined;\n if (requestRecord.validationErrors && isValidationResponseStatus(statusCode)) {\n addValidationErrors(consumerIdentifier, method, route ?? \"\", requestRecord.validationErrors);\n }\n if (statusCode === 500 && requestRecord.exception !== undefined) {\n const sentryEventId = requestRecord.attributes[\"apitally.exception.sentry_event_id\"];\n addServerError(\n consumerIdentifier,\n method,\n route ?? \"\",\n requestRecord.exception,\n typeof sentryEventId === \"string\" ? sentryEventId : undefined,\n );\n }\n // A dropped request's spans are never released, so a stash entry for it\n // would sit unconsumed until the cap evicts it.\n if (requestRecord.serverSpanId !== undefined && requestRecord.dropReason === undefined) {\n const config = getConfig();\n const stash: RequestStash = {};\n if (config.captureRequestHeaders) {\n stash.requestHeaders = normalizeHeaders(options.requestHeaders);\n }\n if (config.captureResponseHeaders) {\n stash.responseHeaders = normalizeHeaders(options.responseHeaders);\n }\n const requestBody = options.capturedRequestBody?.body;\n if (requestBody) {\n stash.requestBody = requestBody;\n stash.requestContentEncoding = getHeaderValue(options.requestHeaders, \"content-encoding\");\n }\n const responseBody = options.capturedResponseBody?.body;\n if (responseBody && config.captureResponseBody) {\n stash.responseBody = responseBody;\n stash.responseContentEncoding = getHeaderValue(options.responseHeaders, \"content-encoding\");\n }\n if (Object.keys(stash).length > 0) {\n getActiveSpanPipeline()?.updateStash(requestRecord.serverSpanId, stash);\n }\n }\n ownSpan?.end(options.completedAtMillis);\n getActiveSpanPipeline()?.handleTransportCompletion(requestRecord);\n}\n\nexport interface FinalizeRequestObservationWithErrorOptions {\n requestRecord: RequestRecord;\n spanHandle: SpanHandle;\n error: unknown;\n durationSeconds: number;\n}\n\nexport function finalizeRequestObservationWithError(\n options: FinalizeRequestObservationWithErrorOptions,\n): void {\n const { requestRecord, spanHandle, error, durationSeconds } = options;\n requestRecord.durationSeconds = durationSeconds;\n if (spanHandle.span?.isRecording()) {\n spanHandle.span.recordException(coerceToException(error));\n }\n if (spanHandle.ownSpan) {\n spanHandle.ownSpan.setStatus({ code: SpanStatusCode.ERROR });\n spanHandle.ownSpan.end();\n }\n getActiveSpanPipeline()?.handleTransportCompletion(requestRecord);\n}\n\nfunction getHeaderValue(\n headers: Headers | Record<string, string | number | string[] | undefined>,\n name: string,\n): string | undefined {\n if (isWebHeaders(headers)) {\n return headers.get(name) ?? undefined;\n }\n for (const [headerName, value] of Object.entries(headers)) {\n if (headerName.toLowerCase() === name) {\n return Array.isArray(value) ? value.join(\",\") : value?.toString();\n }\n }\n return undefined;\n}\n\n// Values remain raw so all redaction happens at the export boundary.\nfunction normalizeHeaders(\n headers: Headers | Record<string, string | number | string[] | undefined>,\n): Record<string, string | string[]> {\n const normalized: Record<string, string | string[]> = {};\n if (isWebHeaders(headers)) {\n // The Headers API combines repeated values except Set-Cookie.\n for (const [name, value] of headers) {\n const existing = normalized[name];\n if (existing === undefined) {\n normalized[name] = value;\n } else if (Array.isArray(existing)) {\n existing.push(value);\n } else {\n normalized[name] = [existing, value];\n }\n }\n return normalized;\n }\n for (const [name, value] of Object.entries(headers)) {\n if (value !== undefined) {\n normalized[name.toLowerCase()] = Array.isArray(value) ? value : String(value);\n }\n }\n return normalized;\n}\n\n// Duck-typed on iterability: a plain header record has no Symbol.iterator, and\n// the Headers instance may come from another realm's implementation.\nfunction isWebHeaders(headers: object): headers is Headers {\n return typeof (headers as Headers)[Symbol.iterator] === \"function\";\n}\n\nfunction warnAboutNonRecordingServerSpan(): void {\n logWarning(\n \"The OpenTelemetry sampler did not sample the SERVER span of a request. Only sampled requests are exported to Apitally as traces and request logs. Request metrics include all requests.\",\n );\n}\n\nfunction warnAboutUnattachedSpanProcessor(): void {\n logWarning(\n \"The recording OpenTelemetry SERVER span created for a request did not reach ApitallySpanProcessor. Traces and request logs are unavailable while request metrics continue. To resolve this, add the ApitallySpanProcessor instance to your tracer provider's spanProcessors constructor option or the NodeSDK spanProcessors option.\",\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"requestObservation.cjs","names":["trace","getActiveSpanPipeline","SpanKind","withRequestHolders","isApitallySpanProcessorDeclared","getRPCMetadata","RPCType","setRPCMetadata","SpanStatusCode","isValidationResponseStatus","getConfig","coerceToException"],"sources":["../src/requestObservation.ts"],"sourcesContent":["import { type Attributes, type Context, SpanKind, SpanStatusCode, trace } from \"@opentelemetry/api\";\nimport { getRPCMetadata, type RPCMetadata, RPCType, setRPCMetadata } from \"@opentelemetry/core\";\nimport type { BodyCapture, CapturedBody } from \"./bodyCapture.js\";\nimport { getConfig } from \"./config.js\";\nimport { emitConsumerUpdateIfChanged } from \"./consumers.js\";\nimport {\n attachRequestRecordToRpcMetadata,\n type RequestRecord,\n type SpanHandle,\n withRequestHolders,\n} from \"./context.js\";\nimport { coerceToException } from \"./exceptions.js\";\nimport { logWarning } from \"./logger.js\";\nimport { writeRequestAttribute } from \"./requestAttributes.js\";\nimport { addServerError } from \"./serverErrors.js\";\nimport {\n getActiveSpanPipeline,\n isApitallySpanProcessorDeclared,\n type RequestStash,\n} from \"./spanProcessor.js\";\nimport { addValidationErrors, isValidationResponseStatus } from \"./validationErrors.js\";\n\ninterface StartRequestObservationOptions {\n activeContext: Context;\n extractedContext: Context;\n tracerName: string;\n method: string;\n startAttributes: Attributes;\n requestBodyCapture: BodyCapture;\n}\n\nexport interface StartedRequestObservation {\n requestRecord: RequestRecord;\n requestContext: Context;\n spanHandle: SpanHandle;\n rpcMetadata?: RPCMetadata;\n}\n\nexport interface HttpRequestStartAttributeInput {\n method: string;\n path?: string;\n query?: string;\n scheme?: string;\n serverAddress?: string;\n fullUrl?: string;\n clientAddress?: string;\n userAgent?: string;\n requestBodySize?: number;\n}\n\nexport function resolveHttpRequestStartAttributes(\n input: HttpRequestStartAttributeInput,\n): Attributes {\n const attributes: Attributes = { \"http.request.method\": input.method };\n const optionalAttributes: [string, string | number | undefined][] = [\n [\"url.path\", input.path],\n [\"url.query\", input.query],\n [\"url.scheme\", input.scheme],\n [\"url.full\", input.fullUrl],\n [\"server.address\", input.serverAddress],\n [\"client.address\", input.clientAddress],\n [\"user_agent.original\", input.userAgent],\n [\"http.request.body.size\", input.requestBodySize],\n ];\n for (const [name, value] of optionalAttributes) {\n if (value !== undefined) {\n attributes[name] = value;\n }\n }\n return attributes;\n}\n\nexport function startRequestObservation(\n options: StartRequestObservationOptions,\n): StartedRequestObservation {\n const {\n activeContext,\n extractedContext,\n tracerName,\n method,\n startAttributes,\n requestBodyCapture,\n } = options;\n const requestRecord: RequestRecord = { attributes: {} };\n const spanHandle: SpanHandle = {};\n // Metrics and the exported span copy read from the request record, so the\n // start attributes are mirrored into it on every path, span or no span.\n Object.assign(requestRecord.attributes, startAttributes);\n const activeSpan = trace.getSpan(activeContext);\n const resolveUnavailableSpanDropReason = (): RequestRecord[\"dropReason\"] =>\n getActiveSpanPipeline()?.resolveRequestDropReasonBeforeSampling(startAttributes) ??\n \"sampled-out\";\n let requestContext: Context;\n // Span kind is not part of the OTel API surface, so read the SDK-level\n // property from whichever package copy produced the span.\n if (activeSpan?.isRecording() && (activeSpan as { kind?: unknown }).kind === SpanKind.SERVER) {\n // A SERVER span produced by the user's own instrumentation is adopted:\n // no second span, and the request runs under the user's context.\n spanHandle.span = activeSpan;\n requestRecord.serverSpanId = activeSpan.spanContext().spanId;\n getActiveSpanPipeline()?.attachRequestRecord(requestRecord.serverSpanId, requestRecord);\n if (getActiveSpanPipeline()?.isRequestInFlight(requestRecord.serverSpanId) !== true) {\n requestRecord.dropReason = resolveUnavailableSpanDropReason();\n }\n requestContext = withRequestHolders(activeContext, spanHandle, requestRecord);\n } else if (activeSpan && !activeSpan.isRecording() && !activeSpan.spanContext().isRemote) {\n requestRecord.dropReason = resolveUnavailableSpanDropReason();\n if (requestRecord.dropReason === \"sampled-out\") {\n warnAboutNonRecordingServerSpan();\n }\n requestContext = withRequestHolders(activeContext, spanHandle, requestRecord);\n } else {\n requestContext = withRequestHolders(extractedContext, spanHandle, requestRecord);\n const ownSpan = trace\n .getTracer(tracerName)\n .startSpan(method, { kind: SpanKind.SERVER, attributes: startAttributes }, requestContext);\n if (!ownSpan.isRecording()) {\n requestRecord.dropReason = resolveUnavailableSpanDropReason();\n if (requestRecord.dropReason === \"sampled-out\") {\n warnAboutNonRecordingServerSpan();\n }\n } else {\n spanHandle.span = ownSpan;\n spanHandle.ownSpan = ownSpan;\n if (isApitallySpanProcessorDeclared() && requestRecord.serverSpanId === undefined) {\n requestRecord.dropReason = resolveUnavailableSpanDropReason();\n if (requestRecord.dropReason === \"sampled-out\") {\n warnAboutUnattachedSpanProcessor();\n }\n }\n }\n // A non-recording span still carries a valid span context, so user child\n // spans parent to it and parent-based samplers drop them consistently.\n requestContext = trace.setSpan(requestContext, ownSpan);\n }\n\n // Middleware-based span producers inspect OTel RPC metadata to demote duplicate\n // transport spans; completion adds the route.\n let rpcMetadata = getRPCMetadata(requestContext);\n if (!rpcMetadata && spanHandle.span) {\n rpcMetadata = { type: RPCType.HTTP, span: spanHandle.span };\n requestContext = setRPCMetadata(requestContext, rpcMetadata);\n }\n attachRequestRecordToRpcMetadata(rpcMetadata, requestRecord);\n if (requestRecord.dropReason !== undefined) {\n requestBodyCapture.stopBuffering();\n }\n return { requestRecord, requestContext, spanHandle, rpcMetadata };\n}\n\nexport interface RequestObservation {\n requestRecord: RequestRecord;\n spanHandle: SpanHandle;\n rpcMetadata?: RPCMetadata;\n method: string;\n startTimeMillis: number;\n}\n\nexport interface FinalizeRequestObservationOptions {\n observation: RequestObservation;\n completedAtMillis: number;\n statusCode: number;\n route?: string;\n clientAddress?: string;\n requestHeaders: Headers | Record<string, string | string[] | undefined>;\n responseHeaders: Headers | Record<string, string | number | string[] | undefined>;\n capturedRequestBody?: CapturedBody;\n capturedResponseBody?: CapturedBody;\n}\n\nexport function finalizeRequestObservation(options: FinalizeRequestObservationOptions): void {\n const { observation, statusCode, route } = options;\n const { requestRecord, spanHandle, rpcMetadata, method } = observation;\n requestRecord.durationSeconds = (options.completedAtMillis - observation.startTimeMillis) / 1000;\n const { span, ownSpan } = spanHandle;\n if (options.clientAddress !== undefined) {\n writeRequestAttribute(span, requestRecord, \"client.address\", options.clientAddress);\n }\n writeRequestAttribute(span, requestRecord, \"http.response.status_code\", statusCode);\n const requestBodySize = options.capturedRequestBody?.size;\n if (requestBodySize !== undefined) {\n writeRequestAttribute(span, requestRecord, \"http.request.body.size\", requestBodySize);\n }\n const responseBodySize = options.capturedResponseBody?.size;\n if (responseBodySize !== undefined) {\n writeRequestAttribute(span, requestRecord, \"http.response.body.size\", responseBodySize);\n }\n if (route !== undefined) {\n writeRequestAttribute(span, requestRecord, \"http.route\", route);\n if (rpcMetadata) {\n rpcMetadata.route = route;\n }\n if (ownSpan?.isRecording()) {\n ownSpan.updateName(`${method} ${route}`);\n }\n } else {\n // An empty route clears one set by the producing instrumentation; request\n // metrics omit empty routes.\n requestRecord.attributes[\"http.route\"] = \"\";\n }\n if (ownSpan && statusCode >= 500) {\n ownSpan.setStatus({ code: SpanStatusCode.ERROR });\n }\n // Validation and server errors are counted for every routed request,\n // including requests dropped from tracing.\n const consumer = requestRecord.attributes[\"apitally.consumer.identifier\"];\n const consumerIdentifier = typeof consumer === \"string\" ? consumer : undefined;\n if (requestRecord.validationErrors && isValidationResponseStatus(statusCode)) {\n addValidationErrors(consumerIdentifier, method, route ?? \"\", requestRecord.validationErrors);\n }\n if (statusCode === 500 && requestRecord.exception !== undefined) {\n const sentryEventId = requestRecord.attributes[\"apitally.exception.sentry_event_id\"];\n addServerError(\n consumerIdentifier,\n method,\n route ?? \"\",\n requestRecord.exception,\n typeof sentryEventId === \"string\" ? sentryEventId : undefined,\n );\n }\n // A dropped request's spans are never released, so a stash entry for it\n // would sit unconsumed until the cap evicts it.\n if (requestRecord.serverSpanId !== undefined && requestRecord.dropReason === undefined) {\n const config = getConfig();\n const stash: RequestStash = {};\n if (config.captureRequestHeaders) {\n stash.requestHeaders = normalizeHeaders(options.requestHeaders);\n }\n if (config.captureResponseHeaders) {\n stash.responseHeaders = normalizeHeaders(options.responseHeaders);\n }\n const requestBody = options.capturedRequestBody?.body;\n if (requestBody) {\n stash.requestBody = requestBody;\n stash.requestContentEncoding = getHeaderValue(options.requestHeaders, \"content-encoding\");\n }\n const responseBody = options.capturedResponseBody?.body;\n if (responseBody && config.captureResponseBody) {\n stash.responseBody = responseBody;\n stash.responseContentEncoding = getHeaderValue(options.responseHeaders, \"content-encoding\");\n }\n if (Object.keys(stash).length > 0) {\n getActiveSpanPipeline()?.updateStash(requestRecord.serverSpanId, stash);\n }\n }\n ownSpan?.end(options.completedAtMillis);\n emitConsumerUpdateIfChanged(requestRecord);\n getActiveSpanPipeline()?.handleTransportCompletion(requestRecord);\n}\n\nexport interface FinalizeRequestObservationWithErrorOptions {\n requestRecord: RequestRecord;\n spanHandle: SpanHandle;\n error: unknown;\n durationSeconds: number;\n}\n\nexport function finalizeRequestObservationWithError(\n options: FinalizeRequestObservationWithErrorOptions,\n): void {\n const { requestRecord, spanHandle, error, durationSeconds } = options;\n requestRecord.durationSeconds = durationSeconds;\n if (spanHandle.span?.isRecording()) {\n spanHandle.span.recordException(coerceToException(error));\n }\n if (spanHandle.ownSpan) {\n spanHandle.ownSpan.setStatus({ code: SpanStatusCode.ERROR });\n spanHandle.ownSpan.end();\n }\n emitConsumerUpdateIfChanged(requestRecord);\n getActiveSpanPipeline()?.handleTransportCompletion(requestRecord);\n}\n\nfunction getHeaderValue(\n headers: Headers | Record<string, string | number | string[] | undefined>,\n name: string,\n): string | undefined {\n if (isWebHeaders(headers)) {\n return headers.get(name) ?? undefined;\n }\n for (const [headerName, value] of Object.entries(headers)) {\n if (headerName.toLowerCase() === name) {\n return Array.isArray(value) ? value.join(\",\") : value?.toString();\n }\n }\n return undefined;\n}\n\n// Values remain raw so all redaction happens at the export boundary.\nfunction normalizeHeaders(\n headers: Headers | Record<string, string | number | string[] | undefined>,\n): Record<string, string | string[]> {\n const normalized: Record<string, string | string[]> = {};\n if (isWebHeaders(headers)) {\n // The Headers API combines repeated values except Set-Cookie.\n for (const [name, value] of headers) {\n const existing = normalized[name];\n if (existing === undefined) {\n normalized[name] = value;\n } else if (Array.isArray(existing)) {\n existing.push(value);\n } else {\n normalized[name] = [existing, value];\n }\n }\n return normalized;\n }\n for (const [name, value] of Object.entries(headers)) {\n if (value !== undefined) {\n normalized[name.toLowerCase()] = Array.isArray(value) ? value : String(value);\n }\n }\n return normalized;\n}\n\n// Duck-typed on iterability: a plain header record has no Symbol.iterator, and\n// the Headers instance may come from another realm's implementation.\nfunction isWebHeaders(headers: object): headers is Headers {\n return typeof (headers as Headers)[Symbol.iterator] === \"function\";\n}\n\nfunction warnAboutNonRecordingServerSpan(): void {\n logWarning(\n \"The OpenTelemetry sampler did not sample the SERVER span of a request. Only sampled requests are exported to Apitally as traces and request logs. Request metrics include all requests.\",\n );\n}\n\nfunction warnAboutUnattachedSpanProcessor(): void {\n logWarning(\n \"The recording OpenTelemetry SERVER span created for a request did not reach ApitallySpanProcessor. Traces and request logs are unavailable while request metrics continue. To resolve this, add the ApitallySpanProcessor instance to your tracer provider's spanProcessors constructor option or the NodeSDK spanProcessors option.\",\n );\n}\n"],"mappings":"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"}
@@ -1,11 +1,12 @@
1
1
  import { logWarning } from "./logger.js";
2
2
  import { getConfig } from "./config.js";
3
- import { attachRequestRecordToRpcMetadata, getConsumerHolder, withRequestHolders } from "./context.js";
3
+ import { attachRequestRecordToRpcMetadata, withRequestHolders } from "./context.js";
4
4
  import { writeRequestAttribute } from "./requestAttributes.js";
5
5
  import { coerceToException } from "./exceptions.js";
6
6
  import { addServerError } from "./serverErrors.js";
7
7
  import { getActiveSpanPipeline, isApitallySpanProcessorDeclared } from "./spanProcessor.js";
8
8
  import { addValidationErrors, isValidationResponseStatus } from "./validationErrors.js";
9
+ import { emitConsumerUpdateIfChanged } from "./consumers.js";
9
10
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
10
11
  import { RPCType, getRPCMetadata, setRPCMetadata } from "@opentelemetry/core";
11
12
  //#region src/requestObservation.ts
@@ -28,7 +29,6 @@ function startRequestObservation(options) {
28
29
  const { activeContext, extractedContext, tracerName, method, startAttributes, requestBodyCapture } = options;
29
30
  const requestRecord = { attributes: {} };
30
31
  const spanHandle = {};
31
- const consumerHolder = getConsumerHolder(activeContext) ?? {};
32
32
  Object.assign(requestRecord.attributes, startAttributes);
33
33
  const activeSpan = trace.getSpan(activeContext);
34
34
  const resolveUnavailableSpanDropReason = () => getActiveSpanPipeline()?.resolveRequestDropReasonBeforeSampling(startAttributes) ?? "sampled-out";
@@ -38,13 +38,13 @@ function startRequestObservation(options) {
38
38
  requestRecord.serverSpanId = activeSpan.spanContext().spanId;
39
39
  getActiveSpanPipeline()?.attachRequestRecord(requestRecord.serverSpanId, requestRecord);
40
40
  if (getActiveSpanPipeline()?.isRequestInFlight(requestRecord.serverSpanId) !== true) requestRecord.dropReason = resolveUnavailableSpanDropReason();
41
- requestContext = withRequestHolders(activeContext, spanHandle, requestRecord, consumerHolder);
41
+ requestContext = withRequestHolders(activeContext, spanHandle, requestRecord);
42
42
  } else if (activeSpan && !activeSpan.isRecording() && !activeSpan.spanContext().isRemote) {
43
43
  requestRecord.dropReason = resolveUnavailableSpanDropReason();
44
44
  if (requestRecord.dropReason === "sampled-out") warnAboutNonRecordingServerSpan();
45
- requestContext = withRequestHolders(activeContext, spanHandle, requestRecord, consumerHolder);
45
+ requestContext = withRequestHolders(activeContext, spanHandle, requestRecord);
46
46
  } else {
47
- requestContext = withRequestHolders(extractedContext, spanHandle, requestRecord, consumerHolder);
47
+ requestContext = withRequestHolders(extractedContext, spanHandle, requestRecord);
48
48
  const ownSpan = trace.getTracer(tracerName).startSpan(method, {
49
49
  kind: SpanKind.SERVER,
50
50
  attributes: startAttributes
@@ -121,6 +121,7 @@ function finalizeRequestObservation(options) {
121
121
  if (Object.keys(stash).length > 0) getActiveSpanPipeline()?.updateStash(requestRecord.serverSpanId, stash);
122
122
  }
123
123
  ownSpan?.end(options.completedAtMillis);
124
+ emitConsumerUpdateIfChanged(requestRecord);
124
125
  getActiveSpanPipeline()?.handleTransportCompletion(requestRecord);
125
126
  }
126
127
  function finalizeRequestObservationWithError(options) {
@@ -131,6 +132,7 @@ function finalizeRequestObservationWithError(options) {
131
132
  spanHandle.ownSpan.setStatus({ code: SpanStatusCode.ERROR });
132
133
  spanHandle.ownSpan.end();
133
134
  }
135
+ emitConsumerUpdateIfChanged(requestRecord);
134
136
  getActiveSpanPipeline()?.handleTransportCompletion(requestRecord);
135
137
  }
136
138
  function getHeaderValue(headers, name) {