repro-nest 0.0.207 → 0.0.209

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -25,12 +25,19 @@
25
25
  /// <reference types="mongoose/types/inferrawdoctype" />
26
26
  import type { Request, Response, NextFunction } from 'express';
27
27
  import type { Schema } from 'mongoose';
28
+ type SpanContext = {
29
+ traceId: string | null;
30
+ spanId: string | number | null;
31
+ parentSpanId: string | number | null;
32
+ depth: number | null;
33
+ };
28
34
  type TracerApi = {
29
35
  init?: (opts: any) => void;
30
36
  tracer?: {
31
37
  on: (fn: (ev: any) => void) => () => void;
32
38
  };
33
39
  getCurrentTraceId?: () => string | null;
40
+ getCurrentSpanContext?: () => SpanContext | null;
34
41
  patchHttp?: () => void;
35
42
  setFunctionLogsEnabled?: (enabled: boolean) => void;
36
43
  };
package/dist/index.js CHANGED
@@ -459,6 +459,42 @@ exports.initReproTracing = initReproTracing;
459
459
  /** Optional helper if users want to check it. */
460
460
  function isReproTracingEnabled() { return __TRACER_READY; }
461
461
  exports.isReproTracingEnabled = isReproTracingEnabled;
462
+ function captureSpanContextFromTracer() {
463
+ try {
464
+ const ctx = __TRACER__?.getCurrentSpanContext?.();
465
+ if (ctx) {
466
+ const span = {
467
+ traceId: ctx.traceId ?? __TRACER__?.getCurrentTraceId?.() ?? null,
468
+ spanId: ctx.spanId ?? null,
469
+ parentSpanId: ctx.parentSpanId ?? null,
470
+ depth: ctx.depth ?? null,
471
+ };
472
+ if (span.traceId || span.spanId !== null || span.parentSpanId !== null) {
473
+ return span;
474
+ }
475
+ }
476
+ else if (__TRACER__?.getCurrentTraceId) {
477
+ const traceId = __TRACER__?.getCurrentTraceId?.() ?? null;
478
+ if (traceId) {
479
+ return { traceId, spanId: null, parentSpanId: null, depth: null };
480
+ }
481
+ }
482
+ }
483
+ catch { }
484
+ return null;
485
+ }
486
+ function attachSpanContext(target, span) {
487
+ if (!target)
488
+ return target;
489
+ const ctx = span ?? captureSpanContextFromTracer();
490
+ if (ctx) {
491
+ try {
492
+ target.spanContext = ctx;
493
+ }
494
+ catch { }
495
+ }
496
+ return target;
497
+ }
462
498
  const als = new async_hooks_1.AsyncLocalStorage();
463
499
  const getCtx = () => als.getStore() || {};
464
500
  function currentClockSkewMs() {
@@ -1327,9 +1363,6 @@ function reproMiddleware(cfg) {
1327
1363
  if (ev.args !== undefined) {
1328
1364
  evt.args = sanitizeTraceArgs(ev.args);
1329
1365
  }
1330
- if (ev.receiver !== undefined) {
1331
- evt.receiver = sanitizeTraceValue(ev.receiver);
1332
- }
1333
1366
  if (ev.returnValue !== undefined) {
1334
1367
  evt.returnValue = sanitizeTraceValue(ev.returnValue);
1335
1368
  }
@@ -1539,6 +1572,7 @@ function reproMongoosePlugin(cfg) {
1539
1572
  wasNew: this.isNew,
1540
1573
  before,
1541
1574
  collection: resolveCollectionOrWarn(this, 'doc'),
1575
+ spanContext: captureSpanContextFromTracer(),
1542
1576
  };
1543
1577
  next();
1544
1578
  });
@@ -1552,13 +1586,21 @@ function reproMongoosePlugin(cfg) {
1552
1586
  const before = meta.before ?? null;
1553
1587
  const after = this.toObject({ depopulate: true });
1554
1588
  const collection = meta.collection || resolveCollectionOrWarn(this, 'doc');
1589
+ const spanContext = meta.spanContext || captureSpanContextFromTracer();
1555
1590
  const query = meta.wasNew
1556
1591
  ? { op: 'insertOne', doc: after }
1557
1592
  : { filter: { _id: this._id }, update: buildMinimalUpdate(before, after), options: { upsert: false } };
1558
1593
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, getCtx().sid, {
1559
1594
  entries: [{
1560
1595
  actionId: getCtx().aid,
1561
- db: [{ collection, pk: { _id: this._id }, before, after, op: meta.wasNew ? 'insert' : 'update', query }],
1596
+ db: [attachSpanContext({
1597
+ collection,
1598
+ pk: { _id: this._id },
1599
+ before,
1600
+ after,
1601
+ op: meta.wasNew ? 'insert' : 'update',
1602
+ query,
1603
+ }, spanContext)],
1562
1604
  t: alignedNow(),
1563
1605
  }]
1564
1606
  });
