dd-trace 5.110.0 → 5.112.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 (164) hide show
  1. package/LICENSE-3rdparty.csv +1 -2
  2. package/README.md +13 -8
  3. package/ci/init.js +21 -2
  4. package/ci/vitest-no-worker-init-setup.mjs +430 -0
  5. package/ext/tags.js +2 -0
  6. package/index.d.ts +34 -1
  7. package/initialize.mjs +5 -6
  8. package/loader-hook.mjs +76 -55
  9. package/package.json +37 -34
  10. package/packages/datadog-instrumentations/src/ai.js +45 -0
  11. package/packages/datadog-instrumentations/src/apollo-server.js +5 -13
  12. package/packages/datadog-instrumentations/src/child_process.js +3 -3
  13. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +587 -0
  14. package/packages/datadog-instrumentations/src/cucumber.js +102 -43
  15. package/packages/datadog-instrumentations/src/cypress-config.js +11 -3
  16. package/packages/datadog-instrumentations/src/fastify.js +27 -8
  17. package/packages/datadog-instrumentations/src/fs.js +8 -6
  18. package/packages/datadog-instrumentations/src/graphql.js +26 -495
  19. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  20. package/packages/datadog-instrumentations/src/helpers/instrument.js +7 -0
  21. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +6 -6
  22. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/claude-agent-sdk.js +17 -0
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +201 -0
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  25. package/packages/datadog-instrumentations/src/jest.js +713 -63
  26. package/packages/datadog-instrumentations/src/mocha/main.js +24 -3
  27. package/packages/datadog-instrumentations/src/mocha/utils.js +128 -22
  28. package/packages/datadog-instrumentations/src/mocha/worker.js +13 -0
  29. package/packages/datadog-instrumentations/src/mongodb.js +74 -0
  30. package/packages/datadog-instrumentations/src/mongoose.js +13 -2
  31. package/packages/datadog-instrumentations/src/playwright.js +13 -9
  32. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1297 -0
  33. package/packages/datadog-instrumentations/src/vitest-main.js +1594 -0
  34. package/packages/datadog-instrumentations/src/vitest-util.js +254 -0
  35. package/packages/datadog-instrumentations/src/vitest-worker.js +823 -0
  36. package/packages/datadog-instrumentations/src/vitest.js +11 -1855
  37. package/packages/datadog-plugin-ai/src/index.js +1 -1
  38. package/packages/datadog-plugin-ai/src/tracing.js +66 -3
  39. package/packages/datadog-plugin-ai/src/utils.js +17 -4
  40. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/client.js +2 -2
  41. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +19 -10
  42. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +1 -0
  43. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +47 -11
  44. package/packages/datadog-plugin-child_process/src/index.js +13 -2
  45. package/packages/datadog-plugin-claude-agent-sdk/src/index.js +31 -0
  46. package/packages/datadog-plugin-claude-agent-sdk/src/tracing.js +107 -0
  47. package/packages/datadog-plugin-claude-agent-sdk/src/util.js +15 -0
  48. package/packages/datadog-plugin-cucumber/src/index.js +15 -24
  49. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +360 -14
  50. package/packages/datadog-plugin-cypress/src/index.js +47 -2
  51. package/packages/datadog-plugin-cypress/src/plugin.js +1 -0
  52. package/packages/datadog-plugin-cypress/src/support.js +45 -1
  53. package/packages/datadog-plugin-express/src/code_origin.js +1 -1
  54. package/packages/datadog-plugin-fastify/src/code_origin.js +1 -1
  55. package/packages/datadog-plugin-graphql/src/execute.js +639 -12
  56. package/packages/datadog-plugin-graphql/src/index.js +37 -9
  57. package/packages/datadog-plugin-graphql/src/parse.js +24 -4
  58. package/packages/datadog-plugin-graphql/src/utils.js +9 -2
  59. package/packages/datadog-plugin-graphql/src/validate.js +17 -6
  60. package/packages/datadog-plugin-http/src/index.js +6 -8
  61. package/packages/datadog-plugin-jest/src/index.js +31 -15
  62. package/packages/datadog-plugin-mocha/src/index.js +40 -15
  63. package/packages/datadog-plugin-mongodb-core/src/bulk-write.js +43 -0
  64. package/packages/datadog-plugin-mongodb-core/src/index.js +8 -443
  65. package/packages/datadog-plugin-mongodb-core/src/query.js +452 -0
  66. package/packages/datadog-plugin-openai/src/services.js +2 -2
  67. package/packages/datadog-plugin-playwright/src/index.js +4 -3
  68. package/packages/datadog-plugin-vitest/src/index.js +120 -72
  69. package/packages/datadog-shimmer/src/shimmer.js +37 -16
  70. package/packages/dd-trace/src/aiguard/index.js +9 -14
  71. package/packages/dd-trace/src/aiguard/integrations/index.js +34 -0
  72. package/packages/dd-trace/src/aiguard/integrations/openai.js +47 -33
  73. package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +42 -28
  74. package/packages/dd-trace/src/aiguard/sdk.js +2 -2
  75. package/packages/dd-trace/src/appsec/api_security/sampler.js +3 -3
  76. package/packages/dd-trace/src/appsec/channels.js +3 -1
  77. package/packages/dd-trace/src/appsec/downstream_requests.js +4 -4
  78. package/packages/dd-trace/src/appsec/graphql.js +14 -11
  79. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +23 -23
  80. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
  81. package/packages/dd-trace/src/appsec/iast/telemetry/index.js +2 -1
  82. package/packages/dd-trace/src/appsec/index.js +10 -1
  83. package/packages/dd-trace/src/appsec/lambda.js +135 -0
  84. package/packages/dd-trace/src/appsec/reporter.js +49 -10
  85. package/packages/dd-trace/src/appsec/telemetry/index.js +1 -1
  86. package/packages/dd-trace/src/appsec/waf/index.js +16 -4
  87. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +4 -4
  88. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +26 -1
  89. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +115 -24
  90. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +21 -6
  91. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +5 -2
  92. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
  93. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
  94. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +6 -2
  95. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
  96. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +130 -20
  97. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -2
  98. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +17 -0
  99. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +47 -26
  100. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +2 -2
  101. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +64 -53
  102. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +3 -3
  103. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +156 -0
  104. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +23 -5
  105. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +128 -0
  106. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +287 -0
  107. package/packages/dd-trace/src/config/defaults.js +3 -2
  108. package/packages/dd-trace/src/config/generated-config-types.d.ts +71 -57
  109. package/packages/dd-trace/src/config/helper.js +1 -0
  110. package/packages/dd-trace/src/config/index.js +35 -22
  111. package/packages/dd-trace/src/config/major-overrides.js +4 -2
  112. package/packages/dd-trace/src/config/remote_config.js +1 -1
  113. package/packages/dd-trace/src/config/supported-configurations.json +127 -56
  114. package/packages/dd-trace/src/constants.js +7 -0
  115. package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -2
  116. package/packages/dd-trace/src/datastreams/processor.js +11 -3
  117. package/packages/dd-trace/src/exporters/agent/index.js +1 -1
  118. package/packages/dd-trace/src/exporters/agentless/writer.js +4 -4
  119. package/packages/dd-trace/src/llmobs/index.js +1 -1
  120. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +403 -0
  121. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +8 -395
  122. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +27 -0
  123. package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +363 -0
  124. package/packages/dd-trace/src/llmobs/plugins/base.js +4 -4
  125. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +270 -0
  126. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/utils.js +10 -0
  127. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  128. package/packages/dd-trace/src/llmobs/sdk.js +3 -3
  129. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  130. package/packages/dd-trace/src/llmobs/tagger.js +3 -3
  131. package/packages/dd-trace/src/llmobs/writers/base.js +1 -1
  132. package/packages/dd-trace/src/opentelemetry/metrics/index.js +54 -5
  133. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +40 -0
  134. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +169 -0
  135. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +38 -39
  136. package/packages/dd-trace/src/opentelemetry/span.js +5 -0
  137. package/packages/dd-trace/src/opentelemetry/trace/index.js +4 -0
  138. package/packages/dd-trace/src/opentelemetry/tracer_provider.js +1 -1
  139. package/packages/dd-trace/src/opentracing/tracer.js +6 -1
  140. package/packages/dd-trace/src/plugin_manager.js +23 -7
  141. package/packages/dd-trace/src/plugins/ci_plugin.js +159 -10
  142. package/packages/dd-trace/src/plugins/index.js +2 -0
  143. package/packages/dd-trace/src/plugins/util/llm.js +6 -1
  144. package/packages/dd-trace/src/plugins/util/test.js +15 -9
  145. package/packages/dd-trace/src/profiling/exporter_cli.js +2 -2
  146. package/packages/dd-trace/src/profiling/exporters/agent.js +28 -3
  147. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +3 -3
  148. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  149. package/packages/dd-trace/src/proxy.js +8 -8
  150. package/packages/dd-trace/src/span_processor.js +5 -6
  151. package/packages/dd-trace/src/span_stats.js +96 -78
  152. package/packages/dd-trace/src/startup-log.js +2 -1
  153. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  154. package/packages/dd-trace/src/telemetry/endpoints.js +6 -4
  155. package/packages/dd-trace/src/telemetry/index.js +2 -2
  156. package/packages/dd-trace/src/telemetry/logs/index.js +1 -1
  157. package/packages/dd-trace/src/telemetry/send-data.js +8 -8
  158. package/packages/dd-trace/src/telemetry/session-propagation.js +1 -1
  159. package/packages/dd-trace/src/telemetry/telemetry.js +9 -9
  160. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  161. package/vendor/dist/protobufjs/index.js +1 -1
  162. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  163. package/vendor/dist/shell-quote/index.js +1 -1
  164. package/packages/datadog-plugin-graphql/src/resolve.js +0 -170
