dd-trace 5.102.0 → 5.103.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 (133) hide show
  1. package/ext/exporters.js +1 -0
  2. package/package.json +12 -11
  3. package/packages/datadog-esbuild/src/utils.js +2 -2
  4. package/packages/datadog-instrumentations/src/ai.js +1 -1
  5. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +32 -15
  6. package/packages/datadog-instrumentations/src/couchbase.js +69 -220
  7. package/packages/datadog-instrumentations/src/cucumber.js +1 -1
  8. package/packages/datadog-instrumentations/src/electron/preload.js +42 -0
  9. package/packages/datadog-instrumentations/src/electron.js +240 -0
  10. package/packages/datadog-instrumentations/src/fetch.js +5 -5
  11. package/packages/datadog-instrumentations/src/graphql.js +13 -12
  12. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
  13. package/packages/datadog-instrumentations/src/helpers/hook.js +4 -1
  14. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  15. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
  16. package/packages/datadog-instrumentations/src/helpers/kafka.js +41 -0
  17. package/packages/datadog-instrumentations/src/ioredis.js +16 -12
  18. package/packages/datadog-instrumentations/src/jest.js +351 -50
  19. package/packages/datadog-instrumentations/src/kafkajs.js +164 -173
  20. package/packages/datadog-instrumentations/src/mocha/main.js +73 -1
  21. package/packages/datadog-instrumentations/src/mongodb-core.js +33 -8
  22. package/packages/datadog-instrumentations/src/pg.js +24 -10
  23. package/packages/datadog-instrumentations/src/playwright.js +427 -55
  24. package/packages/datadog-instrumentations/src/redis.js +19 -10
  25. package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -21
  26. package/packages/datadog-plugin-aws-sdk/src/base.js +18 -24
  27. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +1 -1
  28. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -1
  29. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
  30. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
  31. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -1
  32. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
  33. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -2
  34. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
  35. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +1 -1
  36. package/packages/datadog-plugin-couchbase/src/index.js +58 -52
  37. package/packages/datadog-plugin-cucumber/src/index.js +1 -0
  38. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +214 -22
  39. package/packages/datadog-plugin-cypress/src/support.js +13 -1
  40. package/packages/datadog-plugin-electron/src/index.js +17 -0
  41. package/packages/datadog-plugin-electron/src/ipc.js +143 -0
  42. package/packages/datadog-plugin-electron/src/net.js +82 -0
  43. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +27 -18
  44. package/packages/datadog-plugin-graphql/src/execute.js +6 -28
  45. package/packages/datadog-plugin-graphql/src/resolve.js +30 -35
  46. package/packages/datadog-plugin-graphql/src/tools/signature.js +32 -7
  47. package/packages/datadog-plugin-graphql/src/tools/transforms.js +118 -100
  48. package/packages/datadog-plugin-graphql/src/utils.js +29 -0
  49. package/packages/datadog-plugin-grpc/src/client.js +6 -7
  50. package/packages/datadog-plugin-grpc/src/util.js +57 -22
  51. package/packages/datadog-plugin-http/src/client.js +2 -2
  52. package/packages/datadog-plugin-jest/src/index.js +92 -50
  53. package/packages/datadog-plugin-mocha/src/index.js +1 -0
  54. package/packages/datadog-plugin-mongodb-core/src/index.js +36 -70
  55. package/packages/datadog-plugin-mysql/src/index.js +1 -1
  56. package/packages/datadog-plugin-openai/src/services.js +2 -1
  57. package/packages/datadog-plugin-pg/src/index.js +3 -3
  58. package/packages/datadog-plugin-playwright/src/index.js +4 -0
  59. package/packages/datadog-plugin-redis/src/index.js +18 -23
  60. package/packages/dd-trace/src/aiguard/index.js +3 -1
  61. package/packages/dd-trace/src/aiguard/sdk.js +36 -30
  62. package/packages/dd-trace/src/aiguard/tags.js +20 -11
  63. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -2
  64. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -1
  65. package/packages/dd-trace/src/azure_metadata.js +17 -6
  66. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +4 -4
  67. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
  68. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +6 -4
  69. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +1 -1
  70. package/packages/dd-trace/src/config/defaults.js +3 -14
  71. package/packages/dd-trace/src/config/generated-config-types.d.ts +3 -1
  72. package/packages/dd-trace/src/config/helper.js +4 -0
  73. package/packages/dd-trace/src/config/index.js +2 -2
  74. package/packages/dd-trace/src/config/major-overrides.js +98 -0
  75. package/packages/dd-trace/src/config/parsers.js +7 -1
  76. package/packages/dd-trace/src/config/supported-configurations.json +51 -38
  77. package/packages/dd-trace/src/datastreams/checkpointer.js +2 -2
  78. package/packages/dd-trace/src/datastreams/manager.js +1 -1
  79. package/packages/dd-trace/src/datastreams/processor.js +2 -2
  80. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +2 -2
  81. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +1 -1
  82. package/packages/dd-trace/src/debugger/devtools_client/state.js +2 -1
  83. package/packages/dd-trace/src/debugger/index.js +7 -7
  84. package/packages/dd-trace/src/dogstatsd.js +2 -2
  85. package/packages/dd-trace/src/encode/0.4.js +45 -54
  86. package/packages/dd-trace/src/encode/0.5.js +34 -3
  87. package/packages/dd-trace/src/encode/agentless-json.js +1 -1
  88. package/packages/dd-trace/src/exporter.js +2 -0
  89. package/packages/dd-trace/src/exporters/agent/index.js +2 -1
  90. package/packages/dd-trace/src/exporters/agentless/index.js +3 -2
  91. package/packages/dd-trace/src/exporters/agentless/writer.js +2 -2
  92. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -1
  93. package/packages/dd-trace/src/exporters/common/request.js +1 -1
  94. package/packages/dd-trace/src/exporters/electron/index.js +49 -0
  95. package/packages/dd-trace/src/external-logger/src/index.js +2 -1
  96. package/packages/dd-trace/src/git_metadata.js +10 -8
  97. package/packages/dd-trace/src/lambda/handler-paths.js +52 -0
  98. package/packages/dd-trace/src/lambda/index.js +62 -14
  99. package/packages/dd-trace/src/lambda/runtime/patch.js +21 -46
  100. package/packages/dd-trace/src/llmobs/index.js +13 -2
  101. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +45 -15
  102. package/packages/dd-trace/src/llmobs/writers/base.js +2 -1
  103. package/packages/dd-trace/src/openfeature/writers/base.js +2 -1
  104. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
  105. package/packages/dd-trace/src/opentracing/propagation/text_map.js +20 -9
  106. package/packages/dd-trace/src/payload-tagging/config/index.js +2 -2
  107. package/packages/dd-trace/src/plugins/ci_plugin.js +49 -4
  108. package/packages/dd-trace/src/plugins/database.js +54 -12
  109. package/packages/dd-trace/src/plugins/index.js +1 -0
  110. package/packages/dd-trace/src/plugins/plugin.js +2 -4
  111. package/packages/dd-trace/src/plugins/util/ci.js +8 -8
  112. package/packages/dd-trace/src/plugins/util/git-cache.js +20 -18
  113. package/packages/dd-trace/src/plugins/util/stacktrace.js +2 -2
  114. package/packages/dd-trace/src/plugins/util/test.js +37 -5
  115. package/packages/dd-trace/src/plugins/util/user-provided-git.js +17 -15
  116. package/packages/dd-trace/src/priority_sampler.js +1 -1
  117. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  118. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  119. package/packages/dd-trace/src/profiling/ssi-heuristics.js +1 -1
  120. package/packages/dd-trace/src/rate_limiter.js +1 -1
  121. package/packages/dd-trace/src/remote_config/scheduler.js +1 -1
  122. package/packages/dd-trace/src/ritm.js +2 -1
  123. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -8
  124. package/packages/dd-trace/src/serverless.js +5 -2
  125. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +20 -0
  126. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
  127. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +20 -0
  128. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
  129. package/packages/dd-trace/src/span_stats.js +1 -1
  130. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  131. package/packages/dd-trace/src/telemetry/endpoints.js +1 -1
  132. package/packages/dd-trace/src/telemetry/telemetry.js +2 -2
  133. package/packages/dd-trace/src/lambda/runtime/ritm.js +0 -133
