@oniroproject/core 0.12.0 → 0.13.0

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/index.js CHANGED
@@ -2415,6 +2415,55 @@ async function captureBurst(opts) {
2415
2415
  }
2416
2416
 
2417
2417
  // src/hdc/input.ts
2418
+ var UITEST_KEY_NAMES = ["Back", "Home", "Power"];
2419
+ var KEY_IDS = {
2420
+ back: 2,
2421
+ home: 1,
2422
+ power: 18,
2423
+ volumeup: 16,
2424
+ volumedown: 17,
2425
+ up: 2012,
2426
+ down: 2013,
2427
+ left: 2014,
2428
+ right: 2015,
2429
+ alt: 2045,
2430
+ shift: 2047,
2431
+ tab: 2049,
2432
+ space: 2050,
2433
+ enter: 2054,
2434
+ delete: 2055,
2435
+ backspace: 2055,
2436
+ pageup: 2068,
2437
+ pagedown: 2069,
2438
+ escape: 2070,
2439
+ esc: 2070,
2440
+ forwarddelete: 2071,
2441
+ ctrl: 2072,
2442
+ meta: 2076,
2443
+ movehome: 2081,
2444
+ moveend: 2082
2445
+ };
2446
+ function keyId(name) {
2447
+ const k = name.trim().toLowerCase();
2448
+ if (/^\d+$/.test(k)) return Number(k);
2449
+ if (/^[a-z]$/.test(k)) return 2017 + (k.charCodeAt(0) - 97);
2450
+ const id = KEY_IDS[k];
2451
+ if (id === void 0) {
2452
+ throw new OniroError(
2453
+ `Unknown key "${name}". Use a numeric KeyCode id, a letter, or one of: ${Object.keys(KEY_IDS).join(", ")}. Combine up to three with "+", e.g. Ctrl+A.`
2454
+ );
2455
+ }
2456
+ return id;
2457
+ }
2458
+ function resolveKeyEvent(key) {
2459
+ const spec = String(key).trim();
2460
+ if (spec === "") throw new OniroError('send input "keyEvent" requires a key.');
2461
+ const native = UITEST_KEY_NAMES.find((n) => n.toLowerCase() === spec.toLowerCase());
2462
+ if (native) return native;
2463
+ const parts = spec.includes("+") ? spec.split("+") : spec.split(/\s+/);
2464
+ if (parts.length > 3) throw new OniroError(`uitest injects at most three keys at once; got "${spec}".`);
2465
+ return parts.map(keyId).join(" ");
2466
+ }
2418
2467
  function reqNum(value, name, type) {
2419
2468
  if (value === void 0 || Number.isNaN(value)) {
2420
2469
  throw new OniroError(`send input "${type}" requires a numeric ${name}.`);
@@ -2435,7 +2484,7 @@ function buildInputCommand(opts) {
2435
2484
  }
2436
2485
  case "keyEvent":
2437
2486
  if (opts.key === void 0 || opts.key === "") throw new OniroError('send input "keyEvent" requires a key.');
2438
- return `uitest uiInput keyEvent ${opts.key}`;
2487
+ return `uitest uiInput keyEvent ${resolveKeyEvent(opts.key)}`;
2439
2488
  case "inputText": {
2440
2489
  const t = String(opts.text ?? "").replace(/'/g, `'\\''`);
2441
2490
  if (opts.pxX !== void 0 && opts.pxY !== void 0) {
@@ -2533,6 +2582,48 @@ import * as fs20 from "fs";
2533
2582
  import * as os10 from "os";
2534
2583
  import * as path20 from "path";
2535
2584
  import { randomBytes as randomBytes3 } from "crypto";
2585
+
2586
+ // src/hdc/ime.ts
2587
+ var INPUT_METHOD_SA_ID = 3703;
2588
+ var IME_BUNDLE_FALLBACK = /inputmethod|keyboard|(^|\.)ime(\.|$)/i;
2589
+ function parseImeBundles(output) {
2590
+ const current = [];
2591
+ const others = [];
2592
+ const entry = /\{[^{}]*"ime"\s*:\s*"([^"/]+)\/[^"]*"[^{}]*\}/g;
2593
+ for (const m of output.matchAll(entry)) {
2594
+ const bundle = m[1];
2595
+ const list = /"isCurrentIme"\s*:\s*"true"/.test(m[0]) ? current : others;
2596
+ if (!current.includes(bundle) && !others.includes(bundle)) list.push(bundle);
2597
+ }
2598
+ return [...current, ...others];
2599
+ }
2600
+ async function getImeBundles(config, opts = {}) {
2601
+ try {
2602
+ const res = await shell({
2603
+ config,
2604
+ command: `hidumper -s ${INPUT_METHOD_SA_ID} -a '-a'`,
2605
+ deviceSerial: opts.deviceSerial,
2606
+ timeoutMs: 1e4,
2607
+ logger: opts.logger
2608
+ });
2609
+ if (res.code === 0) return parseImeBundles(res.stdout);
2610
+ } catch (err) {
2611
+ opts.logger?.debug(`could not list input methods: ${err instanceof Error ? err.message : String(err)}`);
2612
+ }
2613
+ return [];
2614
+ }
2615
+ function findKeyboardWindow(tree, imeBundles) {
2616
+ const isIme = (bundle) => imeBundles.length > 0 ? imeBundles.includes(bundle) : IME_BUNDLE_FALLBACK.test(bundle);
2617
+ const stack = [tree];
2618
+ while (stack.length > 0) {
2619
+ const n = stack.shift();
2620
+ if (n.bundle && isIme(n.bundle)) return n;
2621
+ stack.push(...n.children ?? []);
2622
+ }
2623
+ return null;
2624
+ }
2625
+
2626
+ // src/hdc/dump.ts
2536
2627
  function parseBounds(s) {
2537
2628
  const m = /^\[(-?\d+),(-?\d+)\]\[(-?\d+),(-?\d+)\]$/.exec(s ?? "");
2538
2629
  if (!m) return null;
@@ -2567,7 +2658,46 @@ var FLAG_MAP = [
2567
2658
  ["scrollable", "scroll"],
2568
2659
  ["longClickable", "longClick"]
2569
2660
  ];
2570
- function pruneLayout(node, display) {
2661
+ function colorAlpha(color) {
2662
+ const m = /^#([0-9a-f]{2})?[0-9a-f]{6}$/i.exec(color ?? "");
2663
+ if (!m) return 0;
2664
+ return m[1] === void 0 ? 255 : parseInt(m[1], 16);
2665
+ }
2666
+ function paintsFill(a) {
2667
+ if (a.visible === "false") return false;
2668
+ if (a.opacity !== void 0 && a.opacity !== "" && !(Number(a.opacity) > 0)) return false;
2669
+ return colorAlpha(a.backgroundColor) > 0;
2670
+ }
2671
+ function findCoveredNodes(root) {
2672
+ const order = [];
2673
+ const fills = [];
2674
+ const visit = (n) => {
2675
+ const a = n.attributes ?? {};
2676
+ const entry = { node: n, bounds: parseBounds(a.bounds), end: 0 };
2677
+ if (entry.bounds && paintsFill(a)) fills.push(order.length);
2678
+ order.push(entry);
2679
+ const kids = (n.children ?? []).map((c, i) => ({ c, i, z: Number(c.attributes?.zIndex) || 0 })).sort((p, q) => p.z - q.z || p.i - q.i);
2680
+ for (const k of kids) visit(k.c);
2681
+ entry.end = order.length;
2682
+ };
2683
+ visit(root);
2684
+ const covered = /* @__PURE__ */ new Set();
2685
+ for (const p of order) {
2686
+ if (!p.bounds) continue;
2687
+ const cx = (p.bounds[0] + p.bounds[2]) / 2;
2688
+ const cy = (p.bounds[1] + p.bounds[3]) / 2;
2689
+ for (const j of fills) {
2690
+ if (j < p.end) continue;
2691
+ const q = order[j].bounds;
2692
+ if (cx >= q[0] && cx < q[2] && cy >= q[1] && cy < q[3]) {
2693
+ covered.add(p.node);
2694
+ break;
2695
+ }
2696
+ }
2697
+ }
2698
+ return covered;
2699
+ }
2700
+ function pruneLayout(node, display, covered) {
2571
2701
  const a = node.attributes ?? {};
2572
2702
  const px = parseBounds(a.bounds);
2573
2703
  const out = {};
@@ -2585,28 +2715,125 @@ function pruneLayout(node, display) {
2585
2715
  if (a.type && !STRUCTURAL_TYPES.has(a.type)) out.type = a.type;
2586
2716
  if (a.text) out.text = a.text;
2587
2717
  if (a.description) out.desc = a.description;
2718
+ if (a.hint) out.hint = a.hint;
2588
2719
  if (a.id) out.id = a.id;
2589
2720
  if (a.key && a.key !== a.id) out.key = a.key;
2590
2721
  if (a.bundleName) out.bundle = a.bundleName;
2591
2722
  for (const [attr, short] of FLAG_MAP) {
2592
2723
  if (a[attr] === "true") out[short] = true;
2593
2724
  }
2725
+ if (a.enabled === "false") out.disabled = true;
2726
+ if (covered?.has(node)) out.covered = true;
2594
2727
  const children = [];
2595
2728
  for (const c of node.children ?? []) {
2596
- const pc = pruneLayout(c, display);
2729
+ const pc = pruneLayout(c, display, covered);
2597
2730
  if (pc) {
2598
2731
  if (Array.isArray(pc)) children.push(...pc);
2599
2732
  else children.push(pc);
2600
2733
  }
2601
2734
  }
2602
2735
  const hasSignal = Boolean(
2603
- out.text || out.desc || out.id || out.key || out.click || out.scroll || out.check || out.longClick || out.bundle || out.type && out.type !== "root"
2736
+ out.text || out.desc || out.hint || out.id || out.key || out.click || out.scroll || out.check || out.longClick || out.bundle || out.type && out.type !== "root"
2604
2737
  );
2605
2738
  if (!hasSignal && children.length === 0) return null;
2606
2739
  if (!hasSignal) return children.length === 1 ? children[0] : children;
2607
2740
  if (children.length) out.children = children;
2608
2741
  return out;
2609
2742
  }
2743
+ function flattenLayout(tree) {
2744
+ const out = [];
2745
+ const visit = (n, window) => {
2746
+ const { children, ...rest } = n;
2747
+ const win = n.bundle ?? window;
2748
+ if (Object.keys(rest).length > 0) out.push({ ...rest, ...win ? { window: win } : {} });
2749
+ for (const c of children ?? []) visit(c, win);
2750
+ };
2751
+ visit(tree, void 0);
2752
+ return out;
2753
+ }
2754
+ function assertLayoutSelector(selector) {
2755
+ if (selector.text === void 0 && selector.id === void 0 && selector.type === void 0) {
2756
+ throw new OniroError("A layout selector needs a text, id, or type.");
2757
+ }
2758
+ if (selector.text !== void 0 && selector.text.trim() === "") {
2759
+ throw new OniroError("A layout selector text must not be blank.");
2760
+ }
2761
+ }
2762
+ function withoutWindow(tree, bundle) {
2763
+ const children = (tree.children ?? []).filter((c) => c.bundle !== bundle).map((c) => withoutWindow(c, bundle));
2764
+ return tree.children ? { ...tree, children } : tree;
2765
+ }
2766
+ function findLayoutNodes(tree, selector) {
2767
+ assertLayoutSelector(selector);
2768
+ const type = selector.type?.toLowerCase();
2769
+ const nodes = flattenLayout(tree).filter(
2770
+ (n) => (type === void 0 || n.type?.toLowerCase() === type) && (selector.id === void 0 || n.id === selector.id || n.key === selector.id)
2771
+ );
2772
+ if (selector.text === void 0) return nodes;
2773
+ const want = selector.text.trim().toLowerCase();
2774
+ const labels = (n) => [n.text, n.desc, n.hint].filter((s) => !!s).map((s) => s.trim().toLowerCase());
2775
+ const exact = nodes.filter((n) => labels(n).some((l) => l === want));
2776
+ if (exact.length > 0) return exact;
2777
+ return nodes.filter((n) => labels(n).some((l) => l.includes(want)));
2778
+ }
2779
+ function describeSelector(s) {
2780
+ const parts = [];
2781
+ if (s.text !== void 0) parts.push(`text "${s.text}"`);
2782
+ if (s.id !== void 0) parts.push(`id "${s.id}"`);
2783
+ if (s.type !== void 0) parts.push(`type ${s.type}`);
2784
+ return parts.join(", ");
2785
+ }
2786
+ function describeLayoutNode(n) {
2787
+ const label = n.text ?? n.desc ?? (n.hint !== void 0 ? `hint: ${n.hint}` : void 0);
2788
+ const at = n.c ? ` at ${n.c[0].toFixed(3)},${n.c[1].toFixed(3)}` : "";
2789
+ return `${n.type ?? "node"}${label !== void 0 ? ` "${label}"` : ""}${n.id ? ` #${n.id}` : ""}${at}`;
2790
+ }
2791
+ var area = (b) => b ? (b[2] - b[0]) * (b[3] - b[1]) : 0;
2792
+ function enclosesTarget(outer, inner) {
2793
+ const b = outer.b;
2794
+ const c = inner.c;
2795
+ if (!b || !c) return false;
2796
+ return c[0] >= b[0] && c[0] <= b[2] && c[1] >= b[1] && c[1] <= b[3] && area(b) > area(inner.b);
2797
+ }
2798
+ var TargetNotFoundError = class extends OniroError {
2799
+ constructor(message, reason) {
2800
+ super(message);
2801
+ this.reason = reason;
2802
+ this.name = "TargetNotFoundError";
2803
+ }
2804
+ reason;
2805
+ };
2806
+ function pickTarget(tree, selector, index) {
2807
+ const matches = findLayoutNodes(tree, selector).filter((n) => n.c !== void 0);
2808
+ const what = describeSelector(selector);
2809
+ if (matches.length === 0) {
2810
+ throw new TargetNotFoundError(`No on-screen element matches ${what}. Run \`oniro-app dump layout --flat\` to see what is there.`, "none");
2811
+ }
2812
+ const visible = matches.filter((n) => !n.covered);
2813
+ if (visible.length === 0) {
2814
+ throw new TargetNotFoundError(
2815
+ `Found ${matches.length} element(s) matching ${what}, but each is covered by an overlay (dialog, keyboard, or another layer): ${matches.map(describeLayoutNode).join("; ")}.`,
2816
+ "covered"
2817
+ );
2818
+ }
2819
+ const clickable = visible.filter((n) => n.click);
2820
+ const preferred = clickable.length > 0 ? clickable : visible;
2821
+ const candidates = preferred.filter((n) => !preferred.some((o) => o !== n && o.click && enclosesTarget(o, n)));
2822
+ if (index !== void 0) {
2823
+ const picked = candidates[index];
2824
+ if (!picked) {
2825
+ throw new TargetNotFoundError(`Index ${index} is out of range: ${candidates.length} element(s) match ${what}.`, "ambiguous");
2826
+ }
2827
+ return picked;
2828
+ }
2829
+ if (candidates.length > 1) {
2830
+ throw new TargetNotFoundError(
2831
+ `${candidates.length} elements match ${what}; pass an index to choose: ` + candidates.map((n, i) => `[${i}] ${describeLayoutNode(n)}`).join("; "),
2832
+ "ambiguous"
2833
+ );
2834
+ }
2835
+ return candidates[0];
2836
+ }
2610
2837
  async function dumpLayout(opts) {
2611
2838
  const timeoutMs = opts.timeoutMs ?? 3e4;
2612
2839
  const bundleArg = opts.bundleName ? ` -b '${opts.bundleName.replace(/'/g, `'\\''`)}'` : "";
@@ -2624,9 +2851,13 @@ ${dump.stdout}`);
2624
2851
  if (opts.prune === false) {
2625
2852
  return { display, tree: parsed };
2626
2853
  }
2627
- const prunedRaw = pruneLayout(parsed, display);
2854
+ const prunedRaw = pruneLayout(parsed, display, findCoveredNodes(parsed));
2628
2855
  const tree = Array.isArray(prunedRaw) ? { children: prunedRaw } : prunedRaw ?? { children: [] };
2629
- return { display, tree };
2856
+ if (!opts.detectKeyboard || opts.bundleName) return { display, tree };
2857
+ const imeBundles = await getImeBundles(opts.config, { deviceSerial: opts.deviceSerial, logger: opts.logger });
2858
+ const kb = findKeyboardWindow(tree, imeBundles);
2859
+ const keyboard = kb ? { shown: true, bundle: kb.bundle, ...kb.b ? { b: kb.b } : {} } : { shown: false };
2860
+ return { display, tree, keyboard };
2630
2861
  } finally {
2631
2862
  fs20.promises.unlink(local).catch(() => {
2632
2863
  });
@@ -2635,6 +2866,161 @@ ${dump.stdout}`);
2635
2866
  }
2636
2867
  }
2637
2868
 
2869
+ // src/hdc/uiActions.ts
2870
+ var FOCUS_SETTLE_MS = 400;
2871
+ var KEYBOARD_SETTLE_MS = 400;
2872
+ var sleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
2873
+ function targetTree(layout) {
2874
+ const kb = layout.keyboard;
2875
+ return kb?.shown && kb.bundle ? withoutWindow(layout.tree, kb.bundle) : layout.tree;
2876
+ }
2877
+ function fractionToPixel(f, size) {
2878
+ return Math.min(size - 1, Math.round(f * size));
2879
+ }
2880
+ function pressBack(opts) {
2881
+ return sendInput({ config: opts.config, type: "keyEvent", key: "Back", deviceSerial: opts.deviceSerial, logger: opts.logger });
2882
+ }
2883
+ async function hideKeyboard(opts) {
2884
+ const { keyboard } = await dumpLayout({ ...opts, detectKeyboard: true });
2885
+ if (!keyboard?.shown) return false;
2886
+ await pressBack(opts);
2887
+ await sleep(KEYBOARD_SETTLE_MS);
2888
+ return true;
2889
+ }
2890
+ async function locateTarget(opts) {
2891
+ assertLayoutSelector(opts.selector);
2892
+ const dumpOpts = { config: opts.config, detectKeyboard: true, deviceSerial: opts.deviceSerial, logger: opts.logger };
2893
+ let layout = await dumpLayout(dumpOpts);
2894
+ if (!layout.display) throw new OniroError("Could not read the display size to locate the element.");
2895
+ let keyboardHidden = false;
2896
+ let node;
2897
+ let failure;
2898
+ try {
2899
+ node = pickTarget(targetTree(layout), opts.selector, opts.index);
2900
+ } catch (err) {
2901
+ if (!(err instanceof TargetNotFoundError) || err.reason === "ambiguous") throw err;
2902
+ failure = err;
2903
+ }
2904
+ if ((!node || !node.click) && layout.keyboard?.shown && opts.hideKeyboard !== false) {
2905
+ opts.logger?.debug("target not reachable while the keyboard is up; dismissing it and looking again");
2906
+ await pressBack(opts);
2907
+ await sleep(KEYBOARD_SETTLE_MS);
2908
+ keyboardHidden = true;
2909
+ layout = await dumpLayout(dumpOpts);
2910
+ if (!layout.display) throw new OniroError("Could not read the display size to locate the element.");
2911
+ node = pickTarget(targetTree(layout), opts.selector, opts.index);
2912
+ }
2913
+ if (!node) throw failure;
2914
+ if (!node.c) throw new OniroError("The element has no on-screen position.");
2915
+ const x2 = fractionToPixel(node.c[0], layout.display.width);
2916
+ const y = fractionToPixel(node.c[1], layout.display.height);
2917
+ return { node, x: x2, y, display: layout.display, keyboardHidden };
2918
+ }
2919
+ function fraction(value, name) {
2920
+ if (value === void 0) return void 0;
2921
+ if (!(value >= 0 && value <= 1)) throw new OniroError(`${name} must be a fraction between 0 and 1; got ${value}.`);
2922
+ return value;
2923
+ }
2924
+ function pair(a, b, names) {
2925
+ if (a === void 0 && b === void 0) return void 0;
2926
+ if (a === void 0 || b === void 0) throw new OniroError(`Give both ${names}.`);
2927
+ return [a, b];
2928
+ }
2929
+ async function performInput(opts) {
2930
+ const device = { config: opts.config, deviceSerial: opts.deviceSerial, logger: opts.logger };
2931
+ const startFx = pair(fraction(opts.fx, "--fx"), fraction(opts.fy, "--fy"), "--fx and --fy");
2932
+ const startPx = pair(opts.pxX, opts.pxY, "--x and --y");
2933
+ const endFx = pair(fraction(opts.fx2, "--fx2"), fraction(opts.fy2, "--fy2"), "--fx2 and --fy2");
2934
+ const endPx = pair(opts.pxX2, opts.pxY2, "--x2 and --y2");
2935
+ if ([opts.target, startFx, startPx].filter((s) => s !== void 0).length > 1) {
2936
+ throw new OniroError("Give the start point one way: a target, fractions (--fx/--fy), or pixels (--x/--y).");
2937
+ }
2938
+ if (endFx && endPx) throw new OniroError("Give the end point one way: fractions (--fx2/--fy2) or pixels (--x2/--y2).");
2939
+ let display;
2940
+ const toPx = async ([fx, fy]) => {
2941
+ display ??= await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial, logger: opts.logger });
2942
+ if (!display) throw new OniroError("Could not read the display size to convert fractions to pixels.");
2943
+ return [fractionToPixel(fx, display.width), fractionToPixel(fy, display.height)];
2944
+ };
2945
+ const result = { keyboardHidden: false };
2946
+ let start = startPx;
2947
+ if (opts.target) {
2948
+ const located = await locateTarget({ ...device, selector: opts.target, index: opts.targetIndex });
2949
+ display = located.display;
2950
+ start = [located.x, located.y];
2951
+ result.target = located.node;
2952
+ result.keyboardHidden = located.keyboardHidden;
2953
+ } else if (startFx) {
2954
+ start = await toPx(startFx);
2955
+ }
2956
+ const end = endFx ? await toPx(endFx) : endPx;
2957
+ if (start) [result.x, result.y] = start;
2958
+ const tapToFocus = async () => {
2959
+ if (!start) return;
2960
+ await sendInput({ ...device, type: "click", pxX: start[0], pxY: start[1] });
2961
+ await sleep(FOCUS_SETTLE_MS);
2962
+ };
2963
+ const clearFocused = async () => {
2964
+ await sendInput({ ...device, type: "keyEvent", key: "Ctrl+A" });
2965
+ await sendInput({ ...device, type: "keyEvent", key: "Delete" });
2966
+ };
2967
+ switch (opts.type) {
2968
+ case "hideKeyboard":
2969
+ result.keyboardHidden = await hideKeyboard(device) || result.keyboardHidden;
2970
+ return result;
2971
+ case "clearText":
2972
+ await tapToFocus();
2973
+ await clearFocused();
2974
+ break;
2975
+ case "inputText":
2976
+ if (opts.clear) {
2977
+ await tapToFocus();
2978
+ await clearFocused();
2979
+ await sendInput({ ...device, type: "inputText", text: opts.text });
2980
+ } else {
2981
+ await sendInput({ ...device, type: "inputText", pxX: start?.[0], pxY: start?.[1], text: opts.text });
2982
+ }
2983
+ break;
2984
+ default:
2985
+ await sendInput({
2986
+ ...device,
2987
+ type: opts.type,
2988
+ pxX: start?.[0],
2989
+ pxY: start?.[1],
2990
+ pxX2: end?.[0],
2991
+ pxY2: end?.[1],
2992
+ speed: opts.speed,
2993
+ key: opts.key,
2994
+ text: opts.text
2995
+ });
2996
+ }
2997
+ if (opts.hideKeyboard) result.keyboardHidden = await hideKeyboard(device) || result.keyboardHidden;
2998
+ return result;
2999
+ }
3000
+ async function waitForTarget(opts) {
3001
+ const { selector } = opts;
3002
+ assertLayoutSelector(selector);
3003
+ let found = null;
3004
+ await waitForCondition({
3005
+ probe: async () => {
3006
+ const layout = await dumpLayout({
3007
+ config: opts.config,
3008
+ detectKeyboard: true,
3009
+ deviceSerial: opts.deviceSerial,
3010
+ logger: opts.logger
3011
+ });
3012
+ found = findLayoutNodes(targetTree(layout), selector).find((n) => !n.covered) ?? null;
3013
+ return opts.gone ? found === null : found !== null;
3014
+ },
3015
+ timeoutMs: opts.timeoutMs,
3016
+ pollMs: opts.pollMs ?? 500,
3017
+ abortSignal: opts.abortSignal,
3018
+ logger: opts.logger,
3019
+ timeoutMessage: opts.gone ? `An element matching the selector was still on screen after ${opts.timeoutMs}ms.` : `No element matching the selector appeared within ${opts.timeoutMs}ms.`
3020
+ });
3021
+ return opts.gone ? null : found;
3022
+ }
3023
+
2638
3024
  // src/hdc/hilog.ts
2639
3025
  function setHilogLevel(opts) {
2640
3026
  const logger = opts.logger ?? noopLogger;
@@ -4767,7 +5153,7 @@ async function harmonyOsAutoSign(opts) {
4767
5153
  }
4768
5154
 
4769
5155
  // src/index.ts
4770
- var VERSION = "0.12.0";
5156
+ var VERSION = "0.13.0";
4771
5157
  export {
4772
5158
  ALL_SDKS,
4773
5159
  APL_VALUES,
@@ -4786,9 +5172,11 @@ export {
4786
5172
  SIGNING_ERRORS,
4787
5173
  SdkNotInstalledError,
4788
5174
  TMP_DIR_HINT,
5175
+ TargetNotFoundError,
4789
5176
  UnsupportedPlatformError,
4790
5177
  VERSION,
4791
5178
  applyChanges,
5179
+ assertLayoutSelector,
4792
5180
  attemptHdcConnection,
4793
5181
  buildCmdWrapper,
4794
5182
  buildGestureCommands,
@@ -4811,6 +5199,7 @@ export {
4811
5199
  dedupEntries,
4812
5200
  defaultContext,
4813
5201
  defaultPaths,
5202
+ describeLayoutNode,
4814
5203
  detectAaStartFailure,
4815
5204
  detectProjectSdkVersion,
4816
5205
  detectRuntimeOs,
@@ -4836,8 +5225,12 @@ export {
4836
5225
  extractZipWithProgress,
4837
5226
  findAppProcessId,
4838
5227
  findCmdToolsSourceDir,
5228
+ findCoveredNodes,
4839
5229
  findHarmonyOsSdk,
5230
+ findKeyboardWindow,
5231
+ findLayoutNodes,
4840
5232
  findRunningProcess,
5233
+ flattenLayout,
4841
5234
  forceStop,
4842
5235
  formatBytes,
4843
5236
  generateSigningConfigs,
@@ -4852,6 +5245,7 @@ export {
4852
5245
  getFreeSpaceBytes,
4853
5246
  getHdcPath,
4854
5247
  getHvigorwPath,
5248
+ getImeBundles,
4855
5249
  getInstalledSdks,
4856
5250
  getKey,
4857
5251
  getMainAbility,
@@ -4864,6 +5258,7 @@ export {
4864
5258
  harmonyOsAutoSign,
4865
5259
  harmonyOsSdkLabelForApi,
4866
5260
  hdcExec,
5261
+ hideKeyboard,
4867
5262
  installApp,
4868
5263
  installCmdTools,
4869
5264
  installEmulator,
@@ -4880,6 +5275,7 @@ export {
4880
5275
  listModules,
4881
5276
  listRunningProcesses,
4882
5277
  listTemplates,
5278
+ locateTarget,
4883
5279
  needsCmdWrapper,
4884
5280
  nonInteractivePrompter,
4885
5281
  noopLogger,
@@ -4890,9 +5286,12 @@ export {
4890
5286
  parseCodelinterFindings,
4891
5287
  parseDeviceList,
4892
5288
  parseHilogLine,
5289
+ parseImeBundles,
4893
5290
  parseMainAbilityFromBmDump,
4894
5291
  parseRemoteExit,
5292
+ performInput,
4895
5293
  pickSigningKind,
5294
+ pickTarget,
4896
5295
  prepareSigning,
4897
5296
  pruneLayout,
4898
5297
  readJson5File,
@@ -4905,6 +5304,7 @@ export {
4905
5304
  removeSdk,
4906
5305
  removeTempWorkDir,
4907
5306
  requireHarmonyOsSdk,
5307
+ resolveKeyEvent,
4908
5308
  resolveTmpRoot,
4909
5309
  runCodelinter,
4910
5310
  runHvigorw,
@@ -4934,8 +5334,10 @@ export {
4934
5334
  waitForBundle,
4935
5335
  waitForCondition,
4936
5336
  waitForLog,
5337
+ waitForTarget,
4937
5338
  watchLog,
4938
5339
  waypointsToRawEvents,
5340
+ withoutWindow,
4939
5341
  writeJson5File,
4940
5342
  writeJsonFile
4941
5343
  };