@@ -1574,6 +1616,7 @@ function reproMongoosePlugin(cfg) {
1574
1616
  this.__repro_before = await model.findOne(filter).lean().exec();
1575
1617
  this.setOptions({ new: true });
1576
1618
  this.__repro_collection = resolveCollectionOrWarn(this, 'query');
1619
+ this.__repro_spanContext = captureSpanContextFromTracer();
1577
1620
  }
1578
1621
  catch { }
1579
1622
  next();
@@ -1585,11 +1628,18 @@ function reproMongoosePlugin(cfg) {
1585
1628
  const before = this.__repro_before ?? null;
1586
1629
  const after = res ?? null;
1587
1630
  const collection = this.__repro_collection || resolveCollectionOrWarn(this, 'query');
1631
+ const spanContext = this.__repro_spanContext || captureSpanContextFromTracer();
1588
1632
  const pk = after?._id ?? before?._id;
1589
1633
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, getCtx().sid, {
1590
1634
  entries: [{
1591
1635
  actionId: getCtx().aid,
1592
- db: [{ collection, pk: { _id: pk }, before, after, op: after && before ? 'update' : after ? 'insert' : 'update' }],
1636
+ db: [attachSpanContext({
1637
+ collection,
1638
+ pk: { _id: pk },
1639
+ before,
1640
+ after,
1641
+ op: after && before ? 'update' : after ? 'insert' : 'update',
1642
+ }, spanContext)],
1593
1643
  t: alignedNow()
1594
1644
  }]
1595
1645
  });
@@ -1604,6 +1654,7 @@ function reproMongoosePlugin(cfg) {
1604
1654
  this.__repro_before = await this.model.findOne(filter).lean().exec();
1605
1655
  this.__repro_collection = resolveCollectionOrWarn(this, 'query');
1606
1656
  this.__repro_filter = filter;
1657
+ this.__repro_spanContext = captureSpanContextFromTracer();
1607
1658
  }
1608
1659
  catch { }
1609
1660
  next();
@@ -1617,10 +1668,18 @@ function reproMongoosePlugin(cfg) {
1617
1668
  return;
1618
1669
  const collection = this.__repro_collection || resolveCollectionOrWarn(this, 'query');
1619
1670
  const filter = this.__repro_filter ?? { _id: before._id };
1671
+ const spanContext = this.__repro_spanContext || captureSpanContextFromTracer();
1620
1672
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, getCtx().sid, {
1621
1673
  entries: [{
1622
1674
  actionId: getCtx().aid,
1623
- db: [{ collection, pk: { _id: before._id }, before, after: null, op: 'delete', query: { filter } }],
1675
+ db: [attachSpanContext({
1676
+ collection,
1677
+ pk: { _id: before._id },
1678
+ before,
1679
+ after: null,
1680
+ op: 'delete',
1681
+ query: { filter },
1682
+ }, spanContext)],
1624
1683
  t: alignedNow()
1625
1684
  }]
1626
1685
  });
@@ -1658,6 +1717,7 @@ function reproMongoosePlugin(cfg) {
1658
1717
  t0: Date.now(),
1659
1718
  collection: this?.model?.collection?.name || 'unknown',
1660
1719
  op,
1720
+ spanContext: captureSpanContextFromTracer(),
1661
1721
  filter: sanitizeDbValue(this.getFilter?.() ?? this._conditions ?? undefined),
1662
1722
  update: sanitizeDbValue(this.getUpdate?.() ?? this._update ?? undefined),
1663
1723
  projection: sanitizeDbValue(this.projection?.() ?? this._fields ?? undefined),
@@ -1665,7 +1725,12 @@ function reproMongoosePlugin(cfg) {
1665
1725
  };
1666
1726
  }
1667
1727
  catch {
1668
- this.__repro_qmeta = { t0: Date.now(), collection: 'unknown', op };
1728
+ this.__repro_qmeta = {
1729
+ t0: Date.now(),
1730
+ collection: 'unknown',
1731
+ op,
1732
+ spanContext: captureSpanContextFromTracer(),
1733
+ };
1669
1734
  }
1670
1735
  next();
1671
1736
  });
@@ -1675,6 +1740,7 @@ function reproMongoosePlugin(cfg) {
1675
1740
  return;
1676
1741
  const meta = this.__repro_qmeta || { t0: Date.now(), collection: 'unknown', op };
1677
1742
  const resultMeta = summarizeQueryResult(op, res);
1743
+ const spanContext = meta.spanContext || captureSpanContextFromTracer();
1678
1744
  emitDbQuery(cfg, sid, aid, {
1679
1745
  collection: meta.collection,
1680
1746
  op,
@@ -1682,6 +1748,7 @@ function reproMongoosePlugin(cfg) {
1682
1748
  resultMeta,
1683
1749
  durMs: Date.now() - meta.t0,
1684
1750
  t: alignedNow(),
1751
+ spanContext,
1685
1752
  });
1686
1753
  });
1687
1754
  }
@@ -1694,10 +1761,15 @@ function reproMongoosePlugin(cfg) {
1694
1761
  t0: Date.now(),
1695
1762
  collection: this?.collection?.name || this?.model?.collection?.name || 'unknown',
1696
1763
  docs: sanitizeDbValue(docs),
1764
+ spanContext: captureSpanContextFromTracer(),
1697
1765
  };
