@riddledc/riddle-proof 0.7.97 → 0.7.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -8758,6 +8758,7 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
8758
8758
  "frame_no_horizontal_overflow",
8759
8759
  "text_visible",
8760
8760
  "text_absent",
8761
+ "http_status",
8761
8762
  "link_status",
8762
8763
  "artifact_link_status",
8763
8764
  "route_inventory",
@@ -9507,19 +9508,34 @@ function normalizeCheck(input, index) {
9507
9508
  if (type === "route_inventory" && !expectedRoutes?.length) {
9508
9509
  throw new Error(`checks[${index}] route_inventory requires expected_routes.`);
9509
9510
  }
9511
+ const isHttpStatusCheck = type === "http_status";
9510
9512
  const isLinkStatusCheck = type === "link_status" || type === "artifact_link_status";
9511
- const expectedStatus = isLinkStatusCheck ? normalizeHttpStatus(input.expected_status ?? input.expectedStatus ?? input.status, `checks[${index}] expected_status`) : void 0;
9512
- const allowedStatuses = isLinkStatusCheck ? normalizeHttpStatuses(
9513
+ const isStatusCheck = isHttpStatusCheck || isLinkStatusCheck;
9514
+ const requestUrl = stringFromOwn(input, "url", "endpoint_url", "endpointUrl", "endpoint", "request_url", "requestUrl", "path");
9515
+ if (isHttpStatusCheck && !requestUrl) {
9516
+ throw new Error(`checks[${index}] http_status requires url.`);
9517
+ }
9518
+ const method = stringFromOwn(input, "method", "http_method", "httpMethod")?.toUpperCase();
9519
+ if (isHttpStatusCheck && method && !/^[A-Z]+$/.test(method)) {
9520
+ throw new Error(`checks[${index}] http_status method must contain only letters.`);
9521
+ }
9522
+ const hasBodyJson = hasOwn(input, "body_json") || hasOwn(input, "bodyJson") || hasOwn(input, "json");
9523
+ const expectedStatus = isStatusCheck ? normalizeHttpStatus(input.expected_status ?? input.expectedStatus ?? input.status, `checks[${index}] expected_status`) : void 0;
9524
+ const allowedStatuses = isStatusCheck ? normalizeHttpStatuses(
9513
9525
  input.allowed_statuses ?? input.allowedStatuses ?? input.expected_statuses ?? input.expectedStatuses,
9514
9526
  `checks[${index}] allowed_statuses`
9515
9527
  ) : void 0;
9516
9528
  const maxLinks = isLinkStatusCheck ? normalizePositiveInteger(input.max_links ?? input.maxLinks ?? input.limit, `checks[${index}] max_links`, 500) : void 0;
9517
- const minBytes = isLinkStatusCheck ? normalizePositiveInteger(input.min_bytes ?? input.minBytes ?? input.min_response_bytes ?? input.minResponseBytes, `checks[${index}] min_bytes`) : void 0;
9518
- const expectedContentType = isLinkStatusCheck ? stringValue5(input.expected_content_type) || stringValue5(input.expectedContentType) || stringValue5(input.content_type) || stringValue5(input.contentType) : void 0;
9519
- const allowedContentTypes = isLinkStatusCheck ? normalizeStringList(
9529
+ const minBytes = isStatusCheck ? normalizePositiveInteger(input.min_bytes ?? input.minBytes ?? input.min_response_bytes ?? input.minResponseBytes, `checks[${index}] min_bytes`) : void 0;
9530
+ const expectedContentType = isStatusCheck ? stringValue5(input.expected_content_type) || stringValue5(input.expectedContentType) || stringValue5(input.content_type) || stringValue5(input.contentType) : void 0;
9531
+ const allowedContentTypes = isStatusCheck ? normalizeStringList(
9520
9532
  input.allowed_content_types ?? input.allowedContentTypes ?? input.expected_content_types ?? input.expectedContentTypes,
9521
9533
  `checks[${index}] allowed_content_types`
9522
9534
  ) ?? (expectedContentType ? [expectedContentType] : void 0) : void 0;
9535
+ const bodyContains = isHttpStatusCheck ? normalizeStringList(
9536
+ input.body_contains ?? input.bodyContains ?? input.expected_body_contains ?? input.expectedBodyContains ?? input.response_body_contains ?? input.responseBodyContains ?? input.body_includes ?? input.bodyIncludes,
9537
+ `checks[${index}] body_contains`
9538
+ ) : void 0;
9523
9539
  if (isLinkStatusCheck) {
9524
9540
  if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
9525
9541
  throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
@@ -9537,6 +9553,12 @@ function normalizeCheck(input, index) {
9537
9553
  expected_url: expectedUrl,
9538
9554
  expected_routes: expectedRoutes,
9539
9555
  selector: stringValue5(input.selector),
9556
+ url: isHttpStatusCheck ? requestUrl : void 0,
9557
+ method: isHttpStatusCheck ? method || "GET" : void 0,
9558
+ headers: isHttpStatusCheck ? stringRecord(input.headers) : void 0,
9559
+ body: isHttpStatusCheck ? stringValue5(input.body) : void 0,
9560
+ body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
9561
+ body_contains: bodyContains,
9540
9562
  expected_texts: expectedTexts,
9541
9563
  link_selector: stringValue5(input.link_selector) || stringValue5(input.linkSelector),
9542
9564
  source_selector: stringValue5(input.source_selector) || stringValue5(input.sourceSelector),
@@ -9560,7 +9582,7 @@ function normalizeCheck(input, index) {
9560
9582
  max_links: maxLinks,
9561
9583
  same_origin_only: isLinkStatusCheck ? input.same_origin_only === true || input.sameOriginOnly === true : void 0,
9562
9584
  dedupe: isLinkStatusCheck ? input.dedupe === false ? false : true : void 0,
9563
- require_nonzero_bytes: isLinkStatusCheck ? input.require_nonzero_bytes === true || input.requireNonzeroBytes === true : void 0,
9585
+ require_nonzero_bytes: isStatusCheck ? input.require_nonzero_bytes === true || input.requireNonzeroBytes === true : void 0,
9564
9586
  min_bytes: minBytes,
9565
9587
  allowed_content_types: allowedContentTypes,
9566
9588
  allow_get_fallback: isLinkStatusCheck ? input.allow_get_fallback === false || input.allowGetFallback === false ? false : true : void 0,
@@ -9659,14 +9681,32 @@ function selectorKey(check) {
9659
9681
  function linkStatusSelector(check) {
9660
9682
  return check.selector || check.link_selector || "a[href]";
9661
9683
  }
9662
- function linkStatusAllowedStatuses(check) {
9684
+ function httpStatusRequestUrl(check, baseUrl) {
9685
+ const rawUrl = check.url || "";
9686
+ if (!rawUrl) return "";
9687
+ try {
9688
+ return baseUrl ? new URL(rawUrl, baseUrl).href : new URL(rawUrl).href;
9689
+ } catch {
9690
+ return rawUrl;
9691
+ }
9692
+ }
9693
+ function httpStatusMethod(check) {
9694
+ return (check.method || "GET").toUpperCase();
9695
+ }
9696
+ function httpStatusKey(check, baseUrl) {
9697
+ return `${httpStatusMethod(check)} ${httpStatusRequestUrl(check, baseUrl)}`;
9698
+ }
9699
+ function httpStatusAllowedStatuses(check) {
9663
9700
  if (check.allowed_statuses?.length) return check.allowed_statuses;
9664
9701
  if (check.expected_status !== void 0) return [check.expected_status];
9665
9702
  return void 0;
9666
9703
  }
9667
- function linkStatusIsAllowed(status, check) {
9704
+ function linkStatusAllowedStatuses(check) {
9705
+ return httpStatusAllowedStatuses(check);
9706
+ }
9707
+ function httpStatusIsAllowed(status, check) {
9668
9708
  if (status === void 0) return false;
9669
- const allowed = linkStatusAllowedStatuses(check);
9709
+ const allowed = httpStatusAllowedStatuses(check);
9670
9710
  return allowed?.length ? allowed.includes(status) : status >= 200 && status < 400;
9671
9711
  }
9672
9712
  function linkStatusObservedBytes(result) {
@@ -9690,9 +9730,15 @@ function linkStatusContentTypeOk(result, check) {
9690
9730
  return actual === normalized;
9691
9731
  });
9692
9732
  }
9733
+ function httpStatusBodyContainsFailures(result, check) {
9734
+ const expected = check.body_contains?.filter(Boolean) ?? [];
9735
+ if (!expected.length) return [];
9736
+ const observed = isRecord2(result.body_contains) ? result.body_contains : {};
9737
+ return expected.filter((text) => observed[text] !== true);
9738
+ }
9693
9739
  function linkStatusResultOk(result, check) {
9694
9740
  const status = numberValue3(result.status);
9695
- if (!linkStatusIsAllowed(status, check)) return false;
9741
+ if (!httpStatusIsAllowed(status, check)) return false;
9696
9742
  if (stringValue5(result.error)) return false;
9697
9743
  if (result.ok === false) return false;
9698
9744
  if (!linkStatusContentTypeOk(result, check)) return false;
@@ -9704,8 +9750,64 @@ function linkStatusResultOk(result, check) {
9704
9750
  const observedBytes = linkStatusObservedBytes(result);
9705
9751
  if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
9706
9752
  }
9753
+ if (httpStatusBodyContainsFailures(result, check).length) return false;
9707
9754
  return true;
9708
9755
  }
9756
+ function httpStatusEvidenceForCheck(viewport, check) {
9757
+ const evidence = viewport.http_statuses?.[httpStatusKey(check, viewport.url)];
9758
+ return isRecord2(evidence) ? evidence : void 0;
9759
+ }
9760
+ function summarizeHttpStatusEvidence(viewport, check) {
9761
+ const key = httpStatusKey(check, viewport.url);
9762
+ const statusEvidence = httpStatusEvidenceForCheck(viewport, check);
9763
+ if (!statusEvidence) {
9764
+ return {
9765
+ viewport: viewport.name,
9766
+ key,
9767
+ url: httpStatusRequestUrl(check, viewport.url),
9768
+ method: httpStatusMethod(check),
9769
+ ok: false,
9770
+ status: null,
9771
+ failures: [{ code: "http_status_evidence_missing" }]
9772
+ };
9773
+ }
9774
+ const failures = [];
9775
+ const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
9776
+ if (!linkStatusResultOk(statusEvidence, check)) {
9777
+ failures.push({
9778
+ code: "http_status_failed",
9779
+ url: stringValue5(statusEvidence.url) ?? httpStatusRequestUrl(check, viewport.url),
9780
+ status: numberValue3(statusEvidence.status) ?? null,
9781
+ method: stringValue5(statusEvidence.method) ?? httpStatusMethod(check),
9782
+ error: stringValue5(statusEvidence.error) ?? null,
9783
+ content_type: stringValue5(statusEvidence.content_type) ?? null,
9784
+ bytes: linkStatusObservedBytes(statusEvidence) ?? null,
9785
+ allowed_statuses: httpStatusAllowedStatuses(check) ?? ["2xx", "3xx"],
9786
+ min_bytes: check.min_bytes ?? null,
9787
+ allowed_content_types: check.allowed_content_types ?? null,
9788
+ body_contains: check.body_contains ?? null,
9789
+ body_contains_missing: bodyContainsMissing,
9790
+ body_sample: stringValue5(statusEvidence.body_sample) ?? null
9791
+ });
9792
+ }
9793
+ return {
9794
+ viewport: viewport.name,
9795
+ key,
9796
+ url: stringValue5(statusEvidence.url) ?? httpStatusRequestUrl(check, viewport.url),
9797
+ method: stringValue5(statusEvidence.method) ?? httpStatusMethod(check),
9798
+ status: numberValue3(statusEvidence.status) ?? null,
9799
+ status_text: stringValue5(statusEvidence.status_text) ?? null,
9800
+ ok: failures.length === 0,
9801
+ error: stringValue5(statusEvidence.error) ?? null,
9802
+ content_type: stringValue5(statusEvidence.content_type) ?? null,
9803
+ content_length: numberValue3(statusEvidence.content_length) ?? null,
9804
+ bytes: linkStatusObservedBytes(statusEvidence) ?? null,
9805
+ body_contains: isRecord2(statusEvidence.body_contains) ? toJsonValue(statusEvidence.body_contains) : null,
9806
+ body_contains_missing: bodyContainsMissing,
9807
+ body_sample: stringValue5(statusEvidence.body_sample) ?? null,
9808
+ failures
9809
+ };
9810
+ }
9709
9811
  function linkStatusEvidenceForCheck(viewport, check) {
9710
9812
  const evidence = viewport.link_statuses?.[linkStatusSelector(check)];
9711
9813
  return isRecord2(evidence) ? evidence : void 0;
@@ -10296,6 +10398,29 @@ function assessCheckFromEvidence(check, evidence) {
10296
10398
  message: failed ? `Text assertion failed in ${failed} viewport(s).` : void 0
10297
10399
  };
10298
10400
  }
10401
+ if (check.type === "http_status") {
10402
+ const url = httpStatusRequestUrl(check, evidence.target_url);
10403
+ const method = httpStatusMethod(check);
10404
+ const summaries = viewports.map((viewport) => summarizeHttpStatusEvidence(viewport, check));
10405
+ const failed = summaries.filter((summary) => Array.isArray(summary.failures) && summary.failures.length > 0);
10406
+ return {
10407
+ type: check.type,
10408
+ label: checkLabel(check),
10409
+ status: failed.length ? "failed" : "passed",
10410
+ evidence: {
10411
+ url,
10412
+ method,
10413
+ allowed_statuses: httpStatusAllowedStatuses(check) || ["2xx", "3xx"],
10414
+ require_nonzero_bytes: check.require_nonzero_bytes === true,
10415
+ min_bytes: check.min_bytes ?? null,
10416
+ allowed_content_types: check.allowed_content_types ?? null,
10417
+ body_contains: check.body_contains ?? [],
10418
+ viewports: summaries.map((summary) => toJsonValue(summary)),
10419
+ failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue5(summary.viewport) ?? null, failure })) : [])
10420
+ },
10421
+ message: failed.length ? `HTTP status failed in ${failed.length} viewport(s).` : void 0
10422
+ };
10423
+ }
10299
10424
  if (check.type === "link_status" || check.type === "artifact_link_status") {
10300
10425
  const selector = linkStatusSelector(check);
10301
10426
  const summaries = viewports.map((viewport) => summarizeLinkStatusEvidence(viewport, check));
@@ -10905,16 +11030,37 @@ function textOrderMatch(texts, expectedTexts) {
10905
11030
  function linkStatusSelector(check) {
10906
11031
  return check.selector || check.link_selector || "a[href]";
10907
11032
  }
10908
- function linkStatusAllowedStatuses(check) {
11033
+ function httpStatusRequestUrl(check, baseUrl) {
11034
+ const rawUrl = check.url || "";
11035
+ if (!rawUrl) return "";
11036
+ try {
11037
+ return baseUrl ? new URL(rawUrl, baseUrl).href : new URL(rawUrl).href;
11038
+ } catch {
11039
+ return rawUrl;
11040
+ }
11041
+ }
11042
+ function httpStatusMethod(check) {
11043
+ return String(check.method || "GET").toUpperCase();
11044
+ }
11045
+ function httpStatusKey(check, baseUrl) {
11046
+ return httpStatusMethod(check) + " " + httpStatusRequestUrl(check, baseUrl);
11047
+ }
11048
+ function httpStatusAllowedStatuses(check) {
10909
11049
  if (Array.isArray(check.allowed_statuses) && check.allowed_statuses.length) return check.allowed_statuses;
10910
11050
  if (typeof check.expected_status === "number" && Number.isFinite(check.expected_status)) return [check.expected_status];
10911
11051
  return undefined;
10912
11052
  }
10913
- function linkStatusIsAllowed(status, check) {
11053
+ function linkStatusAllowedStatuses(check) {
11054
+ return httpStatusAllowedStatuses(check);
11055
+ }
11056
+ function httpStatusIsAllowed(status, check) {
10914
11057
  if (typeof status !== "number" || !Number.isFinite(status)) return false;
10915
- const allowed = linkStatusAllowedStatuses(check);
11058
+ const allowed = httpStatusAllowedStatuses(check);
10916
11059
  return Array.isArray(allowed) && allowed.length ? allowed.includes(status) : status >= 200 && status < 400;
10917
11060
  }
11061
+ function linkStatusIsAllowed(status, check) {
11062
+ return httpStatusIsAllowed(status, check);
11063
+ }
10918
11064
  function linkStatusObservedBytes(result) {
10919
11065
  const bytes = typeof result.bytes === "number" && Number.isFinite(result.bytes) ? result.bytes : undefined;
10920
11066
  const contentLength = typeof result.content_length === "number" && Number.isFinite(result.content_length) ? result.content_length : undefined;
@@ -10937,9 +11083,17 @@ function linkStatusContentTypeOk(result, check) {
10937
11083
  return actual === normalized;
10938
11084
  });
10939
11085
  }
11086
+ function httpStatusBodyContainsFailures(result, check) {
11087
+ const expected = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
11088
+ if (!expected.length) return [];
11089
+ const observed = result && typeof result.body_contains === "object" && !Array.isArray(result.body_contains)
11090
+ ? result.body_contains
11091
+ : {};
11092
+ return expected.filter((text) => observed[text] !== true);
11093
+ }
10940
11094
  function linkStatusResultOk(result, check) {
10941
11095
  if (!result || typeof result !== "object" || Array.isArray(result)) return false;
10942
- if (!linkStatusIsAllowed(result.status, check)) return false;
11096
+ if (!httpStatusIsAllowed(result.status, check)) return false;
10943
11097
  if (typeof result.error === "string" && result.error.trim()) return false;
10944
11098
  if (result.ok === false) return false;
10945
11099
  if (!linkStatusContentTypeOk(result, check)) return false;
@@ -10951,8 +11105,62 @@ function linkStatusResultOk(result, check) {
10951
11105
  const observedBytes = linkStatusObservedBytes(result);
10952
11106
  if (observedBytes === undefined || observedBytes < check.min_bytes) return false;
10953
11107
  }
11108
+ if (httpStatusBodyContainsFailures(result, check).length) return false;
10954
11109
  return true;
10955
11110
  }
11111
+ function summarizeHttpStatusEvidence(viewport, check) {
11112
+ const key = httpStatusKey(check, viewport && viewport.url);
11113
+ const statusEvidence = viewport && viewport.http_statuses && viewport.http_statuses[key];
11114
+ if (!statusEvidence || typeof statusEvidence !== "object" || Array.isArray(statusEvidence)) {
11115
+ return {
11116
+ viewport: viewport && viewport.name,
11117
+ key,
11118
+ url: httpStatusRequestUrl(check, viewport && viewport.url),
11119
+ method: httpStatusMethod(check),
11120
+ ok: false,
11121
+ status: null,
11122
+ failures: [{ code: "http_status_evidence_missing" }],
11123
+ };
11124
+ }
11125
+ const failures = [];
11126
+ const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
11127
+ if (!linkStatusResultOk(statusEvidence, check)) {
11128
+ failures.push({
11129
+ code: "http_status_failed",
11130
+ url: typeof statusEvidence.url === "string" ? statusEvidence.url : httpStatusRequestUrl(check, viewport && viewport.url),
11131
+ status: typeof statusEvidence.status === "number" && Number.isFinite(statusEvidence.status) ? statusEvidence.status : null,
11132
+ method: typeof statusEvidence.method === "string" ? statusEvidence.method : httpStatusMethod(check),
11133
+ error: typeof statusEvidence.error === "string" ? statusEvidence.error : null,
11134
+ content_type: typeof statusEvidence.content_type === "string" ? statusEvidence.content_type : null,
11135
+ bytes: linkStatusObservedBytes(statusEvidence) ?? null,
11136
+ allowed_statuses: httpStatusAllowedStatuses(check) || ["2xx", "3xx"],
11137
+ min_bytes: typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes) ? check.min_bytes : null,
11138
+ allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
11139
+ body_contains: Array.isArray(check.body_contains) ? check.body_contains : null,
11140
+ body_contains_missing: bodyContainsMissing,
11141
+ body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
11142
+ });
11143
+ }
11144
+ return {
11145
+ viewport: viewport && viewport.name,
11146
+ key,
11147
+ url: typeof statusEvidence.url === "string" ? statusEvidence.url : httpStatusRequestUrl(check, viewport && viewport.url),
11148
+ method: typeof statusEvidence.method === "string" ? statusEvidence.method : httpStatusMethod(check),
11149
+ status: typeof statusEvidence.status === "number" && Number.isFinite(statusEvidence.status) ? statusEvidence.status : null,
11150
+ status_text: typeof statusEvidence.status_text === "string" ? statusEvidence.status_text : null,
11151
+ ok: failures.length === 0,
11152
+ error: typeof statusEvidence.error === "string" ? statusEvidence.error : null,
11153
+ content_type: typeof statusEvidence.content_type === "string" ? statusEvidence.content_type : null,
11154
+ content_length: typeof statusEvidence.content_length === "number" && Number.isFinite(statusEvidence.content_length) ? statusEvidence.content_length : null,
11155
+ bytes: linkStatusObservedBytes(statusEvidence) ?? null,
11156
+ body_contains: statusEvidence.body_contains && typeof statusEvidence.body_contains === "object" && !Array.isArray(statusEvidence.body_contains)
11157
+ ? statusEvidence.body_contains
11158
+ : null,
11159
+ body_contains_missing: bodyContainsMissing,
11160
+ body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
11161
+ failures,
11162
+ };
11163
+ }
10956
11164
  function summarizeLinkStatusEvidence(viewport, check) {
10957
11165
  const selector = linkStatusSelector(check);
10958
11166
  const linkEvidence = viewport && viewport.link_statuses && viewport.link_statuses[selector];
@@ -11708,6 +11916,31 @@ function assessProfile(profile, evidence) {
11708
11916
  });
11709
11917
  continue;
11710
11918
  }
11919
+ if (check.type === "http_status") {
11920
+ const url = httpStatusRequestUrl(check, evidence.target_url);
11921
+ const method = httpStatusMethod(check);
11922
+ const summaries = checkViewports.map((viewport) => summarizeHttpStatusEvidence(viewport, check));
11923
+ const failed = summaries.filter((summary) => Array.isArray(summary.failures) && summary.failures.length > 0);
11924
+ checks.push({
11925
+ type: check.type,
11926
+ label: check.label || check.type,
11927
+ status: failed.length ? "failed" : "passed",
11928
+ evidence: {
11929
+ url,
11930
+ method,
11931
+ allowed_statuses: httpStatusAllowedStatuses(check) || ["2xx", "3xx"],
11932
+ require_nonzero_bytes: check.require_nonzero_bytes === true,
11933
+ min_bytes: check.min_bytes ?? null,
11934
+ allowed_content_types: check.allowed_content_types ?? null,
11935
+ viewports: summaries,
11936
+ failures: failed.flatMap((summary) => Array.isArray(summary.failures)
11937
+ ? summary.failures.map((failure) => ({ viewport: summary.viewport || null, failure }))
11938
+ : []),
11939
+ },
11940
+ message: failed.length ? "HTTP status failed in " + failed.length + " viewport(s)." : undefined,
11941
+ });
11942
+ continue;
11943
+ }
11711
11944
  if (check.type === "link_status" || check.type === "artifact_link_status") {
11712
11945
  const selector = linkStatusSelector(check);
11713
11946
  const summaries = checkViewports.map((viewport) => summarizeLinkStatusEvidence(viewport, check));
@@ -12905,6 +13138,72 @@ function linkProbeResponseFields(response, method) {
12905
13138
  content_length: contentLength,
12906
13139
  };
12907
13140
  }
13141
+ async function collectHttpStatus(check) {
13142
+ const url = httpStatusRequestUrl(check, page.url() || targetUrl);
13143
+ const method = httpStatusMethod(check);
13144
+ const headers = check.headers && typeof check.headers === "object" && !Array.isArray(check.headers)
13145
+ ? Object.fromEntries(Object.entries(check.headers).map(([key, value]) => [key, String(value)]).filter(([key]) => key.trim()))
13146
+ : {};
13147
+ let body;
13148
+ if (check.body_json !== undefined) {
13149
+ body = JSON.stringify(check.body_json);
13150
+ if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) headers["content-type"] = "application/json";
13151
+ } else if (typeof check.body === "string") {
13152
+ body = check.body;
13153
+ }
13154
+ const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
13155
+ const options = {
13156
+ method,
13157
+ redirect: "follow",
13158
+ cache: "no-store",
13159
+ headers,
13160
+ };
13161
+ if (body !== undefined && method !== "GET" && method !== "HEAD") options.body = body;
13162
+ const result = {
13163
+ version: "riddle-proof.http-status.v1",
13164
+ url,
13165
+ method,
13166
+ status: null,
13167
+ ok: false,
13168
+ error: null,
13169
+ request_body_bytes: typeof body === "string" ? body.length : 0,
13170
+ allowed_statuses: httpStatusAllowedStatuses(check) || ["2xx", "3xx"],
13171
+ require_nonzero_bytes: check.require_nonzero_bytes === true,
13172
+ min_bytes: typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes) ? check.min_bytes : null,
13173
+ allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
13174
+ };
13175
+ try {
13176
+ const response = await fetch(url, options);
13177
+ Object.assign(result, linkProbeResponseFields(response, method));
13178
+ result.url = url;
13179
+ result.status_text = response.statusText || "";
13180
+ const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0;
13181
+ if (shouldReadBody) {
13182
+ try {
13183
+ const buffer = await response.arrayBuffer();
13184
+ result.bytes = buffer.byteLength;
13185
+ if (bodyContains.length) {
13186
+ const text = new TextDecoder().decode(buffer);
13187
+ result.body_sample = text.slice(0, 1000);
13188
+ result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
13189
+ }
13190
+ } catch (error) {
13191
+ result.error = String(error && error.message ? error.message : error).slice(0, 500);
13192
+ }
13193
+ }
13194
+ result.ok = linkProbeAllowed(result.status, check)
13195
+ && linkProbeContentTypeAllowed(result, check)
13196
+ && (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
13197
+ && (!(typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || ((linkProbeObservedBytes(result) || 0) >= check.min_bytes))
13198
+ && (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
13199
+ && !result.error;
13200
+ return result;
13201
+ } catch (error) {
13202
+ result.error = String(error && error.message ? error.message : error).slice(0, 500);
13203
+ result.ok = false;
13204
+ return result;
13205
+ }
13206
+ }
12908
13207
  async function probeLinkStatus(candidate, check) {
12909
13208
  const requireNonzeroBytes = check.require_nonzero_bytes === true;
12910
13209
  const minBytes = typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes) ? Math.max(1, Math.floor(check.min_bytes)) : null;
@@ -13597,6 +13896,7 @@ async function captureViewport(viewport) {
13597
13896
  const frames = {};
13598
13897
  const text_sequences = {};
13599
13898
  const text_matches = {};
13899
+ const http_statuses = {};
13600
13900
  const link_statuses = {};
13601
13901
  for (const check of profile.checks || []) {
13602
13902
  if (!profileCheckAppliesToViewport(check, viewport)) continue;
@@ -13623,6 +13923,10 @@ async function captureViewport(viewport) {
13623
13923
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
13624
13924
  frames[check.selector] = frames[check.selector] || await frameEvidence(check.selector);
13625
13925
  }
13926
+ if (check.type === "http_status") {
13927
+ const key = httpStatusKey(check, page.url() || targetUrl);
13928
+ http_statuses[key] = http_statuses[key] || await collectHttpStatus(check);
13929
+ }
13626
13930
  if (check.type === "link_status" || check.type === "artifact_link_status") {
13627
13931
  const selector = linkStatusSelector(check);
13628
13932
  link_statuses[selector] = link_statuses[selector] || await collectLinkStatus(check);
@@ -13690,6 +13994,7 @@ async function captureViewport(viewport) {
13690
13994
  frames,
13691
13995
  text_sequences,
13692
13996
  text_matches,
13997
+ http_statuses,
13693
13998
  link_statuses,
13694
13999
  route_inventory: routeInventory,
13695
14000
  setup_action_results: setupActionResults,
@@ -13739,6 +14044,19 @@ function buildProfileEvidence(currentViewports) {
13739
14044
  ),
13740
14045
  })),
13741
14046
  })),
14047
+ http_status: currentViewports
14048
+ .filter((viewport) => viewport.http_statuses && Object.keys(viewport.http_statuses).length)
14049
+ .map((viewport) => ({
14050
+ viewport: viewport.name,
14051
+ requests: Object.entries(viewport.http_statuses || {}).map(([key, statusSet]) => ({
14052
+ key,
14053
+ url: statusSet && statusSet.url,
14054
+ method: statusSet && statusSet.method,
14055
+ status: statusSet && statusSet.status,
14056
+ ok: statusSet && statusSet.ok === true,
14057
+ error: statusSet && statusSet.error,
14058
+ })),
14059
+ })),
13742
14060
  link_status: currentViewports
13743
14061
  .filter((viewport) => viewport.link_statuses && Object.keys(viewport.link_statuses).length)
13744
14062
  .map((viewport) => ({
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-G3UY3SHZ.js";
61
+ } from "./chunk-W5PBTTMJ.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,