dd-trace 5.86.0 → 5.88.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 (105) hide show
  1. package/LICENSE-3rdparty.csv +60 -32
  2. package/ext/exporters.d.ts +1 -0
  3. package/ext/exporters.js +1 -0
  4. package/index.d.ts +243 -7
  5. package/package.json +9 -6
  6. package/packages/datadog-instrumentations/src/ai.js +54 -90
  7. package/packages/datadog-instrumentations/src/cucumber.js +14 -0
  8. package/packages/datadog-instrumentations/src/helpers/hook.js +17 -11
  9. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  10. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +55 -14
  11. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +15 -13
  12. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +103 -0
  13. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.js +108 -0
  14. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -1
  15. package/packages/datadog-instrumentations/src/helpers/rewriter/transformer.js +21 -0
  16. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +138 -12
  17. package/packages/datadog-instrumentations/src/http/client.js +119 -1
  18. package/packages/datadog-instrumentations/src/jest.js +179 -15
  19. package/packages/datadog-instrumentations/src/kafkajs.js +20 -17
  20. package/packages/datadog-instrumentations/src/mocha/utils.js +6 -0
  21. package/packages/datadog-instrumentations/src/mysql2.js +131 -64
  22. package/packages/datadog-instrumentations/src/playwright.js +9 -1
  23. package/packages/datadog-instrumentations/src/stripe.js +92 -0
  24. package/packages/datadog-instrumentations/src/vitest.js +11 -0
  25. package/packages/datadog-plugin-amqplib/src/consumer.js +14 -10
  26. package/packages/datadog-plugin-amqplib/src/producer.js +23 -19
  27. package/packages/datadog-plugin-azure-functions/src/index.js +53 -37
  28. package/packages/datadog-plugin-bullmq/src/consumer.js +33 -11
  29. package/packages/datadog-plugin-bullmq/src/producer.js +60 -31
  30. package/packages/datadog-plugin-cucumber/src/index.js +9 -6
  31. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +33 -0
  32. package/packages/datadog-plugin-cypress/src/support.js +48 -8
  33. package/packages/datadog-plugin-jest/src/index.js +12 -2
  34. package/packages/datadog-plugin-jest/src/util.js +2 -1
  35. package/packages/datadog-plugin-kafkajs/src/consumer.js +22 -12
  36. package/packages/datadog-plugin-kafkajs/src/producer.js +33 -22
  37. package/packages/datadog-plugin-mocha/src/index.js +9 -6
  38. package/packages/datadog-plugin-playwright/src/index.js +10 -6
  39. package/packages/datadog-plugin-vitest/src/index.js +13 -8
  40. package/packages/dd-trace/src/appsec/addresses.js +11 -0
  41. package/packages/dd-trace/src/appsec/channels.js +5 -1
  42. package/packages/dd-trace/src/appsec/downstream_requests.js +302 -0
  43. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +1 -1
  44. package/packages/dd-trace/src/appsec/iast/analyzers/ssrf-analyzer.js +1 -1
  45. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +1 -1
  46. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +4 -5
  47. package/packages/dd-trace/src/appsec/iast/path-line.js +36 -25
  48. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +1 -1
  49. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -4
  50. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +3 -2
  51. package/packages/dd-trace/src/appsec/index.js +103 -0
  52. package/packages/dd-trace/src/appsec/rasp/ssrf.js +66 -4
  53. package/packages/dd-trace/src/azure_metadata.js +0 -2
  54. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +14 -1
  55. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
  56. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +2 -0
  57. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -1
  58. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -1
  59. package/packages/dd-trace/src/ci-visibility/requests/request.js +236 -0
  60. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
  61. package/packages/dd-trace/src/config/defaults.js +148 -195
  62. package/packages/dd-trace/src/config/helper.js +43 -1
  63. package/packages/dd-trace/src/config/index.js +42 -14
  64. package/packages/dd-trace/src/config/supported-configurations.json +4115 -510
  65. package/packages/dd-trace/src/constants.js +0 -2
  66. package/packages/dd-trace/src/crashtracking/crashtracker.js +10 -3
  67. package/packages/dd-trace/src/datastreams/pathway.js +22 -3
  68. package/packages/dd-trace/src/datastreams/processor.js +14 -1
  69. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +47 -2
  70. package/packages/dd-trace/src/debugger/devtools_client/index.js +75 -23
  71. package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +23 -1
  72. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +3 -3
  73. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +168 -36
  74. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +18 -0
  75. package/packages/dd-trace/src/encode/agentless-json.js +141 -0
  76. package/packages/dd-trace/src/exporter.js +2 -0
  77. package/packages/dd-trace/src/exporters/agent/writer.js +22 -8
  78. package/packages/dd-trace/src/exporters/agentless/index.js +89 -0
  79. package/packages/dd-trace/src/exporters/agentless/writer.js +184 -0
  80. package/packages/dd-trace/src/exporters/common/agents.js +1 -1
  81. package/packages/dd-trace/src/exporters/common/request.js +4 -4
  82. package/packages/dd-trace/src/llmobs/constants/writers.js +1 -1
  83. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -3
  84. package/packages/dd-trace/src/llmobs/sdk.js +34 -5
  85. package/packages/dd-trace/src/opentelemetry/context_manager.js +19 -46
  86. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +3 -4
  87. package/packages/dd-trace/src/opentracing/propagation/text_map.js +3 -5
  88. package/packages/dd-trace/src/opentracing/span.js +6 -4
  89. package/packages/dd-trace/src/plugins/ci_plugin.js +57 -5
  90. package/packages/dd-trace/src/plugins/database.js +57 -45
  91. package/packages/dd-trace/src/plugins/outbound.js +27 -2
  92. package/packages/dd-trace/src/plugins/tracing.js +39 -4
  93. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +7 -0
  94. package/packages/dd-trace/src/plugins/util/test.js +48 -0
  95. package/packages/dd-trace/src/plugins/util/web.js +8 -7
  96. package/packages/dd-trace/src/profiling/exporter_cli.js +1 -0
  97. package/packages/dd-trace/src/propagation-hash/index.js +145 -0
  98. package/packages/dd-trace/src/proxy.js +4 -0
  99. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +1 -1
  100. package/packages/dd-trace/src/startup-log.js +3 -3
  101. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.json +0 -106
  102. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +0 -741
  103. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +0 -11
  104. package/packages/dd-trace/src/plugins/util/serverless.js +0 -8
  105. package/packages/dd-trace/src/scope/noop/scope.js +0 -21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.86.0",
