dd-trace 5.103.0 → 5.105.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 (213) hide show
  1. package/LICENSE-3rdparty.csv +90 -102
  2. package/index.d.ts +107 -6
  3. package/package.json +18 -17
  4. package/packages/datadog-core/src/storage.js +1 -1
  5. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  6. package/packages/datadog-instrumentations/src/ai.js +8 -7
  7. package/packages/datadog-instrumentations/src/aws-sdk.js +15 -2
  8. package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
  9. package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
  10. package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -2
  11. package/packages/datadog-instrumentations/src/cucumber.js +181 -35
  12. package/packages/datadog-instrumentations/src/dns.js +54 -18
  13. package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
  14. package/packages/datadog-instrumentations/src/fastify.js +142 -82
  15. package/packages/datadog-instrumentations/src/graphql.js +188 -67
  16. package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
  17. package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
  18. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
  19. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  20. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
  21. package/packages/datadog-instrumentations/src/helpers/kafka.js +17 -0
  22. package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
  23. package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
  24. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +3 -2
  26. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -6
  27. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
  28. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  29. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
  30. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
  31. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +31 -229
  32. package/packages/datadog-instrumentations/src/hono.js +54 -3
  33. package/packages/datadog-instrumentations/src/http/client.js +2 -2
  34. package/packages/datadog-instrumentations/src/http/server.js +9 -4
  35. package/packages/datadog-instrumentations/src/ioredis.js +3 -3
  36. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
  37. package/packages/datadog-instrumentations/src/jest.js +390 -183
  38. package/packages/datadog-instrumentations/src/kafkajs.js +140 -17
  39. package/packages/datadog-instrumentations/src/mariadb.js +1 -1
  40. package/packages/datadog-instrumentations/src/memcached.js +2 -1
  41. package/packages/datadog-instrumentations/src/mocha/main.js +399 -107
  42. package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
  43. package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
  44. package/packages/datadog-instrumentations/src/mongoose.js +10 -12
  45. package/packages/datadog-instrumentations/src/mysql.js +2 -2
  46. package/packages/datadog-instrumentations/src/mysql2.js +1 -1
  47. package/packages/datadog-instrumentations/src/nats.js +182 -0
  48. package/packages/datadog-instrumentations/src/nyc.js +38 -1
  49. package/packages/datadog-instrumentations/src/openai.js +33 -18
  50. package/packages/datadog-instrumentations/src/oracledb.js +6 -1
  51. package/packages/datadog-instrumentations/src/pg.js +1 -1
  52. package/packages/datadog-instrumentations/src/pino.js +17 -5
  53. package/packages/datadog-instrumentations/src/playwright.js +537 -297
  54. package/packages/datadog-instrumentations/src/router.js +80 -34
  55. package/packages/datadog-instrumentations/src/stripe.js +1 -1
  56. package/packages/datadog-instrumentations/src/vitest.js +246 -149
  57. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
  58. package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
  59. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
  60. package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
  61. package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
  62. package/packages/datadog-plugin-bunyan/src/index.js +28 -0
  63. package/packages/datadog-plugin-cucumber/src/index.js +17 -3
  64. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +223 -45
  65. package/packages/datadog-plugin-cypress/src/support.js +69 -1
  66. package/packages/datadog-plugin-dns/src/lookup.js +8 -6
  67. package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
  68. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
  69. package/packages/datadog-plugin-graphql/src/execute.js +2 -0
  70. package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
  71. package/packages/datadog-plugin-graphql/src/utils.js +4 -1
  72. package/packages/datadog-plugin-http/src/server.js +40 -15
  73. package/packages/datadog-plugin-jest/src/index.js +11 -3
  74. package/packages/datadog-plugin-jest/src/util.js +15 -8
  75. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
  76. package/packages/datadog-plugin-kafkajs/src/producer.js +35 -0
  77. package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
  78. package/packages/datadog-plugin-mocha/src/index.js +19 -4
  79. package/packages/datadog-plugin-mongodb-core/src/index.js +311 -35
  80. package/packages/datadog-plugin-nats/src/consumer.js +43 -0
  81. package/packages/datadog-plugin-nats/src/index.js +20 -0
  82. package/packages/datadog-plugin-nats/src/producer.js +62 -0
  83. package/packages/datadog-plugin-nats/src/util.js +33 -0
  84. package/packages/datadog-plugin-next/src/index.js +5 -3
  85. package/packages/datadog-plugin-openai/src/tracing.js +15 -2
  86. package/packages/datadog-plugin-oracledb/src/index.js +13 -2
  87. package/packages/datadog-plugin-pino/src/index.js +42 -0
  88. package/packages/datadog-plugin-playwright/src/index.js +4 -4
  89. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  90. package/packages/datadog-plugin-redis/src/index.js +37 -2
  91. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  92. package/packages/datadog-plugin-router/src/index.js +33 -44
  93. package/packages/datadog-plugin-selenium/src/index.js +1 -1
  94. package/packages/datadog-plugin-undici/src/index.js +19 -0
  95. package/packages/datadog-plugin-vitest/src/index.js +24 -20
  96. package/packages/datadog-plugin-winston/src/index.js +30 -0
  97. package/packages/datadog-shimmer/src/shimmer.js +49 -21
  98. package/packages/dd-trace/src/aiguard/index.js +1 -1
  99. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  100. package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
  101. package/packages/dd-trace/src/appsec/blocking.js +2 -2
  102. package/packages/dd-trace/src/appsec/index.js +11 -4
  103. package/packages/dd-trace/src/appsec/reporter.js +24 -11
  104. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  105. package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
  106. package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
  107. package/packages/dd-trace/src/baggage.js +7 -1
  108. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
  109. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
  110. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -1
  111. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
  112. package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
  113. package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -2
  114. package/packages/dd-trace/src/config/supported-configurations.json +36 -8
  115. package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
  116. package/packages/dd-trace/src/datastreams/context.js +4 -2
  117. package/packages/dd-trace/src/datastreams/writer.js +2 -4
  118. package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
  119. package/packages/dd-trace/src/encode/0.4.js +124 -108
  120. package/packages/dd-trace/src/encode/0.5.js +114 -26
  121. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +57 -42
  122. package/packages/dd-trace/src/encode/agentless-json.js +4 -2
  123. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
  124. package/packages/dd-trace/src/encode/span-stats.js +16 -16
  125. package/packages/dd-trace/src/encode/tags-processors.js +16 -0
  126. package/packages/dd-trace/src/exporters/common/agents.js +3 -1
  127. package/packages/dd-trace/src/exporters/common/request.js +3 -1
  128. package/packages/dd-trace/src/id.js +17 -4
  129. package/packages/dd-trace/src/lambda/handler.js +2 -4
  130. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  131. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  132. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  133. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
  134. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  135. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
  136. package/packages/dd-trace/src/llmobs/sdk.js +10 -16
  137. package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
  138. package/packages/dd-trace/src/llmobs/tagger.js +9 -1
  139. package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
  140. package/packages/dd-trace/src/llmobs/util.js +66 -3
  141. package/packages/dd-trace/src/log/index.js +1 -1
  142. package/packages/dd-trace/src/log/writer.js +3 -1
  143. package/packages/dd-trace/src/msgpack/chunk.js +394 -10
  144. package/packages/dd-trace/src/msgpack/index.js +96 -2
  145. package/packages/dd-trace/src/noop/span.js +3 -1
  146. package/packages/dd-trace/src/openfeature/encoding.js +70 -0
  147. package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
  148. package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
  149. package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
  150. package/packages/dd-trace/src/openfeature/writers/exposures.js +51 -20
  151. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
  152. package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
  153. package/packages/dd-trace/src/opentelemetry/span.js +1 -1
  154. package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
  155. package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
  156. package/packages/dd-trace/src/opentracing/span.js +59 -19
  157. package/packages/dd-trace/src/opentracing/span_context.js +49 -0
  158. package/packages/dd-trace/src/plugins/apollo.js +3 -1
  159. package/packages/dd-trace/src/plugins/ci_plugin.js +23 -33
  160. package/packages/dd-trace/src/plugins/database.js +7 -6
  161. package/packages/dd-trace/src/plugins/index.js +4 -0
  162. package/packages/dd-trace/src/plugins/log_injection.js +56 -0
  163. package/packages/dd-trace/src/plugins/log_plugin.js +3 -46
  164. package/packages/dd-trace/src/plugins/outbound.js +1 -1
  165. package/packages/dd-trace/src/plugins/plugin.js +15 -17
  166. package/packages/dd-trace/src/plugins/tracing.js +48 -8
  167. package/packages/dd-trace/src/plugins/util/git.js +3 -1
  168. package/packages/dd-trace/src/plugins/util/test.js +318 -13
  169. package/packages/dd-trace/src/plugins/util/web.js +89 -64
  170. package/packages/dd-trace/src/priority_sampler.js +2 -2
  171. package/packages/dd-trace/src/profiling/profiler.js +2 -2
  172. package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
  173. package/packages/dd-trace/src/sampling_rule.js +7 -7
  174. package/packages/dd-trace/src/scope.js +7 -5
  175. package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
  176. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
  177. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
  178. package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
  179. package/packages/dd-trace/src/span_format.js +190 -58
  180. package/packages/dd-trace/src/spanleak.js +1 -1
  181. package/packages/dd-trace/src/standalone/index.js +3 -3
  182. package/packages/dd-trace/src/tagger.js +0 -2
  183. package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
  184. package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
  185. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  186. package/vendor/dist/protobufjs/index.js +1 -1
  187. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  188. package/packages/dd-trace/src/msgpack/encoder.js +0 -308
  189. package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
  190. package/vendor/dist/opentracing/LICENSE +0 -201
  191. package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
  192. package/vendor/dist/opentracing/constants.d.ts +0 -61
  193. package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
  194. package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
  195. package/vendor/dist/opentracing/functions.d.ts +0 -20
  196. package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
  197. package/vendor/dist/opentracing/index.d.ts +0 -12
  198. package/vendor/dist/opentracing/index.js +0 -1
  199. package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
  200. package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
  201. package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
  202. package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
  203. package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
  204. package/vendor/dist/opentracing/noop.d.ts +0 -8
  205. package/vendor/dist/opentracing/reference.d.ts +0 -33
  206. package/vendor/dist/opentracing/span.d.ts +0 -147
  207. package/vendor/dist/opentracing/span_context.d.ts +0 -26
  208. package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
  209. package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
  210. package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
  211. package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
  212. package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
  213. package/vendor/dist/opentracing/tracer.d.ts +0 -127
