dd-trace 6.6.0 → 6.8.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 (209) hide show
  1. package/ci/diagnose.js +162 -21
  2. package/ci/init.js +0 -1
  3. package/ci/runbook.md +187 -180
  4. package/ci/test-optimization-validation/approval-artifacts.js +3 -1
  5. package/ci/test-optimization-validation/approval.js +52 -15
  6. package/ci/test-optimization-validation/ci-command-candidate.js +26 -32
  7. package/ci/test-optimization-validation/ci-discovery.js +1 -1
  8. package/ci/test-optimization-validation/ci-package-scripts.js +141 -0
  9. package/ci/test-optimization-validation/ci-remediation.js +112 -39
  10. package/ci/test-optimization-validation/cli.js +516 -681
  11. package/ci/test-optimization-validation/command-blocker.js +188 -33
  12. package/ci/test-optimization-validation/command-output-policy.js +8 -31
  13. package/ci/test-optimization-validation/command-runner.js +189 -245
  14. package/ci/test-optimization-validation/environment.js +90 -0
  15. package/ci/test-optimization-validation/executable.js +159 -388
  16. package/ci/test-optimization-validation/framework-adapters/cucumber.js +119 -0
  17. package/ci/test-optimization-validation/framework-adapters/cypress.js +107 -0
  18. package/ci/test-optimization-validation/framework-adapters/playwright.js +181 -0
  19. package/ci/test-optimization-validation/generated-files.js +84 -22
  20. package/ci/test-optimization-validation/generated-test-contract.js +281 -0
  21. package/ci/test-optimization-validation/generated-verifier.js +49 -16
  22. package/ci/test-optimization-validation/literal-environment.js +57 -0
  23. package/ci/test-optimization-validation/manifest-loader.js +2 -22
  24. package/ci/test-optimization-validation/manifest-scaffold.js +815 -515
  25. package/ci/test-optimization-validation/manifest-schema.js +494 -702
  26. package/ci/test-optimization-validation/offline-fixtures.js +4 -1
  27. package/ci/test-optimization-validation/offline-output.js +6 -6
  28. package/ci/test-optimization-validation/plan-writer.js +243 -984
  29. package/ci/test-optimization-validation/preflight-runner.js +49 -55
  30. package/ci/test-optimization-validation/redaction.js +2 -1
  31. package/ci/test-optimization-validation/report-writer.js +391 -1357
  32. package/ci/test-optimization-validation/result-semantics.js +86 -0
  33. package/ci/test-optimization-validation/runner-command.js +249 -0
  34. package/ci/test-optimization-validation/runner-contract.js +664 -0
  35. package/ci/test-optimization-validation/safe-files.js +4 -4
  36. package/ci/test-optimization-validation/scenarios/auto-test-retries.js +29 -3
  37. package/ci/test-optimization-validation/scenarios/basic-reporting.js +240 -543
  38. package/ci/test-optimization-validation/scenarios/ci-wiring.js +450 -670
  39. package/ci/test-optimization-validation/scenarios/early-flake-detection.js +4 -3
  40. package/ci/test-optimization-validation/scenarios/helpers.js +67 -9
  41. package/ci/test-optimization-validation/scenarios/test-management.js +6 -5
  42. package/ci/test-optimization-validation/source-text.js +87 -0
  43. package/ci/test-optimization-validation/test-output.js +12 -22
  44. package/ci/vitest-no-worker-init-setup.mjs +348 -51
  45. package/ext/tags.d.ts +1 -0
  46. package/index.d.ts +84 -13
  47. package/package.json +10 -4
  48. package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
  49. package/packages/datadog-esbuild/index.js +4 -2
  50. package/packages/datadog-esbuild/src/utils.js +1 -1
  51. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +4 -4
  52. package/packages/datadog-instrumentations/src/cucumber.js +9 -6
  53. package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
  54. package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
  55. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  56. package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
  57. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +1 -0
  58. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  59. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/openai-agents.js +31 -0
  60. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +57 -0
  61. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
  62. package/packages/datadog-instrumentations/src/helpers/router-helper.js +1 -1
  63. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
  64. package/packages/datadog-instrumentations/src/http/client.js +1 -3
  65. package/packages/datadog-instrumentations/src/jest.js +8 -14
  66. package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
  67. package/packages/datadog-instrumentations/src/mocha/main.js +2 -42
  68. package/packages/datadog-instrumentations/src/mocha/utils.js +68 -2
  69. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +19 -0
  70. package/packages/datadog-instrumentations/src/mocha/worker.js +446 -42
  71. package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
  72. package/packages/datadog-instrumentations/src/openai-agents.js +159 -0
  73. package/packages/datadog-instrumentations/src/playwright.js +3 -2
  74. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  75. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +525 -56
  76. package/packages/datadog-instrumentations/src/vitest-main.js +90 -10
  77. package/packages/datadog-instrumentations/src/webdriverio.js +914 -0
  78. package/packages/datadog-plugin-aerospike/src/index.js +1 -3
  79. package/packages/datadog-plugin-amqplib/src/client.js +1 -1
  80. package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
  81. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  82. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
  83. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
  84. package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
  85. package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
  86. package/packages/datadog-plugin-child_process/src/index.js +3 -3
  87. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +5 -8
  88. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
  89. package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
  90. package/packages/datadog-plugin-fs/src/index.js +0 -4
  91. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
  92. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
  93. package/packages/datadog-plugin-graphql/src/execute.js +1 -0
  94. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
  95. package/packages/datadog-plugin-http/src/client.js +2 -1
  96. package/packages/datadog-plugin-jest/src/index.js +2 -3
  97. package/packages/datadog-plugin-jest/src/util.js +2 -1
  98. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  99. package/packages/datadog-plugin-mocha/src/index.js +25 -6
  100. package/packages/datadog-plugin-openai-agents/src/index.js +74 -0
  101. package/packages/datadog-plugin-openai-agents/src/integration.js +503 -0
  102. package/packages/datadog-plugin-openai-agents/src/processor.js +108 -0
  103. package/packages/datadog-plugin-openai-agents/src/util.js +60 -0
  104. package/packages/datadog-plugin-prisma/src/index.js +5 -1
  105. package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
  106. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  107. package/packages/datadog-plugin-undici/src/index.js +2 -1
  108. package/packages/datadog-plugin-vitest/src/index.js +84 -11
  109. package/packages/datadog-webpack/index.js +2 -2
  110. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
  111. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  112. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
  113. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  114. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
  115. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  116. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
  117. package/packages/dd-trace/src/appsec/sdk/track_event.js +1 -1
  118. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  119. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
  120. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +50 -51
  121. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -1
  122. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +4 -0
  123. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
  124. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
  125. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +161 -33
  126. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
  127. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +7 -5
  128. package/packages/dd-trace/src/config/defaults.js +14 -6
  129. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
  130. package/packages/dd-trace/src/config/index.js +15 -0
  131. package/packages/dd-trace/src/config/parsers.js +19 -1
  132. package/packages/dd-trace/src/config/supported-configurations.json +12 -6
  133. package/packages/dd-trace/src/datastreams/encoding.js +3 -4
  134. package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
  135. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
  136. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
  137. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
  138. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
  139. package/packages/dd-trace/src/encode/span-stats.js +7 -1
  140. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  141. package/packages/dd-trace/src/exporter.js +16 -9
  142. package/packages/dd-trace/src/exporters/common/url.js +3 -5
  143. package/packages/dd-trace/src/exporters/electron/index.js +4 -1
  144. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  145. package/packages/dd-trace/src/flare/index.js +2 -2
  146. package/packages/dd-trace/src/id.js +1 -1
  147. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
  148. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
  149. package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
  150. package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
  151. package/packages/dd-trace/src/llmobs/experiments/index.js +51 -12
  152. package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
  153. package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
  154. package/packages/dd-trace/src/llmobs/experiments/util.js +218 -0
  155. package/packages/dd-trace/src/llmobs/index.js +9 -1
  156. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +104 -22
  157. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
  158. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
  159. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  160. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  161. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +5 -9
  162. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +20 -0
  163. package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +321 -0
  164. package/packages/dd-trace/src/llmobs/sdk.js +6 -12
  165. package/packages/dd-trace/src/llmobs/span_processor.js +14 -7
  166. package/packages/dd-trace/src/llmobs/tagger.js +24 -5
  167. package/packages/dd-trace/src/llmobs/util.js +56 -3
  168. package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
  169. package/packages/dd-trace/src/noop/proxy.js +2 -2
  170. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +3 -6
  171. package/packages/dd-trace/src/openfeature/configuration_source.js +5 -8
  172. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +5 -1
  173. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  174. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
  175. package/packages/dd-trace/src/opentracing/span.js +1 -1
  176. package/packages/dd-trace/src/opentracing/span_context.js +1 -1
  177. package/packages/dd-trace/src/plugins/ci_plugin.js +114 -23
  178. package/packages/dd-trace/src/plugins/index.js +2 -0
  179. package/packages/dd-trace/src/plugins/outbound.js +4 -1
  180. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  181. package/packages/dd-trace/src/plugins/tracing.js +1 -0
  182. package/packages/dd-trace/src/plugins/util/ci.js +7 -6
  183. package/packages/dd-trace/src/plugins/util/git.js +1 -1
  184. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +1 -1
  185. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  186. package/packages/dd-trace/src/plugins/util/tags.js +2 -0
  187. package/packages/dd-trace/src/plugins/util/test.js +38 -12
  188. package/packages/dd-trace/src/plugins/util/url.js +5 -5
  189. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  190. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  191. package/packages/dd-trace/src/priority_sampler.js +6 -3
  192. package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
  193. package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
  194. package/packages/dd-trace/src/ritm.js +5 -20
  195. package/packages/dd-trace/src/span_processor.js +1 -1
  196. package/packages/dd-trace/src/span_stats.js +22 -4
  197. package/packages/dd-trace/src/startup-log.js +3 -0
  198. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
  199. package/packages/dd-trace/src/util.js +16 -0
  200. package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
  201. package/vendor/dist/pprof-format/index.js +1 -1
  202. package/vendor/dist/source-map/index.js +1 -1
  203. package/ci/test-optimization-validation/command-suitability.js +0 -471
  204. package/ci/test-optimization-validation/init-probe-preload.js +0 -163
  205. package/ci/test-optimization-validation/init-probe.js +0 -246
  206. package/ci/test-optimization-validation/late-initialization.js +0 -63
  207. package/ci/test-optimization-validation/local-command.js +0 -163
  208. package/ci/test-optimization-validation/setup-runner.js +0 -97
  209. package/ci/test-optimization-validation-manifest.schema.json +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "6.6.0",
