haltija 1.3.2 → 1.3.4

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.
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var VERSION = "1.3.2";
2
+ var VERSION = "1.3.4";
3
3
 
4
4
  // src/text-selector.ts
5
5
  var TEXT_PSEUDO_RE = /:(?:text-is|has-text|text)\(/;
@@ -551,13 +551,13 @@ function resolveSelectorAll(selector) {
551
551
  }
552
552
  function resolveRefOrSelector(ref, selector) {
553
553
  if (ref) {
554
- const result2 = refRegistry.resolveWithStatus(ref);
555
- if (result2.element) {
554
+ const result = refRegistry.resolveWithStatus(ref);
555
+ if (result.element) {
556
556
  stats.refsResolved++;
557
- return { element: result2.element, targetDesc: `@${ref}` };
557
+ return { element: result.element, targetDesc: `@${ref}` };
558
558
  }
559
559
  stats.refsStale++;
560
- const errorMsg = result2.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result2.status === "removed_from_dom" ? `Ref @${ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${ref} is stale - element was garbage collected (try refreshing /tree)`;
560
+ const errorMsg = result.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result.status === "removed_from_dom" ? `Ref @${ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${ref} is stale - element was garbage collected (try refreshing /tree)`;
561
561
  return { element: null, targetDesc: `@${ref}`, error: errorMsg };
562
562
  }
563
563
  if (selector) {
@@ -568,13 +568,13 @@ function resolveRefOrSelector(ref, selector) {
568
568
  }
569
569
  function resolveRefOrSelectorAll(ref, selector) {
570
570
  if (ref) {
571
- const result2 = refRegistry.resolveWithStatus(ref);
572
- if (result2.element) {
571
+ const result = refRegistry.resolveWithStatus(ref);
572
+ if (result.element) {
573
573
  stats.refsResolved++;
574
- return { elements: [result2.element], targetDesc: `@${ref}` };
574
+ return { elements: [result.element], targetDesc: `@${ref}` };
575
575
  }
576
576
  stats.refsStale++;
577
- const errorMsg = result2.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result2.status === "removed_from_dom" ? `Ref @${ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${ref} is stale - element was garbage collected (try refreshing /tree)`;
577
+ const errorMsg = result.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result.status === "removed_from_dom" ? `Ref @${ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${ref} is stale - element was garbage collected (try refreshing /tree)`;
578
578
  return { elements: [], targetDesc: `@${ref}`, error: errorMsg };
579
579
  }
580
580
  if (selector) {
@@ -1714,6 +1714,7 @@ class DevChannel extends HTMLElement {
1714
1714
  displayStream = null;
1715
1715
  displayVideo = null;
1716
1716
  isActive = true;
1717
+ visibilityHandler = null;
1717
1718
  homeLeft = 0;
1718
1719
  homeBottom = 16;
1719
1720
  headless = false;
@@ -1905,6 +1906,16 @@ class DevChannel extends HTMLElement {
1905
1906
  }
1906
1907
  this.interceptConsole();
1907
1908
  this.interceptDialogs();
1909
+ if (typeof document !== "undefined") {
1910
+ this.visibilityHandler = () => {
1911
+ if (document.visibilityState === "hidden") {
1912
+ this.deactivate();
1913
+ } else {
1914
+ this.activate();
1915
+ }
1916
+ };
1917
+ document.addEventListener("visibilitychange", this.visibilityHandler);
1918
+ }
1908
1919
  this.connect();
1909
1920
  }
1910
1921
  disconnectedCallback() {
@@ -1915,6 +1926,10 @@ class DevChannel extends HTMLElement {
1915
1926
  this.clearEventWatchers();
1916
1927
  this.stopMutationWatch();
1917
1928
  this.stopScreenCapture();
1929
+ if (this.visibilityHandler && typeof document !== "undefined") {
1930
+ document.removeEventListener("visibilitychange", this.visibilityHandler);
1931
+ this.visibilityHandler = null;
1932
+ }
1918
1933
  }
1919
1934
  attributeChangedCallback(name, _old, value) {
1920
1935
  if (name === "server") {
@@ -2808,8 +2823,8 @@ class DevChannel extends HTMLElement {
2808
2823
  headers: { "Content-Type": "application/json" },
2809
2824
  body: JSON.stringify({ action: "start", window: this.windowId })
2810
2825
  });
2811
- const result2 = await response.json();
2812
- if (result2.success) {
2826
+ const result = await response.json();
2827
+ if (result.success) {
2813
2828
  this.isRecording = true;
2814
2829
  this.serverManagedRecording = true;
2815
2830
  this.recordingStartTime = Date.now();
@@ -2821,7 +2836,7 @@ class DevChannel extends HTMLElement {
2821
2836
  this.updateRecordingUI(true);
2822
2837
  console.log("[Haltija] Recording started (server-managed)");
2823
2838
  } else {
2824
- console.error("[Haltija] Failed to start recording:", result2.error);
2839
+ console.error("[Haltija] Failed to start recording:", result.error);
2825
2840
  }
2826
2841
  } catch (err) {
2827
2842
  console.error("[Haltija] Failed to start recording:", err);
@@ -2836,10 +2851,10 @@ class DevChannel extends HTMLElement {
2836
2851
  headers: { "Content-Type": "application/json" },
2837
2852
  body: JSON.stringify({ action: "stop", window: this.windowId })
2838
2853
  });
2839
- const result2 = await response.json();
2840
- if (result2.success && result2.data) {
2841
- this.recordingEvents = result2.data.events || [];
2842
- this.recordingStartTime = result2.data.startTime || this.recordingStartTime;
2854
+ const result = await response.json();
2855
+ if (result.success && result.data) {
2856
+ this.recordingEvents = result.data.events || [];
2857
+ this.recordingStartTime = result.data.startTime || this.recordingStartTime;
2843
2858
  const recordingId = `rec_${this.recordingStartTime}_${Math.random().toString(36).slice(2, 8)}`;
2844
2859
  this.lastRecordingId = recordingId;
2845
2860
  console.log(`[Haltija] Recording stopped (${this.recordingEvents.length} events)`);
@@ -3152,15 +3167,15 @@ class DevChannel extends HTMLElement {
3152
3167
  headers: { "Content-Type": "application/json" },
3153
3168
  body: JSON.stringify({ description, agentId })
3154
3169
  });
3155
- const result2 = await response.json();
3156
- if (result2.error) {
3170
+ const result = await response.json();
3171
+ if (result.error) {
3157
3172
  if (successMsg) {
3158
- successMsg.textContent = `⚠️ ${result2.error}`;
3173
+ successMsg.textContent = `⚠️ ${result.error}`;
3159
3174
  successMsg.style.color = "#f59e0b";
3160
3175
  }
3161
3176
  } else {
3162
3177
  if (successMsg) {
3163
- successMsg.textContent = `✓ Sent to ${agentName}${result2.interrupted ? " (interrupted)" : ""}`;
3178
+ successMsg.textContent = `✓ Sent to ${agentName}${result.interrupted ? " (interrupted)" : ""}`;
3164
3179
  successMsg.style.color = "#22c55e";
3165
3180
  }
3166
3181
  setTimeout(() => this.closeTestModal(), 1500);
@@ -3691,13 +3706,13 @@ class DevChannel extends HTMLElement {
3691
3706
  const haltija = window.haltija;
3692
3707
  if (haltija?.openAgentTab) {
3693
3708
  newAgentText.textContent = "Creating...";
3694
- const result2 = await haltija.openAgentTab();
3695
- if (result2?.shellId) {
3709
+ const result = await haltija.openAgentTab();
3710
+ if (result?.shellId) {
3696
3711
  await new Promise((r) => setTimeout(r, 300));
3697
3712
  if (type === "selection") {
3698
- this.sendSelectionToAgent(result2.shellId, result2.name || "agent");
3713
+ this.sendSelectionToAgent(result.shellId, result.name || "agent");
3699
3714
  } else if (type === "recording") {
3700
- this.sendRecordingToAgent(result2.shellId, result2.name || "agent");
3715
+ this.sendRecordingToAgent(result.shellId, result.name || "agent");
3701
3716
  }
3702
3717
  } else {
3703
3718
  console.error(`${LOG_PREFIX} Failed to create agent tab`);
@@ -3766,8 +3781,8 @@ ${elementSummary}${moreText}`;
3766
3781
  context: `selection from ${window.location.host}`
3767
3782
  })
3768
3783
  });
3769
- const result2 = await response.json();
3770
- if (result2.sent) {
3784
+ const result = await response.json();
3785
+ if (result.sent) {
3771
3786
  this.clearSelection();
3772
3787
  console.log(`${LOG_PREFIX} Selection sent to ${agentName}`);
3773
3788
  }
@@ -5053,6 +5068,7 @@ ${elementSummary}${moreText}`;
5053
5068
  this.state = "connected";
5054
5069
  this.show();
5055
5070
  const windowType = window.opener ? "popup" : window.parent !== window ? "iframe" : "tab";
5071
+ this.isActive = typeof document === "undefined" || document.visibilityState !== "hidden";
5056
5072
  this.send("system", "connected", {
5057
5073
  windowId: this.windowId,
5058
5074
  browserId: this.browserId,
@@ -5281,11 +5297,11 @@ ${elementSummary}${moreText}`;
5281
5297
  this.respond(msg2.id, false, undefined, "Video capture requires the Haltija Desktop app. Run: npx haltija@latest -f");
5282
5298
  return;
5283
5299
  }
5284
- haltija.startVideoCapture({ maxDuration: payload2.maxDuration }).then((result2) => {
5285
- if (result2.success) {
5286
- this.respond(msg2.id, true, { recordingId: result2.recordingId });
5300
+ haltija.startVideoCapture({ maxDuration: payload2.maxDuration }).then((result) => {
5301
+ if (result.success) {
5302
+ this.respond(msg2.id, true, { recordingId: result.recordingId });
5287
5303
  } else {
5288
- this.respond(msg2.id, false, undefined, result2.error || "Failed to start video");
5304
+ this.respond(msg2.id, false, undefined, result.error || "Failed to start video");
5289
5305
  }
5290
5306
  }).catch((err) => {
5291
5307
  this.respond(msg2.id, false, undefined, `Failed to start video: ${err.message}`);
@@ -5295,11 +5311,11 @@ ${elementSummary}${moreText}`;
5295
5311
  this.respond(msg2.id, false, undefined, "Video capture requires the Haltija Desktop app. Run: npx haltija@latest -f");
5296
5312
  return;
5297
5313
  }
5298
- haltija.stopVideoCapture().then((result2) => {
5299
- if (result2.success) {
5300
- this.respond(msg2.id, true, { path: result2.path, duration: result2.duration, size: result2.size, format: result2.format });
5314
+ haltija.stopVideoCapture().then((result) => {
5315
+ if (result.success) {
5316
+ this.respond(msg2.id, true, { path: result.path, duration: result.duration, size: result.size, format: result.format });
5301
5317
  } else {
5302
- this.respond(msg2.id, false, undefined, result2.error || "Failed to stop video");
5318
+ this.respond(msg2.id, false, undefined, result.error || "Failed to stop video");
5303
5319
  }
5304
5320
  }).catch((err) => {
5305
5321
  this.respond(msg2.id, false, undefined, `Failed to stop video: ${err.message}`);
@@ -5309,8 +5325,8 @@ ${elementSummary}${moreText}`;
5309
5325
  this.respond(msg2.id, true, { recording: false });
5310
5326
  return;
5311
5327
  }
5312
- haltija.videoStatus().then((result2) => {
5313
- this.respond(msg2.id, true, result2);
5328
+ haltija.videoStatus().then((result) => {
5329
+ this.respond(msg2.id, true, result);
5314
5330
  }).catch(() => {
5315
5331
  this.respond(msg2.id, true, { recording: false });
5316
5332
  });
@@ -5327,8 +5343,8 @@ ${elementSummary}${moreText}`;
5327
5343
  this.respond(msg2.id, false, undefined, notAvailable);
5328
5344
  return;
5329
5345
  }
5330
- haltija.networkWatch(payload2 || {}).then((result2) => {
5331
- this.respond(msg2.id, result2.success !== false, result2);
5346
+ haltija.networkWatch(payload2 || {}).then((result) => {
5347
+ this.respond(msg2.id, result.success !== false, result);
5332
5348
  }).catch((err) => {
5333
5349
  this.respond(msg2.id, false, undefined, err.message);
5334
5350
  });
@@ -5337,8 +5353,8 @@ ${elementSummary}${moreText}`;
5337
5353
  this.respond(msg2.id, false, undefined, notAvailable);
5338
5354
  return;
5339
5355
  }
5340
- haltija.networkUnwatch().then((result2) => {
5341
- this.respond(msg2.id, true, result2);
5356
+ haltija.networkUnwatch().then((result) => {
5357
+ this.respond(msg2.id, true, result);
5342
5358
  }).catch((err) => {
5343
5359
  this.respond(msg2.id, false, undefined, err.message);
5344
5360
  });
@@ -5347,8 +5363,8 @@ ${elementSummary}${moreText}`;
5347
5363
  this.respond(msg2.id, false, undefined, notAvailable);
5348
5364
  return;
5349
5365
  }
5350
- haltija.networkLog(payload2 || {}).then((result2) => {
5351
- this.respond(msg2.id, true, result2);
5366
+ haltija.networkLog(payload2 || {}).then((result) => {
5367
+ this.respond(msg2.id, true, result);
5352
5368
  }).catch((err) => {
5353
5369
  this.respond(msg2.id, false, undefined, err.message);
5354
5370
  });
@@ -5357,8 +5373,8 @@ ${elementSummary}${moreText}`;
5357
5373
  this.respond(msg2.id, false, undefined, notAvailable);
5358
5374
  return;
5359
5375
  }
5360
- haltija.networkStats().then((result2) => {
5361
- this.respond(msg2.id, true, result2);
5376
+ haltija.networkStats().then((result) => {
5377
+ this.respond(msg2.id, true, result);
5362
5378
  }).catch((err) => {
5363
5379
  this.respond(msg2.id, false, undefined, err.message);
5364
5380
  });
@@ -5367,8 +5383,8 @@ ${elementSummary}${moreText}`;
5367
5383
  this.respond(msg2.id, false, undefined, notAvailable);
5368
5384
  return;
5369
5385
  }
5370
- haltija.networkClear().then((result2) => {
5371
- this.respond(msg2.id, true, result2);
5386
+ haltija.networkClear().then((result) => {
5387
+ this.respond(msg2.id, true, result);
5372
5388
  }).catch((err) => {
5373
5389
  this.respond(msg2.id, false, undefined, err.message);
5374
5390
  });
@@ -5814,9 +5830,9 @@ ${elementSummary}${moreText}`;
5814
5830
  try {
5815
5831
  const capturePromise = targetSelector ? haltija.captureElement(targetSelector) : haltija.capturePage();
5816
5832
  const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve({ success: false, error: "Screenshot capture timed out after 10s" }), 1e4));
5817
- const result2 = await Promise.race([capturePromise, timeoutPromise]);
5818
- if (result2?.success && result2.data) {
5819
- const converted = await convertFormat(result2.data);
5833
+ const result = await Promise.race([capturePromise, timeoutPromise]);
5834
+ if (result?.success && result.data) {
5835
+ const converted = await convertFormat(result.data);
5820
5836
  this.respond(msg2.id, true, {
5821
5837
  image: converted.image,
5822
5838
  viewport,
@@ -5826,8 +5842,8 @@ ${elementSummary}${moreText}`;
5826
5842
  source: "electron"
5827
5843
  });
5828
5844
  return;
5829
- } else if (result2 && !result2.success) {
5830
- this.respond(msg2.id, false, null, result2.error || "Electron capture failed");
5845
+ } else if (result && !result.success) {
5846
+ this.respond(msg2.id, false, null, result.error || "Electron capture failed");
5831
5847
  return;
5832
5848
  }
5833
5849
  } catch (err) {
@@ -5898,14 +5914,29 @@ ${elementSummary}${moreText}`;
5898
5914
  this.respond(msg2.id, true);
5899
5915
  }
5900
5916
  }
5901
- async handleEvalMessage(msg) {
5917
+ async handleEvalMessage(msg2) {
5902
5918
  try {
5903
- const result = eval(msg.payload.code);
5919
+ const result = this.evalCode(msg2.payload.code);
5904
5920
  const resolved = result instanceof Promise ? await result : result;
5905
- this.respond(msg.id, true, resolved);
5921
+ this.respond(msg2.id, true, resolved);
5922
+ } catch (err) {
5923
+ this.respond(msg2.id, false, null, err.message);
5924
+ }
5925
+ }
5926
+ evalCode(code) {
5927
+ try {
5928
+ return eval(code);
5929
+ } catch (err) {
5930
+ if (!(err instanceof SyntaxError) || !/\b(await|return)\b/.test(code))
5931
+ throw err;
5932
+ }
5933
+ try {
5934
+ return eval(`(async () => (${code}))()`);
5906
5935
  } catch (err) {
5907
- this.respond(msg.id, false, null, err.message);
5936
+ if (!(err instanceof SyntaxError))
5937
+ throw err;
5908
5938
  }
5939
+ return eval(`(async () => { ${code} })()`);
5909
5940
  }
5910
5941
  async handleFetchMessage(msg2) {
5911
5942
  const { url } = msg2.payload;
@@ -5983,14 +6014,14 @@ ${elementSummary}${moreText}`;
5983
6014
  let el = null;
5984
6015
  let targetDesc = "";
5985
6016
  if (ref) {
5986
- const result2 = refRegistry.resolveWithStatus(ref);
5987
- el = result2.element;
6017
+ const result = refRegistry.resolveWithStatus(ref);
6018
+ el = result.element;
5988
6019
  targetDesc = `@${ref}`;
5989
6020
  if (el) {
5990
6021
  stats.refsResolved++;
5991
6022
  } else {
5992
6023
  stats.refsStale++;
5993
- const errorMsg = result2.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result2.status === "removed_from_dom" ? `Ref @${ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${ref} is stale - element was garbage collected (try refreshing /tree)`;
6024
+ const errorMsg = result.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result.status === "removed_from_dom" ? `Ref @${ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${ref} is stale - element was garbage collected (try refreshing /tree)`;
5994
6025
  this.respond(responseId, false, null, errorMsg);
5995
6026
  return;
5996
6027
  }
@@ -6335,14 +6366,14 @@ ${elementSummary}${moreText}`;
6335
6366
  let el = null;
6336
6367
  let targetDesc = "";
6337
6368
  if (payload2.ref) {
6338
- const result2 = refRegistry.resolveWithStatus(payload2.ref);
6339
- el = result2.element;
6369
+ const result = refRegistry.resolveWithStatus(payload2.ref);
6370
+ el = result.element;
6340
6371
  targetDesc = `@${payload2.ref}`;
6341
6372
  if (el) {
6342
6373
  stats.refsResolved++;
6343
6374
  } else {
6344
6375
  stats.refsStale++;
6345
- const errorMsg = result2.status === "never_assigned" ? `Ref @${payload2.ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result2.status === "removed_from_dom" ? `Ref @${payload2.ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${payload2.ref} is stale - element was garbage collected (try refreshing /tree)`;
6376
+ const errorMsg = result.status === "never_assigned" ? `Ref @${payload2.ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result.status === "removed_from_dom" ? `Ref @${payload2.ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${payload2.ref} is stale - element was garbage collected (try refreshing /tree)`;
6346
6377
  this.respond(responseId, false, null, errorMsg);
6347
6378
  return;
6348
6379
  }
@@ -6411,15 +6442,15 @@ ${elementSummary}${moreText}`;
6411
6442
  let target = null;
6412
6443
  let targetDesc = "";
6413
6444
  if (ref) {
6414
- const result2 = refRegistry.resolveWithStatus(ref);
6415
- target = result2.element;
6445
+ const result = refRegistry.resolveWithStatus(ref);
6446
+ target = result.element;
6416
6447
  targetDesc = `@${ref}`;
6417
6448
  if (target) {
6418
6449
  stats.refsResolved++;
6419
6450
  target.focus();
6420
6451
  } else {
6421
6452
  stats.refsStale++;
6422
- const errorMsg = result2.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result2.status === "removed_from_dom" ? `Ref @${ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${ref} is stale - element was garbage collected (try refreshing /tree)`;
6453
+ const errorMsg = result.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result.status === "removed_from_dom" ? `Ref @${ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${ref} is stale - element was garbage collected (try refreshing /tree)`;
6423
6454
  this.respond(responseId, false, null, errorMsg);
6424
6455
  return;
6425
6456
  }
@@ -6811,9 +6842,9 @@ ${elementSummary}${moreText}`;
6811
6842
  });
6812
6843
  } else if (action2 === "result") {
6813
6844
  if (this.selectionResult) {
6814
- const result2 = this.selectionResult;
6845
+ const result = this.selectionResult;
6815
6846
  this.clearSelection();
6816
- this.respond(msg2.id, true, result2);
6847
+ this.respond(msg2.id, true, result);
6817
6848
  } else {
6818
6849
  this.respond(msg2.id, false, null, "No selection available");
6819
6850
  }