dd-trace 6.4.0 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/README.electron.md +7 -0
  2. package/README.md +17 -0
  3. package/ci/diagnose.js +2100 -0
  4. package/ci/init.js +23 -2
  5. package/ci/runbook.md +198 -0
  6. package/ci/test-optimization-validation/approval-artifacts.js +143 -0
  7. package/ci/test-optimization-validation/approval.js +299 -0
  8. package/ci/test-optimization-validation/artifact-id.js +20 -0
  9. package/ci/test-optimization-validation/bounded-json.js +121 -0
  10. package/ci/test-optimization-validation/ci-command-candidate.js +83 -0
  11. package/ci/test-optimization-validation/ci-discovery.js +181 -0
  12. package/ci/test-optimization-validation/ci-remediation.js +210 -0
  13. package/ci/test-optimization-validation/cli.js +903 -0
  14. package/ci/test-optimization-validation/command-blocker.js +81 -0
  15. package/ci/test-optimization-validation/command-output-policy.js +206 -0
  16. package/ci/test-optimization-validation/command-runner.js +707 -0
  17. package/ci/test-optimization-validation/command-suitability.js +471 -0
  18. package/ci/test-optimization-validation/executable-approval.js +48 -0
  19. package/ci/test-optimization-validation/executable.js +480 -0
  20. package/ci/test-optimization-validation/generated-file-policy.js +63 -0
  21. package/ci/test-optimization-validation/generated-files.js +351 -0
  22. package/ci/test-optimization-validation/generated-verifier.js +196 -0
  23. package/ci/test-optimization-validation/init-probe-preload.js +163 -0
  24. package/ci/test-optimization-validation/init-probe.js +246 -0
  25. package/ci/test-optimization-validation/late-initialization.js +63 -0
  26. package/ci/test-optimization-validation/local-command.js +163 -0
  27. package/ci/test-optimization-validation/manifest-loader.js +133 -0
  28. package/ci/test-optimization-validation/manifest-scaffold.js +738 -0
  29. package/ci/test-optimization-validation/manifest-schema.js +862 -0
  30. package/ci/test-optimization-validation/offline-fixtures.js +327 -0
  31. package/ci/test-optimization-validation/offline-output.js +406 -0
  32. package/ci/test-optimization-validation/payload-normalizer.js +72 -0
  33. package/ci/test-optimization-validation/plan-writer.js +1120 -0
  34. package/ci/test-optimization-validation/preflight-runner.js +114 -0
  35. package/ci/test-optimization-validation/redaction.js +331 -0
  36. package/ci/test-optimization-validation/report-writer.js +1508 -0
  37. package/ci/test-optimization-validation/safe-files.js +203 -0
  38. package/ci/test-optimization-validation/scenarios/auto-test-retries.js +159 -0
  39. package/ci/test-optimization-validation/scenarios/basic-reporting.js +657 -0
  40. package/ci/test-optimization-validation/scenarios/ci-wiring.js +780 -0
  41. package/ci/test-optimization-validation/scenarios/early-flake-detection.js +141 -0
  42. package/ci/test-optimization-validation/scenarios/helpers.js +539 -0
  43. package/ci/test-optimization-validation/scenarios/test-management.js +218 -0
  44. package/ci/test-optimization-validation/setup-runner.js +97 -0
  45. package/ci/test-optimization-validation/static-diagnosis.js +159 -0
  46. package/ci/test-optimization-validation/test-output.js +129 -0
  47. package/ci/test-optimization-validation-manifest.schema.json +1 -0
  48. package/ci/validate-test-optimization.js +3 -0
  49. package/ext/exporters.js +1 -0
  50. package/index.d.ts +121 -8
  51. package/init.js +18 -0
  52. package/initialize.mjs +1 -1
  53. package/loader-hook.mjs +28 -18
  54. package/openfeature.d.ts +1 -0
  55. package/openfeature.js +4 -0
  56. package/package.json +10 -7
  57. package/packages/datadog-instrumentations/src/ai.js +8 -2
  58. package/packages/datadog-instrumentations/src/child_process.js +1 -1
  59. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -1
  60. package/packages/datadog-instrumentations/src/cucumber-worker-threads.js +9 -3
  61. package/packages/datadog-instrumentations/src/cucumber.js +20 -7
  62. package/packages/datadog-instrumentations/src/cypress-config.js +398 -52
  63. package/packages/datadog-instrumentations/src/fastify.js +7 -11
  64. package/packages/datadog-instrumentations/src/helpers/hook.js +27 -6
  65. package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +8 -8
  66. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +28 -2
  67. package/packages/datadog-instrumentations/src/jest.js +26 -0
  68. package/packages/datadog-instrumentations/src/mariadb.js +1 -1
  69. package/packages/datadog-instrumentations/src/mocha/main.js +0 -2
  70. package/packages/datadog-instrumentations/src/mocha/utils.js +0 -4
  71. package/packages/datadog-instrumentations/src/mongodb.js +3 -3
  72. package/packages/datadog-instrumentations/src/mongoose.js +3 -3
  73. package/packages/datadog-instrumentations/src/mquery.js +2 -2
  74. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  75. package/packages/datadog-instrumentations/src/next.js +24 -0
  76. package/packages/datadog-instrumentations/src/nyc.js +0 -2
  77. package/packages/datadog-instrumentations/src/oracledb.js +2 -2
  78. package/packages/datadog-instrumentations/src/pg.js +2 -2
  79. package/packages/datadog-instrumentations/src/playwright.js +159 -22
  80. package/packages/datadog-instrumentations/src/process.js +3 -0
  81. package/packages/datadog-instrumentations/src/router.js +18 -8
  82. package/packages/datadog-instrumentations/src/selenium.js +52 -26
  83. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +2 -2
  84. package/packages/datadog-instrumentations/src/vitest-main.js +0 -2
  85. package/packages/datadog-instrumentations/src/ws.js +2 -1
  86. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +2 -2
  87. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +2 -1
  88. package/packages/datadog-plugin-aws-sdk/src/util.js +2 -2
  89. package/packages/datadog-plugin-cucumber/src/index.js +1 -1
  90. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +19 -57
  91. package/packages/datadog-plugin-cypress/src/index.js +6 -1
  92. package/packages/datadog-plugin-cypress/src/support.js +92 -26
  93. package/packages/datadog-plugin-electron/src/ipc.js +1 -1
  94. package/packages/datadog-plugin-graphql/src/execute.js +87 -45
  95. package/packages/datadog-plugin-graphql/src/validate.js +2 -2
  96. package/packages/datadog-plugin-http2/src/client.js +1 -1
  97. package/packages/datadog-plugin-langchain/src/handlers/embedding.js +2 -1
  98. package/packages/datadog-plugin-langchain/src/handlers/language_models.js +2 -1
  99. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  100. package/packages/datadog-plugin-playwright/src/index.js +177 -64
  101. package/packages/datadog-plugin-router/src/index.js +11 -2
  102. package/packages/datadog-plugin-selenium/src/index.js +5 -36
  103. package/packages/datadog-plugin-ws/src/close.js +2 -1
  104. package/packages/datadog-plugin-ws/src/producer.js +2 -1
  105. package/packages/datadog-plugin-ws/src/receiver.js +2 -1
  106. package/packages/datadog-plugin-ws/src/server.js +2 -1
  107. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  108. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -2
  109. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +3 -1
  110. package/packages/dd-trace/src/azure_metadata.js +2 -1
  111. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +93 -28
  112. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
  113. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +160 -0
  114. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +288 -0
  115. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/payload-projection.js +84 -0
  116. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +369 -0
  117. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +60 -0
  118. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +41 -3
  119. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +7 -2
  120. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +1 -1
  121. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +6 -2
  122. package/packages/dd-trace/src/ci-visibility/rum.js +7 -0
  123. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
  124. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
  125. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +137 -9
  126. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +168 -8
  127. package/packages/dd-trace/src/ci-visibility/test-screenshot.js +90 -0
  128. package/packages/dd-trace/src/config/generated-config-types.d.ts +16 -0
  129. package/packages/dd-trace/src/config/helper.js +1 -0
  130. package/packages/dd-trace/src/config/index.js +10 -0
  131. package/packages/dd-trace/src/config/supported-configurations.json +66 -0
  132. package/packages/dd-trace/src/exporter.js +2 -0
  133. package/packages/dd-trace/src/exporters/common/client-library-headers.js +21 -0
  134. package/packages/dd-trace/src/exporters/common/request.js +59 -30
  135. package/packages/dd-trace/src/exporters/common/url.js +15 -1
  136. package/packages/dd-trace/src/feature-registry.js +10 -3
  137. package/packages/dd-trace/src/llmobs/experiments/client.js +113 -0
  138. package/packages/dd-trace/src/llmobs/experiments/dataset.js +154 -0
  139. package/packages/dd-trace/src/llmobs/experiments/experiment.js +283 -0
  140. package/packages/dd-trace/src/llmobs/experiments/index.js +152 -0
  141. package/packages/dd-trace/src/llmobs/experiments/noop.js +30 -0
  142. package/packages/dd-trace/src/llmobs/experiments/result.js +34 -0
  143. package/packages/dd-trace/src/llmobs/noop.js +6 -0
  144. package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +20 -3
  145. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +2 -2
  146. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  147. package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +8 -0
  148. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +48 -14
  149. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +43 -0
  150. package/packages/dd-trace/src/llmobs/sdk.js +17 -0
  151. package/packages/dd-trace/src/llmobs/tagger.js +68 -0
  152. package/packages/dd-trace/src/llmobs/telemetry.js +2 -1
  153. package/packages/dd-trace/src/llmobs/util.js +32 -0
  154. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +322 -0
  155. package/packages/dd-trace/src/openfeature/configuration_source.js +90 -0
  156. package/packages/dd-trace/src/openfeature/flagging_provider.js +14 -23
  157. package/packages/dd-trace/src/openfeature/index.js +0 -2
  158. package/packages/dd-trace/src/openfeature/noop.js +1 -28
  159. package/packages/dd-trace/src/openfeature/register.js +16 -27
  160. package/packages/dd-trace/src/openfeature/remote_config.js +15 -18
  161. package/packages/dd-trace/src/openfeature/require-provider.js +18 -0
  162. package/packages/dd-trace/src/opentelemetry/span-ending-hook.js +10 -0
  163. package/packages/dd-trace/src/opentelemetry/span.js +5 -0
  164. package/packages/dd-trace/src/plugins/ci_plugin.js +20 -6
  165. package/packages/dd-trace/src/plugins/util/git.js +3 -2
  166. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +29 -5
  167. package/packages/dd-trace/src/plugins/util/test.js +56 -4
  168. package/packages/dd-trace/src/proxy.js +84 -7
  169. package/packages/dd-trace/src/span_processor.js +5 -0
  170. package/packages/dd-trace/src/standalone/index.js +0 -14
  171. package/packages/dd-trace/src/telemetry/send-data.js +2 -2
  172. package/packages/dd-trace/src/util.js +26 -0
  173. package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
  174. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  175. package/vendor/dist/protobufjs/index.js +1 -1
  176. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  177. package/vendor/dist/shell-quote/index.js +1 -1
  178. package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +0 -17