3
+ "version": "6.8.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -96,6 +96,9 @@
96
96
  "test:integration:playwright:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/playwright/${SPEC:-playwright-*}.spec.js\"",
97
97
  "test:integration:selenium": "mocha --timeout 60000 \"integration-tests/selenium/*.spec.js\"",
98
98
  "test:integration:selenium:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/selenium/*.spec.js\"",
99
+ "test:integration:test-optimization:helpers": "mocha \"integration-tests/cypress/*dependencies.spec.js\" \"integration-tests/jest/*dependencies.spec.js\" \"integration-tests/playwright/version*.spec.js\"",
100
+ "test:integration:webdriverio": "mocha --timeout 60000 \"integration-tests/webdriverio/*.spec.js\"",
101
+ "test:integration:webdriverio:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/webdriverio/*.spec.js\"",
99
102
  "test:integration:vitest": "mocha --timeout 60000 \"integration-tests/vitest/${SPEC:-vitest*}.spec.js\"",
100
103
  "test:integration:vitest:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/vitest/${SPEC:-vitest*}.spec.js\"",
101
104
  "test:integration:testopt": "mocha --timeout 120000 \"integration-tests/ci-visibility/*.spec.js\"",
@@ -178,7 +181,7 @@
178
181
  "@datadog/native-appsec": "11.0.1",
