dd-trace 6.7.0 → 6.9.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 (272) hide show
  1. package/ci/diagnose.js +27 -25
  2. package/ci/init.js +6 -6
  3. package/ci/runbook.md +114 -20
  4. package/ci/test-optimization-validation/approval-artifacts.js +36 -3
  5. package/ci/test-optimization-validation/approval.js +78 -22
  6. package/ci/test-optimization-validation/blocker-category.js +24 -0
  7. package/ci/test-optimization-validation/ci-discovery.js +23 -17
  8. package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
  9. package/ci/test-optimization-validation/ci-remediation.js +1 -1
  10. package/ci/test-optimization-validation/cli.js +280 -52
  11. package/ci/test-optimization-validation/command-blocker.js +159 -20
  12. package/ci/test-optimization-validation/command-output-policy.js +14 -8
  13. package/ci/test-optimization-validation/command-runner.js +9 -7
  14. package/ci/test-optimization-validation/environment.js +4 -2
  15. package/ci/test-optimization-validation/executable.js +15 -13
  16. package/ci/test-optimization-validation/execution-lock.js +70 -0
  17. package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
  18. package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
  19. package/ci/test-optimization-validation/framework-adapters/playwright.js +5 -5
  20. package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
  21. package/ci/test-optimization-validation/generated-files.js +47 -37
  22. package/ci/test-optimization-validation/generated-test-contract.js +9 -7
  23. package/ci/test-optimization-validation/generated-verifier.js +24 -17
  24. package/ci/test-optimization-validation/literal-glob.js +52 -0
  25. package/ci/test-optimization-validation/manifest-loader.js +3 -0
  26. package/ci/test-optimization-validation/manifest-scaffold.js +301 -52
  27. package/ci/test-optimization-validation/manifest-schema.js +80 -17
  28. package/ci/test-optimization-validation/offline-fixtures.js +13 -4
  29. package/ci/test-optimization-validation/offline-output.js +6 -6
  30. package/ci/test-optimization-validation/package-check.js +94 -0
  31. package/ci/test-optimization-validation/plan-writer.js +183 -10
  32. package/ci/test-optimization-validation/preflight-runner.js +110 -31
  33. package/ci/test-optimization-validation/project-build-artifact.js +31 -0
  34. package/ci/test-optimization-validation/redaction.js +18 -27
  35. package/ci/test-optimization-validation/report-writer.js +182 -48
  36. package/ci/test-optimization-validation/result-semantics.js +20 -3
  37. package/ci/test-optimization-validation/runner-command.js +41 -21
  38. package/ci/test-optimization-validation/runner-contract.js +79 -43
  39. package/ci/test-optimization-validation/safe-files.js +4 -4
  40. package/ci/test-optimization-validation/scenarios/basic-reporting.js +60 -6
  41. package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
  42. package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
  43. package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
  44. package/ci/test-optimization-validation/static-diagnosis.js +10 -3
  45. package/ci/test-optimization-validation/test-output.js +2 -1
  46. package/ci/test-optimization-validation/validation-blocker.js +21 -0
  47. package/ci/vitest-no-worker-init-setup.mjs +377 -84
  48. package/index.d.ts +175 -14
  49. package/init.js +1 -17
  50. package/initialize.mjs +11 -0
  51. package/loader-hook.mjs +6 -4
  52. package/package.json +12 -4
  53. package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
  54. package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
  55. package/packages/datadog-esbuild/index.js +4 -2
  56. package/packages/datadog-esbuild/src/utils.js +17 -2
  57. package/packages/datadog-instrumentations/src/ai.js +61 -34
  58. package/packages/datadog-instrumentations/src/bluebird.js +6 -6
  59. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +85 -9
  60. package/packages/datadog-instrumentations/src/cucumber.js +131 -51
  61. package/packages/datadog-instrumentations/src/dns.js +21 -2
  62. package/packages/datadog-instrumentations/src/electron.js +1 -0
  63. package/packages/datadog-instrumentations/src/fastify.js +3 -1
  64. package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
  65. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
  66. package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
  67. package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
  68. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  69. package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
  70. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
  71. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  72. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +175 -0
  73. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
  74. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
  75. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +61 -0
  76. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
  77. package/packages/datadog-instrumentations/src/helpers/router-helper.js +38 -7
  78. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
  79. package/packages/datadog-instrumentations/src/http/client.js +1 -3
  80. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
  81. package/packages/datadog-instrumentations/src/jest.js +986 -246
  82. package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
  83. package/packages/datadog-instrumentations/src/mocha/main.js +109 -51
  84. package/packages/datadog-instrumentations/src/mocha/utils.js +120 -32
  85. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +44 -0
  86. package/packages/datadog-instrumentations/src/mocha/worker.js +441 -43
  87. package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
  88. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  89. package/packages/datadog-instrumentations/src/next.js +155 -23
  90. package/packages/datadog-instrumentations/src/openai.js +14 -0
  91. package/packages/datadog-instrumentations/src/pg.js +180 -6
  92. package/packages/datadog-instrumentations/src/playwright.js +176 -81
  93. package/packages/datadog-instrumentations/src/promise-js.js +4 -4
  94. package/packages/datadog-instrumentations/src/promise.js +3 -3
  95. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  96. package/packages/datadog-instrumentations/src/router.js +195 -19
  97. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +567 -65
  98. package/packages/datadog-instrumentations/src/vitest-main.js +438 -54
  99. package/packages/datadog-instrumentations/src/vitest-util.js +42 -7
  100. package/packages/datadog-instrumentations/src/vitest-worker.js +234 -17
  101. package/packages/datadog-instrumentations/src/webdriverio.js +1090 -0
  102. package/packages/datadog-instrumentations/src/when.js +3 -3
  103. package/packages/datadog-instrumentations/src/ws.js +5 -1
  104. package/packages/datadog-plugin-aerospike/src/index.js +1 -3
  105. package/packages/datadog-plugin-amqplib/src/client.js +1 -1
  106. package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
  107. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
  108. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  109. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
  110. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
  111. package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
  112. package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
  113. package/packages/datadog-plugin-child_process/src/index.js +3 -3
  114. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -11
  115. package/packages/datadog-plugin-cucumber/src/index.js +5 -1
  116. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +50 -46
  117. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
  118. package/packages/datadog-plugin-cypress/src/support.js +7 -4
  119. package/packages/datadog-plugin-electron/src/net.js +10 -4
  120. package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
  121. package/packages/datadog-plugin-fs/src/index.js +0 -4
  122. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
  123. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
  124. package/packages/datadog-plugin-graphql/src/execute.js +1 -0
  125. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
  126. package/packages/datadog-plugin-http/src/client.js +3 -2
  127. package/packages/datadog-plugin-http2/src/client.js +1 -1
  128. package/packages/datadog-plugin-jest/src/index.js +3 -21
  129. package/packages/datadog-plugin-jest/src/util.js +4 -1
  130. package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
  131. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  132. package/packages/datadog-plugin-mocha/src/index.js +342 -6
  133. package/packages/datadog-plugin-next/src/index.js +57 -9
  134. package/packages/datadog-plugin-openai/src/tracing.js +4 -0
  135. package/packages/datadog-plugin-pg/src/index.js +65 -1
  136. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  137. package/packages/datadog-plugin-prisma/src/index.js +5 -1
  138. package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
  139. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  140. package/packages/datadog-plugin-undici/src/index.js +2 -1
  141. package/packages/datadog-plugin-vitest/src/index.js +179 -18
  142. package/packages/datadog-shimmer/src/shimmer.js +6 -2
  143. package/packages/datadog-webpack/index.js +2 -2
  144. package/packages/dd-trace/src/aiguard/sdk.js +3 -0
  145. package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
  146. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
  147. package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
  148. package/packages/dd-trace/src/appsec/handlers/http-request.js +215 -0
  149. package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
  150. package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
  151. package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
  152. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  153. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
  154. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
  155. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  156. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
  157. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
  158. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
  159. package/packages/dd-trace/src/appsec/index.js +48 -476
  160. package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -1
  161. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  162. package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
  163. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
  164. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
  165. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -15
  166. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +19 -1
  167. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +25 -1
  168. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
  169. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
  170. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
  171. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
  172. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
  173. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
  174. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +2 -2
  175. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
  176. package/packages/dd-trace/src/config/defaults.js +14 -6
  177. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
  178. package/packages/dd-trace/src/config/helper.js +2 -0
  179. package/packages/dd-trace/src/config/index.js +31 -5
  180. package/packages/dd-trace/src/config/parsers.js +19 -1
  181. package/packages/dd-trace/src/config/remote_config.js +1 -1
  182. package/packages/dd-trace/src/config/supported-configurations.json +13 -6
  183. package/packages/dd-trace/src/datastreams/encoding.js +3 -4
  184. package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
  185. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
  186. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
  187. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
  188. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
  189. package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
  190. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
  191. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  192. package/packages/dd-trace/src/exporters/common/url.js +3 -5
  193. package/packages/dd-trace/src/exporters/electron/index.js +4 -1
  194. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  195. package/packages/dd-trace/src/flare/index.js +2 -2
  196. package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
  197. package/packages/dd-trace/src/guardrails/log.js +1 -10
  198. package/packages/dd-trace/src/id.js +1 -1
  199. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
  200. package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
  201. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
  202. package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
  203. package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
  204. package/packages/dd-trace/src/llmobs/experiments/index.js +66 -19
  205. package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
  206. package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
  207. package/packages/dd-trace/src/llmobs/experiments/util.js +220 -0
  208. package/packages/dd-trace/src/llmobs/noop.js +2 -0
  209. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
  210. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  211. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
  212. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
  213. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
  214. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  215. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  216. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
  217. package/packages/dd-trace/src/llmobs/sdk.js +152 -78
  218. package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
  219. package/packages/dd-trace/src/llmobs/tagger.js +1 -2
  220. package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
  221. package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
  222. package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
  223. package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
  224. package/packages/dd-trace/src/log/channels.js +1 -9
  225. package/packages/dd-trace/src/log/levels.js +12 -0
  226. package/packages/dd-trace/src/noop/proxy.js +2 -2
  227. package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
  228. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  229. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
  230. package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
  231. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  232. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
  233. package/packages/dd-trace/src/opentelemetry/span.js +4 -0
  234. package/packages/dd-trace/src/opentracing/span.js +1 -1
  235. package/packages/dd-trace/src/opentracing/span_context.js +1 -1
  236. package/packages/dd-trace/src/plugins/ci_plugin.js +124 -23
  237. package/packages/dd-trace/src/plugins/index.js +2 -0
  238. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  239. package/packages/dd-trace/src/plugins/tracing.js +1 -0
  240. package/packages/dd-trace/src/plugins/util/ci.js +13 -6
  241. package/packages/dd-trace/src/plugins/util/git.js +7 -5
  242. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +3 -3
  243. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
  244. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  245. package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
  246. package/packages/dd-trace/src/plugins/util/tags.js +2 -0
  247. package/packages/dd-trace/src/plugins/util/test.js +356 -86
  248. package/packages/dd-trace/src/plugins/util/url.js +5 -5
  249. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  250. package/packages/dd-trace/src/plugins/util/web.js +24 -2
  251. package/packages/dd-trace/src/priority_sampler.js +6 -3
  252. package/packages/dd-trace/src/profiler.js +1 -1
  253. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
  254. package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
  255. package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
  256. package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
  257. package/packages/dd-trace/src/proxy.js +1 -0
  258. package/packages/dd-trace/src/ritm.js +10 -20
  259. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
  260. package/packages/dd-trace/src/sampling_rule.js +4 -2
  261. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
  262. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
  263. package/packages/dd-trace/src/startup-log.js +3 -0
  264. package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
  265. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
  266. package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
  267. package/packages/dd-trace/src/util.js +16 -0
  268. package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
  269. package/vendor/dist/pprof-format/index.js +1 -1
  270. package/vendor/dist/source-map/index.js +1 -1
  271. package/version.js +10 -8
  272. /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
