@riddledc/riddle-proof 0.7.114 → 0.7.116
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 +13 -0
- package/dist/{chunk-3CND75DM.js → chunk-SBOGXOV5.js} +93 -2
- package/dist/cli.cjs +93 -2
- package/dist/cli.js +1 -1
- package/dist/index.cjs +93 -2
- package/dist/index.js +1 -1
- package/dist/profile.cjs +93 -2
- package/dist/profile.d.cts +1 -1
- package/dist/profile.d.ts +1 -1
- package/dist/profile.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -406,6 +406,19 @@ These checks are useful for audit/no-diff profiles where the product should
|
|
|
406
406
|
show a fallback state and avoid rendering stale loaders, duplicate rows, or
|
|
407
407
|
missing-resource iframes.
|
|
408
408
|
|
|
409
|
+
Use `dialog_count_equals`, `dialog_accept_count_equals`, and
|
|
410
|
+
`dialog_dismiss_count_equals` when destructive-action profiles need to prove
|
|
411
|
+
browser confirm/prompt handling directly. The counts come from the captured
|
|
412
|
+
dialog summary and use `expected_count`:
|
|
413
|
+
|
|
414
|
+
```json
|
|
415
|
+
[
|
|
416
|
+
{ "type": "dialog_count_equals", "expected_count": 2 },
|
|
417
|
+
{ "type": "dialog_accept_count_equals", "expected_count": 1 },
|
|
418
|
+
{ "type": "dialog_dismiss_count_equals", "expected_count": 1 }
|
|
419
|
+
]
|
|
420
|
+
```
|
|
421
|
+
|
|
409
422
|
Use `url_search_param_equals` and `url_search_param_absent` when the final URL
|
|
410
423
|
is part of the contract, such as deep-link recovery that must drop a stale
|
|
411
424
|
local identifier while preserving shareable query state:
|
|
@@ -20,6 +20,9 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
20
20
|
"selector_count_equals",
|
|
21
21
|
"selector_count_equal",
|
|
22
22
|
"selector_count_eq",
|
|
23
|
+
"dialog_count_equals",
|
|
24
|
+
"dialog_accept_count_equals",
|
|
25
|
+
"dialog_dismiss_count_equals",
|
|
23
26
|
"selector_text_visible",
|
|
24
27
|
"selector_text_absent",
|
|
25
28
|
"selector_text_order",
|
|
@@ -696,6 +699,38 @@ function collectRiddleProofProfileWarnings(profile) {
|
|
|
696
699
|
}
|
|
697
700
|
return warnings;
|
|
698
701
|
}
|
|
702
|
+
function profileStatusProbeCounts(profile) {
|
|
703
|
+
let httpStatus = 0;
|
|
704
|
+
let linkStatus = 0;
|
|
705
|
+
for (const check of profile.checks || []) {
|
|
706
|
+
if (check.type === "http_status") httpStatus += 1;
|
|
707
|
+
if (check.type === "link_status" || check.type === "artifact_link_status") linkStatus += 1;
|
|
708
|
+
}
|
|
709
|
+
return { httpStatus, linkStatus };
|
|
710
|
+
}
|
|
711
|
+
function riddleApiStrictSafetyWarnings(blocker) {
|
|
712
|
+
const rawWarnings = Array.isArray(blocker?.warnings) ? blocker.warnings.filter((warning) => typeof warning === "string") : [];
|
|
713
|
+
const errorText = typeof blocker?.error === "string" ? blocker.error.toLowerCase() : "";
|
|
714
|
+
const hasSafetyError = errorText.includes("potentially unsafe operations");
|
|
715
|
+
const hasDirectNetworkWarning = rawWarnings.some((warning) => warning.toLowerCase().includes("direct network operations"));
|
|
716
|
+
return hasSafetyError || hasDirectNetworkWarning ? rawWarnings : [];
|
|
717
|
+
}
|
|
718
|
+
function collectRiddleProofProfileEnvironmentBlockedWarnings(profile, blocker) {
|
|
719
|
+
const warnings = collectRiddleProofProfileWarnings(profile);
|
|
720
|
+
const safetyWarnings = riddleApiStrictSafetyWarnings(blocker);
|
|
721
|
+
if (!safetyWarnings.length) return warnings;
|
|
722
|
+
const counts = profileStatusProbeCounts(profile);
|
|
723
|
+
const statusProbeCount = counts.httpStatus + counts.linkStatus;
|
|
724
|
+
if (!statusProbeCount) return warnings;
|
|
725
|
+
const parts = [
|
|
726
|
+
counts.httpStatus ? `${counts.httpStatus} http_status` : "",
|
|
727
|
+
counts.linkStatus ? `${counts.linkStatus} link_status/artifact_link_status` : ""
|
|
728
|
+
].filter(Boolean);
|
|
729
|
+
warnings.push(
|
|
730
|
+
`Riddle API strict script validation blocked a hosted profile runner with ${parts.join(" and ")} check(s). These checks intentionally collect endpoint/link evidence from inside the generated browser runner; hosted run-profile defaults to --strict=false, so omit --strict=true or rerun with --strict=false for trusted generated profile runs.`
|
|
731
|
+
);
|
|
732
|
+
return warnings;
|
|
733
|
+
}
|
|
699
734
|
function normalizeRouteInventoryPath(value, label) {
|
|
700
735
|
const path = stringValue(value);
|
|
701
736
|
if (!path) throw new Error(`${label} requires path.`);
|
|
@@ -772,6 +807,14 @@ function validateRegexPatterns(patterns, label) {
|
|
|
772
807
|
}
|
|
773
808
|
}
|
|
774
809
|
}
|
|
810
|
+
function isDialogCountCheckType(type) {
|
|
811
|
+
return type === "dialog_count_equals" || type === "dialog_accept_count_equals" || type === "dialog_dismiss_count_equals";
|
|
812
|
+
}
|
|
813
|
+
function dialogCountFieldForCheckType(type) {
|
|
814
|
+
if (type === "dialog_accept_count_equals") return "dialog_accept_count";
|
|
815
|
+
if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
|
|
816
|
+
return "dialog_count";
|
|
817
|
+
}
|
|
775
818
|
function normalizeCheck(input, index) {
|
|
776
819
|
if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
|
|
777
820
|
const type = stringValue(input.type);
|
|
@@ -779,6 +822,7 @@ function normalizeCheck(input, index) {
|
|
|
779
822
|
if (!isSupportedCheckType(type)) {
|
|
780
823
|
throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
|
|
781
824
|
}
|
|
825
|
+
const isDialogCountCheck = isDialogCountCheckType(type);
|
|
782
826
|
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") && !stringValue(input.selector)) {
|
|
783
827
|
throw new Error(`checks[${index}] ${type} requires selector.`);
|
|
784
828
|
}
|
|
@@ -810,9 +854,12 @@ function normalizeCheck(input, index) {
|
|
|
810
854
|
throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
|
|
811
855
|
}
|
|
812
856
|
const expectedCount = numberValue(input.expected_count) ?? numberValue(input.expectedCount) ?? numberValue(input.count);
|
|
813
|
-
if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && expectedCount === void 0) {
|
|
857
|
+
if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || isDialogCountCheck) && expectedCount === void 0) {
|
|
814
858
|
throw new Error(`checks[${index}] ${type} requires expected_count.`);
|
|
815
859
|
}
|
|
860
|
+
if (isDialogCountCheck && (expectedCount === void 0 || !Number.isInteger(expectedCount) || expectedCount < 0)) {
|
|
861
|
+
throw new Error(`checks[${index}] ${type} expected_count must be a non-negative integer.`);
|
|
862
|
+
}
|
|
816
863
|
const expectedTexts = normalizeExpectedTexts(input.expected_texts ?? input.expectedTexts, index);
|
|
817
864
|
if (type === "selector_text_order") {
|
|
818
865
|
if (!stringValue(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
|
|
@@ -1482,6 +1529,22 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
1482
1529
|
message: check.viewports?.length ? `No matching viewport evidence was captured for ${check.viewports.join(", ")}.` : "No viewport evidence was captured."
|
|
1483
1530
|
};
|
|
1484
1531
|
}
|
|
1532
|
+
if (isDialogCountCheckType(check.type)) {
|
|
1533
|
+
const field = dialogCountFieldForCheckType(check.type);
|
|
1534
|
+
const expectedCount = check.expected_count ?? 0;
|
|
1535
|
+
const actualCount = numberValue(evidence.dom_summary?.[field]) ?? 0;
|
|
1536
|
+
return {
|
|
1537
|
+
type: check.type,
|
|
1538
|
+
label: checkLabel(check),
|
|
1539
|
+
status: actualCount === expectedCount ? "passed" : "failed",
|
|
1540
|
+
evidence: {
|
|
1541
|
+
field,
|
|
1542
|
+
expected_count: expectedCount,
|
|
1543
|
+
count: actualCount
|
|
1544
|
+
},
|
|
1545
|
+
message: actualCount === expectedCount ? void 0 : `${field} did not equal ${expectedCount}; observed ${actualCount}.`
|
|
1546
|
+
};
|
|
1547
|
+
}
|
|
1485
1548
|
if (check.type === "route_loaded") {
|
|
1486
1549
|
const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
|
|
1487
1550
|
const failed = viewports.filter((viewport) => !successfulRoute({
|
|
@@ -2192,7 +2255,7 @@ function createRiddleProofProfileConfigurationError(name, error, runner = "riddl
|
|
|
2192
2255
|
function createRiddleProofProfileEnvironmentBlockedResult(input) {
|
|
2193
2256
|
const message = input.error instanceof Error ? input.error.message : input.error ? String(input.error) : "Riddle runner did not complete successfully.";
|
|
2194
2257
|
const environmentBlocker = extractRiddleRunnerBlocker(message);
|
|
2195
|
-
const warnings =
|
|
2258
|
+
const warnings = collectRiddleProofProfileEnvironmentBlockedWarnings(input.profile, environmentBlocker);
|
|
2196
2259
|
return {
|
|
2197
2260
|
version: RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
2198
2261
|
profile_name: input.profile.name,
|
|
@@ -2235,6 +2298,11 @@ function extractRiddleRunnerBlocker(message) {
|
|
|
2235
2298
|
for (const key of ["error", "required_seconds", "available_seconds", "deficit_seconds", "minimum_purchase_dollars"]) {
|
|
2236
2299
|
copyScalar(key);
|
|
2237
2300
|
}
|
|
2301
|
+
const warnings = payload?.warnings;
|
|
2302
|
+
if (Array.isArray(warnings)) {
|
|
2303
|
+
const warningStrings = warnings.filter((warning) => typeof warning === "string");
|
|
2304
|
+
if (warningStrings.length) details.warnings = warningStrings;
|
|
2305
|
+
}
|
|
2238
2306
|
const httpStatus = typeof details.http_status === "number" ? details.http_status : void 0;
|
|
2239
2307
|
const errorText = typeof details.error === "string" ? details.error.toLowerCase() : "";
|
|
2240
2308
|
if (httpStatus === 402 && errorText.includes("balance")) {
|
|
@@ -2733,6 +2801,16 @@ function summarizeRouteInventory(viewport, inventory) {
|
|
|
2733
2801
|
function numberValue(value) {
|
|
2734
2802
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
2735
2803
|
}
|
|
2804
|
+
function isDialogCountCheckType(type) {
|
|
2805
|
+
return type === "dialog_count_equals"
|
|
2806
|
+
|| type === "dialog_accept_count_equals"
|
|
2807
|
+
|| type === "dialog_dismiss_count_equals";
|
|
2808
|
+
}
|
|
2809
|
+
function dialogCountFieldForCheckType(type) {
|
|
2810
|
+
if (type === "dialog_accept_count_equals") return "dialog_accept_count";
|
|
2811
|
+
if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
|
|
2812
|
+
return "dialog_count";
|
|
2813
|
+
}
|
|
2736
2814
|
function maxPositiveNumber() {
|
|
2737
2815
|
let max = 0;
|
|
2738
2816
|
for (const value of arguments) {
|
|
@@ -3104,6 +3182,19 @@ function assessProfile(profile, evidence) {
|
|
|
3104
3182
|
});
|
|
3105
3183
|
continue;
|
|
3106
3184
|
}
|
|
3185
|
+
if (isDialogCountCheckType(check.type)) {
|
|
3186
|
+
const field = dialogCountFieldForCheckType(check.type);
|
|
3187
|
+
const expectedCount = check.expected_count == null ? 0 : check.expected_count;
|
|
3188
|
+
const actualCount = numberValue(evidence.dom_summary && evidence.dom_summary[field]) ?? 0;
|
|
3189
|
+
checks.push({
|
|
3190
|
+
type: check.type,
|
|
3191
|
+
label: check.label || check.type,
|
|
3192
|
+
status: actualCount === expectedCount ? "passed" : "failed",
|
|
3193
|
+
evidence: { field, expected_count: expectedCount, count: actualCount },
|
|
3194
|
+
message: actualCount === expectedCount ? undefined : field + " did not equal " + expectedCount + "; observed " + actualCount + ".",
|
|
3195
|
+
});
|
|
3196
|
+
continue;
|
|
3197
|
+
}
|
|
3107
3198
|
if (check.type === "route_loaded") {
|
|
3108
3199
|
const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
|
|
3109
3200
|
const failed = checkViewports.filter((viewport) => {
|
package/dist/cli.cjs
CHANGED
|
@@ -6957,6 +6957,9 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
6957
6957
|
"selector_count_equals",
|
|
6958
6958
|
"selector_count_equal",
|
|
6959
6959
|
"selector_count_eq",
|
|
6960
|
+
"dialog_count_equals",
|
|
6961
|
+
"dialog_accept_count_equals",
|
|
6962
|
+
"dialog_dismiss_count_equals",
|
|
6960
6963
|
"selector_text_visible",
|
|
6961
6964
|
"selector_text_absent",
|
|
6962
6965
|
"selector_text_order",
|
|
@@ -7633,6 +7636,38 @@ function collectRiddleProofProfileWarnings(profile) {
|
|
|
7633
7636
|
}
|
|
7634
7637
|
return warnings;
|
|
7635
7638
|
}
|
|
7639
|
+
function profileStatusProbeCounts(profile) {
|
|
7640
|
+
let httpStatus = 0;
|
|
7641
|
+
let linkStatus = 0;
|
|
7642
|
+
for (const check of profile.checks || []) {
|
|
7643
|
+
if (check.type === "http_status") httpStatus += 1;
|
|
7644
|
+
if (check.type === "link_status" || check.type === "artifact_link_status") linkStatus += 1;
|
|
7645
|
+
}
|
|
7646
|
+
return { httpStatus, linkStatus };
|
|
7647
|
+
}
|
|
7648
|
+
function riddleApiStrictSafetyWarnings(blocker) {
|
|
7649
|
+
const rawWarnings = Array.isArray(blocker?.warnings) ? blocker.warnings.filter((warning) => typeof warning === "string") : [];
|
|
7650
|
+
const errorText = typeof blocker?.error === "string" ? blocker.error.toLowerCase() : "";
|
|
7651
|
+
const hasSafetyError = errorText.includes("potentially unsafe operations");
|
|
7652
|
+
const hasDirectNetworkWarning = rawWarnings.some((warning) => warning.toLowerCase().includes("direct network operations"));
|
|
7653
|
+
return hasSafetyError || hasDirectNetworkWarning ? rawWarnings : [];
|
|
7654
|
+
}
|
|
7655
|
+
function collectRiddleProofProfileEnvironmentBlockedWarnings(profile, blocker) {
|
|
7656
|
+
const warnings = collectRiddleProofProfileWarnings(profile);
|
|
7657
|
+
const safetyWarnings = riddleApiStrictSafetyWarnings(blocker);
|
|
7658
|
+
if (!safetyWarnings.length) return warnings;
|
|
7659
|
+
const counts = profileStatusProbeCounts(profile);
|
|
7660
|
+
const statusProbeCount = counts.httpStatus + counts.linkStatus;
|
|
7661
|
+
if (!statusProbeCount) return warnings;
|
|
7662
|
+
const parts = [
|
|
7663
|
+
counts.httpStatus ? `${counts.httpStatus} http_status` : "",
|
|
7664
|
+
counts.linkStatus ? `${counts.linkStatus} link_status/artifact_link_status` : ""
|
|
7665
|
+
].filter(Boolean);
|
|
7666
|
+
warnings.push(
|
|
7667
|
+
`Riddle API strict script validation blocked a hosted profile runner with ${parts.join(" and ")} check(s). These checks intentionally collect endpoint/link evidence from inside the generated browser runner; hosted run-profile defaults to --strict=false, so omit --strict=true or rerun with --strict=false for trusted generated profile runs.`
|
|
7668
|
+
);
|
|
7669
|
+
return warnings;
|
|
7670
|
+
}
|
|
7636
7671
|
function normalizeRouteInventoryPath(value, label) {
|
|
7637
7672
|
const path7 = stringValue2(value);
|
|
7638
7673
|
if (!path7) throw new Error(`${label} requires path.`);
|
|
@@ -7709,6 +7744,14 @@ function validateRegexPatterns(patterns, label) {
|
|
|
7709
7744
|
}
|
|
7710
7745
|
}
|
|
7711
7746
|
}
|
|
7747
|
+
function isDialogCountCheckType(type) {
|
|
7748
|
+
return type === "dialog_count_equals" || type === "dialog_accept_count_equals" || type === "dialog_dismiss_count_equals";
|
|
7749
|
+
}
|
|
7750
|
+
function dialogCountFieldForCheckType(type) {
|
|
7751
|
+
if (type === "dialog_accept_count_equals") return "dialog_accept_count";
|
|
7752
|
+
if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
|
|
7753
|
+
return "dialog_count";
|
|
7754
|
+
}
|
|
7712
7755
|
function normalizeCheck(input, index) {
|
|
7713
7756
|
if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
|
|
7714
7757
|
const type = stringValue2(input.type);
|
|
@@ -7716,6 +7759,7 @@ function normalizeCheck(input, index) {
|
|
|
7716
7759
|
if (!isSupportedCheckType(type)) {
|
|
7717
7760
|
throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
|
|
7718
7761
|
}
|
|
7762
|
+
const isDialogCountCheck = isDialogCountCheckType(type);
|
|
7719
7763
|
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") && !stringValue2(input.selector)) {
|
|
7720
7764
|
throw new Error(`checks[${index}] ${type} requires selector.`);
|
|
7721
7765
|
}
|
|
@@ -7747,9 +7791,12 @@ function normalizeCheck(input, index) {
|
|
|
7747
7791
|
throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
|
|
7748
7792
|
}
|
|
7749
7793
|
const expectedCount = numberValue(input.expected_count) ?? numberValue(input.expectedCount) ?? numberValue(input.count);
|
|
7750
|
-
if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && expectedCount === void 0) {
|
|
7794
|
+
if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || isDialogCountCheck) && expectedCount === void 0) {
|
|
7751
7795
|
throw new Error(`checks[${index}] ${type} requires expected_count.`);
|
|
7752
7796
|
}
|
|
7797
|
+
if (isDialogCountCheck && (expectedCount === void 0 || !Number.isInteger(expectedCount) || expectedCount < 0)) {
|
|
7798
|
+
throw new Error(`checks[${index}] ${type} expected_count must be a non-negative integer.`);
|
|
7799
|
+
}
|
|
7753
7800
|
const expectedTexts = normalizeExpectedTexts(input.expected_texts ?? input.expectedTexts, index);
|
|
7754
7801
|
if (type === "selector_text_order") {
|
|
7755
7802
|
if (!stringValue2(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
|
|
@@ -8419,6 +8466,22 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
8419
8466
|
message: check.viewports?.length ? `No matching viewport evidence was captured for ${check.viewports.join(", ")}.` : "No viewport evidence was captured."
|
|
8420
8467
|
};
|
|
8421
8468
|
}
|
|
8469
|
+
if (isDialogCountCheckType(check.type)) {
|
|
8470
|
+
const field = dialogCountFieldForCheckType(check.type);
|
|
8471
|
+
const expectedCount = check.expected_count ?? 0;
|
|
8472
|
+
const actualCount = numberValue(evidence.dom_summary?.[field]) ?? 0;
|
|
8473
|
+
return {
|
|
8474
|
+
type: check.type,
|
|
8475
|
+
label: checkLabel(check),
|
|
8476
|
+
status: actualCount === expectedCount ? "passed" : "failed",
|
|
8477
|
+
evidence: {
|
|
8478
|
+
field,
|
|
8479
|
+
expected_count: expectedCount,
|
|
8480
|
+
count: actualCount
|
|
8481
|
+
},
|
|
8482
|
+
message: actualCount === expectedCount ? void 0 : `${field} did not equal ${expectedCount}; observed ${actualCount}.`
|
|
8483
|
+
};
|
|
8484
|
+
}
|
|
8422
8485
|
if (check.type === "route_loaded") {
|
|
8423
8486
|
const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
|
|
8424
8487
|
const failed = viewports.filter((viewport) => !successfulRoute({
|
|
@@ -9113,7 +9176,7 @@ function profileStatusExitCode(profile, status) {
|
|
|
9113
9176
|
function createRiddleProofProfileEnvironmentBlockedResult(input) {
|
|
9114
9177
|
const message = input.error instanceof Error ? input.error.message : input.error ? String(input.error) : "Riddle runner did not complete successfully.";
|
|
9115
9178
|
const environmentBlocker = extractRiddleRunnerBlocker(message);
|
|
9116
|
-
const warnings =
|
|
9179
|
+
const warnings = collectRiddleProofProfileEnvironmentBlockedWarnings(input.profile, environmentBlocker);
|
|
9117
9180
|
return {
|
|
9118
9181
|
version: RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
9119
9182
|
profile_name: input.profile.name,
|
|
@@ -9156,6 +9219,11 @@ function extractRiddleRunnerBlocker(message) {
|
|
|
9156
9219
|
for (const key of ["error", "required_seconds", "available_seconds", "deficit_seconds", "minimum_purchase_dollars"]) {
|
|
9157
9220
|
copyScalar(key);
|
|
9158
9221
|
}
|
|
9222
|
+
const warnings = payload?.warnings;
|
|
9223
|
+
if (Array.isArray(warnings)) {
|
|
9224
|
+
const warningStrings = warnings.filter((warning) => typeof warning === "string");
|
|
9225
|
+
if (warningStrings.length) details.warnings = warningStrings;
|
|
9226
|
+
}
|
|
9159
9227
|
const httpStatus = typeof details.http_status === "number" ? details.http_status : void 0;
|
|
9160
9228
|
const errorText = typeof details.error === "string" ? details.error.toLowerCase() : "";
|
|
9161
9229
|
if (httpStatus === 402 && errorText.includes("balance")) {
|
|
@@ -9654,6 +9722,16 @@ function summarizeRouteInventory(viewport, inventory) {
|
|
|
9654
9722
|
function numberValue(value) {
|
|
9655
9723
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
9656
9724
|
}
|
|
9725
|
+
function isDialogCountCheckType(type) {
|
|
9726
|
+
return type === "dialog_count_equals"
|
|
9727
|
+
|| type === "dialog_accept_count_equals"
|
|
9728
|
+
|| type === "dialog_dismiss_count_equals";
|
|
9729
|
+
}
|
|
9730
|
+
function dialogCountFieldForCheckType(type) {
|
|
9731
|
+
if (type === "dialog_accept_count_equals") return "dialog_accept_count";
|
|
9732
|
+
if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
|
|
9733
|
+
return "dialog_count";
|
|
9734
|
+
}
|
|
9657
9735
|
function maxPositiveNumber() {
|
|
9658
9736
|
let max = 0;
|
|
9659
9737
|
for (const value of arguments) {
|
|
@@ -10025,6 +10103,19 @@ function assessProfile(profile, evidence) {
|
|
|
10025
10103
|
});
|
|
10026
10104
|
continue;
|
|
10027
10105
|
}
|
|
10106
|
+
if (isDialogCountCheckType(check.type)) {
|
|
10107
|
+
const field = dialogCountFieldForCheckType(check.type);
|
|
10108
|
+
const expectedCount = check.expected_count == null ? 0 : check.expected_count;
|
|
10109
|
+
const actualCount = numberValue(evidence.dom_summary && evidence.dom_summary[field]) ?? 0;
|
|
10110
|
+
checks.push({
|
|
10111
|
+
type: check.type,
|
|
10112
|
+
label: check.label || check.type,
|
|
10113
|
+
status: actualCount === expectedCount ? "passed" : "failed",
|
|
10114
|
+
evidence: { field, expected_count: expectedCount, count: actualCount },
|
|
10115
|
+
message: actualCount === expectedCount ? undefined : field + " did not equal " + expectedCount + "; observed " + actualCount + ".",
|
|
10116
|
+
});
|
|
10117
|
+
continue;
|
|
10118
|
+
}
|
|
10028
10119
|
if (check.type === "route_loaded") {
|
|
10029
10120
|
const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
|
|
10030
10121
|
const failed = checkViewports.filter((viewport) => {
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -8750,6 +8750,9 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
8750
8750
|
"selector_count_equals",
|
|
8751
8751
|
"selector_count_equal",
|
|
8752
8752
|
"selector_count_eq",
|
|
8753
|
+
"dialog_count_equals",
|
|
8754
|
+
"dialog_accept_count_equals",
|
|
8755
|
+
"dialog_dismiss_count_equals",
|
|
8753
8756
|
"selector_text_visible",
|
|
8754
8757
|
"selector_text_absent",
|
|
8755
8758
|
"selector_text_order",
|
|
@@ -9426,6 +9429,38 @@ function collectRiddleProofProfileWarnings(profile) {
|
|
|
9426
9429
|
}
|
|
9427
9430
|
return warnings;
|
|
9428
9431
|
}
|
|
9432
|
+
function profileStatusProbeCounts(profile) {
|
|
9433
|
+
let httpStatus = 0;
|
|
9434
|
+
let linkStatus = 0;
|
|
9435
|
+
for (const check of profile.checks || []) {
|
|
9436
|
+
if (check.type === "http_status") httpStatus += 1;
|
|
9437
|
+
if (check.type === "link_status" || check.type === "artifact_link_status") linkStatus += 1;
|
|
9438
|
+
}
|
|
9439
|
+
return { httpStatus, linkStatus };
|
|
9440
|
+
}
|
|
9441
|
+
function riddleApiStrictSafetyWarnings(blocker) {
|
|
9442
|
+
const rawWarnings = Array.isArray(blocker?.warnings) ? blocker.warnings.filter((warning) => typeof warning === "string") : [];
|
|
9443
|
+
const errorText = typeof blocker?.error === "string" ? blocker.error.toLowerCase() : "";
|
|
9444
|
+
const hasSafetyError = errorText.includes("potentially unsafe operations");
|
|
9445
|
+
const hasDirectNetworkWarning = rawWarnings.some((warning) => warning.toLowerCase().includes("direct network operations"));
|
|
9446
|
+
return hasSafetyError || hasDirectNetworkWarning ? rawWarnings : [];
|
|
9447
|
+
}
|
|
9448
|
+
function collectRiddleProofProfileEnvironmentBlockedWarnings(profile, blocker) {
|
|
9449
|
+
const warnings = collectRiddleProofProfileWarnings(profile);
|
|
9450
|
+
const safetyWarnings = riddleApiStrictSafetyWarnings(blocker);
|
|
9451
|
+
if (!safetyWarnings.length) return warnings;
|
|
9452
|
+
const counts = profileStatusProbeCounts(profile);
|
|
9453
|
+
const statusProbeCount = counts.httpStatus + counts.linkStatus;
|
|
9454
|
+
if (!statusProbeCount) return warnings;
|
|
9455
|
+
const parts = [
|
|
9456
|
+
counts.httpStatus ? `${counts.httpStatus} http_status` : "",
|
|
9457
|
+
counts.linkStatus ? `${counts.linkStatus} link_status/artifact_link_status` : ""
|
|
9458
|
+
].filter(Boolean);
|
|
9459
|
+
warnings.push(
|
|
9460
|
+
`Riddle API strict script validation blocked a hosted profile runner with ${parts.join(" and ")} check(s). These checks intentionally collect endpoint/link evidence from inside the generated browser runner; hosted run-profile defaults to --strict=false, so omit --strict=true or rerun with --strict=false for trusted generated profile runs.`
|
|
9461
|
+
);
|
|
9462
|
+
return warnings;
|
|
9463
|
+
}
|
|
9429
9464
|
function normalizeRouteInventoryPath(value, label) {
|
|
9430
9465
|
const path6 = stringValue5(value);
|
|
9431
9466
|
if (!path6) throw new Error(`${label} requires path.`);
|
|
@@ -9502,6 +9537,14 @@ function validateRegexPatterns(patterns, label) {
|
|
|
9502
9537
|
}
|
|
9503
9538
|
}
|
|
9504
9539
|
}
|
|
9540
|
+
function isDialogCountCheckType(type) {
|
|
9541
|
+
return type === "dialog_count_equals" || type === "dialog_accept_count_equals" || type === "dialog_dismiss_count_equals";
|
|
9542
|
+
}
|
|
9543
|
+
function dialogCountFieldForCheckType(type) {
|
|
9544
|
+
if (type === "dialog_accept_count_equals") return "dialog_accept_count";
|
|
9545
|
+
if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
|
|
9546
|
+
return "dialog_count";
|
|
9547
|
+
}
|
|
9505
9548
|
function normalizeCheck(input, index) {
|
|
9506
9549
|
if (!isRecord2(input)) throw new Error(`checks[${index}] must be an object.`);
|
|
9507
9550
|
const type = stringValue5(input.type);
|
|
@@ -9509,6 +9552,7 @@ function normalizeCheck(input, index) {
|
|
|
9509
9552
|
if (!isSupportedCheckType(type)) {
|
|
9510
9553
|
throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
|
|
9511
9554
|
}
|
|
9555
|
+
const isDialogCountCheck = isDialogCountCheckType(type);
|
|
9512
9556
|
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)) {
|
|
9513
9557
|
throw new Error(`checks[${index}] ${type} requires selector.`);
|
|
9514
9558
|
}
|
|
@@ -9540,9 +9584,12 @@ function normalizeCheck(input, index) {
|
|
|
9540
9584
|
throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
|
|
9541
9585
|
}
|
|
9542
9586
|
const expectedCount = numberValue3(input.expected_count) ?? numberValue3(input.expectedCount) ?? numberValue3(input.count);
|
|
9543
|
-
if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && expectedCount === void 0) {
|
|
9587
|
+
if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || isDialogCountCheck) && expectedCount === void 0) {
|
|
9544
9588
|
throw new Error(`checks[${index}] ${type} requires expected_count.`);
|
|
9545
9589
|
}
|
|
9590
|
+
if (isDialogCountCheck && (expectedCount === void 0 || !Number.isInteger(expectedCount) || expectedCount < 0)) {
|
|
9591
|
+
throw new Error(`checks[${index}] ${type} expected_count must be a non-negative integer.`);
|
|
9592
|
+
}
|
|
9546
9593
|
const expectedTexts = normalizeExpectedTexts(input.expected_texts ?? input.expectedTexts, index);
|
|
9547
9594
|
if (type === "selector_text_order") {
|
|
9548
9595
|
if (!stringValue5(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
|
|
@@ -10212,6 +10259,22 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
10212
10259
|
message: check.viewports?.length ? `No matching viewport evidence was captured for ${check.viewports.join(", ")}.` : "No viewport evidence was captured."
|
|
10213
10260
|
};
|
|
10214
10261
|
}
|
|
10262
|
+
if (isDialogCountCheckType(check.type)) {
|
|
10263
|
+
const field = dialogCountFieldForCheckType(check.type);
|
|
10264
|
+
const expectedCount = check.expected_count ?? 0;
|
|
10265
|
+
const actualCount = numberValue3(evidence.dom_summary?.[field]) ?? 0;
|
|
10266
|
+
return {
|
|
10267
|
+
type: check.type,
|
|
10268
|
+
label: checkLabel(check),
|
|
10269
|
+
status: actualCount === expectedCount ? "passed" : "failed",
|
|
10270
|
+
evidence: {
|
|
10271
|
+
field,
|
|
10272
|
+
expected_count: expectedCount,
|
|
10273
|
+
count: actualCount
|
|
10274
|
+
},
|
|
10275
|
+
message: actualCount === expectedCount ? void 0 : `${field} did not equal ${expectedCount}; observed ${actualCount}.`
|
|
10276
|
+
};
|
|
10277
|
+
}
|
|
10215
10278
|
if (check.type === "route_loaded") {
|
|
10216
10279
|
const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
|
|
10217
10280
|
const failed = viewports.filter((viewport) => !successfulRoute({
|
|
@@ -10922,7 +10985,7 @@ function createRiddleProofProfileConfigurationError(name, error, runner = "riddl
|
|
|
10922
10985
|
function createRiddleProofProfileEnvironmentBlockedResult(input) {
|
|
10923
10986
|
const message = input.error instanceof Error ? input.error.message : input.error ? String(input.error) : "Riddle runner did not complete successfully.";
|
|
10924
10987
|
const environmentBlocker = extractRiddleRunnerBlocker(message);
|
|
10925
|
-
const warnings =
|
|
10988
|
+
const warnings = collectRiddleProofProfileEnvironmentBlockedWarnings(input.profile, environmentBlocker);
|
|
10926
10989
|
return {
|
|
10927
10990
|
version: RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
10928
10991
|
profile_name: input.profile.name,
|
|
@@ -10965,6 +11028,11 @@ function extractRiddleRunnerBlocker(message) {
|
|
|
10965
11028
|
for (const key of ["error", "required_seconds", "available_seconds", "deficit_seconds", "minimum_purchase_dollars"]) {
|
|
10966
11029
|
copyScalar(key);
|
|
10967
11030
|
}
|
|
11031
|
+
const warnings = payload?.warnings;
|
|
11032
|
+
if (Array.isArray(warnings)) {
|
|
11033
|
+
const warningStrings = warnings.filter((warning) => typeof warning === "string");
|
|
11034
|
+
if (warningStrings.length) details.warnings = warningStrings;
|
|
11035
|
+
}
|
|
10968
11036
|
const httpStatus = typeof details.http_status === "number" ? details.http_status : void 0;
|
|
10969
11037
|
const errorText = typeof details.error === "string" ? details.error.toLowerCase() : "";
|
|
10970
11038
|
if (httpStatus === 402 && errorText.includes("balance")) {
|
|
@@ -11463,6 +11531,16 @@ function summarizeRouteInventory(viewport, inventory) {
|
|
|
11463
11531
|
function numberValue(value) {
|
|
11464
11532
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
11465
11533
|
}
|
|
11534
|
+
function isDialogCountCheckType(type) {
|
|
11535
|
+
return type === "dialog_count_equals"
|
|
11536
|
+
|| type === "dialog_accept_count_equals"
|
|
11537
|
+
|| type === "dialog_dismiss_count_equals";
|
|
11538
|
+
}
|
|
11539
|
+
function dialogCountFieldForCheckType(type) {
|
|
11540
|
+
if (type === "dialog_accept_count_equals") return "dialog_accept_count";
|
|
11541
|
+
if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
|
|
11542
|
+
return "dialog_count";
|
|
11543
|
+
}
|
|
11466
11544
|
function maxPositiveNumber() {
|
|
11467
11545
|
let max = 0;
|
|
11468
11546
|
for (const value of arguments) {
|
|
@@ -11834,6 +11912,19 @@ function assessProfile(profile, evidence) {
|
|
|
11834
11912
|
});
|
|
11835
11913
|
continue;
|
|
11836
11914
|
}
|
|
11915
|
+
if (isDialogCountCheckType(check.type)) {
|
|
11916
|
+
const field = dialogCountFieldForCheckType(check.type);
|
|
11917
|
+
const expectedCount = check.expected_count == null ? 0 : check.expected_count;
|
|
11918
|
+
const actualCount = numberValue(evidence.dom_summary && evidence.dom_summary[field]) ?? 0;
|
|
11919
|
+
checks.push({
|
|
11920
|
+
type: check.type,
|
|
11921
|
+
label: check.label || check.type,
|
|
11922
|
+
status: actualCount === expectedCount ? "passed" : "failed",
|
|
11923
|
+
evidence: { field, expected_count: expectedCount, count: actualCount },
|
|
11924
|
+
message: actualCount === expectedCount ? undefined : field + " did not equal " + expectedCount + "; observed " + actualCount + ".",
|
|
11925
|
+
});
|
|
11926
|
+
continue;
|
|
11927
|
+
}
|
|
11837
11928
|
if (check.type === "route_loaded") {
|
|
11838
11929
|
const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
|
|
11839
11930
|
const failed = checkViewports.filter((viewport) => {
|
package/dist/index.js
CHANGED
|
@@ -59,7 +59,7 @@ import {
|
|
|
59
59
|
resolveRiddleProofProfileTimeoutSec,
|
|
60
60
|
slugifyRiddleProofProfileName,
|
|
61
61
|
summarizeRiddleProofProfileResult
|
|
62
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-SBOGXOV5.js";
|
|
63
63
|
import {
|
|
64
64
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
65
65
|
DEFAULT_RIDDLE_API_KEY_FILE,
|
package/dist/profile.cjs
CHANGED
|
@@ -64,6 +64,9 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
64
64
|
"selector_count_equals",
|
|
65
65
|
"selector_count_equal",
|
|
66
66
|
"selector_count_eq",
|
|
67
|
+
"dialog_count_equals",
|
|
68
|
+
"dialog_accept_count_equals",
|
|
69
|
+
"dialog_dismiss_count_equals",
|
|
67
70
|
"selector_text_visible",
|
|
68
71
|
"selector_text_absent",
|
|
69
72
|
"selector_text_order",
|
|
@@ -740,6 +743,38 @@ function collectRiddleProofProfileWarnings(profile) {
|
|
|
740
743
|
}
|
|
741
744
|
return warnings;
|
|
742
745
|
}
|
|
746
|
+
function profileStatusProbeCounts(profile) {
|
|
747
|
+
let httpStatus = 0;
|
|
748
|
+
let linkStatus = 0;
|
|
749
|
+
for (const check of profile.checks || []) {
|
|
750
|
+
if (check.type === "http_status") httpStatus += 1;
|
|
751
|
+
if (check.type === "link_status" || check.type === "artifact_link_status") linkStatus += 1;
|
|
752
|
+
}
|
|
753
|
+
return { httpStatus, linkStatus };
|
|
754
|
+
}
|
|
755
|
+
function riddleApiStrictSafetyWarnings(blocker) {
|
|
756
|
+
const rawWarnings = Array.isArray(blocker?.warnings) ? blocker.warnings.filter((warning) => typeof warning === "string") : [];
|
|
757
|
+
const errorText = typeof blocker?.error === "string" ? blocker.error.toLowerCase() : "";
|
|
758
|
+
const hasSafetyError = errorText.includes("potentially unsafe operations");
|
|
759
|
+
const hasDirectNetworkWarning = rawWarnings.some((warning) => warning.toLowerCase().includes("direct network operations"));
|
|
760
|
+
return hasSafetyError || hasDirectNetworkWarning ? rawWarnings : [];
|
|
761
|
+
}
|
|
762
|
+
function collectRiddleProofProfileEnvironmentBlockedWarnings(profile, blocker) {
|
|
763
|
+
const warnings = collectRiddleProofProfileWarnings(profile);
|
|
764
|
+
const safetyWarnings = riddleApiStrictSafetyWarnings(blocker);
|
|
765
|
+
if (!safetyWarnings.length) return warnings;
|
|
766
|
+
const counts = profileStatusProbeCounts(profile);
|
|
767
|
+
const statusProbeCount = counts.httpStatus + counts.linkStatus;
|
|
768
|
+
if (!statusProbeCount) return warnings;
|
|
769
|
+
const parts = [
|
|
770
|
+
counts.httpStatus ? `${counts.httpStatus} http_status` : "",
|
|
771
|
+
counts.linkStatus ? `${counts.linkStatus} link_status/artifact_link_status` : ""
|
|
772
|
+
].filter(Boolean);
|
|
773
|
+
warnings.push(
|
|
774
|
+
`Riddle API strict script validation blocked a hosted profile runner with ${parts.join(" and ")} check(s). These checks intentionally collect endpoint/link evidence from inside the generated browser runner; hosted run-profile defaults to --strict=false, so omit --strict=true or rerun with --strict=false for trusted generated profile runs.`
|
|
775
|
+
);
|
|
776
|
+
return warnings;
|
|
777
|
+
}
|
|
743
778
|
function normalizeRouteInventoryPath(value, label) {
|
|
744
779
|
const path = stringValue(value);
|
|
745
780
|
if (!path) throw new Error(`${label} requires path.`);
|
|
@@ -816,6 +851,14 @@ function validateRegexPatterns(patterns, label) {
|
|
|
816
851
|
}
|
|
817
852
|
}
|
|
818
853
|
}
|
|
854
|
+
function isDialogCountCheckType(type) {
|
|
855
|
+
return type === "dialog_count_equals" || type === "dialog_accept_count_equals" || type === "dialog_dismiss_count_equals";
|
|
856
|
+
}
|
|
857
|
+
function dialogCountFieldForCheckType(type) {
|
|
858
|
+
if (type === "dialog_accept_count_equals") return "dialog_accept_count";
|
|
859
|
+
if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
|
|
860
|
+
return "dialog_count";
|
|
861
|
+
}
|
|
819
862
|
function normalizeCheck(input, index) {
|
|
820
863
|
if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
|
|
821
864
|
const type = stringValue(input.type);
|
|
@@ -823,6 +866,7 @@ function normalizeCheck(input, index) {
|
|
|
823
866
|
if (!isSupportedCheckType(type)) {
|
|
824
867
|
throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
|
|
825
868
|
}
|
|
869
|
+
const isDialogCountCheck = isDialogCountCheckType(type);
|
|
826
870
|
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") && !stringValue(input.selector)) {
|
|
827
871
|
throw new Error(`checks[${index}] ${type} requires selector.`);
|
|
828
872
|
}
|
|
@@ -854,9 +898,12 @@ function normalizeCheck(input, index) {
|
|
|
854
898
|
throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
|
|
855
899
|
}
|
|
856
900
|
const expectedCount = numberValue(input.expected_count) ?? numberValue(input.expectedCount) ?? numberValue(input.count);
|
|
857
|
-
if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && expectedCount === void 0) {
|
|
901
|
+
if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || isDialogCountCheck) && expectedCount === void 0) {
|
|
858
902
|
throw new Error(`checks[${index}] ${type} requires expected_count.`);
|
|
859
903
|
}
|
|
904
|
+
if (isDialogCountCheck && (expectedCount === void 0 || !Number.isInteger(expectedCount) || expectedCount < 0)) {
|
|
905
|
+
throw new Error(`checks[${index}] ${type} expected_count must be a non-negative integer.`);
|
|
906
|
+
}
|
|
860
907
|
const expectedTexts = normalizeExpectedTexts(input.expected_texts ?? input.expectedTexts, index);
|
|
861
908
|
if (type === "selector_text_order") {
|
|
862
909
|
if (!stringValue(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
|
|
@@ -1526,6 +1573,22 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
1526
1573
|
message: check.viewports?.length ? `No matching viewport evidence was captured for ${check.viewports.join(", ")}.` : "No viewport evidence was captured."
|
|
1527
1574
|
};
|
|
1528
1575
|
}
|
|
1576
|
+
if (isDialogCountCheckType(check.type)) {
|
|
1577
|
+
const field = dialogCountFieldForCheckType(check.type);
|
|
1578
|
+
const expectedCount = check.expected_count ?? 0;
|
|
1579
|
+
const actualCount = numberValue(evidence.dom_summary?.[field]) ?? 0;
|
|
1580
|
+
return {
|
|
1581
|
+
type: check.type,
|
|
1582
|
+
label: checkLabel(check),
|
|
1583
|
+
status: actualCount === expectedCount ? "passed" : "failed",
|
|
1584
|
+
evidence: {
|
|
1585
|
+
field,
|
|
1586
|
+
expected_count: expectedCount,
|
|
1587
|
+
count: actualCount
|
|
1588
|
+
},
|
|
1589
|
+
message: actualCount === expectedCount ? void 0 : `${field} did not equal ${expectedCount}; observed ${actualCount}.`
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1529
1592
|
if (check.type === "route_loaded") {
|
|
1530
1593
|
const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
|
|
1531
1594
|
const failed = viewports.filter((viewport) => !successfulRoute({
|
|
@@ -2236,7 +2299,7 @@ function createRiddleProofProfileConfigurationError(name, error, runner = "riddl
|
|
|
2236
2299
|
function createRiddleProofProfileEnvironmentBlockedResult(input) {
|
|
2237
2300
|
const message = input.error instanceof Error ? input.error.message : input.error ? String(input.error) : "Riddle runner did not complete successfully.";
|
|
2238
2301
|
const environmentBlocker = extractRiddleRunnerBlocker(message);
|
|
2239
|
-
const warnings =
|
|
2302
|
+
const warnings = collectRiddleProofProfileEnvironmentBlockedWarnings(input.profile, environmentBlocker);
|
|
2240
2303
|
return {
|
|
2241
2304
|
version: RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
2242
2305
|
profile_name: input.profile.name,
|
|
@@ -2279,6 +2342,11 @@ function extractRiddleRunnerBlocker(message) {
|
|
|
2279
2342
|
for (const key of ["error", "required_seconds", "available_seconds", "deficit_seconds", "minimum_purchase_dollars"]) {
|
|
2280
2343
|
copyScalar(key);
|
|
2281
2344
|
}
|
|
2345
|
+
const warnings = payload?.warnings;
|
|
2346
|
+
if (Array.isArray(warnings)) {
|
|
2347
|
+
const warningStrings = warnings.filter((warning) => typeof warning === "string");
|
|
2348
|
+
if (warningStrings.length) details.warnings = warningStrings;
|
|
2349
|
+
}
|
|
2282
2350
|
const httpStatus = typeof details.http_status === "number" ? details.http_status : void 0;
|
|
2283
2351
|
const errorText = typeof details.error === "string" ? details.error.toLowerCase() : "";
|
|
2284
2352
|
if (httpStatus === 402 && errorText.includes("balance")) {
|
|
@@ -2777,6 +2845,16 @@ function summarizeRouteInventory(viewport, inventory) {
|
|
|
2777
2845
|
function numberValue(value) {
|
|
2778
2846
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
2779
2847
|
}
|
|
2848
|
+
function isDialogCountCheckType(type) {
|
|
2849
|
+
return type === "dialog_count_equals"
|
|
2850
|
+
|| type === "dialog_accept_count_equals"
|
|
2851
|
+
|| type === "dialog_dismiss_count_equals";
|
|
2852
|
+
}
|
|
2853
|
+
function dialogCountFieldForCheckType(type) {
|
|
2854
|
+
if (type === "dialog_accept_count_equals") return "dialog_accept_count";
|
|
2855
|
+
if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
|
|
2856
|
+
return "dialog_count";
|
|
2857
|
+
}
|
|
2780
2858
|
function maxPositiveNumber() {
|
|
2781
2859
|
let max = 0;
|
|
2782
2860
|
for (const value of arguments) {
|
|
@@ -3148,6 +3226,19 @@ function assessProfile(profile, evidence) {
|
|
|
3148
3226
|
});
|
|
3149
3227
|
continue;
|
|
3150
3228
|
}
|
|
3229
|
+
if (isDialogCountCheckType(check.type)) {
|
|
3230
|
+
const field = dialogCountFieldForCheckType(check.type);
|
|
3231
|
+
const expectedCount = check.expected_count == null ? 0 : check.expected_count;
|
|
3232
|
+
const actualCount = numberValue(evidence.dom_summary && evidence.dom_summary[field]) ?? 0;
|
|
3233
|
+
checks.push({
|
|
3234
|
+
type: check.type,
|
|
3235
|
+
label: check.label || check.type,
|
|
3236
|
+
status: actualCount === expectedCount ? "passed" : "failed",
|
|
3237
|
+
evidence: { field, expected_count: expectedCount, count: actualCount },
|
|
3238
|
+
message: actualCount === expectedCount ? undefined : field + " did not equal " + expectedCount + "; observed " + actualCount + ".",
|
|
3239
|
+
});
|
|
3240
|
+
continue;
|
|
3241
|
+
}
|
|
3151
3242
|
if (check.type === "route_loaded") {
|
|
3152
3243
|
const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
|
|
3153
3244
|
const failed = checkViewports.filter((viewport) => {
|
package/dist/profile.d.cts
CHANGED
|
@@ -4,7 +4,7 @@ declare const RIDDLE_PROOF_PROFILE_VERSION: "riddle-proof.profile.v1";
|
|
|
4
4
|
declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evidence.v1";
|
|
5
5
|
declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
|
|
6
6
|
declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
|
|
7
|
-
declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_visible", "selector_text_absent", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
|
|
7
|
+
declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "selector_text_visible", "selector_text_absent", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
|
|
8
8
|
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call"];
|
|
9
9
|
type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
|
|
10
10
|
type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
|
package/dist/profile.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ declare const RIDDLE_PROOF_PROFILE_VERSION: "riddle-proof.profile.v1";
|
|
|
4
4
|
declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evidence.v1";
|
|
5
5
|
declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
|
|
6
6
|
declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
|
|
7
|
-
declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_visible", "selector_text_absent", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
|
|
7
|
+
declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "selector_text_visible", "selector_text_absent", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
|
|
8
8
|
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call"];
|
|
9
9
|
type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
|
|
10
10
|
type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
|
package/dist/profile.js
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
resolveRiddleProofProfileTimeoutSec,
|
|
21
21
|
slugifyRiddleProofProfileName,
|
|
22
22
|
summarizeRiddleProofProfileResult
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-SBOGXOV5.js";
|
|
24
24
|
export {
|
|
25
25
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
26
26
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|