179
182
  "@datadog/native-iast-taint-tracking": "4.2.0",
180
183
  "@datadog/native-metrics": "3.1.2",
181
- "@datadog/openfeature-node-server": "2.0.0",
184
+ "@datadog/openfeature-node-server": "2.0.2",
182
185
  "@datadog/pprof": "5.17.0",
183
186
  "@datadog/wasm-js-rewriter": "5.0.1",
184
187
  "@opentelemetry/api": ">=1.0.0 <1.10.0",
@@ -198,7 +201,8 @@
198
201
  "@types/mocha": "^10.0.10",
199
202
  "@types/node": "^18.19.106",
200
203
  "@types/sinon": "^22.0.0",
201
- "@vercel/nft": "^0.29.4",
204
+ "@vercel/nft": "^1.10.2",
205
+ "@yarnpkg/lockfile": "^1.1.0",
202
206
  "axios": "^1.18.1",
203
207
  "benchmark": "^2.1.4",
204
208
  "body-parser": "^2.3.0",
@@ -213,7 +217,7 @@
213
217
  "eslint-plugin-n": "^18.2.1",
214
218
  "eslint-plugin-promise": "^7.3.0",
215
219
  "eslint-plugin-sonarjs": "^4.2.0",
216
- "eslint-plugin-unicorn": "^68.0.0",
220
+ "eslint-plugin-unicorn": "^72.0.0",
217
221
  "express": "^5.1.0",
218
222
  "glob": "^10.4.5",
219
223
  "globals": "^17.7.0",
@@ -221,7 +225,9 @@
221
225
  "husky": "^9.1.7",
222
226
  "istanbul-lib-report": "^3.0.0",
223
227
  "istanbul-reports": "^3.0.2",
228
+ "jsonc-parser": "^3.3.1",
224
229
  "jszip": "^3.10.1",
230
+ "minimatch": "^10.2.5",
225
231
  "mocha": "^11.7.6",
226
232
  "mocha-junit-reporter": "^2.2.1",
227
233
  "mocha-multi-reporters": "^1.5.1",
@@ -5,10 +5,16 @@ module.exports = function kebabcase (str) {
5
5
  throw new TypeError('Expected a string')
6
6
  }
7
7
 
8
- return str
8
+ const kebab = str
9
9
  .trim()
10
10
  .replaceAll(/([a-z])([A-Z])/g, '$1-$2') // Convert camelCase to kebab-case
11
11
  .replaceAll(/[\s_]+/g, '-') // Replace spaces and underscores with a single dash
12
- .replaceAll(/^-+|-+$/g, '') // Trim leading and trailing dashes
13
12
  .toLowerCase()
13
+
14
+ // Trim by index; a `/-+$/` regex re-examines the dash run once per start position.
15
+ let start = 0
16
+ let end = kebab.length
17
+ while (kebab.charCodeAt(start) === 45) start++ // '-'
18
+ while (end > start && kebab.charCodeAt(end - 1) === 45) end--
19
+ return kebab.slice(start, end)
14
20
  }
