Skip to content

feat(deep-link): handle autonomi:// URLs to trigger downloads#164

Merged
Nic-dorman merged 3 commits into
mainfrom
feat/deep-link-autonomi-scheme
Jun 11, 2026
Merged

feat(deep-link): handle autonomi:// URLs to trigger downloads#164
Nic-dorman merged 3 commits into
mainfrom
feat/deep-link-autonomi-scheme

Conversation

@Nic-dorman

Copy link
Copy Markdown
Contributor

Why

Clicking an autonomi://<public_address> link in a browser should launch/focus the desktop app and start downloading that file — the public address is already the shareable handle, so a clickable link is the natural next step. Public-only by design (a private upload's datamap isn't URL-shareable).

What

  • Registers the autonomi:// URL scheme and routes a clicked link into the existing Download by address flow: the dialog opens prefilled with the address, which doubles as the confirm + filename step (a web-triggered link never downloads silently).
  • Optional filename via autonomi://<addr>?name=<file>, prefilled into the dialog (validated by the existing filenameError check).

How

  • Plugins: tauri-plugin-deep-link (scheme declared in tauri.conf.json) and, on Windows/Linux, tauri-plugin-single-instance with the deep-link feature so a link opened while the app is already running routes into the existing window instead of spawning a duplicate. macOS delivers to the running app via on_open_url.
  • src-tauri/src/lib.rs: register single-instance first (Win/Linux), init deep-link, register_all() at runtime for dev, capture cold-start URLs into DeepLinkState (drained via take_pending_deep_links), and emit a deep-link event for warm opens. On Win/Linux the single-instance callback also parses the autonomi:// URL out of argv and emits it, so warm-start doesn't depend solely on feature forwarding.
  • Frontend (plugins/deep-link.client.ts): validates the URL (parseAutonomiDeepLink / isValidPublicAddress), stashes the address (+ optional name) on the files store, and routes to /files. The store + router are captured at plugin init because the event callback runs outside the Nuxt instance context. DownloadDialog applies the prefill on mount (not just on open-transition) so it works on the very first cold launch, and refreshes if a link arrives while it's open.

Testing

  • Verified end-to-end on Windows (warm start, including first attempt after a fresh launch): clicking the link focuses the app, opens the Download dialog prefilled with address + ?name=, and download_public fetches/decrypts/saves.
  • nuxi typecheck clean, vitest 37/37 (adds parseAutonomiDeepLink / isValidPublicAddress unit tests), cargo check clean.
  • Still to validate: true cold start (app fully closed → click link). This can't be exercised under tauri dev (the bare dev exe has no Vite server), so it needs an installed/bundled build — pending verification on macOS.

Out of scope

  • Private/datamap downloads (not URL-shareable).
  • Per-row single export and other unrelated flows.

🤖 Generated with Claude Code

Nic-dorman and others added 3 commits June 11, 2026 14:32
Clicking an autonomi://<public_address> link in a browser now launches/
focuses the app and opens the Download-by-address dialog prefilled with
the address (the dialog is the confirm + filename step — we never
download silently from a web-triggered action).

- Add tauri-plugin-deep-link (scheme registered in tauri.conf.json) and,
  on Windows/Linux, tauri-plugin-single-instance with the deep-link
  feature so a link opened while the app is already running routes into
  the existing window instead of spawning a duplicate.
- lib.rs: register single-instance first (Win/Linux), init deep-link,
  register_all() at runtime for dev, capture cold-start URLs into
  DeepLinkState (drained via take_pending_deep_links), and emit a
  "deep-link" event for warm opens.
- Frontend: plugins/deep-link.client.ts validates the URL
  (parseAutonomiDeepLink / isValidPublicAddress), stashes the address on
  the files store, and routes to /files; the page opens DownloadDialog
  prefilled. Cold/warm overlap deduped with a 2s window.

Public-only by design (private uploads' datamap isn't URL-shareable).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tested end-to-end on Windows; several fixes from that pass:

- First-attempt prefill: when a link is opened cold, the Files page
  navigates in with the Download dialog already mounted open, so its
  prefill watcher (keyed on a false->true transition) never fired. Make
  it `immediate` and also watch `prefillAddress` so the fields populate
  on mount and refresh if a link arrives while the dialog is open.
- Nuxt context: the `listen` callback runs outside the Nuxt instance
  context, so useFilesStore()/navigateTo() inside it were unreliable.
  Capture the store + router at plugin init and reuse them.
- Warm-start reliability (Win/Linux): also parse the autonomi:// URL out
  of the single-instance argv and emit it, not only relying on the
  deep-link feature forwarding to on_open_url.
- Filename: support autonomi://<addr>?name=<file>, prefilled into the
  dialog (validated by the existing filenameError check).

Adds unit tests for parseAutonomiDeepLink / isValidPublicAddress.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…inputs

These inputs had no placeholder color, so the placeholder rendered near
full text brightness (looked like an entered value in dark mode). Apply
the app-standard placeholder-autonomi-muted token plus a slight opacity
reduction, matching the other inputs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Nic-dorman Nic-dorman merged commit db11c3e into main Jun 11, 2026
4 checks passed
@Nic-dorman Nic-dorman deleted the feat/deep-link-autonomi-scheme branch June 11, 2026 15:14
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