dd-trace 5.37.1 → 5.39.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 (87) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/ci/init.js +2 -2
  3. package/initialize.mjs +8 -4
  4. package/package.json +3 -1
  5. package/packages/datadog-instrumentations/src/apollo-server-core.js +1 -1
  6. package/packages/datadog-instrumentations/src/apollo-server.js +1 -1
  7. package/packages/datadog-instrumentations/src/aws-sdk.js +1 -1
  8. package/packages/datadog-instrumentations/src/express-session.js +41 -0
  9. package/packages/datadog-instrumentations/src/fetch.js +27 -6
  10. package/packages/datadog-instrumentations/src/helpers/fetch.js +6 -1
  11. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -3
  12. package/packages/datadog-instrumentations/src/http/client.js +5 -0
  13. package/packages/datadog-instrumentations/src/jest.js +9 -6
  14. package/packages/datadog-instrumentations/src/mocha/main.js +1 -1
  15. package/packages/datadog-instrumentations/src/nyc.js +1 -1
  16. package/packages/datadog-instrumentations/src/openai.js +114 -90
  17. package/packages/datadog-instrumentations/src/vitest.js +2 -2
  18. package/packages/datadog-plugin-amqplib/src/consumer.js +1 -1
  19. package/packages/datadog-plugin-amqplib/src/producer.js +1 -2
  20. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
  21. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -1
  22. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +9 -8
  23. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -4
  24. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -2
  25. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -2
  26. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -1
  27. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +1 -2
  28. package/packages/datadog-plugin-http/src/client.js +3 -1
  29. package/packages/datadog-plugin-http2/src/client.js +3 -0
  30. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
  31. package/packages/datadog-plugin-kafkajs/src/consumer.js +5 -2
  32. package/packages/datadog-plugin-kafkajs/src/producer.js +4 -3
  33. package/packages/datadog-plugin-mongodb-core/src/index.js +11 -13
  34. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  35. package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
  36. package/packages/datadog-plugin-rhea/src/producer.js +1 -2
  37. package/packages/datadog-shimmer/src/shimmer.js +95 -95
  38. package/packages/dd-trace/src/appsec/addresses.js +1 -0
  39. package/packages/dd-trace/src/appsec/channels.js +1 -0
  40. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -1
  41. package/packages/dd-trace/src/appsec/iast/iast-context.js +2 -2
  42. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -2
  43. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -1
  44. package/packages/dd-trace/src/appsec/index.js +23 -1
  45. package/packages/dd-trace/src/appsec/rule_manager.js +1 -1
  46. package/packages/dd-trace/src/appsec/sdk/set_user.js +9 -5
  47. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +5 -1
  48. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +4 -1
  49. package/packages/dd-trace/src/config.js +9 -9
  50. package/packages/dd-trace/src/{data_streams.js → datastreams/checkpointer.js} +1 -1
  51. package/packages/dd-trace/src/{data_streams_context.js → datastreams/context.js} +2 -2
  52. package/packages/dd-trace/src/datastreams/index.js +104 -0
  53. package/packages/dd-trace/src/datastreams/manager.js +27 -0
  54. package/packages/dd-trace/src/datastreams/processor.js +1 -44
  55. package/packages/dd-trace/src/datastreams/size.js +53 -0
  56. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -2
  57. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +1 -1
  58. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +22 -15
  59. package/packages/dd-trace/src/dogstatsd.js +7 -0
  60. package/packages/dd-trace/src/flare/index.js +3 -0
  61. package/packages/dd-trace/src/opentelemetry/tracer.js +45 -1
  62. package/packages/dd-trace/src/opentracing/propagation/log.js +2 -1
  63. package/packages/dd-trace/src/opentracing/propagation/text_map.js +30 -51
  64. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +1 -1
  65. package/packages/dd-trace/src/opentracing/span.js +12 -2
  66. package/packages/dd-trace/src/payload-tagging/config/aws.json +8 -0
  67. package/packages/dd-trace/src/plugin_manager.js +4 -3
  68. package/packages/dd-trace/src/plugins/util/ci.js +32 -0
  69. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  70. package/packages/dd-trace/src/profiling/profilers/wall.js +15 -4
  71. package/packages/dd-trace/src/proxy.js +2 -11
  72. package/packages/dd-trace/src/{appsec/remote_config → remote_config}/capabilities.js +1 -0
  73. package/packages/dd-trace/src/{appsec/remote_config → remote_config}/index.js +7 -5
  74. package/packages/dd-trace/src/{appsec/remote_config → remote_config}/manager.js +5 -5
  75. package/packages/dd-trace/src/runtime_metrics/index.js +34 -0
  76. package/packages/dd-trace/src/{runtime_metrics.js → runtime_metrics/runtime_metrics.js} +4 -4
  77. package/packages/dd-trace/src/sampling_rule.js +8 -3
  78. package/packages/dd-trace/src/serverless.js +10 -1
  79. package/packages/dd-trace/src/service-naming/index.js +12 -4
  80. package/packages/dd-trace/src/telemetry/index.js +16 -386
  81. package/packages/dd-trace/src/telemetry/telemetry.js +394 -0
  82. package/packages/dd-trace/src/tracer.js +4 -13
  83. package/packages/dd-trace/src/util.js +2 -0
  84. package/register.js +3 -1
  85. package/packages/dd-trace/src/service-naming/schemas/index.js +0 -6
  86. /package/packages/dd-trace/src/{appsec/remote_config → remote_config}/apply_states.js +0 -0
  87. /package/packages/dd-trace/src/{appsec/remote_config → remote_config}/scheduler.js +0 -0