@@ -265,10 +265,12 @@ ${build.initialOptions.banner.js}`
265
265
  }
266
266
  }
267
267
  // The file namespace is used when requiring files from disk in userland
268
+ if (extracted.pkg === null) return
269
+
268
270
  let pathToPackageJson
269
271
  try {
270
272
  // we can't use require.resolve('pkg/package.json') as ESM modules don't make the file available
271
- pathToPackageJson = require.resolve(`${extracted.pkg}`, { paths: [args.resolveDir] })
273
+ pathToPackageJson = require.resolve(extracted.pkg, { paths: [args.resolveDir] })
272
274
  pathToPackageJson = extractPackageAndModulePath(pathToPackageJson).pkgJson
273
275
  } catch (err) {
274
276
  if (err.code === 'MODULE_NOT_FOUND') {
@@ -340,7 +342,7 @@ ${build.initialOptions.banner.js}`
340
342
 
341
343
  if (data.isESM) {
342
344
  if (args.path.endsWith(ESM_INTERCEPTED_SUFFIX)) {
343
- args.path = args.path.slice(0, -1 * ESM_INTERCEPTED_SUFFIX.length)
345
+ args.path = args.path.slice(0, -ESM_INTERCEPTED_SUFFIX.length)
344
346
 
345
347
  if (data.internal) {
346
348
  args.path = args.path.slice(INTERNAL_ESM_INTERCEPTED_PREFIX.length)
@@ -174,7 +174,7 @@ async function processModule ({ path, internal = false, context, excludeDefault
174
174
  for (const n of exportNames) {
175
175
  if (n === 'default' && excludeDefault) continue
176
176
 
177
- if (isStarExportLine(n) === true) {
177
+ if (isStarExportLine(n)) {
178
178
  // export * from 'wherever'
179
179
  const [, modFile] = n.split('* from ')
180
180
 
@@ -54,7 +54,7 @@ function buildTracerHooks (sessionCtx) {
54
54
  sessionCtx.cwd = input.cwd
55
55
  sessionCtx.transcriptPath = input.transcript_path
56
56
  sessionCtx.agentType = input.agent_type
57
- sessionCtx.permissionMode = sessionCtx.permissionMode || input.permission_mode
57
+ sessionCtx.permissionMode ||= input.permission_mode
58
58
  return {}
59
59
  }
60
60
 
@@ -64,8 +64,8 @@ function buildTracerHooks (sessionCtx) {
64
64
  }
65
65
 
66
66
  function onUserPromptSubmit (input) {
67
- sessionCtx.sessionId = sessionCtx.sessionId || input.session_id
68
- sessionCtx.prompt = sessionCtx.prompt || input.prompt
67
+ sessionCtx.sessionId ||= input.session_id
68
+ sessionCtx.prompt ||= input.prompt
69
69
  return {}
70
70
  }
71
71
 
@@ -254,7 +254,7 @@ function createStreamLookup (chunks) {
254
254
  scanLocalLifecycle(chunks, startIndex, toolUseId, localLifecycle)
255
255
  if (localLifecycle.toolResultIndex !== undefined) return localLifecycle
256
256
 
257
- streamIndex = streamIndex || buildStreamIndex(chunks)
257
+ streamIndex ||= buildStreamIndex(chunks)
258
258
  const indexedLifecycle = streamIndex.get(toolUseId)
259
259
  return {
260
260
  taskStartedChunk: localLifecycle.taskStartedChunk || indexedLifecycle?.taskStartedChunk,
@@ -6,6 +6,7 @@ const { createCoverageMap } = require('../../../vendor/dist/istanbul-lib-coverag
6
6
  const shimmer = require('../../datadog-shimmer')
7
7
  const log = require('../../dd-trace/src/log')
8
8
  const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
9
+ const { getSegment } = require('../../dd-trace/src/util')
9
10
  const {
10
11
  getCoveredFilesFromCoverage,
11
12
  getExecutableFilesFromCoverage,
@@ -342,7 +343,7 @@ function handleParallelTestCaseFinished (pickle, worstTestStepResult) {
342
343
  }
343
344
 
344
345
  const testFileAbsolutePath = pickle.uri
345
- const finished = pickleResultByFile[testFileAbsolutePath] || (pickleResultByFile[testFileAbsolutePath] = [])
346
+ const finished = (pickleResultByFile[testFileAbsolutePath] ||= [])
346
347
 
347
348
  if (isEarlyFlakeDetectionEnabled && isNew) {
348
349
  const testFullname = `${pickle.uri}:${pickle.name}`
@@ -555,8 +556,7 @@ function getErrorFromCucumberResult (cucumberResult) {
555
556
  return
556
557
  }
557
558
 
558
- const [message] = cucumberResult.message.split('\n')
559
- const error = new Error(message)
559
+ const error = new Error(getSegment(cucumberResult.message, '\n', 0))
560
560
  if (cucumberResult.exception) {
561
561
  error.type = cucumberResult.exception.type
562
562
  }
@@ -696,7 +696,7 @@ function publishRetriedAttempt (runner, state) {
696
696
 
697
697
  // ATR: record this attempt as failed so when run().finally runs (after retry) we have all statuses
698
698
  if (isFlakyTestRetriesEnabled) {
699
- const nameForKey = runner.pickle.name.replace(/\s*\(attempt \d+(?:, retried)?\)\s*$/, '')
699
+ const nameForKey = runner.pickle.name.replace(/ ?\(attempt \d+(?:, retried)?\) ?$/, '')
700
700
  const atrKey = `${runner.pickle.uri}:${nameForKey}`
701
701
  if (atrStatusesByScenarioKey.has(atrKey)) {
702
702
  atrStatusesByScenarioKey.get(atrKey).push('fail')
@@ -793,7 +793,7 @@ function wrapRun (pl, isLatestVersion, version) {
793
793
  testFnCh.runStores(ctx, () => {
794
794
  promise = run.apply(this, args)
795
795
  })
796
- promise.finally(async () => {
796
+ const finalize = async () => {
797
797
  if (!canAwaitRetries) {
798
798
  this.eventBroadcaster.removeListener('envelope', onEnvelope)
799
799
  }
@@ -889,7 +889,7 @@ function wrapRun (pl, isLatestVersion, version) {
889
889
  // ATR: accumulate statuses by stable scenario key (uri:name) so retries are grouped.
890
890
  // Cucumber appends " (attempt N)" or " (attempt N, retried)" to the scenario name; normalize for keying.
891
891
  if (isFlakyTestRetriesEnabled && !isAttemptToFix && !isEfdRetry && numTestRetries > 0) {
892
- const nameForKey = this.pickle.name.replace(/\s*\(attempt \d+(?:, retried)?\)\s*$/, '')
892
+ const nameForKey = this.pickle.name.replace(/ ?\(attempt \d+(?:, retried)?\) ?$/, '')
893
893
  const atrKey = `${this.pickle.uri}:${nameForKey}`
894
894
  if (atrStatusesByScenarioKey.has(atrKey)) {
895
895
  atrStatusesByScenarioKey.get(atrKey).push(status)
@@ -966,6 +966,9 @@ function wrapRun (pl, isLatestVersion, version) {
966
966
  ...attemptCtx.currentStore,
967
967
  finalStatus,
968
968
  })
969
+ }
970
+ promise.then(finalize, finalize).catch(error => {
971
+ log.error('Cucumber test finalization error', error)
969
972
  })
970
973
  return promise
971
974
  } catch (err) {
@@ -2,11 +2,21 @@
2
2
 
3
3
  const NM = 'node_modules/'
4
4
 
5
+ /**
6
+ * @typedef {object} PackageAndModulePath
7
+ * @property {string|null} pkg
8
+ * @property {string|null} path
9
+ * @property {string} [pkgJson]
10
+ */
11
+
5
12
  /**
6
13
  * For a given full path to a module,
7
14
  * return the package name it belongs to and the local path to the module
8
15
  * input: '/foo/node_modules/@co/stuff/foo/bar/baz.js'
9
16
  * output: { pkg: '@co/stuff', path: 'foo/bar/baz.js', pkgJson: '/foo/node_modules/@co/stuff/package.json' }
17
+ *
18
+ * @param {string} fullPath
19
+ * @returns {PackageAndModulePath}
10
20
  */
11
21
  module.exports = function extractPackageAndModulePath (fullPath) {
12
22
  const nm = fullPath.lastIndexOf(NM)
@@ -6,6 +6,7 @@ const iitm = require('../../../dd-trace/src/iitm')
6
6
  const ritm = require('../../../dd-trace/src/ritm')
7
7
  const log = require('../../../dd-trace/src/log')
8
8
  const requirePackageJson = require('../../../dd-trace/src/require-package-json')
9
+ const { isNodeBuiltinModuleName } = require('./shared-utils')
9
10
 
10
11
  /**
11
12
  * @param {string} moduleBaseDir
@@ -82,7 +83,7 @@ function Hook (modules, hookOptions, onrequire) {
82
83
  moduleVersion ||= getVersion(moduleBaseDir)
83
84
  } catch (error) {
84
85
  log.error('Error getting version for "%s": %s', moduleName, error.message, error)
85
- return
86
+ return moduleExports
86
87
  }
87
88
 
88
89
  if (
@@ -101,7 +102,23 @@ function Hook (modules, hookOptions, onrequire) {
101
102
  }
102
103
  }
103
104
 
104
- const newExports = wrappedOnrequire(moduleExports, moduleName, moduleBaseDir, moduleVersion, isIitm)
105
+ // A builtin's named ESM exports are a second view of what `default` already points at, and
106
+ // `patched` cannot relate them because it keys on the object the hook ran against.
107
+ let newExports
108
+ if (defaultWrapResult && isNodeBuiltinModuleName(moduleName)) {
109
+ // Accessor exports are read, not skipped: `replaceGetter` leaves Node 20's `fs.opendir`
110
+ // an accessor, and Node's ESM facade resolved every export before handing us this view.
111
+ for (const key of Object.keys(defaultWrapResult)) {
112
+ const wrapped = defaultWrapResult[key]
113
+ const existing = moduleExports[key]
114
+ if (existing !== wrapped && existing !== undefined) {
115
+ moduleExports[key] = wrapped
116
+ }
117
+ }
118
+ newExports = moduleExports
119
+ } else {
120
+ newExports = wrappedOnrequire(moduleExports, moduleName, moduleBaseDir, moduleVersion, isIitm)
121
+ }
105
122
 
106
123
  if (defaultWrapResult && defaultExportAliases) {
107
124
  newExports.default = defaultWrapResult
@@ -21,6 +21,8 @@ module.exports = {
21
21
  '@apollo/gateway': () => require('../apollo'),
22
22
  '@langchain/langgraph': { esmFirst: true, fn: () => require('../langgraph') },
23
23
  '@modelcontextprotocol/sdk': { esmFirst: true, fn: () => require('../modelcontextprotocol-sdk') },
24
+ '@openai/agents': () => require('../openai-agents'),
25
+ '@openai/agents-openai': () => require('../openai-agents'),
24
26
  'apollo-server-core': () => require('../apollo-server-core'),
25
27
  '@aws-sdk/smithy-client': () => require('../aws-sdk'),
26
28
  '@aws/durable-execution-sdk-js': () => require('../aws-durable-execution-sdk-js'),
@@ -56,6 +58,8 @@ module.exports = {
56
58
  '@smithy/core': () => require('../aws-sdk'),
57
59
  '@smithy/smithy-client': () => require('../aws-sdk'),
58
60
  '@vitest/runner': { esmFirst: true, fn: () => require('../vitest') },
61
+ '@wdio/cli': { esmFirst: true, fn: () => require('../webdriverio') },
62
+ '@wdio/local-runner': { esmFirst: true, fn: () => require('../webdriverio') },
59
63
  aerospike: () => require('../aerospike'),
60
64
  ai: () => require('../ai'),
61
65
  amqp10: () => require('../amqp10'),
@@ -57,19 +57,23 @@ const alreadyLoggedIncompatibleIntegrations = new Set()
57
57
  // Always disable prefixed and unprefixed node modules if one is disabled.
58
58
  if (disabledInstrumentations.size) {
59
59
  const builtinsSet = new Set(builtinModules)
60
+ const disabledBuiltinCounterparts = []
60
61
  for (const name of disabledInstrumentations) {
61
62
  const hasPrefix = name.startsWith('node:')
62
63
  if (hasPrefix || builtinsSet.has(name)) {
63
64
  if (hasPrefix) {
64
65
  const unprefixedName = name.slice(5)
65
66
  if (!disabledInstrumentations.has(unprefixedName)) {
66
- disabledInstrumentations.add(unprefixedName)
67
+ disabledBuiltinCounterparts.push(unprefixedName)
67
68
  }
68
69
  } else if (!disabledInstrumentations.has(`node:${name}`)) {
69
- disabledInstrumentations.add(`node:${name}`)
70
+ disabledBuiltinCounterparts.push(`node:${name}`)
70
71
  }
71
72
  }
72
73
  }
74
+ for (const name of disabledBuiltinCounterparts) {
75
+ disabledInstrumentations.add(name)
76
+ }
73
77
  builtinsSet.clear()
74
78
  }
75
79
 
@@ -163,7 +167,9 @@ function logAbortedIntegrations () {
163
167
  for (const [nameVersion, success] of instrumentedIntegrationsSuccess) {
164
168
  // Only ever log a single version of an integration, even if it is loaded later.
165
169
  if (!success && !alreadyLoggedIncompatibleIntegrations.has(nameVersion)) {
166
- const [name, version] = nameVersion.split('@')
170
+ const lastAtPosition = nameVersion.lastIndexOf('@')
171
+ const name = nameVersion.slice(0, lastAtPosition)
172
+ const version = nameVersion.slice(lastAtPosition + 1)
167
173
  telemetry('abort.integration', [
168
174
  `integration:${name}`,
169
175
  `integration_version:${version}`,
@@ -39,6 +39,7 @@ for (const matcher of [matcherCjs, matcherEsm]) {
39
39
 
40
40
  // Keep the marker split: source-map scanners can read a contiguous token in
41
41
  // string literals as this file's own inline map.
42
+ // eslint-disable-next-line unicorn/no-useless-concat -- Keep the source-map marker non-contiguous.
42
43
  const SOURCE_MAP_PREFIX = '//# sourceMapping' + 'URL=data:application/json;base64,'
43
44
 
44
45
  function rewrite (content, filename, format) {
@@ -10,6 +10,8 @@ module.exports = [
10
10
  ...require('./langgraph'),
11
11
  ...require('./mercurius'),
12
12
  ...require('./modelcontextprotocol-sdk'),
13
+ ...require('./openai-agents'),
13
14
  ...require('./playwright'),
15
+ ...require('./webdriverio'),
14
16
  ...require('./aws-durable-execution-sdk-js'),
15
17
  ]
@@ -0,0 +1,31 @@
1
+ 'use strict'
2
+
3
+ const moduleName = '@openai/agents-openai'
4
+ const versionRange = '>=0.7.0'
5
+ const functionQuery = {
6
+ methodName: 'constructor',
7
+ className: 'OpenAIChatCompletionsModel',
8
+ kind: 'Sync',
9
+ }
10
+ const channelName = 'OpenAIChatCompletionsModel_constructor'
11
+
12
+ module.exports = [
13
+ {
14
+ module: {
15
+ name: moduleName,
16
+ versionRange,
17
+ filePath: 'dist/openaiChatCompletionsModel.js',
18
+ },
19
+ functionQuery,
20
+ channelName,
21
+ },
22
+ {
23
+ module: {
24
+ name: moduleName,
25
+ versionRange,
26
+ filePath: 'dist/openaiChatCompletionsModel.mjs',
27
+ },
28
+ functionQuery,
29
+ channelName,
30
+ },
31
+ ]
@@ -0,0 +1,57 @@
1
+ 'use strict'
2
+
3
+ module.exports = [
4
+ {
5
+ module: {
6
+ name: '@wdio/cli',
7
+ versionRange: '>=9.0.0',
8
+ filePath: 'build/index.js',
9
+ },
10
+ functionQuery: {
11
+ className: 'Launcher',
12
+ methodName: '_startInstance',
13
+ kind: 'Async',
14
+ },
15
+ channelName: 'Launcher_startInstance',
16
+ },
17
+ {
18
+ module: {
19
+ name: '@wdio/local-runner',
20
+ versionRange: '>=9.0.0',
21
+ filePath: 'build/index.js',
22
+ },
23
+ functionQuery: {
24
+ className: 'LocalRunner',
25
+ methodName: 'run',
26
+ kind: 'Async',
27
+ },
28
+ channelName: 'LocalRunner_run',
29
+ },
30
+ {
31
+ module: {
32
+ name: '@wdio/local-runner',
33
+ versionRange: '>=9.0.0',
34
+ filePath: 'build/index.js',
35
+ },
36
+ functionQuery: {
37
+ className: 'LocalRunner',
38
+ methodName: 'shutdown',
39
+ kind: 'Async',
40
+ },
41
+ channelName: 'LocalRunner_shutdown',
42
+ },
43
+ {
44
+ module: {
45
+ name: '@wdio/local-runner',
46
+ versionRange: '>=9.0.0',
47
+ filePath: 'build/index.js',
48
+ },
49
+ astQuery: 'VariableDeclarator[id.name="LocalRunner"] > ClassExpression > ClassBody > ' +
50
+ 'MethodDefinition[key.name="shutdown"] ReturnStatement > ' +
51
+ 'CallExpression[callee.object.name="promise"][callee.property.name="then"], ' +
52
+ 'ClassDeclaration[id.name="LocalRunner"] > ClassBody > MethodDefinition[key.name="shutdown"] ReturnStatement > ' +
53
+ 'CallExpression[callee.object.name="promise"][callee.property.name="then"]',
54
+ channelName: 'LocalRunner_shutdown',
55
+ transform: 'waitForAsyncEnd',
56
+ },
57
+ ]
@@ -17,8 +17,8 @@ const { parse, query } = require('./compiler')
17
17
  module.exports = { waitForAsyncEnd }
18
18
 
19
19
  /**
20
- * Injects a wait for `ctx.asyncEndPromise` into a generated `tracePromise`
21
- * wrapper's native-Promise fulfillment handler.
20
+ * Injects settlement-specific asyncEnd waits into a generated `tracePromise`
21
+ * wrapper's native-Promise handlers.
22
22
  *
23
23
  * @param {object} _state
24
24
  * @param {import('estree').CallExpression} node
@@ -26,36 +26,68 @@ module.exports = { waitForAsyncEnd }
26
26
  */
27
27
  function waitForAsyncEnd (_state, node) {
28
28
  const onFulfilled = node.arguments[0]
29
- const statements = onFulfilled?.body?.body
29
+ const onRejected = node.arguments[1]
30
30
 
31
- if (!statements || query(onFulfilled.body, '[id.name=__apm$asyncEndPromise]').length > 0) {
31
+ if (!onFulfilled?.body || !onRejected?.body) {
32
32
  return
33
33
  }
34
34
 
35
- const returnIndex = statements.findIndex(statement =>
36
- statement.type === 'ReturnStatement' && statement.argument
35
+ injectAsyncEndCallbackWait(onFulfilled.body, 'ReturnStatement', 'resolveCallback')
36
+ injectAsyncEndCallbackWait(onRejected.body, 'ThrowStatement', 'rejectCallback')
37
+ }
38
+
39
+ /**
40
+ * Injects a settlement-specific callback wait before an exit.
41
+ *
42
+ * @param {import('estree').BlockStatement} body
43
+ * @param {'ReturnStatement'|'ThrowStatement'} exitType
44
+ * @param {'resolveCallback'|'rejectCallback'} callbackProperty
45
+ * @returns {void}
46
+ */
47
+ function injectAsyncEndCallbackWait (body, exitType, callbackProperty) {
48
+ const callbackVariable = `__apm$${callbackProperty}`
49
+ if (query(body, `[id.name=${callbackVariable}]`).length > 0) {
50
+ return
51
+ }
52
+
53
+ const exitIndex = body.body.findIndex(statement =>
54
+ statement.type === exitType && statement.argument
37
55
  )
38
56
 
39
- // The generated fulfillment handler always ends in a return; a miss means the
57
+ // The generated settlement handlers always end in a return or throw; a miss means the
40
58
  // upstream template changed and the caller's try/catch falls back to the
41
59
  // unwrapped source.
42
- assert(returnIndex !== -1, 'waitForAsyncEnd: no return statement to wait on')
60
+ assert(exitIndex !== -1, `waitForAsyncEnd: no ${exitType} to wait on`)
43
61
 
62
+ // This runs inside tracePromise's native-Promise settlement handler. The
63
+ // Promise adapts subscriber callback completion to that existing chain.
44
64
  const waitStatements = parse(`
45
65
  function wrapper () {
46
- const __apm$asyncEndPromise = __apm$ctx.asyncEndPromise;
47
- if (__apm$asyncEndPromise && typeof __apm$asyncEndPromise.then === 'function') {
48
- return __apm$asyncEndPromise.then(() => __apm$result, () => __apm$result);
66
+ const ${callbackVariable} = __apm$ctx.${callbackProperty};
67
+ if (typeof ${callbackVariable} === 'function') {
68
+ return new Promise(${callbackVariable}).then(() => __apm$result, () => __apm$result);
49
69
  }
50
70
  }
51
71
  `).body[0].body.body
52
72
 
53
- // Resolve to whatever the fulfillment handler returns (its return argument),
54
- // so a subscriber that reassigned `__apm$ctx.result` in `asyncEnd` still wins.
55
- const returnArgument = statements[returnIndex].argument
56
- const { arguments: onSettled } = waitStatements[1].consequent.body[0].argument
57
- onSettled[0].body = clone(returnArgument)
58
- onSettled[1].body = clone(returnArgument)
73
+ const exitArgument = body.body[exitIndex].argument
74
+ const callbackIf = waitStatements[1]
75
+ const { arguments: onCallbackSettled } = callbackIf.consequent.body[0].argument
76
+
77
+ if (exitType === 'ThrowStatement') {
78
+ for (const handler of onCallbackSettled) {
79
+ handler.body = {
80
+ type: 'BlockStatement',
81
+ body: [{
82
+ type: 'ThrowStatement',
83
+ argument: clone(exitArgument),
84
+ }],
85
+ }
86
+ }
87
+ } else {
88
+ onCallbackSettled[0].body = clone(exitArgument)
89
+ onCallbackSettled[1].body = clone(exitArgument)
90
+ }
59
91
 
60
- statements.splice(returnIndex, 0, ...waitStatements)
92
+ body.body.splice(exitIndex, 0, ...waitStatements)
61
93
  }
@@ -88,7 +88,7 @@ function collectRoutesFromRouter (router, prefix) {
88
88
  function normalizeRoutePaths (path) {
89
89
  if (path == null) return []
90
90
 
91
- if (Array.isArray(path) === false) {
91
+ if (!Array.isArray(path)) {
92
92
  const normalized = normalizeRoutePath(path)
93
93
  return [normalized]
94
94
  }
@@ -1,9 +1,48 @@
1
1
  'use strict'
2
2
 
3
+ const { builtinModules } = require('node:module')
4
+
5
+ /**
6
+ * @param {string} moduleName
7
+ */
8
+ function stripNodePrefix (moduleName) {
9
+ return moduleName.startsWith('node:') ? moduleName.slice(5) : moduleName
10
+ }
11
+
12
+ const builtinModuleNames = new Set(builtinModules.map(stripNodePrefix))
13
+
14
+ /**
15
+ * @param {string} moduleName
16
+ */
17
+ function isNodeBuiltinModuleName (moduleName) {
18
+ return builtinModuleNames.has(stripNodePrefix(moduleName))
19
+ }
20
+
21
+ /**
22
+ * @param {string} moduleName
23
+ */
24
+ function isBuiltinModuleName (moduleName) {
25
+ return moduleName === 'electron' || isNodeBuiltinModuleName(moduleName)
26
+ }
27
+
28
+ /**
29
+ * @param {string} moduleName
30
+ */
31
+ function normalizeModuleName (moduleName) {
32
+ const stripped = stripNodePrefix(moduleName)
33
+ return builtinModuleNames.has(stripped) ? stripped : moduleName
34
+ }
35
+
36
+ /**
37
+ * @param {string} moduleName
38
+ */
3
39
  function isRelativeRequire (moduleName) {
4
40
  return moduleName.startsWith('./') || moduleName.startsWith('../')
5
41
  }
6
42
 
7
43
  module.exports = {
44
+ isBuiltinModuleName,
45
+ isNodeBuiltinModuleName,
8
46
  isRelativeRequire,
47
+ normalizeModuleName,
9
48
  }
@@ -89,9 +89,7 @@ function setupResponseInstrumentation (ctx, res) {
89
89
  const collectChunk = chunk => {
90
90
  if (!bodyChunks || !chunk) return
91
91
 
92
- if (typeof chunk === 'string') {
93
- bodyChunks.push(chunk)
94
- } else if (Buffer.isBuffer(chunk)) {
92
+ if (typeof chunk === 'string' || Buffer.isBuffer(chunk)) {
95
93
  bodyChunks.push(chunk)
96
94
  } else {
97
95
  // Handle Uint8Array or other array-like types