local-operator-ui 0.39.0 → 0.39.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/main/index.js +1127 -125
- package/out/preload/index.js +11 -1
- package/out/renderer/assets/{_basePickBy-CBn_dsaM.js → _basePickBy-CSbKxvDP.js} +1 -1
- package/out/renderer/assets/{_baseUniq-B-kmAdKj.js → _baseUniq-BCDEv_Oc.js} +1 -1
- package/out/renderer/assets/addressOverlayList-8wdZRD_t.css +1 -0
- package/out/renderer/assets/addressOverlayList-BEh9WU4R.js +1 -0
- package/out/renderer/assets/{agent-details-page-CjksC_ZM.js → agent-details-page-ByULov9A.js} +1 -1
- package/out/renderer/assets/{agent-hub-page-D3y5dujt.js → agent-hub-page-B69p4cyN.js} +1 -1
- package/out/renderer/assets/{agents-page-vmm4VKcI.js → agents-page-Cl3KMRZy.js} +3 -3
- package/out/renderer/assets/{arc-BSYPx6kR.js → arc-CyVR9eoB.js} +1 -1
- package/out/renderer/assets/{architectureDiagram-IEHRJDOE-C-dAuUYf.js → architectureDiagram-IEHRJDOE-D_nbs604.js} +1 -1
- package/out/renderer/assets/{arrow-up-BaHSg-fV.js → arrow-up-JG56D3ZM.js} +1 -1
- package/out/renderer/assets/{blockDiagram-JOT3LUYC-Dw9X_Asu.js → blockDiagram-JOT3LUYC-cGHKlnnj.js} +1 -1
- package/out/renderer/assets/{book-open-CwoTuMOa.js → book-open-_50fvSpZ.js} +1 -1
- package/out/renderer/assets/browser-page-u8Qblazq.js +1 -0
- package/out/renderer/assets/{browser-webauthn-prompt-CFEuJXkX.js → browser-webauthn-prompt-BkYnuYH0.js} +1 -1
- package/out/renderer/assets/{building-2-D06wTZQj.js → building-2-D-6u9f2b.js} +1 -1
- package/out/renderer/assets/{c4Diagram-VJAJSXHY-Bz93LlZc.js → c4Diagram-VJAJSXHY-DPSkxG1K.js} +1 -1
- package/out/renderer/assets/channel-BP0N5Jip.js +1 -0
- package/out/renderer/assets/{chunk-4BMEZGHF-H3mECOID.js → chunk-4BMEZGHF-k7Xc9N8N.js} +1 -1
- package/out/renderer/assets/{chunk-A2AXSNBT-BNJGDJK2.js → chunk-A2AXSNBT-BUQ9LrYj.js} +1 -1
- package/out/renderer/assets/{chunk-AEK57VVT-Baj26p0I.js → chunk-AEK57VVT-T8K0wOxu.js} +1 -1
- package/out/renderer/assets/{chunk-D6G4REZN-B5inAuRK.js → chunk-D6G4REZN-_drafUVH.js} +1 -1
- package/out/renderer/assets/{chunk-RZ5BOZE2-BK_F-zoT.js → chunk-RZ5BOZE2-BlfOLAiK.js} +1 -1
- package/out/renderer/assets/{chunk-XZIHB7SX-DipW3oXc.js → chunk-XZIHB7SX-br7k9c-y.js} +1 -1
- package/out/renderer/assets/classDiagram-GIVACNV2-DgPhvGMc.js +1 -0
- package/out/renderer/assets/classDiagram-v2-COTLJTTW-DgPhvGMc.js +1 -0
- package/out/renderer/assets/clone-D_2R859t.js +1 -0
- package/out/renderer/assets/{console-mirror-DB5yXAr9.js → console-mirror-BFQaHp1b.js} +1 -1
- package/out/renderer/assets/{consoleCapture-Bz69ju0Z.js → consoleCapture-L2qaS8a8.js} +1 -1
- package/out/renderer/assets/{conversation-input-sync-BVPZQjhD.js → conversation-input-sync-CH6BMnVZ.js} +267 -267
- package/out/renderer/assets/{dagre-OKDRZEBW-3ECMKEeo.js → dagre-OKDRZEBW-BnHmlI8H.js} +1 -1
- package/out/renderer/assets/{diagram-SSKATNLV-CmAf5Fvk.js → diagram-SSKATNLV-q_CpwdD7.js} +1 -1
- package/out/renderer/assets/{diagram-VNBRO52H-D_21NrT-.js → diagram-VNBRO52H-B2mKekLo.js} +1 -1
- package/out/renderer/assets/{erDiagram-Q7BY3M3F-CaUQ9PtP.js → erDiagram-Q7BY3M3F-CyQWMyA_.js} +1 -1
- package/out/renderer/assets/{error-boundary-h9802RBt.js → error-boundary-xAR0FhJi.js} +1 -1
- package/out/renderer/assets/{flowDiagram-4HSFHLVR-CVLxJB7Y.js → flowDiagram-4HSFHLVR-DaECRw9d.js} +1 -1
- package/out/renderer/assets/{ganttDiagram-APWFNJXF-Dt6KPnJQ.js → ganttDiagram-APWFNJXF-DcuyjU9V.js} +1 -1
- package/out/renderer/assets/{gitGraphDiagram-7IBYFJ6S-D1BdvS2j.js → gitGraphDiagram-7IBYFJ6S-BY2WvPMI.js} +1 -1
- package/out/renderer/assets/{graph-wsNGWWCD.js → graph-or727h2C.js} +1 -1
- package/out/renderer/assets/{hash-C32vAdag.js → hash-Ch3ejz63.js} +1 -1
- package/out/renderer/assets/{index-3RPijdn_.css → index-BUzMwM-n.css} +1 -1
- package/out/renderer/assets/{index-6JB-jSFn.js → index-Bs2qygzx.js} +1 -1
- package/out/renderer/assets/{index-CiOOz1tp.js → index-C1J-T_Mt.js} +184 -184
- package/out/renderer/assets/{index-CvofVM43.js → index-DQE5o_2l.js} +1 -1
- package/out/renderer/assets/{infoDiagram-PH2N3AL5-CWPf3FZn.js → infoDiagram-PH2N3AL5-BXElUsIa.js} +1 -1
- package/out/renderer/assets/{installer-DKAnScPb.js → installer-DBTiypQJ.js} +1 -1
- package/out/renderer/assets/{journeyDiagram-U35MCT3I-B5eLtG46.js → journeyDiagram-U35MCT3I-GAMZIDYa.js} +1 -1
- package/out/renderer/assets/{kanban-definition-NDS4AKOZ-BtJFd9zq.js → kanban-definition-NDS4AKOZ-ij90M1gN.js} +1 -1
- package/out/renderer/assets/{layout-B3W_M4xE.js → layout-DqWzcUI9.js} +1 -1
- package/out/renderer/assets/{legacy-agents-page-aqbs_qcV.js → legacy-agents-page-D96D0ThJ.js} +1 -1
- package/out/renderer/assets/{library-page-BIa8sD1w.js → library-page-BtkHYaRw.js} +3 -3
- package/out/renderer/assets/{mermaid.core-DzmjLSHb.js → mermaid.core-B9fSy9q8.js} +5 -5
- package/out/renderer/assets/{mesh-page-De8Abvyb.js → mesh-page-BKS4b5nA.js} +1 -1
- package/out/renderer/assets/{mindmap-definition-ALO5MXBD-C1aylJ0P.js → mindmap-definition-ALO5MXBD-CnOp0ZCp.js} +1 -1
- package/out/renderer/assets/{mini-mPtvVJCT.js → mini-BL0qywTp.js} +1 -1
- package/out/renderer/assets/{notebook-pen-CvyIerwZ.js → notebook-pen-DQs4gt50.js} +1 -1
- package/out/renderer/assets/{org-access-Cpt-vs-I.js → org-access-DvoJr_O7.js} +1 -1
- package/out/renderer/assets/{org-surface-gate-C8Gs3DNG.js → org-surface-gate-kYD-nQnh.js} +1 -1
- package/out/renderer/assets/{page-header-DBIgQcaM.js → page-header-BY6LFXsV.js} +1 -1
- package/out/renderer/assets/{pieDiagram-IB7DONF6-CjnobVYZ.js → pieDiagram-IB7DONF6-DkbkzE3D.js} +1 -1
- package/out/renderer/assets/{projects-page-041auzXW.js → projects-page-BLQzs3uM.js} +1 -1
- package/out/renderer/assets/{publication-validation-JvAtW-AY.js → publication-validation-4m4ljeE_.js} +1 -1
- package/out/renderer/assets/{quadrantDiagram-7GDLP6J5-B0TLJJFL.js → quadrantDiagram-7GDLP6J5-Dfe4cbbn.js} +1 -1
- package/out/renderer/assets/{radar-MK3ICKWK-D6MZmkB6.js → radar-MK3ICKWK-BdbftlUx.js} +1 -1
- package/out/renderer/assets/{radient-auth-buttons-quggTTqK.js → radient-auth-buttons-DngU_dyA.js} +1 -1
- package/out/renderer/assets/{requirementDiagram-KVF5MWMF-BSAJQlo8.js → requirementDiagram-KVF5MWMF-PKSI_Jbh.js} +1 -1
- package/out/renderer/assets/{sankeyDiagram-QLVOVGJD-CQqGLTr_.js → sankeyDiagram-QLVOVGJD-Bon1uUIU.js} +1 -1
- package/out/renderer/assets/{schedules-page-B51F-ADQ.js → schedules-page-DW0Ae9De.js} +1 -1
- package/out/renderer/assets/{sequenceDiagram-X6HHIX6F-B0LPyEfC.js → sequenceDiagram-X6HHIX6F-Bnoc1VB7.js} +1 -1
- package/out/renderer/assets/{settings-page-BpTAK-RZ.js → settings-page-Djdtg7c4.js} +1 -1
- package/out/renderer/assets/{smartart-B1Hg0uN6.js → smartart-CIIex-5K.js} +1 -1
- package/out/renderer/assets/{stateDiagram-DGXRK772-hL4-Mzxx.js → stateDiagram-DGXRK772-CGmFZKBF.js} +1 -1
- package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-C7mh141a.js +1 -0
- package/out/renderer/assets/team-bridge-page-B1jfvoLr.js +11 -0
- package/out/renderer/assets/{timeline-definition-BDJGKUSR-BOE8E_XE.js → timeline-definition-BDJGKUSR-B3KzRgdo.js} +1 -1
- package/out/renderer/assets/{ui-preferences-store-Cws2cozv.js → ui-preferences-store-YyZ50qSr.js} +1 -1
- package/out/renderer/assets/{use-download-agent-mutation-HcVu2YgL.js → use-download-agent-mutation-CGnvP-dC.js} +1 -1
- package/out/renderer/assets/{use-session-snapshot-CMQBHevf.js → use-session-snapshot-B0KS_Jw_.js} +1 -1
- package/out/renderer/assets/{xychartDiagram-VJFVF3MP-D3cI5mnO.js → xychartDiagram-VJFVF3MP-BEcciMcG.js} +1 -1
- package/out/renderer/browser-address-overlay-list.html +35 -0
- package/out/renderer/console-capture.html +5 -5
- package/out/renderer/index.html +7 -7
- package/out/renderer/installer.html +4 -4
- package/out/renderer/mini.html +7 -7
- package/package.json +8 -3
- package/out/renderer/assets/browser-page-DmYAxbWu.js +0 -1
- package/out/renderer/assets/channel-BJdem-Qj.js +0 -1
- package/out/renderer/assets/classDiagram-GIVACNV2-BQLeT9Qk.js +0 -1
- package/out/renderer/assets/classDiagram-v2-COTLJTTW-BQLeT9Qk.js +0 -1
- package/out/renderer/assets/clone-BaxJyMvd.js +0 -1
- package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-Bczp9bth.js +0 -1
- package/out/renderer/assets/team-bridge-page-xhQelITo.js +0 -11
- /package/out/renderer/assets/{index-COgOH-4N.js → index-YWHAePtd.js} +0 -0
package/out/main/index.js
CHANGED
|
@@ -15004,10 +15004,24 @@ function resolveLauncherWatchPlan(input) {
|
|
|
15004
15004
|
};
|
|
15005
15005
|
}
|
|
15006
15006
|
if (input.mode !== "headless") {
|
|
15007
|
+
if (input.mode !== "inactive" || input.boundedVisibleProbe !== true) {
|
|
15008
|
+
return {
|
|
15009
|
+
watch: false,
|
|
15010
|
+
launcherPid: null,
|
|
15011
|
+
reason: `window mode ${input.mode} is not launcher-bound: a person can close it`
|
|
15012
|
+
};
|
|
15013
|
+
}
|
|
15014
|
+
if (!Number.isInteger(input.launcherPid) || input.launcherPid <= 1) {
|
|
15015
|
+
return {
|
|
15016
|
+
watch: false,
|
|
15017
|
+
launcherPid: null,
|
|
15018
|
+
reason: "visible probe already detached (no launcher to outlive)"
|
|
15019
|
+
};
|
|
15020
|
+
}
|
|
15007
15021
|
return {
|
|
15008
|
-
watch:
|
|
15009
|
-
launcherPid:
|
|
15010
|
-
reason: `
|
|
15022
|
+
watch: true,
|
|
15023
|
+
launcherPid: input.launcherPid,
|
|
15024
|
+
reason: `visible probe launched by pid ${input.launcherPid}; it is capped and quits when that process goes`
|
|
15011
15025
|
};
|
|
15012
15026
|
}
|
|
15013
15027
|
if (!Number.isInteger(input.launcherPid) || input.launcherPid <= 1) {
|
|
@@ -26052,11 +26066,11 @@ class ConsoleHost {
|
|
|
26052
26066
|
{ rendered: null }
|
|
26053
26067
|
);
|
|
26054
26068
|
}
|
|
26055
|
-
const
|
|
26069
|
+
const rect2 = cropToWindow(
|
|
26056
26070
|
report.contentRect,
|
|
26057
26071
|
window.getContentBounds()
|
|
26058
26072
|
);
|
|
26059
|
-
const png = await this.captureWithRetry(window,
|
|
26073
|
+
const png = await this.captureWithRetry(window, rect2);
|
|
26060
26074
|
const grid = runtime.emulator.grid;
|
|
26061
26075
|
return {
|
|
26062
26076
|
image_base64: png.toString("base64"),
|
|
@@ -26092,10 +26106,10 @@ class ConsoleHost {
|
|
|
26092
26106
|
* renderer paints antialiased text and a cursor — and the empty-terminal case is the
|
|
26093
26107
|
* offscreen path's problem too, so this is not a new ceiling.
|
|
26094
26108
|
*/
|
|
26095
|
-
async captureWithRetry(window,
|
|
26109
|
+
async captureWithRetry(window, rect2) {
|
|
26096
26110
|
let bytes = 0;
|
|
26097
26111
|
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
26098
|
-
const image2 = await window.webContents.capturePage(
|
|
26112
|
+
const image2 = await window.webContents.capturePage(rect2);
|
|
26099
26113
|
const png = framePng(image2);
|
|
26100
26114
|
bytes = png.length;
|
|
26101
26115
|
if (hasTerminalContent(image2.toBitmap())) {
|
|
@@ -27060,14 +27074,14 @@ function wrapBracketedPaste(bytes) {
|
|
|
27060
27074
|
out.set(end, start.length + bytes.length);
|
|
27061
27075
|
return out;
|
|
27062
27076
|
}
|
|
27063
|
-
function cropToWindow(
|
|
27064
|
-
const x = Math.max(Math.floor(
|
|
27065
|
-
const y = Math.max(Math.floor(
|
|
27077
|
+
function cropToWindow(rect2, bounds) {
|
|
27078
|
+
const x = Math.max(Math.floor(rect2.x), 0);
|
|
27079
|
+
const y = Math.max(Math.floor(rect2.y), 0);
|
|
27066
27080
|
return {
|
|
27067
27081
|
x,
|
|
27068
27082
|
y,
|
|
27069
|
-
width: Math.max(Math.min(Math.floor(
|
|
27070
|
-
height: Math.max(Math.min(Math.floor(
|
|
27083
|
+
width: Math.max(Math.min(Math.floor(rect2.width), bounds.width - x), 1),
|
|
27084
|
+
height: Math.max(Math.min(Math.floor(rect2.height), bounds.height - y), 1)
|
|
27071
27085
|
};
|
|
27072
27086
|
}
|
|
27073
27087
|
function framePng(image2) {
|
|
@@ -27836,12 +27850,12 @@ function contentReportOrThrow(value) {
|
|
|
27836
27850
|
throw new Error("A console content report is required.");
|
|
27837
27851
|
}
|
|
27838
27852
|
const report = value;
|
|
27839
|
-
const
|
|
27840
|
-
if (!
|
|
27853
|
+
const rect2 = report.contentRect;
|
|
27854
|
+
if (!rect2 || typeof rect2 !== "object") {
|
|
27841
27855
|
throw new Error("A console content report needs a contentRect.");
|
|
27842
27856
|
}
|
|
27843
27857
|
const numbers = ["x", "y", "width", "height"].map((key) => {
|
|
27844
|
-
const raw =
|
|
27858
|
+
const raw = rect2[key];
|
|
27845
27859
|
if (typeof raw !== "number" || !Number.isFinite(raw)) {
|
|
27846
27860
|
throw new Error(`contentRect.${key} must be a number.`);
|
|
27847
27861
|
}
|
|
@@ -28341,6 +28355,60 @@ async function startConsoleHost(options) {
|
|
|
28341
28355
|
};
|
|
28342
28356
|
}
|
|
28343
28357
|
}
|
|
28358
|
+
const DEV_DRIVER_ENV = "LOCAL_OPERATOR_UI_DEV_DRIVER";
|
|
28359
|
+
const DEV_DRIVER_OUT_ENV = "LOCAL_OPERATOR_UI_DEV_DRIVER_OUT";
|
|
28360
|
+
const DEV_DRIVER_ARG = "--lo-dev-driver";
|
|
28361
|
+
const DEV_DRIVER_CAPTURE = "dev-driver-capture";
|
|
28362
|
+
const DEV_DRIVER_FACTS = "dev-driver-facts";
|
|
28363
|
+
const DEV_DRIVER_ADDRESS_OVERLAY = "dev-driver-address-overlay";
|
|
28364
|
+
const DEV_DRIVER_ADDRESS_OVERLAY_PROJECT = "dev-driver-address-overlay-project";
|
|
28365
|
+
const DEV_DRIVER_ADDRESS_OVERLAY_EVENT = "dev-driver-address-overlay-event";
|
|
28366
|
+
const TRUTHY = /* @__PURE__ */ new Set(["1", "true"]);
|
|
28367
|
+
function readOptIn(env) {
|
|
28368
|
+
const raw = env[DEV_DRIVER_ENV];
|
|
28369
|
+
if (raw === void 0 || raw.trim() === "")
|
|
28370
|
+
return { asked: false, value: null };
|
|
28371
|
+
return { asked: true, value: raw.trim() };
|
|
28372
|
+
}
|
|
28373
|
+
function resolveDevDriverArming(input) {
|
|
28374
|
+
const off = (problems = []) => ({
|
|
28375
|
+
armed: false,
|
|
28376
|
+
outDir: null,
|
|
28377
|
+
problems
|
|
28378
|
+
});
|
|
28379
|
+
const optIn = readOptIn(input.env);
|
|
28380
|
+
if (!optIn.asked) return off();
|
|
28381
|
+
if (!TRUTHY.has(optIn.value.toLowerCase())) {
|
|
28382
|
+
return off([
|
|
28383
|
+
`${DEV_DRIVER_ENV}=${optIn.value} is not an opt-in (accepted: 1, true); the renderer dev driver stayed off`
|
|
28384
|
+
]);
|
|
28385
|
+
}
|
|
28386
|
+
if (input.windowMode !== "headless" && input.windowMode !== "inactive") {
|
|
28387
|
+
return off([
|
|
28388
|
+
`the renderer dev driver refused to arm in a "${input.windowMode}" window; it never raises one, so use --window-mode=headless (or inactive)`
|
|
28389
|
+
]);
|
|
28390
|
+
}
|
|
28391
|
+
const outDir = input.env[DEV_DRIVER_OUT_ENV]?.trim() ?? "";
|
|
28392
|
+
if (outDir === "" || !outDir.startsWith("/")) {
|
|
28393
|
+
return off([
|
|
28394
|
+
`${DEV_DRIVER_ENV} was set but ${DEV_DRIVER_OUT_ENV} is ${outDir === "" ? "missing" : `"${outDir}"`}; an absolute frames directory is required, so the driver did not arm`
|
|
28395
|
+
]);
|
|
28396
|
+
}
|
|
28397
|
+
return { armed: true, outDir, problems: [] };
|
|
28398
|
+
}
|
|
28399
|
+
function headlessExerciserAllowed(input) {
|
|
28400
|
+
return input.arming.armed && input.windowMode === "headless";
|
|
28401
|
+
}
|
|
28402
|
+
function devDriverArgument(outDir) {
|
|
28403
|
+
return `${DEV_DRIVER_ARG}=${outDir}`;
|
|
28404
|
+
}
|
|
28405
|
+
function describeDevDriverArming(arming) {
|
|
28406
|
+
if (arming.armed) {
|
|
28407
|
+
return `[dev-driver] ARMED; frames are written to ${arming.outDir}`;
|
|
28408
|
+
}
|
|
28409
|
+
if (arming.problems.length === 0) return null;
|
|
28410
|
+
return `[dev-driver] not armed: ${arming.problems.join("; ")}`;
|
|
28411
|
+
}
|
|
28344
28412
|
const WEBAUTHN_GROUP_SUFFIX = ".webauthn";
|
|
28345
28413
|
const WEBAUTHN_PROMPT_REASON = "use a passkey for $1";
|
|
28346
28414
|
const WEBAUTHN_CHOOSER_TIMEOUT_MS = 6e4;
|
|
@@ -28763,7 +28831,368 @@ function labelOf(account) {
|
|
|
28763
28831
|
if (!account) return "an unnamed passkey";
|
|
28764
28832
|
return account.displayName || account.name || "an unnamed passkey";
|
|
28765
28833
|
}
|
|
28834
|
+
const ADDRESS_LIST_ENV = "LOCAL_OPERATOR_UI_BROWSER_ADDRESS_OVERLAY_S2";
|
|
28835
|
+
const ADDRESS_LIST_DOCUMENT = "browser-address-overlay-list.html";
|
|
28836
|
+
const ADDRESS_LIST_HEADER_HEIGHT = 28;
|
|
28837
|
+
const ADDRESS_LIST_ROW_HEIGHT = 35.5;
|
|
28838
|
+
const ADDRESS_LIST_ROWS_MAX = 5;
|
|
28839
|
+
const ADDRESS_LIST_MAX_HEIGHT_DIP = 212;
|
|
28840
|
+
const ADDRESS_LIST_NOTICE_HEIGHT_DIP = 104;
|
|
28841
|
+
const ADDRESS_LIST_ANCHOR_GAP_MAX = 24;
|
|
28842
|
+
const ADDRESS_LIST_MAX_PAYLOAD_BYTES = 16 * 1024;
|
|
28843
|
+
const ADDRESS_LIST_MAX_TEXT = 512;
|
|
28844
|
+
const ADDRESS_LIST_MAX_TITLE = 256;
|
|
28845
|
+
const ADDRESS_LIST_MAX_LABEL = 256;
|
|
28846
|
+
const ADDRESS_LIST_THEME_FALLBACK = "#1b1f24";
|
|
28847
|
+
const DIP_INT32_MAX$1 = 2 ** 31 - 1;
|
|
28848
|
+
const NOTICE_KINDS = [
|
|
28849
|
+
"error",
|
|
28850
|
+
"hint",
|
|
28851
|
+
"empty",
|
|
28852
|
+
"no_match"
|
|
28853
|
+
];
|
|
28854
|
+
const HOSTILE_STRING = /[\p{Cc}\u2028\u2029\u202A-\u202E\u2066-\u2069]/gu;
|
|
28855
|
+
const COLOR = /^(#[0-9a-f]{6}|rgb\(\d{1,3}, ?\d{1,3}, ?\d{1,3}\))$/i;
|
|
28856
|
+
const PROJECTION_KEYS = /* @__PURE__ */ new Set([
|
|
28857
|
+
"v",
|
|
28858
|
+
"seq",
|
|
28859
|
+
"tabId",
|
|
28860
|
+
"visible",
|
|
28861
|
+
"pageRect",
|
|
28862
|
+
"field",
|
|
28863
|
+
"listTop",
|
|
28864
|
+
"active",
|
|
28865
|
+
"view",
|
|
28866
|
+
"label",
|
|
28867
|
+
"dir",
|
|
28868
|
+
"theme"
|
|
28869
|
+
]);
|
|
28870
|
+
const RECT_KEYS = ["x", "y", "width", "height"];
|
|
28871
|
+
const THEME_KEYS = [
|
|
28872
|
+
"elevated",
|
|
28873
|
+
"ink",
|
|
28874
|
+
"inkMuted",
|
|
28875
|
+
"accent",
|
|
28876
|
+
"accentWash",
|
|
28877
|
+
"rowHover",
|
|
28878
|
+
"hairline",
|
|
28879
|
+
"control"
|
|
28880
|
+
];
|
|
28881
|
+
function isRecord$1(value) {
|
|
28882
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28883
|
+
}
|
|
28884
|
+
function hasOnlyKeys(value, allowed) {
|
|
28885
|
+
const set2 = allowed instanceof Set ? allowed : new Set(allowed);
|
|
28886
|
+
for (const key of Object.keys(value)) if (!set2.has(key)) return false;
|
|
28887
|
+
return true;
|
|
28888
|
+
}
|
|
28889
|
+
function finite(value) {
|
|
28890
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
28891
|
+
}
|
|
28892
|
+
function rect(value) {
|
|
28893
|
+
if (!isRecord$1(value)) return null;
|
|
28894
|
+
if (!hasOnlyKeys(value, RECT_KEYS)) return null;
|
|
28895
|
+
const x = finite(value.x);
|
|
28896
|
+
const y = finite(value.y);
|
|
28897
|
+
const width = finite(value.width);
|
|
28898
|
+
const height = finite(value.height);
|
|
28899
|
+
if (x === null || y === null || width === null || height === null)
|
|
28900
|
+
return null;
|
|
28901
|
+
return { x, y, width, height };
|
|
28902
|
+
}
|
|
28903
|
+
function sanitizeOverlayText(value, cap) {
|
|
28904
|
+
if (typeof value !== "string") return null;
|
|
28905
|
+
const stripped = value.replace(HOSTILE_STRING, "");
|
|
28906
|
+
const points = [...stripped];
|
|
28907
|
+
return points.length > cap ? points.slice(0, cap).join("") : stripped;
|
|
28908
|
+
}
|
|
28909
|
+
function sanitizeRows(value) {
|
|
28910
|
+
if (!Array.isArray(value)) return null;
|
|
28911
|
+
if (value.length === 0 || value.length > ADDRESS_LIST_ROWS_MAX) return null;
|
|
28912
|
+
const rows = [];
|
|
28913
|
+
for (const entry of value) {
|
|
28914
|
+
if (!isRecord$1(entry) || !hasOnlyKeys(entry, ["text", "title"])) return null;
|
|
28915
|
+
const text = sanitizeOverlayText(entry.text, ADDRESS_LIST_MAX_TEXT);
|
|
28916
|
+
const title = sanitizeOverlayText(entry.title, ADDRESS_LIST_MAX_TITLE);
|
|
28917
|
+
if (text === null || title === null) return null;
|
|
28918
|
+
if (text.length === 0) return null;
|
|
28919
|
+
rows.push({ text, title });
|
|
28920
|
+
}
|
|
28921
|
+
return rows;
|
|
28922
|
+
}
|
|
28923
|
+
function sanitizeTheme(value) {
|
|
28924
|
+
if (value === void 0) return { theme: null, fact: "absent" };
|
|
28925
|
+
if (!isRecord$1(value) || !hasOnlyKeys(value, THEME_KEYS)) {
|
|
28926
|
+
return { theme: null, fact: "fallback" };
|
|
28927
|
+
}
|
|
28928
|
+
const theme = {};
|
|
28929
|
+
for (const key of THEME_KEYS) {
|
|
28930
|
+
const raw = value[key];
|
|
28931
|
+
if (typeof raw !== "string" || !COLOR.test(raw)) {
|
|
28932
|
+
return { theme: null, fact: "fallback" };
|
|
28933
|
+
}
|
|
28934
|
+
theme[key] = raw;
|
|
28935
|
+
}
|
|
28936
|
+
return { theme, fact: "resolved" };
|
|
28937
|
+
}
|
|
28938
|
+
function jsonBytes(value) {
|
|
28939
|
+
try {
|
|
28940
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
28941
|
+
} catch {
|
|
28942
|
+
return Number.POSITIVE_INFINITY;
|
|
28943
|
+
}
|
|
28944
|
+
}
|
|
28945
|
+
function sanitizeProjection(raw) {
|
|
28946
|
+
if (jsonBytes(raw) > ADDRESS_LIST_MAX_PAYLOAD_BYTES) {
|
|
28947
|
+
return { ok: false, reason: "payload_too_large" };
|
|
28948
|
+
}
|
|
28949
|
+
if (!isRecord$1(raw)) return { ok: false, reason: "not_an_object" };
|
|
28950
|
+
if (!hasOnlyKeys(raw, PROJECTION_KEYS)) {
|
|
28951
|
+
return { ok: false, reason: "unknown_key" };
|
|
28952
|
+
}
|
|
28953
|
+
if (raw.v !== 1) return { ok: false, reason: "bad_version" };
|
|
28954
|
+
if (!Number.isInteger(raw.seq) || raw.seq < 1) {
|
|
28955
|
+
return { ok: false, reason: "bad_seq" };
|
|
28956
|
+
}
|
|
28957
|
+
if (!Number.isInteger(raw.tabId)) return { ok: false, reason: "bad_tab" };
|
|
28958
|
+
if (typeof raw.visible !== "boolean") {
|
|
28959
|
+
return { ok: false, reason: "bad_visible" };
|
|
28960
|
+
}
|
|
28961
|
+
if (!raw.visible) {
|
|
28962
|
+
return {
|
|
28963
|
+
ok: true,
|
|
28964
|
+
projection: {
|
|
28965
|
+
v: 1,
|
|
28966
|
+
seq: raw.seq,
|
|
28967
|
+
tabId: raw.tabId,
|
|
28968
|
+
visible: false,
|
|
28969
|
+
pageRect: { x: 0, y: 0, width: 0, height: 0 },
|
|
28970
|
+
field: { x: 0, y: 0, width: 0, height: 0 },
|
|
28971
|
+
listTop: 0,
|
|
28972
|
+
active: -1,
|
|
28973
|
+
view: { kind: "notice", notice: "empty", text: "" },
|
|
28974
|
+
label: "",
|
|
28975
|
+
dir: "ltr",
|
|
28976
|
+
theme: null,
|
|
28977
|
+
themeFact: "absent"
|
|
28978
|
+
}
|
|
28979
|
+
};
|
|
28980
|
+
}
|
|
28981
|
+
const pageRect = rect(raw.pageRect);
|
|
28982
|
+
const field = rect(raw.field);
|
|
28983
|
+
if (pageRect === null || field === null) {
|
|
28984
|
+
return { ok: false, reason: "bad_rect" };
|
|
28985
|
+
}
|
|
28986
|
+
const listTop = finite(raw.listTop);
|
|
28987
|
+
if (listTop === null) return { ok: false, reason: "bad_list_top" };
|
|
28988
|
+
if (field.width <= 0 || field.height <= 0) {
|
|
28989
|
+
return { ok: false, reason: "bad_field" };
|
|
28990
|
+
}
|
|
28991
|
+
if (!Number.isInteger(raw.active)) return { ok: false, reason: "bad_active" };
|
|
28992
|
+
const active = raw.active;
|
|
28993
|
+
const viewRaw = raw.view;
|
|
28994
|
+
if (!isRecord$1(viewRaw)) return { ok: false, reason: "bad_view" };
|
|
28995
|
+
let view;
|
|
28996
|
+
if (viewRaw.kind === "rows") {
|
|
28997
|
+
if (!hasOnlyKeys(viewRaw, ["kind", "rows"])) {
|
|
28998
|
+
return { ok: false, reason: "bad_view" };
|
|
28999
|
+
}
|
|
29000
|
+
const rows = sanitizeRows(viewRaw.rows);
|
|
29001
|
+
if (rows === null) return { ok: false, reason: "bad_rows" };
|
|
29002
|
+
view = { kind: "rows", rows };
|
|
29003
|
+
} else if (viewRaw.kind === "notice") {
|
|
29004
|
+
if (!hasOnlyKeys(viewRaw, ["kind", "notice", "text"])) {
|
|
29005
|
+
return { ok: false, reason: "bad_view" };
|
|
29006
|
+
}
|
|
29007
|
+
if (!NOTICE_KINDS.includes(viewRaw.notice)) {
|
|
29008
|
+
return { ok: false, reason: "bad_notice" };
|
|
29009
|
+
}
|
|
29010
|
+
const text = sanitizeOverlayText(viewRaw.text, ADDRESS_LIST_MAX_LABEL);
|
|
29011
|
+
if (text === null) return { ok: false, reason: "bad_notice_text" };
|
|
29012
|
+
view = {
|
|
29013
|
+
kind: "notice",
|
|
29014
|
+
notice: viewRaw.notice,
|
|
29015
|
+
text
|
|
29016
|
+
};
|
|
29017
|
+
} else {
|
|
29018
|
+
return { ok: false, reason: "bad_view" };
|
|
29019
|
+
}
|
|
29020
|
+
if (view.kind === "rows" ? active < -1 || active >= view.rows.length : active !== -1) {
|
|
29021
|
+
return { ok: false, reason: "bad_active" };
|
|
29022
|
+
}
|
|
29023
|
+
const label = sanitizeOverlayText(raw.label, ADDRESS_LIST_MAX_LABEL);
|
|
29024
|
+
if (label === null) return { ok: false, reason: "bad_label" };
|
|
29025
|
+
if (raw.dir !== "ltr" && raw.dir !== "rtl") {
|
|
29026
|
+
return { ok: false, reason: "bad_dir" };
|
|
29027
|
+
}
|
|
29028
|
+
const { theme, fact } = sanitizeTheme(raw.theme);
|
|
29029
|
+
return {
|
|
29030
|
+
ok: true,
|
|
29031
|
+
projection: {
|
|
29032
|
+
v: 1,
|
|
29033
|
+
seq: raw.seq,
|
|
29034
|
+
tabId: raw.tabId,
|
|
29035
|
+
visible: true,
|
|
29036
|
+
pageRect,
|
|
29037
|
+
field,
|
|
29038
|
+
listTop,
|
|
29039
|
+
active,
|
|
29040
|
+
view,
|
|
29041
|
+
label,
|
|
29042
|
+
dir: raw.dir,
|
|
29043
|
+
theme,
|
|
29044
|
+
themeFact: fact
|
|
29045
|
+
}
|
|
29046
|
+
};
|
|
29047
|
+
}
|
|
29048
|
+
function int32$1(value) {
|
|
29049
|
+
if (!Number.isFinite(value)) return null;
|
|
29050
|
+
const rounded = Math.round(value);
|
|
29051
|
+
return Math.abs(rounded) > DIP_INT32_MAX$1 ? null : rounded;
|
|
29052
|
+
}
|
|
29053
|
+
function addressListHeightFor(view) {
|
|
29054
|
+
if (view.kind === "notice") return ADDRESS_LIST_NOTICE_HEIGHT_DIP;
|
|
29055
|
+
return Math.ceil(
|
|
29056
|
+
ADDRESS_LIST_HEADER_HEIGHT + 2 + view.rows.length * ADDRESS_LIST_ROW_HEIGHT + 2 + 1
|
|
29057
|
+
);
|
|
29058
|
+
}
|
|
29059
|
+
function addressListBoundsFor(field, listTop, view, owner) {
|
|
29060
|
+
const fx = int32$1(field.x);
|
|
29061
|
+
const fy = int32$1(field.y);
|
|
29062
|
+
const fw = int32$1(field.width);
|
|
29063
|
+
const fh = int32$1(field.height);
|
|
29064
|
+
const top = int32$1(listTop);
|
|
29065
|
+
const ownerWidth = int32$1(owner.width);
|
|
29066
|
+
const ownerHeight = int32$1(owner.height);
|
|
29067
|
+
if (fx === null || fy === null || fw === null || fh === null || top === null || ownerWidth === null || ownerHeight === null) {
|
|
29068
|
+
return null;
|
|
29069
|
+
}
|
|
29070
|
+
if (fw <= 0 || fh <= 0 || ownerWidth <= 0 || ownerHeight <= 0) return null;
|
|
29071
|
+
const gap = top - (fy + fh);
|
|
29072
|
+
if (gap < 0 || gap > ADDRESS_LIST_ANCHOR_GAP_MAX) return null;
|
|
29073
|
+
const height = addressListHeightFor(view);
|
|
29074
|
+
if (height > ADDRESS_LIST_MAX_HEIGHT_DIP) return null;
|
|
29075
|
+
const left = Math.max(0, fx);
|
|
29076
|
+
const right = Math.min(ownerWidth, fx + fw);
|
|
29077
|
+
const bottom = Math.min(ownerHeight, top + height);
|
|
29078
|
+
if (right <= left) return null;
|
|
29079
|
+
if (bottom - top !== height) return null;
|
|
29080
|
+
return { x: left, y: top, width: right - left, height };
|
|
29081
|
+
}
|
|
29082
|
+
function addressListRowIndexAt(view, offsetY) {
|
|
29083
|
+
if (view.kind !== "rows") return null;
|
|
29084
|
+
if (!Number.isFinite(offsetY)) return null;
|
|
29085
|
+
const withinRows = offsetY - ADDRESS_LIST_HEADER_HEIGHT - 2;
|
|
29086
|
+
if (withinRows < 0) return null;
|
|
29087
|
+
const index = Math.floor(withinRows / ADDRESS_LIST_ROW_HEIGHT);
|
|
29088
|
+
return index >= 0 && index < view.rows.length ? index : null;
|
|
29089
|
+
}
|
|
29090
|
+
function measurementValue(value) {
|
|
29091
|
+
if (!isRecord$1(value)) return null;
|
|
29092
|
+
if (!Number.isInteger(value.appliedSeq)) return null;
|
|
29093
|
+
if (!Number.isInteger(value.rowCount)) return null;
|
|
29094
|
+
const headerHeight = finite(value.headerHeight);
|
|
29095
|
+
const viewportHeight = finite(value.viewportHeight);
|
|
29096
|
+
const scrollHeight = finite(value.scrollHeight);
|
|
29097
|
+
if (headerHeight === null || viewportHeight === null || scrollHeight === null)
|
|
29098
|
+
return null;
|
|
29099
|
+
if (!Array.isArray(value.rowRects)) return null;
|
|
29100
|
+
const rowRects = [];
|
|
29101
|
+
for (const entry of value.rowRects) {
|
|
29102
|
+
if (!isRecord$1(entry)) return null;
|
|
29103
|
+
const top = finite(entry.top);
|
|
29104
|
+
const height = finite(entry.height);
|
|
29105
|
+
if (top === null || height === null) return null;
|
|
29106
|
+
rowRects.push({ top, height });
|
|
29107
|
+
}
|
|
29108
|
+
const innerHeight = finite(value.innerHeight);
|
|
29109
|
+
const visualHeight = finite(value.visualHeight);
|
|
29110
|
+
let activeRowRect = null;
|
|
29111
|
+
if (value.activeRowRect !== null && value.activeRowRect !== void 0) {
|
|
29112
|
+
if (!isRecord$1(value.activeRowRect)) return null;
|
|
29113
|
+
const top = finite(value.activeRowRect.top);
|
|
29114
|
+
const height = finite(value.activeRowRect.height);
|
|
29115
|
+
if (top === null || height === null) return null;
|
|
29116
|
+
activeRowRect = { top, height };
|
|
29117
|
+
}
|
|
29118
|
+
const appliedSeq = value.appliedSeq;
|
|
29119
|
+
const rowCount = value.rowCount;
|
|
29120
|
+
if (typeof appliedSeq !== "number" || typeof rowCount !== "number")
|
|
29121
|
+
return null;
|
|
29122
|
+
return {
|
|
29123
|
+
appliedSeq,
|
|
29124
|
+
rowCount,
|
|
29125
|
+
headerHeight,
|
|
29126
|
+
rowRects,
|
|
29127
|
+
viewportHeight,
|
|
29128
|
+
scrollHeight,
|
|
29129
|
+
...innerHeight === null ? {} : { innerHeight },
|
|
29130
|
+
...visualHeight === null ? {} : { visualHeight },
|
|
29131
|
+
activeRowRect
|
|
29132
|
+
};
|
|
29133
|
+
}
|
|
29134
|
+
function addressListMeasurementProblem(raw, projection, requestedHeight) {
|
|
29135
|
+
const measurement = measurementValue(raw);
|
|
29136
|
+
if (measurement === null) return "measure_invalid";
|
|
29137
|
+
if (measurement.appliedSeq !== projection.seq) return "measure_stale";
|
|
29138
|
+
const reported = measurement.visualHeight ?? measurement.innerHeight;
|
|
29139
|
+
if (reported !== void 0 && Math.abs(reported - requestedHeight) > 1) {
|
|
29140
|
+
return "measure_viewport";
|
|
29141
|
+
}
|
|
29142
|
+
if (projection.view.kind !== "rows") {
|
|
29143
|
+
return measurement.rowCount === 0 ? null : "measure_extra_rows";
|
|
29144
|
+
}
|
|
29145
|
+
const rows = projection.view.rows;
|
|
29146
|
+
if (measurement.rowCount !== rows.length) return "measure_row_count";
|
|
29147
|
+
if (measurement.rowRects.length !== rows.length) return "measure_row_rects";
|
|
29148
|
+
if (Math.abs(measurement.headerHeight - ADDRESS_LIST_HEADER_HEIGHT) > 0.5) {
|
|
29149
|
+
return "measure_header";
|
|
29150
|
+
}
|
|
29151
|
+
for (const row of measurement.rowRects) {
|
|
29152
|
+
if (Math.abs(row.height - ADDRESS_LIST_ROW_HEIGHT) > 0.5) {
|
|
29153
|
+
return "measure_row_height";
|
|
29154
|
+
}
|
|
29155
|
+
}
|
|
29156
|
+
if (measurement.scrollHeight > measurement.viewportHeight + 1) {
|
|
29157
|
+
return "measure_scroll";
|
|
29158
|
+
}
|
|
29159
|
+
if (projection.active >= 0) {
|
|
29160
|
+
if (measurement.activeRowRect === null) return "measure_active_missing";
|
|
29161
|
+
const paintBox = measurement.visualHeight ?? measurement.innerHeight ?? requestedHeight;
|
|
29162
|
+
const { top, height } = measurement.activeRowRect;
|
|
29163
|
+
const documentBottom = measurement.headerHeight + top + height;
|
|
29164
|
+
if (top < -0.5 || documentBottom > paintBox + 0.5) {
|
|
29165
|
+
return "active_not_visible";
|
|
29166
|
+
}
|
|
29167
|
+
}
|
|
29168
|
+
return null;
|
|
29169
|
+
}
|
|
29170
|
+
function addressListViewModel(projection) {
|
|
29171
|
+
const fallback = {
|
|
29172
|
+
elevated: ADDRESS_LIST_THEME_FALLBACK,
|
|
29173
|
+
ink: "#e6e8ea",
|
|
29174
|
+
inkMuted: "#9aa0a6",
|
|
29175
|
+
accent: "#5b9dd9",
|
|
29176
|
+
accentWash: "#23303d",
|
|
29177
|
+
rowHover: "#24282e",
|
|
29178
|
+
hairline: "#2f343b",
|
|
29179
|
+
control: "#3a4048"
|
|
29180
|
+
};
|
|
29181
|
+
const theme = projection.theme ?? fallback;
|
|
29182
|
+
return {
|
|
29183
|
+
v: 1,
|
|
29184
|
+
seq: projection.seq,
|
|
29185
|
+
dir: projection.dir,
|
|
29186
|
+
label: projection.label,
|
|
29187
|
+
active: projection.active,
|
|
29188
|
+
view: projection.view,
|
|
29189
|
+
height: addressListHeightFor(projection.view),
|
|
29190
|
+
theme
|
|
29191
|
+
};
|
|
29192
|
+
}
|
|
28766
29193
|
const ADDRESS_OVERLAY_S1_ENV = "LOCAL_OPERATOR_UI_BROWSER_ADDRESS_OVERLAY_S1";
|
|
29194
|
+
const ADDRESS_OVERLAY_VISIBLE_ENV = "LOCAL_OPERATOR_UI_BROWSER_ADDRESS_OVERLAY_VISIBLE";
|
|
29195
|
+
const ADDRESS_OVERLAY_VISIBLE_MAX_MS = 12e4;
|
|
28767
29196
|
const ADDRESS_OVERLAY_DOCUMENT = "browser-address-overlay.html";
|
|
28768
29197
|
const ADDRESS_OVERLAY_MAX_HEIGHT_DIP = 160;
|
|
28769
29198
|
const ADDRESS_OVERLAY_READY_TIMEOUT_MS = 5e3;
|
|
@@ -28771,25 +29200,132 @@ const DIP_INT32_MAX = 2 ** 31 - 1;
|
|
|
28771
29200
|
const INDEX_DOCUMENT_SUFFIX$2 = /\/?index\.html(\?.*)?$/;
|
|
28772
29201
|
const TRAILING_SLASH$1 = /\/$/;
|
|
28773
29202
|
function addressOverlayDocumentUrlFor(rendererUrl) {
|
|
28774
|
-
return
|
|
29203
|
+
return documentUrlFor(rendererUrl, ADDRESS_OVERLAY_DOCUMENT);
|
|
29204
|
+
}
|
|
29205
|
+
function addressListDocumentUrlFor(rendererUrl) {
|
|
29206
|
+
return documentUrlFor(rendererUrl, ADDRESS_LIST_DOCUMENT);
|
|
29207
|
+
}
|
|
29208
|
+
function documentUrlFor(rendererUrl, document) {
|
|
29209
|
+
return INDEX_DOCUMENT_SUFFIX$2.test(rendererUrl) ? rendererUrl.replace(INDEX_DOCUMENT_SUFFIX$2, `/${document}`) : `${rendererUrl.replace(TRAILING_SLASH$1, "")}/${document}`;
|
|
28775
29210
|
}
|
|
28776
29211
|
function resolveAddressOverlayGate(input) {
|
|
28777
29212
|
const raw = input.env[ADDRESS_OVERLAY_S1_ENV];
|
|
29213
|
+
const listRaw = input.env[ADDRESS_LIST_ENV];
|
|
29214
|
+
const visibleRaw = input.env[ADDRESS_OVERLAY_VISIBLE_ENV];
|
|
29215
|
+
const listAsked = listRaw !== void 0 && listRaw.trim() !== "";
|
|
29216
|
+
const visibleAsked = visibleRaw !== void 0 && visibleRaw.trim() !== "";
|
|
28778
29217
|
if (raw === void 0 || raw.trim() === "") {
|
|
28779
|
-
|
|
29218
|
+
if (visibleAsked) {
|
|
29219
|
+
return {
|
|
29220
|
+
asked: true,
|
|
29221
|
+
enabled: false,
|
|
29222
|
+
list: false,
|
|
29223
|
+
visible: false,
|
|
29224
|
+
reason: `${ADDRESS_OVERLAY_VISIBLE_ENV} needs ${ADDRESS_OVERLAY_S1_ENV}=1 and ${ADDRESS_LIST_ENV}=1: the visible probe is an increment on S1's child and S2's mirror, not a third arm`
|
|
29225
|
+
};
|
|
29226
|
+
}
|
|
29227
|
+
return listAsked ? {
|
|
29228
|
+
asked: true,
|
|
29229
|
+
enabled: false,
|
|
29230
|
+
list: false,
|
|
29231
|
+
visible: false,
|
|
29232
|
+
reason: `${ADDRESS_LIST_ENV} needs ${ADDRESS_OVERLAY_S1_ENV}=1: S2's list is a mirror inside S1's child, not a second child`
|
|
29233
|
+
} : {
|
|
29234
|
+
asked: false,
|
|
29235
|
+
enabled: false,
|
|
29236
|
+
list: false,
|
|
29237
|
+
visible: false,
|
|
29238
|
+
reason: null
|
|
29239
|
+
};
|
|
28780
29240
|
}
|
|
28781
29241
|
const asked = true;
|
|
28782
29242
|
if (raw.trim() !== "1") {
|
|
28783
29243
|
return {
|
|
28784
29244
|
asked,
|
|
28785
29245
|
enabled: false,
|
|
29246
|
+
list: false,
|
|
29247
|
+
visible: false,
|
|
28786
29248
|
reason: `${ADDRESS_OVERLAY_S1_ENV}=${raw.trim()} is not an opt-in (accepted: 1); the address overlay stayed off`
|
|
28787
29249
|
};
|
|
28788
29250
|
}
|
|
29251
|
+
if (listAsked && listRaw.trim() !== "1") {
|
|
29252
|
+
return {
|
|
29253
|
+
asked,
|
|
29254
|
+
enabled: false,
|
|
29255
|
+
list: false,
|
|
29256
|
+
visible: false,
|
|
29257
|
+
reason: `${ADDRESS_LIST_ENV}=${listRaw.trim()} is not an opt-in (accepted: 1); the address overlay stayed off`
|
|
29258
|
+
};
|
|
29259
|
+
}
|
|
29260
|
+
if (visibleAsked) {
|
|
29261
|
+
if (visibleRaw.trim() !== "1") {
|
|
29262
|
+
return {
|
|
29263
|
+
asked,
|
|
29264
|
+
enabled: false,
|
|
29265
|
+
list: false,
|
|
29266
|
+
visible: false,
|
|
29267
|
+
reason: `${ADDRESS_OVERLAY_VISIBLE_ENV}=${visibleRaw.trim()} is not an opt-in (accepted: 1); the address overlay stayed off`
|
|
29268
|
+
};
|
|
29269
|
+
}
|
|
29270
|
+
if (!listAsked) {
|
|
29271
|
+
return {
|
|
29272
|
+
asked,
|
|
29273
|
+
enabled: false,
|
|
29274
|
+
list: false,
|
|
29275
|
+
visible: false,
|
|
29276
|
+
reason: `${ADDRESS_OVERLAY_VISIBLE_ENV} needs ${ADDRESS_LIST_ENV}=1: S3's visible probe shows S2's mirror, never a bare S1 child`
|
|
29277
|
+
};
|
|
29278
|
+
}
|
|
29279
|
+
if (input.windowMode === "headless") {
|
|
29280
|
+
return {
|
|
29281
|
+
asked,
|
|
29282
|
+
enabled: false,
|
|
29283
|
+
list: false,
|
|
29284
|
+
visible: false,
|
|
29285
|
+
reason: `${ADDRESS_OVERLAY_VISIBLE_ENV} refused in a "headless" window: a headless run labelled visible would misattribute its evidence; use --window-mode=inactive`
|
|
29286
|
+
};
|
|
29287
|
+
}
|
|
29288
|
+
if (input.windowMode !== "inactive") {
|
|
29289
|
+
return {
|
|
29290
|
+
asked,
|
|
29291
|
+
enabled: false,
|
|
29292
|
+
list: false,
|
|
29293
|
+
visible: false,
|
|
29294
|
+
reason: `${ADDRESS_OVERLAY_VISIBLE_ENV} refused in a "${input.windowMode}" window: a visible probe never runs in the product's own mode; use --window-mode=inactive`
|
|
29295
|
+
};
|
|
29296
|
+
}
|
|
29297
|
+
if (!input.devDriverArmed) {
|
|
29298
|
+
return {
|
|
29299
|
+
asked,
|
|
29300
|
+
enabled: false,
|
|
29301
|
+
list: false,
|
|
29302
|
+
visible: false,
|
|
29303
|
+
reason: "the visible address overlay needs the armed renderer dev driver; it has no product path"
|
|
29304
|
+
};
|
|
29305
|
+
}
|
|
29306
|
+
if (input.packaged === true) {
|
|
29307
|
+
return {
|
|
29308
|
+
asked,
|
|
29309
|
+
enabled: false,
|
|
29310
|
+
list: false,
|
|
29311
|
+
visible: false,
|
|
29312
|
+
reason: `${ADDRESS_OVERLAY_VISIBLE_ENV} refused in a packaged build: S3 is an unpackaged probe, never product surface`
|
|
29313
|
+
};
|
|
29314
|
+
}
|
|
29315
|
+
return {
|
|
29316
|
+
asked,
|
|
29317
|
+
enabled: true,
|
|
29318
|
+
list: true,
|
|
29319
|
+
visible: true,
|
|
29320
|
+
reason: null
|
|
29321
|
+
};
|
|
29322
|
+
}
|
|
28789
29323
|
if (!input.devDriverArmed) {
|
|
28790
29324
|
return {
|
|
28791
29325
|
asked,
|
|
28792
29326
|
enabled: false,
|
|
29327
|
+
list: false,
|
|
29328
|
+
visible: false,
|
|
28793
29329
|
reason: "the address overlay needs the armed renderer dev driver; it has no user-facing trigger in S1"
|
|
28794
29330
|
};
|
|
28795
29331
|
}
|
|
@@ -28797,10 +29333,18 @@ function resolveAddressOverlayGate(input) {
|
|
|
28797
29333
|
return {
|
|
28798
29334
|
asked,
|
|
28799
29335
|
enabled: false,
|
|
29336
|
+
list: false,
|
|
29337
|
+
visible: false,
|
|
28800
29338
|
reason: `the address overlay refused to arm in a "${input.windowMode}" window; S1 has no user-facing path, so use --window-mode=headless`
|
|
28801
29339
|
};
|
|
28802
29340
|
}
|
|
28803
|
-
return {
|
|
29341
|
+
return {
|
|
29342
|
+
asked,
|
|
29343
|
+
enabled: true,
|
|
29344
|
+
list: listAsked,
|
|
29345
|
+
visible: false,
|
|
29346
|
+
reason: null
|
|
29347
|
+
};
|
|
28804
29348
|
}
|
|
28805
29349
|
function int32(value) {
|
|
28806
29350
|
if (typeof value !== "number" || !Number.isFinite(value)) return null;
|
|
@@ -28844,11 +29388,15 @@ function copyLayout(snapshot2) {
|
|
|
28844
29388
|
};
|
|
28845
29389
|
}
|
|
28846
29390
|
function layoutKeyOf(snapshot2) {
|
|
28847
|
-
const
|
|
28848
|
-
return `${snapshot2.activeTabId}:${snapshot2.presented ? 1 : 0}:${
|
|
29391
|
+
const rect2 = snapshot2.contentRect;
|
|
29392
|
+
return `${snapshot2.activeTabId}:${snapshot2.presented ? 1 : 0}:${rect2 ? `${rect2.x},${rect2.y},${rect2.width},${rect2.height}` : "null"}`;
|
|
29393
|
+
}
|
|
29394
|
+
function sameRect(a, b) {
|
|
29395
|
+
if (b === null) return false;
|
|
29396
|
+
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
|
28849
29397
|
}
|
|
28850
29398
|
const OVERLAY_BACKGROUND = "#1b1f24";
|
|
28851
|
-
function createHardenedView() {
|
|
29399
|
+
function createHardenedView(options) {
|
|
28852
29400
|
const partition = `address-overlay-${node_crypto.randomUUID()}`;
|
|
28853
29401
|
const childSession = electron.session.fromPartition(partition);
|
|
28854
29402
|
childSession.setPermissionRequestHandler(
|
|
@@ -28868,10 +29416,15 @@ function createHardenedView() {
|
|
|
28868
29416
|
nodeIntegration: false,
|
|
28869
29417
|
webSecurity: true,
|
|
28870
29418
|
allowRunningInsecureContent: false,
|
|
28871
|
-
// No `preload`, and no
|
|
28872
|
-
//
|
|
28873
|
-
|
|
28874
|
-
|
|
29419
|
+
// No `preload`, and no app imports in either document. The flag is the
|
|
29420
|
+
// S1/S2 split: false for the inert document, true for the mirror list.
|
|
29421
|
+
javascript: options.javascript,
|
|
29422
|
+
// The mirror is a tiny document that must stay frame-accurate while the
|
|
29423
|
+
// owner window is hidden, unfocused or occluded (headless probe, a
|
|
29424
|
+
// background app window). Chromium otherwise throttles its frame loop,
|
|
29425
|
+
// and a native resize can sit unapplied for ~1 s — the exact interval
|
|
29426
|
+
// `measure_viewport` is there to catch. S1 keeps the default.
|
|
29427
|
+
...options.javascript ? { backgroundThrottling: false } : {}
|
|
28875
29428
|
}
|
|
28876
29429
|
});
|
|
28877
29430
|
view.webContents.setWindowOpenHandler(() => ({ action: "deny" }));
|
|
@@ -28882,6 +29435,8 @@ class AddressOverlayController {
|
|
|
28882
29435
|
window;
|
|
28883
29436
|
documentUrl;
|
|
28884
29437
|
createView;
|
|
29438
|
+
javascript;
|
|
29439
|
+
onEvent;
|
|
28885
29440
|
readinessTimeoutMs;
|
|
28886
29441
|
log;
|
|
28887
29442
|
now;
|
|
@@ -28909,10 +29464,42 @@ class AddressOverlayController {
|
|
|
28909
29464
|
disposed;
|
|
28910
29465
|
ownerListeners;
|
|
28911
29466
|
childListeners;
|
|
29467
|
+
// ---- S2 mirror state ----------------------------------------------------
|
|
29468
|
+
lastSeq;
|
|
29469
|
+
shownSeq;
|
|
29470
|
+
lastProjection;
|
|
29471
|
+
/** The rectangle last applied for a projection. `onLayout`'s unchanged-key
|
|
29472
|
+
* re-assert uses THIS, never the S1 top-strip rule: an S2 child sits at the
|
|
29473
|
+
* dock, and re-raising it with the S1 rectangle would move the list. */
|
|
29474
|
+
lastAppliedBounds;
|
|
29475
|
+
lastMeasurement;
|
|
29476
|
+
themeFact;
|
|
29477
|
+
applyCount;
|
|
29478
|
+
commitsEmitted;
|
|
29479
|
+
commitsDropped;
|
|
29480
|
+
hideCounts;
|
|
29481
|
+
keysBlocked;
|
|
29482
|
+
mouseDowns;
|
|
29483
|
+
mouseUps;
|
|
29484
|
+
mouseMoves;
|
|
29485
|
+
mouseDownRow;
|
|
29486
|
+
contextMenuBlocked;
|
|
29487
|
+
// ---- S3 focus facts -----------------------------------------------------
|
|
29488
|
+
/** Counted only for the scripted (S2/S3) child, so S1's listener set stays
|
|
29489
|
+
* exactly what it was; see `wireChild`'s S2 policy comment. */
|
|
29490
|
+
childFocusEvents;
|
|
29491
|
+
childBlurEvents;
|
|
29492
|
+
/** The launch gate's `visible` fact, copied in so `facts()` can report it
|
|
29493
|
+
* without re-deriving the gate (which it must never do: one pure decision). */
|
|
29494
|
+
visibleMode;
|
|
29495
|
+
lastRejected;
|
|
29496
|
+
projectQueue;
|
|
28912
29497
|
constructor(deps) {
|
|
28913
29498
|
this.window = deps.window;
|
|
28914
29499
|
this.documentUrl = deps.documentUrl;
|
|
28915
|
-
this.createView = deps.createView ?? createHardenedView;
|
|
29500
|
+
this.createView = deps.createView ?? (() => createHardenedView({ javascript: deps.javascript === true }));
|
|
29501
|
+
this.javascript = deps.javascript === true;
|
|
29502
|
+
this.onEvent = deps.onEvent ?? null;
|
|
28916
29503
|
this.readinessTimeoutMs = deps.readinessTimeoutMs ?? ADDRESS_OVERLAY_READY_TIMEOUT_MS;
|
|
28917
29504
|
this.log = deps.log ?? (() => {
|
|
28918
29505
|
});
|
|
@@ -28946,6 +29533,27 @@ class AddressOverlayController {
|
|
|
28946
29533
|
this.disposed = false;
|
|
28947
29534
|
this.ownerListeners = [];
|
|
28948
29535
|
this.childListeners = [];
|
|
29536
|
+
this.lastSeq = 0;
|
|
29537
|
+
this.shownSeq = -1;
|
|
29538
|
+
this.lastProjection = null;
|
|
29539
|
+
this.lastAppliedBounds = null;
|
|
29540
|
+
this.lastMeasurement = null;
|
|
29541
|
+
this.themeFact = "absent";
|
|
29542
|
+
this.applyCount = 0;
|
|
29543
|
+
this.commitsEmitted = 0;
|
|
29544
|
+
this.commitsDropped = /* @__PURE__ */ new Map();
|
|
29545
|
+
this.hideCounts = /* @__PURE__ */ new Map();
|
|
29546
|
+
this.keysBlocked = 0;
|
|
29547
|
+
this.mouseDowns = 0;
|
|
29548
|
+
this.mouseUps = 0;
|
|
29549
|
+
this.mouseMoves = 0;
|
|
29550
|
+
this.mouseDownRow = null;
|
|
29551
|
+
this.contextMenuBlocked = 0;
|
|
29552
|
+
this.childFocusEvents = 0;
|
|
29553
|
+
this.childBlurEvents = 0;
|
|
29554
|
+
this.visibleMode = deps.visible === true;
|
|
29555
|
+
this.lastRejected = null;
|
|
29556
|
+
this.projectQueue = Promise.resolve();
|
|
28949
29557
|
this.attachOwnerListeners();
|
|
28950
29558
|
}
|
|
28951
29559
|
// ---- observer hooks ------------------------------------------------------
|
|
@@ -28975,7 +29583,7 @@ class AddressOverlayController {
|
|
|
28975
29583
|
if (this.state !== "shown") return;
|
|
28976
29584
|
const view = this.view;
|
|
28977
29585
|
if (!view || this.viewUsable(view) === false) return;
|
|
28978
|
-
const bounds = overlayBoundsFor(next.contentRect, this.ownerSize());
|
|
29586
|
+
const bounds = this.lastProjection !== null ? this.lastAppliedBounds : overlayBoundsFor(next.contentRect, this.ownerSize());
|
|
28979
29587
|
if (bounds === null || !next.presented) {
|
|
28980
29588
|
this.hide("layout_invalid");
|
|
28981
29589
|
return;
|
|
@@ -29022,6 +29630,10 @@ class AddressOverlayController {
|
|
|
29022
29630
|
this.generation += 1;
|
|
29023
29631
|
this.settleReady(false);
|
|
29024
29632
|
this.hiddenReason = reason;
|
|
29633
|
+
this.hideCounts.set(reason, (this.hideCounts.get(reason) ?? 0) + 1);
|
|
29634
|
+
this.shownSeq = -1;
|
|
29635
|
+
this.mouseDownRow = null;
|
|
29636
|
+
this.lastMeasurement = null;
|
|
29025
29637
|
const view = this.view;
|
|
29026
29638
|
if (view && this.viewUsable(view)) {
|
|
29027
29639
|
try {
|
|
@@ -29034,6 +29646,14 @@ class AddressOverlayController {
|
|
|
29034
29646
|
}
|
|
29035
29647
|
this.log(`[browser] address overlay hidden: ${reason}`);
|
|
29036
29648
|
}
|
|
29649
|
+
/** `WebContents.isFocused()` behind a guard: a disposed view throws. */
|
|
29650
|
+
childIsFocused(view) {
|
|
29651
|
+
try {
|
|
29652
|
+
return view.webContents.isFocused();
|
|
29653
|
+
} catch {
|
|
29654
|
+
return false;
|
|
29655
|
+
}
|
|
29656
|
+
}
|
|
29037
29657
|
/** Facts only: identifiers, geometry and counters. No page content. */
|
|
29038
29658
|
facts() {
|
|
29039
29659
|
const view = this.view;
|
|
@@ -29056,7 +29676,10 @@ class AddressOverlayController {
|
|
|
29056
29676
|
visible,
|
|
29057
29677
|
bounds,
|
|
29058
29678
|
order,
|
|
29059
|
-
childCount
|
|
29679
|
+
childCount,
|
|
29680
|
+
focusEvents: this.childFocusEvents,
|
|
29681
|
+
blurEvents: this.childBlurEvents,
|
|
29682
|
+
isFocused: this.childIsFocused(view)
|
|
29060
29683
|
};
|
|
29061
29684
|
}
|
|
29062
29685
|
let ownerDestroyed = true;
|
|
@@ -29067,6 +29690,18 @@ class AddressOverlayController {
|
|
|
29067
29690
|
} catch {
|
|
29068
29691
|
ownerDestroyed = true;
|
|
29069
29692
|
}
|
|
29693
|
+
let ownerWindowFocused = false;
|
|
29694
|
+
try {
|
|
29695
|
+
ownerWindowFocused = !ownerDestroyed && this.window.isFocused();
|
|
29696
|
+
} catch {
|
|
29697
|
+
ownerWindowFocused = false;
|
|
29698
|
+
}
|
|
29699
|
+
let ownerFocusedContentsId = null;
|
|
29700
|
+
try {
|
|
29701
|
+
ownerFocusedContentsId = electron.webContents.getFocusedWebContents()?.id ?? null;
|
|
29702
|
+
} catch {
|
|
29703
|
+
ownerFocusedContentsId = null;
|
|
29704
|
+
}
|
|
29070
29705
|
return {
|
|
29071
29706
|
documentUrl: this.documentUrl,
|
|
29072
29707
|
state: this.state,
|
|
@@ -29094,10 +29729,36 @@ class AddressOverlayController {
|
|
|
29094
29729
|
},
|
|
29095
29730
|
pendingShow: this.showInFlight !== null,
|
|
29096
29731
|
readinessTimer: this.readinessTimer !== null,
|
|
29732
|
+
visibleMode: this.visibleMode,
|
|
29733
|
+
ownerFocusedContentsId,
|
|
29734
|
+
ownerWindowFocused,
|
|
29735
|
+
s2: {
|
|
29736
|
+
list: this.javascript,
|
|
29737
|
+
javascript: this.javascript,
|
|
29738
|
+
lastSeq: this.lastSeq,
|
|
29739
|
+
shownSeq: this.shownSeq,
|
|
29740
|
+
lastRejected: this.lastRejected,
|
|
29741
|
+
theme: this.themeFact,
|
|
29742
|
+
applyCount: this.applyCount,
|
|
29743
|
+
view: this.lastProjection === null ? { kind: "none", rowCount: 0, active: -1 } : {
|
|
29744
|
+
kind: this.lastProjection.view.kind,
|
|
29745
|
+
rowCount: this.lastProjection.view.kind === "rows" ? this.lastProjection.view.rows.length : 0,
|
|
29746
|
+
active: this.lastProjection.active
|
|
29747
|
+
},
|
|
29748
|
+
measured: this.lastMeasurement,
|
|
29749
|
+
commitsEmitted: this.commitsEmitted,
|
|
29750
|
+
commitsDropped: Object.fromEntries(this.commitsDropped),
|
|
29751
|
+
hideCounts: Object.fromEntries(this.hideCounts),
|
|
29752
|
+
keysBlocked: this.keysBlocked,
|
|
29753
|
+
mouseDowns: this.mouseDowns,
|
|
29754
|
+
mouseUps: this.mouseUps,
|
|
29755
|
+
mouseMoves: this.mouseMoves,
|
|
29756
|
+
contextMenuBlocked: this.contextMenuBlocked
|
|
29757
|
+
},
|
|
29097
29758
|
metrics: this.appMetrics ? this.appMetrics() : null
|
|
29098
29759
|
};
|
|
29099
29760
|
}
|
|
29100
|
-
async probe(action) {
|
|
29761
|
+
async probe(action, argument) {
|
|
29101
29762
|
if (action === "show") {
|
|
29102
29763
|
await this.showOverlay();
|
|
29103
29764
|
return this.facts();
|
|
@@ -29106,8 +29767,278 @@ class AddressOverlayController {
|
|
|
29106
29767
|
this.hide("probe");
|
|
29107
29768
|
return this.facts();
|
|
29108
29769
|
}
|
|
29770
|
+
if (action === "click") {
|
|
29771
|
+
this.probeClick(argument);
|
|
29772
|
+
await new Promise((done) => setTimeout(done, 40));
|
|
29773
|
+
return this.facts();
|
|
29774
|
+
}
|
|
29775
|
+
if (action === "measure") {
|
|
29776
|
+
await this.probeMeasure();
|
|
29777
|
+
return this.facts();
|
|
29778
|
+
}
|
|
29779
|
+
if (action === "key") {
|
|
29780
|
+
this.probeKey(argument);
|
|
29781
|
+
await new Promise((done) => setTimeout(done, 20));
|
|
29782
|
+
return this.facts();
|
|
29783
|
+
}
|
|
29109
29784
|
return this.facts();
|
|
29110
29785
|
}
|
|
29786
|
+
/**
|
|
29787
|
+
* Apply one renderer projection (S2). Everything arriving here was or will be
|
|
29788
|
+
* revalidated: JSON size, shape, every string, tab/layout freshness, zoom,
|
|
29789
|
+
* anchor geometry and — after the child paints — the child's own measurements.
|
|
29790
|
+
*
|
|
29791
|
+
* Serialized: a per-frame renderer can outpace `executeJavaScript`, and two
|
|
29792
|
+
* overlapping applies would let an older model win. The queue is per
|
|
29793
|
+
* controller, so a burst between frames costs one apply each in arrival order.
|
|
29794
|
+
*/
|
|
29795
|
+
project(raw) {
|
|
29796
|
+
const run = () => this.projectOnce(raw);
|
|
29797
|
+
const next = this.projectQueue.then(run, run);
|
|
29798
|
+
this.projectQueue = next.then(
|
|
29799
|
+
() => void 0,
|
|
29800
|
+
() => void 0
|
|
29801
|
+
);
|
|
29802
|
+
return next;
|
|
29803
|
+
}
|
|
29804
|
+
async projectOnce(raw) {
|
|
29805
|
+
const parsed = sanitizeProjection(raw);
|
|
29806
|
+
if (!parsed.ok) {
|
|
29807
|
+
this.drop(parsed.reason);
|
|
29808
|
+
return {
|
|
29809
|
+
accepted: false,
|
|
29810
|
+
shown: false,
|
|
29811
|
+
reason: parsed.reason,
|
|
29812
|
+
bounds: null
|
|
29813
|
+
};
|
|
29814
|
+
}
|
|
29815
|
+
const projection = parsed.projection;
|
|
29816
|
+
this.themeFact = projection.themeFact;
|
|
29817
|
+
if (!projection.visible) {
|
|
29818
|
+
if (projection.seq > this.lastSeq) this.lastSeq = projection.seq;
|
|
29819
|
+
this.hide("projection_hidden");
|
|
29820
|
+
return { accepted: true, shown: false, reason: null, bounds: null };
|
|
29821
|
+
}
|
|
29822
|
+
if (this.disposed) {
|
|
29823
|
+
return this.refuseProjection("disposed");
|
|
29824
|
+
}
|
|
29825
|
+
if (projection.seq < this.lastSeq) {
|
|
29826
|
+
this.drop("stale_seq");
|
|
29827
|
+
return {
|
|
29828
|
+
accepted: false,
|
|
29829
|
+
shown: this.state === "shown",
|
|
29830
|
+
reason: "stale_seq",
|
|
29831
|
+
bounds: null
|
|
29832
|
+
};
|
|
29833
|
+
}
|
|
29834
|
+
if (projection.seq === this.lastSeq && projection.seq === this.shownSeq) {
|
|
29835
|
+
return {
|
|
29836
|
+
accepted: true,
|
|
29837
|
+
shown: this.state === "shown",
|
|
29838
|
+
reason: null,
|
|
29839
|
+
bounds: this.view && this.viewUsable(this.view) ? this.view.getBounds() : null
|
|
29840
|
+
};
|
|
29841
|
+
}
|
|
29842
|
+
if (this.failedReason) return this.refuseProjection("overlay_failed");
|
|
29843
|
+
if (this.ownerUnavailable()) {
|
|
29844
|
+
this.releaseChild("owner_unavailable");
|
|
29845
|
+
return this.refuseProjection("owner_unavailable");
|
|
29846
|
+
}
|
|
29847
|
+
const zoom = this.ownerZoom();
|
|
29848
|
+
if (zoom === null || Math.abs(zoom - 1) > 1e-3) {
|
|
29849
|
+
return this.refuseProjection("zoomed");
|
|
29850
|
+
}
|
|
29851
|
+
const layout = this.layout;
|
|
29852
|
+
if (projection.tabId !== layout.activeTabId) {
|
|
29853
|
+
return this.refuseProjection("stale_tab");
|
|
29854
|
+
}
|
|
29855
|
+
if (!layout.presented || !sameRect(projection.pageRect, layout.contentRect)) {
|
|
29856
|
+
return this.refuseProjection("stale_layout");
|
|
29857
|
+
}
|
|
29858
|
+
const bounds = addressListBoundsFor(
|
|
29859
|
+
projection.field,
|
|
29860
|
+
projection.listTop,
|
|
29861
|
+
projection.view,
|
|
29862
|
+
this.ownerSize()
|
|
29863
|
+
);
|
|
29864
|
+
if (bounds === null) return this.refuseProjection("anchor_inconsistent");
|
|
29865
|
+
this.generation += 1;
|
|
29866
|
+
const generation = this.generation;
|
|
29867
|
+
this.boundTabId = projection.tabId;
|
|
29868
|
+
if (!this.view) {
|
|
29869
|
+
const created = this.createChild(bounds);
|
|
29870
|
+
if (!created) {
|
|
29871
|
+
return this.refuseProjection(
|
|
29872
|
+
this.failedReason ?? "child_create_failed"
|
|
29873
|
+
);
|
|
29874
|
+
}
|
|
29875
|
+
}
|
|
29876
|
+
if (!(this.domReady && this.finished)) {
|
|
29877
|
+
this.state = "loading";
|
|
29878
|
+
const ready = await this.waitForReady();
|
|
29879
|
+
if (!ready)
|
|
29880
|
+
return this.refuseProjection(this.failedReason ?? "invalidated");
|
|
29881
|
+
}
|
|
29882
|
+
if (this.disposed || generation !== this.generation) {
|
|
29883
|
+
return this.refuseProjection("invalidated");
|
|
29884
|
+
}
|
|
29885
|
+
const view = this.view;
|
|
29886
|
+
if (!view || !this.viewUsable(view)) {
|
|
29887
|
+
return this.refuseProjection("child_unavailable");
|
|
29888
|
+
}
|
|
29889
|
+
view.setBounds(bounds);
|
|
29890
|
+
this.raiseChild(view);
|
|
29891
|
+
view.setVisible(true);
|
|
29892
|
+
const model = addressListViewModel(projection);
|
|
29893
|
+
let measured = null;
|
|
29894
|
+
let problem = null;
|
|
29895
|
+
try {
|
|
29896
|
+
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
29897
|
+
if (attempt % 2 === 1) view.setBounds(bounds);
|
|
29898
|
+
measured = await view.webContents.executeJavaScript(
|
|
29899
|
+
`window.__loAddressOverlay && window.__loAddressOverlay.apply(${JSON.stringify(model)})`,
|
|
29900
|
+
false
|
|
29901
|
+
);
|
|
29902
|
+
problem = addressListMeasurementProblem(
|
|
29903
|
+
measured,
|
|
29904
|
+
projection,
|
|
29905
|
+
bounds.height
|
|
29906
|
+
);
|
|
29907
|
+
if (problem === null) break;
|
|
29908
|
+
if (problem !== "measure_scroll" && problem !== "measure_viewport")
|
|
29909
|
+
break;
|
|
29910
|
+
await new Promise((done) => setTimeout(done, 150));
|
|
29911
|
+
}
|
|
29912
|
+
} catch {
|
|
29913
|
+
return this.refuseProjection("apply_error");
|
|
29914
|
+
}
|
|
29915
|
+
if (problem !== null) return this.refuseProjection(problem, bounds);
|
|
29916
|
+
this.applyCount += 1;
|
|
29917
|
+
this.lastSeq = projection.seq;
|
|
29918
|
+
this.shownSeq = projection.seq;
|
|
29919
|
+
this.lastProjection = projection;
|
|
29920
|
+
this.lastAppliedBounds = bounds;
|
|
29921
|
+
this.lastMeasurement = measured;
|
|
29922
|
+
this.lastRejected = null;
|
|
29923
|
+
this.state = "shown";
|
|
29924
|
+
this.hiddenReason = null;
|
|
29925
|
+
return { accepted: true, shown: true, reason: null, bounds };
|
|
29926
|
+
}
|
|
29927
|
+
refuseProjection(reason, bounds = null) {
|
|
29928
|
+
this.lastRejected = reason;
|
|
29929
|
+
this.drop(reason);
|
|
29930
|
+
this.hide(reason);
|
|
29931
|
+
return { accepted: false, shown: false, reason, bounds };
|
|
29932
|
+
}
|
|
29933
|
+
drop(reason) {
|
|
29934
|
+
this.commitsDropped.set(reason, (this.commitsDropped.get(reason) ?? 0) + 1);
|
|
29935
|
+
}
|
|
29936
|
+
ownerZoom() {
|
|
29937
|
+
try {
|
|
29938
|
+
const zoom = this.window.webContents.getZoomFactor();
|
|
29939
|
+
return typeof zoom === "number" && Number.isFinite(zoom) ? zoom : null;
|
|
29940
|
+
} catch {
|
|
29941
|
+
return null;
|
|
29942
|
+
}
|
|
29943
|
+
}
|
|
29944
|
+
rowAt(y) {
|
|
29945
|
+
if (this.state !== "shown") return null;
|
|
29946
|
+
if (this.lastProjection === null) return null;
|
|
29947
|
+
if (this.shownSeq !== this.lastSeq || this.shownSeq < 1) return null;
|
|
29948
|
+
const projection = this.lastProjection;
|
|
29949
|
+
if (projection.view.kind !== "rows") return null;
|
|
29950
|
+
const index = addressListRowIndexAt(projection.view, y);
|
|
29951
|
+
if (index === null || index >= projection.view.rows.length) return null;
|
|
29952
|
+
return index;
|
|
29953
|
+
}
|
|
29954
|
+
emitCommit(index) {
|
|
29955
|
+
const projection = this.lastProjection;
|
|
29956
|
+
const sink = this.onEvent;
|
|
29957
|
+
if (projection === null || sink === null) {
|
|
29958
|
+
this.drop("no_sink");
|
|
29959
|
+
return;
|
|
29960
|
+
}
|
|
29961
|
+
if (projection.view.kind !== "rows" || index >= projection.view.rows.length) {
|
|
29962
|
+
this.drop("commit_index");
|
|
29963
|
+
return;
|
|
29964
|
+
}
|
|
29965
|
+
this.commitsEmitted += 1;
|
|
29966
|
+
sink({ type: "commit", seq: projection.seq, index });
|
|
29967
|
+
this.log(
|
|
29968
|
+
`[browser] address overlay commit emitted: seq=${projection.seq} index=${index}`
|
|
29969
|
+
);
|
|
29970
|
+
}
|
|
29971
|
+
/**
|
|
29972
|
+
* Probe-only mouse path: `sendInputEvent` into the child's own input pipeline.
|
|
29973
|
+
* This exercises the child and the before-mouse-event observer; it does NOT
|
|
29974
|
+
* exercise macOS NSView hit-testing between sibling views (matrix V3).
|
|
29975
|
+
*/
|
|
29976
|
+
probeClick(argument) {
|
|
29977
|
+
const view = this.view;
|
|
29978
|
+
const measurement = this.lastMeasurement;
|
|
29979
|
+
if (!view || !this.viewUsable(view) || !measurement) {
|
|
29980
|
+
throw new Error("address_overlay_click: no applied list to click");
|
|
29981
|
+
}
|
|
29982
|
+
const arg = argument ?? {};
|
|
29983
|
+
const row = arg.row;
|
|
29984
|
+
const upRow = arg.upRow === void 0 ? row : arg.upRow;
|
|
29985
|
+
const rows = measurement.rowRects;
|
|
29986
|
+
if (typeof row !== "number" || !Number.isInteger(row) || !rows[row]) {
|
|
29987
|
+
throw new Error(
|
|
29988
|
+
"address_overlay_click: row must be a rendered row index"
|
|
29989
|
+
);
|
|
29990
|
+
}
|
|
29991
|
+
if (typeof upRow !== "number" || !Number.isInteger(upRow)) {
|
|
29992
|
+
throw new Error("address_overlay_click: upRow must be an integer");
|
|
29993
|
+
}
|
|
29994
|
+
const point = (index) => {
|
|
29995
|
+
const rect2 = rows[index];
|
|
29996
|
+
const fallbackY = ADDRESS_LIST_HEADER_HEIGHT + 2 + (index + 0.5) * ADDRESS_LIST_ROW_HEIGHT;
|
|
29997
|
+
return rect2 ? {
|
|
29998
|
+
x: 40,
|
|
29999
|
+
y: ADDRESS_LIST_HEADER_HEIGHT + 2 + rect2.top + rect2.height / 2
|
|
30000
|
+
} : { x: 40, y: fallbackY };
|
|
30001
|
+
};
|
|
30002
|
+
const receive = (type2, index) => {
|
|
30003
|
+
const { x, y } = point(index);
|
|
30004
|
+
view.webContents.sendInputEvent({
|
|
30005
|
+
type: type2,
|
|
30006
|
+
x: Math.round(x),
|
|
30007
|
+
y: Math.round(y),
|
|
30008
|
+
button: "left",
|
|
30009
|
+
clickCount: 1
|
|
30010
|
+
});
|
|
30011
|
+
};
|
|
30012
|
+
receive("mouseMove", row);
|
|
30013
|
+
receive("mouseDown", row);
|
|
30014
|
+
receive("mouseUp", upRow);
|
|
30015
|
+
}
|
|
30016
|
+
/**
|
|
30017
|
+
* Probe-only key into the child's own input pipeline. It is how the gated
|
|
30018
|
+
* harness proves `before-input-event` swallows keys; CDP-injected keys go
|
|
30019
|
+
* through a different path and were measured NOT to fire it.
|
|
30020
|
+
*/
|
|
30021
|
+
probeKey(argument) {
|
|
30022
|
+
const view = this.view;
|
|
30023
|
+
if (!view || !this.viewUsable(view)) {
|
|
30024
|
+
throw new Error("address_overlay_key: no child");
|
|
30025
|
+
}
|
|
30026
|
+
const arg = argument ?? {};
|
|
30027
|
+
const keyCode = typeof arg.keyCode === "string" && arg.keyCode.length > 0 ? arg.keyCode.slice(0, 32) : "A";
|
|
30028
|
+
view.webContents.sendInputEvent({ type: "keyDown", keyCode });
|
|
30029
|
+
view.webContents.sendInputEvent({ type: "keyUp", keyCode });
|
|
30030
|
+
}
|
|
30031
|
+
async probeMeasure() {
|
|
30032
|
+
const view = this.view;
|
|
30033
|
+
if (!view || !this.viewUsable(view)) {
|
|
30034
|
+
throw new Error("address_overlay_measure: no child");
|
|
30035
|
+
}
|
|
30036
|
+
const measured = await view.webContents.executeJavaScript(
|
|
30037
|
+
"window.__loAddressOverlay && window.__loAddressOverlay.measure()",
|
|
30038
|
+
false
|
|
30039
|
+
);
|
|
30040
|
+
this.lastMeasurement = measured;
|
|
30041
|
+
}
|
|
29111
30042
|
/**
|
|
29112
30043
|
* Idempotent teardown for the host's stop/rollback/window-close paths.
|
|
29113
30044
|
* Closing the webContents before detaching is required: removing a
|
|
@@ -29319,6 +30250,54 @@ class AddressOverlayController {
|
|
|
29319
30250
|
event?.preventDefault?.();
|
|
29320
30251
|
this.log(`[browser] address overlay refused redirect to ${url}`);
|
|
29321
30252
|
});
|
|
30253
|
+
if (!this.javascript) return;
|
|
30254
|
+
on(contents, "before-input-event", (...args) => {
|
|
30255
|
+
const event = args[0];
|
|
30256
|
+
event?.preventDefault?.();
|
|
30257
|
+
this.keysBlocked += 1;
|
|
30258
|
+
});
|
|
30259
|
+
on(contents, "context-menu", (...args) => {
|
|
30260
|
+
const event = args[0];
|
|
30261
|
+
event?.preventDefault?.();
|
|
30262
|
+
this.contextMenuBlocked += 1;
|
|
30263
|
+
});
|
|
30264
|
+
on(contents, "focus", () => {
|
|
30265
|
+
this.childFocusEvents += 1;
|
|
30266
|
+
});
|
|
30267
|
+
on(contents, "blur", () => {
|
|
30268
|
+
this.childBlurEvents += 1;
|
|
30269
|
+
});
|
|
30270
|
+
on(contents, "before-mouse-event", (...args) => {
|
|
30271
|
+
const event = args[0];
|
|
30272
|
+
const mouse = args[1];
|
|
30273
|
+
if (!mouse || typeof mouse.x !== "number" || typeof mouse.y !== "number") {
|
|
30274
|
+
return;
|
|
30275
|
+
}
|
|
30276
|
+
if (mouse.type === "mouseMove") {
|
|
30277
|
+
this.mouseMoves += 1;
|
|
30278
|
+
return;
|
|
30279
|
+
}
|
|
30280
|
+
event?.preventDefault?.();
|
|
30281
|
+
if (mouse.type === "mouseDown") {
|
|
30282
|
+
this.mouseDowns += 1;
|
|
30283
|
+
this.mouseDownRow = this.rowAt(mouse.y);
|
|
30284
|
+
return;
|
|
30285
|
+
}
|
|
30286
|
+
if (mouse.type !== "mouseUp") return;
|
|
30287
|
+
this.mouseUps += 1;
|
|
30288
|
+
const row = this.rowAt(mouse.y);
|
|
30289
|
+
const downRow = this.mouseDownRow;
|
|
30290
|
+
this.mouseDownRow = null;
|
|
30291
|
+
if (downRow === null || row === null) {
|
|
30292
|
+
this.drop("mouse_no_row");
|
|
30293
|
+
return;
|
|
30294
|
+
}
|
|
30295
|
+
if (downRow !== row) {
|
|
30296
|
+
this.drop("mouse_mismatch");
|
|
30297
|
+
return;
|
|
30298
|
+
}
|
|
30299
|
+
this.emitCommit(row);
|
|
30300
|
+
});
|
|
29322
30301
|
}
|
|
29323
30302
|
/** Terminal for this host lifetime: a broken document must not be retried. */
|
|
29324
30303
|
failChild(reason) {
|
|
@@ -64082,8 +65061,8 @@ class TabRegistry {
|
|
|
64082
65061
|
* hijacked window. Visiting the route again reports a fresh rect and restores
|
|
64083
65062
|
* it. A null rect is also how the caller hides the view at teardown, so it must
|
|
64084
65063
|
* never be swallowed on the way here (see `use-browser-chrome`). */
|
|
64085
|
-
setContentRect(
|
|
64086
|
-
this.contentRect =
|
|
65064
|
+
setContentRect(rect2) {
|
|
65065
|
+
this.contentRect = rect2;
|
|
64087
65066
|
this.applyLayout();
|
|
64088
65067
|
}
|
|
64089
65068
|
/** Full-window overlays hide the view (design 11.3): a native view paints
|
|
@@ -64109,16 +65088,16 @@ class TabRegistry {
|
|
|
64109
65088
|
record.view.setVisible(record.presented);
|
|
64110
65089
|
}
|
|
64111
65090
|
this.layoutRevision += 1;
|
|
64112
|
-
const
|
|
65091
|
+
const rect2 = this.contentRect;
|
|
64113
65092
|
try {
|
|
64114
65093
|
this.onLayout({
|
|
64115
65094
|
activeTabId: this.activeTabId,
|
|
64116
65095
|
presented: active?.presented === true,
|
|
64117
|
-
contentRect:
|
|
64118
|
-
x:
|
|
64119
|
-
y:
|
|
64120
|
-
width:
|
|
64121
|
-
height:
|
|
65096
|
+
contentRect: rect2 ? {
|
|
65097
|
+
x: rect2.x,
|
|
65098
|
+
y: rect2.y,
|
|
65099
|
+
width: rect2.width,
|
|
65100
|
+
height: rect2.height
|
|
64122
65101
|
} : null,
|
|
64123
65102
|
revision: this.layoutRevision
|
|
64124
65103
|
});
|
|
@@ -66287,9 +67266,9 @@ class BrowserHost {
|
|
|
66287
67266
|
}
|
|
66288
67267
|
/** Layout authority is the renderer's (design 11.2): it measures the content
|
|
66289
67268
|
* area and reports it, and main applies it to the active tab only. */
|
|
66290
|
-
setContentRect(
|
|
66291
|
-
this.registry.setContentRect(
|
|
66292
|
-
if (
|
|
67269
|
+
setContentRect(rect2) {
|
|
67270
|
+
this.registry.setContentRect(rect2);
|
|
67271
|
+
if (rect2 === null) this.clearPageFocus();
|
|
66293
67272
|
return this.chromeState();
|
|
66294
67273
|
}
|
|
66295
67274
|
/** Full-window overlays hide the view: a native view paints above all DOM, so
|
|
@@ -67219,58 +68198,6 @@ function restrictMode(path2, log2) {
|
|
|
67219
68198
|
);
|
|
67220
68199
|
}
|
|
67221
68200
|
}
|
|
67222
|
-
const DEV_DRIVER_ENV = "LOCAL_OPERATOR_UI_DEV_DRIVER";
|
|
67223
|
-
const DEV_DRIVER_OUT_ENV = "LOCAL_OPERATOR_UI_DEV_DRIVER_OUT";
|
|
67224
|
-
const DEV_DRIVER_ARG = "--lo-dev-driver";
|
|
67225
|
-
const DEV_DRIVER_CAPTURE = "dev-driver-capture";
|
|
67226
|
-
const DEV_DRIVER_FACTS = "dev-driver-facts";
|
|
67227
|
-
const DEV_DRIVER_ADDRESS_OVERLAY = "dev-driver-address-overlay";
|
|
67228
|
-
const TRUTHY = /* @__PURE__ */ new Set(["1", "true"]);
|
|
67229
|
-
function readOptIn(env) {
|
|
67230
|
-
const raw = env[DEV_DRIVER_ENV];
|
|
67231
|
-
if (raw === void 0 || raw.trim() === "")
|
|
67232
|
-
return { asked: false, value: null };
|
|
67233
|
-
return { asked: true, value: raw.trim() };
|
|
67234
|
-
}
|
|
67235
|
-
function resolveDevDriverArming(input) {
|
|
67236
|
-
const off = (problems = []) => ({
|
|
67237
|
-
armed: false,
|
|
67238
|
-
outDir: null,
|
|
67239
|
-
problems
|
|
67240
|
-
});
|
|
67241
|
-
const optIn = readOptIn(input.env);
|
|
67242
|
-
if (!optIn.asked) return off();
|
|
67243
|
-
if (!TRUTHY.has(optIn.value.toLowerCase())) {
|
|
67244
|
-
return off([
|
|
67245
|
-
`${DEV_DRIVER_ENV}=${optIn.value} is not an opt-in (accepted: 1, true); the renderer dev driver stayed off`
|
|
67246
|
-
]);
|
|
67247
|
-
}
|
|
67248
|
-
if (input.windowMode !== "headless" && input.windowMode !== "inactive") {
|
|
67249
|
-
return off([
|
|
67250
|
-
`the renderer dev driver refused to arm in a "${input.windowMode}" window; it never raises one, so use --window-mode=headless (or inactive)`
|
|
67251
|
-
]);
|
|
67252
|
-
}
|
|
67253
|
-
const outDir = input.env[DEV_DRIVER_OUT_ENV]?.trim() ?? "";
|
|
67254
|
-
if (outDir === "" || !outDir.startsWith("/")) {
|
|
67255
|
-
return off([
|
|
67256
|
-
`${DEV_DRIVER_ENV} was set but ${DEV_DRIVER_OUT_ENV} is ${outDir === "" ? "missing" : `"${outDir}"`}; an absolute frames directory is required, so the driver did not arm`
|
|
67257
|
-
]);
|
|
67258
|
-
}
|
|
67259
|
-
return { armed: true, outDir, problems: [] };
|
|
67260
|
-
}
|
|
67261
|
-
function headlessExerciserAllowed(input) {
|
|
67262
|
-
return input.arming.armed && input.windowMode === "headless";
|
|
67263
|
-
}
|
|
67264
|
-
function devDriverArgument(outDir) {
|
|
67265
|
-
return `${DEV_DRIVER_ARG}=${outDir}`;
|
|
67266
|
-
}
|
|
67267
|
-
function describeDevDriverArming(arming) {
|
|
67268
|
-
if (arming.armed) {
|
|
67269
|
-
return `[dev-driver] ARMED; frames are written to ${arming.outDir}`;
|
|
67270
|
-
}
|
|
67271
|
-
if (arming.problems.length === 0) return null;
|
|
67272
|
-
return `[dev-driver] not armed: ${arming.problems.join("; ")}`;
|
|
67273
|
-
}
|
|
67274
68201
|
class StartupRollback {
|
|
67275
68202
|
owners = [];
|
|
67276
68203
|
add(cleanup) {
|
|
@@ -67373,7 +68300,8 @@ const BROWSER_IPC_CHANNELS = [
|
|
|
67373
68300
|
* `unregisterBrowserIpc` remove it on a stop/retry like every other channel
|
|
67374
68301
|
* (removing an unregistered handler is a no-op).
|
|
67375
68302
|
*/
|
|
67376
|
-
DEV_DRIVER_ADDRESS_OVERLAY
|
|
68303
|
+
DEV_DRIVER_ADDRESS_OVERLAY,
|
|
68304
|
+
DEV_DRIVER_ADDRESS_OVERLAY_PROJECT
|
|
67377
68305
|
];
|
|
67378
68306
|
function registerBrowserIpc(options) {
|
|
67379
68307
|
function authorizeSender(event) {
|
|
@@ -67518,9 +68446,9 @@ function registerBrowserIpc(options) {
|
|
|
67518
68446
|
}
|
|
67519
68447
|
return host.historyActive(direction);
|
|
67520
68448
|
});
|
|
67521
|
-
electron.ipcMain.handle("browser-set-content-rect", (event,
|
|
68449
|
+
electron.ipcMain.handle("browser-set-content-rect", (event, rect2) => {
|
|
67522
68450
|
const host = authorize(event);
|
|
67523
|
-
return host.setContentRect(contentRectOrNull(
|
|
68451
|
+
return host.setContentRect(contentRectOrNull(rect2));
|
|
67524
68452
|
});
|
|
67525
68453
|
electron.ipcMain.handle("browser-set-visible", (event, visible) => {
|
|
67526
68454
|
const host = authorize(event);
|
|
@@ -67620,21 +68548,40 @@ function registerBrowserIpc(options) {
|
|
|
67620
68548
|
return { retried: true };
|
|
67621
68549
|
});
|
|
67622
68550
|
if (options.addressOverlayProbe) {
|
|
67623
|
-
electron.ipcMain.handle(
|
|
67624
|
-
|
|
67625
|
-
|
|
67626
|
-
|
|
67627
|
-
|
|
67628
|
-
|
|
68551
|
+
electron.ipcMain.handle(
|
|
68552
|
+
DEV_DRIVER_ADDRESS_OVERLAY,
|
|
68553
|
+
(event, action, argument) => {
|
|
68554
|
+
authorizeSender(event);
|
|
68555
|
+
if (action !== "show" && action !== "hide" && action !== "facts" && action !== "click" && action !== "measure" && action !== "key") {
|
|
68556
|
+
throw new Error(
|
|
68557
|
+
"address_overlay_invalid_action: expected 'show', 'hide', 'facts', 'click', 'measure' or 'key'."
|
|
68558
|
+
);
|
|
68559
|
+
}
|
|
68560
|
+
const probe = options.addressOverlayProbe;
|
|
68561
|
+
if (!probe) {
|
|
68562
|
+
throw new Error(
|
|
68563
|
+
"address_overlay_unavailable: the overlay probe is not running."
|
|
68564
|
+
);
|
|
68565
|
+
}
|
|
68566
|
+
const readsArgument = action === "click" || action === "measure" || action === "key";
|
|
68567
|
+
return probe(action, readsArgument ? argument : void 0);
|
|
67629
68568
|
}
|
|
67630
|
-
|
|
67631
|
-
|
|
67632
|
-
|
|
67633
|
-
|
|
67634
|
-
|
|
68569
|
+
);
|
|
68570
|
+
}
|
|
68571
|
+
if (options.addressOverlayProject) {
|
|
68572
|
+
electron.ipcMain.handle(
|
|
68573
|
+
DEV_DRIVER_ADDRESS_OVERLAY_PROJECT,
|
|
68574
|
+
(event, payload) => {
|
|
68575
|
+
authorizeSender(event);
|
|
68576
|
+
const project = options.addressOverlayProject;
|
|
68577
|
+
if (!project) {
|
|
68578
|
+
throw new Error(
|
|
68579
|
+
"address_overlay_unavailable: the overlay projection is not running."
|
|
68580
|
+
);
|
|
68581
|
+
}
|
|
68582
|
+
return project(payload);
|
|
67635
68583
|
}
|
|
67636
|
-
|
|
67637
|
-
});
|
|
68584
|
+
);
|
|
67638
68585
|
}
|
|
67639
68586
|
}
|
|
67640
68587
|
function unregisterBrowserIpc() {
|
|
@@ -67699,17 +68646,17 @@ function contentRectOrNull(value) {
|
|
|
67699
68646
|
if (value === null || value === void 0) return null;
|
|
67700
68647
|
if (typeof value !== "object")
|
|
67701
68648
|
throw new Error("Content rect must be an object.");
|
|
67702
|
-
const
|
|
68649
|
+
const rect2 = value;
|
|
67703
68650
|
for (const key of ["x", "y", "width", "height"]) {
|
|
67704
|
-
if (typeof
|
|
68651
|
+
if (typeof rect2[key] !== "number" || !Number.isFinite(rect2[key])) {
|
|
67705
68652
|
throw new Error("Content rect needs finite x, y, width and height.");
|
|
67706
68653
|
}
|
|
67707
68654
|
}
|
|
67708
68655
|
return {
|
|
67709
|
-
x:
|
|
67710
|
-
y:
|
|
67711
|
-
width:
|
|
67712
|
-
height:
|
|
68656
|
+
x: rect2.x,
|
|
68657
|
+
y: rect2.y,
|
|
68658
|
+
width: rect2.width,
|
|
68659
|
+
height: rect2.height
|
|
67713
68660
|
};
|
|
67714
68661
|
}
|
|
67715
68662
|
function paneNavigationDirection(input) {
|
|
@@ -69619,15 +70566,30 @@ function startBrowserHost(options) {
|
|
|
69619
70566
|
* replaces it) rather than capturing a controller here.
|
|
69620
70567
|
*/
|
|
69621
70568
|
...options.addressOverlay?.enabled ? {
|
|
69622
|
-
addressOverlayProbe: (action) => {
|
|
70569
|
+
addressOverlayProbe: (action, argument) => {
|
|
69623
70570
|
const probe = bindings.addressOverlayProbe;
|
|
69624
70571
|
if (!probe) {
|
|
69625
70572
|
throw new Error(
|
|
69626
70573
|
"address_overlay_unavailable: the overlay controller is not running."
|
|
69627
70574
|
);
|
|
69628
70575
|
}
|
|
69629
|
-
return probe(action);
|
|
69630
|
-
}
|
|
70576
|
+
return probe(action, argument);
|
|
70577
|
+
},
|
|
70578
|
+
/* S2's projection. Registered only with the S1 probe, because the
|
|
70579
|
+
* projection can only drive a child the probe's gate also armed. The
|
|
70580
|
+
* current attempt's handler is read through `bindings` per call, like
|
|
70581
|
+
* the probe above, so a retry cannot leave a stale controller. */
|
|
70582
|
+
...options.addressOverlay.list === true ? {
|
|
70583
|
+
addressOverlayProject: (payload) => {
|
|
70584
|
+
const project = bindings.addressOverlayProject;
|
|
70585
|
+
if (!project) {
|
|
70586
|
+
throw new Error(
|
|
70587
|
+
"address_overlay_unavailable: the overlay controller is not running."
|
|
70588
|
+
);
|
|
70589
|
+
}
|
|
70590
|
+
return project(payload);
|
|
70591
|
+
}
|
|
70592
|
+
} : {}
|
|
69631
70593
|
} : {},
|
|
69632
70594
|
log: options.log
|
|
69633
70595
|
});
|
|
@@ -70017,6 +70979,18 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
70017
70979
|
const addressOverlay = options.addressOverlay?.enabled === true ? new AddressOverlayController({
|
|
70018
70980
|
window: options.window,
|
|
70019
70981
|
documentUrl: options.addressOverlay.documentUrl,
|
|
70982
|
+
javascript: options.addressOverlay.list === true,
|
|
70983
|
+
visible: options.addressOverlay.visible === true,
|
|
70984
|
+
// The only consumer of a validated row click: the owner window's own
|
|
70985
|
+
// renderer. Guarded because a stop can race a queued mouse event.
|
|
70986
|
+
onEvent: (event) => {
|
|
70987
|
+
if (!options.window.isDestroyed()) {
|
|
70988
|
+
options.window.webContents.send(
|
|
70989
|
+
DEV_DRIVER_ADDRESS_OVERLAY_EVENT,
|
|
70990
|
+
event
|
|
70991
|
+
);
|
|
70992
|
+
}
|
|
70993
|
+
},
|
|
70020
70994
|
log: log2,
|
|
70021
70995
|
appMetrics: () => electron.app.getAppMetrics().map((metric) => ({
|
|
70022
70996
|
pid: metric.pid,
|
|
@@ -70325,13 +71299,13 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
70325
71299
|
);
|
|
70326
71300
|
rollback.add(() => stateWriter?.clear());
|
|
70327
71301
|
stateWriter.start(server.port, sessionKey);
|
|
70328
|
-
const probeAddressOverlay = async (action) => {
|
|
71302
|
+
const probeAddressOverlay = async (action, argument) => {
|
|
70329
71303
|
if (!addressOverlay) {
|
|
70330
71304
|
throw new Error(
|
|
70331
71305
|
"address_overlay_unavailable: this host owns no controller."
|
|
70332
71306
|
);
|
|
70333
71307
|
}
|
|
70334
|
-
const facts2 = await addressOverlay.probe(action);
|
|
71308
|
+
const facts2 = await addressOverlay.probe(action, argument);
|
|
70335
71309
|
const record = registry.activeTab;
|
|
70336
71310
|
const page = record ? {
|
|
70337
71311
|
tabId: record.tabId,
|
|
@@ -70341,8 +71315,19 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
70341
71315
|
} : null;
|
|
70342
71316
|
return { ...facts2, page };
|
|
70343
71317
|
};
|
|
71318
|
+
const projectAddressOverlay = (payload) => {
|
|
71319
|
+
if (!addressOverlay) {
|
|
71320
|
+
throw new Error(
|
|
71321
|
+
"address_overlay_unavailable: this host owns no controller."
|
|
71322
|
+
);
|
|
71323
|
+
}
|
|
71324
|
+
return addressOverlay.project(payload);
|
|
71325
|
+
};
|
|
70344
71326
|
if (addressOverlay) {
|
|
70345
71327
|
bindings.addressOverlayProbe = probeAddressOverlay;
|
|
71328
|
+
if (options.addressOverlay?.list === true) {
|
|
71329
|
+
bindings.addressOverlayProject = projectAddressOverlay;
|
|
71330
|
+
}
|
|
70346
71331
|
}
|
|
70347
71332
|
Object.assign(bindings, {
|
|
70348
71333
|
window: () => options.window,
|
|
@@ -81704,11 +82689,12 @@ if (devDriverLine) console.log(devDriverLine);
|
|
|
81704
82689
|
const addressOverlayGate = resolveAddressOverlayGate({
|
|
81705
82690
|
env: launchEnv,
|
|
81706
82691
|
devDriverArmed: devDriverArming.armed,
|
|
81707
|
-
windowMode: windowLaunch.mode
|
|
82692
|
+
windowMode: windowLaunch.mode,
|
|
82693
|
+
packaged: electron.app.isPackaged
|
|
81708
82694
|
});
|
|
81709
82695
|
if (addressOverlayGate.asked) {
|
|
81710
82696
|
console.log(
|
|
81711
|
-
addressOverlayGate.enabled ? "[address-overlay] ARMED (
|
|
82697
|
+
addressOverlayGate.enabled ? addressOverlayGate.visible ? "[address-overlay] ARMED (S3 VISIBLE probe, inactive window, 120 s cap, no product path)" : `[address-overlay] ARMED (S${addressOverlayGate.list ? "2 probe: mirror list" : "1 probe: native child"}, no product path)` : `[address-overlay] not armed: ${addressOverlayGate.reason}`
|
|
81712
82698
|
);
|
|
81713
82699
|
}
|
|
81714
82700
|
const devDriverWebPreferences = devDriverArming.armed && devDriverArming.outDir ? { additionalArguments: [devDriverArgument(devDriverArming.outDir)] } : {};
|
|
@@ -81982,7 +82968,10 @@ electron.app.whenReady().then(async () => {
|
|
|
81982
82968
|
const launcher = resolveLauncherWatchPlan({
|
|
81983
82969
|
mode: windowLaunch.mode,
|
|
81984
82970
|
launcherPid: process.ppid,
|
|
81985
|
-
env: launchEnv
|
|
82971
|
+
env: launchEnv,
|
|
82972
|
+
// S3 only: the one visible run nobody is watching still must not
|
|
82973
|
+
// outlive its launcher. False for every product launch.
|
|
82974
|
+
boundedVisibleProbe: addressOverlayGate.visible
|
|
81986
82975
|
});
|
|
81987
82976
|
logger.info(`[window-mode] ${launcher.reason}`, LogFileType.BACKEND);
|
|
81988
82977
|
if (windowLaunch.mode !== "normal") {
|
|
@@ -81997,12 +82986,23 @@ electron.app.whenReady().then(async () => {
|
|
|
81997
82986
|
onLauncherGone: ({ message, detail }) => endHeadlessRun(message, detail)
|
|
81998
82987
|
});
|
|
81999
82988
|
}
|
|
82000
|
-
if (
|
|
82989
|
+
if (addressOverlayGate.visible) {
|
|
82990
|
+
const cap = setTimeout(() => {
|
|
82991
|
+
endHeadlessRun(
|
|
82992
|
+
`the visible address-overlay probe reached its ${ADDRESS_OVERLAY_VISIBLE_MAX_MS / 1e3} s cap`
|
|
82993
|
+
);
|
|
82994
|
+
}, ADDRESS_OVERLAY_VISIBLE_MAX_MS);
|
|
82995
|
+
cap.unref();
|
|
82996
|
+
console.log(
|
|
82997
|
+
`[address-overlay] visible probe cap: ${ADDRESS_OVERLAY_VISIBLE_MAX_MS / 1e3} s from launch`
|
|
82998
|
+
);
|
|
82999
|
+
}
|
|
83000
|
+
if (windowLaunch.mode === "headless" || addressOverlayGate.visible) {
|
|
82001
83001
|
for (const signal of ["SIGTERM", "SIGINT"]) {
|
|
82002
83002
|
process.on(signal, () => endHeadlessRun(`received ${signal}`));
|
|
82003
83003
|
}
|
|
82004
83004
|
}
|
|
82005
|
-
if (windowLaunch.mode !== "headless") {
|
|
83005
|
+
if (windowLaunch.mode !== "headless" && !addressOverlayGate.visible) {
|
|
82006
83006
|
const onSigtermDuringQuit = () => {
|
|
82007
83007
|
if (!quitState.isQuitting()) {
|
|
82008
83008
|
process.removeListener("SIGTERM", onSigtermDuringQuit);
|
|
@@ -82114,7 +83114,7 @@ electron.app.whenReady().then(async () => {
|
|
|
82114
83114
|
});
|
|
82115
83115
|
const rendererUrl = rendererDocumentUrl();
|
|
82116
83116
|
const consoleCaptureUrl = consoleCaptureUrlFor(rendererUrl);
|
|
82117
|
-
const addressOverlayDocumentUrl = addressOverlayDocumentUrlFor(rendererUrl);
|
|
83117
|
+
const addressOverlayDocumentUrl = addressOverlayGate.list ? addressListDocumentUrlFor(rendererUrl) : addressOverlayDocumentUrlFor(rendererUrl);
|
|
82118
83118
|
backendService.observeDesktopFeed(
|
|
82119
83119
|
(frame) => {
|
|
82120
83120
|
if (frame.type === "notification") {
|
|
@@ -82928,6 +83928,8 @@ electron.app.whenReady().then(async () => {
|
|
|
82928
83928
|
...addressOverlayGate.enabled ? {
|
|
82929
83929
|
addressOverlay: {
|
|
82930
83930
|
enabled: true,
|
|
83931
|
+
list: addressOverlayGate.list,
|
|
83932
|
+
visible: addressOverlayGate.visible,
|
|
82931
83933
|
documentUrl: addressOverlayDocumentUrl
|
|
82932
83934
|
}
|
|
82933
83935
|
} : {},
|