dd-trace 5.133.0 → 5.134.0

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.
Files changed (55) hide show
  1. package/ci/vitest-no-worker-init-runner-setup.mjs +27 -0
  2. package/index.d.ts +16 -5
  3. package/package.json +17 -16
  4. package/packages/datadog-instrumentations/index.js +2 -1
  5. package/packages/datadog-instrumentations/src/cucumber.js +17 -8
  6. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +27 -8
  7. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  8. package/packages/datadog-instrumentations/src/helpers/register.js +9 -0
  9. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +2 -0
  10. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/jest.js +12 -0
  11. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/vitest.js +8 -0
  12. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +5 -0
  13. package/packages/datadog-instrumentations/src/jest.js +69 -57
  14. package/packages/datadog-instrumentations/src/mocha/utils.js +35 -2
  15. package/packages/datadog-instrumentations/src/nova-sonic/session.js +25 -16
  16. package/packages/datadog-instrumentations/src/playwright.js +2 -0
  17. package/packages/datadog-instrumentations/src/stripe.js +23 -12
  18. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1 -0
  19. package/packages/datadog-instrumentations/src/vitest-main.js +7 -3
  20. package/packages/datadog-instrumentations/src/vitest-util.js +5 -2
  21. package/packages/datadog-instrumentations/src/vitest.js +8 -0
  22. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +3 -0
  23. package/packages/datadog-plugin-cypress/src/support.js +2 -0
  24. package/packages/dd-trace/src/aiguard/evaluation.js +143 -1
  25. package/packages/dd-trace/src/appsec/iast/path-line.js +2 -1
  26. package/packages/dd-trace/src/appsec/stack_trace.js +3 -2
  27. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +3 -2
  28. package/packages/dd-trace/src/config/generated-config-types.d.ts +2 -0
  29. package/packages/dd-trace/src/config/index.js +45 -0
  30. package/packages/dd-trace/src/config/supported-configurations.json +9 -0
  31. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +6 -5
  32. package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -5
  33. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +4 -6
  34. package/packages/dd-trace/src/debugger/unsupported-runtime.js +16 -0
  35. package/packages/dd-trace/src/llmobs/agent-manifest.js +19 -2
  36. package/packages/dd-trace/src/llmobs/constants/tags.js +3 -0
  37. package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +5 -0
  38. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +9 -1
  39. package/packages/dd-trace/src/llmobs/sdk.js +15 -4
  40. package/packages/dd-trace/src/llmobs/span_processor.js +12 -0
  41. package/packages/dd-trace/src/llmobs/tagger.js +18 -8
  42. package/packages/dd-trace/src/llmobs/util.js +10 -4
  43. package/packages/dd-trace/src/openfeature/index.js +6 -0
  44. package/packages/dd-trace/src/openfeature/writers/util.js +4 -4
  45. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +18 -1
  46. package/packages/dd-trace/src/plugin_manager.js +1 -2
  47. package/packages/dd-trace/src/plugins/tracing.js +0 -1
  48. package/packages/dd-trace/src/plugins/util/git.js +91 -35
  49. package/packages/dd-trace/src/plugins/util/stacktrace.js +2 -1
  50. package/packages/dd-trace/src/plugins/util/test.js +2 -0
  51. package/packages/dd-trace/src/plugins/util/web.js +90 -20
  52. package/packages/dd-trace/src/span_stats.js +4 -1
  53. package/packages/dd-trace/src/telemetry/logs/log-collector.js +1 -1
  54. package/packages/dd-trace/src/util.js +8 -4
  55. package/vendor/dist/@apm-js-collab/code-transformer/index.js +8 -8
@@ -2,7 +2,34 @@ try {
2
2
  // Vitest does not expose setFn from its public setup API; keep this optional for strict installers.
3
3
  const vitestRunner = await import('@vitest/runner')
4
4
  globalThis[Symbol.for('dd-trace.vitest.set-fn')] = vitestRunner.setFn
5
+ trackNativeRetryOptions(vitestRunner.getCurrentSuite())
5
6
  } catch {}
6
7
  globalThis[Symbol.for('dd-trace.vitest.browser-context-importer')] = () => import('@vitest/browser/context')
7
8
 
8
9
  await import('./vitest-no-worker-init-setup.mjs')
