@riddledc/riddle-proof 0.7.98 → 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.
@@ -803,6 +803,10 @@ function normalizeCheck(input, index) {
803
803
  input.allowed_content_types ?? input.allowedContentTypes ?? input.expected_content_types ?? input.expectedContentTypes,
804
804
  `checks[${index}] allowed_content_types`
805
805
  ) ?? (expectedContentType ? [expectedContentType] : void 0) : void 0;
806
+ const bodyContains = isHttpStatusCheck ? normalizeStringList(
807
+ input.body_contains ?? input.bodyContains ?? input.expected_body_contains ?? input.expectedBodyContains ?? input.response_body_contains ?? input.responseBodyContains ?? input.body_includes ?? input.bodyIncludes,
808
+ `checks[${index}] body_contains`
809
+ ) : void 0;
806
810
  if (isLinkStatusCheck) {
807
811
  if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
808
812
  throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
@@ -825,6 +829,7 @@ function normalizeCheck(input, index) {
825
829
  headers: isHttpStatusCheck ? stringRecord(input.headers) : void 0,
826
830
  body: isHttpStatusCheck ? stringValue(input.body) : void 0,
827
831
  body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
832
+ body_contains: bodyContains,
828
833
  expected_texts: expectedTexts,
829
834
  link_selector: stringValue(input.link_selector) || stringValue(input.linkSelector),
830
835
  source_selector: stringValue(input.source_selector) || stringValue(input.sourceSelector),
@@ -996,6 +1001,12 @@ function linkStatusContentTypeOk(result, check) {
996
1001
  return actual === normalized;
997
1002
  });
998
1003
  }
1004
+ function httpStatusBodyContainsFailures(result, check) {
1005
+ const expected = check.body_contains?.filter(Boolean) ?? [];
1006
+ if (!expected.length) return [];
1007
+ const observed = isRecord(result.body_contains) ? result.body_contains : {};
1008
+ return expected.filter((text) => observed[text] !== true);
1009
+ }
999
1010
  function linkStatusResultOk(result, check) {
1000
1011
  const status = numberValue(result.status);
1001
1012
  if (!httpStatusIsAllowed(status, check)) return false;
@@ -1010,6 +1021,7 @@ function linkStatusResultOk(result, check) {
1010
1021
  const observedBytes = linkStatusObservedBytes(result);
1011
1022
  if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
1012
1023
  }
1024
+ if (httpStatusBodyContainsFailures(result, check).length) return false;
1013
1025
  return true;
1014
1026
  }
1015
1027
  function httpStatusEvidenceForCheck(viewport, check) {
@@ -1031,6 +1043,7 @@ function summarizeHttpStatusEvidence(viewport, check) {
1031
1043
  };
1032
1044
  }
1033
1045
  const failures = [];
1046
+ const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
1034
1047
  if (!linkStatusResultOk(statusEvidence, check)) {
1035
1048
  failures.push({
1036
1049
  code: "http_status_failed",
@@ -1042,7 +1055,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
1042
1055
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
1043
1056
  allowed_statuses: httpStatusAllowedStatuses(check) ?? ["2xx", "3xx"],
1044
1057
  min_bytes: check.min_bytes ?? null,
1045
- allowed_content_types: check.allowed_content_types ?? null
1058
+ allowed_content_types: check.allowed_content_types ?? null,
1059
+ body_contains: check.body_contains ?? null,
1060
+ body_contains_missing: bodyContainsMissing,
1061
+ body_sample: stringValue(statusEvidence.body_sample) ?? null
1046
1062
  });
1047
1063
  }
1048
1064
  return {
@@ -1057,6 +1073,9 @@ function summarizeHttpStatusEvidence(viewport, check) {
1057
1073
  content_type: stringValue(statusEvidence.content_type) ?? null,
1058
1074
  content_length: numberValue(statusEvidence.content_length) ?? null,
1059
1075
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
1076
+ body_contains: isRecord(statusEvidence.body_contains) ? toJsonValue(statusEvidence.body_contains) : null,
1077
+ body_contains_missing: bodyContainsMissing,
1078
+ body_sample: stringValue(statusEvidence.body_sample) ?? null,
1060
1079
  failures
1061
1080
  };
1062
1081
  }
@@ -1666,6 +1685,7 @@ function assessCheckFromEvidence(check, evidence) {
1666
1685
  require_nonzero_bytes: check.require_nonzero_bytes === true,
1667
1686
  min_bytes: check.min_bytes ?? null,
1668
1687
  allowed_content_types: check.allowed_content_types ?? null,
1688
+ body_contains: check.body_contains ?? [],
1669
1689
  viewports: summaries.map((summary) => toJsonValue(summary)),
1670
1690
  failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue(summary.viewport) ?? null, failure })) : [])