package/ext/exporters.js CHANGED
@@ -10,4 +10,5 @@ module.exports = {
10
10
  MOCHA_WORKER: 'mocha_worker',
11
11
  PLAYWRIGHT_WORKER: 'playwright_worker',
12
12
  VITEST_WORKER: 'vitest_worker',
13
+ ELECTRON: 'electron',
13
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.102.0",
3
+ "version": "5.103.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -79,6 +79,7 @@
79
79
  "test:integration:cypress:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/cypress/${SPEC:-cypress-*}.spec.js\"",
80
80
  "test:integration:debugger": "mocha --timeout 60000 \"integration-tests/debugger/*.spec.js\"",
81
81
  "test:integration:debugger:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/debugger/*.spec.js\"",
82
+ "test:integration:electron": "mocha \"integration-tests/electron/*.spec.js\"",
82
83
  "test:integration:esbuild": "mocha --timeout 60000 \"integration-tests/esbuild/*.spec.js\"",
83
84
  "test:integration:esbuild:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/esbuild/*.spec.js\"",
84
85
  "test:integration:webpack": "mocha --timeout 60000 \"integration-tests/webpack/*.spec.js\"",
@@ -159,20 +160,20 @@
159
160
  "version.js"
160
161
  ],
161
162
  "dependencies": {
162
- "dc-polyfill": "^0.1.10",
163
+ "dc-polyfill": "^0.1.11",
163
164
  "import-in-the-middle": "^3.0.1"
164
165
  },
