dd-trace 5.74.0 → 5.75.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.
@@ -14,6 +14,7 @@ require,@opentelemetry/resources,Apache license 2.0,Copyright OpenTelemetry Auth
14
14
  require,@isaacs/ttlcache,ISC,Copyright (c) 2022-2023 - Isaac Z. Schlueter and Contributors
15
15
  require,crypto-randomuuid,MIT,Copyright 2021 Node.js Foundation and contributors
16
16
  require,dc-polyfill,MIT,Copyright 2023 Datadog Inc.
17
+ require,escape-string-regexp,MIT,Copyright Sindre Sorhus
17
18
  require,ignore,MIT,Copyright 2013 Kael Zhang and contributors
18
19
  require,import-in-the-middle,Apache license 2.0,Copyright 2021 Datadog Inc.
19
20
  require,istanbul-lib-coverage,BSD-3-Clause,Copyright 2012-2015 Yahoo! Inc.
package/index.d.ts CHANGED
@@ -181,6 +181,7 @@ interface Tracer extends opentracing.Tracer {
181
181
  /** @hidden */
182
182
  interface Plugins {
183
183
  "aerospike": tracer.plugins.aerospike;
184
+ "ai": tracer.plugins.ai;
184
185
  "amqp10": tracer.plugins.amqp10;
185
186
  "amqplib": tracer.plugins.amqplib;
186
187
  "anthropic": tracer.plugins.anthropic;
@@ -1642,6 +1643,12 @@ declare namespace tracer {
1642
1643
  */
1643
1644
  interface aerospike extends Instrumentation {}
1644
1645
 
1646
+ /**
1647
+ * This plugin automatically instruments the
1648
+ * [Vercel AI SDK](https://ai-sdk.dev/docs/introduction) module.
1649
+ */
1650
+ interface ai extends Instrumentation {}
1651
+
1645
1652
  /**
1646
1653
  * This plugin automatically instruments the
1647
1654
  * [amqp10](https://github.com/noodlefrenzy/node-amqp10) module.
@@ -1698,12 +1705,6 @@ declare namespace tracer {
1698
1705
  * [aws-sdk](https://github.com/aws/aws-sdk-js) module.
1699
1706
  */
1700
1707
  interface aws_sdk extends Instrumentation {
1701
- /**
1702
- * Whether to add a suffix to the service name so that each AWS service has its own service name.
1703
- * @default true
1704
- */
1705
- splitByAwsService?: boolean;
1706
-
1707
1708
  /**
1708
1709
  * Whether to inject all messages during batch AWS SQS, Kinesis, and SNS send operations. Normal
1709
1710
  * behavior is to inject the first message in batch send operations.
@@ -2821,7 +2822,10 @@ declare namespace tracer {
2821
2822
  redactionValuePattern?: string,
2822
2823
 
2823
2824
  /**
2824
- * Allows to enable security controls.
2825
+ * Allows to enable security controls. This option is not supported when
2826
+ * using ESM.
2827
+ * @deprecated Please use the DD_IAST_SECURITY_CONTROLS_CONFIGURATION
2828
+ * environment variable instead.
2825
2829
  */
2826
2830
  securityControlsConfiguration?: string,
2827
2831
 
package/loader-hook.mjs CHANGED
@@ -1 +1,52 @@
1
- export * from 'import-in-the-middle/hook.mjs'
1
+ import regexpEscape from 'escape-string-regexp'
2
+ import * as iitm from 'import-in-the-middle/hook.mjs'
3
+ import hooks from './packages/datadog-instrumentations/src/helpers/hooks.js'
4
+ import configHelper from './packages/dd-trace/src/config-helper.js'
5
+
6
+ // For some reason `getEnvironmentVariable` is not otherwise available to ESM.
7
+ const env = configHelper.getEnvironmentVariable
8
+
9
+ function initialize (data = {}) {
10
+ data.include ??= []
11
+ data.exclude ??= []
12
+
13
+ addInstrumentations(data)
14
+ addSecurityControls(data)
15
+ addExclusions(data)
16
+
17
+ return iitm.initialize(data)
18
+ }
19
+
20
+ function addInstrumentations (data) {
21
+ const instrumentations = Object.keys(hooks)
22
+
23
+ for (const moduleName of instrumentations) {
24
+ data.include.push(new RegExp(`node_modules/${moduleName}/(?!node_modules).+`), moduleName)
25
+ }
26
+ }
27
+
28
+ function addSecurityControls (data) {
29
+ const securityControls = (env('DD_IAST_SECURITY_CONTROLS_CONFIGURATION') || '')
30
+ .split(';')
31
+ .map(sc => sc.trim().split(':')[2])
32
+ .filter(Boolean)
33
+ .map(sc => sc.trim())
34
+
35
+ for (const subpath of securityControls) {
36
+ data.include.push(new RegExp(regexpEscape(subpath)))
37
+ }
38
+ }
39
+
40
+ function addExclusions (data) {
41
+ data.exclude.push(
42
+ /middle/,
43
+ /langsmith/,
44
+ /openai\/_shims/,
45
+ /openai\/resources\/chat\/completions\/messages/,
46
+ /openai\/agents-core\/dist\/shims/,
47
+ /@anthropic-ai\/sdk\/_shims/
48
+ )
49
+ }
50
+
51
+ export { initialize }
52
+ export { load, getFormat, resolve, getSource } from 'import-in-the-middle/hook.mjs'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.74.0",
3
+ "version": "5.75.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -136,6 +136,7 @@
136
136
  "@opentelemetry/resources": ">=1.0.0 <1.10.0",
137
137
  "crypto-randomuuid": "^1.0.0",
138
138
  "dc-polyfill": "^0.1.10",
139
+ "escape-string-regexp": "^5.0.0",
139
140
  "ignore": "^7.0.5",
140
141
  "import-in-the-middle": "^1.14.2",
141
142
  "istanbul-lib-coverage": "^3.2.2",
@@ -158,25 +159,13 @@
158
159
  "tlhunter-sorted-set": "^0.1.0",
159
160
  "ttl-set": "^1.0.0"
160
161
  },
161
- "peerDependencies": {
162
- "@openfeature/core": "^1.9.0",
163
- "@openfeature/server-sdk": "~1.20.0"
164
- },
165
- "peerDependenciesMeta": {
166
- "@openfeature/core": {
167
- "optional": true
168
- },
169
- "@openfeature/server-sdk": {
170
- "optional": true
171
- }
172
- },
173
162
  "devDependencies": {
174
163
  "@babel/helpers": "^7.27.6",
175
164
  "@eslint/eslintrc": "^3.3.1",
176
165
  "@eslint/js": "^9.29.0",
177
166
  "@msgpack/msgpack": "^3.1.2",
178
- "@openfeature/core": "^1.8.1",
179
- "@openfeature/server-sdk": "~1.20.0",
167
+ "@openfeature/core": "^1.9.0",
168
+ "@openfeature/server-sdk": "^1.20.0",
180
169
  "@stylistic/eslint-plugin": "^5.0.0",
181
170
  "@types/chai": "^4.3.16",
182
171
  "@types/mocha": "^10.0.10",
@@ -214,7 +203,7 @@
214
203
  "tap": "^16.3.10",
215
204
  "tiktoken": "^1.0.21",
216
205
  "typescript": "^5.9.2",
217
- "workerpool": "^9.2.0",
206
+ "workerpool": "^10.0.0",
218
207
  "yaml": "^2.8.0",
219
208
  "yarn-deduplicate": "^6.0.2"
220
209
  }
@@ -114,6 +114,7 @@ ${build.initialOptions.banner.js}`
114
114
  }
115
115
 
116
116
  try {
117
+ // eslint-disable-next-line n/no-unpublished-require
117
118
  require.resolve('@openfeature/core')
118
119
  } catch (error) {
119
120
  build.initialOptions.external ??= []
@@ -25,8 +25,6 @@ addHook({
25
25
  name: 'cookie-parser',
26
26
  versions: ['>=1.0.0']
27
27
  }, cookieParser => {
28
- // This prevents the non default export from entering the wrapping process
29
- if (cookieParser.default) return cookieParser
30
28
  return shimmer.wrapFunction(cookieParser, cookieParser => function () {
31
29
  const cookieMiddleware = cookieParser.apply(this, arguments)
32
30
 
@@ -259,7 +259,7 @@ function wrapRun (pl, isLatestVersion, version) {
259
259
  testStartCh.runStores(ctx, () => {})
260
260
  const promises = {}
261
261
  try {
262
- this.eventBroadcaster.on('envelope', shimmer.wrapFunction(null, () => async (testCase) => {
262
+ this.eventBroadcaster.on('envelope', async (testCase) => {
263
263
  // Only supported from >=8.0.0
264
264
  if (testCase?.testCaseFinished) {
265
265
  const { testCaseFinished: { willBeRetried } } = testCase
@@ -289,7 +289,7 @@ function wrapRun (pl, isLatestVersion, version) {
289
289
  testStartCh.runStores(newCtx, () => {})
290
290
  }
291
291
  }
292
- }))
292
+ })
293
293
  let promise
294
294
 
295
295
  testFnCh.runStores(ctx, () => {
@@ -37,6 +37,5 @@ addHook({
37
37
  name: 'express-session',
38
38
  versions: ['>=1.5.0']
39
39
  }, session => {
40
- if (session.default) return session
41
40
  return shimmer.wrapFunction(session, wrapSession)
42
41
  })
@@ -82,12 +82,7 @@ function createWrapQueryCallback (options) {
82
82
 
83
83
  const cb = arguments[arguments.length - 1]
84
84
  const ctx = { sql, conf: options }
85
-
86
- if (typeof cb !== 'function') {
87
- arguments.length += 1
88
- }
89
-
90
- arguments[arguments.length - 1] = shimmer.wrapFunction(cb, cb => function (err) {
85
+ const wrapper = (cb) => function (err) {
91
86
  if (err) {
92
87
  ctx.error = err
93
88
  errorCh.publish(ctx)
@@ -96,7 +91,14 @@ function createWrapQueryCallback (options) {
96
91
  return typeof cb === 'function'
97
92
  ? finishCh.runStores(ctx, cb, this, ...arguments)
98
93
  : finishCh.publish(ctx)
99
- })
94
+ }
95
+
96
+ if (typeof cb === 'function') {
97
+ arguments[arguments.length - 1] = shimmer.wrapFunction(cb, wrapper)
98
+ } else {
99
+ arguments.length += 1
100
+ arguments[arguments.length - 1] = wrapper()
101
+ }
100
102
 
101
103
  return startCh.runStores(ctx, query, this, ...arguments)
102
104
  }
@@ -15,6 +15,7 @@ const { DD_MAJOR } = require('../../../version')
15
15
 
16
16
  const testStartCh = channel('ci:playwright:test:start')
17
17
  const testFinishCh = channel('ci:playwright:test:finish')
18
+ const testSkipCh = channel('ci:playwright:test:skip')
18
19
 
19
20
  const testSessionStartCh = channel('ci:playwright:session:start')
20
21
  const testSessionFinishCh = channel('ci:playwright:session:finish')
@@ -37,6 +38,8 @@ const testSuiteToTestStatuses = new Map()
37
38
  const testSuiteToErrors = new Map()
38
39
  const testsToTestStatuses = new Map()
39
40
 
41
+ const RUM_FLUSH_WAIT_TIME = 1000
42
+
40
43
  let applyRepeatEachIndex = null
41
44
 
42
45
  let startedSuites = []
@@ -285,7 +288,12 @@ function getTestFullname (test) {
285
288
  return names.join(' ')
286
289
  }
287
290
 
288
- function testBeginHandler (test, browserName, isMainProcess) {
291
+ function shouldFinishTestSuite (testSuiteAbsolutePath) {
292
+ const remainingTests = remainingTestsByFile[testSuiteAbsolutePath]
293
+ return !remainingTests.length || remainingTests.every(test => test.expectedStatus === 'skipped')
294
+ }
295
+
296
+ function testBeginHandler (test, browserName, shouldCreateTestSpan) {
289
297
  const {
290
298
  _requireFile: testSuiteAbsolutePath,
291
299
  location: {
@@ -297,6 +305,10 @@ function testBeginHandler (test, browserName, isMainProcess) {
297
305
  if (_type === 'beforeAll' || _type === 'afterAll') {
298
306
  return
299
307
  }
308
+ // this means that a skipped test is being handled
309
+ if (!remainingTestsByFile[testSuiteAbsolutePath].length) {
310
+ return
311
+ }
300
312
 
301
313
  const isNewTestSuite = !startedSuites.includes(testSuiteAbsolutePath)
302
314
 
@@ -313,7 +325,7 @@ function testBeginHandler (test, browserName, isMainProcess) {
313
325
  }
314
326
 
315
327
  // this handles tests that do not go through the worker process (because they're skipped)
316
- if (isMainProcess) {
328
+ if (shouldCreateTestSpan) {
317
329
  const testName = getTestFullname(test)
318
330
  const testCtx = {
319
331
  testName,
@@ -328,8 +340,20 @@ function testBeginHandler (test, browserName, isMainProcess) {
328
340
  }
329
341
  }
330
342
 
331
- function testEndHandler (test, annotations, testStatus, error, isTimeout, isMainProcess) {
332
- const { _requireFile: testSuiteAbsolutePath, results, _type } = test
343
+ function testEndHandler ({
344
+ test,
345
+ annotations,
346
+ testStatus,
347
+ error,
348
+ isTimeout,
349
+ shouldCreateTestSpan,
350
+ projects
351
+ }) {
352
+ const {
353
+ _requireFile: testSuiteAbsolutePath,
354
+ results,
355
+ _type,
356
+ } = test
333
357
 
334
358
  let annotationTags
335
359
  if (annotations.length) {
@@ -368,31 +392,34 @@ function testEndHandler (test, annotations, testStatus, error, isTimeout, isMain
368
392
  }
369
393
 
370
394
  // this handles tests that do not go through the worker process (because they're skipped)
371
- if (isMainProcess) {
395
+ if (shouldCreateTestSpan) {
372
396
  const testResult = results.at(-1)
373
397
  const testCtx = testToCtx.get(test)
374
398
  const isAtrRetry = testResult?.retry > 0 &&
375
399
  isFlakyTestRetriesEnabled &&
376
400
  !test._ddIsAttemptToFix &&
377
401
  !test._ddIsEfdRetry
378
- testFinishCh.publish({
379
- testStatus,
380
- steps: testResult?.steps || [],
381
- isRetry: testResult?.retry > 0,
382
- error,
383
- extraTags: annotationTags,
384
- isNew: test._ddIsNew,
385
- isAttemptToFix: test._ddIsAttemptToFix,
386
- isAttemptToFixRetry: test._ddIsAttemptToFixRetry,
387
- isQuarantined: test._ddIsQuarantined,
388
- isEfdRetry: test._ddIsEfdRetry,
389
- hasFailedAllRetries: test._ddHasFailedAllRetries,
390
- hasPassedAttemptToFixRetries: test._ddHasPassedAttemptToFixRetries,
391
- hasFailedAttemptToFixRetries: test._ddHasFailedAttemptToFixRetries,
392
- isAtrRetry,
393
- isModified: test._ddIsModified,
394
- ...testCtx.currentStore
395
- })
402
+ // if there is no testCtx, the skipped test will be created later
403
+ if (testCtx) {
404
+ testFinishCh.publish({
405
+ testStatus,
406
+ steps: testResult?.steps || [],
407
+ isRetry: testResult?.retry > 0,
408
+ error,
409
+ extraTags: annotationTags,
410
+ isNew: test._ddIsNew,
411
+ isAttemptToFix: test._ddIsAttemptToFix,
412
+ isAttemptToFixRetry: test._ddIsAttemptToFixRetry,
413
+ isQuarantined: test._ddIsQuarantined,
414
+ isEfdRetry: test._ddIsEfdRetry,
415
+ hasFailedAllRetries: test._ddHasFailedAllRetries,
416
+ hasPassedAttemptToFixRetries: test._ddHasPassedAttemptToFixRetries,
417
+ hasFailedAttemptToFixRetries: test._ddHasFailedAttemptToFixRetries,
418
+ isAtrRetry,
419
+ isModified: test._ddIsModified,
420
+ ...testCtx.currentStore
421
+ })
422
+ }
396
423
  }
397
424
 
398
425
  if (testSuiteToTestStatuses.has(testSuiteAbsolutePath)) {
@@ -410,8 +437,25 @@ function testEndHandler (test, annotations, testStatus, error, isTimeout, isMain
410
437
  .filter(currentTest => currentTest !== test)
411
438
  }
412
439
 
413
- // Last test, we finish the suite
414
- if (!remainingTestsByFile[testSuiteAbsolutePath].length) {
440
+ if (shouldFinishTestSuite(testSuiteAbsolutePath)) {
441
+ const skippedTests = remainingTestsByFile[testSuiteAbsolutePath]
442
+ .filter(test => test.expectedStatus === 'skipped')
443
+
444
+ for (const test of skippedTests) {
445
+ const browserName = getBrowserNameFromProjects(projects, test)
446
+ testSkipCh.publish({
447
+ testName: getTestFullname(test),
448
+ testSuiteAbsolutePath,
449
+ testSourceLine: test.location.line,
450
+ browserName,
451
+ isNew: test._ddIsNew,
452
+ isDisabled: test._ddIsDisabled,
453
+ isModified: test._ddIsModified,
454
+ isQuarantined: test._ddIsQuarantined
455
+ })
456
+ }
457
+ remainingTestsByFile[testSuiteAbsolutePath] = []
458
+
415
459
  const testStatuses = testSuiteToTestStatuses.get(testSuiteAbsolutePath)
416
460
  let testSuiteStatus = 'pass'
417
461
  if (testStatuses.includes('fail')) {
@@ -450,10 +494,13 @@ function dispatcherHook (dispatcherExport) {
450
494
  shimmer.wrap(dispatcherExport.Dispatcher.prototype, '_createWorker', createWorker => function () {
451
495
  const dispatcher = this
452
496
  const worker = createWorker.apply(this, arguments)
497
+ const projects = getProjectsFromDispatcher(dispatcher)
498
+
499
+ // for older versions of playwright, `shouldCreateTestSpan` should always be true,
500
+ // since the `_runTest` function wrapper is not available for older versions
453
501
  worker.process.on('message', ({ method, params }) => {
454
502
  if (method === 'testBegin') {
455
503
  const { test } = dispatcher._testById.get(params.testId)
456
- const projects = getProjectsFromDispatcher(dispatcher)
457
504
  const browser = getBrowserNameFromProjects(projects, test)
458
505
  testBeginHandler(test, browser, true)
459
506
  } else if (method === 'testEnd') {
@@ -464,12 +511,15 @@ function dispatcherHook (dispatcherExport) {
464
511
 
465
512
  const isTimeout = testResult.status === 'timedOut'
466
513
  testEndHandler(
467
- test,
468
- params.annotations,
469
- STATUS_TO_TEST_STATUS[testResult.status],
470
- testResult.error,
471
- isTimeout,
472
- true
514
+ {
515
+ test,
516
+ annotations: params.annotations,
517
+ testStatus: STATUS_TO_TEST_STATUS[testResult.status],
518
+ error: testResult.error,
519
+ isTimeout,
520
+ shouldCreateTestSpan: true,
521
+ projects
522
+ }
473
523
  )
474
524
  }
475
525
  })
@@ -484,18 +534,30 @@ function dispatcherHookNew (dispatcherExport, runWrapper) {
484
534
  shimmer.wrap(dispatcherExport.Dispatcher.prototype, '_createWorker', createWorker => function () {
485
535
  const dispatcher = this
486
536
  const worker = createWorker.apply(this, arguments)
537
+ const projects = getProjectsFromDispatcher(dispatcher)
487
538
 
488
539
  worker.on('testBegin', ({ testId }) => {
489
540
  const test = getTestByTestId(dispatcher, testId)
490
- const projects = getProjectsFromDispatcher(dispatcher)
491
541
  const browser = getBrowserNameFromProjects(projects, test)
492
- testBeginHandler(test, browser, false)
542
+ const shouldCreateTestSpan = test.expectedStatus === 'skipped'
543
+ testBeginHandler(test, browser, shouldCreateTestSpan)
493
544
  })
494
545
  worker.on('testEnd', ({ testId, status, errors, annotations }) => {
495
546
  const test = getTestByTestId(dispatcher, testId)
496
547
 
497
548
  const isTimeout = status === 'timedOut'
498
- testEndHandler(test, annotations, STATUS_TO_TEST_STATUS[status], errors && errors[0], isTimeout, false)
549
+ const shouldCreateTestSpan = test.expectedStatus === 'skipped'
550
+ testEndHandler(
551
+ {
552
+ test,
553
+ annotations,
554
+ testStatus: STATUS_TO_TEST_STATUS[status],
555
+ error: errors && errors[0],
556
+ isTimeout,
557
+ shouldCreateTestSpan,
558
+ projects
559
+ }
560
+ )
499
561
  const testResult = test.results.at(-1)
500
562
  const isAtrRetry = testResult?.retry > 0 &&
501
563
  isFlakyTestRetriesEnabled &&
@@ -625,6 +687,9 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
625
687
 
626
688
  let runAllTestsReturn = await runAllTests.apply(this, arguments)
627
689
 
690
+ // Tests that have only skipped tests may reach this point
691
+ // Skipped tests may or may not go through `testBegin` or `testEnd`
692
+ // depending on the playwright configuration
628
693
  Object.values(remainingTestsByFile).forEach(tests => {
629
694
  // `tests` should normally be empty, but if it isn't,
630
695
  // there were tests that did not go through `testBegin` or `testEnd`,
@@ -632,7 +697,15 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
632
697
  tests.forEach(test => {
633
698
  const browser = getBrowserNameFromProjects(projects, test)
634
699
  testBeginHandler(test, browser, true)
635
- testEndHandler(test, [], 'skip', null, false, true)
700
+ testEndHandler({
701
+ test,
702
+ annotations: [],
703
+ testStatus: 'skip',
704
+ error: null,
705
+ isTimeout: false,
706
+ shouldCreateTestSpan: true,
707
+ projects
708
+ })
636
709
  })
637
710
  })
638
711
 
@@ -1007,6 +1080,9 @@ addHook({
1007
1080
  const stepInfoByStepId = {}
1008
1081
 
1009
1082
  shimmer.wrap(workerPackage.WorkerMain.prototype, '_runTest', _runTest => async function (test) {
1083
+ if (test.expectedStatus === 'skipped') {
1084
+ return _runTest.apply(this, arguments)
1085
+ }
1010
1086
  steps = []
1011
1087
 
1012
1088
  const {
@@ -1060,6 +1136,8 @@ addHook({
1060
1136
  })
1061
1137
 
1062
1138
  if (isRumActive) {
1139
+ // Give some time RUM to flush data, similar to what we do in selenium
1140
+ await new Promise(resolve => setTimeout(resolve, RUM_FLUSH_WAIT_TIME))
1063
1141
  const url = page.url()
1064
1142
  if (url) {
1065
1143
  const domain = new URL(url).hostname
@@ -1067,9 +1145,10 @@ addHook({
1067
1145
  name: 'datadog-ci-visibility-test-execution-id',
1068
1146
  value: '',
1069
1147
  domain,
1070
- expires: 0,
1071
1148
  path: '/'
1072
1149
  }])
1150
+ } else {
1151
+ log.error('RUM is active but page.url() is not available')
1073
1152
  }
1074
1153
  }
1075
1154
  }
@@ -153,6 +153,10 @@ function isCliApiPackage (vitestPackage) {
153
153
  return vitestPackage.s?.name === 'startVitest'
154
154
  }
155
155
 
156
+ function isTestPackage (testPackage) {
157
+ return testPackage.V?.name === 'VitestTestRunner'
158
+ }
159
+
156
160
  function getSessionStatus (state) {
157
161
  if (state.getCountOfFailedTests() > 0) {
158
162
  return 'fail'
@@ -240,7 +244,9 @@ function getSortWrapper (sort, frameworkVersion) {
240
244
  if (isFlakyTestRetriesEnabled && !this.ctx.config.retry && flakyTestRetriesCount > 0) {
241
245
  this.ctx.config.retry = flakyTestRetriesCount
242
246
  try {
243
- const workspaceProject = this.ctx.getCoreWorkspaceProject()
247
+ const workspaceProject = this.ctx.getCoreWorkspaceProject
248
+ ? this.ctx.getCoreWorkspaceProject()
249
+ : this.ctx.getRootProject()
244
250
  workspaceProject._provided._ddIsFlakyTestRetriesEnabled = isFlakyTestRetriesEnabled
245
251
  } catch {
246
252
  log.warn('Could not send library configuration to workers.')
@@ -272,7 +278,9 @@ function getSortWrapper (sort, frameworkVersion) {
272
278
  // TODO: use this to pass session and module IDs to the worker, instead of polluting process.env
273
279
  // Note: setting this.ctx.config.provide directly does not work because it's cached
274
280
  try {
275
- const workspaceProject = this.ctx.getCoreWorkspaceProject()
281
+ const workspaceProject = this.ctx.getCoreWorkspaceProject
282
+ ? this.ctx.getCoreWorkspaceProject()
283
+ : this.ctx.getRootProject()
276
284
  workspaceProject._provided._ddIsKnownTestsEnabled = isKnownTestsEnabled
277
285
  workspaceProject._provided._ddKnownTests = knownTests
278
286
  workspaceProject._provided._ddIsEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
@@ -290,7 +298,9 @@ function getSortWrapper (sort, frameworkVersion) {
290
298
 
291
299
  if (isDiEnabled) {
292
300
  try {
293
- const workspaceProject = this.ctx.getCoreWorkspaceProject()
301
+ const workspaceProject = this.ctx.getCoreWorkspaceProject
302
+ ? this.ctx.getCoreWorkspaceProject()
303
+ : this.ctx.getRootProject()
294
304
  workspaceProject._provided._ddIsDiEnabled = isDiEnabled
295
305
  } catch {
296
306
  log.warn('Could not send Dynamic Instrumentation configuration to workers.')
@@ -305,7 +315,9 @@ function getSortWrapper (sort, frameworkVersion) {
305
315
  } else {
306
316
  const testManagementTests = receivedTestManagementTests
307
317
  try {
308
- const workspaceProject = this.ctx.getCoreWorkspaceProject()
318
+ const workspaceProject = this.ctx.getCoreWorkspaceProject
319
+ ? this.ctx.getCoreWorkspaceProject()
320
+ : this.ctx.getRootProject()
309
321
  workspaceProject._provided._ddIsTestManagementTestsEnabled = isTestManagementTestsEnabled
310
322
  workspaceProject._provided._ddTestManagementAttemptToFixRetries = testManagementAttemptToFixRetries
311
323
  workspaceProject._provided._ddTestManagementTests = testManagementTests
@@ -321,7 +333,9 @@ function getSortWrapper (sort, frameworkVersion) {
321
333
  log.error('Could not get modified tests.')
322
334
  } else {
323
335
  try {
324
- const workspaceProject = this.ctx.getCoreWorkspaceProject()
336
+ const workspaceProject = this.ctx.getCoreWorkspaceProject
337
+ ? this.ctx.getCoreWorkspaceProject()
338
+ : this.ctx.getRootProject()
325
339
  workspaceProject._provided._ddIsImpactedTestsEnabled = isImpactedTestsEnabled
326
340
  workspaceProject._provided._ddModifiedFiles = modifiedFiles
327
341
  } catch {
@@ -443,13 +457,7 @@ function getStartVitestWrapper (cliApiPackage, frameworkVersion) {
443
457
  return cliApiPackage
444
458
  }
445
459
 
446
- addHook({
447
- name: 'vitest',
448
- versions: ['>=1.6.0'],
449
- file: 'dist/runners.js'
450
- }, (vitestPackage) => {
451
- const { VitestTestRunner } = vitestPackage
452
-
460
+ function wrapVitestTestRunner (VitestTestRunner) {
453
461
  // `onBeforeRunTask` is run before any repetition or attempt is run
454
462
  // `onBeforeRunTask` is an async function
455
463
  shimmer.wrap(VitestTestRunner.prototype, 'onBeforeRunTask', onBeforeRunTask => function (task) {
@@ -744,6 +752,30 @@ addHook({
744
752
 
745
753
  return result
746
754
  })
755
+ }
756
+
757
+ addHook({
758
+ name: 'vitest',
759
+ versions: ['>=4.0.0'],
760
+ filePattern: 'dist/chunks/test.*'
761
+ }, (testPackage) => {
762
+ if (!isTestPackage(testPackage)) {
763
+ return testPackage
764
+ }
765
+
766
+ wrapVitestTestRunner(testPackage.V)
767
+
768
+ return testPackage
769
+ })
770
+
771
+ addHook({
772
+ name: 'vitest',
773
+ versions: ['>=1.6.0 <4.0.0'],
774
+ file: 'dist/runners.js'
775
+ }, (vitestPackage) => {
776
+ const { VitestTestRunner } = vitestPackage
777
+
778
+ wrapVitestTestRunner(VitestTestRunner)
747
779
 
748
780
  return vitestPackage
749
781
  })
@@ -282,7 +282,6 @@ function normalizeConfig (config, serviceIdentifier) {
282
282
  return {
283
283
  ...config,
284
284
  ...specificConfig,
285
- splitByAwsService: config.splitByAwsService !== false,
286
285
  batchPropagationEnabled,
287
286
  hooks
288
287
  }