1698
1766
  }
1699
1767
  catch {
1700
- this.__repro_insert_meta = { t0: Date.now(), collection: 'unknown' };
1768
+ this.__repro_insert_meta = {
1769
+ t0: Date.now(),
1770
+ collection: 'unknown',
1771
+ spanContext: captureSpanContextFromTracer(),
1772
+ };
1701
1773
  }
1702
1774
  next();
1703
1775
  });
@@ -1707,6 +1779,7 @@ function reproMongoosePlugin(cfg) {
1707
1779
  return;
1708
1780
  const meta = this.__repro_insert_meta || { t0: Date.now(), collection: 'unknown' };
1709
1781
  const resultMeta = Array.isArray(docs) ? { inserted: docs.length } : summarizeQueryResult('insertMany', docs);
1782
+ const spanContext = meta.spanContext || captureSpanContextFromTracer();
1710
1783
  emitDbQuery(cfg, sid, aid, {
1711
1784
  collection: meta.collection,
1712
1785
  op: 'insertMany',
@@ -1714,6 +1787,7 @@ function reproMongoosePlugin(cfg) {
1714
1787
  resultMeta,
1715
1788
  durMs: Date.now() - meta.t0,
1716
1789
  t: alignedNow(),
1790
+ spanContext,
1717
1791
  });
1718
1792
  });
1719
1793
  schema.pre('bulkWrite', { document: false, query: false }, function (next, ops) {
@@ -1722,10 +1796,15 @@ function reproMongoosePlugin(cfg) {
1722
1796
  t0: Date.now(),
1723
1797
  collection: this?.collection?.name || this?.model?.collection?.name || 'unknown',
1724
1798
  ops: sanitizeDbValue(ops),
1799
+ spanContext: captureSpanContextFromTracer(),
1725
1800
  };
1726
1801
  }
1727
1802
  catch {
1728
- this.__repro_bulk_meta = { t0: Date.now(), collection: 'unknown' };
1803
+ this.__repro_bulk_meta = {
1804
+ t0: Date.now(),
1805
+ collection: 'unknown',
1806
+ spanContext: captureSpanContextFromTracer(),
1807
+ };
1729
1808
  }
1730
1809
  next();
1731
1810
  });
@@ -1736,6 +1815,7 @@ function reproMongoosePlugin(cfg) {
1736
1815
  const meta = this.__repro_bulk_meta || { t0: Date.now(), collection: 'unknown' };
1737
1816
  const bulkResult = summarizeBulkResult(res);
1738
1817
  const resultMeta = { ...bulkResult, result: sanitizeResultForMeta(res?.result ?? res) };
1818
+ const spanContext = meta.spanContext || captureSpanContextFromTracer();
1739
1819
  emitDbQuery(cfg, sid, aid, {
1740
1820
  collection: meta.collection,
1741
1821
  op: 'bulkWrite',
@@ -1743,6 +1823,7 @@ function reproMongoosePlugin(cfg) {
1743
1823
  resultMeta,
1744
1824
  durMs: Date.now() - meta.t0,
1745
1825
  t: alignedNow(),
1826
+ spanContext,
1746
1827
  });
1747
1828
  });
1748
1829
  // Aggregate middleware (non-intrusive)
@@ -1754,11 +1835,17 @@ function reproMongoosePlugin(cfg) {
1754
1835
  this?._model?.collection?.name ||
1755
1836
  (this?.model && this.model.collection?.name) ||
1756
1837
  'unknown',
1838
+ spanContext: captureSpanContextFromTracer(),
1757
1839
  pipeline: sanitizeDbValue(this.pipeline?.() ?? this._pipeline ?? undefined),
1758
1840
  };
1759
1841
  }
1760
1842
  catch {
1761
- this.__repro_aggmeta = { t0: Date.now(), collection: 'unknown', pipeline: undefined };
1843
+ this.__repro_aggmeta = {
1844
+ t0: Date.now(),
1845
+ collection: 'unknown',
1846
+ pipeline: undefined,
1847
+ spanContext: captureSpanContextFromTracer(),
1848
+ };
1762
1849
  }
1763
1850
  next();
1764
1851
  });
@@ -1768,6 +1855,7 @@ function reproMongoosePlugin(cfg) {
1768
1855
  return;
1769
1856
  const meta = this.__repro_aggmeta || { t0: Date.now(), collection: 'unknown' };
1770
1857
  const resultMeta = summarizeQueryResult('aggregate', res);
1858
+ const spanContext = meta.spanContext || captureSpanContextFromTracer();
1771
1859
  emitDbQuery(cfg, sid, aid, {
1772
1860
  collection: meta.collection,
1773
1861
  op: 'aggregate',
@@ -1775,6 +1863,7 @@ function reproMongoosePlugin(cfg) {
1775
1863
  resultMeta,
1776
1864
  durMs: Date.now() - meta.t0,
1777
1865
  t: alignedNow(),
1866
+ spanContext,
1778
1867
  });
1779
1868
  });