1671
1691
  },
@@ -2334,6 +2354,14 @@ function linkStatusContentTypeOk(result, check) {
2334
2354
  return actual === normalized;
2335
2355
  });
2336
2356
  }
2357
+ function httpStatusBodyContainsFailures(result, check) {
2358
+ const expected = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
2359
+ if (!expected.length) return [];
2360
+ const observed = result && typeof result.body_contains === "object" && !Array.isArray(result.body_contains)
2361
+ ? result.body_contains
2362
+ : {};
2363
+ return expected.filter((text) => observed[text] !== true);
2364
+ }
2337
2365
  function linkStatusResultOk(result, check) {
2338
2366
  if (!result || typeof result !== "object" || Array.isArray(result)) return false;
2339
2367
  if (!httpStatusIsAllowed(result.status, check)) return false;
@@ -2348,6 +2376,7 @@ function linkStatusResultOk(result, check) {
2348
2376
  const observedBytes = linkStatusObservedBytes(result);
2349
2377
  if (observedBytes === undefined || observedBytes < check.min_bytes) return false;
2350
2378
  }
2379
+ if (httpStatusBodyContainsFailures(result, check).length) return false;
2351
2380
  return true;
2352
2381
  }
2353
2382
  function summarizeHttpStatusEvidence(viewport, check) {
@@ -2365,6 +2394,7 @@ function summarizeHttpStatusEvidence(viewport, check) {
2365
2394
  };
2366
2395
  }
2367
2396
  const failures = [];
2397
+ const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
2368
2398
  if (!linkStatusResultOk(statusEvidence, check)) {
2369
2399
  failures.push({
2370
2400
  code: "http_status_failed",
@@ -2377,6 +2407,9 @@ function summarizeHttpStatusEvidence(viewport, check) {
2377
2407
  allowed_statuses: httpStatusAllowedStatuses(check) || ["2xx", "3xx"],
2378
2408
  min_bytes: typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes) ? check.min_bytes : null,
2379
2409
  allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
2410
+ body_contains: Array.isArray(check.body_contains) ? check.body_contains : null,
2411
+ body_contains_missing: bodyContainsMissing,
2412
+ body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
2380
2413
  });
2381
2414
  }
2382
2415
  return {
@@ -2391,6 +2424,11 @@ function summarizeHttpStatusEvidence(viewport, check) {
2391
2424
  content_type: typeof statusEvidence.content_type === "string" ? statusEvidence.content_type : null,
2392
2425
  content_length: typeof statusEvidence.content_length === "number" && Number.isFinite(statusEvidence.content_length) ? statusEvidence.content_length : null,
2393
2426
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
2427
+ body_contains: statusEvidence.body_contains && typeof statusEvidence.body_contains === "object" && !Array.isArray(statusEvidence.body_contains)
2428
+ ? statusEvidence.body_contains
2429
+ : null,
2430
+ body_contains_missing: bodyContainsMissing,
2431
+ body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
2394
2432
  failures,
2395
2433
  };
2396
2434
  }
@@ -4384,6 +4422,7 @@ async function collectHttpStatus(check) {
4384
4422
  } else if (typeof check.body === "string") {
4385
4423
  body = check.body;
4386
4424
  }