@@ -8,7 +8,7 @@ addHook({
8
8
  name: 'when',
9
9
  file: 'lib/Promise.js',
10
10
  versions: ['>=3'],
11
- }, Promise => {
12
- shimmer.wrap(Promise.prototype, 'then', wrapThen)
13
- return Promise
11
+ }, LibraryPromise => {
12
+ shimmer.wrap(LibraryPromise.prototype, 'then', wrapThen)
13
+ return LibraryPromise
14
14
  })
@@ -49,7 +49,11 @@ const setSocketCh = channel('tracing:ws:server:connect:setSocket')
49
49
  */
50
50
 
51
51
  /**
52
- * @typedef {string | Buffer | ArrayBuffer | ArrayBufferView | Blob | Buffer[]} WebSocketMessageData
52
+ * @typedef {{ buffer: ArrayBuffer | SharedArrayBuffer, byteLength: number, byteOffset: number }} BufferView
53
+ */
54
+
55
+ /**
56
+ * @typedef {string | Buffer | ArrayBuffer | BufferView | Blob | Buffer[]} WebSocketMessageData
53
57
  */
54
58
 
55
59
  /**
@@ -67,9 +67,7 @@ function getMeta (resourceName, commandArgs) {
67
67
  const [ns, set, bin, exp, index] = commandArgs
68
68
 
69
69
  // The `ext` argument was added to IndexCreate in 6.3.0
70
- meta = commandArgs.length > 8
71
- ? getMetaForIndex(ns, set, bin, index)
72
- : getMetaForIndex(ns, set, bin, exp)
70
+ meta = getMetaForIndex(ns, set, bin, commandArgs.length > 8 ? index : exp)
73
71
  } else if (resourceName === 'Query') {
74
72
  const { ns, set } = commandArgs[2]
75
73
  meta = getMetaForQuery({ ns, set })
@@ -33,7 +33,7 @@ class AmqplibClientPlugin extends ClientPlugin {
33
33
  },
34
34
  }, ctx)
35
35
 
36
- fields.headers = fields.headers || {}
36
+ fields.headers ||= {}
37
37
 
38
38
  this.tracer.inject(span, TEXT_MAP, fields.headers)
39
39
 
@@ -52,7 +52,7 @@ class AmqplibProducerPlugin extends ProducerPlugin {
52
52
  },
53
53
  }, ctx)
54
54
 
55
- fields.headers = fields.headers || {}
55
+ fields.headers ||= {}
56
56
 
57
57
  this.tracer.inject(span, TEXT_MAP, fields.headers)
58
58
 
@@ -487,16 +487,18 @@ function extractMessagesFromConverseContent (role, contentBlocks) {
487
487
  const toolCalls = []
488
488
  const toolResults = []
489
489
 
490
- for (const block of contentBlocks || []) {
491
- if (block == null || typeof block !== 'object') continue
492
- if (typeof block.text === 'string') {
493
- content += block.text
494
- } else if (block.toolUse) {
495
- toolCalls.push(buildToolCall(block.toolUse))
496
- } else if (block.toolResult) {
497
- toolResults.push(buildToolResult(block.toolResult))
498
- } else {
499
- content += `[Unsupported content type: ${getContentBlockType(block)}]`
490
+ if (contentBlocks) {
491
+ for (const block of contentBlocks) {
492
+ if (block == null || typeof block !== 'object') continue
493
+ if (typeof block.text === 'string') {
494
+ content += block.text
495
+ } else if (block.toolUse) {
496
+ toolCalls.push(buildToolCall(block.toolUse))
497
+ } else if (block.toolResult) {
498
+ toolResults.push(buildToolResult(block.toolResult))
499
+ } else {
500
+ content += `[Unsupported content type: ${getContentBlockType(block)}]`
501
+ }
500
502
  }
501
503
  }
502
504
 
@@ -572,14 +574,17 @@ function buildUsage (usage = {}) {
572
574
  */