165
166
  "optionalDependencies": {
166
167
  "@datadog/libdatadog": "0.9.3",
167
168
  "@datadog/native-appsec": "11.0.1",
168
169
  "@datadog/native-iast-taint-tracking": "4.1.0",
169
- "@datadog/native-metrics": "3.1.1",
170
- "@datadog/openfeature-node-server": "^1.1.2",
170
+ "@datadog/native-metrics": "3.1.2",
171
+ "@datadog/openfeature-node-server": "1.1.2",
171
172
  "@datadog/pprof": "5.14.1",
172
173
  "@datadog/wasm-js-rewriter": "5.0.1",
173
174
  "@opentelemetry/api": ">=1.0.0 <1.10.0",
174
175
  "@opentelemetry/api-logs": "<1.0.0",
175
- "oxc-parser": "^0.128.0"
176
+ "oxc-parser": "^0.129.0"
176
177
  },
177
178
  "devDependencies": {
178
179
  "@actions/core": "^3.0.1",
@@ -187,17 +188,17 @@
187
188
  "@types/mocha": "^10.0.10",
188
189
  "@types/node": "^18.19.106",
189
190
  "@types/sinon": "^21.0.1",
190
- "axios": "^1.15.2",
191
+ "axios": "^1.16.0",
191
192
  "benchmark": "^2.1.4",
192
193
  "body-parser": "^2.2.2",
193
194
  "bun": "1.3.13",
194
195
  "codeowners-audit": "^2.9.0",
195
196
  "eslint": "^9.39.2",
196
- "eslint-plugin-cypress": "^6.4.0",
197
+ "eslint-plugin-cypress": "^6.4.1",
197
198
  "eslint-plugin-import": "^2.32.0",
198
199
  "eslint-plugin-jsdoc": "^62.9.0",
199
200
  "eslint-plugin-mocha": "^11.2.0",
200
- "eslint-plugin-n": "^17.23.2",
201
+ "eslint-plugin-n": "^18.0.1",
201
202
  "eslint-plugin-promise": "^7.3.0",
202
203
  "eslint-plugin-sonarjs": "^4.0.3",
203
204
  "eslint-plugin-unicorn": "^64.0.0",
@@ -213,7 +214,7 @@
213
214
  "mocha-junit-reporter": "^2.2.1",
214
215
  "mocha-multi-reporters": "^1.5.1",
215
216
  "multer": "^2.1.1",
216
- "nock": "^13.5.6",
217
+ "nock": "^14.0.15",
217
218
  "node-preload": "^0.2.1",
218
219
  "nyc": "^18.0.0",
219
220
  "octokit": "^5.0.3",
@@ -223,11 +224,11 @@
223
224
  "retry": "^0.13.1",
224
225
  "semifies": "^1.0.0",
225
226
  "semver": "^7.7.2",
226
- "sinon": "^21.1.2",
227
+ "sinon": "^22.0.0",
227
228
  "tiktoken": "^1.0.21",
228
229
  "typescript": "^6.0.3",
229
230
  "workerpool": "^10.0.2",
230
- "yaml": "^2.8.3",
231
+ "yaml": "^2.8.4",
231
232
  "yarn-deduplicate": "^6.0.2"
232
233
  }
