dd-trace 6.7.0 → 6.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/ci/diagnose.js +27 -25
  2. package/ci/init.js +6 -6
  3. package/ci/runbook.md +114 -20
  4. package/ci/test-optimization-validation/approval-artifacts.js +36 -3
  5. package/ci/test-optimization-validation/approval.js +78 -22
  6. package/ci/test-optimization-validation/blocker-category.js +24 -0
  7. package/ci/test-optimization-validation/ci-discovery.js +23 -17
  8. package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
  9. package/ci/test-optimization-validation/ci-remediation.js +1 -1
  10. package/ci/test-optimization-validation/cli.js +280 -52
  11. package/ci/test-optimization-validation/command-blocker.js +159 -20
  12. package/ci/test-optimization-validation/command-output-policy.js +14 -8
  13. package/ci/test-optimization-validation/command-runner.js +9 -7
  14. package/ci/test-optimization-validation/environment.js +4 -2
  15. package/ci/test-optimization-validation/executable.js +15 -13
  16. package/ci/test-optimization-validation/execution-lock.js +70 -0
  17. package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
  18. package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
  19. package/ci/test-optimization-validation/framework-adapters/playwright.js +5 -5
  20. package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
  21. package/ci/test-optimization-validation/generated-files.js +47 -37
  22. package/ci/test-optimization-validation/generated-test-contract.js +9 -7
  23. package/ci/test-optimization-validation/generated-verifier.js +24 -17
  24. package/ci/test-optimization-validation/literal-glob.js +52 -0
  25. package/ci/test-optimization-validation/manifest-loader.js +3 -0
  26. package/ci/test-optimization-validation/manifest-scaffold.js +301 -52
  27. package/ci/test-optimization-validation/manifest-schema.js +80 -17
  28. package/ci/test-optimization-validation/offline-fixtures.js +13 -4
  29. package/ci/test-optimization-validation/offline-output.js +6 -6
  30. package/ci/test-optimization-validation/package-check.js +94 -0
  31. package/ci/test-optimization-validation/plan-writer.js +183 -10
  32. package/ci/test-optimization-validation/preflight-runner.js +110 -31
  33. package/ci/test-optimization-validation/project-build-artifact.js +31 -0
  34. package/ci/test-optimization-validation/redaction.js +18 -27
  35. package/ci/test-optimization-validation/report-writer.js +182 -48
  36. package/ci/test-optimization-validation/result-semantics.js +20 -3
  37. package/ci/test-optimization-validation/runner-command.js +41 -21
  38. package/ci/test-optimization-validation/runner-contract.js +79 -43
  39. package/ci/test-optimization-validation/safe-files.js +4 -4
  40. package/ci/test-optimization-validation/scenarios/basic-reporting.js +60 -6
  41. package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
  42. package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
  43. package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
  44. package/ci/test-optimization-validation/static-diagnosis.js +10 -3
  45. package/ci/test-optimization-validation/test-output.js +2 -1
  46. package/ci/test-optimization-validation/validation-blocker.js +21 -0
  47. package/ci/vitest-no-worker-init-setup.mjs +377 -84
  48. package/index.d.ts +175 -14
  49. package/init.js +1 -17
  50. package/initialize.mjs +11 -0
  51. package/loader-hook.mjs +6 -4
  52. package/package.json +12 -4
  53. package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
  54. package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
  55. package/packages/datadog-esbuild/index.js +4 -2
  56. package/packages/datadog-esbuild/src/utils.js +17 -2
  57. package/packages/datadog-instrumentations/src/ai.js +61 -34
  58. package/packages/datadog-instrumentations/src/bluebird.js +6 -6
  59. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +85 -9
  60. package/packages/datadog-instrumentations/src/cucumber.js +131 -51
  61. package/packages/datadog-instrumentations/src/dns.js +21 -2
  62. package/packages/datadog-instrumentations/src/electron.js +1 -0
  63. package/packages/datadog-instrumentations/src/fastify.js +3 -1
  64. package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
  65. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
  66. package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
  67. package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
  68. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  69. package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
  70. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
  71. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  72. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +175 -0
  73. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
  74. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
  75. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +61 -0
  76. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
  77. package/packages/datadog-instrumentations/src/helpers/router-helper.js +38 -7
  78. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
  79. package/packages/datadog-instrumentations/src/http/client.js +1 -3
  80. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
  81. package/packages/datadog-instrumentations/src/jest.js +986 -246
  82. package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
  83. package/packages/datadog-instrumentations/src/mocha/main.js +109 -51
  84. package/packages/datadog-instrumentations/src/mocha/utils.js +120 -32
  85. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +44 -0
  86. package/packages/datadog-instrumentations/src/mocha/worker.js +441 -43
  87. package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
  88. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  89. package/packages/datadog-instrumentations/src/next.js +155 -23
  90. package/packages/datadog-instrumentations/src/openai.js +14 -0
  91. package/packages/datadog-instrumentations/src/pg.js +180 -6
  92. package/packages/datadog-instrumentations/src/playwright.js +176 -81
  93. package/packages/datadog-instrumentations/src/promise-js.js +4 -4
  94. package/packages/datadog-instrumentations/src/promise.js +3 -3
  95. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  96. package/packages/datadog-instrumentations/src/router.js +195 -19
  97. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +567 -65
  98. package/packages/datadog-instrumentations/src/vitest-main.js +438 -54
  99. package/packages/datadog-instrumentations/src/vitest-util.js +42 -7
  100. package/packages/datadog-instrumentations/src/vitest-worker.js +234 -17
  101. package/packages/datadog-instrumentations/src/webdriverio.js +1090 -0
  102. package/packages/datadog-instrumentations/src/when.js +3 -3
  103. package/packages/datadog-instrumentations/src/ws.js +5 -1
  104. package/packages/datadog-plugin-aerospike/src/index.js +1 -3
  105. package/packages/datadog-plugin-amqplib/src/client.js +1 -1
  106. package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
  107. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
  108. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  109. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
  110. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
  111. package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
  112. package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
  113. package/packages/datadog-plugin-child_process/src/index.js +3 -3
  114. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -11
  115. package/packages/datadog-plugin-cucumber/src/index.js +5 -1
  116. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +50 -46
  117. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
  118. package/packages/datadog-plugin-cypress/src/support.js +7 -4
  119. package/packages/datadog-plugin-electron/src/net.js +10 -4
  120. package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
  121. package/packages/datadog-plugin-fs/src/index.js +0 -4
  122. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
  123. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
  124. package/packages/datadog-plugin-graphql/src/execute.js +1 -0
  125. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
  126. package/packages/datadog-plugin-http/src/client.js +3 -2
  127. package/packages/datadog-plugin-http2/src/client.js +1 -1
  128. package/packages/datadog-plugin-jest/src/index.js +3 -21
  129. package/packages/datadog-plugin-jest/src/util.js +4 -1
  130. package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
  131. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  132. package/packages/datadog-plugin-mocha/src/index.js +342 -6
  133. package/packages/datadog-plugin-next/src/index.js +57 -9
  134. package/packages/datadog-plugin-openai/src/tracing.js +4 -0
  135. package/packages/datadog-plugin-pg/src/index.js +65 -1
  136. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  137. package/packages/datadog-plugin-prisma/src/index.js +5 -1
  138. package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
  139. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  140. package/packages/datadog-plugin-undici/src/index.js +2 -1
  141. package/packages/datadog-plugin-vitest/src/index.js +179 -18
  142. package/packages/datadog-shimmer/src/shimmer.js +6 -2
  143. package/packages/datadog-webpack/index.js +2 -2
  144. package/packages/dd-trace/src/aiguard/sdk.js +3 -0
  145. package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
  146. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
  147. package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
  148. package/packages/dd-trace/src/appsec/handlers/http-request.js +215 -0
  149. package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
  150. package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
  151. package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
  152. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  153. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
  154. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
  155. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  156. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
  157. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
  158. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
  159. package/packages/dd-trace/src/appsec/index.js +48 -476
  160. package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -1
  161. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  162. package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
  163. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
  164. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
  165. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -15
  166. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +19 -1
  167. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +25 -1
  168. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
  169. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
  170. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
  171. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
  172. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
  173. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
  174. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +2 -2
  175. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
  176. package/packages/dd-trace/src/config/defaults.js +14 -6
  177. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
  178. package/packages/dd-trace/src/config/helper.js +2 -0
  179. package/packages/dd-trace/src/config/index.js +31 -5
  180. package/packages/dd-trace/src/config/parsers.js +19 -1
  181. package/packages/dd-trace/src/config/remote_config.js +1 -1
  182. package/packages/dd-trace/src/config/supported-configurations.json +13 -6
  183. package/packages/dd-trace/src/datastreams/encoding.js +3 -4
  184. package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
  185. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
  186. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
  187. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
  188. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
  189. package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
  190. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
  191. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  192. package/packages/dd-trace/src/exporters/common/url.js +3 -5
  193. package/packages/dd-trace/src/exporters/electron/index.js +4 -1
  194. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  195. package/packages/dd-trace/src/flare/index.js +2 -2
  196. package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
  197. package/packages/dd-trace/src/guardrails/log.js +1 -10
  198. package/packages/dd-trace/src/id.js +1 -1
  199. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
  200. package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
  201. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
  202. package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
  203. package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
  204. package/packages/dd-trace/src/llmobs/experiments/index.js +66 -19
  205. package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
  206. package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
  207. package/packages/dd-trace/src/llmobs/experiments/util.js +220 -0
  208. package/packages/dd-trace/src/llmobs/noop.js +2 -0
  209. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
  210. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  211. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
  212. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
  213. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
  214. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  215. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  216. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
  217. package/packages/dd-trace/src/llmobs/sdk.js +152 -78
  218. package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
  219. package/packages/dd-trace/src/llmobs/tagger.js +1 -2
  220. package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
  221. package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
  222. package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
  223. package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
  224. package/packages/dd-trace/src/log/channels.js +1 -9
  225. package/packages/dd-trace/src/log/levels.js +12 -0
  226. package/packages/dd-trace/src/noop/proxy.js +2 -2
  227. package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
  228. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  229. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
  230. package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
  231. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  232. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
  233. package/packages/dd-trace/src/opentelemetry/span.js +4 -0
  234. package/packages/dd-trace/src/opentracing/span.js +1 -1
  235. package/packages/dd-trace/src/opentracing/span_context.js +1 -1
  236. package/packages/dd-trace/src/plugins/ci_plugin.js +124 -23
  237. package/packages/dd-trace/src/plugins/index.js +2 -0
  238. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  239. package/packages/dd-trace/src/plugins/tracing.js +1 -0
  240. package/packages/dd-trace/src/plugins/util/ci.js +13 -6
  241. package/packages/dd-trace/src/plugins/util/git.js +7 -5
  242. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +3 -3
  243. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
  244. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  245. package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
  246. package/packages/dd-trace/src/plugins/util/tags.js +2 -0
  247. package/packages/dd-trace/src/plugins/util/test.js +356 -86
  248. package/packages/dd-trace/src/plugins/util/url.js +5 -5
  249. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  250. package/packages/dd-trace/src/plugins/util/web.js +24 -2
  251. package/packages/dd-trace/src/priority_sampler.js +6 -3
  252. package/packages/dd-trace/src/profiler.js +1 -1
  253. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
  254. package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
  255. package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
  256. package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
  257. package/packages/dd-trace/src/proxy.js +1 -0
  258. package/packages/dd-trace/src/ritm.js +10 -20
  259. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
  260. package/packages/dd-trace/src/sampling_rule.js +4 -2
  261. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
  262. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
  263. package/packages/dd-trace/src/startup-log.js +3 -0
  264. package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
  265. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
  266. package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
  267. package/packages/dd-trace/src/util.js +16 -0
  268. package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
  269. package/vendor/dist/pprof-format/index.js +1 -1
  270. package/vendor/dist/source-map/index.js +1 -1
  271. package/version.js +10 -8
  272. /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
