@adcp/sdk 14.2.0 → 14.3.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 (46) hide show
  1. package/dist/lib/reporting/inspection.d.mts +3 -3
  2. package/dist/lib/reporting/inspection.d.ts +3 -3
  3. package/dist/lib/reporting/inspection.js +229 -84
  4. package/dist/lib/reporting/inspection.mjs +229 -84
  5. package/dist/lib/reporting/ledger/status-ingest.js +3 -19
  6. package/dist/lib/reporting/ledger/status-ingest.mjs +2 -18
  7. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  8. package/dist/lib/server/create-adcp-server.js +5 -2
  9. package/dist/lib/server/create-adcp-server.mjs +5 -2
  10. package/dist/lib/signing/canonicalize.d.mts +2 -0
  11. package/dist/lib/signing/canonicalize.d.ts +2 -0
  12. package/dist/lib/signing/canonicalize.js +1 -1
  13. package/dist/lib/signing/canonicalize.mjs +1 -1
  14. package/dist/lib/signing/verifier.js +1 -1
  15. package/dist/lib/signing/verifier.mjs +1 -1
  16. package/dist/lib/testing/storyboard/request-signing/builder.js +13 -1
  17. package/dist/lib/testing/storyboard/request-signing/builder.mjs +13 -1
  18. package/dist/lib/testing/storyboard/request-signing/grader.js +1 -0
  19. package/dist/lib/testing/storyboard/request-signing/grader.mjs +1 -0
  20. package/dist/lib/testing/storyboard/request-signing/vector-loader.js +1 -1
  21. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +1 -1
  22. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  23. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  24. package/dist/lib/utils/pointer-utils.d.mts +2 -0
  25. package/dist/lib/utils/pointer-utils.d.ts +2 -0
  26. package/dist/lib/utils/pointer-utils.js +43 -0
  27. package/dist/lib/utils/pointer-utils.mjs +19 -0
  28. package/dist/lib/validation/diagnostic-limits.d.mts +4 -0
  29. package/dist/lib/validation/diagnostic-limits.d.ts +4 -0
  30. package/dist/lib/validation/diagnostic-limits.js +57 -0
  31. package/dist/lib/validation/diagnostic-limits.mjs +32 -0
  32. package/dist/lib/validation/schema-errors.d.mts +3 -1
  33. package/dist/lib/validation/schema-errors.d.ts +3 -1
  34. package/dist/lib/validation/schema-errors.js +18 -3
  35. package/dist/lib/validation/schema-errors.mjs +18 -3
  36. package/dist/lib/validation/schema-validator.js +56 -4
  37. package/dist/lib/validation/schema-validator.mjs +56 -4
  38. package/dist/lib/version.d.mts +3 -3
  39. package/dist/lib/version.d.ts +3 -3
  40. package/dist/lib/version.js +3 -3
  41. package/dist/lib/version.mjs +3 -3
  42. package/docs/TYPE-SUMMARY.md +2 -2
  43. package/docs/llms.txt +2 -2
  44. package/docs/migration-14.x-rc-worksheet.md +4 -4
  45. package/package.json +2 -2
  46. package/skills/call-adcp-agent/SKILL.md +4 -1
