@riddledc/riddle-proof 0.7.54 → 0.7.56

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 CHANGED
@@ -174,6 +174,9 @@ riddle-proof-loop run-profile \
174
174
  Hosted profile runs emit Riddle poll progress to stderr while waiting. Use
175
175
  `--quiet` to suppress progress lines, or `--progress-every-ms` to tune the
176
176
  heartbeat cadence for long route-inventory or workflow profiles.
177
+ Strict Riddle script validation remains on by default; use `--strict=false`
178
+ only for trusted profile-generated scripts when the validator blocks a large
179
+ workflow profile.
177
180
 
178
181
  The package includes a generic starter profile at
179
182
  `examples/profiles/page-content-basic.json`; copy that shape into a repository
@@ -303,6 +306,22 @@ These checks are useful for audit/no-diff profiles where the product should
303
306
  show a fallback state and avoid rendering stale loaders, duplicate rows, or
304
307
  missing-resource iframes.
305
308
 
309
+ Use `url_search_param_equals` and `url_search_param_absent` when the final URL
310
+ is part of the contract, such as deep-link recovery that must drop a stale
311
+ local identifier while preserving shareable query state:
312
+
313
+ ```json
314
+ [
315
+ { "type": "url_search_param_absent", "param": "seq" },
316
+ { "type": "url_search_param_equals", "param": "song", "expected_value": "monkberry-moon-delight-tab" },
317
+ { "type": "url_search_param_equals", "param": "view", "expected_value": "trainer" }
318
+ ]
319
+ ```
320
+
321
+ The check uses the captured browser URL for each viewport after setup actions
322
+ and waits have completed. `search_param` and `key` are accepted as aliases for
323
+ `param`; `value` is accepted as an alias for `expected_value`.
324
+
306
325
  Use `selector_text_order` when a table, list, or card group must show visible
307
326
  items in a specific order after setup actions such as sorting or filtering:
308
327
 
@@ -12,6 +12,8 @@ var RIDDLE_PROOF_PROFILE_STATUSES = [
12
12
  ];
13
13
  var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
14
14
  "route_loaded",
15
+ "url_search_param_equals",
16
+ "url_search_param_absent",
15
17
  "selector_visible",
16
18
  "selector_absent",
17
19
  "selector_count_at_least",
@@ -488,6 +490,13 @@ function normalizeCheck(input, index) {
488
490
  if ((type === "text_visible" || type === "text_absent") && !stringValue(input.text) && !stringValue(input.pattern)) {
489
491
  throw new Error(`checks[${index}] ${type} requires text or pattern.`);
490
492
  }
493
+ if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue(input.param) && !stringValue(input.search_param) && !stringValue(input.searchParam) && !stringValue(input.key)) {
494
+ throw new Error(`checks[${index}] ${type} requires param.`);
495
+ }
496
+ const expectedValue = stringFromOwn(input, "expected_value", "expectedValue", "value");
497
+ if (type === "url_search_param_equals" && expectedValue === void 0) {
498
+ throw new Error(`checks[${index}] url_search_param_equals requires expected_value.`);
499
+ }
491
500
  if (type === "selector_count_at_least" && numberValue(input.min_count) === void 0) {
492
501
  throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
493
502
  }
@@ -508,6 +517,8 @@ function normalizeCheck(input, index) {
508
517
  type,
509
518
  label: stringValue(input.label),
510
519
  expected_path: stringValue(input.expected_path),
520
+ param: stringValue(input.param) || stringValue(input.search_param) || stringValue(input.searchParam) || stringValue(input.key),
521
+ expected_value: expectedValue,
511
522
  expected_routes: expectedRoutes,
512
523
  selector: stringValue(input.selector),
513
524
  expected_texts: expectedTexts,
@@ -760,6 +771,32 @@ function successfulRoute(route, targetUrl) {
760
771
  const matched = route.matched || routePathMatches(route.observed, route.expected_path, targetUrl);
761
772
  return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
762
773
  }
774
+ function parseEvidenceUrl(value, targetUrl) {
775
+ if (!value) return void 0;
776
+ try {
777
+ return targetUrl ? new URL(value, targetUrl) : new URL(value);
778
+ } catch {
779
+ try {
780
+ return new URL(value);
781
+ } catch {
782
+ return void 0;
783
+ }
784
+ }
785
+ }
786
+ function observedUrlForViewport(viewport, targetUrl) {
787
+ return parseEvidenceUrl(viewport.url, targetUrl) || parseEvidenceUrl(viewport.route?.observed, targetUrl) || parseEvidenceUrl(viewport.route?.requested, targetUrl) || parseEvidenceUrl(targetUrl, void 0);
788
+ }
789
+ function searchParamObservation(viewport, targetUrl, param) {
790
+ const url = observedUrlForViewport(viewport, targetUrl);
791
+ const values = url ? url.searchParams.getAll(param) : [];
792
+ return {
793
+ viewport: viewport.name,
794
+ url: url?.href || null,
795
+ value: values.length ? values[0] : null,
796
+ values,
797
+ present: values.length > 0
798
+ };
799
+ }
763
800
  function viewportsForCheck(check, viewports) {
764
801
  if (!check.viewports?.length) return viewports;
765
802
  const names = new Set(check.viewports);
@@ -797,6 +834,44 @@ function assessCheckFromEvidence(check, evidence) {
797
834
  message: failed.length ? `Route did not load as ${expectedPath} in ${failed.length} viewport(s).` : void 0
798
835
  };
799
836
  }
837
+ if (check.type === "url_search_param_equals") {
838
+ const param = check.param || "";
839
+ const expectedValue = check.expected_value ?? "";
840
+ const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
841
+ const failed = observations.filter((observation) => observation.value !== expectedValue);
842
+ return {
843
+ type: check.type,
844
+ label: checkLabel(check),
845
+ status: failed.length ? "failed" : "passed",
846
+ evidence: {
847
+ param,
848
+ expected_value: expectedValue,
849
+ observed_values: observations.map((observation) => observation.value),
850
+ observed_all_values: observations.map((observation) => observation.values),
851
+ observed_urls: observations.map((observation) => observation.url),
852
+ viewports: observations.map((observation) => toJsonValue(observation))
853
+ },
854
+ message: failed.length ? `URL search param ${param} did not equal ${JSON.stringify(expectedValue)} in ${failed.length} viewport(s).` : void 0
855
+ };
856
+ }
857
+ if (check.type === "url_search_param_absent") {
858
+ const param = check.param || "";
859
+ const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
860
+ const failed = observations.filter((observation) => observation.present);
861
+ return {
862
+ type: check.type,
863
+ label: checkLabel(check),
864
+ status: failed.length ? "failed" : "passed",
865
+ evidence: {
866
+ param,
867
+ observed_values: observations.map((observation) => observation.value),
868
+ observed_all_values: observations.map((observation) => observation.values),
869
+ observed_urls: observations.map((observation) => observation.url),
870
+ viewports: observations.map((observation) => toJsonValue(observation))
871
+ },
872
+ message: failed.length ? `URL search param ${param} was present in ${failed.length} viewport(s).` : void 0
873
+ };
874
+ }
800
875
  if (check.type === "selector_visible") {
801
876
  const key = selectorKey(check);
802
877
  const failed = viewports.filter((viewport) => (viewport.selectors?.[key]?.visible_count || 0) < 1);
@@ -1332,6 +1407,29 @@ function routePathMatches(observed, expected, targetUrl) {
1332
1407
  function routeOk(route, targetUrl) {
1333
1408
  return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path, targetUrl)) && !route.error && (route.http_status == null || route.http_status < 400));
1334
1409
  }
