@adcp/sdk 17.0.0-beta.5 → 17.0.0-beta.7

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 (49) hide show
  1. package/dist/lib/identity-3.3/validation.js +3 -1
  2. package/dist/lib/identity-3.3/validation.mjs +8 -2
  3. package/dist/lib/schemas/index.d.mts +2 -2
  4. package/dist/lib/schemas/index.d.ts +2 -2
  5. package/dist/lib/server/create-adcp-server.js +8 -2
  6. package/dist/lib/server/create-adcp-server.mjs +9 -3
  7. package/dist/lib/testing/storyboard/default-invariants.js +4 -0
  8. package/dist/lib/testing/storyboard/default-invariants.mjs +4 -0
  9. package/dist/lib/testing/storyboard/loader.js +31 -0
  10. package/dist/lib/testing/storyboard/loader.mjs +31 -0
  11. package/dist/lib/testing/storyboard/pricing-currency-filter.d.mts +13 -0
  12. package/dist/lib/testing/storyboard/pricing-currency-filter.d.ts +13 -0
  13. package/dist/lib/testing/storyboard/pricing-currency-filter.js +175 -0
  14. package/dist/lib/testing/storyboard/pricing-currency-filter.mjs +151 -0
  15. package/dist/lib/testing/storyboard/required-metric-filters.d.mts +9 -0
  16. package/dist/lib/testing/storyboard/required-metric-filters.d.ts +9 -0
  17. package/dist/lib/testing/storyboard/required-metric-filters.js +128 -0
  18. package/dist/lib/testing/storyboard/required-metric-filters.mjs +104 -0
  19. package/dist/lib/testing/storyboard/runner.js +244 -48
  20. package/dist/lib/testing/storyboard/runner.mjs +246 -49
  21. package/dist/lib/testing/storyboard/seeding.d.mts +86 -1
  22. package/dist/lib/testing/storyboard/seeding.d.ts +86 -1
  23. package/dist/lib/testing/storyboard/seeding.js +91 -18
  24. package/dist/lib/testing/storyboard/seeding.mjs +90 -18
  25. package/dist/lib/testing/storyboard/types.d.mts +30 -1
  26. package/dist/lib/testing/storyboard/types.d.ts +30 -1
  27. package/dist/lib/testing/storyboard/types.js +1 -0
  28. package/dist/lib/testing/storyboard/types.mjs +1 -0
  29. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  30. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  31. package/dist/lib/utils/envelope-status-compat.d.mts +21 -2
  32. package/dist/lib/utils/envelope-status-compat.d.ts +21 -2
  33. package/dist/lib/utils/envelope-status-compat.js +21 -6
  34. package/dist/lib/utils/envelope-status-compat.mjs +23 -4
  35. package/dist/lib/utils/response-schemas.js +4 -0
  36. package/dist/lib/utils/response-schemas.mjs +5 -1
  37. package/dist/lib/validation/schema-loader.d.mts +2 -2
  38. package/dist/lib/validation/schema-loader.d.ts +2 -2
  39. package/dist/lib/validation/schema-loader.js +72 -9
  40. package/dist/lib/validation/schema-loader.mjs +69 -8
  41. package/dist/lib/version.d.mts +3 -3
  42. package/dist/lib/version.d.ts +3 -3
  43. package/dist/lib/version.js +3 -3
  44. package/dist/lib/version.mjs +3 -3
  45. package/docs/TYPE-SUMMARY.md +2 -2
  46. package/docs/guides/WHOLESALE-PAGE-COLLECTION.md +67 -0
  47. package/docs/llms.txt +2 -2
  48. package/docs/migration-14.x-rc-worksheet.md +4 -4
  49. package/package.json +1 -1
@@ -18,20 +18,34 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var envelope_status_compat_exports = {};
20
20
  __export(envelope_status_compat_exports, {
21
- STATUS_FREE_SYNC_RESPONSE_TOOLS: () => STATUS_FREE_SYNC_RESPONSE_TOOLS,
21
+ COMPACT_SYNC_RESPONSE_TOOLS: () => COMPACT_SYNC_RESPONSE_TOOLS,
22
22
  injectLegacyEnvelopeStatus: () => injectLegacyEnvelopeStatus,
23
23
  isLegacy30xPayload: () => isLegacy30xPayload,
24
- normalizeLegacyMediaBuyStatusForReturn: () => normalizeLegacyMediaBuyStatusForReturn
24
+ normalizeLegacyMediaBuyStatusForReturn: () => normalizeLegacyMediaBuyStatusForReturn,
25
+ omitsEnvelopeStatusForRelease: () => omitsEnvelopeStatusForRelease
25
26
  });
26
27
  module.exports = __toCommonJS(envelope_status_compat_exports);
27
28
  var import_media_buy_status = require('./media-buy-status.js');
28
29
  const MEDIA_BUY_STATUS_RESPONSE_TOOLS = /* @__PURE__ */ new Set(["create_media_buy", "update_media_buy"]);
