@riddledc/riddle-proof 0.7.126 → 0.7.127
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 +24 -2
- package/dist/{chunk-55KDZEB3.js → chunk-JLINSUKO.js} +431 -4
- package/dist/cli.cjs +449 -5
- package/dist/cli.js +19 -2
- package/dist/index.cjs +431 -4
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/profile.cjs +431 -4
- package/dist/profile.d.cts +28 -1
- package/dist/profile.d.ts +28 -1
- package/dist/profile.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
profileStatusExitCode,
|
|
13
13
|
resolveRiddleProofProfileTargetUrl,
|
|
14
14
|
resolveRiddleProofProfileTimeoutSec
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-JLINSUKO.js";
|
|
16
16
|
import {
|
|
17
17
|
createRiddleApiClient,
|
|
18
18
|
parseRiddleViewport
|
|
@@ -741,6 +741,21 @@ function profileHttpStatusAssertionKeys(evidence, viewports, field) {
|
|
|
741
741
|
}
|
|
742
742
|
return [...keys];
|
|
743
743
|
}
|
|
744
|
+
function profileHttpStatusJsonAssertionCount(viewports) {
|
|
745
|
+
if (!viewports.length) return void 0;
|
|
746
|
+
let passed = 0;
|
|
747
|
+
let total = 0;
|
|
748
|
+
for (const viewport of viewports) {
|
|
749
|
+
if (!Array.isArray(viewport.body_json_assertions)) continue;
|
|
750
|
+
for (const assertion of viewport.body_json_assertions) {
|
|
751
|
+
const record = cliRecord(assertion);
|
|
752
|
+
if (!record) continue;
|
|
753
|
+
total += 1;
|
|
754
|
+
if (record.ok === true) passed += 1;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
return total ? { passed, total } : void 0;
|
|
758
|
+
}
|
|
744
759
|
function profileHttpStatusSummaryMarkdown(result) {
|
|
745
760
|
const httpStatusChecks = result.checks.filter((check) => check.type === "http_status");
|
|
746
761
|
const lines = [];
|
|
@@ -771,10 +786,12 @@ function profileHttpStatusSummaryMarkdown(result) {
|
|
|
771
786
|
profileHttpStatusAssertionKeys(evidence, viewports, "body_not_patterns"),
|
|
772
787
|
false
|
|
773
788
|
);
|
|
789
|
+
const bodyJsonAssertions = profileHttpStatusJsonAssertionCount(viewports);
|
|
774
790
|
const bodyParts = [
|
|
775
791
|
bodyContains ? `body_contains ${bodyContains.passed}/${bodyContains.total}` : "",
|
|
776
792
|
bodyNotContains ? `body_not_contains clean ${bodyNotContains.passed}/${bodyNotContains.total}` : "",
|
|
777
|
-
bodyNotPatterns ? `body_not_patterns clean ${bodyNotPatterns.passed}/${bodyNotPatterns.total}` : ""
|
|
793
|
+
bodyNotPatterns ? `body_not_patterns clean ${bodyNotPatterns.passed}/${bodyNotPatterns.total}` : "",
|
|
794
|
+
bodyJsonAssertions ? `body_json_assertions ${bodyJsonAssertions.passed}/${bodyJsonAssertions.total}` : ""
|
|
778
795
|
].filter(Boolean);
|
|
779
796
|
lines.push(
|
|
780
797
|
`- ${label}: ${method}${url ? ` ${markdownInlineCode(url)}` : ""}, statuses ${statuses.length ? statuses.join("/") : "unknown"}${bodyParts.length ? `, ${bodyParts.join(", ")}` : ""}, failures ${failedTotal}`
|
package/dist/index.cjs
CHANGED
|
@@ -8872,6 +8872,9 @@ function valueFromOwn(input, ...keys) {
|
|
|
8872
8872
|
function numberValue3(value) {
|
|
8873
8873
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
8874
8874
|
}
|
|
8875
|
+
function booleanValue(value) {
|
|
8876
|
+
return typeof value === "boolean" ? value : void 0;
|
|
8877
|
+
}
|
|
8875
8878
|
function horizontalBoundsOverflowPx2(value) {
|
|
8876
8879
|
if (!isRecord2(value)) return 0;
|
|
8877
8880
|
let max = maxPositiveNumber2(
|
|
@@ -8966,6 +8969,156 @@ function toJsonValue(value) {
|
|
|
8966
8969
|
if (isRecord2(value)) return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
|
|
8967
8970
|
return String(value);
|
|
8968
8971
|
}
|
|
8972
|
+
function jsonValueType(value) {
|
|
8973
|
+
if (value === null) return "null";
|
|
8974
|
+
if (Array.isArray(value)) return "array";
|
|
8975
|
+
if (typeof value === "boolean") return "boolean";
|
|
8976
|
+
if (typeof value === "number") return "number";
|
|
8977
|
+
if (typeof value === "string") return "string";
|
|
8978
|
+
return "object";
|
|
8979
|
+
}
|
|
8980
|
+
function deepJsonEqual(left, right) {
|
|
8981
|
+
if (left === right) return true;
|
|
8982
|
+
if (typeof left !== typeof right) return false;
|
|
8983
|
+
if (left === null || right === null) return left === right;
|
|
8984
|
+
if (typeof left !== "object" || typeof right !== "object") return false;
|
|
8985
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
8986
|
+
if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) return false;
|
|
8987
|
+
return left.every((item, index) => deepJsonEqual(item, right[index]));
|
|
8988
|
+
}
|
|
8989
|
+
if (!isRecord2(left) || !isRecord2(right)) return false;
|
|
8990
|
+
const leftKeys = Object.keys(left).sort();
|
|
8991
|
+
const rightKeys = Object.keys(right).sort();
|
|
8992
|
+
if (!deepJsonEqual(leftKeys, rightKeys)) return false;
|
|
8993
|
+
return leftKeys.every((key) => deepJsonEqual(left[key], right[key]));
|
|
8994
|
+
}
|
|
8995
|
+
function jsonContains(observed, expected) {
|
|
8996
|
+
if (typeof observed === "string" && typeof expected === "string") {
|
|
8997
|
+
return observed.includes(expected);
|
|
8998
|
+
}
|
|
8999
|
+
if (Array.isArray(observed)) {
|
|
9000
|
+
return observed.some((item) => deepJsonEqual(item, expected));
|
|
9001
|
+
}
|
|
9002
|
+
if (isRecord2(observed) && isRecord2(expected)) {
|
|
9003
|
+
return Object.entries(expected).every(([key, value]) => hasOwn(observed, key) && deepJsonEqual(observed[key], value));
|
|
9004
|
+
}
|
|
9005
|
+
return false;
|
|
9006
|
+
}
|
|
9007
|
+
function parseJsonPathSegments(path6) {
|
|
9008
|
+
let input = path6.trim();
|
|
9009
|
+
if (!input) throw new Error("path is empty");
|
|
9010
|
+
if (input === "$") return [];
|
|
9011
|
+
if (input.startsWith("$.")) input = input.slice(2);
|
|
9012
|
+
else if (input.startsWith("$[")) input = input.slice(1);
|
|
9013
|
+
const segments = [];
|
|
9014
|
+
let token = "";
|
|
9015
|
+
const pushToken = () => {
|
|
9016
|
+
if (!token) return;
|
|
9017
|
+
segments.push(token);
|
|
9018
|
+
token = "";
|
|
9019
|
+
};
|
|
9020
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
9021
|
+
const char = input[index];
|
|
9022
|
+
if (char === ".") {
|
|
9023
|
+
pushToken();
|
|
9024
|
+
continue;
|
|
9025
|
+
}
|
|
9026
|
+
if (char !== "[") {
|
|
9027
|
+
token += char;
|
|
9028
|
+
continue;
|
|
9029
|
+
}
|
|
9030
|
+
pushToken();
|
|
9031
|
+
const closeIndex = input.indexOf("]", index + 1);
|
|
9032
|
+
if (closeIndex === -1) throw new Error(`unterminated bracket at ${index}`);
|
|
9033
|
+
const bracket = input.slice(index + 1, closeIndex).trim();
|
|
9034
|
+
if (!bracket) throw new Error(`empty bracket at ${index}`);
|
|
9035
|
+
if (/^\d+$/.test(bracket)) {
|
|
9036
|
+
segments.push(Number(bracket));
|
|
9037
|
+
} else if (bracket.startsWith('"') && bracket.endsWith('"') || bracket.startsWith("'") && bracket.endsWith("'")) {
|
|
9038
|
+
const quoted = bracket.startsWith("'") ? `"${bracket.slice(1, -1).replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"` : bracket;
|
|
9039
|
+
segments.push(String(JSON.parse(quoted)));
|
|
9040
|
+
} else {
|
|
9041
|
+
segments.push(bracket);
|
|
9042
|
+
}
|
|
9043
|
+
index = closeIndex;
|
|
9044
|
+
}
|
|
9045
|
+
pushToken();
|
|
9046
|
+
return segments;
|
|
9047
|
+
}
|
|
9048
|
+
function resolveJsonPath(root, path6) {
|
|
9049
|
+
let segments;
|
|
9050
|
+
try {
|
|
9051
|
+
segments = parseJsonPathSegments(path6);
|
|
9052
|
+
} catch (error) {
|
|
9053
|
+
return { exists: false, error: String(error instanceof Error ? error.message : error) };
|
|
9054
|
+
}
|
|
9055
|
+
let current = root;
|
|
9056
|
+
for (const segment of segments) {
|
|
9057
|
+
if (typeof segment === "number") {
|
|
9058
|
+
if (!Array.isArray(current) || segment < 0 || segment >= current.length) return { exists: false };
|
|
9059
|
+
current = current[segment];
|
|
9060
|
+
continue;
|
|
9061
|
+
}
|
|
9062
|
+
if (!isRecord2(current) || !hasOwn(current, segment)) return { exists: false };
|
|
9063
|
+
current = current[segment];
|
|
9064
|
+
}
|
|
9065
|
+
return { exists: true, value: current };
|
|
9066
|
+
}
|
|
9067
|
+
function evaluateHttpStatusBodyJsonAssertion(root, assertion) {
|
|
9068
|
+
const resolved = resolveJsonPath(root, assertion.path);
|
|
9069
|
+
const errors = [];
|
|
9070
|
+
const result = {
|
|
9071
|
+
label: assertion.label || assertion.path,
|
|
9072
|
+
path: assertion.path,
|
|
9073
|
+
ok: true,
|
|
9074
|
+
exists: resolved.exists,
|
|
9075
|
+
observed_type: resolved.exists ? jsonValueType(resolved.value) : "missing"
|
|
9076
|
+
};
|
|
9077
|
+
if (resolved.exists) result.observed = toJsonValue(resolved.value);
|
|
9078
|
+
if (resolved.error) errors.push(resolved.error);
|
|
9079
|
+
if (hasOwn(assertion, "exists")) {
|
|
9080
|
+
result.expected_exists = assertion.exists;
|
|
9081
|
+
if (resolved.exists !== assertion.exists) errors.push(`expected exists=${assertion.exists}`);
|
|
9082
|
+
}
|
|
9083
|
+
if (hasOwn(assertion, "type")) {
|
|
9084
|
+
result.type = assertion.type;
|
|
9085
|
+
if (!resolved.exists || jsonValueType(resolved.value) !== assertion.type) errors.push(`expected type ${assertion.type}`);
|
|
9086
|
+
}
|
|
9087
|
+
if (hasOwn(assertion, "equals")) {
|
|
9088
|
+
result.equals = assertion.equals;
|
|
9089
|
+
if (!resolved.exists || !deepJsonEqual(resolved.value, assertion.equals)) errors.push("expected JSON value equality");
|
|
9090
|
+
}
|
|
9091
|
+
if (hasOwn(assertion, "not_equals")) {
|
|
9092
|
+
result.not_equals = assertion.not_equals;
|
|
9093
|
+
if (resolved.exists && deepJsonEqual(resolved.value, assertion.not_equals)) errors.push("expected JSON value inequality");
|
|
9094
|
+
}
|
|
9095
|
+
if (hasOwn(assertion, "contains")) {
|
|
9096
|
+
result.contains = assertion.contains;
|
|
9097
|
+
if (!resolved.exists || !jsonContains(resolved.value, assertion.contains)) errors.push("expected JSON value containment");
|
|
9098
|
+
}
|
|
9099
|
+
result.ok = errors.length === 0;
|
|
9100
|
+
if (errors.length) result.errors = errors;
|
|
9101
|
+
return result;
|
|
9102
|
+
}
|
|
9103
|
+
function evaluateHttpStatusBodyJsonAssertions(bodyText, assertions) {
|
|
9104
|
+
const expected = assertions?.filter((assertion) => assertion.path) ?? [];
|
|
9105
|
+
if (!expected.length) return [];
|
|
9106
|
+
let parsed;
|
|
9107
|
+
try {
|
|
9108
|
+
parsed = JSON.parse(bodyText);
|
|
9109
|
+
} catch (error) {
|
|
9110
|
+
const message = `response body is not valid JSON: ${String(error instanceof Error ? error.message : error).slice(0, 200)}`;
|
|
9111
|
+
return expected.map((assertion) => ({
|
|
9112
|
+
label: assertion.label || assertion.path,
|
|
9113
|
+
path: assertion.path,
|
|
9114
|
+
ok: false,
|
|
9115
|
+
exists: false,
|
|
9116
|
+
observed_type: "missing",
|
|
9117
|
+
errors: [message]
|
|
9118
|
+
}));
|
|
9119
|
+
}
|
|
9120
|
+
return expected.map((assertion) => evaluateHttpStatusBodyJsonAssertion(parsed, assertion));
|
|
9121
|
+
}
|
|
8969
9122
|
function compactProfileSetupSummaryText(value, limit = 160) {
|
|
8970
9123
|
const text = typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "";
|
|
8971
9124
|
if (!text) return void 0;
|
|
@@ -9620,6 +9773,46 @@ function validateRegexPatterns(patterns, label) {
|
|
|
9620
9773
|
}
|
|
9621
9774
|
}
|
|
9622
9775
|
}
|
|
9776
|
+
function normalizeHttpStatusBodyJsonAssertions(value, label) {
|
|
9777
|
+
if (value === void 0) return void 0;
|
|
9778
|
+
if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
|
|
9779
|
+
if (!value.length) throw new Error(`${label} must not be empty.`);
|
|
9780
|
+
return value.map((item, index) => {
|
|
9781
|
+
const itemLabel = `${label}[${index}]`;
|
|
9782
|
+
if (typeof item === "string") {
|
|
9783
|
+
const path7 = stringValue5(item);
|
|
9784
|
+
if (!path7) throw new Error(`${itemLabel} path must not be empty.`);
|
|
9785
|
+
return { path: path7, exists: true };
|
|
9786
|
+
}
|
|
9787
|
+
if (!isRecord2(item)) throw new Error(`${itemLabel} must be an object or JSON path string.`);
|
|
9788
|
+
const path6 = stringFromOwn(item, "path", "json_path", "jsonPath", "key");
|
|
9789
|
+
if (!path6) throw new Error(`${itemLabel}.path is required.`);
|
|
9790
|
+
const assertion = {
|
|
9791
|
+
label: stringValue5(item.label),
|
|
9792
|
+
path: path6
|
|
9793
|
+
};
|
|
9794
|
+
const exists = booleanValue(valueFromOwn(item, "exists", "present"));
|
|
9795
|
+
if (exists !== void 0) assertion.exists = exists;
|
|
9796
|
+
const type = stringValue5(valueFromOwn(item, "type", "value_type", "valueType"));
|
|
9797
|
+
if (type !== void 0) {
|
|
9798
|
+
const allowedTypes = ["array", "boolean", "null", "number", "object", "string"];
|
|
9799
|
+
if (!allowedTypes.includes(type)) {
|
|
9800
|
+
throw new Error(`${itemLabel}.type must be one of ${allowedTypes.join(", ")}.`);
|
|
9801
|
+
}
|
|
9802
|
+
assertion.type = type;
|
|
9803
|
+
}
|
|
9804
|
+
const equalsValue = valueFromOwn(item, "equals", "expected", "expected_value", "expectedValue", "value");
|
|
9805
|
+
if (equalsValue !== void 0) assertion.equals = toJsonValue(equalsValue);
|
|
9806
|
+
const notEqualsValue = valueFromOwn(item, "not_equals", "notEquals", "forbidden", "forbidden_value", "forbiddenValue");
|
|
9807
|
+
if (notEqualsValue !== void 0) assertion.not_equals = toJsonValue(notEqualsValue);
|
|
9808
|
+
const containsValue = valueFromOwn(item, "contains", "includes", "contains_value", "containsValue", "include");
|
|
9809
|
+
if (containsValue !== void 0) assertion.contains = toJsonValue(containsValue);
|
|
9810
|
+
if (assertion.exists === void 0 && assertion.type === void 0 && !hasOwn(assertion, "equals") && !hasOwn(assertion, "not_equals") && !hasOwn(assertion, "contains")) {
|
|
9811
|
+
assertion.exists = true;
|
|
9812
|
+
}
|
|
9813
|
+
return assertion;
|
|
9814
|
+
});
|
|
9815
|
+
}
|
|
9623
9816
|
function isDialogCountCheckType(type) {
|
|
9624
9817
|
return type === "dialog_count_equals" || type === "dialog_accept_count_equals" || type === "dialog_dismiss_count_equals";
|
|
9625
9818
|
}
|
|
@@ -9719,6 +9912,10 @@ function normalizeCheck(input, index) {
|
|
|
9719
9912
|
`checks[${index}] body_not_patterns`
|
|
9720
9913
|
) : void 0;
|
|
9721
9914
|
if (bodyNotPatterns?.length) validateRegexPatterns(bodyNotPatterns, `checks[${index}] body_not_patterns`);
|
|
9915
|
+
const bodyJsonAssertions = isHttpStatusCheck ? normalizeHttpStatusBodyJsonAssertions(
|
|
9916
|
+
input.body_json_assertions ?? input.bodyJsonAssertions ?? input.json_body_assertions ?? input.jsonBodyAssertions ?? input.json_assertions ?? input.jsonAssertions ?? input.response_json_assertions ?? input.responseJsonAssertions,
|
|
9917
|
+
`checks[${index}] body_json_assertions`
|
|
9918
|
+
) : void 0;
|
|
9722
9919
|
if (isLinkStatusCheck) {
|
|
9723
9920
|
if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
|
|
9724
9921
|
throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
|
|
@@ -9744,6 +9941,7 @@ function normalizeCheck(input, index) {
|
|
|
9744
9941
|
body_contains: bodyContains,
|
|
9745
9942
|
body_not_contains: bodyNotContains,
|
|
9746
9943
|
body_not_patterns: bodyNotPatterns,
|
|
9944
|
+
body_json_assertions: bodyJsonAssertions,
|
|
9747
9945
|
expected_texts: expectedTexts,
|
|
9748
9946
|
link_selector: stringValue5(input.link_selector) || stringValue5(input.linkSelector),
|
|
9749
9947
|
source_selector: stringValue5(input.source_selector) || stringValue5(input.sourceSelector),
|
|
@@ -9950,6 +10148,34 @@ function httpStatusBodyNotPatternFailures(result, check) {
|
|
|
9950
10148
|
const observed = isRecord2(result.body_not_patterns) ? result.body_not_patterns : {};
|
|
9951
10149
|
return forbidden.filter((pattern) => observed[pattern] !== false);
|
|
9952
10150
|
}
|
|
10151
|
+
function httpStatusBodyJsonAssertionFailures(result, check) {
|
|
10152
|
+
const expected = check.body_json_assertions?.filter((assertion) => assertion.path) ?? [];
|
|
10153
|
+
if (!expected.length) return [];
|
|
10154
|
+
if (!Array.isArray(result.body_json_assertions)) {
|
|
10155
|
+
return expected.map((assertion) => ({
|
|
10156
|
+
label: assertion.label || assertion.path,
|
|
10157
|
+
path: assertion.path,
|
|
10158
|
+
ok: false,
|
|
10159
|
+
exists: false,
|
|
10160
|
+
observed_type: "missing",
|
|
10161
|
+
errors: ["body_json_assertions evidence missing"]
|
|
10162
|
+
}));
|
|
10163
|
+
}
|
|
10164
|
+
return result.body_json_assertions.filter((assertion) => isRecord2(assertion) && assertion.ok !== true).map((assertion) => ({
|
|
10165
|
+
label: stringValue5(assertion.label) || stringValue5(assertion.path) || "json assertion",
|
|
10166
|
+
path: stringValue5(assertion.path) || "",
|
|
10167
|
+
ok: false,
|
|
10168
|
+
exists: assertion.exists === true,
|
|
10169
|
+
observed: hasOwn(assertion, "observed") ? toJsonValue(assertion.observed) : void 0,
|
|
10170
|
+
observed_type: stringValue5(assertion.observed_type) || "missing",
|
|
10171
|
+
expected_exists: booleanValue(assertion.expected_exists),
|
|
10172
|
+
equals: hasOwn(assertion, "equals") ? toJsonValue(assertion.equals) : void 0,
|
|
10173
|
+
not_equals: hasOwn(assertion, "not_equals") ? toJsonValue(assertion.not_equals) : void 0,
|
|
10174
|
+
contains: hasOwn(assertion, "contains") ? toJsonValue(assertion.contains) : void 0,
|
|
10175
|
+
type: stringValue5(assertion.type),
|
|
10176
|
+
errors: Array.isArray(assertion.errors) ? assertion.errors.map(String) : void 0
|
|
10177
|
+
}));
|
|
10178
|
+
}
|
|
9953
10179
|
function linkStatusResultOk(result, check) {
|
|
9954
10180
|
const status = numberValue3(result.status);
|
|
9955
10181
|
if (!httpStatusIsAllowed(status, check)) return false;
|
|
@@ -9967,6 +10193,7 @@ function linkStatusResultOk(result, check) {
|
|
|
9967
10193
|
if (httpStatusBodyContainsFailures(result, check).length) return false;
|
|
9968
10194
|
if (httpStatusBodyNotContainsFailures(result, check).length) return false;
|
|
9969
10195
|
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
10196
|
+
if (httpStatusBodyJsonAssertionFailures(result, check).length) return false;
|
|
9970
10197
|
return true;
|
|
9971
10198
|
}
|
|
9972
10199
|
function responseHeader(response, name) {
|
|
@@ -10035,7 +10262,7 @@ async function preflightHttpStatusCheck(check, index, targetUrl, fetchImpl) {
|
|
|
10035
10262
|
statusText = typeof response.statusText === "string" ? response.statusText : "";
|
|
10036
10263
|
result.content_type = responseHeader(response, "content-type");
|
|
10037
10264
|
result.content_length = responseContentLength(response);
|
|
10038
|
-
const shouldReadBody = check.require_nonzero_bytes === true || typeof check.min_bytes === "number" || Boolean(check.body_contains?.length) || Boolean(check.body_not_contains?.length) || Boolean(check.body_not_patterns?.length);
|
|
10265
|
+
const shouldReadBody = check.require_nonzero_bytes === true || typeof check.min_bytes === "number" || Boolean(check.body_contains?.length) || Boolean(check.body_not_contains?.length) || Boolean(check.body_not_patterns?.length) || Boolean(check.body_json_assertions?.length);
|
|
10039
10266
|
if (shouldReadBody && method !== "HEAD") {
|
|
10040
10267
|
const body = await responseBodyText(response);
|
|
10041
10268
|
result.bytes = body.bytes;
|
|
@@ -10048,6 +10275,9 @@ async function preflightHttpStatusCheck(check, index, targetUrl, fetchImpl) {
|
|
|
10048
10275
|
if (check.body_not_patterns?.length) {
|
|
10049
10276
|
result.body_not_patterns = Object.fromEntries(check.body_not_patterns.filter(Boolean).map((pattern) => [pattern, new RegExp(pattern).test(body.text)]));
|
|
10050
10277
|
}
|
|
10278
|
+
if (check.body_json_assertions?.length) {
|
|
10279
|
+
result.body_json_assertions = evaluateHttpStatusBodyJsonAssertions(body.text, check.body_json_assertions);
|
|
10280
|
+
}
|
|
10051
10281
|
}
|
|
10052
10282
|
} catch (caught) {
|
|
10053
10283
|
error = String(caught instanceof Error ? caught.message : caught).slice(0, 500);
|
|
@@ -10056,6 +10286,7 @@ async function preflightHttpStatusCheck(check, index, targetUrl, fetchImpl) {
|
|
|
10056
10286
|
const bodyContainsMissing = httpStatusBodyContainsFailures(result, check);
|
|
10057
10287
|
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(result, check);
|
|
10058
10288
|
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(result, check);
|
|
10289
|
+
const bodyJsonAssertionsFailed = httpStatusBodyJsonAssertionFailures(result, check);
|
|
10059
10290
|
const ok = !error && linkStatusResultOk(result, check);
|
|
10060
10291
|
return {
|
|
10061
10292
|
index,
|
|
@@ -10074,7 +10305,9 @@ async function preflightHttpStatusCheck(check, index, targetUrl, fetchImpl) {
|
|
|
10074
10305
|
body_not_contains: isRecord2(result.body_not_contains) ? Object.fromEntries(Object.entries(result.body_not_contains).map(([key, value]) => [key, value === true])) : null,
|
|
10075
10306
|
body_not_contains_found: bodyNotContainsFound,
|
|
10076
10307
|
body_not_patterns: isRecord2(result.body_not_patterns) ? Object.fromEntries(Object.entries(result.body_not_patterns).map(([key, value]) => [key, value === true])) : null,
|
|
10077
|
-
body_not_patterns_found: bodyNotPatternsFound
|
|
10308
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
10309
|
+
body_json_assertions: Array.isArray(result.body_json_assertions) ? result.body_json_assertions : null,
|
|
10310
|
+
body_json_assertions_failed: bodyJsonAssertionsFailed
|
|
10078
10311
|
};
|
|
10079
10312
|
}
|
|
10080
10313
|
async function preflightRiddleProofProfileHttpStatusChecks(profile, options = {}) {
|
|
@@ -10119,6 +10352,7 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
10119
10352
|
const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
|
|
10120
10353
|
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
|
|
10121
10354
|
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
|
|
10355
|
+
const bodyJsonAssertionsFailed = httpStatusBodyJsonAssertionFailures(statusEvidence, check);
|
|
10122
10356
|
if (!linkStatusResultOk(statusEvidence, check)) {
|
|
10123
10357
|
failures.push({
|
|
10124
10358
|
code: "http_status_failed",
|
|
@@ -10137,6 +10371,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
10137
10371
|
body_not_contains_found: bodyNotContainsFound,
|
|
10138
10372
|
body_not_patterns: check.body_not_patterns ?? null,
|
|
10139
10373
|
body_not_patterns_found: bodyNotPatternsFound,
|
|
10374
|
+
body_json_assertions: check.body_json_assertions ?? null,
|
|
10375
|
+
body_json_assertions_failed: bodyJsonAssertionsFailed.map((assertion) => toJsonValue(assertion)),
|
|
10140
10376
|
body_sample: stringValue5(statusEvidence.body_sample) ?? null
|
|
10141
10377
|
});
|
|
10142
10378
|
}
|
|
@@ -10158,6 +10394,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
10158
10394
|
body_not_contains_found: bodyNotContainsFound,
|
|
10159
10395
|
body_not_patterns: isRecord2(statusEvidence.body_not_patterns) ? toJsonValue(statusEvidence.body_not_patterns) : null,
|
|
10160
10396
|
body_not_patterns_found: bodyNotPatternsFound,
|
|
10397
|
+
body_json_assertions: Array.isArray(statusEvidence.body_json_assertions) ? toJsonValue(statusEvidence.body_json_assertions) : null,
|
|
10398
|
+
body_json_assertions_failed: bodyJsonAssertionsFailed.map((assertion) => toJsonValue(assertion)),
|
|
10161
10399
|
body_sample: stringValue5(statusEvidence.body_sample) ?? null,
|
|
10162
10400
|
failures
|
|
10163
10401
|
};
|
|
@@ -10794,6 +11032,7 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
10794
11032
|
body_contains: check.body_contains ?? [],
|
|
10795
11033
|
body_not_contains: check.body_not_contains ?? [],
|
|
10796
11034
|
body_not_patterns: check.body_not_patterns ?? [],
|
|
11035
|
+
body_json_assertions: toJsonValue(check.body_json_assertions ?? []),
|
|
10797
11036
|
viewports: summaries.map((summary) => toJsonValue(summary)),
|
|
10798
11037
|
failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue5(summary.viewport) ?? null, failure })) : [])
|
|
10799
11038
|
},
|
|
@@ -11537,6 +11776,36 @@ function httpStatusBodyNotPatternFailures(result, check) {
|
|
|
11537
11776
|
: {};
|
|
11538
11777
|
return forbidden.filter((pattern) => observed[pattern] !== false);
|
|
11539
11778
|
}
|
|
11779
|
+
function httpStatusBodyJsonAssertionFailures(result, check) {
|
|
11780
|
+
const expected = Array.isArray(check.body_json_assertions) ? check.body_json_assertions.filter((assertion) => assertion && assertion.path) : [];
|
|
11781
|
+
if (!expected.length) return [];
|
|
11782
|
+
if (!Array.isArray(result.body_json_assertions)) {
|
|
11783
|
+
return expected.map((assertion) => ({
|
|
11784
|
+
label: assertion.label || assertion.path,
|
|
11785
|
+
path: assertion.path,
|
|
11786
|
+
ok: false,
|
|
11787
|
+
exists: false,
|
|
11788
|
+
observed_type: "missing",
|
|
11789
|
+
errors: ["body_json_assertions evidence missing"],
|
|
11790
|
+
}));
|
|
11791
|
+
}
|
|
11792
|
+
return result.body_json_assertions
|
|
11793
|
+
.filter((assertion) => assertion && typeof assertion === "object" && assertion.ok !== true)
|
|
11794
|
+
.map((assertion) => ({
|
|
11795
|
+
label: typeof assertion.label === "string" && assertion.label ? assertion.label : typeof assertion.path === "string" && assertion.path ? assertion.path : "json assertion",
|
|
11796
|
+
path: typeof assertion.path === "string" ? assertion.path : "",
|
|
11797
|
+
ok: false,
|
|
11798
|
+
exists: assertion.exists === true,
|
|
11799
|
+
observed: Object.hasOwn(assertion, "observed") ? assertion.observed : undefined,
|
|
11800
|
+
observed_type: typeof assertion.observed_type === "string" && assertion.observed_type ? assertion.observed_type : "missing",
|
|
11801
|
+
expected_exists: typeof assertion.expected_exists === "boolean" ? assertion.expected_exists : undefined,
|
|
11802
|
+
equals: Object.hasOwn(assertion, "equals") ? assertion.equals : undefined,
|
|
11803
|
+
not_equals: Object.hasOwn(assertion, "not_equals") ? assertion.not_equals : undefined,
|
|
11804
|
+
contains: Object.hasOwn(assertion, "contains") ? assertion.contains : undefined,
|
|
11805
|
+
type: typeof assertion.type === "string" ? assertion.type : undefined,
|
|
11806
|
+
errors: Array.isArray(assertion.errors) ? assertion.errors.map(String) : undefined,
|
|
11807
|
+
}));
|
|
11808
|
+
}
|
|
11540
11809
|
function linkStatusResultOk(result, check) {
|
|
11541
11810
|
if (!result || typeof result !== "object" || Array.isArray(result)) return false;
|
|
11542
11811
|
if (!httpStatusIsAllowed(result.status, check)) return false;
|
|
@@ -11554,6 +11823,7 @@ function linkStatusResultOk(result, check) {
|
|
|
11554
11823
|
if (httpStatusBodyContainsFailures(result, check).length) return false;
|
|
11555
11824
|
if (httpStatusBodyNotContainsFailures(result, check).length) return false;
|
|
11556
11825
|
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
11826
|
+
if (httpStatusBodyJsonAssertionFailures(result, check).length) return false;
|
|
11557
11827
|
return true;
|
|
11558
11828
|
}
|
|
11559
11829
|
function summarizeHttpStatusEvidence(viewport, check) {
|
|
@@ -11574,6 +11844,7 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
11574
11844
|
const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
|
|
11575
11845
|
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
|
|
11576
11846
|
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
|
|
11847
|
+
const bodyJsonAssertionsFailed = httpStatusBodyJsonAssertionFailures(statusEvidence, check);
|
|
11577
11848
|
if (!linkStatusResultOk(statusEvidence, check)) {
|
|
11578
11849
|
failures.push({
|
|
11579
11850
|
code: "http_status_failed",
|
|
@@ -11592,6 +11863,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
11592
11863
|
body_not_contains_found: bodyNotContainsFound,
|
|
11593
11864
|
body_not_patterns: Array.isArray(check.body_not_patterns) ? check.body_not_patterns : null,
|
|
11594
11865
|
body_not_patterns_found: bodyNotPatternsFound,
|
|
11866
|
+
body_json_assertions: Array.isArray(check.body_json_assertions) ? check.body_json_assertions : null,
|
|
11867
|
+
body_json_assertions_failed: bodyJsonAssertionsFailed,
|
|
11595
11868
|
body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
|
|
11596
11869
|
});
|
|
11597
11870
|
}
|
|
@@ -11619,6 +11892,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
11619
11892
|
? statusEvidence.body_not_patterns
|
|
11620
11893
|
: null,
|
|
11621
11894
|
body_not_patterns_found: bodyNotPatternsFound,
|
|
11895
|
+
body_json_assertions: Array.isArray(statusEvidence.body_json_assertions) ? statusEvidence.body_json_assertions : null,
|
|
11896
|
+
body_json_assertions_failed: bodyJsonAssertionsFailed,
|
|
11622
11897
|
body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
|
|
11623
11898
|
failures,
|
|
11624
11899
|
};
|
|
@@ -13721,6 +13996,155 @@ function linkProbeResponseFields(response, method) {
|
|
|
13721
13996
|
content_length: contentLength,
|
|
13722
13997
|
};
|
|
13723
13998
|
}
|
|
13999
|
+
function jsonProbeValueType(value) {
|
|
14000
|
+
if (value === null) return "null";
|
|
14001
|
+
if (Array.isArray(value)) return "array";
|
|
14002
|
+
if (typeof value === "boolean") return "boolean";
|
|
14003
|
+
if (typeof value === "number") return "number";
|
|
14004
|
+
if (typeof value === "string") return "string";
|
|
14005
|
+
return "object";
|
|
14006
|
+
}
|
|
14007
|
+
function jsonProbeDeepEqual(left, right) {
|
|
14008
|
+
if (left === right) return true;
|
|
14009
|
+
if (typeof left !== typeof right) return false;
|
|
14010
|
+
if (left === null || right === null) return left === right;
|
|
14011
|
+
if (typeof left !== "object" || typeof right !== "object") return false;
|
|
14012
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
14013
|
+
if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) return false;
|
|
14014
|
+
return left.every((item, index) => jsonProbeDeepEqual(item, right[index]));
|
|
14015
|
+
}
|
|
14016
|
+
const leftKeys = Object.keys(left).sort();
|
|
14017
|
+
const rightKeys = Object.keys(right).sort();
|
|
14018
|
+
if (!jsonProbeDeepEqual(leftKeys, rightKeys)) return false;
|
|
14019
|
+
return leftKeys.every((key) => jsonProbeDeepEqual(left[key], right[key]));
|
|
14020
|
+
}
|
|
14021
|
+
function jsonProbeContains(observed, expected) {
|
|
14022
|
+
if (typeof observed === "string" && typeof expected === "string") return observed.includes(expected);
|
|
14023
|
+
if (Array.isArray(observed)) return observed.some((item) => jsonProbeDeepEqual(item, expected));
|
|
14024
|
+
if (observed && expected && typeof observed === "object" && typeof expected === "object" && !Array.isArray(observed) && !Array.isArray(expected)) {
|
|
14025
|
+
return Object.entries(expected).every(([key, value]) => Object.hasOwn(observed, key) && jsonProbeDeepEqual(observed[key], value));
|
|
14026
|
+
}
|
|
14027
|
+
return false;
|
|
14028
|
+
}
|
|
14029
|
+
function parseJsonProbePathSegments(path) {
|
|
14030
|
+
let input = String(path || "").trim();
|
|
14031
|
+
if (!input) throw new Error("path is empty");
|
|
14032
|
+
if (input === "$") return [];
|
|
14033
|
+
if (input.startsWith("$.")) input = input.slice(2);
|
|
14034
|
+
else if (input.startsWith("$[")) input = input.slice(1);
|
|
14035
|
+
const segments = [];
|
|
14036
|
+
let token = "";
|
|
14037
|
+
const pushToken = () => {
|
|
14038
|
+
if (!token) return;
|
|
14039
|
+
segments.push(token);
|
|
14040
|
+
token = "";
|
|
14041
|
+
};
|
|
14042
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
14043
|
+
const char = input[index];
|
|
14044
|
+
if (char === ".") {
|
|
14045
|
+
pushToken();
|
|
14046
|
+
continue;
|
|
14047
|
+
}
|
|
14048
|
+
if (char !== "[") {
|
|
14049
|
+
token += char;
|
|
14050
|
+
continue;
|
|
14051
|
+
}
|
|
14052
|
+
pushToken();
|
|
14053
|
+
const closeIndex = input.indexOf("]", index + 1);
|
|
14054
|
+
if (closeIndex === -1) throw new Error("unterminated bracket at " + index);
|
|
14055
|
+
const bracket = input.slice(index + 1, closeIndex).trim();
|
|
14056
|
+
if (!bracket) throw new Error("empty bracket at " + index);
|
|
14057
|
+
if (/^\d+$/.test(bracket)) {
|
|
14058
|
+
segments.push(Number(bracket));
|
|
14059
|
+
} else if ((bracket.startsWith('"') && bracket.endsWith('"')) || (bracket.startsWith("'") && bracket.endsWith("'"))) {
|
|
14060
|
+
const quoted = bracket.startsWith("'")
|
|
14061
|
+
? '"' + bracket.slice(1, -1).replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + '"'
|
|
14062
|
+
: bracket;
|
|
14063
|
+
segments.push(String(JSON.parse(quoted)));
|
|
14064
|
+
} else {
|
|
14065
|
+
segments.push(bracket);
|
|
14066
|
+
}
|
|
14067
|
+
index = closeIndex;
|
|
14068
|
+
}
|
|
14069
|
+
pushToken();
|
|
14070
|
+
return segments;
|
|
14071
|
+
}
|
|
14072
|
+
function resolveJsonProbePath(root, path) {
|
|
14073
|
+
let segments;
|
|
14074
|
+
try {
|
|
14075
|
+
segments = parseJsonProbePathSegments(path);
|
|
14076
|
+
} catch (error) {
|
|
14077
|
+
return { exists: false, error: String(error && error.message ? error.message : error) };
|
|
14078
|
+
}
|
|
14079
|
+
let current = root;
|
|
14080
|
+
for (const segment of segments) {
|
|
14081
|
+
if (typeof segment === "number") {
|
|
14082
|
+
if (!Array.isArray(current) || segment < 0 || segment >= current.length) return { exists: false };
|
|
14083
|
+
current = current[segment];
|
|
14084
|
+
continue;
|
|
14085
|
+
}
|
|
14086
|
+
if (!current || typeof current !== "object" || Array.isArray(current) || !Object.hasOwn(current, segment)) {
|
|
14087
|
+
return { exists: false };
|
|
14088
|
+
}
|
|
14089
|
+
current = current[segment];
|
|
14090
|
+
}
|
|
14091
|
+
return { exists: true, value: current };
|
|
14092
|
+
}
|
|
14093
|
+
function evaluateJsonProbeAssertion(root, assertion) {
|
|
14094
|
+
const resolved = resolveJsonProbePath(root, assertion.path);
|
|
14095
|
+
const errors = [];
|
|
14096
|
+
const result = {
|
|
14097
|
+
label: assertion.label || assertion.path,
|
|
14098
|
+
path: assertion.path,
|
|
14099
|
+
ok: true,
|
|
14100
|
+
exists: resolved.exists,
|
|
14101
|
+
observed_type: resolved.exists ? jsonProbeValueType(resolved.value) : "missing",
|
|
14102
|
+
};
|
|
14103
|
+
if (resolved.exists) result.observed = resolved.value;
|
|
14104
|
+
if (resolved.error) errors.push(resolved.error);
|
|
14105
|
+
if (Object.hasOwn(assertion, "exists")) {
|
|
14106
|
+
result.expected_exists = assertion.exists;
|
|
14107
|
+
if (resolved.exists !== assertion.exists) errors.push("expected exists=" + assertion.exists);
|
|
14108
|
+
}
|
|
14109
|
+
if (Object.hasOwn(assertion, "type")) {
|
|
14110
|
+
result.type = assertion.type;
|
|
14111
|
+
if (!resolved.exists || jsonProbeValueType(resolved.value) !== assertion.type) errors.push("expected type " + assertion.type);
|
|
14112
|
+
}
|
|
14113
|
+
if (Object.hasOwn(assertion, "equals")) {
|
|
14114
|
+
result.equals = assertion.equals;
|
|
14115
|
+
if (!resolved.exists || !jsonProbeDeepEqual(resolved.value, assertion.equals)) errors.push("expected JSON value equality");
|
|
14116
|
+
}
|
|
14117
|
+
if (Object.hasOwn(assertion, "not_equals")) {
|
|
14118
|
+
result.not_equals = assertion.not_equals;
|
|
14119
|
+
if (resolved.exists && jsonProbeDeepEqual(resolved.value, assertion.not_equals)) errors.push("expected JSON value inequality");
|
|
14120
|
+
}
|
|
14121
|
+
if (Object.hasOwn(assertion, "contains")) {
|
|
14122
|
+
result.contains = assertion.contains;
|
|
14123
|
+
if (!resolved.exists || !jsonProbeContains(resolved.value, assertion.contains)) errors.push("expected JSON value containment");
|
|
14124
|
+
}
|
|
14125
|
+
result.ok = errors.length === 0;
|
|
14126
|
+
if (errors.length) result.errors = errors;
|
|
14127
|
+
return result;
|
|
14128
|
+
}
|
|
14129
|
+
function evaluateJsonProbeAssertions(text, assertions) {
|
|
14130
|
+
const expected = Array.isArray(assertions) ? assertions.filter((assertion) => assertion && assertion.path) : [];
|
|
14131
|
+
if (!expected.length) return [];
|
|
14132
|
+
let parsed;
|
|
14133
|
+
try {
|
|
14134
|
+
parsed = JSON.parse(text);
|
|
14135
|
+
} catch (error) {
|
|
14136
|
+
const message = "response body is not valid JSON: " + String(error && error.message ? error.message : error).slice(0, 200);
|
|
14137
|
+
return expected.map((assertion) => ({
|
|
14138
|
+
label: assertion.label || assertion.path,
|
|
14139
|
+
path: assertion.path,
|
|
14140
|
+
ok: false,
|
|
14141
|
+
exists: false,
|
|
14142
|
+
observed_type: "missing",
|
|
14143
|
+
errors: [message],
|
|
14144
|
+
}));
|
|
14145
|
+
}
|
|
14146
|
+
return expected.map((assertion) => evaluateJsonProbeAssertion(parsed, assertion));
|
|
14147
|
+
}
|
|
13724
14148
|
async function collectHttpStatus(check) {
|
|
13725
14149
|
const url = httpStatusRequestUrl(check, page.url() || targetUrl);
|
|
13726
14150
|
const method = httpStatusMethod(check);
|
|
@@ -13737,6 +14161,7 @@ async function collectHttpStatus(check) {
|
|
|
13737
14161
|
const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
|
|
13738
14162
|
const bodyNotContains = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
|
|
13739
14163
|
const bodyNotPatterns = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
|
|
14164
|
+
const bodyJsonAssertions = Array.isArray(check.body_json_assertions) ? check.body_json_assertions.filter((assertion) => assertion && assertion.path) : [];
|
|
13740
14165
|
const options = {
|
|
13741
14166
|
method,
|
|
13742
14167
|
redirect: "follow",
|
|
@@ -13762,17 +14187,18 @@ async function collectHttpStatus(check) {
|
|
|
13762
14187
|
Object.assign(result, linkProbeResponseFields(response, method));
|
|
13763
14188
|
result.url = url;
|
|
13764
14189
|
result.status_text = response.statusText || "";
|
|
13765
|
-
const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0 || bodyNotContains.length > 0 || bodyNotPatterns.length > 0;
|
|
14190
|
+
const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0 || bodyNotContains.length > 0 || bodyNotPatterns.length > 0 || bodyJsonAssertions.length > 0;
|
|
13766
14191
|
if (shouldReadBody) {
|
|
13767
14192
|
try {
|
|
13768
14193
|
const buffer = await response.arrayBuffer();
|
|
13769
14194
|
result.bytes = buffer.byteLength;
|
|
13770
|
-
if (bodyContains.length || bodyNotContains.length || bodyNotPatterns.length) {
|
|
14195
|
+
if (bodyContains.length || bodyNotContains.length || bodyNotPatterns.length || bodyJsonAssertions.length) {
|
|
13771
14196
|
const text = new TextDecoder().decode(buffer);
|
|
13772
14197
|
result.body_sample = text.slice(0, 1000);
|
|
13773
14198
|
if (bodyContains.length) result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
|
|
13774
14199
|
if (bodyNotContains.length) result.body_not_contains = Object.fromEntries(bodyNotContains.map((forbidden) => [forbidden, text.includes(forbidden)]));
|
|
13775
14200
|
if (bodyNotPatterns.length) result.body_not_patterns = Object.fromEntries(bodyNotPatterns.map((pattern) => [pattern, new RegExp(pattern).test(text)]));
|
|
14201
|
+
if (bodyJsonAssertions.length) result.body_json_assertions = evaluateJsonProbeAssertions(text, bodyJsonAssertions);
|
|
13776
14202
|
}
|
|
13777
14203
|
} catch (error) {
|
|
13778
14204
|
result.error = String(error && error.message ? error.message : error).slice(0, 500);
|
|
@@ -13785,6 +14211,7 @@ async function collectHttpStatus(check) {
|
|
|
13785
14211
|
&& (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
|
|
13786
14212
|
&& (!bodyNotContains.length || bodyNotContains.every((forbidden) => result.body_not_contains && result.body_not_contains[forbidden] === false))
|
|
13787
14213
|
&& (!bodyNotPatterns.length || bodyNotPatterns.every((pattern) => result.body_not_patterns && result.body_not_patterns[pattern] === false))
|
|
14214
|
+
&& (!bodyJsonAssertions.length || (Array.isArray(result.body_json_assertions) && result.body_json_assertions.every((assertion) => assertion.ok === true)))
|
|
13788
14215
|
&& !result.error;
|
|
13789
14216
|
return result;
|
|
13790
14217
|
} catch (error) {
|
package/dist/index.d.cts
CHANGED
|
@@ -10,5 +10,5 @@ export { CreateCaptureDiagnosticInput, DEFAULT_DIAGNOSTIC_ARRAY_LIMIT, DEFAULT_D
|
|
|
10
10
|
export { BuildVisualProofSessionInput, RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION, RIDDLE_PROOF_VISUAL_SESSION_VERSION, VisualProofSessionMismatch, buildVisualProofSession, compareVisualProofSessionFingerprint, parseVisualProofSession, visualSessionFingerprint, visualSessionFingerprintBasis } from './proof-session.cjs';
|
|
11
11
|
export { AssessPlayabilityOptions, RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION, RIDDLE_PROOF_PLAYABILITY_VERSION, RiddleProofPlayabilityAssessment, RiddleProofPlayabilityEvidence, assessPlayabilityEvidence, extractPlayabilityEvidence, isRiddleProofPlayabilityMode } from './playability.cjs';
|
|
12
12
|
export { AssessBasicGameplayOptions, AttachBasicGameplayArtifactOptions, BASIC_GAMEPLAY_ACTION_TYPES, BASIC_GAMEPLAY_PROGRESS_CHECK_TYPES, BasicGameplayActionResult, BasicGameplayActionType, BasicGameplayArtifactResolution, BasicGameplayAssessmentSummary, BasicGameplayBoundsOffender, BasicGameplayCanvasState, BasicGameplayCatchRecord, BasicGameplayChangeSummary, BasicGameplayFailureCode, BasicGameplayFixReference, BasicGameplayMetric, BasicGameplayMobileEvidence, BasicGameplayProgressCheckType, BasicGameplayProgressionCheck, BasicGameplayProofArtifact, BasicGameplayResponsiveViewportEvidence, BasicGameplayRouteReference, BasicGameplaySnapshot, BasicGameplaySuiteFailure, BasicGameplayWarningCode, CreateBasicGameplayCatchSummaryInput, RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION, RiddleProofBasicGameplayAssessment, RiddleProofBasicGameplayCatchSummary, RiddleProofBasicGameplayEvidence, RiddleProofBasicGameplayRouteAssessment, RiddleProofBasicGameplayRouteEvidence, assessBasicGameplayEvidence, assessBasicGameplayProgressionCheck, assessBasicGameplayProgressionChecks, assessBasicGameplayRoute, attachBasicGameplayArtifactScreenshotHashes, augmentBasicGameplayAssessmentWithProgressionChecks, compactBasicGameplayText, createBasicGameplayCatchRecords, createBasicGameplayCatchSummary, extractBasicGameplayEvidence, resolveBasicGameplayProgressionCheckWithArtifactScreenshots, sanitizeBasicGameplayJsonString } from './basic-gameplay.cjs';
|
|
13
|
-
export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofArtifactBodyAssertionInput, RiddleProofArtifactBodyAssertionResult, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileBoundsOffender, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileHttpStatusPreflightCheckResult, RiddleProofProfileHttpStatusPreflightFetch, RiddleProofProfileHttpStatusPreflightFetchResponse, RiddleProofProfileHttpStatusPreflightOptions, RiddleProofProfileHttpStatusPreflightResult, RiddleProofProfileNetworkAbortErrorCode, RiddleProofProfileNetworkMock, RiddleProofProfileNetworkMockResponse, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRouteInventoryRoute, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, preflightRiddleProofProfileHttpStatusChecks, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.cjs';
|
|
13
|
+
export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofArtifactBodyAssertionInput, RiddleProofArtifactBodyAssertionResult, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileBoundsOffender, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileHttpStatusBodyJsonAssertion, RiddleProofProfileHttpStatusBodyJsonAssertionResult, RiddleProofProfileHttpStatusPreflightCheckResult, RiddleProofProfileHttpStatusPreflightFetch, RiddleProofProfileHttpStatusPreflightFetchResponse, RiddleProofProfileHttpStatusPreflightOptions, RiddleProofProfileHttpStatusPreflightResult, RiddleProofProfileJsonValueType, RiddleProofProfileNetworkAbortErrorCode, RiddleProofProfileNetworkMock, RiddleProofProfileNetworkMockResponse, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRouteInventoryRoute, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, preflightRiddleProofProfileHttpStatusChecks, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.cjs';
|
|
14
14
|
export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployResult, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from './riddle-client.cjs';
|