You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
updates-122: clips desktop auto-updater + download page (#233)
* updates-122: clips desktop auto-updater + download page + release workflow
Initial drop from concurrent agents — auto-updater, download landing
page, desktop release GitHub Actions workflow.
* fix(clips): address all 6 Builder review blockers for auto-updater + download page
1. tauri.conf.json: updater endpoint points at the immutable
/releases/download/clips-latest/clips-latest.json URL instead of
/releases/latest/download/ which resolved to whichever GitHub tag
happened to be marked "latest".
2. clips-desktop-release.yml: add a pre-build guard that fails the
workflow if the updater pubkey is still the placeholder, preventing
accidental release with a non-verifying signature.
3. download.tsx: when the manifest fetch fails or has no matching
asset, the primary button now falls back to the public Releases
PAGE (a browsable URL) instead of the JSON manifest itself. Button
is explicitly disabled during the loading state.
4. download.tsx: Mac arch detection now uses
navigator.userAgentData.architecture (Chromium: "arm" | "x86")
as the canonical signal. Safari, which lacks userAgentData, still
defaults to Apple Silicon since it's the overwhelming majority on
currently-shipping Macs.
5. clips-latest.json.get.ts (new): same-origin server proxy for the
updater manifest. GitHub release-asset responses don't include CORS
headers, so a direct browser fetch fails silently. The download
page now hits /api/clips-latest.json which server-side fetches
GitHub and returns the JSON with correct headers.
6. UpdateBanner.tsx: surface the error state with a Retry button
(wires to new retryUpdateCheck() export) and a Dismiss option.
Signature-verification, download, and network failures no longer
fail silently.
* fix(clips): 5 follow-ups from Builder incremental review
1. UpdateBanner error-dismiss: scope dismissal to the specific error
message so a new, different failure still surfaces. Previously
dismissing one error silenced every subsequent error for the rest of
the session.
2. styles.css: add missing `.update-banner--error` styling (red-tinted
surface with 10% background + 40% border).
3. /api/clips-latest.json: add 10s AbortSignal.timeout on the upstream
fetch so a slow GitHub can't hang the request indefinitely. Maps
TimeoutError to a distinct 502 status message.
4. download.tsx fallback URL: point at
/releases?q=clips-v (the versioned-release listing that actually
holds installers) instead of the clips-latest tag page (manifest
only, no DMG/MSI/AppImage).
5. download.tsx arch detection: use async
userAgentData.getHighEntropyValues(["architecture"]). The sync
property is an empty string until the high-entropy call resolves.
Keeps a sync Apple-Silicon default, then corrects to Intel when
Chromium confirms it.
* fix(clips): download page now sources installers from releases API, not updater manifest
Addresses 3 architectural issues from Builder's final review pass.
Root cause: `/download` was parsing the Tauri updater manifest for
installer URLs, but that manifest lists updater ARCHIVES
(`.app.tar.gz`, `.msi.zip`, `.AppImage.tar.gz`) used for in-app
patching — not the raw installers (.dmg / .msi / .exe) users want on
first install. Every platform fell back to the Releases page.
Fix:
- Rewrite `/api/clips-latest.json` to hit GitHub's releases API,
pick the most recent published `clips-v*` release, and return its
asset list with each asset classified by kind (mac-universal /
mac-arm64 / mac-x64 / windows-msi / windows-exe / linux-*).
Explicitly skips .sig and updater-archive assets (`unknown` kind).
- Rewrite `/download` to match by classified kind instead of filename
regex. Collapses the two Mac variants into a single "macOS
Universal (Apple Silicon + Intel)" card, since the workflow builds
`universal-apple-darwin` which produces one DMG that runs on both.
Drops the Linux variant — `tauri.conf.json` only lists
`["dmg", "msi"]` bundle targets, so no AppImage is produced.
- Drop the Ubuntu matrix job + Linux deps step from the release
workflow to match: no AppImage bundle → no point building one.
Arch-split detection (`refinePlatform`, `userAgentData`) is gone
since macOS is now a single variant.
* fix(clips): cache + paginate /api/clips-latest.json
Two operability fixes on the GitHub-releases proxy from Builder's
final review:
- 5-minute process-wide memoization (+ request-coalescing via an
in-flight promise) so a burst of hits to /download share one
upstream fetch. GitHub's unauthenticated REST API is 60 req/hr/IP,
so the naive every-request fetch would 429 under modest traffic.
- Stale-while-error fallback — if GitHub errors out AND we have a
prior successful payload, serve that instead of bubbling the
error. Prevents a transient upstream hiccup from taking the
download page offline.
- HTTP `cache-control: max-age=60` stays on the response so
downstream caches + the browser also cache aggressively. The
client-side `fetch` drops its `cache: "no-cache"` which was
bypassing both layers.
- Paginate through `/releases` up to 10 pages (1000 releases)
looking for the latest `clips-v*`. Previously capped at the
first 50; as the repo accumulates other releases the `clips-v*`
entry would eventually fall off page 1 and the endpoint would
return a false 404.
* fix(clips): scan all release pages + preserve upstream status codes
Two follow-ups from Builder's review on d7a9502a:
- findLatestClipsRelease no longer early-exits on first match. Walks
every page (bounded by MAX_PAGES) and tracks the `published_at`
maximum. Previously depended on GitHub's implicit created_at-desc
sort, which can diverge from published_at (e.g. a draft published
later than a later-created draft). Same worst-case page count, no
ordering assumption.
- Introduce UpstreamError carrying the GitHub HTTP status. fetchPage
throws that on non-OK responses; the route handler now propagates
the original status (429 stays 429, 503 stays 503) instead of
flattening everything to 502. Rate limits + service-unavailable
failures now show up correctly to monitors.