29
- const STATUS_FREE_SYNC_RESPONSE_TOOLS = /* @__PURE__ */ new Set([
30
+ const COMPACT_SYNC_RESPONSE_TOOLS = /* @__PURE__ */ new Set([
30
31
  "list_products",
31
32
  "decline_proposals",
32
33
  "list_collections",
33
34
  "list_proposals"
34
35
  ]);
36
+ const STATUS_FREE_BEFORE_ENVELOPE_TOOLS = /* @__PURE__ */ new Set(["list_products", "decline_proposals"]);
37
+ function omitsEnvelopeStatusForRelease(toolName, servedVersion) {
38
+ if (!STATUS_FREE_BEFORE_ENVELOPE_TOOLS.has(toolName) || servedVersion === void 0) return false;
39
+ const key = `${toolName}\0${servedVersion}`;
40
+ const cached = omitsStatusCache.get(key);
41
+ if (cached !== void 0) return cached;
42
+ const loader = require('../validation/schema-loader.js');
43
+ const omits = loader.responseSchemaComposesEnvelope(toolName, servedVersion) === false;
44
+ if (omitsStatusCache.size < 256 && !loader.isExternalSchemaRootActive(servedVersion))
45
+ omitsStatusCache.set(key, omits);
46
+ return omits;
47
+ }
48
+ const omitsStatusCache = /* @__PURE__ */ new Map();
35
49
  function isLegacy30xPayload(payload) {
36
50
  const adcpVersion = payload.adcp_version;
37
51
  if (typeof adcpVersion === "string") {
@@ -50,7 +64,7 @@ function injectLegacyEnvelopeStatus(response, options) {
50
64
  if (!response || typeof response !== "object" || Array.isArray(response)) {
51
65
  return response;
52
66
  }
53
- if (options?.toolName && STATUS_FREE_SYNC_RESPONSE_TOOLS.has(options.toolName)) return response;
67
+ if (options?.toolName && COMPACT_SYNC_RESPONSE_TOOLS.has(options.toolName)) return response;
54
68
  if (options?.toolName && MEDIA_BUY_STATUS_RESPONSE_TOOLS.has(options.toolName) && allowsDeprecatedMediaBuyStatus(response) && isMediaBuySuccessStatusForCompat(response, options)) {
55
69
  const mediaBuyStatus = response.status;
56
70
  return {
@@ -108,8 +122,9 @@ function withRequestedVersion(payload, options) {
108
122
  }
109
123
  // Annotate the CommonJS export names for ESM import in node:
110
124
  0 && (module.exports = {
111
- STATUS_FREE_SYNC_RESPONSE_TOOLS,
125
+ COMPACT_SYNC_RESPONSE_TOOLS,
112
126
  injectLegacyEnvelopeStatus,
113
127
  isLegacy30xPayload,
114
- normalizeLegacyMediaBuyStatusForReturn
128
+ normalizeLegacyMediaBuyStatusForReturn,
129
+ omitsEnvelopeStatusForRelease
115
130
  });
@@ -1,11 +1,29 @@
1
+ import { fileURLToPath as __adcpFileURLToPath } from "node:url";
2
+ import { dirname as __adcpDirname } from "node:path";
3
+ import { createRequire as __adcpCreateRequire } from "node:module";
4
+ const __dirname = __adcpDirname(__adcpFileURLToPath(import.meta.url));
5
+ const require2 = __adcpCreateRequire(import.meta.url);
1
6
  import { getAuthoritativeMediaBuyStatus } from "./media-buy-status.mjs";
2
7
  const MEDIA_BUY_STATUS_RESPONSE_TOOLS = /* @__PURE__ */ new Set(["create_media_buy", "update_media_buy"]);
3
- const STATUS_FREE_SYNC_RESPONSE_TOOLS = /* @__PURE__ */ new Set([
8
+ const COMPACT_SYNC_RESPONSE_TOOLS = /* @__PURE__ */ new Set([
4
9
  "list_products",
5
10
  "decline_proposals",
6
11
  "list_collections",
7
12
  "list_proposals"
8
13
  ]);
14
+ const STATUS_FREE_BEFORE_ENVELOPE_TOOLS = /* @__PURE__ */ new Set(["list_products", "decline_proposals"]);
15
+ function omitsEnvelopeStatusForRelease(toolName, servedVersion) {
16
+ if (!STATUS_FREE_BEFORE_ENVELOPE_TOOLS.has(toolName) || servedVersion === void 0) return false;
17
+ const key = `${toolName}\0${servedVersion}`;
18
+ const cached = omitsStatusCache.get(key);
19
+ if (cached !== void 0) return cached;
20
+ const loader = require2("../validation/schema-loader");
21
+ const omits = loader.responseSchemaComposesEnvelope(toolName, servedVersion) === false;
22
+ if (omitsStatusCache.size < 256 && !loader.isExternalSchemaRootActive(servedVersion))
23
+ omitsStatusCache.set(key, omits);
24
+ return omits;
25
+ }
26
+ const omitsStatusCache = /* @__PURE__ */ new Map();
9
27
  function isLegacy30xPayload(payload) {
10
28
  const adcpVersion = payload.adcp_version;
11
29
  if (typeof adcpVersion === "string") {
@@ -24,7 +42,7 @@ function injectLegacyEnvelopeStatus(response, options) {
24
42
  if (!response || typeof response !== "object" || Array.isArray(response)) {
25
43
  return response;
26
44
  }
27
- if (options?.toolName && STATUS_FREE_SYNC_RESPONSE_TOOLS.has(options.toolName)) return response;
45
+ if (options?.toolName && COMPACT_SYNC_RESPONSE_TOOLS.has(options.toolName)) return response;
28
46
  if (options?.toolName && MEDIA_BUY_STATUS_RESPONSE_TOOLS.has(options.toolName) && allowsDeprecatedMediaBuyStatus(response) && isMediaBuySuccessStatusForCompat(response, options)) {
29
47
  const mediaBuyStatus = response.status;
30
48
  return {
@@ -81,8 +99,9 @@ function withRequestedVersion(payload, options) {
81
99
  return { ...payload, adcp_version: requested };
82
100
  }
83
101
  export {
84
- STATUS_FREE_SYNC_RESPONSE_TOOLS,
102
+ COMPACT_SYNC_RESPONSE_TOOLS,
85
103
  injectLegacyEnvelopeStatus,
86
104
  isLegacy30xPayload,
87
- normalizeLegacyMediaBuyStatusForReturn
105
+ normalizeLegacyMediaBuyStatusForReturn,
106
+ omitsEnvelopeStatusForRelease
88
107
  };
@@ -36,6 +36,7 @@ var import_zod = require("zod");
36
36
  var schemas = __toESM(require('../types/schemas.generated.js'));
37
37
  var import_sync_creatives = require('../validation/sync-creatives.js');
38
38
  var import_adcp_version_config = require('./adcp-version-config.js');
39
+ var import_envelope_status_compat = require('./envelope-status-compat.js');
39
40
  var import_reporting_status_response = require('./reporting-status-response.js');
40
41
  var import_version = require('../version.js');
41
42
  var import_response_schema_cache = require('./response-schema-cache.js');
@@ -52,6 +53,9 @@ function prepareResponseForSchemaValidation(toolName, data, responseAdcpVersion)
52
53
  if (typeof response.adcp_version === "string" && /^3\.0\.\d+(?:-[A-Za-z0-9.-]+)?$/.test(response.adcp_version)) {
53
54
  return { ...response, adcp_version: (0, import_version.toReleasePrecisionVersion)(response.adcp_version) };
54
55
  }
56
+ if (response.status === void 0 && (0, import_envelope_status_compat.omitsEnvelopeStatusForRelease)(toolName, responseAdcpVersion) && !(0, import_envelope_status_compat.omitsEnvelopeStatusForRelease)(toolName, import_version.ADCP_VERSION)) {
57
+ return { ...response, status: "completed" };
58
+ }
55
59
  if (toolName !== "get_products") return data;
56
60
  if (!(0, import_adcp_version_config.isPre31AdcpVersion)(responseAdcpVersion)) return data;
57
61
  if (response.adcp_version !== void 0 || response.adcp_major_version !== void 0) return data;
@@ -2,8 +2,9 @@ import { z } from "zod";
2
2
  import * as schemas from "../types/schemas.generated.mjs";
3
3
  import { SyncCreativesResponseStrictSchema } from "../validation/sync-creatives.mjs";
4
4
  import { isPre31AdcpVersion } from "./adcp-version-config.mjs";
5
+ import { omitsEnvelopeStatusForRelease } from "./envelope-status-compat.mjs";
5
6
  import { GetReportingStatusResponseCurrentSchema } from "./reporting-status-response.mjs";
6
- import { toReleasePrecisionVersion } from "../version.mjs";
7
+ import { ADCP_VERSION, toReleasePrecisionVersion } from "../version.mjs";
7
8
  import { cacheResponseSchemas } from "./response-schema-cache.mjs";
8
9
  function declaresLegacy30xPayload(response) {
9
10
  const adcpVersion = response.adcp_version;
@@ -18,6 +19,9 @@ function prepareResponseForSchemaValidation(toolName, data, responseAdcpVersion)
18
19
  if (typeof response.adcp_version === "string" && /^3\.0\.\d+(?:-[A-Za-z0-9.-]+)?$/.test(response.adcp_version)) {
19
20
  return { ...response, adcp_version: toReleasePrecisionVersion(response.adcp_version) };
20
21
  }
22
+ if (response.status === void 0 && omitsEnvelopeStatusForRelease(toolName, responseAdcpVersion) && !omitsEnvelopeStatusForRelease(toolName, ADCP_VERSION)) {
23
+ return { ...response, status: "completed" };
24
+ }
21
25
  if (toolName !== "get_products") return data;
22
26
  if (!isPre31AdcpVersion(responseAdcpVersion)) return data;
23
27
  if (response.adcp_version !== void 0 || response.adcp_major_version !== void 0) return data;
@@ -120,7 +120,7 @@ export interface ResolvedSchemaDocument {
120
120
  /**
121
121
  * Return an unmodified tool JSON Schema from the same version-aware bundle
122
122
  * resolver used by runtime validation. Unlike `getValidator().schema`, response
123
- * documents are not relaxed for extensible envelopes, so callers can publish
123
+ * documents never receive envelope widening, so callers can publish
124
124
  * the protocol-authored schema verbatim from an on-demand discovery tool.
125
125
  */
126
126
  export declare function getToolSchemaDocument(toolName: string, direction: Direction, version?: string): ResolvedToolSchemaDocument | undefined;
@@ -141,7 +141,7 @@ export declare function getSchemaValidatorByRef(schemaRef: string, version?: str
141
141
  allErrors?: boolean;
142
142
  }): ValidateFunction | undefined;
143
143
  /**
144
- * Compile a tool schema without the response-root relaxation used by the SDK's
144
+ * Compile a tool schema without the per-release envelope widening used by the SDK's
145
145
  * live-wire validator. Kept in the loader so the public schema facade does not
146
146
  * need access to loader file-system state.
147
147
  */
@@ -120,7 +120,7 @@ export interface ResolvedSchemaDocument {
120
120
  /**
121
121
  * Return an unmodified tool JSON Schema from the same version-aware bundle
122
122
  * resolver used by runtime validation. Unlike `getValidator().schema`, response
123
- * documents are not relaxed for extensible envelopes, so callers can publish
123
+ * documents never receive envelope widening, so callers can publish
124
124
  * the protocol-authored schema verbatim from an on-demand discovery tool.
125
125
  */
126
126
  export declare function getToolSchemaDocument(toolName: string, direction: Direction, version?: string): ResolvedToolSchemaDocument | undefined;
@@ -141,7 +141,7 @@ export declare function getSchemaValidatorByRef(schemaRef: string, version?: str
141
141
  allErrors?: boolean;
142
142
  }): ValidateFunction | undefined;
143
143
  /**
144
- * Compile a tool schema without the response-root relaxation used by the SDK's
144
+ * Compile a tool schema without the per-release envelope widening used by the SDK's
145
145
  * live-wire validator. Kept in the loader so the public schema facade does not
146
146
  * need access to loader file-system state.
147
147
  */
@@ -30,6 +30,8 @@ var schema_loader_exports = {};
30
30
  __export(schema_loader_exports, {
31
31
  SCHEMA_FILENAME_SUFFIX: () => SCHEMA_FILENAME_SUFFIX,
32
32
  _resetValidationLoader: () => _resetValidationLoader,
33
+ acceptEnvelopeOnClosedResponseRoot: () => acceptEnvelopeOnClosedResponseRoot,
34
+ acceptEnvelopeOnClosedResponseRootForVersion: () => acceptEnvelopeOnClosedResponseRootForVersion,
33
35
  bindIdentity33SchemaScope: () => bindIdentity33SchemaScope,
34
36
  getActiveSchemaArtifactLocation: () => getActiveSchemaArtifactLocation,
35
37
  getCanonicalToolValidatorForVersion: () => getCanonicalToolValidatorForVersion,
@@ -51,11 +53,11 @@ __export(schema_loader_exports, {
51
53
  isIdentity33SchemaScope: () => isIdentity33SchemaScope,
52
54
  listValidatorKeys: () => listValidatorKeys,
53
55
  registerExternalSchemaRoot: () => registerExternalSchemaRoot,
54
- relaxResponseRoot: () => relaxResponseRoot,
55
56
  resolveBundleKey: () => resolveBundleKey,
56
57
  resolveSchemaRoot: () => resolveSchemaRoot,
57
58
  resolveServedValidationVersion: () => resolveServedValidationVersion,
58
59
  resolveValidatorDiagnosticPath: () => resolveValidatorDiagnosticPath,
60
+ responseSchemaComposesEnvelope: () => responseSchemaComposesEnvelope,
59
61
  schemaAllowsTopLevelField: () => schemaAllowsTopLevelField,
60
62
  toReleasePrecisionWire: () => toReleasePrecisionWire,
61
63
  unregisterExternalSchemaRoot: () => unregisterExternalSchemaRoot,
@@ -413,23 +415,82 @@ function loadJson(file) {
413
415
  }
414
416
  return JSON.parse((0, import_fs.readFileSync)(file, "utf-8"));
415
417
  }
416
- function relaxResponseRoot(schema) {
417
- const relaxCompositionNode = (node) => {
418
+ const ENVELOPE_FIELD_SCHEMAS = {
419
+ context_id: { type: "string" },
420
+ context: { type: "object" },
421
+ task_id: { type: "string" },
422
+ message: { type: "string" },
423
+ timestamp: { type: "string", format: "date-time" },
424
+ replayed: { type: "boolean" },
425
+ adcp_error: { type: "object" },
426
+ push_notification_config: { type: "object" },
427
+ governance_context: { type: "string" },
428
+ adcp_version: { type: "string" },
429
+ adcp_major_version: { type: "integer" }
430
+ };
431
+ const releaseEnvelopeFields = /* @__PURE__ */ new Map();
432
+ function envelopeFieldsForRelease(root) {
433
+ const cached = releaseEnvelopeFields.get(root);
434
+ if (cached) return cached;
435
+ const fields = /* @__PURE__ */ new Map();
436
+ const envelopeFile = import_path.default.join(root, "core", "protocol-envelope.json");
437
+ const declared = (0, import_fs.existsSync)(envelopeFile) ? Object.keys(loadJson(envelopeFile).properties ?? {}) : [...Object.keys(ENVELOPE_FIELD_SCHEMAS), "status"];
438
+ for (const name of /* @__PURE__ */ new Set([...declared, "adcp_version", "adcp_major_version"])) {
439
+ if (name === "payload") continue;
440
+ if (name === "status") {
441
+ const statusFile = import_path.default.join(root, "enums", "task-status.json");
442
+ const values = (0, import_fs.existsSync)(statusFile) ? loadJson(statusFile).enum : void 0;
443
+ fields.set("status", Array.isArray(values) ? { type: "string", enum: values } : { type: "string" });
444
+ } else if (ENVELOPE_FIELD_SCHEMAS[name]) {
445
+ fields.set(name, ENVELOPE_FIELD_SCHEMAS[name]);
446
+ }
447
+ }
448
+ const entry = { fields };
449
+ releaseEnvelopeFields.set(root, entry);
450
+ return entry;
451
+ }
452
+ function composesProtocolEnvelope(schema) {
453
+ const members = schema.allOf;
454
+ if (!Array.isArray(members)) return false;
455
+ return members.some((member) => {
456
+ if (!member || typeof member !== "object") return false;
457
+ const node = member;
458
+ return typeof node.$ref === "string" && node.$ref.endsWith("protocol-envelope.json") || typeof node.$id === "string" && node.$id.endsWith("protocol-envelope.json") || node.title === "Protocol Envelope";
459
+ });
460
+ }
461
+ function acceptEnvelopeOnClosedResponseRoot(schema, root) {
462
+ if (composesProtocolEnvelope(schema)) return schema;
463
+ const { fields } = envelopeFieldsForRelease(root);
464
+ const widen = (node) => {
418
465
  const clone = { ...node };
419
466
  if (clone.additionalProperties === false) {
420
- clone.additionalProperties = true;
467
+ const declared = clone.properties ?? {};
468
+ const missing = [...fields].filter(([name]) => !(name in declared));
469
+ if (missing.length > 0) clone.properties = { ...Object.fromEntries(missing), ...declared };
421
470
  }
422
471
  for (const key of ["oneOf", "anyOf", "allOf"]) {
423
472
  const branches = clone[key];
424
473
  if (Array.isArray(branches)) {
425
474
  clone[key] = branches.map(
426
- (branch) => branch && typeof branch === "object" ? relaxCompositionNode(branch) : branch
475
+ (branch) => branch && typeof branch === "object" ? widen(branch) : branch
427
476
  );
428
477
  }
429
478
  }
430
479
  return clone;
431
480
  };
432
- return relaxCompositionNode(schema);
481
+ return widen(schema);
482
+ }
483
+ function responseSchemaComposesEnvelope(toolName, version = import_version.ADCP_VERSION) {
484
+ let document;
485
+ try {
486
+ document = getToolSchemaDocument(toolName, "sync", version);
487
+ } catch {
488
+ return void 0;
489
+ }
490
+ return document ? composesProtocolEnvelope(document.schema) : void 0;
491
+ }
492
+ function acceptEnvelopeOnClosedResponseRootForVersion(schema, version = import_version.ADCP_VERSION) {
493
+ return acceptEnvelopeOnClosedResponseRoot(schema, ensureInit(version).root);
433
494
  }
434
495
  function getAjvRegisteredIds(ajv) {
435
496
  const internals = ajv;
@@ -545,7 +606,7 @@ function ensureCoreLoaded(s) {
545
606
  const selectedSchema = selectedShadowsModular ? loadJson(selected.file) : schema;
546
607
  const prepared = selectedShadowsModular && selected.file.includes(`${import_path.default.sep}bundled${import_path.default.sep}`) ? stripNestedIds(selectedSchema) : selectedSchema;
547
608
  const isResponseTool = selected?.response ?? responseToolFiles.has(file);
548
- const schemaToRegister = isResponseTool ? relaxResponseRoot(prepared) : prepared;
609
+ const schemaToRegister = isResponseTool ? acceptEnvelopeOnClosedResponseRoot(prepared, s.root) : prepared;
549
610
  if (typeof schemaToRegister.$id === "string" && !registeredIds.has(schemaToRegister.$id)) {
550
611
  s.ajv.addSchema(schemaToRegister);
551
612
  registeredIds.add(schemaToRegister.$id);
@@ -566,7 +627,7 @@ function getValidator(toolName, direction, version = import_version.ADCP_VERSION
566
627
  if (!fromBundled) ensureCoreLoaded(s);
567
628
  const rawSchema = loadJson(file);
568
629
  const prepared = fromBundled ? stripNestedIds(rawSchema) : rawSchema;
569
- const envelope = direction === "request" ? prepared : relaxResponseRoot(prepared);
630
+ const envelope = direction === "request" ? prepared : acceptEnvelopeOnClosedResponseRoot(prepared, s.root);
570
631
  const schema = fromBundled ? compactSchemaForValidation(envelope) : envelope;
571
632
  const ajv = fromBundled ? s.bundledAjv : s.ajv;
572
633
  const existing = typeof schema.$id === "string" ? ajv.getSchema(schema.$id) : void 0;
@@ -1193,6 +1254,8 @@ function cloneJsonValue(value) {
1193
1254
  0 && (module.exports = {
1194
1255
  SCHEMA_FILENAME_SUFFIX,
1195
1256
  _resetValidationLoader,
1257
+ acceptEnvelopeOnClosedResponseRoot,
1258
+ acceptEnvelopeOnClosedResponseRootForVersion,
1196
1259
  bindIdentity33SchemaScope,
1197
1260
  getActiveSchemaArtifactLocation,
1198
1261
  getCanonicalToolValidatorForVersion,
@@ -1214,11 +1277,11 @@ function cloneJsonValue(value) {
1214
1277
  isIdentity33SchemaScope,
1215
1278
  listValidatorKeys,
1216
1279
  registerExternalSchemaRoot,
1217
- relaxResponseRoot,
1218
1280
  resolveBundleKey,
1219
1281
  resolveSchemaRoot,
1220
1282
  resolveServedValidationVersion,
1221
1283
  resolveValidatorDiagnosticPath,
1284
+ responseSchemaComposesEnvelope,
1222
1285
  schemaAllowsTopLevelField,
1223
1286
  toReleasePrecisionWire,
1224
1287
  unregisterExternalSchemaRoot,
@@ -355,23 +355,82 @@ function loadJson(file) {
355
355
  }
356
356
  return JSON.parse(readFileSync(file, "utf-8"));
357
357
  }
358
- function relaxResponseRoot(schema) {
359
- const relaxCompositionNode = (node) => {
358
+ const ENVELOPE_FIELD_SCHEMAS = {
359
+ context_id: { type: "string" },
360
+ context: { type: "object" },
361
+ task_id: { type: "string" },
362
+ message: { type: "string" },
363
+ timestamp: { type: "string", format: "date-time" },
364
+ replayed: { type: "boolean" },
365
+ adcp_error: { type: "object" },
366
+ push_notification_config: { type: "object" },
367
+ governance_context: { type: "string" },
368
+ adcp_version: { type: "string" },
369
+ adcp_major_version: { type: "integer" }
370
+ };
371
+ const releaseEnvelopeFields = /* @__PURE__ */ new Map();
372
+ function envelopeFieldsForRelease(root) {
373
+ const cached = releaseEnvelopeFields.get(root);
374
+ if (cached) return cached;
375
+ const fields = /* @__PURE__ */ new Map();
376
+ const envelopeFile = path.join(root, "core", "protocol-envelope.json");
377
+ const declared = existsSync(envelopeFile) ? Object.keys(loadJson(envelopeFile).properties ?? {}) : [...Object.keys(ENVELOPE_FIELD_SCHEMAS), "status"];
378
+ for (const name of /* @__PURE__ */ new Set([...declared, "adcp_version", "adcp_major_version"])) {
379
+ if (name === "payload") continue;
380
+ if (name === "status") {
381
+ const statusFile = path.join(root, "enums", "task-status.json");
382
+ const values = existsSync(statusFile) ? loadJson(statusFile).enum : void 0;
383
+ fields.set("status", Array.isArray(values) ? { type: "string", enum: values } : { type: "string" });
384
+ } else if (ENVELOPE_FIELD_SCHEMAS[name]) {
385
+ fields.set(name, ENVELOPE_FIELD_SCHEMAS[name]);
386
+ }
387
+ }
388
+ const entry = { fields };
389
+ releaseEnvelopeFields.set(root, entry);
390
+ return entry;
391
+ }
392
+ function composesProtocolEnvelope(schema) {
393
+ const members = schema.allOf;
394
+ if (!Array.isArray(members)) return false;
395
+ return members.some((member) => {
396
+ if (!member || typeof member !== "object") return false;
397
+ const node = member;
398
+ return typeof node.$ref === "string" && node.$ref.endsWith("protocol-envelope.json") || typeof node.$id === "string" && node.$id.endsWith("protocol-envelope.json") || node.title === "Protocol Envelope";
399
+ });
400
+ }
401
+ function acceptEnvelopeOnClosedResponseRoot(schema, root) {
402
+ if (composesProtocolEnvelope(schema)) return schema;
403
+ const { fields } = envelopeFieldsForRelease(root);
404
+ const widen = (node) => {
360
405
  const clone = { ...node };
361
406
  if (clone.additionalProperties === false) {
362
- clone.additionalProperties = true;
407
+ const declared = clone.properties ?? {};
408
+ const missing = [...fields].filter(([name]) => !(name in declared));
409
+ if (missing.length > 0) clone.properties = { ...Object.fromEntries(missing), ...declared };
363
410
  }
364
411
  for (const key of ["oneOf", "anyOf", "allOf"]) {
365
412
  const branches = clone[key];
366
413
  if (Array.isArray(branches)) {
367
414
  clone[key] = branches.map(
368
- (branch) => branch && typeof branch === "object" ? relaxCompositionNode(branch) : branch
415
+ (branch) => branch && typeof branch === "object" ? widen(branch) : branch
369
416
  );
370
417
  }
371
418
  }
372
419
  return clone;
373
420
  };
374
- return relaxCompositionNode(schema);
421
+ return widen(schema);
422
+ }
423
+ function responseSchemaComposesEnvelope(toolName, version = ADCP_VERSION) {
424
+ let document;
425
+ try {
426
+ document = getToolSchemaDocument(toolName, "sync", version);
427
+ } catch {
428
+ return void 0;
429
+ }
430
+ return document ? composesProtocolEnvelope(document.schema) : void 0;
431
+ }
432
+ function acceptEnvelopeOnClosedResponseRootForVersion(schema, version = ADCP_VERSION) {
433
+ return acceptEnvelopeOnClosedResponseRoot(schema, ensureInit(version).root);
375
434
  }
376
435
  function getAjvRegisteredIds(ajv) {
377
436
  const internals = ajv;
@@ -487,7 +546,7 @@ function ensureCoreLoaded(s) {
487
546
  const selectedSchema = selectedShadowsModular ? loadJson(selected.file) : schema;
488
547
  const prepared = selectedShadowsModular && selected.file.includes(`${path.sep}bundled${path.sep}`) ? stripNestedIds(selectedSchema) : selectedSchema;
489
548
  const isResponseTool = selected?.response ?? responseToolFiles.has(file);
490
- const schemaToRegister = isResponseTool ? relaxResponseRoot(prepared) : prepared;
549
+ const schemaToRegister = isResponseTool ? acceptEnvelopeOnClosedResponseRoot(prepared, s.root) : prepared;
491
550
  if (typeof schemaToRegister.$id === "string" && !registeredIds.has(schemaToRegister.$id)) {
492
551
  s.ajv.addSchema(schemaToRegister);
493
552
  registeredIds.add(schemaToRegister.$id);
@@ -508,7 +567,7 @@ function getValidator(toolName, direction, version = ADCP_VERSION) {
508
567
  if (!fromBundled) ensureCoreLoaded(s);
509
568
  const rawSchema = loadJson(file);
510
569
  const prepared = fromBundled ? stripNestedIds(rawSchema) : rawSchema;
511
- const envelope = direction === "request" ? prepared : relaxResponseRoot(prepared);
570
+ const envelope = direction === "request" ? prepared : acceptEnvelopeOnClosedResponseRoot(prepared, s.root);
512
571
  const schema = fromBundled ? compactSchemaForValidation(envelope) : envelope;
513
572
  const ajv = fromBundled ? s.bundledAjv : s.ajv;
514
573
  const existing = typeof schema.$id === "string" ? ajv.getSchema(schema.$id) : void 0;
@@ -1134,6 +1193,8 @@ function cloneJsonValue(value) {
1134
1193
  export {
1135
1194
  SCHEMA_FILENAME_SUFFIX,
1136
1195
  _resetValidationLoader,
1196
+ acceptEnvelopeOnClosedResponseRoot,
1197
+ acceptEnvelopeOnClosedResponseRootForVersion,
1137
1198
  bindIdentity33SchemaScope,
1138
1199
  getActiveSchemaArtifactLocation,
1139
1200
  getCanonicalToolValidatorForVersion,
@@ -1155,11 +1216,11 @@ export {
1155
1216
  isIdentity33SchemaScope,
1156
1217
  listValidatorKeys,
1157
1218
  registerExternalSchemaRoot,
1158
- relaxResponseRoot,
1159
1219
  resolveBundleKey,
1160
1220
  resolveSchemaRoot,
1161
1221
  resolveServedValidationVersion,
1162
1222
  resolveValidatorDiagnosticPath,
1223
+ responseSchemaComposesEnvelope,
1163
1224
  schemaAllowsTopLevelField,
1164
1225
  toReleasePrecisionWire,
1165
1226
  unregisterExternalSchemaRoot,
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "17.0.0-beta.5";
4
+ export declare const LIBRARY_VERSION = "17.0.0-beta.7";
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.5";
36
+ readonly library: "17.0.0-beta.7";
37
37
  readonly adcp: "3.3.0-beta.1";
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.1", "3.3-beta.1"];
39
- readonly generatedAt: "2026-10-29T08:17:27.332Z";
39
+ readonly generatedAt: "2026-10-30T02:12:55.702Z";
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.5";
4
+ export declare const LIBRARY_VERSION = "17.0.0-beta.7";
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.5";
36
+ readonly library: "17.0.0-beta.7";
37
37
  readonly adcp: "3.3.0-beta.1";
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.1", "3.3-beta.1"];
39
- readonly generatedAt: "2026-10-29T08:17:27.332Z";
39
+ readonly generatedAt: "2026-10-30T02:12:55.702Z";
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.5";
34
+ const LIBRARY_VERSION = "17.0.0-beta.7";
35
35
  const ADCP_VERSION = "3.3.0-beta.1";
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.1"
107
107
  ];
108
108
  const VERSION_INFO = {
109
- library: "17.0.0-beta.5",
109
+ library: "17.0.0-beta.7",
110
110
  adcp: "3.3.0-beta.1",
111
111
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
112
- generatedAt: "2026-10-29T08:17:27.332Z"
112
+ generatedAt: "2026-10-30T02:12:55.702Z"
113
113
  };
114
114
  function getAdcpVersion() {
115
115
  return ADCP_VERSION;
@@ -1,4 +1,4 @@
1
- const LIBRARY_VERSION = "17.0.0-beta.5";
1
+ const LIBRARY_VERSION = "17.0.0-beta.7";
2
2
  const ADCP_VERSION = "3.3.0-beta.1";
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.1"
74
74
  ];
75
75
  const VERSION_INFO = {
76
- library: "17.0.0-beta.5",
76
+ library: "17.0.0-beta.7",
77
77
  adcp: "3.3.0-beta.1",
78
78
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
79
- generatedAt: "2026-10-29T08:17:27.332Z"
79
+ generatedAt: "2026-10-30T02:12:55.702Z"
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-29
4
- > @adcp/sdk v17.0.0-beta.5
3
+ > Generated at: 2026-10-30
4
+ > @adcp/sdk v17.0.0-beta.7
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
 
@@ -0,0 +1,67 @@
1
+ # Collecting a wholesale product feed in a storyboard
2
+
3
+ Set `collect_product_pages: true` on a `get_products` wholesale step when its
4
+ checks need products beyond the seller's first page. Ordinary steps continue to
5
+ make one request. Declare the intrinsic runtime requirement so an older runner
6
+ reports missing coverage before fixture setup instead of ignoring the new flag:
7
+
8
+ ```yaml
9
+ requires: [collect_product_pages_runner]
10
+ phases:
11
+ - id: discovery
12
+ steps:
13
+ - id: complete_catalog
14
+ task: get_products
15
+ collect_product_pages: true
16
+ sample_request:
17
+ buying_mode: wholesale
18
+ pagination: { max_results: 25 }
19
+ account: { account_id: seller-issued-account }
20
+ validations:
21
+ - check: field_contains
22
+ path: products[*].product_id
23
+ value: expected-product
24
+ ```
25
+
26
+ The first request is unconditional and must omit a continuation cursor. The
27
+ runner preserves account, filters, fields, context, extensions,
28
+ and the authored page size on each continuation. It follows every cursor,
29
+ validates every response, rejects duplicate identities and broken cursors, and
30
+ restarts when the feed identity changes. It permits at most three restarts,
31
+ 1,000 physical requests, 100,000 products, and 100,000 advisory errors. Exhausting a budget fails the
32
+ logical read and never publishes a successful partial snapshot.
33
+
34
+ Collection requires fresh reads without `idempotency_key`. An authored key or
35
+ runtime-injected key is rejected before dispatch; the runner never silently
36
+ rewrites or removes a key. Each cursor page and restarted read has a different
37
+ request body, so reusing a key could conflict with a seller's optional read
38
+ replay protection. The SDK does not automatically add a key to these wholesale
39
+ reads. Ordinary one-page steps keep their existing key behavior.
40
+
41
+ Per-page validation still requires the response schema's required Product
42
+ fields. Forwarding `fields` does not relax schema validation for projections.
43
+
44
+ Authored field checks and context captures use
45
+ `product_page_collection.logical_response`. Its products and advisory errors
46
+ combine all pages of the final stable enumeration, including pages beyond the
47
+ response-retention limit. A restart discards their abandoned counterparts. Other
48
+ envelope fields are representative metadata from the first stable page; this
49
+ feature does not merge arbitrary response fields or extension definitions. The ordinary `response` and
50
+ `response_record` retain an actual physical page; they never masquerade as a
51
+ merged seller response. Each page has its own request, response, extraction,
52
+ schema disposition, and restart number under `product_page_collection.pages`.
53
+ Logical-check pointers are prefixed with
54
+ `/product_page_collection/logical_response`. Physical schema and invariant
55
+ failures cite the actual page exchange instead.
56
+
57
+ Every physical page runs the step's enabled invariants before response-evidence
58
+ retention limits apply, including pages later abandoned during a restart. The
59
+ report retains the first 16 page responses and every request. Later responses
60
+ carry an explicit retention marker; failing checks still retain their actual
61
+ page evidence. Unknown or custom pricing remains visibly unproven under its
62
+ existing invariant contract.
63
+
64
+ Expected-error probes, raw authentication probes, parallel dispatch, conditional
65
+ feed reads, and response-derived skip gates cannot be combined with collection.
66
+ Credentialed functional steps through the official protocol client remain
67
+ supported. `runStoryboardStep` exposes the same complete view and page checks.
package/docs/llms.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  # Ad Context Protocol (AdCP)
2
2
 
3
- > Generated at: 2026-10-29
4
- > Library: @adcp/sdk v17.0.0-beta.5
3
+ > Generated at: 2026-10-30
4
+ > Library: @adcp/sdk v17.0.0-beta.7
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.