@riddledc/riddle-proof 0.7.128 → 0.7.130

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/dist/cli.cjs CHANGED
@@ -7544,6 +7544,17 @@ function normalizeSetupActionCoordinateMode(value, index) {
7544
7544
  if (normalized === "ratio" || normalized === "relative" || normalized === "fraction") return "ratio";
7545
7545
  throw new Error(`target.setup_actions[${index}].coordinate_mode ${String(value)} is not supported. Supported coordinate modes: pixels, ratio.`);
7546
7546
  }
7547
+ function normalizeSetupActionPointerType(value, type, index) {
7548
+ if (value === void 0 || value === null || value === "") return void 0;
7549
+ if (type !== "drag") {
7550
+ throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag actions.`);
7551
+ }
7552
+ const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
7553
+ if (normalized === "mouse") return "mouse";
7554
+ if (normalized === "touch" || normalized === "finger") return "touch";
7555
+ if (normalized === "pen" || normalized === "stylus") return "pen";
7556
+ throw new Error(`target.setup_actions[${index}].pointer_type ${String(value)} is not supported. Supported pointer types: mouse, touch, pen.`);
7557
+ }
7547
7558
  function normalizeSetupAction(input, index) {
7548
7559
  if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
7549
7560
  const type = normalizeSetupActionType(stringValue2(input.type), index);
@@ -7562,6 +7573,7 @@ function normalizeSetupAction(input, index) {
7562
7573
  const toX = numberValue(valueFromOwn(input, "to_x", "toX", "end_x", "endX", "x2"));
7563
7574
  const toY = numberValue(valueFromOwn(input, "to_y", "toY", "end_y", "endY", "y2"));
7564
7575
  const coordinateMode = normalizeSetupActionCoordinateMode(valueFromOwn(input, "coordinate_mode", "coordinateMode", "coords", "units"), index);
7576
+ const pointerType = normalizeSetupActionPointerType(valueFromOwn(input, "pointer_type", "pointerType", "input_type", "inputType"), type, index);
7565
7577
  if (type === "drag") {
7566
7578
  if (fromX === void 0 || fromY === void 0 || toX === void 0 || toY === void 0) {
7567
7579
  throw new Error(`target.setup_actions[${index}] drag requires from_x, from_y, to_x, and to_y.`);
@@ -7646,6 +7658,7 @@ function normalizeSetupAction(input, index) {
7646
7658
  force: type === "click" && (input.force === true || input.force_click === true || input.forceClick === true),
7647
7659
  click_count: normalizeSetupActionClickCount(input, type, index),
7648
7660
  coordinate_mode: coordinateMode,
7661
+ pointer_type: pointerType,
7649
7662
  from_x: fromX,
7650
7663
  from_y: fromY,
7651
7664
  to_x: toX,
@@ -8791,6 +8804,49 @@ function matchText(sample, check) {
8791
8804
  }
8792
8805
  return sample.includes(check.text || "");
8793
8806
  }
8807
+ function compactTextEvidenceSample(value) {
8808
+ return String(value || "").replace(/\s+/g, " ").trim();
8809
+ }
8810
+ function textSampleAroundMatch(sample, index, length) {
8811
+ if (index < 0) return void 0;
8812
+ const source = String(sample || "");
8813
+ const context = 120;
8814
+ const start = Math.max(0, index - context);
8815
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
8816
+ const prefix = start > 0 ? "..." : "";
8817
+ const suffix = end < source.length ? "..." : "";
8818
+ const compacted = compactTextEvidenceSample(`${prefix}${source.slice(start, end)}${suffix}`);
8819
+ return compacted ? compacted.slice(0, 240) : void 0;
8820
+ }
8821
+ function textMatchSamples(sample, check) {
8822
+ const source = String(sample || "");
8823
+ if (!source) return [];
8824
+ if (check.pattern) {
8825
+ try {
8826
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
8827
+ const match = new RegExp(check.pattern, flags).exec(source);
8828
+ const sampleText2 = match ? textSampleAroundMatch(source, match.index, match[0]?.length || 1) : void 0;
8829
+ return sampleText2 ? [sampleText2] : [];
8830
+ } catch {
8831
+ return [];
8832
+ }
8833
+ }
8834
+ const text = check.text || "";
8835
+ if (!text) return [];
8836
+ const index = source.indexOf(text);
8837
+ const sampleText = textSampleAroundMatch(source, index, text.length);
8838
+ return sampleText ? [sampleText] : [];
8839
+ }
8840
+ function textCheckFailureSamples(viewport, check) {
8841
+ const key = textKey(check);
8842
+ const captured = viewport.text_match_samples?.[key] || [];
8843
+ const capturedSamples = captured.map((sample) => compactTextEvidenceSample(sample).slice(0, 240)).filter(Boolean);
8844
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
8845
+ const matchedSamples = textMatchSamples(viewport.body_text_sample || "", check);
8846
+ if (matchedSamples.length) return matchedSamples.slice(0, 3);
8847
+ const fallback = compactTextEvidenceSample(viewport.body_text_sample || "").slice(0, 240);
8848
+ return fallback ? [fallback] : [];
8849
+ }
8794
8850
  function allowedMessageSample(input) {
8795
8851
  if (!isRecord(input)) return String(input || "");
8796
8852
  const parts = [
@@ -9235,10 +9291,17 @@ function assessCheckFromEvidence(check, evidence) {
9235
9291
  if (check.type === "text_visible" || check.type === "text_absent") {
9236
9292
  const key = textKey(check);
9237
9293
  const expectedVisible = check.type === "text_visible";
9238
- const matches = viewports.map((viewport) => {
9294
+ const results = viewports.map((viewport) => {
9239
9295
  const fromEvidence = viewport.text_matches?.[key];
9240
- return typeof fromEvidence === "boolean" ? fromEvidence : matchText(viewport.body_text_sample || "", check);
9296
+ const matched = typeof fromEvidence === "boolean" ? fromEvidence : matchText(viewport.body_text_sample || "", check);
9297
+ const failedAgainstExpectation = matched !== expectedVisible;
9298
+ return {
9299
+ viewport: viewport.name,
9300
+ matched,
9301
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : []
9302
+ };
9241
9303
  });
9304
+ const matches = results.map((result) => result.matched);
9242
9305
  const failed = matches.filter((matched) => matched !== expectedVisible).length;
9243
9306
  return {
9244
9307
  type: check.type,
@@ -9247,7 +9310,8 @@ function assessCheckFromEvidence(check, evidence) {
9247
9310
  evidence: {
9248
9311
  text: check.text || null,
9249
9312
  pattern: check.pattern || null,
9250
- matches
9313
+ matches,
9314
+ viewports: results.map((result) => toJsonValue(result))
9251
9315
  },
9252
9316
  message: failed ? `Text assertion failed in ${failed} viewport(s).` : void 0
9253
9317
  };
@@ -9818,6 +9882,48 @@ function textMatches(sample, check) {
9818
9882
  }
9819
9883
  return String(sample || "").includes(check.text || "");
9820
9884
  }
9885
+ function compactTextEvidenceSample(value) {
9886
+ return String(value || "").replace(/\s+/g, " ").trim();
9887
+ }
9888
+ function textSampleAroundMatch(sample, index, length) {
9889
+ if (index < 0) return undefined;
9890
+ const source = String(sample || "");
9891
+ const context = 120;
9892
+ const start = Math.max(0, index - context);
9893
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
9894
+ const prefix = start > 0 ? "..." : "";
9895
+ const suffix = end < source.length ? "..." : "";
9896
+ const compacted = compactTextEvidenceSample(prefix + source.slice(start, end) + suffix);
9897
+ return compacted ? compacted.slice(0, 240) : undefined;
9898
+ }
9899
+ function textMatchSamples(sample, check) {
9900
+ const source = String(sample || "");
9901
+ if (!source) return [];
9902
+ if (check.pattern) {
9903
+ try {
9904
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
9905
+ const match = new RegExp(check.pattern, flags).exec(source);
9906
+ const sampleText = match ? textSampleAroundMatch(source, match.index, match[0] ? match[0].length : 1) : undefined;
9907
+ return sampleText ? [sampleText] : [];
9908
+ } catch { return []; }
9909
+ }
9910
+ const text = check.text || "";
9911
+ if (!text) return [];
9912
+ const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
9913
+ return sampleText ? [sampleText] : [];
9914
+ }
9915
+ function textCheckFailureSamples(viewport, check) {
9916
+ const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
9917
+ const captured = viewport && viewport.text_match_samples && Array.isArray(viewport.text_match_samples[key]) ? viewport.text_match_samples[key] : [];
9918
+ const capturedSamples = captured
9919
+ .map((sample) => compactTextEvidenceSample(sample).slice(0, 240))
9920
+ .filter(Boolean);
9921
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
9922
+ const matchedSamples = textMatchSamples(viewport && viewport.body_text_sample || "", check);
9923
+ if (matchedSamples.length) return matchedSamples.slice(0, 3);
9924
+ const fallback = compactTextEvidenceSample(viewport && viewport.body_text_sample || "").slice(0, 240);
9925
+ return fallback ? [fallback] : [];
9926
+ }
9821
9927
  function allowedMessageSample(input) {
9822
9928
  if (!input || typeof input !== "object" || Array.isArray(input)) return String(input || "");
9823
9929
  const parts = [
@@ -10895,13 +11001,22 @@ function assessProfile(profile, evidence) {
10895
11001
  if (check.type === "text_visible" || check.type === "text_absent") {
10896
11002
  const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
10897
11003
  const expectedVisible = check.type === "text_visible";
10898
- const matches = checkViewports.map((viewport) => viewport.text_matches && typeof viewport.text_matches[key] === "boolean" ? viewport.text_matches[key] : textMatches(viewport.body_text_sample || "", check));
11004
+ const results = checkViewports.map((viewport) => {
11005
+ const matched = viewport.text_matches && typeof viewport.text_matches[key] === "boolean" ? viewport.text_matches[key] : textMatches(viewport.body_text_sample || "", check);
11006
+ const failedAgainstExpectation = matched !== expectedVisible;
11007
+ return {
11008
+ viewport: viewport.name,
11009
+ matched,
11010
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
11011
+ };
11012
+ });
11013
+ const matches = results.map((result) => result.matched);
10899
11014
  const failed = matches.filter((matched) => matched !== expectedVisible).length;
10900
11015
  checks.push({
10901
11016
  type: check.type,
10902
11017
  label: check.label || check.type,
10903
11018
  status: failed ? "failed" : "passed",
10904
- evidence: { text: check.text, pattern: check.pattern, matches },
11019
+ evidence: { text: check.text, pattern: check.pattern, matches, viewports: results },
10905
11020
  message: failed ? "Text assertion failed in " + failed + " viewport(s)." : undefined,
10906
11021
  });
10907
11022
  continue;
@@ -11221,6 +11336,36 @@ function textMatches(sample, check) {
11221
11336
  }
11222
11337
  return String(sample || "").includes(check.text || "");
11223
11338
  }
11339
+ function compactTextEvidenceSample(value) {
11340
+ return String(value || "").replace(/\s+/g, " ").trim();
11341
+ }
11342
+ function textSampleAroundMatch(sample, index, length) {
11343
+ if (index < 0) return undefined;
11344
+ const source = String(sample || "");
11345
+ const context = 120;
11346
+ const start = Math.max(0, index - context);
11347
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
11348
+ const prefix = start > 0 ? "..." : "";
11349
+ const suffix = end < source.length ? "..." : "";
11350
+ const compacted = compactTextEvidenceSample(prefix + source.slice(start, end) + suffix);
11351
+ return compacted ? compacted.slice(0, 240) : undefined;
11352
+ }
11353
+ function textMatchSamples(sample, check) {
11354
+ const source = String(sample || "");
11355
+ if (!source) return [];
11356
+ if (check.pattern) {
11357
+ try {
11358
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
11359
+ const match = new RegExp(check.pattern, flags).exec(source);
11360
+ const sampleText = match ? textSampleAroundMatch(source, match.index, match[0] ? match[0].length : 1) : undefined;
11361
+ return sampleText ? [sampleText] : [];
11362
+ } catch { return []; }
11363
+ }
11364
+ const text = check.text || "";
11365
+ if (!text) return [];
11366
+ const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
11367
+ return sampleText ? [sampleText] : [];
11368
+ }
11224
11369
  function profileCheckAppliesToViewport(check, viewport) {
11225
11370
  if (!Array.isArray(check.viewports) || !check.viewports.length) return true;
11226
11371
  return Boolean(viewport && viewport.name && check.viewports.includes(viewport.name));
@@ -11698,23 +11843,75 @@ async function executeSetupAction(action, ordinal, viewport) {
11698
11843
  const requestedSteps = setupNumber(action.steps, 8);
11699
11844
  const steps = Math.min(100, Math.max(1, Math.floor(requestedSteps || 8)));
11700
11845
  const durationMs = setupNumber(action.duration_ms ?? action.durationMs, 0);
11701
- await page.mouse.move(start.x, start.y);
11702
- await page.mouse.down();
11703
- try {
11704
- if (durationMs && steps > 1) {
11705
- for (let step = 1; step <= steps; step += 1) {
11706
- const progress = step / steps;
11707
- await page.mouse.move(
11708
- start.x + (end.x - start.x) * progress,
11709
- start.y + (end.y - start.y) * progress,
11710
- );
11711
- await page.waitForTimeout(durationMs / steps);
11846
+ const pointerType = String(action.pointer_type || action.pointerType || "mouse").trim().toLowerCase();
11847
+ if (pointerType === "touch" || pointerType === "pen") {
11848
+ const localStart = {
11849
+ x: coordinate(fromX, box.width),
11850
+ y: coordinate(fromY, box.height),
11851
+ };
11852
+ const localEnd = {
11853
+ x: coordinate(toX, box.width),
11854
+ y: coordinate(toY, box.height),
11855
+ };
11856
+ await target.evaluate(async (element, payload) => {
11857
+ const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
11858
+ const rect = element.getBoundingClientRect();
11859
+ const pointerId = payload.pointerType === "touch" ? 11 : 12;
11860
+ const point = (progress) => ({
11861
+ clientX: rect.left + payload.start.x + (payload.end.x - payload.start.x) * progress,
11862
+ clientY: rect.top + payload.start.y + (payload.end.y - payload.start.y) * progress,
11863
+ });
11864
+ const dispatch = (type, progress) => {
11865
+ const coords = point(progress);
11866
+ element.dispatchEvent(new PointerEvent(type, {
11867
+ bubbles: true,
11868
+ cancelable: true,
11869
+ composed: true,
11870
+ pointerId,
11871
+ pointerType: payload.pointerType,
11872
+ isPrimary: true,
11873
+ buttons: type === "pointerup" ? 0 : 1,
11874
+ button: type === "pointerup" ? 0 : 0,
11875
+ clientX: coords.clientX,
11876
+ clientY: coords.clientY,
11877
+ }));
11878
+ };
11879
+ dispatch("pointerover", 0);
11880
+ dispatch("pointerenter", 0);
11881
+ dispatch("pointerdown", 0);
11882
+ for (let step = 1; step <= payload.steps; step += 1) {
11883
+ dispatch("pointermove", step / payload.steps);
11884
+ if (payload.durationMs && payload.steps > 1) await wait(payload.durationMs / payload.steps);
11712
11885
  }
11713
- } else {
11714
- await page.mouse.move(end.x, end.y, { steps });
11886
+ dispatch("pointerup", 1);
11887
+ dispatch("pointerout", 1);
11888
+ dispatch("pointerleave", 1);
11889
+ }, {
11890
+ pointerType,
11891
+ start: localStart,
11892
+ end: localEnd,
11893
+ steps,
11894
+ durationMs,
11895
+ });
11896
+ } else {
11897
+ await page.mouse.move(start.x, start.y);
11898
+ await page.mouse.down();
11899
+ try {
11900
+ if (durationMs && steps > 1) {
11901
+ for (let step = 1; step <= steps; step += 1) {
11902
+ const progress = step / steps;
11903
+ await page.mouse.move(
11904
+ start.x + (end.x - start.x) * progress,
11905
+ start.y + (end.y - start.y) * progress,
11906
+ );
11907
+ await page.waitForTimeout(durationMs / steps);
11908
+ }
11909
+ } else {
11910
+ await page.mouse.move(end.x, end.y, { steps });
11911
+ }
11912
+ } finally {
11913
+ await page.mouse.up().catch(() => {});
11715
11914
  }
11716
- } finally {
11717
- await page.mouse.up().catch(() => {});
11718
11915
  }
11719
11916
  return {
11720
11917
  ...base,
@@ -11727,6 +11924,7 @@ async function executeSetupAction(action, ordinal, viewport) {
11727
11924
  from_y: fromY,
11728
11925
  to_x: toX,
11729
11926
  to_y: toY,
11927
+ pointer_type: pointerType,
11730
11928
  steps,
11731
11929
  duration_ms: durationMs || undefined,
11732
11930
  };
@@ -13172,6 +13370,7 @@ async function captureViewport(viewport) {
13172
13370
  const frames = {};
13173
13371
  const text_sequences = {};
13174
13372
  const text_matches = {};
13373
+ const text_match_samples = {};
13175
13374
  const http_statuses = {};
13176
13375
  const link_statuses = {};
13177
13376
  for (const check of profile.checks || []) {
@@ -13193,7 +13392,10 @@ async function captureViewport(viewport) {
13193
13392
  text_sequences[check.selector] = await selectorTextSequence(check.selector);
13194
13393
  }
13195
13394
  if ((check.type === "text_visible" || check.type === "text_absent") && (check.text || check.pattern)) {
13196
- text_matches[textKey(check)] = textMatches(dom.body_text || dom.body_text_sample || "", check);
13395
+ const key = textKey(check);
13396
+ const sample = dom.body_text || dom.body_text_sample || "";
13397
+ text_matches[key] = textMatches(sample, check);
13398
+ text_match_samples[key] = textMatchSamples(sample, check);
13197
13399
  }
13198
13400
  if ((check.type === "frame_text_visible" || check.type === "frame_url_equals" || check.type === "frame_url_matches" || check.type === "frame_no_horizontal_overflow") && check.selector) {
13199
13401
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
@@ -13270,6 +13472,7 @@ async function captureViewport(viewport) {
13270
13472
  frames,
13271
13473
  text_sequences,
13272
13474
  text_matches,
13475
+ text_match_samples,
13273
13476
  http_statuses,
13274
13477
  link_statuses,
13275
13478
  route_inventory: routeInventory,
package/dist/cli.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  profileStatusExitCode,
13
13
  resolveRiddleProofProfileTargetUrl,
14
14
  resolveRiddleProofProfileTimeoutSec
15
- } from "./chunk-TO3FVF5S.js";
15
+ } from "./chunk-ZJNM3YAB.js";
16
16
  import {
17
17
  createRiddleApiClient,
18
18
  parseRiddleViewport