• 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
  • v4.48.2 cd44a827ea

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

    Ghost released this 2026-09-11 20:38:00 +00:00 | 3 commits to main since this release

    Added

    • Regression tests pinning the icon rules the oversized-icon bug broke: an icon with no explicit
      size still gets a fixed one, and a layout class can never decide how big an icon is.
    Downloads
  • v4.48.1 a8e0505041

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

    Ghost released this 2026-09-11 20:30:14 +00:00 | 5 commits to main since this release

    Fixed

    • Oversized icons. The sidebar, the site favicons and the auto-backup status dot referenced helper
      classes (sq-s20, h-s20, w-s20, p-s2, sq-s8, …) that global.css never defined, so those
      SVGs and frames fell back to the browser's default size and rendered huge. The classes are now
      generated, and the icon size comes from the SVG's own width/height instead of a stylesheet class.
    • The helper generator only scanned className= attributes, which is why classes written in object
      literals or default parameters were never emitted.

    Changed

    • Icons now come from icons.tsx only: the second icon file (NavIcons.tsx) is gone and every icon
      uses the standard's strokeWidth 1.8 with a fixed size (THEME.md §4.7).
    • Motion follows THEME.md §4.4 again: the looping pulse animation (and a duplicate @keyframes
      definition) is gone, the loading placeholders use the standard fadeIn, and every transition is
      120ms.
    • The version shown in the sidebar, footer, About dialog and update panel now comes from
      app.getVersion() via app:getState instead of a constant baked into the bundle (STANDARD.md §3.2).
    • The account filters use the standard's filter-select and the export actions its export-grid.
    • Test timeout raised above asyncUtilTimeout, so a slow assertion reports the element it could not
      find instead of an opaque "test timed out".
    • Added tests/design-standard.test.ts, which fails when a component references a class the
      stylesheet does not define, when an icon appears outside icons.tsx, when a non-standard animation
      is used, or when a colour is hardcoded in a component.
    Downloads