haltija 1.3.3 → 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.
package/dist/index.js CHANGED
@@ -674,7 +674,7 @@ var injectorCode = `
674
674
  `;
675
675
 
676
676
  // src/version.ts
677
- var VERSION = "1.3.3";
677
+ var VERSION = "1.3.4";
678
678
 
679
679
  // src/embedded-assets.ts
680
680
  var APP_MD = `# Haltija App
@@ -2485,7 +2485,14 @@ Great for debugging - check for errors after actions fail.
2485
2485
  Run arbitrary JavaScript in the browser context. Returns the result.
2486
2486
 
2487
2487
  The code runs in the page's context with access to window, document, etc.
2488
- Return values are JSON-serialized. Promises are awaited.
2488
+ Return values are JSON-serialized.
2489
+
2490
+ Async code is supported: a returned Promise is awaited, and top-level \`await\`
2491
+ works. Multi-statement code needs an explicit \`return\` to produce a value.
2492
+
2493
+ document.title -> the title
2494
+ await fetch('/api').then(r => r.json()) -> the parsed body
2495
+ const r = await fetch('/api'); return r.status -> the status code
2489
2496
 
2490
2497
  **Parameters:**
2491
2498
 
@@ -3021,7 +3028,7 @@ var COMPONENT_JS = `(() => {
3021
3028
  });
3022
3029
 
3023
3030
  // src/version.ts
3024
- var VERSION = "1.3.3";
3031
+ var VERSION = "1.3.4";
3025
3032
 
3026
3033
  // src/text-selector.ts
