@riddledc/riddle-proof 0.7.38 → 0.7.39

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
@@ -202,6 +202,25 @@ clears `local`, `session`, or `both` browser storage scopes, defaults to
202
202
  profile carries its own hosted Riddle worker budget; an explicit CLI `--timeout`
203
203
  still overrides the profile value for one-off runs.
204
204
 
205
+ Use `allowed_console_patterns` / `allowed_console_texts` on
206
+ `no_fatal_console_errors` when a negative-path profile intentionally triggers a
207
+ known browser console error, such as a mocked `503` that the app recovers from:
208
+
209
+ ```json
210
+ {
211
+ "type": "no_fatal_console_errors",
212
+ "allowed_console_patterns": [
213
+ "Failed to load resource: the server responded with a status of 503",
214
+ "Build failed: Error: Synthetic build outage"
215
+ ]
216
+ }
217
+ ```
218
+
219
+ Allowed console events and page errors are still counted in check evidence, but
220
+ only unallowed `error` / `assert` console events and page errors fail the check.
221
+ Use `allowed_page_error_patterns`, `allowed_console_texts`, or
222
+ `allowed_page_error_texts` for narrower matching when needed.
223
+
205
224
  Use `selector_text_order` when a table, list, or card group must show visible
206
225
  items in a specific order after setup actions such as sorting or filtering:
207
226
 
@@ -305,6 +305,13 @@ function normalizeExpectedTexts(value, index) {
305
305
  if (!texts.length) throw new Error(`checks[${index}] selector_text_order expected_texts must contain non-empty strings.`);
306
306
  return texts;
307
307
  }
