@use-tusk/drift-node-sdk 0.1.7 → 0.1.9

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.cjs CHANGED
@@ -58,6 +58,10 @@ let __use_tusk_drift_schemas_backend_span_export_service = require("@use-tusk/dr
58
58
  __use_tusk_drift_schemas_backend_span_export_service = __toESM(__use_tusk_drift_schemas_backend_span_export_service);
59
59
  let jsonpath = require("jsonpath");
60
60
  jsonpath = __toESM(jsonpath);
61
+ let net = require("net");
62
+ net = __toESM(net);
63
+ let stream = require("stream");
64
+ stream = __toESM(stream);
61
65
  let __opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conventions");
62
66
  __opentelemetry_semantic_conventions = __toESM(__opentelemetry_semantic_conventions);
63
67
  let __use_tusk_drift_schemas_backend_span_export_service_client = require("@use-tusk/drift-schemas/backend/span_export_service.client");
@@ -66,8 +70,6 @@ let __protobuf_ts_twirp_transport = require("@protobuf-ts/twirp-transport");
66
70
  __protobuf_ts_twirp_transport = __toESM(__protobuf_ts_twirp_transport);
67
71
  let __opentelemetry_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
68
72
  __opentelemetry_sdk_trace_node = __toESM(__opentelemetry_sdk_trace_node);
69
- let net = require("net");
70
- net = __toESM(net);
71
73
  let child_process = require("child_process");
72
74
  child_process = __toESM(child_process);
73
75
  let __use_tusk_drift_schemas_core_communication = require("@use-tusk/drift-schemas/core/communication");
@@ -227,17 +229,28 @@ function withTuskDrift(nextConfig = {}, options = {}) {
227
229
  if (webpackOptions.isServer) {
228
230
  const originalExternals = webpackConfig.externals;
229
231
  const coreExternals = ["require-in-the-middle", "jsonpath"];
232
+ const externalsMapping = {};
233
+ try {
234
+ const sdkPath = require.resolve("@use-tusk/drift-node-sdk");
235
+ const sdkNodeModules = require("path").resolve(sdkPath, "../..", "node_modules");
236
+ for (const pkg of coreExternals) {
237
+ const pkgPath = require("path").join(sdkNodeModules, pkg);
238
+ externalsMapping[pkg] = `commonjs ${pkgPath}`;
239
+ debugLog(debug, `Mapped external ${pkg} -> ${pkgPath}`);
240
+ }
241
+ } catch (e) {
242
+ warn(suppressAllWarnings || false, `Could not resolve SDK path, falling back to regular externals: ${e instanceof Error ? e.message : String(e)}`);
243
+ for (const pkg of coreExternals) externalsMapping[pkg] = `commonjs ${pkg}`;
244
+ }
230
245
  if (!originalExternals) {
231
- webpackConfig.externals = coreExternals;
232
- debugLog(debug, "Created new externals array with core packages");
246
+ webpackConfig.externals = [externalsMapping];
247
+ debugLog(debug, "Created new externals with SDK paths");
233
248
  } else if (Array.isArray(originalExternals)) {
234
- for (const pkg of coreExternals) if (!originalExternals.includes(pkg)) {
235
- originalExternals.push(pkg);
236
- debugLog(debug, `Added ${pkg} to webpack externals`);
237
- }
249
+ originalExternals.push(externalsMapping);
250
+ debugLog(debug, "Added SDK paths to existing externals array");
238
251
  } else {
239
- webpackConfig.externals = [originalExternals, ...coreExternals];
240
- debugLog(debug, "Wrapped existing externals with core packages");
252
+ webpackConfig.externals = [originalExternals, externalsMapping];
253
+ debugLog(debug, "Wrapped existing externals with SDK paths");
241
254
  }
242
255
  }
243
256
  if (typeof config.webpack === "function") return config.webpack(webpackConfig, webpackOptions);
@@ -273,7 +286,7 @@ var TdInstrumentationAbstract = class {
273
286
 
274
287
  //#endregion
275
288
  //#region package.json
276
- var version = "0.1.7";
289
+ var version = "0.1.9";
277
290
 
278
291
  //#endregion
279
292
  //#region src/version.ts
@@ -470,6 +483,20 @@ function loadTuskConfig() {
470
483
  }
471
484
  }
472
485
 
486
+ //#endregion
487
+ //#region src/core/utils/runtimeDetectionUtils.ts
488
+ function isNextJsRuntime() {
489
+ return process.env.NEXT_RUNTIME !== void 0 || typeof global.__NEXT_DATA__ !== "undefined";
490
+ }
491
+ function isEsm(moduleExports) {
492
+ if (!moduleExports || typeof moduleExports !== "object") return false;
493
+ try {
494
+ return moduleExports[Symbol.toStringTag] === "Module";
495
+ } catch (error) {
496
+ return false;
497
+ }
498
+ }
499
+
473
500
  //#endregion
474
501
  //#region src/core/utils/logger.ts
475
502
  var Logger = class {
@@ -749,9 +776,11 @@ var TdInstrumentationNodeModule = class {
749
776
 
750
777
  //#endregion
751
778
  //#region src/core/types.ts
779
+ const TD_INSTRUMENTATION_LIBRARY_NAME = "tusk-drift-sdk";
752
780
  const REPLAY_TRACE_ID_CONTEXT_KEY = (0, __opentelemetry_api.createContextKey)("td.replayTraceId");
753
781
  const SPAN_KIND_CONTEXT_KEY = (0, __opentelemetry_api.createContextKey)("td.spanKind");
754
782
  const IS_PRE_APP_START_CONTEXT_KEY = (0, __opentelemetry_api.createContextKey)("td.isPreAppStart");
783
+ const STOP_RECORDING_CHILD_SPANS_CONTEXT_KEY = (0, __opentelemetry_api.createContextKey)("td.stopRecordingChildSpans");
755
784
  const CALLING_LIBRARY_CONTEXT_KEY = (0, __opentelemetry_api.createContextKey)("td.callingLibrary");
756
785
  let TdSpanAttributes = /* @__PURE__ */ function(TdSpanAttributes$1) {
757
786
  /**
@@ -794,6 +823,74 @@ let TdSpanAttributes = /* @__PURE__ */ function(TdSpanAttributes$1) {
794
823
  return TdSpanAttributes$1;
795
824
  }({});
796
825
 
826
+ //#endregion
827
+ //#region src/core/tracing/TraceBlockingManager.ts
828
+ /**
829
+ * Manages blocked trace IDs to prevent creation and export of spans
830
+ * that belong to traces exceeding size limits.
831
+ *
832
+ * This class uses an in-memory Set for O(1) lookup performance and
833
+ * automatically cleans up old entries to prevent memory leaks.
834
+ */
835
+ var TraceBlockingManager = class TraceBlockingManager {
836
+ constructor() {
837
+ this.blockedTraceIds = /* @__PURE__ */ new Set();
838
+ this.traceTimestamps = /* @__PURE__ */ new Map();
839
+ this.cleanupIntervalId = null;
840
+ this.DEFAULT_TTL_MS = 600 * 1e3;
841
+ this.CLEANUP_INTERVAL_MS = 120 * 1e3;
842
+ this.startCleanupInterval();
843
+ }
844
+ /**
845
+ * Get singleton instance
846
+ */
847
+ static getInstance() {
848
+ if (!TraceBlockingManager.instance) TraceBlockingManager.instance = new TraceBlockingManager();
849
+ return TraceBlockingManager.instance;
850
+ }
851
+ /**
852
+ * Check if a trace ID is blocked
853
+ */
854
+ isTraceBlocked(traceId) {
855
+ return this.blockedTraceIds.has(traceId);
856
+ }
857
+ /**
858
+ * Block a trace ID and all future spans for this trace
859
+ */
860
+ blockTrace(traceId) {
861
+ if (!this.blockedTraceIds.has(traceId)) {
862
+ this.blockedTraceIds.add(traceId);
863
+ const originalDate = OriginalGlobalUtils.getOriginalDate();
864
+ this.traceTimestamps.set(traceId, originalDate.getTime());
865
+ logger.debug(`[TraceBlockingManager] Blocked trace: ${traceId}`);
866
+ }
867
+ }
868
+ /**
869
+ * Start periodic cleanup of old blocked trace IDs
870
+ */
871
+ startCleanupInterval() {
872
+ if (this.cleanupIntervalId) return;
873
+ this.cleanupIntervalId = setInterval(() => {
874
+ this.cleanupOldTraces();
875
+ }, this.CLEANUP_INTERVAL_MS);
876
+ if (this.cleanupIntervalId.unref) this.cleanupIntervalId.unref();
877
+ }
878
+ /**
879
+ * Clean up trace IDs older than TTL
880
+ */
881
+ cleanupOldTraces() {
882
+ const now = OriginalGlobalUtils.getOriginalDate().getTime();
883
+ const expiredTraces = [];
884
+ for (const [traceId, timestamp] of this.traceTimestamps.entries()) if (now - timestamp > this.DEFAULT_TTL_MS) expiredTraces.push(traceId);
885
+ for (const traceId of expiredTraces) {
886
+ this.blockedTraceIds.delete(traceId);
887
+ this.traceTimestamps.delete(traceId);
888
+ }
889
+ if (expiredTraces.length > 0) logger.debug(`[TraceBlockingManager] Cleaned up ${expiredTraces.length} expired blocked trace(s)`);
890
+ }
891
+ };
892
+ TraceBlockingManager.instance = null;
893
+
797
894
  //#endregion
798
895
  //#region src/core/tracing/SpanUtils.ts
799
896
  var SpanUtils = class SpanUtils {
@@ -804,6 +901,14 @@ var SpanUtils = class SpanUtils {
804
901
  try {
805
902
  const tracer = TuskDriftCore.getInstance().getTracer();
806
903
  const parentContext = options.parentContext || __opentelemetry_api.context.active();
904
+ const activeSpan = __opentelemetry_api.trace.getSpan(parentContext);
905
+ if (activeSpan) {
906
+ const parentTraceId = activeSpan.spanContext().traceId;
907
+ if (TraceBlockingManager.getInstance().isTraceBlocked(parentTraceId)) {
908
+ logger.debug(`[SpanUtils] Skipping span creation for '${options.name}' - trace ${parentTraceId} is blocked`);
909
+ return null;
910
+ }
911
+ }
807
912
  const span = tracer.startSpan(options.name, {
808
913
  kind: options.kind || __opentelemetry_api.SpanKind.CLIENT,
809
914
  attributes: options.attributes || {}
@@ -843,7 +948,14 @@ var SpanUtils = class SpanUtils {
843
948
  * @returns The result of the function execution
844
949
  */
845
950
  static createAndExecuteSpan(mode, originalFunctionCall, options, fn) {
846
- const { name, kind, packageName, instrumentationName, packageType, submodule, inputValue, inputSchemaMerges, isPreAppStart, metadata } = options;
951
+ const spanContext = __opentelemetry_api.trace.getActiveSpan()?.spanContext();
952
+ if (spanContext) {
953
+ if (__opentelemetry_api.context.active().getValue(STOP_RECORDING_CHILD_SPANS_CONTEXT_KEY)) {
954
+ logger.debug(`[SpanUtils] Stopping recording of child spans for span ${spanContext.spanId}, packageName: ${options.packageName}, instrumentationName: ${options.instrumentationName}`);
955
+ return originalFunctionCall();
956
+ }
957
+ }
958
+ const { name, kind, packageName, instrumentationName, packageType, submodule, inputValue, inputSchemaMerges, isPreAppStart, metadata, stopRecordingChildSpans } = options;
847
959
  let spanInfo = null;
848
960
  try {
849
961
  spanInfo = SpanUtils.createSpan({
@@ -868,6 +980,7 @@ var SpanUtils = class SpanUtils {
868
980
  }
869
981
  if (!spanInfo) if (mode === TuskDriftMode.REPLAY) throw new Error("Error creating span in replay mode");
870
982
  else return originalFunctionCall();
983
+ if (stopRecordingChildSpans) spanInfo.context = spanInfo.context.setValue(STOP_RECORDING_CHILD_SPANS_CONTEXT_KEY, true);
871
984
  return SpanUtils.withSpan(spanInfo, () => fn(spanInfo));
872
985
  }
873
986
  /**
@@ -1123,6 +1236,22 @@ function getDecodedType(contentType) {
1123
1236
  const mainType = contentTypeString.toLowerCase().split(";")[0].trim();
1124
1237
  return CONTENT_TYPE_MAPPING[mainType];
1125
1238
  }
1239
+ const STATIC_ASSET_TYPES = new Set([
1240
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.HTML,
1241
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.CSS,
1242
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.JAVASCRIPT,
1243
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.JPEG,
1244
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.PNG,
1245
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.GIF,
1246
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.WEBP,
1247
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.SVG,
1248
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.PDF,
1249
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.AUDIO,
1250
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.VIDEO,
1251
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.BINARY,
1252
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.ZIP,
1253
+ __use_tusk_drift_schemas_core_json_schema.DecodedType.GZIP
1254
+ ]);
1126
1255
 
1127
1256
  //#endregion
1128
1257
  //#region src/instrumentation/libraries/http/mocks/TdHttpMockSocket.ts
@@ -1597,6 +1726,28 @@ async function findMockResponseAsync({ mockRequestData, tuskDrift, inputValueSch
1597
1726
  return null;
1598
1727
  }
1599
1728
  }
1729
+ function findMockResponseSync({ mockRequestData, tuskDrift, inputValueSchemaMerges }) {
1730
+ const outboundSpan = convertMockRequestDataToCleanSpanData(mockRequestData, tuskDrift, inputValueSchemaMerges);
1731
+ try {
1732
+ const replayTraceId = SpanUtils.getCurrentReplayTraceId();
1733
+ logger.debug(`Finding ${outboundSpan.traceId} mock for replay trace ID: ${replayTraceId}`);
1734
+ const mockResponse = tuskDrift.requestMockSync({
1735
+ outboundSpan,
1736
+ testId: replayTraceId || ""
1737
+ });
1738
+ if (!mockResponse || !mockResponse.found) {
1739
+ logger.debug(`No matching mock found for ${outboundSpan.traceId} with input value: ${JSON.stringify(outboundSpan.inputValue)}`, replayTraceId);
1740
+ return null;
1741
+ }
1742
+ const responseBody = mockResponse.response?.response?.body;
1743
+ logger.debug(`Found ${outboundSpan.traceId} mock response and timestamp:`, responseBody, { timestamp: mockResponse.response?.timestamp });
1744
+ if (mockResponse.response?.timestamp) DateTracker.updateLatestTimestamp(replayTraceId || "", mockResponse.response.timestamp);
1745
+ return { result: responseBody };
1746
+ } catch (error) {
1747
+ logger.error(`Error finding ${outboundSpan.traceId} mock response:`, error);
1748
+ return null;
1749
+ }
1750
+ }
1600
1751
 
1601
1752
  //#endregion
1602
1753
  //#region src/instrumentation/libraries/http/mocks/TdMockClientRequest.ts
@@ -1727,6 +1878,24 @@ var TdMockClientRequest = class TdMockClientRequest extends events.EventEmitter
1727
1878
  async startPlayback() {
1728
1879
  this.playbackStarted = true;
1729
1880
  try {
1881
+ if (!this.spanInfo) {
1882
+ logger.debug(`[TdMockClientRequest] Background request detected (no spanInfo), returning 200 OK without mock lookup`);
1883
+ const emptyResponse = {
1884
+ statusCode: 200,
1885
+ statusMessage: "OK",
1886
+ headers: {},
1887
+ httpVersion: "1.1",
1888
+ httpVersionMajor: 1,
1889
+ httpVersionMinor: 1,
1890
+ complete: true,
1891
+ readable: false
1892
+ };
1893
+ this.emit("finish");
1894
+ process.nextTick(() => {
1895
+ this.playResponse(emptyResponse);
1896
+ });
1897
+ return;
1898
+ }
1730
1899
  const rawInputValue = {
1731
1900
  method: this.method || "GET",
1732
1901
  path: this.path,
@@ -1764,7 +1933,10 @@ var TdMockClientRequest = class TdMockClientRequest extends events.EventEmitter
1764
1933
  headers: { matchImportance: 0 }
1765
1934
  }
1766
1935
  });
1767
- if (!mockData) throw new Error(`No matching mock found for ${this.method} ${this.path}`);
1936
+ if (!mockData) {
1937
+ logger.warn(`[TdMockClientRequest] No mock data found for ${this.method} ${this.path}`);
1938
+ throw new Error(`[TdMockClientRequest] No matching mock found for ${this.method} ${this.path}`);
1939
+ }
1768
1940
  this.emit("finish");
1769
1941
  process.nextTick(() => {
1770
1942
  this.playResponse(mockData.result);
@@ -1950,11 +2122,19 @@ function handleRecordMode({ originalFunctionCall, recordModeHandler, spanKind })
1950
2122
  /**
1951
2123
  * Utility function that abstracts the common replay mode pattern of checking if the app is ready
1952
2124
  *
1953
- * Currently just calls the replayModeHandler, but we might add some logic here in the future.
2125
+ * If this is a background request (app is ready and no parent span), calls the backgroundRequestHandler.
2126
+ * Otherwise, calls the replayModeHandler.
1954
2127
  * @param replayModeHandler - Function that handles the replay mode logic when app is ready
1955
- * @returns The result from either originalFunctionCall or replayModeHandler
2128
+ * @param noOpRequestHandler - Function to handle no-op requests, called for background requests
2129
+ * @returns The result from either noOpRequestHandler or replayModeHandler
1956
2130
  */
1957
- function handleReplayMode({ replayModeHandler }) {
2131
+ function handleReplayMode({ replayModeHandler, noOpRequestHandler, isServerRequest }) {
2132
+ const isAppReady = TuskDriftCore.getInstance().isAppReady();
2133
+ const currentSpanInfo = SpanUtils.getCurrentSpanInfo();
2134
+ if (isAppReady && !currentSpanInfo && !isServerRequest) {
2135
+ logger.debug(`[ModeUtils] Handling no-op request`);
2136
+ return noOpRequestHandler();
2137
+ }
1958
2138
  return replayModeHandler();
1959
2139
  }
1960
2140
 
@@ -2009,7 +2189,7 @@ function wrap(target, propertyName, wrapper) {
2009
2189
  * Helper functions for capturing stack traces in replay mode
2010
2190
  *
2011
2191
  * TODO: Consider using a structured format for stack frames:
2012
- *
2192
+ *
2013
2193
  * {
2014
2194
  * "frames": [
2015
2195
  * {
@@ -2025,7 +2205,7 @@ function wrap(target, propertyName, wrapper) {
2025
2205
  * It would also allow for more accurate stack trace reconstruction in replay mode.
2026
2206
  */
2027
2207
  /**
2028
- *
2208
+ *
2029
2209
  * @param excludeClassNames - Class names to exclude from the stack trace
2030
2210
  * @returns The stack trace as a string
2031
2211
  */
@@ -2438,7 +2618,7 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
2438
2618
  logger.debug(`[HttpInstrumentation] ${protocolUpper} module already patched, skipping`);
2439
2619
  return httpModule;
2440
2620
  }
2441
- if (httpModule[Symbol.toStringTag] === "Module") {
2621
+ if (isEsm(httpModule)) {
2442
2622
  if (httpModule.default) {
2443
2623
  this._wrap(httpModule.default, "request", this._getRequestPatchFn(protocol));
2444
2624
  this._wrap(httpModule.default, "get", this._getGetPatchFn(protocol));
@@ -2457,67 +2637,76 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
2457
2637
  return httpModule;
2458
2638
  }
2459
2639
  _createServerSpan({ req, res, originalHandler, protocol }) {
2640
+ if (isNextJsRuntime()) {
2641
+ logger.debug(`[HttpInstrumentation] Skipping recording/replaying for nextJs runtime, handled by nextJs instrumentation`);
2642
+ return originalHandler.call(this);
2643
+ }
2460
2644
  const method = req.method || "GET";
2461
2645
  const url = req.url || "/";
2462
2646
  const target = req.url || "/";
2463
2647
  const spanProtocol = this._normalizeProtocol(protocol, "http");
2464
- if (isTuskDriftIngestionUrl(url) || isTuskDriftIngestionUrl(target)) return originalHandler.call(this);
2648
+ if (isTuskDriftIngestionUrl(url) || isTuskDriftIngestionUrl(target)) {
2649
+ logger.debug(`[HttpInstrumentation] Ignoring drift ingestion endpoints`);
2650
+ return originalHandler.call(this);
2651
+ }
2465
2652
  if (this.transformEngine.shouldDropInboundRequest(method, url, req.headers)) {
2466
2653
  logger.debug(`[HttpInstrumentation] Dropping inbound request due to transforms: ${method} ${url}`);
2467
2654
  return originalHandler.call(this);
2468
2655
  }
2469
- if (this.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
2470
- if (req.headers["accept-encoding"]) delete req.headers["accept-encoding"];
2471
- const fullUrl = `${spanProtocol}://${req.headers.host || "localhost"}${url}`;
2472
- const inputValue = {
2473
- method,
2474
- url: fullUrl,
2475
- target,
2476
- headers: req.headers,
2477
- httpVersion: req.httpVersion,
2478
- remoteAddress: req.socket?.remoteAddress,
2479
- remotePort: req.socket?.remotePort
2480
- };
2481
- const replayTraceId = this.replayHooks.extractTraceIdFromHeaders(req);
2482
- if (!replayTraceId) return originalHandler.call(this);
2483
- logger.debug(`[HttpInstrumentation] Setting replay trace id`, replayTraceId);
2484
- const envVars = this.replayHooks.extractEnvVarsFromHeaders(req);
2485
- if (envVars) EnvVarTracker.setEnvVars(replayTraceId, envVars);
2486
- const ctxWithReplayTraceId = SpanUtils.setCurrentReplayTraceId(replayTraceId);
2487
- if (!ctxWithReplayTraceId) throw new Error("Error setting current replay trace id");
2488
- return __opentelemetry_api.context.with(ctxWithReplayTraceId, () => {
2489
- return SpanUtils.createAndExecuteSpan(this.mode, () => originalHandler.call(this), {
2490
- name: `${target}`,
2491
- kind: __opentelemetry_api.SpanKind.SERVER,
2492
- packageName: spanProtocol,
2493
- submodule: method,
2494
- packageType: __use_tusk_drift_schemas_core_span.PackageType.HTTP,
2495
- instrumentationName: this.INSTRUMENTATION_NAME,
2496
- inputValue,
2497
- inputSchemaMerges: { headers: { matchImportance: 0 } },
2498
- isPreAppStart: false
2499
- }, (spanInfo) => {
2500
- return this._handleInboundRequestInSpan({
2501
- req,
2502
- res,
2503
- originalHandler,
2504
- spanInfo,
2656
+ if (this.mode === TuskDriftMode.REPLAY) return handleReplayMode({
2657
+ noOpRequestHandler: () => {
2658
+ throw new Error(`[HttpInstrumentation] Should never call noOpRequestHandler for server requests`);
2659
+ },
2660
+ isServerRequest: true,
2661
+ replayModeHandler: () => {
2662
+ if (req.headers["accept-encoding"]) delete req.headers["accept-encoding"];
2663
+ const fullUrl = `${spanProtocol}://${req.headers.host || "localhost"}${url}`;
2664
+ const inputValue = {
2665
+ method,
2666
+ url: fullUrl,
2667
+ target,
2668
+ headers: req.headers,
2669
+ httpVersion: req.httpVersion,
2670
+ remoteAddress: req.socket?.remoteAddress,
2671
+ remotePort: req.socket?.remotePort
2672
+ };
2673
+ const replayTraceId = this.replayHooks.extractTraceIdFromHeaders(req);
2674
+ if (!replayTraceId) {
2675
+ logger.debug(`[HttpInstrumentation] No trace id found in headers`, req.headers);
2676
+ return originalHandler.call(this);
2677
+ }
2678
+ logger.debug(`[HttpInstrumentation] Setting replay trace id`, replayTraceId);
2679
+ const envVars = this.replayHooks.extractEnvVarsFromHeaders(req);
2680
+ if (envVars) EnvVarTracker.setEnvVars(replayTraceId, envVars);
2681
+ const ctxWithReplayTraceId = SpanUtils.setCurrentReplayTraceId(replayTraceId);
2682
+ if (!ctxWithReplayTraceId) throw new Error("Error setting current replay trace id");
2683
+ return __opentelemetry_api.context.with(ctxWithReplayTraceId, () => {
2684
+ return SpanUtils.createAndExecuteSpan(this.mode, () => originalHandler.call(this), {
2685
+ name: `${target}`,
2686
+ kind: __opentelemetry_api.SpanKind.SERVER,
2687
+ packageName: spanProtocol,
2688
+ submodule: method,
2689
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.HTTP,
2690
+ instrumentationName: this.INSTRUMENTATION_NAME,
2505
2691
  inputValue,
2506
- schemaMerges: { headers: { matchImportance: 0 } },
2507
- protocol: spanProtocol
2692
+ inputSchemaMerges: { headers: { matchImportance: 0 } },
2693
+ isPreAppStart: false
2694
+ }, (spanInfo) => {
2695
+ return this._handleInboundRequestInSpan({
2696
+ req,
2697
+ res,
2698
+ originalHandler,
2699
+ spanInfo,
2700
+ inputValue,
2701
+ schemaMerges: { headers: { matchImportance: 0 } },
2702
+ protocol: spanProtocol
2703
+ });
2508
2704
  });
2509
2705
  });
2510
- });
2511
- } });
2706
+ }
2707
+ });
2512
2708
  else if (this.mode === TuskDriftMode.RECORD) {
2513
2709
  if (method.toUpperCase() === "OPTIONS" || !!req.headers["access-control-request-method"]) return originalHandler.call(this);
2514
- if (!shouldSample({
2515
- samplingRate: this.tuskDrift.getSamplingRate(),
2516
- isAppReady: this.tuskDrift.isAppReady()
2517
- })) {
2518
- logger.debug(`Skipping server span due to sampling rate`, url, this.tuskDrift.getSamplingRate());
2519
- return originalHandler.call(this);
2520
- }
2521
2710
  logger.debug(`[HttpInstrumentation] Creating server span for ${method} ${url}`);
2522
2711
  return handleRecordMode({
2523
2712
  originalFunctionCall: () => originalHandler.call(this),
@@ -2611,7 +2800,6 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
2611
2800
  outputValue.bodySize = responseBuffer.length;
2612
2801
  } catch (error) {
2613
2802
  logger.error(`[HttpInstrumentation] Error processing server response body:`, error);
2614
- outputValue.bodyProcessingError = error instanceof Error ? error.message : String(error);
2615
2803
  }
2616
2804
  try {
2617
2805
  const spanData = {
@@ -2629,7 +2817,7 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
2629
2817
  outputSchemaMerges: {
2630
2818
  body: {
2631
2819
  encoding: __use_tusk_drift_schemas_core_json_schema.EncodingType.BASE64,
2632
- decodedType: getDecodedType(spanData.outputValue.headers?.["content-type"] || "")
2820
+ decodedType: getDecodedType(spanData.outputValue?.headers?.["content-type"] || "")
2633
2821
  },
2634
2822
  headers: { matchImportance: 0 }
2635
2823
  },
@@ -2642,6 +2830,11 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
2642
2830
  message: `HTTP ${statusCode}`
2643
2831
  } : { code: __opentelemetry_api.SpanStatusCode.OK };
2644
2832
  SpanUtils.setStatus(spanInfo.span, status);
2833
+ const decodedType = getDecodedType(outputValue.headers?.["content-type"] || "");
2834
+ if (decodedType && STATIC_ASSET_TYPES.has(decodedType)) {
2835
+ TraceBlockingManager.getInstance().blockTrace(spanInfo.traceId);
2836
+ logger.debug(`[HttpInstrumentation] Blocking trace ${spanInfo.traceId} because it is an static asset response. Decoded type: ${decodedType}`);
2837
+ }
2645
2838
  SpanUtils.endSpan(spanInfo.span);
2646
2839
  } catch (error) {
2647
2840
  logger.error(`[HttpInstrumentation] Error adding response attributes to span:`, error);
@@ -2992,37 +3185,48 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
2992
3185
  const requestProtocol = self._normalizeProtocol(requestOptions.protocol || void 0, protocol);
2993
3186
  if (self.mode === TuskDriftMode.REPLAY) {
2994
3187
  const stackTrace = captureStackTrace(["HttpInstrumentation"]);
2995
- return handleReplayMode({ replayModeHandler: () => {
2996
- const headers = normalizeHeaders(requestOptions.headers || {});
2997
- const inputValue = {
2998
- method,
2999
- path: requestOptions.path || void 0,
3000
- headers,
3001
- protocol: requestProtocol,
3002
- hostname: requestOptions.hostname || requestOptions.host || void 0,
3003
- port: requestOptions.port ? Number(requestOptions.port) : void 0,
3004
- timeout: requestOptions.timeout || void 0
3005
- };
3006
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalRequest.apply(this, args), {
3007
- name: requestOptions.path || `${requestProtocol.toUpperCase()} ${method}`,
3008
- kind: __opentelemetry_api.SpanKind.CLIENT,
3009
- packageName: requestProtocol,
3010
- packageType: __use_tusk_drift_schemas_core_span.PackageType.HTTP,
3011
- instrumentationName: self.INSTRUMENTATION_NAME,
3012
- submodule: method,
3013
- inputValue,
3014
- isPreAppStart: false
3015
- }, (spanInfo) => {
3188
+ return handleReplayMode({
3189
+ noOpRequestHandler: () => {
3016
3190
  return self.replayHooks.handleOutboundReplayRequest({
3017
3191
  method,
3018
3192
  requestOptions,
3019
3193
  protocol: requestProtocol,
3020
- args,
3021
- spanInfo,
3022
- stackTrace
3194
+ args
3023
3195
  });
3024
- });
3025
- } });
3196
+ },
3197
+ isServerRequest: false,
3198
+ replayModeHandler: () => {
3199
+ const headers = normalizeHeaders(requestOptions.headers || {});
3200
+ const inputValue = {
3201
+ method,
3202
+ path: requestOptions.path || void 0,
3203
+ headers,
3204
+ protocol: requestProtocol,
3205
+ hostname: requestOptions.hostname || requestOptions.host || void 0,
3206
+ port: requestOptions.port ? Number(requestOptions.port) : void 0,
3207
+ timeout: requestOptions.timeout || void 0
3208
+ };
3209
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalRequest.apply(this, args), {
3210
+ name: requestOptions.path || `${requestProtocol.toUpperCase()} ${method}`,
3211
+ kind: __opentelemetry_api.SpanKind.CLIENT,
3212
+ packageName: requestProtocol,
3213
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.HTTP,
3214
+ instrumentationName: self.INSTRUMENTATION_NAME,
3215
+ submodule: method,
3216
+ inputValue,
3217
+ isPreAppStart: false
3218
+ }, (spanInfo) => {
3219
+ return self.replayHooks.handleOutboundReplayRequest({
3220
+ method,
3221
+ requestOptions,
3222
+ protocol: requestProtocol,
3223
+ args,
3224
+ spanInfo,
3225
+ stackTrace
3226
+ });
3227
+ });
3228
+ }
3229
+ });
3026
3230
  } else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
3027
3231
  originalFunctionCall: () => originalRequest.apply(this, args),
3028
3232
  recordModeHandler: ({ isPreAppStart }) => {
@@ -3074,36 +3278,47 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
3074
3278
  } else requestOptions = args[0] || {};
3075
3279
  const method = "GET";
3076
3280
  const requestProtocol = self._normalizeProtocol(requestOptions.protocol || void 0, protocol);
3077
- if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
3078
- const headers = normalizeHeaders(requestOptions.headers || {});
3079
- const inputValue = {
3080
- method,
3081
- path: requestOptions.path || void 0,
3082
- headers,
3083
- protocol: requestProtocol,
3084
- hostname: requestOptions.hostname || requestOptions.host || void 0,
3085
- port: requestOptions.port ? Number(requestOptions.port) : void 0,
3086
- timeout: requestOptions.timeout || void 0
3087
- };
3088
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalGet.apply(this, args), {
3089
- name: requestOptions.path || `${requestProtocol.toUpperCase()} ${method}`,
3090
- kind: __opentelemetry_api.SpanKind.CLIENT,
3091
- packageName: requestProtocol,
3092
- packageType: __use_tusk_drift_schemas_core_span.PackageType.HTTP,
3093
- instrumentationName: self.INSTRUMENTATION_NAME,
3094
- submodule: method,
3095
- inputValue,
3096
- isPreAppStart: false
3097
- }, (spanInfo) => {
3281
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
3282
+ noOpRequestHandler: () => {
3098
3283
  return self.replayHooks.handleOutboundReplayRequest({
3099
3284
  method,
3100
3285
  requestOptions,
3101
3286
  protocol: requestProtocol,
3102
- args,
3103
- spanInfo
3287
+ args
3104
3288
  });
3105
- });
3106
- } });
3289
+ },
3290
+ isServerRequest: false,
3291
+ replayModeHandler: () => {
3292
+ const headers = normalizeHeaders(requestOptions.headers || {});
3293
+ const inputValue = {
3294
+ method,
3295
+ path: requestOptions.path || void 0,
3296
+ headers,
3297
+ protocol: requestProtocol,
3298
+ hostname: requestOptions.hostname || requestOptions.host || void 0,
3299
+ port: requestOptions.port ? Number(requestOptions.port) : void 0,
3300
+ timeout: requestOptions.timeout || void 0
3301
+ };
3302
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalGet.apply(this, args), {
3303
+ name: requestOptions.path || `${requestProtocol.toUpperCase()} ${method}`,
3304
+ kind: __opentelemetry_api.SpanKind.CLIENT,
3305
+ packageName: requestProtocol,
3306
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.HTTP,
3307
+ instrumentationName: self.INSTRUMENTATION_NAME,
3308
+ submodule: method,
3309
+ inputValue,
3310
+ isPreAppStart: false
3311
+ }, (spanInfo) => {
3312
+ return self.replayHooks.handleOutboundReplayRequest({
3313
+ method,
3314
+ requestOptions,
3315
+ protocol: requestProtocol,
3316
+ args,
3317
+ spanInfo
3318
+ });
3319
+ });
3320
+ }
3321
+ });
3107
3322
  else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
3108
3323
  originalFunctionCall: () => originalGet.apply(this, args),
3109
3324
  recordModeHandler: ({ isPreAppStart }) => {
@@ -3143,6 +3358,12 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
3143
3358
  return (originalEmit) => {
3144
3359
  return function(eventName, ...args) {
3145
3360
  if (eventName === "request") {
3361
+ if (self.mode === TuskDriftMode.RECORD) {
3362
+ if (!shouldSample({
3363
+ samplingRate: self.tuskDrift.getSamplingRate(),
3364
+ isAppReady: self.tuskDrift.isAppReady()
3365
+ })) return originalEmit.apply(this, [eventName, ...args]);
3366
+ }
3146
3367
  const req = args[0];
3147
3368
  const res = args[1];
3148
3369
  return self._createServerSpan({
@@ -3493,7 +3714,8 @@ var TdPgClientMock = class extends events.EventEmitter {
3493
3714
  clientType: "client"
3494
3715
  };
3495
3716
  const inputValue = createMockInputValue(rawInputValue);
3496
- return this.pgInstrumentation.handleReplayQuery(queryConfig, inputValue, this.spanInfo, stackTrace);
3717
+ if (this.spanInfo) return this.pgInstrumentation.handleReplayQuery(queryConfig, inputValue, this.spanInfo, stackTrace);
3718
+ else return this.pgInstrumentation.handleNoOpReplayQuery(queryConfig);
3497
3719
  }
3498
3720
  release() {
3499
3721
  this.emit("end");
@@ -3598,22 +3820,28 @@ var PgInstrumentation = class extends TdInstrumentationBase {
3598
3820
  };
3599
3821
  if (self.mode === TuskDriftMode.REPLAY) {
3600
3822
  const stackTrace = captureStackTrace(["PgInstrumentation"]);
3601
- return handleReplayMode({ replayModeHandler: () => {
3602
- const packageName = inputValue.clientType === "pool" ? "pg-pool" : "pg";
3603
- const spanName = inputValue.clientType === "pool" ? "pg-pool.query" : "pg.query";
3604
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalQuery.apply(this, args), {
3605
- name: spanName,
3606
- kind: __opentelemetry_api.SpanKind.CLIENT,
3607
- submodule: "query",
3608
- packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
3609
- packageName,
3610
- instrumentationName: self.INSTRUMENTATION_NAME,
3611
- inputValue,
3612
- isPreAppStart: false
3613
- }, (spanInfo) => {
3614
- return self.handleReplayQuery(queryConfig, inputValue, spanInfo, stackTrace);
3615
- });
3616
- } });
3823
+ return handleReplayMode({
3824
+ noOpRequestHandler: () => {
3825
+ return self.handleNoOpReplayQuery(queryConfig);
3826
+ },
3827
+ isServerRequest: false,
3828
+ replayModeHandler: () => {
3829
+ const packageName = inputValue.clientType === "pool" ? "pg-pool" : "pg";
3830
+ const spanName = inputValue.clientType === "pool" ? "pg-pool.query" : "pg.query";
3831
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalQuery.apply(this, args), {
3832
+ name: spanName,
3833
+ kind: __opentelemetry_api.SpanKind.CLIENT,
3834
+ submodule: "query",
3835
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
3836
+ packageName,
3837
+ instrumentationName: self.INSTRUMENTATION_NAME,
3838
+ inputValue,
3839
+ isPreAppStart: false
3840
+ }, (spanInfo) => {
3841
+ return self.handleReplayQuery(queryConfig, inputValue, spanInfo, stackTrace);
3842
+ });
3843
+ }
3844
+ });
3617
3845
  } else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
3618
3846
  originalFunctionCall: () => originalQuery.apply(this, args),
3619
3847
  recordModeHandler: ({ isPreAppStart }) => {
@@ -3643,20 +3871,29 @@ var PgInstrumentation = class extends TdInstrumentationBase {
3643
3871
  return (originalConnect) => {
3644
3872
  return function connect(callback) {
3645
3873
  const inputValue = { clientType };
3646
- if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
3647
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalConnect.apply(this, [callback]), {
3648
- name: `pg.connect`,
3649
- kind: __opentelemetry_api.SpanKind.CLIENT,
3650
- submodule: "connect",
3651
- packageName: "pg",
3652
- packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
3653
- instrumentationName: self.INSTRUMENTATION_NAME,
3654
- inputValue,
3655
- isPreAppStart: false
3656
- }, (spanInfo) => {
3657
- return self._handleReplayConnect(callback);
3658
- });
3659
- } });
3874
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
3875
+ noOpRequestHandler: () => {
3876
+ if (callback) {
3877
+ process.nextTick(() => callback(null));
3878
+ return;
3879
+ } else return Promise.resolve();
3880
+ },
3881
+ isServerRequest: false,
3882
+ replayModeHandler: () => {
3883
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalConnect.apply(this, [callback]), {
3884
+ name: `pg.connect`,
3885
+ kind: __opentelemetry_api.SpanKind.CLIENT,
3886
+ submodule: "connect",
3887
+ packageName: "pg",
3888
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
3889
+ instrumentationName: self.INSTRUMENTATION_NAME,
3890
+ inputValue,
3891
+ isPreAppStart: false
3892
+ }, (spanInfo) => {
3893
+ return self._handleReplayConnect(callback);
3894
+ });
3895
+ }
3896
+ });
3660
3897
  else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
3661
3898
  originalFunctionCall: () => originalConnect.apply(this, [callback]),
3662
3899
  recordModeHandler: ({ isPreAppStart }) => {
@@ -3760,7 +3997,17 @@ var PgInstrumentation = class extends TdInstrumentationBase {
3760
3997
  throw error;
3761
3998
  });
3762
3999
  }
3763
- async handleReplayQuery(queryConfig, inputValue, spanInfo, stackTrace) {
4000
+ async handleNoOpReplayQuery(queryConfig) {
4001
+ const emptyResult = {
4002
+ rows: [],
4003
+ rowCount: 0
4004
+ };
4005
+ if (queryConfig.callback) {
4006
+ process.nextTick(() => queryConfig.callback(null, emptyResult));
4007
+ return;
4008
+ } else return Promise.resolve(emptyResult);
4009
+ }
4010
+ async handleReplayQuery(queryConfig, inputValue, spanInfo, stackTrace) {
3764
4011
  logger.debug(`[PgInstrumentation] Replaying PG query`);
3765
4012
  const packageName = inputValue.clientType === "pool" ? "pg-pool" : "pg";
3766
4013
  const spanName = inputValue.clientType === "pool" ? "pg-pool.query" : "pg.query";
@@ -3781,10 +4028,7 @@ var PgInstrumentation = class extends TdInstrumentationBase {
3781
4028
  if (!mockData) {
3782
4029
  const queryText = queryConfig.text || inputValue.text || "UNKNOWN_QUERY";
3783
4030
  logger.warn(`[PgInstrumentation] No mock data found for PG query: ${queryText}`);
3784
- if (queryConfig.callback) {
3785
- process.nextTick(() => queryConfig.callback(/* @__PURE__ */ new Error("No mock data found")));
3786
- return;
3787
- } else return Promise.reject(/* @__PURE__ */ new Error("No mock data found"));
4031
+ throw new Error(`[PgInstrumentation] No mock data found for PG query: ${queryText}`);
3788
4032
  }
3789
4033
  const processedResult = this.convertPostgresTypes(mockData.result);
3790
4034
  if (queryConfig.callback) {
@@ -3919,20 +4163,30 @@ var PgInstrumentation = class extends TdInstrumentationBase {
3919
4163
  return (originalConnect) => {
3920
4164
  return function connect(callback) {
3921
4165
  const inputValue = { clientType: "pool" };
3922
- if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
3923
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalConnect.apply(this, [callback]), {
3924
- name: `pg-pool.connect`,
3925
- kind: __opentelemetry_api.SpanKind.CLIENT,
3926
- submodule: "connect",
3927
- packageName: "pg-pool",
3928
- packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
3929
- instrumentationName: self.INSTRUMENTATION_NAME,
3930
- inputValue,
3931
- isPreAppStart: false
3932
- }, (spanInfo) => {
3933
- return self._handleReplayPoolConnect(spanInfo, callback);
3934
- });
3935
- } });
4166
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
4167
+ noOpRequestHandler: () => {
4168
+ const mockClient = new TdPgClientMock(self);
4169
+ if (callback) {
4170
+ process.nextTick(() => callback(null, mockClient, () => {}));
4171
+ return;
4172
+ } else return Promise.resolve(mockClient);
4173
+ },
4174
+ isServerRequest: false,
4175
+ replayModeHandler: () => {
4176
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalConnect.apply(this, [callback]), {
4177
+ name: `pg-pool.connect`,
4178
+ kind: __opentelemetry_api.SpanKind.CLIENT,
4179
+ submodule: "connect",
4180
+ packageName: "pg-pool",
4181
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
4182
+ instrumentationName: self.INSTRUMENTATION_NAME,
4183
+ inputValue,
4184
+ isPreAppStart: false
4185
+ }, (spanInfo) => {
4186
+ return self._handleReplayPoolConnect(spanInfo, callback);
4187
+ });
4188
+ }
4189
+ });
3936
4190
  else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
3937
4191
  originalFunctionCall: () => originalConnect.apply(this, [callback]),
3938
4192
  recordModeHandler: ({ isPreAppStart }) => {
@@ -4055,7 +4309,7 @@ var PostgresInstrumentation = class extends TdInstrumentationBase {
4055
4309
  return postgresModule;
4056
4310
  }
4057
4311
  const self = this;
4058
- if (postgresModule[Symbol.toStringTag] === "Module") {
4312
+ if (isEsm(postgresModule)) {
4059
4313
  logger.debug(`[PostgresInstrumentation] Wrapping ESM default export`);
4060
4314
  this._wrap(postgresModule, "default", (originalFunction) => {
4061
4315
  return function(...args) {
@@ -4095,23 +4349,35 @@ var PostgresInstrumentation = class extends TdInstrumentationBase {
4095
4349
  connectionString: connectionString ? this._sanitizeConnectionString(connectionString) : void 0,
4096
4350
  options: options ? this._sanitizeConnectionOptions(options) : void 0
4097
4351
  };
4098
- if (this.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
4099
- return SpanUtils.createAndExecuteSpan(this.mode, () => {
4100
- const sqlInstance = originalFunction(...args);
4101
- return this._wrapSqlInstance(sqlInstance);
4102
- }, {
4103
- name: "postgres.connect",
4104
- kind: __opentelemetry_api.SpanKind.CLIENT,
4105
- submodule: "connect",
4106
- packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
4107
- packageName: "postgres",
4108
- instrumentationName: this.INSTRUMENTATION_NAME,
4109
- inputValue,
4110
- isPreAppStart: false
4111
- }, (spanInfo) => {
4112
- return this._handleReplayConnect(spanInfo, originalFunction, args);
4113
- });
4114
- } });
4352
+ if (this.mode === TuskDriftMode.REPLAY) return handleReplayMode({
4353
+ noOpRequestHandler: () => {
4354
+ try {
4355
+ const sqlInstance = originalFunction(...args);
4356
+ return this._wrapSqlInstance(sqlInstance);
4357
+ } catch (error) {
4358
+ logger.debug(`[PostgresInstrumentation] Postgres connection error in replay: ${error.message}`);
4359
+ throw error;
4360
+ }
4361
+ },
4362
+ isServerRequest: false,
4363
+ replayModeHandler: () => {
4364
+ return SpanUtils.createAndExecuteSpan(this.mode, () => {
4365
+ const sqlInstance = originalFunction(...args);
4366
+ return this._wrapSqlInstance(sqlInstance);
4367
+ }, {
4368
+ name: "postgres.connect",
4369
+ kind: __opentelemetry_api.SpanKind.CLIENT,
4370
+ submodule: "connect",
4371
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
4372
+ packageName: "postgres",
4373
+ instrumentationName: this.INSTRUMENTATION_NAME,
4374
+ inputValue,
4375
+ isPreAppStart: false
4376
+ }, (spanInfo) => {
4377
+ return this._handleReplayConnect(originalFunction, args);
4378
+ });
4379
+ }
4380
+ });
4115
4381
  else if (this.mode === TuskDriftMode.RECORD) return handleRecordMode({
4116
4382
  originalFunctionCall: () => {
4117
4383
  const sqlInstance = originalFunction(...args);
@@ -4171,20 +4437,13 @@ var PostgresInstrumentation = class extends TdInstrumentationBase {
4171
4437
  }
4172
4438
  return wrappedInstance;
4173
4439
  }
4174
- _handleReplayConnect(spanInfo, originalFunction, args) {
4440
+ _handleReplayConnect(originalFunction, args) {
4175
4441
  logger.debug(`[PostgresInstrumentation] Replaying Postgres connection`);
4176
4442
  try {
4177
4443
  const sqlInstance = originalFunction(...args);
4178
- const wrappedInstance = this._wrapSqlInstance(sqlInstance);
4179
- SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: { connected: true } });
4180
- SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
4181
- return wrappedInstance;
4444
+ return this._wrapSqlInstance(sqlInstance);
4182
4445
  } catch (error) {
4183
4446
  logger.debug(`[PostgresInstrumentation] Postgres connection error in replay: ${error.message}`);
4184
- SpanUtils.endSpan(spanInfo.span, {
4185
- code: __opentelemetry_api.SpanStatusCode.ERROR,
4186
- message: error.message
4187
- });
4188
4447
  throw error;
4189
4448
  }
4190
4449
  }
@@ -4244,26 +4503,30 @@ var PostgresInstrumentation = class extends TdInstrumentationBase {
4244
4503
  };
4245
4504
  if (this.mode === TuskDriftMode.REPLAY) {
4246
4505
  const stackTrace = captureStackTrace(["PostgresInstrumentation"]);
4247
- return handleReplayMode({ replayModeHandler: () => {
4248
- return SpanUtils.createAndExecuteSpan(this.mode, () => originalSql.call(this, strings, ...values), {
4249
- name: "postgres.query",
4250
- kind: __opentelemetry_api.SpanKind.CLIENT,
4251
- submodule: "query",
4252
- packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
4253
- packageName: "postgres",
4254
- instrumentationName: this.INSTRUMENTATION_NAME,
4255
- inputValue,
4256
- isPreAppStart: false
4257
- }, (spanInfo) => {
4258
- return this.handleReplaySqlQuery({
4259
- inputValue,
4260
- spanInfo,
4261
- submodule: "query",
4506
+ return handleReplayMode({
4507
+ noOpRequestHandler: () => {},
4508
+ isServerRequest: false,
4509
+ replayModeHandler: () => {
4510
+ return SpanUtils.createAndExecuteSpan(this.mode, () => originalSql.call(this, strings, ...values), {
4262
4511
  name: "postgres.query",
4263
- stackTrace
4512
+ kind: __opentelemetry_api.SpanKind.CLIENT,
4513
+ submodule: "query",
4514
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
4515
+ packageName: "postgres",
4516
+ instrumentationName: this.INSTRUMENTATION_NAME,
4517
+ inputValue,
4518
+ isPreAppStart: false
4519
+ }, (spanInfo) => {
4520
+ return this.handleReplaySqlQuery({
4521
+ inputValue,
4522
+ spanInfo,
4523
+ submodule: "query",
4524
+ name: "postgres.query",
4525
+ stackTrace
4526
+ });
4264
4527
  });
4265
- });
4266
- } });
4528
+ }
4529
+ });
4267
4530
  } else if (this.mode === TuskDriftMode.RECORD) return handleRecordMode({
4268
4531
  originalFunctionCall: () => originalSql.call(this, strings, ...values),
4269
4532
  recordModeHandler: ({ isPreAppStart }) => {
@@ -4297,28 +4560,34 @@ var PostgresInstrumentation = class extends TdInstrumentationBase {
4297
4560
  };
4298
4561
  if (this.mode === TuskDriftMode.REPLAY) {
4299
4562
  const stackTrace = captureStackTrace(["PostgresInstrumentation"]);
4300
- return handleReplayMode({ replayModeHandler: () => {
4301
- return this._createPendingQueryWrapper(() => {
4302
- return SpanUtils.createAndExecuteSpan(this.mode, () => executeUnsafe(), {
4303
- name: "postgres.unsafe",
4304
- kind: __opentelemetry_api.SpanKind.CLIENT,
4305
- submodule: "unsafe",
4306
- packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
4307
- packageName: "postgres",
4308
- instrumentationName: this.INSTRUMENTATION_NAME,
4309
- inputValue,
4310
- isPreAppStart: false
4311
- }, (spanInfo) => {
4312
- return this.handleReplayUnsafeQuery({
4313
- inputValue,
4314
- spanInfo,
4315
- submodule: "unsafe",
4563
+ return handleReplayMode({
4564
+ noOpRequestHandler: () => {
4565
+ return Promise.resolve(void 0);
4566
+ },
4567
+ isServerRequest: false,
4568
+ replayModeHandler: () => {
4569
+ return this._createPendingQueryWrapper(() => {
4570
+ return SpanUtils.createAndExecuteSpan(this.mode, () => executeUnsafe(), {
4316
4571
  name: "postgres.unsafe",
4317
- stackTrace
4572
+ kind: __opentelemetry_api.SpanKind.CLIENT,
4573
+ submodule: "unsafe",
4574
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
4575
+ packageName: "postgres",
4576
+ instrumentationName: this.INSTRUMENTATION_NAME,
4577
+ inputValue,
4578
+ isPreAppStart: false
4579
+ }, (spanInfo) => {
4580
+ return this.handleReplayUnsafeQuery({
4581
+ inputValue,
4582
+ spanInfo,
4583
+ submodule: "unsafe",
4584
+ name: "postgres.unsafe",
4585
+ stackTrace
4586
+ });
4318
4587
  });
4319
4588
  });
4320
- });
4321
- } });
4589
+ }
4590
+ });
4322
4591
  } else if (this.mode === TuskDriftMode.RECORD) return handleRecordMode({
4323
4592
  originalFunctionCall: executeUnsafe,
4324
4593
  recordModeHandler: ({ isPreAppStart }) => {
@@ -4351,20 +4620,24 @@ var PostgresInstrumentation = class extends TdInstrumentationBase {
4351
4620
  };
4352
4621
  if (this.mode === TuskDriftMode.REPLAY) {
4353
4622
  const stackTrace = captureStackTrace(["PostgresInstrumentation"]);
4354
- return handleReplayMode({ replayModeHandler: () => {
4355
- return SpanUtils.createAndExecuteSpan(this.mode, () => executeBegin(), {
4356
- name: "postgres.begin",
4357
- kind: __opentelemetry_api.SpanKind.CLIENT,
4358
- submodule: "transaction",
4359
- packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
4360
- packageName: "postgres",
4361
- instrumentationName: this.INSTRUMENTATION_NAME,
4362
- inputValue,
4363
- isPreAppStart: false
4364
- }, (spanInfo) => {
4365
- return this._handleReplayBeginTransaction(spanInfo, options, stackTrace);
4366
- });
4367
- } });
4623
+ return handleReplayMode({
4624
+ noOpRequestHandler: () => {},
4625
+ isServerRequest: false,
4626
+ replayModeHandler: () => {
4627
+ return SpanUtils.createAndExecuteSpan(this.mode, () => executeBegin(), {
4628
+ name: "postgres.begin",
4629
+ kind: __opentelemetry_api.SpanKind.CLIENT,
4630
+ submodule: "transaction",
4631
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.PG,
4632
+ packageName: "postgres",
4633
+ instrumentationName: this.INSTRUMENTATION_NAME,
4634
+ inputValue,
4635
+ isPreAppStart: false
4636
+ }, (spanInfo) => {
4637
+ return this._handleReplayBeginTransaction(spanInfo, options, stackTrace);
4638
+ });
4639
+ }
4640
+ });
4368
4641
  } else if (this.mode === TuskDriftMode.RECORD) return handleRecordMode({
4369
4642
  originalFunctionCall: executeBegin,
4370
4643
  recordModeHandler: ({ isPreAppStart }) => {
@@ -4480,28 +4753,13 @@ var PostgresInstrumentation = class extends TdInstrumentationBase {
4480
4753
  });
4481
4754
  if (!mockData) {
4482
4755
  logger.warn(`[PostgresInstrumentation] No mock data found for transaction BEGIN`);
4483
- SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
4484
- return;
4756
+ throw new Error(`[PostgresInstrumentation] No matching mock found for transaction BEGIN`);
4485
4757
  }
4486
4758
  logger.debug(`[PostgresInstrumentation] Found mock data for transaction: ${JSON.stringify(mockData)}`);
4487
4759
  const transactionResult = mockData.result;
4488
- if (transactionResult && typeof transactionResult === "object" && "status" in transactionResult && transactionResult.status === "committed") {
4489
- SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: {
4490
- status: "committed",
4491
- result: transactionResult.result
4492
- } });
4493
- SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
4494
- return transactionResult.result;
4495
- } else {
4760
+ if (transactionResult && typeof transactionResult === "object" && "status" in transactionResult && transactionResult.status === "committed") return transactionResult.result;
4761
+ else {
4496
4762
  const errorMessage = transactionResult && typeof transactionResult === "object" && "error" in transactionResult && transactionResult.error ? transactionResult.error : "Transaction rolled back";
4497
- SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: {
4498
- status: "rolled_back",
4499
- error: errorMessage
4500
- } });
4501
- SpanUtils.endSpan(spanInfo.span, {
4502
- code: __opentelemetry_api.SpanStatusCode.ERROR,
4503
- message: errorMessage
4504
- });
4505
4763
  throw new Error(errorMessage);
4506
4764
  }
4507
4765
  }
@@ -4548,7 +4806,7 @@ var PostgresInstrumentation = class extends TdInstrumentationBase {
4548
4806
  if (!mockData) {
4549
4807
  const queryText = inputValue.query || "UNKNOWN_QUERY";
4550
4808
  logger.warn(`[PostgresInstrumentation] No mock data found for Postgres sql query: ${queryText}`);
4551
- return;
4809
+ throw new Error(`[PostgresInstrumentation] No matching mock found for Postgres sql query: ${queryText}`);
4552
4810
  }
4553
4811
  logger.debug(`[PostgresInstrumentation] Found mock data for Postgres sql query: ${JSON.stringify(mockData)}`);
4554
4812
  const processedResult = this.convertPostgresTypes(mockData.result);
@@ -4579,7 +4837,7 @@ var PostgresInstrumentation = class extends TdInstrumentationBase {
4579
4837
  if (!mockData) {
4580
4838
  const queryText = inputValue.query || "UNKNOWN_QUERY";
4581
4839
  logger.warn(`[PostgresInstrumentation] No mock data found for Postgres unsafe query: ${queryText}`);
4582
- return;
4840
+ throw new Error(`[PostgresInstrumentation] No matching mock found for Postgres unsafe query: ${queryText}`);
4583
4841
  }
4584
4842
  logger.debug(`[PostgresInstrumentation] Found mock data for Postgres unsafe query: ${JSON.stringify(mockData)}`);
4585
4843
  const processedResult = this.convertPostgresTypes(mockData.result);
@@ -4668,7 +4926,7 @@ var PostgresInstrumentation = class extends TdInstrumentationBase {
4668
4926
  * Extends EventEmitter to properly handle all connection methods and events
4669
4927
  */
4670
4928
  var TdMysql2ConnectionMock = class extends events.EventEmitter {
4671
- constructor(mysql2Instrumentation, spanInfo, clientType = "poolConnection") {
4929
+ constructor(mysql2Instrumentation, clientType = "poolConnection", spanInfo) {
4672
4930
  super();
4673
4931
  this.threadId = null;
4674
4932
  this.config = {
@@ -4704,7 +4962,8 @@ var TdMysql2ConnectionMock = class extends events.EventEmitter {
4704
4962
  clientType: this.clientType
4705
4963
  };
4706
4964
  const inputValue = createMockInputValue(rawInputValue);
4707
- return this.mysql2Instrumentation.handleReplayQuery(queryConfig, inputValue, this.spanInfo, stackTrace);
4965
+ if (this.spanInfo) return this.mysql2Instrumentation.handleReplayQuery(queryConfig, inputValue, this.spanInfo, stackTrace);
4966
+ else return this.mysql2Instrumentation.handleNoOpReplayQuery(queryConfig);
4708
4967
  }
4709
4968
  execute(...args) {
4710
4969
  logger.debug(`[TdMysql2ConnectionMock] Mock connection execute intercepted in REPLAY mode`);
@@ -4728,7 +4987,8 @@ var TdMysql2ConnectionMock = class extends events.EventEmitter {
4728
4987
  clientType: this.clientType
4729
4988
  };
4730
4989
  const inputValue = createMockInputValue(rawInputValue);
4731
- return this.mysql2Instrumentation.handleReplayQuery(queryConfig, inputValue, this.spanInfo, stackTrace);
4990
+ if (this.spanInfo) return this.mysql2Instrumentation.handleReplayQuery(queryConfig, inputValue, this.spanInfo, stackTrace);
4991
+ else return this.mysql2Instrumentation.handleNoOpReplayQuery(queryConfig);
4732
4992
  }
4733
4993
  release() {
4734
4994
  this.emit("end");
@@ -4828,6 +5088,27 @@ var TdMysql2QueryMock = class {
4828
5088
  return this._handleQuery(queryConfig, inputValue, spanInfo, spanName, submoduleName, stackTrace);
4829
5089
  }
4830
5090
  /**
5091
+ * Handle background query requests (outside of trace context)
5092
+ * Returns an EventEmitter that immediately completes with empty results
5093
+ */
5094
+ handleNoOpReplayQuery(queryConfig) {
5095
+ logger.debug(`[Mysql2Instrumentation] Background query detected, returning empty result`);
5096
+ const emitter = new events.EventEmitter();
5097
+ emitter.then = function(onResolve, onReject) {
5098
+ return new Promise((resolve) => {
5099
+ emitter.once("end", () => {
5100
+ resolve([[], []]);
5101
+ });
5102
+ }).then(onResolve, onReject);
5103
+ };
5104
+ process.nextTick(() => {
5105
+ const callback = queryConfig.callback;
5106
+ if (callback) callback(null, [], []);
5107
+ emitter.emit("end");
5108
+ });
5109
+ return emitter;
5110
+ }
5111
+ /**
4831
5112
  * Handle query - always returns an EventEmitter (like mysql2 does)
4832
5113
  * This handles both callback and streaming modes
4833
5114
  * The EventEmitter is also thenable (has a .then() method) to support await/Promise usage
@@ -4852,12 +5133,7 @@ var TdMysql2QueryMock = class {
4852
5133
  if (!mockData) {
4853
5134
  const sql = queryConfig.sql || inputValue.sql || "UNKNOWN_QUERY";
4854
5135
  logger.warn(`[Mysql2Instrumentation] No mock data found for MySQL2 query: ${sql}`);
4855
- const error = /* @__PURE__ */ new Error("No mock data found");
4856
- process.nextTick(() => {
4857
- if (queryConfig.callback) queryConfig.callback(error);
4858
- emitter.emit("error", error);
4859
- });
4860
- return;
5136
+ throw new Error(`[Mysql2Instrumentation] No matching mock found for query: ${sql}`);
4861
5137
  }
4862
5138
  const processedResult = this._convertMysql2Types(mockData.result);
4863
5139
  storedRows = processedResult.rows;
@@ -5182,21 +5458,27 @@ var Mysql2Instrumentation = class extends TdInstrumentationBase {
5182
5458
  };
5183
5459
  if (self.mode === TuskDriftMode.REPLAY) {
5184
5460
  const stackTrace = captureStackTrace(["Mysql2Instrumentation"]);
5185
- return handleReplayMode({ replayModeHandler: () => {
5186
- const spanName = `mysql2.${clientType}.query`;
5187
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalQuery.apply(this, args), {
5188
- name: spanName,
5189
- kind: __opentelemetry_api.SpanKind.CLIENT,
5190
- submodule: "query",
5191
- packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5192
- packageName: "mysql2",
5193
- instrumentationName: self.INSTRUMENTATION_NAME,
5194
- inputValue,
5195
- isPreAppStart: false
5196
- }, (spanInfo) => {
5197
- return self.handleReplayQuery(queryConfig, inputValue, spanInfo, "query", stackTrace);
5198
- });
5199
- } });
5461
+ return handleReplayMode({
5462
+ noOpRequestHandler: () => {
5463
+ return self.queryMock.handleNoOpReplayQuery(queryConfig);
5464
+ },
5465
+ isServerRequest: false,
5466
+ replayModeHandler: () => {
5467
+ const spanName = `mysql2.${clientType}.query`;
5468
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalQuery.apply(this, args), {
5469
+ name: spanName,
5470
+ kind: __opentelemetry_api.SpanKind.CLIENT,
5471
+ submodule: "query",
5472
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5473
+ packageName: "mysql2",
5474
+ instrumentationName: self.INSTRUMENTATION_NAME,
5475
+ inputValue,
5476
+ isPreAppStart: false
5477
+ }, (spanInfo) => {
5478
+ return self.handleReplayQuery(queryConfig, inputValue, spanInfo, "query", stackTrace);
5479
+ });
5480
+ }
5481
+ });
5200
5482
  } else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
5201
5483
  originalFunctionCall: () => originalQuery.apply(this, args),
5202
5484
  recordModeHandler: ({ isPreAppStart }) => {
@@ -5241,21 +5523,27 @@ var Mysql2Instrumentation = class extends TdInstrumentationBase {
5241
5523
  };
5242
5524
  if (self.mode === TuskDriftMode.REPLAY) {
5243
5525
  const stackTrace = captureStackTrace(["Mysql2Instrumentation"]);
5244
- return handleReplayMode({ replayModeHandler: () => {
5245
- const spanName = `mysql2.${clientType}.execute`;
5246
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalExecute.apply(this, args), {
5247
- name: spanName,
5248
- kind: __opentelemetry_api.SpanKind.CLIENT,
5249
- submodule: "execute",
5250
- packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5251
- packageName: "mysql2",
5252
- instrumentationName: self.INSTRUMENTATION_NAME,
5253
- inputValue,
5254
- isPreAppStart: false
5255
- }, (spanInfo) => {
5256
- return self.handleReplayQuery(queryConfig, inputValue, spanInfo, "execute", stackTrace);
5257
- });
5258
- } });
5526
+ return handleReplayMode({
5527
+ noOpRequestHandler: () => {
5528
+ return self.queryMock.handleNoOpReplayQuery(queryConfig);
5529
+ },
5530
+ isServerRequest: false,
5531
+ replayModeHandler: () => {
5532
+ const spanName = `mysql2.${clientType}.execute`;
5533
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalExecute.apply(this, args), {
5534
+ name: spanName,
5535
+ kind: __opentelemetry_api.SpanKind.CLIENT,
5536
+ submodule: "execute",
5537
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5538
+ packageName: "mysql2",
5539
+ instrumentationName: self.INSTRUMENTATION_NAME,
5540
+ inputValue,
5541
+ isPreAppStart: false
5542
+ }, (spanInfo) => {
5543
+ return self.handleReplayQuery(queryConfig, inputValue, spanInfo, "execute", stackTrace);
5544
+ });
5545
+ }
5546
+ });
5259
5547
  } else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
5260
5548
  originalFunctionCall: () => originalExecute.apply(this, args),
5261
5549
  recordModeHandler: ({ isPreAppStart }) => {
@@ -5284,20 +5572,26 @@ var Mysql2Instrumentation = class extends TdInstrumentationBase {
5284
5572
  return (originalGetConnection) => {
5285
5573
  return function getConnection(callback) {
5286
5574
  const inputValue = { clientType: "pool" };
5287
- if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
5288
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalGetConnection.apply(this, [callback]), {
5289
- name: `mysql2.pool.getConnection`,
5290
- kind: __opentelemetry_api.SpanKind.CLIENT,
5291
- submodule: "getConnection",
5292
- packageName: "mysql2",
5293
- packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5294
- instrumentationName: self.INSTRUMENTATION_NAME,
5295
- inputValue,
5296
- isPreAppStart: false
5297
- }, (spanInfo) => {
5298
- return self._handleReplayPoolGetConnection(spanInfo, callback);
5299
- });
5300
- } });
5575
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
5576
+ noOpRequestHandler: () => {
5577
+ return self.handleNoOpReplayGetConnection(callback);
5578
+ },
5579
+ isServerRequest: false,
5580
+ replayModeHandler: () => {
5581
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalGetConnection.apply(this, [callback]), {
5582
+ name: `mysql2.pool.getConnection`,
5583
+ kind: __opentelemetry_api.SpanKind.CLIENT,
5584
+ submodule: "getConnection",
5585
+ packageName: "mysql2",
5586
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5587
+ instrumentationName: self.INSTRUMENTATION_NAME,
5588
+ inputValue,
5589
+ isPreAppStart: false
5590
+ }, (spanInfo) => {
5591
+ return self._handleReplayPoolGetConnection(spanInfo, callback);
5592
+ });
5593
+ }
5594
+ });
5301
5595
  else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
5302
5596
  originalFunctionCall: () => originalGetConnection.apply(this, [callback]),
5303
5597
  recordModeHandler: ({ isPreAppStart }) => {
@@ -5325,24 +5619,34 @@ var Mysql2Instrumentation = class extends TdInstrumentationBase {
5325
5619
  return (originalConnect) => {
5326
5620
  return function connect(callback) {
5327
5621
  const inputValue = { clientType };
5328
- if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
5329
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalConnect.apply(this, [callback]), {
5330
- name: `mysql2.${clientType}.connect`,
5331
- kind: __opentelemetry_api.SpanKind.CLIENT,
5332
- submodule: "connect",
5333
- packageName: "mysql2",
5334
- packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5335
- instrumentationName: self.INSTRUMENTATION_NAME,
5336
- inputValue,
5337
- isPreAppStart: false
5338
- }, (spanInfo) => {
5622
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
5623
+ noOpRequestHandler: () => {
5339
5624
  if (callback) {
5340
5625
  process.nextTick(() => callback(null));
5341
5626
  return;
5342
5627
  }
5343
5628
  return Promise.resolve();
5344
- });
5345
- } });
5629
+ },
5630
+ isServerRequest: false,
5631
+ replayModeHandler: () => {
5632
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalConnect.apply(this, [callback]), {
5633
+ name: `mysql2.${clientType}.connect`,
5634
+ kind: __opentelemetry_api.SpanKind.CLIENT,
5635
+ submodule: "connect",
5636
+ packageName: "mysql2",
5637
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5638
+ instrumentationName: self.INSTRUMENTATION_NAME,
5639
+ inputValue,
5640
+ isPreAppStart: false
5641
+ }, (spanInfo) => {
5642
+ if (callback) {
5643
+ process.nextTick(() => callback(null));
5644
+ return;
5645
+ }
5646
+ return Promise.resolve();
5647
+ });
5648
+ }
5649
+ });
5346
5650
  else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
5347
5651
  originalFunctionCall: () => originalConnect.apply(this, [callback]),
5348
5652
  recordModeHandler: ({ isPreAppStart }) => {
@@ -5370,24 +5674,34 @@ var Mysql2Instrumentation = class extends TdInstrumentationBase {
5370
5674
  return (originalPing) => {
5371
5675
  return function ping(callback) {
5372
5676
  const inputValue = { clientType };
5373
- if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
5374
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalPing.apply(this, [callback]), {
5375
- name: `mysql2.${clientType}.ping`,
5376
- kind: __opentelemetry_api.SpanKind.CLIENT,
5377
- submodule: "ping",
5378
- packageName: "mysql2",
5379
- packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5380
- instrumentationName: self.INSTRUMENTATION_NAME,
5381
- inputValue,
5382
- isPreAppStart: false
5383
- }, (spanInfo) => {
5677
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
5678
+ noOpRequestHandler: () => {
5384
5679
  if (callback) {
5385
5680
  process.nextTick(() => callback(null));
5386
5681
  return;
5387
5682
  }
5388
5683
  return Promise.resolve();
5389
- });
5390
- } });
5684
+ },
5685
+ isServerRequest: false,
5686
+ replayModeHandler: () => {
5687
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalPing.apply(this, [callback]), {
5688
+ name: `mysql2.${clientType}.ping`,
5689
+ kind: __opentelemetry_api.SpanKind.CLIENT,
5690
+ submodule: "ping",
5691
+ packageName: "mysql2",
5692
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5693
+ instrumentationName: self.INSTRUMENTATION_NAME,
5694
+ inputValue,
5695
+ isPreAppStart: false
5696
+ }, (spanInfo) => {
5697
+ if (callback) {
5698
+ process.nextTick(() => callback(null));
5699
+ return;
5700
+ }
5701
+ return Promise.resolve();
5702
+ });
5703
+ }
5704
+ });
5391
5705
  else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
5392
5706
  originalFunctionCall: () => originalPing.apply(this, [callback]),
5393
5707
  recordModeHandler: ({ isPreAppStart }) => {
@@ -5415,24 +5729,34 @@ var Mysql2Instrumentation = class extends TdInstrumentationBase {
5415
5729
  return (originalEnd) => {
5416
5730
  return function end(callback) {
5417
5731
  const inputValue = { clientType };
5418
- if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
5419
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalEnd.apply(this, [callback]), {
5420
- name: `mysql2.${clientType}.end`,
5421
- kind: __opentelemetry_api.SpanKind.CLIENT,
5422
- submodule: "end",
5423
- packageName: "mysql2",
5424
- packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5425
- instrumentationName: self.INSTRUMENTATION_NAME,
5426
- inputValue,
5427
- isPreAppStart: false
5428
- }, (spanInfo) => {
5732
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
5733
+ noOpRequestHandler: () => {
5429
5734
  if (callback) {
5430
5735
  process.nextTick(() => callback(null));
5431
5736
  return;
5432
5737
  }
5433
5738
  return Promise.resolve();
5434
- });
5435
- } });
5739
+ },
5740
+ isServerRequest: false,
5741
+ replayModeHandler: () => {
5742
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalEnd.apply(this, [callback]), {
5743
+ name: `mysql2.${clientType}.end`,
5744
+ kind: __opentelemetry_api.SpanKind.CLIENT,
5745
+ submodule: "end",
5746
+ packageName: "mysql2",
5747
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5748
+ instrumentationName: self.INSTRUMENTATION_NAME,
5749
+ inputValue,
5750
+ isPreAppStart: false
5751
+ }, (spanInfo) => {
5752
+ if (callback) {
5753
+ process.nextTick(() => callback(null));
5754
+ return;
5755
+ }
5756
+ return Promise.resolve();
5757
+ });
5758
+ }
5759
+ });
5436
5760
  else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
5437
5761
  originalFunctionCall: () => originalEnd.apply(this, [callback]),
5438
5762
  recordModeHandler: ({ isPreAppStart }) => {
@@ -5607,6 +5931,9 @@ var Mysql2Instrumentation = class extends TdInstrumentationBase {
5607
5931
  handleReplayQuery(queryConfig, inputValue, spanInfo, submoduleName = "query", stackTrace) {
5608
5932
  return this.queryMock.handleReplayQuery(queryConfig, inputValue, spanInfo, submoduleName, stackTrace);
5609
5933
  }
5934
+ handleNoOpReplayQuery(queryConfig) {
5935
+ return this.queryMock.handleNoOpReplayQuery(queryConfig);
5936
+ }
5610
5937
  _handleRecordPoolGetConnectionInSpan(spanInfo, originalGetConnection, callback, context$4) {
5611
5938
  if (callback) {
5612
5939
  const wrappedCallback = (error, connection) => {
@@ -5660,9 +5987,18 @@ var Mysql2Instrumentation = class extends TdInstrumentationBase {
5660
5987
  throw error;
5661
5988
  });
5662
5989
  }
5990
+ handleNoOpReplayGetConnection(callback) {
5991
+ logger.debug(`[Mysql2Instrumentation] Background getConnection detected, returning mock connection`);
5992
+ const mockConnection = new TdMysql2ConnectionMock(this, "pool");
5993
+ if (callback) {
5994
+ process.nextTick(() => callback(null, mockConnection));
5995
+ return;
5996
+ }
5997
+ return Promise.resolve(mockConnection);
5998
+ }
5663
5999
  _handleReplayPoolGetConnection(spanInfo, callback) {
5664
6000
  logger.debug(`[Mysql2Instrumentation] Replaying MySQL2 Pool getConnection`);
5665
- const mockConnection = new TdMysql2ConnectionMock(this, spanInfo, "pool");
6001
+ const mockConnection = new TdMysql2ConnectionMock(this, "pool", spanInfo);
5666
6002
  if (callback) {
5667
6003
  process.nextTick(() => callback(null, mockConnection));
5668
6004
  return;
@@ -5721,58 +6057,59 @@ var Mysql2Instrumentation = class extends TdInstrumentationBase {
5721
6057
  },
5722
6058
  spanKind: __opentelemetry_api.SpanKind.CLIENT
5723
6059
  });
5724
- if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
5725
- return SpanUtils.createAndExecuteSpan(self.mode, () => new OriginalConnection(...args), {
5726
- name: `mysql2.connection.create`,
5727
- kind: __opentelemetry_api.SpanKind.CLIENT,
5728
- submodule: "connectEvent",
5729
- packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
5730
- packageName: "mysql2",
5731
- instrumentationName: self.INSTRUMENTATION_NAME,
5732
- inputValue,
5733
- isPreAppStart: false
5734
- }, (spanInfo) => {
5735
- class MockConnection extends OriginalConnection {
5736
- constructor(...mockConnectionArgs) {
5737
- const clonedArgs = JSON.parse(JSON.stringify(mockConnectionArgs));
5738
- if (clonedArgs[0] && clonedArgs[0].config) {
5739
- clonedArgs[0].config.host = "127.0.0.1";
5740
- clonedArgs[0].config.port = 127;
5741
- } else if (clonedArgs[0]) {
5742
- clonedArgs[0].host = "127.0.0.1";
5743
- clonedArgs[0].port = 127;
6060
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
6061
+ noOpRequestHandler: () => {
6062
+ return new TdMysql2ConnectionMock(self, "connection");
6063
+ },
6064
+ isServerRequest: false,
6065
+ replayModeHandler: () => {
6066
+ return SpanUtils.createAndExecuteSpan(self.mode, () => new OriginalConnection(...args), {
6067
+ name: `mysql2.connection.create`,
6068
+ kind: __opentelemetry_api.SpanKind.CLIENT,
6069
+ submodule: "connectEvent",
6070
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.MYSQL,
6071
+ packageName: "mysql2",
6072
+ instrumentationName: self.INSTRUMENTATION_NAME,
6073
+ inputValue,
6074
+ isPreAppStart: false
6075
+ }, (spanInfo) => {
6076
+ class MockConnection extends OriginalConnection {
6077
+ constructor(...mockConnectionArgs) {
6078
+ const clonedArgs = JSON.parse(JSON.stringify(mockConnectionArgs));
6079
+ if (clonedArgs[0] && clonedArgs[0].config) {
6080
+ clonedArgs[0].config.host = "127.0.0.1";
6081
+ clonedArgs[0].config.port = 127;
6082
+ } else if (clonedArgs[0]) {
6083
+ clonedArgs[0].host = "127.0.0.1";
6084
+ clonedArgs[0].port = 127;
6085
+ }
6086
+ super(...clonedArgs);
6087
+ this._isConnectOrErrorEmitted = false;
6088
+ this._connectEventMock = new TdMysql2ConnectionEventMock(spanInfo);
5744
6089
  }
5745
- super(...clonedArgs);
5746
- this._isConnectOrErrorEmitted = false;
5747
- this._connectEventMock = new TdMysql2ConnectionEventMock(spanInfo);
5748
- }
5749
- on(event, listener) {
5750
- if (!this._connectEventMock) return super.on(event, listener);
5751
- if (event === "connect" && !this._isConnectOrErrorEmitted) {
5752
- this._connectEventMock.getReplayedConnectionEvent(inputValue).then(({ output }) => {
5753
- if (output !== void 0) process.nextTick(() => {
5754
- listener.call(this, output);
5755
- this._isConnectOrErrorEmitted = true;
6090
+ on(event, listener) {
6091
+ if (!this._connectEventMock) return super.on(event, listener);
6092
+ if (event === "connect" && !this._isConnectOrErrorEmitted) {
6093
+ this._connectEventMock.getReplayedConnectionEvent(inputValue).then(({ output }) => {
6094
+ if (output !== void 0) process.nextTick(() => {
6095
+ listener.call(this, output);
6096
+ this._isConnectOrErrorEmitted = true;
6097
+ });
6098
+ }).catch((err) => {
6099
+ logger.error(`[Mysql2Instrumentation] Error replaying connection event:`, err);
5756
6100
  });
5757
- }).catch((err) => {
5758
- logger.error(`[Mysql2Instrumentation] Error replaying connection event:`, err);
5759
- });
5760
- return this;
6101
+ return this;
6102
+ }
6103
+ if (event === "error" && !this._isConnectOrErrorEmitted) return this;
6104
+ return super.on(event, listener);
5761
6105
  }
5762
- if (event === "error" && !this._isConnectOrErrorEmitted) return this;
5763
- return super.on(event, listener);
5764
6106
  }
5765
- }
5766
- const mockConnection = new MockConnection(...args);
5767
- mockConnection.addListener("error", (_err) => {});
5768
- SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: {
5769
- connected: true,
5770
- mock: true
5771
- } });
5772
- SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
5773
- return mockConnection;
5774
- });
5775
- } });
6107
+ const mockConnection = new MockConnection(...args);
6108
+ mockConnection.addListener("error", (_err) => {});
6109
+ return mockConnection;
6110
+ });
6111
+ }
6112
+ });
5776
6113
  return new OriginalConnection(...args);
5777
6114
  }
5778
6115
  const staticProps = Object.getOwnPropertyNames(OriginalConnection).filter((key) => ![
@@ -5821,6 +6158,7 @@ var TcpInstrumentation = class extends TdInstrumentationBase {
5821
6158
  super("tcp", config);
5822
6159
  this.loggedSpans = /* @__PURE__ */ new Set();
5823
6160
  this.mode = config.mode || TuskDriftMode.DISABLED;
6161
+ this._patchLoadedModules();
5824
6162
  }
5825
6163
  init() {
5826
6164
  return [new TdInstrumentationNodeModule({
@@ -5829,6 +6167,17 @@ var TcpInstrumentation = class extends TdInstrumentationBase {
5829
6167
  patch: (moduleExports) => this._patchNetModule(moduleExports)
5830
6168
  })];
5831
6169
  }
6170
+ _patchLoadedModules() {
6171
+ if (isNextJsRuntime()) {
6172
+ logger.debug(`[TcpInstrumentation] Next.js environment detected - force-loading net module to ensure patching`);
6173
+ try {
6174
+ require("net");
6175
+ logger.debug(`[TcpInstrumentation] net module force-loaded`);
6176
+ } catch (err) {
6177
+ logger.error(`[TcpInstrumentation] Error force-loading net module:`, err);
6178
+ }
6179
+ } else logger.debug(`[TcpInstrumentation] Regular Node.js environment - hooks will catch net module on first require`);
6180
+ }
5832
6181
  _patchNetModule(netModule) {
5833
6182
  logger.debug(`[TcpInstrumentation] Patching NET module in ${this.mode} mode`);
5834
6183
  if (this.isModulePatched(netModule)) {
@@ -5958,19 +6307,28 @@ var JsonwebtokenInstrumentation = class extends TdInstrumentationBase {
5958
6307
  }
5959
6308
  if (self.mode === TuskDriftMode.REPLAY) {
5960
6309
  const stackTrace = captureStackTrace(["JsonwebtokenInstrumentation"]);
5961
- return handleReplayMode({ replayModeHandler: () => {
5962
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalVerify.apply(this, args), {
5963
- name: "jsonwebtoken.verify",
5964
- kind: __opentelemetry_api.SpanKind.CLIENT,
5965
- submodule: "verify",
5966
- packageName: "jsonwebtoken",
5967
- instrumentationName: self.INSTRUMENTATION_NAME,
5968
- inputValue,
5969
- isPreAppStart: false
5970
- }, (spanInfo) => {
5971
- return self.handleReplayVerify(verifyConfig, inputValue, spanInfo, stackTrace);
5972
- });
5973
- } });
6310
+ return handleReplayMode({
6311
+ noOpRequestHandler: () => {
6312
+ if (!!verifyConfig.callback) {
6313
+ process.nextTick(() => verifyConfig.callback(null, void 0));
6314
+ return;
6315
+ } else return;
6316
+ },
6317
+ isServerRequest: false,
6318
+ replayModeHandler: () => {
6319
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalVerify.apply(this, args), {
6320
+ name: "jsonwebtoken.verify",
6321
+ kind: __opentelemetry_api.SpanKind.CLIENT,
6322
+ submodule: "verify",
6323
+ packageName: "jsonwebtoken",
6324
+ instrumentationName: self.INSTRUMENTATION_NAME,
6325
+ inputValue,
6326
+ isPreAppStart: false
6327
+ }, (spanInfo) => {
6328
+ return self.handleReplayVerify(verifyConfig, inputValue, spanInfo, stackTrace);
6329
+ });
6330
+ }
6331
+ });
5974
6332
  } else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
5975
6333
  originalFunctionCall: () => originalVerify.apply(this, args),
5976
6334
  recordModeHandler: ({ isPreAppStart }) => {
@@ -6013,19 +6371,28 @@ var JsonwebtokenInstrumentation = class extends TdInstrumentationBase {
6013
6371
  };
6014
6372
  if (self.mode === TuskDriftMode.REPLAY) {
6015
6373
  const stackTrace = captureStackTrace(["JsonwebtokenInstrumentation"]);
6016
- return handleReplayMode({ replayModeHandler: () => {
6017
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalSign.apply(this, args), {
6018
- name: "jsonwebtoken.sign",
6019
- kind: __opentelemetry_api.SpanKind.CLIENT,
6020
- submodule: "sign",
6021
- packageName: "jsonwebtoken",
6022
- instrumentationName: self.INSTRUMENTATION_NAME,
6023
- inputValue,
6024
- isPreAppStart: false
6025
- }, (spanInfo) => {
6026
- return self.handleReplaySign(signConfig, inputValue, spanInfo, stackTrace);
6027
- });
6028
- } });
6374
+ return handleReplayMode({
6375
+ noOpRequestHandler: () => {
6376
+ if (!!signConfig.callback) {
6377
+ process.nextTick(() => signConfig.callback(null, void 0));
6378
+ return;
6379
+ } else return;
6380
+ },
6381
+ isServerRequest: false,
6382
+ replayModeHandler: () => {
6383
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalSign.apply(this, args), {
6384
+ name: "jsonwebtoken.sign",
6385
+ kind: __opentelemetry_api.SpanKind.CLIENT,
6386
+ submodule: "sign",
6387
+ packageName: "jsonwebtoken",
6388
+ instrumentationName: self.INSTRUMENTATION_NAME,
6389
+ inputValue,
6390
+ isPreAppStart: false
6391
+ }, (spanInfo) => {
6392
+ return self.handleReplaySign(signConfig, inputValue, spanInfo, stackTrace);
6393
+ });
6394
+ }
6395
+ });
6029
6396
  } else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
6030
6397
  originalFunctionCall: () => originalSign.apply(this, args),
6031
6398
  recordModeHandler: ({ isPreAppStart }) => {
@@ -6213,11 +6580,7 @@ var JsonwebtokenInstrumentation = class extends TdInstrumentationBase {
6213
6580
  const hasCallback = !!verifyConfig.callback;
6214
6581
  if (!mockData) {
6215
6582
  logger.warn(`[JsonwebtokenInstrumentation] No mock data found for JWT verify: ${verifyConfig.token}`);
6216
- const error = /* @__PURE__ */ new Error("No mock data found");
6217
- if (hasCallback) {
6218
- process.nextTick(() => verifyConfig.callback(error));
6219
- return;
6220
- } else throw error;
6583
+ throw new Error(`[JsonwebtokenInstrumentation] No matching mock found for JWT verify: ${verifyConfig.token}`);
6221
6584
  }
6222
6585
  if (mockData.result && mockData.result.error) {
6223
6586
  let error = mockData.result.error;
@@ -6260,11 +6623,7 @@ var JsonwebtokenInstrumentation = class extends TdInstrumentationBase {
6260
6623
  const hasCallback = !!signConfig.callback;
6261
6624
  if (!mockData) {
6262
6625
  logger.warn(`[JsonwebtokenInstrumentation] No mock data found for JWT sign`);
6263
- const error = /* @__PURE__ */ new Error("No mock data found");
6264
- if (hasCallback) {
6265
- process.nextTick(() => signConfig.callback(error));
6266
- return;
6267
- } else throw error;
6626
+ throw new Error(`[JsonwebtokenInstrumentation] No matching mock found for JWT sign`);
6268
6627
  }
6269
6628
  if (mockData.result && mockData.result.error) {
6270
6629
  let error = mockData.result.error;
@@ -6681,20 +7040,30 @@ var FetchInstrumentation = class extends TdInstrumentationBase {
6681
7040
  headers: normalizedHeaders,
6682
7041
  body: encodedBody
6683
7042
  };
6684
- if (this.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
6685
- return SpanUtils.createAndExecuteSpan(this.mode, () => this.originalFetch(input, init), {
6686
- name: url,
6687
- kind: __opentelemetry_api.SpanKind.CLIENT,
6688
- packageName: "fetch",
6689
- packageType: __use_tusk_drift_schemas_core_span.PackageType.HTTP,
6690
- instrumentationName: this.INSTRUMENTATION_NAME,
6691
- submodule: inputValue.method,
6692
- inputValue,
6693
- isPreAppStart: false
6694
- }, (spanInfo) => {
6695
- return this._handleReplayFetch(inputValue, spanInfo, stackTrace);
6696
- });
6697
- } });
7043
+ if (this.mode === TuskDriftMode.REPLAY) return handleReplayMode({
7044
+ noOpRequestHandler: () => {
7045
+ const mockResponse = new Response(null, {
7046
+ status: 200,
7047
+ statusText: "OK"
7048
+ });
7049
+ return Promise.resolve(mockResponse);
7050
+ },
7051
+ isServerRequest: false,
7052
+ replayModeHandler: () => {
7053
+ return SpanUtils.createAndExecuteSpan(this.mode, () => this.originalFetch(input, init), {
7054
+ name: url,
7055
+ kind: __opentelemetry_api.SpanKind.CLIENT,
7056
+ packageName: "fetch",
7057
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.HTTP,
7058
+ instrumentationName: this.INSTRUMENTATION_NAME,
7059
+ submodule: inputValue.method,
7060
+ inputValue,
7061
+ isPreAppStart: false
7062
+ }, (spanInfo) => {
7063
+ return this._handleReplayFetch(inputValue, spanInfo, stackTrace);
7064
+ });
7065
+ }
7066
+ });
6698
7067
  else if (this.mode === TuskDriftMode.RECORD) return handleRecordMode({
6699
7068
  originalFunctionCall: () => this.originalFetch(input, init),
6700
7069
  recordModeHandler: ({ isPreAppStart }) => this._handleRecordFetch(input, inputValue, isPreAppStart, init),
@@ -6796,7 +7165,10 @@ var FetchInstrumentation = class extends TdInstrumentationBase {
6796
7165
  ...inputValue.headers && { headers: { matchImportance: 0 } }
6797
7166
  }
6798
7167
  });
6799
- if (!mockData) throw new Error(`No matching mock found for fetch request with input value: ${JSON.stringify(inputValue)}`);
7168
+ if (!mockData) {
7169
+ logger.warn(`[FetchInstrumentation] No mock data found for fetch request with input value: ${JSON.stringify(inputValue)}`);
7170
+ throw new Error(`[FetchInstrumentation] No matching mock found for fetch request`);
7171
+ }
6800
7172
  const { result } = mockData;
6801
7173
  const responseBody = this._constructFetchResponseBody(result);
6802
7174
  const mockResponse = new Response(responseBody, {
@@ -6981,7 +7353,7 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
6981
7353
  logger.debug(`[IORedisInstrumentation] IORedis module already patched, skipping`);
6982
7354
  return moduleExports;
6983
7355
  }
6984
- const actualExports = moduleExports[Symbol.toStringTag] === "Module" ? moduleExports.default : moduleExports;
7356
+ const actualExports = isEsm(moduleExports) ? moduleExports.default : moduleExports;
6985
7357
  if (!actualExports || !actualExports.prototype) {
6986
7358
  logger.error(`[IORedisInstrumentation] Invalid module exports, cannot patch`);
6987
7359
  return moduleExports;
@@ -7020,7 +7392,7 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
7020
7392
  logger.debug(`[IORedisInstrumentation] Pipeline module already patched, skipping`);
7021
7393
  return moduleExports;
7022
7394
  }
7023
- const actualExports = moduleExports[Symbol.toStringTag] === "Module" ? moduleExports.default : moduleExports;
7395
+ const actualExports = isEsm(moduleExports) ? moduleExports.default : moduleExports;
7024
7396
  if (!actualExports || !actualExports.prototype) {
7025
7397
  logger.debug(`[IORedisInstrumentation] Invalid Pipeline module exports, cannot patch`);
7026
7398
  return moduleExports;
@@ -7062,20 +7434,24 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
7062
7434
  };
7063
7435
  if (self.mode === TuskDriftMode.REPLAY) {
7064
7436
  const stackTrace = captureStackTrace(["IORedisInstrumentation"]);
7065
- return handleReplayMode({ replayModeHandler: () => {
7066
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalSendCommand.apply(this, arguments), {
7067
- name: `ioredis.${commandName}`,
7068
- kind: __opentelemetry_api.SpanKind.CLIENT,
7069
- submodule: commandName,
7070
- packageType: __use_tusk_drift_schemas_core_span.PackageType.REDIS,
7071
- packageName: "ioredis",
7072
- instrumentationName: self.INSTRUMENTATION_NAME,
7073
- inputValue,
7074
- isPreAppStart: false
7075
- }, (spanInfo) => {
7076
- return self._handleReplaySendCommand(spanInfo, cmd, inputValue, commandName, stackTrace);
7077
- });
7078
- } });
7437
+ return handleReplayMode({
7438
+ noOpRequestHandler: () => {},
7439
+ isServerRequest: false,
7440
+ replayModeHandler: () => {
7441
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalSendCommand.apply(this, arguments), {
7442
+ name: `ioredis.${commandName}`,
7443
+ kind: __opentelemetry_api.SpanKind.CLIENT,
7444
+ submodule: commandName,
7445
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.REDIS,
7446
+ packageName: "ioredis",
7447
+ instrumentationName: self.INSTRUMENTATION_NAME,
7448
+ inputValue,
7449
+ isPreAppStart: false
7450
+ }, (spanInfo) => {
7451
+ return self._handleReplaySendCommand(spanInfo, cmd, inputValue, stackTrace);
7452
+ });
7453
+ }
7454
+ });
7079
7455
  } else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
7080
7456
  originalFunctionCall: () => originalSendCommand.apply(this, arguments),
7081
7457
  recordModeHandler: ({ isPreAppStart }) => {
@@ -7106,20 +7482,29 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
7106
7482
  host: this.options?.host,
7107
7483
  port: this.options?.port
7108
7484
  };
7109
- if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
7110
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalConnect.apply(this, arguments), {
7111
- name: "ioredis.connect",
7112
- kind: __opentelemetry_api.SpanKind.CLIENT,
7113
- submodule: "connect",
7114
- packageType: __use_tusk_drift_schemas_core_span.PackageType.REDIS,
7115
- packageName: "ioredis",
7116
- instrumentationName: self.INSTRUMENTATION_NAME,
7117
- inputValue,
7118
- isPreAppStart: false
7119
- }, (spanInfo) => {
7120
- return self._handleReplayConnect(spanInfo, this);
7121
- });
7122
- } });
7485
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
7486
+ noOpRequestHandler: () => {
7487
+ process.nextTick(() => {
7488
+ this.emit("ready");
7489
+ });
7490
+ return Promise.resolve();
7491
+ },
7492
+ isServerRequest: false,
7493
+ replayModeHandler: () => {
7494
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalConnect.apply(this, arguments), {
7495
+ name: "ioredis.connect",
7496
+ kind: __opentelemetry_api.SpanKind.CLIENT,
7497
+ submodule: "connect",
7498
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.REDIS,
7499
+ packageName: "ioredis",
7500
+ instrumentationName: self.INSTRUMENTATION_NAME,
7501
+ inputValue,
7502
+ isPreAppStart: false
7503
+ }, (spanInfo) => {
7504
+ return self._handleReplayConnect(this);
7505
+ });
7506
+ }
7507
+ });
7123
7508
  else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
7124
7509
  originalFunctionCall: () => originalConnect.apply(this, arguments),
7125
7510
  recordModeHandler: ({ isPreAppStart }) => {
@@ -7176,20 +7561,26 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
7176
7561
  command: q.name,
7177
7562
  args: q.args || []
7178
7563
  })) };
7179
- if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
7180
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalExec.apply(this, args), {
7181
- name: "ioredis.pipeline.exec",
7182
- kind: __opentelemetry_api.SpanKind.CLIENT,
7183
- submodule: "pipeline-exec",
7184
- packageType: __use_tusk_drift_schemas_core_span.PackageType.REDIS,
7185
- packageName: "ioredis",
7186
- instrumentationName: self.INSTRUMENTATION_NAME,
7187
- inputValue,
7188
- isPreAppStart: false
7189
- }, (spanInfo) => {
7190
- return self._handleReplayPipelineExec(spanInfo, inputValue, args);
7191
- });
7192
- } });
7564
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
7565
+ noOpRequestHandler: () => {
7566
+ return [];
7567
+ },
7568
+ isServerRequest: false,
7569
+ replayModeHandler: () => {
7570
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalExec.apply(this, args), {
7571
+ name: "ioredis.pipeline.exec",
7572
+ kind: __opentelemetry_api.SpanKind.CLIENT,
7573
+ submodule: "pipeline-exec",
7574
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.REDIS,
7575
+ packageName: "ioredis",
7576
+ instrumentationName: self.INSTRUMENTATION_NAME,
7577
+ inputValue,
7578
+ isPreAppStart: false
7579
+ }, (spanInfo) => {
7580
+ return self._handleReplayPipelineExec(spanInfo, inputValue, args);
7581
+ });
7582
+ }
7583
+ });
7193
7584
  else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
7194
7585
  originalFunctionCall: () => originalExec.apply(this, args),
7195
7586
  recordModeHandler: ({ isPreAppStart }) => {
@@ -7238,7 +7629,7 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
7238
7629
  });
7239
7630
  return promise;
7240
7631
  }
7241
- async _handleReplaySendCommand(spanInfo, cmd, inputValue, commandName, stackTrace) {
7632
+ async _handleReplaySendCommand(spanInfo, cmd, inputValue, stackTrace) {
7242
7633
  logger.debug(`[IORedisInstrumentation] Replaying IORedis command ${cmd.name}`);
7243
7634
  const mockData = await findMockResponseAsync({
7244
7635
  mockRequestData: {
@@ -7256,13 +7647,10 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
7256
7647
  });
7257
7648
  if (!mockData) {
7258
7649
  logger.warn(`[IORedisInstrumentation] No mock data found for command: ${cmd.name}`);
7259
- SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
7260
- return;
7650
+ throw new Error(`[IORedisInstrumentation] No matching mock found for command: ${cmd.name}`);
7261
7651
  }
7262
7652
  logger.debug(`[IORedisInstrumentation] Found mock data for command ${cmd.name}: ${JSON.stringify(mockData)}`);
7263
7653
  const result = this._deserializeOutput(mockData.result);
7264
- SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: mockData.result });
7265
- SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
7266
7654
  if (cmd.callback && typeof cmd.callback === "function") process.nextTick(() => {
7267
7655
  cmd.callback(null, result);
7268
7656
  });
@@ -7300,10 +7688,8 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
7300
7688
  }
7301
7689
  return promise;
7302
7690
  }
7303
- async _handleReplayConnect(spanInfo, thisContext) {
7691
+ async _handleReplayConnect(thisContext) {
7304
7692
  logger.debug(`[IORedisInstrumentation] Replaying IORedis connect`);
7305
- SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: { connected: true } });
7306
- SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
7307
7693
  process.nextTick(() => {
7308
7694
  thisContext.emit("ready");
7309
7695
  });
@@ -7352,8 +7738,7 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
7352
7738
  });
7353
7739
  if (!mockData) {
7354
7740
  logger.warn(`[IORedisInstrumentation] No mock data found for pipeline exec`);
7355
- SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
7356
- return [];
7741
+ throw new Error(`[IORedisInstrumentation] No matching mock found for pipeline exec`);
7357
7742
  }
7358
7743
  logger.debug(`[IORedisInstrumentation] Found mock data for pipeline exec: ${JSON.stringify(mockData)}`);
7359
7744
  const result = this._deserializePipelineOutput(mockData.result);
@@ -7361,8 +7746,6 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
7361
7746
  if (typeof callback === "function") process.nextTick(() => {
7362
7747
  callback(null, result);
7363
7748
  });
7364
- SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: mockData.result });
7365
- SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
7366
7749
  return Promise.resolve(result);
7367
7750
  }
7368
7751
  _sanitizeArgs(args) {
@@ -7613,6 +7996,7 @@ var GrpcInstrumentation = class GrpcInstrumentation extends TdInstrumentationBas
7613
7996
  return;
7614
7997
  }
7615
7998
  this._wrap(clientPrototype, "makeUnaryRequest", this._getMakeUnaryRequestPatchFn(version$1));
7999
+ this._wrap(clientPrototype, "makeServerStreamRequest", this._getMakeServerStreamRequestPatchFn(version$1));
7616
8000
  this._wrap(clientPrototype, "waitForReady", this._getWaitForReadyPatchFn());
7617
8001
  this._wrap(clientPrototype, "close", this._getClosePatchFn());
7618
8002
  this._wrap(clientPrototype, "getChannel", this._getGetChannelPatchFn());
@@ -7662,6 +8046,7 @@ var GrpcInstrumentation = class GrpcInstrumentation extends TdInstrumentationBas
7662
8046
  logger.debug(`[GrpcInstrumentation] _getMakeUnaryRequestPatchFn called for version: ${version$1}`);
7663
8047
  return (original) => {
7664
8048
  return function makeUnaryRequest(...args) {
8049
+ logger.debug(`[GrpcInstrumentation] makeUnaryRequest called! args length: ${args.length}`);
7665
8050
  const MetadataConstructor = GrpcInstrumentation.metadataStore.get(version$1) || self.Metadata;
7666
8051
  if (!MetadataConstructor) {
7667
8052
  logger.warn(`[GrpcInstrumentation] Metadata constructor not found for version ${version$1}`);
@@ -7701,20 +8086,26 @@ var GrpcInstrumentation = class GrpcInstrumentation extends TdInstrumentationBas
7701
8086
  };
7702
8087
  if (self.mode === TuskDriftMode.REPLAY) {
7703
8088
  const stackTrace = captureStackTrace(["GrpcInstrumentation"]);
7704
- return handleReplayMode({ replayModeHandler: () => {
7705
- return SpanUtils.createAndExecuteSpan(self.mode, () => original.apply(this, args), {
7706
- name: "grpc.client.unary",
7707
- kind: __opentelemetry_api.SpanKind.CLIENT,
7708
- submodule: "client",
7709
- packageType: __use_tusk_drift_schemas_core_span.PackageType.GRPC,
7710
- packageName: GRPC_MODULE_NAME,
7711
- instrumentationName: self.INSTRUMENTATION_NAME,
7712
- inputValue,
7713
- isPreAppStart: false
7714
- }, (spanInfo) => {
7715
- return self._handleReplayUnaryRequest(spanInfo, inputValue, callback, MetadataConstructor, stackTrace);
7716
- });
7717
- } });
8089
+ return handleReplayMode({
8090
+ noOpRequestHandler: () => {
8091
+ callback(null, void 0);
8092
+ },
8093
+ isServerRequest: false,
8094
+ replayModeHandler: () => {
8095
+ return SpanUtils.createAndExecuteSpan(self.mode, () => original.apply(this, args), {
8096
+ name: "grpc.client.unary",
8097
+ kind: __opentelemetry_api.SpanKind.CLIENT,
8098
+ submodule: "client",
8099
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.GRPC,
8100
+ packageName: GRPC_MODULE_NAME,
8101
+ instrumentationName: self.INSTRUMENTATION_NAME,
8102
+ inputValue,
8103
+ isPreAppStart: false
8104
+ }, (spanInfo) => {
8105
+ return self._handleReplayUnaryRequest(spanInfo, inputValue, callback, MetadataConstructor, stackTrace);
8106
+ });
8107
+ }
8108
+ });
7718
8109
  } else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
7719
8110
  originalFunctionCall: () => original.apply(this, args),
7720
8111
  recordModeHandler: ({ isPreAppStart }) => {
@@ -7737,33 +8128,157 @@ var GrpcInstrumentation = class GrpcInstrumentation extends TdInstrumentationBas
7737
8128
  };
7738
8129
  };
7739
8130
  }
7740
- _handleRecordUnaryRequest(spanInfo, original, context$4, parsedParams, callback) {
7741
- let isResponseReceived = false;
7742
- let isStatusEmitted = false;
7743
- let hasErrorOccurred = false;
7744
- let isSpanCompleted = false;
7745
- let readableResponseBody;
7746
- let responseBufferMap = {};
7747
- let responseJsonableStringMap = {};
7748
- let status;
7749
- let responseMetadataInitial = {};
7750
- let serviceError;
7751
- /**
7752
- * Completes the span exactly once, regardless of which event fires first.
7753
- * gRPC's asynchronous nature means the callback and status event can fire in any order,
7754
- * so we need to guard against double span completion.
7755
- */
7756
- const completeSpan = (output, statusCode, errorMessage) => {
7757
- if (isSpanCompleted) return;
7758
- isSpanCompleted = true;
7759
- try {
7760
- SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: output });
7761
- SpanUtils.endSpan(spanInfo.span, {
7762
- code: statusCode,
7763
- message: errorMessage
7764
- });
7765
- } catch (e) {
7766
- logger.error(`[GrpcInstrumentation] Error completing span:`, e);
8131
+ _getMakeServerStreamRequestPatchFn(version$1) {
8132
+ const self = this;
8133
+ logger.debug(`[GrpcInstrumentation] _getMakeServerStreamRequestPatchFn called for version: ${version$1}`);
8134
+ return (original) => {
8135
+ return function makeServerStreamRequest(...args) {
8136
+ logger.debug(`[GrpcInstrumentation] makeServerStreamRequest called! args length: ${args.length}`);
8137
+ const MetadataConstructor = GrpcInstrumentation.metadataStore.get(version$1) || self.Metadata;
8138
+ if (!MetadataConstructor) {
8139
+ logger.warn(`[GrpcInstrumentation] Metadata constructor not found for version ${version$1}`);
8140
+ return original.apply(this, args);
8141
+ }
8142
+ let parsedParams;
8143
+ try {
8144
+ parsedParams = self.extractServerStreamRequestParameters(args, MetadataConstructor);
8145
+ } catch (error) {
8146
+ logger.error(`[GrpcInstrumentation] Error parsing makeServerStreamRequest arguments:`, error);
8147
+ return original.apply(this, args);
8148
+ }
8149
+ const { method: path$5, argument, metadata, options } = parsedParams;
8150
+ let method;
8151
+ let service;
8152
+ let readableBody;
8153
+ let bufferMap;
8154
+ let jsonableStringMap;
8155
+ let readableMetadata;
8156
+ try {
8157
+ ({method, service} = parseGrpcPath(path$5));
8158
+ ({readableBody, bufferMap, jsonableStringMap} = serializeGrpcPayload(argument));
8159
+ readableMetadata = serializeGrpcMetadata(metadata);
8160
+ } catch (error) {
8161
+ logger.error(`[GrpcInstrumentation] Error parsing makeServerStreamRequest arguments:`, error);
8162
+ return original.apply(this, args);
8163
+ }
8164
+ const inputValue = {
8165
+ method,
8166
+ service,
8167
+ body: readableBody,
8168
+ metadata: readableMetadata,
8169
+ inputMeta: {
8170
+ bufferMap,
8171
+ jsonableStringMap
8172
+ }
8173
+ };
8174
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
8175
+ noOpRequestHandler: () => {
8176
+ const stream$1 = new stream.Readable({
8177
+ objectMode: true,
8178
+ read() {}
8179
+ });
8180
+ Object.assign(stream$1, {
8181
+ cancel() {},
8182
+ getPeer: () => "0.0.0.0:0000",
8183
+ call: void 0
8184
+ });
8185
+ return stream$1;
8186
+ },
8187
+ isServerRequest: false,
8188
+ replayModeHandler: () => {
8189
+ return SpanUtils.createAndExecuteSpan(self.mode, () => original.apply(this, args), {
8190
+ name: "grpc.client.server_stream",
8191
+ kind: __opentelemetry_api.SpanKind.CLIENT,
8192
+ submodule: "client",
8193
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.GRPC,
8194
+ packageName: GRPC_MODULE_NAME,
8195
+ instrumentationName: self.INSTRUMENTATION_NAME,
8196
+ inputValue,
8197
+ isPreAppStart: false
8198
+ }, (spanInfo) => {
8199
+ return self._handleReplayServerStreamRequest(spanInfo, inputValue, MetadataConstructor);
8200
+ });
8201
+ }
8202
+ });
8203
+ else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
8204
+ originalFunctionCall: () => original.apply(this, args),
8205
+ recordModeHandler: ({ isPreAppStart }) => {
8206
+ return SpanUtils.createAndExecuteSpan(self.mode, () => original.apply(this, args), {
8207
+ name: "grpc.client.server_stream",
8208
+ kind: __opentelemetry_api.SpanKind.CLIENT,
8209
+ submodule: "client",
8210
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.GRPC,
8211
+ packageName: GRPC_MODULE_NAME,
8212
+ instrumentationName: self.INSTRUMENTATION_NAME,
8213
+ inputValue,
8214
+ isPreAppStart
8215
+ }, (spanInfo) => {
8216
+ return self._handleRecordServerStreamRequest(spanInfo, original, this, parsedParams);
8217
+ });
8218
+ },
8219
+ spanKind: __opentelemetry_api.SpanKind.CLIENT
8220
+ });
8221
+ else return original.apply(this, args);
8222
+ };
8223
+ };
8224
+ }
8225
+ extractServerStreamRequestParameters(args, MetadataConstructor) {
8226
+ const method = args[0];
8227
+ const serialize = args[1];
8228
+ const deserialize = args[2];
8229
+ const argument = args[3];
8230
+ let metadata;
8231
+ let options;
8232
+ if (args.length === 6) {
8233
+ metadata = args[4];
8234
+ options = args[5];
8235
+ } else if (args.length === 5) if (args[4] instanceof MetadataConstructor) {
8236
+ metadata = args[4];
8237
+ options = {};
8238
+ } else {
8239
+ metadata = new MetadataConstructor();
8240
+ options = args[4] || {};
8241
+ }
8242
+ else {
8243
+ metadata = new MetadataConstructor();
8244
+ options = {};
8245
+ }
8246
+ return {
8247
+ method,
8248
+ serialize,
8249
+ deserialize,
8250
+ argument,
8251
+ metadata,
8252
+ options
8253
+ };
8254
+ }
8255
+ _handleRecordUnaryRequest(spanInfo, original, context$4, parsedParams, callback) {
8256
+ let isResponseReceived = false;
8257
+ let isStatusEmitted = false;
8258
+ let hasErrorOccurred = false;
8259
+ let isSpanCompleted = false;
8260
+ let readableResponseBody;
8261
+ let responseBufferMap = {};
8262
+ let responseJsonableStringMap = {};
8263
+ let status;
8264
+ let responseMetadataInitial = {};
8265
+ let serviceError;
8266
+ /**
8267
+ * Completes the span exactly once, regardless of which event fires first.
8268
+ * gRPC's asynchronous nature means the callback and status event can fire in any order,
8269
+ * so we need to guard against double span completion.
8270
+ */
8271
+ const completeSpan = (output, statusCode, errorMessage) => {
8272
+ if (isSpanCompleted) return;
8273
+ isSpanCompleted = true;
8274
+ try {
8275
+ SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: output });
8276
+ SpanUtils.endSpan(spanInfo.span, {
8277
+ code: statusCode,
8278
+ message: errorMessage
8279
+ });
8280
+ } catch (e) {
8281
+ logger.error(`[GrpcInstrumentation] Error completing span:`, e);
7767
8282
  }
