dd-trace 5.98.0 → 5.99.1

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 (139) hide show
  1. package/LICENSE-3rdparty.csv +0 -1
  2. package/ext/tags.js +1 -0
  3. package/index.d.ts +9 -1
  4. package/package.json +68 -47
  5. package/packages/datadog-instrumentations/src/crypto.js +45 -0
  6. package/packages/datadog-instrumentations/src/cypress-config.js +122 -16
  7. package/packages/datadog-instrumentations/src/dns.js +24 -56
  8. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  9. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +74 -0
  10. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +4 -1
  11. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  12. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +10 -3
  13. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  14. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/modelcontextprotocol-sdk.js +59 -0
  15. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +11 -2
  16. package/packages/datadog-instrumentations/src/jest.js +5 -5
  17. package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +7 -0
  18. package/packages/datadog-instrumentations/src/pino.js +4 -28
  19. package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +27 -0
  20. package/packages/datadog-instrumentations/src/playwright.js +5 -17
  21. package/packages/datadog-instrumentations/src/stripe.js +38 -24
  22. package/packages/datadog-instrumentations/src/vitest.js +32 -4
  23. package/packages/datadog-instrumentations/src/zlib.js +29 -0
  24. package/packages/datadog-plugin-aws-sdk/src/base.js +1 -2
  25. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +8 -15
  26. package/packages/datadog-plugin-azure-service-bus/src/producer.js +4 -9
  27. package/packages/datadog-plugin-cucumber/src/index.js +2 -2
  28. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +5 -5
  29. package/packages/datadog-plugin-cypress/src/source-map-utils.js +48 -1
  30. package/packages/datadog-plugin-dd-trace-api/src/index.js +1 -1
  31. package/packages/datadog-plugin-graphql/src/utils.js +2 -2
  32. package/packages/datadog-plugin-http/src/server.js +11 -11
  33. package/packages/datadog-plugin-jest/src/index.js +2 -2
  34. package/packages/datadog-plugin-memcached/src/index.js +1 -1
  35. package/packages/datadog-plugin-mocha/src/index.js +1 -2
  36. package/packages/datadog-plugin-modelcontextprotocol-sdk/src/index.js +24 -0
  37. package/packages/datadog-plugin-modelcontextprotocol-sdk/src/tracing.js +55 -0
  38. package/packages/datadog-plugin-mongodb-core/src/index.js +1 -6
  39. package/packages/datadog-plugin-playwright/src/index.js +2 -3
  40. package/packages/datadog-plugin-vitest/src/index.js +14 -6
  41. package/packages/datadog-plugin-ws/src/close.js +2 -0
  42. package/packages/datadog-plugin-ws/src/producer.js +2 -0
  43. package/packages/datadog-plugin-ws/src/receiver.js +1 -0
  44. package/packages/dd-trace/src/aiguard/channels.js +8 -0
  45. package/packages/dd-trace/src/aiguard/index.js +7 -3
  46. package/packages/dd-trace/src/aiguard/sdk.js +44 -0
  47. package/packages/dd-trace/src/aiguard/tags.js +1 -0
  48. package/packages/dd-trace/src/appsec/blocking.js +18 -6
  49. package/packages/dd-trace/src/appsec/graphql.js +7 -7
  50. package/packages/dd-trace/src/appsec/index.js +9 -11
  51. package/packages/dd-trace/src/appsec/rasp/command_injection.js +4 -5
  52. package/packages/dd-trace/src/appsec/rasp/lfi.js +8 -4
  53. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +5 -10
  54. package/packages/dd-trace/src/appsec/rasp/ssrf.js +5 -6
  55. package/packages/dd-trace/src/appsec/recommended.json +2438 -13
  56. package/packages/dd-trace/src/appsec/reporter.js +6 -5
  57. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +4 -8
  58. package/packages/dd-trace/src/appsec/store.js +50 -0
  59. package/packages/dd-trace/src/appsec/waf/index.js +3 -5
  60. package/packages/dd-trace/src/baggage.js +16 -13
  61. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -2
  62. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -2
  63. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +2 -2
  64. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
  65. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -1
  66. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +3 -4
  67. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -2
  68. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +4 -5
  69. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +3 -4
  70. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +6 -6
  71. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +2 -2
  72. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +2 -2
  73. package/packages/dd-trace/src/config/config-types.d.ts +0 -4
  74. package/packages/dd-trace/src/config/defaults.js +10 -10
  75. package/packages/dd-trace/src/config/generated-config-types.d.ts +39 -38
  76. package/packages/dd-trace/src/config/index.js +29 -39
  77. package/packages/dd-trace/src/config/parsers.js +26 -9
  78. package/packages/dd-trace/src/config/supported-configurations.json +46 -78
  79. package/packages/dd-trace/src/debugger/config.js +2 -0
  80. package/packages/dd-trace/src/debugger/devtools_client/send.js +25 -5
  81. package/packages/dd-trace/src/dogstatsd.js +5 -8
  82. package/packages/dd-trace/src/encode/0.4.js +4 -5
  83. package/packages/dd-trace/src/exporter.js +1 -1
  84. package/packages/dd-trace/src/exporters/agent/index.js +0 -1
  85. package/packages/dd-trace/src/exporters/agent/writer.js +1 -2
  86. package/packages/dd-trace/src/exporters/agentless/writer.js +3 -3
  87. package/packages/dd-trace/src/exporters/common/util.js +2 -2
  88. package/packages/dd-trace/src/git_metadata_tagger.js +1 -1
  89. package/packages/dd-trace/src/id.js +2 -0
  90. package/packages/dd-trace/src/index.js +2 -5
  91. package/packages/dd-trace/src/lambda/handler.js +1 -3
  92. package/packages/dd-trace/src/llmobs/constants/tags.js +3 -0
  93. package/packages/dd-trace/src/llmobs/plugins/{anthropic.js → anthropic/index.js} +5 -63
  94. package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +106 -0
  95. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +3 -2
  96. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +3 -2
  97. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +2 -1
  98. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +0 -49
  99. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/vectorstore.js +2 -1
  100. package/packages/dd-trace/src/llmobs/plugins/langchain/messages.js +76 -0
  101. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -26
  102. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/index.js +68 -0
  103. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +57 -0
  104. package/packages/dd-trace/src/llmobs/sdk.js +23 -3
  105. package/packages/dd-trace/src/llmobs/span_processor.js +14 -1
  106. package/packages/dd-trace/src/llmobs/writers/base.js +7 -1
  107. package/packages/dd-trace/src/llmobs/writers/spans.js +1 -1
  108. package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +103 -0
  109. package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -0
  110. package/packages/dd-trace/src/opentelemetry/logs/index.js +6 -6
  111. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +3 -2
  112. package/packages/dd-trace/src/opentelemetry/metrics/index.js +7 -7
  113. package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +3 -2
  114. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +19 -66
  115. package/packages/dd-trace/src/opentelemetry/trace/index.js +11 -16
  116. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +11 -3
  117. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +51 -41
  118. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -11
  119. package/packages/dd-trace/src/opentracing/propagation/text_map.js +30 -23
  120. package/packages/dd-trace/src/opentracing/span.js +2 -2
  121. package/packages/dd-trace/src/opentracing/tracer.js +12 -5
  122. package/packages/dd-trace/src/plugin_manager.js +6 -6
  123. package/packages/dd-trace/src/plugins/index.js +1 -0
  124. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  125. package/packages/dd-trace/src/plugins/util/test.js +128 -7
  126. package/packages/dd-trace/src/plugins/util/url.js +2 -1
  127. package/packages/dd-trace/src/profiling/profilers/event_plugins/crypto.js +32 -0
  128. package/packages/dd-trace/src/profiling/profilers/event_plugins/zlib.js +19 -0
  129. package/packages/dd-trace/src/profiling/profilers/events.js +35 -0
  130. package/packages/dd-trace/src/proxy.js +8 -14
  131. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +2 -2
  132. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
  133. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
  134. package/packages/dd-trace/src/span_processor.js +1 -2
  135. package/packages/dd-trace/src/tagger.js +2 -2
  136. package/packages/dd-trace/src/telemetry/send-data.js +5 -7
  137. package/packages/dd-trace/src/tracer.js +2 -2
  138. package/vendor/dist/ignore/LICENSE +0 -21
  139. package/vendor/dist/ignore/index.js +0 -1