1780
1869
  };
@@ -1891,18 +1980,19 @@ function dehydrateComplexValue(value) {
1891
1980
  function emitDbQuery(cfg, sid, aid, payload) {
1892
1981
  if (!sid)
1893
1982
  return;
1983
+ const dbEntry = attachSpanContext({
1984
+ collection: payload.collection,
1985
+ op: payload.op,
1986
+ query: payload.query ?? undefined,
1987
+ resultMeta: payload.resultMeta ?? undefined,
1988
+ durMs: payload.durMs ?? undefined,
1989
+ pk: null, before: null, after: null,
1990
+ error: payload.error ?? undefined,
1991
+ }, payload?.spanContext);
1894
1992
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, sid, {
1895
1993
  entries: [{
1896
1994
  actionId: aid ?? null,
1897
- db: [{
1898
- collection: payload.collection,
1899
- op: payload.op,
1900
- query: payload.query ?? undefined,
1901
- resultMeta: payload.resultMeta ?? undefined,
1902
- durMs: payload.durMs ?? undefined,
1903
- pk: null, before: null, after: null,
1904
- error: payload.error ?? undefined,
1905
- }],
1995
+ db: [dbEntry],
1906
1996
  t: payload.t,
1907
1997
  }]
1908
1998
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repro-nest",
3
- "version": "0.0.207",
3
+ "version": "0.0.209",
4
4
  "description": "Repro Nest SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -172,10 +172,18 @@ function patchAllKnownMongooseInstances() {
172
172
  }
173
173
 
174
174
  // ====== tiny, safe tracer auto-init (no node_modules patches) ======
175
+ type SpanContext = {
176
+ traceId: string | null;
177
+ spanId: string | number | null;
178
+ parentSpanId: string | number | null;
179
+ depth: number | null;
180
+ };
181
+
175
182
  type TracerApi = {
176
183
  init?: (opts: any) => void;
177
184
  tracer?: { on: (fn: (ev: any) => void) => () => void };
178
185
  getCurrentTraceId?: () => string | null;
186
+ getCurrentSpanContext?: () => SpanContext | null;
179
187
  patchHttp?: () => void; // optional in your tracer
180
188
  setFunctionLogsEnabled?: (enabled: boolean) => void;
181
189
  };
@@ -210,7 +218,6 @@ type TraceEventRecord = {
210
218
  spanId?: string | number | null;
211
219
  parentSpanId?: string | number | null;
212
220
  args?: any;
213
- receiver?: any;
214
221
  returnValue?: any;
215
222
  threw?: boolean;
216
223
  error?: any;
@@ -641,6 +648,38 @@ export function initReproTracing(opts?: ReproTracingInitOptions) {
641
648
  /** Optional helper if users want to check it. */
642
649
  export function isReproTracingEnabled() { return __TRACER_READY; }
643
650
 
651
+ function captureSpanContextFromTracer(): SpanContext | null {
652
+ try {
653
+ const ctx = __TRACER__?.getCurrentSpanContext?.();
654
+ if (ctx) {
655
+ const span: SpanContext = {
656
+ traceId: ctx.traceId ?? __TRACER__?.getCurrentTraceId?.() ?? null,
657
+ spanId: ctx.spanId ?? null,
658
+ parentSpanId: ctx.parentSpanId ?? null,
659
+ depth: ctx.depth ?? null,
660
+ };
661
+ if (span.traceId || span.spanId !== null || span.parentSpanId !== null) {
662
+ return span;
663
+ }
664
+ } else if (__TRACER__?.getCurrentTraceId) {
665
+ const traceId = __TRACER__?.getCurrentTraceId?.() ?? null;
666
+ if (traceId) {
667
+ return { traceId, spanId: null, parentSpanId: null, depth: null };
668
+ }
669
+ }
670
+ } catch {}
671
+ return null;
672
+ }
673
+
674
+ function attachSpanContext<T extends Record<string, any>>(target: T, span?: SpanContext | null): T {
675
+ if (!target) return target;
676
+ const ctx = span ?? captureSpanContextFromTracer();
677
+ if (ctx) {
678
+ try { (target as any).spanContext = ctx; } catch {}
679
+ }
680
+ return target;
681
+ }
682
+
644
683
  type Ctx = { sid?: string; aid?: string; clockSkewMs?: number };
645
684
  const als = new AsyncLocalStorage<Ctx>();
646
685
  const getCtx = () => als.getStore() || {};
@@ -1533,9 +1572,6 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
1533
1572
  if (ev.args !== undefined) {
1534
1573
  evt.args = sanitizeTraceArgs(ev.args);
1535
1574
  }
1536
- if (ev.receiver !== undefined) {
1537
- evt.receiver = sanitizeTraceValue(ev.receiver);
1538
- }
1539
1575
  if (ev.returnValue !== undefined) {
1540
1576
  evt.returnValue = sanitizeTraceValue(ev.returnValue);
1541
1577
  }
@@ -1749,6 +1785,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1749
1785
  wasNew: this.isNew,
1750
1786
  before,
1751
1787
  collection: resolveCollectionOrWarn(this, 'doc'),
1788
+ spanContext: captureSpanContextFromTracer(),
1752
1789
  };
1753
1790
  next();
1754
1791
  });
@@ -1762,6 +1799,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1762
1799
  const before = meta.before ?? null;
1763
1800
  const after = this.toObject({ depopulate: true });
1764
1801
  const collection = meta.collection || resolveCollectionOrWarn(this, 'doc');
1802
+ const spanContext = meta.spanContext || captureSpanContextFromTracer();
1765
1803
 
1766
1804
  const query = meta.wasNew
1767
1805
  ? { op: 'insertOne', doc: after }
@@ -1770,7 +1808,14 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1770
1808
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, (getCtx() as Ctx).sid!, {
1771
1809
  entries: [{
1772
1810
  actionId: (getCtx() as Ctx).aid!,
1773
- db: [{ collection, pk: { _id: (this as any)._id }, before, after, op: meta.wasNew ? 'insert' : 'update', query }],
1811
+ db: [attachSpanContext({
1812
+ collection,
1813
+ pk: { _id: (this as any)._id },
1814
+ before,
1815
+ after,
1816
+ op: meta.wasNew ? 'insert' : 'update',
1817
+ query,
1818
+ }, spanContext)],
1774
1819
  t: alignedNow(),
1775
1820
  }]
1776
1821
  });