@@ -0,0 +1,269 @@
1
+ 'use strict'
2
+
3
+ const dc = require('dc-polyfill')
4
+ const shimmer = require('../../../datadog-shimmer')
5
+ const {
6
+ convertOpenAIResponseItemsToMessages,
7
+ convertOpenAIResponsePromptToMessages,
8
+ normalizeOpenAIChatMessages,
9
+ } = require('./ai-messages')
10
+
11
+ // TODO: this channel name is incorrect, instrumentations publish with THEIR name, not with their subscribers names.
12
+ const aiguardChannel = dc.channel('dd-trace:ai:aiguard')
13
+
14
+ /**
15
+ * @typedef {object} ResourceHandler
16
+ * @property {(callArgs: object) => (Array<object>|undefined)} getInputMessages
17
+ * @property {(body: object) => Array<object>} getOutputMessages
18
+ * @property {(inputMessages: Array<object>, outputMessages: Array<object>) => Promise<unknown>}
19
+ * publishOutputEvaluation
20
+ */
21
+
22
+ /**
23
+ * @typedef {object} Guard
24
+ * @property {ResourceHandler} handler
25
+ * @property {Array<object>} inputMessages
26
+ * @property {() => Promise<void>} getInputEval
27
+ */
28
+
29
+ /**
30
+ * Publishes already-converted AI-style messages to the AI Guard evaluation channel.
31
+ *
32
+ * @param {Array<object>} messages - AI-style messages to evaluate.
33
+ * @returns {Promise<void>}
34
+ */
35
+ function publishEvaluation (messages) {
36
+ return new Promise((resolve, reject) => {
37
+ aiguardChannel.publish({ messages, integration: 'openai', resolve, reject })
38
+ })
39
+ }
40
+
41
+ /**
42
+ * Extracts OpenAI input messages from a `chat.completions.create` call.
43
+ *
44
+ * @param {object} callArgs - First argument passed to the wrapped method
45
+ * @returns {Array<object>|undefined}
46
+ */
47
+ function getChatCompletionsInputMessages (callArgs) {
48
+ return normalizeOpenAIChatMessages(callArgs?.messages)
49
+ }
50
+
51
+ /**
52
+ * Extracts OpenAI output messages from a `chat.completions.create` parsed body.
53
+ * Includes any choice whose message carries content (including empty string),
54
+ * `tool_calls`, a `refusal` field, or the deprecated `function_call` field. GPT-4o
55
+ * emits `{content: null, refusal: "..."}` on policy refusals, and pre-tool-call
56
+ * SDK paths still produce `function_call`-only output — AI Guard must still see them.
57
+ *
58
+ * @param {object} body - Parsed response body
59
+ * @returns {Array<object>}
60
+ */
61
+ function getChatCompletionsOutputMessages (body) {
62
+ const eligible = []
63
+ const choices = Array.isArray(body?.choices) ? body.choices : []
64
+ for (const choice of choices) {
65
+ const message = choice?.message
66
+ if (
67
+ message?.content != null ||
68
+ message?.tool_calls?.length ||
69
+ message?.refusal != null ||
70
+ message?.function_call != null
71
+ ) {
72
+ eligible.push(message)
73
+ }
74
+ }
75
+ return normalizeOpenAIChatMessages(eligible) ?? []
76
+ }
77
+
78
+ /**
79
+ * Publishes AI Guard After Model evaluation for `chat.completions` output.
80
+ *
81
+ * Chat completions may return multiple choices when `n > 1`. Screen every choice
82
+ * concurrently so any unsafe assistant output rejects `.parse()`, regardless of
83
+ * which choice the caller ends up using.
84
+ *
85
+ * @param {Array<object>} inputMessages
86
+ * @param {Array<object>} outputMessages - One entry per choice
87
+ * @returns {Promise<Array<void>>}
88
+ */
89
+ function publishChatCompletionsOutputEvaluation (inputMessages, outputMessages) {
90
+ const evals = []
91
+ for (const message of outputMessages) {
92
+ evals.push(publishEvaluation([...inputMessages, message]))
93
+ }
94
+ return Promise.all(evals)
95
+ }
96
+
97
+ /**
98
+ * Extracts OpenAI input messages from a `responses.create` call. The `instructions`
99
+ * field is treated as a developer prompt — it directly steers model behavior and the
100
+ * LLMObs OpenAI plugin already surfaces it as one — so AI Guard must screen it too.
101
+ *
102
+ * AI Guard `/evaluate` accepts a single leading system/developer message; if the
103
+ * caller's `input` already begins with one, prepend the `instructions` text to its
104
+ * content rather than emit a second developer turn.
105
+ *
106
+ * @param {object} callArgs - First argument passed to the wrapped method
107
+ * @returns {Array<object>|undefined}
108
+ */
109
+ function getResponsesInputMessages (callArgs) {
110
+ const messages = [
111
+ ...convertOpenAIResponseItemsToMessages(callArgs?.input, 'user'),
112
+ ...convertOpenAIResponsePromptToMessages(callArgs?.prompt),
113
+ ]
114
+
115
+ const instructions = typeof callArgs?.instructions === 'string' && callArgs.instructions.length
116
+ ? callArgs.instructions
117
+ : null
118
+ if (!instructions) return messages.length ? messages : undefined
119
+
120
+ const first = messages[0]
121
+ if (first && (first.role === 'developer' || first.role === 'system')) {
122
+ const merged = { role: 'developer', content: mergeInstructionsWithContent(instructions, first.content) }
123
+ return [merged, ...messages.slice(1)]
124
+ }
125
+ return [{ role: 'developer', content: instructions }, ...messages]
126
+ }
127
+
128
+ /**
129
+ * Merges Responses API instructions with an existing leading developer/system content value.
130
+ *
131
+ * @param {string} instructions
132
+ * @param {string|Array<object>|undefined} content
133
+ * @returns {string|Array<object>}
134
+ */
135
+ function mergeInstructionsWithContent (instructions, content) {
136
+ if (Array.isArray(content)) return [{ type: 'text', text: instructions }, ...content]
137
+ if (typeof content === 'string' && content.length) return `${instructions}\n\n${content}`
138
+ return instructions
139
+ }
140
+
141
+ /**
142
+ * Extracts OpenAI output messages from a `responses.create` parsed body.
143
+ *
144
+ * @param {object} body - Parsed response body
145
+ * @returns {Array<object>}
146
+ */
147
+ function getResponsesOutputMessages (body) {
148
+ return convertOpenAIResponseItemsToMessages(body?.output, 'assistant')
149
+ }
150
+
151
+ /**
152
+ * Publishes AI Guard After Model evaluation for `responses` output.
153
+ *
154
+ * The Responses API returns a single conversation turn whose `output` items form one
155
+ * coherent message (reasoning steps + final assistant message + tool calls + ...);
156
+ * they are screened together as a single evaluation.
157
+ *
158
+ * @param {Array<object>} inputMessages
159
+ * @param {Array<object>} outputMessages
160
+ * @returns {Promise<void>}
161
+ */
162
+ function publishResponsesOutputEvaluation (inputMessages, outputMessages) {
163
+ return publishEvaluation([...inputMessages, ...outputMessages])
164
+ }
165
+
166
+ /**
167
+ * Per-resource handlers describing how AI Guard reads inputs and screens outputs for
168
+ * each LLM-prompt-accepting OpenAI endpoint. The keys also serve as the set of
169
+ * resources eligible for AI Guard evaluation.
170
+ *
171
+ * @type {Record<string, ResourceHandler>}
172
+ */
173
+ const RESOURCE_HANDLERS = {
174
+ 'chat.completions': {
175
+ getInputMessages: getChatCompletionsInputMessages,
176
+ getOutputMessages: getChatCompletionsOutputMessages,
177
+ publishOutputEvaluation: publishChatCompletionsOutputEvaluation,
178
+ },
179
+ responses: {
180
+ getInputMessages: getResponsesInputMessages,
181
+ getOutputMessages: getResponsesOutputMessages,
182
+ publishOutputEvaluation: publishResponsesOutputEvaluation,
183
+ },
184
+ }
185
+
186
+ /**
187
+ * Reports whether the AI Guard channel has subscribers. The OpenAI instrumentation
188
+ * uses this to decide whether to take the AI Guard path at all.
189
+ *
190
+ * @returns {boolean}
191
+ */
192
+ function hasSubscribers () {
193
+ return aiguardChannel.hasSubscribers
194
+ }
195
+
196
+ /**
197
+ * Builds a guard handle when AI Guard is enabled and applicable to this call. The
198
+ * handle binds the per-resource handler so downstream functions never re-dispatch
199
+ * on `baseResource`. Returns null when AI Guard does not apply (no subscribers,
200
+ * non-eligible resource, streaming, or no input messages).
201
+ *
202
+ * @param {string} baseResource - e.g. `'chat.completions'` or `'responses'`
203
+ * @param {object} callArgs - First argument passed to the wrapped OpenAI method
204
+ * @param {boolean} stream - Whether the caller asked for a streamed response
205
+ * @returns {Guard|null}
206
+ */
207
+ function createGuard (baseResource, callArgs, stream) {
208
+ // Streaming AI Guard support lands in a follow-up PR. For now, provider-level AI
209
+ // Guard only evaluates non-streaming responses.
210
+ if (stream || !aiguardChannel.hasSubscribers) return null
211
+ const handler = RESOURCE_HANDLERS[baseResource]
212
+ if (!handler) return null
213
+
214
+ const inputMessages = handler.getInputMessages(callArgs)
215
+ if (!inputMessages) return null
216
+
217
+ let inputEvalPromise
218
+ const getInputEval = () => (inputEvalPromise ??= publishEvaluation(inputMessages))
219
+ return { handler, inputMessages, getInputEval }
220
+ }
221
+
222
+ /**
223
+ * Wraps `apiProm.asResponse` so callers that consume the raw `Response` object still
224
+ * receive the Before Model verdict. After Model evaluation is not performed on this
225
+ * path because the response body has not been parsed.
226
+ *
227
+ * @param {object} apiProm - APIPromise returned from the OpenAI SDK method
228
+ * @param {Guard} guard
229
+ */
230
+ function wrapAsResponse (apiProm, guard) {
231
+ if (typeof apiProm.asResponse !== 'function') return
232
+ shimmer.wrap(apiProm, 'asResponse', origAsResponse => function (...args) {
233
+ const responsePromise = origAsResponse.apply(this, args)
234
+ return Promise.all([guard.getInputEval(), responsePromise]).then(([, response]) => response)
235
+ })
236
+ }
237
+
238
+ /**
239
+ * Gates the parsed-body promise on Before Model evaluation. Resolves to the SDK's
240
+ * result only once the Before Model verdict is in.
241
+ *
242
+ * @param {Promise<unknown>} parsedPromise
243
+ * @param {Guard} guard
244
+ * @returns {Promise<unknown>}
245
+ */
246
+ function gateParse (parsedPromise, guard) {
247
+ return Promise.all([guard.getInputEval(), parsedPromise]).then(([, result]) => result)
248
+ }
249
+
250
+ /**
251
+ * Runs After Model evaluation against the response body.
252
+ *
253
+ * @param {Guard} guard
254
+ * @param {object} body - Parsed OpenAI response body
255
+ * @returns {Promise<unknown>}
256
+ */
257
+ function evaluateOutput (guard, body) {
258
+ const outputMessages = guard.handler.getOutputMessages(body)
259
+ if (!outputMessages.length) return Promise.resolve()
260
+ return guard.handler.publishOutputEvaluation(guard.inputMessages, outputMessages)
261
+ }
262
+
263
+ module.exports = {
264
+ hasSubscribers,
265
+ createGuard,
266
+ wrapAsResponse,
267
+ gateParse,
268
+ evaluateOutput,
269
+ }
@@ -0,0 +1,42 @@
1
+ 'use strict'
2
+
3
+ const dc = require('dc-polyfill')
4
+
5
+ const { channel } = require('./instrument')
6
+
7
+ /**
8
+ * Shimmer-compatible instrumentor for promise-returning APIs (e.g. `dns.promises.lookup`).
9
+ * Mirrors `createCallbackInstrumentor`'s channel triplet (`<prefix>:start`, `:finish`, `:error`)
10
+ * so a plugin subscribing to those channels for the callback variant works for the promise
11
+ * variant unchanged. `:finish` is the `tracingChannel` `asyncEnd` slot, so it fires after the
12
+ * promise settles with `ctx.result` set to the resolved value.
13
+ *
14
+ * @param {string} prefix
15
+ * @returns {(buildContext: (thisArg: unknown, args: unknown[]) => object | undefined) =>
16
+ * (fn: Function) => Function}
17
+ */
18
+ function createPromiseInstrumentor (prefix) {
19
+ const start = channel(prefix + ':start')
20
+ const finish = channel(prefix + ':finish')
21
+ const error = channel(prefix + ':error')
22
+ const tracing = dc.tracingChannel({
23
+ start,
24
+ end: channel(prefix + ':end'),
25
+ asyncStart: channel(prefix + ':asyncStart'),
26
+ asyncEnd: finish,
27
+ error,
28
+ })
29
+
30
+ return function instrument (buildContext) {
31
+ return function wrap (fn) {
32
+ return function (...args) {
33
+ if (!start.hasSubscribers) return fn.apply(this, args)
34
+ const ctx = buildContext(this, args)
35
+ if (ctx === undefined) return fn.apply(this, args)
36
+ return tracing.tracePromise(fn, ctx, this, ...args)
37
+ }
38
+ }
39
+ }
40
+ }
41
+
42
+ module.exports = { createPromiseInstrumentor }
@@ -133,7 +133,7 @@ for (const name of names) {
133
133
  try {
134
134
  loadChannel.publish({ name })
135
135
 
136
- moduleExports = hook(moduleExports, moduleVersion, isIitm) ?? moduleExports
136
+ moduleExports = hook(moduleExports, moduleVersion, isIitm, { moduleBaseDir, moduleName }) ?? moduleExports
137
137
  } catch (error) {
138
138
  log.info('Error during ddtrace instrumentation of application, aborting.', error)
139
139
  telemetry('error', [
@@ -19,9 +19,10 @@ const compiler = {
19
19
  // TODO: Figure out ESBuild `createRequire` issue and remove this hack.
20
20
  const oxc = runtimeRequire(['oxc', 'parser'].join('-'))
21
21
 
22
- compiler.parse = (sourceText, options) => {
22
+ compiler.parse = (sourceText, { range, isModule } = {}) => {
23
23
  const { program, errors } = oxc.parseSync('index.js', sourceText, {
24
- ...options,
24
+ range,
25
+ sourceType: isModule ? 'module' : 'script',
25
26
  preserveParens: false,
26
27
  })
27
28
 
@@ -2,15 +2,25 @@
2
2
 
3
3
  const { readFileSync } = require('fs')
4
4
  const { join } = require('path')
5
+ const { pathToFileURL } = require('url')
5
6
  const log = require('../../../../dd-trace/src/log')
6
7
  const { create } = require('../../../../../vendor/dist/@apm-js-collab/code-transformer')
7
- const { traceAsyncIterator, traceIterator } = require('./transforms')
8
+ const { waitForAsyncEnd } = require('./transforms')
8
9
  const instrumentations = require('./instrumentations')
9
10
 
10
- let dcPolyfill
11
+ // `dc-polyfill` is referenced from injected `require()` (CJS) and `import`
12
+ // (ESM) statements that the transformer splices into the rewritten module.
13
+ // `require()` accepts an absolute filesystem path; the ESM resolver rejects it
14
+ // with `ERR_INVALID_MODULE_SPECIFIER` and needs a `file://` URL instead. We
15
+ // pre-compute both forms here so each matcher hands the transformer a
16
+ // specifier that is valid for the module type it is rewriting.
17
+ let dcPolyfillCjs
18
+ let dcPolyfillEsm
11
19
 
12
20
  try {
13
- dcPolyfill = require.resolve('dc-polyfill').replaceAll('\\', '/')
21
+ const resolved = require.resolve('dc-polyfill')
22
+ dcPolyfillCjs = resolved.replaceAll('\\', '/')
23
+ dcPolyfillEsm = pathToFileURL(resolved).href
14
24
  } catch {
15
25
  // The `dc-polyfill` module is unavailable for some reason (like bundling).
16
26
  // Let's just keep the default of using `diagnostics-channel` as a fallback
@@ -20,10 +30,12 @@ try {
20
30
  /** @type {Record<string, string>} map of module base name to version */
21
31
  const moduleVersions = {}
22
32
  const disabled = new Set()
23
- const matcher = create(instrumentations, dcPolyfill)
33
+ const matcherCjs = create(instrumentations, dcPolyfillCjs)
34
+ const matcherEsm = create(instrumentations, dcPolyfillEsm)
24
35
 
25
- matcher.addTransform('traceIterator', traceIterator)
26
- matcher.addTransform('traceAsyncIterator', traceAsyncIterator)
36
+ for (const matcher of [matcherCjs, matcherEsm]) {
37
+ matcher.addTransform('waitForAsyncEnd', waitForAsyncEnd)
38
+ }
27
39
 
28
40
  function rewrite (content, filename, format) {
29
41
  if (!content) return content
@@ -41,6 +53,7 @@ function rewrite (content, filename, format) {
41
53
 
42
54
  if (disabled.has(moduleName)) return content
43
55
 
56
+ const matcher = moduleType === 'esm' ? matcherEsm : matcherCjs
44
57
  const transformer = matcher.getTransformer(moduleName, version, filePath)
45
58
 
46
59
  if (!transformer) return content
@@ -0,0 +1,50 @@
1
+ 'use strict'
2
+
3
+ module.exports = [{
4
+ module: {
5
+ name: '@azure/cosmos',
6
+ versionRange: '>=4.4.1',
7
+ filePath: 'dist/browser/plugins/Plugin.js',
8
+ },
9
+ functionQuery: {
10
+ functionName: 'executePlugins',
11
+ kind: 'Async',
12
+ },
13
+ channelName: 'executePlugins',
14
+ },
15
+ {
16
+ module: {
17
+ name: '@azure/cosmos',
18
+ versionRange: '>=4.4.1',
19
+ filePath: 'dist/commonjs/plugins/Plugin.js',
20
+ },
21
+ functionQuery: {
22
+ functionName: 'executePlugins',
23
+ kind: 'Async',
24
+ },
25
+ channelName: 'executePlugins',
26
+ },
27
+ {
28
+ module: {
29
+ name: '@azure/cosmos',
30
+ versionRange: '>=4.4.1',
31
+ filePath: 'dist/esm/plugins/Plugin.js',
32
+ },
33
+ functionQuery: {
34
+ functionName: 'executePlugins',
35
+ kind: 'Async',
36
+ },
37
+ channelName: 'executePlugins',
38
+ },
39
+ {
40
+ module: {
41
+ name: '@azure/cosmos',
42
+ versionRange: '>=4.4.1',
43
+ filePath: 'dist/react-native/plugins/Plugin.js',
44
+ },
45
+ functionQuery: {
46
+ functionName: 'executePlugins',
47
+ kind: 'Async',
48
+ },
49
+ channelName: 'executePlugins',
50
+ }]
@@ -2,8 +2,10 @@
2
2
 
3
3
  module.exports = [
4
4
  ...require('./ai'),
5
+ ...require('./azure-cosmos'),
5
6
  ...require('./bullmq'),
6
7
  ...require('./langchain'),
7
8
  ...require('./langgraph'),
8
9
  ...require('./modelcontextprotocol-sdk'),
10
+ ...require('./playwright'),
9
11
  ]
@@ -10,9 +10,10 @@ module.exports = [
10
10
  functionQuery: {
11
11
  methodName: 'stream',
12
12
  className: 'Pregel',
13
+ kind: 'Async',
14
+ returnKind: 'AsyncIterator',
13
15
  },
14
16
  channelName: 'Pregel_stream',
15
- transform: 'traceAsyncIterator',
16
17
  },
17
18
  {
18
19
  module: {
@@ -23,8 +24,9 @@ module.exports = [
23
24
  functionQuery: {
24
25
  methodName: 'stream',
25
26
  className: 'Pregel',
27
+ kind: 'Async',
28
+ returnKind: 'AsyncIterator',
26
29
  },
27
30
  channelName: 'Pregel_stream',
28
- transform: 'traceAsyncIterator',
29
31
  },
30
32
  ]
@@ -0,0 +1,85 @@
1
+ 'use strict'
2
+
3
+ // Playwright 1.60 bundles several former hook targets into local classes/functions.
4
+ // Keep these rewrites limited to private bundled internals that addHook cannot wrap.
5
+ module.exports = [
6
+ {
7
+ module: {
8
+ name: 'playwright',
9
+ versionRange: '>=1.60.0',
10
+ filePath: 'lib/runner/index.js',
11
+ },
12
+ functionQuery: {
13
+ className: 'Dispatcher',
14
+ methodName: 'run',
15
+ kind: 'Async',
16
+ },
17
+ channelName: 'Dispatcher_run',
18
+ },
19
+ {
20
+ module: {
21
+ name: 'playwright',
22
+ versionRange: '>=1.60.0',
23
+ filePath: 'lib/runner/index.js',
24
+ },
25
+ functionQuery: {
26
+ className: 'Dispatcher',
27
+ methodName: '_createWorker',
28
+ kind: 'Sync',
29
+ },
30
+ channelName: 'Dispatcher_createWorker',
31
+ },
32
+ {
33
+ module: {
34
+ name: 'playwright',
35
+ versionRange: '>=1.60.0',
36
+ filePath: 'lib/runner/index.js',
37
+ },
38
+ functionQuery: {
39
+ className: 'ProcessHost',
40
+ methodName: 'startRunner',
41
+ kind: 'Async',
42
+ },
43
+ channelName: 'ProcessHost_startRunner',
44
+ },
45
+ {
46
+ module: {
47
+ name: 'playwright',
48
+ versionRange: '>=1.60.0',
49
+ filePath: 'lib/runner/index.js',
50
+ },
51
+ functionQuery: {
52
+ functionName: 'createRootSuite',
53
+ kind: 'Async',
54
+ },
55
+ channelName: 'createRootSuite',
56
+ },
57
+ {
58
+ module: {
59
+ name: 'playwright-core',
60
+ versionRange: '>=1.60.0',
61
+ filePath: 'lib/coreBundle.js',
62
+ },
63
+ astQuery: 'AssignmentExpression[left.name="Page2"] > ClassExpression > ClassBody > ' +
64
+ 'MethodDefinition[kind="method"][key.name="goto"] > FunctionExpression[async], ' +
65
+ 'VariableDeclarator[id.name="Page2"] > ClassExpression > ClassBody > ' +
66
+ 'MethodDefinition[kind="method"][key.name="goto"] > FunctionExpression[async], ' +
67
+ 'ClassDeclaration[id.name="Page2"] > ClassBody > ' +
68
+ 'MethodDefinition[kind="method"][key.name="goto"] > FunctionExpression[async]',
69
+ functionQuery: {
70
+ methodName: 'goto',
71
+ kind: 'Async',
72
+ },
73
+ channelName: 'Page_goto',
74
+ },
75
+ {
76
+ module: {
77
+ name: 'playwright-core',
78
+ versionRange: '>=1.60.0',
79
+ filePath: 'lib/coreBundle.js',
80
+ },
81
+ astQuery: 'ReturnStatement > CallExpression[callee.object.name="promise"][callee.property.name="then"]',
82
+ channelName: 'Page_goto',
83
+ transform: 'waitForAsyncEnd',
84
+ },
85
+ ]