4425
+ const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
4387
4426
  const options = {
4388
4427
  method,
4389
4428
  redirect: "follow",
@@ -4409,11 +4448,16 @@ async function collectHttpStatus(check) {
4409
4448
  Object.assign(result, linkProbeResponseFields(response, method));
4410
4449
  result.url = url;
4411
4450
  result.status_text = response.statusText || "";
4412
- const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes));
4451
+ const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0;
4413
4452
  if (shouldReadBody) {
4414
4453
  try {
4415
4454
  const buffer = await response.arrayBuffer();
4416
4455
  result.bytes = buffer.byteLength;
4456
+ if (bodyContains.length) {
4457
+ const text = new TextDecoder().decode(buffer);
4458
+ result.body_sample = text.slice(0, 1000);
4459
+ result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
4460
+ }
4417
4461
  } catch (error) {
4418
4462
  result.error = String(error && error.message ? error.message : error).slice(0, 500);
4419
4463
  }
@@ -4422,6 +4466,7 @@ async function collectHttpStatus(check) {
4422
4466
  && linkProbeContentTypeAllowed(result, check)
4423
4467
  && (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
4424
4468
  && (!(typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || ((linkProbeObservedBytes(result) || 0) >= check.min_bytes))
4469
+ && (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
4425
4470
  && !result.error;
4426
4471
  return result;
4427
4472
  } catch (error) {
package/dist/cli.cjs CHANGED
@@ -7696,6 +7696,10 @@ function normalizeCheck(input, index) {
7696
7696
  input.allowed_content_types ?? input.allowedContentTypes ?? input.expected_content_types ?? input.expectedContentTypes,
7697
7697
  `checks[${index}] allowed_content_types`
7698
7698
  ) ?? (expectedContentType ? [expectedContentType] : void 0) : void 0;
7699
+ const bodyContains = isHttpStatusCheck ? normalizeStringList(
7700
+ input.body_contains ?? input.bodyContains ?? input.expected_body_contains ?? input.expectedBodyContains ?? input.response_body_contains ?? input.responseBodyContains ?? input.body_includes ?? input.bodyIncludes,
7701
+ `checks[${index}] body_contains`
7702
+ ) : void 0;
7699
7703
  if (isLinkStatusCheck) {
7700
7704
  if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
7701
7705
  throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
@@ -7718,6 +7722,7 @@ function normalizeCheck(input, index) {
7718
7722
  headers: isHttpStatusCheck ? stringRecord(input.headers) : void 0,
7719
7723
  body: isHttpStatusCheck ? stringValue2(input.body) : void 0,
7720
7724
  body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
7725
+ body_contains: bodyContains,
7721
7726
  expected_texts: expectedTexts,
7722
7727
  link_selector: stringValue2(input.link_selector) || stringValue2(input.linkSelector),
7723
7728
  source_selector: stringValue2(input.source_selector) || stringValue2(input.sourceSelector),
@@ -7889,6 +7894,12 @@ function linkStatusContentTypeOk(result, check) {
7889
7894
  return actual === normalized;
7890
7895
  });
7891
7896
  }
7897
+ function httpStatusBodyContainsFailures(result, check) {
7898
+ const expected = check.body_contains?.filter(Boolean) ?? [];
7899
+ if (!expected.length) return [];
7900
+ const observed = isRecord(result.body_contains) ? result.body_contains : {};
7901
+ return expected.filter((text) => observed[text] !== true);
7902
+ }
7892
7903
  function linkStatusResultOk(result, check) {
7893
7904
  const status = numberValue(result.status);
7894
7905
  if (!httpStatusIsAllowed(status, check)) return false;
@@ -7903,6 +7914,7 @@ function linkStatusResultOk(result, check) {
7903
7914
  const observedBytes = linkStatusObservedBytes(result);
7904
7915
  if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
7905
7916
  }
7917
+ if (httpStatusBodyContainsFailures(result, check).length) return false;
7906
7918
  return true;
7907
7919
  }
7908
7920
  function httpStatusEvidenceForCheck(viewport, check) {
@@ -7924,6 +7936,7 @@ function summarizeHttpStatusEvidence(viewport, check) {
7924
7936
  };
7925
7937
  }
7926
7938
  const failures = [];
7939
+ const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
7927
7940
  if (!linkStatusResultOk(statusEvidence, check)) {
7928
7941
  failures.push({
7929
7942
  code: "http_status_failed",
@@ -7935,7 +7948,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
7935
7948
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
7936
7949
  allowed_statuses: httpStatusAllowedStatuses(check) ?? ["2xx", "3xx"],
7937
7950
  min_bytes: check.min_bytes ?? null,
7938
- allowed_content_types: check.allowed_content_types ?? null
7951
+ allowed_content_types: check.allowed_content_types ?? null,
7952
+ body_contains: check.body_contains ?? null,
7953
+ body_contains_missing: bodyContainsMissing,
7954
+ body_sample: stringValue2(statusEvidence.body_sample) ?? null
7939
7955
  });
7940
7956
  }
7941
7957
  return {
@@ -7950,6 +7966,9 @@ function summarizeHttpStatusEvidence(viewport, check) {
7950
7966
  content_type: stringValue2(statusEvidence.content_type) ?? null,
7951
7967
  content_length: numberValue(statusEvidence.content_length) ?? null,
7952
7968
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
7969
+ body_contains: isRecord(statusEvidence.body_contains) ? toJsonValue(statusEvidence.body_contains) : null,
7970
+ body_contains_missing: bodyContainsMissing,
7971
+ body_sample: stringValue2(statusEvidence.body_sample) ?? null,
7953
7972
  failures
7954
7973
  };
7955
7974
  }
@@ -8559,6 +8578,7 @@ function assessCheckFromEvidence(check, evidence) {
8559
8578
  require_nonzero_bytes: check.require_nonzero_bytes === true,
8560
8579
  min_bytes: check.min_bytes ?? null,
8561
8580
  allowed_content_types: check.allowed_content_types ?? null,
8581
+ body_contains: check.body_contains ?? [],
8562
8582
  viewports: summaries.map((summary) => toJsonValue(summary)),
8563
8583
  failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue2(summary.viewport) ?? null, failure })) : [])
8564
8584
  },
@@ -9211,6 +9231,14 @@ function linkStatusContentTypeOk(result, check) {
9211
9231
  return actual === normalized;
9212
9232
  });
