Repository navigation
Conversation
jpagh
force-pushed
the
feature/mailto-links
branch
from
September 30, 2026 23:52
5221e1e to
01b8f1b
Compare
Discover standards-declared mail handlers from each service's own registerProtocolHandler call or web app manifest, validate them against the service's origin over HTTPS, and store them on that instance. Queue mail links through an account chooser; the chosen account opens a compose window scoped to its own website data store, and the queue keeps its order across errors, locking, and dismissal. Sites that only call registerProtocolHandler when they see a Chromium browser still declare a handler through a serial, invisible Chromium-UA probe. The probe runs at most once per service per five minutes, so a declaration made after sign-in is still found without a hidden page load on every navigation. An invalid registration no longer shadows a valid one for the same service, and a declaration from a subframe is rejected by the router instead of being trusted by the bridge. The stored template and declaring origin now travel as one value; the chooser keeps account identity, provider, and space context. Validation: full Debug suite passed (349 tests, 1 skipped real-store-copy migration, 0 failures), with focused router, AppState routing, compose-session, and manifest-discovery runs. xcodegen reproduces the committed project file byte for byte. Live-provider sending, focus, accessibility, and the real-store copy remain manual checks.
jpagh
force-pushed
the
feature/mailto-links
branch
from
October 4, 2026 01:43
01b8f1b to
a77dd91
Compare
nicojan
requested changes
Oct 6, 2026
nicojan
left a comment
Owner
There was a problem hiding this comment.
Thanks, Jack. This is a lot of careful work. The Info.plist handler, the routing through application(_:open:), the account chooser and the schema stage are all good, and I checked the frozen ChorusSchemaV1_5_19 against the live models field by field. But three choices change Chorus for everyone, and I can't take them as they stand.
Blocking
- Mail links inside a service no longer go to the user's mail app.
.routeMailinWebViewCoordinatorsends every mail link click to the router. Someone who uses Apple Mail and has no mail service in Chorus now gets "None of your added services has declared support…", and the link is lost. Someone whose default is Outlook gets Gmail. If Chorus is the system default,openExternallyalready comes back throughapplication(_:open:), so there is no loop to prevent. Please keepopenExternallyfor clicks inside services. - A page can claim mail links without asking.
acceptMailHandlerDeclarationsaves and enables any template a main-frame page on the service's origin passes in, and a single eligible service skips the chooser. Browsers ask first. Please ask the user the first time, and whenever the template changes, showing the origin and path. Skip the save when nothing changed, too, since a page that calls it in a loop writes the store each time. - Please drop the hidden Chrome probe. It runs for every HTTPS service without a handler: Slack, Teams, WhatsApp, Discord. That's a second WebContent process loading the whole app with the user's cookies, at every launch and every five minutes after a load. It writes into the same data store as the visible page, and it shows the site one session from two browsers. Gmail is the only reason for it, so a compose template in
ServiceCatalogfor the few providers that need one would do the job. The same goes for the manifest fetch on every page load of every service.
Would make it smaller
- Main now has service tabs (
opensAsTab,ServiceTabs.swift). Opening the compose URL as a tab in the service's card would get attachments, popups, downloads, the content blocker and the app lock for free, and you could deleteMailComposeWindowSession, both close scripts and most of the window tests. As it is, the window has no open panel and nocreateWebViewWith, and it stays usable while Chorus is locked. - The auto-close guess (no editable field for 500ms) can close a draft when Gmail's compose box is minimized or re-renders. I'd let the user close it.
- Please leave out the unrelated changes:
AppDependencies, the secondAppState.initthat points the store at/dev/null, andDataStoreManager.makeStore. - The branch is based on 49eb983, eight releases back, and touches the same code as the tabs work, so it needs a rebase.
Smaller things
- The subframe test passes for the wrong reason: an iframe with no
srcisabout:blank, so the origin check rejects it before theisMainFramecheck runs. Give it a same-originsrc. - Use
frameInfo.securityOriginrather thanframeInfo.request.url ?? webView.url. - Name the schema version after the release it ships in, not
1.5.20. - The loopback private key under
ChorusTests/Fixturesis harmless, but the repo's secret scanners will flag it. Generating it at test time avoids that. - In-app text: "declared support" and "register" won't mean much to most people. I'd say what to do instead, such as "Open Gmail in Chorus first."
Happy to talk through any of this before you start.
nicojan
added a commit
that referenced
this pull request
Oct 6, 2026
Author
|
Thanks. I'll take a look. I'm actually really unhappy with how Gmail operates. The fact that it won't even offer mailto support without thinking you're using Chrome is super annoying. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Chorus now handles
mailto:links itself instead of handing them to the system mail app.registerProtocolHandlercall or web app manifest. Chorus validates the handler against the service's own origin over HTTPS and stores it on that service instance.registerProtocolHandlerwhen they see a Chromium browser still declare a handler through a short, invisible probe with a Chromium user agent. The probe runs at most once per service per five minutes, so a handler declared after sign-in is still found without a hidden page load on every navigation.Test plan
xcodegen generatereproduces the committed project file byte for byteThis edits
EditServiceSheet.swift, a settings view, so it can collide with another change to a settings view.