@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 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-TBEVHMU3.js";
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-TBEVHMU3.js";
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,
@@ -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-TBEVHMU3.js";
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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.121",
3
+ "version": "0.7.123",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",