7768
8283
  };
7769
8284
  const patchedCallback = (err, value) => {
@@ -7839,113 +8354,1221 @@ var GrpcInstrumentation = class GrpcInstrumentation extends TdInstrumentationBas
7839
8354
  status,
7840
8355
  metadata: responseMetadataInitial
7841
8356
  };
7842
- completeSpan(errorOutput, __opentelemetry_api.SpanStatusCode.ERROR, serviceError.message);
7843
- }
7844
- });
7845
- return result;
8357
+ completeSpan(errorOutput, __opentelemetry_api.SpanStatusCode.ERROR, serviceError.message);
8358
+ }
8359
+ });
8360
+ return result;
8361
+ }
8362
+ isGrpcErrorOutput(result) {
8363
+ return "error" in result;
8364
+ }
8365
+ _handleReplayUnaryRequest(spanInfo, inputValue, callback, MetadataConstructor, stackTrace) {
8366
+ logger.debug(`[GrpcInstrumentation] Replaying gRPC unary request`);
8367
+ const emitter = Object.assign(new events.EventEmitter(), {
8368
+ cancel() {},
8369
+ getPeer: () => "0.0.0.0:0000",
8370
+ call: void 0
8371
+ });
8372
+ findMockResponseAsync({
8373
+ mockRequestData: {
8374
+ traceId: spanInfo.traceId,
8375
+ spanId: spanInfo.spanId,
8376
+ name: "grpc.client.unary",
8377
+ inputValue,
8378
+ packageName: GRPC_MODULE_NAME,
8379
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.GRPC,
8380
+ instrumentationName: this.INSTRUMENTATION_NAME,
8381
+ submoduleName: "client",
8382
+ kind: __opentelemetry_api.SpanKind.CLIENT,
8383
+ stackTrace
8384
+ },
8385
+ tuskDrift: this.tuskDrift
8386
+ }).then((mockData) => {
8387
+ if (!mockData) {
8388
+ logger.warn(`[GrpcInstrumentation] No mock data found for gRPC request: ${inputValue.service}/${inputValue.method}`, inputValue);
8389
+ throw new Error(`[GrpcInstrumentation] No matching mock found for gRPC unary request`);
8390
+ }
8391
+ const mockResult = mockData.result;
8392
+ let status;
8393
+ if (this.isGrpcErrorOutput(mockResult)) {
8394
+ const { error, status: errorStatus } = mockResult;
8395
+ status = {
8396
+ code: errorStatus.code,
8397
+ details: errorStatus.details,
8398
+ metadata: deserializeGrpcMetadata(MetadataConstructor, errorStatus.metadata)
8399
+ };
8400
+ const errorObj = Object.assign(new Error(error.message), {
8401
+ name: error.name,
8402
+ stack: error.stack,
8403
+ ...status
8404
+ });
8405
+ callback(errorObj);
8406
+ } else {
8407
+ const { body, status: successStatus, bufferMap, jsonableStringMap } = mockResult;
8408
+ const bufferMapToUse = bufferMap || {};
8409
+ const jsonableStringMapToUse = jsonableStringMap || {};
8410
+ status = {
8411
+ code: successStatus.code,
8412
+ details: successStatus.details,
8413
+ metadata: deserializeGrpcMetadata(MetadataConstructor, successStatus.metadata)
8414
+ };
8415
+ const realResponse = deserializeGrpcPayload(body, bufferMapToUse, jsonableStringMapToUse);
8416
+ callback(null, realResponse);
8417
+ }
8418
+ process.nextTick(() => {
8419
+ if (mockResult.metadata) emitter.emit("metadata", deserializeGrpcMetadata(MetadataConstructor, mockResult.metadata));
8420
+ emitter.emit("status", status);
8421
+ });
8422
+ }).catch((error) => {
8423
+ logger.error(`[GrpcInstrumentation] Error fetching mock data:`, error);
8424
+ callback(error);
8425
+ });
8426
+ return emitter;
8427
+ }
8428
+ _handleRecordServerStreamRequest(spanInfo, original, context$4, parsedParams) {
8429
+ let hasErrorOccurred = false;
8430
+ let isSpanCompleted = false;
8431
+ let streamResponses = [];
8432
+ let status;
8433
+ let responseMetadataInitial = {};
8434
+ let serviceError;
8435
+ /**
8436
+ * Completes the span exactly once
8437
+ */
8438
+ const completeSpan = (output, statusCode, errorMessage) => {
8439
+ if (isSpanCompleted) return;
8440
+ isSpanCompleted = true;
8441
+ try {
8442
+ SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: output });
8443
+ SpanUtils.endSpan(spanInfo.span, { code: statusCode });
8444
+ } catch (e) {
8445
+ logger.error(`[GrpcInstrumentation] Error completing span:`, e);
8446
+ }
8447
+ };
8448
+ const inputArgs = [
8449
+ parsedParams.method,
8450
+ parsedParams.serialize,
8451
+ parsedParams.deserialize,
8452
+ parsedParams.argument,
8453
+ parsedParams.metadata,
8454
+ parsedParams.options
8455
+ ];
8456
+ const stream$1 = original.apply(context$4, inputArgs);
8457
+ stream$1.on("data", (data) => {
8458
+ try {
8459
+ const { readableBody, bufferMap, jsonableStringMap } = serializeGrpcPayload(data);
8460
+ streamResponses.push({
8461
+ body: readableBody,
8462
+ bufferMap,
8463
+ jsonableStringMap
8464
+ });
8465
+ } catch (e) {
8466
+ logger.error(`[GrpcInstrumentation] Error serializing stream data:`, e);
8467
+ }
8468
+ });
8469
+ stream$1.on("metadata", (initialMetadata) => {
8470
+ responseMetadataInitial = serializeGrpcMetadata(initialMetadata);
8471
+ });
8472
+ stream$1.on("error", (err) => {
8473
+ serviceError = err;
8474
+ hasErrorOccurred = true;
8475
+ });
8476
+ stream$1.on("status", (responseStatus) => {
8477
+ status = {
8478
+ code: responseStatus.code,
8479
+ details: responseStatus.details,
8480
+ metadata: serializeGrpcMetadata(responseStatus.metadata)
8481
+ };
8482
+ if (!hasErrorOccurred && streamResponses.length > 0) completeSpan({
8483
+ body: streamResponses,
8484
+ metadata: responseMetadataInitial,
8485
+ status,
8486
+ bufferMap: {},
8487
+ jsonableStringMap: {}
8488
+ }, __opentelemetry_api.SpanStatusCode.OK);
8489
+ else if (!hasErrorOccurred && streamResponses.length === 0) completeSpan({
8490
+ body: [],
8491
+ metadata: responseMetadataInitial,
8492
+ status,
8493
+ bufferMap: {},
8494
+ jsonableStringMap: {}
8495
+ }, __opentelemetry_api.SpanStatusCode.OK);
8496
+ else if (hasErrorOccurred) {
8497
+ const errorOutput = {
8498
+ error: {
8499
+ message: serviceError.message,
8500
+ name: serviceError.name,
8501
+ stack: serviceError.stack
8502
+ },
8503
+ status,
8504
+ metadata: responseMetadataInitial
8505
+ };
8506
+ completeSpan(errorOutput, __opentelemetry_api.SpanStatusCode.ERROR, serviceError.message);
8507
+ }
8508
+ });
8509
+ return stream$1;
8510
+ }
8511
+ _handleReplayServerStreamRequest(spanInfo, inputValue, MetadataConstructor) {
8512
+ logger.debug(`[GrpcInstrumentation] Replaying gRPC server stream request`);
8513
+ const stream$1 = new stream.Readable({
8514
+ objectMode: true,
8515
+ read() {}
8516
+ });
8517
+ Object.assign(stream$1, {
8518
+ cancel() {},
8519
+ getPeer: () => "0.0.0.0:0000",
8520
+ call: void 0
8521
+ });
8522
+ findMockResponseAsync({
8523
+ mockRequestData: {
8524
+ traceId: spanInfo.traceId,
8525
+ spanId: spanInfo.spanId,
8526
+ name: "grpc.client.server_stream",
8527
+ inputValue,
8528
+ packageName: GRPC_MODULE_NAME,
8529
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.GRPC,
8530
+ instrumentationName: this.INSTRUMENTATION_NAME,
8531
+ submoduleName: "client",
8532
+ kind: __opentelemetry_api.SpanKind.CLIENT
8533
+ },
8534
+ tuskDrift: this.tuskDrift
8535
+ }).then((mockData) => {
8536
+ if (!mockData) {
8537
+ logger.warn(`[GrpcInstrumentation] No mock data found for gRPC server stream request: ${inputValue.service}/${inputValue.method}`, inputValue);
8538
+ throw new Error(`[GrpcInstrumentation] No matching mock found for gRPC server stream request`);
8539
+ }
8540
+ const mockResult = mockData.result;
8541
+ process.nextTick(() => {
8542
+ if (this.isGrpcErrorOutput(mockResult)) {
8543
+ const { error, status: errorStatus } = mockResult;
8544
+ const status = {
8545
+ code: errorStatus.code,
8546
+ details: errorStatus.details,
8547
+ metadata: deserializeGrpcMetadata(MetadataConstructor, errorStatus.metadata)
8548
+ };
8549
+ if (mockResult.metadata) stream$1.emit("metadata", deserializeGrpcMetadata(MetadataConstructor, mockResult.metadata));
8550
+ const errorObj = Object.assign(new Error(error.message), {
8551
+ name: error.name,
8552
+ stack: error.stack,
8553
+ ...status
8554
+ });
8555
+ stream$1.emit("error", errorObj);
8556
+ stream$1.emit("status", status);
8557
+ stream$1.push(null);
8558
+ } else {
8559
+ const { body, status: successStatus } = mockResult;
8560
+ const status = {
8561
+ code: successStatus.code,
8562
+ details: successStatus.details,
8563
+ metadata: deserializeGrpcMetadata(MetadataConstructor, successStatus.metadata)
8564
+ };
8565
+ if (mockResult.metadata) stream$1.emit("metadata", deserializeGrpcMetadata(MetadataConstructor, mockResult.metadata));
8566
+ if (Array.isArray(body)) body.forEach((item) => {
8567
+ const bufferMapToUse = item.bufferMap || {};
8568
+ const jsonableStringMapToUse = item.jsonableStringMap || {};
8569
+ const realResponse = deserializeGrpcPayload(item.body, bufferMapToUse, jsonableStringMapToUse);
8570
+ stream$1.push(realResponse);
8571
+ });
8572
+ stream$1.push(null);
8573
+ stream$1.emit("status", status);
8574
+ }
8575
+ });
8576
+ }).catch((error) => {
8577
+ logger.error(`[GrpcInstrumentation] Error fetching mock data for server stream:`, error);
8578
+ process.nextTick(() => {
8579
+ stream$1.emit("error", error);
8580
+ stream$1.emit("status", {
8581
+ code: 2,
8582
+ details: error.message,
8583
+ metadata: new MetadataConstructor()
8584
+ });
8585
+ stream$1.push(null);
8586
+ });
8587
+ });
8588
+ return stream$1;
8589
+ }
8590
+ _getWaitForReadyPatchFn() {
8591
+ const self = this;
8592
+ return (original) => {
8593
+ return function waitForReady(deadline, callback) {
8594
+ if (self.mode === TuskDriftMode.REPLAY) {
8595
+ process.nextTick(() => callback());
8596
+ return;
8597
+ } else return original.apply(this, [deadline, callback]);
8598
+ };
8599
+ };
8600
+ }
8601
+ _getClosePatchFn() {
8602
+ const self = this;
8603
+ return (original) => {
8604
+ return function close() {
8605
+ if (self.mode === TuskDriftMode.REPLAY) return;
8606
+ else return original.apply(this, arguments);
8607
+ };
8608
+ };
8609
+ }
8610
+ _getGetChannelPatchFn() {
8611
+ const self = this;
8612
+ return (original) => {
8613
+ return function getChannel() {
8614
+ if (self.mode === TuskDriftMode.REPLAY) return {};
8615
+ else return original.apply(this, arguments);
8616
+ };
8617
+ };
8618
+ }
8619
+ _wrap(target, propertyName, wrapper) {
8620
+ wrap(target, propertyName, wrapper);
8621
+ }
8622
+ };
8623
+ GrpcInstrumentation.metadataStore = /* @__PURE__ */ new Map();
8624
+
8625
+ //#endregion
8626
+ //#region src/instrumentation/libraries/firestore/mocks/TdFirestoreDocumentMock.ts
8627
+ /**
8628
+ * Mock Firestore DocumentSnapshot for replay mode
8629
+ * Mimics the Firestore DocumentSnapshot API
8630
+ */
8631
+ var TdFirestoreDocumentMock = class {
8632
+ constructor(documentData) {
8633
+ this.documentData = documentData;
8634
+ }
8635
+ /**
8636
+ * The document's identifier within its collection
8637
+ */
8638
+ get id() {
8639
+ return this.documentData.id;
8640
+ }
8641
+ /**
8642
+ * Whether the document exists
8643
+ */
8644
+ get exists() {
8645
+ return this.documentData.exists;
8646
+ }
8647
+ /**
8648
+ * A DocumentReference to the document location
8649
+ */
8650
+ get ref() {
8651
+ return {
8652
+ id: this.documentData.id,
8653
+ path: this.documentData.path
8654
+ };
8655
+ }
8656
+ /**
8657
+ * The time the document was created (if available)
8658
+ */
8659
+ get createTime() {
8660
+ return this.documentData.createTime ? {
8661
+ seconds: this.documentData.createTime.seconds,
8662
+ nanoseconds: this.documentData.createTime.nanoseconds,
8663
+ toDate: () => /* @__PURE__ */ new Date(this.documentData.createTime.seconds * 1e3 + this.documentData.createTime.nanoseconds / 1e6)
8664
+ } : null;
8665
+ }
8666
+ /**
8667
+ * The time the document was last updated (if available)
8668
+ */
8669
+ get updateTime() {
8670
+ return this.documentData.updateTime ? {
8671
+ seconds: this.documentData.updateTime.seconds,
8672
+ nanoseconds: this.documentData.updateTime.nanoseconds,
8673
+ toDate: () => /* @__PURE__ */ new Date(this.documentData.updateTime.seconds * 1e3 + this.documentData.updateTime.nanoseconds / 1e6)
8674
+ } : null;
8675
+ }
8676
+ /**
8677
+ * The time the document was read (if available)
8678
+ */
8679
+ get readTime() {
8680
+ return this.documentData.readTime ? {
8681
+ seconds: this.documentData.readTime.seconds,
8682
+ nanoseconds: this.documentData.readTime.nanoseconds,
8683
+ toDate: () => /* @__PURE__ */ new Date(this.documentData.readTime.seconds * 1e3 + this.documentData.readTime.nanoseconds / 1e6)
8684
+ } : null;
8685
+ }
8686
+ /**
8687
+ * Retrieves all fields in the document as an object
8688
+ */
8689
+ data() {
8690
+ return this.documentData.data;
8691
+ }
8692
+ /**
8693
+ * Retrieves the field specified by fieldPath
8694
+ */
8695
+ get(fieldPath) {
8696
+ if (!this.documentData.data) return;
8697
+ return this.documentData.data[fieldPath];
8698
+ }
8699
+ /**
8700
+ * Returns true if the document's data and path are equal to the provided value
8701
+ */
8702
+ isEqual(other) {
8703
+ return this.documentData.path === other.documentData.path;
8704
+ }
8705
+ };
8706
+
8707
+ //#endregion
8708
+ //#region src/instrumentation/libraries/firestore/mocks/TdFirestoreQueryMock.ts
8709
+ /**
8710
+ * Mock Firestore QuerySnapshot for replay mode
8711
+ * Mimics the Firestore QuerySnapshot API
8712
+ */
8713
+ var TdFirestoreQueryMock = class {
8714
+ constructor(queryResult) {
8715
+ this.queryResult = queryResult;
8716
+ this._docs = queryResult.docs.map((doc) => new TdFirestoreDocumentMock(doc));
8717
+ }
8718
+ /**
8719
+ * An array of all the documents in the QuerySnapshot
8720
+ */
8721
+ get docs() {
8722
+ return this._docs;
8723
+ }
8724
+ /**
8725
+ * The number of documents in the QuerySnapshot
8726
+ */
8727
+ get size() {
8728
+ return this.queryResult.size;
8729
+ }
8730
+ /**
8731
+ * True if there are no documents in the QuerySnapshot
8732
+ */
8733
+ get empty() {
8734
+ return this.queryResult.empty;
8735
+ }
8736
+ /**
8737
+ * The time the query snapshot was read
8738
+ */
8739
+ get readTime() {
8740
+ return this.queryResult.readTime ? {
8741
+ seconds: this.queryResult.readTime.seconds,
8742
+ nanoseconds: this.queryResult.readTime.nanoseconds,
8743
+ toDate: () => /* @__PURE__ */ new Date(this.queryResult.readTime.seconds * 1e3 + this.queryResult.readTime.nanoseconds / 1e6)
8744
+ } : null;
8745
+ }
8746
+ /**
8747
+ * The query on which you called get or onSnapshot
8748
+ */
8749
+ get query() {
8750
+ return {};
8751
+ }
8752
+ /**
8753
+ * Enumerates all of the documents in the QuerySnapshot
8754
+ */
8755
+ forEach(callback, thisArg) {
8756
+ this._docs.forEach(callback, thisArg);
8757
+ }
8758
+ /**
8759
+ * Returns an array of the documents changes since the last snapshot
8760
+ */
8761
+ docChanges() {
8762
+ return [];
8763
+ }
8764
+ /**
8765
+ * Returns true if the document data and path are equal to this QuerySnapshot
8766
+ */
8767
+ isEqual(other) {
8768
+ if (this.size !== other.size) return false;
8769
+ return this.size === other.size && this.empty === other.empty;
8770
+ }
8771
+ };
8772
+
8773
+ //#endregion
8774
+ //#region src/instrumentation/libraries/firestore/mocks/TdFirestoreWriteResultMock.ts
8775
+ /**
8776
+ * Mock Firestore WriteResult for replay mode
8777
+ * Mimics the Firestore WriteResult API
8778
+ */
8779
+ var TdFirestoreWriteResultMock = class {
8780
+ constructor(result) {
8781
+ this.result = result;
8782
+ }
8783
+ /**
8784
+ * The write time as reported by the server
8785
+ */
8786
+ get writeTime() {
8787
+ return this.result.writeTime ? {
8788
+ seconds: this.result.writeTime.seconds,
8789
+ nanoseconds: this.result.writeTime.nanoseconds,
8790
+ toDate: () => /* @__PURE__ */ new Date(this.result.writeTime.seconds * 1e3 + this.result.writeTime.nanoseconds / 1e6)
8791
+ } : null;
8792
+ }
8793
+ /**
8794
+ * Returns true if this WriteResult is equal to the provided one
8795
+ */
8796
+ isEqual(other) {
8797
+ if (!this.writeTime || !other.writeTime) return this.writeTime === other.writeTime;
8798
+ return this.writeTime.seconds === other.writeTime.seconds && this.writeTime.nanoseconds === other.writeTime.nanoseconds;
8799
+ }
8800
+ };
8801
+
8802
+ //#endregion
8803
+ //#region src/instrumentation/libraries/firestore/Instrumentation.ts
8804
+ const FIRESTORE_VERSION = "7.*";
8805
+ const PACKAGE_NAME = "@google-cloud/firestore";
8806
+ var FirestoreInstrumentation = class extends TdInstrumentationBase {
8807
+ constructor(config = {}) {
8808
+ super(PACKAGE_NAME, config);
8809
+ this.INSTRUMENTATION_NAME = "FirestoreInstrumentation";
8810
+ this.originalCollectionDocFn = null;
8811
+ this.mode = config.mode || TuskDriftMode.DISABLED;
8812
+ this.tuskDrift = TuskDriftCore.getInstance();
8813
+ }
8814
+ init() {
8815
+ return [new TdInstrumentationNodeModule({
8816
+ name: PACKAGE_NAME,
8817
+ supportedVersions: [FIRESTORE_VERSION],
8818
+ files: [
8819
+ new TdInstrumentationNodeModuleFile({
8820
+ name: "@google-cloud/firestore/build/src/reference/document-reference.js",
8821
+ supportedVersions: [FIRESTORE_VERSION],
8822
+ patch: (moduleExports) => this._patchDocumentReference(moduleExports)
8823
+ }),
8824
+ new TdInstrumentationNodeModuleFile({
8825
+ name: "@google-cloud/firestore/build/src/reference/collection-reference.js",
8826
+ supportedVersions: [FIRESTORE_VERSION],
8827
+ patch: (moduleExports) => this._patchCollectionReference(moduleExports)
8828
+ }),
8829
+ new TdInstrumentationNodeModuleFile({
8830
+ name: "@google-cloud/firestore/build/src/reference/query.js",
8831
+ supportedVersions: [FIRESTORE_VERSION],
8832
+ patch: (moduleExports) => this._patchQuery(moduleExports)
8833
+ })
8834
+ ]
8835
+ })];
8836
+ }
8837
+ _patchDocumentReference(moduleExports) {
8838
+ logger.debug(`[FirestoreInstrumentation] Patching DocumentReference in ${this.mode} mode`);
8839
+ if (this.isModulePatched(moduleExports)) {
8840
+ logger.debug(`[FirestoreInstrumentation] DocumentReference already patched, skipping`);
8841
+ return moduleExports;
8842
+ }
8843
+ const DocumentReference = moduleExports.DocumentReference;
8844
+ if (!DocumentReference || !DocumentReference.prototype) {
8845
+ logger.warn(`[FirestoreInstrumentation] DocumentReference.prototype not found`);
8846
+ return moduleExports;
8847
+ }
8848
+ this._wrap(DocumentReference.prototype, "get", this._getDocumentGetPatchFn());
8849
+ this._wrap(DocumentReference.prototype, "create", this._getDocumentCreatePatchFn());
8850
+ this._wrap(DocumentReference.prototype, "set", this._getDocumentSetPatchFn());
8851
+ this._wrap(DocumentReference.prototype, "update", this._getDocumentUpdatePatchFn());
8852
+ this._wrap(DocumentReference.prototype, "delete", this._getDocumentDeletePatchFn());
8853
+ this.markModuleAsPatched(moduleExports);
8854
+ logger.debug(`[FirestoreInstrumentation] DocumentReference patching complete`);
8855
+ return moduleExports;
8856
+ }
8857
+ _patchCollectionReference(moduleExports) {
8858
+ logger.debug(`[FirestoreInstrumentation] Patching CollectionReference in ${this.mode} mode`);
8859
+ if (this.isModulePatched(moduleExports)) {
8860
+ logger.debug(`[FirestoreInstrumentation] CollectionReference already patched, skipping`);
8861
+ return moduleExports;
8862
+ }
8863
+ const CollectionReference = moduleExports.CollectionReference;
8864
+ if (!CollectionReference || !CollectionReference.prototype) {
8865
+ logger.warn(`[FirestoreInstrumentation] CollectionReference.prototype not found`);
8866
+ return moduleExports;
8867
+ }
8868
+ this.originalCollectionDocFn = CollectionReference.prototype.doc;
8869
+ this._wrap(CollectionReference.prototype, "add", this._getCollectionAddPatchFn());
8870
+ this._wrap(CollectionReference.prototype, "doc", this._getCollectionDocPatchFn());
8871
+ this.markModuleAsPatched(moduleExports);
8872
+ logger.debug(`[FirestoreInstrumentation] CollectionReference patching complete`);
8873
+ return moduleExports;
8874
+ }
8875
+ _patchQuery(moduleExports) {
8876
+ logger.debug(`[FirestoreInstrumentation] Patching Query in ${this.mode} mode`);
8877
+ if (this.isModulePatched(moduleExports)) {
8878
+ logger.debug(`[FirestoreInstrumentation] Query already patched, skipping`);
8879
+ return moduleExports;
8880
+ }
8881
+ const Query = moduleExports.Query;
8882
+ if (!Query || !Query.prototype) {
8883
+ logger.warn(`[FirestoreInstrumentation] Query.prototype not found`);
8884
+ return moduleExports;
8885
+ }
8886
+ this._wrap(Query.prototype, "get", this._getQueryGetPatchFn());
8887
+ this.markModuleAsPatched(moduleExports);
8888
+ logger.debug(`[FirestoreInstrumentation] Query patching complete`);
8889
+ return moduleExports;
8890
+ }
8891
+ _getDocumentGetPatchFn() {
8892
+ const self = this;
8893
+ return (originalGet) => {
8894
+ return function() {
8895
+ const inputValue = {
8896
+ operation: "document.get",
8897
+ path: this.path
8898
+ };
8899
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
8900
+ noOpRequestHandler: () => {
8901
+ return new TdFirestoreDocumentMock({
8902
+ exists: false,
8903
+ id: "",
8904
+ path: ""
8905
+ });
8906
+ },
8907
+ isServerRequest: false,
8908
+ replayModeHandler: () => {
8909
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalGet.call(this), {
8910
+ name: "firestore.document.get",
8911
+ kind: __opentelemetry_api.SpanKind.CLIENT,
8912
+ submodule: "document",
8913
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
8914
+ packageName: PACKAGE_NAME,
8915
+ instrumentationName: self.INSTRUMENTATION_NAME,
8916
+ inputValue,
8917
+ isPreAppStart: false,
8918
+ stopRecordingChildSpans: true
8919
+ }, (spanInfo) => {
8920
+ return self._handleReplayDocumentGet(spanInfo, inputValue);
8921
+ });
8922
+ }
8923
+ });
8924
+ else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
8925
+ originalFunctionCall: () => originalGet.call(this),
8926
+ recordModeHandler: ({ isPreAppStart }) => {
8927
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalGet.call(this), {
8928
+ name: "firestore.document.get",
8929
+ kind: __opentelemetry_api.SpanKind.CLIENT,
8930
+ submodule: "document",
8931
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
8932
+ packageName: PACKAGE_NAME,
8933
+ instrumentationName: self.INSTRUMENTATION_NAME,
8934
+ inputValue,
8935
+ isPreAppStart,
8936
+ stopRecordingChildSpans: true
8937
+ }, (spanInfo) => {
8938
+ return self._handleRecordDocumentGet(spanInfo, originalGet, this);
8939
+ });
8940
+ },
8941
+ spanKind: __opentelemetry_api.SpanKind.CLIENT
8942
+ });
8943
+ else return originalGet.call(this);
8944
+ };
8945
+ };
8946
+ }
8947
+ async _handleRecordDocumentGet(spanInfo, originalGet, context$4) {
8948
+ const snapshot = await originalGet.call(context$4);
8949
+ const documentResult = {
8950
+ id: snapshot.id,
8951
+ path: snapshot.ref.path,
8952
+ exists: snapshot.exists,
8953
+ data: snapshot.exists ? snapshot.data() : void 0,
8954
+ createTime: snapshot.createTime ? {
8955
+ seconds: snapshot.createTime.seconds,
8956
+ nanoseconds: snapshot.createTime.nanoseconds
8957
+ } : void 0,
8958
+ updateTime: snapshot.updateTime ? {
8959
+ seconds: snapshot.updateTime.seconds,
8960
+ nanoseconds: snapshot.updateTime.nanoseconds
8961
+ } : void 0,
8962
+ readTime: snapshot.readTime ? {
8963
+ seconds: snapshot.readTime.seconds,
8964
+ nanoseconds: snapshot.readTime.nanoseconds
8965
+ } : void 0
8966
+ };
8967
+ try {
8968
+ SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: documentResult });
8969
+ SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
8970
+ } catch {
8971
+ logger.error(`[FirestoreInstrumentation] Error updating span attributes for document.get`);
8972
+ }
8973
+ return snapshot;
8974
+ }
8975
+ async _handleReplayDocumentGet(spanInfo, inputValue) {
8976
+ logger.debug(`[FirestoreInstrumentation] Replaying document.get`);
8977
+ const mockData = await findMockResponseAsync({
8978
+ mockRequestData: {
8979
+ traceId: spanInfo.traceId,
8980
+ spanId: spanInfo.spanId,
8981
+ name: "firestore.document.get",
8982
+ inputValue: createMockInputValue(inputValue),
8983
+ packageName: PACKAGE_NAME,
8984
+ instrumentationName: this.INSTRUMENTATION_NAME,
8985
+ submoduleName: "document",
8986
+ kind: __opentelemetry_api.SpanKind.CLIENT
8987
+ },
8988
+ tuskDrift: this.tuskDrift
8989
+ });
8990
+ if (!mockData) {
8991
+ logger.warn(`[FirestoreInstrumentation] No mock data found for document.get: ${inputValue.path}`);
8992
+ throw new Error(`[FirestoreInstrumentation] No matching mock found for document.get`);
8993
+ }
8994
+ const documentResult = mockData.result;
8995
+ return new TdFirestoreDocumentMock(documentResult);
8996
+ }
8997
+ _getDocumentCreatePatchFn() {
8998
+ const self = this;
8999
+ return (originalCreate) => {
9000
+ return function(data) {
9001
+ const inputValue = {
9002
+ operation: "document.create",
9003
+ path: this.path,
9004
+ data
9005
+ };
9006
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
9007
+ noOpRequestHandler: () => {
9008
+ const now = Date.now();
9009
+ const emptyWriteResult = { writeTime: {
9010
+ seconds: Math.floor(now / 1e3),
9011
+ nanoseconds: now % 1e3 * 1e6
9012
+ } };
9013
+ return new TdFirestoreWriteResultMock(emptyWriteResult);
9014
+ },
9015
+ isServerRequest: false,
9016
+ replayModeHandler: () => {
9017
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalCreate.call(this, data), {
9018
+ name: "firestore.document.create",
9019
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9020
+ submodule: "document",
9021
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9022
+ packageName: PACKAGE_NAME,
9023
+ instrumentationName: self.INSTRUMENTATION_NAME,
9024
+ inputValue,
9025
+ isPreAppStart: false,
9026
+ stopRecordingChildSpans: true
9027
+ }, (spanInfo) => {
9028
+ return self._handleReplayDocumentWrite(spanInfo, inputValue);
9029
+ });
9030
+ }
9031
+ });
9032
+ else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
9033
+ originalFunctionCall: () => originalCreate.call(this, data),
9034
+ recordModeHandler: ({ isPreAppStart }) => {
9035
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalCreate.call(this, data), {
9036
+ name: "firestore.document.create",
9037
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9038
+ submodule: "document",
9039
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9040
+ packageName: PACKAGE_NAME,
9041
+ instrumentationName: self.INSTRUMENTATION_NAME,
9042
+ inputValue,
9043
+ isPreAppStart,
9044
+ stopRecordingChildSpans: true
9045
+ }, (spanInfo) => {
9046
+ return self._handleRecordDocumentWrite(spanInfo, originalCreate, this, data);
9047
+ });
9048
+ },
9049
+ spanKind: __opentelemetry_api.SpanKind.CLIENT
9050
+ });
9051
+ else return originalCreate.call(this, data);
9052
+ };
9053
+ };
9054
+ }
9055
+ _getDocumentSetPatchFn() {
9056
+ const self = this;
9057
+ return (originalSet) => {
9058
+ return function(data, options) {
9059
+ const inputValue = {
9060
+ operation: "document.set",
9061
+ path: this.path,
9062
+ data,
9063
+ options
9064
+ };
9065
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
9066
+ noOpRequestHandler: () => {
9067
+ const now = Date.now();
9068
+ const emptyWriteResult = { writeTime: {
9069
+ seconds: Math.floor(now / 1e3),
9070
+ nanoseconds: now % 1e3 * 1e6
9071
+ } };
9072
+ return new TdFirestoreWriteResultMock(emptyWriteResult);
9073
+ },
9074
+ isServerRequest: false,
9075
+ replayModeHandler: () => {
9076
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalSet.call(this, data, options), {
9077
+ name: "firestore.document.set",
9078
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9079
+ submodule: "document",
9080
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9081
+ packageName: PACKAGE_NAME,
9082
+ instrumentationName: self.INSTRUMENTATION_NAME,
9083
+ inputValue,
9084
+ isPreAppStart: false,
9085
+ stopRecordingChildSpans: true
9086
+ }, (spanInfo) => {
9087
+ return self._handleReplayDocumentWrite(spanInfo, inputValue);
9088
+ });
9089
+ }
9090
+ });
9091
+ else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
9092
+ originalFunctionCall: () => originalSet.call(this, data, options),
9093
+ recordModeHandler: ({ isPreAppStart }) => {
9094
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalSet.call(this, data, options), {
9095
+ name: "firestore.document.set",
9096
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9097
+ submodule: "document",
9098
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9099
+ packageName: PACKAGE_NAME,
9100
+ instrumentationName: self.INSTRUMENTATION_NAME,
9101
+ inputValue,
9102
+ isPreAppStart,
9103
+ stopRecordingChildSpans: true
9104
+ }, (spanInfo) => {
9105
+ return self._handleRecordDocumentWrite(spanInfo, originalSet, this, data, options);
9106
+ });
9107
+ },
9108
+ spanKind: __opentelemetry_api.SpanKind.CLIENT
9109
+ });
9110
+ else return originalSet.call(this, data, options);
9111
+ };
9112
+ };
9113
+ }
9114
+ _getDocumentUpdatePatchFn() {
9115
+ const self = this;
9116
+ return (originalUpdate) => {
9117
+ return function(...args) {
9118
+ const inputValue = {
9119
+ operation: "document.update",
9120
+ path: this.path,
9121
+ data: args.length === 1 ? args[0] : args
9122
+ };
9123
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
9124
+ noOpRequestHandler: () => {
9125
+ const now = Date.now();
9126
+ const emptyWriteResult = { writeTime: {
9127
+ seconds: Math.floor(now / 1e3),
9128
+ nanoseconds: now % 1e3 * 1e6
9129
+ } };
9130
+ return new TdFirestoreWriteResultMock(emptyWriteResult);
9131
+ },
9132
+ isServerRequest: false,
9133
+ replayModeHandler: () => {
9134
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalUpdate.apply(this, args), {
9135
+ name: "firestore.document.update",
9136
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9137
+ submodule: "document",
9138
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9139
+ packageName: PACKAGE_NAME,
9140
+ instrumentationName: self.INSTRUMENTATION_NAME,
9141
+ inputValue,
9142
+ isPreAppStart: false,
9143
+ stopRecordingChildSpans: true
9144
+ }, (spanInfo) => {
9145
+ return self._handleReplayDocumentWrite(spanInfo, inputValue);
9146
+ });
9147
+ }
9148
+ });
9149
+ else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
9150
+ originalFunctionCall: () => originalUpdate.apply(this, args),
9151
+ recordModeHandler: ({ isPreAppStart }) => {
9152
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalUpdate.apply(this, args), {
9153
+ name: "firestore.document.update",
9154
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9155
+ submodule: "document",
9156
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9157
+ packageName: PACKAGE_NAME,
9158
+ instrumentationName: self.INSTRUMENTATION_NAME,
9159
+ inputValue,
9160
+ isPreAppStart,
9161
+ stopRecordingChildSpans: true
9162
+ }, (spanInfo) => {
9163
+ return self._handleRecordDocumentWrite(spanInfo, originalUpdate, this, ...args);
9164
+ });
9165
+ },
9166
+ spanKind: __opentelemetry_api.SpanKind.CLIENT
9167
+ });
9168
+ else return originalUpdate.apply(this, args);
9169
+ };
9170
+ };
9171
+ }
9172
+ _getDocumentDeletePatchFn() {
9173
+ const self = this;
9174
+ return (originalDelete) => {
9175
+ return function(precondition) {
9176
+ const inputValue = {
9177
+ operation: "document.delete",
9178
+ path: this.path,
9179
+ options: precondition
9180
+ };
9181
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
9182
+ noOpRequestHandler: () => {
9183
+ const now = Date.now();
9184
+ const emptyWriteResult = { writeTime: {
9185
+ seconds: Math.floor(now / 1e3),
9186
+ nanoseconds: now % 1e3 * 1e6
9187
+ } };
9188
+ return new TdFirestoreWriteResultMock(emptyWriteResult);
9189
+ },
9190
+ isServerRequest: false,
9191
+ replayModeHandler: () => {
9192
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalDelete.call(this, precondition), {
9193
+ name: "firestore.document.delete",
9194
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9195
+ submodule: "document",
9196
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9197
+ packageName: PACKAGE_NAME,
9198
+ instrumentationName: self.INSTRUMENTATION_NAME,
9199
+ inputValue,
9200
+ isPreAppStart: false,
9201
+ stopRecordingChildSpans: true
9202
+ }, (spanInfo) => {
9203
+ return self._handleReplayDocumentWrite(spanInfo, inputValue);
9204
+ });
9205
+ }
9206
+ });
9207
+ else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
9208
+ originalFunctionCall: () => originalDelete.call(this, precondition),
9209
+ recordModeHandler: ({ isPreAppStart }) => {
9210
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalDelete.call(this, precondition), {
9211
+ name: "firestore.document.delete",
9212
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9213
+ submodule: "document",
9214
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9215
+ packageName: PACKAGE_NAME,
9216
+ instrumentationName: self.INSTRUMENTATION_NAME,
9217
+ inputValue,
9218
+ isPreAppStart,
9219
+ stopRecordingChildSpans: true
9220
+ }, (spanInfo) => {
9221
+ return self._handleRecordDocumentWrite(spanInfo, originalDelete, this, precondition);
9222
+ });
9223
+ },
9224
+ spanKind: __opentelemetry_api.SpanKind.CLIENT
9225
+ });
9226
+ else return originalDelete.call(this, precondition);
9227
+ };
9228
+ };
9229
+ }
9230
+ async _handleRecordDocumentWrite(spanInfo, originalWrite, context$4, ...args) {
9231
+ const writeResult = await originalWrite.apply(context$4, args);
9232
+ const result = { writeTime: writeResult.writeTime ? {
9233
+ seconds: writeResult.writeTime.seconds,
9234
+ nanoseconds: writeResult.writeTime.nanoseconds
9235
+ } : void 0 };
9236
+ try {
9237
+ SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: result });
9238
+ SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
9239
+ } catch {
9240
+ logger.error(`[FirestoreInstrumentation] Error updating span attributes for document.write`);
9241
+ }
9242
+ return writeResult;
9243
+ }
9244
+ async _handleReplayDocumentWrite(spanInfo, inputValue) {
9245
+ logger.debug(`[FirestoreInstrumentation] Replaying document write: ${inputValue.operation}`);
9246
+ const mockData = await findMockResponseAsync({
9247
+ mockRequestData: {
9248
+ traceId: spanInfo.traceId,
9249
+ spanId: spanInfo.spanId,
9250
+ name: `firestore.${inputValue.operation}`,
9251
+ inputValue: createMockInputValue(inputValue),
9252
+ packageName: PACKAGE_NAME,
9253
+ instrumentationName: this.INSTRUMENTATION_NAME,
9254
+ submoduleName: "document",
9255
+ kind: __opentelemetry_api.SpanKind.CLIENT
9256
+ },
9257
+ tuskDrift: this.tuskDrift
9258
+ });
9259
+ if (!mockData) {
9260
+ logger.warn(`[FirestoreInstrumentation] No mock data found for ${inputValue.operation}: ${inputValue.path}`);
9261
+ throw new Error(`[FirestoreInstrumentation] No matching mock found for ${inputValue.operation}`);
9262
+ }
9263
+ const writeResult = mockData.result;
9264
+ return new TdFirestoreWriteResultMock(writeResult);
9265
+ }
9266
+ _getCollectionAddPatchFn() {
9267
+ const self = this;
9268
+ return (originalAdd) => {
9269
+ return function(data) {
9270
+ const inputValue = {
9271
+ operation: "collection.add",
9272
+ path: this.path,
9273
+ data
9274
+ };
9275
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
9276
+ noOpRequestHandler: () => {
9277
+ if (!this.originalCollectionDocFn) {
9278
+ logger.error(`[FirestoreInstrumentation] Original doc function not available`);
9279
+ return Promise.reject(/* @__PURE__ */ new Error("Original doc function not available"));
9280
+ }
9281
+ return this.originalCollectionDocFn.call(this, "");
9282
+ },
9283
+ isServerRequest: false,
9284
+ replayModeHandler: () => {
9285
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalAdd.call(this, data), {
9286
+ name: "firestore.collection.add",
9287
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9288
+ submodule: "collection",
9289
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9290
+ packageName: PACKAGE_NAME,
9291
+ instrumentationName: self.INSTRUMENTATION_NAME,
9292
+ inputValue,
9293
+ isPreAppStart: false,
9294
+ stopRecordingChildSpans: true
9295
+ }, (spanInfo) => {
9296
+ return self._handleReplayCollectionAdd(spanInfo, inputValue, this);
9297
+ });
9298
+ }
9299
+ });
9300
+ else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
9301
+ originalFunctionCall: () => originalAdd.call(this, data),
9302
+ recordModeHandler: ({ isPreAppStart }) => {
9303
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalAdd.call(this, data), {
9304
+ name: "firestore.collection.add",
9305
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9306
+ submodule: "collection",
9307
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9308
+ packageName: PACKAGE_NAME,
9309
+ instrumentationName: self.INSTRUMENTATION_NAME,
9310
+ inputValue,
9311
+ isPreAppStart,
9312
+ stopRecordingChildSpans: true
9313
+ }, (spanInfo) => {
9314
+ return self._handleRecordCollectionAdd(spanInfo, originalAdd, this, data);
9315
+ });
9316
+ },
9317
+ spanKind: __opentelemetry_api.SpanKind.CLIENT
9318
+ });
9319
+ else return originalAdd.call(this, data);
9320
+ };
9321
+ };
7846
9322
  }
