From 43ca760291c7eec0635e2211740342de87be1def Mon Sep 17 00:00:00 2001 From: "dobby-yivi-agent[bot]" <275734547+dobby-yivi-agent[bot]@users.noreply.github.com> Date: Sat, 9 May 2026 13:35:53 +0000 Subject: [PATCH 1/5] fix: opt RSS link out of client-side navigation Closes #183 The blog RSS button used a SvelteKit anchor with no reload hint. The (marketing) layout sets trailingSlash: 'always', which causes the client router to redirect /blog/rss.xml to /blog/rss.xml/ on client-side navigation. The +server.js endpoint is prerendered to a file at /blog/rss.xml, so the trailing-slash form falls through to the SPA shell (or errors), and visitors saw a 500. Adding data-sveltekit-reload makes the browser perform a full navigation, bypassing the client router so the static file is served directly. Direct URLs already worked because they are not subject to the router's trailing-slash rewrite. --- src/routes/(marketing)/blog/+page.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/(marketing)/blog/+page.svelte b/src/routes/(marketing)/blog/+page.svelte index 3fa05dd..7b73e53 100644 --- a/src/routes/(marketing)/blog/+page.svelte +++ b/src/routes/(marketing)/blog/+page.svelte @@ -70,6 +70,7 @@ class="rss-link" href={resolve('/(marketing)/blog/rss.xml')} aria-label="RSS feed" + data-sveltekit-reload > Date: Sat, 9 May 2026 13:36:42 +0000 Subject: [PATCH 2/5] fix: extend cryptify retry budget to cover restart window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default pg-js retry policy (5 attempts, 500ms initial delay, multiplier 2) exhausts in ~7.5s of total wait time. That's shorter than a typical cryptify service restart, so users see a hard failure during what should be a recoverable outage. Bump maxAttempts to 8 and initialDelayMs to 1000ms so the retry budget covers ~90s of total wait — long enough to ride out a restart while still failing fast for genuinely down backends. Closes #181 --- src/lib/postguard.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib/postguard.ts b/src/lib/postguard.ts index e161af0..1c8f2fc 100644 --- a/src/lib/postguard.ts +++ b/src/lib/postguard.ts @@ -19,6 +19,12 @@ export const pg = new PostGuard({ cryptifyUrl: FILEHOST_URL, ...(CHUNK_SIZE !== undefined && { uploadChunkSize: CHUNK_SIZE }), retry: { + // Defaults (5 attempts, 500ms initial) exhaust the retry budget in + // ~7.5s — shorter than a typical cryptify restart, so a brief outage + // surfaces as a hard failure to the user. Stretch the budget so the + // total wait covers a realistic restart window (~90s). + maxAttempts: 8, + initialDelayMs: 1000, onRetry: (event) => retryStatus.set(event), }, }) From e9777bde6c9b39c30277aa14bbabea3d3f7bff50 Mon Sep 17 00:00:00 2001 From: "dobby-yivi-agent[bot]" <275734547+dobby-yivi-agent[bot]@users.noreply.github.com> Date: Sat, 9 May 2026 13:36:42 +0000 Subject: [PATCH 3/5] fix: prevent light-mode flash on initial page load Add a synchronous inline script in app.html that reads the user's theme preference (localStorage 'preferredtheme', falling back to prefers-color-scheme) and applies the .dark class to before the browser paints. Previously the class was only set during Svelte hydration, causing a brief light-mode flash on every refresh in dark mode. Closes #180 --- src/app.html | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/app.html b/src/app.html index 72d4d9f..8c848ef 100644 --- a/src/app.html +++ b/src/app.html @@ -5,6 +5,19 @@ + %sveltekit.head% From fd3984c33f59f1a01f513e7506f275eeba0fd8a8 Mon Sep 17 00:00:00 2001 From: "dobby-yivi-agent[bot]" <275734547+dobby-yivi-agent[bot]@users.noreply.github.com> Date: Sat, 9 May 2026 13:37:29 +0000 Subject: [PATCH 4/5] fix: add cancel button during file upload (#182) Closes #182. The encryption/upload progress UI rendered by SendButton exposed only a spinner and progress bar; users had no in-app way to abort a long upload. Adds a Cancel button to the upload-info-box that calls AbortController.abort() on the existing encryption/upload signal, flips selfAborted so the catch path resets to FileSelection, and provisions a fresh AbortController for the next attempt. --- .../components/filesharing/SendButton.svelte | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/lib/components/filesharing/SendButton.svelte b/src/lib/components/filesharing/SendButton.svelte index f2db706..9be62ac 100644 --- a/src/lib/components/filesharing/SendButton.svelte +++ b/src/lib/components/filesharing/SendButton.svelte @@ -266,6 +266,18 @@ } } + function onCancelUpload(): void { + if (!browser) return + // Mark before aborting so the catch in startEncryption() takes the + // self-aborted path and resets to FileSelection rather than showing + // the generic Error panel. + encryptState.selfAborted = true + encryptState.abort.abort() + // AbortController is single-use — provide a fresh one so a subsequent + // send attempt can be cancelled too. + encryptState.abort = new AbortController() + } + function updateProgress(pct: number) { const totalSize = encryptState.files.reduce((a, f) => a + f.size, 0) if (totalSize === 0) return @@ -365,6 +377,14 @@

{/if} + {:else}