1410
+ function parseEvidenceUrl(value, targetUrl) {
1411
+ if (!value) return null;
1412
+ try { return targetUrl ? new URL(value, targetUrl) : new URL(value); } catch {}
1413
+ try { return new URL(value); } catch {}
1414
+ return null;
1415
+ }
1416
+ function observedUrlForViewport(viewport, targetUrl) {
1417
+ return parseEvidenceUrl(viewport && viewport.url, targetUrl)
1418
+ || parseEvidenceUrl(viewport && viewport.route && viewport.route.observed, targetUrl)
1419
+ || parseEvidenceUrl(viewport && viewport.route && viewport.route.requested, targetUrl)
1420
+ || parseEvidenceUrl(targetUrl, null);
1421
+ }
1422
+ function searchParamObservation(viewport, targetUrl, param) {
1423
+ const url = observedUrlForViewport(viewport, targetUrl);
1424
+ const values = url ? url.searchParams.getAll(param) : [];
1425
+ return {
1426
+ viewport: viewport && viewport.name,
1427
+ url: url ? url.href : null,
1428
+ value: values.length ? values[0] : null,
1429
+ values,
1430
+ present: values.length > 0,
1431
+ };
1432
+ }
1335
1433
  function textMatches(sample, check) {
1336
1434
  if (check.pattern) {
1337
1435
  try { return new RegExp(check.pattern, check.flags || "").test(sample || ""); } catch { return false; }
@@ -1636,6 +1734,46 @@ function assessProfile(profile, evidence) {
1636
1734
  });
1637
1735
  continue;
1638
1736
  }
