@use-tusk/drift-node-sdk 0.1.34 → 0.1.36
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/README.md +1 -1
- package/dist/chunk-Cd-22Um9.cjs +69 -0
- package/dist/index.cjs +928 -694
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -83
- package/dist/index.d.ts +1 -83
- package/dist/index.js +625 -353
- package/dist/index.js.map +1 -1
- package/dist/instrumentation-manifest.json +3 -5
- package/dist/next.cjs +211 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +84 -0
- package/dist/next.d.ts +84 -0
- package/dist/next.js +207 -0
- package/dist/next.js.map +1 -0
- package/package.json +15 -2
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import * as fs$1 from "fs";
|
|
3
3
|
import fs from "fs";
|
|
4
|
+
import os from "os";
|
|
4
5
|
import * as path$1 from "path";
|
|
5
6
|
import path, { normalize } from "path";
|
|
6
|
-
import {
|
|
7
|
-
import os from "os";
|
|
7
|
+
import { satisfies } from "semver";
|
|
8
8
|
import { Hook } from "require-in-the-middle";
|
|
9
9
|
import { Hook as Hook$1 } from "import-in-the-middle";
|
|
10
10
|
import yaml from "js-yaml";
|
|
@@ -55,207 +55,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
55
55
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
56
56
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
57
57
|
|
|
58
|
-
//#endregion
|
|
59
|
-
//#region src/nextjs/utils.ts
|
|
60
|
-
/**
|
|
61
|
-
* Get the installed Next.js version by reading package.json from node_modules.
|
|
62
|
-
*
|
|
63
|
-
* @returns The Next.js version string, or undefined if not found
|
|
64
|
-
*/
|
|
65
|
-
function getNextjsVersion() {
|
|
66
|
-
try {
|
|
67
|
-
const nextPackageJsonPath = path$1.join(process.cwd(), "node_modules", "next", "package.json");
|
|
68
|
-
if (fs$1.existsSync(nextPackageJsonPath)) return JSON.parse(fs$1.readFileSync(nextPackageJsonPath, "utf-8")).version;
|
|
69
|
-
} catch (error) {}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Parse a semantic version string into its components.
|
|
73
|
-
*
|
|
74
|
-
* @param version - The version string to parse (e.g., "15.0.0-canary.124")
|
|
75
|
-
* @returns Parsed version object with major, minor, patch, and prerelease
|
|
76
|
-
*/
|
|
77
|
-
function parseVersion(version$1) {
|
|
78
|
-
try {
|
|
79
|
-
const parsed = parse(version$1);
|
|
80
|
-
if (!parsed) return {
|
|
81
|
-
major: void 0,
|
|
82
|
-
minor: void 0,
|
|
83
|
-
patch: void 0,
|
|
84
|
-
prerelease: void 0
|
|
85
|
-
};
|
|
86
|
-
return {
|
|
87
|
-
major: parsed.major,
|
|
88
|
-
minor: parsed.minor,
|
|
89
|
-
patch: parsed.patch,
|
|
90
|
-
prerelease: parsed.prerelease.length > 0 ? parsed.prerelease.join(".") : void 0
|
|
91
|
-
};
|
|
92
|
-
} catch {
|
|
93
|
-
return {
|
|
94
|
-
major: void 0,
|
|
95
|
-
minor: void 0,
|
|
96
|
-
patch: void 0,
|
|
97
|
-
prerelease: void 0
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Check if the Next.js version requires the instrumentationHook to be set.
|
|
103
|
-
* From Next.js 15.0.0-rc.1 onwards, the instrumentationHook is no longer needed
|
|
104
|
-
* and Next.js will warn if it's set.
|
|
105
|
-
*
|
|
106
|
-
* @param version - The Next.js version string
|
|
107
|
-
* @returns true if instrumentationHook should be set, false otherwise
|
|
108
|
-
*/
|
|
109
|
-
function shouldSetInstrumentationHook(version$1) {
|
|
110
|
-
if (!version$1) return true;
|
|
111
|
-
const { major: major$1, minor, patch, prerelease } = parseVersion(version$1);
|
|
112
|
-
if (major$1 === void 0 || minor === void 0 || patch === void 0) return true;
|
|
113
|
-
if (major$1 >= 16) return false;
|
|
114
|
-
if (major$1 < 15) return true;
|
|
115
|
-
if (major$1 === 15) {
|
|
116
|
-
if (minor > 0 || patch > 0) return false;
|
|
117
|
-
if (minor === 0 && patch === 0 && prerelease === void 0) return false;
|
|
118
|
-
if (prerelease?.startsWith("rc.")) {
|
|
119
|
-
if (parseInt(prerelease.split(".")[1] || "0", 10) >= 1) return false;
|
|
120
|
-
}
|
|
121
|
-
if (prerelease?.startsWith("canary.")) {
|
|
122
|
-
if (parseInt(prerelease.split(".")[1] || "0", 10) >= 124) return false;
|
|
123
|
-
}
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
return true;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Log a message if debug mode is enabled.
|
|
130
|
-
*
|
|
131
|
-
* @param debug - Whether debug mode is enabled
|
|
132
|
-
* @param message - The message to log
|
|
133
|
-
*/
|
|
134
|
-
function debugLog(debug, message) {
|
|
135
|
-
if (debug) console.log(`[Tusk Drift] ${message}`);
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Log a warning message if warnings are not suppressed.
|
|
139
|
-
*
|
|
140
|
-
* @param suppress - Whether to suppress the warning
|
|
141
|
-
* @param message - The warning message to log
|
|
142
|
-
*/
|
|
143
|
-
function warn(suppress, message) {
|
|
144
|
-
if (!suppress) console.warn(`[Tusk Drift] ${message}`);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
//#endregion
|
|
148
|
-
//#region src/nextjs/withTuskDrift.ts
|
|
149
|
-
/**
|
|
150
|
-
* Wraps your Next.js configuration with Tusk Drift instrumentation setup.
|
|
151
|
-
*
|
|
152
|
-
* This function automatically configures Next.js to work with Tusk Drift by:
|
|
153
|
-
* - Enabling the Next.js instrumentation hook (for Next.js < 15.0.0-rc.1)
|
|
154
|
-
* - Configuring server external packages to prevent bundling of core instrumentation packages
|
|
155
|
-
* - Supporting both webpack and Turbopack bundlers
|
|
156
|
-
* - Preserving your existing Next.js configuration and webpack customizations
|
|
157
|
-
*
|
|
158
|
-
* @param nextConfig - Your existing Next.js configuration object (optional)
|
|
159
|
-
* @param options - Additional options to configure Tusk Drift's behavior (optional)
|
|
160
|
-
* @returns The wrapped Next.js configuration with Tusk Drift instrumentation enabled
|
|
161
|
-
*
|
|
162
|
-
* @example
|
|
163
|
-
* Basic usage:
|
|
164
|
-
* ```javascript
|
|
165
|
-
* // next.config.js
|
|
166
|
-
* const { withTuskDrift } = require('@use-tusk/drift-node-sdk');
|
|
167
|
-
*
|
|
168
|
-
* module.exports = withTuskDrift({
|
|
169
|
-
* // Your Next.js config
|
|
170
|
-
* });
|
|
171
|
-
* ```
|
|
172
|
-
*
|
|
173
|
-
* @example
|
|
174
|
-
* With debug logging:
|
|
175
|
-
* ```javascript
|
|
176
|
-
* // next.config.js
|
|
177
|
-
* const { withTuskDrift } = require('@use-tusk/drift-node-sdk');
|
|
178
|
-
*
|
|
179
|
-
* module.exports = withTuskDrift(
|
|
180
|
-
* {
|
|
181
|
-
* // Your Next.js config
|
|
182
|
-
* },
|
|
183
|
-
* {
|
|
184
|
-
* debug: true,
|
|
185
|
-
* }
|
|
186
|
-
* );
|
|
187
|
-
* ```
|
|
188
|
-
*
|
|
189
|
-
* @remarks
|
|
190
|
-
* The following packages are added as server externals for both webpack and Turbopack:
|
|
191
|
-
* - `require-in-the-middle` - Required for CommonJS module interception
|
|
192
|
-
* - `jsonpath` - Required for schema manipulation
|
|
193
|
-
* - Additional packages when TUSK_DRIFT_MODE is RECORD or REPLAY (e.g., database clients, etc.)
|
|
194
|
-
*
|
|
195
|
-
* Works with both webpack (default) and Turbopack (`next dev --turbo`).
|
|
196
|
-
*/
|
|
197
|
-
function withTuskDrift(nextConfig = {}, options = {}) {
|
|
198
|
-
const config = nextConfig;
|
|
199
|
-
const debug = options.debug || false;
|
|
200
|
-
const suppressAllWarnings = options.suppressWarnings || false;
|
|
201
|
-
const nextjsVersion = getNextjsVersion();
|
|
202
|
-
if (nextjsVersion) debugLog(debug, `Detected Next.js version: ${nextjsVersion}`);
|
|
203
|
-
else warn(suppressAllWarnings || false, "Could not detect Next.js version. Some features may not work correctly. If you encounter issues, please ensure Next.js is properly installed.");
|
|
204
|
-
const needsInstrumentationHook = !options.disableInstrumentationHook && shouldSetInstrumentationHook(nextjsVersion);
|
|
205
|
-
const mode = process.env.TUSK_DRIFT_MODE?.toUpperCase();
|
|
206
|
-
const coreExternals = [
|
|
207
|
-
"require-in-the-middle",
|
|
208
|
-
"jsonpath",
|
|
209
|
-
...mode === "RECORD" || mode === "REPLAY" ? [
|
|
210
|
-
"@upstash/redis",
|
|
211
|
-
"ioredis",
|
|
212
|
-
"pg",
|
|
213
|
-
"postgres",
|
|
214
|
-
"mysql2",
|
|
215
|
-
"@prisma/client",
|
|
216
|
-
"@google-cloud/firestore",
|
|
217
|
-
"@grpc/grpc-js",
|
|
218
|
-
"graphql",
|
|
219
|
-
"jsonwebtoken",
|
|
220
|
-
"jwks-rsa"
|
|
221
|
-
] : []
|
|
222
|
-
];
|
|
223
|
-
const wrappedConfig = {
|
|
224
|
-
...config,
|
|
225
|
-
...needsInstrumentationHook ? { experimental: {
|
|
226
|
-
...config.experimental,
|
|
227
|
-
instrumentationHook: true
|
|
228
|
-
} } : { experimental: config.experimental },
|
|
229
|
-
serverExternalPackages: [...config.serverExternalPackages || [], ...coreExternals],
|
|
230
|
-
webpack: (webpackConfig, webpackOptions) => {
|
|
231
|
-
if (webpackOptions.isServer) {
|
|
232
|
-
const originalExternals = webpackConfig.externals;
|
|
233
|
-
const externalsMapping = {};
|
|
234
|
-
for (const pkg of coreExternals) {
|
|
235
|
-
externalsMapping[pkg] = `commonjs ${pkg}`;
|
|
236
|
-
debugLog(debug, `Mapped external ${pkg} -> commonjs ${pkg}`);
|
|
237
|
-
}
|
|
238
|
-
if (!originalExternals) {
|
|
239
|
-
webpackConfig.externals = [externalsMapping];
|
|
240
|
-
debugLog(debug, "Created new externals with SDK paths");
|
|
241
|
-
} else if (Array.isArray(originalExternals)) {
|
|
242
|
-
originalExternals.push(externalsMapping);
|
|
243
|
-
debugLog(debug, "Added SDK paths to existing externals array");
|
|
244
|
-
} else {
|
|
245
|
-
webpackConfig.externals = [originalExternals, externalsMapping];
|
|
246
|
-
debugLog(debug, "Wrapped existing externals with SDK paths");
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
if (typeof config.webpack === "function") return config.webpack(webpackConfig, webpackOptions);
|
|
250
|
-
return webpackConfig;
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
if (needsInstrumentationHook) debugLog(debug, "Set experimental.instrumentationHook to true");
|
|
254
|
-
else debugLog(debug, "Skipped setting experimental.instrumentationHook (not needed for Next.js 15.0.0-rc.1+)");
|
|
255
|
-
if (options.disableInstrumentationHook && nextjsVersion && shouldSetInstrumentationHook(nextjsVersion)) warn(suppressAllWarnings || false, "You disabled instrumentationHook, but your Next.js version requires it. Tusk Drift may not initialize properly. Please remove the disableInstrumentationHook option.");
|
|
256
|
-
return wrappedConfig;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
58
|
//#endregion
|
|
260
59
|
//#region src/instrumentation/core/baseClasses/TdInstrumentationAbstract.ts
|
|
261
60
|
var TdInstrumentationAbstract = class {
|
|
@@ -293,6 +92,7 @@ var TdInstrumentationAbstract = class {
|
|
|
293
92
|
function safeJsonStringify(obj) {
|
|
294
93
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
295
94
|
return JSON.stringify(obj, (key, value) => {
|
|
95
|
+
if (typeof value === "bigint") return value.toString();
|
|
296
96
|
if (typeof value === "object" && value !== null) {
|
|
297
97
|
if (seen.has(value)) return "[Circular]";
|
|
298
98
|
seen.add(value);
|
|
@@ -7915,7 +7715,7 @@ var SpanUtils = class SpanUtils {
|
|
|
7915
7715
|
...addSpanAttributesOptions.submodule && { [TdSpanAttributes.SUBMODULE_NAME]: addSpanAttributesOptions.submodule },
|
|
7916
7716
|
...addSpanAttributesOptions.isPreAppStart && { [TdSpanAttributes.IS_PRE_APP_START]: addSpanAttributesOptions.isPreAppStart },
|
|
7917
7717
|
...addSpanAttributesOptions.inputValue && { [TdSpanAttributes.INPUT_VALUE]: createSpanInputValue(addSpanAttributesOptions.inputValue) },
|
|
7918
|
-
...addSpanAttributesOptions.outputValue && { [TdSpanAttributes.OUTPUT_VALUE]:
|
|
7718
|
+
...addSpanAttributesOptions.outputValue && { [TdSpanAttributes.OUTPUT_VALUE]: safeJsonStringify(addSpanAttributesOptions.outputValue) },
|
|
7919
7719
|
...addSpanAttributesOptions.inputSchemaMerges && { [TdSpanAttributes.INPUT_SCHEMA_MERGES]: JSON.stringify(addSpanAttributesOptions.inputSchemaMerges) },
|
|
7920
7720
|
...addSpanAttributesOptions.outputSchemaMerges && { [TdSpanAttributes.OUTPUT_SCHEMA_MERGES]: JSON.stringify(addSpanAttributesOptions.outputSchemaMerges) },
|
|
7921
7721
|
...addSpanAttributesOptions.metadata && { [TdSpanAttributes.METADATA]: JSON.stringify(addSpanAttributesOptions.metadata) },
|
|
@@ -18762,6 +18562,11 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
|
|
|
18762
18562
|
if (self.mode === TuskDriftMode.REPLAY) return handleReplayMode({
|
|
18763
18563
|
noOpRequestHandler: () => {
|
|
18764
18564
|
process.nextTick(() => {
|
|
18565
|
+
this.status = "connecting";
|
|
18566
|
+
this.emit("connecting");
|
|
18567
|
+
this.status = "connect";
|
|
18568
|
+
this.emit("connect");
|
|
18569
|
+
this.status = "ready";
|
|
18765
18570
|
this.emit("ready");
|
|
18766
18571
|
});
|
|
18767
18572
|
return Promise.resolve();
|
|
@@ -18968,6 +18773,11 @@ var IORedisInstrumentation = class extends TdInstrumentationBase {
|
|
|
18968
18773
|
async _handleReplayConnect(thisContext) {
|
|
18969
18774
|
logger.debug(`[IORedisInstrumentation] Replaying IORedis connect`);
|
|
18970
18775
|
process.nextTick(() => {
|
|
18776
|
+
thisContext.status = "connecting";
|
|
18777
|
+
thisContext.emit("connecting");
|
|
18778
|
+
thisContext.status = "connect";
|
|
18779
|
+
thisContext.emit("connect");
|
|
18780
|
+
thisContext.status = "ready";
|
|
18971
18781
|
thisContext.emit("ready");
|
|
18972
18782
|
});
|
|
18973
18783
|
return Promise.resolve();
|
|
@@ -22268,11 +22078,34 @@ let PrismaErrorClassName = /* @__PURE__ */ function(PrismaErrorClassName$1) {
|
|
|
22268
22078
|
//#endregion
|
|
22269
22079
|
//#region src/instrumentation/libraries/prisma/Instrumentation.ts
|
|
22270
22080
|
var import_src$14 = /* @__PURE__ */ __toESM(require_src$7(), 1);
|
|
22271
|
-
|
|
22081
|
+
/**
|
|
22082
|
+
* Prisma instrumentation for recording and replaying database operations.
|
|
22083
|
+
*
|
|
22084
|
+
* ## Type deserialization
|
|
22085
|
+
*
|
|
22086
|
+
* Prisma returns special JS types (Date, BigInt, Decimal, Buffer) for certain
|
|
22087
|
+
* column types. JSON round-trip during record/replay loses this type information.
|
|
22088
|
+
* We reconstruct types during replay using two strategies:
|
|
22089
|
+
*
|
|
22090
|
+
* 1. **Model-based operations** (findFirst, create, update, etc.): The middleware
|
|
22091
|
+
* provides the model name, so we look up field types from `_runtimeDataModel`
|
|
22092
|
+
* at replay time. No extra metadata needed during recording.
|
|
22093
|
+
*
|
|
22094
|
+
* 2. **Raw queries** ($queryRaw): No model name is available. During recording,
|
|
22095
|
+
* we sniff JS types from the result and store a per-column `_tdTypeMap`
|
|
22096
|
+
* (e.g., `{bigNum: "bigint", data: "bytes"}`). During replay, we use this
|
|
22097
|
+
* map to reconstruct the values.
|
|
22098
|
+
*
|
|
22099
|
+
* Both strategies share `_reconstructSingleValue` for the actual conversion.
|
|
22100
|
+
* See docs/prisma-type-deserialization-bug.md for the full design doc.
|
|
22101
|
+
*/
|
|
22102
|
+
var PrismaInstrumentation = class PrismaInstrumentation extends TdInstrumentationBase {
|
|
22272
22103
|
constructor(config = {}) {
|
|
22273
22104
|
super("@prisma/client", config);
|
|
22274
22105
|
this.INSTRUMENTATION_NAME = "PrismaInstrumentation";
|
|
22275
22106
|
this.prismaErrorClasses = [];
|
|
22107
|
+
this.prismaClient = null;
|
|
22108
|
+
this.prismaNamespace = null;
|
|
22276
22109
|
this.mode = config.mode || TuskDriftMode.DISABLED;
|
|
22277
22110
|
this.tuskDrift = TuskDriftCore.getInstance();
|
|
22278
22111
|
}
|
|
@@ -22289,6 +22122,7 @@ var PrismaInstrumentation = class extends TdInstrumentationBase {
|
|
|
22289
22122
|
return prismaModule;
|
|
22290
22123
|
}
|
|
22291
22124
|
this._storePrismaErrorClasses(prismaModule);
|
|
22125
|
+
this.prismaNamespace = prismaModule.Prisma || prismaModule;
|
|
22292
22126
|
logger.debug(`[PrismaInstrumentation] Wrapping PrismaClient constructor`);
|
|
22293
22127
|
this._wrap(prismaModule, "PrismaClient", (OriginalPrismaClient) => {
|
|
22294
22128
|
const self = this;
|
|
@@ -22296,7 +22130,9 @@ var PrismaInstrumentation = class extends TdInstrumentationBase {
|
|
|
22296
22130
|
return class TdPrismaClient {
|
|
22297
22131
|
constructor(...args) {
|
|
22298
22132
|
logger.debug(`[PrismaInstrumentation] Creating patched PrismaClient instance`);
|
|
22299
|
-
|
|
22133
|
+
const prismaClient = new OriginalPrismaClient(...args);
|
|
22134
|
+
self.prismaClient = prismaClient;
|
|
22135
|
+
const extendedClient = prismaClient.$extends({ query: { async $allOperations({ model, operation, args: operationArgs, query }) {
|
|
22300
22136
|
logger.debug(`[PrismaInstrumentation] $allOperations intercepted: ${model}.${operation}`);
|
|
22301
22137
|
return self._handlePrismaOperation({
|
|
22302
22138
|
model,
|
|
@@ -22305,6 +22141,22 @@ var PrismaInstrumentation = class extends TdInstrumentationBase {
|
|
|
22305
22141
|
query
|
|
22306
22142
|
});
|
|
22307
22143
|
} } });
|
|
22144
|
+
if (self.mode === TuskDriftMode.REPLAY) {
|
|
22145
|
+
const originalTransaction = extendedClient.$transaction.bind(extendedClient);
|
|
22146
|
+
extendedClient.$transaction = async function(...txArgs) {
|
|
22147
|
+
const firstArg = txArgs[0];
|
|
22148
|
+
if (typeof firstArg === "function") {
|
|
22149
|
+
logger.debug(`[PrismaInstrumentation] Replay: bypassing interactive $transaction DB connection`);
|
|
22150
|
+
return firstArg(extendedClient);
|
|
22151
|
+
}
|
|
22152
|
+
if (Array.isArray(firstArg)) {
|
|
22153
|
+
logger.debug(`[PrismaInstrumentation] Replay: bypassing sequential $transaction DB connection`);
|
|
22154
|
+
return Promise.all(firstArg);
|
|
22155
|
+
}
|
|
22156
|
+
return originalTransaction(...txArgs);
|
|
22157
|
+
};
|
|
22158
|
+
}
|
|
22159
|
+
return extendedClient;
|
|
22308
22160
|
}
|
|
22309
22161
|
};
|
|
22310
22162
|
});
|
|
@@ -22361,7 +22213,7 @@ var PrismaInstrumentation = class extends TdInstrumentationBase {
|
|
|
22361
22213
|
inputValue,
|
|
22362
22214
|
isPreAppStart
|
|
22363
22215
|
}, (spanInfo) => {
|
|
22364
|
-
return this._handleRecordPrismaOperation(spanInfo, query, args);
|
|
22216
|
+
return this._handleRecordPrismaOperation(spanInfo, query, args, model);
|
|
22365
22217
|
});
|
|
22366
22218
|
},
|
|
22367
22219
|
spanKind: import_src$14.SpanKind.CLIENT
|
|
@@ -22388,13 +22240,15 @@ var PrismaInstrumentation = class extends TdInstrumentationBase {
|
|
|
22388
22240
|
});
|
|
22389
22241
|
} else return query(args);
|
|
22390
22242
|
}
|
|
22391
|
-
async _handleRecordPrismaOperation(spanInfo, query, args) {
|
|
22243
|
+
async _handleRecordPrismaOperation(spanInfo, query, args, model) {
|
|
22392
22244
|
try {
|
|
22393
22245
|
logger.debug(`[PrismaInstrumentation] Recording Prisma operation`);
|
|
22394
22246
|
const result = await query(args);
|
|
22247
|
+
const typeMap = model ? null : this._buildTypeMap(result);
|
|
22395
22248
|
const outputValue = {
|
|
22396
22249
|
prismaResult: result,
|
|
22397
|
-
_tdOriginalFormat: "result"
|
|
22250
|
+
_tdOriginalFormat: "result",
|
|
22251
|
+
...typeMap && { _tdTypeMap: typeMap }
|
|
22398
22252
|
};
|
|
22399
22253
|
try {
|
|
22400
22254
|
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue });
|
|
@@ -22457,8 +22311,158 @@ var PrismaInstrumentation = class extends TdInstrumentationBase {
|
|
|
22457
22311
|
});
|
|
22458
22312
|
throw errorObj;
|
|
22459
22313
|
}
|
|
22314
|
+
let result = outputValue.prismaResult;
|
|
22315
|
+
try {
|
|
22316
|
+
if (inputValue.model) result = this._reconstructPrismaTypes(result, inputValue.model);
|
|
22317
|
+
else if (outputValue._tdTypeMap) result = this._reconstructFromTypeMap(result, outputValue._tdTypeMap);
|
|
22318
|
+
} catch (reconstructError) {
|
|
22319
|
+
logger.debug(`[PrismaInstrumentation] Failed to reconstruct types: ${reconstructError}`);
|
|
22320
|
+
}
|
|
22460
22321
|
SpanUtils.endSpan(spanInfo.span, { code: import_src$14.SpanStatusCode.OK });
|
|
22461
|
-
return
|
|
22322
|
+
return result;
|
|
22323
|
+
}
|
|
22324
|
+
/**
|
|
22325
|
+
* Sniff the JS type of a value returned by Prisma.
|
|
22326
|
+
*
|
|
22327
|
+
* Returns type names that mirror Prisma's internal `QueryIntrospectionBuiltinType`
|
|
22328
|
+
* enum from `@prisma/client/runtime` (used in `deserializeRawResults.ts`):
|
|
22329
|
+
* "bigint" | "bytes" | "decimal" | "datetime"
|
|
22330
|
+
*
|
|
22331
|
+
* We don't import these types directly — we use our own string literals that
|
|
22332
|
+
* match Prisma's naming convention so the type map is self-documenting and
|
|
22333
|
+
* consistent with what Prisma would produce internally.
|
|
22334
|
+
*/
|
|
22335
|
+
_sniffType(value) {
|
|
22336
|
+
if (typeof value === "bigint") return "bigint";
|
|
22337
|
+
if (value instanceof Date) return "datetime";
|
|
22338
|
+
if (Buffer.isBuffer(value) || value instanceof Uint8Array) return "bytes";
|
|
22339
|
+
if (typeof value === "object" && value !== null && typeof value.toFixed === "function" && typeof value.toExponential === "function" && typeof value.toSignificantDigits === "function") return "decimal";
|
|
22340
|
+
return null;
|
|
22341
|
+
}
|
|
22342
|
+
/**
|
|
22343
|
+
* Build a per-column type map by sniffing values in the result.
|
|
22344
|
+
* For arrays of objects (e.g., $queryRaw results), scans all rows to handle
|
|
22345
|
+
* cases where the first row has null values but later rows don't.
|
|
22346
|
+
* Returns null if no special types are detected.
|
|
22347
|
+
*/
|
|
22348
|
+
_buildTypeMap(result) {
|
|
22349
|
+
if (result === null || result === void 0) return null;
|
|
22350
|
+
const rows = Array.isArray(result) ? result : typeof result === "object" ? [result] : null;
|
|
22351
|
+
if (!rows || rows.length === 0) return null;
|
|
22352
|
+
const typeMap = {};
|
|
22353
|
+
let hasTypes = false;
|
|
22354
|
+
for (const row of rows) {
|
|
22355
|
+
if (!row || typeof row !== "object") continue;
|
|
22356
|
+
for (const [key, value] of Object.entries(row)) {
|
|
22357
|
+
if (typeMap[key] || value === null || value === void 0) continue;
|
|
22358
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
22359
|
+
const elemType = this._sniffType(value[0]);
|
|
22360
|
+
if (elemType) {
|
|
22361
|
+
typeMap[key] = `${elemType}-array`;
|
|
22362
|
+
hasTypes = true;
|
|
22363
|
+
continue;
|
|
22364
|
+
}
|
|
22365
|
+
}
|
|
22366
|
+
const type = this._sniffType(value);
|
|
22367
|
+
if (type) {
|
|
22368
|
+
typeMap[key] = type;
|
|
22369
|
+
hasTypes = true;
|
|
22370
|
+
}
|
|
22371
|
+
}
|
|
22372
|
+
if (hasTypes && Object.keys(typeMap).length >= Object.keys(row).length) break;
|
|
22373
|
+
}
|
|
22374
|
+
return hasTypes ? typeMap : null;
|
|
22375
|
+
}
|
|
22376
|
+
/**
|
|
22377
|
+
* Reconstruct types from a _tdTypeMap (used for $queryRaw and other model-less operations).
|
|
22378
|
+
*/
|
|
22379
|
+
_reconstructFromTypeMap(result, typeMap) {
|
|
22380
|
+
if (result === null || result === void 0) return result;
|
|
22381
|
+
const reconstructRow = (row) => {
|
|
22382
|
+
if (typeof row !== "object" || row === null) return row;
|
|
22383
|
+
for (const [key, type] of Object.entries(typeMap)) {
|
|
22384
|
+
const value = row[key];
|
|
22385
|
+
if (value === null || value === void 0) continue;
|
|
22386
|
+
if (typeof type === "string" && type.endsWith("-array") && Array.isArray(value)) {
|
|
22387
|
+
const baseType = type.replace("-array", "");
|
|
22388
|
+
row[key] = value.map((v) => this._reconstructSingleValue(v, baseType));
|
|
22389
|
+
continue;
|
|
22390
|
+
}
|
|
22391
|
+
row[key] = this._reconstructSingleValue(value, type);
|
|
22392
|
+
}
|
|
22393
|
+
return row;
|
|
22394
|
+
};
|
|
22395
|
+
if (Array.isArray(result)) return result.map(reconstructRow);
|
|
22396
|
+
return reconstructRow(result);
|
|
22397
|
+
}
|
|
22398
|
+
/**
|
|
22399
|
+
* Reconstruct a single value from its JSON-deserialized form back to the
|
|
22400
|
+
* original JS type that Prisma would have returned.
|
|
22401
|
+
*
|
|
22402
|
+
* The `type` parameter uses the same names as Prisma's query engine types
|
|
22403
|
+
* (see _sniffType and PRISMA_SCHEMA_TO_ENGINE_TYPE). Both the model-based
|
|
22404
|
+
* and raw-query replay paths converge here.
|
|
22405
|
+
*/
|
|
22406
|
+
_reconstructSingleValue(value, type) {
|
|
22407
|
+
if (value === null || value === void 0) return value;
|
|
22408
|
+
switch (type) {
|
|
22409
|
+
case "bigint":
|
|
22410
|
+
if (typeof value === "string" || typeof value === "number") return BigInt(value);
|
|
22411
|
+
return value;
|
|
22412
|
+
case "datetime":
|
|
22413
|
+
if (typeof value === "string") return new Date(value);
|
|
22414
|
+
return value;
|
|
22415
|
+
case "decimal":
|
|
22416
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
22417
|
+
if (this.prismaNamespace?.Decimal) return new this.prismaNamespace.Decimal(value);
|
|
22418
|
+
const decimalValue = String(value);
|
|
22419
|
+
return {
|
|
22420
|
+
toString: () => decimalValue,
|
|
22421
|
+
toFixed: (dp) => Number(decimalValue).toFixed(dp),
|
|
22422
|
+
valueOf: () => Number(decimalValue),
|
|
22423
|
+
[Symbol.toPrimitive]: (hint) => hint === "string" ? decimalValue : Number(decimalValue)
|
|
22424
|
+
};
|
|
22425
|
+
}
|
|
22426
|
+
return value;
|
|
22427
|
+
case "bytes":
|
|
22428
|
+
if (typeof value === "string") return Buffer.from(value, "base64");
|
|
22429
|
+
if (typeof value === "object" && !Buffer.isBuffer(value)) {
|
|
22430
|
+
const bufferData = value.data || Object.values(value);
|
|
22431
|
+
return Buffer.from(bufferData);
|
|
22432
|
+
}
|
|
22433
|
+
return value;
|
|
22434
|
+
default: return value;
|
|
22435
|
+
}
|
|
22436
|
+
}
|
|
22437
|
+
/**
|
|
22438
|
+
* Reconstruct Prisma types for model-based operations (findFirst, create, update, etc.).
|
|
22439
|
+
*
|
|
22440
|
+
* Uses `prismaClient._runtimeDataModel` — Prisma's internal schema representation
|
|
22441
|
+
* available at runtime — to determine field types. This avoids needing to store
|
|
22442
|
+
* type metadata during recording; the schema itself is the source of truth.
|
|
22443
|
+
*
|
|
22444
|
+
* Handles scalar fields, array fields (e.g., BigInt[]), and nested relations recursively.
|
|
22445
|
+
*/
|
|
22446
|
+
_reconstructPrismaTypes(result, modelName) {
|
|
22447
|
+
if (result === null || result === void 0) return result;
|
|
22448
|
+
const runtimeDataModel = this.prismaClient?._runtimeDataModel;
|
|
22449
|
+
if (!runtimeDataModel) return result;
|
|
22450
|
+
if (Array.isArray(result)) return result.map((item) => this._reconstructPrismaTypes(item, modelName));
|
|
22451
|
+
const model = runtimeDataModel.models[modelName];
|
|
22452
|
+
if (!model) return result;
|
|
22453
|
+
if (typeof result !== "object") return result;
|
|
22454
|
+
const fieldTypeMap = new Map(model.fields.map((f) => [f.name, f]));
|
|
22455
|
+
for (const [key, value] of Object.entries(result)) {
|
|
22456
|
+
const field = fieldTypeMap.get(key);
|
|
22457
|
+
if (!field || value === null || value === void 0) continue;
|
|
22458
|
+
if (field.kind === "scalar") {
|
|
22459
|
+
const engineType = PrismaInstrumentation.PRISMA_SCHEMA_TO_ENGINE_TYPE[field.type];
|
|
22460
|
+
if (engineType) if (Array.isArray(value)) result[key] = value.map((v) => this._reconstructSingleValue(v, engineType));
|
|
22461
|
+
else result[key] = this._reconstructSingleValue(value, engineType);
|
|
22462
|
+
}
|
|
22463
|
+
if (field.kind === "object" && field.type && typeof value === "object") result[key] = this._reconstructPrismaTypes(value, field.type);
|
|
22464
|
+
}
|
|
22465
|
+
return result;
|
|
22462
22466
|
}
|
|
22463
22467
|
_getPrismaErrorClassName(error) {
|
|
22464
22468
|
for (const errorInfo of this.prismaErrorClasses) if (error instanceof errorInfo.errorClass) return errorInfo.name;
|
|
@@ -22483,6 +22487,70 @@ var PrismaInstrumentation = class extends TdInstrumentationBase {
|
|
|
22483
22487
|
wrap(target, propertyName, wrapper);
|
|
22484
22488
|
}
|
|
22485
22489
|
};
|
|
22490
|
+
PrismaInstrumentation.PRISMA_SCHEMA_TO_ENGINE_TYPE = {
|
|
22491
|
+
DateTime: "datetime",
|
|
22492
|
+
BigInt: "bigint",
|
|
22493
|
+
Decimal: "decimal",
|
|
22494
|
+
Bytes: "bytes"
|
|
22495
|
+
};
|
|
22496
|
+
|
|
22497
|
+
//#endregion
|
|
22498
|
+
//#region src/instrumentation/libraries/mongodb/mocks/FakeTopology.ts
|
|
22499
|
+
/**
|
|
22500
|
+
* Fake MongoDB Topology for replay mode.
|
|
22501
|
+
*
|
|
22502
|
+
* When BulkOperationBase is constructed, it calls getTopology(collection)
|
|
22503
|
+
* which requires a connected topology. In replay mode, no real connection
|
|
22504
|
+
* exists, so we inject this fake topology to satisfy the constructor's
|
|
22505
|
+
* requirements without hitting a real server.
|
|
22506
|
+
*
|
|
22507
|
+
* The constructor reads:
|
|
22508
|
+
* - topology.lastHello() -> returns {} so all size limits use defaults
|
|
22509
|
+
* - topology.lastIsMaster() -> returns {} (legacy compat)
|
|
22510
|
+
* - topology.s.options -> returns {} so autoEncryption check is false
|
|
22511
|
+
*
|
|
22512
|
+
* The topology is also injected onto the shared MongoClient (via
|
|
22513
|
+
* _injectFakeTopology) and persists across requests. Other driver code
|
|
22514
|
+
* (e.g. ClientSession.loadBalanced getter) accesses
|
|
22515
|
+
* topology.description.type, so we provide a minimal description to
|
|
22516
|
+
* prevent TypeError when the property is read.
|
|
22517
|
+
*/
|
|
22518
|
+
var TdFakeTopology = class extends EventEmitter {
|
|
22519
|
+
constructor() {
|
|
22520
|
+
super();
|
|
22521
|
+
this.fakeServer = { description: { address: "fake:27017" } };
|
|
22522
|
+
this.s = { options: {} };
|
|
22523
|
+
this.description = {
|
|
22524
|
+
type: "Unknown",
|
|
22525
|
+
servers: /* @__PURE__ */ new Map(),
|
|
22526
|
+
hasServer: () => false
|
|
22527
|
+
};
|
|
22528
|
+
}
|
|
22529
|
+
lastHello() {
|
|
22530
|
+
return {};
|
|
22531
|
+
}
|
|
22532
|
+
lastIsMaster() {
|
|
22533
|
+
return {};
|
|
22534
|
+
}
|
|
22535
|
+
shouldCheckForSessionSupport() {
|
|
22536
|
+
return false;
|
|
22537
|
+
}
|
|
22538
|
+
hasSessionSupport() {
|
|
22539
|
+
return true;
|
|
22540
|
+
}
|
|
22541
|
+
isConnected() {
|
|
22542
|
+
return true;
|
|
22543
|
+
}
|
|
22544
|
+
isDestroyed() {
|
|
22545
|
+
return false;
|
|
22546
|
+
}
|
|
22547
|
+
selectServerAsync() {
|
|
22548
|
+
return Promise.resolve(this.fakeServer);
|
|
22549
|
+
}
|
|
22550
|
+
selectServer(_selector, _options, callback) {
|
|
22551
|
+
if (typeof callback === "function") callback(null, this.fakeServer);
|
|
22552
|
+
}
|
|
22553
|
+
};
|
|
22486
22554
|
|
|
22487
22555
|
//#endregion
|
|
22488
22556
|
//#region src/instrumentation/libraries/mongodb/handlers/ConnectionHandler.ts
|
|
@@ -22517,7 +22585,7 @@ var ConnectionHandler = class {
|
|
|
22517
22585
|
inputValue,
|
|
22518
22586
|
isPreAppStart: !this.isAppReady()
|
|
22519
22587
|
}, (spanInfo) => {
|
|
22520
|
-
return this.handleReplayConnect(spanInfo, thisArg);
|
|
22588
|
+
return this.handleReplayConnect(spanInfo, thisArg, args);
|
|
22521
22589
|
});
|
|
22522
22590
|
}
|
|
22523
22591
|
});
|
|
@@ -22548,17 +22616,21 @@ var ConnectionHandler = class {
|
|
|
22548
22616
|
* - DISABLED: Passthrough.
|
|
22549
22617
|
*/
|
|
22550
22618
|
handleClose(original, thisArg, args) {
|
|
22551
|
-
if (this.mode === TuskDriftMode.REPLAY)
|
|
22552
|
-
|
|
22553
|
-
|
|
22554
|
-
|
|
22555
|
-
|
|
22556
|
-
|
|
22557
|
-
|
|
22558
|
-
|
|
22559
|
-
|
|
22560
|
-
|
|
22561
|
-
|
|
22619
|
+
if (this.mode === TuskDriftMode.REPLAY) {
|
|
22620
|
+
const callback = args.length > 0 && typeof args[args.length - 1] === "function" ? args[args.length - 1] : void 0;
|
|
22621
|
+
return handleReplayMode({
|
|
22622
|
+
noOpRequestHandler: () => {
|
|
22623
|
+
if (callback) callback();
|
|
22624
|
+
return Promise.resolve();
|
|
22625
|
+
},
|
|
22626
|
+
isServerRequest: false,
|
|
22627
|
+
replayModeHandler: () => {
|
|
22628
|
+
logger.debug(`[${this.instrumentationName}] Replaying MongoDB close (no-op)`);
|
|
22629
|
+
if (callback) callback();
|
|
22630
|
+
return Promise.resolve();
|
|
22631
|
+
}
|
|
22632
|
+
});
|
|
22633
|
+
} else if (this.mode === TuskDriftMode.RECORD) return handleRecordMode({
|
|
22562
22634
|
originalFunctionCall: () => original.apply(thisArg, args),
|
|
22563
22635
|
recordModeHandler: ({ isPreAppStart }) => {
|
|
22564
22636
|
return SpanUtils.createAndExecuteSpan(this.mode, () => original.apply(thisArg, args), {
|
|
@@ -22588,7 +22660,18 @@ var ConnectionHandler = class {
|
|
|
22588
22660
|
return original.apply(thisArg, args);
|
|
22589
22661
|
}
|
|
22590
22662
|
handleRecordConnect(spanInfo, original, thisArg, args) {
|
|
22591
|
-
|
|
22663
|
+
const connectResult = original.apply(thisArg, args);
|
|
22664
|
+
if (!(connectResult && typeof connectResult.then === "function")) {
|
|
22665
|
+
try {
|
|
22666
|
+
logger.debug(`[${this.instrumentationName}] MongoDB connect returned a non-promise value; recording best-effort span`);
|
|
22667
|
+
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: { connected: true } });
|
|
22668
|
+
SpanUtils.endSpan(spanInfo.span, { code: import_src$13.SpanStatusCode.OK });
|
|
22669
|
+
} catch (error) {
|
|
22670
|
+
logger.error(`[${this.instrumentationName}] Error ending non-promise connect span:`, error);
|
|
22671
|
+
}
|
|
22672
|
+
return Promise.resolve(connectResult);
|
|
22673
|
+
}
|
|
22674
|
+
return connectResult.then((result) => {
|
|
22592
22675
|
try {
|
|
22593
22676
|
logger.debug(`[${this.instrumentationName}] MongoDB connection created successfully (${SpanUtils.getTraceInfo()})`);
|
|
22594
22677
|
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: { connected: true } });
|
|
@@ -22611,8 +22694,9 @@ var ConnectionHandler = class {
|
|
|
22611
22694
|
throw error;
|
|
22612
22695
|
});
|
|
22613
22696
|
}
|
|
22614
|
-
handleReplayConnect(spanInfo, thisArg) {
|
|
22697
|
+
handleReplayConnect(spanInfo, thisArg, args) {
|
|
22615
22698
|
logger.debug(`[${this.instrumentationName}] Replaying MongoDB connection (skipping TCP connect)`);
|
|
22699
|
+
this.injectFakeTopology(thisArg);
|
|
22616
22700
|
try {
|
|
22617
22701
|
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: {
|
|
22618
22702
|
connected: true,
|
|
@@ -22622,10 +22706,35 @@ var ConnectionHandler = class {
|
|
|
22622
22706
|
} catch (error) {
|
|
22623
22707
|
logger.error(`[${this.instrumentationName}] Error ending replay connect span:`, error);
|
|
22624
22708
|
}
|
|
22709
|
+
const callback = args.length > 0 && typeof args[args.length - 1] === "function" ? args[args.length - 1] : void 0;
|
|
22710
|
+
if (callback) {
|
|
22711
|
+
callback(null, thisArg);
|
|
22712
|
+
return Promise.resolve(thisArg);
|
|
22713
|
+
}
|
|
22625
22714
|
return Promise.resolve(thisArg);
|
|
22626
22715
|
}
|
|
22716
|
+
injectFakeTopology(client) {
|
|
22717
|
+
const fakeTopology = new TdFakeTopology();
|
|
22718
|
+
if (!client) return;
|
|
22719
|
+
if (!client.topology) client.topology = fakeTopology;
|
|
22720
|
+
if (client.s && !client.s.topology) client.s.topology = fakeTopology;
|
|
22721
|
+
if (client.s) {
|
|
22722
|
+
if (client.s.hasBeenClosed === true) client.s.hasBeenClosed = false;
|
|
22723
|
+
if (client.s.isMongoClient === false) client.s.isMongoClient = true;
|
|
22724
|
+
}
|
|
22725
|
+
}
|
|
22627
22726
|
handleRecordClose(spanInfo, original, thisArg, args) {
|
|
22628
|
-
|
|
22727
|
+
const closeResult = original.apply(thisArg, args);
|
|
22728
|
+
if (!(closeResult && typeof closeResult.then === "function")) {
|
|
22729
|
+
try {
|
|
22730
|
+
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: { closed: true } });
|
|
22731
|
+
SpanUtils.endSpan(spanInfo.span, { code: import_src$13.SpanStatusCode.OK });
|
|
22732
|
+
} catch (error) {
|
|
22733
|
+
logger.error(`[${this.instrumentationName}] Error ending non-promise close span:`, error);
|
|
22734
|
+
}
|
|
22735
|
+
return Promise.resolve();
|
|
22736
|
+
}
|
|
22737
|
+
return closeResult.then(() => {
|
|
22629
22738
|
try {
|
|
22630
22739
|
logger.debug(`[${this.instrumentationName}] MongoDB connection closed successfully (${SpanUtils.getTraceInfo()})`);
|
|
22631
22740
|
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: { closed: true } });
|
|
@@ -22706,21 +22815,37 @@ var TdFakeFindCursor = class TdFakeFindCursor {
|
|
|
22706
22815
|
});
|
|
22707
22816
|
if (this._mockLoadPromise) await this._mockLoadPromise;
|
|
22708
22817
|
}
|
|
22709
|
-
|
|
22710
|
-
|
|
22711
|
-
|
|
22818
|
+
toArray(callback) {
|
|
22819
|
+
const promise = this._ensureMockLoaded().then(() => [...this.documents]);
|
|
22820
|
+
if (typeof callback === "function") {
|
|
22821
|
+
promise.then((docs) => callback(null, docs), (error) => callback(error));
|
|
22822
|
+
return;
|
|
22823
|
+
}
|
|
22824
|
+
return promise;
|
|
22712
22825
|
}
|
|
22713
|
-
|
|
22714
|
-
|
|
22715
|
-
|
|
22826
|
+
next(callback) {
|
|
22827
|
+
const promise = this._ensureMockLoaded().then(() => this.documents[this.index++] ?? null);
|
|
22828
|
+
if (typeof callback === "function") {
|
|
22829
|
+
promise.then((doc) => callback(null, doc), (error) => callback(error));
|
|
22830
|
+
return;
|
|
22831
|
+
}
|
|
22832
|
+
return promise;
|
|
22716
22833
|
}
|
|
22717
|
-
|
|
22718
|
-
|
|
22719
|
-
|
|
22834
|
+
tryNext(callback) {
|
|
22835
|
+
const promise = this._ensureMockLoaded().then(() => this.documents[this.index++] ?? null);
|
|
22836
|
+
if (typeof callback === "function") {
|
|
22837
|
+
promise.then((doc) => callback(null, doc), (error) => callback(error));
|
|
22838
|
+
return;
|
|
22839
|
+
}
|
|
22840
|
+
return promise;
|
|
22720
22841
|
}
|
|
22721
|
-
|
|
22722
|
-
|
|
22723
|
-
|
|
22842
|
+
hasNext(callback) {
|
|
22843
|
+
const promise = this._ensureMockLoaded().then(() => this.index < this.documents.length);
|
|
22844
|
+
if (typeof callback === "function") {
|
|
22845
|
+
promise.then((hasNext) => callback(null, hasNext), (error) => callback(error));
|
|
22846
|
+
return;
|
|
22847
|
+
}
|
|
22848
|
+
return promise;
|
|
22724
22849
|
}
|
|
22725
22850
|
async forEach(fn) {
|
|
22726
22851
|
await this._ensureMockLoaded();
|
|
@@ -22793,7 +22918,14 @@ var TdFakeFindCursor = class TdFakeFindCursor {
|
|
|
22793
22918
|
map() {
|
|
22794
22919
|
return this;
|
|
22795
22920
|
}
|
|
22796
|
-
|
|
22921
|
+
close(callback) {
|
|
22922
|
+
const promise = Promise.resolve();
|
|
22923
|
+
if (typeof callback === "function") {
|
|
22924
|
+
promise.then(() => callback(), (error) => callback(error));
|
|
22925
|
+
return;
|
|
22926
|
+
}
|
|
22927
|
+
return promise;
|
|
22928
|
+
}
|
|
22797
22929
|
rewind() {
|
|
22798
22930
|
this.index = 0;
|
|
22799
22931
|
}
|
|
@@ -22911,45 +23043,6 @@ var TdFakeChangeStream = class {
|
|
|
22911
23043
|
}
|
|
22912
23044
|
};
|
|
22913
23045
|
|
|
22914
|
-
//#endregion
|
|
22915
|
-
//#region src/instrumentation/libraries/mongodb/mocks/FakeTopology.ts
|
|
22916
|
-
/**
|
|
22917
|
-
* Fake MongoDB Topology for replay mode.
|
|
22918
|
-
*
|
|
22919
|
-
* When BulkOperationBase is constructed, it calls getTopology(collection)
|
|
22920
|
-
* which requires a connected topology. In replay mode, no real connection
|
|
22921
|
-
* exists, so we inject this fake topology to satisfy the constructor's
|
|
22922
|
-
* requirements without hitting a real server.
|
|
22923
|
-
*
|
|
22924
|
-
* The constructor reads:
|
|
22925
|
-
* - topology.lastHello() -> returns {} so all size limits use defaults
|
|
22926
|
-
* - topology.lastIsMaster() -> returns {} (legacy compat)
|
|
22927
|
-
* - topology.s.options -> returns {} so autoEncryption check is false
|
|
22928
|
-
*
|
|
22929
|
-
* The topology is also injected onto the shared MongoClient (via
|
|
22930
|
-
* _injectFakeTopology) and persists across requests. Other driver code
|
|
22931
|
-
* (e.g. ClientSession.loadBalanced getter) accesses
|
|
22932
|
-
* topology.description.type, so we provide a minimal description to
|
|
22933
|
-
* prevent TypeError when the property is read.
|
|
22934
|
-
*/
|
|
22935
|
-
var TdFakeTopology = class extends EventEmitter {
|
|
22936
|
-
constructor() {
|
|
22937
|
-
super();
|
|
22938
|
-
this.s = { options: {} };
|
|
22939
|
-
this.description = {
|
|
22940
|
-
type: "Unknown",
|
|
22941
|
-
servers: /* @__PURE__ */ new Map(),
|
|
22942
|
-
hasServer: () => false
|
|
22943
|
-
};
|
|
22944
|
-
}
|
|
22945
|
-
lastHello() {
|
|
22946
|
-
return {};
|
|
22947
|
-
}
|
|
22948
|
-
lastIsMaster() {
|
|
22949
|
-
return {};
|
|
22950
|
-
}
|
|
22951
|
-
};
|
|
22952
|
-
|
|
22953
23046
|
//#endregion
|
|
22954
23047
|
//#region node_modules/bson/lib/bson.cjs
|
|
22955
23048
|
var require_bson = /* @__PURE__ */ __commonJS({ "node_modules/bson/lib/bson.cjs": ((exports) => {
|
|
@@ -26999,7 +27092,8 @@ const COLLECTION_METHODS_TO_WRAP = [
|
|
|
26999
27092
|
"createIndexes",
|
|
27000
27093
|
"dropIndex",
|
|
27001
27094
|
"dropIndexes",
|
|
27002
|
-
"indexes"
|
|
27095
|
+
"indexes",
|
|
27096
|
+
"drop"
|
|
27003
27097
|
];
|
|
27004
27098
|
/**
|
|
27005
27099
|
* Cursor-returning methods on Collection.prototype.
|
|
@@ -27024,6 +27118,12 @@ const DB_METHODS_TO_WRAP = [
|
|
|
27024
27118
|
* Db.prototype methods that return cursors.
|
|
27025
27119
|
*/
|
|
27026
27120
|
const DB_CURSOR_METHODS_TO_WRAP = ["listCollections", "aggregate"];
|
|
27121
|
+
const SUPPORTED_MONGODB_VERSIONS = [
|
|
27122
|
+
"4.*",
|
|
27123
|
+
"5.*",
|
|
27124
|
+
"6.*",
|
|
27125
|
+
"7.*"
|
|
27126
|
+
];
|
|
27027
27127
|
var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
27028
27128
|
constructor(config = {}) {
|
|
27029
27129
|
super("mongodb", config);
|
|
@@ -27035,38 +27135,37 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27035
27135
|
init() {
|
|
27036
27136
|
return [new TdInstrumentationNodeModule({
|
|
27037
27137
|
name: "mongodb",
|
|
27038
|
-
supportedVersions: [
|
|
27039
|
-
|
|
27040
|
-
"6.*",
|
|
27041
|
-
"7.*"
|
|
27042
|
-
],
|
|
27043
|
-
patch: (moduleExports) => this._patchMongodbModule(moduleExports),
|
|
27138
|
+
supportedVersions: [...SUPPORTED_MONGODB_VERSIONS],
|
|
27139
|
+
patch: (moduleExports, moduleVersion) => this._patchMongodbModule(moduleExports, moduleVersion),
|
|
27044
27140
|
files: [
|
|
27045
27141
|
new TdInstrumentationNodeModuleFile({
|
|
27046
27142
|
name: "mongodb/lib/sessions.js",
|
|
27047
|
-
supportedVersions: [
|
|
27048
|
-
|
|
27049
|
-
|
|
27050
|
-
|
|
27051
|
-
|
|
27143
|
+
supportedVersions: [...SUPPORTED_MONGODB_VERSIONS],
|
|
27144
|
+
patch: (moduleExports) => this._patchSessionModule(moduleExports)
|
|
27145
|
+
}),
|
|
27146
|
+
new TdInstrumentationNodeModuleFile({
|
|
27147
|
+
name: "mongodb/lib/sessions",
|
|
27148
|
+
supportedVersions: [...SUPPORTED_MONGODB_VERSIONS],
|
|
27052
27149
|
patch: (moduleExports) => this._patchSessionModule(moduleExports)
|
|
27053
27150
|
}),
|
|
27054
27151
|
new TdInstrumentationNodeModuleFile({
|
|
27055
27152
|
name: "mongodb/lib/bulk/ordered.js",
|
|
27056
|
-
supportedVersions: [
|
|
27057
|
-
|
|
27058
|
-
|
|
27059
|
-
|
|
27060
|
-
|
|
27153
|
+
supportedVersions: [...SUPPORTED_MONGODB_VERSIONS],
|
|
27154
|
+
patch: (moduleExports) => this._patchOrderedBulkModule(moduleExports)
|
|
27155
|
+
}),
|
|
27156
|
+
new TdInstrumentationNodeModuleFile({
|
|
27157
|
+
name: "mongodb/lib/bulk/ordered",
|
|
27158
|
+
supportedVersions: [...SUPPORTED_MONGODB_VERSIONS],
|
|
27061
27159
|
patch: (moduleExports) => this._patchOrderedBulkModule(moduleExports)
|
|
27062
27160
|
}),
|
|
27063
27161
|
new TdInstrumentationNodeModuleFile({
|
|
27064
27162
|
name: "mongodb/lib/bulk/unordered.js",
|
|
27065
|
-
supportedVersions: [
|
|
27066
|
-
|
|
27067
|
-
|
|
27068
|
-
|
|
27069
|
-
|
|
27163
|
+
supportedVersions: [...SUPPORTED_MONGODB_VERSIONS],
|
|
27164
|
+
patch: (moduleExports) => this._patchUnorderedBulkModule(moduleExports)
|
|
27165
|
+
}),
|
|
27166
|
+
new TdInstrumentationNodeModuleFile({
|
|
27167
|
+
name: "mongodb/lib/bulk/unordered",
|
|
27168
|
+
supportedVersions: [...SUPPORTED_MONGODB_VERSIONS],
|
|
27070
27169
|
patch: (moduleExports) => this._patchUnorderedBulkModule(moduleExports)
|
|
27071
27170
|
})
|
|
27072
27171
|
]
|
|
@@ -27077,8 +27176,9 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27077
27176
|
* Wraps MongoClient, Collection, Db, and cursor prototypes to intercept
|
|
27078
27177
|
* all database operations for record/replay.
|
|
27079
27178
|
*/
|
|
27080
|
-
_patchMongodbModule(mongodbModule) {
|
|
27081
|
-
|
|
27179
|
+
_patchMongodbModule(mongodbModule, moduleVersion) {
|
|
27180
|
+
this.mongodbMajorVersion = this._getMajorVersion(moduleVersion);
|
|
27181
|
+
logger.debug(`[${this.INSTRUMENTATION_NAME}] Patching MongoDB module v${moduleVersion || "unknown"} in ${this.mode} mode`);
|
|
27082
27182
|
if (this.isModulePatched(mongodbModule)) {
|
|
27083
27183
|
logger.debug(`[${this.INSTRUMENTATION_NAME}] MongoDB module already patched, skipping`);
|
|
27084
27184
|
return mongodbModule;
|
|
@@ -27145,6 +27245,11 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27145
27245
|
logger.debug(`[${this.INSTRUMENTATION_NAME}] MongoDB module patching complete`);
|
|
27146
27246
|
return mongodbModule;
|
|
27147
27247
|
}
|
|
27248
|
+
_getMajorVersion(version$1) {
|
|
27249
|
+
if (!version$1) return void 0;
|
|
27250
|
+
const major$1 = Number(version$1.split(".")[0]);
|
|
27251
|
+
return Number.isFinite(major$1) ? major$1 : void 0;
|
|
27252
|
+
}
|
|
27148
27253
|
/**
|
|
27149
27254
|
* Patch all Collection.prototype CRUD methods that return Promises.
|
|
27150
27255
|
* Guards each method with typeof check for version compatibility.
|
|
@@ -27170,13 +27275,24 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27170
27275
|
const submodule = `collection-${methodName}`;
|
|
27171
27276
|
return (original) => {
|
|
27172
27277
|
return function(...args) {
|
|
27278
|
+
const callback = args.length > 0 && typeof args[args.length - 1] === "function" ? args[args.length - 1] : void 0;
|
|
27279
|
+
const effectiveArgs = callback ? args.slice(0, -1) : args;
|
|
27173
27280
|
const collectionName = this?.s?.namespace?.collection;
|
|
27174
27281
|
const databaseName = this?.s?.namespace?.db;
|
|
27175
|
-
const inputValue = self._extractCollectionInput(methodName, collectionName, databaseName,
|
|
27282
|
+
const inputValue = self._extractCollectionInput(methodName, collectionName, databaseName, effectiveArgs);
|
|
27176
27283
|
if (self.mode === TuskDriftMode.DISABLED) return original.apply(this, args);
|
|
27177
|
-
|
|
27178
|
-
|
|
27179
|
-
|
|
27284
|
+
const invokeHandler = () => {
|
|
27285
|
+
if (self.mode === TuskDriftMode.RECORD) return self._handleRecordCollectionMethod(original, this, effectiveArgs, inputValue, spanName, submodule);
|
|
27286
|
+
if (self.mode === TuskDriftMode.REPLAY) return self._handleReplayCollectionMethod(original, this, effectiveArgs, inputValue, spanName, submodule, methodName);
|
|
27287
|
+
return original.apply(this, effectiveArgs);
|
|
27288
|
+
};
|
|
27289
|
+
if (callback) {
|
|
27290
|
+
Promise.resolve(invokeHandler()).then((result) => callback(null, result)).catch((error) => callback(error));
|
|
27291
|
+
return;
|
|
27292
|
+
}
|
|
27293
|
+
if (self.mode === TuskDriftMode.RECORD) return invokeHandler();
|
|
27294
|
+
if (self.mode === TuskDriftMode.REPLAY) return invokeHandler();
|
|
27295
|
+
return original.apply(this, effectiveArgs);
|
|
27180
27296
|
};
|
|
27181
27297
|
};
|
|
27182
27298
|
}
|
|
@@ -27199,7 +27315,8 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27199
27315
|
isPreAppStart,
|
|
27200
27316
|
stopRecordingChildSpans: true
|
|
27201
27317
|
}, (spanInfo) => {
|
|
27202
|
-
|
|
27318
|
+
const resultPromise = original.apply(thisArg, args);
|
|
27319
|
+
return Promise.resolve(resultPromise).then((result) => {
|
|
27203
27320
|
try {
|
|
27204
27321
|
addOutputAttributesToSpan(spanInfo, wrapDirectOutput(result));
|
|
27205
27322
|
SpanUtils.endSpan(spanInfo.span, { code: import_src$12.SpanStatusCode.OK });
|
|
@@ -27236,7 +27353,7 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27236
27353
|
},
|
|
27237
27354
|
isServerRequest: false,
|
|
27238
27355
|
replayModeHandler: () => {
|
|
27239
|
-
return SpanUtils.createAndExecuteSpan(this.mode, () =>
|
|
27356
|
+
return SpanUtils.createAndExecuteSpan(this.mode, () => Promise.resolve(this._getNoOpResult(methodName)), {
|
|
27240
27357
|
name: spanName,
|
|
27241
27358
|
kind: import_src$12.SpanKind.CLIENT,
|
|
27242
27359
|
submodule,
|
|
@@ -27391,10 +27508,16 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27391
27508
|
};
|
|
27392
27509
|
if (typeof cursor.toArray === "function") {
|
|
27393
27510
|
const originalToArray = cursor.toArray.bind(cursor);
|
|
27394
|
-
cursor.toArray = () => {
|
|
27395
|
-
if (cursorState.recorded)
|
|
27511
|
+
cursor.toArray = (callback) => {
|
|
27512
|
+
if (cursorState.recorded) {
|
|
27513
|
+
if (typeof callback === "function") {
|
|
27514
|
+
originalToArray().then((result) => callback(null, result)).catch((error) => callback(error));
|
|
27515
|
+
return;
|
|
27516
|
+
}
|
|
27517
|
+
return originalToArray();
|
|
27518
|
+
}
|
|
27396
27519
|
cursorState.recorded = true;
|
|
27397
|
-
|
|
27520
|
+
const resultPromise = import_src$12.context.with(creationContext, () => {
|
|
27398
27521
|
return handleRecordMode({
|
|
27399
27522
|
originalFunctionCall: () => originalToArray(),
|
|
27400
27523
|
recordModeHandler: ({ isPreAppStart }) => {
|
|
@@ -27434,37 +27557,125 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27434
27557
|
spanKind: import_src$12.SpanKind.CLIENT
|
|
27435
27558
|
});
|
|
27436
27559
|
});
|
|
27560
|
+
if (typeof callback === "function") {
|
|
27561
|
+
resultPromise.then((result) => callback(null, result)).catch((error) => callback(error));
|
|
27562
|
+
return;
|
|
27563
|
+
}
|
|
27564
|
+
return resultPromise;
|
|
27437
27565
|
};
|
|
27438
27566
|
}
|
|
27439
27567
|
if (typeof cursor.next === "function") {
|
|
27440
27568
|
const originalNext = cursor.next.bind(cursor);
|
|
27441
|
-
cursor.next =
|
|
27442
|
-
if (
|
|
27443
|
-
|
|
27444
|
-
|
|
27445
|
-
|
|
27569
|
+
cursor.next = (callback) => {
|
|
27570
|
+
if (typeof callback === "function") {
|
|
27571
|
+
if (cursorState.recorded) {
|
|
27572
|
+
let settled$1 = false;
|
|
27573
|
+
const finish$1 = (error, doc) => {
|
|
27574
|
+
if (settled$1) return;
|
|
27575
|
+
settled$1 = true;
|
|
27576
|
+
callback(error, doc);
|
|
27577
|
+
};
|
|
27578
|
+
const maybeResult$1 = originalNext((error, doc) => finish$1(error, doc));
|
|
27579
|
+
Promise.resolve(maybeResult$1).then((doc) => finish$1(null, doc)).catch((error) => finish$1(error, null));
|
|
27580
|
+
return;
|
|
27581
|
+
}
|
|
27582
|
+
if (!import_src$12.context.with(creationContext, () => ensureSpanCreated())) {
|
|
27583
|
+
let settled$1 = false;
|
|
27584
|
+
const finish$1 = (error, doc) => {
|
|
27585
|
+
if (settled$1) return;
|
|
27586
|
+
settled$1 = true;
|
|
27587
|
+
callback(error, doc);
|
|
27588
|
+
};
|
|
27589
|
+
const maybeResult$1 = originalNext((error, doc) => finish$1(error, doc));
|
|
27590
|
+
Promise.resolve(maybeResult$1).then((doc) => finish$1(null, doc)).catch((error) => finish$1(error, null));
|
|
27591
|
+
return;
|
|
27592
|
+
}
|
|
27593
|
+
let settled = false;
|
|
27594
|
+
const finish = (error, doc) => {
|
|
27595
|
+
if (settled) return;
|
|
27596
|
+
settled = true;
|
|
27597
|
+
if (error) {
|
|
27598
|
+
handleCursorError(error);
|
|
27599
|
+
callback(error);
|
|
27600
|
+
return;
|
|
27601
|
+
}
|
|
27602
|
+
if (doc !== null) cursorState.collectedDocuments.push(doc);
|
|
27603
|
+
else finalizeCursorSpan();
|
|
27604
|
+
callback(null, doc);
|
|
27605
|
+
};
|
|
27606
|
+
const runOriginal = () => originalNext((error, doc) => {
|
|
27607
|
+
finish(error, doc);
|
|
27608
|
+
});
|
|
27609
|
+
const maybeResult = cursorState.spanInfo ? SpanUtils.withSpan(cursorState.spanInfo, () => runOriginal()) : runOriginal();
|
|
27610
|
+
Promise.resolve(maybeResult).then((doc) => finish(null, doc)).catch((error) => finish(error, null));
|
|
27611
|
+
return;
|
|
27612
|
+
}
|
|
27613
|
+
if (cursorState.recorded) return callback === void 0 ? originalNext() : originalNext(callback);
|
|
27614
|
+
if (!import_src$12.context.with(creationContext, () => ensureSpanCreated())) return callback === void 0 ? originalNext() : originalNext(callback);
|
|
27615
|
+
return Promise.resolve(cursorState.spanInfo ? SpanUtils.withSpan(cursorState.spanInfo, () => callback === void 0 ? originalNext() : originalNext(callback)) : callback === void 0 ? originalNext() : originalNext(callback)).then((doc) => {
|
|
27446
27616
|
if (doc !== null) cursorState.collectedDocuments.push(doc);
|
|
27447
27617
|
else finalizeCursorSpan();
|
|
27448
27618
|
return doc;
|
|
27449
|
-
}
|
|
27619
|
+
}).catch((error) => {
|
|
27450
27620
|
handleCursorError(error);
|
|
27451
27621
|
throw error;
|
|
27452
|
-
}
|
|
27622
|
+
});
|
|
27453
27623
|
};
|
|
27454
27624
|
}
|
|
27455
27625
|
if (typeof cursor.hasNext === "function") {
|
|
27456
27626
|
const originalHasNext = cursor.hasNext.bind(cursor);
|
|
27457
|
-
cursor.hasNext =
|
|
27458
|
-
if (
|
|
27459
|
-
|
|
27460
|
-
|
|
27461
|
-
|
|
27627
|
+
cursor.hasNext = (callback) => {
|
|
27628
|
+
if (typeof callback === "function") {
|
|
27629
|
+
if (cursorState.recorded) {
|
|
27630
|
+
let settled$1 = false;
|
|
27631
|
+
const finish$1 = (error, result) => {
|
|
27632
|
+
if (settled$1) return;
|
|
27633
|
+
settled$1 = true;
|
|
27634
|
+
callback(error, result);
|
|
27635
|
+
};
|
|
27636
|
+
const maybeResult$1 = originalHasNext((error, result) => finish$1(error, result));
|
|
27637
|
+
Promise.resolve(maybeResult$1).then((result) => finish$1(null, result)).catch((error) => finish$1(error, false));
|
|
27638
|
+
return;
|
|
27639
|
+
}
|
|
27640
|
+
if (!import_src$12.context.with(creationContext, () => ensureSpanCreated())) {
|
|
27641
|
+
let settled$1 = false;
|
|
27642
|
+
const finish$1 = (error, result) => {
|
|
27643
|
+
if (settled$1) return;
|
|
27644
|
+
settled$1 = true;
|
|
27645
|
+
callback(error, result);
|
|
27646
|
+
};
|
|
27647
|
+
const maybeResult$1 = originalHasNext((error, result) => finish$1(error, result));
|
|
27648
|
+
Promise.resolve(maybeResult$1).then((result) => finish$1(null, result)).catch((error) => finish$1(error, false));
|
|
27649
|
+
return;
|
|
27650
|
+
}
|
|
27651
|
+
let settled = false;
|
|
27652
|
+
const finish = (error, result) => {
|
|
27653
|
+
if (settled) return;
|
|
27654
|
+
settled = true;
|
|
27655
|
+
if (error) {
|
|
27656
|
+
handleCursorError(error);
|
|
27657
|
+
callback(error);
|
|
27658
|
+
return;
|
|
27659
|
+
}
|
|
27660
|
+
if (!result) finalizeCursorSpan();
|
|
27661
|
+
callback(null, result);
|
|
27662
|
+
};
|
|
27663
|
+
const runOriginal = () => originalHasNext((error, result) => {
|
|
27664
|
+
finish(error, result);
|
|
27665
|
+
});
|
|
27666
|
+
const maybeResult = cursorState.spanInfo ? SpanUtils.withSpan(cursorState.spanInfo, () => runOriginal()) : runOriginal();
|
|
27667
|
+
Promise.resolve(maybeResult).then((result) => finish(null, result)).catch((error) => finish(error, false));
|
|
27668
|
+
return;
|
|
27669
|
+
}
|
|
27670
|
+
if (cursorState.recorded) return callback === void 0 ? originalHasNext() : originalHasNext(callback);
|
|
27671
|
+
if (!import_src$12.context.with(creationContext, () => ensureSpanCreated())) return callback === void 0 ? originalHasNext() : originalHasNext(callback);
|
|
27672
|
+
return Promise.resolve(cursorState.spanInfo ? SpanUtils.withSpan(cursorState.spanInfo, () => callback === void 0 ? originalHasNext() : originalHasNext(callback)) : callback === void 0 ? originalHasNext() : originalHasNext(callback)).then((result) => {
|
|
27462
27673
|
if (!result) finalizeCursorSpan();
|
|
27463
27674
|
return result;
|
|
27464
|
-
}
|
|
27675
|
+
}).catch((error) => {
|
|
27465
27676
|
handleCursorError(error);
|
|
27466
27677
|
throw error;
|
|
27467
|
-
}
|
|
27678
|
+
});
|
|
27468
27679
|
};
|
|
27469
27680
|
}
|
|
27470
27681
|
if (typeof cursor.forEach === "function") {
|
|
@@ -27520,14 +27731,30 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27520
27731
|
}
|
|
27521
27732
|
if (typeof cursor.close === "function") {
|
|
27522
27733
|
const originalClose = cursor.close.bind(cursor);
|
|
27523
|
-
cursor.close =
|
|
27524
|
-
|
|
27525
|
-
|
|
27734
|
+
cursor.close = (callback) => {
|
|
27735
|
+
if (typeof callback === "function") {
|
|
27736
|
+
let settled = false;
|
|
27737
|
+
const finish = (error) => {
|
|
27738
|
+
if (settled) return;
|
|
27739
|
+
settled = true;
|
|
27740
|
+
if (error) {
|
|
27741
|
+
handleCursorError(error);
|
|
27742
|
+
callback(error);
|
|
27743
|
+
return;
|
|
27744
|
+
}
|
|
27745
|
+
finalizeCursorSpan();
|
|
27746
|
+
callback();
|
|
27747
|
+
};
|
|
27748
|
+
const maybeResult = originalClose((error) => finish(error));
|
|
27749
|
+
Promise.resolve(maybeResult).then(() => finish()).catch((error) => finish(error));
|
|
27750
|
+
return;
|
|
27751
|
+
}
|
|
27752
|
+
return Promise.resolve(callback === void 0 ? originalClose() : originalClose(callback)).then(() => {
|
|
27526
27753
|
finalizeCursorSpan();
|
|
27527
|
-
}
|
|
27754
|
+
}).catch((error) => {
|
|
27528
27755
|
handleCursorError(error);
|
|
27529
27756
|
throw error;
|
|
27530
|
-
}
|
|
27757
|
+
});
|
|
27531
27758
|
};
|
|
27532
27759
|
}
|
|
27533
27760
|
if (typeof cursor[Symbol.asyncIterator] === "function") {
|
|
@@ -27803,6 +28030,7 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27803
28030
|
case "dropIndex": return {};
|
|
27804
28031
|
case "dropIndexes": return { ok: 1 };
|
|
27805
28032
|
case "indexes": return [];
|
|
28033
|
+
case "drop": return true;
|
|
27806
28034
|
default: return null;
|
|
27807
28035
|
}
|
|
27808
28036
|
}
|
|
@@ -27831,18 +28059,29 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27831
28059
|
const submodule = `db-${methodName}`;
|
|
27832
28060
|
return (original) => {
|
|
27833
28061
|
return function(...args) {
|
|
28062
|
+
const callback = args.length > 0 && typeof args[args.length - 1] === "function" ? args[args.length - 1] : void 0;
|
|
28063
|
+
const effectiveArgs = callback ? args.slice(0, -1) : args;
|
|
27834
28064
|
const databaseName = this?.databaseName || this?.s?.namespace?.db;
|
|
27835
|
-
const inputValue = self._extractDbInput(methodName, databaseName,
|
|
28065
|
+
const inputValue = self._extractDbInput(methodName, databaseName, effectiveArgs);
|
|
27836
28066
|
if (self.mode === TuskDriftMode.DISABLED) return original.apply(this, args);
|
|
27837
|
-
|
|
27838
|
-
if (
|
|
27839
|
-
|
|
27840
|
-
|
|
27841
|
-
|
|
27842
|
-
if (
|
|
27843
|
-
|
|
28067
|
+
const invokeHandler = () => {
|
|
28068
|
+
if (self.mode === TuskDriftMode.RECORD) {
|
|
28069
|
+
if (methodName === "createCollection") return self._handleRecordCreateCollection(original, this, effectiveArgs, inputValue, spanName, submodule);
|
|
28070
|
+
return self._handleRecordDbMethod(original, this, effectiveArgs, inputValue, spanName, submodule);
|
|
28071
|
+
}
|
|
28072
|
+
if (self.mode === TuskDriftMode.REPLAY) {
|
|
28073
|
+
if (methodName === "createCollection") return self._handleReplayCreateCollection(this, effectiveArgs, inputValue, spanName, submodule);
|
|
28074
|
+
return self._handleReplayDbMethod(original, this, effectiveArgs, inputValue, spanName, submodule, methodName);
|
|
28075
|
+
}
|
|
28076
|
+
return original.apply(this, effectiveArgs);
|
|
28077
|
+
};
|
|
28078
|
+
if (callback) {
|
|
28079
|
+
Promise.resolve(invokeHandler()).then((result) => callback(null, result)).catch((error) => callback(error));
|
|
28080
|
+
return;
|
|
27844
28081
|
}
|
|
27845
|
-
|
|
28082
|
+
if (self.mode === TuskDriftMode.RECORD) return invokeHandler();
|
|
28083
|
+
if (self.mode === TuskDriftMode.REPLAY) return invokeHandler();
|
|
28084
|
+
return original.apply(this, effectiveArgs);
|
|
27846
28085
|
};
|
|
27847
28086
|
};
|
|
27848
28087
|
}
|
|
@@ -27865,7 +28104,8 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27865
28104
|
isPreAppStart,
|
|
27866
28105
|
stopRecordingChildSpans: true
|
|
27867
28106
|
}, (spanInfo) => {
|
|
27868
|
-
|
|
28107
|
+
const resultPromise = original.apply(thisArg, args);
|
|
28108
|
+
return Promise.resolve(resultPromise).then((result) => {
|
|
27869
28109
|
try {
|
|
27870
28110
|
addOutputAttributesToSpan(spanInfo, wrapDirectOutput(result));
|
|
27871
28111
|
SpanUtils.endSpan(spanInfo.span, { code: import_src$12.SpanStatusCode.OK });
|
|
@@ -27902,7 +28142,7 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27902
28142
|
},
|
|
27903
28143
|
isServerRequest: false,
|
|
27904
28144
|
replayModeHandler: () => {
|
|
27905
|
-
return SpanUtils.createAndExecuteSpan(this.mode, () =>
|
|
28145
|
+
return SpanUtils.createAndExecuteSpan(this.mode, () => Promise.resolve(this._getDbNoOpResult(methodName)), {
|
|
27906
28146
|
name: spanName,
|
|
27907
28147
|
kind: import_src$12.SpanKind.CLIENT,
|
|
27908
28148
|
submodule,
|
|
@@ -27960,7 +28200,8 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
27960
28200
|
isPreAppStart,
|
|
27961
28201
|
stopRecordingChildSpans: true
|
|
27962
28202
|
}, (spanInfo) => {
|
|
27963
|
-
|
|
28203
|
+
const resultPromise = original.apply(thisArg, args);
|
|
28204
|
+
return Promise.resolve(resultPromise).then((result) => {
|
|
27964
28205
|
try {
|
|
27965
28206
|
const collectionName = args[0];
|
|
27966
28207
|
SpanUtils.addSpanAttributes(spanInfo.span, { outputValue: sanitizeBsonValue({ collectionName }) });
|
|
@@ -28224,13 +28465,26 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
28224
28465
|
*/
|
|
28225
28466
|
_getStartSessionWrapper() {
|
|
28226
28467
|
const self = this;
|
|
28468
|
+
const REPLAY_WITH_TXN_PATCHED = Symbol("tdReplayWithTransactionPatched");
|
|
28227
28469
|
return (original) => {
|
|
28228
28470
|
return function(...args) {
|
|
28229
|
-
|
|
28230
|
-
|
|
28231
|
-
|
|
28471
|
+
const session = original.apply(this, args);
|
|
28472
|
+
if (self.mode === TuskDriftMode.REPLAY && self.mongodbMajorVersion === 4 && session && typeof session.withTransaction === "function" && !session[REPLAY_WITH_TXN_PATCHED]) {
|
|
28473
|
+
const originalWithTransaction = session.withTransaction.bind(session);
|
|
28474
|
+
session.withTransaction = async (fn, _options) => {
|
|
28475
|
+
try {
|
|
28476
|
+
await Promise.resolve(fn(session));
|
|
28477
|
+
if (typeof session.commitTransaction === "function") return await session.commitTransaction();
|
|
28478
|
+
return;
|
|
28479
|
+
} catch (error) {
|
|
28480
|
+
if (typeof session.abortTransaction === "function") await session.abortTransaction();
|
|
28481
|
+
throw error;
|
|
28482
|
+
}
|
|
28483
|
+
};
|
|
28484
|
+
session.__tdOriginalWithTransaction = originalWithTransaction;
|
|
28485
|
+
session[REPLAY_WITH_TXN_PATCHED] = true;
|
|
28232
28486
|
}
|
|
28233
|
-
return
|
|
28487
|
+
return session;
|
|
28234
28488
|
};
|
|
28235
28489
|
};
|
|
28236
28490
|
}
|
|
@@ -28306,7 +28560,8 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
28306
28560
|
isPreAppStart,
|
|
28307
28561
|
stopRecordingChildSpans: true
|
|
28308
28562
|
}, (spanInfo) => {
|
|
28309
|
-
|
|
28563
|
+
const resultPromise = original.apply(thisArg, args);
|
|
28564
|
+
return Promise.resolve(resultPromise).then((result) => {
|
|
28310
28565
|
try {
|
|
28311
28566
|
addOutputAttributesToSpan(spanInfo, result ?? { success: true });
|
|
28312
28567
|
SpanUtils.endSpan(spanInfo.span, { code: import_src$12.SpanStatusCode.OK });
|
|
@@ -28341,7 +28596,7 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
28341
28596
|
noOpRequestHandler: () => Promise.resolve(void 0),
|
|
28342
28597
|
isServerRequest: false,
|
|
28343
28598
|
replayModeHandler: () => {
|
|
28344
|
-
return SpanUtils.createAndExecuteSpan(this.mode, () =>
|
|
28599
|
+
return SpanUtils.createAndExecuteSpan(this.mode, () => Promise.resolve(void 0), {
|
|
28345
28600
|
name: spanName,
|
|
28346
28601
|
kind: import_src$12.SpanKind.CLIENT,
|
|
28347
28602
|
submodule,
|
|
@@ -28615,7 +28870,8 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
28615
28870
|
isPreAppStart,
|
|
28616
28871
|
stopRecordingChildSpans: true
|
|
28617
28872
|
}, (spanInfo) => {
|
|
28618
|
-
|
|
28873
|
+
const resultPromise = original.apply(thisArg, args);
|
|
28874
|
+
return Promise.resolve(resultPromise).then((result) => {
|
|
28619
28875
|
try {
|
|
28620
28876
|
addOutputAttributesToSpan(spanInfo, wrapDirectOutput(result));
|
|
28621
28877
|
SpanUtils.endSpan(spanInfo.span, { code: import_src$12.SpanStatusCode.OK });
|
|
@@ -28661,7 +28917,16 @@ var MongodbInstrumentation = class extends TdInstrumentationBase {
|
|
|
28661
28917
|
},
|
|
28662
28918
|
isServerRequest: false,
|
|
28663
28919
|
replayModeHandler: () => {
|
|
28664
|
-
return SpanUtils.createAndExecuteSpan(this.mode, () =>
|
|
28920
|
+
return SpanUtils.createAndExecuteSpan(this.mode, () => Promise.resolve({
|
|
28921
|
+
acknowledged: false,
|
|
28922
|
+
insertedCount: 0,
|
|
28923
|
+
matchedCount: 0,
|
|
28924
|
+
modifiedCount: 0,
|
|
28925
|
+
deletedCount: 0,
|
|
28926
|
+
upsertedCount: 0,
|
|
28927
|
+
insertedIds: {},
|
|
28928
|
+
upsertedIds: {}
|
|
28929
|
+
}), {
|
|
28665
28930
|
name: spanName,
|
|
28666
28931
|
kind: import_src$12.SpanKind.CLIENT,
|
|
28667
28932
|
submodule,
|
|
@@ -40896,7 +41161,7 @@ var require_src = /* @__PURE__ */ __commonJS({ "node_modules/@opentelemetry/sdk-
|
|
|
40896
41161
|
//#endregion
|
|
40897
41162
|
//#region package.json
|
|
40898
41163
|
var import_src$1 = /* @__PURE__ */ __toESM(require_src(), 1);
|
|
40899
|
-
var version = "0.1.
|
|
41164
|
+
var version = "0.1.36";
|
|
40900
41165
|
|
|
40901
41166
|
//#endregion
|
|
40902
41167
|
//#region src/version.ts
|
|
@@ -42797,7 +43062,14 @@ var TuskDriftCore = class TuskDriftCore {
|
|
|
42797
43062
|
logger.info(`Rust core path enabled at startup (env=${envDisplay}, reason=${status.reason}).`);
|
|
42798
43063
|
return;
|
|
42799
43064
|
}
|
|
42800
|
-
logger.
|
|
43065
|
+
logger.info(`Rust core path unavailable at startup; using JavaScript path instead (env=${envDisplay}, reason=${status.reason}, error=${status.bindingError}).`);
|
|
43066
|
+
}
|
|
43067
|
+
logStartupSummary() {
|
|
43068
|
+
const serviceName = this.config.service?.name || "unknown";
|
|
43069
|
+
const serviceId = this.config.service?.id || "<unset>";
|
|
43070
|
+
const environment = this.initParams.env || "<unset>";
|
|
43071
|
+
const exportSpans = this.config.recording?.export_spans || false;
|
|
43072
|
+
logger.info(`SDK initialized successfully (version=${SDK_VERSION}, mode=${this.mode}, env=${environment}, service=${serviceName}, serviceId=${serviceId}, exportSpans=${exportSpans}, samplingRate=${this.samplingRate}, logLevel=${logger.getLogLevel()}, runtime=node ${process.version}, platform=${process.platform}/${process.arch}).`);
|
|
42801
43073
|
}
|
|
42802
43074
|
validateSamplingRate(value, source) {
|
|
42803
43075
|
if (typeof value !== "number" || isNaN(value)) {
|
|
@@ -43044,7 +43316,7 @@ var TuskDriftCore = class TuskDriftCore {
|
|
|
43044
43316
|
this.initializeTracing({ baseDirectory });
|
|
43045
43317
|
this.createEnvVarsSnapshot();
|
|
43046
43318
|
this.initialized = true;
|
|
43047
|
-
|
|
43319
|
+
this.logStartupSummary();
|
|
43048
43320
|
}
|
|
43049
43321
|
markAppAsReady() {
|
|
43050
43322
|
if (!this.initialized) {
|
|
@@ -43180,5 +43452,5 @@ var TuskDriftSDK = class {
|
|
|
43180
43452
|
const TuskDrift = new TuskDriftSDK();
|
|
43181
43453
|
|
|
43182
43454
|
//#endregion
|
|
43183
|
-
export { TuskDrift
|
|
43455
|
+
export { TuskDrift };
|
|
43184
43456
|
//# sourceMappingURL=index.js.map
|