@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.
- package/dist/lib/identity-3.3/validation.js +3 -1
- package/dist/lib/identity-3.3/validation.mjs +8 -2
- package/dist/lib/schemas/index.d.mts +2 -2
- package/dist/lib/schemas/index.d.ts +2 -2
- package/dist/lib/server/create-adcp-server.js +8 -2
- package/dist/lib/server/create-adcp-server.mjs +9 -3
- package/dist/lib/testing/storyboard/default-invariants.js +4 -0
- package/dist/lib/testing/storyboard/default-invariants.mjs +4 -0
- package/dist/lib/testing/storyboard/loader.js +31 -0
- package/dist/lib/testing/storyboard/loader.mjs +31 -0
- package/dist/lib/testing/storyboard/pricing-currency-filter.d.mts +13 -0
- package/dist/lib/testing/storyboard/pricing-currency-filter.d.ts +13 -0
- package/dist/lib/testing/storyboard/pricing-currency-filter.js +175 -0
- package/dist/lib/testing/storyboard/pricing-currency-filter.mjs +151 -0
- package/dist/lib/testing/storyboard/required-metric-filters.d.mts +9 -0
- package/dist/lib/testing/storyboard/required-metric-filters.d.ts +9 -0
- package/dist/lib/testing/storyboard/required-metric-filters.js +128 -0
- package/dist/lib/testing/storyboard/required-metric-filters.mjs +104 -0
- package/dist/lib/testing/storyboard/runner.js +244 -48
- package/dist/lib/testing/storyboard/runner.mjs +246 -49
- package/dist/lib/testing/storyboard/seeding.d.mts +86 -1
- package/dist/lib/testing/storyboard/seeding.d.ts +86 -1
- package/dist/lib/testing/storyboard/seeding.js +91 -18
- package/dist/lib/testing/storyboard/seeding.mjs +90 -18
- package/dist/lib/testing/storyboard/types.d.mts +30 -1
- package/dist/lib/testing/storyboard/types.d.ts +30 -1
- package/dist/lib/testing/storyboard/types.js +1 -0
- package/dist/lib/testing/storyboard/types.mjs +1 -0
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/utils/envelope-status-compat.d.mts +21 -2
- package/dist/lib/utils/envelope-status-compat.d.ts +21 -2
- package/dist/lib/utils/envelope-status-compat.js +21 -6
- package/dist/lib/utils/envelope-status-compat.mjs +23 -4
- package/dist/lib/utils/response-schemas.js +4 -0
- package/dist/lib/utils/response-schemas.mjs +5 -1
- package/dist/lib/validation/schema-loader.d.mts +2 -2
- package/dist/lib/validation/schema-loader.d.ts +2 -2
- package/dist/lib/validation/schema-loader.js +72 -9
- package/dist/lib/validation/schema-loader.mjs +69 -8
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.mjs +3 -3
- package/docs/TYPE-SUMMARY.md +2 -2
- package/docs/guides/WHOLESALE-PAGE-COLLECTION.md +67 -0
- package/docs/llms.txt +2 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- 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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1095
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1076
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
@@ -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.
|
|
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.
|
|
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
|
/**
|
|
@@ -44,8 +44,27 @@ export interface LegacyEnvelopeStatusOptions {
|
|
|
44
44
|
*/
|
|
45
45
|
adcpVersion?: string;
|
|
46
46
|
}
|
|
47
|
-
/**
|
|
48
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Compact synchronous responses that the 3.0 shim must never give a `status`.
|
|
49
|
+
*
|
|
50
|
+
* 3.0 emitters never served these tools. On 3.2.x the schema forbids `status`;
|
|
51
|
+
* from the release that composes `core/protocol-envelope.json` into every task
|
|
52
|
+
* response it is REQUIRED, and a missing one is the seller's defect, not
|
|
53
|
+
* something to fill in. `list_collections` and `list_proposals` are 3.3-only.
|
|
54
|
+
*/
|
|
55
|
+
export declare const COMPACT_SYNC_RESPONSE_TOOLS: ReadonlySet<string>;
|
|
56
|
+
/**
|
|
57
|
+
* True when the served release's published schema for `toolName` has no
|
|
58
|
+
* `status`, so a seller serving that release must not emit it: 3.2.x
|
|
59
|
+
* `list_products` / `decline_proposals`. False for every other tool, and for a
|
|
60
|
+
* release whose schema composes the protocol envelope (3.3 and the 3.2.x
|
|
61
|
+
* backport), where `status` is required and preserved.
|
|
62
|
+
*
|
|
63
|
+
* The release's own schema decides, not a version number, so a bundle that
|
|
64
|
+
* adds the envelope later changes the answer without a code change. An unknown
|
|
65
|
+
* version or a release with no such schema keeps `status`.
|
|
66
|
+
*/
|
|
67
|
+
export declare function omitsEnvelopeStatusForRelease(toolName: string, servedVersion: string | undefined): boolean;
|
|
49
68
|
/**
|
|
50
69
|
* Detect whether a response payload should be treated as 3.0.x for the
|
|
51
70
|
* purposes of envelope-status leniency.
|
|
@@ -44,8 +44,27 @@ export interface LegacyEnvelopeStatusOptions {
|
|
|
44
44
|
*/
|
|
45
45
|
adcpVersion?: string;
|
|
46
46
|
}
|
|
47
|
-
/**
|
|
48
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Compact synchronous responses that the 3.0 shim must never give a `status`.
|
|
49
|
+
*
|
|
50
|
+
* 3.0 emitters never served these tools. On 3.2.x the schema forbids `status`;
|
|
51
|
+
* from the release that composes `core/protocol-envelope.json` into every task
|
|
52
|
+
* response it is REQUIRED, and a missing one is the seller's defect, not
|
|
53
|
+
* something to fill in. `list_collections` and `list_proposals` are 3.3-only.
|
|
54
|
+
*/
|
|
55
|
+
export declare const COMPACT_SYNC_RESPONSE_TOOLS: ReadonlySet<string>;
|
|
56
|
+
/**
|
|
57
|
+
* True when the served release's published schema for `toolName` has no
|
|
58
|
+
* `status`, so a seller serving that release must not emit it: 3.2.x
|
|
59
|
+
* `list_products` / `decline_proposals`. False for every other tool, and for a
|
|
60
|
+
* release whose schema composes the protocol envelope (3.3 and the 3.2.x
|
|
61
|
+
* backport), where `status` is required and preserved.
|
|
62
|
+
*
|
|
63
|
+
* The release's own schema decides, not a version number, so a bundle that
|
|
64
|
+
* adds the envelope later changes the answer without a code change. An unknown
|
|
65
|
+
* version or a release with no such schema keeps `status`.
|
|
66
|
+
*/
|
|
67
|
+
export declare function omitsEnvelopeStatusForRelease(toolName: string, servedVersion: string | undefined): boolean;
|
|
49
68
|
/**
|
|
50
69
|
* Detect whether a response payload should be treated as 3.0.x for the
|
|
51
70
|
* purposes of envelope-status leniency.
|