Skip to content

Browser foundations: shared types + pure logic - #467

Open
ianu82 wants to merge 5 commits into
stagingfrom
pr/browser-types-logic
Open

Browser foundations: shared types + pure logic#467
ianu82 wants to merge 5 commits into
stagingfrom
pr/browser-types-logic

Conversation

@ianu82

@ianu82 ianu82 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

What

The shared vocabulary for the embedded browser (part 1 of 5, replacing #462).

  • src/shared/browser-types.ts: the tab/state wire types used by renderer, main, and the agent bridge.
  • browser:* IPC channel constants, snapshot-locked as usual (renames are breaking changes).
  • src/main/browser/browser-logic.ts: the pure decision layer — omnibox→URL normalization (bare domains, localhost:3000, search fallback), the scheme allowlist, tab model transitions, top-sites merging across Chrome import + in-app history, redacted visit history, persisted-state sanitizers, favicon validation, and download-name deduping.

No Electron imports anywhere — every function maps inputs to outputs and is tested directly, in the update-logic.ts tradition.

Why this split

The previous core PR (#462) bundled ~5,000 lines. These are the foundations everything else reads from; landing them first means later PRs are pure behavior.

Verification

  • 59 unit tests pass: the full URL matrix (including file:///javascript: rejection and host:port handling), tab ordering, history merge/redaction, and persisted-state repair.
  • Typecheck clean.

For QA

Nothing user-visible in this one — it's types and pure functions. If the suite is green, this ships. The interesting checks come in the follow-ups.

ianu82 added 2 commits July 22, 2026 15:11
Wire types for the embedded browser plus the pure decision layer they
feed: URL/omnibox normalization, the tab model (add/remove/activate),
top-sites merging, visit history, persisted-state sanitizers, and the
browser:* IPC channel constants (snapshot-locked). No Electron imports —
every function is pure and unit-tested directly.
The decision layer the manager orchestrates: omnibox→URL normalization
(host:port handling, search fallback), scheme allowlist, tab model
transitions, top-sites merge (Chrome import + cowork history), redacted
visit history, persisted tabs/history sanitizers, favicon validation,
download-name dedupe. Pure functions only — the full unit matrix runs
without Electron.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b97dce253a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +313 to +318
tabs.push({
id: tab.id,
url,
title: typeof tab.title === 'string' ? tab.title : '',
favicon: sanitizeFaviconUrl(typeof tab.favicon === 'string' ? tab.favicon : null),
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Cap restored tabs at MAX_TABS

Because sanitizePersistedTabs is the launch-restore validator, a corrupted or hand-edited tabs.json containing more than 50 otherwise valid http tabs is returned in full here. That bypasses the documented hard cap and can make restore allocate an unbounded number of tab views; stop adding once tabs.length reaches MAX_TABS or reject the file.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — restore is capped at MAX_TABS (78ff69c).

Comment on lines +335 to +339
out.push({
url: entry.url,
title: typeof entry.title === 'string' ? entry.title : '',
ts: typeof entry.ts === 'number' ? entry.ts : 0,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Redact restored history URLs before returning them

When history.json comes from an older build or a corrupt/manual edit, this copies entry.url back into the history unchanged. The rest of the history pipeline treats entries as already redacted, so query strings or hashes containing tokens/searches can be surfaced through top sites and persisted again; run the URL through redactUrlForLog here and skip empty results.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — restored history entries go through redactUrlForLog and empty results are skipped (78ff69c).

ianu82 added 3 commits July 22, 2026 17:29
Review follow-up: sanitizePersistedTabs now stops at MAX_TABS so a
corrupt tabs.json can't bypass the cap, and sanitizeHistory runs every
restored URL through redactUrlForLog so stale/hand-edited files can't
reintroduce query strings into top sites.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant