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.
- package/apps/desktop/package.json +1 -1
- package/apps/desktop/resources/component.js +97 -66
- package/dist/api-schema.d.ts +6 -0
- package/dist/component.d.ts +13 -1
- package/dist/component.esm.js +97 -66
- package/dist/component.js +97 -66
- package/dist/index.js +138 -72
- package/dist/server.js +138 -72
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
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.
|
|
677
|
+
var VERSION = "1.3.4";
|
|
678
678
|
|
|
679
679
|
// src/embedded-assets.ts
|
|
680
680
|
var APP_MD = `# Haltija App
|
|
@@ -1086,6 +1086,8 @@ Use ancestors:true to see parent elements when inspecting deep elements.
|
|
|
1086
1086
|
| \`pierceFrames\` | boolean,null | Pierce same-origin iframes (default true) |
|
|
1087
1087
|
| \`compact\` | boolean,null | Minimal output (default false) |
|
|
1088
1088
|
| \`ancestors\` | boolean,null | Include ancestor path from root (default false) |
|
|
1089
|
+
| \`includeBox\` | boolean,null | Include each node's bounding box { x, y, w, h, visible } (default false) |
|
|
1090
|
+
| \`mode\` | string,null | 'actionable' returns a page action summary (url, title, headings, buttons, links, inputs, selects) instead of the DOM tree |
|
|
1089
1091
|
| \`window\` | string,null | Target window ID |
|
|
1090
1092
|
|
|
1091
1093
|
**Examples:**
|
|
@@ -2483,7 +2485,14 @@ Great for debugging - check for errors after actions fail.
|
|
|
2483
2485
|
Run arbitrary JavaScript in the browser context. Returns the result.
|
|
2484
2486
|
|
|
2485
2487
|
The code runs in the page's context with access to window, document, etc.
|
|
2486
|
-
Return values are JSON-serialized.
|
|
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
|
|
2487
2496
|
|
|
2488
2497
|
**Parameters:**
|
|
2489
2498
|
|
|
@@ -3019,7 +3028,7 @@ var COMPONENT_JS = `(() => {
|
|
|
3019
3028
|
});
|
|
3020
3029
|
|
|
3021
3030
|
// src/version.ts
|
|
3022
|
-
var VERSION = "1.3.
|
|
3031
|
+
var VERSION = "1.3.4";
|
|
3023
3032
|
|
|
3024
3033
|
// src/text-selector.ts
|
|
3025
3034
|
var TEXT_PSEUDO_RE = /:(?:text-is|has-text|text)\\(/;
|
|
@@ -3571,13 +3580,13 @@ var COMPONENT_JS = `(() => {
|
|
|
3571
3580
|
}
|
|
3572
3581
|
function resolveRefOrSelector(ref, selector) {
|
|
3573
3582
|
if (ref) {
|
|
3574
|
-
const
|
|
3575
|
-
if (
|
|
3583
|
+
const result = refRegistry.resolveWithStatus(ref);
|
|
3584
|
+
if (result.element) {
|
|
3576
3585
|
stats.refsResolved++;
|
|
3577
|
-
return { element:
|
|
3586
|
+
return { element: result.element, targetDesc: \`@\${ref}\` };
|
|
3578
3587
|
}
|
|
3579
3588
|
stats.refsStale++;
|
|
3580
|
-
const errorMsg =
|
|
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)\`;
|
|
3581
3590
|
return { element: null, targetDesc: \`@\${ref}\`, error: errorMsg };
|
|
3582
3591
|
}
|
|
3583
3592
|
if (selector) {
|
|
@@ -3588,13 +3597,13 @@ var COMPONENT_JS = `(() => {
|
|
|
3588
3597
|
}
|
|
3589
3598
|
function resolveRefOrSelectorAll(ref, selector) {
|
|
3590
3599
|
if (ref) {
|
|
3591
|
-
const
|
|
3592
|
-
if (
|
|
3600
|
+
const result = refRegistry.resolveWithStatus(ref);
|
|
3601
|
+
if (result.element) {
|
|
3593
3602
|
stats.refsResolved++;
|
|
3594
|
-
return { elements: [
|
|
3603
|
+
return { elements: [result.element], targetDesc: \`@\${ref}\` };
|
|
3595
3604
|
}
|
|
3596
3605
|
stats.refsStale++;
|
|
3597
|
-
const errorMsg =
|
|
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)\`;
|
|
3598
3607
|
return { elements: [], targetDesc: \`@\${ref}\`, error: errorMsg };
|
|
3599
3608
|
}
|
|
3600
3609
|
if (selector) {
|
|
@@ -4734,6 +4743,7 @@ var COMPONENT_JS = `(() => {
|
|
|
4734
4743
|
displayStream = null;
|
|
4735
4744
|
displayVideo = null;
|
|
4736
4745
|
isActive = true;
|
|
4746
|
+
visibilityHandler = null;
|
|
4737
4747
|
homeLeft = 0;
|
|
4738
4748
|
homeBottom = 16;
|
|
4739
4749
|
headless = false;
|
|
@@ -4925,6 +4935,16 @@ var COMPONENT_JS = `(() => {
|
|
|
4925
4935
|
}
|
|
4926
4936
|
this.interceptConsole();
|
|
4927
4937
|
this.interceptDialogs();
|
|
4938
|
+
if (typeof document !== "undefined") {
|
|
4939
|
+
this.visibilityHandler = () => {
|
|
4940
|
+
if (document.visibilityState === "hidden") {
|
|
4941
|
+
this.deactivate();
|
|
4942
|
+
} else {
|
|
4943
|
+
this.activate();
|
|
4944
|
+
}
|
|
4945
|
+
};
|
|
4946
|
+
document.addEventListener("visibilitychange", this.visibilityHandler);
|
|
4947
|
+
}
|
|
4928
4948
|
this.connect();
|
|
4929
4949
|
}
|
|
4930
4950
|
disconnectedCallback() {
|
|
@@ -4935,6 +4955,10 @@ var COMPONENT_JS = `(() => {
|
|
|
4935
4955
|
this.clearEventWatchers();
|
|
4936
4956
|
this.stopMutationWatch();
|
|
4937
4957
|
this.stopScreenCapture();
|
|
4958
|
+
if (this.visibilityHandler && typeof document !== "undefined") {
|
|
4959
|
+
document.removeEventListener("visibilitychange", this.visibilityHandler);
|
|
4960
|
+
this.visibilityHandler = null;
|
|
4961
|
+
}
|
|
4938
4962
|
}
|
|
4939
4963
|
attributeChangedCallback(name, _old, value) {
|
|
4940
4964
|
if (name === "server") {
|
|
@@ -5828,8 +5852,8 @@ var COMPONENT_JS = `(() => {
|
|
|
5828
5852
|
headers: { "Content-Type": "application/json" },
|
|
5829
5853
|
body: JSON.stringify({ action: "start", window: this.windowId })
|
|
5830
5854
|
});
|
|
5831
|
-
const
|
|
5832
|
-
if (
|
|
5855
|
+
const result = await response.json();
|
|
5856
|
+
if (result.success) {
|
|
5833
5857
|
this.isRecording = true;
|
|
5834
5858
|
this.serverManagedRecording = true;
|
|
5835
5859
|
this.recordingStartTime = Date.now();
|
|
@@ -5841,7 +5865,7 @@ var COMPONENT_JS = `(() => {
|
|
|
5841
5865
|
this.updateRecordingUI(true);
|
|
5842
5866
|
console.log("[Haltija] Recording started (server-managed)");
|
|
5843
5867
|
} else {
|
|
5844
|
-
console.error("[Haltija] Failed to start recording:",
|
|
5868
|
+
console.error("[Haltija] Failed to start recording:", result.error);
|
|
5845
5869
|
}
|
|
5846
5870
|
} catch (err) {
|
|
5847
5871
|
console.error("[Haltija] Failed to start recording:", err);
|
|
@@ -5856,10 +5880,10 @@ var COMPONENT_JS = `(() => {
|
|
|
5856
5880
|
headers: { "Content-Type": "application/json" },
|
|
5857
5881
|
body: JSON.stringify({ action: "stop", window: this.windowId })
|
|
5858
5882
|
});
|
|
5859
|
-
const
|
|
5860
|
-
if (
|
|
5861
|
-
this.recordingEvents =
|
|
5862
|
-
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;
|
|
5863
5887
|
const recordingId = \`rec_\${this.recordingStartTime}_\${Math.random().toString(36).slice(2, 8)}\`;
|
|
5864
5888
|
this.lastRecordingId = recordingId;
|
|
5865
5889
|
console.log(\`[Haltija] Recording stopped (\${this.recordingEvents.length} events)\`);
|
|
@@ -6172,15 +6196,15 @@ var COMPONENT_JS = `(() => {
|
|
|
6172
6196
|
headers: { "Content-Type": "application/json" },
|
|
6173
6197
|
body: JSON.stringify({ description, agentId })
|
|
6174
6198
|
});
|
|
6175
|
-
const
|
|
6176
|
-
if (
|
|
6199
|
+
const result = await response.json();
|
|
6200
|
+
if (result.error) {
|
|
6177
6201
|
if (successMsg) {
|
|
6178
|
-
successMsg.textContent = \`\u26A0\uFE0F \${
|
|
6202
|
+
successMsg.textContent = \`\u26A0\uFE0F \${result.error}\`;
|
|
6179
6203
|
successMsg.style.color = "#f59e0b";
|
|
6180
6204
|
}
|
|
6181
6205
|
} else {
|
|
6182
6206
|
if (successMsg) {
|
|
6183
|
-
successMsg.textContent = \`\u2713 Sent to \${agentName}\${
|
|
6207
|
+
successMsg.textContent = \`\u2713 Sent to \${agentName}\${result.interrupted ? " (interrupted)" : ""}\`;
|
|
6184
6208
|
successMsg.style.color = "#22c55e";
|
|
6185
6209
|
}
|
|
6186
6210
|
setTimeout(() => this.closeTestModal(), 1500);
|
|
@@ -6711,13 +6735,13 @@ var COMPONENT_JS = `(() => {
|
|
|
6711
6735
|
const haltija = window.haltija;
|
|
6712
6736
|
if (haltija?.openAgentTab) {
|
|
6713
6737
|
newAgentText.textContent = "Creating...";
|
|
6714
|
-
const
|
|
6715
|
-
if (
|
|
6738
|
+
const result = await haltija.openAgentTab();
|
|
6739
|
+
if (result?.shellId) {
|
|
6716
6740
|
await new Promise((r) => setTimeout(r, 300));
|
|
6717
6741
|
if (type === "selection") {
|
|
6718
|
-
this.sendSelectionToAgent(
|
|
6742
|
+
this.sendSelectionToAgent(result.shellId, result.name || "agent");
|
|
6719
6743
|
} else if (type === "recording") {
|
|
6720
|
-
this.sendRecordingToAgent(
|
|
6744
|
+
this.sendRecordingToAgent(result.shellId, result.name || "agent");
|
|
6721
6745
|
}
|
|
6722
6746
|
} else {
|
|
6723
6747
|
console.error(\`\${LOG_PREFIX} Failed to create agent tab\`);
|
|
@@ -6786,8 +6810,8 @@ var COMPONENT_JS = `(() => {
|
|
|
6786
6810
|
context: \`selection from \${window.location.host}\`
|
|
6787
6811
|
})
|
|
6788
6812
|
});
|
|
6789
|
-
const
|
|
6790
|
-
if (
|
|
6813
|
+
const result = await response.json();
|
|
6814
|
+
if (result.sent) {
|
|
6791
6815
|
this.clearSelection();
|
|
6792
6816
|
console.log(\`\${LOG_PREFIX} Selection sent to \${agentName}\`);
|
|
6793
6817
|
}
|
|
@@ -8073,6 +8097,7 @@ var COMPONENT_JS = `(() => {
|
|
|
8073
8097
|
this.state = "connected";
|
|
8074
8098
|
this.show();
|
|
8075
8099
|
const windowType = window.opener ? "popup" : window.parent !== window ? "iframe" : "tab";
|
|
8100
|
+
this.isActive = typeof document === "undefined" || document.visibilityState !== "hidden";
|
|
8076
8101
|
this.send("system", "connected", {
|
|
8077
8102
|
windowId: this.windowId,
|
|
8078
8103
|
browserId: this.browserId,
|
|
@@ -8301,11 +8326,11 @@ var COMPONENT_JS = `(() => {
|
|
|
8301
8326
|
this.respond(msg2.id, false, undefined, "Video capture requires the Haltija Desktop app. Run: npx haltija@latest -f");
|
|
8302
8327
|
return;
|
|
8303
8328
|
}
|
|
8304
|
-
haltija.startVideoCapture({ maxDuration: payload2.maxDuration }).then((
|
|
8305
|
-
if (
|
|
8306
|
-
this.respond(msg2.id, true, { recordingId:
|
|
8329
|
+
haltija.startVideoCapture({ maxDuration: payload2.maxDuration }).then((result) => {
|
|
8330
|
+
if (result.success) {
|
|
8331
|
+
this.respond(msg2.id, true, { recordingId: result.recordingId });
|
|
8307
8332
|
} else {
|
|
8308
|
-
this.respond(msg2.id, false, undefined,
|
|
8333
|
+
this.respond(msg2.id, false, undefined, result.error || "Failed to start video");
|
|
8309
8334
|
}
|
|
8310
8335
|
}).catch((err) => {
|
|
8311
8336
|
this.respond(msg2.id, false, undefined, \`Failed to start video: \${err.message}\`);
|
|
@@ -8315,11 +8340,11 @@ var COMPONENT_JS = `(() => {
|
|
|
8315
8340
|
this.respond(msg2.id, false, undefined, "Video capture requires the Haltija Desktop app. Run: npx haltija@latest -f");
|
|
8316
8341
|
return;
|
|
8317
8342
|
}
|
|
8318
|
-
haltija.stopVideoCapture().then((
|
|
8319
|
-
if (
|
|
8320
|
-
this.respond(msg2.id, true, { path:
|
|
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 });
|
|
8321
8346
|
} else {
|
|
8322
|
-
this.respond(msg2.id, false, undefined,
|
|
8347
|
+
this.respond(msg2.id, false, undefined, result.error || "Failed to stop video");
|
|
8323
8348
|
}
|
|
8324
8349
|
}).catch((err) => {
|
|
8325
8350
|
this.respond(msg2.id, false, undefined, \`Failed to stop video: \${err.message}\`);
|
|
@@ -8329,8 +8354,8 @@ var COMPONENT_JS = `(() => {
|
|
|
8329
8354
|
this.respond(msg2.id, true, { recording: false });
|
|
8330
8355
|
return;
|
|
8331
8356
|
}
|
|
8332
|
-
haltija.videoStatus().then((
|
|
8333
|
-
this.respond(msg2.id, true,
|
|
8357
|
+
haltija.videoStatus().then((result) => {
|
|
8358
|
+
this.respond(msg2.id, true, result);
|
|
8334
8359
|
}).catch(() => {
|
|
8335
8360
|
this.respond(msg2.id, true, { recording: false });
|
|
8336
8361
|
});
|
|
@@ -8347,8 +8372,8 @@ var COMPONENT_JS = `(() => {
|
|
|
8347
8372
|
this.respond(msg2.id, false, undefined, notAvailable);
|
|
8348
8373
|
return;
|
|
8349
8374
|
}
|
|
8350
|
-
haltija.networkWatch(payload2 || {}).then((
|
|
8351
|
-
this.respond(msg2.id,
|
|
8375
|
+
haltija.networkWatch(payload2 || {}).then((result) => {
|
|
8376
|
+
this.respond(msg2.id, result.success !== false, result);
|
|
8352
8377
|
}).catch((err) => {
|
|
8353
8378
|
this.respond(msg2.id, false, undefined, err.message);
|
|
8354
8379
|
});
|
|
@@ -8357,8 +8382,8 @@ var COMPONENT_JS = `(() => {
|
|
|
8357
8382
|
this.respond(msg2.id, false, undefined, notAvailable);
|
|
8358
8383
|
return;
|
|
8359
8384
|
}
|
|
8360
|
-
haltija.networkUnwatch().then((
|
|
8361
|
-
this.respond(msg2.id, true,
|
|
8385
|
+
haltija.networkUnwatch().then((result) => {
|
|
8386
|
+
this.respond(msg2.id, true, result);
|
|
8362
8387
|
}).catch((err) => {
|
|
8363
8388
|
this.respond(msg2.id, false, undefined, err.message);
|
|
8364
8389
|
});
|
|
@@ -8367,8 +8392,8 @@ var COMPONENT_JS = `(() => {
|
|
|
8367
8392
|
this.respond(msg2.id, false, undefined, notAvailable);
|
|
8368
8393
|
return;
|
|
8369
8394
|
}
|
|
8370
|
-
haltija.networkLog(payload2 || {}).then((
|
|
8371
|
-
this.respond(msg2.id, true,
|
|
8395
|
+
haltija.networkLog(payload2 || {}).then((result) => {
|
|
8396
|
+
this.respond(msg2.id, true, result);
|
|
8372
8397
|
}).catch((err) => {
|
|
8373
8398
|
this.respond(msg2.id, false, undefined, err.message);
|
|
8374
8399
|
});
|
|
@@ -8377,8 +8402,8 @@ var COMPONENT_JS = `(() => {
|
|
|
8377
8402
|
this.respond(msg2.id, false, undefined, notAvailable);
|
|
8378
8403
|
return;
|
|
8379
8404
|
}
|
|
8380
|
-
haltija.networkStats().then((
|
|
8381
|
-
this.respond(msg2.id, true,
|
|
8405
|
+
haltija.networkStats().then((result) => {
|
|
8406
|
+
this.respond(msg2.id, true, result);
|
|
8382
8407
|
}).catch((err) => {
|
|
8383
8408
|
this.respond(msg2.id, false, undefined, err.message);
|
|
8384
8409
|
});
|
|
@@ -8387,8 +8412,8 @@ var COMPONENT_JS = `(() => {
|
|
|
8387
8412
|
this.respond(msg2.id, false, undefined, notAvailable);
|
|
8388
8413
|
return;
|
|
8389
8414
|
}
|
|
8390
|
-
haltija.networkClear().then((
|
|
8391
|
-
this.respond(msg2.id, true,
|
|
8415
|
+
haltija.networkClear().then((result) => {
|
|
8416
|
+
this.respond(msg2.id, true, result);
|
|
8392
8417
|
}).catch((err) => {
|
|
8393
8418
|
this.respond(msg2.id, false, undefined, err.message);
|
|
8394
8419
|
});
|
|
@@ -8834,9 +8859,9 @@ var COMPONENT_JS = `(() => {
|
|
|
8834
8859
|
try {
|
|
8835
8860
|
const capturePromise = targetSelector ? haltija.captureElement(targetSelector) : haltija.capturePage();
|
|
8836
8861
|
const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve({ success: false, error: "Screenshot capture timed out after 10s" }), 1e4));
|
|
8837
|
-
const
|
|
8838
|
-
if (
|
|
8839
|
-
const converted = await convertFormat(
|
|
8862
|
+
const result = await Promise.race([capturePromise, timeoutPromise]);
|
|
8863
|
+
if (result?.success && result.data) {
|
|
8864
|
+
const converted = await convertFormat(result.data);
|
|
8840
8865
|
this.respond(msg2.id, true, {
|
|
8841
8866
|
image: converted.image,
|
|
8842
8867
|
viewport,
|
|
@@ -8846,8 +8871,8 @@ var COMPONENT_JS = `(() => {
|
|
|
8846
8871
|
source: "electron"
|
|
8847
8872
|
});
|
|
8848
8873
|
return;
|
|
8849
|
-
} else if (
|
|
8850
|
-
this.respond(msg2.id, false, null,
|
|
8874
|
+
} else if (result && !result.success) {
|
|
8875
|
+
this.respond(msg2.id, false, null, result.error || "Electron capture failed");
|
|
8851
8876
|
return;
|
|
8852
8877
|
}
|
|
8853
8878
|
} catch (err) {
|
|
@@ -8918,14 +8943,29 @@ var COMPONENT_JS = `(() => {
|
|
|
8918
8943
|
this.respond(msg2.id, true);
|
|
8919
8944
|
}
|
|
8920
8945
|
}
|
|
8921
|
-
async handleEvalMessage(
|
|
8946
|
+
async handleEvalMessage(msg2) {
|
|
8922
8947
|
try {
|
|
8923
|
-
const result =
|
|
8948
|
+
const result = this.evalCode(msg2.payload.code);
|
|
8924
8949
|
const resolved = result instanceof Promise ? await result : result;
|
|
8925
|
-
this.respond(
|
|
8950
|
+
this.respond(msg2.id, true, resolved);
|
|
8951
|
+
} catch (err) {
|
|
8952
|
+
this.respond(msg2.id, false, null, err.message);
|
|
8953
|
+
}
|
|
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}))()\`);
|
|
8926
8964
|
} catch (err) {
|
|
8927
|
-
|
|
8965
|
+
if (!(err instanceof SyntaxError))
|
|
8966
|
+
throw err;
|
|
8928
8967
|
}
|
|
8968
|
+
return eval(\`(async () => { \${code} })()\`);
|
|
8929
8969
|
}
|
|
8930
8970
|
async handleFetchMessage(msg2) {
|
|
8931
8971
|
const { url } = msg2.payload;
|
|
@@ -9003,14 +9043,14 @@ var COMPONENT_JS = `(() => {
|
|
|
9003
9043
|
let el = null;
|
|
9004
9044
|
let targetDesc = "";
|
|
9005
9045
|
if (ref) {
|
|
9006
|
-
const
|
|
9007
|
-
el =
|
|
9046
|
+
const result = refRegistry.resolveWithStatus(ref);
|
|
9047
|
+
el = result.element;
|
|
9008
9048
|
targetDesc = \`@\${ref}\`;
|
|
9009
9049
|
if (el) {
|
|
9010
9050
|
stats.refsResolved++;
|
|
9011
9051
|
} else {
|
|
9012
9052
|
stats.refsStale++;
|
|
9013
|
-
const errorMsg =
|
|
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)\`;
|
|
9014
9054
|
this.respond(responseId, false, null, errorMsg);
|
|
9015
9055
|
return;
|
|
9016
9056
|
}
|
|
@@ -9355,14 +9395,14 @@ var COMPONENT_JS = `(() => {
|
|
|
9355
9395
|
let el = null;
|
|
9356
9396
|
let targetDesc = "";
|
|
9357
9397
|
if (payload2.ref) {
|
|
9358
|
-
const
|
|
9359
|
-
el =
|
|
9398
|
+
const result = refRegistry.resolveWithStatus(payload2.ref);
|
|
9399
|
+
el = result.element;
|
|
9360
9400
|
targetDesc = \`@\${payload2.ref}\`;
|
|
9361
9401
|
if (el) {
|
|
9362
9402
|
stats.refsResolved++;
|
|
9363
9403
|
} else {
|
|
9364
9404
|
stats.refsStale++;
|
|
9365
|
-
const errorMsg =
|
|
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)\`;
|
|
9366
9406
|
this.respond(responseId, false, null, errorMsg);
|
|
9367
9407
|
return;
|
|
9368
9408
|
}
|
|
@@ -9431,15 +9471,15 @@ var COMPONENT_JS = `(() => {
|
|
|
9431
9471
|
let target = null;
|
|
9432
9472
|
let targetDesc = "";
|
|
9433
9473
|
if (ref) {
|
|
9434
|
-
const
|
|
9435
|
-
target =
|
|
9474
|
+
const result = refRegistry.resolveWithStatus(ref);
|
|
9475
|
+
target = result.element;
|
|
9436
9476
|
targetDesc = \`@\${ref}\`;
|
|
9437
9477
|
if (target) {
|
|
9438
9478
|
stats.refsResolved++;
|
|
9439
9479
|
target.focus();
|
|
9440
9480
|
} else {
|
|
9441
9481
|
stats.refsStale++;
|
|
9442
|
-
const errorMsg =
|
|
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)\`;
|
|
9443
9483
|
this.respond(responseId, false, null, errorMsg);
|
|
9444
9484
|
return;
|
|
9445
9485
|
}
|
|
@@ -9831,9 +9871,9 @@ var COMPONENT_JS = `(() => {
|
|
|
9831
9871
|
});
|
|
9832
9872
|
} else if (action2 === "result") {
|
|
9833
9873
|
if (this.selectionResult) {
|
|
9834
|
-
const
|
|
9874
|
+
const result = this.selectionResult;
|
|
9835
9875
|
this.clearSelection();
|
|
9836
|
-
this.respond(msg2.id, true,
|
|
9876
|
+
this.respond(msg2.id, true, result);
|
|
9837
9877
|
} else {
|
|
9838
9878
|
this.respond(msg2.id, false, null, "No selection available");
|
|
9839
9879
|
}
|
|
@@ -11094,7 +11134,17 @@ ${isElectronApp ? "" : ` <script>
|
|
|
11094
11134
|
document.getElementById('tab-' + tabId).classList.add('active');
|
|
11095
11135
|
});
|
|
11096
11136
|
});
|
|
11097
|
-
|
|
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
|
+
|
|
11098
11148
|
// Copy button functionality
|
|
11099
11149
|
function copyCode(btn) {
|
|
11100
11150
|
var pre = btn.parentElement.querySelector('pre');
|
|
@@ -11373,6 +11423,8 @@ Use ancestors:true to see parent elements when inspecting deep elements.`,
|
|
|
11373
11423
|
pierceFrames: L.boolean.describe("Pierce same-origin iframes (default true)").optional,
|
|
11374
11424
|
compact: L.boolean.describe("Minimal output (default false)").optional,
|
|
11375
11425
|
ancestors: L.boolean.describe("Include ancestor path from root (default false)").optional,
|
|
11426
|
+
includeBox: L.boolean.describe("Include each node's bounding box { x, y, w, h, visible } (default false)").optional,
|
|
11427
|
+
mode: L.string.describe("'actionable' returns a page action summary (url, title, headings, buttons, links, inputs, selects) instead of the DOM tree").optional,
|
|
11376
11428
|
window: L.string.describe("Target window ID").optional
|
|
11377
11429
|
}),
|
|
11378
11430
|
examples: [
|
|
@@ -12360,7 +12412,14 @@ var eval_ = endpoint({
|
|
|
12360
12412
|
description: `Run arbitrary JavaScript in the browser context. Returns the result.
|
|
12361
12413
|
|
|
12362
12414
|
The code runs in the page's context with access to window, document, etc.
|
|
12363
|
-
Return values are JSON-serialized.
|
|
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`,
|
|
12364
12423
|
category: "debug",
|
|
12365
12424
|
input: L.object({
|
|
12366
12425
|
code: L.string.describe("JavaScript code to execute"),
|
|
@@ -14063,7 +14122,10 @@ registerHandler(tree, async (body, ctx) => {
|
|
|
14063
14122
|
pierceShadow: body.pierceShadow,
|
|
14064
14123
|
pierceFrames: body.pierceFrames,
|
|
14065
14124
|
visibleOnly: body.visibleOnly,
|
|
14066
|
-
|
|
14125
|
+
interactiveOnly: body.interactiveOnly,
|
|
14126
|
+
ancestors: body.ancestors,
|
|
14127
|
+
includeBox: body.includeBox,
|
|
14128
|
+
mode: body.mode
|
|
14067
14129
|
}, 5000, windowId);
|
|
14068
14130
|
return Response.json(response, { headers: ctx.headers });
|
|
14069
14131
|
});
|
|
@@ -18525,7 +18587,8 @@ var serverConfig = {
|
|
|
18525
18587
|
label: existingWindow?.label,
|
|
18526
18588
|
windowType: windowType || "tab"
|
|
18527
18589
|
});
|
|
18528
|
-
|
|
18590
|
+
const isVisibleTab = (windowType || "tab") === "tab" && active !== false;
|
|
18591
|
+
if (!focusedWindowId || focusedWindowId === windowId || isVisibleTab) {
|
|
18529
18592
|
focusedWindowId = windowId;
|
|
18530
18593
|
}
|
|
18531
18594
|
console.log(`${LOG_PREFIX} Window connected: ${windowId} (${url})`);
|
|
@@ -18569,6 +18632,9 @@ var serverConfig = {
|
|
|
18569
18632
|
if (win) {
|
|
18570
18633
|
win.active = active;
|
|
18571
18634
|
win.lastSeen = Date.now();
|
|
18635
|
+
if (active && win.windowType === "tab") {
|
|
18636
|
+
focusedWindowId = windowId;
|
|
18637
|
+
}
|
|
18572
18638
|
}
|
|
18573
18639
|
}
|
|
18574
18640
|
} catch {}
|