@@ -1,515 +1,46 @@
1
1
  'use strict'
2
2
 
3
- const { AsyncLocalStorage } = require('node:async_hooks')
3
+ const { addHook, getHooks } = require('./helpers/instrument')
4
4
 
5
- const shimmer = require('../../datadog-shimmer')
6
- const {
7
- addHook,
8
- channel,
9
- } = require('./helpers/instrument')
5
+ // Orchestrion rewriter handles wrapping of:
6
+ // - graphql: execute, parse, validate (CJS + ESM)
7
+ // - @graphql-tools/executor: execute, normalizedExecutor (CJS + ESM)
8
+ // See helpers/rewriter/instrumentations/graphql.js for the full config.
9
+ //
10
+ // The plugin (packages/datadog-plugin-graphql/src/execute.js) handles the
11
+ // `apm:graphql:execute:start` AppSec/WAF contract from inside its bindStart:
12
+ // publishing the channel synchronously runs subscribers, and an
13
+ // `abortController.abort()` from a subscriber is observed by replacing
14
+ // `ctx.arguments[0]` with an object whose getters throw AbortError. The
15
+ // orchestrion-emitted wrapper's `catch { ...; throw err }` block propagates
16
+ // that throw to the caller of graphql.execute. No outer wrap needed.
10
17
 