7847
- isGrpcErrorOutput(result) {
7848
- return "error" in result;
9323
+ async _handleRecordCollectionAdd(spanInfo, originalAdd, context$4, data) {
9324
+ const docRef = await originalAdd.call(context$4, data);
9325
+ const result = {
9326
+ id: docRef.id,
9327
+ path: docRef.path
9328
+ };
9329
+ try {
9330
+ SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: result });
9331
+ SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
9332
+ } catch {
9333
+ logger.error(`[FirestoreInstrumentation] Error updating span attributes for collection.add`);
9334
+ }
9335
+ return docRef;
7849
9336
  }
7850
- async _handleReplayUnaryRequest(spanInfo, inputValue, callback, MetadataConstructor, stackTrace) {
7851
- logger.debug(`[GrpcInstrumentation] Replaying gRPC unary request`);
9337
+ async _handleReplayCollectionAdd(spanInfo, inputValue, collectionRef) {
9338
+ logger.debug(`[FirestoreInstrumentation] Replaying collection.add`);
7852
9339
  const mockData = await findMockResponseAsync({
7853
9340
  mockRequestData: {
7854
9341
  traceId: spanInfo.traceId,
7855
9342
  spanId: spanInfo.spanId,
7856
- name: "grpc.client.unary",
7857
- inputValue,
7858
- packageName: GRPC_MODULE_NAME,
9343
+ name: "firestore.collection.add",
9344
+ inputValue: createMockInputValue(inputValue),
9345
+ packageName: PACKAGE_NAME,
7859
9346
  instrumentationName: this.INSTRUMENTATION_NAME,
7860
- submoduleName: "client",
7861
- kind: __opentelemetry_api.SpanKind.CLIENT,
7862
- stackTrace
9347
+ submoduleName: "collection",
9348
+ kind: __opentelemetry_api.SpanKind.CLIENT
7863
9349
  },
7864
9350
  tuskDrift: this.tuskDrift
7865
9351
  });
7866
9352
  if (!mockData) {
7867
- logger.warn(`[GrpcInstrumentation] No mock data found for gRPC request: ${inputValue.service}/${inputValue.method}`);
7868
- callback(/* @__PURE__ */ new Error("No mock data found"));
7869
- SpanUtils.endSpan(spanInfo.span, {
7870
- code: __opentelemetry_api.SpanStatusCode.ERROR,
7871
- message: "No mock data found"
7872
- });
7873
- return;
9353
+ logger.warn(`[FirestoreInstrumentation] No mock data found for collection.add: ${inputValue.path}`);
9354
+ throw new Error(`[FirestoreInstrumentation] No matching mock found for collection.add`);
7874
9355
  }
7875
- const mockResult = mockData.result;
7876
- let status;
7877
- if (this.isGrpcErrorOutput(mockResult)) {
7878
- const { error, status: errorStatus } = mockResult;
7879
- status = {
7880
- code: errorStatus.code,
7881
- details: errorStatus.details,
7882
- metadata: deserializeGrpcMetadata(MetadataConstructor, errorStatus.metadata)
7883
- };
7884
- const errorObj = Object.assign(new Error(error.message), {
7885
- name: error.name,
7886
- stack: error.stack,
7887
- ...status
7888
- });
7889
- callback(errorObj);
7890
- } else {
7891
- const { body, status: successStatus, bufferMap, jsonableStringMap } = mockResult;
7892
- const bufferMapToUse = bufferMap || {};
7893
- const jsonableStringMapToUse = jsonableStringMap || {};
7894
- status = {
7895
- code: successStatus.code,
7896
- details: successStatus.details,
7897
- metadata: deserializeGrpcMetadata(MetadataConstructor, successStatus.metadata)
7898
- };
7899
- const realResponse = deserializeGrpcPayload(body, bufferMapToUse, jsonableStringMapToUse);
7900
- callback(null, realResponse);
9356
+ const recordedId = mockData.result.id;
9357
+ if (!this.originalCollectionDocFn) {
9358
+ logger.error(`[FirestoreInstrumentation] Original doc function not available`);
9359
+ return Promise.reject(/* @__PURE__ */ new Error("Original doc function not available"));
7901
9360
  }
7902
- const emitter = Object.assign(new events.EventEmitter(), {
7903
- cancel() {},
7904
- getPeer: () => "0.0.0.0:0000",
7905
- call: void 0
7906
- });
7907
- process.nextTick(() => {
7908
- if (mockResult.metadata) emitter.emit("metadata", deserializeGrpcMetadata(MetadataConstructor, mockResult.metadata));
7909
- emitter.emit("status", status);
7910
- });
7911
- SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: mockResult });
7912
- SpanUtils.endSpan(spanInfo.span, { code: mockResult.error ? __opentelemetry_api.SpanStatusCode.ERROR : __opentelemetry_api.SpanStatusCode.OK });
7913
- return emitter;
9361
+ return this.originalCollectionDocFn.call(collectionRef, recordedId);
7914
9362
  }