@@ -1786,6 +1831,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1786
1831
  (this as any).__repro_before = await model.findOne(filter).lean().exec();
1787
1832
  this.setOptions({ new: true });
1788
1833
  (this as any).__repro_collection = resolveCollectionOrWarn(this, 'query');
1834
+ (this as any).__repro_spanContext = captureSpanContextFromTracer();
1789
1835
  } catch {}
1790
1836
  next();
1791
1837
  });
@@ -1797,12 +1843,19 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1797
1843
  const before = (this as any).__repro_before ?? null;
1798
1844
  const after = res ?? null;
1799
1845
  const collection = (this as any).__repro_collection || resolveCollectionOrWarn(this, 'query');
1846
+ const spanContext = (this as any).__repro_spanContext || captureSpanContextFromTracer();
1800
1847
  const pk = after?._id ?? before?._id;
1801
1848
 
1802
1849
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, (getCtx() as Ctx).sid!, {
1803
1850
  entries: [{
1804
1851
  actionId: (getCtx() as Ctx).aid!,
1805
- db: [{ collection, pk: { _id: pk }, before, after, op: after && before ? 'update' : after ? 'insert' : 'update' }],
1852
+ db: [attachSpanContext({
1853
+ collection,
1854
+ pk: { _id: pk },
1855
+ before,
1856
+ after,
1857
+ op: after && before ? 'update' : after ? 'insert' : 'update',
1858
+ }, spanContext)],
1806
1859
  t: alignedNow()
1807
1860
  }]
1808
1861
  });
@@ -1816,6 +1869,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1816
1869
  (this as any).__repro_before = await (this.model as Model<any>).findOne(filter).lean().exec();
1817
1870
  (this as any).__repro_collection = resolveCollectionOrWarn(this, 'query');
1818
1871
  (this as any).__repro_filter = filter;
1872
+ (this as any).__repro_spanContext = captureSpanContextFromTracer();
1819
1873
  } catch {}
1820
1874
  next();
1821
1875
  });
@@ -1826,10 +1880,18 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1826
1880
  if (!before) return;
1827
1881
  const collection = (this as any).__repro_collection || resolveCollectionOrWarn(this, 'query');
1828
1882
  const filter = (this as any).__repro_filter ?? { _id: before._id };
1883
+ const spanContext = (this as any).__repro_spanContext || captureSpanContextFromTracer();
1829
1884
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, (getCtx() as Ctx).sid!, {
1830
1885
  entries: [{
1831
1886
  actionId: (getCtx() as Ctx).aid!,
1832
- db: [{ collection, pk: { _id: before._id }, before, after: null, op: 'delete', query: { filter } }],
1887
+ db: [attachSpanContext({
1888
+ collection,
1889
+ pk: { _id: before._id },
1890
+ before,
1891
+ after: null,
1892
+ op: 'delete',
1893
+ query: { filter },
1894
+ }, spanContext)],
1833
1895
  t: alignedNow()
1834
1896
  }]
1835
1897
  });
@@ -1871,13 +1933,19 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1871
1933
  t0: Date.now(),
1872
1934
  collection: this?.model?.collection?.name || 'unknown',
1873
1935
  op,
1936
+ spanContext: captureSpanContextFromTracer(),
1874
1937
  filter: sanitizeDbValue(this.getFilter?.() ?? this._conditions ?? undefined),
1875
1938
  update: sanitizeDbValue(this.getUpdate?.() ?? this._update ?? undefined),
1876
1939
  projection: sanitizeDbValue(this.projection?.() ?? this._fields ?? undefined),