11
- const ddGlobal = globalThis[Symbol.for('dd-trace')]
12
-
13
- /** cached objects */
14
-
15
- // `contexts` is the fast resolver-side lookup; `executeCtx` is the fallback
16
- // when `contextValue` is a primitive and cannot key a WeakMap.
17
- const contexts = new WeakMap()
18
- const executeCtx = new AsyncLocalStorage()
19
- // Tracks normalized args already instrumented in an outer wrap so graphql-yoga
20
- // (which stacks `execute` + `normalizedExecutor`) only emits one span per call.
21
- const instrumentedArgs = new WeakSet()
22
- const documentSources = new WeakMap()
23
- const patchedResolvers = new WeakSet()
24
- const patchedTypes = new WeakSet()
25
-
26
- /** CHANNELS */
27
-
28
- // execute channels
29
- const startExecuteCh = channel('apm:graphql:execute:start')
30
- const finishExecuteCh = channel('apm:graphql:execute:finish')
31
- const executeErrorCh = channel('apm:graphql:execute:error')
32
-
33
- // resolve channels
34
- const startResolveCh = channel('apm:graphql:resolve:start')
35
- const finishResolveCh = channel('apm:graphql:resolve:finish')
36
- const updateFieldCh = channel('apm:graphql:resolve:updateField')
37
- const resolveErrorCh = channel('apm:graphql:resolve:error')
38
-
39
- // parse channels
40
- const parseStartCh = channel('apm:graphql:parser:start')
41
- const parseFinishCh = channel('apm:graphql:parser:finish')
42
- const parseErrorCh = channel('apm:graphql:parser:error')
43
-
44
- // validate channels
45
- const validateStartCh = channel('apm:graphql:validate:start')
46
- const validateFinishCh = channel('apm:graphql:validate:finish')
47
- const validateErrorCh = channel('apm:graphql:validate:error')
48
-
49
- class AbortError extends Error {
50
- constructor (message) {
51
- super(message)
52
- this.name = 'AbortError'
53
- }
54
- }
55
-
56
- const types = new Set(['query', 'mutation', 'subscription'])
57
-
58
- function getOperation (document, operationName) {
59
- if (!document || !Array.isArray(document.definitions)) {
60
- return
61
- }
62
-
63
- for (const definition of document.definitions) {
64
- if (definition && types.has(definition.operation) && (!operationName || definition.name?.value === operationName)) {
65
- return definition
66
- }
67
- }
18
+ for (const hook of getHooks('graphql')) {
19
+ addHook(hook, exports => exports)
68
20
  }
69
21
 
70
- function normalizeArgs (args, defaultFieldResolver) {
71
- if (args.length !== 1) return normalizePositional(args, defaultFieldResolver)
72
-
73
- const original = args[0]
74
- const normalized = {
75
- ...original,
76
- fieldResolver: wrapResolve(original.fieldResolver || defaultFieldResolver),
77
- }
78
-
79
- args[0] = normalized
80
- return normalized
81
- }
82
-
83
- function normalizePositional (args, defaultFieldResolver) {
84
- args[6] = wrapResolve(args[6] || defaultFieldResolver) // fieldResolver
85
- args.length = Math.max(args.length, 7)
86
-
87
- return {
88
- schema: args[0],
89
- document: args[1],
90
- rootValue: args[2],
91
- contextValue: args[3],
92
- variableValues: args[4],
93
- operationName: args[5],
94
- fieldResolver: args[6],
95
- }
96
- }
97
-
98
- // `WeakMap.set` throws `TypeError` on a non-object key; `get`/`has`/`delete`
99
- // silently miss. Skip the WeakMap entirely for non-keyable `contextValue`.
100
- function isWeakMapKey (value) {
101
- return value !== null && typeof value === 'object'
22
+ for (const hook of getHooks('@graphql-tools/executor')) {
23
+ addHook(hook, exports => exports)
102
24
  }
103
25
 
104
- function wrapParse (parse) {
105
- return function (source) {
106
- if (!parseStartCh.hasSubscribers) {
107
- return parse.apply(this, arguments)
108
- }
109
-
110
- const ctx = { source }
111
- return parseStartCh.runStores(ctx, () => {
112
- try {
113
- ctx.document = parse.apply(this, arguments)
114
- const operation = getOperation(ctx.document)
115
-
116
- if (!operation) return ctx.document
117
-
118
- if (source) {
119
- documentSources.set(ctx.document, source.body || source)
120
- }
121
- ctx.docSource = documentSources.get(ctx.document)
122
-
123
- return ctx.document
124
- } catch (err) {
125
- void err.stack
126
- ctx.error = err
127
- parseErrorCh.publish(ctx)
128
-
129
- throw err
130
- } finally {
131
- parseFinishCh.publish(ctx)
132
- }
133
- })
134
- }
135
- }
136
-
137
- function wrapValidate (validate) {
138
- return function (_schema, document, _rules, _typeInfo) {
139
- if (!validateStartCh.hasSubscribers) {
140
- return validate.apply(this, arguments)
141
- }
142
-
143
- const ctx = { docSource: documentSources.get(document), document }
144
- return validateStartCh.runStores(ctx, () => {
145
- let errors
146
- try {
147
- errors = validate.apply(this, arguments)
148
- if (errors && errors[0]) {
149
- ctx.error = errors[0]
150
- validateErrorCh.publish(ctx)
151
- }
152
- return errors
153
- } catch (err) {
154
- void err.stack
155
- ctx.error = err
156
- validateErrorCh.publish(ctx)
157
-
158
- throw err
159
- } finally {
160
- ctx.errors = errors
161
- validateFinishCh.publish(ctx)
162
- }
163
- })
164
- }
165
- }
166
-
167
- function wrapExecute (execute) {
168
- return function (exe) {
169
- const defaultFieldResolver = execute.defaultFieldResolver
170
- return function () {
171
- if (!startExecuteCh.hasSubscribers) {
172
- return exe.apply(this, arguments)
173
- }
174
-
175
- // The outer wrap leaves its normalized args object in `arguments[0]`; on
176
- // graphql-yoga's inner wrap that reference is already known here.
177
- if (instrumentedArgs.has(arguments[0])) {
178
- return exe.apply(this, arguments)
179
- }
180
-
181
- const args = normalizeArgs(arguments, defaultFieldResolver)
182
- const schema = args.schema
183
- const document = args.document
184
- const source = documentSources.get(document)
185
- const contextValue = args.contextValue
186
- const keyable = isWeakMapKey(contextValue)
187
- const operation = getOperation(document, args.operationName)
188
-
189
- if (keyable && contexts.has(contextValue)) {
190
- return exe.apply(this, arguments)
191
- }
192
-
193
- const ctx = {
194
- operation,
195
- args,
196
- docSource: source,
197
- source,
198
- fields: new Map(),
199
- abortController: new AbortController(),
200
- }
201
-
202
- // Only the object form leaves a stable single-object handle in
203
- // `arguments[0]` for the inner wrap to see.
204
- if (args === arguments[0]) instrumentedArgs.add(args)
205
-
206
- return startExecuteCh.runStores(ctx, () => {
207
- if (schema) {
208
- wrapFields(schema._queryType)
209
- wrapFields(schema._mutationType)
210
- }
211
-
212
- if (keyable) contexts.set(contextValue, ctx)
213
-
214
- const finish = (err, res) => {
215
- if (finishResolveCh.hasSubscribers) finishResolvers(ctx)
216
-
217
- const error = err || (res && res.errors && res.errors[0])
218
-
219
- if (error) {
220
- ctx.error = error
221
- executeErrorCh.publish(ctx)
222
- }
223
-
224
- ctx.res = res
225
- if (keyable) contexts.delete(contextValue)
226
- instrumentedArgs.delete(args)
227
- finishExecuteCh.publish(ctx)
228
- }
229
-
230
- // Skip the ALS entry on the common object-`contextValue` path; the
231
- // resolver reaches `ctx` via the WeakMap there.
232
- return keyable
233
- ? callInAsyncScope(exe, this, arguments, ctx.abortController, finish)
234
- : executeCtx.run(ctx, () => callInAsyncScope(exe, this, arguments, ctx.abortController, finish))
235
- })
236
- }
237
- }
238
- }
239
-
240
- function wrapResolve (resolve) {
241
- if (typeof resolve !== 'function' || patchedResolvers.has(resolve)) return resolve
242
-
243
- function resolveAsync (source, args, contextValue, info) {
244
- if (!startResolveCh.hasSubscribers) return resolve.apply(this, arguments)
245
-
246
- // `WeakMap.get(primitive)` returns `undefined`, so the fallback covers
247
- // executes that ran with a primitive `contextValue`.
248
- const ctx = contexts.get(contextValue) ?? executeCtx.getStore()
249
-
250
- /* istanbul ignore if: resolver invoked outside execute(), so no per-execute ctx was registered */
251
- if (!ctx) return resolve.apply(this, arguments)
252
-
253
- const field = assertField(ctx, info, args)
254
-
255
- if (ctx.abortController.signal.aborted) {
256
- publishResolverFinish(field, null)
257
- throw new AbortError('Aborted')
258
- }
259
-
260
- try {
261
- const result = resolve.call(this, source, args, contextValue, info)
262
- if (result !== null && typeof result?.then === 'function') {
263
- return result.then(
264
- res => {
265
- publishResolverFinish(field, null)
266
- return res
267
- },
268
- error => {
269
- publishResolverFinish(field, error)
270
- throw error
271
- }
272
- )
273
- }
274
- publishResolverFinish(field, null)
275
- return result
276
- } catch (error) {
277
- publishResolverFinish(field, error)
278
- throw error
279
- }
280
- }
281
-
282
- patchedResolvers.add(resolveAsync)
283
-
284
- return resolveAsync
285
- }
286
-
287
- /**
288
- * @param {{ ctx: object, error: unknown }} field
289
- * @param {unknown} error
290
- */
291
- function publishResolverFinish (field, error) {
292
- const fieldCtx = field.ctx
293
- fieldCtx.error = error
294
- fieldCtx.field = field
295
- updateFieldCh.publish(fieldCtx)
296
- }
297
-
298
- function callInAsyncScope (fn, thisArg, args, abortController, cb) {
299
- if (abortController.signal.aborted) {
300
- cb(null, null)
301
- throw new AbortError('Aborted')
302
- }
303
-
304
- try {
305
- const result = fn.apply(thisArg, args)
306
- if (result !== null && typeof result?.then === 'function') {
307
- return result.then(
308
- res => {
309
- cb(null, res)
310
- return res
311
- },
312
- /* istanbul ignore next: graphql.execute() rejects only via custom executors (graphql-yoga / graphql-tools) */
313
- error => {
314
- cb(error)
315
- throw error
316
- }
317
- )
318
- }
319
- cb(null, result)
320
- return result
321
- } catch (error) {
322
- cb(error)
323
- throw error
324
- }
325
- }
326
-
327
- /**
328
- * @typedef {{ prev: PathNode | undefined, key: string | number }} PathNode
329
- *
330
- * @typedef {{ error: unknown, ctx: object }} TrackedField
331
- */
332
-
333
- /**
334
- * @param {{
335
- * fields: Map<object, TrackedField>,
336
- * collapse: boolean,
337
- * collapsedFields?: Map<string, TrackedField>,
338
- * pathCache?: Map<PathNode, string>,
339
- * }} rootCtx
340
- * @param {import('graphql').GraphQLResolveInfo} info
341
- * @param {Record<string, unknown>} args
342
- */
343
- function assertField (rootCtx, info, args) {
344
- const path = info.path
345
- const collapse = rootCtx.collapse
346
-
347
- const cache = rootCtx.pathCache ??= new Map()
348
- const prev = path.prev
349
- const key = path.key
350
- const segment = collapse && typeof key !== 'string' ? '*' : key
351
-
352
- const pathString = prev === undefined
353
- ? String(segment)
354
- : (cache.get(prev) ?? buildCachedPathString(prev, cache, collapse)) + '.' + segment
355
- cache.set(path, pathString)
356
-
357
- const fieldCtx = {
358
- rootCtx,
359
- args,
360
- path,
361
- pathString,
362
- fieldName: info.fieldName,
363
- returnType: info.returnType,
364
- fieldNode: info.fieldNodes[0],
365
- variableValues: info.variableValues,
366
- }
367
- // Publish per resolver call, before the collapse / depth dedupe below.
368
- // IAST mutates each call's own args object; if siblings 2..N skip the
369
- // publish, those args objects never get tainted.
370
- startResolveCh.publish(fieldCtx)
371
-
372
- let collapsedFields
373
- if (collapse) {
374
- collapsedFields = rootCtx.collapsedFields ??= new Map()
375
- const existing = collapsedFields.get(pathString)
376
- // Subsequent siblings of a collapsed list share the first sibling's field
377
- // so updateFieldCh fires for every call and the span's finishTime tracks
378
- // the last sibling's completion, not the first.
379
- if (existing !== undefined) return existing
380
- }
381
-
382
- const field = { error: null, ctx: fieldCtx }
383
- rootCtx.fields.set(path, field)
384
- if (collapsedFields !== undefined) collapsedFields.set(pathString, field)
385
- return field
386
- }
387
-
388
- /**
389
- * Cold path for assertField. graphql-js inserts a synthetic array-index
390
- * node between a list field and its items, and that node never reaches a
391
- * resolver — so assertField has no chance to cache it. The first child of
392
- * the list item that hits the path cache lands here to walk and populate
393
- * back to a cached ancestor.
394
- *
395
- * @param {PathNode} path
396
- * @param {Map<PathNode, string>} cache
397
- * @param {boolean} collapse
398
- */
399
- function buildCachedPathString (path, cache, collapse) {
400
- const key = path.key
401
- const segment = collapse && typeof key !== 'string' ? '*' : key
402
- const prev = path.prev
403
-
404
- const pathString = prev === undefined
405
- ? String(segment)
406
- : (cache.get(prev) ?? buildCachedPathString(prev, cache, collapse)) + '.' + segment
407
- cache.set(path, pathString)
408
- return pathString
409
- }
410
-
411
- function wrapFields (type) {
412
- if (!type || !type._fields || patchedTypes.has(type)) {
413
- return
414
- }
415
-
416
- patchedTypes.add(type)
417
-
418
- for (const field of Object.values(type._fields)) {
419
- wrapFieldResolve(field)
420
- wrapFieldType(field)
421
- }
422
- }
423
-
424
- function wrapFieldResolve (field) {
425
- if (!field || !field.resolve) return
426
- field.resolve = wrapResolve(field.resolve)
427
- }
428
-
429
- function wrapFieldType (field) {
430
- if (!field || !field.type) return
431
-
432
- let unwrappedType = field.type
433
-
434
- while (unwrappedType.ofType) {
435
- unwrappedType = unwrappedType.ofType
436
- }
437
-
438
- wrapFields(unwrappedType)
439
- }
440
-
441
- function finishResolvers ({ fields }) {
442
- for (const field of fields.values()) {
443
- const fieldCtx = field.ctx
444
- // A depth-gated field publishes startResolveCh for IAST/AppSec but the
445
- // resolve plugin's start short-circuits before creating a span, so there
446
- // is no span here to finish.
447
- if (fieldCtx.currentStore === undefined) continue
448
- fieldCtx.finishTime = field.finishTime
449
- fieldCtx.field = field
450
- if (field.error) {
451
- fieldCtx.error = field.error
452
- resolveErrorCh.publish(fieldCtx)
453
- }
454
- finishResolveCh.publish(fieldCtx)
455
- }
456
- }
457
-
458
- // The CJS package root re-exports `execute` and `normalizedExecutor` as
459
- // non-configurable tslib `__exportStar` getters that shimmer cannot rewrite in
460
- // place, so the inner execute.js hook below carries CJS instead: graphql-yoga
461
- // (`normalizedExecutor`) and direct callers both funnel through that `execute`.
462
- // Under iitm (ESM) the namespace is settable and the inner-file hook never
463
- // matches the `esm/` path, so the root wrap is the only option there.
464
- addHook({ name: '@graphql-tools/executor', versions: ['>=0.0.14'] }, (executor, _version, isIitm) => {
465
- /* istanbul ignore if: covered only by the graphql-yoga ESM integration test (subprocess) */
466
- if (isIitm) {
467
- shimmer.wrap(executor, 'execute', wrapExecute(executor))
468
- shimmer.wrap(executor, 'normalizedExecutor', wrapExecute(executor))
469
- }
470
- return executor
471
- })
472
-
473
- addHook({ name: '@graphql-tools/executor', file: 'cjs/execution/execute.js', versions: ['>=0.0.14'] }, execute => {
474
- shimmer.wrap(execute, 'execute', wrapExecute(execute))
475
- return execute
476
- })
477
-
478
- // TODO(BridgeAR): graphql >=17.0.0-alpha.9 routes execute() through
479
- // experimentalExecuteIncrementally(), bypassing this hook. The same
480
- // function returns { initialResult, subsequentResults } for @defer /
481
- // @stream which callInAsyncScope does not handle — execute finishes
482
- // before the streamed payloads land.
483
- addHook({ name: 'graphql', file: 'execution/execute.js', versions: ['>=0.10'] }, execute => {
484
- shimmer.wrap(execute, 'execute', wrapExecute(execute))
485
- return execute
486
- })
487
-
488
- addHook({ name: 'graphql', file: 'language/parser.js', versions: ['>=0.10'] }, parser => {
489
- shimmer.wrap(parser, 'parse', wrapParse)
490
- return parser
491
- })
492
-
493
- addHook({ name: 'graphql', file: 'validation/validate.js', versions: ['>=0.10'] }, validate => {
494
- shimmer.wrap(validate, 'validate', wrapValidate)
495
-
496
- return validate
497
- })
26
+ // Module-load hooks: capture references on ddGlobal for cross-plugin access
27
+ // (read lazily inside each callback so agent.load() between mocha suites can
28
+ // rebind globalThis[dd-trace] without us stashing a stale reference).
498
29
 
499
30
  addHook({ name: 'graphql', file: 'language/printer.js', versions: ['>=0.10'] }, printer => {
500
- // HACK: It's possible `graphql` is loaded before `@apollo/gateway` so we
501
- // can't use a channel as the latter plugin would load after the publish
502
- // happened. Not sure how to handle this so for now use a global.
503
- ddGlobal.graphql_printer = printer
31
+ const ddGlobal = globalThis[Symbol.for('dd-trace')]
32
+ if (ddGlobal) ddGlobal.graphql_printer = printer
504
33
  return printer
505
34
  })
506
35
 
507
36
  addHook({ name: 'graphql', file: 'language/visitor.js', versions: ['>=0.10'] }, visitor => {
508
- ddGlobal.graphql_visitor = visitor
37
+ const ddGlobal = globalThis[Symbol.for('dd-trace')]
38
+ if (ddGlobal) ddGlobal.graphql_visitor = visitor
509
39
  return visitor
510
40
  })
511
41
 
512
42
  addHook({ name: 'graphql', file: 'utilities/index.js', versions: ['>=0.10'] }, utilities => {
513
- ddGlobal.graphql_utilities = utilities
43
+ const ddGlobal = globalThis[Symbol.for('dd-trace')]
44
+ if (ddGlobal) ddGlobal.graphql_utilities = utilities
514
45
  return utilities
515
46
  })
@@ -15,6 +15,7 @@ module.exports = {
15
15
  vm: () => require('../vm'),
16
16
  zlib: () => require('../zlib'),
17
17
  // Non Node.js modules
18
+ '@anthropic-ai/claude-agent-sdk': { esmFirst: true, fn: () => require('../claude-agent-sdk') },
18
19
  '@anthropic-ai/sdk': { esmFirst: true, fn: () => require('../anthropic') },
19
20
  '@apollo/server': () => require('../apollo-server'),
20
21
  '@apollo/gateway': () => require('../apollo'),
@@ -51,6 +51,13 @@ exports.tracingChannel = function (name) {
51
51
  * inside Express) still reaches its subscribers instead of being dropped, and
52
52
  * the guard costs a closure read rather than a per-publish channel lookup.
53
53
  *
54
+ * The flag bounds only synchronous re-entry. A sequential re-drive of the same
55
+ * error (fastify's avvio boot loop) runs after the publish returned and the
56
+ * `finally` cleared the flag, so the framework that produces that shape guards
57
+ * it at its own seam; the middleware frameworks that republish the same error
58
+ * once per unwound layer (koa, router, connect, restify, each tagging a
59
+ * distinct span) must keep publishing it.
60
+ *
54
61
  * @param {Channel} errorChannel
55
62
  */
56
63
  exports.createErrorPublisher = function createErrorPublisher (errorChannel) {
@@ -5,7 +5,7 @@ module.exports = [
5
5
  {
6
6
  module: {
7
7
  name: 'ai',
8
- versionRange: '>=4.0.0',
8
+ versionRange: '>=4.0.0 <7.0.0',
9
9
  filePath: 'dist/index.js',
10
10
  },
11
11
  functionQuery: {
@@ -17,7 +17,7 @@ module.exports = [
17
17
  {
18
18
  module: {
19
19
  name: 'ai',
20
- versionRange: '>=4.0.0',
20
+ versionRange: '>=4.0.0 <7.0.0',
21
21
  filePath: 'dist/index.mjs',
22
22
  },
23
23
  functionQuery: {
@@ -54,7 +54,7 @@ module.exports = [
54
54
  {
55
55
  module: {
56
56
  name: 'ai',
57
- versionRange: '>=6.0.0',
57
+ versionRange: '>=6.0.0 <7.0.0',
58
58
  filePath: 'dist/index.js',
59
59
  },
60
60
  functionQuery: {
@@ -66,7 +66,7 @@ module.exports = [
66
66
  {
67
67
  module: {
68
68
  name: 'ai',
69
- versionRange: '>=6.0.0',
69
+ versionRange: '>=6.0.0 <7.0.0',
70
70
  filePath: 'dist/index.mjs',
71
71
  },
72
72
  functionQuery: {
@@ -104,7 +104,7 @@ module.exports = [
104
104
  {
105
105
  module: {
106
106
  name: 'ai',
107
- versionRange: '>=4.0.0',
107
+ versionRange: '>=4.0.0 <7.0.0',
108
108
  filePath: 'dist/index.js',
109
109
  },
110
110
  functionQuery: {
@@ -116,7 +116,7 @@ module.exports = [
116
116
  {
117
117
  module: {
118
118
  name: 'ai',
119
- versionRange: '>=4.0.0',
119
+ versionRange: '>=4.0.0 <7.0.0',
120
120
  filePath: 'dist/index.mjs',
121
121
  },
122
122
  functionQuery: {
@@ -0,0 +1,17 @@
1
+ 'use strict'
2
+
3
+ module.exports = [
4
+ {
5
+ module: {
6
+ name: '@anthropic-ai/claude-agent-sdk',
7
+ versionRange: '>=0.2.113',
8
+ filePath: 'sdk.mjs',
9
+ },
10
+ functionQuery: {
11
+ functionName: 'query',
12
+ kind: 'Async',
13
+ isExportAlias: true,
14
+ },
15
+ channelName: 'query',
16
+ },
17
+ ]