@@ -0,0 +1,288 @@
1
+ 'use strict'
2
+
3
+ const MAX_COLLECTION_ENTRIES = 100_000
4
+ const MAX_INPUT_BYTES = 16 * 1024 * 1024
5
+ const MAX_NESTING_DEPTH = 128
6
+ const MAX_OUTPUT_BYTES = 16 * 1024 * 1024
7
+ const MAX_STRING_BYTES = 64 * 1024
8
+
9
+ /**
10
+ * Converts one bounded MessagePack value to JSON without losing 64-bit integer precision.
11
+ *
12
+ * @param {Buffer} input encoded MessagePack payload
13
+ * @returns {Buffer} JSON payload
14
+ */
15
+ function msgpackToJson (input) {
16
+ if (!Buffer.isBuffer(input) || input.length === 0) {
17
+ throw new Error('MessagePack validation payload must be a non-empty Buffer.')
18
+ }
19
+ if (input.length > MAX_INPUT_BYTES) {
20
+ throw new Error(`MessagePack validation payload exceeds ${MAX_INPUT_BYTES} bytes.`)
21
+ }
22
+
23
+ const writer = new BoundedJsonWriter()
24
+ const converter = new MsgpackJsonConverter(input, writer)
25
+ converter.convert()
26
+ return writer.toBuffer()
27
+ }
28
+
29
+ class BoundedJsonWriter {
30
+ #bytes = 0
31
+ #chunks = []
32
+
33
+ /**
34
+ * Appends one JSON fragment while enforcing the aggregate output limit.
35
+ *
36
+ * @param {string} fragment JSON fragment
37
+ */
38
+ write (fragment) {
39
+ const bytes = Buffer.byteLength(fragment)
40
+ if (this.#bytes + bytes > MAX_OUTPUT_BYTES) {
41
+ throw new Error(`JSON validation payload exceeds ${MAX_OUTPUT_BYTES} bytes.`)
42
+ }
43
+ this.#bytes += bytes
44
+ this.#chunks.push(fragment)
45
+ }
46
+
47
+ /**
48
+ * Materializes the completed bounded JSON payload.
49
+ *
50
+ * @returns {Buffer} JSON payload
51
+ */
52
+ toBuffer () {
53
+ return Buffer.from(this.#chunks.join(''))
54
+ }
55
+ }
56
+
57
+ class MsgpackJsonConverter {
58
+ #collectionEntries = 0
59
+ #input
60
+ #offset = 0
61
+ #writer
62
+
63
+ /**
64
+ * Creates a converter for one MessagePack payload.
65
+ *
66
+ * @param {Buffer} input encoded MessagePack payload
67
+ * @param {BoundedJsonWriter} writer bounded JSON writer
68
+ */
69
+ constructor (input, writer) {
70
+ this.#input = input
71
+ this.#writer = writer
72
+ }
73
+
74
+ /**
75
+ * Converts exactly one top-level value and rejects trailing data.
76
+ */
77
+ convert () {
78
+ this.#writeValue(0)
79
+ if (this.#offset !== this.#input.length) {
80
+ throw new Error('MessagePack validation payload contains trailing data.')
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Writes one MessagePack value as JSON.
86
+ *
87
+ * @param {number} depth current nesting depth
88
+ */
89
+ #writeValue (depth) {
90
+ if (depth > MAX_NESTING_DEPTH) {
91
+ throw new Error('MessagePack nesting exceeds validation payload limit.')
92
+ }
93
+
94
+ const prefix = this.#readUInt8()
95
+ if (prefix <= 0x7F) return this.#writer.write(String(prefix))
96
+ if (prefix >= 0xE0) return this.#writer.write(String(prefix - 0x01_00))
97
+ if ((prefix & 0xE0) === 0xA0) return this.#writeString(prefix & 0x1F)
98
+ if ((prefix & 0xF0) === 0x90) return this.#writeArray(prefix & 0x0F, depth)
99
+ if ((prefix & 0xF0) === 0x80) return this.#writeMap(prefix & 0x0F, depth)
100
+
101
+ switch (prefix) {
102
+ case 0xC0: return this.#writer.write('null')
103
+ case 0xC2: return this.#writer.write('false')
104
+ case 0xC3: return this.#writer.write('true')
105
+ case 0xC4: return this.#writeBinary(this.#readUInt8())
106
+ case 0xC5: return this.#writeBinary(this.#read('readUInt16BE', 2))
107
+ case 0xC6: return this.#writeBinary(this.#read('readUInt32BE', 4))
108
+ case 0xCA: return this.#writeFloat(this.#read('readFloatBE', 4))
109
+ case 0xCB: return this.#writeFloat(this.#read('readDoubleBE', 8))
110
+ case 0xCC: return this.#writer.write(String(this.#readUInt8()))
111
+ case 0xCD: return this.#writer.write(String(this.#read('readUInt16BE', 2)))
112
+ case 0xCE: return this.#writer.write(String(this.#read('readUInt32BE', 4)))
113
+ case 0xCF: return this.#writer.write(this.#read('readBigUInt64BE', 8).toString())
114
+ case 0xD0: return this.#writer.write(String(this.#read('readInt8', 1)))
115
+ case 0xD1: return this.#writer.write(String(this.#read('readInt16BE', 2)))
116
+ case 0xD2: return this.#writer.write(String(this.#read('readInt32BE', 4)))
117
+ case 0xD3: return this.#writer.write(this.#read('readBigInt64BE', 8).toString())
118
+ case 0xD9: return this.#writeString(this.#readUInt8())
119
+ case 0xDA: return this.#writeString(this.#read('readUInt16BE', 2))
120
+ case 0xDB: return this.#writeString(this.#read('readUInt32BE', 4))
121
+ case 0xDC: return this.#writeArray(this.#read('readUInt16BE', 2), depth)
122
+ case 0xDD: return this.#writeArray(this.#read('readUInt32BE', 4), depth)
123
+ case 0xDE: return this.#writeMap(this.#read('readUInt16BE', 2), depth)
124
+ case 0xDF: return this.#writeMap(this.#read('readUInt32BE', 4), depth)
125
+ default:
126
+ throw new Error(`Unsupported MessagePack byte 0x${prefix.toString(16)} at offset ${this.#offset - 1}.`)
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Writes one MessagePack array.
132
+ *
133
+ * @param {number} length array length
134
+ * @param {number} depth current nesting depth
135
+ */
136
+ #writeArray (length, depth) {
137
+ this.#assertCollectionLength(length)
138
+ this.#writer.write('[')
139
+ for (let index = 0; index < length; index++) {
140
+ if (index > 0) this.#writer.write(',')
141
+ this.#writeValue(depth + 1)
142
+ }
143
+ this.#writer.write(']')
144
+ }
145
+
146
+ /**
147
+ * Writes one MessagePack map with JSON-compatible keys.
148
+ *
149
+ * @param {number} length map entry count
150
+ * @param {number} depth current nesting depth
151
+ */
152
+ #writeMap (length, depth) {
153
+ this.#assertCollectionLength(length)
154
+ this.#writer.write('{')
155
+ for (let index = 0; index < length; index++) {
156
+ if (index > 0) this.#writer.write(',')
157
+ this.#writeMapKey()
158
+ this.#writer.write(':')
159
+ this.#writeValue(depth + 1)
160
+ }
161
+ this.#writer.write('}')
162
+ }
163
+
164
+ /**
165
+ * Writes a string or integer MessagePack map key as a JSON string.
166
+ */
167
+ #writeMapKey () {
168
+ const prefix = this.#readUInt8()
169
+ if (prefix <= 0x7F) return this.#writer.write(JSON.stringify(String(prefix)))
170
+ if (prefix >= 0xE0) return this.#writer.write(JSON.stringify(String(prefix - 0x01_00)))
171
+ if ((prefix & 0xE0) === 0xA0) return this.#writeString(prefix & 0x1F)
172
+
173
+ let value
174
+ switch (prefix) {
175
+ case 0xCC: value = this.#readUInt8(); break
176
+ case 0xCD: value = this.#read('readUInt16BE', 2); break
177
+ case 0xCE: value = this.#read('readUInt32BE', 4); break
178
+ case 0xCF: value = this.#read('readBigUInt64BE', 8); break
179
+ case 0xD0: value = this.#read('readInt8', 1); break
180
+ case 0xD1: value = this.#read('readInt16BE', 2); break
181
+ case 0xD2: value = this.#read('readInt32BE', 4); break
182
+ case 0xD3: value = this.#read('readBigInt64BE', 8); break
183
+ case 0xD9: return this.#writeString(this.#readUInt8())
184
+ case 0xDA: return this.#writeString(this.#read('readUInt16BE', 2))
185
+ case 0xDB: return this.#writeString(this.#read('readUInt32BE', 4))
186
+ default:
187
+ throw new Error(`Unsupported MessagePack map key byte 0x${prefix.toString(16)}.`)
188
+ }
189
+ this.#writer.write(JSON.stringify(String(value)))
190
+ }
191
+
192
+ /**
193
+ * Writes one UTF-8 MessagePack string.
194
+ *
195
+ * @param {number} length encoded byte length
196
+ */
197
+ #writeString (length) {
198
+ if (length > MAX_STRING_BYTES) {
199
+ throw new Error('MessagePack string exceeds validation payload limit.')
200
+ }
201
+ this.#assertAvailable(length)
202
+ const end = this.#offset + length
203
+ const value = this.#input.toString('utf8', this.#offset, end)
204
+ this.#offset = end
205
+ this.#writer.write(JSON.stringify(value))
206
+ }
207
+
208
+ /**
209
+ * Writes one binary MessagePack value as a base64 JSON string.
210
+ *
211
+ * @param {number} length encoded byte length
212
+ */
213
+ #writeBinary (length) {
214
+ this.#assertAvailable(length)
215
+ const end = this.#offset + length
216
+ const value = this.#input.subarray(this.#offset, end).toString('base64')
217
+ this.#offset = end
218
+ this.#writer.write(JSON.stringify(value))
219
+ }
220
+
221
+ /**
222
+ * Writes one finite floating-point value.
223
+ *
224
+ * @param {number} value decoded floating-point value
225
+ */
226
+ #writeFloat (value) {
227
+ if (!Number.isFinite(value)) throw new Error('MessagePack validation payload contains a non-finite number.')
228
+ this.#writer.write(Object.is(value, -0) ? '-0' : String(value))
229
+ }
230
+
231
+ /**
232
+ * Enforces per-collection and aggregate collection-entry limits.
233
+ *
234
+ * @param {number} length collection length
235
+ */
236
+ #assertCollectionLength (length) {
237
+ if (length > MAX_COLLECTION_ENTRIES) {
238
+ throw new Error(`MessagePack collection length ${length} exceeds validation entry limit.`)
239
+ }
240
+ this.#collectionEntries += length
241
+ if (this.#collectionEntries > MAX_COLLECTION_ENTRIES) {
242
+ throw new Error('MessagePack aggregate collection entries exceed validation limit.')
243
+ }
244
+ if (length > this.#input.length - this.#offset) {
245
+ throw new Error(`MessagePack collection length ${length} exceeds remaining payload bytes.`)
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Ensures the requested bytes remain in the input.
251
+ *
252
+ * @param {number} length byte count
253
+ */
254
+ #assertAvailable (length) {
255
+ if (length < 0 || this.#offset + length > this.#input.length) {
256
+ throw new Error('Unexpected end of MessagePack validation payload.')
257
+ }
258
+ }
259
+
260
+ /** @returns {number} unsigned 8-bit integer */
261
+ #readUInt8 () {
262
+ this.#assertAvailable(1)
263
+ return this.#input[this.#offset++]
264
+ }
265
+
266
+ /**
267
+ * Reads one fixed-width numeric value.
268
+ *
269
+ * @param {keyof Buffer} method Buffer reader method
270
+ * @param {number} bytes encoded width
271
+ * @returns {number|bigint} decoded value
272
+ */
273
+ #read (method, bytes) {
274
+ this.#assertAvailable(bytes)
275
+ const value = this.#input[method](this.#offset)
276
+ this.#offset += bytes
277
+ return value
278
+ }
279
+ }
280
+
281
+ module.exports = {
282
+ MAX_COLLECTION_ENTRIES,
283
+ MAX_INPUT_BYTES,
284
+ MAX_NESTING_DEPTH,
285
+ MAX_OUTPUT_BYTES,
286
+ MAX_STRING_BYTES,
287
+ msgpackToJson,
288
+ }
@@ -0,0 +1,84 @@
1
+ 'use strict'
2
+
3
+ const EVENT_TYPES = new Set(['test', 'test_module_end', 'test_session_end', 'test_suite_end'])
4
+ const META_FIELDS = new Set([
5
+ 'test.command',
6
+ 'test.early_flake.enabled',
7
+ 'test.final_status',
8
+ 'test.is_new',
9
+ 'test.is_retry',
10
+ 'test.module',
11
+ 'test.name',
12
+ 'test.retry_reason',
13
+ 'test.source.file',
14
+ 'test.status',
15
+ 'test.suite',
16
+ 'test.test_management.attempt_to_fix_passed',
17
+ 'test.test_management.enabled',
18
+ 'test.test_management.is_attempt_to_fix',
19
+ 'test.test_management.is_quarantined',
20
+ 'test.test_management.is_test_disabled',
21
+ ])
22
+ const METRIC_FIELDS = new Set(['test.is_new', 'test.is_retry'])
23
+
24
+ /**
25
+ * Projects a decoded Test Optimization payload into the fixed validation-only event schema.
26
+ *
27
+ * @param {unknown} payload decoded Test Optimization payload
28
+ * @returns {{events: object[], version: 1}} allowlisted payload
29
+ */
30
+ function projectTestCyclePayload (payload) {
31
+ if (!isObject(payload) || payload.version !== 1 || !Array.isArray(payload.events)) {
32
+ throw new Error('Test Optimization validation payload has an unsupported envelope.')
33
+ }
34
+
35
+ const events = []
36
+ for (const event of payload.events) {
37
+ if (isNonTestSpan(event)) continue
38
+ events.push(projectEvent(event))
39
+ }
40
+ return { version: 1, events }
41
+ }
42
+
43
+ function projectEvent (event) {
44
+ if (!isObject(event) || !EVENT_TYPES.has(event.type) || !isObject(event.content)) {
45
+ throw new Error('Test Optimization validation payload contains an unsupported event shape.')
46
+ }
47
+
48
+ return {
49
+ type: event.type,
50
+ content: {
51
+ meta: projectFields(event.content.meta, META_FIELDS),
52
+ metrics: projectFields(event.content.metrics, METRIC_FIELDS),
53
+ },
54
+ }
55
+ }
56
+
57
+ function isNonTestSpan (event) {
58
+ if (!isObject(event) || event.type !== 'span') return false
59
+ if (!isObject(event.content)) {
60
+ throw new Error('Test Optimization validation payload contains an unsupported span shape.')
61
+ }
62
+ return true
63
+ }
64
+
65
+ function projectFields (source, allowed) {
66
+ const projected = {}
67
+ if (!isObject(source)) return projected
68
+ for (const name of allowed) copyScalar(projected, source, name)
69
+ return projected
70
+ }
71
+
72
+ function copyScalar (target, source, name) {
73
+ const value = source[name]
74
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') target[name] = value
75
+ }
76
+
77
+ function isObject (value) {
78
+ return Boolean(value && typeof value === 'object' && !Array.isArray(value))
79
+ }
80
+
81
+ module.exports = {
82
+ EVENT_TYPES,
83
+ projectTestCyclePayload,
84
+ }