dd-trace 5.72.0 → 5.74.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 (53) hide show
  1. package/LICENSE-3rdparty.csv +3 -0
  2. package/index.d.ts +49 -0
  3. package/package.json +11 -6
  4. package/packages/datadog-core/src/utils/src/set.js +5 -1
  5. package/packages/datadog-esbuild/index.js +112 -36
  6. package/packages/datadog-esbuild/src/utils.js +198 -0
  7. package/packages/datadog-instrumentations/src/azure-service-bus.js +49 -22
  8. package/packages/datadog-instrumentations/src/cookie-parser.js +2 -0
  9. package/packages/datadog-instrumentations/src/express-session.js +1 -0
  10. package/packages/datadog-instrumentations/src/express.js +82 -0
  11. package/packages/datadog-instrumentations/src/helpers/router-helper.js +238 -0
  12. package/packages/datadog-instrumentations/src/jest.js +60 -14
  13. package/packages/datadog-instrumentations/src/mocha/utils.js +3 -4
  14. package/packages/datadog-instrumentations/src/playwright.js +110 -56
  15. package/packages/datadog-instrumentations/src/router.js +63 -6
  16. package/packages/datadog-instrumentations/src/ws.js +3 -3
  17. package/packages/datadog-plugin-amqplib/src/consumer.js +1 -1
  18. package/packages/datadog-plugin-azure-functions/src/index.js +24 -14
  19. package/packages/datadog-plugin-azure-service-bus/src/index.js +1 -1
  20. package/packages/datadog-plugin-azure-service-bus/src/producer.js +60 -12
  21. package/packages/datadog-plugin-express/src/code_origin.js +2 -0
  22. package/packages/datadog-plugin-jest/src/index.js +53 -18
  23. package/packages/datadog-plugin-ws/src/close.js +2 -2
  24. package/packages/datadog-plugin-ws/src/producer.js +1 -1
  25. package/packages/datadog-plugin-ws/src/receiver.js +1 -1
  26. package/packages/dd-trace/src/appsec/index.js +9 -1
  27. package/packages/dd-trace/src/appsec/reporter.js +2 -3
  28. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +5 -0
  29. package/packages/dd-trace/src/config-helper.js +3 -1
  30. package/packages/dd-trace/src/config.js +437 -446
  31. package/packages/dd-trace/src/config_defaults.js +5 -12
  32. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +8 -3
  33. package/packages/dd-trace/src/llmobs/plugins/base.js +11 -12
  34. package/packages/dd-trace/src/llmobs/sdk.js +20 -4
  35. package/packages/dd-trace/src/llmobs/tagger.js +12 -0
  36. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +7 -127
  37. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +19 -134
  38. package/packages/dd-trace/src/opentelemetry/otlp/metrics.proto +720 -0
  39. package/packages/dd-trace/src/opentelemetry/otlp/metrics_service.proto +78 -0
  40. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +177 -0
  41. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +163 -0
  42. package/packages/dd-trace/src/opentelemetry/{protos → otlp}/protobuf_loader.js +24 -6
  43. package/packages/dd-trace/src/plugins/util/ci.js +3 -2
  44. package/packages/dd-trace/src/plugins/util/stacktrace.js +16 -1
  45. package/packages/dd-trace/src/supported-configurations.json +2 -0
  46. package/packages/dd-trace/src/telemetry/endpoints.js +27 -1
  47. package/packages/dd-trace/src/telemetry/index.js +16 -13
  48. package/scripts/preinstall.js +3 -1
  49. package/version.js +2 -1
  50. /package/packages/dd-trace/src/opentelemetry/{protos → otlp}/common.proto +0 -0
  51. /package/packages/dd-trace/src/opentelemetry/{protos → otlp}/logs.proto +0 -0
  52. /package/packages/dd-trace/src/opentelemetry/{protos → otlp}/logs_service.proto +0 -0
  53. /package/packages/dd-trace/src/opentelemetry/{protos → otlp}/resource.proto +0 -0
@@ -50,6 +50,7 @@ dev,@stylistic/eslint-plugin,MIT,Copyright OpenJS Foundation and other contribut
50
50
  dev,axios,MIT,Copyright 2014-present Matt Zabriskie