7915
- _getWaitForReadyPatchFn() {
9363
+ _getCollectionDocPatchFn() {
7916
9364
  const self = this;
7917
- return (original) => {
7918
- return function waitForReady(deadline, callback) {
7919
- if (self.mode === TuskDriftMode.REPLAY) {
7920
- process.nextTick(() => callback());
7921
- return;
7922
- } else return original.apply(this, [deadline, callback]);
9365
+ return (originalDoc) => {
9366
+ return function(documentPath) {
9367
+ const collectionPath = this.path;
9368
+ const inputValue = {
9369
+ operation: "collection.doc",
9370
+ path: collectionPath,
9371
+ documentId: documentPath
9372
+ };
9373
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
9374
+ noOpRequestHandler: () => {
9375
+ return originalDoc.call(this, "");
9376
+ },
9377
+ isServerRequest: false,
9378
+ replayModeHandler: () => {
9379
+ return SpanUtils.createAndExecuteSpan(self.mode, () => documentPath ? originalDoc.call(this, documentPath) : originalDoc.call(this), {
9380
+ name: "firestore.collection.doc",
9381
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9382
+ submodule: "collection",
9383
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9384
+ packageName: PACKAGE_NAME,
9385
+ instrumentationName: self.INSTRUMENTATION_NAME,
9386
+ inputValue,
9387
+ isPreAppStart: false,
9388
+ stopRecordingChildSpans: true
9389
+ }, (spanInfo) => {
9390
+ const mockData = findMockResponseSync({
9391
+ mockRequestData: {
9392
+ traceId: spanInfo.traceId,
9393
+ spanId: spanInfo.spanId,
9394
+ name: "firestore.collection.doc",
9395
+ inputValue: createMockInputValue(inputValue),
9396
+ packageName: PACKAGE_NAME,
9397
+ instrumentationName: self.INSTRUMENTATION_NAME,
9398
+ submoduleName: "collection",
9399
+ kind: __opentelemetry_api.SpanKind.CLIENT
9400
+ },
9401
+ tuskDrift: self.tuskDrift
9402
+ });
9403
+ if (!mockData) {
9404
+ logger.warn(`[FirestoreInstrumentation] No mock data found for collection.doc: ${collectionPath}`);
9405
+ throw new Error(`[FirestoreInstrumentation] No matching mock found for collection.doc`);
9406
+ }
9407
+ const recordedId = mockData.result.id;
9408
+ logger.debug(`[FirestoreInstrumentation] replaying doc call with recorded id: ${recordedId}`);
9409
+ const docRef = originalDoc.call(this, recordedId);
9410
+ logger.debug(`[FirestoreInstrumentation] doc ref, id`, docRef, recordedId);
9411
+ return docRef;
9412
+ });
9413
+ }
9414
+ });
9415
+ else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
9416
+ originalFunctionCall: () => documentPath ? originalDoc.call(this, documentPath) : originalDoc.call(this),
9417
+ recordModeHandler: ({ isPreAppStart }) => {
9418
+ return SpanUtils.createAndExecuteSpan(self.mode, () => documentPath ? originalDoc.call(this, documentPath) : originalDoc.call(this), {
9419
+ name: "firestore.collection.doc",
9420
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9421
+ submodule: "collection",
9422
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9423
+ packageName: PACKAGE_NAME,
9424
+ instrumentationName: self.INSTRUMENTATION_NAME,
9425
+ inputValue,
9426
+ isPreAppStart,
9427
+ stopRecordingChildSpans: true
9428
+ }, (spanInfo) => {
9429
+ const docRef = documentPath ? originalDoc.call(this, documentPath) : originalDoc.call(this);
9430
+ const result = {
9431
+ id: docRef.id,
9432
+ path: docRef.path
9433
+ };
9434
+ try {
9435
+ SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: result });
9436
+ SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
9437
+ } catch {
9438
+ logger.error(`[FirestoreInstrumentation] Error updating span attributes for collection.doc`);
9439
+ }
9440
+ return docRef;
9441
+ });
9442
+ },
9443
+ spanKind: __opentelemetry_api.SpanKind.CLIENT
9444
+ });
9445
+ else return documentPath ? originalDoc.call(this, documentPath) : originalDoc.call(this);
7923
9446
  };
