@adcp/sdk 17.0.0-beta.6 → 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 (33) hide show
  1. package/dist/lib/testing/storyboard/default-invariants.js +4 -0
  2. package/dist/lib/testing/storyboard/default-invariants.mjs +4 -0
  3. package/dist/lib/testing/storyboard/loader.js +31 -0
  4. package/dist/lib/testing/storyboard/loader.mjs +31 -0
  5. package/dist/lib/testing/storyboard/pricing-currency-filter.d.mts +13 -0
  6. package/dist/lib/testing/storyboard/pricing-currency-filter.d.ts +13 -0
  7. package/dist/lib/testing/storyboard/pricing-currency-filter.js +175 -0
  8. package/dist/lib/testing/storyboard/pricing-currency-filter.mjs +151 -0
  9. package/dist/lib/testing/storyboard/required-metric-filters.d.mts +9 -0
  10. package/dist/lib/testing/storyboard/required-metric-filters.d.ts +9 -0
  11. package/dist/lib/testing/storyboard/required-metric-filters.js +128 -0
  12. package/dist/lib/testing/storyboard/required-metric-filters.mjs +104 -0
  13. package/dist/lib/testing/storyboard/runner.js +244 -48
  14. package/dist/lib/testing/storyboard/runner.mjs +246 -49
  15. package/dist/lib/testing/storyboard/seeding.d.mts +86 -1
  16. package/dist/lib/testing/storyboard/seeding.d.ts +86 -1
  17. package/dist/lib/testing/storyboard/seeding.js +91 -18
  18. package/dist/lib/testing/storyboard/seeding.mjs +90 -18
  19. package/dist/lib/testing/storyboard/types.d.mts +30 -1
  20. package/dist/lib/testing/storyboard/types.d.ts +30 -1
  21. package/dist/lib/testing/storyboard/types.js +1 -0
  22. package/dist/lib/testing/storyboard/types.mjs +1 -0
  23. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  24. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  25. package/dist/lib/version.d.mts +3 -3
  26. package/dist/lib/version.d.ts +3 -3
  27. package/dist/lib/version.js +3 -3
  28. package/dist/lib/version.mjs +3 -3
  29. package/docs/TYPE-SUMMARY.md +2 -2
  30. package/docs/guides/WHOLESALE-PAGE-COLLECTION.md +67 -0
  31. package/docs/llms.txt +2 -2
  32. package/docs/migration-14.x-rc-worksheet.md +4 -4
  33. package/package.json +1 -1
@@ -20,12 +20,14 @@ var seeding_exports = {};
20
20
  __export(seeding_exports, {
21
21
  CONTROLLER_SEEDING_PHASE_ID: () => CONTROLLER_SEEDING_PHASE_ID,
22
22
  buildSeedCalls: () => buildSeedCalls,
23
+ collectWholesaleProductPages: () => collectWholesaleProductPages,
23
24
  runControllerSeeding: () => runControllerSeeding
24
25
  });
25
26
  module.exports = __toCommonJS(seeding_exports);
26
27
  var import_client = require('../client.js');
27
28
  var import_schema_loader = require('../../validation/schema-loader.js');
28
29
  var import_version = require('../../version.js');
30
+ var import_creative_delivery = require('../../v2/projection/creative-delivery.js');
29
31
  var import_envelope_status_compat = require('../../utils/envelope-status-compat.js');
30
32
  var import_response_unwrapper = require('../../utils/response-unwrapper.js');
31
33
  var import_test_controller = require('../test-controller.js');
@@ -1021,7 +1023,7 @@ function resolveDiscoverySchemaIdentity(adcpVersion) {
1021
1023
  }