9213
9233
  }
9234
+ function httpStatusBodyContainsFailures(result, check) {
9235
+ const expected = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
9236
+ if (!expected.length) return [];
9237
+ const observed = result && typeof result.body_contains === "object" && !Array.isArray(result.body_contains)
9238
+ ? result.body_contains
9239
+ : {};
9240
+ return expected.filter((text) => observed[text] !== true);
9241
+ }
9214
9242
  function linkStatusResultOk(result, check) {
9215
9243
  if (!result || typeof result !== "object" || Array.isArray(result)) return false;
9216
9244
  if (!httpStatusIsAllowed(result.status, check)) return false;
@@ -9225,6 +9253,7 @@ function linkStatusResultOk(result, check) {
9225
9253
  const observedBytes = linkStatusObservedBytes(result);
9226
9254
  if (observedBytes === undefined || observedBytes < check.min_bytes) return false;
9227
9255
  }
9256
+ if (httpStatusBodyContainsFailures(result, check).length) return false;
9228
9257
  return true;
9229
9258
  }
9230
9259
  function summarizeHttpStatusEvidence(viewport, check) {
@@ -9242,6 +9271,7 @@ function summarizeHttpStatusEvidence(viewport, check) {
9242
9271
  };
9243
9272
  }
9244
9273
  const failures = [];
9274
+ const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
9245
9275
  if (!linkStatusResultOk(statusEvidence, check)) {
9246
9276
  failures.push({
9247
9277
  code: "http_status_failed",
@@ -9254,6 +9284,9 @@ function summarizeHttpStatusEvidence(viewport, check) {
9254
9284
  allowed_statuses: httpStatusAllowedStatuses(check) || ["2xx", "3xx"],
9255
9285
  min_bytes: typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes) ? check.min_bytes : null,
9256
9286
  allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
9287
+ body_contains: Array.isArray(check.body_contains) ? check.body_contains : null,
9288
+ body_contains_missing: bodyContainsMissing,
9289
+ body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
9257
9290
  });
9258
9291
  }
9259
9292
  return {
@@ -9268,6 +9301,11 @@ function summarizeHttpStatusEvidence(viewport, check) {
9268
9301
  content_type: typeof statusEvidence.content_type === "string" ? statusEvidence.content_type : null,
9269
9302
  content_length: typeof statusEvidence.content_length === "number" && Number.isFinite(statusEvidence.content_length) ? statusEvidence.content_length : null,
9270
9303
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
9304
+ body_contains: statusEvidence.body_contains && typeof statusEvidence.body_contains === "object" && !Array.isArray(statusEvidence.body_contains)
9305
+ ? statusEvidence.body_contains
9306
+ : null,
9307
+ body_contains_missing: bodyContainsMissing,
9308
+ body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
9271
9309
  failures,
9272
9310
  };
9273
9311
  }
@@ -11261,6 +11299,7 @@ async function collectHttpStatus(check) {
11261
11299
  } else if (typeof check.body === "string") {
11262
11300
  body = check.body;
11263
11301
  }
