local-operator-ui 0.39.4 → 0.39.6
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 +844 -105
- package/out/preload/index.js +12 -0
- package/out/renderer/assets/{_basePickBy-DpOw3Tny.js → _basePickBy-CEM-62na.js} +1 -1
- package/out/renderer/assets/{_baseUniq-CloF1Z39.js → _baseUniq-DKUG2lEn.js} +1 -1
- package/out/renderer/assets/{addressOverlayList-8wdZRD_t.css → addressOverlayList-B7X6o95l.css} +1 -1
- package/out/renderer/assets/{addressOverlayList-BEh9WU4R.js → addressOverlayList-SGt8bawf.js} +1 -1
- package/out/renderer/assets/{agent-details-page-B-wOn-JJ.js → agent-details-page-uwmizvcA.js} +1 -1
- package/out/renderer/assets/{agent-hub-page-kOIRpx4R.js → agent-hub-page-DY0hrFjh.js} +1 -1
- package/out/renderer/assets/{agents-page-A6mqclDx.js → agents-page-B82GhyEm.js} +3 -3
- package/out/renderer/assets/{arc-C-USYSJX.js → arc-CwS59wEx.js} +1 -1
- package/out/renderer/assets/{architectureDiagram-IEHRJDOE-BStVetpz.js → architectureDiagram-IEHRJDOE-CrSOPHPj.js} +1 -1
- package/out/renderer/assets/{blockDiagram-JOT3LUYC-DFraQTdY.js → blockDiagram-JOT3LUYC-DOKW2aS1.js} +1 -1
- package/out/renderer/assets/{book-open-CbkGl_K7.js → book-open-BrVlmR50.js} +1 -1
- package/out/renderer/assets/browser-page-kxT2NYqz.js +1 -0
- package/out/renderer/assets/{browser-webauthn-prompt-CzS7qaIE.js → browser-webauthn-prompt-D4Pmblc_.js} +1 -1
- package/out/renderer/assets/{building-2-cVqkqSs_.js → building-2-BbJxBV3t.js} +1 -1
- package/out/renderer/assets/{c4Diagram-VJAJSXHY-Bpo5tV9E.js → c4Diagram-VJAJSXHY-BNZOSwVL.js} +1 -1
- package/out/renderer/assets/channel-D2-Cirxc.js +1 -0
- package/out/renderer/assets/{chunk-4BMEZGHF-BvVdPPZL.js → chunk-4BMEZGHF-DatYJ8Pc.js} +1 -1
- package/out/renderer/assets/{chunk-A2AXSNBT-DtDHNfFN.js → chunk-A2AXSNBT-kofNI-nh.js} +1 -1
- package/out/renderer/assets/{chunk-AEK57VVT-Cy4jpw-R.js → chunk-AEK57VVT-RG-vyDkt.js} +1 -1
- package/out/renderer/assets/{chunk-D6G4REZN-DvaHPHsB.js → chunk-D6G4REZN-DbgxdXuD.js} +1 -1
- package/out/renderer/assets/{chunk-RZ5BOZE2-CEKwLFh6.js → chunk-RZ5BOZE2-Pwbky5G7.js} +1 -1
- package/out/renderer/assets/{chunk-XZIHB7SX-CSpNkV4-.js → chunk-XZIHB7SX-nMQwH5Ev.js} +1 -1
- package/out/renderer/assets/classDiagram-GIVACNV2-D1u4IPED.js +1 -0
- package/out/renderer/assets/classDiagram-v2-COTLJTTW-D1u4IPED.js +1 -0
- package/out/renderer/assets/clone-D45gbF22.js +1 -0
- package/out/renderer/assets/{console-mirror-3ddzbqxj.js → console-mirror-B7HDmLVb.js} +1 -1
- package/out/renderer/assets/{consoleCapture-CUH-HGgu.js → consoleCapture-wuvuMPlf.js} +1 -1
- package/out/renderer/assets/{conversation-input-sync-C16E6bmc.js → conversation-input-sync-DeQTtOSG.js} +172 -172
- package/out/renderer/assets/{dagre-OKDRZEBW-CZM6WQD8.js → dagre-OKDRZEBW-BXF3VqDs.js} +1 -1
- package/out/renderer/assets/{diagram-SSKATNLV-DhfdsL7X.js → diagram-SSKATNLV-C6ZzdCUp.js} +1 -1
- package/out/renderer/assets/{diagram-VNBRO52H-6SKM5YIe.js → diagram-VNBRO52H-ND-gVRs3.js} +1 -1
- package/out/renderer/assets/{erDiagram-Q7BY3M3F-Dr-mAd-w.js → erDiagram-Q7BY3M3F-DJ8vCpMT.js} +1 -1
- package/out/renderer/assets/{error-boundary-BQkbSeb-.js → error-boundary-D81PAlVn.js} +3 -3
- package/out/renderer/assets/{flowDiagram-4HSFHLVR-XzjnYaiy.js → flowDiagram-4HSFHLVR-C0lG2NYg.js} +1 -1
- package/out/renderer/assets/{ganttDiagram-APWFNJXF-BiDYLq2r.js → ganttDiagram-APWFNJXF-BBxt5Pgj.js} +1 -1
- package/out/renderer/assets/{gitGraphDiagram-7IBYFJ6S-CHG8kjsH.js → gitGraphDiagram-7IBYFJ6S-B5eei6E_.js} +1 -1
- package/out/renderer/assets/{graph-CCrDrJrv.js → graph-lWFNtwh7.js} +1 -1
- package/out/renderer/assets/{hash-m3f0Pwzh.js → hash-3k6_lTgk.js} +1 -1
- package/out/renderer/assets/index-BtI7uak5.js +835 -0
- package/out/renderer/assets/index-DsY6xpO9.js +57 -0
- package/out/renderer/assets/{index-D1rKdut2.js → index-FqHXqlQT.js} +1 -1
- package/out/renderer/assets/index-ZC-NNW64.css +1 -0
- package/out/renderer/assets/{index-DQdKGxDM.js → index-tyh1i-0R.js} +1 -1
- package/out/renderer/assets/{infoDiagram-PH2N3AL5-Boc-74q5.js → infoDiagram-PH2N3AL5-DfdIGj2q.js} +1 -1
- package/out/renderer/assets/{installer-DIGUKrBB.js → installer-OLhNHLbA.js} +1 -1
- package/out/renderer/assets/{journeyDiagram-U35MCT3I-D7_ElfaN.js → journeyDiagram-U35MCT3I-DY36aDPm.js} +1 -1
- package/out/renderer/assets/{kanban-definition-NDS4AKOZ-C6QsJ5yF.js → kanban-definition-NDS4AKOZ-DkmkP4pt.js} +1 -1
- package/out/renderer/assets/{layout-aAj5fMFf.js → layout-Wh_eVbud.js} +1 -1
- package/out/renderer/assets/{legacy-agents-page-USk5n9oW.js → legacy-agents-page-m5-4VKbu.js} +1 -1
- package/out/renderer/assets/{library-page-D8DpGQTs.js → library-page-vUP7gWsI.js} +3 -3
- package/out/renderer/assets/{mermaid.core-3ySvSsav.js → mermaid.core-CIUeSke9.js} +5 -5
- package/out/renderer/assets/{mesh-page-DzMTk3NO.js → mesh-page-CoUCZ19i.js} +1 -1
- package/out/renderer/assets/{mindmap-definition-ALO5MXBD-B0nPGBao.js → mindmap-definition-ALO5MXBD-E7Cl2drf.js} +1 -1
- package/out/renderer/assets/{mini-DFKXChgT.js → mini-D6HdkQvd.js} +1 -1
- package/out/renderer/assets/{notebook-pen-D0aUl8AG.js → notebook-pen-CiUgTpp-.js} +1 -1
- package/out/renderer/assets/{org-access-HADVafzg.js → org-access-DMUk8SEr.js} +1 -1
- package/out/renderer/assets/{org-surface-gate-DgSDgcYC.js → org-surface-gate-DdKUA8S8.js} +1 -1
- package/out/renderer/assets/{page-header-gQzwRfwk.js → page-header-DyRHEB-L.js} +1 -1
- package/out/renderer/assets/{pieDiagram-IB7DONF6-BiqgPuyx.js → pieDiagram-IB7DONF6-C3KFzuOU.js} +1 -1
- package/out/renderer/assets/{projects-page-ZOe4bm_U.js → projects-page-BdU99VZf.js} +1 -1
- package/out/renderer/assets/{publication-validation-hQvjDgK-.js → publication-validation-Cv6lnH83.js} +1 -1
- package/out/renderer/assets/{quadrantDiagram-7GDLP6J5-DIWtZVho.js → quadrantDiagram-7GDLP6J5-DommBk0z.js} +1 -1
- package/out/renderer/assets/{radar-MK3ICKWK-2Q646pxQ.js → radar-MK3ICKWK-D5VUcmjY.js} +1 -1
- package/out/renderer/assets/{radient-auth-buttons-CfbkjaWR.js → radient-auth-buttons-BXc5xVU7.js} +1 -1
- package/out/renderer/assets/{requirementDiagram-KVF5MWMF-BgM3WO01.js → requirementDiagram-KVF5MWMF-RSR1-rSs.js} +1 -1
- package/out/renderer/assets/{sankeyDiagram-QLVOVGJD-B0mmrM-5.js → sankeyDiagram-QLVOVGJD-Caojpkpm.js} +1 -1
- package/out/renderer/assets/{schedules-page-CSLJTbio.js → schedules-page-BWM0NUo9.js} +1 -1
- package/out/renderer/assets/{sequenceDiagram-X6HHIX6F-D-_IaAU6.js → sequenceDiagram-X6HHIX6F-CrZCUpMQ.js} +1 -1
- package/out/renderer/assets/{settings-page-DMJjQldW.js → settings-page-sXBnyGof.js} +1 -1
- package/out/renderer/assets/{smartart-Bko--HTI.js → smartart-BJStpUh7.js} +1 -1
- package/out/renderer/assets/{stateDiagram-DGXRK772-CuY0nRt2.js → stateDiagram-DGXRK772-PFp2Dzsd.js} +1 -1
- package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-DhzpDrem.js +1 -0
- package/out/renderer/assets/{team-bridge-page-BSiDGZ0J.js → team-bridge-page-pZkYpCnA.js} +1 -1
- package/out/renderer/assets/{timeline-definition-BDJGKUSR-CRyMxdHE.js → timeline-definition-BDJGKUSR-BI2T4N_q.js} +1 -1
- package/out/renderer/assets/{ui-preferences-store-Bop4_ZlF.js → ui-preferences-store-BZs48Tq1.js} +1 -1
- package/out/renderer/assets/{use-download-agent-mutation-C8Fg7G5t.js → use-download-agent-mutation-B3ghS441.js} +1 -1
- package/out/renderer/assets/{use-session-snapshot-Bg0gSZ12.js → use-session-snapshot-BbulmIXL.js} +1 -1
- package/out/renderer/assets/{xychartDiagram-VJFVF3MP-CEgHjMik.js → xychartDiagram-VJFVF3MP-CuNt7ik-.js} +1 -1
- package/out/renderer/browser-address-overlay-list.html +2 -2
- 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 +2 -2
- package/out/renderer/assets/browser-page-BZouue9V.js +0 -1
- package/out/renderer/assets/channel-Dw6-NFJz.js +0 -1
- package/out/renderer/assets/classDiagram-GIVACNV2-CadtvAj7.js +0 -1
- package/out/renderer/assets/classDiagram-v2-COTLJTTW-CadtvAj7.js +0 -1
- package/out/renderer/assets/clone-Bfys-Y9K.js +0 -1
- package/out/renderer/assets/index-DGTlmx84.js +0 -57
- package/out/renderer/assets/index-DULvJq2X.js +0 -830
- package/out/renderer/assets/index-Dyn0TMCv.css +0 -1
- package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-rk6LIoPS.js +0 -1
package/out/main/index.js
CHANGED
|
@@ -28839,6 +28839,7 @@ const ADDRESS_LIST_ROWS_MAX = 5;
|
|
|
28839
28839
|
const ADDRESS_LIST_MAX_HEIGHT_DIP = 212;
|
|
28840
28840
|
const ADDRESS_LIST_NOTICE_HEIGHT_DIP = 104;
|
|
28841
28841
|
const ADDRESS_LIST_ANCHOR_GAP_MAX = 24;
|
|
28842
|
+
const ADDRESS_LIST_MIN_WIDTH_DIP = 240;
|
|
28842
28843
|
const ADDRESS_LIST_MAX_PAYLOAD_BYTES = 16 * 1024;
|
|
28843
28844
|
const ADDRESS_LIST_MAX_TEXT = 512;
|
|
28844
28845
|
const ADDRESS_LIST_MAX_TITLE = 256;
|
|
@@ -28847,13 +28848,12 @@ const ADDRESS_LIST_THEME_FALLBACK = "#1b1f24";
|
|
|
28847
28848
|
const DIP_INT32_MAX$1 = 2 ** 31 - 1;
|
|
28848
28849
|
const NOTICE_KINDS = [
|
|
28849
28850
|
"error",
|
|
28850
|
-
"hint",
|
|
28851
28851
|
"empty",
|
|
28852
28852
|
"no_match"
|
|
28853
28853
|
];
|
|
28854
28854
|
const HOSTILE_STRING = /[\p{Cc}\u2028\u2029\u202A-\u202E\u2066-\u2069]/gu;
|
|
28855
28855
|
const COLOR = /^(#[0-9a-f]{6}|rgb\(\d{1,3}, ?\d{1,3}, ?\d{1,3}\))$/i;
|
|
28856
|
-
const
|
|
28856
|
+
const PROJECTION_KEYS_V1 = /* @__PURE__ */ new Set([
|
|
28857
28857
|
"v",
|
|
28858
28858
|
"seq",
|
|
28859
28859
|
"tabId",
|
|
@@ -28867,6 +28867,20 @@ const PROJECTION_KEYS = /* @__PURE__ */ new Set([
|
|
|
28867
28867
|
"dir",
|
|
28868
28868
|
"theme"
|
|
28869
28869
|
]);
|
|
28870
|
+
const PROJECTION_KEYS_V2 = /* @__PURE__ */ new Set([
|
|
28871
|
+
"v",
|
|
28872
|
+
"seq",
|
|
28873
|
+
"tabId",
|
|
28874
|
+
"visible",
|
|
28875
|
+
"pageRect",
|
|
28876
|
+
"anchor",
|
|
28877
|
+
"active",
|
|
28878
|
+
"view",
|
|
28879
|
+
"label",
|
|
28880
|
+
"dir",
|
|
28881
|
+
"theme"
|
|
28882
|
+
]);
|
|
28883
|
+
const ANCHOR_KEYS = ["x", "width"];
|
|
28870
28884
|
const RECT_KEYS = ["x", "y", "width", "height"];
|
|
28871
28885
|
const THEME_KEYS = [
|
|
28872
28886
|
"elevated",
|
|
@@ -28947,10 +28961,10 @@ function sanitizeProjection(raw) {
|
|
|
28947
28961
|
return { ok: false, reason: "payload_too_large" };
|
|
28948
28962
|
}
|
|
28949
28963
|
if (!isRecord$1(raw)) return { ok: false, reason: "not_an_object" };
|
|
28950
|
-
if (
|
|
28951
|
-
|
|
28952
|
-
|
|
28953
|
-
if (raw
|
|
28964
|
+
if (raw.v !== 1 && raw.v !== 2) return { ok: false, reason: "bad_version" };
|
|
28965
|
+
const version = raw.v;
|
|
28966
|
+
const keys = version === 2 ? PROJECTION_KEYS_V2 : PROJECTION_KEYS_V1;
|
|
28967
|
+
if (!hasOnlyKeys(raw, keys)) return { ok: false, reason: "unknown_key" };
|
|
28954
28968
|
if (!Number.isInteger(raw.seq) || raw.seq < 1) {
|
|
28955
28969
|
return { ok: false, reason: "bad_seq" };
|
|
28956
28970
|
}
|
|
@@ -28959,15 +28973,29 @@ function sanitizeProjection(raw) {
|
|
|
28959
28973
|
return { ok: false, reason: "bad_visible" };
|
|
28960
28974
|
}
|
|
28961
28975
|
if (!raw.visible) {
|
|
28976
|
+
const empty = { x: 0, y: 0, width: 0, height: 0 };
|
|
28962
28977
|
return {
|
|
28963
28978
|
ok: true,
|
|
28964
|
-
projection: {
|
|
28979
|
+
projection: version === 2 ? {
|
|
28980
|
+
v: 2,
|
|
28981
|
+
seq: raw.seq,
|
|
28982
|
+
tabId: raw.tabId,
|
|
28983
|
+
visible: false,
|
|
28984
|
+
pageRect: empty,
|
|
28985
|
+
anchor: { x: 0, width: 0 },
|
|
28986
|
+
active: -1,
|
|
28987
|
+
view: { kind: "notice", notice: "empty", text: "" },
|
|
28988
|
+
label: "",
|
|
28989
|
+
dir: "ltr",
|
|
28990
|
+
theme: null,
|
|
28991
|
+
themeFact: "absent"
|
|
28992
|
+
} : {
|
|
28965
28993
|
v: 1,
|
|
28966
28994
|
seq: raw.seq,
|
|
28967
28995
|
tabId: raw.tabId,
|
|
28968
28996
|
visible: false,
|
|
28969
|
-
pageRect:
|
|
28970
|
-
field:
|
|
28997
|
+
pageRect: empty,
|
|
28998
|
+
field: empty,
|
|
28971
28999
|
listTop: 0,
|
|
28972
29000
|
active: -1,
|
|
28973
29001
|
view: { kind: "notice", notice: "empty", text: "" },
|
|
@@ -28979,14 +29007,30 @@ function sanitizeProjection(raw) {
|
|
|
28979
29007
|
};
|
|
28980
29008
|
}
|
|
28981
29009
|
const pageRect = rect(raw.pageRect);
|
|
28982
|
-
|
|
28983
|
-
|
|
28984
|
-
|
|
28985
|
-
|
|
28986
|
-
|
|
28987
|
-
|
|
28988
|
-
|
|
28989
|
-
|
|
29010
|
+
if (pageRect === null) return { ok: false, reason: "bad_rect" };
|
|
29011
|
+
let field = null;
|
|
29012
|
+
let listTop = 0;
|
|
29013
|
+
let anchor = null;
|
|
29014
|
+
if (version === 2) {
|
|
29015
|
+
if (!isRecord$1(raw.anchor) || !hasOnlyKeys(raw.anchor, ANCHOR_KEYS)) {
|
|
29016
|
+
return { ok: false, reason: "bad_anchor" };
|
|
29017
|
+
}
|
|
29018
|
+
const x = finite(raw.anchor.x);
|
|
29019
|
+
const width = finite(raw.anchor.width);
|
|
29020
|
+
if (x === null || width === null) {
|
|
29021
|
+
return { ok: false, reason: "bad_anchor" };
|
|
29022
|
+
}
|
|
29023
|
+
if (width <= 0) return { ok: false, reason: "bad_anchor" };
|
|
29024
|
+
anchor = { x, width };
|
|
29025
|
+
} else {
|
|
29026
|
+
field = rect(raw.field);
|
|
29027
|
+
if (field === null) return { ok: false, reason: "bad_rect" };
|
|
29028
|
+
const top = finite(raw.listTop);
|
|
29029
|
+
if (top === null) return { ok: false, reason: "bad_list_top" };
|
|
29030
|
+
listTop = top;
|
|
29031
|
+
if (field.width <= 0 || field.height <= 0) {
|
|
29032
|
+
return { ok: false, reason: "bad_field" };
|
|
29033
|
+
}
|
|
28990
29034
|
}
|
|
28991
29035
|
if (!Number.isInteger(raw.active)) return { ok: false, reason: "bad_active" };
|
|
28992
29036
|
const active = raw.active;
|
|
@@ -29026,6 +29070,27 @@ function sanitizeProjection(raw) {
|
|
|
29026
29070
|
return { ok: false, reason: "bad_dir" };
|
|
29027
29071
|
}
|
|
29028
29072
|
const { theme, fact } = sanitizeTheme(raw.theme);
|
|
29073
|
+
if (version === 2) {
|
|
29074
|
+
if (anchor === null) return { ok: false, reason: "bad_anchor" };
|
|
29075
|
+
return {
|
|
29076
|
+
ok: true,
|
|
29077
|
+
projection: {
|
|
29078
|
+
v: 2,
|
|
29079
|
+
seq: raw.seq,
|
|
29080
|
+
tabId: raw.tabId,
|
|
29081
|
+
visible: true,
|
|
29082
|
+
pageRect,
|
|
29083
|
+
anchor,
|
|
29084
|
+
active,
|
|
29085
|
+
view,
|
|
29086
|
+
label,
|
|
29087
|
+
dir: raw.dir,
|
|
29088
|
+
theme,
|
|
29089
|
+
themeFact: fact
|
|
29090
|
+
}
|
|
29091
|
+
};
|
|
29092
|
+
}
|
|
29093
|
+
if (field === null) return { ok: false, reason: "bad_rect" };
|
|
29029
29094
|
return {
|
|
29030
29095
|
ok: true,
|
|
29031
29096
|
projection: {
|
|
@@ -29079,6 +29144,26 @@ function addressListBoundsFor(field, listTop, view, owner) {
|
|
|
29079
29144
|
if (bottom - top !== height) return null;
|
|
29080
29145
|
return { x: left, y: top, width: right - left, height };
|
|
29081
29146
|
}
|
|
29147
|
+
function addressListBoundsV2For(anchor, pageRect, view, owner) {
|
|
29148
|
+
const ax = int32$1(anchor.x);
|
|
29149
|
+
const aw = int32$1(anchor.width);
|
|
29150
|
+
const px = int32$1(pageRect.x);
|
|
29151
|
+
const pw = int32$1(pageRect.width);
|
|
29152
|
+
const py = int32$1(pageRect.y);
|
|
29153
|
+
const ownerWidth = int32$1(owner.width);
|
|
29154
|
+
const ownerHeight = int32$1(owner.height);
|
|
29155
|
+
if (ax === null || aw === null || px === null || pw === null || py === null || ownerWidth === null || ownerHeight === null) {
|
|
29156
|
+
return null;
|
|
29157
|
+
}
|
|
29158
|
+
if (aw <= 0 || pw <= 0 || ownerWidth <= 0 || ownerHeight <= 0) return null;
|
|
29159
|
+
const left = Math.max(0, Math.max(ax, px));
|
|
29160
|
+
const right = Math.min(ownerWidth, Math.min(ax + aw, px + pw));
|
|
29161
|
+
if (right - left < ADDRESS_LIST_MIN_WIDTH_DIP) return null;
|
|
29162
|
+
const height = addressListHeightFor(view);
|
|
29163
|
+
if (height > ADDRESS_LIST_MAX_HEIGHT_DIP) return null;
|
|
29164
|
+
if (py < 0 || py + height > ownerHeight) return null;
|
|
29165
|
+
return { x: left, y: py, width: right - left, height };
|
|
29166
|
+
}
|
|
29082
29167
|
function addressListRowIndexAt(view, offsetY) {
|
|
29083
29168
|
if (view.kind !== "rows") return null;
|
|
29084
29169
|
if (!Number.isFinite(offsetY)) return null;
|
|
@@ -29391,6 +29476,10 @@ function layoutKeyOf(snapshot2) {
|
|
|
29391
29476
|
const rect2 = snapshot2.contentRect;
|
|
29392
29477
|
return `${snapshot2.activeTabId}:${snapshot2.presented ? 1 : 0}:${rect2 ? `${rect2.x},${rect2.y},${rect2.width},${rect2.height}` : "null"}`;
|
|
29393
29478
|
}
|
|
29479
|
+
function layoutContentKeyOf(snapshot2) {
|
|
29480
|
+
const rect2 = snapshot2.contentRect;
|
|
29481
|
+
return `${snapshot2.activeTabId}:${rect2 ? `${rect2.x},${rect2.y},${rect2.width},${rect2.height}` : "null"}`;
|
|
29482
|
+
}
|
|
29394
29483
|
function sameRect(a, b) {
|
|
29395
29484
|
if (b === null) return false;
|
|
29396
29485
|
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
|
@@ -29437,6 +29526,7 @@ class AddressOverlayController {
|
|
|
29437
29526
|
createView;
|
|
29438
29527
|
javascript;
|
|
29439
29528
|
onEvent;
|
|
29529
|
+
onHealthChange;
|
|
29440
29530
|
readinessTimeoutMs;
|
|
29441
29531
|
log;
|
|
29442
29532
|
now;
|
|
@@ -29452,6 +29542,9 @@ class AddressOverlayController {
|
|
|
29452
29542
|
lastShow;
|
|
29453
29543
|
layout;
|
|
29454
29544
|
layoutKey;
|
|
29545
|
+
/** The layout's content identity (tab + rect), the fact a product dismissal
|
|
29546
|
+
* is allowed to rest on; see `layoutContentKeyOf`. */
|
|
29547
|
+
layoutContentKey;
|
|
29455
29548
|
boundTabId;
|
|
29456
29549
|
domReady;
|
|
29457
29550
|
finished;
|
|
@@ -29492,14 +29585,25 @@ class AddressOverlayController {
|
|
|
29492
29585
|
/** The launch gate's `visible` fact, copied in so `facts()` can report it
|
|
29493
29586
|
* without re-deriving the gate (which it must never do: one pure decision). */
|
|
29494
29587
|
visibleMode;
|
|
29588
|
+
product;
|
|
29589
|
+
warmScheduled;
|
|
29495
29590
|
lastRejected;
|
|
29496
29591
|
projectQueue;
|
|
29592
|
+
/** The native page is hidden for a reason that says nothing about the popout
|
|
29593
|
+
* (the page menu suppresses it while its panel is open). The row stays
|
|
29594
|
+
* raised, so the child's paint stops and its "shown" state does not. */
|
|
29595
|
+
presentationSuspended;
|
|
29596
|
+
/** A projection that arrived while the page was suppressed. Applied on
|
|
29597
|
+
* resume rather than refused: a refusal would make the mirror re-project
|
|
29598
|
+
* every frame until the menu closed. */
|
|
29599
|
+
deferredProjection;
|
|
29497
29600
|
constructor(deps) {
|
|
29498
29601
|
this.window = deps.window;
|
|
29499
29602
|
this.documentUrl = deps.documentUrl;
|
|
29500
29603
|
this.createView = deps.createView ?? (() => createHardenedView({ javascript: deps.javascript === true }));
|
|
29501
29604
|
this.javascript = deps.javascript === true;
|
|
29502
29605
|
this.onEvent = deps.onEvent ?? null;
|
|
29606
|
+
this.onHealthChange = deps.onHealthChange ?? null;
|
|
29503
29607
|
this.readinessTimeoutMs = deps.readinessTimeoutMs ?? ADDRESS_OVERLAY_READY_TIMEOUT_MS;
|
|
29504
29608
|
this.log = deps.log ?? (() => {
|
|
29505
29609
|
});
|
|
@@ -29521,6 +29625,7 @@ class AddressOverlayController {
|
|
|
29521
29625
|
revision: 0
|
|
29522
29626
|
};
|
|
29523
29627
|
this.layoutKey = "none";
|
|
29628
|
+
this.layoutContentKey = "none";
|
|
29524
29629
|
this.boundTabId = null;
|
|
29525
29630
|
this.domReady = false;
|
|
29526
29631
|
this.finished = false;
|
|
@@ -29552,8 +29657,12 @@ class AddressOverlayController {
|
|
|
29552
29657
|
this.childFocusEvents = 0;
|
|
29553
29658
|
this.childBlurEvents = 0;
|
|
29554
29659
|
this.visibleMode = deps.visible === true;
|
|
29660
|
+
this.product = deps.product === true;
|
|
29661
|
+
this.warmScheduled = false;
|
|
29555
29662
|
this.lastRejected = null;
|
|
29556
29663
|
this.projectQueue = Promise.resolve();
|
|
29664
|
+
this.presentationSuspended = false;
|
|
29665
|
+
this.deferredProjection = null;
|
|
29557
29666
|
this.attachOwnerListeners();
|
|
29558
29667
|
}
|
|
29559
29668
|
// ---- observer hooks ------------------------------------------------------
|
|
@@ -29561,25 +29670,41 @@ class AddressOverlayController {
|
|
|
29561
29670
|
* The registry's post-layout hook. Called after every page layout pass,
|
|
29562
29671
|
* including null and suppressed ones.
|
|
29563
29672
|
*
|
|
29564
|
-
* A changed key (tab, presentation or rectangle)
|
|
29565
|
-
*
|
|
29566
|
-
*
|
|
29567
|
-
*
|
|
29568
|
-
*
|
|
29569
|
-
* and
|
|
29570
|
-
*
|
|
29673
|
+
* A changed key (tab, presentation or rectangle) is handled by ONE of two
|
|
29674
|
+
* rules, and the split is load-bearing (agent review round 1, MAJOR-1):
|
|
29675
|
+
* a CONTENT change (tab or rectangle) hides and invalidates, while a
|
|
29676
|
+
* PRESENTATION-only change is a suppression that belongs to someone else —
|
|
29677
|
+
* the page menu, which paints into the content rect — so it only stops the
|
|
29678
|
+
* child's paint and keeps the shown state. Collapsing the two made opening
|
|
29679
|
+
* the menu dismiss the popout it was opened from. An unchanged key is the
|
|
29680
|
+
* background-page-creation case: the layout pass may have added a page above
|
|
29681
|
+
* the child, so the child is re-added last and given the same rectangle. It
|
|
29682
|
+
* never re-opens by itself; showing again is always an explicit probe call.
|
|
29571
29683
|
*/
|
|
29572
29684
|
onLayout(snapshot2) {
|
|
29573
29685
|
if (this.disposed) return;
|
|
29574
29686
|
const next = copyLayout(snapshot2);
|
|
29575
29687
|
const nextKey = layoutKeyOf(next);
|
|
29576
29688
|
const previousKey = this.layoutKey;
|
|
29689
|
+
const nextContentKey = layoutContentKeyOf(next);
|
|
29690
|
+
const previousContentKey = this.layoutContentKey;
|
|
29577
29691
|
this.layout = next;
|
|
29578
29692
|
this.layoutKey = nextKey;
|
|
29693
|
+
this.layoutContentKey = nextContentKey;
|
|
29579
29694
|
if (previousKey !== nextKey) {
|
|
29695
|
+
const contentChanged = previousContentKey !== nextContentKey;
|
|
29696
|
+
if (!contentChanged) {
|
|
29697
|
+
if (next.presented) this.resumePresentation();
|
|
29698
|
+
else this.suspendPresentation();
|
|
29699
|
+
return;
|
|
29700
|
+
}
|
|
29580
29701
|
this.hide("layout");
|
|
29702
|
+
if (this.product && previousKey !== "none") this.emitDismiss("layout");
|
|
29581
29703
|
return;
|
|
29582
29704
|
}
|
|
29705
|
+
if (this.product && next.presented && next.contentRect !== null) {
|
|
29706
|
+
this.ensureChild();
|
|
29707
|
+
}
|
|
29583
29708
|
if (this.state !== "shown") return;
|
|
29584
29709
|
const view = this.view;
|
|
29585
29710
|
if (!view || this.viewUsable(view) === false) return;
|
|
@@ -29596,6 +29721,40 @@ class AddressOverlayController {
|
|
|
29596
29721
|
this.log(`[browser] address overlay layout failed: ${String(error)}`);
|
|
29597
29722
|
}
|
|
29598
29723
|
}
|
|
29724
|
+
/** Hide the child's paint without dropping the popout's state; see `onLayout`. */
|
|
29725
|
+
suspendPresentation() {
|
|
29726
|
+
this.presentationSuspended = true;
|
|
29727
|
+
const view = this.view;
|
|
29728
|
+
if (!view || this.viewUsable(view) === false) return;
|
|
29729
|
+
try {
|
|
29730
|
+
view.setVisible(false);
|
|
29731
|
+
} catch {
|
|
29732
|
+
}
|
|
29733
|
+
}
|
|
29734
|
+
/** The page is back. Re-present the child from the bounds last applied, or
|
|
29735
|
+
* apply the projection that arrived while the page was hidden. */
|
|
29736
|
+
resumePresentation() {
|
|
29737
|
+
if (!this.presentationSuspended) return;
|
|
29738
|
+
this.presentationSuspended = false;
|
|
29739
|
+
const deferred = this.deferredProjection;
|
|
29740
|
+
this.deferredProjection = null;
|
|
29741
|
+
if (deferred !== null) {
|
|
29742
|
+
void this.project(deferred);
|
|
29743
|
+
return;
|
|
29744
|
+
}
|
|
29745
|
+
if (this.state !== "shown") return;
|
|
29746
|
+
const bounds = this.lastAppliedBounds ?? overlayBoundsFor(this.layout.contentRect, this.ownerSize());
|
|
29747
|
+
if (bounds === null) return;
|
|
29748
|
+
const view = this.view;
|
|
29749
|
+
if (!view || this.viewUsable(view) === false) return;
|
|
29750
|
+
try {
|
|
29751
|
+
view.setBounds(bounds);
|
|
29752
|
+
this.raiseChild(view);
|
|
29753
|
+
view.setVisible(true);
|
|
29754
|
+
} catch {
|
|
29755
|
+
this.releaseChild("layout_error");
|
|
29756
|
+
}
|
|
29757
|
+
}
|
|
29599
29758
|
/** The bound page is going away. Dispose the child before the page release. */
|
|
29600
29759
|
onTabReleased(tabId) {
|
|
29601
29760
|
if (this.disposed) return;
|
|
@@ -29610,6 +29769,63 @@ class AddressOverlayController {
|
|
|
29610
29769
|
if (this.boundTabId !== tabId) return;
|
|
29611
29770
|
this.releaseChild("page-crash");
|
|
29612
29771
|
}
|
|
29772
|
+
/**
|
|
29773
|
+
* The popout's current health, in the one shape the renderer reads.
|
|
29774
|
+
*
|
|
29775
|
+
* `suspend` is sticky for the app run: the child is either latched failed or
|
|
29776
|
+
* gone, and the restart that would clear it is a new process. A conditional
|
|
29777
|
+
* refusal (`zoomed`, `anchor_too_narrow`, `stale_*`) is NOT reported here —
|
|
29778
|
+
* those clear themselves, and the projection answer names them while they
|
|
29779
|
+
* last.
|
|
29780
|
+
*/
|
|
29781
|
+
mode() {
|
|
29782
|
+
if (this.disposed) return { mode: "suspend", reason: "disposed" };
|
|
29783
|
+
if (this.failedReason)
|
|
29784
|
+
return { mode: "suspend", reason: this.failedReason };
|
|
29785
|
+
return { mode: "popout", reason: null };
|
|
29786
|
+
}
|
|
29787
|
+
/**
|
|
29788
|
+
* A main-decided dismissal (the page took focus, the bound tab's main frame
|
|
29789
|
+
* navigated, the tab went away). Idempotent: a second reason for a popout that
|
|
29790
|
+
* is already hidden sends nothing.
|
|
29791
|
+
*/
|
|
29792
|
+
dismiss(reason) {
|
|
29793
|
+
if (this.disposed) return;
|
|
29794
|
+
this.hide(reason);
|
|
29795
|
+
if (this.product) this.emitDismiss(reason);
|
|
29796
|
+
}
|
|
29797
|
+
/** The page `tabId` took focus. Only the bound tab can dismiss its own list;
|
|
29798
|
+
* a background tab's focus event is not this popout's business. */
|
|
29799
|
+
dismissForTab(tabId, reason) {
|
|
29800
|
+
if (this.disposed) return;
|
|
29801
|
+
if (this.boundTabId !== null && this.boundTabId !== tabId) return;
|
|
29802
|
+
if (this.layout.activeTabId !== null && this.layout.activeTabId !== tabId)
|
|
29803
|
+
return;
|
|
29804
|
+
this.dismiss(reason);
|
|
29805
|
+
}
|
|
29806
|
+
/**
|
|
29807
|
+
* Warm the list child once the page has a presented layout, so the first
|
|
29808
|
+
* raise finds a loaded document instead of paying the load after Cmd+L. The
|
|
29809
|
+
* child is created hidden and stays hidden until a projection shows it.
|
|
29810
|
+
*/
|
|
29811
|
+
ensureChild() {
|
|
29812
|
+
if (!this.product || this.view || this.failedReason || this.warmScheduled)
|
|
29813
|
+
return;
|
|
29814
|
+
const bounds = overlayBoundsFor(this.layout.contentRect, this.ownerSize());
|
|
29815
|
+
if (bounds === null || !this.layout.presented) return;
|
|
29816
|
+
this.warmScheduled = true;
|
|
29817
|
+
setTimeout(() => {
|
|
29818
|
+
this.warmScheduled = false;
|
|
29819
|
+
if (this.disposed || this.view || this.failedReason) return;
|
|
29820
|
+
if (!this.layout.presented) return;
|
|
29821
|
+
const rect2 = overlayBoundsFor(this.layout.contentRect, this.ownerSize());
|
|
29822
|
+
if (rect2 === null) return;
|
|
29823
|
+
if (this.createChild(rect2)) this.state = "loading";
|
|
29824
|
+
}, 0);
|
|
29825
|
+
}
|
|
29826
|
+
emitDismiss(reason) {
|
|
29827
|
+
this.onEvent?.({ type: "dismiss", reason });
|
|
29828
|
+
}
|
|
29613
29829
|
// ---- probe surface ------------------------------------------------------
|
|
29614
29830
|
async showOverlay() {
|
|
29615
29831
|
if (this.showInFlight) return this.showInFlight;
|
|
@@ -29627,6 +29843,8 @@ class AddressOverlayController {
|
|
|
29627
29843
|
}
|
|
29628
29844
|
hide(reason = "hide") {
|
|
29629
29845
|
if (this.disposed) return;
|
|
29846
|
+
this.presentationSuspended = false;
|
|
29847
|
+
this.deferredProjection = null;
|
|
29630
29848
|
this.generation += 1;
|
|
29631
29849
|
this.settleReady(false);
|
|
29632
29850
|
this.hiddenReason = reason;
|
|
@@ -29793,6 +30011,15 @@ class AddressOverlayController {
|
|
|
29793
30011
|
* controller, so a burst between frames costs one apply each in arrival order.
|
|
29794
30012
|
*/
|
|
29795
30013
|
project(raw) {
|
|
30014
|
+
if (this.presentationSuspended) {
|
|
30015
|
+
this.deferredProjection = raw;
|
|
30016
|
+
return Promise.resolve({
|
|
30017
|
+
accepted: true,
|
|
30018
|
+
shown: false,
|
|
30019
|
+
reason: null,
|
|
30020
|
+
bounds: null
|
|
30021
|
+
});
|
|
30022
|
+
}
|
|
29796
30023
|
const run = () => this.projectOnce(raw);
|
|
29797
30024
|
const next = this.projectQueue.then(run, run);
|
|
29798
30025
|
this.projectQueue = next.then(
|
|
@@ -29855,13 +30082,23 @@ class AddressOverlayController {
|
|
|
29855
30082
|
if (!layout.presented || !sameRect(projection.pageRect, layout.contentRect)) {
|
|
29856
30083
|
return this.refuseProjection("stale_layout");
|
|
29857
30084
|
}
|
|
29858
|
-
const bounds =
|
|
30085
|
+
const bounds = projection.v === 2 ? projection.anchor.width < ADDRESS_LIST_MIN_WIDTH_DIP ? null : addressListBoundsV2For(
|
|
30086
|
+
projection.anchor,
|
|
30087
|
+
projection.pageRect,
|
|
30088
|
+
projection.view,
|
|
30089
|
+
this.ownerSize()
|
|
30090
|
+
) : addressListBoundsFor(
|
|
29859
30091
|
projection.field,
|
|
29860
30092
|
projection.listTop,
|
|
29861
30093
|
projection.view,
|
|
29862
30094
|
this.ownerSize()
|
|
29863
30095
|
);
|
|
29864
|
-
if (bounds === null)
|
|
30096
|
+
if (bounds === null) {
|
|
30097
|
+
const tooNarrow = projection.v === 2 && projection.anchor.width < ADDRESS_LIST_MIN_WIDTH_DIP;
|
|
30098
|
+
return this.refuseProjection(
|
|
30099
|
+
tooNarrow ? "anchor_too_narrow" : "anchor_inconsistent"
|
|
30100
|
+
);
|
|
30101
|
+
}
|
|
29865
30102
|
this.generation += 1;
|
|
29866
30103
|
const generation = this.generation;
|
|
29867
30104
|
this.boundTabId = projection.tabId;
|
|
@@ -30307,6 +30544,7 @@ class AddressOverlayController {
|
|
|
30307
30544
|
this.settleReady(false);
|
|
30308
30545
|
this.destroyChild();
|
|
30309
30546
|
this.log(`[browser] address overlay failed: ${reason}`);
|
|
30547
|
+
this.onHealthChange?.();
|
|
30310
30548
|
}
|
|
30311
30549
|
/** Recoverable: the child goes, a later explicit show may lazily recreate one. */
|
|
30312
30550
|
releaseChild(reason) {
|
|
@@ -30319,6 +30557,7 @@ class AddressOverlayController {
|
|
|
30319
30557
|
this.finished = false;
|
|
30320
30558
|
this.loadStartedAt = null;
|
|
30321
30559
|
this.log(`[browser] address overlay child released: ${reason}`);
|
|
30560
|
+
this.onHealthChange?.();
|
|
30322
30561
|
}
|
|
30323
30562
|
destroyChild() {
|
|
30324
30563
|
const view = this.view;
|
|
@@ -35118,11 +35357,15 @@ const enUiBrowser = {
|
|
|
35118
35357
|
"ui.browser.browser_tab_strip.unmute_tab": "Unmute tab",
|
|
35119
35358
|
"ui.browser.browser_tab_strip.watch": 'Watch "{title}"',
|
|
35120
35359
|
"ui.browser.browser_url_bar.address": "Address",
|
|
35121
|
-
"ui.browser.browser_url_bar.
|
|
35360
|
+
"ui.browser.browser_url_bar.address_search_row": 'Search DuckDuckGo for "{query}"',
|
|
35361
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "Already open — {title}",
|
|
35362
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Already open",
|
|
35122
35363
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} suggestion available} other {{count, number, ::group-off} suggestions available}}",
|
|
35123
|
-
"ui.browser.browser_url_bar.
|
|
35124
|
-
"ui.browser.browser_url_bar.
|
|
35125
|
-
"ui.browser.browser_url_bar.
|
|
35364
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "Only web addresses can open here.",
|
|
35365
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "No browsing history yet.",
|
|
35366
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "From your history",
|
|
35367
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "Suggestions",
|
|
35368
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "No matching pages in your history.",
|
|
35126
35369
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "Address suggestions are unavailable.",
|
|
35127
35370
|
"ui.browser.browser_url_bar.approvals_waiting": "Approvals, {count, plural, other {{count, number, ::group-off} waiting}}",
|
|
35128
35371
|
"ui.browser.browser_url_bar.back": "Back",
|
|
@@ -35135,6 +35378,7 @@ const enUiBrowser = {
|
|
|
35135
35378
|
"ui.browser.browser_url_bar.home_destination": "Home — go to the start page (blank)",
|
|
35136
35379
|
"ui.browser.browser_url_bar.latest_download": "Open downloads folder — {name} was saved there",
|
|
35137
35380
|
"ui.browser.browser_url_bar.newest_download": "Open downloads folder — {name} was the newest saved there ({count, plural, other {{count, number, ::group-off} this session}})",
|
|
35381
|
+
"ui.browser.browser_url_bar.page_menu": "Page options",
|
|
35138
35382
|
"ui.browser.browser_url_bar.page_zoom_reset": "Page zoom {zoom, number, ::group-off}%, reset to 100%",
|
|
35139
35383
|
"ui.browser.browser_url_bar.print_page": "Print page",
|
|
35140
35384
|
"ui.browser.browser_url_bar.reload": "Reload",
|
|
@@ -38842,15 +39086,20 @@ const esUiBrowser = {
|
|
|
38842
39086
|
"ui.browser.browser_url_bar.print_page": "Imprimir página",
|
|
38843
39087
|
"ui.browser.browser_url_bar.forward": "Adelante",
|
|
38844
39088
|
"ui.browser.browser_url_bar.reset_page_zoom_shortcut": "Restablecer zoom de la página ({shortcut})",
|
|
39089
|
+
"ui.browser.browser_url_bar.page_menu": "Opciones de página",
|
|
38845
39090
|
"ui.browser.browser_url_bar.page_zoom_reset": "Zoom de la página al {zoom, number, ::group-off}%, restablecer al 100%",
|
|
38846
39091
|
"ui.browser.browser_url_bar.stop_loading": "Detener carga",
|
|
38847
39092
|
"ui.browser.browser_url_bar.reload": "Recargar",
|
|
38848
39093
|
"ui.browser.browser_url_bar.address": "Dirección",
|
|
38849
|
-
"ui.browser.browser_url_bar.
|
|
39094
|
+
"ui.browser.browser_url_bar.address_search_row": "Buscar «{query}» en DuckDuckGo",
|
|
39095
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "Ya abierto — {title}",
|
|
39096
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Ya abierto",
|
|
38850
39097
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} sugerencia disponible} other {{count, number, ::group-off} sugerencias disponibles}}",
|
|
38851
|
-
"ui.browser.browser_url_bar.
|
|
38852
|
-
"ui.browser.browser_url_bar.
|
|
38853
|
-
"ui.browser.browser_url_bar.
|
|
39098
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "Aquí solo se pueden abrir direcciones web.",
|
|
39099
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "Aún no hay historial de navegación.",
|
|
39100
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "De tu historial",
|
|
39101
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "Sugerencias",
|
|
39102
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "No hay páginas coincidentes en tu historial.",
|
|
38854
39103
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "Las sugerencias de direcciones no están disponibles.",
|
|
38855
39104
|
"ui.browser.browser_url_bar.approvals_waiting": "Aprobaciones, {count, plural, other {{count, number, ::group-off} en espera}}",
|
|
38856
39105
|
"ui.browser.browser_url_bar.home_destination": "Inicio — ir a la página inicial (en blanco)",
|
|
@@ -42418,15 +42667,20 @@ const frUiBrowser = {
|
|
|
42418
42667
|
"ui.browser.browser_url_bar.print_page": "Imprimer la page",
|
|
42419
42668
|
"ui.browser.browser_url_bar.forward": "Avancer",
|
|
42420
42669
|
"ui.browser.browser_url_bar.reset_page_zoom_shortcut": "Réinitialiser le zoom de la page ({shortcut})",
|
|
42670
|
+
"ui.browser.browser_url_bar.page_menu": "Options de la page",
|
|
42421
42671
|
"ui.browser.browser_url_bar.page_zoom_reset": "Zoom de la page {zoom, number, ::group-off} %, réinitialiser à 100 %",
|
|
42422
42672
|
"ui.browser.browser_url_bar.stop_loading": "Arrêter le chargement",
|
|
42423
42673
|
"ui.browser.browser_url_bar.reload": "Recharger",
|
|
42424
42674
|
"ui.browser.browser_url_bar.address": "Adresse",
|
|
42425
|
-
"ui.browser.browser_url_bar.
|
|
42675
|
+
"ui.browser.browser_url_bar.address_search_row": "Rechercher « {query} » sur DuckDuckGo",
|
|
42676
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "Déjà ouvert — {title}",
|
|
42677
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Déjà ouvert",
|
|
42426
42678
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} suggestion disponible} many {{count, number, ::group-off} de suggestions disponibles} other {{count, number, ::group-off} suggestions disponibles}}",
|
|
42427
|
-
"ui.browser.browser_url_bar.
|
|
42428
|
-
"ui.browser.browser_url_bar.
|
|
42429
|
-
"ui.browser.browser_url_bar.
|
|
42679
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "Seules les adresses web peuvent s’ouvrir ici.",
|
|
42680
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "Pas encore d'historique de navigation.",
|
|
42681
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "De votre historique",
|
|
42682
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "Suggestions",
|
|
42683
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "Aucune page correspondante dans votre historique.",
|
|
42430
42684
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "Les suggestions d’adresses ne sont pas disponibles.",
|
|
42431
42685
|
"ui.browser.browser_url_bar.approvals_waiting": "Approbations, {count, plural, one {{count, number, ::group-off} en attente} many {{count, number, ::group-off} en attente} other {{count, number, ::group-off} en attente}}",
|
|
42432
42686
|
"ui.browser.browser_url_bar.home_destination": "Accueil — aller à la page de départ (vide)",
|
|
@@ -45998,11 +46252,15 @@ const hiUiBrowser = {
|
|
|
45998
46252
|
"ui.browser.browser_tab_strip.unmute_tab": "टैब की आवाज़ चालू करें",
|
|
45999
46253
|
"ui.browser.browser_tab_strip.watch": '"{title}" देखें',
|
|
46000
46254
|
"ui.browser.browser_url_bar.address": "पता",
|
|
46001
|
-
"ui.browser.browser_url_bar.
|
|
46255
|
+
"ui.browser.browser_url_bar.address_search_row": 'DuckDuckGo पर "{query}" खोजें',
|
|
46256
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "पहले से खुला — {title}",
|
|
46257
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "पहले से खुला",
|
|
46002
46258
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} सुझाव उपलब्ध है} other {{count, number, ::group-off} सुझाव उपलब्ध हैं}}",
|
|
46003
|
-
"ui.browser.browser_url_bar.
|
|
46004
|
-
"ui.browser.browser_url_bar.
|
|
46005
|
-
"ui.browser.browser_url_bar.
|
|
46259
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "यहाँ केवल वेब पते खुल सकते हैं।",
|
|
46260
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "अभी तक कोई ब्राउज़िंग इतिहास नहीं।",
|
|
46261
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "आपके इतिहास से",
|
|
46262
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "सुझाव",
|
|
46263
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "आपके इतिहास में कोई मेल खाता पृष्ठ नहीं।",
|
|
46006
46264
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "पते के सुझाव उपलब्ध नहीं हैं।",
|
|
46007
46265
|
"ui.browser.browser_url_bar.approvals_waiting": "स्वीकृतियाँ, {count, plural, other {{count, number, ::group-off} इंतज़ार में}}",
|
|
46008
46266
|
"ui.browser.browser_url_bar.back": "पीछे",
|
|
@@ -46015,6 +46273,7 @@ const hiUiBrowser = {
|
|
|
46015
46273
|
"ui.browser.browser_url_bar.home_destination": "होम — शुरुआती पेज पर जाएँ (खाली)",
|
|
46016
46274
|
"ui.browser.browser_url_bar.latest_download": "डाउनलोड फ़ोल्डर खोलें — {name} वहाँ सहेजी गई थी",
|
|
46017
46275
|
"ui.browser.browser_url_bar.newest_download": "डाउनलोड फ़ोल्डर खोलें — {name} वहाँ सबसे हाल में सहेजी गई थी ({count, plural, other {इस सत्र में {count, number, ::group-off}}})",
|
|
46276
|
+
"ui.browser.browser_url_bar.page_menu": "पेज विकल्प",
|
|
46018
46277
|
"ui.browser.browser_url_bar.page_zoom_reset": "पेज ज़ूम {zoom, number, ::group-off}%, 100% पर रीसेट करें",
|
|
46019
46278
|
"ui.browser.browser_url_bar.print_page": "पेज प्रिंट करें",
|
|
46020
46279
|
"ui.browser.browser_url_bar.reload": "फिर लोड करें",
|
|
@@ -49351,11 +49610,15 @@ const ruUiBrowser = {
|
|
|
49351
49610
|
"ui.browser.browser_tab_strip.unmute_tab": "Включить звук вкладки",
|
|
49352
49611
|
"ui.browser.browser_tab_strip.watch": "Смотреть «{title}»",
|
|
49353
49612
|
"ui.browser.browser_url_bar.address": "Адрес",
|
|
49354
|
-
"ui.browser.browser_url_bar.
|
|
49613
|
+
"ui.browser.browser_url_bar.address_search_row": "Искать «{query}» в DuckDuckGo",
|
|
49614
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "Уже открыто — {title}",
|
|
49615
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Уже открыто",
|
|
49355
49616
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} подсказка доступна} few {{count, number, ::group-off} подсказки доступны} many {{count, number, ::group-off} подсказок доступно} other {{count, number, ::group-off} подсказки доступны}}",
|
|
49356
|
-
"ui.browser.browser_url_bar.
|
|
49357
|
-
"ui.browser.browser_url_bar.
|
|
49358
|
-
"ui.browser.browser_url_bar.
|
|
49617
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "Здесь можно открывать только веб-адреса.",
|
|
49618
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "Истории просмотров пока нет.",
|
|
49619
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "Из вашей истории",
|
|
49620
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "Подсказки",
|
|
49621
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "В вашей истории нет подходящих страниц.",
|
|
49359
49622
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "Подсказки адресов недоступны.",
|
|
49360
49623
|
"ui.browser.browser_url_bar.approvals_waiting": "Одобрения, {count, plural, one {ожидает {count, number, ::group-off}} few {ожидают {count, number, ::group-off}} many {ожидают {count, number, ::group-off}} other {ожидают {count, number, ::group-off}}}",
|
|
49361
49624
|
"ui.browser.browser_url_bar.back": "Назад",
|
|
@@ -49368,6 +49631,7 @@ const ruUiBrowser = {
|
|
|
49368
49631
|
"ui.browser.browser_url_bar.home_destination": "Домой — перейти на стартовую страницу (пустую)",
|
|
49369
49632
|
"ui.browser.browser_url_bar.latest_download": "Открыть папку загрузок — {name} сохранён туда",
|
|
49370
49633
|
"ui.browser.browser_url_bar.newest_download": "Открыть папку загрузок — {name} сохранён туда последним ({count, plural, one {{count, number, ::group-off} за эту сессию} few {{count, number, ::group-off} за эту сессию} many {{count, number, ::group-off} за эту сессию} other {{count, number, ::group-off} за эту сессию}})",
|
|
49634
|
+
"ui.browser.browser_url_bar.page_menu": "Параметры страницы",
|
|
49371
49635
|
"ui.browser.browser_url_bar.page_zoom_reset": "Масштаб страницы {zoom, number, ::group-off}%, сбросить до 100%",
|
|
49372
49636
|
"ui.browser.browser_url_bar.print_page": "Печать страницы",
|
|
49373
49637
|
"ui.browser.browser_url_bar.reload": "Перезагрузить",
|
|
@@ -52810,11 +53074,15 @@ const urUiBrowser = {
|
|
|
52810
53074
|
"ui.browser.browser_tab_strip.unmute_tab": "ٹیب کی آواز بحال کریں",
|
|
52811
53075
|
"ui.browser.browser_tab_strip.watch": "“{title}” پر نظر رکھیں",
|
|
52812
53076
|
"ui.browser.browser_url_bar.address": "پتہ",
|
|
52813
|
-
"ui.browser.browser_url_bar.
|
|
53077
|
+
"ui.browser.browser_url_bar.address_search_row": 'DuckDuckGo پر "{query}" تلاش کریں',
|
|
53078
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "پہلے سے کھلا — {title}",
|
|
53079
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "پہلے سے کھلا",
|
|
52814
53080
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} تجویز دستیاب ہے} other {{count, number, ::group-off} تجاویز دستیاب ہیں}}",
|
|
52815
|
-
"ui.browser.browser_url_bar.
|
|
52816
|
-
"ui.browser.browser_url_bar.
|
|
52817
|
-
"ui.browser.browser_url_bar.
|
|
53081
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "یہاں صرف ویب پتے کھل سکتے ہیں۔",
|
|
53082
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "ابھی تک کوئی براؤزنگ سرگزشت نہیں۔",
|
|
53083
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "آپ کی سرگزشت سے",
|
|
53084
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "تجاویز",
|
|
53085
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "آپ کی سرگزشت میں کوئی مماثل صفحہ نہیں۔",
|
|
52818
53086
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "پتے کی تجاویز دستیاب نہیں ہیں۔",
|
|
52819
53087
|
"ui.browser.browser_url_bar.approvals_waiting": "منظوریاں، {count, plural, other {{count, number, ::group-off} منتظر}}",
|
|
52820
53088
|
"ui.browser.browser_url_bar.back": "پیچھے",
|
|
@@ -52827,6 +53095,7 @@ const urUiBrowser = {
|
|
|
52827
53095
|
"ui.browser.browser_url_bar.home_destination": "ابتدائی صفحہ — آغاز کے خالی صفحے پر جائیں",
|
|
52828
53096
|
"ui.browser.browser_url_bar.latest_download": "ڈاؤن لوڈ فولڈر کھولیں — {name} وہاں محفوظ ہوئی",
|
|
52829
53097
|
"ui.browser.browser_url_bar.newest_download": "ڈاؤن لوڈ فولڈر کھولیں — وہاں سب سے حال میں {name} محفوظ ہوئی ({count, plural, other {اس سیشن میں {count, number, ::group-off}}})",
|
|
53098
|
+
"ui.browser.browser_url_bar.page_menu": "صفحے کے اختیارات",
|
|
52830
53099
|
"ui.browser.browser_url_bar.page_zoom_reset": "صفحے کا زوم {zoom, number, ::group-off}%، 100% پر ری سیٹ کریں",
|
|
52831
53100
|
"ui.browser.browser_url_bar.print_page": "صفحہ پرنٹ کریں",
|
|
52832
53101
|
"ui.browser.browser_url_bar.reload": "دوبارہ لوڈ کریں",
|
|
@@ -56183,11 +56452,15 @@ const viUiBrowser = {
|
|
|
56183
56452
|
"ui.browser.browser_tab_strip.unmute_tab": "Bật tiếng tab",
|
|
56184
56453
|
"ui.browser.browser_tab_strip.watch": 'Theo dõi "{title}"',
|
|
56185
56454
|
"ui.browser.browser_url_bar.address": "Địa chỉ",
|
|
56186
|
-
"ui.browser.browser_url_bar.
|
|
56455
|
+
"ui.browser.browser_url_bar.address_search_row": 'Tìm "{query}" trên DuckDuckGo',
|
|
56456
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "Đã mở — {title}",
|
|
56457
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Đã mở",
|
|
56187
56458
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, other {{count, number, ::group-off} gợi ý có sẵn}}",
|
|
56188
|
-
"ui.browser.browser_url_bar.
|
|
56189
|
-
"ui.browser.browser_url_bar.
|
|
56190
|
-
"ui.browser.browser_url_bar.
|
|
56459
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "Chỉ có thể mở địa chỉ web ở đây.",
|
|
56460
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "Chưa có lịch sử duyệt web.",
|
|
56461
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "Từ lịch sử của bạn",
|
|
56462
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "Gợi ý",
|
|
56463
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "Không có trang nào phù hợp trong lịch sử của bạn.",
|
|
56191
56464
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "Gợi ý địa chỉ không khả dụng.",
|
|
56192
56465
|
"ui.browser.browser_url_bar.approvals_waiting": "Phê duyệt, {count, plural, other {{count, number, ::group-off} đang chờ}}",
|
|
56193
56466
|
"ui.browser.browser_url_bar.back": "Quay lại",
|
|
@@ -56200,6 +56473,7 @@ const viUiBrowser = {
|
|
|
56200
56473
|
"ui.browser.browser_url_bar.home_destination": "Trang chủ — đến trang bắt đầu (trống)",
|
|
56201
56474
|
"ui.browser.browser_url_bar.latest_download": "Mở thư mục tải xuống — {name} đã được lưu ở đó",
|
|
56202
56475
|
"ui.browser.browser_url_bar.newest_download": "Mở thư mục tải xuống — {name} là tệp mới nhất được lưu ở đó ({count, plural, other {{count, number, ::group-off} trong phiên này}})",
|
|
56476
|
+
"ui.browser.browser_url_bar.page_menu": "Tùy chọn trang",
|
|
56203
56477
|
"ui.browser.browser_url_bar.page_zoom_reset": "Thu phóng trang {zoom, number, ::group-off}%, đặt lại về 100%",
|
|
56204
56478
|
"ui.browser.browser_url_bar.print_page": "In trang",
|
|
56205
56479
|
"ui.browser.browser_url_bar.reload": "Tải lại",
|
|
@@ -59451,11 +59725,15 @@ const zhCNUiBrowser = {
|
|
|
59451
59725
|
"ui.browser.browser_tab_strip.unmute_tab": "取消标签页静音",
|
|
59452
59726
|
"ui.browser.browser_tab_strip.watch": "查看“{title}”",
|
|
59453
59727
|
"ui.browser.browser_url_bar.address": "地址",
|
|
59454
|
-
"ui.browser.browser_url_bar.
|
|
59728
|
+
"ui.browser.browser_url_bar.address_search_row": "在 DuckDuckGo 中搜索“{query}”",
|
|
59729
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab": "已打开 — {title}",
|
|
59730
|
+
"ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "已打开",
|
|
59455
59731
|
"ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, other {{count, number, ::group-off}条建议可用}}",
|
|
59456
|
-
"ui.browser.browser_url_bar.
|
|
59457
|
-
"ui.browser.browser_url_bar.
|
|
59458
|
-
"ui.browser.browser_url_bar.
|
|
59732
|
+
"ui.browser.browser_url_bar.address_suggestions_blocked": "此处只能打开网页地址。",
|
|
59733
|
+
"ui.browser.browser_url_bar.address_suggestions_empty": "还没有浏览历史记录。",
|
|
59734
|
+
"ui.browser.browser_url_bar.address_suggestions_label": "来自你的历史记录",
|
|
59735
|
+
"ui.browser.browser_url_bar.address_suggestions_label_mixed": "建议",
|
|
59736
|
+
"ui.browser.browser_url_bar.address_suggestions_no_match": "你的历史记录中没有匹配的页面。",
|
|
59459
59737
|
"ui.browser.browser_url_bar.address_suggestions_unavailable": "地址建议不可用。",
|
|
59460
59738
|
"ui.browser.browser_url_bar.approvals_waiting": "审批,{count, plural, other {{count, number, ::group-off}项待处理}}",
|
|
59461
59739
|
"ui.browser.browser_url_bar.back": "后退",
|
|
@@ -59468,6 +59746,7 @@ const zhCNUiBrowser = {
|
|
|
59468
59746
|
"ui.browser.browser_url_bar.home_destination": "主页——前往起始页(空白页)",
|
|
59469
59747
|
"ui.browser.browser_url_bar.latest_download": "打开下载文件夹——{name}已保存于此",
|
|
59470
59748
|
"ui.browser.browser_url_bar.newest_download": "打开下载文件夹——最新保存的文件为{name}(本次会话共{count, plural, other {{count, number, ::group-off}个}})",
|
|
59749
|
+
"ui.browser.browser_url_bar.page_menu": "页面选项",
|
|
59471
59750
|
"ui.browser.browser_url_bar.page_zoom_reset": "页面缩放{zoom, number, ::group-off}%,重置为100%",
|
|
59472
59751
|
"ui.browser.browser_url_bar.print_page": "打印页面",
|
|
59473
59752
|
"ui.browser.browser_url_bar.reload": "重新加载",
|
|
@@ -65747,7 +66026,8 @@ const ADDRESS_HISTORY_MAX_ENTRIES_PER_TAB = 50;
|
|
|
65747
66026
|
const ADDRESS_HISTORY_MAX_ENTRIES = 256;
|
|
65748
66027
|
const ADDRESS_HISTORY_MAX_URL_LENGTH = 2048;
|
|
65749
66028
|
const ADDRESS_HISTORY_MAX_TITLE_LENGTH = 256;
|
|
65750
|
-
const
|
|
66029
|
+
const ADDRESS_HISTORY_MAX_QUERY_LENGTH = ADDRESS_HISTORY_MAX_URL_LENGTH;
|
|
66030
|
+
const ADDRESS_HISTORY_MAX_LIMIT = 20;
|
|
65751
66031
|
const CONTROL_CHARS$1 = /[\p{Cc}]/u;
|
|
65752
66032
|
function windowAround(entries, activeIndexRaw, max) {
|
|
65753
66033
|
const activeIndex = Math.min(
|
|
@@ -65823,12 +66103,9 @@ function historyTitle(raw) {
|
|
|
65823
66103
|
const cleaned = raw.replace(CONTROL_CHARS$1, " ").replace(/\s+/g, " ").trim();
|
|
65824
66104
|
return cleaned.length > ADDRESS_HISTORY_MAX_TITLE_LENGTH ? cleaned.slice(0, ADDRESS_HISTORY_MAX_TITLE_LENGTH) : cleaned;
|
|
65825
66105
|
}
|
|
65826
|
-
function collectAddressHistory(tabs2,
|
|
65827
|
-
const
|
|
65828
|
-
|
|
65829
|
-
);
|
|
65830
|
-
const active = inScope.find((tab) => tab.tabId === activeTabId);
|
|
65831
|
-
const ordered = active ? [active, ...inScope.filter((tab) => tab.tabId !== activeTabId)] : inScope;
|
|
66106
|
+
function collectAddressHistory(tabs2, activeTabId) {
|
|
66107
|
+
const active = tabs2.find((tab) => tab.tabId === activeTabId);
|
|
66108
|
+
const ordered = active ? [active, ...tabs2.filter((tab) => tab.tabId !== activeTabId)] : [...tabs2];
|
|
65832
66109
|
const seen = /* @__PURE__ */ new Set();
|
|
65833
66110
|
const entries = [];
|
|
65834
66111
|
for (const tab of ordered.slice(0, ADDRESS_HISTORY_MAX_TABS)) {
|
|
@@ -65844,6 +66121,12 @@ function collectAddressHistory(tabs2, scope, activeTabId) {
|
|
|
65844
66121
|
entries.push({
|
|
65845
66122
|
url,
|
|
65846
66123
|
title: historyTitle(entry.title),
|
|
66124
|
+
// A stack has no visit count and no visit timestamp. Zero is the
|
|
66125
|
+
// honest absence; the renderer treats a tab row's order as stack
|
|
66126
|
+
// distance, never as frequency.
|
|
66127
|
+
visitCount: 0,
|
|
66128
|
+
lastVisitedAt: 0,
|
|
66129
|
+
source: "tab",
|
|
65847
66130
|
sourceTabId: tab.tabId,
|
|
65848
66131
|
sourceIndex,
|
|
65849
66132
|
activeTab: tab.tabId === activeTabId,
|
|
@@ -65857,6 +66140,38 @@ function collectAddressHistory(tabs2, scope, activeTabId) {
|
|
|
65857
66140
|
}
|
|
65858
66141
|
return { activeTabId, entries };
|
|
65859
66142
|
}
|
|
66143
|
+
function foldAscii(value) {
|
|
66144
|
+
return value.replace(/[A-Z]/g, (letter) => letter.toLowerCase());
|
|
66145
|
+
}
|
|
66146
|
+
function mergeAddressHistory(tabEntries, historyEntries, query, limit) {
|
|
66147
|
+
const cap = Math.max(0, Math.floor(limit));
|
|
66148
|
+
if (cap === 0) return [];
|
|
66149
|
+
const seen = /* @__PURE__ */ new Set();
|
|
66150
|
+
const merged = [];
|
|
66151
|
+
for (const entry of historyEntries) {
|
|
66152
|
+
if (merged.length >= cap) break;
|
|
66153
|
+
const url = canonicalHistoryUrl(entry.url);
|
|
66154
|
+
if (!url || seen.has(url)) continue;
|
|
66155
|
+
seen.add(url);
|
|
66156
|
+
merged.push({
|
|
66157
|
+
url,
|
|
66158
|
+
title: historyTitle(entry.title),
|
|
66159
|
+
visitCount: entry.visitCount,
|
|
66160
|
+
lastVisitedAt: entry.lastVisitedAt,
|
|
66161
|
+
source: "history"
|
|
66162
|
+
});
|
|
66163
|
+
}
|
|
66164
|
+
const needle = foldAscii(query.trim());
|
|
66165
|
+
for (const entry of tabEntries) {
|
|
66166
|
+
if (merged.length >= cap) break;
|
|
66167
|
+
if (seen.has(entry.url)) continue;
|
|
66168
|
+
if (needle.length > 0 && !foldAscii(entry.url).includes(needle) && !foldAscii(entry.title).includes(needle))
|
|
66169
|
+
continue;
|
|
66170
|
+
seen.add(entry.url);
|
|
66171
|
+
merged.push(entry);
|
|
66172
|
+
}
|
|
66173
|
+
return merged;
|
|
66174
|
+
}
|
|
65860
66175
|
class ChromeTabOrder {
|
|
65861
66176
|
ids = [];
|
|
65862
66177
|
customized = false;
|
|
@@ -65886,6 +66201,305 @@ class ChromeTabOrder {
|
|
|
65886
66201
|
return true;
|
|
65887
66202
|
}
|
|
65888
66203
|
}
|
|
66204
|
+
const HISTORY_STORE_VERSION = 1;
|
|
66205
|
+
const HISTORY_STORE_MAX_ENTRIES = 5e3;
|
|
66206
|
+
const HISTORY_STORE_MAX_BYTES = 2 * 1024 * 1024;
|
|
66207
|
+
const HISTORY_STORE_WRITE_DEBOUNCE_MS = 500;
|
|
66208
|
+
const HISTORY_STORE_MAX_CANDIDATES = 200;
|
|
66209
|
+
const PREFIX_WIDTH = 3;
|
|
66210
|
+
const RECENCY_HALF_LIFE_DAYS = 7;
|
|
66211
|
+
const DAY_MS = 24 * 60 * 60 * 1e3;
|
|
66212
|
+
const SCHEME_PREFIX = /^([a-z][a-z0-9+.-]*):\/\//i;
|
|
66213
|
+
const PATH_OR_QUERY = /[/?#]/;
|
|
66214
|
+
function schemeLess(value) {
|
|
66215
|
+
const match = SCHEME_PREFIX.exec(value);
|
|
66216
|
+
return match ? value.slice(match[0].length) : value;
|
|
66217
|
+
}
|
|
66218
|
+
function stripWww(value) {
|
|
66219
|
+
return value.startsWith("www.") && value.length > "www.".length ? value.slice("www.".length) : value;
|
|
66220
|
+
}
|
|
66221
|
+
function matchKey(value) {
|
|
66222
|
+
return stripWww(schemeLess(value.trim()).toLowerCase());
|
|
66223
|
+
}
|
|
66224
|
+
function literalKey(value) {
|
|
66225
|
+
return schemeLess(value.trim()).toLowerCase();
|
|
66226
|
+
}
|
|
66227
|
+
function indexKeys(url) {
|
|
66228
|
+
const keys = /* @__PURE__ */ new Set([literalKey(url), matchKey(url)]);
|
|
66229
|
+
return [...keys].filter((key) => key.length > 0);
|
|
66230
|
+
}
|
|
66231
|
+
function queryNeedles(raw) {
|
|
66232
|
+
const literal = literalKey(raw);
|
|
66233
|
+
const keys = /* @__PURE__ */ new Set([literal, stripWww(literal)]);
|
|
66234
|
+
return [...keys].filter((key) => key.length > 0);
|
|
66235
|
+
}
|
|
66236
|
+
function matchesNeedle(value, needle) {
|
|
66237
|
+
if (!value.startsWith(needle)) return false;
|
|
66238
|
+
const hostOnly = !PATH_OR_QUERY.test(needle);
|
|
66239
|
+
if (!hostOnly) return true;
|
|
66240
|
+
if (!needle.includes(".") || needle.endsWith(".")) return true;
|
|
66241
|
+
const next = value.charAt(needle.length);
|
|
66242
|
+
return next === "" || next === "/" || next === "?" || next === "#" || next === ":";
|
|
66243
|
+
}
|
|
66244
|
+
function prefixKey(matchKeyValue) {
|
|
66245
|
+
return matchKeyValue.slice(0, PREFIX_WIDTH);
|
|
66246
|
+
}
|
|
66247
|
+
function historyScore(entry, now) {
|
|
66248
|
+
const ageDays = Math.max(0, now - entry.lastVisitedAt) / DAY_MS;
|
|
66249
|
+
return Math.log2(1 + entry.visitCount) + 0.5 ** (ageDays / RECENCY_HALF_LIFE_DAYS);
|
|
66250
|
+
}
|
|
66251
|
+
function compareEntries(now) {
|
|
66252
|
+
return (a, b) => {
|
|
66253
|
+
const scoreDiff = historyScore(b, now) - historyScore(a, now);
|
|
66254
|
+
if (scoreDiff !== 0) return scoreDiff;
|
|
66255
|
+
if (a.lastVisitedAt !== b.lastVisitedAt)
|
|
66256
|
+
return b.lastVisitedAt - a.lastVisitedAt;
|
|
66257
|
+
return a.url < b.url ? -1 : a.url > b.url ? 1 : 0;
|
|
66258
|
+
};
|
|
66259
|
+
}
|
|
66260
|
+
function storageUrl(raw) {
|
|
66261
|
+
const canonical = canonicalHistoryUrl(raw);
|
|
66262
|
+
if (!canonical) return null;
|
|
66263
|
+
const hash = canonical.indexOf("#");
|
|
66264
|
+
return hash < 0 ? canonical : canonical.slice(0, hash);
|
|
66265
|
+
}
|
|
66266
|
+
function isEntry(value) {
|
|
66267
|
+
if (typeof value !== "object" || value === null) return false;
|
|
66268
|
+
const record = value;
|
|
66269
|
+
return typeof record.url === "string" && typeof record.title === "string" && typeof record.host === "string" && Number.isSafeInteger(record.visitCount) && record.visitCount > 0 && typeof record.lastVisitedAt === "number" && Number.isFinite(record.lastVisitedAt);
|
|
66270
|
+
}
|
|
66271
|
+
function createBrowserHistoryStore(filePath, options = {}) {
|
|
66272
|
+
const now = options.now ?? Date.now;
|
|
66273
|
+
const byUrl = /* @__PURE__ */ new Map();
|
|
66274
|
+
const prefix = /* @__PURE__ */ new Map();
|
|
66275
|
+
let writeTimer = null;
|
|
66276
|
+
let approxBytes = 0;
|
|
66277
|
+
function estimate(entry) {
|
|
66278
|
+
return entry.url.length + entry.title.length + entry.host.length + 192;
|
|
66279
|
+
}
|
|
66280
|
+
function indexAdd(entry) {
|
|
66281
|
+
approxBytes += estimate(entry);
|
|
66282
|
+
for (const key of indexKeys(entry.url)) {
|
|
66283
|
+
const bucketKey = prefixKey(key);
|
|
66284
|
+
let bucket = prefix.get(bucketKey);
|
|
66285
|
+
if (!bucket) {
|
|
66286
|
+
bucket = /* @__PURE__ */ new Set();
|
|
66287
|
+
prefix.set(bucketKey, bucket);
|
|
66288
|
+
}
|
|
66289
|
+
bucket.add(entry.url);
|
|
66290
|
+
}
|
|
66291
|
+
}
|
|
66292
|
+
function indexRemove(entry) {
|
|
66293
|
+
approxBytes -= estimate(entry);
|
|
66294
|
+
for (const key of indexKeys(entry.url)) {
|
|
66295
|
+
const bucketKey = prefixKey(key);
|
|
66296
|
+
const bucket = prefix.get(bucketKey);
|
|
66297
|
+
bucket?.delete(entry.url);
|
|
66298
|
+
if (bucket?.size === 0) prefix.delete(bucketKey);
|
|
66299
|
+
}
|
|
66300
|
+
}
|
|
66301
|
+
function setTitle(entry, next) {
|
|
66302
|
+
const before = estimate(entry);
|
|
66303
|
+
entry.title = next;
|
|
66304
|
+
approxBytes += estimate(entry) - before;
|
|
66305
|
+
}
|
|
66306
|
+
function enforceBounds(at) {
|
|
66307
|
+
let changed = false;
|
|
66308
|
+
if (byUrl.size <= HISTORY_STORE_MAX_ENTRIES && approxBytes <= HISTORY_STORE_MAX_BYTES)
|
|
66309
|
+
return false;
|
|
66310
|
+
if (byUrl.size > HISTORY_STORE_MAX_ENTRIES) {
|
|
66311
|
+
const overflow = byUrl.size - HISTORY_STORE_MAX_ENTRIES;
|
|
66312
|
+
const victims = [...byUrl.values()].sort(compareEntries(at)).reverse().slice(0, overflow);
|
|
66313
|
+
for (const victim of victims) {
|
|
66314
|
+
byUrl.delete(victim.url);
|
|
66315
|
+
indexRemove(victim);
|
|
66316
|
+
changed = true;
|
|
66317
|
+
}
|
|
66318
|
+
}
|
|
66319
|
+
let guard = 0;
|
|
66320
|
+
while (guard < 200 && byUrl.size > 0) {
|
|
66321
|
+
guard += 1;
|
|
66322
|
+
const bytes = Buffer.byteLength(
|
|
66323
|
+
JSON.stringify(document(), null, 2),
|
|
66324
|
+
"utf8"
|
|
66325
|
+
);
|
|
66326
|
+
if (bytes <= HISTORY_STORE_MAX_BYTES) {
|
|
66327
|
+
approxBytes = bytes;
|
|
66328
|
+
break;
|
|
66329
|
+
}
|
|
66330
|
+
const batch = Math.max(1, Math.ceil(byUrl.size / 100));
|
|
66331
|
+
const victims = [...byUrl.values()].sort(compareEntries(at)).reverse().slice(0, batch);
|
|
66332
|
+
for (const victim of victims) {
|
|
66333
|
+
byUrl.delete(victim.url);
|
|
66334
|
+
indexRemove(victim);
|
|
66335
|
+
changed = true;
|
|
66336
|
+
}
|
|
66337
|
+
}
|
|
66338
|
+
return changed;
|
|
66339
|
+
}
|
|
66340
|
+
function document() {
|
|
66341
|
+
return {
|
|
66342
|
+
version: HISTORY_STORE_VERSION,
|
|
66343
|
+
entries: [...byUrl.values()]
|
|
66344
|
+
};
|
|
66345
|
+
}
|
|
66346
|
+
function writeNow() {
|
|
66347
|
+
if (writeTimer !== null) {
|
|
66348
|
+
clearTimeout(writeTimer);
|
|
66349
|
+
writeTimer = null;
|
|
66350
|
+
}
|
|
66351
|
+
writeJsonAtomic(filePath, document());
|
|
66352
|
+
}
|
|
66353
|
+
function scheduleWrite2() {
|
|
66354
|
+
if (writeTimer !== null) return;
|
|
66355
|
+
writeTimer = setTimeout(() => {
|
|
66356
|
+
writeTimer = null;
|
|
66357
|
+
writeJsonAtomic(filePath, document());
|
|
66358
|
+
}, HISTORY_STORE_WRITE_DEBOUNCE_MS);
|
|
66359
|
+
writeTimer.unref?.();
|
|
66360
|
+
}
|
|
66361
|
+
const loaded = readJson(filePath);
|
|
66362
|
+
if (loaded && loaded.version === HISTORY_STORE_VERSION && Array.isArray(loaded.entries)) {
|
|
66363
|
+
for (const raw of loaded.entries) {
|
|
66364
|
+
if (!isEntry(raw)) continue;
|
|
66365
|
+
const url = storageUrl(raw.url);
|
|
66366
|
+
if (!url) continue;
|
|
66367
|
+
const host = new URL(url).host;
|
|
66368
|
+
const existing = byUrl.get(url);
|
|
66369
|
+
if (existing) {
|
|
66370
|
+
existing.visitCount = Math.max(existing.visitCount, raw.visitCount);
|
|
66371
|
+
existing.lastVisitedAt = Math.max(
|
|
66372
|
+
existing.lastVisitedAt,
|
|
66373
|
+
raw.lastVisitedAt
|
|
66374
|
+
);
|
|
66375
|
+
if (existing.title.length === 0) {
|
|
66376
|
+
const title = historyTitle(raw.title);
|
|
66377
|
+
if (title.length > 0) setTitle(existing, title);
|
|
66378
|
+
}
|
|
66379
|
+
continue;
|
|
66380
|
+
}
|
|
66381
|
+
const entry = {
|
|
66382
|
+
url,
|
|
66383
|
+
title: historyTitle(raw.title),
|
|
66384
|
+
host,
|
|
66385
|
+
visitCount: raw.visitCount,
|
|
66386
|
+
lastVisitedAt: raw.lastVisitedAt
|
|
66387
|
+
};
|
|
66388
|
+
byUrl.set(url, entry);
|
|
66389
|
+
indexAdd(entry);
|
|
66390
|
+
}
|
|
66391
|
+
if (enforceBounds(now())) {
|
|
66392
|
+
writeNow();
|
|
66393
|
+
}
|
|
66394
|
+
}
|
|
66395
|
+
return {
|
|
66396
|
+
record(rawUrl, rawTitle, at = now()) {
|
|
66397
|
+
const url = storageUrl(rawUrl);
|
|
66398
|
+
if (!url) return;
|
|
66399
|
+
const title = historyTitle(rawTitle);
|
|
66400
|
+
const existing = byUrl.get(url);
|
|
66401
|
+
if (existing) {
|
|
66402
|
+
existing.visitCount += 1;
|
|
66403
|
+
existing.lastVisitedAt = at;
|
|
66404
|
+
if (title.length > 0 && title !== existing.title)
|
|
66405
|
+
setTitle(existing, title);
|
|
66406
|
+
} else {
|
|
66407
|
+
const entry = {
|
|
66408
|
+
url,
|
|
66409
|
+
title,
|
|
66410
|
+
host: new URL(url).host,
|
|
66411
|
+
visitCount: 1,
|
|
66412
|
+
lastVisitedAt: at
|
|
66413
|
+
};
|
|
66414
|
+
byUrl.set(url, entry);
|
|
66415
|
+
indexAdd(entry);
|
|
66416
|
+
}
|
|
66417
|
+
enforceBounds(at);
|
|
66418
|
+
scheduleWrite2();
|
|
66419
|
+
},
|
|
66420
|
+
updateTitle(rawUrl, rawTitle) {
|
|
66421
|
+
const url = storageUrl(rawUrl);
|
|
66422
|
+
if (!url) return;
|
|
66423
|
+
const entry = byUrl.get(url);
|
|
66424
|
+
if (!entry) return;
|
|
66425
|
+
const title = historyTitle(rawTitle);
|
|
66426
|
+
if (title.length === 0 || title === entry.title) return;
|
|
66427
|
+
setTitle(entry, title);
|
|
66428
|
+
enforceBounds(now());
|
|
66429
|
+
scheduleWrite2();
|
|
66430
|
+
},
|
|
66431
|
+
suggest(rawQuery, limit) {
|
|
66432
|
+
const wanted = Math.max(0, Math.floor(limit));
|
|
66433
|
+
if (wanted === 0 || byUrl.size === 0) return [];
|
|
66434
|
+
const at = now();
|
|
66435
|
+
if (rawQuery.length === 0) {
|
|
66436
|
+
return [...byUrl.values()].sort(compareEntries(at)).slice(0, wanted);
|
|
66437
|
+
}
|
|
66438
|
+
const needles = queryNeedles(rawQuery);
|
|
66439
|
+
if (needles.length === 0) return [];
|
|
66440
|
+
const bucketSet = /* @__PURE__ */ new Set();
|
|
66441
|
+
for (const needle of needles) {
|
|
66442
|
+
if (needle.length >= PREFIX_WIDTH) {
|
|
66443
|
+
const bucket = prefix.get(prefixKey(needle));
|
|
66444
|
+
if (bucket) bucketSet.add(bucket);
|
|
66445
|
+
} else {
|
|
66446
|
+
for (const [key, bucket] of prefix) {
|
|
66447
|
+
if (key.startsWith(needle)) bucketSet.add(bucket);
|
|
66448
|
+
}
|
|
66449
|
+
}
|
|
66450
|
+
}
|
|
66451
|
+
const buckets = [...bucketSet];
|
|
66452
|
+
if (buckets.length === 0) return [];
|
|
66453
|
+
const candidates = [];
|
|
66454
|
+
const seen = /* @__PURE__ */ new Set();
|
|
66455
|
+
for (const bucket of buckets) {
|
|
66456
|
+
for (const url of bucket) {
|
|
66457
|
+
if (candidates.length >= HISTORY_STORE_MAX_CANDIDATES) break;
|
|
66458
|
+
if (seen.has(url)) continue;
|
|
66459
|
+
const keys = indexKeys(url);
|
|
66460
|
+
const hit = needles.some(
|
|
66461
|
+
(needle) => keys.some((key) => matchesNeedle(key, needle))
|
|
66462
|
+
);
|
|
66463
|
+
if (!hit) continue;
|
|
66464
|
+
const entry = byUrl.get(url);
|
|
66465
|
+
if (!entry) continue;
|
|
66466
|
+
seen.add(url);
|
|
66467
|
+
candidates.push(entry);
|
|
66468
|
+
}
|
|
66469
|
+
if (candidates.length >= HISTORY_STORE_MAX_CANDIDATES) break;
|
|
66470
|
+
}
|
|
66471
|
+
candidates.sort(compareEntries(at));
|
|
66472
|
+
return candidates.slice(0, wanted);
|
|
66473
|
+
},
|
|
66474
|
+
size() {
|
|
66475
|
+
return byUrl.size;
|
|
66476
|
+
},
|
|
66477
|
+
clear() {
|
|
66478
|
+
byUrl.clear();
|
|
66479
|
+
prefix.clear();
|
|
66480
|
+
writeNow();
|
|
66481
|
+
},
|
|
66482
|
+
clearOrigin(rawOrigin) {
|
|
66483
|
+
let parsed;
|
|
66484
|
+
try {
|
|
66485
|
+
parsed = new URL(rawOrigin);
|
|
66486
|
+
} catch {
|
|
66487
|
+
return;
|
|
66488
|
+
}
|
|
66489
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return;
|
|
66490
|
+
const origin = parsed.origin;
|
|
66491
|
+
for (const [url, entry] of [...byUrl.entries()]) {
|
|
66492
|
+
if (new URL(url).origin !== origin) continue;
|
|
66493
|
+
byUrl.delete(url);
|
|
66494
|
+
indexRemove(entry);
|
|
66495
|
+
}
|
|
66496
|
+
writeNow();
|
|
66497
|
+
},
|
|
66498
|
+
flush() {
|
|
66499
|
+
if (writeTimer !== null) writeNow();
|
|
66500
|
+
}
|
|
66501
|
+
};
|
|
66502
|
+
}
|
|
65889
66503
|
const PAGE_ZOOM_STEPS = [
|
|
65890
66504
|
0.25,
|
|
65891
66505
|
0.33,
|
|
@@ -66259,6 +66873,14 @@ class BrowserHost {
|
|
|
66259
66873
|
facts;
|
|
66260
66874
|
/** The session's per-origin storage clear, injected (see `BrowserHostOptions`). */
|
|
66261
66875
|
forgetSiteData;
|
|
66876
|
+
/** S4b's popout health, read from the controller (or the launch's platform
|
|
66877
|
+
* answer when no controller exists). The strip reads this from the same
|
|
66878
|
+
* projection as the tabs, so the renderer has one source for "child or
|
|
66879
|
+
* fallback" and never guesses from a failed IPC call. */
|
|
66880
|
+
addressOverlayMode;
|
|
66881
|
+
/** One instance per host, constructed once in the constructor. `null` when
|
|
66882
|
+
* no path was supplied (see `BrowserHostOptions.historyFilePath`). */
|
|
66883
|
+
historyStore;
|
|
66262
66884
|
/**
|
|
66263
66885
|
* The last main-frame load failure per tab, cleared by the next load.
|
|
66264
66886
|
*
|
|
@@ -66284,6 +66906,8 @@ class BrowserHost {
|
|
|
66284
66906
|
this.tabAudio = new TabAudioTracker(() => this.onChanged());
|
|
66285
66907
|
this.facts = options.facts;
|
|
66286
66908
|
this.forgetSiteData = options.forgetSiteData;
|
|
66909
|
+
this.addressOverlayMode = options.addressOverlayMode ?? (() => ({ mode: "suspend", reason: "unavailable" }));
|
|
66910
|
+
this.historyStore = options.historyFilePath ? createBrowserHistoryStore(options.historyFilePath) : null;
|
|
66287
66911
|
}
|
|
66288
66912
|
/** Answer one wire request. The only place a method name becomes an action. */
|
|
66289
66913
|
async dispatch(method, params, requestId2) {
|
|
@@ -66564,6 +67188,7 @@ class BrowserHost {
|
|
|
66564
67188
|
new Set(this.registry.snapshot().map((entry) => entry.tabId))
|
|
66565
67189
|
);
|
|
66566
67190
|
return {
|
|
67191
|
+
addressOverlay: this.addressOverlayMode(),
|
|
66567
67192
|
pageControls: this.pageControls.state(active),
|
|
66568
67193
|
tabs: this.chromeTabOrder.project(this.registry.snapshot()).map((entry, displayOrder) => ({
|
|
66569
67194
|
...this.chromeTabOrder.hasCustomOrder ? { displayOrder } : {},
|
|
@@ -67150,8 +67775,13 @@ class BrowserHost {
|
|
|
67150
67775
|
* no longer matches, which covers the race between this check and the reply
|
|
67151
67776
|
* landing.
|
|
67152
67777
|
*
|
|
67153
|
-
*
|
|
67154
|
-
*
|
|
67778
|
+
* RANKING MOVED HERE with the persistent store: the renderer used to rank a
|
|
67779
|
+
* snapshot of every stack, which cannot scale to a 5000-entry history either
|
|
67780
|
+
* in memory or across IPC. Main now asks the store for its top matches, puts
|
|
67781
|
+
* them ahead of the live-tab rows (`mergeAddressHistory`), and bounds the
|
|
67782
|
+
* answer by `request.limit`. The renderer still derives display text, the
|
|
67783
|
+
* target URL and the inline suffix, because those depend on exactly what the
|
|
67784
|
+
* user typed.
|
|
67155
67785
|
*/
|
|
67156
67786
|
addressHistory(request) {
|
|
67157
67787
|
const activeTabId = this.registry.activeTab?.tabId ?? null;
|
|
@@ -67161,20 +67791,59 @@ class BrowserHost {
|
|
|
67161
67791
|
"the active tab changed before suggestions were read"
|
|
67162
67792
|
);
|
|
67163
67793
|
}
|
|
67794
|
+
const live = collectAddressHistory(
|
|
67795
|
+
this.registry.list().map((record) => ({
|
|
67796
|
+
tabId: record.tabId,
|
|
67797
|
+
sessionId: record.sessionId,
|
|
67798
|
+
webContents: record.view.webContents,
|
|
67799
|
+
restoreRow: record.restoreRow ?? null
|
|
67800
|
+
})),
|
|
67801
|
+
activeTabId
|
|
67802
|
+
);
|
|
67803
|
+
const historyMatches = this.historyStore?.suggest(request.query, request.limit) ?? [];
|
|
67164
67804
|
return {
|
|
67165
67805
|
requestId: request.requestId,
|
|
67166
|
-
|
|
67167
|
-
|
|
67168
|
-
|
|
67169
|
-
|
|
67170
|
-
|
|
67171
|
-
|
|
67172
|
-
})),
|
|
67173
|
-
request.scope,
|
|
67174
|
-
activeTabId
|
|
67806
|
+
activeTabId: live.activeTabId,
|
|
67807
|
+
entries: mergeAddressHistory(
|
|
67808
|
+
live.entries,
|
|
67809
|
+
historyMatches,
|
|
67810
|
+
request.query,
|
|
67811
|
+
request.limit
|
|
67175
67812
|
)
|
|
67176
67813
|
};
|
|
67177
67814
|
}
|
|
67815
|
+
/**
|
|
67816
|
+
* Record one committed top-level navigation.
|
|
67817
|
+
*
|
|
67818
|
+
* Called from the per-view wiring in `index.ts`, which is the only place that
|
|
67819
|
+
* sees the event for every tab. A non-HTTP(S) URL is dropped by the store, so
|
|
67820
|
+
* `about:blank`, `chrome://` and a refused scheme never enter the document.
|
|
67821
|
+
* The title is filled in by `recordHistoryTitle` when Chromium announces it;
|
|
67822
|
+
* recording the visit first is deliberate, because the commit is the fact and
|
|
67823
|
+
* the title is a later, optional update.
|
|
67824
|
+
*/
|
|
67825
|
+
recordHistoryVisit(url) {
|
|
67826
|
+
this.historyStore?.record(url, "");
|
|
67827
|
+
}
|
|
67828
|
+
/** Update the stored title for a URL that is already in the history. Never
|
|
67829
|
+
* increments a visit: `page-title-updated` fires for a page that has already
|
|
67830
|
+
* been counted, sometimes several times. */
|
|
67831
|
+
recordHistoryTitle(url, title) {
|
|
67832
|
+
this.historyStore?.updateTitle(url, title);
|
|
67833
|
+
}
|
|
67834
|
+
/** Write any debounced history change now (quit, and the host's own stop). */
|
|
67835
|
+
flushHistory() {
|
|
67836
|
+
this.historyStore?.flush();
|
|
67837
|
+
}
|
|
67838
|
+
/** "Clear everything" also forgets the suggestion history (`profile.ts` is
|
|
67839
|
+
* the path that calls this, so cookies/cache alone cannot reach it). */
|
|
67840
|
+
clearHistory() {
|
|
67841
|
+
this.historyStore?.clear();
|
|
67842
|
+
}
|
|
67843
|
+
/** "Forget this site" drops that origin's rows; other origins stay. */
|
|
67844
|
+
clearOriginHistory(origin) {
|
|
67845
|
+
this.historyStore?.clearOrigin(origin);
|
|
67846
|
+
}
|
|
67178
67847
|
/**
|
|
67179
67848
|
* A URL the USER typed goes through here, and it is deliberately different from
|
|
67180
67849
|
* an agent navigation in one way and identical in another (design 6.1):
|
|
@@ -68278,6 +68947,7 @@ function tabIdOrThrow(value, name) {
|
|
|
68278
68947
|
return id2;
|
|
68279
68948
|
}
|
|
68280
68949
|
const CONTROL_CHARS = /[\p{Cc}]/u;
|
|
68950
|
+
const PRODUCT_ADDRESS_OVERLAY_EVENT = "browser-address-overlay-event";
|
|
68281
68951
|
const BROWSER_IPC_CHANNELS = [
|
|
68282
68952
|
"browser-state",
|
|
68283
68953
|
"browser-set-chord-focus",
|
|
@@ -68291,6 +68961,7 @@ const BROWSER_IPC_CHANNELS = [
|
|
|
68291
68961
|
"browser-close-tabs",
|
|
68292
68962
|
"browser-activate-tab",
|
|
68293
68963
|
"browser-address-history",
|
|
68964
|
+
"browser-address-overlay-project",
|
|
68294
68965
|
"browser-navigate",
|
|
68295
68966
|
"browser-home",
|
|
68296
68967
|
"browser-reload",
|
|
@@ -68591,6 +69262,21 @@ function registerBrowserIpc(options) {
|
|
|
68591
69262
|
}
|
|
68592
69263
|
);
|
|
68593
69264
|
}
|
|
69265
|
+
if (options.addressOverlayProduct) {
|
|
69266
|
+
electron.ipcMain.handle(
|
|
69267
|
+
"browser-address-overlay-project",
|
|
69268
|
+
(event, payload) => {
|
|
69269
|
+
authorizeSender(event);
|
|
69270
|
+
const project = options.addressOverlayProduct;
|
|
69271
|
+
if (!project) {
|
|
69272
|
+
throw new Error(
|
|
69273
|
+
"address_overlay_unavailable: the overlay projection is not running."
|
|
69274
|
+
);
|
|
69275
|
+
}
|
|
69276
|
+
return project(payload);
|
|
69277
|
+
}
|
|
69278
|
+
);
|
|
69279
|
+
}
|
|
68594
69280
|
if (options.addressOverlayProject) {
|
|
68595
69281
|
electron.ipcMain.handle(
|
|
68596
69282
|
DEV_DRIVER_ADDRESS_OVERLAY_PROJECT,
|
|
@@ -68617,21 +69303,17 @@ function addressHistoryRequestOrThrow(value) {
|
|
|
68617
69303
|
const request = value;
|
|
68618
69304
|
const requestId2 = numberOrThrow(request.requestId, "requestId");
|
|
68619
69305
|
const expectedTabId = tabIdOrThrow(request.expectedTabId, "expectedTabId");
|
|
68620
|
-
|
|
68621
|
-
|
|
68622
|
-
scope = "all";
|
|
68623
|
-
} else if (request.scope && typeof request.scope === "object" && typeof request.scope.sessionId === "string") {
|
|
68624
|
-
const sessionId2 = request.scope.sessionId.trim();
|
|
68625
|
-
if (!sessionId2 || sessionId2.length > ADDRESS_HISTORY_MAX_SESSION_ID_LENGTH || CONTROL_CHARS.test(sessionId2)) {
|
|
68626
|
-
throw new Error(
|
|
68627
|
-
"The address history scope needs a valid conversation id."
|
|
68628
|
-
);
|
|
68629
|
-
}
|
|
68630
|
-
scope = { sessionId: sessionId2 };
|
|
68631
|
-
} else {
|
|
68632
|
-
throw new Error("The address history scope is invalid.");
|
|
69306
|
+
if (typeof request.query !== "string") {
|
|
69307
|
+
throw new Error("The address history query must be a string.");
|
|
68633
69308
|
}
|
|
68634
|
-
|
|
69309
|
+
const query = request.query;
|
|
69310
|
+
if (query.length > ADDRESS_HISTORY_MAX_QUERY_LENGTH || CONTROL_CHARS.test(query)) {
|
|
69311
|
+
throw new Error("The address history query is invalid.");
|
|
69312
|
+
}
|
|
69313
|
+
if (typeof request.limit !== "number" || !Number.isSafeInteger(request.limit) || request.limit < 1 || request.limit > ADDRESS_HISTORY_MAX_LIMIT) {
|
|
69314
|
+
throw new Error("The address history limit is invalid.");
|
|
69315
|
+
}
|
|
69316
|
+
return { requestId: requestId2, expectedTabId, query, limit: request.limit };
|
|
68635
69317
|
}
|
|
68636
69318
|
function closeTabsIntentOrThrow(value) {
|
|
68637
69319
|
if (!value || typeof value !== "object") {
|
|
@@ -69150,7 +69832,7 @@ function installBrowserSessionHandlers(browserSession, hooks = {}) {
|
|
|
69150
69832
|
browserSession.removeListener("will-download", onDownload);
|
|
69151
69833
|
};
|
|
69152
69834
|
}
|
|
69153
|
-
async function clearBrowsingData(browserSession, what) {
|
|
69835
|
+
async function clearBrowsingData(browserSession, what, history) {
|
|
69154
69836
|
browserSession.flushStorageData();
|
|
69155
69837
|
if (what === "cache") {
|
|
69156
69838
|
await browserSession.clearCache();
|
|
@@ -69172,8 +69854,9 @@ async function clearBrowsingData(browserSession, what) {
|
|
|
69172
69854
|
}
|
|
69173
69855
|
await browserSession.clearData();
|
|
69174
69856
|
await browserSession.clearCache();
|
|
69857
|
+
history?.clear();
|
|
69175
69858
|
}
|
|
69176
|
-
async function clearOriginData(browserSession, origin) {
|
|
69859
|
+
async function clearOriginData(browserSession, origin, history) {
|
|
69177
69860
|
browserSession.flushStorageData();
|
|
69178
69861
|
await browserSession.clearData({
|
|
69179
69862
|
origins: [origin],
|
|
@@ -69189,6 +69872,7 @@ async function clearOriginData(browserSession, origin) {
|
|
|
69189
69872
|
"cache"
|
|
69190
69873
|
]
|
|
69191
69874
|
});
|
|
69875
|
+
history?.clearOrigin(origin);
|
|
69192
69876
|
}
|
|
69193
69877
|
function flushBrowserStorage(browserSession) {
|
|
69194
69878
|
try {
|
|
@@ -70475,6 +71159,9 @@ function refusesNavigation(rawUrl) {
|
|
|
70475
71159
|
}
|
|
70476
71160
|
}
|
|
70477
71161
|
let activeHost = null;
|
|
71162
|
+
electron.app.on("before-quit", () => {
|
|
71163
|
+
activeHost?.host.flushHistory();
|
|
71164
|
+
});
|
|
70478
71165
|
function routeBrowserZoomInput(event, input) {
|
|
70479
71166
|
const candidate = browserChordIntent(
|
|
70480
71167
|
{ ...input, isAutoRepeat: false, isComposing: false },
|
|
@@ -70588,6 +71275,17 @@ function startBrowserHost(options) {
|
|
|
70588
71275
|
* then it reads the current attempt's callback through `bindings` (a retry
|
|
70589
71276
|
* replaces it) rather than capturing a controller here.
|
|
70590
71277
|
*/
|
|
71278
|
+
...options.addressOverlay?.product === true ? {
|
|
71279
|
+
addressOverlayProduct: (payload) => {
|
|
71280
|
+
const project = bindings.addressOverlayProject;
|
|
71281
|
+
if (!project) {
|
|
71282
|
+
throw new Error(
|
|
71283
|
+
"address_overlay_unavailable: the overlay controller is not running."
|
|
71284
|
+
);
|
|
71285
|
+
}
|
|
71286
|
+
return project(payload);
|
|
71287
|
+
}
|
|
71288
|
+
} : {},
|
|
70591
71289
|
...options.addressOverlay?.enabled ? {
|
|
70592
71290
|
addressOverlayProbe: (action, argument) => {
|
|
70593
71291
|
const probe = bindings.addressOverlayProbe;
|
|
@@ -70678,8 +71376,18 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
70678
71376
|
return view;
|
|
70679
71377
|
}, wireView = function(view, tabId) {
|
|
70680
71378
|
const contents = view.webContents;
|
|
70681
|
-
contents.on("focus", () =>
|
|
71379
|
+
contents.on("focus", () => {
|
|
71380
|
+
host.setPageFocused(tabId, true);
|
|
71381
|
+
addressOverlay?.dismissForTab(tabId, "page_focus");
|
|
71382
|
+
});
|
|
70682
71383
|
contents.on("blur", () => host.setPageFocused(tabId, false));
|
|
71384
|
+
contents.on(
|
|
71385
|
+
"did-start-navigation",
|
|
71386
|
+
(_event, _url, isInPlace, isMainFrame) => {
|
|
71387
|
+
if (isMainFrame && !isInPlace)
|
|
71388
|
+
addressOverlay?.dismissForTab(tabId, "navigation");
|
|
71389
|
+
}
|
|
71390
|
+
);
|
|
70683
71391
|
const popupChildren = /* @__PURE__ */ new Set();
|
|
70684
71392
|
contents.setWindowOpenHandler((details) => {
|
|
70685
71393
|
const decision = decidePopup(
|
|
@@ -70801,7 +71509,10 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
70801
71509
|
notifyChrome();
|
|
70802
71510
|
});
|
|
70803
71511
|
contents.on("did-stop-loading", notifyChrome);
|
|
70804
|
-
contents.on("page-title-updated",
|
|
71512
|
+
contents.on("page-title-updated", (_event, title) => {
|
|
71513
|
+
host.recordHistoryTitle(contents.getURL(), title);
|
|
71514
|
+
notifyChrome();
|
|
71515
|
+
});
|
|
70805
71516
|
contents.on("render-process-gone", () => {
|
|
70806
71517
|
addressOverlay?.onPageGone(tabId);
|
|
70807
71518
|
});
|
|
@@ -70829,12 +71540,14 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
70829
71540
|
stopLogCapture(contents.id);
|
|
70830
71541
|
startLogCapture(contents.id);
|
|
70831
71542
|
log2(`[browser] tab ${tabId} navigated to ${url}`);
|
|
71543
|
+
host.recordHistoryVisit(url);
|
|
70832
71544
|
notifyChanged();
|
|
70833
71545
|
});
|
|
70834
71546
|
contents.on("did-navigate-in-page", (_event, url, isMainFrame) => {
|
|
70835
71547
|
if (!isMainFrame) return;
|
|
70836
71548
|
registry.bumpEpoch(tabId, false);
|
|
70837
71549
|
log2(`[browser] tab ${tabId} navigated in page to ${url}`);
|
|
71550
|
+
host.recordHistoryVisit(url);
|
|
70838
71551
|
notifyChanged();
|
|
70839
71552
|
});
|
|
70840
71553
|
contents.on("destroyed", () => {
|
|
@@ -70973,6 +71686,9 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
70973
71686
|
rollback.add(() => webauthn.dispose());
|
|
70974
71687
|
const detachWebauthn = attachWebauthnChooser(browserSession, webauthn, log2);
|
|
70975
71688
|
rollback.add(detachWebauthn);
|
|
71689
|
+
const historyClearer = {
|
|
71690
|
+
current: null
|
|
71691
|
+
};
|
|
70976
71692
|
const cookieJar = createHiddenCookieJarTarget(
|
|
70977
71693
|
new electron.WebContentsView({
|
|
70978
71694
|
webPreferences: { ...HIDDEN_COOKIE_JAR_WEB_PREFERENCES }
|
|
@@ -70984,7 +71700,7 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
70984
71700
|
cipher: browserProfileCipher(),
|
|
70985
71701
|
...sessionCookiePaths(options.userDataDir),
|
|
70986
71702
|
flushStore: () => browserSession.cookies.flushStore(),
|
|
70987
|
-
clearSessionData: (what) => clearBrowsingData(browserSession, what),
|
|
71703
|
+
clearSessionData: (what) => clearBrowsingData(browserSession, what, historyClearer.current),
|
|
70988
71704
|
log: log2
|
|
70989
71705
|
});
|
|
70990
71706
|
let restoreReport = null;
|
|
@@ -70999,21 +71715,26 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
70999
71715
|
const views = /* @__PURE__ */ new Map();
|
|
71000
71716
|
const releases = /* @__PURE__ */ new Set();
|
|
71001
71717
|
let stateWriter = null;
|
|
71718
|
+
let notifyAddressOverlayHealth = () => {
|
|
71719
|
+
};
|
|
71002
71720
|
const addressOverlay = options.addressOverlay?.enabled === true ? new AddressOverlayController({
|
|
71003
71721
|
window: options.window,
|
|
71004
71722
|
documentUrl: options.addressOverlay.documentUrl,
|
|
71005
71723
|
javascript: options.addressOverlay.list === true,
|
|
71006
71724
|
visible: options.addressOverlay.visible === true,
|
|
71725
|
+
product: options.addressOverlay.product === true,
|
|
71007
71726
|
// The only consumer of a validated row click: the owner window's own
|
|
71008
71727
|
// renderer. Guarded because a stop can race a queued mouse event.
|
|
71009
71728
|
onEvent: (event) => {
|
|
71010
|
-
if (
|
|
71011
|
-
|
|
71012
|
-
|
|
71013
|
-
|
|
71014
|
-
|
|
71015
|
-
}
|
|
71729
|
+
if (options.window.isDestroyed()) return;
|
|
71730
|
+
options.window.webContents.send(
|
|
71731
|
+
options.addressOverlay?.product === true ? PRODUCT_ADDRESS_OVERLAY_EVENT : DEV_DRIVER_ADDRESS_OVERLAY_EVENT,
|
|
71732
|
+
event
|
|
71733
|
+
);
|
|
71016
71734
|
},
|
|
71735
|
+
// The renderer reads Tier 1 out of the projection, so a child that
|
|
71736
|
+
// fails while the field is already raised must push one.
|
|
71737
|
+
onHealthChange: () => notifyAddressOverlayHealth(),
|
|
71017
71738
|
log: log2,
|
|
71018
71739
|
appMetrics: () => electron.app.getAppMetrics().map((metric) => ({
|
|
71019
71740
|
pid: metric.pid,
|
|
@@ -71065,6 +71786,7 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
71065
71786
|
}
|
|
71066
71787
|
captureSession();
|
|
71067
71788
|
};
|
|
71789
|
+
notifyAddressOverlayHealth = notifyChanged;
|
|
71068
71790
|
const registry = new TabRegistry(
|
|
71069
71791
|
(_createOptions, tabId) => {
|
|
71070
71792
|
const view = buildView(options.window);
|
|
@@ -71135,8 +71857,17 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
71135
71857
|
log: log2,
|
|
71136
71858
|
onChanged: notifyChanged,
|
|
71137
71859
|
facts: () => facts,
|
|
71138
|
-
forgetSiteData: (origin) => clearOriginData(browserSession, origin)
|
|
71860
|
+
forgetSiteData: (origin) => clearOriginData(browserSession, origin, historyClearer.current),
|
|
71861
|
+
historyFilePath: path$1.join(options.userDataDir, "browser-history.json"),
|
|
71862
|
+
addressOverlayMode: () => addressOverlay ? addressOverlay.mode() : {
|
|
71863
|
+
mode: "suspend",
|
|
71864
|
+
reason: options.addressOverlay?.product === true ? "unavailable" : "platform"
|
|
71865
|
+
}
|
|
71139
71866
|
});
|
|
71867
|
+
historyClearer.current = {
|
|
71868
|
+
clear: () => host.clearHistory(),
|
|
71869
|
+
clearOrigin: (origin) => host.clearOriginHistory(origin)
|
|
71870
|
+
};
|
|
71140
71871
|
const ownsChrome = () => browserChromeOwnsChord({
|
|
71141
71872
|
logicalFocus: host.chordFocus,
|
|
71142
71873
|
chromeVisible: registry.chromeVisible,
|
|
@@ -71384,6 +72115,7 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
71384
72115
|
...addressOverlay ? { addressOverlay: probeAddressOverlay } : {},
|
|
71385
72116
|
stop: async () => {
|
|
71386
72117
|
detachChords();
|
|
72118
|
+
host.flushHistory();
|
|
71387
72119
|
const atStop = captureTabs(
|
|
71388
72120
|
registry.list(),
|
|
71389
72121
|
registry.activeTab?.tabId ?? null,
|
|
@@ -82715,6 +83447,12 @@ const addressOverlayGate = resolveAddressOverlayGate({
|
|
|
82715
83447
|
windowMode: windowLaunch.mode,
|
|
82716
83448
|
packaged: electron.app.isPackaged
|
|
82717
83449
|
});
|
|
83450
|
+
const addressOverlayProduct = process.platform === "darwin" && !addressOverlayGate.enabled;
|
|
83451
|
+
if (addressOverlayProduct) {
|
|
83452
|
+
console.log(
|
|
83453
|
+
"[address-overlay] product chrome armed (darwin): popout field over the tab strip, native list child"
|
|
83454
|
+
);
|
|
83455
|
+
}
|
|
82718
83456
|
if (addressOverlayGate.asked) {
|
|
82719
83457
|
console.log(
|
|
82720
83458
|
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}`
|
|
@@ -83137,7 +83875,7 @@ electron.app.whenReady().then(async () => {
|
|
|
83137
83875
|
});
|
|
83138
83876
|
const rendererUrl = rendererDocumentUrl();
|
|
83139
83877
|
const consoleCaptureUrl = consoleCaptureUrlFor(rendererUrl);
|
|
83140
|
-
const addressOverlayDocumentUrl = addressOverlayGate.list ? addressListDocumentUrlFor(rendererUrl) : addressOverlayDocumentUrlFor(rendererUrl);
|
|
83878
|
+
const addressOverlayDocumentUrl = addressOverlayGate.list || addressOverlayProduct ? addressListDocumentUrlFor(rendererUrl) : addressOverlayDocumentUrlFor(rendererUrl);
|
|
83141
83879
|
backendService.observeDesktopFeed(
|
|
83142
83880
|
(frame) => {
|
|
83143
83881
|
if (frame.type === "notification") {
|
|
@@ -83948,11 +84686,12 @@ electron.app.whenReady().then(async () => {
|
|
|
83948
84686
|
consoleCaptureUrl,
|
|
83949
84687
|
// S1: only a gated headless probe arm gets this option at all. The
|
|
83950
84688
|
// URL is this app's own packaged document, not a caller's string.
|
|
83951
|
-
...addressOverlayGate.enabled ? {
|
|
84689
|
+
...addressOverlayGate.enabled || addressOverlayProduct ? {
|
|
83952
84690
|
addressOverlay: {
|
|
83953
84691
|
enabled: true,
|
|
83954
|
-
list: addressOverlayGate.list,
|
|
84692
|
+
list: addressOverlayGate.list || addressOverlayProduct,
|
|
83955
84693
|
visible: addressOverlayGate.visible,
|
|
84694
|
+
product: addressOverlayProduct,
|
|
83956
84695
|
documentUrl: addressOverlayDocumentUrl
|
|
83957
84696
|
}
|
|
83958
84697
|
} : {},
|