@mearl/native-host 2.7.0 → 2.7.1

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.
Files changed (2) hide show
  1. package/dist/index.js +160 -6
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -2091,8 +2091,8 @@ function resolvePageDragInput(data) {
2091
2091
  if (!data || typeof data !== "object") {
2092
2092
  throw new Error("page_drag: payload is required");
2093
2093
  }
2094
- if (data.dragMode !== void 0 && !["auto", "mouse", "touch"].includes(data.dragMode)) {
2095
- throw new Error('page_drag: "dragMode" must be one of auto, mouse, touch');
2094
+ if (data.dragMode !== void 0 && !["auto", "dom", "mouse", "touch"].includes(data.dragMode)) {
2095
+ throw new Error('page_drag: "dragMode" must be one of auto, dom, mouse, touch');
2096
2096
  }
2097
2097
  const durationMs = data.durationMs ?? PAGE_DRAG_DEFAULT_DURATION_MS;
2098
2098
  if (!Number.isFinite(durationMs) || durationMs < 0 || durationMs > PAGE_DRAG_MAX_DURATION_MS) {
@@ -2105,6 +2105,16 @@ function resolvePageDragInput(data) {
2105
2105
  durationMs: Math.round(durationMs)
2106
2106
  };
2107
2107
  }
2108
+ function resolvePageDragDispatchPolicy(dragMode, visibilityState, touchEmulationEnabled) {
2109
+ const requestedMode = dragMode ?? "auto";
2110
+ const pointerType = requestedMode === "mouse" || requestedMode === "touch" ? requestedMode : touchEmulationEnabled ? "touch" : "mouse";
2111
+ if (requestedMode === "dom")
2112
+ return { dispatchMode: "dom", pointerType };
2113
+ if (requestedMode === "auto" && visibilityState === "hidden") {
2114
+ return { dispatchMode: "dom", pointerType, fallbackReason: "page-hidden" };
2115
+ }
2116
+ return { dispatchMode: "trusted-input", pointerType };
2117
+ }
2108
2118
  function buildPageDragPath(from, to, durationMs) {
2109
2119
  const steps = Math.max(PAGE_DRAG_MIN_STEPS, Math.min(PAGE_DRAG_MAX_STEPS, Math.ceil(durationMs / PAGE_DRAG_STEP_INTERVAL_MS)));
2110
2120
  const points = Array.from({ length: steps }, (_, index) => {
@@ -2116,6 +2126,116 @@ function buildPageDragPath(from, to, durationMs) {
2116
2126
  });
2117
2127
  return { points, intervalMs: durationMs / steps };
2118
2128
  }
2129
+ function dragBetweenPointsInPage(from, points, pointerType) {
2130
+ const target = document.elementFromPoint(from.x, from.y);
2131
+ if (!target) {
2132
+ return {
2133
+ dragged: false,
2134
+ steps: 0,
2135
+ error: `No element found at drag start point (${from.x}, ${from.y})`
2136
+ };
2137
+ }
2138
+ if (points.length === 0) {
2139
+ return { dragged: false, steps: 0, error: "Drag path must contain at least one point" };
2140
+ }
2141
+ const view = target.ownerDocument.defaultView ?? window;
2142
+ const realm = view;
2143
+ const pointerId = 1;
2144
+ const pointerInit = (point, buttons, pressure) => ({
2145
+ bubbles: true,
2146
+ cancelable: true,
2147
+ composed: true,
2148
+ view,
2149
+ clientX: point.x,
2150
+ clientY: point.y,
2151
+ screenX: point.x,
2152
+ screenY: point.y,
2153
+ button: 0,
2154
+ buttons,
2155
+ pointerId,
2156
+ pointerType,
2157
+ isPrimary: true,
2158
+ pressure,
2159
+ width: 1,
2160
+ height: 1
2161
+ });
2162
+ const dispatchPointer = (type, point, buttons, pressure) => {
2163
+ if (typeof realm.PointerEvent !== "function")
2164
+ return false;
2165
+ target.dispatchEvent(new realm.PointerEvent(type, pointerInit(point, buttons, pressure)));
2166
+ return true;
2167
+ };
2168
+ const dispatchMouse = (type, point, buttons) => {
2169
+ if (typeof realm.MouseEvent !== "function")
2170
+ return false;
2171
+ target.dispatchEvent(new realm.MouseEvent(type, {
2172
+ bubbles: true,
2173
+ cancelable: true,
2174
+ composed: true,
2175
+ view,
2176
+ clientX: point.x,
2177
+ clientY: point.y,
2178
+ screenX: point.x,
2179
+ screenY: point.y,
2180
+ button: 0,
2181
+ buttons
2182
+ }));
2183
+ return true;
2184
+ };
2185
+ const createTouch = (point) => {
2186
+ const init = {
2187
+ identifier: pointerId,
2188
+ target,
2189
+ clientX: point.x,
2190
+ clientY: point.y,
2191
+ screenX: point.x,
2192
+ screenY: point.y,
2193
+ pageX: point.x + view.scrollX,
2194
+ pageY: point.y + view.scrollY,
2195
+ radiusX: 1,
2196
+ radiusY: 1,
2197
+ rotationAngle: 0,
2198
+ force: 0.5
2199
+ };
2200
+ return typeof realm.Touch === "function" ? new realm.Touch(init) : init;
2201
+ };
2202
+ const dispatchTouch = (type, point) => {
2203
+ if (typeof realm.TouchEvent !== "function")
2204
+ return false;
2205
+ const touch = createTouch(point);
2206
+ const activeTouches = type === "touchend" ? [] : [touch];
2207
+ target.dispatchEvent(new realm.TouchEvent(type, {
2208
+ bubbles: true,
2209
+ cancelable: true,
2210
+ composed: true,
2211
+ touches: activeTouches,
2212
+ targetTouches: activeTouches,
2213
+ changedTouches: [touch]
2214
+ }));
2215
+ return true;
2216
+ };
2217
+ let dispatched = dispatchPointer("pointerdown", from, 1, 0.5);
2218
+ dispatched = pointerType === "touch" ? dispatchTouch("touchstart", from) || dispatched : dispatchMouse("mousedown", from, 1) || dispatched;
2219
+ for (const point of points) {
2220
+ dispatched = dispatchPointer("pointermove", point, 1, 0.5) || dispatched;
2221
+ dispatched = pointerType === "touch" ? dispatchTouch("touchmove", point) || dispatched : dispatchMouse("mousemove", point, 1) || dispatched;
2222
+ }
2223
+ const end = points[points.length - 1];
2224
+ dispatched = pointerType === "touch" ? dispatchTouch("touchend", end) || dispatched : dispatchMouse("mouseup", end, 0) || dispatched;
2225
+ dispatched = dispatchPointer("pointerup", end, 0, 0) || dispatched;
2226
+ return dispatched ? { dragged: true, steps: points.length } : { dragged: false, steps: 0, error: "This page does not support synthetic drag events" };
2227
+ }
2228
+ var DRAG_BETWEEN_POINTS_IN_PAGE_SOURCE = dragBetweenPointsInPage.toString();
2229
+ function buildPageDragDomExpression(from, points, pointerType) {
2230
+ return `(${DRAG_BETWEEN_POINTS_IN_PAGE_SOURCE})(${JSON.stringify(from)}, ${JSON.stringify(points)}, ${JSON.stringify(pointerType)})`;
2231
+ }
2232
+ function unwrapPageDragDomResult(result) {
2233
+ if (!result)
2234
+ throw new Error("page_drag: DOM simulation returned no result");
2235
+ if (!result.dragged)
2236
+ throw new Error(`page_drag: ${result.error}`);
2237
+ return result;
2238
+ }
2119
2239
  function getDragCoordsFromNode() {
2120
2240
  const el = this.nodeType === Node.TEXT_NODE ? this.parentElement : this;
2121
2241
  if (!el || typeof el.getBoundingClientRect !== "function")
@@ -8489,18 +8609,52 @@ async function resolveDragEndpoint(session, endpoint) {
8489
8609
  }
8490
8610
  async function cdpPageDrag(session, data) {
8491
8611
  const input = resolvePageDragInput(data);
8612
+ const visibilityResult = input.dragMode === "auto" ? await session.client.sendCommand("Runtime.evaluate", {
8613
+ expression: "document.visibilityState",
8614
+ returnByValue: true
8615
+ }) : void 0;
8616
+ const touchEmulationEnabled = input.dragMode === "auto" || input.dragMode === "dom" ? await prefersTouchInput(session) : input.dragMode === "touch";
8617
+ const policy = resolvePageDragDispatchPolicy(
8618
+ input.dragMode,
8619
+ visibilityResult?.result?.value,
8620
+ touchEmulationEnabled
8621
+ );
8492
8622
  await scrollDragSourceIntoView(session, input.from);
8493
8623
  const from = await resolveDragEndpoint(session, input.from);
8494
8624
  const to = await resolveDragEndpoint(session, input.to);
8495
8625
  if (Math.hypot(to.point.x - from.point.x, to.point.y - from.point.y) < 1) {
8496
8626
  throw new Error("page_drag: resolved endpoints must be at least 1 viewport pixel apart");
8497
8627
  }
8498
- const pointerType = input.dragMode === "auto" ? await prefersTouchInput(session) ? "touch" : "mouse" : input.dragMode;
8628
+ if (policy.dispatchMode === "dom") {
8629
+ const path15 = buildPageDragPath(from.point, to.point, input.durationMs);
8630
+ const result = await session.client.sendCommand("Runtime.evaluate", {
8631
+ expression: buildPageDragDomExpression(from.point, path15.points, policy.pointerType),
8632
+ returnByValue: true
8633
+ });
8634
+ if (result.exceptionDetails) {
8635
+ throw new Error(
8636
+ result.exceptionDetails.exception?.description ?? result.exceptionDetails.text ?? "page_drag: DOM simulation failed"
8637
+ );
8638
+ }
8639
+ const { steps: steps2 } = unwrapPageDragDomResult(
8640
+ result.result?.value
8641
+ );
8642
+ return {
8643
+ dragged: true,
8644
+ from,
8645
+ to,
8646
+ dispatchMode: "dom",
8647
+ pointerType: policy.pointerType,
8648
+ durationMs: input.durationMs,
8649
+ steps: steps2,
8650
+ ...policy.fallbackReason ? { fallbackReason: policy.fallbackReason } : {}
8651
+ };
8652
+ }
8499
8653
  const { steps } = await dispatchCdpDrag(
8500
8654
  session,
8501
8655
  from.point,
8502
8656
  to.point,
8503
- pointerType,
8657
+ policy.pointerType,
8504
8658
  input.durationMs
8505
8659
  );
8506
8660
  return {
@@ -8508,7 +8662,7 @@ async function cdpPageDrag(session, data) {
8508
8662
  from,
8509
8663
  to,
8510
8664
  dispatchMode: "trusted-input",
8511
- pointerType,
8665
+ pointerType: policy.pointerType,
8512
8666
  durationMs: input.durationMs,
8513
8667
  steps
8514
8668
  };
@@ -10634,7 +10788,7 @@ import os2 from "node:os";
10634
10788
  import { randomUUID as randomUUID4 } from "node:crypto";
10635
10789
 
10636
10790
  // src/version.ts
10637
- var NATIVE_HOST_VERSION = true ? "2.7.0" : "unknown";
10791
+ var NATIVE_HOST_VERSION = true ? "2.7.1" : "unknown";
10638
10792
 
10639
10793
  // src/analytics.ts
10640
10794
  var MEASUREMENT_ID = "G-W84LJDZ6PH";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/native-host",
3
- "version": "2.7.0",
3
+ "version": "2.7.1",
4
4
  "description": "Native Messaging Host for Mearl — bridges Chrome Extension and local socket server",
5
5
  "type": "module",
6
6
  "main": "dist/install.js",
@@ -37,9 +37,9 @@
37
37
  "@types/ws": "^8.18.1",
38
38
  "esbuild": "^0.25.2",
39
39
  "typescript": "^5.8.3",
40
- "@mearl/browser-core": "2.7.0",
41
- "@mearl/daemon-core": "2.7.0",
42
- "@mearl/setup": "2.7.0"
40
+ "@mearl/browser-core": "2.7.1",
41
+ "@mearl/daemon-core": "2.7.1",
42
+ "@mearl/setup": "2.7.1"
43
43
  },
44
44
  "scripts": {
45
45
  "build": "rm -rf dist/ && node build.mjs",