Skip to content

Latest commit

 

History

History

safari

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

README.md

Hydra Safari Extension

Same code, same transport, same experience as the Chrome extension — with one platform limit that cannot be worked around (see below).

Why this needs no separate source tree

The extension code in extensions/chrome is browser-neutral: it binds whichever namespace exists (browser on Safari, chrome on Chromium), handles both native-messaging dialects (Safari returns a promise, Chrome takes a callback), and feature-detects every API it uses. What differs per browser is the manifest and the download-capture path, and Safari has no downloads API to capture with — so scripts/sync-extension-resources.sh safari copies the shared files next to Safari's own manifest into Resources/, with core.js (the browser-neutral part of the extension) taking the background.js name the manifest points at.

Edit extensions/chrome/*, never extensions/safari/Resources/* — the latter is regenerated on every sync.

The transport is the reason this works so cleanly: since the extension talks to Hydra over a WebSocket on a fixed loopback port (6799), Safari needs no special IPC at all. The app accepts safari-web-extension://… origins exactly as it accepts chrome-extension://….

What works, and the one thing that does not

Feature Chrome Safari
Right-click → Download with Hydra ✅ ✅
Selection pill over highlighted links ✅ ✅
Download all links ✅ ✅
Popup, capture toggle, status badge ✅ ✅
Media sniffing ✅ ⚠️ only where Safari exposes webRequest
Automatic download capture ✅ ❌ impossible

Safari has no downloads API — Apple does not expose download events to extensions at all, so there is nothing to intercept. Every other browser integration on macOS has the same limit; it is not a gap in this code. Use the right-click menu or the selection pill instead.

Build & install

Requires full Xcode (Command Line Tools alone cannot build app extensions):

sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

Then:

scripts/build-safari-extension.sh

The script syncs the resources, generates the wrapper app, installs SafariWebExtensionHandler.swift, disables the app sandbox (the handler must read ~/.config/hydra/ipc.json and launch the app), allows cleartext loopback via ATS, and builds.

Afterwards: open the built app once, then Safari → Settings → Extensions → enable Hydra. For an unsigned dev build also tick Develop → Allow Unsigned Extensions (Safari clears this on restart).

Native handler

SafariWebExtensionHandler.swift is the fallback path, mirroring hydra-host: it forwards a request to the app's line-protocol socket using the token from ipc.json, and launches "Hydra Download Manager" when nothing answers. Day to day the WebSocket carries the traffic; the handler exists so the first click can start the app.