repro-nest 0.0.212 → 0.0.214

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -491,6 +491,26 @@ function isReproTracingEnabled() { return __TRACER_READY; }
491
491
  exports.isReproTracingEnabled = isReproTracingEnabled;
492
492
  function captureSpanContextFromTracer(source) {
493
493
  try {
494
+ // Prefer a preserved store captured at the call-site for thenables (e.g., Mongoose Query),
495
+ // because the tracer intentionally detaches spans before the query is actually executed.
496
+ const promiseStore = source && source[Symbol.for('__repro_promise_store')];
497
+ if (promiseStore) {
498
+ const stack = Array.isArray(promiseStore.__repro_span_stack) ? promiseStore.__repro_span_stack : [];
499
+ const top = stack.length ? stack[stack.length - 1] : null;
500
+ const spanId = top && top.id != null ? top.id : null;
501
+ const parentSpanId = top && top.parentId != null
502
+ ? top.parentId
503
+ : (stack.length >= 2 ? (stack[stack.length - 2]?.id ?? null) : null);
504
+ const depth = top && top.depth != null
505
+ ? top.depth
506
+ : (typeof promiseStore.depth === 'number'
507
+ ? promiseStore.depth
508
+ : (stack.length ? stack.length : null));
509
+ const traceId = promiseStore.traceId ?? null;
510
+ if (traceId || spanId !== null || parentSpanId !== null) {
511
+ return { traceId, spanId, parentSpanId, depth: depth == null ? null : depth };
512
+ }
513
+ }
494
514
  const fromSource = source && source.__repro_span_context;
495
515
  if (fromSource) {
496
516
  return {
@@ -522,6 +542,26 @@ function captureSpanContextFromTracer(source) {
522
542
  catch { }
523
543
  return null;
524
544
  }
545
+ function isExcludedSpanId(spanId) {
546
+ if (spanId === null || spanId === undefined)
547
+ return false;
548
+ try {
549
+ const excluded = getCtx().excludedSpanIds;
550
+ if (!excluded || excluded.size === 0)
551
+ return false;
552
+ return excluded.has(String(spanId));
553
+ }
554
+ catch {
555
+ return false;
556
+ }
557
+ }
558
+ function shouldCaptureDbSpan(span) {
559
+ if (!span || span.spanId === null || span.spanId === undefined)
560
+ return false;
561
+ if (isExcludedSpanId(span.spanId))
562
+ return false;
563
+ return true;
564
+ }
525
565
  function attachSpanContext(target, span) {
526
566
  if (!target)
527
567
  return target;
@@ -1274,7 +1314,7 @@ function reproMiddleware(cfg) {
1274
1314
  }
1275
1315
  return fn();
1276
1316
  };
1277
- runInTrace(() => als.run({ sid, aid, clockSkewMs }, () => {
1317
+ runInTrace(() => als.run({ sid, aid, clockSkewMs, excludedSpanIds: new Set() }, () => {
1278
1318
  const events = [];
1279
1319
  let endpointTrace = null;
1280
1320
  let preferredAppTrace = null;
@@ -1423,6 +1463,7 @@ function reproMiddleware(cfg) {
1423
1463
  depth: evt.depth,
1424
1464
  library: inferLibraryNameFromFile(evt.file),
1425
1465
  };
1466
+ const dropEvent = shouldDropTraceEvent(candidate);
1426
1467
  const spanKey = normalizeSpanId(evt.spanId);
1427
1468
  if (evt.type === 'enter') {
1428
1469
  lastEventAt = Date.now();
@@ -1442,7 +1483,13 @@ function reproMiddleware(cfg) {
1442
1483
  anonymousSpanDepth = Math.max(0, anonymousSpanDepth - 1);
1443
1484
  }
1444
1485
  }
1445
- if (shouldDropTraceEvent(candidate)) {
1486
+ if (dropEvent) {
1487
+ if (evt.type === 'enter' && spanKey) {
1488
+ try {
1489
+ getCtx().excludedSpanIds?.add(spanKey);
1490
+ }
1491
+ catch { }
1492
+ }
1446
1493
  if (finished) {
1447
1494
  scheduleIdleFlush();
1448
1495
  }
@@ -1626,6 +1673,8 @@ function reproMongoosePlugin(cfg) {
1626
1673
  const after = this.toObject({ depopulate: true });
1627
1674
  const collection = meta.collection || resolveCollectionOrWarn(this, 'doc');
1628
1675
  const spanContext = meta.spanContext || captureSpanContextFromTracer(this);
1676
+ if (!shouldCaptureDbSpan(spanContext))
1677
+ return;
1629
1678
  const query = meta.wasNew
1630
1679
  ? { op: 'insertOne', doc: after }
1631
1680
  : { filter: { _id: this._id }, update: buildMinimalUpdate(before, after), options: { upsert: false } };
@@ -1668,6 +1717,8 @@ function reproMongoosePlugin(cfg) {
1668
1717
  const after = res ?? null;
1669
1718
  const collection = this.__repro_collection || resolveCollectionOrWarn(this, 'query');
1670
1719
  const spanContext = this.__repro_spanContext || captureSpanContextFromTracer(this);
1720
+ if (!shouldCaptureDbSpan(spanContext))
1721
+ return;
1671
1722
  const pk = after?._id ?? before?._id;
1672
1723
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, getCtx().sid, {
1673
1724
  entries: [{
@@ -1708,6 +1759,8 @@ function reproMongoosePlugin(cfg) {
1708
1759
  const collection = this.__repro_collection || resolveCollectionOrWarn(this, 'query');
1709
1760
  const filter = this.__repro_filter ?? { _id: before._id };
1710
1761
  const spanContext = this.__repro_spanContext || captureSpanContextFromTracer(this);
1762
+ if (!shouldCaptureDbSpan(spanContext))
1763
+ return;
1711
1764
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, getCtx().sid, {
1712
1765
  entries: [{
1713
1766
  actionId: getCtx().aid,
@@ -2019,6 +2072,9 @@ function dehydrateComplexValue(value) {
2019
2072
  function emitDbQuery(cfg, sid, aid, payload) {
2020
2073
  if (!sid)
2021
2074
  return;
2075
+ const spanContext = payload?.spanContext ?? captureSpanContextFromTracer();
2076
+ if (!shouldCaptureDbSpan(spanContext))
2077
+ return;
2022
2078
  const dbEntry = attachSpanContext({
2023
2079
  collection: payload.collection,
2024
2080
  op: payload.op,
@@ -2027,7 +2083,7 @@ function emitDbQuery(cfg, sid, aid, payload) {
2027
2083
  durMs: payload.durMs ?? undefined,
2028
2084
  pk: null, before: null, after: null,
2029
2085
  error: payload.error ?? undefined,
2030
- }, payload?.spanContext);
2086
+ }, spanContext);
2031
2087
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, sid, {
2032
2088
  entries: [{
2033
2089
  actionId: aid ?? null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repro-nest",
3
- "version": "0.0.212",
3
+ "version": "0.0.214",
4
4
  "description": "Repro Nest SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -684,6 +684,27 @@ export function isReproTracingEnabled() { return __TRACER_READY; }
684
684
 
685
685
  function captureSpanContextFromTracer(source?: any): SpanContext | null {
686
686
  try {
687
+ // Prefer a preserved store captured at the call-site for thenables (e.g., Mongoose Query),
688
+ // because the tracer intentionally detaches spans before the query is actually executed.
689
+ const promiseStore = source && source[Symbol.for('__repro_promise_store')];
690
+ if (promiseStore) {
691
+ const stack = Array.isArray(promiseStore.__repro_span_stack) ? promiseStore.__repro_span_stack : [];
692
+ const top = stack.length ? stack[stack.length - 1] : null;
693
+ const spanId = top && top.id != null ? top.id : null;
694
+ const parentSpanId = top && top.parentId != null
695
+ ? top.parentId
696
+ : (stack.length >= 2 ? (stack[stack.length - 2]?.id ?? null) : null);
697
+ const depth = top && top.depth != null
698
+ ? top.depth
699
+ : (typeof promiseStore.depth === 'number'
700
+ ? promiseStore.depth
701
+ : (stack.length ? stack.length : null));
702
+ const traceId = promiseStore.traceId ?? null;
703
+ if (traceId || spanId !== null || parentSpanId !== null) {
704
+ return { traceId, spanId, parentSpanId, depth: depth == null ? null : depth };
705
+ }
706
+ }
707
+
687
708
  const fromSource = source && source.__repro_span_context;
688
709
  if (fromSource) {
689
710
  return {
@@ -715,6 +736,23 @@ function captureSpanContextFromTracer(source?: any): SpanContext | null {
715
736
  return null;
716
737
  }
717
738
 
739
+ function isExcludedSpanId(spanId: string | number | null | undefined): boolean {
740
+ if (spanId === null || spanId === undefined) return false;
741
+ try {
742
+ const excluded = (getCtx() as Ctx).excludedSpanIds;
743
+ if (!excluded || excluded.size === 0) return false;
744
+ return excluded.has(String(spanId));
745
+ } catch {
746
+ return false;
747
+ }
748
+ }
749
+
750
+ function shouldCaptureDbSpan(span: SpanContext | null | undefined): span is SpanContext {
751
+ if (!span || span.spanId === null || span.spanId === undefined) return false;
752
+ if (isExcludedSpanId(span.spanId)) return false;
753
+ return true;
754
+ }
755
+
718
756
  function attachSpanContext<T extends Record<string, any>>(target: T, span?: SpanContext | null): T {
719
757
  if (!target) return target;
720
758
  const ctx = span ?? captureSpanContextFromTracer();
@@ -724,7 +762,7 @@ function attachSpanContext<T extends Record<string, any>>(target: T, span?: Span
724
762
  return target;
725
763
  }
726
764
 
727
- type Ctx = { sid?: string; aid?: string; clockSkewMs?: number };
765
+ type Ctx = { sid?: string; aid?: string; clockSkewMs?: number; excludedSpanIds?: Set<string> };
728
766
  const als = new AsyncLocalStorage<Ctx>();
729
767
  const getCtx = () => als.getStore() || {};
730
768
 
@@ -1504,7 +1542,7 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
1504
1542
  return fn();
1505
1543
  };
1506
1544
 
1507
- runInTrace(() => als.run({ sid, aid, clockSkewMs }, () => {
1545
+ runInTrace(() => als.run({ sid, aid, clockSkewMs, excludedSpanIds: new Set<string>() }, () => {
1508
1546
  const events: TraceEventRecord[] = [];
1509
1547
  let endpointTrace: EndpointTraceInfo | null = null;
1510
1548
  let preferredAppTrace: EndpointTraceInfo | null = null;
@@ -1639,6 +1677,7 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
1639
1677
  library: inferLibraryNameFromFile(evt.file),
1640
1678
  };
1641
1679
 
1680
+ const dropEvent = shouldDropTraceEvent(candidate);
1642
1681
  const spanKey = normalizeSpanId(evt.spanId);
1643
1682
  if (evt.type === 'enter') {
1644
1683
  lastEventAt = Date.now();
@@ -1656,7 +1695,10 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
1656
1695
  }
1657
1696
  }
1658
1697
 
1659
- if (shouldDropTraceEvent(candidate)) {
1698
+ if (dropEvent) {
1699
+ if (evt.type === 'enter' && spanKey) {
1700
+ try { (getCtx() as Ctx).excludedSpanIds?.add(spanKey); } catch {}
1701
+ }
1660
1702
  if (finished) {
1661
1703
  scheduleIdleFlush();
1662
1704
  }
@@ -1844,6 +1886,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1844
1886
  const after = this.toObject({ depopulate: true });
1845
1887
  const collection = meta.collection || resolveCollectionOrWarn(this, 'doc');
1846
1888
  const spanContext = meta.spanContext || captureSpanContextFromTracer(this);
1889
+ if (!shouldCaptureDbSpan(spanContext)) return;
1847
1890
 
1848
1891
  const query = meta.wasNew
1849
1892
  ? { op: 'insertOne', doc: after }
@@ -1888,6 +1931,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1888
1931
  const after = res ?? null;
1889
1932
  const collection = (this as any).__repro_collection || resolveCollectionOrWarn(this, 'query');
1890
1933
  const spanContext = (this as any).__repro_spanContext || captureSpanContextFromTracer(this);
1934
+ if (!shouldCaptureDbSpan(spanContext)) return;
1891
1935
  const pk = after?._id ?? before?._id;
1892
1936
 
1893
1937
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, (getCtx() as Ctx).sid!, {
@@ -1925,6 +1969,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1925
1969
  const collection = (this as any).__repro_collection || resolveCollectionOrWarn(this, 'query');
1926
1970
  const filter = (this as any).__repro_filter ?? { _id: before._id };
1927
1971
  const spanContext = (this as any).__repro_spanContext || captureSpanContextFromTracer(this);
1972
+ if (!shouldCaptureDbSpan(spanContext)) return;
1928
1973
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, (getCtx() as Ctx).sid!, {
1929
1974
  entries: [{
1930
1975
  actionId: (getCtx() as Ctx).aid!,
@@ -2240,6 +2285,8 @@ function dehydrateComplexValue(value: any) {
2240
2285
 
2241
2286
  function emitDbQuery(cfg: any, sid?: string, aid?: string, payload?: any) {
2242
2287
  if (!sid) return;
2288
+ const spanContext = payload?.spanContext ?? captureSpanContextFromTracer();
2289
+ if (!shouldCaptureDbSpan(spanContext)) return;
2243
2290
  const dbEntry = attachSpanContext({
2244
2291
  collection: payload.collection,
2245
2292
  op: payload.op,
@@ -2248,7 +2295,7 @@ function emitDbQuery(cfg: any, sid?: string, aid?: string, payload?: any) {
2248
2295
  durMs: payload.durMs ?? undefined,
2249
2296
  pk: null, before: null, after: null,
2250
2297
  error: payload.error ?? undefined,
2251
- }, payload?.spanContext);
2298
+ }, spanContext);
2252
2299
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, sid, {
2253
2300
  entries: [{
2254
2301
  actionId: aid ?? null,
package/tracer/runtime.js CHANGED
@@ -545,7 +545,13 @@ if (!global.__repro_call) {
545
545
  const perCallStore = cloneStore(baseStoreSnapshot);
546
546
  let result;
547
547
  als.run(perCallStore, () => {
548
- result = arg.apply(this, arguments);
548
+ // Support both callbacks and constructors: some libraries (e.g., class-transformer)
549
+ // pass class constructors as args and invoke them with `new`.
550
+ if (new.target) {
551
+ result = Reflect.construct(arg, arguments, arg);
552
+ } else {
553
+ result = arg.apply(this, arguments);
554
+ }
549
555
  });
550
556
  return result;
551
557
  };