@quanta-intellect/vessel-browser 0.1.56 → 0.1.60

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 CHANGED
@@ -1376,6 +1376,10 @@ async function highlightBatchOnPage(wc, entries) {
1376
1376
  }
1377
1377
  const HIGHLIGHT_SELECTOR = "'.__vessel-highlight, .__vessel-highlight-text'";
1378
1378
  async function getHighlightCount(wc) {
1379
+ if (wc.isDestroyed()) return 0;
1380
+ if (wc.isLoading()) return 0;
1381
+ const currentUrl = wc.getURL();
1382
+ if (!currentUrl || currentUrl === "about:blank") return 0;
1379
1383
  return wc.executeJavaScript(
1380
1384
  `document.querySelectorAll(${HIGHLIGHT_SELECTOR}).length`
1381
1385
  );
@@ -2615,7 +2619,9 @@ const Channels = {
2615
2619
  TAB_BACK: "tab:back",
2616
2620
  TAB_FORWARD: "tab:forward",
2617
2621
  TAB_RELOAD: "tab:reload",
2622
+ TAB_STATE_GET: "tab:state-get",
2618
2623
  TAB_STATE_UPDATE: "tab:state-update",
2624
+ RENDERER_VIEW_READY: "renderer:view-ready",
2619
2625
  // AI
2620
2626
  AI_QUERY: "ai:query",
2621
2627
  AI_STREAM_START: "ai:stream-start",
@@ -2677,6 +2683,8 @@ const Channels = {
2677
2683
  DEVTOOLS_PANEL_TOGGLE: "devtools-panel:toggle",
2678
2684
  DEVTOOLS_PANEL_STATE: "devtools-panel:state",
2679
2685
  DEVTOOLS_PANEL_RESIZE: "devtools-panel:resize",
2686
+ // Ad blocking
2687
+ TAB_TOGGLE_AD_BLOCK: "tab:toggle-ad-block",
2680
2688
  // Find in page
2681
2689
  FIND_IN_PAGE_START: "find:start",
2682
2690
  FIND_IN_PAGE_NEXT: "find:next",
@@ -2700,6 +2708,11 @@ const Channels = {
2700
2708
  PREMIUM_RESET: "premium:reset",
2701
2709
  PREMIUM_TRACK_CONTEXT: "premium:track-context",
2702
2710
  PREMIUM_UPDATE: "premium:update",
2711
+ // Named sessions
2712
+ SESSION_LIST: "session:list",
2713
+ SESSION_SAVE: "session:save",
2714
+ SESSION_LOAD: "session:load",
2715
+ SESSION_DELETE: "session:delete",
2703
2716
  // Agent Credential Vault
2704
2717
  VAULT_LIST: "vault:list",
2705
2718
  VAULT_ADD: "vault:add",
@@ -2734,6 +2747,7 @@ const Channels = {
2734
2747
  };
2735
2748
  const MAX_DETAIL_ITEMS = 3;
2736
2749
  const MIN_BLOCK_SIMILARITY = 0.82;
2750
+ const MAX_DIFF_BLOCKS = 500;
2737
2751
  function normalizeText$2(value) {
2738
2752
  return value.replace(/\s+/g, " ").trim();
2739
2753
  }
@@ -2850,8 +2864,10 @@ function diffSnapshots(oldSnap, currentContent, currentTitle, currentHeadings) {
2850
2864
  const oldHeadings = oldSnap.headings.split("\n").filter(Boolean);
2851
2865
  const newHeadings = currentHeadings.split("\n").filter(Boolean);
2852
2866
  if (oldHeadings.join("\n") !== newHeadings.join("\n")) {
2853
- const added = newHeadings.filter((h) => !oldHeadings.includes(h));
2854
- const removed = oldHeadings.filter((h) => !newHeadings.includes(h));
2867
+ const oldSet = new Set(oldHeadings);
2868
+ const newSet = new Set(newHeadings);
2869
+ const added = newHeadings.filter((h) => !oldSet.has(h));
2870
+ const removed = oldHeadings.filter((h) => !newSet.has(h));
2855
2871
  const parts = [];
2856
2872
  if (added.length > 0) parts.push(`New: ${added.join(", ")}`);
2857
2873
  if (removed.length > 0) parts.push(`Gone: ${removed.join(", ")}`);
@@ -2865,8 +2881,10 @@ function diffSnapshots(oldSnap, currentContent, currentTitle, currentHeadings) {
2865
2881
  });
2866
2882
  }
2867
2883
  }
2868
- const oldBlocks = extractTextBlocks(oldSnap.textContent);
2869
- const newBlocks = extractTextBlocks(currentContent);
2884
+ const rawOldBlocks = extractTextBlocks(oldSnap.textContent);
2885
+ const rawNewBlocks = extractTextBlocks(currentContent);
2886
+ const oldBlocks = rawOldBlocks.slice(0, MAX_DIFF_BLOCKS);
2887
+ const newBlocks = rawNewBlocks.slice(0, MAX_DIFF_BLOCKS);
2870
2888
  const overallSimilarity = similarityScore(oldSnap.textContent, currentContent);
2871
2889
  if (overallSimilarity < 0.98) {
2872
2890
  const ops = diffBlocks(oldBlocks, newBlocks);
@@ -3748,7 +3766,7 @@ async function getCheckoutUrl(email) {
3748
3766
  async function getPortalUrl() {
3749
3767
  return {
3750
3768
  ok: false,
3751
- error: "Billing portal access is temporarily disabled while we harden the premium API. Use the Stripe billing link from your subscription email for now."
3769
+ error: "Billing portal access is temporarily disabled until authenticated customer access is implemented."
3752
3770
  };
3753
3771
  }
3754
3772
  async function verifySubscription(identifier) {
@@ -5170,6 +5188,20 @@ const pendingPageSnapshotTimers = /* @__PURE__ */ new Map();
5170
5188
  const pendingPageSnapshotDueAt = /* @__PURE__ */ new Map();
5171
5189
  const lastMutationSnapshotAt = /* @__PURE__ */ new Map();
5172
5190
  const lastMutationActivityAt = /* @__PURE__ */ new Map();
5191
+ const destroyListenerAttached = /* @__PURE__ */ new WeakSet();
5192
+ function attachDestroyCleanup(wc) {
5193
+ if (destroyListenerAttached.has(wc)) return;
5194
+ destroyListenerAttached.add(wc);
5195
+ wc.once("destroyed", () => {
5196
+ const wcId = wc.id;
5197
+ const timer = pendingPageSnapshotTimers.get(wcId);
5198
+ if (timer) clearTimeout(timer);
5199
+ pendingPageSnapshotTimers.delete(wcId);
5200
+ pendingPageSnapshotDueAt.delete(wcId);
5201
+ lastMutationSnapshotAt.delete(wcId);
5202
+ lastMutationActivityAt.delete(wcId);
5203
+ });
5204
+ }
5173
5205
  const MIN_MUTATION_CAPTURE_INTERVAL_MS = 5e3;
5174
5206
  const SETTLE_AFTER_ACTIVITY_MS = 1500;
5175
5207
  function getLatestPageDiff(rawUrl) {
@@ -5216,6 +5248,7 @@ async function capturePageSnapshot(url, wc, sendToRendererViews) {
5216
5248
  sendToRendererViews(Channels.PAGE_CHANGED, enrichedDiff);
5217
5249
  } else {
5218
5250
  latestPageDiffs.delete(key);
5251
+ recentPageDiffBursts.delete(key);
5219
5252
  }
5220
5253
  } else {
5221
5254
  latestPageDiffs.delete(key);
@@ -5233,6 +5266,7 @@ function computeNextSnapshotDueAt(wcId, now, delayMs) {
5233
5266
  return Math.max(now + delayMs, earliestAllowedAt, stableAfterActivityAt);
5234
5267
  }
5235
5268
  function scheduleTimerAt(wc, sendToRendererViews, dueAt) {
5269
+ attachDestroyCleanup(wc);
5236
5270
  const wcId = wc.id;
5237
5271
  const existing = pendingPageSnapshotTimers.get(wcId);
5238
5272
  if (existing) clearTimeout(existing);
@@ -5518,9 +5552,9 @@ function layoutViews(state2) {
5518
5552
  if (uiState.sidebarOpen) {
5519
5553
  sidebarView.setBounds({
5520
5554
  x: width - sidebarWidth - resizeHandleOverlap,
5521
- y: 0,
5555
+ y: chromeHeight,
5522
5556
  width: sidebarWidth + resizeHandleOverlap,
5523
- height
5557
+ height: height - chromeHeight
5524
5558
  });
5525
5559
  } else {
5526
5560
  sidebarView.setBounds({ x: width, y: 0, width: 0, height: 0 });
@@ -22814,6 +22848,13 @@ function registerIpcHandlers(windowState, runtime2) {
22814
22848
  flushRuntimeUpdate();
22815
22849
  }, 32);
22816
22850
  };
22851
+ electron.app.on("before-quit", () => {
22852
+ if (runtimeUpdateTimer) {
22853
+ clearTimeout(runtimeUpdateTimer);
22854
+ runtimeUpdateTimer = null;
22855
+ }
22856
+ flushRuntimeUpdate();
22857
+ });
22817
22858
  const sendToRendererViews = (channel, ...args) => {
22818
22859
  chromeView.webContents.send(channel, ...args);
22819
22860
  sidebarView.webContents.send(channel, ...args);
@@ -22938,6 +22979,18 @@ function registerIpcHandlers(windowState, runtime2) {
22938
22979
  electron.ipcMain.handle(Channels.TAB_RELOAD, (_, id) => {
22939
22980
  tabManager.reloadTab(id);
22940
22981
  });
22982
+ electron.ipcMain.handle(Channels.TAB_TOGGLE_AD_BLOCK, (_, id) => {
22983
+ assertString(id, "id");
22984
+ const tab = tabManager.getTab(id);
22985
+ if (!tab) return null;
22986
+ const newState = !tab.state.adBlockingEnabled;
22987
+ tab.setAdBlockingEnabled(newState);
22988
+ return newState;
22989
+ });
22990
+ electron.ipcMain.handle(Channels.TAB_STATE_GET, () => ({
22991
+ tabs: tabManager.getAllStates(),
22992
+ activeId: tabManager.getActiveTabId() || ""
22993
+ }));
22941
22994
  electron.ipcMain.handle(Channels.AI_QUERY, async (_, query, history) => {
22942
22995
  const settings2 = loadSettings();
22943
22996
  const chatConfig = settings2.chatProvider;
@@ -23049,6 +23102,16 @@ function registerIpcHandlers(windowState, runtime2) {
23049
23102
  setSetting("sidebarWidth", windowState.uiState.sidebarWidth);
23050
23103
  layoutViews(windowState);
23051
23104
  });
23105
+ electron.ipcMain.on(
23106
+ Channels.RENDERER_VIEW_READY,
23107
+ (_event, view) => {
23108
+ if (view !== "sidebar") return;
23109
+ if (!windowState.uiState.sidebarOpen) {
23110
+ windowState.uiState.sidebarOpen = true;
23111
+ layoutViews(windowState);
23112
+ }
23113
+ }
23114
+ );
23052
23115
  electron.ipcMain.handle(Channels.FOCUS_MODE_TOGGLE, () => {
23053
23116
  windowState.uiState.focusMode = !windowState.uiState.focusMode;
23054
23117
  layoutViews(windowState);
@@ -23234,17 +23297,29 @@ function registerIpcHandlers(windowState, runtime2) {
23234
23297
  }
23235
23298
  });
23236
23299
  let findWiredWcId = null;
23300
+ let findResultListener = null;
23237
23301
  function wireFindEvents(wc) {
23238
23302
  if (findWiredWcId === wc.id) return;
23239
- if (findWiredWcId !== null) {
23303
+ if (findWiredWcId !== null && findResultListener) {
23240
23304
  const prev = tabManager.findTabByWebContentsId(findWiredWcId);
23241
- if (prev) prev.view.webContents.removeAllListeners("found-in-page");
23305
+ const prevWc = prev?.view.webContents;
23306
+ if (prevWc && !prevWc.isDestroyed()) {
23307
+ prevWc.removeListener("found-in-page", findResultListener);
23308
+ }
23242
23309
  }
23243
23310
  findWiredWcId = wc.id;
23244
- wc.on("found-in-page", (_event, result) => {
23311
+ const listener = (_event, result) => {
23245
23312
  if (!chromeView.webContents.isDestroyed()) {
23246
23313
  chromeView.webContents.send(Channels.FIND_IN_PAGE_RESULT, result);
23247
23314
  }
23315
+ };
23316
+ findResultListener = listener;
23317
+ wc.on("found-in-page", listener);
23318
+ wc.once("destroyed", () => {
23319
+ if (findWiredWcId === wc.id) {
23320
+ findWiredWcId = null;
23321
+ findResultListener = null;
23322
+ }
23248
23323
  });
23249
23324
  }
23250
23325
  electron.ipcMain.handle(Channels.FIND_IN_PAGE_START, (_, text, options) => {
@@ -23263,6 +23338,7 @@ function registerIpcHandlers(windowState, runtime2) {
23263
23338
  if (!tab) return null;
23264
23339
  const wc = tab.view.webContents;
23265
23340
  if (wc.isDestroyed()) return null;
23341
+ wireFindEvents(wc);
23266
23342
  return wc.findInPage("", { forward: forward ?? true, findNext: true });
23267
23343
  });
23268
23344
  electron.ipcMain.handle(Channels.FIND_IN_PAGE_STOP, (_, action) => {
@@ -23362,6 +23438,21 @@ function registerIpcHandlers(windowState, runtime2) {
23362
23438
  }
23363
23439
  return result;
23364
23440
  });
23441
+ electron.ipcMain.handle(Channels.SESSION_LIST, () => {
23442
+ return listNamedSessions();
23443
+ });
23444
+ electron.ipcMain.handle(Channels.SESSION_SAVE, async (_, name) => {
23445
+ assertString(name, "name");
23446
+ return await saveNamedSession(tabManager, name);
23447
+ });
23448
+ electron.ipcMain.handle(Channels.SESSION_LOAD, async (_, name) => {
23449
+ assertString(name, "name");
23450
+ return await loadNamedSession(tabManager, name);
23451
+ });
23452
+ electron.ipcMain.handle(Channels.SESSION_DELETE, (_, name) => {
23453
+ assertString(name, "name");
23454
+ return deleteNamedSession(name);
23455
+ });
23365
23456
  registerVaultHandlers();
23366
23457
  registerWindowControlHandlers(mainWindow);
23367
23458
  electron.ipcMain.handle(Channels.AUTOMATION_GET_INSTALLED, () => {
@@ -24750,6 +24841,7 @@ async function bootstrap() {
24750
24841
  windowState.mainWindow.show();
24751
24842
  closeSplash(splash, 0);
24752
24843
  };
24844
+ let didInitializeChromeRenderer = false;
24753
24845
  const splashTimeout = setTimeout(() => {
24754
24846
  console.warn("[bootstrap] Renderer did not finish loading before splash timeout");
24755
24847
  revealMainWindow();
@@ -24776,8 +24868,9 @@ async function bootstrap() {
24776
24868
  installDownloadHandler(chromeView);
24777
24869
  startBackgroundRevalidation();
24778
24870
  startTelemetry();
24779
- loadRenderers(chromeView, sidebarView, devtoolsPanelView);
24780
- chromeView.webContents.once("did-finish-load", () => {
24871
+ const initializeChromeRenderer = () => {
24872
+ if (didInitializeChromeRenderer) return;
24873
+ didInitializeChromeRenderer = true;
24781
24874
  const savedSession = runtime.getState().session;
24782
24875
  if (settings2.autoRestoreSession && savedSession?.tabs.length) {
24783
24876
  runtime.restoreSession(savedSession);
@@ -24790,6 +24883,12 @@ async function bootstrap() {
24790
24883
  clearTimeout(splashTimeout);
24791
24884
  revealMainWindow();
24792
24885
  void maybeShowStartupHealthDialog(windowState);
24886
+ };
24887
+ chromeView.webContents.once("dom-ready", () => {
24888
+ initializeChromeRenderer();
24889
+ });
24890
+ chromeView.webContents.once("did-finish-load", () => {
24891
+ initializeChromeRenderer();
24793
24892
  });
24794
24893
  chromeView.webContents.once(
24795
24894
  "did-fail-load",
@@ -24805,6 +24904,7 @@ async function bootstrap() {
24805
24904
  revealMainWindow();
24806
24905
  }
24807
24906
  );
24907
+ loadRenderers(chromeView, sidebarView, devtoolsPanelView);
24808
24908
  startMcpServer(tabManager, runtime, settings2.mcpPort).catch((err) => {
24809
24909
  console.error("[bootstrap] MCP server failed to start:", err);
24810
24910
  });
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  const electron = require("electron");
3
- const channels = require("./chunks/channels-Dfv8z3Ui.js");
4
3
  var Readability = { exports: {} };
5
4
  var hasRequiredReadability$1;
6
5
  function requireReadability$1() {
@@ -2187,11 +2186,11 @@ function emitPageDiffDirty() {
2187
2186
  const nextSignature = getPageDiffSignature();
2188
2187
  if (!nextSignature || nextSignature === lastPageDiffSignature) return;
2189
2188
  lastPageDiffSignature = nextSignature;
2190
- electron.ipcRenderer.send(channels.Channels.PAGE_DIFF_DIRTY);
2189
+ electron.ipcRenderer.send("page:diff-dirty");
2191
2190
  }
2192
2191
  function notifyPageDiffActivity() {
2193
2192
  if (pageDiffActivityThrottleTimer) return;
2194
- electron.ipcRenderer.send(channels.Channels.PAGE_DIFF_ACTIVITY);
2193
+ electron.ipcRenderer.send("page:diff-activity");
2195
2194
  pageDiffActivityThrottleTimer = setTimeout(() => {
2196
2195
  pageDiffActivityThrottleTimer = null;
2197
2196
  }, PAGE_DIFF_ACTIVITY_THROTTLE_MS);
@@ -2213,6 +2212,11 @@ function startPageDiffObserver() {
2213
2212
  emitPageDiffDirty();
2214
2213
  }, PAGE_DIFF_MUTATION_DEBOUNCE_MS);
2215
2214
  });
2215
+ const resetSignature = () => {
2216
+ lastPageDiffSignature = "";
2217
+ };
2218
+ window.addEventListener("popstate", resetSignature);
2219
+ window.addEventListener("hashchange", resetSignature);
2216
2220
  observer.observe(document.documentElement, {
2217
2221
  subtree: true,
2218
2222
  childList: true,