@riddledc/riddle-proof 0.7.121 → 0.7.123
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/README.md +28 -0
- package/dist/{chunk-TBEVHMU3.js → chunk-JVZWSI55.js} +129 -0
- package/dist/cli.cjs +165 -0
- package/dist/cli.js +39 -1
- package/dist/index.cjs +130 -0
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/profile.cjs +130 -0
- package/dist/profile.d.cts +45 -1
- package/dist/profile.d.ts +45 -1
- package/dist/profile.js +3 -1
- package/examples/profiles/terminal-result-partial-evidence.json +122 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -216,12 +216,30 @@ required snippets make the command exit non-zero. This keeps Good Catch and
|
|
|
216
216
|
audit-profile promotions tied to real artifacts instead of hand-authored token
|
|
217
217
|
guesses.
|
|
218
218
|
|
|
219
|
+
Before spending a hosted browser run on a public-promotion profile, preflight
|
|
220
|
+
the profile-level `http_status` checks directly:
|
|
221
|
+
|
|
222
|
+
```sh
|
|
223
|
+
riddle-proof-loop profile-http-status-preflight \
|
|
224
|
+
--profile .riddle-proof/profiles/good-catch-promotion.json \
|
|
225
|
+
--url https://preview.riddledc.com/s/ps_12345678/ \
|
|
226
|
+
--format summary
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The preflight resolves the profile's `http_status` URLs against the same base
|
|
230
|
+
URL that `run-profile` would use, then verifies status, content type, byte
|
|
231
|
+
requirements, `body_contains`, `body_not_contains`, and `body_not_patterns`.
|
|
232
|
+
It exits non-zero if any body assertion is missing or any forbidden body text is
|
|
233
|
+
present, which catches raw/escaped proof-artifact mistakes before a full
|
|
234
|
+
viewport matrix run.
|
|
235
|
+
|
|
219
236
|
The package includes generic starter profiles:
|
|
220
237
|
|
|
221
238
|
- `examples/profiles/page-content-basic.json` for route/content/layout smoke profiles.
|
|
222
239
|
- `examples/profiles/route-inventory-basic.json` for source-link and direct-route audits.
|
|
223
240
|
- `examples/profiles/handled-recovery-list-load.json` for failed or malformed list-load recovery profiles.
|
|
224
241
|
- `examples/profiles/handled-recovery-action-malformed-success.json` for action recovery profiles where the request succeeds at HTTP level but returns an unusable body.
|
|
242
|
+
- `examples/profiles/terminal-result-partial-evidence.json` for API-console terminal error or timeout receipts that preserve partial screenshot, console, and HAR evidence.
|
|
225
243
|
|
|
226
244
|
Copy one of those shapes into a repository profile directory and replace the
|
|
227
245
|
routes, selectors, mock URLs, and text checks with app-specific invariants.
|
|
@@ -254,6 +272,16 @@ message, captures a recovery screenshot, and keeps parser text plus browser
|
|
|
254
272
|
console/page errors out of the final proof. This catches action paths that look
|
|
255
273
|
recovered to a user but still poison the browser evidence stream.
|
|
256
274
|
|
|
275
|
+
For terminal result profiles, prove status honesty separately from artifact
|
|
276
|
+
presence. A page can preserve screenshots, console output, HAR, billing, and raw
|
|
277
|
+
response evidence while still lying about the terminal state or omitting that
|
|
278
|
+
the evidence is partial. Return a terminal `completed_error` or
|
|
279
|
+
`completed_timeout` response with partial evidence, require the visible status
|
|
280
|
+
and `partial results available` copy, assert each artifact class, reject Success
|
|
281
|
+
and contradictory empty-evidence copy, assert success/error/timeout selector
|
|
282
|
+
polarity, and keep `no_horizontal_overflow`, `no_fatal_console_errors`, and
|
|
283
|
+
`no_console_warnings` in the same profile.
|
|
284
|
+
|
|
257
285
|
Checks normally apply to every captured viewport. Add `viewports` (or
|
|
258
286
|
`viewport_names`) to a check when responsive UI intentionally exposes an
|
|
259
287
|
invariant only on named viewports, such as desktop-only helper copy while phone
|
|
@@ -1221,6 +1221,134 @@ function linkStatusResultOk(result, check) {
|
|
|
1221
1221
|
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
1222
1222
|
return true;
|
|
1223
1223
|
}
|
|
1224
|
+
function responseHeader(response, name) {
|
|
1225
|
+
const getter = response.headers?.get;
|
|
1226
|
+
if (typeof getter !== "function") return null;
|
|
1227
|
+
return getter.call(response.headers, name);
|
|
1228
|
+
}
|
|
1229
|
+
function responseContentLength(response) {
|
|
1230
|
+
const value = responseHeader(response, "content-length");
|
|
1231
|
+
return value && /^\d+$/.test(value) ? Number(value) : null;
|
|
1232
|
+
}
|
|
1233
|
+
async function responseBodyText(response) {
|
|
1234
|
+
if (typeof response.arrayBuffer === "function") {
|
|
1235
|
+
const buffer = await response.arrayBuffer();
|
|
1236
|
+
return {
|
|
1237
|
+
text: new TextDecoder().decode(buffer),
|
|
1238
|
+
bytes: buffer.byteLength
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
if (typeof response.text === "function") {
|
|
1242
|
+
const text = await response.text();
|
|
1243
|
+
return {
|
|
1244
|
+
text,
|
|
1245
|
+
bytes: new TextEncoder().encode(text).byteLength
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
1248
|
+
return { text: "", bytes: null };
|
|
1249
|
+
}
|
|
1250
|
+
function httpStatusRequestBody(check) {
|
|
1251
|
+
const headers = isRecord(check.headers) ? Object.fromEntries(Object.entries(check.headers).map(([key, value]) => [key, String(value)]).filter(([key]) => key.trim())) : {};
|
|
1252
|
+
if (check.body_json !== void 0) {
|
|
1253
|
+
if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
|
|
1254
|
+
headers["content-type"] = "application/json";
|
|
1255
|
+
}
|
|
1256
|
+
return { headers, body: JSON.stringify(check.body_json) };
|
|
1257
|
+
}
|
|
1258
|
+
if (typeof check.body === "string") {
|
|
1259
|
+
return { headers, body: check.body };
|
|
1260
|
+
}
|
|
1261
|
+
return { headers };
|
|
1262
|
+
}
|
|
1263
|
+
async function preflightHttpStatusCheck(check, index, targetUrl, fetchImpl) {
|
|
1264
|
+
const url = httpStatusRequestUrl(check, targetUrl);
|
|
1265
|
+
const method = httpStatusMethod(check);
|
|
1266
|
+
const request = httpStatusRequestBody(check);
|
|
1267
|
+
const init = {
|
|
1268
|
+
method,
|
|
1269
|
+
redirect: "follow",
|
|
1270
|
+
cache: "no-store",
|
|
1271
|
+
headers: request.headers
|
|
1272
|
+
};
|
|
1273
|
+
if (request.body !== void 0 && method !== "GET" && method !== "HEAD") {
|
|
1274
|
+
init.body = request.body;
|
|
1275
|
+
}
|
|
1276
|
+
const result = {
|
|
1277
|
+
status: null,
|
|
1278
|
+
content_type: null,
|
|
1279
|
+
content_length: null,
|
|
1280
|
+
bytes: null
|
|
1281
|
+
};
|
|
1282
|
+
let error = null;
|
|
1283
|
+
let statusText = "";
|
|
1284
|
+
try {
|
|
1285
|
+
const response = await fetchImpl(url, init);
|
|
1286
|
+
result.status = typeof response.status === "number" && Number.isFinite(response.status) ? response.status : null;
|
|
1287
|
+
statusText = typeof response.statusText === "string" ? response.statusText : "";
|
|
1288
|
+
result.content_type = responseHeader(response, "content-type");
|
|
1289
|
+
result.content_length = responseContentLength(response);
|
|
1290
|
+
const shouldReadBody = check.require_nonzero_bytes === true || typeof check.min_bytes === "number" || Boolean(check.body_contains?.length) || Boolean(check.body_not_contains?.length) || Boolean(check.body_not_patterns?.length);
|
|
1291
|
+
if (shouldReadBody && method !== "HEAD") {
|
|
1292
|
+
const body = await responseBodyText(response);
|
|
1293
|
+
result.bytes = body.bytes;
|
|
1294
|
+
if (check.body_contains?.length) {
|
|
1295
|
+
result.body_contains = Object.fromEntries(check.body_contains.filter(Boolean).map((snippet) => [snippet, body.text.includes(snippet)]));
|
|
1296
|
+
}
|
|
1297
|
+
if (check.body_not_contains?.length) {
|
|
1298
|
+
result.body_not_contains = Object.fromEntries(check.body_not_contains.filter(Boolean).map((snippet) => [snippet, body.text.includes(snippet)]));
|
|
1299
|
+
}
|
|
1300
|
+
if (check.body_not_patterns?.length) {
|
|
1301
|
+
result.body_not_patterns = Object.fromEntries(check.body_not_patterns.filter(Boolean).map((pattern) => [pattern, new RegExp(pattern).test(body.text)]));
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
} catch (caught) {
|
|
1305
|
+
error = String(caught instanceof Error ? caught.message : caught).slice(0, 500);
|
|
1306
|
+
result.error = error;
|
|
1307
|
+
}
|
|
1308
|
+
const bodyContainsMissing = httpStatusBodyContainsFailures(result, check);
|
|
1309
|
+
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(result, check);
|
|
1310
|
+
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(result, check);
|
|
1311
|
+
const ok = !error && linkStatusResultOk(result, check);
|
|
1312
|
+
return {
|
|
1313
|
+
index,
|
|
1314
|
+
label: checkLabel(check) || `checks[${index}]`,
|
|
1315
|
+
url,
|
|
1316
|
+
method,
|
|
1317
|
+
ok,
|
|
1318
|
+
status: numberValue(result.status) ?? null,
|
|
1319
|
+
status_text: statusText,
|
|
1320
|
+
error,
|
|
1321
|
+
content_type: stringValue(result.content_type) ?? null,
|
|
1322
|
+
content_length: numberValue(result.content_length) ?? null,
|
|
1323
|
+
bytes: numberValue(result.bytes) ?? null,
|
|
1324
|
+
body_contains: isRecord(result.body_contains) ? Object.fromEntries(Object.entries(result.body_contains).map(([key, value]) => [key, value === true])) : null,
|
|
1325
|
+
body_contains_missing: bodyContainsMissing,
|
|
1326
|
+
body_not_contains: isRecord(result.body_not_contains) ? Object.fromEntries(Object.entries(result.body_not_contains).map(([key, value]) => [key, value === true])) : null,
|
|
1327
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
1328
|
+
body_not_patterns: isRecord(result.body_not_patterns) ? Object.fromEntries(Object.entries(result.body_not_patterns).map(([key, value]) => [key, value === true])) : null,
|
|
1329
|
+
body_not_patterns_found: bodyNotPatternsFound
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
async function preflightRiddleProofProfileHttpStatusChecks(profile, options = {}) {
|
|
1333
|
+
const targetUrl = options.target_url || resolveRiddleProofProfileTargetUrl(profile);
|
|
1334
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
1335
|
+
if (typeof fetchImpl !== "function") {
|
|
1336
|
+
throw new Error("profile http_status preflight requires fetch support or options.fetchImpl.");
|
|
1337
|
+
}
|
|
1338
|
+
const httpStatusChecks = profile.checks.map((check, index) => ({ check, index })).filter((item) => item.check.type === "http_status");
|
|
1339
|
+
const checks = await Promise.all(httpStatusChecks.map((item) => preflightHttpStatusCheck(item.check, item.index, targetUrl, fetchImpl)));
|
|
1340
|
+
const failed = checks.filter((check) => !check.ok).length;
|
|
1341
|
+
return {
|
|
1342
|
+
version: "riddle-proof.profile-http-status-preflight.v1",
|
|
1343
|
+
ok: failed === 0,
|
|
1344
|
+
profile_name: profile.name,
|
|
1345
|
+
target_url: targetUrl,
|
|
1346
|
+
checked: checks.length,
|
|
1347
|
+
failed,
|
|
1348
|
+
checks,
|
|
1349
|
+
summary: failed === 0 ? `${profile.name} http_status preflight passed ${checks.length} check(s).` : `${profile.name} http_status preflight failed ${failed} of ${checks.length} check(s).`
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1224
1352
|
function httpStatusEvidenceForCheck(viewport, check) {
|
|
1225
1353
|
const evidence = viewport.http_statuses?.[httpStatusKey(check, viewport.url)];
|
|
1226
1354
|
return isRecord(evidence) ? evidence : void 0;
|
|
@@ -5920,6 +6048,7 @@ export {
|
|
|
5920
6048
|
normalizeRiddleProofProfile,
|
|
5921
6049
|
resolveRiddleProofProfileTargetUrl,
|
|
5922
6050
|
resolveRiddleProofProfileTimeoutSec,
|
|
6051
|
+
preflightRiddleProofProfileHttpStatusChecks,
|
|
5923
6052
|
resolveRiddleProofProfileRouteUrl,
|
|
5924
6053
|
assessRiddleProofProfileEvidence,
|
|
5925
6054
|
summarizeRiddleProofProfileResult,
|
package/dist/cli.cjs
CHANGED
|
@@ -8158,6 +8158,134 @@ function linkStatusResultOk(result, check) {
|
|
|
8158
8158
|
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
8159
8159
|
return true;
|
|
8160
8160
|
}
|
|
8161
|
+
function responseHeader(response, name) {
|
|
8162
|
+
const getter = response.headers?.get;
|
|
8163
|
+
if (typeof getter !== "function") return null;
|
|
8164
|
+
return getter.call(response.headers, name);
|
|
8165
|
+
}
|
|
8166
|
+
function responseContentLength(response) {
|
|
8167
|
+
const value = responseHeader(response, "content-length");
|
|
8168
|
+
return value && /^\d+$/.test(value) ? Number(value) : null;
|
|
8169
|
+
}
|
|
8170
|
+
async function responseBodyText(response) {
|
|
8171
|
+
if (typeof response.arrayBuffer === "function") {
|
|
8172
|
+
const buffer = await response.arrayBuffer();
|
|
8173
|
+
return {
|
|
8174
|
+
text: new TextDecoder().decode(buffer),
|
|
8175
|
+
bytes: buffer.byteLength
|
|
8176
|
+
};
|
|
8177
|
+
}
|
|
8178
|
+
if (typeof response.text === "function") {
|
|
8179
|
+
const text = await response.text();
|
|
8180
|
+
return {
|
|
8181
|
+
text,
|
|
8182
|
+
bytes: new TextEncoder().encode(text).byteLength
|
|
8183
|
+
};
|
|
8184
|
+
}
|
|
8185
|
+
return { text: "", bytes: null };
|
|
8186
|
+
}
|
|
8187
|
+
function httpStatusRequestBody(check) {
|
|
8188
|
+
const headers = isRecord(check.headers) ? Object.fromEntries(Object.entries(check.headers).map(([key, value]) => [key, String(value)]).filter(([key]) => key.trim())) : {};
|
|
8189
|
+
if (check.body_json !== void 0) {
|
|
8190
|
+
if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
|
|
8191
|
+
headers["content-type"] = "application/json";
|
|
8192
|
+
}
|
|
8193
|
+
return { headers, body: JSON.stringify(check.body_json) };
|
|
8194
|
+
}
|
|
8195
|
+
if (typeof check.body === "string") {
|
|
8196
|
+
return { headers, body: check.body };
|
|
8197
|
+
}
|
|
8198
|
+
return { headers };
|
|
8199
|
+
}
|
|
8200
|
+
async function preflightHttpStatusCheck(check, index, targetUrl, fetchImpl) {
|
|
8201
|
+
const url = httpStatusRequestUrl(check, targetUrl);
|
|
8202
|
+
const method = httpStatusMethod(check);
|
|
8203
|
+
const request = httpStatusRequestBody(check);
|
|
8204
|
+
const init = {
|
|
8205
|
+
method,
|
|
8206
|
+
redirect: "follow",
|
|
8207
|
+
cache: "no-store",
|
|
8208
|
+
headers: request.headers
|
|
8209
|
+
};
|
|
8210
|
+
if (request.body !== void 0 && method !== "GET" && method !== "HEAD") {
|
|
8211
|
+
init.body = request.body;
|
|
8212
|
+
}
|
|
8213
|
+
const result = {
|
|
8214
|
+
status: null,
|
|
8215
|
+
content_type: null,
|
|
8216
|
+
content_length: null,
|
|
8217
|
+
bytes: null
|
|
8218
|
+
};
|
|
8219
|
+
let error = null;
|
|
8220
|
+
let statusText = "";
|
|
8221
|
+
try {
|
|
8222
|
+
const response = await fetchImpl(url, init);
|
|
8223
|
+
result.status = typeof response.status === "number" && Number.isFinite(response.status) ? response.status : null;
|
|
8224
|
+
statusText = typeof response.statusText === "string" ? response.statusText : "";
|
|
8225
|
+
result.content_type = responseHeader(response, "content-type");
|
|
8226
|
+
result.content_length = responseContentLength(response);
|
|
8227
|
+
const shouldReadBody = check.require_nonzero_bytes === true || typeof check.min_bytes === "number" || Boolean(check.body_contains?.length) || Boolean(check.body_not_contains?.length) || Boolean(check.body_not_patterns?.length);
|
|
8228
|
+
if (shouldReadBody && method !== "HEAD") {
|
|
8229
|
+
const body = await responseBodyText(response);
|
|
8230
|
+
result.bytes = body.bytes;
|
|
8231
|
+
if (check.body_contains?.length) {
|
|
8232
|
+
result.body_contains = Object.fromEntries(check.body_contains.filter(Boolean).map((snippet) => [snippet, body.text.includes(snippet)]));
|
|
8233
|
+
}
|
|
8234
|
+
if (check.body_not_contains?.length) {
|
|
8235
|
+
result.body_not_contains = Object.fromEntries(check.body_not_contains.filter(Boolean).map((snippet) => [snippet, body.text.includes(snippet)]));
|
|
8236
|
+
}
|
|
8237
|
+
if (check.body_not_patterns?.length) {
|
|
8238
|
+
result.body_not_patterns = Object.fromEntries(check.body_not_patterns.filter(Boolean).map((pattern) => [pattern, new RegExp(pattern).test(body.text)]));
|
|
8239
|
+
}
|
|
8240
|
+
}
|
|
8241
|
+
} catch (caught) {
|
|
8242
|
+
error = String(caught instanceof Error ? caught.message : caught).slice(0, 500);
|
|
8243
|
+
result.error = error;
|
|
8244
|
+
}
|
|
8245
|
+
const bodyContainsMissing = httpStatusBodyContainsFailures(result, check);
|
|
8246
|
+
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(result, check);
|
|
8247
|
+
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(result, check);
|
|
8248
|
+
const ok = !error && linkStatusResultOk(result, check);
|
|
8249
|
+
return {
|
|
8250
|
+
index,
|
|
8251
|
+
label: checkLabel(check) || `checks[${index}]`,
|
|
8252
|
+
url,
|
|
8253
|
+
method,
|
|
8254
|
+
ok,
|
|
8255
|
+
status: numberValue(result.status) ?? null,
|
|
8256
|
+
status_text: statusText,
|
|
8257
|
+
error,
|
|
8258
|
+
content_type: stringValue2(result.content_type) ?? null,
|
|
8259
|
+
content_length: numberValue(result.content_length) ?? null,
|
|
8260
|
+
bytes: numberValue(result.bytes) ?? null,
|
|
8261
|
+
body_contains: isRecord(result.body_contains) ? Object.fromEntries(Object.entries(result.body_contains).map(([key, value]) => [key, value === true])) : null,
|
|
8262
|
+
body_contains_missing: bodyContainsMissing,
|
|
8263
|
+
body_not_contains: isRecord(result.body_not_contains) ? Object.fromEntries(Object.entries(result.body_not_contains).map(([key, value]) => [key, value === true])) : null,
|
|
8264
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
8265
|
+
body_not_patterns: isRecord(result.body_not_patterns) ? Object.fromEntries(Object.entries(result.body_not_patterns).map(([key, value]) => [key, value === true])) : null,
|
|
8266
|
+
body_not_patterns_found: bodyNotPatternsFound
|
|
8267
|
+
};
|
|
8268
|
+
}
|
|
8269
|
+
async function preflightRiddleProofProfileHttpStatusChecks(profile, options = {}) {
|
|
8270
|
+
const targetUrl = options.target_url || resolveRiddleProofProfileTargetUrl(profile);
|
|
8271
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
8272
|
+
if (typeof fetchImpl !== "function") {
|
|
8273
|
+
throw new Error("profile http_status preflight requires fetch support or options.fetchImpl.");
|
|
8274
|
+
}
|
|
8275
|
+
const httpStatusChecks = profile.checks.map((check, index) => ({ check, index })).filter((item) => item.check.type === "http_status");
|
|
8276
|
+
const checks = await Promise.all(httpStatusChecks.map((item) => preflightHttpStatusCheck(item.check, item.index, targetUrl, fetchImpl)));
|
|
8277
|
+
const failed = checks.filter((check) => !check.ok).length;
|
|
8278
|
+
return {
|
|
8279
|
+
version: "riddle-proof.profile-http-status-preflight.v1",
|
|
8280
|
+
ok: failed === 0,
|
|
8281
|
+
profile_name: profile.name,
|
|
8282
|
+
target_url: targetUrl,
|
|
8283
|
+
checked: checks.length,
|
|
8284
|
+
failed,
|
|
8285
|
+
checks,
|
|
8286
|
+
summary: failed === 0 ? `${profile.name} http_status preflight passed ${checks.length} check(s).` : `${profile.name} http_status preflight failed ${failed} of ${checks.length} check(s).`
|
|
8287
|
+
};
|
|
8288
|
+
}
|
|
8161
8289
|
function httpStatusEvidenceForCheck(viewport, check) {
|
|
8162
8290
|
const evidence = viewport.http_statuses?.[httpStatusKey(check, viewport.url)];
|
|
8163
8291
|
return isRecord(evidence) ? evidence : void 0;
|
|
@@ -12838,6 +12966,7 @@ function usage() {
|
|
|
12838
12966
|
" riddle-proof-loop status --state-path <path>",
|
|
12839
12967
|
" riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--strict true|false; default false] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--quiet]",
|
|
12840
12968
|
" riddle-proof-loop profile-body-assertions --artifact <file|url|-> --candidates-json <file|json|-> [--required-json <file|json|->] [--format json|body-contains]",
|
|
12969
|
+
" riddle-proof-loop profile-http-status-preflight --profile <file|json|-> --url <base-url> [--format json|summary]",
|
|
12841
12970
|
" riddle-proof-loop riddle-preview-deploy <build-dir> <label> [--framework spa|static]",
|
|
12842
12971
|
" riddle-proof-loop riddle-server-preview <directory> --script-file <file> [--path /route] [--wait-for-selector selector]",
|
|
12843
12972
|
" riddle-proof-loop riddle-run-script --url <url> --script-file <file> [--viewport 1280x720] [--strict true|false]",
|
|
@@ -13118,6 +13247,27 @@ function normalizeProfileForCli(options) {
|
|
|
13118
13247
|
viewports: parseProfileViewports(optionString(options, "viewports") || optionString(options, "viewport"))
|
|
13119
13248
|
});
|
|
13120
13249
|
}
|
|
13250
|
+
function profileHttpStatusPreflightSummary(result) {
|
|
13251
|
+
const lines = [
|
|
13252
|
+
result.summary,
|
|
13253
|
+
`Profile: ${result.profile_name}`,
|
|
13254
|
+
`Target: ${result.target_url}`,
|
|
13255
|
+
`Checked: ${result.checked}`,
|
|
13256
|
+
`Failed: ${result.failed}`
|
|
13257
|
+
];
|
|
13258
|
+
for (const check of result.checks) {
|
|
13259
|
+
lines.push(`- ${check.ok ? "passed" : "failed"}: ${check.method} ${check.url}`);
|
|
13260
|
+
if (!check.ok) {
|
|
13261
|
+
if (check.status !== null) lines.push(` status: ${check.status}`);
|
|
13262
|
+
if (check.error) lines.push(` error: ${check.error}`);
|
|
13263
|
+
if (check.body_contains_missing.length) lines.push(` missing body_contains: ${check.body_contains_missing.join(", ")}`);
|
|
13264
|
+
if (check.body_not_contains_found.length) lines.push(` found body_not_contains: ${check.body_not_contains_found.join(", ")}`);
|
|
13265
|
+
if (check.body_not_patterns_found.length) lines.push(` found body_not_patterns: ${check.body_not_patterns_found.join(", ")}`);
|
|
13266
|
+
}
|
|
13267
|
+
}
|
|
13268
|
+
return `${lines.join("\n")}
|
|
13269
|
+
`;
|
|
13270
|
+
}
|
|
13121
13271
|
function profileResultMarkdown(result) {
|
|
13122
13272
|
const lines = [
|
|
13123
13273
|
`# Riddle Proof Profile: ${result.profile_name}`,
|
|
@@ -13691,6 +13841,21 @@ async function main() {
|
|
|
13691
13841
|
process.exitCode = profileStatusExitCode(profile, result.status);
|
|
13692
13842
|
return;
|
|
13693
13843
|
}
|
|
13844
|
+
if (command === "profile-http-status-preflight") {
|
|
13845
|
+
const profile = normalizeProfileForCli(options);
|
|
13846
|
+
const result = await preflightRiddleProofProfileHttpStatusChecks(profile);
|
|
13847
|
+
const format = optionString(options, "format") || "json";
|
|
13848
|
+
if (format === "summary") {
|
|
13849
|
+
process.stdout.write(profileHttpStatusPreflightSummary(result));
|
|
13850
|
+
} else if (format === "json") {
|
|
13851
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
13852
|
+
`);
|
|
13853
|
+
} else {
|
|
13854
|
+
throw new Error("--format must be json or summary.");
|
|
13855
|
+
}
|
|
13856
|
+
process.exitCode = result.ok ? 0 : 1;
|
|
13857
|
+
return;
|
|
13858
|
+
}
|
|
13694
13859
|
if (command === "profile-body-assertions") {
|
|
13695
13860
|
const artifactText = await readTextValue(optionString(options, "artifact") ?? optionString(options, "input"), "--artifact");
|
|
13696
13861
|
const candidates = readOptionalJsonStringArray(optionString(options, "candidatesJson") ?? optionString(options, "candidateJson"), "--candidates-json") ?? [];
|
package/dist/cli.js
CHANGED
|
@@ -8,10 +8,11 @@ import {
|
|
|
8
8
|
deriveRiddleProofArtifactBodyAssertions,
|
|
9
9
|
extractRiddleProofProfileResult,
|
|
10
10
|
normalizeRiddleProofProfile,
|
|
11
|
+
preflightRiddleProofProfileHttpStatusChecks,
|
|
11
12
|
profileStatusExitCode,
|
|
12
13
|
resolveRiddleProofProfileTargetUrl,
|
|
13
14
|
resolveRiddleProofProfileTimeoutSec
|
|
14
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-JVZWSI55.js";
|
|
15
16
|
import {
|
|
16
17
|
createRiddleApiClient,
|
|
17
18
|
parseRiddleViewport
|
|
@@ -47,6 +48,7 @@ function usage() {
|
|
|
47
48
|
" riddle-proof-loop status --state-path <path>",
|
|
48
49
|
" riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--strict true|false; default false] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--quiet]",
|
|
49
50
|
" riddle-proof-loop profile-body-assertions --artifact <file|url|-> --candidates-json <file|json|-> [--required-json <file|json|->] [--format json|body-contains]",
|
|
51
|
+
" riddle-proof-loop profile-http-status-preflight --profile <file|json|-> --url <base-url> [--format json|summary]",
|
|
50
52
|
" riddle-proof-loop riddle-preview-deploy <build-dir> <label> [--framework spa|static]",
|
|
51
53
|
" riddle-proof-loop riddle-server-preview <directory> --script-file <file> [--path /route] [--wait-for-selector selector]",
|
|
52
54
|
" riddle-proof-loop riddle-run-script --url <url> --script-file <file> [--viewport 1280x720] [--strict true|false]",
|
|
@@ -327,6 +329,27 @@ function normalizeProfileForCli(options) {
|
|
|
327
329
|
viewports: parseProfileViewports(optionString(options, "viewports") || optionString(options, "viewport"))
|
|
328
330
|
});
|
|
329
331
|
}
|
|
332
|
+
function profileHttpStatusPreflightSummary(result) {
|
|
333
|
+
const lines = [
|
|
334
|
+
result.summary,
|
|
335
|
+
`Profile: ${result.profile_name}`,
|
|
336
|
+
`Target: ${result.target_url}`,
|
|
337
|
+
`Checked: ${result.checked}`,
|
|
338
|
+
`Failed: ${result.failed}`
|
|
339
|
+
];
|
|
340
|
+
for (const check of result.checks) {
|
|
341
|
+
lines.push(`- ${check.ok ? "passed" : "failed"}: ${check.method} ${check.url}`);
|
|
342
|
+
if (!check.ok) {
|
|
343
|
+
if (check.status !== null) lines.push(` status: ${check.status}`);
|
|
344
|
+
if (check.error) lines.push(` error: ${check.error}`);
|
|
345
|
+
if (check.body_contains_missing.length) lines.push(` missing body_contains: ${check.body_contains_missing.join(", ")}`);
|
|
346
|
+
if (check.body_not_contains_found.length) lines.push(` found body_not_contains: ${check.body_not_contains_found.join(", ")}`);
|
|
347
|
+
if (check.body_not_patterns_found.length) lines.push(` found body_not_patterns: ${check.body_not_patterns_found.join(", ")}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return `${lines.join("\n")}
|
|
351
|
+
`;
|
|
352
|
+
}
|
|
330
353
|
function profileResultMarkdown(result) {
|
|
331
354
|
const lines = [
|
|
332
355
|
`# Riddle Proof Profile: ${result.profile_name}`,
|
|
@@ -900,6 +923,21 @@ async function main() {
|
|
|
900
923
|
process.exitCode = profileStatusExitCode(profile, result.status);
|
|
901
924
|
return;
|
|
902
925
|
}
|
|
926
|
+
if (command === "profile-http-status-preflight") {
|
|
927
|
+
const profile = normalizeProfileForCli(options);
|
|
928
|
+
const result = await preflightRiddleProofProfileHttpStatusChecks(profile);
|
|
929
|
+
const format = optionString(options, "format") || "json";
|
|
930
|
+
if (format === "summary") {
|
|
931
|
+
process.stdout.write(profileHttpStatusPreflightSummary(result));
|
|
932
|
+
} else if (format === "json") {
|
|
933
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
934
|
+
`);
|
|
935
|
+
} else {
|
|
936
|
+
throw new Error("--format must be json or summary.");
|
|
937
|
+
}
|
|
938
|
+
process.exitCode = result.ok ? 0 : 1;
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
903
941
|
if (command === "profile-body-assertions") {
|
|
904
942
|
const artifactText = await readTextValue(optionString(options, "artifact") ?? optionString(options, "input"), "--artifact");
|
|
905
943
|
const candidates = readOptionalJsonStringArray(optionString(options, "candidatesJson") ?? optionString(options, "candidateJson"), "--candidates-json") ?? [];
|
package/dist/index.cjs
CHANGED
|
@@ -2991,6 +2991,7 @@ __export(index_exports, {
|
|
|
2991
2991
|
parseRiddleViewport: () => parseRiddleViewport,
|
|
2992
2992
|
parseVisualProofSession: () => parseVisualProofSession,
|
|
2993
2993
|
pollRiddleJob: () => pollRiddleJob,
|
|
2994
|
+
preflightRiddleProofProfileHttpStatusChecks: () => preflightRiddleProofProfileHttpStatusChecks,
|
|
2994
2995
|
profileStatusExitCode: () => profileStatusExitCode,
|
|
2995
2996
|
proofContractFromAuthorCheckpointResponse: () => proofContractFromAuthorCheckpointResponse,
|
|
2996
2997
|
readRiddleProofRunStatus: () => readRiddleProofRunStatus,
|
|
@@ -9953,6 +9954,134 @@ function linkStatusResultOk(result, check) {
|
|
|
9953
9954
|
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
9954
9955
|
return true;
|
|
9955
9956
|
}
|
|
9957
|
+
function responseHeader(response, name) {
|
|
9958
|
+
const getter = response.headers?.get;
|
|
9959
|
+
if (typeof getter !== "function") return null;
|
|
9960
|
+
return getter.call(response.headers, name);
|
|
9961
|
+
}
|
|
9962
|
+
function responseContentLength(response) {
|
|
9963
|
+
const value = responseHeader(response, "content-length");
|
|
9964
|
+
return value && /^\d+$/.test(value) ? Number(value) : null;
|
|
9965
|
+
}
|
|
9966
|
+
async function responseBodyText(response) {
|
|
9967
|
+
if (typeof response.arrayBuffer === "function") {
|
|
9968
|
+
const buffer = await response.arrayBuffer();
|
|
9969
|
+
return {
|
|
9970
|
+
text: new TextDecoder().decode(buffer),
|
|
9971
|
+
bytes: buffer.byteLength
|
|
9972
|
+
};
|
|
9973
|
+
}
|
|
9974
|
+
if (typeof response.text === "function") {
|
|
9975
|
+
const text = await response.text();
|
|
9976
|
+
return {
|
|
9977
|
+
text,
|
|
9978
|
+
bytes: new TextEncoder().encode(text).byteLength
|
|
9979
|
+
};
|
|
9980
|
+
}
|
|
9981
|
+
return { text: "", bytes: null };
|
|
9982
|
+
}
|
|
9983
|
+
function httpStatusRequestBody(check) {
|
|
9984
|
+
const headers = isRecord2(check.headers) ? Object.fromEntries(Object.entries(check.headers).map(([key, value]) => [key, String(value)]).filter(([key]) => key.trim())) : {};
|
|
9985
|
+
if (check.body_json !== void 0) {
|
|
9986
|
+
if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
|
|
9987
|
+
headers["content-type"] = "application/json";
|
|
9988
|
+
}
|
|
9989
|
+
return { headers, body: JSON.stringify(check.body_json) };
|
|
9990
|
+
}
|
|
9991
|
+
if (typeof check.body === "string") {
|
|
9992
|
+
return { headers, body: check.body };
|
|
9993
|
+
}
|
|
9994
|
+
return { headers };
|
|
9995
|
+
}
|
|
9996
|
+
async function preflightHttpStatusCheck(check, index, targetUrl, fetchImpl) {
|
|
9997
|
+
const url = httpStatusRequestUrl(check, targetUrl);
|
|
9998
|
+
const method = httpStatusMethod(check);
|
|
9999
|
+
const request = httpStatusRequestBody(check);
|
|
10000
|
+
const init = {
|
|
10001
|
+
method,
|
|
10002
|
+
redirect: "follow",
|
|
10003
|
+
cache: "no-store",
|
|
10004
|
+
headers: request.headers
|
|
10005
|
+
};
|
|
10006
|
+
if (request.body !== void 0 && method !== "GET" && method !== "HEAD") {
|
|
10007
|
+
init.body = request.body;
|
|
10008
|
+
}
|
|
10009
|
+
const result = {
|
|
10010
|
+
status: null,
|
|
10011
|
+
content_type: null,
|
|
10012
|
+
content_length: null,
|
|
10013
|
+
bytes: null
|
|
10014
|
+
};
|
|
10015
|
+
let error = null;
|
|
10016
|
+
let statusText = "";
|
|
10017
|
+
try {
|
|
10018
|
+
const response = await fetchImpl(url, init);
|
|
10019
|
+
result.status = typeof response.status === "number" && Number.isFinite(response.status) ? response.status : null;
|
|
10020
|
+
statusText = typeof response.statusText === "string" ? response.statusText : "";
|
|
10021
|
+
result.content_type = responseHeader(response, "content-type");
|
|
10022
|
+
result.content_length = responseContentLength(response);
|
|
10023
|
+
const shouldReadBody = check.require_nonzero_bytes === true || typeof check.min_bytes === "number" || Boolean(check.body_contains?.length) || Boolean(check.body_not_contains?.length) || Boolean(check.body_not_patterns?.length);
|
|
10024
|
+
if (shouldReadBody && method !== "HEAD") {
|
|
10025
|
+
const body = await responseBodyText(response);
|
|
10026
|
+
result.bytes = body.bytes;
|
|
10027
|
+
if (check.body_contains?.length) {
|
|
10028
|
+
result.body_contains = Object.fromEntries(check.body_contains.filter(Boolean).map((snippet) => [snippet, body.text.includes(snippet)]));
|
|
10029
|
+
}
|
|
10030
|
+
if (check.body_not_contains?.length) {
|
|
10031
|
+
result.body_not_contains = Object.fromEntries(check.body_not_contains.filter(Boolean).map((snippet) => [snippet, body.text.includes(snippet)]));
|
|
10032
|
+
}
|
|
10033
|
+
if (check.body_not_patterns?.length) {
|
|
10034
|
+
result.body_not_patterns = Object.fromEntries(check.body_not_patterns.filter(Boolean).map((pattern) => [pattern, new RegExp(pattern).test(body.text)]));
|
|
10035
|
+
}
|
|
10036
|
+
}
|
|
10037
|
+
} catch (caught) {
|
|
10038
|
+
error = String(caught instanceof Error ? caught.message : caught).slice(0, 500);
|
|
10039
|
+
result.error = error;
|
|
10040
|
+
}
|
|
10041
|
+
const bodyContainsMissing = httpStatusBodyContainsFailures(result, check);
|
|
10042
|
+
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(result, check);
|
|
10043
|
+
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(result, check);
|
|
10044
|
+
const ok = !error && linkStatusResultOk(result, check);
|
|
10045
|
+
return {
|
|
10046
|
+
index,
|
|
10047
|
+
label: checkLabel(check) || `checks[${index}]`,
|
|
10048
|
+
url,
|
|
10049
|
+
method,
|
|
10050
|
+
ok,
|
|
10051
|
+
status: numberValue3(result.status) ?? null,
|
|
10052
|
+
status_text: statusText,
|
|
10053
|
+
error,
|
|
10054
|
+
content_type: stringValue5(result.content_type) ?? null,
|
|
10055
|
+
content_length: numberValue3(result.content_length) ?? null,
|
|
10056
|
+
bytes: numberValue3(result.bytes) ?? null,
|
|
10057
|
+
body_contains: isRecord2(result.body_contains) ? Object.fromEntries(Object.entries(result.body_contains).map(([key, value]) => [key, value === true])) : null,
|
|
10058
|
+
body_contains_missing: bodyContainsMissing,
|
|
10059
|
+
body_not_contains: isRecord2(result.body_not_contains) ? Object.fromEntries(Object.entries(result.body_not_contains).map(([key, value]) => [key, value === true])) : null,
|
|
10060
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
10061
|
+
body_not_patterns: isRecord2(result.body_not_patterns) ? Object.fromEntries(Object.entries(result.body_not_patterns).map(([key, value]) => [key, value === true])) : null,
|
|
10062
|
+
body_not_patterns_found: bodyNotPatternsFound
|
|
10063
|
+
};
|
|
10064
|
+
}
|
|
10065
|
+
async function preflightRiddleProofProfileHttpStatusChecks(profile, options = {}) {
|
|
10066
|
+
const targetUrl = options.target_url || resolveRiddleProofProfileTargetUrl(profile);
|
|
10067
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
10068
|
+
if (typeof fetchImpl !== "function") {
|
|
10069
|
+
throw new Error("profile http_status preflight requires fetch support or options.fetchImpl.");
|
|
10070
|
+
}
|
|
10071
|
+
const httpStatusChecks = profile.checks.map((check, index) => ({ check, index })).filter((item) => item.check.type === "http_status");
|
|
10072
|
+
const checks = await Promise.all(httpStatusChecks.map((item) => preflightHttpStatusCheck(item.check, item.index, targetUrl, fetchImpl)));
|
|
10073
|
+
const failed = checks.filter((check) => !check.ok).length;
|
|
10074
|
+
return {
|
|
10075
|
+
version: "riddle-proof.profile-http-status-preflight.v1",
|
|
10076
|
+
ok: failed === 0,
|
|
10077
|
+
profile_name: profile.name,
|
|
10078
|
+
target_url: targetUrl,
|
|
10079
|
+
checked: checks.length,
|
|
10080
|
+
failed,
|
|
10081
|
+
checks,
|
|
10082
|
+
summary: failed === 0 ? `${profile.name} http_status preflight passed ${checks.length} check(s).` : `${profile.name} http_status preflight failed ${failed} of ${checks.length} check(s).`
|
|
10083
|
+
};
|
|
10084
|
+
}
|
|
9956
10085
|
function httpStatusEvidenceForCheck(viewport, check) {
|
|
9957
10086
|
const evidence = viewport.http_statuses?.[httpStatusKey(check, viewport.url)];
|
|
9958
10087
|
return isRecord2(evidence) ? evidence : void 0;
|
|
@@ -15108,6 +15237,7 @@ function createRiddleApiClient(config = {}) {
|
|
|
15108
15237
|
parseRiddleViewport,
|
|
15109
15238
|
parseVisualProofSession,
|
|
15110
15239
|
pollRiddleJob,
|
|
15240
|
+
preflightRiddleProofProfileHttpStatusChecks,
|
|
15111
15241
|
profileStatusExitCode,
|
|
15112
15242
|
proofContractFromAuthorCheckpointResponse,
|
|
15113
15243
|
readRiddleProofRunStatus,
|
package/dist/index.d.cts
CHANGED
|
@@ -10,5 +10,5 @@ export { CreateCaptureDiagnosticInput, DEFAULT_DIAGNOSTIC_ARRAY_LIMIT, DEFAULT_D
|
|
|
10
10
|
export { BuildVisualProofSessionInput, RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION, RIDDLE_PROOF_VISUAL_SESSION_VERSION, VisualProofSessionMismatch, buildVisualProofSession, compareVisualProofSessionFingerprint, parseVisualProofSession, visualSessionFingerprint, visualSessionFingerprintBasis } from './proof-session.cjs';
|
|
11
11
|
export { AssessPlayabilityOptions, RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION, RIDDLE_PROOF_PLAYABILITY_VERSION, RiddleProofPlayabilityAssessment, RiddleProofPlayabilityEvidence, assessPlayabilityEvidence, extractPlayabilityEvidence, isRiddleProofPlayabilityMode } from './playability.cjs';
|
|
12
12
|
export { AssessBasicGameplayOptions, AttachBasicGameplayArtifactOptions, BASIC_GAMEPLAY_ACTION_TYPES, BASIC_GAMEPLAY_PROGRESS_CHECK_TYPES, BasicGameplayActionResult, BasicGameplayActionType, BasicGameplayArtifactResolution, BasicGameplayAssessmentSummary, BasicGameplayBoundsOffender, BasicGameplayCanvasState, BasicGameplayCatchRecord, BasicGameplayChangeSummary, BasicGameplayFailureCode, BasicGameplayFixReference, BasicGameplayMetric, BasicGameplayMobileEvidence, BasicGameplayProgressCheckType, BasicGameplayProgressionCheck, BasicGameplayProofArtifact, BasicGameplayResponsiveViewportEvidence, BasicGameplayRouteReference, BasicGameplaySnapshot, BasicGameplaySuiteFailure, BasicGameplayWarningCode, CreateBasicGameplayCatchSummaryInput, RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION, RiddleProofBasicGameplayAssessment, RiddleProofBasicGameplayCatchSummary, RiddleProofBasicGameplayEvidence, RiddleProofBasicGameplayRouteAssessment, RiddleProofBasicGameplayRouteEvidence, assessBasicGameplayEvidence, assessBasicGameplayProgressionCheck, assessBasicGameplayProgressionChecks, assessBasicGameplayRoute, attachBasicGameplayArtifactScreenshotHashes, augmentBasicGameplayAssessmentWithProgressionChecks, compactBasicGameplayText, createBasicGameplayCatchRecords, createBasicGameplayCatchSummary, extractBasicGameplayEvidence, resolveBasicGameplayProgressionCheckWithArtifactScreenshots, sanitizeBasicGameplayJsonString } from './basic-gameplay.cjs';
|
|
13
|
-
export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofArtifactBodyAssertionInput, RiddleProofArtifactBodyAssertionResult, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileBoundsOffender, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileNetworkAbortErrorCode, RiddleProofProfileNetworkMock, RiddleProofProfileNetworkMockResponse, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRouteInventoryRoute, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.cjs';
|
|
13
|
+
export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofArtifactBodyAssertionInput, RiddleProofArtifactBodyAssertionResult, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileBoundsOffender, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileHttpStatusPreflightCheckResult, RiddleProofProfileHttpStatusPreflightFetch, RiddleProofProfileHttpStatusPreflightFetchResponse, RiddleProofProfileHttpStatusPreflightOptions, RiddleProofProfileHttpStatusPreflightResult, RiddleProofProfileNetworkAbortErrorCode, RiddleProofProfileNetworkMock, RiddleProofProfileNetworkMockResponse, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRouteInventoryRoute, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, preflightRiddleProofProfileHttpStatusChecks, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.cjs';
|
|
14
14
|
export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployResult, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from './riddle-client.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,5 @@ export { CreateCaptureDiagnosticInput, DEFAULT_DIAGNOSTIC_ARRAY_LIMIT, DEFAULT_D
|
|
|
10
10
|
export { BuildVisualProofSessionInput, RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION, RIDDLE_PROOF_VISUAL_SESSION_VERSION, VisualProofSessionMismatch, buildVisualProofSession, compareVisualProofSessionFingerprint, parseVisualProofSession, visualSessionFingerprint, visualSessionFingerprintBasis } from './proof-session.js';
|
|
11
11
|
export { AssessPlayabilityOptions, RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION, RIDDLE_PROOF_PLAYABILITY_VERSION, RiddleProofPlayabilityAssessment, RiddleProofPlayabilityEvidence, assessPlayabilityEvidence, extractPlayabilityEvidence, isRiddleProofPlayabilityMode } from './playability.js';
|
|
12
12
|
export { AssessBasicGameplayOptions, AttachBasicGameplayArtifactOptions, BASIC_GAMEPLAY_ACTION_TYPES, BASIC_GAMEPLAY_PROGRESS_CHECK_TYPES, BasicGameplayActionResult, BasicGameplayActionType, BasicGameplayArtifactResolution, BasicGameplayAssessmentSummary, BasicGameplayBoundsOffender, BasicGameplayCanvasState, BasicGameplayCatchRecord, BasicGameplayChangeSummary, BasicGameplayFailureCode, BasicGameplayFixReference, BasicGameplayMetric, BasicGameplayMobileEvidence, BasicGameplayProgressCheckType, BasicGameplayProgressionCheck, BasicGameplayProofArtifact, BasicGameplayResponsiveViewportEvidence, BasicGameplayRouteReference, BasicGameplaySnapshot, BasicGameplaySuiteFailure, BasicGameplayWarningCode, CreateBasicGameplayCatchSummaryInput, RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION, RiddleProofBasicGameplayAssessment, RiddleProofBasicGameplayCatchSummary, RiddleProofBasicGameplayEvidence, RiddleProofBasicGameplayRouteAssessment, RiddleProofBasicGameplayRouteEvidence, assessBasicGameplayEvidence, assessBasicGameplayProgressionCheck, assessBasicGameplayProgressionChecks, assessBasicGameplayRoute, attachBasicGameplayArtifactScreenshotHashes, augmentBasicGameplayAssessmentWithProgressionChecks, compactBasicGameplayText, createBasicGameplayCatchRecords, createBasicGameplayCatchSummary, extractBasicGameplayEvidence, resolveBasicGameplayProgressionCheckWithArtifactScreenshots, sanitizeBasicGameplayJsonString } from './basic-gameplay.js';
|
|
13
|
-
export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofArtifactBodyAssertionInput, RiddleProofArtifactBodyAssertionResult, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileBoundsOffender, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileNetworkAbortErrorCode, RiddleProofProfileNetworkMock, RiddleProofProfileNetworkMockResponse, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRouteInventoryRoute, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.js';
|
|
13
|
+
export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofArtifactBodyAssertionInput, RiddleProofArtifactBodyAssertionResult, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileBoundsOffender, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileHttpStatusPreflightCheckResult, RiddleProofProfileHttpStatusPreflightFetch, RiddleProofProfileHttpStatusPreflightFetchResponse, RiddleProofProfileHttpStatusPreflightOptions, RiddleProofProfileHttpStatusPreflightResult, RiddleProofProfileNetworkAbortErrorCode, RiddleProofProfileNetworkMock, RiddleProofProfileNetworkMockResponse, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRouteInventoryRoute, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, preflightRiddleProofProfileHttpStatusChecks, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.js';
|
|
14
14
|
export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployResult, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from './riddle-client.js';
|
package/dist/index.js
CHANGED
|
@@ -55,13 +55,14 @@ import {
|
|
|
55
55
|
deriveRiddleProofArtifactBodyAssertions,
|
|
56
56
|
extractRiddleProofProfileResult,
|
|
57
57
|
normalizeRiddleProofProfile,
|
|
58
|
+
preflightRiddleProofProfileHttpStatusChecks,
|
|
58
59
|
profileStatusExitCode,
|
|
59
60
|
resolveRiddleProofProfileRouteUrl,
|
|
60
61
|
resolveRiddleProofProfileTargetUrl,
|
|
61
62
|
resolveRiddleProofProfileTimeoutSec,
|
|
62
63
|
slugifyRiddleProofProfileName,
|
|
63
64
|
summarizeRiddleProofProfileResult
|
|
64
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-JVZWSI55.js";
|
|
65
66
|
import {
|
|
66
67
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
67
68
|
DEFAULT_RIDDLE_API_KEY_FILE,
|
|
@@ -234,6 +235,7 @@ export {
|
|
|
234
235
|
parseRiddleViewport,
|
|
235
236
|
parseVisualProofSession,
|
|
236
237
|
pollRiddleJob,
|
|
238
|
+
preflightRiddleProofProfileHttpStatusChecks,
|
|
237
239
|
profileStatusExitCode,
|
|
238
240
|
proofContractFromAuthorCheckpointResponse,
|
|
239
241
|
readRiddleProofRunStatus,
|
package/dist/profile.cjs
CHANGED
|
@@ -37,6 +37,7 @@ __export(profile_exports, {
|
|
|
37
37
|
deriveRiddleProofArtifactBodyAssertions: () => deriveRiddleProofArtifactBodyAssertions,
|
|
38
38
|
extractRiddleProofProfileResult: () => extractRiddleProofProfileResult,
|
|
39
39
|
normalizeRiddleProofProfile: () => normalizeRiddleProofProfile,
|
|
40
|
+
preflightRiddleProofProfileHttpStatusChecks: () => preflightRiddleProofProfileHttpStatusChecks,
|
|
40
41
|
profileStatusExitCode: () => profileStatusExitCode,
|
|
41
42
|
resolveRiddleProofProfileRouteUrl: () => resolveRiddleProofProfileRouteUrl,
|
|
42
43
|
resolveRiddleProofProfileTargetUrl: () => resolveRiddleProofProfileTargetUrl,
|
|
@@ -1267,6 +1268,134 @@ function linkStatusResultOk(result, check) {
|
|
|
1267
1268
|
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
1268
1269
|
return true;
|
|
1269
1270
|
}
|
|
1271
|
+
function responseHeader(response, name) {
|
|
1272
|
+
const getter = response.headers?.get;
|
|
1273
|
+
if (typeof getter !== "function") return null;
|
|
1274
|
+
return getter.call(response.headers, name);
|
|
1275
|
+
}
|
|
1276
|
+
function responseContentLength(response) {
|
|
1277
|
+
const value = responseHeader(response, "content-length");
|
|
1278
|
+
return value && /^\d+$/.test(value) ? Number(value) : null;
|
|
1279
|
+
}
|
|
1280
|
+
async function responseBodyText(response) {
|
|
1281
|
+
if (typeof response.arrayBuffer === "function") {
|
|
1282
|
+
const buffer = await response.arrayBuffer();
|
|
1283
|
+
return {
|
|
1284
|
+
text: new TextDecoder().decode(buffer),
|
|
1285
|
+
bytes: buffer.byteLength
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
if (typeof response.text === "function") {
|
|
1289
|
+
const text = await response.text();
|
|
1290
|
+
return {
|
|
1291
|
+
text,
|
|
1292
|
+
bytes: new TextEncoder().encode(text).byteLength
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
return { text: "", bytes: null };
|
|
1296
|
+
}
|
|
1297
|
+
function httpStatusRequestBody(check) {
|
|
1298
|
+
const headers = isRecord(check.headers) ? Object.fromEntries(Object.entries(check.headers).map(([key, value]) => [key, String(value)]).filter(([key]) => key.trim())) : {};
|
|
1299
|
+
if (check.body_json !== void 0) {
|
|
1300
|
+
if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
|
|
1301
|
+
headers["content-type"] = "application/json";
|
|
1302
|
+
}
|
|
1303
|
+
return { headers, body: JSON.stringify(check.body_json) };
|
|
1304
|
+
}
|
|
1305
|
+
if (typeof check.body === "string") {
|
|
1306
|
+
return { headers, body: check.body };
|
|
1307
|
+
}
|
|
1308
|
+
return { headers };
|
|
1309
|
+
}
|
|
1310
|
+
async function preflightHttpStatusCheck(check, index, targetUrl, fetchImpl) {
|
|
1311
|
+
const url = httpStatusRequestUrl(check, targetUrl);
|
|
1312
|
+
const method = httpStatusMethod(check);
|
|
1313
|
+
const request = httpStatusRequestBody(check);
|
|
1314
|
+
const init = {
|
|
1315
|
+
method,
|
|
1316
|
+
redirect: "follow",
|
|
1317
|
+
cache: "no-store",
|
|
1318
|
+
headers: request.headers
|
|
1319
|
+
};
|
|
1320
|
+
if (request.body !== void 0 && method !== "GET" && method !== "HEAD") {
|
|
1321
|
+
init.body = request.body;
|
|
1322
|
+
}
|
|
1323
|
+
const result = {
|
|
1324
|
+
status: null,
|
|
1325
|
+
content_type: null,
|
|
1326
|
+
content_length: null,
|
|
1327
|
+
bytes: null
|
|
1328
|
+
};
|
|
1329
|
+
let error = null;
|
|
1330
|
+
let statusText = "";
|
|
1331
|
+
try {
|
|
1332
|
+
const response = await fetchImpl(url, init);
|
|
1333
|
+
result.status = typeof response.status === "number" && Number.isFinite(response.status) ? response.status : null;
|
|
1334
|
+
statusText = typeof response.statusText === "string" ? response.statusText : "";
|
|
1335
|
+
result.content_type = responseHeader(response, "content-type");
|
|
1336
|
+
result.content_length = responseContentLength(response);
|
|
1337
|
+
const shouldReadBody = check.require_nonzero_bytes === true || typeof check.min_bytes === "number" || Boolean(check.body_contains?.length) || Boolean(check.body_not_contains?.length) || Boolean(check.body_not_patterns?.length);
|
|
1338
|
+
if (shouldReadBody && method !== "HEAD") {
|
|
1339
|
+
const body = await responseBodyText(response);
|
|
1340
|
+
result.bytes = body.bytes;
|
|
1341
|
+
if (check.body_contains?.length) {
|
|
1342
|
+
result.body_contains = Object.fromEntries(check.body_contains.filter(Boolean).map((snippet) => [snippet, body.text.includes(snippet)]));
|
|
1343
|
+
}
|
|
1344
|
+
if (check.body_not_contains?.length) {
|
|
1345
|
+
result.body_not_contains = Object.fromEntries(check.body_not_contains.filter(Boolean).map((snippet) => [snippet, body.text.includes(snippet)]));
|
|
1346
|
+
}
|
|
1347
|
+
if (check.body_not_patterns?.length) {
|
|
1348
|
+
result.body_not_patterns = Object.fromEntries(check.body_not_patterns.filter(Boolean).map((pattern) => [pattern, new RegExp(pattern).test(body.text)]));
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
} catch (caught) {
|
|
1352
|
+
error = String(caught instanceof Error ? caught.message : caught).slice(0, 500);
|
|
1353
|
+
result.error = error;
|
|
1354
|
+
}
|
|
1355
|
+
const bodyContainsMissing = httpStatusBodyContainsFailures(result, check);
|
|
1356
|
+
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(result, check);
|
|
1357
|
+
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(result, check);
|
|
1358
|
+
const ok = !error && linkStatusResultOk(result, check);
|
|
1359
|
+
return {
|
|
1360
|
+
index,
|
|
1361
|
+
label: checkLabel(check) || `checks[${index}]`,
|
|
1362
|
+
url,
|
|
1363
|
+
method,
|
|
1364
|
+
ok,
|
|
1365
|
+
status: numberValue(result.status) ?? null,
|
|
1366
|
+
status_text: statusText,
|
|
1367
|
+
error,
|
|
1368
|
+
content_type: stringValue(result.content_type) ?? null,
|
|
1369
|
+
content_length: numberValue(result.content_length) ?? null,
|
|
1370
|
+
bytes: numberValue(result.bytes) ?? null,
|
|
1371
|
+
body_contains: isRecord(result.body_contains) ? Object.fromEntries(Object.entries(result.body_contains).map(([key, value]) => [key, value === true])) : null,
|
|
1372
|
+
body_contains_missing: bodyContainsMissing,
|
|
1373
|
+
body_not_contains: isRecord(result.body_not_contains) ? Object.fromEntries(Object.entries(result.body_not_contains).map(([key, value]) => [key, value === true])) : null,
|
|
1374
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
1375
|
+
body_not_patterns: isRecord(result.body_not_patterns) ? Object.fromEntries(Object.entries(result.body_not_patterns).map(([key, value]) => [key, value === true])) : null,
|
|
1376
|
+
body_not_patterns_found: bodyNotPatternsFound
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
async function preflightRiddleProofProfileHttpStatusChecks(profile, options = {}) {
|
|
1380
|
+
const targetUrl = options.target_url || resolveRiddleProofProfileTargetUrl(profile);
|
|
1381
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
1382
|
+
if (typeof fetchImpl !== "function") {
|
|
1383
|
+
throw new Error("profile http_status preflight requires fetch support or options.fetchImpl.");
|
|
1384
|
+
}
|
|
1385
|
+
const httpStatusChecks = profile.checks.map((check, index) => ({ check, index })).filter((item) => item.check.type === "http_status");
|
|
1386
|
+
const checks = await Promise.all(httpStatusChecks.map((item) => preflightHttpStatusCheck(item.check, item.index, targetUrl, fetchImpl)));
|
|
1387
|
+
const failed = checks.filter((check) => !check.ok).length;
|
|
1388
|
+
return {
|
|
1389
|
+
version: "riddle-proof.profile-http-status-preflight.v1",
|
|
1390
|
+
ok: failed === 0,
|
|
1391
|
+
profile_name: profile.name,
|
|
1392
|
+
target_url: targetUrl,
|
|
1393
|
+
checked: checks.length,
|
|
1394
|
+
failed,
|
|
1395
|
+
checks,
|
|
1396
|
+
summary: failed === 0 ? `${profile.name} http_status preflight passed ${checks.length} check(s).` : `${profile.name} http_status preflight failed ${failed} of ${checks.length} check(s).`
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1270
1399
|
function httpStatusEvidenceForCheck(viewport, check) {
|
|
1271
1400
|
const evidence = viewport.http_statuses?.[httpStatusKey(check, viewport.url)];
|
|
1272
1401
|
return isRecord(evidence) ? evidence : void 0;
|
|
@@ -5970,6 +6099,7 @@ function extractRiddleProofProfileResult(input) {
|
|
|
5970
6099
|
deriveRiddleProofArtifactBodyAssertions,
|
|
5971
6100
|
extractRiddleProofProfileResult,
|
|
5972
6101
|
normalizeRiddleProofProfile,
|
|
6102
|
+
preflightRiddleProofProfileHttpStatusChecks,
|
|
5973
6103
|
profileStatusExitCode,
|
|
5974
6104
|
resolveRiddleProofProfileRouteUrl,
|
|
5975
6105
|
resolveRiddleProofProfileTargetUrl,
|
package/dist/profile.d.cts
CHANGED
|
@@ -28,6 +28,49 @@ interface RiddleProofArtifactBodyAssertionResult {
|
|
|
28
28
|
missing_required: string[];
|
|
29
29
|
warnings: string[];
|
|
30
30
|
}
|
|
31
|
+
interface RiddleProofProfileHttpStatusPreflightFetchResponse {
|
|
32
|
+
status?: number;
|
|
33
|
+
statusText?: string;
|
|
34
|
+
headers?: {
|
|
35
|
+
get?: (name: string) => string | null;
|
|
36
|
+
};
|
|
37
|
+
arrayBuffer?: () => Promise<ArrayBuffer>;
|
|
38
|
+
text?: () => Promise<string>;
|
|
39
|
+
}
|
|
40
|
+
type RiddleProofProfileHttpStatusPreflightFetch = (url: string, init?: Record<string, unknown>) => Promise<RiddleProofProfileHttpStatusPreflightFetchResponse>;
|
|
41
|
+
interface RiddleProofProfileHttpStatusPreflightOptions {
|
|
42
|
+
fetchImpl?: RiddleProofProfileHttpStatusPreflightFetch;
|
|
43
|
+
target_url?: string;
|
|
44
|
+
}
|
|
45
|
+
interface RiddleProofProfileHttpStatusPreflightCheckResult {
|
|
46
|
+
index: number;
|
|
47
|
+
label: string;
|
|
48
|
+
url: string;
|
|
49
|
+
method: string;
|
|
50
|
+
ok: boolean;
|
|
51
|
+
status: number | null;
|
|
52
|
+
status_text: string;
|
|
53
|
+
error: string | null;
|
|
54
|
+
content_type: string | null;
|
|
55
|
+
content_length: number | null;
|
|
56
|
+
bytes: number | null;
|
|
57
|
+
body_contains: Record<string, boolean> | null;
|
|
58
|
+
body_contains_missing: string[];
|
|
59
|
+
body_not_contains: Record<string, boolean> | null;
|
|
60
|
+
body_not_contains_found: string[];
|
|
61
|
+
body_not_patterns: Record<string, boolean> | null;
|
|
62
|
+
body_not_patterns_found: string[];
|
|
63
|
+
}
|
|
64
|
+
interface RiddleProofProfileHttpStatusPreflightResult {
|
|
65
|
+
version: "riddle-proof.profile-http-status-preflight.v1";
|
|
66
|
+
ok: boolean;
|
|
67
|
+
profile_name: string;
|
|
68
|
+
target_url: string;
|
|
69
|
+
checked: number;
|
|
70
|
+
failed: number;
|
|
71
|
+
checks: RiddleProofProfileHttpStatusPreflightCheckResult[];
|
|
72
|
+
summary: string;
|
|
73
|
+
}
|
|
31
74
|
declare function deriveRiddleProofArtifactBodyAssertions(input: RiddleProofArtifactBodyAssertionInput): RiddleProofArtifactBodyAssertionResult;
|
|
32
75
|
interface RiddleProofProfileViewport {
|
|
33
76
|
name: string;
|
|
@@ -313,6 +356,7 @@ declare function collectRiddleProofProfileWarnings(profile: RiddleProofProfile):
|
|
|
313
356
|
declare function normalizeRiddleProofProfile(input: unknown, options?: NormalizeRiddleProofProfileOptions): RiddleProofProfile;
|
|
314
357
|
declare function resolveRiddleProofProfileTargetUrl(profile: RiddleProofProfile): string;
|
|
315
358
|
declare function resolveRiddleProofProfileTimeoutSec(profile: RiddleProofProfile, requestedTimeoutSec?: number): number | undefined;
|
|
359
|
+
declare function preflightRiddleProofProfileHttpStatusChecks(profile: RiddleProofProfile, options?: RiddleProofProfileHttpStatusPreflightOptions): Promise<RiddleProofProfileHttpStatusPreflightResult>;
|
|
316
360
|
declare function resolveRiddleProofProfileRouteUrl(targetUrl: string, route: string): string;
|
|
317
361
|
declare function assessRiddleProofProfileEvidence(profile: RiddleProofProfile, evidence: RiddleProofProfileEvidence | undefined, options?: {
|
|
318
362
|
runner?: RiddleProofProfileRunner;
|
|
@@ -345,4 +389,4 @@ declare function buildRiddleProofProfileScript(profile: RiddleProofProfile): str
|
|
|
345
389
|
declare function collectRiddleProfileArtifactRefs(input: unknown): RiddleProofProfileArtifactRef[];
|
|
346
390
|
declare function extractRiddleProofProfileResult(input: unknown): RiddleProofProfileResult | undefined;
|
|
347
391
|
|
|
348
|
-
export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofArtifactBodyAssertionInput, type RiddleProofArtifactBodyAssertionResult, type RiddleProofProfile, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileBoundsOffender, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileNetworkAbortErrorCode, type RiddleProofProfileNetworkMock, type RiddleProofProfileNetworkMockResponse, type RiddleProofProfileResult, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRouteInventoryRoute, type RiddleProofProfileRunner, type RiddleProofProfileSetupAction, type RiddleProofProfileSetupActionType, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
|
|
392
|
+
export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofArtifactBodyAssertionInput, type RiddleProofArtifactBodyAssertionResult, type RiddleProofProfile, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileBoundsOffender, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileHttpStatusPreflightCheckResult, type RiddleProofProfileHttpStatusPreflightFetch, type RiddleProofProfileHttpStatusPreflightFetchResponse, type RiddleProofProfileHttpStatusPreflightOptions, type RiddleProofProfileHttpStatusPreflightResult, type RiddleProofProfileNetworkAbortErrorCode, type RiddleProofProfileNetworkMock, type RiddleProofProfileNetworkMockResponse, type RiddleProofProfileResult, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRouteInventoryRoute, type RiddleProofProfileRunner, type RiddleProofProfileSetupAction, type RiddleProofProfileSetupActionType, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, preflightRiddleProofProfileHttpStatusChecks, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
|
package/dist/profile.d.ts
CHANGED
|
@@ -28,6 +28,49 @@ interface RiddleProofArtifactBodyAssertionResult {
|
|
|
28
28
|
missing_required: string[];
|
|
29
29
|
warnings: string[];
|
|
30
30
|
}
|
|
31
|
+
interface RiddleProofProfileHttpStatusPreflightFetchResponse {
|
|
32
|
+
status?: number;
|
|
33
|
+
statusText?: string;
|
|
34
|
+
headers?: {
|
|
35
|
+
get?: (name: string) => string | null;
|
|
36
|
+
};
|
|
37
|
+
arrayBuffer?: () => Promise<ArrayBuffer>;
|
|
38
|
+
text?: () => Promise<string>;
|
|
39
|
+
}
|
|
40
|
+
type RiddleProofProfileHttpStatusPreflightFetch = (url: string, init?: Record<string, unknown>) => Promise<RiddleProofProfileHttpStatusPreflightFetchResponse>;
|
|
41
|
+
interface RiddleProofProfileHttpStatusPreflightOptions {
|
|
42
|
+
fetchImpl?: RiddleProofProfileHttpStatusPreflightFetch;
|
|
43
|
+
target_url?: string;
|
|
44
|
+
}
|
|
45
|
+
interface RiddleProofProfileHttpStatusPreflightCheckResult {
|
|
46
|
+
index: number;
|
|
47
|
+
label: string;
|
|
48
|
+
url: string;
|
|
49
|
+
method: string;
|
|
50
|
+
ok: boolean;
|
|
51
|
+
status: number | null;
|
|
52
|
+
status_text: string;
|
|
53
|
+
error: string | null;
|
|
54
|
+
content_type: string | null;
|
|
55
|
+
content_length: number | null;
|
|
56
|
+
bytes: number | null;
|
|
57
|
+
body_contains: Record<string, boolean> | null;
|
|
58
|
+
body_contains_missing: string[];
|
|
59
|
+
body_not_contains: Record<string, boolean> | null;
|
|
60
|
+
body_not_contains_found: string[];
|
|
61
|
+
body_not_patterns: Record<string, boolean> | null;
|
|
62
|
+
body_not_patterns_found: string[];
|
|
63
|
+
}
|
|
64
|
+
interface RiddleProofProfileHttpStatusPreflightResult {
|
|
65
|
+
version: "riddle-proof.profile-http-status-preflight.v1";
|
|
66
|
+
ok: boolean;
|
|
67
|
+
profile_name: string;
|
|
68
|
+
target_url: string;
|
|
69
|
+
checked: number;
|
|
70
|
+
failed: number;
|
|
71
|
+
checks: RiddleProofProfileHttpStatusPreflightCheckResult[];
|
|
72
|
+
summary: string;
|
|
73
|
+
}
|
|
31
74
|
declare function deriveRiddleProofArtifactBodyAssertions(input: RiddleProofArtifactBodyAssertionInput): RiddleProofArtifactBodyAssertionResult;
|
|
32
75
|
interface RiddleProofProfileViewport {
|
|
33
76
|
name: string;
|
|
@@ -313,6 +356,7 @@ declare function collectRiddleProofProfileWarnings(profile: RiddleProofProfile):
|
|
|
313
356
|
declare function normalizeRiddleProofProfile(input: unknown, options?: NormalizeRiddleProofProfileOptions): RiddleProofProfile;
|
|
314
357
|
declare function resolveRiddleProofProfileTargetUrl(profile: RiddleProofProfile): string;
|
|
315
358
|
declare function resolveRiddleProofProfileTimeoutSec(profile: RiddleProofProfile, requestedTimeoutSec?: number): number | undefined;
|
|
359
|
+
declare function preflightRiddleProofProfileHttpStatusChecks(profile: RiddleProofProfile, options?: RiddleProofProfileHttpStatusPreflightOptions): Promise<RiddleProofProfileHttpStatusPreflightResult>;
|
|
316
360
|
declare function resolveRiddleProofProfileRouteUrl(targetUrl: string, route: string): string;
|
|
317
361
|
declare function assessRiddleProofProfileEvidence(profile: RiddleProofProfile, evidence: RiddleProofProfileEvidence | undefined, options?: {
|
|
318
362
|
runner?: RiddleProofProfileRunner;
|
|
@@ -345,4 +389,4 @@ declare function buildRiddleProofProfileScript(profile: RiddleProofProfile): str
|
|
|
345
389
|
declare function collectRiddleProfileArtifactRefs(input: unknown): RiddleProofProfileArtifactRef[];
|
|
346
390
|
declare function extractRiddleProofProfileResult(input: unknown): RiddleProofProfileResult | undefined;
|
|
347
391
|
|
|
348
|
-
export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofArtifactBodyAssertionInput, type RiddleProofArtifactBodyAssertionResult, type RiddleProofProfile, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileBoundsOffender, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileNetworkAbortErrorCode, type RiddleProofProfileNetworkMock, type RiddleProofProfileNetworkMockResponse, type RiddleProofProfileResult, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRouteInventoryRoute, type RiddleProofProfileRunner, type RiddleProofProfileSetupAction, type RiddleProofProfileSetupActionType, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
|
|
392
|
+
export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofArtifactBodyAssertionInput, type RiddleProofArtifactBodyAssertionResult, type RiddleProofProfile, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileBoundsOffender, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileHttpStatusPreflightCheckResult, type RiddleProofProfileHttpStatusPreflightFetch, type RiddleProofProfileHttpStatusPreflightFetchResponse, type RiddleProofProfileHttpStatusPreflightOptions, type RiddleProofProfileHttpStatusPreflightResult, type RiddleProofProfileNetworkAbortErrorCode, type RiddleProofProfileNetworkMock, type RiddleProofProfileNetworkMockResponse, type RiddleProofProfileResult, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRouteInventoryRoute, type RiddleProofProfileRunner, type RiddleProofProfileSetupAction, type RiddleProofProfileSetupActionType, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, preflightRiddleProofProfileHttpStatusChecks, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
|
package/dist/profile.js
CHANGED
|
@@ -16,13 +16,14 @@ import {
|
|
|
16
16
|
deriveRiddleProofArtifactBodyAssertions,
|
|
17
17
|
extractRiddleProofProfileResult,
|
|
18
18
|
normalizeRiddleProofProfile,
|
|
19
|
+
preflightRiddleProofProfileHttpStatusChecks,
|
|
19
20
|
profileStatusExitCode,
|
|
20
21
|
resolveRiddleProofProfileRouteUrl,
|
|
21
22
|
resolveRiddleProofProfileTargetUrl,
|
|
22
23
|
resolveRiddleProofProfileTimeoutSec,
|
|
23
24
|
slugifyRiddleProofProfileName,
|
|
24
25
|
summarizeRiddleProofProfileResult
|
|
25
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-JVZWSI55.js";
|
|
26
27
|
export {
|
|
27
28
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
28
29
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|
|
@@ -41,6 +42,7 @@ export {
|
|
|
41
42
|
deriveRiddleProofArtifactBodyAssertions,
|
|
42
43
|
extractRiddleProofProfileResult,
|
|
43
44
|
normalizeRiddleProofProfile,
|
|
45
|
+
preflightRiddleProofProfileHttpStatusChecks,
|
|
44
46
|
profileStatusExitCode,
|
|
45
47
|
resolveRiddleProofProfileRouteUrl,
|
|
46
48
|
resolveRiddleProofProfileTargetUrl,
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "riddle-proof.profile.v1",
|
|
3
|
+
"name": "terminal-result-partial-evidence",
|
|
4
|
+
"target": {
|
|
5
|
+
"route": "/playground",
|
|
6
|
+
"viewports": [
|
|
7
|
+
{ "name": "mobile", "width": 390, "height": 844 },
|
|
8
|
+
{ "name": "tablet", "width": 820, "height": 1180 },
|
|
9
|
+
{ "name": "desktop", "width": 1440, "height": 1000 }
|
|
10
|
+
],
|
|
11
|
+
"timeout_sec": 300,
|
|
12
|
+
"wait_ms": 800,
|
|
13
|
+
"network_mocks": [
|
|
14
|
+
{
|
|
15
|
+
"label": "api-console-sync-terminal-error-with-partial-evidence",
|
|
16
|
+
"url": "**/v1/run",
|
|
17
|
+
"method": "POST",
|
|
18
|
+
"status": 200,
|
|
19
|
+
"content_type": "application/json",
|
|
20
|
+
"required_hit_count": 3,
|
|
21
|
+
"max_hit_count": 3,
|
|
22
|
+
"capture_request_body": true,
|
|
23
|
+
"request_body_contains": [
|
|
24
|
+
"\"sync\":true",
|
|
25
|
+
"\"include\":[\"screenshots\",\"console\",\"har\"]",
|
|
26
|
+
"terminal-result-template-screenshot"
|
|
27
|
+
],
|
|
28
|
+
"json": {
|
|
29
|
+
"status": "completed_error",
|
|
30
|
+
"success": false,
|
|
31
|
+
"job_id": "job_terminal_result_template",
|
|
32
|
+
"error": {
|
|
33
|
+
"message": "Synthetic terminal result template failed after collecting partial evidence"
|
|
34
|
+
},
|
|
35
|
+
"screenshots": [
|
|
36
|
+
{
|
|
37
|
+
"name": "terminal-result-template-screenshot",
|
|
38
|
+
"url": "https://cdn.example.invalid/terminal-result-template-screenshot.png"
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"console": [
|
|
42
|
+
{
|
|
43
|
+
"type": "log",
|
|
44
|
+
"text": "terminal result template collected console evidence"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"har": {
|
|
48
|
+
"log": {
|
|
49
|
+
"entries": [
|
|
50
|
+
{
|
|
51
|
+
"request": {
|
|
52
|
+
"method": "GET",
|
|
53
|
+
"url": "https://example.com/terminal-result-template-resource"
|
|
54
|
+
},
|
|
55
|
+
"response": {
|
|
56
|
+
"status": 500
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"billing": {
|
|
63
|
+
"actual_seconds": 30,
|
|
64
|
+
"cost_usd": 0.004
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"setup_actions": [
|
|
70
|
+
{ "type": "clear_storage", "storage": "both", "reload": true },
|
|
71
|
+
{ "type": "wait_for_selector", "selector": "[data-testid='api-console-page']", "timeout_ms": 30000 },
|
|
72
|
+
{ "type": "fill", "selector": "[data-testid='api-console-json']", "value": "{ \"steps\": [{ \"screenshot\": \"terminal-result-template-screenshot\" }], \"sync\": true, \"include\": [\"screenshots\", \"console\", \"har\"] }" },
|
|
73
|
+
{ "type": "clear_console" },
|
|
74
|
+
{ "type": "screenshot", "label": "terminal-result-before-submit" },
|
|
75
|
+
{ "type": "click", "selector": "[data-testid='run-api-console']", "text": "Run" },
|
|
76
|
+
{ "type": "wait_for_text", "selector": "body", "text": "Synthetic terminal result template failed after collecting partial evidence", "timeout_ms": 30000 },
|
|
77
|
+
{ "type": "wait_for_text", "selector": "body", "text": "partial results available", "timeout_ms": 30000 },
|
|
78
|
+
{ "type": "assert_text_visible", "selector": "body", "text": "terminal-result-template-screenshot", "timeout_ms": 5000 },
|
|
79
|
+
{ "type": "assert_text_visible", "selector": "body", "text": "terminal result template collected console evidence", "timeout_ms": 5000 },
|
|
80
|
+
{ "type": "assert_text_visible", "selector": "body", "text": "terminal-result-template-resource", "timeout_ms": 5000 },
|
|
81
|
+
{ "type": "assert_text_absent", "selector": "body", "text": "Success", "timeout_ms": 1000 },
|
|
82
|
+
{ "type": "assert_text_absent", "selector": "body", "text": "No screenshots captured", "timeout_ms": 1000 },
|
|
83
|
+
{ "type": "assert_text_absent", "selector": "body", "text": "No console output captured", "timeout_ms": 1000 },
|
|
84
|
+
{ "type": "assert_text_absent", "selector": "body", "text": "No network requests captured", "timeout_ms": 1000 },
|
|
85
|
+
{ "type": "screenshot", "label": "terminal-result-partial-evidence-expanded" }
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
"checks": [
|
|
89
|
+
{ "type": "route_loaded", "expected_path": "/playground" },
|
|
90
|
+
{ "type": "selector_visible", "selector": "[data-testid='api-console-page']" },
|
|
91
|
+
{ "type": "text_visible", "text": "Error" },
|
|
92
|
+
{ "type": "text_visible", "text": "Synthetic terminal result template failed after collecting partial evidence" },
|
|
93
|
+
{ "type": "text_visible", "text": "partial results available" },
|
|
94
|
+
{ "type": "selector_text_visible", "selector": "[data-testid='api-console-screenshots']", "text": "terminal-result-template-screenshot" },
|
|
95
|
+
{ "type": "selector_text_visible", "selector": "[data-testid='api-console-output']", "text": "terminal result template collected console evidence" },
|
|
96
|
+
{ "type": "selector_text_visible", "selector": "[data-testid='api-console-har']", "text": "terminal-result-template-resource" },
|
|
97
|
+
{ "type": "text_absent", "text": "Success" },
|
|
98
|
+
{ "type": "text_absent", "text": "No screenshots captured" },
|
|
99
|
+
{ "type": "text_absent", "text": "No console output captured" },
|
|
100
|
+
{ "type": "text_absent", "text": "No network requests captured" },
|
|
101
|
+
{ "type": "text_absent", "text": "Application error" },
|
|
102
|
+
{ "type": "selector_count_equals", "selector": "[data-testid='api-console-error-indicator']", "expected_count": 1 },
|
|
103
|
+
{ "type": "selector_count_equals", "selector": "[data-testid='api-console-timeout-indicator']", "expected_count": 0 },
|
|
104
|
+
{ "type": "selector_count_equals", "selector": "[data-testid='api-console-success-indicator']", "expected_count": 0 },
|
|
105
|
+
{ "type": "selector_count_equals", "selector": "[data-testid='api-console-screenshot-item']", "expected_count": 1 },
|
|
106
|
+
{ "type": "selector_count_at_least", "selector": "[data-testid='api-console-output']", "min_count": 1 },
|
|
107
|
+
{ "type": "selector_count_at_least", "selector": "[data-testid='api-console-har']", "min_count": 1 },
|
|
108
|
+
{ "type": "no_horizontal_overflow", "max_overflow_px": 1 },
|
|
109
|
+
{ "type": "no_fatal_console_errors" },
|
|
110
|
+
{ "type": "no_console_warnings" }
|
|
111
|
+
],
|
|
112
|
+
"artifacts": ["screenshot", "console", "dom_summary", "proof_json"],
|
|
113
|
+
"baseline_policy": "invariant_only",
|
|
114
|
+
"failure_policy": {
|
|
115
|
+
"environment_blocked": "neutral",
|
|
116
|
+
"proof_insufficient": "fail",
|
|
117
|
+
"product_regression": "fail"
|
|
118
|
+
},
|
|
119
|
+
"metadata": {
|
|
120
|
+
"purpose": "Template for API-console terminal result honesty: return a terminal error or timeout JSON response with partial screenshot, console, and HAR evidence; require visible status honesty, partial-results copy, each artifact class, correct success/error/timeout selector polarity, no contradictory empty-evidence copy, and clean browser evidence. For timeout variants, change the mocked status and visible status checks to the product's timeout indicator while preserving the same partial-evidence contract."
|
|
121
|
+
}
|
|
122
|
+
}
|