11302
+ const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
11264
11303
  const options = {
11265
11304
  method,
11266
11305
  redirect: "follow",
@@ -11286,11 +11325,16 @@ async function collectHttpStatus(check) {
11286
11325
  Object.assign(result, linkProbeResponseFields(response, method));
11287
11326
  result.url = url;
11288
11327
  result.status_text = response.statusText || "";
11289
- const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes));
11328
+ const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0;
11290
11329
  if (shouldReadBody) {
11291
11330
  try {
11292
11331
  const buffer = await response.arrayBuffer();
11293
11332
  result.bytes = buffer.byteLength;
11333
+ if (bodyContains.length) {
11334
+ const text = new TextDecoder().decode(buffer);
11335
+ result.body_sample = text.slice(0, 1000);
11336
+ result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
11337
+ }
11294
11338
  } catch (error) {
11295
11339
  result.error = String(error && error.message ? error.message : error).slice(0, 500);
11296
11340
  }
@@ -11299,6 +11343,7 @@ async function collectHttpStatus(check) {
11299
11343
  && linkProbeContentTypeAllowed(result, check)
11300
11344
  && (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
11301
11345
  && (!(typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || ((linkProbeObservedBytes(result) || 0) >= check.min_bytes))
11346
+ && (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
11302
11347
  && !result.error;
11303
11348
  return result;
11304
11349
  } catch (error) {
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl,
12
12
  resolveRiddleProofProfileTimeoutSec
13
- } from "./chunk-OMTWNL4B.js";
13
+ } from "./chunk-W5PBTTMJ.js";
14
14
  import {
15
15
  createRiddleApiClient,
16
16
  parseRiddleViewport
package/dist/index.cjs CHANGED
@@ -9532,6 +9532,10 @@ function normalizeCheck(input, index) {
9532
9532
  input.allowed_content_types ?? input.allowedContentTypes ?? input.expected_content_types ?? input.expectedContentTypes,
9533
9533
  `checks[${index}] allowed_content_types`
9534
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;
9535
9539
  if (isLinkStatusCheck) {
9536
9540
  if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
9537
9541
  throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
@@ -9554,6 +9558,7 @@ function normalizeCheck(input, index) {
9554
9558
  headers: isHttpStatusCheck ? stringRecord(input.headers) : void 0,
9555
9559
  body: isHttpStatusCheck ? stringValue5(input.body) : void 0,
9556
9560
  body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
9561
+ body_contains: bodyContains,
9557
9562
  expected_texts: expectedTexts,
9558
9563
  link_selector: stringValue5(input.link_selector) || stringValue5(input.linkSelector),
9559
9564
  source_selector: stringValue5(input.source_selector) || stringValue5(input.sourceSelector),
@@ -9725,6 +9730,12 @@ function linkStatusContentTypeOk(result, check) {
9725
9730
  return actual === normalized;
9726
9731
  });
9727
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
+ }
9728
9739
  function linkStatusResultOk(result, check) {
9729
9740
  const status = numberValue3(result.status);
9730
9741
  if (!httpStatusIsAllowed(status, check)) return false;
@@ -9739,6 +9750,7 @@ function linkStatusResultOk(result, check) {
9739
9750
  const observedBytes = linkStatusObservedBytes(result);
9740
9751
  if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
9741
9752
  }
9753
+ if (httpStatusBodyContainsFailures(result, check).length) return false;
9742
9754
  return true;
9743
9755
  }
9744
9756
  function httpStatusEvidenceForCheck(viewport, check) {
@@ -9760,6 +9772,7 @@ function summarizeHttpStatusEvidence(viewport, check) {
9760
9772
  };
9761
9773
  }
9762
9774
  const failures = [];
9775
+ const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
9763
9776
  if (!linkStatusResultOk(statusEvidence, check)) {
9764
9777
  failures.push({
9765
9778
  code: "http_status_failed",
@@ -9771,7 +9784,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
9771
9784
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
9772
9785
  allowed_statuses: httpStatusAllowedStatuses(check) ?? ["2xx", "3xx"],
9773
9786
  min_bytes: check.min_bytes ?? null,
9774
- allowed_content_types: check.allowed_content_types ?? 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
9775
9791
  });
9776
9792
  }
9777
9793
  return {
@@ -9786,6 +9802,9 @@ function summarizeHttpStatusEvidence(viewport, check) {
9786
9802
  content_type: stringValue5(statusEvidence.content_type) ?? null,
9787
9803
  content_length: numberValue3(statusEvidence.content_length) ?? null,
9788
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,
9789
9808
  failures
9790
9809
  };
9791
9810
  }
@@ -10395,6 +10414,7 @@ function assessCheckFromEvidence(check, evidence) {
10395
10414
  require_nonzero_bytes: check.require_nonzero_bytes === true,
10396
10415
  min_bytes: check.min_bytes ?? null,
10397
10416
  allowed_content_types: check.allowed_content_types ?? null,
10417
+ body_contains: check.body_contains ?? [],
10398
10418
  viewports: summaries.map((summary) => toJsonValue(summary)),
10399
10419
  failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue5(summary.viewport) ?? null, failure })) : [])
10400
10420
  },
@@ -11063,6 +11083,14 @@ function linkStatusContentTypeOk(result, check) {
11063
11083
  return actual === normalized;
11064
11084
  });