10
+
11
+ /**
12
+ * Legacy Vitest inherits numeric retries and loses their origin during collection.
13
+ * These collectors and their chainable callbacks are created at runtime.
14
+ * @param {object} collector
15
+ */
16
+ function trackNativeRetryOptions (collector) {
17
+ const original = collector.test.fn
18
+ collector.test.fn = function (name, optionsOrFn, fnOrOptions) {
19
+ const options = optionsOrFn !== null && typeof optionsOrFn === 'object' ? optionsOrFn : fnOrOptions
20
+ const length = collector.tasks.length
21
+ const result = original.apply(this, arguments)
22
+ if ((options?.retry !== undefined || collector.options?.retry !== undefined) && collector.tasks.length > length) {
23
+ const task = collector.tasks.at(-1)
24
+ task.meta = { ...task.meta, __ddTestOptNativeRetry: true }
25
+ }
26
+ return result
27
+ }
28
+ const push = collector.tasks.push
29
+ collector.tasks.push = function (...tasks) {
30
+ for (const task of tasks) {
31
+ if (task.type === 'collector') trackNativeRetryOptions(task)
32
+ }
33
+ return push.apply(this, tasks)
34
+ }
35
+ }
package/index.d.ts CHANGED
@@ -218,6 +218,7 @@ interface Tracer extends opentracing.Tracer {
218
218
  * @env DD_FEATURE_FLAGS_ENABLED
219
219
  * @env DD_FEATURE_FLAGS_CONFIGURATION_SOURCE
220
220
  * @env DD_FLAGGING_EVALUATION_COUNTS_ENABLED
221
+ * @env DD_FEATURE_FLAGS_EXPOSURES_DATADOG_LOGGING_ENABLED
221
222
  */
222
223
  openfeature: tracer.OpenFeatureProvider;
223
224
 
@@ -5076,11 +5077,14 @@ declare namespace tracer {
5076
5077
  }
5077
5078
 
5078
5079
  /**
5079
- * Declares the agent an `agent` span represents, reported as the agent's manifest. Only applies to
5080
- * `agent` spans. Unreportable values are dropped with a warning, and unset values (`undefined`, `null`,
5081
- * `''`, `[]`) leave what an earlier annotation declared in place.
5080
+ * Declares the agent an `agent` span represents. `version` is set as an `agent_version` tag on the agent
5081
+ * span and its child spans within the same process. The other fields are reported as the agent's manifest.
5082
+ * Only applies to `agent` spans. Unreportable values are dropped with a warning, and unset values
5083
+ * (`undefined`, `null`, `''`, `[]`) leave what an earlier annotation declared in place.
5082
5084
  */
5083
5085
  interface Agent {
5086
+ /** The version of the agent. Must not contain a comma. */
5087
+ version?: string,
5084
5088
  /** The agent's name. Defaults to the agent span's name. */
5085
5089
  name?: string,
5086
5090
  /** The system instructions the agent runs with. */
@@ -5176,8 +5180,8 @@ declare namespace tracer {
5176
5180
  prompt?: Prompt,
5177
5181
 
5178
5182
  /**
5179
- * Declares the agent running in this context, read when the context is entered. The manifest is
5180
- * reported on every `agent` span in the context, nested ones included. Use `annotate` on a nested agent
5183
+ * Declares the agent running in this context, read when the context is entered. The version and manifest
5184
+ * are reported on every `agent` span in the context, nested ones included. Use `annotate` on a nested agent
5181
5185
  * span to declare its own agent.
5182
5186
  */
5183
5187
  agent?: Agent,
@@ -5238,6 +5242,13 @@ declare namespace tracer {
5238
5242
  * If not provided for LLM or embedding spans, a default value of 'custom' will be set.
5239
5243
  */
5240
5244
  modelProvider?: string,
5245
+
5246
+ /**
5247
+ * The version of the agent, set as an `agent_version` tag on the agent span and its child spans within the
5248
+ * same process. Must not contain a comma. Only used on `agent` spans, and wins over a version declared by an
5249
+ * enclosing `annotationContext`.
5250
+ */
5251
+ version?: string,
5241
5252
  }
5242
5253
 
5243
5254
  interface LLMObsNamedSpanOptions extends LLMObsSpanOptions {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.133.0",
3
+ "version": "5.134.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -84,8 +84,8 @@
84
84
  "test:integration:appsec:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/appsec/*.spec.js\"",
85
85
  "test:integration:crashtracking": "mocha --timeout 60000 \"integration-tests/crashtracking/*.spec.js\"",
86
86
  "test:integration:bun": "mocha --timeout 60000 \"integration-tests/bun/*.spec.js\"",
87
- "test:integration:cucumber": "mocha --timeout 60000 \"integration-tests/cucumber/*.spec.js\"",
88
- "test:integration:cucumber:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/cucumber/*.spec.js\"",
87
+ "test:integration:cucumber": "mocha --timeout 60000 \"integration-tests/cucumber/${SPEC:-cucumber*}.spec.js\"",
88
+ "test:integration:cucumber:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/cucumber/${SPEC:-cucumber*}.spec.js\"",
89
89
  "test:integration:cypress": "mocha --timeout 60000 \"integration-tests/cypress/${SPEC:-cypress-*}.spec.js\"",
90
90
  "test:integration:cypress:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/cypress/${SPEC:-cypress-*}.spec.js\"",
91
91
  "test:integration:debugger": "mocha --timeout 60000 \"integration-tests/debugger/*.spec.js\"",
@@ -94,24 +94,25 @@
94
94
  "test:integration:esbuild": "mocha --timeout 60000 \"integration-tests/esbuild/*.spec.js\"",
95
95
  "test:integration:esbuild:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/esbuild/*.spec.js\"",
96
96
  "test:integration:turbopack": "mocha --timeout 60000 \"integration-tests/turbopack/*.spec.js\"",
97
+ "test:integration:vite": "mocha --timeout 60000 \"integration-tests/vite/*.spec.js\"",
97
98
  "test:integration:webpack": "mocha --timeout 60000 \"integration-tests/webpack/*.spec.js\"",
98
99
  "test:integration:openfeature": "mocha --timeout 60000 \"integration-tests/openfeature/*.spec.js\"",
99
100
  "test:integration:openfeature:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/openfeature/*.spec.js\"",
100
101
  "test:integration:jest": "mocha --timeout 60000 \"integration-tests/jest/${SPEC:-jest*}.spec.js\"",
101
102
  "test:integration:jest:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/jest/${SPEC:-jest*}.spec.js\"",
102
- "test:integration:mocha": "mocha --timeout 60000 \"integration-tests/mocha/*.spec.js\"",
103
- "test:integration:mocha:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/mocha/*.spec.js\"",
103
+ "test:integration:mocha": "mocha --timeout 60000 \"integration-tests/mocha/${SPEC:-mocha*}.spec.js\"",
104
+ "test:integration:mocha:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/mocha/${SPEC:-mocha*}.spec.js\"",
104
105
  "test:integration:playwright": "mocha --timeout 60000 \"integration-tests/playwright/${SPEC:-playwright-*}.spec.js\"",
105
106
  "test:integration:playwright:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/playwright/${SPEC:-playwright-*}.spec.js\"",
106
107
  "test:integration:selenium": "mocha --timeout 60000 \"integration-tests/selenium/*.spec.js\"",
107
108
  "test:integration:selenium:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/selenium/*.spec.js\"",
108
- "test:integration:test-optimization:helpers": "mocha \"integration-tests/cypress/*dependencies.spec.js\" \"integration-tests/jest/*dependencies.spec.js\" \"integration-tests/playwright/version*.spec.js\"",
109
+ "test:integration:test-optimization:helpers": "mocha \"integration-tests/cypress/*dependencies.spec.js\" \"integration-tests/jest/*dependencies.spec.js\" \"integration-tests/playwright/version*.spec.js\" \"integration-tests/mocha/version*.spec.js\"",
109
110
  "test:integration:webdriverio": "mocha --timeout 60000 \"integration-tests/webdriverio/${SPEC:-*}.spec.js\"",
110
111
  "test:integration:webdriverio:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/webdriverio/${SPEC:-*}.spec.js\"",
111
112
  "test:integration:vitest": "mocha --timeout 60000 \"integration-tests/vitest/${SPEC:-vitest*}.spec.js\"",
112
113
  "test:integration:vitest:coverage": "node ./integration-tests/vitest/run-with-coverage.js --timeout 60000 \"integration-tests/vitest/${SPEC:-vitest*}.spec.js\"",
113
- "test:integration:testopt": "mocha --timeout 120000 \"integration-tests/ci-visibility/*.spec.js\"",
114
- "test:integration:testopt:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 120000 \"integration-tests/ci-visibility/*.spec.js\"",
114
+ "test:integration:testopt": "mocha --timeout 120000 \"integration-tests/ci-visibility/${SPEC:-*}.spec.js\"",
115
+ "test:integration:testopt:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 120000 \"integration-tests/ci-visibility/${SPEC:-*}.spec.js\"",
115
116
  "test:integration:profiler": "mocha --timeout 180000 \"integration-tests/profiler/*.spec.js\"",
116
117
  "test:integration:profiler:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 180000 \"integration-tests/profiler/*.spec.js\"",
117
118
  "test:integration:plugins": "yarn services && mocha \"packages/datadog-plugin-@(${PLUGINS})/test/integration-test/**/${SPEC:-*}*.spec.js\"",
@@ -186,7 +187,7 @@
186
187
  ],
187
188
  "dependencies": {
188
189
  "dc-polyfill": "^0.1.11",
189
- "import-in-the-middle": "3.5.1",
190
+ "import-in-the-middle": "3.5.3",
190
191
  "opentracing": ">=0.14.7"
191
192
  },
192
193
  "optionalDependencies": {
@@ -204,7 +205,7 @@
204
205
  "devDependencies": {
205
206
  "@actions/core": "^3.0.1",
206
207
  "@actions/github": "^9.1.1",
207
- "@babel/helpers": "^8.0.7",
208
+ "@babel/helpers": "^8.0.8",
208
209
  "@eslint/eslintrc": "^3.3.7",
209
210
  "@eslint/js": "^10.0.1",
210
211
  "@eslint/plugin-kit": "^0.7.3",
@@ -215,24 +216,24 @@
215
216
  "@stylistic/eslint-plugin": "^5.10.0",
216
217
  "@types/mocha": "^10.0.10",
217
218
  "@types/node": "^18.19.106",
218
- "@types/sinon": "^22.0.0",
219
+ "@types/sinon": "^22.0.1",
219
220
  "@vercel/nft": "^1.11.0",
220
221
  "@yarnpkg/lockfile": "^1.1.0",
221
222
  "benchmark": "^2.1.4",
222
- "body-parser": "^2.3.0",
223
- "bun": "1.4.3",
223
+ "body-parser": "^2.4.0",
224
+ "bun": "1.4.4",
224
225
  "c8": "^12.0.0",
225
226
  "codeowners-audit": "^2.9.0",
226
227
  "eslint": "^10.13.0",
227
228
  "eslint-plugin-cypress": "^7.0.2",
228
229
  "eslint-plugin-import-x": "^4.16.2",
229
- "eslint-plugin-jsdoc": "^65.3.12",
230
+ "eslint-plugin-jsdoc": "^65.4.2",
230
231
  "eslint-plugin-mocha": "^12.0.2",
231
232
  "eslint-plugin-n": "^18.5.0",
232
233
  "eslint-plugin-promise": "^7.3.0",
233
234
  "eslint-plugin-regexp": "^3.3.1",
234
235
  "eslint-plugin-sonarjs": "^4.2.2",
235
- "eslint-plugin-unicorn": "^74.0.0",
236
+ "eslint-plugin-unicorn": "^78.0.0",
236
237
  "express": "^5.3.0",
237
238
  "glob": "^10.4.5",
238
239
  "globals": "^17.13.0",
@@ -247,7 +248,7 @@
247
248
  "mocha": "^11.8.0",
248
249
  "mocha-junit-reporter": "^2.2.1",
249
250
  "mocha-multi-reporters": "^1.5.2",
250
- "multer": "^2.4.0",
251
+ "multer": "^2.5.0",
251
252
  "nock": "^14.0.17",
252
253
  "node-preload": "^0.2.1",
253
254
  "nyc": "^18.0.0",
@@ -2,4 +2,5 @@
2
2
 
3
3
  require('./src/helpers/bundler-register')
4
4
  require('./src/helpers/register')
5
- require('./src/helpers/rewriter/loader')
5
+ // The extension is required: bundlers that prefer `.mjs` (e.g. Vite) would otherwise pick the ESM loader hook.
6
+ require('./src/helpers/rewriter/loader.js')
@@ -129,6 +129,7 @@ let earlyFlakeDetectionRetryPolicy = EMPTY_EFD_RETRY_POLICY
129
129
  let earlyFlakeDetectionFaultyThreshold = 0
130
130
  let isEarlyFlakeDetectionFaulty = false
131
131
  let isFlakyTestRetriesEnabled = false
132
+ let hasAutomaticRetries = false
132
133
  let isDynamicAtrEnabled = false
133
134
  let dynamicAtrBuckets
134
135
  let isKnownTestsEnabled = false
@@ -255,6 +256,7 @@ function configureParallelWorkerWorldParameters (options) {
255
256
  }
256
257
 
257
258
  options.worldParameters._ddIsFlakyTestRetriesEnabled = isFlakyTestRetriesEnabled
259
+ options.worldParameters._ddHasAutomaticRetries = hasAutomaticRetries
258
260
  options.worldParameters._ddNumTestRetries = numTestRetries
259
261
  options.worldParameters._ddIsDynamicAtrEnabled = isDynamicAtrEnabled
260
262
  options.worldParameters._ddDynamicAtrBuckets = dynamicAtrBuckets
@@ -298,6 +300,7 @@ function readParallelWorkerWorldParameters (options) {
298
300
  /**
299
301
  * @param {object} worldParameters
300
302
  * @param {boolean} [worldParameters._ddIsFlakyTestRetriesEnabled]
303
+ * @param {boolean} [worldParameters._ddHasAutomaticRetries]
301
304
  * @param {number} [worldParameters._ddNumTestRetries]
302
305
  * @param {boolean} [worldParameters._ddIsDynamicAtrEnabled]
303
306
  * @param {number[]} [worldParameters._ddDynamicAtrBuckets]
@@ -306,6 +309,7 @@ function readParallelWorkerWorldParameters (options) {
306
309
  */
307
310
  function readParallelWorkerAtrParameters (worldParameters) {
308
311
  isFlakyTestRetriesEnabled = !!worldParameters._ddIsFlakyTestRetriesEnabled
312
+ hasAutomaticRetries = !!worldParameters._ddHasAutomaticRetries
309
313
  numTestRetries = worldParameters._ddNumTestRetries ?? 0
310
314
  isDynamicAtrEnabled = !!worldParameters._ddIsDynamicAtrEnabled
311
315
  dynamicAtrBuckets = worldParameters._ddDynamicAtrBuckets
@@ -741,9 +745,10 @@ function publishRetriedAttempt (runner, state) {
741
745
  const nextAttempt = currentAttempt + 1
742
746
  const failedAttemptCtx = numAttemptToCtx.get(currentAttempt)
743
747
  const isFirstAttempt = currentAttempt === 0
744
- const isAtrRetry = !isFirstAttempt && isFlakyTestRetriesEnabled
748
+ const isAtrRetry = !isFirstAttempt && state.hasAutomaticRetries
745
749
 
746
750
  if (isFirstAttempt && isDynamicAtrEnabled && isFlakyTestRetriesEnabled) {
751
+ state.hasAutomaticRetries = true
747
752
  state.dynamicAtrRetryCount = getDynamicAtrRetryCount(
748
753
  performance.now() - state.executionStart,
749
754
  earlyFlakeDetectionRetryPolicy,
@@ -755,7 +760,7 @@ function publishRetriedAttempt (runner, state) {
755
760
  }
756
761
 
757
762
  // ATR: record this attempt as failed so when run().finally runs (after retry) we have all statuses
758
- if (isFlakyTestRetriesEnabled) {
763
+ if (state.hasAutomaticRetries) {
759
764
  const nameForKey = getCucumberTestName(runner.pickle.name, currentAttempt > 0)
760
765
  const atrKey = `${runner.pickle.uri}:${nameForKey}`
761
766
  if (atrStatusesByScenarioKey.has(atrKey)) {
@@ -831,7 +836,7 @@ function wrapRun (pl, isLatestVersion, version) {
831
836
  }
832
837
  const ctx = testStartPayload
833
838
  const promises = {}
834
- const state = { numAttempt: 0, promises, testStartPayload }
839
+ const state = { numAttempt: 0, promises, testStartPayload, hasAutomaticRetries }
835
840
  numAttemptToCtx.set(state.numAttempt, ctx)
836
841
  runnerToRetryState.set(this, state)
837
842
  if (isTestManagementTestsEnabled && getTestProperties(testSuitePath, this.pickle.name).attemptToFix) {
@@ -961,7 +966,7 @@ function wrapRun (pl, isLatestVersion, version) {
961
966
 
962
967
  // ATR: accumulate statuses by stable scenario key (uri:name) so retries are grouped.
963
968
  // Cucumber appends " (attempt N)" or " (attempt N, retried)" to the scenario name; normalize for keying.
964
- if (isFlakyTestRetriesEnabled && !isAttemptToFix && !isEfdRetry && numTestRetries > 0) {
969
+ if (state.hasAutomaticRetries && !isAttemptToFix && !isEfdRetry && numTestRetries > 0) {
965
970
  const atrKey = `${this.pickle.uri}:${testName}`
966
971
  if (atrStatusesByScenarioKey.has(atrKey)) {
967
972
  atrStatusesByScenarioKey.get(atrKey).push(status)
@@ -1010,7 +1015,7 @@ function wrapRun (pl, isLatestVersion, version) {
1010
1015
 
1011
1016
  // Notice that ATR is handled using cucumber native retries features.
1012
1017
  // Therefore, if we reach this point, we are certain that it's the last ATR execution
1013
- const isLastAtrRetry = isFlakyTestRetriesEnabled && !isAttemptToFix && !isEfdRetry &&
1018
+ const isLastAtrRetry = state.hasAutomaticRetries && !isAttemptToFix && !isEfdRetry &&
1014
1019
  numTestRetries > 0 && this.maxAttempts > 1
1015
1020
 
1016
1021
  const statuses = lastStatusByPickleId.get(this.pickle.id)
@@ -1039,8 +1044,8 @@ function wrapRun (pl, isLatestVersion, version) {
1039
1044
  error,
1040
1045
  isNew,
1041
1046
  isEfdRetry,
1042
- isFlakyRetry: state.numAttempt > 0 && isFlakyTestRetriesEnabled,
1043
- isExternalRetry: state.numAttempt > 0 && !isFlakyTestRetriesEnabled,
1047
+ isFlakyRetry: state.numAttempt > 0 && state.hasAutomaticRetries,
1048
+ isExternalRetry: state.numAttempt > 0 && !state.hasAutomaticRetries,
1044
1049
  isAttemptToFix,
1045
1050
  isAttemptToFixRetry,
1046
1051
  hasFailedAllRetries,
@@ -1261,7 +1266,9 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1261
1266
  const processArgv = process.argv.slice(2).join(' ')
1262
1267
  const command = getEnvironmentVariable('npm_lifecycle_script') || `cucumber-js ${processArgv}`
1263
1268
 
1264
- if (isFlakyTestRetriesEnabled && !options.retry && numTestRetries > 0) {
1269
+ const originalRetryCount = options.retry
1270
+ hasAutomaticRetries = isFlakyTestRetriesEnabled && !options.retry && numTestRetries > 0
1271
+ if (hasAutomaticRetries) {
1265
1272
  options.retry = numTestRetries
1266
1273
  }
1267
1274
 
@@ -1303,6 +1310,8 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1303
1310
  log.error('Cucumber test session finalization error: %s', finalizationError)
1304
1311
  }
1305
1312
  throw error
1313
+ } finally {
1314
+ if (hasAutomaticRetries) options.retry = originalRetryCount
1306
1315
  }
1307
1316
  const success = satisfies(frameworkVersion, '>=13.1.0') ? result.success : result
1308
1317
 
@@ -4,7 +4,7 @@ const Module = require('module')
4
4
  const dc = require('dc-polyfill')
5
5
 
6
6
  const log = require('../../../dd-trace/src/log')
7
- const { activate, loadChannel } = require('./register.js')
7
+ const { activate, loadChannel, registeredBuiltinNames } = require('./register.js')
8
8
  const {
9
9
  filename,
10
10
  getDisabledInstrumentations,
@@ -17,25 +17,44 @@ const { isRewriteActivationEnabled } = require('./rewriter/targets')
17
17
  const disabledInstrumentations = getDisabledInstrumentations()
18
18
 
19
19
  // register.js has now set up ritm (require-in-the-middle). In bundled
20
- // environments (webpack, esbuild), Node.js built-in modules required by
21
- // dd-trace internal modules (e.g. http from request.js) may have been loaded
22
- // before ritm was active. The bundler's module cache then returns those
23
- // pre-loaded modules for any subsequent require() calls, bypassing ritm.
24
- // Re-requiring them via the real Module.prototype.require ensures ritm applies
25
- // their instrumentation hooks.
20
+ // environments (webpack, esbuild, Turbopack), Node.js built-ins required by the
21
+ // application or by dd-trace itself may have been loaded and cached by the
22
+ // bundle before ritm was active, bypassing it. Re-requiring them via the real
23
+ // Module.prototype.require lets ritm apply their hooks to the shared exports.
26
24
  //
27
25
  // In regular Node.js, `module` is an instance of Module. In bundlers, the
28
26
  // module wrapper object is a plain object (not a Module instance), so we use
29
27
  // that to detect a bundled context and avoid unintended side-effects in
30
28
  // normal Node.js (e.g. shimmer-wrapping http before ESM modules load).
31
29
  if (!(module instanceof Module)) {
32
- for (const name of ['http', 'https']) {
30
+ patchLoadedBuiltins()
31
+ }
32
+
33
+ function patchLoadedBuiltins () {
34
+ // A built-in nobody has loaded cannot be cached by the bundle yet, and a later require reaches ritm, so it is
35
+ // skipped. moduleLoadList is undocumented: if it ever disappears, every registered built-in is loaded instead.
36
+ // @ts-expect-error - process.moduleLoadList is not typed
37
+ const { moduleLoadList } = process
38
+ const loadedBuiltins = Array.isArray(moduleLoadList) ? moduleLoadList : undefined
39
+
40
+ let patched = false
41
+ for (const name of registeredBuiltinNames) {
42
+ if (loadedBuiltins?.includes(`NativeModule ${name}`) === false) continue
43
+
33
44
  try {
34
45
  Module.prototype.require.call(module, name)
46
+ patched = true
35
47
  } catch {
36
48
  // Built-in not available in this environment, skip
37
49
  }
38
50
  }
51
+
52
+ if (!patched) return
53
+ try {
54
+ Module.syncBuiltinESMExports()
55
+ } catch (error) {
56
+ log.error('Error synchronizing bundled built-in ESM exports: %s', String(error?.message ?? error), error)
57
+ }
39
58
  }
40
59
 
41
60
  const CHANNEL = 'dd-trace:bundler:load'
@@ -97,6 +97,7 @@ module.exports = {
97
97
  'jest-config': () => require('../jest'),
98
98
  'jest-environment-node': () => require('../jest'),
99
99
  'jest-environment-jsdom': () => require('../jest'),
100
+ 'jest-runner': () => require('../jest'),
100
101
  'jest-runtime': () => require('../jest'),
101
102
  'jest-worker': () => require('../jest'),
102
103
  knex: () => require('../knex'),
@@ -15,6 +15,7 @@ const {
15
15
  } = require('./instrumentation-utils')
16
16
  const rewriter = require('./rewriter')
17
17
  const { getActivationSetup } = require('./rewriter/instrumentation-registry')
18
+ const { isNodeBuiltinModuleName } = require('./shared-utils')
18
19
 
19
20
  const DD_TRACE_DEBUG = getValueFromEnvSources('DD_TRACE_DEBUG')
20
21
 
@@ -61,6 +62,11 @@ const alreadyLoggedIncompatibleIntegrations = new Set()
61
62
  const compatibleOrchestrionTargets = new Set()
62
63
  /** @type {Set<(activation: import('./rewriter/instrumentation-registry').Activation) => void>} */
63
64
  const blockedActivationSetups = new Set()
65
+ /**
66
+ * Node.js built-ins that passed the disabled and serverless checks and received a hook.
67
+ * @type {string[]}
68
+ */
69
+ const registeredBuiltinNames = []
64
70
 
65
71
  /**
66
72
  * @param {string} moduleName
@@ -124,6 +130,8 @@ for (const name of names) {
124
130
  hook = hook.fn
125
131
  }
126
132
 
133
+ if (isNodeBuiltinModuleName(name)) registeredBuiltinNames.push(name)
134
+
127
135
  Hook([name], hookOptions, (moduleExports, moduleName, moduleBaseDir, moduleVersion, isIitm) => {
128
136
  // All loaded versions are first expected to fail instrumentation.
129
137
  if (!instrumentedIntegrationsSuccess.has(`${name}@${moduleVersion}`)) {
@@ -214,4 +222,5 @@ module.exports = {
214
222
  filename,
215
223
  pathSepExpr,
216
224
  loadChannel,
225
+ registeredBuiltinNames,
217
226
  }
@@ -32,6 +32,7 @@ const registry = [
32
32
  },
33
33
  { instrumentations: require('./instrumentations/graphql') },
34
34
  { instrumentations: require('./instrumentations/graphql-jit') },
35
+ { instrumentations: require('./instrumentations/jest') },
35
36
  { activate: true, instrumentations: require('./instrumentations/langchain') },
36
37
  { activate: true, instrumentations: require('./instrumentations/langgraph') },
37
38
  { activate: true, instrumentations: require('./instrumentations/mercurius') },
@@ -39,6 +40,7 @@ const registry = [
39
40
  { instrumentations: require('./instrumentations/openai-agents') },
40
41
  { instrumentations: require('./instrumentations/playwright') },
41
42
  { activate: true, instrumentations: require('./instrumentations/postgres') },
43
+ { instrumentations: require('./instrumentations/vitest') },
42
44
  { instrumentations: require('./instrumentations/webdriverio') },
43
45
  {
44
46
  activate: { setup: () => require('../../aws-durable-execution-sdk-js') },
@@ -0,0 +1,12 @@
1
+ 'use strict'
2
+
3
+ module.exports = [
4
+ ['>=24.8.0 <30.0.0', 'build/runTest.js'],
5
+ ['>=30.0.0', 'build/index.js'],
6
+ ['>=30.0.0', 'build/testWorker.js'],
7
+ ].map(([versionRange, filePath]) => ({
8
+ module: { name: 'jest-runner', versionRange, filePath },
9
+ // Wrap the returned promise so completion covers both successful and failed teardown.
10
+ functionQuery: { functionName: 'runTestInternal', kind: 'Sync' },
11
+ channelName: 'runTestInternal',
12
+ }))
@@ -0,0 +1,8 @@
1
+ 'use strict'
2
+
3
+ module.exports = ['dist/index.js', 'dist/chunk-hooks.js'].map(filePath => ({
4
+ module: { name: '@vitest/runner', versionRange: '>=1.6.0 <4.1.0', filePath },
5
+ astQuery: 'FunctionDeclaration[id.name="createSuiteCollector"] ' +
6
+ 'VariableDeclarator[id.name="task"] > FunctionExpression',
7
+ channelName: 'createTestTask',
8
+ }))
@@ -41,6 +41,8 @@
41
41
  "@supabase/realtime-js/dist/module/RealtimeChannel.js": "@supabase/realtime-js",
42
42
  "@supabase/storage-js/dist/index.cjs": "@supabase/storage-js",
43
43
  "@supabase/storage-js/dist/index.mjs": "@supabase/storage-js",
44
+ "@vitest/runner/dist/chunk-hooks.js": "@vitest/runner",
45
+ "@vitest/runner/dist/index.js": "@vitest/runner",
44
46
  "@wdio/cli/build/index.js": "@wdio/cli",
45
47
  "@wdio/config/build/node/index.js": "@wdio/config",
46
48
  "@wdio/jasmine-framework/build/index.js": "@wdio/jasmine-framework",
@@ -76,6 +78,9 @@
76
78
  "graphql/validation/validate.js": "graphql",
77
79
  "graphql/validation/validate.mjs": "graphql",
78
80
  "jasmine-core/lib/jasmine-core/jasmine.js": "jasmine-core",
81
+ "jest-runner/build/index.js": "jest-runner",
82
+ "jest-runner/build/runTest.js": "jest-runner",
83
+ "jest-runner/build/testWorker.js": "jest-runner",
79
84
  "mercurius/index.js": "mercurius",
80
85
  "playwright-core/lib/coreBundle.js": "playwright-core",
81
86
  "playwright/lib/common/config.js": "playwright",