dd-trace 6.21.0 → 6.22.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 (204) hide show
  1. package/ci/diagnose.js +9 -14
  2. package/ci/init.js +1 -2
  3. package/ci/test-optimization-validation/ci-discovery.js +9 -4
  4. package/ci/test-optimization-validation/executable.js +1 -5
  5. package/ci/test-optimization-validation/framework-adapters/cypress.js +1 -4
  6. package/ci/test-optimization-validation/framework-adapters/vitest.js +1 -1
  7. package/ci/test-optimization-validation/generated-files.js +6 -4
  8. package/ci/test-optimization-validation/generated-test-contract.js +7 -3
  9. package/ci/test-optimization-validation/manifest-scaffold.js +7 -2
  10. package/ci/test-optimization-validation/manifest-schema.js +6 -7
  11. package/ci/test-optimization-validation/report-writer.js +6 -2
  12. package/ci/test-optimization-validation/runner-command.js +2 -4
  13. package/ci/test-optimization-validation/runner-contract.js +1 -2
  14. package/ci/test-optimization-validation/scenarios/auto-test-retries.js +1 -15
  15. package/ci/vitest-no-worker-init-setup.mjs +10 -7
  16. package/index.d.ts +25 -14
  17. package/initialize.mjs +1 -3
  18. package/openfeature/rules-based.d.ts +11 -0
  19. package/openfeature/rules-based.js +7 -0
  20. package/package.json +12 -10
  21. package/packages/datadog-core/src/storage.js +16 -0
  22. package/packages/datadog-esbuild/index.js +18 -12
  23. package/packages/datadog-instrumentations/src/aerospike.js +3 -3
  24. package/packages/datadog-instrumentations/src/ai.js +3 -3
  25. package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +0 -6
  26. package/packages/datadog-instrumentations/src/aws-sdk.js +21 -13
  27. package/packages/datadog-instrumentations/src/cassandra-driver.js +25 -20
  28. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +9 -23
  29. package/packages/datadog-instrumentations/src/cucumber.js +48 -33
  30. package/packages/datadog-instrumentations/src/elasticsearch.js +1 -5
  31. package/packages/datadog-instrumentations/src/electron.js +6 -6
  32. package/packages/datadog-instrumentations/src/fastify.js +13 -4
  33. package/packages/datadog-instrumentations/src/fs.js +2 -2
  34. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +9 -5
  35. package/packages/datadog-instrumentations/src/grpc/client.js +2 -0
  36. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +2 -2
  37. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +1 -2
  38. package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
  39. package/packages/datadog-instrumentations/src/helpers/register.js +36 -1
  40. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -0
  41. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +87 -6
  42. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +5 -6
  43. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +48 -31
  44. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +7 -7
  45. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +42 -4
  46. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +7 -10
  47. package/packages/datadog-instrumentations/src/ioredis.js +7 -5
  48. package/packages/datadog-instrumentations/src/iovalkey.js +7 -5
  49. package/packages/datadog-instrumentations/src/jest.js +3 -10
  50. package/packages/datadog-instrumentations/src/knex.js +9 -5
  51. package/packages/datadog-instrumentations/src/mariadb-bundle.js +3 -3
  52. package/packages/datadog-instrumentations/src/mocha/common.js +20 -8
  53. package/packages/datadog-instrumentations/src/mocha/main.js +140 -43
  54. package/packages/datadog-instrumentations/src/mocha/utils.js +3 -2
  55. package/packages/datadog-instrumentations/src/mocha/worker.js +1 -2
  56. package/packages/datadog-instrumentations/src/mongodb-core.js +3 -3
  57. package/packages/datadog-instrumentations/src/mongoose.js +3 -3
  58. package/packages/datadog-instrumentations/src/nova-sonic/audio.js +173 -0
  59. package/packages/datadog-instrumentations/src/nova-sonic/index.js +209 -0
  60. package/packages/datadog-instrumentations/src/nova-sonic/session.js +483 -0
  61. package/packages/datadog-instrumentations/src/openai-realtime/index.js +18 -6
  62. package/packages/datadog-instrumentations/src/openai-realtime/session.js +1 -1
  63. package/packages/datadog-instrumentations/src/openai.js +7 -0
  64. package/packages/datadog-instrumentations/src/pino.js +5 -6
  65. package/packages/datadog-instrumentations/src/redis.js +27 -13
  66. package/packages/datadog-instrumentations/src/router.js +30 -0
  67. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +2 -6
  68. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +7 -5
  69. package/packages/datadog-instrumentations/src/vitest-main.js +9 -15
  70. package/packages/datadog-instrumentations/src/vitest-util.js +2 -2
  71. package/packages/datadog-instrumentations/src/vitest-worker.js +1 -2
  72. package/packages/datadog-instrumentations/src/vitest.js +2 -2
  73. package/packages/datadog-instrumentations/src/webdriverio.js +5 -8
  74. package/packages/datadog-instrumentations/src/ws.js +1 -4
  75. package/packages/datadog-plugin-amqplib/src/client.js +1 -2
  76. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -5
  77. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +1 -2
  78. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -8
  79. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +18 -0
  80. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/sonic.js +45 -0
  81. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +9 -3
  82. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -5
  83. package/packages/datadog-plugin-azure-durable-functions/src/index.js +5 -4
  84. package/packages/datadog-plugin-azure-functions/src/index.js +5 -3
  85. package/packages/datadog-plugin-claude-agent-sdk/src/index.js +0 -2
  86. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +1 -5
  87. package/packages/datadog-plugin-cypress/src/index.js +6 -6
  88. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -2
  89. package/packages/datadog-plugin-cypress/src/support.js +1 -4
  90. package/packages/datadog-plugin-express/src/code_origin.js +1 -2
  91. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -2
  92. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +1 -2
  93. package/packages/datadog-plugin-graphql/src/execute.js +5 -5
  94. package/packages/datadog-plugin-grpc/src/util.js +1 -2
  95. package/packages/datadog-plugin-kafkajs/src/producer.js +1 -2
  96. package/packages/datadog-plugin-mocha/src/index.js +7 -10
  97. package/packages/datadog-plugin-mocha/src/webdriverio-video.js +8 -4
  98. package/packages/datadog-plugin-mongodb-core/src/query.js +8 -5
  99. package/packages/datadog-plugin-next/src/index.js +1 -2
  100. package/packages/datadog-plugin-openai/src/tracing.js +5 -2
  101. package/packages/datadog-plugin-openai-agents/src/integration.js +6 -2
  102. package/packages/datadog-plugin-openai-agents/src/processor.js +2 -4
  103. package/packages/datadog-plugin-postgres/src/index.js +24 -0
  104. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -5
  105. package/packages/datadog-plugin-rhea/src/consumer.js +1 -4
  106. package/packages/datadog-plugin-vitest/src/index.js +5 -2
  107. package/packages/datadog-shimmer/src/shimmer.js +5 -4
  108. package/packages/datadog-webpack/index.js +55 -43
  109. package/packages/datadog-webpack/src/loader.js +56 -8
  110. package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +2 -4
  111. package/packages/dd-trace/src/aiguard/messages/utils.js +1 -2
  112. package/packages/dd-trace/src/aiguard/redaction.js +8 -2
  113. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +3 -2
  114. package/packages/dd-trace/src/appsec/api_security/sampler.js +2 -6
  115. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -9
  116. package/packages/dd-trace/src/appsec/handlers/http-request.js +3 -9
  117. package/packages/dd-trace/src/appsec/handlers/http-response.js +7 -2
  118. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +4 -3
  119. package/packages/dd-trace/src/appsec/iast/analyzers/set-cookies-header-interceptor.js +1 -4
  120. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +7 -1
  121. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -3
  122. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +1 -3
  123. package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +1 -6
  124. package/packages/dd-trace/src/appsec/lambda.js +1 -3
  125. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +37 -27
  126. package/packages/dd-trace/src/appsec/rasp/lfi.js +9 -5
  127. package/packages/dd-trace/src/appsec/reporter.js +21 -1
  128. package/packages/dd-trace/src/appsec/stack_trace.js +1 -2
  129. package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +3 -6
  130. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +1 -1
  131. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +13 -7
  132. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +1 -2
  133. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +2 -8
  134. package/packages/dd-trace/src/ci-visibility/resolve-runfile-path.js +54 -0
  135. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +5 -8
  136. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +2 -53
  137. package/packages/dd-trace/src/config/config-types.d.ts +2 -2
  138. package/packages/dd-trace/src/config/defaults.js +5 -5
  139. package/packages/dd-trace/src/config/generated-config-types.d.ts +8 -0
  140. package/packages/dd-trace/src/config/helper.js +34 -3
  141. package/packages/dd-trace/src/config/index.js +10 -9
  142. package/packages/dd-trace/src/config/normalize-service.js +1 -1
  143. package/packages/dd-trace/src/config/parsers.js +2 -2
  144. package/packages/dd-trace/src/config/supported-configurations.json +35 -0
  145. package/packages/dd-trace/src/datastreams/processor.js +3 -2
  146. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +1 -4
  147. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -0
  148. package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -0
  149. package/packages/dd-trace/src/debugger/guardrail-metrics.js +2 -2
  150. package/packages/dd-trace/src/dogstatsd.js +1 -1
  151. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  152. package/packages/dd-trace/src/exporters/common/request.js +1 -5
  153. package/packages/dd-trace/src/id.js +14 -1
  154. package/packages/dd-trace/src/lambda/handler.js +179 -19
  155. package/packages/dd-trace/src/lambda/index.js +15 -1
  156. package/packages/dd-trace/src/lambda/runtime/patch.js +34 -7
  157. package/packages/dd-trace/src/llmobs/audio-utils.js +3 -2
  158. package/packages/dd-trace/src/llmobs/constants/tags.js +12 -0
  159. package/packages/dd-trace/src/llmobs/experiments/experiment.js +1 -1
  160. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +15 -0
  161. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +1 -2
  162. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +1 -3
  163. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  164. package/packages/dd-trace/src/llmobs/plugins/nova-sonic.js +92 -0
  165. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +56 -2
  166. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +38 -0
  167. package/packages/dd-trace/src/llmobs/prompts/manager.js +5 -7
  168. package/packages/dd-trace/src/llmobs/prompts/prompt.js +1 -1
  169. package/packages/dd-trace/src/llmobs/span_processor.js +1 -2
  170. package/packages/dd-trace/src/llmobs/tagger.js +2 -2
  171. package/packages/dd-trace/src/llmobs/util.js +1 -2
  172. package/packages/dd-trace/src/llmobs/writers/base.js +4 -5
  173. package/packages/dd-trace/src/log/log.js +1 -5
  174. package/packages/dd-trace/src/openfeature/evaluation-telemetry-opt-out-hook.js +51 -0
  175. package/packages/dd-trace/src/openfeature/flagging_provider.js +48 -21
  176. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +1 -1
  177. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  178. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -2
  179. package/packages/dd-trace/src/opentelemetry/otlp/common.proto +1 -1
  180. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +6 -23
  181. package/packages/dd-trace/src/opentracing/propagation/text_map.js +53 -13
  182. package/packages/dd-trace/src/otel-sampling.js +4 -5
  183. package/packages/dd-trace/src/otel-thread-ctx.js +79 -13
  184. package/packages/dd-trace/src/plugins/database.js +7 -16
  185. package/packages/dd-trace/src/plugins/util/git.js +9 -25
  186. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +1 -5
  187. package/packages/dd-trace/src/plugins/util/test.js +48 -4
  188. package/packages/dd-trace/src/priority_sampler.js +1 -2
  189. package/packages/dd-trace/src/profiling/profiler.js +4 -6
  190. package/packages/dd-trace/src/proxy.js +1 -2
  191. package/packages/dd-trace/src/ritm.js +4 -2
  192. package/packages/dd-trace/src/serverless.js +5 -0
  193. package/packages/dd-trace/src/span_processor.js +13 -17
  194. package/packages/dd-trace/src/telemetry/endpoints.js +1 -3
  195. package/packages/dd-trace/src/util.js +29 -0
  196. package/packages/dd-trace/src/web-tags-cache.js +6 -2
  197. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
  198. package/vendor/dist/@datadog/openfeature-node-server/rules-based/LICENSE +201 -0
  199. package/vendor/dist/@datadog/openfeature-node-server/rules-based/index.d.ts +925 -0
  200. package/vendor/dist/@datadog/openfeature-node-server/rules-based/index.js +1 -0
  201. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  202. package/vendor/dist/protobufjs/index.js +1 -1
  203. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  204. package/vendor/dist/shell-quote/index.js +1 -1