233
234
  }
@@ -83,9 +83,9 @@ function getSource (url, { format }) {
83
83
  *
84
84
  * @param {object} moduleData
85
85
  * @param {string} moduleData.path
86
- * @param {boolean} [moduleData.internal = false]
86
+ * @param {boolean} [moduleData.internal]
87
87
  * @param {object} moduleData.context
88
- * @param {boolean} [moduleData.excludeDefault = false]
88
+ * @param {boolean} [moduleData.excludeDefault]
89
89
  * @returns {Promise<Map>}
90
90
  */
91
91
  async function processModule ({ path, internal = false, context, excludeDefault = false }) {
@@ -20,7 +20,7 @@ const wrappedModels = new WeakSet()
20
20
  */
21
21
  function publishToAIGuard (messages) {
22
22
  return new Promise((resolve, reject) => {
23
- aiguardChannel.publish({ messages, resolve, reject })
23
+ aiguardChannel.publish({ messages, integration: 'ai', resolve, reject })
24
24
  })
25
25
  }
26
26
 
@@ -7,6 +7,7 @@ const {
7
7
  addHook,
8
8
  channel,
9
9
  } = require('./helpers/instrument')
10
+ const { cloneMessages } = require('./helpers/kafka')
10
11
 
11
12
  // Create channels for Confluent Kafka JavaScript
12
13
  const channels = {
@@ -211,46 +212,62 @@ function instrumentKafkaJS (kafkaJS) {
211
212
  return send.apply(this, arguments)
212
213
  }
213
214
 
215
+ const disableHeaderInjection = disabledHeaderWeakSet.has(producer)
216
+
217
+ // Hand the underlying client a shallow clone so neither
218
+ // injection nor the client's auto-fields (it sets
219
+ // `headers: null` on messages without headers) ever
220
+ // touch caller-owned objects. With injection disabled the
221
+ // clone must not seed `headers: {}` either: brokers that
222
+ // reject any header field cannot recover otherwise.
223
+ let outgoingPayload = payload
224
+ if (payload && Array.isArray(payload.messages)) {
225
+ outgoingPayload = {
226
+ ...payload,
227
+ messages: cloneMessages(payload.messages, !disableHeaderInjection),
228
+ }
229
+ }
230
+
214
231
  const ctx = {
215
- topic: payload?.topic,
216
- messages: payload?.messages || [],
232
+ topic: outgoingPayload?.topic,
233
+ messages: outgoingPayload?.messages || [],
217
234
  bootstrapServers: kafka._ddBrokers,
218
- disableHeaderInjection: disabledHeaderWeakSet.has(producer),
235
+ disableHeaderInjection,
219
236
  }
220
237
 
221
238
  return channels.producerStart.runStores(ctx, () => {
222
239
  try {
223
- const result = send.apply(this, arguments)
240
+ const result = send.call(this, outgoingPayload)
224
241
 
225
242
  result.then((res) => {
226
243
  ctx.result = res
227
244
  channels.producerCommit.publish(ctx)
228
245
  channels.producerFinish.publish(ctx)
229
- }, (err) => {
230
- if (err) {
231
- // Fixes bug where we would inject message headers for kafka brokers
232
- // that don't support headers (version <0.11). On the error, we disable
233
- // header injection. Tnfortunately the error name / type is not more specific.
234
- // This approach is implemented by other tracers as well.
235
- if (err.name === 'KafkaJSError' && err.type === 'ERR_UNKNOWN') {
246
+ }, (error) => {
247
+ if (error) {
248
+ // KafkaJS-compat reports `ERR_UNKNOWN` for brokers
249
+ // <0.11 that cannot parse headers. Stop injecting
250
+ // for this producer; subsequent sends to the same
251
+ // broker succeed.
252
+ if (error.name === 'KafkaJSError' && error.type === 'ERR_UNKNOWN') {
236
253
  disabledHeaderWeakSet.add(producer)
237
254
  log.error(
238
255
  // eslint-disable-next-line @stylistic/max-len
239
256
  'Kafka Broker responded with UNKNOWN_SERVER_ERROR (-1). Please look at broker logs for more information. Tracer message header injection for Kafka is disabled.'
240
257
  )
241
258
  }
242
- ctx.error = err
259
+ ctx.error = error
243
260
  channels.producerError.publish(ctx)
244
261
  }
245
262
  channels.producerFinish.publish(ctx)
246
263
  })
247
264
 
248
265
  return result
249
- } catch (e) {
250
- ctx.error = e
266
+ } catch (error) {
267
+ ctx.error = error
251
268
  channels.producerError.publish(ctx)
252
269
  channels.producerFinish.publish(ctx)
253
- throw e
270
+ throw error
254
271
  }
255
272
  })
256
273
  }
@@ -1,12 +1,27 @@
1
1
  'use strict'
2
2
 
3
- const { errorMonitor } = require('events')
3
+ const { tracingChannel } = require('dc-polyfill')
4
+
4
5
  const shimmer = require('../../datadog-shimmer')
5
6
  const {
6
- channel,
7
7
  addHook,
8
8
  } = require('./helpers/instrument')
9
9
 
10
+ // One TracingChannel per traced operation, looked up at module init so the
11
+ // hot path only does property reads on a stable handle.
12
+ const queryCh = tracingChannel('apm:couchbase:query')
13
+ const upsertCh = tracingChannel('apm:couchbase:upsert')
14
+ const insertCh = tracingChannel('apm:couchbase:insert')
15
+ const replaceCh = tracingChannel('apm:couchbase:replace')
16
+
17
+ /** @type {Map<string, ReturnType<typeof tracingChannel>>} */
18
+ const opChannelByName = new Map([
19
+ ['query', queryCh],
20
+ ['upsert', upsertCh],
21
+ ['insert', insertCh],
22
+ ['replace', replaceCh],
23
+ ])
24
+
10
25
  function findCallbackIndex (args, lowerbound = 2) {
11
26
  for (let i = args.length - 1; i >= lowerbound; i--) {
12
27
  if (typeof args[i] === 'function') return i
@@ -19,244 +34,78 @@ function getQueryResource (q) {
19
34
  return q && (typeof q === 'string' ? q : q.statement)
20
35
  }
21
36
 
22
- function wrapAllNames (names, action) {
23
- for (const name of names) {
24
- action(name)
37
+ // Hand-rolled instead of `tracingChannel.tracePromise`: synchronous
38
+ // `res.then(...)` dodges the `Promise.resolve(thenable)` microtask race on
39
+ // SDK v3.2.x / v4.0-v4.4 (lazy listener attachment), and external `.on()`
40
+ // is forbidden on v4.5.0+ (JSCBC-1301 depromisify). See commit body.
41
+ /**
42
+ * @param {import('node:diagnostics_channel').TracingChannel} ch
43
+ * Pinned per-op channel.
44
+ * @param {(...callArgs: unknown[]) => unknown} fn The SDK method being traced.
45
+ * @param {object} ctx Mutated to record `result` / `error`.
46
+ * @param {object} thisArg
47
+ * @param {unknown[]} args Forwarded to `fn` verbatim.
48
+ */
49
+ function traceV3 (ch, fn, ctx, thisArg, args) {
50
+ if (!ch.start.hasSubscribers) return fn.apply(thisArg, args)
51
+ const cbIndex = findCallbackIndex(args, 1)
52
+ if (cbIndex >= 0) {
53
+ return ch.traceCallback(fn, cbIndex, ctx, thisArg, ...args)
25
54
  }
26
- }
27
-
28
- function wrapCallback (callback, ctx, channelPrefix) {
29
- const callbackStartCh = channel(`${channelPrefix}:callback:start`)
30
- const callbackFinishCh = channel(`${channelPrefix}:callback:finish`)
31
-
32
- const wrapped = callbackStartCh.runStores(ctx, () => {
33
- return function (...args) {
34
- return callbackFinishCh.runStores(ctx, () => {
35
- return callback.apply(this, args)
36
- })
37
- }
38
- })
39
- Object.defineProperty(wrapped, '_dd_wrapped', { value: true })
40
- return wrapped
41
- }
42
-
43
- function wrapQuery (query) {
44
- return function (q, params, callback) {
45
- const cb = arguments[arguments.length - 1]
46
- if (typeof cb === 'function') {
47
- const ctx = {}
48
- arguments[arguments.length - 1] = wrapCallback(cb, ctx, 'apm:couchbase:query')
49
- }
50
-
51
- return query.apply(this, arguments)
52
- }
53
- }
54
-
55
- function wrapCallbackFinish (callback, thisArg, _args, errorCh, finishCh, ctx, channelPrefix) {
56
- const callbackStartCh = channel(`${channelPrefix}:callback:start`)
57
- const callbackFinishCh = channel(`${channelPrefix}:callback:finish`)
58
-
59
- const wrapped = callbackStartCh.runStores(ctx, () => {
60
- return function finish (error, result) {
61
- return callbackFinishCh.runStores(ctx, () => {
62
- if (error) {
63
- ctx.error = error
64
- errorCh.publish(ctx)
65
- }
66
- finishCh.publish(ctx)
67
- return callback.apply(thisArg, [error, result])
68
- })
69
- }
70
- })
71
- Object.defineProperty(wrapped, '_dd_wrapped', { value: true })
72
- return wrapped
73
- }
74
-
75
- function wrap (prefix, fn) {
76
- const startCh = channel(prefix + ':start')
77
- const finishCh = channel(prefix + ':finish')
78
- const errorCh = channel(prefix + ':error')
79
-
80
- return function (...args) {
81
- if (!startCh.hasSubscribers) {
82
- return fn.apply(this, args)
83
- }
84
-
85
- const callbackIndex = findCallbackIndex(args, 1)
86
-
87
- if (callbackIndex < 0) return fn.apply(this, args)
88
-
89
- const ctx = { bucket: { name: this.name || this._name }, seedNodes: this._dd_hosts }
90
- return startCh.runStores(ctx, () => {
91
- const cb = args[callbackIndex]
92
-
93
- args[callbackIndex] = shimmer.wrapFunction(cb, (cb) => {
94
- return wrapCallbackFinish(cb, this, args, errorCh, finishCh, ctx, prefix)
95
- })
96
-
97
- try {
98
- return fn.apply(this, args)
99
- } catch (error) {
100
- ctx.error = error
101
- void error.stack // trigger getting the stack at the original throwing point
102
- errorCh.publish(ctx)
103
-
104
- throw error
105
- }
106
- })
107
- }
108
- }
109
-
110
- // semver >=2 <3
111
- function wrapMaybeInvoke (_maybeInvoke, channelPrefix) {
112
- return function (fn, args) {
113
- if (!Array.isArray(args)) return _maybeInvoke.apply(this, arguments)
114
-
115
- const callbackIndex = findCallbackIndex(args, 0)
116
-
117
- if (callbackIndex === -1) return _maybeInvoke.apply(this, arguments)
118
-
119
- const callback = args[callbackIndex]
120
-
121
- if (typeof callback === 'function' && !callback._dd_wrapped) {
122
- const ctx = {}
123
- args[callbackIndex] = wrapCallback(callback, ctx, channelPrefix)
124
- }
125
-
126
- return _maybeInvoke.apply(this, arguments)
127
- }
128
- }
129
-
130
- // semver >=3
131
-
132
- function wrapCBandPromise (fn, name, startData, thisArg, args) {
133
- const startCh = channel(`apm:couchbase:${name}:start`)
134
- const finishCh = channel(`apm:couchbase:${name}:finish`)
135
- const errorCh = channel(`apm:couchbase:${name}:error`)
136
-
137
- if (!startCh.hasSubscribers) return fn.apply(thisArg, args)
138
-
139
- const ctx = startData
140
- return startCh.runStores(ctx, () => {
55
+ return ch.start.runStores(ctx, () => {
141
56
  try {
142
- const cbIndex = findCallbackIndex(args, 1)
143
- if (cbIndex >= 0) {
144
- // v3 offers callback or promises event handling
145
- // NOTE: this does not work with v3.2.0-3.2.1 cluster.query, as there is a bug in the couchbase source code
146
- args[cbIndex] = shimmer.wrapFunction(args[cbIndex], (cb) => {
147
- return wrapCallbackFinish(cb, thisArg, args, errorCh, finishCh, ctx, `apm:couchbase:${name}`)
148
- })
149
- }
150
57
  const res = fn.apply(thisArg, args)
151
-
152
- // semver >=3 will always return promise by default
153
58
  res.then(
154
59
  (result) => {
155
60
  ctx.result = result
156
- finishCh.publish(ctx)
61
+ ch.asyncStart.publish(ctx)
62
+ ch.asyncEnd.publish(ctx)
157
63
  },
158
- (err) => {
159
- ctx.error = err
160
- errorCh.publish(ctx)
161
- finishCh.publish(ctx)
64
+ (error) => {
65
+ ctx.error = error
66
+ ch.error.publish(ctx)
67
+ ch.asyncStart.publish(ctx)
68
+ ch.asyncEnd.publish(ctx)
162
69
  }
163
70
  )
164
71
  return res
165
- } catch (e) {
166
- void e.stack
167
- ctx.error = e
168
- errorCh.publish(ctx)
169
- throw e
72
+ } catch (error) {
73
+ ctx.error = error
74
+ ch.error.publish(ctx)
75
+ throw error
76
+ } finally {
77
+ ch.end.publish(ctx)
170
78
  }
171
79
  })
172
80
  }
173
81
 
174
- function wrapWithName (name) {
82
+ /**
83
+ * @param {string} name Operation name (`upsert`, `insert`, `replace`).
84
+ */
85
+ function wrapV3WithName (name) {
86
+ const ch = opChannelByName.get(name)
175
87
  return function (operation) {
176
- return function (...args) { // no arguments used by us
177
- return wrapCBandPromise(operation, name, {
88
+ return function (...args) {
89
+ const ctx = {
178
90
  collection: { name: this._name || '_default' },
179
91
  bucket: { name: this._scope._bucket._name },
180
92
  seedNodes: this._dd_connStr,
181
- }, this, args)
93
+ }
94
+ return traceV3(ch, operation, ctx, this, args)
182
95
  }
183
96
  }
184
97
  }
185
98
 
99
+ /**
100
+ * @param {(...args: unknown[]) => unknown} query Original `Cluster.prototype.query`.
101
+ */
186
102
  function wrapV3Query (query) {
187
- return function (q) {
188
- const resource = getQueryResource(q)
189
- return wrapCBandPromise(query, 'query', { resource, seedNodes: this._connStr }, this, arguments)
103
+ return function (...args) {
104
+ const ctx = { resource: getQueryResource(args[0]), seedNodes: this._connStr }
105
+ return traceV3(queryCh, query, ctx, this, args)
190
106
  }
191
107
  }
192
108
 
193
- // semver >=2 <3
194
- addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^2.6.12'] }, Bucket => {
195
- shimmer.wrap(Bucket.prototype, '_maybeInvoke', maybeInvoke => {
196
- return wrapMaybeInvoke(maybeInvoke, 'apm:couchbase:bucket:maybeInvoke')
197
- })
198
-
199
- const startCh = channel('apm:couchbase:query:start')
200
- const finishCh = channel('apm:couchbase:query:finish')
201
- const errorCh = channel('apm:couchbase:query:error')
202
-
203
- shimmer.wrap(Bucket.prototype, 'query', query => wrapQuery(query))
204
-
205
- shimmer.wrap(Bucket.prototype, '_n1qlReq', _n1qlReq => function (host, q, adhoc, emitter) {
206
- if (!startCh.hasSubscribers) {
207
- return _n1qlReq.apply(this, arguments)
208
- }
209
-
210
- if (!emitter || !emitter.once) return _n1qlReq.apply(this, arguments)
211
-
212
- const n1qlQuery = getQueryResource(q)
213
-
214
- const ctx = { resource: n1qlQuery, bucket: { name: this.name || this._name }, seedNodes: this._dd_hosts }
215
- return startCh.runStores(ctx, () => {
216
- emitter.once('rows', () => {
217
- finishCh.publish(ctx)
218
- })
219
-
220
- emitter.once(errorMonitor, (error) => {
221
- if (!error) return
222
- ctx.error = error
223
- errorCh.publish(ctx)
224
- finishCh.publish(ctx)
225
- })
226
-
227
- try {
228
- return _n1qlReq.apply(this, arguments)
229
- } catch (err) {
230
- void err.stack // trigger getting the stack at the original throwing point
231
- ctx.error = err
232
- errorCh.publish(ctx)
233
-
234
- throw err
235
- }
236
- })
237
- })
238
-
239
- wrapAllNames(['upsert', 'insert', 'replace', 'append', 'prepend'], name => {
240
- shimmer.wrap(Bucket.prototype, name, fn => wrap(`apm:couchbase:${name}`, fn))
241
- })
242
- })
243
-
244
- addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^2.6.12'] }, Cluster => {
245
- shimmer.wrap(Cluster.prototype, '_maybeInvoke', maybeInvoke => {
246
- return wrapMaybeInvoke(maybeInvoke, 'apm:couchbase:cluster:maybeInvoke')
247
- })
248
-
249
- shimmer.wrap(Cluster.prototype, 'query', query => wrapQuery(query))
250
- shimmer.wrap(Cluster.prototype, 'openBucket', openBucket => {
251
- return function (...args) {
252
- const bucket = openBucket.apply(this, args)
253
- const hosts = this.dsnObj.hosts
254
- bucket._dd_hosts = hosts.map(hostAndPort => hostAndPort.join(':')).join(',')
255
- return bucket
256
- }
257
- })
258
- })
259
-
260
109
  // semver >=3 <3.2.0
261
110
 
262
111
  addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^3.0.7', '^3.1.3'] }, Bucket => {
@@ -271,9 +120,9 @@ addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^3.0.7', '^3.1.3
271
120
  })
272
121
 
273
122
  addHook({ name: 'couchbase', file: 'lib/collection.js', versions: ['^3.0.7', '^3.1.3'] }, Collection => {
274
- wrapAllNames(['upsert', 'insert', 'replace'], name => {
275
- shimmer.wrap(Collection.prototype, name, wrapWithName(name))
276
- })
123
+ for (const name of ['upsert', 'insert', 'replace']) {
124
+ shimmer.wrap(Collection.prototype, name, wrapV3WithName(name))
125
+ }
277
126
  })
278
127
 
279
128
  addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^3.0.7', '^3.1.3'] }, Cluster => {
@@ -286,9 +135,9 @@ addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^3.0.7', '^3.1.
286
135
  addHook({ name: 'couchbase', file: 'dist/collection.js', versions: ['>=3.2.2'] }, collection => {
287
136
  const Collection = collection.Collection
288
137
 
289
- wrapAllNames(['upsert', 'insert', 'replace'], name => {
290
- shimmer.wrap(Collection.prototype, name, wrapWithName(name))
291
- })
138
+ for (const name of ['upsert', 'insert', 'replace']) {
139
+ shimmer.wrap(Collection.prototype, name, wrapV3WithName(name))
140
+ }
292
141
  })
293
142
 
294
143
  addHook({ name: 'couchbase', file: 'dist/bucket.js', versions: ['>=3.2.2'] }, bucket => {
@@ -653,7 +653,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
653
653
  const skippableResponse = await getChannelPromise(skippableSuitesCh)
654
654
 
655
655
  errorSkippableRequest = skippableResponse.err
656
- skippableSuites = skippableResponse.skippableSuites
656
+ skippableSuites = skippableResponse.skippableSuites ?? []
657
657
 
658
658
  if (!errorSkippableRequest) {
659
659
  const filteredPickles = isCoordinator
@@ -0,0 +1,42 @@
1
+ 'use strict'
2
+
3
+ // eslint-disable-next-line n/no-missing-require
4
+ const { contextBridge, ipcRenderer } = require('electron')
5
+
6
+ const BRIDGE_CHANNEL = 'datadog:bridge-send'
7
+ const CONFIG_CHANNEL = 'datadog:bridge-config'
8
+
9
+ // Privacy levels matching @datadog/browser-core DefaultPrivacyLevel
10
+ const MASK = 'mask'
11
+
12
+ const config = ipcRenderer.sendSync(CONFIG_CHANNEL)
13
+
14
+ const defaultPrivacyLevel = config?.defaultPrivacyLevel ?? MASK
15
+ const configuredHosts = config?.allowedWebViewHosts ?? []
16
+ // eslint-disable-next-line no-undef
17
+ const allowedHosts = [...new Set([location.hostname, ...configuredHosts])]
18
+
19
+ const bridge = {
20
+ getCapabilities () {
21
+ return '[]'
22
+ },
23
+ getPrivacyLevel () {
24
+ return defaultPrivacyLevel
25
+ },
26
+ getAllowedWebViewHosts () {
27
+ return JSON.stringify(allowedHosts)
28
+ },
29
+ send (msg) {
30
+ ipcRenderer.send(BRIDGE_CHANNEL, msg)
31
+ },
32
+ }
33
+
34
+ // Support both contextIsolation enabled (default) and disabled
35
+
36
+ window.DatadogEventBridge = bridge
37
+
38
+ try {
39
+ contextBridge.exposeInMainWorld('DatadogEventBridge', bridge)
40
+ } catch {
41
+ // exposeInMainWorld throws when contextIsolation is disabled
42
+ }