@riddledc/riddle-proof 0.7.99 → 0.7.100

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.
@@ -807,6 +807,15 @@ function normalizeCheck(input, index) {
807
807
  input.body_contains ?? input.bodyContains ?? input.expected_body_contains ?? input.expectedBodyContains ?? input.response_body_contains ?? input.responseBodyContains ?? input.body_includes ?? input.bodyIncludes,
808
808
  `checks[${index}] body_contains`
809
809
  ) : void 0;
810
+ const bodyNotContains = isHttpStatusCheck ? normalizeStringList(
811
+ input.body_not_contains ?? input.bodyNotContains ?? input.expected_body_not_contains ?? input.expectedBodyNotContains ?? input.response_body_not_contains ?? input.responseBodyNotContains ?? input.body_absent ?? input.bodyAbsent,
812
+ `checks[${index}] body_not_contains`
813
+ ) : void 0;
814
+ const bodyNotPatterns = isHttpStatusCheck ? normalizeStringList(
815
+ input.body_not_patterns ?? input.bodyNotPatterns ?? input.expected_body_not_patterns ?? input.expectedBodyNotPatterns ?? input.response_body_not_patterns ?? input.responseBodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
816
+ `checks[${index}] body_not_patterns`
817
+ ) : void 0;
818
+ if (bodyNotPatterns?.length) validateRegexPatterns(bodyNotPatterns, `checks[${index}] body_not_patterns`);
810
819
  if (isLinkStatusCheck) {
811
820
  if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
812
821
  throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
@@ -830,6 +839,8 @@ function normalizeCheck(input, index) {
830
839
  body: isHttpStatusCheck ? stringValue(input.body) : void 0,
831
840
  body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
832
841
  body_contains: bodyContains,
842
+ body_not_contains: bodyNotContains,
843
+ body_not_patterns: bodyNotPatterns,
833
844
  expected_texts: expectedTexts,
834
845
  link_selector: stringValue(input.link_selector) || stringValue(input.linkSelector),
835
846
  source_selector: stringValue(input.source_selector) || stringValue(input.sourceSelector),
@@ -1007,6 +1018,18 @@ function httpStatusBodyContainsFailures(result, check) {
1007
1018
  const observed = isRecord(result.body_contains) ? result.body_contains : {};
1008
1019
  return expected.filter((text) => observed[text] !== true);
1009
1020
  }
1021
+ function httpStatusBodyNotContainsFailures(result, check) {
1022
+ const forbidden = check.body_not_contains?.filter(Boolean) ?? [];
1023
+ if (!forbidden.length) return [];
1024
+ const observed = isRecord(result.body_not_contains) ? result.body_not_contains : {};
1025
+ return forbidden.filter((text) => observed[text] !== false);
1026
+ }
1027
+ function httpStatusBodyNotPatternFailures(result, check) {
1028
+ const forbidden = check.body_not_patterns?.filter(Boolean) ?? [];
1029
+ if (!forbidden.length) return [];
1030
+ const observed = isRecord(result.body_not_patterns) ? result.body_not_patterns : {};
1031
+ return forbidden.filter((pattern) => observed[pattern] !== false);
1032
+ }
1010
1033
  function linkStatusResultOk(result, check) {
1011
1034
  const status = numberValue(result.status);
1012
1035
  if (!httpStatusIsAllowed(status, check)) return false;
@@ -1022,6 +1045,8 @@ function linkStatusResultOk(result, check) {
1022
1045
  if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
1023
1046
  }
1024
1047
  if (httpStatusBodyContainsFailures(result, check).length) return false;
1048
+ if (httpStatusBodyNotContainsFailures(result, check).length) return false;
1049
+ if (httpStatusBodyNotPatternFailures(result, check).length) return false;
1025
1050
  return true;
1026
1051
  }
1027
1052
  function httpStatusEvidenceForCheck(viewport, check) {
@@ -1044,6 +1069,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
1044
1069
  }
1045
1070
  const failures = [];
1046
1071
  const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
1072
+ const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
1073
+ const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
1047
1074
  if (!linkStatusResultOk(statusEvidence, check)) {
1048
1075
  failures.push({
1049
1076
  code: "http_status_failed",
@@ -1058,6 +1085,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
1058
1085
  allowed_content_types: check.allowed_content_types ?? null,
1059
1086
  body_contains: check.body_contains ?? null,
1060
1087
  body_contains_missing: bodyContainsMissing,
1088
+ body_not_contains: check.body_not_contains ?? null,
1089
+ body_not_contains_found: bodyNotContainsFound,
1090
+ body_not_patterns: check.body_not_patterns ?? null,
1091
+ body_not_patterns_found: bodyNotPatternsFound,
1061
1092
  body_sample: stringValue(statusEvidence.body_sample) ?? null
1062
1093
  });
1063
1094
  }
@@ -1075,6 +1106,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
1075
1106
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
1076
1107
  body_contains: isRecord(statusEvidence.body_contains) ? toJsonValue(statusEvidence.body_contains) : null,
1077
1108
  body_contains_missing: bodyContainsMissing,
1109
+ body_not_contains: isRecord(statusEvidence.body_not_contains) ? toJsonValue(statusEvidence.body_not_contains) : null,
1110
+ body_not_contains_found: bodyNotContainsFound,
1111
+ body_not_patterns: isRecord(statusEvidence.body_not_patterns) ? toJsonValue(statusEvidence.body_not_patterns) : null,
1112
+ body_not_patterns_found: bodyNotPatternsFound,
1078
1113
  body_sample: stringValue(statusEvidence.body_sample) ?? null,
1079
1114
  failures
1080
1115
  };
@@ -1686,6 +1721,8 @@ function assessCheckFromEvidence(check, evidence) {
1686
1721
  min_bytes: check.min_bytes ?? null,
1687
1722
  allowed_content_types: check.allowed_content_types ?? null,
1688
1723
  body_contains: check.body_contains ?? [],
1724
+ body_not_contains: check.body_not_contains ?? [],
1725
+ body_not_patterns: check.body_not_patterns ?? [],
1689
1726
  viewports: summaries.map((summary) => toJsonValue(summary)),
1690
1727
  failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue(summary.viewport) ?? null, failure })) : [])