@@ -68,7 +68,6 @@
68
68
  "esquery","https://github.com/estools/esquery","['BSD-3-Clause']","['Joel Feenstra']"
69
69
  "estraverse","https://github.com/estools/estraverse","['BSD-2-Clause']","['estools']"
70
70
  "fast-fifo","https://github.com/mafintosh/fast-fifo","['MIT']","['Mathias Buus']"
71
- "ignore","https://github.com/kaelzhang/node-ignore","['MIT']","['kael']"
72
71
  "import-in-the-middle","https://github.com/nodejs/import-in-the-middle","['Apache-2.0']","['Bryan English']"
73
72
  "istanbul-lib-coverage","https://github.com/istanbuljs/istanbuljs","['BSD-3-Clause']","['Krishnan Anantheswaran']"
74
73
  "jest-docblock","https://github.com/jestjs/jest","['MIT']","['jestjs']"
package/ext/tags.js CHANGED
@@ -25,6 +25,7 @@ const tags = {
25
25
  HTTP_RESPONSE_HEADERS: 'http.response.headers',
26
26
  HTTP_USERAGENT: 'http.useragent',
27
27
  HTTP_CLIENT_IP: 'http.client_ip',
28
+ NETWORK_CLIENT_IP: 'network.client.ip',
28
29
 
29
30
  // Messaging
30
31
 
package/index.d.ts CHANGED
@@ -272,6 +272,7 @@ interface Plugins {
272
272
  "memcached": tracer.plugins.memcached;
273
273
  "microgateway-core": tracer.plugins.microgateway_core;
274
274
  "mocha": tracer.plugins.mocha;
275
+ "modelcontextprotocol-sdk": tracer.plugins.modelcontextprotocol_sdk;
275
276
  "moleculer": tracer.plugins.moleculer;
276
277
  "mongodb-core": tracer.plugins.mongodb_core;
277
278
  "mongoose": tracer.plugins.mongoose;
@@ -2848,11 +2849,18 @@ declare namespace tracer {
2848
2849
  * [mocha](https://mochajs.org/) module.
2849
2850
  */
2850
2851
  interface mocha extends Integration {}
2851
-
2852
+
2853
+ /**
2854
+ * This plugin automatically instruments the
2855
+ * [modelcontextprotocol-sdk](https://github.com/npmjs/package/@modelcontextprotocol/sdk) library.
2856
+ */
2857
+ interface modelcontextprotocol_sdk extends Instrumentation {}
2858
+
2852
2859
  /**
2853
2860
  * This plugin automatically instruments the
2854
2861
  * [moleculer](https://moleculer.services/) module.
2855
2862
  */
2863
+
2856
2864
  interface moleculer extends Moleculer {
2857
2865
  /**
2858
2866
  * Configuration for Moleculer clients. Set to false to disable client
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.98.0",
3
+ "version": "5.99.1",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -13,6 +13,8 @@
13
13
  "dependencies:dedupe": "yarn-deduplicate yarn.lock",
14
14
  "generate:config:types": "node scripts/generate-config-types.js",
15
15
  "verify:config:types": "node scripts/generate-config-types.js --check",
16
+ "generate:supported-integrations": "node scripts/generate-supported-integrations.js",
17
+ "verify:supported-integrations": "node scripts/generate-supported-integrations.js --check",
16
18
  "type:check": "tsc --noEmit -p tsconfig.dev.json",
17
19
  "type:doc:build": "cd docs && yarn && yarn build",
18
20
  "type:doc:test": "cd docs && yarn && yarn test",
@@ -24,66 +26,82 @@
24
26
  "release:proposal": "node scripts/release/proposal",
25
27
  "services": "node ./scripts/install_plugin_modules && node packages/dd-trace/test/setup/services",
26
28
  "test": "echo '\nError: The root \"npm test\" command is intentionally disabled.\n\nInstead, run specific test suites:\n - npm run test:trace:core\n - npm run test:appsec\n - etc.\n\nOr run individual test files:\n npx mocha path/to/test.spec.js\n\nSee CONTRIBUTING.md (Testing section) for more details.\n' && exit 1",
27
- "test:aiguard": "mocha packages/dd-trace/test/aiguard/**/*.spec.js",
28
- "test:aiguard:ci": "nyc -- npm run test:aiguard",
29
+ "test:aiguard": "mocha \"packages/dd-trace/test/aiguard/**/*.spec.js\"",
30
+ "test:aiguard:ci": "nyc --silent node init && nyc -- npm run test:aiguard",
29
31
  "test:appsec": "mocha --exclude \"packages/dd-trace/test/appsec/**/*.plugin.spec.js\" \"packages/dd-trace/test/appsec/**/*.spec.js\"",
30
- "test:appsec:ci": "nyc -- npm run test:appsec",
32
+ "test:appsec:ci": "nyc --silent node init && nyc -- npm run test:appsec",
31
33
  "test:appsec:plugins": "mocha \"packages/dd-trace/test/appsec/**/*.@(${PLUGINS}).plugin.spec.js\"",
32
- "test:appsec:plugins:ci": "yarn services && nyc -- npm run test:appsec:plugins",
33
- "test:debugger": "mocha packages/dd-trace/test/debugger/**/*.spec.js",
34
- "test:debugger:ci": "nyc -- npm run test:debugger",
34
+ "test:appsec:plugins:ci": "yarn services && nyc --silent node init && nyc -- npm run test:appsec:plugins",
35
+ "test:debugger": "mocha \"packages/dd-trace/test/debugger/**/*.spec.js\"",
36
+ "test:debugger:ci": "nyc --silent node init && nyc -- npm run test:debugger",
35
37
  "test:eslint-rules": "node eslint-rules/*.test.mjs",
36
38
  "test:trace:core": "node scripts/mocha-parallel-files.js --expose-gc --timeout 30000 -- \"packages/dd-trace/test/*.spec.js\" \"packages/dd-trace/test/{agent,ci-visibility,config,crashtracking,datastreams,encode,exporters,msgpack,opentelemetry,opentracing,payload-tagging,plugins,remote_config,service-naming,standalone,telemetry,external-logger}/**/*.spec.js\"",
37
- "test:trace:core:ci": "nyc -- npm run test:trace:core",
38
- "test:trace:guardrails": "mocha packages/dd-trace/test/guardrails/**/*.spec.js",
39
- "test:trace:guardrails:ci": "nyc -- npm run test:trace:guardrails",
40
- "test:esbuild": "mocha packages/datadog-esbuild/test/**/*.spec.js",
41
- "test:esbuild:ci": "nyc -- npm run test:esbuild",
42
- "test:webpack": "mocha packages/datadog-webpack/test/**/*.spec.js",
43
- "test:webpack:ci": "nyc -- npm run test:webpack",
39
+ "test:trace:core:ci": "nyc --silent node init && nyc -- npm run test:trace:core",
40
+ "test:trace:guardrails": "mocha \"packages/dd-trace/test/guardrails/**/*.spec.js\"",
41
+ "test:trace:guardrails:ci": "nyc --silent node init && nyc -- npm run test:trace:guardrails",
42
+ "test:esbuild": "mocha \"packages/datadog-esbuild/test/**/*.spec.js\"",
43
+ "test:esbuild:ci": "nyc --silent node init && nyc -- npm run test:esbuild",
44
+ "test:webpack": "mocha \"packages/datadog-webpack/test/**/*.spec.js\"",
45
+ "test:webpack:ci": "nyc --silent node init && nyc -- npm run test:webpack",
44
46
  "test:instrumentations": "mocha \"packages/datadog-instrumentations/test/@(${PLUGINS}).spec.js\"",
45
- "test:instrumentations:ci": "yarn services && nyc -- npm run test:instrumentations",
46
- "test:instrumentations:misc": "mocha packages/datadog-instrumentations/test/*/**/*.spec.js",
47
- "test:instrumentations:misc:ci": "nyc -- npm run test:instrumentations:misc",
48
- "test:core": "node scripts/mocha-parallel-files.js --expose-gc --timeout 30000 -- packages/datadog-core/test/**/*.spec.js",
49
- "test:core:ci": "nyc -- npm run test:core",
50
- "test:code-origin": "mocha packages/datadog-code-origin/test/**/*.spec.js",
51
- "test:code-origin:ci": "nyc -- npm run test:code-origin",
52
- "test:lambda": "mocha packages/dd-trace/test/lambda/**/*.spec.js",
53
- "test:lambda:ci": "nyc -- npm run test:lambda",
47
+ "test:instrumentations:ci": "yarn services && nyc --silent node init && nyc -- npm run test:instrumentations",
48
+ "test:instrumentations:misc": "mocha \"packages/datadog-instrumentations/test/*/**/*.spec.js\"",
49
+ "test:instrumentations:misc:ci": "nyc --silent node init && nyc -- npm run test:instrumentations:misc",
50
+ "test:core": "node scripts/mocha-parallel-files.js --expose-gc --timeout 30000 -- \"packages/datadog-core/test/**/*.spec.js\"",
51
+ "test:core:ci": "nyc --silent node init && nyc -- npm run test:core",
52
+ "test:code-origin": "mocha \"packages/datadog-code-origin/test/**/*.spec.js\"",
53
+ "test:code-origin:ci": "nyc --silent node init && nyc -- npm run test:code-origin",
54
+ "test:lambda": "mocha \"packages/dd-trace/test/lambda/**/*.spec.js\"",
55
+ "test:lambda:ci": "nyc --silent node init && nyc -- npm run test:lambda",
54
56
  "test:llmobs:sdk": "mocha --exclude \"packages/dd-trace/test/llmobs/plugins/**/*.spec.js\" \"packages/dd-trace/test/llmobs/**/*.spec.js\"",
55
- "test:llmobs:sdk:ci": "nyc -- npm run test:llmobs:sdk",
57
+ "test:llmobs:sdk:ci": "nyc --silent node init && nyc -- npm run test:llmobs:sdk",
56
58
  "test:llmobs:plugins": "mocha \"packages/dd-trace/test/llmobs/plugins/@(${PLUGINS})/*.spec.js\"",
57
- "test:llmobs:plugins:ci": "yarn services && nyc -- npm run test:llmobs:plugins",
58
- "test:openfeature": "mocha packages/dd-trace/test/openfeature/**/*.spec.js",
59
- "test:openfeature:ci": "nyc -- npm run test:openfeature",
59
+ "test:llmobs:plugins:ci": "yarn services && nyc --silent node init && nyc -- npm run test:llmobs:plugins",
60
+ "test:openfeature": "mocha \"packages/dd-trace/test/openfeature/**/*.spec.js\"",
61
+ "test:openfeature:ci": "nyc --silent node init && nyc -- npm run test:openfeature",
60
62
  "test:plugins": "node --expose-gc ./node_modules/mocha/bin/mocha.js \"packages/datadog-plugin-@(${PLUGINS})/test/**/${SPEC:-*}*.spec.js\"",
61
- "test:plugins:ci": "yarn services && nyc -- npm run test:plugins",
62
- "test:plugins:ci:flaky": "yarn services && nyc -- npm run test:plugins -- --bail --retries 2",
63
+ "test:plugins:ci": "yarn services && nyc --silent node init && nyc -- npm run test:plugins",
64
+ "test:plugins:ci:flaky": "yarn services && nyc --silent node init && nyc -- npm run test:plugins -- --bail --retries 2",
63
65
  "test:plugins:upstream": "node ./packages/dd-trace/test/plugins/suite.js",
64
- "test:profiler": "node scripts/mocha-parallel-files.js --expose-gc --timeout 30000 -- packages/dd-trace/test/profiling/**/*.spec.js",
65
- "test:profiler:ci": "nyc -- npm run test:profiler",
66
+ "test:profiler": "node scripts/mocha-parallel-files.js --expose-gc --timeout 30000 -- \"packages/dd-trace/test/profiling/**/*.spec.js\"",
67
+ "test:profiler:ci": "nyc --silent node init && nyc -- npm run test:profiler",
66
68
  "test:integration": "mocha --timeout 60000 \"integration-tests/*.spec.js\"",
69
+ "test:integration:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/*.spec.js\"",
67
70
  "test:integration:aiguard": "mocha --timeout 60000 \"integration-tests/aiguard/*.spec.js\"",
71
+ "test:integration:aiguard:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/aiguard/*.spec.js\"",
68
72
  "test:integration:appsec": "mocha --timeout 60000 \"integration-tests/appsec/*.spec.js\"",
73
+ "test:integration:appsec:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/appsec/*.spec.js\"",
69
74
  "test:integration:bun": "mocha --timeout 60000 \"integration-tests/bun/*.spec.js\"",
70
75
  "test:integration:cucumber": "mocha --timeout 60000 \"integration-tests/cucumber/*.spec.js\"",
71
- "test:integration:cypress": "mocha --timeout 60000 \"integration-tests/cypress/*.spec.js\"",
76
+ "test:integration:cucumber:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/cucumber/*.spec.js\"",
77
+ "test:integration:cypress": "mocha --timeout 60000 \"integration-tests/cypress/${SPEC:-cypress-*}.spec.js\"",
78
+ "test:integration:cypress:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/cypress/${SPEC:-cypress-*}.spec.js\"",
72
79
  "test:integration:debugger": "mocha --timeout 60000 \"integration-tests/debugger/*.spec.js\"",
80
+ "test:integration:debugger:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/debugger/*.spec.js\"",
73
81
  "test:integration:esbuild": "mocha --timeout 60000 \"integration-tests/esbuild/*.spec.js\"",
82
+ "test:integration:esbuild:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/esbuild/*.spec.js\"",
74
83
  "test:integration:webpack": "mocha --timeout 60000 \"integration-tests/webpack/*.spec.js\"",
75
84
  "test:integration:openfeature": "mocha --timeout 60000 \"integration-tests/openfeature/*.spec.js\"",
85
+ "test:integration:openfeature:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/openfeature/*.spec.js\"",
76
86
  "test:integration:jest": "mocha --timeout 60000 \"integration-tests/jest/*.spec.js\"",
87
+ "test:integration:jest:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/jest/*.spec.js\"",
77
88
  "test:integration:mocha": "mocha --timeout 60000 \"integration-tests/mocha/*.spec.js\"",
78
- "test:integration:playwright": "mocha --timeout 60000 \"integration-tests/playwright/*.spec.js\"",
89
+ "test:integration:mocha:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/mocha/*.spec.js\"",
90
+ "test:integration:playwright": "mocha --timeout 60000 \"integration-tests/playwright/${SPEC:-playwright-*}.spec.js\"",
91
+ "test:integration:playwright:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/playwright/${SPEC:-playwright-*}.spec.js\"",
79
92
  "test:integration:selenium": "mocha --timeout 60000 \"integration-tests/selenium/*.spec.js\"",
93
+ "test:integration:selenium:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/selenium/*.spec.js\"",
80
94
  "test:integration:vitest": "mocha --timeout 60000 \"integration-tests/vitest/*.spec.js\"",
95
+ "test:integration:vitest:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/vitest/*.spec.js\"",
81
96
  "test:integration:testopt": "mocha --timeout 120000 \"integration-tests/ci-visibility/*.spec.js\"",
97
+ "test:integration:testopt:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 120000 \"integration-tests/ci-visibility/*.spec.js\"",
82
98
  "test:integration:profiler": "mocha --timeout 180000 \"integration-tests/profiler/*.spec.js\"",
83
- "test:integration:plugins": "mocha \"packages/datadog-plugin-@(${PLUGINS})/test/integration-test/**/*.spec.js\"",
99
+ "test:integration:profiler:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 180000 \"integration-tests/profiler/*.spec.js\"",
100
+ "test:integration:plugins": "yarn services && mocha \"packages/datadog-plugin-@(${PLUGINS})/test/integration-test/**/${SPEC:-*}*.spec.js\"",
101
+ "test:integration:plugins:coverage": "yarn services && node ./integration-tests/coverage/run-suite.js \"packages/datadog-plugin-@(${PLUGINS})/test/integration-test/**/${SPEC:-*}*.spec.js\"",
84
102
  "test:unit:plugins": "mocha \"packages/datadog-instrumentations/test/@(${PLUGINS}).spec.js\" \"packages/datadog-plugin-@(${PLUGINS})/test/**/*.spec.js\" --exclude \"packages/datadog-plugin-@(${PLUGINS})/test/integration-test/**/*.spec.js\"",
85
103
  "test:shimmer": "mocha \"packages/datadog-shimmer/test/**/*.spec.js\"",
86
- "test:shimmer:ci": "nyc -- npm run test:shimmer",
104
+ "test:shimmer:ci": "nyc --silent node init && nyc -- npm run test:shimmer",
87
105
  "verify:workflow-job-names": "node scripts/verify-workflow-job-names.js",
88
106
  "verify-exercised-tests": "node scripts/verify-exercised-tests.js"
89
107
  },
@@ -153,28 +171,28 @@
153
171
  "@datadog/wasm-js-rewriter": "5.0.1",
154
172
  "@opentelemetry/api": ">=1.0.0 <1.10.0",
155
173
  "@opentelemetry/api-logs": "<1.0.0",
156
- "oxc-parser": "^0.121.0"
174
+ "oxc-parser": "^0.127.0"
157
175
  },
158
176
  "devDependencies": {
159
- "@actions/core": "^3.0.0",
160
- "@actions/github": "^9.0.0",
177
+ "@actions/core": "^3.0.1",
178
+ "@actions/github": "^9.1.1",
161
179
  "@babel/helpers": "^7.29.2",
162
180
  "@eslint/eslintrc": "^3.3.5",
163
181
  "@eslint/js": "^9.39.2",
164
182
  "@msgpack/msgpack": "^3.1.3",
165
- "@openfeature/core": "^1.8.1",
166
- "@openfeature/server-sdk": "~1.20.0",
183
+ "@openfeature/core": "^1.10.0",
184
+ "@openfeature/server-sdk": "~1.21.0",
167
185
  "@stylistic/eslint-plugin": "^5.10.0",
168
186
  "@types/mocha": "^10.0.10",
169
187
  "@types/node": "^18.19.106",
170
- "@types/sinon": "^21.0.0",
171
- "axios": "^1.15.0",
188
+ "@types/sinon": "^21.0.1",
189
+ "axios": "^1.15.2",
172
190
  "benchmark": "^2.1.4",
173
191
  "body-parser": "^2.2.2",
174
- "bun": "1.3.11",
192
+ "bun": "1.3.13",
175
193
  "codeowners-audit": "^2.9.0",
176
194
  "eslint": "^9.39.2",
177
- "eslint-plugin-cypress": "^6.2.2",
195
+ "eslint-plugin-cypress": "^6.3.1",
178
196
  "eslint-plugin-import": "^2.32.0",
179
197
  "eslint-plugin-jsdoc": "^62.9.0",
180
198
  "eslint-plugin-mocha": "^11.2.0",
@@ -186,12 +204,15 @@
186
204
  "globals": "^17.2.0",
187
205
  "graphql": "*",
188
206
  "husky": "^9.1.7",
207
+ "istanbul-lib-report": "^3.0.0",
208
+ "istanbul-reports": "^3.0.2",
189
209
  "jszip": "^3.10.1",
190
210
  "mocha": "^11.6.0",
191
211
  "mocha-junit-reporter": "^2.2.1",
192
212
  "mocha-multi-reporters": "^1.5.1",
193
213
  "multer": "^2.1.1",
194
214
  "nock": "^13.5.6",
215
+ "node-preload": "^0.2.1",
195
216
  "nyc": "^18.0.0",
196
217
  "octokit": "^5.0.3",
197
218
  "opentracing": ">=0.14.7",
@@ -200,10 +221,10 @@
200
221
  "retry": "^0.13.1",
201
222
  "semifies": "^1.0.0",
202
223
  "semver": "^7.7.2",
203
- "sinon": "^21.0.3",
224
+ "sinon": "^21.1.2",
204
225
  "tiktoken": "^1.0.21",
205
- "typescript": "^6.0.2",
206
- "workerpool": "^10.0.0",
226
+ "typescript": "^6.0.3",
227
+ "workerpool": "^10.0.2",
207
228
  "yaml": "^2.8.3",
208
229
  "yarn-deduplicate": "^6.0.2"
209
230
  }
@@ -5,6 +5,7 @@ const {
5
5
  channel,
6
6
  addHook,
7
7
  } = require('./helpers/instrument')
8
+ const { createCallbackInstrumentor } = require('./helpers/callback-instrumentor')
8
9
 
9
10
  const cryptoHashCh = channel('datadog:crypto:hashing:start')
10
11
  const cryptoCipherCh = channel('datadog:crypto:cipher:start')
@@ -12,9 +13,35 @@ const cryptoCipherCh = channel('datadog:crypto:cipher:start')
12
13
  const hashMethods = ['createHash', 'createHmac', 'createSign', 'createVerify', 'sign', 'verify']
13
14
  const cipherMethods = ['createCipheriv', 'createDecipheriv']
14
15
 
16
+ // Async crypto APIs that offload work to the libuv worker thread pool. The mapped sparse array
17
+ // names each callback-preceding argument position whose value should be captured on the context
18
+ // (string or number only). Unused positions are elided so iteration can skip them. Consumers of
19
+ // the context (e.g. the events profiler) read these fields as sample labels.
20
+ const asyncParamsByMethod = {
21
+ checkPrime: [],
22
+ generateKey: ['type'],
23
+ generateKeyPair: ['type'],
24
+ generatePrime: ['size'],
25
+ hkdf: ['digest', , , , 'keylen'], // eslint-disable-line no-sparse-arrays
26
+ pbkdf2: [, , 'iterations', 'keylen', 'digest'], // eslint-disable-line no-sparse-arrays
27
+ randomBytes: ['size'],
28
+ randomFill: [, 'offset', 'size'], // eslint-disable-line no-sparse-arrays
29
+ randomInt: [],
30
+ scrypt: [, , 'keylen'], // eslint-disable-line no-sparse-arrays
31
+ sign: ['algorithm'],
32
+ verify: ['algorithm'],
33
+ }
34
+
15
35
  addHook({ name: 'crypto' }, crypto => {
16
36
  shimmer.massWrap(crypto, hashMethods, wrapCryptoMethod(cryptoHashCh))
17
37
  shimmer.massWrap(crypto, cipherMethods, wrapCryptoMethod(cryptoCipherCh))
38
+
39
+ const instrument = createCallbackInstrumentor('apm:crypto:operation')
40
+ for (const [method, paramNames] of Object.entries(asyncParamsByMethod)) {
41
+ if (typeof crypto[method] === 'function') {
42
+ shimmer.wrap(crypto, method, instrument(buildAsyncContext(method, paramNames)))
43
+ }
44
+ }
18
45
  return crypto
19
46
  })
20
47
 
@@ -30,3 +57,21 @@ function wrapCryptoMethod (channel) {
30
57
  }
31
58
  return wrapMethod
32
59
  }
60
+
61
+ function buildAsyncContext (operation, paramNames) {
62
+ return function (_, args) {
63
+ const ctx = { operation }
64
+ const lastIndex = args.length - 1
65
+ // paramNames is a sparse array; for-in yields only populated slot indices, in ascending
66
+ // numeric order, so we can break once we pass the callback position.
67
+ for (const i in paramNames) {
68
+ if (i >= lastIndex) break
69
+ const name = paramNames[i]
70
+ const value = args[i]
71
+ if (typeof value === 'string' || typeof value === 'number') {
72
+ ctx[name] = value
73
+ }
74
+ }
75
+ return ctx
76
+ }
77
+ }
@@ -229,32 +229,139 @@ function wrapConfig (config) {
229
229
  return config
230
230
  }
231
231
 
232
+ /**
233
+ * Returns `true` if the nearest package.json walking up from `filePath`
234
+ * sets `"type": "module"`. Used to decide whether ambiguous extensions
235
+ * (`.js`, `.ts`) are loaded as ESM or CJS.
236
+ *
237
+ * @param {string} filePath absolute path to a file under the project
238
+ * @returns {boolean}
239
+ */
240
+ function isUnderEsmPackage (filePath) {
241
+ let dir = path.dirname(filePath)
242
+ while (true) {
243
+ const candidate = path.join(dir, 'package.json')
244
+ try {
245
+ const pkg = JSON.parse(fs.readFileSync(candidate, 'utf8'))
246
+ return pkg && pkg.type === 'module'
247
+ } catch { /* no package.json at this level */ }
248
+ const parent = path.dirname(dir)
249
+ if (parent === dir) return false
250
+ dir = parent
251
+ }
252
+ }
253
+
232
254
  /**
233
255
  * @param {string} originalConfigFile absolute path to the original config file
234
256
  * @returns {string} path to the generated wrapper file
235
257
  */
236
258
  function createConfigWrapper (originalConfigFile) {
259
+ // Decide the wrapper's module mode (ESM vs CJS). It must match how
260
+ // Cypress would interpret the user's original config so that (1) Cypress
261
+ // keeps the loader it would have used (notably the ts-node registration
262
+ // for `.ts` configs), and (2) the wrapper body parses in that mode.
263
+ const originalExt = path.extname(originalConfigFile)
264
+ const isEsm = originalExt === '.mjs' || originalExt === '.mts' ||
265
+ (originalExt !== '.cjs' && originalExt !== '.cts' && isUnderEsmPackage(originalConfigFile))
266
+
267
+ // Preserve `.ts`/`.cts`/`.mts` so Cypress keeps ts-node registered for
268
+ // the wrapper. For plain JS originals, pick the extension that encodes
269
+ // the chosen module mode directly.
270
+ let wrapperExt
271
+ if (originalExt === '.ts' || originalExt === '.cts' || originalExt === '.mts') {
272
+ wrapperExt = originalExt
273
+ } else {
274
+ wrapperExt = isEsm ? '.mjs' : '.cjs'
275
+ }
276
+
237
277
  const wrapperFile = path.join(
238
278
  path.dirname(originalConfigFile),
239
- `.dd-cypress-config-${process.pid}.mjs`
279
+ `.dd-cypress-config-${process.pid}${wrapperExt}`
240
280
  )
241
281
 
242
282
  const cypressConfigPath = require.resolve('./cypress-config')
243
283
 
244
- // Always use ESM: it can import both CJS and ESM configs, so it works
245
- // regardless of the original file's extension or "type": "module" in package.json.
246
- // Import cypress-config.js directly (CJS default = module.exports object).
247
- fs.writeFileSync(wrapperFile, [
248
- `import originalConfig from ${JSON.stringify(pathToFileURL(originalConfigFile).href)}`,
249
- `import cypressConfig from ${JSON.stringify(pathToFileURL(cypressConfigPath).href)}`,
250
- '',
251
- 'export default cypressConfig.wrapConfig(originalConfig)',
252
- '',
253
- ].join('\n'))
254
-
284
+ // ESM body: `import` default-interops a CJS module (cypress-config.js)
285
+ // by exposing its `module.exports` as the default binding, and handles
286
+ // both CJS and ESM user configs transparently.
287
+ // CJS body: avoids top-level `import` — older Cypress transpiles `.ts`
288
+ // configs through CJS ts-node, where `require('file://...')` is not
289
+ // supported. Guards against ES-module-default shape so TS-authored
290
+ // configs using `export default` still work.
291
+ const body = isEsm
292
+ ? [
293
+ `import originalConfig from ${JSON.stringify(pathToFileURL(originalConfigFile).href)}`,
294
+ `import cypressConfig from ${JSON.stringify(pathToFileURL(cypressConfigPath).href)}`,
295
+ '',
296
+ 'export default cypressConfig.wrapConfig(originalConfig)',
297
+ '',
298
+ ].join('\n')
299
+ : [
300
+ `const cypressConfig = require(${JSON.stringify(cypressConfigPath)})`,
301
+ `const originalExports = require(${JSON.stringify(originalConfigFile)})`,
302
+ 'const originalConfig = originalExports && originalExports.__esModule',
303
+ ' ? originalExports.default',
304
+ ' : originalExports',
305
+ 'module.exports = cypressConfig.wrapConfig(originalConfig)',
306
+ '',
307
+ ].join('\n')
308
+
309
+ fs.writeFileSync(wrapperFile, body)
255
310
  return wrapperFile
256
311
  }
257
312
 
313
+ /**
314
+ * @param {string} projectRoot
315
+ * @returns {boolean}
316
+ */
317
+ function isTypeScript6OrNewer (projectRoot) {
318
+ try {
319
+ // eslint-disable-next-line n/no-unpublished-require
320
+ const packageJsonPath = require.resolve('typescript/package.json', { paths: [projectRoot] })
321
+ const { version } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
322
+ const major = Number(String(version).split('.')[0])
323
+ return major >= 6
324
+ } catch {
325
+ return false
326
+ }
327
+ }
328
+
329
+ /**
330
+ * @param {string} projectRoot
331
+ * @param {string} configFilePath
332
+ * @returns {() => void}
333
+ */
334
+ function configureTsNodeForTypeScript6 (projectRoot, configFilePath) {
335
+ const configExt = path.extname(configFilePath)
336
+ if (configExt !== '.ts' && configExt !== '.cts' && configExt !== '.mts') return () => {}
337
+ if (!isTypeScript6OrNewer(projectRoot)) return () => {}
338
+
339
+ /* eslint-disable eslint-rules/eslint-process-env */
340
+ const previousCompilerOptions = process.env.TS_NODE_COMPILER_OPTIONS
341
+ let compilerOptions = {}
342
+ if (previousCompilerOptions) {
343
+ try {
344
+ compilerOptions = JSON.parse(previousCompilerOptions)
345
+ } catch {
346
+ compilerOptions = {}
347
+ }
348
+ }
349
+
350
+ process.env.TS_NODE_COMPILER_OPTIONS = JSON.stringify({
351
+ ...compilerOptions,
352
+ ignoreDeprecations: '6.0',
353
+ })
354
+
355
+ return () => {
356
+ if (previousCompilerOptions === undefined) {
357
+ delete process.env.TS_NODE_COMPILER_OPTIONS
358
+ } else {
359
+ process.env.TS_NODE_COMPILER_OPTIONS = previousCompilerOptions
360
+ }
361
+ }
362
+ /* eslint-enable eslint-rules/eslint-process-env */
363
+ }
364
+
258
365
  /**
259
366
  * Wraps the Cypress config file for a CLI start() call. When an explicit
260
367
  * configFile is provided, creates a temp wrapper that imports the original
@@ -291,17 +398,16 @@ function wrapCliConfigFileOptions (options) {
291
398
  }
292
399
  }
293
400
 
294
- // Skip .ts files — Cypress transpiles them internally via its own loader.
295
- // The ESM wrapper can't import .ts directly. The defineConfig shimmer
296
- // handles .ts configs since they're transpiled to CJS by Cypress.
297
- if (!configFilePath || !fs.existsSync(configFilePath) || path.extname(configFilePath) === '.ts') return noop
401
+ if (!configFilePath || !fs.existsSync(configFilePath)) return noop
298
402
 
299
403
  try {
300
404
  const wrapperFile = createConfigWrapper(configFilePath)
405
+ const restoreTsNodeCompilerOptions = configureTsNodeForTypeScript6(projectRoot, configFilePath)
301
406
 
302
407
  return {
303
408
  options: { ...options, configFile: wrapperFile },
304
409
  cleanup: () => {
410
+ restoreTsNodeCompilerOptions()
305
411
  try { fs.unlinkSync(wrapperFile) } catch { /* best effort */ }
306
412
  },
