@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/README.md +25 -3
- package/dist/{chunk-QLBOFUON.js → chunk-5OCJKEHE.js} +188 -25
- package/dist/cli.cjs +203 -29
- package/dist/cli.js +16 -5
- package/dist/index.cjs +188 -25
- package/dist/index.js +1 -1
- package/dist/profile.cjs +188 -25
- package/dist/profile.d.cts +3 -1
- package/dist/profile.d.ts +3 -1
- package/dist/profile.js +1 -1
- package/dist/proof-run-engine.d.cts +3 -3
- package/dist/proof-run-engine.d.ts +3 -3
- package/package.json +1 -1
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
|
|
9669
|
-
|
|
9670
|
-
|
|
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
|
-
|
|
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
|
|
10841
|
-
|
|
10842
|
-
|
|
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
|
-
|
|
10871
|
-
|
|
10872
|
-
|
|
10873
|
-
|
|
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
|
|
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
|
-
&& (
|
|
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-
|
|
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
|
-
|
|
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-
|
|
61
|
+
} from "./chunk-5OCJKEHE.js";
|
|
62
62
|
import {
|
|
63
63
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
64
64
|
DEFAULT_RIDDLE_API_KEY_FILE,
|