1877
1940
  options: sanitizeDbValue(this.getOptions?.() ?? this.options ?? undefined),
1878
1941
  };
1879
1942
  } catch {
1880
- (this as any).__repro_qmeta = { t0: Date.now(), collection: 'unknown', op };
1943
+ (this as any).__repro_qmeta = {
1944
+ t0: Date.now(),
1945
+ collection: 'unknown',
1946
+ op,
1947
+ spanContext: captureSpanContextFromTracer(),
1948
+ };
1881
1949
  }
1882
1950
  next();
1883
1951
  });
@@ -1888,6 +1956,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1888
1956
 
1889
1957
  const meta = (this as any).__repro_qmeta || { t0: Date.now(), collection: 'unknown', op };
1890
1958
  const resultMeta = summarizeQueryResult(op, res);
1959
+ const spanContext = meta.spanContext || captureSpanContextFromTracer();
1891
1960
 
1892
1961
  emitDbQuery(cfg, sid, aid, {
1893
1962
  collection: meta.collection,
@@ -1896,6 +1965,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1896
1965
  resultMeta,
1897
1966
  durMs: Date.now() - meta.t0,
1898
1967
  t: alignedNow(),
1968
+ spanContext,
1899
1969
  });
1900
1970
  });
1901
1971
  }
@@ -1910,9 +1980,14 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1910
1980
  t0: Date.now(),
1911
1981
  collection: this?.collection?.name || this?.model?.collection?.name || 'unknown',
1912
1982
  docs: sanitizeDbValue(docs),
1983
+ spanContext: captureSpanContextFromTracer(),
1913
1984
  };
1914
1985
  } catch {
1915
- (this as any).__repro_insert_meta = { t0: Date.now(), collection: 'unknown' };
1986
+ (this as any).__repro_insert_meta = {
1987
+ t0: Date.now(),
1988
+ collection: 'unknown',
1989
+ spanContext: captureSpanContextFromTracer(),
1990
+ };
1916
1991
  }
1917
1992
  next();
1918
1993
  } as any);
@@ -1922,6 +1997,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1922
1997
  if (!sid) return;
1923
1998
  const meta = (this as any).__repro_insert_meta || { t0: Date.now(), collection: 'unknown' };
1924
1999
  const resultMeta = Array.isArray(docs) ? { inserted: docs.length } : summarizeQueryResult('insertMany', docs);
2000
+ const spanContext = meta.spanContext || captureSpanContextFromTracer();
1925
2001
 
1926
2002
  emitDbQuery(cfg, sid, aid, {
1927
2003
  collection: meta.collection,
@@ -1930,6 +2006,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1930
2006
  resultMeta,
1931
2007
  durMs: Date.now() - meta.t0,
1932
2008
  t: alignedNow(),
2009
+ spanContext,
1933
2010
  });
1934
2011
  } as any);
1935
2012
 
@@ -1939,9 +2016,14 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1939
2016
  t0: Date.now(),
1940
2017
  collection: this?.collection?.name || this?.model?.collection?.name || 'unknown',
1941
2018
  ops: sanitizeDbValue(ops),
2019
+ spanContext: captureSpanContextFromTracer(),
1942
2020
  };
1943
2021
  } catch {
1944
- (this as any).__repro_bulk_meta = { t0: Date.now(), collection: 'unknown' };
2022
+ (this as any).__repro_bulk_meta = {
2023
+ t0: Date.now(),
2024
+ collection: 'unknown',
2025
+ spanContext: captureSpanContextFromTracer(),
2026
+ };
1945
2027
  }
1946
2028
  next();
1947
2029
  } as any);
@@ -1952,6 +2034,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1952
2034
  const meta = (this as any).__repro_bulk_meta || { t0: Date.now(), collection: 'unknown' };
1953
2035
  const bulkResult = summarizeBulkResult(res);
1954
2036
  const resultMeta = { ...bulkResult, result: sanitizeResultForMeta(res?.result ?? res) };
2037
+ const spanContext = meta.spanContext || captureSpanContextFromTracer();
1955
2038
 
1956
2039
  emitDbQuery(cfg, sid, aid, {
1957
2040
  collection: meta.collection,
@@ -1960,6 +2043,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1960
2043
  resultMeta,
1961
2044
  durMs: Date.now() - meta.t0,
1962
2045
  t: alignedNow(),
2046
+ spanContext,
1963
2047
  });
1964
2048
  } as any);
1965
2049
 
@@ -1973,10 +2057,16 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1973
2057
  this?._model?.collection?.name ||
1974
2058
  (this?.model && this.model.collection?.name) ||
1975
2059
  'unknown',
2060
+ spanContext: captureSpanContextFromTracer(),
1976
2061
  pipeline: sanitizeDbValue(this.pipeline?.() ?? this._pipeline ?? undefined),
1977
2062
  };
1978
2063
  } catch {
1979
- (this as any).__repro_aggmeta = { t0: Date.now(), collection: 'unknown', pipeline: undefined };
2064
+ (this as any).__repro_aggmeta = {
2065
+ t0: Date.now(),
2066
+ collection: 'unknown',
2067
+ pipeline: undefined,
2068
+ spanContext: captureSpanContextFromTracer(),
2069
+ };
1980
2070
  }
