@riddledc/riddle-proof 0.7.93 → 0.7.95

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
@@ -8749,6 +8749,8 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
8749
8749
  "selector_count_equals",
8750
8750
  "selector_count_equal",
8751
8751
  "selector_count_eq",
8752
+ "selector_text_visible",
8753
+ "selector_text_absent",
8752
8754
  "selector_text_order",
8753
8755
  "frame_text_visible",
8754
8756
  "frame_url_equals",
@@ -9462,7 +9464,7 @@ function normalizeCheck(input, index) {
9462
9464
  if (!isSupportedCheckType(type)) {
9463
9465
  throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
9464
9466
  }
9465
- if ((type === "selector_visible" || type === "selector_absent" || type === "selector_count_at_least" || type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && !stringValue5(input.selector)) {
9467
+ if ((type === "selector_visible" || type === "selector_absent" || type === "selector_count_at_least" || type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || type === "selector_text_visible" || type === "selector_text_absent") && !stringValue5(input.selector)) {
9466
9468
  throw new Error(`checks[${index}] ${type} requires selector.`);
9467
9469
  }
9468
9470
  if ((type === "frame_text_visible" || type === "frame_url_equals" || type === "frame_url_matches" || type === "frame_no_horizontal_overflow") && !stringValue5(input.selector)) {
@@ -9478,7 +9480,7 @@ function normalizeCheck(input, index) {
9478
9480
  if (type === "frame_url_matches" && !stringValue5(input.pattern)) {
9479
9481
  throw new Error(`checks[${index}] frame_url_matches requires pattern.`);
9480
9482
  }
9481
- if ((type === "text_visible" || type === "text_absent") && !stringValue5(input.text) && !stringValue5(input.pattern)) {
9483
+ if ((type === "text_visible" || type === "text_absent" || type === "selector_text_visible" || type === "selector_text_absent") && !stringValue5(input.text) && !stringValue5(input.pattern)) {
9482
9484
  throw new Error(`checks[${index}] ${type} requires text or pattern.`);
9483
9485
  }
9484
9486
  if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue5(input.param) && !stringValue5(input.search_param) && !stringValue5(input.searchParam) && !stringValue5(input.key)) {
@@ -9512,6 +9514,12 @@ function normalizeCheck(input, index) {
9512
9514
  `checks[${index}] allowed_statuses`
9513
9515
  ) : void 0;
9514
9516
  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(
9520
+ input.allowed_content_types ?? input.allowedContentTypes ?? input.expected_content_types ?? input.expectedContentTypes,
9521
+ `checks[${index}] allowed_content_types`
9522
+ ) ?? (expectedContentType ? [expectedContentType] : void 0) : void 0;
9515
9523
  if (isLinkStatusCheck) {
9516
9524
  if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
9517
9525
  throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
@@ -9553,6 +9561,8 @@ function normalizeCheck(input, index) {
9553
9561
  same_origin_only: isLinkStatusCheck ? input.same_origin_only === true || input.sameOriginOnly === true : void 0,
9554
9562
  dedupe: isLinkStatusCheck ? input.dedupe === false ? false : true : void 0,
9555
9563
  require_nonzero_bytes: isLinkStatusCheck ? input.require_nonzero_bytes === true || input.requireNonzeroBytes === true : void 0,
9564
+ min_bytes: minBytes,
9565
+ allowed_content_types: allowedContentTypes,
9556
9566
  allow_get_fallback: isLinkStatusCheck ? input.allow_get_fallback === false || input.allowGetFallback === false ? false : true : void 0,
9557
9567
  max_overflow_px: numberValue3(input.max_overflow_px),
9558
9568
  timeout_ms: numberValue3(input.timeout_ms) ?? numberValue3(input.timeoutMs),
@@ -9659,15 +9669,40 @@ function linkStatusIsAllowed(status, check) {
9659
9669
  const allowed = linkStatusAllowedStatuses(check);
9660
9670
  return allowed?.length ? allowed.includes(status) : status >= 200 && status < 400;
9661
9671
  }
9672
+ function linkStatusObservedBytes(result) {
9673
+ const bytes = numberValue3(result.bytes);
9674
+ const contentLength = numberValue3(result.content_length);
9675
+ return Math.max(bytes ?? 0, contentLength ?? 0) || void 0;
9676
+ }
9677
+ function normalizeLinkStatusContentType(value) {
9678
+ const normalized = value?.split(";")[0]?.trim().toLowerCase();
9679
+ return normalized || void 0;
9680
+ }
9681
+ function linkStatusContentTypeOk(result, check) {
9682
+ const expected = check.allowed_content_types;
9683
+ if (!expected?.length) return true;
9684
+ const actual = normalizeLinkStatusContentType(stringValue5(result.content_type));
9685
+ if (!actual) return false;
9686
+ return expected.some((contentType) => {
9687
+ const normalized = normalizeLinkStatusContentType(contentType);
9688
+ if (!normalized) return false;
9689
+ if (normalized.endsWith("/*")) return actual.startsWith(normalized.slice(0, -1));
9690
+ return actual === normalized;
9691
+ });
9692
+ }
9662
9693
  function linkStatusResultOk(result, check) {
9663
9694
  const status = numberValue3(result.status);
9664
9695
  if (!linkStatusIsAllowed(status, check)) return false;
9665
9696
  if (stringValue5(result.error)) return false;
9666
9697
  if (result.ok === false) return false;
9698
+ if (!linkStatusContentTypeOk(result, check)) return false;
9667
9699
  if (check.require_nonzero_bytes) {
9668
- const bytes = numberValue3(result.bytes);
9669
- const contentLength = numberValue3(result.content_length);
9670
- return bytes !== void 0 && bytes > 0 || contentLength !== void 0 && contentLength > 0;
9700
+ const observedBytes = linkStatusObservedBytes(result);
9701
+ if (observedBytes === void 0 || observedBytes <= 0) return false;
9702
+ }
9703
+ if (check.min_bytes !== void 0) {
9704
+ const observedBytes = linkStatusObservedBytes(result);
9705
+ if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
9671
9706
  }
9672
9707
  return true;
9673
9708
  }
@@ -9696,7 +9731,10 @@ function summarizeLinkStatusEvidence(viewport, check) {
9696
9731
  status: numberValue3(result.status) ?? null,
9697
9732
  method: stringValue5(result.method) ?? null,
9698
9733
  error: stringValue5(result.error) ?? null,
9699
- bytes: numberValue3(result.bytes) ?? numberValue3(result.content_length) ?? null
9734
+ content_type: stringValue5(result.content_type) ?? null,
9735
+ bytes: linkStatusObservedBytes(result) ?? null,
9736
+ min_bytes: check.min_bytes ?? null,
9737
+ allowed_content_types: check.allowed_content_types ?? null
9700
9738
  }));
9701
9739
  if (stringValue5(linkEvidence.error)) {
9702
9740
  failures.push({ code: "link_status_capture_failed", error: stringValue5(linkEvidence.error) ?? "" });
@@ -9733,6 +9771,8 @@ function summarizeLinkStatusEvidence(viewport, check) {
9733
9771
  failed_count: failures.length,
9734
9772
  truncated: linkEvidence.truncated === true,
9735
9773
  max_links: numberValue3(linkEvidence.max_links) ?? check.max_links ?? 100,
9774
+ min_bytes: check.min_bytes ?? null,
9775
+ allowed_content_types: check.allowed_content_types ?? null,
9736
9776
  status_counts: statusCounts,
9737
9777
  failures: failures.slice(0, 20)
9738
9778
  };
@@ -9744,9 +9784,11 @@ function textSequenceForCheck(viewport, check) {
9744
9784
  const key = selectorKey(check);
9745
9785
  const sequence = viewport.text_sequences?.[key];
9746
9786
  if (isRecord2(sequence)) {
9787
+ const visibleMatchTexts = Array.isArray(sequence.visible_match_texts) ? sequence.visible_match_texts : [];
9788
+ const matchTexts = Array.isArray(sequence.match_texts) ? sequence.match_texts : [];
9747
9789
  const visibleTexts = Array.isArray(sequence.visible_texts) ? sequence.visible_texts : [];
9748
9790
  const texts = Array.isArray(sequence.texts) ? sequence.texts : [];
9749
- const candidates = visibleTexts.length ? visibleTexts : texts;
9791
+ const candidates = visibleMatchTexts.length ? visibleMatchTexts : matchTexts.length ? matchTexts : visibleTexts.length ? visibleTexts : texts;
9750
9792
  return candidates.map((text) => String(text).replace(/\s+/g, " ").trim()).filter(Boolean);
9751
9793
  }
9752
9794
  return [];
@@ -10080,6 +10122,35 @@ function assessCheckFromEvidence(check, evidence) {
10080
10122
  message: failed.length ? `Selector ${key} count did not equal ${expectedCount} in ${failed.length} viewport(s).` : void 0
10081
10123
  };
10082
10124
  }
10125
+ if (check.type === "selector_text_visible" || check.type === "selector_text_absent") {
10126
+ const key = selectorKey(check);
10127
+ const expectedVisible = check.type === "selector_text_visible";
10128
+ const results = viewports.map((viewport) => {
10129
+ const texts = textSequenceForCheck(viewport, check);
10130
+ const matches = texts.filter((text) => matchText(text, check));
10131
+ return {
10132
+ viewport: viewport.name,
10133
+ selector_count: viewport.selectors?.[key]?.count || 0,
10134
+ visible_count: viewport.selectors?.[key]?.visible_count || 0,
10135
+ matched_count: matches.length,
10136
+ matched: matches.length > 0,
10137
+ samples: matches.slice(0, 3).map((text) => text.slice(0, 240))
10138
+ };
10139
+ });
10140
+ const failed = results.filter((result) => result.matched !== expectedVisible).length;
10141
+ return {
10142
+ type: check.type,
10143
+ label: checkLabel(check),
10144
+ status: failed ? "failed" : "passed",
10145
+ evidence: {
10146
+ selector: key,
10147
+ text: check.text || null,
10148
+ pattern: check.pattern || null,
10149
+ viewports: results.map((result) => toJsonValue(result))
10150
+ },
10151
+ message: failed ? `Selector ${key} text assertion failed in ${failed} viewport(s).` : void 0
10152
+ };
10153
+ }
10083
10154
  if (check.type === "selector_text_order") {
10084
10155
  const key = selectorKey(check);
10085
10156
  const expectedTexts = check.expected_texts || [];
@@ -10090,7 +10161,7 @@ function assessCheckFromEvidence(check, evidence) {
10090
10161
  viewport: viewport.name,
10091
10162
  matched: match.matched,
10092
10163
  matched_positions: match.positions,
10093
- visible_texts: texts.slice(0, 20)
10164
+ visible_texts: texts.slice(0, 20).map((text) => text.slice(0, 240))
10094
10165
  };
10095
10166
  });
10096
10167
  const failed = results.filter((result) => !result.matched).length;
@@ -10230,6 +10301,8 @@ function assessCheckFromEvidence(check, evidence) {
10230
10301
  min_count: check.min_count ?? null,
10231
10302
  allowed_statuses: linkStatusAllowedStatuses(check) || ["2xx", "3xx"],
10232
10303
  require_nonzero_bytes: check.require_nonzero_bytes === true,
10304
+ min_bytes: check.min_bytes ?? null,
10305
+ allowed_content_types: check.allowed_content_types ?? null,
10233
10306
  viewports: summaries.map((summary) => toJsonValue(summary)),
10234
10307
  failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue5(summary.viewport) ?? null, failure })) : [])
10235
10308
  },
@@ -10800,9 +10873,11 @@ function textSequenceForCheck(viewport, check) {
10800
10873
  const key = check.selector || "";
10801
10874
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
10802
10875
  if (sequence && typeof sequence === "object") {
10876
+ const visibleMatchTexts = Array.isArray(sequence.visible_match_texts) ? sequence.visible_match_texts : [];
10877
+ const matchTexts = Array.isArray(sequence.match_texts) ? sequence.match_texts : [];
10803
10878
  const visibleTexts = Array.isArray(sequence.visible_texts) ? sequence.visible_texts : [];
10804
10879
  const texts = Array.isArray(sequence.texts) ? sequence.texts : [];
10805
- const candidates = visibleTexts.length ? visibleTexts : texts;
10880
+ const candidates = visibleMatchTexts.length ? visibleMatchTexts : matchTexts.length ? matchTexts : visibleTexts.length ? visibleTexts : texts;
10806
10881
  return candidates.map((text) => String(text || "").replace(/\s+/g, " ").trim()).filter(Boolean);
10807
10882
  }
10808
10883
  return [];
@@ -10831,15 +10906,41 @@ function linkStatusIsAllowed(status, check) {
10831
10906
  const allowed = linkStatusAllowedStatuses(check);
10832
10907
  return Array.isArray(allowed) && allowed.length ? allowed.includes(status) : status >= 200 && status < 400;
10833
10908
  }
10909
+ function linkStatusObservedBytes(result) {
10910
+ const bytes = typeof result.bytes === "number" && Number.isFinite(result.bytes) ? result.bytes : undefined;
10911
+ const contentLength = typeof result.content_length === "number" && Number.isFinite(result.content_length) ? result.content_length : undefined;
10912
+ const observed = Math.max(bytes || 0, contentLength || 0);
10913
+ return observed > 0 ? observed : undefined;
10914
+ }
10915
+ function normalizeLinkStatusContentType(value) {
10916
+ if (typeof value !== "string") return undefined;
10917
+ const normalized = (value.split(";")[0] || "").trim().toLowerCase();
10918
+ return normalized || undefined;
10919
+ }
10920
+ function linkStatusContentTypeOk(result, check) {
10921
+ if (!Array.isArray(check.allowed_content_types) || !check.allowed_content_types.length) return true;
10922
+ const actual = normalizeLinkStatusContentType(result.content_type);
10923
+ if (!actual) return false;
10924
+ return check.allowed_content_types.some((contentType) => {
10925
+ const normalized = normalizeLinkStatusContentType(contentType);
10926
+ if (!normalized) return false;
10927
+ if (normalized.endsWith("/*")) return actual.startsWith(normalized.slice(0, -1));
10928
+ return actual === normalized;
10929
+ });
10930
+ }
10834
10931
  function linkStatusResultOk(result, check) {
10835
10932
  if (!result || typeof result !== "object" || Array.isArray(result)) return false;
10836
10933
  if (!linkStatusIsAllowed(result.status, check)) return false;
10837
10934
  if (typeof result.error === "string" && result.error.trim()) return false;
10838
10935
  if (result.ok === false) return false;
10936
+ if (!linkStatusContentTypeOk(result, check)) return false;
10839
10937
  if (check.require_nonzero_bytes === true) {
10840
- const bytes = typeof result.bytes === "number" && Number.isFinite(result.bytes) ? result.bytes : undefined;
10841
- const contentLength = typeof result.content_length === "number" && Number.isFinite(result.content_length) ? result.content_length : undefined;
10842
- return (bytes !== undefined && bytes > 0) || (contentLength !== undefined && contentLength > 0);
10938
+ const observedBytes = linkStatusObservedBytes(result);
10939
+ if (observedBytes === undefined || observedBytes <= 0) return false;
10940
+ }
10941
+ if (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) {
10942
+ const observedBytes = linkStatusObservedBytes(result);
10943
+ if (observedBytes === undefined || observedBytes < check.min_bytes) return false;
10843
10944
  }
10844
10945
  return true;
10845
10946
  }
@@ -10867,11 +10968,10 @@ function summarizeLinkStatusEvidence(viewport, check) {
10867
10968
  status: typeof result.status === "number" && Number.isFinite(result.status) ? result.status : null,
10868
10969
  method: typeof result.method === "string" ? result.method : null,
10869
10970
  error: typeof result.error === "string" ? result.error : null,
10870
- bytes: typeof result.bytes === "number" && Number.isFinite(result.bytes)
10871
- ? result.bytes
10872
- : typeof result.content_length === "number" && Number.isFinite(result.content_length)
10873
- ? result.content_length
10874
- : null,
10971
+ content_type: typeof result.content_type === "string" ? result.content_type : null,
10972
+ bytes: linkStatusObservedBytes(result) ?? null,
10973
+ min_bytes: typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes) ? check.min_bytes : null,
10974
+ allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
10875
10975
  }));
