dd-trace 5.108.0 → 5.110.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/ci/init.js +4 -3
- package/index.d.ts +88 -25
- package/loader-hook.mjs +88 -2
- package/package.json +19 -14
- package/packages/datadog-esbuild/index.js +26 -0
- package/packages/datadog-esbuild/src/utils.js +46 -3
- package/packages/datadog-instrumentations/src/ai.js +43 -48
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js-context-methods.js +18 -0
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +111 -0
- package/packages/datadog-instrumentations/src/aws-sdk.js +3 -1
- package/packages/datadog-instrumentations/src/connect.js +4 -3
- package/packages/datadog-instrumentations/src/electron.js +1 -1
- package/packages/datadog-instrumentations/src/fastify.js +4 -12
- package/packages/datadog-instrumentations/src/graphql.js +17 -6
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +81 -8
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -2
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +65 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +6 -4
- package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/aws-durable-execution-sdk-js.js +31 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +18 -2
- package/packages/datadog-instrumentations/src/http/client.js +12 -2
- package/packages/datadog-instrumentations/src/ioredis.js +0 -1
- package/packages/datadog-instrumentations/src/iovalkey.js +1 -2
- package/packages/datadog-instrumentations/src/koa.js +3 -2
- package/packages/datadog-instrumentations/src/mariadb.js +4 -2
- package/packages/datadog-instrumentations/src/mocha/main.js +3 -3
- package/packages/datadog-instrumentations/src/next.js +44 -10
- package/packages/datadog-instrumentations/src/openai.js +77 -18
- package/packages/datadog-instrumentations/src/otel-sdk-trace.js +7 -6
- package/packages/datadog-instrumentations/src/playwright.js +1 -1
- package/packages/datadog-instrumentations/src/redis.js +0 -1
- package/packages/datadog-instrumentations/src/restify.js +4 -3
- package/packages/datadog-instrumentations/src/router.js +18 -5
- package/packages/datadog-instrumentations/src/selenium.js +1 -2
- package/packages/datadog-instrumentations/src/tedious.js +28 -0
- package/packages/datadog-instrumentations/src/vitest.js +323 -7
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +2 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/checkpoint.js +31 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/client.js +55 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +114 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +128 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/index.js +19 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +224 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +43 -0
- package/packages/datadog-plugin-aws-sdk/src/base.js +14 -16
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +43 -6
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +100 -37
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +108 -99
- package/packages/datadog-plugin-bullmq/src/filter.js +35 -0
- package/packages/datadog-plugin-bullmq/src/producer.js +84 -4
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +9 -1
- package/packages/datadog-plugin-fs/src/index.js +1 -0
- package/packages/datadog-plugin-http/src/client.js +8 -3
- package/packages/datadog-plugin-http2/src/client.js +5 -2
- package/packages/datadog-plugin-mysql/src/index.js +7 -2
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +2 -2
- package/packages/datadog-plugin-redis/src/index.js +1 -2
- package/packages/datadog-plugin-undici/src/index.js +5 -2
- package/packages/datadog-plugin-vitest/src/index.js +11 -2
- package/packages/datadog-webpack/index.js +17 -1
- package/packages/datadog-webpack/src/optional-peer-loader.js +17 -0
- package/packages/dd-trace/src/aiguard/channels.js +0 -1
- package/packages/dd-trace/src/aiguard/index.js +11 -49
- package/packages/dd-trace/src/aiguard/integrations/evaluate.js +46 -0
- package/packages/dd-trace/src/aiguard/integrations/openai.js +66 -0
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +78 -0
- package/packages/{datadog-instrumentations/src/helpers/ai-messages.js → dd-trace/src/aiguard/messages/openai.js} +85 -193
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +185 -0
- package/packages/dd-trace/src/aiguard/sdk.js +13 -1
- package/packages/dd-trace/src/appsec/api_security/index.js +55 -0
- package/packages/dd-trace/src/appsec/api_security/sampler.js +147 -0
- package/packages/dd-trace/src/appsec/channels.js +1 -0
- package/packages/dd-trace/src/appsec/downstream_requests.js +111 -58
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +54 -12
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +5 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +29 -4
- package/packages/dd-trace/src/appsec/index.js +10 -6
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +19 -11
- package/packages/dd-trace/src/appsec/reporter.js +1 -0
- package/packages/dd-trace/src/appsec/telemetry/api_security.js +34 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +26 -0
- package/packages/dd-trace/src/ci-visibility/requests/request.js +1 -17
- package/packages/dd-trace/src/config/defaults.js +22 -3
- package/packages/dd-trace/src/config/generated-config-types.d.ts +538 -1
- package/packages/dd-trace/src/config/helper.js +133 -33
- package/packages/dd-trace/src/config/index.js +4 -1
- package/packages/dd-trace/src/config/parsers.js +19 -1
- package/packages/dd-trace/src/config/supported-configurations.json +45 -5
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +49 -35
- package/packages/dd-trace/src/debugger/devtools_client/index.js +31 -66
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +83 -0
- package/packages/dd-trace/src/debugger/devtools_client/state.js +1 -0
- package/packages/dd-trace/src/debugger/index.js +5 -0
- package/packages/dd-trace/src/debugger/probe_sampler.js +112 -0
- package/packages/dd-trace/src/debugger/probe_sampler_constants.js +19 -0
- package/packages/dd-trace/src/dogstatsd.js +15 -8
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +77 -26
- package/packages/dd-trace/src/exporters/agentless/index.js +7 -5
- package/packages/dd-trace/src/exporters/agentless/intake.js +43 -0
- package/packages/dd-trace/src/exporters/agentless/writer.js +5 -4
- package/packages/dd-trace/src/exporters/common/request.js +1 -20
- package/packages/dd-trace/src/exporters/common/url.js +34 -0
- package/packages/dd-trace/src/exporters/span-stats/writer.js +1 -3
- package/packages/dd-trace/src/guardrails/index.js +8 -5
- package/packages/dd-trace/src/index.js +6 -4
- package/packages/dd-trace/src/llmobs/constants/tags.js +6 -0
- package/packages/dd-trace/src/llmobs/index.js +16 -5
- package/packages/dd-trace/src/llmobs/plugins/genai/util.js +3 -3
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +5 -1
- package/packages/dd-trace/src/llmobs/sdk.js +5 -3
- package/packages/dd-trace/src/llmobs/span_processor.js +4 -0
- package/packages/dd-trace/src/llmobs/tagger.js +55 -0
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -0
- package/packages/dd-trace/src/log/index.js +18 -20
- package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -1
- package/packages/dd-trace/src/opentelemetry/bridge-span-base.js +5 -4
- package/packages/dd-trace/src/opentelemetry/metrics/instruments.js +2 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +4 -3
- package/packages/dd-trace/src/opentelemetry/metrics/time.js +19 -0
- package/packages/dd-trace/src/opentelemetry/otlp/common.proto +2 -2
- package/packages/dd-trace/src/opentelemetry/otlp/logs.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/logs_service.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/metrics.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/metrics_service.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +11 -4
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +29 -13
- package/packages/dd-trace/src/opentelemetry/span.js +14 -3
- package/packages/dd-trace/src/opentelemetry/span_context.js +1 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +2 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +3 -2
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +26 -13
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +3 -3
- package/packages/dd-trace/src/opentracing/span_context.js +17 -0
- package/packages/dd-trace/src/plugin_manager.js +7 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +36 -3
- package/packages/dd-trace/src/plugins/index.js +3 -0
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +276 -0
- package/packages/dd-trace/src/plugins/util/test.js +80 -0
- package/packages/dd-trace/src/plugins/util/url.js +68 -1
- package/packages/dd-trace/src/plugins/util/web.js +19 -36
- package/packages/dd-trace/src/priority_sampler.js +1 -13
- package/packages/dd-trace/src/profiling/config.js +129 -198
- package/packages/dd-trace/src/profiling/constants.js +4 -7
- package/packages/dd-trace/src/profiling/exporter_cli.js +10 -10
- package/packages/dd-trace/src/profiling/exporters/agent.js +23 -16
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +45 -14
- package/packages/dd-trace/src/profiling/exporters/file.js +16 -5
- package/packages/dd-trace/src/profiling/oom.js +71 -0
- package/packages/dd-trace/src/profiling/profiler.js +35 -23
- package/packages/dd-trace/src/profiling/profilers/events.js +14 -7
- package/packages/dd-trace/src/profiling/profilers/space.js +27 -18
- package/packages/dd-trace/src/profiling/profilers/wall.js +35 -25
- package/packages/dd-trace/src/ritm.js +4 -2
- package/packages/dd-trace/src/serverless.js +1 -2
- package/packages/dd-trace/src/service-naming/schemas/util.js +36 -5
- package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +12 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +12 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/web.js +5 -3
- package/packages/dd-trace/src/span_format.js +2 -1
- package/packages/dd-trace/src/span_processor.js +6 -0
- package/packages/dd-trace/src/telemetry/send-data.js +12 -10
- package/packages/dd-trace/src/tracer.js +15 -1
- package/packages/dd-trace/src/util.js +14 -0
- package/register.js +58 -1
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +0 -284
- package/packages/dd-trace/src/appsec/api_security_sampler.js +0 -117
|
@@ -2,29 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
const { channel, tracingChannel } = require('dc-polyfill')
|
|
4
4
|
const shimmer = require('../../datadog-shimmer')
|
|
5
|
-
const { convertVercelPromptToMessages, buildOutputMessages } = require('./helpers/ai-messages')
|
|
6
5
|
const { addHook, getHooks } = require('./helpers/instrument')
|
|
7
6
|
|
|
8
7
|
const vercelAiTracingChannel = tracingChannel('dd-trace:vercel-ai')
|
|
9
8
|
const vercelAiSpanSetAttributesChannel = channel('dd-trace:vercel-ai:span:setAttributes')
|
|
10
|
-
const
|
|
9
|
+
const doGenerateBeforeChannel = channel('dd-trace:vercel-ai:doGenerate:before')
|
|
10
|
+
const doGenerateAfterChannel = channel('dd-trace:vercel-ai:doGenerate:after')
|
|
11
|
+
const doStreamBeforeChannel = channel('dd-trace:vercel-ai:doStream:before')
|
|
12
|
+
const doStreamAfterChannel = channel('dd-trace:vercel-ai:doStream:after')
|
|
11
13
|
|
|
12
14
|
const tracers = new WeakSet()
|
|
13
15
|
const wrappedModels = new WeakSet()
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
|
-
* Publishes
|
|
18
|
+
* Publishes a provider-native lifecycle payload to a cancelable lifecycle channel.
|
|
17
19
|
*
|
|
18
|
-
* Subscribers push async work into `pending`
|
|
20
|
+
* Subscribers push async work into `pending` synchronously during publication and
|
|
21
|
+
* abort `abortController` with an error before the pushed promise resolves to block.
|
|
19
22
|
*
|
|
20
|
-
* @param {
|
|
23
|
+
* @param {object} lifecycleChannel
|
|
24
|
+
* @param {object} payload
|
|
21
25
|
* @returns {Promise<void>}
|
|
22
26
|
*/
|
|
23
|
-
function
|
|
27
|
+
function publishLifecycle (lifecycleChannel, payload) {
|
|
24
28
|
const abortController = new AbortController()
|
|
25
|
-
const ctx = {
|
|
29
|
+
const ctx = { ...payload, abortController, pending: [] }
|
|
26
30
|
|
|
27
|
-
|
|
31
|
+
lifecycleChannel.publish(ctx)
|
|
28
32
|
|
|
29
33
|
return Promise.all(ctx.pending).then(() => {
|
|
30
34
|
if (abortController.signal.aborted) {
|
|
@@ -34,12 +38,11 @@ function publishEvaluation (messages) {
|
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
/**
|
|
37
|
-
* Wraps a Vercel AI language model's doGenerate and doStream methods
|
|
38
|
-
* messages with AIGuard.
|
|
41
|
+
* Wraps a Vercel AI language model's doGenerate and doStream lifecycle methods.
|
|
39
42
|
*
|
|
40
43
|
* @param {object} model - A Vercel AI language model instance
|
|
41
44
|
*/
|
|
42
|
-
function
|
|
45
|
+
function wrapModelWithLifecycle (model) {
|
|
43
46
|
if (!model || wrappedModels.has(model)) return
|
|
44
47
|
wrappedModels.add(model)
|
|
45
48
|
|
|
@@ -48,20 +51,18 @@ function wrapModelWithAIGuard (model) {
|
|
|
48
51
|
return function (options) {
|
|
49
52
|
const originalResult = original.call(this, options)
|
|
50
53
|
|
|
51
|
-
if (!
|
|
54
|
+
if (!doGenerateBeforeChannel.hasSubscribers && !doGenerateAfterChannel.hasSubscribers) return originalResult
|
|
52
55
|
if (!options.prompt?.length) return originalResult
|
|
53
56
|
|
|
54
|
-
const
|
|
55
|
-
|
|
57
|
+
const beforeEvaluation = doGenerateBeforeChannel.hasSubscribers
|
|
58
|
+
? publishLifecycle(doGenerateBeforeChannel, { prompt: options.prompt, options })
|
|
59
|
+
: Promise.resolve()
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
// The LLM has no side effects so it is safe to discard its result if AI Guard blocks.
|
|
59
|
-
return Promise.all([publishEvaluation(inputMessages), originalResult])
|
|
61
|
+
return Promise.all([beforeEvaluation, originalResult])
|
|
60
62
|
.then(([, result]) => {
|
|
61
|
-
if (!result.content?.length) return result
|
|
62
|
-
const
|
|
63
|
-
return
|
|
64
|
-
.then(() => result)
|
|
63
|
+
if (!doGenerateAfterChannel.hasSubscribers || !result.content?.length) return result
|
|
64
|
+
const payload = { prompt: options.prompt, options, result }
|
|
65
|
+
return publishLifecycle(doGenerateAfterChannel, payload).then(() => result)
|
|
65
66
|
})
|
|
66
67
|
}
|
|
67
68
|
})
|
|
@@ -72,16 +73,17 @@ function wrapModelWithAIGuard (model) {
|
|
|
72
73
|
return function (options) {
|
|
73
74
|
const originalResult = original.call(this, options)
|
|
74
75
|
|
|
75
|
-
if (!
|
|
76
|
+
if (!doStreamBeforeChannel.hasSubscribers && !doStreamAfterChannel.hasSubscribers) return originalResult
|
|
76
77
|
if (!options.prompt?.length) return originalResult
|
|
77
78
|
|
|
78
|
-
const
|
|
79
|
-
|
|
79
|
+
const beforeEvaluation = doStreamBeforeChannel.hasSubscribers
|
|
80
|
+
? publishLifecycle(doStreamBeforeChannel, { prompt: options.prompt, options })
|
|
81
|
+
: Promise.resolve()
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
// The LLM has no side effects so it is safe to discard its result if AI Guard blocks.
|
|
83
|
-
return Promise.all([publishEvaluation(inputMessages), originalResult])
|
|
83
|
+
return Promise.all([beforeEvaluation, originalResult])
|
|
84
84
|
.then(([, result]) => {
|
|
85
|
+
if (!doStreamAfterChannel.hasSubscribers) return result
|
|
86
|
+
|
|
85
87
|
const chunks = []
|
|
86
88
|
const reader = result.stream.getReader()
|
|
87
89
|
|
|
@@ -94,26 +96,19 @@ function wrapModelWithAIGuard (model) {
|
|
|
94
96
|
}
|
|
95
97
|
|
|
96
98
|
return readAll().then(() => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
for (const chunk of chunks) {
|
|
110
|
-
controller.enqueue(chunk)
|
|
111
|
-
}
|
|
112
|
-
controller.close()
|
|
113
|
-
},
|
|
99
|
+
return publishLifecycle(doStreamAfterChannel, { prompt: options.prompt, options, chunks })
|
|
100
|
+
.then(() => {
|
|
101
|
+
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
102
|
+
const stream = new ReadableStream({
|
|
103
|
+
start (controller) {
|
|
104
|
+
for (const chunk of chunks) {
|
|
105
|
+
controller.enqueue(chunk)
|
|
106
|
+
}
|
|
107
|
+
controller.close()
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
return { ...result, stream }
|
|
114
111
|
})
|
|
115
|
-
return { ...result, stream }
|
|
116
|
-
})
|
|
117
112
|
})
|
|
118
113
|
})
|
|
119
114
|
}
|
|
@@ -230,7 +225,7 @@ for (const hook of getHooks('ai')) {
|
|
|
230
225
|
// generateObject, streamObject)
|
|
231
226
|
tracingChannel('orchestrion:ai:resolveLanguageModel').subscribe({
|
|
232
227
|
end (ctx) {
|
|
233
|
-
|
|
228
|
+
wrapModelWithLifecycle(ctx.result)
|
|
234
229
|
},
|
|
235
230
|
})
|
|
236
231
|
|
|
@@ -238,4 +233,4 @@ for (const hook of getHooks('ai')) {
|
|
|
238
233
|
})
|
|
239
234
|
}
|
|
240
235
|
|
|
241
|
-
module.exports = {
|
|
236
|
+
module.exports = { wrapModelWithLifecycle }
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Methods on `DurableContextImpl` that return a lazy DurablePromise. The rewriter
|
|
4
|
+
// instrumentation generates a `kind: 'Sync'` Orchestrion hook for each so Orchestrion
|
|
5
|
+
// does not eagerly side-chain `.then()`; the runtime instrumentation side-chains the
|
|
6
|
+
// returned DurablePromise itself and publishes a `:settle` channel once it settles,
|
|
7
|
+
// preserving the SDK's lazy semantics. Shared between both so the lists cannot drift.
|
|
8
|
+
module.exports = [
|
|
9
|
+
'step',
|
|
10
|
+
'invoke',
|
|
11
|
+
'runInChildContext',
|
|
12
|
+
'wait',
|
|
13
|
+
'waitForCondition',
|
|
14
|
+
'waitForCallback',
|
|
15
|
+
'createCallback',
|
|
16
|
+
'map',
|
|
17
|
+
'parallel',
|
|
18
|
+
]
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { channel, tracingChannel } = require('dc-polyfill')
|
|
4
|
+
const shimmer = require('../../datadog-shimmer')
|
|
5
|
+
const { addHook, getHooks } = require('./helpers/instrument')
|
|
6
|
+
const LAZY_DURABLE_PROMISE_METHODS = require('./aws-durable-execution-sdk-js-context-methods')
|
|
7
|
+
|
|
8
|
+
for (const method of LAZY_DURABLE_PROMISE_METHODS) {
|
|
9
|
+
const orchestrionCh = tracingChannel(`orchestrion:@aws/durable-execution-sdk-js:DurableContextImpl_${method}`)
|
|
10
|
+
const settleCh = channel(`apm:aws-durable-execution-sdk-js:${method}:settle`)
|
|
11
|
+
|
|
12
|
+
orchestrionCh.end.subscribe(ctx => {
|
|
13
|
+
if (!settleCh.hasSubscribers) return
|
|
14
|
+
observeDurablePromise(ctx.result, error => {
|
|
15
|
+
if (error !== undefined) ctx.error = error
|
|
16
|
+
settleCh.publish(ctx)
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// runHandler(event, context, executionContext, mode, checkpointToken, handler) creates the
|
|
22
|
+
// DurableContext internally and passes it to the user handler, and drives suspension through
|
|
23
|
+
// executionContext.terminationManager.terminate(). The cross-invocation checkpoint plugin needs
|
|
24
|
+
// both: the DurableContext (to reach the checkpoint manager) and a signal that the execution is
|
|
25
|
+
// suspending. Capture the former off the handler call and surface the latter on a channel.
|
|
26
|
+
const HANDLER_ARG_INDEX = 5
|
|
27
|
+
const EXECUTION_CONTEXT_ARG_INDEX = 2
|
|
28
|
+
|
|
29
|
+
const withDurableExecutionCh = tracingChannel('orchestrion:@aws/durable-execution-sdk-js:withDurableExecution')
|
|
30
|
+
const terminateCh = channel('apm:aws-durable-execution-sdk-js:terminate')
|
|
31
|
+
|
|
32
|
+
withDurableExecutionCh.start.subscribe(ctx => {
|
|
33
|
+
// Only wrap while the plugin is listening (cross-invocation tracing enabled).
|
|
34
|
+
if (!terminateCh.hasSubscribers) return
|
|
35
|
+
|
|
36
|
+
// ctx.arguments is an array-like `arguments` object, not a true Array.
|
|
37
|
+
const args = ctx.arguments
|
|
38
|
+
if (!args) return
|
|
39
|
+
|
|
40
|
+
if (typeof args[HANDLER_ARG_INDEX] === 'function') {
|
|
41
|
+
shimmer.wrap(args, HANDLER_ARG_INDEX, handler => function (event, durableContext) {
|
|
42
|
+
ctx.durableContext = durableContext
|
|
43
|
+
return handler.apply(this, arguments)
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const terminationManager = args[EXECUTION_CONTEXT_ARG_INDEX]?.terminationManager
|
|
48
|
+
if (typeof terminationManager?.terminate === 'function') {
|
|
49
|
+
shimmer.wrap(terminationManager, 'terminate', terminate => function (options) {
|
|
50
|
+
// Publish before the original runs so the plugin can enqueue the checkpoint while the
|
|
51
|
+
// checkpoint manager is still accepting writes (it flips to "terminating" inside terminate()).
|
|
52
|
+
ctx.terminationReason = options?.reason
|
|
53
|
+
terminateCh.publish(ctx)
|
|
54
|
+
return terminate.apply(this, arguments)
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
// Per-instance settle callback read by the shared prototype wrappers installed by
|
|
60
|
+
// `instrumentDurablePromiseProto`. Stored on the DurablePromise instance so the prototype
|
|
61
|
+
// wrappers stay allocation-free and the promise carries its own observer.
|
|
62
|
+
const ON_SETTLE = Symbol('_dd.durableExecution.onSettle')
|
|
63
|
+
|
|
64
|
+
const instrumentedProtos = new WeakSet()
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Wraps `then`/`catch`/`finally` on a DurablePromise prototype once so every instance shares
|
|
68
|
+
* the same wrappers instead of being re-wrapped individually. The wrappers side-chain a settle
|
|
69
|
+
* observer the first time user code chains off the promise, then clear `ON_SETTLE` so the
|
|
70
|
+
* observer attaches at most once (a promise settles only once). Instances we don't observe
|
|
71
|
+
* never set `ON_SETTLE`, so for them the wrappers are a single property read and a passthrough.
|
|
72
|
+
* @param {object} proto - The DurablePromise prototype (`Object.getPrototypeOf(dp)`).
|
|
73
|
+
* @returns {void}
|
|
74
|
+
*/
|
|
75
|
+
function instrumentDurablePromiseProto (proto) {
|
|
76
|
+
if (instrumentedProtos.has(proto)) return
|
|
77
|
+
instrumentedProtos.add(proto)
|
|
78
|
+
|
|
79
|
+
// Capture the genuine `.then` before wrapping so the settle observer side-chains without
|
|
80
|
+
// recursing back into the wrapper below.
|
|
81
|
+
const originalThen = proto.then
|
|
82
|
+
|
|
83
|
+
shimmer.massWrap(proto, ['then', 'catch', 'finally'], original => function (...args) {
|
|
84
|
+
const onSettle = this[ON_SETTLE]
|
|
85
|
+
if (onSettle !== undefined) {
|
|
86
|
+
this[ON_SETTLE] = undefined
|
|
87
|
+
originalThen.call(this, () => onSettle(), err => onSettle(err))
|
|
88
|
+
}
|
|
89
|
+
return original.apply(this, args)
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Registers a settle observer on a returned DurablePromise. Callers pair `kind: 'Sync'` with this
|
|
95
|
+
* helper so `onSettle` only fires after user code first awaits / chains, preserving the SDK's
|
|
96
|
+
* lazy semantics.
|
|
97
|
+
* @param {object} dp - The returned DurablePromise instance.
|
|
98
|
+
* @param {(err: unknown) => void} onSettle - Called once with `undefined` on success or the
|
|
99
|
+
* rejection reason on failure.
|
|
100
|
+
* @returns {void}
|
|
101
|
+
*/
|
|
102
|
+
function observeDurablePromise (dp, onSettle) {
|
|
103
|
+
if (!dp || typeof dp.then !== 'function') return
|
|
104
|
+
instrumentDurablePromiseProto(Object.getPrototypeOf(dp))
|
|
105
|
+
dp[ON_SETTLE] = onSettle
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (const hook of getHooks('@aws/durable-execution-sdk-js')) {
|
|
109
|
+
hook.file = null
|
|
110
|
+
addHook(hook, exports => exports)
|
|
111
|
+
}
|
|
@@ -150,6 +150,7 @@ function wrapDeserialize (deserialize, headersCh, responseIndex = 0) {
|
|
|
150
150
|
function wrapSmithySend (send) {
|
|
151
151
|
return function (command, ...args) {
|
|
152
152
|
const cb = args.at(-1)
|
|
153
|
+
const cbExists = typeof cb === 'function'
|
|
153
154
|
const serviceIdentifier = this.config.serviceId.toLowerCase()
|
|
154
155
|
const channelSuffix = getChannelSuffix(serviceIdentifier)
|
|
155
156
|
const channels = getChannelBag(channelSuffix)
|
|
@@ -188,6 +189,7 @@ function wrapSmithySend (send) {
|
|
|
188
189
|
operation,
|
|
189
190
|
awsService: clientName,
|
|
190
191
|
request,
|
|
192
|
+
cbExists,
|
|
191
193
|
}
|
|
192
194
|
|
|
193
195
|
return channels.start.runStores(ctx, () => {
|
|
@@ -197,7 +199,7 @@ function wrapSmithySend (send) {
|
|
|
197
199
|
channels.region.publish(ctx)
|
|
198
200
|
})
|
|
199
201
|
|
|
200
|
-
if (
|
|
202
|
+
if (cbExists) {
|
|
201
203
|
args[args.length - 1] = shimmer.wrapCallback(cb, cb => function (err, result) {
|
|
202
204
|
addResponse(ctx, err, result)
|
|
203
205
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
|
-
const { addHook, channel } = require('./helpers/instrument')
|
|
4
|
+
const { addHook, channel, createErrorPublisher } = require('./helpers/instrument')
|
|
5
5
|
|
|
6
6
|
const enterChannel = channel('apm:connect:middleware:enter')
|
|
7
7
|
const exitChannel = channel('apm:connect:middleware:exit')
|
|
@@ -9,6 +9,7 @@ const errorChannel = channel('apm:connect:middleware:error')
|
|
|
9
9
|
const nextChannel = channel('apm:connect:middleware:next')
|
|
10
10
|
const finishChannel = channel('apm:connect:middleware:finish')
|
|
11
11
|
const handleChannel = channel('apm:connect:request:handle')
|
|
12
|
+
const publishError = createErrorPublisher(errorChannel)
|
|
12
13
|
|
|
13
14
|
function wrapConnect (connect) {
|
|
14
15
|
if (typeof connect !== 'function') return connect
|
|
@@ -78,7 +79,7 @@ function wrapLayerHandle (layer) {
|
|
|
78
79
|
try {
|
|
79
80
|
return original.apply(this, args)
|
|
80
81
|
} catch (error) {
|
|
81
|
-
|
|
82
|
+
publishError({ req, error })
|
|
82
83
|
nextChannel.publish({ req })
|
|
83
84
|
finishChannel.publish({ req })
|
|
84
85
|
|
|
@@ -93,7 +94,7 @@ function wrapNext (req, next) {
|
|
|
93
94
|
// Mirror next's name/arity so wrapCallback skips its per-call identity rewrite.
|
|
94
95
|
return shimmer.wrapCallback(next, original => function next (error) {
|
|
95
96
|
if (error) {
|
|
96
|
-
|
|
97
|
+
publishError({ req, error })
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
nextChannel.publish({ req })
|
|
@@ -218,7 +218,7 @@ addHook({ name: 'electron', versions: ['>=37.0.0'] }, electron => {
|
|
|
218
218
|
wrap(ipcRenderer, 'removeAllListeners', createWrapRemoveAllListeners(listeners))
|
|
219
219
|
|
|
220
220
|
ipcRenderer.send('datadog:apm:renderer:patched')
|
|
221
|
-
} else {
|
|
221
|
+
} else if (ipcMain) {
|
|
222
222
|
wrap(ipcMain, 'addListener', createWrapAddListener(mainReceiveCh, listeners))
|
|
223
223
|
wrap(ipcMain, 'handle', createWrapAddListener(mainHandleCh, handlers))
|
|
224
224
|
wrap(ipcMain, 'handleOnce', createWrapAddListener(mainHandleCh, handlers))
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
|
-
const { addHook, channel } = require('./helpers/instrument')
|
|
4
|
+
const { addHook, channel, createErrorPublisher } = require('./helpers/instrument')
|
|
5
5
|
|
|
6
6
|
const errorChannel = channel('apm:fastify:middleware:error')
|
|
7
|
+
const publishErrorChannel = createErrorPublisher(errorChannel)
|
|
7
8
|
const handleChannel = channel('apm:fastify:request:handle')
|
|
8
9
|
const routeAddedChannel = channel('apm:fastify:route:added')
|
|
9
10
|
const bodyParserReadCh = channel('datadog:fastify:body-parser:finish')
|
|
@@ -303,18 +304,9 @@ function getRouteConfig (request) {
|
|
|
303
304
|
return request?.routeOptions?.config
|
|
304
305
|
}
|
|
305
306
|
|
|
306
|
-
let publishingError = false
|
|
307
|
-
|
|
308
307
|
function publishError (ctx) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if (ctx.error && !publishingError) {
|
|
312
|
-
publishingError = true
|
|
313
|
-
try {
|
|
314
|
-
errorChannel.publish(ctx)
|
|
315
|
-
} finally {
|
|
316
|
-
publishingError = false
|
|
317
|
-
}
|
|
308
|
+
if (ctx.error) {
|
|
309
|
+
publishErrorChannel(ctx)
|
|
318
310
|
}
|
|
319
311
|
|
|
320
312
|
return ctx.error
|
|
@@ -455,15 +455,26 @@ function finishResolvers ({ fields }) {
|
|
|
455
455
|
}
|
|
456
456
|
}
|
|
457
457
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
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
|
+
}
|
|
464
470
|
return executor
|
|
465
471
|
})
|
|
466
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
|
+
|
|
467
478
|
// TODO(BridgeAR): graphql >=17.0.0-alpha.9 routes execute() through
|
|
468
479
|
// experimentalExecuteIncrementally(), bypassing this hook. The same
|
|
469
480
|
// function returns { initialResult, subsequentResults } for @defer /
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
const
|
|
3
|
+
// Queued before the logger is ready; flushed once the tracer knows its config.
|
|
4
|
+
const warnings = [] // conflicts; flushed under DD_TRACE_DEBUG
|
|
5
|
+
const loadOrderWarnings = [] // "loaded before dd-trace"; flushed under startupLogs
|
|
6
|
+
const frameworkWarnings = [] // curated (e.g. Next.js); flushed unconditionally
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Here we maintain a list of packages that an application
|
|
@@ -28,6 +29,24 @@ const potentialConflicts = new Set([
|
|
|
28
29
|
|
|
29
30
|
const extractPackageAndModulePath = require('./extract-package-and-module-path')
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Frameworks that load their own server code before any user code (and thus
|
|
34
|
+
* before a late `tracer.init()`) can run. When their server module is already
|
|
35
|
+
* in `require.cache` at init time, dd-trace was loaded too late to instrument
|
|
36
|
+
* them and the integration silently no-ops. Unlike the broad scan below, this
|
|
37
|
+
* set is high-signal enough to warn on by default. `file` is the module whose
|
|
38
|
+
* presence proves the server is already loaded; `guidance` is the bundler note
|
|
39
|
+
* appended to the warning.
|
|
40
|
+
*/
|
|
41
|
+
const earlyLoadFrameworks = new Map([
|
|
42
|
+
['next', {
|
|
43
|
+
// dist/server/next-server.js (>=11.1), dist/next-server/server/next-server.js (older)
|
|
44
|
+
file: 'next-server.js',
|
|
45
|
+
guidance: "add 'dd-trace' to `serverExternalPackages` (Next.js >=15) or " +
|
|
46
|
+
'`experimental.serverComponentsExternalPackages` (13-14) so it is not bundled',
|
|
47
|
+
}],
|
|
48
|
+
])
|
|
49
|
+
|
|
31
50
|
/**
|
|
32
51
|
* The lowest hanging fruit to debug an app that isn't tracing
|
|
33
52
|
* properly is to check that it is loaded before any modules
|
|
@@ -43,25 +62,53 @@ const extractPackageAndModulePath = require('./extract-package-and-module-path')
|
|
|
43
62
|
* app loads a package we instrument but outside of an
|
|
44
63
|
* unsupported version then a warning would still be displayed.
|
|
45
64
|
* This is OK as the tracer should be loaded earlier anyway.
|
|
65
|
+
*
|
|
66
|
+
* Curated frameworks (see `earlyLoadFrameworks`) surface unconditionally; the
|
|
67
|
+
* broad list of packages loaded before dd-trace is queued for the startupLogs-
|
|
68
|
+
* gated flush (`flushLoadOrderWarnings`).
|
|
46
69
|
*/
|
|
47
70
|
module.exports.checkForRequiredModules = function () {
|
|
48
71
|
const packages = require('./hooks')
|
|
49
72
|
const naughties = new Set()
|
|
73
|
+
const frameworksSeen = new Set()
|
|
50
74
|
let didWarn = false
|
|
51
75
|
|
|
52
76
|
for (const pathToModule of Object.keys(require.cache)) {
|
|
53
|
-
|
|
77
|
+
// require.cache keys use the platform separator; normalize so the
|
|
78
|
+
// `node_modules/<pkg>` parsing works on Windows (backslash paths).
|
|
79
|
+
const { pkg, path } = extractPackageAndModulePath(pathToModule.replaceAll('\\', '/'))
|
|
54
80
|
|
|
55
|
-
if (
|
|
56
|
-
|
|
81
|
+
if (pkg === null) continue
|
|
82
|
+
|
|
83
|
+
// A curated framework loads its own server before user code, so its server
|
|
84
|
+
// module being cached means dd-trace was too late to instrument it. These
|
|
85
|
+
// surface unconditionally (see flushFrameworkWarnings) with an actionable
|
|
86
|
+
// message, so they never fall through to the broad load-order list below.
|
|
87
|
+
const framework = earlyLoadFrameworks.get(pkg)
|
|
88
|
+
if (framework !== undefined) {
|
|
89
|
+
if (!frameworksSeen.has(pkg) && path?.endsWith(framework.file)) {
|
|
90
|
+
frameworksSeen.add(pkg)
|
|
91
|
+
frameworkWarnings.push(
|
|
92
|
+
`'${pkg}' was loaded before dd-trace, so the ${pkg} integration will not be applied. ` +
|
|
93
|
+
'Initialize dd-trace before your application starts — ' +
|
|
94
|
+
"NODE_OPTIONS='--require dd-trace/init' (CommonJS) or '--import dd-trace/initialize.mjs' (ESM) — " +
|
|
95
|
+
`and ${framework.guidance}.`
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
continue
|
|
99
|
+
}
|
|
57
100
|
|
|
58
|
-
|
|
101
|
+
if (naughties.has(pkg) || !(pkg in packages)) continue
|
|
102
|
+
|
|
103
|
+
loadOrderWarnings.push(
|
|
104
|
+
() => `Warning: Package '${pkg}' was loaded before dd-trace! This may break instrumentation.`
|
|
105
|
+
)
|
|
59
106
|
|
|
60
107
|
naughties.add(pkg)
|
|
61
108
|
didWarn = true
|
|
62
109
|
}
|
|
63
110
|
|
|
64
|
-
if (didWarn)
|
|
111
|
+
if (didWarn) loadOrderWarnings.push('Warning: Please ensure dd-trace is loaded before other modules.')
|
|
65
112
|
}
|
|
66
113
|
|
|
67
114
|
/**
|
|
@@ -104,3 +151,29 @@ module.exports.flushStartupLogs = function (log) {
|
|
|
104
151
|
log.warn(typeof entry === 'function' ? entry() : entry)
|
|
105
152
|
}
|
|
106
153
|
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Drains the broad "loaded before dd-trace" warnings collected by
|
|
157
|
+
* `checkForRequiredModules`. The tracer gates this on startupLogs (these are
|
|
158
|
+
* startup diagnostics), unlike the unconditional `flushFrameworkWarnings`.
|
|
159
|
+
* @param {(message: string) => void} warn
|
|
160
|
+
*/
|
|
161
|
+
module.exports.flushLoadOrderWarnings = function (warn) {
|
|
162
|
+
while (loadOrderWarnings.length) {
|
|
163
|
+
const entry = loadOrderWarnings.shift()
|
|
164
|
+
warn(typeof entry === 'function' ? entry() : entry)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Drains the framework warnings collected by `checkForRequiredModules`. The
|
|
170
|
+
* tracer surfaces these unconditionally (not gated on startupLogs or
|
|
171
|
+
* DD_TRACE_DEBUG), unlike the DD_TRACE_DEBUG-only `flushStartupLogs` queue,
|
|
172
|
+
* because the affected users run with neither enabled (#5430 / #5432).
|
|
173
|
+
* @param {(message: string) => void} warn
|
|
174
|
+
*/
|
|
175
|
+
module.exports.flushFrameworkWarnings = function (warn) {
|
|
176
|
+
while (frameworkWarnings.length) {
|
|
177
|
+
warn(frameworkWarnings.shift())
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -22,6 +22,7 @@ module.exports = {
|
|
|
22
22
|
'@modelcontextprotocol/sdk': () => require('../modelcontextprotocol-sdk'),
|
|
23
23
|
'apollo-server-core': () => require('../apollo-server-core'),
|
|
24
24
|
'@aws-sdk/smithy-client': () => require('../aws-sdk'),
|
|
25
|
+
'@aws/durable-execution-sdk-js': () => require('../aws-durable-execution-sdk-js'),
|
|
25
26
|
'@azure/cosmos': { esmFirst: true, fn: () => require('../azure-cosmos') },
|
|
26
27
|
'@azure/event-hubs': () => require('../azure-event-hubs'),
|
|
27
28
|
'@azure/functions': () => require('../azure-functions'),
|
|
@@ -42,6 +42,31 @@ exports.tracingChannel = function (name) {
|
|
|
42
42
|
return tc
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Build a guarded publisher for a public error channel. A subscriber that
|
|
47
|
+
* re-enters the same wrapped dispatch while handling the error would otherwise
|
|
48
|
+
* republish here and recurse until the stack overflows. Each framework binds
|
|
49
|
+
* its own publisher, so the in-flight flag stays private to one channel: a
|
|
50
|
+
* genuinely nested error on a different framework's channel (a Koa app mounted
|
|
51
|
+
* inside Express) still reaches its subscribers instead of being dropped, and
|
|
52
|
+
* the guard costs a closure read rather than a per-publish channel lookup.
|
|
53
|
+
*
|
|
54
|
+
* @param {Channel} errorChannel
|
|
55
|
+
*/
|
|
56
|
+
exports.createErrorPublisher = function createErrorPublisher (errorChannel) {
|
|
57
|
+
let publishing = false
|
|
58
|
+
/** @param {object} message */
|
|
59
|
+
return function publishError (message) {
|
|
60
|
+
if (publishing) return
|
|
61
|
+
publishing = true
|
|
62
|
+
try {
|
|
63
|
+
errorChannel.publish(message)
|
|
64
|
+
} finally {
|
|
65
|
+
publishing = false
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
45
70
|
exports.getHooks = function getHooks (names) {
|
|
46
71
|
names = [names].flat()
|
|
47
72
|
|
|
@@ -55,9 +80,9 @@ exports.getHooks = function getHooks (names) {
|
|
|
55
80
|
* @param {object} args
|
|
56
81
|
* @param {string} args.name module name
|
|
57
82
|
* @param {string[]} [args.versions] array of semver range strings
|
|
58
|
-
* @param {string} [args.file] path to file within package to instrument. Defaults to 'index.js'.
|
|
83
|
+
* @param {string} [args.file] path to file within package to instrument. Defaults to 'index.js'.
|
|
59
84
|
* @param {string} [args.filePattern] pattern to match files within package to instrument
|
|
60
|
-
* @param {boolean} [args.patchDefault] whether to patch the default export. Defaults to true.
|
|
85
|
+
* @param {boolean} [args.patchDefault] whether to patch the default export. Defaults to true.
|
|
61
86
|
* @param {(moduleExports: unknown, version: string, isIitm?: boolean, hookMeta?: object) => unknown} [hook]
|
|
62
87
|
* Patches module exports
|
|
63
88
|
*/
|