3027
3034
  var TEXT_PSEUDO_RE = /:(?:text-is|has-text|text)\\(/;
@@ -3573,13 +3580,13 @@ var COMPONENT_JS = `(() => {
3573
3580
  }
3574
3581
  function resolveRefOrSelector(ref, selector) {
3575
3582
  if (ref) {
3576
- const result2 = refRegistry.resolveWithStatus(ref);
3577
- if (result2.element) {
3583
+ const result = refRegistry.resolveWithStatus(ref);
3584
+ if (result.element) {
3578
3585
  stats.refsResolved++;
3579
- return { element: result2.element, targetDesc: \`@\${ref}\` };
3586
+ return { element: result.element, targetDesc: \`@\${ref}\` };
3580
3587
  }
3581
3588
  stats.refsStale++;
3582
- 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)\`;
3589
+ 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)\`;
3583
3590
  return { element: null, targetDesc: \`@\${ref}\`, error: errorMsg };
3584
3591
  }
3585
3592
  if (selector) {
@@ -3590,13 +3597,13 @@ var COMPONENT_JS = `(() => {
3590
3597
  }
3591
3598
  function resolveRefOrSelectorAll(ref, selector) {
3592
3599
  if (ref) {
3593
- const result2 = refRegistry.resolveWithStatus(ref);
3594
- if (result2.element) {
3600
+ const result = refRegistry.resolveWithStatus(ref);
3601
+ if (result.element) {
3595
3602
  stats.refsResolved++;
3596
- return { elements: [result2.element], targetDesc: \`@\${ref}\` };
3603
+ return { elements: [result.element], targetDesc: \`@\${ref}\` };
3597
3604
  }
3598
3605
  stats.refsStale++;
3599
- 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)\`;
3606
+ 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)\`;
3600
3607
  return { elements: [], targetDesc: \`@\${ref}\`, error: errorMsg };
3601
3608
  }
3602
3609
  if (selector) {
@@ -5845,8 +5852,8 @@ var COMPONENT_JS = `(() => {
5845
5852
  headers: { "Content-Type": "application/json" },
5846
5853
  body: JSON.stringify({ action: "start", window: this.windowId })
5847
5854
  });
5848
- const result2 = await response.json();
5849
- if (result2.success) {
5855
+ const result = await response.json();
5856
+ if (result.success) {
5850
5857
  this.isRecording = true;
5851
5858
  this.serverManagedRecording = true;
5852
5859
  this.recordingStartTime = Date.now();
@@ -5858,7 +5865,7 @@ var COMPONENT_JS = `(() => {
5858
5865
  this.updateRecordingUI(true);
5859
5866
  console.log("[Haltija] Recording started (server-managed)");
5860
5867
  } else {
5861
- console.error("[Haltija] Failed to start recording:", result2.error);
5868
+ console.error("[Haltija] Failed to start recording:", result.error);
5862
5869
  }
5863
5870
  } catch (err) {
5864
5871
  console.error("[Haltija] Failed to start recording:", err);
@@ -5873,10 +5880,10 @@ var COMPONENT_JS = `(() => {
5873
5880
  headers: { "Content-Type": "application/json" },
5874
5881
  body: JSON.stringify({ action: "stop", window: this.windowId })
5875
5882
  });
5876
- const result2 = await response.json();
5877
- if (result2.success && result2.data) {
5878
- this.recordingEvents = result2.data.events || [];
5879
- this.recordingStartTime = result2.data.startTime || this.recordingStartTime;
5883
+ const result = await response.json();
5884
+ if (result.success && result.data) {
5885
+ this.recordingEvents = result.data.events || [];
5886
+ this.recordingStartTime = result.data.startTime || this.recordingStartTime;
5880
5887
  const recordingId = \`rec_\${this.recordingStartTime}_\${Math.random().toString(36).slice(2, 8)}\`;
5881
5888
  this.lastRecordingId = recordingId;
5882
5889
  console.log(\`[Haltija] Recording stopped (\${this.recordingEvents.length} events)\`);
@@ -6189,15 +6196,15 @@ var COMPONENT_JS = `(() => {
6189
6196
  headers: { "Content-Type": "application/json" },
6190
6197
  body: JSON.stringify({ description, agentId })
6191
6198
  });
6192
- const result2 = await response.json();
6193
- if (result2.error) {
6199
+ const result = await response.json();
6200
+ if (result.error) {
6194
6201
  if (successMsg) {
6195
- successMsg.textContent = \`\u26A0\uFE0F \${result2.error}\`;
6202
+ successMsg.textContent = \`\u26A0\uFE0F \${result.error}\`;
6196
6203
  successMsg.style.color = "#f59e0b";
6197
6204
  }
6198
6205
  } else {
6199
6206
  if (successMsg) {
6200
- successMsg.textContent = \`\u2713 Sent to \${agentName}\${result2.interrupted ? " (interrupted)" : ""}\`;
6207
+ successMsg.textContent = \`\u2713 Sent to \${agentName}\${result.interrupted ? " (interrupted)" : ""}\`;
6201
6208
  successMsg.style.color = "#22c55e";
6202
6209
  }
6203
6210
  setTimeout(() => this.closeTestModal(), 1500);
@@ -6728,13 +6735,13 @@ var COMPONENT_JS = `(() => {
6728
6735
  const haltija = window.haltija;
6729
6736
  if (haltija?.openAgentTab) {
6730
6737
  newAgentText.textContent = "Creating...";
6731
- const result2 = await haltija.openAgentTab();
6732
- if (result2?.shellId) {
6738
+ const result = await haltija.openAgentTab();
6739
+ if (result?.shellId) {
6733
6740
  await new Promise((r) => setTimeout(r, 300));
6734
6741
  if (type === "selection") {
6735
- this.sendSelectionToAgent(result2.shellId, result2.name || "agent");
6742
+ this.sendSelectionToAgent(result.shellId, result.name || "agent");
6736
6743
  } else if (type === "recording") {
6737
- this.sendRecordingToAgent(result2.shellId, result2.name || "agent");
6744
+ this.sendRecordingToAgent(result.shellId, result.name || "agent");
6738
6745
  }
6739
6746
  } else {
6740
6747
  console.error(\`\${LOG_PREFIX} Failed to create agent tab\`);
@@ -6803,8 +6810,8 @@ var COMPONENT_JS = `(() => {
6803
6810
  context: \`selection from \${window.location.host}\`
6804
6811
  })
6805
6812
  });
6806
- const result2 = await response.json();
6807
- if (result2.sent) {
6813
+ const result = await response.json();
6814
+ if (result.sent) {
6808
6815
  this.clearSelection();
6809
6816
  console.log(\`\${LOG_PREFIX} Selection sent to \${agentName}\`);
6810
6817
  }
@@ -8319,11 +8326,11 @@ var COMPONENT_JS = `(() => {
8319
8326
  this.respond(msg2.id, false, undefined, "Video capture requires the Haltija Desktop app. Run: npx haltija@latest -f");
8320
8327
  return;
8321
8328
  }
8322
- haltija.startVideoCapture({ maxDuration: payload2.maxDuration }).then((result2) => {
8323
- if (result2.success) {
8324
- this.respond(msg2.id, true, { recordingId: result2.recordingId });
8329
+ haltija.startVideoCapture({ maxDuration: payload2.maxDuration }).then((result) => {
8330
+ if (result.success) {
8331
+ this.respond(msg2.id, true, { recordingId: result.recordingId });
8325
8332
  } else {
8326
- this.respond(msg2.id, false, undefined, result2.error || "Failed to start video");
8333
+ this.respond(msg2.id, false, undefined, result.error || "Failed to start video");
8327
8334
  }
8328
8335
  }).catch((err) => {
8329
8336
  this.respond(msg2.id, false, undefined, \`Failed to start video: \${err.message}\`);
@@ -8333,11 +8340,11 @@ var COMPONENT_JS = `(() => {
8333
8340
  this.respond(msg2.id, false, undefined, "Video capture requires the Haltija Desktop app. Run: npx haltija@latest -f");
8334
8341
  return;
8335
8342
  }
8336
- haltija.stopVideoCapture().then((result2) => {
8337
- if (result2.success) {
8338
- this.respond(msg2.id, true, { path: result2.path, duration: result2.duration, size: result2.size, format: result2.format });
8343
+ haltija.stopVideoCapture().then((result) => {
8344
+ if (result.success) {
8345
+ this.respond(msg2.id, true, { path: result.path, duration: result.duration, size: result.size, format: result.format });
8339
8346
  } else {
8340
- this.respond(msg2.id, false, undefined, result2.error || "Failed to stop video");
8347
+ this.respond(msg2.id, false, undefined, result.error || "Failed to stop video");
8341
8348
  }
8342
8349
  }).catch((err) => {
8343
8350
  this.respond(msg2.id, false, undefined, \`Failed to stop video: \${err.message}\`);
@@ -8347,8 +8354,8 @@ var COMPONENT_JS = `(() => {
8347
8354
  this.respond(msg2.id, true, { recording: false });
8348
8355
  return;
8349
8356
  }
8350
- haltija.videoStatus().then((result2) => {
8351
- this.respond(msg2.id, true, result2);
8357
+ haltija.videoStatus().then((result) => {
8358
+ this.respond(msg2.id, true, result);
8352
8359
  }).catch(() => {
8353
8360
  this.respond(msg2.id, true, { recording: false });
8354
8361
  });
@@ -8365,8 +8372,8 @@ var COMPONENT_JS = `(() => {
8365
8372
  this.respond(msg2.id, false, undefined, notAvailable);
8366
8373
  return;
8367
8374
  }
8368
- haltija.networkWatch(payload2 || {}).then((result2) => {
8369
- this.respond(msg2.id, result2.success !== false, result2);
8375
+ haltija.networkWatch(payload2 || {}).then((result) => {
8376
+ this.respond(msg2.id, result.success !== false, result);
8370
8377
  }).catch((err) => {
8371
8378
  this.respond(msg2.id, false, undefined, err.message);
8372
8379
  });
@@ -8375,8 +8382,8 @@ var COMPONENT_JS = `(() => {
8375
8382
  this.respond(msg2.id, false, undefined, notAvailable);
8376
8383
  return;
8377
8384
  }
8378
- haltija.networkUnwatch().then((result2) => {
8379
- this.respond(msg2.id, true, result2);
8385
+ haltija.networkUnwatch().then((result) => {
8386
+ this.respond(msg2.id, true, result);
8380
8387
  }).catch((err) => {
8381
8388
  this.respond(msg2.id, false, undefined, err.message);
8382
8389
  });
@@ -8385,8 +8392,8 @@ var COMPONENT_JS = `(() => {
8385
8392
  this.respond(msg2.id, false, undefined, notAvailable);
8386
8393
  return;
8387
8394
  }
8388
- haltija.networkLog(payload2 || {}).then((result2) => {
8389
- this.respond(msg2.id, true, result2);
8395
+ haltija.networkLog(payload2 || {}).then((result) => {
8396
+ this.respond(msg2.id, true, result);
8390
8397
  }).catch((err) => {
8391
8398
  this.respond(msg2.id, false, undefined, err.message);
8392
8399
  });
@@ -8395,8 +8402,8 @@ var COMPONENT_JS = `(() => {
8395
8402
  this.respond(msg2.id, false, undefined, notAvailable);
8396
8403
  return;
8397
8404
  }
8398
- haltija.networkStats().then((result2) => {
8399
- this.respond(msg2.id, true, result2);
8405
+ haltija.networkStats().then((result) => {
8406
+ this.respond(msg2.id, true, result);
8400
8407
  }).catch((err) => {
8401
8408
  this.respond(msg2.id, false, undefined, err.message);
8402
8409
  });
@@ -8405,8 +8412,8 @@ var COMPONENT_JS = `(() => {
8405
8412
  this.respond(msg2.id, false, undefined, notAvailable);
8406
8413
  return;
8407
8414
  }
8408
- haltija.networkClear().then((result2) => {
8409
- this.respond(msg2.id, true, result2);
8415
+ haltija.networkClear().then((result) => {
8416
+ this.respond(msg2.id, true, result);
8410
8417
  }).catch((err) => {
8411
8418
  this.respond(msg2.id, false, undefined, err.message);
8412
8419
  });
@@ -8852,9 +8859,9 @@ var COMPONENT_JS = `(() => {
8852
8859
  try {
8853
8860
  const capturePromise = targetSelector ? haltija.captureElement(targetSelector) : haltija.capturePage();
8854
8861
  const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve({ success: false, error: "Screenshot capture timed out after 10s" }), 1e4));
8855
- const result2 = await Promise.race([capturePromise, timeoutPromise]);
8856
- if (result2?.success && result2.data) {
8857
- const converted = await convertFormat(result2.data);
8862
+ const result = await Promise.race([capturePromise, timeoutPromise]);
8863
+ if (result?.success && result.data) {
8864
+ const converted = await convertFormat(result.data);
8858
8865
  this.respond(msg2.id, true, {
8859
8866
  image: converted.image,
8860
8867
  viewport,
@@ -8864,8 +8871,8 @@ var COMPONENT_JS = `(() => {
8864
8871
  source: "electron"
8865
8872
  });
8866
8873
  return;
8867
- } else if (result2 && !result2.success) {
8868
- this.respond(msg2.id, false, null, result2.error || "Electron capture failed");
8874
+ } else if (result && !result.success) {
8875
+ this.respond(msg2.id, false, null, result.error || "Electron capture failed");
8869
8876
  return;
8870
8877
  }
8871
8878
  } catch (err) {
@@ -8936,15 +8943,30 @@ var COMPONENT_JS = `(() => {
8936
8943
  this.respond(msg2.id, true);
8937
8944
  }
8938
8945
  }
8939
- async handleEvalMessage(msg) {
8946
+ async handleEvalMessage(msg2) {
8940
8947
  try {
8941
- const result = eval(msg.payload.code);
8948
+ const result = this.evalCode(msg2.payload.code);
8942
8949
  const resolved = result instanceof Promise ? await result : result;
8943
- this.respond(msg.id, true, resolved);
8950
+ this.respond(msg2.id, true, resolved);
8944
8951
  } catch (err) {
8945
- this.respond(msg.id, false, null, err.message);
8952
+ this.respond(msg2.id, false, null, err.message);
8946
8953
  }
8947
8954
  }
8955
+ evalCode(code) {
8956
+ try {
8957
+ return eval(code);
8958
+ } catch (err) {
8959
+ if (!(err instanceof SyntaxError) || !/\\b(await|return)\\b/.test(code))
8960
+ throw err;
8961
+ }
8962
+ try {
8963
+ return eval(\`(async () => (\${code}))()\`);
8964
+ } catch (err) {
8965
+ if (!(err instanceof SyntaxError))
8966
+ throw err;
8967
+ }
8968
+ return eval(\`(async () => { \${code} })()\`);
8969
+ }
8948
8970
  async handleFetchMessage(msg2) {
8949
8971
  const { url } = msg2.payload;
8950
8972
  if (!url) {
@@ -9021,14 +9043,14 @@ var COMPONENT_JS = `(() => {
9021
9043
  let el = null;
9022
9044
  let targetDesc = "";
9023
9045
  if (ref) {
9024
- const result2 = refRegistry.resolveWithStatus(ref);
9025
- el = result2.element;
9046
+ const result = refRegistry.resolveWithStatus(ref);
9047
+ el = result.element;
9026
9048
  targetDesc = \`@\${ref}\`;
9027
9049
  if (el) {
9028
9050
  stats.refsResolved++;
9029
9051
  } else {
9030
9052
  stats.refsStale++;
9031
- 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)\`;
9053
+ 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)\`;
9032
9054
  this.respond(responseId, false, null, errorMsg);
9033
9055
  return;
9034
9056
  }
@@ -9373,14 +9395,14 @@ var COMPONENT_JS = `(() => {
9373
9395
  let el = null;
9374
9396
  let targetDesc = "";
9375
9397
  if (payload2.ref) {
9376
- const result2 = refRegistry.resolveWithStatus(payload2.ref);
9377
- el = result2.element;
9398
+ const result = refRegistry.resolveWithStatus(payload2.ref);
9399
+ el = result.element;
9378
9400
  targetDesc = \`@\${payload2.ref}\`;
9379
9401
  if (el) {
9380
9402
  stats.refsResolved++;
9381
9403
  } else {
9382
9404
  stats.refsStale++;
9383
- 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)\`;
9405
+ 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)\`;
9384
9406
  this.respond(responseId, false, null, errorMsg);
9385
9407
  return;
9386
9408
  }
@@ -9449,15 +9471,15 @@ var COMPONENT_JS = `(() => {
9449
9471
  let target = null;
9450
9472
  let targetDesc = "";
9451
9473
  if (ref) {
9452
- const result2 = refRegistry.resolveWithStatus(ref);
9453
- target = result2.element;
9474
+ const result = refRegistry.resolveWithStatus(ref);
9475
+ target = result.element;
9454
9476
  targetDesc = \`@\${ref}\`;
9455
9477
  if (target) {
9456
9478
  stats.refsResolved++;
9457
9479
  target.focus();
9458
9480
  } else {
9459
9481
  stats.refsStale++;
9460
- 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)\`;
9482
+ 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)\`;
9461
9483
  this.respond(responseId, false, null, errorMsg);
9462
9484
  return;
9463
9485
  }
@@ -9849,9 +9871,9 @@ var COMPONENT_JS = `(() => {
9849
9871
  });
9850
9872
  } else if (action2 === "result") {
9851
9873
  if (this.selectionResult) {
9852
- const result2 = this.selectionResult;
9874
+ const result = this.selectionResult;
9853
9875
  this.clearSelection();
9854
- this.respond(msg2.id, true, result2);
9876
+ this.respond(msg2.id, true, result);
9855
9877
  } else {
9856
9878
  this.respond(msg2.id, false, null, "No selection available");
9857
9879
  }
@@ -11112,7 +11134,17 @@ ${isElectronApp ? "" : ` <script>
11112
11134
  document.getElementById('tab-' + tabId).classList.add('active');
11113
11135
  });
11114
11136
  });
11115
-
11137
+
11138
+ // Deep-link to a tab via ?tab=<name>. Lets tests (and links) land directly
11139
+ // on a tab instead of relying on a click landing right after navigation \u2014
11140
+ // which raced under headless CI.
11141
+ (function() {
11142
+ var wanted = new URLSearchParams(location.search).get('tab');
11143
+ if (!wanted) return;
11144
+ var btn = document.querySelector('.tab[data-tab="' + wanted + '"]');
11145
+ if (btn) btn.click();
11146
+ })();
11147
+
11116
11148
  // Copy button functionality
11117
11149
  function copyCode(btn) {
11118
11150
  var pre = btn.parentElement.querySelector('pre');
@@ -12380,7 +12412,14 @@ var eval_ = endpoint({
12380
12412
  description: `Run arbitrary JavaScript in the browser context. Returns the result.
12381
12413
 
12382
12414
  The code runs in the page's context with access to window, document, etc.
12383
- Return values are JSON-serialized. Promises are awaited.`,
12415
+ Return values are JSON-serialized.
12416
+
12417
+ Async code is supported: a returned Promise is awaited, and top-level \`await\`
12418
+ works. Multi-statement code needs an explicit \`return\` to produce a value.
12419
+
12420
+ document.title -> the title
12421
+ await fetch('/api').then(r => r.json()) -> the parsed body
12422
+ const r = await fetch('/api'); return r.status -> the status code`,
12384
12423
  category: "debug",
12385
12424
  input: L.object({
12386
12425
  code: L.string.describe("JavaScript code to execute"),