@quanta-intellect/vessel-browser 0.1.58 → 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
@@ -2683,6 +2683,8 @@ const Channels = {
2683
2683
  DEVTOOLS_PANEL_TOGGLE: "devtools-panel:toggle",
2684
2684
  DEVTOOLS_PANEL_STATE: "devtools-panel:state",
2685
2685
  DEVTOOLS_PANEL_RESIZE: "devtools-panel:resize",
2686
+ // Ad blocking
2687
+ TAB_TOGGLE_AD_BLOCK: "tab:toggle-ad-block",
2686
2688
  // Find in page
2687
2689
  FIND_IN_PAGE_START: "find:start",
2688
2690
  FIND_IN_PAGE_NEXT: "find:next",
@@ -2706,6 +2708,11 @@ const Channels = {
2706
2708
  PREMIUM_RESET: "premium:reset",
2707
2709
  PREMIUM_TRACK_CONTEXT: "premium:track-context",
2708
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",
2709
2716
  // Agent Credential Vault
2710
2717
  VAULT_LIST: "vault:list",
2711
2718
  VAULT_ADD: "vault:add",
@@ -2740,6 +2747,7 @@ const Channels = {
2740
2747
  };
2741
2748
  const MAX_DETAIL_ITEMS = 3;
2742
2749
  const MIN_BLOCK_SIMILARITY = 0.82;
2750
+ const MAX_DIFF_BLOCKS = 500;
2743
2751
  function normalizeText$2(value) {
2744
2752
  return value.replace(/\s+/g, " ").trim();
2745
2753
  }
@@ -2856,8 +2864,10 @@ function diffSnapshots(oldSnap, currentContent, currentTitle, currentHeadings) {
2856
2864
  const oldHeadings = oldSnap.headings.split("\n").filter(Boolean);
2857
2865
  const newHeadings = currentHeadings.split("\n").filter(Boolean);
2858
2866
  if (oldHeadings.join("\n") !== newHeadings.join("\n")) {
2859
- const added = newHeadings.filter((h) => !oldHeadings.includes(h));
2860
- 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));
2861
2871
  const parts = [];
2862
2872
  if (added.length > 0) parts.push(`New: ${added.join(", ")}`);
2863
2873
  if (removed.length > 0) parts.push(`Gone: ${removed.join(", ")}`);
@@ -2871,8 +2881,10 @@ function diffSnapshots(oldSnap, currentContent, currentTitle, currentHeadings) {
2871
2881
  });
2872
2882
  }
2873
2883
  }
2874
- const oldBlocks = extractTextBlocks(oldSnap.textContent);
2875
- 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);
2876
2888
  const overallSimilarity = similarityScore(oldSnap.textContent, currentContent);