1737
+ if (check.type === "url_search_param_equals") {
1738
+ const param = check.param || "";
1739
+ const expectedValue = check.expected_value == null ? "" : String(check.expected_value);
1740
+ const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
1741
+ const failed = observations.filter((observation) => observation.value !== expectedValue);
1742
+ checks.push({
1743
+ type: check.type,
1744
+ label: check.label || check.type,
1745
+ status: failed.length ? "failed" : "passed",
1746
+ evidence: {
1747
+ param,
1748
+ expected_value: expectedValue,
1749
+ observed_values: observations.map((observation) => observation.value),
1750
+ observed_all_values: observations.map((observation) => observation.values),
1751
+ observed_urls: observations.map((observation) => observation.url),
1752
+ viewports: observations,
1753
+ },
1754
+ message: failed.length ? "URL search param " + param + " did not equal " + JSON.stringify(expectedValue) + " in " + failed.length + " viewport(s)." : undefined,
1755
+ });
1756
+ continue;
1757
+ }
1758
+ if (check.type === "url_search_param_absent") {
1759
+ const param = check.param || "";
1760
+ const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
1761
+ const failed = observations.filter((observation) => observation.present);
1762
+ checks.push({
1763
+ type: check.type,
1764
+ label: check.label || check.type,
1765
+ status: failed.length ? "failed" : "passed",
1766
+ evidence: {
1767
+ param,
1768
+ observed_values: observations.map((observation) => observation.value),
1769
+ observed_all_values: observations.map((observation) => observation.values),
1770
+ observed_urls: observations.map((observation) => observation.url),
1771
+ viewports: observations,
1772
+ },
1773
+ message: failed.length ? "URL search param " + param + " was present in " + failed.length + " viewport(s)." : undefined,
1774
+ });
1775
+ continue;
1776
+ }
1639
1777
  if (check.type === "selector_visible") {
1640
1778
  const selector = check.selector || "";
1641
1779
  const failed = checkViewports.filter((viewport) => !viewport.selectors || !viewport.selectors[selector] || viewport.selectors[selector].visible_count < 1);
package/dist/cli.cjs CHANGED
@@ -6885,6 +6885,8 @@ var RIDDLE_PROOF_PROFILE_STATUSES = [
6885
6885
  ];
6886
6886
  var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
6887
6887
  "route_loaded",
6888
+ "url_search_param_equals",
6889
+ "url_search_param_absent",
6888
6890
  "selector_visible",
6889
6891
  "selector_absent",
6890
6892
  "selector_count_at_least",
@@ -7361,6 +7363,13 @@ function normalizeCheck(input, index) {
7361
7363
  if ((type === "text_visible" || type === "text_absent") && !stringValue2(input.text) && !stringValue2(input.pattern)) {
7362
7364
  throw new Error(`checks[${index}] ${type} requires text or pattern.`);
7363
7365
  }
7366
+ if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue2(input.param) && !stringValue2(input.search_param) && !stringValue2(input.searchParam) && !stringValue2(input.key)) {
7367
+ throw new Error(`checks[${index}] ${type} requires param.`);
7368
+ }
7369
+ const expectedValue = stringFromOwn(input, "expected_value", "expectedValue", "value");
7370
+ if (type === "url_search_param_equals" && expectedValue === void 0) {
7371
+ throw new Error(`checks[${index}] url_search_param_equals requires expected_value.`);
7372
+ }
7364
7373
  if (type === "selector_count_at_least" && numberValue(input.min_count) === void 0) {
7365
7374
  throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
7366
7375
  }
@@ -7381,6 +7390,8 @@ function normalizeCheck(input, index) {
7381
7390
  type,
7382
7391
  label: stringValue2(input.label),
7383
7392
  expected_path: stringValue2(input.expected_path),
7393
+ param: stringValue2(input.param) || stringValue2(input.search_param) || stringValue2(input.searchParam) || stringValue2(input.key),
7394
+ expected_value: expectedValue,
7384
7395
  expected_routes: expectedRoutes,
7385
7396
  selector: stringValue2(input.selector),
7386
7397
  expected_texts: expectedTexts,
@@ -7633,6 +7644,32 @@ function successfulRoute(route, targetUrl) {
7633
7644
  const matched = route.matched || routePathMatches(route.observed, route.expected_path, targetUrl);
7634
7645
  return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
7635
7646
  }
7647
+ function parseEvidenceUrl(value, targetUrl) {
7648
+ if (!value) return void 0;
7649
+ try {
7650
+ return targetUrl ? new URL(value, targetUrl) : new URL(value);
7651
+ } catch {
7652
+ try {
7653
+ return new URL(value);
7654
+ } catch {
7655
+ return void 0;
7656
+ }
7657
+ }
7658
+ }
7659
+ function observedUrlForViewport(viewport, targetUrl) {
7660
+ return parseEvidenceUrl(viewport.url, targetUrl) || parseEvidenceUrl(viewport.route?.observed, targetUrl) || parseEvidenceUrl(viewport.route?.requested, targetUrl) || parseEvidenceUrl(targetUrl, void 0);
7661
+ }
7662
+ function searchParamObservation(viewport, targetUrl, param) {
7663
+ const url = observedUrlForViewport(viewport, targetUrl);
7664
+ const values = url ? url.searchParams.getAll(param) : [];
7665
+ return {
7666
+ viewport: viewport.name,
7667
+ url: url?.href || null,
7668
+ value: values.length ? values[0] : null,
7669
+ values,
7670
+ present: values.length > 0
7671
+ };
7672
+ }
7636
7673
  function viewportsForCheck(check, viewports) {
7637
7674
  if (!check.viewports?.length) return viewports;
7638
7675
  const names = new Set(check.viewports);
@@ -7670,6 +7707,44 @@ function assessCheckFromEvidence(check, evidence) {
7670
7707
  message: failed.length ? `Route did not load as ${expectedPath} in ${failed.length} viewport(s).` : void 0
7671
7708
  };
7672
7709
  }
7710
+ if (check.type === "url_search_param_equals") {
7711
+ const param = check.param || "";
7712
+ const expectedValue = check.expected_value ?? "";
7713
+ const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
7714
+ const failed = observations.filter((observation) => observation.value !== expectedValue);
7715
+ return {
7716
+ type: check.type,
7717
+ label: checkLabel(check),
7718
+ status: failed.length ? "failed" : "passed",
7719
+ evidence: {
7720
+ param,
7721
+ expected_value: expectedValue,
7722
+ observed_values: observations.map((observation) => observation.value),
7723
+ observed_all_values: observations.map((observation) => observation.values),
7724
+ observed_urls: observations.map((observation) => observation.url),
7725
+ viewports: observations.map((observation) => toJsonValue(observation))
7726
+ },
7727
+ message: failed.length ? `URL search param ${param} did not equal ${JSON.stringify(expectedValue)} in ${failed.length} viewport(s).` : void 0
7728
+ };
7729
+ }
7730
+ if (check.type === "url_search_param_absent") {
7731
+ const param = check.param || "";
7732
+ const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
7733
+ const failed = observations.filter((observation) => observation.present);
7734
+ return {
7735
+ type: check.type,
7736
+ label: checkLabel(check),
7737
+ status: failed.length ? "failed" : "passed",
7738
+ evidence: {
7739
+ param,
7740
+ observed_values: observations.map((observation) => observation.value),
7741
+ observed_all_values: observations.map((observation) => observation.values),
7742
+ observed_urls: observations.map((observation) => observation.url),
7743
+ viewports: observations.map((observation) => toJsonValue(observation))
7744
+ },
7745
+ message: failed.length ? `URL search param ${param} was present in ${failed.length} viewport(s).` : void 0
7746
+ };
7747
+ }
7673
7748
  if (check.type === "selector_visible") {
7674
7749
  const key = selectorKey(check);
7675
7750
  const failed = viewports.filter((viewport) => (viewport.selectors?.[key]?.visible_count || 0) < 1);
@@ -8189,6 +8264,29 @@ function routePathMatches(observed, expected, targetUrl) {
8189
8264
  function routeOk(route, targetUrl) {
8190
8265
  return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path, targetUrl)) && !route.error && (route.http_status == null || route.http_status < 400));
8191
8266
  }
8267
+ function parseEvidenceUrl(value, targetUrl) {
8268
+ if (!value) return null;
8269
+ try { return targetUrl ? new URL(value, targetUrl) : new URL(value); } catch {}
8270
+ try { return new URL(value); } catch {}
8271
+ return null;
8272
+ }
8273
+ function observedUrlForViewport(viewport, targetUrl) {
8274
+ return parseEvidenceUrl(viewport && viewport.url, targetUrl)
8275
+ || parseEvidenceUrl(viewport && viewport.route && viewport.route.observed, targetUrl)
8276
+ || parseEvidenceUrl(viewport && viewport.route && viewport.route.requested, targetUrl)
8277
+ || parseEvidenceUrl(targetUrl, null);
8278
+ }
8279
+ function searchParamObservation(viewport, targetUrl, param) {
8280
+ const url = observedUrlForViewport(viewport, targetUrl);
8281
+ const values = url ? url.searchParams.getAll(param) : [];
8282
+ return {
8283
+ viewport: viewport && viewport.name,
8284
+ url: url ? url.href : null,
8285
+ value: values.length ? values[0] : null,
8286
+ values,
8287
+ present: values.length > 0,
8288
+ };
8289
+ }
8192
8290
  function textMatches(sample, check) {
8193
8291
  if (check.pattern) {
8194
8292
  try { return new RegExp(check.pattern, check.flags || "").test(sample || ""); } catch { return false; }
@@ -8493,6 +8591,46 @@ function assessProfile(profile, evidence) {
8493
8591
  });
8494
8592
  continue;
8495
8593
  }
8594
+ if (check.type === "url_search_param_equals") {
8595
+ const param = check.param || "";
8596
+ const expectedValue = check.expected_value == null ? "" : String(check.expected_value);
8597
+ const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
8598
+ const failed = observations.filter((observation) => observation.value !== expectedValue);
8599
+ checks.push({
8600
+ type: check.type,
8601
+ label: check.label || check.type,
8602
+ status: failed.length ? "failed" : "passed",
8603
+ evidence: {
8604
+ param,
8605
+ expected_value: expectedValue,
8606
+ observed_values: observations.map((observation) => observation.value),
8607
+ observed_all_values: observations.map((observation) => observation.values),
8608
+ observed_urls: observations.map((observation) => observation.url),
8609
+ viewports: observations,
8610
+ },
8611
+ message: failed.length ? "URL search param " + param + " did not equal " + JSON.stringify(expectedValue) + " in " + failed.length + " viewport(s)." : undefined,
8612
+ });
8613
+ continue;
8614
+ }
8615
+ if (check.type === "url_search_param_absent") {
8616
+ const param = check.param || "";
8617
+ const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
8618
+ const failed = observations.filter((observation) => observation.present);
8619
+ checks.push({
8620
+ type: check.type,
8621
+ label: check.label || check.type,
8622
+ status: failed.length ? "failed" : "passed",
8623
+ evidence: {
8624
+ param,
8625
+ observed_values: observations.map((observation) => observation.value),
8626
+ observed_all_values: observations.map((observation) => observation.values),
8627
+ observed_urls: observations.map((observation) => observation.url),
8628
+ viewports: observations,
8629
+ },
8630
+ message: failed.length ? "URL search param " + param + " was present in " + failed.length + " viewport(s)." : undefined,
8631
+ });
8632
+ continue;
8633
+ }
8496
8634
  if (check.type === "selector_visible") {
8497
8635
  const selector = check.selector || "";
8498
8636
  const failed = checkViewports.filter((viewport) => !viewport.selectors || !viewport.selectors[selector] || viewport.selectors[selector].visible_count < 1);
@@ -10138,7 +10276,7 @@ function usage() {
10138
10276
  " riddle-proof-loop respond --state-path <path> --response-json <file|json|->",
10139
10277
  " riddle-proof-loop respond --state-path <path> --decision <decision> --summary <text> [--payload-json <file|json|->]",
10140
10278
  " riddle-proof-loop status --state-path <path>",
10141
- " riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--output <dir>] [--quiet]",
10279
+ " riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--strict true|false] [--output <dir>] [--quiet]",
10142
10280
  " riddle-proof-loop riddle-preview-deploy <build-dir> <label>",
10143
10281
  " riddle-proof-loop riddle-server-preview <directory> --script-file <file> [--path /route] [--wait-for-selector selector]",
10144
10282
  " riddle-proof-loop riddle-run-script --url <url> --script-file <file> [--viewport 1280x720] [--strict true|false]",
@@ -10496,6 +10634,7 @@ async function runProfileForCli(profile, options) {
10496
10634
  profile,
10497
10635
  optionString(options, "timeout") ? Number(optionString(options, "timeout")) : void 0
10498
10636
  ),
10637
+ strict: optionBoolean(options, "strict"),
10499
10638
  sync: options.sync === true ? true : void 0
10500
10639
  });
10501
10640
  } catch (error) {
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl,
12
12
  resolveRiddleProofProfileTimeoutSec
13
- } from "./chunk-H3DOYKAQ.js";
13
+ } from "./chunk-2JFDTCIC.js";
14
14
  import {
15
15
  createRiddleApiClient,
16
16
  parseRiddleViewport
@@ -44,7 +44,7 @@ function usage() {
44
44
  " riddle-proof-loop respond --state-path <path> --response-json <file|json|->",
45
45
  " riddle-proof-loop respond --state-path <path> --decision <decision> --summary <text> [--payload-json <file|json|->]",
46
46
  " riddle-proof-loop status --state-path <path>",
47
- " riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--output <dir>] [--quiet]",
47
+ " riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--strict true|false] [--output <dir>] [--quiet]",
48
48
  " riddle-proof-loop riddle-preview-deploy <build-dir> <label>",
49
49
  " riddle-proof-loop riddle-server-preview <directory> --script-file <file> [--path /route] [--wait-for-selector selector]",
50
50
  " riddle-proof-loop riddle-run-script --url <url> --script-file <file> [--viewport 1280x720] [--strict true|false]",
@@ -402,6 +402,7 @@ async function runProfileForCli(profile, options) {
402
402
  profile,
403
403
  optionString(options, "timeout") ? Number(optionString(options, "timeout")) : void 0
404
404
  ),
405
+ strict: optionBoolean(options, "strict"),
405
406
  sync: options.sync === true ? true : void 0
406
407
  });
