Conversation
|
Caution Review failedFailed to post review comments WalkthroughThis PR implements a major architectural refactor of the Electron app's main process, replacing a centralized Browser singleton pattern with a modular controller-based architecture. It introduces controllers for windows, tabs, profiles, sessions, spaces, menus, and updates, removes the old Browser, WindowManager, and ProfileManager classes, updates all IPC handlers to use the new controllers, and adds platform-specific initialization flows for app lifecycle and onboarding. Changes
Sequence Diagram(s)sequenceDiagram
participant App as Electron App
participant Browser as browser.ts
participant LC as lifecycle
participant Inst as instance
participant Platform as platform
participant Onboarding as onboarding
participant Windows as windows-controller
participant Menus as app-menu
App->>Browser: (import)
Browser->>Browser: processInitialUrl()
Browser->>Inst: setupSecondInstanceHandling()
Browser->>Platform: setupPlatformIntegration()
Browser->>Onboarding: runOnboardingOrInitialWindow()
Onboarding->>Windows: create browser/onboarding window
Browser->>LC: setupAppLifecycle()
LC->>App: on window-all-closed
LC->>App: on ready
LC->>App: on open-url
note over App,Browser: App now runs under<br/>controller-based architecture
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Areas requiring extra attention:
Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Build artifacts for all platforms are ready! 🚀Download the artifacts from: (execution 18892620143 / attempt 1) |
4234e15 to
17ddf49
Compare
…ving initialization flow
…formance optimization
0e3ec48 to
33bfcd1
Compare
…owserWindow class
…oller and related classes
There was a problem hiding this comment.
Actionable comments posted: 89
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (14)
src/main/controllers/sessions-controller/protocols/utils.ts (4)
27-37: Block path traversal; validate resolved path stays within baseDir.
path.joinwith untrustedfilePath/extraDirallows..escapes. Resolve and enforce baseDir containment before reading.- if (extraDir) { - transformedPath = path.join(extraDir, transformedPath); - } - - const fullFilePath = path.join(baseDir, transformedPath); + const base = path.resolve(baseDir); + const joined = extraDir ? path.join(extraDir, transformedPath) : transformedPath; + const fullFilePath = path.resolve(base, joined); + // Ensure the resolved path is inside base + const baseWithSep = base.endsWith(path.sep) ? base : base + path.sep; + if (!(fullFilePath === base || fullFilePath.startsWith(baseWithSep))) { + return new Response("File not found", { status: 404 }); + }
38-46: Hot-reload setup should be idempotent and cheap.
setupHotReloadFileDescriptors()runs on every request in dev mode. Ensure it’s idempotent or move behind a one‑time guard.I can add a simple module‑level
initializedflag in./hot-reloadif needed.
60-65: Optional: add caching headers for static assets.Consider
Cache-Control(e.g.,public, max-age=31536000, immutable) for hashed assets, andno-storefor HTML. This materially improves load times.
49-55: Minor: prefer streaming for large files.For big assets,
fsPromises.readFilebuffers whole files. Afs.createReadStreamorBun.file()Response would reduce memory spikes. If Bun is available per guidelines,return new Response(Bun.file(fullFilePath));Confirm whether the main process runs under Bun in production; if not, keep Node streams.
src/main/controllers/quit-controller/handlers/before-quit.ts (1)
29-37: Simplify promise handling.The
Promise.allwith a single-element array and.every()check are unnecessary for a single promise that already resolves to boolean.Apply this diff:
export function beforeQuit(): boolean | Promise<boolean> { - const flushSessionsDataPromise = flushSessionsData() + return flushSessionsData() .then(() => true) .catch(() => true); - - return Promise.all([flushSessionsDataPromise]).then((results) => { - return results.every((result) => result); - }); }src/main/ipc/app/updates.ts (1)
21-22: Consider logging errors in update check.The empty catch block silently swallows all errors from
checkForUpdates(). This could hide important issues like network failures or invalid update manifests.Consider logging the error:
} catch { + console.error('[Updates] Failed to check for updates:', error); return false; }Or better yet, with the error parameter:
- } catch { + } catch (error) { + console.error('[Updates] Failed to check for updates:', error); return false; }src/main/controllers/windows-controller/utils/close-preventer.ts (1)
11-16: Tidy listener lifecycle and key detection; avoid shadowing
- Don’t shadow the imported webContents; rename param.
- Remove IDs on destroyed to prevent growth.
- Normalize key and ignore auto‑repeat to avoid multiple closes on long press.
-function newWebContents(webContents: WebContents) { +function newWebContents(contents: WebContents) { if (!enabled) return; - if (registeredWebContentIds.has(webContents.id)) return; - registeredWebContentIds.add(webContents.id); + if (registeredWebContentIds.has(contents.id)) return; + registeredWebContentIds.add(contents.id); - webContents.on("before-input-event", (event, input) => { - if (input.key === "w" && input.control) { + contents.on("before-input-event", (event, input) => { + if (input.key?.toLowerCase() === "w" && input.control) { event.preventDefault(); - if (input.type === "keyDown") { + if (input.type === "keyDown" && !input.isAutoRepeat) { menuCloseTab(); } } }); + contents.once("destroyed", () => { + registeredWebContentIds.delete(contents.id); + }); } @@ - app.on("web-contents-created", (_event, webContents) => { - newWebContents(webContents); + app.on("web-contents-created", (_event, contents) => { + newWebContents(contents); });Also applies to: 17-23, 28-39
src/main/controllers/tabs-controller/context-menu.ts (2)
80-84: Dictionary suggestions visibility check may hide valid itemsSome suggestion items may not set .visible; using .some(s => s.visible) can return false when items are usable. Prefer length check.
- const hasDictionarySuggestions = dictionarySuggestions.some((suggestion) => suggestion.visible); - if (hasDictionarySuggestions) { + if (dictionarySuggestions.length > 0) { sections.push(dictionarySuggestions); }
186-191: Remove ts-expect-error by typing extensions context menu APILeaning on @ts-expect-error hides real issues. Add an interface for getContextMenuItems.
// e.g., somewhere in extensions types export interface ExtensionsApi { getContextMenuItems: (wc: Electron.WebContents, params: Electron.ContextMenuParams) => Electron.MenuItemConstructorOptions[]; }Then type loadedProfile.extensions accordingly and drop the ts-expect-error.
src/main/controllers/windows-controller/utils/browser/omnibox.ts (1)
213-219: Cleanup: destroy view and remove map entry to prevent leaksEnsure Omnibox fully cleans up resources.
destroy() { this.assertNotDestroyed(); this.isDestroyed = true; - this.webContents.close(); + const win = this.window; + try { + this.view?.destroy?.(); + } catch {} + try { + if (!this.webContents.isDestroyed()) this.webContents.destroy(); + } catch {} + omniboxes.delete(win); }src/main/controllers/tabs-controller/tab-groups/index.ts (2)
142-147: Undefined windowId can propagate into setWindow().
const newWindowId = tab.getWindow()?.id;may be undefined. The comparison still passes andsetWindow(undefined)throws. Guard before calling.- const newWindowId = tab.getWindow()?.id; - if (newWindowId !== this.windowId) { - this.setWindow(newWindowId); - } + const maybeWindowId = tab.getWindow()?.id; + if (typeof maybeWindowId === "number" && maybeWindowId !== this.windowId) { + this.setWindow(maybeWindowId); + }
211-214: position accessor can throw for empty groups.If all tabs are removed,
this.tabs[0]is undefined. Return a sentinel or throw a clear error.- return this.tabs[0].position; + if (this.tabs.length === 0) throw new Error("TabGroup has no tabs"); + return this.tabs[0].position;src/main/controllers/tabs-controller/tab.ts (1)
270-273: Redundant assignmentthis.setWindow(window) already assigns this.window; the extra set is unnecessary.
Apply:
// Setup window this.setWindow(window); - this.window = window;src/main/controllers/tabs-controller/index.ts (1)
96-149: Create-tab flow is clear; consider friendlier errorsThrown errors bubble to callers. For UX, log and return a structured result or map to IPC error codes; keep throws for truly exceptional states.
If you want, I can add a Result<T, E> style return and update IPC handlers accordingly.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (107)
.vscode/settings.json(1 hunks)electron.vite.config.ts(2 hunks)package.json(2 hunks)src/main/app/instance.ts(1 hunks)src/main/app/lifecycle.ts(1 hunks)src/main/app/onboarding.ts(1 hunks)src/main/app/platform.ts(1 hunks)src/main/app/urls.ts(1 hunks)src/main/browser.ts(1 hunks)src/main/browser/browser.ts(0 hunks)src/main/browser/events.ts(0 hunks)src/main/browser/profile-manager.ts(0 hunks)src/main/browser/utility/intercept-rules.ts(0 hunks)src/main/browser/utility/menu.ts(0 hunks)src/main/browser/utility/menu/helpers.ts(0 hunks)src/main/browser/utility/menu/items/file.ts(0 hunks)src/main/browser/utility/protocols/index.ts(0 hunks)src/main/browser/window-manager.ts(0 hunks)src/main/browser/window.ts(0 hunks)src/main/controllers/README.md(1 hunks)src/main/controllers/app-menu-controller/index.ts(1 hunks)src/main/controllers/app-menu-controller/menu/helpers.ts(1 hunks)src/main/controllers/app-menu-controller/menu/items/app.ts(2 hunks)src/main/controllers/app-menu-controller/menu/items/archive.ts(2 hunks)src/main/controllers/app-menu-controller/menu/items/edit.ts(2 hunks)src/main/controllers/app-menu-controller/menu/items/file.ts(1 hunks)src/main/controllers/app-menu-controller/menu/items/spaces.ts(4 hunks)src/main/controllers/app-menu-controller/menu/items/view.ts(4 hunks)src/main/controllers/auto-update-controller/index.ts(1 hunks)src/main/controllers/default-browser-controller/index.ts(1 hunks)src/main/controllers/index.ts(1 hunks)src/main/controllers/loaded-profiles-controller/index.ts(1 hunks)src/main/controllers/posthog-controller/identify.ts(1 hunks)src/main/controllers/posthog-controller/index.ts(1 hunks)src/main/controllers/posthog-controller/posthog-error-capture-sdk/index.ts(1 hunks)src/main/controllers/profiles-controller/index.ts(1 hunks)src/main/controllers/profiles-controller/raw.ts(1 hunks)src/main/controllers/quit-controller/README.md(1 hunks)src/main/controllers/quit-controller/handlers/before-quit.ts(1 hunks)src/main/controllers/quit-controller/index.ts(1 hunks)src/main/controllers/sessions-controller/README.md(1 hunks)src/main/controllers/sessions-controller/default-session/index.ts(1 hunks)src/main/controllers/sessions-controller/handlers/index.ts(1 hunks)src/main/controllers/sessions-controller/index.ts(1 hunks)src/main/controllers/sessions-controller/intercept-rules/better-pdf-viewer.ts(1 hunks)src/main/controllers/sessions-controller/intercept-rules/cors-bypass-custom-protocols.ts(1 hunks)src/main/controllers/sessions-controller/intercept-rules/index.ts(1 hunks)src/main/controllers/sessions-controller/intercept-rules/user-agent-transformer.ts(1 hunks)src/main/controllers/sessions-controller/preload-scripts/index.ts(1 hunks)src/main/controllers/sessions-controller/protocols/_protocols/flow-external.ts(1 hunks)src/main/controllers/sessions-controller/protocols/_protocols/flow-internal.ts(3 hunks)src/main/controllers/sessions-controller/protocols/_protocols/flow.ts(2 hunks)src/main/controllers/sessions-controller/protocols/hot-reload.ts(2 hunks)src/main/controllers/sessions-controller/protocols/index.ts(1 hunks)src/main/controllers/sessions-controller/protocols/utils.ts(1 hunks)src/main/controllers/sessions-controller/web-requests/index.ts(2 hunks)src/main/controllers/spaces-controller/index.ts(1 hunks)src/main/controllers/spaces-controller/raw.ts(1 hunks)src/main/controllers/tabs-controller/bounds.ts(1 hunks)src/main/controllers/tabs-controller/context-menu.ts(5 hunks)src/main/controllers/tabs-controller/index.ts(12 hunks)src/main/controllers/tabs-controller/tab-groups/glance.ts(1 hunks)src/main/controllers/tabs-controller/tab-groups/index.ts(9 hunks)src/main/controllers/tabs-controller/tab-groups/split.ts(1 hunks)src/main/controllers/tabs-controller/tab.ts(20 hunks)src/main/controllers/windows-controller/README.md(1 hunks)src/main/controllers/windows-controller/index.ts(1 hunks)src/main/controllers/windows-controller/interfaces/browser.ts(1 hunks)src/main/controllers/windows-controller/interfaces/onboarding.ts(1 hunks)src/main/controllers/windows-controller/interfaces/settings.ts(1 hunks)src/main/controllers/windows-controller/type-manager.ts(1 hunks)src/main/controllers/windows-controller/types/base.ts(1 hunks)src/main/controllers/windows-controller/types/browser.ts(1 hunks)src/main/controllers/windows-controller/types/extension-popup.ts(1 hunks)src/main/controllers/windows-controller/types/index.ts(1 hunks)src/main/controllers/windows-controller/types/onboarding.ts(1 hunks)src/main/controllers/windows-controller/types/settings.ts(1 hunks)src/main/controllers/windows-controller/utils/browser/omnibox.ts(4 hunks)src/main/controllers/windows-controller/utils/browser/portal-component-windows.ts(3 hunks)src/main/controllers/windows-controller/utils/close-preventer.ts(2 hunks)src/main/index.ts(2 hunks)src/main/ipc/README.md(1 hunks)src/main/ipc/app/actions.ts(1 hunks)src/main/ipc/app/app.ts(2 hunks)src/main/ipc/app/extensions.ts(7 hunks)src/main/ipc/app/new-tab.ts(1 hunks)src/main/ipc/app/updates.ts(2 hunks)src/main/ipc/browser/browser.ts(1 hunks)src/main/ipc/browser/interface.ts(1 hunks)src/main/ipc/browser/navigation.ts(2 hunks)src/main/ipc/browser/page.ts(2 hunks)src/main/ipc/browser/tabs.ts(11 hunks)src/main/ipc/listeners-manager.ts(1 hunks)src/main/ipc/session/profiles.ts(1 hunks)src/main/ipc/session/spaces.ts(1 hunks)src/main/ipc/window/omnibox.ts(1 hunks)src/main/ipc/window/settings.ts(1 hunks)src/main/modules/auto-update.ts(0 hunks)src/main/modules/content-blocker.ts(4 hunks)src/main/modules/default-browser.ts(0 hunks)src/main/modules/extensions/main.ts(2 hunks)src/main/modules/icons.ts(3 hunks)src/main/modules/output.ts(1 hunks)src/main/modules/pdf-cache.ts(1 hunks)src/main/modules/posthog.ts(0 hunks)src/main/modules/quit-handlers/index.ts(0 hunks)src/main/modules/typed-event-emitter.ts(1 hunks)
⛔ Files not processed due to max files limit (11)
- src/main/modules/utils.ts
- src/main/modules/windows.ts
- src/main/onboarding/main.ts
- src/main/saving/datastore.ts
- src/main/saving/onboarding.ts
- src/main/saving/tabs.ts
- src/main/sessions/profiles.ts
- src/main/sessions/spaces.ts
- src/main/settings/main.ts
- src/preload/index.ts
- src/renderer/src/router/provider.tsx
💤 Files with no reviewable changes (14)
- src/main/browser/events.ts
- src/main/browser/utility/menu.ts
- src/main/browser/utility/intercept-rules.ts
- src/main/modules/auto-update.ts
- src/main/browser/utility/protocols/index.ts
- src/main/browser/window-manager.ts
- src/main/browser/utility/menu/items/file.ts
- src/main/modules/quit-handlers/index.ts
- src/main/modules/default-browser.ts
- src/main/modules/posthog.ts
- src/main/browser/utility/menu/helpers.ts
- src/main/browser/browser.ts
- src/main/browser/window.ts
- src/main/browser/profile-manager.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{js,jsx,ts,tsx}: Usebun <file>instead ofnode <file>orts-node <file>
Bun automatically loads .env, so don't use dotenv.
UseBun.serve()for HTTP servers and WebSockets instead ofexpress.
Usebun:sqlitefor SQLite instead ofbetter-sqlite3.
UseBun.redisfor Redis instead ofioredis.
UseBun.sqlfor Postgres instead ofpgorpostgres.js.
Use built-inWebSocketinstead ofws.
PreferBun.fileovernode:fs's readFile/writeFile.
UseBun.$for shell commands instead of execa.
Files:
src/main/controllers/sessions-controller/preload-scripts/index.tssrc/main/app/lifecycle.tssrc/main/app/instance.tssrc/main/controllers/tabs-controller/bounds.tssrc/main/controllers/windows-controller/types/extension-popup.tssrc/main/controllers/tabs-controller/tab-groups/split.tssrc/main/controllers/sessions-controller/default-session/index.tssrc/main/controllers/posthog-controller/posthog-error-capture-sdk/index.tssrc/main/controllers/app-menu-controller/menu/items/file.tssrc/main/controllers/tabs-controller/tab-groups/glance.tssrc/main/controllers/app-menu-controller/menu/items/archive.tssrc/main/modules/typed-event-emitter.tssrc/main/controllers/sessions-controller/protocols/hot-reload.tssrc/main/controllers/sessions-controller/intercept-rules/cors-bypass-custom-protocols.tssrc/main/controllers/windows-controller/types/settings.tssrc/main/controllers/app-menu-controller/index.tssrc/main/ipc/listeners-manager.tssrc/main/controllers/sessions-controller/web-requests/index.tssrc/main/controllers/quit-controller/index.tssrc/main/controllers/sessions-controller/handlers/index.tssrc/main/controllers/sessions-controller/intercept-rules/index.tssrc/main/controllers/windows-controller/index.tssrc/main/app/urls.tssrc/main/ipc/browser/tabs.tssrc/main/controllers/windows-controller/utils/close-preventer.tssrc/main/controllers/app-menu-controller/menu/items/spaces.tssrc/main/modules/output.tssrc/main/controllers/windows-controller/utils/browser/portal-component-windows.tssrc/main/controllers/windows-controller/interfaces/settings.tssrc/main/ipc/app/new-tab.tssrc/main/controllers/sessions-controller/protocols/_protocols/flow.tssrc/main/controllers/index.tssrc/main/controllers/sessions-controller/intercept-rules/user-agent-transformer.tssrc/main/modules/pdf-cache.tssrc/main/controllers/sessions-controller/intercept-rules/better-pdf-viewer.tssrc/main/controllers/windows-controller/types/index.tselectron.vite.config.tssrc/main/ipc/browser/browser.tssrc/main/controllers/sessions-controller/protocols/_protocols/flow-external.tssrc/main/controllers/default-browser-controller/index.tssrc/main/controllers/profiles-controller/raw.tssrc/main/ipc/browser/interface.tssrc/main/ipc/browser/page.tssrc/main/app/platform.tssrc/main/controllers/tabs-controller/context-menu.tssrc/main/controllers/loaded-profiles-controller/index.tssrc/main/controllers/sessions-controller/index.tssrc/main/controllers/spaces-controller/raw.tssrc/main/controllers/posthog-controller/identify.tssrc/main/ipc/window/omnibox.tssrc/main/ipc/window/settings.tssrc/main/controllers/windows-controller/interfaces/onboarding.tssrc/main/controllers/windows-controller/types/onboarding.tssrc/main/controllers/app-menu-controller/menu/items/edit.tssrc/main/ipc/app/extensions.tssrc/main/controllers/sessions-controller/protocols/index.tssrc/main/controllers/windows-controller/interfaces/browser.tssrc/main/controllers/app-menu-controller/menu/items/view.tssrc/main/modules/extensions/main.tssrc/main/browser.tssrc/main/controllers/windows-controller/type-manager.tssrc/main/controllers/spaces-controller/index.tssrc/main/app/onboarding.tssrc/main/controllers/tabs-controller/tab-groups/index.tssrc/main/ipc/app/updates.tssrc/main/controllers/quit-controller/handlers/before-quit.tssrc/main/controllers/tabs-controller/tab.tssrc/main/controllers/profiles-controller/index.tssrc/main/ipc/session/profiles.tssrc/main/modules/content-blocker.tssrc/main/ipc/app/app.tssrc/main/controllers/windows-controller/types/base.tssrc/main/controllers/posthog-controller/index.tssrc/main/controllers/sessions-controller/protocols/utils.tssrc/main/controllers/windows-controller/types/browser.tssrc/main/ipc/session/spaces.tssrc/main/controllers/auto-update-controller/index.tssrc/main/controllers/app-menu-controller/menu/helpers.tssrc/main/ipc/app/actions.tssrc/main/controllers/sessions-controller/protocols/_protocols/flow-internal.tssrc/main/index.tssrc/main/modules/icons.tssrc/main/controllers/app-menu-controller/menu/items/app.tssrc/main/ipc/browser/navigation.tssrc/main/controllers/tabs-controller/index.tssrc/main/controllers/windows-controller/utils/browser/omnibox.ts
**/*.{html,ts,css}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file.html|file.ts|file.css>instead ofwebpackoresbuild
Files:
src/main/controllers/sessions-controller/preload-scripts/index.tssrc/main/app/lifecycle.tssrc/main/app/instance.tssrc/main/controllers/tabs-controller/bounds.tssrc/main/controllers/windows-controller/types/extension-popup.tssrc/main/controllers/tabs-controller/tab-groups/split.tssrc/main/controllers/sessions-controller/default-session/index.tssrc/main/controllers/posthog-controller/posthog-error-capture-sdk/index.tssrc/main/controllers/app-menu-controller/menu/items/file.tssrc/main/controllers/tabs-controller/tab-groups/glance.tssrc/main/controllers/app-menu-controller/menu/items/archive.tssrc/main/modules/typed-event-emitter.tssrc/main/controllers/sessions-controller/protocols/hot-reload.tssrc/main/controllers/sessions-controller/intercept-rules/cors-bypass-custom-protocols.tssrc/main/controllers/windows-controller/types/settings.tssrc/main/controllers/app-menu-controller/index.tssrc/main/ipc/listeners-manager.tssrc/main/controllers/sessions-controller/web-requests/index.tssrc/main/controllers/quit-controller/index.tssrc/main/controllers/sessions-controller/handlers/index.tssrc/main/controllers/sessions-controller/intercept-rules/index.tssrc/main/controllers/windows-controller/index.tssrc/main/app/urls.tssrc/main/ipc/browser/tabs.tssrc/main/controllers/windows-controller/utils/close-preventer.tssrc/main/controllers/app-menu-controller/menu/items/spaces.tssrc/main/modules/output.tssrc/main/controllers/windows-controller/utils/browser/portal-component-windows.tssrc/main/controllers/windows-controller/interfaces/settings.tssrc/main/ipc/app/new-tab.tssrc/main/controllers/sessions-controller/protocols/_protocols/flow.tssrc/main/controllers/index.tssrc/main/controllers/sessions-controller/intercept-rules/user-agent-transformer.tssrc/main/modules/pdf-cache.tssrc/main/controllers/sessions-controller/intercept-rules/better-pdf-viewer.tssrc/main/controllers/windows-controller/types/index.tselectron.vite.config.tssrc/main/ipc/browser/browser.tssrc/main/controllers/sessions-controller/protocols/_protocols/flow-external.tssrc/main/controllers/default-browser-controller/index.tssrc/main/controllers/profiles-controller/raw.tssrc/main/ipc/browser/interface.tssrc/main/ipc/browser/page.tssrc/main/app/platform.tssrc/main/controllers/tabs-controller/context-menu.tssrc/main/controllers/loaded-profiles-controller/index.tssrc/main/controllers/sessions-controller/index.tssrc/main/controllers/spaces-controller/raw.tssrc/main/controllers/posthog-controller/identify.tssrc/main/ipc/window/omnibox.tssrc/main/ipc/window/settings.tssrc/main/controllers/windows-controller/interfaces/onboarding.tssrc/main/controllers/windows-controller/types/onboarding.tssrc/main/controllers/app-menu-controller/menu/items/edit.tssrc/main/ipc/app/extensions.tssrc/main/controllers/sessions-controller/protocols/index.tssrc/main/controllers/windows-controller/interfaces/browser.tssrc/main/controllers/app-menu-controller/menu/items/view.tssrc/main/modules/extensions/main.tssrc/main/browser.tssrc/main/controllers/windows-controller/type-manager.tssrc/main/controllers/spaces-controller/index.tssrc/main/app/onboarding.tssrc/main/controllers/tabs-controller/tab-groups/index.tssrc/main/ipc/app/updates.tssrc/main/controllers/quit-controller/handlers/before-quit.tssrc/main/controllers/tabs-controller/tab.tssrc/main/controllers/profiles-controller/index.tssrc/main/ipc/session/profiles.tssrc/main/modules/content-blocker.tssrc/main/ipc/app/app.tssrc/main/controllers/windows-controller/types/base.tssrc/main/controllers/posthog-controller/index.tssrc/main/controllers/sessions-controller/protocols/utils.tssrc/main/controllers/windows-controller/types/browser.tssrc/main/ipc/session/spaces.tssrc/main/controllers/auto-update-controller/index.tssrc/main/controllers/app-menu-controller/menu/helpers.tssrc/main/ipc/app/actions.tssrc/main/controllers/sessions-controller/protocols/_protocols/flow-internal.tssrc/main/index.tssrc/main/modules/icons.tssrc/main/controllers/app-menu-controller/menu/items/app.tssrc/main/ipc/browser/navigation.tssrc/main/controllers/tabs-controller/index.tssrc/main/controllers/windows-controller/utils/browser/omnibox.ts
package.json
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
package.json: Usebun installinstead ofnpm installoryarn installorpnpm install
Usebun run <script>instead ofnpm run <script>oryarn run <script>orpnpm run <script>
Files:
package.json
🧠 Learnings (2)
📚 Learning: 2025-07-24T08:49:07.217Z
Learnt from: CR
PR: MultiboxLabs/flow-browser#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-07-24T08:49:07.217Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use `bun <file>` instead of `node <file>` or `ts-node <file>`
Applied to files:
package.json
📚 Learning: 2025-03-21T23:17:56.301Z
Learnt from: iamEvanYT
PR: MultiboxLabs/flow-browser#2
File: electron/browser/menu.ts:36-47
Timestamp: 2025-03-21T23:17:56.301Z
Learning: The `setOmniboxBounds` function accepts `null` as a valid argument, which means "use the default bounds" rather than requiring explicit bounds.
Applied to files:
src/main/controllers/windows-controller/utils/browser/omnibox.ts
🧬 Code graph analysis (66)
src/main/controllers/sessions-controller/preload-scripts/index.ts (1)
src/main/modules/paths.ts (1)
PATHS(18-23)
src/main/app/lifecycle.ts (3)
src/main/saving/onboarding.ts (1)
hasCompletedOnboarding(9-12)src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/app/urls.ts (1)
handleOpenUrl(15-30)
src/main/app/instance.ts (2)
src/main/app/urls.ts (2)
isValidOpenerUrl(5-13)handleOpenUrl(15-30)src/main/modules/output.ts (1)
debugPrint(29-35)
src/main/controllers/sessions-controller/default-session/index.ts (5)
src/main/controllers/sessions-controller/protocols/index.ts (1)
registerProtocolsWithSession(24-36)src/main/controllers/sessions-controller/intercept-rules/index.ts (1)
setupInterceptRules(7-16)src/main/controllers/sessions-controller/preload-scripts/index.ts (1)
registerPreloadScripts(4-10)src/main/controllers/sessions-controller/index.ts (1)
isDefaultSessionReady(51-53)src/main/modules/utils.ts (1)
sleep(65-67)
src/main/controllers/app-menu-controller/menu/items/file.ts (4)
src/main/modules/shortcuts.ts (1)
getCurrentShortcut(107-111)src/main/controllers/app-menu-controller/menu/helpers.ts (1)
getFocusedBrowserWindow(10-19)src/main/ipc/app/new-tab.ts (1)
openNewTab(8-30)src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)
src/main/controllers/app-menu-controller/menu/items/archive.ts (2)
src/main/modules/shortcuts.ts (1)
getCurrentShortcut(107-111)src/main/controllers/app-menu-controller/menu/helpers.ts (1)
getTabWcFromFocusedWindow(49-53)
src/main/controllers/sessions-controller/protocols/hot-reload.ts (1)
src/main/modules/utils.ts (1)
sleep(65-67)
src/main/controllers/sessions-controller/intercept-rules/cors-bypass-custom-protocols.ts (1)
src/main/controllers/sessions-controller/web-requests/index.ts (1)
createBetterWebRequest(675-780)
src/main/controllers/windows-controller/types/settings.ts (1)
src/main/controllers/windows-controller/types/base.ts (1)
BaseWindow(14-115)
src/main/controllers/app-menu-controller/index.ts (4)
src/main/controllers/spaces-controller/index.ts (1)
spacesController(229-229)src/main/saving/shortcuts.ts (1)
shortcutsEmitter(18-18)src/main/controllers/windows-controller/index.ts (1)
windowsController(110-110)src/main/controllers/app-menu-controller/menu/items/spaces.ts (1)
createSpacesMenu(144-198)
src/main/controllers/quit-controller/index.ts (2)
src/main/controllers/quit-controller/handlers/can-quit.ts (1)
canQuit(2-4)src/main/controllers/quit-controller/handlers/before-quit.ts (1)
beforeQuit(29-37)
src/main/controllers/sessions-controller/intercept-rules/index.ts (4)
src/main/controllers/sessions-controller/intercept-rules/user-agent-transformer.ts (1)
setupUserAgentTransformer(5-32)src/main/controllers/sessions-controller/intercept-rules/cors-bypass-custom-protocols.ts (1)
setupCorsBypassForCustomProtocols(8-36)src/main/controllers/sessions-controller/intercept-rules/better-pdf-viewer.ts (1)
setupBetterPdfViewer(7-56)src/main/browser/utility/intercept-rules.ts (1)
setupInterceptRules(120-129)
src/main/controllers/windows-controller/index.ts (4)
src/main/controllers/windows-controller/types/base.ts (2)
id(37-39)BaseWindow(14-115)src/main/modules/typed-event-emitter.ts (1)
TypedEventEmitter(11-114)src/main/controllers/windows-controller/type-manager.ts (1)
WindowTypeManager(13-115)src/main/modules/output.ts (1)
debugPrint(29-35)
src/main/app/urls.ts (3)
src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/controllers/tabs-controller/index.ts (1)
tabsController(758-758)src/main/modules/output.ts (1)
debugPrint(29-35)
src/main/ipc/browser/tabs.ts (5)
src/main/controllers/windows-controller/types/browser.ts (1)
BrowserWindow(31-183)src/main/controllers/tabs-controller/index.ts (1)
tabsController(758-758)src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/controllers/spaces-controller/index.ts (1)
spacesController(229-229)src/main/controllers/tabs-controller/tab.ts (1)
Tab(115-989)
src/main/controllers/windows-controller/utils/close-preventer.ts (1)
src/main/controllers/app-menu-controller/menu/items/view.ts (1)
menuCloseTab(7-27)
src/main/controllers/app-menu-controller/menu/items/spaces.ts (4)
src/main/controllers/app-menu-controller/menu/helpers.ts (1)
getFocusedBrowserWindow(10-19)src/main/ipc/session/spaces.ts (1)
setWindowSpace(52-55)src/main/controllers/spaces-controller/index.ts (1)
spacesController(229-229)src/main/controllers/windows-controller/index.ts (2)
windowsController(110-110)browserWindowsManager(111-111)
src/main/controllers/windows-controller/utils/browser/portal-component-windows.ts (1)
src/main/controllers/windows-controller/types/browser.ts (1)
BrowserWindow(31-183)
src/main/controllers/windows-controller/interfaces/settings.ts (1)
src/main/controllers/windows-controller/index.ts (1)
windowsController(110-110)
src/main/ipc/app/new-tab.ts (5)
src/main/controllers/windows-controller/types/browser.ts (1)
BrowserWindow(31-183)src/main/saving/settings.ts (1)
getSettingValueById(54-56)src/main/controllers/spaces-controller/index.ts (1)
spacesController(229-229)src/main/controllers/tabs-controller/index.ts (1)
tabsController(758-758)src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)
src/main/controllers/sessions-controller/protocols/_protocols/flow.ts (1)
src/main/controllers/loaded-profiles-controller/index.ts (1)
loadedProfilesController(325-325)
src/main/controllers/sessions-controller/intercept-rules/user-agent-transformer.ts (2)
src/main/controllers/sessions-controller/web-requests/index.ts (1)
createBetterWebRequest(675-780)src/main/modules/user-agent.ts (1)
transformUserAgentHeader(6-48)
src/main/controllers/sessions-controller/intercept-rules/better-pdf-viewer.ts (4)
src/main/controllers/sessions-controller/web-requests/index.ts (1)
createBetterWebRequest(675-780)src/main/saving/settings.ts (1)
getSettingValueById(54-56)src/main/modules/utils.ts (1)
generateID(73-75)src/main/modules/pdf-cache.ts (1)
addPdfResponseToCache(8-10)
src/main/ipc/browser/browser.ts (2)
src/main/controllers/loaded-profiles-controller/index.ts (1)
loadedProfilesController(325-325)src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)
src/main/controllers/default-browser-controller/index.ts (1)
src/main/controllers/default-browser-controller/windows-handler.ts (1)
registerAppForCurrentUserOnWindows(48-144)
src/main/controllers/profiles-controller/raw.ts (6)
src/main/modules/paths.ts (1)
FLOW_DATA_DIR(16-16)src/main/controllers/profiles-controller/index.ts (1)
profilesController(182-182)src/main/saving/datastore.ts (2)
getDatastore(310-324)DataStoreData(14-14)src/main/modules/utils.ts (2)
getCurrentTimestamp(92-94)getAllDirectories(101-108)src/main/modules/output.ts (1)
debugError(37-45)src/main/controllers/spaces-controller/index.ts (1)
spacesController(229-229)
src/main/ipc/browser/interface.ts (2)
src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/controllers/windows-controller/types/browser.ts (1)
BrowserWindow(31-183)
src/main/ipc/browser/page.ts (1)
src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)
src/main/app/platform.ts (2)
src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/modules/output.ts (1)
debugPrint(29-35)
src/main/controllers/tabs-controller/context-menu.ts (3)
src/main/controllers/tabs-controller/index.ts (2)
tabsController(758-758)TabsController(757-757)src/main/controllers/tabs-controller/tab.ts (1)
Tab(115-989)src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)
src/main/controllers/loaded-profiles-controller/index.ts (10)
src/main/modules/extensions/management.ts (1)
ExtensionManager(153-466)src/main/modules/typed-event-emitter.ts (1)
TypedEventEmitter(11-114)src/main/controllers/profiles-controller/index.ts (1)
profilesController(182-182)src/main/controllers/sessions-controller/index.ts (1)
sessionsController(59-59)src/main/modules/user-agent.ts (1)
transformUserAgentHeader(6-48)src/main/controllers/tabs-controller/index.ts (2)
tabsController(758-758)NEW_TAB_URL(15-15)src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/ipc/session/spaces.ts (1)
setWindowSpace(52-55)src/main/controllers/windows-controller/index.ts (1)
windowsController(110-110)src/main/saving/settings.ts (1)
getSettingValueById(54-56)
src/main/controllers/sessions-controller/index.ts (7)
src/main/controllers/profiles-controller/index.ts (1)
profilesController(182-182)src/main/controllers/sessions-controller/protocols/index.ts (1)
registerProtocolsWithSession(24-36)src/main/controllers/sessions-controller/handlers/index.ts (1)
registerHandlersWithSession(5-55)src/main/controllers/sessions-controller/preload-scripts/index.ts (1)
registerPreloadScripts(4-10)src/main/controllers/sessions-controller/intercept-rules/index.ts (1)
setupInterceptRules(7-16)src/main/controllers/sessions-controller/default-session/index.ts (2)
isDefaultSessionReady(16-16)defaultSessionReady(18-26)src/main/controllers/sessions-controller/web-requests/index.ts (2)
createBetterWebRequest(675-780)createBetterSession(785-823)
src/main/controllers/spaces-controller/raw.ts (5)
src/main/controllers/spaces-controller/index.ts (1)
spacesController(229-229)src/main/saving/datastore.ts (2)
getDatastore(310-324)DataStoreData(14-14)src/main/modules/output.ts (1)
debugError(37-45)src/main/controllers/profiles-controller/index.ts (1)
profilesController(182-182)src/main/modules/utils.ts (1)
getAllDirectories(101-108)
src/main/controllers/posthog-controller/identify.ts (1)
src/main/saving/settings.ts (1)
SettingsDataStore(7-7)
src/main/ipc/window/omnibox.ts (2)
src/main/modules/output.ts (1)
debugPrint(29-35)src/main/controllers/windows-controller/index.ts (2)
windowsController(110-110)browserWindowsManager(111-111)
src/main/controllers/windows-controller/interfaces/onboarding.ts (1)
src/main/controllers/windows-controller/index.ts (1)
windowsController(110-110)
src/main/controllers/app-menu-controller/menu/items/edit.ts (2)
src/main/controllers/app-menu-controller/menu/helpers.ts (1)
getFocusedBrowserWindow(10-19)src/main/ipc/app/actions.ts (1)
fireCopyLinkAction(4-6)
src/main/ipc/app/extensions.ts (3)
src/main/controllers/loaded-profiles-controller/index.ts (1)
loadedProfilesController(325-325)src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/controllers/spaces-controller/index.ts (1)
spacesController(229-229)
src/main/controllers/sessions-controller/protocols/index.ts (3)
src/main/controllers/sessions-controller/protocols/_protocols/flow.ts (1)
registerFlowProtocol(22-165)src/main/controllers/sessions-controller/protocols/_protocols/flow-internal.ts (1)
registerFlowInternalProtocol(26-98)src/main/controllers/sessions-controller/protocols/_protocols/flow-external.ts (1)
registerFlowExternalProtocol(15-36)
src/main/controllers/windows-controller/interfaces/browser.ts (4)
src/main/controllers/windows-controller/index.ts (2)
browserWindowsManager(111-111)windowsController(110-110)src/main/modules/output.ts (1)
debugPrint(29-35)src/main/modules/electron-components.ts (1)
waitForElectronComponentsToBeReady(1-15)src/main/controllers/windows-controller/types/browser.ts (2)
BrowserWindowType(14-14)BrowserWindowCreationOptions(16-21)
src/main/controllers/app-menu-controller/menu/items/view.ts (4)
src/main/controllers/app-menu-controller/menu/helpers.ts (4)
getFocusedWindow(6-8)getTab(21-35)getFocusedBrowserWindow(10-19)getTabWcFromFocusedWindow(49-53)src/main/controllers/windows-controller/index.ts (1)
browserWindowsManager(111-111)src/main/modules/shortcuts.ts (1)
getCurrentShortcut(107-111)src/main/ipc/browser/interface.ts (1)
toggleSidebar(20-22)
src/main/modules/extensions/main.ts (1)
src/main/controllers/sessions-controller/index.ts (1)
sessionsController(59-59)
src/main/browser.ts (5)
src/main/app/urls.ts (1)
processInitialUrl(32-39)src/main/app/instance.ts (1)
setupSecondInstanceHandling(9-19)src/main/app/platform.ts (1)
setupPlatformIntegration(44-52)src/main/app/onboarding.ts (1)
runOnboardingOrInitialWindow(6-18)src/main/app/lifecycle.ts (1)
setupAppLifecycle(6-31)
src/main/controllers/windows-controller/type-manager.ts (2)
src/main/controllers/windows-controller/types/base.ts (2)
BaseWindow(14-115)id(37-39)src/main/controllers/windows-controller/index.ts (3)
WindowsController(109-109)WindowType(14-14)windowsController(110-110)
src/main/controllers/spaces-controller/index.ts (5)
src/main/controllers/spaces-controller/raw.ts (2)
SpaceData(37-37)RawSpacesController(62-197)src/main/modules/typed-event-emitter.ts (1)
TypedEventEmitter(11-114)src/main/modules/utils.ts (1)
generateID(73-75)src/main/controllers/profiles-controller/index.ts (1)
profilesController(182-182)src/main/modules/output.ts (1)
debugError(37-45)
src/main/app/onboarding.ts (4)
src/main/modules/output.ts (1)
debugPrint(29-35)src/main/saving/onboarding.ts (1)
hasCompletedOnboarding(9-12)src/main/controllers/windows-controller/interfaces/onboarding.ts (1)
onboarding(6-34)src/main/saving/tabs.ts (1)
createInitialWindow(153-163)
src/main/ipc/app/updates.ts (3)
src/main/controllers/auto-update-controller/index.ts (1)
autoUpdateController(217-217)src/shared/types/updates.ts (1)
UpdateStatus(3-7)src/main/ipc/listeners-manager.ts (1)
sendMessageToListeners(35-44)
src/main/controllers/quit-controller/handlers/before-quit.ts (1)
src/main/controllers/loaded-profiles-controller/index.ts (1)
loadedProfilesController(325-325)
src/main/controllers/tabs-controller/tab.ts (5)
src/main/modules/utils.ts (1)
getCurrentTimestamp(92-94)src/main/controllers/tabs-controller/context-menu.ts (1)
createTabContextMenu(33-126)src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/ipc/session/spaces.ts (1)
setWindowSpace(52-55)src/main/controllers/tabs-controller/tab-groups/glance.ts (1)
GlanceTabGroup(3-21)
src/main/controllers/profiles-controller/index.ts (4)
src/main/controllers/profiles-controller/raw.ts (2)
ProfileData(37-37)RawProfilesController(57-171)src/main/modules/typed-event-emitter.ts (1)
TypedEventEmitter(11-114)src/main/modules/utils.ts (1)
generateID(73-75)src/main/modules/output.ts (1)
debugError(37-45)
src/main/ipc/session/profiles.ts (4)
src/main/controllers/profiles-controller/index.ts (2)
profilesController(182-182)ProfileData(21-21)src/main/controllers/profiles-controller/raw.ts (1)
ProfileData(37-37)src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/controllers/spaces-controller/index.ts (1)
spacesController(229-229)
src/main/modules/content-blocker.ts (3)
src/main/controllers/sessions-controller/index.ts (1)
unifiedWebRequests(61-64)src/main/saving/settings.ts (1)
getSettingValueById(54-56)src/main/controllers/loaded-profiles-controller/index.ts (1)
loadedProfilesController(325-325)
src/main/ipc/app/app.ts (1)
src/main/controllers/default-browser-controller/index.ts (1)
defaultBrowserController(46-46)
src/main/controllers/windows-controller/types/base.ts (4)
src/main/modules/typed-event-emitter.ts (1)
TypedEventEmitter(11-114)src/main/controllers/windows-controller/index.ts (1)
WindowType(14-14)src/main/controllers/windows-controller/types/browser.ts (1)
BrowserWindow(31-183)src/main/ipc/listeners-manager.ts (1)
sendMessageToListenersWithWebContents(46-61)
src/main/controllers/posthog-controller/index.ts (2)
src/main/controllers/posthog-controller/posthog-error-capture-sdk/index.ts (1)
ErrorTracking(12-74)src/main/controllers/posthog-controller/identify.ts (1)
_getPosthogIdentifier(12-17)
src/main/controllers/windows-controller/types/browser.ts (11)
src/main/controllers/windows-controller/types/base.ts (2)
BaseWindow(14-115)BaseWindowEvents(6-8)src/main/ipc/browser/page.ts (1)
PageBounds(4-9)src/main/controllers/windows-controller/utils/view-manager.ts (1)
ViewManager(3-87)src/main/controllers/windows-controller/utils/browser/omnibox.ts (1)
Omnibox(10-238)src/main/controllers/sessions-controller/index.ts (1)
sessionsController(59-59)src/main/ipc/browser/interface.ts (1)
fireWindowStateChanged(105-107)src/main/controllers/spaces-controller/index.ts (1)
spacesController(229-229)src/main/controllers/windows-controller/utils/browser/portal-component-windows.ts (1)
initializePortalComponentWindows(8-102)src/main/ipc/listeners-manager.ts (1)
sendMessageToListenersWithWebContents(46-61)src/main/controllers/tabs-controller/index.ts (1)
tabsController(758-758)src/main/controllers/app-menu-controller/index.ts (1)
appMenuController(48-48)
src/main/ipc/session/spaces.ts (4)
src/main/controllers/spaces-controller/index.ts (3)
spacesController(229-229)SpaceData(23-23)SpaceOrderMap(11-11)src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/controllers/windows-controller/types/browser.ts (1)
BrowserWindow(31-183)src/main/ipc/listeners-manager.ts (1)
sendMessageToListeners(35-44)
src/main/controllers/auto-update-controller/index.ts (6)
src/renderer/src/components/main/platform.tsx (1)
Platform(6-6)src/main/modules/typed-event-emitter.ts (1)
TypedEventEmitter(11-114)src/main/modules/output.ts (1)
debugPrint(29-35)src/main/modules/utils.ts (1)
sleep(65-67)src/shared/types/updates.ts (1)
UpdateStatus(3-7)src/main/saving/settings.ts (3)
getSettingValueById(54-56)onSettingsCached(51-51)settingsEmitter(12-12)
src/main/controllers/app-menu-controller/menu/helpers.ts (3)
src/main/controllers/windows-controller/index.ts (2)
windowsController(110-110)browserWindowsManager(111-111)src/main/controllers/windows-controller/types/base.ts (1)
BaseWindow(14-115)src/main/controllers/tabs-controller/index.ts (1)
tabsController(758-758)
src/main/ipc/app/actions.ts (1)
src/main/controllers/windows-controller/types/browser.ts (1)
BrowserWindow(31-183)
src/main/controllers/sessions-controller/protocols/_protocols/flow-internal.ts (1)
src/main/controllers/tabs-controller/index.ts (1)
tabsController(758-758)
src/main/modules/icons.ts (2)
src/main/controllers/windows-controller/index.ts (1)
windowsController(110-110)src/main/controllers/windows-controller/types/base.ts (1)
id(37-39)
src/main/controllers/app-menu-controller/menu/items/app.ts (1)
src/main/controllers/default-browser-controller/index.ts (1)
defaultBrowserController(46-46)
src/main/ipc/browser/navigation.ts (2)
src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/controllers/tabs-controller/index.ts (1)
tabsController(758-758)
src/main/controllers/tabs-controller/index.ts (8)
src/main/modules/typed-event-emitter.ts (1)
TypedEventEmitter(11-114)src/main/controllers/tabs-controller/tab.ts (1)
Tab(115-989)src/main/controllers/tabs-controller/tab-groups/index.ts (1)
TabGroup(26-26)src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/controllers/spaces-controller/index.ts (1)
spacesController(229-229)src/main/controllers/loaded-profiles-controller/index.ts (1)
loadedProfilesController(325-325)src/main/controllers/tabs-controller/tab-groups/glance.ts (1)
GlanceTabGroup(3-21)src/main/controllers/tabs-controller/tab-groups/split.ts (1)
SplitTabGroup(3-7)
src/main/controllers/windows-controller/utils/browser/omnibox.ts (2)
src/main/controllers/windows-controller/interfaces/browser.ts (1)
browserWindowsController(30-86)src/main/modules/output.ts (1)
debugPrint(29-35)
🪛 LanguageTool
src/main/controllers/sessions-controller/README.md
[style] ~17-~17: This phrase is redundant. Consider using “outside”.
Context: ... The only thing that should be required outside of this controller is the index.ts file....
(OUTSIDE_OF)
[style] ~18-~18: This phrase is redundant. Consider using “outside”.
Context: ...les are internal and should not be used outside of this controller.
(OUTSIDE_OF)
src/main/controllers/quit-controller/README.md
[style] ~12-~12: This phrase is redundant. Consider using “outside”.
Context: ... The only thing that should be required outside of this controller is the index.ts file....
(OUTSIDE_OF)
[style] ~13-~13: This phrase is redundant. Consider using “outside”.
Context: ...les are internal and should not be used outside of this controller.
(OUTSIDE_OF)
src/main/controllers/windows-controller/README.md
[grammar] ~3-~3: Ensure spelling is correct
Context: ...ll BrowserWindows from electron and seperates them into different types of windows to...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[style] ~15-~15: This phrase is redundant. Consider using “outside”.
Context: ... The only thing that should be required outside of this controller is the index.ts file ...
(OUTSIDE_OF)
[style] ~16-~16: This phrase is redundant. Consider using “outside”.
Context: ...les are internal and should not be used outside of this controller.
(OUTSIDE_OF)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: build (ubuntu-latest)
- GitHub Check: build (macos-latest)
- GitHub Check: build (windows-latest)
- GitHub Check: build (ubuntu-24.04-arm)
- GitHub Check: build (macos-15-intel)
| "[json]": { | ||
| "editor.defaultFormatter": "esbenp.prettier-vscode" | ||
| } | ||
| }, | ||
| "typescript.tsdk": "node_modules/typescript/lib" |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Minor: Consider grouping the TypeScript SDK setting with language-scoped settings.
The new typescript.tsdk setting is currently at the root level, separate from the language-specific formatter configurations. While this is functionally correct, consider organizing it within a "[typescript]" scope or adding a comment to clarify its purpose, for better maintainability as the configuration grows.
Example refactor (optional):
"[typescript]": {
- "editor.defaultFormatter": "esbenp.prettier-vscode"
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "typescript.tsdk": "node_modules/typescript/lib"
},Alternatively, you can keep it at the root level if you prefer global scope; this is purely a matter of organization preference.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
.vscode/settings.json around lines 8 to 11: the typescript.tsdk setting is at
the root while formatter settings are language-scoped; to improve organization
either move "typescript.tsdk" into a "[typescript]" scope alongside
language-specific settings or add an inline comment above the root-level setting
explaining it is intentionally global, ensuring consistency and maintainability
as the config grows.
| app.on("second-instance", async (_event, commandLine) => { | ||
| const url = commandLine.pop(); | ||
| if (url && isValidOpenerUrl(url)) { | ||
| const shouldCreate = shouldCreateNewWindow(commandLine); | ||
| handleOpenUrl(shouldCreate, url); | ||
| } |
There was a problem hiding this comment.
Don't mutate argv; robustly detect URL and flag.
Using commandLine.pop() can drop --new-window (if last) or grab the working directory instead of the URL. Parse without mutation and find the first valid URL. Also await and guard handleOpenUrl to avoid unhandled rejections.
Apply:
- app.on("second-instance", async (_event, commandLine) => {
- const url = commandLine.pop();
- if (url && isValidOpenerUrl(url)) {
- const shouldCreate = shouldCreateNewWindow(commandLine);
- handleOpenUrl(shouldCreate, url);
- }
- });
+ app.on("second-instance", async (_event, commandLine) => {
+ const args = [...commandLine]; // do not mutate
+ const useNewWindow = shouldCreateNewWindow(args);
+ const urlArg = args.find((a) => isValidOpenerUrl(a));
+ if (!urlArg) return;
+ try {
+ await handleOpenUrl(useNewWindow, urlArg);
+ } catch (err) {
+ console.error("second-instance open failed:", err);
+ }
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| app.on("second-instance", async (_event, commandLine) => { | |
| const url = commandLine.pop(); | |
| if (url && isValidOpenerUrl(url)) { | |
| const shouldCreate = shouldCreateNewWindow(commandLine); | |
| handleOpenUrl(shouldCreate, url); | |
| } | |
| app.on("second-instance", async (_event, commandLine) => { | |
| const args = [...commandLine]; // do not mutate | |
| const useNewWindow = shouldCreateNewWindow(args); | |
| const urlArg = args.find((a) => isValidOpenerUrl(a)); | |
| if (!urlArg) return; | |
| try { | |
| await handleOpenUrl(useNewWindow, urlArg); | |
| } catch (err) { | |
| console.error("second-instance open failed:", err); | |
| } | |
| }); |
🤖 Prompt for AI Agents
In src/main/app/instance.ts around lines 10 to 15, the handler mutates
commandLine with commandLine.pop() and may drop flags like --new-window or
misidentify the working directory as the URL; instead, do not mutate argv — scan
commandLine for the first element that passes isValidOpenerUrl and separately
detect the presence of the --new-window flag (or other flags) without removing
items; call handleOpenUrl with await and wrap it in a try/catch to handle and
log any rejection so there are no unhandled promise rejections.
| export function runOnboardingOrInitialWindow() { | ||
| debugPrint("INITIALIZATION", "grabbing hasCompletedOnboarding()"); | ||
| hasCompletedOnboarding().then((completed) => { | ||
| debugPrint("INITIALIZATION", "grabbed hasCompletedOnboarding()", completed); | ||
| if (!completed) { | ||
| onboarding.show(); | ||
| debugPrint("INITIALIZATION", "show onboarding window"); | ||
| } else { | ||
| createInitialWindow(); | ||
| debugPrint("INITIALIZATION", "show browser window"); | ||
| } | ||
| }); | ||
| } |
There was a problem hiding this comment.
Add error handling for the promise chain.
The function doesn't handle potential rejections from hasCompletedOnboarding(). If the promise rejects, it will result in an unhandled promise rejection, potentially causing the app to fail silently during initialization.
Consider one of these approaches:
Option 1: Add error handling to the promise chain
export function runOnboardingOrInitialWindow() {
debugPrint("INITIALIZATION", "grabbing hasCompletedOnboarding()");
hasCompletedOnboarding().then((completed) => {
debugPrint("INITIALIZATION", "grabbed hasCompletedOnboarding()", completed);
if (!completed) {
onboarding.show();
debugPrint("INITIALIZATION", "show onboarding window");
} else {
createInitialWindow();
debugPrint("INITIALIZATION", "show browser window");
}
+ }).catch((error) => {
+ debugPrint("INITIALIZATION", "Error during onboarding check:", error);
+ // Fallback: show onboarding window or handle gracefully
+ onboarding.show();
});
}Option 2: Make the function async and return the promise
-export function runOnboardingOrInitialWindow() {
+export async function runOnboardingOrInitialWindow() {
debugPrint("INITIALIZATION", "grabbing hasCompletedOnboarding()");
- hasCompletedOnboarding().then((completed) => {
+ try {
+ const completed = await hasCompletedOnboarding();
debugPrint("INITIALIZATION", "grabbed hasCompletedOnboarding()", completed);
if (!completed) {
onboarding.show();
debugPrint("INITIALIZATION", "show onboarding window");
} else {
createInitialWindow();
debugPrint("INITIALIZATION", "show browser window");
}
- });
+ } catch (error) {
+ debugPrint("INITIALIZATION", "Error during onboarding check:", error);
+ onboarding.show();
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function runOnboardingOrInitialWindow() { | |
| debugPrint("INITIALIZATION", "grabbing hasCompletedOnboarding()"); | |
| hasCompletedOnboarding().then((completed) => { | |
| debugPrint("INITIALIZATION", "grabbed hasCompletedOnboarding()", completed); | |
| if (!completed) { | |
| onboarding.show(); | |
| debugPrint("INITIALIZATION", "show onboarding window"); | |
| } else { | |
| createInitialWindow(); | |
| debugPrint("INITIALIZATION", "show browser window"); | |
| } | |
| }); | |
| } | |
| export function runOnboardingOrInitialWindow() { | |
| debugPrint("INITIALIZATION", "grabbing hasCompletedOnboarding()"); | |
| hasCompletedOnboarding().then((completed) => { | |
| debugPrint("INITIALIZATION", "grabbed hasCompletedOnboarding()", completed); | |
| if (!completed) { | |
| onboarding.show(); | |
| debugPrint("INITIALIZATION", "show onboarding window"); | |
| } else { | |
| createInitialWindow(); | |
| debugPrint("INITIALIZATION", "show browser window"); | |
| } | |
| }).catch((error) => { | |
| debugPrint("INITIALIZATION", "Error during onboarding check:", error); | |
| // Fallback: show onboarding window or handle gracefully | |
| onboarding.show(); | |
| }); | |
| } |
| export function runOnboardingOrInitialWindow() { | |
| debugPrint("INITIALIZATION", "grabbing hasCompletedOnboarding()"); | |
| hasCompletedOnboarding().then((completed) => { | |
| debugPrint("INITIALIZATION", "grabbed hasCompletedOnboarding()", completed); | |
| if (!completed) { | |
| onboarding.show(); | |
| debugPrint("INITIALIZATION", "show onboarding window"); | |
| } else { | |
| createInitialWindow(); | |
| debugPrint("INITIALIZATION", "show browser window"); | |
| } | |
| }); | |
| } | |
| export async function runOnboardingOrInitialWindow() { | |
| debugPrint("INITIALIZATION", "grabbing hasCompletedOnboarding()"); | |
| try { | |
| const completed = await hasCompletedOnboarding(); | |
| debugPrint("INITIALIZATION", "grabbed hasCompletedOnboarding()", completed); | |
| if (!completed) { | |
| onboarding.show(); | |
| debugPrint("INITIALIZATION", "show onboarding window"); | |
| } else { | |
| createInitialWindow(); | |
| debugPrint("INITIALIZATION", "show browser window"); | |
| } | |
| } catch (error) { | |
| debugPrint("INITIALIZATION", "Error during onboarding check:", error); | |
| onboarding.show(); | |
| } | |
| } |
🤖 Prompt for AI Agents
In src/main/app/onboarding.ts around lines 6 to 18, the call to
hasCompletedOnboarding() lacks rejection handling and can trigger an unhandled
promise rejection; either add a .catch handler to the existing promise chain
that logs the error (with context) and falls back to createInitialWindow() (so
the app still starts), or convert runOnboardingOrInitialWindow to async, await
hasCompletedOnboarding() inside a try/catch, handle errors by logging and
creating the initial window, and ensure the function returns the resulting
promise so callers can await it.
| function setupWindowsUserTasks() { | ||
| app.setUserTasks([ | ||
| { | ||
| program: process.execPath, | ||
| arguments: "--new-window", | ||
| iconPath: process.execPath, | ||
| iconIndex: 0, | ||
| title: "New Window", | ||
| description: "Create a new window" | ||
| } | ||
| ]); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Set Windows user tasks after app is ready; add cleanup on quit
Safer to configure tasks post‑ready and clear on quit.
-function setupWindowsUserTasks() {
- app.setUserTasks([
+function setupWindowsUserTasks() {
+ app.whenReady().then(() => app.setUserTasks([
{
program: process.execPath,
arguments: "--new-window",
iconPath: process.execPath,
iconIndex: 0,
title: "New Window",
description: "Create a new window"
- }
- ]);
+ }
+ ]));
+ app.on("before-quit", () => app.setUserTasks([]));
}🤖 Prompt for AI Agents
In src/main/app/platform.ts around lines 5 to 16, the user task setup is
currently executed immediately; move the setup to run after Electron app is
ready and add cleanup on quit. Wrap the setUserTasks call inside
app.whenReady().then(...) (or await app.whenReady()) so tasks are configured
only after readiness, and register an app.on('will-quit' or 'quit') handler that
clears tasks via app.setUserTasks([]) to remove them on exit.
| dockMenu.append( | ||
| new MenuItem({ | ||
| label: "New Window", | ||
| click: () => { | ||
| browserWindowsController.create(); | ||
| } | ||
| }) |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Avoid floating promise on window creation
If lint rules enforce no‑floating‑promises, discard explicitly.
- click: () => {
- browserWindowsController.create();
- }
+ click: () => {
+ void browserWindowsController.create();
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| dockMenu.append( | |
| new MenuItem({ | |
| label: "New Window", | |
| click: () => { | |
| browserWindowsController.create(); | |
| } | |
| }) | |
| dockMenu.append( | |
| new MenuItem({ | |
| label: "New Window", | |
| click: () => { | |
| void browserWindowsController.create(); | |
| } | |
| }) |
🤖 Prompt for AI Agents
In src/main/app/platform.ts around lines 21 to 27, the click handler calls
browserWindowsController.create() and leaves its returned promise unhandled;
update the handler to explicitly discard or handle the promise to satisfy
no‑floating‑promises lint rules — e.g. prefix the call with "void" to
intentionally ignore the result or attach a .catch(...) to log/handle errors so
the promise is not left floating.
| ipcMain.handle("spaces:reorder", async (_event, orderMap: SpaceOrderMap) => { | ||
| return await spacesController.reorder(orderMap); | ||
| }); |
There was a problem hiding this comment.
Validate reorder payload server-side
orderMap contains profileId and spaceId pairs from the renderer. Validate each entry against the authoritative space profile before calling reorder to prevent cross-profile tampering.
Example guard inside the handler:
const validated = [];
for (const item of orderMap) {
const space = await spacesController.get(item.spaceId);
if (!space || space.profileId !== item.profileId) {
throw new Error("Invalid reorder entry");
}
validated.push(item);
}
return await spacesController.reorder(validated);🤖 Prompt for AI Agents
In src/main/ipc/session/spaces.ts around lines 48-50, the handler accepts an
orderMap from the renderer without server-side validation, allowing potential
cross-profile tampering; for each item in orderMap, fetch the authoritative
space (await spacesController.get(item.spaceId)), verify it exists and that its
profileId matches item.profileId, accumulate only the validated items into a new
array, and if any entry is missing or mismatched throw an error (or return a
clear IPC error) instead of calling reorder; finally call
spacesController.reorder with the validated array and ensure awaits and errors
are propagated properly.
| spacesController.on("space-created", fireOnSpacesChanged); | ||
| spacesController.on("space-updated", fireOnSpacesChanged); | ||
| spacesController.on("space-deleted", fireOnSpacesChanged); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
LGTM: spaces change events wiring
Broadcasts on created/updated/deleted via listeners manager. Consider including minimal payloads later for selective updates.
🤖 Prompt for AI Agents
In src/main/ipc/session/spaces.ts around lines 60–62 the three space events are
correctly wired to fireOnSpacesChanged; to support selective updates, change the
emitter and handler to pass a minimal payload (e.g., { id, action, meta })
instead of no args: update emit sites to include that payload, update the
spacesController.on callbacks to forward the payload to fireOnSpacesChanged
(fireOnSpacesChanged(payload)), and update fireOnSpacesChanged to accept and
propagate the payload to listeners so consumers can react only to relevant
changes.
| const blocker = await this.blockerInstancePromise; | ||
| for (const session of this.blockedSessions) { | ||
| blocker.disableBlockingInSession(createBetterSession(session, SESSION_KEY)); | ||
| blocker.disableBlockingInSession(unifiedWebRequests.createSession(session, SESSION_KEY)); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Document the SESSION_KEY constant usage.
The SESSION_KEY constant is passed to createSession() but its purpose and behavior are not documented. Based on the relevant code snippets, it appears to be used for caching/deduplication, but this should be clarified.
Add a comment explaining the SESSION_KEY:
type BlockerInstanceType = "all" | "adsAndTrackers" | "adsOnly";
+// Used to create a unified session wrapper for consistent content blocking across profiles
const SESSION_KEY = "content-blocker";Also applies to: 85-85
🤖 Prompt for AI Agents
In src/main/modules/content-blocker.ts around lines 63 and 85, the SESSION_KEY
passed to unifiedWebRequests.createSession(session, SESSION_KEY) is
undocumented; add a concise inline comment explaining that SESSION_KEY is the
session identifier used by createSession for caching and deduplication of
request/state across calls (e.g., must be unique per logical browsing session,
stable for dedupe, not secret), note expected format and lifetime (how long
entries are cached) and any security/privacy considerations (don’t use PII), and
place the comment immediately where SESSION_KEY is defined or immediately above
these createSession usages so future readers understand its purpose and
constraints.
| loadedProfilesController.on("profile-loaded", () => { | ||
| this.updateConfig(); | ||
| }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider handling profile unloading events.
The code subscribes to profile-loaded events but doesn't handle profile unloading. When profiles are unloaded, their sessions should be removed from this.blockedSessions to prevent memory leaks and avoid attempting to apply blocking to destroyed sessions.
Check if loadedProfilesController emits a profile unload event and subscribe to it:
#!/bin/bash
# Search for profile unload/remove events in the controller
ast-grep --pattern 'emit($$$, "profile-$_", $$$)'
rg -A 3 'profile-.*(?:unload|remove|destroy|close)' src/main/controllers/loaded-profiles-controller/If such an event exists, add a handler:
loadedProfilesController.on("profile-unloaded", (profileId) => {
// Remove the session from blockedSessions
const profile = loadedProfilesController.get(profileId);
if (profile) {
const index = this.blockedSessions.indexOf(profile.session);
if (index > -1) {
this.blockedSessions.splice(index, 1);
}
}
});🤖 Prompt for AI Agents
In src/main/modules/content-blocker.ts around lines 123 to 125, the code
subscribes to loadedProfilesController "profile-loaded" events but does not
handle profile unload/removal, which can leave stale sessions in
this.blockedSessions; add a listener for the controller's profile
unload/remove/close event (match the actual event name used by
loadedProfilesController) and in that handler remove the corresponding
profile.session from this.blockedSessions (lookup the profile by id via
loadedProfilesController.get(id), find the session index in this.blockedSessions
and splice it out) so blockedSessions does not retain destroyed sessions.
| const PDF_CACHE = new Map<string, Response>(); | ||
|
|
||
| export function addPdfResponseToCache(key: string, response: Response) { | ||
| PDF_CACHE.set(key, response); | ||
| } | ||
|
|
||
| export function getPdfResponseFromCache(key: string): Response | undefined { | ||
| return PDF_CACHE.get(key); | ||
| } | ||
|
|
||
| export function removePdfResponseFromCache(key: string) { | ||
| PDF_CACHE.delete(key); | ||
| } |
There was a problem hiding this comment.
Add cache size limit or eviction policy to prevent memory leak.
The PDF cache has no size limit or eviction policy, which could lead to unbounded memory growth if many PDFs are cached. Since Response objects can hold large binary data, this could become a significant memory leak.
Consider implementing one of these strategies:
Option 1: Add a maximum cache size with LRU eviction
+const MAX_CACHE_SIZE = 50; // Adjust based on requirements
const PDF_CACHE = new Map<string, Response>();
+const cacheAccessOrder: string[] = [];
export function addPdfResponseToCache(key: string, response: Response) {
+ if (PDF_CACHE.size >= MAX_CACHE_SIZE && !PDF_CACHE.has(key)) {
+ const oldestKey = cacheAccessOrder.shift();
+ if (oldestKey) PDF_CACHE.delete(oldestKey);
+ }
PDF_CACHE.set(key, response);
+ // Move to end (most recently used)
+ const index = cacheAccessOrder.indexOf(key);
+ if (index > -1) cacheAccessOrder.splice(index, 1);
+ cacheAccessOrder.push(key);
}
export function getPdfResponseFromCache(key: string): Response | undefined {
+ const response = PDF_CACHE.get(key);
+ if (response) {
+ // Move to end (most recently used)
+ const index = cacheAccessOrder.indexOf(key);
+ if (index > -1) cacheAccessOrder.splice(index, 1);
+ cacheAccessOrder.push(key);
+ }
- return PDF_CACHE.get(key);
+ return response;
}Option 2: Add a cache clearing function
+export function clearPdfCache() {
+ PDF_CACHE.clear();
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const PDF_CACHE = new Map<string, Response>(); | |
| export function addPdfResponseToCache(key: string, response: Response) { | |
| PDF_CACHE.set(key, response); | |
| } | |
| export function getPdfResponseFromCache(key: string): Response | undefined { | |
| return PDF_CACHE.get(key); | |
| } | |
| export function removePdfResponseFromCache(key: string) { | |
| PDF_CACHE.delete(key); | |
| } | |
| const PDF_CACHE = new Map<string, Response>(); | |
| export function addPdfResponseToCache(key: string, response: Response) { | |
| PDF_CACHE.set(key, response); | |
| } | |
| export function getPdfResponseFromCache(key: string): Response | undefined { | |
| return PDF_CACHE.get(key); | |
| } | |
| export function removePdfResponseFromCache(key: string) { | |
| PDF_CACHE.delete(key); | |
| } | |
| export function clearPdfCache() { | |
| PDF_CACHE.clear(); | |
| } |
🤖 Prompt for AI Agents
In src/main/modules/pdf-cache.ts around lines 6 to 18, the in-memory PDF_CACHE
currently has no size limit or eviction policy which can cause unbounded memory
growth; implement a bounded cache with an LRU eviction policy (or at minimum a
clear function) by: replace the simple Map with an LRU-capable structure (either
implement a small LRU using a Map + usage order tracking or import a lightweight
LRU cache lib), add a MAX_ENTRIES constant, on addPdfResponseToCache check if
cache size >= MAX_ENTRIES and evict the least-recently-used entry before
inserting, update getPdfResponseFromCache to mark entries as recently used, and
provide an exported clearPdfCache() function to allow manual clearing; ensure
removePdfResponseFromCache still deletes specific keys and that response bodies
are properly released/closed if needed to avoid retaining large buffers.
Goals
@/browser@/controllersSummary by CodeRabbit
Release Notes
Build & Configuration
New Features
Improvements