1691
1728
  },
@@ -4423,6 +4460,8 @@ async function collectHttpStatus(check) {
4423
4460
  body = check.body;
4424
4461
  }
4425
4462
  const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
4463
+ const bodyNotContains = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
4464
+ const bodyNotPatterns = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
4426
4465
  const options = {
4427
4466
  method,
4428
4467
  redirect: "follow",
@@ -4448,15 +4487,17 @@ async function collectHttpStatus(check) {
4448
4487
  Object.assign(result, linkProbeResponseFields(response, method));
4449
4488
  result.url = url;
4450
4489
  result.status_text = response.statusText || "";
4451
- const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0;
4490
+ const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0 || bodyNotContains.length > 0 || bodyNotPatterns.length > 0;
4452
4491
  if (shouldReadBody) {
4453
4492
  try {
4454
4493
  const buffer = await response.arrayBuffer();
4455
4494
  result.bytes = buffer.byteLength;
4456
- if (bodyContains.length) {
4495
+ if (bodyContains.length || bodyNotContains.length || bodyNotPatterns.length) {
4457
4496
  const text = new TextDecoder().decode(buffer);
4458
4497
  result.body_sample = text.slice(0, 1000);
4459
- result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
4498
+ if (bodyContains.length) result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
4499
+ if (bodyNotContains.length) result.body_not_contains = Object.fromEntries(bodyNotContains.map((forbidden) => [forbidden, text.includes(forbidden)]));
4500
+ if (bodyNotPatterns.length) result.body_not_patterns = Object.fromEntries(bodyNotPatterns.map((pattern) => [pattern, new RegExp(pattern).test(text)]));
4460
4501
  }
4461
4502
  } catch (error) {
4462
4503
  result.error = String(error && error.message ? error.message : error).slice(0, 500);
@@ -4467,6 +4508,8 @@ async function collectHttpStatus(check) {
4467
4508
  && (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
4468
4509
  && (!(typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || ((linkProbeObservedBytes(result) || 0) >= check.min_bytes))
4469
4510
  && (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
4511
+ && (!bodyNotContains.length || bodyNotContains.every((forbidden) => result.body_not_contains && result.body_not_contains[forbidden] === false))
4512
+ && (!bodyNotPatterns.length || bodyNotPatterns.every((pattern) => result.body_not_patterns && result.body_not_patterns[pattern] === false))
4470
4513
  && !result.error;
4471
4514
  return result;
4472
4515
  } catch (error) {
package/dist/cli.cjs CHANGED
@@ -7700,6 +7700,15 @@ function normalizeCheck(input, index) {
7700
7700
  input.body_contains ?? input.bodyContains ?? input.expected_body_contains ?? input.expectedBodyContains ?? input.response_body_contains ?? input.responseBodyContains ?? input.body_includes ?? input.bodyIncludes,
7701
7701
  `checks[${index}] body_contains`
7702
7702
  ) : void 0;
7703
+ const bodyNotContains = isHttpStatusCheck ? normalizeStringList(
7704
+ input.body_not_contains ?? input.bodyNotContains ?? input.expected_body_not_contains ?? input.expectedBodyNotContains ?? input.response_body_not_contains ?? input.responseBodyNotContains ?? input.body_absent ?? input.bodyAbsent,
7705
+ `checks[${index}] body_not_contains`
7706
+ ) : void 0;
7707
+ const bodyNotPatterns = isHttpStatusCheck ? normalizeStringList(
7708
+ input.body_not_patterns ?? input.bodyNotPatterns ?? input.expected_body_not_patterns ?? input.expectedBodyNotPatterns ?? input.response_body_not_patterns ?? input.responseBodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
7709
+ `checks[${index}] body_not_patterns`
7710
+ ) : void 0;
7711
+ if (bodyNotPatterns?.length) validateRegexPatterns(bodyNotPatterns, `checks[${index}] body_not_patterns`);
7703
7712
  if (isLinkStatusCheck) {
7704
7713
  if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
7705
7714
  throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
@@ -7723,6 +7732,8 @@ function normalizeCheck(input, index) {
7723
7732
  body: isHttpStatusCheck ? stringValue2(input.body) : void 0,
7724
7733
  body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
7725
7734
  body_contains: bodyContains,
7735
+ body_not_contains: bodyNotContains,
7736
+ body_not_patterns: bodyNotPatterns,
7726
7737
  expected_texts: expectedTexts,
7727
7738
  link_selector: stringValue2(input.link_selector) || stringValue2(input.linkSelector),
7728
7739
  source_selector: stringValue2(input.source_selector) || stringValue2(input.sourceSelector),
@@ -7900,6 +7911,18 @@ function httpStatusBodyContainsFailures(result, check) {
7900
7911
  const observed = isRecord(result.body_contains) ? result.body_contains : {};
7901
7912
  return expected.filter((text) => observed[text] !== true);
7902
7913
  }
7914
+ function httpStatusBodyNotContainsFailures(result, check) {
7915
+ const forbidden = check.body_not_contains?.filter(Boolean) ?? [];
7916
+ if (!forbidden.length) return [];
7917
+ const observed = isRecord(result.body_not_contains) ? result.body_not_contains : {};
7918
+ return forbidden.filter((text) => observed[text] !== false);
7919
+ }
7920
+ function httpStatusBodyNotPatternFailures(result, check) {
7921
+ const forbidden = check.body_not_patterns?.filter(Boolean) ?? [];
7922
+ if (!forbidden.length) return [];
7923
+ const observed = isRecord(result.body_not_patterns) ? result.body_not_patterns : {};
7924
+ return forbidden.filter((pattern) => observed[pattern] !== false);
7925
+ }
7903
7926
  function linkStatusResultOk(result, check) {
7904
7927
  const status = numberValue(result.status);
7905
7928
  if (!httpStatusIsAllowed(status, check)) return false;
@@ -7915,6 +7938,8 @@ function linkStatusResultOk(result, check) {
7915
7938
  if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
7916
7939
  }
7917
7940
  if (httpStatusBodyContainsFailures(result, check).length) return false;
7941
+ if (httpStatusBodyNotContainsFailures(result, check).length) return false;
7942
+ if (httpStatusBodyNotPatternFailures(result, check).length) return false;
7918
7943
  return true;
7919
7944
  }
7920
7945
  function httpStatusEvidenceForCheck(viewport, check) {
@@ -7937,6 +7962,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
7937
7962
  }
7938
7963
  const failures = [];
7939
7964
  const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
7965
+ const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
7966
+ const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
7940
7967
  if (!linkStatusResultOk(statusEvidence, check)) {
7941
7968
  failures.push({
7942
7969
  code: "http_status_failed",
@@ -7951,6 +7978,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
7951
7978
  allowed_content_types: check.allowed_content_types ?? null,
7952
7979
  body_contains: check.body_contains ?? null,
7953
7980
  body_contains_missing: bodyContainsMissing,
7981
+ body_not_contains: check.body_not_contains ?? null,
7982
+ body_not_contains_found: bodyNotContainsFound,
7983
+ body_not_patterns: check.body_not_patterns ?? null,
7984
+ body_not_patterns_found: bodyNotPatternsFound,
7954
7985
  body_sample: stringValue2(statusEvidence.body_sample) ?? null
7955
7986
  });
7956
7987
  }
@@ -7968,6 +7999,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
7968
7999
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
7969
8000
  body_contains: isRecord(statusEvidence.body_contains) ? toJsonValue(statusEvidence.body_contains) : null,
7970
8001
  body_contains_missing: bodyContainsMissing,
8002
+ body_not_contains: isRecord(statusEvidence.body_not_contains) ? toJsonValue(statusEvidence.body_not_contains) : null,
8003
+ body_not_contains_found: bodyNotContainsFound,
8004
+ body_not_patterns: isRecord(statusEvidence.body_not_patterns) ? toJsonValue(statusEvidence.body_not_patterns) : null,
8005
+ body_not_patterns_found: bodyNotPatternsFound,
7971
8006
  body_sample: stringValue2(statusEvidence.body_sample) ?? null,
7972
8007
  failures
7973
8008
  };
@@ -8579,6 +8614,8 @@ function assessCheckFromEvidence(check, evidence) {
8579
8614
  min_bytes: check.min_bytes ?? null,
8580
8615
  allowed_content_types: check.allowed_content_types ?? null,
8581
8616
  body_contains: check.body_contains ?? [],
8617
+ body_not_contains: check.body_not_contains ?? [],
8618
+ body_not_patterns: check.body_not_patterns ?? [],
8582
8619
  viewports: summaries.map((summary) => toJsonValue(summary)),
8583
8620
  failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue2(summary.viewport) ?? null, failure })) : [])
8584
8621
  },
@@ -11300,6 +11337,8 @@ async function collectHttpStatus(check) {
11300
11337
  body = check.body;
11301
11338
  }
11302
11339
  const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
11340
+ const bodyNotContains = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
11341
+ const bodyNotPatterns = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
11303
11342
  const options = {
11304
11343
  method,
11305
11344
  redirect: "follow",
@@ -11325,15 +11364,17 @@ async function collectHttpStatus(check) {
11325
11364
  Object.assign(result, linkProbeResponseFields(response, method));
11326
11365
  result.url = url;
11327
11366
  result.status_text = response.statusText || "";
11328
- const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0;
11367
+ const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0 || bodyNotContains.length > 0 || bodyNotPatterns.length > 0;
11329
11368
  if (shouldReadBody) {
11330
11369
  try {
11331
11370
  const buffer = await response.arrayBuffer();
11332
11371
  result.bytes = buffer.byteLength;
11333
- if (bodyContains.length) {
11372
+ if (bodyContains.length || bodyNotContains.length || bodyNotPatterns.length) {
11334
11373
  const text = new TextDecoder().decode(buffer);
11335
11374
  result.body_sample = text.slice(0, 1000);
11336
- result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
11375
+ if (bodyContains.length) result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
11376
+ if (bodyNotContains.length) result.body_not_contains = Object.fromEntries(bodyNotContains.map((forbidden) => [forbidden, text.includes(forbidden)]));
11377
+ if (bodyNotPatterns.length) result.body_not_patterns = Object.fromEntries(bodyNotPatterns.map((pattern) => [pattern, new RegExp(pattern).test(text)]));
11337
11378
  }
11338
11379
  } catch (error) {
11339
11380
  result.error = String(error && error.message ? error.message : error).slice(0, 500);
@@ -11344,6 +11385,8 @@ async function collectHttpStatus(check) {
11344
11385
  && (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
11345
11386
  && (!(typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || ((linkProbeObservedBytes(result) || 0) >= check.min_bytes))
11346
11387
  && (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
11388
+ && (!bodyNotContains.length || bodyNotContains.every((forbidden) => result.body_not_contains && result.body_not_contains[forbidden] === false))
11389
+ && (!bodyNotPatterns.length || bodyNotPatterns.every((pattern) => result.body_not_patterns && result.body_not_patterns[pattern] === false))
11347
11390
  && !result.error;
11348
11391
  return result;
11349
11392
  } catch (error) {
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl,
12
12
  resolveRiddleProofProfileTimeoutSec
13
- } from "./chunk-W5PBTTMJ.js";
13
+ } from "./chunk-TRNLSX3U.js";
14
14
  import {
15
15
  createRiddleApiClient,
16
16
  parseRiddleViewport
package/dist/index.cjs CHANGED
@@ -9536,6 +9536,15 @@ function normalizeCheck(input, index) {
9536
9536
  input.body_contains ?? input.bodyContains ?? input.expected_body_contains ?? input.expectedBodyContains ?? input.response_body_contains ?? input.responseBodyContains ?? input.body_includes ?? input.bodyIncludes,
9537
9537
  `checks[${index}] body_contains`
9538
9538
  ) : void 0;
9539
+ const bodyNotContains = isHttpStatusCheck ? normalizeStringList(
9540
+ input.body_not_contains ?? input.bodyNotContains ?? input.expected_body_not_contains ?? input.expectedBodyNotContains ?? input.response_body_not_contains ?? input.responseBodyNotContains ?? input.body_absent ?? input.bodyAbsent,
9541
+ `checks[${index}] body_not_contains`
9542
+ ) : void 0;
9543
+ const bodyNotPatterns = isHttpStatusCheck ? normalizeStringList(
9544
+ input.body_not_patterns ?? input.bodyNotPatterns ?? input.expected_body_not_patterns ?? input.expectedBodyNotPatterns ?? input.response_body_not_patterns ?? input.responseBodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
9545
+ `checks[${index}] body_not_patterns`
9546
+ ) : void 0;
9547
+ if (bodyNotPatterns?.length) validateRegexPatterns(bodyNotPatterns, `checks[${index}] body_not_patterns`);
9539
9548
  if (isLinkStatusCheck) {
9540
9549
  if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
9541
9550
  throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
@@ -9559,6 +9568,8 @@ function normalizeCheck(input, index) {
9559
9568
  body: isHttpStatusCheck ? stringValue5(input.body) : void 0,
9560
9569
  body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
9561
9570
  body_contains: bodyContains,
9571
+ body_not_contains: bodyNotContains,
9572
+ body_not_patterns: bodyNotPatterns,
9562
9573
  expected_texts: expectedTexts,
9563
9574
  link_selector: stringValue5(input.link_selector) || stringValue5(input.linkSelector),
9564
9575
  source_selector: stringValue5(input.source_selector) || stringValue5(input.sourceSelector),
@@ -9736,6 +9747,18 @@ function httpStatusBodyContainsFailures(result, check) {
9736
9747
  const observed = isRecord2(result.body_contains) ? result.body_contains : {};
9737
9748
  return expected.filter((text) => observed[text] !== true);
9738
9749
  }
9750
+ function httpStatusBodyNotContainsFailures(result, check) {
9751
+ const forbidden = check.body_not_contains?.filter(Boolean) ?? [];
9752
+ if (!forbidden.length) return [];
9753
+ const observed = isRecord2(result.body_not_contains) ? result.body_not_contains : {};
9754
+ return forbidden.filter((text) => observed[text] !== false);
9755
+ }
9756
+ function httpStatusBodyNotPatternFailures(result, check) {
9757
+ const forbidden = check.body_not_patterns?.filter(Boolean) ?? [];
9758
+ if (!forbidden.length) return [];
9759
+ const observed = isRecord2(result.body_not_patterns) ? result.body_not_patterns : {};
9760
+ return forbidden.filter((pattern) => observed[pattern] !== false);
9761
+ }
9739
9762
  function linkStatusResultOk(result, check) {
9740
9763
  const status = numberValue3(result.status);
9741
9764
  if (!httpStatusIsAllowed(status, check)) return false;
@@ -9751,6 +9774,8 @@ function linkStatusResultOk(result, check) {
9751
9774
  if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
9752
9775
  }
9753
9776
  if (httpStatusBodyContainsFailures(result, check).length) return false;
9777
+ if (httpStatusBodyNotContainsFailures(result, check).length) return false;
9778
+ if (httpStatusBodyNotPatternFailures(result, check).length) return false;
9754
9779
  return true;
9755
9780
  }
9756
9781
  function httpStatusEvidenceForCheck(viewport, check) {
@@ -9773,6 +9798,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
9773
9798
  }
9774
9799
  const failures = [];
9775
9800
  const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
9801
+ const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
9802
+ const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
9776
9803
  if (!linkStatusResultOk(statusEvidence, check)) {
9777
9804
  failures.push({
9778
9805
  code: "http_status_failed",
@@ -9787,6 +9814,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
9787
9814
  allowed_content_types: check.allowed_content_types ?? null,
9788
9815
  body_contains: check.body_contains ?? null,
9789
9816
  body_contains_missing: bodyContainsMissing,
9817
+ body_not_contains: check.body_not_contains ?? null,
9818
+ body_not_contains_found: bodyNotContainsFound,
9819
+ body_not_patterns: check.body_not_patterns ?? null,
9820
+ body_not_patterns_found: bodyNotPatternsFound,
9790
9821
  body_sample: stringValue5(statusEvidence.body_sample) ?? null
9791
9822
  });
9792
9823
  }
@@ -9804,6 +9835,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
9804
9835
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
9805
9836
  body_contains: isRecord2(statusEvidence.body_contains) ? toJsonValue(statusEvidence.body_contains) : null,
9806
9837
  body_contains_missing: bodyContainsMissing,
9838
+ body_not_contains: isRecord2(statusEvidence.body_not_contains) ? toJsonValue(statusEvidence.body_not_contains) : null,
9839
+ body_not_contains_found: bodyNotContainsFound,
9840
+ body_not_patterns: isRecord2(statusEvidence.body_not_patterns) ? toJsonValue(statusEvidence.body_not_patterns) : null,
9841
+ body_not_patterns_found: bodyNotPatternsFound,
9807
9842
  body_sample: stringValue5(statusEvidence.body_sample) ?? null,
9808
9843
  failures
9809
9844
  };
@@ -10415,6 +10450,8 @@ function assessCheckFromEvidence(check, evidence) {
10415
10450
  min_bytes: check.min_bytes ?? null,
10416
10451
  allowed_content_types: check.allowed_content_types ?? null,
10417
10452
  body_contains: check.body_contains ?? [],
10453
+ body_not_contains: check.body_not_contains ?? [],
10454
+ body_not_patterns: check.body_not_patterns ?? [],
10418
10455
  viewports: summaries.map((summary) => toJsonValue(summary)),
10419
10456
  failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue5(summary.viewport) ?? null, failure })) : [])
10420
10457
  },
@@ -13152,6 +13189,8 @@ async function collectHttpStatus(check) {
13152
13189
  body = check.body;
13153
13190
  }
13154
13191
  const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
13192
+ const bodyNotContains = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
13193
+ const bodyNotPatterns = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
13155
13194
  const options = {
13156
13195
  method,
13157
13196
  redirect: "follow",
@@ -13177,15 +13216,17 @@ async function collectHttpStatus(check) {
13177
13216
  Object.assign(result, linkProbeResponseFields(response, method));
13178
13217
  result.url = url;
13179
13218
  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;
13219
+ const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0 || bodyNotContains.length > 0 || bodyNotPatterns.length > 0;
13181
13220
  if (shouldReadBody) {
13182
13221
  try {
13183
13222
  const buffer = await response.arrayBuffer();
13184
13223
  result.bytes = buffer.byteLength;
13185
- if (bodyContains.length) {
13224
+ if (bodyContains.length || bodyNotContains.length || bodyNotPatterns.length) {
13186
13225
  const text = new TextDecoder().decode(buffer);
13187
13226
  result.body_sample = text.slice(0, 1000);
13188
- result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
13227
+ if (bodyContains.length) result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
13228
+ if (bodyNotContains.length) result.body_not_contains = Object.fromEntries(bodyNotContains.map((forbidden) => [forbidden, text.includes(forbidden)]));
13229
+ if (bodyNotPatterns.length) result.body_not_patterns = Object.fromEntries(bodyNotPatterns.map((pattern) => [pattern, new RegExp(pattern).test(text)]));
13189
13230
  }
13190
13231
  } catch (error) {
13191
13232
  result.error = String(error && error.message ? error.message : error).slice(0, 500);
@@ -13196,6 +13237,8 @@ async function collectHttpStatus(check) {
13196
13237
  && (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
13197
13238
  && (!(typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || ((linkProbeObservedBytes(result) || 0) >= check.min_bytes))
13198
13239
  && (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
13240
+ && (!bodyNotContains.length || bodyNotContains.every((forbidden) => result.body_not_contains && result.body_not_contains[forbidden] === false))
13241
+ && (!bodyNotPatterns.length || bodyNotPatterns.every((pattern) => result.body_not_patterns && result.body_not_patterns[pattern] === false))
13199
13242
  && !result.error;
13200
13243
  return result;
13201
13244
  } catch (error) {
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-W5PBTTMJ.js";
61
+ } from "./chunk-TRNLSX3U.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -850,6 +850,15 @@ function normalizeCheck(input, index) {
850
850
  input.body_contains ?? input.bodyContains ?? input.expected_body_contains ?? input.expectedBodyContains ?? input.response_body_contains ?? input.responseBodyContains ?? input.body_includes ?? input.bodyIncludes,
851
851
  `checks[${index}] body_contains`
852
852
  ) : void 0;
853
+ const bodyNotContains = isHttpStatusCheck ? normalizeStringList(
854
+ input.body_not_contains ?? input.bodyNotContains ?? input.expected_body_not_contains ?? input.expectedBodyNotContains ?? input.response_body_not_contains ?? input.responseBodyNotContains ?? input.body_absent ?? input.bodyAbsent,
855
+ `checks[${index}] body_not_contains`
856
+ ) : void 0;
857
+ const bodyNotPatterns = isHttpStatusCheck ? normalizeStringList(
858
+ input.body_not_patterns ?? input.bodyNotPatterns ?? input.expected_body_not_patterns ?? input.expectedBodyNotPatterns ?? input.response_body_not_patterns ?? input.responseBodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
859
+ `checks[${index}] body_not_patterns`
860
+ ) : void 0;
861
+ if (bodyNotPatterns?.length) validateRegexPatterns(bodyNotPatterns, `checks[${index}] body_not_patterns`);
853
862
  if (isLinkStatusCheck) {
854
863
  if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
855
864
  throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
@@ -873,6 +882,8 @@ function normalizeCheck(input, index) {
873
882
  body: isHttpStatusCheck ? stringValue(input.body) : void 0,
874
883
  body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
875
884
  body_contains: bodyContains,
885
+ body_not_contains: bodyNotContains,
886
+ body_not_patterns: bodyNotPatterns,
876
887
  expected_texts: expectedTexts,
877
888
  link_selector: stringValue(input.link_selector) || stringValue(input.linkSelector),
878
889
  source_selector: stringValue(input.source_selector) || stringValue(input.sourceSelector),
@@ -1050,6 +1061,18 @@ function httpStatusBodyContainsFailures(result, check) {
1050
1061
  const observed = isRecord(result.body_contains) ? result.body_contains : {};
1051
1062
  return expected.filter((text) => observed[text] !== true);
1052
1063
  }
1064
+ function httpStatusBodyNotContainsFailures(result, check) {
1065
+ const forbidden = check.body_not_contains?.filter(Boolean) ?? [];
1066
+ if (!forbidden.length) return [];
1067
+ const observed = isRecord(result.body_not_contains) ? result.body_not_contains : {};
1068
+ return forbidden.filter((text) => observed[text] !== false);
1069
+ }
1070
+ function httpStatusBodyNotPatternFailures(result, check) {
1071
+ const forbidden = check.body_not_patterns?.filter(Boolean) ?? [];
1072
+ if (!forbidden.length) return [];
1073
+ const observed = isRecord(result.body_not_patterns) ? result.body_not_patterns : {};
1074
+ return forbidden.filter((pattern) => observed[pattern] !== false);
1075
+ }
1053
1076
  function linkStatusResultOk(result, check) {
1054
1077
  const status = numberValue(result.status);
1055
1078
  if (!httpStatusIsAllowed(status, check)) return false;
@@ -1065,6 +1088,8 @@ function linkStatusResultOk(result, check) {
1065
1088
  if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
1066
1089
  }
1067
1090
  if (httpStatusBodyContainsFailures(result, check).length) return false;
1091
+ if (httpStatusBodyNotContainsFailures(result, check).length) return false;
1092
+ if (httpStatusBodyNotPatternFailures(result, check).length) return false;
1068
1093
  return true;
1069
1094
  }
1070
1095
  function httpStatusEvidenceForCheck(viewport, check) {
@@ -1087,6 +1112,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
1087
1112
  }
1088
1113
  const failures = [];
1089
1114
  const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
1115
+ const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
1116
+ const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
1090
1117
  if (!linkStatusResultOk(statusEvidence, check)) {
1091
1118
  failures.push({
1092
1119
  code: "http_status_failed",
@@ -1101,6 +1128,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
1101
1128
  allowed_content_types: check.allowed_content_types ?? null,
1102
1129
  body_contains: check.body_contains ?? null,
1103
1130
  body_contains_missing: bodyContainsMissing,
1131
+ body_not_contains: check.body_not_contains ?? null,
1132
+ body_not_contains_found: bodyNotContainsFound,
1133
+ body_not_patterns: check.body_not_patterns ?? null,
1134
+ body_not_patterns_found: bodyNotPatternsFound,
1104
1135
  body_sample: stringValue(statusEvidence.body_sample) ?? null
1105
1136
  });
1106
1137
  }
@@ -1118,6 +1149,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
1118
1149
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
1119
1150
  body_contains: isRecord(statusEvidence.body_contains) ? toJsonValue(statusEvidence.body_contains) : null,
1120
1151
  body_contains_missing: bodyContainsMissing,
1152
+ body_not_contains: isRecord(statusEvidence.body_not_contains) ? toJsonValue(statusEvidence.body_not_contains) : null,
1153
+ body_not_contains_found: bodyNotContainsFound,
1154
+ body_not_patterns: isRecord(statusEvidence.body_not_patterns) ? toJsonValue(statusEvidence.body_not_patterns) : null,
1155
+ body_not_patterns_found: bodyNotPatternsFound,
1121
1156
  body_sample: stringValue(statusEvidence.body_sample) ?? null,
1122
1157
  failures
1123
1158
  };
@@ -1729,6 +1764,8 @@ function assessCheckFromEvidence(check, evidence) {
1729
1764
  min_bytes: check.min_bytes ?? null,
1730
1765
  allowed_content_types: check.allowed_content_types ?? null,
1731
1766
  body_contains: check.body_contains ?? [],
1767
+ body_not_contains: check.body_not_contains ?? [],
1768
+ body_not_patterns: check.body_not_patterns ?? [],
1732
1769
  viewports: summaries.map((summary) => toJsonValue(summary)),
1733
1770
  failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue(summary.viewport) ?? null, failure })) : [])
1734
1771
  },
@@ -4466,6 +4503,8 @@ async function collectHttpStatus(check) {
4466
4503
  body = check.body;
4467
4504
  }
4468
4505
  const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
4506
+ const bodyNotContains = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
4507
+ const bodyNotPatterns = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
4469
4508
  const options = {
4470
4509
  method,
4471
4510
  redirect: "follow",
@@ -4491,15 +4530,17 @@ async function collectHttpStatus(check) {
4491
4530
  Object.assign(result, linkProbeResponseFields(response, method));
4492
4531
  result.url = url;
4493
4532
  result.status_text = response.statusText || "";
4494
- const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0;
4533
+ const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0 || bodyNotContains.length > 0 || bodyNotPatterns.length > 0;
4495
4534
  if (shouldReadBody) {
4496
4535
  try {
4497
4536
  const buffer = await response.arrayBuffer();
4498
4537
  result.bytes = buffer.byteLength;
4499
- if (bodyContains.length) {
4538
+ if (bodyContains.length || bodyNotContains.length || bodyNotPatterns.length) {
4500
4539
  const text = new TextDecoder().decode(buffer);
4501
4540
  result.body_sample = text.slice(0, 1000);
4502
- result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
4541
+ if (bodyContains.length) result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
4542
+ if (bodyNotContains.length) result.body_not_contains = Object.fromEntries(bodyNotContains.map((forbidden) => [forbidden, text.includes(forbidden)]));
4543
+ if (bodyNotPatterns.length) result.body_not_patterns = Object.fromEntries(bodyNotPatterns.map((pattern) => [pattern, new RegExp(pattern).test(text)]));
4503
4544
  }
4504
4545
  } catch (error) {
4505
4546
  result.error = String(error && error.message ? error.message : error).slice(0, 500);
@@ -4510,6 +4551,8 @@ async function collectHttpStatus(check) {
4510
4551
  && (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
4511
4552
  && (!(typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || ((linkProbeObservedBytes(result) || 0) >= check.min_bytes))
4512
4553
  && (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
4554
+ && (!bodyNotContains.length || bodyNotContains.every((forbidden) => result.body_not_contains && result.body_not_contains[forbidden] === false))
4555
+ && (!bodyNotPatterns.length || bodyNotPatterns.every((pattern) => result.body_not_patterns && result.body_not_patterns[pattern] === false))
4513
4556
  && !result.error;
4514
4557
  return result;
4515
4558
  } catch (error) {
@@ -120,6 +120,8 @@ interface RiddleProofProfileCheck {
120
120
  body?: string;
121
121
  body_json?: JsonValue;
122
122
  body_contains?: string[];
123
+ body_not_contains?: string[];
124
+ body_not_patterns?: string[];
123
125
  expected_texts?: string[];
124
126
  link_selector?: string;
125
127
  source_selector?: string;
package/dist/profile.d.ts CHANGED
@@ -120,6 +120,8 @@ interface RiddleProofProfileCheck {
120
120
  body?: string;
121
121
  body_json?: JsonValue;
122
122
  body_contains?: string[];
123
+ body_not_contains?: string[];
124
+ body_not_patterns?: string[];
123
125
  expected_texts?: string[];
124
126
  link_selector?: string;
125
127
  source_selector?: string;
package/dist/profile.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  resolveRiddleProofProfileTimeoutSec,
20
20
  slugifyRiddleProofProfileName,
21
21
  summarizeRiddleProofProfileResult
22
- } from "./chunk-W5PBTTMJ.js";
22
+ } from "./chunk-TRNLSX3U.js";
23
23
  export {
24
24
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
25
25
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.99",
3
+ "version": "0.7.100",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",