7924
9447
  };
7925
9448
  }
7926
- _getClosePatchFn() {
9449
+ _getQueryGetPatchFn() {
7927
9450
  const self = this;
7928
- return (original) => {
7929
- return function close() {
7930
- if (self.mode === TuskDriftMode.REPLAY) return;
7931
- else return original.apply(this, arguments);
9451
+ return (originalGet) => {
9452
+ return function() {
9453
+ const inputValue = {
9454
+ operation: "query.get",
9455
+ path: this._queryOptions?.parentPath?.formattedName || "unknown"
9456
+ };
9457
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
9458
+ noOpRequestHandler: () => {
9459
+ return new TdFirestoreQueryMock({
9460
+ size: 0,
9461
+ empty: true,
9462
+ docs: []
9463
+ });
9464
+ },
9465
+ isServerRequest: false,
9466
+ replayModeHandler: () => {
9467
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalGet.call(this), {
9468
+ name: "firestore.query.get",
9469
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9470
+ submodule: "query",
9471
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9472
+ packageName: PACKAGE_NAME,
9473
+ instrumentationName: self.INSTRUMENTATION_NAME,
9474
+ inputValue,
9475
+ isPreAppStart: false,
9476
+ stopRecordingChildSpans: true
9477
+ }, (spanInfo) => {
9478
+ return self._handleReplayQueryGet(spanInfo, inputValue);
9479
+ });
9480
+ }
9481
+ });
9482
+ else if (self.mode === TuskDriftMode.RECORD) return handleRecordMode({
9483
+ originalFunctionCall: () => originalGet.call(this),
9484
+ recordModeHandler: ({ isPreAppStart }) => {
9485
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalGet.call(this), {
9486
+ name: "firestore.query.get",
9487
+ kind: __opentelemetry_api.SpanKind.CLIENT,
9488
+ submodule: "query",
9489
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.FIRESTORE,
9490
+ packageName: PACKAGE_NAME,
9491
+ instrumentationName: self.INSTRUMENTATION_NAME,
9492
+ inputValue,
9493
+ isPreAppStart,
9494
+ stopRecordingChildSpans: true
9495
+ }, (spanInfo) => {
9496
+ return self._handleRecordQueryGet(spanInfo, originalGet, this);
9497
+ });
9498
+ },
9499
+ spanKind: __opentelemetry_api.SpanKind.CLIENT
9500
+ });
9501
+ else return originalGet.call(this);
7932
9502
  };
7933
9503
  };