51
51
  dev,benchmark,MIT,Copyright 2010-2016 Mathias Bynens Robert Kieffer John-David Dalton
52
52
  dev,body-parser,MIT,Copyright 2014 Jonathan Ong 2014-2015 Douglas Christopher Wilson
53
+ dev,bun,MIT,Copyright contributors
53
54
  dev,chai,MIT,Copyright 2017 Chai.js Assertion Library
54
55
  dev,eslint,MIT,Copyright JS Foundation and other contributors https://js.foundation
55
56
  dev,eslint-plugin-cypress,MIT,Copyright (c) 2019 Cypress.io
@@ -64,6 +65,8 @@ dev,globals,MIT,Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://si
64
65
  dev,graphql,MIT,Copyright 2015 Facebook Inc.
65
66
  dev,jszip,MIT,Copyright 2015-2016 Stuart Knightley and contributors
66
67
  dev,mocha,MIT,Copyright 2011-2018 JS Foundation and contributors https://js.foundation
68
+ dev,mocha-multi-reporters,MIT,Copyright 2015-2019 Yousaf Nabi and Stanley Ng
69
+ dev,mocha-junit-reporter,MIT, Copyright 2015 Michael Allen
67
70
  dev,multer,MIT,Copyright 2014 Hage Yaapa
68
71
  dev,nock,MIT,Copyright 2017 Pedro Teixeira and other contributors
69
72
  dev,nyc,ISC,Copyright 2015 Contributors