3
+ "version": "5.88.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -16,6 +16,7 @@
16
16
  "lint": "node scripts/check_licenses.js && node scripts/check-no-coverage-artifacts.js && eslint . --concurrency=auto --max-warnings 0",
17
17
  "lint:fix": "node scripts/check_licenses.js && node scripts/check-no-coverage-artifacts.js && eslint . --concurrency=auto --max-warnings 0 --fix",
18
18
  "lint:inspect": "npx @eslint/config-inspector@latest",
19
+ "lint:codeowners": "node scripts/codeowners.mjs",
19
20
  "release:proposal": "node scripts/release/proposal",
20
21
  "services": "node ./scripts/install_plugin_modules && node packages/dd-trace/test/setup/services",
21
22
  "test": "echo '\nError: The root \"npm test\" command is intentionally disabled.\n\nInstead, run specific test suites:\n - npm run test:trace:core\n - npm run test:appsec\n - etc.\n\nOr run individual test files:\n npx mocha path/to/test.spec.js\n\nSee CONTRIBUTING.md (Testing section) for more details.\n' && exit 1",
@@ -134,15 +135,16 @@
134
135
  "import-in-the-middle": "^2.0.6"
135
136
  },
136
137
  "optionalDependencies": {
137
- "@datadog/libdatadog": "0.7.0",
138
- "@datadog/native-appsec": "10.3.0",
138
+ "@datadog/libdatadog": "0.8.1",
139
+ "@datadog/native-appsec": "11.0.1",
139
140
  "@datadog/native-iast-taint-tracking": "4.1.0",
140
141
  "@datadog/native-metrics": "3.1.1",
141
142
  "@datadog/openfeature-node-server": "^0.3.3",
142
- "@datadog/pprof": "5.13.3",
143
+ "@datadog/pprof": "5.13.4",
143
144
  "@datadog/wasm-js-rewriter": "5.0.1",
144
145
  "@opentelemetry/api": ">=1.0.0 <1.10.0",
145
- "@opentelemetry/api-logs": "<1.0.0"
146
+ "@opentelemetry/api-logs": "<1.0.0",
147
+ "oxc-parser": "^0.115.0"
146
148
  },
