dd-trace 6.21.0 → 6.22.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 (204) hide show
  1. package/ci/diagnose.js +9 -14
  2. package/ci/init.js +1 -2
  3. package/ci/test-optimization-validation/ci-discovery.js +9 -4
  4. package/ci/test-optimization-validation/executable.js +1 -5
  5. package/ci/test-optimization-validation/framework-adapters/cypress.js +1 -4
  6. package/ci/test-optimization-validation/framework-adapters/vitest.js +1 -1
  7. package/ci/test-optimization-validation/generated-files.js +6 -4
  8. package/ci/test-optimization-validation/generated-test-contract.js +7 -3
  9. package/ci/test-optimization-validation/manifest-scaffold.js +7 -2
  10. package/ci/test-optimization-validation/manifest-schema.js +6 -7
  11. package/ci/test-optimization-validation/report-writer.js +6 -2
  12. package/ci/test-optimization-validation/runner-command.js +2 -4
  13. package/ci/test-optimization-validation/runner-contract.js +1 -2
  14. package/ci/test-optimization-validation/scenarios/auto-test-retries.js +1 -15
  15. package/ci/vitest-no-worker-init-setup.mjs +10 -7
  16. package/index.d.ts +25 -14
  17. package/initialize.mjs +1 -3
  18. package/openfeature/rules-based.d.ts +11 -0
  19. package/openfeature/rules-based.js +7 -0
  20. package/package.json +12 -10
  21. package/packages/datadog-core/src/storage.js +16 -0
  22. package/packages/datadog-esbuild/index.js +18 -12
  23. package/packages/datadog-instrumentations/src/aerospike.js +3 -3
  24. package/packages/datadog-instrumentations/src/ai.js +3 -3
  25. package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +0 -6
  26. package/packages/datadog-instrumentations/src/aws-sdk.js +21 -13
  27. package/packages/datadog-instrumentations/src/cassandra-driver.js +25 -20
  28. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +9 -23
  29. package/packages/datadog-instrumentations/src/cucumber.js +48 -33
  30. package/packages/datadog-instrumentations/src/elasticsearch.js +1 -5
  31. package/packages/datadog-instrumentations/src/electron.js +6 -6
  32. package/packages/datadog-instrumentations/src/fastify.js +13 -4
  33. package/packages/datadog-instrumentations/src/fs.js +2 -2
  34. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +9 -5
  35. package/packages/datadog-instrumentations/src/grpc/client.js +2 -0
  36. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +2 -2
  37. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +1 -2
  38. package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
  39. package/packages/datadog-instrumentations/src/helpers/register.js +36 -1
  40. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -0
  41. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +87 -6
  42. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +5 -6
  43. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +48 -31
  44. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +7 -7
  45. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +42 -4
  46. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +7 -10
  47. package/packages/datadog-instrumentations/src/ioredis.js +7 -5
  48. package/packages/datadog-instrumentations/src/iovalkey.js +7 -5
  49. package/packages/datadog-instrumentations/src/jest.js +3 -10
  50. package/packages/datadog-instrumentations/src/knex.js +9 -5
  51. package/packages/datadog-instrumentations/src/mariadb-bundle.js +3 -3
  52. package/packages/datadog-instrumentations/src/mocha/common.js +20 -8
  53. package/packages/datadog-instrumentations/src/mocha/main.js +140 -43
  54. package/packages/datadog-instrumentations/src/mocha/utils.js +3 -2
  55. package/packages/datadog-instrumentations/src/mocha/worker.js +1 -2
  56. package/packages/datadog-instrumentations/src/mongodb-core.js +3 -3
  57. package/packages/datadog-instrumentations/src/mongoose.js +3 -3
  58. package/packages/datadog-instrumentations/src/nova-sonic/audio.js +173 -0
  59. package/packages/datadog-instrumentations/src/nova-sonic/index.js +209 -0
  60. package/packages/datadog-instrumentations/src/nova-sonic/session.js +483 -0
  61. package/packages/datadog-instrumentations/src/openai-realtime/index.js +18 -6
  62. package/packages/datadog-instrumentations/src/openai-realtime/session.js +1 -1
  63. package/packages/datadog-instrumentations/src/openai.js +7 -0
  64. package/packages/datadog-instrumentations/src/pino.js +5 -6
  65. package/packages/datadog-instrumentations/src/redis.js +27 -13
  66. package/packages/datadog-instrumentations/src/router.js +30 -0
  67. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +2 -6
  68. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +7 -5
  69. package/packages/datadog-instrumentations/src/vitest-main.js +9 -15
  70. package/packages/datadog-instrumentations/src/vitest-util.js +2 -2
  71. package/packages/datadog-instrumentations/src/vitest-worker.js +1 -2
  72. package/packages/datadog-instrumentations/src/vitest.js +2 -2
  73. package/packages/datadog-instrumentations/src/webdriverio.js +5 -8
  74. package/packages/datadog-instrumentations/src/ws.js +1 -4
  75. package/packages/datadog-plugin-amqplib/src/client.js +1 -2
  76. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -5
  77. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +1 -2
  78. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -8
  79. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +18 -0
  80. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/sonic.js +45 -0
  81. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +9 -3
  82. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -5
  83. package/packages/datadog-plugin-azure-durable-functions/src/index.js +5 -4
  84. package/packages/datadog-plugin-azure-functions/src/index.js +5 -3
  85. package/packages/datadog-plugin-claude-agent-sdk/src/index.js +0 -2
  86. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +1 -5
  87. package/packages/datadog-plugin-cypress/src/index.js +6 -6
  88. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -2
  89. package/packages/datadog-plugin-cypress/src/support.js +1 -4
  90. package/packages/datadog-plugin-express/src/code_origin.js +1 -2
  91. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -2
  92. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +1 -2
  93. package/packages/datadog-plugin-graphql/src/execute.js +5 -5
  94. package/packages/datadog-plugin-grpc/src/util.js +1 -2
  95. package/packages/datadog-plugin-kafkajs/src/producer.js +1 -2
  96. package/packages/datadog-plugin-mocha/src/index.js +7 -10
  97. package/packages/datadog-plugin-mocha/src/webdriverio-video.js +8 -4
  98. package/packages/datadog-plugin-mongodb-core/src/query.js +8 -5
  99. package/packages/datadog-plugin-next/src/index.js +1 -2
  100. package/packages/datadog-plugin-openai/src/tracing.js +5 -2
  101. package/packages/datadog-plugin-openai-agents/src/integration.js +6 -2
  102. package/packages/datadog-plugin-openai-agents/src/processor.js +2 -4
  103. package/packages/datadog-plugin-postgres/src/index.js +24 -0
  104. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -5
  105. package/packages/datadog-plugin-rhea/src/consumer.js +1 -4
  106. package/packages/datadog-plugin-vitest/src/index.js +5 -2
  107. package/packages/datadog-shimmer/src/shimmer.js +5 -4
  108. package/packages/datadog-webpack/index.js +55 -43
  109. package/packages/datadog-webpack/src/loader.js +56 -8
  110. package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +2 -4
  111. package/packages/dd-trace/src/aiguard/messages/utils.js +1 -2
  112. package/packages/dd-trace/src/aiguard/redaction.js +8 -2
  113. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +3 -2
  114. package/packages/dd-trace/src/appsec/api_security/sampler.js +2 -6
  115. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -9
  116. package/packages/dd-trace/src/appsec/handlers/http-request.js +3 -9
  117. package/packages/dd-trace/src/appsec/handlers/http-response.js +7 -2
  118. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +4 -3
  119. package/packages/dd-trace/src/appsec/iast/analyzers/set-cookies-header-interceptor.js +1 -4
  120. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +7 -1
  121. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -3
  122. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +1 -3
  123. package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +1 -6
  124. package/packages/dd-trace/src/appsec/lambda.js +1 -3
  125. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +37 -27
  126. package/packages/dd-trace/src/appsec/rasp/lfi.js +9 -5
  127. package/packages/dd-trace/src/appsec/reporter.js +21 -1
  128. package/packages/dd-trace/src/appsec/stack_trace.js +1 -2
  129. package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +3 -6
  130. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +1 -1
  131. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +13 -7
  132. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +1 -2
  133. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +2 -8
  134. package/packages/dd-trace/src/ci-visibility/resolve-runfile-path.js +54 -0
  135. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +5 -8
  136. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +2 -53
  137. package/packages/dd-trace/src/config/config-types.d.ts +2 -2
  138. package/packages/dd-trace/src/config/defaults.js +5 -5
  139. package/packages/dd-trace/src/config/generated-config-types.d.ts +8 -0
  140. package/packages/dd-trace/src/config/helper.js +34 -3
  141. package/packages/dd-trace/src/config/index.js +10 -9
  142. package/packages/dd-trace/src/config/normalize-service.js +1 -1
  143. package/packages/dd-trace/src/config/parsers.js +2 -2
  144. package/packages/dd-trace/src/config/supported-configurations.json +35 -0
  145. package/packages/dd-trace/src/datastreams/processor.js +3 -2
  146. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +1 -4
  147. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -0
  148. package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -0
  149. package/packages/dd-trace/src/debugger/guardrail-metrics.js +2 -2
  150. package/packages/dd-trace/src/dogstatsd.js +1 -1
  151. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  152. package/packages/dd-trace/src/exporters/common/request.js +1 -5
  153. package/packages/dd-trace/src/id.js +14 -1
  154. package/packages/dd-trace/src/lambda/handler.js +179 -19
  155. package/packages/dd-trace/src/lambda/index.js +15 -1
  156. package/packages/dd-trace/src/lambda/runtime/patch.js +34 -7
  157. package/packages/dd-trace/src/llmobs/audio-utils.js +3 -2
  158. package/packages/dd-trace/src/llmobs/constants/tags.js +12 -0
  159. package/packages/dd-trace/src/llmobs/experiments/experiment.js +1 -1
  160. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +15 -0
  161. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +1 -2
  162. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +1 -3
  163. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  164. package/packages/dd-trace/src/llmobs/plugins/nova-sonic.js +92 -0
  165. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +56 -2
  166. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +38 -0
  167. package/packages/dd-trace/src/llmobs/prompts/manager.js +5 -7
  168. package/packages/dd-trace/src/llmobs/prompts/prompt.js +1 -1
  169. package/packages/dd-trace/src/llmobs/span_processor.js +1 -2
  170. package/packages/dd-trace/src/llmobs/tagger.js +2 -2
  171. package/packages/dd-trace/src/llmobs/util.js +1 -2
  172. package/packages/dd-trace/src/llmobs/writers/base.js +4 -5
  173. package/packages/dd-trace/src/log/log.js +1 -5
  174. package/packages/dd-trace/src/openfeature/evaluation-telemetry-opt-out-hook.js +51 -0
  175. package/packages/dd-trace/src/openfeature/flagging_provider.js +48 -21
  176. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +1 -1
  177. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  178. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -2
  179. package/packages/dd-trace/src/opentelemetry/otlp/common.proto +1 -1
  180. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +6 -23
  181. package/packages/dd-trace/src/opentracing/propagation/text_map.js +53 -13
  182. package/packages/dd-trace/src/otel-sampling.js +4 -5
  183. package/packages/dd-trace/src/otel-thread-ctx.js +79 -13
  184. package/packages/dd-trace/src/plugins/database.js +7 -16
  185. package/packages/dd-trace/src/plugins/util/git.js +9 -25
  186. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +1 -5
  187. package/packages/dd-trace/src/plugins/util/test.js +48 -4
  188. package/packages/dd-trace/src/priority_sampler.js +1 -2
  189. package/packages/dd-trace/src/profiling/profiler.js +4 -6
  190. package/packages/dd-trace/src/proxy.js +1 -2
  191. package/packages/dd-trace/src/ritm.js +4 -2
  192. package/packages/dd-trace/src/serverless.js +5 -0
  193. package/packages/dd-trace/src/span_processor.js +13 -17
  194. package/packages/dd-trace/src/telemetry/endpoints.js +1 -3
  195. package/packages/dd-trace/src/util.js +29 -0
  196. package/packages/dd-trace/src/web-tags-cache.js +6 -2
  197. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
  198. package/vendor/dist/@datadog/openfeature-node-server/rules-based/LICENSE +201 -0
  199. package/vendor/dist/@datadog/openfeature-node-server/rules-based/index.d.ts +925 -0
  200. package/vendor/dist/@datadog/openfeature-node-server/rules-based/index.js +1 -0
  201. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  202. package/vendor/dist/protobufjs/index.js +1 -1
  203. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  204. package/vendor/dist/shell-quote/index.js +1 -1