407
408
  } catch (error) {
package/dist/index.cjs CHANGED
@@ -8726,6 +8726,8 @@ var RIDDLE_PROOF_PROFILE_STATUSES = [
8726
8726
  ];
8727
8727
  var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
8728
8728
  "route_loaded",
8729
+ "url_search_param_equals",
8730
+ "url_search_param_absent",
8729
8731
  "selector_visible",
8730
8732
  "selector_absent",
8731
8733
  "selector_count_at_least",
@@ -9202,6 +9204,13 @@ function normalizeCheck(input, index) {
9202
9204
  if ((type === "text_visible" || type === "text_absent") && !stringValue5(input.text) && !stringValue5(input.pattern)) {
9203
9205
  throw new Error(`checks[${index}] ${type} requires text or pattern.`);
9204
9206
  }
9207
+ if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue5(input.param) && !stringValue5(input.search_param) && !stringValue5(input.searchParam) && !stringValue5(input.key)) {
9208
+ throw new Error(`checks[${index}] ${type} requires param.`);
9209
+ }
9210
+ const expectedValue = stringFromOwn(input, "expected_value", "expectedValue", "value");
9211
+ if (type === "url_search_param_equals" && expectedValue === void 0) {
9212
+ throw new Error(`checks[${index}] url_search_param_equals requires expected_value.`);
9213
+ }
9205
9214
  if (type === "selector_count_at_least" && numberValue3(input.min_count) === void 0) {
9206
9215
  throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
9207
9216
  }
@@ -9222,6 +9231,8 @@ function normalizeCheck(input, index) {
9222
9231
  type,
9223
9232
  label: stringValue5(input.label),
9224
9233
  expected_path: stringValue5(input.expected_path),
9234
+ param: stringValue5(input.param) || stringValue5(input.search_param) || stringValue5(input.searchParam) || stringValue5(input.key),
9235
+ expected_value: expectedValue,
9225
9236
  expected_routes: expectedRoutes,
9226
9237
  selector: stringValue5(input.selector),
9227
9238
  expected_texts: expectedTexts,
@@ -9474,6 +9485,32 @@ function successfulRoute(route, targetUrl) {
9474
9485
  const matched = route.matched || routePathMatches(route.observed, route.expected_path, targetUrl);
9475
9486
  return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
9476
9487
  }
9488
+ function parseEvidenceUrl(value, targetUrl) {
9489
+ if (!value) return void 0;
9490
+ try {
9491
+ return targetUrl ? new URL(value, targetUrl) : new URL(value);
9492
+ } catch {
9493
+ try {
9494
+ return new URL(value);
9495
+ } catch {
9496
+ return void 0;
9497
+ }
9498
+ }
9499
+ }
9500
+ function observedUrlForViewport(viewport, targetUrl) {
9501
+ return parseEvidenceUrl(viewport.url, targetUrl) || parseEvidenceUrl(viewport.route?.observed, targetUrl) || parseEvidenceUrl(viewport.route?.requested, targetUrl) || parseEvidenceUrl(targetUrl, void 0);
9502
+ }
9503
+ function searchParamObservation(viewport, targetUrl, param) {
9504
+ const url = observedUrlForViewport(viewport, targetUrl);
9505
+ const values = url ? url.searchParams.getAll(param) : [];
9506
+ return {
9507
+ viewport: viewport.name,
9508
+ url: url?.href || null,
9509
+ value: values.length ? values[0] : null,
9510
+ values,
9511
+ present: values.length > 0
9512
+ };
9513
+ }
9477
9514
  function viewportsForCheck(check, viewports) {
9478
9515
  if (!check.viewports?.length) return viewports;
9479
9516
  const names = new Set(check.viewports);
@@ -9511,6 +9548,44 @@ function assessCheckFromEvidence(check, evidence) {
9511
9548
  message: failed.length ? `Route did not load as ${expectedPath} in ${failed.length} viewport(s).` : void 0
9512
9549
  };
9513
9550
  }
9551
+ if (check.type === "url_search_param_equals") {
9552
+ const param = check.param || "";
9553
+ const expectedValue = check.expected_value ?? "";
9554
+ const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
9555
+ const failed = observations.filter((observation) => observation.value !== expectedValue);
9556
+ return {
9557
+ type: check.type,
9558
+ label: checkLabel(check),
9559
+ status: failed.length ? "failed" : "passed",
9560
+ evidence: {
9561
+ param,
9562
+ expected_value: expectedValue,
9563
+ observed_values: observations.map((observation) => observation.value),
9564
+ observed_all_values: observations.map((observation) => observation.values),
9565
+ observed_urls: observations.map((observation) => observation.url),
9566
+ viewports: observations.map((observation) => toJsonValue(observation))
9567
+ },
9568
+ message: failed.length ? `URL search param ${param} did not equal ${JSON.stringify(expectedValue)} in ${failed.length} viewport(s).` : void 0
9569
+ };
9570
+ }
9571
+ if (check.type === "url_search_param_absent") {
9572
+ const param = check.param || "";
9573
+ const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
9574
+ const failed = observations.filter((observation) => observation.present);
9575
+ return {
9576
+ type: check.type,
9577
+ label: checkLabel(check),
9578
+ status: failed.length ? "failed" : "passed",
9579
+ evidence: {
9580
+ param,
9581
+ observed_values: observations.map((observation) => observation.value),
9582
+ observed_all_values: observations.map((observation) => observation.values),
9583
+ observed_urls: observations.map((observation) => observation.url),
9584
+ viewports: observations.map((observation) => toJsonValue(observation))
9585
+ },
9586
+ message: failed.length ? `URL search param ${param} was present in ${failed.length} viewport(s).` : void 0
9587
+ };
9588
+ }
9514
9589
  if (check.type === "selector_visible") {
9515
9590
  const key = selectorKey(check);
9516
9591
  const failed = viewports.filter((viewport) => (viewport.selectors?.[key]?.visible_count || 0) < 1);
@@ -10046,6 +10121,29 @@ function routePathMatches(observed, expected, targetUrl) {
10046
10121
  function routeOk(route, targetUrl) {
10047
10122
  return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path, targetUrl)) && !route.error && (route.http_status == null || route.http_status < 400));
10048
10123
  }
10124
+ function parseEvidenceUrl(value, targetUrl) {
10125
+ if (!value) return null;
10126
+ try { return targetUrl ? new URL(value, targetUrl) : new URL(value); } catch {}
10127
+ try { return new URL(value); } catch {}
10128
+ return null;
10129
+ }
10130
+ function observedUrlForViewport(viewport, targetUrl) {
10131
+ return parseEvidenceUrl(viewport && viewport.url, targetUrl)
10132
+ || parseEvidenceUrl(viewport && viewport.route && viewport.route.observed, targetUrl)
10133
+ || parseEvidenceUrl(viewport && viewport.route && viewport.route.requested, targetUrl)
10134
+ || parseEvidenceUrl(targetUrl, null);
10135
+ }
10136
+ function searchParamObservation(viewport, targetUrl, param) {
10137
+ const url = observedUrlForViewport(viewport, targetUrl);
10138
+ const values = url ? url.searchParams.getAll(param) : [];
10139
+ return {
10140
+ viewport: viewport && viewport.name,
10141
+ url: url ? url.href : null,
10142
+ value: values.length ? values[0] : null,
10143
+ values,
10144
+ present: values.length > 0,
10145
+ };
10146
+ }
10049
10147
  function textMatches(sample, check) {
10050
10148
  if (check.pattern) {
10051
10149
  try { return new RegExp(check.pattern, check.flags || "").test(sample || ""); } catch { return false; }
@@ -10350,6 +10448,46 @@ function assessProfile(profile, evidence) {
10350
10448
  });
10351
10449
  continue;
10352
10450
  }
10451
+ if (check.type === "url_search_param_equals") {
10452
+ const param = check.param || "";
10453
+ const expectedValue = check.expected_value == null ? "" : String(check.expected_value);
10454
+ const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
10455
+ const failed = observations.filter((observation) => observation.value !== expectedValue);
10456
+ checks.push({
10457
+ type: check.type,
10458
+ label: check.label || check.type,
10459
+ status: failed.length ? "failed" : "passed",
10460
+ evidence: {
10461
+ param,
10462
+ expected_value: expectedValue,
10463
+ observed_values: observations.map((observation) => observation.value),
10464
+ observed_all_values: observations.map((observation) => observation.values),
10465
+ observed_urls: observations.map((observation) => observation.url),
10466
+ viewports: observations,
10467
+ },
10468
+ message: failed.length ? "URL search param " + param + " did not equal " + JSON.stringify(expectedValue) + " in " + failed.length + " viewport(s)." : undefined,
10469
+ });
10470
+ continue;
10471
+ }
10472
+ if (check.type === "url_search_param_absent") {
10473
+ const param = check.param || "";
10474
+ const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
10475
+ const failed = observations.filter((observation) => observation.present);
10476
+ checks.push({
10477
+ type: check.type,
10478
+ label: check.label || check.type,
10479
+ status: failed.length ? "failed" : "passed",
10480
+ evidence: {
10481
+ param,
10482
+ observed_values: observations.map((observation) => observation.value),
10483
+ observed_all_values: observations.map((observation) => observation.values),
10484
+ observed_urls: observations.map((observation) => observation.url),
10485
+ viewports: observations,
10486
+ },
10487
+ message: failed.length ? "URL search param " + param + " was present in " + failed.length + " viewport(s)." : undefined,
10488
+ });
10489
+ continue;
10490
+ }
10353
10491
  if (check.type === "selector_visible") {
10354
10492
  const selector = check.selector || "";
10355
10493
  const failed = checkViewports.filter((viewport) => !viewport.selectors || !viewport.selectors[selector] || viewport.selectors[selector].visible_count < 1);
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-H3DOYKAQ.js";
61
+ } from "./chunk-2JFDTCIC.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -55,6 +55,8 @@ var RIDDLE_PROOF_PROFILE_STATUSES = [
55
55
  ];