573
575
  function extractConverseToolDefinitions (params) {
574
576
  const toolDefinitions = []
575
- for (const tool of params.toolConfig?.tools || []) {
576
- const toolSpec = tool?.toolSpec
577
- if (!toolSpec?.name) continue
578
- toolDefinitions.push({
579
- name: toolSpec.name,
580
- description: toolSpec.description ?? '',
581
- schema: toolSpec.inputSchema ?? {},
582
- })
577
+ const tools = params.toolConfig?.tools
578
+ if (tools) {
579
+ for (const tool of tools) {
580
+ const toolSpec = tool?.toolSpec
581
+ if (!toolSpec?.name) continue
582
+ toolDefinitions.push({
583
+ name: toolSpec.name,
584
+ description: toolSpec.description ?? '',
585
+ schema: toolSpec.inputSchema ?? {},
586
+ })
587
+ }
583
588
  }
584
589
  return toolDefinitions
585
590
  }
@@ -593,13 +598,17 @@ function extractConverseToolDefinitions (params) {
593
598
  */
594
599
  function extractRequestParamsConverse (params) {
595
600
  const prompt = []
596
- for (const block of params.system || []) {
597
- if (typeof block?.text === 'string') prompt.push({ content: block.text, role: 'system' })
601
+ if (params.system) {
602
+ for (const block of params.system) {
603
+ if (typeof block?.text === 'string') prompt.push({ content: block.text, role: 'system' })
604
+ }
598
605
  }
599
- for (const msg of params.messages || []) {
600
- if (msg == null || typeof msg !== 'object') continue
601
- const message = extractMessagesFromConverseContent(msg.role || 'user', msg.content)
602
- if (message) prompt.push(message)
606
+ if (params.messages) {
607
+ for (const msg of params.messages) {
608
+ if (msg == null || typeof msg !== 'object') continue
609
+ const message = extractMessagesFromConverseContent(msg.role || 'user', msg.content)
610
+ if (message) prompt.push(message)
611
+ }
603
612
  }
604
613
 
605
614
  const { temperature, topP, maxTokens, stopSequences } = params.inferenceConfig || {}
@@ -632,7 +641,7 @@ function extractTextAndResponseReasonConverse (response) {
632
641
  * response, spread across start/delta chunks. We reassemble those chunks
633
642
  * into a normalized content-block array and reuse the non-stream extractor.
634
643
  *
635
- * @param {Array<object>} chunks - Ordered ConverseStreamOutput events.
644
+ * @param {Array<object> | undefined} chunks - Ordered ConverseStreamOutput events.
636
645
  * @returns {Generation}
637
646
  */
638
647
  function extractTextAndResponseReasonConverseFromStream (chunks) {
@@ -641,29 +650,31 @@ function extractTextAndResponseReasonConverseFromStream (chunks) {
641
650
  let usage = {}
642
651
  const blocksByIdx = new Map()
643
652
 
644
- for (const chunk of chunks || []) {
645
- if (chunk.messageStart?.role) {
646
- role = chunk.messageStart.role
647
- } else if (chunk.messageStop?.stopReason) {
648
- stopReason = chunk.messageStop.stopReason
649
- } else if (chunk.metadata?.usage) {
650
- usage = chunk.metadata.usage
651
- } else if (chunk.contentBlockStart?.start?.toolUse) {
652
- const { contentBlockIndex, start: { toolUse } } = chunk.contentBlockStart
653
- blocksByIdx.set(contentBlockIndex, {
654
- toolUse: { toolUseId: toolUse.toolUseId, name: toolUse.name, inputStr: '' },
655
- })
656
- } else if (chunk.contentBlockDelta) {
657
- const { contentBlockIndex, delta } = chunk.contentBlockDelta
658
- if (typeof delta?.text === 'string') {
659
- const block = blocksByIdx.get(contentBlockIndex) ?? {}
660
- block.text = (block.text ?? '') + delta.text
661
- blocksByIdx.set(contentBlockIndex, block)
662
- } else if (typeof delta?.toolUse?.input === 'string') {
663
- const block = blocksByIdx.get(contentBlockIndex) ?? { toolUse: { inputStr: '' } }
664
- block.toolUse ??= { inputStr: '' }
665
- block.toolUse.inputStr += delta.toolUse.input
666
- blocksByIdx.set(contentBlockIndex, block)
653
+ if (chunks) {
654
+ for (const chunk of chunks) {
655
+ if (chunk.messageStart?.role) {
656
+ role = chunk.messageStart.role
657
+ } else if (chunk.messageStop?.stopReason) {
658
+ stopReason = chunk.messageStop.stopReason
659
+ } else if (chunk.metadata?.usage) {
660
+ usage = chunk.metadata.usage
661
+ } else if (chunk.contentBlockStart?.start?.toolUse) {
662
+ const { contentBlockIndex, start: { toolUse } } = chunk.contentBlockStart
663
+ blocksByIdx.set(contentBlockIndex, {
664
+ toolUse: { toolUseId: toolUse.toolUseId, name: toolUse.name, inputStr: '' },
665
+ })
666
+ } else if (chunk.contentBlockDelta) {
667
+ const { contentBlockIndex, delta } = chunk.contentBlockDelta
668
+ if (typeof delta?.text === 'string') {
669
+ const block = blocksByIdx.get(contentBlockIndex) ?? {}
670
+ block.text = (block.text ?? '') + delta.text
671
+ blocksByIdx.set(contentBlockIndex, block)
672
+ } else if (typeof delta?.toolUse?.input === 'string') {
673
+ const block = blocksByIdx.get(contentBlockIndex) ?? { toolUse: { inputStr: '' } }
674
+ block.toolUse ??= { inputStr: '' }
675
+ block.toolUse.inputStr += delta.toolUse.input
676
+ blocksByIdx.set(contentBlockIndex, block)
677
+ }
667
678
  }
668
679
  }
669
680
  }
@@ -39,9 +39,9 @@ class EventBridge extends BaseAwsSdkPlugin {
39
39
  const rulename = params.Name ?? ''
40
40
  return {
41
41
  'resource.name': operation ? `${operation} ${params.source}` : params.source,
42
- 'aws.eventbridge.source': `${params.source}`,
42
+ 'aws.eventbridge.source': params.source,
43
43
  'messaging.system': 'aws_eventbridge',
44
- rulename: `${rulename}`,
44
+ rulename,
45
45
  }
46
46
  }
47
47
 
@@ -29,9 +29,9 @@ class Stepfunctions extends BaseAwsSdkPlugin {
29
29
 
30
30
  generateTags (params, operation, response) {
31
31
  if (!params) return
32
- const tags = { 'resource.name': params.name ? `${operation} ${params.name}` : `${operation}` }
32
+ const tags = { 'resource.name': params.name ? `${operation} ${params.name}` : operation }
33
33
  if (operation === 'startExecution' || operation === 'startSyncExecution') {
34
- tags.statemachinearn = `${params.stateMachineArn}`
34
+ tags.statemachinearn = params.stateMachineArn
35
35
  }
36
36
  return tags
37
37
  }
@@ -46,9 +46,7 @@ class AzureEventHubsProducerPlugin extends ProducerPlugin {
46
46
  }
47
47
  injectTraceContext(this.tracer, span, ctx.eventData)
48
48
  }
49
- }
50
-
51
- if (ctx.functionName === 'sendBatch') {
49
+ } else if (ctx.functionName === 'sendBatch') {
52
50
  const eventData = ctx.eventData
53
51
  const eventDataLength = eventData.length || eventData._context.connection._eventsCount
54
52
  span.setTag('messaging.operation', 'send')
@@ -45,9 +45,11 @@ class AzureServiceBusProducerPlugin extends ProducerPlugin {
45
45
  }
46
46
  injectTraceContext(this.tracer, span, ctx.msg)
47
47
  }
48
- }
49
-
50
- if (ctx.functionName === 'send' || ctx.functionName === 'sendBatch' || ctx.functionName === 'scheduleMessages') {
48
+ } else if (
49
+ ctx.functionName === 'send' ||
50
+ ctx.functionName === 'sendBatch' ||
51
+ ctx.functionName === 'scheduleMessages'
52
+ ) {
51
53
  const messages = ctx.msg
52
54
  const isBatch = messages.constructor?.name === 'ServiceBusMessageBatchImpl'
53
55
  if (isBatch) {
@@ -222,7 +222,7 @@ class QueueAddBulkPlugin extends BaseBullmqProducerPlugin {
222
222
  for (let i = 0; i < jobs.length; i++) {
223
223
  const job = jobs[i]
224
224
  if (!job) continue
225
- job.opts = job.opts || {}
225
+ job.opts ||= {}
226
226
  cache[i] = this._injectIntoOpts(span, job.opts)
227
227
  }
228
228
  ctx._ddMetadata = cache
@@ -274,7 +274,7 @@ class FlowProducerAddPlugin extends BaseBullmqProducerPlugin {
274
274
  injectTraceContext (span, ctx) {
275
275
  const flow = ctx.arguments?.[0]
276
276
  if (!flow) return
277
- flow.opts = flow.opts || {}
277
+ flow.opts ||= {}
278
278
  ctx._ddMetadata = this._injectIntoOpts(span, flow.opts)
279
279
  }
280
280
 
@@ -283,7 +283,7 @@ class FlowProducerAddPlugin extends BaseBullmqProducerPlugin {
283
283
  if (!flow) {
284
284
  return { queueName: 'bullmq', payloadSize: 0, optsTarget: undefined }
285
285
  }
286
- flow.opts = flow.opts || {}
286
+ flow.opts ||= {}
287
287
  return {
288
288
  queueName: flow.queueName || 'bullmq',
289
289
  payloadSize: flow.data ? getMessageSize(flow.data) : 0,
@@ -52,7 +52,7 @@ class ChildProcessPlugin extends TracingPlugin {
52
52
  }
53
53
 
54
54
  if (truncated) {
55
- meta['cmd.truncated'] = `${truncated}`
55
+ meta['cmd.truncated'] = 'true'
56
56
  }
57
57
 
58
58
  this.startSpan('command_execution', {
@@ -81,7 +81,7 @@ class ChildProcessPlugin extends TracingPlugin {
81
81
 
82
82
  const span = ctx.currentStore?.span || this.activeSpan
83
83
 
84
- span?.setTag('cmd.exit_code', `${exitCode}`)
84
+ span?.setTag('cmd.exit_code', String(exitCode))
85
85
  span?.finish()
86
86
 
87
87
  return ctx.parentStore
@@ -112,7 +112,7 @@ class ChildProcessPlugin extends TracingPlugin {
112
112
 
113
113
  const span = ctx.currentStore?.span || this.activeSpan
114
114
 
115
- span?.setTag('cmd.exit_code', `${exitCode}`)
115
+ span?.setTag('cmd.exit_code', String(exitCode))
116
116
  span?.finish()
117
117
 
118
118
  return ctx.parentStore
@@ -5,7 +5,7 @@ const shellParser = require('../../../vendor/dist/shell-quote').parse
5
5
  const ALLOWED_ENV_VARIABLES = new Set(['LD_PRELOAD', 'LD_LIBRARY_PATH', 'PATH'])
6
6
  const PROCESS_DENYLIST = new Set(['md5'])
7
7
 
8
- const VARNAMES_REGEX = /\$(\w*)(?:[^\w]|$)/gmi
8
+ const VARNAMES_REGEX = /\$(\w*)(?:[^\w]|$)/gm
9
9
  // eslint-disable-next-line @stylistic/max-len
10
10
  const PARAM_PATTERN = '^-{0,2}(?:p(?:ass(?:w(?:or)?d)?)?|address|api[-_]?key|e?mail|secret(?:[-_]?key)?|a(?:ccess|uth)[-_]?token|mysql_pwd|credentials|(?:stripe)?token)$'
11
11
  const regexParam = new RegExp(PARAM_PATTERN, 'i')
@@ -14,18 +14,15 @@ const envVarRegex = new RegExp(ENV_PATTERN)
14
14
  const REDACTED = '?'
15
15
 
16
16
  function extractVarNames (expression) {
17
- const varNames = new Set()
17
+ const varNames = {}
18
18
  let match
19
19
 
20
20
  while ((match = VARNAMES_REGEX.exec(expression))) {
21
- varNames.add(match[1])
21
+ const name = match[1]
22
+ varNames[name] = `$${name}`
22
23
  }
23
24
 
24
- const varNamesObject = {}
25
- for (const varName of varNames.keys()) {
26
- varNamesObject[varName] = `$${varName}`
27
- }
28
- return varNamesObject
25
+ return varNames
29
26
  }
30
27
 
31
28
  function getTokensByExpression (expressionTokens) {
@@ -61,9 +58,7 @@ function scrubChildProcessCmd (expression) {
61
58
  for (let index = 0; index < expressionTokens.length; index++) {
62
59
  const token = expressionTokens[index]
63
60
 
64
- if (token === null) {
65
- continue
66
- } else if (typeof token === 'object') {
61
+ if (token !== null && typeof token === 'object') {
67
62
  if (token.pattern) {
68
63
  result.push(token.pattern)
69
64
  } else if (token.op) {
@@ -308,6 +308,7 @@ class CucumberPlugin extends CiPlugin {
308
308
  isNew,
309
309
  isEfdRetry,
310
310
  isFlakyRetry,
311
+ isExternalRetry,
311
312
  isAttemptToFix,
312
313
  isAttemptToFixRetry,
313
314
  hasFailedAllRetries,
@@ -348,9 +349,12 @@ class CucumberPlugin extends CiPlugin {
348
349
  span.setTag(ERROR_MESSAGE, errorMessage)
349
350
  }
350
351
 
351
- if (isFlakyRetry > 0) {
352
+ if (isFlakyRetry) {
352
353
  span.setTag(TEST_IS_RETRY, 'true')
353
354
  span.setTag(TEST_RETRY_REASON, TEST_RETRY_REASON_TYPES.atr)
355
+ } else if (isExternalRetry) {
356
+ span.setTag(TEST_IS_RETRY, 'true')
357
+ span.setTag(TEST_RETRY_REASON, TEST_RETRY_REASON_TYPES.ext)
354
358
  }
355
359
 
356
360
  if (hasFailedAllRetries) {
@@ -8,6 +8,12 @@ const dateNow = Date.now
8
8
  const { createCoverageMap } = require('../../../vendor/dist/istanbul-lib-coverage')
9
9
  const satisfies = require('../../../vendor/dist/semifies')
10
10
  const { RUM_TEST_EXECUTION_ID_COOKIE_NAME } = require('../../dd-trace/src/ci-visibility/rum')
11
+ const {
12
+ EMPTY_EFD_RETRY_POLICY,
13
+ getEfdRetryCountForDuration,
14
+ hasEfdRetries,
15
+ shouldSkipEfdRetry,
16
+ } = require('../../dd-trace/src/ci-visibility/efd-retry-policy')
11
17
  const {
12
18
  TEST_STATUS,
13
19
  setRumTestTags,
@@ -73,10 +79,9 @@ const {
73
79
  getIsFaultyEarlyFlakeDetection,
74
80
  DYNAMIC_NAME_RE,
75
81
  recordAttemptToFixExecution,
82
+ recordTestManagementExecution,
76
83
  logAttemptToFixTestExecution,
77
84
  logTestOptimizationSummary,
78
- getEfdRetryCount,
79
- getMaxEfdRetryCount,
80
85
  getPullRequestBaseBranch,
81
86
  TEST_FINAL_STATUS,
82
87
  getTestOptimizationRequestResults,
@@ -465,8 +470,7 @@ class CypressPlugin {
465
470
  isEarlyFlakeDetectionEnabled = false
466
471
  isEarlyFlakeDetectionFaulty = false
467
472
  isKnownTestsEnabled = false
468
- earlyFlakeDetectionNumRetries = 0
469
- earlyFlakeDetectionSlowTestRetries = {}
473
+ earlyFlakeDetectionRetryPolicy = EMPTY_EFD_RETRY_POLICY
470
474
  efdRetryCountByTest = {}
471
475
  efdSlowAbortedTests = {}
472
476
  earlyFlakeDetectionFaultyThreshold = 0
@@ -554,8 +558,7 @@ class CypressPlugin {
554
558
  this.isEarlyFlakeDetectionEnabled = false
555
559
  this.isEarlyFlakeDetectionFaulty = false
556
560
  this.isKnownTestsEnabled = false
557
- this.earlyFlakeDetectionNumRetries = 0
558
- this.earlyFlakeDetectionSlowTestRetries = {}
561
+ this.earlyFlakeDetectionRetryPolicy = EMPTY_EFD_RETRY_POLICY
559
562
  this.efdRetryCountByTest = {}
560
563
  this.efdSlowAbortedTests = {}
561
564
  this.earlyFlakeDetectionFaultyThreshold = 0
@@ -835,8 +838,7 @@ class CypressPlugin {
835
838
  isCodeCoverageEnabled,
836
839
  isCoverageReportUploadEnabled,
837
840
  isEarlyFlakeDetectionEnabled,
838
- earlyFlakeDetectionNumRetries,
839
- earlyFlakeDetectionSlowTestRetries,
841
+ earlyFlakeDetectionRetryPolicy,
840
842
  earlyFlakeDetectionFaultyThreshold,
841
843
  isFlakyTestRetriesEnabled,
842
844
  flakyTestRetriesCount,
@@ -851,8 +853,7 @@ class CypressPlugin {
851
853
  this.isCodeCoverageEnabled = isCodeCoverageEnabled
852
854
  this.isCoverageReportUploadEnabled = isCoverageReportUploadEnabled
853
855
  this.isEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
854
- this.earlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
855
- this.earlyFlakeDetectionSlowTestRetries = earlyFlakeDetectionSlowTestRetries ?? {}
856
+ this.earlyFlakeDetectionRetryPolicy = earlyFlakeDetectionRetryPolicy ?? EMPTY_EFD_RETRY_POLICY
856
857
  this.earlyFlakeDetectionFaultyThreshold = earlyFlakeDetectionFaultyThreshold
857
858
  this.isKnownTestsEnabled = isKnownTestsEnabled
858
859
  if (isFlakyTestRetriesEnabled && this.isTestIsolationEnabled) {
@@ -900,34 +901,6 @@ class CypressPlugin {
900
901
  return { isAttemptToFix, isDisabled, isQuarantined }
901
902
  }
902
903
 
903
- /**
904
- * Returns how many EFD retries must be scheduled before the first duration is known.
905
- *
906
- * @returns {number}
907
- */
908
- getConfiguredEfdRetryCount () {
909
- const { earlyFlakeDetectionSlowTestRetries } = this
910
- if (!earlyFlakeDetectionSlowTestRetries || !Object.keys(earlyFlakeDetectionSlowTestRetries).length) {
911
- return this.earlyFlakeDetectionNumRetries
912
- }
913
- return getMaxEfdRetryCount(earlyFlakeDetectionSlowTestRetries)
914
- }
915
-
916
- /**
917
- * Returns the selected EFD retry count for a test, or the scheduling count if it has not run yet.
918
- *
919
- * @param {string} testSuite
920
- * @param {string} testName
921
- * @returns {number}
922
- */
923
- getEfdRetryCountForTest (testSuite, testName) {
924
- const testSuiteRetries = this.efdRetryCountByTest[testSuite]
925
- if (!testSuiteRetries || testSuiteRetries[testName] === undefined) {
926
- return this.getConfiguredEfdRetryCount()
927
- }
928
- return testSuiteRetries[testName]
929
- }
930
-
931
904
  /**
932
905
  * Stores the selected EFD retry count for a test after its first execution duration is known.
933
906
  *
@@ -940,7 +913,7 @@ class CypressPlugin {
940
913
  if (!this.efdRetryCountByTest[testSuite]) {
941
914
  this.efdRetryCountByTest[testSuite] = {}
942
915
  }
943
- const retryCount = getEfdRetryCount(duration ?? 0, this.earlyFlakeDetectionSlowTestRetries)
916
+ const retryCount = getEfdRetryCountForDuration(duration ?? 0, this.earlyFlakeDetectionRetryPolicy)
944
917
  this.efdRetryCountByTest[testSuite][testName] = retryCount
945
918
  if (retryCount === 0) {
946
919
  if (!this.efdSlowAbortedTests[testSuite]) {
@@ -961,7 +934,7 @@ class CypressPlugin {
961
934
  */
962
935
  shouldSkipEfdRetry (testSuite, testName, efdRetryIndex) {
963
936
  const testSuiteRetries = this.efdRetryCountByTest[testSuite]
964
- return testSuiteRetries?.[testName] !== undefined && efdRetryIndex > testSuiteRetries[testName]
937
+ return shouldSkipEfdRetry(efdRetryIndex, testSuiteRetries?.[testName])
965
938
  }
966
939
 
967
940
  getTestSuiteSpan ({ testSuite, testSuiteAbsolutePath }) {
@@ -1431,7 +1404,8 @@ class CypressPlugin {
1431
1404
  skippedTestSpan.setTag(ITR_CORRELATION_ID, this.itrCorrelationId)
1432
1405
  }
1433
1406
 
1434
- const { isDisabled, isQuarantined } = this.getTestProperties(spec.relative, cypressTestName)
1407
+ const { isAttemptToFix, isDisabled, isQuarantined } =
1408
+ this.getTestProperties(spec.relative, cypressTestName)
1435
1409
 
1436
1410
  if (isDisabled) {
1437
1411
  skippedTestSpan.setTag(TEST_MANAGEMENT_IS_DISABLED, 'true')
@@ -1439,6 +1413,24 @@ class CypressPlugin {
1439
1413
  skippedTestSpan.setTag(TEST_MANAGEMENT_IS_QUARANTINED, 'true')
1440
1414
  }
1441
1415
 
1416
+ recordTestManagementExecution({
1417
+ testSuite: spec.relative,
1418
+ testName: cypressTestName,
1419
+ status: 'skip',
1420
+ isAttemptToFix,
1421
+ isDisabled,
1422
+ isQuarantined,
1423
+ })
1424
+ if (isAttemptToFix) {
1425
+ recordAttemptToFixExecution(this.attemptToFixExecutions, {
1426
+ testSuite: spec.relative,
1427
+ testName: cypressTestName,
1428
+ status: 'skip',
1429
+ isDisabled,
1430
+ isQuarantined,
1431
+ })
1432
+ }
1433
+
1442
1434
  skippedTestSpan.finish()
1443
1435
  }
1444
1436
 
@@ -1522,6 +1514,15 @@ class CypressPlugin {
1522
1514
  finishedTest.testSpan.setTag(TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED, 'false')
1523
1515
  }
1524
1516
  }
1517
+ const testManagementTags = finishedTest.testSpan.context().getTags()
1518
+ recordTestManagementExecution({
1519
+ testSuite: spec.relative,
1520
+ testName,
1521
+ status: testManagementTags[TEST_STATUS] || cypressTestStatus,
1522
+ isAttemptToFix: finishedTest.isAttemptToFix,
1523
+ isDisabled: testManagementTags[TEST_MANAGEMENT_IS_DISABLED] === 'true',
1524
+ isQuarantined: testManagementTags[TEST_MANAGEMENT_IS_QUARANTINED] === 'true',
1525
+ })
1525
1526
  if (this.itrCorrelationId) {
1526
1527
  finishedTest.testSpan.setTag(ITR_CORRELATION_ID, this.itrCorrelationId)
1527
1528
  }
@@ -1671,10 +1672,10 @@ class CypressPlugin {
1671
1672
  return {
1672
1673
  'dd:testSuiteStart': ({ testSuite, testSuiteAbsolutePath }) => {
1673
1674
  const suitePayload = {
1674
- isEarlyFlakeDetectionEnabled: this.isEarlyFlakeDetectionEnabled,
1675
+ isEarlyFlakeDetectionEnabled:
1676
+ this.isEarlyFlakeDetectionEnabled && hasEfdRetries(this.earlyFlakeDetectionRetryPolicy),
1675
1677
  knownTestsForSuite: this.knownTestsByTestSuite?.[testSuite] || [],
1676
- earlyFlakeDetectionNumRetries: this.getConfiguredEfdRetryCount(),
1677
- earlyFlakeDetectionSlowTestRetries: this.earlyFlakeDetectionSlowTestRetries,
1678
+ earlyFlakeDetectionSchedulingRetryCount: this.earlyFlakeDetectionRetryPolicy.schedulingRetryCount,
1678
1679
  isKnownTestsEnabled: this.isKnownTestsEnabled,
1679
1680
  isTestManagementEnabled: this.isTestManagementTestsEnabled,
1680
1681
  testManagementAttemptToFixRetries: this.testManagementAttemptToFixRetries,
@@ -1784,7 +1785,10 @@ class CypressPlugin {
1784
1785
  }
1785
1786
  this.tracer._tracer._exporter.exportCoverage(formattedCoverage)
1786
1787
  }
1787
- const isEfdManagedTest = (isNew || isModified) && this.isEarlyFlakeDetectionEnabled && !isAttemptToFix
1788
+ const isEfdManagedTest = (isNew || isModified) &&
1789
+ this.isEarlyFlakeDetectionEnabled &&
1790
+ hasEfdRetries(this.earlyFlakeDetectionRetryPolicy) &&
1791
+ !isAttemptToFix
1788
1792
  let testStatus = CYPRESS_STATUS_TO_TEST_STATUS[state]
1789
1793
  let didAbortSlowEfdRetries = false
1790
1794
  if (isEfdManagedTest && !isEfdRetry && this.efdRetryCountByTest[testSuite]?.[testName] === undefined) {
@@ -1858,7 +1862,7 @@ class CypressPlugin {
1858
1862
  }
1859
1863
  // Check if all EFD retries failed
1860
1864
  if (isEfdManagedTest) {
1861
- const efdRetryCount = this.getEfdRetryCountForTest(testSuite, testName)
1865
+ const efdRetryCount = this.efdRetryCountByTest[testSuite]?.[testName]
1862
1866
  const isLastEfdAttempt = testStatuses.length === efdRetryCount + 1
1863
1867
  if (efdRetryCount > 0 && isLastEfdAttempt && testStatuses.every(status => status === 'fail')) {
1864
1868
  this.activeTestSpan.setTag(TEST_HAS_FAILED_ALL_RETRIES, 'true')
@@ -61,7 +61,7 @@ function decodeVLQ (str, cursor) {
61
61
  * @returns {string | null}
62
62
  */
63
63
  function resolveSourcePath (mapDir, sourceRoot, sourcePath) {
64
- const cleanSourcePath = sourcePath.replace(/[?#].*$/, '')
64
+ const cleanSourcePath = sourcePath.split(/[?#]/)[0]
65
65
  if (/^[A-Za-z][A-Za-z\d+.-]*:\/\//.test(cleanSourcePath)) {
66
66
  // Virtual sources may use URL-like schemes (e.g. file://, webpack://, vite://).
67
67
  // If they encode an absolute local path in the URL pathname, use it.
@@ -1,12 +1,15 @@
1
1
  'use strict'
2
2
 
3
+ // No optional chaining or nullish coalescing in this file: Cypress 12 bundles it with webpack 4,
4
+ // whose parser predates both, and its babel-loader skips node_modules.
5
+
3
6
  let rumFlushWaitMillis = 500
4
7
  let rumTestExecutionIdCookieName
5
8
 
6
9
  let isEarlyFlakeDetectionEnabled = false
7
10
  let isKnownTestsEnabled = false
8
11
  let knownTestsForSuite = []
9
- let earlyFlakeDetectionNumRetries = 0
12
+ let earlyFlakeDetectionSchedulingRetryCount = 0
10
13
  let isTestManagementEnabled = false
11
14
  let testManagementAttemptToFixRetries = 0
12
15
  let testManagementTests = {}
@@ -336,7 +339,7 @@ Cypress.mocha.getRunner().runTests = function (suite, fn) {
336
339
  } else if (isModified && isEarlyFlakeDetectionEnabled) {
337
340
  disableFrameworkRetries(test)
338
341
  retryMessage = 'to detect flakes because it is modified'
339
- retriedTests = getRetriedTests(test, earlyFlakeDetectionNumRetries, [
342
+ retriedTests = getRetriedTests(test, earlyFlakeDetectionSchedulingRetryCount, [
340
343
  '_ddIsModified',
341
344
  '_ddIsEfdRetry',
342
345
  isKnownTestsEnabled && isNewTest(test) && '_ddIsNew',
@@ -344,7 +347,7 @@ Cypress.mocha.getRunner().runTests = function (suite, fn) {
344
347
  } else if (isNew && isEarlyFlakeDetectionEnabled) {
345
348
  disableFrameworkRetries(test)
346
349
  retryMessage = 'to detect flakes because it is new'
347
- retriedTests = getRetriedTests(test, earlyFlakeDetectionNumRetries, ['_ddIsNew', '_ddIsEfdRetry'])
350
+ retriedTests = getRetriedTests(test, earlyFlakeDetectionSchedulingRetryCount, ['_ddIsNew', '_ddIsEfdRetry'])
348
351
  }
349
352
 
350
353
  testsWithRetries.push(...retriedTests)
@@ -428,7 +431,7 @@ before(function () {
428
431
  isEarlyFlakeDetectionEnabled = suiteConfig.isEarlyFlakeDetectionEnabled
429
432
  isKnownTestsEnabled = suiteConfig.isKnownTestsEnabled
430
433
  knownTestsForSuite = suiteConfig.knownTestsForSuite
431
- earlyFlakeDetectionNumRetries = suiteConfig.earlyFlakeDetectionNumRetries
434
+ earlyFlakeDetectionSchedulingRetryCount = suiteConfig.earlyFlakeDetectionSchedulingRetryCount
432
435
  isTestManagementEnabled = suiteConfig.isTestManagementEnabled
433
436
  testManagementAttemptToFixRetries = suiteConfig.testManagementAttemptToFixRetries
434
437
  testManagementTests = suiteConfig.testManagementTests
@@ -64,12 +64,18 @@ class ElectronRequestPlugin extends HttpClientPlugin {
64
64
  const responseHead = ctx.res?._responseHead
65
65
  const { statusCode } = responseHead || {}
66
66
 
67
- for (const header in ctx.req._urlLoaderOptions?.headers || {}) {
68
- reqHeaders[header.name] = header.value
67
+ const requestHeaders = ctx.req._urlLoaderOptions?.headers
68
+ if (requestHeaders) {
69
+ for (const header in requestHeaders) {
70
+ reqHeaders[header.name] = header.value
71
+ }
69
72
  }
70
73
 
71
- for (const header in responseHead?.rawHeaders || {}) {
72
- resHeaders[header.name] = header.value
74
+ const responseHeaders = responseHead?.rawHeaders
75
+ if (responseHeaders) {
76
+ for (const header in responseHeaders) {
77
+ resHeaders[header.name] = header.value
78
+ }
73
79
  }
74
80
 
75
81
  ctx.req = { headers: reqHeaders }