@riddledc/riddle-proof 0.7.122 → 0.7.124

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,6 +216,23 @@ 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.
@@ -570,6 +587,8 @@ JSON, YAML, robots, sitemap, or other machine-readable endpoint:
570
587
  text. Use `text_visible` or `selector_text_visible` when CSS transforms,
571
588
  hydration, client rendering, hidden elements, or layout-specific copy should be
572
589
  judged exactly as the browser exposes it to users.
590
+ Hosted `summary.md` includes `http_status` body assertion pass counts so a
591
+ reviewer can see raw body proof coverage without opening `proof.json`.
573
592
 
574
593
  When the profile target is a mounted Riddle static Preview such as
575
594
  `https://preview.riddledc.com/s/ps_1234abcd/docs/`, root-relative
@@ -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}`,
@@ -13485,6 +13635,17 @@ function profileLinkStatusSummaryMarkdown(result) {
13485
13635
  }
13486
13636
  return lines;
13487
13637
  }
13638
+ function profileHttpStatusAssertionCount(viewports, field, expected, passValue) {
13639
+ if (!expected.length || !viewports.length) return void 0;
13640
+ let passed = 0;
13641
+ for (const viewport of viewports) {
13642
+ const observed = cliRecord(viewport[field]);
13643
+ for (const value of expected) {
13644
+ if (observed?.[value] === passValue) passed += 1;
13645
+ }
13646
+ }
13647
+ return { passed, total: expected.length * viewports.length };
13648
+ }
13488
13649
  function profileHttpStatusSummaryMarkdown(result) {
13489
13650
  const httpStatusChecks = result.checks.filter((check) => check.type === "http_status");
13490
13651
  const lines = [];
@@ -13497,8 +13658,16 @@ function profileHttpStatusSummaryMarkdown(result) {
13497
13658
  const viewports = Array.isArray(evidence.viewports) ? evidence.viewports.map(cliRecord).filter((viewport) => Boolean(viewport)) : [];
13498
13659
  const statuses = viewports.map((viewport) => cliFiniteNumber(viewport.status)).map((status) => status === void 0 ? "error" : String(status));
13499
13660
  const failedTotal = Array.isArray(evidence.failures) ? evidence.failures.length : 0;
13661
+ const bodyContains = profileHttpStatusAssertionCount(viewports, "body_contains", cliStringArray(evidence.body_contains), true);
13662
+ const bodyNotContains = profileHttpStatusAssertionCount(viewports, "body_not_contains", cliStringArray(evidence.body_not_contains), false);
13663
+ const bodyNotPatterns = profileHttpStatusAssertionCount(viewports, "body_not_patterns", cliStringArray(evidence.body_not_patterns), false);
13664
+ const bodyParts = [
13665
+ bodyContains ? `body_contains ${bodyContains.passed}/${bodyContains.total}` : "",
13666
+ bodyNotContains ? `body_not_contains clean ${bodyNotContains.passed}/${bodyNotContains.total}` : "",
13667
+ bodyNotPatterns ? `body_not_patterns clean ${bodyNotPatterns.passed}/${bodyNotPatterns.total}` : ""
13668
+ ].filter(Boolean);
13500
13669
  lines.push(
13501
- `- ${label}: ${method}${url ? ` ${markdownInlineCode(url)}` : ""}, statuses ${statuses.length ? statuses.join("/") : "unknown"}, failures ${failedTotal}`
13670
+ `- ${label}: ${method}${url ? ` ${markdownInlineCode(url)}` : ""}, statuses ${statuses.length ? statuses.join("/") : "unknown"}${bodyParts.length ? `, ${bodyParts.join(", ")}` : ""}, failures ${failedTotal}`
13502
13671
  );
13503
13672
  }
13504
13673
  return lines;
@@ -13691,6 +13860,21 @@ async function main() {
13691
13860
  process.exitCode = profileStatusExitCode(profile, result.status);
13692
13861
  return;
13693
13862
  }
13863
+ if (command === "profile-http-status-preflight") {
13864
+ const profile = normalizeProfileForCli(options);
13865
+ const result = await preflightRiddleProofProfileHttpStatusChecks(profile);
13866
+ const format = optionString(options, "format") || "json";
13867
+ if (format === "summary") {
13868
+ process.stdout.write(profileHttpStatusPreflightSummary(result));
13869
+ } else if (format === "json") {
13870
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
13871
+ `);
13872
+ } else {
13873
+ throw new Error("--format must be json or summary.");
13874
+ }
13875
+ process.exitCode = result.ok ? 0 : 1;
13876
+ return;
13877
+ }
13694
13878
  if (command === "profile-body-assertions") {
13695
13879
  const artifactText = await readTextValue(optionString(options, "artifact") ?? optionString(options, "input"), "--artifact");
13696
13880
  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}`,
@@ -694,6 +717,17 @@ function profileLinkStatusSummaryMarkdown(result) {
694
717
  }
695
718
  return lines;
696
719
  }
720
+ function profileHttpStatusAssertionCount(viewports, field, expected, passValue) {
721
+ if (!expected.length || !viewports.length) return void 0;
722
+ let passed = 0;
723
+ for (const viewport of viewports) {
724
+ const observed = cliRecord(viewport[field]);
725
+ for (const value of expected) {
726
+ if (observed?.[value] === passValue) passed += 1;
727
+ }
728
+ }
729
+ return { passed, total: expected.length * viewports.length };
730
+ }
697
731
  function profileHttpStatusSummaryMarkdown(result) {
698
732
  const httpStatusChecks = result.checks.filter((check) => check.type === "http_status");
699
733
  const lines = [];
@@ -706,8 +740,16 @@ function profileHttpStatusSummaryMarkdown(result) {
706
740
  const viewports = Array.isArray(evidence.viewports) ? evidence.viewports.map(cliRecord).filter((viewport) => Boolean(viewport)) : [];
707
741
  const statuses = viewports.map((viewport) => cliFiniteNumber(viewport.status)).map((status) => status === void 0 ? "error" : String(status));
708
742
  const failedTotal = Array.isArray(evidence.failures) ? evidence.failures.length : 0;
743
+ const bodyContains = profileHttpStatusAssertionCount(viewports, "body_contains", cliStringArray(evidence.body_contains), true);
744
+ const bodyNotContains = profileHttpStatusAssertionCount(viewports, "body_not_contains", cliStringArray(evidence.body_not_contains), false);
745
+ const bodyNotPatterns = profileHttpStatusAssertionCount(viewports, "body_not_patterns", cliStringArray(evidence.body_not_patterns), false);
746
+ const bodyParts = [
747
+ bodyContains ? `body_contains ${bodyContains.passed}/${bodyContains.total}` : "",
748
+ bodyNotContains ? `body_not_contains clean ${bodyNotContains.passed}/${bodyNotContains.total}` : "",
749
+ bodyNotPatterns ? `body_not_patterns clean ${bodyNotPatterns.passed}/${bodyNotPatterns.total}` : ""
750
+ ].filter(Boolean);
709
751
  lines.push(
710
- `- ${label}: ${method}${url ? ` ${markdownInlineCode(url)}` : ""}, statuses ${statuses.length ? statuses.join("/") : "unknown"}, failures ${failedTotal}`
752
+ `- ${label}: ${method}${url ? ` ${markdownInlineCode(url)}` : ""}, statuses ${statuses.length ? statuses.join("/") : "unknown"}${bodyParts.length ? `, ${bodyParts.join(", ")}` : ""}, failures ${failedTotal}`
711
753
  );
712
754
  }
713
755
  return lines;
@@ -900,6 +942,21 @@ async function main() {
900
942
  process.exitCode = profileStatusExitCode(profile, result.status);
901
943
  return;
902
944
  }
945
+ if (command === "profile-http-status-preflight") {
946
+ const profile = normalizeProfileForCli(options);
947
+ const result = await preflightRiddleProofProfileHttpStatusChecks(profile);
948
+ const format = optionString(options, "format") || "json";
949
+ if (format === "summary") {
950
+ process.stdout.write(profileHttpStatusPreflightSummary(result));
951
+ } else if (format === "json") {
952
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
953
+ `);
954
+ } else {
955
+ throw new Error("--format must be json or summary.");
956
+ }
957
+ process.exitCode = result.ok ? 0 : 1;
958
+ return;
959
+ }
903
960
  if (command === "profile-body-assertions") {
904
961
  const artifactText = await readTextValue(optionString(options, "artifact") ?? optionString(options, "input"), "--artifact");
905
962
  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,
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
295
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
385
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
662
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
295
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
385
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
662
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.122",
3
+ "version": "0.7.124",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",