56
56
  var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
57
57
  "route_loaded",
58
+ "url_search_param_equals",
59
+ "url_search_param_absent",
58
60
  "selector_visible",
59
61
  "selector_absent",
60
62
  "selector_count_at_least",
@@ -531,6 +533,13 @@ function normalizeCheck(input, index) {
531
533
  if ((type === "text_visible" || type === "text_absent") && !stringValue(input.text) && !stringValue(input.pattern)) {
532
534
  throw new Error(`checks[${index}] ${type} requires text or pattern.`);
533
535
  }
536
+ if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue(input.param) && !stringValue(input.search_param) && !stringValue(input.searchParam) && !stringValue(input.key)) {
537
+ throw new Error(`checks[${index}] ${type} requires param.`);
538
+ }
539
+ const expectedValue = stringFromOwn(input, "expected_value", "expectedValue", "value");
540
+ if (type === "url_search_param_equals" && expectedValue === void 0) {
541
+ throw new Error(`checks[${index}] url_search_param_equals requires expected_value.`);
542
+ }
534
543
  if (type === "selector_count_at_least" && numberValue(input.min_count) === void 0) {
535
544
  throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
536
545
  }
@@ -551,6 +560,8 @@ function normalizeCheck(input, index) {
551
560
  type,
552
561
  label: stringValue(input.label),
553
562
  expected_path: stringValue(input.expected_path),
563
+ param: stringValue(input.param) || stringValue(input.search_param) || stringValue(input.searchParam) || stringValue(input.key),
564
+ expected_value: expectedValue,
554
565
  expected_routes: expectedRoutes,
555
566
  selector: stringValue(input.selector),
556
567
  expected_texts: expectedTexts,
@@ -803,6 +814,32 @@ function successfulRoute(route, targetUrl) {
803
814
  const matched = route.matched || routePathMatches(route.observed, route.expected_path, targetUrl);
804
815
  return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
805
816
  }
817
+ function parseEvidenceUrl(value, targetUrl) {
818
+ if (!value) return void 0;
819
+ try {
820
+ return targetUrl ? new URL(value, targetUrl) : new URL(value);
821
+ } catch {
822
+ try {
823
+ return new URL(value);
824
+ } catch {
825
+ return void 0;
826
+ }
827
+ }
828
+ }
829
+ function observedUrlForViewport(viewport, targetUrl) {
830
+ return parseEvidenceUrl(viewport.url, targetUrl) || parseEvidenceUrl(viewport.route?.observed, targetUrl) || parseEvidenceUrl(viewport.route?.requested, targetUrl) || parseEvidenceUrl(targetUrl, void 0);
831
+ }
832
+ function searchParamObservation(viewport, targetUrl, param) {
833
+ const url = observedUrlForViewport(viewport, targetUrl);
834
+ const values = url ? url.searchParams.getAll(param) : [];
835
+ return {
836
+ viewport: viewport.name,
837
+ url: url?.href || null,
838
+ value: values.length ? values[0] : null,
839
+ values,
840
+ present: values.length > 0
841
+ };
842
+ }
806
843
  function viewportsForCheck(check, viewports) {
807
844
  if (!check.viewports?.length) return viewports;
808
845
  const names = new Set(check.viewports);
@@ -840,6 +877,44 @@ function assessCheckFromEvidence(check, evidence) {
840
877
  message: failed.length ? `Route did not load as ${expectedPath} in ${failed.length} viewport(s).` : void 0
841
878
  };
842
879
  }
880
+ if (check.type === "url_search_param_equals") {
881
+ const param = check.param || "";
882
+ const expectedValue = check.expected_value ?? "";
883
+ const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
884
+ const failed = observations.filter((observation) => observation.value !== expectedValue);
885
+ return {
886
+ type: check.type,
887
+ label: checkLabel(check),
888
+ status: failed.length ? "failed" : "passed",
889
+ evidence: {
890
+ param,
891
+ expected_value: expectedValue,
892
+ observed_values: observations.map((observation) => observation.value),
893
+ observed_all_values: observations.map((observation) => observation.values),
894
+ observed_urls: observations.map((observation) => observation.url),
895
+ viewports: observations.map((observation) => toJsonValue(observation))
896
+ },
897
+ message: failed.length ? `URL search param ${param} did not equal ${JSON.stringify(expectedValue)} in ${failed.length} viewport(s).` : void 0
898
+ };
899
+ }
900
+ if (check.type === "url_search_param_absent") {
901
+ const param = check.param || "";
902
+ const observations = viewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
903
+ const failed = observations.filter((observation) => observation.present);
904
+ return {
905
+ type: check.type,
906
+ label: checkLabel(check),
907
+ status: failed.length ? "failed" : "passed",
908
+ evidence: {
909
+ param,
910
+ observed_values: observations.map((observation) => observation.value),
911
+ observed_all_values: observations.map((observation) => observation.values),
912
+ observed_urls: observations.map((observation) => observation.url),
913
+ viewports: observations.map((observation) => toJsonValue(observation))
914
+ },
915
+ message: failed.length ? `URL search param ${param} was present in ${failed.length} viewport(s).` : void 0
916
+ };
917
+ }
843
918
  if (check.type === "selector_visible") {
844
919
  const key = selectorKey(check);
845
920
  const failed = viewports.filter((viewport) => (viewport.selectors?.[key]?.visible_count || 0) < 1);
@@ -1375,6 +1450,29 @@ function routePathMatches(observed, expected, targetUrl) {
1375
1450
  function routeOk(route, targetUrl) {
1376
1451
  return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path, targetUrl)) && !route.error && (route.http_status == null || route.http_status < 400));
1377
1452
  }