7934
9504
  }
7935
- _getGetChannelPatchFn() {
7936
- const self = this;
7937
- return (original) => {
7938
- return function getChannel() {
7939
- if (self.mode === TuskDriftMode.REPLAY) return {};
7940
- else return original.apply(this, arguments);
7941
- };
9505
+ async _handleRecordQueryGet(spanInfo, originalGet, context$4) {
9506
+ const querySnapshot = await originalGet.call(context$4);
9507
+ const queryResult = {
9508
+ docs: querySnapshot.docs.map((doc) => ({
9509
+ id: doc.id,
9510
+ path: doc.ref.path,
9511
+ exists: doc.exists,
9512
+ data: doc.exists ? doc.data() : void 0,
9513
+ createTime: doc.createTime ? {
9514
+ seconds: doc.createTime.seconds,
9515
+ nanoseconds: doc.createTime.nanoseconds
9516
+ } : void 0,
9517
+ updateTime: doc.updateTime ? {
9518
+ seconds: doc.updateTime.seconds,
9519
+ nanoseconds: doc.updateTime.nanoseconds
9520
+ } : void 0,
9521
+ readTime: doc.readTime ? {
9522
+ seconds: doc.readTime.seconds,
9523
+ nanoseconds: doc.readTime.nanoseconds
9524
+ } : void 0
9525
+ })),
9526
+ size: querySnapshot.size,
9527
+ empty: querySnapshot.empty,
9528
+ readTime: querySnapshot.readTime ? {
9529
+ seconds: querySnapshot.readTime.seconds,
9530
+ nanoseconds: querySnapshot.readTime.nanoseconds
9531
+ } : void 0
7942
9532
  };
9533
+ try {
9534
+ SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: queryResult });
9535
+ SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
9536
+ } catch {
9537
+ logger.error(`[FirestoreInstrumentation] Error updating span attributes for query.get`);
9538
+ }
9539
+ return querySnapshot;
9540
+ }
9541
+ async _handleReplayQueryGet(spanInfo, inputValue) {
9542
+ logger.debug(`[FirestoreInstrumentation] Replaying query.get`);
9543
+ const mockData = await findMockResponseAsync({
9544
+ mockRequestData: {
9545
+ traceId: spanInfo.traceId,
9546
+ spanId: spanInfo.spanId,
9547
+ name: "firestore.query.get",
9548
+ inputValue: createMockInputValue(inputValue),
9549
+ packageName: PACKAGE_NAME,
9550
+ instrumentationName: this.INSTRUMENTATION_NAME,
9551
+ submoduleName: "query",
9552
+ kind: __opentelemetry_api.SpanKind.CLIENT
9553
+ },
9554
+ tuskDrift: this.tuskDrift
9555
+ });
9556
+ if (!mockData) {
9557
+ logger.warn(`[FirestoreInstrumentation] No mock data found for query.get: ${inputValue.path}`);
9558
+ throw new Error(`[FirestoreInstrumentation] No matching mock found for query.get`);
9559
+ }
9560
+ const queryResult = mockData.result;
9561
+ return new TdFirestoreQueryMock(queryResult);
7943
9562
  }