package/ci/diagnose.js CHANGED
@@ -1743,9 +1743,7 @@ function readTextFiles (root, physicalRoot, files, maxTotalBytes) {
1743
1743
 
1744
1744
  for (const relativePath of files) {
1745
1745
  const file = getSafeScannedFile(root, physicalRoot, relativePath)
1746
- if (!file) continue
1747
-
1748
- if (file.stat.size > MAX_TEXT_FILE_SIZE) continue
1746
+ if (!file || file.stat.size > MAX_TEXT_FILE_SIZE) continue
1749
1747
  if (totalBytes + file.stat.size > maxTotalBytes) {
1750
1748
  textFiles.truncated = true
1751
1749
  break
@@ -1862,15 +1860,13 @@ function isTestSetupOrCiFile (file) {
1862
1860
  const relativePath = file.relativePath
1863
1861
  const basename = path.basename(relativePath)
1864
1862
 
1865
- if (isWorkflowFile(relativePath)) return true
1866
- if (basename === 'package.json') return true
1867
- if (/^(?:jest|config-jest|vitest|vite|playwright|cypress|cucumber)\.config\./.test(basename)) return true
1868
- if (/^\.mocharc\./.test(basename)) return true
1869
- if (basename === 'cypress.json') return true
1870
- if (/setup|bootstrap/i.test(basename)) return true
1871
- if (relativePath.startsWith('cypress/support/')) return true
1872
-
1873
- return false
1863
+ return isWorkflowFile(relativePath) ||
1864
+ basename === 'package.json' ||
1865
+ /^(?:jest|config-jest|vitest|vite|playwright|cypress|cucumber)\.config\./.test(basename) ||
1866
+ /^\.mocharc\./.test(basename) ||
1867
+ basename === 'cypress.json' ||
1868
+ /setup|bootstrap/i.test(basename) ||
1869
+ relativePath.startsWith('cypress/support/')
1874
1870
  }
1875
1871
 
1876
1872
  /**
@@ -2014,8 +2010,7 @@ function coerceVersion (rawVersion) {
2014
2010
  */
2015
2011
  function isAmbiguousRange (rawVersion) {
2016
2012
  const version = String(rawVersion || '').trim()
2017
- if (!version) return true
2018
- if (version.includes('||')) return true
2013
+ if (!version || version.includes('||')) return true
2019
2014
  return /<=?\s*\d/.test(version)
2020
2015
  }
2021
2016
 
package/ci/init.js CHANGED
@@ -32,8 +32,7 @@ function detectTestWorkerType () {
32
32
  if (getEnvironmentVariable('CUCUMBER_WORKER_ID')) return 'cucumber'
33
33
  if (getEnvironmentVariable('MOCHA_WORKER_ID')) return 'mocha'
34
34
  if (getValueFromEnvSources('DD_PLAYWRIGHT_WORKER')) return 'playwright'
35
- if (getEnvironmentVariable('TINYPOOL_WORKER_ID')) return 'vitest'
36
- if (getValueFromEnvSources('DD_VITEST_WORKER')) return 'vitest'
35
+ if (getEnvironmentVariable('TINYPOOL_WORKER_ID') || getValueFromEnvSources('DD_VITEST_WORKER')) return 'vitest'
37
36
  return null
38
37
  }
39
38
 
@@ -40,8 +40,7 @@ function buildCiDiscovery ({ manifest, diagnosis }) {
40
40
  const candidateFound = getManifestWorkflowLocations(manifest)
41
41
  const manifestFound = uniqueStrings([...declaredFound, ...candidateFound])
42
42
  const searched = normalizeStringArray(declared.searched)
43
- let method = 'validator-static-diagnosis'
44
- if (candidateFound.length > 0) method = 'framework-ci-command'
43
+ let method = candidateFound.length > 0 ? 'framework-ci-command' : 'validator-static-diagnosis'
45
44
  if (declaredFound.length > 0) method = 'manifest'
46
45
  if (typeof declared.method === 'string' && declared.method) method = declared.method
47
46
  const found = manifestFound.length > 0 ? manifestFound : staticFound
@@ -83,8 +82,14 @@ function getManifestWorkflowLocations (manifest) {
83
82
 
84
83
  function getFrameworkCiDiscoveryContradiction (framework, manifest) {
85
84
  const ciDiscovery = manifest?.ciDiscovery
86
- if (!ciDiscovery || !Array.isArray(ciDiscovery.staticFound) || ciDiscovery.staticFound.length === 0) return null
87
- if (!frameworkClaimsNoCi(framework)) return null
85
+ if (
86
+ !ciDiscovery ||
87
+ !Array.isArray(ciDiscovery.staticFound) ||
88
+ ciDiscovery.staticFound.length === 0 ||
89
+ !frameworkClaimsNoCi(framework)
90
+ ) {
91
+ return null
92
+ }
88
93
 
89
94
  return {
90
95
  reason: 'CI workflow files were found by validator static diagnosis, but this manifest entry says no CI ' +
@@ -158,11 +158,7 @@ function splitNodeOptions (source) {
158
158
  }
159
159
  }
160
160
  const next = source[index + 1]
161
- if (character === '\\' && next && (next === quote || /[\s'"\\]/.test(next))) {
162
- value += source[++index]
163
- } else {
164
- value += character
165
- }
161
+ value += character === '\\' && next && (next === quote || /[\s'"\\]/.test(next)) ? source[++index] : character
166
162
  started = true
167
163
  }
168
164
  if (quote) throw new Error('NODE_OPTIONS contains an unterminated quoted value.')
@@ -37,10 +37,7 @@ function getTestExtension (filename) {
37
37
  * @param {string} input.testName generated test name
38
38
  */
39
39
  function getGeneratedTestContent ({ scenarioId, testName }) {
40
- let content = ''
41
- if (scenarioId === 'atr-fail-once') {
42
- content = 'let attempt = 0\n\n'
43
- }
40
+ let content = scenarioId === 'atr-fail-once' ? 'let attempt = 0\n\n' : ''
44
41
  content += "describe('dd-test-optimization-validation', () => {\n" +
45
42
  ` it(${JSON.stringify(testName)}, () => {\n` +
46
43
  (scenarioId === 'atr-fail-once'
@@ -361,7 +361,7 @@ function getDelimitedRanges (source, open, close) {
361
361
  function getLiteralStringProperties (source, property) {
362
362
  return getPropertyPositions(source, property).flatMap(({ index, valueStart }) => {
363
363
  const literal = /^(["'])([^"'\\]+)\1/.exec(source.slice(valueStart))
364
- return literal ? [{ index, value: literal[2] }] : []
364
+ return literal ? { index, value: literal[2] } : []
365
365
  })
366
366
  }
367
367
 
@@ -305,12 +305,14 @@ function isCleanupAuthorizationValid (filename, authorization) {
305
305
  try {
306
306
  const currentPhysicalRoot = fs.realpathSync(authorization.lexicalRoot)
307
307
  const rootStat = fs.statSync(currentPhysicalRoot, { bigint: true })
308
- if (currentPhysicalRoot !== authorization.physicalRoot ||
309
- rootStat.dev !== authorization.rootDevice || rootStat.ino !== authorization.rootInode) {
308
+ if (
309
+ currentPhysicalRoot !== authorization.physicalRoot ||
310
+ rootStat.dev !== authorization.rootDevice ||
311
+ rootStat.ino !== authorization.rootInode ||
312
+ authorization.physicalParent === undefined
313
+ ) {
310
314
  return false
311
315
  }
312
-
313
- if (authorization.physicalParent === undefined) return false
314
316
  const physicalParent = fs.realpathSync(path.dirname(filename))
315
317
  const parentStat = fs.statSync(physicalParent, { bigint: true })
316
318
  if (physicalParent !== authorization.physicalParent ||
@@ -124,9 +124,13 @@ function getGeneratedTestContent ({ framework, moduleSystem, scenarioId, stateFi
124
124
  */
125
125
  function getGeneratedTestContractError (framework) {
126
126
  const strategy = framework.generatedTestStrategy
127
- if (!strategy || !['planned', 'verified'].includes(strategy.status)) return
128
-
129
- if (!['cucumber', 'cypress', 'jest', 'mocha', 'playwright', 'vitest'].includes(framework.framework)) return
127
+ if (
128
+ !strategy ||
129
+ !['planned', 'verified'].includes(strategy.status) ||
130
+ !['cucumber', 'cypress', 'jest', 'mocha', 'playwright', 'vitest'].includes(framework.framework)
131
+ ) {
132
+ return
133
+ }
130
134
  if (!['commonjs', 'esm'].includes(strategy.moduleSystem)) {
131
135
  return 'must retain generatedTestStrategy.moduleSystem as "commonjs" or "esm".'
132
136
  }
@@ -750,8 +750,13 @@ function hasCucumberBrowserSupport (files, retainedInputs, projectRoot) {
750
750
  function isTestFile (filename, source, framework, projectRoot, allowDirectoryConvention) {
751
751
  const basename = path.basename(filename)
752
752
  const normalized = filename.replaceAll('\\', '/')
753
- if (normalized.includes('/dd-test-optimization-validation-')) return false
754
- if (TYPE_ONLY_TEST_PATTERN.test(basename) || TYPE_ONLY_DIRECTORY_PATTERN.test(normalized)) return false
753
+ if (
754
+ normalized.includes('/dd-test-optimization-validation-') ||
755
+ TYPE_ONLY_TEST_PATTERN.test(basename) ||
756
+ TYPE_ONLY_DIRECTORY_PATTERN.test(normalized)
757
+ ) {
758
+ return false
759
+ }
755
760
  if (framework === 'cucumber') return cucumber.isTestFile(filename)
756
761
  if (framework === 'cypress') return cypress.isTestFile(basename, path.dirname(filename), projectRoot)
757
762
  if (framework === 'playwright') return playwright.isTestFile(basename, path.dirname(filename), projectRoot)
@@ -441,16 +441,15 @@ function validateCiWiring (repositoryRoot, ciWiring, prefix, errors) {
441
441
  if (typeof ciWiring.reviewComplete !== 'boolean') errors.push(`${prefix}.reviewComplete must be a boolean.`)
442
442
  validateStringArray(ciWiring.unresolved, `${prefix}.unresolved`, errors)
443
443
 
444
- if (!isObject(ciWiring.initialization) ||
445
- !INITIALIZATION_STATUSES.has(ciWiring.initialization.status)) {
446
- errors.push(`${prefix}.initialization.status must be configured, not_configured, or unknown.`)
447
- } else {
444
+ if (isObject(ciWiring.initialization) && INITIALIZATION_STATUSES.has(ciWiring.initialization.status)) {
448
445
  validateStringArray(ciWiring.initialization.evidence, `${prefix}.initialization.evidence`, errors)
449
- }
450
- if (!isObject(ciWiring.transport) || !TRANSPORT_MODES.has(ciWiring.transport.mode)) {
451
- errors.push(`${prefix}.transport.mode must be agent, agentless, none, or unknown.`)
452
446
  } else {
447
+ errors.push(`${prefix}.initialization.status must be configured, not_configured, or unknown.`)
448
+ }
449
+ if (isObject(ciWiring.transport) && TRANSPORT_MODES.has(ciWiring.transport.mode)) {
453
450
  validateStringArray(ciWiring.transport.evidence, `${prefix}.transport.evidence`, errors)
451
+ } else {
452
+ errors.push(`${prefix}.transport.mode must be agent, agentless, none, or unknown.`)
454
453
  }
455
454
  }
456
455
 
@@ -332,8 +332,12 @@ function getActions (results) {
332
332
  function getActionPriority (result, localPasses) {
333
333
  if (result.evidence?.possibleLibraryBug) return 0
334
334
  if (result.scenario === 'ci-wiring' && localPasses.has(result.frameworkId)) return 0
335
- if (result.evidence?.blockerCategory === 'EXECUTION_ENVIRONMENT_BLOCKED') return 1
336
- if (result.evidence?.blockerCategory === 'VALIDATOR_LIMITATION') return 1
335
+ if (
336
+ result.evidence?.blockerCategory === 'EXECUTION_ENVIRONMENT_BLOCKED' ||
337
+ result.evidence?.blockerCategory === 'VALIDATOR_LIMITATION'
338
+ ) {
339
+ return 1
340
+ }
337
341
  if (result.scenario === 'ci-wiring') return 2
338
342
  return 3
339
343
  }
@@ -46,8 +46,7 @@ function getGeneratedCommand (framework, scenario) {
46
46
  * @returns {Array<[string, object]>} labeled direct-runner commands
47
47
  */
48
48
  function getFrameworkCommands (framework, requestedScenario = null) {
49
- if (framework.status !== 'runnable') return []
50
- if (requestedScenario === 'ci-wiring') return []
49
+ if (framework.status !== 'runnable' || requestedScenario === 'ci-wiring') return []
51
50
 
52
51
  const commands = [['basic-reporting', getBasicCommand(framework)]]
53
52
  const fallbackTests = framework.validation.fallbackTests
@@ -99,8 +98,7 @@ function getManifestInputFiles (manifest, { includeLocal = true } = {}) {
99
98
  for (const framework of manifest.frameworks) {
100
99
  addExistingFile(files, framework.ciWiring?.configFile)
101
100
  addExistingFile(files, framework.project?.packageJson)
102
- if (!includeLocal) continue
103
- if (framework.status !== 'runnable') continue
101
+ if (!includeLocal || framework.status !== 'runnable') continue
104
102
  addExistingFile(files, framework.validation?.runner)
105
103
  addExistingFile(files, framework.validation?.testFile)
106
104
  const fallbackTests = framework.validation?.fallbackTests
@@ -450,8 +450,7 @@ function getRunnerInputError (args, environment, projectRoot, repositoryRoot, co
450
450
  * @returns {{error?: string, runnerIndex: number, tokens: string[]}|undefined} parsed invocation
451
451
  */
452
452
  function getFrameworkInvocation (command, framework) {
453
- if (CONTROL_PATTERN.test(String(command || ''))) return
454
- if (command === `direct ${framework} binary`) return
453
+ if (CONTROL_PATTERN.test(String(command || '')) || command === `direct ${framework} binary`) return
455
454
  const tokens = tokenizeCommand(command)
456
455
  const executable = getRunnerExecutableName(framework)
457
456
  const runnerIndex = tokens.findIndex(token => {
@@ -100,21 +100,7 @@ async function runAutoTestRetries ({ framework, out, options }) {
100
100
  })
101
101
  }
102
102
 
103
- if (run.result.exitCode !== 0) {
104
- return failWithDebugRerun({
105
- command: scenario.runCommand,
106
- fixtureConfig,
107
- diagnosis: getAutoTestRetriesFailureDiagnosis(framework, evidence),
108
- evidence,
109
- framework,
110
- options,
111
- out,
112
- outDir,
113
- scenarioName,
114
- })
115
- }
116
-
117
- if (tests.length < 2 || autoTestRetryEvents.length === 0) {
103
+ if (run.result.exitCode !== 0 || tests.length < 2 || autoTestRetryEvents.length === 0) {
118
104
  return failWithDebugRerun({
119
105
  command: scenario.runCommand,
120
106
  fixtureConfig,
@@ -3,7 +3,7 @@ import { afterEach, beforeAll, beforeEach, inject } from 'vitest'
3
3
  // Instrumentation-less setup for DD_EXPERIMENTAL_TEST_OPT_VITEST_NO_WORKER_INIT.
4
4
  // It applies Test Optimization execution changes without initializing dd-trace and also supports Browser Mode.
5
5
  const VITEST_NO_WORKER_INIT_ACTIVE_ENV = 'DD_TEST_OPT_VITEST_NO_WORKER_INIT_ACTIVE'
6
- const SERIALIZED_CONTEXT_PREFIX = '\u0000dd-vitest-context:'
6
+ const SERIALIZED_CONTEXT_PREFIX = '\0dd-vitest-context:'
7
7
  const providedContext = getProvidedContext()
8
8
  const isNoWorkerInitActive = providedContext.isActive ?? getIsNoWorkerInitActive()
9
9
  const attemptToFixTests = providedContext.attemptToFixTests || {}
@@ -220,9 +220,8 @@ function getNextAttemptIndex (task) {
220
220
  */
221
221
  function prepareRumCorrelation (task, attemptIndex) {
222
222
  // A per-origin cookie cannot identify overlapping attempts without racing.
223
- if (!isRumCorrelationEnabled || isConcurrentTask(task)) return
224
-
225
223
  if (
224
+ !isRumCorrelationEnabled || isConcurrentTask(task) ||
226
225
  typeof window === 'undefined' ||
227
226
  typeof document === 'undefined' ||
228
227
  typeof rumTestExecutionIdCookieName !== 'string'
@@ -289,8 +288,7 @@ function getRum () {
289
288
  * @param {object|undefined} rum
290
289
  */
291
290
  function getIsRumActive (rum) {
292
- if (!rum) return false
293
- if (typeof rum.getInternalContext !== 'function') return false
291
+ if (!rum || typeof rum.getInternalContext !== 'function') return false
294
292
 
295
293
  try {
296
294
  return !!rum.getInternalContext()
@@ -770,8 +768,13 @@ function getEarlyFlakeDetectionSuiteCandidate (suite) {
770
768
 
771
769
  const testSuite = getTestSuite(task)
772
770
  const testName = getTestName(task)
773
- if (attemptToFixTests[testSuite]?.[testName] || disabledTests[testSuite]?.[testName]) continue
774
- if (!isEarlyFlakeDetectionTest(testSuite, testName)) continue
771
+ if (
772
+ attemptToFixTests[testSuite]?.[testName] ||
773
+ disabledTests[testSuite]?.[testName] ||
774
+ !isEarlyFlakeDetectionTest(testSuite, testName)
775
+ ) {
776
+ continue
777
+ }
775
778
 
776
779
  candidate ||= {
777
780
  hasNewTest: false,
package/index.d.ts CHANGED
@@ -218,7 +218,6 @@ 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
- * @beta This feature is in preview and not ready for production use
222
221
  */
223
222
  openfeature: tracer.OpenFeatureProvider;
224
223
 
@@ -275,7 +274,7 @@ interface Tracer extends opentracing.Tracer {
275
274
  *
276
275
  * Removes all baggage items from the current context and returns the new context.
277
276
  *
278
- * @see https://opentelemetry.io/docs/specs/otel/baggage/api/#remove-all-values
277
+ * @see https://opentelemetry.io/docs/specs/otel/baggage/api/#clear-baggage-in-the-context
279
278
  */
280
279
  removeAllBaggageItems (): Record<string, string>;
281
280
  }
@@ -818,6 +817,22 @@ declare namespace tracer {
818
817
  */
819
818
  site?: string;
820
819
 
820
+ /**
821
+ * Feature Flags configuration.
822
+ */
823
+ featureFlags?: {
824
+ /**
825
+ * Allow boolean true in dd_evaluation_telemetry_opt_out to suppress evaluation events, metrics, and span tags.
826
+ * The attribute remains available to targeting rules and exposure reporting.
827
+ * Enabling this option does not change exposure events or flag evaluation results.
828
+ * Captured when the provider is constructed.
829
+ * Explicit configuration takes precedence over the environment variable, including false.
830
+ * @default false
831
+ * @env DD_FEATURE_FLAGS_EVALUATION_TELEMETRY_PER_SUBJECT_OPT_OUT_ENABLED
832
+ */
833
+ enableEvaluationTelemetryOptOutParameter?: boolean
834
+ }
835
+
821
836
  /**
822
837
  * Experimental features can be enabled individually using key / value pairs.
823
838
  * @default {}
@@ -890,8 +905,6 @@ declare namespace tracer {
890
905
 
891
906
  /**
892
907
  * Configuration for Feature Flagging & Experimentation.
893
- *
894
- * @beta This feature is in preview and not ready for production use
895
908
  */
896
909
  flaggingProvider?: {
897
910
  /**
@@ -1728,8 +1741,6 @@ declare namespace tracer {
1728
1741
  *
1729
1742
  * Wraps @datadog/openfeature-node-server with agentless and Agent Remote Config delivery.
1730
1743
  * Implements the OpenFeature Provider interface for flag evaluation.
1731
- *
1732
- * @beta This feature is in preview and not ready for production use
1733
1744
  */
1734
1745
  export interface OpenFeatureProvider {
1735
1746
  /**
@@ -2494,14 +2505,14 @@ declare namespace tracer {
2494
2505
  /**
2495
2506
  * This plugin patches the [browser-bunyan](https://github.com/philmander/browser-bunyan)
2496
2507
  * to automatically inject trace identifiers in log records when the
2497
- * [logInjection](interfaces/traceroptions.html#logInjection) option is enabled
2508
+ * {@link TracerOptions.logInjection | logInjection} option is enabled
2498
2509
  * on the tracer.
2499
2510
  */
2500
2511
  interface browser_bunyan extends Integration {}
2501
2512
 
2502
2513
  /**
2503
2514
  * This plugin automatically instruments the
2504
- * [bullmq](https://github.com/npmjs/package/bullmq) message queue library.
2515
+ * [bullmq](https://www.npmjs.com/package/bullmq) message queue library.
2505
2516
  */
2506
2517
  interface bullmq extends Instrumentation {
2507
2518
  /**
@@ -2522,7 +2533,7 @@ declare namespace tracer {
2522
2533
  /**
2523
2534
  * This plugin patches the [bunyan](https://github.com/trentm/node-bunyan)
2524
2535
  * to automatically inject trace identifiers in log records when the
2525
- * [logInjection](interfaces/traceroptions.html#logInjection) option is enabled
2536
+ * {@link TracerOptions.logInjection | logInjection} option is enabled
2526
2537
  * on the tracer.
2527
2538
  */
2528
2539
  interface bunyan extends Integration {}
@@ -2975,7 +2986,7 @@ declare namespace tracer {
2975
2986
 
2976
2987
  /**
2977
2988
  * This plugin automatically instruments the
2978
- * [langgraph](https://github.com/npmjs/package/langgraph) library.
2989
+ * [langgraph](https://www.npmjs.com/package/@langchain/langgraph) library.
2979
2990
  */
2980
2991
  interface langgraph extends Instrumentation, LLMObsIntegration {}
2981
2992
 
@@ -3011,7 +3022,7 @@ declare namespace tracer {
3011
3022
 
3012
3023
  /**
3013
3024
  * This plugin automatically instruments the
3014
- * [modelcontextprotocol-sdk](https://github.com/npmjs/package/@modelcontextprotocol/sdk) library.
3025
+ * [modelcontextprotocol-sdk](https://www.npmjs.com/package/@modelcontextprotocol/sdk) library.
3015
3026
  */
3016
3027
  interface modelcontextprotocol_sdk extends Instrumentation, LLMObsIntegration {}
3017
3028
 
@@ -3190,7 +3201,7 @@ declare namespace tracer {
3190
3201
  /**
3191
3202
  * This plugin patches the [pino](http://getpino.io)
3192
3203
  * to automatically inject trace identifiers in log records when the
3193
- * [logInjection](interfaces/traceroptions.html#logInjection) option is enabled
3204
+ * {@link TracerOptions.logInjection | logInjection} option is enabled
3194
3205
  * on the tracer.
3195
3206
  */
3196
3207
  interface pino extends Integration {}
@@ -3361,7 +3372,7 @@ declare namespace tracer {
3361
3372
  /**
3362
3373
  * This plugin patches the [winston](https://github.com/winstonjs/winston)
3363
3374
  * to automatically inject trace identifiers in log records when the
3364
- * [logInjection](interfaces/traceroptions.html#logInjection) option is enabled
3375
+ * {@link TracerOptions.logInjection | logInjection} option is enabled
3365
3376
  * on the tracer.
3366
3377
  */
3367
3378
  interface winston extends Integration {}
@@ -3652,7 +3663,7 @@ declare namespace tracer {
3652
3663
  * key/value pair separated by an equals sign `=`. Spaces and horizontal tabs
3653
3664
  * surrounding `list-members` are ignored. There can be a maximum of 32
3654
3665
  * `list-members` in a `list`.
3655
- * More Info: https://www.w3.org/TR/trace-context/#tracestate-field
3666
+ * More Info: https://www.w3.org/TR/trace-context/#tracestate-header
3656
3667
  *
3657
3668
  * Examples:
3658
3669
  * Single tracing system (generic format):
package/initialize.mjs CHANGED
@@ -101,8 +101,6 @@ if (isMainThread) {
101
101
  // Only register the loader hook when instrumentation initialized. On a bailout the
102
102
  // loader has nothing to instrument and can keep a short-lived process from exiting.
103
103
  if (Module.register && initialized) {
104
- // The loader builds its own include/exclude matcher in `initialize`, so no
105
- // options need to cross the registration boundary.
106
- Module.register('./loader-hook.mjs', import.meta.url)
104
+ require('./register.js')
107
105
  }
108
106
  }
@@ -0,0 +1,11 @@
1
+ export {
2
+ configurationToString,
3
+ ConfigurationFetchError,
4
+ fetchRulesConfiguration,
5
+ } from '../vendor/dist/@datadog/openfeature-node-server/rules-based';
6
+ export type {
7
+ ConfigurationFetchErrorCode,
8
+ FlagsConfiguration,
9
+ FlagsConfigurationWire,
10
+ RulesConfigurationFetchOptions,
11
+ } from '../vendor/dist/@datadog/openfeature-node-server/rules-based';
@@ -0,0 +1,7 @@
1
+ 'use strict'
2
+
3
+ const rules = require('../vendor/dist/@datadog/openfeature-node-server/rules-based')
4
+
5
+ exports.configurationToString = rules.configurationToString
6
+ exports.ConfigurationFetchError = rules.ConfigurationFetchError
7
+ exports.fetchRulesConfiguration = rules.fetchRulesConfiguration
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "6.21.0",
3
+ "version": "6.22.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -109,7 +109,7 @@
109
109
  "test:integration:webdriverio": "mocha --timeout 60000 \"integration-tests/webdriverio/${SPEC:-*}.spec.js\"",
110
110
  "test:integration:webdriverio:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/webdriverio/${SPEC:-*}.spec.js\"",
111
111
  "test:integration:vitest": "mocha --timeout 60000 \"integration-tests/vitest/${SPEC:-vitest*}.spec.js\"",
112
- "test:integration:vitest:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/vitest/${SPEC:-vitest*}.spec.js\"",
112
+ "test:integration:vitest:coverage": "node ./integration-tests/vitest/run-with-coverage.js --timeout 60000 \"integration-tests/vitest/${SPEC:-vitest*}.spec.js\"",
113
113
  "test:integration:testopt": "mocha --timeout 120000 \"integration-tests/ci-visibility/*.spec.js\"",
114
114
  "test:integration:testopt:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 120000 \"integration-tests/ci-visibility/*.spec.js\"",
115
115
  "test:integration:profiler": "mocha --timeout 180000 \"integration-tests/profiler/*.spec.js\"",
@@ -143,7 +143,7 @@
143
143
  "bugs": {
144
144
  "url": "https://github.com/DataDog/dd-trace-js/issues"
145
145
  },
146
- "homepage": "https://github.com/DataDog/dd-trace-js#readme",
146
+ "homepage": "https://github.com/DataDog/dd-trace-js",
147
147
  "engines": {
148
148
  "node": ">=22"
149
149
  },
@@ -169,6 +169,8 @@
169
169
  "loader-hook.mjs",
170
170
  "openfeature.d.ts",
171
171
  "openfeature.js",
172
+ "openfeature/rules-based.js",
173
+ "openfeature/rules-based.d.ts",
172
174
  "packages/*/index.js",
173
175
  "packages/*/index.electron.js",
174
176
  "packages/*/lib/**/*",
@@ -202,11 +204,11 @@
202
204
  "devDependencies": {
203
205
  "@actions/core": "^3.0.1",
204
206
  "@actions/github": "^9.1.1",
205
- "@babel/helpers": "^8.0.5",
207
+ "@babel/helpers": "^8.0.7",
206
208
  "@eslint/eslintrc": "^3.3.7",
207
209
  "@eslint/js": "^10.0.1",
208
210
  "@eslint/plugin-kit": "^0.7.3",
209
- "@datadog/openfeature-node-server": "2.4.0",
211
+ "@datadog/openfeature-node-server": "2.5.0",
210
212
  "@msgpack/msgpack": "^3.1.3",
211
213
  "@openfeature/core": "^1.12.0",
212
214
  "@openfeature/server-sdk": "~1.23.0",
@@ -218,20 +220,20 @@
218
220
  "@yarnpkg/lockfile": "^1.1.0",
219
221
  "benchmark": "^2.1.4",
220
222
  "body-parser": "^2.3.0",
221
- "bun": "1.4.2",
223
+ "bun": "1.4.3",
222
224
  "c8": "^12.0.0",
223
225
  "codeowners-audit": "^2.9.0",
224
- "eslint": "^10.11.0",
226
+ "eslint": "^10.13.0",
225
227
  "eslint-plugin-cypress": "^7.0.2",
226
228
  "eslint-plugin-import-x": "^4.16.2",
227
- "eslint-plugin-jsdoc": "^64.5.4",
229
+ "eslint-plugin-jsdoc": "^65.3.12",
228
230
  "eslint-plugin-mocha": "^12.0.2",
229
- "eslint-plugin-n": "^18.4.0",
231
+ "eslint-plugin-n": "^18.5.0",
230
232
  "eslint-plugin-promise": "^7.3.0",
231
233
  "eslint-plugin-regexp": "^3.3.1",
232
234
  "eslint-plugin-sonarjs": "^4.2.2",
233
235
  "eslint-plugin-unicorn": "^74.0.0",
234
- "express": "^5.1.0",
236
+ "express": "^5.3.0",
235
237
  "glob": "^10.4.5",
236
238
  "globals": "^17.13.0",
237
239
  "graphql": "*",
@@ -56,12 +56,28 @@ const isACFActive = (() => {
56
56
  if (!isACFActive) {
57
57
  const superGetStore = AsyncLocalStorage.prototype.getStore
58
58
  const superEnterWith = AsyncLocalStorage.prototype.enterWith
59
+ // @ts-expect-error Node calls this undocumented AsyncLocalStorage hook.
60
+ const superPropagate = AsyncLocalStorage.prototype._propagate
59
61
 
60
62
  // Without ACF, ALS writes the entered value onto the async resource. Keep the
61
63
  // real store off the resource by entering a small handle and mapping it to
62
64
  // the store through a WeakMap, then reversing the lookup on read.
63
65
  const stores = new WeakMap()
64
66
 
67
+ /**
68
+ * Node can omit the trigger resource while the inspector is paused. Guard
69
+ * the shared hook because every enabled AsyncLocalStorage receives the call.
70
+ *
71
+ * @param {object} resource
72
+ * @param {object | undefined} triggerResource
73
+ * @param {string} type
74
+ */
75
+ AsyncLocalStorage.prototype._propagate = function _propagate (resource, triggerResource, type) {
76
+ if (triggerResource) {
77
+ superPropagate.call(this, resource, triggerResource, type)
78
+ }
79
+ }
80
+
65
81
  /**
66
82
  * @param {Store<unknown>} [store]
67
83
  */
@@ -8,6 +8,7 @@ const { pathToFileURL, fileURLToPath } = require('node:url')
8
8
  const instrumentations = require('../datadog-instrumentations/src/helpers/instrumentations')
9
9
  const extractPackageAndModulePath = require('../datadog-instrumentations/src/helpers/extract-package-and-module-path')
10
10
  const hooks = require('../datadog-instrumentations/src/helpers/hooks')
11
+ const { getValueFromEnvSources } = require('../dd-trace/src/config/helper')
11
12
  const log = require('./src/log')
12
13
  const { createEsmResolver } = require('./src/resolver')
13
14
  const { isESMFile, processModule } = require('./src/utils')
@@ -60,6 +61,7 @@ for (const builtin of builtinModules) {
60
61
 
61
62
  // eslint-disable-next-line eslint-rules/eslint-process-env
62
63
  const DD_IAST_ENABLED = process.env.DD_IAST_ENABLED?.toLowerCase() === 'true' || process.env.DD_IAST_ENABLED === '1'
64
+ const DD_BUNDLER_INJECT_GIT_METADATA = getValueFromEnvSources('DD_BUNDLER_INJECT_GIT_METADATA') !== false
63
65
 
64
66
  module.exports.name = 'datadog-esbuild'
65
67
 
@@ -143,26 +145,30 @@ globalThis.__dirname ??= $dd_dirname(globalThis.__filename);
143
145
  ${build.initialOptions.banner.js}`
144
146
  }
145
147
 
146
- // Get git metadata at build time and add it to the banner for both ESM and CommonJS builds
147
- const gitMetadata = getGitMetadata()
148
- if (gitMetadata.repositoryURL || gitMetadata.commitSHA) {
149
- build.initialOptions.banner ??= {}
150
- build.initialOptions.banner.js ??= ''
148
+ // Bake DD_GIT_* into the banner unless DD_BUNDLER_INJECT_GIT_METADATA=false (stable artifact hashes).
149
+ if (DD_BUNDLER_INJECT_GIT_METADATA) {
150
+ const gitMetadata = getGitMetadata()
151
+ if (gitMetadata.repositoryURL || gitMetadata.commitSHA) {
152
+ build.initialOptions.banner ??= {}
153
+ build.initialOptions.banner.js ??= ''
151
154
 
152
- build.initialOptions.banner.js = `if (typeof process === 'object' && process !== null &&
155
+ build.initialOptions.banner.js = `if (typeof process === 'object' && process !== null &&
153
156
  process.env !== null && typeof process.env === 'object') {
154
157
  ${gitMetadata.repositoryURL ? `process.env.DD_GIT_REPOSITORY_URL = '${gitMetadata.repositoryURL}';` : ''}
155
158
  ${gitMetadata.commitSHA ? `process.env.DD_GIT_COMMIT_SHA = '${gitMetadata.commitSHA}';` : ''}
156
159
  }
157
160
  ${build.initialOptions.banner.js}`
158
161
 
159
- log.debug(
160
- 'Automatically injected git metadata (DD_GIT_REPOSITORY_URL: %s, DD_GIT_COMMIT_SHA: %s)',
161
- gitMetadata.repositoryURL || 'not available',
162
- gitMetadata.commitSHA || 'not available'
163
- )
162
+ log.debug(
163
+ 'Automatically injected git metadata (DD_GIT_REPOSITORY_URL: %s, DD_GIT_COMMIT_SHA: %s)',
164
+ gitMetadata.repositoryURL || 'not available',
165
+ gitMetadata.commitSHA || 'not available'
166
+ )
167
+ } else {
168
+ log.warn('No git metadata available - skipping injection')
169
+ }
164
170
  } else {
165
- log.warn('No git metadata available - skipping injection')
171
+ log.debug('Skipping git metadata injection (DD_BUNDLER_INJECT_GIT_METADATA=false)')
166
172
  }
167
173
 
168
174
  let resolver