1453
+ function parseEvidenceUrl(value, targetUrl) {
1454
+ if (!value) return null;
1455
+ try { return targetUrl ? new URL(value, targetUrl) : new URL(value); } catch {}
1456
+ try { return new URL(value); } catch {}
1457
+ return null;
1458
+ }
1459
+ function observedUrlForViewport(viewport, targetUrl) {
1460
+ return parseEvidenceUrl(viewport && viewport.url, targetUrl)
1461
+ || parseEvidenceUrl(viewport && viewport.route && viewport.route.observed, targetUrl)
1462
+ || parseEvidenceUrl(viewport && viewport.route && viewport.route.requested, targetUrl)
1463
+ || parseEvidenceUrl(targetUrl, null);
1464
+ }
1465
+ function searchParamObservation(viewport, targetUrl, param) {
1466
+ const url = observedUrlForViewport(viewport, targetUrl);
1467
+ const values = url ? url.searchParams.getAll(param) : [];
1468
+ return {
1469
+ viewport: viewport && viewport.name,
1470
+ url: url ? url.href : null,
1471
+ value: values.length ? values[0] : null,
1472
+ values,
1473
+ present: values.length > 0,
1474
+ };
1475
+ }
1378
1476
  function textMatches(sample, check) {
1379
1477
  if (check.pattern) {
1380
1478
  try { return new RegExp(check.pattern, check.flags || "").test(sample || ""); } catch { return false; }
@@ -1679,6 +1777,46 @@ function assessProfile(profile, evidence) {
1679
1777
  });
1680
1778
  continue;
1681
1779
  }