1022
1024
  function describeDiscoverySchemaFailure(data, options) {
1023
1025
  try {
1024
- const version = options.adcpVersion ?? import_version.ADCP_VERSION;
1026
+ const version = options._serverAdcpVersion ?? options.adcpVersion ?? import_version.ADCP_VERSION;
1025
1027
  const validator = (0, import_schema_loader.getValidator)("get_products", "sync", version);
1026
1028
  let detail;
1027
1029
  if (validator) {
@@ -1029,7 +1031,7 @@ function describeDiscoverySchemaFailure(data, options) {
1029
1031
  if (validator(schemaData)) return void 0;
1030
1032
  detail = (validator.errors ?? []).map((error) => `${error.instancePath || "/"} ${error.message ?? error.keyword}`).join("; ");
1031
1033
  } else {
1032
- const schema = (0, import_client.validateResponseSchema)("get_products", data, options.adcpVersion);
1034
+ const schema = (0, import_client.validateResponseSchema)("get_products", data, version);
1033
1035
  if (schema.passed) return void 0;
1034
1036
  detail = schema.error ?? schema.details ?? "schema validation failed";
1035
1037
  }
@@ -1047,20 +1049,38 @@ async function discoverProductCatalog(client, options, context) {
1047
1049
  }
1048
1050
  const accountBrand = isPlainRecord(account.brand) ? account.brand : void 0;
1049
1051
  const brand = isPlainRecord(context.brand) ? context.brand : accountBrand ?? (0, import_client.resolveBrand)(options);
1052
+ const query = structuredClone({
1053
+ buying_mode: "wholesale",
1054
+ brand,
1055
+ account,
1056
+ pagination: { max_results: 100 },
1057
+ ...(0, import_creative_delivery.resolveCreativeFormatWireMode)(
1058
+ options._profile?.raw_capabilities,
1059
+ options._serverAdcpVersion ?? options.adcpVersion ?? import_version.ADCP_VERSION
1060
+ ) === "canonical" && { ext: { adcp: { creative_wire: "canonical" } } }
1061
+ });
1062
+ return collectWholesaleProductPages(client, options, query);
1063
+ }
1064
+ async function collectWholesaleProductPages(client, options, query, controls = {}) {
1065
+ if (Object.hasOwn(query, "idempotency_key")) {
1066
+ return {
1067
+ ok: false,
1068
+ error: "fixture discovery requires fresh reads without idempotency_key; pagination changes the request body"
1069
+ };
1070
+ }
1071
+ const dispatch = controls.dispatch ?? ((request) => (0, import_task_map.executeStoryboardTask)(client, "get_products", request, { signal: options.signal }));
1050
1072
  const products = [];
1073
+ const errors = [];
1051
1074
  const seenProductIds = /* @__PURE__ */ new Set();
1052
1075
  const cursors = [];
1053
1076
  const seenCursors = /* @__PURE__ */ new Set();
1054
- let cursor;
1077
+ const initialPagination = isPlainRecord(query.pagination) ? query.pagination : void 0;
1078
+ const initialCursor = typeof initialPagination?.cursor === "string" ? initialPagination.cursor : void 0;
1079
+ let cursor = initialCursor;
1080
+ let firstPage;
1055
1081
  let pageCount = 0;
1056
1082
  let restarts = 0;
1057
1083
  let feedIdentity;
1058
- const query = structuredClone({
1059
- buying_mode: "wholesale",
1060
- brand,
1061
- account,
1062
- ext: { adcp: { creative_wire: "canonical" } }
1063
- });
1064
1084
  let lastExchange;
1065
1085
  const exchanges = [];
1066
1086
  const pageOfProduct = /* @__PURE__ */ new Map();
@@ -1077,7 +1097,7 @@ async function discoverProductCatalog(client, options, context) {
1077
1097
  }
1078
1098
  const request = {
1079
1099
  ...structuredClone(query),
1080
- pagination: { max_results: 100, ...cursor && { cursor } }
1100
+ ...cursor !== void 0 && { pagination: { ...initialPagination, cursor } }
1081
1101
  };
1082
1102
  let result;
1083
1103
  let observedResponse;
@@ -1090,17 +1110,31 @@ async function discoverProductCatalog(client, options, context) {
1090
1110
  };
1091
1111
  try {
1092
1112
  if (options.protocol === "a2a") {
1093
- const captured = await (0, import_rawResponseCapture.withRawResponseCapture)(
1094
- () => (0, import_task_map.executeStoryboardTask)(client, "get_products", request, { signal: options.signal }),
1095
- { maxBodyBytes: 65536, maxCaptures: 8, maxTotalBodyBytes: 262144 }
1096
- );
1113
+ const captured = await (0, import_rawResponseCapture.withRawResponseCapture)(() => dispatch(request), {
1114
+ maxBodyBytes: 65536,
1115
+ maxCaptures: 8,
1116
+ maxTotalBodyBytes: 262144
1117
+ });
1097
1118
  result = captured.result;
1098
1119
  observedResponse = toolResponse(captured.captures);
1099
1120
  } else {
1100
- result = await (0, import_task_map.executeStoryboardTask)(client, "get_products", request, { signal: options.signal });
1121
+ result = await dispatch(request);
1101
1122
  }
1102
1123
  } catch (err) {
1103
1124
  const observed = toolResponse((0, import_rawResponseCapture.getCapturesFromError)(err) ?? []);
1125
+ await controls.onPage?.({
1126
+ page_index: pageCount + 1,
1127
+ restart_count: restarts,
1128
+ request: requestRecord,
1129
+ response: observed ? {
1130
+ transport: requestRecord.transport,
1131
+ payload: (0, import_discovery_evidence.redactDiscoveryEvidence)(observed.body),
1132
+ status: observed.status,
1133
+ duration_ms: Date.now() - pageStart
1134
+ } : null,
1135
+ extraction: { path: "none" },
1136
+ schema_validated: false
1137
+ });
1104
1138
  return {
1105
1139
  ok: false,
1106
1140
  error: `fixture discovery transport failure: ${(0, import_redact_credential_patterns.redactCredentialPatterns)(err instanceof Error ? err.message : String(err), false)}`,
@@ -1128,6 +1162,15 @@ async function discoverProductCatalog(client, options, context) {
1128
1162
  }
1129
1163
  }
1130
1164
  if ((!result.success || result.data === void 0) && result._extraction_path === void 0 && observedResponse === void 0 && wireResponse === void 0) {
1165
+ await controls.onPage?.({
1166
+ page_index: pageCount,
1167
+ restart_count: restarts,
1168
+ request: requestRecord,
1169
+ response: null,
1170
+ extraction: { path: "none" },
1171
+ result,
1172
+ schema_validated: false
1173
+ });
1131
1174
  return {
1132
1175
  ok: false,
1133
1176
  error: `fixture discovery get_products rejected: ${(0, import_redact_credential_patterns.redactCredentialPatterns)(result.error ?? result.adcp_error?.code ?? "unknown error", false)}`,
@@ -1174,7 +1217,21 @@ async function discoverProductCatalog(client, options, context) {
1174
1217
  const nativeState = nativeResult && isPlainRecord(nativeResult.status) ? nativeResult.status.state : void 0;
1175
1218
  const sellerRejected = result._extraction_path === "error" || isPlainRecord(schemaData) && (schemaData.adcp_error !== void 0 || schemaData.status === "failed" || schemaData.status === "rejected") || nativeState === "failed" || nativeState === "rejected" || nativeState === "canceled";
1176
1219
  const schemaCheck = sellerRejected || schemaData === void 0 ? void 0 : describeDiscoverySchemaFailure(schemaData, options);
1177
- if (!result.success) {
1220
+ const observation = {
1221
+ page_index: pageCount,
1222
+ restart_count: restarts,
1223
+ request: requestRecord,
1224
+ response: failedExchange.response,
1225
+ extraction,
1226
+ result,
1227
+ schema_validated: schemaCheck === void 0 && !sellerRejected && result.success,
1228
+ ...!schemaCheck && !sellerRejected && result.success && {
1229
+ strict_schema_validated: (0, import_schema_loader.getValidator)("get_products", "sync", options._serverAdcpVersion ?? options.adcpVersion ?? import_version.ADCP_VERSION) !== void 0
1230
+ },
1231
+ ...schemaCheck?.schemaFailure && { schemaFailure: schemaCheck.schemaFailure }
1232
+ };
1233
+ await controls.onPage?.(observation);
1234
+ if (!result.success || sellerRejected) {
1178
1235
  return {
1179
1236
  ok: false,
1180
1237
  error: `fixture discovery get_products rejected: ${(0, import_redact_credential_patterns.redactCredentialPatterns)(result.error ?? result.adcp_error?.code ?? "unknown error", false)}`,
@@ -1230,16 +1287,29 @@ async function discoverProductCatalog(client, options, context) {
1230
1287
  }
1231
1288
  restarts++;
1232
1289
  products.length = 0;
1290
+ errors.length = 0;
1233
1291
  seenProductIds.clear();
1234
1292
  cursors.length = 0;
1235
1293
  seenCursors.clear();
1236
- exchanges.length = 0;
1294
+ if (!controls.retainRestartEvidence) exchanges.length = 0;
1237
1295
  pageOfProduct.clear();
1238
- cursor = void 0;
1296
+ firstPage = void 0;
1297
+ cursor = initialCursor;
1239
1298
  feedIdentity = void 0;
1240
1299
  continue;
1241
1300
  }
1242
1301
  feedIdentity = identity;
1302
+ firstPage ??= observation;
1303
+ if (Array.isArray(result.data.errors)) {
1304
+ if (errors.length + result.data.errors.length > 1e5) {
1305
+ return {
1306
+ ok: false,
1307
+ error: "fixture discovery exceeded the 100,000-advisory safety limit",
1308
+ exchange: failedExchange
1309
+ };
1310
+ }
1311
+ for (const error of result.data.errors) errors.push(error);
1312
+ }
1243
1313
  const pageProducts = result.data.products;
1244
1314
  if (pageProducts !== void 0 && !Array.isArray(pageProducts)) {
1245
1315
  return {
@@ -1305,6 +1375,8 @@ async function discoverProductCatalog(client, options, context) {
1305
1375
  ok: true,
1306
1376
  catalog: {
1307
1377
  products,
1378
+ firstPage,
1379
+ errors,
1308
1380
  evidence: {
1309
1381
  page_count: pageCount,
1310
1382
  product_count: products.length,
@@ -1600,5 +1672,6 @@ function buildMissingControllerResult(storyboard, calls, context) {
1600
1672
  0 && (module.exports = {
1601
1673
  CONTROLLER_SEEDING_PHASE_ID,
1602
1674
  buildSeedCalls,
1675
+ collectWholesaleProductPages,
1603
1676
  runControllerSeeding
1604
1677
  });
@@ -1,6 +1,7 @@
1
1
  import { resolveAccount, resolveBrand, validateResponseSchema } from "../client.mjs";
2
2
  import { getValidator } from "../../validation/schema-loader.mjs";
3
3
  import { ADCP_VERSION } from "../../version.mjs";
4
+ import { resolveCreativeFormatWireMode } from "../../v2/projection/creative-delivery.mjs";
4
5
  import { injectLegacyEnvelopeStatus } from "../../utils/envelope-status-compat.mjs";
5
6
  import { readExtractionPath, unwrapProtocolResponse } from "../../utils/response-unwrapper.mjs";
6
7
  import { callControllerRaw } from "../test-controller.mjs";
@@ -1002,7 +1003,7 @@ function resolveDiscoverySchemaIdentity(adcpVersion) {
1002
1003
  }
1003
1004
  function describeDiscoverySchemaFailure(data, options) {
1004
1005
  try {
1005
- const version = options.adcpVersion ?? ADCP_VERSION;
1006
+ const version = options._serverAdcpVersion ?? options.adcpVersion ?? ADCP_VERSION;
1006
1007
  const validator = getValidator("get_products", "sync", version);
1007
1008
  let detail;
1008
1009
  if (validator) {
@@ -1010,7 +1011,7 @@ function describeDiscoverySchemaFailure(data, options) {
1010
1011
  if (validator(schemaData)) return void 0;
1011
1012
  detail = (validator.errors ?? []).map((error) => `${error.instancePath || "/"} ${error.message ?? error.keyword}`).join("; ");
1012
1013
  } else {
1013
- const schema = validateResponseSchema("get_products", data, options.adcpVersion);
1014
+ const schema = validateResponseSchema("get_products", data, version);
1014
1015
  if (schema.passed) return void 0;
1015
1016
  detail = schema.error ?? schema.details ?? "schema validation failed";
1016
1017
  }
@@ -1028,20 +1029,38 @@ async function discoverProductCatalog(client, options, context) {
1028
1029
  }
1029
1030
  const accountBrand = isPlainRecord(account.brand) ? account.brand : void 0;
1030
1031
  const brand = isPlainRecord(context.brand) ? context.brand : accountBrand ?? resolveBrand(options);
1032
+ const query = structuredClone({
1033
+ buying_mode: "wholesale",
1034
+ brand,
1035
+ account,
1036
+ pagination: { max_results: 100 },
1037
+ ...resolveCreativeFormatWireMode(
1038
+ options._profile?.raw_capabilities,
1039
+ options._serverAdcpVersion ?? options.adcpVersion ?? ADCP_VERSION
1040
+ ) === "canonical" && { ext: { adcp: { creative_wire: "canonical" } } }
1041
+ });
1042
+ return collectWholesaleProductPages(client, options, query);
1043
+ }
1044
+ async function collectWholesaleProductPages(client, options, query, controls = {}) {
1045
+ if (Object.hasOwn(query, "idempotency_key")) {
1046
+ return {
1047
+ ok: false,
1048
+ error: "fixture discovery requires fresh reads without idempotency_key; pagination changes the request body"
1049
+ };
1050
+ }
1051
+ const dispatch = controls.dispatch ?? ((request) => executeStoryboardTask(client, "get_products", request, { signal: options.signal }));
1031
1052
  const products = [];
1053
+ const errors = [];
1032
1054
  const seenProductIds = /* @__PURE__ */ new Set();
1033
1055
  const cursors = [];
1034
1056
  const seenCursors = /* @__PURE__ */ new Set();
1035
- let cursor;
1057
+ const initialPagination = isPlainRecord(query.pagination) ? query.pagination : void 0;
1058
+ const initialCursor = typeof initialPagination?.cursor === "string" ? initialPagination.cursor : void 0;
1059
+ let cursor = initialCursor;
1060
+ let firstPage;
1036
1061
  let pageCount = 0;
1037
1062
  let restarts = 0;
1038
1063
  let feedIdentity;
1039
- const query = structuredClone({
1040
- buying_mode: "wholesale",
1041
- brand,
1042
- account,
1043
- ext: { adcp: { creative_wire: "canonical" } }
1044
- });
1045
1064
  let lastExchange;
1046
1065
  const exchanges = [];
1047
1066
  const pageOfProduct = /* @__PURE__ */ new Map();
@@ -1058,7 +1077,7 @@ async function discoverProductCatalog(client, options, context) {
1058
1077
  }
1059
1078
  const request = {
1060
1079
  ...structuredClone(query),
1061
- pagination: { max_results: 100, ...cursor && { cursor } }
1080
+ ...cursor !== void 0 && { pagination: { ...initialPagination, cursor } }
1062
1081
  };
1063
1082
  let result;
1064
1083
  let observedResponse;
@@ -1071,17 +1090,31 @@ async function discoverProductCatalog(client, options, context) {
1071
1090
  };
1072
1091
  try {
1073
1092
  if (options.protocol === "a2a") {
1074
- const captured = await withRawResponseCapture(
1075
- () => executeStoryboardTask(client, "get_products", request, { signal: options.signal }),
1076
- { maxBodyBytes: 65536, maxCaptures: 8, maxTotalBodyBytes: 262144 }
1077
- );
1093
+ const captured = await withRawResponseCapture(() => dispatch(request), {
1094
+ maxBodyBytes: 65536,
1095
+ maxCaptures: 8,
1096
+ maxTotalBodyBytes: 262144
1097
+ });
1078
1098
  result = captured.result;
1079
1099
  observedResponse = toolResponse(captured.captures);
1080
1100
  } else {
1081
- result = await executeStoryboardTask(client, "get_products", request, { signal: options.signal });
1101
+ result = await dispatch(request);
1082
1102
  }
1083
1103
  } catch (err) {
1084
1104
  const observed = toolResponse(getCapturesFromError(err) ?? []);
1105
+ await controls.onPage?.({
1106
+ page_index: pageCount + 1,
1107
+ restart_count: restarts,
1108
+ request: requestRecord,
1109
+ response: observed ? {
1110
+ transport: requestRecord.transport,
1111
+ payload: redactDiscoveryResponse(observed.body),
1112
+ status: observed.status,
1113
+ duration_ms: Date.now() - pageStart
1114
+ } : null,
1115
+ extraction: { path: "none" },
1116
+ schema_validated: false
1117
+ });
1085
1118
  return {
1086
1119
  ok: false,
1087
1120
  error: `fixture discovery transport failure: ${redactCredentialPatterns(err instanceof Error ? err.message : String(err), false)}`,
@@ -1109,6 +1142,15 @@ async function discoverProductCatalog(client, options, context) {
1109
1142
  }
1110
1143
  }
1111
1144
  if ((!result.success || result.data === void 0) && result._extraction_path === void 0 && observedResponse === void 0 && wireResponse === void 0) {
1145
+ await controls.onPage?.({
1146
+ page_index: pageCount,
1147
+ restart_count: restarts,
1148
+ request: requestRecord,
1149
+ response: null,
1150
+ extraction: { path: "none" },
1151
+ result,
1152
+ schema_validated: false
1153
+ });
1112
1154
  return {
1113
1155
  ok: false,
1114
1156
  error: `fixture discovery get_products rejected: ${redactCredentialPatterns(result.error ?? result.adcp_error?.code ?? "unknown error", false)}`,
@@ -1155,7 +1197,21 @@ async function discoverProductCatalog(client, options, context) {
1155
1197
  const nativeState = nativeResult && isPlainRecord(nativeResult.status) ? nativeResult.status.state : void 0;
1156
1198
  const sellerRejected = result._extraction_path === "error" || isPlainRecord(schemaData) && (schemaData.adcp_error !== void 0 || schemaData.status === "failed" || schemaData.status === "rejected") || nativeState === "failed" || nativeState === "rejected" || nativeState === "canceled";
1157
1199
  const schemaCheck = sellerRejected || schemaData === void 0 ? void 0 : describeDiscoverySchemaFailure(schemaData, options);
1158
- if (!result.success) {
1200
+ const observation = {
1201
+ page_index: pageCount,
1202
+ restart_count: restarts,
1203
+ request: requestRecord,
1204
+ response: failedExchange.response,
1205
+ extraction,
1206
+ result,
1207
+ schema_validated: schemaCheck === void 0 && !sellerRejected && result.success,
1208
+ ...!schemaCheck && !sellerRejected && result.success && {
1209
+ strict_schema_validated: getValidator("get_products", "sync", options._serverAdcpVersion ?? options.adcpVersion ?? ADCP_VERSION) !== void 0
1210
+ },
1211
+ ...schemaCheck?.schemaFailure && { schemaFailure: schemaCheck.schemaFailure }
1212
+ };
1213
+ await controls.onPage?.(observation);
1214
+ if (!result.success || sellerRejected) {
1159
1215
  return {
1160
1216
  ok: false,
1161
1217
  error: `fixture discovery get_products rejected: ${redactCredentialPatterns(result.error ?? result.adcp_error?.code ?? "unknown error", false)}`,
@@ -1211,16 +1267,29 @@ async function discoverProductCatalog(client, options, context) {
1211
1267
  }
1212
1268
  restarts++;
1213
1269
  products.length = 0;
1270
+ errors.length = 0;
1214
1271
  seenProductIds.clear();
1215
1272
  cursors.length = 0;
1216
1273
  seenCursors.clear();
1217
- exchanges.length = 0;
1274
+ if (!controls.retainRestartEvidence) exchanges.length = 0;
1218
1275
  pageOfProduct.clear();
1219
- cursor = void 0;
1276
+ firstPage = void 0;
1277
+ cursor = initialCursor;
1220
1278
  feedIdentity = void 0;
1221
1279
  continue;
1222
1280
  }
1223
1281
  feedIdentity = identity;
1282
+ firstPage ??= observation;
1283
+ if (Array.isArray(result.data.errors)) {
1284
+ if (errors.length + result.data.errors.length > 1e5) {
1285
+ return {
1286
+ ok: false,
1287
+ error: "fixture discovery exceeded the 100,000-advisory safety limit",
1288
+ exchange: failedExchange
1289
+ };
1290
+ }
1291
+ for (const error of result.data.errors) errors.push(error);
1292
+ }
1224
1293
  const pageProducts = result.data.products;
1225
1294
  if (pageProducts !== void 0 && !Array.isArray(pageProducts)) {
1226
1295
  return {
@@ -1286,6 +1355,8 @@ async function discoverProductCatalog(client, options, context) {
1286
1355
  ok: true,
1287
1356
  catalog: {
1288
1357
  products,
1358
+ firstPage,
1359
+ errors,
1289
1360
  evidence: {
1290
1361
  page_count: pageCount,
1291
1362
  product_count: products.length,
@@ -1580,5 +1651,6 @@ function buildMissingControllerResult(storyboard, calls, context) {
1580
1651
  export {
1581
1652
  CONTROLLER_SEEDING_PHASE_ID,
1582
1653
  buildSeedCalls,
1654
+ collectWholesaleProductPages,
1583
1655
  runControllerSeeding
1584
1656
  };
@@ -88,6 +88,8 @@ export interface Storyboard {
88
88
  * staging fixture). The runner does not verify the assertion;
89
89
  * scenarios that need state still fail naturally if the seed is
90
90
  * not actually present.
91
+ * - `collect_product_pages_runner` — intrinsic support for explicit wholesale
92
+ * all-page steps; unavailable on older runners that ignore this metadata.
91
93
  * - `real_wire` — always available. Tag scenarios that observe
92
94
  * production behavior with this when you want them excluded from
93
95
  * a future `--mock-only` mode; today the tag is a no-op gate.
@@ -797,6 +799,14 @@ export interface StoryboardStep {
797
799
  * fields from the same seller response without changing the request wire.
798
800
  */
799
801
  response_projection?: 'raw';
802
+ /**
803
+ * Follow every wholesale product page before authored checks and captures.
804
+ * Requires `collect_product_pages_runner` in the storyboard's `requires`.
805
+ * Reads must omit idempotency_key; each page/restart is a fresh request.
806
+ * Every page retains its own exchange and is schema/invariant checked; the
807
+ * combined logical view is explicitly separate from the wire response.
808
+ */
809
+ collect_product_pages?: true;
800
810
  /** Whether this step depends on state from a previous step */
801
811
  stateful?: boolean;
802
812
  /**
@@ -2391,7 +2401,7 @@ export interface RunnerSelectionResult {
2391
2401
  *
2392
2402
  * Spec: adcp-client#1626, adcp-client#2281, adcp-client#2356.
2393
2403
  */
2394
- export type RequirementName = 'controller' | 'seeded_state' | 'real_wire' | 'webhook_receiver' | 'webhook_replay_receiver' | 'trusted_match_context_router_runner' | 'trusted_match_publisher_auth_runner' | 'property_list_reference_runner' | 'request_signer' | 'multi_agent';
2404
+ export type RequirementName = 'controller' | 'collect_product_pages_runner' | 'seeded_state' | 'real_wire' | 'webhook_receiver' | 'webhook_replay_receiver' | 'trusted_match_context_router_runner' | 'trusted_match_publisher_auth_runner' | 'property_list_reference_runner' | 'request_signer' | 'multi_agent';
2395
2405
  /**
2396
2406
  * Enumeration of every requirement this SDK knows how to satisfy. The loader
2397
2407
  * accepts other non-empty strings for forward compatibility; the runner treats
@@ -2728,6 +2738,8 @@ export interface StoryboardStepResult {
2728
2738
  request?: RunnerRequestRecord;
2729
2739
  /** Exact response observed, including transport, status, headers. */
2730
2740
  response_record?: RunnerResponseRecord;
2741
+ /** Explicit logical wholesale view with separately retained actual pages. */
2742
+ product_page_collection?: ProductPageCollectionRecord;
2731
2743
  /** Which extraction path produced the parsed response (required per contract). */
2732
2744
  extraction: RunnerExtractionRecord;
2733
2745
  /**
@@ -2744,6 +2756,23 @@ export interface StoryboardStepResult {
2744
2756
  */
2745
2757
  hints?: StoryboardStepHint[];
2746
2758
  }
2759
+ /** One physical exchange within an opted-in logical wholesale read. */
2760
+ export interface ProductPageRecord {
2761
+ page_index: number;
2762
+ restart_count: number;
2763
+ request: RunnerRequestRecord;
2764
+ response: RunnerResponseRecord | null;
2765
+ extraction: RunnerExtractionRecord;
2766
+ schema_validated: boolean;
2767
+ }
2768
+ export interface ProductPageCollectionRecord {
2769
+ complete: boolean;
2770
+ page_count: number;
2771
+ restart_count: number;
2772
+ pages: ProductPageRecord[];
2773
+ /** Runner-derived view used only for authored checks and context capture. */
2774
+ logical_response?: Record<string, unknown>;
2775
+ }
2747
2776
  /**
2748
2777
  * Provenance entry for a context key: which step wrote it and how.
2749
2778
  * Populated by the runner as it applies `context_outputs` and convention-
@@ -88,6 +88,8 @@ export interface Storyboard {
88
88
  * staging fixture). The runner does not verify the assertion;
89
89
  * scenarios that need state still fail naturally if the seed is
90
90
  * not actually present.
91
+ * - `collect_product_pages_runner` — intrinsic support for explicit wholesale
92
+ * all-page steps; unavailable on older runners that ignore this metadata.
91
93
  * - `real_wire` — always available. Tag scenarios that observe
92
94
  * production behavior with this when you want them excluded from
93
95
  * a future `--mock-only` mode; today the tag is a no-op gate.
@@ -797,6 +799,14 @@ export interface StoryboardStep {
797
799
  * fields from the same seller response without changing the request wire.
798
800
  */
799
801
  response_projection?: 'raw';
802
+ /**
803
+ * Follow every wholesale product page before authored checks and captures.
804
+ * Requires `collect_product_pages_runner` in the storyboard's `requires`.
805
+ * Reads must omit idempotency_key; each page/restart is a fresh request.
806
+ * Every page retains its own exchange and is schema/invariant checked; the
807
+ * combined logical view is explicitly separate from the wire response.
808
+ */
809
+ collect_product_pages?: true;
800
810
  /** Whether this step depends on state from a previous step */
801
811
  stateful?: boolean;
802
812
  /**
@@ -2391,7 +2401,7 @@ export interface RunnerSelectionResult {
2391
2401
  *
2392
2402
  * Spec: adcp-client#1626, adcp-client#2281, adcp-client#2356.
2393
2403
  */
2394
- export type RequirementName = 'controller' | 'seeded_state' | 'real_wire' | 'webhook_receiver' | 'webhook_replay_receiver' | 'trusted_match_context_router_runner' | 'trusted_match_publisher_auth_runner' | 'property_list_reference_runner' | 'request_signer' | 'multi_agent';
2404
+ export type RequirementName = 'controller' | 'collect_product_pages_runner' | 'seeded_state' | 'real_wire' | 'webhook_receiver' | 'webhook_replay_receiver' | 'trusted_match_context_router_runner' | 'trusted_match_publisher_auth_runner' | 'property_list_reference_runner' | 'request_signer' | 'multi_agent';
2395
2405
  /**
2396
2406
  * Enumeration of every requirement this SDK knows how to satisfy. The loader
2397
2407
  * accepts other non-empty strings for forward compatibility; the runner treats
@@ -2728,6 +2738,8 @@ export interface StoryboardStepResult {
2728
2738
  request?: RunnerRequestRecord;
2729
2739
  /** Exact response observed, including transport, status, headers. */
2730
2740
  response_record?: RunnerResponseRecord;
2741
+ /** Explicit logical wholesale view with separately retained actual pages. */
2742
+ product_page_collection?: ProductPageCollectionRecord;
2731
2743
  /** Which extraction path produced the parsed response (required per contract). */
2732
2744
  extraction: RunnerExtractionRecord;
2733
2745
  /**
@@ -2744,6 +2756,23 @@ export interface StoryboardStepResult {
2744
2756
  */
2745
2757
  hints?: StoryboardStepHint[];
2746
2758
  }
2759
+ /** One physical exchange within an opted-in logical wholesale read. */
2760
+ export interface ProductPageRecord {
2761
+ page_index: number;
2762
+ restart_count: number;
2763
+ request: RunnerRequestRecord;
2764
+ response: RunnerResponseRecord | null;
2765
+ extraction: RunnerExtractionRecord;
2766
+ schema_validated: boolean;
2767
+ }
2768
+ export interface ProductPageCollectionRecord {
2769
+ complete: boolean;
2770
+ page_count: number;
2771
+ restart_count: number;
2772
+ pages: ProductPageRecord[];
2773
+ /** Runner-derived view used only for authored checks and context capture. */
2774
+ logical_response?: Record<string, unknown>;
2775
+ }
2747
2776
  /**
2748
2777
  * Provenance entry for a context key: which step wrote it and how.
2749
2778
  * Populated by the runner as it applies `context_outputs` and convention-
@@ -62,6 +62,7 @@ const DETAILED_SKIP_TO_CANONICAL = {
62
62
  };
63
63
  const KNOWN_REQUIREMENTS = /* @__PURE__ */ new Set([
64
64
  "controller",
65
+ "collect_product_pages_runner",
65
66
  "seeded_state",
66
67
  "real_wire",
67
68
  "webhook_receiver",
@@ -36,6 +36,7 @@ const DETAILED_SKIP_TO_CANONICAL = {
36
36
  };
37
37
  const KNOWN_REQUIREMENTS = /* @__PURE__ */ new Set([
38
38
  "controller",
39
+ "collect_product_pages_runner",
39
40
  "seeded_state",
40
41
  "real_wire",
41
42
  "webhook_receiver",
@@ -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 = "17.0.0-beta.6";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "17.0.0-beta.7";
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 = "17.0.0-beta.6";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "17.0.0-beta.7";
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
  /**
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "17.0.0-beta.6";
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.6";
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-29T19:03:50.550Z";
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.6";
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.6";
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-29T19:03:50.550Z";
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.6";
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.6",
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-29T19:03:50.550Z"
112
+ generatedAt: "2026-10-30T02:12:55.702Z"
113
113
  };
114
114
  function getAdcpVersion() {
115
115
  return ADCP_VERSION;