@@ -54,6 +54,7 @@ dev,eslint-plugin-import,MIT,Copyright 2015 Ben Mosher
54
54
  dev,eslint-plugin-mocha,MIT,Copyright 2014 Mathias Schreck
55
55
  dev,eslint-plugin-n,MIT,Copyright 2015 Toru Nagashima
56
56
  dev,eslint-plugin-promise,ISC,jden and other contributors
57
+ dev,eslint-plugin-unicorn,MIT,Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
57
58
  dev,express,MIT,Copyright 2009-2014 TJ Holowaychuk 2013-2014 Roman Shtylman 2014-2015 Douglas Christopher Wilson
58
59
  dev,get-port,MIT,Copyright Sindre Sorhus
59
60
  dev,glob,ISC,Copyright Isaac Z. Schlueter and Contributors
package/ci/init.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable no-console */
2
2
  const tracer = require('../packages/dd-trace')
3
- const { isTrue } = require('../packages/dd-trace/src/util')
3
+ const { isTrue, isFalse } = require('../packages/dd-trace/src/util')
4
4
  const log = require('../packages/dd-trace/src/log')
5
5
 
6
6
  const isJestWorker = !!process.env.JEST_WORKER_ID
@@ -23,7 +23,7 @@ const options = {
23
23
  flushInterval: isJestWorker ? 0 : 5000
24
24
  }
25
25
 
26
- let shouldInit = true
26
+ let shouldInit = !isFalse(process.env.DD_CIVISIBILITY_ENABLED)
27
27
 