11065
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
+ }
11066
11094
  function linkStatusResultOk(result, check) {
11067
11095
  if (!result || typeof result !== "object" || Array.isArray(result)) return false;
11068
11096
  if (!httpStatusIsAllowed(result.status, check)) return false;
@@ -11077,6 +11105,7 @@ function linkStatusResultOk(result, check) {
11077
11105
  const observedBytes = linkStatusObservedBytes(result);
11078
11106
  if (observedBytes === undefined || observedBytes < check.min_bytes) return false;
11079
11107
  }
11108
+ if (httpStatusBodyContainsFailures(result, check).length) return false;
11080
11109
  return true;
11081
11110
  }
11082
11111
  function summarizeHttpStatusEvidence(viewport, check) {
@@ -11094,6 +11123,7 @@ function summarizeHttpStatusEvidence(viewport, check) {
11094
11123
  };
11095
11124
  }
11096
11125
  const failures = [];
11126
+ const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
11097
11127
  if (!linkStatusResultOk(statusEvidence, check)) {
11098
11128
  failures.push({
11099
11129
  code: "http_status_failed",
@@ -11106,6 +11136,9 @@ function summarizeHttpStatusEvidence(viewport, check) {
11106
11136
  allowed_statuses: httpStatusAllowedStatuses(check) || ["2xx", "3xx"],
11107
11137
  min_bytes: typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes) ? check.min_bytes : null,
11108
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,
11109
11142
  });
11110
11143
  }
11111
11144
  return {
@@ -11120,6 +11153,11 @@ function summarizeHttpStatusEvidence(viewport, check) {
11120
11153
  content_type: typeof statusEvidence.content_type === "string" ? statusEvidence.content_type : null,
11121
11154
  content_length: typeof statusEvidence.content_length === "number" && Number.isFinite(statusEvidence.content_length) ? statusEvidence.content_length : null,
11122
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,
11123
11161
  failures,
11124
11162
  };
11125
11163
  }
@@ -13113,6 +13151,7 @@ async function collectHttpStatus(check) {
13113
13151
  } else if (typeof check.body === "string") {
13114
13152
  body = check.body;
13115
13153
  }
13154
+ const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
13116
13155
  const options = {
13117
13156
  method,
13118
13157
  redirect: "follow",
@@ -13138,11 +13177,16 @@ async function collectHttpStatus(check) {
13138
13177
  Object.assign(result, linkProbeResponseFields(response, method));
13139
13178
  result.url = url;
13140
13179
  result.status_text = response.statusText || "";
13141
- const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes));
13180
+ const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0;
13142
13181
  if (shouldReadBody) {
13143
13182
  try {
13144
13183
  const buffer = await response.arrayBuffer();
13145
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
+ }
13146
13190
  } catch (error) {
13147
13191
  result.error = String(error && error.message ? error.message : error).slice(0, 500);
13148
13192
  }
@@ -13151,6 +13195,7 @@ async function collectHttpStatus(check) {
13151
13195
  && linkProbeContentTypeAllowed(result, check)
13152
13196
  && (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
13153
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))
13154
13199
  && !result.error;
13155
13200
  return result;
13156
13201
  } catch (error) {
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-OMTWNL4B.js";
61
+ } from "./chunk-W5PBTTMJ.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -846,6 +846,10 @@ function normalizeCheck(input, index) {
846
846
  input.allowed_content_types ?? input.allowedContentTypes ?? input.expected_content_types ?? input.expectedContentTypes,
847
847
  `checks[${index}] allowed_content_types`
848
848
  ) ?? (expectedContentType ? [expectedContentType] : void 0) : void 0;
849
+ const bodyContains = isHttpStatusCheck ? normalizeStringList(
850
+ input.body_contains ?? input.bodyContains ?? input.expected_body_contains ?? input.expectedBodyContains ?? input.response_body_contains ?? input.responseBodyContains ?? input.body_includes ?? input.bodyIncludes,
851
+ `checks[${index}] body_contains`
852
+ ) : void 0;
849
853
  if (isLinkStatusCheck) {
850
854
  if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
851
855
  throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
@@ -868,6 +872,7 @@ function normalizeCheck(input, index) {
868
872
  headers: isHttpStatusCheck ? stringRecord(input.headers) : void 0,
869
873
  body: isHttpStatusCheck ? stringValue(input.body) : void 0,
870
874
  body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
875
+ body_contains: bodyContains,
871
876
  expected_texts: expectedTexts,
872
877
  link_selector: stringValue(input.link_selector) || stringValue(input.linkSelector),
873
878
  source_selector: stringValue(input.source_selector) || stringValue(input.sourceSelector),
@@ -1039,6 +1044,12 @@ function linkStatusContentTypeOk(result, check) {
1039
1044
  return actual === normalized;
1040
1045
  });
1041
1046
  }