307
413
  }
@@ -1,7 +1,8 @@
1
1
  'use strict'
2
2
 
3
3
  const shimmer = require('../../datadog-shimmer')
4
- const { channel, addHook } = require('./helpers/instrument')
4
+ const { addHook } = require('./helpers/instrument')
5
+ const { createCallbackInstrumentor } = require('./helpers/callback-instrumentor')
5
6
 
6
7
  const rrtypes = {
7
8
  resolveAny: 'ANY',
@@ -20,78 +21,45 @@ const rrtypes = {
20
21
  const rrtypeMap = new WeakMap()
21
22
 
22
23
  addHook({ name: 'dns' }, dns => {
23
- shimmer.wrap(dns, 'lookup', fn => wrap('apm:dns:lookup', fn, 2))
24
- shimmer.wrap(dns, 'lookupService', fn => wrap('apm:dns:lookup_service', fn, 2))
25
- shimmer.wrap(dns, 'resolve', fn => wrap('apm:dns:resolve', fn, 2))
26
- shimmer.wrap(dns, 'reverse', fn => wrap('apm:dns:reverse', fn, 2))
24
+ const lookup = createCallbackInstrumentor('apm:dns:lookup', { captureResult: true })
25
+ const lookupService = createCallbackInstrumentor('apm:dns:lookup_service', { captureResult: true })
26
+ const resolve = createCallbackInstrumentor('apm:dns:resolve', { captureResult: true })
27
+ const reverse = createCallbackInstrumentor('apm:dns:reverse', { captureResult: true })
27
28
 
28
- patchResolveShorthands(dns)
29
+ shimmer.wrap(dns, 'lookup', lookup(buildArgsContext()))
30
+ shimmer.wrap(dns, 'lookupService', lookupService(buildArgsContext()))
31
+ shimmer.wrap(dns, 'resolve', resolve(buildArgsContext()))
32
+ shimmer.wrap(dns, 'reverse', reverse(buildArgsContext()))
33
+
34
+ patchResolveShorthands(dns, resolve)
29
35
 
30
36
  if (dns.Resolver) {
31
- shimmer.wrap(dns.Resolver.prototype, 'resolve', fn => wrap('apm:dns:resolve', fn, 2))
32
- shimmer.wrap(dns.Resolver.prototype, 'reverse', fn => wrap('apm:dns:reverse', fn, 2))
37
+ shimmer.wrap(dns.Resolver.prototype, 'resolve', resolve(buildArgsContext()))
38
+ shimmer.wrap(dns.Resolver.prototype, 'reverse', reverse(buildArgsContext()))
33
39
 
34
- patchResolveShorthands(dns.Resolver.prototype)
40
+ patchResolveShorthands(dns.Resolver.prototype, resolve)
35
41
  }
36
42
 
37
43
  return dns
38
44
  })
39
45
 
40
- function patchResolveShorthands (prototype) {
46
+ function patchResolveShorthands (prototype, resolve) {
41
47
  for (const method of Object.keys(rrtypes)) {
42
48
  if (prototype[method]) {
43
49
  rrtypeMap.set(prototype[method], rrtypes[method])
44
- shimmer.wrap(prototype, method, fn => wrap('apm:dns:resolve', fn, 2, rrtypes[method]))
50
+ shimmer.wrap(prototype, method, resolve(buildArgsContext(rrtypes[method])))
45
51
  }
46
52
  }
47
53
  }
48
54
 
49
- function wrap (prefix, fn, expectedArgs, rrtype) {
50
- const startCh = channel(prefix + ':start')
51
- const finishCh = channel(prefix + ':finish')
52
- const errorCh = channel(prefix + ':error')
53
-
54
- const wrapped = function () {
55
- const cb = arguments[arguments.length - 1]
56
- if (
57
- !startCh.hasSubscribers ||
58
- arguments.length < expectedArgs ||
59
- typeof cb !== 'function'
60
- ) {
61
- return fn.apply(this, arguments)
62
- }
63
-
64
- const args = [...arguments]
65
- args.pop() // gets rid of the callback
55
+ function buildArgsContext (rrtype) {
56
+ return function (_, args) {
57
+ if (args.length < 2) return
58
+ const captured = [...args]
59
+ captured.pop() // remove the callback
66
60
  if (rrtype) {
67
- args.push(rrtype)
61
+ captured.push(rrtype)
68
62
  }
69
-
70
- const ctx = { args }
71
-
72
- return startCh.runStores(ctx, () => {
73
- arguments[arguments.length - 1] = shimmer.wrapFunction(cb, cb => function (error, result, ...args) {
74
- if (error) {
75
- ctx.error = error
76
- errorCh.publish(ctx)
77
- }
78
-
79
- ctx.result = result
80
- finishCh.runStores(ctx, cb, this, error, result, ...args)
81
- })
82
-
83
- try {
84
- return fn.apply(this, arguments)
85
- // TODO deal with promise versions when we support `dns/promises`
86
- } catch (error) {
87
- void error.stack // trigger getting the stack at the original throwing point
88
- ctx.error = error
89
- errorCh.publish(ctx)
90
-
91
- throw error
92
- }
93
- })
63
+ return { args: captured }
94
64
  }
95
-
96
- return wrapped
97
65
  }
@@ -129,7 +129,7 @@ function wrapValidate (validate) {
129
129
  try {
130
130
  errors = validate.apply(this, arguments)
131
131
  if (errors && errors[0]) {
132
- ctx.error = errors && errors[0]
132
+ ctx.error = errors[0]
133
133
  validateErrorCh.publish(ctx)
134
134
  }
135
135
  return errors