28
28
  if (isPackageManager()) {
29
29
  log.debug('dd-trace is not initialized in a package manager.')
package/initialize.mjs CHANGED
@@ -35,10 +35,12 @@ ${result.source}`
35
35
  const [NODE_MAJOR, NODE_MINOR] = process.versions.node.split('.').map(x => +x)
36
36
 
37
37
  const brokenLoaders = NODE_MAJOR === 18 && NODE_MINOR === 0
38
+ const iitmExclusions = [/langsmith/, /openai\/_shims/, /openai\/resources\/chat\/completions\/messages/]
38
39
 
39
- export async function load (...args) {
40
- const loadHook = brokenLoaders ? args[args.length - 1] : origLoad
41
- return insertInit(await loadHook(...args))
40
+ export async function load (url, context, nextLoad) {
41
+ const iitmExclusionsMatch = iitmExclusions.some((exclusion) => exclusion.test(url))
42
+ const loadHook = (brokenLoaders || iitmExclusionsMatch) ? nextLoad : origLoad
43
+ return insertInit(await loadHook(url, context, nextLoad))
42
44
  }
43
45
 
44
46
  export const resolve = brokenLoaders ? undefined : origResolve
@@ -53,6 +55,8 @@ if (isMainThread) {
53
55
  const require = Module.createRequire(import.meta.url)
54
56
  require('./init.js')
55
57
  if (Module.register) {
56
- Module.register('./loader-hook.mjs', import.meta.url)
58
+ Module.register('./loader-hook.mjs', import.meta.url, {
59
+ data: { exclude: iitmExclusions }
60
+ })
57
61
  }
58
62
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.37.1",
3
+ "version": "5.39.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -14,6 +14,7 @@
14
14
  "type:test": "cd docs && yarn && yarn test",
15
15
  "lint": "node scripts/check_licenses.js && eslint . --max-warnings 0 && yarn audit",
16
16
  "lint:fix": "node scripts/check_licenses.js && eslint . --max-warnings 0 --fix && yarn audit",
17
+ "lint:inspect": "npx @eslint/config-inspector@latest",
17
18
  "release:proposal": "node scripts/release/proposal",
18
19
  "services": "node ./scripts/install_plugin_modules && node packages/dd-trace/test/setup/services",
19
20
  "test": "SERVICES=* yarn services && mocha --expose-gc 'packages/dd-trace/test/setup/node.js' 'packages/*/test/**/*.spec.js'",
@@ -138,6 +139,7 @@
138
139
  "eslint-plugin-mocha": "^10.5.0",
139
140
  "eslint-plugin-n": "^17.15.1",
140
141
  "eslint-plugin-promise": "^7.2.1",
142
+ "eslint-plugin-unicorn": "^57.0.0",
141
143
  "express": "^4.21.2",
142
144
  "get-port": "^3.2.0",
143
145
  "glob": "^7.1.6",
@@ -10,7 +10,7 @@ addHook({ name: 'apollo-server-core', file: 'dist/runHttpQuery.js', versions: ['
10
10
  const HttpQueryError = runHttpQueryModule.HttpQueryError
11
11
 
12
12
  shimmer.wrap(runHttpQueryModule, 'runHttpQuery', function wrapRunHttpQuery (originalRunHttpQuery) {
13
- return async function runHttpQuery () {
13
+ return function runHttpQuery () {
14
14
  if (!requestChannel.start.hasSubscribers) {
15
15
  return originalRunHttpQuery.apply(this, arguments)
16
16
  }
@@ -12,7 +12,7 @@ const requestChannel = dc.tracingChannel('datadog:apollo:request')
12
12
  let HeaderMap
13
13
 
14
14
  function wrapExecuteHTTPGraphQLRequest (originalExecuteHTTPGraphQLRequest) {
15
- return async function executeHTTPGraphQLRequest () {
15
+ return function executeHTTPGraphQLRequest () {
16
16
  if (!HeaderMap || !requestChannel.start.hasSubscribers) {
17
17
  return originalExecuteHTTPGraphQLRequest.apply(this, arguments)
18
18
  }
@@ -172,7 +172,7 @@ function getMessage (request, error, result) {
172
172
 
173
173
  function getChannelSuffix (name) {
174
174
  // some resource identifiers have spaces between ex: bedrock runtime
175
- name = name.replaceAll(' ', '')
175
+ name = String(name).replaceAll(' ', '')
176
176
  return [
177
177
  'cloudwatchlogs',
178
178
  'dynamodb',
@@ -0,0 +1,41 @@
1
+ 'use strict'
2
+
3
+ const shimmer = require('../../datadog-shimmer')
4
+ const { channel, addHook } = require('./helpers/instrument')
5
+
6
+ const sessionMiddlewareFinishCh = channel('datadog:express-session:middleware:finish')
7
+
8
+ function wrapSessionMiddleware (sessionMiddleware) {
9
+ return function wrappedSessionMiddleware (req, res, next) {
10
+ shimmer.wrap(arguments, 2, function wrapNext (next) {
11
+ return function wrappedNext () {
12
+ if (sessionMiddlewareFinishCh.hasSubscribers) {
13
+ const abortController = new AbortController()
14
+
15
+ sessionMiddlewareFinishCh.publish({ req, res, sessionId: req.sessionID, abortController })
16
+
17
+ if (abortController.signal.aborted) return
18
+ }
19
+
20
+ return next.apply(this, arguments)
21
+ }
22
+ })
23
+
24
+ return sessionMiddleware.apply(this, arguments)
25
+ }
26
+ }
27
+
28
+ function wrapSession (session) {
29
+ return function wrappedSession () {
30
+ const sessionMiddleware = session.apply(this, arguments)
31
+
32
+ return shimmer.wrapFunction(sessionMiddleware, wrapSessionMiddleware)
33
+ }
34
+ }
35
+
36
+ addHook({
37
+ name: 'express-session',
38
+ versions: ['>=1.5.0']
39
+ }, session => {
40
+ return shimmer.wrapFunction(session, wrapSession)
41
+ })
@@ -1,12 +1,33 @@
1
1
  'use strict'
2
2
 
3
- const shimmer = require('../../datadog-shimmer')
4
- const { tracingChannel } = require('dc-polyfill')
5
- const { createWrapFetch } = require('./helpers/fetch')
3
+ const { isInServerlessEnvironment } = require('../../dd-trace/src/serverless')
6
4
 
7
5
  if (globalThis.fetch) {
8
- const ch = tracingChannel('apm:fetch:request')
9
- const wrapFetch = createWrapFetch(globalThis.Request, ch)
6
+ const globalFetch = globalThis.fetch
10
7
 
11
- globalThis.fetch = shimmer.wrapFunction(fetch, fetch => wrapFetch(fetch))
8
+ let fetch = (input, init) => {
9
+ wrapRealFetch()
10
+
11
+ return fetch(input, init)
12
+ }
13
+
14
+ function wrapRealFetch () {
15
+ const { channel, tracingChannel } = require('dc-polyfill')
16
+ const { createWrapFetch } = require('./helpers/fetch')
17
+
18
+ const ch = tracingChannel('apm:fetch:request')
19
+ const wrapFetch = createWrapFetch(globalThis.Request, ch, () => {
20
+ channel('dd-trace:instrumentation:load').publish({ name: 'fetch' })
21
+ })
22
+
23
+ fetch = wrapFetch(globalFetch)
24
+ }
25
+
26
+ if (!isInServerlessEnvironment()) {
27
+ wrapRealFetch()
28
+ }
29
+
30
+ globalThis.fetch = function value (input, init) {
31
+ return fetch(input, init)
32
+ }
12
33
  }
@@ -1,10 +1,15 @@
1
1
  'use strict'
2
2
 
3
- exports.createWrapFetch = function createWrapFetch (Request, ch) {
3
+ exports.createWrapFetch = function createWrapFetch (Request, ch, onLoad) {
4
4
  return function wrapFetch (fetch) {
5
5
  if (typeof fetch !== 'function') return fetch
6
6
 
7
7
  return function (input, init) {
8
+ if (onLoad) {
9
+ onLoad()
10
+ onLoad = undefined
11
+ }
12
+
8
13
  if (!ch.start.hasSubscribers) return fetch.apply(this, arguments)
9
14
 
10
15
  if (input instanceof Request) {
@@ -19,8 +19,8 @@ module.exports = {
19
19
  '@jest/test-sequencer': () => require('../jest'),
20
20
  '@jest/transform': () => require('../jest'),
21
21
  '@koa/router': () => require('../koa'),
22
- '@langchain/core': () => require('../langchain'),
23
- '@langchain/openai': () => require('../langchain'),
22
+ '@langchain/core': { esmFirst: true, fn: () => require('../langchain') },
23
+ '@langchain/openai': { esmFirst: true, fn: () => require('../langchain') },
24
24
  '@node-redis/client': () => require('../redis'),
25
25
  '@opensearch-project/opensearch': () => require('../opensearch'),
26
26
  '@opentelemetry/sdk-trace-node': () => require('../otel-sdk-trace'),
@@ -47,6 +47,7 @@ module.exports = {
47
47
  elasticsearch: () => require('../elasticsearch'),
48
48
  express: () => require('../express'),
49
49
  'express-mongo-sanitize': () => require('../express-mongo-sanitize'),
50
+ 'express-session': () => require('../express-session'),
50
51
  fastify: () => require('../fastify'),
51
52
  'find-my-way': () => require('../find-my-way'),
52
53
  fs: () => require('../fs'),
@@ -100,7 +101,7 @@ module.exports = {
100
101
  'node:vm': () => require('../vm'),
101
102
  nyc: () => require('../nyc'),
102
103
  oracledb: () => require('../oracledb'),
103
- openai: () => require('../openai'),
104
+ openai: { esmFirst: true, fn: () => require('../openai') },
104
105
  paperplane: () => require('../paperplane'),
105
106
  passport: () => require('../passport'),
106
107
  'passport-http': () => require('../passport-http'),
@@ -117,6 +117,11 @@ function patch (http, methodName) {
117
117
  } catch (e) {
118
118
  ctx.error = e
119
119
  errorChannel.publish(ctx)
120
+ // if the initial request failed, ctx.req will be unset, we must close the span here
121
+ // fix for: https://github.com/DataDog/dd-trace-js/issues/5016
122
+ if (!ctx.req) {
123
+ finish()
124
+ }
120
125
  throw e
121
126
  } finally {
122
127
  endChannel.publish(ctx)
@@ -170,7 +170,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
170
170
  try {
171
171
  const hasQuarantinedTests = !!quarantinedTests.jest
172
172
  this.quarantinedTestsForThisSuite = hasQuarantinedTests
173
- ? this.getQuarantinedTestsForSuite(quarantinedTests.jest.suites[this.testSuite].tests)
173
+ ? this.getQuarantinedTestsForSuite(quarantinedTests.jest.suites?.[this.testSuite]?.tests)
174
174
  : this.getQuarantinedTestsForSuite(this.testEnvironmentOptions._ddQuarantinedTests)
175
175
  } catch (e) {
176
176
  log.error('Error parsing quarantined tests', e)
@@ -209,11 +209,14 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
209
209
  return knownTestsForSuite
210
210
  }
211
211
 
212
- getQuarantinedTestsForSuite (quaratinedTests) {
212
+ getQuarantinedTestsForSuite (quarantined) {
213
213
  if (this.quarantinedTestsForThisSuite) {
214
214
  return this.quarantinedTestsForThisSuite
215
215
  }
216
- let quarantinedTestsForSuite = quaratinedTests
216
+ if (!quarantined) {
217
+ return []
218
+ }
219
+ let quarantinedTestsForSuite = quarantined
217
220
  // If jest is using workers, quarantined tests are serialized to json.
218
221
  // If jest runs in band, they are not.
219
222
  if (typeof quarantinedTestsForSuite === 'string') {
@@ -439,7 +442,7 @@ addHook({
439
442
  }, getTestEnvironment)
440
443
 
441
444
  function getWrappedScheduleTests (scheduleTests, frameworkVersion) {
442
- return async function (tests) {
445
+ return function (tests) {
443
446
  if (!isSuitesSkippingEnabled || hasFilteredSkippableSuites) {
444
447
  return scheduleTests.apply(this, arguments)
445
448
  }
@@ -741,7 +744,7 @@ function coverageReporterWrapper (coverageReporter) {
741
744
  * This calculation adds no value, so we'll skip it, as long as the user has not manually opted in to code coverage,
742
745
  * in which case we'll leave it.
743
746
  */
744
- shimmer.wrap(CoverageReporter.prototype, '_addUntestedFiles', addUntestedFiles => async function () {
747
+ shimmer.wrap(CoverageReporter.prototype, '_addUntestedFiles', addUntestedFiles => function () {
745
748
  // If the user has added coverage manually, they're willing to pay the price of this execution, so
746
749
  // we will not skip it.
747
750
  if (isSuitesSkippingEnabled && !isUserCodeCoverageEnabled) {
@@ -898,7 +901,7 @@ addHook({
898
901
  }, transformPackage => {
899
902
  const originalCreateScriptTransformer = transformPackage.createScriptTransformer
900
903
 
901
- transformPackage.createScriptTransformer = async function (config) {
904
+ transformPackage.createScriptTransformer = function (config) {
902
905
  const { testEnvironmentOptions, ...restOfConfig } = config
903
906
  const {
904
907
  _ddTestModuleId,
@@ -349,7 +349,7 @@ addHook({
349
349
  versions: ['>=5.2.0'],
350
350
  file: 'lib/cli/run-helpers.js'
351
351
  }, (run) => {
352
- shimmer.wrap(run, 'runMocha', runMocha => async function () {
352
+ shimmer.wrap(run, 'runMocha', runMocha => function () {
353
353
  if (!testStartCh.hasSubscribers) {
354
354
  return runMocha.apply(this, arguments)
355
355
  }
@@ -7,7 +7,7 @@ addHook({
7
7
  name: 'nyc',
8
8
  versions: ['>=17']
9
9
  }, (nycPackage) => {
10
- shimmer.wrap(nycPackage.prototype, 'wrap', wrap => async function () {
10
+ shimmer.wrap(nycPackage.prototype, 'wrap', wrap => function () {
11
11
  // Only relevant if the config `all` is set to true
12
12
  try {
13
13
  if (JSON.parse(process.env.NYC_CONFIG).all) {
@@ -8,98 +8,98 @@ const ch = dc.tracingChannel('apm:openai:request')
8
8
 
9
9
  const V4_PACKAGE_SHIMS = [
10
10
  {
11
- file: 'resources/chat/completions.js',
11
+ file: 'resources/chat/completions',
12
12
  targetClass: 'Completions',
13
13
  baseResource: 'chat.completions',
14
14
  methods: ['create'],
15
15
  streamedResponse: true
16
16
  },
17
17
  {
18
- file: 'resources/completions.js',
18
+ file: 'resources/completions',
19
19
  targetClass: 'Completions',
20
20
  baseResource: 'completions',
21
21
  methods: ['create'],
22
22
  streamedResponse: true
23
23
  },
24
24
  {
25
- file: 'resources/embeddings.js',
25
+ file: 'resources/embeddings',
26
26
  targetClass: 'Embeddings',
27
27
  baseResource: 'embeddings',
28
28
  methods: ['create']
29
29
  },
30
30
  {
31
- file: 'resources/files.js',
31
+ file: 'resources/files',
32
32
  targetClass: 'Files',
33
33
  baseResource: 'files',
34
34
  methods: ['create', 'del', 'list', 'retrieve']
35
35
  },
36
36
  {
37
- file: 'resources/files.js',
37
+ file: 'resources/files',
38
38
  targetClass: 'Files',
39
39
  baseResource: 'files',
40
40
  methods: ['retrieveContent'],
41
41
  versions: ['>=4.0.0 <4.17.1']
42
42
  },
43
43
  {
44
- file: 'resources/files.js',
44
+ file: 'resources/files',
45
45
  targetClass: 'Files',
46
46
  baseResource: 'files',
47
47
  methods: ['content'], // replaced `retrieveContent` in v4.17.1
48
48
  versions: ['>=4.17.1']
49
49
  },
50
50
  {
51
- file: 'resources/images.js',
51
+ file: 'resources/images',
52
52
  targetClass: 'Images',
53
53
  baseResource: 'images',
54
54
  methods: ['createVariation', 'edit', 'generate']
55
55
  },
56
56
  {
57
- file: 'resources/fine-tuning/jobs/jobs.js',
57
+ file: 'resources/fine-tuning/jobs/jobs',
58
58
  targetClass: 'Jobs',
59
59
  baseResource: 'fine_tuning.jobs',
60
60
  methods: ['cancel', 'create', 'list', 'listEvents', 'retrieve'],
61
61
  versions: ['>=4.34.0'] // file location changed in 4.34.0
62
62
  },
63
63
  {
64
- file: 'resources/fine-tuning/jobs.js',
64
+ file: 'resources/fine-tuning/jobs',
65
65
  targetClass: 'Jobs',
66
66
  baseResource: 'fine_tuning.jobs',
67
67
  methods: ['cancel', 'create', 'list', 'listEvents', 'retrieve'],
68
68
  versions: ['>=4.1.0 <4.34.0']
69
69
  },
70
70
  {
71
- file: 'resources/fine-tunes.js', // deprecated after 4.1.0
71
+ file: 'resources/fine-tunes', // deprecated after 4.1.0
72
72
  targetClass: 'FineTunes',
73
73
  baseResource: 'fine-tune',
74
74
  methods: ['cancel', 'create', 'list', 'listEvents', 'retrieve'],
75
75
  versions: ['>=4.0.0 <4.1.0']
76
76
  },
77
77
  {
78
- file: 'resources/models.js',
78
+ file: 'resources/models',
79
79
  targetClass: 'Models',
80
80
  baseResource: 'models',
81
81
  methods: ['del', 'list', 'retrieve']
82
82
  },
83
83
  {
84
- file: 'resources/moderations.js',
84
+ file: 'resources/moderations',
85
85
  targetClass: 'Moderations',
86
86
  baseResource: 'moderations',
87
87
  methods: ['create']
88
88
  },
89
89
  {
90
- file: 'resources/audio/transcriptions.js',
90
+ file: 'resources/audio/transcriptions',
91
91
  targetClass: 'Transcriptions',
92
92
  baseResource: 'audio.transcriptions',
93
93
  methods: ['create']
94
94
  },
95
95
  {
96
- file: 'resources/audio/translations.js',
96
+ file: 'resources/audio/translations',
97
97
  targetClass: 'Translations',
98
98
  baseResource: 'audio.translations',
99
99
  methods: ['create']
100
100
  },
101
101
  {
102
- file: 'resources/chat/completions/completions.js',
102
+ file: 'resources/chat/completions/completions',
103
103
  targetClass: 'Completions',
104
104
  baseResource: 'chat.completions',
105
105
  methods: ['create'],
@@ -267,93 +267,117 @@ function wrapStreamIterator (response, options, n, ctx) {
267
267
  }
268
268
  }
269
269
 
270
- for (const shim of V4_PACKAGE_SHIMS) {
271
- const { file, targetClass, baseResource, methods, versions, streamedResponse } = shim
272
- addHook({ name: 'openai', file, versions: versions || ['>=4'] }, exports => {
273
- const targetPrototype = exports[targetClass].prototype
270
+ const extensions = ['.js', '.mjs']
274
271
 
275
- for (const methodName of methods) {
276
- shimmer.wrap(targetPrototype, methodName, methodFn => function () {
277
- if (!ch.start.hasSubscribers) {
278
- return methodFn.apply(this, arguments)
279
- }
272
+ for (const extension of extensions) {
273
+ for (const shim of V4_PACKAGE_SHIMS) {
274
+ const { file, targetClass, baseResource, methods, versions, streamedResponse } = shim
275
+ addHook({ name: 'openai', file: file + extension, versions: versions || ['>=4'] }, exports => {
276
+ const targetPrototype = exports[targetClass].prototype
280
277
 
281
- // The OpenAI library lets you set `stream: true` on the options arg to any method
282
- // However, we only want to handle streamed responses in specific cases
283
- // chat.completions and completions
284
- const stream = streamedResponse && getOption(arguments, 'stream', false)
285
-
286
- // we need to compute how many prompts we are sending in streamed cases for completions
287
- // not applicable for chat completiond
288
- let n
289
- if (stream) {
290
- n = getOption(arguments, 'n', 1)
291
- const prompt = getOption(arguments, 'prompt')
292
- if (Array.isArray(prompt) && typeof prompt[0] !== 'number') {
293
- n *= prompt.length
278
+ for (const methodName of methods) {
279
+ shimmer.wrap(targetPrototype, methodName, methodFn => function () {
280
+ if (!ch.start.hasSubscribers) {
281
+ return methodFn.apply(this, arguments)
294
282
  }
295
- }
296
283
 
297
- const client = this._client || this.client
284
+ // The OpenAI library lets you set `stream: true` on the options arg to any method
285
+ // However, we only want to handle streamed responses in specific cases
286
+ // chat.completions and completions
287
+ const stream = streamedResponse && getOption(arguments, 'stream', false)
288
+
289
+ // we need to compute how many prompts we are sending in streamed cases for completions
290
+ // not applicable for chat completiond
291
+ let n
292
+ if (stream) {
293
+ n = getOption(arguments, 'n', 1)
294
+ const prompt = getOption(arguments, 'prompt')
295
+ if (Array.isArray(prompt) && typeof prompt[0] !== 'number') {
296
+ n *= prompt.length
297
+ }
298
+ }
298
299
 
299
- const ctx = {
300
- methodName: `${baseResource}.${methodName}`,
301
- args: arguments,
302
- basePath: client.baseURL,
303
- apiKey: client.apiKey
304
- }
300
+ const client = this._client || this.client
305
301
 
306
- return ch.start.runStores(ctx, () => {
307
- const apiProm = methodFn.apply(this, arguments)
308
-
309
- // wrapping `parse` avoids problematic wrapping of `then` when trying to call
310
- // `withResponse` in userland code after. This way, we can return the whole `APIPromise`
311
- shimmer.wrap(apiProm, 'parse', origApiPromParse => function () {
312
- return origApiPromParse.apply(this, arguments)
313
- // the original response is wrapped in a promise, so we need to unwrap it
314
- .then(body => Promise.all([this.responsePromise, body]))
315
- .then(([{ response, options }, body]) => {
316
- if (stream) {
317
- if (body.iterator) {
318
- shimmer.wrap(body, 'iterator', wrapStreamIterator(response, options, n, ctx))
319
- } else {
320
- shimmer.wrap(
321
- body.response.body, Symbol.asyncIterator, wrapStreamIterator(response, options, n, ctx)
322
- )
323
- }
324
- } else {
325
- finish(ctx, {
326
- headers: response.headers,
327
- data: body,
328
- request: {
329
- path: response.url,
330
- method: options.method
331
- }
332
- })
333
- }
302
+ const ctx = {
303
+ methodName: `${baseResource}.${methodName}`,
304
+ args: arguments,
305
+ basePath: client.baseURL,
306
+ apiKey: client.apiKey
307
+ }
334
308
 
335
- return body
336
- })
337
- .catch(error => {
338
- finish(ctx, undefined, error)
309
+ return ch.start.runStores(ctx, () => {
310
+ const apiProm = methodFn.apply(this, arguments)
339
311
 
340
- throw error
341
- })
342
- .finally(() => {
343
- // maybe we don't want to unwrap here in case the promise is re-used?
344
- // other hand: we want to avoid resource leakage
345
- shimmer.unwrap(apiProm, 'parse')
312
+ if (baseResource === 'chat.completions' && typeof apiProm._thenUnwrap === 'function') {
313
+ // this should only ever be invoked from a client.beta.chat.completions.parse call
314
+ shimmer.wrap(apiProm, '_thenUnwrap', origApiPromThenUnwrap => function () {
315
+ // TODO(sam.brenner): I wonder if we can patch the APIPromise prototype instead, although
316
+ // we might not have access to everything we need...
317
+
318
+ // this is a new apipromise instance
319
+ const unwrappedPromise = origApiPromThenUnwrap.apply(this, arguments)
320
+
321
+ shimmer.wrap(unwrappedPromise, 'parse', origApiPromParse => function () {
322
+ const parsedPromise = origApiPromParse.apply(this, arguments)
323
+ .then(body => Promise.all([this.responsePromise, body]))
324
+
325
+ return handleUnwrappedAPIPromise(parsedPromise, ctx, stream, n)
326
+ })
327
+
328
+ return unwrappedPromise
346
329
  })
347
- })
330
+ }
331
+
332
+ // wrapping `parse` avoids problematic wrapping of `then` when trying to call
333
+ // `withResponse` in userland code after. This way, we can return the whole `APIPromise`
334
+ shimmer.wrap(apiProm, 'parse', origApiPromParse => function () {
335
+ const parsedPromise = origApiPromParse.apply(this, arguments)
336
+ .then(body => Promise.all([this.responsePromise, body]))
337
+
338
+ return handleUnwrappedAPIPromise(parsedPromise, ctx, stream, n)
339
+ })
348
340
 
349
- ch.end.publish(ctx)
341
+ ch.end.publish(ctx)
350
342
 
351
- return apiProm
343
+ return apiProm
344
+ })
352
345
  })
353
- })
354
- }
355
- return exports
356
- })
346
+ }
347
+ return exports
348
+ })
349
+ }
350
+ }
351
+
352
+ function handleUnwrappedAPIPromise (apiProm, ctx, stream, n) {
353
+ return apiProm
354
+ .then(([{ response, options }, body]) => {
355
+ if (stream) {
356
+ if (body.iterator) {
357
+ shimmer.wrap(body, 'iterator', wrapStreamIterator(response, options, n, ctx))
358
+ } else {
359
+ shimmer.wrap(
360
+ body.response.body, Symbol.asyncIterator, wrapStreamIterator(response, options, n, ctx)
361
+ )
362
+ }
363
+ } else {
364
+ finish(ctx, {
365
+ headers: response.headers,
366
+ data: body,
367
+ request: {
368
+ path: response.url,
369
+ method: options.method
370
+ }
371
+ })
372
+ }
373
+
374
+ return body
375
+ })
376
+ .catch(error => {
377
+ finish(ctx, undefined, error)
378
+
379
+ throw error
380
+ })
357
381
  }
358
382
 
359
383
  function finish (ctx, response, error) {
@@ -329,7 +329,7 @@ addHook({
329
329
  const { VitestTestRunner } = vitestPackage
330
330
 
331
331
  // `onBeforeRunTask` is run before any repetition or attempt is run
332
- shimmer.wrap(VitestTestRunner.prototype, 'onBeforeRunTask', onBeforeRunTask => async function (task) {
332
+ shimmer.wrap(VitestTestRunner.prototype, 'onBeforeRunTask', onBeforeRunTask => function (task) {
333
333
  const testName = getTestName(task)
334
334
 
335
335
  const {
@@ -361,7 +361,7 @@ addHook({
361
361
  })
362
362
 
363
363
  // `onAfterRunTask` is run after all repetitions or attempts are run
364
- shimmer.wrap(VitestTestRunner.prototype, 'onAfterRunTask', onAfterRunTask => async function (task) {
364
+ shimmer.wrap(VitestTestRunner.prototype, 'onAfterRunTask', onAfterRunTask => function (task) {
365
365
  const { isEarlyFlakeDetectionEnabled, isQuarantinedTestsEnabled } = getProvidedContext()
366
366
 
367
367
  if (isEarlyFlakeDetectionEnabled && taskToStatuses.has(task)) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { TEXT_MAP } = require('../../../ext/formats')
4
4
  const ConsumerPlugin = require('../../dd-trace/src/plugins/consumer')
5
- const { getAmqpMessageSize } = require('../../dd-trace/src/datastreams/processor')
5
+ const { getAmqpMessageSize } = require('../../dd-trace/src/datastreams')
6
6
  const { getResourceName } = require('./util')
7
7
 
8
8
  class AmqplibConsumerPlugin extends ConsumerPlugin {