1780
+ if (check.type === "url_search_param_equals") {
1781
+ const param = check.param || "";
1782
+ const expectedValue = check.expected_value == null ? "" : String(check.expected_value);
1783
+ const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
1784
+ const failed = observations.filter((observation) => observation.value !== expectedValue);
1785
+ checks.push({
1786
+ type: check.type,
1787
+ label: check.label || check.type,
1788
+ status: failed.length ? "failed" : "passed",
1789
+ evidence: {
1790
+ param,
1791
+ expected_value: expectedValue,
1792
+ observed_values: observations.map((observation) => observation.value),
1793
+ observed_all_values: observations.map((observation) => observation.values),
1794
+ observed_urls: observations.map((observation) => observation.url),
1795
+ viewports: observations,
1796
+ },
1797
+ message: failed.length ? "URL search param " + param + " did not equal " + JSON.stringify(expectedValue) + " in " + failed.length + " viewport(s)." : undefined,
1798
+ });
1799
+ continue;
1800
+ }
1801
+ if (check.type === "url_search_param_absent") {
1802
+ const param = check.param || "";
1803
+ const observations = checkViewports.map((viewport) => searchParamObservation(viewport, evidence.target_url, param));
1804
+ const failed = observations.filter((observation) => observation.present);
1805
+ checks.push({
1806
+ type: check.type,
1807
+ label: check.label || check.type,
1808
+ status: failed.length ? "failed" : "passed",
1809
+ evidence: {
1810
+ param,
1811
+ observed_values: observations.map((observation) => observation.value),
1812
+ observed_all_values: observations.map((observation) => observation.values),
1813
+ observed_urls: observations.map((observation) => observation.url),
1814
+ viewports: observations,
1815
+ },
1816
+ message: failed.length ? "URL search param " + param + " was present in " + failed.length + " viewport(s)." : undefined,
1817
+ });
1818
+ continue;
1819
+ }
1682
1820
  if (check.type === "selector_visible") {
1683
1821
  const selector = check.selector || "";
1684
1822
  const failed = checkViewports.filter((viewport) => !viewport.selectors || !viewport.selectors[selector] || viewport.selectors[selector].visible_count < 1);
@@ -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", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_order", "frame_text_visible", "frame_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
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_order", "frame_text_visible", "frame_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
8
8
  declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "local_storage", "session_storage", "clear_storage", "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];
@@ -88,6 +88,8 @@ interface RiddleProofProfileCheck {
88
88
  type: RiddleProofProfileCheckType;
89
89
  label?: string;
90
90
  expected_path?: string;
91
+ param?: string;
92
+ expected_value?: string;
91
93
  expected_routes?: RiddleProofProfileRouteInventoryRoute[];
92
94
  selector?: string;
93
95
  expected_texts?: string[];
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", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_order", "frame_text_visible", "frame_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
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_order", "frame_text_visible", "frame_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
8
8
  declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "local_storage", "session_storage", "clear_storage", "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];
@@ -88,6 +88,8 @@ interface RiddleProofProfileCheck {
88
88
  type: RiddleProofProfileCheckType;
89
89
  label?: string;
90
90
  expected_path?: string;
91
+ param?: string;
92
+ expected_value?: string;
91
93
  expected_routes?: RiddleProofProfileRouteInventoryRoute[];
92
94
  selector?: string;
93
95
  expected_texts?: string[];
package/dist/profile.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  resolveRiddleProofProfileTimeoutSec,
20
20
  slugifyRiddleProofProfileName,
21
21
  summarizeRiddleProofProfileResult
22
- } from "./chunk-H3DOYKAQ.js";
22
+ } from "./chunk-2JFDTCIC.js";
23
23
  export {
24
24
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
25
25
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.54",
3
+ "version": "0.7.56",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",