2877
2889
  if (overallSimilarity < 0.98) {
2878
2890
  const ops = diffBlocks(oldBlocks, newBlocks);
@@ -3754,7 +3766,7 @@ async function getCheckoutUrl(email) {
3754
3766
  async function getPortalUrl() {
3755
3767
  return {
3756
3768
  ok: false,
3757
- 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."
3758
3770
  };
3759
3771
  }
3760
3772
  async function verifySubscription(identifier) {
@@ -5176,6 +5188,20 @@ const pendingPageSnapshotTimers = /* @__PURE__ */ new Map();
5176
5188
  const pendingPageSnapshotDueAt = /* @__PURE__ */ new Map();
5177
5189
  const lastMutationSnapshotAt = /* @__PURE__ */ new Map();
5178
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
+ }
5179
5205
  const MIN_MUTATION_CAPTURE_INTERVAL_MS = 5e3;
5180
5206
  const SETTLE_AFTER_ACTIVITY_MS = 1500;
5181
5207
  function getLatestPageDiff(rawUrl) {
@@ -5222,6 +5248,7 @@ async function capturePageSnapshot(url, wc, sendToRendererViews) {
5222
5248
  sendToRendererViews(Channels.PAGE_CHANGED, enrichedDiff);
5223
5249
  } else {
5224
5250
  latestPageDiffs.delete(key);
5251
+ recentPageDiffBursts.delete(key);
5225
5252
  }
5226
5253
  } else {
5227
5254
  latestPageDiffs.delete(key);
@@ -5239,6 +5266,7 @@ function computeNextSnapshotDueAt(wcId, now, delayMs) {
5239
5266
  return Math.max(now + delayMs, earliestAllowedAt, stableAfterActivityAt);
5240
5267
  }
5241
5268
  function scheduleTimerAt(wc, sendToRendererViews, dueAt) {
5269
+ attachDestroyCleanup(wc);
5242
5270
  const wcId = wc.id;
5243
5271
  const existing = pendingPageSnapshotTimers.get(wcId);
5244
5272
  if (existing) clearTimeout(existing);
@@ -22820,6 +22848,13 @@ function registerIpcHandlers(windowState, runtime2) {
22820
22848
  flushRuntimeUpdate();
22821
22849
  }, 32);
22822
22850
  };
22851
+ electron.app.on("before-quit", () => {
22852
+ if (runtimeUpdateTimer) {
22853
+ clearTimeout(runtimeUpdateTimer);
22854
+ runtimeUpdateTimer = null;
22855
+ }
22856
+ flushRuntimeUpdate();
22857
+ });
22823
22858
  const sendToRendererViews = (channel, ...args) => {
22824
22859
  chromeView.webContents.send(channel, ...args);
22825
22860
  sidebarView.webContents.send(channel, ...args);
@@ -22944,6 +22979,14 @@ function registerIpcHandlers(windowState, runtime2) {
22944
22979
  electron.ipcMain.handle(Channels.TAB_RELOAD, (_, id) => {
22945
22980
  tabManager.reloadTab(id);
22946
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
+ });
22947
22990
  electron.ipcMain.handle(Channels.TAB_STATE_GET, () => ({
22948
22991
  tabs: tabManager.getAllStates(),
22949
22992
  activeId: tabManager.getActiveTabId() || ""
@@ -23254,17 +23297,29 @@ function registerIpcHandlers(windowState, runtime2) {
23254
23297
  }
23255
23298
  });
23256
23299
  let findWiredWcId = null;
23300
+ let findResultListener = null;
23257
23301
  function wireFindEvents(wc) {
23258
23302
  if (findWiredWcId === wc.id) return;
23259
- if (findWiredWcId !== null) {
23303
+ if (findWiredWcId !== null && findResultListener) {
23260
23304
  const prev = tabManager.findTabByWebContentsId(findWiredWcId);
23261
- 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
+ }
23262
23309
  }
23263
23310
  findWiredWcId = wc.id;
23264
- wc.on("found-in-page", (_event, result) => {
23311
+ const listener = (_event, result) => {
23265
23312
  if (!chromeView.webContents.isDestroyed()) {
23266
23313
  chromeView.webContents.send(Channels.FIND_IN_PAGE_RESULT, result);
23267
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
+ }
23268
23323
  });
23269
23324
  }
23270
23325
  electron.ipcMain.handle(Channels.FIND_IN_PAGE_START, (_, text, options) => {
@@ -23283,6 +23338,7 @@ function registerIpcHandlers(windowState, runtime2) {
23283
23338
  if (!tab) return null;
23284
23339
  const wc = tab.view.webContents;
23285
23340
  if (wc.isDestroyed()) return null;
23341
+ wireFindEvents(wc);
23286
23342
  return wc.findInPage("", { forward: forward ?? true, findNext: true });
23287
23343
  });
23288
23344
  electron.ipcMain.handle(Channels.FIND_IN_PAGE_STOP, (_, action) => {
@@ -23382,6 +23438,21 @@ function registerIpcHandlers(windowState, runtime2) {
23382
23438
  }
23383
23439
  return result;
23384
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
+ });
23385
23456
  registerVaultHandlers();
23386
23457
  registerWindowControlHandlers(mainWindow);
23387
23458
  electron.ipcMain.handle(Channels.AUTOMATION_GET_INSTALLED, () => {
@@ -2212,6 +2212,11 @@ function startPageDiffObserver() {
2212
2212
  emitPageDiffDirty();
2213
2213
  }, PAGE_DIFF_MUTATION_DEBOUNCE_MS);
2214
2214
  });
2215
+ const resetSignature = () => {
2216
+ lastPageDiffSignature = "";
2217
+ };
2218
+ window.addEventListener("popstate", resetSignature);
2219
+ window.addEventListener("hashchange", resetSignature);
2215
2220
  observer.observe(document.documentElement, {
2216
2221
  subtree: true,
2217
2222
  childList: true,
@@ -72,6 +72,8 @@ const Channels = {
72
72
  DEVTOOLS_PANEL_TOGGLE: "devtools-panel:toggle",
73
73
  DEVTOOLS_PANEL_STATE: "devtools-panel:state",
74
74
  DEVTOOLS_PANEL_RESIZE: "devtools-panel:resize",
75
+ // Ad blocking
76
+ TAB_TOGGLE_AD_BLOCK: "tab:toggle-ad-block",
75
77
  // Find in page
76
78
  FIND_IN_PAGE_START: "find:start",
77
79
  FIND_IN_PAGE_NEXT: "find:next",
@@ -82,6 +84,10 @@ const Channels = {
82
84
  HISTORY_SEARCH: "history:search",
83
85
  HISTORY_CLEAR: "history:clear",
84
86
  HISTORY_UPDATE: "history:update",
87
+ // Downloads
88
+ DOWNLOAD_STARTED: "download:started",
89
+ DOWNLOAD_PROGRESS: "download:progress",
90
+ DOWNLOAD_DONE: "download:done",
85
91
  // Premium
86
92
  PREMIUM_GET_STATE: "premium:get-state",
87
93
  PREMIUM_ACTIVATION_START: "premium:activation-start",
@@ -91,6 +97,11 @@ const Channels = {
91
97
  PREMIUM_RESET: "premium:reset",
92
98
  PREMIUM_TRACK_CONTEXT: "premium:track-context",
93
99
  PREMIUM_UPDATE: "premium:update",
100
+ // Named sessions
101
+ SESSION_LIST: "session:list",
102
+ SESSION_SAVE: "session:save",
103
+ SESSION_LOAD: "session:load",
104
+ SESSION_DELETE: "session:delete",
94
105
  // Agent Credential Vault
95
106
  VAULT_LIST: "vault:list",
96
107
  VAULT_ADD: "vault:add",
@@ -129,6 +140,7 @@ const api = {
129
140
  back: (id) => electron.ipcRenderer.invoke(Channels.TAB_BACK, id),
130
141
  forward: (id) => electron.ipcRenderer.invoke(Channels.TAB_FORWARD, id),
131
142
  reload: (id) => electron.ipcRenderer.invoke(Channels.TAB_RELOAD, id),
143
+ toggleAdBlock: (id) => electron.ipcRenderer.invoke(Channels.TAB_TOGGLE_AD_BLOCK, id),
132
144
  getState: () => electron.ipcRenderer.invoke(Channels.TAB_STATE_GET),
133
145
  onStateUpdate: (cb) => {
134
146
  const handler = (_, tabs, activeId) => cb(tabs, activeId);
@@ -315,6 +327,12 @@ const api = {
315
327
  return () => electron.ipcRenderer.removeListener(Channels.PREMIUM_UPDATE, handler);
316
328
  }
317
329
  },
330
+ sessions: {
331
+ list: () => electron.ipcRenderer.invoke(Channels.SESSION_LIST),
332
+ save: (name) => electron.ipcRenderer.invoke(Channels.SESSION_SAVE, name),
333
+ load: (name) => electron.ipcRenderer.invoke(Channels.SESSION_LOAD, name),
334
+ delete: (name) => electron.ipcRenderer.invoke(Channels.SESSION_DELETE, name)
335
+ },
318
336
  vault: {
319
337
  list: () => electron.ipcRenderer.invoke(Channels.VAULT_LIST),
320
338
  add: (entry) => electron.ipcRenderer.invoke(Channels.VAULT_ADD, entry),
@@ -350,6 +368,23 @@ const api = {
350
368
  delete: (id) => electron.ipcRenderer.invoke(Channels.AUTOFILL_DELETE, id),
351
369
  fill: (profileId) => electron.ipcRenderer.invoke(Channels.AUTOFILL_FILL, profileId)
352
370
  },
371
+ downloads: {
372
+ onStarted: (cb) => {
373
+ const handler = (_, info) => cb(info);
374
+ electron.ipcRenderer.on(Channels.DOWNLOAD_STARTED, handler);
375
+ return () => electron.ipcRenderer.removeListener(Channels.DOWNLOAD_STARTED, handler);
376
+ },
377
+ onProgress: (cb) => {
378
+ const handler = (_, info) => cb(info);
379
+ electron.ipcRenderer.on(Channels.DOWNLOAD_PROGRESS, handler);
380
+ return () => electron.ipcRenderer.removeListener(Channels.DOWNLOAD_PROGRESS, handler);
381
+ },
382
+ onDone: (cb) => {
383
+ const handler = (_, info) => cb(info);
384
+ electron.ipcRenderer.on(Channels.DOWNLOAD_DONE, handler);
385
+ return () => electron.ipcRenderer.removeListener(Channels.DOWNLOAD_DONE, handler);
386
+ }
387
+ },
353
388
  pageDiff: {
354
389
  onChanged: (cb) => {
355
390
  const handler = (_, diff) => cb(diff);