dd-trace 5.104.0 → 5.106.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.
- package/LICENSE-3rdparty.csv +90 -102
- package/index.d.ts +82 -3
- package/package.json +15 -15
- package/packages/datadog-core/src/storage.js +1 -1
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/ai.js +8 -7
- package/packages/datadog-instrumentations/src/aws-sdk.js +16 -2
- package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
- package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
- package/packages/datadog-instrumentations/src/cucumber-worker-threads.js +19 -0
- package/packages/datadog-instrumentations/src/cucumber.js +390 -157
- package/packages/datadog-instrumentations/src/dns.js +54 -18
- package/packages/datadog-instrumentations/src/fastify.js +142 -82
- package/packages/datadog-instrumentations/src/graphql.js +188 -62
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
- package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +37 -236
- package/packages/datadog-instrumentations/src/hono.js +54 -3
- package/packages/datadog-instrumentations/src/http/server.js +9 -4
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
- package/packages/datadog-instrumentations/src/jest.js +360 -150
- package/packages/datadog-instrumentations/src/kafkajs.js +120 -16
- package/packages/datadog-instrumentations/src/mocha/main.js +128 -17
- package/packages/datadog-instrumentations/src/nats.js +182 -0
- package/packages/datadog-instrumentations/src/nyc.js +38 -1
- package/packages/datadog-instrumentations/src/openai.js +33 -18
- package/packages/datadog-instrumentations/src/oracledb.js +6 -1
- package/packages/datadog-instrumentations/src/pino.js +17 -5
- package/packages/datadog-instrumentations/src/playwright.js +515 -292
- package/packages/datadog-instrumentations/src/router.js +76 -32
- package/packages/datadog-instrumentations/src/stripe.js +1 -1
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +218 -4
- package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
- package/packages/datadog-plugin-bunyan/src/index.js +28 -0
- package/packages/datadog-plugin-cucumber/src/index.js +17 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +199 -28
- package/packages/datadog-plugin-cypress/src/support.js +69 -1
- package/packages/datadog-plugin-dns/src/lookup.js +8 -6
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +2 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
- package/packages/datadog-plugin-http/src/server.js +40 -15
- package/packages/datadog-plugin-jest/src/index.js +11 -3
- package/packages/datadog-plugin-jest/src/util.js +15 -8
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +3 -0
- package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +19 -4
- package/packages/datadog-plugin-mongodb-core/src/index.js +281 -40
- package/packages/datadog-plugin-nats/src/consumer.js +43 -0
- package/packages/datadog-plugin-nats/src/index.js +20 -0
- package/packages/datadog-plugin-nats/src/producer.js +62 -0
- package/packages/datadog-plugin-nats/src/util.js +33 -0
- package/packages/datadog-plugin-next/src/index.js +5 -3
- package/packages/datadog-plugin-openai/src/tracing.js +15 -2
- package/packages/datadog-plugin-oracledb/src/index.js +13 -2
- package/packages/datadog-plugin-pino/src/index.js +42 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -4
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +33 -44
- package/packages/datadog-plugin-selenium/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +5 -13
- package/packages/datadog-plugin-winston/src/index.js +30 -0
- package/packages/datadog-shimmer/src/shimmer.js +33 -40
- package/packages/dd-trace/src/aiguard/index.js +1 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/index.js +1 -1
- package/packages/dd-trace/src/appsec/reporter.js +5 -6
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
- package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
- package/packages/dd-trace/src/baggage.js +7 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +6 -2
- package/packages/dd-trace/src/config/supported-configurations.json +27 -8
- package/packages/dd-trace/src/datastreams/writer.js +2 -4
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
- package/packages/dd-trace/src/encode/0.4.js +124 -108
- package/packages/dd-trace/src/encode/0.5.js +114 -26
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +31 -23
- package/packages/dd-trace/src/encode/agentless-json.js +4 -2
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
- package/packages/dd-trace/src/encode/span-stats.js +16 -16
- package/packages/dd-trace/src/encode/tags-processors.js +16 -0
- package/packages/dd-trace/src/id.js +15 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +92 -6
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +43 -21
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +0 -16
- package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
- package/packages/dd-trace/src/llmobs/tagger.js +9 -1
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/util.js +66 -3
- package/packages/dd-trace/src/log/index.js +1 -1
- package/packages/dd-trace/src/msgpack/chunk.js +394 -10
- package/packages/dd-trace/src/msgpack/index.js +96 -2
- package/packages/dd-trace/src/openfeature/encoding.js +70 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
- package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
- package/packages/dd-trace/src/opentelemetry/span.js +1 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +22 -3
- package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +64 -77
- package/packages/dd-trace/src/opentracing/span.js +59 -19
- package/packages/dd-trace/src/opentracing/span_context.js +50 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +20 -20
- package/packages/dd-trace/src/plugins/database.js +7 -6
- package/packages/dd-trace/src/plugins/index.js +4 -0
- package/packages/dd-trace/src/plugins/log_injection.js +56 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -48
- package/packages/dd-trace/src/plugins/outbound.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +15 -17
- package/packages/dd-trace/src/plugins/tracing.js +43 -5
- package/packages/dd-trace/src/plugins/util/test.js +236 -13
- package/packages/dd-trace/src/plugins/util/web.js +79 -65
- package/packages/dd-trace/src/priority_sampler.js +2 -2
- package/packages/dd-trace/src/profiling/config.js +10 -23
- package/packages/dd-trace/src/profiling/exporters/agent.js +11 -10
- package/packages/dd-trace/src/profiling/profiler.js +21 -11
- package/packages/dd-trace/src/profiling/profilers/wall.js +12 -7
- package/packages/dd-trace/src/sampling_rule.js +7 -7
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
- package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
- package/packages/dd-trace/src/span_format.js +190 -58
- package/packages/dd-trace/src/spanleak.js +1 -1
- package/packages/dd-trace/src/standalone/index.js +3 -3
- package/packages/dd-trace/src/tagger.js +0 -2
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
- package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/dd-trace/src/msgpack/encoder.js +0 -308
- package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { AsyncLocalStorage } = require('node:async_hooks')
|
|
4
|
+
|
|
3
5
|
const shimmer = require('../../datadog-shimmer')
|
|
4
6
|
const {
|
|
5
7
|
addHook,
|
|
@@ -10,7 +12,13 @@ const ddGlobal = globalThis[Symbol.for('dd-trace')]
|
|
|
10
12
|
|
|
11
13
|
/** cached objects */
|
|
12
14
|
|
|
15
|
+
// `contexts` is the fast resolver-side lookup; `executeCtx` is the fallback
|
|
16
|
+
// when `contextValue` is a primitive and cannot key a WeakMap.
|
|
13
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()
|
|
14
22
|
const documentSources = new WeakMap()
|
|
15
23
|
const patchedResolvers = new WeakSet()
|
|
16
24
|
const patchedTypes = new WeakSet()
|
|
@@ -62,14 +70,17 @@ function getOperation (document, operationName) {
|
|
|
62
70
|
function normalizeArgs (args, defaultFieldResolver) {
|
|
63
71
|
if (args.length !== 1) return normalizePositional(args, defaultFieldResolver)
|
|
64
72
|
|
|
65
|
-
args[0]
|
|
66
|
-
|
|
73
|
+
const original = args[0]
|
|
74
|
+
const normalized = {
|
|
75
|
+
...original,
|
|
76
|
+
fieldResolver: wrapResolve(original.fieldResolver || defaultFieldResolver),
|
|
77
|
+
}
|
|
67
78
|
|
|
68
|
-
|
|
79
|
+
args[0] = normalized
|
|
80
|
+
return normalized
|
|
69
81
|
}
|
|
70
82
|
|
|
71
83
|
function normalizePositional (args, defaultFieldResolver) {
|
|
72
|
-
args[3] = args[3] || {} // contextValue
|
|
73
84
|
args[6] = wrapResolve(args[6] || defaultFieldResolver) // fieldResolver
|
|
74
85
|
args.length = Math.max(args.length, 7)
|
|
75
86
|
|
|
@@ -84,6 +95,12 @@ function normalizePositional (args, defaultFieldResolver) {
|
|
|
84
95
|
}
|
|
85
96
|
}
|
|
86
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'
|
|
102
|
+
}
|
|
103
|
+
|
|
87
104
|
function wrapParse (parse) {
|
|
88
105
|
return function (source) {
|
|
89
106
|
if (!parseStartCh.hasSubscribers) {
|
|
@@ -155,14 +172,21 @@ function wrapExecute (execute) {
|
|
|
155
172
|
return exe.apply(this, arguments)
|
|
156
173
|
}
|
|
157
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
|
+
|
|
158
181
|
const args = normalizeArgs(arguments, defaultFieldResolver)
|
|
159
182
|
const schema = args.schema
|
|
160
183
|
const document = args.document
|
|
161
184
|
const source = documentSources.get(document)
|
|
162
185
|
const contextValue = args.contextValue
|
|
186
|
+
const keyable = isWeakMapKey(contextValue)
|
|
163
187
|
const operation = getOperation(document, args.operationName)
|
|
164
188
|
|
|
165
|
-
if (contexts.has(contextValue)) {
|
|
189
|
+
if (keyable && contexts.has(contextValue)) {
|
|
166
190
|
return exe.apply(this, arguments)
|
|
167
191
|
}
|
|
168
192
|
|
|
@@ -171,19 +195,23 @@ function wrapExecute (execute) {
|
|
|
171
195
|
args,
|
|
172
196
|
docSource: source,
|
|
173
197
|
source,
|
|
174
|
-
fields:
|
|
198
|
+
fields: new Map(),
|
|
175
199
|
abortController: new AbortController(),
|
|
176
200
|
}
|
|
177
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
|
+
|
|
178
206
|
return startExecuteCh.runStores(ctx, () => {
|
|
179
207
|
if (schema) {
|
|
180
208
|
wrapFields(schema._queryType)
|
|
181
209
|
wrapFields(schema._mutationType)
|
|
182
210
|
}
|
|
183
211
|
|
|
184
|
-
contexts.set(contextValue, ctx)
|
|
212
|
+
if (keyable) contexts.set(contextValue, ctx)
|
|
185
213
|
|
|
186
|
-
|
|
214
|
+
const finish = (err, res) => {
|
|
187
215
|
if (finishResolveCh.hasSubscribers) finishResolvers(ctx)
|
|
188
216
|
|
|
189
217
|
const error = err || (res && res.errors && res.errors[0])
|
|
@@ -194,8 +222,16 @@ function wrapExecute (execute) {
|
|
|
194
222
|
}
|
|
195
223
|
|
|
196
224
|
ctx.res = res
|
|
225
|
+
if (keyable) contexts.delete(contextValue)
|
|
226
|
+
instrumentedArgs.delete(args)
|
|
197
227
|
finishExecuteCh.publish(ctx)
|
|
198
|
-
}
|
|
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))
|
|
199
235
|
})
|
|
200
236
|
}
|
|
201
237
|
}
|
|
@@ -207,18 +243,40 @@ function wrapResolve (resolve) {
|
|
|
207
243
|
function resolveAsync (source, args, contextValue, info) {
|
|
208
244
|
if (!startResolveCh.hasSubscribers) return resolve.apply(this, arguments)
|
|
209
245
|
|
|
210
|
-
|
|
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()
|
|
211
249
|
|
|
250
|
+
/* istanbul ignore if: resolver invoked outside execute(), so no per-execute ctx was registered */
|
|
212
251
|
if (!ctx) return resolve.apply(this, arguments)
|
|
213
252
|
|
|
214
253
|
const field = assertField(ctx, info, args)
|
|
215
254
|
|
|
216
|
-
|
|
217
|
-
field
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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
|
+
}
|
|
222
280
|
}
|
|
223
281
|
|
|
224
282
|
patchedResolvers.add(resolveAsync)
|
|
@@ -226,72 +284,130 @@ function wrapResolve (resolve) {
|
|
|
226
284
|
return resolveAsync
|
|
227
285
|
}
|
|
228
286
|
|
|
229
|
-
|
|
230
|
-
|
|
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
|
+
}
|
|
231
297
|
|
|
232
|
-
|
|
298
|
+
function callInAsyncScope (fn, thisArg, args, abortController, cb) {
|
|
299
|
+
if (abortController.signal.aborted) {
|
|
233
300
|
cb(null, null)
|
|
234
301
|
throw new AbortError('Aborted')
|
|
235
302
|
}
|
|
236
303
|
|
|
237
304
|
try {
|
|
238
305
|
const result = fn.apply(thisArg, args)
|
|
239
|
-
if (result && typeof result
|
|
306
|
+
if (result !== null && typeof result?.then === 'function') {
|
|
240
307
|
return result.then(
|
|
241
308
|
res => {
|
|
242
309
|
cb(null, res)
|
|
243
310
|
return res
|
|
244
311
|
},
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
312
|
+
/* istanbul ignore next: graphql.execute() rejects only via custom executors (graphql-yoga / graphql-tools) */
|
|
313
|
+
error => {
|
|
314
|
+
cb(error)
|
|
315
|
+
throw error
|
|
248
316
|
}
|
|
249
317
|
)
|
|
250
318
|
}
|
|
251
319
|
cb(null, result)
|
|
252
320
|
return result
|
|
253
|
-
} catch (
|
|
254
|
-
cb(
|
|
255
|
-
throw
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function pathToArray (path) {
|
|
260
|
-
let length = 0
|
|
261
|
-
for (let curr = path; curr; curr = curr.prev) {
|
|
262
|
-
length += 1
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const flattened = new Array(length)
|
|
266
|
-
let index = length
|
|
267
|
-
for (let curr = path; curr; curr = curr.prev) {
|
|
268
|
-
flattened[--index] = curr.key
|
|
321
|
+
} catch (error) {
|
|
322
|
+
cb(error)
|
|
323
|
+
throw error
|
|
269
324
|
}
|
|
270
|
-
return flattened
|
|
271
325
|
}
|
|
272
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
|
+
*/
|
|
273
343
|
function assertField (rootCtx, info, args) {
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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
|
|
290
380
|
}
|
|
291
381
|
|
|
382
|
+
const field = { error: null, ctx: fieldCtx }
|
|
383
|
+
rootCtx.fields.set(path, field)
|
|
384
|
+
if (collapsedFields !== undefined) collapsedFields.set(pathString, field)
|
|
292
385
|
return field
|
|
293
386
|
}
|
|
294
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
|
+
|
|
295
411
|
function wrapFields (type) {
|
|
296
412
|
if (!type || !type._fields || patchedTypes.has(type)) {
|
|
297
413
|
return
|
|
@@ -323,14 +439,19 @@ function wrapFieldType (field) {
|
|
|
323
439
|
}
|
|
324
440
|
|
|
325
441
|
function finishResolvers ({ fields }) {
|
|
326
|
-
for (const field of
|
|
327
|
-
|
|
328
|
-
field
|
|
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
|
|
329
450
|
if (field.error) {
|
|
330
|
-
|
|
331
|
-
resolveErrorCh.publish(
|
|
451
|
+
fieldCtx.error = field.error
|
|
452
|
+
resolveErrorCh.publish(fieldCtx)
|
|
332
453
|
}
|
|
333
|
-
finishResolveCh.publish(
|
|
454
|
+
finishResolveCh.publish(fieldCtx)
|
|
334
455
|
}
|
|
335
456
|
}
|
|
336
457
|
|
|
@@ -343,6 +464,11 @@ addHook({ name: '@graphql-tools/executor', versions: ['>=0.0.14'] }, executor =>
|
|
|
343
464
|
return executor
|
|
344
465
|
})
|
|
345
466
|
|
|
467
|
+
// TODO(BridgeAR): graphql >=17.0.0-alpha.9 routes execute() through
|
|
468
|
+
// experimentalExecuteIncrementally(), bypassing this hook. The same
|
|
469
|
+
// function returns { initialResult, subsequentResults } for @defer /
|
|
470
|
+
// @stream which callInAsyncScope does not handle — execute finishes
|
|
471
|
+
// before the streamed payloads land.
|
|
346
472
|
addHook({ name: 'graphql', file: 'execution/execute.js', versions: ['>=0.10'] }, execute => {
|
|
347
473
|
shimmer.wrap(execute, 'execute', wrapExecute(execute))
|
|
348
474
|
return execute
|