@riddledc/riddle-proof 0.7.172 → 0.7.174
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 +7 -1
- package/dist/{chunk-5ELOMJ7U.js → chunk-BD4RHTGW.js} +179 -39
- package/dist/cli.cjs +206 -40
- package/dist/cli.js +28 -2
- package/dist/index.cjs +179 -39
- package/dist/index.js +1 -1
- package/dist/profile.cjs +179 -39
- package/dist/profile.d.cts +1 -1
- package/dist/profile.d.ts +1 -1
- package/dist/profile.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -397,7 +397,7 @@ when body matching overrides sequence order.
|
|
|
397
397
|
`target.setup_actions` is optional. Use it when the meaningful proof surface
|
|
398
398
|
appears only after a picker, tab, login stub, storage seed, form fill,
|
|
399
399
|
transport control, or other bounded interaction. Supported setup actions are
|
|
400
|
-
`click`, `drag`, `press`, `fill`, `set_input_value`, `set_range_value`,
|
|
400
|
+
`click`, `tap`, `drag`, `press`, `fill`, `set_input_value`, `set_range_value`,
|
|
401
401
|
`deterministic_runtime`, `canvas_signature`, `assert_text_visible`, `assert_text_absent`,
|
|
402
402
|
`assert_selector_count`, `assert_window_value`, `assert_window_number`,
|
|
403
403
|
`local_storage`, `session_storage`, `clear_storage`, `clear_console`,
|
|
@@ -416,6 +416,12 @@ Use `click_count` / `clickCount` / `clicks` from 1 to 10 on a single `click`
|
|
|
416
416
|
action for atomic double-click or double-submit contracts where modeling the
|
|
417
417
|
interaction as repeated setup actions would incorrectly require the target to
|
|
418
418
|
remain in the DOM after the first click.
|
|
419
|
+
Use `tap` for touch-first controls, especially canvas regions where a mobile
|
|
420
|
+
tap should produce trusted touch events and the browser's synthesized click.
|
|
421
|
+
It requires `selector`, defaults to a touch tap at the target center, and
|
|
422
|
+
accepts `x` / `y` or `from_x` / `from_y` plus `coordinate_mode: "ratio"` for
|
|
423
|
+
element-relative coordinates. Set `pointer_type` to `mouse`, `touch`, or `pen`
|
|
424
|
+
when the proof must distinguish input modality.
|
|
419
425
|
Use `set_range_value` for HTML range inputs and React-controlled sliders. It
|
|
420
426
|
accepts aliases such as `set-slider-value`, requires `selector` plus `value`,
|
|
421
427
|
uses the native input value setter, dispatches bubbling `input` and `change`
|
|
@@ -44,6 +44,7 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
44
44
|
];
|
|
45
45
|
var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
46
46
|
"click",
|
|
47
|
+
"tap",
|
|
47
48
|
"drag",
|
|
48
49
|
"press",
|
|
49
50
|
"fill",
|
|
@@ -595,6 +596,21 @@ function profileSetupDragReceipts(results) {
|
|
|
595
596
|
reason: result.reason ?? result.error ?? null
|
|
596
597
|
}));
|
|
597
598
|
}
|
|
599
|
+
function profileSetupTapReceipts(results) {
|
|
600
|
+
return results.filter((result) => profileSetupResultAction(result) === "tap").map((result) => ({
|
|
601
|
+
ordinal: result.ordinal ?? null,
|
|
602
|
+
ok: result.ok !== false,
|
|
603
|
+
selector: result.selector ?? null,
|
|
604
|
+
frame_selector: result.frame_selector ?? null,
|
|
605
|
+
pointer_type: result.pointer_type ?? null,
|
|
606
|
+
input_dispatch: result.input_dispatch ?? null,
|
|
607
|
+
coordinate_mode: result.coordinate_mode ?? null,
|
|
608
|
+
x: result.x ?? null,
|
|
609
|
+
y: result.y ?? null,
|
|
610
|
+
duration_ms: result.duration_ms ?? null,
|
|
611
|
+
reason: result.reason ?? result.error ?? null
|
|
612
|
+
}));
|
|
613
|
+
}
|
|
598
614
|
function profileSetupCanvasSignatureReceipts(results) {
|
|
599
615
|
return results.filter((result) => profileSetupResultAction(result) === "canvas_signature").map((result) => ({
|
|
600
616
|
ordinal: result.ordinal ?? null,
|
|
@@ -632,21 +648,28 @@ function profileSetupCanvasSignatureStableHashGroups(results) {
|
|
|
632
648
|
}
|
|
633
649
|
const warnings = [];
|
|
634
650
|
for (const group of groups.values()) {
|
|
635
|
-
const
|
|
636
|
-
const
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
651
|
+
const receiptsByHash = /* @__PURE__ */ new Map();
|
|
652
|
+
for (const receipt of group.receipts) {
|
|
653
|
+
const hashReceipts = receiptsByHash.get(receipt.hash) || [];
|
|
654
|
+
hashReceipts.push(receipt);
|
|
655
|
+
receiptsByHash.set(receipt.hash, hashReceipts);
|
|
656
|
+
}
|
|
657
|
+
for (const [hash, receipts] of receiptsByHash.entries()) {
|
|
658
|
+
const labels = [...new Set(receipts.map((receipt) => receipt.label))];
|
|
659
|
+
if (receipts.length < 2 || labels.length < 2) continue;
|
|
660
|
+
const visibleLabels = labels.slice(0, 8);
|
|
661
|
+
warnings.push({
|
|
662
|
+
selector: group.selector,
|
|
663
|
+
frame_selector: group.frame_selector ?? null,
|
|
664
|
+
hash,
|
|
665
|
+
count: receipts.length,
|
|
666
|
+
label_count: labels.length,
|
|
667
|
+
labels: visibleLabels,
|
|
668
|
+
omitted_label_count: Math.max(0, labels.length - visibleLabels.length),
|
|
669
|
+
ordinals: receipts.map((receipt) => receipt.ordinal).filter((value) => value !== void 0).slice(0, 12),
|
|
670
|
+
reason: "stable_canvas_signature_hash"
|
|
671
|
+
});
|
|
672
|
+
}
|
|
650
673
|
}
|
|
651
674
|
return warnings;
|
|
652
675
|
}
|
|
@@ -749,6 +772,8 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
|
|
|
749
772
|
const sampledRangeValueReceipts = sampleProfileSetupSummaryItems(rangeValueReceipts, 8);
|
|
750
773
|
const dragReceipts = profileSetupDragReceipts(results);
|
|
751
774
|
const sampledDragReceipts = sampleProfileSetupSummaryItems(dragReceipts, 8);
|
|
775
|
+
const tapReceipts = profileSetupTapReceipts(results);
|
|
776
|
+
const sampledTapReceipts = sampleProfileSetupSummaryItems(tapReceipts, 8);
|
|
752
777
|
const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
|
|
753
778
|
const sampledCanvasSignatureReceipts = sampleProfileSetupSummaryItems(canvasSignatureReceipts, 8);
|
|
754
779
|
const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => {
|
|
@@ -813,6 +838,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
|
|
|
813
838
|
drag_total: dragReceipts.length,
|
|
814
839
|
drag_truncated: dragReceipts.length > sampledDragReceipts.length,
|
|
815
840
|
drag: sampledDragReceipts,
|
|
841
|
+
tap_total: tapReceipts.length,
|
|
842
|
+
tap_truncated: tapReceipts.length > sampledTapReceipts.length,
|
|
843
|
+
tap: sampledTapReceipts,
|
|
816
844
|
canvas_signature_total: canvasSignatureReceipts.length,
|
|
817
845
|
canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
|
|
818
846
|
canvas_signature: sampledCanvasSignatureReceipts,
|
|
@@ -869,7 +897,7 @@ function isSupportedCheckType(value) {
|
|
|
869
897
|
}
|
|
870
898
|
function normalizeSetupActionType(value, index) {
|
|
871
899
|
const normalizedInput = String(value || "").trim().replace(/-/g, "_");
|
|
872
|
-
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 === "keyboard_press" || normalizedInput === "key_press" ? "press" : 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;
|
|
900
|
+
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 === "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;
|
|
873
901
|
if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
|
|
874
902
|
return normalized;
|
|
875
903
|
}
|
|
@@ -951,8 +979,8 @@ function normalizeSetupActionCoordinateMode(value, index) {
|
|
|
951
979
|
}
|
|
952
980
|
function normalizeSetupActionPointerType(value, type, index) {
|
|
953
981
|
if (value === void 0 || value === null || value === "") return void 0;
|
|
954
|
-
if (type !== "drag") {
|
|
955
|
-
throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag actions.`);
|
|
982
|
+
if (type !== "drag" && type !== "tap") {
|
|
983
|
+
throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag/tap actions.`);
|
|
956
984
|
}
|
|
957
985
|
const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
|
|
958
986
|
if (normalized === "mouse") return "mouse";
|
|
@@ -1031,11 +1059,11 @@ function normalizeSetupAction(input, index) {
|
|
|
1031
1059
|
if (frameIndex !== void 0 && (!Number.isInteger(frameIndex) || frameIndex < 0)) {
|
|
1032
1060
|
throw new Error(`target.setup_actions[${index}].frame_index must be a non-negative integer.`);
|
|
1033
1061
|
}
|
|
1034
|
-
if ((type === "click" || 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) {
|
|
1062
|
+
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) {
|
|
1035
1063
|
throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
|
|
1036
1064
|
}
|
|
1037
|
-
const fromX = type === "click" ? numberValue(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
|
|
1038
|
-
const fromY = type === "click" ? numberValue(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
|
|
1065
|
+
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"));
|
|
1066
|
+
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"));
|
|
1039
1067
|
const toX = numberValue(valueFromOwn(input, "to_x", "toX", "end_x", "endX", "x2"));
|
|
1040
1068
|
const toY = numberValue(valueFromOwn(input, "to_y", "toY", "end_y", "endY", "y2"));
|
|
1041
1069
|
const coordinateMode = normalizeSetupActionCoordinateMode(valueFromOwn(input, "coordinate_mode", "coordinateMode", "coords", "units"), index);
|
|
@@ -1055,6 +1083,21 @@ function normalizeSetupAction(input, index) {
|
|
|
1055
1083
|
}
|
|
1056
1084
|
}
|
|
1057
1085
|
}
|
|
1086
|
+
if (type === "tap") {
|
|
1087
|
+
const hasTapCoordinate = fromX !== void 0 || fromY !== void 0;
|
|
1088
|
+
if (hasTapCoordinate && (fromX === void 0 || fromY === void 0)) {
|
|
1089
|
+
throw new Error(`target.setup_actions[${index}] tap coordinates require both x and y.`);
|
|
1090
|
+
}
|
|
1091
|
+
if (hasTapCoordinate && fromX !== void 0 && fromY !== void 0) {
|
|
1092
|
+
const tapCoordinates = [fromX, fromY];
|
|
1093
|
+
if (coordinateMode === "ratio" && tapCoordinates.some((value2) => value2 < 0 || value2 > 1)) {
|
|
1094
|
+
throw new Error(`target.setup_actions[${index}] tap ratio coordinates must be between 0 and 1.`);
|
|
1095
|
+
}
|
|
1096
|
+
if ((coordinateMode === void 0 || coordinateMode === "pixels") && tapCoordinates.some((value2) => value2 < 0)) {
|
|
1097
|
+
throw new Error(`target.setup_actions[${index}] tap pixel coordinates must be non-negative.`);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1058
1101
|
if (type === "drag") {
|
|
1059
1102
|
if (fromX === void 0 || fromY === void 0 || toX === void 0 || toY === void 0) {
|
|
1060
1103
|
throw new Error(`target.setup_actions[${index}] drag requires from_x, from_y, to_x, and to_y.`);
|
|
@@ -4409,24 +4452,31 @@ function profileSetupCanvasSignatureStableHashGroups(results) {
|
|
|
4409
4452
|
}
|
|
4410
4453
|
const warnings = [];
|
|
4411
4454
|
for (const group of groups.values()) {
|
|
4412
|
-
const
|
|
4413
|
-
const
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
.
|
|
4427
|
-
.
|
|
4428
|
-
|
|
4429
|
-
|
|
4455
|
+
const receiptsByHash = new Map();
|
|
4456
|
+
for (const receipt of group.receipts) {
|
|
4457
|
+
const hashReceipts = receiptsByHash.get(receipt.hash) || [];
|
|
4458
|
+
hashReceipts.push(receipt);
|
|
4459
|
+
receiptsByHash.set(receipt.hash, hashReceipts);
|
|
4460
|
+
}
|
|
4461
|
+
for (const [hash, receipts] of receiptsByHash.entries()) {
|
|
4462
|
+
const labels = [...new Set(receipts.map((receipt) => receipt.label))];
|
|
4463
|
+
if (receipts.length < 2 || labels.length < 2) continue;
|
|
4464
|
+
const visibleLabels = labels.slice(0, 8);
|
|
4465
|
+
warnings.push({
|
|
4466
|
+
selector: group.selector,
|
|
4467
|
+
frame_selector: group.frame_selector || null,
|
|
4468
|
+
hash,
|
|
4469
|
+
count: receipts.length,
|
|
4470
|
+
label_count: labels.length,
|
|
4471
|
+
labels: visibleLabels,
|
|
4472
|
+
omitted_label_count: Math.max(0, labels.length - visibleLabels.length),
|
|
4473
|
+
ordinals: receipts
|
|
4474
|
+
.map((receipt) => receipt.ordinal)
|
|
4475
|
+
.filter((value) => value !== undefined)
|
|
4476
|
+
.slice(0, 12),
|
|
4477
|
+
reason: "stable_canvas_signature_hash",
|
|
4478
|
+
});
|
|
4479
|
+
}
|
|
4430
4480
|
}
|
|
4431
4481
|
return warnings;
|
|
4432
4482
|
}
|
|
@@ -6043,6 +6093,96 @@ async function executeSetupAction(action, ordinal, viewport) {
|
|
|
6043
6093
|
await waitForAnyVisibleSelector(scope.context, action.selector, timeout);
|
|
6044
6094
|
return { ...base, ...setupScopeEvidence(scope), ok: true, timeout_ms: timeout };
|
|
6045
6095
|
}
|
|
6096
|
+
if (type === "tap") {
|
|
6097
|
+
const scope = await setupActionScope(action, timeout);
|
|
6098
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
6099
|
+
const locator = scope.context.locator(action.selector);
|
|
6100
|
+
const count = await locator.count();
|
|
6101
|
+
if (!count) return { ...base, ...setupScopeEvidence(scope), reason: "selector_not_found", count };
|
|
6102
|
+
const targetIndex = Number.isInteger(action.index) ? action.index : 0;
|
|
6103
|
+
if (targetIndex < 0 || targetIndex >= count) return { ...base, ...setupScopeEvidence(scope), reason: "index_out_of_range", count, target_index: targetIndex };
|
|
6104
|
+
const target = locator.nth(targetIndex);
|
|
6105
|
+
await target.waitFor({ state: "visible", timeout });
|
|
6106
|
+
const box = await target.boundingBox();
|
|
6107
|
+
if (!box) return { ...base, ...setupScopeEvidence(scope), reason: "bounding_box_unavailable", count, target_index: targetIndex };
|
|
6108
|
+
const fromX = setupFiniteNumber(action.from_x ?? action.fromX ?? action.x ?? action.click_x ?? action.clickX);
|
|
6109
|
+
const fromY = setupFiniteNumber(action.from_y ?? action.fromY ?? action.y ?? action.click_y ?? action.clickY);
|
|
6110
|
+
const hasTapPosition = fromX !== undefined || fromY !== undefined;
|
|
6111
|
+
if (hasTapPosition && (fromX === undefined || fromY === undefined)) return { ...base, ...setupScopeEvidence(scope), reason: "missing_tap_coordinates", count, target_index: targetIndex };
|
|
6112
|
+
const mode = String(action.coordinate_mode || action.coordinateMode || (hasTapPosition ? "pixels" : "ratio")).trim();
|
|
6113
|
+
if (hasTapPosition && mode === "ratio" && [fromX, fromY].some((value) => value < 0 || value > 1)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_ratio_coordinates", count, target_index: targetIndex };
|
|
6114
|
+
if (hasTapPosition && mode !== "ratio" && [fromX, fromY].some((value) => value < 0)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_pixel_coordinates", count, target_index: targetIndex };
|
|
6115
|
+
const coordinate = (value, size) => mode === "ratio" ? value * size : value;
|
|
6116
|
+
const localX = hasTapPosition && fromX !== undefined ? fromX : 0.5;
|
|
6117
|
+
const localY = hasTapPosition && fromY !== undefined ? fromY : 0.5;
|
|
6118
|
+
const point = {
|
|
6119
|
+
x: box.x + coordinate(localX, box.width),
|
|
6120
|
+
y: box.y + coordinate(localY, box.height),
|
|
6121
|
+
};
|
|
6122
|
+
const durationMs = setupNumber(action.duration_ms ?? action.durationMs, 0);
|
|
6123
|
+
const pointerType = String(action.pointer_type || action.pointerType || "touch").trim().toLowerCase();
|
|
6124
|
+
if (pointerType === "touch" || pointerType === "pen") {
|
|
6125
|
+
const client = await page.context().newCDPSession(page);
|
|
6126
|
+
try {
|
|
6127
|
+
if (pointerType === "touch") {
|
|
6128
|
+
const touchPoint = {
|
|
6129
|
+
x: point.x,
|
|
6130
|
+
y: point.y,
|
|
6131
|
+
radiusX: 1,
|
|
6132
|
+
radiusY: 1,
|
|
6133
|
+
force: 1,
|
|
6134
|
+
id: 11,
|
|
6135
|
+
};
|
|
6136
|
+
await client.send("Input.dispatchTouchEvent", {
|
|
6137
|
+
type: "touchStart",
|
|
6138
|
+
touchPoints: [touchPoint],
|
|
6139
|
+
});
|
|
6140
|
+
if (durationMs) await page.waitForTimeout(durationMs);
|
|
6141
|
+
await client.send("Input.dispatchTouchEvent", {
|
|
6142
|
+
type: "touchEnd",
|
|
6143
|
+
touchPoints: [],
|
|
6144
|
+
});
|
|
6145
|
+
} else {
|
|
6146
|
+
await client.send("Input.dispatchMouseEvent", {
|
|
6147
|
+
type: "mousePressed",
|
|
6148
|
+
x: point.x,
|
|
6149
|
+
y: point.y,
|
|
6150
|
+
button: "left",
|
|
6151
|
+
buttons: 1,
|
|
6152
|
+
clickCount: 1,
|
|
6153
|
+
pointerType: "pen",
|
|
6154
|
+
});
|
|
6155
|
+
if (durationMs) await page.waitForTimeout(durationMs);
|
|
6156
|
+
await client.send("Input.dispatchMouseEvent", {
|
|
6157
|
+
type: "mouseReleased",
|
|
6158
|
+
x: point.x,
|
|
6159
|
+
y: point.y,
|
|
6160
|
+
button: "left",
|
|
6161
|
+
buttons: 0,
|
|
6162
|
+
clickCount: 1,
|
|
6163
|
+
pointerType: "pen",
|
|
6164
|
+
});
|
|
6165
|
+
}
|
|
6166
|
+
} finally {
|
|
6167
|
+
await client.detach().catch(() => {});
|
|
6168
|
+
}
|
|
6169
|
+
} else {
|
|
6170
|
+
await page.mouse.click(point.x, point.y);
|
|
6171
|
+
}
|
|
6172
|
+
return {
|
|
6173
|
+
...base,
|
|
6174
|
+
...setupScopeEvidence(scope),
|
|
6175
|
+
ok: true,
|
|
6176
|
+
count,
|
|
6177
|
+
target_index: targetIndex,
|
|
6178
|
+
coordinate_mode: hasTapPosition ? mode : undefined,
|
|
6179
|
+
x: hasTapPosition ? fromX : undefined,
|
|
6180
|
+
y: hasTapPosition ? fromY : undefined,
|
|
6181
|
+
pointer_type: pointerType,
|
|
6182
|
+
input_dispatch: pointerType === "touch" || pointerType === "pen" ? "cdp" : "playwright_mouse",
|
|
6183
|
+
duration_ms: durationMs || undefined,
|
|
6184
|
+
};
|
|
6185
|
+
}
|
|
6046
6186
|
if (type === "drag") {
|
|
6047
6187
|
const scope = await setupActionScope(action, timeout);
|
|
6048
6188
|
if (!scope.ok) return setupScopeFailure(base, scope);
|