147
149
  "devDependencies": {
148
150
  "@babel/helpers": "^7.28.6",
@@ -151,6 +153,7 @@
151
153
  "@msgpack/msgpack": "^3.1.3",
152
154
  "@openfeature/core": "^1.8.1",
153
155
  "@openfeature/server-sdk": "~1.20.0",
156
+ "@snyk/github-codeowners": "^1.1.0",
154
157
  "@stylistic/eslint-plugin": "^5.7.1",
155
158
  "@types/mocha": "^10.0.10",
156
159
  "@types/node": "^18.19.106",
@@ -171,6 +174,7 @@
171
174
  "glob": "^10.4.5",
172
175
  "globals": "^17.2.0",
173
176
  "graphql": "*",
177
+ "husky": "^9.1.7",
174
178
  "jszip": "^3.10.1",
175
179
  "mocha": "^11.6.0",
176
180
  "mocha-junit-reporter": "^2.2.1",
@@ -190,7 +194,6 @@
190
194
  "typescript": "^5.9.2",
191
195
  "workerpool": "^10.0.0",
192
196
  "yaml": "^2.8.0",
193
- "husky": "^9.1.7",
194
197
  "yarn-deduplicate": "^6.0.2"
195
198
  }
196
199
  }
@@ -2,45 +2,11 @@
2
2
 
3
3
  const { channel, tracingChannel } = require('dc-polyfill')
4
4
  const shimmer = require('../../datadog-shimmer')
5
- const { addHook } = require('./helpers/instrument')
6
-
7
- const toolCreationChannel = channel('dd-trace:vercel-ai:tool')
8
-
9
- const TRACED_FUNCTIONS = {
10
- generateText: wrapWithTracer,
11
- streamText: wrapWithTracer,
12
- generateObject: wrapWithTracer,
13
- streamObject: wrapWithTracer,
14
- embed: wrapWithTracer,
15
- embedMany: wrapWithTracer,
16
- tool: wrapTool,
17
- }
5
+ const { addHook, getHooks } = require('./helpers/instrument')
18
6
 
19
7
  const vercelAiTracingChannel = tracingChannel('dd-trace:vercel-ai')
20
8
  const vercelAiSpanSetAttributesChannel = channel('dd-trace:vercel-ai:span:setAttributes')
21
9
 
22
- const noopTracer = {
23
- startActiveSpan () {
24
- const fn = arguments[arguments.length - 1]
25
-
26
- const span = {
27
- spanContext () { return { traceId: '', spanId: '', traceFlags: 0 } },
28
- setAttribute () { return this },
29
- setAttributes () { return this },
30
- addEvent () { return this },
31
- addLink () { return this },
32
- addLinks () { return this },
33
- setStatus () { return this },
34
- updateName () { return this },
35
- end () { return this },
36
- isRecording () { return false },
37
- recordException () { return this },
38
- }
39
-
40
- return fn(span)
41
- },
42
- }
43
-
44
10
  const tracers = new WeakSet()