1047
+ function httpStatusBodyContainsFailures(result, check) {
1048
+ const expected = check.body_contains?.filter(Boolean) ?? [];
1049
+ if (!expected.length) return [];
1050
+ const observed = isRecord(result.body_contains) ? result.body_contains : {};
1051
+ return expected.filter((text) => observed[text] !== true);
1052
+ }
1042
1053
  function linkStatusResultOk(result, check) {
1043
1054
  const status = numberValue(result.status);
1044
1055
  if (!httpStatusIsAllowed(status, check)) return false;
@@ -1053,6 +1064,7 @@ function linkStatusResultOk(result, check) {
1053
1064
  const observedBytes = linkStatusObservedBytes(result);
1054
1065
  if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
1055
1066
  }
1067
+ if (httpStatusBodyContainsFailures(result, check).length) return false;
1056
1068
  return true;
1057
1069
  }
1058
1070
  function httpStatusEvidenceForCheck(viewport, check) {
@@ -1074,6 +1086,7 @@ function summarizeHttpStatusEvidence(viewport, check) {
1074
1086
  };
1075
1087
  }
1076
1088
  const failures = [];
1089
+ const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
1077
1090
  if (!linkStatusResultOk(statusEvidence, check)) {
1078
1091
  failures.push({
1079
1092
  code: "http_status_failed",
@@ -1085,7 +1098,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
1085
1098
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
1086
1099
  allowed_statuses: httpStatusAllowedStatuses(check) ?? ["2xx", "3xx"],
1087
1100
  min_bytes: check.min_bytes ?? null,
1088
- allowed_content_types: check.allowed_content_types ?? null
1101
+ allowed_content_types: check.allowed_content_types ?? null,
1102
+ body_contains: check.body_contains ?? null,
1103
+ body_contains_missing: bodyContainsMissing,
1104
+ body_sample: stringValue(statusEvidence.body_sample) ?? null
1089
1105
  });
1090
1106
  }
1091
1107
  return {
@@ -1100,6 +1116,9 @@ function summarizeHttpStatusEvidence(viewport, check) {
1100
1116
  content_type: stringValue(statusEvidence.content_type) ?? null,
1101
1117
  content_length: numberValue(statusEvidence.content_length) ?? null,
1102
1118
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
1119
+ body_contains: isRecord(statusEvidence.body_contains) ? toJsonValue(statusEvidence.body_contains) : null,
1120
+ body_contains_missing: bodyContainsMissing,
1121
+ body_sample: stringValue(statusEvidence.body_sample) ?? null,
1103
1122
  failures
1104
1123
  };
1105
1124
  }
@@ -1709,6 +1728,7 @@ function assessCheckFromEvidence(check, evidence) {
1709
1728
  require_nonzero_bytes: check.require_nonzero_bytes === true,
1710
1729
  min_bytes: check.min_bytes ?? null,
1711
1730
  allowed_content_types: check.allowed_content_types ?? null,
1731
+ body_contains: check.body_contains ?? [],
1712
1732
  viewports: summaries.map((summary) => toJsonValue(summary)),
1713
1733
  failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue(summary.viewport) ?? null, failure })) : [])
1714
1734
  },
@@ -2377,6 +2397,14 @@ function linkStatusContentTypeOk(result, check) {
2377
2397
  return actual === normalized;
2378
2398
  });
2379
2399
  }
2400
+ function httpStatusBodyContainsFailures(result, check) {
2401
+ const expected = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
2402
+ if (!expected.length) return [];
2403
+ const observed = result && typeof result.body_contains === "object" && !Array.isArray(result.body_contains)
2404
+ ? result.body_contains
2405
+ : {};
2406
+ return expected.filter((text) => observed[text] !== true);
2407
+ }
2380
2408
  function linkStatusResultOk(result, check) {
2381
2409
  if (!result || typeof result !== "object" || Array.isArray(result)) return false;
2382
2410
  if (!httpStatusIsAllowed(result.status, check)) return false;
@@ -2391,6 +2419,7 @@ function linkStatusResultOk(result, check) {
2391
2419
  const observedBytes = linkStatusObservedBytes(result);
2392
2420
  if (observedBytes === undefined || observedBytes < check.min_bytes) return false;
2393
2421
  }
2422
+ if (httpStatusBodyContainsFailures(result, check).length) return false;
2394
2423
  return true;
2395
2424
  }