@@ -132,8 +132,7 @@ module.exports.checkForPotentialConflicts = function () {
132
132
 
133
133
  for (const pathToModule of Object.keys(require.cache)) {
134
134
  const { pkg } = extractPackageAndModulePath(pathToModule)
135
- if (naughties.has(pkg)) continue
136
- if (!potentialConflicts.has(pkg)) continue
135
+ if (naughties.has(pkg) || !potentialConflicts.has(pkg)) continue
137
136
 
138
137
  warnings.push(() => `Warning: Package '${pkg}' may cause conflicts with dd-trace.`)
139
138
 
@@ -88,7 +88,7 @@ exports.getHooks = function getHooks (names) {
88
88
  for (const { module } of rewriterInstrumentations) {
89
89
  if (!requested.has(module.name)) continue
90
90
  // Fresh objects, including the versions array: callers may adjust a hook
91
- // for their own registration (the ai, claude-agent-sdk and
91
+ // for their own registration (the ai and
92
92
  // aws-durable-execution-sdk-js plugins set `hook.file = null`), which must
93
93
  // not leak into any other call.
94
94
  const hook = { name: module.name, versions: [module.versionRange], file: module.filePath }
@@ -14,6 +14,7 @@ const {
14
14
  matchesInstrumentation,
15
15
  } = require('./instrumentation-utils')
16
16
  const rewriter = require('./rewriter')
17
+ const { getActivationSetup } = require('./rewriter/instrumentation-registry')
17
18
 
18
19
  const DD_TRACE_DEBUG = getValueFromEnvSources('DD_TRACE_DEBUG')
19
20
 
@@ -58,6 +59,39 @@ const instrumentedIntegrationsSuccess = new Map()
58
59
  const alreadyLoggedIncompatibleIntegrations = new Set()
59
60
  /** @type {Set<string>} */
60
61
  const compatibleOrchestrionTargets = new Set()
62
+ /** @type {Set<(activation: import('./rewriter/instrumentation-registry').Activation) => void>} */
63
+ const blockedActivationSetups = new Set()
64
+
65
+ /**
66
+ * @param {string} moduleName
67
+ * @param {string} [version]
68
+ */
69
+ function activate (moduleName, version) {
70
+ const setup = getActivationSetup(moduleName)
71
+ if (setup) {
72
+ if (blockedActivationSetups.has(setup)) return
73
+ // Block re-entrant activation until setup completes, and never retry a failed setup.
74
+ blockedActivationSetups.add(setup)
75
+ try {
76
+ setup({ moduleName, version })
77
+ blockedActivationSetups.delete(setup)
78
+ } catch (error) {
79
+ const message = String(error?.message ?? error)
80
+ log.error('Error during activation setup of %s: %s', moduleName, message, error)
81
+ telemetry('error', [
82
+ `error_type:${error?.constructor?.name ?? typeof error}`,
83
+ `integration:${moduleName}`,
84
+ `integration_version:${version ?? 'unknown'}`,
85
+ ], {
86
+ result: 'error',
87
+ result_class: 'internal_error',
88
+ result_reason: `Error during activation of ${moduleName}: ${message}`,
89
+ })
90
+ return
91
+ }
92
+ }
93
+ loadChannel.publish({ name: moduleName })
94
+ }
61
95
 
62
96
  orchestrionLoadChannel.subscribe(({ moduleName, version, result }) => {
63
97
  const nameVersion = `${moduleName}@${version}`
@@ -72,7 +106,7 @@ orchestrionLoadChannel.subscribe(({ moduleName, version, result }) => {
72
106
  if (result === 'matched' || result === 'rewritten') {
73
107
  compatibleOrchestrionTargets.add(nameVersion)
74
108
  instrumentedIntegrationsSuccess.set(nameVersion, true)
75
- if (result === 'rewritten') loadChannel.publish({ name: moduleName })
109
+ if (result === 'rewritten') activate(moduleName, version)
76
110
  }
77
111
  })
78
112
 
@@ -176,6 +210,7 @@ function logAbortedIntegrations () {
176
210
  }
177
211
 
178
212
  module.exports = {
213
+ activate,
179
214
  filename,
180
215
  pathSepExpr,
181
216
  loadChannel,
@@ -188,6 +188,7 @@ function createMatcher (dcModule) {
188
188
  waitForAsyncEnd,
189
189
  } = require('./transforms')
190
190
  const {
191
+ postgresQueryAcquire,
191
192
  postgresQueryHandlers,
192
193
  postgresQueryLifecycle,
193
194
  postgresQueryPreparation,
@@ -204,6 +205,7 @@ function createMatcher (dcModule) {
204
205
  matcher.addTransform('configureGraphqlJitRuntime', configureGraphqlJitRuntime)
205
206
  matcher.addTransform('configureMercuriusRequest', configureMercuriusRequest)
206
207
  matcher.addTransform('publishDurableOrchestrationFailure', publishDurableOrchestrationFailure)
208
+ matcher.addTransform('postgresQueryAcquire', postgresQueryAcquire)
207
209
  matcher.addTransform('postgresQueryHandlers', postgresQueryHandlers)
208
210
  matcher.addTransform('postgresQueryLifecycle', postgresQueryLifecycle)
209
211
  matcher.addTransform('postgresQueryPreparation', postgresQueryPreparation)
@@ -1,14 +1,35 @@
1
1
  'use strict'
2
2
 
3
3
  // Activated rewrites publish their module name to the plugin manager after evaluation.
4
- // Only pure Orchestrion integrations that need this activation set activate: true.
4
+ // Integrations can also provide synchronous runtime setup before plugin activation.
5
+ // Setup must not load rewrite targets: re-entrant activations of the same group are dropped.
6
+ // activate: true covers every rewrite target in the entry; activate.modules narrows it to the packages
7
+ // that should trigger activation, leaving the rest of the entry rewrite-only.
5
8
  // Other entries use hooks or another activation path, or do not need activation from a rewrite.
9
+ /**
10
+ * @typedef {object} Activation
11
+ * @property {string} moduleName
12
+ * @property {string} [version]
13
+ *
14
+ * @typedef {object} ActivationConfig
15
+ * @property {string[]} [modules]
16
+ * @property {((activation: Activation) => void)} [setup]
17
+ *
18
+ * @typedef {object} InstrumentationRegistryEntry
19
+ * @property {true|ActivationConfig} [activate]
20
+ * @property {Array<{ module: { name: string } }>} instrumentations
21
+ */
22
+
23
+ /** @satisfies {InstrumentationRegistryEntry[]} */
6
24
  const registry = [
7
25
  { instrumentations: require('./instrumentations/ai') },
8
26
  { activate: true, instrumentations: require('./instrumentations/azure-cosmos') },
9
27
  { instrumentations: require('./instrumentations/azure-durable-functions') },
10
28
  { activate: true, instrumentations: require('./instrumentations/bullmq') },
11
- { instrumentations: require('./instrumentations/claude-agent-sdk') },
29
+ {
30
+ activate: { setup: () => require('../../claude-agent-sdk') },
31
+ instrumentations: require('./instrumentations/claude-agent-sdk'),
32
+ },
12
33
  { instrumentations: require('./instrumentations/graphql') },
13
34
  { instrumentations: require('./instrumentations/graphql-jit') },
14
35
  { activate: true, instrumentations: require('./instrumentations/langchain') },
@@ -19,14 +40,66 @@ const registry = [
19
40
  { instrumentations: require('./instrumentations/playwright') },
20
41
  { activate: true, instrumentations: require('./instrumentations/postgres') },
21
42
  { instrumentations: require('./instrumentations/webdriverio') },
22
- { instrumentations: require('./instrumentations/aws-durable-execution-sdk-js') },
43
+ {
44
+ activate: { setup: () => require('../../aws-durable-execution-sdk-js') },
45
+ instrumentations: require('./instrumentations/aws-durable-execution-sdk-js'),
46
+ },
23
47
  { activate: true, instrumentations: require('./instrumentations/supabase') },
24
48
  ]
25
49
 
26
50
  const activatedModules = new Set()
51
+ /** @type {Map<string, (activation: Activation) => void>} */
52
+ const activationSetups = new Map()
27
53
  for (const { activate, instrumentations } of registry) {
28
- if (!activate) continue
29
- for (const { module } of instrumentations) activatedModules.add(module.name)
54
+ if (activate === undefined) continue
55
+ if (activate !== true && (typeof activate !== 'object' || activate === null || Array.isArray(activate))) {
56
+ throw new TypeError('Instrumentation registry activate must be true or an activation config object')
57
+ }
58
+ const config = activate === true ? undefined : activate
59
+ const setup = config?.setup
60
+ if (setup !== undefined && typeof setup !== 'function') {
61
+ throw new TypeError('Instrumentation registry activate.setup must be a function')
62
+ }
63
+
64
+ const rewriteModules = new Set(instrumentations.map(({ module }) => module.name))
65
+ for (const moduleName of resolveActivationModules(config?.modules, rewriteModules)) {
66
+ if (activatedModules.has(moduleName) && activationSetups.get(moduleName) !== setup) {
67
+ throw new TypeError(`Instrumentation registry activation module "${moduleName}" has conflicting setup functions`)
68
+ }
69
+ activatedModules.add(moduleName)
70
+ if (setup) activationSetups.set(moduleName, setup)
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Activation covers every rewrite target in the entry unless it names the packages to activate. An explicit
76
+ * list keeps helper packages that share the entry rewrite-only.
77
+ * @param {string[]|undefined} modules
78
+ * @param {Set<string>} rewriteModules
79
+ * @returns {Set<string>}
80
+ */
81
+ function resolveActivationModules (modules, rewriteModules) {
82
+ if (modules === undefined) return rewriteModules
83
+ if (!Array.isArray(modules) || modules.length === 0) {
84
+ throw new TypeError('Instrumentation registry activate.modules must be a non-empty array')
85
+ }
86
+
87
+ const entryModules = new Set()
88
+ for (const moduleName of modules) {
89
+ if (typeof moduleName !== 'string' || moduleName.length === 0) {
90
+ throw new TypeError('Instrumentation registry activate.modules must contain non-empty strings')
91
+ }
92
+ if (!rewriteModules.has(moduleName)) {
93
+ throw new TypeError(
94
+ `Instrumentation registry activation module "${moduleName}" is not a rewrite target in its entry`
95
+ )
96
+ }
97
+ if (entryModules.has(moduleName)) {
98
+ throw new TypeError(`Instrumentation registry activation module "${moduleName}" is duplicated in its entry`)
99
+ }
100
+ entryModules.add(moduleName)
101
+ }
102
+ return entryModules
30
103
  }
31
104
 
32
105
  const instrumentations = registry.flatMap(entry => entry.instrumentations)
@@ -38,4 +111,12 @@ function isRewriteActivationEnabled (moduleName) {
38
111
  return activatedModules.has(moduleName)
39
112
  }
40
113
 
41
- module.exports = { isRewriteActivationEnabled, instrumentations, registry }
114
+ /**
115
+ * @param {string} moduleName
116
+ * @returns {((activation: Activation) => void)|undefined}
117
+ */
118
+ function getActivationSetup (moduleName) {
119
+ return activationSetups.get(moduleName)
120
+ }
121
+
122
+ module.exports = { getActivationSetup, isRewriteActivationEnabled, instrumentations, registry }
@@ -26,11 +26,10 @@ const COMPILE_DEFERRED_FIELD = 'FunctionDeclaration[id.name="compileDeferredFiel
26
26
  */
27
27
 
28
28
  /**
29
- * @param {GraphqlJitInstrumentation[]} instrumentations
30
29
  * @param {string} versionRange
31
30
  * @param {string} filePath
32
31
  */
33
- function addInstrumentations (instrumentations, versionRange, filePath) {
32
+ function addInstrumentations (versionRange, filePath) {
34
33
  const moduleDefinition = { name: 'graphql-jit', versionRange, filePath }
35
34
  instrumentations.push(
36
35
  {
@@ -75,9 +74,9 @@ function addInstrumentations (instrumentations, versionRange, filePath) {
75
74
  const instrumentations = []
76
75
  // graphql-jit 0.7 and 0.8.0 use this layout and remain compatible with GraphQL 15 and 16.
77
76
  // GraphQL 17 compatibility starts at 0.8.1.
78
- addInstrumentations(instrumentations, '>=0.7.0 <0.8.5 || >=0.8.7 <0.9.0', 'dist/execution.js')
79
- addInstrumentations(instrumentations, '>=0.8.5 <0.8.7', 'dist/cjs/execution.js')
80
- addInstrumentations(instrumentations, '>=0.8.5 <0.8.7', 'dist/esm/execution.js')
81
- addInstrumentations(instrumentations, '>=0.8.7 <0.9.0', 'dist/execution.mjs')
77
+ addInstrumentations('>=0.7.0 <0.8.5 || >=0.8.7 <0.9.0', 'dist/execution.js')
78
+ addInstrumentations('>=0.8.5 <0.8.7', 'dist/cjs/execution.js')
79
+ addInstrumentations('>=0.8.5 <0.8.7', 'dist/esm/execution.js')
80
+ addInstrumentations('>=0.8.7 <0.9.0', 'dist/execution.mjs')
82
81
 
83
82
  module.exports = instrumentations
@@ -1,36 +1,53 @@
1
1
  'use strict'
2
2
 
3
- const handlers = ['src/index.js', 'cjs/src/index.js'].map(filePath => ({
4
- module: {
5
- name: 'postgres',
6
- versionRange: '>=3.0.0',
7
- filePath,
8
- },
9
- astQuery: 'Program',
10
- transform: 'postgresQueryHandlers',
11
- channelName: 'query',
12
- }))
3
+ const instrumentations = []
13
4
 
14
- const preparations = ['src/connection.js', 'cjs/src/connection.js'].map(filePath => ({
15
- module: {
16
- name: 'postgres',
17
- versionRange: '>=3.0.0',
18
- filePath,
19
- },
20
- astQuery: 'Program',
21
- transform: 'postgresQueryPreparation',
22
- channelName: 'query:prepare',
23
- }))
5
+ for (const filePath of ['src/index.js', 'cjs/src/index.js']) {
6
+ instrumentations.push({
7
+ module: {
8
+ name: 'postgres',
9
+ versionRange: '>=3.0.0',
10
+ filePath,
11
+ },
12
+ astQuery: 'Program',
13
+ transform: 'postgresQueryHandlers',
14
+ channelName: 'query',
15
+ })
16
+ }
24
17
 
25
- const lifecycles = ['src/query.js', 'cjs/src/query.js'].map(filePath => ({
26
- module: {
27
- name: 'postgres',
28
- versionRange: '>=3.0.0',
29
- filePath,
30
- },
31
- astQuery: 'Program',
32
- transform: 'postgresQueryLifecycle',
33
- channelName: 'query',
34
- }))
18
+ for (const filePath of ['src/connection.js', 'cjs/src/connection.js']) {
19
+ instrumentations.push({
20
+ module: {
21
+ name: 'postgres',
22
+ versionRange: '>=3.0.0',
23
+ filePath,
24
+ },
25
+ astQuery: 'Program',
26
+ transform: 'postgresQueryAcquire',
27
+ channelName: 'query:acquire',
28
+ }, {
29
+ module: {
30
+ name: 'postgres',
31
+ versionRange: '>=3.0.0',
32
+ filePath,
33
+ },
34
+ astQuery: 'Program',
35
+ transform: 'postgresQueryPreparation',
36
+ channelName: 'query:prepare',
37
+ })
38
+ }
35
39
 
36
- module.exports = [...handlers, ...preparations, ...lifecycles]
40
+ for (const filePath of ['src/query.js', 'cjs/src/query.js']) {
41
+ instrumentations.push({
42
+ module: {
43
+ name: 'postgres',
44
+ versionRange: '>=3.0.0',
45
+ filePath,
46
+ },
47
+ astQuery: 'Program',
48
+ transform: 'postgresQueryLifecycle',
49
+ channelName: 'query',
50
+ })
51
+ }
52
+
53
+ module.exports = instrumentations
@@ -506,9 +506,8 @@ module.exports = [
506
506
  versionRange: '>=9.0.0',
507
507
  filePath: 'build/index.js',
508
508
  },
509
- astQuery: 'TryStatement:has(CatchClause IfStatement[test.operator=">"]' +
510
- '[test.left.object.name="retries"][test.left.property.name="limit"]' +
511
- '[test.right.object.name="retries"][test.right.property.name="attempts"]) > BlockStatement',
509
+ astQuery: 'FunctionDeclaration[id.name="executeAsync"] TryStatement:has(CatchClause ' +
510
+ 'CallExpression[callee.object.name="executeAsync"][callee.property.name="call"]) > BlockStatement',
512
511
  channelName: 'executeAsync',
513
512
  transform: 'awaitContextCallback',
514
513
  transformOptions: {
@@ -521,10 +520,8 @@ module.exports = [
521
520
  versionRange: '>=9.0.0',
522
521
  filePath: 'build/index.js',
523
522
  },
524
- astQuery: 'FunctionDeclaration[id.name="executeAsync"] CatchClause ' +
525
- 'IfStatement[test.operator=">"][test.left.object.name="retries"]' +
526
- '[test.left.property.name="limit"][test.right.object.name="retries"]' +
527
- '[test.right.property.name="attempts"]',
523
+ astQuery: 'FunctionDeclaration[id.name="executeAsync"] CatchClause > BlockStatement > ' +
524
+ 'IfStatement:has(CallExpression[callee.object.name="executeAsync"][callee.property.name="call"])',
528
525
  channelName: 'executeAsync',
529
526
  transform: 'awaitContextCallback',
530
527
  transformOptions: {
@@ -540,7 +537,10 @@ module.exports = [
540
537
  },
541
538
  astQuery: 'AssignmentExpression[left.object.object.name="Spec"]' +
542
539
  '[left.object.property.name="prototype"][left.property.name="execute"] > FunctionExpression',
540
+ // A method name keeps the original function expression, so the start context
541
+ // carries `self` (the legacy Spec) that the WebdriverIO Jasmine lifecycle reads.
543
542
  functionQuery: {
543
+ methodName: 'execute',
544
544
  kind: 'Sync',
545
545
  },
546
546
  channelName: 'Spec_execute',
@@ -12,11 +12,37 @@ const POSTGRES_SIMPLE_DBM_QUERIES = '__ddTracePostgresSimpleDbmQueries'
12
12
  const POSTGRES_STATEMENT = 'this.string ?? (this.tagged && this.strings?.length !== 1 ? undefined : this.strings?.[0])'
13
13
 
14
14
  module.exports = {
15
+ postgresQueryAcquire,
15
16
  postgresQueryHandlers,
16
17
  postgresQueryLifecycle,
17
18
  postgresQueryPreparation,
18
19
  }
19
20
 
21
+ /**
22
+ * @param {object} state
23
+ * @param {import('estree').Program} program
24
+ */
25
+ function postgresQueryAcquire (state, program) {
26
+ const channelVariable = injectPostgresTracingChannel(state, program)
27
+ const executeFunctions = query(program, 'FunctionDeclaration[id.name="execute"]')
28
+ assert(executeFunctions.length === 1, 'postgresQueryAcquire: unexpected execute function count')
29
+
30
+ const execute = executeFunctions[0]
31
+ const queryParameter = execute.params[0]
32
+ assert(queryParameter?.type === 'Identifier', 'postgresQueryAcquire: execute query parameter changed')
33
+ assert(execute.body.type === 'BlockStatement', 'postgresQueryAcquire: execute body changed')
34
+
35
+ const body = execute.body.body
36
+ const executeIndex = body.findIndex(statement => statement.type === 'TryStatement')
37
+ assert(executeIndex !== -1, 'postgresQueryAcquire: execute try block changed')
38
+
39
+ body.splice(executeIndex, 0, ...parse(`
40
+ if (${channelVariable}.start.hasSubscribers) {
41
+ ${channelVariable}.start.publish({ query: ${queryParameter.name} });
42
+ }
43
+ `).body)
44
+ }
45
+
20
46
  /**
21
47
  * Starts a Postgres.js query at the pool handler that owns its connection options.
22
48
  *
@@ -154,6 +180,7 @@ function wrapPostgresHandler (handler, queryParameter, channelVariable) {
154
180
  assert(handler.body.type === 'BlockStatement', 'postgresQueryHandlers: handler body changed')
155
181
  assert(!handler.async && !handler.generator, 'postgresQueryHandlers: unsupported handler kind')
156
182
 
183
+ // Direct handoffs publish before the handler returns, so they record zero pool wait.
157
184
  const originalBody = handler.body.body
158
185
  const wrapperBody = parse(`
159
186
  function wrapper () {
@@ -167,12 +194,18 @@ function wrapPostgresHandler (handler, queryParameter, channelVariable) {
167
194
  __ddTraceContext.host = ${POSTGRES_OPTIONS}.host[0];
168
195
  __ddTraceContext.port = ${POSTGRES_OPTIONS}.port[0];
169
196
  }
170
- return ${channelVariable}.start.runStores(__ddTraceContext, () => {});
197
+ const __ddTraceResult = ${channelVariable}.start.runStores(__ddTraceContext, () => {});
198
+ if (!__ddTraceContext.poolWaitFinished) {
199
+ __ddTraceContext.poolWaitStartMs = performance.now();
200
+ }
201
+ return __ddTraceResult;
171
202
  }
172
203
  }
173
204
  `).body[0].body.body
174
205
 
175
- wrapperBody[0].consequent.body.at(-1).argument.arguments[1].body.body = originalBody
206
+ const tracingCalls = query(wrapperBody[0], 'CallExpression[callee.property.name="runStores"]')
207
+ assert(tracingCalls.length === 1, 'postgresQueryHandlers: runStores call changed')
208
+ tracingCalls[0].arguments[1].body.body = originalBody
176
209
  handler.body.body = [...wrapperBody, ...originalBody]
177
210
  }
178
211
 
@@ -272,8 +305,13 @@ function findPostgresQueryIdentifier (program) {
272
305
 
273
306
  const declarations = query(program, 'VariableDeclarator[id.type="ObjectPattern"]')
274
307
  for (const declaration of declarations) {
275
- if (declaration.init?.type !== 'CallExpression' || declaration.init.callee.name !== 'require') continue
276
- if (declaration.init.arguments[0]?.value !== './query.js') continue
308
+ if (
309
+ declaration.init?.type !== 'CallExpression' ||
310
+ declaration.init.callee.name !== 'require' ||
311
+ declaration.init.arguments[0]?.value !== './query.js'
312
+ ) {
313
+ continue
314
+ }
277
315
 
278
316
  for (const property of declaration.id.properties) {
279
317
  if (property.type === 'Property' && property.key.name === 'Query' && property.value.type === 'Identifier') {
@@ -140,8 +140,7 @@ function awaitContextCallback (state, node, _parent, ancestry) {
140
140
  const generatedCallback = createAwaitedContextCallback(
141
141
  state,
142
142
  insertionTarget,
143
- callbackAncestry,
144
- 'awaitContextCallback'
143
+ callbackAncestry
145
144
  )
146
145
  if (!generatedCallback) return
147
146
 
@@ -158,8 +157,7 @@ function awaitContextCallback (state, node, _parent, ancestry) {
158
157
  const generatedCallback = createAwaitedContextCallback(
159
158
  state,
160
159
  node.consequent,
161
- ancestry,
162
- 'awaitContextCallback'
160
+ ancestry
163
161
  )
164
162
  if (!generatedCallback) return
165
163
 
@@ -181,18 +179,17 @@ function awaitContextCallback (state, node, _parent, ancestry) {
181
179
  * @param {Parameters<typeof awaitContextCallback>[0]} state
182
180
  * @param {import('estree').BlockStatement} insertionTarget
183
181
  * @param {import('estree').Node[]} ancestry
184
- * @param {string} transformName
185
182
  * @returns {{
186
183
  * callbackStatements: import('estree').Statement[],
187
184
  * callbackVariable: string
188
185
  * }|undefined}
189
186
  */
190
- function createAwaitedContextCallback (state, insertionTarget, ancestry, transformName) {
187
+ function createAwaitedContextCallback (state, insertionTarget, ancestry) {
191
188
  const { callbackArgumentNames = [], callbackName, callbackThis = false } = state.transformOptions ?? {}
192
189
 
193
- assert(identifierPattern.test(callbackName), `${transformName}: callbackName must be an identifier`)
190
+ assert(identifierPattern.test(callbackName), 'awaitContextCallback: callbackName must be an identifier')
194
191
  assert(Array.isArray(callbackArgumentNames) && callbackArgumentNames.every(name => identifierPattern.test(name)),
195
- `${transformName}: callbackArgumentNames must be identifiers`)
192
+ 'awaitContextCallback: callbackArgumentNames must be identifiers')
196
193
 
197
194
  let enclosingFunction
198
195
  let hasTraceWrapper = false
@@ -215,8 +212,8 @@ function createAwaitedContextCallback (state, insertionTarget, ancestry, transfo
215
212
  hasTraceWrapper ||= hasContextBinding && hasTracedBinding
216
213
  }
217
214
 
218
- assert(enclosingFunction?.async, `${transformName}: expected an enclosing async function`)
219
- assert(hasTraceWrapper, `${transformName}: expected an enclosing trace wrapper`)
215
+ assert(enclosingFunction?.async, 'awaitContextCallback: expected an enclosing async function')
216
+ assert(hasTraceWrapper, 'awaitContextCallback: expected an enclosing trace wrapper')
220
217
 
221
218
  const callbackVariable = `__apm$${callbackName}`
222
219
  if (query(insertionTarget, `[id.name="${callbackVariable}"]`).length > 0) return
@@ -14,9 +14,7 @@ const connectionOptionsCache = new WeakMap()
14
14
 
15
15
  function wrapRedis (Redis) {
16
16
  shimmer.wrap(Redis.prototype, 'sendCommand', sendCommand => function (command, stream) {
17
- if (!startCh.hasSubscribers) return sendCommand.call(this, command, stream)
18
-
19
- if (!command?.promise) return sendCommand.call(this, command, stream)
17
+ if (!startCh.hasSubscribers || !command?.promise) return sendCommand.call(this, command, stream)
20
18
 
21
19
  const options = this.options || {}
22
20
  let connectionOptions = connectionOptionsCache.get(this)
@@ -32,7 +30,7 @@ function wrapRedis (Redis) {
32
30
  connectionName: options.connectionName,
33
31
  }
34
32
  return startCh.runStores(ctx, () => {
35
- command.promise.then(() => finish(finishCh, errorCh, ctx), err => finish(finishCh, errorCh, ctx, err))
33
+ command.promise.then(() => finish(ctx), err => finish(ctx, err))
36
34
 
37
35
  return sendCommand.call(this, command, stream)
38
36
  })
@@ -51,7 +49,11 @@ addHook({ name: 'ioredis', versions: ['>=4.11.0 <5'], file: 'built/redis/index.j
51
49
 
52
50
  addHook({ name: 'ioredis', versions: ['>=5'] }, wrapRedis)
53
51
 
54
- function finish (finishCh, errorCh, ctx, error) {
52
+ /**
53
+ * @param {Record<string, unknown> & { error?: Error }} ctx
54
+ * @param {Error} [error]
55
+ */
56
+ function finish (ctx, error) {
55
57
  if (error) {
56
58
  ctx.error = error
57
59
  errorCh.publish(ctx)
@@ -12,9 +12,7 @@ const errorCh = channel('apm:iovalkey:command:error')
12
12
 
13
13
  addHook({ name: 'iovalkey', versions: ['>=0.0.1'] }, Valkey => {
14
14
  shimmer.wrap(Valkey.prototype, 'sendCommand', sendCommand => function (command, stream) {
15
- if (!startCh.hasSubscribers) return sendCommand.apply(this, arguments)
16
-
17
- if (!command?.promise) return sendCommand.apply(this, arguments)
15
+ if (!startCh.hasSubscribers || !command?.promise) return sendCommand.apply(this, arguments)
18
16
 
19
17
  const options = this.options || {}
20
18
  const connectionName = options.connectionName
@@ -22,7 +20,7 @@ addHook({ name: 'iovalkey', versions: ['>=0.0.1'] }, Valkey => {
22
20
 
23
21
  const ctx = { command: command.name, args: command.args, connectionOptions, connectionName }
24
22
  return startCh.runStores(ctx, () => {
25
- command.promise.then(() => finish(finishCh, errorCh, ctx), err => finish(finishCh, errorCh, ctx, err))
23
+ command.promise.then(() => finish(ctx), err => finish(ctx, err))
26
24
 
27
25
  try {
28
26
  return sendCommand.apply(this, arguments)
@@ -37,7 +35,11 @@ addHook({ name: 'iovalkey', versions: ['>=0.0.1'] }, Valkey => {
37
35
  return Valkey
38
36
  })
39
37
 
40
- function finish (finishCh, errorCh, ctx, error) {
38
+ /**
39
+ * @param {Record<string, unknown> & { error?: Error }} ctx
40
+ * @param {Error} [error]
41
+ */
42
+ function finish (ctx, error) {
41
43
  if (error) {
42
44
  ctx.error = error
43
45
  errorCh.publish(ctx)
@@ -891,8 +891,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
891
891
  */
892
892
  wrapConcurrentTestFunction (target, methodName, state) {
893
893
  let concurrentTest = target?.[methodName]
894
- if (typeof concurrentTest !== 'function') return
895
- if (this.wrappedConcurrentTestFunctions.has(concurrentTest)) return
894
+ if (typeof concurrentTest !== 'function' || this.wrappedConcurrentTestFunctions.has(concurrentTest)) return
896
895
 
897
896
  const originalConcurrentTest = getOriginalConcurrentTest(concurrentTest)
898
897
  if (originalConcurrentTest !== concurrentTest) {
@@ -2675,10 +2674,7 @@ function getTestEnvironment (pkg, jestVersion) {
2675
2674
  const wrappedTestEnvironment = getWrappedEnvironment(pkg.default, jestVersion)
2676
2675
  return new Proxy(pkg, {
2677
2676
  get (target, prop) {
2678
- if (prop === 'default') {
2679
- return wrappedTestEnvironment
2680
- }
2681
- if (prop === 'TestEnvironment') {
2677
+ if (prop === 'default' || prop === 'TestEnvironment') {
2682
2678
  return wrappedTestEnvironment
2683
2679
  }
2684
2680
  return target[prop]
@@ -4495,10 +4491,7 @@ function sendWrapper (send) {
4495
4491
  // In here we modify the `config.testEnvironmentOptions` to include the known tests for the suite.
4496
4492
  // This way the suite only knows about the tests that are part of it.
4497
4493
  const args = request.at(-1)
4498
- if (args.length > 1) {
4499
- return send.apply(this, arguments)
4500
- }
4501
- if (!args[0]?.config) {
4494
+ if (args.length > 1 || !args[0]?.config) {
4502
4495
  return send.apply(this, arguments)
4503
4496
  }
4504
4497
  const [{ globalConfig, config, path: testSuiteAbsolutePath }] = args
@@ -62,13 +62,13 @@ addHook({
62
62
  const rawResult = raw.apply(this, args)
63
63
  shimmer.wrap(rawResult, 'then', originalThen => function (...args) {
64
64
  return rawQuerySubscribes.runStores(context, () => {
65
- args[0] = wrapCallbackWithFinish(args[0], finish, context)
66
- if (args[1]) args[1] = wrapCallbackWithFinish(args[1], finish, context)
65
+ args[0] = wrapCallbackWithFinish(args[0], context)
66
+ if (args[1]) args[1] = wrapCallbackWithFinish(args[1], context)
67
67
 
68
68
  const originalThenResult = originalThen.apply(this, args)
69
69
 
70
70
  shimmer.wrap(originalThenResult, 'catch', originalCatch => function (...args) {
71
- args[0] = wrapCallbackWithFinish(args[0], finish, context)
71
+ args[0] = wrapCallbackWithFinish(args[0], context)
72
72
  return originalCatch.apply(this, args)
73
73
  })
74
74
 
@@ -78,7 +78,7 @@ addHook({
78
78
 
79
79
  shimmer.wrap(rawResult, 'asCallback', originalAsCallback => function (...args) {
80
80
  return rawQuerySubscribes.runStores(context, () => {
81
- args[0] = wrapCallbackWithFinish(args[0], finish, context)
81
+ args[0] = wrapCallbackWithFinish(args[0], context)
82
82
  return originalAsCallback.apply(this, args)
83
83
  })
84
84
  })
@@ -118,7 +118,11 @@ addHook({
118
118
  return Transaction
119
119
  })
120
120
 
121
- function wrapCallbackWithFinish (callback, finish, context) {
121
+ /**
122
+ * @param {unknown} callback
123
+ * @param {object} context
124
+ */
125
+ function wrapCallbackWithFinish (callback, context) {
122
126
  if (typeof callback !== 'function') return callback
123
127
 
124
128
  return shimmer.wrapFunction(callback, callback => function (...args) {