• v4.49.0 24f9e3a054

    v4.49.0
    All checks were successful
    test / test (push) Successful in 2m20s
    build-and-release / appimage (push) Successful in 2m27s
    Stable

    Ghost released this 2026-09-27 20:06:59 +00:00 | 0 commits to main since this release

    Added

    • Pause and resume an account. A paused account stays saved but leaves every due list, reminder,
      projection and attention panel; nothing is deleted and the due date is kept for the day it resumes.
      It shows a "Paused" badge with the date it was paused. (Schema v19 adds paused_at.)
    • Restore a value from the account history. The audit trail already stores both sides of every
      edit, so any recorded change to the title, amount or currency can be put back from the history
      panel. The restore is recorded too, so it is not a hole in the trail.
    • A price-change report on the Insights page: every recorded change to what an account costs, with
      the direction and percentage.
    • Encrypted automatic backups (opt-in, in Settings → Backup). They are encrypted with the app-lock
      PIN held in memory for the unlocked session, so the file is unreadable without it and restoring it
      asks for that PIN. When the app has not been unlocked yet the backup skips rather than silently
      writing a plaintext copy. A short PIN is weaker than a long passphrase — this protects a lost or
      copied file, not a determined attacker, and the setting says so.
    • scripts/smoke-test.mjs: boots the packaged app on a throwaway profile and checks the database it
      creates (schema version, tables, indexes, search index triggers, and search add/update/delete). The
      release workflow runs it before publishing, so a build that starts broken never ships.
    • scripts/gen-css.mjs: the stylesheet's generated helper block now has its generator inside the
      repo, so global.css is reproducible instead of being the output of a throwaway script.
    • Focus trapping for every dialog (useFocusTrap), plus a test suite for it.

    Changed

    • The packaged app shipped unminified JavaScript. electron-vite defaults the renderer target to
      build.minify: false, so the entry chunk was 1,184 kB of mostly-readable source. Turning on Vite's
      built-in esbuild minifier takes the entry chunk to 557 kB (−52.9%), total renderer JS from 1,559 kB
      to 746 kB (−52.1%) and the stylesheet from 57 kB to 43 kB — with no dependency added and no code
      change.
    • backup.ts (1399 → 1298 lines) no longer registers IPC; that lives in backupIpc.ts.
    • The PIN hashing, verification, change authorisation and brute-force lockout moved out of the
      Electron-only index.ts into src/main/pin.ts, with tests — they were the only security-relevant
      code excluded from coverage.
    • 65 unused CSS rules and 8 unused classes removed (217 lines); tests/design-standard.test.ts now
      also fails if the generated block drifts from the generator, or if a component class the standard
      documents disappears.
    • Test timeout raised above asyncUtilTimeout so a slow assertion reports the element it could not
      find rather than an opaque "test timed out".
    • allowScripts in package.json allowlists the better-sqlite3 install script: npm 12 blocks
      dependency install scripts by default, which silently turned npm rebuild better-sqlite3 into a
      no-op and broke the native module locally.

    Fixed

    • Two $1-reuse bugs of the kind that broke search: pauseSubscription bound one value for two
      placeholders and threw "Too few parameter values were provided".
    Downloads