dd-trace 6.4.0 → 6.6.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 (185) hide show
  1. package/README.electron.md +7 -0
  2. package/README.md +17 -0
  3. package/ci/diagnose.js +2100 -0
  4. package/ci/init.js +23 -2
  5. package/ci/runbook.md +198 -0
  6. package/ci/test-optimization-validation/approval-artifacts.js +143 -0
  7. package/ci/test-optimization-validation/approval.js +299 -0
  8. package/ci/test-optimization-validation/artifact-id.js +20 -0
  9. package/ci/test-optimization-validation/bounded-json.js +121 -0
  10. package/ci/test-optimization-validation/ci-command-candidate.js +83 -0
  11. package/ci/test-optimization-validation/ci-discovery.js +181 -0
  12. package/ci/test-optimization-validation/ci-remediation.js +210 -0
  13. package/ci/test-optimization-validation/cli.js +903 -0
  14. package/ci/test-optimization-validation/command-blocker.js +81 -0
  15. package/ci/test-optimization-validation/command-output-policy.js +206 -0
  16. package/ci/test-optimization-validation/command-runner.js +707 -0
  17. package/ci/test-optimization-validation/command-suitability.js +471 -0
  18. package/ci/test-optimization-validation/executable-approval.js +48 -0
  19. package/ci/test-optimization-validation/executable.js +480 -0
  20. package/ci/test-optimization-validation/generated-file-policy.js +63 -0
  21. package/ci/test-optimization-validation/generated-files.js +351 -0
  22. package/ci/test-optimization-validation/generated-verifier.js +196 -0
  23. package/ci/test-optimization-validation/init-probe-preload.js +163 -0
  24. package/ci/test-optimization-validation/init-probe.js +246 -0
  25. package/ci/test-optimization-validation/late-initialization.js +63 -0
  26. package/ci/test-optimization-validation/local-command.js +163 -0
  27. package/ci/test-optimization-validation/manifest-loader.js +133 -0
  28. package/ci/test-optimization-validation/manifest-scaffold.js +738 -0
  29. package/ci/test-optimization-validation/manifest-schema.js +862 -0
  30. package/ci/test-optimization-validation/offline-fixtures.js +327 -0
  31. package/ci/test-optimization-validation/offline-output.js +406 -0
  32. package/ci/test-optimization-validation/payload-normalizer.js +72 -0
  33. package/ci/test-optimization-validation/plan-writer.js +1120 -0
  34. package/ci/test-optimization-validation/preflight-runner.js +114 -0
  35. package/ci/test-optimization-validation/redaction.js +331 -0
  36. package/ci/test-optimization-validation/report-writer.js +1508 -0
  37. package/ci/test-optimization-validation/safe-files.js +203 -0
  38. package/ci/test-optimization-validation/scenarios/auto-test-retries.js +159 -0
  39. package/ci/test-optimization-validation/scenarios/basic-reporting.js +657 -0
  40. package/ci/test-optimization-validation/scenarios/ci-wiring.js +780 -0
  41. package/ci/test-optimization-validation/scenarios/early-flake-detection.js +141 -0
  42. package/ci/test-optimization-validation/scenarios/helpers.js +539 -0
  43. package/ci/test-optimization-validation/scenarios/test-management.js +218 -0
  44. package/ci/test-optimization-validation/setup-runner.js +97 -0
  45. package/ci/test-optimization-validation/static-diagnosis.js +159 -0
  46. package/ci/test-optimization-validation/test-output.js +129 -0
  47. package/ci/test-optimization-validation-manifest.schema.json +1 -0
  48. package/ci/validate-test-optimization.js +3 -0
  49. package/ext/exporters.js +1 -0
  50. package/index.d.ts +121 -8
  51. package/init.js +18 -0
  52. package/initialize.mjs +1 -1
  53. package/loader-hook.mjs +28 -18
  54. package/openfeature.d.ts +1 -0
  55. package/openfeature.js +4 -0
  56. package/package.json +11 -8
  57. package/packages/datadog-instrumentations/src/ai.js +8 -2
  58. package/packages/datadog-instrumentations/src/child_process.js +1 -1
  59. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -1
  60. package/packages/datadog-instrumentations/src/cucumber-worker-threads.js +9 -3
  61. package/packages/datadog-instrumentations/src/cucumber.js +31 -19
  62. package/packages/datadog-instrumentations/src/cypress-config.js +398 -52
  63. package/packages/datadog-instrumentations/src/fastify.js +7 -11
  64. package/packages/datadog-instrumentations/src/helpers/channel.js +74 -0
  65. package/packages/datadog-instrumentations/src/helpers/hook.js +27 -6
  66. package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +8 -8
  67. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +28 -2
  68. package/packages/datadog-instrumentations/src/jest.js +44 -17
  69. package/packages/datadog-instrumentations/src/mariadb.js +1 -1
  70. package/packages/datadog-instrumentations/src/mocha/main.js +79 -32
  71. package/packages/datadog-instrumentations/src/mocha/utils.js +0 -4
  72. package/packages/datadog-instrumentations/src/mongodb.js +3 -3
  73. package/packages/datadog-instrumentations/src/mongoose.js +3 -3
  74. package/packages/datadog-instrumentations/src/mquery.js +2 -2
  75. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  76. package/packages/datadog-instrumentations/src/next.js +24 -0
  77. package/packages/datadog-instrumentations/src/nyc.js +0 -2
  78. package/packages/datadog-instrumentations/src/oracledb.js +2 -2
  79. package/packages/datadog-instrumentations/src/pg.js +2 -2
  80. package/packages/datadog-instrumentations/src/playwright.js +162 -46
  81. package/packages/datadog-instrumentations/src/process.js +3 -0
  82. package/packages/datadog-instrumentations/src/router.js +18 -8
  83. package/packages/datadog-instrumentations/src/selenium.js +52 -26
  84. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +3 -3
  85. package/packages/datadog-instrumentations/src/vitest-main.js +14 -28
  86. package/packages/datadog-instrumentations/src/vitest-util.js +0 -7
  87. package/packages/datadog-instrumentations/src/vitest-worker.js +5 -8
  88. package/packages/datadog-instrumentations/src/ws.js +2 -1
  89. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +2 -2
  90. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +2 -1
  91. package/packages/datadog-plugin-aws-sdk/src/util.js +2 -2
  92. package/packages/datadog-plugin-cucumber/src/index.js +3 -2
  93. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +19 -57
  94. package/packages/datadog-plugin-cypress/src/index.js +6 -1
  95. package/packages/datadog-plugin-cypress/src/support.js +92 -26
  96. package/packages/datadog-plugin-electron/src/ipc.js +1 -1
  97. package/packages/datadog-plugin-graphql/src/execute.js +87 -45
  98. package/packages/datadog-plugin-graphql/src/validate.js +2 -2
  99. package/packages/datadog-plugin-http2/src/client.js +1 -1
  100. package/packages/datadog-plugin-langchain/src/handlers/embedding.js +2 -1
  101. package/packages/datadog-plugin-langchain/src/handlers/language_models.js +2 -1
  102. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  103. package/packages/datadog-plugin-mocha/src/index.js +2 -1
  104. package/packages/datadog-plugin-playwright/src/index.js +181 -65
  105. package/packages/datadog-plugin-router/src/index.js +11 -2
  106. package/packages/datadog-plugin-selenium/src/index.js +5 -36
  107. package/packages/datadog-plugin-vitest/src/index.js +5 -5
  108. package/packages/datadog-plugin-ws/src/close.js +2 -1
  109. package/packages/datadog-plugin-ws/src/producer.js +2 -1
  110. package/packages/datadog-plugin-ws/src/receiver.js +2 -1
  111. package/packages/datadog-plugin-ws/src/server.js +2 -1
  112. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  113. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -2
  114. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +3 -1
  115. package/packages/dd-trace/src/azure_metadata.js +2 -1
  116. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +93 -28
  117. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
  118. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +160 -0
  119. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +288 -0
  120. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/payload-projection.js +84 -0
  121. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +369 -0
  122. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +60 -0
  123. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +41 -3
  124. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +7 -2
  125. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +1 -1
  126. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +6 -2
  127. package/packages/dd-trace/src/ci-visibility/rum.js +7 -0
  128. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
  129. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
  130. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +137 -9
  131. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +168 -8
  132. package/packages/dd-trace/src/ci-visibility/test-screenshot.js +90 -0
  133. package/packages/dd-trace/src/config/generated-config-types.d.ts +16 -0
  134. package/packages/dd-trace/src/config/helper.js +1 -0
  135. package/packages/dd-trace/src/config/index.js +10 -0
  136. package/packages/dd-trace/src/config/supported-configurations.json +66 -0
  137. package/packages/dd-trace/src/exporter.js +2 -0
  138. package/packages/dd-trace/src/exporters/common/client-library-headers.js +21 -0
  139. package/packages/dd-trace/src/exporters/common/request.js +59 -30
  140. package/packages/dd-trace/src/exporters/common/url.js +15 -1
  141. package/packages/dd-trace/src/feature-registry.js +10 -3
  142. package/packages/dd-trace/src/llmobs/experiments/client.js +113 -0
  143. package/packages/dd-trace/src/llmobs/experiments/dataset.js +154 -0
  144. package/packages/dd-trace/src/llmobs/experiments/experiment.js +283 -0
  145. package/packages/dd-trace/src/llmobs/experiments/index.js +152 -0
  146. package/packages/dd-trace/src/llmobs/experiments/noop.js +30 -0
  147. package/packages/dd-trace/src/llmobs/experiments/result.js +34 -0
  148. package/packages/dd-trace/src/llmobs/noop.js +6 -0
  149. package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +20 -3
  150. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +2 -2
  151. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  152. package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +8 -0
  153. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +48 -14
  154. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +43 -0
  155. package/packages/dd-trace/src/llmobs/sdk.js +17 -0
  156. package/packages/dd-trace/src/llmobs/tagger.js +68 -0
  157. package/packages/dd-trace/src/llmobs/telemetry.js +2 -1
  158. package/packages/dd-trace/src/llmobs/util.js +32 -0
  159. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +322 -0
  160. package/packages/dd-trace/src/openfeature/configuration_source.js +90 -0
  161. package/packages/dd-trace/src/openfeature/flagging_provider.js +14 -23
  162. package/packages/dd-trace/src/openfeature/index.js +0 -2
  163. package/packages/dd-trace/src/openfeature/noop.js +1 -28
  164. package/packages/dd-trace/src/openfeature/register.js +16 -27
  165. package/packages/dd-trace/src/openfeature/remote_config.js +15 -18
  166. package/packages/dd-trace/src/openfeature/require-provider.js +18 -0
  167. package/packages/dd-trace/src/opentelemetry/span-ending-hook.js +10 -0
  168. package/packages/dd-trace/src/opentelemetry/span.js +5 -0
  169. package/packages/dd-trace/src/plugins/ci_plugin.js +20 -6
  170. package/packages/dd-trace/src/plugins/util/git.js +3 -2
  171. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +29 -5
  172. package/packages/dd-trace/src/plugins/util/test.js +56 -4
  173. package/packages/dd-trace/src/profiling/profilers/space.js +1 -1
  174. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
  175. package/packages/dd-trace/src/proxy.js +84 -7
  176. package/packages/dd-trace/src/span_processor.js +5 -0
  177. package/packages/dd-trace/src/standalone/index.js +0 -14
  178. package/packages/dd-trace/src/telemetry/send-data.js +2 -2
  179. package/packages/dd-trace/src/util.js +26 -0
  180. package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
  181. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  182. package/vendor/dist/protobufjs/index.js +1 -1
  183. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  184. package/vendor/dist/shell-quote/index.js +1 -1
  185. package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +0 -17