7944
9563
  _wrap(target, propertyName, wrapper) {
7945
- wrap(target, propertyName, wrapper);
9564
+ if (!target || typeof target[propertyName] !== "function") {
9565
+ logger.warn(`[FirestoreInstrumentation] Cannot wrap ${propertyName}: not a function or target is undefined`);
9566
+ return;
9567
+ }
9568
+ const original = target[propertyName];
9569
+ target[propertyName] = wrapper(original);
7946
9570
  }
7947
9571
  };
7948
- GrpcInstrumentation.metadataStore = /* @__PURE__ */ new Map();
7949
9572
 
7950
9573
  //#endregion
7951
9574
  //#region src/instrumentation/libraries/nextjs/Instrumentation.ts
@@ -8005,58 +9628,64 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
8005
9628
  const self = this;
8006
9629
  return (originalHandleRequest) => {
8007
9630
  return async function(req, res, parsedUrl) {
9631
+ if (self.mode === TuskDriftMode.RECORD) {
9632
+ if (!shouldSample({
9633
+ samplingRate: self.tuskDrift.getSamplingRate(),
9634
+ isAppReady: self.tuskDrift.isAppReady()
9635
+ })) return originalHandleRequest.call(this, req, res, parsedUrl);
9636
+ }
8008
9637
  const method = req.method || "GET";
8009
9638
  const url = req.url || "/";
8010
9639
  logger.debug(`[NextjsInstrumentation] Intercepted Next.js request: ${method} ${url}`);
8011
- if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({ replayModeHandler: () => {
8012
- const inputValue = {
8013
- method,
8014
- url,
8015
- target: url,
8016
- headers: self._normalizeHeaders(req.headers || {})
8017
- };
8018
- const replayTraceId = self.replayHooks.extractTraceIdFromHeaders(req);
8019
- if (!replayTraceId) {
8020
- logger.debug(`[NextjsInstrumentation] No trace ID found, calling original handler`);
8021
- return originalHandleRequest.call(this, req, res, parsedUrl);
8022
- }
8023
- const envVars = self.replayHooks.extractEnvVarsFromHeaders(req);
8024
- if (envVars) EnvVarTracker.setEnvVars(replayTraceId, envVars);
8025
- const ctxWithReplayTraceId = SpanUtils.setCurrentReplayTraceId(replayTraceId);
8026
- if (!ctxWithReplayTraceId) throw new Error("Error setting current replay trace id");
8027
- return __opentelemetry_api.context.with(ctxWithReplayTraceId, () => {
8028
- return SpanUtils.createAndExecuteSpan(self.mode, () => originalHandleRequest.call(this, req, res, parsedUrl), {
8029
- name: url,
8030
- kind: __opentelemetry_api.SpanKind.SERVER,
8031
- packageName: "nextjs",
8032
- submodule: method,
8033
- packageType: __use_tusk_drift_schemas_core_span.PackageType.HTTP,
8034
- instrumentationName: self.INSTRUMENTATION_NAME,
8035
- inputValue,
8036
- inputSchemaMerges: { headers: { matchImportance: 0 } },
8037
- isPreAppStart: false
8038
- }, (spanInfo) => {
8039
- return self._handleNextjsRequestInSpan({
8040
- req,
8041
- res,
8042
- parsedUrl,
8043
- originalHandleRequest,
8044
- spanInfo,
9640
+ if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
9641
+ noOpRequestHandler: () => {
9642
+ throw new Error(`[NextjsInstrumentation] Should never call noOpRequestHandler for server requests ${method} ${url}`);
9643
+ },
9644
+ isServerRequest: true,
9645
+ replayModeHandler: () => {
9646
+ const inputValue = {
9647
+ method,
9648
+ url,
9649
+ target: url,
9650
+ headers: self._normalizeHeaders(req.headers || {})
9651
+ };
9652
+ const replayTraceId = self.replayHooks.extractTraceIdFromHeaders(req);
9653
+ if (!replayTraceId) {
9654
+ logger.debug(`[NextjsInstrumentation] No trace ID found, calling original handler`);
9655
+ return originalHandleRequest.call(this, req, res, parsedUrl);
9656
+ }
9657
+ logger.debug(`[NextjsInstrumentation] Setting replay trace id`, replayTraceId);
9658
+ const envVars = self.replayHooks.extractEnvVarsFromHeaders(req);
9659
+ if (envVars) EnvVarTracker.setEnvVars(replayTraceId, envVars);
9660
+ const ctxWithReplayTraceId = SpanUtils.setCurrentReplayTraceId(replayTraceId);
9661
+ if (!ctxWithReplayTraceId) throw new Error("Error setting current replay trace id");
9662
+ return __opentelemetry_api.context.with(ctxWithReplayTraceId, () => {
9663
+ return SpanUtils.createAndExecuteSpan(self.mode, () => originalHandleRequest.call(this, req, res, parsedUrl), {
9664
+ name: url,
9665
+ kind: __opentelemetry_api.SpanKind.SERVER,
9666
+ packageName: "nextjs",
9667
+ submodule: method,
9668
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.HTTP,
9669
+ instrumentationName: self.INSTRUMENTATION_NAME,
8045
9670
  inputValue,
8046
- thisContext: this
9671
+ inputSchemaMerges: { headers: { matchImportance: 0 } },
9672
+ isPreAppStart: false
9673
+ }, (spanInfo) => {
9674
+ return self._handleNextjsRequestInSpan({
9675
+ req,
9676
+ res,
9677
+ parsedUrl,
9678
+ originalHandleRequest,
9679
+ spanInfo,
9680
+ inputValue,
9681
+ thisContext: this
9682
+ });
8047
9683
  });
8048
9684
  });
8049
- });
8050
- } });
9685
+ }
9686
+ });
8051
9687
  else if (self.mode === TuskDriftMode.RECORD) {
8052
9688
  if (method.toUpperCase() === "OPTIONS" || !!req.headers["access-control-request-method"]) return originalHandleRequest.call(this, req, res, parsedUrl);
8053
- if (!shouldSample({
8054
- samplingRate: self.tuskDrift.getSamplingRate(),
8055
- isAppReady: self.tuskDrift.isAppReady()
8056
- })) {
8057
- logger.debug(`[NextjsInstrumentation] Skipping server span due to sampling rate: ${url}`);
8058
- return originalHandleRequest.call(this, req, res, parsedUrl);
8059
- }
8060
9689
  logger.debug(`[NextjsInstrumentation] Creating server span for ${method} ${url}`);
8061
9690
  return handleRecordMode({
8062
9691
  originalFunctionCall: () => originalHandleRequest.call(this, req, res, parsedUrl),
@@ -8135,6 +9764,19 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
8135
9764
  };
8136
9765
  try {
8137
9766
  await originalHandleRequest.call(thisContext, req, res, parsedUrl);
9767
+ } catch (error) {
9768
+ logger.error(`[NextjsInstrumentation] Error in Next.js request: ${error instanceof Error ? error.message : "Unknown error"}`);
9769
+ try {
9770
+ SpanUtils.endSpan(spanInfo.span, {
9771
+ code: __opentelemetry_api.SpanStatusCode.ERROR,
9772
+ message: error instanceof Error ? error.message : "Unknown error"
9773
+ });
9774
+ } catch (e) {
9775
+ logger.error(`[NextjsInstrumentation] Error ending span:`, e);
9776
+ }
9777
+ throw error;
9778
+ }
9779
+ try {
8138
9780
  if (!capturedStatusCode) {
8139
9781
  capturedStatusCode = res.statusCode;
8140
9782
  capturedStatusMessage = res.statusMessage;
@@ -8159,7 +9801,6 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
8159
9801
  outputValue.bodySize = responseBuffer.length;
8160
9802
  } catch (error) {
8161
9803
  logger.error(`[NextjsInstrumentation] Error processing response body:`, error);
8162
- outputValue.bodyProcessingError = error instanceof Error ? error.message : String(error);
8163
9804
  }
8164
9805
  SpanUtils.addSpanAttributes(spanInfo.span, {
8165
9806
  inputValue: completeInputValue,
@@ -8179,6 +9820,11 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
8179
9820
  message: `HTTP ${capturedStatusCode}`
8180
9821
  } : { code: __opentelemetry_api.SpanStatusCode.OK };
8181
9822
  SpanUtils.setStatus(spanInfo.span, status);
9823
+ const decodedType = getDecodedType(outputValue.headers?.["content-type"] || "");
9824
+ if (decodedType && STATIC_ASSET_TYPES.has(decodedType)) {
9825
+ TraceBlockingManager.getInstance().blockTrace(spanInfo.traceId);
9826
+ logger.debug(`[NextjsInstrumentation] Blocking trace ${spanInfo.traceId} because it is an static asset response. Decoded type: ${decodedType}`);
9827
+ }
8182
9828
  SpanUtils.endSpan(spanInfo.span);
8183
9829
  if (self.mode === TuskDriftMode.REPLAY) try {
8184
9830
  const now = OriginalGlobalUtils.getOriginalDate();
@@ -8236,12 +9882,15 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
8236
9882
  logger.error("[NextjsInstrumentation] Failed to build/send inbound replay span:", e);
8237
9883
  }
8238
9884
  } catch (error) {
8239
- logger.error(`[NextjsInstrumentation] Error in Next.js request: ${error instanceof Error ? error.message : String(error)}`);
8240
- SpanUtils.endSpan(spanInfo.span, {
8241
- code: __opentelemetry_api.SpanStatusCode.ERROR,
8242
- message: error instanceof Error ? error.message : String(error)
8243
- });
8244
- throw error;
9885
+ logger.error(`[NextjsInstrumentation] Error in Next.js request: ${error instanceof Error ? error.message : "Unknown error"}`);
9886
+ try {
9887
+ SpanUtils.endSpan(spanInfo.span, {
9888
+ code: __opentelemetry_api.SpanStatusCode.ERROR,
9889
+ message: error instanceof Error ? error.message : "Unknown error"
9890
+ });
9891
+ } catch (e) {
9892
+ logger.error(`[NextjsInstrumentation] Error ending span:`, e);
9893
+ }
8245
9894
  }
8246
9895
  }
8247
9896
  /**
@@ -10468,20 +12117,21 @@ var SpanTransformer = class SpanTransformer {
10468
12117
  const inputData = JSON.parse(inputValueString);
10469
12118
  const inputSchemaMergesString = attributes[TdSpanAttributes.INPUT_SCHEMA_MERGES];
10470
12119
  const inputSchemaMerges = inputSchemaMergesString ? JSON.parse(inputSchemaMergesString) : void 0;
10471
- const { schema: inputSchema, decodedValueHash: inputValueHash } = JsonSchemaHelper.generateSchemaAndHash(inputData, inputSchemaMerges);
12120
+ const { schema: inputSchema, decodedValueHash: inputValueHash, decodedSchemaHash: inputSchemaHash } = JsonSchemaHelper.generateSchemaAndHash(inputData, inputSchemaMerges);
10472
12121
  let outputData = {};
10473
12122
  let outputSchema = {
10474
12123
  type: __use_tusk_drift_schemas_core_json_schema.JsonSchemaType.OBJECT,
10475
12124
  properties: {}
10476
12125
  };
10477
12126
  let outputValueHash = "";
12127
+ let outputSchemaHash = "";
10478
12128
  if (attributes[TdSpanAttributes.OUTPUT_VALUE]) {
10479
12129
  const outputValueString = attributes[TdSpanAttributes.OUTPUT_VALUE];
10480
12130
  outputData = JSON.parse(outputValueString);
10481
12131
  const outputSchemaMergesString = attributes[TdSpanAttributes.OUTPUT_SCHEMA_MERGES];
10482
12132
  const outputSchemaMerges = outputSchemaMergesString ? JSON.parse(outputSchemaMergesString) : void 0;
10483
- ({schema: outputSchema, decodedValueHash: outputValueHash} = JsonSchemaHelper.generateSchemaAndHash(outputData, outputSchemaMerges));
10484
- } else ({schema: outputSchema, decodedSchemaHash: outputValueHash} = JsonSchemaHelper.generateSchemaAndHash(outputData));
12133
+ ({schema: outputSchema, decodedValueHash: outputValueHash, decodedSchemaHash: outputSchemaHash} = JsonSchemaHelper.generateSchemaAndHash(outputData, outputSchemaMerges));
12134
+ } else ({schema: outputSchema, decodedValueHash: outputValueHash, decodedSchemaHash: outputSchemaHash} = JsonSchemaHelper.generateSchemaAndHash(outputData));
10485
12135
  let metadata = void 0;
10486
12136
  if (attributes[TdSpanAttributes.METADATA]) metadata = JSON.parse(attributes[TdSpanAttributes.METADATA]);
10487
12137
  let transformMetadata;
@@ -10505,8 +12155,8 @@ var SpanTransformer = class SpanTransformer {
10505
12155
  outputValue: outputData,
10506
12156
  inputSchema,
10507
12157
  outputSchema,
10508
- inputSchemaHash: JsonSchemaHelper.generateDeterministicHash(inputSchema),
10509
- outputSchemaHash: JsonSchemaHelper.generateDeterministicHash(outputSchema),
12158
+ inputSchemaHash,
12159
+ outputSchemaHash,
10510
12160
  inputValueHash,
10511
12161
  outputValueHash,
10512
12162
  kind: span.kind,
@@ -10749,18 +12399,35 @@ var TdSpanExporter = class {
10749
12399
  */
10750
12400
  export(spans, resultCallback) {
10751
12401
  logger.debug(`TdSpanExporter.export() called with ${spans.length} span(s)`);
10752
- const filteredSpans = spans.filter((span) => {
10753
- if (span.instrumentationLibrary?.name === "next.js") return false;
12402
+ const traceBlockingManager = TraceBlockingManager.getInstance();
12403
+ const filteredSpansBasedOnLibraryName = spans.filter((span) => {
12404
+ if (span.instrumentationLibrary.name === TD_INSTRUMENTATION_LIBRARY_NAME) return true;
12405
+ return false;
12406
+ });
12407
+ logger.debug(`After filtering based on library name: ${filteredSpansBasedOnLibraryName.length} span(s) remaining`);
12408
+ const MAX_SPAN_SIZE_MB = 1;
12409
+ const MAX_SPAN_SIZE_BYTES = MAX_SPAN_SIZE_MB * 1024 * 1024;
12410
+ const filteredBlockedSpans = filteredSpansBasedOnLibraryName.filter((span) => {
12411
+ const traceId = span.spanContext().traceId;
12412
+ if (traceBlockingManager.isTraceBlocked(traceId)) {
12413
+ logger.debug(`Skipping span '${span.name}' (${span.spanContext().spanId}) - trace ${traceId} is blocked`);
12414
+ return false;
12415
+ }
12416
+ const inputValueString = span.attributes[TdSpanAttributes.INPUT_VALUE] || "";
12417
+ const outputValueString = span.attributes[TdSpanAttributes.OUTPUT_VALUE] || "";
12418
+ const inputSize = Buffer.byteLength(inputValueString, "utf8");
12419
+ const outputSize = Buffer.byteLength(outputValueString, "utf8");
12420
+ const estimatedTotalSize = inputSize + outputSize + 5e4;
12421
+ const estimatedSizeMB = estimatedTotalSize / (1024 * 1024);
12422
+ if (estimatedTotalSize > MAX_SPAN_SIZE_BYTES) {
12423
+ traceBlockingManager.blockTrace(traceId);
12424
+ logger.warn(`Blocking trace ${traceId} - span '${span.name}' (${span.spanContext().spanId}) has estimated size ${estimatedSizeMB.toFixed(2)} MB exceeding limit of ${MAX_SPAN_SIZE_MB} MB. Future spans for this trace will be prevented.`);
12425
+ return false;
12426
+ }
10754
12427
  return true;
10755
12428
  });
10756
- logger.debug(`After filtering: ${filteredSpans.length} span(s) remaining`);
10757
- let cleanSpans;
10758
- try {
10759
- cleanSpans = filteredSpans.map((span) => SpanTransformer.transformSpanToCleanJSON(span));
10760
- } catch (error) {
10761
- logger.error("Error transforming spans to CleanSpanData", error);
10762
- throw error;
10763
- }
12429
+ logger.debug(`Filtered ${filteredSpansBasedOnLibraryName.length - filteredBlockedSpans.length} blocked/oversized span(s), ${filteredBlockedSpans.length} remaining`);
12430
+ const cleanSpans = filteredBlockedSpans.map((span) => SpanTransformer.transformSpanToCleanJSON(span));
10764
12431
  if (this.adapters.length === 0) {
10765
12432
  logger.debug("No adapters configured");
10766
12433
  resultCallback({ code: import_src.ExportResultCode.SUCCESS });
@@ -10895,15 +12562,12 @@ var ProtobufCommunicator = class {
10895
12562
  });
10896
12563
  }
10897
12564
  /**
10898
- * This function uses a Node.js script to communicate with the CLI over a socket.
10899
- * The script is called using execSync, which will block the main thread until the child process exits. This makes requesting mocks from the CLI synchronous.
10900
- *
10901
- * Since this function blocks the main thread, there is a perfomance impact for using this. We should use requestMockAsync whenever possilbe and only use this function
10902
- * for instrumentations that request fetching mocks synchronously.
12565
+ * This function uses a separate Node.js child process to communicate with the CLI over a socket.
12566
+ * The child process creates its own connection and event loop, allowing proper async socket handling.
12567
+ * The parent process blocks synchronously waiting for the child to complete.
10903
12568
  *
10904
- * (10/9/2025) Currently not using this function since we are not actually fetching mocks for the only sync instrumentation (Date)
10905
- * NOTE: This function probably doesn't work. plus, nc might not be installed on all machines (especially windows)
10906
- * Better approach is replacing nc command with pure Node.js implementation
12569
+ * Since this function blocks the main thread, there is a performance impact. We should use requestMockAsync whenever possible and only use this function
12570
+ * for instrumentations that require fetching mocks synchronously.
10907
12571
  */
10908
12572
  requestMockSync(mockRequest) {
10909
12573
  const requestId = this.generateRequestId();
@@ -10926,10 +12590,15 @@ var ProtobufCommunicator = class {
10926
12590
  getMockRequest: protoMockRequest
10927
12591
  }
10928
12592
  });
12593
+ logger.debug("Sending protobuf request to CLI (sync)", {
12594
+ outboundSpan: mockRequest.outboundSpan,
12595
+ testId: mockRequest.testId
12596
+ });
10929
12597
  const messageBytes = __use_tusk_drift_schemas_core_communication.SDKMessage.toBinary(sdkMessage);
10930
12598
  const tempDir = os.default.tmpdir();
10931
- const requestFile = path.default.join(tempDir, `tusk-request-${requestId}.bin`);
10932
- const responseFile = path.default.join(tempDir, `tusk-response-${requestId}.bin`);
12599
+ const requestFile = path.default.join(tempDir, `tusk-sync-request-${requestId}.bin`);
12600
+ const responseFile = path.default.join(tempDir, `tusk-sync-response-${requestId}.bin`);
12601
+ const scriptFile = path.default.join(tempDir, `tusk-sync-script-${requestId}.js`);
10933
12602
  try {
10934
12603
  const lengthBuffer = Buffer.allocUnsafe(4);
10935
12604
  lengthBuffer.writeUInt32BE(messageBytes.length, 0);
@@ -10938,19 +12607,112 @@ var ProtobufCommunicator = class {
10938
12607
  const mockSocket = OriginalGlobalUtils.getOriginalProcessEnvVar("TUSK_MOCK_SOCKET");
10939
12608
  const mockHost = OriginalGlobalUtils.getOriginalProcessEnvVar("TUSK_MOCK_HOST");
10940
12609
  const mockPort = OriginalGlobalUtils.getOriginalProcessEnvVar("TUSK_MOCK_PORT");
10941
- let command;
10942
- if (mockSocket) {
10943
- if (!fs.default.existsSync(mockSocket)) throw new Error(`Socket file does not exist: ${mockSocket}`);
10944
- command = `nc -U -w 10 "${mockSocket}" < "${requestFile}" > "${responseFile}"`;
10945
- } else if (mockHost && mockPort) command = `nc -w 10 "${mockHost}" ${mockPort} < "${requestFile}" > "${responseFile}"`;
10946
- else {
10947
- const socketPath = path.default.join(os.default.tmpdir(), "tusk-connect.sock");
10948
- if (!fs.default.existsSync(socketPath)) throw new Error(`Socket file does not exist: ${socketPath}`);
10949
- command = `nc -U -w 10 "${socketPath}" < "${requestFile}" > "${responseFile}"`;
10950
- }
12610
+ let connectionConfig;
12611
+ if (mockSocket) connectionConfig = {
12612
+ type: "unix",
12613
+ path: mockSocket
12614
+ };
12615
+ else if (mockHost && mockPort) connectionConfig = {
12616
+ type: "tcp",
12617
+ host: mockHost,
12618
+ port: parseInt(mockPort, 10)
12619
+ };
12620
+ else connectionConfig = {
12621
+ type: "unix",
12622
+ path: path.default.join(os.default.tmpdir(), "tusk-connect.sock")
12623
+ };
12624
+ fs.default.writeFileSync(scriptFile, `
12625
+ const net = require('net');
12626
+ const fs = require('fs');
12627
+
12628
+ const requestFile = process.argv[2];
12629
+ const responseFile = process.argv[3];
12630
+ const config = JSON.parse(process.argv[4]);
12631
+
12632
+ let responseReceived = false;
12633
+ let timeoutId;
12634
+
12635
+ function cleanup(exitCode) {
12636
+ if (timeoutId) clearTimeout(timeoutId);
12637
+ process.exit(exitCode);
12638
+ }
12639
+
12640
+ try {
12641
+ // Read the request data
12642
+ const requestData = fs.readFileSync(requestFile);
12643
+
12644
+ // Create connection based on config
12645
+ const client = config.type === 'unix'
12646
+ ? net.createConnection({ path: config.path })
12647
+ : net.createConnection({ host: config.host, port: config.port });
12648
+
12649
+ const incomingChunks = [];
12650
+ let incomingBuffer = Buffer.alloc(0);
12651
+
12652
+ // Set timeout
12653
+ timeoutId = setTimeout(() => {
12654
+ if (!responseReceived) {
12655
+ console.error('Timeout waiting for response');
12656
+ client.destroy();
12657
+ cleanup(1);
12658
+ }
12659
+ }, 10000);
12660
+
12661
+ client.on('connect', () => {
12662
+ // Send the request
12663
+ client.write(requestData);
12664
+ });
12665
+
12666
+ client.on('data', (data) => {
12667
+ incomingBuffer = Buffer.concat([incomingBuffer, data]);
12668
+
12669
+ // Try to parse complete message (4 byte length prefix + message)
12670
+ while (incomingBuffer.length >= 4) {
12671
+ const messageLength = incomingBuffer.readUInt32BE(0);
12672
+
12673
+ if (incomingBuffer.length < 4 + messageLength) {
12674
+ // Incomplete message, wait for more data
12675
+ break;
12676
+ }
12677
+
12678
+ // We have a complete message
12679
+ const messageData = incomingBuffer.slice(4, 4 + messageLength);
12680
+ incomingBuffer = incomingBuffer.slice(4 + messageLength);
12681
+
12682
+ // Write the complete response (including length prefix)
12683
+ const lengthPrefix = Buffer.allocUnsafe(4);
12684
+ lengthPrefix.writeUInt32BE(messageLength, 0);
12685
+ fs.writeFileSync(responseFile, Buffer.concat([lengthPrefix, messageData]));
12686
+
12687
+ responseReceived = true;
12688
+ client.destroy();
12689
+ cleanup(0);
12690
+ break;
12691
+ }
12692
+ });
12693
+
12694
+ client.on('error', (err) => {
12695
+ if (!responseReceived) {
12696
+ console.error('Connection error:', err.message);
12697
+ cleanup(1);
12698
+ }
12699
+ });
12700
+
12701
+ client.on('close', () => {
12702
+ if (!responseReceived) {
12703
+ console.error('Connection closed without response');
12704
+ cleanup(1);
12705
+ }
12706
+ });
12707
+
12708
+ } catch (err) {
12709
+ console.error('Script error:', err.message);
12710
+ cleanup(1);
12711
+ }
12712
+ `);
10951
12713
  try {
10952
- (0, child_process.execSync)(command, {
10953
- timeout: 1e4,
12714
+ (0, child_process.execSync)(`node "${scriptFile}" "${requestFile}" "${responseFile}" '${JSON.stringify(connectionConfig)}'`, {
12715
+ timeout: 12e3,
10954
12716
  stdio: "pipe"
10955
12717
  });
10956
12718
  const responseBuffer = fs.default.readFileSync(responseFile);
@@ -10975,22 +12737,27 @@ var ProtobufCommunicator = class {
10975
12737
  error: mockResponse.error || "Mock not found"
10976
12738
  };
10977
12739
  } catch (error) {
10978
- logger.error("[ProtobufCommunicator] error sending request to CLI:", error);
12740
+ logger.error("[ProtobufCommunicator] error in sync request child process:", error);
10979
12741
  throw error;
10980
12742
  }
10981
12743
  } catch (error) {
10982
12744
  throw new Error(`Sync request failed: ${error.message}`);
10983
12745
  } finally {
10984
12746
  try {
10985
- fs.default.unlinkSync(requestFile);
12747
+ if (fs.default.existsSync(requestFile)) fs.default.unlinkSync(requestFile);
10986
12748
  } catch (e) {
10987
12749
  logger.error("[ProtobufCommunicator] error cleaning up request file:", e);
10988
12750
  }
10989
12751
  try {
10990
- fs.default.unlinkSync(responseFile);
12752
+ if (fs.default.existsSync(responseFile)) fs.default.unlinkSync(responseFile);
10991
12753
  } catch (e) {
10992
12754
  logger.error("[ProtobufCommunicator] error cleaning up response file:", e);
10993
12755
  }
12756
+ try {
12757
+ if (fs.default.existsSync(scriptFile)) fs.default.unlinkSync(scriptFile);
12758
+ } catch (e) {
12759
+ logger.error("[ProtobufCommunicator] error cleaning up script file:", e);
12760
+ }
10994
12761
  }
10995
12762
  }
10996
12763
  async sendProtobufMessage(message) {
@@ -11158,7 +12925,8 @@ const TuskDriftInstrumentationModuleNames = [
11158
12925
  "jwks-rsa",
11159
12926
  "mysql2",
11160
12927
  "ioredis",
11161
- "@grpc/grpc-js"
12928
+ "@grpc/grpc-js",
12929
+ "@google-cloud/firestore"
11162
12930
  ];
11163
12931
 
11164
12932
  //#endregion
@@ -11280,6 +13048,10 @@ var TuskDriftCore = class TuskDriftCore {
11280
13048
  enabled: true,
11281
13049
  mode: this.mode
11282
13050
  });
13051
+ new FirestoreInstrumentation({
13052
+ enabled: true,
13053
+ mode: this.mode
13054
+ });
11283
13055
  new NextjsInstrumentation({
11284
13056
  enabled: true,
11285
13057
  mode: this.mode
@@ -11299,14 +13071,15 @@ var TuskDriftCore = class TuskDriftCore {
11299
13071
  sdkVersion: SDK_VERSION,
11300
13072
  sdkInstanceId: this.generateSdkInstanceId()
11301
13073
  });
11302
- const tracerProvider = new __opentelemetry_sdk_trace_node.NodeTracerProvider({ resource: new __opentelemetry_resources.Resource({ [__opentelemetry_semantic_conventions.ATTR_SERVICE_NAME]: serviceName }) });
11303
- tracerProvider.addSpanProcessor(new __opentelemetry_sdk_trace_node.BatchSpanProcessor(this.spanExporter, {
11304
- maxQueueSize: 2048,
11305
- maxExportBatchSize: 512,
11306
- scheduledDelayMillis: 2e3,
11307
- exportTimeoutMillis: 3e4
11308
- }));
11309
- tracerProvider.register();
13074
+ new __opentelemetry_sdk_trace_node.NodeTracerProvider({
13075
+ resource: new __opentelemetry_resources.Resource({ [__opentelemetry_semantic_conventions.ATTR_SERVICE_NAME]: serviceName }),
13076
+ spanProcessors: [new __opentelemetry_sdk_trace_node.BatchSpanProcessor(this.spanExporter, {
13077
+ maxQueueSize: 2048,
13078
+ maxExportBatchSize: 512,
13079
+ scheduledDelayMillis: 2e3,
13080
+ exportTimeoutMillis: 3e4
13081
+ })]
13082
+ }).register();
11310
13083
  logger.debug(`OpenTelemetry tracing initialized`);
11311
13084
  }
11312
13085
  generateSdkInstanceId() {
@@ -11452,6 +13225,10 @@ var TuskDriftCore = class TuskDriftCore {
11452
13225
  }
11453
13226
  }
11454
13227
  requestMockSync(mockRequest) {
13228
+ if (!this.isConnectedWithCLI) {
13229
+ logger.error("Requesting sync mock but CLI is not ready yet");
13230
+ throw new Error("Requesting sync mock but CLI is not ready yet");
13231
+ }
11455
13232
  const mockRequestCore = this.createMockRequestCore(mockRequest);
11456
13233
  if (mockRequestCore) return mockRequestCore;
11457
13234
  return this.requestMockFromCLISync(mockRequest);
@@ -11499,7 +13276,7 @@ var TuskDriftCore = class TuskDriftCore {
11499
13276
  return this.initParams;
11500
13277
  }
11501
13278
  getTracer() {
11502
- return __opentelemetry_api.trace.getTracer("tusk-drift-sdk", "1.0.0");
13279
+ return __opentelemetry_api.trace.getTracer(TD_INSTRUMENTATION_LIBRARY_NAME);
11503
13280
  }
11504
13281
  };
11505
13282
  var TuskDriftSDK = class {