@use-tusk/drift-node-sdk 0.1.11 → 0.1.13

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
@@ -276,15 +276,6 @@ var TdInstrumentationAbstract = class {
276
276
  }
277
277
  };
278
278
 
279
- //#endregion
280
- //#region package.json
281
- var version = "0.1.11";
282
-
283
- //#endregion
284
- //#region src/version.ts
285
- const SDK_VERSION = version;
286
- const MIN_CLI_VERSION = "0.1.0";
287
-
288
279
  //#endregion
289
280
  //#region src/core/utils/dataNormalizationUtils.ts
290
281
  /**
@@ -564,51 +555,40 @@ const logger = {
564
555
 
565
556
  //#endregion
566
557
  //#region src/core/analytics/analyticsUtils.ts
567
- function sendAnalyticsPayload(payload) {
568
- try {
569
- if (TuskDriftCore.getInstance().getConfig().recording?.enable_analytics) {}
570
- } catch (e) {
571
- logger.error("Error sending analytics event:", e);
572
- }
573
- }
574
- function sendTdAnalytics(eventName, properties = {}) {
575
- const serviceId = TuskDriftCore.getInstance().getConfig().service?.id || "unknown-service";
576
- const payload = {
577
- distinctId: `tusk-drift:${serviceId}`,
578
- event: `${eventName}`,
579
- properties: {
580
- serviceId,
581
- tdMode: TuskDriftCore.getInstance().getMode(),
582
- sdkVersion: SDK_VERSION,
583
- ...properties
584
- }
585
- };
586
- sendAnalyticsPayload(payload);
587
- }
588
558
  /**
589
- * NOTE: analytics has not been implemented yet, so this function does nothing
559
+ * Send version mismatch alert to CLI (only in REPLAY mode)
590
560
  */