10876
10976
  if (typeof linkEvidence.error === "string" && linkEvidence.error.trim()) {
10877
10977
  failures.push({ code: "link_status_capture_failed", error: linkEvidence.error });
@@ -10906,6 +11006,8 @@ function summarizeLinkStatusEvidence(viewport, check) {
10906
11006
  failed_count: failures.length,
10907
11007
  truncated: linkEvidence.truncated === true,
10908
11008
  max_links: typeof linkEvidence.max_links === "number" ? linkEvidence.max_links : check.max_links || 100,
11009
+ min_bytes: typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes) ? check.min_bytes : null,
11010
+ allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
10909
11011
  status_counts: linkEvidence.status_counts && typeof linkEvidence.status_counts === "object" && !Array.isArray(linkEvidence.status_counts) ? linkEvidence.status_counts : {},
10910
11012
  failures: failures.slice(0, 20),
10911
11013
  };
@@ -11440,6 +11542,31 @@ function assessProfile(profile, evidence) {
11440
11542
  });
11441
11543
  continue;
11442
11544
  }
11545
+ if (check.type === "selector_text_visible" || check.type === "selector_text_absent") {
11546
+ const selector = check.selector || "";
11547
+ const expectedVisible = check.type === "selector_text_visible";
11548
+ const results = checkViewports.map((viewport) => {
11549
+ const texts = textSequenceForCheck(viewport, check);
11550
+ const matches = texts.filter((text) => textMatches(text, check));
11551
+ return {
11552
+ viewport: viewport.name,
11553
+ selector_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].count : 0,
11554
+ visible_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].visible_count : 0,
11555
+ matched_count: matches.length,
11556
+ matched: matches.length > 0,
11557
+ samples: matches.slice(0, 3).map((text) => text.slice(0, 240)),
11558
+ };
11559
+ });
11560
+ const failed = results.filter((result) => result.matched !== expectedVisible).length;
11561
+ checks.push({
11562
+ type: check.type,
11563
+ label: check.label || check.type,
11564
+ status: failed ? "failed" : "passed",
11565
+ evidence: { selector, text: check.text || null, pattern: check.pattern || null, viewports: results },
11566
+ message: failed ? "Selector " + selector + " text assertion failed in " + failed + " viewport(s)." : undefined,
11567
+ });
11568
+ continue;
11569
+ }
11443
11570
  if (check.type === "selector_text_order") {
11444
11571
  const selector = check.selector || "";
11445
11572
  const expectedTexts = check.expected_texts || [];
@@ -11450,7 +11577,7 @@ function assessProfile(profile, evidence) {
11450
11577
  viewport: viewport.name,
11451
11578
  matched: match.matched,
11452
11579
  matched_positions: match.positions,
11453
- visible_texts: texts.slice(0, 20),
11580
+ visible_texts: texts.slice(0, 20).map((text) => text.slice(0, 240)),
11454
11581
  };
11455
11582
  });