45
11
 
46
12
  function wrapTracer (tracer) {
@@ -63,21 +29,27 @@ function wrapTracer (tracer) {
63
29
 
64
30
  arguments[arguments.length - 1] = shimmer.wrapFunction(cb, function (originalCb) {
65
31
  return function (span) {
66
- shimmer.wrap(span, 'end', function (spanEnd) {
32
+ // the below is necessary in the case that the span is vercel ai's noopSpan.
33
+ // while we don't want to patch the noopSpan more than once, we do want to treat each as a
34
+ // fresh instance. However, this is really not necessary for non-noop spans, but not sure
35
+ // how to differentiate.
36
+ const freshSpan = Object.create(span) // TODO: does this cause memory leaks?
37
+
38
+ shimmer.wrap(freshSpan, 'end', function (spanEnd) {
67
39
  return function () {
68
40
  vercelAiTracingChannel.asyncEnd.publish(ctx)
69
41
  return spanEnd.apply(this, arguments)
70
42
  }
71
43
  })
72
44
 
73
- shimmer.wrap(span, 'setAttributes', function (setAttributes) {
45
+ shimmer.wrap(freshSpan, 'setAttributes', function (setAttributes) {
74
46
  return function (attributes) {
75
47
  vercelAiSpanSetAttributesChannel.publish({ ctx, attributes })
76
48
  return setAttributes.apply(this, arguments)
77
49
  }
78
50
  })
79
51
 
80
- shimmer.wrap(span, 'recordException', function (recordException) {
52
+ shimmer.wrap(freshSpan, 'recordException', function (recordException) {
81
53
  return function (exception) {
82
54
  ctx.error = exception
83
55
  vercelAiTracingChannel.error.publish(ctx)
@@ -85,7 +57,7 @@ function wrapTracer (tracer) {
85
57
  }
86
58
  })
87
59
 
88
- return originalCb.apply(this, arguments)
60
+ return originalCb.call(this, freshSpan)
89
61
  }
90
62
  })
91
63
 
@@ -98,58 +70,50 @@ function wrapTracer (tracer) {
98
70
  })
99
71
  }
100
72
 
101
- function wrapWithTracer (fn) {
102
- return function () {
103
- const options = arguments[0]
104
-
105
- const experimentalTelemetry = options.experimental_telemetry
106
- if (experimentalTelemetry?.isEnabled === false) {
107
- return fn.apply(this, arguments)
108
- }
109
-
110
- if (experimentalTelemetry == null) {
111
- options.experimental_telemetry = { isEnabled: true, tracer: noopTracer }
112
- } else {
113
- experimentalTelemetry.isEnabled = true
114
- experimentalTelemetry.tracer ??= noopTracer
115
- }
116
-
117
- wrapTracer(options.experimental_telemetry.tracer)
118
-
119
- return fn.apply(this, arguments)
73
+ for (const hook of getHooks('ai')) {
74
+ if (hook.file === 'dist/index.js') {
75
+ // if not removed, the below hook will never match correctly
76
+ // however, it is still needed in the orchestrion definition
77
+ hook.file = null
120
78
  }
121
- }
122
-
123
- function wrapTool (tool) {
124
- return function () {
125
- const args = arguments[0]
126
- toolCreationChannel.publish(args)
127
-
128
- return tool.apply(this, arguments)
129
- }
130
- }
131
79
 
132
- // CJS exports
133
- addHook({
134
- name: 'ai',
135
- versions: ['>=4.0.0'],
136
- }, exports => {
137
- for (const [fnName, patchingFn] of Object.entries(TRACED_FUNCTIONS)) {
138
- exports = shimmer.wrap(exports, fnName, patchingFn, { replaceGetter: true })
139
- }
80
+ addHook(hook, exports => {
81
+ const getTracerChannel = tracingChannel('orchestrion:ai:getTracer')
82
+ getTracerChannel.subscribe({
83
+ end (ctx) {
84
+ const { arguments: args, result: tracer } = ctx
85
+ const { isEnabled } = args[0] ?? {}
140
86
 
141
- return exports
142
- })
143
-
144
- // ESM exports
145
- addHook({
146
- name: 'ai',
147
- versions: ['>=4.0.0'],
148
- file: 'dist/index.mjs',
149
- }, exports => {
150
- for (const [fnName, patchingFn] of Object.entries(TRACED_FUNCTIONS)) {
151
- exports = shimmer.wrap(exports, fnName, patchingFn, { replaceGetter: true })
152
- }
87
+ if (isEnabled !== false) {
88
+ wrapTracer(tracer)
89
+ }
90
+ },
91
+ })
92
+
93
+ /**
94
+ * We patch this function to ensure that the telemetry attributes/tags are set always,
95
+ * even when telemetry options are not specified. This is to ensure easy use of this integration.
96
+ *
97
+ * If it is explicitly disabled, however, we will not change the options.
98
+ */
99
+ const selectTelemetryAttributesChannel = tracingChannel('orchestrion:ai:selectTelemetryAttributes')
100
+ selectTelemetryAttributesChannel.subscribe({
101
+ start (ctx) {
102
+ const { arguments: args } = ctx
103
+ const options = args[0]
104
+
105
+ if (options.telemetry?.isEnabled !== false) {
106
+ args[0] = {
107
+ ...options,
108
+ telemetry: {
109
+ ...options.telemetry,
110
+ isEnabled: true,
111
+ },
112
+ }
113
+ }
114
+ },
115
+ })
153
116
 
154
- return exports
155
- })
117
+ return exports
118
+ })
119
+ }
@@ -353,6 +353,20 @@ function wrapRun (pl, isLatestVersion, version) {
353
353
  isEfdRetry = numRetries > 0
354
354
  }
355
355
 
356
+ // Check if all EFD retries failed
357
+ if (isEfdRetry && (isNew || isModified)) {
358
+ const statuses = lastStatusByPickleId.get(this.pickle.id)
359
+ if (statuses.length === earlyFlakeDetectionNumRetries + 1) {
360
+ const { fail } = statuses.reduce((acc, status) => {
361
+ acc[status]++
362
+ return acc
363
+ }, { pass: 0, fail: 0 })
364
+ if (fail === earlyFlakeDetectionNumRetries + 1) {
365
+ hasFailedAllRetries = true
366
+ }
367
+ }
368
+ }
369
+
356
370
  const attemptCtx = numAttemptToCtx.get(numAttempt)
357
371
 
358
372
  const error = getErrorFromCucumberResult(result)
@@ -26,31 +26,37 @@ function Hook (modules, hookOptions, onrequire) {
26
26
  const parts = [moduleBaseDir, moduleName].filter(Boolean)
27
27
  const filename = path.join(...parts)
28
28
 
29
- if (this._patched[filename] && patched.has(moduleExports)) {
30
- return patched.get(moduleExports)
31
- }
32
-
33
29
  let defaultWrapResult
34
30
 
31
+ const wrappedOnrequire = (moduleExports, ...args) => {
32
+ if (this._patched[filename] && patched.has(moduleExports)) {
33
+ return patched.get(moduleExports)
34
+ }
35
+
36
+ const result = onrequire(moduleExports, ...args)
37
+ if (result && (typeof result === 'object' || typeof result === 'function')) {
38
+ patched.set(moduleExports, result)
39
+ patched.set(result, result)
40
+ }
41
+
42
+ return result
43
+ }
44
+
35
45
  if (
36
46
  isIitm &&
37
47
  moduleExports.default &&
38
48
  (typeof moduleExports.default === 'object' ||
39
49
  typeof moduleExports.default === 'function')
40
50
  ) {
41
- defaultWrapResult = onrequire(moduleExports.default, moduleName, moduleBaseDir, moduleVersion, isIitm)
51
+ defaultWrapResult = wrappedOnrequire(moduleExports.default, moduleName, moduleBaseDir, moduleVersion, isIitm)
42
52
  }
43
53
 
44
- const newExports = onrequire(moduleExports, moduleName, moduleBaseDir, moduleVersion, isIitm)
54
+ const newExports = wrappedOnrequire(moduleExports, moduleName, moduleBaseDir, moduleVersion, isIitm)
45
55
 
46
56
  if (defaultWrapResult) newExports.default = defaultWrapResult
47
57
 
48
58
  this._patched[filename] = true
49
- if (newExports &&
50
- (typeof newExports === 'object' ||
51
- typeof newExports === 'function')) {
52
- patched.set(moduleExports, newExports)
53
- }
59
+
54
60
  return newExports
55
61
  }
56
62
 
@@ -136,6 +136,7 @@ module.exports = {
136
136
  'selenium-webdriver': () => require('../selenium'),
137
137
  sequelize: () => require('../sequelize'),
138
138
  sharedb: () => require('../sharedb'),
139
+ stripe: () => require('../stripe'),
139
140
  tedious: () => require('../tedious'),
140
141
  tinypool: { esmFirst: true, fn: () => require('../vitest') },
141
142
  undici: () => require('../undici'),
@@ -1,33 +1,74 @@
1
1
  'use strict'
2
2
 
3
- let meriyah
4
- let astring
5
- let esquery
3
+ const log = require('../../../../dd-trace/src/log')
6
4
 
7
- module.exports = {
8
- parse: (...args) => {
9
- meriyah ??= require('../../../../../vendor/dist/meriyah')
5
+ // eslint-disable-next-line camelcase, no-undef
6
+ const runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
7
+
8
+ const compiler = {
9
+ parse: (sourceText, options) => {
10
+ try {
11
+ // TODO: Figure out ESBuild `createRequire` issue and remove this hack.
12
+ const oxc = runtimeRequire(['oxc', 'parser'].join('-'))
13
+
14
+ compiler.parse = (sourceText, options) => {
15
+ const { program, errors } = oxc.parseSync('index.js', sourceText, {
16
+ ...options,
17
+ preserveParens: false,
18
+ })
19
+
20
+ if (errors?.length > 0) throw errors[0]
21
+
22
+ return program
23
+ }
24
+ } catch (e) {
25
+ log.error(e)
26
+
27
+ // Fallback for when OXC is not available.
28
+ const meriyah = require('../../../../../vendor/dist/meriyah')
10
29
 
11
- return meriyah.parse(...args)
30
+ compiler.parse = (sourceText, { range, sourceType } = {}) => {
31
+ return meriyah.parse(sourceText.toString(), {
32
+ loc: range,
33
+ ranges: range,
34
+ module: sourceType === 'module',
35
+ })
36
+ }
37
+ }
38
+
39
+ return compiler.parse(sourceText, options)
12
40
  },
13
41
 
14
42
  generate: (...args) => {
15
- astring ??= require('../../../../../vendor/dist/astring')
43
+ const astring = require('../../../../../vendor/dist/astring')
44
+
45
+ compiler.generate = astring.generate
16
46
 
17
- return astring.generate(...args)
47
+ return compiler.generate(...args)
18
48
  },
19
49
 
20
50
  traverse: (ast, query, visitor) => {
21
- esquery ??= require('../../../../../vendor/dist/esquery').default
51
+ const esquery = require('../../../../../vendor/dist/esquery').default
22
52
 
23
- const selector = esquery.parse(query)
53
+ compiler.traverse = (ast, query, visitor) => {
54
+ return esquery.traverse(ast, esquery.parse(query), visitor)
55
+ }
24
56
 
25
- return esquery.traverse(ast, selector, visitor)
57
+ return compiler.traverse(ast, query, visitor)
26
58
  },
27
59
 
28
60
  query: (ast, query) => {
29
- esquery ??= require('../../../../../vendor/dist/esquery').default
61
+ const esquery = require('../../../../../vendor/dist/esquery').default
62
+
63
+ compiler.query = esquery.query
30
64
 
31
- return esquery.query(ast, query)
65
+ return compiler.query(ast, query)
32
66
  },
33
67
  }
68
+
69
+ module.exports = {
70
+ parse: (...args) => compiler.parse(...args),
71
+ generate: (...args) => compiler.generate(...args),
72
+ traverse: (...args) => compiler.traverse(...args),
73
+ query: (...args) => compiler.query(...args),
74
+ }
@@ -29,6 +29,7 @@ Orchestrion-JS that will need to be backported:
29
29
  is not a function. We'll see over time if something like this is needed to be
30
30
  backported or if it can be replaced by simpler queries.
31
31
  - Supports replacing methods of child class instances in the base constructor.
32
+ - Supports tracing iterator (sync/async) returning functions (sync/async).
32
33
  */
33
34
 
34
35
  const { readFileSync } = require('fs')
@@ -36,12 +37,13 @@ const { join } = require('path')
36
37
  const semifies = require('../../../../../vendor/dist/semifies')
37
38
  const log = require('../../../../dd-trace/src/log')
38
39
  const { getEnvironmentVariable } = require('../../../../dd-trace/src/config/helper')
39
- const transforms = require('./transforms')
40
+ const { transform } = require('./transformer')
40
41
  const { generate, parse, traverse } = require('./compiler')
41
42
  const instrumentations = require('./instrumentations')
42
43
 
43
44
  const NODE_OPTIONS = getEnvironmentVariable('NODE_OPTIONS')
44
45
 
46
+ /** @type {Record<string, Set<string>>} map of module base name to supported function query versions */
45
47
  const supported = {}
46
48
  const disabled = new Set()
47
49
 
@@ -54,6 +56,8 @@ let SourceMapGenerator
54
56
  function rewrite (content, filename, format) {
55
57
  if (!content) return content
56
58
 
59
+ const sourceType = format === 'module' ? 'module' : 'script'
60
+
57
61
  try {
58
62
  let ast
59
63
 
@@ -61,19 +65,15 @@ function rewrite (content, filename, format) {
61
65
 
62
66
  for (const inst of instrumentations) {
63
67
  const { astQuery, functionQuery = {}, module: { name, versionRange, filePath } } = inst
64
- const { kind } = functionQuery
65
- const operator = kind === 'Async' ? 'tracePromise' : kind === 'Callback' ? 'traceCallback' : 'traceSync'
66
- const transform = transforms[operator]
67
68
 
68
69
  if (disabled.has(name)) continue
69
70
  if (!filename.endsWith(`${name}/${filePath}`)) continue
70
- if (!transform) continue
71
71
  if (!satisfies(filename, filePath, versionRange)) continue
72
72
 
73
- ast ??= parse(content.toString(), { loc: true, ranges: true, module: format === 'module' })
73
+ ast ??= parse(content.toString(), { range: true, sourceType })
74
74
 
75
75
  const query = astQuery || fromFunctionQuery(functionQuery)
76
- const state = { ...inst, format, functionQuery, operator }
76
+ const state = { ...inst, sourceType, functionQuery }
77
77
 
78
78
  traverse(ast, query, (...args) => transform(state, ...args))
79
79
  }
@@ -104,19 +104,21 @@ function disable (instrumentation) {
104
104
  function satisfies (filename, filePath, versions) {
105
105
  const [basename] = filename.split(filePath)
106
106
 
107
- if (supported[basename] === undefined) {
107
+ supported[basename] ??= new Set()
108
+
109
+ if (!supported[basename].has(versions)) {
108
110
  try {
109
111
  const pkg = JSON.parse(readFileSync(
110
112
  join(basename, 'package.json'), 'utf8'
111
113
  ))
112
114
 
113
- supported[basename] = semifies(pkg.version, versions)
114
- } catch {
115
- supported[basename] = false
116
- }
115
+ if (semifies(pkg.version, versions)) {
116
+ supported[basename].add(versions)
117
+ }
118
+ } catch {}
117
119
  }
118
120
 
119
- return supported[basename]
121
+ return supported[basename].has(versions)
120
122
  }
121
123
 
122
124
  // TODO: Support index
@@ -0,0 +1,103 @@
1
+ 'use strict'
2
+
3
+ module.exports = [
4
+ // getTracer - for patching tracer
5
+ {
6
+ module: {
7
+ name: 'ai',
8
+ versionRange: '>=4.0.0',
9
+ filePath: 'dist/index.js',
10
+ },
11
+ functionQuery: {
12
+ functionName: 'getTracer',
13
+ kind: 'Sync',
14
+ },
15
+ channelName: 'getTracer',
16
+ },
17
+ {
18
+ module: {
19
+ name: 'ai',
20
+ versionRange: '>=4.0.0',
21
+ filePath: 'dist/index.mjs',
22
+ },
23
+ functionQuery: {
24
+ functionName: 'getTracer',
25
+ kind: 'Sync',
26
+ },
27
+ channelName: 'getTracer',
28
+ },
29
+ // selectTelemetryAttributes - makes sure we set isEnabled properly
30
+ {
31
+ module: {
32
+ name: 'ai',
33
+ versionRange: '>=4.0.0 <6.0.0',
34
+ filePath: 'dist/index.js',
35
+ },
36
+ functionQuery: {
37
+ functionName: 'selectTelemetryAttributes',
38
+ kind: 'Sync',
39
+ },
40
+ channelName: 'selectTelemetryAttributes',
41
+ },
42
+ {
43
+ module: {
44
+ name: 'ai',
45
+ versionRange: '>=4.0.0 <6.0.0',
46
+ filePath: 'dist/index.mjs',
47
+ },
48
+ functionQuery: {
49
+ functionName: 'selectTelemetryAttributes',
50
+ kind: 'Sync',
51
+ },
52
+ channelName: 'selectTelemetryAttributes',
53
+ },
54
+ {
55
+ module: {
56
+ name: 'ai',
57
+ versionRange: '>=6.0.0',
58
+ filePath: 'dist/index.js',
59
+ },
60
+ functionQuery: {
61
+ functionName: 'selectTelemetryAttributes',
62
+ kind: 'Async',
63
+ },
64
+ channelName: 'selectTelemetryAttributes',
65
+ },
66
+ {
67
+ module: {
68
+ name: 'ai',
69
+ versionRange: '>=6.0.0',
70
+ filePath: 'dist/index.mjs',
71
+ },
72
+ functionQuery: {
73
+ functionName: 'selectTelemetryAttributes',
74
+ kind: 'Async',
75
+ },
76
+ channelName: 'selectTelemetryAttributes',
77
+ },
78
+ // tool
79
+ {
80
+ module: {
81
+ name: 'ai',
82
+ versionRange: '>=4.0.0',
83
+ filePath: 'dist/index.js',
84
+ },
85
+ functionQuery: {
86
+ functionName: 'tool',
87
+ kind: 'Sync',
88
+ },
89
+ channelName: 'tool',
90
+ },
91
+ {
92
+ module: {
93
+ name: 'ai',
94
+ versionRange: '>=4.0.0',
95
+ filePath: 'dist/index.mjs',
96
+ },
97
+ functionQuery: {
98
+ functionName: 'tool',
99
+ kind: 'Sync',
100
+ },
101
+ channelName: 'tool',
102
+ },
103
+ ]