dd-trace 5.73.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.
- package/LICENSE-3rdparty.csv +2 -0
- package/index.d.ts +39 -7
- package/loader-hook.mjs +52 -1
- package/package.json +8 -16
- package/packages/datadog-core/src/utils/src/set.js +5 -1
- package/packages/datadog-esbuild/index.js +105 -36
- package/packages/datadog-esbuild/src/utils.js +198 -0
- package/packages/datadog-instrumentations/src/cookie-parser.js +0 -2
- package/packages/datadog-instrumentations/src/cucumber.js +2 -2
- package/packages/datadog-instrumentations/src/express.js +82 -0
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +238 -0
- package/packages/datadog-instrumentations/src/jest.js +2 -1
- package/packages/datadog-instrumentations/src/mariadb.js +9 -7
- package/packages/datadog-instrumentations/src/playwright.js +226 -93
- package/packages/datadog-instrumentations/src/router.js +63 -6
- package/packages/datadog-instrumentations/src/vitest.js +44 -12
- package/packages/datadog-instrumentations/src/ws.js +3 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +0 -1
- package/packages/datadog-plugin-express/src/code_origin.js +2 -0
- package/packages/datadog-plugin-playwright/src/index.js +74 -31
- package/packages/datadog-plugin-ws/src/close.js +1 -1
- package/packages/datadog-shimmer/src/shimmer.js +2 -0
- package/packages/dd-trace/src/aiguard/sdk.js +25 -3
- package/packages/dd-trace/src/aiguard/tags.js +4 -1
- package/packages/dd-trace/src/config-helper.js +4 -1
- package/packages/dd-trace/src/config.js +599 -592
- package/packages/dd-trace/src/config_defaults.js +14 -12
- package/packages/dd-trace/src/plugins/util/ci.js +3 -2
- package/packages/dd-trace/src/plugins/util/stacktrace.js +16 -1
- package/packages/dd-trace/src/proxy.js +1 -1
- package/packages/dd-trace/src/supported-configurations.json +1 -0
- package/packages/dd-trace/src/telemetry/endpoints.js +27 -1
- package/packages/dd-trace/src/telemetry/index.js +16 -13
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +5 -3
- package/register.js +1 -11
- package/scripts/preinstall.js +3 -1
- package/version.js +2 -1
package/LICENSE-3rdparty.csv
CHANGED
|
@@ -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.
|
|
@@ -50,6 +51,7 @@ dev,@stylistic/eslint-plugin,MIT,Copyright OpenJS Foundation and other contribut
|
|
|
50
51
|
dev,axios,MIT,Copyright 2014-present Matt Zabriskie
|
|
51
52
|
dev,benchmark,MIT,Copyright 2010-2016 Mathias Bynens Robert Kieffer John-David Dalton
|
|
52
53
|
dev,body-parser,MIT,Copyright 2014 Jonathan Ong 2014-2015 Douglas Christopher Wilson
|
|
54
|
+
dev,bun,MIT,Copyright contributors
|
|
53
55
|
dev,chai,MIT,Copyright 2017 Chai.js Assertion Library
|
|
54
56
|
dev,eslint,MIT,Copyright JS Foundation and other contributors https://js.foundation
|
|
55
57
|
dev,eslint-plugin-cypress,MIT,Copyright (c) 2019 Cypress.io
|
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
|
*/
|
|
@@ -176,6 +181,7 @@ interface Tracer extends opentracing.Tracer {
|
|
|
176
181
|
/** @hidden */
|
|
177
182
|
interface Plugins {
|
|
178
183
|
"aerospike": tracer.plugins.aerospike;
|
|
184
|
+
"ai": tracer.plugins.ai;
|
|
179
185
|
"amqp10": tracer.plugins.amqp10;
|
|
180
186
|
"amqplib": tracer.plugins.amqplib;
|
|
181
187
|
"anthropic": tracer.plugins.anthropic;
|
|
@@ -1026,6 +1032,29 @@ declare namespace tracer {
|
|
|
1026
1032
|
flush(): void
|
|
1027
1033
|
}
|
|
1028
1034
|
|
|
1035
|
+
/**
|
|
1036
|
+
* Manual Data Streams Monitoring checkpointer API.
|
|
1037
|
+
*/
|
|
1038
|
+
export interface DataStreamsCheckpointer {
|
|
1039
|
+
/**
|
|
1040
|
+
* Sets a produce checkpoint and injects the DSM context into the provided carrier.
|
|
1041
|
+
* @param type The streaming technology (e.g., kafka, kinesis, sns).
|
|
1042
|
+
* @param target The target of data (topic, exchange, stream name).
|
|
1043
|
+
* @param carrier The carrier object to inject DSM context into.
|
|
1044
|
+
*/
|
|
1045
|
+
setProduceCheckpoint (type: string, target: string, carrier: any): void;
|
|
1046
|
+
|
|
1047
|
+
/**
|
|
1048
|
+
* Sets a consume checkpoint and extracts DSM context from the provided carrier.
|
|
1049
|
+
* @param type The streaming technology (e.g., kafka, kinesis, sns).
|
|
1050
|
+
* @param source The source of data (topic, exchange, stream name).
|
|
1051
|
+
* @param carrier The carrier object to extract DSM context from.
|
|
1052
|
+
* @param manualCheckpoint Whether this checkpoint was manually set. Defaults to true.
|
|
1053
|
+
* @returns The DSM context associated with the current pathway.
|
|
1054
|
+
*/
|
|
1055
|
+
setConsumeCheckpoint (type: string, source: string, carrier: any, manualCheckpoint?: boolean): any;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1029
1058
|
export interface EventTrackingV2 {
|
|
1030
1059
|
/**
|
|
1031
1060
|
* Links a successful login event to the current trace. Will link the passed user to the current trace with Appsec.setUser() internally.
|
|
@@ -1614,6 +1643,12 @@ declare namespace tracer {
|
|
|
1614
1643
|
*/
|
|
1615
1644
|
interface aerospike extends Instrumentation {}
|
|
1616
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
|
+
|
|
1617
1652
|
/**
|
|
1618
1653
|
* This plugin automatically instruments the
|
|
1619
1654
|
* [amqp10](https://github.com/noodlefrenzy/node-amqp10) module.
|
|
@@ -1670,12 +1705,6 @@ declare namespace tracer {
|
|
|
1670
1705
|
* [aws-sdk](https://github.com/aws/aws-sdk-js) module.
|
|
1671
1706
|
*/
|
|
1672
1707
|
interface aws_sdk extends Instrumentation {
|
|
1673
|
-
/**
|
|
1674
|
-
* Whether to add a suffix to the service name so that each AWS service has its own service name.
|
|
1675
|
-
* @default true
|
|
1676
|
-
*/
|
|
1677
|
-
splitByAwsService?: boolean;
|
|
1678
|
-
|
|
1679
1708
|
/**
|
|
1680
1709
|
* Whether to inject all messages during batch AWS SQS, Kinesis, and SNS send operations. Normal
|
|
1681
1710
|
* behavior is to inject the first message in batch send operations.
|
|
@@ -2793,7 +2822,10 @@ declare namespace tracer {
|
|
|
2793
2822
|
redactionValuePattern?: string,
|
|
2794
2823
|
|
|
2795
2824
|
/**
|
|
2796
|
-
* 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.
|
|
2797
2829
|
*/
|
|
2798
2830
|
securityControlsConfiguration?: string,
|
|
2799
2831
|
|
package/loader-hook.mjs
CHANGED
|
@@ -1 +1,52 @@
|
|
|
1
|
-
|
|
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.
|
|
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",
|
|
@@ -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'",
|
|
@@ -134,6 +136,7 @@
|
|
|
134
136
|
"@opentelemetry/resources": ">=1.0.0 <1.10.0",
|
|
135
137
|
"crypto-randomuuid": "^1.0.0",
|
|
136
138
|
"dc-polyfill": "^0.1.10",
|
|
139
|
+
"escape-string-regexp": "^5.0.0",
|
|
137
140
|
"ignore": "^7.0.5",
|
|
138
141
|
"import-in-the-middle": "^1.14.2",
|
|
139
142
|
"istanbul-lib-coverage": "^3.2.2",
|
|
@@ -156,25 +159,13 @@
|
|
|
156
159
|
"tlhunter-sorted-set": "^0.1.0",
|
|
157
160
|
"ttl-set": "^1.0.0"
|
|
158
161
|
},
|
|
159
|
-
"peerDependencies": {
|
|
160
|
-
"@openfeature/core": "^1.9.0",
|
|
161
|
-
"@openfeature/server-sdk": "~1.19.0"
|
|
162
|
-
},
|
|
163
|
-
"peerDependenciesMeta": {
|
|
164
|
-
"@openfeature/core": {
|
|
165
|
-
"optional": true
|
|
166
|
-
},
|
|
167
|
-
"@openfeature/server-sdk": {
|
|
168
|
-
"optional": true
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
162
|
"devDependencies": {
|
|
172
163
|
"@babel/helpers": "^7.27.6",
|
|
173
164
|
"@eslint/eslintrc": "^3.3.1",
|
|
174
165
|
"@eslint/js": "^9.29.0",
|
|
175
166
|
"@msgpack/msgpack": "^3.1.2",
|
|
176
|
-
"@openfeature/core": "^1.
|
|
177
|
-
"@openfeature/server-sdk": "
|
|
167
|
+
"@openfeature/core": "^1.9.0",
|
|
168
|
+
"@openfeature/server-sdk": "^1.20.0",
|
|
178
169
|
"@stylistic/eslint-plugin": "^5.0.0",
|
|
179
170
|
"@types/chai": "^4.3.16",
|
|
180
171
|
"@types/mocha": "^10.0.10",
|
|
@@ -184,6 +175,7 @@
|
|
|
184
175
|
"axios": "^1.12.2",
|
|
185
176
|
"benchmark": "^2.1.4",
|
|
186
177
|
"body-parser": "^2.2.0",
|
|
178
|
+
"bun": "1.3.1",
|
|
187
179
|
"chai": "^4.5.0",
|
|
188
180
|
"eslint": "^9.29.0",
|
|
189
181
|
"eslint-plugin-cypress": "^5.1.0",
|
|
@@ -211,7 +203,7 @@
|
|
|
211
203
|
"tap": "^16.3.10",
|
|
212
204
|
"tiktoken": "^1.0.21",
|
|
213
205
|
"typescript": "^5.9.2",
|
|
214
|
-
"workerpool": "^
|
|
206
|
+
"workerpool": "^10.0.0",
|
|
215
207
|
"yaml": "^2.8.0",
|
|
216
208
|
"yarn-deduplicate": "^6.0.2"
|
|
217
209
|
}
|
|
@@ -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
|
-
|
|
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) {
|
|
@@ -117,13 +114,15 @@ ${build.initialOptions.banner.js}`
|
|
|
117
114
|
}
|
|
118
115
|
|
|
119
116
|
try {
|
|
117
|
+
// eslint-disable-next-line n/no-unpublished-require
|
|
120
118
|
require.resolve('@openfeature/core')
|
|
121
119
|
} catch (error) {
|
|
122
120
|
build.initialOptions.external ??= []
|
|
123
121
|
build.initialOptions.external.push('@openfeature/core')
|
|
124
122
|
}
|
|
125
123
|
|
|
126
|
-
|
|
124
|
+
const esmBuild = isESMBuild(build)
|
|
125
|
+
if (esmBuild) {
|
|
127
126
|
if (!build.initialOptions.banner.js.includes('import { createRequire as $dd_createRequire } from \'module\'')) {
|
|
128
127
|
build.initialOptions.banner.js = `import { createRequire as $dd_createRequire } from 'module';
|
|
129
128
|
import { fileURLToPath as $dd_fileURLToPath } from 'url';
|
|
@@ -157,6 +156,9 @@ ${build.initialOptions.banner.js}`
|
|
|
157
156
|
console.warn('Warning: No git metadata available - skipping injection')
|
|
158
157
|
}
|
|
159
158
|
|
|
159
|
+
// first time is intercepted, proxy should be created, next time the original should be loaded
|
|
160
|
+
const interceptedESMModules = new Set()
|
|
161
|
+
|
|
160
162
|
build.onResolve({ filter: /.*/ }, args => {
|
|
161
163
|
if (externalModules.has(args.path)) {
|
|
162
164
|
// Internal Node.js packages will still be instrumented via require()
|
|
@@ -175,7 +177,7 @@ ${build.initialOptions.banner.js}`
|
|
|
175
177
|
|
|
176
178
|
let fullPathToModule
|
|
177
179
|
try {
|
|
178
|
-
fullPathToModule = dotFriendlyResolve(args.path, args.resolveDir)
|
|
180
|
+
fullPathToModule = dotFriendlyResolve(args.path, args.resolveDir, args.kind === 'import-statement')
|
|
179
181
|
} catch (err) {
|
|
180
182
|
if (DEBUG) {
|
|
181
183
|
console.warn(`Warning: Unable to find "${args.path}".` +
|
|
@@ -205,8 +207,25 @@ ${build.initialOptions.banner.js}`
|
|
|
205
207
|
if (args.namespace === 'file' && (
|
|
206
208
|
modulesOfInterest.has(args.path) || modulesOfInterest.has(`${extracted.pkg}/${extracted.path}`))
|
|
207
209
|
) {
|
|
210
|
+
// Internal module like http/fs is imported and the build output is ESM
|
|
211
|
+
if (internal && args.kind === 'import-statement' && esmBuild && !interceptedESMModules.has(fullPathToModule)) {
|
|
212
|
+
fullPathToModule = `${INTERNAL_ESM_INTERCEPTED_PREFIX}${fullPathToModule}${ESM_INTERCEPTED_SUFFIX}`
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
path: fullPathToModule,
|
|
216
|
+
pluginData: {
|
|
217
|
+
pkg: extracted?.pkg,
|
|
218
|
+
path: extracted?.path,
|
|
219
|
+
full: fullPathToModule,
|
|
220
|
+
raw: args.path,
|
|
221
|
+
pkgOfInterest: true,
|
|
222
|
+
kind: args.kind,
|
|
223
|
+
internal,
|
|
224
|
+
isESM: true
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
208
228
|
// The file namespace is used when requiring files from disk in userland
|
|
209
|
-
|
|
210
229
|
let pathToPackageJson
|
|
211
230
|
try {
|
|
212
231
|
// we can't use require.resolve('pkg/package.json') as ESM modules don't make the file available
|
|
@@ -228,6 +247,11 @@ ${build.initialOptions.banner.js}`
|
|
|
228
247
|
|
|
229
248
|
const packageJson = JSON.parse(fs.readFileSync(pathToPackageJson).toString())
|
|
230
249
|
|
|
250
|
+
const isESM = isESMFile(fullPathToModule, pathToPackageJson, packageJson)
|
|
251
|
+
if (isESM && !interceptedESMModules.has(fullPathToModule)) {
|
|
252
|
+
fullPathToModule += ESM_INTERCEPTED_SUFFIX
|
|
253
|
+
}
|
|
254
|
+
|
|
231
255
|
if (DEBUG) console.log(`RESOLVE: ${args.path}@${packageJson.version}`)
|
|
232
256
|
|
|
233
257
|
// https://esbuild.github.io/plugins/#on-resolve-arguments
|
|
@@ -240,13 +264,15 @@ ${build.initialOptions.banner.js}`
|
|
|
240
264
|
full: fullPathToModule,
|
|
241
265
|
raw: args.path,
|
|
242
266
|
pkgOfInterest: true,
|
|
243
|
-
|
|
267
|
+
kind: args.kind,
|
|
268
|
+
internal,
|
|
269
|
+
isESM
|
|
244
270
|
}
|
|
245
271
|
}
|
|
246
272
|
}
|
|
247
273
|
})
|
|
248
274
|
|
|
249
|
-
build.onLoad({ filter: /.*/ }, args => {
|
|
275
|
+
build.onLoad({ filter: /.*/ }, async args => {
|
|
250
276
|
if (args.pluginData?.pkgOfInterest) {
|
|
251
277
|
const data = args.pluginData
|
|
252
278
|
|
|
@@ -257,26 +283,63 @@ ${build.initialOptions.banner.js}`
|
|
|
257
283
|
: data.pkg
|
|
258
284
|
|
|
259
285
|
// Read the content of the module file of interest
|
|
260
|
-
|
|
286
|
+
let contents
|
|
287
|
+
|
|
288
|
+
if (data.isESM) {
|
|
289
|
+
if (args.path.endsWith(ESM_INTERCEPTED_SUFFIX)) {
|
|
290
|
+
args.path = args.path.slice(0, -1 * ESM_INTERCEPTED_SUFFIX.length)
|
|
291
|
+
|
|
292
|
+
if (data.internal) {
|
|
293
|
+
args.path = args.path.slice(INTERNAL_ESM_INTERCEPTED_PREFIX.length)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
interceptedESMModules.add(args.path)
|
|
297
|
+
|
|
298
|
+
const setters = await processModule({
|
|
299
|
+
path: args.path,
|
|
300
|
+
internal: data.internal,
|
|
301
|
+
context: { format: 'module' }
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
const iitmPath = require.resolve('import-in-the-middle/lib/register.js')
|
|
305
|
+
const toRegister = data.internal ? args.path : pathToFileURL(args.path)
|
|
306
|
+
// Mimic a Module object (https://tc39.es/ecma262/#sec-module-namespace-objects).
|
|
307
|
+
contents = `
|
|
308
|
+
import { register } from ${JSON.stringify(iitmPath)};
|
|
309
|
+
import * as namespace from ${JSON.stringify(args.path)};
|
|
310
|
+
const _ = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
|
|
311
|
+
const set = {};
|
|
312
|
+
const get = {};
|
|
313
|
+
|
|
314
|
+
${Array.from(setters.values()).join(';\n')};
|
|
315
|
+
|
|
316
|
+
register(${JSON.stringify(toRegister)}, _, set, get, ${JSON.stringify(data.raw)});
|
|
317
|
+
`
|
|
318
|
+
} else {
|
|
319
|
+
contents = fs.readFileSync(args.path, 'utf8')
|
|
320
|
+
}
|
|
321
|
+
} else {
|
|
322
|
+
const fileCode = fs.readFileSync(args.path, 'utf8')
|
|
323
|
+
contents = `
|
|
324
|
+
(function() {
|
|
325
|
+
${fileCode}
|
|
326
|
+
})(...arguments);
|
|
327
|
+
{
|
|
328
|
+
const dc = require('dc-polyfill');
|
|
329
|
+
const ch = dc.channel('${CHANNEL}');
|
|
330
|
+
const mod = module.exports
|
|
331
|
+
const payload = {
|
|
332
|
+
module: mod,
|
|
333
|
+
version: '${data.version}',
|
|
334
|
+
package: '${data.pkg}',
|
|
335
|
+
path: '${pkgPath}'
|
|
336
|
+
};
|
|
337
|
+
ch.publish(payload);
|
|
338
|
+
module.exports = payload.module;
|
|
339
|
+
}
|
|
340
|
+
`
|
|
341
|
+
}
|
|
261
342
|
|
|
262
|
-
const contents = `
|
|
263
|
-
(function() {
|
|
264
|
-
${fileCode}
|
|
265
|
-
})(...arguments);
|
|
266
|
-
{
|
|
267
|
-
const dc = require('dc-polyfill');
|
|
268
|
-
const ch = dc.channel('${CHANNEL}');
|
|
269
|
-
const mod = module.exports
|
|
270
|
-
const payload = {
|
|
271
|
-
module: mod,
|
|
272
|
-
version: '${data.version}',
|
|
273
|
-
package: '${data.pkg}',
|
|
274
|
-
path: '${pkgPath}'
|
|
275
|
-
};
|
|
276
|
-
ch.publish(payload);
|
|
277
|
-
module.exports = payload.module;
|
|
278
|
-
}
|
|
279
|
-
`
|
|
280
343
|
// https://esbuild.github.io/plugins/#on-load-results
|
|
281
344
|
return {
|
|
282
345
|
contents,
|
|
@@ -284,7 +347,6 @@ ${build.initialOptions.banner.js}`
|
|
|
284
347
|
resolveDir: path.dirname(args.path)
|
|
285
348
|
}
|
|
286
349
|
}
|
|
287
|
-
|
|
288
350
|
if (DD_IAST_ENABLED && args.pluginData?.applicationFile) {
|
|
289
351
|
const ext = path.extname(args.path).toLowerCase()
|
|
290
352
|
const isJs = /^\.(js|mjs|cjs)$/.test(ext)
|
|
@@ -303,12 +365,19 @@ ${build.initialOptions.banner.js}`
|
|
|
303
365
|
}
|
|
304
366
|
|
|
305
367
|
// @see https://github.com/nodejs/node/issues/47000
|
|
306
|
-
function dotFriendlyResolve (path, directory) {
|
|
368
|
+
function dotFriendlyResolve (path, directory, usesImportStatement) {
|
|
307
369
|
if (path === '.') {
|
|
308
370
|
path = './'
|
|
309
371
|
} else if (path === '..') {
|
|
310
372
|
path = '../'
|
|
311
373
|
}
|
|
374
|
+
let conditions
|
|
375
|
+
if (usesImportStatement) {
|
|
376
|
+
conditions = new Set(['import', 'node'])
|
|
377
|
+
}
|
|
312
378
|
|
|
313
|
-
|
|
379
|
+
if (path.startsWith('file://')) {
|
|
380
|
+
path = fileURLToPath(path)
|
|
381
|
+
}
|
|
382
|
+
return require.resolve(path, { paths: [directory], conditions })
|
|
314
383
|
}
|
|
@@ -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
|
+
}
|
|
@@ -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
|
|