fix(downloads): support offline fallback drafts

- launch Firefox handoffs through authenticated reconnect
- preserve usable drafts when metadata lookup fails
- reject stale metadata results and retry failed rows only
This commit is contained in:
NimBold
2026-06-22 17:21:47 +03:30
parent f469c5d7eb
commit 6b3753949b
10 changed files with 745 additions and 183 deletions
+148
View File
@@ -0,0 +1,148 @@
# Firefox Offline Handoff and Metadata Fallback Plan
## Constraints
- No Native Messaging, helper executable, background service, or Apple Developer account dependency.
- Firefox controls first-use external-protocol confirmation. Firelink cannot suppress it.
- First use requires user approval; Firefox may offer “Always allow this extension to open firelink links.”
- Automatic browser-download capture never launches Firelink and resumes Firefox unless `/download` confirms acceptance.
## 1. Firefox launch-and-reconnect flow
1. Add launch-only `firelink://launch`.
2. Manual action first sends original authenticated `/download` payload.
3. Launch fallback is allowed only when authenticated discovery finds no Firelink server.
- Never launch for `403`, other `4xx`, or a Firelink server returning `5xx`.
- A startup `503` may be retried within the existing startup deadline.
- Never retry an ambiguous POST failure after request transmission because delivery may already have happened.
4. Offline manual actions use one shared launch operation:
- Create one inactive `firelink://launch` tab.
- Queue immutable original payloads while startup is in progress.
- Poll authenticated `/ping` across `127.0.0.1:6412-6422` with bounded retries.
- Deliver every queued payload exactly once after startup.
- Close the launch tab only after all queued payloads reach a terminal result.
5. Success means authenticated `/download` returned success. Tab creation is never success.
6. Timeout/cancel:
- Stop after defined deadline.
- Close temporary tab where Firefox permits.
- Notify that Firelink was not opened and no download was added.
7. Store consecutive launch-timeout count and cooldown timestamp in `chrome.storage.local`.
- Reset both after successful startup delivery.
- During cooldown, do not open another protocol tab; show concise troubleshooting guidance.
8. Invalid pairing tokens never trigger protocol fallback.
## 2. Firefox first-use guidance
- README and popup explain first-use Firefox confirmation and “Always allow.”
- State clearly Firelink cannot bypass browser-controlled prompt.
- Repeated timeout guidance suggests confirming protocol permission, opening Firelink once, and checking installation.
## 3. Typed desktop deep links
Use a typed parser result:
- `Launch`
- `Add(Vec<String>)`
- `Invalid`
Rules:
- `firelink://launch` must contain exact scheme and host, with no username, password, port, path beyond `/`, query, or fragment.
- `Launch` restores/focuses window and never enters `CaptureUrls`.
- `firelink://add?url=...` keeps current external integration behavior.
- Unsupported schemes/hosts and malformed nested URLs return `Invalid`.
- Startup and already-running links use same dispatch function.
- Add URLs remain buffered in `DownloadCoordinator` until frontend listeners report ready.
## 4. Explicit metadata model
Each draft row has:
- Stable `id`
- Normalized `sourceUrl` identity
- `downloadUrl`, which metadata redirects may update
- Monotonic request `generation`
- Required status union: `loading | ready | metadata-error | invalid`
- Fallback filename and optional size bytes (`undefined` means unknown)
- Direct/media classification
- Optional successful metadata and selected media format
Malformed or unsupported URLs are `invalid`. Valid URLs whose metadata request fails remain `metadata-error`.
## 5. Parsing and enrichment separation
- Extract pure URL parsing/reconciliation helpers from modal.
- Normalize and deduplicate input by `sourceUrl`, preserving first occurrence order.
- Preserve existing rows, IDs, successful metadata, and selected formats.
- Create `loading` rows only for new valid URLs.
- Metadata results apply only when row ID, `sourceUrl`, and request generation still match.
- Save location, selection, and another rows result never restart metadata.
- Credential edits affect transfer credentials and future failed-row retries only. Ready metadata remains unchanged.
## 6. Failed-only refresh
- Refresh selects only `metadata-error` rows.
- Increment only those rows generations and mark only those rows `loading`.
- Preserve every successful row and selected format.
- Failed retry restores fallback row as `metadata-error`.
- Disable refresh when no failed rows exist.
## 7. Submission eligibility and fallback routing
Eligible: `ready`, `metadata-error`.
Blocking: `loading`, `invalid`.
- Start Downloads and Add to Queue share one eligibility helper.
- Unknown size stays `undefined`; display text is derived and `"Unknown"` is not persisted as size.
- Failed direct rows retain original URL, fallback filename, direct routing, credentials, mirrors, duplicate checks, and destination logic.
- Failed media rows retain `isMedia: true`, send no format selector, and use yt-dlp default selection.
- Remove redownload validation requiring a media selector; selector-less media items remain valid.
## 8. Add-window messaging
- Loading: “Waiting for metadata for N downloads.”
- Mixed: “N downloads ready; M will use fallback filename and unknown size.”
- All failed: “Metadata is unavailable. Downloads can still be added using fallback details.”
- Invalid: “Correct or remove N invalid URL(s) before continuing.”
- Failed rows remain visually distinct but usable.
## 9. Tests
### Extension
- Offline manual action opens `firelink://launch`, not `firelink://add`.
- Tab creation is not success.
- Authenticated discovery retries; original payload fields survive startup.
- Shared startup sends concurrent payloads once and closes tab after terminal delivery.
- Timeout/cancel notifies failure and records cooldown.
- Automatic capture never opens protocol tab.
- Invalid token and other server errors never launch.
- Ambiguous POST failure never resends.
### Desktop
- Exact launch restores without downloads.
- Add links still parse.
- Unsupported/malformed links reject.
- Startup/running dispatch match.
- Startup Add URLs wait for frontend readiness.
### Add window
- Pure helper tests cover reconciliation, stale generations, failed-only refresh, eligibility, fallback routing, unknown size, duplicate filenames, and destinations.
- Component-level behavior uses pure helpers where possible; no DOM test runtime is required unless interaction coverage cannot be expressed through helpers.
## 10. Acceptance and verification
Run:
```bash
npm run test
npm run build
(cd Extensions/Firefox && npm run check)
(cd src-tauri && cargo check)
(cd src-tauri && cargo test --all-targets)
```
Then perform Firefox offline and mixed/all-failed metadata acceptance scenarios from original plan.