308
+ function normalizeStringList(value, label) {
309
+ if (value === void 0) return void 0;
310
+ if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
311
+ const values = value.map((item) => String(item).replace(/\s+/g, " ").trim()).filter(Boolean);
312
+ if (!values.length) throw new Error(`${label} must contain non-empty strings.`);
313
+ return values;
314
+ }
308
315
  function normalizeCheck(input, index) {
309
316
  if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
310
317
  const type = stringValue(input.type);
@@ -353,6 +360,10 @@ function normalizeCheck(input, index) {
353
360
  text: stringValue(input.text),
354
361
  pattern: stringValue(input.pattern),
355
362
  flags: stringValue(input.flags),
363
+ allowed_console_texts: normalizeStringList(input.allowed_console_texts ?? input.allowedConsoleTexts ?? input.allow_console_texts ?? input.allowConsoleTexts, `checks[${index}] allowed_console_texts`),
364
+ allowed_console_patterns: normalizeStringList(input.allowed_console_patterns ?? input.allowedConsolePatterns ?? input.allow_console_patterns ?? input.allowConsolePatterns, `checks[${index}] allowed_console_patterns`),
365
+ allowed_page_error_texts: normalizeStringList(input.allowed_page_error_texts ?? input.allowedPageErrorTexts ?? input.allow_page_error_texts ?? input.allowPageErrorTexts, `checks[${index}] allowed_page_error_texts`),
366
+ allowed_page_error_patterns: normalizeStringList(input.allowed_page_error_patterns ?? input.allowedPageErrorPatterns ?? input.allow_page_error_patterns ?? input.allowPageErrorPatterns, `checks[${index}] allowed_page_error_patterns`),
356
367
  min_count: numberValue(input.min_count),
357
368
  max_overflow_px: numberValue(input.max_overflow_px),
358
369
  timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
@@ -516,6 +527,18 @@ function matchText(sample, check) {
516
527
  }
517
528
  return sample.includes(check.text || "");
518
529
  }
530
+ function matchesAllowedMessage(message, texts, patterns) {
531
+ const sample = String(message || "");
532
+ if (texts?.some((text) => sample.includes(text))) return true;
533
+ for (const pattern of patterns || []) {
534
+ try {
535
+ if (new RegExp(pattern).test(sample)) return true;
536
+ } catch {
537
+ continue;
538
+ }
539
+ }
540
+ return false;
541
+ }
519
542
  function normalizeRoutePath(path) {
520
543
  const value = path || "/";
521
544
  if (value === "/") return "/";
@@ -802,14 +825,28 @@ function assessCheckFromEvidence(check, evidence) {
802
825
  };
803
826
  }
804
827
  if (check.type === "no_fatal_console_errors") {
805
- const fatalCount = (evidence.console?.fatal_count || 0) + (evidence.page_errors?.length || 0);
828
+ const fatalConsoleEvents = (evidence.console?.events || []).filter((event) => event.type === "error" || event.type === "assert");
829
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
830
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
831
+ const pageErrors = evidence.page_errors || [];
832
+ const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
833
+ const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
834
+ const fatalCount = unallowedConsoleEvents.length + unallowedPageErrors.length;
806
835
  return {
807
836
  type: check.type,
808
837
  label: checkLabel(check),
809
838
  status: fatalCount ? "failed" : "passed",
810
839
  evidence: {
811
- console_fatal_count: evidence.console?.fatal_count || 0,
812
- page_error_count: evidence.page_errors?.length || 0
840
+ console_fatal_count: unallowedConsoleEvents.length,
841
+ page_error_count: unallowedPageErrors.length,
842
+ total_console_fatal_count: fatalConsoleEvents.length,
843
+ total_page_error_count: pageErrors.length,
844
+ allowed_console_fatal_count: allowedConsoleEvents.length,
845
+ allowed_page_error_count: allowedPageErrors.length,
846
+ allowed_console_texts: check.allowed_console_texts || [],
847
+ allowed_console_patterns: check.allowed_console_patterns || [],
848
+ allowed_page_error_texts: check.allowed_page_error_texts || [],
849
+ allowed_page_error_patterns: check.allowed_page_error_patterns || []
813
850
  },
814
851
  message: fatalCount ? `${fatalCount} fatal browser error(s) were captured.` : void 0
815
852
  };
@@ -1065,6 +1102,16 @@ function textMatches(sample, check) {
1065
1102
  }
1066
1103
  return String(sample || "").includes(check.text || "");
1067
1104
  }
1105
+ function matchesAllowedMessage(message, texts, patterns) {
1106
+ const sample = String(message || "");
1107
+ if ((texts || []).some((text) => sample.includes(text))) return true;
1108
+ for (const pattern of patterns || []) {
1109
+ try {
1110
+ if (new RegExp(pattern).test(sample)) return true;
1111
+ } catch {}
1112
+ }
1113
+ return false;
1114
+ }
1068
1115
  function textSequenceForCheck(viewport, check) {
1069
1116
  const key = check.selector || "";
1070
1117
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
@@ -1499,12 +1546,29 @@ function assessProfile(profile, evidence) {
1499
1546
  continue;
1500
1547
  }
1501
1548
  if (check.type === "no_fatal_console_errors") {
1502
- const fatalCount = ((evidence.console && evidence.console.fatal_count) || 0) + ((evidence.page_errors || []).length);
1549
+ const fatalConsoleEvents = ((evidence.console && evidence.console.events) || []).filter((event) => event && (event.type === "error" || event.type === "assert"));
1550
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
1551
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
1552
+ const pageErrors = evidence.page_errors || [];
1553
+ const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error && error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
1554
+ const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error && error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
1555
+ const fatalCount = unallowedConsoleEvents.length + unallowedPageErrors.length;
1503
1556
  checks.push({
1504
1557
  type: check.type,
1505
1558
  label: check.label || check.type,
1506
1559
  status: fatalCount ? "failed" : "passed",
1507
- evidence: { console_fatal_count: (evidence.console && evidence.console.fatal_count) || 0, page_error_count: (evidence.page_errors || []).length },
1560
+ evidence: {
1561
+ console_fatal_count: unallowedConsoleEvents.length,
1562
+ page_error_count: unallowedPageErrors.length,
1563
+ total_console_fatal_count: fatalConsoleEvents.length,
1564
+ total_page_error_count: pageErrors.length,
1565
+ allowed_console_fatal_count: allowedConsoleEvents.length,
1566
+ allowed_page_error_count: allowedPageErrors.length,
1567
+ allowed_console_texts: check.allowed_console_texts || [],
1568
+ allowed_console_patterns: check.allowed_console_patterns || [],
1569
+ allowed_page_error_texts: check.allowed_page_error_texts || [],
1570
+ allowed_page_error_patterns: check.allowed_page_error_patterns || [],
1571
+ },
1508
1572
  message: fatalCount ? String(fatalCount) + " fatal browser error(s) were captured." : undefined,
1509
1573
  });
1510
1574
  continue;
package/dist/cli.cjs CHANGED
@@ -7178,6 +7178,13 @@ function normalizeExpectedTexts(value, index) {
7178
7178
  if (!texts.length) throw new Error(`checks[${index}] selector_text_order expected_texts must contain non-empty strings.`);
7179
7179
  return texts;
7180
7180
  }
7181
+ function normalizeStringList(value, label) {
7182
+ if (value === void 0) return void 0;
7183
+ if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
7184
+ const values = value.map((item) => String(item).replace(/\s+/g, " ").trim()).filter(Boolean);
7185
+ if (!values.length) throw new Error(`${label} must contain non-empty strings.`);
7186
+ return values;
7187
+ }
7181
7188
  function normalizeCheck(input, index) {
7182
7189
  if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
7183
7190
  const type = stringValue2(input.type);
@@ -7226,6 +7233,10 @@ function normalizeCheck(input, index) {
7226
7233
  text: stringValue2(input.text),
7227
7234
  pattern: stringValue2(input.pattern),
7228
7235
  flags: stringValue2(input.flags),
7236
+ allowed_console_texts: normalizeStringList(input.allowed_console_texts ?? input.allowedConsoleTexts ?? input.allow_console_texts ?? input.allowConsoleTexts, `checks[${index}] allowed_console_texts`),
7237
+ allowed_console_patterns: normalizeStringList(input.allowed_console_patterns ?? input.allowedConsolePatterns ?? input.allow_console_patterns ?? input.allowConsolePatterns, `checks[${index}] allowed_console_patterns`),
7238
+ allowed_page_error_texts: normalizeStringList(input.allowed_page_error_texts ?? input.allowedPageErrorTexts ?? input.allow_page_error_texts ?? input.allowPageErrorTexts, `checks[${index}] allowed_page_error_texts`),
7239
+ allowed_page_error_patterns: normalizeStringList(input.allowed_page_error_patterns ?? input.allowedPageErrorPatterns ?? input.allow_page_error_patterns ?? input.allowPageErrorPatterns, `checks[${index}] allowed_page_error_patterns`),
7229
7240
  min_count: numberValue(input.min_count),
7230
7241
  max_overflow_px: numberValue(input.max_overflow_px),
7231
7242
  timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
@@ -7389,6 +7400,18 @@ function matchText(sample, check) {
7389
7400
  }
7390
7401
  return sample.includes(check.text || "");
7391
7402
  }
7403
+ function matchesAllowedMessage(message, texts, patterns) {
7404
+ const sample = String(message || "");
7405
+ if (texts?.some((text) => sample.includes(text))) return true;
7406
+ for (const pattern of patterns || []) {
7407
+ try {
7408
+ if (new RegExp(pattern).test(sample)) return true;
7409
+ } catch {
7410
+ continue;
7411
+ }
7412
+ }
7413
+ return false;
7414
+ }
7392
7415
  function normalizeRoutePath(path7) {
7393
7416
  const value = path7 || "/";
7394
7417
  if (value === "/") return "/";
@@ -7675,14 +7698,28 @@ function assessCheckFromEvidence(check, evidence) {
7675
7698
  };
7676
7699
  }
7677
7700
  if (check.type === "no_fatal_console_errors") {
7678
- const fatalCount = (evidence.console?.fatal_count || 0) + (evidence.page_errors?.length || 0);
7701
+ const fatalConsoleEvents = (evidence.console?.events || []).filter((event) => event.type === "error" || event.type === "assert");
7702
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
7703
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
7704
+ const pageErrors = evidence.page_errors || [];
7705
+ const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
7706
+ const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
7707
+ const fatalCount = unallowedConsoleEvents.length + unallowedPageErrors.length;
7679
7708
  return {
7680
7709
  type: check.type,
7681
7710
  label: checkLabel(check),
7682
7711
  status: fatalCount ? "failed" : "passed",
7683
7712
  evidence: {
7684
- console_fatal_count: evidence.console?.fatal_count || 0,
7685
- page_error_count: evidence.page_errors?.length || 0
7713
+ console_fatal_count: unallowedConsoleEvents.length,
7714
+ page_error_count: unallowedPageErrors.length,
7715
+ total_console_fatal_count: fatalConsoleEvents.length,
7716
+ total_page_error_count: pageErrors.length,
7717
+ allowed_console_fatal_count: allowedConsoleEvents.length,
7718
+ allowed_page_error_count: allowedPageErrors.length,
7719
+ allowed_console_texts: check.allowed_console_texts || [],
7720
+ allowed_console_patterns: check.allowed_console_patterns || [],
7721
+ allowed_page_error_texts: check.allowed_page_error_texts || [],
7722
+ allowed_page_error_patterns: check.allowed_page_error_patterns || []
7686
7723
  },
7687
7724
  message: fatalCount ? `${fatalCount} fatal browser error(s) were captured.` : void 0
7688
7725
  };
@@ -7922,6 +7959,16 @@ function textMatches(sample, check) {
7922
7959
  }
7923
7960
  return String(sample || "").includes(check.text || "");
7924
7961
  }
7962
+ function matchesAllowedMessage(message, texts, patterns) {
7963
+ const sample = String(message || "");
7964
+ if ((texts || []).some((text) => sample.includes(text))) return true;
7965
+ for (const pattern of patterns || []) {
7966
+ try {
7967
+ if (new RegExp(pattern).test(sample)) return true;
7968
+ } catch {}
7969
+ }
7970
+ return false;
7971
+ }
7925
7972
  function textSequenceForCheck(viewport, check) {
7926
7973
  const key = check.selector || "";
7927
7974
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
@@ -8356,12 +8403,29 @@ function assessProfile(profile, evidence) {
8356
8403
  continue;
8357
8404
  }
8358
8405
  if (check.type === "no_fatal_console_errors") {
8359
- const fatalCount = ((evidence.console && evidence.console.fatal_count) || 0) + ((evidence.page_errors || []).length);
8406
+ const fatalConsoleEvents = ((evidence.console && evidence.console.events) || []).filter((event) => event && (event.type === "error" || event.type === "assert"));
8407
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
8408
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
8409
+ const pageErrors = evidence.page_errors || [];
8410
+ const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error && error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
8411
+ const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error && error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
8412
+ const fatalCount = unallowedConsoleEvents.length + unallowedPageErrors.length;
8360
8413
  checks.push({
8361
8414
  type: check.type,
8362
8415
  label: check.label || check.type,
8363
8416
  status: fatalCount ? "failed" : "passed",
8364
- evidence: { console_fatal_count: (evidence.console && evidence.console.fatal_count) || 0, page_error_count: (evidence.page_errors || []).length },
8417
+ evidence: {
8418
+ console_fatal_count: unallowedConsoleEvents.length,
8419
+ page_error_count: unallowedPageErrors.length,
8420
+ total_console_fatal_count: fatalConsoleEvents.length,
8421
+ total_page_error_count: pageErrors.length,
8422
+ allowed_console_fatal_count: allowedConsoleEvents.length,
8423
+ allowed_page_error_count: allowedPageErrors.length,
8424
+ allowed_console_texts: check.allowed_console_texts || [],
8425
+ allowed_console_patterns: check.allowed_console_patterns || [],
8426
+ allowed_page_error_texts: check.allowed_page_error_texts || [],
8427
+ allowed_page_error_patterns: check.allowed_page_error_patterns || [],
8428
+ },
8365
8429
  message: fatalCount ? String(fatalCount) + " fatal browser error(s) were captured." : undefined,
8366
8430
  });
8367
8431
  continue;
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl,
12
12
  resolveRiddleProofProfileTimeoutSec
13
- } from "./chunk-ZB7AFRN3.js";
13
+ } from "./chunk-L4FLSU7L.js";
14
14
  import {
15
15
  createRiddleApiClient,
16
16
  parseRiddleViewport
package/dist/index.cjs CHANGED
@@ -9019,6 +9019,13 @@ function normalizeExpectedTexts(value, index) {
9019
9019
  if (!texts.length) throw new Error(`checks[${index}] selector_text_order expected_texts must contain non-empty strings.`);
9020
9020
  return texts;
9021
9021
  }
9022
+ function normalizeStringList(value, label) {
9023
+ if (value === void 0) return void 0;
9024
+ if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
9025
+ const values = value.map((item) => String(item).replace(/\s+/g, " ").trim()).filter(Boolean);
9026
+ if (!values.length) throw new Error(`${label} must contain non-empty strings.`);
9027
+ return values;
9028
+ }
9022
9029
  function normalizeCheck(input, index) {
9023
9030
  if (!isRecord2(input)) throw new Error(`checks[${index}] must be an object.`);
9024
9031
  const type = stringValue5(input.type);
@@ -9067,6 +9074,10 @@ function normalizeCheck(input, index) {
9067
9074
  text: stringValue5(input.text),
9068
9075
  pattern: stringValue5(input.pattern),
9069
9076
  flags: stringValue5(input.flags),
9077
+ allowed_console_texts: normalizeStringList(input.allowed_console_texts ?? input.allowedConsoleTexts ?? input.allow_console_texts ?? input.allowConsoleTexts, `checks[${index}] allowed_console_texts`),
9078
+ allowed_console_patterns: normalizeStringList(input.allowed_console_patterns ?? input.allowedConsolePatterns ?? input.allow_console_patterns ?? input.allowConsolePatterns, `checks[${index}] allowed_console_patterns`),
9079
+ allowed_page_error_texts: normalizeStringList(input.allowed_page_error_texts ?? input.allowedPageErrorTexts ?? input.allow_page_error_texts ?? input.allowPageErrorTexts, `checks[${index}] allowed_page_error_texts`),
9080
+ allowed_page_error_patterns: normalizeStringList(input.allowed_page_error_patterns ?? input.allowedPageErrorPatterns ?? input.allow_page_error_patterns ?? input.allowPageErrorPatterns, `checks[${index}] allowed_page_error_patterns`),
9070
9081
  min_count: numberValue3(input.min_count),
9071
9082
  max_overflow_px: numberValue3(input.max_overflow_px),
9072
9083
  timeout_ms: numberValue3(input.timeout_ms) ?? numberValue3(input.timeoutMs),
@@ -9230,6 +9241,18 @@ function matchText(sample, check) {
9230
9241
  }
9231
9242
  return sample.includes(check.text || "");
9232
9243
  }
9244
+ function matchesAllowedMessage(message, texts, patterns) {
9245
+ const sample = String(message || "");
9246
+ if (texts?.some((text) => sample.includes(text))) return true;
9247
+ for (const pattern of patterns || []) {
9248
+ try {
9249
+ if (new RegExp(pattern).test(sample)) return true;
9250
+ } catch {
9251
+ continue;
9252
+ }
9253
+ }
9254
+ return false;
9255
+ }
9233
9256
  function normalizeRoutePath(path6) {
9234
9257
  const value = path6 || "/";
9235
9258
  if (value === "/") return "/";
@@ -9516,14 +9539,28 @@ function assessCheckFromEvidence(check, evidence) {
9516
9539
  };
9517
9540
  }
9518
9541
  if (check.type === "no_fatal_console_errors") {
9519
- const fatalCount = (evidence.console?.fatal_count || 0) + (evidence.page_errors?.length || 0);
9542
+ const fatalConsoleEvents = (evidence.console?.events || []).filter((event) => event.type === "error" || event.type === "assert");
9543
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
9544
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
9545
+ const pageErrors = evidence.page_errors || [];
9546
+ const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
9547
+ const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
9548
+ const fatalCount = unallowedConsoleEvents.length + unallowedPageErrors.length;
9520
9549
  return {
9521
9550
  type: check.type,
9522
9551
  label: checkLabel(check),
9523
9552
  status: fatalCount ? "failed" : "passed",
9524
9553
  evidence: {
9525
- console_fatal_count: evidence.console?.fatal_count || 0,
9526
- page_error_count: evidence.page_errors?.length || 0
9554
+ console_fatal_count: unallowedConsoleEvents.length,
9555
+ page_error_count: unallowedPageErrors.length,
9556
+ total_console_fatal_count: fatalConsoleEvents.length,
9557
+ total_page_error_count: pageErrors.length,
9558
+ allowed_console_fatal_count: allowedConsoleEvents.length,
9559
+ allowed_page_error_count: allowedPageErrors.length,
9560
+ allowed_console_texts: check.allowed_console_texts || [],
9561
+ allowed_console_patterns: check.allowed_console_patterns || [],
9562
+ allowed_page_error_texts: check.allowed_page_error_texts || [],
9563
+ allowed_page_error_patterns: check.allowed_page_error_patterns || []
9527
9564
  },
9528
9565
  message: fatalCount ? `${fatalCount} fatal browser error(s) were captured.` : void 0
9529
9566
  };
@@ -9779,6 +9816,16 @@ function textMatches(sample, check) {
9779
9816
  }
9780
9817
  return String(sample || "").includes(check.text || "");
9781
9818
  }
9819
+ function matchesAllowedMessage(message, texts, patterns) {
9820
+ const sample = String(message || "");
9821
+ if ((texts || []).some((text) => sample.includes(text))) return true;
9822
+ for (const pattern of patterns || []) {
9823
+ try {
9824
+ if (new RegExp(pattern).test(sample)) return true;
9825
+ } catch {}
9826
+ }
9827
+ return false;
9828
+ }
9782
9829
  function textSequenceForCheck(viewport, check) {
9783
9830
  const key = check.selector || "";
9784
9831
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
@@ -10213,12 +10260,29 @@ function assessProfile(profile, evidence) {
10213
10260
  continue;
10214
10261
  }
10215
10262
  if (check.type === "no_fatal_console_errors") {
10216
- const fatalCount = ((evidence.console && evidence.console.fatal_count) || 0) + ((evidence.page_errors || []).length);
10263
+ const fatalConsoleEvents = ((evidence.console && evidence.console.events) || []).filter((event) => event && (event.type === "error" || event.type === "assert"));
10264
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
10265
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
10266
+ const pageErrors = evidence.page_errors || [];
10267
+ const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error && error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
10268
+ const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error && error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
10269
+ const fatalCount = unallowedConsoleEvents.length + unallowedPageErrors.length;
10217
10270
  checks.push({
10218
10271
  type: check.type,
10219
10272
  label: check.label || check.type,
10220
10273
  status: fatalCount ? "failed" : "passed",
10221
- evidence: { console_fatal_count: (evidence.console && evidence.console.fatal_count) || 0, page_error_count: (evidence.page_errors || []).length },
10274
+ evidence: {
10275
+ console_fatal_count: unallowedConsoleEvents.length,
10276
+ page_error_count: unallowedPageErrors.length,
10277
+ total_console_fatal_count: fatalConsoleEvents.length,
10278
+ total_page_error_count: pageErrors.length,
10279
+ allowed_console_fatal_count: allowedConsoleEvents.length,
10280
+ allowed_page_error_count: allowedPageErrors.length,
10281
+ allowed_console_texts: check.allowed_console_texts || [],
10282
+ allowed_console_patterns: check.allowed_console_patterns || [],
10283
+ allowed_page_error_texts: check.allowed_page_error_texts || [],
10284
+ allowed_page_error_patterns: check.allowed_page_error_patterns || [],
10285
+ },
10222
10286
  message: fatalCount ? String(fatalCount) + " fatal browser error(s) were captured." : undefined,
10223
10287
  });
10224
10288
  continue;
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-ZB7AFRN3.js";
61
+ } from "./chunk-L4FLSU7L.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -348,6 +348,13 @@ function normalizeExpectedTexts(value, index) {
348
348
  if (!texts.length) throw new Error(`checks[${index}] selector_text_order expected_texts must contain non-empty strings.`);
349
349
  return texts;
350
350
  }
351
+ function normalizeStringList(value, label) {
352
+ if (value === void 0) return void 0;
353
+ if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
354
+ const values = value.map((item) => String(item).replace(/\s+/g, " ").trim()).filter(Boolean);
355
+ if (!values.length) throw new Error(`${label} must contain non-empty strings.`);
356
+ return values;
357
+ }
351
358
  function normalizeCheck(input, index) {
352
359
  if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
353
360
  const type = stringValue(input.type);
@@ -396,6 +403,10 @@ function normalizeCheck(input, index) {
396
403
  text: stringValue(input.text),
397
404
  pattern: stringValue(input.pattern),
398
405
  flags: stringValue(input.flags),
406
+ allowed_console_texts: normalizeStringList(input.allowed_console_texts ?? input.allowedConsoleTexts ?? input.allow_console_texts ?? input.allowConsoleTexts, `checks[${index}] allowed_console_texts`),
407
+ allowed_console_patterns: normalizeStringList(input.allowed_console_patterns ?? input.allowedConsolePatterns ?? input.allow_console_patterns ?? input.allowConsolePatterns, `checks[${index}] allowed_console_patterns`),
408
+ allowed_page_error_texts: normalizeStringList(input.allowed_page_error_texts ?? input.allowedPageErrorTexts ?? input.allow_page_error_texts ?? input.allowPageErrorTexts, `checks[${index}] allowed_page_error_texts`),
409
+ allowed_page_error_patterns: normalizeStringList(input.allowed_page_error_patterns ?? input.allowedPageErrorPatterns ?? input.allow_page_error_patterns ?? input.allowPageErrorPatterns, `checks[${index}] allowed_page_error_patterns`),
399
410
  min_count: numberValue(input.min_count),
400
411
  max_overflow_px: numberValue(input.max_overflow_px),
401
412
  timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
@@ -559,6 +570,18 @@ function matchText(sample, check) {
559
570
  }
560
571
  return sample.includes(check.text || "");
561
572
  }
573
+ function matchesAllowedMessage(message, texts, patterns) {
574
+ const sample = String(message || "");
575
+ if (texts?.some((text) => sample.includes(text))) return true;
576
+ for (const pattern of patterns || []) {
577
+ try {
578
+ if (new RegExp(pattern).test(sample)) return true;
579
+ } catch {
580
+ continue;
581
+ }
582
+ }
583
+ return false;
584
+ }
562
585
  function normalizeRoutePath(path) {
563
586
  const value = path || "/";
564
587
  if (value === "/") return "/";
@@ -845,14 +868,28 @@ function assessCheckFromEvidence(check, evidence) {
845
868
  };
846
869
  }
847
870
  if (check.type === "no_fatal_console_errors") {
848
- const fatalCount = (evidence.console?.fatal_count || 0) + (evidence.page_errors?.length || 0);
871
+ const fatalConsoleEvents = (evidence.console?.events || []).filter((event) => event.type === "error" || event.type === "assert");
872
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
873
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
874
+ const pageErrors = evidence.page_errors || [];
875
+ const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
876
+ const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
877
+ const fatalCount = unallowedConsoleEvents.length + unallowedPageErrors.length;
849
878
  return {
850
879
  type: check.type,
851
880
  label: checkLabel(check),
852
881
  status: fatalCount ? "failed" : "passed",
853
882
  evidence: {
854
- console_fatal_count: evidence.console?.fatal_count || 0,
855
- page_error_count: evidence.page_errors?.length || 0
883
+ console_fatal_count: unallowedConsoleEvents.length,
884
+ page_error_count: unallowedPageErrors.length,
885
+ total_console_fatal_count: fatalConsoleEvents.length,
886
+ total_page_error_count: pageErrors.length,
887
+ allowed_console_fatal_count: allowedConsoleEvents.length,
888
+ allowed_page_error_count: allowedPageErrors.length,
889
+ allowed_console_texts: check.allowed_console_texts || [],
890
+ allowed_console_patterns: check.allowed_console_patterns || [],
891
+ allowed_page_error_texts: check.allowed_page_error_texts || [],
892
+ allowed_page_error_patterns: check.allowed_page_error_patterns || []
856
893
  },
857
894
  message: fatalCount ? `${fatalCount} fatal browser error(s) were captured.` : void 0
858
895
  };
@@ -1108,6 +1145,16 @@ function textMatches(sample, check) {
1108
1145
  }
1109
1146
  return String(sample || "").includes(check.text || "");
1110
1147
  }
1148
+ function matchesAllowedMessage(message, texts, patterns) {
1149
+ const sample = String(message || "");
1150
+ if ((texts || []).some((text) => sample.includes(text))) return true;
1151
+ for (const pattern of patterns || []) {
1152
+ try {
1153
+ if (new RegExp(pattern).test(sample)) return true;
1154
+ } catch {}
1155
+ }
1156
+ return false;
1157
+ }
1111
1158
  function textSequenceForCheck(viewport, check) {
1112
1159
  const key = check.selector || "";
1113
1160
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
@@ -1542,12 +1589,29 @@ function assessProfile(profile, evidence) {
1542
1589
  continue;
1543
1590
  }
1544
1591
  if (check.type === "no_fatal_console_errors") {
1545
- const fatalCount = ((evidence.console && evidence.console.fatal_count) || 0) + ((evidence.page_errors || []).length);
1592
+ const fatalConsoleEvents = ((evidence.console && evidence.console.events) || []).filter((event) => event && (event.type === "error" || event.type === "assert"));
1593
+ const allowedConsoleEvents = fatalConsoleEvents.filter((event) => matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
1594
+ const unallowedConsoleEvents = fatalConsoleEvents.filter((event) => !matchesAllowedMessage(event.text, check.allowed_console_texts, check.allowed_console_patterns));
1595
+ const pageErrors = evidence.page_errors || [];
1596
+ const allowedPageErrors = pageErrors.filter((error) => matchesAllowedMessage(error && error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
1597
+ const unallowedPageErrors = pageErrors.filter((error) => !matchesAllowedMessage(error && error.message, check.allowed_page_error_texts, check.allowed_page_error_patterns));
1598
+ const fatalCount = unallowedConsoleEvents.length + unallowedPageErrors.length;
1546
1599
  checks.push({
1547
1600
  type: check.type,
1548
1601
  label: check.label || check.type,
1549
1602
  status: fatalCount ? "failed" : "passed",
1550
- evidence: { console_fatal_count: (evidence.console && evidence.console.fatal_count) || 0, page_error_count: (evidence.page_errors || []).length },
1603
+ evidence: {
1604
+ console_fatal_count: unallowedConsoleEvents.length,
1605
+ page_error_count: unallowedPageErrors.length,
1606
+ total_console_fatal_count: fatalConsoleEvents.length,
1607
+ total_page_error_count: pageErrors.length,
1608
+ allowed_console_fatal_count: allowedConsoleEvents.length,
1609
+ allowed_page_error_count: allowedPageErrors.length,
1610
+ allowed_console_texts: check.allowed_console_texts || [],
1611
+ allowed_console_patterns: check.allowed_console_patterns || [],
1612
+ allowed_page_error_texts: check.allowed_page_error_texts || [],
1613
+ allowed_page_error_patterns: check.allowed_page_error_patterns || [],
1614
+ },
1551
1615
  message: fatalCount ? String(fatalCount) + " fatal browser error(s) were captured." : undefined,
1552
1616
  });
1553
1617
  continue;
@@ -77,6 +77,10 @@ interface RiddleProofProfileCheck {
77
77
  text?: string;
78
78
  pattern?: string;
79
79
  flags?: string;
80
+ allowed_console_texts?: string[];
81
+ allowed_console_patterns?: string[];
82
+ allowed_page_error_texts?: string[];
83
+ allowed_page_error_patterns?: string[];
80
84
  min_count?: number;
81
85
  max_overflow_px?: number;
82
86
  timeout_ms?: number;
package/dist/profile.d.ts CHANGED
@@ -77,6 +77,10 @@ interface RiddleProofProfileCheck {
77
77
  text?: string;
78
78
  pattern?: string;
79
79
  flags?: string;
80
+ allowed_console_texts?: string[];
81
+ allowed_console_patterns?: string[];
82
+ allowed_page_error_texts?: string[];
83
+ allowed_page_error_patterns?: string[];
80
84
  min_count?: number;
81
85
  max_overflow_px?: number;
82
86
  timeout_ms?: number;
package/dist/profile.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  resolveRiddleProofProfileTimeoutSec,
20
20
  slugifyRiddleProofProfileName,
21
21
  summarizeRiddleProofProfileResult
22
- } from "./chunk-ZB7AFRN3.js";
22
+ } from "./chunk-L4FLSU7L.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.38",
3
+ "version": "0.7.39",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",