dd-trace 6.13.0 → 6.14.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 +3 -1
- package/ci/init.js +8 -3
- package/ci/test-optimization-validation/ci-package-scripts.js +2 -2
- package/ci/test-optimization-validation/ci-remediation.js +6 -6
- package/ci/test-optimization-validation/command-blocker.js +7 -5
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +1 -1
- package/ci/test-optimization-validation/framework-adapters/vitest.js +3 -3
- package/ci/test-optimization-validation/package-check.js +1 -1
- package/ci/test-optimization-validation/report-writer.js +7 -5
- package/ci/vitest-no-worker-init-runner-setup.mjs +8 -0
- package/ci/vitest-no-worker-init-setup.mjs +13 -13
- package/ci/vitest-no-worker-init-v5-setup.mjs +4 -0
- package/package.json +13 -10
- package/packages/datadog-esbuild/index.js +3 -1
- package/packages/datadog-instrumentations/src/cypress-config.js +19 -17
- package/packages/datadog-instrumentations/src/fs.js +24 -20
- package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -2
- package/packages/datadog-instrumentations/src/graphql.js +16 -16
- package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +504 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +265 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +95 -30
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +0 -25
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +83 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +85 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/mercurius.js +30 -12
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +13 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +251 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +11 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +562 -27
- package/packages/datadog-instrumentations/src/jest.js +25 -20
- package/packages/datadog-instrumentations/src/knex.js +76 -0
- package/packages/datadog-instrumentations/src/mariadb.js +6 -0
- package/packages/datadog-instrumentations/src/mocha/common.js +59 -2
- package/packages/datadog-instrumentations/src/mocha/main.js +25 -15
- package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +98 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +12 -8
- package/packages/datadog-instrumentations/src/net.js +14 -17
- package/packages/datadog-instrumentations/src/next.js +212 -62
- package/packages/datadog-instrumentations/src/openai.js +42 -40
- package/packages/datadog-instrumentations/src/pg.js +15 -0
- package/packages/datadog-instrumentations/src/playwright.js +109 -13
- package/packages/datadog-instrumentations/src/rum-browser-scripts.js +40 -0
- package/packages/datadog-instrumentations/src/sequelize.js +94 -2
- package/packages/datadog-instrumentations/src/undici.js +53 -4
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +37 -3
- package/packages/datadog-instrumentations/src/vitest-main.js +92 -9
- package/packages/datadog-instrumentations/src/vitest-worker.js +71 -14
- package/packages/datadog-instrumentations/src/webdriverio.js +965 -6
- package/packages/datadog-plugin-amqp10/src/consumer.js +3 -1
- package/packages/datadog-plugin-amqp10/src/producer.js +3 -1
- package/packages/datadog-plugin-amqp10/src/util.js +2 -1
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +6 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +16 -5
- package/packages/datadog-plugin-cassandra-driver/src/index.js +8 -3
- package/packages/datadog-plugin-cucumber/src/index.js +0 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +262 -48
- package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -1
- package/packages/datadog-plugin-graphql/src/execute.js +998 -196
- package/packages/datadog-plugin-graphql/src/index.js +27 -7
- package/packages/datadog-plugin-graphql/src/jit.js +136 -0
- package/packages/datadog-plugin-graphql/src/request.js +18 -27
- package/packages/datadog-plugin-graphql/src/resolve-error.js +108 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -2
- package/packages/datadog-plugin-graphql/src/tools/transforms.js +45 -3
- package/packages/datadog-plugin-graphql/src/utils.js +208 -120
- package/packages/datadog-plugin-graphql/src/validate.js +10 -23
- package/packages/datadog-plugin-jest/src/index.js +0 -6
- package/packages/datadog-plugin-langchain/src/tracing.js +7 -0
- package/packages/datadog-plugin-mocha/src/index.js +403 -75
- package/packages/datadog-plugin-mongodb-core/src/query.js +6 -0
- package/packages/datadog-plugin-mysql/src/index.js +41 -15
- package/packages/datadog-plugin-net/src/tcp.js +3 -1
- package/packages/datadog-plugin-next/src/index.js +63 -29
- package/packages/datadog-plugin-playwright/src/index.js +167 -27
- package/packages/datadog-plugin-undici/src/index.js +27 -41
- package/packages/datadog-plugin-vitest/src/index.js +6 -12
- package/packages/dd-trace/src/aiguard/evaluation.js +2 -1
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +8 -1
- package/packages/dd-trace/src/aiguard/messages/openai.js +8 -1
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +20 -6
- package/packages/dd-trace/src/appsec/api_security/index.js +23 -6
- package/packages/dd-trace/src/appsec/api_security/sampler.js +99 -40
- package/packages/dd-trace/src/appsec/graphql.js +6 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -1
- package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +8 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +11 -36
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/lambda.js +44 -26
- package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +32 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +8 -8
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +6 -4
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +20 -4
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +5 -173
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agents.js +54 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +1 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +394 -225
- package/packages/dd-trace/src/ci-visibility/exporters/limits.js +9 -0
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +323 -31
- package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +42 -0
- package/packages/dd-trace/src/ci-visibility/final-flush.js +2 -1
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +57 -18
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +0 -3
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +164 -71
- package/packages/dd-trace/src/ci-visibility/requests/video-request.js +176 -0
- package/packages/dd-trace/src/ci-visibility/telemetry.js +10 -7
- package/packages/dd-trace/src/ci-visibility/test-video.js +61 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -0
- package/packages/dd-trace/src/config/index.js +73 -13
- package/packages/dd-trace/src/config/parsers.js +11 -1
- package/packages/dd-trace/src/config/stable.js +3 -3
- package/packages/dd-trace/src/config/supported-configurations.json +20 -2
- package/packages/dd-trace/src/crashtracking/crashtracker.js +82 -18
- package/packages/dd-trace/src/debugger/config.js +12 -1
- package/packages/dd-trace/src/debugger/constants.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/request-options.js +33 -0
- package/packages/dd-trace/src/debugger/devtools_client/send.js +7 -40
- package/packages/dd-trace/src/debugger/devtools_client/status.js +11 -6
- package/packages/dd-trace/src/debugger/devtools_client/tags.js +41 -0
- package/packages/dd-trace/src/debugger/index.js +23 -3
- package/packages/dd-trace/src/dogstatsd.js +510 -76
- package/packages/dd-trace/src/encode/0.4-cross-payload.js +170 -0
- package/packages/dd-trace/src/encode/0.4.js +5 -5
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +9 -8
- package/packages/dd-trace/src/evp_proxy/direct.js +27 -23
- package/packages/dd-trace/src/exporters/agent/index.js +2 -1
- package/packages/dd-trace/src/exporters/agent/writer.js +24 -7
- package/packages/dd-trace/src/exporters/agentless/index.js +7 -9
- package/packages/dd-trace/src/exporters/agentless/writer.js +100 -118
- package/packages/dd-trace/src/exporters/common/agents.js +28 -6
- package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -2
- package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +191 -0
- package/packages/dd-trace/src/exporters/common/request.js +31 -11
- package/packages/dd-trace/src/exporters/common/url.js +40 -1
- package/packages/dd-trace/src/exporters/common/writer.js +9 -7
- package/packages/dd-trace/src/flush.js +6 -3
- package/packages/dd-trace/src/id.js +14 -0
- package/packages/dd-trace/src/index.js +5 -2
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +2 -1
- package/packages/dd-trace/src/llmobs/index.js +32 -32
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +22 -71
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +23 -13
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +7 -0
- package/packages/dd-trace/src/llmobs/util.js +0 -33
- package/packages/dd-trace/src/llmobs/writers/base.js +49 -32
- package/packages/dd-trace/src/log/index.js +7 -1
- package/packages/dd-trace/src/{ci-visibility/log-submission → log-submission}/log-submission-plugin.js +48 -19
- package/packages/dd-trace/src/openfeature/writers/base.js +14 -12
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/index.js +5 -24
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +14 -4
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +15 -22
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +14 -4
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +10 -0
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +19 -4
- package/packages/dd-trace/src/opentelemetry/resource-attributes.js +55 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +6 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +10 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +93 -18
- package/packages/dd-trace/src/payload-tagging/index.js +2 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +1 -6
- package/packages/dd-trace/src/plugins/tracing.js +12 -10
- package/packages/dd-trace/src/plugins/util/ci.js +3 -1
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +16 -15
- package/packages/dd-trace/src/plugins/util/test.js +83 -20
- package/packages/dd-trace/src/plugins/util/url.js +2 -2
- package/packages/dd-trace/src/plugins/util/web.js +4 -9
- package/packages/dd-trace/src/profiling/config.js +1 -0
- package/packages/dd-trace/src/profiling/oom.js +7 -2
- package/packages/dd-trace/src/profiling/profiler.js +23 -13
- package/packages/dd-trace/src/profiling/profilers/space.js +38 -11
- package/packages/dd-trace/src/profiling/webspan-utils.js +7 -4
- package/packages/dd-trace/src/proxy.js +75 -5
- package/packages/dd-trace/src/remote_config/index.js +319 -101
- package/packages/dd-trace/src/remote_config/scheduler.js +37 -12
- package/packages/dd-trace/src/runtime_metrics/client.js +37 -8
- package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +5 -1
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -1
- package/packages/dd-trace/src/sampling_rule.js +36 -9
- package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +4 -8
- package/packages/dd-trace/src/serverless/vercel.js +53 -20
- package/packages/dd-trace/src/serverless.js +10 -3
- package/packages/dd-trace/src/service-naming/schemas/util.js +1 -1
- package/packages/dd-trace/src/span_stats.js +24 -28
- package/packages/dd-trace/src/startup-log.js +3 -2
- package/packages/dd-trace/src/telemetry/agentless-url.js +28 -0
- package/packages/dd-trace/src/telemetry/send-data.js +18 -16
- package/packages/dd-trace/src/telemetry/session-propagation.js +3 -2
- package/packages/dd-trace/src/tracer.js +4 -5
- package/packages/dd-trace/src/tracer_metadata.js +11 -3
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +0 -27
- package/packages/dd-trace/src/encode/agentless-json.js +0 -210
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { isNativeError } = require('node:util').types
|
|
4
|
+
|
|
3
5
|
const shimmer = require('../../datadog-shimmer')
|
|
4
6
|
const nomenclature = require('../../dd-trace/src/service-naming')
|
|
5
7
|
const spanEndingHook = require('../../dd-trace/src/opentelemetry/span-ending-hook')
|
|
@@ -12,11 +14,44 @@ const errorChannel = channel('apm:next:request:error')
|
|
|
12
14
|
const pageLoadChannel = channel('apm:next:page:load')
|
|
13
15
|
const bodyParsedChannel = channel('apm:next:body-parsed')
|
|
14
16
|
const queryParsedChannel = channel('apm:next:query-parsed')
|
|
17
|
+
const backgroundRevalidationChannel = channel('apm:next:request:background-revalidation')
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {import('node:http').IncomingMessage & {
|
|
21
|
+
* error?: unknown,
|
|
22
|
+
* originalRequest?: import('node:http').IncomingMessage
|
|
23
|
+
* }} NextNodeRequest
|
|
24
|
+
*
|
|
25
|
+
* @typedef {import('node:http').ServerResponse & {
|
|
26
|
+
* originalResponse?: import('node:http').ServerResponse
|
|
27
|
+
* }} NextNodeResponse
|
|
28
|
+
*
|
|
29
|
+
* @typedef {object} NextRequest
|
|
30
|
+
* @property {unknown} [error]
|
|
31
|
+
*
|
|
32
|
+
* @typedef {object} NextRequestContext
|
|
33
|
+
* @property {NextNodeRequest} req
|
|
34
|
+
* @property {NextNodeResponse} res
|
|
35
|
+
* @property {boolean} [finishOnResponse]
|
|
36
|
+
* @property {boolean} [handlerFinished]
|
|
37
|
+
* @property {boolean} [responseFinished]
|
|
38
|
+
* @property {unknown} [error]
|
|
39
|
+
* @property {NextRequest} [nextRequest]
|
|
40
|
+
*
|
|
41
|
+
* @typedef {object} ResponseGeneratorContext
|
|
42
|
+
* @property {boolean} [hasResolved]
|
|
43
|
+
*
|
|
44
|
+
* @typedef {object} HandleResponseOptions
|
|
45
|
+
* @property {NextNodeRequest} req
|
|
46
|
+
* @property {(context?: ResponseGeneratorContext) => Promise<unknown>} responseGenerator
|
|
47
|
+
*
|
|
48
|
+
* @typedef {object} ResponseCacheEntry
|
|
49
|
+
* @property {{ status?: number }} [value]
|
|
50
|
+
*/
|
|
15
51
|
|
|
16
52
|
const requests = new WeakSet()
|
|
17
53
|
const nodeNextRequestsToNextRequests = new WeakMap()
|
|
18
|
-
const
|
|
19
|
-
|
|
54
|
+
const noFallbackErrorPrototypes = new WeakSet()
|
|
20
55
|
// Next.js <= 14.2.6
|
|
21
56
|
const MIDDLEWARE_HEADER = 'x-middleware-invoke'
|
|
22
57
|
|
|
@@ -149,7 +184,16 @@ function getRequestMeta (req, key) {
|
|
|
149
184
|
return typeof key === 'string' ? meta[key] : meta
|
|
150
185
|
}
|
|
151
186
|
|
|
152
|
-
|
|
187
|
+
/**
|
|
188
|
+
* @template T
|
|
189
|
+
* @param {NextNodeRequest} req
|
|
190
|
+
* @param {NextNodeResponse} res
|
|
191
|
+
* @param {(ctx: NextRequestContext) => Promise<T>} handler
|
|
192
|
+
* @param {unknown} [error]
|
|
193
|
+
* @param {boolean} [finishOnResponse]
|
|
194
|
+
* @returns {Promise<T>}
|
|
195
|
+
*/
|
|
196
|
+
function instrument (req, res, handler, error, finishOnResponse = false) {
|
|
153
197
|
req = req.originalRequest || req
|
|
154
198
|
res = res.originalResponse || res
|
|
155
199
|
|
|
@@ -165,7 +209,17 @@ function instrument (req, res, handler, error) {
|
|
|
165
209
|
|
|
166
210
|
requests.add(req)
|
|
167
211
|
|
|
168
|
-
const ctx = { req, res }
|
|
212
|
+
const ctx = finishOnResponse ? { req, res, finishOnResponse } : { req, res }
|
|
213
|
+
if (finishOnResponse) {
|
|
214
|
+
const onResponseFinish = () => {
|
|
215
|
+
res.removeListener('finish', onResponseFinish)
|
|
216
|
+
res.removeListener('close', onResponseFinish)
|
|
217
|
+
ctx.responseFinished = true
|
|
218
|
+
if (ctx.handlerFinished) publishFinish(ctx, ctx.error)
|
|
219
|
+
}
|
|
220
|
+
res.once('finish', onResponseFinish)
|
|
221
|
+
res.once('close', onResponseFinish)
|
|
222
|
+
}
|
|
169
223
|
if (queryParsedChannel.hasSubscribers && req.url) {
|
|
170
224
|
const queryIndex = req.url.indexOf('?')
|
|
171
225
|
if (queryIndex !== -1) {
|
|
@@ -213,9 +267,8 @@ function wrapServeStatic (serveStatic) {
|
|
|
213
267
|
}
|
|
214
268
|
}
|
|
215
269
|
|
|
216
|
-
function
|
|
217
|
-
publishError(ctx.req, ctx,
|
|
218
|
-
requestErrors.delete(ctx.req)
|
|
270
|
+
function publishFinish (ctx, error) {
|
|
271
|
+
publishError(ctx.req, ctx, error)
|
|
219
272
|
|
|
220
273
|
const maybeNextRequest = nodeNextRequestsToNextRequests.get(ctx.req)
|
|
221
274
|
if (maybeNextRequest) {
|
|
@@ -225,24 +278,35 @@ function finish (ctx, result, err) {
|
|
|
225
278
|
finishChannel.publish(ctx)
|
|
226
279
|
}
|
|
227
280
|
|
|
228
|
-
function
|
|
229
|
-
if (
|
|
281
|
+
function finish (ctx, result, error) {
|
|
282
|
+
if (ctx.finishOnResponse) {
|
|
283
|
+
ctx.handlerFinished = true
|
|
284
|
+
if (error && !isNoFallbackError(error)) ctx.error = error
|
|
285
|
+
if (!ctx.responseFinished) return
|
|
286
|
+
}
|
|
230
287
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (errors?.has(error)) return
|
|
288
|
+
publishFinish(ctx, error)
|
|
289
|
+
}
|
|
234
290
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
291
|
+
/** @param {unknown} error */
|
|
292
|
+
function isNoFallbackError (error) {
|
|
293
|
+
return isNativeError(error) && noFallbackErrorPrototypes.has(Object.getPrototypeOf(error))
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* @param {NextNodeRequest} req
|
|
298
|
+
* @param {NextRequestContext | undefined} ctx
|
|
299
|
+
* @param {unknown} error
|
|
300
|
+
*/
|
|
301
|
+
function publishError (req, ctx, error) {
|
|
302
|
+
if (!error || isNoFallbackError(error)) return
|
|
240
303
|
|
|
241
304
|
if (ctx) {
|
|
242
305
|
ctx.error = error
|
|
243
306
|
errorChannel.publish(ctx)
|
|
244
307
|
} else {
|
|
245
|
-
|
|
308
|
+
req = req.originalRequest || req
|
|
309
|
+
errorChannel.publish({ req, error })
|
|
246
310
|
}
|
|
247
311
|
}
|
|
248
312
|
|
|
@@ -267,13 +331,29 @@ addHook({
|
|
|
267
331
|
// From Next 15.4.1, route modules execute through precompiled runtime bundles that bypass the
|
|
268
332
|
// classic server hooks above. Match bundler and experimental filename variants without enumerating
|
|
269
333
|
// them so App Routes, Pages APIs, and App Pages reuse the existing Next request lifecycle.
|
|
334
|
+
// The route module classes and inherited methods are selected inside those bundles, so there is no
|
|
335
|
+
// stable source function for Orchestrion to rewrite.
|
|
270
336
|
const patchedRouteModules = new WeakSet()
|
|
337
|
+
const routeResponses = new WeakMap()
|
|
338
|
+
const activeRouteRequests = new WeakMap()
|
|
271
339
|
const COMPILED_RUNTIME_PATH = 'dist/compiled/next-server/'
|
|
340
|
+
|
|
341
|
+
/** @param {{ NoFallbackError: typeof Error }} noFallbackError */
|
|
342
|
+
function captureNoFallbackError (noFallbackError) {
|
|
343
|
+
noFallbackErrorPrototypes.add(noFallbackError.NoFallbackError.prototype)
|
|
344
|
+
return noFallbackError
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// The sentinel identity only exists at runtime, so there is no source function for Orchestrion to rewrite.
|
|
348
|
+
addHook({
|
|
349
|
+
name: 'next',
|
|
350
|
+
versions: ['>=15.4.1'],
|
|
351
|
+
file: 'dist/shared/lib/no-fallback-error.external.js',
|
|
352
|
+
}, captureNoFallbackError)
|
|
353
|
+
|
|
272
354
|
function wrapOnRequestError (onRequestError) {
|
|
273
355
|
return function (req, error) {
|
|
274
|
-
if (error)
|
|
275
|
-
errorChannel.publish({ error })
|
|
276
|
-
}
|
|
356
|
+
if (error) publishError(req, undefined, error)
|
|
277
357
|
return onRequestError.apply(this, arguments)
|
|
278
358
|
}
|
|
279
359
|
}
|
|
@@ -296,37 +376,127 @@ function publishRoutePage (ctx, routeModule, fallbackPage, isAppPath) {
|
|
|
296
376
|
|
|
297
377
|
const pageData = getRoutePage(routeModule, fallbackPage)
|
|
298
378
|
if (pageData.page) {
|
|
299
|
-
|
|
379
|
+
if (isAppPath) pageData.isAppPath = true
|
|
380
|
+
pageLoadChannel.publish(pageData)
|
|
300
381
|
}
|
|
301
382
|
}
|
|
302
383
|
|
|
303
384
|
function wrapAppRouteHandle (handle) {
|
|
304
385
|
return function (req, context) {
|
|
386
|
+
if (finishChannel.hasSubscribers) {
|
|
387
|
+
const nodeRequest = activeRouteRequests.get(this)
|
|
388
|
+
if (nodeRequest) {
|
|
389
|
+
nodeNextRequestsToNextRequests.set(nodeRequest, req)
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return handle.apply(this, arguments)
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function wrapPrepare (prepare) {
|
|
398
|
+
return function (req, res) {
|
|
399
|
+
if (startChannel.hasSubscribers || queryParsedChannel.hasSubscribers) {
|
|
400
|
+
routeResponses.set(req, res)
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return prepare.apply(this, arguments)
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* @param {(context?: ResponseGeneratorContext) => unknown} responseGenerator
|
|
409
|
+
* @param {object | undefined} routeModule
|
|
410
|
+
* @param {NextNodeRequest} req
|
|
411
|
+
* @returns {(context?: ResponseGeneratorContext) => unknown}
|
|
412
|
+
*/
|
|
413
|
+
function wrapResponseGenerator (responseGenerator, routeModule, req) {
|
|
414
|
+
return function (context) {
|
|
415
|
+
if (context?.hasResolved) {
|
|
416
|
+
const nodeRequest = req.originalRequest || req
|
|
417
|
+
return backgroundRevalidationChannel.runStores(nodeRequest, () => responseGenerator.apply(this, arguments))
|
|
418
|
+
}
|
|
419
|
+
if (!routeModule) {
|
|
420
|
+
return responseGenerator.apply(this, arguments)
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Next calls the route module before the generator's first await. Limit the association to that
|
|
424
|
+
// synchronous call so concurrent requests can share the route module instance safely.
|
|
425
|
+
activeRouteRequests.set(routeModule, req)
|
|
426
|
+
try {
|
|
427
|
+
return responseGenerator.apply(this, arguments)
|
|
428
|
+
} finally {
|
|
429
|
+
activeRouteRequests.delete(routeModule)
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* @param {(options: HandleResponseOptions) => Promise<ResponseCacheEntry | undefined>} handleResponse
|
|
436
|
+
* @param {boolean} associateNextRequest
|
|
437
|
+
* @returns {(options: HandleResponseOptions) => Promise<ResponseCacheEntry | undefined>}
|
|
438
|
+
*/
|
|
439
|
+
function wrapHandleResponse (handleResponse, associateNextRequest) {
|
|
440
|
+
return function (options) {
|
|
441
|
+
const req = options.req
|
|
305
442
|
if (!startChannel.hasSubscribers && !queryParsedChannel.hasSubscribers) {
|
|
306
|
-
return
|
|
443
|
+
return handleResponse.apply(this, arguments)
|
|
307
444
|
}
|
|
308
445
|
|
|
309
|
-
const res =
|
|
310
|
-
|
|
446
|
+
const res = routeResponses.get(req)
|
|
447
|
+
routeResponses.delete(req)
|
|
448
|
+
|
|
449
|
+
const routeModule = res && associateNextRequest ? this : undefined
|
|
450
|
+
options.responseGenerator = wrapResponseGenerator(options.responseGenerator, routeModule, req)
|
|
451
|
+
|
|
452
|
+
if (!res) return handleResponse.apply(this, arguments)
|
|
311
453
|
|
|
312
454
|
return instrument(req, res, ctx => {
|
|
313
455
|
publishRoutePage(ctx, this, undefined, true)
|
|
314
456
|
|
|
315
|
-
return
|
|
316
|
-
|
|
317
|
-
|
|
457
|
+
return handleResponse.apply(this, arguments).then(result => {
|
|
458
|
+
const statusCode = result?.value?.status
|
|
459
|
+
if (ctx && typeof statusCode === 'number') {
|
|
460
|
+
ctx.res.statusCode = statusCode
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return result
|
|
464
|
+
}, error => {
|
|
465
|
+
if (ctx && (typeof ctx.res.statusCode !== 'number' || ctx.res.statusCode < 400)) {
|
|
466
|
+
ctx.res.statusCode = 500
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
throw error
|
|
318
470
|
})
|
|
319
|
-
})
|
|
471
|
+
}, undefined, finishChannel.hasSubscribers)
|
|
320
472
|
}
|
|
321
473
|
}
|
|
322
474
|
|
|
323
|
-
|
|
475
|
+
/**
|
|
476
|
+
* @param {(options: HandleResponseOptions) => Promise<ResponseCacheEntry | undefined>} handleResponse
|
|
477
|
+
* @returns {(options: HandleResponseOptions) => Promise<ResponseCacheEntry | undefined>}
|
|
478
|
+
*/
|
|
479
|
+
function wrapAppRouteHandleResponse (handleResponse) {
|
|
480
|
+
return wrapHandleResponse(handleResponse, true)
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* @param {(options: HandleResponseOptions) => Promise<ResponseCacheEntry | undefined>} handleResponse
|
|
485
|
+
* @returns {(options: HandleResponseOptions) => Promise<ResponseCacheEntry | undefined>}
|
|
486
|
+
*/
|
|
487
|
+
function wrapAppPageHandleResponse (handleResponse) {
|
|
488
|
+
return wrapHandleResponse(handleResponse, false)
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function instrumentRouteModule (RouteModule, wrappers, handleErrors) {
|
|
324
492
|
const proto = RouteModule?.prototype
|
|
325
493
|
if (!proto || patchedRouteModules.has(RouteModule)) return
|
|
326
494
|
|
|
327
495
|
patchedRouteModules.add(RouteModule)
|
|
328
|
-
|
|
329
|
-
|
|
496
|
+
for (const [method, wrapper] of wrappers) {
|
|
497
|
+
if (typeof proto[method] === 'function') {
|
|
498
|
+
shimmer.wrap(proto, method, wrapper)
|
|
499
|
+
}
|
|
330
500
|
}
|
|
331
501
|
if (handleErrors && typeof proto.onRequestError === 'function') {
|
|
332
502
|
shimmer.wrap(proto, 'onRequestError', wrapOnRequestError)
|
|
@@ -334,7 +504,11 @@ function instrumentRouteModule (RouteModule, method, wrapper, handleErrors) {
|
|
|
334
504
|
}
|
|
335
505
|
|
|
336
506
|
function instrumentAppRouteRuntime (runtime) {
|
|
337
|
-
instrumentRouteModule(runtime.AppRouteRouteModule,
|
|
507
|
+
instrumentRouteModule(runtime.AppRouteRouteModule, [
|
|
508
|
+
['prepare', wrapPrepare],
|
|
509
|
+
['handleResponse', wrapAppRouteHandleResponse],
|
|
510
|
+
['handle', wrapAppRouteHandle],
|
|
511
|
+
], true)
|
|
338
512
|
return runtime
|
|
339
513
|
}
|
|
340
514
|
|
|
@@ -361,40 +535,16 @@ function wrapPagesApiRender (render) {
|
|
|
361
535
|
|
|
362
536
|
function instrumentPagesApiRuntime (runtime) {
|
|
363
537
|
const PagesAPIRouteModule = runtime.PagesAPIRouteModule || runtime.default
|
|
364
|
-
instrumentRouteModule(PagesAPIRouteModule, 'render', wrapPagesApiRender, false)
|
|
538
|
+
instrumentRouteModule(PagesAPIRouteModule, [['render', wrapPagesApiRender]], false)
|
|
365
539
|
return runtime
|
|
366
540
|
}
|
|
367
541
|
|
|
368
|
-
function wrapAppPageRender (render) {
|
|
369
|
-
return function (req, res, context = {}) {
|
|
370
|
-
if (!startChannel.hasSubscribers && !queryParsedChannel.hasSubscribers) {
|
|
371
|
-
return render.apply(this, arguments)
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
return instrument(req, res, ctx => {
|
|
375
|
-
publishRoutePage(ctx, this, context.page, true)
|
|
376
|
-
|
|
377
|
-
return render.apply(this, arguments).then(result => {
|
|
378
|
-
const statusCode = result?.metadata?.statusCode
|
|
379
|
-
if (ctx && typeof statusCode === 'number') {
|
|
380
|
-
ctx.res.statusCode = statusCode
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return result
|
|
384
|
-
}, error => {
|
|
385
|
-
if (ctx && (typeof ctx.res.statusCode !== 'number' || ctx.res.statusCode < 400)) {
|
|
386
|
-
ctx.res.statusCode = 500
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
throw error
|
|
390
|
-
})
|
|
391
|
-
})
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
542
|
function instrumentAppPageRuntime (runtime) {
|
|
396
543
|
const AppPageRouteModule = runtime.AppPageRouteModule || runtime.default
|
|
397
|
-
instrumentRouteModule(AppPageRouteModule,
|
|
544
|
+
instrumentRouteModule(AppPageRouteModule, [
|
|
545
|
+
['prepare', wrapPrepare],
|
|
546
|
+
['handleResponse', wrapAppPageHandleResponse],
|
|
547
|
+
], true)
|
|
398
548
|
return runtime
|
|
399
549
|
}
|
|
400
550
|
|
|
@@ -6,6 +6,7 @@ const { addHook } = require('./helpers/instrument')
|
|
|
6
6
|
|
|
7
7
|
const ch = dc.tracingChannel('apm:openai:request')
|
|
8
8
|
const onStreamedChunkCh = dc.channel('apm:openai:request:chunk')
|
|
9
|
+
const responsePromiseContexts = new WeakMap()
|
|
9
10
|
|
|
10
11
|
// Provider lifecycle channels. Payloads stay OpenAI-native:
|
|
11
12
|
// before { args, parentSpan, abortController, pending }
|
|
@@ -68,7 +69,7 @@ const V4_PACKAGE_SHIMS = [
|
|
|
68
69
|
file: 'resources/responses/responses',
|
|
69
70
|
targetClass: 'Responses',
|
|
70
71
|
baseResource: 'responses',
|
|
71
|
-
methods: ['create'],
|
|
72
|
+
methods: ['create'], // implicitly covers `parse` as well which calls `create` under the hood
|
|
72
73
|
streamedResponse: true,
|
|
73
74
|
versions: ['>=4.87.0'],
|
|
74
75
|
},
|
|
@@ -264,6 +265,42 @@ function wrapStreamIterator (response, options, ctx) {
|
|
|
264
265
|
|
|
265
266
|
const extensions = ['.js', '.mjs']
|
|
266
267
|
|
|
268
|
+
for (const extension of extensions) {
|
|
269
|
+
const apiPromiseShims = [
|
|
270
|
+
{ file: `core${extension}`, versions: ['>=4 <5'] },
|
|
271
|
+
{ file: `core/api-promise${extension}`, versions: ['>=5'] },
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
for (const { file, versions } of apiPromiseShims) {
|
|
275
|
+
// APIPromise is a Promise subclass whose methods are dynamically replaced on pagination instances,
|
|
276
|
+
// so preserving the returned object's identity requires shimmer instead of Orchestrion.
|
|
277
|
+
addHook({ name: 'openai', file, versions }, exports => {
|
|
278
|
+
const { prototype } = exports.APIPromise
|
|
279
|
+
|
|
280
|
+
shimmer.wrap(prototype, 'parse', parse => function (...args) {
|
|
281
|
+
const state = responsePromiseContexts.get(this.responsePromise)
|
|
282
|
+
if (!state) return parse.apply(this, args)
|
|
283
|
+
|
|
284
|
+
const parsedPromise = parse.apply(this, args)
|
|
285
|
+
.then(body => Promise.all([this.responsePromise, body]))
|
|
286
|
+
|
|
287
|
+
return handleUnwrappedAPIPromise(parsedPromise, state)
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
shimmer.wrap(prototype, 'asResponse', asResponse => function (...args) {
|
|
291
|
+
const state = responsePromiseContexts.get(this.responsePromise)
|
|
292
|
+
const responsePromise = asResponse.apply(this, args)
|
|
293
|
+
|
|
294
|
+
if (!state?.getBeforeVerdict) return responsePromise
|
|
295
|
+
|
|
296
|
+
return Promise.all([state.getBeforeVerdict(), responsePromise]).then(([, response]) => response)
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
return exports
|
|
300
|
+
})
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
267
304
|
for (const extension of extensions) {
|
|
268
305
|
for (const shim of V4_PACKAGE_SHIMS) {
|
|
269
306
|
const { file, targetClass, baseResource, methods, versions, streamedResponse } = shim
|
|
@@ -309,44 +346,8 @@ for (const extension of extensions) {
|
|
|
309
346
|
}
|
|
310
347
|
: null
|
|
311
348
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
shimmer.wrap(apiProm, '_thenUnwrap', origApiPromThenUnwrap => function (...args) {
|
|
315
|
-
// TODO(sam.brenner): I wonder if we can patch the APIPromise prototype instead, although
|
|
316
|
-
// we might not have access to everything we need...
|
|
317
|
-
|
|
318
|
-
// this is a new apipromise instance
|
|
319
|
-
const unwrappedPromise = origApiPromThenUnwrap.apply(this, args)
|
|
320
|
-
|
|
321
|
-
shimmer.wrap(unwrappedPromise, 'parse', origApiPromParse => function (...args) {
|
|
322
|
-
const parsedPromise = origApiPromParse.apply(this, args)
|
|
323
|
-
.then(body => Promise.all([this.responsePromise, body]))
|
|
324
|
-
|
|
325
|
-
return handleUnwrappedAPIPromise(
|
|
326
|
-
parsedPromise, ctx, stream, getBeforeVerdict, afterChannel, parentSpan
|
|
327
|
-
)
|
|
328
|
-
})
|
|
329
|
-
|
|
330
|
-
return unwrappedPromise
|
|
331
|
-
})
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// wrapping `parse` avoids problematic wrapping of `then` when trying to call
|
|
335
|
-
// `withResponse` in userland code after. This way, we can return the whole `APIPromise`
|
|
336
|
-
shimmer.wrap(apiProm, 'parse', origApiPromParse => function (...args) {
|
|
337
|
-
const parsedPromise = origApiPromParse.apply(this, args)
|
|
338
|
-
.then(body => Promise.all([this.responsePromise, body]))
|
|
339
|
-
|
|
340
|
-
return handleUnwrappedAPIPromise(parsedPromise, ctx, stream, getBeforeVerdict, afterChannel, parentSpan)
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
// Gate `.asResponse()` callers on the before verdict so raw-response paths still block.
|
|
344
|
-
if (beforeChannel && typeof apiProm.asResponse === 'function') {
|
|
345
|
-
shimmer.wrap(apiProm, 'asResponse', origAsResponse => function (...args) {
|
|
346
|
-
const responsePromise = origAsResponse.apply(this, args)
|
|
347
|
-
return Promise.all([getBeforeVerdict(), responsePromise]).then(([, response]) => response)
|
|
348
|
-
})
|
|
349
|
-
}
|
|
349
|
+
const state = { ctx, stream, getBeforeVerdict, afterChannel, parentSpan }
|
|
350
|
+
responsePromiseContexts.set(apiProm.responsePromise, state)
|
|
350
351
|
|
|
351
352
|
ch.end.publish(ctx)
|
|
352
353
|
|
|
@@ -359,7 +360,8 @@ for (const extension of extensions) {
|
|
|
359
360
|
}
|
|
360
361
|
}
|
|
361
362
|
|
|
362
|
-
function handleUnwrappedAPIPromise (apiProm,
|
|
363
|
+
function handleUnwrappedAPIPromise (apiProm, state) {
|
|
364
|
+
const { ctx, stream, getBeforeVerdict, afterChannel, parentSpan } = state
|
|
363
365
|
const gatedApiProm = getBeforeVerdict
|
|
364
366
|
? Promise.all([getBeforeVerdict(), apiProm]).then(([, result]) => result)
|
|
365
367
|
: apiProm
|
|
@@ -11,10 +11,12 @@ const {
|
|
|
11
11
|
const {
|
|
12
12
|
clearPoolWaitTime,
|
|
13
13
|
dispatchesAcquireSynchronously,
|
|
14
|
+
getPoolAcquireCapture,
|
|
14
15
|
isPoolQueryAcquire,
|
|
15
16
|
runOutsidePoolQueryAcquire,
|
|
16
17
|
runPoolAcquireError,
|
|
17
18
|
runWithPoolWait,
|
|
19
|
+
setPoolAcquireCaptureWaitTime,
|
|
18
20
|
takePoolWaitTime,
|
|
19
21
|
wrapPoolAcquireCarrier,
|
|
20
22
|
wrapPoolQueryMethod,
|
|
@@ -69,6 +71,19 @@ addHook({ name: 'pg', versions: ['>=8.0.3'] }, pg => {
|
|
|
69
71
|
* @returns {unknown}
|
|
70
72
|
*/
|
|
71
73
|
const wrappedConnect = function (callback) {
|
|
74
|
+
const capture = getPoolAcquireCapture()
|
|
75
|
+
if (capture !== undefined && typeof callback !== 'function') {
|
|
76
|
+
const start = acquireStart(this)
|
|
77
|
+
const result = connect.apply(this, arguments)
|
|
78
|
+
return result.then(client => {
|
|
79
|
+
setPoolAcquireCaptureWaitTime(capture, acquireWait(start))
|
|
80
|
+
return client
|
|
81
|
+
}, error => {
|
|
82
|
+
setPoolAcquireCaptureWaitTime(capture, acquireWait(start))
|
|
83
|
+
throw error
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
72
87
|
// Pool.query always supplies a callback, so a missing callback is an explicit acquire.
|
|
73
88
|
if (typeof callback !== 'function') {
|
|
74
89
|
if (!poolAcquireStartCh.hasSubscribers) {
|