591
561
  function sendVersionMismatchAlert({ moduleName, foundVersion, supportedVersions }) {
562
+ logger.info("Sending version mismatch alert", {
563
+ moduleName,
564
+ foundVersion,
565
+ supportedVersions
566
+ });
592
567
  try {
593
- sendTdAnalytics("version_mismatch", {
568
+ if (TuskDriftCore.getInstance().getMode() !== TuskDriftMode.REPLAY) return;
569
+ const protobufComm = TuskDriftCore.getInstance().getProtobufCommunicator();
570
+ if (protobufComm) protobufComm.sendInstrumentationVersionMismatchAlert({
594
571
  moduleName,
595
- foundVersion: foundVersion || "unknown",
596
- supportedVersions: supportedVersions.join(", ")
572
+ requestedVersion: foundVersion,
573
+ supportedVersions
597
574
  });
598
575
  } catch (e) {
599
576
  logger.error("Error sending version mismatch alert:", e);
600
577
  }
601
578
  }
602
579
  /**
603
- * NOTE: analytics has not been implemented yet, so this function does nothing
580
+ * Send unpatched dependency alert to CLI
604
581
  */
605
- function sendUnpatchedDependencyAlert({ method, spanId, traceId, stackTrace }) {
582
+ function sendUnpatchedDependencyAlert({ traceTestServerSpanId, stackTrace }) {
583
+ logger.info("Sending unpatched dependency alert", {
584
+ traceTestServerSpanId,
585
+ stackTrace
586
+ });
606
587
  try {
607
- sendTdAnalytics("unpatched_dependency", {
608
- method,
609
- spanId,
610
- traceId,
611
- stackTrace: stackTrace ? stackTrace.split("\n").slice(0, 10).join("\n") : void 0
588
+ const protobufComm = TuskDriftCore.getInstance().getProtobufCommunicator();
589
+ if (protobufComm && stackTrace) protobufComm.sendUnpatchedDependencyAlert({
590
+ stackTrace,
591
+ traceTestServerSpanId
612
592
  });
613
593
  } catch (e) {
614
594
  logger.error("Error sending unpatched dependency alert:", e);
@@ -2039,9 +2019,12 @@ var HttpReplayHooks = class {
2039
2019
  const traceIdHeader = req.headers["x-td-trace-id"] || req.headers["X-TD-TRACE-ID"];
2040
2020
  return traceIdHeader ? String(traceIdHeader) : null;
2041
2021
  }
2042
- extractEnvVarsFromHeaders(req) {
2043
- const envVarsHeader = req.headers["x-td-env-vars"] || req.headers["X-TD-ENV-VARS"];
2044
- return envVarsHeader ? JSON.parse(String(envVarsHeader)) : void 0;
2022
+ /**
2023
+ * Check if we should fetch env vars from CLI
2024
+ */
2025
+ extractShouldFetchEnvVars(req) {
2026
+ const fetchHeader = req.headers["x-td-fetch-env-vars"] || req.headers["X-TD-FETCH-ENV-VARS"];
2027
+ return fetchHeader === "true" || fetchHeader === true;
2045
2028
  }
2046
2029
  /**
2047
2030
  * Handle outbound HTTP requests in replay mode
@@ -2060,7 +2043,7 @@ var HttpReplayHooks = class {
2060
2043
  auth: requestOptions.auth || void 0,
2061
2044
  agent: requestOptions.agent || void 0,
2062
2045
  protocol,
2063
- hostname: requestOptions.hostname || void 0,
2046
+ hostname: requestOptions.hostname || requestOptions.host || void 0,
2064
2047
  port: requestOptions.port ? Number(requestOptions.port) : void 0,
2065
2048
  method
2066
2049
  };
@@ -2654,8 +2637,13 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
2654
2637
  return originalHandler.call(this);
2655
2638
  }
2656
2639
  logger.debug(`[HttpInstrumentation] Setting replay trace id`, replayTraceId);
2657
- const envVars = this.replayHooks.extractEnvVarsFromHeaders(req);
2658
- if (envVars) EnvVarTracker.setEnvVars(replayTraceId, envVars);
2640
+ if (this.replayHooks.extractShouldFetchEnvVars(req)) try {
2641
+ const envVars = this.tuskDrift.requestEnvVarsSync(replayTraceId);
2642
+ EnvVarTracker.setEnvVars(replayTraceId, envVars);
2643
+ logger.debug(`[HttpInstrumentation] Fetched env vars from CLI for trace ${replayTraceId}`);
2644
+ } catch (error) {
2645
+ logger.error(`[HttpInstrumentation] Failed to fetch env vars from CLI:`, error);
2646
+ }
2659
2647
  const ctxWithReplayTraceId = SpanUtils.setCurrentReplayTraceId(replayTraceId);
2660
2648
  if (!ctxWithReplayTraceId) throw new Error("Error setting current replay trace id");
2661
2649
  return __opentelemetry_api.context.with(ctxWithReplayTraceId, () => {
@@ -3029,13 +3017,29 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
3029
3017
  readable: res.readable
3030
3018
  };
3031
3019
  const responseChunks = [];
3032
- if (res.readable) {
3020
+ let streamConsumptionMode = "NOT_CONSUMING";
3021
+ const originalRead = res.read?.bind(res);
3022
+ if (originalRead) res.read = function read(size) {
3023
+ const chunk = originalRead(size);
3024
+ if (chunk && (streamConsumptionMode === "READ" || streamConsumptionMode === "NOT_CONSUMING")) {
3025
+ streamConsumptionMode = "READ";
3026
+ responseChunks.push(Buffer.from(chunk));
3027
+ }
3028
+ return chunk;
3029
+ };
3030
+ res.once("resume", () => {
3033
3031
  res.on("data", (chunk) => {
3034
- responseChunks.push(chunk);
3032
+ if (chunk && (streamConsumptionMode === "PIPE" || streamConsumptionMode === "NOT_CONSUMING")) {
3033
+ streamConsumptionMode = "PIPE";
3034
+ responseChunks.push(Buffer.from(chunk));
3035
+ }
3035
3036
  });
3036
- res.on("end", async () => {
3037
- if (responseChunks.length > 0) try {
3038
- const responseBuffer = combineChunks(responseChunks);
3037
+ });
3038
+ res.on("end", async (chunk) => {
3039
+ if (chunk && typeof chunk !== "function") responseChunks.push(Buffer.from(chunk));
3040
+ try {
3041
+ if (responseChunks.length > 0) {
3042
+ const responseBuffer = Buffer.concat(responseChunks);
3039
3043
  const rawHeaders = this._captureHeadersFromRawHeaders(res.rawHeaders);
3040
3044
  outputValue.headers = rawHeaders;
3041
3045
  const contentEncoding = rawHeaders["content-encoding"];
@@ -3044,40 +3048,24 @@ var HttpInstrumentation = class extends TdInstrumentationBase {
3044
3048
  contentEncoding
3045
3049
  });
3046
3050
  outputValue.bodySize = responseBuffer.length;
3047
- this._addOutputAttributesToSpan({
3048
- spanInfo,
3049
- outputValue,
3050
- statusCode: res.statusCode || 1,
3051
- outputSchemaMerges: {
3052
- body: {
3053
- encoding: __use_tusk_drift_schemas_core_json_schema.EncodingType.BASE64,
3054
- decodedType: getDecodedType(outputValue.headers["content-type"] || "")
3055
- },
3056
- headers: { matchImportance: 0 }
3057
- },
3058
- inputValue: completeInputValue
3059
- });
3060
- } catch (error) {
3061
- logger.error(`[HttpInstrumentation] Error processing response body:`, error);
3062
3051
  }
3063
- });
3064
- } else try {
3065
- this._addOutputAttributesToSpan({
3066
- spanInfo,
3067
- outputValue,
3068
- statusCode: res.statusCode || 1,
3069
- outputSchemaMerges: {
3070
- body: {
3071
- encoding: __use_tusk_drift_schemas_core_json_schema.EncodingType.BASE64,
3072
- decodedType: getDecodedType(outputValue.headers["content-type"] || "")
3052
+ this._addOutputAttributesToSpan({
3053
+ spanInfo,
3054
+ outputValue,
3055
+ statusCode: res.statusCode || 1,
3056
+ outputSchemaMerges: {
3057
+ body: {
3058
+ encoding: __use_tusk_drift_schemas_core_json_schema.EncodingType.BASE64,
3059
+ decodedType: getDecodedType(outputValue.headers["content-type"] || "")
3060
+ },
3061
+ headers: { matchImportance: 0 }
3073
3062
  },
3074
- headers: { matchImportance: 0 }
3075
- },
3076
- inputValue: completeInputValue
3077
- });
3078
- } catch (error) {
3079
- logger.error(`[HttpInstrumentation] Error adding output attributes to span:`, error);
3080
- }
3063
+ inputValue: completeInputValue
3064
+ });
3065
+ } catch (error) {
3066
+ logger.error(`[HttpInstrumentation] Error processing response body:`, error);
3067
+ }
3068
+ });
3081
3069
  });
3082
3070
  req.on("error", (error) => {
3083
3071
  try {
@@ -6189,12 +6177,13 @@ var TcpInstrumentation = class extends TdInstrumentationBase {
6189
6177
  traceId: currentSpanInfo.traceId,
6190
6178
  socketContext
6191
6179
  });
6192
- logger.warn(`[TcpInstrumentation] Full stack trace:\n${(/* @__PURE__ */ new Error()).stack}`);
6180
+ const stackTrace = (/* @__PURE__ */ new Error()).stack || "";
6181
+ const traceTestServerSpanId = SpanUtils.getCurrentReplayTraceId();
6182
+ logger.warn(`[TcpInstrumentation] Full stack trace:\n${stackTrace}`, { traceTestServerSpanId });
6193
6183
  Error.stackTraceLimit = 10;
6194
6184
  sendUnpatchedDependencyAlert({
6195
- method: methodName,
6196
- spanId: currentSpanInfo.spanId,
6197
- traceId: currentSpanInfo.traceId
6185
+ traceTestServerSpanId: traceTestServerSpanId || "",
6186
+ stackTrace
6198
6187
  });
6199
6188
  if (this.loggedSpans.size > 1e3) {
6200
6189
  logger.debug(`[TcpInstrumentation] Cleaning up logged spans cache (${this.loggedSpans.size} entries)`);
@@ -9633,8 +9622,13 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
9633
9622
  return originalHandleRequest.call(this, req, res, parsedUrl);
9634
9623
  }
9635
9624
  logger.debug(`[NextjsInstrumentation] Setting replay trace id`, replayTraceId);
9636
- const envVars = self.replayHooks.extractEnvVarsFromHeaders(req);
9637
- if (envVars) EnvVarTracker.setEnvVars(replayTraceId, envVars);
9625
+ if (self.replayHooks.extractShouldFetchEnvVars(req)) try {
9626
+ const envVars = self.tuskDrift.requestEnvVarsSync(replayTraceId);
9627
+ EnvVarTracker.setEnvVars(replayTraceId, envVars);
9628
+ logger.debug(`[NextjsInstrumentation] Fetched env vars from CLI for trace ${replayTraceId}`);
9629
+ } catch (error) {
9630
+ logger.error(`[NextjsInstrumentation] Failed to fetch env vars from CLI:`, error);
9631
+ }
9638
9632
  const ctxWithReplayTraceId = SpanUtils.setCurrentReplayTraceId(replayTraceId);
9639
9633
  if (!ctxWithReplayTraceId) throw new Error("Error setting current replay trace id");
9640
9634
  return __opentelemetry_api.context.with(ctxWithReplayTraceId, () => {
@@ -9940,6 +9934,239 @@ var NextjsInstrumentation = class extends TdInstrumentationBase {
9940
9934
  }
9941
9935
  };
9942
9936
 
9937
+ //#endregion
9938
+ //#region src/instrumentation/libraries/prisma/types.ts
9939
+ /**
9940
+ * Prisma error class names for proper error handling
9941
+ */
9942
+ let PrismaErrorClassName = /* @__PURE__ */ function(PrismaErrorClassName$1) {
9943
+ PrismaErrorClassName$1["PrismaClientKnownRequestError"] = "PrismaClientKnownRequestError";
9944
+ PrismaErrorClassName$1["PrismaClientUnknownRequestError"] = "PrismaClientUnknownRequestError";
9945
+ PrismaErrorClassName$1["PrismaClientInitializationError"] = "PrismaClientInitializationError";
9946
+ PrismaErrorClassName$1["PrismaClientValidationError"] = "PrismaClientValidationError";
9947
+ PrismaErrorClassName$1["PrismaClientRustPanicError"] = "PrismaClientRustPanicError";
9948
+ PrismaErrorClassName$1["NotFoundError"] = "NotFoundError";
9949
+ return PrismaErrorClassName$1;
9950
+ }({});
9951
+
9952
+ //#endregion
9953
+ //#region src/instrumentation/libraries/prisma/Instrumentation.ts
9954
+ var PrismaInstrumentation = class extends TdInstrumentationBase {
9955
+ constructor(config = {}) {
9956
+ super("@prisma/client", config);
9957
+ this.INSTRUMENTATION_NAME = "PrismaInstrumentation";
9958
+ this.prismaErrorClasses = [];
9959
+ this.mode = config.mode || TuskDriftMode.DISABLED;
9960
+ this.tuskDrift = TuskDriftCore.getInstance();
9961
+ }
9962
+ init() {
9963
+ return [new TdInstrumentationNodeModule({
9964
+ name: "@prisma/client",
9965
+ supportedVersions: ["5.*", "6.*"],
9966
+ patch: (moduleExports) => this._patchPrismaModule(moduleExports)
9967
+ })];
9968
+ }
9969
+ _patchPrismaModule(prismaModule) {
9970
+ if (this.isModulePatched(prismaModule)) {
9971
+ logger.debug(`[PrismaInstrumentation] Prisma module already patched, skipping`);
9972
+ return prismaModule;
9973
+ }
9974
+ this._storePrismaErrorClasses(prismaModule);
9975
+ logger.debug(`[PrismaInstrumentation] Wrapping PrismaClient constructor`);
9976
+ this._wrap(prismaModule, "PrismaClient", (OriginalPrismaClient) => {
9977
+ const self = this;
9978
+ logger.debug(`[PrismaInstrumentation] PrismaClient wrapper called`);
9979
+ return class TdPrismaClient {
9980
+ constructor(...args) {
9981
+ logger.debug(`[PrismaInstrumentation] Creating patched PrismaClient instance`);
9982
+ return new OriginalPrismaClient(...args).$extends({ query: { async $allOperations({ model, operation, args: operationArgs, query }) {
9983
+ logger.debug(`[PrismaInstrumentation] $allOperations intercepted: ${model}.${operation}`);
9984
+ return self._handlePrismaOperation({
9985
+ model,
9986
+ operation,
9987
+ args: operationArgs,
9988
+ query
9989
+ });
9990
+ } } });
9991
+ }
9992
+ };
9993
+ });
9994
+ this.markModuleAsPatched(prismaModule);
9995
+ logger.debug(`[PrismaInstrumentation] Prisma module patching complete`);
9996
+ return prismaModule;
9997
+ }
9998
+ _storePrismaErrorClasses(moduleExports) {
9999
+ const prismaNamespace = moduleExports.Prisma || {};
10000
+ this.prismaErrorClasses = [
10001
+ {
10002
+ name: PrismaErrorClassName.PrismaClientKnownRequestError,
10003
+ errorClass: moduleExports.PrismaClientKnownRequestError || prismaNamespace.PrismaClientKnownRequestError
10004
+ },
10005
+ {
10006
+ name: PrismaErrorClassName.PrismaClientUnknownRequestError,
10007
+ errorClass: moduleExports.PrismaClientUnknownRequestError || prismaNamespace.PrismaClientUnknownRequestError
10008
+ },
10009
+ {
10010
+ name: PrismaErrorClassName.PrismaClientInitializationError,
10011
+ errorClass: moduleExports.PrismaClientInitializationError || prismaNamespace.PrismaClientInitializationError
10012
+ },
10013
+ {
10014
+ name: PrismaErrorClassName.PrismaClientValidationError,
10015
+ errorClass: moduleExports.PrismaClientValidationError || prismaNamespace.PrismaClientValidationError
10016
+ },
10017
+ {
10018
+ name: PrismaErrorClassName.PrismaClientRustPanicError,
10019
+ errorClass: moduleExports.PrismaClientRustPanicError || prismaNamespace.PrismaClientRustPanicError
10020
+ },
10021
+ {
10022
+ name: PrismaErrorClassName.NotFoundError,
10023
+ errorClass: moduleExports.NotFoundError || prismaNamespace.NotFoundError
10024
+ }
10025
+ ];
10026
+ }
10027
+ _handlePrismaOperation({ model, operation, args, query }) {
10028
+ const inputValue = {
10029
+ model,
10030
+ operation,
10031
+ args
10032
+ };
10033
+ logger.debug(`[PrismaInstrumentation] Intercepted Prisma operation: ${model}.${operation} in ${this.mode} mode`);
10034
+ if (this.mode === TuskDriftMode.RECORD) return handleRecordMode({
10035
+ originalFunctionCall: () => query(args),
10036
+ recordModeHandler: ({ isPreAppStart }) => {
10037
+ return SpanUtils.createAndExecuteSpan(this.mode, () => query(args), {
10038
+ name: `prisma.${operation}`,
10039
+ kind: __opentelemetry_api.SpanKind.CLIENT,
10040
+ submodule: model,
10041
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.UNSPECIFIED,
10042
+ packageName: "@prisma/client",
10043
+ instrumentationName: this.INSTRUMENTATION_NAME,
10044
+ inputValue,
10045
+ isPreAppStart
10046
+ }, (spanInfo) => {
10047
+ return this._handleRecordPrismaOperation(spanInfo, query, args);
10048
+ });
10049
+ },
10050
+ spanKind: __opentelemetry_api.SpanKind.CLIENT
10051
+ });
10052
+ else if (this.mode === TuskDriftMode.REPLAY) {
10053
+ const stackTrace = captureStackTrace(["PrismaInstrumentation"]);
10054
+ return handleReplayMode({
10055
+ noOpRequestHandler: () => query(args),
10056
+ isServerRequest: false,
10057
+ replayModeHandler: () => {
10058
+ return SpanUtils.createAndExecuteSpan(this.mode, () => query(args), {
10059
+ name: `prisma.${operation}`,
10060
+ kind: __opentelemetry_api.SpanKind.CLIENT,
10061
+ submodule: model,
10062
+ packageType: __use_tusk_drift_schemas_core_span.PackageType.UNSPECIFIED,
10063
+ packageName: "@prisma/client",
10064
+ instrumentationName: this.INSTRUMENTATION_NAME,
10065
+ inputValue,
10066
+ isPreAppStart: false
10067
+ }, (spanInfo) => {
10068
+ return this._handleReplayPrismaOperation(spanInfo, inputValue, stackTrace);
10069
+ });
10070
+ }
10071
+ });
10072
+ } else return query(args);
10073
+ }
10074
+ async _handleRecordPrismaOperation(spanInfo, query, args) {
10075
+ try {
10076
+ logger.debug(`[PrismaInstrumentation] Recording Prisma operation`);
10077
+ const result = await query(args);
10078
+ const outputValue = {
10079
+ prismaResult: result,
10080
+ _tdOriginalFormat: "result"
10081
+ };
10082
+ try {
10083
+ SpanUtils.addSpanAttributes(spanInfo.span, { outputValue });
10084
+ SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
10085
+ } catch (spanError) {
10086
+ logger.error(`[PrismaInstrumentation] error adding span attributes:`, spanError);
10087
+ }
10088
+ return result;
10089
+ } catch (error) {
10090
+ logger.debug(`[PrismaInstrumentation] Prisma operation error: ${error.message}`);
10091
+ try {
10092
+ const errorClassName = this._getPrismaErrorClassName(error);
10093
+ const errorWithClassName = this._cloneError(error);
10094
+ if (errorClassName) errorWithClassName.customTdName = errorClassName;
10095
+ const outputValue = {
10096
+ prismaResult: errorWithClassName,
10097
+ _tdOriginalFormat: "error"
10098
+ };
10099
+ SpanUtils.addSpanAttributes(spanInfo.span, { outputValue });
10100
+ SpanUtils.endSpan(spanInfo.span, {
10101
+ code: __opentelemetry_api.SpanStatusCode.ERROR,
10102
+ message: error.message
10103
+ });
10104
+ } catch (spanError) {
10105
+ logger.error(`[PrismaInstrumentation] error extracting error and adding span attributes:`, spanError);
10106
+ }
10107
+ throw error;
10108
+ }
10109
+ }
10110
+ async _handleReplayPrismaOperation(spanInfo, inputValue, stackTrace) {
10111
+ const mockData = await findMockResponseAsync({
10112
+ mockRequestData: {
10113
+ traceId: spanInfo.traceId,
10114
+ spanId: spanInfo.spanId,
10115
+ name: `prisma.${inputValue.operation}`,
10116
+ inputValue,
10117
+ packageName: "@prisma/client",
10118
+ instrumentationName: this.INSTRUMENTATION_NAME,
10119
+ submoduleName: inputValue.model,
10120
+ kind: __opentelemetry_api.SpanKind.CLIENT,
10121
+ stackTrace
10122
+ },
10123
+ tuskDrift: this.tuskDrift
10124
+ });
10125
+ if (!mockData) {
10126
+ logger.warn(`[PrismaInstrumentation] No mock data found for Prisma operation: ${inputValue.model}.${inputValue.operation}`);
10127
+ throw new Error(`[PrismaInstrumentation] No matching mock found for Prisma operation: ${inputValue.model}.${inputValue.operation}`);
10128
+ }
10129
+ logger.debug(`[PrismaInstrumentation] Found mock data for Prisma operation: ${inputValue.model}.${inputValue.operation}`);
10130
+ const outputValue = mockData.result;
10131
+ if (outputValue._tdOriginalFormat === "error") {
10132
+ const errorObj = outputValue.prismaResult;
10133
+ if (errorObj.customTdName) {
10134
+ const errorClass = this._getPrismaErrorClassFromName(errorObj.customTdName);
10135
+ if (errorClass) Object.setPrototypeOf(errorObj, errorClass.prototype);
10136
+ }
10137
+ SpanUtils.endSpan(spanInfo.span, {
10138
+ code: __opentelemetry_api.SpanStatusCode.ERROR,
10139
+ message: errorObj.message || "Prisma error"
10140
+ });
10141
+ throw errorObj;
10142
+ }
10143
+ SpanUtils.endSpan(spanInfo.span, { code: __opentelemetry_api.SpanStatusCode.OK });
10144
+ return outputValue.prismaResult;
10145
+ }
10146
+ _getPrismaErrorClassName(error) {
10147
+ for (const errorInfo of this.prismaErrorClasses) if (error instanceof errorInfo.errorClass) return errorInfo.name;
10148
+ }
10149
+ _getPrismaErrorClassFromName(className) {
10150
+ for (const errorInfo of this.prismaErrorClasses) if (errorInfo.name === className) return errorInfo.errorClass;
10151
+ return null;
10152
+ }
10153
+ /**
10154
+ * Deep clone an error object to make it serializable
10155
+ */
10156
+ _cloneError(error) {
10157
+ const cloned = new Error(error.message);
10158
+ cloned.name = error.name;
10159
+ cloned.stack = error.stack;
10160
+ for (const key in error) if (error.hasOwnProperty(key)) try {
10161
+ cloned[key] = error[key];
10162
+ } catch (e) {}
10163
+ return cloned;
10164
+ }
10165
+ _wrap(target, propertyName, wrapper) {
10166
+ wrap(target, propertyName, wrapper);
10167
+ }
10168
+ };
10169
+
9943
10170
  //#endregion
9944
10171
  //#region node_modules/@opentelemetry/core/build/src/trace/suppress-tracing.js
9945
10172
  var require_suppress_tracing = /* @__PURE__ */ __commonJS({ "node_modules/@opentelemetry/core/build/src/trace/suppress-tracing.js": ((exports) => {
@@ -12440,9 +12667,18 @@ var TdSpanExporter = class {
12440
12667
  }
12441
12668
  };
12442
12669
 
12670
+ //#endregion
12671
+ //#region package.json
12672
+ var version = "0.1.13";
12673
+
12674
+ //#endregion
12675
+ //#region src/version.ts
12676
+ const SDK_VERSION = version;
12677
+ const MIN_CLI_VERSION = "0.1.0";
12678
+
12443
12679
  //#endregion
12444
12680
  //#region src/core/ProtobufCommunicator.ts
12445
- var ProtobufCommunicator = class {
12681
+ var ProtobufCommunicator = class ProtobufCommunicator {
12446
12682
  constructor() {
12447
12683
  this.client = null;
12448
12684
  this.pendingRequests = /* @__PURE__ */ new Map();
@@ -12540,43 +12776,18 @@ var ProtobufCommunicator = class {
12540
12776
  });
12541
12777
  }
12542
12778
  /**
12543
- * This function uses a separate Node.js child process to communicate with the CLI over a socket.
12544
- * The child process creates its own connection and event loop, allowing proper async socket handling.
12545
- * The parent process blocks synchronously waiting for the child to complete.
12546
- *
12547
- * Since this function blocks the main thread, there is a performance impact. We should use requestMockAsync whenever possible and only use this function
12548
- * for instrumentations that require fetching mocks synchronously.
12779
+ * Generic synchronous request handler that spawns a child process.
12780
+ * @param sdkMessage The SDK message to send
12781
+ * @param filePrefix Prefix for temporary files (e.g., 'envvar', 'mock')
12782
+ * @param responseHandler Function to extract and return the desired response
12549
12783
  */
12550
- requestMockSync(mockRequest) {
12551
- const requestId = this.generateRequestId();
12552
- const cleanSpan = mockRequest.outboundSpan ? this.cleanSpan(mockRequest.outboundSpan) : void 0;
12553
- if (cleanSpan?.inputValue) cleanSpan.inputValue = objectToProtobufStruct(cleanSpan.inputValue);
12554
- if (cleanSpan?.inputSchema) cleanSpan.inputSchema = objectToProtobufStruct(cleanSpan.inputSchema);
12555
- if (cleanSpan?.kind) cleanSpan.kind = mapOtToPb(cleanSpan.kind);
12556
- const protoMockRequest = __use_tusk_drift_schemas_core_communication.GetMockRequest.create({
12557
- ...mockRequest,
12558
- requestId,
12559
- tags: {},
12560
- outboundSpan: cleanSpan,
12561
- stackTrace: cleanSpan?.stackTrace
12562
- });
12563
- const sdkMessage = __use_tusk_drift_schemas_core_communication.SDKMessage.create({
12564
- type: __use_tusk_drift_schemas_core_communication.MessageType.MOCK_REQUEST,
12565
- requestId,
12566
- payload: {
12567
- oneofKind: "getMockRequest",
12568
- getMockRequest: protoMockRequest
12569
- }
12570
- });
12571
- logger.debug("Sending protobuf request to CLI (sync)", {
12572
- outboundSpan: mockRequest.outboundSpan,
12573
- testId: mockRequest.testId
12574
- });
12784
+ executeSyncRequest(sdkMessage, filePrefix, responseHandler) {
12785
+ const requestId = sdkMessage.requestId;
12575
12786
  const messageBytes = __use_tusk_drift_schemas_core_communication.SDKMessage.toBinary(sdkMessage);
12576
12787
  const tempDir = os.default.tmpdir();
12577
- const requestFile = path.default.join(tempDir, `tusk-sync-request-${requestId}.bin`);
12578
- const responseFile = path.default.join(tempDir, `tusk-sync-response-${requestId}.bin`);
12579
- const scriptFile = path.default.join(tempDir, `tusk-sync-script-${requestId}.js`);
12788
+ const requestFile = path.default.join(tempDir, `tusk-sync-${filePrefix}-request-${requestId}.bin`);
12789
+ const responseFile = path.default.join(tempDir, `tusk-sync-${filePrefix}-response-${requestId}.bin`);
12790
+ const scriptFile = path.default.join(tempDir, `tusk-sync-${filePrefix}-script-${requestId}.js`);
12580
12791
  try {
12581
12792
  const lengthBuffer = Buffer.allocUnsafe(4);
12582
12793
  lengthBuffer.writeUInt32BE(messageBytes.length, 0);
@@ -12599,95 +12810,7 @@ var ProtobufCommunicator = class {
12599
12810
  type: "unix",
12600
12811
  path: path.default.join(os.default.tmpdir(), "tusk-connect.sock")
12601
12812
  };
12602
- fs.default.writeFileSync(scriptFile, `
12603
- const net = require('net');
12604
- const fs = require('fs');
12605
-
12606
- const requestFile = process.argv[2];
12607
- const responseFile = process.argv[3];
12608
- const config = JSON.parse(process.argv[4]);
12609
-
12610
- let responseReceived = false;
12611
- let timeoutId;
12612
-
12613
- function cleanup(exitCode) {
12614
- if (timeoutId) clearTimeout(timeoutId);
12615
- process.exit(exitCode);
12616
- }
12617
-
12618
- try {
12619
- // Read the request data
12620
- const requestData = fs.readFileSync(requestFile);
12621
-
12622
- // Create connection based on config
12623
- const client = config.type === 'unix'
12624
- ? net.createConnection({ path: config.path })
12625
- : net.createConnection({ host: config.host, port: config.port });
12626
-
12627
- const incomingChunks = [];
12628
- let incomingBuffer = Buffer.alloc(0);
12629
-
12630
- // Set timeout
12631
- timeoutId = setTimeout(() => {
12632
- if (!responseReceived) {
12633
- console.error('Timeout waiting for response');
12634
- client.destroy();
12635
- cleanup(1);
12636
- }
12637
- }, 10000);
12638
-
12639
- client.on('connect', () => {
12640
- // Send the request
12641
- client.write(requestData);
12642
- });
12643
-
12644
- client.on('data', (data) => {
12645
- incomingBuffer = Buffer.concat([incomingBuffer, data]);
12646
-
12647
- // Try to parse complete message (4 byte length prefix + message)
12648
- while (incomingBuffer.length >= 4) {
12649
- const messageLength = incomingBuffer.readUInt32BE(0);
12650
-
12651
- if (incomingBuffer.length < 4 + messageLength) {
12652
- // Incomplete message, wait for more data
12653
- break;
12654
- }
12655
-
12656
- // We have a complete message
12657
- const messageData = incomingBuffer.slice(4, 4 + messageLength);
12658
- incomingBuffer = incomingBuffer.slice(4 + messageLength);
12659
-
12660
- // Write the complete response (including length prefix)
12661
- const lengthPrefix = Buffer.allocUnsafe(4);
12662
- lengthPrefix.writeUInt32BE(messageLength, 0);
12663
- fs.writeFileSync(responseFile, Buffer.concat([lengthPrefix, messageData]));
12664
-
12665
- responseReceived = true;
12666
- client.destroy();
12667
- cleanup(0);
12668
- break;
12669
- }
12670
- });
12671
-
12672
- client.on('error', (err) => {
12673
- if (!responseReceived) {
12674
- console.error('Connection error:', err.message);
12675
- cleanup(1);
12676
- }
12677
- });
12678
-
12679
- client.on('close', () => {
12680
- if (!responseReceived) {
12681
- console.error('Connection closed without response');
12682
- cleanup(1);
12683
- }
12684
- });
12685
-
12686
- } catch (err) {
12687
- console.error('Script error:', err.message);
12688
- cleanup(1);
12689
- }
12690
- `);
12813
+ fs.default.writeFileSync(scriptFile, ProtobufCommunicator.SYNC_CHILD_SCRIPT);
12691
12814
  try {
12692
12815
  (0, child_process.execSync)(`node "${scriptFile}" "${requestFile}" "${responseFile}" '${JSON.stringify(connectionConfig)}'`, {
12693
12816
  timeout: 12e3,
@@ -12699,27 +12822,13 @@ try {
12699
12822
  if (responseBuffer.length < 4 + responseLength) throw new Error("Invalid response: incomplete message");
12700
12823
  const responseData = responseBuffer.slice(4, 4 + responseLength);
12701
12824
  const cliMessage = __use_tusk_drift_schemas_core_communication.CLIMessage.fromBinary(responseData);
12702
- if (cliMessage.payload.oneofKind !== "getMockResponse") throw new Error(`Unexpected response type: ${cliMessage.type}`);
12703
- const mockResponse = cliMessage.payload.getMockResponse;
12704
- if (!mockResponse) throw new Error("No mock response received");
12705
- if (mockResponse.found) try {
12706
- return {
12707
- found: true,
12708
- response: this.extractResponseData(mockResponse)
12709
- };
12710
- } catch (error) {
12711
- throw new Error(`Failed to extract response data: ${error}`);
12712
- }
12713
- else return {
12714
- found: false,
12715
- error: mockResponse.error || "Mock not found"
12716
- };
12825
+ return responseHandler(cliMessage);
12717
12826
  } catch (error) {
12718
- logger.error("[ProtobufCommunicator] error in sync request child process:", error);
12827
+ logger.error(`[ProtobufCommunicator] error in sync ${filePrefix} request child process:`, error);
12719
12828
  throw error;
12720
12829
  }
12721
12830
  } catch (error) {
12722
- throw new Error(`Sync request failed: ${error.message}`);
12831
+ throw new Error(`Sync ${filePrefix} request failed: ${error.message}`);
12723
12832
  } finally {
12724
12833
  try {
12725
12834
  if (fs.default.existsSync(requestFile)) fs.default.unlinkSync(requestFile);
@@ -12738,6 +12847,86 @@ try {
12738
12847
  }
12739
12848
  }
12740
12849
  }
12850
+ /**
12851
+ * Request environment variables from CLI synchronously using a child process.
12852
+ * This blocks the main thread, so it should be used carefully.
12853
+ * Similar to requestMockSync but for environment variables.
12854
+ */
12855
+ requestEnvVarsSync(traceTestServerSpanId) {
12856
+ const requestId = this.generateRequestId();
12857
+ const envVarRequest = __use_tusk_drift_schemas_core_communication.EnvVarRequest.create({ traceTestServerSpanId });
12858
+ const sdkMessage = __use_tusk_drift_schemas_core_communication.SDKMessage.create({
12859
+ type: __use_tusk_drift_schemas_core_communication.MessageType.ENV_VAR_REQUEST,
12860
+ requestId,
12861
+ payload: {
12862
+ oneofKind: "envVarRequest",
12863
+ envVarRequest
12864
+ }
12865
+ });
12866
+ logger.debug(`[ProtobufCommunicator] Requesting env vars (sync) for trace: ${traceTestServerSpanId}`);
12867
+ return this.executeSyncRequest(sdkMessage, "envvar", (cliMessage) => {
12868
+ if (cliMessage.payload.oneofKind !== "envVarResponse") throw new Error(`Unexpected response type: ${cliMessage.type}`);
12869
+ const envVarResponse = cliMessage.payload.envVarResponse;
12870
+ if (!envVarResponse) throw new Error("No env var response received");
12871
+ const envVars = {};
12872
+ if (envVarResponse.envVars) Object.entries(envVarResponse.envVars).forEach(([key, value]) => {
12873
+ envVars[key] = value;
12874
+ });
12875
+ logger.debug(`[ProtobufCommunicator] Received env vars (sync), count: ${Object.keys(envVars).length}`);
12876
+ return envVars;
12877
+ });
12878
+ }
12879
+ /**
12880
+ * This function uses a separate Node.js child process to communicate with the CLI over a socket.
12881
+ * The child process creates its own connection and event loop, allowing proper async socket handling.
12882
+ * The parent process blocks synchronously waiting for the child to complete.
12883
+ *
12884
+ * Since this function blocks the main thread, there is a performance impact. We should use requestMockAsync whenever possible and only use this function
12885
+ * for instrumentations that require fetching mocks synchronously.
12886
+ */
12887
+ requestMockSync(mockRequest) {
12888
+ const requestId = this.generateRequestId();
12889
+ const cleanSpan = mockRequest.outboundSpan ? this.cleanSpan(mockRequest.outboundSpan) : void 0;
12890
+ if (cleanSpan?.inputValue) cleanSpan.inputValue = objectToProtobufStruct(cleanSpan.inputValue);
12891
+ if (cleanSpan?.inputSchema) cleanSpan.inputSchema = objectToProtobufStruct(cleanSpan.inputSchema);
12892
+ if (cleanSpan?.kind) cleanSpan.kind = mapOtToPb(cleanSpan.kind);
12893
+ const protoMockRequest = __use_tusk_drift_schemas_core_communication.GetMockRequest.create({
12894
+ ...mockRequest,
12895
+ requestId,
12896
+ tags: {},
12897
+ outboundSpan: cleanSpan,
12898
+ stackTrace: cleanSpan?.stackTrace
12899
+ });
12900
+ const sdkMessage = __use_tusk_drift_schemas_core_communication.SDKMessage.create({
12901
+ type: __use_tusk_drift_schemas_core_communication.MessageType.MOCK_REQUEST,
12902
+ requestId,
12903
+ payload: {
12904
+ oneofKind: "getMockRequest",
12905
+ getMockRequest: protoMockRequest
12906
+ }
12907
+ });
12908
+ logger.debug("Sending protobuf request to CLI (sync)", {
12909
+ outboundSpan: mockRequest.outboundSpan,
12910
+ testId: mockRequest.testId
12911
+ });
12912
+ return this.executeSyncRequest(sdkMessage, "mock", (cliMessage) => {
12913
+ if (cliMessage.payload.oneofKind !== "getMockResponse") throw new Error(`Unexpected response type: ${cliMessage.type}`);
12914
+ const mockResponse = cliMessage.payload.getMockResponse;
12915
+ if (!mockResponse) throw new Error("No mock response received");
12916
+ if (mockResponse.found) try {
12917
+ return {
12918
+ found: true,
12919
+ response: this.extractResponseData(mockResponse)
12920
+ };
12921
+ } catch (error) {
12922
+ throw new Error(`Failed to extract response data: ${error}`);
12923
+ }
12924
+ else return {
12925
+ found: false,
12926
+ error: mockResponse.error || "Mock not found"
12927
+ };
12928
+ });
12929
+ }
12741
12930
  async sendProtobufMessage(message) {
12742
12931
  if (!this.client || !this.protobufContext) throw new Error("Not connected to CLI");
12743
12932
  const messageBytes = __use_tusk_drift_schemas_core_communication.SDKMessage.toBinary(message);
@@ -12790,6 +12979,58 @@ try {
12790
12979
  });
12791
12980
  await this.sendProtobufMessage(sdkMessage);
12792
12981
  }
12982
+ /**
12983
+ * Send an alert to the CLI (fire-and-forget, no response expected)
12984
+ */
12985
+ async sendAlert(alert) {
12986
+ if (!this.client || !this.protobufContext) {
12987
+ logger.debug("[ProtobufCommunicator] Not connected to CLI, skipping alert");
12988
+ return;
12989
+ }
12990
+ const sdkMessage = __use_tusk_drift_schemas_core_communication.SDKMessage.create({
12991
+ type: __use_tusk_drift_schemas_core_communication.MessageType.ALERT,
12992
+ requestId: this.generateRequestId(),
12993
+ payload: {
12994
+ oneofKind: "sendAlertRequest",
12995
+ sendAlertRequest: alert
12996
+ }
12997
+ });
12998
+ try {
12999
+ await this.sendProtobufMessage(sdkMessage);
13000
+ logger.debug("[ProtobufCommunicator] Alert sent to CLI");
13001
+ } catch (error) {
13002
+ logger.debug("[ProtobufCommunicator] Failed to send alert to CLI:", error);
13003
+ }
13004
+ }
13005
+ /**
13006
+ * Send instrumentation version mismatch alert to CLI
13007
+ */
13008
+ async sendInstrumentationVersionMismatchAlert(params) {
13009
+ const alert = __use_tusk_drift_schemas_core_communication.SendAlertRequest.create({ alert: {
13010
+ oneofKind: "versionMismatch",
13011
+ versionMismatch: __use_tusk_drift_schemas_core_communication.InstrumentationVersionMismatchAlert.create({
13012
+ moduleName: params.moduleName,
13013
+ requestedVersion: params.requestedVersion || "",
13014
+ supportedVersions: params.supportedVersions,
13015
+ sdkVersion: SDK_VERSION
13016
+ })
13017
+ } });
13018
+ await this.sendAlert(alert);
13019
+ }
13020
+ /**
13021
+ * Send unpatched dependency alert to CLI
13022
+ */
13023
+ async sendUnpatchedDependencyAlert(params) {
13024
+ const alert = __use_tusk_drift_schemas_core_communication.SendAlertRequest.create({ alert: {
13025
+ oneofKind: "unpatchedDependency",
13026
+ unpatchedDependency: __use_tusk_drift_schemas_core_communication.UnpatchedDependencyAlert.create({
13027
+ stackTrace: params.stackTrace,
13028
+ traceTestServerSpanId: params.traceTestServerSpanId,
13029
+ sdkVersion: SDK_VERSION
13030
+ })
13031
+ } });
13032
+ await this.sendAlert(alert);
13033
+ }
12793
13034
  handleIncomingData(data) {
12794
13035
  this.incomingBuffer = Buffer.concat([this.incomingBuffer, data]);
12795
13036
  logger.debug(`[ProtobufCommunicator] Processing buffer, length: ${this.incomingBuffer.length}`);
@@ -12847,6 +13088,22 @@ try {
12847
13088
  error: mockResponse.error || "Mock not found"
12848
13089
  });
12849
13090
  }
13091
+ if (message.payload.oneofKind === "envVarResponse") {
13092
+ const envVarResponse = message.payload.envVarResponse;
13093
+ logger.debug(`[ProtobufCommunicator] Received env var response for requestId: ${requestId}`);
13094
+ const pendingRequest = this.pendingRequests.get(requestId);
13095
+ if (!pendingRequest) {
13096
+ logger.warn("[ProtobufCommunicator] received env var response for unknown request:", requestId);
13097
+ return;
13098
+ }
13099
+ this.pendingRequests.delete(requestId);
13100
+ const envVars = {};
13101
+ if (envVarResponse?.envVars) Object.entries(envVarResponse.envVars).forEach(([key, value]) => {
13102
+ envVars[key] = value;
13103
+ });
13104
+ pendingRequest.resolve(envVars);
13105
+ return;
13106
+ }
12850
13107
  }
12851
13108
  /**
12852
13109
  * Extract response data from MockResponse
@@ -12889,6 +13146,95 @@ try {
12889
13146
  }
12890
13147
  }
12891
13148
  };
13149
+ ProtobufCommunicator.SYNC_CHILD_SCRIPT = `
13150
+ const net = require('net');
13151
+ const fs = require('fs');
13152
+
13153
+ const requestFile = process.argv[2];
13154
+ const responseFile = process.argv[3];
13155
+ const config = JSON.parse(process.argv[4]);
13156
+
13157
+ let responseReceived = false;
13158
+ let timeoutId;
13159
+
13160
+ function cleanup(exitCode) {
13161
+ if (timeoutId) clearTimeout(timeoutId);
13162
+ process.exit(exitCode);
13163
+ }
13164
+
13165
+ try {
13166
+ // Read the request data
13167
+ const requestData = fs.readFileSync(requestFile);
13168
+
13169
+ // Create connection based on config
13170
+ const client = config.type === 'unix'
13171
+ ? net.createConnection({ path: config.path })
13172
+ : net.createConnection({ host: config.host, port: config.port });
13173
+
13174
+ const incomingChunks = [];
13175
+ let incomingBuffer = Buffer.alloc(0);
13176
+
13177
+ // Set timeout
13178
+ timeoutId = setTimeout(() => {
13179
+ if (!responseReceived) {
13180
+ console.error('Timeout waiting for response');
13181
+ client.destroy();
13182
+ cleanup(1);
13183
+ }
13184
+ }, 10000);
13185
+
13186
+ client.on('connect', () => {
13187
+ // Send the request
13188
+ client.write(requestData);
13189
+ });
13190
+
13191
+ client.on('data', (data) => {
13192
+ incomingBuffer = Buffer.concat([incomingBuffer, data]);
13193
+
13194
+ // Try to parse complete message (4 byte length prefix + message)
13195
+ while (incomingBuffer.length >= 4) {
13196
+ const messageLength = incomingBuffer.readUInt32BE(0);
13197
+
13198
+ if (incomingBuffer.length < 4 + messageLength) {
13199
+ // Incomplete message, wait for more data
13200
+ break;
13201
+ }
13202
+
13203
+ // We have a complete message
13204
+ const messageData = incomingBuffer.slice(4, 4 + messageLength);
13205
+ incomingBuffer = incomingBuffer.slice(4 + messageLength);
13206
+
13207
+ // Write the complete response (including length prefix)
13208
+ const lengthPrefix = Buffer.allocUnsafe(4);
13209
+ lengthPrefix.writeUInt32BE(messageLength, 0);
13210
+ fs.writeFileSync(responseFile, Buffer.concat([lengthPrefix, messageData]));
13211
+
13212
+ responseReceived = true;
13213
+ client.destroy();
13214
+ cleanup(0);
13215
+ break;
13216
+ }
13217
+ });
13218
+
13219
+ client.on('error', (err) => {
13220
+ if (!responseReceived) {
13221
+ console.error('Connection error:', err.message);
13222
+ cleanup(1);
13223
+ }
13224
+ });
13225
+
13226
+ client.on('close', () => {
13227
+ if (!responseReceived) {
13228
+ console.error('Connection closed without response');
13229
+ cleanup(1);
13230
+ }
13231
+ });
13232
+
13233
+ } catch (err) {
13234
+ console.error('Script error:', err.message);
13235
+ cleanup(1);
13236
+ }
13237
+ `;
12892
13238
 
12893
13239
  //#endregion
12894
13240
  //#region src/core/TuskDriftInstrumentationModuleNames.ts
@@ -13069,6 +13415,10 @@ var TuskDriftCore = class TuskDriftCore {
13069
13415
  enabled: true,
13070
13416
  mode: this.mode
13071
13417
  });
13418
+ new PrismaInstrumentation({
13419
+ enabled: true,
13420
+ mode: this.mode
13421
+ });
13072
13422
  }
13073
13423
  initializeTracing({ baseDirectory }) {
13074
13424
  const serviceName = this.config.service?.name || "unknown";
@@ -13237,6 +13587,30 @@ var TuskDriftCore = class TuskDriftCore {
13237
13587
  };
13238
13588
  }
13239
13589
  }
13590
+ /**
13591
+ * Request environment variables from CLI for a specific trace (synchronously).
13592
+ * This blocks the main thread, so it should be used carefully.
13593
+ */
13594
+ requestEnvVarsSync(traceTestServerSpanId) {
13595
+ if (!this.isConnectedWithCLI) {
13596
+ logger.error("Requesting sync env vars but CLI is not ready yet");
13597
+ throw new Error("Requesting sync env vars but CLI is not ready yet");
13598
+ }
13599
+ if (!this.communicator || this.mode !== TuskDriftMode.REPLAY) {
13600
+ logger.debug("Cannot request env vars: not in replay mode or no CLI connection");
13601
+ return {};
13602
+ }
13603
+ try {
13604
+ logger.debug(`Requesting env vars (sync) for trace: ${traceTestServerSpanId}`);
13605
+ const envVars = this.communicator.requestEnvVarsSync(traceTestServerSpanId);
13606
+ logger.debug(`Received env vars from CLI, count: ${Object.keys(envVars).length}`);
13607
+ logger.debug(`First 10 env vars: ${JSON.stringify(Object.keys(envVars).slice(0, 10), null, 2)}`);
13608
+ return envVars;
13609
+ } catch (error) {
13610
+ logger.error(`[TuskDrift] Error requesting env vars from CLI:`, error);
13611
+ return {};
13612
+ }
13613
+ }
13240
13614
  requestMockSync(mockRequest) {
13241
13615
  if (!this.isConnectedWithCLI) {
13242
13616
  logger.error("Requesting sync mock but CLI is not ready yet");
@@ -13291,6 +13665,9 @@ var TuskDriftCore = class TuskDriftCore {
13291
13665
  getTracer() {
13292
13666
  return __opentelemetry_api.trace.getTracer(TD_INSTRUMENTATION_LIBRARY_NAME);
13293
13667
  }
13668
+ getProtobufCommunicator() {
13669
+ return this.communicator;
13670
+ }
13294
13671
  };
13295
13672
  var TuskDriftSDK = class {
13296
13673
  constructor() {