@adcp/sdk 17.0.0-beta.0 → 17.0.0-beta.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 (70) hide show
  1. package/dist/lib/adapters/version/3.1/bidding.js +1 -1
  2. package/dist/lib/adapters/version/3.1/bidding.mjs +1 -1
  3. package/dist/lib/core/ResponseValidator.js +1 -1
  4. package/dist/lib/core/ResponseValidator.mjs +1 -1
  5. package/dist/lib/core/SingleAgentClient.d.mts +7 -5
  6. package/dist/lib/core/SingleAgentClient.d.ts +7 -5
  7. package/dist/lib/core/SingleAgentClient.js +57 -32
  8. package/dist/lib/core/SingleAgentClient.mjs +59 -33
  9. package/dist/lib/core/TaskExecutor.js +5 -3
  10. package/dist/lib/core/TaskExecutor.mjs +5 -3
  11. package/dist/lib/errors/index.d.mts +22 -0
  12. package/dist/lib/errors/index.d.ts +22 -0
  13. package/dist/lib/errors/index.js +43 -0
  14. package/dist/lib/errors/index.mjs +42 -0
  15. package/dist/lib/index.d.mts +1 -1
  16. package/dist/lib/index.d.ts +1 -1
  17. package/dist/lib/index.js +2 -0
  18. package/dist/lib/index.mjs +2 -0
  19. package/dist/lib/protocols/mcp-modern.d.mts +2 -0
  20. package/dist/lib/protocols/mcp-modern.d.ts +2 -0
  21. package/dist/lib/protocols/mcp-modern.js +31 -5
  22. package/dist/lib/protocols/mcp-modern.mjs +31 -5
  23. package/dist/lib/protocols/mcp-scope.d.mts +3 -1
  24. package/dist/lib/protocols/mcp-scope.d.ts +3 -1
  25. package/dist/lib/protocols/mcp-scope.js +19 -2
  26. package/dist/lib/protocols/mcp-scope.mjs +18 -2
  27. package/dist/lib/protocols/mcp.js +12 -6
  28. package/dist/lib/protocols/mcp.mjs +13 -6
  29. package/dist/lib/testing/client.d.mts +1 -0
  30. package/dist/lib/testing/client.d.ts +1 -0
  31. package/dist/lib/testing/client.js +6 -5
  32. package/dist/lib/testing/client.mjs +6 -5
  33. package/dist/lib/testing/storyboard/agent-routing.d.mts +5 -2
  34. package/dist/lib/testing/storyboard/agent-routing.d.ts +5 -2
  35. package/dist/lib/testing/storyboard/agent-routing.js +11 -4
  36. package/dist/lib/testing/storyboard/agent-routing.mjs +11 -4
  37. package/dist/lib/testing/storyboard/context.d.mts +13 -3
  38. package/dist/lib/testing/storyboard/context.d.ts +13 -3
  39. package/dist/lib/testing/storyboard/context.js +15 -10
  40. package/dist/lib/testing/storyboard/context.mjs +15 -10
  41. package/dist/lib/testing/storyboard/runner.js +141 -13
  42. package/dist/lib/testing/storyboard/runner.mjs +141 -13
  43. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  44. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  45. package/dist/lib/testing/storyboard/validations.js +4 -1
  46. package/dist/lib/testing/storyboard/validations.mjs +4 -1
  47. package/dist/lib/testing/test-controller.js +3 -0
  48. package/dist/lib/testing/test-controller.mjs +3 -0
  49. package/dist/lib/utils/envelope-status-compat.d.mts +18 -1
  50. package/dist/lib/utils/envelope-status-compat.d.ts +18 -1
  51. package/dist/lib/utils/envelope-status-compat.js +11 -5
  52. package/dist/lib/utils/envelope-status-compat.mjs +11 -5
  53. package/dist/lib/utils/response-unwrapper.js +12 -9
  54. package/dist/lib/utils/response-unwrapper.mjs +12 -9
  55. package/dist/lib/v2/projection/creative-delivery.js +56 -11
  56. package/dist/lib/v2/projection/creative-delivery.mjs +56 -11
  57. package/dist/lib/validation/schema-validator.js +1 -1
  58. package/dist/lib/validation/schema-validator.mjs +1 -1
  59. package/dist/lib/version.d.mts +3 -3
  60. package/dist/lib/version.d.ts +3 -3
  61. package/dist/lib/version.js +3 -3
  62. package/dist/lib/version.mjs +3 -3
  63. package/docs/TYPE-SUMMARY.md +2 -2
  64. package/docs/guides/COLLECTION-FIXTURE-FOUNDATION.md +11 -0
  65. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +12 -1
  66. package/docs/llms.txt +2 -2
  67. package/docs/migration-14.x-rc-worksheet.md +4 -4
  68. package/docs/migration-16-to-17.md +24 -1
  69. package/docs/migration-reporting-storage-package.md +1 -1
  70. package/package.json +1 -1
@@ -25,7 +25,7 @@ function injectLegacyEnvelopeStatus(response, options) {
25
25
  return response;
26
26
  }
27
27
  if (options?.toolName && STATUS_FREE_SYNC_RESPONSE_TOOLS.has(options.toolName)) return response;