package/index.d.ts CHANGED
@@ -156,12 +156,12 @@ interface Tracer extends opentracing.Tracer {
156
156
  llmobs: tracer.llmobs.LLMObs;
157
157
 
158
158
  /**
159
- * OpenFeature Provider with Remote Config integration.
159
+ * OpenFeature Provider with agentless and Agent Remote Config delivery.
160
160
  *
161
- * Extends DatadogNodeServerProvider with Remote Config integration for dynamic flag configuration.
162
- * Enable with DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true.
161
+ * Agentless delivery is enabled by default and starts when the provider is first accessed.
163
162
  *
164
- * @env DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED
163
+ * @env DD_FEATURE_FLAGS_ENABLED
164
+ * @env DD_FEATURE_FLAGS_CONFIGURATION_SOURCE
165
165
  * @beta This feature is in preview and not ready for production use
166
166
  */
167
167
  openfeature: tracer.OpenFeatureProvider;
@@ -799,9 +799,9 @@ declare namespace tracer {
799
799
  */
800
800
  flaggingProvider?: {
801
801
  /**
802
- * Whether to enable the feature flagging provider.
803
- * Requires Remote Config to be properly configured.
804
- * Can be configured via DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED environment variable.
802
+ * Legacy feature flagging provider switch.
803
+ * When the stable Feature Flags configuration is unset, true selects Agent Remote Config and false disables
804
+ * the provider.
805
805
  *
806
806
  * @default false
807
807
  * @env DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED
@@ -1620,7 +1620,7 @@ declare namespace tracer {
1620
1620
  /**
1621
1621
  * Flagging Provider (OpenFeature-compatible).
1622
1622
  *
1623
- * Wraps @datadog/openfeature-node-server with Remote Config integration for dynamic flag configuration.
1623
+ * Wraps @datadog/openfeature-node-server with agentless and Agent Remote Config delivery.
1624
1624
  * Implements the OpenFeature Provider interface for flag evaluation.
1625
1625
  *
1626
1626
  * @beta This feature is in preview and not ready for production use
@@ -3568,6 +3568,12 @@ declare namespace tracer {
3568
3568
  */
3569
3569
  enabled: boolean,
3570
3570
 
3571
+ /**
3572
+ * Datasets & Experiments API. Requires LLM Observability to be enabled and
3573
+ * `DD_API_KEY` / `DD_APP_KEY` to be set.
3574
+ */
3575
+ experiments: Experiments,
3576
+
3571
3577
  /**
3572
3578
  * Enable LLM Observability tracing.
3573
3579
  *
@@ -3721,6 +3727,93 @@ declare namespace tracer {
3721
3727
  flush (): void
3722
3728
  }
3723
3729
 
3730
+ /**
3731
+ * A task run over each dataset record during an experiment.
3732
+ */
3733
+ type ExperimentTask = (input: any, config: Record<string, any>) => any | Promise<any>
3734
+
3735
+ /**
3736
+ * Scores a single task output. The return type selects the metric:
3737
+ * `boolean` -> boolean, `number` -> score, anything else -> categorical.
3738
+ */
3739
+ type ExperimentEvaluator = (input: any, output: any, expectedOutput: any) => any | Promise<any>
3740
+
3741
+ interface ExperimentOptions {
3742
+ name: string
3743
+ dataset: Dataset
3744
+ task: ExperimentTask
3745
+ /** Evaluators keyed by metric label. */
3746
+ evaluators?: Record<string, ExperimentEvaluator>
3747
+ description?: string
3748
+ config?: Record<string, any>
3749
+ tags?: Record<string, string>
3750
+ }
3751
+
3752
+ interface PullDatasetOptions {
3753
+ /** Wait until at least this many records are readable (absorbs write lag). */
3754
+ expectedRecordCount?: number
3755
+ /** Maximum total time to wait, in ms. Default 30000. */
3756
+ maxWaitMs?: number
3757
+ }
3758
+
3759
+ interface ExperimentResultRow {
3760
+ index: number
3761
+ spanId: string
3762
+ traceId: string
3763
+ startNs: number
3764
+ durationNs: number
3765
+ input: any
3766
+ output: any
3767
+ expectedOutput: any
3768
+ readonly isError: boolean
3769
+ errorType: string | null
3770
+ errorMessage: string | null
3771
+ evaluations: Record<string, any>
3772
+ evaluationErrors: Record<string, string>
3773
+ }
3774
+
3775
+ interface ExperimentResult {
3776
+ experimentId: string
3777
+ rows: ExperimentResultRow[]
3778
+ /** Dashboard URL for the experiment. */
3779
+ url: string
3780
+ }
3781
+
3782
+ interface DatasetPushResult {
3783
+ /** Number of records from this push that were confirmed with a record id. */
3784
+ pushedCount: number
3785
+ /** Number of records attempted in this push. */
3786
+ totalCount: number
3787
+ }
3788
+
3789
+ interface Dataset {
3790
+ addRecord (input: any, expectedOutput?: any, metadata?: Record<string, any>): Dataset
3791
+ /** Creates the dataset remotely if needed and pushes any unpushed records. */
3792
+ push (): Promise<DatasetPushResult>
3793
+ name (): string
3794
+ id (): string | null
3795
+ projectId (): string | null
3796
+ records (): Array<{ input: any, expectedOutput: any, metadata: Record<string, any> }>
3797
+ /** Dashboard URL for the dataset, or null until pushed. */
3798
+ url (): string | null
3799
+ }
3800
+
3801
+ interface Experiment {
3802
+ name (): string
3803
+ experimentId (): string | null
3804
+ url (): string | null
3805
+ run (): Promise<ExperimentResult>
3806
+ }
3807
+
3808
+ interface Experiments {
3809
+ /** Create a local dataset buffer; pushed on the first experiment run. */
3810
+ createDataset (name: string, description?: string): Dataset
3811
+ /** Pull an existing dataset (with records) by name. */
3812
+ pullDataset (name: string, options?: PullDatasetOptions): Promise<Dataset>
3813
+ /** Build an experiment to run over a dataset. */
3814
+ experiment (options: ExperimentOptions): Experiment
3815
+ }
3816
+
3724
3817
  interface LLMObservabilitySpan {
3725
3818
  /**
3726
3819
  * The span kind
@@ -3833,6 +3926,26 @@ declare namespace tracer {
3833
3926
  * Tool calls of the message
3834
3927
  */
3835
3928
  toolCalls?: ToolCall[],
3929
+
3930
+ /**
3931
+ * Audio segments attached to the message (e.g. speech input/output)
3932
+ */
3933
+ audioParts?: AudioPart[],
3934
+ }
3935
+
3936
+ /**
3937
+ * Represents an audio segment attached to an LLM chat model message.
3938
+ */
3939
+ interface AudioPart {
3940
+ /**
3941
+ * The MIME type of the audio (e.g. "audio/wav", "audio/mpeg")
3942
+ */
3943
+ mimeType: string,
3944
+
3945
+ /**
3946
+ * The audio content as a base64-encoded string
3947
+ */
3948
+ content: string,
3836
3949
  }
3837
3950
 
3838
3951
  /**
package/init.js CHANGED
@@ -1,5 +1,23 @@
1
1
  'use strict'
2
2
 
3
+ // In PM2 cluster mode, per-app env vars arrive as a `pm2_env`
4
+ // JSON string after --require has already run so we extract them
5
+ // manually if present.
6
+ var pm2EnvStr = process.env.pm2_env
7
+ if (typeof pm2EnvStr === 'string') {
8
+ try {
9
+ var pm2Config = JSON.parse(pm2EnvStr)
10
+ var pm2Keys = Object.keys(pm2Config)
11
+ for (var i = 0; i < pm2Keys.length; i++) {
12
+ var k = pm2Keys[i]
13
+ var v = pm2Config[k]
14
+ if (v != null) {
15
+ process.env[k] = String(v)
16
+ }
17
+ }
18
+ } catch (e) {}
19
+ }
20
+
3
21
  var guard = require('./packages/dd-trace/src/guardrails')
4
22
 
5
23
  module.exports = guard(function () {
package/initialize.mjs CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  iitmExclusionRegExp,
23
23
  load as hookLoad,
24
24
  resolve as hookResolve,
25
- } from './loader-hook.mjs'
25
+ } from './loader-hook.mjs?initialize'
26
26
 
27
27
  let hasInsertedInit = false
28
28
  const initJsUrl = new URL('init.js', import.meta.url).href
package/loader-hook.mjs CHANGED
@@ -2,24 +2,22 @@
2
2
 
3
3
  import * as Module from 'node:module'
4
4
  import { pathToFileURL } from 'node:url'
5
+ import { isMainThread } from 'node:worker_threads'
5
6
 
6
7
  import { createHook, supportsSyncHooks } from 'import-in-the-middle/create-hook.mjs'
7
- import { initialize as origInitialize, load as origLoad, resolve } from 'import-in-the-middle/hook.mjs'
8
- import regexpEscapeModule from './vendor/dist/escape-string-regexp/index.js'
9
- import hooks from './packages/datadog-instrumentations/src/helpers/hooks.js'
10
- import configHelper from './packages/dd-trace/src/config/helper.js'
8
+ import { initialize as origInitialize, load as origLoad } from 'import-in-the-middle/hook.mjs'
11
9
  import * as rewriterLoader from './packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs'
12
- import { isRelativeRequire } from './packages/datadog-instrumentations/src/helpers/shared-utils.js'
13
10
 
14
11
  // This file must support Node.js 12.0.0 syntax
15
12
 
16
13
  const { builtinModules } = Module
17
- const regexpEscape = regexpEscapeModule.default
18
14
  const require = Module.createRequire(import.meta.url)
15
+ // The query marks initialize.mjs's application-thread preload; loader workers use the full graph.
16
+ const isInitializeMainThread = isMainThread && import.meta.url.endsWith('?initialize')
19
17
  let syncImportInTheMiddleHook
20
18
 
21
- // The config helper's named exports aren't visible to ESM; destructure the default.
22
- const { getValueFromEnvSources } = configHelper
19
+ let getValueFromEnvSources
20
+ let regexpEscape
23
21
 
24
22
  // Substrings of resolved URLs that import-in-the-middle must never wrap: re-export
25
23
  // shims and internal helper graphs that break when proxied, plus iitm's own files
@@ -32,15 +30,26 @@ export const iitmExclusionRegExp = /middle|langsmith|openai\/_shims|openai\/reso
32
30
  // against a regex metacharacter entering a package name.
33
31
  const includeModuleNames = new Set()
34
32
  let moduleNameAlternation = ''
35
- for (const moduleName of Object.keys(hooks)) {
36
- // Relative hooks resolve outside node_modules and are not instrumented here.
37
- if (isRelativeRequire(moduleName)) continue
38
- includeModuleNames.add(moduleName)
39
- // iitm matches a built-in by its node: specifier too, so mirror that and
40
- // wrap `import 'node:crypto'` as well as `import 'crypto'`.
41
- if (builtinModules.includes(moduleName)) includeModuleNames.add(`node:${moduleName}`)
42
- if (moduleNameAlternation !== '') moduleNameAlternation += '|'
43
- moduleNameAlternation += regexpEscape(moduleName)
33
+
34
+ if (!isInitializeMainThread) {
35
+ const regexpEscapeModule = require('./vendor/dist/escape-string-regexp/index.js')
36
+ const hooks = require('./packages/datadog-instrumentations/src/helpers/hooks.js')
37
+ const configHelper = require('./packages/dd-trace/src/config/helper.js')
38
+ const { isRelativeRequire } = require('./packages/datadog-instrumentations/src/helpers/shared-utils.js')
39
+
40
+ regexpEscape = regexpEscapeModule.default
41
+ getValueFromEnvSources = configHelper.getValueFromEnvSources
42
+
43
+ for (const moduleName of Object.keys(hooks)) {
44
+ // Relative hooks resolve outside node_modules and are not instrumented here.
45
+ if (isRelativeRequire(moduleName)) continue
46
+ includeModuleNames.add(moduleName)
47
+ // iitm matches a built-in by its node: specifier too, so mirror that and
48
+ // wrap `import 'node:crypto'` as well as `import 'crypto'`.
49
+ if (builtinModules.includes(moduleName)) includeModuleNames.add(`node:${moduleName}`)
50
+ if (moduleNameAlternation !== '') moduleNameAlternation += '|'
51
+ moduleNameAlternation += regexpEscape(moduleName)
52
+ }
44
53
  }
45
54
 
46
55
  const nodeModulesIncludeSource = `node_modules/(?:${moduleNameAlternation})/(?!node_modules).+`
@@ -181,4 +190,5 @@ function registerSyncLoaderHooks (data = {}) {
181
190
  return true
182
191
  }
183
192
 
184
- export { initialize, load, registerSyncLoaderHooks, resolve }
193
+ export { resolve } from 'import-in-the-middle/hook.mjs'
194
+ export { initialize, load, registerSyncLoaderHooks }
@@ -0,0 +1 @@
1
+ export {};
package/openfeature.js ADDED
@@ -0,0 +1,4 @@
1
+ 'use strict'
2
+
3
+ // Static fallback for file tracers that do not recognize the optional-peer wrapper.
4
+ require('@datadog/openfeature-node-server')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "6.4.0",
3
+ "version": "6.6.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -153,6 +153,8 @@
153
153
  "LICENSE.Apache",
154
154
  "LICENSE.BSD3",
155
155
  "loader-hook.mjs",
156
+ "openfeature.d.ts",
157
+ "openfeature.js",
156
158
  "packages/*/index.js",
157
159
  "packages/*/index.electron.js",
158
160
  "packages/*/lib/**/*",
@@ -168,7 +170,7 @@
168
170
  ],
169
171
  "dependencies": {
170
172
  "dc-polyfill": "^0.1.11",
171
- "import-in-the-middle": "^3.3.1",
173
+ "import-in-the-middle": "^3.3.2",
172
174
  "opentracing": ">=0.14.7"
173
175
  },
174
176
  "optionalDependencies": {
@@ -177,7 +179,7 @@
177
179
  "@datadog/native-iast-taint-tracking": "4.2.0",
178
180
  "@datadog/native-metrics": "3.1.2",
179
181
  "@datadog/openfeature-node-server": "2.0.0",
180
- "@datadog/pprof": "5.15.1",
182
+ "@datadog/pprof": "5.17.0",
181
183
  "@datadog/wasm-js-rewriter": "5.0.1",
182
184
  "@opentelemetry/api": ">=1.0.0 <1.10.0",
183
185
  "@opentelemetry/api-logs": "<1.0.0",
@@ -188,7 +190,7 @@
188
190
  "@actions/github": "^9.1.1",
189
191
  "@babel/helpers": "^8.0.0",
190
192
  "@eslint/eslintrc": "^3.3.5",
191
- "@eslint/js": "^9.39.2",
193
+ "@eslint/js": "^10.0.1",
192
194
  "@msgpack/msgpack": "^3.1.3",
193
195
  "@openfeature/core": "^1.11.0",
194
196
  "@openfeature/server-sdk": "~1.22.0",
@@ -196,21 +198,22 @@
196
198
  "@types/mocha": "^10.0.10",
197
199
  "@types/node": "^18.19.106",
198
200
  "@types/sinon": "^22.0.0",
201
+ "@vercel/nft": "^0.29.4",
199
202
  "axios": "^1.18.1",
200
203
  "benchmark": "^2.1.4",
201
204
  "body-parser": "^2.3.0",
202
205
  "bun": "1.3.14",
203
- "c8": "^11.0.0",
206
+ "c8": "^12.0.0",
204
207
  "codeowners-audit": "^2.9.0",
205
- "eslint": "^9.39.2",
208
+ "eslint": "^10.5.0",
206
209
  "eslint-plugin-cypress": "^6.4.2",
207
- "eslint-plugin-import": "^2.32.0",
210
+ "eslint-plugin-import-x": "^4.16.2",
208
211
  "eslint-plugin-jsdoc": "^63.0.12",
209
212
  "eslint-plugin-mocha": "^11.3.0",
210
213
  "eslint-plugin-n": "^18.2.1",
211
214
  "eslint-plugin-promise": "^7.3.0",
212
215
  "eslint-plugin-sonarjs": "^4.2.0",
213
- "eslint-plugin-unicorn": "^64.0.0",
216
+ "eslint-plugin-unicorn": "^68.0.0",
214
217
  "express": "^5.1.0",
215
218
  "glob": "^10.4.5",
216
219
  "globals": "^17.7.0",
@@ -127,7 +127,7 @@ function wrapTracer (tracer) {
127
127
  return function (...args) {
128
128
  const name = args[0]
129
129
  const options = args.length > 2 ? (args[1] ?? {}) : {} // startActiveSpan(name, fn)
130
- const cb = args[args.length - 1]
130
+ const cb = args.at(-1)
131
131
 
132
132
  const ctx = {
133
133
  name,
@@ -230,7 +230,13 @@ for (const hook of getHooks('ai')) {
230
230
  // generateObject, streamObject)
231
231
  tracingChannel('orchestrion:ai:resolveLanguageModel').subscribe({
232
232
  end (ctx) {
233
- wrapModelWithLifecycle(ctx.result)
233
+ const model = ctx.arguments[0]
234
+ if (typeof model !== 'string' && model !== ctx.result) {
235
+ wrapModelWithLifecycle(model)
236
+ wrappedModels.add(ctx.result)
237
+ } else {
238
+ wrapModelWithLifecycle(ctx.result)
239
+ }
234
240
  },
235
241
  })
236
242
 
@@ -190,7 +190,7 @@ function wrapChildProcessAsyncMethod (ChildProcess, shell = false) {
190
190
  const error = context.abortController.signal.reason || new Error('Aborted')
191
191
  childProcess.emit('error', error)
192
192
 
193
- const cb = context.callArgs[context.callArgs.length - 1]
193
+ const cb = context.callArgs.at(-1)
194
194
  if (typeof cb === 'function') {
195
195
  cb(error)
196
196
  }
@@ -496,7 +496,7 @@ function finishStream (chunks, ctx, error) {
496
496
 
497
497
  let processError
498
498
  if (chunks.length > 0) {
499
- const lastChunk = chunks[chunks.length - 1]
499
+ const lastChunk = chunks.at(-1)
500
500
  if (lastChunk?.type === 'result') ctx.output = lastChunk.result
501
501
 
502
502
  try {
@@ -9,11 +9,17 @@ const appRequire = createRequire(path.join(process.cwd(), 'package.json'))
9
9
 
10
10
  try {
11
11
  // Cucumber v13 parallel workers start from an ESM worker.mjs entrypoint, which
12
- // statically imports the internal runtime Worker before it runs support-code
12
+ // statically imports the internal runtime Worker/Executor before it runs support-code
13
13
  // requireModules. The regular module hook does not patch that internal worker
14
- // import, so this preload is injected into requireModules to patch the cached Worker
14
+ // import, so this preload is injected into requireModules to patch the cached class
15
15
  // prototype before Cucumber constructs the worker instance.
16
- patchCucumberWorkerRunTestCase(appRequire('@cucumber/cucumber/lib/runtime/worker'), true)
16
+ let runtimeExecutorPackage
17
+ try {
18
+ runtimeExecutorPackage = appRequire('@cucumber/cucumber/lib/runtime/executor')
19
+ } catch {
20
+ runtimeExecutorPackage = appRequire('@cucumber/cucumber/lib/runtime/worker')
21
+ }
22
+ patchCucumberWorkerRunTestCase(runtimeExecutorPackage, true)
17
23
  } catch {
18
24
  // Ignore preload failures so cucumber can keep running if its internals change.
19
25
  }
@@ -28,6 +28,7 @@ const {
28
28
  } = require('../../dd-trace/src/plugins/util/test')
29
29
  const { writeCoverageBackfillToCache } = require('../../dd-trace/src/ci-visibility/test-optimization-cache')
30
30
  const satisfies = require('../../../vendor/dist/semifies')
31
+ const { getChannelPromise } = require('./helpers/channel')
31
32
  const { addHook, channel } = require('./helpers/instrument')
32
33
 
33
34
  const cucumberWorkerThreadsPatchModule = require.resolve('./cucumber-worker-threads')
@@ -563,12 +564,6 @@ function getErrorFromCucumberResult (cucumberResult) {
563
564
  return error
564
565
  }
565
566
 
566
- function getChannelPromise (channelToPublishTo, frameworkVersion = null) {
567
- return new Promise(resolve => {
568
- channelToPublishTo.publish({ onDone: resolve, frameworkVersion })
569
- })
570
- }
571
-
572
567
  function getShouldBeSkippedSuite (pickle, suitesToSkip) {
573
568
  const testSuitePath = getTestSuitePath(pickle.uri, process.cwd())
574
569
  const isUnskippable = isMarkedAsUnskippable(pickle)
@@ -1036,7 +1031,9 @@ function testCaseHook (TestCaseRunner, version) {
1036
1031
  // Valid for old and new cucumber versions
1037
1032
  function getCucumberOptions (adapterOrCoordinator) {
1038
1033
  if (adapterOrCoordinator.adapter) {
1039
- return adapterOrCoordinator.adapter.worker?.options || adapterOrCoordinator.adapter.options
1034
+ return adapterOrCoordinator.adapter.worker?.options ||
1035
+ adapterOrCoordinator.adapter.executor?.options ||
1036
+ adapterOrCoordinator.adapter.options
1040
1037
  }
1041
1038
  return adapterOrCoordinator.options
1042
1039
  }
@@ -1054,7 +1051,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1054
1051
  }
1055
1052
  let errorSkippableRequest
1056
1053
 
1057
- const configurationResponse = await getChannelPromise(libraryConfigurationCh, frameworkVersion)
1054
+ const configurationResponse = await getChannelPromise(libraryConfigurationCh, { frameworkVersion }) || {}
1058
1055
 
1059
1056
  repositoryRoot = configurationResponse.repositoryRoot
1060
1057
  isItrEnabled = configurationResponse.libraryConfig?.isItrEnabled
@@ -1087,7 +1084,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1087
1084
 
1088
1085
  if (isKnownTestsEnabled) {
1089
1086
  const currentKnownTestsResponse = knownTestsResponse || await getChannelPromise(knownTestsCh)
1090
- if (currentKnownTestsResponse.err) {
1087
+ if (!currentKnownTestsResponse || currentKnownTestsResponse.err) {
1091
1088
  isEarlyFlakeDetectionEnabled = false
1092
1089
  isKnownTestsEnabled = false
1093
1090
  } else {
@@ -1096,7 +1093,9 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1096
1093
  }
1097
1094
 
1098
1095
  if (isSuitesSkippingEnabled) {
1099
- const skippableResponse = skippableSuitesResponse || await getChannelPromise(skippableSuitesCh)
1096
+ const skippableResponse = skippableSuitesResponse ||
1097
+ await getChannelPromise(skippableSuitesCh) ||
1098
+ { err: true }
1100
1099
 
1101
1100
  errorSkippableRequest = skippableResponse.err
1102
1101
  skippableSuites = skippableResponse.skippableSuites ?? []
@@ -1145,7 +1144,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1145
1144
  if (isTestManagementTestsEnabled) {
1146
1145
  const currentTestManagementTestsResponse =
1147
1146
  testManagementTestsResponse || await getChannelPromise(testManagementTestsCh)
1148
- if (currentTestManagementTestsResponse.err) {
1147
+ if (!currentTestManagementTestsResponse || currentTestManagementTestsResponse.err) {
1149
1148
  isTestManagementTestsEnabled = false
1150
1149
  } else {
1151
1150
  testManagementTests = currentTestManagementTestsResponse.testManagementTests
@@ -1154,7 +1153,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1154
1153
 
1155
1154
  if (isImpactedTestsEnabled) {
1156
1155
  const impactedTestsResponse = await getChannelPromise(modifiedFilesCh)
1157
- if (!impactedTestsResponse.err) {
1156
+ if (impactedTestsResponse && !impactedTestsResponse.err) {
1158
1157
  modifiedFiles = impactedTestsResponse.modifiedFiles
1159
1158
  }
1160
1159
  }
@@ -1213,7 +1212,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1213
1212
  global.__coverage__ = fromCoverageMapToCoverage(originalCoverageMap)
1214
1213
  }
1215
1214
 
1216
- sessionFinishCh.publish({
1215
+ const flushPromise = getChannelPromise(sessionFinishCh, {
1217
1216
  status: success ? 'pass' : 'fail',
1218
1217
  isSuitesSkipped,
1219
1218
  testCodeCoverageLinesTotal,
@@ -1226,9 +1225,11 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1226
1225
  isTestManagementTestsEnabled,
1227
1226
  isParallel,
1228
1227
  })
1228
+
1229
1229
  logTestOptimizationSummary({ attemptToFixExecutions })
1230
1230
  loggedAttemptToFixTests.clear()
1231
1231
  eventDataCollector = null
1232
+ await flushPromise
1232
1233
  return result
1233
1234
  }
1234
1235
  }
@@ -1434,13 +1435,14 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
1434
1435
  }
1435
1436
  }
1436
1437
 
1437
- function patchCucumberWorkerRunTestCase (workerPackage, isWorker) {
1438
- const workerPrototype = workerPackage?.Worker?.prototype
1439
- if (!workerPrototype || patchedCucumberWorkers.has(workerPrototype)) return
1438
+ function patchCucumberWorkerRunTestCase (runtimeExecutorPackage, isWorker) {
1439
+ const runtimeExecutorPrototype =
1440
+ runtimeExecutorPackage?.Worker?.prototype || runtimeExecutorPackage?.Executor?.prototype
1441
+ if (!runtimeExecutorPrototype || patchedCucumberWorkers.has(runtimeExecutorPrototype)) return
1440
1442
 
1441
- patchedCucumberWorkers.add(workerPrototype)
1443
+ patchedCucumberWorkers.add(runtimeExecutorPrototype)
1442
1444
  shimmer.wrap(
1443
- workerPrototype,
1445
+ runtimeExecutorPrototype,
1444
1446
  'runTestCase',
1445
1447
  runTestCase => getWrappedRunTestCase(runTestCase, true, isWorker)
1446
1448
  )
@@ -1572,15 +1574,25 @@ addHook({
1572
1574
  // `getWrappedRunTestCase` does two things:
1573
1575
  // - generates suite start and finish events in the main process,
1574
1576
  // - handles EFD in both the main process and the worker process.
1577
+ // Shimmer is required because this wrapper may invoke the original test case multiple times and mutate runtime options.
1575
1578
  addHook({
1576
1579
  name: '@cucumber/cucumber',
1577
- versions: ['>=11.0.0'],
1580
+ versions: ['>=11.0.0 <13.2.0'],
1578
1581
  file: 'lib/runtime/worker.js',
1579
1582
  }, (workerPackage) => {
1580
1583
  patchCucumberWorkerRunTestCase(workerPackage, !!getEnvironmentVariable('CUCUMBER_WORKER_ID'))
1581
1584
  return workerPackage
1582
1585
  })
1583
1586
 
1587
+ addHook({
1588
+ name: '@cucumber/cucumber',
1589
+ versions: ['>=13.2.0'],
1590
+ file: 'lib/runtime/executor.js',
1591
+ }, (executorPackage) => {
1592
+ patchCucumberWorkerRunTestCase(executorPackage, !!getEnvironmentVariable('CUCUMBER_WORKER_ID'))
1593
+ return executorPackage
1594
+ })
1595
+
1584
1596
  // `getWrappedStart` generates session start and finish events
1585
1597
  addHook({
1586
1598
  name: '@cucumber/cucumber',