@@ -13,6 +13,8 @@ const errorChannel = channel('apm:grpc:client:request:error')
13
13
  const finishChannel = channel('apm:grpc:client:request:finish')
14
14
  const emitChannel = channel('apm:grpc:client:request:emit')
15
15
 
16
+ /** @typedef {{ length: number, [index: number]: unknown } & Iterable<unknown>} ArgumentsLike */
17
+
16
18
  function createWrapMakeRequest (type, hasPeer = false) {
17
19
  const metadataIndex = type === types.client_stream || type === types.bidi ? 3 : 4
18
20
 
@@ -186,9 +188,9 @@ function callMethod (client, method, args, path, metadata, type, hasPeer = false
186
188
  * one at `index` when the user did not pass their own.
187
189
  *
188
190
  * @param {object} client
189
- * @param {ArrayLike<unknown>} args
191
+ * @param {ArgumentsLike} args
190
192
  * @param {number} index
191
- * @returns {{ metadata: object | undefined, args: ArrayLike<unknown> }}
193
+ * @returns {{ metadata: object | undefined, args: ArgumentsLike }}
192
194
  */
193
195
  function resolveMetadata (client, args, index) {
194
196
  const grpc = client && getGrpc(client)
@@ -3,6 +3,8 @@
3
3
  const shimmer = require('../../../datadog-shimmer')
4
4
  const { channel } = require('./instrument')
5
5
 
6
+ /** @typedef {{ length: number, [index: number]: unknown } & Iterable<unknown>} ArgumentsLike */
7
+
6
8
  /**
7
9
  * Create a shimmer-compatible instrumentor for callback-style APIs whose work is offloaded to the
8
10
  * libuv worker thread pool (e.g. zlib.gzip, crypto.pbkdf2, dns.lookup). Builds a set of three
@@ -22,7 +24,7 @@ const { channel } = require('./instrument')
22
24
  * @param {boolean} [options.captureResult] set `ctx.result` to the callback's first
23
25
  * non-error argument before publishing `:finish`. Plugins that tag spans from the call's
24
26
  * return value (e.g. the DNS lookup plugin) rely on this.
25
- * @returns {(buildContext: (thisArg: unknown, args: IArguments) => object | undefined) =>
27
+ * @returns {(buildContext: (thisArg: unknown, args: ArgumentsLike) => object | undefined) =>
26
28
  * (fn: Function) => Function}
27
29
  */
28
30
  function createCallbackInstrumentor (prefix, { captureResult = false } = {}) {
@@ -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
@@ -58,6 +58,10 @@ module.exports = {
58
58
  '@smithy/core': () => require('../aws-sdk'),
59
59
  '@smithy/smithy-client': () => require('../aws-sdk'),
60
60
  '@vitest/runner': { esmFirst: true, fn: () => require('../vitest') },
61
+ '@wdio/cli': { esmFirst: true, fn: () => require('../webdriverio') },
62
+ '@wdio/jasmine-framework': { esmFirst: true, fn: () => require('../webdriverio') },
63
+ '@wdio/local-runner': { esmFirst: true, fn: () => require('../webdriverio') },
64
+ '@wdio/utils': { esmFirst: true, fn: () => require('../webdriverio') },
61
65
  aerospike: () => require('../aerospike'),
62
66
  ai: () => require('../ai'),
63
67
  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}`,
@@ -5,8 +5,9 @@ const { join } = require('path')
5
5
  const { pathToFileURL } = require('url')
6
6
  const log = require('../../../../dd-trace/src/log')
7
7
  const { create } = require('../../../../../vendor/dist/@apm-js-collab/code-transformer')
8
- const { waitForAsyncEnd } = require('./transforms')
9
8
  const instrumentations = require('./instrumentations')
9
+ const { getRewriteTarget } = require('./targets')
10
+ const { waitForAsyncEnd } = require('./transforms')
10
11
 
11
12
  // `dc-polyfill` is referenced from injected `require()` (CJS) and `import`
12
13
  // (ESM) statements that the transformer splices into the rewritten module.
@@ -39,20 +40,26 @@ for (const matcher of [matcherCjs, matcherEsm]) {
39
40
 
40
41
  // Keep the marker split: source-map scanners can read a contiguous token in
41
42
  // string literals as this file's own inline map.
43
+ // eslint-disable-next-line unicorn/no-useless-concat -- Keep the source-map marker non-contiguous.
42
44
  const SOURCE_MAP_PREFIX = '//# sourceMapping' + 'URL=data:application/json;base64,'
43
45
 
44
- function rewrite (content, filename, format) {
46
+ /**
47
+ * @param {string|Buffer|ArrayBuffer|Uint8Array} content
48
+ * @param {string} filename
49
+ * @param {string} [format]
50
+ * @param {{ moduleName: string, filePath: string }} [target]
51
+ * @returns {string|Buffer|ArrayBuffer|Uint8Array}
52
+ */
53
+ function rewrite (content, filename, format, target) {
45
54
  if (!content) return content
46
- if (!filename.includes('node_modules')) return content
55
+
56
+ target ||= getRewriteTarget(filename)
57
+ if (!target) return content
47
58
 
48
59
  filename = filename.replace('file://', '')
49
60
 
50
61
  const moduleType = format === 'module' ? 'esm' : 'cjs'
51
- const [modulePath] = filename.split('/node_modules/').reverse()
52
- const moduleParts = modulePath.split('/')
53
- const splitIndex = moduleParts[0].startsWith('@') ? 2 : 1
54
- const moduleName = moduleParts.slice(0, splitIndex).join('/')
55
- const filePath = moduleParts.slice(splitIndex).join('/')
62
+ const { moduleName, filePath } = target
56
63
  const version = getVersion(filename, filePath)
57
64
 
58
65
  if (disabled.has(moduleName)) return content
@@ -63,8 +70,10 @@ function rewrite (content, filename, format) {
63
70
  if (!transformer) return content
64
71
 
65
72
  try {
73
+ const source = getSourceText(content)
74
+
66
75
  // TODO: pass existing sourcemap as input for remapping
67
- const { code, map } = transformer.transform(content, moduleType)
76
+ const { code, map } = transformer.transform(source, moduleType)
68
77
 
69
78
  if (!map) return code
70
79
 
@@ -78,6 +87,22 @@ function rewrite (content, filename, format) {
78
87
  return content
79
88
  }
80
89
 
90
+ /** @typedef {{ buffer: ArrayBuffer | SharedArrayBuffer, byteLength: number, byteOffset: number }} BufferView */
91
+
92
+ /**
93
+ * Convert the source representations accepted by Node.js loader hooks to text.
94
+ *
95
+ * @param {string | ArrayBuffer | BufferView} source
96
+ * @returns {string}
97
+ */
98
+ function getSourceText (source) {
99
+ if (typeof source === 'string') return source
100
+ if (ArrayBuffer.isView(source)) {
101
+ return Buffer.from(source.buffer, source.byteOffset, source.byteLength).toString('utf8')
102
+ }
103
+ return Buffer.from(source).toString('utf8')
104
+ }
105
+
81
106
  function disable (instrumentation) {
82
107
  disabled.add(instrumentation)
83
108
  }
@@ -12,5 +12,6 @@ module.exports = [
12
12
  ...require('./modelcontextprotocol-sdk'),
13
13
  ...require('./openai-agents'),
14
14
  ...require('./playwright'),
15
+ ...require('./webdriverio'),
15
16
  ...require('./aws-durable-execution-sdk-js'),
16
17
  ]
@@ -0,0 +1,175 @@
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
+ {
58
+ module: {
59
+ name: '@wdio/jasmine-framework',
60
+ versionRange: '>=9.0.0',
61
+ filePath: 'build/index.js',
62
+ },
63
+ functionQuery: {
64
+ className: 'JasmineAdapter',
65
+ methodName: 'init',
66
+ kind: 'Async',
67
+ },
68
+ channelName: 'JasmineAdapter_init',
69
+ },
70
+ {
71
+ module: {
72
+ name: '@wdio/jasmine-framework',
73
+ versionRange: '>=9.0.0',
74
+ filePath: 'build/index.js',
75
+ },
76
+ astQuery: 'VariableDeclarator[id.name="JasmineAdapter"] > ClassExpression > ClassBody > ' +
77
+ 'MethodDefinition[key.name="init"] ReturnStatement > ' +
78
+ 'CallExpression[callee.object.name="promise"][callee.property.name="then"], ' +
79
+ 'ClassDeclaration[id.name="JasmineAdapter"] > ClassBody > MethodDefinition[key.name="init"] ReturnStatement > ' +
80
+ 'CallExpression[callee.object.name="promise"][callee.property.name="then"]',
81
+ channelName: 'JasmineAdapter_init',
82
+ transform: 'waitForAsyncEnd',
83
+ },
84
+ {
85
+ module: {
86
+ name: '@wdio/jasmine-framework',
87
+ versionRange: '>=9.0.0',
88
+ filePath: 'build/index.js',
89
+ },
90
+ functionQuery: {
91
+ className: 'JasmineAdapter',
92
+ methodName: 'run',
93
+ kind: 'Async',
94
+ },
95
+ channelName: 'JasmineAdapter_run',
96
+ },
97
+ {
98
+ module: {
99
+ name: '@wdio/jasmine-framework',
100
+ versionRange: '>=9.0.0',
101
+ filePath: 'build/index.js',
102
+ },
103
+ astQuery: 'VariableDeclarator[id.name="JasmineAdapter"] > ClassExpression > ClassBody > ' +
104
+ 'MethodDefinition[key.name="run"] ReturnStatement > ' +
105
+ 'CallExpression[callee.object.name="promise"][callee.property.name="then"], ' +
106
+ 'ClassDeclaration[id.name="JasmineAdapter"] > ClassBody > MethodDefinition[key.name="run"] ReturnStatement > ' +
107
+ 'CallExpression[callee.object.name="promise"][callee.property.name="then"]',
108
+ channelName: 'JasmineAdapter_run',
109
+ transform: 'waitForAsyncEnd',
110
+ },
111
+ {
112
+ module: {
113
+ name: '@wdio/jasmine-framework',
114
+ versionRange: '>=9.0.0',
115
+ filePath: 'build/index.js',
116
+ },
117
+ functionQuery: {
118
+ className: 'JasmineReporter',
119
+ methodName: 'specDone',
120
+ kind: 'Sync',
121
+ },
122
+ channelName: 'JasmineReporter_specDone',
123
+ },
124
+ {
125
+ module: {
126
+ name: '@wdio/jasmine-framework',
127
+ versionRange: '>=9.0.0',
128
+ filePath: 'build/index.js',
129
+ },
130
+ functionQuery: {
131
+ className: 'JasmineReporter',
132
+ methodName: 'specStarted',
133
+ kind: 'Sync',
134
+ },
135
+ channelName: 'JasmineReporter_specStarted',
136
+ },
137
+ {
138
+ module: {
139
+ name: '@wdio/jasmine-framework',
140
+ versionRange: '>=9.0.0',
141
+ filePath: 'build/index.js',
142
+ },
143
+ functionQuery: {
144
+ className: 'JasmineReporter',
145
+ methodName: 'suiteStarted',
146
+ kind: 'Sync',
147
+ },
148
+ channelName: 'JasmineReporter_suiteStarted',
149
+ },
150
+ {
151
+ module: {
152
+ name: '@wdio/jasmine-framework',
153
+ versionRange: '>=9.0.0',
154
+ filePath: 'build/index.js',
155
+ },
156
+ functionQuery: {
157
+ className: 'JasmineReporter',
158
+ methodName: 'suiteDone',
159
+ kind: 'Sync',
160
+ },
161
+ channelName: 'JasmineReporter_suiteDone',
162
+ },
163
+ {
164
+ module: {
165
+ name: '@wdio/utils',
166
+ versionRange: '>=9.0.0',
167
+ filePath: 'build/index.js',
168
+ },
169
+ functionQuery: {
170
+ expressionName: 'testFrameworkFnWrapper',
171
+ kind: 'Async',
172
+ },
173
+ channelName: 'testFrameworkFnWrapper',
174
+ },
175
+ ]
@@ -1,4 +1,8 @@
1
- import { rewrite } from './index.js'
1
+ import * as Module from 'module'
2
+
3
+ const require = Module.createRequire(import.meta.url)
4
+ const { getRewriteTarget } = require('./targets.js')
5
+ let rewriter
2
6
 
3
7
  async function load (url, context, nextLoad) {
4
8
  const result = await nextLoad(url, context)
@@ -12,6 +16,11 @@ function loadSync (url, context, nextLoad) {
12
16
  return rewriteResult(result, url, context)
13
17
  }
14
18
 
19
+ /**
20
+ * @param {{ format?: string, source?: unknown }} result
21
+ * @param {string} url
22
+ * @param {{ format?: string }} context
23
+ */
15
24
  function rewriteResult (result, url, context) {
16
25
  const format = result.format || context.format
17
26
 
@@ -19,7 +28,16 @@ function rewriteResult (result, url, context) {
19
28
  // double-instruments CommonJS entrypoints loaded through sync hooks.
20
29
  if (format === 'commonjs') return result
21
30
 
22
- result.source = rewrite(result.source, url, format)
31
+ if (result.source) {
32
+ const target = getRewriteTarget(url)
33
+ if (target) {
34
+ if (!rewriter) {
35
+ rewriter = require('./index.js')
36
+ }
37
+
38
+ result.source = rewriter.rewrite(result.source, url, format, target)
39
+ }
40
+ }
23
41
 
24
42
  return result
25
43
  }
@@ -0,0 +1,32 @@
1
+ 'use strict'
2
+
3
+ // Generated by scripts/generate-rewriter-targets.js from ./instrumentations. Do not edit by hand.
4
+ const targets = require('./targets.json')
5
+
6
+ const NODE_MODULES = '/node_modules/'
7
+
8
+ /**
9
+ * @typedef {object} RewriteTarget
10
+ * @property {string} moduleName
11
+ * @property {string} filePath
12
+ */
13
+
14
+ /**
15
+ * @param {string} filename
16
+ * @returns {RewriteTarget|undefined}
17
+ */
18
+ function getRewriteTarget (filename) {
19
+ const nodeModulesIndex = filename.lastIndexOf(NODE_MODULES)
20
+ if (nodeModulesIndex === -1) return
21
+
22
+ const modulePath = filename.slice(nodeModulesIndex + NODE_MODULES.length)
23
+ const moduleName = targets[modulePath]
24
+ if (typeof moduleName !== 'string') return
25
+
26
+ return {
27
+ moduleName,
28
+ filePath: modulePath.slice(moduleName.length + 1),
29
+ }
30
+ }
31
+
32
+ module.exports = { getRewriteTarget }
@@ -0,0 +1,61 @@
1
+ {
2
+ "@anthropic-ai/claude-agent-sdk/sdk.mjs": "@anthropic-ai/claude-agent-sdk",
3
+ "@aws/durable-execution-sdk-js/dist-cjs/index.js": "@aws/durable-execution-sdk-js",
4
+ "@aws/durable-execution-sdk-js/dist/index.mjs": "@aws/durable-execution-sdk-js",
5
+ "@azure/cosmos/dist/browser/plugins/Plugin.js": "@azure/cosmos",
6
+ "@azure/cosmos/dist/commonjs/plugins/Plugin.js": "@azure/cosmos",
7
+ "@azure/cosmos/dist/esm/plugins/Plugin.js": "@azure/cosmos",
8
+ "@azure/cosmos/dist/react-native/plugins/Plugin.js": "@azure/cosmos",
9
+ "@graphql-tools/executor/cjs/execution/execute.js": "@graphql-tools/executor",
10
+ "@graphql-tools/executor/cjs/execution/normalizedExecutor.js": "@graphql-tools/executor",
11
+ "@graphql-tools/executor/esm/execution/execute.js": "@graphql-tools/executor",
12
+ "@graphql-tools/executor/esm/execution/normalizedExecutor.js": "@graphql-tools/executor",
13
+ "@langchain/core/dist/embeddings.cjs": "@langchain/core",
14
+ "@langchain/core/dist/embeddings.js": "@langchain/core",
15
+ "@langchain/core/dist/language_models/chat_models.cjs": "@langchain/core",
16
+ "@langchain/core/dist/language_models/chat_models.js": "@langchain/core",
17
+ "@langchain/core/dist/language_models/llms.cjs": "@langchain/core",
18
+ "@langchain/core/dist/language_models/llms.js": "@langchain/core",
19
+ "@langchain/core/dist/runnables/base.cjs": "@langchain/core",
20
+ "@langchain/core/dist/runnables/base.js": "@langchain/core",
21
+ "@langchain/core/dist/tools/index.cjs": "@langchain/core",
22
+ "@langchain/core/dist/tools/index.js": "@langchain/core",
23
+ "@langchain/core/dist/vectorstores.cjs": "@langchain/core",
24
+ "@langchain/core/dist/vectorstores.js": "@langchain/core",
25
+ "@langchain/langgraph/dist/pregel/index.cjs": "@langchain/langgraph",
26
+ "@langchain/langgraph/dist/pregel/index.js": "@langchain/langgraph",
27
+ "@modelcontextprotocol/sdk/dist/cjs/client/index.js": "@modelcontextprotocol/sdk",
28
+ "@modelcontextprotocol/sdk/dist/cjs/server/mcp.js": "@modelcontextprotocol/sdk",
29
+ "@modelcontextprotocol/sdk/dist/esm/client/index.js": "@modelcontextprotocol/sdk",
30
+ "@modelcontextprotocol/sdk/dist/esm/server/mcp.js": "@modelcontextprotocol/sdk",
31
+ "@openai/agents-openai/dist/openaiChatCompletionsModel.js": "@openai/agents-openai",
32
+ "@openai/agents-openai/dist/openaiChatCompletionsModel.mjs": "@openai/agents-openai",
33
+ "@wdio/cli/build/index.js": "@wdio/cli",
34
+ "@wdio/jasmine-framework/build/index.js": "@wdio/jasmine-framework",
35
+ "@wdio/local-runner/build/index.js": "@wdio/local-runner",
36
+ "@wdio/utils/build/index.js": "@wdio/utils",
37
+ "ai/dist/index.js": "ai",
38
+ "ai/dist/index.mjs": "ai",
39
+ "bullmq/dist/cjs/classes/flow-producer.js": "bullmq",
40
+ "bullmq/dist/cjs/classes/queue.js": "bullmq",
41
+ "bullmq/dist/cjs/classes/worker.js": "bullmq",
42
+ "bullmq/dist/esm/classes/flow-producer.js": "bullmq",
43
+ "bullmq/dist/esm/classes/queue.js": "bullmq",
44
+ "bullmq/dist/esm/classes/worker.js": "bullmq",
45
+ "graphql/execution/execute.js": "graphql",
46
+ "graphql/execution/execute.mjs": "graphql",
47
+ "graphql/language/parser.js": "graphql",
48
+ "graphql/language/parser.mjs": "graphql",
49
+ "graphql/language/printer.js": "graphql",
50
+ "graphql/language/printer.mjs": "graphql",
51
+ "graphql/language/visitor.js": "graphql",
52
+ "graphql/language/visitor.mjs": "graphql",
53
+ "graphql/utilities/index.js": "graphql",
54
+ "graphql/utilities/index.mjs": "graphql",
55
+ "graphql/validation/validate.js": "graphql",
56
+ "graphql/validation/validate.mjs": "graphql",
57
+ "mercurius/index.js": "mercurius",
58
+ "playwright-core/lib/coreBundle.js": "playwright-core",
59
+ "playwright/lib/index.js": "playwright",
60
+ "playwright/lib/runner/index.js": "playwright"
61
+ }
@@ -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
  }