@reproapp/node-sdk 0.0.38 → 0.0.41

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
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.__reproTestHooks = exports.initRepro = exports.patchSendgridMail = exports.patchMongoDb = exports.patchRedis = exports.patchAmqplib = exports.patchKafkaJs = exports.reproMongoosePlugin = exports.reproMiddleware = exports.__materializePendingTraceEventsForWorker = exports.isReproTracingEnabled = exports.initReproTracing = exports.disableReproTraceLogs = exports.enableReproTraceLogs = exports.setReproTraceLogsEnabled = exports.setDisabledTraceFiles = exports.setDisabledFunctionTypes = exports.setDisabledFunctionTraces = void 0;
3
+ exports.__reproTestHooks = exports.initRepro = exports.patchSendgridMail = exports.patchMongoDb = exports.patchPostgreSql = exports.patchRedis = exports.patchAmqplib = exports.patchKafkaJs = exports.reproMongoosePlugin = exports.reproMiddleware = exports.__materializePendingTraceEventsForWorker = exports.isReproTracingEnabled = exports.initReproTracing = exports.disableReproTraceLogs = exports.enableReproTraceLogs = exports.setReproTraceLogsEnabled = exports.setDisabledTraceFiles = exports.setDisabledFunctionTypes = exports.setDisabledFunctionTraces = void 0;
4
4
  const mongoose = require("mongoose");
5
5
  const async_hooks_1 = require("async_hooks");
6
6
  const crypto_1 = require("crypto");
@@ -305,6 +305,9 @@ const KAFKA_HEADER_SESSION_ID = 'x-bug-session-id';
305
305
  const KAFKA_HEADER_ACTION_ID = 'x-bug-action-id';
306
306
  const DEFAULT_INGEST_BASE = 'http://localhost:8080';
307
307
  const DEFAULT_INGEST_PATH = '/v1/ingest/events';
308
+ const DEFAULT_LIVE_SESSION_DURATION_MS = 3 * 60000;
309
+ const DEFAULT_LIVE_SEGMENT_IDLE_MS = 15000;
310
+ const DEFAULT_LIVE_SEGMENT_DURATION_MS = DEFAULT_LIVE_SESSION_DURATION_MS;
308
311
  function escapeRx(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
309
312
  let __TRACER__ = null;
310
313
  let __TRACER_READY = false;
@@ -819,6 +822,27 @@ function buildRequestCaptureManifestPayload(scope, traceBatchTotal, closedAtMs)
819
822
  closedAt,
820
823
  };
821
824
  }
825
+ function emitRequestCaptureStart(cfg, sessionId, actionId, scope, openedAtMs) {
826
+ if (!sessionId) {
827
+ return;
828
+ }
829
+ const openedAt = typeof openedAtMs === 'number' && Number.isFinite(openedAtMs)
830
+ ? openedAtMs
831
+ : alignedNow();
832
+ post(cfg, sessionId, {
833
+ entries: [{
834
+ actionId: actionId ?? null,
835
+ requestRid: scope.requestRid,
836
+ requestCaptureStart: {
837
+ scopeId: `req:${scope.requestRid}`,
838
+ requestRid: scope.requestRid,
839
+ transport: scope.transport,
840
+ openedAt,
841
+ },
842
+ t: openedAt,
843
+ }],
844
+ }, { priority: 'high' });
845
+ }
822
846
  const als = new async_hooks_1.AsyncLocalStorage();
823
847
  const getCtx = () => als.getStore() || {};
824
848
  function normalizeNativeMongoSuppressionOp(op) {
@@ -1681,6 +1705,299 @@ function toIngestConfig(cfg) {
1681
1705
  schemaVersion: cfg.schemaVersion,
1682
1706
  };
1683
1707
  }
