@riddledc/riddle-proof 0.7.197 → 0.7.198

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/profile.cjs CHANGED
@@ -92,6 +92,7 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
92
92
  var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
93
93
  "click",
94
94
  "tap",
95
+ "tap_until",
95
96
  "drag",
96
97
  "press",
97
98
  "key_down",
@@ -662,6 +663,28 @@ function profileSetupTapReceipts(results) {
662
663
  reason: result.reason ?? result.error ?? null
663
664
  }));
664
665
  }
666
+ function profileSetupTapUntilReceipts(results) {
667
+ return results.filter((result) => profileSetupResultAction(result) === "tap_until").map((result) => ({
668
+ ordinal: result.ordinal ?? null,
669
+ ok: result.ok !== false,
670
+ selector: result.selector ?? null,
671
+ frame_selector: result.frame_selector ?? null,
672
+ pointer_type: result.pointer_type ?? null,
673
+ input_dispatch: result.input_dispatch ?? null,
674
+ coordinate_mode: result.coordinate_mode ?? null,
675
+ x: result.x ?? null,
676
+ y: result.y ?? null,
677
+ duration_ms: result.duration_ms ?? null,
678
+ until_path: result.until_path ?? null,
679
+ until_value: result.until_value ?? null,
680
+ until_expected_value: result.until_expected_value ?? null,
681
+ tap_count: result.tap_count ?? null,
682
+ max_taps: result.max_taps ?? result.max_calls ?? null,
683
+ interval_ms: result.interval_ms ?? null,
684
+ timeout_ms: result.timeout_ms ?? null,
685
+ reason: result.reason ?? result.error ?? null
686
+ }));
687
+ }
665
688
  function profileSetupKeyboardReceipts(results) {
666
689
  return results.filter((result) => ["press", "key_down", "key_up"].includes(profileSetupResultAction(result))).map((result) => ({
667
690
  action: profileSetupResultAction(result),
@@ -837,6 +860,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
837
860
  const sampledDragReceipts = sampleProfileSetupSummaryItems(dragReceipts, 8);
838
861
  const tapReceipts = profileSetupTapReceipts(results);
839
862
  const sampledTapReceipts = sampleProfileSetupSummaryItems(tapReceipts, 8);
863
+ const tapUntilReceipts = profileSetupTapUntilReceipts(results);
864
+ const tapUntilTapCounts = tapUntilReceipts.map((result) => typeof result.tap_count === "number" && Number.isFinite(result.tap_count) ? result.tap_count : void 0).filter((value) => value !== void 0);
865
+ const sampledTapUntilReceipts = sampleProfileSetupSummaryItems(tapUntilReceipts, 8);
840
866
  const keyboardReceipts = profileSetupKeyboardReceipts(results);
841
867
  const sampledKeyboardReceipts = sampleProfileSetupSummaryItems(keyboardReceipts, 8);
842
868
  const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
@@ -909,6 +935,10 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
909
935
  tap_total: tapReceipts.length,
910
936
  tap_truncated: tapReceipts.length > sampledTapReceipts.length,
911
937
  tap: sampledTapReceipts,
938
+ tap_until_total: tapUntilReceipts.length,
939
+ tap_until_tap_total: tapUntilTapCounts.reduce((sum, value) => sum + value, 0),
940
+ tap_until_truncated: tapUntilReceipts.length > sampledTapUntilReceipts.length,
941
+ tap_until: sampledTapUntilReceipts,
912
942
  keyboard_total: keyboardReceipts.length,
913
943
  keyboard_truncated: keyboardReceipts.length > sampledKeyboardReceipts.length,
914
944
  keyboard: sampledKeyboardReceipts,
@@ -970,7 +1000,7 @@ function isSupportedCheckType(value) {
970
1000
  }
971
1001
  function normalizeSetupActionType(value, index) {
972
1002
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
973
- const normalized = normalizedInput === "clear_browser_storage" ? "clear_storage" : normalizedInput === "reset_console" || normalizedInput === "clear_browser_console" || normalizedInput === "reset_browser_console" ? "clear_console" : normalizedInput === "pointer_drag" || normalizedInput === "mouse_drag" || normalizedInput === "drag_to" ? "drag" : normalizedInput === "pointer_tap" || normalizedInput === "touch_tap" || normalizedInput === "canvas_tap" ? "tap" : normalizedInput === "keyboard_press" || normalizedInput === "key_press" ? "press" : normalizedInput === "keyboard_down" || normalizedInput === "key_down" || normalizedInput === "keydown" || normalizedInput === "press_down" ? "key_down" : normalizedInput === "keyboard_up" || normalizedInput === "key_up" || normalizedInput === "keyup" || normalizedInput === "press_up" || normalizedInput === "release_key" || normalizedInput === "key_release" ? "key_up" : normalizedInput === "set_slider_value" || normalizedInput === "slider_value" || normalizedInput === "set_slider" || normalizedInput === "set_range" || normalizedInput === "range_value" || normalizedInput === "range_input" || normalizedInput === "set_range_input" ? "set_range_value" : normalizedInput === "deterministic_runtime" || normalizedInput === "mock_runtime" || normalizedInput === "mock_random" || normalizedInput === "mock_random_queue" || normalizedInput === "seed_random_queue" || normalizedInput === "set_random_queue" || normalizedInput === "mock_clock" || normalizedInput === "set_mock_clock" || normalizedInput === "set_runtime_determinism" || normalizedInput === "runtime_determinism" ? "deterministic_runtime" : normalizedInput === "canvas_hash" || normalizedInput === "capture_canvas_hash" || normalizedInput === "capture_canvas_signature" || normalizedInput === "canvas_state_signature" ? "canvas_signature" : normalizedInput === "capture_screenshot" || normalizedInput === "save_screenshot" || normalizedInput === "setup_screenshot" ? "screenshot" : normalizedInput === "accept_dialog" || normalizedInput === "accept_dialogs" || normalizedInput === "confirm_dialog" || normalizedInput === "set_dialog_response" ? "dialog_response" : normalizedInput === "dismiss_dialog" || normalizedInput === "dismiss_dialogs" || normalizedInput === "cancel_dialog" ? "dialog_response" : normalizedInput === "window_call_until" || normalizedInput === "call_until" || normalizedInput === "window_call_repeat_until" || normalizedInput === "repeat_window_call_until" ? "window_call_until" : normalizedInput === "window_evaluate" || normalizedInput === "browser_eval" || normalizedInput === "browser_evaluate" || normalizedInput === "evaluate_script" || normalizedInput === "profile_script" ? "window_eval" : normalizedInput;
1003
+ const normalized = normalizedInput === "clear_browser_storage" ? "clear_storage" : normalizedInput === "reset_console" || normalizedInput === "clear_browser_console" || normalizedInput === "reset_browser_console" ? "clear_console" : normalizedInput === "pointer_drag" || normalizedInput === "mouse_drag" || normalizedInput === "drag_to" ? "drag" : normalizedInput === "pointer_tap" || normalizedInput === "touch_tap" || normalizedInput === "canvas_tap" ? "tap" : normalizedInput === "tap_until" || normalizedInput === "pointer_tap_until" || normalizedInput === "touch_tap_until" || normalizedInput === "canvas_tap_until" || normalizedInput === "tap_repeat_until" || normalizedInput === "repeat_tap_until" ? "tap_until" : normalizedInput === "keyboard_press" || normalizedInput === "key_press" ? "press" : normalizedInput === "keyboard_down" || normalizedInput === "key_down" || normalizedInput === "keydown" || normalizedInput === "press_down" ? "key_down" : normalizedInput === "keyboard_up" || normalizedInput === "key_up" || normalizedInput === "keyup" || normalizedInput === "press_up" || normalizedInput === "release_key" || normalizedInput === "key_release" ? "key_up" : normalizedInput === "set_slider_value" || normalizedInput === "slider_value" || normalizedInput === "set_slider" || normalizedInput === "set_range" || normalizedInput === "range_value" || normalizedInput === "range_input" || normalizedInput === "set_range_input" ? "set_range_value" : normalizedInput === "deterministic_runtime" || normalizedInput === "mock_runtime" || normalizedInput === "mock_random" || normalizedInput === "mock_random_queue" || normalizedInput === "seed_random_queue" || normalizedInput === "set_random_queue" || normalizedInput === "mock_clock" || normalizedInput === "set_mock_clock" || normalizedInput === "set_runtime_determinism" || normalizedInput === "runtime_determinism" ? "deterministic_runtime" : normalizedInput === "canvas_hash" || normalizedInput === "capture_canvas_hash" || normalizedInput === "capture_canvas_signature" || normalizedInput === "canvas_state_signature" ? "canvas_signature" : normalizedInput === "capture_screenshot" || normalizedInput === "save_screenshot" || normalizedInput === "setup_screenshot" ? "screenshot" : normalizedInput === "accept_dialog" || normalizedInput === "accept_dialogs" || normalizedInput === "confirm_dialog" || normalizedInput === "set_dialog_response" ? "dialog_response" : normalizedInput === "dismiss_dialog" || normalizedInput === "dismiss_dialogs" || normalizedInput === "cancel_dialog" ? "dialog_response" : normalizedInput === "window_call_until" || normalizedInput === "call_until" || normalizedInput === "window_call_repeat_until" || normalizedInput === "repeat_window_call_until" ? "window_call_until" : normalizedInput === "window_evaluate" || normalizedInput === "browser_eval" || normalizedInput === "browser_evaluate" || normalizedInput === "evaluate_script" || normalizedInput === "profile_script" ? "window_eval" : normalizedInput;
974
1004
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
975
1005
  return normalized;
976
1006
  }
@@ -1052,8 +1082,8 @@ function normalizeSetupActionCoordinateMode(value, index) {
1052
1082
  }
1053
1083
  function normalizeSetupActionPointerType(value, type, index) {
1054
1084
  if (value === void 0 || value === null || value === "") return void 0;
1055
- if (type !== "drag" && type !== "tap") {
1056
- throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag/tap actions.`);
1085
+ if (type !== "drag" && type !== "tap" && type !== "tap_until") {
1086
+ throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag/tap/tap_until actions.`);
1057
1087
  }
1058
1088
  const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
1059
1089
  if (normalized === "mouse") return "mouse";
@@ -1132,11 +1162,11 @@ function normalizeSetupAction(input, index) {
1132
1162
  if (frameIndex !== void 0 && (!Number.isInteger(frameIndex) || frameIndex < 0)) {
1133
1163
  throw new Error(`target.setup_actions[${index}].frame_index must be a non-negative integer.`);
1134
1164
  }
1135
- if ((type === "click" || type === "tap" || type === "drag" || type === "fill" || type === "set_input_value" || type === "set_range_value" || type === "canvas_signature" || type === "wait_for_selector" || type === "wait_for_text" || type === "assert_text_visible" || type === "assert_text_absent" || type === "assert_selector_count") && !selector) {
1165
+ if ((type === "click" || type === "tap" || type === "tap_until" || type === "drag" || type === "fill" || type === "set_input_value" || type === "set_range_value" || type === "canvas_signature" || type === "wait_for_selector" || type === "wait_for_text" || type === "assert_text_visible" || type === "assert_text_absent" || type === "assert_selector_count") && !selector) {
1136
1166
  throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
1137
1167
  }
1138
- const fromX = type === "click" || type === "tap" ? numberValue(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
1139
- const fromY = type === "click" || type === "tap" ? numberValue(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
1168
+ const fromX = type === "click" || type === "tap" || type === "tap_until" ? numberValue(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
1169
+ const fromY = type === "click" || type === "tap" || type === "tap_until" ? numberValue(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
1140
1170
  const toX = numberValue(valueFromOwn(input, "to_x", "toX", "end_x", "endX", "x2"));
1141
1171
  const toY = numberValue(valueFromOwn(input, "to_y", "toY", "end_y", "endY", "y2"));
1142
1172
  const coordinateMode = normalizeSetupActionCoordinateMode(valueFromOwn(input, "coordinate_mode", "coordinateMode", "coords", "units"), index);
@@ -1161,18 +1191,18 @@ function normalizeSetupAction(input, index) {
1161
1191
  }
1162
1192
  }
1163
1193
  }
1164
- if (type === "tap") {
1194
+ if (type === "tap" || type === "tap_until") {
1165
1195
  const hasTapCoordinate = fromX !== void 0 || fromY !== void 0;
1166
1196
  if (hasTapCoordinate && (fromX === void 0 || fromY === void 0)) {
1167
- throw new Error(`target.setup_actions[${index}] tap coordinates require both x and y.`);
1197
+ throw new Error(`target.setup_actions[${index}] ${type} coordinates require both x and y.`);
1168
1198
  }
1169
1199
  if (hasTapCoordinate && fromX !== void 0 && fromY !== void 0) {
1170
1200
  const tapCoordinates = [fromX, fromY];
1171
1201
  if (coordinateMode === "ratio" && tapCoordinates.some((value2) => value2 < 0 || value2 > 1)) {
1172
- throw new Error(`target.setup_actions[${index}] tap ratio coordinates must be between 0 and 1.`);
1202
+ throw new Error(`target.setup_actions[${index}] ${type} ratio coordinates must be between 0 and 1.`);
1173
1203
  }
1174
1204
  if ((coordinateMode === void 0 || coordinateMode === "pixels") && tapCoordinates.some((value2) => value2 < 0)) {
1175
- throw new Error(`target.setup_actions[${index}] tap pixel coordinates must be non-negative.`);
1205
+ throw new Error(`target.setup_actions[${index}] ${type} pixel coordinates must be non-negative.`);
1176
1206
  }
1177
1207
  }
1178
1208
  }
@@ -1278,7 +1308,7 @@ function normalizeSetupAction(input, index) {
1278
1308
  const captureReturn = input.capture_return === false || input.captureReturn === false || input.include_return === false || input.includeReturn === false || input.omit_return === true || input.omitReturn === true ? false : void 0;
1279
1309
  const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
1280
1310
  const hasUntilExpectedValue = hasOwn(input, "until_expected_value") || hasOwn(input, "untilExpectedValue") || hasOwn(input, "until_expected") || hasOwn(input, "untilExpected") || hasOwn(input, "until_value") || hasOwn(input, "untilValue") || hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected");
1281
- if (type === "window_call_until") {
1311
+ if (type === "window_call_until" || type === "tap_until") {
1282
1312
  if (!untilPath) {
1283
1313
  throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
1284
1314
  }
@@ -1286,12 +1316,12 @@ function normalizeSetupAction(input, index) {
1286
1316
  throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
1287
1317
  }
1288
1318
  }
1289
- const maxCalls = numberValue(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
1290
- if (type === "window_call_until" && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
1319
+ const maxCalls = numberValue(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts", "max_taps", "maxTaps", "tap_limit", "tapLimit"));
1320
+ if ((type === "window_call_until" || type === "tap_until") && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
1291
1321
  throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
1292
1322
  }
1293
1323
  const intervalMs = numberValue(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
1294
- if (type === "window_call_until" && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
1324
+ if ((type === "window_call_until" || type === "tap_until") && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
1295
1325
  throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
1296
1326
  }
1297
1327
  const steps = numberValue(input.steps);
@@ -4557,6 +4587,30 @@ function profileSetupTapReceipts(results) {
4557
4587
  reason: result.reason || result.error || null,
4558
4588
  }));
4559
4589
  }
4590
+ function profileSetupTapUntilReceipts(results) {
4591
+ return (results || [])
4592
+ .filter((result) => result && profileSetupResultAction(result) === "tap_until")
4593
+ .map((result) => ({
4594
+ ordinal: result.ordinal ?? null,
4595
+ ok: result.ok !== false,
4596
+ selector: result.selector ?? null,
4597
+ frame_selector: result.frame_selector ?? null,
4598
+ pointer_type: result.pointer_type ?? null,
4599
+ input_dispatch: result.input_dispatch ?? null,
4600
+ coordinate_mode: result.coordinate_mode ?? null,
4601
+ x: result.x ?? null,
4602
+ y: result.y ?? null,
4603
+ duration_ms: result.duration_ms ?? null,
4604
+ until_path: result.until_path ?? null,
4605
+ until_value: result.until_value ?? null,
4606
+ until_expected_value: result.until_expected_value ?? null,
4607
+ tap_count: result.tap_count ?? null,
4608
+ max_taps: result.max_taps ?? result.max_calls ?? null,
4609
+ interval_ms: result.interval_ms ?? null,
4610
+ timeout_ms: result.timeout_ms ?? null,
4611
+ reason: result.reason || result.error || null,
4612
+ }));
4613
+ }
4560
4614
  function profileSetupKeyboardReceipts(results) {
4561
4615
  return (results || [])
4562
4616
  .filter((result) => result && ["press", "key_down", "key_up"].includes(profileSetupResultAction(result)))
@@ -4759,6 +4813,11 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
4759
4813
  const sampledDragReceipts = sampleProfileSetupSummaryItems(dragReceipts, 8);
4760
4814
  const tapReceipts = profileSetupTapReceipts(results);
4761
4815
  const sampledTapReceipts = sampleProfileSetupSummaryItems(tapReceipts, 8);
4816
+ const tapUntilReceipts = profileSetupTapUntilReceipts(results);
4817
+ const tapUntilTapCounts = tapUntilReceipts
4818
+ .map((result) => typeof result.tap_count === "number" && Number.isFinite(result.tap_count) ? result.tap_count : undefined)
4819
+ .filter((value) => value !== undefined);
4820
+ const sampledTapUntilReceipts = sampleProfileSetupSummaryItems(tapUntilReceipts, 8);
4762
4821
  const keyboardReceipts = profileSetupKeyboardReceipts(results);
4763
4822
  const sampledKeyboardReceipts = sampleProfileSetupSummaryItems(keyboardReceipts, 8);
4764
4823
  const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
@@ -4841,6 +4900,10 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
4841
4900
  tap_total: tapReceipts.length,
4842
4901
  tap_truncated: tapReceipts.length > sampledTapReceipts.length,
4843
4902
  tap: sampledTapReceipts,
4903
+ tap_until_total: tapUntilReceipts.length,
4904
+ tap_until_tap_total: tapUntilTapCounts.reduce((sum, value) => sum + value, 0),
4905
+ tap_until_truncated: tapUntilReceipts.length > sampledTapUntilReceipts.length,
4906
+ tap_until: sampledTapUntilReceipts,
4844
4907
  keyboard_total: keyboardReceipts.length,
4845
4908
  keyboard_truncated: keyboardReceipts.length > sampledKeyboardReceipts.length,
4846
4909
  keyboard: sampledKeyboardReceipts,
@@ -5787,6 +5850,108 @@ async function waitForAnyVisibleSelector(context, selector, timeout) {
5787
5850
  }
5788
5851
  throw new Error("No visible match for selector " + selector + ": " + lastReason);
5789
5852
  }
5853
+ async function dispatchSetupTapPoint(point, pointerType, durationMs) {
5854
+ if (pointerType === "touch" || pointerType === "pen") {
5855
+ const client = await page.context().newCDPSession(page);
5856
+ try {
5857
+ if (pointerType === "touch") {
5858
+ const touchPoint = {
5859
+ x: point.x,
5860
+ y: point.y,
5861
+ radiusX: 1,
5862
+ radiusY: 1,
5863
+ force: 1,
5864
+ id: 11,
5865
+ };
5866
+ await client.send("Input.dispatchTouchEvent", {
5867
+ type: "touchStart",
5868
+ touchPoints: [touchPoint],
5869
+ });
5870
+ if (durationMs) await page.waitForTimeout(durationMs);
5871
+ await client.send("Input.dispatchTouchEvent", {
5872
+ type: "touchEnd",
5873
+ touchPoints: [],
5874
+ });
5875
+ } else {
5876
+ await client.send("Input.dispatchMouseEvent", {
5877
+ type: "mousePressed",
5878
+ x: point.x,
5879
+ y: point.y,
5880
+ button: "left",
5881
+ buttons: 1,
5882
+ clickCount: 1,
5883
+ pointerType: "pen",
5884
+ });
5885
+ if (durationMs) await page.waitForTimeout(durationMs);
5886
+ await client.send("Input.dispatchMouseEvent", {
5887
+ type: "mouseReleased",
5888
+ x: point.x,
5889
+ y: point.y,
5890
+ button: "left",
5891
+ buttons: 0,
5892
+ clickCount: 1,
5893
+ pointerType: "pen",
5894
+ });
5895
+ }
5896
+ } finally {
5897
+ await client.detach().catch(() => {});
5898
+ }
5899
+ } else {
5900
+ await page.mouse.click(point.x, point.y);
5901
+ }
5902
+ }
5903
+ async function resolveSetupTapTarget(action, base, scope, timeout) {
5904
+ const locator = scope.context.locator(action.selector);
5905
+ const count = await locator.count();
5906
+ if (!count) return { result: { ...base, ...setupScopeEvidence(scope), reason: "selector_not_found", count } };
5907
+ const targetIndex = Number.isInteger(action.index) ? action.index : 0;
5908
+ if (targetIndex < 0 || targetIndex >= count) return { result: { ...base, ...setupScopeEvidence(scope), reason: "index_out_of_range", count, target_index: targetIndex } };
5909
+ const target = locator.nth(targetIndex);
5910
+ await target.waitFor({ state: "visible", timeout });
5911
+ const box = await target.boundingBox();
5912
+ if (!box) return { result: { ...base, ...setupScopeEvidence(scope), reason: "bounding_box_unavailable", count, target_index: targetIndex } };
5913
+ const fromX = setupFiniteNumber(action.from_x ?? action.fromX ?? action.x ?? action.click_x ?? action.clickX);
5914
+ const fromY = setupFiniteNumber(action.from_y ?? action.fromY ?? action.y ?? action.click_y ?? action.clickY);
5915
+ const hasTapPosition = fromX !== undefined || fromY !== undefined;
5916
+ if (hasTapPosition && (fromX === undefined || fromY === undefined)) return { result: { ...base, ...setupScopeEvidence(scope), reason: "missing_tap_coordinates", count, target_index: targetIndex } };
5917
+ const mode = String(action.coordinate_mode || action.coordinateMode || (hasTapPosition ? "pixels" : "ratio")).trim();
5918
+ if (hasTapPosition && mode === "ratio" && [fromX, fromY].some((value) => value < 0 || value > 1)) return { result: { ...base, ...setupScopeEvidence(scope), reason: "invalid_ratio_coordinates", count, target_index: targetIndex } };
5919
+ if (hasTapPosition && mode !== "ratio" && [fromX, fromY].some((value) => value < 0)) return { result: { ...base, ...setupScopeEvidence(scope), reason: "invalid_pixel_coordinates", count, target_index: targetIndex } };
5920
+ const coordinate = (value, size) => mode === "ratio" ? value * size : value;
5921
+ const localX = hasTapPosition && fromX !== undefined ? fromX : 0.5;
5922
+ const localY = hasTapPosition && fromY !== undefined ? fromY : 0.5;
5923
+ const point = {
5924
+ x: box.x + coordinate(localX, box.width),
5925
+ y: box.y + coordinate(localY, box.height),
5926
+ };
5927
+ const durationMs = setupNumber(action.duration_ms ?? action.durationMs, 0);
5928
+ const pointerType = String(action.pointer_type || action.pointerType || "touch").trim().toLowerCase();
5929
+ return {
5930
+ target: {
5931
+ count,
5932
+ targetIndex,
5933
+ point,
5934
+ mode,
5935
+ fromX,
5936
+ fromY,
5937
+ hasTapPosition,
5938
+ pointerType,
5939
+ durationMs,
5940
+ },
5941
+ };
5942
+ }
5943
+ function setupTapTargetEvidence(tapTarget) {
5944
+ return {
5945
+ count: tapTarget.count,
5946
+ target_index: tapTarget.targetIndex,
5947
+ coordinate_mode: tapTarget.hasTapPosition ? tapTarget.mode : undefined,
5948
+ x: tapTarget.hasTapPosition ? tapTarget.fromX : undefined,
5949
+ y: tapTarget.hasTapPosition ? tapTarget.fromY : undefined,
5950
+ pointer_type: tapTarget.pointerType,
5951
+ input_dispatch: tapTarget.pointerType === "touch" || tapTarget.pointerType === "pen" ? "cdp" : "playwright_mouse",
5952
+ duration_ms: tapTarget.durationMs || undefined,
5953
+ };
5954
+ }
5790
5955
  function setupHasOwn(action, key) {
5791
5956
  return Boolean(action) && Object.keys(action).includes(key);
5792
5957
  }
@@ -6389,91 +6554,108 @@ async function executeSetupAction(action, ordinal, viewport) {
6389
6554
  if (type === "tap") {
6390
6555
  const scope = await setupActionScope(action, timeout);
6391
6556
  if (!scope.ok) return setupScopeFailure(base, scope);
6392
- const locator = scope.context.locator(action.selector);
6393
- const count = await locator.count();
6394
- if (!count) return { ...base, ...setupScopeEvidence(scope), reason: "selector_not_found", count };
6395
- const targetIndex = Number.isInteger(action.index) ? action.index : 0;
6396
- if (targetIndex < 0 || targetIndex >= count) return { ...base, ...setupScopeEvidence(scope), reason: "index_out_of_range", count, target_index: targetIndex };
6397
- const target = locator.nth(targetIndex);
6398
- await target.waitFor({ state: "visible", timeout });
6399
- const box = await target.boundingBox();
6400
- if (!box) return { ...base, ...setupScopeEvidence(scope), reason: "bounding_box_unavailable", count, target_index: targetIndex };
6401
- const fromX = setupFiniteNumber(action.from_x ?? action.fromX ?? action.x ?? action.click_x ?? action.clickX);
6402
- const fromY = setupFiniteNumber(action.from_y ?? action.fromY ?? action.y ?? action.click_y ?? action.clickY);
6403
- const hasTapPosition = fromX !== undefined || fromY !== undefined;
6404
- if (hasTapPosition && (fromX === undefined || fromY === undefined)) return { ...base, ...setupScopeEvidence(scope), reason: "missing_tap_coordinates", count, target_index: targetIndex };
6405
- const mode = String(action.coordinate_mode || action.coordinateMode || (hasTapPosition ? "pixels" : "ratio")).trim();
6406
- if (hasTapPosition && mode === "ratio" && [fromX, fromY].some((value) => value < 0 || value > 1)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_ratio_coordinates", count, target_index: targetIndex };
6407
- if (hasTapPosition && mode !== "ratio" && [fromX, fromY].some((value) => value < 0)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_pixel_coordinates", count, target_index: targetIndex };
6408
- const coordinate = (value, size) => mode === "ratio" ? value * size : value;
6409
- const localX = hasTapPosition && fromX !== undefined ? fromX : 0.5;
6410
- const localY = hasTapPosition && fromY !== undefined ? fromY : 0.5;
6411
- const point = {
6412
- x: box.x + coordinate(localX, box.width),
6413
- y: box.y + coordinate(localY, box.height),
6557
+ const prepared = await resolveSetupTapTarget(action, base, scope, timeout);
6558
+ if (prepared.result) return prepared.result;
6559
+ await dispatchSetupTapPoint(prepared.target.point, prepared.target.pointerType, prepared.target.durationMs);
6560
+ return {
6561
+ ...base,
6562
+ ...setupScopeEvidence(scope),
6563
+ ok: true,
6564
+ ...setupTapTargetEvidence(prepared.target),
6414
6565
  };
6415
- const durationMs = setupNumber(action.duration_ms ?? action.durationMs, 0);
6416
- const pointerType = String(action.pointer_type || action.pointerType || "touch").trim().toLowerCase();
6417
- if (pointerType === "touch" || pointerType === "pen") {
6418
- const client = await page.context().newCDPSession(page);
6419
- try {
6420
- if (pointerType === "touch") {
6421
- const touchPoint = {
6422
- x: point.x,
6423
- y: point.y,
6424
- radiusX: 1,
6425
- radiusY: 1,
6426
- force: 1,
6427
- id: 11,
6428
- };
6429
- await client.send("Input.dispatchTouchEvent", {
6430
- type: "touchStart",
6431
- touchPoints: [touchPoint],
6432
- });
6433
- if (durationMs) await page.waitForTimeout(durationMs);
6434
- await client.send("Input.dispatchTouchEvent", {
6435
- type: "touchEnd",
6436
- touchPoints: [],
6437
- });
6438
- } else {
6439
- await client.send("Input.dispatchMouseEvent", {
6440
- type: "mousePressed",
6441
- x: point.x,
6442
- y: point.y,
6443
- button: "left",
6444
- buttons: 1,
6445
- clickCount: 1,
6446
- pointerType: "pen",
6447
- });
6448
- if (durationMs) await page.waitForTimeout(durationMs);
6449
- await client.send("Input.dispatchMouseEvent", {
6450
- type: "mouseReleased",
6451
- x: point.x,
6452
- y: point.y,
6453
- button: "left",
6454
- buttons: 0,
6455
- clickCount: 1,
6456
- pointerType: "pen",
6457
- });
6458
- }
6459
- } finally {
6460
- await client.detach().catch(() => {});
6566
+ }
6567
+ if (type === "tap_until") {
6568
+ const untilPath = String(action.until_path || action.untilPath || action.until_state_path || action.untilStatePath || action.until_window_path || action.untilWindowPath || action.until || "");
6569
+ const hasUntilExpected = setupHasOwn(action, "until_expected_value")
6570
+ || setupHasOwn(action, "untilExpectedValue")
6571
+ || setupHasOwn(action, "until_expected")
6572
+ || setupHasOwn(action, "untilExpected")
6573
+ || setupHasOwn(action, "until_value")
6574
+ || setupHasOwn(action, "untilValue")
6575
+ || setupHasOwn(action, "expected_value")
6576
+ || setupHasOwn(action, "expectedValue")
6577
+ || setupHasOwn(action, "expected");
6578
+ const untilExpected = setupHasOwn(action, "until_expected_value")
6579
+ ? action.until_expected_value
6580
+ : setupHasOwn(action, "untilExpectedValue")
6581
+ ? action.untilExpectedValue
6582
+ : setupHasOwn(action, "until_expected")
6583
+ ? action.until_expected
6584
+ : setupHasOwn(action, "untilExpected")
6585
+ ? action.untilExpected
6586
+ : setupHasOwn(action, "until_value")
6587
+ ? action.until_value
6588
+ : setupHasOwn(action, "untilValue")
6589
+ ? action.untilValue
6590
+ : setupHasOwn(action, "expected_value")
6591
+ ? action.expected_value
6592
+ : setupHasOwn(action, "expectedValue")
6593
+ ? action.expectedValue
6594
+ : action.expected;
6595
+ if (!untilPath) return { ...base, reason: "missing_until_path" };
6596
+ if (!hasUntilExpected) return { ...base, until_path: untilPath, reason: "missing_until_expected_value" };
6597
+ const maxTaps = Math.min(100, Math.max(1, Math.floor(setupNumber(action.max_taps ?? action.maxTaps ?? action.tap_limit ?? action.tapLimit ?? action.max_calls ?? action.maxCalls ?? action.max_attempts ?? action.maxAttempts ?? action.attempts, 1) || 1)));
6598
+ const intervalMs = Math.min(5000, Math.max(0, Math.floor(setupNumber(action.interval_ms ?? action.intervalMs ?? action.poll_ms ?? action.pollMs ?? action.tap_interval_ms ?? action.tapIntervalMs, 100) || 0)));
6599
+ const scope = await setupActionScope(action, timeout);
6600
+ if (!scope.ok) return setupScopeFailure(base, scope);
6601
+ const prepared = await resolveSetupTapTarget(action, base, scope, timeout);
6602
+ if (prepared.result) return prepared.result;
6603
+ const startedAt = Date.now();
6604
+ let tapCount = 0;
6605
+ let lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
6606
+ const targetEvidence = setupTapTargetEvidence(prepared.target);
6607
+ if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
6608
+ return {
6609
+ ...base,
6610
+ ...setupScopeEvidence(scope),
6611
+ ok: true,
6612
+ ...targetEvidence,
6613
+ until_path: untilPath,
6614
+ until_value: setupJsonValue(lastPredicateResult.value),
6615
+ until_expected_value: setupJsonValue(untilExpected),
6616
+ tap_count: tapCount,
6617
+ max_taps: maxTaps,
6618
+ max_calls: maxTaps,
6619
+ interval_ms: intervalMs,
6620
+ timeout_ms: timeout,
6621
+ };
6622
+ }
6623
+ while (tapCount < maxTaps && Date.now() - startedAt <= timeout) {
6624
+ await dispatchSetupTapPoint(prepared.target.point, prepared.target.pointerType, prepared.target.durationMs);
6625
+ tapCount += 1;
6626
+ lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
6627
+ if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
6628
+ return {
6629
+ ...base,
6630
+ ...setupScopeEvidence(scope),
6631
+ ok: true,
6632
+ ...targetEvidence,
6633
+ until_path: untilPath,
6634
+ until_value: setupJsonValue(lastPredicateResult.value),
6635
+ until_expected_value: setupJsonValue(untilExpected),
6636
+ tap_count: tapCount,
6637
+ max_taps: maxTaps,
6638
+ max_calls: maxTaps,
6639
+ interval_ms: intervalMs,
6640
+ timeout_ms: timeout,
6641
+ };
6461
6642
  }
6462
- } else {
6463
- await page.mouse.click(point.x, point.y);
6643
+ if (tapCount < maxTaps && intervalMs) await page.waitForTimeout(intervalMs);
6464
6644
  }
6465
6645
  return {
6466
6646
  ...base,
6467
6647
  ...setupScopeEvidence(scope),
6468
- ok: true,
6469
- count,
6470
- target_index: targetIndex,
6471
- coordinate_mode: hasTapPosition ? mode : undefined,
6472
- x: hasTapPosition ? fromX : undefined,
6473
- y: hasTapPosition ? fromY : undefined,
6474
- pointer_type: pointerType,
6475
- input_dispatch: pointerType === "touch" || pointerType === "pen" ? "cdp" : "playwright_mouse",
6476
- duration_ms: durationMs || undefined,
6648
+ ...targetEvidence,
6649
+ until_path: untilPath,
6650
+ until_value: setupJsonValue(lastPredicateResult?.value),
6651
+ until_expected_value: setupJsonValue(untilExpected),
6652
+ tap_count: tapCount,
6653
+ max_taps: maxTaps,
6654
+ max_calls: maxTaps,
6655
+ interval_ms: intervalMs,
6656
+ timeout_ms: timeout,
6657
+ reason: Date.now() - startedAt > timeout ? "timeout" : "until_condition_not_met",
6658
+ missing_part: lastPredicateResult?.missing_part || undefined,
6477
6659
  };
6478
6660
  }
6479
6661
  if (type === "drag") {
@@ -5,7 +5,7 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
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
7
  declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "selector_text_visible", "selector_text_absent", "selector_text_order", "observe_within", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
8
- declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "tap", "drag", "press", "key_down", "key_up", "fill", "set_input_value", "set_range_value", "deterministic_runtime", "canvas_signature", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_eval", "window_call", "window_call_until"];
8
+ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "tap", "tap_until", "drag", "press", "key_down", "key_up", "fill", "set_input_value", "set_range_value", "deterministic_runtime", "canvas_signature", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_eval", "window_call", "window_call_until"];
9
9
  type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
10
10
  type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
11
11
  type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
package/dist/profile.d.ts CHANGED
@@ -5,7 +5,7 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
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
7
  declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "selector_text_visible", "selector_text_absent", "selector_text_order", "observe_within", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
8
- declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "tap", "drag", "press", "key_down", "key_up", "fill", "set_input_value", "set_range_value", "deterministic_runtime", "canvas_signature", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_eval", "window_call", "window_call_until"];
8
+ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "tap", "tap_until", "drag", "press", "key_down", "key_up", "fill", "set_input_value", "set_range_value", "deterministic_runtime", "canvas_signature", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_eval", "window_call", "window_call_until"];
9
9
  type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
10
10
  type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
11
11
  type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
package/dist/profile.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  resolveRiddleProofProfileTimeoutSec,
24
24
  slugifyRiddleProofProfileName,
25
25
  summarizeRiddleProofProfileResult
26
- } from "./chunk-EYLIXKE2.js";
26
+ } from "./chunk-DL6UB4N6.js";
27
27
  export {
28
28
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
29
29
  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.197",
3
+ "version": "0.7.198",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",