1981
2071
  next();
1982
2072
  });
@@ -1987,6 +2077,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1987
2077
 
1988
2078
  const meta = (this as any).__repro_aggmeta || { t0: Date.now(), collection: 'unknown' };
1989
2079
  const resultMeta = summarizeQueryResult('aggregate', res);
2080
+ const spanContext = meta.spanContext || captureSpanContextFromTracer();
1990
2081
 
1991
2082
  emitDbQuery(cfg, sid, aid, {
1992
2083
  collection: meta.collection,
@@ -1995,6 +2086,7 @@ export function reproMongoosePlugin(cfg: { appId: string; tenantId: string; appS
1995
2086
  resultMeta,
1996
2087
  durMs: Date.now() - meta.t0,
1997
2088
  t: alignedNow(),
2089
+ spanContext,
1998
2090
  });
1999
2091
  });
2000
2092
  };
@@ -2104,18 +2196,19 @@ function dehydrateComplexValue(value: any) {
2104
2196
 
2105
2197
  function emitDbQuery(cfg: any, sid?: string, aid?: string, payload?: any) {
2106
2198
  if (!sid) return;
2199
+ const dbEntry = attachSpanContext({
2200
+ collection: payload.collection,
2201
+ op: payload.op,
2202
+ query: payload.query ?? undefined,
2203
+ resultMeta: payload.resultMeta ?? undefined,
2204
+ durMs: payload.durMs ?? undefined,
2205
+ pk: null, before: null, after: null,
2206
+ error: payload.error ?? undefined,
2207
+ }, payload?.spanContext);
2107
2208
  post(cfg.apiBase, cfg.tenantId, cfg.appId, cfg.appSecret, sid, {
2108
2209
  entries: [{
2109
2210
  actionId: aid ?? null,
2110
- db: [{
2111
- collection: payload.collection,
2112
- op: payload.op,
2113
- query: payload.query ?? undefined,
2114
- resultMeta: payload.resultMeta ?? undefined,
2115
- durMs: payload.durMs ?? undefined,
2116
- pk: null, before: null, after: null,
2117
- error: payload.error ?? undefined,
2118
- }],
2211
+ db: [dbEntry],
2119
2212
  t: payload.t,
2120
2213
  }]
2121
2214
  });
package/tracer/index.js CHANGED
@@ -9,6 +9,7 @@ const {
9
9
  printV8,
10
10
  patchConsole,
11
11
  getCurrentTraceId,
12
+ getCurrentSpanContext,
12
13
  setFunctionLogsEnabled
13
14
  } = require('./runtime');
14
15
  const { installCJS } = require('./cjs-hook');
@@ -60,6 +61,7 @@ function api(){
60
61
  tracer: trace,
61
62
  withTrace: trace.withTrace,
62
63
  getCurrentTraceId,
64
+ getCurrentSpanContext,
63
65
  setFunctionLogsEnabled,
64
66
  };
65
67
  }
package/tracer/runtime.js CHANGED
@@ -132,7 +132,6 @@ const trace = {
132
132
  traceId: ctx.traceId,
133
133
  depth: ctx.depth,
134
134
  args: detail?.args,
135
- receiver: detail?.receiver,
136
135
  spanId: span.id,
137
136
  parentSpanId: span.parentId
138
137
  });
@@ -160,8 +159,7 @@ const trace = {
160
159
  returnValue: detail?.returnValue,
161
160
  error: detail?.error,
162
161
  threw: detail?.threw === true,
163
- unawaited: detail?.unawaited === true || frameUnawaited,
164
- receiver: detail?.receiver
162
+ unawaited: detail?.unawaited === true || frameUnawaited
165
163
  };
166
164
 
167
165
  const promiseTaggedUnawaited = !!(baseDetail.returnValue && baseDetail.returnValue[SYM_UNAWAITED]);
@@ -181,9 +179,6 @@ const trace = {
181
179
  unawaited: overrides.hasOwnProperty('unawaited')
182
180
  ? overrides.unawaited
183
181
  : forceUnawaited,
184
- receiver: overrides.hasOwnProperty('receiver')
185
- ? overrides.receiver
186
- : baseDetail.receiver,
187
182
  args: overrides.hasOwnProperty('args')
188
183
  ? overrides.args
189
184
  : baseDetail.args
@@ -204,7 +199,6 @@ const trace = {
204
199
  threw: finalDetail.threw === true,
205
200
  error: finalDetail.error,
206
201
  args: finalDetail.args,
207
- receiver: finalDetail.receiver,
208
202
  unawaited: finalDetail.unawaited === true
209
203
  });
210
204
  };
@@ -481,24 +475,6 @@ function forkAlsStoreForUnawaited(baseStore) {
481
475
  return cloned;
482
476
  }
483
477
 