1708
+ function normalizeLiveModeConfig(cfg) {
1709
+ const liveMode = cfg.liveMode;
1710
+ if (liveMode === true) {
1711
+ return { enabled: true };
1712
+ }
1713
+ if (!liveMode || typeof liveMode !== 'object') {
1714
+ return null;
1715
+ }
1716
+ if (liveMode.enabled === false) {
1717
+ return null;
1718
+ }
1719
+ return liveMode;
1720
+ }
1721
+ let backendLiveTimingOverrideForTest = null;
1722
+ function positiveInternalDuration(value, fallback) {
1723
+ const numeric = Number(value);
1724
+ if (!Number.isFinite(numeric) || numeric <= 0)
1725
+ return fallback;
1726
+ return Math.max(1, Math.trunc(numeric));
1727
+ }
1728
+ function getBackendLiveTiming() {
1729
+ return {
1730
+ sessionMaxDurationMs: positiveInternalDuration(backendLiveTimingOverrideForTest?.sessionMaxDurationMs, DEFAULT_LIVE_SESSION_DURATION_MS),
1731
+ segmentMaxDurationMs: positiveInternalDuration(backendLiveTimingOverrideForTest?.segmentMaxDurationMs, DEFAULT_LIVE_SEGMENT_DURATION_MS),
1732
+ segmentIdleMs: positiveInternalDuration(backendLiveTimingOverrideForTest?.segmentIdleMs, DEFAULT_LIVE_SEGMENT_IDLE_MS),
1733
+ };
1734
+ }
1735
+ function normalizeLiveActorId(value) {
1736
+ if (value === undefined || value === null)
1737
+ return null;
1738
+ const normalized = String(value).trim();
1739
+ return normalized.length ? normalized : null;
1740
+ }
1741
+ function normalizeLiveActorLabels(value) {
1742
+ if (!value || typeof value !== 'object' || Array.isArray(value))
1743
+ return undefined;
1744
+ const labels = {};
1745
+ for (const [key, rawValue] of Object.entries(value)) {
1746
+ const normalizedKey = key.trim();
1747
+ if (!normalizedKey || rawValue === undefined || rawValue === null)
1748
+ continue;
1749
+ const normalizedValue = String(rawValue).trim();
1750
+ if (normalizedValue)
1751
+ labels[normalizedKey] = normalizedValue;
1752
+ }
1753
+ return Object.keys(labels).length ? labels : undefined;
1754
+ }
1755
+ function newSessionId(base = Date.now()) {
1756
+ return `S_${Math.max(0, Math.trunc(base))}_${(0, crypto_1.randomUUID)().slice(0, 8)}`;
1757
+ }
1758
+ function newActionId(base = Date.now()) {
1759
+ return `A_${Math.max(0, Math.trunc(base))}_${(0, crypto_1.randomUUID)().slice(0, 8)}`;
1760
+ }
1761
+ function resolveLiveApiBase(cfg, liveMode) {
1762
+ const env = typeof process !== 'undefined' ? process?.env : undefined;
1763
+ const raw = liveMode?.apiBase ||
1764
+ cfg.apiBase ||
1765
+ env?.REPRO_API_BASE_URL ||
1766
+ env?.REPRO_API_BASE ||
1767
+ cfg.privacy?.apiBase ||
1768
+ null;
1769
+ if (typeof raw !== 'string' || !raw.trim())
1770
+ return null;
1771
+ return raw.trim().replace(/\/+$/, '');
1772
+ }
1773
+ function liveApiHeaders(cfg) {
1774
+ const headers = {
1775
+ 'Content-Type': 'application/json',
1776
+ 'X-App-Id': cfg.appId,
1777
+ };
1778
+ if (cfg.appSecret) {
1779
+ headers['X-App-Secret'] = cfg.appSecret;
1780
+ }
1781
+ if (cfg.appName) {
1782
+ headers['X-App-Name'] = cfg.appName;
1783
+ }
1784
+ return headers;
1785
+ }
1786
+ async function postLiveApi(cfg, liveMode, path, body) {
1787
+ await postLiveApiJson(cfg, liveMode, path, body);
1788
+ }
1789
+ async function postLiveApiJson(cfg, liveMode, path, body) {
1790
+ const apiBase = resolveLiveApiBase(cfg, liveMode);
1791
+ const fetchImpl = globalThis.fetch;
1792
+ if (!apiBase || !cfg.appId || !cfg.appSecret || typeof fetchImpl !== 'function') {
1793
+ return null;
1794
+ }
1795
+ try {
1796
+ const res = await fetchImpl(`${apiBase}${path}`, {
1797
+ method: 'POST',
1798
+ headers: liveApiHeaders(cfg),
1799
+ body: JSON.stringify(body),
1800
+ });
1801
+ if (!res?.ok) {
1802
+ return null;
1803
+ }
1804
+ try {
1805
+ return await res.json();
1806
+ }
1807
+ catch {
1808
+ return null;
1809
+ }
1810
+ }
1811
+ catch {
1812
+ // never break user code
1813
+ return null;
1814
+ }
1815
+ }
1816
+ function enqueueLiveSessionStart(cfg, liveMode, payload) {
1817
+ scheduleSdkBackgroundWork(() => postLiveApi(cfg, liveMode, '/v1/live-sessions', payload), { priority: 'high' });
1818
+ }
1819
+ function enqueueLiveSessionFinish(cfg, liveMode, sessionId) {
1820
+ scheduleSdkBackgroundWork(() => postLiveApi(cfg, liveMode, `/v1/live-sessions/${encodeURIComponent(sessionId)}/finish`, { notes: '' }), { priority: 'high' });
1821
+ }
1822
+ function emitBackendLiveSessionManifest(cfg, session, options) {
1823
+ post(cfg, session.sessionId, {
1824
+ entries: [{
1825
+ sessionCaptureManifest: {
1826
+ mode: 'backend-only',
1827
+ captureMode: 'backend-only',
1828
+ sessionKind: options.sessionKind,
1829
+ parentSessionId: options.parentSessionId ?? null,
1830
+ previousSessionId: options.previousSessionId ?? null,
1831
+ actorId: options.actorId,
1832
+ actorType: options.actorType,
1833
+ actorLabels: options.actorLabels,
1834
+ expected: {
1835
+ frontendActionDoc: 0,
1836
+ rrwebChunk: 0,
1837
+ frontendSessionEnd: 0,
1838
+ },
1839
+ closedAt: options.closedAt,
1840
+ },
1841
+ t: options.closedAt,
1842
+ }],
1843
+ }, { priority: 'high' });
1844
+ }
1845
+ function closeBackendLiveParent(cfg, liveMode, state, parent, closedAt) {
1846
+ if (parent.closed) {
1847
+ return;
1848
+ }
1849
+ parent.closed = true;
1850
+ if (parent.closeTimer) {
1851
+ try {
1852
+ clearTimeout(parent.closeTimer);
1853
+ }
1854
+ catch { }
1855
+ parent.closeTimer = null;
1856
+ }
1857
+ state.previousParentSessionId = parent.sessionId;
1858
+ if (state.parent === parent) {
1859
+ state.parent = null;
1860
+ }
1861
+ emitBackendLiveSessionManifest(cfg, parent, {
1862
+ sessionKind: 'parent',
1863
+ actorId: parent.actorId,
1864
+ actorType: parent.actorType,
1865
+ actorLabels: parent.actorLabels,
1866
+ previousSessionId: parent.previousSessionId,
1867
+ closedAt,
1868
+ });
1869
+ enqueueLiveSessionFinish(cfg, liveMode, parent.sessionId);
1870
+ }
1871
+ function scheduleBackendLiveParentClose(cfg, liveMode, state, parent) {
1872
+ if (parent.closed) {
1873
+ return;
1874
+ }
1875
+ if (parent.closeTimer) {
1876
+ try {
1877
+ clearTimeout(parent.closeTimer);
1878
+ }
1879
+ catch { }
1880
+ parent.closeTimer = null;
1881
+ }
1882
+ const now = Date.now();
1883
+ const activeChild = state.activeChild;
1884
+ const activeChildBelongsToParent = activeChild?.parentSessionId === parent.sessionId;
1885
+ const closeAt = activeChildBelongsToParent && now >= parent.expiresAt
1886
+ ? Math.max(parent.expiresAt, activeChild.closeDeadline, now + 1)
1887
+ : parent.expiresAt;
1888
+ parent.closeTimer = setTimeout(() => {
1889
+ parent.closeTimer = null;
1890
+ if (parent.closed || state.parent !== parent) {
1891
+ return;
1892
+ }
1893
+ const currentChild = state.activeChild;
1894
+ if (currentChild?.parentSessionId === parent.sessionId) {
1895
+ if (currentChild.requestsInFlight <= 0) {
1896
+ scheduleBackendLiveChildClose(cfg, liveMode, state, currentChild);
1897
+ }
1898
+ scheduleBackendLiveParentClose(cfg, liveMode, state, parent);
1899
+ return;
1900
+ }
1901
+ closeBackendLiveParent(cfg, liveMode, state, parent, Date.now());
1902
+ }, Math.max(0, closeAt - now));
1903
+ try {
1904
+ parent.closeTimer.unref?.();
1905
+ }
1906
+ catch { }
1907
+ }
1908
+ function scheduleBackendLiveChildClose(cfg, liveMode, state, child) {
1909
+ if (child.closeTimer) {
1910
+ try {
1911
+ clearTimeout(child.closeTimer);
1912
+ }
1913
+ catch { }
1914
+ child.closeTimer = null;
1915
+ }
1916
+ const delay = Math.max(0, child.closeDeadline - Date.now());
1917
+ child.closeTimer = setTimeout(() => {
1918
+ child.closeTimer = null;
1919
+ if (child.requestsInFlight > 0 || Date.now() < child.closeDeadline) {
1920
+ scheduleBackendLiveChildClose(cfg, liveMode, state, child);
1921
+ return;
1922
+ }
1923
+ if (state.activeChild === child) {
1924
+ state.activeChild = null;
1925
+ }
1926
+ state.previousChildSessionId = child.sessionId;
1927
+ const closedAt = Date.now();
1928
+ emitBackendLiveSessionManifest(cfg, child, {
1929
+ sessionKind: 'child',
1930
+ actorId: child.actorId,
1931
+ actorType: child.actorType,
1932
+ actorLabels: child.actorLabels,
1933
+ parentSessionId: child.parentSessionId,
1934
+ previousSessionId: child.previousSessionId,
1935
+ closedAt,
1936
+ });
1937
+ enqueueLiveSessionFinish(cfg, liveMode, child.sessionId);
1938
+ }, delay);
1939
+ try {
1940
+ child.closeTimer.unref?.();
1941
+ }
1942
+ catch { }
1943
+ }
1944
+ function releaseBackendLiveRequest(cfg, liveMode, state, child, finishedAt) {
1945
+ child.requestsInFlight = Math.max(0, child.requestsInFlight - 1);
1946
+ const idleMs = getBackendLiveTiming().segmentIdleMs;
1947
+ child.closeDeadline = Math.max(child.closeDeadline, finishedAt + idleMs);
1948
+ if (child.requestsInFlight <= 0) {
1949
+ scheduleBackendLiveChildClose(cfg, liveMode, state, child);
1950
+ }
1951
+ }
1952
+ async function resolveBackendLiveContext(cfg, req, requestStart) {
1953
+ const liveMode = normalizeLiveModeConfig(cfg);
1954
+ if (!liveMode?.backendOnly) {
1955
+ return null;
1956
+ }
1957
+ const method = String(req.method || 'GET').toUpperCase();
1958
+ if (method === 'OPTIONS' && !hasReproRequestCorrelation(req)) {
1959
+ return null;
1960
+ }
1961
+ const identity = await resolveLiveActorIdentity(cfg, req);
1962
+ if (!identity) {
1963
+ return null;
1964
+ }
1965
+ const { actorId, actorType, actorLabels } = identity;
1966
+ const claim = await postLiveApiJson(cfg, liveMode, '/v1/live-sessions/claim', {
1967
+ clientTime: requestStart,
1968
+ captureMode: 'backend-only',
1969
+ actorId,
1970
+ actorIds: [actorId],
1971
+ actorType,
1972
+ actorLabels,
1973
+ });
1974
+ const sid = normalizeLiveActorId(claim?.childSessionId) ??
1975
+ normalizeLiveActorId(claim?.sessionId);
1976
+ if (!sid) {
1977
+ return null;
1978
+ }
1979
+ const aid = normalizeLiveActorId(claim?.actionId) ?? newActionId(requestStart);
1980
+ const parentSessionId = normalizeLiveActorId(claim?.parentSessionId) ?? '';
1981
+ const liveChild = {
1982
+ sessionId: sid,
1983
+ parentSessionId,
1984
+ previousSessionId: null,
1985
+ actorId,
1986
+ actorType,
1987
+ actorLabels,
1988
+ startedAt: requestStart,
1989
+ expiresAt: requestStart,
1990
+ closeDeadline: requestStart,
1991
+ requestsInFlight: 0,
1992
+ closeTimer: null,
1993
+ };
1994
+ return {
1995
+ sid: liveChild.sessionId,
1996
+ aid,
1997
+ requestStart,
1998
+ child: liveChild,
1999
+ };
2000
+ }
1684
2001
  function resolveIngestUrl(cfg) {
1685
2002
  const envBase = typeof process !== 'undefined' ? process?.env?.REPRO_INGEST_BASE : undefined;
1686
2003
  const ingestBase = String(envBase || cfg.ingestBase || DEFAULT_INGEST_BASE).replace(/\/+$/, '');
@@ -1727,6 +2044,19 @@ function readRequestQueryNumber(req, name) {
1727
2044
  const parsed = Number(raw);
1728
2045
  return Number.isFinite(parsed) ? parsed : null;
1729
2046
  }
2047
+ function hasReproRequestCorrelation(req) {
2048
+ const headers = req.headers || {};
2049
+ if (hasHttpHeader(headers, KAFKA_HEADER_SESSION_ID) ||
2050
+ hasHttpHeader(headers, KAFKA_HEADER_ACTION_ID) ||
2051
+ hasHttpHeader(headers, KAFKA_HEADER_REQUEST_ID) ||
2052
+ hasHttpHeader(headers, KAFKA_HEADER_TRACE_ID) ||
2053
+ hasHttpHeader(headers, KAFKA_HEADER_SPAN_ID) ||
2054
+ hasHttpHeader(headers, KAFKA_HEADER_PARENT_SPAN_ID)) {
2055
+ return true;
2056
+ }
2057
+ return Boolean(readRequestQueryParam(req, REPRO_QUERY_SESSION_PARAM) ||
2058
+ readRequestQueryParam(req, REPRO_QUERY_ACTION_PARAM));
2059
+ }
1730
2060
  function stripReproQueryFromUrl(rawUrl) {
1731
2061
  if (!rawUrl || !rawUrl.includes('?')) {
1732
2062
  return rawUrl;
@@ -4131,6 +4461,72 @@ async function maybeCaptureDbValueFromCandidatesAsync(params, sink) {
4131
4461
  }
4132
4462
  return skippedRef;
4133
4463
  }
4464
+ function buildLiveActorArgs(cfg, req) {
4465
+ const rawUrl = String(req.originalUrl || req.url || '/');
4466
+ const path = rawUrl.split('?')[0] || '/';
4467
+ return {
4468
+ req,
4469
+ headers: req.headers,
4470
+ method: String(req.method || 'GET').toUpperCase(),
4471
+ url: rawUrl,
4472
+ path,
4473
+ ip: req.ip ?? req.socket?.remoteAddress ?? null,
4474
+ appId: cfg.appId,
4475
+ appName: cfg.appName,
4476
+ serviceName: cfg.serviceName,
4477
+ };
4478
+ }
4479
+ async function resolveLiveActorIdentity(cfg, req) {
4480
+ const liveMode = normalizeLiveModeConfig(cfg);
4481
+ if (!liveMode) {
4482
+ return null;
4483
+ }
4484
+ const args = buildLiveActorArgs(cfg, req);
4485
+ let rawActorId;
4486
+ try {
4487
+ rawActorId = liveMode.defineActorId
4488
+ ? await liveMode.defineActorId(args)
4489
+ : cfg.actorId;
4490
+ }
4491
+ catch {
4492
+ rawActorId = null;
4493
+ }
4494
+ const actorId = normalizeLiveActorId(rawActorId);
4495
+ if (!actorId) {
4496
+ return null;
4497
+ }
4498
+ const actorType = normalizeLiveActorId(liveMode.actorType) ?? cfg.actorType ?? 'user';
4499
+ const decision = {
4500
+ ...args,
4501
+ actorId,
4502
+ actorType,
4503
+ };
4504
+ if (liveMode.shouldCapture) {
4505
+ let shouldCapture = false;
4506
+ try {
4507
+ shouldCapture = (await liveMode.shouldCapture(decision)) === true;
4508
+ }
4509
+ catch {
4510
+ shouldCapture = false;
4511
+ }
4512
+ if (!shouldCapture) {
4513
+ return null;
4514
+ }
4515
+ }
4516
+ let rawLabels;
4517
+ try {
4518
+ rawLabels =
4519
+ typeof liveMode.actorLabels === 'function'
4520
+ ? await liveMode.actorLabels(decision)
4521
+ : liveMode.actorLabels;
4522
+ }
4523
+ catch {
4524
+ rawLabels = undefined;
4525
+ }
4526
+ const actorLabels = normalizeLiveActorLabels(rawLabels) ?? normalizeLiveActorLabels(cfg.actorLabels);
4527
+ return { actorId, actorType, actorLabels };
4528
+ }
4529
+ const backendLiveActors = new Map();
4134
4530
  function reproMiddleware(cfg) {
4135
4531
  const masking = normalizeMaskingConfig(cfg.masking);
4136
4532
  patchMongoDb(cfg);
@@ -4165,20 +4561,65 @@ function reproMiddleware(cfg) {
4165
4561
  clientRequestEnded = true;
4166
4562
  endClientRequest();
4167
4563
  };
4168
- const sid = req.headers['x-bug-session-id'] || querySid || '';
4169
- const aid = req.headers['x-bug-action-id'] || queryAid || '';
4564
+ const requestStartRaw = Date.now();
4565
+ const headerTs = readHeaderNumber(req.headers[REQUEST_START_HEADER]) ?? queryTs;
4566
+ const requestEpochMs = headerTs !== null ? headerTs : requestStartRaw;
4567
+ let backendLiveState = null;
4568
+ let backendLiveChild = null;
4569
+ const headerSid = req.headers['x-bug-session-id'] || '';
4570
+ const headerAid = req.headers['x-bug-action-id'] || '';
4571
+ const hasIncomingReproSession = Boolean(headerSid || querySid || headerAid || queryAid);
4572
+ const backendLiveContext = !hasIncomingReproSession
4573
+ ? await resolveBackendLiveContext(cfg, req, requestEpochMs)
4574
+ : null;
4575
+ const taggedActorIdentity = hasIncomingReproSession
4576
+ ? await resolveLiveActorIdentity(cfg, req)
4577
+ : null;
4578
+ if (backendLiveContext) {
4579
+ backendLiveState = backendLiveActors.get(backendLiveContext.child.actorId) ?? null;
4580
+ backendLiveChild = backendLiveContext.child;
4581
+ }
4582
+ const sid = headerSid || querySid || backendLiveContext?.sid || '';
4583
+ const aid = headerAid || queryAid || backendLiveContext?.aid || '';
4170
4584
  if (!sid || !aid) {
4171
4585
  res.on('finish', endTrackedClientRequest);
4172
4586
  res.on('close', endTrackedClientRequest);
4173
4587
  return next(); // only capture tagged requests
4174
4588
  }
4175
- const resolvePrivacy = () => getRuntimePrivacyState(cfg).policy ?? null;
4176
- const requestStartRaw = Date.now();
4177
- const headerTs = readHeaderNumber(req.headers[REQUEST_START_HEADER]) ?? queryTs;
4589
+ const captureCfg = backendLiveChild
4590
+ ? {
4591
+ ...cfg,
4592
+ actorId: backendLiveChild.actorId,
4593
+ actorType: backendLiveChild.actorType,
4594
+ actorLabels: backendLiveChild.actorLabels,
4595
+ }
4596
+ : taggedActorIdentity
4597
+ ? {
4598
+ ...cfg,
4599
+ actorId: taggedActorIdentity.actorId,
4600
+ actorType: taggedActorIdentity.actorType,
4601
+ actorLabels: taggedActorIdentity.actorLabels,
4602
+ }
4603
+ : cfg;
4604
+ if (taggedActorIdentity) {
4605
+ post(captureCfg, sid, {
4606
+ entries: [{
4607
+ actionId: aid,
4608
+ sessionActor: {
4609
+ actorId: taggedActorIdentity.actorId,
4610
+ actorType: taggedActorIdentity.actorType,
4611
+ actorLabels: taggedActorIdentity.actorLabels,
4612
+ source: 'node-sdk',
4613
+ },
4614
+ t: requestEpochMs,
4615
+ }],
4616
+ }, { priority: 'high' });
4617
+ }
4618
+ const resolvePrivacy = () => getRuntimePrivacyState(captureCfg).policy ?? null;
4178
4619
  const clockSkewMs = headerTs !== null ? headerTs - requestStartRaw : 0;
4179
- const requestEpochMs = headerTs !== null ? headerTs : requestStartRaw + clockSkewMs;
4180
4620
  const rid = nextRequestId(requestEpochMs);
4181
4621
  const captureScope = createRequestCaptureScope(rid, 'http');
4622
+ emitRequestCaptureStart(captureCfg, sid, aid, captureScope, requestEpochMs);
4182
4623
  const t0 = requestStartRaw;
4183
4624
  const url = req.originalUrl || req.url || '/';
4184
4625
  const urlPathOnly = (url || '/').split('?')[0] || '/';
@@ -4380,15 +4821,15 @@ function reproMiddleware(cfg) {
4380
4821
  const activePrivacy = resolvePrivacy();
4381
4822
  const requestBodyRaw = req.body;
4382
4823
  const requestBodyMaterialization = limitRawInlinePrivacyValue('request.body', requestBodyRaw)
4383
- ?? await materializeInlinePrivacyValueAsync('request.body', sanitizeRequestSnapshot(requestBodyRaw), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
4824
+ ?? await materializeInlinePrivacyValueAsync('request.body', sanitizeRequestSnapshot(requestBodyRaw), captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy);
4384
4825
  const requestBody = requestBodyMaterialization.value;
4385
- const requestParams = await applyPrivacyThenMaskAsync('request.params', sanitizeRequestSnapshot(req.params), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
4386
- const requestQuery = await applyPrivacyThenMaskAsync('request.query', sanitizeRequestSnapshot(req.query), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
4387
- const maskedHeaders = await applyPrivacyThenMaskAsync('request.headers', requestHeaders, cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
4826
+ const requestParams = await applyPrivacyThenMaskAsync('request.params', sanitizeRequestSnapshot(req.params), captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy);
4827
+ const requestQuery = await applyPrivacyThenMaskAsync('request.query', sanitizeRequestSnapshot(req.query), captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy);
4828
+ const maskedHeaders = await applyPrivacyThenMaskAsync('request.headers', requestHeaders, captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy);
4388
4829
  const responseBodyMaterialization = capturedBody === undefined
4389
4830
  ? { value: undefined }
4390
4831
  : limitRawInlinePrivacyValue('response.body', capturedBody)
4391
- ?? await materializeInlinePrivacyValueAsync('response.body', sanitizeRequestSnapshot(capturedBody), cfg, maskReq, endpointTraceCtx, masking, activePrivacy);
4832
+ ?? await materializeInlinePrivacyValueAsync('response.body', sanitizeRequestSnapshot(capturedBody), captureCfg, maskReq, endpointTraceCtx, masking, activePrivacy);
4392
4833
  const responseBody = responseBodyMaterialization.value;
4393
4834
  const requestValueEntries = [];
4394
4835
  const bodyValueCapture = requestBodyMaterialization.skipped
@@ -4398,7 +4839,7 @@ function reproMiddleware(cfg) {
4398
4839
  rawValue: req.body,
4399
4840
  previewValue: requestBody,
4400
4841
  capture: {
4401
- runtimeConfig: cfg,
4842
+ runtimeConfig: captureCfg,
4402
4843
  captureHeaders: cfg.captureHeaders,
4403
4844
  maskReq,
4404
4845
  trace: endpointTraceCtx,
@@ -4411,7 +4852,7 @@ function reproMiddleware(cfg) {
4411
4852
  rawValue: req.params,
4412
4853
  previewValue: requestParams,
4413
4854
  capture: {
4414
- runtimeConfig: cfg,
4855
+ runtimeConfig: captureCfg,
4415
4856
  captureHeaders: cfg.captureHeaders,
4416
4857
  maskReq,
4417
4858
  trace: endpointTraceCtx,
@@ -4424,7 +4865,7 @@ function reproMiddleware(cfg) {
4424
4865
  rawValue: req.query,
4425
4866
  previewValue: requestQuery,
4426
4867
  capture: {
4427
- runtimeConfig: cfg,
4868
+ runtimeConfig: captureCfg,
4428
4869
  captureHeaders: cfg.captureHeaders,
4429
4870
  maskReq,
4430
4871
  trace: endpointTraceCtx,
@@ -4437,7 +4878,7 @@ function reproMiddleware(cfg) {
4437
4878
  rawValue: req.headers,
4438
4879
  previewValue: maskedHeaders,
4439
4880
  capture: {
4440
- runtimeConfig: cfg,
4881
+ runtimeConfig: captureCfg,
4441
4882
  captureHeaders: cfg.captureHeaders,
4442
4883
  maskReq,
4443
4884
  trace: endpointTraceCtx,
@@ -4452,7 +4893,7 @@ function reproMiddleware(cfg) {
4452
4893
  rawValue: capturedBody,
4453
4894
  previewValue: responseBody,
4454
4895
  capture: {
4455
- runtimeConfig: cfg,
4896
+ runtimeConfig: captureCfg,
4456
4897
  captureHeaders: cfg.captureHeaders,
4457
4898
  maskReq,
4458
4899
  trace: endpointTraceCtx,
@@ -4513,7 +4954,7 @@ function reproMiddleware(cfg) {
4513
4954
  }
4514
4955
  const { chosenEndpoint, hasTraceEvents } = chooseRequestEndpoint();
4515
4956
  const { requestPayload, requestValueEntries } = await buildRequestCapturePayloadAsync(chosenEndpoint, hasTraceEvents);
4516
- post(cfg, sid, {
4957
+ post(captureCfg, sid, {
4517
4958
  entries: [{
4518
4959
  actionId: aid,
4519
4960
  request: requestPayload,
@@ -4531,7 +4972,7 @@ function reproMiddleware(cfg) {
4531
4972
  if (requestCaptureManifestScheduled)
4532
4973
  return;
4533
4974
  requestCaptureManifestScheduled = true;
4534
- post(cfg, sid, {
4975
+ post(captureCfg, sid, {
4535
4976
  entries: [{
4536
4977
  actionId: aid,
4537
4978
  requestRid: rid,
@@ -4634,7 +5075,7 @@ function reproMiddleware(cfg) {
4634
5075
  try {
4635
5076
  const pendingEvents = preparePendingTraceEventsForFlush(events.slice());
4636
5077
  const materializedEvents = await materializePendingTraceEventsAsync(pendingEvents, {
4637
- cfg,
5078
+ cfg: captureCfg,
4638
5079
  maskReq,
4639
5080
  masking,
4640
5081
  resolvePrivacy,
@@ -4662,7 +5103,7 @@ function reproMiddleware(cfg) {
4662
5103
  for (let i = 0; i < traceBatches.length; i++) {
4663
5104
  const batch = traceBatches[i];
4664
5105
  const traceValues = collectBatchTraceValueEntries(batch, i);
4665
- post(cfg, sid, {
5106
+ post(captureCfg, sid, {
4666
5107
  entries: [{
4667
5108
  actionId: aid,
4668
5109
  trace: batch,
@@ -4684,6 +5125,9 @@ function reproMiddleware(cfg) {
4684
5125
  }
4685
5126
  sessionDrainWait = waitForSessionDrain(sid);
4686
5127
  endSessionRequest(sid);
5128
+ if (backendLiveState && backendLiveChild) {
5129
+ releaseBackendLiveRequest(cfg, normalizeLiveModeConfig(cfg), backendLiveState, backendLiveChild, finishedAtAligned ?? alignedNow());
5130
+ }
4687
5131
  endTrackedClientRequest();
4688
5132
  if (__TRACER_READY) {
4689
5133
  bumpIdle();
@@ -6093,6 +6537,7 @@ function patchKafkaProducerInstance(producer, cfg) {
6093
6537
  const span = captureSpanContextFromTracer();
6094
6538
  const publishRid = nextRequestId(alignedNow());
6095
6539
  const captureScope = createRequestCaptureScope(publishRid, 'kafka');
6540
+ emitRequestCaptureStart(cfg, sid, aid, captureScope);
6096
6541
  const payloadObj = payload && typeof payload === 'object' ? payload : {};
6097
6542
  const topic = sanitizeKafkaTopic(payloadObj.topic);
6098
6543
  const rawMessages = Array.isArray(payloadObj.messages) ? payloadObj.messages : [];
@@ -6201,6 +6646,7 @@ function patchKafkaProducerInstance(producer, cfg) {
6201
6646
  const span = captureSpanContextFromTracer();
6202
6647
  const publishRid = nextRequestId(alignedNow());
6203
6648
  const captureScope = createRequestCaptureScope(publishRid, 'kafka');
6649
+ emitRequestCaptureStart(cfg, sid, aid, captureScope);
6204
6650
  const payloadObj = payload && typeof payload === 'object' ? payload : {};
6205
6651
  const topicMessages = Array.isArray(payloadObj.topicMessages)
6206
6652
  ? payloadObj.topicMessages
@@ -6342,6 +6788,7 @@ function wrapKafkaEachMessageHandler(eachMessage, cfg, consumer) {
6342
6788
  const consumeRid = nextRequestId(`${topic}-${message?.offset ?? alignedNow()}`);
6343
6789
  const traceId = consumeRid;
6344
6790
  const captureScope = createRequestCaptureScope(consumeRid, 'kafka');
6791
+ emitRequestCaptureStart(cfg, sid, aid, captureScope);
6345
6792
  const rawTraceEvents = [];
6346
6793
  const maskReq = {
6347
6794
  method: 'KAFKA_CONSUME',
@@ -6456,6 +6903,7 @@ function wrapKafkaEachBatchHandler(eachBatch, cfg, consumer) {
6456
6903
  const consumeRid = nextRequestId(`${topic}-batch-${alignedNow()}`);
6457
6904
  const traceId = consumeRid;
6458
6905
  const captureScope = createRequestCaptureScope(consumeRid, 'kafka');
6906
+ emitRequestCaptureStart(cfg, sid, aid, captureScope);
6459
6907
  const rawTraceEvents = [];
6460
6908
  const maskReq = {
6461
6909
  method: 'KAFKA_CONSUME_BATCH',
@@ -7084,6 +7532,7 @@ function patchAmqplibPublishMethod(channel, cfg, methodName) {
7084
7532
  const key = `${method} ${methodName === 'publish' ? `${exchange || 'default'}/${routingKey}` : queue}`;
7085
7533
  const content = methodName === 'publish' ? args[2] : args[1];
7086
7534
  const captureScope = createRequestCaptureScope(publishRid, 'amqp');
7535
+ emitRequestCaptureStart(cfg, sid, aid, captureScope);
7087
7536
  const t0 = Date.now();
7088
7537
  let finished = false;
7089
7538
  const finish = (status, error, result) => {
@@ -7170,6 +7619,7 @@ function wrapAmqplibConsumeHandler(onMessage, cfg, queue) {
7170
7619
  const consumeRid = nextRequestId(`${queueName}-${deliveryTag}`);
7171
7620
  const traceId = consumeRid;
7172
7621
  const captureScope = createRequestCaptureScope(consumeRid, 'amqp');
7622
+ emitRequestCaptureStart(cfg, sid, aid, captureScope);
7173
7623
  const rawTraceEvents = [];
7174
7624
  const maskReq = {
7175
7625
  method: 'AMQP_CONSUME',
@@ -7732,6 +8182,564 @@ function patchRedis(cfg) {
7732
8182
  }
7733
8183
  }
7734
8184
  exports.patchRedis = patchRedis;
8185
+ const postgresSqlPatchConfigs = [];
8186
+ const postgresSqlSourceAls = new async_hooks_1.AsyncLocalStorage();
8187
+ const pgPoolQueryAls = new async_hooks_1.AsyncLocalStorage();
8188
+ let pgRequireHookInstalled = false;
8189
+ let postgresJsRequireHookInstalled = false;
8190
+ let typeOrmRequireHookInstalled = false;
8191
+ const PG_CLIENT_PATCHED = Symbol.for('@reproapp/node-sdk/pg-client-patched');
8192
+ const PG_POOL_PATCHED = Symbol.for('@reproapp/node-sdk/pg-pool-patched');
8193
+ const POSTGRES_JS_QUERY_PATCHED = Symbol.for('@reproapp/node-sdk/postgres-js-query-patched');
8194
+ const TYPEORM_DATASOURCE_PATCHED = Symbol.for('@reproapp/node-sdk/typeorm-datasource-patched');
8195
+ const TYPEORM_QUERY_RUNNER_PATCHED = Symbol.for('@reproapp/node-sdk/typeorm-query-runner-patched');
8196
+ function registerPostgreSqlPatchConfig(cfg) {
8197
+ if (!postgresSqlPatchConfigs.includes(cfg)) {
8198
+ postgresSqlPatchConfigs.push(cfg);
8199
+ }
8200
+ }
8201
+ function resolvePostgreSqlCaptureContext(defaultSource, source) {
8202
+ const ctx = getCtx();
8203
+ const contextualSource = postgresSqlSourceAls.getStore();
8204
+ for (let i = postgresSqlPatchConfigs.length - 1; i >= 0; i -= 1) {
8205
+ const cfg = postgresSqlPatchConfigs[i];
8206
+ if (!cfg)
8207
+ continue;
8208
+ const fallback = cfg.resolveContext?.() ?? {};
8209
+ const sid = ctx.sid ?? fallback.sid ?? null;
8210
+ if (!sid)
8211
+ continue;
8212
+ return {
8213
+ cfg,
8214
+ sid,
8215
+ aid: ctx.aid ?? fallback.aid ?? null,
8216
+ spanContext: captureSpanContextFromTracer(source),
8217
+ source: contextualSource ?? defaultSource,
8218
+ };
8219
+ }
8220
+ return null;
8221
+ }
8222
+ function stripSqlComments(sql) {
8223
+ let remaining = sql.trimStart();
8224
+ while (remaining.length) {
8225
+ if (remaining.startsWith('--')) {
8226
+ const newline = remaining.indexOf('\n');
8227
+ remaining = newline < 0 ? '' : remaining.slice(newline + 1).trimStart();
8228
+ continue;
8229
+ }
8230
+ if (remaining.startsWith('/*')) {
8231
+ const end = remaining.indexOf('*/', 2);
8232
+ remaining = end < 0 ? '' : remaining.slice(end + 2).trimStart();
8233
+ continue;
8234
+ }
8235
+ break;
8236
+ }
8237
+ return remaining;
8238
+ }
8239
+ function normalizeSqlOperation(sql) {
8240
+ const normalized = stripSqlComments(sql);
8241
+ const first = normalized.match(/^([a-z]+)/i)?.[1]?.toLowerCase() ?? 'query';
8242
+ if (first !== 'with')
8243
+ return first;
8244
+ // CTEs can wrap any DML statement. The last top-level DML keyword is the
8245
+ // operation users care about, while nested SELECTs only build the CTE.
8246
+ const matches = Array.from(normalized.matchAll(/\b(select|insert|update|delete|merge)\b/gi));
8247
+ return matches.length ? String(matches[matches.length - 1][1]).toLowerCase() : 'query';
8248
+ }
8249
+ function cleanSqlIdentifier(value) {
8250
+ if (!value)
8251
+ return undefined;
8252
+ const cleaned = value
8253
+ .trim()
8254
+ .replace(/[;,]$/, '')
8255
+ .split('.')
8256
+ .map((part) => part.replace(/^['"`]|['"`]$/g, ''))
8257
+ .join('.');
8258
+ return cleaned || undefined;
8259
+ }
8260
+ function resolveSqlTable(sql, op) {
8261
+ const normalized = stripSqlComments(sql);
8262
+ let match = null;
8263
+ if (op === 'insert')
8264
+ match = normalized.match(/\binsert\s+into\s+([^\s(]+)/i);
8265
+ else if (op === 'update')
8266
+ match = normalized.match(/\bupdate\s+([^\s(]+)/i);
8267
+ else if (op === 'delete')
8268
+ match = normalized.match(/\bdelete\s+from\s+([^\s(]+)/i);
8269
+ else if (op === 'merge')
8270
+ match = normalized.match(/\bmerge\s+into\s+([^\s(]+)/i);
8271
+ else
8272
+ match = normalized.match(/\bfrom\s+([^\s(]+)/i);
8273
+ return cleanSqlIdentifier(match?.[1]) ?? 'unknown';
8274
+ }
8275
+ function buildPostgresQueryPayload(sql, parameters, source, extra) {
8276
+ return {
8277
+ sql,
8278
+ parameters,
8279
+ library: source.library,
8280
+ driver: source.driver,
8281
+ ...(extra ?? {}),
8282
+ };
8283
+ }
8284
+ function summarizePostgresError(error) {
8285
+ return {
8286
+ name: error?.name ?? 'Error',
8287
+ message: error?.message ?? String(error),
8288
+ code: error?.code,
8289
+ severity: error?.severity,
8290
+ detail: error?.detail,
8291
+ hint: error?.hint,
8292
+ position: error?.position,
8293
+ internalPosition: error?.internalPosition,
8294
+ internalQuery: error?.internalQuery,
8295
+ where: error?.where,
8296
+ schema: error?.schema,
8297
+ table: error?.table,
8298
+ column: error?.column,
8299
+ dataType: error?.dataType,
8300
+ constraint: error?.constraint,
8301
+ file: error?.file,
8302
+ line: error?.line,
8303
+ routine: error?.routine,
8304
+ };
8305
+ }
8306
+ function normalizePgQueryInput(config, values) {
8307
+ if (typeof config === 'string') {
8308
+ return { sql: config, parameters: Array.isArray(values) ? values : [] };
8309
+ }
8310
+ const sql = typeof config?.text === 'string' ? config.text : '';
8311
+ const parameters = Array.isArray(config?.values)
8312
+ ? config.values
8313
+ : Array.isArray(values)
8314
+ ? values
8315
+ : [];
8316
+ return {
8317
+ sql,
8318
+ parameters,
8319
+ extra: {
8320
+ name: typeof config?.name === 'string' ? config.name : undefined,
8321
+ rowMode: config?.rowMode,
8322
+ binary: config?.binary,
8323
+ },
8324
+ };
8325
+ }
8326
+ function normalizePgResult(result) {
8327
+ if (Array.isArray(result))
8328
+ return result.map(normalizePgResult);
8329
+ if (!result || typeof result !== 'object')
8330
+ return result;
8331
+ return {
8332
+ command: result.command,
8333
+ rowCount: result.rowCount,
8334
+ oid: result.oid,
8335
+ fields: Array.isArray(result.fields)
8336
+ ? result.fields.map((field) => ({
8337
+ name: field?.name,
8338
+ tableID: field?.tableID,
8339
+ columnID: field?.columnID,
8340
+ dataTypeID: field?.dataTypeID,
8341
+ dataTypeSize: field?.dataTypeSize,
8342
+ dataTypeModifier: field?.dataTypeModifier,
8343
+ format: field?.format,
8344
+ }))
8345
+ : undefined,
8346
+ rows: result.rows,
8347
+ };
8348
+ }
8349
+ function emitPostgreSqlResult(capture, sql, parameters, startedAt, result, error, extra) {
8350
+ const op = normalizeSqlOperation(sql);
8351
+ emitDbQuery(capture.cfg, capture.sid, capture.aid ?? undefined, {
8352
+ type: 'postgresql',
8353
+ collection: resolveSqlTable(sql, op),
8354
+ op,
8355
+ queryRaw: buildPostgresQueryPayload(sql, parameters, capture.source, extra),
8356
+ resultMetaRaw: error ? undefined : result,
8357
+ error: error ? summarizePostgresError(error) : undefined,
8358
+ durMs: Date.now() - startedAt,
8359
+ t: alignedNow(),
8360
+ spanContext: capture.spanContext,
8361
+ });
8362
+ }
8363
+ function findPgCallbackIndex(args) {
8364
+ for (let i = args.length - 1; i >= 1; i -= 1) {
8365
+ if (typeof args[i] === 'function')
8366
+ return i;
8367
+ }
8368
+ return -1;
8369
+ }
8370
+ function patchPgClientPrototype(proto) {
8371
+ if (!proto || proto[PG_CLIENT_PATCHED])
8372
+ return;
8373
+ const original = proto.query;
8374
+ if (typeof original !== 'function')
8375
+ return;
8376
+ try {
8377
+ Object.defineProperty(proto, PG_CLIENT_PATCHED, { value: true, configurable: true });
8378
+ }
8379
+ catch {
8380
+ return;
8381
+ }
8382
+ proto.query = function reproPatchedPgQuery(...args) {
8383
+ if (pgPoolQueryAls.getStore())
8384
+ return original.apply(this, args);
8385
+ const capture = resolvePostgreSqlCaptureContext({ library: 'pg', driver: 'pg' }, this);
8386
+ if (!capture)
8387
+ return original.apply(this, args);
8388
+ const input = normalizePgQueryInput(args[0], args[1]);
8389
+ const startedAt = Date.now();
8390
+ const callbackIndex = findPgCallbackIndex(args);
8391
+ const actualArgs = callbackIndex >= 0 ? [...args] : args;
8392
+ let emitted = false;
8393
+ const emitSuccess = (result) => {
8394
+ if (emitted)
8395
+ return;
8396
+ emitted = true;
8397
+ emitPostgreSqlResult(capture, input.sql, input.parameters, startedAt, normalizePgResult(result), undefined, input.extra);
8398
+ };
8399
+ const emitFailure = (error) => {
8400
+ if (emitted)
8401
+ return;
8402
+ emitted = true;
8403
+ emitPostgreSqlResult(capture, input.sql, input.parameters, startedAt, undefined, error, input.extra);
8404
+ };
8405
+ if (callbackIndex >= 0) {
8406
+ const callback = args[callbackIndex];
8407
+ actualArgs[callbackIndex] = function reproPgQueryCallback(error, result, ...rest) {
8408
+ if (error)
8409
+ emitFailure(error);
8410
+ else
8411
+ emitSuccess(result);
8412
+ return callback.call(this, error, result, ...rest);
8413
+ };
8414
+ }
8415
+ try {
8416
+ const returned = original.apply(this, actualArgs);
8417
+ if (returned && typeof returned.then === 'function') {
8418
+ return returned.then((result) => {
8419
+ emitSuccess(result);
8420
+ return result;
8421
+ }, (error) => {
8422
+ emitFailure(error);
8423
+ throw error;
8424
+ });
8425
+ }
8426
+ if (returned && callbackIndex < 0 && typeof returned.once === 'function') {
8427
+ returned.once('end', emitSuccess);
8428
+ returned.once('error', emitFailure);
8429
+ }
8430
+ return returned;
8431
+ }
8432
+ catch (error) {
8433
+ emitFailure(error);
8434
+ throw error;
8435
+ }
8436
+ };
8437
+ }
8438
+ function patchPgPoolPrototype(proto) {
8439
+ if (!proto || proto[PG_POOL_PATCHED])
8440
+ return;
8441
+ const original = proto.query;
8442
+ if (typeof original !== 'function')
8443
+ return;
8444
+ try {
8445
+ Object.defineProperty(proto, PG_POOL_PATCHED, { value: true, configurable: true });
8446
+ }
8447
+ catch {
8448
+ return;
8449
+ }
8450
+ proto.query = function reproPatchedPgPoolQuery(...args) {
8451
+ const capture = resolvePostgreSqlCaptureContext({ library: 'pg', driver: 'pg' }, this);
8452
+ if (!capture)
8453
+ return original.apply(this, args);
8454
+ const input = normalizePgQueryInput(args[0], args[1]);
8455
+ const startedAt = Date.now();
8456
+ const callbackIndex = findPgCallbackIndex(args);
8457
+ const actualArgs = callbackIndex >= 0 ? [...args] : args;
8458
+ let emitted = false;
8459
+ const emitSuccess = (result) => {
8460
+ if (emitted)
8461
+ return;
8462
+ emitted = true;
8463
+ emitPostgreSqlResult(capture, input.sql, input.parameters, startedAt, normalizePgResult(result), undefined, input.extra);
8464
+ };
8465
+ const emitFailure = (error) => {
8466
+ if (emitted)
8467
+ return;
8468
+ emitted = true;
8469
+ emitPostgreSqlResult(capture, input.sql, input.parameters, startedAt, undefined, error, input.extra);
8470
+ };
8471
+ if (callbackIndex >= 0) {
8472
+ const callback = args[callbackIndex];
8473
+ actualArgs[callbackIndex] = function reproPgPoolQueryCallback(error, result, ...rest) {
8474
+ if (error)
8475
+ emitFailure(error);
8476
+ else
8477
+ emitSuccess(result);
8478
+ return callback.call(this, error, result, ...rest);
8479
+ };
8480
+ }
8481
+ try {
8482
+ const returned = pgPoolQueryAls.run(true, () => original.apply(this, actualArgs));
8483
+ if (returned && typeof returned.then === 'function') {
8484
+ return returned.then((result) => {
8485
+ emitSuccess(result);
8486
+ return result;
8487
+ }, (error) => {
8488
+ emitFailure(error);
8489
+ throw error;
8490
+ });
8491
+ }
8492
+ return returned;
8493
+ }
8494
+ catch (error) {
8495
+ emitFailure(error);
8496
+ throw error;
8497
+ }
8498
+ };
8499
+ }
8500
+ function patchPgFromModuleExports(pgModule) {
8501
+ if (!pgModule)
8502
+ return;
8503
+ const candidates = [pgModule, pgModule.default];
8504
+ for (const candidate of candidates) {
8505
+ patchPgClientPrototype(candidate?.Client?.prototype);
8506
+ patchPgClientPrototype(candidate?.native?.Client?.prototype);
8507
+ patchPgPoolPrototype(candidate?.Pool?.prototype);
8508
+ patchPgPoolPrototype(candidate?.native?.Pool?.prototype);
8509
+ }
8510
+ }
8511
+ function installPgRequireHook() {
8512
+ if (pgRequireHookInstalled)
8513
+ return;
8514
+ pgRequireHookInstalled = true;
8515
+ try {
8516
+ const rim = requireOptionalHostModule('require-in-the-middle');
8517
+ const Hook = rim?.Hook ?? rim;
8518
+ if (typeof Hook !== 'function')
8519
+ return;
8520
+ // eslint-disable-next-line no-new
8521
+ new Hook(['pg'], (exports) => {
8522
+ patchPgFromModuleExports(exports);
8523
+ return exports;
8524
+ });
8525
+ }
8526
+ catch { }
8527
+ }
8528
+ function normalizePostgresJsInput(query) {
8529
+ if (typeof query?.statement?.string === 'string') {
8530
+ return {
8531
+ sql: query.statement.string,
8532
+ parameters: Array.isArray(query?.parameters) ? query.parameters : [],
8533
+ extra: {
8534
+ tagged: query?.tagged === true,
8535
+ parameterTypes: Array.isArray(query?.statement?.types) ? query.statement.types : undefined,
8536
+ },
8537
+ };
8538
+ }
8539
+ const strings = Array.isArray(query?.strings) ? query.strings : [];
8540
+ const parameters = Array.isArray(query?.args) ? query.args : [];
8541
+ if (query?.tagged) {
8542
+ return {
8543
+ sql: strings.map((part, index) => `${String(part)}${index < parameters.length ? `$${index + 1}` : ''}`).join(''),
8544
+ parameters,
8545
+ extra: { tagged: true },
8546
+ };
8547
+ }
8548
+ return {
8549
+ sql: typeof strings[0] === 'string' ? strings[0] : '',
8550
+ parameters,
8551
+ extra: { tagged: false },
8552
+ };
8553
+ }
8554
+ function normalizePostgresJsResult(result) {
8555
+ if (!Array.isArray(result))
8556
+ return result;
8557
+ const metadata = result;
8558
+ return {
8559
+ command: metadata.command,
8560
+ count: metadata.count,
8561
+ columns: Array.isArray(metadata.columns)
8562
+ ? metadata.columns.map((column) => ({
8563
+ name: column?.name,
8564
+ type: column?.type,
8565
+ table: column?.table,
8566
+ number: column?.number,
8567
+ }))
8568
+ : undefined,
8569
+ rows: Array.from(result),
8570
+ };
8571
+ }
8572
+ function patchPostgresJsQueryPrototype(proto) {
8573
+ if (!proto || proto[POSTGRES_JS_QUERY_PATCHED])
8574
+ return;
8575
+ const originalHandle = proto.handle;
8576
+ if (typeof originalHandle !== 'function')
8577
+ return;
8578
+ try {
8579
+ Object.defineProperty(proto, POSTGRES_JS_QUERY_PATCHED, { value: true, configurable: true });
8580
+ }
8581
+ catch {
8582
+ return;
8583
+ }
8584
+ proto.handle = function reproPatchedPostgresJsHandle(...args) {
8585
+ if (!this.__repro_postgres_capture_attached) {
8586
+ const capture = resolvePostgreSqlCaptureContext({ library: 'postgres', driver: 'postgres' }, this);
8587
+ if (capture) {
8588
+ try {
8589
+ Object.defineProperty(this, '__repro_postgres_capture_attached', { value: true, configurable: true });
8590
+ }
8591
+ catch {
8592
+ this.__repro_postgres_capture_attached = true;
8593
+ }
8594
+ const input = normalizePostgresJsInput(this);
8595
+ const startedAt = Date.now();
8596
+ Promise.prototype.then.call(this, (result) => {
8597
+ const executedInput = normalizePostgresJsInput(this);
8598
+ emitPostgreSqlResult(capture, executedInput.sql || input.sql, executedInput.parameters, startedAt, normalizePostgresJsResult(result), undefined, executedInput.extra);
8599
+ return result;
8600
+ }, (error) => {
8601
+ const executedInput = normalizePostgresJsInput(this);
8602
+ emitPostgreSqlResult(capture, executedInput.sql || input.sql, executedInput.parameters.length ? executedInput.parameters : input.parameters, startedAt, undefined, error, executedInput.extra);
8603
+ });
8604
+ }
8605
+ }
8606
+ return originalHandle.apply(this, args);
8607
+ };
8608
+ }
8609
+ function patchPostgresJsFromModuleExports(postgresModule) {
8610
+ const factories = new Set();
8611
+ const addFactory = (candidate) => {
8612
+ if (typeof candidate !== 'function')
8613
+ return;
8614
+ // getLoadedModuleExportsByPackage also returns internal postgres.js
8615
+ // helpers. Only the public factory carries these static exports.
8616
+ if (!candidate.PostgresError && !candidate.BigInt && !candidate.__repro_postgres_factory)
8617
+ return;
8618
+ factories.add(candidate);
8619
+ };
8620
+ addFactory(postgresModule);
8621
+ addFactory(postgresModule?.default);
8622
+ for (const factory of factories) {
8623
+ let sql;
8624
+ try {
8625
+ sql = factory({ max: 1, idle_timeout: 1, connect_timeout: 1 });
8626
+ const query = sql.unsafe('select 1');
8627
+ patchPostgresJsQueryPrototype(Object.getPrototypeOf(query));
8628
+ }
8629
+ catch { }
8630
+ try {
8631
+ const ended = sql?.end?.({ timeout: 0 });
8632
+ if (ended && typeof ended.catch === 'function')
8633
+ ended.catch(() => undefined);
8634
+ }
8635
+ catch { }
8636
+ }
8637
+ }
8638
+ function installPostgresJsRequireHook() {
8639
+ if (postgresJsRequireHookInstalled)
8640
+ return;
8641
+ postgresJsRequireHookInstalled = true;
8642
+ try {
8643
+ const rim = requireOptionalHostModule('require-in-the-middle');
8644
+ const Hook = rim?.Hook ?? rim;
8645
+ if (typeof Hook !== 'function')
8646
+ return;
8647
+ // eslint-disable-next-line no-new
8648
+ new Hook(['postgres'], (exports) => {
8649
+ patchPostgresJsFromModuleExports(exports);
8650
+ return exports;
8651
+ });
8652
+ }
8653
+ catch { }
8654
+ }
8655
+ function patchTypeOrmQueryRunner(queryRunner) {
8656
+ if (!queryRunner || queryRunner[TYPEORM_QUERY_RUNNER_PATCHED])
8657
+ return queryRunner;
8658
+ const original = queryRunner.query;
8659
+ if (typeof original !== 'function')
8660
+ return queryRunner;
8661
+ try {
8662
+ Object.defineProperty(queryRunner, TYPEORM_QUERY_RUNNER_PATCHED, { value: true, configurable: true });
8663
+ }
8664
+ catch {
8665
+ return queryRunner;
8666
+ }
8667
+ queryRunner.query = function reproPatchedTypeOrmQuery(...args) {
8668
+ return postgresSqlSourceAls.run({ library: 'typeorm', driver: 'pg' }, () => original.apply(this, args));
8669
+ };
8670
+ return queryRunner;
8671
+ }
8672
+ function patchTypeOrmDataSourcePrototype(proto) {
8673
+ if (!proto || proto[TYPEORM_DATASOURCE_PATCHED])
8674
+ return;
8675
+ const original = proto.createQueryRunner;
8676
+ if (typeof original !== 'function')
8677
+ return;
8678
+ try {
8679
+ Object.defineProperty(proto, TYPEORM_DATASOURCE_PATCHED, { value: true, configurable: true });
8680
+ }
8681
+ catch {
8682
+ return;
8683
+ }
8684
+ proto.createQueryRunner = function reproPatchedCreateQueryRunner(...args) {
8685
+ return patchTypeOrmQueryRunner(original.apply(this, args));
8686
+ };
8687
+ }
8688
+ function patchTypeOrmFromModuleExports(typeOrmModule) {
8689
+ if (!typeOrmModule)
8690
+ return;
8691
+ patchTypeOrmDataSourcePrototype(typeOrmModule?.DataSource?.prototype);
8692
+ patchTypeOrmDataSourcePrototype(typeOrmModule?.Connection?.prototype);
8693
+ patchTypeOrmDataSourcePrototype(typeOrmModule?.default?.DataSource?.prototype);
8694
+ }
8695
+ function installTypeOrmRequireHook() {
8696
+ if (typeOrmRequireHookInstalled)
8697
+ return;
8698
+ typeOrmRequireHookInstalled = true;
8699
+ try {
8700
+ const rim = requireOptionalHostModule('require-in-the-middle');
8701
+ const Hook = rim?.Hook ?? rim;
8702
+ if (typeof Hook !== 'function')
8703
+ return;
8704
+ // eslint-disable-next-line no-new
8705
+ new Hook(['typeorm'], (exports) => {
8706
+ patchTypeOrmFromModuleExports(exports);
8707
+ return exports;
8708
+ });
8709
+ }
8710
+ catch { }
8711
+ }
8712
+ function patchPostgreSql(cfg) {
8713
+ registerPostgreSqlPatchConfig(cfg);
8714
+ installPgRequireHook();
8715
+ installPostgresJsRequireHook();
8716
+ installTypeOrmRequireHook();
8717
+ const pgModules = new Set();
8718
+ const pg = requireOptionalHostModule('pg');
8719
+ if (pg)
8720
+ pgModules.add(pg);
8721
+ for (const loaded of getLoadedModuleExportsByPackage('pg'))
8722
+ pgModules.add(loaded);
8723
+ for (const loaded of pgModules)
8724
+ patchPgFromModuleExports(loaded);
8725
+ const postgresModules = new Set();
8726
+ const postgres = requireOptionalHostModule('postgres');
8727
+ if (postgres)
8728
+ postgresModules.add(postgres);
8729
+ for (const loaded of getLoadedModuleExportsByPackage('postgres'))
8730
+ postgresModules.add(loaded);
8731
+ for (const loaded of postgresModules)
8732
+ patchPostgresJsFromModuleExports(loaded);
8733
+ const typeOrmModules = new Set();
8734
+ const typeOrm = requireOptionalHostModule('typeorm');
8735
+ if (typeOrm)
8736
+ typeOrmModules.add(typeOrm);
8737
+ for (const loaded of getLoadedModuleExportsByPackage('typeorm'))
8738
+ typeOrmModules.add(loaded);
8739
+ for (const loaded of typeOrmModules)
8740
+ patchTypeOrmFromModuleExports(loaded);
8741
+ }
8742
+ exports.patchPostgreSql = patchPostgreSql;
7735
8743
  const mongoDbPatchConfigs = [];
7736
8744
  let mongoDbRequireHookInstalled = false;
7737
8745
  let mongoDbImportHookInstalled = false;
@@ -8801,9 +9809,11 @@ async function initRepro(cfg) {
8801
9809
  const ingestCfg = toIngestConfig(cfg);
8802
9810
  reproAutoMiddlewareConfig = {
8803
9811
  ...ingestCfg,
9812
+ apiBase: cfg.apiBase,
8804
9813
  captureHeaders: cfg.captureHeaders,
8805
9814
  masking: cfg.masking,
8806
9815
  privacy: cfg.privacy,
9816
+ liveMode: cfg.liveMode,
8807
9817
  };
8808
9818
  const integrationCfg = {
8809
9819
  ...reproAutoMiddlewareConfig,
@@ -8820,6 +9830,7 @@ async function initRepro(cfg) {
8820
9830
  patchKafkaJs(integrationCfg);
8821
9831
  patchAmqplib(integrationCfg);
8822
9832
  patchRedis(integrationCfg);
9833
+ patchPostgreSql(integrationCfg);
8823
9834
  patchMongoDb(integrationCfg);
8824
9835
  await installMongoDbImportHook();
8825
9836
  patchSendgridMail(integrationCfg);
@@ -8855,6 +9866,9 @@ exports.__reproTestHooks = {
8855
9866
  lastClientActivityAt = 0;
8856
9867
  sdkBackgroundQuietUntil = 0;
8857
9868
  },
9869
+ setBackendLiveTimingForTest(override) {
9870
+ backendLiveTimingOverrideForTest = override;
9871
+ },
8858
9872
  runWithRequestContextForTest(ctx, fn) {
8859
9873
  return als.run({
8860
9874
  ...ctx,
@@ -8879,6 +9893,9 @@ exports.__reproTestHooks = {
8879
9893
  patchAmqplibConnectionForTest: patchAmqplibConnection,
8880
9894
  patchAmqplibChannelForTest: patchAmqplibChannel,
8881
9895
  wrapAmqplibConsumeHandlerForTest: wrapAmqplibConsumeHandler,
9896
+ patchPgModuleForTest: patchPgFromModuleExports,
9897
+ patchPostgresJsModuleForTest: patchPostgresJsFromModuleExports,
9898
+ patchTypeOrmModuleForTest: patchTypeOrmFromModuleExports,
8882
9899
  patchMongoDbModuleForTest: patchMongoDbFromModuleExports,
8883
9900
  patchMongoCollectionPrototypeForTest: patchMongoCollectionPrototype,
8884
9901
  chunkTraceEventsForTransportForTest: chunkTraceEventsForTransport,