2396
2425
  function summarizeHttpStatusEvidence(viewport, check) {
@@ -2408,6 +2437,7 @@ function summarizeHttpStatusEvidence(viewport, check) {
2408
2437
  };
2409
2438
  }
2410
2439
  const failures = [];
2440
+ const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
2411
2441
  if (!linkStatusResultOk(statusEvidence, check)) {
2412
2442
  failures.push({
2413
2443
  code: "http_status_failed",
@@ -2420,6 +2450,9 @@ function summarizeHttpStatusEvidence(viewport, check) {
2420
2450
  allowed_statuses: httpStatusAllowedStatuses(check) || ["2xx", "3xx"],
2421
2451
  min_bytes: typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes) ? check.min_bytes : null,
2422
2452
  allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
2453
+ body_contains: Array.isArray(check.body_contains) ? check.body_contains : null,
2454
+ body_contains_missing: bodyContainsMissing,
2455
+ body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
2423
2456
  });
2424
2457
  }
2425
2458
  return {
@@ -2434,6 +2467,11 @@ function summarizeHttpStatusEvidence(viewport, check) {
2434
2467
  content_type: typeof statusEvidence.content_type === "string" ? statusEvidence.content_type : null,
2435
2468
  content_length: typeof statusEvidence.content_length === "number" && Number.isFinite(statusEvidence.content_length) ? statusEvidence.content_length : null,
2436
2469
  bytes: linkStatusObservedBytes(statusEvidence) ?? null,
2470
+ body_contains: statusEvidence.body_contains && typeof statusEvidence.body_contains === "object" && !Array.isArray(statusEvidence.body_contains)
2471
+ ? statusEvidence.body_contains
2472
+ : null,
2473
+ body_contains_missing: bodyContainsMissing,
2474
+ body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
2437
2475
  failures,
2438
2476
  };
2439
2477
  }
@@ -4427,6 +4465,7 @@ async function collectHttpStatus(check) {
4427
4465
  } else if (typeof check.body === "string") {
4428
4466
  body = check.body;
4429
4467
  }
4468
+ const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
4430
4469
  const options = {
4431
4470
  method,
4432
4471
  redirect: "follow",
@@ -4452,11 +4491,16 @@ async function collectHttpStatus(check) {
4452
4491
  Object.assign(result, linkProbeResponseFields(response, method));
4453
4492
  result.url = url;
4454
4493
  result.status_text = response.statusText || "";
4455
- const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes));
4494
+ const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0;
4456
4495
  if (shouldReadBody) {
4457
4496
  try {
4458
4497
  const buffer = await response.arrayBuffer();
4459
4498
  result.bytes = buffer.byteLength;
4499
+ if (bodyContains.length) {
4500
+ const text = new TextDecoder().decode(buffer);
4501
+ result.body_sample = text.slice(0, 1000);
4502
+ result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
4503
+ }
4460
4504
  } catch (error) {
4461
4505
  result.error = String(error && error.message ? error.message : error).slice(0, 500);
4462
4506
  }
@@ -4465,6 +4509,7 @@ async function collectHttpStatus(check) {
4465
4509
  && linkProbeContentTypeAllowed(result, check)
4466
4510
  && (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
4467
4511
  && (!(typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || ((linkProbeObservedBytes(result) || 0) >= check.min_bytes))
4512
+ && (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
4468
4513
  && !result.error;
4469
4514
  return result;
4470
4515
  } catch (error) {
@@ -119,6 +119,7 @@ interface RiddleProofProfileCheck {
119
119
  headers?: Record<string, string>;
120
120
  body?: string;
121
121
  body_json?: JsonValue;
122
+ body_contains?: string[];
122
123
  expected_texts?: string[];
123
124
  link_selector?: string;
124
125
  source_selector?: string;
package/dist/profile.d.ts CHANGED
@@ -119,6 +119,7 @@ interface RiddleProofProfileCheck {
119
119
  headers?: Record<string, string>;
120
120
  body?: string;
121
121
  body_json?: JsonValue;
122
+ body_contains?: string[];
122
123
  expected_texts?: string[];
123
124
  link_selector?: string;
124
125
  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-OMTWNL4B.js";
22
+ } from "./chunk-W5PBTTMJ.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.98",
3
+ "version": "0.7.99",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",