@@ -65,6 +65,7 @@ var import_envelope_status_compat = require('../utils/envelope-status-compat.js'
65
65
  var import_schema_validator = require('../validation/schema-validator.js');
66
66
  var import_sync_reporting_status_envelope = require('../validation/sync-reporting-status-envelope.js');
67
67
  var import_schema_errors = require('../validation/schema-errors.js');
68
+ var import_diagnostic_limits = require('../validation/diagnostic-limits.js');
68
69
  var import_idempotency2 = require('./idempotency/index.js');
69
70
  var import_webhook_emitter = require('./webhook-emitter.js');
70
71
  var import_middleware = require('../signing/middleware.js');
@@ -2287,7 +2288,7 @@ function createAdcpServer(config) {
2287
2288
  const validationMode = effectiveRequestValidationMode(extra);
2288
2289
  const accountIssues = protocolTaskAccountExtensionIssues(params);
2289
2290
  const outcome = validationMode === "off" ? { valid: true, issues: [], schemaId: void 0 } : (0, import_schema_validator.validateRequest)(toolName, params, requestServedRelease(params)?.validationVersion ?? adcpVersion);
2290
- const issues = [...outcome.valid ? [] : outcome.issues, ...accountIssues];
2291
+ const issues = [...accountIssues, ...outcome.valid ? [] : outcome.issues];
2291
2292
  if (issues.length === 0) return void 0;
2292
2293
  if (validationMode === "strict" || accountIssues.length > 0) {
2293
2294
  return (0, import_errors2.adcpError)(
@@ -2838,7 +2839,9 @@ function createAdcpServer(config) {
2838
2839
  })
2839
2840
  );
2840
2841
  }
2841
- let issues = idempotencyDisabled && requestIsStateChanging ? outcome.issues.filter((i) => !(i.keyword === "required" && i.pointer === "/idempotency_key")) : outcome.issues;
2842
+ let issues = idempotencyDisabled && requestIsStateChanging ? outcome.issues.filter(
2843
+ (i) => !(i.keyword === "required" && i.pointer === "/idempotency_key" && !(0, import_diagnostic_limits.validationDiagnosticsTruncated)([i]))
2844
+ ) : outcome.issues;
2842
2845
  if (toolName === "sync_accounts" && effectiveFrameworkRequestValidationMode === "strict") {
2843
2846
  const eventIssues = issues.filter(isAccountNotificationEventIssue);
2844
2847
  if (eventIssues.length > 0 && eventIssues.length === issues.length) {
@@ -98,6 +98,7 @@ import { STATUS_FREE_SYNC_RESPONSE_TOOLS } from "../utils/envelope-status-compat
98
98
  import { validateRequest, validateResponse, formatIssues } from "../validation/schema-validator.mjs";
99
99
  import { validateSyncReportingStatusEnvelope } from "../validation/sync-reporting-status-envelope.mjs";
100
100
  import { buildAdcpValidationErrorPayload } from "../validation/schema-errors.mjs";
101
+ import { validationDiagnosticsTruncated } from "../validation/diagnostic-limits.mjs";
101
102
  import { hashPayload, IdempotencyClaimOwnershipError } from "./idempotency/index.mjs";
102
103
  import {
103
104
  createWebhookEmitter
@@ -2359,7 +2360,7 @@ function createAdcpServer(config) {
2359
2360
  const validationMode = effectiveRequestValidationMode(extra);
2360
2361
  const accountIssues = protocolTaskAccountExtensionIssues(params);
2361
2362
  const outcome = validationMode === "off" ? { valid: true, issues: [], schemaId: void 0 } : validateRequest(toolName, params, requestServedRelease(params)?.validationVersion ?? adcpVersion);
2362
- const issues = [...outcome.valid ? [] : outcome.issues, ...accountIssues];
2363
+ const issues = [...accountIssues, ...outcome.valid ? [] : outcome.issues];
2363
2364
  if (issues.length === 0) return void 0;
2364
2365
  if (validationMode === "strict" || accountIssues.length > 0) {
2365
2366
  return adcpError(
@@ -2910,7 +2911,9 @@ function createAdcpServer(config) {
2910
2911
  })
2911
2912
  );
2912
2913
  }
2913
- let issues = idempotencyDisabled && requestIsStateChanging ? outcome.issues.filter((i) => !(i.keyword === "required" && i.pointer === "/idempotency_key")) : outcome.issues;
2914
+ let issues = idempotencyDisabled && requestIsStateChanging ? outcome.issues.filter(
2915
+ (i) => !(i.keyword === "required" && i.pointer === "/idempotency_key" && !validationDiagnosticsTruncated([i]))
2916
+ ) : outcome.issues;
2914
2917
  if (toolName === "sync_accounts" && effectiveFrameworkRequestValidationMode === "strict") {
2915
2918
  const eventIssues = issues.filter(isAccountNotificationEventIssue);
2916
2919
  if (eventIssues.length > 0 && eventIssues.length === issues.length) {
@@ -68,5 +68,7 @@ export declare function formatSignatureParams(components: ReadonlyArray<string>,
68
68
  * non-transitional produce different A-labels for the same input, which
69
69
  * would open a signer/verifier canonicalization differential. Accepts
70
70
  * both absolute (`scheme://…`) and scheme-relative (`//…`) URL shapes.
71
+ * The transport taxonomy classifies the received URI as malformed. Diagnostic
72
+ * step 1 is SDK-local parsing, not the checklist's signature-header parser.
71
73
  */
72
74
  export declare function rejectNonAsciiHost(rawUrl: string): void;
@@ -68,5 +68,7 @@ export declare function formatSignatureParams(components: ReadonlyArray<string>,
68
68
  * non-transitional produce different A-labels for the same input, which
69
69
  * would open a signer/verifier canonicalization differential. Accepts
70
70
  * both absolute (`scheme://…`) and scheme-relative (`//…`) URL shapes.
71
+ * The transport taxonomy classifies the received URI as malformed. Diagnostic
72
+ * step 1 is SDK-local parsing, not the checklist's signature-header parser.
71
73
  */
72
74
  export declare function rejectNonAsciiHost(rawUrl: string): void;
@@ -269,7 +269,7 @@ function rejectNonAsciiHost(rawUrl) {
269
269
  for (let i = 0; i < authority.length; i++) {
270
270
  if (authority.charCodeAt(i) > 127) {
271
271
  throw new import_errors.RequestSignatureError(
272
- "request_signature_header_malformed",
272
+ "request_target_uri_malformed",
273
273
  1,
274
274
  "URL authority contains non-ASCII bytes; use the A-label (Punycode) form"
275
275
  );
@@ -239,7 +239,7 @@ function rejectNonAsciiHost(rawUrl) {
239
239
  for (let i = 0; i < authority.length; i++) {
240
240
  if (authority.charCodeAt(i) > 127) {
241
241
  throw new RequestSignatureError(
242
- "request_signature_header_malformed",
242
+ "request_target_uri_malformed",
243
243
  1,
244
244
  "URL authority contains non-ASCII bytes; use the A-label (Punycode) form"
245
245
  );
@@ -99,7 +99,7 @@ async function verifyRequestSignature(request, options) {
99
99
  if (!parsedSig) throw parseError;
100
100
  const effectiveEncoding = pinnedBinaryEncoding ?? parsedEncoding;
101
101
  const canonicalizationProfile = effectiveEncoding === "rfc8941-base64" ? "3.2" : "legacy";
102
- if (canonicalizationProfile === "legacy") (0, import_canonicalize.rejectNonAsciiHost)(request.url);
102
+ (0, import_canonicalize.rejectNonAsciiHost)(request.url);
103
103
  validateSingleValuedCoveredHeaders(parsedInput.components, request);
104
104
  requireParams(parsedInput);
105
105
  if (parsedInput.params.tag !== import_types.REQUEST_SIGNING_TAG) {
@@ -92,7 +92,7 @@ async function verifyRequestSignature(request, options) {
92
92
  if (!parsedSig) throw parseError;
93
93
  const effectiveEncoding = pinnedBinaryEncoding ?? parsedEncoding;
94
94
  const canonicalizationProfile = effectiveEncoding === "rfc8941-base64" ? "3.2" : "legacy";
95
- if (canonicalizationProfile === "legacy") rejectNonAsciiHost(request.url);
95
+ rejectNonAsciiHost(request.url);
96
96
  validateSingleValuedCoveredHeaders(parsedInput.components, request);
97
97
  requireParams(parsedInput);
98
98
  if (parsedInput.params.tag !== REQUEST_SIGNING_TAG) {
@@ -192,6 +192,7 @@ const MUTATIONS = {
192
192
  // transport-ungradable by the live probe because no HTTP client can route
193
193
  // to that intentionally invalid host spelling.
194
194
  "profile-3.2/negative/001-base64url-sf-binary": (vector, _keys, options) => passthrough(vector, options),
195
+ "profile-3.2/negative/001-no-signature-header": delegateToRoot("001-no-signature-header"),
195
196
  "profile-3.2/negative/002-multiple-trailing-dots": (vector, _keys, options) => passthrough(vector, options),
196
197
  "profile-3.2/negative/002-wrong-tag": delegateToRoot("002-wrong-tag"),
197
198
  "profile-3.2/negative/003-expired-signature": delegateToRoot("003-expired-signature"),
@@ -208,6 +209,7 @@ const MUTATIONS = {
208
209
  "profile-3.2/negative/008-unknown-keyid": delegateToRoot("008-unknown-keyid"),
209
210
  "profile-3.2/negative/009-key-ops-missing-verify": delegateToRoot("009-key-ops-missing-verify"),
210
211
  "profile-3.2/negative/010-content-digest-mismatch": delegateToRoot("010-content-digest-mismatch"),
212
+ "profile-3.2/negative/011-malformed-header": delegateToRoot("011-malformed-header"),
211
213
  "profile-3.2/negative/012-missing-expires-param": delegateToRoot("012-missing-expires-param"),
212
214
  "profile-3.2/negative/013-expires-le-created": delegateToRoot("013-expires-le-created"),
213
215
  "profile-3.2/negative/014-missing-nonce-param": delegateToRoot("014-missing-nonce-param"),
@@ -220,8 +222,18 @@ const MUTATIONS = {
220
222
  },
221
223
  "profile-3.2/negative/016-replayed-nonce": delegateToRoot("016-replayed-nonce"),
222
224
  "profile-3.2/negative/017-key-revoked": delegateToRoot("017-key-revoked"),
225
+ "profile-3.2/negative/019-signature-without-signature-input": delegateToRoot("019-signature-without-signature-input"),
223
226
  "profile-3.2/negative/020-rate-abuse": delegateToRoot("020-rate-abuse"),
224
- "profile-3.2/negative/025-jwk-alg-crv-mismatch": delegateToRoot("025-jwk-alg-crv-mismatch")
227
+ "profile-3.2/negative/021-duplicate-signature-input-label": delegateToRoot("021-duplicate-signature-input-label"),
228
+ "profile-3.2/negative/022-multi-valued-content-type": delegateToRoot("022-multi-valued-content-type"),
229
+ "profile-3.2/negative/023-multi-valued-content-digest": delegateToRoot("023-multi-valued-content-digest"),
230
+ "profile-3.2/negative/024-unquoted-string-param": delegateToRoot("024-unquoted-string-param"),
231
+ "profile-3.2/negative/025-jwk-alg-crv-mismatch": delegateToRoot("025-jwk-alg-crv-mismatch"),
232
+ "profile-3.2/negative/026-non-ascii-host": delegateToRoot("026-non-ascii-host"),
233
+ "profile-3.2/negative/027-webhook-registration-authentication-unsigned": delegateToRoot(
234
+ "027-webhook-registration-authentication-unsigned"
235
+ ),
236
+ "profile-3.2/negative/028-unsigned-protocol-method-required": delegateToRoot("028-unsigned-protocol-method-required")
225
237
  };
226
238
  function delegateToRoot(rootId) {
227
239
  return (vector, keys, options) => {
@@ -175,6 +175,7 @@ const MUTATIONS = {
175
175
  // transport-ungradable by the live probe because no HTTP client can route
176
176
  // to that intentionally invalid host spelling.
177
177
  "profile-3.2/negative/001-base64url-sf-binary": (vector, _keys, options) => passthrough(vector, options),
178
+ "profile-3.2/negative/001-no-signature-header": delegateToRoot("001-no-signature-header"),
178
179
  "profile-3.2/negative/002-multiple-trailing-dots": (vector, _keys, options) => passthrough(vector, options),
179
180
  "profile-3.2/negative/002-wrong-tag": delegateToRoot("002-wrong-tag"),
180
181
  "profile-3.2/negative/003-expired-signature": delegateToRoot("003-expired-signature"),
@@ -191,6 +192,7 @@ const MUTATIONS = {
191
192
  "profile-3.2/negative/008-unknown-keyid": delegateToRoot("008-unknown-keyid"),
192
193
  "profile-3.2/negative/009-key-ops-missing-verify": delegateToRoot("009-key-ops-missing-verify"),
193
194
  "profile-3.2/negative/010-content-digest-mismatch": delegateToRoot("010-content-digest-mismatch"),
195
+ "profile-3.2/negative/011-malformed-header": delegateToRoot("011-malformed-header"),
194
196
  "profile-3.2/negative/012-missing-expires-param": delegateToRoot("012-missing-expires-param"),
195
197
  "profile-3.2/negative/013-expires-le-created": delegateToRoot("013-expires-le-created"),
196
198
  "profile-3.2/negative/014-missing-nonce-param": delegateToRoot("014-missing-nonce-param"),
@@ -203,8 +205,18 @@ const MUTATIONS = {
203
205
  },
204
206
  "profile-3.2/negative/016-replayed-nonce": delegateToRoot("016-replayed-nonce"),
205
207
  "profile-3.2/negative/017-key-revoked": delegateToRoot("017-key-revoked"),
208
+ "profile-3.2/negative/019-signature-without-signature-input": delegateToRoot("019-signature-without-signature-input"),
206
209
  "profile-3.2/negative/020-rate-abuse": delegateToRoot("020-rate-abuse"),
207
- "profile-3.2/negative/025-jwk-alg-crv-mismatch": delegateToRoot("025-jwk-alg-crv-mismatch")
210
+ "profile-3.2/negative/021-duplicate-signature-input-label": delegateToRoot("021-duplicate-signature-input-label"),
211
+ "profile-3.2/negative/022-multi-valued-content-type": delegateToRoot("022-multi-valued-content-type"),
212
+ "profile-3.2/negative/023-multi-valued-content-digest": delegateToRoot("023-multi-valued-content-digest"),
213
+ "profile-3.2/negative/024-unquoted-string-param": delegateToRoot("024-unquoted-string-param"),
214
+ "profile-3.2/negative/025-jwk-alg-crv-mismatch": delegateToRoot("025-jwk-alg-crv-mismatch"),
215
+ "profile-3.2/negative/026-non-ascii-host": delegateToRoot("026-non-ascii-host"),
216
+ "profile-3.2/negative/027-webhook-registration-authentication-unsigned": delegateToRoot(
217
+ "027-webhook-registration-authentication-unsigned"
218
+ ),
219
+ "profile-3.2/negative/028-unsigned-protocol-method-required": delegateToRoot("028-unsigned-protocol-method-required")
208
220
  };
209
221
  function delegateToRoot(rootId) {
210
222
  return (vector, keys, options) => {
@@ -134,6 +134,7 @@ const TRANSPORT_UNGRADABLE = {
134
134
  // agent as Punycode, defeating the parse-time check. Direct verifier
135
135
  // tests exercise this edge.
136
136
  "026-non-ascii-host": "HTTP transport punycodes U-labels before the request leaves the client; verified at the library level.",
137
+ "profile-3.2/negative/026-non-ascii-host": "HTTP transport punycodes U-labels before the request leaves the client; verified at the library level.",
137
138
  "profile-3.2/negative/002-multiple-trailing-dots": "HTTP transport cannot route to an intentionally malformed DNS authority; verified at the library level."
138
139
  };
139
140
  function semanticVectorExclusion(vector, declaredCapability) {
@@ -113,6 +113,7 @@ const TRANSPORT_UNGRADABLE = {
113
113
  // agent as Punycode, defeating the parse-time check. Direct verifier
114
114
  // tests exercise this edge.
115
115
  "026-non-ascii-host": "HTTP transport punycodes U-labels before the request leaves the client; verified at the library level.",
116
+ "profile-3.2/negative/026-non-ascii-host": "HTTP transport punycodes U-labels before the request leaves the client; verified at the library level.",
116
117
  "profile-3.2/negative/002-multiple-trailing-dots": "HTTP transport cannot route to an intentionally malformed DNS authority; verified at the library level."
117
118
  };
118
119
  function semanticVectorExclusion(vector, declaredCapability) {
@@ -39,7 +39,7 @@ function selectRequestSigningVectors(loaded, signingProfileVersion) {
39
39
  }
40
40
  function signingProfileForAdcpVersion(version) {
41
41
  const match = /^(\d+)\.(\d+)/.exec(version ?? "");
42
- return match && Number(match[1]) === 3 && Number(match[2]) === 2 ? "3.2" : void 0;
42
+ return match && (Number(match[1]) > 3 || Number(match[1]) === 3 && Number(match[2]) >= 2) ? "3.2" : void 0;
43
43
  }
44
44
  const ERROR_CODES = /* @__PURE__ */ new Set([
45
45
  "request_signature_required",
@@ -11,7 +11,7 @@ function selectRequestSigningVectors(loaded, signingProfileVersion) {
11
11
  }
12
12
  function signingProfileForAdcpVersion(version) {
13
13
  const match = /^(\d+)\.(\d+)/.exec(version ?? "");
14
- return match && Number(match[1]) === 3 && Number(match[2]) === 2 ? "3.2" : void 0;
14
+ return match && (Number(match[1]) > 3 || Number(match[1]) === 3 && Number(match[2]) >= 2) ? "3.2" : void 0;
15
15
  }
16
16
  const ERROR_CODES = /* @__PURE__ */ new Set([
17
17
  "request_signature_required",
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
197
197
  */
198
198
  export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
199
199
  /** Capability semver emitted in run summaries and used for advisory expiry. */
200
- export declare const RUNNER_CAPABILITY_VERSION = "14.2.0";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "14.3.0";
201
201
  /** True when a failed validation contributes to the owning step's grade. */
202
202
  export declare function validationFailsStep(result: ValidationResult): boolean;
203
203
  /**
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
197
197
  */
198
198
  export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
199
199
  /** Capability semver emitted in run summaries and used for advisory expiry. */
200
- export declare const RUNNER_CAPABILITY_VERSION = "14.2.0";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "14.3.0";
201
201
  /** True when a failed validation contributes to the owning step's grade. */
202
202
  export declare function validationFailsStep(result: ValidationResult): boolean;
203
203
  /**
@@ -0,0 +1,2 @@
1
+ /** Translate SDK JSON Pointers to the AdCP error.field JSONPath-lite notation. */
2
+ export declare function jsonPointerToJsonPathLite(pointer: string): string | undefined;
@@ -0,0 +1,2 @@
1
+ /** Translate SDK JSON Pointers to the AdCP error.field JSONPath-lite notation. */
2
+ export declare function jsonPointerToJsonPathLite(pointer: string): string | undefined;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var pointer_utils_exports = {};
20
+ __export(pointer_utils_exports, {
21
+ jsonPointerToJsonPathLite: () => jsonPointerToJsonPathLite
22
+ });
23
+ module.exports = __toCommonJS(pointer_utils_exports);
24
+ function jsonPointerToJsonPathLite(pointer) {
25
+ if (pointer === "" || pointer === "/") return "$";
26
+ if (!pointer.startsWith("/")) return void 0;
27
+ let field = "";
28
+ for (const encoded of pointer.slice(1).split("/")) {
29
+ const segment = encoded.replace(/~1/g, "/").replace(/~0/g, "~");
30
+ if (/^(0|[1-9][0-9]*)$/.test(segment)) {
31
+ field += `${field ? "" : "$"}[${segment}]`;
32
+ } else if (/^[A-Za-z_][A-Za-z0-9_-]*$/.test(segment)) {
33
+ field += field ? `.${segment}` : segment;
34
+ } else {
35
+ field += `${field ? "" : "$"}[${JSON.stringify(segment)}]`;
36
+ }
37
+ }
38
+ return field;
39
+ }
40
+ // Annotate the CommonJS export names for ESM import in node:
41
+ 0 && (module.exports = {
42
+ jsonPointerToJsonPathLite
43
+ });
@@ -0,0 +1,19 @@
1
+ function jsonPointerToJsonPathLite(pointer) {
2
+ if (pointer === "" || pointer === "/") return "$";
3
+ if (!pointer.startsWith("/")) return void 0;
4
+ let field = "";
5
+ for (const encoded of pointer.slice(1).split("/")) {
6
+ const segment = encoded.replace(/~1/g, "/").replace(/~0/g, "~");
7
+ if (/^(0|[1-9][0-9]*)$/.test(segment)) {
8
+ field += `${field ? "" : "$"}[${segment}]`;
9
+ } else if (/^[A-Za-z_][A-Za-z0-9_-]*$/.test(segment)) {
10
+ field += field ? `.${segment}` : segment;
11
+ } else {
12
+ field += `${field ? "" : "$"}[${JSON.stringify(segment)}]`;
13
+ }
14
+ }
15
+ return field;
16
+ }
17
+ export {
18
+ jsonPointerToJsonPathLite
19
+ };
@@ -0,0 +1,4 @@
1
+ import type { ValidationIssue } from './schema-validator.mjs';
2
+ export declare function validationDiagnosticsTruncated(issues: readonly ValidationIssue[]): boolean;
3
+ /** Retain actionable diagnostics with a visible marker when count/bytes overflow. */
4
+ export declare function boundValidationIssues(issues: Iterable<ValidationIssue>): ValidationIssue[];
@@ -0,0 +1,4 @@
1
+ import type { ValidationIssue } from './schema-validator';
2
+ export declare function validationDiagnosticsTruncated(issues: readonly ValidationIssue[]): boolean;
3
+ /** Retain actionable diagnostics with a visible marker when count/bytes overflow. */
4
+ export declare function boundValidationIssues(issues: Iterable<ValidationIssue>): ValidationIssue[];
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var diagnostic_limits_exports = {};
20
+ __export(diagnostic_limits_exports, {
21
+ boundValidationIssues: () => boundValidationIssues,
22
+ validationDiagnosticsTruncated: () => validationDiagnosticsTruncated
23
+ });
24
+ module.exports = __toCommonJS(diagnostic_limits_exports);
25
+ const MAX_ISSUES = 100;
26
+ const MAX_ISSUE_BYTES = 64 * 1024;
27
+ const MAX_SINGLE_ISSUE_BYTES = 8 * 1024;
28
+ const OMITTED_MESSAGE = "Validation failed; additional diagnostics omitted because the diagnostic limit was reached.";
29
+ const OMITTED_BYTES = 8 * 1024;
30
+ function validationDiagnosticsTruncated(issues) {
31
+ return issues.some((issue) => issue.message === OMITTED_MESSAGE);
32
+ }
33
+ function boundValidationIssues(issues) {
34
+ const bounded = [];
35
+ let bytes = 2;
36
+ for (const issue of issues) {
37
+ const issueBytes = Buffer.byteLength(JSON.stringify(issue), "utf8") + 1;
38
+ if (bounded.length >= MAX_ISSUES || issueBytes > MAX_SINGLE_ISSUE_BYTES || bytes + issueBytes + OMITTED_BYTES > MAX_ISSUE_BYTES) {
39
+ const omitted = bounded.length === MAX_ISSUES ? bounded.pop() : issue;
40
+ bounded.push({
41
+ pointer: Buffer.byteLength(omitted.pointer, "utf8") <= 1024 ? omitted.pointer : "/",
42
+ keyword: Buffer.byteLength(omitted.keyword, "utf8") <= 128 ? omitted.keyword : "type",
43
+ message: OMITTED_MESSAGE,
44
+ schemaPath: ""
45
+ });
46
+ break;
47
+ }
48
+ bounded.push(issue);
49
+ bytes += issueBytes;
50
+ }
51
+ return bounded;
52
+ }
53
+ // Annotate the CommonJS export names for ESM import in node:
54
+ 0 && (module.exports = {
55
+ boundValidationIssues,
56
+ validationDiagnosticsTruncated
57
+ });
@@ -0,0 +1,32 @@
1
+ const MAX_ISSUES = 100;
2
+ const MAX_ISSUE_BYTES = 64 * 1024;
3
+ const MAX_SINGLE_ISSUE_BYTES = 8 * 1024;
4
+ const OMITTED_MESSAGE = "Validation failed; additional diagnostics omitted because the diagnostic limit was reached.";
5
+ const OMITTED_BYTES = 8 * 1024;
6
+ function validationDiagnosticsTruncated(issues) {
7
+ return issues.some((issue) => issue.message === OMITTED_MESSAGE);
8
+ }
9
+ function boundValidationIssues(issues) {
10
+ const bounded = [];
11
+ let bytes = 2;
12
+ for (const issue of issues) {
13
+ const issueBytes = Buffer.byteLength(JSON.stringify(issue), "utf8") + 1;
14
+ if (bounded.length >= MAX_ISSUES || issueBytes > MAX_SINGLE_ISSUE_BYTES || bytes + issueBytes + OMITTED_BYTES > MAX_ISSUE_BYTES) {
15
+ const omitted = bounded.length === MAX_ISSUES ? bounded.pop() : issue;
16
+ bounded.push({
17
+ pointer: Buffer.byteLength(omitted.pointer, "utf8") <= 1024 ? omitted.pointer : "/",
18
+ keyword: Buffer.byteLength(omitted.keyword, "utf8") <= 128 ? omitted.keyword : "type",
19
+ message: OMITTED_MESSAGE,
20
+ schemaPath: ""
21
+ });
22
+ break;
23
+ }
24
+ bounded.push(issue);
25
+ bytes += issueBytes;
26
+ }
27
+ return bounded;
28
+ }
29
+ export {
30
+ boundValidationIssues,
31
+ validationDiagnosticsTruncated
32
+ };
@@ -9,8 +9,9 @@ export interface ValidationErrorDetails {
9
9
  tool: string;
10
10
  /** Which side of the exchange — request (outgoing) or response (incoming). */
11
11
  side: 'request' | 'response';
12
- /** All failures, each with a JSON Pointer to the bad field. */
12
+ /** Bounded failures, each with a JSON Pointer to the bad field. */
13
13
  issues: ValidationIssue[];
14
+ issues_truncated?: boolean;
14
15
  }
15
16
  /**
16
17
  * Build a `ValidationError` thrown by strict-mode client hooks. Keeps the
@@ -34,6 +35,7 @@ export interface AdcpValidationErrorDetails {
34
35
  issues: Array<Omit<ValidationIssue, 'schemaPath'> & {
35
36
  schemaPath?: string;
36
37
  }>;
38
+ issues_truncated?: boolean;
37
39
  }
38
40
  /**
39
41
  * Serialize issues for the server-side `adcpError('VALIDATION_ERROR', ...)` call.
@@ -9,8 +9,9 @@ export interface ValidationErrorDetails {
9
9
  tool: string;
10
10
  /** Which side of the exchange — request (outgoing) or response (incoming). */
11
11
  side: 'request' | 'response';
12
- /** All failures, each with a JSON Pointer to the bad field. */
12
+ /** Bounded failures, each with a JSON Pointer to the bad field. */
13
13
  issues: ValidationIssue[];
14
+ issues_truncated?: boolean;
14
15
  }
15
16
  /**
16
17
  * Build a `ValidationError` thrown by strict-mode client hooks. Keeps the
@@ -34,6 +35,7 @@ export interface AdcpValidationErrorDetails {
34
35
  issues: Array<Omit<ValidationIssue, 'schemaPath'> & {
35
36
  schemaPath?: string;
36
37
  }>;
38
+ issues_truncated?: boolean;
37
39
  }
38
40
  /**
39
41
  * Serialize issues for the server-side `adcpError('VALIDATION_ERROR', ...)` call.
@@ -24,6 +24,8 @@ __export(schema_errors_exports, {
24
24
  module.exports = __toCommonJS(schema_errors_exports);
25
25
  var import_errors = require('../errors/index.js');
26
26
  var import_schema_validator = require('./schema-validator.js');
27
+ var import_pointer_utils = require('../utils/pointer-utils.js');
28
+ var import_diagnostic_limits = require('./diagnostic-limits.js');
27
29
  function buildIssueProseSuffix(issue, rootSchemaId) {
28
30
  const parts = [];
29
31
  if (issue.schemaId && issue.schemaId !== rootSchemaId) parts.push(`schema: ${issue.schemaId}`);
@@ -33,14 +35,21 @@ function buildIssueProseSuffix(issue, rootSchemaId) {
33
35
  return parts.length > 0 ? ` (${parts.join("; ")})` : "";
34
36
  }
35
37
  function buildValidationError(tool, side, issues) {
38
+ issues = (0, import_diagnostic_limits.boundValidationIssues)(issues);
36
39
  const first = issues[0];
37
40
  const field = first?.pointer ?? "/";
38
41
  const constraint = first ? `${first.keyword}: ${first.message}${buildIssueProseSuffix(first, void 0)}` : "schema validation failed";
39
42
  const err = new import_errors.ValidationError(field, void 0, `${tool} ${side}: ${constraint}`);
40
- err.details = { tool, side, issues };
43
+ err.details = {
44
+ tool,
45
+ side,
46
+ issues,
47
+ ...(0, import_diagnostic_limits.validationDiagnosticsTruncated)(issues) && { issues_truncated: true }
48
+ };
41
49
  return err;
42
50
  }
43
51
  function buildAdcpValidationErrorPayload(tool, side, issues, options = {}) {
52
+ issues = (0, import_diagnostic_limits.boundValidationIssues)(issues);
44
53
  const first = issues[0];
45
54
  let message;
46
55
  if (first != null) {
@@ -52,9 +61,15 @@ function buildAdcpValidationErrorPayload(tool, side, issues, options = {}) {
52
61
  const payload = {
53
62
  message,
54
63
  issues: emittedIssues,
55
- details: { tool, side, issues: emittedIssues }
64
+ details: {
65
+ tool,
66
+ side,
67
+ issues: emittedIssues,
68
+ ...(0, import_diagnostic_limits.validationDiagnosticsTruncated)(issues) && { issues_truncated: true }
69
+ }
56
70
  };
57
- if (first?.pointer) payload.field = first.pointer;
71
+ const field = first && (0, import_pointer_utils.jsonPointerToJsonPathLite)(first.pointer);
72
+ if (field !== void 0) payload.field = field;
58
73
  return payload;
59
74
  }
60
75
  // Annotate the CommonJS export names for ESM import in node:
@@ -1,5 +1,7 @@
1
1
  import { ValidationError } from "../errors/index.mjs";
2
2
  import { formatDiscriminator } from "./schema-validator.mjs";
3
+ import { jsonPointerToJsonPathLite } from "../utils/pointer-utils.mjs";
4
+ import { boundValidationIssues, validationDiagnosticsTruncated } from "./diagnostic-limits.mjs";
3
5
  function buildIssueProseSuffix(issue, rootSchemaId) {
4
6
  const parts = [];
5
7
  if (issue.schemaId && issue.schemaId !== rootSchemaId) parts.push(`schema: ${issue.schemaId}`);
@@ -9,14 +11,21 @@ function buildIssueProseSuffix(issue, rootSchemaId) {
9
11
  return parts.length > 0 ? ` (${parts.join("; ")})` : "";
10
12
  }
11
13
  function buildValidationError(tool, side, issues) {
14
+ issues = boundValidationIssues(issues);
12
15
  const first = issues[0];
13
16
  const field = first?.pointer ?? "/";
14
17
  const constraint = first ? `${first.keyword}: ${first.message}${buildIssueProseSuffix(first, void 0)}` : "schema validation failed";
15
18
  const err = new ValidationError(field, void 0, `${tool} ${side}: ${constraint}`);
16
- err.details = { tool, side, issues };
19
+ err.details = {
20
+ tool,
21
+ side,
22
+ issues,
23
+ ...validationDiagnosticsTruncated(issues) && { issues_truncated: true }
24
+ };
17
25
  return err;
18
26
  }
19
27
  function buildAdcpValidationErrorPayload(tool, side, issues, options = {}) {
28
+ issues = boundValidationIssues(issues);
20
29
  const first = issues[0];
21
30
  let message;
22
31
  if (first != null) {
@@ -28,9 +37,15 @@ function buildAdcpValidationErrorPayload(tool, side, issues, options = {}) {
28
37
  const payload = {
29
38
  message,
30
39
  issues: emittedIssues,
31
- details: { tool, side, issues: emittedIssues }
40
+ details: {
41
+ tool,
42
+ side,
43
+ issues: emittedIssues,
44
+ ...validationDiagnosticsTruncated(issues) && { issues_truncated: true }
45
+ }
32
46
  };
33
- if (first?.pointer) payload.field = first.pointer;
47
+ const field = first && jsonPointerToJsonPathLite(first.pointer);
48
+ if (field !== void 0) payload.field = field;
34
49
  return payload;
35
50
  }
36
51
  export {