484
- // Only capture receiver/collection snapshots for common array iteration helpers to keep noise low.
485
- const RECEIVER_METHOD_NAMES = new Set([
486
- // Array iterators
487
- 'map', 'forEach', 'filter', 'find', 'findIndex', 'findLast', 'findLastIndex',
488
- 'some', 'every', 'reduce', 'reduceRight', 'flatMap', 'flat',
489
- // Set / Map mutators
490
- 'add', 'delete', 'clear', 'set'
491
- ]);
492
-
493
- function shouldCaptureReceiver(label, receiver) {
494
- if (!label || receiver === null || receiver === undefined) return false;
495
- const method = String(label).split('.').pop() || '';
496
- if (!RECEIVER_METHOD_NAMES.has(method)) return false;
497
- if (Array.isArray(receiver)) return true;
498
- if (typeof receiver === 'object' && typeof receiver[Symbol.iterator] === 'function') return true;
499
- return false;
500
- }
501
-
502
478
  // ========= Generic call-site shim (used by Babel transform) =========
503
479
  // Decides whether to emit a top-level event based on callee origin tags.
504
480
  // No hardcoded library names or file paths.
@@ -620,15 +596,13 @@ if (!global.__repro_call) {
620
596
  ? (label && label.length ? label : fn.name)
621
597
  : '(anonymous)';
622
598
  const sourceFile = fn[SYM_SRC_FILE];
623
- const receiverForTrace = shouldCaptureReceiver(label, thisArg) ? thisArg : undefined;
624
599
  const meta = {
625
- // Prefer callsite file/line so traces point to where the function was invoked.
626
- file: callFile || sourceFile || null,
627
- line: callLine ?? null,
600
+ file: sourceFile || callFile || null,
601
+ line: sourceFile ? null : (callLine || null),
628
602
  parentSpanId: forcedParentSpanId
629
603
  };
630
604
 
631
- trace.enter(name, meta, { args, receiver: receiverForTrace });
605
+ trace.enter(name, meta, { args });
632
606
  // After entering, snapshot a clean store that captures the parent + this call’s span,
633
607
  // so callbacks invoked during the callee run are isolated per invocation.
634
608
  const snapshotForArgs = cloneStore(als.getStore());
@@ -643,8 +617,7 @@ if (!global.__repro_call) {
643
617
  const exitDetailBase = {
644
618
  returnValue: out,
645
619
  args,
646
- unawaited: shouldForceExit,
647
- receiver: receiverForTrace
620
+ unawaited: shouldForceExit
648
621
  };
649
622
 
650
623
  if (shouldForceExit) markPromiseUnawaited(out);
@@ -686,8 +659,7 @@ if (!global.__repro_call) {
686
659
  args,
687
660
  threw,
688
661
  error,
689
- unawaited: shouldForceExit,
690
- receiver: receiverForTrace
662
+ unawaited: shouldForceExit
691
663
  };
692
664
  runExit(detail);
693
665
  return value;
@@ -707,7 +679,7 @@ if (!global.__repro_call) {
707
679
  runExit(exitDetailBase);
708
680
  return out;
709
681
  } catch (e) {
710
- trace.exit({ fn: name, file: meta.file, line: meta.line }, { threw: true, error: e, args, receiver: receiverForTrace });
682
+ trace.exit({ fn: name, file: meta.file, line: meta.line }, { threw: true, error: e, args });
711
683
  throw e;
712
684
  } finally {
713
685
  if (pendingMarker) {
@@ -869,6 +841,32 @@ function getCurrentTraceId() {
869
841
  return s && s.traceId || null;
870
842
  }
871
843
 
844
+ function getCurrentSpanContext() {
845
+ try {
846
+ const store = als.getStore();
847
+ if (!store) return null;
848
+
849
+ const stack = Array.isArray(store.__repro_span_stack) ? store.__repro_span_stack : [];
850
+ const top = stack.length ? stack[stack.length - 1] : null;
851
+ const spanId = top && top.id != null ? top.id : null;
852
+ const parentSpanId = top && top.parentId != null
853
+ ? top.parentId
854
+ : (stack.length >= 2 ? (stack[stack.length - 2]?.id ?? null) : null);
855
+ const depth = top && top.depth != null
856
+ ? top.depth
857
+ : (typeof store.depth === 'number'
858
+ ? store.depth
859
+ : (stack.length ? stack.length : null));
860
+
861
+ const traceId = store.traceId || null;
862
+
863
+ if (spanId === null && parentSpanId === null && traceId === null) return null;
864
+ return { traceId, spanId, parentSpanId, depth: depth == null ? null : depth };
865
+ } catch {
866
+ return null;
867
+ }
868
+ }
869
+
872
870
  // ---- Promise propagation fallback: ensure continuations run with the captured store ----
873
871
  let PROMISE_PATCHED = false;
874
872
  function patchPromise() {
@@ -913,6 +911,7 @@ module.exports = {
913
911
  printV8,
914
912
  patchConsole,
915
913
  getCurrentTraceId,
914
+ getCurrentSpanContext,
916
915
  setFunctionLogsEnabled,
917
916
  // export symbols so the require hook can tag function origins
918
917
  SYM_SRC_FILE,