28
- if (options?.toolName && MEDIA_BUY_STATUS_RESPONSE_TOOLS.has(options.toolName) && allowsDeprecatedMediaBuyStatus(response) && isMediaBuySuccessStatusForCompat(response)) {
28
+ if (options?.toolName && MEDIA_BUY_STATUS_RESPONSE_TOOLS.has(options.toolName) && allowsDeprecatedMediaBuyStatus(response) && isMediaBuySuccessStatusForCompat(response, options)) {
29
29
  const mediaBuyStatus = response.status;
30
30
  return {
31
31
  ...response,
@@ -50,16 +50,16 @@ function normalizeLegacyMediaBuyStatusForReturn(response, options) {
50
50
  if (!response || typeof response !== "object" || Array.isArray(response)) {
51
51
  return response;
52
52
  }
53
- if (!options?.toolName || !MEDIA_BUY_STATUS_RESPONSE_TOOLS.has(options.toolName) || !allowsDeprecatedMediaBuyStatus(response) || !isMediaBuySuccessStatusForCompat(response)) {
53
+ if (!options?.toolName || !MEDIA_BUY_STATUS_RESPONSE_TOOLS.has(options.toolName) || !allowsDeprecatedMediaBuyStatus(response) || !isMediaBuySuccessStatusForCompat(response, options)) {
54
54
  return response;
55
55
  }
56
- const status = getAuthoritativeMediaBuyStatus(response);
56
+ const status = getAuthoritativeMediaBuyStatus(withRequestedVersion(response, options));
57
57
  if (!status || response.media_buy_status === status) return response;
58
58
  return { ...response, media_buy_status: status };
59
59
  }
60
- function isMediaBuySuccessStatusForCompat(response) {
60
+ function isMediaBuySuccessStatusForCompat(response, options) {
61
61
  const status = response.status;
62
- if (getAuthoritativeMediaBuyStatus(response) !== status) return false;
62
+ if (getAuthoritativeMediaBuyStatus(withRequestedVersion(response, options)) !== status) return false;
63
63
  if (typeof response.media_buy_status === "string" && response.media_buy_status !== status) {
64
64
  return false;
65
65
  }
@@ -74,6 +74,12 @@ function allowsDeprecatedMediaBuyStatus(payload) {
74
74
  if (typeof major === "number") return major === 3;
75
75
  return true;
76
76
  }
77
+ function withRequestedVersion(payload, options) {
78
+ const requested = options?.adcpVersion;
79
+ if (typeof requested !== "string" || requested.length === 0) return payload;
80
+ if (typeof payload.adcp_version === "string" || typeof payload.adcp_major_version === "number") return payload;
81
+ return { ...payload, adcp_version: requested };
82
+ }
77
83
  export {
78
84
  STATUS_FREE_SYNC_RESPONSE_TOOLS,
79
85
  injectLegacyEnvelopeStatus,
@@ -218,9 +218,10 @@ function unwrapProtocolResponse(protocolResponse, toolName, protocol, options) {
218
218
  const schema = TOOL_RESPONSE_SCHEMAS[toolName];
219
219
  if (schema) {
220
220
  const { _message: _msg, ...stripped } = unwrapped;
221
+ const compatOptions = { toolName, adcpVersion: options?.responseAdcpVersion };
221
222
  const dataToValidate = prepareResponseForSchemaValidation(
222
223
  toolName,
223
- (0, import_envelope_status_compat.injectLegacyEnvelopeStatus)(stripped, { toolName }),
224
+ (0, import_envelope_status_compat.injectLegacyEnvelopeStatus)(stripped, compatOptions),
224
225
  options?.responseAdcpVersion
225
226
  );
226
227
  const result = schema.safeParse(dataToValidate);
@@ -233,7 +234,7 @@ function unwrapProtocolResponse(protocolResponse, toolName, protocol, options) {
233
234
  const { status: _s, ...rest } = validated2;
234
235
  validated2 = rest;
235
236
  } else {
236
- validated2 = restoreLegacyMediaBuyStatusForReturn(validated2, stripped, dataToValidate, toolName);
237
+ validated2 = restoreLegacyMediaBuyStatusForReturn(validated2, stripped, dataToValidate, compatOptions);
237
238
  }
238
239
  validated2 = restoreCompatibilityVersionForReturn(validated2, stripped, dataToValidate);
239
240
  if (!("adcp_version" in stripped)) {
@@ -260,7 +261,7 @@ function unwrapProtocolResponse(protocolResponse, toolName, protocol, options) {
260
261
  const { status: _s, ...rest } = validated;
261
262
  validated = rest;
262
263
  } else {
263
- validated = restoreLegacyMediaBuyStatusForReturn(validated, stripped, dataToValidate, toolName);
264
+ validated = restoreLegacyMediaBuyStatusForReturn(validated, stripped, dataToValidate, compatOptions);
264
265
  }
265
266
  validated = restoreCompatibilityVersionForReturn(validated, stripped, dataToValidate);
266
267
  if (!("adcp_version" in stripped)) {
@@ -279,16 +280,18 @@ function restoreCompatibilityVersionForReturn(validated, original, compat) {
279
280
  }
280
281
  return validated;
281
282
  }
282
- function restoreLegacyMediaBuyStatusForReturn(validated, original, compat, toolName) {
283
+ function restoreLegacyMediaBuyStatusForReturn(validated, original, compat, compatOptions) {
284
+ const { toolName } = compatOptions;
283
285
  if ((toolName === "create_media_buy" || toolName === "update_media_buy") && typeof original.media_buy_id === "string" && typeof original.status === "string" && compat.status === "completed" && typeof compat.media_buy_status === "string") {
284
286
  return (0, import_envelope_status_compat.normalizeLegacyMediaBuyStatusForReturn)(
285
287
  { ...validated, status: original.status },
286
- { toolName }
288
+ compatOptions
287
289
  );
288
290
  }
289
- return (0, import_envelope_status_compat.normalizeLegacyMediaBuyStatusForReturn)(validated, {
290
- toolName
291
- });
291
+ return (0, import_envelope_status_compat.normalizeLegacyMediaBuyStatusForReturn)(
292
+ validated,
293
+ compatOptions
294
+ );
292
295
  }
293
296
  function filterInvalidProducts(schema, data) {
294
297
  const { z } = require("zod");
@@ -499,7 +502,7 @@ function isAdcpSuccess(response, taskName, responseAdcpVersion) {
499
502
  const { _message: _, ...stripped } = response ?? {};
500
503
  const dataToValidate = prepareResponseForSchemaValidation(
501
504
  taskName,
502
- (0, import_envelope_status_compat.injectLegacyEnvelopeStatus)(stripped, { toolName: taskName }),
505
+ (0, import_envelope_status_compat.injectLegacyEnvelopeStatus)(stripped, { toolName: taskName, adcpVersion: responseAdcpVersion }),
503
506
  responseAdcpVersion
504
507
  );
505
508
  const result = schema.safeParse(dataToValidate);
@@ -192,9 +192,10 @@ function unwrapProtocolResponse(protocolResponse, toolName, protocol, options) {
192
192
  const schema = TOOL_RESPONSE_SCHEMAS[toolName];
193
193
  if (schema) {
194
194
  const { _message: _msg, ...stripped } = unwrapped;
195
+ const compatOptions = { toolName, adcpVersion: options?.responseAdcpVersion };
195
196
  const dataToValidate = prepareResponseForSchemaValidation(
196
197
  toolName,
197
- injectLegacyEnvelopeStatus(stripped, { toolName }),
198
+ injectLegacyEnvelopeStatus(stripped, compatOptions),
198
199
  options?.responseAdcpVersion
199
200
  );
200
201
  const result = schema.safeParse(dataToValidate);
@@ -207,7 +208,7 @@ function unwrapProtocolResponse(protocolResponse, toolName, protocol, options) {
207
208
  const { status: _s, ...rest } = validated2;
208
209
  validated2 = rest;
209
210
  } else {
210
- validated2 = restoreLegacyMediaBuyStatusForReturn(validated2, stripped, dataToValidate, toolName);
211
+ validated2 = restoreLegacyMediaBuyStatusForReturn(validated2, stripped, dataToValidate, compatOptions);
211
212
  }
212
213
  validated2 = restoreCompatibilityVersionForReturn(validated2, stripped, dataToValidate);
213
214
  if (!("adcp_version" in stripped)) {
@@ -234,7 +235,7 @@ function unwrapProtocolResponse(protocolResponse, toolName, protocol, options) {
234
235
  const { status: _s, ...rest } = validated;
235
236
  validated = rest;
236
237
  } else {
237
- validated = restoreLegacyMediaBuyStatusForReturn(validated, stripped, dataToValidate, toolName);
238
+ validated = restoreLegacyMediaBuyStatusForReturn(validated, stripped, dataToValidate, compatOptions);
238
239
  }
239
240
  validated = restoreCompatibilityVersionForReturn(validated, stripped, dataToValidate);
240
241
  if (!("adcp_version" in stripped)) {
@@ -253,16 +254,18 @@ function restoreCompatibilityVersionForReturn(validated, original, compat) {
253
254
  }
254
255
  return validated;
255
256
  }
256
- function restoreLegacyMediaBuyStatusForReturn(validated, original, compat, toolName) {
257
+ function restoreLegacyMediaBuyStatusForReturn(validated, original, compat, compatOptions) {
258
+ const { toolName } = compatOptions;
257
259
  if ((toolName === "create_media_buy" || toolName === "update_media_buy") && typeof original.media_buy_id === "string" && typeof original.status === "string" && compat.status === "completed" && typeof compat.media_buy_status === "string") {
258
260
  return normalizeLegacyMediaBuyStatusForReturn(
259
261
  { ...validated, status: original.status },
260
- { toolName }
262
+ compatOptions
261
263
  );
262
264
  }
263
- return normalizeLegacyMediaBuyStatusForReturn(validated, {
264
- toolName
265
- });
265
+ return normalizeLegacyMediaBuyStatusForReturn(
266
+ validated,
267
+ compatOptions
268
+ );
266
269
  }
267
270
  function filterInvalidProducts(schema, data) {
268
271
  const { z } = require2("zod");
@@ -473,7 +476,7 @@ function isAdcpSuccess(response, taskName, responseAdcpVersion) {
473
476
  const { _message: _, ...stripped } = response ?? {};
474
477
  const dataToValidate = prepareResponseForSchemaValidation(
475
478
  taskName,
476
- injectLegacyEnvelopeStatus(stripped, { toolName: taskName }),
479
+ injectLegacyEnvelopeStatus(stripped, { toolName: taskName, adcpVersion: responseAdcpVersion }),
477
480
  responseAdcpVersion
478
481
  );
479
482
  const result = schema.safeParse(dataToValidate);
@@ -725,7 +725,6 @@ function projectInlineMarkupToLegacyHtml(assetsValue, definition, operation, cre
725
725
  {
726
726
  asset_type: "html",
727
727
  content: asset.markup,
728
- ...renderedSizeFields(asset),
729
728
  ...asset.provenance !== void 0 && { provenance: asset.provenance }
730
729
  }
731
730
  ];
@@ -787,15 +786,31 @@ function projectCreative(creative, formatId, legacyFormatDefinitions, operation
787
786
  }
788
787
  }
789
788
  if (Object.hasOwn(creative, "assets")) {
790
- next.assets = projectLegacyAssetKeys(
791
- projectInlineMarkupToLegacyHtml(
792
- creative.assets,
793
- markupDefinition,
794
- operation,
795
- typeof creative.creative_id === "string" ? creative.creative_id : "(unknown)"
796
- ),
797
- definition
789
+ const legacyAssets = projectInlineMarkupToLegacyHtml(
790
+ creative.assets,
791
+ markupDefinition,
792
+ operation,
793
+ typeof creative.creative_id === "string" ? creative.creative_id : "(unknown)"
798
794
  );
795
+ const refSize = legacyRefParameterConstraints(formatId);
796
+ const acceptsDimensions = Array.isArray(markupDefinition?.accepts_parameters) && markupDefinition.accepts_parameters.includes("dimensions");
797
+ const hasFixedRender = Array.isArray(markupDefinition?.renders) && markupDefinition.renders.some(
798
+ (render) => typeof render.dimensions?.width === "number" || typeof render.dimensions?.height === "number"
799
+ );
800
+ if (legacyAssets !== creative.assets && acceptsDimensions && !hasFixedRender && refSize.width === void 0 && refSize.height === void 0) {
801
+ const inlineAssets = Object.fromEntries(
802
+ Object.entries(record(creative.assets) ?? {}).filter(([, value]) => {
803
+ const asset = record(value);
804
+ return asset?.asset_type === "display_tag" && asset.delivery_type === "inline_markup";
805
+ })
806
+ );
807
+ const size = assetRenderedSize({ assets: inlineAssets });
808
+ const requested = creativeFormatParameterConstraints(creative);
809
+ if (typeof size?.width === "number" && typeof size.height === "number" && Number.isSafeInteger(size.width) && Number.isSafeInteger(size.height) && size.width > 0 && size.height > 0 && (requested?.width === void 0 || requested.width === size.width) && (requested?.height === void 0 || requested.height === size.height)) {
810
+ next.format_id = { ...formatId, width: size.width, height: size.height };
811
+ }
812
+ }
813
+ next.assets = projectLegacyAssetKeys(legacyAssets, definition);
799
814
  }
800
815
  return next;
801
816
  }
@@ -1130,14 +1145,44 @@ function projectCreativeForDelivery(creative, selectorContainer, wireMode = "can
1130
1145
  throw new CreativeFormatProjectionError(
1131
1146
  operation,
1132
1147
  creativeId,
1133
- `the seller advertised ${candidates.length} legacy refs for canonical kind ${creativeRecord.format_kind}`
1148
+ `the seller advertised ${candidates.length} legacy refs for canonical kind ${creativeRecord.format_kind}` + (candidates.some((candidate) => legacyIdPinsDimensions(candidate.ref) === true) ? "; set format_parameters.width/height or give the asset one rendered width/height to select one" : "")
1134
1149
  );
1135
1150
  }
1136
- const reason = pinned ? "the creative is pinned to a format option that names none of the selected seller product legacy format references" : "the selected seller product did not provide one unambiguous legacy format reference";
1151
+ const reason = pinned ? "the creative is pinned to a format option that names none of the selected seller product legacy format references" : describeUnmatchedLegacyCandidates(creativeRecord, allCandidates);
1137
1152
  throw new CreativeFormatProjectionError(operation, creativeId, reason);
1138
1153
  }
1139
1154
  return creative;
1140
1155
  }
1156
+ function describeUnmatchedLegacyCandidates(creative, allCandidates) {
1157
+ const generic = "the selected seller product did not provide one unambiguous legacy format reference";
1158
+ const kind = String(creative.format_kind);
1159
+ if (allCandidates.length === 0) return generic;
1160
+ const sameKind = allCandidates.filter((candidate) => candidate.formatKind === kind);
1161
+ if (sameKind.length === 0) {
1162
+ const offered = [
1163
+ ...new Set(allCandidates.flatMap((candidate) => candidate.formatKind ? [candidate.formatKind] : []))
1164
+ ];
1165
+ if (offered.length === 0) return generic;
1166
+ const htmlMarkupHint = kind === "html5" && offered.includes("display_tag") ? ". HTML-markup formats (display_html, display_WxH_html) take display_tag inline markup since SDK 17; send HTML snippets as a display_tag asset with delivery_type inline_markup (docs/migration-16-to-17.md)" : "";
1167
+ return `the selected seller product offers legacy refs for canonical kind ${offered.join(", ")}, not ${kind}${htmlMarkupHint}`;
1168
+ }
1169
+ const deliveryTypes = creativeDisplayTagDeliveryTypes(creative);
1170
+ if (deliveryTypes) {
1171
+ const accepting = sameKind.filter((candidate) => {
1172
+ const accepted = candidateDeliveryTypes(candidate);
1173
+ return [...deliveryTypes].every((type) => accepted.includes(type));
1174
+ });
1175
+ if (accepting.length === 0) {
1176
+ const accepted = [...new Set(sameKind.flatMap((candidate) => candidateDeliveryTypes(candidate).map(String)))];
1177
+ return `none of the seller's ${sameKind.length} ${kind} legacy refs accepts delivery_type ${[...deliveryTypes].join(", ")} (they accept ${accepted.join(", ")})`;
1178
+ }
1179
+ }
1180
+ const size = creativeFormatParameterConstraints(creative);
1181
+ if (size?.width !== void 0 && size.height !== void 0) {
1182
+ return `none of the seller's ${sameKind.length} ${kind} legacy refs matches the creative's ${size.width}x${size.height} size`;
1183
+ }
1184
+ return generic;
1185
+ }
1141
1186
  function projectMediaBuyCreativesForDelivery(request, wireMode = "canonical", operation = "create_media_buy", legacyFormatConverter, canonicalFormatLegacyResolver, legacyFormatDefinitions) {
1142
1187
  const requestRecord = record(request);
1143
1188
  if (!requestRecord) return request;
@@ -704,7 +704,6 @@ function projectInlineMarkupToLegacyHtml(assetsValue, definition, operation, cre
704
704
  {
705
705
  asset_type: "html",
706
706
  content: asset.markup,
707
- ...renderedSizeFields(asset),
708
707
  ...asset.provenance !== void 0 && { provenance: asset.provenance }
709
708
  }
710
709
  ];
@@ -766,15 +765,31 @@ function projectCreative(creative, formatId, legacyFormatDefinitions, operation
766
765
  }
767
766
  }
768
767
  if (Object.hasOwn(creative, "assets")) {
769
- next.assets = projectLegacyAssetKeys(
770
- projectInlineMarkupToLegacyHtml(
771
- creative.assets,
772
- markupDefinition,
773
- operation,
774
- typeof creative.creative_id === "string" ? creative.creative_id : "(unknown)"
775
- ),
776
- definition
768
+ const legacyAssets = projectInlineMarkupToLegacyHtml(
769
+ creative.assets,
770
+ markupDefinition,
771
+ operation,
772
+ typeof creative.creative_id === "string" ? creative.creative_id : "(unknown)"
777
773
  );
774
+ const refSize = legacyRefParameterConstraints(formatId);
775
+ const acceptsDimensions = Array.isArray(markupDefinition?.accepts_parameters) && markupDefinition.accepts_parameters.includes("dimensions");
776
+ const hasFixedRender = Array.isArray(markupDefinition?.renders) && markupDefinition.renders.some(
777
+ (render) => typeof render.dimensions?.width === "number" || typeof render.dimensions?.height === "number"
778
+ );
779
+ if (legacyAssets !== creative.assets && acceptsDimensions && !hasFixedRender && refSize.width === void 0 && refSize.height === void 0) {
780
+ const inlineAssets = Object.fromEntries(
781
+ Object.entries(record(creative.assets) ?? {}).filter(([, value]) => {
782
+ const asset = record(value);
783
+ return asset?.asset_type === "display_tag" && asset.delivery_type === "inline_markup";
784
+ })
785
+ );
786
+ const size = assetRenderedSize({ assets: inlineAssets });
787
+ const requested = creativeFormatParameterConstraints(creative);
788
+ if (typeof size?.width === "number" && typeof size.height === "number" && Number.isSafeInteger(size.width) && Number.isSafeInteger(size.height) && size.width > 0 && size.height > 0 && (requested?.width === void 0 || requested.width === size.width) && (requested?.height === void 0 || requested.height === size.height)) {
789
+ next.format_id = { ...formatId, width: size.width, height: size.height };
790
+ }
791
+ }
792
+ next.assets = projectLegacyAssetKeys(legacyAssets, definition);
778
793
  }
779
794
  return next;
780
795
  }
@@ -1109,14 +1124,44 @@ function projectCreativeForDelivery(creative, selectorContainer, wireMode = "can
1109
1124
  throw new CreativeFormatProjectionError(
1110
1125
  operation,
1111
1126
  creativeId,
1112
- `the seller advertised ${candidates.length} legacy refs for canonical kind ${creativeRecord.format_kind}`
1127
+ `the seller advertised ${candidates.length} legacy refs for canonical kind ${creativeRecord.format_kind}` + (candidates.some((candidate) => legacyIdPinsDimensions(candidate.ref) === true) ? "; set format_parameters.width/height or give the asset one rendered width/height to select one" : "")
1113
1128
  );
1114
1129
  }
1115
- const reason = pinned ? "the creative is pinned to a format option that names none of the selected seller product legacy format references" : "the selected seller product did not provide one unambiguous legacy format reference";
1130
+ const reason = pinned ? "the creative is pinned to a format option that names none of the selected seller product legacy format references" : describeUnmatchedLegacyCandidates(creativeRecord, allCandidates);
1116
1131
  throw new CreativeFormatProjectionError(operation, creativeId, reason);
1117
1132
  }
1118
1133
  return creative;
1119
1134
  }
1135
+ function describeUnmatchedLegacyCandidates(creative, allCandidates) {
1136
+ const generic = "the selected seller product did not provide one unambiguous legacy format reference";
1137
+ const kind = String(creative.format_kind);
1138
+ if (allCandidates.length === 0) return generic;
1139
+ const sameKind = allCandidates.filter((candidate) => candidate.formatKind === kind);
1140
+ if (sameKind.length === 0) {
1141
+ const offered = [
1142
+ ...new Set(allCandidates.flatMap((candidate) => candidate.formatKind ? [candidate.formatKind] : []))
1143
+ ];
1144
+ if (offered.length === 0) return generic;
1145
+ const htmlMarkupHint = kind === "html5" && offered.includes("display_tag") ? ". HTML-markup formats (display_html, display_WxH_html) take display_tag inline markup since SDK 17; send HTML snippets as a display_tag asset with delivery_type inline_markup (docs/migration-16-to-17.md)" : "";
1146
+ return `the selected seller product offers legacy refs for canonical kind ${offered.join(", ")}, not ${kind}${htmlMarkupHint}`;
1147
+ }
1148
+ const deliveryTypes = creativeDisplayTagDeliveryTypes(creative);
1149
+ if (deliveryTypes) {
1150
+ const accepting = sameKind.filter((candidate) => {
1151
+ const accepted = candidateDeliveryTypes(candidate);
1152
+ return [...deliveryTypes].every((type) => accepted.includes(type));
1153
+ });
1154
+ if (accepting.length === 0) {
1155
+ const accepted = [...new Set(sameKind.flatMap((candidate) => candidateDeliveryTypes(candidate).map(String)))];
1156
+ return `none of the seller's ${sameKind.length} ${kind} legacy refs accepts delivery_type ${[...deliveryTypes].join(", ")} (they accept ${accepted.join(", ")})`;
1157
+ }
1158
+ }
1159
+ const size = creativeFormatParameterConstraints(creative);
1160
+ if (size?.width !== void 0 && size.height !== void 0) {
1161
+ return `none of the seller's ${sameKind.length} ${kind} legacy refs matches the creative's ${size.width}x${size.height} size`;
1162
+ }
1163
+ return generic;
1164
+ }
1120
1165
  function projectMediaBuyCreativesForDelivery(request, wireMode = "canonical", operation = "create_media_buy", legacyFormatConverter, canonicalFormatLegacyResolver, legacyFormatDefinitions) {
1121
1166
  const requestRecord = record(request);
1122
1167
  if (!requestRecord) return request;
@@ -319,7 +319,7 @@ function selectResponseVariant(payload) {
319
319
  return "sync";
320
320
  }
321
321
  function validateResponse(toolName, payload, version) {
322
- const compatPayload = payload && typeof payload === "object" && !Array.isArray(payload) ? (0, import_envelope_status_compat.injectLegacyEnvelopeStatus)(payload, { toolName }) : payload;
322
+ const compatPayload = payload && typeof payload === "object" && !Array.isArray(payload) ? (0, import_envelope_status_compat.injectLegacyEnvelopeStatus)(payload, { toolName, adcpVersion: version }) : payload;
323
323
  const variant = selectResponseVariant(compatPayload);
324
324
  const validator = (0, import_schema_loader.getValidator)(toolName, variant, version);
325
325
  const effective = validator ?? (variant !== "sync" ? (0, import_schema_loader.getValidator)(toolName, "sync", version) : void 0);
@@ -292,7 +292,7 @@ function selectResponseVariant(payload) {
292
292
  return "sync";
293
293
  }
294
294
  function validateResponse(toolName, payload, version) {
295
- const compatPayload = payload && typeof payload === "object" && !Array.isArray(payload) ? injectLegacyEnvelopeStatus(payload, { toolName }) : payload;
295
+ const compatPayload = payload && typeof payload === "object" && !Array.isArray(payload) ? injectLegacyEnvelopeStatus(payload, { toolName, adcpVersion: version }) : payload;
296
296
  const variant = selectResponseVariant(compatPayload);
297
297
  const validator = getValidator(toolName, variant, version);
298
298
  const effective = validator ?? (variant !== "sync" ? getValidator(toolName, "sync", version) : void 0);
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "17.0.0-beta.0";
4
+ export declare const LIBRARY_VERSION = "17.0.0-beta.1";
5
5
  /**
6
6
  * AdCP specification version this library is built for
7
7
  */
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
33
33
  * Full version information
34
34
  */
35
35
  export declare const VERSION_INFO: {
36
- readonly library: "17.0.0-beta.0";
36
+ readonly library: "17.0.0-beta.1";
37
37
  readonly adcp: "3.3.0-beta.0";
38
38
  readonly compatibleVersions: readonly ["v3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.1.19", "3.1.20", "3.1.21", "3.1.22", "3.1.23", "3.1.24", "3.1.25", "3.1.26", "3.1.27", "3.1.28", "3.1.29", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4", "3.2.5", "3.2.6", "3.2.7", "3.3.0-beta.0", "3.3-beta.0"];
39
- readonly generatedAt: "2026-10-25T18:17:08.998Z";
39
+ readonly generatedAt: "2026-10-26T05:11:17.402Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "17.0.0-beta.0";
4
+ export declare const LIBRARY_VERSION = "17.0.0-beta.1";
5
5
  /**
6
6
  * AdCP specification version this library is built for
7
7
  */
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
33
33
  * Full version information
34
34
  */
35
35
  export declare const VERSION_INFO: {
36
- readonly library: "17.0.0-beta.0";
36
+ readonly library: "17.0.0-beta.1";
37
37
  readonly adcp: "3.3.0-beta.0";
38
38
  readonly compatibleVersions: readonly ["v3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.1.19", "3.1.20", "3.1.21", "3.1.22", "3.1.23", "3.1.24", "3.1.25", "3.1.26", "3.1.27", "3.1.28", "3.1.29", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4", "3.2.5", "3.2.6", "3.2.7", "3.3.0-beta.0", "3.3-beta.0"];
39
- readonly generatedAt: "2026-10-25T18:17:08.998Z";
39
+ readonly generatedAt: "2026-10-26T05:11:17.402Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for
@@ -31,7 +31,7 @@ __export(version_exports, {
31
31
  toReleasePrecisionVersion: () => toReleasePrecisionVersion
32
32
  });
33
33
  module.exports = __toCommonJS(version_exports);
34
- const LIBRARY_VERSION = "17.0.0-beta.0";
34
+ const LIBRARY_VERSION = "17.0.0-beta.1";
35
35
  const ADCP_VERSION = "3.3.0-beta.0";
36
36
  const ADCP_MAJOR_VERSION = 3;
37
37
  const COMPATIBLE_ADCP_VERSIONS = [
@@ -106,10 +106,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
106
106
  "3.3-beta.0"
107
107
  ];
108
108
  const VERSION_INFO = {
109
- library: "17.0.0-beta.0",
109
+ library: "17.0.0-beta.1",
110
110
  adcp: "3.3.0-beta.0",
111
111
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
112
- generatedAt: "2026-10-25T18:17:08.998Z"
112
+ generatedAt: "2026-10-26T05:11:17.402Z"
113
113
  };
114
114
  function getAdcpVersion() {
115
115
  return ADCP_VERSION;
@@ -1,4 +1,4 @@
1
- const LIBRARY_VERSION = "17.0.0-beta.0";
1
+ const LIBRARY_VERSION = "17.0.0-beta.1";
2
2
  const ADCP_VERSION = "3.3.0-beta.0";
3
3
  const ADCP_MAJOR_VERSION = 3;
4
4
  const COMPATIBLE_ADCP_VERSIONS = [
@@ -73,10 +73,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
73
73
  "3.3-beta.0"
74
74
  ];
75
75
  const VERSION_INFO = {
76
- library: "17.0.0-beta.0",
76
+ library: "17.0.0-beta.1",
77
77
  adcp: "3.3.0-beta.0",
78
78
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
79
- generatedAt: "2026-10-25T18:17:08.998Z"
79
+ generatedAt: "2026-10-26T05:11:17.402Z"
80
80
  };
81
81
  function getAdcpVersion() {
82
82
  return ADCP_VERSION;
@@ -1,7 +1,7 @@
1
1
  # AdCP Type Summary
2
2
 
3
- > Generated at: 2026-10-25
4
- > @adcp/sdk v17.0.0-beta.0
3
+ > Generated at: 2026-10-26
4
+ > @adcp/sdk v17.0.0-beta.1
5
5
 
6
6
  Curated reference of the types that matter for using the AdCP client. For full generated types see `src/lib/types/tools.generated.ts` and `src/lib/types/core.generated.ts`.
7
7
 
@@ -562,6 +562,17 @@ guarantees:
562
562
  retain their host-owned identity. A drift refusal after contact cannot undo
563
563
  earlier calls; their evidence goes only to the private audit sink.
564
564
 
565
+ After authorization and capability discovery, preparation evaluates the same
566
+ root `requires_capability`, `requires_all_capabilities`, `required_any_of_tools`,
567
+ and `required_tools` applicability gates as execution. `required_tools` accepts
568
+ any listed tool; every `required_any_of_tools` family must have a match.
569
+ Routed preparation unions advertised tools across routes. Root capability
570
+ predicates belong to `default_agent` when set; otherwise each selected step
571
+ route is evaluated separately, and preparation skips only when all decline.
572
+ Unmet gates return `status: 'unsupported', reason: 'not_applicable'` with a
573
+ discovery phase before any catalog read or controller seeding. Hosts can pass
574
+ the preparation authorizer directly without doing their own discovery first.
575
+
565
576
  The existing `PreparedFixturesLookup.binding` stays required and its gate
566
577
  union stays `run | pass | step`. Existing reuse authorizers need no migration.
567
578
  A host can explicitly share one implementation between the two options:
@@ -115,7 +115,18 @@ const client = new AgentClient(seller, {
115
115
 
116
116
  The partition is local configuration. It is hashed into MCP connection, discovery, and signing-policy cache keys and never sent in headers or tool arguments. Keep it stable for the same authorization scope, and use distinct values for different principals even when they share a seller token. Partitions also separate sessions within a single `withMCPConnectionScope` workflow.
117
117
 
118
- Outside a connection scope, calls now open and close their own MCP sessions by default. To retain process-wide reuse, provide a nonempty `connectionPartition`, or set `transport: { connectionReuse: 'process' }` when every caller with the same credentials and routing headers represents one principal. A supplied `trustedFetchFn` continues to use one-shot sessions outside an explicit scope, including with a partition or process opt-in.
118
+ Outside a connection scope, calls now open and close their own MCP sessions by default. To retain process-wide reuse, provide a nonempty `connectionPartition`, or set `transport: { connectionReuse: 'process' }` when every caller with the same credentials and routing headers represents one principal. Low-level calls with a supplied `trustedFetchFn` continue to use one-shot sessions outside a scope, including with a partition or process opt-in.
119
+
120
+ High-level `SingleAgentClient` task and discovery methods create a scope for
121
+ one operation when the caller has not configured reuse. Endpoint discovery,
122
+ `tools/list`, capability preflight, and dispatch share that operation's sessions,
123
+ which close when it finishes. Caller-owned scopes and explicit process reuse
124
+ keep their existing lifetimes. A supplied `trustedFetchFn` shares sessions
125
+ within this operation scope, including when a principal partition is set;
126
+ it never enables process-wide session reuse. A cold legacy endpoint still needs one v2 era
127
+ classification handshake and one v1 Tasks-capable session; the credential- and
128
+ policy-scoped classification is cached for five minutes, so later operations
129
+ can go straight to their v1 session. Different credentials remain isolated.
119
130
 
120
131
  Successful calls and ordinary errors terminate one-shot sessions. When a call throws because it was cancelled or timed out, the SDK closes its client without sending DELETE, so it does not terminate work still running on the seller; remaining server session state follows the seller's TTL.
121
132
 
package/docs/llms.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  # Ad Context Protocol (AdCP)
2
2
 
3
- > Generated at: 2026-10-25
4
- > Library: @adcp/sdk v17.0.0-beta.0
3
+ > Generated at: 2026-10-26
4
+ > Library: @adcp/sdk v17.0.0-beta.1
5
5
  > AdCP major version: 3
6
6
  > Canonical URL: https://adcontextprotocol.github.io/adcp-client/llms.txt
7
7
  > Note: the `Library` stamp reflects the package.json version at doc-generation time. The narrative below describes the surface that lands on the next-published minor — including any 6.7 helpers documented here ahead of the release tag.
@@ -16,8 +16,8 @@ pin using `ADCP_VERSION` inside that tarball.
16
16
 
17
17
  | Fact | Value |
18
18
  | --- | --- |
19
- | Checkout `package.json` version | `@adcp/sdk@17.0.0-beta.0` |
20
- | npm integrity | registry-derived after publication; run `npm view @adcp/sdk@17.0.0-beta.0 dist.integrity` |
19
+ | Checkout `package.json` version | `@adcp/sdk@17.0.0-beta.1` |
20
+ | npm integrity | registry-derived after publication; run `npm view @adcp/sdk@17.0.0-beta.1 dist.integrity` |
21
21
  | Node.js runtime | `^20.19.0 || >=22.12.0` |
22
22
  | Default AdCP wire release | `3.3.0-beta.0` |
23
23
  | Maintained wire releases | `v3`, `3.0.0`, `3.0`, `3.0.1`, `3.0.2`, `3.0.3`, `3.0.4`, `3.0.5`, `3.0.6`, `3.0.7`, `3.0.8`, `3.0.9`, `3.0.10`, `3.0.11`, `3.0.12`, `3.0.13`, `3.0.14`, `3.0.15`, `3.0.16`, `3.0.17`, `3.0.18`, `3.0.19`, `3.0.20`, `3.0.21`, `3.0.22`, `3.0.23`, `3.0.24`, `3.0.25`, `3.1.0`, `3.1`, `3.1.1`, `3.1.2`, `3.1.3`, `3.1.4`, `3.1.5`, `3.1.6`, `3.1.7`, `3.1.8`, `3.1.9`, `3.1.10`, `3.1.11`, `3.1.12`, `3.1.13`, `3.1.14`, `3.1.15`, `3.1.16`, `3.1.17`, `3.1.18`, `3.1.19`, `3.1.20`, `3.1.21`, `3.1.22`, `3.1.23`, `3.1.24`, `3.1.25`, `3.1.26`, `3.1.27`, `3.1.28`, `3.1.29`, `3.2.1`, `3.2`, `3.2.2`, `3.2.3`, `3.2.4`, `3.2.5`, `3.2.6`, `3.2.7`, `3.3.0-beta.0`, `3.3-beta.0` |
@@ -26,8 +26,8 @@ pin using `ADCP_VERSION` inside that tarball.
26
26
  For a checkout at the published release commit, install the exact package version:
27
27
 
28
28
  ```bash
29
- npm install --save-exact '@adcp/sdk@17.0.0-beta.0'
30
- npm view '@adcp/sdk@17.0.0-beta.0' dist.integrity
29
+ npm install --save-exact '@adcp/sdk@17.0.0-beta.1'
30
+ npm view '@adcp/sdk@17.0.0-beta.1' dist.integrity
31
31
  ```
32
32
 
33
33
  ### Required and optional peers
@@ -3,6 +3,26 @@
3
3
  SDK 17 beta pins the signed AdCP `3.3.0-beta.0` release. Use the beta in
4
4
  development and staging; production remains on SDK 16 and AdCP 3.2.
5
5
 
6
+ ## Companion packages
7
+
8
+ `@adcp/reporting-storage` declares `@adcp/sdk` as a peer, so it ships a release
9
+ for each SDK line. Its stable releases accept only SDK 16: `0.1.x` takes
10
+ `^16.0.0` and `0.2.0` takes `^16.5.0`. Installing SDK 17 beta beside either one
11
+ makes npm report an invalid tree (`npm ls` prints
12
+ `invalid: "^16.0.0" from node_modules/@adcp/reporting-storage` for `0.1.x`) or
13
+ refuse with `ERESOLVE`. Install the
14
+ storage release from the same `beta` train:
15
+
16
+ ```bash
17
+ npm install --save-exact @adcp/sdk@17.0.0-beta.0 @adcp/reporting-storage@0.2.1-beta.0
18
+ ```
19
+
20
+ `0.2.1-beta.0` has the same storage code and SQL migrations as `0.2.0`; only its
21
+ `@adcp/sdk` peer range changes (`^17.0.0-beta.0`). A `~0.2.0` range does not match
22
+ the prerelease, so pin the exact version. If you are upgrading from SDK 16.4 or
23
+ earlier, read the [`0.2.0` notes](https://github.com/adcontextprotocol/adcp-client/blob/main/packages/reporting-storage/CHANGELOG.md#020)
24
+ for BigQuery sinks that omit `location`. No other storage change is required.
25
+
6
26
  ## Protocol and discovery
7
27
 
8
28
  The SDK packages the exact 3.3 beta schema and compliance bundle alongside
@@ -77,7 +97,10 @@ including when the local `assetType: 'html5'` hint selects an `_html` ID.
77
97
  Actual zip creatives remain `html5` and cannot match HTML-markup-only products.
78
98
 
79
99
  Legacy delivery preserves the seller's format URL and size and emits the markup
80
- bytes in `html_creative.content`. Tag URLs and inline markup select only legacy
100
+ bytes in `html_creative.content`. The rendered `width`, `height` and `sizes` are
101
+ AdCP 3.3 asset fields, so they are not copied onto the legacy `html` asset: the
102
+ selected `display_WxH_html` ref carries the size. Sellers on 3.3 get the
103
+ canonical `display_tag` with those fields. Tag URLs and inline markup select only legacy
81
104
  refs that accept their delivery type. A paired redirect or inline-markup creative
82
105
  cannot use a ref that accepts only tag URLs. Multi-size tag-URL declarations keep
83
106
  their seller-asserted refs rather than expanding into inline-markup HTML formats.
@@ -14,7 +14,7 @@ Why: storage keeps its own release cadence, as Auth.js, LangGraph and OpenTeleme
14
14
  npm install @adcp/sdk@^16.0.0 @adcp/reporting-storage@~0.1.0
15
15
  ```
16
16
 
17
- Pin the storage package with `~` (`"@adcp/reporting-storage": "~0.1.0"`; this stable range does not match the earlier `0.1.0-beta.0` prerelease): it is pre-1.0 and every export is experimental. The cloud SDKs are optional peers of the new package, not of `@adcp/sdk` any more, so keep `@aws-sdk/client-s3`, `@azure/storage-blob` and `@google-cloud/storage` in your own dependencies for the providers you use.
17
+ Pin the storage package with `~` (`"@adcp/reporting-storage": "~0.1.0"`; this stable range does not match the earlier `0.1.0-beta.0` prerelease): it is pre-1.0 and every export is experimental. Choose the storage release whose `@adcp/sdk` peer range covers your SDK: `~0.1.0` for SDK 16.0 to 16.4, `~0.2.0` for SDK 16.5 and later 16.x, and the exact `0.2.1-beta.0` for SDK 17 beta (see the [16 to 17 migration guide](migration-16-to-17.md#companion-packages)). The cloud SDKs are optional peers of the new package, not of `@adcp/sdk` any more, so keep `@aws-sdk/client-s3`, `@azure/storage-blob` and `@google-cloud/storage` in your own dependencies for the providers you use.
18
18
 
19
19
  2. Change the imports using the table below, then run `tsc --noEmit`. A moved name on `@adcp/sdk/reporting/ledger` or `/service` is `TS2305: Module '"@adcp/sdk/reporting/ledger"' has no exported member 'PostgresReportingLedgerStore'`; a deleted subpath is `TS2307: Cannot find module '@adcp/sdk/reporting/gcs'`. At runtime the deleted subpaths fail with `ERR_PACKAGE_PATH_NOT_EXPORTED`, and a stale CommonJS `require` of a moved name on a kept subpath destructures to `undefined` and fails later as `X is not a constructor`, so grep JavaScript too (see [Self-grade](#self-grade)).
20
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adcp/sdk",
3
- "version": "17.0.0-beta.0",
3
+ "version": "17.0.0-beta.1",
4
4
  "description": "AdCP SDK — client, server, and compliance harnesses for the AdContext Protocol (MCP + A2A)",
5
5
  "workspaces": [
6
6
  ".",