package/index.d.ts CHANGED
@@ -134,6 +134,11 @@ interface Tracer extends opentracing.Tracer {
134
134
 
135
135
  dogstatsd: tracer.DogStatsD;
136
136
 
137
+ /**
138
+ * Data Streams manual checkpointer API.
139
+ */
140
+ dataStreamsCheckpointer: tracer.DataStreamsCheckpointer;
141
+
137
142
  /**
138
143
  * LLM Observability SDK
139
144
  */
@@ -1026,6 +1031,29 @@ declare namespace tracer {
1026
1031
  flush(): void
1027
1032
  }
1028
1033
 
1034
+ /**
1035
+ * Manual Data Streams Monitoring checkpointer API.
1036
+ */
1037
+ export interface DataStreamsCheckpointer {
1038
+ /**
1039
+ * Sets a produce checkpoint and injects the DSM context into the provided carrier.
1040
+ * @param type The streaming technology (e.g., kafka, kinesis, sns).
1041
+ * @param target The target of data (topic, exchange, stream name).
1042
+ * @param carrier The carrier object to inject DSM context into.
1043
+ */
1044
+ setProduceCheckpoint (type: string, target: string, carrier: any): void;
1045
+
1046
+ /**
1047
+ * Sets a consume checkpoint and extracts DSM context from the provided carrier.
1048
+ * @param type The streaming technology (e.g., kafka, kinesis, sns).
1049
+ * @param source The source of data (topic, exchange, stream name).
1050
+ * @param carrier The carrier object to extract DSM context from.
1051
+ * @param manualCheckpoint Whether this checkpoint was manually set. Defaults to true.
1052
+ * @returns The DSM context associated with the current pathway.
1053
+ */
1054
+ setConsumeCheckpoint (type: string, source: string, carrier: any, manualCheckpoint?: boolean): any;
1055
+ }
1056
+
1029
1057
  export interface EventTrackingV2 {
1030
1058
  /**
1031
1059
  * Links a successful login event to the current trace. Will link the passed user to the current trace with Appsec.setUser() internally.
@@ -2938,6 +2966,15 @@ declare namespace tracer {
2938
2966
  */
2939
2967
  submitEvaluation (spanContext: llmobs.ExportedLLMObsSpan, options: llmobs.EvaluationOptions): void
2940
2968
 
2969
+
2970
+ /**
2971
+ * Annotates all spans, including auto-instrumented spans, with the provided tags created in the context of the callback function.
2972
+ * @param options The annotation context options.
2973
+ * @param fn The callback over which to apply the annotation context options.
2974
+ * @returns The result of the function.
2975
+ */
2976
+ annotationContext<T> (options: llmobs.AnnotationContextOptions, fn: () => T): T
2977
+
2941
2978
  /**
2942
2979
  * Flushes any remaining spans and evaluation metrics to LLM Observability.
2943
2980
  */
@@ -3099,6 +3136,18 @@ declare namespace tracer {
3099
3136
  tags?: { [key: string]: any }
3100
3137
  }
3101
3138
 
3139
+ interface AnnotationContextOptions {
3140
+ /**
3141
+ * Dictionary of JSON serializable key-value tag pairs to set or update on the LLMObs span regarding the span's context.
3142
+ */
3143
+ tags?: { [key: string]: any },
3144
+
3145
+ /**
3146
+ * Set to override the span name for any spans annotated within the returned context.
3147
+ */
3148
+ name?: string,
3149
+ }
3150
+
3102
3151
  /**
3103
3152
  * An object containing the span ID and trace ID of interest
3104
3153
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.72.0",
3
+ "version": "5.74.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -32,6 +32,8 @@
32
32
  "test:trace:core:ci": "npm run test:trace:core -- --coverage --nyc-arg=--include=\"packages/dd-trace/src/**/*.js\"",
33
33
  "test:trace:guardrails": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/dd-trace/test/guardrails/**/*.spec.js\"",
34
34
  "test:trace:guardrails:ci": "nyc --no-clean --include \"packages/dd-trace/src/guardrails/**/*.js\" -- npm run test:trace:guardrails",
35
+ "test:esbuild": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/datadog-esbuild/test/**/*.spec.js\"",
36
+ "test:esbuild:ci": "nyc --no-clean --include \"packages/datadog-esbuild/test/**/*.js\" -- npm run test:esbuild",
35
37
  "test:instrumentations": "mocha -r 'packages/dd-trace/test/setup/mocha.js' \"packages/datadog-instrumentations/test/@($(echo $PLUGINS)).spec.js\"",
36
38
  "test:instrumentations:ci": "yarn services && nyc --no-clean --include \"packages/datadog-instrumentations/src/@($(echo $PLUGINS)).js\" --include \"packages/datadog-instrumentations/src/@($(echo $PLUGINS))/**/*.js\" -- npm run test:instrumentations",
37
39
  "test:instrumentations:misc": "mocha -r 'packages/dd-trace/test/setup/mocha.js' 'packages/datadog-instrumentations/test/*/**/*.spec.js'",
@@ -44,7 +46,7 @@
44
46
  "test:llmobs:sdk:ci": "nyc --no-clean --include \"packages/dd-trace/src/llmobs/**/*.js\" -- npm run test:llmobs:sdk",
45
47
  "test:llmobs:plugins": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/dd-trace/test/llmobs/plugins/@($(echo $PLUGINS))/*.spec.js\"",
46
48
  "test:llmobs:plugins:ci": "yarn services && nyc --no-clean --include \"packages/dd-trace/src/llmobs/**/*.js\" -- npm run test:llmobs:plugins",
47
- "test:plugins": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/**/*.spec.js\"",
49
+ "test:plugins": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/**/@($(echo ${SPEC:-'*'})).spec.js\"",
48
50
  "test:plugins:ci": "yarn services && nyc --no-clean --include \"packages/datadog-plugin-@($(echo $PLUGINS))/src/**/*.js\" -- npm run test:plugins",
49
51
  "test:plugins:ci:flaky": "yarn services && nyc --no-clean --include \"packages/datadog-plugin-@($(echo $PLUGINS))/src/**/*.js\" -- npm run test:plugins -- --bail --retries 2",
50
52
  "test:plugins:upstream": "node ./packages/dd-trace/test/plugins/suite.js",
@@ -120,10 +122,10 @@
120
122
  ],
121
123
  "dependencies": {
122
124
  "@datadog/libdatadog": "0.7.0",
123
- "@datadog/native-appsec": "10.2.1",
125
+ "@datadog/native-appsec": "10.3.0",
124
126
  "@datadog/native-iast-taint-tracking": "4.0.0",
125
127
  "@datadog/native-metrics": "3.1.1",
126
- "@datadog/openfeature-node-server": "0.1.0-preview.10",
128
+ "@datadog/openfeature-node-server": "0.1.0-preview.12",
127
129
  "@datadog/pprof": "5.11.1",
128
130
  "@datadog/sketches-js": "2.1.1",
129
131
  "@datadog/wasm-js-rewriter": "4.0.1",
@@ -158,7 +160,7 @@
158
160
  },
159
161
  "peerDependencies": {
160
162
  "@openfeature/core": "^1.9.0",
161
- "@openfeature/server-sdk": "~1.18.0"
163
+ "@openfeature/server-sdk": "~1.20.0"
162
164
  },
163
165
  "peerDependenciesMeta": {
164
166
  "@openfeature/core": {
@@ -174,7 +176,7 @@
174
176
  "@eslint/js": "^9.29.0",
175
177
  "@msgpack/msgpack": "^3.1.2",
176
178
  "@openfeature/core": "^1.8.1",
177
- "@openfeature/server-sdk": "~1.18.0",
179
+ "@openfeature/server-sdk": "~1.20.0",
178
180
  "@stylistic/eslint-plugin": "^5.0.0",
179
181
  "@types/chai": "^4.3.16",
180
182
  "@types/mocha": "^10.0.10",
@@ -184,6 +186,7 @@
184
186
  "axios": "^1.12.2",
185
187
  "benchmark": "^2.1.4",
186
188
  "body-parser": "^2.2.0",
189
+ "bun": "1.3.1",
187
190
  "chai": "^4.5.0",
188
191
  "eslint": "^9.29.0",
189
192
  "eslint-plugin-cypress": "^5.1.0",
@@ -198,6 +201,8 @@
198
201
  "graphql": "*",
199
202
  "jszip": "^3.10.1",
200
203
  "mocha": "^11.6.0",
204
+ "mocha-junit-reporter": "^2.2.1",
205
+ "mocha-multi-reporters": "^1.5.1",
201
206
  "multer": "^2.0.2",
202
207
  "nock": "^13.5.6",
203
208
  "nyc": "^15.1.0",
@@ -5,7 +5,11 @@ module.exports = function set (object, path, value) {
5
5
  while (true) {
6
6
  const nextIndex = path.indexOf('.', index + 1)
7
7
  if (nextIndex === -1) {
8
- object[path.slice(index + 1)] = value
8
+ if (index === -1) {
9
+ object[path] = value
10
+ } else {
11
+ object[path.slice(index + 1)] = value
12
+ }
9
13
  return
10
14
  }
11
15
  object = object[path.slice(index + 1, nextIndex)] ??= {}
@@ -8,6 +8,12 @@ const extractPackageAndModulePath = require(
8
8
  '../datadog-instrumentations/src/helpers/extract-package-and-module-path.js'
9
9
  )
10
10
 
11
+ const { pathToFileURL, fileURLToPath } = require('url')
12
+ const { processModule, isESMFile } = require('./src/utils.js')
13
+
14
+ const ESM_INTERCEPTED_SUFFIX = '._dd_esbuild_intercepted'
15
+ const INTERNAL_ESM_INTERCEPTED_PREFIX = '/_dd_esm_internal_/'
16
+
11
17
  let rewriter
12
18
 
13
19
  for (const hook of Object.values(hooks)) {
@@ -30,7 +36,6 @@ for (const instrumentation of Object.values(instrumentations)) {
30
36
  }
31
37
  }
32
38
 
33
- const INSTRUMENTED = Object.keys(instrumentations)
34
39
  const RAW_BUILTINS = require('module').builtinModules
35
40
  const CHANNEL = 'dd-trace:bundler:load'
36
41
  const path = require('path')
@@ -47,14 +52,6 @@ for (const builtin of RAW_BUILTINS) {
47
52
  const DEBUG = !!process.env.DD_TRACE_DEBUG
48
53
  const DD_IAST_ENABLED = process.env.DD_IAST_ENABLED?.toLowerCase() === 'true' || process.env.DD_IAST_ENABLED === '1'
49
54
 
50
- // We don't want to handle any built-in packages
51
- // Those packages will still be handled via RITM
52
- // Attempting to instrument them would fail as they have no package.json file
53
- for (const pkg of INSTRUMENTED) {
54
- if (builtins.has(pkg) || pkg.startsWith('node:')) continue
55
- modulesOfInterest.add(pkg)
56
- }
57
-
58
55
  module.exports.name = 'datadog-esbuild'
59
56
 
60
57
  function isESMBuild (build) {
@@ -115,7 +112,16 @@ module.exports.setup = function (build) {
115
112
  ${isSourceMapEnabled ? `globalThis.__DD_ESBUILD_BASEPATH = '${require('../dd-trace/src/util').ddBasePath}';` : ''}
116
113
  ${build.initialOptions.banner.js}`
117
114
  }
118
- if (isESMBuild(build)) {
115
+
116
+ try {
117
+ require.resolve('@openfeature/core')
118
+ } catch (error) {
119
+ build.initialOptions.external ??= []
120
+ build.initialOptions.external.push('@openfeature/core')
121
+ }
122
+
123
+ const esmBuild = isESMBuild(build)
124
+ if (esmBuild) {
119
125
  if (!build.initialOptions.banner.js.includes('import { createRequire as $dd_createRequire } from \'module\'')) {
120
126
  build.initialOptions.banner.js = `import { createRequire as $dd_createRequire } from 'module';
121
127
  import { fileURLToPath as $dd_fileURLToPath } from 'url';
@@ -149,6 +155,9 @@ ${build.initialOptions.banner.js}`
149
155
  console.warn('Warning: No git metadata available - skipping injection')
150
156
  }
151
157
 
158
+ // first time is intercepted, proxy should be created, next time the original should be loaded
159
+ const interceptedESMModules = new Set()
160
+
152
161
  build.onResolve({ filter: /.*/ }, args => {
153
162
  if (externalModules.has(args.path)) {
154
163
  // Internal Node.js packages will still be instrumented via require()
@@ -167,7 +176,7 @@ ${build.initialOptions.banner.js}`
167
176
 
168
177
  let fullPathToModule
169
178
  try {
170
- fullPathToModule = dotFriendlyResolve(args.path, args.resolveDir)
179
+ fullPathToModule = dotFriendlyResolve(args.path, args.resolveDir, args.kind === 'import-statement')
171
180
  } catch (err) {
172
181
  if (DEBUG) {
173
182
  console.warn(`Warning: Unable to find "${args.path}".` +
@@ -197,8 +206,25 @@ ${build.initialOptions.banner.js}`
197
206
  if (args.namespace === 'file' && (
198
207
  modulesOfInterest.has(args.path) || modulesOfInterest.has(`${extracted.pkg}/${extracted.path}`))
199
208
  ) {
209
+ // Internal module like http/fs is imported and the build output is ESM
210
+ if (internal && args.kind === 'import-statement' && esmBuild && !interceptedESMModules.has(fullPathToModule)) {
211
+ fullPathToModule = `${INTERNAL_ESM_INTERCEPTED_PREFIX}${fullPathToModule}${ESM_INTERCEPTED_SUFFIX}`
212
+
213
+ return {
214
+ path: fullPathToModule,
215
+ pluginData: {
216
+ pkg: extracted?.pkg,
217
+ path: extracted?.path,
218
+ full: fullPathToModule,
219
+ raw: args.path,
220
+ pkgOfInterest: true,
221
+ kind: args.kind,
222
+ internal,
223
+ isESM: true
224
+ }
225
+ }
226
+ }
200
227
  // The file namespace is used when requiring files from disk in userland
201
-
202
228
  let pathToPackageJson
203
229
  try {
204
230
  // we can't use require.resolve('pkg/package.json') as ESM modules don't make the file available
@@ -220,6 +246,11 @@ ${build.initialOptions.banner.js}`
220
246
 
221
247
  const packageJson = JSON.parse(fs.readFileSync(pathToPackageJson).toString())
222
248
 
249
+ const isESM = isESMFile(fullPathToModule, pathToPackageJson, packageJson)
250
+ if (isESM && !interceptedESMModules.has(fullPathToModule)) {
251
+ fullPathToModule += ESM_INTERCEPTED_SUFFIX
252
+ }
253
+
223
254
  if (DEBUG) console.log(`RESOLVE: ${args.path}@${packageJson.version}`)
224
255
 
225
256
  // https://esbuild.github.io/plugins/#on-resolve-arguments
@@ -232,13 +263,15 @@ ${build.initialOptions.banner.js}`
232
263
  full: fullPathToModule,
233
264
  raw: args.path,
234
265
  pkgOfInterest: true,
235
- internal
266
+ kind: args.kind,
267
+ internal,
268
+ isESM
236
269
  }
237
270
  }
238
271
  }
239
272
  })
240
273
 
241
- build.onLoad({ filter: /.*/ }, args => {
274
+ build.onLoad({ filter: /.*/ }, async args => {
242
275
  if (args.pluginData?.pkgOfInterest) {
243
276
  const data = args.pluginData
244
277
 
@@ -249,26 +282,63 @@ ${build.initialOptions.banner.js}`
249
282
  : data.pkg
250
283
 
251
284
  // Read the content of the module file of interest
252
- const fileCode = fs.readFileSync(args.path, 'utf8')
285
+ let contents
286
+
287
+ if (data.isESM) {
288
+ if (args.path.endsWith(ESM_INTERCEPTED_SUFFIX)) {
289
+ args.path = args.path.slice(0, -1 * ESM_INTERCEPTED_SUFFIX.length)
290
+
291
+ if (data.internal) {
292
+ args.path = args.path.slice(INTERNAL_ESM_INTERCEPTED_PREFIX.length)
293
+ }
294
+
295
+ interceptedESMModules.add(args.path)
296
+
297
+ const setters = await processModule({
298
+ path: args.path,
299
+ internal: data.internal,
300
+ context: { format: 'module' }
301
+ })
302
+
303
+ const iitmPath = require.resolve('import-in-the-middle/lib/register.js')
304
+ const toRegister = data.internal ? args.path : pathToFileURL(args.path)
305
+ // Mimic a Module object (https://tc39.es/ecma262/#sec-module-namespace-objects).
306
+ contents = `
307
+ import { register } from ${JSON.stringify(iitmPath)};
308
+ import * as namespace from ${JSON.stringify(args.path)};
309
+ const _ = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
310
+ const set = {};
311
+ const get = {};
312
+
313
+ ${Array.from(setters.values()).join(';\n')};
314
+
315
+ register(${JSON.stringify(toRegister)}, _, set, get, ${JSON.stringify(data.raw)});
316
+ `
317
+ } else {
318
+ contents = fs.readFileSync(args.path, 'utf8')
319
+ }
320
+ } else {
321
+ const fileCode = fs.readFileSync(args.path, 'utf8')
322
+ contents = `
323
+ (function() {
324
+ ${fileCode}
325
+ })(...arguments);
326
+ {
327
+ const dc = require('dc-polyfill');
328
+ const ch = dc.channel('${CHANNEL}');
329
+ const mod = module.exports
330
+ const payload = {
331
+ module: mod,
332
+ version: '${data.version}',
333
+ package: '${data.pkg}',
334
+ path: '${pkgPath}'
335
+ };
336
+ ch.publish(payload);
337
+ module.exports = payload.module;
338
+ }
339
+ `
340
+ }
253
341
 
254
- const contents = `
255
- (function() {
256
- ${fileCode}
257
- })(...arguments);
258
- {
259
- const dc = require('dc-polyfill');
260
- const ch = dc.channel('${CHANNEL}');
261
- const mod = module.exports
262
- const payload = {
263
- module: mod,
264
- version: '${data.version}',
265
- package: '${data.pkg}',
266
- path: '${pkgPath}'
267
- };
268
- ch.publish(payload);
269
- module.exports = payload.module;
270
- }
271
- `
272
342
  // https://esbuild.github.io/plugins/#on-load-results
273
343
  return {
274
344
  contents,
@@ -276,7 +346,6 @@ ${build.initialOptions.banner.js}`
276
346
  resolveDir: path.dirname(args.path)
277
347
  }
278
348
  }
279
-
280
349
  if (DD_IAST_ENABLED && args.pluginData?.applicationFile) {
281
350
  const ext = path.extname(args.path).toLowerCase()
282
351
  const isJs = /^\.(js|mjs|cjs)$/.test(ext)
@@ -295,12 +364,19 @@ ${build.initialOptions.banner.js}`
295
364
  }
296
365
 
297
366
  // @see https://github.com/nodejs/node/issues/47000
298
- function dotFriendlyResolve (path, directory) {
367
+ function dotFriendlyResolve (path, directory, usesImportStatement) {
299
368
  if (path === '.') {
300
369
  path = './'
301
370
  } else if (path === '..') {
302
371
  path = '../'
303
372
  }
373
+ let conditions
374
+ if (usesImportStatement) {
375
+ conditions = new Set(['import', 'node'])
376
+ }
304
377
 
305
- return require.resolve(path, { paths: [directory] })
378
+ if (path.startsWith('file://')) {
379
+ path = fileURLToPath(path)
380
+ }
381
+ return require.resolve(path, { paths: [directory], conditions })
306
382
  }
@@ -0,0 +1,198 @@
1
+ 'use strict'
2
+
3
+ // The content of this file is copied from the `import-in-the-middle` package with minor modifications (https://www.npmjs.com/package/import-in-the-middle)
4
+ const { pathToFileURL, fileURLToPath } = require('node:url')
5
+ const fs = require('node:fs')
6
+ const path = require('node:path')
7
+ const { NODE_MAJOR, NODE_MINOR } = require('../../../version.js')
8
+
9
+ const getExportsImporting = (url) => import(url).then(Object.keys)
10
+ const getExports = NODE_MAJOR >= 20 || (NODE_MAJOR === 18 && NODE_MINOR >= 19)
11
+ ? require('import-in-the-middle/lib/get-exports.js')
12
+ : getExportsImporting
13
+
14
+ function isStarExportLine (line) {
15
+ return /^\* from /.test(line)
16
+ }
17
+
18
+ function isBareSpecifier (specifier) {
19
+ // Relative and absolute paths are not bare specifiers.
20
+ if (
21
+ specifier.startsWith('.') ||
22
+ specifier.startsWith('/')) {
23
+ return false
24
+ }
25
+
26
+ // Valid URLs are not bare specifiers. (file:, http:, node:, etc.)
27
+
28
+ if (URL.hasOwnProperty('canParse')) {
29
+ // eslint-disable-next-line n/no-unsupported-features/node-builtins
30
+ return !URL.canParse(specifier)
31
+ }
32
+
33
+ try {
34
+ // eslint-disable-next-line no-new
35
+ new URL(specifier)
36
+ return false
37
+ } catch {
38
+ return true
39
+ }
40
+ }
41
+
42
+ function resolve (specifier, context) {
43
+ // This comes from an import, that is why import makes preference
44
+ const conditions = ['import']
45
+
46
+ if (specifier.startsWith('file://')) {
47
+ specifier = fileURLToPath(specifier)
48
+ }
49
+
50
+ const resolved = require.resolve(specifier, { conditions, paths: [fileURLToPath(context.parentURL)] })
51
+
52
+ return {
53
+ url: pathToFileURL(resolved),
54
+ format: isESMFile(resolved) ? 'module' : 'commonjs'
55
+ }
56
+ }
57
+
58
+ function getSource (url, { format }) {
59
+ return {
60
+ source: fs.readFileSync(fileURLToPath(url), 'utf8'),
61
+ format
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Generates the pieces of code for the proxy module before the path
67
+ *
68
+ * @param {Object} moduleData { path, internal, context, excludeDefault }
69
+ * @returns {Promise<Map>}
70
+ */
71
+ async function processModule ({ path, internal, context, excludeDefault }) {
72
+ let exportNames, srcUrl
73
+ if (internal) {
74
+ // we can not read and parse of internal modules
75
+ exportNames = await getExportsImporting(path)
76
+ } else {
77
+ srcUrl = pathToFileURL(path)
78
+ exportNames = await getExports(srcUrl, context, getSource)
79
+ }
80
+
81
+ const starExports = new Set()
82
+ const setters = new Map()
83
+
84
+ const addSetter = (name, setter, isStarExport = false) => {
85
+ if (setters.has(name)) {
86
+ if (isStarExport) {
87
+ // If there's already a matching star export, delete it
88
+ if (starExports.has(name)) {
89
+ setters.delete(name)
90
+ }
91
+ // and return so this is excluded
92
+ return
93
+ }
94
+
95
+ // if we already have this export but it is from a * export, overwrite it
96
+ if (starExports.has(name)) {
97
+ starExports.delete(name)
98
+ setters.set(name, setter)
99
+ }
100
+ } else {
101
+ // Store export * exports so we know they can be overridden by explicit
102
+ // named exports
103
+ if (isStarExport) {
104
+ starExports.add(name)
105
+ }
106
+
107
+ setters.set(name, setter)
108
+ }
109
+ }
110
+
111
+ for (const n of exportNames) {
112
+ if (n === 'default' && excludeDefault) continue
113
+
114
+ if (isStarExportLine(n) === true) {
115
+ // export * from 'wherever'
116
+ const [, modFile] = n.split('* from ')
117
+
118
+ // Relative paths need to be resolved relative to the parent module
119
+ const newSpecifier = isBareSpecifier(modFile) ? modFile : new URL(modFile, srcUrl).href
120
+ // We need to call `parentResolve` to resolve bare specifiers to a full
121
+ // URL. We also need to call `parentResolve` for all sub-modules to get
122
+ // the `format`. We can't rely on the parents `format` to know if this
123
+ // sub-module is ESM or CJS!
124
+
125
+ const result = resolve(newSpecifier, { parentURL: srcUrl })
126
+
127
+ // eslint-disable-next-line no-await-in-loop
128
+ const subSetters = await processModule({
129
+ path: fileURLToPath(result.url),
130
+ context: { ...context, format: result.format },
131
+ excludeDefault: true
132
+ })
133
+
134
+ for (const [name, setter] of subSetters.entries()) {
135
+ addSetter(name, setter, true)
136
+ }
137
+ } else {
138
+ const variableName = `$${n.replaceAll(/[^a-zA-Z0-9_$]/g, '_')}`
139
+ const objectKey = JSON.stringify(n)
140
+ const reExportedName = n === 'default' ? n : objectKey
141
+
142
+ addSetter(n, `
143
+ let ${variableName}
144
+ try {
145
+ ${variableName} = _[${objectKey}] = namespace[${objectKey}]
146
+ } catch (err) {
147
+ if (!(err instanceof ReferenceError)) throw err
148
+ }
149
+ export { ${variableName} as ${reExportedName} }
150
+ set[${objectKey}] = (v) => {
151
+ ${variableName} = v
152
+ return true
153
+ }
154
+ get[${objectKey}] = () => ${variableName}
155
+ `)
156
+ }
157
+ }
158
+
159
+ return setters
160
+ }
161
+
162
+ /**
163
+ * Determines if a file is a ESM module or CommonJS
164
+ *
165
+ * @param {string} fullPathToModule File to analize
166
+ * @param {string} [modulePackageJsonPath] Path of the package.json
167
+ * @param {Object} [packageJson] The content of the module package.json
168
+ * @returns {boolean}
169
+ */
170
+ function isESMFile (fullPathToModule, modulePackageJsonPath, packageJson = {}) {
171
+ if (fullPathToModule.endsWith('.mjs')) return true
172
+ if (fullPathToModule.endsWith('.cjs')) return false
173
+
174
+ const pathParts = fullPathToModule.split(path.sep)
175
+ do {
176
+ pathParts.pop()
177
+
178
+ const packageJsonPath = [...pathParts, 'package.json'].join(path.sep)
179
+ if (packageJsonPath === modulePackageJsonPath) {
180
+ return packageJson.type === 'module'
181
+ }
182
+
183
+ try {
184
+ const packageJsonContent = fs.readFileSync(packageJsonPath).toString()
185
+ const packageJson = JSON.parse(packageJsonContent)
186
+ return packageJson.type === 'module'
187
+ } catch {
188
+ // file does not exit, continue
189
+ }
190
+ } while (pathParts.length > 0)
191
+
192
+ return packageJson.type === 'module'
193
+ }
194
+
195
+ module.exports = {
196
+ processModule,
197
+ isESMFile
198
+ }