11456
11583
  const failed = results.filter((result) => !result.matched).length;
@@ -11577,6 +11704,8 @@ function assessProfile(profile, evidence) {
11577
11704
  min_count: check.min_count ?? null,
11578
11705
  allowed_statuses: linkStatusAllowedStatuses(check) || ["2xx", "3xx"],
11579
11706
  require_nonzero_bytes: check.require_nonzero_bytes === true,
11707
+ min_bytes: check.min_bytes ?? null,
11708
+ allowed_content_types: check.allowed_content_types ?? null,
11580
11709
  viewports: summaries,
11581
11710
  failures: failed.flatMap((summary) => Array.isArray(summary.failures)
11582
11711
  ? summary.failures.map((failure) => ({ viewport: summary.viewport || null, failure }))
@@ -12654,6 +12783,7 @@ async function selectorStats(selector) {
12654
12783
  async function selectorTextSequence(selector) {
12655
12784
  return page.locator(selector).evaluateAll((elements) => {
12656
12785
  const compact = (value) => String(value || "").replace(/\s+/g, " ").trim().slice(0, 240);
12786
+ const matchText = (value) => String(value || "").replace(/\s+/g, " ").trim().slice(0, 8000);
12657
12787
  const isVisible = (element) => {
12658
12788
  const style = window.getComputedStyle(element);
12659
12789
  const rect = element.getBoundingClientRect();
@@ -12662,6 +12792,7 @@ async function selectorTextSequence(selector) {
12662
12792
  const rows = elements.map((element, index) => ({
12663
12793
  index,
12664
12794
  text: compact(element.innerText || element.textContent || ""),
12795
+ match_text: matchText(element.innerText || element.textContent || ""),
12665
12796
  visible: isVisible(element),
12666
12797
  }));
12667
12798
  return {
@@ -12669,8 +12800,10 @@ async function selectorTextSequence(selector) {
12669
12800
  visible_count: rows.filter((row) => row.visible).length,
12670
12801
  texts: rows.map((row) => row.text).filter(Boolean).slice(0, 40),
12671
12802
  visible_texts: rows.filter((row) => row.visible).map((row) => row.text).filter(Boolean).slice(0, 40),
12803
+ match_texts: rows.map((row) => row.match_text).filter(Boolean).slice(0, 40),
12804
+ visible_match_texts: rows.filter((row) => row.visible).map((row) => row.match_text).filter(Boolean).slice(0, 40),
12672
12805
  };
12673
- }).catch((error) => ({ count: 0, visible_count: 0, texts: [], visible_texts: [], error: String(error && error.message ? error.message : error).slice(0, 500) }));
12806
+ }).catch((error) => ({ count: 0, visible_count: 0, texts: [], visible_texts: [], match_texts: [], visible_match_texts: [], error: String(error && error.message ? error.message : error).slice(0, 500) }));
12674
12807
  }
12675
12808
  function linkProbeMaxLinks(check) {
12676
12809
  const value = Number(check.max_links || check.maxLinks || check.limit || 100);
@@ -12720,6 +12853,28 @@ function linkProbeAllowed(status, check) {
12720
12853
  : null;
12721
12854
  return allowed ? allowed.includes(status) : status >= 200 && status < 400;
12722
12855
  }
12856
+ function linkProbeObservedBytes(result) {
12857
+ const bytes = typeof result.bytes === "number" && Number.isFinite(result.bytes) ? result.bytes : undefined;
12858
+ const contentLength = typeof result.content_length === "number" && Number.isFinite(result.content_length) ? result.content_length : undefined;
12859
+ const observed = Math.max(bytes || 0, contentLength || 0);
12860
+ return observed > 0 ? observed : undefined;
12861
+ }
12862
+ function normalizeLinkProbeContentType(value) {
12863
+ if (typeof value !== "string") return undefined;
12864
+ const normalized = (value.split(";")[0] || "").trim().toLowerCase();
12865
+ return normalized || undefined;
12866
+ }
12867
+ function linkProbeContentTypeAllowed(result, check) {
12868
+ if (!Array.isArray(check.allowed_content_types) || !check.allowed_content_types.length) return true;
12869
+ const actual = normalizeLinkProbeContentType(result.content_type);
12870
+ if (!actual) return false;
12871
+ return check.allowed_content_types.some((contentType) => {
12872
+ const normalized = normalizeLinkProbeContentType(contentType);
12873
+ if (!normalized) return false;
12874
+ if (normalized.endsWith("/*")) return actual.startsWith(normalized.slice(0, -1));
12875
+ return actual === normalized;
12876
+ });
12877
+ }
12723
12878
  function linkProbeResponseFields(response, method) {
12724
12879
  const contentLengthHeader = response.headers && typeof response.headers.get === "function" ? response.headers.get("content-length") : null;
12725
12880
  const contentLength = contentLengthHeader && /^\d+$/.test(contentLengthHeader) ? Number(contentLengthHeader) : null;
@@ -12734,6 +12889,7 @@ function linkProbeResponseFields(response, method) {
12734
12889
  }
12735
12890
  async function probeLinkStatus(candidate, check) {
12736
12891
  const requireNonzeroBytes = check.require_nonzero_bytes === true;
12892
+ const minBytes = typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes) ? Math.max(1, Math.floor(check.min_bytes)) : null;
12737
12893
  const allowGetFallback = check.allow_get_fallback !== false;
12738
12894
  const result = {
12739
12895
  url: candidate.url,
@@ -12751,7 +12907,7 @@ async function probeLinkStatus(candidate, check) {
12751
12907
  };
12752
12908
  const applyResponse = async (response, method, readBytes) => {
12753
12909
  Object.assign(result, linkProbeResponseFields(response, method));
12754
- if (readBytes || requireNonzeroBytes) {
12910
+ if (readBytes) {
12755
12911
  try {
12756
12912
  const buffer = await response.arrayBuffer();
12757
12913
  result.bytes = buffer.byteLength;
@@ -12760,7 +12916,9 @@ async function probeLinkStatus(candidate, check) {
12760
12916
  }
12761
12917
  }
12762
12918
  result.ok = linkProbeAllowed(result.status, check)
12763
- && (!requireNonzeroBytes || (typeof result.bytes === "number" ? result.bytes > 0 : typeof result.content_length === "number" && result.content_length > 0))
12919
+ && linkProbeContentTypeAllowed(result, check)
12920
+ && (!requireNonzeroBytes || ((linkProbeObservedBytes(result) || 0) > 0))
12921
+ && (minBytes === null || ((linkProbeObservedBytes(result) || 0) >= minBytes))
12764
12922
  && !result.error;
12765
12923
  };
12766
12924
  try {
@@ -12777,9 +12935,9 @@ async function probeLinkStatus(candidate, check) {
12777
12935
  method: "GET",
12778
12936
  redirect: "follow",
12779
12937
  cache: "no-store",
12780
- headers: { Range: "bytes=0-0" },
12938
+ headers: { Range: "bytes=0-" + String((minBytes || 1) - 1) },
12781
12939
  });
12782
- await applyResponse(response, "GET", requireNonzeroBytes);
12940
+ await applyResponse(response, "GET", requireNonzeroBytes || minBytes !== null);
12783
12941
  return result;
12784
12942
  } catch (error) {
12785
12943
  result.error = String(error && error.message ? error.message : error).slice(0, 500);
@@ -12833,7 +12991,10 @@ async function collectLinkStatus(check) {
12833
12991
  status: result.status,
12834
12992
  method: result.method,
12835
12993
  error: result.error,
12836
- bytes: result.bytes == null ? result.content_length : result.bytes,
12994
+ content_type: result.content_type,
12995
+ bytes: linkProbeObservedBytes(result) || null,
12996
+ min_bytes: typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes) ? check.min_bytes : null,
12997
+ allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
12837
12998
  }));
12838
12999
  const statusCounts = {};
12839
13000
  for (const result of results) {
@@ -12847,6 +13008,8 @@ async function collectLinkStatus(check) {
12847
13008
  same_origin_only: linkProbeSameOriginOnly(check),
12848
13009
  dedupe: linkProbeDedupe(check),
12849
13010
  require_nonzero_bytes: check.require_nonzero_bytes === true,
13011
+ min_bytes: typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes) ? check.min_bytes : null,
13012
+ allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
12850
13013
  allowed_statuses: Array.isArray(check.allowed_statuses) && check.allowed_statuses.length
12851
13014
  ? check.allowed_statuses
12852
13015
  : typeof check.expected_status === "number"
@@ -13406,7 +13569,7 @@ async function captureViewport(viewport) {
13406
13569
  ) {
13407
13570
  selectors[check.selector] = await selectorStats(check.selector);
13408
13571
  }
13409
- if (check.type === "selector_text_order" && check.selector) {
13572
+ if ((check.type === "selector_text_order" || check.type === "selector_text_visible" || check.type === "selector_text_absent") && check.selector) {
13410
13573
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
13411
13574
  text_sequences[check.selector] = await selectorTextSequence(check.selector);
13412
13575
  }
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-QLBOFUON.js";
61
+ } from "./chunk-5OCJKEHE.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,